diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..77dede83 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# Dictionary license inputs are checksum-addressed byte artifacts. Preserve +# upstream bytes generally, while pinning the one normalized source file to +# the LF representation stored in Git and recorded in the inventory. +assets/spelling/licenses/** -text +assets/spelling/licenses/es/README_th_es.txt text eol=lf +assets/spelling/CHECKSUMS.sha256 text eol=lf +assets/spelling/NOTICE text eol=lf +assets/spelling/VERSION text eol=lf +assets/spelling/dictionaries.json text eol=lf diff --git a/.github/workflows/flutter-linux.yml b/.github/workflows/flutter-linux.yml index d37447a2..575b53dd 100644 --- a/.github/workflows/flutter-linux.yml +++ b/.github/workflows/flutter-linux.yml @@ -2,9 +2,11 @@ name: Flutter Linux on: pull_request: - branches: [main] + branches: + - main push: - branches: [main] + branches: + - main jobs: writerside-conformance: @@ -38,6 +40,8 @@ jobs: ninja-build \ pkg-config \ libgtk-3-dev \ + libglib2.0-dev \ + libpango1.0-dev \ libhandy-1-dev \ libsecret-1-dev \ libwebkit2gtk-4.1-dev \ @@ -100,9 +104,50 @@ jobs: - name: Analyze run: flutter analyze + - name: Test native Hunspell package explicitly + working-directory: packages/busymark_spellcheck_native + run: | + dart pub get + dart test + + - name: Prepare all-language spelling test resources + run: tools/fetch_spelling_dictionaries.sh build/spelling-test + + - name: Validate every supported dictionary with the native engine + env: + BUSYMARK_TEST_SPELLING_ROOT: ${{ github.workspace }}/build/spelling-test + run: flutter test test/src/spelling_bundle_integration_test.dart + - name: Build Linux release run: flutter build linux --release + - name: Verify release ships catalog and notices without language pairs + run: | + spelling_root="build/linux/x64/release/bundle/share/busymark/spelling" + test -s "$spelling_root/dictionaries.json" + test -s "$spelling_root/NOTICE" + test -z "$(find "$spelling_root" -type f \( -name '*.aff' -o -name '*.dic' \) -print -quit)" + + - name: Install one dictionary and exercise it after an offline restart + run: | + report="${RUNNER_TEMP}/spelling-release.json" + profile="${RUNNER_TEMP}/spelling-profile" + mkdir -p "$profile" + xvfb-run -a -s '-screen 0 1280x1024x24' \ + env GDK_BACKEND=x11 BUSYMARK_RELEASE_SMOKE=1 \ + XDG_DATA_HOME="$profile" LIBGL_ALWAYS_SOFTWARE=1 \ + build/linux/x64/release/bundle/busymark \ + --spelling-release-smoke="$report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert report["checks"]["bundledDictionaryFileCount"] == 0, report; assert report["checks"]["dictionaryInstalledDuringRun"], report; assert report["checks"]["installedDictionaryCount"] == 1, report' "$report" + sudo unshare --net --fork -- \ + runuser -u "$(id -un)" -- \ + xvfb-run -a -s '-screen 0 1280x1024x24' \ + env GDK_BACKEND=x11 BUSYMARK_RELEASE_SMOKE=1 \ + XDG_DATA_HOME="$profile" LIBGL_ALWAYS_SOFTWARE=1 \ + build/linux/x64/release/bundle/busymark \ + --spelling-release-smoke="$report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert not report["checks"]["dictionaryInstalledDuringRun"], report; assert report["checks"]["personalWordPresentBeforeRun"], report' "$report" + - name: Test including bundled D2 and Typst paths env: BUSYMARK_D2_PATH: ${{ github.workspace }}/build/linux/x64/release/bundle/libexec/busymark/d2 @@ -131,7 +176,7 @@ jobs: python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report' "$report" test -s "${RUNNER_TEMP}/visualization-smoke.pdf" - - name: Run visualization smoke tests under Wayland + - name: Run spelling and visualization smoke tests under Wayland run: | runtime_dir="/run/user/$(id -u)" sudo install -d -m 700 -o "$(id -u)" -g "$(id -g)" "$runtime_dir" @@ -151,6 +196,16 @@ jobs: sleep 0.25 done test -S "$runtime_dir/wayland-99" + spelling_report="${RUNNER_TEMP}/spelling-release-wayland.json" + spelling_profile="${RUNNER_TEMP}/spelling-profile" + sudo unshare --net --fork -- \ + runuser -u "$(id -un)" -- \ + env XDG_RUNTIME_DIR="$runtime_dir" WAYLAND_DISPLAY=wayland-99 \ + XDG_DATA_HOME="$spelling_profile" GDK_BACKEND=wayland \ + BUSYMARK_RELEASE_SMOKE=1 LIBGL_ALWAYS_SOFTWARE=1 \ + build/linux/x64/release/bundle/busymark \ + --spelling-release-smoke="$spelling_report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert report["checks"]["sourceEditorTransaction"], report; assert report["checks"]["formattedRichEditorTransaction"], report; assert report["checks"]["tableCellEditorTransaction"], report' "$spelling_report" XDG_RUNTIME_DIR="$runtime_dir" WAYLAND_DISPLAY=wayland-99 \ GDK_BACKEND=wayland LIBGL_ALWAYS_SOFTWARE=1 \ /usr/bin/python3 -u tools/visualization_smoke.py \ @@ -222,6 +277,33 @@ jobs: "$query" "$loader" | grep -q "\"svg\" 6 \"gdk-pixbuf\"" ' + - name: Install one strict-Snap dictionary and verify refresh/offline use + run: | + report="$HOME/snap/busymark/common/spelling-release.json" + rm -f "$report" + xvfb-run -a -s '-screen 0 1280x1024x24' \ + env GDK_BACKEND=x11 BUSYMARK_RELEASE_SMOKE=1 \ + LIBGL_ALWAYS_SOFTWARE=1 snap run busymark \ + --spelling-release-smoke="$report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert report["checks"]["bundledDictionaryFileCount"] == 0, report; assert report["checks"]["dictionaryInstalledDuringRun"], report; assert report["checks"]["installedDictionaryCount"] == 1, report' "$report" + test -d "$HOME/snap/busymark/common/spelling/dictionaries/downloaded/en-US" + before_revision="$(snap list busymark | awk 'NR == 2 {print $3}')" + sudo snap install --dangerous \ + "${{ steps.snap-artifact.outputs.snap }}" + after_revision="$(snap list busymark | awk 'NR == 2 {print $3}')" + test -n "$before_revision" + test -n "$after_revision" + test "$before_revision" != "$after_revision" + sudo snap disconnect busymark:network + trap 'sudo snap connect busymark:network >/dev/null' EXIT + xvfb-run -a -s '-screen 0 1280x1024x24' \ + env GDK_BACKEND=x11 BUSYMARK_RELEASE_SMOKE=1 \ + LIBGL_ALWAYS_SOFTWARE=1 snap run busymark \ + --spelling-release-smoke="$report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert not report["checks"]["dictionaryInstalledDuringRun"], report; assert report["checks"]["installedDictionaryCount"] == 1, report; assert report["checks"]["personalWordPresentBeforeRun"], report' "$report" + sudo snap connect busymark:network + trap - EXIT + - name: Exercise strict Snap visualization and PDF paths under X11 run: | report="$HOME/snap/busymark/common/visualization-release-x11.json" @@ -234,7 +316,7 @@ jobs: python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report' "$report" test -s "$HOME/snap/busymark/common/visualization-smoke.pdf" - - name: Exercise strict Snap visualization and PDF paths under Wayland + - name: Exercise strict Snap spelling and visualization under Wayland run: | runtime_dir="/run/user/$(id -u)" sudo install -d -m 700 -o "$(id -u)" -g "$(id -g)" "$runtime_dir" @@ -242,7 +324,8 @@ jobs: weston --backend=headless-backend.so --socket=wayland-99 \ --idle-time=0 --log="${RUNNER_TEMP}/weston-snap.log" & weston_pid=$! - trap 'kill "$weston_pid" 2>/dev/null || true' EXIT + sudo snap disconnect busymark:network + trap 'sudo snap connect busymark:network >/dev/null; kill "$weston_pid" 2>/dev/null || true' EXIT for attempt in {1..40}; do if [ -S "$runtime_dir/wayland-99" ]; then break @@ -254,6 +337,13 @@ jobs: sleep 0.25 done test -S "$runtime_dir/wayland-99" + spelling_report="$HOME/snap/busymark/common/spelling-release-wayland.json" + XDG_RUNTIME_DIR="$runtime_dir" WAYLAND_DISPLAY=wayland-99 \ + GDK_BACKEND=wayland BUSYMARK_RELEASE_SMOKE=1 \ + LIBGL_ALWAYS_SOFTWARE=1 \ + timeout --signal=TERM 300s snap run busymark \ + --spelling-release-smoke="$spelling_report" + python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report; assert report["checks"]["sourceEditorTransaction"], report; assert report["checks"]["formattedRichEditorTransaction"], report; assert report["checks"]["tableCellEditorTransaction"], report' "$spelling_report" report="$HOME/snap/busymark/common/visualization-release-wayland.json" XDG_RUNTIME_DIR="$runtime_dir" WAYLAND_DISPLAY=wayland-99 \ GDK_BACKEND=wayland BUSYMARK_RELEASE_SMOKE=1 \ @@ -262,3 +352,5 @@ jobs: --visualization-release-smoke="$report" python3 -c 'import json,sys; report=json.load(open(sys.argv[1], encoding="utf-8")); assert report["ok"], report' "$report" test -s "$HOME/snap/busymark/common/visualization-smoke.pdf" + sudo snap connect busymark:network + trap 'kill "$weston_pid" 2>/dev/null || true' EXIT diff --git a/README.md b/README.md index d1dafd74..f07efe3e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ for filesystem and Git-integration details. ## Run from source -BusyMark currently uses Flutter 3.47.2. Install the Linux packages required by +BusyMark currently uses Flutter 3.47.4. Install the Linux packages required by Flutter and BusyMark's CMake configuration: ```bash diff --git a/assets/spelling/CHECKSUMS.sha256 b/assets/spelling/CHECKSUMS.sha256 new file mode 100644 index 00000000..5c127b04 --- /dev/null +++ b/assets/spelling/CHECKSUMS.sha256 @@ -0,0 +1,77 @@ +4575a8d402694008656ed3cda93d158f58adbd0ae54a8b9b47824e53f9f7d19e NOTICE +8b037210fca77dc4fb8f6f0573e1578717d73f429cbb25e8f10b54d314800a11 VERSION +4fa250112cfbee3fcf3e2dc1cc1f9b60bc556f439bdc0310e35dce19ed5b8bd3 dictionaries.json +73480d918cd78d655508e80aa88c022cbd53634524a0f714b5f2519f2cf19124 licenses/ar/COPYING.txt +5ead684ae5211ccf615686959e24bd21ef6eebbb6195997529fda08b993f615e licenses/ar/README_ar.txt +e7431ac20e815b6797369e802f9e4bb1b0082485060d8b096235f035d741bd89 licenses/de/COPYING_GPLv2 +8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903 licenses/de/COPYING_GPLv3 +b7993225104d90ddd8024fd838faf300bea5e83d91203eab98e29512acebd69c licenses/de/COPYING_LGPL_v2.0.txt +dc626520dcd53a22f727af3ee42c770e56c97a64fe3adb063799d8ab032fe551 licenses/de/COPYING_LGPL_v2.1.txt +2d9d81e88ecd0e837122f4688ca7a6a5bd7bb41bff6e21ff5d4663eb43372db3 licenses/de/COPYING_OASIS.txt +c141f4f79c428b7348b5012836f4ad3db4d124f288f15effc22696dc876512ae licenses/de/README_de_DE_frami.txt +7662cbc363fdee12bc03a5295148587bb76923c121792a401115e654fea37b5c licenses/de/README_extension_owner.txt +be7b3c67a66ea7185a69a3ce3b1e712cd6bb904dce8ac0eecdefd2f1a948baf3 licenses/de/README_hyph_de.txt +405accab10106f6d09152f2f5865ec3545fbcf40817b5416b4b99a077f303a87 licenses/de/README_thesaurus.txt +b8dd4d2ace5358adf5e6ddfac720871188e6f211cf56af97db631f4ee53e0ff3 licenses/en/README.txt +f0897dcfdf058bcfc93fbc8e7e1b5da4c27ae9e175ee3a9242e887f02eb84a8b licenses/en/README_en_AU.txt +86700e39b2307dda4c087ad3505a1e634a5b4d518ab808c398a16d21ebe957e2 licenses/en/README_en_CA.txt +18b5833de60a52ffcb6e5b6b5048bb5a5d910acfecd5b096985b77058223880c licenses/en/README_en_GB.txt +cc8abeac37067747d66d5365e8163145be6f3c23f488005074bf255bac89f2e4 licenses/en/README_en_GB_thes.txt +168b4c01cb841f766a72f310b065c04d09cff46376c37a81d799593ce751c371 licenses/en/README_en_US.txt +116ade99dd4a92715b21ae5b358a1a8cc814c76c0d6e582fdba4870835d1a6e2 licenses/en/README_en_ZA.txt +6f3d1dddcf62d2d452801bd86289ad5826a30d15a502c0825f5c73715372db50 licenses/en/README_hyph_en_GB.txt +9bcae072bff45cc0333d6b3c508c92d85b9065fc861c743c1506b303eba3f4a1 licenses/en/README_hyph_en_US.txt +2271b9893955aa0abae1193cf56a66badaa906c0af030edd46113d10c59f2e24 licenses/en/README_lightproof_en.txt +23dbc4f3ea771304e5ab3e5709843813d2619f3c0cfc81229b53fcdb9985f29a licenses/en/WordNet_license.txt +df84246204e3c54cd24aebbc23714235f5fc41d754d53b65444a2afbf070130f licenses/en/license.txt +2b70fd5cb8d3b34cc6ae322c969557a2270b99017594addb2531ef5ffd9e1b17 licenses/es/LICENSE.md +0b5c39a863ecb61f5c5631ec1cd977667ef9bda6da6f90e80e9fc0edcbfadd97 licenses/es/README_hunspell_es.txt +1f1088dce1140d981660faf3f5acc825e74aa1f943a8bec88cb046e4c528a1fb licenses/es/README_hyph_es.txt +c721aad5e8f15297d4a8aa30b31a1bec1a4cbbeaeec6b2633cd64e2b0fafab30 licenses/es/README_th_es.txt +4cff6a48ea9168d545316ab96bac24eff4745bf198cbdd9f57eb10a9d8f93f0d licenses/et_EE/README_et_EE.txt +da273b8ec03e35774a426e9df047ad85253ec9e61a5c056f019d57c1395ef1cb licenses/et_EE/README_hyph_et_EE.txt +7429736f069a84049bcfbee436e5cea3a3fd9b98348d880d9e43ebcf39721989 licenses/fa_IR/LICENSE +aa1450d6eab0d140719048e7277204bae086947fe5d8cd834d115c0dd0cf7a81 licenses/fa_IR/README_fa_IR.txt +4a25abf740ad6ba5e8d0cfc0d2ffadc3c13c303f8fe389f323b061a389350f83 licenses/fr_FR/dictionaries/README_dict_fr.txt +6951d9806c65c7f757d303061ca49cd7a1ddeddc552147f5c29de6540821f2cf licenses/fr_FR/dictionaries/README_hyph_fr.txt +431a690c5be7741eeaa0e9654aeb75ed2b0af337492e622e8393d090b4612b3e licenses/fr_FR/dictionaries/README_thes_fr.txt +204d8eff92f95aac4df6c8122bc1505f468f3a901e5a4cc08940e0ede1938994 licenses/hi_IN/COPYING +2b373a1e07efe18e89c04c7f69bd540681a5926edcb478a4331d0df387861487 licenses/hi_IN/README_hi_IN.txt +97628afebc60f026f5c2b25d7491c46a5c4ee61f693e7cfa07fbd2c03605979b licenses/id/LICENSE-dict +1f3360c2c2fbe9918f3658a20fcd2f64113a11726b7327ca1df7220c433689e1 licenses/id/LICENSE-thes +7c18fabf4169a4b7f0f7effac5309c26294d8cb354d9ed5cbc8ea2868abcf942 licenses/id/README-dict.adoc +6bbe6d0559d00b6e05acc9477cebfbf0da2b183b4c541cf47f7153dc7e3dfda5 licenses/id/README-thes +e6f356c3c49bc6016b6a635c20b468468eef6d011953a7051bbdfd56e17f0d3b licenses/it_IT/README_hyph_it_IT.txt +34c3e93595cf3cf5f3afc9bc0d98eea12593750383f1e82ed1d3ca29f9681283 licenses/it_IT/README_it_IT.txt +07cd83b0d7664ebc620f589524069549f6ead33bccedb7f27d04ed0311e62905 licenses/it_IT/README_th_it_IT.txt +3e41d215a0d9ce21c1fa982d48d2958d539a51011f469f741b51f97e2595ec7e licenses/it_IT/legacy/it_IT_COPYING +0328874f246fa9511fb19be6fc38db57f1351b00356e7c7187de59529fb04e6f licenses/it_IT/legacy/it_IT_README.1st +ec6332fd60cca5d4cd1b69c78aebae33bb49ccea856ed1d69722e3a23f0dfc82 licenses/it_IT/legacy/it_IT_README.txt +4de624abc748506298e7be68f2213e422673b43e1674da4b376804096b87dcec licenses/it_IT/legacy/it_IT_license.txt +3e41d215a0d9ce21c1fa982d48d2958d539a51011f469f741b51f97e2595ec7e licenses/it_IT/legacy/th_it_IT_COPYING +3097ecbc3ebd844266b556768748b7c07bde915dd5dd0b70eee30670a91a2599 licenses/it_IT/legacy/th_it_IT_README +e0b13b74b287a71bc668a756fe0d1bcfe5adafb860acab0d81e71593333e1724 licenses/ko_KR/README_ko_KR.txt +2189c248cbc054445aeac6cd65b87eebd0a115efeb55ed498b0f2a73441805dd licenses/nl_NL/LICENSE.txt +aa4685a78f32d0d24a67dd5043ef4e39acc8720c3e416fe5d201985980dbc004 licenses/nl_NL/README.md +e7431ac20e815b6797369e802f9e4bb1b0082485060d8b096235f035d741bd89 licenses/no/COPYING +0fb3b682bbe5fd3fe23a22d26cc7c417115016bb5f40ec4cf5a62aabe6e5c9c9 licenses/no/README +0fb3b682bbe5fd3fe23a22d26cc7c417115016bb5f40ec4cf5a62aabe6e5c9c9 licenses/no/README_NO.txt +5dd6d4fa61585062d8774afff75d0c51d76bb8126078fef0c0e69740eb093ce0 licenses/no/README_hyph_NO.txt +fb5f9b4a0643821cf88775c0932810c1cd05f236136c913e3eaf1e24806f3f44 licenses/pl_PL/README_en.txt +ce3ad7ab1d3a8b767b8f7dcc870796fbda76bc7ad8cde22f6312b0cf86a5bd11 licenses/pl_PL/README_pl.txt +e691ed1e79934293b0cd6996a14af1520ff893c02f920c09ed0c90aa5f0a8abc licenses/pl_PL/README_pl_PL.txt +9300db07784a8575743e68cd4c9b966c66f9212c708bd3bbf0190df61e75114a licenses/pt_BR/README_Lightproof_pt_BR.txt +bb064f3db7ba5f5536da7d079773f692c5f928822e8aebc3d78259ff6cceb9e5 licenses/pt_BR/README_en.txt +07400608865ce4c964cc443a9f354c733ca7f3f7d31f4463222b927cb7c54b87 licenses/pt_BR/README_hyph_pt_BR.txt +9974ce691fdc1fe731717d7a2dc668244405fdc2bf9bf3367eb9b29e85177c88 licenses/pt_BR/README_pt_BR.txt +253031afa265c7bec5d2e195c659129a7ff254f9d57c57a08eba4a9051868840 licenses/pt_BR/license-thes.readme +8de865eb2f5a83a182d96964d1fe0eee05ae0d68a94f9e9938e4f6349075f5c4 licenses/ru_RU/README_Lightproof_ru_RU.txt +262af2f6ad70a61e5ee1332ff44fa8ee50edca819cf33207d8ad6ba6a0c9be52 licenses/ru_RU/README_ru_RU.txt +faf06127db60c80b4deefc26a86b3c8a18e1ba46e89d29db8f232501ea850b69 licenses/ru_RU/README_thes_ru_RU_M_aot_and_v2.txt +3f3d9e0024b1921b067d6f7f88deb4a60cbe7a78e76c64e3f1d7fc3b779b9d04 licenses/tr_TR/LICENSE +18750c09a1e666a6d34854b92dfdc0353c3bfe39008b412d539f52821ecdbdec licenses/tr_TR/README.txt +b5866714694f0e9a7c9d044984b4b39ec6289ade07fa7d2a083a31f5072f3529 licenses/uk_UA/README_hyph_uk_UA.txt +29aed1f76c8552b9ba22b00f9f3a5f8316498f95b50f5c1aad3a9743a560ba6c licenses/uk_UA/README_th_uk_UA.txt +664436fee625b4a3e712483947d1711a2f467670f4c389bcf10abca2a564e1dc licenses/uk_UA/README_uk_UA.txt +d32e4c8faf974bdeb87da10a5951556b33744cf9b50a7f06125074e11f30d7f6 licenses/vi/LICENSES-en.txt +e300eee4d3fd59e2886e785b63f6ded6badc7b9c6883cf73e365b59635d6128d licenses/vi/LICENSES-vi.txt diff --git a/assets/spelling/NOTICE b/assets/spelling/NOTICE new file mode 100644 index 00000000..6bf103b5 --- /dev/null +++ b/assets/spelling/NOTICE @@ -0,0 +1,3 @@ +LibreOffice dictionary data +Revision: 32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4 +Each dictionary remains under the terms recorded in licenses/. diff --git a/assets/spelling/VERSION b/assets/spelling/VERSION new file mode 100644 index 00000000..8a46fc9c --- /dev/null +++ b/assets/spelling/VERSION @@ -0,0 +1 @@ +32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4 diff --git a/assets/spelling/dictionaries.json b/assets/spelling/dictionaries.json new file mode 100644 index 00000000..110be0b5 --- /dev/null +++ b/assets/spelling/dictionaries.json @@ -0,0 +1,1045 @@ +{ + "schemaVersion": 2, + "source": { + "name": "LibreOffice dictionaries", + "url": "https://github.com/LibreOffice/dictionaries", + "revision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "archiveSha256": "cbd790eca560de5e8ec8bd64117a00dfd0bc06b091c8f52d23e44ea00d3e8461" + }, + "dictionaries": [ + { + "resourceId": "ar-SA", + "id": "ar-SA", + "knownValidProbe": "بيت", + "locales": [ + "ar-AE", + "ar-BH", + "ar-DZ", + "ar-EG", + "ar-IQ", + "ar-JO", + "ar-KW", + "ar-LB", + "ar-LY", + "ar-MA", + "ar-OM", + "ar-QA", + "ar-SA", + "ar-SD", + "ar-SY", + "ar-TN", + "ar-YE" + ], + "label": "Arabic (ar-SA)", + "affSourcePath": "ar/ar.aff", + "dicSourcePath": "ar/ar.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ar/ar.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ar/ar.dic", + "affSize": 86949, + "dicSize": 7217161, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "cec30b8621001e49618feb05aec1984c5fcfbf7d2ec309901d5cbf66585217a3", + "dicSha256": "2a3e5367f61c1583734db9d66734f5603e6be5c2d227cf5c5cd7e4ca586e34fe", + "licenseDirectory": "licenses/ar" + }, + { + "resourceId": "nl-AW", + "id": "nl-AW", + "knownValidProbe": "huis", + "locales": [ + "nl-AW", + "nl-BE", + "nl-NL", + "nl-SR" + ], + "label": "Dutch (nl-AW)", + "affSourcePath": "nl_NL/nl_NL.aff", + "dicSourcePath": "nl_NL/nl_NL.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/nl_NL/nl_NL.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/nl_NL/nl_NL.dic", + "affSize": 46557, + "dicSize": 2488246, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "f0233d4f721f4661cf5f4d05ed2739549322bf3b6b66764b55a38257e1e16e6f", + "dicSha256": "bc28af45307700a9927ad5719184da44dfd7eed4f707b8c1477f6d8a21b586a6", + "licenseDirectory": "licenses/nl_NL" + }, + { + "resourceId": "en-AU", + "id": "en-AU", + "knownValidProbe": "house", + "locales": [ + "en-AU" + ], + "label": "English (en-AU)", + "affSourcePath": "en/en_AU.aff", + "dicSourcePath": "en/en_AU.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_AU.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_AU.dic", + "affSize": 3205, + "dicSize": 554336, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "e746c882dd6f303c2c46e7452804b9201115a6942cfeb15f18f8edf774d2e24e", + "dicSha256": "aa07c46571f306b79fc1bc534357ed357af15687381b26f891ba66e8a2caed89", + "licenseDirectory": "licenses/en" + }, + { + "resourceId": "en-CA", + "id": "en-CA", + "knownValidProbe": "house", + "locales": [ + "en-CA" + ], + "label": "English (en-CA)", + "affSourcePath": "en/en_CA.aff", + "dicSourcePath": "en/en_CA.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_CA.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_CA.dic", + "affSize": 3205, + "dicSize": 551583, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "e746c882dd6f303c2c46e7452804b9201115a6942cfeb15f18f8edf774d2e24e", + "dicSha256": "53096689870246a78fa408b1e7a8c49bc140bd466a84a384cfb509445fff7173", + "licenseDirectory": "licenses/en" + }, + { + "resourceId": "en-GB", + "id": "en-GB", + "knownValidProbe": "house", + "locales": [ + "en-BS", + "en-BZ", + "en-GB", + "en-GH", + "en-IE", + "en-IN", + "en-JM", + "en-NZ", + "en-TT" + ], + "label": "English (en-GB)", + "affSourcePath": "en/en_GB.aff", + "dicSourcePath": "en/en_GB.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_GB.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_GB.dic", + "affSize": 44158, + "dicSize": 1230571, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "0fd6ed120ef28957847d98ba5149b117e27116cf81b5aa36208453f6755a36fd", + "dicSha256": "04e90f34f5263bf26780e9c4a442e9ad16584e227af49ddd1b3b21b01df5b29c", + "licenseDirectory": "licenses/en" + }, + { + "resourceId": "en-US", + "id": "en-US", + "knownValidProbe": "house", + "locales": [ + "en-IL", + "en-PH", + "en-US" + ], + "label": "English (en-US)", + "affSourcePath": "en/en_US.aff", + "dicSourcePath": "en/en_US.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_US.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_US.dic", + "affSize": 3205, + "dicSize": 551762, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "e746c882dd6f303c2c46e7452804b9201115a6942cfeb15f18f8edf774d2e24e", + "dicSha256": "f0b1a234bd178bdd01875b2a392a9647f888b8fe879f79c52aae62c2759b3647", + "licenseDirectory": "licenses/en" + }, + { + "resourceId": "en-ZA", + "id": "en-ZA", + "knownValidProbe": "house", + "locales": [ + "en-MW", + "en-NA", + "en-ZA", + "en-ZW" + ], + "label": "English (en-ZA)", + "affSourcePath": "en/en_ZA.aff", + "dicSourcePath": "en/en_ZA.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_ZA.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/en/en_ZA.dic", + "affSize": 43842, + "dicSize": 998279, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "5ddaf2bd123df16cbb887adf7dd835593200d0454703c461714886833c9ddec9", + "dicSha256": "a438af6c6bfa9b25208d72c6ebf53507e178d6e6d285895e97870c36193433b1", + "licenseDirectory": "licenses/en" + }, + { + "resourceId": "et-EE", + "id": "et-EE", + "knownValidProbe": "maja", + "locales": [ + "et-EE" + ], + "label": "Estonian (et-EE)", + "affSourcePath": "et_EE/et_EE.aff", + "dicSourcePath": "et_EE/et_EE.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/et_EE/et_EE.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/et_EE/et_EE.dic", + "affSize": 236336, + "dicSize": 4383841, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "2fa53b7853762ec8c63ffa14b2d96d23433e3f2c2d3d218ad7c2461673099f95", + "dicSha256": "cd1378434aefeaa8a31f49369dbf71caf4e6340badb5c2cf7a55820933ed4f13", + "licenseDirectory": "licenses/et_EE" + }, + { + "resourceId": "fr-FR", + "id": "fr-FR", + "knownValidProbe": "maison", + "locales": [ + "fr-BE", + "fr-BF", + "fr-BJ", + "fr-CA", + "fr-CH", + "fr-CI", + "fr-FR", + "fr-LU", + "fr-MC", + "fr-ML", + "fr-NE", + "fr-SN", + "fr-TG" + ], + "label": "French (fr-FR)", + "affSourcePath": "fr_FR/dictionaries/fr.aff", + "dicSourcePath": "fr_FR/dictionaries/fr.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/fr_FR/dictionaries/fr.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/fr_FR/dictionaries/fr.dic", + "affSize": 199870, + "dicSize": 1236490, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "c176610cd5dc4846806a65ddd029f422d87978bf58f224aa44222662a16a2de5", + "dicSha256": "b78a868e31dd6e373b6c3217969afb898a9acde828a5e7ef97308da42218c88c", + "licenseDirectory": "licenses/fr_FR" + }, + { + "resourceId": "de-AT", + "id": "de-AT", + "knownValidProbe": "Haus", + "locales": [ + "de-AT" + ], + "label": "German (de-AT)", + "affSourcePath": "de/de_AT_frami.aff", + "dicSourcePath": "de/de_AT_frami.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_AT_frami.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_AT_frami.dic", + "affSize": 19068, + "dicSize": 4359309, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "8b428f6215e36e145626e3d150cd0ffe273e1ad9a9ec0a1bbd31ee468ee39edc", + "dicSha256": "d821e0a5a029b66df696c982a4cd55eb792139c33716ccbde364941db2448cbb", + "licenseDirectory": "licenses/de" + }, + { + "resourceId": "de-CH", + "id": "de-CH", + "knownValidProbe": "Haus", + "locales": [ + "de-CH" + ], + "label": "German (de-CH)", + "affSourcePath": "de/de_CH_frami.aff", + "dicSourcePath": "de/de_CH_frami.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_CH_frami.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_CH_frami.dic", + "affSize": 19068, + "dicSize": 4358308, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "d86884be4c3f07e5e08057884856feabf2872b4e2f90a587a11376082bc4126b", + "dicSha256": "80a4df38cdc3e16d2f042f8eba4a99668ab9c075662e4262c62f8bba46c7bd16", + "licenseDirectory": "licenses/de" + }, + { + "resourceId": "de-DE", + "id": "de-DE", + "knownValidProbe": "Haus", + "locales": [ + "de-DE" + ], + "label": "German (de-DE)", + "affSourcePath": "de/de_DE_frami.aff", + "dicSourcePath": "de/de_DE_frami.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_DE_frami.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/de/de_DE_frami.dic", + "affSize": 19067, + "dicSize": 4356903, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "646bf3333ac69c23e9d794533ee5241d6f755c359e8fe10a648f87613743d594", + "dicSha256": "4ca3c958b0e5545910999bc246f668840bf8ede3df8e5e6790d05edd5a586c38", + "licenseDirectory": "licenses/de" + }, + { + "resourceId": "hi-IN", + "id": "hi-IN", + "knownValidProbe": "घर", + "locales": [ + "hi-IN" + ], + "label": "Hindi (hi-IN)", + "affSourcePath": "hi_IN/hi_IN.aff", + "dicSourcePath": "hi_IN/hi_IN.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/hi_IN/hi_IN.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/hi_IN/hi_IN.dic", + "affSize": 12671, + "dicSize": 5004835, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "3ab96772dc3d1cdbec4141798efb8b7a091b92c9acbeb5dfd3c4998a5c508302", + "dicSha256": "1e01f962a02638ef73e3f8de3c44bfd854f7059d31c9fa96cff0b73a2840f9d9", + "licenseDirectory": "licenses/hi_IN" + }, + { + "resourceId": "id-ID", + "id": "id-ID", + "knownValidProbe": "rumah", + "locales": [ + "id-ID" + ], + "label": "Indonesian (id-ID)", + "affSourcePath": "id/id_ID.aff", + "dicSourcePath": "id/id_ID.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/id/id_ID.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/id/id_ID.dic", + "affSize": 15274, + "dicSize": 453700, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "c625d5b237a489c452cf1f9c666600103e8093667dff89e7030a24217995dc79", + "dicSha256": "775ff17a52801f3d2ee80120952fb44cc9bac6c3cf61740de775e439851a5803", + "licenseDirectory": "licenses/id" + }, + { + "resourceId": "it-IT", + "id": "it-IT", + "knownValidProbe": "casa", + "locales": [ + "it-CH", + "it-IT" + ], + "label": "Italian (it-IT)", + "affSourcePath": "it_IT/it_IT.aff", + "dicSourcePath": "it_IT/it_IT.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/it_IT/it_IT.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/it_IT/it_IT.dic", + "affSize": 70054, + "dicSize": 1295083, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "951afaa19272f13555b8823e8bcf9ccf78f8fe1a07835bdfb912ab3e4d537c2b", + "dicSha256": "bae1e3501dcd2a923669592493b3fde6c02aae7c7aab83bf5e5b49077e73dd64", + "licenseDirectory": "licenses/it_IT" + }, + { + "resourceId": "ko-KR", + "id": "ko-KR", + "knownValidProbe": "사람", + "locales": [ + "ko-KR" + ], + "label": "Korean (ko-KR)", + "affSourcePath": "ko_KR/ko_KR.aff", + "dicSourcePath": "ko_KR/ko_KR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ko_KR/ko_KR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ko_KR/ko_KR.dic", + "affSize": 11094418, + "dicSize": 2864524, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "43a984d8f1e2309490b69cfde31832d217a0b31164c67661e293efc096083688", + "dicSha256": "14117a72811ed6a083ed374ceb728b0846a689da6f4dbfe0a84d3b3bce124e80", + "licenseDirectory": "licenses/ko_KR" + }, + { + "resourceId": "nb-NO", + "id": "nb-NO", + "knownValidProbe": "hus", + "locales": [ + "nb-NO" + ], + "label": "Norwegian Bokmål (nb-NO)", + "affSourcePath": "no/nb_NO.aff", + "dicSourcePath": "no/nb_NO.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/no/nb_NO.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/no/nb_NO.dic", + "affSize": 17382, + "dicSize": 9336265, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "b9e828538222b3580d8adb4660d5bae9bc1fbe42e7c21fd3e01970efed96b4f8", + "dicSha256": "aadaf9ea6b437b4edada54a2084e1c8dc00029addc6dfb4e15637f8e798dacc1", + "licenseDirectory": "licenses/no" + }, + { + "resourceId": "nn-NO", + "id": "nn-NO", + "knownValidProbe": "hus", + "locales": [ + "nn-NO" + ], + "label": "Norwegian Nynorsk (nn-NO)", + "affSourcePath": "no/nn_NO.aff", + "dicSourcePath": "no/nn_NO.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/no/nn_NO.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/no/nn_NO.dic", + "affSize": 13616, + "dicSize": 6467674, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "454f0bf09e6581ca8e153c245a6136bec15e954f752d930ad32fedeb012ce5de", + "dicSha256": "9173f6b9e943cea8e3a2097b7c1cd67e09a0839cb85dfaad9114d7fc2c313c81", + "licenseDirectory": "licenses/no" + }, + { + "resourceId": "fa-IR", + "id": "fa-IR", + "knownValidProbe": "خانه", + "locales": [ + "fa-IR" + ], + "label": "Persian (fa-IR)", + "affSourcePath": "fa_IR/fa-IR.aff", + "dicSourcePath": "fa_IR/fa-IR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/fa_IR/fa-IR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/fa_IR/fa-IR.dic", + "affSize": 5439, + "dicSize": 2575990, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "cf7cd88fa8658b9c1bae8196b34ee2ff52456f6ce7a44482c1f5063feb6d8768", + "dicSha256": "314f31e059994f26e8016c834b14dfd10f74834b3f623a6040265b8f2a9dddab", + "licenseDirectory": "licenses/fa_IR" + }, + { + "resourceId": "pl-PL", + "id": "pl-PL", + "knownValidProbe": "dom", + "locales": [ + "pl-PL" + ], + "label": "Polish (pl-PL)", + "affSourcePath": "pl_PL/pl_PL.aff", + "dicSourcePath": "pl_PL/pl_PL.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/pl_PL/pl_PL.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/pl_PL/pl_PL.dic", + "affSize": 257542, + "dicSize": 5252096, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "82973651651aa930335c865b339b98db376ca3dbf3a661b70b9eeb71fdf41dca", + "dicSha256": "c0848440599eb88e5aca500418d5f389e562ec2c157b63dbe39d354658ffba49", + "licenseDirectory": "licenses/pl_PL" + }, + { + "resourceId": "pt-BR", + "id": "pt-BR", + "knownValidProbe": "casa", + "locales": [ + "pt-BR" + ], + "label": "Portuguese (pt-BR)", + "affSourcePath": "pt_BR/pt_BR.aff", + "dicSourcePath": "pt_BR/pt_BR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/pt_BR/pt_BR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/pt_BR/pt_BR.dic", + "affSize": 979792, + "dicSize": 4477695, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "21d8ad2a769a60e17e2b5ea4ef11d4d593a58b9e2a82d642ef82d6a4c5523865", + "dicSha256": "a38bfb26b68ece2834e79fe83e48d5792652970ace12db89d1b9674bf9933183", + "licenseDirectory": "licenses/pt_BR" + }, + { + "resourceId": "ru-RU", + "id": "ru-RU", + "knownValidProbe": "дом", + "locales": [ + "ru-RU" + ], + "label": "Russian (ru-RU)", + "affSourcePath": "ru_RU/ru_RU.aff", + "dicSourcePath": "ru_RU/ru_RU.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ru_RU/ru_RU.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/ru_RU/ru_RU.dic", + "affSize": 71236, + "dicSize": 3473191, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "38ce7d4af78e211e9bafe4bf7e3d6a2c420591136cb738ec6648f8fdf6524cd7", + "dicSha256": "f6047416a0204adbecf3a451b874ec8a97ee37e2cbc714466ef04d8dbcc0d6fc", + "licenseDirectory": "licenses/ru_RU" + }, + { + "resourceId": "es-AR", + "id": "es-AR", + "knownValidProbe": "casa", + "locales": [ + "es-AR" + ], + "label": "Spanish (es-AR)", + "affSourcePath": "es/es_AR.aff", + "dicSourcePath": "es/es_AR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_AR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_AR.dic", + "affSize": 171527, + "dicSize": 707817, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "e9a96514295f8664db270d024c345700ccb9410a384eb71aec0fe5f0931d8c70", + "dicSha256": "4fe3e193425bb3841ee218d36a9fc95d85b8daa8909363bdbba55a2f9f4e3d1d", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-BO", + "id": "es-BO", + "knownValidProbe": "casa", + "locales": [ + "es-BO" + ], + "label": "Spanish (es-BO)", + "affSourcePath": "es/es_BO.aff", + "dicSourcePath": "es/es_BO.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_BO.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_BO.dic", + "affSize": 162395, + "dicSize": 702886, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "c882b993a0ae83c94ab94c4b84a8f8300979e0e44fc4dceb2f15eaba521a30e7", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-CL", + "id": "es-CL", + "knownValidProbe": "casa", + "locales": [ + "es-CL" + ], + "label": "Spanish (es-CL)", + "affSourcePath": "es/es_CL.aff", + "dicSourcePath": "es/es_CL.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CL.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CL.dic", + "affSize": 162395, + "dicSize": 705568, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "e249a50ed9c9b939801bd2ba12099c9decb59217782c59fc65e7f72831b0b401", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-CO", + "id": "es-CO", + "knownValidProbe": "casa", + "locales": [ + "es-CO" + ], + "label": "Spanish (es-CO)", + "affSourcePath": "es/es_CO.aff", + "dicSourcePath": "es/es_CO.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CO.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CO.dic", + "affSize": 160081, + "dicSize": 751422, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "243d5dc50b68261dd10118799724beb95a6c19d4f9d6848ebfc977430bf2f8e2", + "dicSha256": "10f5e38e1c6898194cd860c237b1569725f721eb5eb0705e3a7158c69652c226", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-CR", + "id": "es-CR", + "knownValidProbe": "casa", + "locales": [ + "es-CR" + ], + "label": "Spanish (es-CR)", + "affSourcePath": "es/es_CR.aff", + "dicSourcePath": "es/es_CR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CR.dic", + "affSize": 162395, + "dicSize": 700936, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "073b27663394a297eb1c896419b5b5518bd5b345acfe244d00968433ad9709bd", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-CU", + "id": "es-CU", + "knownValidProbe": "casa", + "locales": [ + "es-CU" + ], + "label": "Spanish (es-CU)", + "affSourcePath": "es/es_CU.aff", + "dicSourcePath": "es/es_CU.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CU.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_CU.dic", + "affSize": 162395, + "dicSize": 702808, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "3fc1bb0eeffdb99ec8851166453b8d32745da51e9d1036c689f2512dd22c887c", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-DO", + "id": "es-DO", + "knownValidProbe": "casa", + "locales": [ + "es-DO" + ], + "label": "Spanish (es-DO)", + "affSourcePath": "es/es_DO.aff", + "dicSourcePath": "es/es_DO.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_DO.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_DO.dic", + "affSize": 162395, + "dicSize": 699651, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "194293e1785b2a0ce9b8166cdc4164afebc1ef57db92305786b32350fcb13832", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-EC", + "id": "es-EC", + "knownValidProbe": "casa", + "locales": [ + "es-EC" + ], + "label": "Spanish (es-EC)", + "affSourcePath": "es/es_EC.aff", + "dicSourcePath": "es/es_EC.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_EC.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_EC.dic", + "affSize": 162395, + "dicSize": 701539, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "caeea1b6bb09c80ca1ff36c81a02ca868fe709f330ac4303806cbf1cd7a6bc0b", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-ES", + "id": "es-ES", + "knownValidProbe": "casa", + "locales": [ + "es-ES" + ], + "label": "Spanish (es-ES)", + "affSourcePath": "es/es_ES.aff", + "dicSourcePath": "es/es_ES.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_ES.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_ES.dic", + "affSize": 169202, + "dicSize": 715989, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "e73a9bf8e1383f4986a5dc9e2fbed49371c0c61f511c626d15586bd433c1cad9", + "dicSha256": "6975dddec3d5d2c676069537bc67b4b5f786c65c5d4cf6703a82acf779ac9ec1", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-GQ", + "id": "es-GQ", + "knownValidProbe": "casa", + "locales": [ + "es-GQ" + ], + "label": "Spanish (es-GQ)", + "affSourcePath": "es/es_GQ.aff", + "dicSourcePath": "es/es_GQ.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_GQ.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_GQ.dic", + "affSize": 171524, + "dicSize": 835304, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "674c5a4b4d39fd3b4452f045a4e6e0649db4a2ce23f5903df8c311e21f1a757c", + "dicSha256": "967175eb16b2cccd8f1ed327098c279848840fff6fe0f729fcf614ec77c54380", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-GT", + "id": "es-GT", + "knownValidProbe": "casa", + "locales": [ + "es-GT" + ], + "label": "Spanish (es-GT)", + "affSourcePath": "es/es_GT.aff", + "dicSourcePath": "es/es_GT.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_GT.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_GT.dic", + "affSize": 162395, + "dicSize": 700565, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "2cdfcb8d86b70090b3f23f2fe2b6d9d6cfa5f76c803fa8229c674af2b87e6adc", + "dicSha256": "f424e3546db88d36b38bbc735fd01126296a4f7500ca1368d7017fac561107e7", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-HN", + "id": "es-HN", + "knownValidProbe": "casa", + "locales": [ + "es-HN" + ], + "label": "Spanish (es-HN)", + "affSourcePath": "es/es_HN.aff", + "dicSourcePath": "es/es_HN.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_HN.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_HN.dic", + "affSize": 162395, + "dicSize": 702581, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "a1fa7c74a68cb4e7746bae221dd53a27467c320a1cdc2d712cf55926896ee28d", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-MX", + "id": "es-MX", + "knownValidProbe": "casa", + "locales": [ + "es-MX" + ], + "label": "Spanish (es-MX)", + "affSourcePath": "es/es_MX.aff", + "dicSourcePath": "es/es_MX.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_MX.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_MX.dic", + "affSize": 160081, + "dicSize": 723507, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "d966cb748e4a688ed75ec84b50c0835ac438e5325ee4fce703a093794f9cba7e", + "dicSha256": "44ce35af220962c68f97962776639bef271f7d90a85ba924b539a36e33315f82", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-NI", + "id": "es-NI", + "knownValidProbe": "casa", + "locales": [ + "es-NI" + ], + "label": "Spanish (es-NI)", + "affSourcePath": "es/es_NI.aff", + "dicSourcePath": "es/es_NI.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_NI.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_NI.dic", + "affSize": 162395, + "dicSize": 701487, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "4d7ecc54d369aab904733e64729fffa42413412e14e6a27a32f7fbd56e9161b9", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-PA", + "id": "es-PA", + "knownValidProbe": "casa", + "locales": [ + "es-PA" + ], + "label": "Spanish (es-PA)", + "affSourcePath": "es/es_PA.aff", + "dicSourcePath": "es/es_PA.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PA.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PA.dic", + "affSize": 162395, + "dicSize": 700221, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "bd87e7e25b776d8fe96c4197360909b41d45289ec91c7c47eb000948c04a3ae2", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-PE", + "id": "es-PE", + "knownValidProbe": "casa", + "locales": [ + "es-PE" + ], + "label": "Spanish (es-PE)", + "affSourcePath": "es/es_PE.aff", + "dicSourcePath": "es/es_PE.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PE.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PE.dic", + "affSize": 160081, + "dicSize": 715404, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "d966cb748e4a688ed75ec84b50c0835ac438e5325ee4fce703a093794f9cba7e", + "dicSha256": "1d810a0a319fee329000538cf4df76621bb71228172558b87490f8b9c19b9d75", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-PH", + "id": "es-PH", + "knownValidProbe": "casa", + "locales": [ + "es-PH" + ], + "label": "Spanish (es-PH)", + "affSourcePath": "es/es_PH.aff", + "dicSourcePath": "es/es_PH.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PH.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PH.dic", + "affSize": 171524, + "dicSize": 797554, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "674c5a4b4d39fd3b4452f045a4e6e0649db4a2ce23f5903df8c311e21f1a757c", + "dicSha256": "ce05ef779b88e398b9949cb873ee3cf0827685884116d48250d157f50faeb9b3", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-PR", + "id": "es-PR", + "knownValidProbe": "casa", + "locales": [ + "es-PR" + ], + "label": "Spanish (es-PR)", + "affSourcePath": "es/es_PR.aff", + "dicSourcePath": "es/es_PR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PR.dic", + "affSize": 162395, + "dicSize": 699760, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "11e0815f41a25aac5d6871a13767b1c14a1c6ad5a7c40b359fc4c22f8297ff7f", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-PY", + "id": "es-PY", + "knownValidProbe": "casa", + "locales": [ + "es-PY" + ], + "label": "Spanish (es-PY)", + "affSourcePath": "es/es_PY.aff", + "dicSourcePath": "es/es_PY.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PY.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_PY.dic", + "affSize": 162395, + "dicSize": 700375, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "f9a18929f9e5234bc4aba83df1744351156932cb47b77b2ed3358c3170bb41ff", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-SV", + "id": "es-SV", + "knownValidProbe": "casa", + "locales": [ + "es-SV" + ], + "label": "Spanish (es-SV)", + "affSourcePath": "es/es_SV.aff", + "dicSourcePath": "es/es_SV.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_SV.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_SV.dic", + "affSize": 162395, + "dicSize": 700941, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "dc8213bb8fb08e51dd5869b348d873de23f89e3315656396ca3031fe1d7ffcea", + "dicSha256": "3a015f4469046d37806bf374c4d88149cdf570f467a60732f50d736f23d9cac5", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-US", + "id": "es-US", + "knownValidProbe": "casa", + "locales": [ + "es-US" + ], + "label": "Spanish (es-US)", + "affSourcePath": "es/es_US.aff", + "dicSourcePath": "es/es_US.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_US.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_US.dic", + "affSize": 171524, + "dicSize": 696235, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "674c5a4b4d39fd3b4452f045a4e6e0649db4a2ce23f5903df8c311e21f1a757c", + "dicSha256": "d46932a5c0ec3881fdf265333df4de45a73de51741baedcb5bb54d37b03979c8", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-UY", + "id": "es-UY", + "knownValidProbe": "casa", + "locales": [ + "es-UY" + ], + "label": "Spanish (es-UY)", + "affSourcePath": "es/es_UY.aff", + "dicSourcePath": "es/es_UY.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_UY.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_UY.dic", + "affSize": 162371, + "dicSize": 702491, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "d7ace3a7ef1fdf6dc89701d37f109730c0bc19aeaeda0ecf59fc67a1c5c28232", + "dicSha256": "9f05b75265a78bcd394993b7fee5f9f0e4031c41ce8915828c6fce8ee6579e13", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "es-VE", + "id": "es-VE", + "knownValidProbe": "casa", + "locales": [ + "es-VE" + ], + "label": "Spanish (es-VE)", + "affSourcePath": "es/es_VE.aff", + "dicSourcePath": "es/es_VE.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_VE.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/es/es_VE.dic", + "affSize": 160081, + "dicSize": 704472, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "d966cb748e4a688ed75ec84b50c0835ac438e5325ee4fce703a093794f9cba7e", + "dicSha256": "57eb3aa695c24e1f8f469ac86367b952194c08ee25bc2b761ba4681686ccc723", + "licenseDirectory": "licenses/es" + }, + { + "resourceId": "tr-TR", + "id": "tr-TR", + "knownValidProbe": "ev", + "locales": [ + "tr", + "tr-TR" + ], + "label": "Turkish (tr-TR)", + "affSourcePath": "tr_TR/tr_TR.aff", + "dicSourcePath": "tr_TR/tr_TR.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/tr_TR/tr_TR.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/tr_TR/tr_TR.dic", + "affSize": 2283891, + "dicSize": 36136702, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "a04a227b2ee45574000b876a1afa982e3436d49ebb97a7a796ddc5ec0cc8191b", + "dicSha256": "48e5352c5770956b24f355265aef7649b25bcb4d933c0b254ea8b419c241f4bd", + "licenseDirectory": "licenses/tr_TR" + }, + { + "resourceId": "uk-UA", + "id": "uk-UA", + "knownValidProbe": "дім", + "locales": [ + "uk-UA" + ], + "label": "Ukrainian (uk-UA)", + "affSourcePath": "uk_UA/uk_UA.aff", + "dicSourcePath": "uk_UA/uk_UA.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/uk_UA/uk_UA.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/uk_UA/uk_UA.dic", + "affSize": 211759, + "dicSize": 8919324, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "2219dd15e9802adebc45722c60943b1472640260491af38dd3e43b07e75585e6", + "dicSha256": "2e5a9e67be63bdb089b3459addb5d71113319d13768e277bcae20f3cc1ad5a93", + "licenseDirectory": "licenses/uk_UA" + }, + { + "resourceId": "vi-VN", + "id": "vi-VN", + "knownValidProbe": "nhà", + "locales": [ + "vi-VN" + ], + "label": "Vietnamese (vi-VN)", + "affSourcePath": "vi/vi_VN.aff", + "dicSourcePath": "vi/vi_VN.dic", + "affDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/vi/vi_VN.aff", + "dicDownloadUrl": "https://raw.githubusercontent.com/LibreOffice/dictionaries/32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4/vi/vi_VN.dic", + "affSize": 788, + "dicSize": 39852, + "sourceRevision": "32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4", + "affSha256": "b58b31ba3cfbf1c5a3730f2cceb8652604180770020f291d2cf6c6fecc9721f4", + "dicSha256": "21d59c8385d2ac8d708bc5dfe83b62753d7769a8b2c9c38d319ce5c57bfba0c7", + "licenseDirectory": "licenses/vi" + } + ], + "attributions": [ + "licenses/ar/COPYING.txt", + "licenses/ar/README_ar.txt", + "licenses/de/COPYING_GPLv2", + "licenses/de/COPYING_GPLv3", + "licenses/de/COPYING_LGPL_v2.0.txt", + "licenses/de/COPYING_LGPL_v2.1.txt", + "licenses/de/COPYING_OASIS.txt", + "licenses/de/README_de_DE_frami.txt", + "licenses/de/README_extension_owner.txt", + "licenses/de/README_hyph_de.txt", + "licenses/de/README_thesaurus.txt", + "licenses/en/README.txt", + "licenses/en/README_en_AU.txt", + "licenses/en/README_en_CA.txt", + "licenses/en/README_en_GB.txt", + "licenses/en/README_en_GB_thes.txt", + "licenses/en/README_en_US.txt", + "licenses/en/README_en_ZA.txt", + "licenses/en/README_hyph_en_GB.txt", + "licenses/en/README_hyph_en_US.txt", + "licenses/en/README_lightproof_en.txt", + "licenses/en/WordNet_license.txt", + "licenses/en/license.txt", + "licenses/es/LICENSE.md", + "licenses/es/README_hunspell_es.txt", + "licenses/es/README_hyph_es.txt", + "licenses/es/README_th_es.txt", + "licenses/et_EE/README_et_EE.txt", + "licenses/et_EE/README_hyph_et_EE.txt", + "licenses/fa_IR/LICENSE", + "licenses/fa_IR/README_fa_IR.txt", + "licenses/fr_FR/dictionaries/README_dict_fr.txt", + "licenses/fr_FR/dictionaries/README_hyph_fr.txt", + "licenses/fr_FR/dictionaries/README_thes_fr.txt", + "licenses/hi_IN/COPYING", + "licenses/hi_IN/README_hi_IN.txt", + "licenses/id/LICENSE-dict", + "licenses/id/LICENSE-thes", + "licenses/id/README-dict.adoc", + "licenses/id/README-thes", + "licenses/it_IT/README_hyph_it_IT.txt", + "licenses/it_IT/README_it_IT.txt", + "licenses/it_IT/README_th_it_IT.txt", + "licenses/it_IT/legacy/it_IT_COPYING", + "licenses/it_IT/legacy/it_IT_README.1st", + "licenses/it_IT/legacy/it_IT_README.txt", + "licenses/it_IT/legacy/it_IT_license.txt", + "licenses/it_IT/legacy/th_it_IT_COPYING", + "licenses/it_IT/legacy/th_it_IT_README", + "licenses/ko_KR/README_ko_KR.txt", + "licenses/nl_NL/LICENSE.txt", + "licenses/nl_NL/README.md", + "licenses/no/COPYING", + "licenses/no/README", + "licenses/no/README_NO.txt", + "licenses/no/README_hyph_NO.txt", + "licenses/pl_PL/README_en.txt", + "licenses/pl_PL/README_pl.txt", + "licenses/pl_PL/README_pl_PL.txt", + "licenses/pt_BR/README_Lightproof_pt_BR.txt", + "licenses/pt_BR/README_en.txt", + "licenses/pt_BR/README_hyph_pt_BR.txt", + "licenses/pt_BR/README_pt_BR.txt", + "licenses/pt_BR/license-thes.readme", + "licenses/ru_RU/README_Lightproof_ru_RU.txt", + "licenses/ru_RU/README_ru_RU.txt", + "licenses/ru_RU/README_thes_ru_RU_M_aot_and_v2.txt", + "licenses/tr_TR/LICENSE", + "licenses/tr_TR/README.txt", + "licenses/uk_UA/README_hyph_uk_UA.txt", + "licenses/uk_UA/README_th_uk_UA.txt", + "licenses/uk_UA/README_uk_UA.txt", + "licenses/vi/LICENSES-en.txt", + "licenses/vi/LICENSES-vi.txt" + ] +} diff --git a/assets/spelling/licenses/ar/COPYING.txt b/assets/spelling/licenses/ar/COPYING.txt new file mode 100644 index 00000000..90c5d98f --- /dev/null +++ b/assets/spelling/licenses/ar/COPYING.txt @@ -0,0 +1,9 @@ +GPL 2.0/LGPL 2.1/MPL 1.1 tri-license + +The contents of this software may be used under the terms of 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") the Mozilla Public License Version 1.1 or later (the "MPL"). + +Software distributed under these licenses is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the licences +for the specific language governing rights and limitations under the licenses. + + diff --git a/assets/spelling/licenses/ar/README_ar.txt b/assets/spelling/licenses/ar/README_ar.txt new file mode 100644 index 00000000..4496ee2b --- /dev/null +++ b/assets/spelling/licenses/ar/README_ar.txt @@ -0,0 +1,14 @@ +Arabic Spellchecker for Openoffice.org 3.0 +------------------------------------------ + +Welcome! + +This is a package I made for Openoffice.org Arabic spellchecker. I did NOT write this checker, I merely packaged the checker provided by the Ayaspell project[1] into a format recognized by Openoffice.org 3.0. + +Any improvements are welcome. + +[1] http://ayaspell.sourceforge.net/ + + +-- +Ahmad Farghal | ahmad.farghal@gmail.com diff --git a/assets/spelling/licenses/de/COPYING_GPLv2 b/assets/spelling/licenses/de/COPYING_GPLv2 new file mode 100644 index 00000000..a8cab035 --- /dev/null +++ b/assets/spelling/licenses/de/COPYING_GPLv2 @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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) year + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/assets/spelling/licenses/de/COPYING_GPLv3 b/assets/spelling/licenses/de/COPYING_GPLv3 new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/assets/spelling/licenses/de/COPYING_GPLv3 @@ -0,0 +1,674 @@ + 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 +. diff --git a/assets/spelling/licenses/de/COPYING_LGPL_v2.0.txt b/assets/spelling/licenses/de/COPYING_LGPL_v2.0.txt new file mode 100644 index 00000000..5bc8fb2c --- /dev/null +++ b/assets/spelling/licenses/de/COPYING_LGPL_v2.0.txt @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/assets/spelling/licenses/de/COPYING_LGPL_v2.1.txt b/assets/spelling/licenses/de/COPYING_LGPL_v2.1.txt new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/assets/spelling/licenses/de/COPYING_LGPL_v2.1.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/assets/spelling/licenses/de/COPYING_OASIS.txt b/assets/spelling/licenses/de/COPYING_OASIS.txt new file mode 100644 index 00000000..47c1c2bb --- /dev/null +++ b/assets/spelling/licenses/de/COPYING_OASIS.txt @@ -0,0 +1,14 @@ +OASIS distribution license agreement 0.1 from 2005-11-10 + +Without any modifications this dictionary may be distributed with programs that +support the OASIS Open Document Format for Office Applications and whose +PRIMARY format for saving documents is the Open Document Format. + +This requires that all licenses and copyright files are also distributed together +with the package the dictionary is shipped with. + +Any modifications of the dictionary files are not allowed for this +agreement, modifications require the use of the GNU GENERAL PUBLIC LICENSE. + +If you have questions or don't get along with this, send me your +comments/questions/ideas to Bjoern Jacke diff --git a/assets/spelling/licenses/de/README_de_DE_frami.txt b/assets/spelling/licenses/de/README_de_DE_frami.txt new file mode 100644 index 00000000..43d6c6c4 --- /dev/null +++ b/assets/spelling/licenses/de/README_de_DE_frami.txt @@ -0,0 +1,17 @@ +Bei dem Wörterbuch xxx_frami handelt es sich um ein Addon. Es enthält +alle Wörter des Basiswörterbuchs, zusätzlich jedoch etliche, die entweder +im Basiswörterbuch noch fehlen oder die nicht unbedingt zum Kernwortschatz +des Deutschen gehören. Die zusätzlichen Aufnahmen sind ungeprüft. +Dieses Wörterbuch basiert auf dem igerman98 Ispell-Wörterbuch, zu finden +unter https://www.j3e.de/ispell/igerman98/ . + +Das Wörterbuch und alle enthaltenen Wortlisten sind lizenziert unter der +GNU GPL, Version 2 oder 3. +Fehlermeldungen oder Ergänzungswünsche können gemailt werden an: +Franz Michael Baumann + +Autor des Grundwörterbuchs: +Bjoern Jacke + +Autor der Erweiterung +Franz Michael Baumann diff --git a/assets/spelling/licenses/de/README_extension_owner.txt b/assets/spelling/licenses/de/README_extension_owner.txt new file mode 100644 index 00000000..822409cc --- /dev/null +++ b/assets/spelling/licenses/de/README_extension_owner.txt @@ -0,0 +1,47 @@ + +COMMENT OF THE EXTENSION OWNER (KARL ZEILER) + + +Compatibility +============= +This extension is compatible with: +- Apache OpenOffice (Versions 3.3, 3.4; 4.0, 4.1) +- LibreOffice (Versions 3.3, 3.4, 3.5, 3.6; 4.0, 4.1, 4.2, 4.3, 4.4; 5.0, 5.1, 5.2) +- OpenOffice.org (Versions 3.0 or later) + +Spell checking +============== +de-DE_frami +Version: 2017-01-09 +Author: Franz Michael Baumann +Based on igerman98 dictionary: +Version: 2016-12-07 +Author: Björn Jacke + Download: https://www.j3e.de/ispell/igerman98/dict/ +License: GNU GPL Version 2 or GPL Version 3 or OASIS 0.1 + +The frami dictionary contains the complete word list of igerman98 +and in addition numerous supplements by Franz Michael Baumann according to +the reform of 2006-08-01. + +Hyphenation +=========== +Version: 2017-01-12 + New: using the COMPOUND feature for improved hyphenation + New: list with over 69,000 words and compounds by Karl Zeiler +Authors: Marco Huggenberger + Daniel Naber + Karl Zeiler +License: GNU LGPL Version 2.1 or later + +Thesaurus +========= +OpenThesaurus - Deutscher Thesaurus - Synonyme und Assoziationen +Version: 2017-01-06 DE +License: GNU LGPL Version 2.1 or later +https://www.openthesaurus.de/ + +Please note +=========== +Detecting errors or missing words, please contact the extension owner: +Karl Zeiler diff --git a/assets/spelling/licenses/de/README_hyph_de.txt b/assets/spelling/licenses/de/README_hyph_de.txt new file mode 100644 index 00000000..8921caef --- /dev/null +++ b/assets/spelling/licenses/de/README_hyph_de.txt @@ -0,0 +1,42 @@ +Hyphenation dictionary "hyph_de_DE.dic" +--------------------------------------- + +Language: German (de DE) + according to the reform of 2006-08-01 (i.e. reformed or new spelling) + +Version: 2017-01-12 + New: using the COMPOUND feature for improved hyphenation + New: list with over 69,000 words and compounds by Karl Zeiler + +Origin: Based on the TeX hyphenation tables "dehyphn.tex", revision level 31. + http://www.ctan.org/tex-archive/language/hyphenation/dehyphn.tex + The TeX hyphenation tables are released under the LaTeX Project + Public License (LPPL) + +License: OpenOffice.org Adaptions of this package are licensed under the + GNU Lesser General Public License (LGPL 2 or later) and are under + Copyright by + +Author: conversion author: Marco Huggenberger + revised conversion and extensions: Daniel Naber + improvements: Karl Zeiler + +Note: This dictionary is based on syllable matching patterns + and thus should be suitable under other variations of German: + HYPH de AT hyph_de_AT + HYPH de CH hyph_de_CH + + +Trennmuster (hyph_de_DE.dic) +---------------------------- + +Die Trennmuster (hyph_de_DE.dic) basieren auf den TeX Trennmustern +"dehyphn.tex", revision level 31. +Lizenz der Trennmuster: LPPL. Die Anpassung der Trennmuster an +den in OpenOffice.org benutzten "ALTLinux LibHnj Hyphenator" wurde +mit dem Script substrings.pl durchgeführt, das unter +https://www.openoffice.org/lingucomponent/hyphenator.html als Teil +der Datei altlinux_Hyph.zip heruntergeladen werden kann. +Die Original-Trennmuster können hier heruntergeladen werden: +https://www.ctan.org/tex-archive/language/hyphenation/dehyphn.tex + diff --git a/assets/spelling/licenses/de/README_thesaurus.txt b/assets/spelling/licenses/de/README_thesaurus.txt new file mode 100644 index 00000000..9bdaebf7 --- /dev/null +++ b/assets/spelling/licenses/de/README_thesaurus.txt @@ -0,0 +1,524 @@ +OpenThesaurus - Deutscher Thesaurus - Version für OpenOffice.org +Copyright (C) 2003-2017 Daniel Naber (naber at danielnaber de) +Snapshot, automatisch generiert 2017-01-06 23:22 (DE/AT) +Homepage: http://www.openthesaurus.de + + +This library 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 2.1 of the License, or (at your option) any later version. + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Lizenz: =================================================================== + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/assets/spelling/licenses/en/README.txt b/assets/spelling/licenses/en/README.txt new file mode 100644 index 00000000..16ef20b5 --- /dev/null +++ b/assets/spelling/licenses/en/README.txt @@ -0,0 +1,76 @@ +OpenOffice.org Hunspell en_US dictionary +2010-03-09 release + +-- +This dictionary is based on a subset of the original +English wordlist created by Kevin Atkinson for Pspell +and Aspell and thus is covered by his original +LGPL license. The affix file is a heavily modified +version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as +such is covered by his BSD license. + +Thanks to both authors for there wonderful work. + +ChangeLog + +2010-03-09 (nemeth AT OOo) + - UTF-8 encoded dictionary: + - fix em-dash problem of OOo 3.2 by BREAK + - suggesting words with typographical apostrophes + - recognizing words with Unicode f ligatures + - add phonetic suggestion (Copyright (C) 2000 Björn Jacke, see the end of the file) + +2007-08-29 nemeth AT OOo + +Mozilla 376296 - add "axe" (variant of ax) +Mozilla 386259 - add "JavaScript" +Mozilla 383694 - add "foci" and "octopi" (plurals of focus and octopus) +Issue 73024 - add "gauge" +Issue 75710 - add "foldable" +Issue 75772 - add "GHz" +Mozilla 379527 and Issue 62294 - add "dialogue" +Issue 64246 - add "acknowledgement" as a variant of "acknowledgment" + +- TRY extended with apostrophe and dash for + dont -> don't + alltime -> all-time suggestions +- new REP suggestions: +- REP alot a_lot (alot -> a lot) +for suggestion) +- REP nt n't (dont -> don't) +- REP avengence -> a_vengeance (avengence -> a vengeance) +- REP ninties 1990s +- REP tion ssion: readmition -> readmission + +- add Mozilla words (blog, cafe, inline, online, eBay, PayPal, etc.) +- add cybercafé +- alias compression (saving 15 kB disk space + 0.8 MB memory) + +Mozilla 355178 - add scot-free +Mozilla 374411 - add Scotty +Mozilla 359305 - add archaeology, archeological, archeologist +Mozilla 358754 - add doughnut +Mozilla 254814 - add gauging, canoeing, *canoing, proactively +Issue 71718 - remove *opthalmic, *opthalmology; *opthalmologic -> ophthalmologic +Issue 68550 - *estoppal -> estoppel +Issue 69345 - add tapenade +Issue 67975 - add assistive +Issue 63541 - remove *dessicate +Issue 62599 - add toolbar + +2006-02-07 nemeth AT OOo + +Issue 48060 - add ordinal numbers with COMPOUNDRULE (1st, 11th, 101st etc.) +Issue 29112, 55498 - add NOSUGGEST flags to taboo words +Issue 56755 - add sequitor (non sequitor) +Issue 50616 - add open source words (GNOME, KDE, OOo, OpenOffice.org) +Issue 56389 - add Mozilla words (Mozilla, Firefox, Thunderbird) +Issue 29110 - add okay +Issue 58468 - add advisors +Issue 58708 - add hiragana & katakana +Issue 60240 - add arginine, histidine, monovalent, polymorphism, pyroelectric, pyroelectricity + +2005-11-01 dnaber AT OOo + +Issue 25797 - add proven, advisor, etc. diff --git a/assets/spelling/licenses/en/README_en_AU.txt b/assets/spelling/licenses/en/README_en_AU.txt new file mode 100644 index 00000000..8e870199 --- /dev/null +++ b/assets/spelling/licenses/en/README_en_AU.txt @@ -0,0 +1,347 @@ +en_AU Hunspell Dictionary +Version 2020.12.07 +Mon Dec 7 20:14:35 2020 -0500 [5ef55f9] +http://wordlist.sourceforge.net + +README file for English Hunspell dictionaries derived from SCOWL. + +These dictionaries are created using the speller/make-hunspell-dict +script in SCOWL. + +The following dictionaries are available: + + en_US (American) + en_CA (Canadian) + en_GB-ise (British with "ise" spelling) + en_GB-ize (British with "ize" spelling) + en_AU (Australian) + + en_US-large + en_CA-large + en_GB-large (with both "ise" and "ize" spelling) + en_AU-large + +The normal (non-large) dictionaries correspond to SCOWL size 60 and, +to encourage consistent spelling, generally only include one spelling +variant for a word. The large dictionaries correspond to SCOWL size +70 and may include multiple spelling for a word when both variants are +considered almost equal. The larger dictionaries however (1) have not +been as carefully checked for errors as the normal dictionaries and +thus may contain misspelled or invalid words; and (2) contain +uncommon, yet valid, words that might cause problems as they are +likely to be misspellings of more common words (for example, "ort" and +"calender"). + +To get an idea of the difference in size, here are 25 random words +only found in the large dictionary for American English: + + Bermejo Freyr's Guenevere Hatshepsut Nottinghamshire arrestment + crassitudes crural dogwatches errorless fetial flaxseeds godroon + incretion jalapeño's kelpie kishkes neuroglias pietisms pullulation + stemwinder stenoses syce thalassic zees + +The en_US, en_CA and en_AU are the official dictionaries for Hunspell. +The en_GB and large dictionaries are made available on an experimental +basis. If you find them useful please send me a quick email at +kevina@gnu.org. + +If none of these dictionaries suite you (for example, maybe you want +the normal dictionary that also includes common variants) additional +dictionaries can be generated at http://app.aspell.net/create or by +modifying speller/make-hunspell-dict in SCOWL. Please do let me know +if you end up publishing a customized dictionary. + +If a word is not found in the dictionary or a word is there you think +shouldn't be, you can lookup the word up at http://app.aspell.net/lookup +to help determine why that is. + +General comments on these list can be sent directly to me at +kevina@gnu.org or to the wordlist-devel mailing lists +(https://lists.sourceforge.net/lists/listinfo/wordlist-devel). If you +have specific issues with any of these dictionaries please file a bug +report at https://github.com/kevina/wordlist/issues. + +IMPORTANT CHANGES INTRODUCED In 2016.11.20: + +New Australian dictionaries thanks to the work of Benjamin Titze +(btitze@protonmail.ch). + +IMPORTANT CHANGES INTRODUCED IN 2016.04.24: + +The dictionaries are now in UTF-8 format instead of ISO-8859-1. This +was required to handle smart quotes correctly. + +IMPORTANT CHANGES INTRODUCED IN 2016.01.19: + +"SET UTF8" was changes to "SET UTF-8" in the affix file as some +versions of Hunspell do not recognize "UTF8". + +ADDITIONAL NOTES: + +The NOSUGGEST flag was added to certain taboo words. While I made an +honest attempt to flag the strongest taboo words with the NOSUGGEST +flag, I MAKE NO GUARANTEE THAT I FLAGGED EVERY POSSIBLE TABOO WORD. +The list was originally derived from Németh László, however I removed +some words which, while being considered taboo by some dictionaries, +are not really considered swear words in today's society. + +COPYRIGHT, SOURCES, and CREDITS: + +The English dictionaries come directly from SCOWL +and is thus under the same copyright of SCOWL. The affix file is +a heavily modified version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as such is covered by +his BSD license. Part of SCOWL is also based on Ispell thus the +Ispell copyright is included with the SCOWL copyright. + +The collective work is Copyright 2000-2018 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2018 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + 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. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING 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 GEOFF KUENNING 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. + +Build Date: Mon Dec 7 20:19:31 EST 2020 +Wordlist Command: mk-list --accents=strip en_AU 60 diff --git a/assets/spelling/licenses/en/README_en_CA.txt b/assets/spelling/licenses/en/README_en_CA.txt new file mode 100644 index 00000000..e1777310 --- /dev/null +++ b/assets/spelling/licenses/en/README_en_CA.txt @@ -0,0 +1,347 @@ +en_CA Hunspell Dictionary +Version 2020.12.07 +Mon Dec 7 20:14:35 2020 -0500 [5ef55f9] +http://wordlist.sourceforge.net + +README file for English Hunspell dictionaries derived from SCOWL. + +These dictionaries are created using the speller/make-hunspell-dict +script in SCOWL. + +The following dictionaries are available: + + en_US (American) + en_CA (Canadian) + en_GB-ise (British with "ise" spelling) + en_GB-ize (British with "ize" spelling) + en_AU (Australian) + + en_US-large + en_CA-large + en_GB-large (with both "ise" and "ize" spelling) + en_AU-large + +The normal (non-large) dictionaries correspond to SCOWL size 60 and, +to encourage consistent spelling, generally only include one spelling +variant for a word. The large dictionaries correspond to SCOWL size +70 and may include multiple spelling for a word when both variants are +considered almost equal. The larger dictionaries however (1) have not +been as carefully checked for errors as the normal dictionaries and +thus may contain misspelled or invalid words; and (2) contain +uncommon, yet valid, words that might cause problems as they are +likely to be misspellings of more common words (for example, "ort" and +"calender"). + +To get an idea of the difference in size, here are 25 random words +only found in the large dictionary for American English: + + Bermejo Freyr's Guenevere Hatshepsut Nottinghamshire arrestment + crassitudes crural dogwatches errorless fetial flaxseeds godroon + incretion jalapeño's kelpie kishkes neuroglias pietisms pullulation + stemwinder stenoses syce thalassic zees + +The en_US, en_CA and en_AU are the official dictionaries for Hunspell. +The en_GB and large dictionaries are made available on an experimental +basis. If you find them useful please send me a quick email at +kevina@gnu.org. + +If none of these dictionaries suite you (for example, maybe you want +the normal dictionary that also includes common variants) additional +dictionaries can be generated at http://app.aspell.net/create or by +modifying speller/make-hunspell-dict in SCOWL. Please do let me know +if you end up publishing a customized dictionary. + +If a word is not found in the dictionary or a word is there you think +shouldn't be, you can lookup the word up at http://app.aspell.net/lookup +to help determine why that is. + +General comments on these list can be sent directly to me at +kevina@gnu.org or to the wordlist-devel mailing lists +(https://lists.sourceforge.net/lists/listinfo/wordlist-devel). If you +have specific issues with any of these dictionaries please file a bug +report at https://github.com/kevina/wordlist/issues. + +IMPORTANT CHANGES INTRODUCED In 2016.11.20: + +New Australian dictionaries thanks to the work of Benjamin Titze +(btitze@protonmail.ch). + +IMPORTANT CHANGES INTRODUCED IN 2016.04.24: + +The dictionaries are now in UTF-8 format instead of ISO-8859-1. This +was required to handle smart quotes correctly. + +IMPORTANT CHANGES INTRODUCED IN 2016.01.19: + +"SET UTF8" was changes to "SET UTF-8" in the affix file as some +versions of Hunspell do not recognize "UTF8". + +ADDITIONAL NOTES: + +The NOSUGGEST flag was added to certain taboo words. While I made an +honest attempt to flag the strongest taboo words with the NOSUGGEST +flag, I MAKE NO GUARANTEE THAT I FLAGGED EVERY POSSIBLE TABOO WORD. +The list was originally derived from Németh László, however I removed +some words which, while being considered taboo by some dictionaries, +are not really considered swear words in today's society. + +COPYRIGHT, SOURCES, and CREDITS: + +The English dictionaries come directly from SCOWL +and is thus under the same copyright of SCOWL. The affix file is +a heavily modified version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as such is covered by +his BSD license. Part of SCOWL is also based on Ispell thus the +Ispell copyright is included with the SCOWL copyright. + +The collective work is Copyright 2000-2018 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2018 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + 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. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING 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 GEOFF KUENNING 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. + +Build Date: Mon Dec 7 20:19:28 EST 2020 +Wordlist Command: mk-list --accents=strip en_CA 60 diff --git a/assets/spelling/licenses/en/README_en_GB.txt b/assets/spelling/licenses/en/README_en_GB.txt new file mode 100644 index 00000000..505bc27b --- /dev/null +++ b/assets/spelling/licenses/en/README_en_GB.txt @@ -0,0 +1,262 @@ +This dictionary was initially based on a subset of the +original English wordlist created by Kevin Atkinson for +Pspell and Aspell, and thus is covered by his original +LGPL licence. + +It has been extensively updated by David Bartlett, Brian Kelk, +Andrew Brown and Marco A.G.Pinto: + — Numerous Americanisms/spellings have been removed; + — Missing words have been added; + — Many errors have been corrected; + — Compound hyphenated words have been added where appropriate; + — Thousands of proper/places names have been added; + — Thousands of possessives have been added; + — Thousands of plurals have been added; + — Thousands of duplicates have been removed. + +Valuable inputs to this process were received from many other +people — far too numerous to name. Serious thanks to all for +your greatly appreciated help. + +This wordlist is intended to be a good representation of +current modern British English, and thus it should be a good +basis for Commonwealth English in most countries of the world +outside North America. + +The affix file has been created completely from scratch +by David Bartlett and Andrew Brown, based on the published +rules for MySpell and is also provided under the LGPL. + +In creating the affix rules, an attempt has been made to +reproduce the most general rules for English word +formation, rather than merely use it to compress the +size of the dictionary. It is hoped that this will +facilitate future localisation to other variants of English. + +------- + +This is a locally hosted copy of the English dictionaries with fixed +dash handling and new ligature and phonetic suggestion support extension: +https://extensions.openoffice.org/en/node/3785 + +Original version of the en_GB dictionary: +https://bz.apache.org/ooo/show_bug.cgi?id=72145 + +OpenOffice.org patch and morphological extension. + +The morphological extension based on Wordlist POS and AGID data +created by Kevin Atkinson and released on http://wordlist.sourceforge.net. + +Other fixes: +OOo Issue 48060 — add numbers with affixes by COMPOUNDRULE (1st, 111th, 1990s etc.) +OOo Issue 29112, 55498 — add NOSUGGEST flags to taboo words +New REP items (better suggestions for accented words and a few mistakes) +OOo Issue 63541 — remove *dessicated + +------- +2025-02-23 (Marco A.G.Pinto) + - Unified the ZA and GB .AFF file. + +2025-02-22 (Marco A.G.Pinto) + - Taken from ZA .AFF: #PHONEtic transformation rules for use with #PHONEtic.c. + +2025-02-20 (Marco A.G.Pinto) + - New icon for Mozilla (GB) in 96×96 and for LibreOffice/OpenOffice in 128×128. + +2025-01-23 (Marco A.G.Pinto) + - Fixed/improved: flag “O” and “W”. + +2024-12-17: + - “REP si ci” and merged/sorted REP GB/ZA (Shantanu Oak): https://bugs.documentfoundation.org/show_bug.cgi?id=152554 . + - Copied the ICONV and OCONV from ZA. + +2024-04-02: + — Improved flag “S”, increasing the wordlist in 13 valid words. + +2023-10-26: + — Improved flag “J”, increasing the wordlist in 70 valid words. + +2023-10-07: + — Improved flag “-”, increasing the wordlist in 128 valid words. + +2023-10-03: + — Improved flag “q”, increasing the wordlist in 126 valid words. + +2023-09-03: + — Improved flag “N”, increasing the wordlist in 596 valid words. + +2023-05-23: + — Improved flag “J”. + +2023-05-17: + — Improved flag “W”. + +2023-05-07: + — Improved flag “O”. + +2023-03-01: + — Removed most of the possessives of plurals ending with “s”. + +2023-02-14: + — Improved flag “W”. + +2023-02-02: + — Added flag “~” for “ish” ending words. + — Improved flag “J” (“ings” → “ing's” and “ings”), increasing the wordlist in ~490 valid words. + +2023-01-01: + — Sorted alphabetically the tags of the .aff, so the order of words in the wordlist changed. + +2020-11-01: + — Added the State and union territory capitals in India: + — https://en.wikipedia.org/wiki/List_of_state_and_union_territory_capitals_in_India + +2019-11-01+: + — Added thousands of possessives and plurals. + — Improved flags: “1”, “3”, “N”, “O”, “W”. + +2019-07-01+: + — Major clean-up of the .dic by removing thousands of duplicates, merging flags, adding + possessives and plurals. + — Improved flags: “i”, “n”, “N”, “O”, “W”, “Z”, “2” and “3”: + — Flag “2” increased the wordlist in ~400 valid words; + — Flag “i” increased the wordlist in ~200 valid words; + — Flag “n” increased the wordlist in ~1000 valid words. + +2019-04-01: + — Improved flag “P” thanks to Ding-adong, giving also -nesses which + increased the wordlist in ~1800 valid words. + +2019-03-01: + — Added the LGPL_V3 License .txt into the Extension. + — Ding-adong added a flag “=” for suffixes: -lessness, -lessnesses, -lessness's. + — Ding-adong changed the prefix flag “O” to “^” since “O” was both prefix and suffix. + — Small fixes and enhancements on flags “z” and “O” by Ding-adong. + +2019-02-01: + — Improved flag “5” thanks to the GitHub user Ding-adong: + Some “swomen's” and “women's” entries were missing. + — Fixed flag “3”: -ists, -ists, -ist's → -ist, -ists, -ist's. + — Improved flag “N”. + +2018-12-01: + — Added the cities from Canada: + — https://en.wikipedia.org/wiki/List_of_cities_in_Canada + +2018-10-01: + — Added the cities from Australia by population: + — https://en.wikipedia.org/wiki/List_of_cities_in_Australia_by_population + — Added tons of cities from the US with a 10 000+ population. + This list was supplied by Michael Holroyd on Kevin Atkinson's GitHub. + — Added tons of possessives to nouns, thanks to Jörg Knobloch. + +2018-06-01+: + — Added places from New Zealand/UK (England, Scotland, Wales & Northern Ireland): + On V2.61–2.64 I included tons of place names. + My scientist friend, Peter McGavin, told me that in NZ they use British, so I decided + to do something about it. I did the same for the UK. I searched on Wikipedia for “towns”, + “counties”, “villages”, “boroughs”, “suburbs”, etc. and based me on: + — https://en.wikipedia.org/wiki/List_of_towns_in_England; + — https://en.wikipedia.org/wiki/List_of_towns_in_New_Zealand; + — https://en.wikipedia.org/wiki/List_of_civil_parishes_in_England; + — https://en.wikipedia.org/wiki/List_of_civil_parishes_in_Scotland; + — https://en.wikipedia.org/wiki/List_of_places_in_Scotland; + — https://en.wikipedia.org/wiki/List_of_communities_in_Wales; + — https://en.wikipedia.org/wiki/Local_government_in_Wales; + — https://en.wikipedia.org/wiki/List_of_towns_and_villages_in_Northern_Ireland; + — https://en.wikipedia.org/wiki/Counties_of_Northern_Ireland; + — https://en.wikipedia.org/wiki/Category:Suburbs_in_New_Zealand; + — https://en.wikipedia.org/wiki/List_of_Church_of_Scotland_parishes. + Furthermore, added places sent to me by Peter C.: + © OpenStreetMap contributors: www.openstreetmap.org/copyright. + © The Clergy of the Church of England Database Project, 2005. + +2018-08-01: + — Slightly higher quality icon + — Added tons of drug names supplied by the user Andrew Ziem on Kevin's GitHub + — Fixed/improved flag “5”: “women's” was missing + +2018-05-01: + — Andrew Ziem suggested a list of 328 names of famous people on Kevin's GitHub: + “These 328 name tokens were derived from the top 100 lists in Google Trends via + this repository (https://github.com/az0/google-trend-names). The geography was + set to US, and it spanned dates from 2004 to 2018.” + +2017-12-16: + — Added to the .AFF: + ICONV 1 + ICONV ’ ' + Thanks to Jeroen Ooms + +2017-10-08: + — Mozilla: used * to work with all future + versions, except Thunderbird + +2016-09-11: + — .AFF + .DIC now use UNIX line endings + +2016-08-01: + — GB changelog is no longer included in the README file + +2016-06-21: + — COMPOUNDING added to this clean version of the GB .AFF (Áron Budea) + +2016-06-10: + — NOSUGGEST added to this clean version of the GB .AFF (Marco A.G.Pinto) + +2013-08-25: + — GB forked by Marco A.G.Pinto + +2010-03-09 (nemeth AT OOo): + — UTF-8 encoded dictionary: + — Fix em-dash problem of OOo 3.2 by BREAK + — Suggesting words with typographical apostrophes + — Recognising words with Unicode f ligatures + — Add phonetic suggestion (© 2000 Björn Jacke) + +2008-12-18: + — NOSUGGEST, NUMBER/COMPOUNDRULE patches (nemeth AT OOo) + +------- + +MARCO A.G.PINTO: +Since the dictionary wasn't updated for many years, I forked it in 2013 to add new words and fixes. + +I grabbed Mozilla's version, since it wasn't obfuscated. Alexandro Colorado and I +tried to unmunch the OpenOffice version, but all we got was rubbish. + +The dictionary icon in the Extension Manager was designed by Pedro Ribeiro Marques. + +The sources used to verify the spelling of the words I included in the dictionary: + 1) Oxford Dictionaries; + 2) Collins Dictionary; + 3) Cambridge Dictionary; + 4) Merriam-Webster Dictionary (used with caution ⚠); + 5) Wiktionary (used with caution ⚠); + 6) Wikipedia (used with caution ⚠); + 7) Physical dictionaries. + +Main difficulties developing this dictionary: + 1) Proper names; + 2) Possessive forms; + 3) Plurals. + +Please let Marco A.G.Pinto know of any errors that you find: +E-mail: +marcoagpinto@sapo.pt + +Website: +https://proofingtoolgui.org + +FAQ: +https://proofingtoolgui.org/faq.html + +FAQ (“movie”, “automobile”, “airplane”, “hardcover” and “bookstore”): +https://proofingtoolgui.org/faq.html#7 +Notice: Due to complaints, “movie” was added on V2.57 since it is a widely used word. + +Changelog: +https://proofingtoolgui.org/en_GB_CHANGES.txt + +Nightly changes/latest releases (GitHub): +https://github.com/marcoagpinto/aoo-mozilla-en-dict diff --git a/assets/spelling/licenses/en/README_en_GB_thes.txt b/assets/spelling/licenses/en/README_en_GB_thes.txt new file mode 100644 index 00000000..aff398af --- /dev/null +++ b/assets/spelling/licenses/en/README_en_GB_thes.txt @@ -0,0 +1 @@ +en_GB is using the WordNet thesaurus from the en_US directory. diff --git a/assets/spelling/licenses/en/README_en_US.txt b/assets/spelling/licenses/en/README_en_US.txt new file mode 100644 index 00000000..4585c30c --- /dev/null +++ b/assets/spelling/licenses/en/README_en_US.txt @@ -0,0 +1,347 @@ +en_US Hunspell Dictionary +Version 2020.12.07 +Mon Dec 7 20:14:35 2020 -0500 [5ef55f9] +http://wordlist.sourceforge.net + +README file for English Hunspell dictionaries derived from SCOWL. + +These dictionaries are created using the speller/make-hunspell-dict +script in SCOWL. + +The following dictionaries are available: + + en_US (American) + en_CA (Canadian) + en_GB-ise (British with "ise" spelling) + en_GB-ize (British with "ize" spelling) + en_AU (Australian) + + en_US-large + en_CA-large + en_GB-large (with both "ise" and "ize" spelling) + en_AU-large + +The normal (non-large) dictionaries correspond to SCOWL size 60 and, +to encourage consistent spelling, generally only include one spelling +variant for a word. The large dictionaries correspond to SCOWL size +70 and may include multiple spelling for a word when both variants are +considered almost equal. The larger dictionaries however (1) have not +been as carefully checked for errors as the normal dictionaries and +thus may contain misspelled or invalid words; and (2) contain +uncommon, yet valid, words that might cause problems as they are +likely to be misspellings of more common words (for example, "ort" and +"calender"). + +To get an idea of the difference in size, here are 25 random words +only found in the large dictionary for American English: + + Bermejo Freyr's Guenevere Hatshepsut Nottinghamshire arrestment + crassitudes crural dogwatches errorless fetial flaxseeds godroon + incretion jalapeño's kelpie kishkes neuroglias pietisms pullulation + stemwinder stenoses syce thalassic zees + +The en_US, en_CA and en_AU are the official dictionaries for Hunspell. +The en_GB and large dictionaries are made available on an experimental +basis. If you find them useful please send me a quick email at +kevina@gnu.org. + +If none of these dictionaries suite you (for example, maybe you want +the normal dictionary that also includes common variants) additional +dictionaries can be generated at http://app.aspell.net/create or by +modifying speller/make-hunspell-dict in SCOWL. Please do let me know +if you end up publishing a customized dictionary. + +If a word is not found in the dictionary or a word is there you think +shouldn't be, you can lookup the word up at http://app.aspell.net/lookup +to help determine why that is. + +General comments on these list can be sent directly to me at +kevina@gnu.org or to the wordlist-devel mailing lists +(https://lists.sourceforge.net/lists/listinfo/wordlist-devel). If you +have specific issues with any of these dictionaries please file a bug +report at https://github.com/kevina/wordlist/issues. + +IMPORTANT CHANGES INTRODUCED In 2016.11.20: + +New Australian dictionaries thanks to the work of Benjamin Titze +(btitze@protonmail.ch). + +IMPORTANT CHANGES INTRODUCED IN 2016.04.24: + +The dictionaries are now in UTF-8 format instead of ISO-8859-1. This +was required to handle smart quotes correctly. + +IMPORTANT CHANGES INTRODUCED IN 2016.01.19: + +"SET UTF8" was changes to "SET UTF-8" in the affix file as some +versions of Hunspell do not recognize "UTF8". + +ADDITIONAL NOTES: + +The NOSUGGEST flag was added to certain taboo words. While I made an +honest attempt to flag the strongest taboo words with the NOSUGGEST +flag, I MAKE NO GUARANTEE THAT I FLAGGED EVERY POSSIBLE TABOO WORD. +The list was originally derived from Németh László, however I removed +some words which, while being considered taboo by some dictionaries, +are not really considered swear words in today's society. + +COPYRIGHT, SOURCES, and CREDITS: + +The English dictionaries come directly from SCOWL +and is thus under the same copyright of SCOWL. The affix file is +a heavily modified version of the original english.aff file which was +released as part of Geoff Kuenning's Ispell and as such is covered by +his BSD license. Part of SCOWL is also based on Ispell thus the +Ispell copyright is included with the SCOWL copyright. + +The collective work is Copyright 2000-2018 by Kevin Atkinson as well +as any of the copyrights mentioned below: + + Copyright 2000-2018 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell these word + lists, the associated scripts, the output created from the scripts, + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appears in all copies and + that both that copyright notice and this permission notice appear in + supporting documentation. Kevin Atkinson makes no representations + about the suitability of this array for any purpose. It is provided + "as is" without express or implied warranty. + +Alan Beale also deserves special credit as he has, +in addition to providing the 12Dicts package and being a major +contributor to the ENABLE word list, given me an incredible amount of +feedback and created a number of special lists (those found in the +Supplement) in order to help improve the overall quality of SCOWL. + +The 10 level includes the 1000 most common English words (according to +the Moby (TM) Words II [MWords] package), a subset of the 1000 most +common words on the Internet (again, according to Moby Words II), and +frequently class 16 from Brian Kelk's "UK English Wordlist +with Frequency Classification". + +The MWords package was explicitly placed in the public domain: + + The Moby lexicon project is complete and has + been place into the public domain. Use, sell, + rework, excerpt and use in any way on any platform. + + Placing this material on internal or public servers is + also encouraged. The compiler is not aware of any + export restrictions so freely distribute world-wide. + + You can verify the public domain status by contacting + + Grady Ward + 3449 Martha Ct. + Arcata, CA 95521-4884 + + grady@netcom.com + grady@northcoast.com + +The "UK English Wordlist With Frequency Classification" is also in the +Public Domain: + + Date: Sat, 08 Jul 2000 20:27:21 +0100 + From: Brian Kelk + + > I was wondering what the copyright status of your "UK English + > Wordlist With Frequency Classification" word list as it seems to + > be lacking any copyright notice. + + There were many many sources in total, but any text marked + "copyright" was avoided. Locally-written documentation was one + source. An earlier version of the list resided in a filespace called + PUBLIC on the University mainframe, because it was considered public + domain. + + Date: Tue, 11 Jul 2000 19:31:34 +0100 + + > So are you saying your word list is also in the public domain? + + That is the intention. + +The 20 level includes frequency classes 7-15 from Brian's word list. + +The 35 level includes frequency classes 2-6 and words appearing in at +least 11 of 12 dictionaries as indicated in the 12Dicts package. All +words from the 12Dicts package have had likely inflections added via +my inflection database. + +The 12Dicts package and Supplement is in the Public Domain. + +The WordNet database, which was used in the creation of the +Inflections database, is under the following copyright: + + This software and database is being provided to you, the LICENSEE, + by Princeton University under the following license. By obtaining, + using and/or copying this software and database, you agree that you + have read, understood, and will comply with these terms and + conditions.: + + Permission to use, copy, modify and distribute this software and + database and its documentation for any purpose and without fee or + royalty is hereby granted, provided that you agree to comply with + the following copyright notice and statements, including the + disclaimer, and that the same appear on ALL copies of the software, + database and documentation, including modifications that you make + for internal use or for distribution. + + WordNet 1.6 Copyright 1997 by Princeton University. All rights + reserved. + + THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON + UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- + ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE + LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT INFRINGE ANY + THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + + The name of Princeton University or Princeton may not be used in + advertising or publicity pertaining to distribution of the software + and/or database. Title to copyright in this software, database and + any associated documentation shall at all times remain with + Princeton University and LICENSEE agrees to preserve same. + +The 40 level includes words from Alan's 3esl list found in version 4.0 +of his 12dicts package. Like his other stuff the 3esl list is also in the +public domain. + +The 50 level includes Brian's frequency class 1, words appearing +in at least 5 of 12 of the dictionaries as indicated in the 12Dicts +package, and uppercase words in at least 4 of the previous 12 +dictionaries. A decent number of proper names is also included: The +top 1000 male, female, and Last names from the 1990 Census report; a +list of names sent to me by Alan Beale; and a few names that I added +myself. Finally a small list of abbreviations not commonly found in +other word lists is included. + +The name files form the Census report is a government document which I +don't think can be copyrighted. + +The file special-jargon.50 uses common.lst and word.lst from the +"Unofficial Jargon File Word Lists" which is derived from "The Jargon +File". All of which is in the Public Domain. This file also contain +a few extra UNIX terms which are found in the file "unix-terms" in the +special/ directory. + +The 55 level includes words from Alan's 2of4brif list found in version +4.0 of his 12dicts package. Like his other stuff the 2of4brif is also +in the public domain. + +The 60 level includes all words appearing in at least 2 of the 12 +dictionaries as indicated by the 12Dicts package. + +The 70 level includes Brian's frequency class 0 and the 74,550 common +dictionary words from the MWords package. The common dictionary words, +like those from the 12Dicts package, have had all likely inflections +added. The 70 level also included the 5desk list from version 4.0 of +the 12Dics package which is in the public domain. + +The 80 level includes the ENABLE word list, all the lists in the +ENABLE supplement package (except for ABLE), the "UK Advanced Cryptics +Dictionary" (UKACD), the list of signature words from the YAWL package, +and the 10,196 places list from the MWords package. + +The ENABLE package, mainted by M\Cooper , +is in the Public Domain: + + The ENABLE master word list, WORD.LST, is herewith formally released + into the Public Domain. Anyone is free to use it or distribute it in + any manner they see fit. No fee or registration is required for its + use nor are "contributions" solicited (if you feel you absolutely + must contribute something for your own peace of mind, the authors of + the ENABLE list ask that you make a donation on their behalf to your + favorite charity). This word list is our gift to the Scrabble + community, as an alternate to "official" word lists. Game designers + may feel free to incorporate the WORD.LST into their games. Please + mention the source and credit us as originators of the list. Note + that if you, as a game designer, use the WORD.LST in your product, + you may still copyright and protect your product, but you may *not* + legally copyright or in any way restrict redistribution of the + WORD.LST portion of your product. This *may* under law restrict your + rights to restrict your users' rights, but that is only fair. + +UKACD, by J Ross Beresford , is under the +following copyright: + + Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved. + + The following restriction is placed on the use of this publication: + if The UK Advanced Cryptics Dictionary is used in a software package + or redistributed in any form, the copyright notice must be + prominently displayed and the text of this document must be included + verbatim. + + There are no other restrictions: I would like to see the list + distributed as widely as possible. + +The 95 level includes the 354,984 single words, 256,772 compound +words, 4,946 female names and the 3,897 male names, and 21,986 names +from the MWords package, ABLE.LST from the ENABLE Supplement, and some +additional words found in my part-of-speech database that were not +found anywhere else. + +Accent information was taken from UKACD. + +The VarCon package was used to create the American, British, Canadian, +and Australian word list. It is under the following copyright: + + Copyright 2000-2016 by Kevin Atkinson + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Kevin Atkinson makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Copyright 2016 by Benjamin Titze + + Permission to use, copy, modify, distribute and sell this array, the + associated software, and its documentation for any purpose is hereby + granted without fee, provided that the above copyright notice appears + in all copies and that both that copyright notice and this permission + notice appear in supporting documentation. Benjamin Titze makes no + representations about the suitability of this array for any + purpose. It is provided "as is" without express or implied warranty. + + Since the original words lists come from the Ispell distribution: + + Copyright 1993, Geoff Kuenning, Granada Hills, CA + 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. + (clause 4 removed with permission from Geoff Kuenning) + 5. The name of Geoff Kuenning may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING 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 GEOFF KUENNING 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. + +Build Date: Mon Dec 7 20:19:27 EST 2020 +Wordlist Command: mk-list --accents=strip en_US 60 diff --git a/assets/spelling/licenses/en/README_en_ZA.txt b/assets/spelling/licenses/en/README_en_ZA.txt new file mode 100644 index 00000000..5a793072 --- /dev/null +++ b/assets/spelling/licenses/en/README_en_ZA.txt @@ -0,0 +1,780 @@ +In 2025 Marco A.G.Pinto officially forked the ZA dictionary. +Since 2021 that the ZA dictionary has been improved/fixed by Marco A.G.Pinto. + +2025-02-23 (Marco A.G.Pinto) + - Unified the ZA and GB .AFF file. + +2025-02-20 (Marco A.G.Pinto) + - Unified the ZA flags with GB (~2800 new words including fixes in some). + +2025-02-05 (Marco A.G.Pinto) + - Inserted ~35000 proper names (70000+ with possessives and plurals) extracted from the GB Dictionary. + +2025-01-27 (Marco A.G.Pinto) + - Inserted ~2400 uncountable nouns (4800 with possessives) extracted from the GB Dictionary; + - Fixed/improved: flag “1”. + +2025-01-23 (Marco A.G.Pinto) + - Fixed/improved: flag “O” and “W”. + +2024-12-17 (Marco A.G.Pinto) + - “REP si ci” and merged/sorted REP GB/ZA (Shantanu Oak): https://bugs.documentfoundation.org/show_bug.cgi?id=152554 . + - Added support for 1st, 2nd, 3rd, 4th, etc. + +2024-11-30 (Marco A.G.Pinto) + - Improved flag “Z”. + +2024-11-05 (Marco A.G.Pinto) + - Improved flag “O” and replaced its PFX with “^”. + +2024-07-11 (Marco A.G.Pinto) + - Improved flag “n” adding 962 words (possessives). + +2024-05-12 (Marco A.G.Pinto) + - Started parallel adding of words from GB to ZA. + +2024-04-02 (Marco A.G.Pinto) + - Improved flag “S” adding 9 words (possessives); + - Improved flag “N” adding 1114 words (possessives). + +2024-01-29 (Marco A.G.Pinto) + - Fix: Removed the: ICONV ’ ' because it was already at the end of the .aff; + - Fix: apostrophe handling, by adding: WORDCHARS 0123456789’ to the .aff; + - Improved flag “J” adding 424 words. + +2023-01-26 (Marco A.G.Pinto) + - Fixed/improved: flag “3”. + +2023-01-17 (Marco A.G.Pinto) + - Added: Czechia + Czechia's. + +2023-01-01 (Marco A.G.Pinto) + - Added the: ICONV ’ '; + - Sorted alphabetically the tags of the .aff. + +2022-07-12 (Marco A.G.Pinto) + - Fixed: “!” flag at start of words; + - Removed duplicate words; + - Sorted alphabetically the dictionary. + +2021-02-15 (Marco A.G.Pinto) + - Fixed: concious + conciousness. + +2010-03-09 (nemeth AT OOo) + - UTF-8 encoded dictionary: + - Fix em-dash problem of OOo 3.2 by BREAK + - Suggesting words with typographical apostrophes + - Recognizing words with Unicode f ligatures + - Add phonetic suggestion (Copyright (C) 2000 Björn Jacke, see the end of the file). + +------- + +MySpell English (South African) Spellchecker +-------------------------------------------- + +1. Welcome +2. Copyright +3. Installation and Setup +4. Contributing +5. Copying + +Enjoy! + +1. Welcome +========== + +This spellchecker is Free Software: + + Free to use - Free to share - Free to change. + +See section 4. Contributing to see how you can help make it even better. + + +Why Free Software? +------------------ + +The Translate.org.za project's aim is to make language resources and software +available to the speakers of that language and licensed in such a way that the +resources remain Free and thus available to all the language's speakers. +After all it is you, the speakers of South African English, who has actually developed +it into the language that it is today. + +What is Free Software? +---------------------- + +For a good explanation of Free Software visit: + http://www.gnu.org/philosophy/philosophy.html AND + http://www.gnu.org/philosophy/free-sw.html + + +2. Copyright +============ + +British English Wordlist +------------------------ + +The South African English wordlist uses the same list developed for the +British English spell checker. That word list itself is derived from +the English word lists developed for Aspell. This list is released +under the LGPL. + +More details of the British English dictionary project can be found here: +http://en-gb.pyxidium.co.uk/dictionary + +From the README for the British English Myspell spell checker: + + This dictionary was initially based on a subset of the + original English wordlist created by Kevin Atkinson for + Pspell and Aspell and thus is covered by his original + LGPL licence. + + It has been extensively updated by David Bartlett, Brian Kelk + and Andrew Brown: + - numerous Americanism have been removed + - numerous American spellings have been corrected + - missing words have been added + - many errors have been corrected + - compound hyphenated words have been added where appropriate + + Valuable inputs to this process were received from many other + people - far too numerous to name. Serious thanks to you all + for your greatly appreciated help. + + This word list is intended to be a good representation of + current modern British English and thus it should be a good + basis for Commonwealth English in most countries of the world + outside North America. + + The affix file has been created completely from scratch + by David Bartlett and Andrew Brown, based on the published + rules for MySpell and is also provided under the LGPL. + + In creating the affix rules an attempt has been made to + reproduce the most general rules for English word + formation, rather than merely use it as a means to + compress the size of the dictionary. It is hoped that this + will facilitate future localisation to other variants of + English. + + Please let David Bartlett know of any + errors that you find. + + The current release is R 1.18, 11/04/05 + + +MySpell Affix File +------------------ + +Copyright David Bartlett and Andrew Brown +Released under the LGPL + +South African English Wordlists +------------------------------- + +See the respective header files of the source wordlists for their copyright. +All those developed by the Zuza Software Foundation are released under the +LGPL. + +3. Installation and Setup +========================= + +Automated +--------- + +Newer versions of OpenOffice.org have a built in macro to step you through an +automatic install process. + + File -> Autopilot -> Install new dictionaries... + +If this is unavailable then download 'DicOOo.sxw' from: +http://ftp.services.openoffice.org/pub/OpenOffice.org/contrib/dictionaries/dicooo/DicOOo.sxw + +Run the macro and follow the steps outlined. If you would like the dictionary +to be available to all users then run the installation as the administrative or +root user. It is best to restart OpenOffice.org after the installation. + +The macro operates in two modes: + +1) Online - the latest dictionaries are retrieved from the OpenOffice.org + website. + +2) Offline - an offline dictionary pack, which you have already downloaded, is + installed from the hard-drive. Offline dictionaries can be downloaded from: + http://lingucomponent.openoffice.org/dictpack.html + OR + http://sourceforge.net/project/showfiles.php?group_id=91920&package_id=103504 + +For more detailed instructions see: + http://lingucomponent.openoffice.org/auto_instal.html + + +Non-automated +------------- + +For instructions on how to install the Afrikaans dictionary manually please visit +the following URL: +http://lingucomponent.openoffice.org/manual_instal.html + + +Spellchecker Selection +---------------------- + +Once the spellchecker is installed you need to configure a few settings and +perform some checks. + +1) Check that the Afrikaans Spellchecker is enabled. + + Tools -> Options -> Language Settings -> Writing Aids + +In the section marked 'Available language modules' select 'Edit...'. Under +the languages drop-down select Afrikaans and ensure that the 'OpenOffice.org +MySpell SpellChecker' is enabled. + +2) Set your default document language to Afrikaans + +If most of your writing is in Afrikaans then this step will ensure that +documents you compose from now on are treated as Afrikaans documents. If much +of your writing is in English you might want to skip this step. + + Tools -> Options -> Language Settings -> Languages + +In the section marked 'Default languages for documents' is a drop-down labelled +'Western'. Afrikaans has a tick next to it to indicate that a spellchecker is +installed. Set your default language to Afrikaans. + +3) Changing existing documents or paragraphs to Afrikaans + +Some old document might be written in Afrikaans but the document was stored +indicating that the text was in English. You can indicate that this is +Afrikaans text by: + + a) Select the relevant text (Ctrl-A selects the whole document) + b) Format -> Character... + Change the 'Language' drop-down to Afrikaans. + + +4. Contributing +=============== + +You can help to make this software better by: + +a) Contributing corrections and missing words +b) Contributing your wordlists +c) Reviewing the existing wordlists and user contributed lists. +d) Joining the Afrikaans translation and dictionary discussion list + 'translate-discuss-af' at: + http://sourceforge.net/mail/?group_id=91920 + +Email your contributions to Dwayne Bailey . + + +5. Copying +========== + +This software is released under the LGPL which is included here for your +information. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/assets/spelling/licenses/en/README_hyph_en_GB.txt b/assets/spelling/licenses/en/README_hyph_en_GB.txt new file mode 100644 index 00000000..4afac7b6 --- /dev/null +++ b/assets/spelling/licenses/en/README_hyph_en_GB.txt @@ -0,0 +1,198 @@ +hyph_en_GB.dic - British English hyphenation patterns for OpenOffice.org + +version 2011-10-07 + +- remove unnecessary parts for Hyphen 2.8.2 + +version 2010-03-16 + +Changes + +- forbid hyphenation at 1-character distances from dashes (eg. ad=d-on) + and at the dashes (fix for OpenOffice.org 3.2) +- UTF-8 encoding and corrected hyphenation for words with Unicode f ligatures + (conversion scripts: see Hyphen 2.6) + +version 2009-01-23 + +Changes + +- add missing \hyphenation list (how-ever, through-out etc.) +- set correct LEFTHYPHENMIN = 2, RIGHTHYPHENMIN = 3 +- handle apostrophes (forbid *can='t, *abaser='s, *o'c=lock etc.) +- set COMPOUNDLEFTHYPHENMIN, COMPOUNDRIGHTHYPHENMIN values + +License + +BSD-style. Unlimited copying, redistribution and modification of this file +is permitted with this copyright and license information. + +British English hyphenation patterns, based on "ukhyphen.tex" Version 1.0a +Created by Dominik Wujastyk and Graham Toal using Frank Liang's PATGEN 1.0, +source: http://ctan.org + +See original ukhyphen.tex license in this file, too. + +Conversion and modifications by László Németh (nemeth at OOo). + +Conversion: + +./substrings.pl hyph_en_GB.dic.source /tmp/hyph_en_GB.dic.patterns >/dev/null +cat hyph_en_GB.dic.header /tmp/hyph_en_GB.dic.patterns >hyph_en_GB.dic + +hyph_en_GB.dic.header: + +ISO8859-1 +LEFTHYPHENMIN 2 +RIGHTHYPHENMIN 3 +COMPOUNDLEFTHYPHENMIN 2 +COMPOUNDRIGHTHYPHENMIN 3 +1'. +1's. +1't. +NEXTLEVEL + +OpenOffice.org ukhyphen patch (hyph_en_GB.dic.source): + +--- ukhyphen.tex 2008-12-17 15:37:04.000000000 +0100 ++++ hyph_en_GB.dic.source 2008-12-18 10:07:02.000000000 +0100 +@@ -52,7 +52,6 @@ + % + % These patterns require a value of about 14000 for TeX's pattern memory size. + % +-\patterns{ % just type if you're not using INITEX + .ab4i + .ab3ol + .ace4 +@@ -8580,13 +8579,64 @@ + z3zie + zzo3 + z5zot +-} +-\hyphenation{ % Do NOT make any alterations to this list! --- DW +-uni-ver-sity +-uni-ver-sit-ies +-how-ever +-ma-nu-script +-ma-nu-scripts +-re-ci-pro-city +-through-out +-some-thing} ++.uni5ver5sity. ++.uni5ver5sit5ies. ++.how5ever. ++.ma5nu5script. ++.ma5nu5scripts. ++.re5ci5pro5city. ++.through5out. ++.some5thing. ++4'4 ++4a' ++4b' ++4c' ++4d' ++4e' ++4f' ++4g' ++4h' ++4i' ++4j' ++4k' ++4l' ++4m' ++4n' ++4o' ++4p' ++4q' ++4r' ++4s' ++4t' ++4u' ++4v' ++4w' ++4x' ++4y' ++4z' ++'a4 ++'b4 ++'c4 ++'d4 ++'e4 ++'f4 ++'g4 ++'h4 ++'i4 ++'j4 ++'k4 ++'l4 ++'m4 ++'n4 ++'o4 ++'p4 ++'q4 ++'r4 ++'s4 ++'t4 ++'u4 ++'v4 ++'w4 ++'x4 ++'y4 ++'z4 + +Original License + +% File: ukhyphen.tex +% TeX hyphenation patterns for UK English + +% Unlimited copying and redistribution of this file +% is permitted so long as the file is not modified +% in any way. +% +% Modifications may be made for private purposes (though +% this is discouraged, as it could result in documents +% hyphenating differently on different systems) but if +% such modifications are re-distributed, the modified +% file must not be capable of being confused with the +% original. In particular, this means +% +%(a) the filename (the portion before the extension, if any) +% must not match any of : +% +% UKHYPH UK-HYPH +% UKHYPHEN UK-HYPHEN +% UKHYPHENS UK-HYPHENS +% UKHYPHENATION UK-HYPHENATION +% UKHYPHENISATION UK-HYPHENISATION +% UKHYPHENIZATION UK-HYPHENIZATION +% +% regardless of case, and +% +%(b) the file must contain conditions identical to these, +% except that the modifier/distributor may, if he or she +% wishes, augment the list of proscribed filenames. + +% $Log: ukhyph.tex $ +% Revision 2.0 1996/09/10 15:04:04 ucgadkw +% o added list of hyphenation exceptions at the end of this file. +% +% +% Version 1.0a. Released 18th October 2005/PT. +% +% Created by Dominik Wujastyk and Graham Toal using Frank Liang's PATGEN 1.0. +% Like the US patterns, these UK patterns correctly hyphenate about 90% of +% the words in the input list, and produce no hyphens not in the list +% (see TeXbook pp. 451--2). +% +% These patterns are based on a file of 114925 British-hyphenated words +% generously made available to Dominik Wujastyk by Oxford University Press. +% This list of words is copyright to the OUP and may not be redistributed. +% The hyphenation break points in the words in the abovementioned file is +% also copyright to the OUP. +% +% We are very grateful to Oxford University Press for allowing us to use +% their list of hyphenated words to produce the following TeX hyphenation +% patterns. This file of hyphenation patterns may be freely distributed. +% +% These patterns require a value of about 14000 for TeX's pattern memory size. +% diff --git a/assets/spelling/licenses/en/README_hyph_en_US.txt b/assets/spelling/licenses/en/README_hyph_en_US.txt new file mode 100644 index 00000000..8420172b --- /dev/null +++ b/assets/spelling/licenses/en/README_hyph_en_US.txt @@ -0,0 +1,59 @@ +hyph_en_US.dic - American English hyphenation patterns for OpenOffice.org + +version 2011-10-07 + +- remove unnecessary parts for the new Hyphen 2.8.2 + +version 2010-03-16 + +Changes + +- forbid hyphenation at 1-character distances from dashes (eg. ad=d-on) + and at the dashes (fix for OpenOffice.org 3.2) +- set correct LEFTHYPHENMIN = 2, RIGHTHYPHENMIN = 3 +- handle apostrophes (forbid *o'=clock etc.) +- set COMPOUNDLEFTHYPHENMIN, COMPOUNDRIGHTHYPHENMIN values +- UTF-8 encoding +- Unicode ligature support + +License + +BSD-style. Unlimited copying, redistribution and modification of this file +is permitted with this copyright and license information. + +See original license in this file. + +Conversion and modifications by László Németh (nemeth at OOo). + +Based on the plain TeX hyphenation table +(http://tug.ctan.org/text-archive/macros/plain/base/hyphen.tex) and +the TugBoat hyphenation exceptions log in +http://www.ctan.org/tex-archive/info/digests/tugboat/tb0hyf.tex, processed +by the hyphenex.sh script (see in the same directory). + +Originally developed and distributed with the Hyphen hyphenation library, +see http://hunspell.sourceforge.net/ for the source files and the conversion +scripts. + +Licenses + +hyphen.tex: +% The Plain TeX hyphenation tables [NOT TO BE CHANGED IN ANY WAY!] +% Unlimited copying and redistribution of this file are permitted as long +% as this file is not modified. Modifications are permitted, but only if +% the resulting file is not named hyphen.tex. + +output of hyphenex.sh: +% Hyphenation exceptions for US English, based on hyphenation exception +% log articles in TUGboat. +% +% Copyright 2007 TeX Users Group. +% You may freely use, modify and/or distribute this file. +% +% This is an automatically generated file. Do not edit! +% +% Please contact the TUGboat editorial staff +% for corrections and omissions. + +hyph_en_US.txt: +See the previous licenses. diff --git a/assets/spelling/licenses/en/README_lightproof_en.txt b/assets/spelling/licenses/en/README_lightproof_en.txt new file mode 100644 index 00000000..43c91fe4 --- /dev/null +++ b/assets/spelling/licenses/en/README_lightproof_en.txt @@ -0,0 +1,3 @@ +English sentence checker for LibreOffice +see git://anongit.freedesktop.org/libreoffice/lightproof +2011-2012 (c) László Németh, license: MPL 1.1 / GPLv3+ / LGPLv3+ diff --git a/assets/spelling/licenses/en/WordNet_license.txt b/assets/spelling/licenses/en/WordNet_license.txt new file mode 100644 index 00000000..f1f96d88 --- /dev/null +++ b/assets/spelling/licenses/en/WordNet_license.txt @@ -0,0 +1,31 @@ +WordNet Release 2.1 + +This software and database is being provided to you, the LICENSEE, by +Princeton University under the following license. By obtaining, using +and/or copying this software and database, you agree that you have +read, understood, and will comply with these terms and conditions.: + +Permission to use, copy, modify and distribute this software and +database and its documentation for any purpose and without fee or +royalty is hereby granted, provided that you agree to comply with +the following copyright notice and statements, including the disclaimer, +and that the same appear on ALL copies of the software, database and +documentation, including modifications that you make for internal +use or for distribution. + +WordNet 2.1 Copyright 2005 by Princeton University. All rights reserved. + +THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON +UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PRINCETON +UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- +ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE +OF THE LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT +INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR +OTHER RIGHTS. + +The name of Princeton University or Princeton may not be used in +advertising or publicity pertaining to distribution of the software +and/or database. Title to copyright in this software, database and +any associated documentation shall at all times remain with +Princeton University and LICENSEE agrees to preserve same. diff --git a/assets/spelling/licenses/en/license.txt b/assets/spelling/licenses/en/license.txt new file mode 100644 index 00000000..e37680cf --- /dev/null +++ b/assets/spelling/licenses/en/license.txt @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + END OF TERMS AND CONDITIONS diff --git a/assets/spelling/licenses/es/LICENSE.md b/assets/spelling/licenses/es/LICENSE.md new file mode 100644 index 00000000..2e4370a6 --- /dev/null +++ b/assets/spelling/licenses/es/LICENSE.md @@ -0,0 +1,25 @@ +# Licencia + +El proyecto y los diccionarios se distribuyen bajo un triple esquema de +licencias disjuntas: [GNU GPL versión 3 o posterior](https://www.gnu.org/licenses/gpl-3.0.en.html), [GNU LGPL versión 3 o +posterior](https://www.gnu.org/licenses/lgpl-3.0.en.html) o [MPL versión 1.1 o posterior](https://www.mozilla.org/en-US/MPL/1.1/). +Puede seleccionar libremente bajo cuál de estas licencias realizará el uso. + +El detalle de cada licencia está accesible en: + +- https://www.gnu.org/licenses/gpl-3.0.en.html +- https://www.gnu.org/licenses/lgpl-3.0.en.html +- https://www.mozilla.org/en-US/MPL/1.1/ + +y en los ficheros: +- LICENSE/GPLv3.txt +- LICENSE/LGPLv3.txt +- LICENSE/MPL-1.1.txt + + +El diccionario de sinónimos se distribuye según lo auspiciado por la [GNU LGPL v2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html). + +El detalle está accesible: + +- en la dirección web https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +- y en el fichero LICENSE/LGPLv2.1.txt diff --git a/assets/spelling/licenses/es/README_hunspell_es.txt b/assets/spelling/licenses/es/README_hunspell_es.txt new file mode 100644 index 00000000..80f26484 --- /dev/null +++ b/assets/spelling/licenses/es/README_hunspell_es.txt @@ -0,0 +1,75 @@ + **************************************************************************** + ** ** + ** Diccionario para corrección ortográfica en español de ** + ** LibreOffice/Apache OpenOffice ** + ** ** + **************************************************************************** + +Para: __LOCALES__ + + **************************************************************************** + + Versión __VERSION__ + +SUMARIO + +1. AUTOR +2. LICENCIA +3. COLABORACIÓN +4. AGRADECIMIENTOS + + +1. AUTOR + + Este diccionario ha sido desarrollado inicialmente por Santiago Bosio; +quien actualmente coordina el desarrollo de todos los diccionarios localizados. + + El diccionario es un desarrollo completamente nuevo, y NO ESTÁ BASADO en el +trabajo de Jesús Carretero y Santiago Rodríguez, ni en la versión adaptada al +formato de MySpell por Richard Holt. + +2. LICENCIA + + Este diccionario para corrección ortográfica, integrado por el fichero +de afijos y la lista de palabras (__LOCALE__[.aff|.dic]) se distribuye +bajo un triple esquema de licencias disjuntas: GNU GPL versión 3 o posterior, +GNU LGPL versión 3 o posterior, ó MPL versión 1.1 o posterior. Puede +seleccionar libremente bajo cuál de estas licencias utilizará este diccionario. +En el fichero LICENSE.md encontrá más detalles. + +3. COLABORACIÓN + + Este diccionario es resultado del trabajo colaborativo de muchas personas. +La buena noticia es que ¡usted también puede participar! + + ¿Tiene dudas o sugerencias? ¿Desearía ver palabras agregadas, o que se +realizaran correcciones? Consulte las indicaciones técnicas publicadas en +CONTRIBUTING.md. Estaremos encantados de atenderle. + +4. AGRADECIMIENTOS + + Hay varias personas que han colaborado con aportes o sugerencias a la +creación de este diccionario. Se agradece especialmente a: + + - Richard Holt. + - Marcelo Garrone. + - Kevin Hendricks. + - Juan Rey Saura. + - Carlos Dávila. + - Román Gelbort. + - J. Eduardo Moreno. + - Gonzalo Higuera Díaz. + - Ricardo Palomares Martínez. + - Sergio Medina. + - Ismael Olea. + - Alejandro Moreno. + - Alexandro Colorado. + - Andrés Sánchez. + - Juan Rafael Fernández García. + - eksperimental. + - Ezequiel (ezeperez26). + - KNTRO. + - Ricardo Berlasso. + - Edward Villegas-Pulgarin (cosmocalibur) + - y a todos los integrantes de la comunidad en español que proponen mejoras + a este diccionario. diff --git a/assets/spelling/licenses/es/README_hyph_es.txt b/assets/spelling/licenses/es/README_hyph_es.txt new file mode 100644 index 00000000..3010a9aa --- /dev/null +++ b/assets/spelling/licenses/es/README_hyph_es.txt @@ -0,0 +1,45 @@ + **************************************************************************** + ** ** + ** Patrones de separación silábica en español de ** + ** LibreOffice/Apache OpenOffice ** + ** ** + **************************************************************************** + ** VERSIÓN GENÉRICA PARA TODAS LAS LOCALIZACIONES DEL ESPAÑOL ** + **************************************************************************** + + Versión __VERSION__ + +SUMARIO + +1. AUTOR +2. LICENCIA +3. COLABORACIÓN +4. AGRADECIMIENTOS + + +1. AUTOR + + Este fichero de patrones para separación silábica ha sido desarrollado +inicialmente por Santiago Bosio; mediante el uso de la herramienta libre +"patgen" y datos de entrenamiento etiquetados manualmente. + +Actualmente, se genera a partir del proyecto "tex-hyphen-spanish" de Javier +Bezos, adaptado por Edward Villegas. + +2. LICENCIA + + Este listado de patrones para separación silábica, integrado por el +fichero hyph_es.dic se distribuye bajo un triple esquema de licencias +disjuntas: GNU GPL versión 3 o posterior, GNU LGPL versión 3 o posterior, ó +MPL versión 1.1 o posterior. Puede seleccionar libremente bajo cuál de +estas licencias utilizará este diccionario. En el fichero LICENSE.md +encontrará más detalles. + +El fichero retiene por obligación la licencia del fichero original para TeX, +disponible bajo licencia MIT, cuya transformación se distribuye como parte +del diccionario bajo el esquema de licenciamiento descrito. + +3. COLABORACIÓN + + Puede reportar errores del separador directamente al proyecto +tex-hyphen-spanish. diff --git a/assets/spelling/licenses/es/README_th_es.txt b/assets/spelling/licenses/es/README_th_es.txt new file mode 100644 index 00000000..5f5ad0be --- /dev/null +++ b/assets/spelling/licenses/es/README_th_es.txt @@ -0,0 +1,18 @@ +OpenThesaurus - Tesauro Español - Versión para LibreOffice/Apache OpenOffice +Marcelo Garrone (mgarrone at users.sf.net) +Snapshot, generado automáticamente: 2012-01-11 21:33 +Homepage: http://openthes-es.berlios.de + +Requisitos: ========================================================== + +LibreOffice/Apache OpenOffice + +Nota: ================================================================ + + * El diccionario de sinónimos y separación silábica es el mismo para Windows como para Linux. + +licencia: ========================================================= + +LGPL 2.1: + - https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html + - fichero COPYING diff --git a/assets/spelling/licenses/et_EE/README_et_EE.txt b/assets/spelling/licenses/et_EE/README_et_EE.txt new file mode 100644 index 00000000..8378dca1 --- /dev/null +++ b/assets/spelling/licenses/et_EE/README_et_EE.txt @@ -0,0 +1,468 @@ +Eesti sõnastik OpenOffice.org õigekirjakontrollile +Estonian dictionary for OpenOffice.org spellchecker +================================================== +versioon 1.0 /version 1.0 +juuni 2004 / June 2004 + +1. Üldist / General +------------------- + +Käesolev sõnastik on mõeldud OpenOffice.org myspell-il baseeruva õigekirjakontrollija +tarbeks. Sõnastik sisaldab umbes 15 miljonit sõna. +Sõnastik sisaldab kahte faili: +et_EE.dic (sõnastik) +et_EE.aff (afiksid) +Sõnastiku paigaldamiseks võib kasutada OpenOffice.org koosseisu kuuluvat abiprogrammi +DictOOO, samuti võib ka tegutseda vastavalt OpenOffice.org käsiraamatus toodud +juhistele. +README käesoleva versiooni on koostanud ja sõnastikud pakendanud Ain Vagula +(vagula@openoffice.org) + +This dictionary is created for myspell-based OpenOffice.org spellchecker. Dictionary +contains about 15 million words. +Dictionary contais two files: +et_EE.dic (dictionary) +et_EE.aff (affixes) +To install the dicionary use the OpenOffice.org tool DictOOO or refer to the OpenOffice.org +Online Help. +Current version of README is written and packages are made by Ain Vagula +(vagula@openoffice.org) + +2. Autorid ja litsentsid / Authors and licenses +----------------------------------------------- + +Sõnastiku on myspelli jaoks kohandanud Jaak Pruulmann (jjpp@meso.ee, +http://www.meso.ee/~jjpp/speller/ ), kes on oma töö pannud GNU LGPL-i (GNU Vähem Üldine +Avalik Litsents) alla. +Kasutatud on EKI (Eesti Keele Instituut, tarkvara@eki.ee) poolt välja töötatud eesti keele +sõnade loendit. +EKI tarkvara litsentsi originaal asub aadressil http://www.eki.ee/eki/litsents.html +Litsentside koopiad on lisatud käesolevale failile. Sõnade loendi kasutamisest on EKI-t teavitatud. + +Dictionary is adapted to myspell by Jaak Pruulmann (jjpp@meso.ee, +http://www.meso.ee/~jjpp/speller/ ) on the base of word list created and shared by IEL +(Institute of the Estonian Language, tarkvara@eki.ee). The original +of EKI software license is available at http://www.eki.ee/eki/licence.html +The work of Jaak Pruulmann is licensed under LGPL (GNU Lesser General Public License). +The copies of licenses are added to current file. IEL is informed about the use of this word list. + +----------------------------------------------- +EESTI KEELE INSTITUUDI TARKVARA LITSENTSILEPING + +Autoriõigus © Eesti Keele Instituut. + +e-post: tarkvara@eki.ee + +URL: http://www.eki.ee/tarkvara/ + +Käesoleva litsentsilepinguga on selle tarkvaratoote kasutajail õigus tarkvara kasutada +mistahes eesmärgil, sh levitada, kopeerida, muuta, kasutada muu tarkvara koosseisus ja müüa +järgnevatel tingimustel: +Käesolev litsentsileping tuleb muutmata kujul säilitada kõigi selle tarkvara koopiate juures. +Ei Eesti Keele Instituut ega tarkvara autor(id) ei vastuta mistahes otseste või kaudsete +kahjude eest, mis võivad johtuda selle tarkvaratoote kasutamisest. +EKI jagab tarkvara sooviga edendada eesti keele uuringuid ja soodustada eesti keele kasutust +kiiresti arenevas infotehnoloogias, kuid ei võta sellega endale lisakohustusi – EKI ei taga +tarkvara sobivust konkreetseks otstarbeks, ei kohustu programmi täiustama või põhjalikumalt +kirjeldama kasutatud algoritme. (Mis muidugi ei tähenda, et me seda ei tee). +Tarkvara kasutamisel palume sellest teada anda ülaltoodud elektronposti aadressil. + +---------- litsentsilepingu lõpp ---------- + +Software Licence Agreement +Institute of the Estonian Language + +Copyright © Institute of the Estonian Language + +E-mail: tarkvara@eki.ee + +URL: http://www.eki.ee/tarkvara/ + +The present Licence Agreement gives the user of this Software Product (hereinafter: Product) +the right to use the Product for whatever purpose (incl. distribution, copying, altering, +inclusion in other software, and selling) on the following conditions: +The present Licence Agreement should belong unaltered to each copy ever made of this Product; +Neither the Institute of the Estonian Language (hereinafter: IEL) nor the author(s) of the Product will take responsibility for any detriment, direct or indirect, possibly ensuing from the application of the Product; +The IEL is ready to share the Product with other users as we wish to advance research on the Estonian language and to promote the use of Estonian in IT-technology now rapidly developing, yet we refuse to bind ourselves to any further obligation, which means that the IEL is not obliged either to warrant the suitability of the Product for a concrete use, to improve the program, or to provide a more detailed description of the underlying algorithms. (Which does not mean, though, that we may not do it.) +Whenever you use the Product, we request that you inform us by writing to the e-mail address tarkvara@eki.ee or to street address listed below. + +Institute of the Estonian Language + Roosikrantsi 6 + EE-10119 Tallinn + ESTONIA + +E-mail: eki@eki.ee +Phone & Fax: +372-6411443 +---------- end of Licence Agreement ---------- + + + +GNU Vähem Üldine Avalik Litsents + +Versioon number 2.1, Veebruar 1999 + +Autoriõigus (C) 1991, 1999 Free Software Foundation, Inc. + +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Igaüks võib käesolevast dokumendist valmistada koopiaid ning valmistatud koopiaid levitada tingimusel, et need koopiad vastavad originaaldokumendile sõnasõnalt. + +[See on GNU Vähem Üldise Avaliku Litsentsi esimene avaldatud versioon. See on ka GNU Üldise Avaliku Litsentsi versiooni 2 järeltulija, seega on versiooni number 2.1.] + +Eessõna + +Enamik tarkvara litsentse on loodud selleks, et võtta Teilt õigus tarkvara jagada ja muuta. + +Vastukaaluks on GNU Üldine Avalik Litsents mõeldud selleks, et tagada Teile vabadus jagada ja muuta vaba tarkvara - kindlustada, et tarkvara oleks vaba kõigile selle kasutajatele. + +Käesolev, Vähem Üldine Avalik Litsents, kehtib mõnele spetsiaalse suunitlusega Free Software Foundation'i ja teiste autorite, kes otsustavad seda kasutada, poolt loodud tarkvara pakettidele - tavaliselt teekidele. Ka Teie võite käesolevat litsentsi kasutada, kuid soovitame Teil allpool toodud selgitustele tuginedes igal üksikjuhul enne hoolega mõelda, kas strateegiliselt on parem kasutada käesolevat litsentsi või tavalist Üldist Avalikku Litsentsi. + +Rääkides vabast tarkvarast peame silmas vabadust, mitte hinda. Üldised Avalikud Litsentsid on loodud selleks, et tagada Teile järgnevat: õigust levitada koopiaid vabast tarkvarast (soovi korral ka levitamise eest tasu võttes), tarkvara lähtetekstide kättesaadavust, õigust tarkvara muuta või kasutada tarkvara osi uute vaba tarkvaratoodete loomisel ning kindlustada, et Te olete teadlik eelpoolnimetatud õigustest. + +Teie õiguste tagamiseks on vaja rakendada mõningaid piiranguid, et levitajad ei saaks Teilt neid õigusi ära võtta või nõuda nendest loobumist. Tarkvara muutmisel või selle koopiate levitamisel kätkevad need piirangud Teie jaoks teatud kohustusi. + +Näiteks levitades teegi koopiaid, kas tasuta või levitamise eest tasu võttes, peate Te saajatele andma kõik need õigused, mis meie Teile andsime. Te peate kindlustama, et ka nemad saavad või võivad soovi korral saada lähteteksti. + +Kui Te lingite teegiga muud koodi, peate andma saajatele ka täielikud objektfailid, et nad saaksid pärast muudatuste tegemist teegis ja selle uuesti kompileerimist neid uuesti teegiga linkida. Ning Te peate neid teavitama käesoleva Litsentsi tingimustest, et nad teaksid oma õigusi. + +Me kaitseme Teie õigusi kaheastmeliselt: + +1. anname teegile autoriõiguse, ja + +2. pakume Teile käesolevat litsentsi, mis annab Teile seadusliku õiguse kopeerida, levitada ja/või muuta teeki. + +Iga levitaja kaitsmiseks tahame me teha väga selgeks, et vabal teegil pole garantiid. Kui keegi teeki muudab ja edasi levitab, peavad selle saajad teadma, et nende omanduses pole originaal vältimaks teiste poolt põhjustatud probleemide mõju originaali autori mainele. + +Lõpuks, tarkvara patendid kujutavad pidevat ohtu mistahes vaba programmi olemasolule. Me soovime kindlustada, et ükski firma ei saaks efektiivselt piirata vaba programmi kasutajaid saades patendi omanikult piirava litsentsi. Seega - me nõuame, et mistahes patendi litsents, mis on saadud teegi versioonile, peab olema kooskõlas käesolevas litsentsis sätestatud täieliku kasutamisvabadusega. + +Enamus GNU tarkvara, kaasaarvatud mõned teegid, on kaitstud tavalise GNU Üldise Avaliku Litsentsiga. Käesolev litsents, GNU Vähem Üldine Avalik Litsents, kehtib teatud kindlatele teekidele ja on tavalisest Üldisest Avalikust Litsentsist küllaltki erinev. Me kasutame käesolevat litsentsi, et lubada mitte-vabade programmide linkimist nende teekidega. + +Kui programm on lingitud teegiga, kas staatiliselt või kasutades jagatud teeki, on nende kombinatsioon juriidilises mõistes ühendatud töö, algsest teegist tulenev. Tavaline Üldine Avalik Litsents lubab seega sellist linkimist ainult kui kogu kombinatsioon vastab selle vabaduse nõudele. Vähem Üldine Avalik Litsents lubab vabamalt muud koodi teegiga siduda. + +Me nimetame käesolevat litsentsi "Vähem" Üldiseks Avalikuks Litsentsiks, sest see teeb kasutaja vabaduse kaitsmiseks vähem kui tavaline Üldine Avalik Litsents. See annab teistele vaba tarkvara arendajatele ka vähem eeliseid konkureerimaks mitte-vabade programmidega. Nende puuduste tõttu kasutame me paljude teekide puhul tavalist Üldist Avalikku Litsentsi. Siiski annab Vähem Üldine Avalik Litsents teatud kindlates olukordades eeliseid. + +Näiteks võib harvadel juhtudel olla eriline vajadus julgustada teatud teegi võimalikult laia kasutamist, et see muutuks de-facto standardiks. Selle saavutamiseks peab mitte-vabadele programmidele lubama teegi kasutamist. Sagedamini juhtub, et vaba teek teeb ära sama töö kui laialdaselt kasutatavad mitte-vabad teegid. Sel juhul on vähe kasu vaba teegi kasutamise piiramisest ainult vabale tarkvarale ning me kasutame Vähem Üldist Avalikku Litsentsi . + +Teistel juhtudel võimaldab luba kasutada teatud teeki mitte-vabades programmides suuremal hulgal inimestel kasutada suurt hulka vaba tarkvara. Näiteks, luba kasutada GNU C teeki mitte-vabades programmides võimaldab suuremal hulgal inimestel kasutada kogu GNU operatsioonisüsteemi ning ka selle varianti, GNU/Linux operatsioonisüsteemi. + +Kuigi Vähem Üldine Avalik Litsents kaitseb vähem kasutaja vabadust, kindlustab see, et teegiga lingitud programmi kasutajal on vabadus ja vajalikud vahendid töötamaks programmiga kasutades teegi muudetud versiooni. + +Järgnevad kopeerimise, levitamise ja muutmise täpsed terminid ning tingimused. + +Pöörake tähelepanu erinevusele "teegil põhinev teos " ja "teeki kasutav teos" vahel. Esimene sisaldab teegist tuletatud koodi, teise peab teegiga ühendama, et töötada. + +Kopeerimise, levitamise ja muutmise terminid ja tingimused. + +0. Käesolev Litsentsileping kehtib iga tarkvara teegi või muu programmi puhul, mis sisaldab autoriõiguse omaniku või muu pädeva poole märget selle kohta, et antud programmi võib levitada vastavalt käesoleva Vähem Üldise Avaliku Litsentsi (edaspidi: käesolev Litsents) tingimustele. Iga litsentsiaat on edaspidi "Teie". + +"Teek" tähendab tarkvara funktsioonide kogumit ja/või andmeid, mis on ette valmistatud mugavaks linkimiseks rakendusprogrammidega (mis kasutavad neid funktsioone või andmeid), et luua käivitatavaid teoseid. + +Allpool viitab "Teek" igasugusele tarkvara teegile või teosele, mida levitatakse nende tingimuste kohaselt. "Teegil põhinev teos" tähendab kas Teeki või igasugust autoriõiguse kohaselt tuletatud teost: see tähendab, teost, mis sisaldab Teeki või osa sellest, kas originaalis või muudetuna ja/või otse teise keelde tõlgituna. (Nüüd ja edaspidi, tõlge kuulub piiranguteta mõiste "muutmine" alla.) + +Teose "Lähtekood" tähendab teose eelistatumat vormi, millesse muudatusi teha. Teegi täielik lähtekood tähendab kõikide moodulite, mida ta sisaldab, lähtekoode ja kõiki sellega seotud liidese definitsioonifaile ning skripte, mida kasutatakse teegi kompileerimise ja paigaldamise kontrollimiseks. + +Litsents ei laiene muudele tegevustele kui kopeerimine, levitamine ja muutmine; need ei ole Litsentsiga kaetud. Teeki kasutava programmiga töötamisel pole kitsendusi ja Programmi väljund on kaitstud vaid siis, kui selles sisaldub teos, mis põhineb Teegil (sõltumatuna sellest, et see on kirjutatud Teegi abil). Kas see on tõene, sõltub sellest mida Teek teeb ja mida Teeki kasutav programm teeb. + +1. Te võite kopeerida ja levitada sõnasõnalisi koopiaid Teegi täielikust lähtekoodist nii, nagu olete selle saanud, igas vormis, eeldusel, et Te avaldate arusaadavalt ja sobivalt igal koopial vastava autoriõiguse märke ja garantii välistamise märke: hoiate puutumatuna kõik märked, mis viitavad käesolevale Litsentsile ja igasugusele garantii puudumisele ning levitate Teeki koos käesoleva Litsentsi koopiaga. + +Te võite võtta tasu koopia füüsilise kättetoimetamise akti eest ning võite oma valiku kohaselt pakkuda tasu eest omapoolset garantiikaitset. + +2. Te võite muuta Teegi koopiat või koopiaid või ükskõik millist selle osa, luues nii Teegil põhineva teose ning kopeerida ja levitada selliseid muudatusi või teoseid vastavalt punkti 1 tingimustele, eeldades, et Te täidate kõik järgnevad tingimused: + +a) muudetud teos peab ise olema tarkvara teek. + +b) Te peate kaasama muudetud failile silmatorkavad märked, mis teatavad Teie poolt tehtud muudatused failides ja iga muudatuse kuupäeva. + +c) Te peate koge teose tasuta litsenseerima kõigile kolmandatele isikutele vastavalt käesoleva Litsentsi tingimustele. + +d) Kui muudetud teegi poolt pakutav teenus kasutab funktsiooni või andmeid, mille peab pakkuma rakendus, mis kasutab teenust, kuid mis ei ole selle teenuse väljakutsumise argumendiks, siis peate Te tegema kõik, et tagada teenuse töö ka juhul, kui rakendus vajalikku funktsiooni või andmeid ei paku ja teostab ükskõik millise osa oma otstarbest ning mis ka mõtet omab. + +(Näiteks teegis olev funktsioon ruutjuure arvutamiseks omab otstarvet, mis on täiesti sõltumatu rakendusest. Seega, alapunkt 2d nõuab, et iga rakenduse poolt pakutav funktsioon või andmekogum, mida see funktsioon kasutaks, poleks kohustuslik: kui rakendus neid funktsioone või andmeid ei paku, peab ruutjuure funktsioon ikkagi arvutama ruutjuurt.) + +Need nõuded kehtivad nii muudetud teosele kui ka tervikule. Kui eristatavad osad teosest ei ole tuletatud Teegist ja neid võib mõistlikult pidada iseseisvateks ja eraldi teosteks, siis käesolev Litsents ja selle tingimused ei kehti nende osade suhtes kui Te levitate neid kui eraldi teoseid. Aga kui Te levitate samu osasid osana tervikust, mis on Teegil põhinev teos, peab levitamine toimuma vastavalt käesoleva Litsentsi tingimustele, mille lubadused teistele litsensiaatidele laienevad kogu teosele ja seega igale osale, olenemata sellest, kes selle kirjutas. Seega pole käesoleva punkti eesmärk nõuda õigusi või vaidlustada Teie õigusi teosele, mille Te olete tervikuna loonud; pigem on eesmärk kasutada õigust suunata Teegil põhinevate teoste või ühisteoste levitamist. + +Lisaks, ainuüksi asjaolu, et ühtsesse levitamis- või säilitusvormi on liidetud teine teos, mis ei põhine Teegil, Teegiga (või Teegil põhineva teosega), ei muuda nimetatud teost käesoleva Litsentsi alla kuuluvaks. + +3. Te võite valida, et teatud Teegi koopiale kehtivad käesoleva Litsentsi asemel tavalise GNU Üldise Avaliku Litsentsi tingimused. Selleks peate Te muutma kõiki märkeid, mis viitavad käesolevale Litsentsile, nii et need viitaksid selle asemel tavalisele GNU Üldise Avaliku Litsentsi versioonile 2. (Kui ilmub uuem GNU Üldise Avaliku Litsentsi versioon kui praegune versioon 2, võite täpsustada selle versiooni kui soovite.) Ärge tehke neis märgetes muid muudatusi. + +Kui teatud koopiale on nimetatud muudatus tehtud, on see selle koopia suhtes pöördumatu, nii et tavaline GNU Üldine Avalik Litsents kehtib kõigi sellest koopiast tulenevate teoste ja järgnevate koopiate suhtes. + +See võimalus on kasulik, kui Te soovite kopeerida osa Teegi koodist programmi, mis pole Teek. + +4. Te võite Teeki kopeerida ja levitada (või punkti 2 kohaselt Teegi osa või Teegil põhinevat teost) objektkoodina või käivitataval kujul vastavalt punktide 1 ja 2 kohaselt eeldusel, et Te lisate sellele täieliku vastava masinloetava lähteteksti, mida peab levitama vastavalt punktides 1 ja 2 toodud tingimustele, vormis, mida kasutatakse valdavalt tarkvara vahendustegevuses. + +Kui objektkoodi levitamine toimub ligipääsu pakkumisega kopeerimiseks määratud kohas, siis ligipääsu pakkumine lähteteksti kopeerimiseks samast kohast loetakse võrdseks lähteteksti levitamisega, kuigi kolmandad osapooled pole kohustatud koos objektkoodiga lähteteksti kopeerima. + +5. Programmi, mis ei sisalda Teegi osa ega Teegist tuletatud teost, aga on loodud töötama koos Teegiga kompileerimise kaudu või lingitud sellega, kutsutakse "Teeki kasutavaks teoseks". Selline teos ei ole eraldiseisvana Teegist tuletatud teos ja ei ole seega käesoleva Litsentsiga kaetud. + +Siiski, "Teeki kasutava teose" Teegiga linkimine loob käivitatava vormi, mis on Teegist tuletatud (sest see sisaldab Teegi osi), mitte "Teeki kasutava teose". Käivitatav vorm on seega käesoleva Litsentsiga kaetud. Punktis 6 sätestatakse selliste käivitatavate vormide levitamise tingimused. + +Kui "Teeki kasutav teos" kasutab materjali Teegi osaks olevast päisefailist, võib teose objektkood olla Teegist tuletatud teos kuigi lähtekood seda pole. Kas see on tõene, on eriti tähtis, kui teost saab linkida ilma Teegita, või teos ise on Teek. Kas see on tõene, ei ole täpselt seadusega sätestatud. + +Kui selline objektfail kasutab ainult arvparameetreid, andmete struktuuri paigutust ja lisandeid, väikseid makrosid ja väikseid inline funktsioone (kümme märki või vähem pikad), siis pole objektfaili kasutamine piiratud, vaatamata sellele, et see on juriidiliselt tuletatud teos. (Käivitatavad failid, mis sisaldavad seda objektkoodi ja osi Teegist on ikkagi kaetud punktiga 6.) + +Vastasel juhul, kui teos tuleneb Teegist, võite Te levitada teose objektkoodi vastavalt punktis 6 toodud tingimustele. Iga käivitatav vorm, mis sisaldab teost, käib samuti punkti 6 alla, vaatamata sellele kas need on otseselt Teegiga seotud. + +6. Ülaltoodud punktide erandina võite Te kombineerida või linkida "Teeki kasutava teose" Teegiga, et luua teost, mis sisaldab Teegi osi, ning levitada seda teost vastavalt oma tingimustele, eeldusel, et tingimused lubavad teose muutmist kliendi soovil ning pöördprojekteerimist (reverse engineering) selliste muudatuste silumiseks. + +Te peate andma silmatorkavad märked igale Teeki kasutava teose koopiale, et selles on kasutatud Teeki ning et Teegi kasutamine on kaetud käesoleva Litsentsiga. Te peate pakkuma käesoleva Litsentsi koopiat. Kui teos kuvab käivitamisel autoriõiguse märked, peate Te lisama neile ka Teegi autoriõiguse märke ja viite, mis juhatab kasutaja käesoleva Litsentsi koopia juurde. Samuti peate Te tegema ühe järgmistest asjadest: + +a) Lisama teosele täieliku vastava masinloetava Teegi lähteteksti, kaasa arvatud muudatused, mida kasutati teoses (mida peab levitama vastavalt Punktidele 1 ja 2); ja, kui teos on Teegiga lingitud käivitatav vorm, koos täieliku masinloetava "Teeki kasutava teose" objektkoodiga ja/või lähtekoodiga, et kasutaja saaks muuta Teeki ja uuesti linkida, et valmistada muudetud käivitatavat vormi, mis sisaldab muudetud Teeki. (On arusaadav, et kasutaja, kes muudab Teegi definitsioonifailide sisu, ei ole tingimata võimeline rakendust uuesti kompileerima, et muudetud definitsioone kasutada.) + +b) Kasutama Teegiga linkimiseks sobivat jagatud mehanismi. Mehanism on sobiv kui see (1) kasutab käitusajal koopiat Teegist, mis juba on kasutaja arvutisüsteemis, mitte ei kopeeri teegi funktsioone käivitatavasse vormi, ja (2) töötab korralikult teegi muudetud variandiga, kui kasutaja selle installeerib, tingimusel, et muudetud variant on liides-ühilduv variandiga, millega teos tehti. + +c) Lisama teosele kirjaliku pakkumise, mis kehtib vähemalt 3 aastat, et anda samale kasutajale alapunktis 6a nimetatud materjalid, mitte kallimalt kui levitamise hinnaga. + +d) Kui teost levitatakse ligipääsu pakkumise teel koopiale määratud kohas, võrdub pakkumine ligipääsuga kopeerida ülalnimetatud materjalid samast kohast. + +e) Kontrollima, et kasutaja on juba saanud koopia nii nendest materjalidest või sa oled juba saatnud sellel kasutajale koopia. + +Käivitatava vormi jaoks peab "Teeki kasutava teose" nõutud vorm sisaldama andmeid ja utiliite, mis on vajalikud käivitatava vormi taasloomiseks. Siiski, erilise erandina, ei pea levitatavad materjalid sisaldama midagi (ei lähte- ega kahendvormis), mida tavaliselt levitatakse koos operatsioonisüsteemi põhiliste osadega (kompilaator, kernel jne.), millel käivitatav vorm töötab, välja arvatud juhul kui see osa käib käivitatava vormiga kaasas. + +Võib juhtuda, et see nõue läheb vastuollu teiste kaitstud teekide litsentsi piirangutega, mis tavaliselt ei käi operatsioonisüsteemiga kaasas. Selline vastuolu tähendab, et Te ei saa kasutada käivitatavas vormis, mida Te levitate, neid ja Teeki koos. + +7. Te võite panna teegi teenused, mis on Teegil põhinevad teosed, kõrvuti ühte teeki koos teiste teegi teenustega, mis ei ole kaetud käesoleva Litsentsiga, ja levitada sellist ühendatud teeki, tingimusel, et Teegil põhineva teose ja teiste teegi vahendite eraldi levitamine on lubatud ja et Te teete järgmised asjad: + +a) lisate ühendatud teegile koopia samast teosest, mis põhineb Teegil, mis ei ole ühendatud teiste Teegi vahenditega. Seda peab levitama vastavalt ülaltoodud punktidele. + +b) annate koos ühendatud teegiga silmatorkavad märked asjaolust, et osa sellest on Teegil põhinev teos, ja seletate kust leida sama teose mitte ühendatud vorm. + +8. Te ei tohi kopeerida, muuta, edasi litsentseerida, linkida või levitada Teeki teisiti kui käesolevas Litsentsis väljendatud. Iga katse kopeerida, muuta, edasi litsentseerida, linkida või levitada Teeki teisiti, on kehtetu ja lõpetab automaatselt Teie õigused vastavalt käesolevale Litsentsile. Siiski, osapoolte litsentse, kes on saanud koopiad või õigused Teilt vastavalt käesolevale Litsentsile, ei lõpetata nii kaua kui kõik osapooled täidavad täielikult kehtestatud tingimusi. + +9. Te ei pea käesolevat Litsentsi arvestama, kuna Te pole sellele alla kirjutanud. Siiski, miski muu ei anna Teile luba muuta või levitada Teeki või sellest tulenevaid teoseid. Need tegevused on keelatud seadusega kui Te käesoleva Litsentsiga ei arvesta. Seega, muutes või levitades Teeki (või teegil põhinevat teost) näitate Te seda tehes oma nõusolekut käesoleva Litsentsiga ning kõigi selle Teegi või teegil põhineva teose kopeerimise, levitamise või muutmise terminite ja tingimustega. + +10. Iga kord kui Te Teeki (või Teegil põhinevat teost) edasi levitate, saab vastuvõtja automaatselt originaallitsenstiaarilt litsentsi kopeerida, levitada, linkida või muuta Teeki vastavalt nendele terminitele ja tingimustele. Te ei tohi kohustada vastuvõtjat rohkem millekski temale siin antud õiguste kasutamisel. Te ei ole vastutav kolmandate poolte poolt kehtestatud tingimuste täitmise eest. + +11. Kui kohtulahendi või väidetava patendiõiguse rikkumise tagajärjel või mõnel muul põhjusel (mis ei piirdu patendiga seotud küsimustega) on Teile pandud kohustusi, mis on vastuolus käesoleva Litsentsi tingimustega, siis ei vabasta need Teid käesoleva Litsentsi tingimuste täitmisest. Kui Te ei suuda Teeki levitada, täites samaaegselt käesoleva Litsentsi tingimusi ja teisi kohustusi, siis ei tohi Te Teeki üldse levitada. Näiteks kui patendilitsents ei luba Teil litsentsitasuta Teeki edasi levitada neile, kes on saanud Teilt või Teie kaudu Teegi koopia, siis ainus võimalus täita nimetatud patendilitsentsi ja käesoleva Litsentsi tingimusi on loobuda Teegi levitamisest. + +Kui käesoleva punkti mõni osa osutub mingil asjaolul kehtetuks või mitterakendatavaks, siis käesoleva punkti ülejäänud osa loetakse rakendatavaks ja punkt tervikuna loetakse rakendatavaks ülejäänud tingimustel. + +Käesoleva punkti eesmärk ei ole kellegi ajendamine patendi- või muude õiguste rikkumiseks või nende kehtivuse vaidlustamiseks; käesoleva punkti ainus eesmärk on vaba tarkvara levitamise süsteemi terviklikkuse kaitsmine, mida kasutavad avalike litsentside kasutajad. Paljud isikud on andnud suure panuse tarkvara laiale sektorile, mida levitatakse läbi nimetatud süsteemi usaldades järjekindlat süsteemi rakendumist; autor/annetaja on otsustaja, kas ta soovib tarkvara levitada mõne teise süsteemi kaudu ja litsenstiaat ei saa seda valikut mõjutada. + +Selle punkti eesmärk on täpselt selgitada, mida soovitakse käesoleva Litsentsi ülejäänud osaga saavutada. + +12. Kui Teegi levitamist ja/või kasutamist piiratakse mõnedes riikides kas patentide või autoriõigusega, võib autoriõiguse omanik, kes on Teegi litsenseerinud, lisada kindla geograafilise piirangu, jättes nimekirjast välja mainitud riigid, et levitamine oleks lubatud vaid nimekirjas toodud riikides või riikide vahel. Nimetatud juhul Litsents liitub piiranguga, nagu see on ära toodud käesoleva Litsentsi põhiosas. + +13. Free Software Foundation võib aeg-ajalt välja anda ümbertöötatud ja/või uusi versioone Vähem Üldisest Avalikust Litsentsist. Need uued versioonid on käesoleva Litsentsi versiooniga sarnase sisuga, kuid võivad erineda detailides, osundades uusi probleeme või huviobjekte. + +Igale versioonile antakse unikaalne versiooninumber. Kui Teegis tuuakse ära selle kohta kehtiva käesoleva litsentsi versiooninumber ja lisatakse märge "kõik hilisemad versioonid", siis on Teil võimalik valida, kas järgida selle või ükskõik millise hilisema Free Software Foundation'i poolt avaldatava versiooni tingimusi. Kui Teek ei täpsusta käesoleva litsentsi versiooninumbrit, on Teil võimalus valida ükskõik milline Free Software Foundation'i poolt avaldatud käesoleva Litsentsi versioon. + +14. Kui Te soovite Teegi osi liita teiste vabade teekidega, mille levitamise tingimused on erinevad, siis kirjutage loa saamiseks autorile. Tarkvara puhul, mis on autoriõigusega kaitstud Free Software Foundation'i poolt, kontakteeruge Free Software Foundation'iga, mõnikord me teeme erandeid. Meie otsuse määravad kaks eesmärki: säilitada vaba staatus meie vaba tarkvara igasugustele derivaatidele ja edendada tarkvara jagamist ning taaskasutamist üldiselt. + +GARANTII PUUDUMINE + +15. KUNA PROGRAMM ON LITSENSEERITUD TASUTA, PUUDUB TEEGIL IGASUGUNE GARANTII ULATUSENI, MIDA LUBAB RAKENDATAV SEADUS. KUI KIRJALIKULT POLE TEISITI SÄTESTATUD, SIIS AUTORIÕIGUSE OMANIKUD JA/VÕI MUUD OSAPOOLED PAKUVAD TEEKI "NII, NAGU TA ON" ILMA IGASUGUSE VÄLJENDATUD VÕI OLETATAVA GARANTIITA, KAASA ARVATUD, KUID MITTE AINULT, KESKMISE/TAVALISE KVALITEEDI JA MINGILE KINDLALE EESMÄRGILE SOBIVUSE GARANTIITA. KOGU TEEGI KVALITEEDI JA TOIMIMISE RISK LANGEB TEILE. KUI TEEK ON PUUDULIK, KANNATE TEIE KÕIK TEENINDUSE, PARANDUSE VÕI TAASTAMISE KULUD. + +16. MITTE MINGIL JUHUL, VÄLJA ARVATUD SIIS, KUI SEDA NÕUAB RAKENDATAV SEADUS VÕI KIRJALIKULT ON TEISITI KOKKU LEPITUD, POLE ÜKSKI AUTORIÕIGUSE OMANIK VÕI KOLMAS OSAPOOL, KES VÕIB MUUTA JA/VÕI LEVITADA TEEKI VASTAVALT ÜLALPOOL TOODUD TINGIMUSTELE, TEIE EES VASTUTAV KAHJUSTUSTE EEST, KAASA ARVATUD IGASUGUSED ÜLDISED, SPETSIIFILISED, JUHUSLIKUD VÕI TAGAJÄRJEL TEKKINUD KAHJUD, MIS TULENEVAD KAS TEEGI KASUTAMISEST VÕI VÕIMATUSEST TEEKI KASUTADA (KAASA ARVATUD, KUID MITTE AINULT, TEIE VÕI KOLMANDATE OSAPOOLTE ANDMETE KADUMINE VÕI ANDMETE MUUTMINE VÕI TEEGI VÕIMETUS TÖÖTADA KOOS MISTAHES MUU TARKVARAGA), ISEGI SIIS, KUI VALDAJAT VÕI MUUD OSAPOOLT ON TEAVITATUD SELLISTE KAHJUDE VÕIMALIKKUSEST. + +TERMINITE JA TINGIMUSTE LÕPP. + +Kuidas rakendada oma uutele teekidele neid termineid ja tingimusi? + +Kui Te loote uue teegi ja soovite, et see olekas avalikkusele võimalikult kasulik, soovitame selle muuta vabaks tarkvaraks, et igaüks saaks seda edasi levitada ja muuta. Te võite seda teha lubades edasi levitamist vastavalt käesolevatele tingimustele (või vastavalt tavalise Üldise Avaliku Litsentsi tingimustele). + +Et rakendada neid tingimusi, lisage teegile järgmised märkused. Kõige kindlam on lisada need märked iga lähtefaili algusse, et võimalikult efektiivselt teatada garantii puudumisest: igal failil peaks olema vähemalt üks "autoriõiguse" rida ja viide kohale, kust võib leida tervikliku märkuse. + +üks rida teegi nime jaoks ja mida see teeb + +Copyright (C) aasta autori nimi + +Käesolev teek on vaba tarkvara. Te võite seda edasi levitada ja/või muuta vastavalt GNU Vähem Üldise Avaliku Litsentsi tingimustele, nagu need on Vaba Tarkvara Fondi poolt avaldatud; kas Litsentsi versioon number 2.1 või (vastavalt Teie valikule) ükskõik milline hilisem versioon. + +Seda teeki levitatakse lootuses, et see on kasulik, kuid ILMA IGASUGUSE GARANTIITA; isegi KESKMISE/TAVALISE KVALITEEDI GARANTIITA või SOBIVUSELE TEATUD KINDLAKS EESMÄRGIKS. Üksikasjalise info saamiseks vaata GNU Üldist Vähem Avalikku Litsentsi. + +Te peaks olema saanud GNU Üldise Vähem Avaliku Litsentsi koopia koos selle teegiga, kui ei, siis kontakteeruge Free Software Foundation'iga, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Samuti lisage informatsioon, kuidas Teiega kontakteeruda kas posti või meili teel. + +Te peaksite laskma oma tööandjal (kui te töötate programmeerijana), või koolil alla kirjutada autoriõiguslike pretensioonide loobumise kohta käivale dokumendile. Siin on näidis, muutke ise nimed: + +Yoyodyne, Inc., loobub kõigist autoriõigustest teegile "Frob", mille on kirjutanud James Random Hacker. + +allkiri, 1 April 1990 + +Ty Coon, President of Vice + +---------------------------------------------- + +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + +a) The modified work must itself be a software library. +b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. +c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. +d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) +b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. +c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. +d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. +e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. 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 not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. +b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the 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 specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library 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 2.1 of the License, or (at your option) any later version. + +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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/assets/spelling/licenses/et_EE/README_hyph_et_EE.txt b/assets/spelling/licenses/et_EE/README_hyph_et_EE.txt new file mode 100644 index 00000000..854c053c --- /dev/null +++ b/assets/spelling/licenses/et_EE/README_hyph_et_EE.txt @@ -0,0 +1,408 @@ +Eesti keele poolitamist kirjeldav fail OpenOffice.org jaoks +Estonian hyphenation for OpenOffice.org +================================================== +versioon 1.0 /version 1.0 +juuni 2004 / June 2004 + +1. Üldist / General +------------------- + +Käesolev poolitusfail on mõeldud OpenOffice.org tarbeks. +Sõnastiku paigaldamiseks tuleb tegutseda vastavalt OpenOffice.org käsiraamatus toodud +juhistele. +README käesoleva versiooni on koostanud ja poolitusfaili pakendanud Ain Vagula +(vagula@openoffice.org) + +This hyphenation file is created for OpenOffice.org. +To install the hyphenation file refer to the OpenOffice.orgOnline Help. +Current version of README is written and packages are made by Ain Vagula +(vagula@openoffice.org) + +2. Autorid ja litsentsid / Authors and licenses +----------------------------------------------- + +Poolitusfaili on OpenOffice.org jaoks kohandanud Jaak Pruulmann (jjpp@meso.ee, +http://www.meso.ee/~jjpp/speller/ ), kes on oma töö pannud GNU LGPL-i (GNU Vähem Üldine +Avalik Litsents) alla. +Kasutatud on Enn Saare (saar@aai.ee) poolt koostatud LaTeX-i poolitusfaili. Enn Saar on +allkirjastanud JCA (Joint Copyright Agreement), mis lubab tema tööd OpenOffice.org +koosseisus kasutada. +Originaalfail on saadaval asukohas: http://www.cs.ut.ee/~tqnu/eehyph.tex ja selle päises on ka viide LPPL litsentsile. + +Hyphenation file is adapted to OpenOffice.org by Jaak Pruulmann (jjpp@meso.ee, +http://www.meso.ee/~jjpp/speller/ ) on the base of the LaTeX hyphenation file created by Enn +Saar (saar@aai.ee), who has signed the JCA (Joint Copyright Agreement) allowing to use +his work for OpenOffice.org. The original file is available at address http://www.cs.ut.ee/~tqnu/eehyph.tex and in the heading of the file it is written that this file is licensed under LPPL. +The work of Jaak Pruulmann is licensed under LGPL (GNU Lesser General Public License). + +----------------------------------- + +GNU Vähem Üldine Avalik Litsents + +Versioon number 2.1, Veebruar 1999 + +Autoriõigus (C) 1991, 1999 Free Software Foundation, Inc. + +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Igaüks võib käesolevast dokumendist valmistada koopiaid ning valmistatud koopiaid levitada tingimusel, et need koopiad vastavad originaaldokumendile sõnasõnalt. + +[See on GNU Vähem Üldise Avaliku Litsentsi esimene avaldatud versioon. See on ka GNU Üldise Avaliku Litsentsi versiooni 2 järeltulija, seega on versiooni number 2.1.] + +Eessõna + +Enamik tarkvara litsentse on loodud selleks, et võtta Teilt õigus tarkvara jagada ja muuta. + +Vastukaaluks on GNU Üldine Avalik Litsents mõeldud selleks, et tagada Teile vabadus jagada ja muuta vaba tarkvara - kindlustada, et tarkvara oleks vaba kõigile selle kasutajatele. + +Käesolev, Vähem Üldine Avalik Litsents, kehtib mõnele spetsiaalse suunitlusega Free Software Foundation'i ja teiste autorite, kes otsustavad seda kasutada, poolt loodud tarkvara pakettidele - tavaliselt teekidele. Ka Teie võite käesolevat litsentsi kasutada, kuid soovitame Teil allpool toodud selgitustele tuginedes igal üksikjuhul enne hoolega mõelda, kas strateegiliselt on parem kasutada käesolevat litsentsi või tavalist Üldist Avalikku Litsentsi. + +Rääkides vabast tarkvarast peame silmas vabadust, mitte hinda. Üldised Avalikud Litsentsid on loodud selleks, et tagada Teile järgnevat: õigust levitada koopiaid vabast tarkvarast (soovi korral ka levitamise eest tasu võttes), tarkvara lähtetekstide kättesaadavust, õigust tarkvara muuta või kasutada tarkvara osi uute vaba tarkvaratoodete loomisel ning kindlustada, et Te olete teadlik eelpoolnimetatud õigustest. + +Teie õiguste tagamiseks on vaja rakendada mõningaid piiranguid, et levitajad ei saaks Teilt neid õigusi ära võtta või nõuda nendest loobumist. Tarkvara muutmisel või selle koopiate levitamisel kätkevad need piirangud Teie jaoks teatud kohustusi. + +Näiteks levitades teegi koopiaid, kas tasuta või levitamise eest tasu võttes, peate Te saajatele andma kõik need õigused, mis meie Teile andsime. Te peate kindlustama, et ka nemad saavad või võivad soovi korral saada lähteteksti. + +Kui Te lingite teegiga muud koodi, peate andma saajatele ka täielikud objektfailid, et nad saaksid pärast muudatuste tegemist teegis ja selle uuesti kompileerimist neid uuesti teegiga linkida. Ning Te peate neid teavitama käesoleva Litsentsi tingimustest, et nad teaksid oma õigusi. + +Me kaitseme Teie õigusi kaheastmeliselt: + +1. anname teegile autoriõiguse, ja + +2. pakume Teile käesolevat litsentsi, mis annab Teile seadusliku õiguse kopeerida, levitada ja/või muuta teeki. + +Iga levitaja kaitsmiseks tahame me teha väga selgeks, et vabal teegil pole garantiid. Kui keegi teeki muudab ja edasi levitab, peavad selle saajad teadma, et nende omanduses pole originaal vältimaks teiste poolt põhjustatud probleemide mõju originaali autori mainele. + +Lõpuks, tarkvara patendid kujutavad pidevat ohtu mistahes vaba programmi olemasolule. Me soovime kindlustada, et ükski firma ei saaks efektiivselt piirata vaba programmi kasutajaid saades patendi omanikult piirava litsentsi. Seega - me nõuame, et mistahes patendi litsents, mis on saadud teegi versioonile, peab olema kooskõlas käesolevas litsentsis sätestatud täieliku kasutamisvabadusega. + +Enamus GNU tarkvara, kaasaarvatud mõned teegid, on kaitstud tavalise GNU Üldise Avaliku Litsentsiga. Käesolev litsents, GNU Vähem Üldine Avalik Litsents, kehtib teatud kindlatele teekidele ja on tavalisest Üldisest Avalikust Litsentsist küllaltki erinev. Me kasutame käesolevat litsentsi, et lubada mitte-vabade programmide linkimist nende teekidega. + +Kui programm on lingitud teegiga, kas staatiliselt või kasutades jagatud teeki, on nende kombinatsioon juriidilises mõistes ühendatud töö, algsest teegist tulenev. Tavaline Üldine Avalik Litsents lubab seega sellist linkimist ainult kui kogu kombinatsioon vastab selle vabaduse nõudele. Vähem Üldine Avalik Litsents lubab vabamalt muud koodi teegiga siduda. + +Me nimetame käesolevat litsentsi "Vähem" Üldiseks Avalikuks Litsentsiks, sest see teeb kasutaja vabaduse kaitsmiseks vähem kui tavaline Üldine Avalik Litsents. See annab teistele vaba tarkvara arendajatele ka vähem eeliseid konkureerimaks mitte-vabade programmidega. Nende puuduste tõttu kasutame me paljude teekide puhul tavalist Üldist Avalikku Litsentsi. Siiski annab Vähem Üldine Avalik Litsents teatud kindlates olukordades eeliseid. + +Näiteks võib harvadel juhtudel olla eriline vajadus julgustada teatud teegi võimalikult laia kasutamist, et see muutuks de-facto standardiks. Selle saavutamiseks peab mitte-vabadele programmidele lubama teegi kasutamist. Sagedamini juhtub, et vaba teek teeb ära sama töö kui laialdaselt kasutatavad mitte-vabad teegid. Sel juhul on vähe kasu vaba teegi kasutamise piiramisest ainult vabale tarkvarale ning me kasutame Vähem Üldist Avalikku Litsentsi . + +Teistel juhtudel võimaldab luba kasutada teatud teeki mitte-vabades programmides suuremal hulgal inimestel kasutada suurt hulka vaba tarkvara. Näiteks, luba kasutada GNU C teeki mitte-vabades programmides võimaldab suuremal hulgal inimestel kasutada kogu GNU operatsioonisüsteemi ning ka selle varianti, GNU/Linux operatsioonisüsteemi. + +Kuigi Vähem Üldine Avalik Litsents kaitseb vähem kasutaja vabadust, kindlustab see, et teegiga lingitud programmi kasutajal on vabadus ja vajalikud vahendid töötamaks programmiga kasutades teegi muudetud versiooni. + +Järgnevad kopeerimise, levitamise ja muutmise täpsed terminid ning tingimused. + +Pöörake tähelepanu erinevusele "teegil põhinev teos " ja "teeki kasutav teos" vahel. Esimene sisaldab teegist tuletatud koodi, teise peab teegiga ühendama, et töötada. + +Kopeerimise, levitamise ja muutmise terminid ja tingimused. + +0. Käesolev Litsentsileping kehtib iga tarkvara teegi või muu programmi puhul, mis sisaldab autoriõiguse omaniku või muu pädeva poole märget selle kohta, et antud programmi võib levitada vastavalt käesoleva Vähem Üldise Avaliku Litsentsi (edaspidi: käesolev Litsents) tingimustele. Iga litsentsiaat on edaspidi "Teie". + +"Teek" tähendab tarkvara funktsioonide kogumit ja/või andmeid, mis on ette valmistatud mugavaks linkimiseks rakendusprogrammidega (mis kasutavad neid funktsioone või andmeid), et luua käivitatavaid teoseid. + +Allpool viitab "Teek" igasugusele tarkvara teegile või teosele, mida levitatakse nende tingimuste kohaselt. "Teegil põhinev teos" tähendab kas Teeki või igasugust autoriõiguse kohaselt tuletatud teost: see tähendab, teost, mis sisaldab Teeki või osa sellest, kas originaalis või muudetuna ja/või otse teise keelde tõlgituna. (Nüüd ja edaspidi, tõlge kuulub piiranguteta mõiste "muutmine" alla.) + +Teose "Lähtekood" tähendab teose eelistatumat vormi, millesse muudatusi teha. Teegi täielik lähtekood tähendab kõikide moodulite, mida ta sisaldab, lähtekoode ja kõiki sellega seotud liidese definitsioonifaile ning skripte, mida kasutatakse teegi kompileerimise ja paigaldamise kontrollimiseks. + +Litsents ei laiene muudele tegevustele kui kopeerimine, levitamine ja muutmine; need ei ole Litsentsiga kaetud. Teeki kasutava programmiga töötamisel pole kitsendusi ja Programmi väljund on kaitstud vaid siis, kui selles sisaldub teos, mis põhineb Teegil (sõltumatuna sellest, et see on kirjutatud Teegi abil). Kas see on tõene, sõltub sellest mida Teek teeb ja mida Teeki kasutav programm teeb. + +1. Te võite kopeerida ja levitada sõnasõnalisi koopiaid Teegi täielikust lähtekoodist nii, nagu olete selle saanud, igas vormis, eeldusel, et Te avaldate arusaadavalt ja sobivalt igal koopial vastava autoriõiguse märke ja garantii välistamise märke: hoiate puutumatuna kõik märked, mis viitavad käesolevale Litsentsile ja igasugusele garantii puudumisele ning levitate Teeki koos käesoleva Litsentsi koopiaga. + +Te võite võtta tasu koopia füüsilise kättetoimetamise akti eest ning võite oma valiku kohaselt pakkuda tasu eest omapoolset garantiikaitset. + +2. Te võite muuta Teegi koopiat või koopiaid või ükskõik millist selle osa, luues nii Teegil põhineva teose ning kopeerida ja levitada selliseid muudatusi või teoseid vastavalt punkti 1 tingimustele, eeldades, et Te täidate kõik järgnevad tingimused: + +a) muudetud teos peab ise olema tarkvara teek. + +b) Te peate kaasama muudetud failile silmatorkavad märked, mis teatavad Teie poolt tehtud muudatused failides ja iga muudatuse kuupäeva. + +c) Te peate koge teose tasuta litsenseerima kõigile kolmandatele isikutele vastavalt käesoleva Litsentsi tingimustele. + +d) Kui muudetud teegi poolt pakutav teenus kasutab funktsiooni või andmeid, mille peab pakkuma rakendus, mis kasutab teenust, kuid mis ei ole selle teenuse väljakutsumise argumendiks, siis peate Te tegema kõik, et tagada teenuse töö ka juhul, kui rakendus vajalikku funktsiooni või andmeid ei paku ja teostab ükskõik millise osa oma otstarbest ning mis ka mõtet omab. + +(Näiteks teegis olev funktsioon ruutjuure arvutamiseks omab otstarvet, mis on täiesti sõltumatu rakendusest. Seega, alapunkt 2d nõuab, et iga rakenduse poolt pakutav funktsioon või andmekogum, mida see funktsioon kasutaks, poleks kohustuslik: kui rakendus neid funktsioone või andmeid ei paku, peab ruutjuure funktsioon ikkagi arvutama ruutjuurt.) + +Need nõuded kehtivad nii muudetud teosele kui ka tervikule. Kui eristatavad osad teosest ei ole tuletatud Teegist ja neid võib mõistlikult pidada iseseisvateks ja eraldi teosteks, siis käesolev Litsents ja selle tingimused ei kehti nende osade suhtes kui Te levitate neid kui eraldi teoseid. Aga kui Te levitate samu osasid osana tervikust, mis on Teegil põhinev teos, peab levitamine toimuma vastavalt käesoleva Litsentsi tingimustele, mille lubadused teistele litsensiaatidele laienevad kogu teosele ja seega igale osale, olenemata sellest, kes selle kirjutas. Seega pole käesoleva punkti eesmärk nõuda õigusi või vaidlustada Teie õigusi teosele, mille Te olete tervikuna loonud; pigem on eesmärk kasutada õigust suunata Teegil põhinevate teoste või ühisteoste levitamist. + +Lisaks, ainuüksi asjaolu, et ühtsesse levitamis- või säilitusvormi on liidetud teine teos, mis ei põhine Teegil, Teegiga (või Teegil põhineva teosega), ei muuda nimetatud teost käesoleva Litsentsi alla kuuluvaks. + +3. Te võite valida, et teatud Teegi koopiale kehtivad käesoleva Litsentsi asemel tavalise GNU Üldise Avaliku Litsentsi tingimused. Selleks peate Te muutma kõiki märkeid, mis viitavad käesolevale Litsentsile, nii et need viitaksid selle asemel tavalisele GNU Üldise Avaliku Litsentsi versioonile 2. (Kui ilmub uuem GNU Üldise Avaliku Litsentsi versioon kui praegune versioon 2, võite täpsustada selle versiooni kui soovite.) Ärge tehke neis märgetes muid muudatusi. + +Kui teatud koopiale on nimetatud muudatus tehtud, on see selle koopia suhtes pöördumatu, nii et tavaline GNU Üldine Avalik Litsents kehtib kõigi sellest koopiast tulenevate teoste ja järgnevate koopiate suhtes. + +See võimalus on kasulik, kui Te soovite kopeerida osa Teegi koodist programmi, mis pole Teek. + +4. Te võite Teeki kopeerida ja levitada (või punkti 2 kohaselt Teegi osa või Teegil põhinevat teost) objektkoodina või käivitataval kujul vastavalt punktide 1 ja 2 kohaselt eeldusel, et Te lisate sellele täieliku vastava masinloetava lähteteksti, mida peab levitama vastavalt punktides 1 ja 2 toodud tingimustele, vormis, mida kasutatakse valdavalt tarkvara vahendustegevuses. + +Kui objektkoodi levitamine toimub ligipääsu pakkumisega kopeerimiseks määratud kohas, siis ligipääsu pakkumine lähteteksti kopeerimiseks samast kohast loetakse võrdseks lähteteksti levitamisega, kuigi kolmandad osapooled pole kohustatud koos objektkoodiga lähteteksti kopeerima. + +5. Programmi, mis ei sisalda Teegi osa ega Teegist tuletatud teost, aga on loodud töötama koos Teegiga kompileerimise kaudu või lingitud sellega, kutsutakse "Teeki kasutavaks teoseks". Selline teos ei ole eraldiseisvana Teegist tuletatud teos ja ei ole seega käesoleva Litsentsiga kaetud. + +Siiski, "Teeki kasutava teose" Teegiga linkimine loob käivitatava vormi, mis on Teegist tuletatud (sest see sisaldab Teegi osi), mitte "Teeki kasutava teose". Käivitatav vorm on seega käesoleva Litsentsiga kaetud. Punktis 6 sätestatakse selliste käivitatavate vormide levitamise tingimused. + +Kui "Teeki kasutav teos" kasutab materjali Teegi osaks olevast päisefailist, võib teose objektkood olla Teegist tuletatud teos kuigi lähtekood seda pole. Kas see on tõene, on eriti tähtis, kui teost saab linkida ilma Teegita, või teos ise on Teek. Kas see on tõene, ei ole täpselt seadusega sätestatud. + +Kui selline objektfail kasutab ainult arvparameetreid, andmete struktuuri paigutust ja lisandeid, väikseid makrosid ja väikseid inline funktsioone (kümme märki või vähem pikad), siis pole objektfaili kasutamine piiratud, vaatamata sellele, et see on juriidiliselt tuletatud teos. (Käivitatavad failid, mis sisaldavad seda objektkoodi ja osi Teegist on ikkagi kaetud punktiga 6.) + +Vastasel juhul, kui teos tuleneb Teegist, võite Te levitada teose objektkoodi vastavalt punktis 6 toodud tingimustele. Iga käivitatav vorm, mis sisaldab teost, käib samuti punkti 6 alla, vaatamata sellele kas need on otseselt Teegiga seotud. + +6. Ülaltoodud punktide erandina võite Te kombineerida või linkida "Teeki kasutava teose" Teegiga, et luua teost, mis sisaldab Teegi osi, ning levitada seda teost vastavalt oma tingimustele, eeldusel, et tingimused lubavad teose muutmist kliendi soovil ning pöördprojekteerimist (reverse engineering) selliste muudatuste silumiseks. + +Te peate andma silmatorkavad märked igale Teeki kasutava teose koopiale, et selles on kasutatud Teeki ning et Teegi kasutamine on kaetud käesoleva Litsentsiga. Te peate pakkuma käesoleva Litsentsi koopiat. Kui teos kuvab käivitamisel autoriõiguse märked, peate Te lisama neile ka Teegi autoriõiguse märke ja viite, mis juhatab kasutaja käesoleva Litsentsi koopia juurde. Samuti peate Te tegema ühe järgmistest asjadest: + +a) Lisama teosele täieliku vastava masinloetava Teegi lähteteksti, kaasa arvatud muudatused, mida kasutati teoses (mida peab levitama vastavalt Punktidele 1 ja 2); ja, kui teos on Teegiga lingitud käivitatav vorm, koos täieliku masinloetava "Teeki kasutava teose" objektkoodiga ja/või lähtekoodiga, et kasutaja saaks muuta Teeki ja uuesti linkida, et valmistada muudetud käivitatavat vormi, mis sisaldab muudetud Teeki. (On arusaadav, et kasutaja, kes muudab Teegi definitsioonifailide sisu, ei ole tingimata võimeline rakendust uuesti kompileerima, et muudetud definitsioone kasutada.) + +b) Kasutama Teegiga linkimiseks sobivat jagatud mehanismi. Mehanism on sobiv kui see (1) kasutab käitusajal koopiat Teegist, mis juba on kasutaja arvutisüsteemis, mitte ei kopeeri teegi funktsioone käivitatavasse vormi, ja (2) töötab korralikult teegi muudetud variandiga, kui kasutaja selle installeerib, tingimusel, et muudetud variant on liides-ühilduv variandiga, millega teos tehti. + +c) Lisama teosele kirjaliku pakkumise, mis kehtib vähemalt 3 aastat, et anda samale kasutajale alapunktis 6a nimetatud materjalid, mitte kallimalt kui levitamise hinnaga. + +d) Kui teost levitatakse ligipääsu pakkumise teel koopiale määratud kohas, võrdub pakkumine ligipääsuga kopeerida ülalnimetatud materjalid samast kohast. + +e) Kontrollima, et kasutaja on juba saanud koopia nii nendest materjalidest või sa oled juba saatnud sellel kasutajale koopia. + +Käivitatava vormi jaoks peab "Teeki kasutava teose" nõutud vorm sisaldama andmeid ja utiliite, mis on vajalikud käivitatava vormi taasloomiseks. Siiski, erilise erandina, ei pea levitatavad materjalid sisaldama midagi (ei lähte- ega kahendvormis), mida tavaliselt levitatakse koos operatsioonisüsteemi põhiliste osadega (kompilaator, kernel jne.), millel käivitatav vorm töötab, välja arvatud juhul kui see osa käib käivitatava vormiga kaasas. + +Võib juhtuda, et see nõue läheb vastuollu teiste kaitstud teekide litsentsi piirangutega, mis tavaliselt ei käi operatsioonisüsteemiga kaasas. Selline vastuolu tähendab, et Te ei saa kasutada käivitatavas vormis, mida Te levitate, neid ja Teeki koos. + +7. Te võite panna teegi teenused, mis on Teegil põhinevad teosed, kõrvuti ühte teeki koos teiste teegi teenustega, mis ei ole kaetud käesoleva Litsentsiga, ja levitada sellist ühendatud teeki, tingimusel, et Teegil põhineva teose ja teiste teegi vahendite eraldi levitamine on lubatud ja et Te teete järgmised asjad: + +a) lisate ühendatud teegile koopia samast teosest, mis põhineb Teegil, mis ei ole ühendatud teiste Teegi vahenditega. Seda peab levitama vastavalt ülaltoodud punktidele. + +b) annate koos ühendatud teegiga silmatorkavad märked asjaolust, et osa sellest on Teegil põhinev teos, ja seletate kust leida sama teose mitte ühendatud vorm. + +8. Te ei tohi kopeerida, muuta, edasi litsentseerida, linkida või levitada Teeki teisiti kui käesolevas Litsentsis väljendatud. Iga katse kopeerida, muuta, edasi litsentseerida, linkida või levitada Teeki teisiti, on kehtetu ja lõpetab automaatselt Teie õigused vastavalt käesolevale Litsentsile. Siiski, osapoolte litsentse, kes on saanud koopiad või õigused Teilt vastavalt käesolevale Litsentsile, ei lõpetata nii kaua kui kõik osapooled täidavad täielikult kehtestatud tingimusi. + +9. Te ei pea käesolevat Litsentsi arvestama, kuna Te pole sellele alla kirjutanud. Siiski, miski muu ei anna Teile luba muuta või levitada Teeki või sellest tulenevaid teoseid. Need tegevused on keelatud seadusega kui Te käesoleva Litsentsiga ei arvesta. Seega, muutes või levitades Teeki (või teegil põhinevat teost) näitate Te seda tehes oma nõusolekut käesoleva Litsentsiga ning kõigi selle Teegi või teegil põhineva teose kopeerimise, levitamise või muutmise terminite ja tingimustega. + +10. Iga kord kui Te Teeki (või Teegil põhinevat teost) edasi levitate, saab vastuvõtja automaatselt originaallitsenstiaarilt litsentsi kopeerida, levitada, linkida või muuta Teeki vastavalt nendele terminitele ja tingimustele. Te ei tohi kohustada vastuvõtjat rohkem millekski temale siin antud õiguste kasutamisel. Te ei ole vastutav kolmandate poolte poolt kehtestatud tingimuste täitmise eest. + +11. Kui kohtulahendi või väidetava patendiõiguse rikkumise tagajärjel või mõnel muul põhjusel (mis ei piirdu patendiga seotud küsimustega) on Teile pandud kohustusi, mis on vastuolus käesoleva Litsentsi tingimustega, siis ei vabasta need Teid käesoleva Litsentsi tingimuste täitmisest. Kui Te ei suuda Teeki levitada, täites samaaegselt käesoleva Litsentsi tingimusi ja teisi kohustusi, siis ei tohi Te Teeki üldse levitada. Näiteks kui patendilitsents ei luba Teil litsentsitasuta Teeki edasi levitada neile, kes on saanud Teilt või Teie kaudu Teegi koopia, siis ainus võimalus täita nimetatud patendilitsentsi ja käesoleva Litsentsi tingimusi on loobuda Teegi levitamisest. + +Kui käesoleva punkti mõni osa osutub mingil asjaolul kehtetuks või mitterakendatavaks, siis käesoleva punkti ülejäänud osa loetakse rakendatavaks ja punkt tervikuna loetakse rakendatavaks ülejäänud tingimustel. + +Käesoleva punkti eesmärk ei ole kellegi ajendamine patendi- või muude õiguste rikkumiseks või nende kehtivuse vaidlustamiseks; käesoleva punkti ainus eesmärk on vaba tarkvara levitamise süsteemi terviklikkuse kaitsmine, mida kasutavad avalike litsentside kasutajad. Paljud isikud on andnud suure panuse tarkvara laiale sektorile, mida levitatakse läbi nimetatud süsteemi usaldades järjekindlat süsteemi rakendumist; autor/annetaja on otsustaja, kas ta soovib tarkvara levitada mõne teise süsteemi kaudu ja litsenstiaat ei saa seda valikut mõjutada. + +Selle punkti eesmärk on täpselt selgitada, mida soovitakse käesoleva Litsentsi ülejäänud osaga saavutada. + +12. Kui Teegi levitamist ja/või kasutamist piiratakse mõnedes riikides kas patentide või autoriõigusega, võib autoriõiguse omanik, kes on Teegi litsenseerinud, lisada kindla geograafilise piirangu, jättes nimekirjast välja mainitud riigid, et levitamine oleks lubatud vaid nimekirjas toodud riikides või riikide vahel. Nimetatud juhul Litsents liitub piiranguga, nagu see on ära toodud käesoleva Litsentsi põhiosas. + +13. Free Software Foundation võib aeg-ajalt välja anda ümbertöötatud ja/või uusi versioone Vähem Üldisest Avalikust Litsentsist. Need uued versioonid on käesoleva Litsentsi versiooniga sarnase sisuga, kuid võivad erineda detailides, osundades uusi probleeme või huviobjekte. + +Igale versioonile antakse unikaalne versiooninumber. Kui Teegis tuuakse ära selle kohta kehtiva käesoleva litsentsi versiooninumber ja lisatakse märge "kõik hilisemad versioonid", siis on Teil võimalik valida, kas järgida selle või ükskõik millise hilisema Free Software Foundation'i poolt avaldatava versiooni tingimusi. Kui Teek ei täpsusta käesoleva litsentsi versiooninumbrit, on Teil võimalus valida ükskõik milline Free Software Foundation'i poolt avaldatud käesoleva Litsentsi versioon. + +14. Kui Te soovite Teegi osi liita teiste vabade teekidega, mille levitamise tingimused on erinevad, siis kirjutage loa saamiseks autorile. Tarkvara puhul, mis on autoriõigusega kaitstud Free Software Foundation'i poolt, kontakteeruge Free Software Foundation'iga, mõnikord me teeme erandeid. Meie otsuse määravad kaks eesmärki: säilitada vaba staatus meie vaba tarkvara igasugustele derivaatidele ja edendada tarkvara jagamist ning taaskasutamist üldiselt. + +GARANTII PUUDUMINE + +15. KUNA PROGRAMM ON LITSENSEERITUD TASUTA, PUUDUB TEEGIL IGASUGUNE GARANTII ULATUSENI, MIDA LUBAB RAKENDATAV SEADUS. KUI KIRJALIKULT POLE TEISITI SÄTESTATUD, SIIS AUTORIÕIGUSE OMANIKUD JA/VÕI MUUD OSAPOOLED PAKUVAD TEEKI "NII, NAGU TA ON" ILMA IGASUGUSE VÄLJENDATUD VÕI OLETATAVA GARANTIITA, KAASA ARVATUD, KUID MITTE AINULT, KESKMISE/TAVALISE KVALITEEDI JA MINGILE KINDLALE EESMÄRGILE SOBIVUSE GARANTIITA. KOGU TEEGI KVALITEEDI JA TOIMIMISE RISK LANGEB TEILE. KUI TEEK ON PUUDULIK, KANNATE TEIE KÕIK TEENINDUSE, PARANDUSE VÕI TAASTAMISE KULUD. + +16. MITTE MINGIL JUHUL, VÄLJA ARVATUD SIIS, KUI SEDA NÕUAB RAKENDATAV SEADUS VÕI KIRJALIKULT ON TEISITI KOKKU LEPITUD, POLE ÜKSKI AUTORIÕIGUSE OMANIK VÕI KOLMAS OSAPOOL, KES VÕIB MUUTA JA/VÕI LEVITADA TEEKI VASTAVALT ÜLALPOOL TOODUD TINGIMUSTELE, TEIE EES VASTUTAV KAHJUSTUSTE EEST, KAASA ARVATUD IGASUGUSED ÜLDISED, SPETSIIFILISED, JUHUSLIKUD VÕI TAGAJÄRJEL TEKKINUD KAHJUD, MIS TULENEVAD KAS TEEGI KASUTAMISEST VÕI VÕIMATUSEST TEEKI KASUTADA (KAASA ARVATUD, KUID MITTE AINULT, TEIE VÕI KOLMANDATE OSAPOOLTE ANDMETE KADUMINE VÕI ANDMETE MUUTMINE VÕI TEEGI VÕIMETUS TÖÖTADA KOOS MISTAHES MUU TARKVARAGA), ISEGI SIIS, KUI VALDAJAT VÕI MUUD OSAPOOLT ON TEAVITATUD SELLISTE KAHJUDE VÕIMALIKKUSEST. + +TERMINITE JA TINGIMUSTE LÕPP. + +Kuidas rakendada oma uutele teekidele neid termineid ja tingimusi? + +Kui Te loote uue teegi ja soovite, et see olekas avalikkusele võimalikult kasulik, soovitame selle muuta vabaks tarkvaraks, et igaüks saaks seda edasi levitada ja muuta. Te võite seda teha lubades edasi levitamist vastavalt käesolevatele tingimustele (või vastavalt tavalise Üldise Avaliku Litsentsi tingimustele). + +Et rakendada neid tingimusi, lisage teegile järgmised märkused. Kõige kindlam on lisada need märked iga lähtefaili algusse, et võimalikult efektiivselt teatada garantii puudumisest: igal failil peaks olema vähemalt üks "autoriõiguse" rida ja viide kohale, kust võib leida tervikliku märkuse. + +üks rida teegi nime jaoks ja mida see teeb + +Copyright (C) aasta autori nimi + +Käesolev teek on vaba tarkvara. Te võite seda edasi levitada ja/või muuta vastavalt GNU Vähem Üldise Avaliku Litsentsi tingimustele, nagu need on Vaba Tarkvara Fondi poolt avaldatud; kas Litsentsi versioon number 2.1 või (vastavalt Teie valikule) ükskõik milline hilisem versioon. + +Seda teeki levitatakse lootuses, et see on kasulik, kuid ILMA IGASUGUSE GARANTIITA; isegi KESKMISE/TAVALISE KVALITEEDI GARANTIITA või SOBIVUSELE TEATUD KINDLAKS EESMÄRGIKS. Üksikasjalise info saamiseks vaata GNU Üldist Vähem Avalikku Litsentsi. + +Te peaks olema saanud GNU Üldise Vähem Avaliku Litsentsi koopia koos selle teegiga, kui ei, siis kontakteeruge Free Software Foundation'iga, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Samuti lisage informatsioon, kuidas Teiega kontakteeruda kas posti või meili teel. + +Te peaksite laskma oma tööandjal (kui te töötate programmeerijana), või koolil alla kirjutada autoriõiguslike pretensioonide loobumise kohta käivale dokumendile. Siin on näidis, muutke ise nimed: + +Yoyodyne, Inc., loobub kõigist autoriõigustest teegile "Frob", mille on kirjutanud James Random Hacker. + +allkiri, 1 April 1990 + +Ty Coon, President of Vice + +---------------------------------------------- + +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + +a) The modified work must itself be a software library. +b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. +c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. +d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) +b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. +c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. +d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. +e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. 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 not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. +b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the 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 specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library 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 2.1 of the License, or (at your option) any later version. + +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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice + +That's all there is to it! diff --git a/assets/spelling/licenses/fa_IR/LICENSE b/assets/spelling/licenses/fa_IR/LICENSE new file mode 100644 index 00000000..ec0ca93c --- /dev/null +++ b/assets/spelling/licenses/fa_IR/LICENSE @@ -0,0 +1,15 @@ +Lilak, Persian Spell Checking Dictionary + +Copyright 2015 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/assets/spelling/licenses/fa_IR/README_fa_IR.txt b/assets/spelling/licenses/fa_IR/README_fa_IR.txt new file mode 100644 index 00000000..0da5dca5 --- /dev/null +++ b/assets/spelling/licenses/fa_IR/README_fa_IR.txt @@ -0,0 +1,26 @@ +Source +====== +https://github.com/b00f/lilak + +License +======= +Lilak, Persian Spell Checking Dictionary + +Copyright 2015 Mostafa Sedaghat Joo + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +README +====== +Lilak is an open source project for generating Persian dictionary for hunspell spell checker based on Persian Morphology. +This dictionary is free and the source is available under Apache License Version 2.0. diff --git a/assets/spelling/licenses/fr_FR/dictionaries/README_dict_fr.txt b/assets/spelling/licenses/fr_FR/dictionaries/README_dict_fr.txt new file mode 100644 index 00000000..fc74384d --- /dev/null +++ b/assets/spelling/licenses/fr_FR/dictionaries/README_dict_fr.txt @@ -0,0 +1,67 @@ +_______________________________________________________________________________ + + DICTIONNAIRES ORTHOGRAPHIQUES FRANÇAIS + version 7.7 + + Olivier R. + https://grammalecte.net/ + + Licence : + MPL : Mozilla Public License + version 2.0 -- http://www.mozilla.org/MPL/2.0/ + + Ce dictionnaire ne peut fonctionner qu’avec un logiciel utilisant le + correcteur Hunspell : OpenOffice.org 3.2+, Firefox 4+, Thunderbird 5+ + + Principaux contributeurs : + - Jean-Luc T. ; + - Sylvain P. ; + - Laurent Dubois ; + - Dominique Pellé ; + - Pierre Poisson ; + - Pierre-Yves ; + - Pierre Choffardet ; + - Leywen ; + - Romain Muller et Serge Bibauw, de l’association RENOUVO, grâce à qui + la nouvelle orthographe et ses anciennes variantes ont pu être établies ; + - Chantal Contant, pour ses recherches sur la réforme de 1990 ; + - Benoît Sagot, qui nous a autorisé à comparer notre lexique avec Lefff, + ce qui a mis en évidence des dizaines d’erreurs d’étiquetage grammatical ; + - Philipp Burgess, pour la normalisation Unicode avec Hunspell. + + Merci aussi à tous ceux qui ont apporté leur pierre à l’édifice. + https://grammalecte.net/members.php?prj=fr + + Pour participer à l’amélioration du dictionnaire, allez sur : + https://grammalecte.net/home.php?prj=fr + +_______________________________________________________________________________ + + À propos des différents dictionnaires français +_______________________________________________________________________________ + + En 1990, le Conseil supérieur à la langue française et l’Académie française + ont proposé une réforme de l’orthographe qui concerne plusieurs milliers de + mots. L’emploi des nouvelles graphies n’est pas obligatoire. Les anciennes + comme les nouvelles sont considérées comme correctes. + + Pour en savoir plus sur la réforme de 1990 : + http://www.renouvo.org/regles.php + http://www.orthographe-recommandee.info/ + + Malgré les rectifications modestes apportées par cette réforme, la nouvelle + orthographe suscite beaucoup de polémiques. Afin de satisfaire les exigences + de chacun, quatre dictionnaires existent, respectant différemment cette + réforme. + + Dictionnaire “Classique” [recommandé] + Ce dictionnaire propose l’orthographe usuelle du français, avec en sus + quelques graphies nouvelles rectifiant les incohérences passées. + + Dictionnaire “Réforme 1990” + Ce dictionnaire ne connaît que les graphies nouvelles des mots concernés + par la réforme de 1990. + + Dictionnaire “Toutes variantes” + Ce dictionnaire contient les nouvelles et les anciennes graphies des + mots concernés par la réforme de 1990. diff --git a/assets/spelling/licenses/fr_FR/dictionaries/README_hyph_fr.txt b/assets/spelling/licenses/fr_FR/dictionaries/README_hyph_fr.txt new file mode 100644 index 00000000..3f35865c --- /dev/null +++ b/assets/spelling/licenses/fr_FR/dictionaries/README_hyph_fr.txt @@ -0,0 +1,87 @@ +_______________________________________________________________________________ + + Motifs de division des mots pour le français (fr) + Version 4.0 (2021-11-06) + + Licence : + GNU LGPL + + Origine : + Basé sur le fichier des motifs de division de TeX *hyph-fr.tex*, + version renommée, en juin 2008, du fichier *frhyph.tex* (V2.12, + 2002/12/11) pour la cohérence avec d'autres fichiers de motifs + de division de la collection hyph-utf8. Pour plus d'informations, + voyez sous ce lien : https://ctan.org/tex-archive/language/hyph-utf8. + Initialement distribué sous la licence LPPL (LaTeX Project Public + License), le fichier *hyph-fr.tex* (v2.12) a été distribué sous + la licence MIT (https://opensource.org/licenses/MIT) à compter + du 20 mars 2016. + + Licence : + Les adaptations pour LibreOffice et OpenOffice sont publiées sous la + licence GNU Lesser General Public License (LGPL) version 2.1 ou + supérieure. + Voir sous ce lien: http://www.gnu.org/licenses/ + + Auteurs : + 3.0-4.0 Marc Lodewijck + 2.0 Paul Pichaureau + 1.0 Blaise Drayer + + Journal : + 4.0 Adaptation des motifs avec trait d'union, ajout de motifs, + suppression des mots-clefs COMPOUNDLEFTHYPHENMIN + et COMPOUNDRIGHTHYPHENMIN (inutilisés) + 3.0.1 Correction : COUMPOUNDLEFTHYPHENMIN -> COMPOUNDLEFTHYPHENMIN + 3.0 Nouvelle version révisée et augmentée : + + Conversion au format UTF-8 + + Traitement des noms composés à trait d'union + + Redressement de motifs altérés + 2.0 Traitement des mots avec apostrophe + 1.0 Première conversion + + Ce dictionnaire convient pour toutes les variétés régionales du français. + +_______________________________________________________________________________ + + Hyphenation patterns for French + Version 4.0 (2021-11-06) + + Language: + French (fr) + + License: + GNU LGPL + + Origin: + Based on the TeX hyphenation file *hyph-fr.tex*, renamed (June 2008) + from *frhyph.tex* (V2.12, 2002/12/11) for consistency with other files + in the hyph-utf8 package. For more details, see at the following link: + https://ctan.org/tex-archive/language/hyph-utf8. Initially released + under the LPPL license (LaTeX Project Public License), the file + *hyph-fr.tex* (v2.12) has been released, as of March 20, 2016, under + the MIT license (https://opensource.org/licenses/MIT). + + License: + LibreOffice and OpenOffice adaptions of this package are licensed under + the GNU Lesser General Public License (LGPL) version 2.1 or higher. + See at this link: http://www.gnu.org/licenses/ + + Authors: + 3.0-4.0 Marc Lodewijck + 2.0 Paul Pichaureau + 1.0 Blaise Drayer + + Log: + 4.0 Adjustments to patterns with a hyphen, addition of new + patterns, and deletion of the COMPOUNDLEFTHYPHENMIN and + COMPOUNDRIGHTHYPHENMIN keywords (unused) + 3.0.1 Typo fix: COUMPOUNDLEFTHYPHENMIN -> COMPOUNDLEFTHYPHENMIN + 3.0 New revised and expanded version: + + Conversion to UTF-8 encoding + + Processing of hyphenated compounds + + Correction of altered patterns + 2.0 Fix for words with apostrophe + 1.0 First conversion + + This dictionary is suitable for all regional varieties of French. diff --git a/assets/spelling/licenses/fr_FR/dictionaries/README_thes_fr.txt b/assets/spelling/licenses/fr_FR/dictionaries/README_thes_fr.txt new file mode 100644 index 00000000..400e9b9b --- /dev/null +++ b/assets/spelling/licenses/fr_FR/dictionaries/README_thes_fr.txt @@ -0,0 +1,50 @@ +_______________________________________________________________________________ + + Dictionnaire des synonymes français myThes + version 2.3 + + Par Frédéric Labbé + + Pour les mises à jour, allez sur Dicollecte : + https://grammalecte.net/home.php?prj=fr + + Licence: + LGPL : GNU Lesser General Public License + version 2.1 ou supérieure -- http://www.gnu.org/licenses/lgpl-2.1.html +_______________________________________________________________________________ + + Ce dictionnaire des synonymes est encore en cours d'élaboration. + Actuellement, seules les graphies précédant la réforme de l'orthographe + de 1990 sont reconnues. + +_______________________________________________________________________________ + + Historique +_______________________________________________________________________________ + + * myThes est le format de thesaurus de OOo à partir de la version 2.0 + developpé par Kevin Hendricks sur la base des travaux de l'université de + Priceton: http://lingucomponent.openoffice.org/thesaurus.html + + Cette version est incompatible avec le format binaire utilisé pour les + versions 1.x d'OpenOffice.org. + + * La conception du thesaurus dans le format 1.0 a été initiée par Frederic Labbé. + + * La version 2 a été transformée par la société Indesko. + Laurent Godard (lgodard@indesko.com) + + Les catégories grammaticales des mots ont été complétées sur la base de + InDico, dictionnaire taggué developpé par InDesko et issu de la + transformation des listes de l'abu (http://abu.cnam.fr/) + + * La version 2.1 n'apporte que la reconnaissance des mots avec ligatures. + Ce thesaurus a été découvert ici : + http://user.services.openoffice.org/fr/forum/viewtopic.php?p=15783#15783 + + * La version 2.2 est générée à partir de la base de données de Dicollecte. + Pour l'instant, seules quelques modifications ont été faites. + + * Version 2.3 : nettoyage des entrées erronées. + +_______________________________________________________________________________ \ No newline at end of file diff --git a/assets/spelling/licenses/hi_IN/COPYING b/assets/spelling/licenses/hi_IN/COPYING new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/assets/spelling/licenses/hi_IN/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/assets/spelling/licenses/hi_IN/README_hi_IN.txt b/assets/spelling/licenses/hi_IN/README_hi_IN.txt new file mode 100644 index 00000000..ed3cdb26 --- /dev/null +++ b/assets/spelling/licenses/hi_IN/README_hi_IN.txt @@ -0,0 +1,76 @@ +See original package: http://ftp.gnu.org/gnu/aspell/dict/hi/aspell6-hi-0.01-0.tar.bz2 +Conversion made by Laszlo Nemeth, for demonstration of Hunspell Unicode support +(see http://hunspell.sourceforge.net) +ORIGINAL README: +----------------------------- + +GNU Aspell 0.60 Hindi (हिंदी) Dictionary Package +Version 0.01-0 +2005-01-27 +Maintained By: + The janabhaaratii Team (जनभारती) +Copyright Terms: GPL (see the file Copyright for the exact terms) +Wordlist URL: http://www.janabhaaratii.org.in +Source Verson: 0.01 + +This is the Hindi dictionary for Aspell. It requires Aspell +version 0.60 or better. + +If Aspell is installed and aspell and prezip-bin are all +in the path first do a: + + ./configure + +Which should output something like: + + Finding Dictionary file location ... /usr/local/lib/aspell + Finding Data file location ... /usr/local/share/aspell + +if it did not something likely went wrong. + +After that build the package with: + make +and then install it with + make install + +If any of the above mentioned programs are not in your path than the +variables, ASPELL and/or PREZIP need to be set to the +commands (with path) to run the utilities. These variables may be set +in the environment before configure is run or specified at the command +line using the following syntax + ./configure --vars VAR1=VAL1 ... +Other useful variables configure recognizes are ASPELL_PARMS, and DESTDIR. + +To clean up after the build: + make clean + +To uninstall the files: + make uninstall + +After the dictionaries are installed you can use the main one (hi) by +setting the LANG environmental variable to hi or running Aspell +with "--lang=hi". You may also chose the dictionary directly +with the "-d" or "--master" option of Aspell. You can chose from any of +the following dictionaries: + hi (hindi) +Whereas the names in parentheses are alternate names for the +dictionary preceding the parentheses. + +The individual word lists have an extension of ".cwl" and are +compressed to save space. To uncompress a word list use +"preunzip BASE.cwl" which will uncompress it and rename the file +to "BASE.wl". To dump a compressed word list to standard output use +"precat BASE.cwl". To uncompress all word lists in the current +directory use "preunzip *.cwl". For more help on "preunzip" use +"preunzip --help". + +If you have any problem with installing or using the word lists please +let the Aspell maintainer, Kevin Atkinson, know at kevina@gnu.org. + +If you have problems with the actual word lists please contact one of +the Word lists authors as the Aspell maintainer does not maintain the +actual Word Lists. + +Any additional documentation that came with the original word list can +be found in the doc/ directory. + diff --git a/assets/spelling/licenses/id/LICENSE-dict b/assets/spelling/licenses/id/LICENSE-dict new file mode 100644 index 00000000..341c30bd --- /dev/null +++ b/assets/spelling/licenses/id/LICENSE-dict @@ -0,0 +1,166 @@ + 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. + diff --git a/assets/spelling/licenses/id/LICENSE-thes b/assets/spelling/licenses/id/LICENSE-thes new file mode 100644 index 00000000..fec0bf37 --- /dev/null +++ b/assets/spelling/licenses/id/LICENSE-thes @@ -0,0 +1,503 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/assets/spelling/licenses/id/README-dict.adoc b/assets/spelling/licenses/id/README-dict.adoc new file mode 100644 index 00000000..e619633d --- /dev/null +++ b/assets/spelling/licenses/id/README-dict.adoc @@ -0,0 +1,137 @@ += hunspell-id +:toc: +:sectanchors: +:sectlinks: + +Proyek ini adalah kelanjutan dari ekstensi Kamus Indonesia pada +https://extensions.libreoffice.org/extension-center/indonesian-dictionary-kamus-indonesia-by-benitius/releases/2.0[LibreOffice^]. + +== Unduh + +Unduh arsip zip yang terbaru lewat tautan berikut +https://github.com/shuLhan/hunspell-id/archive/master.zip[master.zip^], +atau salin dengan `git` + +---- +$ git clone git@github.com:shuLhan/hunspell-id.git +---- + +Jika mengunduh arsip zip, ekstrak berkas zip tersebut. + + +== Pasang + +=== Sistem Operasi GNU/Linux atau BSD + +Langkah pemasangan secara manual, + + $ sudo make install + +Perintah tersebut juga mengikutkan pemasangan berkas eja untuk program myspell +dan vim. + +Untuk menghapus kembali pemasangan, lakukan + + $ sudo make uninstall + +Paket untuk GNU/Linux tersedia sebagai berikut. + +Arch Linux:: Pengguna Arch dapat memasang paket ini lewat +git submodule dalam direktori AUR atau +https://aur.archlinux.org/packages/hunspell-id-git/[AUR^]. + +Debian (dan turunan):: Lihat dalam direktori debian. + +Solus:: Paket ini dapat dipasang dengan cara, ++ +-- +---- +$ sudo eopkg it hunspell-id +---- +-- + +=== Ekstensi LibreOffice + +Pindah ke direktori sumber repositori, + +---- +$ cd hunspell-id +---- + +Eksekusi skrip `build.sh` pada direktori sumber + +---- +$ ./build.sh +---- + +Skrip tersebut akan menghasilkan berkas `hunspell-id.oxt`. +Buka pengatur berkas, dan klik dua kali pada berkas `hunspell-id.oxt`, nanti +layanan pemasangan ekstensi LibreOffice akan muncul. + +=== Vim + +Buat direktori `$HOME/.vim/spell`, kemudian salin atau buat _symlink_ dari +berkas `vim/id.utf-8.spl` ke dalam direktori tersebut. + + +== Sejarah + +Versi 1.0, 1.1, dan 1.2 diciptakan tahun 2004 dengan bantuan Kurniadi dan +Volker Mueller serta Arno Brevoort, yang menyumbangkan daftar kata mereka +sebagai dasar penyusunan berkas tersebut bagi program MySpell, yang dipakai +oleh OpenOffice.org. +Sesudah itu bertahun-tahun lamanya tidak dikerjakan lagi. + +Tanggal 05 Mei 2009 Ammar Shadiq menuangkan berkas-berkas lama itu dalam +bentuk ekstensi bagi OpenOffice. +Ekstensi yang sama ini diunggah ke LibreOffice pada tanggal 19 Mei 2012 +sebagai Indonesian dictionary - Kamus Indonesia 1.0. +Viko Adi Rahmawan kemudian menguji ekstensi ini kembali dan pada tanggal 16 +Mei 2014 diterbitkan sebagai Indonesian dictionary - Kamus Indonesia 1.1 bagi +LibreOffice 4.0. + +Versi 2.0 merupakan pengerjaan ulang dari kedua berkas `id_ID.dic` dan +`id_ID.aff` agar lebih sesuai dengan sifat Bahasa Indonesia. +Berkas .aff (affiks) diperbaharui sehingga jauh lebih sesuai +dengan sifat bahasa Indonesia dengan awalan, akhiran dan imbuhan. +Berkas .dic (daftar kata) diperiksa dengan semua lemma dari Kamus Besar Bahasa +Indonesia, edisi 3. +Berkas hyphenator tidak mengalami perubahan. + +== Lisensi + +---- +Copyright (C) 2004-2022 hunspell-id Authors + +This program 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, with the additional exemption that +compiling, linking, and/or using OpenSSL is allowed. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . +A copy of the GNU Lesser General Public License is in the file COPYING. +---- + +Daftar pengembang yang diketahui (diurut berdasarkan abjad), + +* Ammar Shadiq +* Andika Triwidada (Untuk paket Debian) +* Arno Brevoort +* Benitius Brevoort +* Kurniadi +* Viko Adi Rahmawan +* Volker Mueller +* Yurizal Susanto (Untuk paket Solus) + +Jika Anda pernah berkontribusi sebelumnya tapi tidak tercantum di sini +silahkan kirim email ke ms@kilabit.info. + +// SPDX-FileCopyrightText: 2015 hunspell-id Authors +// SPDX-License-Identifier: LGPL-3.0-only diff --git a/assets/spelling/licenses/id/README-thes b/assets/spelling/licenses/id/README-thes new file mode 100644 index 00000000..1d34fe8e --- /dev/null +++ b/assets/spelling/licenses/id/README-thes @@ -0,0 +1,24 @@ +Kamus Tesaurus Bahasa Indonesia - untuk Apache OpenOffice.org/LibreOffice +Copyright (C) 2008 Pusat Bahasa Departemen Pendidikan Nasional RI, dikompilasi +ke dalam format kamus Stardict oleh Steven Haryanto . +Kompilasi v0.02 2010-03-03. +Diubah ke dalam format MyThes oleh Ali Ahmadi pada +2017-02-21. +Copyright (C) 2017 Ali Ahmadi . +Homepage: https://idnux.wordpress.com/proyek/mythes-id + + +===== Tentang thes-id atau mythes-id ==== + +thes-id atau mythes-id ini adalah sebuah kamus tesaurus bahasa Indonesia untuk +kelompok perkakas perkantoran LibreOffice dan Apache OpenOffice.org. Kamus +tesaurus ini dibangun memanfaatkan data kamus TBIPB (Tesaurus Bahasa Indonesia +Pusat Bahasa) edisi I (2008) untuk aplikasi kamus Stardict yang dikompilasi +oleh Bapak Steven Haryanto yang kemudian diubah ke dalam format MyThes +(http://www.openoffice.org/lingucomponent) yang ditulis oleh Kevin Hendricks +(kevin.hendricks@sympatico.ca). + +MyThes sendiri adalah sebuah sistem tesaurus sederhana yang menggunakan berkas +data terstruktur dan berkas indeks dengan pencarian biner untuk mencari kata-kata +dan frase dan mengembalikan informasi tentang bagian dari ucapan, makna, dan +sinonim. MyThes ini ditulis untuk menyediakan tesaurus untuk proyek OpenOffice.org. diff --git a/assets/spelling/licenses/it_IT/README_hyph_it_IT.txt b/assets/spelling/licenses/it_IT/README_hyph_it_IT.txt new file mode 100644 index 00000000..5965123b --- /dev/null +++ b/assets/spelling/licenses/it_IT/README_hyph_it_IT.txt @@ -0,0 +1,28 @@ +Hyphenation dictionary +---------------------- + +Language: it_IT (Italian, Italy) +Origin: Based on the TeX hyphenation tables by Claudio Beccari +License: LGPL + http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=ithyph +Author: conversion author is Giuseppe Bilotta + +This dictionary should be usable under other Italian variants + +=============================================================================== + +Dizionario sillabazione +---------------------- + +Language: it_IT (Italiano, Italia) +Origin: Basato sulle tabelle di sillabazione di Claudio Beccari per il TeX +License: LGPL + http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=ithyph +Author: conversione di Giuseppe Bilotta + +Questo dizionario dovrebbe essere valido anche per altre varianti di italiano + +=============================================================================== + +HYPH it IT hyph_it_IT_v2 + diff --git a/assets/spelling/licenses/it_IT/README_it_IT.txt b/assets/spelling/licenses/it_IT/README_it_IT.txt new file mode 100644 index 00000000..60a8a160 --- /dev/null +++ b/assets/spelling/licenses/it_IT/README_it_IT.txt @@ -0,0 +1,316 @@ +Version 5.1.1, 07-Nov-2022 + +# Estensione linguistica italiana - Italian Writing Aids extension +# Copyright (C) 2020-2022, LibreItalia - Marina Latini +# Portions Copyright (C) 2001-2015 other authors, see below for details. +# License: GNU GPL 3 +# Home: https://libreitalia.org +# E-Mail: marina.latinilibreofficeorg + +[ Please scroll down for English. ] + +ITALIANO + +L'estensione linguistica italiana fornisce le funzioni di correzione +ortografica, dizionario dei sinonimi e sillabazione per la lingua +italiana in LibreOffice. Il modulo di correzione ortografica è +utilizzabile anche in altri programmi che offrano supporto per +dizionari MySpell, ASpell o HunSpell. + +L'estensione linguistica italiana è rilasciata da LibreItalia +e Marina Latini marina.latinilibreofficeorg ne è l'attuale +maintainer. L'estensione è rilasciata sotto i termini e le condizioni della +GNU General Public License (GPL) 3. Una copia della licenza è +disponibile in coda al presente file. + +L'estensione linguistica italiana contiene evoluzioni indipendenti +("fork") dei pacchetti "Dizionario italiano" 2.4 e "Thesaurus italiano" +2.07.gh disponibili su http://linguistico.sourceforge.net/ ; tutti i +file README e le note di copyright applicabili a tali due pacchetti si +trovano inalterati nella cartella "legacy" del presente pacchetto. + +L'estensione linguistica italiana include pattern di sillabazione +basati su un'elaborazione dei pattern per TeX presenti nel +pacchetto "Hyphenation patterns for the Italian language" disponibile +su http://tug.ctan.org/pkg/ithyph ; il file README_hyph_it_IT.txt +contiene le note di copyright applicabili a tale pacchetto. + +I volontari elencati di seguito, e in generale la Comunità +OpenOffice.org e il PLIO http://www.plio.it hanno contribuito +alla precedente versione dell'estensione linguistica italiana: +- Andrea Pescetti, precedente maintainer fino alla versione 2015 +- Paolo Mantovani, struttura dell'estensione +- Carlo Strata, suggerimenti e segnalazione di errori nel dizionario +- Diego Favaro, suggerimenti e segnalazione di errori nel thesaurus +- Renzo Bianchi, grafica e QA + +ENGLISH + +The Italian Writing Aids extension provides spellchecker, theasurus and +hyphenation functionality in Italian for LibreOffice. The spell +checking module can be used in any other programs too that support +MySpell, ASpell or HunSpell dictionaries. + +The Italian Writing Aids extension is distributed by LibreItalia +and Marina Latini marina.latinilibreofficeorg is the current +extension's maintainer. +The extensione is released under the terms and conditions of the +GNU General Public License (GPL), version 3. A copy of the license is +at the end of this file. + +The Italian Writing Aids extension contains forks of the two packages +named "Dizionario italiano" v. 2.4 and "Thesaurus italiano" v. 2.07.gh +available at http://linguistico.sourceforge.net/ ; all README files +and copyright notices relevant to those two packages are in the +"legacy" folder of the current package. + +The Italian Writing Aids extension includes hyphenation patterns +based on a conversion of the "Hyphenation patterns for the Italian +language" available at http://tug.ctan.org/pkg/ithyph ; see the +README_hyph_it_IT.txt file for the relevant copyright notices. + +The following volunteers, and in general the OpenOffice.org Community +and PLIO http://www.plio.it contributed to the previous versions of Italian +Writing Aids extension: +- Andrea Pescetti, previous maintainer until version 2015 +- Paolo Mantovani, extension structure +- Carlo Strata, suggestions and bug reports (spellchecker) +- Diego Favaro, suggestions and bug reports (thesaurus) +- Renzo Bianchi, graphics and QA + +---------------------------------------------------------------------- + +# The "Italian thesaurus" is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License, +# version 3, as published by the Free Software Foundation. +# +# The "Italian thesaurus" is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +GNU GENERAL PUBLIC LICENSE + +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 . diff --git a/assets/spelling/licenses/it_IT/README_th_it_IT.txt b/assets/spelling/licenses/it_IT/README_th_it_IT.txt new file mode 100644 index 00000000..899277f5 --- /dev/null +++ b/assets/spelling/licenses/it_IT/README_th_it_IT.txt @@ -0,0 +1,415 @@ +Version 5.1.1 (07/11/2022) (dd/mm/yyyy) + +# Dizionario dei sinonimi italiano - Italian Thesaurus +# Copyright (C) 2004,2005,2006,2007,2008 Daniela Volta +# Copyright (C) 2008 Giovanni Zuliani +# Copyright (C) 2006,2007,2008 Davide Prina +# Copyright (C) 2010 - 2015, Andrea Pescetti +# Copyright (C) 2020, LibreItalia - Marina Latini +# E-Mail: marinalatinilibreofficeorg +# License: GNU GPL 3 +# Home: https://libreitalia.or + +For English Readers: please scroll down for English version. + +********************************** +*********** Italiano *********** +********************************** + +SOMMARIO + +1. Licenza +2. Compatibilità +3. Ringraziamenti + +1. Licenza +---------- + +Il thesaurus italiano per il programma MyThes usato da LibreOffice è +distribuito da LibreItalia a Marina Latini, contattabili all'indirizzo +e-mail: marina(punto)latini(chiocciola)libreoffice(punto)org +sotto i termini e le condizioni della GNU General Public License (GPL) +versione 3. Una volta accettata la licenza, l'accettante dovrà rispettare +tutti i termini e le condizioni riportate nella licenza scelta. + +Una copia della licenza applicabile a questo lavoro è disponibile in +coda al presente file. + +Dalla versione 2.0 è stato incluso parzialmente anche un altro +thesaurus presente anche nel programma GPL http://search.mnogo.ru. +Questo thesaurus è stato fornito da Marcello Bianchetti sotto licenza +di pubblico dominio per l'integrazione con il thesaurus di OOo. + +2. Compatibilità +---------------- + +Il presente thesaurus funziona con le versioni di LibreOffice maggiori +o uguali della versione 3.X. + +Il file degli indici è ottenuto con MyThes. + +3. Ringraziamenti +----------------- +Hanno collaborato: + +- Versione 5.1.1: Emanuele Goldoni +- Versione 5.1.0: Marina Latini (maintainer), LibreItalia. +- Versione 3.3: Andrea Pescetti (maintainer), Paolo Mantovani + (struttura dell'estensione), Diego Favaro, Renzo Bianchi. +- Versioni 2.0 - 2.07.gh_2008_02_10: Daniela Volta (coordinatrice dei + lavori e responsabile del progetto), Davide Prina (creazione + pacchetti, controlli generali finali, allineamento + dizionario <-> thesaurus, estrazione controlli, definizioni), Valter + Mura e Fernando Nappo (thesaurus 1.x e 2.x); Marcella Audino, Edgardo + Lugaresi, Daniele Limonta, Ambrogio Ratti, Piero Graziano (thesaurus + 1.x e 2.x); Enzo Coacci, Renzo Perer, Lanfranco Fabriani, Renzo + Coacci, Giacomo Scocco, Giovanni Zuliani (thesaurus 2.x). +- Versioni 1.x: Giuseppe Modugno (autore di ThesCoder utilizzato per + ottenere i binari del thesaurus per OOo 1.x.y), gli alunni del liceo + scientifico dell'Istituto di Istruzione Superiore J.M. Keynes di + Castelmaggiore Bologna Classi 3HL, 3GL, 5GL anno scolastico 2003/2004, + Prof. Giuseppe Gioffré Florio con la classe 3 A ITC Leonida Rapaci + Villa San Giovanni (RC) anno scolastico 2003/2004; Marco Ardito, + Valter Ballantini, Paolo Baldi, Luca Baralis, Michele Bariani, + Giuseppe Santo Barile, Stefano Battocletti, Luigi Belli, Lorenzo + Bellini, Roberto Bellucci, Enrico Benucci, Andrea Bernasconi, Marco + Boneff, Massimiliano Borghesi, Enrico Boschi, Laura Brandi, Francesco + Brollo, Elisa Calcagni, Fabio Cantoni, Marco Caresia, Paolo + Castagnini, Riccardo Caverni, Claudia Ciabatti, Marco Ciacci, Ascanio + Colacino, Claudio Colombo, Luigi Conti, Alberto Crescentini, + Alessandro Cum, Dario Curvino, Antonio D'Andrea, Alessio Del Ben, + Alessandro Della Torre, Vittorio De Zan, Enrico Diacci, Luca Di + Gianleonardo, Marco Di Meo, Carlo Dodi, Alessandro Donati, Marco + Faenzi Vallés, Andrea Favini, Carlo Ferrari, Fabio Ferriccioli, + Massimo Forti, Lorenzo Fragiacomo, Diego Favaro, Ferdinando Fiumara, + Davide Gallo, Fabrizio Gareggia, Silvio Gaspar, Fabrizio Gerardi, + Mario Govoni, Ilaria Giacalone, Alberto Gilardi, Paolo Iacobazzi, + Andrea Iavarone, Enrico Imberti, Andrea Invernizzi, Lorenzo Iorio, + Mario L'Abbate, Valerio Magnani, Luca Marletta, Pietro Marogna, + Angelo Mastrogiacomo, Cristian Michelini, Marco Montanari, Andrea + Nardi, Enrico Nardi, Fernando Nappo, Simone Paolucci, Valerio + Passini, Federico Pellagatta, Daniele Pertile, Enrico Pitea, Fabiano + e Fabiola Piva, Maurizio Placidi, Antonio Pistis, Carlo Poggiali, + Daniele Ragusa, Diego Regina, Giuseppe Restuccia, Antonio Ricci, + Carla Rigamonti, Nicola Romana, Aldo Rossi, Luca Saba, Virginio + Savani, Carlo Scarpato, Simone Severa, Riccardo Signorotto, Dario + Tambone, Pietro Tamburrano, Eugenio Tiziani, Anna Treossi, Alessandro + Turato, Livio Trucano, Andrea Vaccari, Giuseppe Zafarone, Riccardo + Zancan, Fabio Zeneudelli, Mirco Zorzo. + +********************************** +*********** English ************ +********************************** + +The Italian Thesaurus + +INDEX + +1. License +2. Compatibility +3. Acknowledgements + +1. License +---------- + +The Italian thesaurus used by LibreOffice is released by LibreItalia and +Marina Latini, marina(dot)latini(at)libreofficee(dot)org, under the terms and +conditions of the GNU General Public License (GPL), version 3. +The users must obey the licensing terms. + +A copy of the license is at the end of this file. + +Starting with version 2.0, it includes a GPL thesaurus found here: +http://search.mnogo.ru by Marcello Bianchetti, who agreed to contribute +it under public domain for use in the current thesaurus. + +2. Compatibility +---------------- + +The Italian Thesaurus works with LibreOffice version 3.6 and above. + +The index file is created using MyThes. + +3. Acknowledgements +------------------- +The following people helped in developing the thesaurus: + + +- Version 5.1.1: Emanuele Goldoni +- Version 5.1.0: Marina Latini (maintainer), LibreItalia. +- Version 3.3: Andrea Pescetti (maintainer), Paolo Mantovani + (extension structure), Diego Favaro, Renzo Bianchi. +- Versions 2.0 - 2.07.gh_2008_02_10: Daniela Volta (coordinator), + Davide Prina (maintainer), Valter Mura and Fernando Nappo (thesaurus + 1.x and 2.x); Marcella Audino, Edgardo Lugaresi, Daniele Limonta, + Ambrogio Ratti, Piero Graziano (thesaurus 1.x and 2.x); Enzo Coacci, + Renzo Perer, Lanfranco Fabriani, Renzo Coacci, Giacomo Scocco, + Giovanni Zuliani (thesaurus 2.x). +- Versions 1.x: Giuseppe Modugno (author of ThesCoder), students from + "liceo scientifico dell'Istituto di Istruzione Superiore J.M. Keynes + di Castelmaggiore Bologna Classi 3HL, 3GL, 5GL anno scolastico + 2003/2004", Prof. Giuseppe Gioffré Florio with "classe 3 A ITC + Leonida Rapaci Villa San Giovanni (RC) anno scolastico 2003/2004"; + Marco Ardito, Valter Ballantini, Paolo Baldi, Luca Baralis, Michele + Bariani, Giuseppe Santo Barile, Stefano Battocletti, Luigi Belli, + Lorenzo Bellini, Roberto Bellucci, Enrico Benucci, Andrea Bernasconi, + Marco Boneff, Massimiliano Borghesi, Enrico Boschi, Laura Brandi, + Francesco Brollo, Elisa Calcagni, Fabio Cantoni, Marco Caresia, Paolo + Castagnini, Riccardo Caverni, Claudia Ciabatti, Marco Ciacci, Ascanio + Colacino, Claudio Colombo, Luigi Conti, Alberto Crescentini, + Alessandro Cum, Dario Curvino, Antonio D'Andrea, Alessio Del Ben, + Alessandro Della Torre, Vittorio De Zan, Enrico Diacci, Luca Di + Gianleonardo, Marco Di Meo, Carlo Dodi, Alessandro Donati, Marco + Faenzi Vallés, Andrea Favini, Carlo Ferrari, Fabio Ferriccioli, + Massimo Forti, Lorenzo Fragiacomo, Diego Favaro, Ferdinando Fiumara, + Davide Gallo, Fabrizio Gareggia, Silvio Gaspar, Fabrizio Gerardi, + Mario Govoni, Ilaria Giacalone, Alberto Gilardi, Paolo Iacobazzi, + Andrea Iavarone, Enrico Imberti, Andrea Invernizzi, Lorenzo Iorio, + Mario L'Abbate, Valerio Magnani, Luca Marletta, Pietro Marogna, + Angelo Mastrogiacomo, Cristian Michelini, Marco Montanari, Andrea + Nardi, Enrico Nardi, Fernando Nappo, Simone Paolucci, Valerio + Passini, Federico Pellagatta, Daniele Pertile, Enrico Pitea, Fabiano + e Fabiola Piva, Maurizio Placidi, Antonio Pistis, Carlo Poggiali, + Daniele Ragusa, Diego Regina, Giuseppe Restuccia, Antonio Ricci, + Carla Rigamonti, Nicola Romana, Aldo Rossi, Luca Saba, Virginio + Savani, Carlo Scarpato, Simone Severa, Riccardo Signorotto, Dario + Tambone, Pietro Tamburrano, Eugenio Tiziani, Anna Treossi, Alessandro + Turato, Livio Trucano, Andrea Vaccari, Giuseppe Zafarone, Riccardo + Zancan, Fabio Zeneudelli, Mirco Zorzo. + +---------------------------------------------------------------------- + +# The "Italian thesaurus" is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public License, +# version 3, as published by the Free Software Foundation. +# +# The "Italian thesaurus" is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +GNU GENERAL PUBLIC LICENSE + +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 . diff --git a/assets/spelling/licenses/it_IT/legacy/it_IT_COPYING b/assets/spelling/licenses/it_IT/legacy/it_IT_COPYING new file mode 100644 index 00000000..e5dedf3f --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/it_IT_COPYING @@ -0,0 +1,225 @@ +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 . diff --git a/assets/spelling/licenses/it_IT/legacy/it_IT_README.1st b/assets/spelling/licenses/it_IT/legacy/it_IT_README.1st new file mode 100644 index 00000000..9994450a --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/it_IT_README.1st @@ -0,0 +1,77 @@ +Versione 2.4 (01/09/2007) (dd/mm/yyyy) + +home page: http://linguistico.sf.net/wiki + +For English Readers: please see the text at the end of this document +---------------------------------- + +********************************** +*********** Italiano *********** +********************************** + +Questo dizionario è rilasciato sotto licenza GPL versione 3.0 o superiore. +Puoi trovare il testo della licenza qui: http://www.gnu.org/ +(http://www.gnu.org/licenses/gpl.txt) + +Con questo file (it_IT_README.1st) sono inclusi anche i seguenti: +* it_IT.dic il file del dizionario (radici + regole per l'espansione) +* it_IT.aff il file delle affix (le regole) +* it_IT_COPYING (la licenza GPL) +* it_IT_license.txt (il copyright e la licenza usata per questo lavoro) +* it_IT_README.txt (una piccola documentazione) +* it_IT_statistiche.sxc (un file di OOoCalc con le statistiche tra le varie + versioni del dizionario) +* it_IT_ChangeLog (file contenente la storia del dizionario) +* it_IT_AUTHORS (file contenente i nomi dei volontari) +* it_IT_notes.txt (file contenente note varie relative alla versione attuale del + dizionario) +* it_IT_todo.txt (file contenente le cose da fare) + +Puoi trovare le nuove versioni del dizionario qui: +- http://linguistico.sourceforge.net/wiki +- http://sourceforge.net/projects/linguistico/ + +Puoi trovare alcune delle vecchie versioni del dizionario qui: +- http://sourceforge.net/projects/ooodocs/ +- http://xoomer.virgilio.it/alessandro.prina/ + +Ulteriori informazioni circa questo dizionario, gli autori e chi ha contribuito, +possono essere reperite visitando la pagina: +- http://it.openoffice.org/contribuire/spellcheck.html + +Per contattare gli autori è possibile scrivere a: +* DavidePrina(chiocciola)yahoo(punto)com + +********************************** +*********** English ************ +********************************** + +This dictionary is released under GPL license version 2.0 or above. +You can find the text of the license on http://www.gnu.org/ +(http://www.gnu.org/licenses/gpl.txt) + +With this file (it_IT_README.1st) you must find: +* it_IT.dic the dictionary file (words with rules) +* it_IT.aff the affix file (rules) +* it_IT_COPYING (the GPL license) +* it_IT_license.txt (the copyright and license used for this work) +* it_IT_README.txt (a small documentation) +* it_IT_statistiche.sxc (a calc file with statistics on our works) +* it_IT_ChangeLog (file with the history of the Italian dictionary) +* it_IT_AUTHORS (file with volunteer names) +* it_IT_notes.txt (file with additional notes about acutual dictionary version) +* it_IT_todo.txt (file with things todo) + +You can find new Italian dictionary versions here: +- http://linguistico.sourceforge.net/wiki +- http://sourceforge.net/projects/linguistico/ + +You can find some old Italian dictionary versions here: +- http://sourceforge.net/projects/ooodocs/ +- http://xoomer.virgilio.it/alessandro.prina/ + +For further information about this dictionary, the authors or how to contribute +to it, please visit http://it.openoffice.org/contribuire/spellcheck.html + +You can contact authours writing to: +* DavidePrina(at)yahoo(dot)com diff --git a/assets/spelling/licenses/it_IT/legacy/it_IT_README.txt b/assets/spelling/licenses/it_IT/legacy/it_IT_README.txt new file mode 100644 index 00000000..d8d4ab98 --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/it_IT_README.txt @@ -0,0 +1,447 @@ +Version 2.4 (01/09/2007) (dd/mm/yyyy) + +Home page: http://linguistico.sf.net/wiki + +For English Readers: please see the text at the end of this document + +********************************** +*********** Italiano *********** +********************************** + +Il dizionario italiano + +SOMMARIO + +1. Licenza +2. Avvertenze importanti (leggere assolutamente) +3. Modalità d'installazione in OpenOffice.org +4. Integrazione con altri prodotti +5. Altri correttori ortografici che fanno uso di questo dizionario +6. Ringraziamenti + + +********** +1. Licenza + +Il file affix e il dizionario italiano per il correttore ortografico MySpell +usato da OpenOffice.org sono rilasciati da Davide Prina +davideprinayahoocom (sostituire con @ e con . per il +contatto via E-Mail) sotto i termini e le condizioni della GNU General Public +License (GPL) 3.0 o successiva. Una volta accettata la licenza per +l'uso, la distribuzione e la modifica di questo prodotto, l'accettante dovrà +rispettare tutti i termini e le condizioni riportate nella licenza scelta. + +La copia della licenza applicabile a questo lavoro è disponibile presso il sito +del progetto GNU: + +http://www.gnu.org/ + +La licenza è anche allegata nel file it_IT_COPYING + +************************************************ +2. Avvertenze importanti (leggere assolutamente) + +A partire da OpenOffice.org 1.1, il dizionario italiano per la correzione +ortografica è direttamente integrato nella suite e perciò non necessita più di +alcuna installazione manuale. L'unico problema è che non è aggiornato all'ultima +versione e quindi è consigliato effettuare l'aggiornamento manuale o automatico +ad ogni nuova versione rilasciata, come è indicato di seguito. + +È opportuno verificare che il dizionario sia attivo, selezionando dalla barra +dei menù Strumenti->Opzioni->Impostazione Lingua->Lingue e controllando che +sotto lingue standard/Occidentale, l'opzione di scelta "Italiano (Italia)" sia +selezionata e abbia al suo fianco un segno di spunta sormontato dalle lettere +ABC. + +Nel caso il correttore non risultasse attivo, è sufficiente scegliere dalla +barra dei menù Strumenti->Opzioni->Impostazione Lingua->Linguistica e dopo avere +premuto sul pulsante "Modifica" della finestra di dialogo, attivarlo seleziondo +l'apposita voce. + +Se tuttavia il correttore non risultasse ancora attivo o nell'eventualità che si +voglia aggiornare la versione del dizionario installata è possibile utilizzare +le procedure di installazione indicate oltre. + +È vivamente consigliato l'aggiornamento del dizionario perché le ultime versioni +contengono molte correzioni rispetto alle precedenti e sono meno esose di +risorse. + +****************************************************************************** +3. Modalità d'installazione (procedura corretta a partire dalla versione 641c) + +Ulteriore documentazione può essere trovata qui: +http://linguistico.sourceforge.net/wiki + +Esistono principalmente due modalità per installare il dizionario italiano: + +a) in automatico, grazie a due comodi installer creati da membri della comunità + che si occupano di tutte le fasi dell'installazione. + +Nota: non è detto che l'aggiornamento automatico prelevi l'ultima versione del + dizionario, in alcuni casi potrebbe addirittura installare una versione + più vecchia rispetto a quella presente sul proprio sistema. + L'installazione manuale/semimanuale è quella sempre corretta ed è molto + semplice da effettuare. + +La versione per MS Windows si trova su + +http://www.ooodocs.org/dictinstall/ + +Mentre la versione per Linux è reperibile presso + +http://www.deadletterdrop.worldonline.co.uk/OOo/ + +oppure + +http://ooodi.sourceforge.net/ + +Nelle ultime versioni l'installatore dei dizionari è già inserito in OOo e +quindi è possibile effettuare un'installazine semiautomatica seguendo i seguenti +punti: +* scaricare l'ultima versione del dizionario da + http://sourceforge.net/projects/linguistico/ + andando sulla sezione download + + Nota: è possibile prendere il file più recente contenuto in: + - Strumenti Linguistici DicOOo <- contiene sia il dizionario che il + thesaurus, però bisogna scegliere il + pacchetto corretto rispetto alla + propria versione di OOo (2.0 o 1.1.x) + +* aprire qualsiasi documento di OOo od il contenitore soffice +* dal menù: File->Pilota automatico->Installa nuovi dizionari + Nota: il documento contiene una macro necessaria per l'installazione + automatica +* selezionare l'italiano +* premere il bottone Avvia DicOOo +* mettere il check su "Installazione pacchetto linguistico off-line" +* premere sul bottone "sfoglia", cercare e selezionare il file scaricato nel + primo punto +* selezionare gli strumeti linguistici che si vogliono installare + +b) manualmente +I nuovi dizionari sono scaricabili da qui: +http://sourceforge.net/projects/linguistico/ +nella sezione download -> "Dizionario italiano per OOo" + +Scompattate il file compresso (.zip, tar.gz, bzip,...) nella directory/cartella +corretta; tale directory dipende dal sistema operativo usato e dalla propria +versione di OOo (per visualizzare la propria versione è sufficiente aprire un +documento di OOo, aprire il menù ? e selezionare la voce "Informazioni su +OpenOffice.org ...) + +Per Debian GNU/Linux: /usr/share/myspell/dict + +Per le versioni ufficiali Sun: +* per le versioni maggiori o uguale alla 1.0.1 la directory su windows è: + /share/dict/ooo +* per le versioni inferiori alla versione 1.0.1 la directory è: + /user/wordbook/ + +Se il vostro sistema operativo è differente e/o non riuscite a trovare la +directory in cui effettuare l'installazione, allora è possibile cercare il file +dictionary.lst; la directory dove trovare questo file è quella in cui dovete +installare il dizionario. + +Aprite in un qualsiasi editor di testo il file dictionary.lst che troverete +nella cartella citata precedentemente, in modo da poter inserire il codice +della lingua e della regione che vi interessa. + +Per esempio: +nel vostro editor di testo aggiungete questa linea al file dictionary.lst: + +DICT it IT it_IT + +ATTENZIONE: la riga sopra indicata non deve iniziare con il simbolo #, +altrimenti l'istruzione è commentata e di conseguenza non è eseguita. +È indispensabile che siano rispettati i caratteri maiuscoli e minuscoli come +riportato nell'esempio, altrimenti non funziona. Inoltre è consigliabile +controllare che tale riga sia presente una sola volta nel file, altrimenti il +dizionario verrà caricato più volte (una volta per ogni riga presente) causando +uno spreco di memoria RAM e l'inconveniente di fornire più volte gli stessi +suggerimenti alle parole errate. + +Quindi salvate il file con le vostre modifiche. +I significati dei vari campi sono: + +Campo 1: Tipo di stringa: "DICT" , al momento è l'unica voce disponibile. +Campo 2: Codice linguistico "it" o "de" o "en" ...(vedi Codici Linguistici ISO) +Campo 3: Codice Regionale "IT" o"DE" o "US" ... (vedi Codici Regionali ISO) +Campo 4: Il nome del dizionario da utilizzare "it_IT" o "it_CH" o ... + Senza aggiungere le estensioni .aff o .dic dei files. Questa voce è + particolarmente utile se vogliamo creare i nostri dizionari + specialistici. Per esempio it_INFORMATICA o it_DIRITTO. Sarà + sufficiente aggiungere un'altra linea al file dictionary.lst cambiando + solo il nome del dizionario e il correttore ortografico di + OpenOffice.org controllerà i vostri documenti usando in successione + tutti i dizionari elencati e presenti nella cartella wordbook per la + lingua italiana. + +Ora è necessario chiudere tutte le applicazione di OpenOffice.org attive, +compreso il quick start. Questo passo serve per permettere ad OOo di vedere le +modifiche apportate e di utilizzarle. + +Successivamente : + +1) Aprite un nuovo documento di OpenOffice.org e scegliete dalla barra dei menù + il comando: + Strumenti->Opzioni->Impostazioni Lingua->Lingue + (Tools->Options->Language settings->Languages nella versione inglese) +2) Impostate nell'elenco a discesa che vedete sulla destra la lingua italiana + quale linguaggio di default per i vostri documenti +3) selezionando l'elemento Linguistica (Writing Aids) che troverete nella + sezione Impostazioni Lingua (Language Settings) e premendo il tasto di + modifica della sezione Moduli Linguistici Disponibili (Available language + modules) collocato sulla destra della finestra di dialogo, potrete accedere + alla sezione che vi permetterà di impostare il correttore in italiano. Sarà + sufficiente scegliere la nostra lingua dall'elenco a discesa che mostra tutti + i dizionari disponibili nella Suite, facendo attenzione a selezionare con un + segno di spunta, la funzione di correzione ortografica nel riquadro + immediatamente sottostante l'elenco a discesa. + +Attenzione: La denominazione dei comandi di menù o delle finestre può subire +modifiche o la loro collocazione può essere modificata nel passaggio da una +versione ad un'altra. + +Attenzione: gli utenti di OpenOffice.org per MS Windows, devono riavviare anche +il quickstarter della Suite, la piccola icona con i gabbiani (versione 1.0 o +superiore) che dovrebbe apparire sulla System Tray nell'angolo in basso a destra +dello schermo, proprio a fianco dell'orologio di sistema. È sufficiente cliccare +col tasto destro del mouse sull'icona e scegliere esci o exit dal menù di +contesto. Successivamente, si dovrà effettuare l'installazione del dizionario, +mantenendo disattivato il quickstarter durante tutta la procedura, chiudere il +documento dal quale si sono modificate le opzioni generali e riaprirne uno nuovo +per verificare il funzionamento del correttore italiano. + +Questo è tutto, il correttore ortografico in italiano dovrebbe funzionare in +modo adeguato. + + +********************************** +4. Integrazione con altri prodotti + +Il dizionario italiano può essere usato con vari programmi. +Qui di seguito ne vengono riportati alcuni: +* OpenOffice.org: in modo nativo + Caratteristiche: controllo ortografico durante la digitazione o su richiesta + http://it.openoffice.org + +* Mozilla-ThunderBird (è un client di posta): in modo nativo + Caratteristiche: controllo ortografico solo su richiesta) + http://www.mozilla.org/products/thunderbird/ +* Mozilla (browser con client di posta): in modo nativo + Caratteristiche: controllo ortografico solo su richiesta + http://www.mozilla.org +* Mozilla-FireFox (è un browser): con l'estensione SpellBound + Caratteristiche: controllo ortografico durante la digitazione o su richiesta + Nota: il dizionario è installato in una directory differente + http://spellbound.sourceforge.net/ +* Mozilla-ThunderBird (è un client di posta): con l'estensione Thunderbird + In-Line SpellChecker + Caratteristiche: controllo ortografico durante la digitazione + http://www.supportware.net/mozilla/#ext8 + +* vim: è possibile convertire un dizionario per MySpell in modo da poter essere + usato direttamente anche da vim. Per ora tale funzionalità è disponibile solo + sulla versione in sviluppo di vim. + +* gaim + +Nota: è possibile scaricarsi i dizionari anche dal sito di mozilla (ma non è + detto che siano aggiornati all'ultima versione): http://www.mozdev.org/ + +* ... + + +****************************************************************** +5. Altri correttori ortografici che fanno uso di questo dizionario + +Questo dizionario può essere usato dai seguenti programmi di correzione +ortografica: +* MySpell. http://lingucomponent.openoffice.org +* Aspell. http://aspell.net +* HunSpell. http://hunspell.sf.net + + +************************************************ +6. Ringraziamenti + +Gli utenti di un elaboratore di testi, come di qualunque altra applicazione +software che utilizzi un correttore ortografico, spesso sottovalutano il lavoro +necessario per produrre questo strumento fondamentale. I problemi sono molti: +la lingua italiana non è statica, ma in continua evoluzione; semplici errori di +digitazione in un dizionario digitale possono portare a gravi conseguenze sul +funzionamento del correttore; ciò che si usa correntemente nella lingua parlata +non sempre è corretto in quella scritta. + +Proprio per ovviare a tali difficoltà, i volontari della Comunità OpenOffice.org +hanno partecipato attivamente al controllo di qualità del contenuto dell'attuale +dizionario per la correzione ortografica. Con questa sezione si vuole rendere +merito a tutti coloro che hanno collaborato in questa attività. + +È possibile vedere l'elenco dei volontari all'interno del file AUTHOURS + + +********************************** +*********** English ************ +********************************** + +The Italian dictionary. + +INDEX + +1. License +2. Warnings (to read absolutely) +3. How to install it in OpenOffice.org +4. Others product that can use this dictionary +5. Other spell checking program that can use this dictionary +6. Thanks + + +********** +1. License + +The Italian dictionary and affix file for the MySpell spell-checker used by +OpenOffice.org are released by Davide Prina davideprinayahoocom (please +change with @ and with . in order to contact the authors) under the +terms and conditions of the GNU General Public License (GPL) version 3.0 or +above. The user, distributor and/or programmer after accept this license when +he/she uses, distributes and/or modifies these files. He/she must agree with +every term and condition included in the chosen license. + +A copy of the licenses applicable to this work is available at: + +http://www.gnu.org/ + +A copy of the license is in the GPL.txt file + + +******************************** +2. Warnings (to read absolutely) + +Warning: Since the release of OpenOffice.org 1.1 the Italian dictionary is +directly integrated into the applications and so it doesn't need any manual +installation. Probably in OpenOffice.org there is not the last version so it is +better to install it as show below. It is a good norm to verify that the +dictionary has been activate. You can do so simply by selecting from the menu +bar Tools->Options->Language Settings->Languages and by checking that the item +"Italian (italy)" is selected and a slash with the letters ABC is displayed to +its side. + +If the dictionary is not activated yet, you can perform this action by selecting +from the menu bar Tools->Options->Language Settings->Writing Aids and by +clicking on the "Edit..." button you will find in the dialog window. In the new +dialog that will appear, you can activate the dictionary. + +In the case the dictionary doesn't still work or you wish to upgarde the version +of your installed dictionary you can follow the procedures explained below. + + +************************************** +3. How to install it in OpenOffice.org + +Note: new dictionary versions are avaiable from here: +http://sourceforge.net/projects/linguistico/ + +a) To install these dictionaries in OOo build 641c and greater: + A. Unzip the dictionary files, *.aff and *.dic, + into your \user\wordbook\*.* directory + +Attention: since OpenOffice.org 1.0.1 the right folder for the dictionary is + \share\dict\ooo + + B. Edit the dictionary.lst file that is in that same directory + using any text editor to register a dictionary for a specific + locale (the same dictionary can be registered for multiple locales). + +For example: +To add the it_IT.zip dictionary under the Italian (Italy) locale to OOo you +would: +cd \user\wordbook (or \share\dict\ooo) +unzip it_IT.zip + + +b) And then, using any text editor, add the following line to dictionary.lst: + DICT it IT it_IT + +This line tells OOo to register the affix file it_IT.aff and the wordlist +it_IT.dic to the locale it IT, which is Italian (Italy). The specific fields of +this line are: + +Field 1: Entry Type "DICT" is the only supported entry type so far +Field 2: Language code from Locale "en" or "it" or "pt" ... + (see {ISO Language Code} page) +Field 3: Country code from Locale "IT" ... + (see {ISO Country Code} page) +Field 4: Root name of Dictionary "italian" or "it_it" ... + (do not add the .aff or .dic extensions to the name) + + +c) Start up OpenOffice.org. and go to: + +Tools->Options->LanguageSettings->WritingAids + +Hit "Edit" and use the pull down menu to select your locale, Italy, +and then make sure to check the MySpell SpellChecker for that locale. + +That it! Your dictionary is installed and registered for that language. + + +********************************************** +4. Others product that can use this dictionary + +The Italian dictionary can be used with many programs. +Here is some programs that can use this dictionary: + +* OpenOffice.org + spell checking when you type or upon request + http://it.openoffice.org + +* Mozilla-ThunderBird + spell checking only upon request + http://www.mozilla.org/products/thunderbird/ +* Mozilla con il client di posta: in modo nativo + spell checking only upon request + http://www.mozilla.org +* Mozilla-FireFox: with SpellBound extension + spell checking when you type or upon request + Note: the dictionary is installed under a different directory + http://spellbound.sourceforge.net/ +* Mozilla-ThunderBird: with "Thunderbird In-Line SpellChecker" extension + spell checking when you type + http://www.supportware.net/mozilla/#ext8 + +* vim: the MySpell dictionary can be converted and used with the last vim + version + +Note: you can download dictionary at mozilla site: http://www.mozdev.org/ + +* ... + + +************************************************************ +5. Other spell checking program that can use this dictionary + +This dictionary can be used with different spell checking programs: +* MySpell. http://lingucomponent.openoffice.org +* Aspell. http://aspell.net +* HunSpell. http://hunspell.sf.net + + +********* +6. Thanks + +The users of a word processor, like of whatever application that utilizes a +spell checker, often underestimate the work needed to produce this basic tool. +There are a lot of problems: the Italian language is not static, but always +evolving; simple misspelled words in a digital dictionary can cause several +problems to the spell checker; what is commonly used in the spoken language, it +is not always right in the written one. + +Just to overcome such difficulties, the volunteers of the OpenOffice.org +Community have actively took part into the quality check of this dictionary +content. With this section, we want to give the right credit to all people who +have collaborated in this activity. + +You can read the volunteers names in the file AUTHOURS + diff --git a/assets/spelling/licenses/it_IT/legacy/it_IT_license.txt b/assets/spelling/licenses/it_IT/legacy/it_IT_license.txt new file mode 100644 index 00000000..fa95246c --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/it_IT_license.txt @@ -0,0 +1,28 @@ +# Dizionario italiano +# +# Copyright (C) 2001, 2002 Gianluca Turconi +# Copyright (C) 2002, 2003, 2004 Gianluca Turconi and Davide Prina +# Copyright (C) 2004, 2005, 2006, 2007 Davide Prina +# +# E-Mail: DavidePrina(CHIOCCIOLA)yahoo(PUNTO)com +# home: http://linguistico.sf.net/wiki +# +# Version 2.4 (01/09/2007) (DD/MM/YYYY) +# +# This file is distributed under GPL license. +# +# This file is part of the "dizionario italiano". +# +# The "dizionario italiano" 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. +# +# The "dizionario italiano" 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 the "dizionario italiano", +# if not, see . diff --git a/assets/spelling/licenses/it_IT/legacy/th_it_IT_COPYING b/assets/spelling/licenses/it_IT/legacy/th_it_IT_COPYING new file mode 100644 index 00000000..e5dedf3f --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/th_it_IT_COPYING @@ -0,0 +1,225 @@ +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 . diff --git a/assets/spelling/licenses/it_IT/legacy/th_it_IT_README b/assets/spelling/licenses/it_IT/legacy/th_it_IT_README new file mode 100644 index 00000000..dfb63acb --- /dev/null +++ b/assets/spelling/licenses/it_IT/legacy/th_it_IT_README @@ -0,0 +1,209 @@ +Version 2.07.gh (10/02/2008) (dd/mm/yyyy) + +For English Readers: please see the text at the end of this document + +********************************** +*********** Italiano *********** +********************************** + +Il thesaurus italiano + +SOMMARIO + +1. Licenza +2. Avvertenze importanti (leggere assolutamente) +3. Modalità di installazione e configurazione in OpenOffice.org +4. Ringraziamenti +5. Link/download + + +********** +1. Licenza + +Il thesaurus italiano per il programma MyThes usato da OpenOffice.org è +distribuito da Daniela Volta, contattabile all'indirizzo e-mail: +openoffice(chiocciola)keynes(punto)scuole(punto)bo(punto)it e da Davide Prina, +contattabile all'indirizzo e-mail: davideprina(chiocciola)yanoo(punto)com, +sotto i termini e le condizioni della GNU General Public License (GPL) +versione 3.0 o successiva. +Una volta accettata la licenza per l'uso, la distribuzione è consentita la +modifica di questo prodotto, l'accettante dovrà rispettare tutti i termini e le +condizioni riportate nella licenza scelta. + +Dalla versione 2.0 è stato incluso parzialmente anche un altro thesaurus +presente anche nel programma GPL http://search.mnogo.ru. + +Questo thesaurus è stato fornito da Marcello Bianchetti sotto licenza di +pubblico dominio per l'integrazione con il thesaurus di OOo. +In ogni caso verrà allegato un file contenente tutti i sinonimi ricavati da +questo thesaurus nel file: thes_PD.txt + + +************************************************ +2. Avvertenze importanti (leggere assolutamente) + +Il presente thesaurus funziona con le versioni di OpenOffice.org (OOo) maggiori +o uguali della versione 2.0 (comprese alcune delle sue beta nominate 1.9.x) + +Il file degli indici è ottenuto con MyThes, disponibile sul sito di OOo. + + +*************************************************************** +3. Modalità di installazione e configurazione in OpenOffice.org + +Se possibile è meglio consultare la guida d'installazione on-line, disponibile +qui, che di sicuro è più aggiornata e completa: +a) come installare il thesaurus: +http://linguistico.sf.net/wiki/doku.php?id=come_installare_un_thesaurus +b) come aggiornare il thesaurus: +http://linguistico.sf.net/wiki/doku.php?id=come_aggiornare_un_thesaurus + +Per installare il thesaurus occorre seguire i seguenti punti: +1) copiare i file th_it_IT.* nella directory contenente il file dictionary.lst + (questa posizione può essere diversa a seconda del sistema operativo in uso + e della versione sia del sistema operativo che di OpenOffice.org; per + esempio sotto Debian GNU/Linux è attualmente sotto + /usr/share/myspell/dict, mentre sotto windows si trova normalmente in una + directory con percorso simile a questo \Programmi\OpenOffice\share\dict\ooo) +2) editare il file di testo dictionary.lst ed aggiungendo la seguente linea +THES it IT th_it_IT +3) occorre ora chiudere tutti i processi di OpenOffice.org (compreso il + quickstart) per poter caricare il thesaurus appena installato con il prossimo + documento aperto di OOo + +Occorre successivamente configurare OpenOffice.org affinché utilizzi il +thesaurus italiano; per fare questo seguire i seguenti punti: +1) aprire un qualsiasi programma di OpenOffice.org (per esempio Write) +2) aprire il menù "Strumenti" e selezionare "Opzioni" +3) aprire "Impostazioni lingua" (facendo click sul segno "+") +4) selezionare "Lingue" +5) impostare l'italiano come lingua predefinita (vedi disegno Lingua.png) +6) selezionare "Linguistica" +7) premere il bottone "Modifica ..." +8) selezionare "Italiano" dal combo box +9) mettere il check per i check box di: + - "Controllo ortografico" + - "Sillabazione" + - "Sinonimi" + Vedere disegno Linguistica-Modifica.png +10) premere il bottone "Chiudi" +11) premere il bottone "Ok" + +Ora è possibile utilizzare il thesaurus: +1) editare una parola (es: casa) +2) posizionarsi su casa e fare una delle seguenti cose: + - premere Ctrl-F7 + - Strumenti->Sinonimi +Nota: la parola deve essere contenuta nel thesaurus per funzionare l'esempio +Nota: è possibile anche crearsi un bottone su una barra per la visualizzazione + dei sinonimi della parola su cui si è posizionati; per fare questo è + sufficiente posizionarsi con il cursore su una barra degli strumenti in + una posizione vuota (senza nessun bottone), premere con il tasto destro + del mouse e selezionare "Modifica" dal menù pop-up che appare. A questo + punto si può aprire "Varie" e selezionare il bottone "Sinonimi". + + +***************** +4. Ringraziamenti + +Vedere i file: +* AUTHORS +* lettera in inglese.txt + + +****** +5.Link/download + +Le ultime versioni del thesaurus, thescoder e tutto quanto riguarda il progetto +linguistico italiano può essere scaricate da qui: +http://linguistico.sf.net/wiki +http://sf.net/projects/linguistico + + +********************************** +*********** English ************ +********************************** + +The Italian Thesaurus + +INDEX + +1. License +2. Warnings (to read absolutely) +3. How to install it in OpenOffice.org +4. Thanks +5. Links/downloads + + +********** +1. License + +The Italian thesaurus used by OpenOffice.org are released by Daniela Volta +openoffice(at)keynes(dot)scuole(dot)bo(dot)it and Davide Prina +davideprina(at)yahoo(dot)com (please change with @ and + with . in order to contact the authors) under the terms and conditions of +the GNU General Public License (GPL) version 3.0 or above. The user, +distributor and/or programmer after accept this license when he/she uses, +distributes and/or modifies these files. He/she must agree with every term and +condition included in the chosen license. + +From version 2.0 we have been added a GPL thesaurus found here: +http://search.mnogo.ru +This thesaurus author is Marcello Bianchetti. +All words added from that thesaurus can be found here: thes_GPL.txt + + +******************************** +2. Warnings (to read absolutely) + +The Italian Thesaurus work only with at least OpenOffice.org (OOo) version 2.0. + +The index file is created by MyThes, you can find MyThes on the OOo site. + + +************************************** +3. How to install it in OpenOffice.org + +It is best to read the italian documentation found here: +a) come installare il thesaurus: +http://linguistico.sf.net/wiki/doku.php?id=come_installare_un_thesaurus +b) come aggiornare il thesaurus: +http://linguistico.sf.net/wiki/doku.php?id=come_aggiornare_un_thesaurus + +When you have the two binary files you can install they do the following: +1) copy th_it_IT.* files into the directory with the dictionary.lst file +2) edit the dictionary.lst file and adding the following line: +THES it IT th_it_IT +3) shutdown all the OOo process (also the OOo quickstart) and than start a OOo +program to have the new Italian thesaurus ready + +Now you must configure OpenOffice.org: +1) open one OOo program (for example Write) +2) open "Tools" menù and select "Options" +3) open "Lenguage tools" +4) select "Lenguage" +5) set Italian as default lenguage (as show in the file Lingua.png) +6) select "Linguistic" +7) press "Modify" button +8) select "Italian" from the combo box +9) check all the check box (as show in the file Linguistica-Modifica.png) +10) press "Close" button +11) press "Ok" + +Now you can use the Italian thesaurus using Ctrl-F7 or Tools->Thesaurus + + +********* +4. Thanks + +You can read thanks in the following files: +* AUTHORS +* lettera in inglese.txt + +****** +5.Link + +Last thesaurus versions and related programs can be found here +http://linguistico.sf.net/wiki (Italian only) +http://sf.net/projects/linguistico/ + diff --git a/assets/spelling/licenses/ko_KR/README_ko_KR.txt b/assets/spelling/licenses/ko_KR/README_ko_KR.txt new file mode 100644 index 00000000..5ac3299f --- /dev/null +++ b/assets/spelling/licenses/ko_KR/README_ko_KR.txt @@ -0,0 +1,6 @@ +name : Korean(ko_KR) spellcheck dictionary +date : 2024. 08. 21. +License: GPL-3.0 + +- The dictionary files (ko_KR.aff and ko_KR.dic) were built from the Korean hunspell dictionary project(https://github.com/spellcheck-ko/hunspell-dict-ko) by Changwoo Ryu. +- Update dictionary file (ko_KR.dic) by DaeHyun Sung (2024.08.21) diff --git a/assets/spelling/licenses/nl_NL/LICENSE.txt b/assets/spelling/licenses/nl_NL/LICENSE.txt new file mode 100644 index 00000000..acd929a9 --- /dev/null +++ b/assets/spelling/licenses/nl_NL/LICENSE.txt @@ -0,0 +1,440 @@ +_for English, please see below_ + + +# Nederlandse licentiebepalingen + +U wordt vriendelijk verzocht om dit bestand genaamd `LICENSE.txt` door te lezen +en een kopie te behouden bij elke kopie die u van dit project of bestanden van +dit project maakt. + +1. Titel: Nederlands woordenboek voor spellingcontrole +2. Maker: OpenTaal https://opentaal.org +3. Rechten: Revised BSD License en/of CC BY 3.0 +4. Datum en versie: zie het bestand datetimeversion.txt + +Voor vragen over licenties of bronvermelding, contacteer a.u.b. OpenTaal. + +5. Bron: https://github.com/OpenTaal/opentaal-hunspell +6. Licentiekeuze: Om zo groot mogelijk (her)gebruik mogelijk te maken, zijn deze + taalbestanden vrij beschikbaar onder liberale licenties naar discretie van de + gebruiker. We raden aan de relevante licenties door te lezen voor gebruik te + starten. Kies een of beide licenties die voor u het meest van toepassing is. + A) Revised BSD License (3-clause license), as is defined at + https://opensource.org/licenses/BSD-3-Clause (see also below) + B) Creative Commons, Attribution 3.0 Unported (CC BY 3.0), as is defined at + https://creativecommons.org/licenses/by/3.0/legalcode.txt (see also below) +7. Makergeschiedenis: + © 2020 OpenTaal (Simon Brouwer, Sander van Geloven) + © 2006 - 2011 OpenTaal (Ruud Baars, Simon Brouwer) + © 2001 - 2005 Simon Brouwer e.a. + © 1996 Nederlandstalige TeX Gebruikersgroep +8. Ondersteuning: Stichting OpenTaal is een vrijwilligersorganisatie die door de + Nederlandse Belastingdienst is aangemerkt als een algemeen nut beogende + instelling of ANBI, https://belastingdienst.nl/anbi . Hierdoor is kunnen uw + donaties via https://opentaal.org/vrienden-van-opentaal aftrekbaar zijn. +9. Deelname: Iedereen is welkom bijdrages te leven. Door bij te dragen stemt u + in dat uw bijdragen onder vrije en/of opensource licenties beschikbaar komen. + Als u wilt kan uw naam vermeld worden op onze website. +10.Rechten van derden: OpenTaal respecteert de rechten van derden en probeert + haar data vrij beschikbaar te houden. Daarom mag u geen beschermde bronnen + gebruiken om bij te dragen aan dit project. Het is toegestaan om spellings- + instructies en woordenlijst van de Nederlandse Taalunie te raadplegen. In het + geval dat u denkt dat OpenTaal rechten schendt, vragen wij u om zo spoedig + mogelijk een schriftelijke kennisgeving toe te sturen. + + +# English license stipulations + +You are kindly requested to read this file called `LICENSE.txt` and to keep a +copy of it with every copy you make of this project or files of this project. + +1. Title: Dutch dictionary for spelling checker +2. Creator: OpenTaal https://opentaal.org +3. Rights: Revised BSD License and/or CC BY 3.0 +4. Date and version: see the file datetimeversion.txt + +For questions regarding licenses or source attribution, please contact OpenTaal. + +5. Source: https://github.com/OpenTaal/opentaal-hunspell +6. License choice: To enable the broadest (re)use, these language files are + freely available under the liberal licenses at the discretion of the user. We + strongly recommend to read the applicable license before usage. Choose one or + both licenses which apply best for you. + A) Revised BSD License (3-clause license), as is defined at + https://opensource.org/licenses/BSD-3-Clause (see also below) + B) Creative Commons, Attribution 3.0 Unported (CC BY 3.0), as is defined at + https://creativecommons.org/licenses/by/3.0/legalcode.txt (see also below) +7. Creator history: + © 2020 OpenTaal (Simon Brouwer, Sander van Geloven) + © 2006 - 2011 OpenTaal (Ruud Baars, Simon Brouwer) + © 2001 - 2005 Simon Brouwer and others + © 1996 Nederlandstalige TeX Gebruikersgroep +8. Support: Stichting OpenTaal is a volunteer organisation which is designated + by the Dutch Tax Administration as an Institution for General Benefit + (algemeen nut beogende instelling or ANBI), https://belastingdienst.nl/anbi . + Hence, your donations via https://opentaal.org/vrienden-van-opentaal can be + tax deductible. +9. Participate: Everyone is welcome to participate. By contributing to the + project you agree that your contribution is available under free or/open + source licenses. If you wish, your name will be mentioned on the website. +10.Rights of third parties: OpenTaal respects the rights of third parties and + aims to keep its data freely available. Therefore you may not use protected + sources of third parties, i.e. dictionaries, without their permission when + you contribute to the project. It is permitted to consult the materials of + the Dutch Language Union, i.e. their spelling instruction and word list. In + case you believe OpenTaal is violating your rights, we ask you to send us a + written notice as soon as possible. + + +# Revised BSD License (3-clause license) + +Copyright (c) 2020, OpenTaal +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT HOLDER 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. + + +# Creative Commons, Attribution 3.0 Unported (CC BY 3.0) + +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/. diff --git a/assets/spelling/licenses/nl_NL/README.md b/assets/spelling/licenses/nl_NL/README.md new file mode 100644 index 00000000..08e94798 --- /dev/null +++ b/assets/spelling/licenses/nl_NL/README.md @@ -0,0 +1,191 @@ +_for English, please see below_ + + +# Nederlandse spellingcontrole + +Dit is de Nederlandse spellingcontrole van +[Stichting OpenTaal](https://www.opentaal.org). Mits aan volledige +bronvermelding wordt gedaan en de licenties worden gerespecteerd, is deze +spellingcontrole vrij te gebruiken. De exacte voorwaarden zijn te vinden in he + bestand [LICENSE.txt](LICENSE.txt). Lees deze goed door. + +![logo Stichting OpenTaal](images/logo-shape-trans-640x360.png?raw=true) + +Deze spellingcontrole is gebaseerd op de +[Nederlandse woordenlijst](https://github.com/OpenTaal/opentaal-wordlist) van +OpenTaal. Deze lijst heeft het +[Keurmerk Spelling](http://taalunieversum.org/inhoud/spelling-meer-hulpmiddelen/keurmerk) +van de [Taalunie](http://taalunie.org) gekregen. Dit betekent dat de woorden in +deze spellingcontrole voldoen aan de officiële spelling. + +![logo Keurmerk Spelling](images/keurmerk.png?raw=true) + +Naast het gebruiken van de woordenlijst is er veel handmatig werk verricht om de +spellingcontrole te optimaliseren. + +## Inhoud + +De spellingcontrole bestaat, naast de documentatie en licentie, uit de volgende +bestanden: +- `nl.aff` +- `nl.dic` +- `datetimeversion.txt` + +Deze zijn samengesteld en gecontroleerd met een aantal hulpbestanden: +- `../opentaal-wordlist/wordparts.tsv` +- `../opentaal-wordlist/corrections.tsv` +- `elements/archaic.tsv` +- `elements/excluded.tsv` +- `elements/inflections.tsv` +- `elements/nosuggest.txt` +- `elements/objectionable.txt` +- `elements/obsolete.tsv` +- `elements/outdated.tsv` +- `elements/replacements.tsv` +- `elements/stress.tsv` + +De spellingcontrole bestaat uit de twee +[UTF-8 Unicode](https://nl.wikipedia.org/wiki/UTF-8) bestanden +[nl.aff](nl.aff) en [nl.dic](nl.dic). Het +[formaat](https://linux.die.net/man/4/hunspell) ervan is redelijk complex en +is niet bedoeld om voor andere doeleinden te gebruiken. Dit formaat maakt het +mogelijk om van de meer dan 400.000 woorden uit de woordenlijst een woordenboek +te maken dat minder dan de helft zo groot is én informatie heeft over +vervoegingen, samenstellingen en suggesties. + +De datum, de tijd en het versienummer van al deze bestanden is te vinden in +[datetimeversion.txt](datetimeversion.txt). + +Beschrijving van de overige bestanden is: + +- [elements/excluded.tsv](elements/excluded.tsv), deze woorden worden +uitgesloten van de spellingcontrole omdat ze een veel voorkomende fout van een +ander woord zijn +- [elements/inflections.tsv](elements/inflections.tsv), zijn flexies met hun +basiswoorden, soms zijn dat er meerdere +als suggestie gegeven worden +- [elements/nosuggest.txt](elements/nosuggest.txt), deze woorden mogen niet +als suggestie gegeven worden +- [elements/objectionable.txt](elements/objectionable.txt) (verwerpelijk), deze +woorden zijn verwerpelijk omdat ze (buiten de studie naar dit woord) als +discriminerend of racistisch worden ervaren + + + +## Installatie + +Spellingcontrole is in veel software zoals Chrome, Firefox, Thunderbird, +LibreOffice en Adobe-producten al geïntegreerd. Daardoor is het eenvoudig deze +Nederlandse ondersteuning te installeren. + +Na installatie ondersteunt de spellingcontrole `Nederlands` of `Dutch`. +De spellingregels en de spellingcontrole zijn overigens identiek voor het +Nederlands in de landen waar deze wordt gebruikt, zoals Nederland, België en +Suriname. + +Besturingssystemen bieden ook softwarepakketten die deze spellingcontrole +installeren en automatisch updaten. Voorbeelden hiervan zijn: +- [hunspell-nl](https://packages.ubuntu.com/search?keywords=hunspell-nl) voor Ubuntu +- [hunspell-nl](https://packages.debian.org/search?keywords=hunspell-nl) voor Debian + +Voor andere besturingssystemen, zie +https://repology.org/project/hunspell-nl/versions + +Ondersteuning voor Aspell en Ispell is te vinden in de respectievelijke +architectuuronafhankelijke Debianpakketten +[aspell-nl](https://packages.debian.org/stable/aspell-nl) en +[idutch](https://packages.debian.org/stable/idutch). Sinds 2011 wordt MySpell +niet meer ondersteund. + +## Toetsenbord + +Voor Android is er een toetsenbord dat gebruik maakt van de woordenlijst van +OpenTaal. Zie dit +[artikel](https://www.opentaal.org/het-laatste-nieuws/projectnieuws/51-publicaties/221-anysoftkeyboard) +op onze website voor meer informatie. + +## Wordfeud + +Of een woord wel of niet wordt geaccepteerd in Wordfeud of bepaalde andere +woordspellen is niet de verantwoordelijkheid van Stichting OpenTaal. Hiervoor +kan het beste contact opgenomen worden met [TaalTik](https://taaltik.nl). + +## Draag bij + +Help ons vrije en open Nederlandse schrijftools te ontwikkelen. Doneer +belastingvrij aan onze ANBI via https://www.opentaal.org/vrienden-van-opentaal +of contacteer ons als je woordenlijsten of databasevaardigheden te bieden hebt. + +## Zie ook + +- https://bugzilla.redhat.com/show_bug.cgi?id=1912135 + +# Dutch spelling checker + +This is the Dutch spell checker by [Stichting OpenTaal](https://www.opentaal.org). +As long as full attribution is provided and the licenses are respected, this +spell checker can be used freely. The exact conditions can be found in the file +[LICENSE.txt](LICENSE.txt). Please, read these carefully. + +![logo Stichting OpenTaal](images/logo-shape-white-640x360.png?raw=true) + +This spell checker is based on the +[Dutch word list](https://github.com/OpenTaal/opentaal-wordlist) from OpenTaal +This list has received the Quality Mark Spelling +([Keurmerk Spelling](http://taalunieversum.org/inhoud/spelling-meer-hulpmiddelen/keurmerk)) +from the Dutch Language Union ([Taalunie](http://taalunie.org)). This means that +the words in this spell checker conform to the official spelling. + +![logo Keurmerk Spelling](images/keurmerk.png?raw=true) + +Besides using the word list, there has been done a lot of manual editing to +optimize this spelling checker. + +## Contents + +_Please, see the relevant section in Dutch_ + +## Installation + +TODO + +Operating systems offer software packages which install this spelling checker +and update it automatically. Examples of this are: +- [hunspell-nl](https://packages.ubuntu.com/search?keywords=hunspell-nl) for Ubuntu +- [hunspell-nl](https://packages.debian.org/search?keywords=hunspell-nl) for Debian + +For other operating systems, see https://repology.org/project/hunspell-nl/versions + +Support for Aspell and Ispell can be found in the respective +architecture-independent Debian packages +[aspell-nl](https://packages.debian.org/stable/aspell-nl) and +[idutch](https://packages.debian.org/stable/idutch). Since 2011, MySpell is no +longer supported. + +## Keyboard + +A keyboard for Android which uses this word list has been developed. Please, see +this +[article](https://www.opentaal.org/het-laatste-nieuws/projectnieuws/51-publicaties/221-anysoftkeyboard) +on our website for more information. + +## Wordfeud + +Whether or not a word is accepted in the Dutch version of Wordfeud or certain +other Dutch word games is not the responsibility of Stichting OpenTaal. For +this, please contact [TaalTik](https://taaltik.nl). + +## Contribute + +Please, help us create free and open Dutch writing tools. Donate tax free to our +foundation at https://www.opentaal.org/vrienden-van-opentaal or contact us is +you have word lists to database skills to offer. + +## See also + +- https://bugzilla.redhat.com/show_bug.cgi?id=1912135 diff --git a/assets/spelling/licenses/no/COPYING b/assets/spelling/licenses/no/COPYING new file mode 100644 index 00000000..a8cab035 --- /dev/null +++ b/assets/spelling/licenses/no/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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) year + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/assets/spelling/licenses/no/README b/assets/spelling/licenses/no/README new file mode 100644 index 00000000..8d8e5f9e --- /dev/null +++ b/assets/spelling/licenses/no/README @@ -0,0 +1,121 @@ +Norwegian (Bokmål and Nynorsk) spelling dictionaries for LibreOffice +==================================================================== + +Version 3.0 +Maintainer: Lars Bungum + +This package updates the bundled Norwegian dictionaries (dict-no). +It replaces the Hunspell word lists for Norwegian Bokmål (nb-NO) and +Norwegian Nynorsk (nn-NO). Affix files are the existing spell-norwegian +affixes, recoded to UTF-8. Hyphenation patterns and thesauri are +unchanged from the previous dict-no package. + + +Spell-check word lists +---------------------- + +nb_NO.dic 708615 words (Norwegian Bokmål) +nn_NO.dic 540664 words (Norwegian Nynorsk) + +Encoding: UTF-8 (SET UTF-8 in the corresponding .aff files). + + +Sources and licences +-------------------- + +1. Ordbanken (Nasjonalbiblioteket) + + The morphological database Ordbanken was downloaded from + Nasjonalbiblioteket / Språkbanken. Full-form lists were taken out + of that download and used as the bulk of the spelling word lists. + + Licence: CC BY 4.0 — free use with attribution to + Nasjonalbiblioteket. + + https://creativecommons.org/licenses/by/4.0/ + + +2. New headwords from the 2018–2024 revision of Bokmålsordboka and + Nynorskordboka (CLARIN PUB +BY) + + Additional lemmas for Bokmål and Nynorsk were taken from the + nyordslister published after the revision of the two official + dictionaries (2018–2024): + + Bokmål: + https://www.nb.no/sprakbanken/ressurskatalog/oai-repo-clarino-uib-no-11509-152/ + Persistent identifier: http://hdl.handle.net/11509/152 + oai:repo.clarino.uib.no:11509/152 + “Nyordsliste etter revisjonen av Bokmålsordboka (2018–2024)” + + Nynorsk: + https://www.nb.no/sprakbanken/ressurskatalog/oai-repo-clarino-uib-no-11509-151/ + Persistent identifier: http://hdl.handle.net/11509/151 + oai:repo.clarino.uib.no:11509/151 + “Nyordsliste etter revisjon av Nynorskordboka (2018–2024)” + + Distributed by CLARINO Bergen. + + Licence: CLARIN PUB +BY (attribution required) + https://www.kielipankki.fi/wp-content/uploads/CLARIN_PUB_BY_en.html + Persistent identifier: http://urn.fi/urn:nbn:fi:lb-2019071721 + + Acknowledgement: Kultur- og likestillingsdepartementet (KUD) + + +3. «Årets ord» from Språkrådet + + Words of the year and related new-word material were collected + manually from Språkrådet’s public web pages and added to the + merged lists. + + +4. Full-form generation + + Full-form lists for the new lemmas were created according to + Ordbanken’s own code / inflection machinery, so that inflected + forms follow the same patterns as the rest of the dictionary. + + +Affix files, hyphenation, and thesaurus +--------------------------------------- + +nb_NO.aff, nn_NO.aff, hyphenation patterns, and thesauri originate +from the spell-norwegian project and the previous LibreOffice dict-no +package. + + Copyright: The spell-norwegian project + https://alioth.debian.org/projects/spell-norwegian/ + Licence: GNU GPL version 2 (see COPYING) + +The affix files in this update differ from upstream only by encoding: +SET ISO8859-1 was changed to SET UTF-8, and the files were recoded +from ISO-8859-1 to UTF-8 so they match the UTF-8 .dic files. + + +File layout (matches dictionaries/no in dictionaries.git) +--------------------------------------------------------- + + nb_NO.aff / nb_NO.dic Hunspell, locale nb-NO + nn_NO.aff / nn_NO.dic Hunspell, locale nn-NO + hyph_nb_NO.dic hyphenation, locale nb-NO + hyph_nn_NO.dic hyphenation, locale nn-NO + th_nb_NO_v2.dat thesaurus, locale nb-NO + th_nn_NO_v2.dat thesaurus, locale nn-NO + dictionaries.xcu Linguistic configuration + description.xml extension identifier + org.no.openoffice.dictionary.no-NO + + +Attribution summary +------------------- + + Nasjonalbiblioteket — Ordbanken (CC BY 4.0) + CLARINO Bergen / Språkbanken — nyordslister 11509/152 and 11509/151 + (CLARIN PUB +BY) + Kultur- og likestillingsdepartementet (KUD) — acknowledgement for + the dictionary revision resources + Språkrådet — «årets ord» (manually collected from public pages) + The spell-norwegian project — affix files, hyphenation, thesaurus + (GNU GPL v2) + Lars Bungum — merging, full-form generation, UTF-8 packaging diff --git a/assets/spelling/licenses/no/README_NO.txt b/assets/spelling/licenses/no/README_NO.txt new file mode 100644 index 00000000..8d8e5f9e --- /dev/null +++ b/assets/spelling/licenses/no/README_NO.txt @@ -0,0 +1,121 @@ +Norwegian (Bokmål and Nynorsk) spelling dictionaries for LibreOffice +==================================================================== + +Version 3.0 +Maintainer: Lars Bungum + +This package updates the bundled Norwegian dictionaries (dict-no). +It replaces the Hunspell word lists for Norwegian Bokmål (nb-NO) and +Norwegian Nynorsk (nn-NO). Affix files are the existing spell-norwegian +affixes, recoded to UTF-8. Hyphenation patterns and thesauri are +unchanged from the previous dict-no package. + + +Spell-check word lists +---------------------- + +nb_NO.dic 708615 words (Norwegian Bokmål) +nn_NO.dic 540664 words (Norwegian Nynorsk) + +Encoding: UTF-8 (SET UTF-8 in the corresponding .aff files). + + +Sources and licences +-------------------- + +1. Ordbanken (Nasjonalbiblioteket) + + The morphological database Ordbanken was downloaded from + Nasjonalbiblioteket / Språkbanken. Full-form lists were taken out + of that download and used as the bulk of the spelling word lists. + + Licence: CC BY 4.0 — free use with attribution to + Nasjonalbiblioteket. + + https://creativecommons.org/licenses/by/4.0/ + + +2. New headwords from the 2018–2024 revision of Bokmålsordboka and + Nynorskordboka (CLARIN PUB +BY) + + Additional lemmas for Bokmål and Nynorsk were taken from the + nyordslister published after the revision of the two official + dictionaries (2018–2024): + + Bokmål: + https://www.nb.no/sprakbanken/ressurskatalog/oai-repo-clarino-uib-no-11509-152/ + Persistent identifier: http://hdl.handle.net/11509/152 + oai:repo.clarino.uib.no:11509/152 + “Nyordsliste etter revisjonen av Bokmålsordboka (2018–2024)” + + Nynorsk: + https://www.nb.no/sprakbanken/ressurskatalog/oai-repo-clarino-uib-no-11509-151/ + Persistent identifier: http://hdl.handle.net/11509/151 + oai:repo.clarino.uib.no:11509/151 + “Nyordsliste etter revisjon av Nynorskordboka (2018–2024)” + + Distributed by CLARINO Bergen. + + Licence: CLARIN PUB +BY (attribution required) + https://www.kielipankki.fi/wp-content/uploads/CLARIN_PUB_BY_en.html + Persistent identifier: http://urn.fi/urn:nbn:fi:lb-2019071721 + + Acknowledgement: Kultur- og likestillingsdepartementet (KUD) + + +3. «Årets ord» from Språkrådet + + Words of the year and related new-word material were collected + manually from Språkrådet’s public web pages and added to the + merged lists. + + +4. Full-form generation + + Full-form lists for the new lemmas were created according to + Ordbanken’s own code / inflection machinery, so that inflected + forms follow the same patterns as the rest of the dictionary. + + +Affix files, hyphenation, and thesaurus +--------------------------------------- + +nb_NO.aff, nn_NO.aff, hyphenation patterns, and thesauri originate +from the spell-norwegian project and the previous LibreOffice dict-no +package. + + Copyright: The spell-norwegian project + https://alioth.debian.org/projects/spell-norwegian/ + Licence: GNU GPL version 2 (see COPYING) + +The affix files in this update differ from upstream only by encoding: +SET ISO8859-1 was changed to SET UTF-8, and the files were recoded +from ISO-8859-1 to UTF-8 so they match the UTF-8 .dic files. + + +File layout (matches dictionaries/no in dictionaries.git) +--------------------------------------------------------- + + nb_NO.aff / nb_NO.dic Hunspell, locale nb-NO + nn_NO.aff / nn_NO.dic Hunspell, locale nn-NO + hyph_nb_NO.dic hyphenation, locale nb-NO + hyph_nn_NO.dic hyphenation, locale nn-NO + th_nb_NO_v2.dat thesaurus, locale nb-NO + th_nn_NO_v2.dat thesaurus, locale nn-NO + dictionaries.xcu Linguistic configuration + description.xml extension identifier + org.no.openoffice.dictionary.no-NO + + +Attribution summary +------------------- + + Nasjonalbiblioteket — Ordbanken (CC BY 4.0) + CLARINO Bergen / Språkbanken — nyordslister 11509/152 and 11509/151 + (CLARIN PUB +BY) + Kultur- og likestillingsdepartementet (KUD) — acknowledgement for + the dictionary revision resources + Språkrådet — «årets ord» (manually collected from public pages) + The spell-norwegian project — affix files, hyphenation, thesaurus + (GNU GPL v2) + Lars Bungum — merging, full-form generation, UTF-8 packaging diff --git a/assets/spelling/licenses/no/README_hyph_NO.txt b/assets/spelling/licenses/no/README_hyph_NO.txt new file mode 100644 index 00000000..16666337 --- /dev/null +++ b/assets/spelling/licenses/no/README_hyph_NO.txt @@ -0,0 +1,12 @@ +Myspell hyphenation +------------------- + +Language: Norwegian Nynorsk (nn NO) +Language: Norwegian Bokmål (nb NO) +Origin: Generated from the spell-norwegian source v2.0.7 +License: GNU General Public license +Author: The spell-norwegian project, + +HYPH nn NO nn_NO +HYPH nb NO nb_NO + diff --git a/assets/spelling/licenses/pl_PL/README_en.txt b/assets/spelling/licenses/pl_PL/README_en.txt new file mode 100644 index 00000000..aa60cd78 --- /dev/null +++ b/assets/spelling/licenses/pl_PL/README_en.txt @@ -0,0 +1,65 @@ +Spellchecker +------------ + +This dictionary for spell-checking Polish texts is licensed under +GPL, LGPL, MPL (Mozilla Public License), Apache 2.0 and Creative Commons +ShareAlike licenses (see http://creativecommons.org/licenses/sa/1.0). + +This version of the dictionary was generated on 2017-05-14 +The most up-to-date version can be found at: +http://www.sjp.pl/slownik/en/ + +Dictionary maintainer: Marek Futrega (futrega@gmail.com) + +Thesaurus +---------- + +Copyright (C) 2014-2017 Dobry słownik +Copyright (C) 2004-2014 Marcin Miłkowski +This product is made available subject to the terms of GNU Lesser +General Public License Version 2.1. + +Generated on 2017.05.07. +Homepage: http://dobryslownik.pl + +Hyphenation dictionary +---------------------- + +Language: Polish (pl PL). +Origin: Based on the TeX hyphenation patterns plhyph.tex, +version 3.0a, Wednesday, May 17th, 1995 + +The original file is in CTAN archives, for example here: + +http://ctan.binkerton.com/ctan.readme.php?filename=language/polish/plhyph.tex + +and is licensed under LPPL. + +The first version of the patterns was developed +by Hanna Kołodziejska (1987). + +The adaptation to the LeX format (see below) and extensive modification +were done by Bogusław Jackowski & Marek Ryćko (1987--1989). + +The hyphenation rules were further improved and adapted to the +TeX 3.x requirements by Hanna Kołodziejska (1991). + +Lone-standing version (3.0a) of patterns was prepared (under pressure +from LaTeX users) by Bogusław Jackowski and Marek Ryćko, following +Mariusz Olko's suggestions, 1995. + +The LeX format mentioned above was the first version of the adaptation +of TeX to the Polish language. The next version is called MeX. + +The original macro file plhyph.tex belongs to the public domain +under the conditions specified by the author of TeX: + + ``Macro files like PLAIN.TEX should not be changed in any way, + except with respect to preloaded fonts, + unless the changes are authorized by the authors of the macros.'' + + Donald E. Knuth +License OpenOffice.org Adaptions of this package are licensed under the + GNU LGPL license. +Author: conversion and corrects author is + Artur Polaczyński diff --git a/assets/spelling/licenses/pl_PL/README_pl.txt b/assets/spelling/licenses/pl_PL/README_pl.txt new file mode 100644 index 00000000..04e81dec --- /dev/null +++ b/assets/spelling/licenses/pl_PL/README_pl.txt @@ -0,0 +1,542 @@ +Korektor pisowni +---------------- + +Niniejszy slownik do sprawdzania pisowni jest udostepniany na licencjach +GPL, LGPL, MPL (Mozilla Public License), Apache 2.0 i Creative Commons +ShareAlike (zobacz http://creativecommons.org/licenses/sa/1.0). + +Data utworzenia tej wersji slownika: 2017-05-14 +Najnowsza wersje mozna pobrac ze strony: +http://www.sjp.pl/ + +Opiekun slownika: Marek Futrega (futrega@gmail.com) + +Słownik synonimów +----------------- + +Copyright (C) 2014-2017 Dobry słownik +Copyright (C) 2004-2014 Marcin Miłkowski +Licencja: LGPL 2.1. + +Wersja wygenerowana automatycznie dnia 2017.05.07; +Strona główna: http://dobryslownik.pl + +Wzorce podziału wyrazów +----------------------- +Licencja: LGPL 2.1, wersja pierwotna dostępna na zasadach public domain. + +Oparte na danych z pakietu TeX: plhyph.tex, +wersja 3.0a, 17.05.1995 +Pierwsza wersja - Hanna Kołodziejska (1987). +Adaptacja do formatu LeX i duże zmiany: Bogusław Jackowski & Marek Ryćko (1987-1989). +Dalsze poprawki - Hanna Kołodziejska (1991). +Wersja samodzielna - Bogusław Jackowski i Marek Ryćko, z uwzględnieniem sugestii +Mariusza Olki, 1995. +Konwersja do OOo i poprawki: Artur Polaczyński + +Licencja LGPL 2.1 +----------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/assets/spelling/licenses/pl_PL/README_pl_PL.txt b/assets/spelling/licenses/pl_PL/README_pl_PL.txt new file mode 100644 index 00000000..13932d87 --- /dev/null +++ b/assets/spelling/licenses/pl_PL/README_pl_PL.txt @@ -0,0 +1,27 @@ +English: +======== + +This dictionary for spell-checking Polish texts is licensed under +GPL 2, LGPL 2.1, MPL (Mozilla Public License) 1.1, Apache 2.0 and +Creative Commons Attribution 4.0 International + +This version of the dictionary was generated on 2026-05-11 + +https://sjp.pl/sl/en/ + +Contact: sjpslownik@gmail.com + + +Polski: +======= + +Slownik do sprawdzania pisowni jest udostepniany na licencjach +GPL 2, LGPL 2.1, MPL (Mozilla Public License) 1.1, Apache 2.0 i +Creative Commons Attribution 4.0 International + +Data utworzenia tej wersji: 2026-05-11 + +https://sjp.pl + +Contact: sjpslownik@gmail.com + diff --git a/assets/spelling/licenses/pt_BR/README_Lightproof_pt_BR.txt b/assets/spelling/licenses/pt_BR/README_Lightproof_pt_BR.txt new file mode 100644 index 00000000..a8319cab --- /dev/null +++ b/assets/spelling/licenses/pt_BR/README_Lightproof_pt_BR.txt @@ -0,0 +1,7 @@ +Portuguese Brasilian sentence checker for LibreOffice + +(developed by the Lightproof grammar checker extension generator, +see http://launchpad.net/lightproof) + +2013 (c) Raimundo Santos Moura, license: MPL 1.1 / GPLv3+ / LGPLv3+ + diff --git a/assets/spelling/licenses/pt_BR/README_en.txt b/assets/spelling/licenses/pt_BR/README_en.txt new file mode 100644 index 00000000..bfc16998 --- /dev/null +++ b/assets/spelling/licenses/pt_BR/README_en.txt @@ -0,0 +1,29 @@ +Author: Raimundo Moura + +en-US: This dictionary is under continuous development by Raimundo Moura and his team. It is +licensed under the terms of the GNU Lesser General Public License version 3 (LGPLv3), +as published by the Free Software Foundation, and Mozilla Public License as published by +The Mozilla Foundation. The credits are available at +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ and you can +find new releases at +http://extensions.libreoffice.org + +Copyright (C) 2006 - 2013 by Raimundo Santos Moura + +============ +INTRODUCTION +============ + +The LibreOffice Spell Checker and Hyphenation is a colaborative project developed +by the Brazilian community. +The complete list of participants in this project is at +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + +*********************************************************************** +* This is a dictionary for spell correction and hyphenation for the * +* Brazilian Portuguese language for hunspell. * +* This is a free program and it can be redistributed and/or * +* modified under the terms of the GNU Lesser General Public License * +* (LGPL) version 3 and Mozilla Public License. * +* * +*********************************************************************** diff --git a/assets/spelling/licenses/pt_BR/README_hyph_pt_BR.txt b/assets/spelling/licenses/pt_BR/README_hyph_pt_BR.txt new file mode 100644 index 00000000..d1f76298 --- /dev/null +++ b/assets/spelling/licenses/pt_BR/README_hyph_pt_BR.txt @@ -0,0 +1,1394 @@ +Autor/Author: Raimundo Moura + +pt-BR: Este Divisor de Sílabas está em desenvolvimento por Raimundo Moura. Ele está +licenciado sob os termos da Licença Pública Geral Menor versão 3 (LGPLv3), como +publicado pela Free Software Foundation e pela Mozilla Public License como publicada +pela Mozilla Foundation. Os créditos estão disponíveis em +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ +e você pode encontrar novas versões em +http://extensions.libreoffice.org + +Copyright (C) 2008 - 2013 por/by Raimundo Santos Moura + +======================================================================================== +APRESENTAÇÃO +======================================================================================== + +O Projeto DivSilab do LibreOffice é um projeto +colaborativo desenvolvido pela comunidade Brasileira. +A relação completa dos colaboradores deste projeto está em: +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + +O DivSilab é uma ferramenta para realizar a translineação de textos. +Ele divide a palavra silabicamente, ficando parte no final da linha e o restante no início +da linha inferior. +====================== +SOBRE ESTA ATUALIZAÇÃO +====================== +Versão 1.0.8 DivSilab +Retirada de duplicadas: +1n2â +1s2â +1t2â +1x2â +1z2â +Inclusão de: +1s2õ (pro.vi.sões) +Colaboração Adriano Konzen. + +Inclusão/alteração de: +2e4as. +2e4os. (alterado de 2eos.) +1n2ú (alterado de 1n3ú) +1b2â re.tum.bân.cia +1c2â al.cân.ta.ra +1d2â a.bun.dân.cia +1f2â al.fân.de.ga +1g2â a.mal.gâ.mi.co +1j2ô em.jô.o +1m2â ger.mâ.ni.co +1p2â cam.pâ.nu.la +1p2è am.pè.re +1r2â ce.râ.mi.ca +1v2â gal.vâ.ni.co +1x2ú lu.xú.ria +Colaboração Adriano Konzen. + +Inclusão de: +e1â pre.âm.bu.lo - o.ce.â.ni.co +h2â bri.lhâ.ncia +i1â di.â.me.tro +1j2â ca.jâ.nea +a3ô fa.ra.ô.ni.co +o3ô al.co.ô.me.tro +u3ô va.cu.ô.me.tro + +Para corrigir separação de psi inclusão de: +a3p2s2i1c +o2p3s2i1c +a3p2s2i1q +o2p3s2i1q +á2p3s2i +é2p3s2i +í2p3s2i +ó2p3s2i +2p1s2i +.p2s2i + + +â1n2a +â2n1c +â2n1d +â1n2e +â2n1f +â2n1g +â1n2h +â1n2i +â2n1j +â2n1n +â1n2o +â2n1q +â2n1r +â2n1s2i +â2n1s2e +â2n4s1c +â2n4s1f +â2n1t +â1n2u +â2n1v +â2n1z + +Inclusão de regras para palavras acentuadas terminadas em io e ia + +2á1b2i4a +2á1c2i4a +2á1d2i4a +2á1f2i4a +2á1g2i4a +2á1l2i4a +2á1p2i4a +2á1r2i4a +2á1s2i4a +2á1t2i4a +2á1v2i4a +2á1x2i4a +2á1z2i4a +2â1m2i4a +2â1n2i4a +2é1b2i4a +2é1c2i4a +2é1d2i4a +2é1f2i4a +2é1g2i4a +2é1l2i4a +2é1n2i4a +2é1p2i4a +2é1r2i4a +2é1s2i4a +2é1t2i4a +2é1v2i4a +2é1x2i4a +2é1y2i4a +2é1z2i4a +2ê1m2i4a +2ê1n2i4a +2í1b2i4a +2í1c2i4a +2í1d2i4a +2í1f2i4a +2í1g2i4a +2í1j2i4a +2í1l2i4a +2í1m2i4a +2í1n2i4a +2í1p2i4a +2í1r2i4a +2í1s2i4a +2í1t2i4a +2í1v2i4a +2í1x2i4a +2í1z2i4a +2ó1b2i4a +2ó1c2i4a +2ó1d2i4a +2ó1f2i4a +2ó1g2i4a +2ó1j2i4a +2ó1l2i4a +2ó1p2i4a +2ó1r2i4a +2ó1s2i4a +2ó1t2i4a +2ó1v2i4a +2ó1x2i4a +2ó1z2i4a +2ô1d2i4a +2ô1m2i4a +2ô1n2i4a +2ú1b2i4a +2ú1c2i4a +2ú1d2i4a +2ú1f2i4a +2ú1g2i4a +2ú1l2i4a +2ú1m2i4a +2ú1n2i4a +2ú1p2i4a +2ú1r2i4a +2ú1s2i4a +2ú1v2i4a +2ú1x2i4a +2ú1z2i4a +2á1b2i4o +2á1c2i4o +2á1d2i4o +2á1f2i4o +2á1g2i4o +2á1l2i4o +2á1n2i4o +2á1p2i4o +2á1r2i4o +2á1s2i4o +2á1t2i4o +2á1v2i4o +2á1x2i4o +2á1z2i4o +2â1m2i4o +2â1n2i4o +2é1b2i4o +2é1c2i4o +2é1d2i4o +2é1f2i4o +2é1g2i4o +2é1l2i4o +2é1n2i4o +2é1p2i4o +2é1r2i4o +2é1s2i4o +2é1t2i4o +2é1v2i4o +2é1x2i4o +2é1z2i4o +2ê1m2i4o +2ê1n2i4o +2ê1s2i4o +2í1b2i4o +2í1c2i4o +2í1d2i4o +2í1f2i4o +2í1g2i4o +2í1l2i4o +2í1m2i4o +2í1n2i4o +2í1p2i4o +2í1r2i4o +2í1s2i4o +2í1t2i4o +2í1v2i4o +2í1z2i4o +2ó1b2i4o +2ó1c2i4o +2ó1d2i4o +2ó1f2i4o +2ó1g2i4o +2ó1l2i4o +2ó1m2i4o +2ó1p2i4o +2ó1r2i4o +2ó1s2i4o +2ó1t2i4o +2ó1v2i4o +2ó1x2i4o +2ó1z2i4o +2ô1d2i4o +2ô1m2i4o +2ô1n2i4o +2ú1b2i4o +2ú1c2i4o +2ú1d2i4o +2ú1f2i4o +2ú1g2i4o +2ú1j2i4o +2ú1l2i4o +2ú1m2i4o +2ú1n2i4o +2ú1p2i4o +2ú1r2i4o +2ú1s2i4o +2ú1t2i4o +2ú1v2i4o +2ú1z2i4o +2á4i1b2i4a +2â4m1b2i4a +2é4b1b2i4a +2é4r1b2i4a +2é4s1b2i4a +2í4l1b2i4a +2í4m1b2i4a +2í4r1b2i4a +2ó4b1b2i4a +2ô4m1b2i4a +2ó4s1b2i4a +2ú4m1b2i4a +2á4l1c2i4a +2â4n1c2i4a +2á4r1c2i4a +2á4u1c2i4a +2ê4n1c2i4a +2é4p1c2i4a +2é4r1c2i4a +2é4s1c2i4a +2ê4u1c2i4a +2í4l1c2i4a +2í4n1c2i4a +2í4r1c2i4a +2í4s1c2i4a +2ó4l1c2i4a +2ô4n1c2i4a +2ó4r1c2i4a +2ó4s1c2i4a +2ú4n1c2i4a +2ú4p1c2i4a +2ú4r1c2i4a +2á4b1d2i4a +2á4g1d2i4a +2á4l1d2i4a +2â4n1d2i4a +2á4r1d2i4a +2á4u1d2i4a +2ê4i1d2i4a +2é4l1d2i4a +2ê4n1d2i4a +2é4r1d2i4a +2í4l1d2i4a +2í4n1d2i4a +2ó4l1d2i4a +2ô4l1d2i4a +2ô4n1d2i4a +2ó4r1d2i4a +2ú4l1d2i4a +2ú4n1d2i4a +2ú4r1d2i4a +2â4n1f2i4a +2á4r1f2i4a +2é4l1f2i4a +2ó4l1f2i4a +2ô4n1f2i4a +2ó4r1f2i4a +2ú4l1f2i4a +2á4i1g2i4a +2á4l1g2i4a +2â4n1g2i4a +2á4r1g2i4a +2é4r1g2i4a +2í4n1g2i4a +2ô4n1g2i4a +2ó4r1g2i4a +2ú4n1g2i4a +2ú4r1g2i4a +2á1c4h2i4a +2á1l4h2i4a +2â1n4h2i4a +2é1c4h2i4a +2é4t1h2i4a +2í4g1h2i4a +2ô1n4h2i4a +2ú1c4h2i4a +2á1c4l2i4a +2á1g4l2i4a +2á4l1l2i4a +2á4r1l2i4a +2á4u1l2i4a +2é4l1l2i4a +2é4s1l2i4a +2é1t4l2i4a +2ê4u1l2i4a +2í1b4l2i4a +2í1c4l2i4a +2ó1g4l2i4a +2ó1p4l2i4a +2ô4u1l2i4a +2á4l1m2i4a +2á4r1m2i4a +2á4s1m2i4a +2á4u1m2i4a +2ê4i1m2i4a +2é4l1m2i4a +2é4r1m2i4a +2é4s1m2i4a +2ê4s1m2i4a +2í4m1m2i4a +2í4s1m2i4a +2ô4l1m2i4a +2ó4r1m2i4a +2ó4s1m2i4a +2á4f1n2i4a +2á4g1n2i4a +2â4g1n2i4a +2â4i1n2i4a +2â4m1n2i4a +2â4n1n2i4a +2á4u1n2i4a +2é4g1n2i4a +2ê4i1n2i4a +2é4r1n2i4a +2í4g1n2i4a +2í4m1n2i4a +2í4r1n2i4a +2ó4c1n2i4a +2ó4d1n2i4a +2ó4l1n2i4a +2ó4r1n2i4a +2ó4t1n2i4a +2ú4r1n2i4a +2á4l1p2i4a +2â4m1p2i4a +2á4p1p2i4a +2á4r1p2i4a +2é4r1p2i4a +2í4m1p2i4a +2í4p1p2i4a +2ó4r1p2i4a +2ó4s1p2i4a +2ú4l1p2i4a +2ú4p1p2i4a +2á1b4r2i4a +2á1c4r2i4a +2á1d4r2i4a +2á1f4r2i4a +2á1g4r2i4a +2â4n1r2i4a +2á4r1r2i4a +2á1t4r2i4a +2á4u1r2i4a +2é1b4r2i4a +2é1d4r2i4a +2é1f4r2i4a +2é4r1r2i4a +2é1t4r2i4a +2ê4u1r2i4a +2í1c4r2i4a +2í1d4r2i4a +2í1p4r2i4a +2í1t4r2i4a +2ó1d4r2i4a +2ó1f4r2i4a +2ô4i1r2i4a +2ó1p4r2i4a +2ó4r1r2i4a +2ó1t4r2i4a +2ô4u1r2i4a +2ú1g4r2i4a +2ú4r1r2i4a +2ú1t4r2i4a +2á4i1s2i4a +2â4n1s2i4a +2á4p1s2i4a +2á4r1s2i4a +2á4s1s2i4a +2á4t1s2i4a +2á4u1s2i4a +2é4l1s2i4a +2ê4n1s2i4a +2é4p1s2i4a +2é4r1s2i4a +2é4s1s2i4a +2é4t1s2i4a +2ê4y1s2i4a +2í4n1s2i4a +2í4p1s2i4a +2í4s1s2i4a +2í4t1s2i4a +2ô4n1s2i4a +2ó4p1s2i4a +2ó4r1s2i4a +2ó4s1s2i4a +2ô4u1s2i4a +2ú4c1s2i4a +2ú4n1s2i4a +2ú4s1s2i4a +2á4c1t2i4a +2á4l1t2i4a +2â4n1t2i4a +2á4p1t2i4a +2á4r1t2i4a +2á4s1t2i4a +2á4t1t2i4a +2é4c1t2i4a +2é4d1t2i4a +2ê4n1t2i4a +2é4r1t2i4a +2é4s1t2i4a +2é4t1t2i4a +2í4c1t2i4a +2í4d1t2i4a +2í4f1t2i4a +2í4n1t2i4a +2í4p1t2i4a +2í4s1t2i4a +2ô4n1t2i4a +2ó4r1t2i4a +2ó4s1t2i4a +2ó4t1t2i4a +2ú4r1t2i4a +2ú4s1t2i4a +2á1g4u2i4a +2á1q4u2i4a +2é1g4u2i4a +2é1q4u2i4a +2í1q4u2i4a +2ó1q4u2i4a +2ú1q4u2i4a +2á4l1v2i4a +2á4u1v2i4a +2é4r1v2i4a +2í4l1v2i4a +2ó4r1v2i4a +2á4r1x2i4a +2á4u1x2i4a +2â4u1x2i4a +2ê4i1x2i4a +2á4r1z2i4a +2ê4n1z2i4a +2é4t1z2i4a +2í4t1z2i4a +2ó4l1z2i4a +2ô4l1z2i4a +2ô4n1z2i4a +2ó4t1z2i4a +2ó4z1z2i4a +2â4m1b2i4o +2á4r1b2i4o +2é4r1b2i4o +2é4s1b2i4o +2í4m1b2i4o +2ô4m1b2i4o +2ó4r1b2i4o +2ú4m1b2i4o +2ú4r1b2i4o +2á4l1c2i4o +2â4n1c2i4o +2á4r1c2i4o +2á4s1c2i4o +2á4u1c2i4o +2é4l1c2i4o +2ê4n1c2i4o +2é4r1c2i4o +2é4s1c2i4o +2ê4u1c2i4o +2í4n1c2i4o +2í4p1c2i4o +2í4r1c2i4o +2í4s1c2i4o +2ô4n1c2i4o +2ó4r1c2i4o +2ó4s1c2i4o +2ú4l1c2i4o +2ú4n1c2i4o +2ú4r1c2i4o +2ú4s1c2i4o +2á4b1d2i4o +2â4n1d2i4o +2á4r1d2i4o +2á4u1d2i4o +2ê4i1d2i4o +2ê4n1d2i4o +2í4l1d2i4o +2í4n1d2i4o +2ô4n1d2i4o +2ó4r1d2i4o +2ú4n1d2i4o +2ú4r1d2i4o +2á4r1f2i4o +2é4l1f2i4o +2ê4n1f2i4o +2í4l1f2i4o +2ú4n1f2i4o +2á4l1g2i4o +2â4n1g2i4o +2á4r1g2i4o +2á4s1g2i4o +2é4l1g2i4o +2é4r1g2i4o +2í4n1g2i4o +2ô4n1g2i4o +2ó4r1g2i4o +2ú4r1g2i4o +2á1c4h2i4o +2ó1c4h2i4o +2á1b4l2i4o +2á1c4l2i4o +2á4u1l2i4o +2ê4i1l2i4o +2í1b4l2i4o +2í1c4l2i4o +2í1g4l2i4o +2ó1c4l2i4o +2ó1g4l2i4o +2ó1p4l2i4o +2ú1c4l2i4o +2á4d1m2i4o +2á4g1m2i4o +2á4i1m2i4o +2á4j1m2i4o +2á4l1m2i4o +2á4s1m2i4o +2á4t1m2i4o +2é4l1m2i4o +2é4r1m2i4o +2é4s1m2i4o +2í4s1m2i4o +2ó4c1m2i4o +2ó4l1m2i4o +2ó4r1m2i4o +2ó4s1m2i4o +2á4c1n2i4o +2á4f1n2i4o +2á4g1n2i4o +2â4m1n2i4o +2á4r1n2i4o +2á4u1n2i4o +2é4g1n2i4o +2ê4i1n2i4o +2ê4m1n2i4o +2é4r1n2i4o +2í4c1n2i4o +2í4f1n2i4o +2í4g1n2i4o +2í4m1n2i4o +2í4r1n2i4o +2í4s1n2i4o +2í4t1n2i4o +2ó4d1n2i4o +2ó4g1n2i4o +2ó4r1n2i4o +2ó4s1n2i4o +2ú4b1n2i4o +2ú4r1n2i4o +2á4l1p2i4o +2â4m1p2i4o +2á4r1p2i4o +2á4s1p2i4o +2á4u1p2i4o +2é4s1p2i4o +2í4m1p2i4o +2ó4l1p2i4o +2ó4r1p2i4o +2ó4s1p2i4o +2ú4l1p2i4o +2á4b1r2i4o +2á1c4r2i4o +2á1d4r2i4o +2á1f4r2i4o +2á1g4r2i4o +2á4r1r2i4o +2á4s1r2i4o +2á1t4r2i4o +2á4u1r2i4o +2é1b4r2i4o +2é1d4r2i4o +2é1g4r2i4o +2ê1n4r2i4o +2é1t4r2i4o +2ê4u1r2i4o +2í1b4r2i4o +2í1d4r2i4o +2í1p4r2i4o +2í1t4r2i4o +2ó1b4r2i4o +2ó1c4r2i4o +2ó1f4r2i4o +2ó4h1r2i4o +2ó1p4r2i4o +2ó4r1r2i4o +2ó1t4r2i4o +2ú1b4r2i4o +2ú4h1r2i4o +2ú4r1r2i4o +2ú1t4r2i4o +2á4i1s2i4o +2á4r1s2i4o +2á4s1s2i4o +2á4u1s2i4o +2ê4n1s2i4o +2é4p1s2i4o +2é4r1s2i4o +2é4s1s2i4o +2í4s1s2i4o +2ô4n1s2i4o +2ó4p1s2i4o +2ó4s1s2i4o +2ú4r1s2i4o +2ú4s1s2i4o +2á4c1t2i4o +2â4n1t2i4o +2á4r1t2i4o +2á4s1t2i4o +2é4l1t2i4o +2ê4n1t2i4o +2é4r1t2i4o +2é4s1t2i4o +2í4c1t2i4o +2í4n1t2i4o +2í4p1t2i4o +2í4r1t2i4o +2í4s1t2i4o +2ó4c1t2i4o +2ó4l1t2i4o +2ô4n1t2i4o +2ó4p1t2i4o +2ó4s1t2i4o +2ú4r1t2i4o +2ú4s1t2i4o +2á1q4u2i4o +2é1q4u2i4o +2í1q4u2i4o +2ó1q4u2i4o +2á4l1v2i4o +2â4n1v2i4o +2é4l1v2i4o +2é4r1v2i4o +2í4l1v2i4o +2í4n1v2i4o +2ó4b1v2i4o +2ú4l1v2i4o +2é4l1z2i4o + + + +Versão 1.0.7 DivSilab + +Correção da quebra de sílabas das palavras com 'guin', como: 'seguintes' ERRADO(se-gu-in-tes) +Colaboração Flávio Cardoso; +inclusão das regras: +1g2u4i3n2a +1g2u4i3n2á +1g2u4i2n1c +1g2u4i2n1d +1g2u4i3n2e +1g2u4i3n2é +1g2u4i2n1g +1g2u4i3n2h +1g2u4i3n2i +1g2u4i3n2í +1g2u4i2n1j +1g2u4i3n2o +1g2u4i3n2ó +1g2u4i2n2s +1g2u4i2n1t +1g2u4i3n2u +1g2u4i2n1x + + +Versão 1.0.6 DivSilab + +Correção da quebra de sílabas das palavras com 'br', como: 'vibração' ERRADO(vib-ra-ção) +Colaboração Leandro Dutra; +Correção da quebra de sílabas das palavras com 'psic', como: 'neuropsicologia' ERRADO(neu-rop-si-co-lo-gia) +Colaboração Raimundo; +Correção da quebra de sílabas das palavras com 'uin', como: 'contribuinte' ERRADO(con-tri-buin-te) +Colaboração João Paulo Vinha Bittar; + + + +Versão 1.0.5 DivSilab + +Correção da quebra de sílabas das palavras com 'gn', como: 'incógnito' ERRADO(in-có-g-ni-to) + +Exclusão dos códigos +ó2s3t2 +2g1g2 +2g3s2 +2g1t2 +2m1m2 +1n2ã +2n3c42 +2n3d2 +2n3t2 +2p1p2 +2t3g2 +2d1g2 +2d1d2 +2d1t2 +ó1g2a +ó1g2e +ó1g2i +ó1g2l2 +ó2g3n2 +ó1g2o +ó1g2r2 +ó2g1u +o1g2a +o1g2á +o1g2â +o1g2ã +o2g1b2 +o2g1c2 +o2g1d2 +o1g2e +o1g2é +o1g2ê +o2g1g2 +o1g2i +o1g2í +o1g4l2 +o2g1m2 +o2g1n2 +o1g2o +o1g2ó +o1g2ô +o1g4r2 +o2g1s2 +o2g1t2 +o1g2u +o1g2ú +i1g2a +i1g2á +i1g2â +i1g2ã +i2g1b2 +i2g1d2 +i1g2e +i1g2é +i1g2ê +i2g1g2 +i2g1h2 +i1g2i +i1g2í +i1g4l2 +i2g1m2 +i2g1n2 +i1g2o +i1g2ó +i1g2ô +i1g2õ +i2g1p2 +i1g4r2 +i2g1s2 +i2g1t2 +i1g2u +i1g2ú +i2g1v2 +i1g2y +í1g2a +í2g1d2 +í1g2e +í2g1h2 +í1g2i +í1g4l2 +í2g1m2 +í2g1n2 +í1g2o +í1g4r2 +í1g2u +u1g2a +u1g2á +u1g2â +u1g2ã +u2g1b2 +u2g1d2 +u1g2e +u1g2é +u1g2ê +u2g1g2 +u2g1h2 +u1g2i +u1g2í +u1g4l2 +u2g1m2 +u2g1n2 +u1g2o +u1g2ó +u1g2ô +u1g4r2 +u2g1t2 +u1g2u +u1g2ú +ú1g2a +ú2g1b2 +ú1g2e +ú1g2i +ú1g2o +ú1g4r2 +ú1g2u + +========================================================= +Versão 1.0.4 DivSilab + +Sílabas 'a1rô' estão duplicadas com 'a1rô'. Ignorada! +Sílabas '2a4y3i1' estão duplicadas com '2a4y3i'. Usada '2a4y3i1'! +Sílabas '2a4y3l' estão duplicadas com '2a4yl3'. Concatenada '2a4y3l3'! +Sílabas '1co3ê' estão duplicadas com '1co3ê'. Ignorada! +Sílabas '1co3ê' estão duplicadas com '1co3ê'. Ignorada! +Sílabas '1co3ê' estão duplicadas com '1co3ê'. Ignorada! +Sílabas 'e3r2o1m2a' estão duplicadas com 'e3r2o1m2a'. Ignorada! +Sílabas 'e3r2o1m2e' estão duplicadas com 'e3r2o1m2e'. Ignorada! +Sílabas 'e3r2o1m2i' estão duplicadas com 'e3r2o1m2i'. Ignorada! +Sílabas 'e3r4o2m1n2' estão duplicadas com 'e3r2o2m1n2'. Usada 'e3r4o2m1n2'! +Sílabas 'e3r2o1m2o' estão duplicadas com 'e3r2o1m2o'. Ignorada! +Sílabas 'e3r2o1m2u' estão duplicadas com 'e3r2o1m2u'. Ignorada! +Sílabas 'e3r2o1m2á' estão duplicadas com 'e3r2o1m2á'. Ignorada! +Sílabas 'e3r2o1m2â' estão duplicadas com 'e3r2o1m2â'. Ignorada! +Sílabas 'e3r2o1m2é' estão duplicadas com 'e3r2o1m2é'. Ignorada! +Sílabas 'e3r2o1m2í' estão duplicadas com 'e3r2o1m2í'. Ignorada! +Sílabas 'e3r2o1m2ó' estão duplicadas com 'e3r2o1m2ó'. Ignorada! +Sílabas 'e3r2o1m2ô' estão duplicadas com 'e3r2o1m2ô'. Ignorada! +Sílabas '1lo3w' estão duplicadas com 'l2ow1'. Concatenada '1l2o3w1'! +Sílabas 'o3g2' estão duplicadas com 'o3g2'. Ignorada! +Sílabas 'r2a2i4s.' estão duplicadas com 'r2a2i4s.'. Ignorada! +Sílabas 'r2a3i2s.' estão duplicadas com 'r2a2i4s.'. Concatenada 'r2a3i4s.'! +Sílabas '1rais.' estão duplicadas com 'r2a2i4s.'. Concatenada '1r2a3i4s.'! +Sílabas 'r2a3y' estão duplicadas com 'r2a2y3'. Concatenada 'r2a3y3'! +Sílabas '1ra3ó' estão duplicadas com 'r2a3ó'. Concatenada '1r2a3ó'! +Sílabas '1s2e' estão duplicadas com '1s2e'. Ignorada! +Colaboração Adriano Konzen + +Correção da quebra de sílabas das palavras 'envolvidos' (en-vo-lvi-dos) +substituição de 'o1l2v' por 'o2l1v' +Colaboração João Paulo Vinha Bittar + +Inclusão dos códigos +t3g +1t4h2 +1t2i +1t2í +1t2l4 +2t3m4 +1t3n2 +1t2o +1t2ó +1t2ô +1t2õ4 +1t4r2 +2t3s4 +2t3t4 +1t2u +1t2ú +2t3z +u2a +g4u6á +u1á +q4u6á +u1ã +g4u6ã +q4u6ã +u1b2á +u1b2a +u2b1z2 +u2bl +u1b2â +u2b1n2 +u2b1t2 +u2b1m2 +u2b1j2 +u2b1f2 +u1b2ú +u2b1v2 +u2b1p2 +u2br +u1b2u +u1b2i +u1b2é +u1b2e +u2b1d2 +u1b2ô +u1b2ã +u1b2ó +u2b1g2 +u2b1c2 +u2b1s2 +u2b1q4 +u1b2í +u1b2o +ú3b2 +.s2u4b3s4i6s1 +.s2u4b3s4e6r1 +.s2u4b3s2e1 +.s2u4b3l2i5n4h2 +1s2u4b4s3t2 +.s2u4b5r2 +.s2u4b3n2 +.s2u4b3s2i1 +.s2u4b4s3t2 +.s2u4b4s3c2 +.s2u4b3s2í1 +.s2u4b3m2 +.s2u4b3l2i5m2i3n2 +.s2u4b3l2o5 +.s2u4b3p2 +u1c2á +u1c2o +u1c2í +u1c4h2 +u1c2ú +u1c2u +u1c2ô +u1c2e +u1c2ê +u1c2ã +u2c1n2 +u1c2é +u2c1ç2 +u1c2a +u2c1z2 +u1c2y +u2c1m2 +u1c4r2 +u2c1s2 +u1c2ó +u1c2i +u2c1t2 +u2c1c2 +u1c2â +u1c4l2 +ú3c2 +u3d2 +ú3d2 +u2e +u1é +q4u6é +g4u6é +u1ê +g4u6ê +q4u6ê +u3f2 +u3g2 +ú1g +u2i +u1í +g4u6í +q4u6í +u3j2 +u1l2o +u2l1ç2 +u2l1d2 +u1l2õ4 +u1l2ô +u2l1c2 +u1l2a +u2l1b2 +u2l1p2 +u2l1g2 +u2l1t2 +u1l2e +u2l1q4 +u1l2u +u2l1f2 +u2l1m2 +u2l1l2 +u2l1z2 +u1l2ó +u1l2ã +u1l2â +u2l1s2 +u1l2á +u2l1x2 +u2l1n2 +u1l4h2 +u2l1v2 +u1l2í +u2l1r2 +u1l2ú +u1l2é +u1l2ê +u1l2i +ú2l1m2 +ú2l1v2 +ú1l2u +ú1l2e +ú2l1f2 +ú1l4h2 +ú2l1p2 +ú2l1t2 +ú1l2a +ú2l1g2 +ú1l2o +ú1l2i +ú2l1d2 +ú2l1b2 +ú2l1c2 +u2m1m2 +u1m2é +u2m1t2 +u1m2í +u2m1z2 +u2m1n2 +u1m2a +u1m2â +u1m2i +u2m1h2 +u1m2o +u1m2ó +u1m2ã +u1m2e +u2m1l2 +u1m2á +u2m1b2 +u2m1p2 +u1m2ô +u1m2ú +u1m2ê +u1m2u +ú2m1n2 +ú1m2e +ú1m2a +ú2m1p2 +ú1m2i +ú1m2u +ú2m1b2 +u2n4s1v2 +u2n1l2 +u2n1x2 +u2n1z2 +u2n4s1p2 +u2n1f2 +u2n1t2 +u2n1v2 +u2n4s1f2 +u2n4s1t2 +u2n4s. +u2n4s1d2 +u2n1r2 +u2n1g2 +u2n1s2é +u2n1b2 +u2n1ç2 +u2n1d2 +u2n1s2i +u2n1s2o +u2n1j2 +u2n1k2 +u2n1n2 +u1n2í +u1n2ó +u1n2ú +u1n2i +u1n2é +u1n2e +u1n2ã +u1n2â +u1n2á +u2n1q4 +u1n2a +u2n4s1c2 +u1n2o +u1n2ô +u1n4h2 +u2n1s2e +u1n2u +u2n1c2 +ú1n2i +ú2n1q4 +ú1n2e +ú1n4h2 +ú1n2o +ú2n1d2 +ú2n1z2 +ú1n2a +ú2n1v2 +ú2n1s2i +ú2n1g2 +ú2n3s. +ú2n1c2 +ú2n1j2 +ú2n1f2 +ú1n2u +u2o +2u1ó3 +u3p2 +ú3p2 +u3q4 +u2r1z2 +u2r1j2 +u2r1t2 +u2r3r2 +u1r2ú +u2r1c2 +u2r1s2 +u2r1b2 +u1r2i +u2r1f2 +u1r2a +u1r2ô +u2r1d2 +u1r2õ4 +u1r2í +u1r2e +u2r1n2 +u1r2ó +u1r2á +u1r2â +u1r2o +u2r1h2 +u1r2é +u1r2ê +u1r2ã +u2r1g2 +u2r1q4 +u2r1m2 +u2r1ç2 +u2r1p2 +u2r1k2 +u1r2y +u2r1v2 +u1r2u +u2r1l2 +ú3r2 +u1s2u +u2s1z2 +u2s1q4 +u2s1b2 +u1s4h2 +u2s3s2 +u2s1t2 +u2s1j2 +u2s1n2 +u2s1m2 +u2s1v2 +u2s1g2 +u2s1c2 +u1s2i +u2s1l2 +u1s2o +u1s2á +u1s2ó +u1s2ú +u2s1f2 +u2s1d2 +u1s2a +u1s2é +u1s2í +u1s2ê +u1s2â +u1s2ã +u1s2e +u1s2ô +u2s1p2 +u2s1r2 +ú2s1p2 +ú2s3s2 +ú2s1m2 +ú2s1q4 +ú1s2a +ú2s1t2 +ú2s1n2 +ú1s2o +ú1s2e +ú1s2i +ú2s1c2 +u3t2 +ú3t2 +u3u +u3v2 +ú3v2 +u3x2 +u1z2a +u1z2ã +u1z2o +u1z2ú +u1z2â +u1z2e +u1z2í +u2z1m2 +u2z1b2 +u1z2á +u2z1z2 +u1z2ô +u1z2ê +u2z1l2 +u1z2i +u1z2u +u1z2ó +u1z2é +1v2a +1v2á +1v2ã +1v2e +1v2é +1v2ê +1v2i +1v2í +1v2o +1v2ó +1v2ô +1võe3z +1vões +1v4r2 +1v2u +w2a +1x2a +1x2á +1x2ã +2x3c4 +1x2e +1x2é +1x2ê +1x2i +1x2í +1x2o +1x2ó +1x2ô +2x3p4 +x1s +2x3t4 +1x2u +y2a +1ye +.yer1 +1z2a +1z2á +1z2ã +1z2e +1z2é +1z2ê +1z2i +z4í +1z2o +1z2ó +1z2ô +1z2u +z1z +e1õ2e3z + + +========== + +Versão 1.0.3 DivSilab. Nela foram implementados os seguintes recursos: + +.Inclusão de regras para o par 'eg'. Corrigindo translineação de 'segmento'. +.Inclusão de regras para o par 'ég'. +.Inclusão de regras para o par 'eb'. +.Inclusão de regras para o par 'éb'. +.Inclusão de regras para o par 'ed'. +.Inclusão de regras para o par 'éd'. +.Inclusão de regras para o par 'ef'. +.Inclusão de regras para o par 'éf'. +.Inclusão de regras para os pares: ab, áb, ad, ád, af, áf, ag, ág, ah,aj,ak, at e át. +.Correção de regras para o par 'ob'.Corrigindo translineação de 'problema'. + +======================= +Versões Anteriores + +Versão 1.0.2 DivSilab + +Nesta atualização foi implementado o DivSilab - Divisor de Sílabas do LibreOffice. + +Desenvolvido com base no léxico do VERO, através de análise combinatória, +extraíndo-se os casos reais e descartando-se as condições inexistentes. + +O DivSilab é um arquivo texto. Seu desenvolvimento está baseado no algorítmo de Frank M. Liang. +O algorítimo de Liang usa valores entre 0 e 9 exclui-se o valor 0 (zero), uma vez que está +implícito. Valores ímpares indicam possíveis pontos divisão silábica, e os valores pares +(incluindo 0) indicam pontos que não devem ter divisão. Números mais altos indicam uma maior +magnitude do "melhor" para os números ímpares, e pares uma maior amplitude do "pior". +O ponto (.) indica a extremidade de uma palavra. À esquerda início e à direita término. + +Exemplo: +Examinemos a palavra a baixo. + + Silábicas + +Extraindo-se do arquivo somente as regras envolvidas para a formação desta palavra vamos encontrar: + + s2i + i3l2á + l4á + á1b2 + 3b2i + i1c4 + 3c2a + 2s. + +Compondo teremos: + +obs.: mude a fonte para Courier New para visualizar melhor o exemplo. + +s i l á b i c a s +s2i + l4á + i3l2á + l4á + á1b2 + 3b2i + i1c4 + 3c2a + 2s. +------------------ +s2i3l4á3b2i3c4a2s <--- Resultado +s i-l á-b i-c a s --> si-lá-bi-cas + +Obs.: ao resultado é agregado o maior peso de cada coluna. + + + +Esquema de Liang +-------------------------------------------------- +Descrição Peso Entrada Liang +-------------------------------------------------- +Melhor que abaixo 5 9 +Melhor que abaixo 4 7 +Melhor que abaixo 3 5 +Melhor que abaixo 2 3 +Admissível 1 1 +Evitar 0 0 +Pior que acima -1 2 +Pior que acima -2 4 +Pior que acima -3 6 +Pior que acima -4 8 +-------------------------------------------------- + +No nosso trabalho usamos até o nível 6. +Foram desenvolvidos três pequenos aplicativos. Um para gerar combinações ' ab','ac' ,'ad' +... 'ich', 'ras', etc, etc. +O outro para conferir a existência destas combinações no léxico do VERO, extraindo somente +as válidas e o número de ocorrências de cada uma. +E um terceiro para extrair as regras envolvidas na composição de uma determinada palavra. +Usamos uma planilha no Calc para ordenar e configurar as regras, começando pelas de maior +incidência. As combinações óbvias como 'ca', 'ba', 'pr', dr, bl... +foram rapidamente configuradas ...'c2a', 'b2a', 'p4r', 'd4r', 'b4l' ... +Para os mais complexos, extraímos do Vero todas as palavras contempladas com a combinação +pesquisada, e criamos as regras. Exemplo 'ic' +mICAreta --> i3c2a +frICCionar --> i2c3c4 +mICRo --> i2c3r4 +... diff --git a/assets/spelling/licenses/pt_BR/README_pt_BR.txt b/assets/spelling/licenses/pt_BR/README_pt_BR.txt new file mode 100644 index 00000000..b3b5b26c --- /dev/null +++ b/assets/spelling/licenses/pt_BR/README_pt_BR.txt @@ -0,0 +1,294 @@ +Autor/Author: Raimundo Moura + +pt-BR: Este dicionário está em desenvolvimento por Raimundo Moura e sua equipe. +Ele está licenciado sob os termos da Licença Pública Geral Menor versão 3 (LGPLv3), +como publicado pela Free Software Foundation e pela Mozilla Public License como +publicado pela Mozilla Foundation . Os créditos estão disponíveis em +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ +e você pode encontrar novas versões em + +en-US: This dictionary is under development by Raimundo Moura and his team. It is +licensed under the terms of the GNU Lesser General Public License version 3 (LGPLv3), +as published by the Free Software Foundation and the Mozilla Public License as publishen +by the Mozilla Foundation. Credits are available at +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ +and you can find new releases at + +Copyright (C) 2006 - 2013 por/by Raimundo Santos Moura + +============= +APRESENTAÇÃO +============= + +O Projeto Verificador Ortográfico do LibreOffice é um projeto +colaborativo desenvolvido pela comunidade Brasileira. +A relação completa dos colaboradores deste projeto está em: +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + +*********************************************************************** +* Este é um dicionário para correção ortográfica da língua Portuguesa * +* para o Hunspell. * +* Este programa é livre e pode ser redistribuído e/ou modificado nos * +* termos da GNU Lesser General Public License (LGPL) versão 3 e a * +* Mozilla Public License, como publicado pela Mozilla Foundation. * +* * +*********************************************************************** + +====================== +SOBRE ESTA ATUALIZAÇÃO +====================== +. Inclusão de: autoatualizar, subposição. Colaboração de Vera Cavalcante. +. Inclusão de: assuntor, coassunção, perfurocortocontundente, + perfurocontundente e cortocontundente. Colaboração de João Eduardo Strottmann. +. Inclusão de: macrogotejamento, vertebromuscular, marca-página, + transmídia, policlonal e papainizada. Colaboração de Guilherme Rebecchi. +. Inclusão de: acontecimental, adiministrativo-pedagógico, antivaríola, + apicoamento, archaea, autoanticorpo, autoeliminar, autossubsistência, + balbuciamento, baratíssimo, beijaço, bem-inserido, betacateninas, + bolsa-permanência, burocrato-normativo, camarassauru, cientifização, + classificacional, clínico-cirúrgico, Coca-Cola, coimbrãos, coindexação, + computólogo, cultural-religioso, desmoplasia, desmoplásico, dessaturado, + didático-escolar, diligentíssimo, econômico-produtivo, edifício-escola, + eletrocatalítico, encalacramento, endoscopicamente, endoscopista, enlamaçado, + entelodonte, entoacional, Escola-Modelo, espetacularização, esquadrinhamento, + Étnico-Racial, etno-histórico, etnoconstrucionismo, etnoeducacional, exogeneidade, + extrainstitucional, extraturno, favelão, filosófico-existencial, flutuacional, + geoposicionamento, Governador-Geral, grafocêntrico, greco-árabe, hadrossauro, + hamartomatoso, hiperproliferação, HLA, HRTV, inapercebidamente, interempresarial, + interfrásica, interobservador, intraescolar, intramucoso, intraorganizacional, + linfovascular, linguístico-comunicativo, lógico-abstrato, lógico-analítico, + macro-organização, macroagricultura, macrossetor, macrotendência, + médico-assistencial, médico-dentárias, megapotência, metafunção, metafunção, + micro-organização, micro-RNAs, microabertura, microagricultura, microgestão, + microideologia, microrregulação, microssetor, microtendência, mimivírus, + miniacademia, miniarroz, minicolegiado, minigrão, minipôster, miRNA, mucinoso, + mucosectomia, multientidade, mutaburrassauro, nanocarbono, nanografeno, + nanografeno, não-polipoide, neurorregeneração, Palavras-Chave, pandoravírus, + pinhole, planaridade, planaridade, político-eleitoreira, pré-elaborado, + Pré-Textual, precaríssimo, pseudoempresário, pseudoestratificado, + pseudoinvasão, pseudoinvasivo, pseudoparticipativo, público-comunitário, + punctório, redescontos, semantificar, semiatacadista, semipediculado, + semiqualificação, sino-brasileira, sobrecusto, sociorracial, sódio-enxofre, + subcentro, superdotação, supersistema, tecnoburocrata, teórico-científico, + teórico-descritivo, tipado, toxicofilia, transfobia, transfrásica, + túbulo-viloso, valor-trabalho, valores-trabalhos, webjornalismo. +. Inclusão de: outorgativa, derrelinquir, delitual, ininscritibilidade, + aformalidade e exigir-se-lhe-ia. Colaboração de João Eduardo Strottmann. +. Inclusão de: incidível, Ludwig Wittgenstein e liquidativo. Colaboração + de João Eduardo Strottmann. +. Inclusão de: reestender, desjuridiciza, desjuridicizante, pré-juridicizante, + suspensibilidade, interrompibilidade, irratificável, pré-excluiria, cogentemente + jurislativo, Goldschimidt e prius. Colaboração de João Eduardo Strottmann. +. Inclusão de: extrapetita, ultrapetita e infrapetita. Colaboração de João + Eduardo Strottmann. +. Inclusão de: restricionista. Colaboração de Luyse Moraes Moura. +. Inclusão de: Adolphus, aí-ibiretê, aí-igapó, aí-mirim, aí-pixuna, + aís-ibiretês, aís-igapós, aís-mirins, aís-pixunas, ajudanta, âmago-furado, + âmagos-furados, amalgamamento, amamentamento, amaralista, amargamento, + amatronamento, amatutamento, âmbar-branco, âmbares-brancos, âmbares-grises, + âmbares-mexueiras, âmbares-pardos, âmbares-pretos, âmbares-vegetais, + âmbares-virgens, âmbar-gris, âmbar-mexueira, âmbar-pardo, âmbar-preto, + âmbar-vegetal, âmbar-virgem, atto, Bobbio, centi, Chaïm, deci, Dworkin, + exa, femto, Ford, Hart, Herbert, Immanuel, Lacordaire, Marinoni, mili, + Mitidiero, oxalufã, Perelman, Planck, Ronald, tera, yocto, yotta, + zepto, zetta. Colaboração de João Eduardo Strottmann. +. Inclusão de: saltimbanca e TJDF. Colaboração de João Mac-Cormick. +. Exclusão de: sotopor. Colaboração de João Mac-Cormick. +. Inclusão de: aformal, atecnicamente, Chiovenda, continuabilidade, + desparcialização, desparcializado, dessecencializar, egressibilidade, + elipticamente, essencializar, estoicizar, estritíssimo, explicitude, + extracomércio, indeslocabilidade, inexcetuado, inindividuado, irrevogado, + irrompente, justinianeia, justianeu, personificativo, pertinencial, + pertinencialização, pertinencialmente, Pompônio, pré-excludente, + e superfluamente. Colaboração de João Eduardo Strottmann. +. Inclusão de 'coartífice'. Colaboração e-villela. +. Inclusão de: antiqueda, antroposófico, cavaquinista, hipocontratilidade, + hipocontrátil, hipocortisolismo, hiporético, posológico, pré-festa, + pré-gravidez, pré-lanche e vídeo-histeroscopia. Colaboração de + Eduardo Mundim. +. Inclusão de: Andreas, anteprojetador, anteprojetar, anticretizado, + Antistio, Cincia, evitamento, ficticiamente, Golschmidt, há-o, há-se, + iliteral, incontagiação, iniscritibilidade, milieu, Labeo, Lex, + Lex Cincia, ordinariedade, pertinencialidade, pré-admissão, + pré-eliminação, Próculo, revelatório, sobredireito, supraestatal e + vonThur. Colaboração de João Eduardo Strottmann. +. Inclusão de: aardvark, aileron, baby-doll, Beagle, bitter, charleston, + Colt, copyright, copyleft, curry, Dachshund, Dewar, ecstasy, + factoring, Farad, Faraday, Farads, fortran, gap, garamond, hovercraft, + Laika, laissez-faire, laissez-passer, linguincinha, overbooking, panzer, + pit-bull, pizzaiolo, portland, Reich, riesling, sashimi, sauvignon, + shiatsu, shoyu, Sputinik, stout, sushi, tête-à-tête, time-sharing, + tomahawk, Vernier e waffle. Colaboração de João Eduardo Strottmann. +. Inclusão de: aL, anterocaudal, antimicrossoma, antinucleico, + antinúcleo, apócrina, attolitro, cefalo-occipital, cefaloanterior, + cefalocaudal, cefalolateral, cefalomedial, cefaloumbilical, + cL, daL, depletar, dL, écrina, exalitro, femtolitro, fL, gigalitro, + GL, hiperdenso, hipodenso, hL, kL, laudar, loxocélico, macroalbuminúria, + megalitro, merócrina, mL, musculotendínea, nL, pericaudal, perimedial, + perioccipital, periumbilical, petalitro, pL, pulsoterapia, recaptação, + tendinomuscular, teralitro, uropatia, YL, yL, yoctolitro, yottalitro, + zeptolitro, zettalitro, ZL, zL e µL. Colaboração de Rogerio Luz Coelho. +. Inclusão de: autotutelar, averbalidade, correspectividade, delitualmente, + derrelinquente, desnegociação, desobjetivar, emancipativo, estatalizar, + estatalização, expectativo, inespecificação, inexcessivo, interimístico, + interpersonalidade, intraestatal, invalidamente, Goldschmidt, jurislador, + Licurgo, paraestatalização, participacional, pré-personificação, + privaticidade, pululamento, ratificativo, recepticiedade, reduzinte, + semicheio, Siegfried, transubjetivo, unitemporal, tem-se-lhe, + tendo-se-lhe, tivemo-lo e negar-lho. Colaboração de João Eduardo + Strottmann. +. Inclusão de: anteterminação, codecisão, cominatório, extranegocial, + indestituibilidade, ingressandos, institutivo, intrastatal, + Lessa, membridade e presentativa. Colaboração de João Eduardo + Strottmann. +. Inclusão de: nomofobia e nomofóbico. +. Inclusão de: subtópico, apenamento, eletrofísica, µm, torda-anã, + tordas-anãs, microfonação, microcrustáceo, microangstrom, microelectródio, + microeléctrodo, microelectrômetro, microelectrônico, microgranulita, + microinch, micropegmatite, hemonúcleo, bairro-sede e bairros-sede. + Colaboração de Guilherme Rebecchi. +. Inclusão de: cervicotorácico, glico-hemoglobina e Saramenha. + Colaboração de Eduardo Mundim. +. Correção de cervicodorscostal para cervicodorsocostal. + Colaboração de Eduardo Mundim. +. Inclusão de: caducificante, quejanda, despatrimonializar, Gödel, + imobiliaridade, mobiliaridade, voluptuariedade, Labeão, + parapertinencialidade, insuperponibilidade, absolutilidade, + interadaptação, intromissivo, reclamativa, pré-savigniano, pré-elidida, + Desdêmona, Thoreau, Citrapetita, infrapetita, LINDB, omnes, Mévio + e adulteramento. Colaboração de João Eduardo Strottmann. +. Inclusão de: mandibulado, biorrefino, Anglo-Americano, Ricardão e + bandeide. +. Inclusão de: abacinamento, abalaiamento, abaldeamento, abandalhamento, + abarbetamento, abarticulamento, abasbacamento, abjuramento, + acamponesamento, acamurçamento, acanceramento, aceiramento, + aceramento, aclimamento, acobreamento, açoramento, acordamento, + acutizamento, adaptamento, adernamento, adimento, adomingamento, + adoramento, adquirimento, adubamento, adunamento, afervoramento, + afixamento, afuliginamento, afumamento, afundimento, agabamento, + agomamento, aguiamento, amaduramento, amoldamento, amolgamento, + amontanhamento, amostramento e amuamento. Colaboração de João + Eduardo Strottmann. +. Inclusão de: abaritãos, abelha-irapuá, abelha-irapuã, abelha-rainha, + abóboras-cabaça, abóboras-cabaças, abóboras-carneiras, abóboras-chila, + abóboras-chilas, abóboras-d’água, abóboras-de-coroa, abóboras-do-mato, + abóboras-gila, abóboras-gilas, abóboras-meninas, abóboras-porqueiras, + abrótea-de-três-barbas, âmios-maiores e âmios-vulgares. Colaboração de + João Eduardo Strottmann. + +======================================================= +GRAMATICAL +======================================================= + Colaboradores do Gramatical nesta versão: + João Mac-Cormick, Olivier Halot, João Eduardo Strottmann, Guilherme Rebecchi, + Eduardo Mundim, Luyse M. Moura, Marcos Souza, e-villela e Alexandre Vicenzi. +======================================================= +COMO INSTALAR O VERIFICADOR BRASILEIRO NO LIBREOFFICE +======================================================= + +O VERO vem dentro do pacote de instalação do Português do Brasil do +LibreOffice, como uma extensão de instalação. Ele é automaticamente instalado. + +Caso ele não tenha sido instalado na versão de seu LibreOffice (por exemplo, se sua +versão é de outro idioma) você pode instalá-lo como uma extensão do LibreOffice. +Baixe-o de http://extensions.libreoffice.org + +=================== +DÚVIDAS FREQUENTES +=================== + +Os arquivos foram copiados mas o Verificador não está funcionando. +O Verificador Ortográfico não deve estar configurado corretamente, +isto pode ocorrer por um dos seguintes motivos: + +1- O dicionário provavelmente não está instalado. + +Para se certificar de que está utilizando o idioma correto confira como +estão as informações em: Ferramentas >> Opções >> Configurações de +Idioma >> Idiomas. O item Ocidental deve apresentar o dicionário +selecionado (deve aparecer um logo "Abc" do lado do idioma). + +Se não estiver Português (Brasil) mude para esse idioma. Após +configurado clique em 'OK'. +Feche o LibreOffice, inclusive o Iniciador Rápido, e em seguida reabra-o; + + +2 - O verificador não está configurado para verificar texto ao digitar. +Neste caso confira como estão as informações em: + +(Até a Versão 3.0.X) +Ferramentas >> Opções>> Configurações de Idiomas >> Recursos de Verificação +Ortográfica e, no campo opções deste formulário marque a opção 'Verificar +texto ao digitar'; + +(Versão 3.1 em diante) +Ferramentas >> Opções >> Configurações de Idiomas >> Recursos para redação e, +no campo opções deste formulário marque a opção 'Verificar ortografia ao digitar + + +Novas atualizações estarão disponíveis no site do LibreOffice, na +página do Verificador Ortográfico. +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + + +============ +INTRODUCTION +============ + +The LibreOffice Spell Checker is a colaborative project developed +by the Brazilian community. +The complete list of participants in this project is at +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + +*********************************************************************** +* This is a dictionary for orthography correction for the Portuguese * +* language for Hunspell. * +* This is a free program and it can be redistributed and/or * +* modified under the terms of the GNU Lesser General Public License * +* (LGPL) version 3 and Mozilla Public License. * +* * +*********************************************************************** + +================= +ABOUT THIS UPDATE +================= + +============================================================== +HOW TO INSTALL THE BRAZILIAN SPELL CHECKER IN LIBREOFFICE +============================================================== + +The spell checker is included in the pt-BR packages of LibreOffice and +should install automatically. + +If this is not the case you can install VERO as an extension. Please +downlad it from http://extensions.libreoffice.org + + +========================== +FREQUENTLY ASKED QUESTIONS +========================== + +The files have been copied but the checker is not working. The orthography checker may not be +configured correctly, this may be due to one of the following reasons: + +1- The dictionary is probably not installed. + +To make sure that you are using the right language, check the information at +Ferramentas >> Opções >> Configurações de Idioma >> Idiomas. +The item "Ocidental" must present the selected dictionary (a logo "Abc" should +appear beside the language). +If the language selected is not "Português (Brasil)" change to this language. +After the configuration is correct, click on 'OK'. +Close BrOffice and the fast start, and open it afterwards; + +2 - The checker is not configured to verify the orthography on typing. For this + +problem, check the information at +"Ferramentas >> Opções >> Configurações de Idiomas >> Recursos de Verificação Ortográfica" +and, in the field "Opções" of this form, check the option ''Verificar texto ao digitar'; + +New updates will be available at the LibreOffice website, on the page of the +Spell Checker. + +http://pt-br.libreoffice.org/projetos/projeto-vero-verificador-ortografico/ + diff --git a/assets/spelling/licenses/pt_BR/license-thes.readme b/assets/spelling/licenses/pt_BR/license-thes.readme new file mode 100644 index 00000000..b6bf70a0 --- /dev/null +++ b/assets/spelling/licenses/pt_BR/license-thes.readme @@ -0,0 +1,34 @@ +/* + * Copyright 2003 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. + * + */ diff --git a/assets/spelling/licenses/ru_RU/README_Lightproof_ru_RU.txt b/assets/spelling/licenses/ru_RU/README_Lightproof_ru_RU.txt new file mode 100644 index 00000000..9c5dbb01 --- /dev/null +++ b/assets/spelling/licenses/ru_RU/README_Lightproof_ru_RU.txt @@ -0,0 +1,7 @@ +Russian grammar checker + +(developed by the Lightproof grammar checker extension generator, +see http://launchpad.net/lightproof) + +2009, 2011, 2012, 2014 (c) Yakov Reztsov , license: MPL 1.1 / GPL / LGPL + diff --git a/assets/spelling/licenses/ru_RU/README_ru_RU.txt b/assets/spelling/licenses/ru_RU/README_ru_RU.txt new file mode 100644 index 00000000..4620b48a --- /dev/null +++ b/assets/spelling/licenses/ru_RU/README_ru_RU.txt @@ -0,0 +1,38 @@ +* Copyright (c) 1997-2008, Alexander I. Lebedev + +Modifications: +------------------------------------------------------------------ +2012-08-24: Laszlo Nemeth (nemeth at numbertext org) +* ru_RU.aff: add TRY line for better suggestions + (fix fdo#35001, reported by sasha.libreoffice at gmail) + +Copyright: +------------------------------------------------------------------ +* Copyright (c) 1997-2008, Alexander I. Lebedev + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* 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. +* Modified versions must be clearly marked as such. +* The name of Alexander I. Lebedev may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. diff --git a/assets/spelling/licenses/ru_RU/README_thes_ru_RU_M_aot_and_v2.txt b/assets/spelling/licenses/ru_RU/README_thes_ru_RU_M_aot_and_v2.txt new file mode 100644 index 00000000..1736d7f3 --- /dev/null +++ b/assets/spelling/licenses/ru_RU/README_thes_ru_RU_M_aot_and_v2.txt @@ -0,0 +1,21 @@ +Thesauri merged 12.06.2020 + + + +New Russian Thesaurus Dictionary (based on AOT) +-------------------------------- +Language: Russian (ru RU) +License: GNU LGPL 2.1 +Based on: http://aot.ru (http://sourceforge.net/projects/seman/) +Origin: Dicts/SrcBinDict/synonyms.txt https://github.com/yakovru/RussianDict/tree/master/Thesaurus +Packager: Yakov Reztsov , 2014 + +Russian Thesaurus Dictionary for OpenOffice.org 2 +------------------------------------------------- + +Language: Russian (ru RU) +License: GNU LGPL +Author: Mikhail Korolyov +Origin: Абрамовъ, Н. Словарь русскихъ синонимовъ и сходныхъ по смыслу выраженiй. Изд. 3-е, доп., Пг., 1911 +Packager: Rail Aliev + diff --git a/assets/spelling/licenses/tr_TR/LICENSE b/assets/spelling/licenses/tr_TR/LICENSE new file mode 100644 index 00000000..d0a1fa14 --- /dev/null +++ b/assets/spelling/licenses/tr_TR/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/assets/spelling/licenses/tr_TR/README.txt b/assets/spelling/licenses/tr_TR/README.txt new file mode 100644 index 00000000..05b54435 --- /dev/null +++ b/assets/spelling/licenses/tr_TR/README.txt @@ -0,0 +1,13 @@ +Hunspell dictionary for Turkish language developed by Turkish Data Depository group +Version 1.1.1 (Dec 30, 2023) + +This dictionary is licensed under MPL 2.0 License. +Original project page https://github.com/tdd-ai/hunspell-tr. + +**Contributors** (alphabetically): + +- Ali Safaya (alisafaya@gmail.com) +- Arda Göktoğan +- Deniz Yuret +- Emirhan Kurtuluş +- Taner Sezer diff --git a/assets/spelling/licenses/uk_UA/README_hyph_uk_UA.txt b/assets/spelling/licenses/uk_UA/README_hyph_uk_UA.txt new file mode 100644 index 00000000..0f06722f --- /dev/null +++ b/assets/spelling/licenses/uk_UA/README_hyph_uk_UA.txt @@ -0,0 +1,23 @@ +% Ukrainian hyphenation patterns. +% Copyright 1998-2002 Maksym Polyakov. +% Released 2002/12/19. +% Please, send bug reports via e-mail: +% polyama@auburn.edu +% +% The rules for myspell hypenation can be found on +% http://lingucomponent.openoffice.org/hyphenator.html +% +% This 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 file 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, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + diff --git a/assets/spelling/licenses/uk_UA/README_th_uk_UA.txt b/assets/spelling/licenses/uk_UA/README_th_uk_UA.txt new file mode 100644 index 00000000..bb7f1cab --- /dev/null +++ b/assets/spelling/licenses/uk_UA/README_th_uk_UA.txt @@ -0,0 +1,10 @@ +This is Ukrainian thesaurus for OpenOffice.org version 1.6.0. + +This thesaurus is based on: +П. М. Деркач, Короткий словник синонімів української мови, Радянська школа, Київ, 1960 +С. Караванський, Пошук українського слова + +Copyright (C) 2009, 2016 + Andriy Rysin + +This thesaurus is licensed under GPL, LGPL and MPL (Mozilla Public License) licenses. diff --git a/assets/spelling/licenses/uk_UA/README_uk_UA.txt b/assets/spelling/licenses/uk_UA/README_uk_UA.txt new file mode 100644 index 00000000..bce4936b --- /dev/null +++ b/assets/spelling/licenses/uk_UA/README_uk_UA.txt @@ -0,0 +1,8 @@ +This is Ukrainian spelling dictionary, thesaurus, and hyphenation rules for LibreOffice.org +that use hunspell as spelling engine and it is based on +dictionary of dict_uk project https://github.com/brown-uk/dict_uk + +oxt package authors: + Andriy Rysin , 2007 — 2017 + +This dictionary is licensed under MPL (Mozilla Public License) 1.1 license. diff --git a/assets/spelling/licenses/vi/LICENSES-en.txt b/assets/spelling/licenses/vi/LICENSES-en.txt new file mode 100644 index 00000000..7a04f8c7 --- /dev/null +++ b/assets/spelling/licenses/vi/LICENSES-en.txt @@ -0,0 +1,13 @@ +VIETNAMESE SPELLCHECKER FOR OPENOFFICE Version 1.0.45 + +Authors: +Ivan Garcia +Nguyễn Xuân Minh + +This spellchecker for OpenOffice was based on the Vietnamese Dictionary list from Proffessor Hồ Ngọc Đức + +Project site: http://code.google.com/p/hunspell-spellcheck-vi/ +OpenOffice in Vietnamese: http://vi.openoffice.org/ + +This spellchecker is released with GPLv2 license +Visit http://www.gnu.org/licenses/ for more information diff --git a/assets/spelling/licenses/vi/LICENSES-vi.txt b/assets/spelling/licenses/vi/LICENSES-vi.txt new file mode 100644 index 00000000..518ba5b3 --- /dev/null +++ b/assets/spelling/licenses/vi/LICENSES-vi.txt @@ -0,0 +1,18 @@ +TỪ ĐIỂN KIỂM TRA CHÍNH TẢ TIẾNG VIỆT CHO OPENOFFICE phiên bản 1.0.45 + +Tác giả: +Ivan Garcia +Nguyễn Xuân Minh + +Từ điển kiểm tra chính tả OpenOffice.org này dựa vào danh sách Từ Điển Tiếng Việt của Hồ Ngọc Đức. + +Trang chủ dự án: http://code.google.com/p/hunspell-spellcheck-vi/ +OpenOffice tiếng Việt: http://vi.openoffice.org/ + +Từ điển kiểm tra chính tả này được phát hành dưới Giấy Phép Công Cộng GNU (GPL) phiên bản 2. +Xem: + +http://www.gnu.org/licenses/ +http://vi.wikisource.org/wiki/GPL + +để tìm thêm thông tin. diff --git a/docs/development/history.md b/docs/development/history.md index 76d13d23..fb338006 100644 --- a/docs/development/history.md +++ b/docs/development/history.md @@ -36,6 +36,45 @@ Copy and cut snapshot the selection before asynchronous publication. Cut deletes only after a successful write and after revalidating the document, active target, and selection. Paste uses the same revalidation and normal one-step undo path. +Live clipboard paste and Clipboard History use one ordered resolver. Editor and +Markdown Source share the same semantic interpretation; only the final inserted +representation differs. Plain-text mode consumes only interoperable text, never +source markup, HTML, rich fragments, or media. Paste revalidates both its target +and, when native image acquisition crosses a second platform boundary, clipboard +identity around asynchronous work. + +Source fragment insertion uses the Markdown serializer's inline entry point, +including block-start and table-cell escaping, without document-level trimming. +Destination source is parsed after modeling the captured replacement: complete +non-paragraph fragments remain blocks, enclosing inline styles are reconciled +within the smallest changed source range, and table-cell serialization is used +only for a selection contained by one cell. Raw/code protection and list or +blockquote continuation apply only to structure that survives the replacement. + +The Source widget is the asynchronous execution shell: it captures and +revalidates the target, prepares assets, commits one edit, restores focus, and +reports Undo and retention. `SourcePasteEngine` is pure planning over an +immutable source snapshot and returns one of ready, try-next, or stop; its ready +result includes the expected source identity, exact replacement bounds, and +final caret. `MarkdownSourceMapper` owns source/logical/semantic projections, +while `MarkdownAstAdapter` remains the ordinary semantic converter. Raw HTML is +converted as one safe parser fragment and gains optional occurrence metadata at +that conversion boundary. Position probes are operation-local and never define +HTML, links, attributes, references, or whitespace classification. + +Inline serialization has one syntax-emission path. Ordinary serialization and +serialization with caret or break provenance differ only in requested output +bookkeeping, so identical content and options must produce byte-identical +source. Standalone HTML-break layout is indexed once per snapshot; retained +breaks keep their own source occurrence, line ending, and container prefix. + +Paste outcomes distinguish insertion, cancellation, stale targets, unsupported +representations, and unavailable targets. Cancellation and staleness terminate +candidate processing. All paste mutations are discrete external-history +transactions and invalidate continuous-typing groups; active IME composition is +checked at entry and again immediately before mutation. Newly published assets +are removed after cancellation or invalidation, while reused assets are kept. + ## Clipboard retention `ClipboardHistoryController` retains successful BusyMark copy/cut payloads and @@ -45,6 +84,14 @@ and byte accounting. The default policy is 100 entries, 64 MiB total payload, and 8 MiB of decoded thumbnails. Deduplication compares every meaningful representation. +The editor adapter that completes a successful paste is the sole retention +owner. Candidate helpers return capture data but never retain it, the history +panel never performs a second write, and the insertion registry only restores +focus. Image-path captures use the immutable bytes returned by ingestion rather +than reopening the original file. Plain-text paste may retain the original +external snapshot after success but never probes richer fields for insertion or +acquires image bytes to enrich it. + The insertion registry exposes only the latest mounted editable surface and uses identity-safe unregistering. An adapter must capture and revalidate its document, revision, mode, selection generation, and target lifetime around asynchronous diff --git a/docs/development/writerside-toc-implementation.md b/docs/development/writerside-toc-implementation.md index a83d34ac..bf153be8 100644 --- a/docs/development/writerside-toc-implementation.md +++ b/docs/development/writerside-toc-implementation.md @@ -10,7 +10,7 @@ parity**; retained safety and integration differences are listed below. The receiving checkout was clean at `c3b53ff` (BusyMark 0.4.2). The named handoff implementation points matched the receiving source; no archive was copied over it. -Flutter 3.47.2 and Dart 3.13.2 were used without upgrading dependencies. +Flutter 3.47.4 and Dart 3.13.2 were used without upgrading dependencies. User decisions: retain BusyMark AI, Git, clipboard, and file commands **after** the Writerside actions; use installed Writerside **2026.07.8925** for undocumented @@ -344,7 +344,7 @@ production controller/services. Only desktop host/theme and persistence services are isolated. Their framework menu fallback is test-only; these checks do not replace or claim a new recording of the native GTK evidence above. -Review verification (Flutter 3.47.2 / Dart 3.13.2): +Review verification (Flutter 3.47.4 / Dart 3.13.2): - Full `flutter test --no-pub --concurrency=2 --file-reporter json:/tmp/busymark-toc-review-full.json`: exit 0, **1,921 passed, 58 optional @@ -404,7 +404,7 @@ remain explicitly documented adaptations. Full original-Writerside parity is not claimed. Translations are BusyMark translations, not verified original JetBrains locale strings. -Verification for this follow-up (Flutter 3.47.2 / Dart 3.13.2): +Verification for this follow-up (Flutter 3.47.4 / Dart 3.13.2): - Full `flutter test --no-pub --concurrency=2 --file-reporter json:/tmp/busymark-title-full.json`: exit 0, **1,938 passed, 58 optional integration skips**; 17 new regressions. diff --git a/docs/history.md b/docs/history.md index 88be4aa9..f9046884 100644 --- a/docs/history.md +++ b/docs/history.md @@ -11,6 +11,10 @@ context menu. Search examines each item's complete text. Select an item and use **Paste** or **Paste as Plain Text**; Enter and double-click also insert the selected item at the latest editable selection. +`Ctrl+Shift+V` invokes that same **Paste as Plain Text** operation in Editor and +Source. It uses only the clipboard's interoperable plain-text representation; +Markdown punctuation and whitespace in that representation remain literal. + BusyMark collects successful copy and cut operations from its editors. Supported content copied in another application is added after it is successfully pasted into BusyMark. Refresh can inspect the current system clipboard without adding @@ -20,7 +24,15 @@ Entries can contain Source selections, BusyMark rich fragments, supported HTML, plain-text alternatives, and images. Rich content retains Markdown structure for insertion between BusyMark editors. Supported external HTML goes through the same safe conversion as an ordinary paste. Image bytes are retained and are -added to a document's assets only when you paste them. +added to a document's assets only when you paste them. A retained local-image +paste therefore keeps working if the original file is later changed or removed. +Cancelling image insertion leaves the document, Undo history, assets, and +Clipboard History unchanged. + +Every accepted paste is one discrete Undo operation, separate from typing just +before and after it. If the destination changes or starts an input-method +composition while clipboard or image work is in progress, BusyMark rejects the +paste instead of redirecting it to the new target. Clipboard History is memory-only and disappears when BusyMark exits. It keeps up to 100 entries and 64 MiB in total, evicting the oldest entries first. An diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index cca3df9b..3ac306b7 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "عرض المزيد من النتائج", "workspaceSearchSkippedFiles": "البحث غير مكتمل. تجاوز حجم هذه الملفات 1 MiB أو تعذّرت قراءتها:", "@@locale": "ar", + "spelling": "الإملاء", + "automaticSpelling": "التدقيق الإملائي التلقائي", + "defaultSpellingLanguage": "لغة الإملاء الافتراضية", + "projectSpellingLanguage": "لغة التدقيق الإملائي للمشروع", + "chooseSpellingLanguage": "اختر لغة الإملاء", + "spellingLanguageUnsetStatus": "اللغة…", + "spellingOffStatus": "التدقيق الإملائي متوقف", + "checkSpelling": "تدقيق الإملاء", + "ignoreSpellingOnce": "تجاهل مرة واحدة", + "ignoreSpellingDocument": "تجاهل الكل في هذا المستند", + "addPersonalSpellingWord": "إضافة إلى القاموس الشخصي", + "addProjectSpellingWord": "إضافة إلى قاموس المشروع", + "inheritSpellingLanguage": "استخدام لغة المشروع أو التطبيق", + "disableDocumentSpelling": "عدم التدقيق الإملائي", + "importSpellingDictionary": "استيراد قاموس", + "personalSpellingDictionary": "القاموس الشخصي", + "projectSpellingDictionary": "قاموس المشروع", + "noSpellingErrors": "لا توجد أخطاء إملائية", + "noSpellingSuggestions": "لا توجد اقتراحات إملائية", + "spellingWordCheckFailed": "تعذّر التحقق من هذه الكلمة", + "spellingCheckFailed": "فشل التدقيق الإملائي", + "spellingCheckIncomplete": "التدقيق الإملائي غير مكتمل", + "spellingDictionaryNotInstalled": "القاموس غير مثبّت", + "spellingDictionaryNotInstalledForLanguage": "قاموس ⁨{dictionary}⁩ غير مثبّت", + "spellingDictionaryNotInstalledWithSize": "غير مثبّت · ⁨{size}⁩", + "spellingDictionaryInstalled": "مثبّت", + "installSpellingDictionary": "تثبيت القاموس", + "removeSpellingDictionary": "إزالة القاموس", + "cancelSpellingDictionaryInstall": "إلغاء تنزيل القاموس", + "retrySpellingDictionaryInstall": "إعادة محاولة تثبيت القاموس", + "spellingDictionaryDownloading": "جارٍ تنزيل ⁨{size}⁩…", + "spellingDictionaryValidating": "جارٍ التحقق من القاموس…", + "spellingDictionaryInstallFailed": "فشل تثبيت القاموس — حدده لإعادة المحاولة", + "spellingDictionaryInstallPrompt": "هل تريد تثبيت ⁨{dictionary}⁩ (⁨{size}⁩)؟ بعد التثبيت، يظل متاحًا دون اتصال حتى تزيله.", + "spellingDictionaryUnavailable": "القاموس غير متاح", + "spellingChecking": "جارٍ التدقيق الإملائي…", "reportIssue": "الإبلاغ عن مشكلة", "feedbackCategory": "الفئة", "feedbackChooseCategory": "اختر فئة", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "التفاف النص", + "wordWrapDescription": "التفاف السطور الطويلة لتلائم عرض المحرر بدلاً من التمرير أفقيًا.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "أزرار التحرير", + "spellingDictionaries": "قواميس التدقيق الإملائي", + "spellingDictionariesDescription": "تثبيت قواميس التدقيق الإملائي وإدارتها", + "settingsDictionariesSectionTitle": "القواميس", + "availableSpellingDictionaries": "القواميس المتاحة", + "customSpellingDictionaries": "القواميس المخصصة", + "spellingDictionaryProblems": "مشكلات القواميس", "settingsWindowSectionTitle": "النافذة", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "الملفات المتأثرة", "renameTopicFileInstead": "تُشتق معرّفات الموضوعات من أسماء ملفاتها. استخدم «إعادة تسمية ملف الموضوع» في جدول المحتويات أو الشريط الجانبي للملفات.", "diagnosticWritersideWebFileNameInvalid": "ينشر المثيل \"{instanceId}\" اسم ملف ويب غير صالح \"{webFileName}\" للموضوع \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "ينشر المثيل \"{instanceId}\" الموضوعين \"{firstTopic}\" و\"{secondTopic}\" باسم \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "ينشر المثيل \"{instanceId}\" الموضوعين \"{firstTopic}\" و\"{secondTopic}\" باسم \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "تم تغيير قاموس التدقيق الإملائي خارجيًا. تم الاحتفاظ بنسخة استرداد." } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 70569cb2..d8e66e47 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Weitere Ergebnisse anzeigen", "workspaceSearchSkippedFiles": "Die Suche ist unvollständig. Diese Dateien sind größer als 1 MiB oder konnten nicht gelesen werden:", "@@locale": "de", + "spelling": "Rechtschreibung", + "automaticSpelling": "Automatische Rechtschreibprüfung", + "defaultSpellingLanguage": "Standardsprache für Rechtschreibung", + "projectSpellingLanguage": "Projektsprache für Rechtschreibung", + "chooseSpellingLanguage": "Rechtschreibsprache auswählen", + "spellingLanguageUnsetStatus": "Sprache…", + "spellingOffStatus": "Rechtschreibung aus", + "checkSpelling": "Rechtschreibung prüfen", + "ignoreSpellingOnce": "Einmal ignorieren", + "ignoreSpellingDocument": "Alle in diesem Dokument ignorieren", + "addPersonalSpellingWord": "Zum persönlichen Wörterbuch hinzufügen", + "addProjectSpellingWord": "Zum Projektwörterbuch hinzufügen", + "inheritSpellingLanguage": "Projekt- oder Anwendungssprache verwenden", + "disableDocumentSpelling": "Rechtschreibung nicht prüfen", + "importSpellingDictionary": "Wörterbuch importieren", + "personalSpellingDictionary": "Persönliches Wörterbuch", + "projectSpellingDictionary": "Projektwörterbuch", + "noSpellingErrors": "Keine Rechtschreibfehler", + "noSpellingSuggestions": "Keine Rechtschreibvorschläge", + "spellingWordCheckFailed": "Dieses Wort konnte nicht geprüft werden", + "spellingCheckFailed": "Rechtschreibprüfung fehlgeschlagen", + "spellingCheckIncomplete": "Rechtschreibprüfung ist unvollständig", + "spellingDictionaryNotInstalled": "Wörterbuch nicht installiert", + "spellingDictionaryNotInstalledForLanguage": "Das Wörterbuch {dictionary} ist nicht installiert", + "spellingDictionaryNotInstalledWithSize": "Nicht installiert · {size}", + "spellingDictionaryInstalled": "Installiert", + "installSpellingDictionary": "Wörterbuch installieren", + "removeSpellingDictionary": "Wörterbuch entfernen", + "cancelSpellingDictionaryInstall": "Wörterbuchdownload abbrechen", + "retrySpellingDictionaryInstall": "Wörterbuchinstallation wiederholen", + "spellingDictionaryDownloading": "{size} werden heruntergeladen…", + "spellingDictionaryValidating": "Wörterbuch wird überprüft…", + "spellingDictionaryInstallFailed": "Wörterbuchinstallation fehlgeschlagen – zum Wiederholen auswählen", + "spellingDictionaryInstallPrompt": "{dictionary} ({size}) installieren? Danach bleibt es offline verfügbar, bis Sie es entfernen.", + "spellingDictionaryUnavailable": "Wörterbuch nicht verfügbar", + "spellingChecking": "Rechtschreibung wird geprüft…", "reportIssue": "Problem melden", "feedbackCategory": "Kategorie", "feedbackChooseCategory": "Kategorie auswählen", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Zeilenumbruch", + "wordWrapDescription": "Lange Zeilen an die Breite des Editors anpassen, anstatt horizontal zu scrollen.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Bearbeitungsschaltflächen", + "spellingDictionaries": "Rechtschreibwörterbücher", + "spellingDictionariesDescription": "Rechtschreibwörterbücher installieren und verwalten", + "settingsDictionariesSectionTitle": "Wörterbücher", + "availableSpellingDictionaries": "Verfügbare Wörterbücher", + "customSpellingDictionaries": "Benutzerdefinierte Wörterbücher", + "spellingDictionaryProblems": "Wörterbuchprobleme", "settingsWindowSectionTitle": "Fenster", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Betroffene Dateien", "renameTopicFileInstead": "Themen-IDs werden aus ihren Dateinamen abgeleitet. Verwenden Sie „Themendatei umbenennen“ im Inhaltsverzeichnis oder in der Seitenleiste „Dateien“.", "diagnosticWritersideWebFileNameInvalid": "Instanz \"{instanceId}\" veröffentlicht den ungültigen Webdateinamen \"{webFileName}\" für das Thema \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Instanz \"{instanceId}\" veröffentlicht sowohl \"{firstTopic}\" als auch \"{secondTopic}\" unter \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Instanz \"{instanceId}\" veröffentlicht sowohl \"{firstTopic}\" als auch \"{secondTopic}\" unter \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Das Rechtschreibwörterbuch wurde extern geändert. Eine Wiederherstellungskopie wurde aufbewahrt." } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ad8aa999..32eb36df 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -600,6 +600,8 @@ "@autoSaveDescription": {"description": "Editor setting description for saving files automatically."}, "wordWrap": "Word wrap", "@wordWrap": {"description": "Word wrap setting label."}, + "wordWrapDescription": "Wrap long lines to fit the editor width instead of scrolling horizontally.", + "@wordWrapDescription": {"description": "Editor setting description for wrapping long lines."}, "editorFontSize": "Editor font size", "@editorFontSize": {"description": "Editor font size setting label."}, "validateOnEdit": "Validate on edit", @@ -634,6 +636,20 @@ "clearGitWorkspaceTrustDescription": "Ask before enabling Git features for previously trusted workspaces.", "@clearGitWorkspaceTrustDescription": {"description": "Settings action description for clearing trusted Git workspaces."}, + "settingsEditingButtonsSectionTitle": "Editing buttons", + "@settingsEditingButtonsSectionTitle": {"description":"Editor-settings section title for editing-button controls."}, + "spellingDictionaries": "Spelling Dictionaries", + "@spellingDictionaries": {"description":"Title for the spelling-dictionary management subpage and its navigation row."}, + "spellingDictionariesDescription": "Install and manage spelling dictionaries", + "@spellingDictionariesDescription": {"description":"Description for the navigation row that opens spelling-dictionary management."}, + "settingsDictionariesSectionTitle": "Dictionaries", + "@settingsDictionariesSectionTitle": {"description":"Editor-settings section title for dictionary management and word-store controls."}, + "availableSpellingDictionaries": "Available Dictionaries", + "@availableSpellingDictionaries": {"description":"Settings group title for downloadable spelling dictionaries."}, + "customSpellingDictionaries": "Custom Dictionaries", + "@customSpellingDictionaries": {"description":"Settings group title for imported spelling dictionaries."}, + "spellingDictionaryProblems": "Dictionary Problems", + "@spellingDictionaryProblems": {"description":"Settings group title for invalid imported spelling dictionaries."}, "settingsWindowSectionTitle": "Window", "@settingsWindowSectionTitle": {"description":"Settings section title for native window behavior."}, "settingsReopenWorkspaceOnStartupTitle": "Reopen previous workspace on startup", @@ -2729,6 +2745,48 @@ "@settingsDaysValue": {"placeholders": {"value": {"type": "int"}}}, "settingsMebibytesValue": "{value} MiB", "@settingsMebibytesValue": {"placeholders": {"value": {"type": "int"}}}, + "spelling": "Spelling", + "automaticSpelling": "Check spelling automatically", + "defaultSpellingLanguage": "Default spelling language", + "projectSpellingLanguage": "Project spelling language", + "chooseSpellingLanguage": "Choose spelling language", + "spellingLanguageUnsetStatus": "Language…", + "@spellingLanguageUnsetStatus": {"description": "Compact document status shown when no spelling language resolves."}, + "spellingOffStatus": "Spelling Off", + "@spellingOffStatus": {"description": "Compact document status shown when spelling is disabled for the document."}, + "checkSpelling": "Check Spelling", + "ignoreSpellingOnce": "Ignore Once", + "ignoreSpellingDocument": "Ignore All in This Document", + "addPersonalSpellingWord": "Add to Personal Dictionary", + "addProjectSpellingWord": "Add to Project Dictionary", + "inheritSpellingLanguage": "Use project or application language", + "disableDocumentSpelling": "Do not check spelling", + "importSpellingDictionary": "Import Dictionary", + "personalSpellingDictionary": "Personal Dictionary", + "projectSpellingDictionary": "Project Dictionary", + "noSpellingErrors": "No spelling errors", + "noSpellingSuggestions": "No spelling suggestions", + "spellingWordCheckFailed": "Could not check this word", + "spellingCheckFailed": "Spelling check failed", + "spellingCheckIncomplete": "Spelling check is incomplete", + "spellingDictionaryNotInstalled": "Dictionary not installed", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} dictionary is not installed", + "@spellingDictionaryNotInstalledForLanguage": {"placeholders": {"dictionary": {"type": "String"}}}, + "spellingDictionaryNotInstalledWithSize": "Not installed · {size}", + "@spellingDictionaryNotInstalledWithSize": {"placeholders": {"size": {"type": "String"}}}, + "spellingDictionaryInstalled": "Installed", + "installSpellingDictionary": "Install dictionary", + "removeSpellingDictionary": "Remove dictionary", + "cancelSpellingDictionaryInstall": "Cancel dictionary download", + "retrySpellingDictionaryInstall": "Retry dictionary installation", + "spellingDictionaryDownloading": "Downloading {size}…", + "@spellingDictionaryDownloading": {"placeholders": {"size": {"type": "String"}}}, + "spellingDictionaryValidating": "Validating dictionary…", + "spellingDictionaryInstallFailed": "Dictionary installation failed — select to retry", + "spellingDictionaryInstallPrompt": "Install {dictionary} ({size})? After installation, it remains available offline until you remove it.", + "@spellingDictionaryInstallPrompt": {"placeholders": {"dictionary": {"type": "String"}, "size": {"type": "String"}}}, + "spellingDictionaryUnavailable": "Dictionary unavailable", + "spellingChecking": "Checking spelling…", "exportInvalidRange": "{field}: enter a number between {minimum} and {maximum}.", "@exportInvalidRange": { "description": "Invalid numeric export setting.", @@ -2743,5 +2801,6 @@ "type": "String" } } - } + }, + "spellingDictionaryRecoveryConflict": "The spelling dictionary changed externally. A recovery copy was preserved." } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 43652c33..b93644a7 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Mostrar más resultados", "workspaceSearchSkippedFiles": "La búsqueda está incompleta. Estos archivos superan 1 MiB o no se pudieron leer:", "@@locale": "es", + "spelling": "Ortografía", + "automaticSpelling": "Revisión ortográfica automática", + "defaultSpellingLanguage": "Idioma ortográfico predeterminado", + "projectSpellingLanguage": "Idioma de corrección ortográfica del proyecto", + "chooseSpellingLanguage": "Elegir idioma ortográfico", + "spellingLanguageUnsetStatus": "Idioma…", + "spellingOffStatus": "Ortografía desactivada", + "checkSpelling": "Revisar ortografía", + "ignoreSpellingOnce": "Ignorar una vez", + "ignoreSpellingDocument": "Ignorar todo en este documento", + "addPersonalSpellingWord": "Añadir al diccionario personal", + "addProjectSpellingWord": "Añadir al diccionario del proyecto", + "inheritSpellingLanguage": "Usar el idioma del proyecto o la aplicación", + "disableDocumentSpelling": "No revisar la ortografía", + "importSpellingDictionary": "Importar diccionario", + "personalSpellingDictionary": "Diccionario personal", + "projectSpellingDictionary": "Diccionario del proyecto", + "noSpellingErrors": "No hay errores ortográficos", + "noSpellingSuggestions": "No hay sugerencias ortográficas", + "spellingWordCheckFailed": "No se pudo comprobar esta palabra", + "spellingCheckFailed": "La revisión ortográfica falló", + "spellingCheckIncomplete": "La revisión ortográfica está incompleta", + "spellingDictionaryNotInstalled": "Diccionario no instalado", + "spellingDictionaryNotInstalledForLanguage": "El diccionario de {dictionary} no está instalado", + "spellingDictionaryNotInstalledWithSize": "No instalado · {size}", + "spellingDictionaryInstalled": "Instalado", + "installSpellingDictionary": "Instalar diccionario", + "removeSpellingDictionary": "Eliminar diccionario", + "cancelSpellingDictionaryInstall": "Cancelar descarga del diccionario", + "retrySpellingDictionaryInstall": "Reintentar instalación del diccionario", + "spellingDictionaryDownloading": "Descargando {size}…", + "spellingDictionaryValidating": "Validando diccionario…", + "spellingDictionaryInstallFailed": "La instalación falló; selecciónelo para reintentar", + "spellingDictionaryInstallPrompt": "¿Instalar {dictionary} ({size})? Tras instalarlo, estará disponible sin conexión hasta que lo elimine.", + "spellingDictionaryUnavailable": "Diccionario no disponible", + "spellingChecking": "Comprobando la ortografía…", "reportIssue": "Informar de un problema", "feedbackCategory": "Categoría", "feedbackChooseCategory": "Elige una categoría", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Ajuste de línea", + "wordWrapDescription": "Ajusta las líneas largas al ancho del editor en lugar de desplazarse horizontalmente.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Botones de edición", + "spellingDictionaries": "Diccionarios ortográficos", + "spellingDictionariesDescription": "Instalar y gestionar diccionarios ortográficos", + "settingsDictionariesSectionTitle": "Diccionarios", + "availableSpellingDictionaries": "Diccionarios disponibles", + "customSpellingDictionaries": "Diccionarios personalizados", + "spellingDictionaryProblems": "Problemas de diccionarios", "settingsWindowSectionTitle": "Ventana", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Archivos afectados", "renameTopicFileInstead": "Los ID de los temas proceden de sus nombres de archivo. Use «Cambiar nombre del archivo de tema» en la tabla de contenido o en la barra lateral Archivos.", "diagnosticWritersideWebFileNameInvalid": "La instancia \"{instanceId}\" publica el nombre de archivo web no válido \"{webFileName}\" para el tema \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "La instancia \"{instanceId}\" publica \"{firstTopic}\" y \"{secondTopic}\" como \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "La instancia \"{instanceId}\" publica \"{firstTopic}\" y \"{secondTopic}\" como \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "El diccionario ortográfico se modificó externamente. Se conservó una copia de recuperación." } diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index cdb6e55b..f129aa47 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Kuva rohkem tulemusi", "workspaceSearchSkippedFiles": "Otsing pole täielik. Need failid on suuremad kui 1 MiB või neid ei saanud lugeda:", "@@locale": "et", + "spelling": "Õigekiri", + "automaticSpelling": "Automaatne õigekirjakontroll", + "defaultSpellingLanguage": "Vaikimisi õigekirjakeel", + "projectSpellingLanguage": "Projekti õigekirjakontrolli keel", + "chooseSpellingLanguage": "Vali õigekirjakeel", + "spellingLanguageUnsetStatus": "Keel…", + "spellingOffStatus": "Õigekirjakontroll väljas", + "checkSpelling": "Kontrolli õigekirja", + "ignoreSpellingOnce": "Eira üks kord", + "ignoreSpellingDocument": "Eira selles dokumendis kõiki", + "addPersonalSpellingWord": "Lisa isiklikku sõnastikku", + "addProjectSpellingWord": "Lisa projekti sõnastikku", + "inheritSpellingLanguage": "Kasuta projekti või rakenduse keelt", + "disableDocumentSpelling": "Ära kontrolli õigekirja", + "importSpellingDictionary": "Impordi sõnastik", + "personalSpellingDictionary": "Isiklik sõnastik", + "projectSpellingDictionary": "Projekti sõnastik", + "noSpellingErrors": "Õigekirjavigu pole", + "noSpellingSuggestions": "Õigekirjasoovitusi pole", + "spellingWordCheckFailed": "Seda sõna ei saanud kontrollida", + "spellingCheckFailed": "Õigekirjakontroll nurjus", + "spellingCheckIncomplete": "Õigekirjakontroll on pooleli", + "spellingDictionaryNotInstalled": "Sõnastik pole installitud", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} sõnastik pole installitud", + "spellingDictionaryNotInstalledWithSize": "Pole installitud · {size}", + "spellingDictionaryInstalled": "Installitud", + "installSpellingDictionary": "Installi sõnastik", + "removeSpellingDictionary": "Eemalda sõnastik", + "cancelSpellingDictionaryInstall": "Katkesta sõnastiku allalaadimine", + "retrySpellingDictionaryInstall": "Proovi sõnastikku uuesti installida", + "spellingDictionaryDownloading": "Allalaadimine: {size}…", + "spellingDictionaryValidating": "Sõnastiku kontrollimine…", + "spellingDictionaryInstallFailed": "Sõnastiku installimine nurjus — uuesti proovimiseks vali see", + "spellingDictionaryInstallPrompt": "Kas installida {dictionary} ({size})? Pärast installimist on see võrguühenduseta saadaval, kuni selle eemaldad.", + "spellingDictionaryUnavailable": "Sõnastik pole saadaval", + "spellingChecking": "Õigekirja kontrollimine…", "reportIssue": "Teata probleemist", "@reportIssue": { "description": "Menu action and dialog title for reporting an issue." @@ -890,6 +926,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Reamurdmine", + "wordWrapDescription": "Murrab pikad read redaktori laiusele, selle asemel et horisontaalselt kerida.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -957,6 +994,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Redigeerimisnupud", + "spellingDictionaries": "Õigekirjasõnastikud", + "spellingDictionariesDescription": "Õigekirjasõnastike installimine ja haldamine", + "settingsDictionariesSectionTitle": "Sõnastikud", + "availableSpellingDictionaries": "Saadaolevad sõnastikud", + "customSpellingDictionaries": "Kohandatud sõnastikud", + "spellingDictionaryProblems": "Sõnastikuprobleemid", "settingsWindowSectionTitle": "Aken", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3789,5 +3833,6 @@ "topicRenameAffectedFiles": "Mõjutatud failid", "renameTopicFileInstead": "Teema ID-d tuletatakse failinimedest. Kasuta sisukorras või failide külgribal käsku „Nimeta teemafail ümber“.", "diagnosticWritersideWebFileNameInvalid": "Eksemplar \"{instanceId}\" avaldab teema \"{topic}\" jaoks sobimatu veebifailinime \"{webFileName}\".", - "diagnosticWritersideWebFileNameCollision": "Eksemplar \"{instanceId}\" avaldab nii \"{firstTopic}\" kui ka \"{secondTopic}\" nimega \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Eksemplar \"{instanceId}\" avaldab nii \"{firstTopic}\" kui ka \"{secondTopic}\" nimega \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Õigekirjasõnastikku muudeti väliselt. Taastekoopia säilitati." } diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 60a8ff7e..a324bdfc 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "نمایش نتایج بیشتر", "workspaceSearchSkippedFiles": "جستجو کامل نیست. حجم این فایل‌ها بیش از 1 MiB است یا خواندن آن‌ها ممکن نبود:", "@@locale": "fa", + "spelling": "املا", + "automaticSpelling": "بررسی خودکار املا", + "defaultSpellingLanguage": "زبان پیش‌فرض بررسی املا", + "projectSpellingLanguage": "زبان غلط‌یابی پروژه", + "chooseSpellingLanguage": "انتخاب زبان املا", + "spellingLanguageUnsetStatus": "زبان…", + "spellingOffStatus": "بررسی املا خاموش", + "checkSpelling": "بررسی املا", + "ignoreSpellingOnce": "یک‌بار نادیده بگیر", + "ignoreSpellingDocument": "همه را در این سند نادیده بگیر", + "addPersonalSpellingWord": "افزودن به واژه‌نامه شخصی", + "addProjectSpellingWord": "افزودن به واژه‌نامه پروژه", + "inheritSpellingLanguage": "استفاده از زبان پروژه یا برنامه", + "disableDocumentSpelling": "املاء بررسی نشود", + "importSpellingDictionary": "درون‌ریزی واژه‌نامه", + "personalSpellingDictionary": "واژه‌نامه شخصی", + "projectSpellingDictionary": "واژه‌نامه پروژه", + "noSpellingErrors": "خطای املایی وجود ندارد", + "noSpellingSuggestions": "پیشنهاد املایی وجود ندارد", + "spellingWordCheckFailed": "بررسی این واژه ممکن نشد", + "spellingCheckFailed": "بررسی املا ناموفق بود", + "spellingCheckIncomplete": "بررسی املا کامل نیست", + "spellingDictionaryNotInstalled": "واژه‌نامه نصب نشده است", + "spellingDictionaryNotInstalledForLanguage": "واژه‌نامهٔ ⁨{dictionary}⁩ نصب نشده است", + "spellingDictionaryNotInstalledWithSize": "نصب‌نشده · ⁨{size}⁩", + "spellingDictionaryInstalled": "نصب‌شده", + "installSpellingDictionary": "نصب واژه‌نامه", + "removeSpellingDictionary": "حذف واژه‌نامه", + "cancelSpellingDictionaryInstall": "لغو بارگیری واژه‌نامه", + "retrySpellingDictionaryInstall": "تلاش دوباره برای نصب واژه‌نامه", + "spellingDictionaryDownloading": "در حال بارگیری ⁨{size}⁩…", + "spellingDictionaryValidating": "در حال اعتبارسنجی واژه‌نامه…", + "spellingDictionaryInstallFailed": "نصب واژه‌نامه ناموفق بود — برای تلاش دوباره انتخاب کنید", + "spellingDictionaryInstallPrompt": "واژه‌نامهٔ ⁨{dictionary}⁩ (⁨{size}⁩) نصب شود؟ پس از نصب تا زمانی که آن را حذف نکنید، آفلاین در دسترس می‌ماند.", + "spellingDictionaryUnavailable": "واژه‌نامه در دسترس نیست", + "spellingChecking": "در حال بررسی املا…", "reportIssue": "گزارش مشکل", "feedbackCategory": "دسته‌بندی", "feedbackChooseCategory": "یک دسته‌بندی انتخاب کنید", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "شکستن خودکار خطوط", + "wordWrapDescription": "سطرهای بلند را به‌جای پیمایش افقی متناسب با عرض ویرایشگر می‌شکند.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "دکمه‌های ویرایش", + "spellingDictionaries": "واژه‌نامه‌های املایی", + "spellingDictionariesDescription": "نصب و مدیریت واژه‌نامه‌های املایی", + "settingsDictionariesSectionTitle": "واژه‌نامه‌ها", + "availableSpellingDictionaries": "واژه‌نامه‌های موجود", + "customSpellingDictionaries": "واژه‌نامه‌های سفارشی", + "spellingDictionaryProblems": "مشکلات واژه‌نامه", "settingsWindowSectionTitle": "پنجره", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3371,5 +3415,6 @@ "topicRenameAffectedFiles": "فایل‌های تحت تأثیر", "renameTopicFileInstead": "شناسه‌های موضوع از نام فایل‌هایشان گرفته می‌شوند. از «تغییر نام فایل موضوع» در فهرست مطالب یا نوار کناری فایل‌ها استفاده کنید.", "diagnosticWritersideWebFileNameInvalid": "نمونهٔ \"{instanceId}\" نام فایل وب نامعتبر \"{webFileName}\" را برای موضوع \"{topic}\" منتشر می‌کند.", - "diagnosticWritersideWebFileNameCollision": "نمونهٔ \"{instanceId}\" هر دو موضوع \"{firstTopic}\" و \"{secondTopic}\" را با نام \"{webFileName}\" منتشر می‌کند." + "diagnosticWritersideWebFileNameCollision": "نمونهٔ \"{instanceId}\" هر دو موضوع \"{firstTopic}\" و \"{secondTopic}\" را با نام \"{webFileName}\" منتشر می‌کند.", + "spellingDictionaryRecoveryConflict": "فرهنگ لغت املایی به‌صورت خارجی تغییر کرد. یک نسخهٔ بازیابی حفظ شد." } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 353e80ff..ac279995 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Afficher plus de résultats", "workspaceSearchSkippedFiles": "La recherche est incomplète. Ces fichiers dépassent 1 MiB ou n’ont pas pu être lus :", "@@locale": "fr", + "spelling": "Orthographe", + "automaticSpelling": "Vérification orthographique automatique", + "defaultSpellingLanguage": "Langue orthographique par défaut", + "projectSpellingLanguage": "Langue de correction du projet", + "chooseSpellingLanguage": "Choisir la langue orthographique", + "spellingLanguageUnsetStatus": "Langue…", + "spellingOffStatus": "Orthographe désactivée", + "checkSpelling": "Vérifier l’orthographe", + "ignoreSpellingOnce": "Ignorer une fois", + "ignoreSpellingDocument": "Tout ignorer dans ce document", + "addPersonalSpellingWord": "Ajouter au dictionnaire personnel", + "addProjectSpellingWord": "Ajouter au dictionnaire du projet", + "inheritSpellingLanguage": "Utiliser la langue du projet ou de l’application", + "disableDocumentSpelling": "Ne pas vérifier l’orthographe", + "importSpellingDictionary": "Importer un dictionnaire", + "personalSpellingDictionary": "Dictionnaire personnel", + "projectSpellingDictionary": "Dictionnaire du projet", + "noSpellingErrors": "Aucune faute d’orthographe", + "noSpellingSuggestions": "Aucune suggestion orthographique", + "spellingWordCheckFailed": "Impossible de vérifier ce mot", + "spellingCheckFailed": "Échec de la vérification orthographique", + "spellingCheckIncomplete": "La vérification orthographique est incomplète", + "spellingDictionaryNotInstalled": "Dictionnaire non installé", + "spellingDictionaryNotInstalledForLanguage": "Le dictionnaire {dictionary} n’est pas installé", + "spellingDictionaryNotInstalledWithSize": "Non installé · {size}", + "spellingDictionaryInstalled": "Installé", + "installSpellingDictionary": "Installer le dictionnaire", + "removeSpellingDictionary": "Supprimer le dictionnaire", + "cancelSpellingDictionaryInstall": "Annuler le téléchargement du dictionnaire", + "retrySpellingDictionaryInstall": "Réessayer l’installation du dictionnaire", + "spellingDictionaryDownloading": "Téléchargement de {size}…", + "spellingDictionaryValidating": "Validation du dictionnaire…", + "spellingDictionaryInstallFailed": "Échec de l’installation — sélectionnez pour réessayer", + "spellingDictionaryInstallPrompt": "Installer {dictionary} ({size}) ? Après installation, il restera disponible hors ligne jusqu’à sa suppression.", + "spellingDictionaryUnavailable": "Dictionnaire indisponible", + "spellingChecking": "Vérification de l’orthographe…", "reportIssue": "Signaler un problème", "feedbackCategory": "Catégorie", "feedbackChooseCategory": "Choisir une catégorie", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Retour à la ligne automatique", + "wordWrapDescription": "Ajuster les lignes longues à la largeur de l’éditeur plutôt que de les faire défiler horizontalement.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Boutons d’édition", + "spellingDictionaries": "Dictionnaires orthographiques", + "spellingDictionariesDescription": "Installer et gérer les dictionnaires orthographiques", + "settingsDictionariesSectionTitle": "Dictionnaires", + "availableSpellingDictionaries": "Dictionnaires disponibles", + "customSpellingDictionaries": "Dictionnaires personnalisés", + "spellingDictionaryProblems": "Problèmes de dictionnaires", "settingsWindowSectionTitle": "Fenêtre", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Fichiers concernés", "renameTopicFileInstead": "Les ID de sujet proviennent de leur nom de fichier. Utilisez « Renommer le fichier de sujet » dans la table des matières ou la barre latérale Fichiers.", "diagnosticWritersideWebFileNameInvalid": "L’instance \"{instanceId}\" publie le nom de fichier web non valide \"{webFileName}\" pour le sujet \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "L’instance \"{instanceId}\" publie \"{firstTopic}\" et \"{secondTopic}\" sous le nom \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "L’instance \"{instanceId}\" publie \"{firstTopic}\" et \"{secondTopic}\" sous le nom \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Le dictionnaire orthographique a été modifié en externe. Une copie de récupération a été conservée." } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index b27c5607..3490fb0a 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "अधिक परिणाम दिखाएँ", "workspaceSearchSkippedFiles": "खोज अधूरी है। ये फ़ाइलें 1 MiB से बड़ी हैं या पढ़ी नहीं जा सकीं:", "@@locale": "hi", + "spelling": "वर्तनी", + "automaticSpelling": "स्वचालित वर्तनी जाँच", + "defaultSpellingLanguage": "डिफ़ॉल्ट वर्तनी भाषा", + "projectSpellingLanguage": "परियोजना की वर्तनी भाषा", + "chooseSpellingLanguage": "वर्तनी भाषा चुनें", + "spellingLanguageUnsetStatus": "भाषा…", + "spellingOffStatus": "वर्तनी बंद", + "checkSpelling": "वर्तनी जाँचें", + "ignoreSpellingOnce": "एक बार अनदेखा करें", + "ignoreSpellingDocument": "इस दस्तावेज़ में सभी अनदेखे करें", + "addPersonalSpellingWord": "निजी शब्दकोश में जोड़ें", + "addProjectSpellingWord": "परियोजना शब्दकोश में जोड़ें", + "inheritSpellingLanguage": "परियोजना या ऐप की भाषा उपयोग करें", + "disableDocumentSpelling": "वर्तनी जाँच न करें", + "importSpellingDictionary": "शब्दकोश आयात करें", + "personalSpellingDictionary": "व्यक्तिगत शब्दकोश", + "projectSpellingDictionary": "परियोजना शब्दकोश", + "noSpellingErrors": "कोई वर्तनी त्रुटि नहीं", + "noSpellingSuggestions": "कोई वर्तनी सुझाव नहीं", + "spellingWordCheckFailed": "इस शब्द की जाँच नहीं हो सकी", + "spellingCheckFailed": "वर्तनी जाँच विफल रही", + "spellingCheckIncomplete": "वर्तनी जाँच अधूरी है", + "spellingDictionaryNotInstalled": "शब्दकोश इंस्टॉल नहीं है", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} शब्दकोश इंस्टॉल नहीं है", + "spellingDictionaryNotInstalledWithSize": "इंस्टॉल नहीं है · {size}", + "spellingDictionaryInstalled": "इंस्टॉल है", + "installSpellingDictionary": "शब्दकोश इंस्टॉल करें", + "removeSpellingDictionary": "शब्दकोश हटाएँ", + "cancelSpellingDictionaryInstall": "शब्दकोश डाउनलोड रद्द करें", + "retrySpellingDictionaryInstall": "शब्दकोश इंस्टॉलेशन फिर आज़माएँ", + "spellingDictionaryDownloading": "{size} डाउनलोड हो रहा है…", + "spellingDictionaryValidating": "शब्दकोश सत्यापित हो रहा है…", + "spellingDictionaryInstallFailed": "शब्दकोश इंस्टॉलेशन विफल — फिर प्रयास करने के लिए चुनें", + "spellingDictionaryInstallPrompt": "{dictionary} ({size}) इंस्टॉल करें? इंस्टॉल होने के बाद यह हटाए जाने तक ऑफ़लाइन उपलब्ध रहेगा।", + "spellingDictionaryUnavailable": "शब्दकोश उपलब्ध नहीं है", + "spellingChecking": "वर्तनी की जाँच हो रही है…", "reportIssue": "समस्या की रिपोर्ट करें", "feedbackCategory": "श्रेणी", "feedbackChooseCategory": "श्रेणी चुनें", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "वर्ड रैप", + "wordWrapDescription": "लंबी पंक्तियों को क्षैतिज रूप से स्क्रॉल करने के बजाय संपादक की चौड़ाई में समेटें।", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "संपादन बटन", + "spellingDictionaries": "वर्तनी शब्दकोश", + "spellingDictionariesDescription": "वर्तनी शब्दकोश इंस्टॉल और प्रबंधित करें", + "settingsDictionariesSectionTitle": "शब्दकोश", + "availableSpellingDictionaries": "उपलब्ध शब्दकोश", + "customSpellingDictionaries": "कस्टम शब्दकोश", + "spellingDictionaryProblems": "शब्दकोश समस्याएँ", "settingsWindowSectionTitle": "विंडो", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "प्रभावित फ़ाइलें", "renameTopicFileInstead": "विषय ID उनके फ़ाइल नामों से बनते हैं। विषय-सूची या फ़ाइलें साइडबार में ‘विषय फ़ाइल का नाम बदलें’ का उपयोग करें।", "diagnosticWritersideWebFileNameInvalid": "इंस्टेंस \"{instanceId}\" विषय \"{topic}\" के लिए अमान्य वेब फ़ाइल नाम \"{webFileName}\" प्रकाशित करता है।", - "diagnosticWritersideWebFileNameCollision": "इंस्टेंस \"{instanceId}\" \"{firstTopic}\" और \"{secondTopic}\" दोनों को \"{webFileName}\" के रूप में प्रकाशित करता है।" + "diagnosticWritersideWebFileNameCollision": "इंस्टेंस \"{instanceId}\" \"{firstTopic}\" और \"{secondTopic}\" दोनों को \"{webFileName}\" के रूप में प्रकाशित करता है।", + "spellingDictionaryRecoveryConflict": "वर्तनी शब्दकोश को बाहरी रूप से बदला गया। पुनर्प्राप्ति प्रति सुरक्षित रखी गई।" } diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index d93051c3..e512d425 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Tampilkan lebih banyak hasil", "workspaceSearchSkippedFiles": "Pencarian belum lengkap. Berkas ini melebihi 1 MiB atau tidak dapat dibaca:", "@@locale": "id", + "spelling": "Ejaan", + "automaticSpelling": "Periksa ejaan secara otomatis", + "defaultSpellingLanguage": "Bahasa ejaan bawaan", + "projectSpellingLanguage": "Bahasa ejaan proyek", + "chooseSpellingLanguage": "Pilih bahasa ejaan", + "spellingLanguageUnsetStatus": "Bahasa…", + "spellingOffStatus": "Ejaan Nonaktif", + "checkSpelling": "Periksa Ejaan", + "ignoreSpellingOnce": "Abaikan Sekali", + "ignoreSpellingDocument": "Abaikan Semua di Dokumen Ini", + "addPersonalSpellingWord": "Tambahkan ke Kamus Pribadi", + "addProjectSpellingWord": "Tambahkan ke Kamus Proyek", + "inheritSpellingLanguage": "Gunakan bahasa proyek atau aplikasi", + "disableDocumentSpelling": "Jangan periksa ejaan", + "importSpellingDictionary": "Impor Kamus", + "personalSpellingDictionary": "Kamus Pribadi", + "projectSpellingDictionary": "Kamus Proyek", + "noSpellingErrors": "Tidak ada kesalahan ejaan", + "noSpellingSuggestions": "Tidak ada saran ejaan", + "spellingWordCheckFailed": "Kata ini tidak dapat diperiksa", + "spellingCheckFailed": "Pemeriksaan ejaan gagal", + "spellingCheckIncomplete": "Pemeriksaan ejaan belum lengkap", + "spellingDictionaryNotInstalled": "Kamus belum terpasang", + "spellingDictionaryNotInstalledForLanguage": "Kamus {dictionary} belum terpasang", + "spellingDictionaryNotInstalledWithSize": "Belum terpasang · {size}", + "spellingDictionaryInstalled": "Terpasang", + "installSpellingDictionary": "Pasang kamus", + "removeSpellingDictionary": "Hapus kamus", + "cancelSpellingDictionaryInstall": "Batalkan unduhan kamus", + "retrySpellingDictionaryInstall": "Coba lagi pemasangan kamus", + "spellingDictionaryDownloading": "Mengunduh {size}…", + "spellingDictionaryValidating": "Memvalidasi kamus…", + "spellingDictionaryInstallFailed": "Pemasangan kamus gagal — pilih untuk mencoba lagi", + "spellingDictionaryInstallPrompt": "Pasang {dictionary} ({size})? Setelah dipasang, kamus tetap tersedia luring sampai Anda menghapusnya.", + "spellingDictionaryUnavailable": "Kamus tidak tersedia", + "spellingChecking": "Memeriksa ejaan…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Pindah baris otomatis", + "wordWrapDescription": "Bungkus baris panjang agar sesuai dengan lebar editor alih-alih menggulir secara horizontal.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Tombol pengeditan", + "spellingDictionaries": "Kamus ejaan", + "spellingDictionariesDescription": "Instal dan kelola kamus ejaan", + "settingsDictionariesSectionTitle": "Kamus", + "availableSpellingDictionaries": "Kamus yang tersedia", + "customSpellingDictionaries": "Kamus kustom", + "spellingDictionaryProblems": "Masalah kamus", "settingsWindowSectionTitle": "Jendela", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "File yang terpengaruh", "renameTopicFileInstead": "ID topik berasal dari nama filenya. Gunakan Ganti Nama File Topik di daftar isi atau bilah samping File.", "diagnosticWritersideWebFileNameInvalid": "Instans \"{instanceId}\" menerbitkan nama file web tidak valid \"{webFileName}\" untuk topik \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Instans \"{instanceId}\" menerbitkan \"{firstTopic}\" dan \"{secondTopic}\" sebagai \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Instans \"{instanceId}\" menerbitkan \"{firstTopic}\" dan \"{secondTopic}\" sebagai \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Kamus ejaan diubah secara eksternal. Salinan pemulihan telah disimpan." } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index c0a5d39a..1dc0d3b0 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Mostra altri risultati", "workspaceSearchSkippedFiles": "La ricerca è incompleta. Questi file superano 1 MiB o non è stato possibile leggerli:", "@@locale": "it", + "spelling": "Ortografia", + "automaticSpelling": "Controllo ortografico automatico", + "defaultSpellingLanguage": "Lingua ortografica predefinita", + "projectSpellingLanguage": "Lingua di controllo ortografico del progetto", + "chooseSpellingLanguage": "Scegli la lingua ortografica", + "spellingLanguageUnsetStatus": "Lingua…", + "spellingOffStatus": "Controllo ortografico disattivato", + "checkSpelling": "Controlla ortografia", + "ignoreSpellingOnce": "Ignora una volta", + "ignoreSpellingDocument": "Ignora tutto in questo documento", + "addPersonalSpellingWord": "Aggiungi al dizionario personale", + "addProjectSpellingWord": "Aggiungi al dizionario del progetto", + "inheritSpellingLanguage": "Usa la lingua del progetto o dell’app", + "disableDocumentSpelling": "Non controllare l’ortografia", + "importSpellingDictionary": "Importa dizionario", + "personalSpellingDictionary": "Dizionario personale", + "projectSpellingDictionary": "Dizionario del progetto", + "noSpellingErrors": "Nessun errore di ortografia", + "noSpellingSuggestions": "Nessun suggerimento ortografico", + "spellingWordCheckFailed": "Impossibile controllare questa parola", + "spellingCheckFailed": "Controllo ortografico non riuscito", + "spellingCheckIncomplete": "Il controllo ortografico è incompleto", + "spellingDictionaryNotInstalled": "Dizionario non installato", + "spellingDictionaryNotInstalledForLanguage": "Il dizionario {dictionary} non è installato", + "spellingDictionaryNotInstalledWithSize": "Non installato · {size}", + "spellingDictionaryInstalled": "Installato", + "installSpellingDictionary": "Installa dizionario", + "removeSpellingDictionary": "Rimuovi dizionario", + "cancelSpellingDictionaryInstall": "Annulla download del dizionario", + "retrySpellingDictionaryInstall": "Riprova l’installazione del dizionario", + "spellingDictionaryDownloading": "Download di {size}…", + "spellingDictionaryValidating": "Convalida del dizionario…", + "spellingDictionaryInstallFailed": "Installazione non riuscita — seleziona per riprovare", + "spellingDictionaryInstallPrompt": "Installare {dictionary} ({size})? Dopo l’installazione resterà disponibile offline finché non verrà rimosso.", + "spellingDictionaryUnavailable": "Dizionario non disponibile", + "spellingChecking": "Controllo ortografico…", "reportIssue": "Segnala un problema", "feedbackCategory": "Categoria", "feedbackChooseCategory": "Scegli una categoria", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "A capo automatico", + "wordWrapDescription": "Adatta le righe lunghe alla larghezza dell’editor invece di scorrerle orizzontalmente.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Pulsanti di modifica", + "spellingDictionaries": "Dizionari ortografici", + "spellingDictionariesDescription": "Installa e gestisci i dizionari ortografici", + "settingsDictionariesSectionTitle": "Dizionari", + "availableSpellingDictionaries": "Dizionari disponibili", + "customSpellingDictionaries": "Dizionari personalizzati", + "spellingDictionaryProblems": "Problemi dei dizionari", "settingsWindowSectionTitle": "Finestra", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "File interessati", "renameTopicFileInstead": "Gli ID degli argomenti derivano dai nomi dei file. Usa Rinomina file argomento nel sommario o nella barra laterale File.", "diagnosticWritersideWebFileNameInvalid": "L’istanza \"{instanceId}\" pubblica il nome file web non valido \"{webFileName}\" per l’argomento \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "L’istanza \"{instanceId}\" pubblica sia \"{firstTopic}\" sia \"{secondTopic}\" come \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "L’istanza \"{instanceId}\" pubblica sia \"{firstTopic}\" sia \"{secondTopic}\" come \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Il dizionario ortografico è stato modificato esternamente. È stata conservata una copia di ripristino." } diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index b20f226e..2902a604 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "さらに結果を表示", "workspaceSearchSkippedFiles": "検索は未完了です。次のファイルは 1 MiB を超えているか、読み取れませんでした:", "@@locale": "ja", + "spelling": "スペルチェック", + "automaticSpelling": "自動スペルチェック", + "defaultSpellingLanguage": "既定のスペルチェック言語", + "projectSpellingLanguage": "プロジェクトのスペルチェック言語", + "chooseSpellingLanguage": "スペルチェック言語を選択", + "spellingLanguageUnsetStatus": "言語…", + "spellingOffStatus": "スペルチェック オフ", + "checkSpelling": "スペルチェック", + "ignoreSpellingOnce": "一度だけ無視", + "ignoreSpellingDocument": "この文書ですべて無視", + "addPersonalSpellingWord": "個人辞書に追加", + "addProjectSpellingWord": "プロジェクト辞書に追加", + "inheritSpellingLanguage": "プロジェクトまたはアプリの言語を使用", + "disableDocumentSpelling": "スペルチェックしない", + "importSpellingDictionary": "辞書をインポート", + "personalSpellingDictionary": "個人辞書", + "projectSpellingDictionary": "プロジェクト辞書", + "noSpellingErrors": "スペルミスはありません", + "noSpellingSuggestions": "スペル候補はありません", + "spellingWordCheckFailed": "この単語を確認できませんでした", + "spellingCheckFailed": "スペルチェックに失敗しました", + "spellingCheckIncomplete": "スペルチェックが完了していません", + "spellingDictionaryNotInstalled": "辞書がインストールされていません", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} の辞書がインストールされていません", + "spellingDictionaryNotInstalledWithSize": "未インストール · {size}", + "spellingDictionaryInstalled": "インストール済み", + "installSpellingDictionary": "辞書をインストール", + "removeSpellingDictionary": "辞書を削除", + "cancelSpellingDictionaryInstall": "辞書のダウンロードをキャンセル", + "retrySpellingDictionaryInstall": "辞書のインストールを再試行", + "spellingDictionaryDownloading": "{size} をダウンロード中…", + "spellingDictionaryValidating": "辞書を検証中…", + "spellingDictionaryInstallFailed": "辞書のインストールに失敗しました — 選択して再試行", + "spellingDictionaryInstallPrompt": "{dictionary}({size})をインストールしますか?インストール後は削除するまでオフラインで利用できます。", + "spellingDictionaryUnavailable": "辞書を利用できません", + "spellingChecking": "スペルを確認中…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "折り返し", + "wordWrapDescription": "長い行を横方向にスクロールせず、エディターの幅に合わせて折り返します。", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "編集ボタン", + "spellingDictionaries": "スペルチェック辞書", + "spellingDictionariesDescription": "スペルチェック辞書をインストールして管理", + "settingsDictionariesSectionTitle": "辞書", + "availableSpellingDictionaries": "利用可能な辞書", + "customSpellingDictionaries": "カスタム辞書", + "spellingDictionaryProblems": "辞書の問題", "settingsWindowSectionTitle": "ウィンドウ", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "影響を受けるファイル", "renameTopicFileInstead": "トピック ID はファイル名から生成されます。目次またはファイルサイドバーの「トピックファイルの名前を変更」を使用してください。", "diagnosticWritersideWebFileNameInvalid": "インスタンス \"{instanceId}\" はトピック \"{topic}\" に無効な Web ファイル名 \"{webFileName}\" を使用しています。", - "diagnosticWritersideWebFileNameCollision": "インスタンス \"{instanceId}\" は \"{firstTopic}\" と \"{secondTopic}\" の両方を \"{webFileName}\" として公開します。" + "diagnosticWritersideWebFileNameCollision": "インスタンス \"{instanceId}\" は \"{firstTopic}\" と \"{secondTopic}\" の両方を \"{webFileName}\" として公開します。", + "spellingDictionaryRecoveryConflict": "スペルチェック辞書が外部で変更されました。復旧用コピーを保持しました。" } diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index deafd22e..bc9f4ada 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "결과 더 보기", "workspaceSearchSkippedFiles": "검색이 완료되지 않았습니다. 다음 파일은 1 MiB를 초과하거나 읽을 수 없습니다:", "@@locale": "ko", + "spelling": "맞춤법", + "automaticSpelling": "자동 맞춤법 검사", + "defaultSpellingLanguage": "기본 맞춤법 언어", + "projectSpellingLanguage": "프로젝트 맞춤법 검사 언어", + "chooseSpellingLanguage": "맞춤법 언어 선택", + "spellingLanguageUnsetStatus": "언어…", + "spellingOffStatus": "맞춤법 검사 끄기", + "checkSpelling": "맞춤법 검사", + "ignoreSpellingOnce": "한 번 무시", + "ignoreSpellingDocument": "이 문서에서 모두 무시", + "addPersonalSpellingWord": "개인 사전에 추가", + "addProjectSpellingWord": "프로젝트 사전에 추가", + "inheritSpellingLanguage": "프로젝트 또는 앱 언어 사용", + "disableDocumentSpelling": "맞춤법 검사 안 함", + "importSpellingDictionary": "사전 가져오기", + "personalSpellingDictionary": "개인 사전", + "projectSpellingDictionary": "프로젝트 사전", + "noSpellingErrors": "맞춤법 오류가 없습니다", + "noSpellingSuggestions": "맞춤법 제안이 없습니다", + "spellingWordCheckFailed": "이 단어를 확인할 수 없습니다", + "spellingCheckFailed": "맞춤법 검사에 실패했습니다", + "spellingCheckIncomplete": "맞춤법 검사가 완료되지 않았습니다", + "spellingDictionaryNotInstalled": "사전이 설치되지 않음", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} 사전이 설치되지 않았습니다", + "spellingDictionaryNotInstalledWithSize": "설치되지 않음 · {size}", + "spellingDictionaryInstalled": "설치됨", + "installSpellingDictionary": "사전 설치", + "removeSpellingDictionary": "사전 제거", + "cancelSpellingDictionaryInstall": "사전 다운로드 취소", + "retrySpellingDictionaryInstall": "사전 설치 다시 시도", + "spellingDictionaryDownloading": "{size} 다운로드 중…", + "spellingDictionaryValidating": "사전 검증 중…", + "spellingDictionaryInstallFailed": "사전 설치 실패 — 선택하여 다시 시도", + "spellingDictionaryInstallPrompt": "{dictionary}({size})을 설치하시겠습니까? 설치 후 제거할 때까지 오프라인에서 사용할 수 있습니다.", + "spellingDictionaryUnavailable": "사전을 사용할 수 없습니다", + "spellingChecking": "맞춤법 검사 중…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "자동 줄 바꿈", + "wordWrapDescription": "긴 줄을 가로로 스크롤하지 않고 편집기 너비에 맞게 줄 바꿈합니다.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "편집 버튼", + "spellingDictionaries": "맞춤법 검사 사전", + "spellingDictionariesDescription": "맞춤법 검사 사전 설치 및 관리", + "settingsDictionariesSectionTitle": "사전", + "availableSpellingDictionaries": "사용 가능한 사전", + "customSpellingDictionaries": "사용자 지정 사전", + "spellingDictionaryProblems": "사전 문제", "settingsWindowSectionTitle": "창", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "영향을 받는 파일", "renameTopicFileInstead": "토픽 ID는 파일 이름에서 생성됩니다. 목차 또는 파일 사이드바에서 토픽 파일 이름 바꾸기를 사용하세요.", "diagnosticWritersideWebFileNameInvalid": "인스턴스 \"{instanceId}\"에서 토픽 \"{topic}\"의 웹 파일 이름 \"{webFileName}\"이 올바르지 않습니다.", - "diagnosticWritersideWebFileNameCollision": "인스턴스 \"{instanceId}\"에서 \"{firstTopic}\"과 \"{secondTopic}\"이 모두 \"{webFileName}\"으로 게시됩니다." + "diagnosticWritersideWebFileNameCollision": "인스턴스 \"{instanceId}\"에서 \"{firstTopic}\"과 \"{secondTopic}\"이 모두 \"{webFileName}\"으로 게시됩니다.", + "spellingDictionaryRecoveryConflict": "맞춤법 사전이 외부에서 변경되었습니다. 복구 사본을 보존했습니다." } diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index b59e5292..b805ea54 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Vis flere resultater", "workspaceSearchSkippedFiles": "Søket er ufullstendig. Disse filene er større enn 1 MiB eller kunne ikke leses:", "@@locale": "nb", + "spelling": "Stavekontroll", + "automaticSpelling": "Automatisk stavekontroll", + "defaultSpellingLanguage": "Standard språk for stavekontroll", + "projectSpellingLanguage": "Prosjektspråk for stavekontroll", + "chooseSpellingLanguage": "Velg språk for stavekontroll", + "spellingLanguageUnsetStatus": "Språk…", + "spellingOffStatus": "Stavekontroll av", + "checkSpelling": "Kontroller staving", + "ignoreSpellingOnce": "Ignorer én gang", + "ignoreSpellingDocument": "Ignorer alle i dette dokumentet", + "addPersonalSpellingWord": "Legg til i personlig ordliste", + "addProjectSpellingWord": "Legg til i prosjektordlisten", + "inheritSpellingLanguage": "Bruk prosjekt- eller programspråk", + "disableDocumentSpelling": "Ikke kontroller staving", + "importSpellingDictionary": "Importer ordliste", + "personalSpellingDictionary": "Personlig ordliste", + "projectSpellingDictionary": "Prosjektordliste", + "noSpellingErrors": "Ingen stavefeil", + "noSpellingSuggestions": "Ingen staveforslag", + "spellingWordCheckFailed": "Kunne ikke kontrollere dette ordet", + "spellingCheckFailed": "Stavekontrollen mislyktes", + "spellingCheckIncomplete": "Stavekontrollen er ufullstendig", + "spellingDictionaryNotInstalled": "Ordliste er ikke installert", + "spellingDictionaryNotInstalledForLanguage": "Ordlisten for {dictionary} er ikke installert", + "spellingDictionaryNotInstalledWithSize": "Ikke installert · {size}", + "spellingDictionaryInstalled": "Installert", + "installSpellingDictionary": "Installer ordliste", + "removeSpellingDictionary": "Fjern ordliste", + "cancelSpellingDictionaryInstall": "Avbryt nedlasting av ordliste", + "retrySpellingDictionaryInstall": "Prøv å installere ordlisten på nytt", + "spellingDictionaryDownloading": "Laster ned {size}…", + "spellingDictionaryValidating": "Validerer ordliste…", + "spellingDictionaryInstallFailed": "Installasjonen mislyktes — velg for å prøve på nytt", + "spellingDictionaryInstallPrompt": "Installere {dictionary} ({size})? Etter installering er den tilgjengelig frakoblet til du fjerner den.", + "spellingDictionaryUnavailable": "Ordliste utilgjengelig", + "spellingChecking": "Kontrollerer staving…", "reportIssue": "Rapporter et problem", "feedbackCategory": "Kategori", "feedbackChooseCategory": "Velg en kategori", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Tekstbryting", + "wordWrapDescription": "Bryt lange linjer så de passer til redigeringsbredden i stedet for å rulle vannrett.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Redigeringsknapper", + "spellingDictionaries": "Stavekontrollordbøker", + "spellingDictionariesDescription": "Installer og administrer stavekontrollordbøker", + "settingsDictionariesSectionTitle": "Ordbøker", + "availableSpellingDictionaries": "Tilgjengelige ordbøker", + "customSpellingDictionaries": "Egendefinerte ordbøker", + "spellingDictionaryProblems": "Ordbokproblemer", "settingsWindowSectionTitle": "Vindu", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Berørte filer", "renameTopicFileInstead": "Emne-ID-er kommer fra filnavnene. Bruk Gi nytt navn til emnefil i innholdsfortegnelsen eller sidepanelet Filer.", "diagnosticWritersideWebFileNameInvalid": "Instansen \"{instanceId}\" publiserer det ugyldige nettfilnavnet \"{webFileName}\" for emnet \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Instansen \"{instanceId}\" publiserer både \"{firstTopic}\" og \"{secondTopic}\" som \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Instansen \"{instanceId}\" publiserer både \"{firstTopic}\" og \"{secondTopic}\" som \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Staveordboken ble endret eksternt. En gjenopprettingskopi ble bevart." } diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index aabc5711..88ea5ddc 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Meer resultaten tonen", "workspaceSearchSkippedFiles": "De zoekopdracht is onvolledig. Deze bestanden zijn groter dan 1 MiB of konden niet worden gelezen:", "@@locale": "nl", + "spelling": "Spellingcontrole", + "automaticSpelling": "Spelling automatisch controleren", + "defaultSpellingLanguage": "Standaardtaal voor spelling", + "projectSpellingLanguage": "Projecttaal voor spelling", + "chooseSpellingLanguage": "Taal voor spelling kiezen", + "spellingLanguageUnsetStatus": "Taal…", + "spellingOffStatus": "Spelling uit", + "checkSpelling": "Spelling controleren", + "ignoreSpellingOnce": "Eenmaal negeren", + "ignoreSpellingDocument": "Alles in dit document negeren", + "addPersonalSpellingWord": "Aan persoonlijk woordenboek toevoegen", + "addProjectSpellingWord": "Aan projectwoordenboek toevoegen", + "inheritSpellingLanguage": "Project- of toepassingstaal gebruiken", + "disableDocumentSpelling": "Spelling niet controleren", + "importSpellingDictionary": "Woordenboek importeren", + "personalSpellingDictionary": "Persoonlijk woordenboek", + "projectSpellingDictionary": "Projectwoordenboek", + "noSpellingErrors": "Geen spelfouten", + "noSpellingSuggestions": "Geen spellingsuggesties", + "spellingWordCheckFailed": "Dit woord kon niet worden gecontroleerd", + "spellingCheckFailed": "Spellingcontrole mislukt", + "spellingCheckIncomplete": "De spellingcontrole is onvolledig", + "spellingDictionaryNotInstalled": "Woordenboek niet geïnstalleerd", + "spellingDictionaryNotInstalledForLanguage": "Het woordenboek voor {dictionary} is niet geïnstalleerd", + "spellingDictionaryNotInstalledWithSize": "Niet geïnstalleerd · {size}", + "spellingDictionaryInstalled": "Geïnstalleerd", + "installSpellingDictionary": "Woordenboek installeren", + "removeSpellingDictionary": "Woordenboek verwijderen", + "cancelSpellingDictionaryInstall": "Download van woordenboek annuleren", + "retrySpellingDictionaryInstall": "Installatie van woordenboek opnieuw proberen", + "spellingDictionaryDownloading": "{size} downloaden…", + "spellingDictionaryValidating": "Woordenboek valideren…", + "spellingDictionaryInstallFailed": "Installatie mislukt — selecteer om opnieuw te proberen", + "spellingDictionaryInstallPrompt": "{dictionary} ({size}) installeren? Daarna blijft het offline beschikbaar totdat u het verwijdert.", + "spellingDictionaryUnavailable": "Woordenboek niet beschikbaar", + "spellingChecking": "Spelling controleren…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Regelterugloop", + "wordWrapDescription": "Laat lange regels op de editorbreedte doorlopen in plaats van horizontaal te schuiven.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Bewerkingsknoppen", + "spellingDictionaries": "Spellingswoordenboeken", + "spellingDictionariesDescription": "Spellingswoordenboeken installeren en beheren", + "settingsDictionariesSectionTitle": "Woordenboeken", + "availableSpellingDictionaries": "Beschikbare woordenboeken", + "customSpellingDictionaries": "Aangepaste woordenboeken", + "spellingDictionaryProblems": "Woordenboekproblemen", "settingsWindowSectionTitle": "Raam", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "Betrokken bestanden", "renameTopicFileInstead": "Onderwerp-ID's zijn afgeleid van de bestandsnamen. Gebruik Onderwerpbestand hernoemen in de inhoudsopgave of de zijbalk Bestanden.", "diagnosticWritersideWebFileNameInvalid": "Instantie \"{instanceId}\" publiceert de ongeldige webbestandsnaam \"{webFileName}\" voor onderwerp \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Instantie \"{instanceId}\" publiceert zowel \"{firstTopic}\" als \"{secondTopic}\" als \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Instantie \"{instanceId}\" publiceert zowel \"{firstTopic}\" als \"{secondTopic}\" als \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Het spellingwoordenboek is extern gewijzigd. Er is een herstelkopie bewaard." } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 32f0bce3..e76da42e 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Pokaż więcej wyników", "workspaceSearchSkippedFiles": "Wyszukiwanie jest niepełne. Te pliki przekraczają 1 MiB lub nie można ich odczytać:", "@@locale": "pl", + "spelling": "Pisownia", + "automaticSpelling": "Automatyczne sprawdzanie pisowni", + "defaultSpellingLanguage": "Domyślny język pisowni", + "projectSpellingLanguage": "Język sprawdzania pisowni projektu", + "chooseSpellingLanguage": "Wybierz język pisowni", + "spellingLanguageUnsetStatus": "Język…", + "spellingOffStatus": "Pisownia wyłączona", + "checkSpelling": "Sprawdź pisownię", + "ignoreSpellingOnce": "Ignoruj raz", + "ignoreSpellingDocument": "Ignoruj wszystkie w tym dokumencie", + "addPersonalSpellingWord": "Dodaj do słownika osobistego", + "addProjectSpellingWord": "Dodaj do słownika projektu", + "inheritSpellingLanguage": "Użyj języka projektu lub aplikacji", + "disableDocumentSpelling": "Nie sprawdzaj pisowni", + "importSpellingDictionary": "Importuj słownik", + "personalSpellingDictionary": "Słownik osobisty", + "projectSpellingDictionary": "Słownik projektu", + "noSpellingErrors": "Brak błędów pisowni", + "noSpellingSuggestions": "Brak sugestii pisowni", + "spellingWordCheckFailed": "Nie można sprawdzić tego słowa", + "spellingCheckFailed": "Sprawdzanie pisowni nie powiodło się", + "spellingCheckIncomplete": "Sprawdzanie pisowni jest niepełne", + "spellingDictionaryNotInstalled": "Słownik nie jest zainstalowany", + "spellingDictionaryNotInstalledForLanguage": "Słownik {dictionary} nie jest zainstalowany", + "spellingDictionaryNotInstalledWithSize": "Niezainstalowany · {size}", + "spellingDictionaryInstalled": "Zainstalowany", + "installSpellingDictionary": "Zainstaluj słownik", + "removeSpellingDictionary": "Usuń słownik", + "cancelSpellingDictionaryInstall": "Anuluj pobieranie słownika", + "retrySpellingDictionaryInstall": "Ponów instalację słownika", + "spellingDictionaryDownloading": "Pobieranie {size}…", + "spellingDictionaryValidating": "Sprawdzanie słownika…", + "spellingDictionaryInstallFailed": "Instalacja nie powiodła się — wybierz, aby ponowić", + "spellingDictionaryInstallPrompt": "Zainstalować {dictionary} ({size})? Po instalacji będzie dostępny offline do czasu usunięcia.", + "spellingDictionaryUnavailable": "Słownik jest niedostępny", + "spellingChecking": "Sprawdzanie pisowni…", "reportIssue": "Zgłoś problem", "feedbackCategory": "Kategoria", "feedbackChooseCategory": "Wybierz kategorię", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Zawijanie wierszy", + "wordWrapDescription": "Zawijaj długie wiersze do szerokości edytora zamiast przewijać je poziomo.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Przyciski edycji", + "spellingDictionaries": "Słowniki pisowni", + "spellingDictionariesDescription": "Instaluj słowniki pisowni i zarządzaj nimi", + "settingsDictionariesSectionTitle": "Słowniki", + "availableSpellingDictionaries": "Dostępne słowniki", + "customSpellingDictionaries": "Słowniki niestandardowe", + "spellingDictionaryProblems": "Problemy ze słownikami", "settingsWindowSectionTitle": "Okno", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3355,5 +3399,6 @@ "topicRenameAffectedFiles": "Pliki objęte zmianą", "renameTopicFileInstead": "Identyfikatory tematów pochodzą z nazw ich plików. Użyj polecenia Zmień nazwę pliku tematu w spisie treści lub na pasku bocznym Pliki.", "diagnosticWritersideWebFileNameInvalid": "Instancja \"{instanceId}\" publikuje nieprawidłową nazwę pliku internetowego \"{webFileName}\" dla tematu \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Instancja \"{instanceId}\" publikuje zarówno \"{firstTopic}\", jak i \"{secondTopic}\" jako \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Instancja \"{instanceId}\" publikuje zarówno \"{firstTopic}\", jak i \"{secondTopic}\" jako \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Słownik pisowni został zmieniony zewnętrznie. Zachowano kopię odzyskiwania." } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index b3f71907..0f24d460 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Mostrar mais resultados", "workspaceSearchSkippedFiles": "A pesquisa está incompleta. Estes ficheiros excedem 1 MiB ou não foi possível lê-los:", "@@locale": "pt", + "spelling": "Ortografia", + "automaticSpelling": "Verificação ortográfica automática", + "defaultSpellingLanguage": "Idioma ortográfico predefinido", + "projectSpellingLanguage": "Idioma de verificação ortográfica do projeto", + "chooseSpellingLanguage": "Escolher idioma ortográfico", + "spellingLanguageUnsetStatus": "Idioma…", + "spellingOffStatus": "Ortografia desativada", + "checkSpelling": "Verificar ortografia", + "ignoreSpellingOnce": "Ignorar uma vez", + "ignoreSpellingDocument": "Ignorar tudo neste documento", + "addPersonalSpellingWord": "Adicionar ao dicionário pessoal", + "addProjectSpellingWord": "Adicionar ao dicionário do projeto", + "inheritSpellingLanguage": "Usar o idioma do projeto ou da aplicação", + "disableDocumentSpelling": "Não verificar a ortografia", + "importSpellingDictionary": "Importar dicionário", + "personalSpellingDictionary": "Dicionário pessoal", + "projectSpellingDictionary": "Dicionário do projeto", + "noSpellingErrors": "Sem erros ortográficos", + "noSpellingSuggestions": "Sem sugestões ortográficas", + "spellingWordCheckFailed": "Não foi possível verificar esta palavra", + "spellingCheckFailed": "A verificação ortográfica falhou", + "spellingCheckIncomplete": "A verificação ortográfica está incompleta", + "spellingDictionaryNotInstalled": "Dicionário não instalado", + "spellingDictionaryNotInstalledForLanguage": "O dicionário de {dictionary} não está instalado", + "spellingDictionaryNotInstalledWithSize": "Não instalado · {size}", + "spellingDictionaryInstalled": "Instalado", + "installSpellingDictionary": "Instalar dicionário", + "removeSpellingDictionary": "Remover dicionário", + "cancelSpellingDictionaryInstall": "Cancelar transferência do dicionário", + "retrySpellingDictionaryInstall": "Repetir instalação do dicionário", + "spellingDictionaryDownloading": "A transferir {size}…", + "spellingDictionaryValidating": "A validar o dicionário…", + "spellingDictionaryInstallFailed": "A instalação falhou — selecione para repetir", + "spellingDictionaryInstallPrompt": "Instalar {dictionary} ({size})? Depois de instalado, ficará disponível offline até ser removido.", + "spellingDictionaryUnavailable": "Dicionário indisponível", + "spellingChecking": "A verificar a ortografia…", "reportIssue": "Comunicar um problema", "feedbackCategory": "Categoria", "feedbackChooseCategory": "Escolha uma categoria", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Quebra de linha", + "wordWrapDescription": "Ajustar linhas longas à largura do editor em vez de deslocar horizontalmente.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Botões de edição", + "spellingDictionaries": "Dicionários ortográficos", + "spellingDictionariesDescription": "Instalar e gerir dicionários ortográficos", + "settingsDictionariesSectionTitle": "Dicionários", + "availableSpellingDictionaries": "Dicionários disponíveis", + "customSpellingDictionaries": "Dicionários personalizados", + "spellingDictionaryProblems": "Problemas de dicionários", "settingsWindowSectionTitle": "Janela", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Ficheiros afetados", "renameTopicFileInstead": "Os IDs dos tópicos provêm dos nomes dos ficheiros. Utilize Mudar o nome do ficheiro de tópico no índice ou na barra lateral Ficheiros.", "diagnosticWritersideWebFileNameInvalid": "A instância \"{instanceId}\" publica o nome de ficheiro Web inválido \"{webFileName}\" para o tópico \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "A instância \"{instanceId}\" publica \"{firstTopic}\" e \"{secondTopic}\" como \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "A instância \"{instanceId}\" publica \"{firstTopic}\" e \"{secondTopic}\" como \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "O dicionário ortográfico foi alterado externamente. Foi preservada uma cópia de recuperação." } diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 73743e2d..b745d481 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Mostrar mais resultados", "workspaceSearchSkippedFiles": "A pesquisa está incompleta. Estes arquivos excedem 1 MiB ou não puderam ser lidos:", "@@locale": "pt_BR", + "spelling": "Ortografia", + "automaticSpelling": "Verificação ortográfica automática", + "defaultSpellingLanguage": "Idioma ortográfico padrão", + "projectSpellingLanguage": "Idioma de verificação ortográfica do projeto", + "chooseSpellingLanguage": "Escolher idioma ortográfico", + "spellingLanguageUnsetStatus": "Idioma…", + "spellingOffStatus": "Ortografia desativada", + "checkSpelling": "Verificar ortografia", + "ignoreSpellingOnce": "Ignorar uma vez", + "ignoreSpellingDocument": "Ignorar tudo neste documento", + "addPersonalSpellingWord": "Adicionar ao dicionário pessoal", + "addProjectSpellingWord": "Adicionar ao dicionário do projeto", + "inheritSpellingLanguage": "Usar o idioma do projeto ou do aplicativo", + "disableDocumentSpelling": "Não verificar a ortografia", + "importSpellingDictionary": "Importar dicionário", + "personalSpellingDictionary": "Dicionário pessoal", + "projectSpellingDictionary": "Dicionário do projeto", + "noSpellingErrors": "Nenhum erro ortográfico", + "noSpellingSuggestions": "Nenhuma sugestão ortográfica", + "spellingWordCheckFailed": "Não foi possível verificar esta palavra", + "spellingCheckFailed": "A verificação ortográfica falhou", + "spellingCheckIncomplete": "A verificação ortográfica está incompleta", + "spellingDictionaryNotInstalled": "Dicionário não instalado", + "spellingDictionaryNotInstalledForLanguage": "O dicionário de {dictionary} não está instalado", + "spellingDictionaryNotInstalledWithSize": "Não instalado · {size}", + "spellingDictionaryInstalled": "Instalado", + "installSpellingDictionary": "Instalar dicionário", + "removeSpellingDictionary": "Remover dicionário", + "cancelSpellingDictionaryInstall": "Cancelar download do dicionário", + "retrySpellingDictionaryInstall": "Tentar instalar o dicionário novamente", + "spellingDictionaryDownloading": "Baixando {size}…", + "spellingDictionaryValidating": "Validando dicionário…", + "spellingDictionaryInstallFailed": "Falha na instalação — selecione para tentar novamente", + "spellingDictionaryInstallPrompt": "Instalar {dictionary} ({size})? Depois de instalado, ficará disponível offline até ser removido.", + "spellingDictionaryUnavailable": "Dicionário indisponível", + "spellingChecking": "Verificando a ortografia…", "reportIssue": "Comunicar um problema", "feedbackCategory": "Categoria", "feedbackChooseCategory": "Escolha uma categoria", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Quebra de linha", + "wordWrapDescription": "Quebre linhas longas para ajustá-las à largura do editor em vez de rolar horizontalmente.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Botões de edição", + "spellingDictionaries": "Dicionários ortográficos", + "spellingDictionariesDescription": "Instalar e gerenciar dicionários ortográficos", + "settingsDictionariesSectionTitle": "Dicionários", + "availableSpellingDictionaries": "Dicionários disponíveis", + "customSpellingDictionaries": "Dicionários personalizados", + "spellingDictionaryProblems": "Problemas de dicionários", "settingsWindowSectionTitle": "Janela", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3329,5 +3373,6 @@ "topicRenameAffectedFiles": "Arquivos afetados", "renameTopicFileInstead": "Os IDs dos tópicos vêm dos nomes dos arquivos. Use Renomear arquivo do tópico no sumário ou na barra lateral Arquivos.", "diagnosticWritersideWebFileNameInvalid": "A instância \"{instanceId}\" publica o nome de arquivo da Web inválido \"{webFileName}\" para o tópico \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "A instância \"{instanceId}\" publica \"{firstTopic}\" e \"{secondTopic}\" como \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "A instância \"{instanceId}\" publica \"{firstTopic}\" e \"{secondTopic}\" como \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "O dicionário ortográfico foi alterado externamente. Uma cópia de recuperação foi preservada." } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 13ada108..fc0020b9 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Показать больше результатов", "workspaceSearchSkippedFiles": "Поиск неполный. Эти файлы превышают 1 MiB или не могут быть прочитаны:", "@@locale": "ru", + "spelling": "Правописание", + "automaticSpelling": "Автоматическая проверка правописания", + "defaultSpellingLanguage": "Язык проверки правописания по умолчанию", + "projectSpellingLanguage": "Язык проверки орфографии проекта", + "chooseSpellingLanguage": "Выбрать язык правописания", + "spellingLanguageUnsetStatus": "Язык…", + "spellingOffStatus": "Проверка правописания отключена", + "checkSpelling": "Проверить правописание", + "ignoreSpellingOnce": "Игнорировать один раз", + "ignoreSpellingDocument": "Игнорировать все в этом документе", + "addPersonalSpellingWord": "Добавить в личный словарь", + "addProjectSpellingWord": "Добавить в словарь проекта", + "inheritSpellingLanguage": "Использовать язык проекта или приложения", + "disableDocumentSpelling": "Не проверять орфографию", + "importSpellingDictionary": "Импортировать словарь", + "personalSpellingDictionary": "Личный словарь", + "projectSpellingDictionary": "Словарь проекта", + "noSpellingErrors": "Орфографических ошибок нет", + "noSpellingSuggestions": "Нет вариантов исправления", + "spellingWordCheckFailed": "Не удалось проверить это слово", + "spellingCheckFailed": "Не удалось проверить правописание", + "spellingCheckIncomplete": "Проверка правописания не завершена", + "spellingDictionaryNotInstalled": "Словарь не установлен", + "spellingDictionaryNotInstalledForLanguage": "Словарь «{dictionary}» не установлен", + "spellingDictionaryNotInstalledWithSize": "Не установлен · {size}", + "spellingDictionaryInstalled": "Установлен", + "installSpellingDictionary": "Установить словарь", + "removeSpellingDictionary": "Удалить словарь", + "cancelSpellingDictionaryInstall": "Отменить загрузку словаря", + "retrySpellingDictionaryInstall": "Повторить установку словаря", + "spellingDictionaryDownloading": "Загрузка {size}…", + "spellingDictionaryValidating": "Проверка словаря…", + "spellingDictionaryInstallFailed": "Не удалось установить словарь — выберите для повтора", + "spellingDictionaryInstallPrompt": "Установить {dictionary} ({size})? После установки он будет доступен без сети, пока вы его не удалите.", + "spellingDictionaryUnavailable": "Словарь недоступен", + "spellingChecking": "Проверка правописания…", "reportIssue": "Сообщить о проблеме", "feedbackCategory": "Категория", "feedbackChooseCategory": "Выберите категорию", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Перенос строк", + "wordWrapDescription": "Переносить длинные строки по ширине редактора вместо горизонтальной прокрутки.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Кнопки редактирования", + "spellingDictionaries": "Орфографические словари", + "spellingDictionariesDescription": "Установка и управление орфографическими словарями", + "settingsDictionariesSectionTitle": "Словари", + "availableSpellingDictionaries": "Доступные словари", + "customSpellingDictionaries": "Пользовательские словари", + "spellingDictionaryProblems": "Проблемы со словарями", "settingsWindowSectionTitle": "Окно", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3355,5 +3399,6 @@ "topicRenameAffectedFiles": "Затронутые файлы", "renameTopicFileInstead": "ID тем определяются именами их файлов. Используйте «Переименовать файл темы» в оглавлении или на боковой панели «Файлы».", "diagnosticWritersideWebFileNameInvalid": "Экземпляр \"{instanceId}\" публикует недопустимое имя веб-файла \"{webFileName}\" для темы \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Экземпляр \"{instanceId}\" публикует темы \"{firstTopic}\" и \"{secondTopic}\" под одним именем \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Экземпляр \"{instanceId}\" публикует темы \"{firstTopic}\" и \"{secondTopic}\" под одним именем \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Орфографический словарь был изменён извне. Резервная копия для восстановления сохранена." } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 2fe8e553..926e572c 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Daha fazla sonuç göster", "workspaceSearchSkippedFiles": "Arama eksik. Bu dosyalar 1 MiB boyutunu aşıyor veya okunamadı:", "@@locale": "tr", + "spelling": "Yazım", + "automaticSpelling": "Otomatik yazım denetimi", + "defaultSpellingLanguage": "Varsayılan yazım dili", + "projectSpellingLanguage": "Proje yazım denetimi dili", + "chooseSpellingLanguage": "Yazım dili seç", + "spellingLanguageUnsetStatus": "Dil…", + "spellingOffStatus": "Yazım denetimi kapalı", + "checkSpelling": "Yazımı Denetle", + "ignoreSpellingOnce": "Bir Kez Yoksay", + "ignoreSpellingDocument": "Bu Belgede Tümünü Yoksay", + "addPersonalSpellingWord": "Kişisel Sözlüğe Ekle", + "addProjectSpellingWord": "Proje Sözlüğüne Ekle", + "inheritSpellingLanguage": "Proje veya uygulama dilini kullan", + "disableDocumentSpelling": "Yazımı denetleme", + "importSpellingDictionary": "Sözlük İçe Aktar", + "personalSpellingDictionary": "Kişisel Sözlük", + "projectSpellingDictionary": "Proje Sözlüğü", + "noSpellingErrors": "Yazım hatası yok", + "noSpellingSuggestions": "Yazım önerisi yok", + "spellingWordCheckFailed": "Bu sözcük denetlenemedi", + "spellingCheckFailed": "Yazım denetimi başarısız oldu", + "spellingCheckIncomplete": "Yazım denetimi tamamlanmadı", + "spellingDictionaryNotInstalled": "Sözlük yüklü değil", + "spellingDictionaryNotInstalledForLanguage": "{dictionary} sözlüğü yüklü değil", + "spellingDictionaryNotInstalledWithSize": "Yüklü değil · {size}", + "spellingDictionaryInstalled": "Yüklü", + "installSpellingDictionary": "Sözlüğü yükle", + "removeSpellingDictionary": "Sözlüğü kaldır", + "cancelSpellingDictionaryInstall": "Sözlük indirmesini iptal et", + "retrySpellingDictionaryInstall": "Sözlük yüklemesini yeniden dene", + "spellingDictionaryDownloading": "{size} indiriliyor…", + "spellingDictionaryValidating": "Sözlük doğrulanıyor…", + "spellingDictionaryInstallFailed": "Sözlük yüklenemedi — yeniden denemek için seçin", + "spellingDictionaryInstallPrompt": "{dictionary} ({size}) yüklensin mi? Yüklendikten sonra kaldırılana kadar çevrimdışı kullanılabilir.", + "spellingDictionaryUnavailable": "Sözlük kullanılamıyor", + "spellingChecking": "Yazım denetleniyor…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Satır kaydırma", + "wordWrapDescription": "Uzun satırları yatay kaydırmak yerine düzenleyici genişliğine sığacak şekilde kaydırın.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Düzenleme düğmeleri", + "spellingDictionaries": "Yazım sözlükleri", + "spellingDictionariesDescription": "Yazım sözlüklerini kurun ve yönetin", + "settingsDictionariesSectionTitle": "Sözlükler", + "availableSpellingDictionaries": "Kullanılabilir sözlükler", + "customSpellingDictionaries": "Özel sözlükler", + "spellingDictionaryProblems": "Sözlük sorunları", "settingsWindowSectionTitle": "Pencere", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "Etkilenen dosyalar", "renameTopicFileInstead": "Konu kimlikleri dosya adlarından gelir. İçindekiler tablosunda veya Dosyalar kenar çubuğunda Konu Dosyasını Yeniden Adlandır'ı kullanın.", "diagnosticWritersideWebFileNameInvalid": "\"{instanceId}\" örneği, \"{topic}\" konusu için geçersiz \"{webFileName}\" web dosyası adını yayımlıyor.", - "diagnosticWritersideWebFileNameCollision": "\"{instanceId}\" örneği hem \"{firstTopic}\" hem de \"{secondTopic}\" konusunu \"{webFileName}\" olarak yayımlıyor." + "diagnosticWritersideWebFileNameCollision": "\"{instanceId}\" örneği hem \"{firstTopic}\" hem de \"{secondTopic}\" konusunu \"{webFileName}\" olarak yayımlıyor.", + "spellingDictionaryRecoveryConflict": "Yazım sözlüğü harici olarak değiştirildi. Bir kurtarma kopyası korundu." } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index c9be81c3..f1a8f944 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Показати більше результатів", "workspaceSearchSkippedFiles": "Пошук неповний. Ці файли перевищують 1 MiB або їх не вдалося прочитати:", "@@locale": "uk", + "spelling": "Правопис", + "automaticSpelling": "Автоматична перевірка правопису", + "defaultSpellingLanguage": "Типова мова перевірки правопису", + "projectSpellingLanguage": "Мова перевірки правопису проєкту", + "chooseSpellingLanguage": "Вибрати мову правопису", + "spellingLanguageUnsetStatus": "Мова…", + "spellingOffStatus": "Перевірку правопису вимкнено", + "checkSpelling": "Перевірити правопис", + "ignoreSpellingOnce": "Ігнорувати один раз", + "ignoreSpellingDocument": "Ігнорувати все в цьому документі", + "addPersonalSpellingWord": "Додати до особистого словника", + "addProjectSpellingWord": "Додати до словника проєкту", + "inheritSpellingLanguage": "Використовувати мову проєкту або програми", + "disableDocumentSpelling": "Не перевіряти правопис", + "importSpellingDictionary": "Імпортувати словник", + "personalSpellingDictionary": "Особистий словник", + "projectSpellingDictionary": "Словник проєкту", + "noSpellingErrors": "Орфографічних помилок немає", + "noSpellingSuggestions": "Немає варіантів виправлення", + "spellingWordCheckFailed": "Не вдалося перевірити це слово", + "spellingCheckFailed": "Не вдалося перевірити правопис", + "spellingCheckIncomplete": "Перевірку правопису не завершено", + "spellingDictionaryNotInstalled": "Словник не встановлено", + "spellingDictionaryNotInstalledForLanguage": "Словник «{dictionary}» не встановлено", + "spellingDictionaryNotInstalledWithSize": "Не встановлено · {size}", + "spellingDictionaryInstalled": "Встановлено", + "installSpellingDictionary": "Встановити словник", + "removeSpellingDictionary": "Видалити словник", + "cancelSpellingDictionaryInstall": "Скасувати завантаження словника", + "retrySpellingDictionaryInstall": "Повторити встановлення словника", + "spellingDictionaryDownloading": "Завантаження {size}…", + "spellingDictionaryValidating": "Перевірка словника…", + "spellingDictionaryInstallFailed": "Не вдалося встановити словник — виберіть, щоб повторити", + "spellingDictionaryInstallPrompt": "Встановити {dictionary} ({size})? Після встановлення він буде доступний офлайн, доки ви його не видалите.", + "spellingDictionaryUnavailable": "Словник недоступний", + "spellingChecking": "Перевірка правопису…", "reportIssue": "Повідомити про проблему", "feedbackCategory": "Категорія", "feedbackChooseCategory": "Виберіть категорію", @@ -802,6 +838,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Перенесення рядків", + "wordWrapDescription": "Переносити довгі рядки за шириною редактора замість горизонтального прокручування.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -869,6 +906,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Кнопки редагування", + "spellingDictionaries": "Орфографічні словники", + "spellingDictionariesDescription": "Установлення й керування орфографічними словниками", + "settingsDictionariesSectionTitle": "Словники", + "availableSpellingDictionaries": "Доступні словники", + "customSpellingDictionaries": "Власні словники", + "spellingDictionaryProblems": "Проблеми зі словниками", "settingsWindowSectionTitle": "Вікно", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -3355,5 +3399,6 @@ "topicRenameAffectedFiles": "Змінені файли", "renameTopicFileInstead": "ID тем визначаються іменами їхніх файлів. Скористайтеся командою «Перейменувати файл теми» у змісті або на бічній панелі «Файли».", "diagnosticWritersideWebFileNameInvalid": "Екземпляр \"{instanceId}\" публікує неприпустиме ім’я вебфайлу \"{webFileName}\" для теми \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Екземпляр \"{instanceId}\" публікує теми \"{firstTopic}\" і \"{secondTopic}\" під одним іменем \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Екземпляр \"{instanceId}\" публікує теми \"{firstTopic}\" і \"{secondTopic}\" під одним іменем \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Орфографічний словник було змінено ззовні. Копію для відновлення збережено." } diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 2ddce938..b125a60f 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "Hiển thị thêm kết quả", "workspaceSearchSkippedFiles": "Tìm kiếm chưa đầy đủ. Các tệp này vượt quá 1 MiB hoặc không thể đọc được:", "@@locale": "vi", + "spelling": "Chính tả", + "automaticSpelling": "Tự động kiểm tra chính tả", + "defaultSpellingLanguage": "Ngôn ngữ chính tả mặc định", + "projectSpellingLanguage": "Ngôn ngữ kiểm tra chính tả của dự án", + "chooseSpellingLanguage": "Chọn ngôn ngữ chính tả", + "spellingLanguageUnsetStatus": "Ngôn ngữ…", + "spellingOffStatus": "Tắt chính tả", + "checkSpelling": "Kiểm tra chính tả", + "ignoreSpellingOnce": "Bỏ qua một lần", + "ignoreSpellingDocument": "Bỏ qua tất cả trong tài liệu này", + "addPersonalSpellingWord": "Thêm vào từ điển cá nhân", + "addProjectSpellingWord": "Thêm vào từ điển dự án", + "inheritSpellingLanguage": "Dùng ngôn ngữ dự án hoặc ứng dụng", + "disableDocumentSpelling": "Không kiểm tra chính tả", + "importSpellingDictionary": "Nhập từ điển", + "personalSpellingDictionary": "Từ điển cá nhân", + "projectSpellingDictionary": "Từ điển dự án", + "noSpellingErrors": "Không có lỗi chính tả", + "noSpellingSuggestions": "Không có đề xuất chính tả", + "spellingWordCheckFailed": "Không thể kiểm tra từ này", + "spellingCheckFailed": "Kiểm tra chính tả thất bại", + "spellingCheckIncomplete": "Kiểm tra chính tả chưa hoàn tất", + "spellingDictionaryNotInstalled": "Từ điển chưa được cài đặt", + "spellingDictionaryNotInstalledForLanguage": "Từ điển {dictionary} chưa được cài đặt", + "spellingDictionaryNotInstalledWithSize": "Chưa cài đặt · {size}", + "spellingDictionaryInstalled": "Đã cài đặt", + "installSpellingDictionary": "Cài đặt từ điển", + "removeSpellingDictionary": "Gỡ từ điển", + "cancelSpellingDictionaryInstall": "Hủy tải từ điển", + "retrySpellingDictionaryInstall": "Thử cài đặt lại từ điển", + "spellingDictionaryDownloading": "Đang tải {size}…", + "spellingDictionaryValidating": "Đang xác thực từ điển…", + "spellingDictionaryInstallFailed": "Cài đặt từ điển thất bại — chọn để thử lại", + "spellingDictionaryInstallPrompt": "Cài đặt {dictionary} ({size})? Sau khi cài đặt, từ điển sẽ dùng được ngoại tuyến cho đến khi bạn gỡ bỏ.", + "spellingDictionaryUnavailable": "Từ điển không khả dụng", + "spellingChecking": "Đang kiểm tra chính tả…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "Tự động xuống dòng", + "wordWrapDescription": "Ngắt các dòng dài cho vừa chiều rộng trình biên tập thay vì cuộn ngang.", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "Nút chỉnh sửa", + "spellingDictionaries": "Từ điển chính tả", + "spellingDictionariesDescription": "Cài đặt và quản lý từ điển chính tả", + "settingsDictionariesSectionTitle": "Từ điển", + "availableSpellingDictionaries": "Từ điển có sẵn", + "customSpellingDictionaries": "Từ điển tùy chỉnh", + "spellingDictionaryProblems": "Sự cố từ điển", "settingsWindowSectionTitle": "Cửa sổ", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "Các tệp bị ảnh hưởng", "renameTopicFileInstead": "ID chủ đề được tạo từ tên tệp. Hãy dùng Đổi tên tệp chủ đề trong mục lục hoặc thanh bên Tệp.", "diagnosticWritersideWebFileNameInvalid": "Phiên bản \"{instanceId}\" xuất bản tên tệp web không hợp lệ \"{webFileName}\" cho chủ đề \"{topic}\".", - "diagnosticWritersideWebFileNameCollision": "Phiên bản \"{instanceId}\" xuất bản cả \"{firstTopic}\" và \"{secondTopic}\" dưới tên \"{webFileName}\"." + "diagnosticWritersideWebFileNameCollision": "Phiên bản \"{instanceId}\" xuất bản cả \"{firstTopic}\" và \"{secondTopic}\" dưới tên \"{webFileName}\".", + "spellingDictionaryRecoveryConflict": "Từ điển chính tả đã được thay đổi từ bên ngoài. Một bản sao khôi phục đã được giữ lại." } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 0d3c2411..208f9870 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "显示更多结果", "workspaceSearchSkippedFiles": "搜索不完整。以下文件超过 1 MiB 或无法读取:", "@@locale": "zh", + "spelling": "拼写检查", + "automaticSpelling": "自动检查拼写", + "defaultSpellingLanguage": "默认拼写语言", + "projectSpellingLanguage": "项目拼写检查语言", + "chooseSpellingLanguage": "选择拼写语言", + "spellingLanguageUnsetStatus": "语言…", + "spellingOffStatus": "拼写检查已关闭", + "checkSpelling": "检查拼写", + "ignoreSpellingOnce": "忽略一次", + "ignoreSpellingDocument": "在此文档中全部忽略", + "addPersonalSpellingWord": "添加到个人词典", + "addProjectSpellingWord": "添加到项目词典", + "inheritSpellingLanguage": "使用项目或应用语言", + "disableDocumentSpelling": "不检查拼写", + "importSpellingDictionary": "导入词典", + "personalSpellingDictionary": "个人词典", + "projectSpellingDictionary": "项目词典", + "noSpellingErrors": "没有拼写错误", + "noSpellingSuggestions": "没有拼写建议", + "spellingWordCheckFailed": "无法检查此单词", + "spellingCheckFailed": "拼写检查失败", + "spellingCheckIncomplete": "拼写检查未完成", + "spellingDictionaryNotInstalled": "尚未安装词典", + "spellingDictionaryNotInstalledForLanguage": "尚未安装 {dictionary} 词典", + "spellingDictionaryNotInstalledWithSize": "未安装 · {size}", + "spellingDictionaryInstalled": "已安装", + "installSpellingDictionary": "安装词典", + "removeSpellingDictionary": "移除词典", + "cancelSpellingDictionaryInstall": "取消下载词典", + "retrySpellingDictionaryInstall": "重试安装词典", + "spellingDictionaryDownloading": "正在下载 {size}…", + "spellingDictionaryValidating": "正在验证词典…", + "spellingDictionaryInstallFailed": "词典安装失败 — 选择以重试", + "spellingDictionaryInstallPrompt": "要安装 {dictionary}({size})吗?安装后,在移除前都可离线使用。", + "spellingDictionaryUnavailable": "词典不可用", + "spellingChecking": "正在检查拼写…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "自动换行", + "wordWrapDescription": "将长行换行以适应编辑器宽度,而不是水平滚动。", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "编辑按钮", + "spellingDictionaries": "拼写词典", + "spellingDictionariesDescription": "安装和管理拼写词典", + "settingsDictionariesSectionTitle": "词典", + "availableSpellingDictionaries": "可用词典", + "customSpellingDictionaries": "自定义词典", + "spellingDictionaryProblems": "词典问题", "settingsWindowSectionTitle": "窗口", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "受影响的文件", "renameTopicFileInstead": "主题 ID 来自其文件名。请在目录或“文件”侧边栏中使用“重命名主题文件”。", "diagnosticWritersideWebFileNameInvalid": "实例 \"{instanceId}\" 为主题 \"{topic}\" 发布了无效的 Web 文件名 \"{webFileName}\"。", - "diagnosticWritersideWebFileNameCollision": "实例 \"{instanceId}\" 将 \"{firstTopic}\" 和 \"{secondTopic}\" 都发布为 \"{webFileName}\"。" + "diagnosticWritersideWebFileNameCollision": "实例 \"{instanceId}\" 将 \"{firstTopic}\" 和 \"{secondTopic}\" 都发布为 \"{webFileName}\"。", + "spellingDictionaryRecoveryConflict": "拼写词典已被外部更改。已保留恢复副本。" } diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 6e9cdc1f..ae0bbb1d 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -83,6 +83,42 @@ "workspaceSearchShowMore": "显示更多结果", "workspaceSearchSkippedFiles": "搜索不完整。以下文件超过 1 MiB 或无法读取:", "@@locale": "zh_CN", + "spelling": "拼写检查", + "automaticSpelling": "自动检查拼写", + "defaultSpellingLanguage": "默认拼写语言", + "projectSpellingLanguage": "项目拼写检查语言", + "chooseSpellingLanguage": "选择拼写语言", + "spellingLanguageUnsetStatus": "语言…", + "spellingOffStatus": "拼写检查已关闭", + "checkSpelling": "检查拼写", + "ignoreSpellingOnce": "忽略一次", + "ignoreSpellingDocument": "在此文档中全部忽略", + "addPersonalSpellingWord": "添加到个人词典", + "addProjectSpellingWord": "添加到项目词典", + "inheritSpellingLanguage": "使用项目或应用语言", + "disableDocumentSpelling": "不检查拼写", + "importSpellingDictionary": "导入词典", + "personalSpellingDictionary": "个人词典", + "projectSpellingDictionary": "项目词典", + "noSpellingErrors": "没有拼写错误", + "noSpellingSuggestions": "没有拼写建议", + "spellingWordCheckFailed": "无法检查此单词", + "spellingCheckFailed": "拼写检查失败", + "spellingCheckIncomplete": "拼写检查未完成", + "spellingDictionaryNotInstalled": "尚未安装词典", + "spellingDictionaryNotInstalledForLanguage": "尚未安装 {dictionary} 词典", + "spellingDictionaryNotInstalledWithSize": "未安装 · {size}", + "spellingDictionaryInstalled": "已安装", + "installSpellingDictionary": "安装词典", + "removeSpellingDictionary": "移除词典", + "cancelSpellingDictionaryInstall": "取消下载词典", + "retrySpellingDictionaryInstall": "重试安装词典", + "spellingDictionaryDownloading": "正在下载 {size}…", + "spellingDictionaryValidating": "正在验证词典…", + "spellingDictionaryInstallFailed": "词典安装失败 — 选择以重试", + "spellingDictionaryInstallPrompt": "要安装 {dictionary}({size})吗?安装后,在移除前都可离线使用。", + "spellingDictionaryUnavailable": "词典不可用", + "spellingChecking": "正在检查拼写…", "appTitle": "BusyMark", "@appTitle": { "description": "Application name." @@ -932,6 +968,7 @@ "description": "Editor setting description for saving files automatically." }, "wordWrap": "自动换行", + "wordWrapDescription": "将长行换行以适应编辑器宽度,而不是水平滚动。", "@wordWrap": { "description": "Word wrap setting label." }, @@ -999,6 +1036,13 @@ "@clearGitWorkspaceTrustDescription": { "description": "Settings action description for clearing trusted Git workspaces." }, + "settingsEditingButtonsSectionTitle": "编辑按钮", + "spellingDictionaries": "拼写词典", + "spellingDictionariesDescription": "安装和管理拼写词典", + "settingsDictionariesSectionTitle": "词典", + "availableSpellingDictionaries": "可用词典", + "customSpellingDictionaries": "自定义词典", + "spellingDictionaryProblems": "词典问题", "settingsWindowSectionTitle": "窗口", "@settingsWindowSectionTitle": { "description": "Settings section title for native window behavior." @@ -4868,5 +4912,6 @@ "topicRenameAffectedFiles": "受影响的文件", "renameTopicFileInstead": "主题 ID 来自其文件名。请在目录或“文件”侧边栏中使用“重命名主题文件”。", "diagnosticWritersideWebFileNameInvalid": "实例 \"{instanceId}\" 为主题 \"{topic}\" 发布了无效的 Web 文件名 \"{webFileName}\"。", - "diagnosticWritersideWebFileNameCollision": "实例 \"{instanceId}\" 将 \"{firstTopic}\" 和 \"{secondTopic}\" 都发布为 \"{webFileName}\"。" + "diagnosticWritersideWebFileNameCollision": "实例 \"{instanceId}\" 将 \"{firstTopic}\" 和 \"{secondTopic}\" 都发布为 \"{webFileName}\"。", + "spellingDictionaryRecoveryConflict": "拼写词典已被外部更改。已保留恢复副本。" } diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index e30992e2..93b9d9fc 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -1885,6 +1885,12 @@ abstract class AppLocalizations { /// **'Word wrap'** String get wordWrap; + /// Editor setting description for wrapping long lines. + /// + /// In en, this message translates to: + /// **'Wrap long lines to fit the editor width instead of scrolling horizontally.'** + String get wordWrapDescription; + /// Editor font size setting label. /// /// In en, this message translates to: @@ -1981,6 +1987,48 @@ abstract class AppLocalizations { /// **'Ask before enabling Git features for previously trusted workspaces.'** String get clearGitWorkspaceTrustDescription; + /// Editor-settings section title for editing-button controls. + /// + /// In en, this message translates to: + /// **'Editing buttons'** + String get settingsEditingButtonsSectionTitle; + + /// Title for the spelling-dictionary management subpage and its navigation row. + /// + /// In en, this message translates to: + /// **'Spelling Dictionaries'** + String get spellingDictionaries; + + /// Description for the navigation row that opens spelling-dictionary management. + /// + /// In en, this message translates to: + /// **'Install and manage spelling dictionaries'** + String get spellingDictionariesDescription; + + /// Editor-settings section title for dictionary management and word-store controls. + /// + /// In en, this message translates to: + /// **'Dictionaries'** + String get settingsDictionariesSectionTitle; + + /// Settings group title for downloadable spelling dictionaries. + /// + /// In en, this message translates to: + /// **'Available Dictionaries'** + String get availableSpellingDictionaries; + + /// Settings group title for imported spelling dictionaries. + /// + /// In en, this message translates to: + /// **'Custom Dictionaries'** + String get customSpellingDictionaries; + + /// Settings group title for invalid imported spelling dictionaries. + /// + /// In en, this message translates to: + /// **'Dictionary Problems'** + String get spellingDictionaryProblems; + /// Settings section title for native window behavior. /// /// In en, this message translates to: @@ -7578,11 +7626,233 @@ abstract class AppLocalizations { /// **'{value} MiB'** String settingsMebibytesValue(int value); + /// No description provided for @spelling. + /// + /// In en, this message translates to: + /// **'Spelling'** + String get spelling; + + /// No description provided for @automaticSpelling. + /// + /// In en, this message translates to: + /// **'Check spelling automatically'** + String get automaticSpelling; + + /// No description provided for @defaultSpellingLanguage. + /// + /// In en, this message translates to: + /// **'Default spelling language'** + String get defaultSpellingLanguage; + + /// No description provided for @projectSpellingLanguage. + /// + /// In en, this message translates to: + /// **'Project spelling language'** + String get projectSpellingLanguage; + + /// No description provided for @chooseSpellingLanguage. + /// + /// In en, this message translates to: + /// **'Choose spelling language'** + String get chooseSpellingLanguage; + + /// Compact document status shown when no spelling language resolves. + /// + /// In en, this message translates to: + /// **'Language…'** + String get spellingLanguageUnsetStatus; + + /// Compact document status shown when spelling is disabled for the document. + /// + /// In en, this message translates to: + /// **'Spelling Off'** + String get spellingOffStatus; + + /// No description provided for @checkSpelling. + /// + /// In en, this message translates to: + /// **'Check Spelling'** + String get checkSpelling; + + /// No description provided for @ignoreSpellingOnce. + /// + /// In en, this message translates to: + /// **'Ignore Once'** + String get ignoreSpellingOnce; + + /// No description provided for @ignoreSpellingDocument. + /// + /// In en, this message translates to: + /// **'Ignore All in This Document'** + String get ignoreSpellingDocument; + + /// No description provided for @addPersonalSpellingWord. + /// + /// In en, this message translates to: + /// **'Add to Personal Dictionary'** + String get addPersonalSpellingWord; + + /// No description provided for @addProjectSpellingWord. + /// + /// In en, this message translates to: + /// **'Add to Project Dictionary'** + String get addProjectSpellingWord; + + /// No description provided for @inheritSpellingLanguage. + /// + /// In en, this message translates to: + /// **'Use project or application language'** + String get inheritSpellingLanguage; + + /// No description provided for @disableDocumentSpelling. + /// + /// In en, this message translates to: + /// **'Do not check spelling'** + String get disableDocumentSpelling; + + /// No description provided for @importSpellingDictionary. + /// + /// In en, this message translates to: + /// **'Import Dictionary'** + String get importSpellingDictionary; + + /// No description provided for @personalSpellingDictionary. + /// + /// In en, this message translates to: + /// **'Personal Dictionary'** + String get personalSpellingDictionary; + + /// No description provided for @projectSpellingDictionary. + /// + /// In en, this message translates to: + /// **'Project Dictionary'** + String get projectSpellingDictionary; + + /// No description provided for @noSpellingErrors. + /// + /// In en, this message translates to: + /// **'No spelling errors'** + String get noSpellingErrors; + + /// No description provided for @noSpellingSuggestions. + /// + /// In en, this message translates to: + /// **'No spelling suggestions'** + String get noSpellingSuggestions; + + /// No description provided for @spellingWordCheckFailed. + /// + /// In en, this message translates to: + /// **'Could not check this word'** + String get spellingWordCheckFailed; + + /// No description provided for @spellingCheckFailed. + /// + /// In en, this message translates to: + /// **'Spelling check failed'** + String get spellingCheckFailed; + + /// No description provided for @spellingCheckIncomplete. + /// + /// In en, this message translates to: + /// **'Spelling check is incomplete'** + String get spellingCheckIncomplete; + + /// No description provided for @spellingDictionaryNotInstalled. + /// + /// In en, this message translates to: + /// **'Dictionary not installed'** + String get spellingDictionaryNotInstalled; + + /// No description provided for @spellingDictionaryNotInstalledForLanguage. + /// + /// In en, this message translates to: + /// **'{dictionary} dictionary is not installed'** + String spellingDictionaryNotInstalledForLanguage(String dictionary); + + /// No description provided for @spellingDictionaryNotInstalledWithSize. + /// + /// In en, this message translates to: + /// **'Not installed · {size}'** + String spellingDictionaryNotInstalledWithSize(String size); + + /// No description provided for @spellingDictionaryInstalled. + /// + /// In en, this message translates to: + /// **'Installed'** + String get spellingDictionaryInstalled; + + /// No description provided for @installSpellingDictionary. + /// + /// In en, this message translates to: + /// **'Install dictionary'** + String get installSpellingDictionary; + + /// No description provided for @removeSpellingDictionary. + /// + /// In en, this message translates to: + /// **'Remove dictionary'** + String get removeSpellingDictionary; + + /// No description provided for @cancelSpellingDictionaryInstall. + /// + /// In en, this message translates to: + /// **'Cancel dictionary download'** + String get cancelSpellingDictionaryInstall; + + /// No description provided for @retrySpellingDictionaryInstall. + /// + /// In en, this message translates to: + /// **'Retry dictionary installation'** + String get retrySpellingDictionaryInstall; + + /// No description provided for @spellingDictionaryDownloading. + /// + /// In en, this message translates to: + /// **'Downloading {size}…'** + String spellingDictionaryDownloading(String size); + + /// No description provided for @spellingDictionaryValidating. + /// + /// In en, this message translates to: + /// **'Validating dictionary…'** + String get spellingDictionaryValidating; + + /// No description provided for @spellingDictionaryInstallFailed. + /// + /// In en, this message translates to: + /// **'Dictionary installation failed — select to retry'** + String get spellingDictionaryInstallFailed; + + /// No description provided for @spellingDictionaryInstallPrompt. + /// + /// In en, this message translates to: + /// **'Install {dictionary} ({size})? After installation, it remains available offline until you remove it.'** + String spellingDictionaryInstallPrompt(String dictionary, String size); + + /// No description provided for @spellingDictionaryUnavailable. + /// + /// In en, this message translates to: + /// **'Dictionary unavailable'** + String get spellingDictionaryUnavailable; + + /// No description provided for @spellingChecking. + /// + /// In en, this message translates to: + /// **'Checking spelling…'** + String get spellingChecking; + /// Invalid numeric export setting. /// /// In en, this message translates to: /// **'{field}: enter a number between {minimum} and {maximum}.'** String exportInvalidRange(String field, String minimum, String maximum); + + /// No description provided for @spellingDictionaryRecoveryConflict. + /// + /// In en, this message translates to: + /// **'The spelling dictionary changed externally. A recovery copy was preserved.'** + String get spellingDictionaryRecoveryConflict; } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index 4d07aaf2..35f4eb30 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -938,6 +938,10 @@ class AppLocalizationsAr extends AppLocalizations { @override String get wordWrap => 'التفاف النص'; + @override + String get wordWrapDescription => + 'التفاف السطور الطويلة لتلائم عرض المحرر بدلاً من التمرير أفقيًا.'; + @override String get editorFontSize => 'حجم خط المحرر'; @@ -991,6 +995,28 @@ class AppLocalizationsAr extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'طلب التأكيد قبل تمكين ميزات Git لمساحات العمل التي سبق الوثوق بها.'; + @override + String get settingsEditingButtonsSectionTitle => 'أزرار التحرير'; + + @override + String get spellingDictionaries => 'قواميس التدقيق الإملائي'; + + @override + String get spellingDictionariesDescription => + 'تثبيت قواميس التدقيق الإملائي وإدارتها'; + + @override + String get settingsDictionariesSectionTitle => 'القواميس'; + + @override + String get availableSpellingDictionaries => 'القواميس المتاحة'; + + @override + String get customSpellingDictionaries => 'القواميس المخصصة'; + + @override + String get spellingDictionaryProblems => 'مشكلات القواميس'; + @override String get settingsWindowSectionTitle => 'النافذة'; @@ -4523,8 +4549,129 @@ class AppLocalizationsAr extends AppLocalizations { return '$value ميجابايت'; } + @override + String get spelling => 'الإملاء'; + + @override + String get automaticSpelling => 'التدقيق الإملائي التلقائي'; + + @override + String get defaultSpellingLanguage => 'لغة الإملاء الافتراضية'; + + @override + String get projectSpellingLanguage => 'لغة التدقيق الإملائي للمشروع'; + + @override + String get chooseSpellingLanguage => 'اختر لغة الإملاء'; + + @override + String get spellingLanguageUnsetStatus => 'اللغة…'; + + @override + String get spellingOffStatus => 'التدقيق الإملائي متوقف'; + + @override + String get checkSpelling => 'تدقيق الإملاء'; + + @override + String get ignoreSpellingOnce => 'تجاهل مرة واحدة'; + + @override + String get ignoreSpellingDocument => 'تجاهل الكل في هذا المستند'; + + @override + String get addPersonalSpellingWord => 'إضافة إلى القاموس الشخصي'; + + @override + String get addProjectSpellingWord => 'إضافة إلى قاموس المشروع'; + + @override + String get inheritSpellingLanguage => 'استخدام لغة المشروع أو التطبيق'; + + @override + String get disableDocumentSpelling => 'عدم التدقيق الإملائي'; + + @override + String get importSpellingDictionary => 'استيراد قاموس'; + + @override + String get personalSpellingDictionary => 'القاموس الشخصي'; + + @override + String get projectSpellingDictionary => 'قاموس المشروع'; + + @override + String get noSpellingErrors => 'لا توجد أخطاء إملائية'; + + @override + String get noSpellingSuggestions => 'لا توجد اقتراحات إملائية'; + + @override + String get spellingWordCheckFailed => 'تعذّر التحقق من هذه الكلمة'; + + @override + String get spellingCheckFailed => 'فشل التدقيق الإملائي'; + + @override + String get spellingCheckIncomplete => 'التدقيق الإملائي غير مكتمل'; + + @override + String get spellingDictionaryNotInstalled => 'القاموس غير مثبّت'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'قاموس ⁨$dictionary⁩ غير مثبّت'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'غير مثبّت · ⁨$size⁩'; + } + + @override + String get spellingDictionaryInstalled => 'مثبّت'; + + @override + String get installSpellingDictionary => 'تثبيت القاموس'; + + @override + String get removeSpellingDictionary => 'إزالة القاموس'; + + @override + String get cancelSpellingDictionaryInstall => 'إلغاء تنزيل القاموس'; + + @override + String get retrySpellingDictionaryInstall => 'إعادة محاولة تثبيت القاموس'; + + @override + String spellingDictionaryDownloading(String size) { + return 'جارٍ تنزيل ⁨$size⁩…'; + } + + @override + String get spellingDictionaryValidating => 'جارٍ التحقق من القاموس…'; + + @override + String get spellingDictionaryInstallFailed => + 'فشل تثبيت القاموس — حدده لإعادة المحاولة'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'هل تريد تثبيت ⁨$dictionary⁩ (⁨$size⁩)؟ بعد التثبيت، يظل متاحًا دون اتصال حتى تزيله.'; + } + + @override + String get spellingDictionaryUnavailable => 'القاموس غير متاح'; + + @override + String get spellingChecking => 'جارٍ التدقيق الإملائي…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: أدخل رقمًا بين $minimum و$maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'تم تغيير قاموس التدقيق الإملائي خارجيًا. تم الاحتفاظ بنسخة استرداد.'; } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 7f2309a2..0555ff1b 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -964,6 +964,10 @@ class AppLocalizationsDe extends AppLocalizations { @override String get wordWrap => 'Zeilenumbruch'; + @override + String get wordWrapDescription => + 'Lange Zeilen an die Breite des Editors anpassen, anstatt horizontal zu scrollen.'; + @override String get editorFontSize => 'Schriftgröße des Editors'; @@ -1021,6 +1025,28 @@ class AppLocalizationsDe extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Vor dem Aktivieren von Git-Funktionen für zuvor vertrauenswürdige Arbeitsbereiche nachfragen.'; + @override + String get settingsEditingButtonsSectionTitle => 'Bearbeitungsschaltflächen'; + + @override + String get spellingDictionaries => 'Rechtschreibwörterbücher'; + + @override + String get spellingDictionariesDescription => + 'Rechtschreibwörterbücher installieren und verwalten'; + + @override + String get settingsDictionariesSectionTitle => 'Wörterbücher'; + + @override + String get availableSpellingDictionaries => 'Verfügbare Wörterbücher'; + + @override + String get customSpellingDictionaries => 'Benutzerdefinierte Wörterbücher'; + + @override + String get spellingDictionaryProblems => 'Wörterbuchprobleme'; + @override String get settingsWindowSectionTitle => 'Fenster'; @@ -4530,8 +4556,133 @@ class AppLocalizationsDe extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Rechtschreibung'; + + @override + String get automaticSpelling => 'Automatische Rechtschreibprüfung'; + + @override + String get defaultSpellingLanguage => 'Standardsprache für Rechtschreibung'; + + @override + String get projectSpellingLanguage => 'Projektsprache für Rechtschreibung'; + + @override + String get chooseSpellingLanguage => 'Rechtschreibsprache auswählen'; + + @override + String get spellingLanguageUnsetStatus => 'Sprache…'; + + @override + String get spellingOffStatus => 'Rechtschreibung aus'; + + @override + String get checkSpelling => 'Rechtschreibung prüfen'; + + @override + String get ignoreSpellingOnce => 'Einmal ignorieren'; + + @override + String get ignoreSpellingDocument => 'Alle in diesem Dokument ignorieren'; + + @override + String get addPersonalSpellingWord => + 'Zum persönlichen Wörterbuch hinzufügen'; + + @override + String get addProjectSpellingWord => 'Zum Projektwörterbuch hinzufügen'; + + @override + String get inheritSpellingLanguage => + 'Projekt- oder Anwendungssprache verwenden'; + + @override + String get disableDocumentSpelling => 'Rechtschreibung nicht prüfen'; + + @override + String get importSpellingDictionary => 'Wörterbuch importieren'; + + @override + String get personalSpellingDictionary => 'Persönliches Wörterbuch'; + + @override + String get projectSpellingDictionary => 'Projektwörterbuch'; + + @override + String get noSpellingErrors => 'Keine Rechtschreibfehler'; + + @override + String get noSpellingSuggestions => 'Keine Rechtschreibvorschläge'; + + @override + String get spellingWordCheckFailed => + 'Dieses Wort konnte nicht geprüft werden'; + + @override + String get spellingCheckFailed => 'Rechtschreibprüfung fehlgeschlagen'; + + @override + String get spellingCheckIncomplete => 'Rechtschreibprüfung ist unvollständig'; + + @override + String get spellingDictionaryNotInstalled => 'Wörterbuch nicht installiert'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Das Wörterbuch $dictionary ist nicht installiert'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Nicht installiert · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installiert'; + + @override + String get installSpellingDictionary => 'Wörterbuch installieren'; + + @override + String get removeSpellingDictionary => 'Wörterbuch entfernen'; + + @override + String get cancelSpellingDictionaryInstall => 'Wörterbuchdownload abbrechen'; + + @override + String get retrySpellingDictionaryInstall => + 'Wörterbuchinstallation wiederholen'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size werden heruntergeladen…'; + } + + @override + String get spellingDictionaryValidating => 'Wörterbuch wird überprüft…'; + + @override + String get spellingDictionaryInstallFailed => + 'Wörterbuchinstallation fehlgeschlagen – zum Wiederholen auswählen'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary ($size) installieren? Danach bleibt es offline verfügbar, bis Sie es entfernen.'; + } + + @override + String get spellingDictionaryUnavailable => 'Wörterbuch nicht verfügbar'; + + @override + String get spellingChecking => 'Rechtschreibung wird geprüft…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: Geben Sie eine Zahl zwischen $minimum und $maximum ein.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Das Rechtschreibwörterbuch wurde extern geändert. Eine Wiederherstellungskopie wurde aufbewahrt.'; } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index efd38e82..8b5c64be 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -948,6 +948,10 @@ class AppLocalizationsEn extends AppLocalizations { @override String get wordWrap => 'Word wrap'; + @override + String get wordWrapDescription => + 'Wrap long lines to fit the editor width instead of scrolling horizontally.'; + @override String get editorFontSize => 'Editor font size'; @@ -1001,6 +1005,28 @@ class AppLocalizationsEn extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Ask before enabling Git features for previously trusted workspaces.'; + @override + String get settingsEditingButtonsSectionTitle => 'Editing buttons'; + + @override + String get spellingDictionaries => 'Spelling Dictionaries'; + + @override + String get spellingDictionariesDescription => + 'Install and manage spelling dictionaries'; + + @override + String get settingsDictionariesSectionTitle => 'Dictionaries'; + + @override + String get availableSpellingDictionaries => 'Available Dictionaries'; + + @override + String get customSpellingDictionaries => 'Custom Dictionaries'; + + @override + String get spellingDictionaryProblems => 'Dictionary Problems'; + @override String get settingsWindowSectionTitle => 'Window'; @@ -4508,8 +4534,129 @@ class AppLocalizationsEn extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Spelling'; + + @override + String get automaticSpelling => 'Check spelling automatically'; + + @override + String get defaultSpellingLanguage => 'Default spelling language'; + + @override + String get projectSpellingLanguage => 'Project spelling language'; + + @override + String get chooseSpellingLanguage => 'Choose spelling language'; + + @override + String get spellingLanguageUnsetStatus => 'Language…'; + + @override + String get spellingOffStatus => 'Spelling Off'; + + @override + String get checkSpelling => 'Check Spelling'; + + @override + String get ignoreSpellingOnce => 'Ignore Once'; + + @override + String get ignoreSpellingDocument => 'Ignore All in This Document'; + + @override + String get addPersonalSpellingWord => 'Add to Personal Dictionary'; + + @override + String get addProjectSpellingWord => 'Add to Project Dictionary'; + + @override + String get inheritSpellingLanguage => 'Use project or application language'; + + @override + String get disableDocumentSpelling => 'Do not check spelling'; + + @override + String get importSpellingDictionary => 'Import Dictionary'; + + @override + String get personalSpellingDictionary => 'Personal Dictionary'; + + @override + String get projectSpellingDictionary => 'Project Dictionary'; + + @override + String get noSpellingErrors => 'No spelling errors'; + + @override + String get noSpellingSuggestions => 'No spelling suggestions'; + + @override + String get spellingWordCheckFailed => 'Could not check this word'; + + @override + String get spellingCheckFailed => 'Spelling check failed'; + + @override + String get spellingCheckIncomplete => 'Spelling check is incomplete'; + + @override + String get spellingDictionaryNotInstalled => 'Dictionary not installed'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary dictionary is not installed'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Not installed · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installed'; + + @override + String get installSpellingDictionary => 'Install dictionary'; + + @override + String get removeSpellingDictionary => 'Remove dictionary'; + + @override + String get cancelSpellingDictionaryInstall => 'Cancel dictionary download'; + + @override + String get retrySpellingDictionaryInstall => 'Retry dictionary installation'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Downloading $size…'; + } + + @override + String get spellingDictionaryValidating => 'Validating dictionary…'; + + @override + String get spellingDictionaryInstallFailed => + 'Dictionary installation failed — select to retry'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Install $dictionary ($size)? After installation, it remains available offline until you remove it.'; + } + + @override + String get spellingDictionaryUnavailable => 'Dictionary unavailable'; + + @override + String get spellingChecking => 'Checking spelling…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: enter a number between $minimum and $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'The spelling dictionary changed externally. A recovery copy was preserved.'; } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 0e8e05b3..f355d87a 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -963,6 +963,10 @@ class AppLocalizationsEs extends AppLocalizations { @override String get wordWrap => 'Ajuste de línea'; + @override + String get wordWrapDescription => + 'Ajusta las líneas largas al ancho del editor en lugar de desplazarse horizontalmente.'; + @override String get editorFontSize => 'Tamaño de fuente del editor'; @@ -1018,6 +1022,28 @@ class AppLocalizationsEs extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Preguntar antes de activar funciones de Git para espacios de trabajo que ya eran de confianza.'; + @override + String get settingsEditingButtonsSectionTitle => 'Botones de edición'; + + @override + String get spellingDictionaries => 'Diccionarios ortográficos'; + + @override + String get spellingDictionariesDescription => + 'Instalar y gestionar diccionarios ortográficos'; + + @override + String get settingsDictionariesSectionTitle => 'Diccionarios'; + + @override + String get availableSpellingDictionaries => 'Diccionarios disponibles'; + + @override + String get customSpellingDictionaries => 'Diccionarios personalizados'; + + @override + String get spellingDictionaryProblems => 'Problemas de diccionarios'; + @override String get settingsWindowSectionTitle => 'Ventana'; @@ -4532,8 +4558,134 @@ class AppLocalizationsEs extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Ortografía'; + + @override + String get automaticSpelling => 'Revisión ortográfica automática'; + + @override + String get defaultSpellingLanguage => 'Idioma ortográfico predeterminado'; + + @override + String get projectSpellingLanguage => + 'Idioma de corrección ortográfica del proyecto'; + + @override + String get chooseSpellingLanguage => 'Elegir idioma ortográfico'; + + @override + String get spellingLanguageUnsetStatus => 'Idioma…'; + + @override + String get spellingOffStatus => 'Ortografía desactivada'; + + @override + String get checkSpelling => 'Revisar ortografía'; + + @override + String get ignoreSpellingOnce => 'Ignorar una vez'; + + @override + String get ignoreSpellingDocument => 'Ignorar todo en este documento'; + + @override + String get addPersonalSpellingWord => 'Añadir al diccionario personal'; + + @override + String get addProjectSpellingWord => 'Añadir al diccionario del proyecto'; + + @override + String get inheritSpellingLanguage => + 'Usar el idioma del proyecto o la aplicación'; + + @override + String get disableDocumentSpelling => 'No revisar la ortografía'; + + @override + String get importSpellingDictionary => 'Importar diccionario'; + + @override + String get personalSpellingDictionary => 'Diccionario personal'; + + @override + String get projectSpellingDictionary => 'Diccionario del proyecto'; + + @override + String get noSpellingErrors => 'No hay errores ortográficos'; + + @override + String get noSpellingSuggestions => 'No hay sugerencias ortográficas'; + + @override + String get spellingWordCheckFailed => 'No se pudo comprobar esta palabra'; + + @override + String get spellingCheckFailed => 'La revisión ortográfica falló'; + + @override + String get spellingCheckIncomplete => + 'La revisión ortográfica está incompleta'; + + @override + String get spellingDictionaryNotInstalled => 'Diccionario no instalado'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'El diccionario de $dictionary no está instalado'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'No instalado · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Instalado'; + + @override + String get installSpellingDictionary => 'Instalar diccionario'; + + @override + String get removeSpellingDictionary => 'Eliminar diccionario'; + + @override + String get cancelSpellingDictionaryInstall => + 'Cancelar descarga del diccionario'; + + @override + String get retrySpellingDictionaryInstall => + 'Reintentar instalación del diccionario'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Descargando $size…'; + } + + @override + String get spellingDictionaryValidating => 'Validando diccionario…'; + + @override + String get spellingDictionaryInstallFailed => + 'La instalación falló; selecciónelo para reintentar'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '¿Instalar $dictionary ($size)? Tras instalarlo, estará disponible sin conexión hasta que lo elimine.'; + } + + @override + String get spellingDictionaryUnavailable => 'Diccionario no disponible'; + + @override + String get spellingChecking => 'Comprobando la ortografía…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: introduzca un número entre $minimum y $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'El diccionario ortográfico se modificó externamente. Se conservó una copia de recuperación.'; } diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index 14d5c2f4..d313d670 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -949,6 +949,10 @@ class AppLocalizationsEt extends AppLocalizations { @override String get wordWrap => 'Reamurdmine'; + @override + String get wordWrapDescription => + 'Murrab pikad read redaktori laiusele, selle asemel et horisontaalselt kerida.'; + @override String get editorFontSize => 'Redaktori fondi suurus'; @@ -1004,6 +1008,28 @@ class AppLocalizationsEt extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Küsi varem usaldatud tööruumides Giti funktsioonide lubamisel uuesti kinnitust.'; + @override + String get settingsEditingButtonsSectionTitle => 'Redigeerimisnupud'; + + @override + String get spellingDictionaries => 'Õigekirjasõnastikud'; + + @override + String get spellingDictionariesDescription => + 'Õigekirjasõnastike installimine ja haldamine'; + + @override + String get settingsDictionariesSectionTitle => 'Sõnastikud'; + + @override + String get availableSpellingDictionaries => 'Saadaolevad sõnastikud'; + + @override + String get customSpellingDictionaries => 'Kohandatud sõnastikud'; + + @override + String get spellingDictionaryProblems => 'Sõnastikuprobleemid'; + @override String get settingsWindowSectionTitle => 'Aken'; @@ -4490,8 +4516,131 @@ class AppLocalizationsEt extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Õigekiri'; + + @override + String get automaticSpelling => 'Automaatne õigekirjakontroll'; + + @override + String get defaultSpellingLanguage => 'Vaikimisi õigekirjakeel'; + + @override + String get projectSpellingLanguage => 'Projekti õigekirjakontrolli keel'; + + @override + String get chooseSpellingLanguage => 'Vali õigekirjakeel'; + + @override + String get spellingLanguageUnsetStatus => 'Keel…'; + + @override + String get spellingOffStatus => 'Õigekirjakontroll väljas'; + + @override + String get checkSpelling => 'Kontrolli õigekirja'; + + @override + String get ignoreSpellingOnce => 'Eira üks kord'; + + @override + String get ignoreSpellingDocument => 'Eira selles dokumendis kõiki'; + + @override + String get addPersonalSpellingWord => 'Lisa isiklikku sõnastikku'; + + @override + String get addProjectSpellingWord => 'Lisa projekti sõnastikku'; + + @override + String get inheritSpellingLanguage => 'Kasuta projekti või rakenduse keelt'; + + @override + String get disableDocumentSpelling => 'Ära kontrolli õigekirja'; + + @override + String get importSpellingDictionary => 'Impordi sõnastik'; + + @override + String get personalSpellingDictionary => 'Isiklik sõnastik'; + + @override + String get projectSpellingDictionary => 'Projekti sõnastik'; + + @override + String get noSpellingErrors => 'Õigekirjavigu pole'; + + @override + String get noSpellingSuggestions => 'Õigekirjasoovitusi pole'; + + @override + String get spellingWordCheckFailed => 'Seda sõna ei saanud kontrollida'; + + @override + String get spellingCheckFailed => 'Õigekirjakontroll nurjus'; + + @override + String get spellingCheckIncomplete => 'Õigekirjakontroll on pooleli'; + + @override + String get spellingDictionaryNotInstalled => 'Sõnastik pole installitud'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary sõnastik pole installitud'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Pole installitud · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installitud'; + + @override + String get installSpellingDictionary => 'Installi sõnastik'; + + @override + String get removeSpellingDictionary => 'Eemalda sõnastik'; + + @override + String get cancelSpellingDictionaryInstall => + 'Katkesta sõnastiku allalaadimine'; + + @override + String get retrySpellingDictionaryInstall => + 'Proovi sõnastikku uuesti installida'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Allalaadimine: $size…'; + } + + @override + String get spellingDictionaryValidating => 'Sõnastiku kontrollimine…'; + + @override + String get spellingDictionaryInstallFailed => + 'Sõnastiku installimine nurjus — uuesti proovimiseks vali see'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Kas installida $dictionary ($size)? Pärast installimist on see võrguühenduseta saadaval, kuni selle eemaldad.'; + } + + @override + String get spellingDictionaryUnavailable => 'Sõnastik pole saadaval'; + + @override + String get spellingChecking => 'Õigekirja kontrollimine…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: sisesta arv vahemikus $minimum kuni $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Õigekirjasõnastikku muudeti väliselt. Taastekoopia säilitati.'; } diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index 984e23bf..cf14e58c 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -944,6 +944,10 @@ class AppLocalizationsFa extends AppLocalizations { @override String get wordWrap => 'شکستن خودکار خطوط'; + @override + String get wordWrapDescription => + 'سطرهای بلند را به‌جای پیمایش افقی متناسب با عرض ویرایشگر می‌شکند.'; + @override String get editorFontSize => 'اندازهٔ قلم ویرایشگر'; @@ -997,6 +1001,28 @@ class AppLocalizationsFa extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'پیش از فعال‌کردن ویژگی‌های Git برای فضاهای کاری که قبلاً مورد اعتماد بوده‌اند، پرسیده شود.'; + @override + String get settingsEditingButtonsSectionTitle => 'دکمه‌های ویرایش'; + + @override + String get spellingDictionaries => 'واژه‌نامه‌های املایی'; + + @override + String get spellingDictionariesDescription => + 'نصب و مدیریت واژه‌نامه‌های املایی'; + + @override + String get settingsDictionariesSectionTitle => 'واژه‌نامه‌ها'; + + @override + String get availableSpellingDictionaries => 'واژه‌نامه‌های موجود'; + + @override + String get customSpellingDictionaries => 'واژه‌نامه‌های سفارشی'; + + @override + String get spellingDictionaryProblems => 'مشکلات واژه‌نامه'; + @override String get settingsWindowSectionTitle => 'پنجره'; @@ -4531,8 +4557,129 @@ class AppLocalizationsFa extends AppLocalizations { return '$value مگابایت'; } + @override + String get spelling => 'املا'; + + @override + String get automaticSpelling => 'بررسی خودکار املا'; + + @override + String get defaultSpellingLanguage => 'زبان پیش‌فرض بررسی املا'; + + @override + String get projectSpellingLanguage => 'زبان غلط‌یابی پروژه'; + + @override + String get chooseSpellingLanguage => 'انتخاب زبان املا'; + + @override + String get spellingLanguageUnsetStatus => 'زبان…'; + + @override + String get spellingOffStatus => 'بررسی املا خاموش'; + + @override + String get checkSpelling => 'بررسی املا'; + + @override + String get ignoreSpellingOnce => 'یک‌بار نادیده بگیر'; + + @override + String get ignoreSpellingDocument => 'همه را در این سند نادیده بگیر'; + + @override + String get addPersonalSpellingWord => 'افزودن به واژه‌نامه شخصی'; + + @override + String get addProjectSpellingWord => 'افزودن به واژه‌نامه پروژه'; + + @override + String get inheritSpellingLanguage => 'استفاده از زبان پروژه یا برنامه'; + + @override + String get disableDocumentSpelling => 'املاء بررسی نشود'; + + @override + String get importSpellingDictionary => 'درون‌ریزی واژه‌نامه'; + + @override + String get personalSpellingDictionary => 'واژه‌نامه شخصی'; + + @override + String get projectSpellingDictionary => 'واژه‌نامه پروژه'; + + @override + String get noSpellingErrors => 'خطای املایی وجود ندارد'; + + @override + String get noSpellingSuggestions => 'پیشنهاد املایی وجود ندارد'; + + @override + String get spellingWordCheckFailed => 'بررسی این واژه ممکن نشد'; + + @override + String get spellingCheckFailed => 'بررسی املا ناموفق بود'; + + @override + String get spellingCheckIncomplete => 'بررسی املا کامل نیست'; + + @override + String get spellingDictionaryNotInstalled => 'واژه‌نامه نصب نشده است'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'واژه‌نامهٔ ⁨$dictionary⁩ نصب نشده است'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'نصب‌نشده · ⁨$size⁩'; + } + + @override + String get spellingDictionaryInstalled => 'نصب‌شده'; + + @override + String get installSpellingDictionary => 'نصب واژه‌نامه'; + + @override + String get removeSpellingDictionary => 'حذف واژه‌نامه'; + + @override + String get cancelSpellingDictionaryInstall => 'لغو بارگیری واژه‌نامه'; + + @override + String get retrySpellingDictionaryInstall => 'تلاش دوباره برای نصب واژه‌نامه'; + + @override + String spellingDictionaryDownloading(String size) { + return 'در حال بارگیری ⁨$size⁩…'; + } + + @override + String get spellingDictionaryValidating => 'در حال اعتبارسنجی واژه‌نامه…'; + + @override + String get spellingDictionaryInstallFailed => + 'نصب واژه‌نامه ناموفق بود — برای تلاش دوباره انتخاب کنید'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'واژه‌نامهٔ ⁨$dictionary⁩ (⁨$size⁩) نصب شود؟ پس از نصب تا زمانی که آن را حذف نکنید، آفلاین در دسترس می‌ماند.'; + } + + @override + String get spellingDictionaryUnavailable => 'واژه‌نامه در دسترس نیست'; + + @override + String get spellingChecking => 'در حال بررسی املا…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: عددی بین $minimum و $maximum وارد کنید.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'فرهنگ لغت املایی به‌صورت خارجی تغییر کرد. یک نسخهٔ بازیابی حفظ شد.'; } diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 872d7a8f..8952190b 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -967,6 +967,10 @@ class AppLocalizationsFr extends AppLocalizations { @override String get wordWrap => 'Retour à la ligne automatique'; + @override + String get wordWrapDescription => + 'Ajuster les lignes longues à la largeur de l’éditeur plutôt que de les faire défiler horizontalement.'; + @override String get editorFontSize => 'Taille de la police de l’éditeur'; @@ -1022,6 +1026,28 @@ class AppLocalizationsFr extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Demander confirmation avant d’activer les fonctions Git pour les espaces de travail précédemment approuvés.'; + @override + String get settingsEditingButtonsSectionTitle => 'Boutons d’édition'; + + @override + String get spellingDictionaries => 'Dictionnaires orthographiques'; + + @override + String get spellingDictionariesDescription => + 'Installer et gérer les dictionnaires orthographiques'; + + @override + String get settingsDictionariesSectionTitle => 'Dictionnaires'; + + @override + String get availableSpellingDictionaries => 'Dictionnaires disponibles'; + + @override + String get customSpellingDictionaries => 'Dictionnaires personnalisés'; + + @override + String get spellingDictionaryProblems => 'Problèmes de dictionnaires'; + @override String get settingsWindowSectionTitle => 'Fenêtre'; @@ -4535,8 +4561,133 @@ class AppLocalizationsFr extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Orthographe'; + + @override + String get automaticSpelling => 'Vérification orthographique automatique'; + + @override + String get defaultSpellingLanguage => 'Langue orthographique par défaut'; + + @override + String get projectSpellingLanguage => 'Langue de correction du projet'; + + @override + String get chooseSpellingLanguage => 'Choisir la langue orthographique'; + + @override + String get spellingLanguageUnsetStatus => 'Langue…'; + + @override + String get spellingOffStatus => 'Orthographe désactivée'; + + @override + String get checkSpelling => 'Vérifier l’orthographe'; + + @override + String get ignoreSpellingOnce => 'Ignorer une fois'; + + @override + String get ignoreSpellingDocument => 'Tout ignorer dans ce document'; + + @override + String get addPersonalSpellingWord => 'Ajouter au dictionnaire personnel'; + + @override + String get addProjectSpellingWord => 'Ajouter au dictionnaire du projet'; + + @override + String get inheritSpellingLanguage => + 'Utiliser la langue du projet ou de l’application'; + + @override + String get disableDocumentSpelling => 'Ne pas vérifier l’orthographe'; + + @override + String get importSpellingDictionary => 'Importer un dictionnaire'; + + @override + String get personalSpellingDictionary => 'Dictionnaire personnel'; + + @override + String get projectSpellingDictionary => 'Dictionnaire du projet'; + + @override + String get noSpellingErrors => 'Aucune faute d’orthographe'; + + @override + String get noSpellingSuggestions => 'Aucune suggestion orthographique'; + + @override + String get spellingWordCheckFailed => 'Impossible de vérifier ce mot'; + + @override + String get spellingCheckFailed => 'Échec de la vérification orthographique'; + + @override + String get spellingCheckIncomplete => + 'La vérification orthographique est incomplète'; + + @override + String get spellingDictionaryNotInstalled => 'Dictionnaire non installé'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Le dictionnaire $dictionary n’est pas installé'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Non installé · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installé'; + + @override + String get installSpellingDictionary => 'Installer le dictionnaire'; + + @override + String get removeSpellingDictionary => 'Supprimer le dictionnaire'; + + @override + String get cancelSpellingDictionaryInstall => + 'Annuler le téléchargement du dictionnaire'; + + @override + String get retrySpellingDictionaryInstall => + 'Réessayer l’installation du dictionnaire'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Téléchargement de $size…'; + } + + @override + String get spellingDictionaryValidating => 'Validation du dictionnaire…'; + + @override + String get spellingDictionaryInstallFailed => + 'Échec de l’installation — sélectionnez pour réessayer'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Installer $dictionary ($size) ? Après installation, il restera disponible hors ligne jusqu’à sa suppression.'; + } + + @override + String get spellingDictionaryUnavailable => 'Dictionnaire indisponible'; + + @override + String get spellingChecking => 'Vérification de l’orthographe…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field : saisissez un nombre entre $minimum et $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Le dictionnaire orthographique a été modifié en externe. Une copie de récupération a été conservée.'; } diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index b8e1b3dd..27d7b3c9 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -945,6 +945,10 @@ class AppLocalizationsHi extends AppLocalizations { @override String get wordWrap => 'वर्ड रैप'; + @override + String get wordWrapDescription => + 'लंबी पंक्तियों को क्षैतिज रूप से स्क्रॉल करने के बजाय संपादक की चौड़ाई में समेटें।'; + @override String get editorFontSize => 'संपादक फ़ॉन्ट आकार'; @@ -998,6 +1002,28 @@ class AppLocalizationsHi extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'पहले से विश्वसनीय कार्यस्थानों के लिए Git सुविधाएँ चालू करने से पहले पूछें।'; + @override + String get settingsEditingButtonsSectionTitle => 'संपादन बटन'; + + @override + String get spellingDictionaries => 'वर्तनी शब्दकोश'; + + @override + String get spellingDictionariesDescription => + 'वर्तनी शब्दकोश इंस्टॉल और प्रबंधित करें'; + + @override + String get settingsDictionariesSectionTitle => 'शब्दकोश'; + + @override + String get availableSpellingDictionaries => 'उपलब्ध शब्दकोश'; + + @override + String get customSpellingDictionaries => 'कस्टम शब्दकोश'; + + @override + String get spellingDictionaryProblems => 'शब्दकोश समस्याएँ'; + @override String get settingsWindowSectionTitle => 'विंडो'; @@ -4483,8 +4509,129 @@ class AppLocalizationsHi extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'वर्तनी'; + + @override + String get automaticSpelling => 'स्वचालित वर्तनी जाँच'; + + @override + String get defaultSpellingLanguage => 'डिफ़ॉल्ट वर्तनी भाषा'; + + @override + String get projectSpellingLanguage => 'परियोजना की वर्तनी भाषा'; + + @override + String get chooseSpellingLanguage => 'वर्तनी भाषा चुनें'; + + @override + String get spellingLanguageUnsetStatus => 'भाषा…'; + + @override + String get spellingOffStatus => 'वर्तनी बंद'; + + @override + String get checkSpelling => 'वर्तनी जाँचें'; + + @override + String get ignoreSpellingOnce => 'एक बार अनदेखा करें'; + + @override + String get ignoreSpellingDocument => 'इस दस्तावेज़ में सभी अनदेखे करें'; + + @override + String get addPersonalSpellingWord => 'निजी शब्दकोश में जोड़ें'; + + @override + String get addProjectSpellingWord => 'परियोजना शब्दकोश में जोड़ें'; + + @override + String get inheritSpellingLanguage => 'परियोजना या ऐप की भाषा उपयोग करें'; + + @override + String get disableDocumentSpelling => 'वर्तनी जाँच न करें'; + + @override + String get importSpellingDictionary => 'शब्दकोश आयात करें'; + + @override + String get personalSpellingDictionary => 'व्यक्तिगत शब्दकोश'; + + @override + String get projectSpellingDictionary => 'परियोजना शब्दकोश'; + + @override + String get noSpellingErrors => 'कोई वर्तनी त्रुटि नहीं'; + + @override + String get noSpellingSuggestions => 'कोई वर्तनी सुझाव नहीं'; + + @override + String get spellingWordCheckFailed => 'इस शब्द की जाँच नहीं हो सकी'; + + @override + String get spellingCheckFailed => 'वर्तनी जाँच विफल रही'; + + @override + String get spellingCheckIncomplete => 'वर्तनी जाँच अधूरी है'; + + @override + String get spellingDictionaryNotInstalled => 'शब्दकोश इंस्टॉल नहीं है'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary शब्दकोश इंस्टॉल नहीं है'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'इंस्टॉल नहीं है · $size'; + } + + @override + String get spellingDictionaryInstalled => 'इंस्टॉल है'; + + @override + String get installSpellingDictionary => 'शब्दकोश इंस्टॉल करें'; + + @override + String get removeSpellingDictionary => 'शब्दकोश हटाएँ'; + + @override + String get cancelSpellingDictionaryInstall => 'शब्दकोश डाउनलोड रद्द करें'; + + @override + String get retrySpellingDictionaryInstall => 'शब्दकोश इंस्टॉलेशन फिर आज़माएँ'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size डाउनलोड हो रहा है…'; + } + + @override + String get spellingDictionaryValidating => 'शब्दकोश सत्यापित हो रहा है…'; + + @override + String get spellingDictionaryInstallFailed => + 'शब्दकोश इंस्टॉलेशन विफल — फिर प्रयास करने के लिए चुनें'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary ($size) इंस्टॉल करें? इंस्टॉल होने के बाद यह हटाए जाने तक ऑफ़लाइन उपलब्ध रहेगा।'; + } + + @override + String get spellingDictionaryUnavailable => 'शब्दकोश उपलब्ध नहीं है'; + + @override + String get spellingChecking => 'वर्तनी की जाँच हो रही है…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: $minimum से $maximum के बीच संख्या दर्ज करें।'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'वर्तनी शब्दकोश को बाहरी रूप से बदला गया। पुनर्प्राप्ति प्रति सुरक्षित रखी गई।'; } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 5e1ca88d..d8099504 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -952,6 +952,10 @@ class AppLocalizationsId extends AppLocalizations { @override String get wordWrap => 'Pindah baris otomatis'; + @override + String get wordWrapDescription => + 'Bungkus baris panjang agar sesuai dengan lebar editor alih-alih menggulir secara horizontal.'; + @override String get editorFontSize => 'Ukuran font editor'; @@ -1005,6 +1009,27 @@ class AppLocalizationsId extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Tanyakan sebelum mengaktifkan fitur Git untuk ruang kerja tepercaya sebelumnya.'; + @override + String get settingsEditingButtonsSectionTitle => 'Tombol pengeditan'; + + @override + String get spellingDictionaries => 'Kamus ejaan'; + + @override + String get spellingDictionariesDescription => 'Instal dan kelola kamus ejaan'; + + @override + String get settingsDictionariesSectionTitle => 'Kamus'; + + @override + String get availableSpellingDictionaries => 'Kamus yang tersedia'; + + @override + String get customSpellingDictionaries => 'Kamus kustom'; + + @override + String get spellingDictionaryProblems => 'Masalah kamus'; + @override String get settingsWindowSectionTitle => 'Jendela'; @@ -4493,8 +4518,129 @@ class AppLocalizationsId extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Ejaan'; + + @override + String get automaticSpelling => 'Periksa ejaan secara otomatis'; + + @override + String get defaultSpellingLanguage => 'Bahasa ejaan bawaan'; + + @override + String get projectSpellingLanguage => 'Bahasa ejaan proyek'; + + @override + String get chooseSpellingLanguage => 'Pilih bahasa ejaan'; + + @override + String get spellingLanguageUnsetStatus => 'Bahasa…'; + + @override + String get spellingOffStatus => 'Ejaan Nonaktif'; + + @override + String get checkSpelling => 'Periksa Ejaan'; + + @override + String get ignoreSpellingOnce => 'Abaikan Sekali'; + + @override + String get ignoreSpellingDocument => 'Abaikan Semua di Dokumen Ini'; + + @override + String get addPersonalSpellingWord => 'Tambahkan ke Kamus Pribadi'; + + @override + String get addProjectSpellingWord => 'Tambahkan ke Kamus Proyek'; + + @override + String get inheritSpellingLanguage => 'Gunakan bahasa proyek atau aplikasi'; + + @override + String get disableDocumentSpelling => 'Jangan periksa ejaan'; + + @override + String get importSpellingDictionary => 'Impor Kamus'; + + @override + String get personalSpellingDictionary => 'Kamus Pribadi'; + + @override + String get projectSpellingDictionary => 'Kamus Proyek'; + + @override + String get noSpellingErrors => 'Tidak ada kesalahan ejaan'; + + @override + String get noSpellingSuggestions => 'Tidak ada saran ejaan'; + + @override + String get spellingWordCheckFailed => 'Kata ini tidak dapat diperiksa'; + + @override + String get spellingCheckFailed => 'Pemeriksaan ejaan gagal'; + + @override + String get spellingCheckIncomplete => 'Pemeriksaan ejaan belum lengkap'; + + @override + String get spellingDictionaryNotInstalled => 'Kamus belum terpasang'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Kamus $dictionary belum terpasang'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Belum terpasang · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Terpasang'; + + @override + String get installSpellingDictionary => 'Pasang kamus'; + + @override + String get removeSpellingDictionary => 'Hapus kamus'; + + @override + String get cancelSpellingDictionaryInstall => 'Batalkan unduhan kamus'; + + @override + String get retrySpellingDictionaryInstall => 'Coba lagi pemasangan kamus'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Mengunduh $size…'; + } + + @override + String get spellingDictionaryValidating => 'Memvalidasi kamus…'; + + @override + String get spellingDictionaryInstallFailed => + 'Pemasangan kamus gagal — pilih untuk mencoba lagi'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Pasang $dictionary ($size)? Setelah dipasang, kamus tetap tersedia luring sampai Anda menghapusnya.'; + } + + @override + String get spellingDictionaryUnavailable => 'Kamus tidak tersedia'; + + @override + String get spellingChecking => 'Memeriksa ejaan…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: masukkan angka antara $minimum dan $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Kamus ejaan diubah secara eksternal. Salinan pemulihan telah disimpan.'; } diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 53eaa5ea..9c85d3f8 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -960,6 +960,10 @@ class AppLocalizationsIt extends AppLocalizations { @override String get wordWrap => 'A capo automatico'; + @override + String get wordWrapDescription => + 'Adatta le righe lunghe alla larghezza dell’editor invece di scorrerle orizzontalmente.'; + @override String get editorFontSize => 'Dimensione del carattere dell\'editor'; @@ -1015,6 +1019,28 @@ class AppLocalizationsIt extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Chiedi conferma prima di attivare le funzionalità Git per le aree di lavoro considerate attendibili in precedenza.'; + @override + String get settingsEditingButtonsSectionTitle => 'Pulsanti di modifica'; + + @override + String get spellingDictionaries => 'Dizionari ortografici'; + + @override + String get spellingDictionariesDescription => + 'Installa e gestisci i dizionari ortografici'; + + @override + String get settingsDictionariesSectionTitle => 'Dizionari'; + + @override + String get availableSpellingDictionaries => 'Dizionari disponibili'; + + @override + String get customSpellingDictionaries => 'Dizionari personalizzati'; + + @override + String get spellingDictionaryProblems => 'Problemi dei dizionari'; + @override String get settingsWindowSectionTitle => 'Finestra'; @@ -4529,8 +4555,132 @@ class AppLocalizationsIt extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Ortografia'; + + @override + String get automaticSpelling => 'Controllo ortografico automatico'; + + @override + String get defaultSpellingLanguage => 'Lingua ortografica predefinita'; + + @override + String get projectSpellingLanguage => + 'Lingua di controllo ortografico del progetto'; + + @override + String get chooseSpellingLanguage => 'Scegli la lingua ortografica'; + + @override + String get spellingLanguageUnsetStatus => 'Lingua…'; + + @override + String get spellingOffStatus => 'Controllo ortografico disattivato'; + + @override + String get checkSpelling => 'Controlla ortografia'; + + @override + String get ignoreSpellingOnce => 'Ignora una volta'; + + @override + String get ignoreSpellingDocument => 'Ignora tutto in questo documento'; + + @override + String get addPersonalSpellingWord => 'Aggiungi al dizionario personale'; + + @override + String get addProjectSpellingWord => 'Aggiungi al dizionario del progetto'; + + @override + String get inheritSpellingLanguage => 'Usa la lingua del progetto o dell’app'; + + @override + String get disableDocumentSpelling => 'Non controllare l’ortografia'; + + @override + String get importSpellingDictionary => 'Importa dizionario'; + + @override + String get personalSpellingDictionary => 'Dizionario personale'; + + @override + String get projectSpellingDictionary => 'Dizionario del progetto'; + + @override + String get noSpellingErrors => 'Nessun errore di ortografia'; + + @override + String get noSpellingSuggestions => 'Nessun suggerimento ortografico'; + + @override + String get spellingWordCheckFailed => 'Impossibile controllare questa parola'; + + @override + String get spellingCheckFailed => 'Controllo ortografico non riuscito'; + + @override + String get spellingCheckIncomplete => 'Il controllo ortografico è incompleto'; + + @override + String get spellingDictionaryNotInstalled => 'Dizionario non installato'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Il dizionario $dictionary non è installato'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Non installato · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installato'; + + @override + String get installSpellingDictionary => 'Installa dizionario'; + + @override + String get removeSpellingDictionary => 'Rimuovi dizionario'; + + @override + String get cancelSpellingDictionaryInstall => + 'Annulla download del dizionario'; + + @override + String get retrySpellingDictionaryInstall => + 'Riprova l’installazione del dizionario'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Download di $size…'; + } + + @override + String get spellingDictionaryValidating => 'Convalida del dizionario…'; + + @override + String get spellingDictionaryInstallFailed => + 'Installazione non riuscita — seleziona per riprovare'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Installare $dictionary ($size)? Dopo l’installazione resterà disponibile offline finché non verrà rimosso.'; + } + + @override + String get spellingDictionaryUnavailable => 'Dizionario non disponibile'; + + @override + String get spellingChecking => 'Controllo ortografico…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: inserisci un numero tra $minimum e $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Il dizionario ortografico è stato modificato esternamente. È stata conservata una copia di ripristino.'; } diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 9eb3f516..66538f3a 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -914,6 +914,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get wordWrap => '折り返し'; + @override + String get wordWrapDescription => '長い行を横方向にスクロールせず、エディターの幅に合わせて折り返します。'; + @override String get editorFontSize => 'エディターのフォントサイズ'; @@ -967,6 +970,27 @@ class AppLocalizationsJa extends AppLocalizations { String get clearGitWorkspaceTrustDescription => '以前信頼したワークスペースで Git 機能を有効にする前に確認する'; + @override + String get settingsEditingButtonsSectionTitle => '編集ボタン'; + + @override + String get spellingDictionaries => 'スペルチェック辞書'; + + @override + String get spellingDictionariesDescription => 'スペルチェック辞書をインストールして管理'; + + @override + String get settingsDictionariesSectionTitle => '辞書'; + + @override + String get availableSpellingDictionaries => '利用可能な辞書'; + + @override + String get customSpellingDictionaries => 'カスタム辞書'; + + @override + String get spellingDictionaryProblems => '辞書の問題'; + @override String get settingsWindowSectionTitle => 'ウィンドウ'; @@ -4367,8 +4391,128 @@ class AppLocalizationsJa extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'スペルチェック'; + + @override + String get automaticSpelling => '自動スペルチェック'; + + @override + String get defaultSpellingLanguage => '既定のスペルチェック言語'; + + @override + String get projectSpellingLanguage => 'プロジェクトのスペルチェック言語'; + + @override + String get chooseSpellingLanguage => 'スペルチェック言語を選択'; + + @override + String get spellingLanguageUnsetStatus => '言語…'; + + @override + String get spellingOffStatus => 'スペルチェック オフ'; + + @override + String get checkSpelling => 'スペルチェック'; + + @override + String get ignoreSpellingOnce => '一度だけ無視'; + + @override + String get ignoreSpellingDocument => 'この文書ですべて無視'; + + @override + String get addPersonalSpellingWord => '個人辞書に追加'; + + @override + String get addProjectSpellingWord => 'プロジェクト辞書に追加'; + + @override + String get inheritSpellingLanguage => 'プロジェクトまたはアプリの言語を使用'; + + @override + String get disableDocumentSpelling => 'スペルチェックしない'; + + @override + String get importSpellingDictionary => '辞書をインポート'; + + @override + String get personalSpellingDictionary => '個人辞書'; + + @override + String get projectSpellingDictionary => 'プロジェクト辞書'; + + @override + String get noSpellingErrors => 'スペルミスはありません'; + + @override + String get noSpellingSuggestions => 'スペル候補はありません'; + + @override + String get spellingWordCheckFailed => 'この単語を確認できませんでした'; + + @override + String get spellingCheckFailed => 'スペルチェックに失敗しました'; + + @override + String get spellingCheckIncomplete => 'スペルチェックが完了していません'; + + @override + String get spellingDictionaryNotInstalled => '辞書がインストールされていません'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary の辞書がインストールされていません'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return '未インストール · $size'; + } + + @override + String get spellingDictionaryInstalled => 'インストール済み'; + + @override + String get installSpellingDictionary => '辞書をインストール'; + + @override + String get removeSpellingDictionary => '辞書を削除'; + + @override + String get cancelSpellingDictionaryInstall => '辞書のダウンロードをキャンセル'; + + @override + String get retrySpellingDictionaryInstall => '辞書のインストールを再試行'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size をダウンロード中…'; + } + + @override + String get spellingDictionaryValidating => '辞書を検証中…'; + + @override + String get spellingDictionaryInstallFailed => '辞書のインストールに失敗しました — 選択して再試行'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary($size)をインストールしますか?インストール後は削除するまでオフラインで利用できます。'; + } + + @override + String get spellingDictionaryUnavailable => '辞書を利用できません'; + + @override + String get spellingChecking => 'スペルを確認中…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: $minimum から $maximum の数値を入力してください。'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'スペルチェック辞書が外部で変更されました。復旧用コピーを保持しました。'; } diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 66c566d7..a38007c9 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -909,6 +909,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get wordWrap => '자동 줄 바꿈'; + @override + String get wordWrapDescription => '긴 줄을 가로로 스크롤하지 않고 편집기 너비에 맞게 줄 바꿈합니다.'; + @override String get editorFontSize => '편집기 글꼴 크기'; @@ -962,6 +965,27 @@ class AppLocalizationsKo extends AppLocalizations { String get clearGitWorkspaceTrustDescription => '이전에 신뢰한 작업공간에서 Git 기능을 활성화하기 전에 확인하도록 설정합니다.'; + @override + String get settingsEditingButtonsSectionTitle => '편집 버튼'; + + @override + String get spellingDictionaries => '맞춤법 검사 사전'; + + @override + String get spellingDictionariesDescription => '맞춤법 검사 사전 설치 및 관리'; + + @override + String get settingsDictionariesSectionTitle => '사전'; + + @override + String get availableSpellingDictionaries => '사용 가능한 사전'; + + @override + String get customSpellingDictionaries => '사용자 지정 사전'; + + @override + String get spellingDictionaryProblems => '사전 문제'; + @override String get settingsWindowSectionTitle => '창'; @@ -4361,8 +4385,128 @@ class AppLocalizationsKo extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => '맞춤법'; + + @override + String get automaticSpelling => '자동 맞춤법 검사'; + + @override + String get defaultSpellingLanguage => '기본 맞춤법 언어'; + + @override + String get projectSpellingLanguage => '프로젝트 맞춤법 검사 언어'; + + @override + String get chooseSpellingLanguage => '맞춤법 언어 선택'; + + @override + String get spellingLanguageUnsetStatus => '언어…'; + + @override + String get spellingOffStatus => '맞춤법 검사 끄기'; + + @override + String get checkSpelling => '맞춤법 검사'; + + @override + String get ignoreSpellingOnce => '한 번 무시'; + + @override + String get ignoreSpellingDocument => '이 문서에서 모두 무시'; + + @override + String get addPersonalSpellingWord => '개인 사전에 추가'; + + @override + String get addProjectSpellingWord => '프로젝트 사전에 추가'; + + @override + String get inheritSpellingLanguage => '프로젝트 또는 앱 언어 사용'; + + @override + String get disableDocumentSpelling => '맞춤법 검사 안 함'; + + @override + String get importSpellingDictionary => '사전 가져오기'; + + @override + String get personalSpellingDictionary => '개인 사전'; + + @override + String get projectSpellingDictionary => '프로젝트 사전'; + + @override + String get noSpellingErrors => '맞춤법 오류가 없습니다'; + + @override + String get noSpellingSuggestions => '맞춤법 제안이 없습니다'; + + @override + String get spellingWordCheckFailed => '이 단어를 확인할 수 없습니다'; + + @override + String get spellingCheckFailed => '맞춤법 검사에 실패했습니다'; + + @override + String get spellingCheckIncomplete => '맞춤법 검사가 완료되지 않았습니다'; + + @override + String get spellingDictionaryNotInstalled => '사전이 설치되지 않음'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary 사전이 설치되지 않았습니다'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return '설치되지 않음 · $size'; + } + + @override + String get spellingDictionaryInstalled => '설치됨'; + + @override + String get installSpellingDictionary => '사전 설치'; + + @override + String get removeSpellingDictionary => '사전 제거'; + + @override + String get cancelSpellingDictionaryInstall => '사전 다운로드 취소'; + + @override + String get retrySpellingDictionaryInstall => '사전 설치 다시 시도'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size 다운로드 중…'; + } + + @override + String get spellingDictionaryValidating => '사전 검증 중…'; + + @override + String get spellingDictionaryInstallFailed => '사전 설치 실패 — 선택하여 다시 시도'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary($size)을 설치하시겠습니까? 설치 후 제거할 때까지 오프라인에서 사용할 수 있습니다.'; + } + + @override + String get spellingDictionaryUnavailable => '사전을 사용할 수 없습니다'; + + @override + String get spellingChecking => '맞춤법 검사 중…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: $minimum에서 $maximum 사이의 숫자를 입력하세요.'; } + + @override + String get spellingDictionaryRecoveryConflict => + '맞춤법 사전이 외부에서 변경되었습니다. 복구 사본을 보존했습니다.'; } diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index ef1db2ee..82239d9f 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -952,6 +952,10 @@ class AppLocalizationsNb extends AppLocalizations { @override String get wordWrap => 'Tekstbryting'; + @override + String get wordWrapDescription => + 'Bryt lange linjer så de passer til redigeringsbredden i stedet for å rulle vannrett.'; + @override String get editorFontSize => 'Skriftstørrelse i redigereren'; @@ -1006,6 +1010,28 @@ class AppLocalizationsNb extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Spør før Git-funksjoner aktiveres for tidligere klarerte arbeidsområder.'; + @override + String get settingsEditingButtonsSectionTitle => 'Redigeringsknapper'; + + @override + String get spellingDictionaries => 'Stavekontrollordbøker'; + + @override + String get spellingDictionariesDescription => + 'Installer og administrer stavekontrollordbøker'; + + @override + String get settingsDictionariesSectionTitle => 'Ordbøker'; + + @override + String get availableSpellingDictionaries => 'Tilgjengelige ordbøker'; + + @override + String get customSpellingDictionaries => 'Egendefinerte ordbøker'; + + @override + String get spellingDictionaryProblems => 'Ordbokproblemer'; + @override String get settingsWindowSectionTitle => 'Vindu'; @@ -4491,8 +4517,130 @@ class AppLocalizationsNb extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Stavekontroll'; + + @override + String get automaticSpelling => 'Automatisk stavekontroll'; + + @override + String get defaultSpellingLanguage => 'Standard språk for stavekontroll'; + + @override + String get projectSpellingLanguage => 'Prosjektspråk for stavekontroll'; + + @override + String get chooseSpellingLanguage => 'Velg språk for stavekontroll'; + + @override + String get spellingLanguageUnsetStatus => 'Språk…'; + + @override + String get spellingOffStatus => 'Stavekontroll av'; + + @override + String get checkSpelling => 'Kontroller staving'; + + @override + String get ignoreSpellingOnce => 'Ignorer én gang'; + + @override + String get ignoreSpellingDocument => 'Ignorer alle i dette dokumentet'; + + @override + String get addPersonalSpellingWord => 'Legg til i personlig ordliste'; + + @override + String get addProjectSpellingWord => 'Legg til i prosjektordlisten'; + + @override + String get inheritSpellingLanguage => 'Bruk prosjekt- eller programspråk'; + + @override + String get disableDocumentSpelling => 'Ikke kontroller staving'; + + @override + String get importSpellingDictionary => 'Importer ordliste'; + + @override + String get personalSpellingDictionary => 'Personlig ordliste'; + + @override + String get projectSpellingDictionary => 'Prosjektordliste'; + + @override + String get noSpellingErrors => 'Ingen stavefeil'; + + @override + String get noSpellingSuggestions => 'Ingen staveforslag'; + + @override + String get spellingWordCheckFailed => 'Kunne ikke kontrollere dette ordet'; + + @override + String get spellingCheckFailed => 'Stavekontrollen mislyktes'; + + @override + String get spellingCheckIncomplete => 'Stavekontrollen er ufullstendig'; + + @override + String get spellingDictionaryNotInstalled => 'Ordliste er ikke installert'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Ordlisten for $dictionary er ikke installert'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Ikke installert · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Installert'; + + @override + String get installSpellingDictionary => 'Installer ordliste'; + + @override + String get removeSpellingDictionary => 'Fjern ordliste'; + + @override + String get cancelSpellingDictionaryInstall => 'Avbryt nedlasting av ordliste'; + + @override + String get retrySpellingDictionaryInstall => + 'Prøv å installere ordlisten på nytt'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Laster ned $size…'; + } + + @override + String get spellingDictionaryValidating => 'Validerer ordliste…'; + + @override + String get spellingDictionaryInstallFailed => + 'Installasjonen mislyktes — velg for å prøve på nytt'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Installere $dictionary ($size)? Etter installering er den tilgjengelig frakoblet til du fjerner den.'; + } + + @override + String get spellingDictionaryUnavailable => 'Ordliste utilgjengelig'; + + @override + String get spellingChecking => 'Kontrollerer staving…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: skriv inn et tall mellom $minimum og $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Staveordboken ble endret eksternt. En gjenopprettingskopi ble bevart.'; } diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index c84b0b31..71d37bfe 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -953,6 +953,10 @@ class AppLocalizationsNl extends AppLocalizations { @override String get wordWrap => 'Regelterugloop'; + @override + String get wordWrapDescription => + 'Laat lange regels op de editorbreedte doorlopen in plaats van horizontaal te schuiven.'; + @override String get editorFontSize => 'Lettergrootte van de editor'; @@ -1007,6 +1011,28 @@ class AppLocalizationsNl extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Vraag dit voordat u Git-functies inschakelt voor eerder vertrouwde werkruimten.'; + @override + String get settingsEditingButtonsSectionTitle => 'Bewerkingsknoppen'; + + @override + String get spellingDictionaries => 'Spellingswoordenboeken'; + + @override + String get spellingDictionariesDescription => + 'Spellingswoordenboeken installeren en beheren'; + + @override + String get settingsDictionariesSectionTitle => 'Woordenboeken'; + + @override + String get availableSpellingDictionaries => 'Beschikbare woordenboeken'; + + @override + String get customSpellingDictionaries => 'Aangepaste woordenboeken'; + + @override + String get spellingDictionaryProblems => 'Woordenboekproblemen'; + @override String get settingsWindowSectionTitle => 'Raam'; @@ -4535,8 +4561,132 @@ class AppLocalizationsNl extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Spellingcontrole'; + + @override + String get automaticSpelling => 'Spelling automatisch controleren'; + + @override + String get defaultSpellingLanguage => 'Standaardtaal voor spelling'; + + @override + String get projectSpellingLanguage => 'Projecttaal voor spelling'; + + @override + String get chooseSpellingLanguage => 'Taal voor spelling kiezen'; + + @override + String get spellingLanguageUnsetStatus => 'Taal…'; + + @override + String get spellingOffStatus => 'Spelling uit'; + + @override + String get checkSpelling => 'Spelling controleren'; + + @override + String get ignoreSpellingOnce => 'Eenmaal negeren'; + + @override + String get ignoreSpellingDocument => 'Alles in dit document negeren'; + + @override + String get addPersonalSpellingWord => 'Aan persoonlijk woordenboek toevoegen'; + + @override + String get addProjectSpellingWord => 'Aan projectwoordenboek toevoegen'; + + @override + String get inheritSpellingLanguage => 'Project- of toepassingstaal gebruiken'; + + @override + String get disableDocumentSpelling => 'Spelling niet controleren'; + + @override + String get importSpellingDictionary => 'Woordenboek importeren'; + + @override + String get personalSpellingDictionary => 'Persoonlijk woordenboek'; + + @override + String get projectSpellingDictionary => 'Projectwoordenboek'; + + @override + String get noSpellingErrors => 'Geen spelfouten'; + + @override + String get noSpellingSuggestions => 'Geen spellingsuggesties'; + + @override + String get spellingWordCheckFailed => + 'Dit woord kon niet worden gecontroleerd'; + + @override + String get spellingCheckFailed => 'Spellingcontrole mislukt'; + + @override + String get spellingCheckIncomplete => 'De spellingcontrole is onvolledig'; + + @override + String get spellingDictionaryNotInstalled => 'Woordenboek niet geïnstalleerd'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Het woordenboek voor $dictionary is niet geïnstalleerd'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Niet geïnstalleerd · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Geïnstalleerd'; + + @override + String get installSpellingDictionary => 'Woordenboek installeren'; + + @override + String get removeSpellingDictionary => 'Woordenboek verwijderen'; + + @override + String get cancelSpellingDictionaryInstall => + 'Download van woordenboek annuleren'; + + @override + String get retrySpellingDictionaryInstall => + 'Installatie van woordenboek opnieuw proberen'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size downloaden…'; + } + + @override + String get spellingDictionaryValidating => 'Woordenboek valideren…'; + + @override + String get spellingDictionaryInstallFailed => + 'Installatie mislukt — selecteer om opnieuw te proberen'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary ($size) installeren? Daarna blijft het offline beschikbaar totdat u het verwijdert.'; + } + + @override + String get spellingDictionaryUnavailable => 'Woordenboek niet beschikbaar'; + + @override + String get spellingChecking => 'Spelling controleren…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: voer een getal tussen $minimum en $maximum in.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Het spellingwoordenboek is extern gewijzigd. Er is een herstelkopie bewaard.'; } diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 36d8894a..24a9c53d 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -958,6 +958,10 @@ class AppLocalizationsPl extends AppLocalizations { @override String get wordWrap => 'Zawijanie wierszy'; + @override + String get wordWrapDescription => + 'Zawijaj długie wiersze do szerokości edytora zamiast przewijać je poziomo.'; + @override String get editorFontSize => 'Rozmiar czcionki edytora'; @@ -1013,6 +1017,28 @@ class AppLocalizationsPl extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Pytaj przed włączeniem funkcji Git w zaufanych wcześniej obszarach roboczych.'; + @override + String get settingsEditingButtonsSectionTitle => 'Przyciski edycji'; + + @override + String get spellingDictionaries => 'Słowniki pisowni'; + + @override + String get spellingDictionariesDescription => + 'Instaluj słowniki pisowni i zarządzaj nimi'; + + @override + String get settingsDictionariesSectionTitle => 'Słowniki'; + + @override + String get availableSpellingDictionaries => 'Dostępne słowniki'; + + @override + String get customSpellingDictionaries => 'Słowniki niestandardowe'; + + @override + String get spellingDictionaryProblems => 'Problemy ze słownikami'; + @override String get settingsWindowSectionTitle => 'Okno'; @@ -4545,8 +4571,129 @@ class AppLocalizationsPl extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Pisownia'; + + @override + String get automaticSpelling => 'Automatyczne sprawdzanie pisowni'; + + @override + String get defaultSpellingLanguage => 'Domyślny język pisowni'; + + @override + String get projectSpellingLanguage => 'Język sprawdzania pisowni projektu'; + + @override + String get chooseSpellingLanguage => 'Wybierz język pisowni'; + + @override + String get spellingLanguageUnsetStatus => 'Język…'; + + @override + String get spellingOffStatus => 'Pisownia wyłączona'; + + @override + String get checkSpelling => 'Sprawdź pisownię'; + + @override + String get ignoreSpellingOnce => 'Ignoruj raz'; + + @override + String get ignoreSpellingDocument => 'Ignoruj wszystkie w tym dokumencie'; + + @override + String get addPersonalSpellingWord => 'Dodaj do słownika osobistego'; + + @override + String get addProjectSpellingWord => 'Dodaj do słownika projektu'; + + @override + String get inheritSpellingLanguage => 'Użyj języka projektu lub aplikacji'; + + @override + String get disableDocumentSpelling => 'Nie sprawdzaj pisowni'; + + @override + String get importSpellingDictionary => 'Importuj słownik'; + + @override + String get personalSpellingDictionary => 'Słownik osobisty'; + + @override + String get projectSpellingDictionary => 'Słownik projektu'; + + @override + String get noSpellingErrors => 'Brak błędów pisowni'; + + @override + String get noSpellingSuggestions => 'Brak sugestii pisowni'; + + @override + String get spellingWordCheckFailed => 'Nie można sprawdzić tego słowa'; + + @override + String get spellingCheckFailed => 'Sprawdzanie pisowni nie powiodło się'; + + @override + String get spellingCheckIncomplete => 'Sprawdzanie pisowni jest niepełne'; + + @override + String get spellingDictionaryNotInstalled => 'Słownik nie jest zainstalowany'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Słownik $dictionary nie jest zainstalowany'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Niezainstalowany · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Zainstalowany'; + + @override + String get installSpellingDictionary => 'Zainstaluj słownik'; + + @override + String get removeSpellingDictionary => 'Usuń słownik'; + + @override + String get cancelSpellingDictionaryInstall => 'Anuluj pobieranie słownika'; + + @override + String get retrySpellingDictionaryInstall => 'Ponów instalację słownika'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Pobieranie $size…'; + } + + @override + String get spellingDictionaryValidating => 'Sprawdzanie słownika…'; + + @override + String get spellingDictionaryInstallFailed => + 'Instalacja nie powiodła się — wybierz, aby ponowić'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Zainstalować $dictionary ($size)? Po instalacji będzie dostępny offline do czasu usunięcia.'; + } + + @override + String get spellingDictionaryUnavailable => 'Słownik jest niedostępny'; + + @override + String get spellingChecking => 'Sprawdzanie pisowni…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: wpisz liczbę między $minimum a $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Słownik pisowni został zmieniony zewnętrznie. Zachowano kopię odzyskiwania.'; } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index ada2ec6f..6df76e1d 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -958,6 +958,10 @@ class AppLocalizationsPt extends AppLocalizations { @override String get wordWrap => 'Quebra de linha'; + @override + String get wordWrapDescription => + 'Ajustar linhas longas à largura do editor em vez de deslocar horizontalmente.'; + @override String get editorFontSize => 'Tamanho da fonte do editor'; @@ -1013,6 +1017,28 @@ class AppLocalizationsPt extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Perguntar antes de ativar recursos do Git em espaços de trabalho considerados confiáveis anteriormente.'; + @override + String get settingsEditingButtonsSectionTitle => 'Botões de edição'; + + @override + String get spellingDictionaries => 'Dicionários ortográficos'; + + @override + String get spellingDictionariesDescription => + 'Instalar e gerir dicionários ortográficos'; + + @override + String get settingsDictionariesSectionTitle => 'Dicionários'; + + @override + String get availableSpellingDictionaries => 'Dicionários disponíveis'; + + @override + String get customSpellingDictionaries => 'Dicionários personalizados'; + + @override + String get spellingDictionaryProblems => 'Problemas de dicionários'; + @override String get settingsWindowSectionTitle => 'Janela'; @@ -4546,10 +4572,137 @@ class AppLocalizationsPt extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Ortografia'; + + @override + String get automaticSpelling => 'Verificação ortográfica automática'; + + @override + String get defaultSpellingLanguage => 'Idioma ortográfico predefinido'; + + @override + String get projectSpellingLanguage => + 'Idioma de verificação ortográfica do projeto'; + + @override + String get chooseSpellingLanguage => 'Escolher idioma ortográfico'; + + @override + String get spellingLanguageUnsetStatus => 'Idioma…'; + + @override + String get spellingOffStatus => 'Ortografia desativada'; + + @override + String get checkSpelling => 'Verificar ortografia'; + + @override + String get ignoreSpellingOnce => 'Ignorar uma vez'; + + @override + String get ignoreSpellingDocument => 'Ignorar tudo neste documento'; + + @override + String get addPersonalSpellingWord => 'Adicionar ao dicionário pessoal'; + + @override + String get addProjectSpellingWord => 'Adicionar ao dicionário do projeto'; + + @override + String get inheritSpellingLanguage => + 'Usar o idioma do projeto ou da aplicação'; + + @override + String get disableDocumentSpelling => 'Não verificar a ortografia'; + + @override + String get importSpellingDictionary => 'Importar dicionário'; + + @override + String get personalSpellingDictionary => 'Dicionário pessoal'; + + @override + String get projectSpellingDictionary => 'Dicionário do projeto'; + + @override + String get noSpellingErrors => 'Sem erros ortográficos'; + + @override + String get noSpellingSuggestions => 'Sem sugestões ortográficas'; + + @override + String get spellingWordCheckFailed => + 'Não foi possível verificar esta palavra'; + + @override + String get spellingCheckFailed => 'A verificação ortográfica falhou'; + + @override + String get spellingCheckIncomplete => + 'A verificação ortográfica está incompleta'; + + @override + String get spellingDictionaryNotInstalled => 'Dicionário não instalado'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'O dicionário de $dictionary não está instalado'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Não instalado · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Instalado'; + + @override + String get installSpellingDictionary => 'Instalar dicionário'; + + @override + String get removeSpellingDictionary => 'Remover dicionário'; + + @override + String get cancelSpellingDictionaryInstall => + 'Cancelar transferência do dicionário'; + + @override + String get retrySpellingDictionaryInstall => + 'Repetir instalação do dicionário'; + + @override + String spellingDictionaryDownloading(String size) { + return 'A transferir $size…'; + } + + @override + String get spellingDictionaryValidating => 'A validar o dicionário…'; + + @override + String get spellingDictionaryInstallFailed => + 'A instalação falhou — selecione para repetir'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Instalar $dictionary ($size)? Depois de instalado, ficará disponível offline até ser removido.'; + } + + @override + String get spellingDictionaryUnavailable => 'Dicionário indisponível'; + + @override + String get spellingChecking => 'A verificar a ortografia…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: introduza um número entre $minimum e $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'O dicionário ortográfico foi alterado externamente. Foi preservada uma cópia de recuperação.'; } /// The translations for Portuguese, as used in Brazil (`pt_BR`). @@ -5505,6 +5658,10 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get wordWrap => 'Quebra de linha'; + @override + String get wordWrapDescription => + 'Quebre linhas longas para ajustá-las à largura do editor em vez de rolar horizontalmente.'; + @override String get editorFontSize => 'Tamanho da fonte do editor'; @@ -5560,6 +5717,28 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { String get clearGitWorkspaceTrustDescription => 'Perguntar antes de ativar recursos do Git em espaços de trabalho considerados confiáveis anteriormente.'; + @override + String get settingsEditingButtonsSectionTitle => 'Botões de edição'; + + @override + String get spellingDictionaries => 'Dicionários ortográficos'; + + @override + String get spellingDictionariesDescription => + 'Instalar e gerenciar dicionários ortográficos'; + + @override + String get settingsDictionariesSectionTitle => 'Dicionários'; + + @override + String get availableSpellingDictionaries => 'Dicionários disponíveis'; + + @override + String get customSpellingDictionaries => 'Dicionários personalizados'; + + @override + String get spellingDictionaryProblems => 'Problemas de dicionários'; + @override String get settingsWindowSectionTitle => 'Janela'; @@ -9091,8 +9270,135 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { return '$value MiB'; } + @override + String get spelling => 'Ortografia'; + + @override + String get automaticSpelling => 'Verificação ortográfica automática'; + + @override + String get defaultSpellingLanguage => 'Idioma ortográfico padrão'; + + @override + String get projectSpellingLanguage => + 'Idioma de verificação ortográfica do projeto'; + + @override + String get chooseSpellingLanguage => 'Escolher idioma ortográfico'; + + @override + String get spellingLanguageUnsetStatus => 'Idioma…'; + + @override + String get spellingOffStatus => 'Ortografia desativada'; + + @override + String get checkSpelling => 'Verificar ortografia'; + + @override + String get ignoreSpellingOnce => 'Ignorar uma vez'; + + @override + String get ignoreSpellingDocument => 'Ignorar tudo neste documento'; + + @override + String get addPersonalSpellingWord => 'Adicionar ao dicionário pessoal'; + + @override + String get addProjectSpellingWord => 'Adicionar ao dicionário do projeto'; + + @override + String get inheritSpellingLanguage => + 'Usar o idioma do projeto ou do aplicativo'; + + @override + String get disableDocumentSpelling => 'Não verificar a ortografia'; + + @override + String get importSpellingDictionary => 'Importar dicionário'; + + @override + String get personalSpellingDictionary => 'Dicionário pessoal'; + + @override + String get projectSpellingDictionary => 'Dicionário do projeto'; + + @override + String get noSpellingErrors => 'Nenhum erro ortográfico'; + + @override + String get noSpellingSuggestions => 'Nenhuma sugestão ortográfica'; + + @override + String get spellingWordCheckFailed => + 'Não foi possível verificar esta palavra'; + + @override + String get spellingCheckFailed => 'A verificação ortográfica falhou'; + + @override + String get spellingCheckIncomplete => + 'A verificação ortográfica está incompleta'; + + @override + String get spellingDictionaryNotInstalled => 'Dicionário não instalado'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'O dicionário de $dictionary não está instalado'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Não instalado · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Instalado'; + + @override + String get installSpellingDictionary => 'Instalar dicionário'; + + @override + String get removeSpellingDictionary => 'Remover dicionário'; + + @override + String get cancelSpellingDictionaryInstall => + 'Cancelar download do dicionário'; + + @override + String get retrySpellingDictionaryInstall => + 'Tentar instalar o dicionário novamente'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Baixando $size…'; + } + + @override + String get spellingDictionaryValidating => 'Validando dicionário…'; + + @override + String get spellingDictionaryInstallFailed => + 'Falha na instalação — selecione para tentar novamente'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Instalar $dictionary ($size)? Depois de instalado, ficará disponível offline até ser removido.'; + } + + @override + String get spellingDictionaryUnavailable => 'Dicionário indisponível'; + + @override + String get spellingChecking => 'Verificando a ortografia…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: insira um número entre $minimum e $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'O dicionário ortográfico foi alterado externamente. Uma cópia de recuperação foi preservada.'; } diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 9184a8ca..c5313195 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -953,6 +953,10 @@ class AppLocalizationsRu extends AppLocalizations { @override String get wordWrap => 'Перенос строк'; + @override + String get wordWrapDescription => + 'Переносить длинные строки по ширине редактора вместо горизонтальной прокрутки.'; + @override String get editorFontSize => 'Размер шрифта редактора'; @@ -1009,6 +1013,28 @@ class AppLocalizationsRu extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Спрашивать перед включением функций Git для ранее доверенных рабочих областей.'; + @override + String get settingsEditingButtonsSectionTitle => 'Кнопки редактирования'; + + @override + String get spellingDictionaries => 'Орфографические словари'; + + @override + String get spellingDictionariesDescription => + 'Установка и управление орфографическими словарями'; + + @override + String get settingsDictionariesSectionTitle => 'Словари'; + + @override + String get availableSpellingDictionaries => 'Доступные словари'; + + @override + String get customSpellingDictionaries => 'Пользовательские словари'; + + @override + String get spellingDictionaryProblems => 'Проблемы со словарями'; + @override String get settingsWindowSectionTitle => 'Окно'; @@ -4547,8 +4573,131 @@ class AppLocalizationsRu extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Правописание'; + + @override + String get automaticSpelling => 'Автоматическая проверка правописания'; + + @override + String get defaultSpellingLanguage => + 'Язык проверки правописания по умолчанию'; + + @override + String get projectSpellingLanguage => 'Язык проверки орфографии проекта'; + + @override + String get chooseSpellingLanguage => 'Выбрать язык правописания'; + + @override + String get spellingLanguageUnsetStatus => 'Язык…'; + + @override + String get spellingOffStatus => 'Проверка правописания отключена'; + + @override + String get checkSpelling => 'Проверить правописание'; + + @override + String get ignoreSpellingOnce => 'Игнорировать один раз'; + + @override + String get ignoreSpellingDocument => 'Игнорировать все в этом документе'; + + @override + String get addPersonalSpellingWord => 'Добавить в личный словарь'; + + @override + String get addProjectSpellingWord => 'Добавить в словарь проекта'; + + @override + String get inheritSpellingLanguage => + 'Использовать язык проекта или приложения'; + + @override + String get disableDocumentSpelling => 'Не проверять орфографию'; + + @override + String get importSpellingDictionary => 'Импортировать словарь'; + + @override + String get personalSpellingDictionary => 'Личный словарь'; + + @override + String get projectSpellingDictionary => 'Словарь проекта'; + + @override + String get noSpellingErrors => 'Орфографических ошибок нет'; + + @override + String get noSpellingSuggestions => 'Нет вариантов исправления'; + + @override + String get spellingWordCheckFailed => 'Не удалось проверить это слово'; + + @override + String get spellingCheckFailed => 'Не удалось проверить правописание'; + + @override + String get spellingCheckIncomplete => 'Проверка правописания не завершена'; + + @override + String get spellingDictionaryNotInstalled => 'Словарь не установлен'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Словарь «$dictionary» не установлен'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Не установлен · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Установлен'; + + @override + String get installSpellingDictionary => 'Установить словарь'; + + @override + String get removeSpellingDictionary => 'Удалить словарь'; + + @override + String get cancelSpellingDictionaryInstall => 'Отменить загрузку словаря'; + + @override + String get retrySpellingDictionaryInstall => 'Повторить установку словаря'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Загрузка $size…'; + } + + @override + String get spellingDictionaryValidating => 'Проверка словаря…'; + + @override + String get spellingDictionaryInstallFailed => + 'Не удалось установить словарь — выберите для повтора'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Установить $dictionary ($size)? После установки он будет доступен без сети, пока вы его не удалите.'; + } + + @override + String get spellingDictionaryUnavailable => 'Словарь недоступен'; + + @override + String get spellingChecking => 'Проверка правописания…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: введите число от $minimum до $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Орфографический словарь был изменён извне. Резервная копия для восстановления сохранена.'; } diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index ed871651..911544eb 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -952,6 +952,10 @@ class AppLocalizationsTr extends AppLocalizations { @override String get wordWrap => 'Satır kaydırma'; + @override + String get wordWrapDescription => + 'Uzun satırları yatay kaydırmak yerine düzenleyici genişliğine sığacak şekilde kaydırın.'; + @override String get editorFontSize => 'Düzenleyici yazı tipi boyutu'; @@ -1006,6 +1010,28 @@ class AppLocalizationsTr extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Daha önce güvenilen çalışma alanları için Git özelliklerini etkinleştirmeden önce sorun.'; + @override + String get settingsEditingButtonsSectionTitle => 'Düzenleme düğmeleri'; + + @override + String get spellingDictionaries => 'Yazım sözlükleri'; + + @override + String get spellingDictionariesDescription => + 'Yazım sözlüklerini kurun ve yönetin'; + + @override + String get settingsDictionariesSectionTitle => 'Sözlükler'; + + @override + String get availableSpellingDictionaries => 'Kullanılabilir sözlükler'; + + @override + String get customSpellingDictionaries => 'Özel sözlükler'; + + @override + String get spellingDictionaryProblems => 'Sözlük sorunları'; + @override String get settingsWindowSectionTitle => 'Pencere'; @@ -4493,8 +4519,130 @@ class AppLocalizationsTr extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Yazım'; + + @override + String get automaticSpelling => 'Otomatik yazım denetimi'; + + @override + String get defaultSpellingLanguage => 'Varsayılan yazım dili'; + + @override + String get projectSpellingLanguage => 'Proje yazım denetimi dili'; + + @override + String get chooseSpellingLanguage => 'Yazım dili seç'; + + @override + String get spellingLanguageUnsetStatus => 'Dil…'; + + @override + String get spellingOffStatus => 'Yazım denetimi kapalı'; + + @override + String get checkSpelling => 'Yazımı Denetle'; + + @override + String get ignoreSpellingOnce => 'Bir Kez Yoksay'; + + @override + String get ignoreSpellingDocument => 'Bu Belgede Tümünü Yoksay'; + + @override + String get addPersonalSpellingWord => 'Kişisel Sözlüğe Ekle'; + + @override + String get addProjectSpellingWord => 'Proje Sözlüğüne Ekle'; + + @override + String get inheritSpellingLanguage => 'Proje veya uygulama dilini kullan'; + + @override + String get disableDocumentSpelling => 'Yazımı denetleme'; + + @override + String get importSpellingDictionary => 'Sözlük İçe Aktar'; + + @override + String get personalSpellingDictionary => 'Kişisel Sözlük'; + + @override + String get projectSpellingDictionary => 'Proje Sözlüğü'; + + @override + String get noSpellingErrors => 'Yazım hatası yok'; + + @override + String get noSpellingSuggestions => 'Yazım önerisi yok'; + + @override + String get spellingWordCheckFailed => 'Bu sözcük denetlenemedi'; + + @override + String get spellingCheckFailed => 'Yazım denetimi başarısız oldu'; + + @override + String get spellingCheckIncomplete => 'Yazım denetimi tamamlanmadı'; + + @override + String get spellingDictionaryNotInstalled => 'Sözlük yüklü değil'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '$dictionary sözlüğü yüklü değil'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Yüklü değil · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Yüklü'; + + @override + String get installSpellingDictionary => 'Sözlüğü yükle'; + + @override + String get removeSpellingDictionary => 'Sözlüğü kaldır'; + + @override + String get cancelSpellingDictionaryInstall => 'Sözlük indirmesini iptal et'; + + @override + String get retrySpellingDictionaryInstall => + 'Sözlük yüklemesini yeniden dene'; + + @override + String spellingDictionaryDownloading(String size) { + return '$size indiriliyor…'; + } + + @override + String get spellingDictionaryValidating => 'Sözlük doğrulanıyor…'; + + @override + String get spellingDictionaryInstallFailed => + 'Sözlük yüklenemedi — yeniden denemek için seçin'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '$dictionary ($size) yüklensin mi? Yüklendikten sonra kaldırılana kadar çevrimdışı kullanılabilir.'; + } + + @override + String get spellingDictionaryUnavailable => 'Sözlük kullanılamıyor'; + + @override + String get spellingChecking => 'Yazım denetleniyor…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: $minimum ile $maximum arasında bir sayı girin.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Yazım sözlüğü harici olarak değiştirildi. Bir kurtarma kopyası korundu.'; } diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index ab6b85ff..fbf67d6f 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -958,6 +958,10 @@ class AppLocalizationsUk extends AppLocalizations { @override String get wordWrap => 'Перенесення рядків'; + @override + String get wordWrapDescription => + 'Переносити довгі рядки за шириною редактора замість горизонтального прокручування.'; + @override String get editorFontSize => 'Розмір шрифту редактора'; @@ -1014,6 +1018,28 @@ class AppLocalizationsUk extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Запитувати перед увімкненням функцій Git для раніше довірених робочих областей.'; + @override + String get settingsEditingButtonsSectionTitle => 'Кнопки редагування'; + + @override + String get spellingDictionaries => 'Орфографічні словники'; + + @override + String get spellingDictionariesDescription => + 'Установлення й керування орфографічними словниками'; + + @override + String get settingsDictionariesSectionTitle => 'Словники'; + + @override + String get availableSpellingDictionaries => 'Доступні словники'; + + @override + String get customSpellingDictionaries => 'Власні словники'; + + @override + String get spellingDictionaryProblems => 'Проблеми зі словниками'; + @override String get settingsWindowSectionTitle => 'Вікно'; @@ -4555,8 +4581,132 @@ class AppLocalizationsUk extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Правопис'; + + @override + String get automaticSpelling => 'Автоматична перевірка правопису'; + + @override + String get defaultSpellingLanguage => 'Типова мова перевірки правопису'; + + @override + String get projectSpellingLanguage => 'Мова перевірки правопису проєкту'; + + @override + String get chooseSpellingLanguage => 'Вибрати мову правопису'; + + @override + String get spellingLanguageUnsetStatus => 'Мова…'; + + @override + String get spellingOffStatus => 'Перевірку правопису вимкнено'; + + @override + String get checkSpelling => 'Перевірити правопис'; + + @override + String get ignoreSpellingOnce => 'Ігнорувати один раз'; + + @override + String get ignoreSpellingDocument => 'Ігнорувати все в цьому документі'; + + @override + String get addPersonalSpellingWord => 'Додати до особистого словника'; + + @override + String get addProjectSpellingWord => 'Додати до словника проєкту'; + + @override + String get inheritSpellingLanguage => + 'Використовувати мову проєкту або програми'; + + @override + String get disableDocumentSpelling => 'Не перевіряти правопис'; + + @override + String get importSpellingDictionary => 'Імпортувати словник'; + + @override + String get personalSpellingDictionary => 'Особистий словник'; + + @override + String get projectSpellingDictionary => 'Словник проєкту'; + + @override + String get noSpellingErrors => 'Орфографічних помилок немає'; + + @override + String get noSpellingSuggestions => 'Немає варіантів виправлення'; + + @override + String get spellingWordCheckFailed => 'Не вдалося перевірити це слово'; + + @override + String get spellingCheckFailed => 'Не вдалося перевірити правопис'; + + @override + String get spellingCheckIncomplete => 'Перевірку правопису не завершено'; + + @override + String get spellingDictionaryNotInstalled => 'Словник не встановлено'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Словник «$dictionary» не встановлено'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Не встановлено · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Встановлено'; + + @override + String get installSpellingDictionary => 'Встановити словник'; + + @override + String get removeSpellingDictionary => 'Видалити словник'; + + @override + String get cancelSpellingDictionaryInstall => + 'Скасувати завантаження словника'; + + @override + String get retrySpellingDictionaryInstall => + 'Повторити встановлення словника'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Завантаження $size…'; + } + + @override + String get spellingDictionaryValidating => 'Перевірка словника…'; + + @override + String get spellingDictionaryInstallFailed => + 'Не вдалося встановити словник — виберіть, щоб повторити'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Встановити $dictionary ($size)? Після встановлення він буде доступний офлайн, доки ви його не видалите.'; + } + + @override + String get spellingDictionaryUnavailable => 'Словник недоступний'; + + @override + String get spellingChecking => 'Перевірка правопису…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: введіть число від $minimum до $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Орфографічний словник було змінено ззовні. Копію для відновлення збережено.'; } diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 71ecbe08..c302818b 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -946,6 +946,10 @@ class AppLocalizationsVi extends AppLocalizations { @override String get wordWrap => 'Tự động xuống dòng'; + @override + String get wordWrapDescription => + 'Ngắt các dòng dài cho vừa chiều rộng trình biên tập thay vì cuộn ngang.'; + @override String get editorFontSize => 'Cỡ chữ trình biên tập'; @@ -1000,6 +1004,28 @@ class AppLocalizationsVi extends AppLocalizations { String get clearGitWorkspaceTrustDescription => 'Hỏi trước khi bật các tính năng Git cho những không gian làm việc đã từng được tin cậy.'; + @override + String get settingsEditingButtonsSectionTitle => 'Nút chỉnh sửa'; + + @override + String get spellingDictionaries => 'Từ điển chính tả'; + + @override + String get spellingDictionariesDescription => + 'Cài đặt và quản lý từ điển chính tả'; + + @override + String get settingsDictionariesSectionTitle => 'Từ điển'; + + @override + String get availableSpellingDictionaries => 'Từ điển có sẵn'; + + @override + String get customSpellingDictionaries => 'Từ điển tùy chỉnh'; + + @override + String get spellingDictionaryProblems => 'Sự cố từ điển'; + @override String get settingsWindowSectionTitle => 'Cửa sổ'; @@ -4484,8 +4510,129 @@ class AppLocalizationsVi extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => 'Chính tả'; + + @override + String get automaticSpelling => 'Tự động kiểm tra chính tả'; + + @override + String get defaultSpellingLanguage => 'Ngôn ngữ chính tả mặc định'; + + @override + String get projectSpellingLanguage => 'Ngôn ngữ kiểm tra chính tả của dự án'; + + @override + String get chooseSpellingLanguage => 'Chọn ngôn ngữ chính tả'; + + @override + String get spellingLanguageUnsetStatus => 'Ngôn ngữ…'; + + @override + String get spellingOffStatus => 'Tắt chính tả'; + + @override + String get checkSpelling => 'Kiểm tra chính tả'; + + @override + String get ignoreSpellingOnce => 'Bỏ qua một lần'; + + @override + String get ignoreSpellingDocument => 'Bỏ qua tất cả trong tài liệu này'; + + @override + String get addPersonalSpellingWord => 'Thêm vào từ điển cá nhân'; + + @override + String get addProjectSpellingWord => 'Thêm vào từ điển dự án'; + + @override + String get inheritSpellingLanguage => 'Dùng ngôn ngữ dự án hoặc ứng dụng'; + + @override + String get disableDocumentSpelling => 'Không kiểm tra chính tả'; + + @override + String get importSpellingDictionary => 'Nhập từ điển'; + + @override + String get personalSpellingDictionary => 'Từ điển cá nhân'; + + @override + String get projectSpellingDictionary => 'Từ điển dự án'; + + @override + String get noSpellingErrors => 'Không có lỗi chính tả'; + + @override + String get noSpellingSuggestions => 'Không có đề xuất chính tả'; + + @override + String get spellingWordCheckFailed => 'Không thể kiểm tra từ này'; + + @override + String get spellingCheckFailed => 'Kiểm tra chính tả thất bại'; + + @override + String get spellingCheckIncomplete => 'Kiểm tra chính tả chưa hoàn tất'; + + @override + String get spellingDictionaryNotInstalled => 'Từ điển chưa được cài đặt'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return 'Từ điển $dictionary chưa được cài đặt'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return 'Chưa cài đặt · $size'; + } + + @override + String get spellingDictionaryInstalled => 'Đã cài đặt'; + + @override + String get installSpellingDictionary => 'Cài đặt từ điển'; + + @override + String get removeSpellingDictionary => 'Gỡ từ điển'; + + @override + String get cancelSpellingDictionaryInstall => 'Hủy tải từ điển'; + + @override + String get retrySpellingDictionaryInstall => 'Thử cài đặt lại từ điển'; + + @override + String spellingDictionaryDownloading(String size) { + return 'Đang tải $size…'; + } + + @override + String get spellingDictionaryValidating => 'Đang xác thực từ điển…'; + + @override + String get spellingDictionaryInstallFailed => + 'Cài đặt từ điển thất bại — chọn để thử lại'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return 'Cài đặt $dictionary ($size)? Sau khi cài đặt, từ điển sẽ dùng được ngoại tuyến cho đến khi bạn gỡ bỏ.'; + } + + @override + String get spellingDictionaryUnavailable => 'Từ điển không khả dụng'; + + @override + String get spellingChecking => 'Đang kiểm tra chính tả…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field: nhập số từ $minimum đến $maximum.'; } + + @override + String get spellingDictionaryRecoveryConflict => + 'Từ điển chính tả đã được thay đổi từ bên ngoài. Một bản sao khôi phục đã được giữ lại.'; } diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 18d2d364..aabe1633 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -902,6 +902,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get wordWrap => '自动换行'; + @override + String get wordWrapDescription => '将长行换行以适应编辑器宽度,而不是水平滚动。'; + @override String get editorFontSize => '编辑器字体大小'; @@ -951,6 +954,27 @@ class AppLocalizationsZh extends AppLocalizations { @override String get clearGitWorkspaceTrustDescription => '为之前受信任的工作区启用 Git 功能前先进行询问。'; + @override + String get settingsEditingButtonsSectionTitle => '编辑按钮'; + + @override + String get spellingDictionaries => '拼写词典'; + + @override + String get spellingDictionariesDescription => '安装和管理拼写词典'; + + @override + String get settingsDictionariesSectionTitle => '词典'; + + @override + String get availableSpellingDictionaries => '可用词典'; + + @override + String get customSpellingDictionaries => '自定义词典'; + + @override + String get spellingDictionaryProblems => '词典问题'; + @override String get settingsWindowSectionTitle => '窗口'; @@ -4294,10 +4318,129 @@ class AppLocalizationsZh extends AppLocalizations { return '$value MiB'; } + @override + String get spelling => '拼写检查'; + + @override + String get automaticSpelling => '自动检查拼写'; + + @override + String get defaultSpellingLanguage => '默认拼写语言'; + + @override + String get projectSpellingLanguage => '项目拼写检查语言'; + + @override + String get chooseSpellingLanguage => '选择拼写语言'; + + @override + String get spellingLanguageUnsetStatus => '语言…'; + + @override + String get spellingOffStatus => '拼写检查已关闭'; + + @override + String get checkSpelling => '检查拼写'; + + @override + String get ignoreSpellingOnce => '忽略一次'; + + @override + String get ignoreSpellingDocument => '在此文档中全部忽略'; + + @override + String get addPersonalSpellingWord => '添加到个人词典'; + + @override + String get addProjectSpellingWord => '添加到项目词典'; + + @override + String get inheritSpellingLanguage => '使用项目或应用语言'; + + @override + String get disableDocumentSpelling => '不检查拼写'; + + @override + String get importSpellingDictionary => '导入词典'; + + @override + String get personalSpellingDictionary => '个人词典'; + + @override + String get projectSpellingDictionary => '项目词典'; + + @override + String get noSpellingErrors => '没有拼写错误'; + + @override + String get noSpellingSuggestions => '没有拼写建议'; + + @override + String get spellingWordCheckFailed => '无法检查此单词'; + + @override + String get spellingCheckFailed => '拼写检查失败'; + + @override + String get spellingCheckIncomplete => '拼写检查未完成'; + + @override + String get spellingDictionaryNotInstalled => '尚未安装词典'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '尚未安装 $dictionary 词典'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return '未安装 · $size'; + } + + @override + String get spellingDictionaryInstalled => '已安装'; + + @override + String get installSpellingDictionary => '安装词典'; + + @override + String get removeSpellingDictionary => '移除词典'; + + @override + String get cancelSpellingDictionaryInstall => '取消下载词典'; + + @override + String get retrySpellingDictionaryInstall => '重试安装词典'; + + @override + String spellingDictionaryDownloading(String size) { + return '正在下载 $size…'; + } + + @override + String get spellingDictionaryValidating => '正在验证词典…'; + + @override + String get spellingDictionaryInstallFailed => '词典安装失败 — 选择以重试'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '要安装 $dictionary($size)吗?安装后,在移除前都可离线使用。'; + } + + @override + String get spellingDictionaryUnavailable => '词典不可用'; + + @override + String get spellingChecking => '正在检查拼写…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field:请输入 $minimum 到 $maximum 之间的数字。'; } + + @override + String get spellingDictionaryRecoveryConflict => '拼写词典已被外部更改。已保留恢复副本。'; } /// The translations for Chinese, as used in China (`zh_CN`). @@ -5196,6 +5339,9 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get wordWrap => '自动换行'; + @override + String get wordWrapDescription => '将长行换行以适应编辑器宽度,而不是水平滚动。'; + @override String get editorFontSize => '编辑器字体大小'; @@ -5245,6 +5391,27 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get clearGitWorkspaceTrustDescription => '为之前受信任的工作区启用 Git 功能前先进行询问。'; + @override + String get settingsEditingButtonsSectionTitle => '编辑按钮'; + + @override + String get spellingDictionaries => '拼写词典'; + + @override + String get spellingDictionariesDescription => '安装和管理拼写词典'; + + @override + String get settingsDictionariesSectionTitle => '词典'; + + @override + String get availableSpellingDictionaries => '可用词典'; + + @override + String get customSpellingDictionaries => '自定义词典'; + + @override + String get spellingDictionaryProblems => '词典问题'; + @override String get settingsWindowSectionTitle => '窗口'; @@ -8588,8 +8755,127 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { return '$value MiB'; } + @override + String get spelling => '拼写检查'; + + @override + String get automaticSpelling => '自动检查拼写'; + + @override + String get defaultSpellingLanguage => '默认拼写语言'; + + @override + String get projectSpellingLanguage => '项目拼写检查语言'; + + @override + String get chooseSpellingLanguage => '选择拼写语言'; + + @override + String get spellingLanguageUnsetStatus => '语言…'; + + @override + String get spellingOffStatus => '拼写检查已关闭'; + + @override + String get checkSpelling => '检查拼写'; + + @override + String get ignoreSpellingOnce => '忽略一次'; + + @override + String get ignoreSpellingDocument => '在此文档中全部忽略'; + + @override + String get addPersonalSpellingWord => '添加到个人词典'; + + @override + String get addProjectSpellingWord => '添加到项目词典'; + + @override + String get inheritSpellingLanguage => '使用项目或应用语言'; + + @override + String get disableDocumentSpelling => '不检查拼写'; + + @override + String get importSpellingDictionary => '导入词典'; + + @override + String get personalSpellingDictionary => '个人词典'; + + @override + String get projectSpellingDictionary => '项目词典'; + + @override + String get noSpellingErrors => '没有拼写错误'; + + @override + String get noSpellingSuggestions => '没有拼写建议'; + + @override + String get spellingWordCheckFailed => '无法检查此单词'; + + @override + String get spellingCheckFailed => '拼写检查失败'; + + @override + String get spellingCheckIncomplete => '拼写检查未完成'; + + @override + String get spellingDictionaryNotInstalled => '尚未安装词典'; + + @override + String spellingDictionaryNotInstalledForLanguage(String dictionary) { + return '尚未安装 $dictionary 词典'; + } + + @override + String spellingDictionaryNotInstalledWithSize(String size) { + return '未安装 · $size'; + } + + @override + String get spellingDictionaryInstalled => '已安装'; + + @override + String get installSpellingDictionary => '安装词典'; + + @override + String get removeSpellingDictionary => '移除词典'; + + @override + String get cancelSpellingDictionaryInstall => '取消下载词典'; + + @override + String get retrySpellingDictionaryInstall => '重试安装词典'; + + @override + String spellingDictionaryDownloading(String size) { + return '正在下载 $size…'; + } + + @override + String get spellingDictionaryValidating => '正在验证词典…'; + + @override + String get spellingDictionaryInstallFailed => '词典安装失败 — 选择以重试'; + + @override + String spellingDictionaryInstallPrompt(String dictionary, String size) { + return '要安装 $dictionary($size)吗?安装后,在移除前都可离线使用。'; + } + + @override + String get spellingDictionaryUnavailable => '词典不可用'; + + @override + String get spellingChecking => '正在检查拼写…'; + @override String exportInvalidRange(String field, String minimum, String maximum) { return '$field:请输入 $minimum 到 $maximum 之间的数字。'; } + + @override + String get spellingDictionaryRecoveryConflict => '拼写词典已被外部更改。已保留恢复副本。'; } diff --git a/lib/main.dart b/lib/main.dart index f3b65821..bc682a30 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'src/app/system_accent.dart'; import 'src/git/application/git_controller.dart'; import 'src/git/data/git_cli_gateway.dart'; import 'src/platform/linux_header_bar_service.dart'; +import 'src/spellcheck/spelling_release_smoke.dart'; import 'src/visualization/visualization_release_smoke.dart'; Future main(List args) async { @@ -19,6 +20,9 @@ Future main(List args) async { if (visualizationReleaseSmokeReportPath(args) case final reportPath?) { exit(await runVisualizationReleaseSmoke(reportPath)); } + if (spellingReleaseSmokeReportPath(args) case final reportPath?) { + exit(await runSpellingReleaseSmoke(reportPath)); + } var initialAccent = busyMarkDefaultAccentColor; if (Platform.isLinux) { initialAccent = diff --git a/lib/src/app/app_metadata.dart b/lib/src/app/app_metadata.dart index 6d645a6e..228206cc 100644 --- a/lib/src/app/app_metadata.dart +++ b/lib/src/app/app_metadata.dart @@ -1 +1 @@ -const busyMarkAppVersion = '0.4.2'; +const busyMarkAppVersion = '0.5.0'; diff --git a/lib/src/app/app_settings.dart b/lib/src/app/app_settings.dart index 0fa4544e..686415c4 100644 --- a/lib/src/app/app_settings.dart +++ b/lib/src/app/app_settings.dart @@ -8,6 +8,7 @@ import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import '../export/export_options.dart'; +import '../spellcheck/spelling_language.dart'; import 'app_locale.dart'; enum BusyMarkThemeModePreference { system, light, dark } @@ -86,6 +87,8 @@ class AppSettings { required this.editorToolbarDirection, required this.autoSave, required this.validateOnEdit, + required this.automaticSpelling, + required this.defaultSpellingLanguage, required this.clipboardHistoryEnabled, required this.localHistoryRecordingEnabled, required this.localHistoryCheckpointSeconds, @@ -125,6 +128,8 @@ class AppSettings { editorToolbarDirection: EditorToolbarDirection.horizontal, autoSave: true, validateOnEdit: true, + automaticSpelling: true, + defaultSpellingLanguage: null, clipboardHistoryEnabled: true, localHistoryRecordingEnabled: true, localHistoryCheckpointSeconds: 60, @@ -188,6 +193,11 @@ class AppSettings { autoSave: json['autoSave'] as bool? ?? defaults.autoSave, validateOnEdit: json['validateOnEdit'] as bool? ?? defaults.validateOnEdit, + automaticSpelling: + json['automaticSpelling'] as bool? ?? defaults.automaticSpelling, + defaultSpellingLanguage: normalizeSpellingLanguageId( + json['defaultSpellingLanguage'], + ), clipboardHistoryEnabled: json['clipboardHistoryEnabled'] as bool? ?? defaults.clipboardHistoryEnabled, @@ -281,6 +291,8 @@ class AppSettings { final EditorToolbarDirection editorToolbarDirection; final bool autoSave; final bool validateOnEdit; + final bool automaticSpelling; + final String? defaultSpellingLanguage; final bool clipboardHistoryEnabled; final bool localHistoryRecordingEnabled; final int localHistoryCheckpointSeconds; @@ -322,6 +334,8 @@ class AppSettings { 'editorToolbarDirection': editorToolbarDirection.name, 'autoSave': autoSave, 'validateOnEdit': validateOnEdit, + 'automaticSpelling': automaticSpelling, + 'defaultSpellingLanguage': defaultSpellingLanguage, 'clipboardHistoryEnabled': clipboardHistoryEnabled, 'localHistoryRecordingEnabled': localHistoryRecordingEnabled, 'localHistoryCheckpointSeconds': localHistoryCheckpointSeconds, @@ -402,6 +416,8 @@ class AppSettings { EditorToolbarDirection? editorToolbarDirection, bool? autoSave, bool? validateOnEdit, + bool? automaticSpelling, + Object? defaultSpellingLanguage = _unset, bool? clipboardHistoryEnabled, bool? localHistoryRecordingEnabled, int? localHistoryCheckpointSeconds, @@ -443,6 +459,10 @@ class AppSettings { editorToolbarDirection ?? this.editorToolbarDirection, autoSave: autoSave ?? this.autoSave, validateOnEdit: validateOnEdit ?? this.validateOnEdit, + automaticSpelling: automaticSpelling ?? this.automaticSpelling, + defaultSpellingLanguage: identical(defaultSpellingLanguage, _unset) + ? this.defaultSpellingLanguage + : normalizeSpellingLanguageId(defaultSpellingLanguage), clipboardHistoryEnabled: clipboardHistoryEnabled ?? this.clipboardHistoryEnabled, localHistoryRecordingEnabled: @@ -649,6 +669,18 @@ class AppSettingsController extends Notifier { return _mutate((settings) => settings.copyWith(validateOnEdit: enabled)); } + Future setAutomaticSpelling(bool enabled) { + return _mutate((settings) => settings.copyWith(automaticSpelling: enabled)); + } + + Future setDefaultSpellingLanguage(String? languageId) { + return _mutate( + (settings) => settings.copyWith( + defaultSpellingLanguage: normalizeSpellingLanguageId(languageId), + ), + ); + } + Future setClipboardHistoryEnabled(bool enabled) { return _mutate( (settings) => settings.copyWith(clipboardHistoryEnabled: enabled), diff --git a/lib/src/app/busymark_app.dart b/lib/src/app/busymark_app.dart index 59bc75ec..bdd0628a 100644 --- a/lib/src/app/busymark_app.dart +++ b/lib/src/app/busymark_app.dart @@ -536,6 +536,9 @@ class BusyMarkApp extends ConsumerWidget { WidgetRef ref, GoRouter router, ) async { + final startsWorkspace = + settingsReturnTargetForUri(router.routeInformationProvider.value.uri) == + SettingsReturnTarget.welcome; final headerBar = ref.read(linuxHeaderBarServiceProvider); final choice = await showBusyMarkModalDialog<_NewChooserChoice>( context, @@ -579,9 +582,15 @@ class BusyMarkApp extends ConsumerWidget { } switch (choice) { case _CreateMarkdownFile(): - await ref - .read(workspaceControllerProvider.notifier) - .createMarkdownFile(); + final controller = ref.read(workspaceControllerProvider.notifier); + if (startsWorkspace) { + if (!await confirmSafeToContinue(context, ref) || !context.mounted) { + return; + } + if (!await controller.createMarkdownWorkspace()) return; + } else { + await controller.createMarkdownFile(); + } if (context.mounted) { router.go('/workspace'); } diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index e4b9704e..4894c553 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -56,6 +56,7 @@ abstract final class BusyMarkSizes { static const double settingsSidebarBreakpoint = sidebarWidth + 520; static const double toolbarHeight = kYaruTitleBarHeight; static const double paneHeaderHeight = 38; + static const double documentStatusBarHeight = 28; static const double iconButton = kYaruTitleBarItemHeight; static const double compactIconButton = 24; static const double compactIcon = 13; @@ -261,11 +262,13 @@ String busyMarkBidiIsolateFor(BuildContext context, Object value) { abstract final class BusyMarkMotion { static const Duration dialogInsets = Duration(milliseconds: 160); + static const Duration bannerReveal = Duration(milliseconds: 250); static const Duration sidebarExpand = Duration(milliseconds: 120); static const Duration scroll = Duration(milliseconds: 180); static const Duration previewSearchDelay = Duration(milliseconds: 80); static const Duration tooltipWait = Duration(milliseconds: 450); static const Curve dialogInsetsCurve = Curves.easeOutCubic; + static const Curve bannerRevealCurve = Curves.easeOutCubic; } abstract final class BusyMarkInsets { @@ -386,6 +389,8 @@ abstract final class BusyMarkLinuxPalette { static const ubuntuPrussianGreenAccent = Color(0xFF308280); static const ubuntuSageAccent = Color(0xFF657B69); static const ubuntuWartyBrownAccent = Color(0xFFB39169); + static const destructiveForegroundLight = Color(0xFFC30000); + static const destructiveForegroundDark = Color(0xFFFF938C); static const red = Color(0xFFC01C28); static const yellow = Color(0xFFE5A50A); static const green = Color(0xFF2EC27E); @@ -561,7 +566,9 @@ enum BusyMarkVcsFileColor { } Color busyMarkDestructiveForeground(BuildContext context) { - return Theme.of(context).colorScheme.error; + return Theme.of(context).brightness == Brightness.dark + ? BusyMarkLinuxPalette.destructiveForegroundDark + : BusyMarkLinuxPalette.destructiveForegroundLight; } Color busyMarkVcsFileStatusColor( @@ -976,8 +983,9 @@ Color busyMarkRowHoverColor(BuildContext context) { TextStyle? busyMarkSectionHeaderStyle(BuildContext context) { final theme = Theme.of(context); - return theme.textTheme.titleSmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + return theme.textTheme.bodyMedium?.copyWith( + color: BusyMarkSurfaceColors.of(context).foreground, + fontWeight: FontWeight.w700, ); } @@ -1441,6 +1449,7 @@ List? _busyMarkNativeMenuEntries( enabled: item.enabled, checkable: item.trailingCheck, selected: item.trailingCheck && item.checked, + mutuallyExclusive: item.mutuallyExclusive, ), ); } else if (item is BusyMarkSubmenuItem) { @@ -1685,24 +1694,50 @@ class _BusyMarkNestedMenuState extends State<_BusyMarkNestedMenu> { child: Text(item.label), ) else if (item is BusyMarkPopupMenuItem) - MenuItemButton( - focusNode: root && identical(item, items.first) ? _firstFocus : null, - closeOnActivate: false, - onPressed: item.enabled - ? () { - _selected = true; - Navigator.of(context).pop(item.menuValue); - } - : null, - leadingIcon: item.icon == null - ? null - : Icon( - item.icon, - size: BusyMarkSizes.iconSm, - color: item.iconColor, - ), - trailingIcon: item.shortcut == null ? null : Text(item.shortcut!), - child: Text(item.label), + Semantics( + checked: item.trailingCheck ? item.checked : null, + inMutuallyExclusiveGroup: + item.trailingCheck && item.mutuallyExclusive, + child: MenuItemButton( + focusNode: root && identical(item, items.first) + ? _firstFocus + : null, + closeOnActivate: false, + onPressed: item.enabled + ? () { + _selected = true; + Navigator.of(context).pop(item.menuValue); + } + : null, + leadingIcon: item.icon == null + ? null + : Icon( + item.icon, + size: BusyMarkSizes.iconSm, + color: item.iconColor, + ), + trailingIcon: item.trailingCheck + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (item.shortcut case final shortcut?) ...[ + Text(shortcut), + const SizedBox(width: BusyMarkSpacing.sm), + ], + Visibility.maintain( + visible: item.checked, + child: const Icon( + BusyMarkGlyphs.check, + size: BusyMarkSizes.iconSm, + ), + ), + ], + ) + : item.shortcut == null + ? null + : Text(item.shortcut!), + child: Text(item.label), + ), ) else if (item is PopupMenuDivider) const Divider(height: BusyMarkSpacing.sm), @@ -2907,6 +2942,103 @@ class _BusyMarkSidebarRecordRowState } } +/// A native contextual information bar embedded in the surrounding layout. +/// +/// This mirrors Libadwaita's banner pattern: the host decides when the banner +/// is revealed, while the banner owns semantic surface, typography, and +/// native action-control presentation without floating over content. +class BusyMarkBanner extends StatelessWidget { + const BusyMarkBanner({ + super.key, + required this.title, + this.actionLabel, + this.onAction, + this.suggestedAction = false, + this.revealed = true, + }) : assert(actionLabel != null || onAction == null); + + final String title; + final String? actionLabel; + final VoidCallback? onAction; + final bool suggestedAction; + final bool revealed; + + @override + Widget build(BuildContext context) { + final colors = BusyMarkSurfaceColors.of(context); + final actionLabel = this.actionLabel; + final action = actionLabel == null + ? null + : suggestedAction + ? BusyMarkPushButton.suggested( + onPressed: onAction, + child: Text(actionLabel), + ) + : BusyMarkPushButton.standard( + onPressed: onAction, + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: BusyMarkSpacing.sm, + ), + visualDensity: VisualDensity.compact, + ), + child: Text(actionLabel), + ); + final banner = Semantics( + container: true, + liveRegion: true, + child: DecoratedBox( + decoration: BoxDecoration( + color: colors.panel, + border: Border(bottom: BorderSide(color: colors.divider)), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: BusyMarkSpacing.md, + vertical: BusyMarkSpacing.xs, + ), + child: Row( + children: [ + Expanded( + child: Text( + title, + maxLines: 2, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: colors.foreground), + textAlign: TextAlign.start, + ), + ), + if (action != null) ...[ + const SizedBox(width: BusyMarkSpacing.md), + action, + ], + ], + ), + ), + ), + ); + final revealDuration = MediaQuery.disableAnimationsOf(context) + ? Duration.zero + : BusyMarkMotion.bannerReveal; + if (revealDuration == Duration.zero) { + return ClipRect(child: revealed ? banner : const SizedBox.shrink()); + } + return ClipRect( + child: AnimatedSize( + alignment: Alignment.topCenter, + clipBehavior: Clip.hardEdge, + duration: revealDuration, + reverseDuration: revealDuration, + curve: BusyMarkMotion.bannerRevealCurve, + child: revealed ? banner : const SizedBox.shrink(), + ), + ); + } +} + class BusyMarkGroupedList extends StatelessWidget { const BusyMarkGroupedList({ super.key, @@ -3245,12 +3377,11 @@ class _BusyMarkActionRowState extends State { @override Widget build(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; final colors = BusyMarkSurfaceColors.of(context); final titleStyle = widget.destructive ? TextStyle( color: widget.enabled - ? colorScheme.error + ? busyMarkDestructiveForeground(context) : colors.disabledForeground, ) : null; @@ -3351,6 +3482,129 @@ class _BusyMarkActionRowState extends State { } } +/// A Yaru switch with Libadwaita-style state colors and no external halo. +class BusyMarkSwitch extends StatefulWidget { + const BusyMarkSwitch({ + super.key, + required this.value, + required this.onChanged, + this.focusNode, + this.autofocus = false, + this.mouseCursor, + this.onOffShapes, + this.hasFocusBorder, + }); + + final bool value; + final ValueChanged? onChanged; + final FocusNode? focusNode; + final bool autofocus; + final MouseCursor? mouseCursor; + final bool? onOffShapes; + final bool? hasFocusBorder; + + @override + State createState() => _BusyMarkSwitchState(); +} + +class _BusyMarkSwitchState extends State { + bool _hovered = false; + int? _pressedPointer; + + bool get _pressed => _pressedPointer != null; + + @override + void didUpdateWidget(BusyMarkSwitch oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.onChanged == null) { + _pressedPointer = null; + } + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final inheritedSwitchTheme = YaruSwitchTheme.of(context); + final checkedTrackColor = _busyMarkCheckedSwitchColor( + theme.colorScheme.primary, + brightness: theme.brightness, + hovered: _hovered, + pressed: _pressed, + ); + + return MouseRegion( + onEnter: (_) => _setHovered(true), + onExit: (_) => _setHovered(false), + child: Listener( + onPointerDown: widget.onChanged == null ? null : _handlePointerDown, + onPointerUp: widget.onChanged == null ? null : _handlePointerUp, + onPointerCancel: widget.onChanged == null ? null : _handlePointerCancel, + child: YaruSwitchTheme( + data: inheritedSwitchTheme.copyWith( + indicatorColor: const WidgetStatePropertyAll( + Colors.transparent, + ), + ), + child: YaruSwitch( + value: widget.value, + onChanged: widget.onChanged, + selectedColor: checkedTrackColor, + focusNode: widget.focusNode, + autofocus: widget.autofocus, + mouseCursor: widget.mouseCursor, + onOffShapes: widget.onOffShapes, + hasFocusBorder: widget.hasFocusBorder, + ), + ), + ), + ); + } + + void _setHovered(bool hovered) { + if (_hovered != hovered) { + setState(() => _hovered = hovered); + } + } + + void _handlePointerDown(PointerDownEvent event) { + if (_pressedPointer != null || event.buttons != kPrimaryButton) { + return; + } + setState(() => _pressedPointer = event.pointer); + } + + void _handlePointerUp(PointerUpEvent event) { + if (_pressedPointer == event.pointer) { + setState(() => _pressedPointer = null); + } + } + + void _handlePointerCancel(PointerCancelEvent event) { + if (_pressedPointer == event.pointer) { + setState(() => _pressedPointer = null); + } + } +} + +Color _busyMarkCheckedSwitchColor( + Color accent, { + required Brightness brightness, + required bool hovered, + required bool pressed, +}) { + final normalLightnessDelta = brightness == Brightness.light ? 0.05 : 0.0; + final stateLightnessDelta = pressed ? -0.07 : (hovered ? 0.07 : 0.0); + final hsl = HSLColor.fromColor(accent); + return hsl + .withLightness( + (hsl.lightness + normalLightnessDelta + stateLightnessDelta).clamp( + 0.0, + 1.0, + ), + ) + .toColor(); +} + class BusyMarkSwitchRow extends StatelessWidget { const BusyMarkSwitchRow({ super.key, @@ -3371,9 +3625,14 @@ class BusyMarkSwitchRow extends StatelessWidget { @override Widget build(BuildContext context) { + final switchControl = BusyMarkSwitch( + value: value, + onChanged: enabled ? onChanged : null, + ); return YaruSwitchListTile( value: value, onChanged: enabled ? onChanged : null, + control: switchControl, secondary: leading, title: Text(title), subtitle: subtitle == null @@ -3389,6 +3648,144 @@ class BusyMarkSwitchRow extends StatelessWidget { } } +/// A Yaru radio button with GTK-style state colors and no external halo. +class BusyMarkRadioButton extends StatefulWidget { + const BusyMarkRadioButton({ + super.key, + required this.value, + required this.groupValue, + required this.onChanged, + required this.title, + this.subtitle, + this.contentPadding, + this.autofocus = false, + this.focusNode, + this.mouseCursor, + this.hasFocusBorder, + }); + + final T value; + final T? groupValue; + final ValueChanged? onChanged; + final Widget title; + final Widget? subtitle; + final EdgeInsetsGeometry? contentPadding; + final bool autofocus; + final FocusNode? focusNode; + final MouseCursor? mouseCursor; + final bool? hasFocusBorder; + + @override + State> createState() => _BusyMarkRadioButtonState(); +} + +class _BusyMarkRadioButtonState extends State> { + bool _hovered = false; + int? _pressedPointer; + + bool get _pressed => _pressedPointer != null; + + @override + void didUpdateWidget(BusyMarkRadioButton oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.onChanged == null) { + _pressedPointer = null; + } + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final inheritedRadioTheme = YaruRadioTheme.of(context); + final checkedColor = _busyMarkCheckedRadioColor( + theme.colorScheme.primary, + brightness: theme.brightness, + hovered: _hovered, + pressed: _pressed, + ); + + return MouseRegion( + onEnter: (_) => _setHovered(true), + onExit: (_) => _setHovered(false), + child: Listener( + onPointerDown: widget.onChanged == null ? null : _handlePointerDown, + onPointerUp: widget.onChanged == null ? null : _handlePointerUp, + onPointerCancel: widget.onChanged == null ? null : _handlePointerCancel, + child: YaruRadioTheme( + data: inheritedRadioTheme.copyWith( + color: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return inheritedRadioTheme.color?.resolve(states); + } + if (states.contains(WidgetState.selected)) { + return checkedColor; + } + return inheritedRadioTheme.color?.resolve(states); + }), + indicatorColor: const WidgetStatePropertyAll(Colors.transparent), + ), + child: YaruRadioButton( + value: widget.value, + groupValue: widget.groupValue, + onChanged: widget.onChanged, + title: widget.title, + subtitle: widget.subtitle, + contentPadding: widget.contentPadding, + autofocus: widget.autofocus, + focusNode: widget.focusNode, + mouseCursor: widget.mouseCursor, + hasFocusBorder: widget.hasFocusBorder, + ), + ), + ), + ); + } + + void _setHovered(bool hovered) { + if (_hovered != hovered) { + setState(() => _hovered = hovered); + } + } + + void _handlePointerDown(PointerDownEvent event) { + if (_pressedPointer != null || event.buttons != kPrimaryButton) { + return; + } + setState(() => _pressedPointer = event.pointer); + } + + void _handlePointerUp(PointerUpEvent event) { + if (_pressedPointer == event.pointer) { + setState(() => _pressedPointer = null); + } + } + + void _handlePointerCancel(PointerCancelEvent event) { + if (_pressedPointer == event.pointer) { + setState(() => _pressedPointer = null); + } + } +} + +Color _busyMarkCheckedRadioColor( + Color accent, { + required Brightness brightness, + required bool hovered, + required bool pressed, +}) { + final normalLightnessDelta = brightness == Brightness.light ? 0.05 : 0.0; + final stateLightnessDelta = pressed ? -0.07 : (hovered ? 0.07 : 0.0); + final hsl = HSLColor.fromColor(accent); + return hsl + .withLightness( + (hsl.lightness + normalLightnessDelta + stateLightnessDelta).clamp( + 0.0, + 1.0, + ), + ) + .toColor(); +} + class BusyMarkCheckbox extends StatelessWidget { const BusyMarkCheckbox({ super.key, diff --git a/lib/src/app/busymark_dialogs.dart b/lib/src/app/busymark_dialogs.dart index 41350185..5a22af42 100644 --- a/lib/src/app/busymark_dialogs.dart +++ b/lib/src/app/busymark_dialogs.dart @@ -708,6 +708,14 @@ void showLegacyBusyMarkKeyboardShortcutsDialog(BuildContext context) { BusyMarkTextEditingShortcutLabels.paste, ), ), + BusyMarkActionRow( + title: context.l10n.clipboardPastePlainText, + subtitle: context.l10n.shortcutPastePlainTextDescription, + leading: const Icon(BusyMarkGlyphs.paste), + trailing: const _KeyboardShortcutBadge( + BusyMarkTextEditingShortcutLabels.pastePlainText, + ), + ), BusyMarkActionRow( title: context.l10n.undo, subtitle: context.l10n.shortcutUndoDescription, diff --git a/lib/src/app/busymark_shortcuts.dart b/lib/src/app/busymark_shortcuts.dart index 7d9e628d..f95852b2 100644 --- a/lib/src/app/busymark_shortcuts.dart +++ b/lib/src/app/busymark_shortcuts.dart @@ -371,6 +371,7 @@ enum BusyMarkTextEditingShortcutAction { cut, copy, paste, + pastePlainText, undo, redo, insertIndentation, @@ -385,6 +386,7 @@ abstract final class BusyMarkTextEditingShortcuts { static const cutLabel = 'Ctrl+X'; static const copyLabel = 'Ctrl+C'; static const pasteLabel = 'Ctrl+V'; + static const pastePlainTextLabel = 'Ctrl+Shift+V'; static const undoLabel = 'Ctrl+Z'; static const redoLabel = 'Ctrl+Shift+Z'; static const insertIndentationLabel = 'Tab'; @@ -407,6 +409,14 @@ abstract final class BusyMarkTextEditingShortcuts { label: pasteLabel, activator: SingleActivator(LogicalKeyboardKey.keyV, control: true), ); + static const pastePlainText = BusyMarkShortcutDefinition( + label: pastePlainTextLabel, + activator: SingleActivator( + LogicalKeyboardKey.keyV, + control: true, + shift: true, + ), + ); static const undo = BusyMarkShortcutDefinition( label: undoLabel, activator: SingleActivator(LogicalKeyboardKey.keyZ, control: true), @@ -438,6 +448,7 @@ abstract final class BusyMarkTextEditingShortcuts { BusyMarkTextEditingShortcutAction.cut: cut, BusyMarkTextEditingShortcutAction.copy: copy, BusyMarkTextEditingShortcutAction.paste: paste, + BusyMarkTextEditingShortcutAction.pastePlainText: pastePlainText, BusyMarkTextEditingShortcutAction.undo: undo, BusyMarkTextEditingShortcutAction.redo: redo, BusyMarkTextEditingShortcutAction.insertIndentation: insertIndentation, @@ -453,6 +464,8 @@ abstract final class BusyMarkTextEditingShortcutLabels { static const cut = BusyMarkTextEditingShortcuts.cutLabel; static const copy = BusyMarkTextEditingShortcuts.copyLabel; static const paste = BusyMarkTextEditingShortcuts.pasteLabel; + static const pastePlainText = + BusyMarkTextEditingShortcuts.pastePlainTextLabel; static const undo = BusyMarkTextEditingShortcuts.undoLabel; static const redo = BusyMarkTextEditingShortcuts.redoLabel; static const insertIndentation = @@ -472,6 +485,8 @@ abstract final class BusyMarkTextEditingShortcutActivators { BusyMarkTextEditingShortcuts.copy.activator; static ShortcutActivator get paste => BusyMarkTextEditingShortcuts.paste.activator; + static ShortcutActivator get pastePlainText => + BusyMarkTextEditingShortcuts.pastePlainText.activator; static ShortcutActivator get undo => BusyMarkTextEditingShortcuts.undo.activator; static ShortcutActivator get redo => diff --git a/lib/src/app/command_registry.dart b/lib/src/app/command_registry.dart index 0497da16..ffeae413 100644 --- a/lib/src/app/command_registry.dart +++ b/lib/src/app/command_registry.dart @@ -268,12 +268,14 @@ abstract final class BusyMarkCommandIds { static const textCopy = 'text.copy'; static const editorCopyPlainText = 'editor.copyPlainText'; static const textPaste = 'text.paste'; + static const textPastePlainText = 'text.pastePlainText'; static const textUndo = 'text.undo'; static const textRedo = 'text.redo'; static const textInsertIndentation = 'text.insertIndentation'; static const textOutdentSource = 'text.outdentSource'; static const textEscape = 'text.escape'; static const editorRefineWithAi = 'editor.refineWithAi'; + static const checkSpelling = 'spelling.check'; static const sidebarFiles = 'sidebar.files'; static const sidebarToc = 'sidebar.toc'; static const sidebarOutline = 'sidebar.outline'; @@ -400,6 +402,20 @@ abstract final class BusyMarkCommandCatalog { shortcut: BusyMarkEditorShortcuts.definitions[action], description: (context) => _editorDescription(context, action), ), + command( + id: BusyMarkCommandIds.checkSpelling, + label: (context) => context.l10n.checkSpelling, + category: (context) => context.l10n.shortcutGroupTextEditing, + scope: BusyMarkCommandScope.editor, + shortcut: const BusyMarkShortcutDefinition( + label: 'F7', + activator: SingleActivator( + LogicalKeyboardKey.f7, + includeRepeats: false, + ), + gtkAccelerator: 'F7', + ), + ), for (final action in BusyMarkSidebarShortcutAction.values) command( id: _sidebarId(action), @@ -538,6 +554,8 @@ abstract final class BusyMarkCommandCatalog { BusyMarkTextEditingShortcutAction.cut => context.l10n.cut, BusyMarkTextEditingShortcutAction.copy => context.l10n.copy, BusyMarkTextEditingShortcutAction.paste => context.l10n.paste, + BusyMarkTextEditingShortcutAction.pastePlainText => + context.l10n.clipboardPastePlainText, BusyMarkTextEditingShortcutAction.undo => context.l10n.undo, BusyMarkTextEditingShortcutAction.redo => context.l10n.redo, BusyMarkTextEditingShortcutAction.insertIndentation => @@ -595,6 +613,8 @@ abstract final class BusyMarkCommandCatalog { context.l10n.shortcutCopyDescription, BusyMarkTextEditingShortcutAction.paste => context.l10n.shortcutPasteDescription, + BusyMarkTextEditingShortcutAction.pastePlainText => + context.l10n.shortcutPastePlainTextDescription, BusyMarkTextEditingShortcutAction.undo => context.l10n.shortcutUndoDescription, BusyMarkTextEditingShortcutAction.redo => diff --git a/lib/src/assets/asset_ingestion_service.dart b/lib/src/assets/asset_ingestion_service.dart index 97710bbb..9f8113d4 100644 --- a/lib/src/assets/asset_ingestion_service.dart +++ b/lib/src/assets/asset_ingestion_service.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -6,6 +7,8 @@ import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as p; import 'package:xml/xml.dart' as xml; +import '../core/atomic_file_writer.dart'; + enum AssetIngestionOrigin { imagePicker, screenshotPaste, @@ -56,6 +59,7 @@ class IngestedAsset { required this.mimeType, required this.reusedExisting, required this.origin, + this.publicationId, }); final String absolutePath; @@ -63,6 +67,26 @@ class IngestedAsset { final String mimeType; final bool reusedExisting; final AssetIngestionOrigin origin; + + /// Identifies a publication that is provisional until the caller commits + /// the document reference. Reused, already-committed assets have no ID. + final String? publicationId; +} + +class AssetIngestionHooks { + const AssetIngestionHooks({ + this.afterDestinationReserved, + this.afterPublication, + this.beforeCommit, + this.beforeRollback, + this.afterRollback, + }); + + final Future Function(String path)? afterDestinationReserved; + final Future Function(IngestedAsset asset)? afterPublication; + final Future Function(IngestedAsset asset)? beforeCommit; + final Future Function(IngestedAsset asset)? beforeRollback; + final Future Function(IngestedAsset asset)? afterRollback; } class IngestedAssetSnapshot { @@ -73,9 +97,19 @@ class IngestedAssetSnapshot { } class AssetIngestionService { - const AssetIngestionService({this.maximumAssetBytes = 100 * 1024 * 1024}); + const AssetIngestionService({ + this.maximumAssetBytes = 100 * 1024 * 1024, + this.hooks, + }); final int maximumAssetBytes; + final AssetIngestionHooks? hooks; + + static final Map _directoryOperations = {}; + static var _nextPublicationId = 0; + + static const _transactionDirectoryName = '.busymark-asset-transactions'; + static const _directoryLockFileName = 'directory.lock'; Future ingestFile({ required String sourcePath, @@ -205,34 +239,132 @@ class AssetIngestionService { required _DetectedAssetType type, }) async { final destination = await _destinationDirectory(request); - final contentHash = sha256.convert(bytes).toString(); - final existing = await _identicalAsset( - destination, - bytes.length, - contentHash, - ); - late final File published; - var reused = existing != null; - if (existing != null) { - published = existing; - } else { - final stem = _safeStem(p.basenameWithoutExtension(suggestedFileName)); - published = await _publishUnique( + final result = await _withDirectoryOperation(destination.path, () async { + final pending = await _pendingPublications(destination); + final contentHash = sha256.convert(bytes).toString(); + final existing = await _identicalAsset( destination, - stem: stem, - extension: type.extension, - bytes: bytes, + bytes.length, + contentHash, + pendingFinalNames: pending.values.toSet(), ); - reused = false; + late final File published; + String? publicationId; + final reused = existing != null; + if (existing != null) { + published = existing; + } else { + final stem = _safeStem(p.basenameWithoutExtension(suggestedFileName)); + publicationId = + '$pid-${DateTime.now().microsecondsSinceEpoch}-' + '${_nextPublicationId++}'; + published = await _publishUnique( + destination, + stem: stem, + extension: type.extension, + bytes: bytes, + publicationId: publicationId, + initiallyPendingFinalNames: pending.values.toSet(), + ); + } + return IngestedAsset( + absolutePath: published.path, + markdownPath: p + .relative(published.path, from: p.dirname(request.documentFilePath)) + .replaceAll(p.separator, '/'), + mimeType: type.mimeType, + reusedExisting: reused, + origin: origin, + publicationId: publicationId, + ); + }); + await hooks?.afterPublication?.call(result); + return result; + } + + /// Makes a provisional publication reusable and transfers its lifetime to + /// the successfully inserted document reference. + Future commit(IngestedAsset asset) async { + final publicationId = asset.publicationId; + if (publicationId == null) return; + await hooks?.beforeCommit?.call(asset); + final directory = p.dirname(asset.absolutePath); + await _withDirectoryOperation(directory, () async { + final record = await _ownedPendingRecord( + Directory(directory), + publicationId, + p.basename(asset.absolutePath), + ); + if (record != null) await record.delete(); + }); + } + + Future commitAll(Iterable assets) async { + for (final asset in assets) { + await commit(asset); } - return IngestedAsset( - absolutePath: published.path, - markdownPath: p - .relative(published.path, from: p.dirname(request.documentFilePath)) - .replaceAll(p.separator, '/'), - mimeType: type.mimeType, - reusedExisting: reused, - origin: origin, + } + + /// Removes [asset] only while this exact provisional publication still owns + /// the path. A reused or already-committed asset is never deleted. + Future rollback(IngestedAsset asset) async { + final publicationId = asset.publicationId; + if (publicationId == null) return; + await hooks?.beforeRollback?.call(asset); + final directory = p.dirname(asset.absolutePath); + await _withDirectoryOperation(directory, () async { + final record = await _ownedPendingRecord( + Directory(directory), + publicationId, + p.basename(asset.absolutePath), + ); + if (record == null) return; + final file = File(asset.absolutePath); + try { + if (await file.exists()) await file.delete(); + await record.delete(); + } on FileSystemException { + // Keep the durable ownership record when cleanup is incomplete. A + // later process must not deduplicate against an uncommitted asset. + } + }); + await hooks?.afterRollback?.call(asset); + } + + Future rollbackAll(Iterable assets) async { + for (final asset in assets) { + await rollback(asset); + } + } + + static Future _withDirectoryOperation( + String directoryPath, + Future Function() operation, + ) { + final key = p.normalize(p.absolute(directoryPath)); + final lock = _directoryOperations.putIfAbsent(key, _AssetDirectoryLock.new); + return lock.run( + () async { + final metadata = Directory(p.join(key, _transactionDirectoryName)); + await metadata.create(recursive: true); + final lockFile = File(p.join(metadata.path, _directoryLockFileName)); + final operatingSystemLock = lockFile.openSync(mode: FileMode.append); + try { + operatingSystemLock.lockSync(FileLock.blockingExclusive); + return await operation(); + } finally { + try { + operatingSystemLock.unlockSync(); + } finally { + operatingSystemLock.closeSync(); + } + } + }, + () { + if (identical(_directoryOperations[key], lock)) { + _directoryOperations.remove(key); + } + }, ); } @@ -307,8 +439,9 @@ class AssetIngestionService { Future _identicalAsset( Directory directory, int size, - String expectedHash, - ) async { + String expectedHash, { + required Set pendingFinalNames, + }) async { var inspected = 0; await for (final entity in directory.list(followLinks: false)) { if (++inspected > 10000) { @@ -317,7 +450,15 @@ class AssetIngestionService { if (entity is! File) { continue; } - final stat = await entity.stat(); + if (pendingFinalNames.contains(p.basename(entity.path))) { + continue; + } + late final FileStat stat; + try { + stat = await entity.stat(); + } on FileSystemException { + continue; + } if (stat.size != size) { continue; } @@ -334,32 +475,165 @@ class AssetIngestionService { required String stem, required String extension, required Uint8List bytes, + required String publicationId, + required Set initiallyPendingFinalNames, }) async { + final pendingFinalNames = {...initiallyPendingFinalNames}; var suffix = 1; - late File target; while (true) { final name = suffix == 1 ? '$stem.$extension' : '$stem-$suffix.$extension'; - target = File(p.join(directory.path, name)); - if (!await target.exists()) { - break; + final target = File(p.join(directory.path, name)); + if (pendingFinalNames.contains(name) || await target.exists()) { + suffix++; + continue; + } + final record = await _writePendingRecord( + directory, + publicationId: publicationId, + finalFilename: name, + ); + try { + await const AtomicFileWriter().writeBytes( + target.path, + bytes, + overwrite: false, + beforePublish: () async { + await hooks?.afterDestinationReserved?.call(target.path); + }, + ); + return target; + } on AtomicFileAlreadyExistsException { + await _removeOwnedPendingRecord( + record, + publicationId: publicationId, + finalFilename: name, + ); + suffix++; + } catch (_) { + await _removeOwnedPendingRecordBestEffort( + record, + publicationId: publicationId, + finalFilename: name, + ); + rethrow; } - suffix++; } - final staging = File( - p.join( - directory.path, - '.busymark-asset-$pid-${DateTime.now().microsecondsSinceEpoch}', + } + + static Directory _transactionDirectory(Directory assetDirectory) => + Directory(p.join(assetDirectory.path, _transactionDirectoryName)); + + static File _pendingRecordFile( + Directory assetDirectory, + String publicationId, + ) { + final digest = sha256.convert(utf8.encode(publicationId)).toString(); + return File( + p.join(_transactionDirectory(assetDirectory).path, '$digest.json'), + ); + } + + static Future _writePendingRecord( + Directory assetDirectory, { + required String publicationId, + required String finalFilename, + }) async { + final record = _pendingRecordFile(assetDirectory, publicationId); + await const AtomicFileWriter().writeBytes( + record.path, + utf8.encode( + jsonEncode({ + 'publicationToken': publicationId, + 'finalFilename': finalFilename, + }), ), + overwrite: false, ); + return record; + } + + static Future> _pendingPublications( + Directory assetDirectory, + ) async { + final result = {}; + final metadata = _transactionDirectory(assetDirectory); + if (!await metadata.exists()) return result; + await for (final entity in metadata.list(followLinks: false)) { + if (entity is! File || + p.basename(entity.path) == _directoryLockFileName) { + continue; + } + final record = await _readPendingRecord(entity); + if (record != null) { + result[record.publicationId] = record.finalFilename; + } + } + return result; + } + + static Future<({String publicationId, String finalFilename})?> + _readPendingRecord(File record) async { try { - await staging.writeAsBytes(bytes, flush: true); - return await staging.rename(target.path); - } finally { - if (await staging.exists()) { - await staging.delete(); + final decoded = jsonDecode(await record.readAsString()); + if (decoded is! Map) return null; + final publicationId = decoded['publicationToken']; + final finalFilename = decoded['finalFilename']; + if (publicationId is! String || + publicationId.isEmpty || + finalFilename is! String || + finalFilename.isEmpty || + p.basename(finalFilename) != finalFilename) { + return null; } + return (publicationId: publicationId, finalFilename: finalFilename); + } on Object { + return null; + } + } + + static Future _ownedPendingRecord( + Directory assetDirectory, + String publicationId, + String finalFilename, + ) async { + final record = _pendingRecordFile(assetDirectory, publicationId); + if (!await record.exists()) return null; + final contents = await _readPendingRecord(record); + if (contents == null || + contents.publicationId != publicationId || + contents.finalFilename != finalFilename) { + return null; + } + return record; + } + + static Future _removeOwnedPendingRecord( + File record, { + required String publicationId, + required String finalFilename, + }) async { + final contents = await _readPendingRecord(record); + if (contents?.publicationId == publicationId && + contents?.finalFilename == finalFilename) { + await record.delete(); + } + } + + static Future _removeOwnedPendingRecordBestEffort( + File record, { + required String publicationId, + required String finalFilename, + }) async { + try { + await _removeOwnedPendingRecord( + record, + publicationId: publicationId, + finalFilename: finalFilename, + ); + } on FileSystemException { + // A stale reservation is safer than making uncertain bytes reusable. } } @@ -430,6 +704,34 @@ class AssetIngestionService { }; } +class _AssetDirectoryLock { + var _locked = false; + final _waiters = >[]; + + Future run( + Future Function() operation, + void Function() onIdle, + ) async { + if (_locked) { + final waiter = Completer(); + _waiters.add(waiter); + await waiter.future; + } else { + _locked = true; + } + try { + return await operation(); + } finally { + if (_waiters.isNotEmpty) { + _waiters.removeAt(0).complete(); + } else { + _locked = false; + onIdle(); + } + } + } +} + class _DetectedAssetType { const _DetectedAssetType(this.extension, this.mimeType); diff --git a/lib/src/clipboard/clipboard_history_controller.dart b/lib/src/clipboard/clipboard_history_controller.dart index c3278ca3..a56dd09b 100644 --- a/lib/src/clipboard/clipboard_history_controller.dart +++ b/lib/src/clipboard/clipboard_history_controller.dart @@ -183,8 +183,8 @@ class ClipboardHistoryController extends Notifier { } else if (first.text != null || first.sourceText != null) { capture = BusyMarkClipboardCapture( kind: BusyMarkClipboardContentKind.text, - text: first.text ?? first.sourceText, - sourceText: first.sourceText ?? first.text, + text: first.text, + sourceText: first.sourceText, origin: first.origin, external: !first.sessionOwned, ); @@ -200,6 +200,7 @@ class ClipboardHistoryController extends Notifier { imageBytes: image.bytes, imageMimeType: image.mimeType, imageDisplayName: image.name, + origin: first.origin, external: true, ); } diff --git a/lib/src/clipboard/clipboard_history_panel.dart b/lib/src/clipboard/clipboard_history_panel.dart index e93f823f..69a10b1c 100644 --- a/lib/src/clipboard/clipboard_history_panel.dart +++ b/lib/src/clipboard/clipboard_history_panel.dart @@ -169,16 +169,25 @@ class _ClipboardHistoryPanelState extends ConsumerState { payload: payload, current: identical(payload, current), selected: payload.id == _selectedId, - canPaste: registry.canPaste(payload), + canPaste: registry.canPaste( + payload, + mode: BusyMarkPasteMode.normal, + ), onSelect: () { setState(() => _selectedId = payload.id); _listFocusNode.requestFocus(); }, - onPaste: () => _paste(payload, plainText: false), + onPaste: () => + _paste(payload, mode: BusyMarkPasteMode.normal), onPastePlain: - payload.hasMeaningfulTextRepresentation && - registry.canPaste(payload, plainText: true) - ? () => _paste(payload, plainText: true) + registry.canPaste( + payload, + mode: BusyMarkPasteMode.plainText, + ) + ? () => _paste( + payload, + mode: BusyMarkPasteMode.plainText, + ) : null, onRemove: identical(payload, current) ? null @@ -235,8 +244,8 @@ class _ClipboardHistoryPanelState extends ConsumerState { } final selected = index < 0 ? visible.first : visible[index]; if (event.logicalKey == LogicalKeyboardKey.enter && - registry.canPaste(selected)) { - unawaited(_paste(selected, plainText: false)); + registry.canPaste(selected, mode: BusyMarkPasteMode.normal)) { + unawaited(_paste(selected, mode: BusyMarkPasteMode.normal)); return KeyEventResult.handled; } if (event.logicalKey == LogicalKeyboardKey.delete && @@ -267,17 +276,13 @@ class _ClipboardHistoryPanelState extends ConsumerState { Future _paste( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }) async { - // Both dependencies outlive this sidebar panel. Capture them before the - // asynchronous insertion so a successful editor operation can still be - // retained if the user switches sidebar tabs while it is in flight. final registry = ref.read(clipboardInsertionRegistryProvider); - final history = ref.read(clipboardHistoryControllerProvider.notifier); - final result = await registry.paste(payload, plainText: plainText); - if (result == ClipboardPasteResult.inserted && payload.external) { - history.retainCurrentAfterPaste(payload); - } else if (result != ClipboardPasteResult.inserted && mounted) { + final result = await registry.paste(payload, mode: mode); + if ((result == ClipboardPasteResult.unsupported || + result == ClipboardPasteResult.unavailable) && + mounted) { BusyMarkToastOverlay.show( context, message: context.l10n.clipboardUnavailable, @@ -432,7 +437,7 @@ String _clipboardEntryPreview( ) { final value = payload.imageDisplayName ?? - payload.preferredSourceText ?? + payload.displayText ?? payload.text ?? fallback; final preview = value.trim(); diff --git a/lib/src/clipboard/clipboard_insertion.dart b/lib/src/clipboard/clipboard_insertion.dart index f538520e..313e1843 100644 --- a/lib/src/clipboard/clipboard_insertion.dart +++ b/lib/src/clipboard/clipboard_insertion.dart @@ -4,6 +4,8 @@ import 'package:flutter/foundation.dart'; import 'clipboard_models.dart'; +enum BusyMarkPasteMode { normal, plainText } + abstract interface class BusyMarkClipboardInsertionTarget { String get documentId; String get documentName; @@ -12,7 +14,7 @@ abstract interface class BusyMarkClipboardInsertionTarget { Future paste( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }); void requestEditorFocus(); @@ -20,7 +22,10 @@ abstract interface class BusyMarkClipboardInsertionTarget { /// Optional destination-specific capability used to keep panel actions honest. abstract interface class BusyMarkClipboardInsertionCapabilities { - bool canPaste(BusyMarkClipboardPayload payload, {required bool plainText}); + bool canPaste( + BusyMarkClipboardPayload payload, { + required BusyMarkPasteMode mode, + }); } /// Holds only the currently mounted document surface. Registrations remove @@ -33,12 +38,15 @@ class BusyMarkClipboardInsertionRegistry extends ChangeNotifier { BusyMarkClipboardInsertionTarget? get target => _target; - bool canPaste(BusyMarkClipboardPayload payload, {bool plainText = false}) { + bool canPaste( + BusyMarkClipboardPayload payload, { + BusyMarkPasteMode mode = BusyMarkPasteMode.normal, + }) { final captured = _target; if (captured == null || !captured.editable) return false; if (captured is BusyMarkClipboardInsertionCapabilities) { final capabilities = captured as BusyMarkClipboardInsertionCapabilities; - return capabilities.canPaste(payload, plainText: plainText); + return capabilities.canPaste(payload, mode: mode); } return true; } @@ -72,7 +80,7 @@ class BusyMarkClipboardInsertionRegistry extends ChangeNotifier { Future paste( BusyMarkClipboardPayload payload, { - bool plainText = false, + BusyMarkPasteMode mode = BusyMarkPasteMode.normal, }) async { final captured = _target; if (captured == null || @@ -80,11 +88,11 @@ class BusyMarkClipboardInsertionRegistry extends ChangeNotifier { (captured is BusyMarkClipboardInsertionCapabilities && !(captured as BusyMarkClipboardInsertionCapabilities).canPaste( payload, - plainText: plainText, + mode: mode, ))) { return ClipboardPasteResult.unavailable; } - final result = await captured.paste(payload, plainText: plainText); + final result = await captured.paste(payload, mode: mode); if (result == ClipboardPasteResult.inserted && identical(_target, captured)) { captured.requestEditorFocus(); diff --git a/lib/src/clipboard/clipboard_models.dart b/lib/src/clipboard/clipboard_models.dart index df9ff64b..8ed8a054 100644 --- a/lib/src/clipboard/clipboard_models.dart +++ b/lib/src/clipboard/clipboard_models.dart @@ -21,10 +21,11 @@ class BusyMarkClipboardOrigin { /// An immutable, source-independent clipboard snapshot. /// -/// [sourceText] is the representation inserted into Source mode. [text] is -/// the interoperable plain-text representation. A rich fragment is an opaque, -/// validated BusyMark schema and is never reconstructed from plain-text -/// equality. +/// [text] is the interoperable plain-text representation. [sourceText] is an +/// optional authored/source representation. The active paste mode and +/// destination decide which representation is inserted. A rich fragment is an +/// opaque, validated BusyMark schema and is never reconstructed from +/// plain-text equality. @immutable class BusyMarkClipboardPayload { BusyMarkClipboardPayload({ @@ -97,10 +98,14 @@ class BusyMarkClipboardPayload { final String fingerprint; final int accountedBytes; - bool get hasMeaningfulTextRepresentation => - sourceText != null || text != null; + bool get hasPlainTextRepresentation => text != null && text!.isNotEmpty; - String? get preferredSourceText => sourceText ?? text; + bool get hasSourceOrTextRepresentation => + (sourceText != null && sourceText!.isNotEmpty) || + hasPlainTextRepresentation; + + /// Used only for Clipboard History presentation, never paste policy. + String? get displayText => sourceText ?? text; bool equivalentTo(BusyMarkClipboardPayload other) => fingerprint == other.fingerprint && @@ -271,4 +276,10 @@ class ClipboardHistoryPolicy { enum ClipboardRetentionResult { retained, deduplicated, disabled, oversized } -enum ClipboardPasteResult { inserted, staleTarget, unsupported, unavailable } +enum ClipboardPasteResult { + inserted, + cancelled, + staleTarget, + unsupported, + unavailable, +} diff --git a/lib/src/core/atomic_file_writer.dart b/lib/src/core/atomic_file_writer.dart index 6899b468..32feba68 100644 --- a/lib/src/core/atomic_file_writer.dart +++ b/lib/src/core/atomic_file_writer.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:path/path.dart' as p; @@ -13,6 +14,23 @@ class AtomicFileAlreadyExistsException implements Exception { String toString() => 'A filesystem entity already exists at "$path".'; } +class AtomicFileChangedException implements Exception { + const AtomicFileChangedException(this.path, {this.recoveryPath, this.cause}); + + final String path; + final String? recoveryPath; + final Object? cause; + + @override + String toString() { + final recovery = recoveryPath == null + ? '' + : ' The displaced version was preserved at "$recoveryPath".'; + final detail = cause == null ? '' : ' Validation failed: $cause.'; + return 'The file at "$path" changed during publication.$recovery$detail'; + } +} + /// Publishes generated bytes without ever exposing a partially written file. class AtomicFileWriter { const AtomicFileWriter(); @@ -21,6 +39,8 @@ class AtomicFileWriter { String targetPath, List bytes, { required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, }) async { if (!Platform.isLinux) { throw UnsupportedError( @@ -38,8 +58,10 @@ class AtomicFileWriter { final stagingDirectory = await parent.createTemp('.busymark-export-'); final stagedFile = File(p.join(stagingDirectory.path, 'document.bin')); + var preserveStagedFile = false; try { await stagedFile.writeAsBytes(bytes, flush: true); + await beforePublish?.call(); if (overwrite) { final targetType = await FileSystemEntity.type( absoluteTarget, @@ -52,6 +74,59 @@ class AtomicFileWriter { absoluteTarget, ); } + if (acceptReplaced != null) { + if (targetType == FileSystemEntityType.notFound) { + final errorNumber = LinuxAtomicFileApi.instance.publishNoReplace( + stagedFile.absolute.path, + absoluteTarget, + ); + if (errorNumber == null) return; + if (errorNumber == LinuxAtomicFileApi.fileExistsError) { + throw AtomicFileChangedException(absoluteTarget); + } + throw FileSystemException( + 'Failed to atomically publish the new file', + absoluteTarget, + OSError('no-replace publication failed', errorNumber), + ); + } + final atomicApi = LinuxAtomicFileApi.instance; + if (!atomicApi.isAvailable) { + throw FileSystemException( + 'Conflict-safe replacement requires Linux renameat2', + absoluteTarget, + ); + } + final exchangeError = atomicApi.exchange( + stagedFile.absolute.path, + absoluteTarget, + ); + if (exchangeError != null) { + throw AtomicFileChangedException(absoluteTarget); + } + Object? callbackError; + var accepted = false; + try { + accepted = await acceptReplaced(stagedFile.absolute.path); + } on Object catch (error) { + callbackError = error; + } + if (!accepted || callbackError != null) { + // Once the exchange has completed, [absoluteTarget] can be + // changed again while the asynchronous validation is running. + // A second exchange would then overwrite that newer version and + // the normal staging cleanup would delete it. Ownership is + // uncertain here, so leave the destination alone and retain the + // displaced bytes for explicit recovery. + preserveStagedFile = true; + throw AtomicFileChangedException( + absoluteTarget, + recoveryPath: stagedFile.absolute.path, + cause: callbackError, + ); + } + return; + } await stagedFile.rename(absoluteTarget); return; } @@ -72,9 +147,9 @@ class AtomicFileWriter { OSError('no-replace publication failed', errorNumber), ); } finally { - await _deleteBestEffort(stagedFile); + if (!preserveStagedFile) await _deleteBestEffort(stagedFile); try { - if (await stagingDirectory.exists()) { + if (!preserveStagedFile && await stagingDirectory.exists()) { await stagingDirectory.delete(); } } on Object { diff --git a/lib/src/editor/clipboard_local_image_path.dart b/lib/src/editor/clipboard_local_image_path.dart new file mode 100644 index 00000000..a9abd8dd --- /dev/null +++ b/lib/src/editor/clipboard_local_image_path.dart @@ -0,0 +1,52 @@ +import 'dart:io'; + +import 'package:path/path.dart' as p; + +const _supportedImageExtensions = { + '.png', + '.jpg', + '.jpeg', + '.gif', + '.webp', + '.svg', +}; + +/// Returns a supported, existing local image path when [value] can safely be +/// interpreted as one. Callers must keep [value] unchanged for text fallback. +String? busyMarkLocalImagePathFromClipboardText(String value) { + final detectionValue = value.trim(); + if (detectionValue.isEmpty || + detectionValue.contains('\n') || + detectionValue.contains('\r')) { + return null; + } + final uri = Uri.tryParse(detectionValue); + if (uri == null) return null; + String candidate; + if (uri.scheme.isEmpty) { + candidate = detectionValue; + } else if (uri.scheme == 'file' && + uri.authority.isEmpty && + !uri.hasQuery && + !uri.hasFragment) { + try { + candidate = File.fromUri(uri).path; + } on ArgumentError { + return null; + } on UnsupportedError { + return null; + } + } else { + return null; + } + if (!_supportedImageExtensions.contains( + p.extension(candidate).toLowerCase(), + )) { + return null; + } + try { + return File(candidate).existsSync() ? candidate : null; + } on FileSystemException { + return null; + } +} diff --git a/lib/src/editor/clipboard_paste_resolver.dart b/lib/src/editor/clipboard_paste_resolver.dart new file mode 100644 index 00000000..f3ff28ea --- /dev/null +++ b/lib/src/editor/clipboard_paste_resolver.dart @@ -0,0 +1,305 @@ +import 'package:flutter/foundation.dart'; + +import '../clipboard/clipboard_insertion.dart'; +import '../clipboard/clipboard_models.dart'; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_model.dart'; +import '../platform/rich_clipboard_service.dart'; +import 'wysiwyg/wysiwyg_clipboard_fragment.dart'; +import 'wysiwyg/wysiwyg_clipboard_html.dart'; + +enum BusyMarkPasteDestination { + editor, + markdownSource, + writersideXmlSource, + genericXmlSource, + plainSource, +} + +@immutable +class BusyMarkClipboardSnapshot { + BusyMarkClipboardSnapshot({ + this.text, + this.sourceText, + this.html, + this.richFragment, + Map mediaBytes = const {}, + this.mediaComplete = true, + Uint8List? imageBytes, + this.imageMimeType, + this.imageDisplayName, + this.origin, + required this.external, + required this.sessionOwned, + this.contentKind, + required this.fromSystemClipboard, + }) : mediaBytes = Map.unmodifiable({ + for (final entry in mediaBytes.entries) + entry.key: Uint8List.fromList(entry.value), + }), + imageBytes = imageBytes == null ? null : Uint8List.fromList(imageBytes); + + factory BusyMarkClipboardSnapshot.fromSystem(RichClipboardData data) => + BusyMarkClipboardSnapshot( + text: data.text, + sourceText: data.sourceText, + html: data.html, + richFragment: data.richFragment, + mediaBytes: data.mediaBytes, + mediaComplete: data.mediaComplete, + origin: data.origin, + external: !data.sessionOwned, + sessionOwned: data.sessionOwned, + fromSystemClipboard: true, + ); + + factory BusyMarkClipboardSnapshot.fromPayload( + BusyMarkClipboardPayload payload, + ) => BusyMarkClipboardSnapshot( + text: payload.text, + sourceText: payload.sourceText, + html: payload.html, + richFragment: payload.richFragment, + mediaBytes: payload.mediaBytes, + mediaComplete: payload.mediaComplete, + imageBytes: payload.imageBytes, + imageMimeType: payload.imageMimeType, + imageDisplayName: payload.imageDisplayName, + origin: payload.origin, + external: payload.external, + sessionOwned: !payload.external, + contentKind: payload.kind, + fromSystemClipboard: false, + ); + + final String? text; + final String? sourceText; + final String? html; + final String? richFragment; + final Map mediaBytes; + final bool mediaComplete; + final Uint8List? imageBytes; + final String? imageMimeType; + final String? imageDisplayName; + final BusyMarkClipboardOrigin? origin; + final bool external; + final bool sessionOwned; + final BusyMarkClipboardContentKind? contentKind; + final bool fromSystemClipboard; +} + +enum BusyMarkStructuredClipboardSource { richFragment, html } + +sealed class BusyMarkPasteCandidate { + const BusyMarkPasteCandidate(); +} + +@immutable +class BusyMarkStructuredPasteCandidate extends BusyMarkPasteCandidate { + const BusyMarkStructuredPasteCandidate({ + required this.fragment, + required this.source, + }); + + final WysiwygClipboardFragment fragment; + final BusyMarkStructuredClipboardSource source; +} + +@immutable +class BusyMarkSourceTextPasteCandidate extends BusyMarkPasteCandidate { + const BusyMarkSourceTextPasteCandidate(this.text); + + final String text; +} + +@immutable +class BusyMarkPlainTextPasteCandidate extends BusyMarkPasteCandidate { + const BusyMarkPlainTextPasteCandidate(this.text); + + final String text; +} + +@immutable +class BusyMarkImagePasteCandidate extends BusyMarkPasteCandidate { + const BusyMarkImagePasteCandidate({ + required this.bytes, + this.mimeType, + this.displayName, + }); + + final Uint8List bytes; + final String? mimeType; + final String? displayName; +} + +/// Marks the separate native image boundary. The insertion adapter must +/// acquire the bytes and revalidate the system clipboard identity. +@immutable +class BusyMarkNativeImagePasteCandidate extends BusyMarkPasteCandidate { + const BusyMarkNativeImagePasteCandidate(); +} + +@immutable +class BusyMarkPastePlan { + const BusyMarkPastePlan(this.candidates); + + final List candidates; + + bool get isEmpty => candidates.isEmpty; +} + +class BusyMarkClipboardPasteResolver { + const BusyMarkClipboardPasteResolver(); + + BusyMarkPastePlan resolve({ + required BusyMarkClipboardSnapshot snapshot, + required BusyMarkPasteMode mode, + required BusyMarkPasteDestination destination, + MarkdownMode? markdownMode, + }) { + final text = _available(snapshot.text); + if (mode == BusyMarkPasteMode.plainText) { + return BusyMarkPastePlan( + text == null ? const [] : [BusyMarkPlainTextPasteCandidate(text)], + ); + } + + final supportsImages = switch (destination) { + BusyMarkPasteDestination.editor || + BusyMarkPasteDestination.markdownSource || + BusyMarkPasteDestination.writersideXmlSource => true, + BusyMarkPasteDestination.genericXmlSource || + BusyMarkPasteDestination.plainSource => false, + }; + if (snapshot.contentKind == BusyMarkClipboardContentKind.image) { + final bytes = snapshot.imageBytes; + return BusyMarkPastePlan( + supportsImages && bytes != null && bytes.isNotEmpty + ? [ + BusyMarkImagePasteCandidate( + bytes: bytes, + mimeType: snapshot.imageMimeType, + displayName: snapshot.imageDisplayName, + ), + ] + : const [], + ); + } + + final sourceText = _available(snapshot.sourceText); + final candidates = []; + final supportsStructured = + destination == BusyMarkPasteDestination.editor || + destination == BusyMarkPasteDestination.markdownSource; + if (supportsStructured) { + final encoded = _available(snapshot.richFragment); + final nativeFragment = encoded == null + ? null + : WysiwygClipboardFragment.decode(encoded); + if (nativeFragment != null) { + candidates.add( + BusyMarkStructuredPasteCandidate( + fragment: nativeFragment, + source: BusyMarkStructuredClipboardSource.richFragment, + ), + ); + } + final html = _available(snapshot.html); + if (html != null) { + try { + final decoded = const WysiwygClipboardHtml().decode( + html, + mode: markdownMode ?? MarkdownMode.commonMark, + ); + if (decoded != null && hasUsableClipboardHtmlContent(decoded)) { + candidates.add( + BusyMarkStructuredPasteCandidate( + fragment: decoded, + source: BusyMarkStructuredClipboardSource.html, + ), + ); + } + } on FormatException { + // A malformed richer representation never suppresses fallbacks. + } on ArgumentError { + // Treat invalid HTML input as unavailable. + } + } + } + + switch (destination) { + case BusyMarkPasteDestination.editor: + if (text != null) candidates.add(BusyMarkPlainTextPasteCandidate(text)); + if (text == null && sourceText != null) { + candidates.add(BusyMarkSourceTextPasteCandidate(sourceText)); + } + case BusyMarkPasteDestination.markdownSource: + if (sourceText != null) { + candidates.add(BusyMarkSourceTextPasteCandidate(sourceText)); + } + if (text != null) candidates.add(BusyMarkPlainTextPasteCandidate(text)); + case BusyMarkPasteDestination.writersideXmlSource: + case BusyMarkPasteDestination.genericXmlSource: + case BusyMarkPasteDestination.plainSource: + if (sourceText != null) { + candidates.add(BusyMarkSourceTextPasteCandidate(sourceText)); + } + if (text != null) candidates.add(BusyMarkPlainTextPasteCandidate(text)); + } + if (candidates.isEmpty && snapshot.fromSystemClipboard && supportsImages) { + candidates.add(const BusyMarkNativeImagePasteCandidate()); + } + return BusyMarkPastePlan(List.unmodifiable(candidates)); + } +} + +BusyMarkClipboardCapture busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot snapshot, { + Uint8List? imageBytes, + String? imageMimeType, + String? imageDisplayName, +}) { + final retainedImageBytes = imageBytes ?? snapshot.imageBytes; + final kind = retainedImageBytes != null && retainedImageBytes.isNotEmpty + ? BusyMarkClipboardContentKind.image + : snapshot.contentKind ?? + (snapshot.richFragment != null || snapshot.html != null + ? BusyMarkClipboardContentKind.richText + : BusyMarkClipboardContentKind.text); + return BusyMarkClipboardCapture( + kind: kind, + text: snapshot.text, + sourceText: snapshot.sourceText, + html: snapshot.html, + richFragment: snapshot.richFragment, + imageBytes: retainedImageBytes, + imageMimeType: imageMimeType ?? snapshot.imageMimeType, + imageDisplayName: imageDisplayName ?? snapshot.imageDisplayName, + origin: snapshot.origin, + mediaBytes: snapshot.mediaBytes, + mediaComplete: snapshot.mediaComplete, + external: snapshot.external, + ); +} + +bool hasUsableClipboardHtmlContent(WysiwygClipboardFragment fragment) => + fragment.documentBlocks.any(_hasUsableClipboardBlockContent); + +bool _hasUsableClipboardBlockContent(BusyBlock block) { + if (block.plainText.isNotEmpty || + block.kind == BusyBlockKind.image || + block.kind == BusyBlockKind.video || + block.kind == BusyBlockKind.thematicBreak || + block.kind == BusyBlockKind.table || + block.inlines.any(_hasUsableClipboardInlineContent)) { + return true; + } + return block.children.any(_hasUsableClipboardBlockContent); +} + +bool _hasUsableClipboardInlineContent(BusyInline inline) => + inline.kind == BusyInlineKind.image || + inline.children.any(_hasUsableClipboardInlineContent); + +String? _available(String? value) => + value == null || value.isEmpty ? null : value; diff --git a/lib/src/editor/editor_text_context_menu.dart b/lib/src/editor/editor_text_context_menu.dart index 218d8c2a..2123f6b7 100644 --- a/lib/src/editor/editor_text_context_menu.dart +++ b/lib/src/editor/editor_text_context_menu.dart @@ -6,6 +6,70 @@ import '../app/busymark_design.dart'; import '../app/busymark_glyphs.dart'; import '../app/command_registry.dart'; +@immutable +class BusyMarkEditorTextPasteAvailability { + const BusyMarkEditorTextPasteAvailability({ + required this.normal, + required this.plainText, + }); + + static const unavailable = BusyMarkEditorTextPasteAvailability( + normal: false, + plainText: false, + ); + + final bool normal; + final bool plainText; +} + +typedef BusyMarkEditorTextPasteAvailabilityReader = + Future Function(); + +@immutable +class BusyMarkEditorSpellingMenuItem { + const BusyMarkEditorSpellingMenuItem({ + required this.label, + required this.onSelected, + this.enabled = true, + this.suggestion = false, + this.checked = false, + this.mutuallyExclusive = false, + }) : children = const [], + divider = false; + + const BusyMarkEditorSpellingMenuItem.submenu({ + required this.label, + required this.children, + this.enabled = true, + }) : onSelected = null, + suggestion = false, + checked = false, + mutuallyExclusive = false, + divider = false; + + const BusyMarkEditorSpellingMenuItem.divider() + : label = '', + onSelected = null, + enabled = false, + suggestion = false, + checked = false, + mutuallyExclusive = false, + children = const [], + divider = true; + + final String label; + final VoidCallback? onSelected; + final bool enabled; + final bool suggestion; + final bool checked; + final bool mutuallyExclusive; + final List children; + final bool divider; +} + +typedef BusyMarkEditorSpellingMenuReader = + Future> Function(int offset); + Widget buildBusyMarkEditorTextContextMenu( BuildContext context, EditableTextState editableTextState, { @@ -14,8 +78,12 @@ Widget buildBusyMarkEditorTextContextMenu( VoidCallback? onCut, VoidCallback? onCopy, VoidCallback? onPaste, + VoidCallback? onPastePlainText, + BusyMarkEditorTextPasteAvailabilityReader? readPasteAvailability, VoidCallback? onCopyPlainText, List> additionalItems = const [], + BusyMarkEditorSpellingMenuReader? readSpellingItems, + VoidCallback? onCheckSpelling, }) { return _BusyMarkEditorTextContextMenu( editableTextState: editableTextState, @@ -24,8 +92,12 @@ Widget buildBusyMarkEditorTextContextMenu( onCut: onCut, onCopy: onCopy, onPaste: onPaste, + onPastePlainText: onPastePlainText, + readPasteAvailability: readPasteAvailability, onCopyPlainText: onCopyPlainText, additionalItems: additionalItems, + readSpellingItems: readSpellingItems, + onCheckSpelling: onCheckSpelling, ); } @@ -37,8 +109,12 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { required this.onCut, required this.onCopy, required this.onPaste, + required this.onPastePlainText, + required this.readPasteAvailability, required this.onCopyPlainText, required this.additionalItems, + required this.readSpellingItems, + required this.onCheckSpelling, }); final EditableTextState editableTextState; @@ -47,8 +123,12 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { final VoidCallback? onCut; final VoidCallback? onCopy; final VoidCallback? onPaste; + final VoidCallback? onPastePlainText; + final BusyMarkEditorTextPasteAvailabilityReader? readPasteAvailability; final VoidCallback? onCopyPlainText; final List> additionalItems; + final BusyMarkEditorSpellingMenuReader? readSpellingItems; + final VoidCallback? onCheckSpelling; @override State<_BusyMarkEditorTextContextMenu> createState() => @@ -59,6 +139,9 @@ class _BusyMarkEditorTextContextMenuState extends State<_BusyMarkEditorTextContextMenu> { final _menuSession = BusyMarkMenuSession(); var _presented = false; + var _pasteAvailability = BusyMarkEditorTextPasteAvailability.unavailable; + List _spellingItems = const []; + var _spellingPreparationTimedOut = false; @override void initState() { @@ -80,22 +163,18 @@ class _BusyMarkEditorTextContextMenuState return; } _presented = true; - final clipboardStatus = widget.editableTextState.clipboardStatus; - if (clipboardStatus.value == ClipboardStatus.unknown) { - await clipboardStatus.update().timeout( - const Duration(milliseconds: 500), - onTimeout: () {}, - ); - if (!mounted) { - return; - } + final selection = widget.editableTextState.textEditingValue.selection; + final offset = selection.isValid ? selection.extentOffset : 0; + await Future.wait([_preparePaste(), _prepareSpelling(offset)]); + if (!mounted) { + return; } final action = await showBusyMarkMenu( context: context, anchorPoint: widget.editableTextState.contextMenuAnchors.primaryAnchor, items: _menuItems(context), session: _menuSession, - width: widget.onCopyPlainText == null + width: widget.onCopyPlainText == null && widget.onPastePlainText == null ? BusyMarkSizes.popupMenuMinWidth : BusyMarkSizes.editorContextMenuWidth, ); @@ -106,6 +185,46 @@ class _BusyMarkEditorTextContextMenuState action?.call(); } + Future _preparePaste() async { + final availabilityReader = widget.readPasteAvailability; + if (availabilityReader != null) { + try { + _pasteAvailability = await availabilityReader(); + } on Object { + _pasteAvailability = BusyMarkEditorTextPasteAvailability.unavailable; + } + return; + } + final clipboardStatus = widget.editableTextState.clipboardStatus; + if (clipboardStatus.value == ClipboardStatus.unknown) { + await clipboardStatus.update().timeout( + const Duration(milliseconds: 500), + onTimeout: () {}, + ); + } + final textAvailable = clipboardStatus.value == ClipboardStatus.pasteable; + _pasteAvailability = BusyMarkEditorTextPasteAvailability( + normal: textAvailable, + plainText: textAvailable, + ); + } + + Future _prepareSpelling(int offset) async { + final reader = widget.readSpellingItems; + if (reader == null) return; + try { + _spellingItems = await reader(offset).timeout( + const Duration(milliseconds: 350), + onTimeout: () { + _spellingPreparationTimedOut = true; + return const []; + }, + ); + } on Object { + _spellingItems = const []; + } + } + List> _menuItems(BuildContext context) { final editable = widget.editableTextState; final commands = @@ -114,7 +233,64 @@ class _BusyMarkEditorTextContextMenuState final selection = editable.textEditingValue.selection; final hasSelection = selection.isValid && !selection.isCollapsed; final items = >[]; + var addedBusyMarkPaste = false; + final spellingFallback = widget.onCheckSpelling; + + if (_spellingItems.isNotEmpty) { + for (final item in _spellingItems) { + items.add(_spellingMenuEntry(item)); + } + items.add(const PopupMenuDivider(height: BusyMarkSpacing.sm)); + } else if (_spellingPreparationTimedOut && spellingFallback != null) { + final command = commands[BusyMarkCommandIds.checkSpelling]; + items.add( + BusyMarkPopupMenuItem( + value: spellingFallback, + label: command?.label(context) ?? '', + shortcut: command?.shortcut?.label, + ), + ); + items.add(const PopupMenuDivider(height: BusyMarkSpacing.sm)); + } + + void addBusyMarkPasteItems() { + if (addedBusyMarkPaste) return; + addedBusyMarkPaste = true; + final paste = widget.onPaste; + if (paste != null && _pasteAvailability.normal) { + final command = commands[BusyMarkCommandIds.textPaste]!; + items.add( + BusyMarkPopupMenuItem( + value: paste, + label: command.label(context), + icon: BusyMarkGlyphs.paste, + shortcut: command.shortcut?.label, + ), + ); + } + final pastePlainText = widget.onPastePlainText; + if (pastePlainText != null && _pasteAvailability.plainText) { + final command = commands[BusyMarkCommandIds.textPastePlainText]!; + items.add( + BusyMarkPopupMenuItem( + value: pastePlainText, + label: command.label(context), + icon: BusyMarkGlyphs.paste, + shortcut: command.shortcut?.label, + ), + ); + } + } + for (final item in editable.contextMenuButtonItems) { + if (widget.onPaste != null && item.type == ContextMenuButtonType.paste) { + addBusyMarkPasteItems(); + continue; + } + if (widget.onPaste != null && + item.type == ContextMenuButtonType.selectAll) { + addBusyMarkPasteItems(); + } final callback = switch (item.type) { ContextMenuButtonType.cut => widget.onCut ?? item.onPressed, ContextMenuButtonType.copy => widget.onCopy ?? item.onPressed, @@ -156,6 +332,7 @@ class _BusyMarkEditorTextContextMenuState ); } } + if (widget.onPaste != null) addBusyMarkPasteItems(); final refineWithAi = widget.onRefineWithAi; if (refineWithAi != null && hasSelection) { items.add( @@ -191,6 +368,31 @@ class _BusyMarkEditorTextContextMenuState items.addAll(widget.additionalItems); return items; } + + PopupMenuEntry _spellingMenuEntry( + BusyMarkEditorSpellingMenuItem item, + ) { + if (item.divider) { + return const PopupMenuDivider(height: BusyMarkSpacing.sm); + } + if (item.children.isNotEmpty) { + return BusyMarkSubmenuItem( + label: item.label, + enabled: item.enabled, + items: [for (final child in item.children) _spellingMenuEntry(child)], + ); + } + return BusyMarkPopupMenuItem( + value: item.onSelected ?? _noOp, + label: item.label, + enabled: item.enabled, + checked: item.checked, + trailingCheck: item.mutuallyExclusive, + mutuallyExclusive: item.mutuallyExclusive, + ); + } + + static void _noOp() {} } IconData? _iconFor(ContextMenuButtonType type) { diff --git a/lib/src/editor/inline_semantics.dart b/lib/src/editor/inline_semantics.dart new file mode 100644 index 00000000..4d471afb --- /dev/null +++ b/lib/src/editor/inline_semantics.dart @@ -0,0 +1,54 @@ +import '../markdown/busymark_document.dart'; + +/// Whether two inline wrappers carry the same semantic context independently +/// of their child content. +bool busyMarkSameInlineSemantics(BusyInline left, BusyInline right) => + left.kind == right.kind && + left.destination == right.destination && + left.attributes.length == right.attributes.length && + left.attributes.entries.every( + (entry) => right.attributes[entry.key] == entry.value, + ); + +bool busyMarkIsInheritedInlineContext(BusyInlineKind kind) => + kind == BusyInlineKind.strong || + kind == BusyInlineKind.emphasis || + kind == BusyInlineKind.underline || + kind == BusyInlineKind.strikethrough || + kind == BusyInlineKind.link; + +/// Markdown table cells occupy one physical source line. Normalize every +/// platform newline form at the semantic boundary shared by Editor and Source. +String busyMarkNormalizeTableCellText(String text) { + return text.replaceAll(RegExp(r'\r\n|\r|\n'), ' '); +} + +/// Flattens clipboard blocks into the one inline stream accepted by a table +/// cell while retaining supported inline styles. +List busyMarkTableCellInlinesFromBlocks( + Iterable blocks, +) { + BusyInline normalize(BusyInline inline) => + inline.kind == BusyInlineKind.hardBreak || + inline.kind == BusyInlineKind.softBreak + ? const BusyInline(kind: BusyInlineKind.text, text: ' ') + : inline.copyWith( + text: busyMarkNormalizeTableCellText(inline.text), + children: [for (final child in inline.children) normalize(child)], + ); + final inlines = []; + void append(BusyBlock block) { + if (inlines.isNotEmpty) { + inlines.add(const BusyInline(kind: BusyInlineKind.text, text: ' ')); + } + inlines.addAll(block.inlines.map(normalize)); + for (final child in block.children) { + append(child); + } + } + + for (final block in blocks) { + append(block); + } + return inlines; +} diff --git a/lib/src/editor/source/source_editor.dart b/lib/src/editor/source/source_editor.dart index d6266e6a..3f9742f0 100644 --- a/lib/src/editor/source/source_editor.dart +++ b/lib/src/editor/source/source_editor.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:math' as math; -import 'package:flutter/foundation.dart' show setEquals; +import 'package:flutter/foundation.dart' show setEquals, visibleForTesting; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -17,12 +17,19 @@ import '../../app/busymark_toast.dart'; import '../../app/command_registry.dart'; import '../../app/localization.dart'; import '../../assets/asset_ingestion_service.dart'; +import '../../assets/asset_input_service.dart'; import '../../clipboard/clipboard_insertion.dart'; import '../../clipboard/clipboard_models.dart'; import '../../core/diagnostic.dart'; +import '../../markdown/markdown_model.dart'; import '../../platform/rich_clipboard_service.dart'; import '../../search/search_replace_service.dart'; +import '../../spellcheck/spelling_coordinator.dart'; +import '../../spellcheck/spelling_projection.dart'; +import '../../spellcheck/spelling_replacement.dart'; import '../document_text_geometry.dart'; +import '../clipboard_paste_resolver.dart'; +import '../clipboard_local_image_path.dart'; import '../editor_text_context_menu.dart'; import '../wysiwyg/wysiwyg_clipboard_fragment.dart'; import '../source_folding.dart'; @@ -33,8 +40,12 @@ import 'source_diagnostics.dart'; import 'source_document.dart'; import 'source_gutter.dart'; import 'source_intrinsic_width.dart'; +import 'source_paste_engine.dart'; import 'source_search.dart'; +export 'source_paste_engine.dart' + show SourceDocumentFormat, debugBusyMarkSourceInlineMappingParseCount; + typedef BusyMarkSourceChanged = void Function(String fullText, String? sourceFilePath); @@ -96,7 +107,13 @@ class BusyMarkSourceEditor extends StatefulWidget { this.imagesDir = 'images', this.assetWorkspaceKind, this.assetIngestionService = const AssetIngestionService(), + this.assetInputService, + this.documentFormat, + this.markdownMode, this.onAssetSaveRequired, + this.spellingAnnotations = const [], + this.onCheckSpelling, + this.readSpellingMenuItems, }); final String text; @@ -134,7 +151,13 @@ class BusyMarkSourceEditor extends StatefulWidget { final String imagesDir; final AssetWorkspaceKind? assetWorkspaceKind; final AssetIngestionService assetIngestionService; + final AssetInputService? assetInputService; + final SourceDocumentFormat? documentFormat; + final MarkdownMode? markdownMode; final VoidCallback? onAssetSaveRequired; + final List spellingAnnotations; + final VoidCallback? onCheckSpelling; + final BusyMarkEditorSpellingMenuReader? readSpellingMenuItems; @override State createState() => BusyMarkSourceEditorState(); @@ -157,6 +180,7 @@ class BusyMarkSourceEditorState extends State { final _intrinsicWidthCache = SourceIntrinsicWidthCache(); final _lineLayoutCache = SourceLineLayoutCache(); final _autocompleteProvider = const SourceAutocompleteProvider(); + final _pasteEngine = const SourcePasteEngine(); List _foldRegions = const []; List _autocompleteSuggestions = const []; var _autocompleteSelection = 0; @@ -175,6 +199,128 @@ class BusyMarkSourceEditorState extends State { RichClipboardService get _clipboard => widget.clipboardService ?? busyMarkRichClipboardService; + int get spellingCaretOffset => _controller.fullSelection.extentOffset + .clamp(0, _controller.fullText.length) + .toInt(); + + void restoreSpellingFocus() => _focusNode.requestFocus(); + + void revealSpellingOccurrence(SpellingOccurrence occurrence) { + if (occurrence.run.snapshot.bufferId != + (widget.documentId ?? widget.filePath) || + occurrence.run.snapshot.contentRevision != widget.editRevision || + occurrence.run.target is! SpellingSourceTarget) { + return; + } + final start = occurrence.sourceStart; + final end = occurrence.sourceEnd; + if (start == null || end == null || end > _controller.fullText.length) { + return; + } + _unfoldSourceRange(start, end); + _focusNode.requestFocus(); + scrollToOffset(start, updateSelection: false); + _controller.fullSelection = TextSelection( + baseOffset: start, + extentOffset: end, + ); + } + + bool applySpellingCorrection({ + required SpellingOccurrence occurrence, + required String suggestion, + }) { + final before = spellingSourceSnapshot(occurrence); + if (before == null) return false; + late final SpellingReplacementPlan plan; + late final String after; + try { + plan = const SpellingReplacementPlanner().build( + occurrence: occurrence, + suggestion: suggestion, + ); + after = plan.applyToSource(before); + } on Object { + return false; + } + return applyPreparedSpellingCorrection( + occurrence: occurrence, + plan: plan, + expectedSource: before, + replacementSource: after, + ); + } + + String? spellingSourceSnapshot(SpellingOccurrence occurrence) { + final snapshot = occurrence.run.snapshot; + final target = occurrence.run.target; + if (snapshot.bufferId != (widget.documentId ?? widget.filePath) || + snapshot.contentRevision != widget.editRevision || + target is! SpellingSourceTarget || + target.filePath != (widget.filePath ?? widget.documentId) || + occurrence.word != + occurrence.run.text.substring( + occurrence.logicalStart, + occurrence.logicalEnd, + )) { + return null; + } + final before = _controller.fullText; + for (final atom in occurrence.atoms) { + if (atom.sourceStart < 0 || + atom.sourceEnd > before.length || + atom.sourceEnd < atom.sourceStart) { + return null; + } + } + return before; + } + + bool applyPreparedSpellingCorrection({ + required SpellingOccurrence occurrence, + required SpellingReplacementPlan plan, + required String expectedSource, + required String replacementSource, + }) { + final snapshot = occurrence.run.snapshot; + // Final guard and mutation are synchronous; no operation is awaited here. + if (snapshot.bufferId != (widget.documentId ?? widget.filePath) || + snapshot.contentRevision != widget.editRevision || + expectedSource != _controller.fullText) { + return false; + } + if (replacementSource == expectedSource || plan.sourceEdits.isEmpty) { + return false; + } + final start = plan.sourceEdits.map((edit) => edit.start).reduce(math.min); + final selectionOffset = plan.resultingSourceCaret ?? start; + _unfoldSourceRange( + start, + plan.sourceEdits.map((edit) => edit.end).reduce(math.max), + ); + _applyFullEditingValue( + TextEditingValue( + text: replacementSource, + selection: TextSelection.collapsed( + offset: selectionOffset.clamp(0, replacementSource.length), + ), + ), + origin: _SourceEditOrigin.spellingCorrection, + ); + return true; + } + + SourceDocumentFormat get _documentFormat => + widget.documentFormat ?? + switch (widget.language) { + SourceSyntaxLanguage.markdown => SourceDocumentFormat.markdown, + SourceSyntaxLanguage.xml => SourceDocumentFormat.genericXml, + SourceSyntaxLanguage.plain => SourceDocumentFormat.plainText, + }; + + MarkdownMode get _destinationMarkdownMode => + widget.markdownMode ?? MarkdownMode.commonMark; + @override void initState() { super.initState(); @@ -320,14 +466,16 @@ class BusyMarkSourceEditorState extends State { } /// Reveals a full-document offset, including a destination inside a fold. - void scrollToOffset(int offset) { + void scrollToOffset(int offset, {bool updateSelection = true}) { final textOffset = offset.clamp(0, _controller.fullText.length); final line = '\n'.allMatches(_controller.fullText.substring(0, textOffset)).length + 1; _unfoldSourceLine(line); _focusNode.requestFocus(); - _controller.fullSelection = TextSelection.collapsed(offset: textOffset); + if (updateSelection) { + _controller.fullSelection = TextSelection.collapsed(offset: textOffset); + } WidgetsBinding.instance.addPostFrameCallback((_) { _animateScrollToLine(line); WidgetsBinding.instance.addPostFrameCallback((_) { @@ -496,12 +644,20 @@ class BusyMarkSourceEditorState extends State { unawaited(_copyOrCutSource(cut: true)); return KeyEventResult.handled; } + if (commands.shortcutAccepts( + BusyMarkCommandIds.textPastePlainText, + event, + keyboard, + )) { + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)); + return KeyEventResult.handled; + } if (commands.shortcutAccepts( BusyMarkCommandIds.textPaste, event, keyboard, )) { - unawaited(_pasteFromSystemClipboard()); + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)); return KeyEventResult.handled; } if (commands.shortcutAccepts( @@ -605,6 +761,7 @@ class BusyMarkSourceEditorState extends State { collapsedRegionKeys: _foldedRegionKeys, foldRegions: _foldRegions, diagnosticMarkers: markers, + spellingAnnotations: widget.spellingAnnotations, layoutCache: _lineLayoutCache, intrinsicWidthCache: _intrinsicWidthCache, onToggleFold: _toggleFold, @@ -627,7 +784,9 @@ class BusyMarkSourceEditorState extends State { BusyMarkContextCommandAction( isCommandEnabled: (commandId) => !_hasActiveComposition && - (commandId.startsWith('editor.') || + (commandId == + BusyMarkCommandIds.checkSpelling || + commandId.startsWith('editor.') || (widget.filePath?.toLowerCase().endsWith( '.tree', ) == @@ -640,8 +799,14 @@ class BusyMarkSourceEditorState extends State { BusyMarkCommandIds.textCopy, BusyMarkCommandIds.textCut, BusyMarkCommandIds.textPaste, + BusyMarkCommandIds.textPastePlainText, }.contains(commandId)), onCommand: (commandId) { + if (commandId == + BusyMarkCommandIds.checkSpelling) { + widget.onCheckSpelling?.call(); + return; + } if (commandId == BusyMarkCommandIds.treeMoveLineUp || commandId == @@ -662,7 +827,20 @@ class BusyMarkSourceEditorState extends State { return; } if (commandId == BusyMarkCommandIds.textPaste) { - unawaited(_pasteFromSystemClipboard()); + unawaited( + _pasteFromSystemClipboard( + BusyMarkPasteMode.normal, + ), + ); + return; + } + if (commandId == + BusyMarkCommandIds.textPastePlainText) { + unawaited( + _pasteFromSystemClipboard( + BusyMarkPasteMode.plainText, + ), + ); return; } final name = commandId.substring( @@ -732,6 +910,17 @@ class BusyMarkSourceEditorState extends State { context, editableTextState, refineWithAiLabel: context.l10n.aiRefineWithAi, + readSpellingItems: + widget.readSpellingMenuItems == null + ? null + : (visibleOffset) => + widget.readSpellingMenuItems!( + _controller + .visibleOffsetToFullOffset( + visibleOffset, + ), + ), + onCheckSpelling: widget.onCheckSpelling, additionalItems: [ if (widget.onSymbolAction != null) for (final action @@ -767,8 +956,18 @@ class BusyMarkSourceEditorState extends State { unawaited(_copyOrCutSource(cut: false)), onCut: () => unawaited(_copyOrCutSource(cut: true)), - onPaste: () => - unawaited(_pasteFromSystemClipboard()), + onPaste: () => unawaited( + _pasteFromSystemClipboard( + BusyMarkPasteMode.normal, + ), + ), + onPastePlainText: () => unawaited( + _pasteFromSystemClipboard( + BusyMarkPasteMode.plainText, + ), + ), + readPasteAvailability: + _readContextMenuPasteAvailability, ), onChanged: (_) => _handleSourceChanged(), ), @@ -1285,7 +1484,9 @@ class BusyMarkSourceEditorState extends State { }); } - void _handleSourceChanged() { + void _handleSourceChanged({ + _SourceEditOrigin origin = _SourceEditOrigin.userTyping, + }) { _replacementWorker.cancel(); // Sidebar offsets belong to the pre-edit document. Once the user edits, // resume normal search on the new text instead of awaiting the old range. @@ -1295,11 +1496,19 @@ class BusyMarkSourceEditorState extends State { final selection = _controller.fullSelection; final previousSelection = _controller.lastFullSelectionBeforeEdit ?? selection; - final undoGroup = _undoGroupForSourceEdit( - visibleEdit, - previousSelection: previousSelection, - selection: selection, - ); + final undoGroup = + origin == _SourceEditOrigin.paste || + origin == _SourceEditOrigin.spellingCorrection + ? null + : _undoGroupForSourceEdit( + visibleEdit, + previousSelection: previousSelection, + selection: selection, + ); + if (origin == _SourceEditOrigin.paste || + origin == _SourceEditOrigin.spellingCorrection) { + _continuousSourceEdit = null; + } final currentSearchIndex = _searchController.result.currentMatchIndex; final firstMatchIndex = _searchController.result.firstMatchIndex; _scheduleFoldRefresh(); @@ -1524,10 +1733,13 @@ class BusyMarkSourceEditorState extends State { composing.end <= value.text.length; } - void _applyFullEditingValue(TextEditingValue value) { + void _applyFullEditingValue( + TextEditingValue value, { + _SourceEditOrigin origin = _SourceEditOrigin.userTyping, + }) { _controller.setFullEditingValue(value); _focusNode.requestFocus(); - _handleSourceChanged(); + _handleSourceChanged(origin: origin); } void _applyOwnedUndoValue(TextEditingValue value) { @@ -1744,8 +1956,11 @@ class BusyMarkSourceEditorState extends State { documentId: widget.documentId ?? widget.filePath ?? '', filePath: widget.filePath, language: widget.language, + format: _documentFormat, + markdownMode: _destinationMarkdownMode, text: _controller.fullText, selection: _controller.fullSelection, + composing: _controller.fullComposing, ); bool _isClipboardTargetCurrent(_SourceClipboardOperationTarget target) => @@ -1753,8 +1968,22 @@ class BusyMarkSourceEditorState extends State { target.documentId == (widget.documentId ?? widget.filePath ?? '') && target.filePath == widget.filePath && target.language == widget.language && + target.format == _documentFormat && + target.markdownMode == _destinationMarkdownMode && target.text == _controller.fullText && - target.selection == _controller.fullSelection; + target.selection == _controller.fullSelection && + target.composing == _controller.fullComposing && + !_hasActiveComposition; + + SourcePasteDocumentSnapshot _sourcePasteSnapshot( + _SourceClipboardOperationTarget target, + ) => SourcePasteDocumentSnapshot( + expectedSource: target.text, + selection: target.selection, + format: target.format, + markdownMode: target.markdownMode, + filePath: target.filePath, + ); Future _copyOrCutSource({required bool cut}) async { if (_hasActiveComposition) return false; @@ -1799,109 +2028,356 @@ class BusyMarkSourceEditorState extends State { return true; } - Future _pasteFromSystemClipboard() async { + Future _pasteFromSystemClipboard( + BusyMarkPasteMode mode, + ) async { if (_hasActiveComposition) return ClipboardPasteResult.staleTarget; + final onCaptured = widget.onClipboardCaptured; final target = _captureClipboardTarget(); final data = await _clipboard.read(); if (!_isClipboardTargetCurrent(target)) { return ClipboardPasteResult.staleTarget; } - final text = data.sourceText ?? data.text; - if (text == null) return ClipboardPasteResult.unsupported; - final result = _insertClipboardText(target, text); - if (result == ClipboardPasteResult.inserted && !data.sessionOwned) { - widget.onClipboardCaptured?.call( - BusyMarkClipboardCapture( - kind: data.richFragment == null - ? BusyMarkClipboardContentKind.text - : BusyMarkClipboardContentKind.richText, - text: data.text, - sourceText: text, - html: data.html, - richFragment: data.richFragment, - origin: _clipboardOrigin, - external: true, - ), + final snapshot = BusyMarkClipboardSnapshot.fromSystem(data); + final outcome = await _pasteClipboardSnapshot( + snapshot, + mode: mode, + target: target, + systemIdentity: data, + ); + if (outcome.result == ClipboardPasteResult.inserted && snapshot.external) { + onCaptured?.call( + outcome.capture ?? busyMarkClipboardCaptureFromSnapshot(snapshot), ); } - return result; + return outcome.result; + } + + Future + _readContextMenuPasteAvailability() async { + if (_hasActiveComposition) { + return BusyMarkEditorTextPasteAvailability.unavailable; + } + final target = _captureClipboardTarget(); + final first = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target)) { + return BusyMarkEditorTextPasteAvailability.unavailable; + } + final snapshot = BusyMarkClipboardSnapshot.fromSystem(first); + final destination = switch (target.format) { + SourceDocumentFormat.markdown => BusyMarkPasteDestination.markdownSource, + SourceDocumentFormat.writersideXmlTopic => + BusyMarkPasteDestination.writersideXmlSource, + SourceDocumentFormat.genericXml => + BusyMarkPasteDestination.genericXmlSource, + SourceDocumentFormat.plainText => BusyMarkPasteDestination.plainSource, + }; + const resolver = BusyMarkClipboardPasteResolver(); + final plainText = resolver + .resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.plainText, + destination: destination, + markdownMode: target.markdownMode, + ) + .candidates + .isNotEmpty; + final normalPlan = resolver.resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.normal, + destination: destination, + markdownMode: target.markdownMode, + ); + var normal = false; + var inspectNativeImage = false; + candidates: + for (final candidate in normalPlan.candidates) { + if (candidate is BusyMarkStructuredPasteCandidate) { + final preparation = _pasteEngine.prepareStructured( + target: _sourcePasteSnapshot(target), + fragment: candidate.fragment, + ); + if (preparation is SourcePasteStop) break candidates; + if (preparation is SourcePasteTryNext) continue; + if (!_structuredMediaCanBePrepared(snapshot, candidate.fragment)) { + continue; + } + normal = true; + break candidates; + } + if (candidate is BusyMarkImagePasteCandidate) { + normal = widget.assetIngestionService.canIngestMediaBytes( + bytes: candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + ); + if (normal) break candidates; + continue; + } + if (candidate is BusyMarkNativeImagePasteCandidate) { + inspectNativeImage = true; + break candidates; + } + normal = true; + break candidates; + } + if (!normal && inspectNativeImage) { + final input = widget.assetInputService ?? busyMarkAssetInputService; + final files = await input.readClipboardImageFiles(); + Uint8List? png; + if (files.isEmpty) png = await input.readClipboardImagePng(); + final second = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target)) { + return BusyMarkEditorTextPasteAvailability.unavailable; + } + normal = + first.sameExternalIdentity(second) && + (files.isNotEmpty || (png != null && png.isNotEmpty)); + } + return BusyMarkEditorTextPasteAvailability( + normal: normal, + plainText: plainText, + ); + } + + bool _structuredMediaCanBePrepared( + BusyMarkClipboardSnapshot snapshot, + WysiwygClipboardFragment fragment, + ) { + if (fragment.mediaPaths.isEmpty) return true; + return snapshot.mediaComplete && + fragment.mediaPaths.entries.every((entry) { + final bytes = snapshot.mediaBytes[entry.key]; + return bytes != null && + widget.assetIngestionService.canIngestMediaBytes( + bytes: bytes, + suggestedFileName: p.basename(entry.value), + ); + }); } Future _pasteHistoryPayload( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }) async { if (_hasActiveComposition) { - return ClipboardPasteResult.unsupported; + return ClipboardPasteResult.staleTarget; } + final onCaptured = widget.onClipboardCaptured; final target = _captureClipboardTarget(); - if (payload.kind == BusyMarkClipboardContentKind.image) { - if (plainText) { - final text = payload.text; - return text == null - ? ClipboardPasteResult.unsupported - : _insertClipboardText(target, text); - } - return _pasteHistoryImage(payload, target); + final outcome = await _pasteClipboardSnapshot( + BusyMarkClipboardSnapshot.fromPayload(payload), + mode: mode, + target: target, + ); + if (outcome.result == ClipboardPasteResult.inserted && payload.external) { + onCaptured?.call( + outcome.capture ?? + busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromPayload(payload), + ), + ); + } + return outcome.result; + } + + Future<({ClipboardPasteResult result, BusyMarkClipboardCapture? capture})> + _pasteClipboardSnapshot( + BusyMarkClipboardSnapshot snapshot, { + required BusyMarkPasteMode mode, + required _SourceClipboardOperationTarget target, + RichClipboardData? systemIdentity, + }) async { + final destination = switch (target.format) { + SourceDocumentFormat.markdown => BusyMarkPasteDestination.markdownSource, + SourceDocumentFormat.writersideXmlTopic => + BusyMarkPasteDestination.writersideXmlSource, + SourceDocumentFormat.genericXml => + BusyMarkPasteDestination.genericXmlSource, + SourceDocumentFormat.plainText => BusyMarkPasteDestination.plainSource, + }; + final plan = const BusyMarkClipboardPasteResolver().resolve( + snapshot: snapshot, + mode: mode, + destination: destination, + markdownMode: target.markdownMode, + ); + if (plan.isEmpty) { + return (result: ClipboardPasteResult.unsupported, capture: null); } - if (!plainText && payload.richFragment != null) { - final decoded = WysiwygClipboardFragment.decode(payload.richFragment!); - if (decoded != null) { - var fragment = decoded.rebase(widget.filePath ?? ''); + for (final candidate in plan.candidates) { + if (!_isClipboardTargetCurrent(target)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + if (candidate is BusyMarkStructuredPasteCandidate) { + final decoded = candidate.fragment; + var fragment = decoded.rebase(target.filePath ?? ''); var assets = const []; if (decoded.mediaPaths.isNotEmpty) { - if (!payload.mediaComplete) return ClipboardPasteResult.unsupported; + if (!snapshot.mediaComplete) continue; final prepared = await _prepareRetainedClipboardMedia( decoded, - payload, + snapshot, target, ); if (prepared == null) { - return _isClipboardTargetCurrent(target) - ? ClipboardPasteResult.unsupported - : ClipboardPasteResult.staleTarget; + if (!_isClipboardTargetCurrent(target)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + continue; } fragment = prepared.fragment; assets = prepared.assets; } - final result = _insertClipboardText(target, fragment.markdown); + final preparation = _pasteEngine.prepareStructured( + target: _sourcePasteSnapshot(target), + fragment: fragment, + ); + if (preparation is SourcePasteTryNext) { + await _deleteUncommittedClipboardAssets(assets); + continue; + } + if (preparation is SourcePasteStop) { + await _deleteUncommittedClipboardAssets(assets); + return (result: ClipboardPasteResult.unsupported, capture: null); + } + final edit = (preparation as SourcePasteReady).edit; + final result = _insertClipboardText( + target, + edit.replacement, + replacementStart: edit.start, + replacementEnd: edit.end, + resultingSelectionOffset: edit.caretOffset, + ); if (result != ClipboardPasteResult.inserted) { await _deleteUncommittedClipboardAssets(assets); } - return result; + if (result == ClipboardPasteResult.inserted) { + await _finalizeInsertedAssets(assets); + return (result: result, capture: null); + } + return (result: result, capture: null); } + if (candidate is BusyMarkImagePasteCandidate) { + final result = await _pasteImageBytes( + candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + target: target, + ); + if (result == ClipboardPasteResult.inserted) { + return (result: result, capture: null); + } + if (result == ClipboardPasteResult.staleTarget) { + return (result: result, capture: null); + } + continue; + } + if (candidate is BusyMarkNativeImagePasteCandidate) { + final native = await _pasteNativeClipboardImage( + target, + systemIdentity!, + ); + return (result: native.result, capture: native.capture); + } + final text = switch (candidate) { + BusyMarkPlainTextPasteCandidate(:final text) => text, + BusyMarkSourceTextPasteCandidate(:final text) => text, + _ => null, + }; + if (text == null) continue; + if (mode == BusyMarkPasteMode.normal && + candidate is BusyMarkPlainTextPasteCandidate && + _formatSupportsImages(target.format)) { + final path = busyMarkLocalImagePathFromClipboardText(text); + if (path != null) { + Uint8List? retainedBytes; + final result = await _pasteImageFile( + path, + target: target, + onInserted: (value) => retainedBytes = value, + ); + if (result == ClipboardPasteResult.inserted) { + return ( + result: result, + capture: retainedBytes == null + ? null + : busyMarkClipboardCaptureFromSnapshot( + snapshot, + imageBytes: retainedBytes, + imageMimeType: _sourceClipboardImageMimeType(path), + imageDisplayName: p.basename(path), + ), + ); + } + if (result == ClipboardPasteResult.staleTarget) { + return (result: result, capture: null); + } + } + } + final result = _insertClipboardText(target, text); + return (result: result, capture: null); } - final text = plainText ? payload.text : payload.preferredSourceText; - if (text == null) return ClipboardPasteResult.unsupported; - return _insertClipboardText(target, text); + return ( + result: _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget, + capture: null, + ); } - Future _pasteHistoryImage( - BusyMarkClipboardPayload payload, - _SourceClipboardOperationTarget target, - ) async { - final bytes = payload.imageBytes; - if (bytes == null || bytes.isEmpty) { - return ClipboardPasteResult.unsupported; - } - if (target.language == SourceSyntaxLanguage.plain) { - return ClipboardPasteResult.unsupported; + bool _formatSupportsImages(SourceDocumentFormat format) => + format == SourceDocumentFormat.markdown || + format == SourceDocumentFormat.writersideXmlTopic; + + Future _pasteImageFile( + String sourcePath, { + required _SourceClipboardOperationTarget target, + ValueChanged? onInserted, + }) async { + try { + final snapshot = await widget.assetIngestionService.ingestFileSnapshot( + sourcePath: sourcePath, + request: _assetIngestionRequest, + origin: AssetIngestionOrigin.clipboardImageFile, + ); + final result = await _insertIngestedImage(snapshot.asset, target); + if (result == ClipboardPasteResult.inserted) { + onInserted?.call(snapshot.bytes); + } + return result; + } on AssetSaveRequiredException { + widget.onAssetSaveRequired?.call(); + return _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget; + } on AssetIngestionException { + return _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget; + } on FileSystemException { + return _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget; } - final alt = context.l10n.image; - late final IngestedAsset asset; + } + + Future _pasteImageBytes( + Uint8List bytes, { + required String suggestedFileName, + required _SourceClipboardOperationTarget target, + }) async { try { - asset = await widget.assetIngestionService.ingestBytes( + final asset = await widget.assetIngestionService.ingestBytes( bytes: bytes, - suggestedFileName: payload.imageDisplayName ?? 'clipboard-image.png', + suggestedFileName: suggestedFileName, request: _assetIngestionRequest, origin: AssetIngestionOrigin.screenshotPaste, ); + return await _insertIngestedImage(asset, target); } on AssetSaveRequiredException { - if (!_isClipboardTargetCurrent(target)) { - return ClipboardPasteResult.staleTarget; - } widget.onAssetSaveRequired?.call(); - return ClipboardPasteResult.unsupported; + return _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget; } on AssetIngestionException { return _isClipboardTargetCurrent(target) ? ClipboardPasteResult.unsupported @@ -1911,40 +2387,107 @@ class BusyMarkSourceEditorState extends State { ? ClipboardPasteResult.unsupported : ClipboardPasteResult.staleTarget; } + } + + Future _insertIngestedImage( + IngestedAsset asset, + _SourceClipboardOperationTarget target, + ) async { if (!_isClipboardTargetCurrent(target)) { await _deleteUncommittedClipboardAssets([asset]); return ClipboardPasteResult.staleTarget; } - final result = _insertClipboardText(target, switch (target.language) { - SourceSyntaxLanguage.markdown => SourceCommands.imageReference( - alt: alt, - sourceReference: asset.markdownPath, - ), - SourceSyntaxLanguage.xml => SourceCommands.writersideImageReference( - alt: alt, + final reference = switch (target.format) { + SourceDocumentFormat.markdown => SourceCommands.imageReference( + alt: context.l10n.image, sourceReference: asset.markdownPath, ), - SourceSyntaxLanguage.plain => throw StateError( - 'Plain source cannot contain an image reference.', - ), - }); + SourceDocumentFormat.writersideXmlTopic => + SourceCommands.writersideImageReference( + alt: context.l10n.image, + sourceReference: asset.markdownPath, + ), + SourceDocumentFormat.genericXml || SourceDocumentFormat.plainText => null, + }; + if (reference == null) { + await _deleteUncommittedClipboardAssets([asset]); + return ClipboardPasteResult.unsupported; + } + final result = _insertClipboardText(target, reference); if (result != ClipboardPasteResult.inserted) { await _deleteUncommittedClipboardAssets([asset]); + } else { + await _finalizeInsertedAssets([asset]); } return result; } + Future<({ClipboardPasteResult result, BusyMarkClipboardCapture? capture})> + _pasteNativeClipboardImage( + _SourceClipboardOperationTarget target, + RichClipboardData first, + ) async { + final input = widget.assetInputService ?? busyMarkAssetInputService; + final files = await input.readClipboardImageFiles(); + Uint8List? png; + if (files.isEmpty) png = await input.readClipboardImagePng(); + final second = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target) || + !first.sameExternalIdentity(second)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + if (files.isNotEmpty) { + Uint8List? bytes; + final result = await _pasteImageFile( + files.first, + target: target, + onInserted: (value) => bytes = value, + ); + return ( + result: result, + capture: result == ClipboardPasteResult.inserted && bytes != null + ? busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromSystem(first), + imageBytes: bytes, + imageMimeType: _sourceClipboardImageMimeType(files.first), + imageDisplayName: p.basename(files.first), + ) + : null, + ); + } + if (png == null || png.isEmpty) { + return (result: ClipboardPasteResult.unsupported, capture: null); + } + final name = 'screenshot-${DateTime.now().millisecondsSinceEpoch}.png'; + final result = await _pasteImageBytes( + png, + suggestedFileName: name, + target: target, + ); + return ( + result: result, + capture: result == ClipboardPasteResult.inserted + ? busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromSystem(first), + imageBytes: png, + imageMimeType: 'image/png', + imageDisplayName: name, + ) + : null, + ); + } + Future<({WysiwygClipboardFragment fragment, List assets})?> _prepareRetainedClipboardMedia( WysiwygClipboardFragment fragment, - BusyMarkClipboardPayload payload, + BusyMarkClipboardSnapshot snapshot, _SourceClipboardOperationTarget target, ) async { final destinations = {}; final assets = []; try { for (final entry in fragment.mediaPaths.entries) { - final bytes = payload.mediaBytes[entry.key]; + final bytes = snapshot.mediaBytes[entry.key]; if (bytes == null || bytes.isEmpty) { await _deleteUncommittedClipboardAssets(assets); return null; @@ -1999,33 +2542,53 @@ class BusyMarkSourceEditorState extends State { Future _deleteUncommittedClipboardAssets( Iterable assets, ) async { - for (final asset in assets) { - if (asset.reusedExisting) continue; - try { - await File(asset.absolutePath).delete(); - } on FileSystemException { - // Failed cancellation cleanup must not make the editor unusable. - } + await widget.assetIngestionService.rollbackAll(assets); + } + + Future _finalizeInsertedAssets(Iterable assets) async { + try { + await widget.assetIngestionService.commitAll(assets); + } on Object catch (error) { + // Insertion already succeeded. A stale pending record safely protects + // the referenced file; rolling it back would corrupt document content. + if (!mounted) return; + BusyMarkToastOverlay.show( + context, + message: error is AssetIngestionException + ? error.message + : context.l10n.clipboardUnavailable, + priority: BusyMarkToastPriority.high, + ); } } ClipboardPasteResult _insertClipboardText( _SourceClipboardOperationTarget target, - String text, - ) { + String text, { + int? replacementStart, + int? replacementEnd, + int? resultingSelectionOffset, + }) { if (!_isClipboardTargetCurrent(target)) { return ClipboardPasteResult.staleTarget; } final selection = target.selection.isValid ? target.selection : TextSelection.collapsed(offset: target.text.length); - final start = selection.start.clamp(0, target.text.length).toInt(); - final end = selection.end.clamp(start, target.text.length).toInt(); + final start = (replacementStart ?? selection.start) + .clamp(0, target.text.length) + .toInt(); + final end = (replacementEnd ?? selection.end) + .clamp(start, target.text.length) + .toInt(); _applyFullEditingValue( TextEditingValue( text: target.text.replaceRange(start, end, text), - selection: TextSelection.collapsed(offset: start + text.length), + selection: TextSelection.collapsed( + offset: resultingSelectionOffset ?? start + text.length, + ), ), + origin: _SourceEditOrigin.paste, ); return ClipboardPasteResult.inserted; } @@ -2204,6 +2767,7 @@ class _SourceEditorFrame extends StatelessWidget { required this.foldRegions, required this.collapsedRegionKeys, required this.diagnosticMarkers, + required this.spellingAnnotations, required this.layoutCache, required this.intrinsicWidthCache, required this.onToggleFold, @@ -2228,6 +2792,7 @@ class _SourceEditorFrame extends StatelessWidget { final List foldRegions; final Set collapsedRegionKeys; final List diagnosticMarkers; + final List spellingAnnotations; final SourceLineLayoutCache layoutCache; final SourceIntrinsicWidthCache intrinsicWidthCache; final ValueChanged onToggleFold; @@ -2355,6 +2920,7 @@ class _SourceEditorFrame extends StatelessWidget { textStyle: textStyle, strutStyle: strutStyle, textWidth: textWidth, + spellingAnnotations: spellingAnnotations, ), ), if (collapsedRegionKeys.isNotEmpty) @@ -2369,6 +2935,7 @@ class _SourceEditorFrame extends StatelessWidget { foldRegions: foldRegions, collapsedRegionKeys: collapsedRegionKeys, diagnosticMarkers: diagnosticMarkers, + spellingAnnotations: spellingAnnotations, layoutCache: layoutCache, ), ), @@ -2412,13 +2979,14 @@ RenderEditable? _findSourceRenderEditable(RenderObject root) { return result; } -class _SourceRenderedTextLayer extends StatelessWidget { +class _SourceRenderedTextLayer extends StatefulWidget { const _SourceRenderedTextLayer({ required this.controller, required this.scrollController, required this.textStyle, required this.strutStyle, required this.textWidth, + required this.spellingAnnotations, }); final BusyMarkSourceEditingController controller; @@ -2426,17 +2994,27 @@ class _SourceRenderedTextLayer extends StatelessWidget { final TextStyle textStyle; final StrutStyle? strutStyle; final double textWidth; + final List spellingAnnotations; + + @override + State<_SourceRenderedTextLayer> createState() => + _SourceRenderedTextLayerState(); +} + +class _SourceRenderedTextLayerState extends State<_SourceRenderedTextLayer> { + final _paragraphKey = GlobalKey(); @override Widget build(BuildContext context) { final renderedText = RichText( + key: _paragraphKey, textDirection: TextDirection.ltr, - text: controller.buildSourceTextSpan( + text: widget.controller.buildSourceTextSpan( context: context, - style: textStyle, + style: widget.textStyle, hideCollapsedStartLines: true, ), - strutStyle: strutStyle, + strutStyle: widget.strutStyle, textHeightBehavior: sourceTextHeightBehavior, textScaler: MediaQuery.textScalerOf(context), textWidthBasis: TextWidthBasis.parent, @@ -2444,18 +3022,33 @@ class _SourceRenderedTextLayer extends StatelessWidget { return IgnorePointer( child: ClipRect( child: AnimatedBuilder( - animation: scrollController, + animation: Listenable.merge([ + widget.controller, + widget.scrollController, + ]), child: renderedText, builder: (context, child) { - final scrollOffset = safeScrollOffset(scrollController); + final scrollOffset = safeScrollOffset(widget.scrollController); return Stack( clipBehavior: Clip.none, children: [ Positioned( top: _SourceEditorFrame.editorPaddingTop - scrollOffset, left: _SourceEditorFrame.editorPaddingLeft, - width: textWidth, - child: child!, + width: widget.textWidth, + child: CustomPaint( + foregroundPainter: _SourceSpellingPainter( + paragraphKey: _paragraphKey, + controller: widget.controller, + document: widget.controller.document, + annotations: widget.spellingAnnotations, + color: busyMarkStatusColor( + context, + BusyMarkStatusKind.error, + ), + ), + child: child!, + ), ), ], ); @@ -2478,6 +3071,7 @@ class _CollapsedSourceLineOverlay extends StatelessWidget { required this.collapsedRegionKeys, required this.diagnosticMarkers, required this.layoutCache, + required this.spellingAnnotations, }); final BusyMarkSourceEditingController controller; @@ -2490,6 +3084,7 @@ class _CollapsedSourceLineOverlay extends StatelessWidget { final Set collapsedRegionKeys; final List diagnosticMarkers; final SourceLineLayoutCache layoutCache; + final List spellingAnnotations; @override Widget build(BuildContext context) { @@ -2543,6 +3138,9 @@ class _CollapsedSourceLineOverlay extends StatelessWidget { height: layout.height, child: _CollapsedSourceLine( text: _collapsedLineText(fullLine.text), + authoredLength: fullLine.text.trimRight().length, + sourceStart: fullLine.startOffset, + spellingAnnotations: spellingAnnotations, height: lineHeight, textStyle: textStyle, ), @@ -2559,16 +3157,108 @@ class _CollapsedSourceLineOverlay extends StatelessWidget { } } +class _SourceSpellingPainter extends CustomPainter { + const _SourceSpellingPainter({ + required this.paragraphKey, + required this.controller, + required this.document, + required this.annotations, + required this.color, + }) : super(repaint: controller); + + final GlobalKey paragraphKey; + final BusyMarkSourceEditingController controller; + final SourceDocument document; + final List annotations; + final Color color; + + @override + void paint(Canvas canvas, Size size) { + final paragraph = paragraphKey.currentContext?.findRenderObject(); + if (paragraph is! RenderParagraph) return; + final paint = Paint() + ..color = color + ..strokeWidth = BusyMarkStroke.hairline + ..style = PaintingStyle.stroke; + for (final annotation in annotations) { + if (annotation.target is! SpellingSourceTarget || + annotation.end <= annotation.start || + busyMarkSourceSpellingUnderlineSuppressed( + controller, + TextRange(start: annotation.start, end: annotation.end), + )) { + continue; + } + final mapped = document.fullRangeToVisibleRange( + annotation.start, + annotation.end, + ); + if (mapped.clippedByHiddenRange || mapped.range.isCollapsed) continue; + final boxes = paragraph.getBoxesForSelection( + TextSelection( + baseOffset: mapped.range.start, + extentOffset: mapped.range.end, + ), + boxHeightStyle: BusyMarkDocumentTextGeometry.selectionHeightStyle, + boxWidthStyle: BusyMarkDocumentTextGeometry.selectionWidthStyle, + ); + for (final box in boxes) { + _paintSpellingWave(canvas, box.toRect(), paint); + } + } + } + + @override + bool shouldRepaint(covariant _SourceSpellingPainter oldDelegate) => + oldDelegate.document != document || + oldDelegate.annotations != annotations || + oldDelegate.controller != controller || + oldDelegate.color != color; +} + +@visibleForTesting +bool busyMarkSourceSpellingUnderlineSuppressed( + BusyMarkSourceEditingController controller, + TextRange range, +) { + final composing = controller.fullComposing; + return composing.isValid && + !composing.isCollapsed && + range.start < composing.end && + range.end > composing.start; +} + +void _paintSpellingWave(Canvas canvas, Rect rect, Paint paint) { + if (rect.width <= 0) return; + final y = rect.bottom - 1; + const halfWave = 2.0; + final path = Path()..moveTo(rect.left, y); + var x = rect.left; + var up = true; + while (x < rect.right) { + x = math.min(rect.right, x + halfWave); + path.lineTo(x, y + (up ? -1.25 : 1.25)); + up = !up; + } + canvas.drawPath(path, paint); +} + class _CollapsedSourceLine extends StatelessWidget { const _CollapsedSourceLine({ required this.text, required this.height, required this.textStyle, + required this.authoredLength, + required this.sourceStart, + required this.spellingAnnotations, }); final String text; final double height; final TextStyle textStyle; + final int authoredLength; + final int sourceStart; + final List spellingAnnotations; @override Widget build(BuildContext context) { @@ -2590,12 +3280,23 @@ class _CollapsedSourceLine extends StatelessWidget { ), child: Align( alignment: Alignment.centerLeft, - child: Text( - text, - textDirection: TextDirection.ltr, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: textStyle.copyWith(color: colors.mutedForeground), + child: CustomPaint( + foregroundPainter: _CollapsedSpellingPainter( + text: text, + authoredLength: authoredLength, + sourceStart: sourceStart, + annotations: spellingAnnotations, + style: textStyle, + color: busyMarkStatusColor(context, BusyMarkStatusKind.error), + textScaler: MediaQuery.textScalerOf(context), + ), + child: Text( + text, + textDirection: TextDirection.ltr, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: textStyle.copyWith(color: colors.mutedForeground), + ), ), ), ), @@ -2605,6 +3306,69 @@ class _CollapsedSourceLine extends StatelessWidget { } } +class _CollapsedSpellingPainter extends CustomPainter { + const _CollapsedSpellingPainter({ + required this.text, + required this.authoredLength, + required this.sourceStart, + required this.annotations, + required this.style, + required this.color, + required this.textScaler, + }); + + final String text; + final int authoredLength; + final int sourceStart; + final List annotations; + final TextStyle style; + final Color color; + final TextScaler textScaler; + + @override + void paint(Canvas canvas, Size size) { + if (authoredLength <= 0 || size.width <= 0) return; + final painter = TextPainter( + text: TextSpan(text: text, style: style), + textDirection: TextDirection.ltr, + textScaler: textScaler, + maxLines: 1, + ellipsis: '…', + )..layout(maxWidth: size.width); + final wave = Paint() + ..color = color + ..strokeWidth = BusyMarkStroke.hairline + ..style = PaintingStyle.stroke; + for (final annotation in annotations) { + if (annotation.target is! SpellingSourceTarget || + annotation.start < sourceStart || + annotation.end > sourceStart + authoredLength) { + continue; + } + final boxes = painter.getBoxesForSelection( + TextSelection( + baseOffset: annotation.start - sourceStart, + extentOffset: annotation.end - sourceStart, + ), + ); + for (final box in boxes) { + _paintSpellingWave(canvas, box.toRect(), wave); + } + } + painter.dispose(); + } + + @override + bool shouldRepaint(covariant _CollapsedSpellingPainter oldDelegate) => + oldDelegate.text != text || + oldDelegate.authoredLength != authoredLength || + oldDelegate.sourceStart != sourceStart || + oldDelegate.annotations != annotations || + oldDelegate.style != style || + oldDelegate.color != color || + oldDelegate.textScaler != textScaler; +} + class _SourceSearchPanel extends StatefulWidget { const _SourceSearchPanel({ required this.result, @@ -2992,17 +3756,25 @@ class _SourceClipboardOperationTarget { required this.documentId, required this.filePath, required this.language, + required this.format, + required this.markdownMode, required this.text, required this.selection, + required this.composing, }); final String documentId; final String? filePath; final SourceSyntaxLanguage language; + final SourceDocumentFormat format; + final MarkdownMode markdownMode; final String text; final TextSelection selection; + final TextRange composing; } +enum _SourceEditOrigin { userTyping, paste, spellingCorrection } + class _SourceClipboardInsertionTarget implements BusyMarkClipboardInsertionTarget, @@ -3030,42 +3802,78 @@ class _SourceClipboardInsertionTarget bool get editable => state.mounted && !state._hasActiveComposition; @override - bool canPaste(BusyMarkClipboardPayload payload, {required bool plainText}) { + bool canPaste( + BusyMarkClipboardPayload payload, { + required BusyMarkPasteMode mode, + }) { if (!editable) return false; - if (plainText) return payload.hasMeaningfulTextRepresentation; - if (payload.kind == BusyMarkClipboardContentKind.image) { - return state.widget.language != SourceSyntaxLanguage.plain && - payload.imageBytes?.isNotEmpty == true; - } - if (payload.richFragment != null) { - final fragment = WysiwygClipboardFragment.decode(payload.richFragment!); - if (fragment == null) return payload.preferredSourceText != null; - if (fragment.mediaPaths.isNotEmpty) { - return payload.mediaComplete && - fragment.mediaPaths.entries.every((entry) { - final bytes = payload.mediaBytes[entry.key]; - return bytes != null && - state.widget.assetIngestionService.canIngestMediaBytes( - bytes: bytes, - suggestedFileName: p.basename(entry.value), - ); - }); + final snapshot = BusyMarkClipboardSnapshot.fromPayload(payload); + final destination = switch (state._documentFormat) { + SourceDocumentFormat.markdown => BusyMarkPasteDestination.markdownSource, + SourceDocumentFormat.writersideXmlTopic => + BusyMarkPasteDestination.writersideXmlSource, + SourceDocumentFormat.genericXml => + BusyMarkPasteDestination.genericXmlSource, + SourceDocumentFormat.plainText => BusyMarkPasteDestination.plainSource, + }; + final plan = const BusyMarkClipboardPasteResolver().resolve( + snapshot: snapshot, + mode: mode, + destination: destination, + markdownMode: state._destinationMarkdownMode, + ); + final target = state._captureClipboardTarget(); + for (final candidate in plan.candidates) { + if (candidate is BusyMarkStructuredPasteCandidate) { + final preparation = state._pasteEngine.prepareStructured( + target: state._sourcePasteSnapshot(target), + fragment: candidate.fragment, + ); + if (preparation is SourcePasteStop) return false; + if (preparation is SourcePasteTryNext) continue; + if (!state._structuredMediaCanBePrepared( + snapshot, + candidate.fragment, + )) { + continue; + } + return true; + } + if (candidate is BusyMarkImagePasteCandidate) { + if (state.widget.assetIngestionService.canIngestMediaBytes( + bytes: candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + )) { + return true; + } + continue; } + if (candidate is BusyMarkNativeImagePasteCandidate) return false; return true; } - return payload.preferredSourceText != null; + return false; } @override Future paste( BusyMarkClipboardPayload payload, { - required bool plainText, - }) => state._pasteHistoryPayload(payload, plainText: plainText); + required BusyMarkPasteMode mode, + }) => state._pasteHistoryPayload(payload, mode: mode); @override void requestEditorFocus() => state._focusNode.requestFocus(); } +String _sourceClipboardImageMimeType(String path) => + switch (p.extension(path).toLowerCase()) { + '.jpg' || '.jpeg' => 'image/jpeg', + '.gif' => 'image/gif', + '.webp' => 'image/webp', + '.bmp' => 'image/bmp', + '.svg' => 'image/svg+xml', + _ => 'image/png', + }; + class _SourceEditorShortcutIntent extends Intent { const _SourceEditorShortcutIntent(this.action); diff --git a/lib/src/editor/source/source_paste_engine.dart b/lib/src/editor/source/source_paste_engine.dart new file mode 100644 index 00000000..1b4344df --- /dev/null +++ b/lib/src/editor/source/source_paste_engine.dart @@ -0,0 +1,2850 @@ +import 'dart:math' as math; + +import 'package:flutter/foundation.dart' show ValueChanged, visibleForTesting; +import 'package:flutter/services.dart'; + +import '../../markdown/busymark_document.dart'; +import '../../markdown/busymark_markdown_serializer.dart'; +import '../../markdown/markdown_model.dart'; +import '../../markdown/markdown_parser.dart'; +import '../../markdown/markdown_source_map.dart'; +import '../../markdown/markdown_source_structure.dart'; +import '../inline_semantics.dart'; +import '../wysiwyg/wysiwyg_clipboard_fragment.dart'; + +enum SourceDocumentFormat { + markdown, + writersideXmlTopic, + genericXml, + plainText, +} + +@visibleForTesting +ValueChanged? debugBusyMarkSourceInlineMappingParseCount; + +class SourcePasteDocumentSnapshot { + const SourcePasteDocumentSnapshot({ + required this.expectedSource, + required this.selection, + required this.format, + required this.markdownMode, + required this.filePath, + }); + + final String expectedSource; + final TextSelection selection; + final SourceDocumentFormat format; + final MarkdownMode markdownMode; + final String? filePath; + + String get text => expectedSource; +} + +sealed class SourcePastePreparation { + const SourcePastePreparation(); +} + +class SourcePasteReady extends SourcePastePreparation { + const SourcePasteReady(this.edit); + + final SourcePasteEdit edit; +} + +class SourcePasteTryNext extends SourcePastePreparation { + const SourcePasteTryNext(); +} + +class SourcePasteStop extends SourcePastePreparation { + const SourcePasteStop(); +} + +class SourcePasteEdit { + const SourcePasteEdit({ + required this.expectedSource, + required this.start, + required this.end, + required this.replacement, + required this.caretOffset, + }); + + final String expectedSource; + final int start; + final int end; + final String replacement; + final int caretOffset; +} + +class SourcePasteEngine { + const SourcePasteEngine(); + + SourcePastePreparation prepareStructured({ + required SourcePasteDocumentSnapshot target, + required WysiwygClipboardFragment fragment, + }) { + final insertion = _serializeStructuredClipboardInsertion(target, fragment); + if (insertion == null) return const SourcePasteTryNext(); + if (insertion is _SourceTerminalPlan) return const SourcePasteStop(); + final edit = insertion as _SourceEditPlan; + return SourcePasteReady( + SourcePasteEdit( + expectedSource: target.expectedSource, + start: edit.start, + end: edit.end, + replacement: edit.text, + caretOffset: edit.caretOffset ?? edit.start + edit.text.length, + ), + ); + } + + _SourcePlan? _serializeStructuredClipboardInsertion( + SourcePasteDocumentSnapshot target, + WysiwygClipboardFragment fragment, + ) { + final context = _structuredSourceInsertionContext(target); + if (context.sourceProtected || context.unsafeStructuredContainer) { + return null; + } + if (context.tableCell || fragment.isInlineSourceFragment) { + final inlines = fragment.sourceInsertionInlinesFor( + tableCell: context.tableCell, + ); + final hasSharedInheritedContext = + context.inlineContext?.commonAncestors.any( + (inline) => busyMarkIsInheritedInlineContext(inline.kind), + ) ?? + false; + if (context.start != context.end && + (context.tableCell || + context.inlineMappingFailed || + !hasSharedInheritedContext)) { + final planned = _serializeSingleParagraphRangeInsertion( + target, + context, + inlines, + independentRange: context.tableCell, + ); + return planned ?? const _SourceTerminalPlan(); + } + if (context.inlineMappingFailed) { + return _reconcileIncompleteSyntaxBoundary(target, context, inlines); + } + if (inlines.isEmpty) return null; + final serialized = context.inlineContext == null + ? _serializeGeneratedInline( + inlines, + context, + textOffset: inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ).source + : ''; + if (serialized.isEmpty && context.inlineContext == null) return null; + return _reconcileStructuredInlineInsertion( + target, + context, + inlines, + serialized, + ); + } + final blocks = fragment.sourceInsertionBlocks; + final paragraphOnly = + blocks.length > 1 && + blocks.every( + (block) => + block.kind == BusyBlockKind.paragraph && + block.children.isEmpty && + !block.isSourceOnly, + ); + if (paragraphOnly) { + return _serializeParagraphBlockInsertion(target, context, blocks); + } + final serialized = fragment.serializeFor( + destinationMode: target.markdownMode, + destinationFilePath: target.filePath ?? '', + ); + if (serialized.isEmpty) return null; + return _serializeCompleteBlockInsertion(target, context, serialized); + } + + _SourcePlan? _serializeSingleParagraphRangeInsertion( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + List incoming, { + bool independentRange = false, + }) { + final split = _mappedStructuredBlockSplit( + target, + context, + independentRange: independentRange, + ); + if (split == null) return null; + final beforeLength = split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final incomingLength = incoming.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final serialized = _serializeStructuredBlockSide( + [...split.before, ...incoming, ...split.after], + beforeLength + incomingLength, + context, + split, + null, + retainedLineBreaks: _retainedMappedLineBreaks( + context, + split.beforeAuthoredWrapper ?? split.afterAuthoredWrapper, + beforeLength: beforeLength, + incomingLength: incomingLength, + ), + atBlockStart: split.startAtBlockStart, + ); + return _SourceEditPlan( + start: split.sourceRange.start, + end: split.sourceRange.end, + text: serialized.source, + caretOffset: split.sourceRange.start + serialized.sourceOffset, + ); + } + + _SourcePlan _serializeCompleteBlockInsertion( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + String serialized, + ) { + final split = _mappedStructuredBlockSplit(target, context); + if (split == null) return const _SourceTerminalPlan(); + final heading = context.headingSource; + final trailingHeadingSyntax = heading?.trailingSyntaxRange; + final replacementStart = + split.startAtBlockStart && split.startBlockKind == BusyBlockKind.heading + ? heading?.openingAtxMarkerRange?.start ?? split.sourceRange.start + : split.sourceRange.start; + final replacementEnd = math.max( + split.sourceRange.end, + trailingHeadingSyntax?.end ?? split.sourceRange.end, + ); + final retainedHeadingTail = + trailingHeadingSyntax != null && + split.sourceRange.end <= trailingHeadingSyntax.start + ? target.text.substring( + split.sourceRange.end, + trailingHeadingSyntax.start, + ) + : ''; + final beforeInline = _serializeStructuredBlockSide( + split.before, + split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + context, + split, + split.beforeAuthoredWrapper, + retainedLineBreaks: + _retainedMappedLineBreaks( + context, + split.beforeAuthoredWrapper ?? split.afterAuthoredWrapper, + beforeLength: split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + incomingLength: 0, + ).where( + (lineBreak) => + lineBreak.textOffset < + split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ), + atBlockStart: context.atBlockStart, + ); + final afterInline = _serializeStructuredBlockSide( + split.after, + 0, + context, + split, + split.afterAuthoredWrapper, + retainedLineBreaks: [ + for (final lineBreak in _retainedMappedLineBreaks( + context, + split.beforeAuthoredWrapper ?? split.afterAuthoredWrapper, + beforeLength: split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + incomingLength: 0, + )) + if (lineBreak.textOffset >= + split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + )) + BusyMarkMappedSourceLineBreak( + textOffset: + lineBreak.textOffset - + split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + lineEnding: lineBreak.lineEnding, + continuationPrefix: lineBreak.continuationPrefix, + sourceOffset: lineBreak.sourceOffset, + ), + ], + atBlockStart: true, + preferInsideOpeningBoundary: true, + ); + final survivingSetextSyntax = + context.hasContainerContentBefore && + heading?.setextUnderlineRange != null + ? target.text.substring( + heading!.setextUnderlineRange!.start, + heading.setextUnderlineRange!.end, + ) + : ''; + final beforeSource = '${beforeInline.source}$survivingSetextSyntax'; + final afterSource = '${afterInline.source}$retainedHeadingTail'; + final before = target.text.substring(0, replacementStart); + final after = target.text.substring(replacementEnd); + if (context.containerContinuationPrefix.isNotEmpty) { + final lines = serialized.endsWith('\n') + ? serialized.substring(0, serialized.length - 1).split('\n') + : serialized.split('\n'); + final nested = [ + for (var index = 0; index < lines.length; index++) + if (!context.hasContainerContentBefore && + !context.taskItemAtContentStart && + index == 0) + lines[index] + else if (lines[index].isEmpty) + context.containerBlankPrefix + else + '${context.containerContinuationPrefix}${lines[index]}', + ].join(context.lineEnding); + final beforeBoundary = + context.hasContainerContentBefore || context.taskItemAtContentStart + ? '${context.lineEnding}${context.containerBlankPrefix}' + '${context.lineEnding}' + : ''; + final afterBoundary = context.hasContainerContentAfter + ? '${context.lineEnding}${context.containerBlankPrefix}' + '${context.lineEnding}${context.containerContinuationPrefix}' + : ''; + final contentBefore = split.expanded + ? target.text.substring(0, split.sourceRange.start) + beforeSource + : before; + final contentAfter = split.expanded || retainedHeadingTail.isNotEmpty + ? afterSource + target.text.substring(replacementEnd) + : after; + final localBeforeBoundary = contentBefore.isNotEmpty + ? beforeBoundary + : ''; + final localAfterBoundary = contentAfter.isNotEmpty ? afterBoundary : ''; + final afterStart = + beforeSource.length + + localBeforeBoundary.length + + nested.length + + localAfterBoundary.length; + return _SourceEditPlan( + start: replacementStart, + end: replacementEnd, + text: + '$beforeSource$localBeforeBoundary$nested' + '$localAfterBoundary$afterSource', + caretOffset: replacementStart + afterStart + afterInline.sourceOffset, + ); + } + final generated = _restoreGeneratedLineEndings( + serialized, + context.lineEnding, + ); + final leadingBreaks = _leadingLineBreaks(generated); + final trailingBreaks = _trailingLineBreaks(generated); + final expandedBefore = split.expanded + ? target.text.substring(0, split.sourceRange.start) + beforeSource + : before; + final expandedAfter = split.expanded || retainedHeadingTail.isNotEmpty + ? afterSource + target.text.substring(replacementEnd) + : after; + final prefix = expandedBefore.isEmpty + ? '' + : _repeatLineEnding( + context.lineEnding, + math.max( + 0, + 2 - _trailingLineBreaks(expandedBefore) - leadingBreaks, + ), + ); + final suffix = expandedAfter.isEmpty + ? '' + : _repeatLineEnding( + context.lineEnding, + math.max(0, 2 - trailingBreaks - _leadingLineBreaks(expandedAfter)), + ); + final afterStart = + beforeSource.length + prefix.length + generated.length + suffix.length; + return _SourceEditPlan( + start: replacementStart, + end: replacementEnd, + text: '$beforeSource$prefix$generated$suffix$afterSource', + caretOffset: replacementStart + afterStart + afterInline.sourceOffset, + ); + } + + _SourcePlan _serializeParagraphBlockInsertion( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + List blocks, + ) { + final split = _mappedStructuredBlockSplit(target, context); + if (split == null) return const _SourceTerminalPlan(); + final heading = context.headingSource; + final trailingHeadingSyntax = heading?.trailingSyntaxRange; + final replacementEnd = math.max( + split.sourceRange.end, + trailingHeadingSyntax?.end ?? split.sourceRange.end, + ); + final retainedHeadingTail = + trailingHeadingSyntax != null && + split.sourceRange.end <= trailingHeadingSyntax.start + ? target.text.substring( + split.sourceRange.end, + trailingHeadingSyntax.start, + ) + : ''; + final firstInlines = [...split.before, ...blocks.first.inlines]; + final lastInlines = [...blocks.last.inlines, ...split.after]; + final beforeLength = split.before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final firstIncomingLength = blocks.first.inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final retainedLineBreaks = _retainedMappedLineBreaks( + context, + split.beforeAuthoredWrapper ?? split.afterAuthoredWrapper, + beforeLength: beforeLength, + incomingLength: firstIncomingLength, + ); + final first = _serializeStructuredBlockSide( + firstInlines, + firstInlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + context, + split, + split.beforeAuthoredWrapper, + retainedLineBreaks: retainedLineBreaks.where( + (lineBreak) => + lineBreak.textOffset < + firstInlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ), + atBlockStart: split.startAtBlockStart, + ); + final lastCaretOffset = blocks.last.inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final last = _serializeStructuredBlockSide( + lastInlines, + lastCaretOffset, + context, + split, + split.afterAuthoredWrapper, + retainedLineBreaks: [ + for (final lineBreak in retainedLineBreaks) + if (lineBreak.textOffset >= beforeLength + firstIncomingLength) + BusyMarkMappedSourceLineBreak( + textOffset: + blocks.last.inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ) + + lineBreak.textOffset - + beforeLength - + firstIncomingLength, + lineEnding: lineBreak.lineEnding, + continuationPrefix: lineBreak.continuationPrefix, + sourceOffset: lineBreak.sourceOffset, + ), + ], + atBlockStart: true, + ); + final separator = context.containerContinuationPrefix.isEmpty + ? '${context.lineEnding}${context.lineEnding}' + : '${context.lineEnding}${context.containerBlankPrefix}' + '${context.lineEnding}${context.containerContinuationPrefix}'; + final middle = [ + for (final block in blocks.skip(1).take(blocks.length - 2)) + _serializeGeneratedInline( + block.inlines, + context, + atBlockStart: true, + textOffset: block.inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ).source, + ]; + final survivingSetextSyntax = + context.hasContainerContentBefore && + heading?.setextUnderlineRange != null + ? target.text.substring( + heading!.setextUnderlineRange!.start, + heading.setextUnderlineRange!.end, + ) + : ''; + final prefix = [ + '${first.source}$survivingSetextSyntax', + ...middle, + ].join(separator); + final replacement = '$prefix$separator${last.source}$retainedHeadingTail'; + final replacementStart = + split.startAtBlockStart && + split.startBlockKind == BusyBlockKind.heading && + blocks.first.kind == BusyBlockKind.paragraph + ? heading?.openingAtxMarkerRange?.start ?? split.sourceRange.start + : split.sourceRange.start; + return _SourceEditPlan( + start: replacementStart, + end: replacementEnd, + text: replacement, + caretOffset: + replacementStart + + prefix.length + + separator.length + + last.sourceOffset, + ); + } + + _StructuredBlockInlineSplit? _mappedStructuredBlockSplit( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, { + bool independentRange = false, + }) { + if (context.completeBlockSelection) { + return _StructuredBlockInlineSplit( + sourceRange: TextRange(start: context.start, end: context.end), + before: const [], + after: const [], + annotations: _SourceInlineOccurrenceAnnotations(), + startBlockKind: context.destinationBlockKind, + startBlockSourceStart: context.destinationBlockSourceStart, + startBlockStructuralPrefixStart: + context.destinationBlockStructuralPrefixStart, + startAtBlockStart: context.atBlockStart, + ); + } + if (context.start != context.end) { + if (!independentRange && !context.inlineMappingFailed) { + final shared = _mappedSharedStructuredBlockSplit(context); + if (shared != null) return shared; + } + return _mappedIndependentStructuredBlockSplit(target, context); + } + return _mappedCollapsedStructuredBlockSplit(context); + } + + _StructuredBlockInlineSplit? _mappedSharedStructuredBlockSplit( + _StructuredSourceInsertionContext context, + ) { + final destination = context.inlineContext; + final outermost = destination?.commonAncestors + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .firstOrNull; + if (destination == null || outermost == null) return null; + final mapped = destination.wrapperFor(outermost); + if (mapped == null || mapped.isAutolink) return null; + final annotations = _SourceInlineOccurrenceAnnotations(); + final partition = _partitionMappedInline( + mapped.inline, + destination.startMarker, + destination.endMarker, + rawHtmlSourceInlines: _rawHtmlSourceInlines(destination), + annotations: annotations, + ); + if (partition == null) return null; + return _StructuredBlockInlineSplit( + sourceRange: mapped.sourceRange, + before: partition.before, + after: partition.after, + annotations: annotations, + beforeAuthoredWrapper: mapped, + afterAuthoredWrapper: mapped, + expanded: true, + startBlockKind: context.destinationBlockKind, + startBlockSourceStart: context.destinationBlockSourceStart, + startBlockStructuralPrefixStart: + context.destinationBlockStructuralPrefixStart, + startAtBlockStart: context.atBlockStart, + ); + } + + _StructuredBlockInlineSplit? _mappedCollapsedStructuredBlockSplit( + _StructuredSourceInsertionContext context, { + _SourceInlineOccurrenceAnnotations? sharedAnnotations, + }) { + if (context.inlineMappingFailed) return null; + final annotations = + sharedAnnotations ?? _SourceInlineOccurrenceAnnotations(); + final destination = context.inlineContext; + final outermost = destination?.commonAncestors + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .firstOrNull; + if (destination == null || outermost == null) { + return _StructuredBlockInlineSplit( + sourceRange: TextRange(start: context.start, end: context.end), + before: const [], + after: const [], + annotations: annotations, + startBlockKind: context.destinationBlockKind, + startBlockSourceStart: context.destinationBlockSourceStart, + startBlockStructuralPrefixStart: + context.destinationBlockStructuralPrefixStart, + startAtBlockStart: context.atBlockStart, + ); + } + final mapped = destination.wrapperFor(outermost); + if (mapped == null || mapped.isAutolink) return null; + final partition = _partitionMappedInline( + mapped.inline, + destination.startMarker, + null, + rawHtmlSourceInlines: _rawHtmlSourceInlines(destination), + annotations: annotations, + ); + if (partition == null) return null; + return _StructuredBlockInlineSplit( + sourceRange: mapped.sourceRange, + before: partition.before, + after: partition.after, + annotations: annotations, + beforeAuthoredWrapper: mapped, + afterAuthoredWrapper: mapped, + expanded: true, + startBlockKind: context.destinationBlockKind, + startBlockSourceStart: context.destinationBlockSourceStart, + startBlockStructuralPrefixStart: + context.destinationBlockStructuralPrefixStart, + startAtBlockStart: context.atBlockStart, + ); + } + + _StructuredBlockInlineSplit? _mappedIndependentStructuredBlockSplit( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + ) { + final startContext = _structuredSourceInsertionContext( + SourcePasteDocumentSnapshot( + expectedSource: target.expectedSource, + selection: TextSelection.collapsed(offset: context.start), + format: target.format, + markdownMode: target.markdownMode, + filePath: target.filePath, + ), + ); + final endContext = _structuredSourceInsertionContext( + SourcePasteDocumentSnapshot( + expectedSource: target.expectedSource, + selection: TextSelection.collapsed(offset: context.end), + format: target.format, + markdownMode: target.markdownMode, + filePath: target.filePath, + ), + ); + if (startContext.sourceProtected || + endContext.sourceProtected || + startContext.unsafeStructuredContainer || + endContext.unsafeStructuredContainer) { + return null; + } + final annotations = _SourceInlineOccurrenceAnnotations(); + final start = _mappedCollapsedStructuredBlockSplit( + startContext, + sharedAnnotations: annotations, + ); + final end = _mappedCollapsedStructuredBlockSplit( + endContext, + sharedAnnotations: annotations, + ); + if (start == null || + end == null || + start.sourceRange.start > end.sourceRange.end) { + return null; + } + return _StructuredBlockInlineSplit( + sourceRange: TextRange( + start: math.min(start.sourceRange.start, end.sourceRange.start), + end: math.max(start.sourceRange.end, end.sourceRange.end), + ), + before: start.before, + after: end.after, + annotations: annotations, + beforeAuthoredWrapper: start.beforeAuthoredWrapper, + afterAuthoredWrapper: end.afterAuthoredWrapper, + expanded: start.expanded || end.expanded, + startBlockKind: startContext.destinationBlockKind, + startBlockSourceStart: startContext.destinationBlockSourceStart, + startBlockStructuralPrefixStart: + startContext.destinationBlockStructuralPrefixStart, + startAtBlockStart: startContext.atBlockStart, + ); + } + + BusyMarkSerializedInlineFragment _serializeStructuredBlockSide( + List inlines, + int caretTextOffset, + _StructuredSourceInsertionContext context, + _StructuredBlockInlineSplit split, + _MappedSourceInlineWrapper? authoredWrapper, { + required bool atBlockStart, + bool preferInsideOpeningBoundary = false, + Iterable retainedLineBreaks = const [], + }) { + final prepared = _stabilizeMappedWrapperWhitespace( + _mergeAdjacentSourceInlineStyles(inlines, split.annotations), + split.annotations, + ); + final lineBreakOffsets = { + for (final lineBreak in retainedLineBreaks) + lineBreak: BusyMarkInlineLineBreakOffset( + textOffset: lineBreak.textOffset, + ), + }; + final rawSerialized = _serializeMappedInlineSequence( + prepared, + caretTextOffset, + context, + authoredWrapper, + atBlockStart: atBlockStart, + lineBreakOffsets: lineBreakOffsets.values, + ); + final serialized = _restoreMappedSourceLineBreaks( + rawSerialized, + [ + for (final entry in lineBreakOffsets.entries) + if (rawSerialized.lineBreakSourceOffsets[entry.value] + case final offset?) + _SerializedMappedSourceLineBreak( + sourceOffset: offset, + lineBreak: entry.key, + ), + ], + context.containerContinuationPrefix, + context.lineEnding, + ); + if (!preferInsideOpeningBoundary || prepared.isEmpty) return serialized; + final markedInlines = [...prepared]; + markedInlines[0] = _prependSourceCaretMarker( + markedInlines.first, + context.marker, + ); + final markedLineBreakOffsets = { + for (final lineBreak in retainedLineBreaks) + lineBreak: BusyMarkInlineLineBreakOffset( + textOffset: lineBreak.textOffset + context.marker.length, + ), + }; + final rawMarked = _serializeMappedInlineSequence( + markedInlines, + context.marker.length, + context, + authoredWrapper, + atBlockStart: atBlockStart, + lineBreakOffsets: markedLineBreakOffsets.values, + ); + final marked = _restoreMappedSourceLineBreaks( + rawMarked, + [ + for (final entry in markedLineBreakOffsets.entries) + if (rawMarked.lineBreakSourceOffsets[entry.value] case final offset?) + _SerializedMappedSourceLineBreak( + sourceOffset: offset, + lineBreak: entry.key, + ), + ], + context.containerContinuationPrefix, + context.lineEnding, + ); + final markerOffset = marked.source.indexOf(context.marker); + if (markerOffset >= 0 && + marked.source.replaceRange( + markerOffset, + markerOffset + context.marker.length, + '', + ) == + serialized.source) { + return BusyMarkSerializedInlineFragment( + source: serialized.source, + sourceOffset: markerOffset, + ); + } + return serialized; + } + + BusyInline _prependSourceCaretMarker(BusyInline inline, String marker) { + if (inline.children.isEmpty) { + return inline.copyWith(text: '$marker${inline.text}'); + } + final children = [...inline.children]; + children[0] = _prependSourceCaretMarker(children.first, marker); + return inline.copyWith( + text: '$marker${inline.plainText}', + children: children, + ); + } + + _SourceEditPlan? _reconcileIncompleteSyntaxBoundary( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + List incoming, + ) { + final destination = context.inlineContext; + final singleIncoming = incoming.length == 1 ? incoming.single : null; + if (destination == null || + context.start != context.end || + singleIncoming == null) { + return null; + } + final adjacent = _adjacentEquivalentInlineRuns( + target.text, + context.start, + singleIncoming, + destination, + ); + if (adjacent == null) return null; + final innerSource = _serializeSourceInlineSequence( + _removeEquivalentInlineContexts(incoming, [singleIncoming]), + context, + ); + return _SourceEditPlan( + start: adjacent.leftClosingRange.start, + end: adjacent.rightOpeningRange.end, + text: innerSource, + caretOffset: adjacent.leftClosingRange.start + innerSource.length, + ); + } + + _SourcePlan _reconcileStructuredInlineInsertion( + SourcePasteDocumentSnapshot target, + _StructuredSourceInsertionContext context, + List incoming, + String serialized, + ) { + final destination = context.inlineContext; + if (destination != null) { + final activeContexts = destination.commonAncestors + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .toList(growable: false); + final destinationLinkIndex = activeContexts.indexWhere( + (inline) => inline.kind == BusyInlineKind.link, + ); + if (destinationLinkIndex >= 0 && + (destination + .wrapperFor(activeContexts[destinationLinkIndex]) + ?.isAutolink == + true || + destination + .wrapperFor(activeContexts[destinationLinkIndex]) + ?.isReference == + true || + _containsDifferentLink( + incoming, + activeContexts[destinationLinkIndex], + ))) { + final expanded = _replaceMappedDestinationLink( + context, + destination, + incoming, + activeContexts[destinationLinkIndex], + ); + return expanded ?? const _SourceTerminalPlan(); + } + if (context.tableCell && + activeContexts.isNotEmpty && + !_allInlinesCarryContexts(incoming, activeContexts)) { + final expanded = _replaceMappedInlineContext( + context, + destination, + incoming, + ); + if (expanded != null) return expanded; + } + final reconciled = _removeEquivalentInlineContexts( + incoming, + activeContexts, + ); + final reconciledSource = _serializeSourceInlineSequence( + reconciled, + context, + ); + final singleIncoming = incoming.length == 1 ? incoming.single : null; + final adjacent = context.start == context.end && singleIncoming != null + ? _adjacentEquivalentInlineRuns( + target.text, + context.start, + singleIncoming, + destination, + ) + : null; + // Joining three semantically adjacent equivalent runs is local and + // retains the authored delimiter choice on the destination runs. + if (adjacent != null) { + final innerSource = _serializeSourceInlineSequence( + _removeEquivalentInlineContexts(incoming, [singleIncoming!]), + context, + ); + return _SourceEditPlan( + start: adjacent.leftClosingRange.start, + end: adjacent.rightOpeningRange.end, + text: innerSource, + caretOffset: adjacent.leftClosingRange.start + innerSource.length, + ); + } + return _SourceEditPlan( + start: context.start, + end: context.end, + text: reconciledSource, + caretOffset: context.start + reconciledSource.length, + ); + } + return _SourceEditPlan( + start: context.start, + end: context.end, + text: serialized, + caretOffset: context.start + serialized.length, + ); + } + + String _serializeSourceInlineSequence( + List inlines, + _StructuredSourceInsertionContext context, + ) => _serializeGeneratedInline( + inlines, + context, + textOffset: inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ).source; + + bool _containsDifferentLink( + List inlines, + BusyInline destination, + ) { + for (final inline in inlines) { + if (inline.kind == BusyInlineKind.link && + !busyMarkSameInlineSemantics(inline, destination)) { + return true; + } + if (_containsDifferentLink(inline.children, destination)) return true; + } + return false; + } + + bool _containsSourceInlineKind( + List inlines, + BusyInlineKind kind, + ) { + for (final inline in inlines) { + if (inline.kind == kind || + _containsSourceInlineKind(inline.children, kind)) { + return true; + } + } + return false; + } + + bool _allInlinesCarryContexts( + List inlines, + List contexts, + ) { + var sawContent = false; + var covered = true; + void visit(BusyInline inline, List inherited) { + final active = busyMarkIsInheritedInlineContext(inline.kind) + ? [...inherited, inline] + : inherited; + if (inline.children.isEmpty) { + if (inline.plainText.isEmpty) return; + sawContent = true; + if (!contexts.every( + (context) => active.any( + (candidate) => busyMarkSameInlineSemantics(candidate, context), + ), + )) { + covered = false; + } + return; + } + for (final child in inline.children) { + visit(child, active); + } + } + + for (final inline in inlines) { + visit(inline, const []); + } + return sawContent && covered; + } + + List _removeEquivalentInlineContexts( + List inlines, + List contexts, [ + _SourceInlineOccurrenceAnnotations? annotations, + ]) { + List transform(BusyInline inline) { + final children = inline.children.isEmpty + ? [ + if (inline.text.isNotEmpty) + BusyInline(kind: BusyInlineKind.text, text: inline.text), + ] + : [for (final child in inline.children) ...transform(child)]; + if (busyMarkIsInheritedInlineContext(inline.kind) && + contexts.any( + (context) => busyMarkSameInlineSemantics(context, inline), + )) { + return children; + } + final rebuilt = inline.copyWith( + text: children.isEmpty + ? inline.text + : children.map((child) => child.plainText).join(), + children: inline.children.isEmpty ? inline.children : children, + ); + return [annotations?.copyAnnotation(inline, rebuilt) ?? rebuilt]; + } + + return [for (final inline in inlines) ...transform(inline)]; + } + + List _applySourceInlineContexts( + List inlines, + List contexts, + Set rawHtmlSourceInlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + var result = inlines; + for (final wrapper in contexts.reversed) { + if (wrapper.kind == BusyInlineKind.link && + _containsSourceInlineKind(result, BusyInlineKind.link)) { + continue; + } + if (result.length == 1 && + busyMarkSameInlineSemantics(wrapper, result.single)) { + continue; + } + if (wrapper.kind == BusyInlineKind.underline && + _containsSourceInlineKind(result, BusyInlineKind.link)) { + BusyInline applyInsideLinks(BusyInline inline) { + if (inline.kind == BusyInlineKind.link) { + final wrapped = annotations.copyAnnotation( + wrapper, + wrapper.copyWith( + text: inline.plainText, + children: inline.children, + ), + rawHtml: rawHtmlSourceInlines.contains(wrapper), + ); + return annotations.copyAnnotation( + inline, + inline.copyWith(children: [wrapped]), + ); + } + if (inline.children.isNotEmpty) { + return annotations.copyAnnotation( + inline, + inline.copyWith( + children: [ + for (final child in inline.children) applyInsideLinks(child), + ], + ), + ); + } + return annotations.copyAnnotation( + wrapper, + wrapper.copyWith(text: inline.plainText, children: [inline]), + rawHtml: rawHtmlSourceInlines.contains(wrapper), + ); + } + + result = [for (final inline in result) applyInsideLinks(inline)]; + continue; + } + result = [ + annotations.copyAnnotation( + wrapper, + wrapper.copyWith( + text: result.map((inline) => inline.plainText).join(), + children: result, + ), + rawHtml: rawHtmlSourceInlines.contains(wrapper), + ), + ]; + } + return result; + } + + _SourceEditPlan? _replaceMappedInlineContext( + _StructuredSourceInsertionContext context, + _MappedSourceInlineContext destination, + List incoming, + ) { + final outermost = destination.commonAncestors + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .firstOrNull; + if (outermost == null) return null; + final mapped = destination.wrapperFor(outermost); + if (mapped == null) return null; + final annotations = _SourceInlineOccurrenceAnnotations(); + final partition = _partitionMappedInline( + mapped.inline, + destination.startMarker, + destination.endMarker, + rawHtmlSourceInlines: _rawHtmlSourceInlines(destination), + annotations: annotations, + ); + if (partition == null) return null; + return _serializeMappedInlineReplacement( + context, + mapped.sourceRange, + partition.before, + incoming, + partition.after, + authoredWrapper: mapped, + annotations: annotations, + ); + } + + _SourceEditPlan? _replaceMappedDestinationLink( + _StructuredSourceInsertionContext context, + _MappedSourceInlineContext destination, + List incoming, + BusyInline destinationLink, + ) { + final mapped = destination.wrapperFor(destinationLink); + if (mapped == null) return null; + final rawHtmlSourceInlines = _rawHtmlSourceInlines(destination); + final annotations = _SourceInlineOccurrenceAnnotations(); + final partition = _partitionMappedInline( + mapped.inline, + destination.startMarker, + destination.endMarker, + rawHtmlSourceInlines: rawHtmlSourceInlines, + annotations: annotations, + ); + if (partition == null) return null; + final linkIndex = destination.commonAncestors.indexWhere( + (inline) => identical(inline, destinationLink), + ); + if (linkIndex < 0) return null; + final outerContexts = destination.commonAncestors + .take(linkIndex) + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .toList(growable: false); + final innerContexts = destination.commonAncestors + .skip(linkIndex + 1) + .where((inline) => busyMarkIsInheritedInlineContext(inline.kind)) + .toList(growable: false); + final adjustedIncoming = _removeEquivalentInlineContexts( + _applySourceInlineContexts( + incoming, + innerContexts, + rawHtmlSourceInlines, + annotations, + ), + outerContexts, + annotations, + ); + return _serializeMappedInlineReplacement( + context, + mapped.sourceRange, + partition.before, + adjustedIncoming, + partition.after, + authoredWrapper: mapped, + annotations: annotations, + ); + } + + Set _rawHtmlSourceInlines( + _MappedSourceInlineContext destination, + ) { + final result = Set.identity(); + for (final wrapper in destination.wrappers) { + if (wrapper.opening?.trimLeft().startsWith('<') ?? false) { + result.add(wrapper.inline); + } + } + return result; + } + + _SourceEditPlan _serializeMappedInlineReplacement( + _StructuredSourceInsertionContext context, + TextRange sourceRange, + List before, + List incoming, + List after, { + _MappedSourceInlineWrapper? authoredWrapper, + required _SourceInlineOccurrenceAnnotations annotations, + }) { + final caretTextOffset = [ + ...before, + ...incoming, + ].fold(0, (length, inline) => length + inline.plainText.length); + final retainedLineBreaks = _retainedMappedLineBreaks( + context, + authoredWrapper, + beforeLength: before.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + incomingLength: incoming.fold( + 0, + (length, inline) => length + inline.plainText.length, + ), + ); + final merged = _stabilizeMappedWrapperWhitespace( + _mergeAdjacentSourceInlineStyles([ + ...before, + ...incoming, + ...after, + ], annotations), + annotations, + ); + final lineBreakOffsets = { + for (final lineBreak in retainedLineBreaks) + lineBreak: BusyMarkInlineLineBreakOffset( + textOffset: lineBreak.textOffset, + ), + }; + final serialized = _serializeMappedInlineSequence( + merged, + caretTextOffset, + context, + authoredWrapper, + lineBreakOffsets: lineBreakOffsets.values, + ); + final serializedLineBreaks = [ + for (final entry in lineBreakOffsets.entries) + if (serialized.lineBreakSourceOffsets[entry.value] case final offset?) + _SerializedMappedSourceLineBreak( + sourceOffset: offset, + lineBreak: entry.key, + ), + ]; + final restored = _restoreMappedSourceLineBreaks( + serialized, + serializedLineBreaks, + context.containerContinuationPrefix, + context.lineEnding, + ); + return _SourceEditPlan( + start: sourceRange.start, + end: sourceRange.end, + text: restored.source, + caretOffset: sourceRange.start + restored.sourceOffset, + ); + } + + List _retainedMappedLineBreaks( + _StructuredSourceInsertionContext context, + _MappedSourceInlineWrapper? authoredWrapper, { + required int beforeLength, + required int incomingLength, + }) { + final mappedText = authoredWrapper?.inline.plainText; + final inlineContext = context.inlineContext; + if (authoredWrapper == null || + mappedText == null || + inlineContext == null) { + return const []; + } + final markerStart = mappedText.indexOf(inlineContext.startMarker); + if (markerStart < 0) return const []; + final markerEnd = inlineContext.endMarker == null + ? markerStart + inlineContext.startMarker.length + : mappedText.indexOf( + inlineContext.endMarker!, + markerStart + inlineContext.startMarker.length, + ) + + inlineContext.endMarker!.length; + if (markerEnd < markerStart) return const []; + return List.unmodifiable([ + for (final lineBreak in authoredWrapper.lineBreaks) + if (lineBreak.textOffset < markerStart) + lineBreak + else if (lineBreak.textOffset >= markerEnd) + BusyMarkMappedSourceLineBreak( + textOffset: + beforeLength + + incomingLength + + lineBreak.textOffset - + markerEnd, + lineEnding: lineBreak.lineEnding, + continuationPrefix: lineBreak.continuationPrefix, + sourceOffset: lineBreak.sourceOffset, + ), + ]); + } + + BusyMarkSerializedInlineFragment _restoreMappedSourceLineBreaks( + BusyMarkSerializedInlineFragment serialized, + List<_SerializedMappedSourceLineBreak> lineBreaks, + String fallbackPrefix, + String fallbackLineEnding, + ) { + if (!serialized.source.contains('\n')) return serialized; + final source = StringBuffer(); + var sourceOffset = serialized.sourceOffset; + final lineBreaksByOffset = { + for (final lineBreak in lineBreaks) lineBreak.sourceOffset: lineBreak, + }; + for (var index = 0; index < serialized.source.length; index++) { + final character = serialized.source[index]; + if (character != '\n') { + source.write(character); + continue; + } + final mapped = lineBreaksByOffset[index]?.lineBreak; + final lineEnding = mapped?.lineEnding ?? fallbackLineEnding; + final prefix = mapped?.continuationPrefix ?? fallbackPrefix; + source.write(lineEnding); + source.write(prefix); + if (index < serialized.sourceOffset) { + sourceOffset += lineEnding.length - 1 + prefix.length; + } + } + return BusyMarkSerializedInlineFragment( + source: source.toString(), + sourceOffset: sourceOffset, + ); + } + + BusyMarkSerializedInlineFragment _serializeMappedInlineSequence( + List inlines, + int caretTextOffset, + _StructuredSourceInsertionContext context, + _MappedSourceInlineWrapper? authoredWrapper, { + Iterable lineBreakOffsets = const [], + bool? atBlockStart, + }) { + final opening = authoredWrapper?.opening; + final closing = authoredWrapper?.closing; + return const BusyMarkMarkdownSerializer() + .serializeInlineFragmentWithOffsets( + inlines, + textOffset: caretTextOffset, + lineBreakOffsets: lineBreakOffsets, + tableCell: context.tableCell, + atBlockStart: atBlockStart ?? context.atBlockStart, + readableHardBreakRuns: !context.tableCell, + delimiterOverrides: opening == null || closing == null + ? const {} + : { + authoredWrapper!.inline.kind: BusyMarkInlineDelimiter( + opening: opening, + closing: closing, + ), + }, + ); + } + + BusyMarkSerializedInlineFragment _serializeGeneratedInline( + List inlines, + _StructuredSourceInsertionContext context, { + required int textOffset, + bool? atBlockStart, + }) { + final serialized = const BusyMarkMarkdownSerializer() + .serializeInlineFragmentWithOffsets( + inlines, + textOffset: textOffset, + tableCell: context.tableCell, + atBlockStart: atBlockStart ?? context.atBlockStart, + readableHardBreakRuns: !context.tableCell, + ); + return _restoreMappedSourceLineBreaks( + serialized, + const [], + context.containerContinuationPrefix, + context.lineEnding, + ); + } + + List _mergeAdjacentSourceInlineStyles( + List inlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + final merged = []; + for (final sourceInline in inlines) { + final inline = sourceInline.children.isEmpty + ? sourceInline + : annotations.copyAnnotation( + sourceInline, + sourceInline.copyWith( + children: _mergeAdjacentSourceInlineStyles( + sourceInline.children, + annotations, + ), + ), + ); + final previous = merged.lastOrNull; + if (previous == null || + !busyMarkSameInlineSemantics(previous, inline) || + (inline.kind != BusyInlineKind.text && + (!busyMarkIsInheritedInlineContext(inline.kind) || + previous.children.isEmpty || + inline.children.isEmpty))) { + merged.add(inline); + continue; + } + merged.removeLast(); + if (inline.kind == BusyInlineKind.text) { + merged.add( + annotations.copyAnnotations([ + previous, + inline, + ], previous.copyWith(text: previous.text + inline.text)), + ); + } else { + final children = _mergeAdjacentSourceInlineStyles([ + ...previous.children, + ...inline.children, + ], annotations); + merged.add( + annotations.copyAnnotations( + [previous, inline], + previous.copyWith( + text: children.map((child) => child.plainText).join(), + children: children, + ), + ), + ); + } + } + return merged; + } + + /// Raw-HTML conversion can trim whitespace at a styled element or link edge. + /// When mapped paste splits such a wrapper at that edge, hoist the whitespace + /// outside the affected delimiter so its text semantics survive the + /// serializer/reparse round trip. + List _stabilizeMappedWrapperWhitespace( + List inlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + final result = []; + for (final inline in inlines) { + if (inline.children.isEmpty) { + result.add(inline); + continue; + } + final containsRawHtmlWrapper = _containsMappedRawHtmlInline( + inline.children, + annotations, + ); + final children = _stabilizeMappedWrapperWhitespace( + inline.children, + annotations, + ); + final rebuilt = annotations.copyAnnotation( + inline, + inline.copyWith( + text: children.map((child) => child.plainText).join(), + children: children, + ), + ); + final rawHtmlStyle = annotations.isRawHtml(inline); + final containingInheritedContext = + busyMarkIsInheritedInlineContext(inline.kind) && + containsRawHtmlWrapper; + if (!rawHtmlStyle && !containingInheritedContext) { + result.add(rebuilt); + continue; + } + + final leading = children.firstOrNull?.kind == BusyInlineKind.text + ? RegExp(r'^\s+').firstMatch(children.first.text)?.group(0) ?? '' + : ''; + final core = [...children]; + if (leading.isNotEmpty) { + final first = core.first; + core[0] = first.copyWith(text: first.text.substring(leading.length)); + } + final trailing = core.lastOrNull?.kind == BusyInlineKind.text + ? RegExp(r'\s+$').firstMatch(core.last.text)?.group(0) ?? '' + : ''; + if (leading.isEmpty && trailing.isEmpty) { + result.add(rebuilt); + continue; + } + if (trailing.isNotEmpty) { + final last = core.last; + core[core.length - 1] = last.copyWith( + text: last.text.substring(0, last.text.length - trailing.length), + ); + } + core.removeWhere( + (child) => child.kind == BusyInlineKind.text && child.plainText.isEmpty, + ); + if (leading.isNotEmpty) { + result.add(BusyInline(kind: BusyInlineKind.text, text: leading)); + } + if (core.isNotEmpty) { + result.add( + rebuilt.copyWith( + text: core.map((child) => child.plainText).join(), + children: core, + ), + ); + } + if (trailing.isNotEmpty) { + result.add(BusyInline(kind: BusyInlineKind.text, text: trailing)); + } + } + return result; + } + + bool _containsMappedRawHtmlInline( + List inlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + for (final inline in inlines) { + if (annotations.isRawHtml(inline) || + _containsMappedRawHtmlInline(inline.children, annotations)) { + return true; + } + } + return false; + } + + ({List before, List after})? _partitionMappedInline( + BusyInline inline, + String startMarker, + String? endMarker, { + required Set rawHtmlSourceInlines, + required _SourceInlineOccurrenceAnnotations annotations, + }) { + final text = inline.plainText; + final start = text.indexOf(startMarker); + if (start < 0) return null; + final end = endMarker == null + ? start + startMarker.length + : text.indexOf(endMarker, start + startMarker.length) + + endMarker.length; + if (end < start + startMarker.length) return null; + final partition = _partitionSourceInline( + inline, + start, + end, + rawHtmlSourceInlines, + annotations, + ); + return ( + before: [if (partition.before case final before?) before], + after: [if (partition.after case final after?) after], + ); + } + + ({List before, List after}) _partitionSourceInlines( + List inlines, + int start, + int end, + Set rawHtmlSourceInlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + final before = []; + final after = []; + var offset = 0; + for (final inline in inlines) { + final length = inline.plainText.length; + final inlineEnd = offset + length; + if (inlineEnd <= start) { + before.add(inline); + } else if (offset >= end) { + after.add(inline); + } else { + final partition = _partitionSourceInline( + inline, + (start - offset).clamp(0, length).toInt(), + (end - offset).clamp(0, length).toInt(), + rawHtmlSourceInlines, + annotations, + ); + if (partition.before != null) before.add(partition.before!); + if (partition.after != null) after.add(partition.after!); + } + offset = inlineEnd; + } + return (before: before, after: after); + } + + ({BusyInline? before, BusyInline? after}) _partitionSourceInline( + BusyInline inline, + int start, + int end, + Set rawHtmlSourceInlines, + _SourceInlineOccurrenceAnnotations annotations, + ) { + final length = inline.plainText.length; + if (inline.children.isNotEmpty) { + final partition = _partitionSourceInlines( + inline.children, + start, + end, + rawHtmlSourceInlines, + annotations, + ); + final before = partition.before.isEmpty + ? null + : inline.copyWith( + text: partition.before.map((child) => child.plainText).join(), + children: partition.before, + ); + final after = partition.after.isEmpty + ? null + : inline.copyWith( + text: partition.after.map((child) => child.plainText).join(), + children: partition.after, + ); + if (rawHtmlSourceInlines.contains(inline)) { + if (before != null) annotations.markRawHtml(before); + if (after != null) annotations.markRawHtml(after); + } + return (before: before, after: after); + } + return ( + before: start == 0 + ? null + : inline.copyWith(text: inline.text.substring(0, start)), + after: end == length + ? null + : inline.copyWith(text: inline.text.substring(end)), + ); + } + + _MappedAdjacentInlineRuns? _adjacentEquivalentInlineRuns( + String source, + int offset, + BusyInline incoming, + _MappedSourceInlineContext destination, + ) { + final previous = destination.previousSibling; + final next = destination.nextSibling; + if (previous == null || + next == null || + !busyMarkSameInlineSemantics(previous, incoming) || + !busyMarkSameInlineSemantics(next, incoming)) { + return null; + } + final delimiters = switch (incoming.kind) { + BusyInlineKind.strong => const ['**', '__'], + BusyInlineKind.emphasis => const ['*', '_'], + BusyInlineKind.strikethrough => const ['~~'], + _ => const [], + }; + for (final delimiter in delimiters) { + if (offset >= delimiter.length && + offset + delimiter.length <= source.length && + source.substring(offset - delimiter.length, offset) == delimiter && + source.substring(offset, offset + delimiter.length) == delimiter) { + return _MappedAdjacentInlineRuns( + leftClosingRange: TextRange( + start: offset - delimiter.length, + end: offset, + ), + rightOpeningRange: TextRange( + start: offset, + end: offset + delimiter.length, + ), + ); + } + } + return null; + } + + _StructuredSourceInsertionContext _structuredSourceInsertionContext( + SourcePasteDocumentSnapshot target, + ) { + final selection = target.selection.isValid + ? target.selection + : TextSelection.collapsed(offset: target.text.length); + final start = math + .min(selection.start, selection.end) + .clamp(0, target.text.length) + .toInt(); + final end = math + .max(selection.start, selection.end) + .clamp(start, target.text.length) + .toInt(); + if (target.format != SourceDocumentFormat.markdown) { + return _StructuredSourceInsertionContext(start: start, end: end); + } + final marker = _sourceClipboardMarker(target.text); + final markedSource = target.text.replaceRange(start, end, marker); + final original = const MarkdownParser().parse( + filePath: target.filePath ?? '', + source: target.text, + mode: target.markdownMode, + validateLocalReferences: false, + ); + final marked = const MarkdownParser().parse( + filePath: target.filePath ?? '', + source: markedSource, + mode: target.markdownMode, + validateLocalReferences: false, + ); + final path = _sourceBlockPathContainingMarker( + marked.busyDocument.blocks, + marker, + ); + final markerBlock = path?.lastOrNull; + final markerOffset = markerBlock?.plainText.indexOf(marker); + final sourceProtected = + path == null || + path.any( + (block) => + block.isSourceProtected || + block.preserveRaw || + block.kind == BusyBlockKind.codeBlock || + block.kind == BusyBlockKind.math || + block.kind == BusyBlockKind.htmlBlock || + block.kind == BusyBlockKind.writersideRawXml, + ); + final survivingTable = + path?.any((block) => block.kind == BusyBlockKind.table) ?? false; + final originalCell = _singleTableCellContainingSelection( + original.busyDocument.blocks, + target.text, + start, + end, + ); + final originalTable = _tableIntersectingSelection( + original.busyDocument.blocks, + start, + end, + ); + final partialTableSelection = + originalTable != null && + !originalTable.coversWhole && + originalCell == null; + final tableCell = survivingTable && originalCell != null; + final unsafeStructuredContainer = + partialTableSelection || (survivingTable && originalCell == null); + final atBlockStart = markerOffset == null || markerOffset == 0; + final prefixes = _sourceContainerPrefixes(markedSource, start, path ?? []); + final inlineMappingRange = originalCell == null + ? _sourceInlineMappingRange( + original.busyDocument.blocks, + target.text, + start, + end, + ) + : TextRange( + start: originalCell.span.startOffset, + end: originalCell.span.endOffset, + ); + final inlineMapping = _mappedSourceInlineContext( + target, + start, + end, + inlineMappingRange, + inlineOnly: originalCell != null, + ); + final completeBlockSelection = _selectionCoversCompleteBlocks( + original.busyDocument.blocks, + target.text, + start, + end, + ); + final headingSource = _headingSourceDescriptor( + target.text, + markerBlock?.kind == BusyBlockKind.heading + ? markerBlock + : _headingContainingSelection( + original.busyDocument.blocks, + start, + end, + ), + contentOffset: start, + ); + return _StructuredSourceInsertionContext( + start: start, + end: end, + lineEnding: _sourceInsertionLineEnding(target.text, start), + marker: marker, + tableCell: tableCell, + sourceProtected: sourceProtected, + unsafeStructuredContainer: unsafeStructuredContainer, + atBlockStart: atBlockStart, + containerContinuationPrefix: prefixes.continuation, + containerBlankPrefix: prefixes.blank, + hasContainerContentBefore: markerOffset != null && markerOffset > 0, + hasContainerContentAfter: + markerOffset != null && + markerBlock != null && + markerOffset + marker.length < markerBlock.plainText.length, + taskItemAtContentStart: + markerOffset == 0 && markerBlock?.kind == BusyBlockKind.taskListItem, + completeBlockSelection: completeBlockSelection, + destinationBlockKind: markerBlock?.kind, + destinationBlockSourceStart: markerBlock?.sourceSpan?.startOffset, + headingSource: headingSource, + inlineContext: inlineMapping.context, + inlineMappingFailed: inlineMapping.failed, + ); + } + + BusyBlock? _headingContainingSelection( + Iterable blocks, + int start, + int end, + ) { + BusyBlock? result; + void visit(Iterable values) { + for (final block in values) { + final span = block.sourceSpan; + final intersects = + span != null && + (start == end + ? start >= span.startOffset && start <= span.endOffset + : start < span.endOffset && end > span.startOffset); + if (intersects && block.kind == BusyBlockKind.heading) result = block; + if (intersects) visit(block.children); + } + } + + visit(blocks); + return result; + } + + _HeadingSourceDescriptor? _headingSourceDescriptor( + String source, + BusyBlock? heading, { + required int contentOffset, + }) { + final span = heading?.sourceSpan; + if (heading == null || source.isEmpty) return null; + final firstLine = busyMarkSourceLineBounds( + source, + span?.startOffset ?? contentOffset, + ); + final line = source.substring(firstLine.start, firstLine.end); + final atx = RegExp( + r'^(?:[ \t]*(?:>[ \t]*|(?:[-+*]|\d+[.)])[ \t]+))*?' + r'(#{1,6}[ \t]+)', + ).firstMatch(line); + if (atx != null) { + final openingEnd = atx.end; + final openingStart = openingEnd - atx.group(1)!.length; + final openingRange = TextRange( + start: firstLine.start + openingStart, + end: firstLine.start + openingEnd, + ); + final closing = RegExp( + r'[ \t]+#+[ \t]*$', + ).firstMatch(line.substring(openingEnd)); + final closingRange = closing == null + ? null + : TextRange( + start: firstLine.start + openingEnd + closing.start, + end: firstLine.start + openingEnd + closing.end, + ); + return _HeadingSourceDescriptor( + contentRange: TextRange( + start: openingRange.end, + end: closingRange?.start ?? firstLine.end, + ), + openingAtxMarkerRange: openingRange, + closingAtxMarkerRange: closingRange, + enclosingContainerPrefixRange: TextRange( + start: firstLine.start, + end: openingRange.start, + ), + ); + } + + final nextLineStart = firstLine.end < source.length + ? firstLine.end + 1 + : source.length; + if (nextLineStart >= source.length) return null; + final underlineLine = busyMarkSourceLineBounds(source, nextLineStart); + final underline = source.substring(underlineLine.start, underlineLine.end); + if (!RegExp(r'^[ \t]*(?:>[ \t]*)*(?:=+|-+)[ \t]*$').hasMatch(underline)) { + return null; + } + final contentPrefix = RegExp( + r'^[ \t]*(?:(?:>[ \t]*)|(?:[-+*][ \t]+)|(?:\d+[.)][ \t]+))*', + ).firstMatch(line)!; + return _HeadingSourceDescriptor( + contentRange: TextRange( + start: firstLine.start + contentPrefix.end, + end: firstLine.end, + ), + setextUnderlineRange: TextRange( + start: firstLine.end, + end: underlineLine.end, + ), + enclosingContainerPrefixRange: TextRange( + start: firstLine.start, + end: firstLine.start + contentPrefix.end, + ), + ); + } + + bool _selectionCoversCompleteBlocks( + Iterable blocks, + String source, + int start, + int end, + ) { + if (start == end) return false; + final selected = []; + for (final block in blocks) { + final span = block.sourceSpan; + if (span == null || start >= span.endOffset || end <= span.startOffset) { + continue; + } + if (start > span.startOffset || end < span.endOffset) return false; + selected.add(TextRange(start: span.startOffset, end: span.endOffset)); + } + if (selected.isEmpty) return false; + selected.sort((left, right) => left.start.compareTo(right.start)); + var cursor = start; + for (final span in selected) { + if (source.substring(cursor, span.start).trim().isNotEmpty) { + return false; + } + cursor = span.end; + } + return source.substring(cursor, end).trim().isEmpty; + } + + String _sourceInsertionLineEnding(String source, int offset) { + final before = source.lastIndexOf('\n', math.max(0, offset - 1)); + if (before >= 0) { + return before > 0 && source.codeUnitAt(before - 1) == 0x0d + ? '\r\n' + : '\n'; + } + final after = source.indexOf('\n', offset.clamp(0, source.length).toInt()); + if (after >= 0) { + return after > 0 && source.codeUnitAt(after - 1) == 0x0d ? '\r\n' : '\n'; + } + return '\n'; + } + + ({_MappedSourceInlineContext? context, bool failed}) + _mappedSourceInlineContext( + SourcePasteDocumentSnapshot target, + int start, + int end, + TextRange sourceBounds, { + required bool inlineOnly, + }) { + final startMarker = _sourceClipboardMarker(target.text); + final endMarker = start == end + ? startMarker + : _sourceClipboardMarker('${target.text}$startMarker'); + var markedSource = target.text; + if (start != end) { + markedSource = markedSource.replaceRange(end, end, endMarker); + } + markedSource = markedSource.replaceRange(start, start, startMarker); + final parserContext = const MarkdownSourceMapper() + .createInlineParserContext( + documentSource: target.text, + mode: target.markdownMode, + ); + final markerCount = + startMarker.length + (start == end ? 0 : endMarker.length); + final markedBounds = TextRange( + start: sourceBounds.start, + end: (sourceBounds.end + markerCount) + .clamp(0, markedSource.length) + .toInt(), + ); + if (markedBounds.start < 0 || + markedBounds.start > markedBounds.end || + markedBounds.end > markedSource.length) { + return (context: null, failed: true); + } + final markers = [startMarker, if (start != end) endMarker]; + final mapped = inlineOnly + ? parserContext.parseMapped( + markedSource.substring(markedBounds.start, markedBounds.end), + ignoredReferenceLabelMarkers: markers, + ) + : parserContext.parseMappedBlock( + markedSource, + sourceStart: markedBounds.start, + sourceEnd: markedBounds.end, + ignoredReferenceLabelMarkers: markers, + ); + if (mapped == null) { + return (context: null, failed: true); + } + if (!mapped.positionRecordsComplete) { + final boundary = start == end + ? _mappedSourceBoundaryContext( + mapped, + start, + rangeBaseOffset: inlineOnly ? markedBounds.start : 0, + startMarker: startMarker, + ) + : null; + return (context: boundary, failed: true); + } + final startTrace = _sourceInlineTraceContainingMarkerInInlines( + mapped.inlines, + startMarker, + ); + if (startTrace == null) return (context: null, failed: true); + final endTrace = start == end + ? startTrace + : _sourceInlineTraceContainingMarkerInInlines( + mapped.inlines, + endMarker, + ); + if (endTrace == null) return (context: null, failed: true); + final commonAncestors = []; + final commonLength = math.min( + startTrace.frames.length, + endTrace.frames.length, + ); + for (var index = 0; index < commonLength; index++) { + final startInline = startTrace.frames[index].inline; + if (!identical(startInline, endTrace.frames[index].inline)) break; + commonAncestors.add(startInline); + } + final wrappers = <_MappedSourceInlineWrapper>[]; + for (final inline in commonAncestors) { + if (!busyMarkIsInheritedInlineContext(inline.kind)) continue; + final range = mapped.ranges[inline]; + final wrapper = range == null + ? _mappedSourceInlineWrapperFallback( + target, + markedSource, + inline, + startMarker, + start == end ? null : endMarker, + start, + end, + markedBounds, + parserContext, + ) + : _mappedSourceInlineWrapperFromRange( + target, + inline, + range, + start, + end, + markerCount, + markedBounds, + rangeBaseOffset: inlineOnly ? markedBounds.start : 0, + ); + if (wrapper != null) wrappers.add(wrapper); + } + assert(() { + debugBusyMarkSourceInlineMappingParseCount?.call( + parserContext.parseInvocations, + ); + return true; + }()); + return ( + context: _MappedSourceInlineContext( + commonAncestors: List.unmodifiable(commonAncestors), + wrappers: List.unmodifiable(wrappers), + startMarker: startMarker, + endMarker: start == end ? null : endMarker, + previousSibling: start == end + ? _sourceInlineSibling(startTrace, startMarker, before: true) + : null, + nextSibling: start == end + ? _sourceInlineSibling(startTrace, startMarker, before: false) + : null, + ), + failed: false, + ); + } + + _MappedSourceInlineContext? _mappedSourceBoundaryContext( + BusyMarkMappedInlineParse mapped, + int sourceOffset, { + required int rangeBaseOffset, + required String startMarker, + }) { + BusyInline semantic(BusyInline inline) => + mapped.ranges[inline]?.originalInline ?? inline; + + ({BusyInline previous, BusyInline next})? find(List siblings) { + for (var index = 1; index < siblings.length; index++) { + final previous = siblings[index - 1]; + final next = siblings[index]; + final previousRange = mapped.ranges[previous]; + final nextRange = mapped.ranges[next]; + if (previousRange != null && + nextRange != null && + rangeBaseOffset + previousRange.end == sourceOffset && + rangeBaseOffset + nextRange.start == sourceOffset) { + return (previous: semantic(previous), next: semantic(next)); + } + } + for (final inline in siblings) { + final nested = find(inline.children); + if (nested != null) return nested; + } + // CommonMark treats `**left****right**` as one strong run whose middle + // delimiter text is literal. Source editing has historically treated + // the authored close/open pair as a joinable boundary. Keep that local + // behavior only when the authoritative parse says the boundary remains + // inside the same matching semantic wrapper; the caller separately + // verifies the exact delimiter bytes on both sides of the caret. + for (final inline in siblings.reversed) { + final range = mapped.ranges[inline]; + final value = semantic(inline); + if (range != null && + rangeBaseOffset + range.start < sourceOffset && + sourceOffset < rangeBaseOffset + range.end && + (value.kind == BusyInlineKind.strong || + value.kind == BusyInlineKind.emphasis || + value.kind == BusyInlineKind.strikethrough)) { + return (previous: value, next: value); + } + } + return null; + } + + final boundary = find(mapped.inlines); + if (boundary == null) return null; + return _MappedSourceInlineContext( + commonAncestors: const [], + wrappers: const [], + startMarker: startMarker, + endMarker: null, + previousSibling: boundary.previous, + nextSibling: boundary.next, + ); + } + + _MappedSourceInlineWrapper? _mappedSourceInlineWrapperFromRange( + SourcePasteDocumentSnapshot target, + BusyInline inline, + BusyMarkMappedInlineRange mappedRange, + int selectionStart, + int selectionEnd, + int markerCount, + TextRange markedBounds, { + required int rangeBaseOffset, + }) { + if (inline.kind == BusyInlineKind.link && + mappedRange.originalInline == null) { + return null; + } + final markedStart = rangeBaseOffset + mappedRange.start; + final markedEnd = rangeBaseOffset + mappedRange.end; + final originalEnd = markedEnd - markerCount; + if (markedStart < markedBounds.start || + markedStart > selectionStart || + originalEnd < selectionEnd || + markedEnd > markedBounds.end || + originalEnd > target.text.length) { + return null; + } + return _MappedSourceInlineWrapper( + inline: inline, + sourceRange: TextRange(start: markedStart, end: originalEnd), + opening: mappedRange.opening, + closing: mappedRange.closing, + lineBreaks: mappedRange.lineBreaks, + isAutolink: mappedRange.isAutolink, + isReference: mappedRange.isReference, + ); + } + + _MappedSourceInlineWrapper? _mappedSourceInlineWrapperFallback( + SourcePasteDocumentSnapshot target, + String markedSource, + BusyInline inline, + String startMarker, + String? endMarker, + int selectionStart, + int selectionEnd, + TextRange markedBounds, + BusyMarkInlineParserContext parserContext, + ) { + final markerCount = startMarker.length + (endMarker?.length ?? 0); + TextRange? originalRange(int markedStart, int markedEnd) { + final end = markedEnd - markerCount; + if (markedStart < 0 || + markedStart > selectionStart || + end < selectionEnd || + end > target.text.length) { + return null; + } + return TextRange(start: markedStart, end: end); + } + + bool containsMarkers(String text) => + text.contains(startMarker) && + (endMarker == null || text.contains(endMarker)); + bool candidateMatches(int start, int end) { + if (start < markedBounds.start || + end > markedBounds.end || + start >= end) { + return false; + } + final parsed = parserContext.parse( + markedSource.substring(start, end), + ignoredReferenceLabelMarkers: [ + startMarker, + if (endMarker != null) endMarker, + ], + ); + return parsed.length == 1 && + busyMarkSameInlineSemantics(parsed.single, inline) && + parsed.single.plainText == inline.plainText && + containsMarkers(parsed.single.plainText); + } + + final markedStart = markedSource.indexOf(startMarker); + final markedEnd = endMarker == null + ? markedStart + startMarker.length + : markedSource.indexOf(endMarker, markedStart + startMarker.length) + + endMarker.length; + if (markedStart < 0 || markedEnd <= markedStart) return null; + if (inline.kind == BusyInlineKind.link) { + // A known original link must have a parser-derived range and semantic + // association. Falling back to marked link content could persist a + // mapping marker as its destination or change reference identity. + return null; + } + + if (inline.kind == BusyInlineKind.underline) { + const openingDelimiter = ''; + const closingDelimiter = ''; + final opening = markedSource.lastIndexOf(openingDelimiter, markedStart); + final closing = markedSource.indexOf(closingDelimiter, markedEnd); + final candidateEnd = closing + closingDelimiter.length; + if (opening >= markedBounds.start && + closing >= markedEnd && + candidateEnd <= markedBounds.end && + candidateMatches(opening, candidateEnd)) { + final range = originalRange(opening, candidateEnd); + return range == null + ? null + : _MappedSourceInlineWrapper( + inline: inline, + sourceRange: range, + opening: openingDelimiter, + closing: closingDelimiter, + ); + } + } + return null; + } + + _SourceInlineTrace? _sourceInlineTraceContainingMarkerInInlines( + List siblings, + String marker, + ) { + for (var index = 0; index < siblings.length; index++) { + final inline = siblings[index]; + if (!inline.plainText.contains(marker)) continue; + final child = _sourceInlineTraceContainingMarkerInInlines( + inline.children, + marker, + ); + return _SourceInlineTrace( + frames: [ + _SourceInlineFrame(inline: inline, siblings: siblings, index: index), + ...?child?.frames, + ], + ); + } + return null; + } + + BusyInline? _sourceInlineSibling( + _SourceInlineTrace trace, + String marker, { + required bool before, + }) { + final leafText = trace.frames.last.inline.plainText; + final markerOffset = leafText.indexOf(marker); + if (markerOffset < 0) return null; + if (before && markerOffset != 0) return null; + if (!before && markerOffset + marker.length != leafText.length) { + return null; + } + for (final frame in trace.frames.reversed) { + final siblingIndex = before ? frame.index - 1 : frame.index + 1; + if (siblingIndex >= 0 && siblingIndex < frame.siblings.length) { + return frame.siblings[siblingIndex]; + } + } + return null; + } + + String _sourceClipboardMarker(String source) { + for (var codePoint = 0xe000; codePoint <= 0xf8ff; codePoint++) { + final marker = String.fromCharCode(codePoint); + if (!source.contains(marker)) return marker; + } + return '\u{f0000}'; + } + + List? _sourceBlockPathContainingMarker( + Iterable blocks, + String marker, + ) { + bool contains(BusyBlock block) => + block.plainText.contains(marker) || + block.children.any((child) => contains(child)); + + for (final block in blocks) { + if (!contains(block)) continue; + final childPath = _sourceBlockPathContainingMarker( + block.children, + marker, + ); + return [block, ...?childPath]; + } + return null; + } + + BusyMarkMarkdownTableCellRegion? _singleTableCellContainingSelection( + Iterable blocks, + String source, + int start, + int end, + ) { + for (final block in _sourceBlocksDepthFirst(blocks)) { + if (block.kind != BusyBlockKind.table || block.sourceSpan == null) { + continue; + } + for (final region in busyMarkMarkdownTableCellRegions( + source: source, + table: block, + )) { + if (start >= region.span.startOffset && end <= region.span.endOffset) { + return region; + } + } + } + return null; + } + + TextRange _sourceInlineMappingRange( + Iterable blocks, + String source, + int start, + int end, + ) { + TextRange? smallest; + for (final block in _sourceBlocksDepthFirst(blocks)) { + final span = block.sourceSpan; + if (span == null || start < span.startOffset || end > span.endOffset) { + continue; + } + final candidate = TextRange(start: span.startOffset, end: span.endOffset); + if (smallest == null || + candidate.end - candidate.start < smallest.end - smallest.start) { + smallest = candidate; + } + } + if (smallest != null) return smallest; + final line = busyMarkSourceLineBounds(source, start); + return TextRange(start: line.start, end: line.end); + } + + ({BusyBlock table, bool coversWhole})? _tableIntersectingSelection( + Iterable blocks, + int start, + int end, + ) { + for (final block in _sourceBlocksDepthFirst(blocks)) { + final span = block.sourceSpan; + if (block.kind != BusyBlockKind.table || span == null) continue; + final intersects = start == end + ? start >= span.startOffset && start <= span.endOffset + : start < span.endOffset && end > span.startOffset; + if (!intersects) continue; + return ( + table: block, + coversWhole: start <= span.startOffset && end >= span.endOffset, + ); + } + return null; + } + + Iterable _sourceBlocksDepthFirst( + Iterable blocks, + ) sync* { + for (final block in blocks) { + yield block; + yield* _sourceBlocksDepthFirst(block.children); + } + } + + ({String continuation, String blank}) _sourceContainerPrefixes( + String source, + int markerOffset, + List path, + ) { + final containerKinds = [ + for (final block in path) + if (block.kind == BusyBlockKind.blockquote || + block.kind == BusyBlockKind.unorderedListItem || + block.kind == BusyBlockKind.orderedListItem || + block.kind == BusyBlockKind.taskListItem) + block.kind, + ]; + if (containerKinds.isEmpty) return (continuation: '', blank: ''); + ({String value, int count}) parseLineFrom(String line, int firstKindIndex) { + var cursor = 0; + var count = 0; + final continuation = StringBuffer(); + for ( + var kindIndex = firstKindIndex; + kindIndex < containerKinds.length; + kindIndex++ + ) { + final kind = containerKinds[kindIndex]; + if (kind == BusyBlockKind.blockquote) { + final start = cursor; + var spaces = 0; + while (cursor < line.length && + (firstKindIndex > 0 || spaces < 3) && + line.codeUnitAt(cursor) == 0x20) { + cursor += 1; + spaces += 1; + } + if (cursor >= line.length || line.codeUnitAt(cursor) != 0x3e) { + cursor = start; + break; + } + cursor += 1; + if (cursor < line.length && + (line.codeUnitAt(cursor) == 0x20 || + line.codeUnitAt(cursor) == 0x09)) { + cursor += 1; + } + continuation.write(line.substring(start, cursor)); + count++; + continue; + } + final start = cursor; + while (cursor < line.length && + (line.codeUnitAt(cursor) == 0x20 || + line.codeUnitAt(cursor) == 0x09)) { + cursor += 1; + } + final marker = _consumeSourceListMarker(line, cursor); + if (marker == null) { + cursor = start; + break; + } + cursor = marker.end; + continuation + ..write(line.substring(start, marker.start)) + ..write( + ' ' * + (_sourceIndentationColumn(line, cursor) - + _sourceIndentationColumn(line, marker.start)), + ); + count++; + } + return ( + value: continuation.toString(), + count: count == 0 ? 0 : firstKindIndex + count, + ); + } + + ({String value, int count}) parseLine(String line) { + var best = (value: '', count: 0); + for (var index = 0; index < containerKinds.length; index++) { + final candidate = parseLineFrom(line, index); + if (candidate.count > best.count) best = candidate; + } + return best; + } + + final currentLine = busyMarkSourceLineBounds(source, markerOffset); + final currentLineStart = currentLine.start; + final currentLineEnd = currentLine.end; + var best = parseLine(source.substring(currentLineStart, currentLineEnd)); + + // Continuation and lazy-quote lines need not repeat their ancestors' + // opening markers. Search only within the surviving outer container and + // resolve the deepest visible ancestor on each opening line. This permits + // outer and inner containers to open on different physical lines. + final outerContainer = path.firstWhere( + (block) => + block.kind == BusyBlockKind.blockquote || + block.kind == BusyBlockKind.unorderedListItem || + block.kind == BusyBlockKind.orderedListItem || + block.kind == BusyBlockKind.taskListItem, + ); + final outerStart = + (outerContainer.sourceSpan?.startOffset ?? currentLineStart) + .clamp(0, currentLineStart) + .toInt(); + var scanEnd = currentLineStart; + while (best.count < containerKinds.length && scanEnd > outerStart) { + final previousLine = busyMarkSourceLineBounds(source, scanEnd - 1); + final scanStart = math.max(outerStart, previousLine.start); + final candidate = parseLine( + source.substring(scanStart, previousLine.end), + ); + if (candidate.count > best.count) best = candidate; + if (candidate.count == containerKinds.length || scanStart == outerStart) { + break; + } + scanEnd = scanStart; + } + var value = best.value; + if (containerKinds.every( + (kind) => + kind == BusyBlockKind.unorderedListItem || + kind == BusyBlockKind.orderedListItem || + kind == BusyBlockKind.taskListItem, + )) { + var indentationEnd = currentLineStart; + while (indentationEnd < currentLineEnd && + (source.codeUnitAt(indentationEnd) == 0x20 || + source.codeUnitAt(indentationEnd) == 0x09)) { + indentationEnd += 1; + } + final authoredIndentation = source.substring( + currentLineStart, + indentationEnd, + ); + if (_sourceIndentationColumn( + authoredIndentation, + authoredIndentation.length, + ) >= + _sourceIndentationColumn(value, value.length)) { + value = authoredIndentation; + } + } + return (continuation: value, blank: value.trimRight()); + } + + ({int start, int end})? _consumeSourceListMarker(String line, int offset) { + if (offset >= line.length) return null; + var cursor = offset; + final first = line.codeUnitAt(cursor); + if (first == 0x2d || first == 0x2b || first == 0x2a) { + cursor += 1; + } else if (first >= 0x30 && first <= 0x39) { + var digits = 0; + while (cursor < line.length && + line.codeUnitAt(cursor) >= 0x30 && + line.codeUnitAt(cursor) <= 0x39 && + digits < 9) { + cursor += 1; + digits += 1; + } + if (cursor >= line.length || + (line.codeUnitAt(cursor) != 0x2e && + line.codeUnitAt(cursor) != 0x29)) { + return null; + } + cursor += 1; + } else { + return null; + } + if (cursor >= line.length || + (line.codeUnitAt(cursor) != 0x20 && line.codeUnitAt(cursor) != 0x09)) { + return null; + } + while (cursor < line.length && + (line.codeUnitAt(cursor) == 0x20 || line.codeUnitAt(cursor) == 0x09)) { + cursor += 1; + } + return (start: offset, end: cursor); + } + + int _sourceIndentationColumn(String line, int offset) { + var column = 0; + for (var index = 0; index < offset; index++) { + if (line.codeUnitAt(index) == 0x09) { + column += 4 - (column % 4); + } else { + column += 1; + } + } + return column; + } + + int _leadingLineBreaks(String value) { + var count = 0; + var offset = 0; + while (offset < value.length) { + if (value.codeUnitAt(offset) == 0x0d && + offset + 1 < value.length && + value.codeUnitAt(offset + 1) == 0x0a) { + count++; + offset += 2; + } else if (value.codeUnitAt(offset) == 0x0a) { + count++; + offset++; + } else { + break; + } + } + return count; + } + + int _trailingLineBreaks(String value) { + var count = 0; + var offset = value.length; + while (offset > 0 && value.codeUnitAt(offset - 1) == 0x0a) { + count++; + offset--; + if (offset > 0 && value.codeUnitAt(offset - 1) == 0x0d) offset--; + } + return count; + } + + String _restoreGeneratedLineEndings(String source, String lineEnding) => + lineEnding == '\n' ? source : source.replaceAll('\n', lineEnding); + + String _repeatLineEnding(String lineEnding, int count) => + List.filled(count, lineEnding).join(); +} + +class _StructuredSourceInsertionContext { + const _StructuredSourceInsertionContext({ + required this.start, + required this.end, + this.lineEnding = '\n', + this.marker = '', + this.tableCell = false, + this.sourceProtected = false, + this.unsafeStructuredContainer = false, + this.atBlockStart = false, + this.containerContinuationPrefix = '', + this.containerBlankPrefix = '', + this.hasContainerContentBefore = false, + this.hasContainerContentAfter = false, + this.taskItemAtContentStart = false, + this.completeBlockSelection = false, + this.destinationBlockKind, + this.destinationBlockSourceStart, + this.headingSource, + this.inlineMappingFailed = false, + this.inlineContext, + }); + + final int start; + final int end; + final String lineEnding; + final String marker; + final bool tableCell; + final bool sourceProtected; + final bool unsafeStructuredContainer; + final bool atBlockStart; + final String containerContinuationPrefix; + final String containerBlankPrefix; + final bool hasContainerContentBefore; + final bool hasContainerContentAfter; + final bool taskItemAtContentStart; + final bool completeBlockSelection; + final BusyBlockKind? destinationBlockKind; + final int? destinationBlockSourceStart; + final _HeadingSourceDescriptor? headingSource; + int? get destinationBlockStructuralPrefixStart => + headingSource?.openingAtxMarkerRange?.start; + final bool inlineMappingFailed; + final _MappedSourceInlineContext? inlineContext; +} + +class _HeadingSourceDescriptor { + const _HeadingSourceDescriptor({ + required this.contentRange, + required this.enclosingContainerPrefixRange, + this.openingAtxMarkerRange, + this.closingAtxMarkerRange, + this.setextUnderlineRange, + }); + + final TextRange contentRange; + final TextRange? openingAtxMarkerRange; + final TextRange? closingAtxMarkerRange; + final TextRange? setextUnderlineRange; + final TextRange enclosingContainerPrefixRange; + + TextRange? get trailingSyntaxRange => + closingAtxMarkerRange ?? setextUnderlineRange; +} + +class _MappedSourceInlineContext { + const _MappedSourceInlineContext({ + required this.commonAncestors, + required this.wrappers, + required this.startMarker, + required this.endMarker, + this.previousSibling, + this.nextSibling, + }); + + final List commonAncestors; + final List<_MappedSourceInlineWrapper> wrappers; + final String startMarker; + final String? endMarker; + final BusyInline? previousSibling; + final BusyInline? nextSibling; + + _MappedSourceInlineWrapper? wrapperFor(BusyInline inline) { + for (final wrapper in wrappers) { + if (identical(wrapper.inline, inline)) return wrapper; + } + return null; + } +} + +class _MappedSourceInlineWrapper { + const _MappedSourceInlineWrapper({ + required this.inline, + required this.sourceRange, + this.opening, + this.closing, + this.lineBreaks = const [], + this.isAutolink = false, + this.isReference = false, + }); + + final BusyInline inline; + final TextRange sourceRange; + final String? opening; + final String? closing; + final List lineBreaks; + final bool isAutolink; + final bool isReference; +} + +class _SerializedMappedSourceLineBreak { + const _SerializedMappedSourceLineBreak({ + required this.sourceOffset, + required this.lineBreak, + }); + + final int sourceOffset; + final BusyMarkMappedSourceLineBreak lineBreak; +} + +class _SourceInlineTrace { + const _SourceInlineTrace({required this.frames}); + + final List<_SourceInlineFrame> frames; +} + +class _SourceInlineFrame { + const _SourceInlineFrame({ + required this.inline, + required this.siblings, + required this.index, + }); + + final BusyInline inline; + final List siblings; + final int index; +} + +class _MappedAdjacentInlineRuns { + const _MappedAdjacentInlineRuns({ + required this.leftClosingRange, + required this.rightOpeningRange, + }); + + final TextRange leftClosingRange; + final TextRange rightOpeningRange; +} + +class _StructuredBlockInlineSplit { + const _StructuredBlockInlineSplit({ + required this.sourceRange, + required this.before, + required this.after, + required this.annotations, + this.beforeAuthoredWrapper, + this.afterAuthoredWrapper, + this.expanded = false, + this.startBlockKind, + this.startBlockSourceStart, + this.startBlockStructuralPrefixStart, + this.startAtBlockStart = false, + }); + + final TextRange sourceRange; + final List before; + final List after; + final _SourceInlineOccurrenceAnnotations annotations; + final _MappedSourceInlineWrapper? beforeAuthoredWrapper; + final _MappedSourceInlineWrapper? afterAuthoredWrapper; + final bool expanded; + final BusyBlockKind? startBlockKind; + final int? startBlockSourceStart; + final int? startBlockStructuralPrefixStart; + final bool startAtBlockStart; +} + +class _SourceInlineOccurrenceAnnotations { + final Set _rawHtml = Set.identity(); + + bool isRawHtml(BusyInline inline) => _rawHtml.contains(inline); + + void markRawHtml(BusyInline inline) => _rawHtml.add(inline); + + BusyInline copyAnnotation( + BusyInline source, + BusyInline replacement, { + bool rawHtml = false, + }) { + if (rawHtml || isRawHtml(source)) markRawHtml(replacement); + return replacement; + } + + BusyInline copyAnnotations( + Iterable sources, + BusyInline replacement, + ) { + if (sources.any(isRawHtml)) markRawHtml(replacement); + return replacement; + } +} + +sealed class _SourcePlan { + const _SourcePlan(); +} + +class _SourceTerminalPlan extends _SourcePlan { + const _SourceTerminalPlan(); +} + +class _SourceEditPlan extends _SourcePlan { + const _SourceEditPlan({ + required this.start, + required this.end, + required this.text, + this.caretOffset, + }); + + final int start; + final int end; + final String text; + final int? caretOffset; +} diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index 27eb5b15..a12447f5 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import '../../app/busymark_design.dart'; @@ -167,6 +168,9 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { required this.onFocused, this.onCut, this.onCopy, + this.onPaste, + this.onPastePlainText, + this.readPasteAvailability, this.onCopyPlainText, this.onRefineWithAi, this.editRevision = 0, @@ -181,6 +185,13 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { this.tableCellFocusNode, this.tableCellKey, this.onTableCellFocused, + this.spellingRanges = const [], + this.spellingEditableKey, + this.tableCellSpellingRanges, + this.tableCellSpellingEditableKey, + this.spellingMenuReader, + this.tableCellSpellingMenuReader, + this.onCheckSpelling, }); final BusyBlock block; @@ -213,6 +224,9 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final VoidCallback onFocused; final VoidCallback? onCut; final VoidCallback? onCopy; + final VoidCallback? onPaste; + final VoidCallback? onPastePlainText; + final BusyMarkEditorTextPasteAvailabilityReader? readPasteAvailability; final VoidCallback? onCopyPlainText; final VoidCallback? onRefineWithAi; final int editRevision; @@ -227,6 +241,14 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final FocusNode Function(BusyBlock cell)? tableCellFocusNode; final GlobalKey Function(String cellId)? tableCellKey; final ValueChanged? onTableCellFocused; + final List spellingRanges; + final GlobalKey? spellingEditableKey; + final List Function(String cellId)? tableCellSpellingRanges; + final GlobalKey Function(String cellId)? tableCellSpellingEditableKey; + final BusyMarkEditorSpellingMenuReader? spellingMenuReader; + final BusyMarkEditorSpellingMenuReader Function(String cellId)? + tableCellSpellingMenuReader; + final VoidCallback? onCheckSpelling; @override Widget build(BuildContext context) { @@ -391,9 +413,16 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { cellFocusNode: tableCellFocusNode, cellKey: tableCellKey, onCellFocused: onTableCellFocused, + cellSpellingRanges: tableCellSpellingRanges, + cellSpellingEditableKey: tableCellSpellingEditableKey, + cellSpellingMenuReader: tableCellSpellingMenuReader, + onCheckSpelling: onCheckSpelling, suppressContextMenu: documentSelectionActive, onCut: onCut, onCopy: onCopy, + onPaste: onPaste, + onPastePlainText: onPastePlainText, + readPasteAvailability: readPasteAvailability, onCopyPlainText: onCopyPlainText, ), ); @@ -517,50 +546,71 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { selectionColor: BusyMarkLinuxPalette.transparent, ), - child: TextField( - key: ValueKey( - 'wysiwyg-field-$documentFilePath-${block.id}', - ), - controller: controller, - undoController: undoController, - focusNode: focusNode, - maxLines: null, - minLines: 1, - textDirection: textDirection, - style: style, - cursorWidth: BusyMarkDocumentTextGeometry - .editableCursorWidth, - selectionHeightStyle: BusyMarkDocumentTextGeometry - .selectionHeightStyle, - selectionWidthStyle: BusyMarkDocumentTextGeometry - .selectionWidthStyle, - decoration: const InputDecoration( - isCollapsed: true, - border: InputBorder.none, - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - filled: false, - hoverColor: BusyMarkLinuxPalette.transparent, - contentPadding: EdgeInsets.zero, + child: KeyedSubtree( + key: spellingEditableKey, + child: TextField( + key: ValueKey( + 'wysiwyg-field-$documentFilePath-${block.id}', + ), + controller: controller, + undoController: undoController, + focusNode: focusNode, + maxLines: null, + minLines: 1, + textDirection: textDirection, + style: style, + cursorWidth: BusyMarkDocumentTextGeometry + .editableCursorWidth, + selectionHeightStyle: + BusyMarkDocumentTextGeometry + .selectionHeightStyle, + selectionWidthStyle: + BusyMarkDocumentTextGeometry + .selectionWidthStyle, + decoration: const InputDecoration( + isCollapsed: true, + border: InputBorder.none, + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + filled: false, + hoverColor: BusyMarkLinuxPalette.transparent, + contentPadding: EdgeInsets.zero, + ), + contextMenuBuilder: documentSelectionActive + ? (context, editableTextState) => + const SizedBox.shrink() + : (context, editableTextState) => + buildBusyMarkEditorTextContextMenu( + context, + editableTextState, + refineWithAiLabel: + context.l10n.aiRefineWithAi, + onRefineWithAi: onRefineWithAi, + onCut: onCut, + onCopy: onCopy, + onPaste: onPaste, + onPastePlainText: onPastePlainText, + readPasteAvailability: + readPasteAvailability, + onCopyPlainText: onCopyPlainText, + readSpellingItems: + spellingMenuReader, + onCheckSpelling: onCheckSpelling, + ), + onTap: onFocused, + onChanged: onChanged, ), - contextMenuBuilder: documentSelectionActive - ? (context, editableTextState) => - const SizedBox.shrink() - : (context, editableTextState) => - buildBusyMarkEditorTextContextMenu( - context, - editableTextState, - refineWithAiLabel: - context.l10n.aiRefineWithAi, - onRefineWithAi: onRefineWithAi, - onCut: onCut, - onCopy: onCopy, - onCopyPlainText: onCopyPlainText, - ), - onTap: onFocused, - onChanged: onChanged, ), ), + if (spellingRanges.isNotEmpty && + spellingEditableKey != null) + Positioned.fill( + child: _SpellingUnderlineOverlay( + editableKey: spellingEditableKey!, + controller: controller, + ranges: spellingRanges, + ), + ), ], )), ), @@ -1471,7 +1521,14 @@ class _TableBlockEditor extends StatefulWidget { this.suppressContextMenu = false, this.onCut, this.onCopy, + this.onPaste, + this.onPastePlainText, + this.readPasteAvailability, this.onCopyPlainText, + this.cellSpellingRanges, + this.cellSpellingEditableKey, + this.cellSpellingMenuReader, + this.onCheckSpelling, }); final BusyBlock block; @@ -1495,7 +1552,15 @@ class _TableBlockEditor extends StatefulWidget { final bool suppressContextMenu; final VoidCallback? onCut; final VoidCallback? onCopy; + final VoidCallback? onPaste; + final VoidCallback? onPastePlainText; + final BusyMarkEditorTextPasteAvailabilityReader? readPasteAvailability; final VoidCallback? onCopyPlainText; + final List Function(String cellId)? cellSpellingRanges; + final GlobalKey Function(String cellId)? cellSpellingEditableKey; + final BusyMarkEditorSpellingMenuReader Function(String cellId)? + cellSpellingMenuReader; + final VoidCallback? onCheckSpelling; @override State<_TableBlockEditor> createState() => _TableBlockEditorState(); @@ -1664,9 +1729,22 @@ class _TableBlockEditorState extends State<_TableBlockEditor> { onCellFocused(cellId); } }, + spellingRanges: cell == null + ? const [] + : widget.cellSpellingRanges?.call(cell.id) ?? const [], + spellingEditableKey: cell == null + ? null + : widget.cellSpellingEditableKey?.call(cell.id), + spellingMenuReader: cell == null + ? null + : widget.cellSpellingMenuReader?.call(cell.id), + onCheckSpelling: widget.onCheckSpelling, suppressContextMenu: widget.suppressContextMenu, onCut: widget.onCut, onCopy: widget.onCopy, + onPaste: widget.onPaste, + onPastePlainText: widget.onPastePlainText, + readPasteAvailability: widget.readPasteAvailability, onCopyPlainText: widget.onCopyPlainText, ), ); @@ -2029,7 +2107,14 @@ class _TableCellEditor extends StatefulWidget { this.suppressContextMenu = false, this.onCut, this.onCopy, + this.onPaste, + this.onPastePlainText, + this.readPasteAvailability, this.onCopyPlainText, + this.spellingRanges = const [], + this.spellingEditableKey, + this.spellingMenuReader, + this.onCheckSpelling, }); final BusyBlock? cell; @@ -2049,7 +2134,14 @@ class _TableCellEditor extends StatefulWidget { final bool suppressContextMenu; final VoidCallback? onCut; final VoidCallback? onCopy; + final VoidCallback? onPaste; + final VoidCallback? onPastePlainText; + final BusyMarkEditorTextPasteAvailabilityReader? readPasteAvailability; final VoidCallback? onCopyPlainText; + final List spellingRanges; + final GlobalKey? spellingEditableKey; + final BusyMarkEditorSpellingMenuReader? spellingMenuReader; + final VoidCallback? onCheckSpelling; @override State<_TableCellEditor> createState() => _TableCellEditorState(); @@ -2197,64 +2289,278 @@ class _TableCellEditorState extends State<_TableCellEditor> { key: widget.cellKey, child: Padding( padding: BusyMarkInsets.documentTableCell, - child: TextField( - key: ValueKey(cell.id), - controller: _controller, - focusNode: _focusNode, - undoController: widget.undoController, - minLines: 1, - maxLines: 1, - inputFormatters: const [_SingleLineTableCellFormatter()], - style: textStyle, - textAlign: textAlign, - selectionHeightStyle: - BusyMarkDocumentTextGeometry.selectionHeightStyle, - selectionWidthStyle: BusyMarkDocumentTextGeometry.selectionWidthStyle, - decoration: InputDecoration( - isCollapsed: true, - border: InputBorder.none, - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - filled: false, - hoverColor: BusyMarkLinuxPalette.transparent, - hintText: widget.header - ? context.l10n.tableHeaderHint - : context.l10n.tableCellHint, - hintStyle: textStyle.copyWith(color: colors.mutedForeground), - contentPadding: EdgeInsets.zero, - ), - contextMenuBuilder: widget.suppressContextMenu - ? (context, editableTextState) => const SizedBox.shrink() - : (context, editableTextState) => - buildBusyMarkEditorTextContextMenu( - context, - editableTextState, - refineWithAiLabel: context.l10n.aiRefineWithAi, - onCut: widget.onCut, - onCopy: widget.onCopy, - onCopyPlainText: widget.onCopyPlainText, - ), - onTap: () { - final onCellFocused = widget.onCellFocused; - if (onCellFocused == null) { - widget.onFocused(); - } else { - onCellFocused(cell.id); - } - }, - onChanged: (value) { - if (_sourceEditing) { - widget.onSourceChanged(cell.id, value); - } else { - widget.onChanged(cell.id, value); - } - }, + child: Stack( + clipBehavior: Clip.hardEdge, + children: [ + KeyedSubtree( + key: widget.spellingEditableKey, + child: TextField( + key: ValueKey(cell.id), + controller: _controller, + focusNode: _focusNode, + undoController: widget.undoController, + minLines: 1, + maxLines: 1, + inputFormatters: const [_SingleLineTableCellFormatter()], + style: textStyle, + textAlign: textAlign, + selectionHeightStyle: + BusyMarkDocumentTextGeometry.selectionHeightStyle, + selectionWidthStyle: + BusyMarkDocumentTextGeometry.selectionWidthStyle, + decoration: InputDecoration( + isCollapsed: true, + border: InputBorder.none, + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + filled: false, + hoverColor: BusyMarkLinuxPalette.transparent, + hintText: widget.header + ? context.l10n.tableHeaderHint + : context.l10n.tableCellHint, + hintStyle: textStyle.copyWith(color: colors.mutedForeground), + contentPadding: EdgeInsets.zero, + ), + contextMenuBuilder: widget.suppressContextMenu + ? (context, editableTextState) => const SizedBox.shrink() + : (context, editableTextState) => + buildBusyMarkEditorTextContextMenu( + context, + editableTextState, + refineWithAiLabel: context.l10n.aiRefineWithAi, + onCut: widget.onCut, + onCopy: widget.onCopy, + onPaste: widget.onPaste, + onPastePlainText: widget.onPastePlainText, + readPasteAvailability: widget.readPasteAvailability, + onCopyPlainText: widget.onCopyPlainText, + readSpellingItems: widget.spellingMenuReader, + onCheckSpelling: widget.onCheckSpelling, + ), + onTap: () { + final onCellFocused = widget.onCellFocused; + if (onCellFocused == null) { + widget.onFocused(); + } else { + onCellFocused(cell.id); + } + }, + onChanged: (value) { + if (_sourceEditing) { + widget.onSourceChanged(cell.id, value); + } else { + widget.onChanged(cell.id, value); + } + }, + ), + ), + if (widget.spellingRanges.isNotEmpty && + widget.spellingEditableKey != null) + Positioned.fill( + child: _SpellingUnderlineOverlay( + editableKey: widget.spellingEditableKey!, + controller: _controller, + ranges: widget.spellingRanges, + ), + ), + ], + ), + ), + ); + } +} + +class _SpellingUnderlineOverlay extends StatefulWidget { + const _SpellingUnderlineOverlay({ + required this.editableKey, + required this.controller, + required this.ranges, + }); + + final GlobalKey editableKey; + final TextEditingController controller; + final List ranges; + + @override + State<_SpellingUnderlineOverlay> createState() => + _SpellingUnderlineOverlayState(); +} + +class _SpellingUnderlineOverlayState extends State<_SpellingUnderlineOverlay> { + final _overlayKey = GlobalKey(); + final _repaint = ValueNotifier(0); + ViewportOffset? _editableOffset; + + @override + void initState() { + super.initState(); + widget.controller.addListener(_requestRepaint); + _scheduleOffsetBinding(); + } + + @override + void didUpdateWidget(covariant _SpellingUnderlineOverlay oldWidget) { + super.didUpdateWidget(oldWidget); + if (!identical(oldWidget.controller, widget.controller)) { + oldWidget.controller.removeListener(_requestRepaint); + widget.controller.addListener(_requestRepaint); + } + _scheduleOffsetBinding(); + _requestRepaint(); + } + + void _scheduleOffsetBinding() { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + final editable = _findRenderEditable( + widget.editableKey.currentContext?.findRenderObject(), + ); + final offset = editable?.offset; + if (identical(offset, _editableOffset)) return; + _editableOffset?.removeListener(_requestRepaint); + _editableOffset = offset; + _editableOffset?.addListener(_requestRepaint); + _requestRepaint(); + }); + } + + void _requestRepaint() => _repaint.value++; + + @override + void dispose() { + widget.controller.removeListener(_requestRepaint); + _editableOffset?.removeListener(_requestRepaint); + _repaint.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return IgnorePointer( + child: CustomPaint( + key: _overlayKey, + painter: _SpellingUnderlinePainter( + editableKey: widget.editableKey, + overlayKey: _overlayKey, + controller: widget.controller, + ranges: widget.ranges, + color: Theme.of(context).colorScheme.error, + repaint: _repaint, ), ), ); } } +class _SpellingUnderlinePainter extends CustomPainter { + _SpellingUnderlinePainter({ + required this.editableKey, + required this.overlayKey, + required this.controller, + required this.ranges, + required this.color, + required Listenable repaint, + }) : super(repaint: repaint); + + final GlobalKey editableKey; + final GlobalKey overlayKey; + final TextEditingController controller; + final List ranges; + final Color color; + + @override + void paint(Canvas canvas, Size size) { + final editable = _findRenderEditable( + editableKey.currentContext?.findRenderObject(), + ); + final overlay = overlayKey.currentContext?.findRenderObject(); + if (editable == null || overlay is! RenderBox || !overlay.hasSize) return; + canvas.save(); + canvas.clipRect(Offset.zero & size); + final paint = Paint() + ..color = color + ..strokeWidth = 1.2 + ..style = PaintingStyle.stroke; + for (final range in ranges) { + if (!range.isValid || + range.isCollapsed || + range.end > (editable.text?.toPlainText().length ?? 0)) { + continue; + } + if (busyMarkSpellingUnderlineSuppressed(controller, range)) continue; + final boxes = editable.getBoxesForSelection( + TextSelection(baseOffset: range.start, extentOffset: range.end), + ); + for (final box in boxes) { + final topLeft = overlay.globalToLocal( + editable.localToGlobal(Offset(box.left, box.top)), + ); + final bottomRight = overlay.globalToLocal( + editable.localToGlobal(Offset(box.right, box.bottom)), + ); + _paintWave( + canvas, + paint, + left: topLeft.dx, + right: bottomRight.dx, + y: bottomRight.dy - 1, + ); + } + } + canvas.restore(); + } + + void _paintWave( + Canvas canvas, + Paint paint, { + required double left, + required double right, + required double y, + }) { + if (right <= left) return; + const halfWave = 2.0; + const amplitude = 1.25; + final path = Path()..moveTo(left, y); + var x = left; + var up = true; + while (x < right) { + x = (x + halfWave).clamp(left, right); + path.lineTo(x, y + (up ? -amplitude : amplitude)); + up = !up; + } + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant _SpellingUnderlinePainter oldDelegate) => + oldDelegate.ranges != ranges || + oldDelegate.controller != controller || + oldDelegate.color != color || + oldDelegate.editableKey != editableKey; +} + +@visibleForTesting +bool busyMarkSpellingUnderlineSuppressed( + TextEditingController controller, + TextRange range, +) { + final composing = controller.value.composing; + return composing.isValid && + !composing.isCollapsed && + range.start < composing.end && + range.end > composing.start; +} + +RenderEditable? _findRenderEditable(RenderObject? root) { + if (root == null) return null; + if (root is RenderEditable) return root; + RenderEditable? result; + root.visitChildren((child) { + result ??= _findRenderEditable(child); + }); + return result; +} + TextAlign _tableCellTextAlign(String? value) { return switch (busyTableAlignmentFromAttribute(value)) { BusyTableAlignment.unspecified => TextAlign.start, diff --git a/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart index 287baaf3..6167f374 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart @@ -6,6 +6,7 @@ import '../../markdown/busymark_document.dart'; import '../../markdown/busymark_markdown_serializer.dart'; import '../../markdown/markdown_model.dart'; import '../../platform/rich_clipboard_service.dart'; +import '../inline_semantics.dart'; import 'wysiwyg_document_controller.dart'; import 'wysiwyg_inline_controller.dart'; @@ -33,6 +34,77 @@ class WysiwygClipboardFragment { BusyDocument(filePath: sourcePath, mode: mode, blocks: documentBlocks), ); + String serializeFor({ + required MarkdownMode destinationMode, + required String destinationFilePath, + }) => const BusyMarkMarkdownSerializer().serialize( + BusyDocument( + filePath: destinationFilePath, + mode: destinationMode, + blocks: [ + for (final block in documentBlocks) + _destinationSerializationBlock(block), + ], + ), + ); + + bool get isInlineSourceFragment { + final values = documentBlocks; + return values.length == 1 && + !busyMarkClipboardRequiresCompleteBlockInsertion(blocks.single) && + values.single.kind == BusyBlockKind.paragraph && + values.single.children.isEmpty && + !values.single.isSourceOnly; + } + + String serializeInlineFor({ + required MarkdownMode destinationMode, + required String destinationFilePath, + bool tableCell = false, + bool atBlockStart = false, + }) { + final inlines = sourceInsertionInlinesFor(tableCell: tableCell); + if (inlines.isEmpty) return ''; + return const BusyMarkMarkdownSerializer().serializeInlineFragment( + inlines, + tableCell: tableCell, + atBlockStart: atBlockStart, + readableHardBreakRuns: !tableCell, + ); + } + + /// Returns the exact semantic inline sequence used for Source insertion. + /// Table destinations receive the same flattened, newline-free model as + /// Editor table-cell insertion. + List sourceInsertionInlinesFor({required bool tableCell}) { + final values = sourceInsertionBlocks; + if (tableCell) { + return busyMarkTableCellInlinesFromBlocks(values); + } + if (!isInlineSourceFragment) return const []; + return values.single.inlines; + } + + List get sourceInsertionBlocks => List.unmodifiable([ + for (final block in documentBlocks) _destinationSerializationBlock(block), + ]); + + /// Flattens structured blocks with the same semantics as an Editor table + /// cell: block and line boundaries become spaces and inline styles survive. + String serializeTableCellFor({ + required MarkdownMode destinationMode, + required String destinationFilePath, + bool atBlockStart = false, + }) { + final inlines = sourceInsertionInlinesFor(tableCell: true); + return const BusyMarkMarkdownSerializer().serializeInlineFragment( + inlines, + tableCell: true, + atBlockStart: atBlockStart, + readableHardBreakRuns: false, + ); + } + String encode() => jsonEncode({ 'version': 1, 'mode': mode.name, @@ -312,6 +384,22 @@ bool _boundedJsonDepth(String source) { return true; } +BusyBlock _destinationSerializationBlock(BusyBlock block) => BusyBlock( + id: block.id, + kind: block.kind, + inlines: block.inlines, + children: [ + for (final child in block.children) _destinationSerializationBlock(child), + ], + attributes: block.attributes, + rawSource: block.rawSource, + preserveRaw: false, + isSourceOnly: block.isSourceOnly, + isGenerated: block.isGenerated, + isSourceProtected: false, + dirty: true, +); + class _FragmentReader { var nodes = 0; diff --git a/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart b/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart index e749669c..12595636 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart @@ -323,6 +323,7 @@ class _HtmlWriter { class _HtmlNormalizer { var count = 0; + static const _formattingTags = ['strong', 'em', 'u', 'del']; static const _discard = { 'script', 'style', @@ -351,13 +352,22 @@ class _HtmlNormalizer { throw const FormatException('Clipboard HTML node limit'); } if (node is dom.Text) { - dom.Node text = dom.Text(node.data); - if (node.data.trim().isNotEmpty) { - for (final tag in styles) { - text = _element(tag, [text]); - } + final content = node.data.trim(); + if (content.isEmpty || styles.isEmpty) { + out.add(dom.Text(node.data)); + continue; + } + // Markdown emphasis cannot open/close against whitespace. Keep that + // whitespace as text outside the formatting, not inside delimiters. + final start = node.data.length - node.data.trimLeft().length; + final end = node.data.trimRight().length; + if (start > 0) out.add(dom.Text(node.data.substring(0, start))); + dom.Node text = dom.Text(content); + for (final tag in _formattingTags.where(styles.contains)) { + text = _element(tag, [text]); } out.add(text); + if (end < node.data.length) out.add(dom.Text(node.data.substring(end))); continue; } if (node is! dom.Element) continue; @@ -371,7 +381,16 @@ class _HtmlNormalizer { } continue; } - final inherited = {...styles}; + tag = switch (tag) { + 'b' => 'strong', + 'i' => 'em', + 's' || 'strike' => 'del', + 'font' => 'span', + _ => tag, + }; + // Semantic tags and CSS contribute to the same set. Wrapping both + // produces duplicate emphasis (e.g. ******title******) after paste. + final inherited = {...styles, if (_formattingTags.contains(tag)) tag}; for (final declaration in (node.attributes['style'] ?? '').split(';')) { final colon = declaration.indexOf(':'); if (colon < 0) continue; @@ -405,13 +424,7 @@ class _HtmlNormalizer { } } final children = nodes(node.nodes, depth + 1, inherited); - tag = switch (tag) { - 'b' => 'strong', - 'i' => 'em', - 'strike' => 'del', - 'font' => 'span', - _ => tag, - }; + if (_formattingTags.contains(tag)) tag = 'span'; if (!isSafeHtmlTag(tag)) { out.addAll(children); continue; @@ -426,10 +439,112 @@ class _HtmlNormalizer { attrs[name] = entry.value; } } - out.add( - _element(tag, children, sanitizeHtmlAttributes(tag, attrs) ?? const {}), + final normalized = _element( + tag, + children, + sanitizeHtmlAttributes(tag, attrs) ?? const {}, ); + if (tag == 'span' && normalized.attributes.isEmpty) { + out.addAll(normalized.nodes.toList()); + } else if (tag == 'table' && _isLayoutTable(normalized, node)) { + // Web pages often use a one-column table to wrap an entire article. + // Sending that wrapper to the table adapter flattens its headings, + // paragraphs, lists and nested data tables into inline cell text. + // Keep each cell as a block container and retain real tables inside it. + out.add( + _element( + 'div', + [ + for (final caption in normalized.children.where( + (child) => child.localName == 'caption', + )) + _element('div', caption.nodes.toList()), + for (final row in _tableRows(normalized)) + for (final cell in row.children) + if (cell.localName == 'td' || cell.localName == 'th') + _element('div', cell.nodes.toList(), { + if (cell.attributes['dir'] case final direction?) + 'dir': direction, + }), + ], + { + if (normalized.attributes['dir'] case final direction?) + 'dir': direction, + }, + ), + ); + } else { + out.add(normalized); + } } - return out; + return _mergeAdjacentFormatting(out); + } + + List _mergeAdjacentFormatting(List nodes) { + final result = []; + for (final node in nodes) { + final previous = result.lastOrNull; + if (node is dom.Element && + previous is dom.Element && + _formattingTags.contains(node.localName) && + node.localName == previous.localName && + node.attributes.isEmpty && + previous.attributes.isEmpty) { + final children = _mergeAdjacentFormatting([ + ...previous.nodes, + ...node.nodes, + ]); + previous.nodes.clear(); + previous.nodes.addAll(children); + } else { + result.add(node); + } + } + return result; + } + + Iterable _tableRows(dom.Element table) sync* { + for (final child in table.children) { + if (child.localName == 'tr') { + yield child; + } else if (const {'thead', 'tbody', 'tfoot'}.contains(child.localName)) { + yield* child.children.where((row) => row.localName == 'tr'); + } + } + } + + bool _isLayoutTable(dom.Element table, dom.Element original) { + final normalizedRole = original.attributes['role']?.trim().toLowerCase(); + if (normalizedRole == 'presentation' || normalizedRole == 'none') { + return true; + } + if (const {'table', 'grid', 'treegrid'}.contains(normalizedRole) || + (int.tryParse(original.attributes['border'] ?? '0') ?? 0) > 0 || + table.children.any( + (child) => const {'caption', 'thead'}.contains(child.localName), + )) { + return false; + } + final rows = _tableRows(table).toList(); + if (rows.isEmpty) return false; + var hasDocumentContent = false; + for (final row in rows) { + final cells = row.children + .where((cell) => cell.localName == 'td' || cell.localName == 'th') + .toList(); + if (cells.length != 1) return false; + final cell = cells.single; + if (cell.localName == 'th' || + (int.tryParse(cell.attributes['colspan'] ?? '1') ?? 1) != 1 || + (int.tryParse(cell.attributes['rowspan'] ?? '1') ?? 1) != 1) { + return false; + } + hasDocumentContent = + hasDocumentContent || + cell.querySelector('table, h1, h2, h3, h4, h5, h6, ul, ol, pre') != + null || + cell.querySelectorAll('p').length > 1; + } + return hasDocumentContent; } } diff --git a/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart b/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart index 09520e9f..ac6d9f3b 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart @@ -7,16 +7,11 @@ import '../../markdown/markdown_model.dart'; import '../../markdown/markdown_parser.dart'; import '../../markdown/math_syntax.dart'; import '../../markdown/raw_html_adapter.dart'; +import '../../spellcheck/spelling_replacement.dart'; +import '../inline_semantics.dart'; import 'wysiwyg_commands.dart'; import 'wysiwyg_inline_controller.dart'; -/// Markdown table cells are represented by one source line. Normalize all -/// platform newline forms at the model boundary so programmatic callers cannot -/// create content that the table serializer cannot faithfully represent. -String busyMarkNormalizeTableCellText(String text) { - return text.replaceAll(RegExp(r'\r\n|\r|\n'), ' '); -} - BusyBlock busyMarkWysiwygImmutableBlockSnapshot(BusyBlock block) { BusyInline snapshotInline(BusyInline inline) { return BusyInline( @@ -51,6 +46,8 @@ BusyBlock busyMarkWysiwygImmutableBlockSnapshot(BusyBlock block) { ); } +enum BusyWysiwygReplacementScope { fieldContent, documentRange } + class BusyMarkWysiwygDocumentController extends ChangeNotifier { BusyMarkWysiwygDocumentController({ required BusyDocument document, @@ -82,8 +79,8 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { return block == null ? '' : busyMarkWysiwygEditableText(block); } - String _sourceWithBlockStructure(BusyBlock block, String source) { - final prefix = switch (block.kind) { + String _blockStructurePrefix(BusyBlock block) { + return switch (block.kind) { BusyBlockKind.heading => '${'#' * (int.tryParse(block.attributes['level'] ?? '') ?? 1)} ', BusyBlockKind.unorderedListItem => @@ -95,17 +92,26 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { BusyBlockKind.blockquote => '> ', _ => '', }; - return '$prefix$source'; } - void updateMathSource(String blockId, String source) { + String _sourceWithBlockStructure(BusyBlock block, String source) => + '${_blockStructurePrefix(block)}$source'; + + BusyWysiwygTextSplitResult? updateMathSource( + String blockId, + String source, { + int? sourceCaretOffset, + BusyWysiwygReplacementScope replacementScope = + BusyWysiwygReplacementScope.fieldContent, + }) { final current = blockById(blockId); if (current == null) { - return; + return null; } + final structuralPrefix = _blockStructurePrefix(current); final parsed = const MarkdownParser().parse( filePath: _document.filePath, - source: _sourceWithBlockStructure(current, source), + source: '$structuralPrefix$source', mode: _document.mode, validateLocalReferences: false, ); @@ -115,7 +121,32 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { block.kind != BusyBlockKind.frontMatter && !block.isSourceOnly, ) .toList(growable: false); - final replacements = parsedBlocks.isEmpty + List? descendantOwnerPath; + if (replacementScope == BusyWysiwygReplacementScope.fieldContent && + current.children.isNotEmpty) { + var ownerMarker = '\ue018'; + while (source.contains(ownerMarker)) { + ownerMarker = '${ownerMarker}x'; + } + final anchored = const MarkdownParser().parse( + filePath: _document.filePath, + source: '$structuralPrefix$ownerMarker$source', + mode: _document.mode, + validateLocalReferences: false, + ); + final anchoredBlocks = anchored.busyDocument.blocks + .where( + (block) => + block.kind != BusyBlockKind.frontMatter && !block.isSourceOnly, + ) + .toList(growable: false); + descendantOwnerPath = _blockPathContainingText( + anchoredBlocks, + ownerMarker, + )?.path; + if (descendantOwnerPath == null) return null; + } + var replacements = parsedBlocks.isEmpty ? [ BusyBlock( id: current.id, @@ -133,7 +164,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { : _nextGeneratedBlockId('math-edit'), kind: parsedBlock.kind, inlines: parsedBlock.inlines, - children: index == 0 ? current.children : parsedBlock.children, + children: parsedBlock.children, attributes: _mathEditedBlockAttributes( current, parsedBlock, @@ -145,10 +176,61 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { dirty: true, ), ]; + if (descendantOwnerPath != null) { + final owner = _blockAtPath(replacements, descendantOwnerPath); + if (owner == null || owner.kind != current.kind) return null; + replacements = _replaceBlockAtPath( + replacements, + descendantOwnerPath, + owner.copyWith(children: [...owner.children, ...current.children]), + ); + } + + var destinationPath = const [0]; + var destinationOffset = replacements.firstOrNull?.plainText.length ?? 0; + if (sourceCaretOffset != null && parsedBlocks.isNotEmpty) { + var marker = '\ue019'; + while (source.contains(marker)) { + marker = '${marker}x'; + } + final caret = sourceCaretOffset.clamp(0, source.length).toInt(); + final marked = const MarkdownParser().parse( + filePath: _document.filePath, + source: '$structuralPrefix${source.replaceRange(caret, caret, marker)}', + mode: _document.mode, + validateLocalReferences: false, + ); + final markedBlocks = marked.busyDocument.blocks + .where( + (block) => + block.kind != BusyBlockKind.frontMatter && !block.isSourceOnly, + ) + .toList(growable: false); + final located = _blockPathContainingText(markedBlocks, marker); + if (located != null) { + destinationPath = located.path; + final markedDestination = _blockAtPath(markedBlocks, located.path); + final editableOffset = markedDestination == null + ? -1 + : busyMarkWysiwygEditableText(markedDestination).indexOf(marker); + destinationOffset = editableOffset < 0 + ? located.offset + : editableOffset; + } + } _document = _document.copyWith( blocks: _replaceBlockWithMany(_document.blocks, blockId, replacements), ); notifyListeners(); + final destination = _blockAtPath(replacements, destinationPath); + final fallback = replacements.firstOrNull; + if (destination == null && fallback == null) return null; + final resolved = destination ?? fallback!; + final destinationText = busyMarkWysiwygEditableText(resolved); + return BusyWysiwygTextSplitResult( + blockId: resolved.id, + offset: destinationOffset.clamp(0, destinationText.length).toInt(), + ); } ({int selectionStart, int selectionEnd})? insertInlineMath( @@ -439,6 +521,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { String blockId, String text, { Iterable activeInlineKinds = const [], + bool preserveTextWhitespace = false, }) { _replaceBlock( blockId, @@ -446,6 +529,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { block, text, activeInlineKinds: activeInlineKinds, + preserveTextWhitespace: preserveTextWhitespace, ), ); } @@ -472,6 +556,114 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ); } + /// Applies a verified spelling plan directly to the owning inline leaves. + /// This intentionally bypasses whole-string style-range inference. + bool replaceSpellingInBlock({ + required String blockId, + required String expectedFieldText, + required SpellingReplacementPlan plan, + String? preparedFieldText, + }) { + final current = blockById(blockId); + if (current == null || + current.isSourceProtected || + busyMarkWysiwygEditableText(current) != expectedFieldText) { + return false; + } + if (busyMarkWysiwygBlockContainsMath(current)) { + late final String updatedSource; + if (preparedFieldText != null) { + if (preparedFieldText == expectedFieldText) return false; + updatedSource = preparedFieldText; + } else { + try { + updatedSource = plan.applyToField(expectedFieldText); + } on StateError { + return false; + } + } + updateMathSource(blockId, updatedSource); + return true; + } + final updatedInlines = _applySpellingLeafEdits( + current.inlines, + plan.richLeafEdits, + ); + if (updatedInlines == null) return false; + final updatedText = updatedInlines.map((inline) => inline.plainText).join(); + _replaceBlock( + blockId, + (block) => block.copyWith( + inlines: updatedInlines, + attributes: _attributesAfterInlineMathEdit(block, updatedInlines), + preserveRaw: false, + dirty: true, + ), + ); + return updatedText != current.plainText; + } + + bool replaceSpellingInTableCell({ + required String tableBlockId, + required String cellId, + required String expectedFieldText, + required SpellingReplacementPlan plan, + String? preparedFieldText, + }) { + final table = blockById(tableBlockId); + final current = blockById(cellId); + if (table?.kind != BusyBlockKind.table || + current == null || + current.isSourceProtected || + busyMarkWysiwygEditableText(current) != expectedFieldText) { + return false; + } + if (busyMarkWysiwygBlockContainsMath(current)) { + late final String updatedSource; + if (preparedFieldText != null) { + if (preparedFieldText == expectedFieldText) return false; + updatedSource = preparedFieldText; + } else { + try { + updatedSource = plan.applyToField(expectedFieldText); + } on StateError { + return false; + } + } + updateTableCellMarkdownSource(tableBlockId, cellId, updatedSource); + return true; + } + final updatedInlines = _applySpellingLeafEdits( + current.inlines, + plan.richLeafEdits, + ); + if (updatedInlines == null) return false; + var changed = false; + _document = _document.copyWith( + blocks: _replaceInBlocks(_document.blocks, tableBlockId, (block) { + if (block.kind != BusyBlockKind.table) return block; + final children = _replaceInBlocks(block.children, cellId, (cell) { + changed = true; + return cell.copyWith( + inlines: updatedInlines, + preserveRaw: false, + dirty: true, + ); + }); + return changed + ? block.copyWith( + children: children, + preserveRaw: false, + dirty: true, + ) + : block; + }), + ); + if (!changed) return false; + notifyListeners(); + return true; + } + /// A table cell accepts inline formatting; block boundaries become spaces. int? insertStyledInlinesInTableCell({ required String tableBlockId, @@ -485,28 +677,9 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { if (cell == null || table?.kind != BusyBlockKind.table || blocks.isEmpty) { return null; } - BusyInline normalize(BusyInline inline) => - inline.kind == BusyInlineKind.hardBreak || - inline.kind == BusyInlineKind.softBreak - ? const BusyInline(kind: BusyInlineKind.text, text: ' ') - : inline.copyWith( - text: busyMarkNormalizeTableCellText(inline.text), - children: [for (final child in inline.children) normalize(child)], - ); - final inserted = []; - void append(BusyBlock block) { - if (inserted.isNotEmpty) { - inserted.add(const BusyInline(kind: BusyInlineKind.text, text: ' ')); - } - inserted.addAll(block.inlines.map(normalize)); - for (final child in block.children) { - append(child); - } - } - - for (final block in blocks) { - append(busyMarkWysiwygClipboardBlock(block)); - } + final inserted = busyMarkTableCellInlinesFromBlocks([ + for (final block in blocks) busyMarkWysiwygClipboardBlock(block), + ]); final start = selectionStart.clamp(0, cell.plainText.length); final end = selectionEnd.clamp(start, cell.plainText.length); final partition = _partitionInlinesForReplacement(cell.inlines, start, end); @@ -593,8 +766,10 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { BusyWysiwygTextSplitResult? replaceBlockTextWithParagraphs( String blockId, String text, - int cursorOffset, - ) { + int cursorOffset, { + bool preserveTextWhitespace = false, + bool allowListExit = true, + }) { final block = blockById(blockId); if (block == null || !_shouldSplitNewlines(block.kind)) { return null; @@ -615,7 +790,9 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { if (paragraphBreaks.isEmpty) { return null; } - if (_isListItemKind(block.kind) && normalizedText.trim().isEmpty) { + if (allowListExit && + _isListItemKind(block.kind) && + normalizedText.trim().isEmpty) { _replaceBlockWithParagraph(blockId); return BusyWysiwygTextSplitResult(blockId: blockId, offset: 0); } @@ -656,6 +833,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { _sourceBackedSplitAttributes(block.attributes), block.kind, part, + preserveTextWhitespace: preserveTextWhitespace, ), preserveRaw: false, dirty: true, @@ -674,6 +852,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ), splitKind, part, + preserveTextWhitespace: preserveTextWhitespace, ), dirty: true, ), @@ -1782,8 +1961,21 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { return null; } - final mergedText = - firstText.substring(0, firstStart) + lastText.substring(lastEnd); + final firstPartition = _partitionInlinesForReplacement( + firstBlock.inlines, + firstStart, + firstText.length, + ); + final lastPartition = _partitionInlinesForReplacement( + lastBlock.inlines, + 0, + lastEnd, + ); + final mergedInlines = _mergeAdjacentInlineStyles([ + ...firstPartition.before, + ...lastPartition.after, + ]); + final mergedText = mergedInlines.map((inline) => inline.plainText).join(); final removeIds = removedIds.where((id) => id != firstBlockId).toSet(); _document = _document.copyWith( blocks: _removeBlocksByIds( @@ -1794,7 +1986,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ? BusyBlock( id: block.id, kind: BusyBlockKind.paragraph, - inlines: _textInlines(mergedText), + inlines: mergedInlines, attributes: _attributesForText( const {}, BusyBlockKind.paragraph, @@ -1802,7 +1994,11 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ), dirty: true, ) - : _blockWithEditedText(block, mergedText), + : block.copyWith( + inlines: mergedInlines, + preserveRaw: false, + dirty: true, + ), ), removeIds, ), @@ -1819,6 +2015,9 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { required int selectionStart, required int selectionEnd, required List blocks, + BusyWysiwygReplacementScope replacementScope = + BusyWysiwygReplacementScope.fieldContent, + bool destinationBlockFullySelected = false, }) { if (blocks.isEmpty) { return null; @@ -1837,8 +2036,11 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { start, end, ); + final ownsDestinationStructure = + replacementScope == BusyWysiwygReplacementScope.documentRange && + destinationBlockFullySelected; - if (blocks.any(_requiresCompleteBlockInsertion)) { + if (blocks.any(busyMarkClipboardRequiresCompleteBlockInsertion)) { return _insertCompleteBlocksAtSelection( block: block, blockId: blockId, @@ -1847,29 +2049,54 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { beforeInlines: partition.before, afterInlines: partition.after, blocks: blocks, + replaceDestinationStructure: ownsDestinationStructure, ); } final replacements = []; if (blocks.length == 1) { final inserted = blocks.single; - replacements.add( - block.copyWith( - kind: beforeText.isEmpty && afterText.isEmpty - ? inserted.kind - : block.kind, - attributes: beforeText.isEmpty && afterText.isEmpty - ? inserted.attributes - : block.attributes, - inlines: [ - ...partition.before, - ...busyMarkWysiwygClipboardBlock(inserted).inlines, - ...partition.after, - ], - preserveRaw: false, - dirty: true, - ), - ); + final clipboardBlock = busyMarkWysiwygClipboardBlock(inserted); + final insertedInlines = ownsDestinationStructure + ? clipboardBlock.inlines + : _applyInlineReplacementContext( + clipboardBlock.inlines, + _inlineContextForReplacement(block.inlines, start, end), + ); + final mergedInlines = _mergeAdjacentInlineStyles([ + ...partition.before, + ...insertedInlines, + ...partition.after, + ]); + if (ownsDestinationStructure) { + final structural = _styledBlockToBusyBlock(inserted, rootId: block.id); + final retainsDescendants = _isBlockContentContainer(structural.kind); + replacements.add( + structural.copyWith( + inlines: mergedInlines, + children: retainsDescendants + ? [...structural.children, ...block.children] + : structural.children, + preserveRaw: false, + dirty: true, + ), + ); + if (!retainsDescendants) replacements.addAll(block.children); + } else { + replacements.add( + block.copyWith( + // A text-field selection never owns the destination block itself. + // In particular, selecting all of a list item's own text does not + // select its descendants. Keep the destination structure and only + // replace its inline content. + kind: block.kind, + attributes: block.attributes, + inlines: mergedInlines, + preserveRaw: false, + dirty: true, + ), + ); + } _document = _document.copyWith( blocks: _replaceBlockWithMany(_document.blocks, blockId, replacements), ); @@ -1880,19 +2107,48 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ); } + if (_isBlockContentContainer(block.kind) && !ownsDestinationStructure) { + return _insertParagraphBlocksInsideContainer( + block: block, + beforeInlines: partition.before, + afterInlines: partition.after, + blocks: blocks, + ); + } + final first = blocks.first; - replacements.add( - block.copyWith( - kind: beforeText.isEmpty ? first.kind : block.kind, - attributes: beforeText.isEmpty ? first.attributes : block.attributes, - inlines: [ - ...partition.before, - ...busyMarkWysiwygClipboardBlock(first).inlines, - ], - preserveRaw: false, - dirty: true, - ), - ); + final adoptIncomingStructure = + beforeText.isEmpty && + (replacementScope == BusyWysiwygReplacementScope.documentRange || + start == end); + if (adoptIncomingStructure) { + final structural = _styledBlockToBusyBlock(first, rootId: block.id); + final retainsDescendants = _isBlockContentContainer(structural.kind); + replacements.add( + structural.copyWith( + inlines: [ + ...partition.before, + ...busyMarkWysiwygClipboardBlock(first).inlines, + ], + children: retainsDescendants + ? [...structural.children, ...block.children] + : structural.children, + preserveRaw: false, + dirty: true, + ), + ); + } else { + replacements.add( + block.copyWith( + inlines: [ + ...partition.before, + ...busyMarkWysiwygClipboardBlock(first).inlines, + ], + preserveRaw: false, + dirty: true, + ), + ); + } for (final inserted in blocks.skip(1).take(blocks.length - 2)) { replacements.add(_styledBlockToBusyBlock(inserted)); @@ -1907,6 +2163,10 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { dirty: true, ); replacements.add(lastBlock); + if (adoptIncomingStructure && + !_isBlockContentContainer(replacements.first.kind)) { + replacements.addAll(block.children); + } _document = _document.copyWith( blocks: _replaceBlockWithMany(_document.blocks, blockId, replacements), @@ -1926,7 +2186,19 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { required List beforeInlines, required List afterInlines, required List blocks, + required bool replaceDestinationStructure, }) { + if (_isBlockContentContainer(block.kind) && !replaceDestinationStructure) { + return _insertCompleteBlocksInsideContainer( + block: block, + blockId: blockId, + beforeText: beforeText, + afterText: afterText, + beforeInlines: beforeInlines, + afterInlines: afterInlines, + blocks: blocks, + ); + } final replacements = []; var originalIdAvailable = true; if (beforeText.isNotEmpty) { @@ -1953,7 +2225,19 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ); originalIdAvailable = false; } + if (replaceDestinationStructure && block.children.isNotEmpty) { + final firstInsertedIndex = beforeText.isEmpty ? 0 : 1; + final firstInserted = replacements[firstInsertedIndex]; + if (_isBlockContentContainer(firstInserted.kind)) { + replacements[firstInsertedIndex] = firstInserted.copyWith( + children: [...firstInserted.children, ...block.children], + ); + } else { + replacements.addAll(block.children); + } + } late final BusyBlock focusBlock; + late final int focusOffset; if (afterText.isNotEmpty) { focusBlock = BusyBlock( id: originalIdAvailable ? block.id : _nextGeneratedBlockId('paragraph'), @@ -1962,6 +2246,12 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { dirty: true, ); replacements.add(focusBlock); + focusOffset = 0; + } else if (beforeText.isEmpty && + block.kind != BusyBlockKind.paragraph && + replacements.isNotEmpty) { + focusBlock = replacements.last; + focusOffset = focusBlock.plainText.length; } else { focusBlock = BusyBlock( id: _nextGeneratedBlockId('paragraph'), @@ -1971,12 +2261,108 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { dirty: true, ); replacements.add(focusBlock); + focusOffset = 0; } _document = _document.copyWith( blocks: _replaceBlockWithMany(_document.blocks, blockId, replacements), ); notifyListeners(); - return BusyWysiwygTextSplitResult(blockId: focusBlock.id, offset: 0); + return BusyWysiwygTextSplitResult( + blockId: focusBlock.id, + offset: focusOffset, + ); + } + + bool _isBlockContentContainer(BusyBlockKind kind) => + kind == BusyBlockKind.unorderedListItem || + kind == BusyBlockKind.orderedListItem || + kind == BusyBlockKind.taskListItem || + kind == BusyBlockKind.blockquote; + + BusyWysiwygTextSplitResult _insertParagraphBlocksInsideContainer({ + required BusyBlock block, + required List beforeInlines, + required List afterInlines, + required List blocks, + }) { + final first = busyMarkWysiwygClipboardBlock(blocks.first); + final insertedChildren = [ + for (final styled in blocks.skip(1).take(blocks.length - 2)) + _styledBlockToBusyBlock(styled), + ]; + final lastStyled = blocks.last; + final last = _styledBlockToBusyBlock(lastStyled).copyWith( + inlines: [ + ...busyMarkWysiwygClipboardBlock(lastStyled).inlines, + ...afterInlines, + ], + dirty: true, + ); + insertedChildren.add(last); + final updated = block.copyWith( + inlines: _mergeAdjacentInlineStyles([...beforeInlines, ...first.inlines]), + children: [...insertedChildren, ...block.children], + preserveRaw: false, + dirty: true, + ); + _document = _document.copyWith( + blocks: _replaceBlockWithMany(_document.blocks, block.id, [updated]), + ); + notifyListeners(); + return BusyWysiwygTextSplitResult( + blockId: last.id, + offset: lastStyled.text.length, + ); + } + + BusyWysiwygTextSplitResult _insertCompleteBlocksInsideContainer({ + required BusyBlock block, + required String blockId, + required String beforeText, + required String afterText, + required List beforeInlines, + required List afterInlines, + required List blocks, + }) { + final inserted = [ + for (final styled in blocks) _styledBlockToBusyBlock(styled), + ]; + BusyBlock? trailing; + if (afterText.isNotEmpty) { + trailing = BusyBlock( + id: _nextGeneratedBlockId('paragraph'), + kind: BusyBlockKind.paragraph, + inlines: afterInlines, + dirty: true, + ); + } else if (beforeText.isNotEmpty) { + trailing = BusyBlock( + id: _nextGeneratedBlockId('paragraph'), + kind: BusyBlockKind.paragraph, + inlines: _textInlines(''), + attributes: const {busyMarkPreserveEmptyParagraphAttribute: 'true'}, + dirty: true, + ); + } + final updated = block.copyWith( + inlines: beforeInlines, + children: [ + ...inserted, + if (trailing != null) trailing, + ...block.children, + ], + preserveRaw: false, + dirty: true, + ); + _document = _document.copyWith( + blocks: _replaceBlockWithMany(_document.blocks, blockId, [updated]), + ); + notifyListeners(); + final focus = trailing ?? inserted.last; + return BusyWysiwygTextSplitResult( + blockId: focus.id, + offset: trailing == null ? focus.plainText.length : 0, + ); } BusyWysiwygTextSplitResult? replaceTextSelectionWithStyledBlocks({ @@ -1986,7 +2372,17 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { required int lastEndOffset, required Iterable removedBlockIds, required List blocks, + BusyWysiwygReplacementScope replacementScope = + BusyWysiwygReplacementScope.documentRange, }) { + final firstBlock = blockById(firstBlockId); + final selectedIds = removedBlockIds.toSet(); + final destinationBlockFullySelected = + firstBlock != null && + selectedIds.contains(firstBlockId) && + firstStartOffset <= 0 && + (firstBlockId != lastBlockId || + lastEndOffset >= firstBlock.plainText.length); final staged = BusyMarkWysiwygDocumentController(document: _document); final deletion = staged.deleteTextSelection( firstBlockId: firstBlockId, @@ -2004,6 +2400,8 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { selectionStart: deletion.offset, selectionEnd: deletion.offset, blocks: blocks, + replacementScope: replacementScope, + destinationBlockFullySelected: destinationBlockFullySelected, ); if (result == null) { staged.dispose(); @@ -2015,6 +2413,91 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { return result; } + BusyWysiwygTextSplitResult? replaceTextSelectionWithText({ + required String firstBlockId, + required int firstStartOffset, + required String lastBlockId, + required int lastEndOffset, + required Iterable removedBlockIds, + required String replacementText, + required Iterable activeInlineKinds, + required bool preserveTextWhitespace, + BusyWysiwygReplacementScope replacementScope = + BusyWysiwygReplacementScope.documentRange, + }) { + final firstBlock = blockById(firstBlockId); + final selectedIds = removedBlockIds.toSet(); + final destinationBlockFullySelected = + replacementScope == BusyWysiwygReplacementScope.documentRange && + firstBlock != null && + selectedIds.contains(firstBlockId) && + firstStartOffset <= 0 && + (firstBlockId != lastBlockId || + lastEndOffset >= firstBlock.plainText.length); + final staged = BusyMarkWysiwygDocumentController(document: _document); + final deletion = staged.deleteTextSelection( + firstBlockId: firstBlockId, + firstStartOffset: firstStartOffset, + lastBlockId: lastBlockId, + lastEndOffset: lastEndOffset, + removedBlockIds: selectedIds, + ); + if (deletion == null) { + staged.dispose(); + return null; + } + if (destinationBlockFullySelected) { + staged._replaceBlock( + deletion.blockId, + (block) => BusyBlock( + id: block.id, + kind: BusyBlockKind.paragraph, + inlines: block.inlines, + children: block.children, + attributes: _attributesForText( + const {}, + BusyBlockKind.paragraph, + block.plainText, + preserveTextWhitespace: preserveTextWhitespace, + ), + dirty: true, + ), + ); + } + final mergedText = staged.blockText(deletion.blockId); + final insertionOffset = deletion.offset.clamp(0, mergedText.length).toInt(); + final nextText = mergedText.replaceRange( + insertionOffset, + insertionOffset, + replacementText, + ); + final split = staged.replaceBlockTextWithParagraphs( + deletion.blockId, + nextText, + insertionOffset + replacementText.length, + preserveTextWhitespace: preserveTextWhitespace, + allowListExit: false, + ); + final result = + split ?? + BusyWysiwygTextSplitResult( + blockId: deletion.blockId, + offset: insertionOffset + replacementText.length, + ); + if (split == null) { + staged.updateBlockText( + deletion.blockId, + nextText, + activeInlineKinds: activeInlineKinds, + preserveTextWhitespace: preserveTextWhitespace, + ); + } + _document = staged.document; + staged.dispose(); + notifyListeners(); + return result; + } + String? insertThematicBreakAfter(String blockId) { if (blockById(blockId) == null) { return null; @@ -2318,6 +2801,56 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { } } +({List path, int offset})? _blockPathContainingText( + List blocks, + String marker, +) { + for (final (index, block) in blocks.indexed) { + final ownOffset = block.plainText.indexOf(marker); + if (ownOffset >= 0) return (path: [index], offset: ownOffset); + final child = _blockPathContainingText(block.children, marker); + if (child != null) { + return (path: [index, ...child.path], offset: child.offset); + } + } + return null; +} + +BusyBlock? _blockAtPath(List blocks, List path) { + var current = blocks; + BusyBlock? result; + for (final index in path) { + if (index < 0 || index >= current.length) return null; + result = current[index]; + current = result.children; + } + return result; +} + +List _replaceBlockAtPath( + List blocks, + List path, + BusyBlock replacement, +) { + if (path.isEmpty) return blocks; + final index = path.first; + if (index < 0 || index >= blocks.length) return blocks; + final updated = [...blocks]; + if (path.length == 1) { + updated[index] = replacement; + } else { + final current = blocks[index]; + updated[index] = current.copyWith( + children: _replaceBlockAtPath( + current.children, + path.sublist(1), + replacement, + ), + ); + } + return updated; +} + class BusyWysiwygTextSplitResult { const BusyWysiwygTextSplitResult({ required this.blockId, @@ -2369,13 +2902,11 @@ List busyMarkWysiwygClipboardInlineSlice( ).before; } -bool _requiresCompleteBlockInsertion(BusyWysiwygStyledBlock styled) { +bool busyMarkClipboardRequiresCompleteBlockInsertion( + BusyWysiwygStyledBlock styled, +) { final block = styled.completeBlock; - return block != null && - !busyMarkWysiwygCanApplyBlockCommand( - block, - BusyWysiwygBlockCommand.paragraph, - ); + return block != null && block.kind != BusyBlockKind.paragraph; } class _OutdentResult { @@ -2385,6 +2916,75 @@ class _OutdentResult { final List outdented; } +List? _applySpellingLeafEdits( + List inlines, + List edits, +) { + if (edits.isEmpty) return null; + final byPath = >{}; + for (final edit in edits) { + byPath.putIfAbsent(edit.path.join('.'), () => []).add(edit); + } + var fieldOffset = 0; + var applied = 0; + + BusyInline? visit(BusyInline inline, List path) { + if (inline.children.isNotEmpty) { + final children = []; + for (final (index, child) in inline.children.indexed) { + final updated = visit(child, [...path, index]); + if (updated != null) children.add(updated); + } + final text = children.map((child) => child.plainText).join(); + if (text.isEmpty && + _removableEmptyFormattingKinds.contains(inline.kind)) { + return null; + } + return inline.copyWith(text: text, children: children); + } + final leafStart = fieldOffset; + final leafEnd = leafStart + inline.text.length; + fieldOffset = leafEnd; + final leafEdits = byPath[path.join('.')]; + if (leafEdits == null || leafEdits.isEmpty) return inline; + var text = inline.text; + final descending = [...leafEdits] + ..sort((left, right) => right.start.compareTo(left.start)); + for (final edit in descending) { + if (edit.start < leafStart || + edit.end < edit.start || + edit.end > leafEnd) { + throw StateError('Spelling leaf edit escaped its verified leaf.'); + } + text = text.replaceRange( + edit.start - leafStart, + edit.end - leafStart, + edit.replacement, + ); + applied++; + } + return inline.copyWith(text: text); + } + + try { + final result = []; + for (final (index, inline) in inlines.indexed) { + final updated = visit(inline, [index]); + if (updated != null) result.add(updated); + } + return applied == edits.length ? result : null; + } on StateError { + return null; + } +} + +const _removableEmptyFormattingKinds = { + BusyInlineKind.strong, + BusyInlineKind.emphasis, + BusyInlineKind.underline, + BusyInlineKind.strikethrough, +}; + List _textInlines(String text) { return [BusyInline(kind: BusyInlineKind.text, text: text)]; } @@ -2508,10 +3108,23 @@ Map _splitAttributesFor( Map _attributesForText( Map attributes, BusyBlockKind kind, - String text, -) { + String text, { + bool preserveTextWhitespace = false, +}) { final updated = {...attributes} ..remove(busyMarkPreserveEmptyParagraphAttribute); + + final wasPreservingTextWhitespace = + updated[busyMarkPreserveTextWhitespaceAttribute] == 'true'; + final hasTrailingWhitespace = text.isNotEmpty && text.trimRight() != text; + + if (hasTrailingWhitespace && + (preserveTextWhitespace || wasPreservingTextWhitespace)) { + updated[busyMarkPreserveTextWhitespaceAttribute] = 'true'; + } else { + updated.remove(busyMarkPreserveTextWhitespaceAttribute); + } + if (text.isNotEmpty) { updated.remove(busyMarkTransientTrailingParagraphAttribute); } @@ -2635,6 +3248,69 @@ _partitionInlinesForReplacement(List inlines, int start, int end) { ); } +List _inlineContextForReplacement( + List inlines, + int start, + int end, +) { + var offset = 0; + for (final inline in inlines) { + final length = inline.plainText.length; + final inlineEnd = offset + length; + final contains = + start >= offset && + end <= inlineEnd && + (start < inlineEnd || start == offset); + if (contains && + inline.children.isNotEmpty && + busyMarkIsInheritedInlineContext(inline.kind)) { + return [ + inline, + ..._inlineContextForReplacement( + inline.children, + (start - offset).clamp(0, length).toInt(), + (end - offset).clamp(0, length).toInt(), + ), + ]; + } + offset = inlineEnd; + } + return const []; +} + +List _applyInlineReplacementContext( + List inserted, + List context, +) { + var result = inserted; + for (final wrapper in context.reversed) { + if (wrapper.kind == BusyInlineKind.link && + _containsInlineKind(result, BusyInlineKind.link)) { + continue; + } + if (result.length == 1 && + busyMarkSameInlineSemantics(wrapper, result.single)) { + continue; + } + result = [ + wrapper.copyWith( + text: result.map((inline) => inline.plainText).join(), + children: result, + ), + ]; + } + return result; +} + +bool _containsInlineKind(List inlines, BusyInlineKind kind) { + for (final inline in inlines) { + if (inline.kind == kind || _containsInlineKind(inline.children, kind)) { + return true; + } + } + return false; +} + ({String expression, String leading, String trailing})? _inlineMathExpressionParts(String value) { if (value.contains('\n') || value.contains('\r')) { @@ -2885,6 +3561,7 @@ BusyBlock _blockWithEditedText( BusyBlock block, String nextText, { Iterable activeInlineKinds = const [], + bool preserveTextWhitespace = false, }) { final oldText = block.plainText; final oldRanges = busyInlineStyleRanges(block.inlines); @@ -2911,7 +3588,12 @@ BusyBlock _blockWithEditedText( newText: nextText, rebuiltInlines: rebuiltInlines, ), - attributes: _attributesForText(block.attributes, block.kind, nextText), + attributes: _attributesForText( + block.attributes, + block.kind, + nextText, + preserveTextWhitespace: preserveTextWhitespace, + ), preserveRaw: false, dirty: true, ); diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 859452ce..ad3783e6 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -31,14 +31,23 @@ import '../../markdown/busymark_document.dart'; import '../../markdown/document_outline.dart'; import '../../markdown/markdown_model.dart'; import '../../markdown/markdown_parser.dart'; +import '../../markdown/markdown_source_structure.dart'; import '../../platform/linux_header_bar_service.dart'; import '../../platform/rich_clipboard_service.dart'; +import '../../spellcheck/spelling_projection.dart'; +import '../../spellcheck/spelling_replacement.dart'; +import '../../spellcheck/spelling_coordinator.dart'; import '../document_callout.dart'; import '../document_code_block.dart'; import '../document_collapsible.dart'; import '../document_layout.dart'; import '../document_surface.dart'; import '../document_text_geometry.dart'; +import '../editor_text_context_menu.dart'; +import '../inline_semantics.dart'; +import '../clipboard_paste_resolver.dart'; +import '../clipboard_local_image_path.dart'; +import '../source/source_paste_engine.dart'; import 'wysiwyg_block_widgets.dart'; import 'wysiwyg_commands.dart'; import 'wysiwyg_clipboard_fragment.dart'; @@ -54,6 +63,18 @@ typedef BusyMarkWysiwygSessionChanged = void Function(String documentId, WysiwygEditorSessionState state); typedef BusyMarkWysiwygTransactionalSourceChanged = void Function(String filePath, String source, String? undoGroup); +typedef BusyMarkWysiwygSpellingSourceChanged = + void Function( + String filePath, + String source, + WysiwygEditorSessionState beforeSession, + WysiwygEditorSessionState afterSession, + ); +typedef BusyMarkWysiwygSpellingMenuReader = + Future> Function( + SpellingEditorTarget target, + int offset, + ); class BusyMarkWysiwygSourceRange { const BusyMarkWysiwygSourceRange({ @@ -74,6 +95,11 @@ class BusyMarkWysiwygEditor extends StatefulWidget { this.initialSessionState = const WysiwygEditorSessionState(), this.onSessionChanged, this.onTransactionalSourceChanged, + this.onSpellingSourceChanged, + this.contentRevision, + this.spellingAnnotations = const [], + this.onCheckSpelling, + this.readSpellingMenuItems, this.useExternalUndoHistory = false, this.onDocumentChanged, this.workspaceRoot, @@ -115,6 +141,11 @@ class BusyMarkWysiwygEditor extends StatefulWidget { final WysiwygEditorSessionState initialSessionState; final BusyMarkWysiwygSessionChanged? onSessionChanged; final BusyMarkWysiwygTransactionalSourceChanged? onTransactionalSourceChanged; + final BusyMarkWysiwygSpellingSourceChanged? onSpellingSourceChanged; + final int? contentRevision; + final List spellingAnnotations; + final VoidCallback? onCheckSpelling; + final BusyMarkWysiwygSpellingMenuReader? readSpellingMenuItems; final bool useExternalUndoHistory; final ValueChanged? onDocumentChanged; final String? workspaceRoot; @@ -150,10 +181,10 @@ class BusyMarkWysiwygEditor extends StatefulWidget { final BusyMarkWysiwygMathDiagnosticCallback? onMathDiagnostic; @override - State createState() => _BusyMarkWysiwygEditorState(); + State createState() => BusyMarkWysiwygEditorState(); } -class _BusyMarkWysiwygEditorState extends State { +class BusyMarkWysiwygEditorState extends State { static const _historyLimit = 100; late final BusyMarkWysiwygDocumentController _documentController; @@ -163,6 +194,8 @@ class _BusyMarkWysiwygEditorState extends State { final _tableCellControllers = {}; final _tableCellFocusNodes = {}; final _tableCellKeys = {}; + final _spellingEditableKeys = {}; + final _tableCellSpellingEditableKeys = {}; StreamSubscription>? _assetDropSubscription; final _blockKeys = {}; final _undoStack = []; @@ -197,6 +230,7 @@ class _BusyMarkWysiwygEditorState extends State { bool _sessionReportScheduled = false; double? _viewportHeight; late final _WysiwygClipboardInsertionTarget _historyInsertionTarget; + _PendingTextFocus? _pendingTextFocus; String get _documentId => widget.documentId ?? widget.document.filePath; @@ -209,6 +243,234 @@ class _BusyMarkWysiwygEditorState extends State { @visibleForTesting int get debugUndoSnapshotCount => _undoStack.length; + /// Generation that projection adapters must capture for rich targets. + int get spellingDocumentGeneration => _documentGeneration; + + int spellingReviewStartIndex(List occurrences) { + final targetId = _activeCellId ?? _activeBlockId; + if (targetId == null) return 0; + final controller = _activeCellId == null + ? _textControllers[targetId] + : _tableCellControllers[targetId]; + final caret = controller?.selection.extentOffset ?? 0; + final exact = occurrences.indexWhere((occurrence) { + final target = occurrence.run.target; + final matches = switch (target) { + SpellingRichBlockTarget(:final blockId) => + _activeCellId == null && blockId == targetId, + SpellingRichTableCellTarget(:final cellId) => cellId == targetId, + _ => false, + }; + return matches && + (occurrence.fieldEnd ?? -1) >= caret && + occurrence.run.snapshot.bufferId == _documentId; + }); + return exact < 0 ? 0 : exact; + } + + void revealSpellingOccurrence(SpellingOccurrence occurrence) { + final target = occurrence.run.target; + final fieldStart = occurrence.fieldStart; + final fieldEnd = occurrence.fieldEnd; + if (fieldStart == null || fieldEnd == null) return; + switch (target) { + case SpellingRichBlockTarget(:final blockId): + _revealBlockThen(blockId, () { + final controller = _textControllers[blockId]; + if (controller == null || fieldEnd > controller.text.length) return; + _setActiveBlock(blockId); + controller.selection = TextSelection( + baseOffset: fieldStart, + extentOffset: fieldEnd, + ); + _focusNodes[blockId]?.requestFocus(); + }); + case SpellingRichTableCellTarget(:final tableBlockId, :final cellId): + _revealBlockThen(tableBlockId, () { + final controller = _tableCellControllers[cellId]; + if (controller == null || fieldEnd > controller.text.length) return; + _setActiveTableCell(tableBlockId, cellId); + controller.selection = TextSelection( + baseOffset: fieldStart, + extentOffset: fieldEnd, + ); + _tableCellFocusNodes[cellId]?.requestFocus(); + }); + case SpellingSourceTarget(): + break; + } + } + + void restoreSpellingFocus() => _restoreEditingFocusAfterFrame(); + + /// Applies one already-checked occurrence as a single structured edit. + /// + /// Every identity is checked both before planning and immediately before + /// the synchronous controller mutation. Stale occurrences are never + /// recovered by searching for the same word. + bool applySpellingCorrection({ + required SpellingOccurrence occurrence, + required String suggestion, + }) { + final expectedFieldText = spellingFieldSnapshot(occurrence); + if (expectedFieldText == null) return false; + late final SpellingReplacementPlan plan; + String? preparedFieldText; + try { + plan = const SpellingReplacementPlanner().build( + occurrence: occurrence, + suggestion: suggestion, + ); + if (plan.fieldEdits.isNotEmpty) { + preparedFieldText = plan.applyToField(expectedFieldText); + } + } on Object { + return false; + } + return applyPreparedSpellingCorrection( + occurrence: occurrence, + suggestion: suggestion, + plan: plan, + expectedFieldText: expectedFieldText, + preparedFieldText: preparedFieldText, + ); + } + + String? spellingFieldSnapshot(SpellingOccurrence occurrence) { + if (!_isSpellingOccurrenceCurrent(occurrence)) return null; + final target = occurrence.run.target; + if (target is! SpellingRichBlockTarget && + target is! SpellingRichTableCellTarget) { + return null; + } + final targetId = switch (target) { + SpellingRichBlockTarget(:final blockId) => blockId, + SpellingRichTableCellTarget(:final cellId) => cellId, + _ => throw StateError('Unreachable spelling target.'), + }; + final controller = target is SpellingRichTableCellTarget + ? _tableCellControllers[targetId] + : _textControllers[targetId]; + final currentBlock = _documentController.blockById(targetId); + if (controller == null || currentBlock == null) return null; + final expectedFieldText = busyMarkWysiwygEditableText(currentBlock); + final start = occurrence.fieldStart; + final end = occurrence.fieldEnd; + if (controller.text != expectedFieldText || + start == null || + end == null || + start < 0 || + end < start || + end > expectedFieldText.length || + occurrence.run.text.substring( + occurrence.logicalStart, + occurrence.logicalEnd, + ) != + occurrence.word) { + return null; + } + return expectedFieldText; + } + + bool applyPreparedSpellingCorrection({ + required SpellingOccurrence occurrence, + required String suggestion, + required SpellingReplacementPlan plan, + required String expectedFieldText, + String? preparedFieldText, + }) { + if (!_isSpellingOccurrenceCurrent(occurrence)) return false; + final target = occurrence.run.target; + if (target is! SpellingRichBlockTarget && + target is! SpellingRichTableCellTarget) { + return false; + } + final targetId = switch (target) { + SpellingRichBlockTarget(:final blockId) => blockId, + SpellingRichTableCellTarget(:final cellId) => cellId, + _ => throw StateError('Unreachable spelling target.'), + }; + final controller = target is SpellingRichTableCellTarget + ? _tableCellControllers[targetId] + : _textControllers[targetId]; + final currentBlock = _documentController.blockById(targetId); + final start = occurrence.fieldStart; + if (controller == null || currentBlock == null || start == null) { + return false; + } + // Final guard: no asynchronous operation may occur between this check and + // the structured mutation below. + if (!_isSpellingOccurrenceCurrent(occurrence) || + _documentController.blockById(targetId) != currentBlock || + busyMarkWysiwygEditableText(currentBlock) != expectedFieldText || + controller.text != expectedFieldText) { + return false; + } + final beforeSession = _captureSessionState(); + _continuousTextEdit = null; + _recordUndoSnapshot(); + final changed = switch (target) { + SpellingRichBlockTarget(:final blockId) => + _documentController.replaceSpellingInBlock( + blockId: blockId, + expectedFieldText: expectedFieldText, + plan: plan, + preparedFieldText: preparedFieldText, + ), + SpellingRichTableCellTarget(:final tableBlockId, :final cellId) => + _documentController.replaceSpellingInTableCell( + tableBlockId: tableBlockId, + cellId: cellId, + expectedFieldText: expectedFieldText, + plan: plan, + preparedFieldText: preparedFieldText, + ), + _ => false, + }; + if (!changed) return false; + + _clearBlockSelection(); + if (target is SpellingRichTableCellTarget) { + _setActiveTableCell(target.tableBlockId, target.cellId); + } else { + _setActiveBlock(targetId); + } + final updatedController = target is SpellingRichTableCellTarget + ? _tableCellControllers[targetId] + : _textControllers[targetId]; + if (updatedController != null) { + final caret = (plan.resultingFieldCaret ?? start + suggestion.length) + .clamp(0, updatedController.text.length) + .toInt(); + updatedController.selection = TextSelection.collapsed(offset: caret); + } + final afterSession = _captureSessionState(); + _emitMarkdown( + beforeSpellingSession: beforeSession, + afterSpellingSession: afterSession, + ); + return true; + } + + bool _isSpellingOccurrenceCurrent(SpellingOccurrence occurrence) { + if (!mounted || occurrence.outcome != SpellingCheckOutcome.rejected) { + return false; + } + final snapshot = occurrence.run.snapshot; + if (snapshot.bufferId != _documentId || + (widget.contentRevision != null && + snapshot.contentRevision != widget.contentRevision)) { + return false; + } + return switch (occurrence.run.target) { + SpellingRichBlockTarget(:final documentGeneration) || + SpellingRichTableCellTarget( + :final documentGeneration, + ) => documentGeneration == _documentGeneration, + _ => false, + }; + } + @override void initState() { super.initState(); @@ -325,6 +587,8 @@ class _BusyMarkWysiwygEditorState extends State { _tableCellFocusNodes.clear(); _blockKeys.clear(); _tableCellKeys.clear(); + _spellingEditableKeys.clear(); + _tableCellSpellingEditableKeys.clear(); _pendingInlineKindsByBlockId.clear(); _activeBlockId = null; _activeCellId = null; @@ -439,7 +703,12 @@ class _BusyMarkWysiwygEditorState extends State { intentFor: BusyMarkContextCommandIntent.new, ), commandRegistry[BusyMarkCommandIds.textPaste]!.shortcut!.activator: - const _PasteTextIntent(), + const _PasteTextIntent(BusyMarkPasteMode.normal), + commandRegistry[BusyMarkCommandIds.textPastePlainText]! + .shortcut! + .activator: const _PasteTextIntent( + BusyMarkPasteMode.plainText, + ), commandRegistry[BusyMarkCommandIds.textSelectAll]!.shortcut!.activator: const _SelectAllTextIntent(), commandRegistry['text.undo']!.shortcut!.activator: @@ -476,7 +745,7 @@ class _BusyMarkWysiwygEditorState extends State { ), _PasteTextIntent: CallbackAction<_PasteTextIntent>( onInvoke: (intent) { - unawaited(_pasteIntoActiveBlock()); + unawaited(_pasteFromSystemClipboard(intent.mode)); return null; }, ), @@ -906,6 +1175,11 @@ class _BusyMarkWysiwygEditorState extends State { onFocused: () => _handleBlockFocused(block.id), onCut: _cutCurrentSelection, onCopy: _copyCurrentSelection, + onPaste: () => + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)), + onPastePlainText: () => + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)), + readPasteAvailability: _readContextMenuPasteAvailability, onCopyPlainText: _copyCurrentSelectionAsPlainText, onRefineWithAi: widget.onAiEdit == null ? null @@ -929,6 +1203,31 @@ class _BusyMarkWysiwygEditorState extends State { tableCellUndoController: _textUndoControllerFor, tableCellFocusNode: (cell) => _tableCellFocusNodeFor(block.id, cell), tableCellKey: _tableCellKeyFor, + spellingRanges: _spellingRangesForBlock(block.id), + spellingEditableKey: _spellingEditableKeyFor(block.id), + tableCellSpellingRanges: _spellingRangesForCell, + tableCellSpellingEditableKey: _tableCellSpellingEditableKeyFor, + spellingMenuReader: widget.readSpellingMenuItems == null + ? null + : (offset) => widget.readSpellingMenuItems!( + SpellingRichBlockTarget( + blockId: block.id, + documentGeneration: _documentGeneration, + ), + offset, + ), + tableCellSpellingMenuReader: widget.readSpellingMenuItems == null + ? null + : (cellId) => + (offset) => widget.readSpellingMenuItems!( + SpellingRichTableCellTarget( + tableBlockId: block.id, + cellId: cellId, + documentGeneration: _documentGeneration, + ), + offset, + ), + onCheckSpelling: widget.onCheckSpelling, onTableCellFocused: (cellId) => _handleTableCellFocused(block.id, cellId), onTableRowInserted: (rowIndex, {required after}) => _handleTableRowInserted(block.id, rowIndex, after: after), @@ -1010,11 +1309,21 @@ class _BusyMarkWysiwygEditorState extends State { _blockKeys.remove(id); } } + for (final id in _spellingEditableKeys.keys.toList()) { + if (!ids.contains(id)) { + _spellingEditableKeys.remove(id); + } + } for (final id in _tableCellKeys.keys.toList()) { if (!cellIds.contains(id)) { _tableCellKeys.remove(id); } } + for (final id in _tableCellSpellingEditableKeys.keys.toList()) { + if (!cellIds.contains(id)) { + _tableCellSpellingEditableKeys.remove(id); + } + } for (final id in _pendingInlineKindsByBlockId.keys.toList()) { if (!ids.contains(id)) { _pendingInlineKindsByBlockId.remove(id); @@ -1134,6 +1443,22 @@ class _BusyMarkWysiwygEditorState extends State { return _tableCellKeys.putIfAbsent(cellId, GlobalKey.new); } + GlobalKey _tableCellSpellingEditableKeyFor(String cellId) { + return _tableCellSpellingEditableKeys.putIfAbsent(cellId, GlobalKey.new); + } + + List _spellingRangesForCell(String cellId) => [ + for (final annotation in widget.spellingAnnotations) + if (annotation.target + case SpellingRichTableCellTarget( + cellId: final targetCellId, + :final documentGeneration, + ) + when targetCellId == cellId && + documentGeneration == _documentGeneration) + TextRange(start: annotation.start, end: annotation.end), + ]; + FocusNode _focusNodeFor(BusyBlock block) { final focusNode = _focusNodes.putIfAbsent( block.id, @@ -1447,8 +1772,9 @@ class _BusyMarkWysiwygEditorState extends State { void _handleBlockTextChanged( String documentFilePath, String blockId, - String value, - ) { + String value, { + _WysiwygTextEditOrigin origin = _WysiwygTextEditOrigin.userTyping, + }) { if (documentFilePath != _documentController.document.filePath) { return; } @@ -1468,12 +1794,17 @@ class _BusyMarkWysiwygEditorState extends State { return; } final controller = _textControllers[blockId]; - final undoGroup = _undoGroupForTextEdit( - targetId: blockId, - oldText: oldText, - newText: value, - selection: controller?.selection, - ); + final undoGroup = origin == _WysiwygTextEditOrigin.paste + ? null + : _undoGroupForTextEdit( + targetId: blockId, + oldText: oldText, + newText: value, + selection: controller?.selection, + ); + if (origin == _WysiwygTextEditOrigin.paste) { + _continuousTextEdit = null; + } _recordUndoSnapshot(); final currentBlock = _documentController.blockById(blockId); if (currentBlock != null && @@ -1492,6 +1823,8 @@ class _BusyMarkWysiwygEditorState extends State { blockId, value, offset, + preserveTextWhitespace: origin == _WysiwygTextEditOrigin.paste, + allowListExit: origin != _WysiwygTextEditOrigin.paste, ); if (splitResult != null) { _emitMarkdown(undoGroup: undoGroup); @@ -1502,6 +1835,7 @@ class _BusyMarkWysiwygEditorState extends State { blockId, value, activeInlineKinds: pendingInlineKinds, + preserveTextWhitespace: origin == _WysiwygTextEditOrigin.paste, ); if (value.isNotEmpty) { _pendingInlineKindsByBlockId.remove(blockId); @@ -1704,16 +2038,22 @@ class _BusyMarkWysiwygEditorState extends State { return; } final target = _captureDialogTarget(); + final assets = _ImageAssetTransaction( + service: widget.assetIngestionService, + request: _assetIngestionRequest, + ); final result = await _showImageDialog( context, title: context.l10n.image, initialSource: _imageSourceForBlock(block), initialAlt: block.plainText, submitLabel: context.l10n.apply, + assets: assets, ); if (!_isDialogTargetCurrent(target) || result == null || result.source.trim().isEmpty) { + await assets.rollbackAll(); return; } _recordUndoSnapshot(); @@ -1723,6 +2063,7 @@ class _BusyMarkWysiwygEditorState extends State { alt: result.alt, ); _emitMarkdown(); + await _finalizeAcceptedImageAssets(assets, result.asset); } Future _handleHtmlBlockEditRequested(String blockId) async { @@ -1882,6 +2223,21 @@ class _BusyMarkWysiwygEditorState extends State { if (report == null) { return; } + final session = _captureSessionState(); + final targetDocumentId = documentId ?? _documentId; + if (SchedulerBinding.instance.schedulerPhase == + SchedulerPhase.persistentCallbacks) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + report(targetDocumentId, session); + } + }); + return; + } + report(targetDocumentId, session); + } + + WysiwygEditorSessionState _captureSessionState() { String? anchorBlockId; String? extentBlockId; var anchorOffset = 0; @@ -1919,8 +2275,7 @@ class _BusyMarkWysiwygEditorState extends State { viewportBlockId = _viewportBlockIds[positions.first.index]; viewportAlignment = positions.first.itemLeadingEdge.clamp(0.0, 1.0); } - final targetDocumentId = documentId ?? _documentId; - final session = WysiwygEditorSessionState( + return WysiwygEditorSessionState( activeBlockId: _activeBlockId, activeCellId: _activeCellId, anchorBlockId: anchorBlockId, @@ -1930,16 +2285,6 @@ class _BusyMarkWysiwygEditorState extends State { viewportBlockId: viewportBlockId, viewportAlignment: viewportAlignment, ); - if (SchedulerBinding.instance.schedulerPhase == - SchedulerPhase.persistentCallbacks) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) { - report(targetDocumentId, session); - } - }); - return; - } - report(targetDocumentId, session); } void _scheduleHeadingScroll() { @@ -2160,108 +2505,32 @@ class _BusyMarkWysiwygEditorState extends State { int sourceStart, int sourceEnd, ) { - if (tableSpan.startOffset < 0 || tableSpan.endOffset > source.length) { - return const []; - } - final raw = source.substring(tableSpan.startOffset, tableSpan.endOffset); - final lines = <({String text, int offset})>[]; - var offset = 0; - for (final match in RegExp(r'.*(?:\n|$)').allMatches(raw)) { - var text = match.group(0) ?? ''; - if (text.isEmpty) { - continue; - } - if (text.endsWith('\n')) { - text = text.substring(0, text.length - 1); - } - if (text.endsWith('\r')) { - text = text.substring(0, text.length - 1); - } - lines.add((text: text, offset: offset)); - offset = match.end; - } final targets = <_WysiwygSourceTarget>[]; - for (final (rowIndex, row) in table.children.indexed) { - final lineIndex = rowIndex == 0 ? 0 : rowIndex + 1; - if (lineIndex >= lines.length) { - break; - } - final line = lines[lineIndex]; - final cellSpans = _markdownTableCellSpans(line.text); - for (final (column, cell) in row.children.indexed) { - if (column >= cellSpans.length) { - break; - } - final local = cellSpans[column]; - final span = SourceSpan.fromOffsets( - filePath: tableSpan.filePath, - source: source, - startOffset: tableSpan.startOffset + line.offset + local.start, - endOffset: tableSpan.startOffset + line.offset + local.end, - ); - final visibleRange = _visibleRangeForSourceRange( - source: source, - block: cell, - span: span, - sourceStart: sourceStart, - sourceEnd: sourceEnd, - ); - targets.add( - _WysiwygSourceTarget( - block: cell, - outerBlockId: table.id, - cellId: cell.id, - span: span, - visibleStart: visibleRange?.start ?? 0, - visibleEnd: visibleRange?.end ?? cell.plainText.length, - ), - ); - } + for (final region in busyMarkMarkdownTableCellRegions( + source: source, + table: table.copyWith(sourceSpan: tableSpan), + )) { + final visibleRange = _visibleRangeForSourceRange( + source: source, + block: region.cell, + span: region.span, + sourceStart: sourceStart, + sourceEnd: sourceEnd, + ); + targets.add( + _WysiwygSourceTarget( + block: region.cell, + outerBlockId: table.id, + cellId: region.cell.id, + span: region.span, + visibleStart: visibleRange?.start ?? 0, + visibleEnd: visibleRange?.end ?? region.cell.plainText.length, + ), + ); } return targets; } - List<({int start, int end})> _markdownTableCellSpans(String line) { - final delimiters = []; - var escaped = false; - for (var index = 0; index < line.length; index++) { - final codeUnit = line.codeUnitAt(index); - if (codeUnit == 0x5c && !escaped) { - escaped = true; - continue; - } - if (codeUnit == 0x7c && !escaped) { - delimiters.add(index); - } - escaped = false; - } - final boundaries = [0, ...delimiters, line.length]; - final spans = <({int start, int end})>[]; - for (var index = 0; index < boundaries.length - 1; index++) { - if (index == 0 && delimiters.isNotEmpty && delimiters.first == 0) { - continue; - } - if (index == boundaries.length - 2 && - delimiters.isNotEmpty && - delimiters.last == line.length - 1) { - continue; - } - var start = boundaries[index] + (index == 0 ? 0 : 1); - var end = boundaries[index + 1]; - while (start < end && - (line.codeUnitAt(start) == 0x20 || line.codeUnitAt(start) == 0x09)) { - start++; - } - while (end > start && - (line.codeUnitAt(end - 1) == 0x20 || - line.codeUnitAt(end - 1) == 0x09)) { - end--; - } - spans.add((start: start, end: end)); - } - return spans; - } - ({int start, int end})? _visibleRangeForSourceRange({ required String source, required BusyBlock block, @@ -2550,12 +2819,20 @@ class _BusyMarkWysiwygEditorState extends State { _cutCurrentSelection()) { return KeyEventResult.handled; } + if (commands.shortcutAccepts( + BusyMarkCommandIds.textPastePlainText, + event, + keyboard, + )) { + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)); + return KeyEventResult.handled; + } if (commands.shortcutAccepts( BusyMarkCommandIds.textPaste, event, keyboard, )) { - unawaited(_pasteIntoActiveBlock()); + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)); return KeyEventResult.handled; } if (commands.shortcutAccepts( @@ -2810,12 +3087,20 @@ class _BusyMarkWysiwygEditorState extends State { ? KeyEventResult.handled : KeyEventResult.ignored; } + if (commands.shortcutAccepts( + BusyMarkCommandIds.textPastePlainText, + event, + keyboard, + )) { + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)); + return KeyEventResult.handled; + } if (commands.shortcutAccepts( BusyMarkCommandIds.textPaste, event, keyboard, )) { - unawaited(_pasteIntoActiveBlock()); + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)); return KeyEventResult.handled; } if (commands.shortcutAccepts( @@ -3400,7 +3685,12 @@ class _BusyMarkWysiwygEditorState extends State { void _focusBlockAfterFrame(String blockId, {required int offset}) { _activeBlockId = blockId; + final pending = _PendingTextFocus(targetId: blockId, offset: offset); + _pendingTextFocus = pending; WidgetsBinding.instance.addPostFrameCallback((_) { + if (identical(_pendingTextFocus, pending)) { + _pendingTextFocus = null; + } if (!mounted) { return; } @@ -3425,7 +3715,12 @@ class _BusyMarkWysiwygEditorState extends State { } _activeBlockId = cellEntry.table.id; _activeCellId = targetId; + final pending = _PendingTextFocus(targetId: targetId, offset: offset); + _pendingTextFocus = pending; WidgetsBinding.instance.addPostFrameCallback((_) { + if (identical(_pendingTextFocus, pending)) { + _pendingTextFocus = null; + } if (!mounted) { return; } @@ -3441,6 +3736,24 @@ class _BusyMarkWysiwygEditorState extends State { }); } + void _requestEditorFocusAfterHistoryPaste() { + final pending = _pendingTextFocus; + if (pending != null) { + _focusTextTargetAfterFrame(pending.targetId, offset: pending.offset); + return; + } + final target = _activeTextTarget(); + final targetId = target?.targetId ?? _activeBlockId; + if (targetId == null) return; + _focusTextTargetAfterFrame( + targetId, + offset: + target?.controller.selection.extentOffset ?? + target?.controller.text.length ?? + 0, + ); + } + List _focusableBlocks() { return [ for (final block in _editableBlocks(_documentController.document.blocks)) @@ -3812,17 +4125,26 @@ class _BusyMarkWysiwygEditorState extends State { } bool _canApplyContextCommand(String commandId) { + if ((commandId == BusyMarkCommandIds.textPaste || + commandId == BusyMarkCommandIds.textPastePlainText) && + _hasActiveClipboardComposition) { + return false; + } if (commandId.startsWith('editor.')) { final name = commandId.substring('editor.'.length); return BusyMarkEditorShortcutAction.values.any( (action) => action.name == name, ); } + if (commandId == BusyMarkCommandIds.checkSpelling) { + return widget.onCheckSpelling != null; + } return switch (commandId) { BusyMarkCommandIds.textSelectAll || BusyMarkCommandIds.textCut || BusyMarkCommandIds.textCopy || BusyMarkCommandIds.textPaste || + BusyMarkCommandIds.textPastePlainText || 'text.undo' || 'text.redo' => true, _ => false, @@ -3830,6 +4152,10 @@ class _BusyMarkWysiwygEditorState extends State { } void _applyContextCommand(String commandId) { + if (commandId == BusyMarkCommandIds.checkSpelling) { + widget.onCheckSpelling?.call(); + return; + } if (commandId.startsWith('editor.')) { final name = commandId.substring('editor.'.length); final action = BusyMarkEditorShortcutAction.values @@ -3848,7 +4174,9 @@ class _BusyMarkWysiwygEditorState extends State { case BusyMarkCommandIds.textCopy: _copyCurrentSelection(); case BusyMarkCommandIds.textPaste: - unawaited(_pasteIntoActiveBlock()); + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)); + case BusyMarkCommandIds.textPastePlainText: + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)); case 'text.undo': if (widget.useExternalUndoHistory || !_undoEditorChange()) { widget.onUndo?.call(); @@ -4139,14 +4467,20 @@ class _BusyMarkWysiwygEditorState extends State { return; } final target = _captureDialogTarget(); + final assets = _ImageAssetTransaction( + service: widget.assetIngestionService, + request: _assetIngestionRequest, + ); final result = await _showImageDialog( context, title: context.l10n.image, submitLabel: context.l10n.insert, + assets: assets, ); if (!_isDialogTargetCurrent(target) || result == null || result.source.trim().isEmpty) { + await assets.rollbackAll(); return; } _recordUndoSnapshot(); @@ -4156,167 +4490,381 @@ class _BusyMarkWysiwygEditorState extends State { alt: result.alt, ); _emitMarkdown(); + await _finalizeAcceptedImageAssets(assets, result.asset); } - Future _pasteIntoActiveBlock() async { + Future _pasteFromSystemClipboard( + BusyMarkPasteMode mode, + ) async { + if (_hasActiveClipboardComposition) { + return ClipboardPasteResult.staleTarget; + } + final onCaptured = widget.onClipboardCaptured; final target = _captureClipboardTarget(); final data = await _clipboard.read(); - if (!_isClipboardTargetCurrent(target)) return; - var fragment = data.richFragment == null - ? null - : WysiwygClipboardFragment.decode(data.richFragment!); - fragment ??= data.html == null - ? null - : const WysiwygClipboardHtml().decode( - data.html!, - mode: _documentController.document.mode, - ); - if (fragment != null) { - fragment = fragment.rebase(_documentController.document.filePath); - if (_pasteStyledClipboardIntoActiveBlock( - fragment.blocks, - data.text ?? - fragment.documentBlocks.map(_copyTextForBlock).join('\n\n'), - )) { - _retainExternalClipboardData(data, fragment: fragment); - return; - } - } - final text = data.text; - if (text != null && text.isNotEmpty) { - final filePath = _localFilePathFromClipboardText(text); - if (filePath != null && - await _ingestExternalImageFile( - filePath, - AssetIngestionOrigin.clipboardImageFile, - reportInvalidImage: false, - clipboardTarget: target, - onInserted: data.sessionOwned - ? null - : (bytes) => _retainExternalImageSnapshot(filePath, bytes), - )) { - return; - } - if (_isClipboardTargetCurrent(target)) { - final inserted = await _pastePlainTextIntoActiveBlock( - textOverride: text, - ); - if (inserted) _retainExternalClipboardData(data); - } - return; - } - final assetInput = widget.assetInputService ?? busyMarkAssetInputService; - final clipboardFiles = await assetInput.readClipboardImageFiles(); - if (!_isClipboardTargetCurrent(target)) return; - if (clipboardFiles.isNotEmpty && - await _ingestExternalImageFile( - clipboardFiles.first, - AssetIngestionOrigin.clipboardImageFile, - clipboardTarget: target, - onInserted: (bytes) => - _retainExternalImageSnapshot(clipboardFiles.first, bytes), - )) { - return; + if (!_isClipboardTargetCurrent(target)) { + return ClipboardPasteResult.staleTarget; } - final png = await assetInput.readClipboardImagePng(); - if (!_isClipboardTargetCurrent(target)) return; - if (png != null && png.isNotEmpty) { - final inserted = await _ingestExternalImageBytes( - png, - suggestedFileName: - 'screenshot-${DateTime.now().millisecondsSinceEpoch}.png', - origin: AssetIngestionOrigin.screenshotPaste, - clipboardTarget: target, + final snapshot = BusyMarkClipboardSnapshot.fromSystem(data); + final outcome = await _pasteClipboardSnapshot( + snapshot, + mode: mode, + target: target, + systemIdentity: data, + ); + if (outcome.result == ClipboardPasteResult.inserted && snapshot.external) { + onCaptured?.call( + outcome.capture ?? busyMarkClipboardCaptureFromSnapshot(snapshot), ); - if (inserted) { - widget.onClipboardCaptured?.call( - BusyMarkClipboardCapture( - kind: BusyMarkClipboardContentKind.image, - imageBytes: png, - imageMimeType: 'image/png', - imageDisplayName: - 'screenshot-${DateTime.now().millisecondsSinceEpoch}.png', - origin: _clipboardOrigin, - external: true, - ), - ); - } } + return outcome.result; } - void _retainExternalClipboardData( - RichClipboardData data, { - WysiwygClipboardFragment? fragment, - }) { - if (data.sessionOwned) return; - final text = data.text; - final source = fragment?.markdown ?? data.sourceText ?? text; - widget.onClipboardCaptured?.call( - BusyMarkClipboardCapture( - kind: fragment == null - ? BusyMarkClipboardContentKind.text - : BusyMarkClipboardContentKind.richText, - text: text, - sourceText: source, - html: data.html, - richFragment: fragment?.encode() ?? data.richFragment, - origin: _clipboardOrigin, - external: true, - ), - ); - } - - void _retainExternalImageSnapshot(String path, Uint8List bytes) { - widget.onClipboardCaptured?.call( - BusyMarkClipboardCapture( - kind: BusyMarkClipboardContentKind.image, - imageBytes: bytes, - imageMimeType: _clipboardImageMimeType(path), - imageDisplayName: p.basename(path), - origin: _clipboardOrigin, - external: true, - ), + Future + _readContextMenuPasteAvailability() async { + final target = _captureClipboardTarget(); + final first = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target)) { + return BusyMarkEditorTextPasteAvailability.unavailable; + } + final snapshot = BusyMarkClipboardSnapshot.fromSystem(first); + const resolver = BusyMarkClipboardPasteResolver(); + final plainText = resolver + .resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.plainText, + destination: BusyMarkPasteDestination.editor, + markdownMode: _documentController.document.mode, + ) + .candidates + .isNotEmpty; + final normalPlan = resolver.resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.normal, + destination: BusyMarkPasteDestination.editor, + markdownMode: _documentController.document.mode, + ); + var normal = normalPlan.candidates.any( + (candidate) => + candidate is! BusyMarkNativeImagePasteCandidate && + _canPrepareSystemPasteCandidate(snapshot, candidate), + ); + if (!normal && + normalPlan.candidates.any( + (candidate) => candidate is BusyMarkNativeImagePasteCandidate, + )) { + final input = widget.assetInputService ?? busyMarkAssetInputService; + final files = await input.readClipboardImageFiles(); + Uint8List? png; + if (files.isEmpty) png = await input.readClipboardImagePng(); + final second = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target)) { + return BusyMarkEditorTextPasteAvailability.unavailable; + } + normal = + first.sameExternalIdentity(second) && + (files.isNotEmpty || (png != null && png.isNotEmpty)); + } + return BusyMarkEditorTextPasteAvailability( + normal: normal, + plainText: plainText, ); } - bool _pasteStyledClipboardIntoActiveBlock( - List blocks, - String text, + bool _canPrepareSystemPasteCandidate( + BusyMarkClipboardSnapshot snapshot, + BusyMarkPasteCandidate candidate, ) { - if (_hasBlockSelection) { - return _replaceDocumentSelectionWithStyledBlocks(blocks); + if (candidate is BusyMarkImagePasteCandidate) { + return widget.assetIngestionService.canIngestMediaBytes( + bytes: candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + ); } - if (_activeCellId != null) { - return _replaceActiveTableCellSelection(text, styledBlocks: blocks); + if (candidate is! BusyMarkStructuredPasteCandidate || + candidate.fragment.mediaPaths.isEmpty) { + return true; } - final target = _activeTextTarget(); - if (target == null) { - return false; + return snapshot.mediaComplete && + candidate.fragment.mediaPaths.entries.every((entry) { + final bytes = snapshot.mediaBytes[entry.key]; + return bytes != null && + widget.assetIngestionService.canIngestMediaBytes( + bytes: bytes, + suggestedFileName: p.basename(entry.value), + ); + }); + } + + Future<({ClipboardPasteResult result, BusyMarkClipboardCapture? capture})> + _pasteClipboardSnapshot( + BusyMarkClipboardSnapshot snapshot, { + required BusyMarkPasteMode mode, + required _ClipboardTarget target, + RichClipboardData? systemIdentity, + }) async { + final plan = const BusyMarkClipboardPasteResolver().resolve( + snapshot: snapshot, + mode: mode, + destination: BusyMarkPasteDestination.editor, + markdownMode: _documentController.document.mode, + ); + if (plan.isEmpty) { + return (result: ClipboardPasteResult.unsupported, capture: null); } - final blockId = target.targetId; - final controller = target.controller; - final currentText = controller.text; - final selection = controller.selection.isValid - ? controller.selection - : TextSelection.collapsed(offset: currentText.length); - final start = math - .min(selection.start, selection.end) + for (final candidate in plan.candidates) { + if (!_isClipboardTargetCurrent(target)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + if (candidate is BusyMarkStructuredPasteCandidate) { + final decoded = candidate.fragment; + var fragment = decoded.rebase(_documentController.document.filePath); + var assets = const []; + if (decoded.mediaPaths.isNotEmpty) { + if (!snapshot.mediaComplete) continue; + final prepared = await _prepareRetainedClipboardMedia( + decoded, + snapshot, + target, + ); + if (prepared == null) { + if (!_isClipboardTargetCurrent(target)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + continue; + } + fragment = prepared.fragment; + assets = prepared.assets; + } + if (!_isClipboardTargetCurrent(target)) { + await _deleteUncommittedClipboardAssets(assets); + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + final inserted = _pasteStyledClipboardIntoActiveBlock( + fragment.blocks, + snapshot.text ?? + fragment.documentBlocks.map(_copyTextForBlock).join('\n\n'), + fragment: fragment, + ); + if (inserted) { + await _finalizeInsertedClipboardAssets(assets); + return (result: ClipboardPasteResult.inserted, capture: null); + } + await _deleteUncommittedClipboardAssets(assets); + continue; + } + if (candidate is BusyMarkImagePasteCandidate) { + final result = await _ingestExternalImageBytes( + candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + origin: AssetIngestionOrigin.screenshotPaste, + clipboardTarget: target, + ); + if (result == ClipboardPasteResult.inserted) { + return (result: ClipboardPasteResult.inserted, capture: null); + } + if (result == ClipboardPasteResult.cancelled || + result == ClipboardPasteResult.staleTarget) { + return (result: result, capture: null); + } + continue; + } + if (candidate is BusyMarkNativeImagePasteCandidate) { + final native = await _pasteNativeClipboardImage( + target, + systemIdentity!, + ); + return (result: native.result, capture: native.capture); + } + final text = switch (candidate) { + BusyMarkPlainTextPasteCandidate() => candidate.text, + BusyMarkSourceTextPasteCandidate() => candidate.text, + _ => null, + }; + if (text == null) continue; + if (mode == BusyMarkPasteMode.normal && + candidate is BusyMarkPlainTextPasteCandidate) { + final filePath = busyMarkLocalImagePathFromClipboardText(text); + if (filePath != null) { + final image = await _ingestExternalImageFile( + filePath, + AssetIngestionOrigin.clipboardImageFile, + reportInvalidImage: false, + clipboardTarget: target, + ); + if (image.result == ClipboardPasteResult.inserted) { + return ( + result: ClipboardPasteResult.inserted, + capture: image.bytes == null + ? null + : busyMarkClipboardCaptureFromSnapshot( + snapshot, + imageBytes: image.bytes, + imageMimeType: _clipboardImageMimeType(filePath), + imageDisplayName: p.basename(filePath), + ), + ); + } + if (image.result == ClipboardPasteResult.cancelled || + image.result == ClipboardPasteResult.staleTarget) { + return (result: image.result, capture: null); + } + } + } + if (await _pastePlainTextIntoActiveBlock(target, text)) { + return (result: ClipboardPasteResult.inserted, capture: null); + } + } + return ( + result: _isClipboardTargetCurrent(target) + ? ClipboardPasteResult.unsupported + : ClipboardPasteResult.staleTarget, + capture: null, + ); + } + + Future<({ClipboardPasteResult result, BusyMarkClipboardCapture? capture})> + _pasteNativeClipboardImage( + _ClipboardTarget target, + RichClipboardData first, + ) async { + final assetInput = widget.assetInputService ?? busyMarkAssetInputService; + final files = await assetInput.readClipboardImageFiles(); + Uint8List? png; + if (files.isEmpty) png = await assetInput.readClipboardImagePng(); + final second = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target) || + !first.sameExternalIdentity(second)) { + return (result: ClipboardPasteResult.staleTarget, capture: null); + } + if (files.isNotEmpty) { + final image = await _ingestExternalImageFile( + files.first, + AssetIngestionOrigin.clipboardImageFile, + clipboardTarget: target, + ); + return ( + result: image.result, + capture: + image.result == ClipboardPasteResult.inserted && image.bytes != null + ? busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromSystem(first), + imageBytes: image.bytes, + imageMimeType: _clipboardImageMimeType(files.first), + imageDisplayName: p.basename(files.first), + ) + : null, + ); + } + if (png == null || png.isEmpty) { + return (result: ClipboardPasteResult.unsupported, capture: null); + } + final name = 'screenshot-${DateTime.now().millisecondsSinceEpoch}.png'; + final result = await _ingestExternalImageBytes( + png, + suggestedFileName: name, + origin: AssetIngestionOrigin.screenshotPaste, + clipboardTarget: target, + ); + return ( + result: result, + capture: result == ClipboardPasteResult.inserted + ? busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromSystem(first), + imageBytes: png, + imageMimeType: 'image/png', + imageDisplayName: name, + ) + : null, + ); + } + + bool _pasteStyledClipboardIntoActiveBlock( + List blocks, + String text, { + WysiwygClipboardFragment? fragment, + }) { + if (_hasActiveClipboardComposition) return false; + if (_hasBlockSelection) { + return _replaceDocumentSelectionWithStyledBlocks(blocks); + } + if (_activeCellId != null) { + return _replaceActiveTableCellSelection( + text, + styledBlocks: blocks, + origin: _WysiwygTextEditOrigin.paste, + ); + } + final target = _activeTextTarget(); + if (target == null || _hasActiveComposition(target.controller)) { + return false; + } + final blockId = target.targetId; + final controller = target.controller; + final currentText = controller.text; + final selection = controller.selection.isValid + ? controller.selection + : TextSelection.collapsed(offset: currentText.length); + final start = math + .min(selection.start, selection.end) .clamp(0, currentText.length) .toInt(); final end = math .max(selection.start, selection.end) .clamp(start, currentText.length) .toInt(); + if (busyMarkWysiwygBlockContainsMath(target.block)) { + final sourceFragment = + fragment ?? + WysiwygClipboardFragment( + blocks: blocks, + mode: _documentController.document.mode, + sourcePath: _documentController.document.filePath, + ); + final preparation = const SourcePasteEngine().prepareStructured( + target: SourcePasteDocumentSnapshot( + expectedSource: currentText, + selection: TextSelection(baseOffset: start, extentOffset: end), + format: SourceDocumentFormat.markdown, + markdownMode: _documentController.document.mode, + filePath: _documentController.document.filePath, + ), + fragment: sourceFragment, + ); + if (preparation is! SourcePasteReady) return false; + final edit = preparation.edit; + final updatedSource = currentText.replaceRange( + edit.start, + edit.end, + edit.replacement, + ); + final undoSnapshot = _historySnapshot(); + final destination = _documentController.updateMathSource( + blockId, + updatedSource, + sourceCaretOffset: edit.caretOffset, + replacementScope: BusyWysiwygReplacementScope.fieldContent, + ); + if (destination == null) return false; + _continuousTextEdit = null; + _recordUndoSnapshot(undoSnapshot); + _clearBlockSelection(collapseFields: false); + _emitMarkdown(); + _focusBlockAfterFrame(destination.blockId, offset: destination.offset); + return true; + } final undoSnapshot = _historySnapshot(); final result = _documentController.insertStyledBlocksAtSelection( blockId: blockId, selectionStart: start, selectionEnd: end, blocks: blocks, + replacementScope: BusyWysiwygReplacementScope.fieldContent, ); if (result == null) { return false; } + _continuousTextEdit = null; _recordUndoSnapshot(undoSnapshot); _clearBlockSelection(collapseFields: false); _emitMarkdown(); @@ -4324,25 +4872,32 @@ class _BusyMarkWysiwygEditorState extends State { return true; } - Future _pastePlainTextIntoActiveBlock({String? textOverride}) async { - final captured = _captureClipboardTarget(); - final text = textOverride ?? await _clipboard.readPlainText(); - if (!_isClipboardTargetCurrent(captured) || text == null || text.isEmpty) { + Future _pastePlainTextIntoActiveBlock( + _ClipboardTarget captured, + String text, + ) async { + if (!_isClipboardTargetCurrent(captured) || text.isEmpty) { return false; } + if (_hasBlockSelection && + _replaceDocumentSelectionWithText( + text, + origin: _WysiwygTextEditOrigin.paste, + )) { + return true; + } + if (_activeCellId != null) { + return _replaceActiveTableCellSelection( + text, + origin: _WysiwygTextEditOrigin.paste, + ); + } final target = _activeTextTarget(); - if (target == null) { + if (target == null || _hasActiveComposition(target.controller)) { return false; } final blockId = target.targetId; final controller = target.controller; - if (_activeCellId != null) { - _replaceActiveTableCellSelection(text); - return true; - } - if (_hasBlockSelection && _replaceDocumentSelectionWithText(text)) { - return true; - } final currentText = controller.text; final selection = controller.selection.isValid ? controller.selection @@ -4364,6 +4919,7 @@ class _BusyMarkWysiwygEditorState extends State { _documentController.document.filePath, blockId, nextText, + origin: _WysiwygTextEditOrigin.paste, ); return true; } @@ -4371,6 +4927,7 @@ class _BusyMarkWysiwygEditorState extends State { bool _replaceActiveTableCellSelection( String replacement, { List? styledBlocks, + _WysiwygTextEditOrigin origin = _WysiwygTextEditOrigin.userTyping, }) { final cellId = _activeCellId; final tableId = _activeBlockId; @@ -4403,6 +4960,9 @@ class _BusyMarkWysiwygEditorState extends State { blocks: styledBlocks, ); if (offset == null) return false; + if (origin == _WysiwygTextEditOrigin.paste) { + _continuousTextEdit = null; + } _recordUndoSnapshot(undoSnapshot); _emitMarkdown(); _focusTextTargetAfterFrame(cellId, offset: offset); @@ -4414,6 +4974,9 @@ class _BusyMarkWysiwygEditorState extends State { end, acceptedReplacement, ); + if (origin == _WysiwygTextEditOrigin.paste) { + _continuousTextEdit = null; + } _recordUndoSnapshot(); _updateTableCellFromControllerText(tableId, cellId, nextText); _emitMarkdown(); @@ -4483,15 +5046,21 @@ class _BusyMarkWysiwygEditorState extends State { final insertLabel = context.l10n.insert; final fallbackAltText = context.l10n.image; final target = _captureDialogTarget(); + final assets = _ImageAssetTransaction( + service: widget.assetIngestionService, + request: _assetIngestionRequest, + ); final result = await _showImageDialog( context, title: dialogTitle, initialAlt: initialAlt, submitLabel: insertLabel, + assets: assets, ); if (!_isDialogTargetCurrent(target) || result == null || result.source.trim().isEmpty) { + await assets.rollbackAll(); return; } if (selectedRanges.isNotEmpty) { @@ -4508,6 +5077,7 @@ class _BusyMarkWysiwygEditorState extends State { } _clearBlockSelection(); _emitMarkdown(); + await _finalizeAcceptedImageAssets(assets, result.asset); return; } final selection = activeSelection!; @@ -4521,6 +5091,7 @@ class _BusyMarkWysiwygEditorState extends State { fallbackAltText: fallbackAltText, ); _emitMarkdown(); + await _finalizeAcceptedImageAssets(assets, result.asset); } Future _applyTableCommand() async { @@ -4807,7 +5378,10 @@ class _BusyMarkWysiwygEditorState extends State { String initialSource = '', String initialAlt = '', required String submitLabel, + required _ImageAssetTransaction assets, + IngestedAsset? initialAsset, }) { + if (initialAsset != null) assets.register(initialAsset); return _showEditorDialog<_ImageDialogResult>( context, builder: (context) => _ImageDialog( @@ -4815,19 +5389,30 @@ class _BusyMarkWysiwygEditorState extends State { initialSource: initialSource, initialAlt: initialAlt, submitLabel: submitLabel, - ingestSelectedImage: _ingestSelectedImage, + initialAsset: initialAsset, + ingestSelectedImage: assets.ingestSelectedImage, + findSelectedAsset: assets.assetForMarkdownPath, onSaveRequired: widget.onAssetSaveRequired, ), ); } - Future _ingestSelectedImage(String sourcePath) async { - final asset = await widget.assetIngestionService.ingestFile( - sourcePath: sourcePath, - request: _assetIngestionRequest, - origin: AssetIngestionOrigin.imagePicker, - ); - return asset.markdownPath; + Future _finalizeAcceptedImageAssets( + _ImageAssetTransaction assets, + IngestedAsset? selected, + ) async { + try { + await assets.commitSelected(selected); + } on Object catch (error) { + if (!mounted) return; + BusyMarkToastOverlay.show( + context, + message: error is AssetIngestionException + ? error.message + : context.l10n.clipboardUnavailable, + priority: BusyMarkToastPriority.high, + ); + } } AssetIngestionRequest get _assetIngestionRequest => AssetIngestionRequest( @@ -4860,22 +5445,12 @@ class _BusyMarkWysiwygEditorState extends State { } } - String? _localFilePathFromClipboardText(String value) { - final trimmed = value.trim(); - if (trimmed.contains('\n') || trimmed.contains('\r')) { - return null; - } - final uri = Uri.tryParse(trimmed); - final candidate = uri?.scheme == 'file' ? File.fromUri(uri!).path : trimmed; - return File(candidate).existsSync() ? candidate : null; - } - - Future _ingestExternalImageFile( + Future<({ClipboardPasteResult result, Uint8List? bytes})> + _ingestExternalImageFile( String sourcePath, AssetIngestionOrigin origin, { bool reportInvalidImage = true, _ClipboardTarget? clipboardTarget, - ValueChanged? onInserted, }) async { try { final snapshot = await widget.assetIngestionService.ingestFileSnapshot( @@ -4883,16 +5458,25 @@ class _BusyMarkWysiwygEditorState extends State { request: _assetIngestionRequest, origin: origin, ); - final inserted = await _requestAltAndInsertAsset( + final result = await _requestAltAndInsertAsset( snapshot.asset, suggestedAlt: p.basenameWithoutExtension(sourcePath), clipboardTarget: clipboardTarget, ); - if (inserted) onInserted?.call(snapshot.bytes); - return inserted; + return ( + result: result, + bytes: result == ClipboardPasteResult.inserted ? snapshot.bytes : null, + ); } on AssetSaveRequiredException { widget.onAssetSaveRequired?.call(); - return false; + return ( + result: + clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported, + bytes: null, + ); } on AssetIngestionException catch (error) { if (reportInvalidImage && mounted) { BusyMarkToastOverlay.show( @@ -4901,13 +5485,27 @@ class _BusyMarkWysiwygEditorState extends State { priority: BusyMarkToastPriority.high, ); } - return false; + return ( + result: + clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported, + bytes: null, + ); } on FileSystemException { - return false; + return ( + result: + clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported, + bytes: null, + ); } } - Future _ingestExternalImageBytes( + Future _ingestExternalImageBytes( Uint8List bytes, { required String suggestedFileName, required AssetIngestionOrigin origin, @@ -4928,7 +5526,10 @@ class _BusyMarkWysiwygEditorState extends State { ); } on AssetSaveRequiredException { widget.onAssetSaveRequired?.call(); - return false; + return clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported; } on AssetIngestionException catch (error) { if (mounted) { BusyMarkToastOverlay.show( @@ -4937,11 +5538,26 @@ class _BusyMarkWysiwygEditorState extends State { priority: BusyMarkToastPriority.high, ); } - return false; + return clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported; + } on FileSystemException { + if (mounted) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.clipboardUnavailable, + priority: BusyMarkToastPriority.high, + ); + } + return clipboardTarget != null && + !_isClipboardTargetCurrent(clipboardTarget) + ? ClipboardPasteResult.staleTarget + : ClipboardPasteResult.unsupported; } } - Future _requestAltAndInsertAsset( + Future _requestAltAndInsertAsset( IngestedAsset asset, { required String suggestedAlt, _ClipboardTarget? clipboardTarget, @@ -4950,53 +5566,76 @@ class _BusyMarkWysiwygEditorState extends State { (clipboardTarget != null && !_isClipboardTargetCurrent(clipboardTarget))) { await _deleteUncommittedClipboardAsset(asset); - return false; + return ClipboardPasteResult.staleTarget; } final fallbackAltText = context.l10n.image; final target = _captureDialogTarget(); + final assets = _ImageAssetTransaction( + service: widget.assetIngestionService, + request: _assetIngestionRequest, + ); final result = await _showImageDialog( context, title: context.l10n.image, initialSource: asset.markdownPath, initialAlt: suggestedAlt, submitLabel: context.l10n.insert, + assets: assets, + initialAsset: asset, ); if (!_isDialogTargetCurrent(target) || (clipboardTarget != null && - !_isClipboardTargetCurrent(clipboardTarget)) || - result == null) { - await _deleteUncommittedClipboardAsset(asset); - return false; + !_isClipboardTargetCurrent(clipboardTarget))) { + await assets.rollbackAll(); + return ClipboardPasteResult.staleTarget; } - final blockId = _activeBlockId; - final controller = blockId == null ? null : _textControllers[blockId]; - if (blockId == null || controller == null) { - await _deleteUncommittedClipboardAsset(asset); - return false; + if (result == null) { + await assets.rollbackAll(); + return ClipboardPasteResult.cancelled; + } + final alt = result.alt.trim().isEmpty ? fallbackAltText : result.alt.trim(); + final inserted = _pasteStyledClipboardIntoActiveBlock([ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: alt, + ranges: [ + BusyInlineStyleRange( + start: 0, + end: alt.length, + kind: BusyInlineKind.image, + destination: result.source, + ), + ], + ), + ], alt); + if (!inserted) { + await assets.rollbackAll(); + return ClipboardPasteResult.unsupported; } - final selection = controller.selection.isValid - ? controller.selection - : TextSelection.collapsed(offset: controller.text.length); - _recordUndoSnapshot(); - _documentController.insertInlineImage( - blockId, - selectionStart: selection.start, - selectionEnd: selection.end, - source: result.source, - alt: result.alt, - fallbackAltText: fallbackAltText, - ); - _emitMarkdown(); - return true; + unawaited(_finalizeAcceptedImageAssets(assets, result.asset)); + return ClipboardPasteResult.inserted; } Future _deleteUncommittedClipboardAsset(IngestedAsset asset) async { - if (asset.reusedExisting) return; + await widget.assetIngestionService.rollback(asset); + } + + Future _finalizeInsertedClipboardAssets( + Iterable assets, + ) async { try { - await File(asset.absolutePath).delete(); - } on FileSystemException { - // Cancellation cleanup must not make the editor unusable. Existing and - // shared assets are never removed through this path. + await widget.assetIngestionService.commitAll(assets); + } on Object catch (error) { + // The document already references these paths. Leave any failed pending + // record in place so the bytes remain protected from reuse or rollback. + if (!mounted) return; + BusyMarkToastOverlay.show( + context, + message: error is AssetIngestionException + ? error.message + : context.l10n.clipboardUnavailable, + priority: BusyMarkToastPriority.high, + ); } } @@ -5151,7 +5790,11 @@ class _BusyMarkWysiwygEditorState extends State { return group; } - void _emitMarkdown({String? undoGroup}) { + void _emitMarkdown({ + String? undoGroup, + WysiwygEditorSessionState? beforeSpellingSession, + WysiwygEditorSessionState? afterSpellingSession, + }) { if (undoGroup == null) { _continuousTextEdit = null; } @@ -5160,15 +5803,27 @@ class _BusyMarkWysiwygEditorState extends State { widget.onDocumentChanged?.call( _documentController.document.copyWith(source: markdown), ); - final transactionalCallback = widget.onTransactionalSourceChanged; - if (transactionalCallback != null) { - transactionalCallback( + final spellingCallback = widget.onSpellingSourceChanged; + if (spellingCallback != null && + beforeSpellingSession != null && + afterSpellingSession != null) { + spellingCallback( _documentController.document.filePath, markdown, - undoGroup, + beforeSpellingSession, + afterSpellingSession, ); } else { - widget.onSourceChanged(_documentController.document.filePath, markdown); + final transactionalCallback = widget.onTransactionalSourceChanged; + if (transactionalCallback != null) { + transactionalCallback( + _documentController.document.filePath, + markdown, + undoGroup, + ); + } else { + widget.onSourceChanged(_documentController.document.filePath, markdown); + } } WidgetsBinding.instance.addPostFrameCallback((_) { _internalChange = false; @@ -5571,6 +6226,22 @@ class _BusyMarkWysiwygEditorState extends State { return _blockKeys.putIfAbsent(blockId, GlobalKey.new); } + GlobalKey _spellingEditableKeyFor(String blockId) { + return _spellingEditableKeys.putIfAbsent(blockId, GlobalKey.new); + } + + List _spellingRangesForBlock(String blockId) => [ + for (final annotation in widget.spellingAnnotations) + if (annotation.target + case SpellingRichBlockTarget( + blockId: final targetBlockId, + :final documentGeneration, + ) + when targetBlockId == blockId && + documentGeneration == _documentGeneration) + TextRange(start: annotation.start, end: annotation.end), + ]; + Set _selectedBlockIds(List blocks) { final selection = _documentSelection; if (selection == null) { @@ -5790,6 +6461,12 @@ class _BusyMarkWysiwygEditorState extends State { Offset position, _DocumentTextSelection snapshot, ) async { + _preserveSelectionFocusCallbacks = math.max( + _preserveSelectionFocusCallbacks, + 4, + ); + final pasteAvailability = await _readContextMenuPasteAvailability(); + if (!mounted || snapshot != _documentSelection) return; final commands = BusyMarkCommandRegistryScope.maybeOf(context) ?? BusyMarkCommandCatalog.metadata; @@ -5827,11 +6504,18 @@ class _BusyMarkWysiwygEditorState extends State { BusyMarkCommandIds.editorCopyPlainText, BusyMarkGlyphs.copy, ), - item( - _DocumentSelectionMenuAction.paste, - BusyMarkCommandIds.textPaste, - BusyMarkGlyphs.paste, - ), + if (pasteAvailability.normal) + item( + _DocumentSelectionMenuAction.paste, + BusyMarkCommandIds.textPaste, + BusyMarkGlyphs.paste, + ), + if (pasteAvailability.plainText) + item( + _DocumentSelectionMenuAction.pastePlainText, + BusyMarkCommandIds.textPastePlainText, + BusyMarkGlyphs.paste, + ), item( _DocumentSelectionMenuAction.selectAll, BusyMarkCommandIds.textSelectAll, @@ -5867,7 +6551,9 @@ class _BusyMarkWysiwygEditorState extends State { case _DocumentSelectionMenuAction.copyPlainText: _copyCurrentSelectionAsPlainText(); case _DocumentSelectionMenuAction.paste: - unawaited(_pasteIntoActiveBlock()); + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.normal)); + case _DocumentSelectionMenuAction.pastePlainText: + unawaited(_pasteFromSystemClipboard(BusyMarkPasteMode.plainText)); case _DocumentSelectionMenuAction.selectAll: _selectWholeDocumentText(); case _DocumentSelectionMenuAction.refineWithAi: @@ -6115,7 +6801,10 @@ class _BusyMarkWysiwygEditorState extends State { return true; } - bool _replaceDocumentSelectionWithText(String replacementText) { + bool _replaceDocumentSelectionWithText( + String replacementText, { + _WysiwygTextEditOrigin origin = _WysiwygTextEditOrigin.userTyping, + }) { final ranges = _selectedTextRanges(null, true); if (ranges.isEmpty) { return false; @@ -6129,48 +6818,31 @@ class _BusyMarkWysiwygEditorState extends State { .replaceAll('\r\n', '\n') .replaceAll('\r', '\n'); final activeInlineKinds = _activeInlineKindsAt(first.block.id, first.start); - _recordUndoSnapshot(); - final deletion = _documentController.deleteTextSelection( + final undoSnapshot = _historySnapshot(); + final result = _documentController.replaceTextSelectionWithText( firstBlockId: first.block.id, firstStartOffset: first.start, lastBlockId: last.block.id, lastEndOffset: last.end, removedBlockIds: ranges.map((range) => range.block.id), + replacementText: normalizedReplacement, + activeInlineKinds: activeInlineKinds, + preserveTextWhitespace: origin == _WysiwygTextEditOrigin.paste, + replacementScope: BusyWysiwygReplacementScope.documentRange, ); - if (deletion == null) { + if (result == null) { return false; } - final mergedText = _documentController.blockText(deletion.blockId); - final insertionOffset = deletion.offset.clamp(0, mergedText.length).toInt(); - final nextText = mergedText.replaceRange( - insertionOffset, - insertionOffset, - normalizedReplacement, - ); - final splitResult = _documentController.replaceBlockTextWithParagraphs( - deletion.blockId, - nextText, - insertionOffset + normalizedReplacement.length, - ); - final focusResult = - splitResult ?? - BusyWysiwygTextSplitResult( - blockId: deletion.blockId, - offset: insertionOffset + normalizedReplacement.length, - ); - if (splitResult == null) { - _documentController.updateBlockText( - deletion.blockId, - nextText, - activeInlineKinds: activeInlineKinds, - ); + _recordUndoSnapshot(undoSnapshot); + if (origin == _WysiwygTextEditOrigin.paste) { + _continuousTextEdit = null; } - if (nextText.isEmpty) { - _setPendingInlineKinds(deletion.blockId, activeInlineKinds); + if (_documentController.blockText(result.blockId).isEmpty) { + _setPendingInlineKinds(result.blockId, activeInlineKinds); } _clearBlockSelection(collapseFields: false); _emitMarkdown(); - _focusBlockAfterFrame(focusResult.blockId, offset: focusResult.offset); + _focusBlockAfterFrame(result.blockId, offset: result.offset); return true; } @@ -6197,10 +6869,12 @@ class _BusyMarkWysiwygEditorState extends State { lastEndOffset: last.end, removedBlockIds: ranges.map((range) => range.block.id), blocks: blocks, + replacementScope: BusyWysiwygReplacementScope.documentRange, ); if (result == null) { return false; } + _continuousTextEdit = null; _recordUndoSnapshot(undoSnapshot); _clearBlockSelection(collapseFields: false); _emitMarkdown(); @@ -6359,114 +7033,43 @@ class _BusyMarkWysiwygEditorState extends State { Future _pasteHistoryPayload( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }) async { - final captured = _captureClipboardTarget(); - if (payload.kind == BusyMarkClipboardContentKind.image) { - final bytes = payload.imageBytes; - if (bytes == null || bytes.isEmpty) { - return ClipboardPasteResult.unsupported; - } - final inserted = await _ingestExternalImageBytes( - bytes, - suggestedFileName: payload.imageDisplayName ?? 'clipboard-image.png', - origin: AssetIngestionOrigin.screenshotPaste, - clipboardTarget: captured, - ); - return inserted - ? ClipboardPasteResult.inserted - : ClipboardPasteResult.unsupported; + if (_hasActiveClipboardComposition) { + return ClipboardPasteResult.staleTarget; } + final onCaptured = widget.onClipboardCaptured; + final captured = _captureClipboardTarget(); if (!_isClipboardTargetCurrent(captured)) { return ClipboardPasteResult.staleTarget; } - if (!plainText && payload.richFragment != null) { - final decoded = WysiwygClipboardFragment.decode(payload.richFragment!); - if (decoded != null) { - var fragment = decoded.rebase(_documentController.document.filePath); - var ingestedAssets = const []; - if (decoded.mediaPaths.isNotEmpty) { - if (!payload.mediaComplete) return ClipboardPasteResult.unsupported; - final prepared = await _prepareRetainedClipboardMedia( - decoded, - payload, - captured, - ); - if (prepared == null) { - return _isClipboardTargetCurrent(captured) - ? ClipboardPasteResult.unsupported - : ClipboardPasteResult.staleTarget; - } - fragment = prepared.fragment; - ingestedAssets = prepared.assets; - } - if (!_isClipboardTargetCurrent(captured)) { - await _deleteUncommittedClipboardAssets(ingestedAssets); - return ClipboardPasteResult.staleTarget; - } - final inserted = _pasteStyledClipboardIntoActiveBlock( - fragment.blocks, - payload.text ?? - fragment.documentBlocks.map(_copyTextForBlock).join('\n\n'), - ); - if (!inserted) { - await _deleteUncommittedClipboardAssets(ingestedAssets); - } - return inserted - ? ClipboardPasteResult.inserted - : ClipboardPasteResult.unsupported; - } - } - if (!plainText && payload.html != null) { - final fragment = const WysiwygClipboardHtml().decode( - payload.html!, - mode: _documentController.document.mode, + final outcome = await _pasteClipboardSnapshot( + BusyMarkClipboardSnapshot.fromPayload(payload), + mode: mode, + target: captured, + ); + if (outcome.result == ClipboardPasteResult.inserted && payload.external) { + onCaptured?.call( + outcome.capture ?? + busyMarkClipboardCaptureFromSnapshot( + BusyMarkClipboardSnapshot.fromPayload(payload), + ), ); - if (fragment != null && _hasUsableClipboardHtmlContent(fragment)) { - if (!_isClipboardTargetCurrent(captured)) { - return ClipboardPasteResult.staleTarget; - } - final rebased = fragment.rebase(_documentController.document.filePath); - final inserted = _pasteStyledClipboardIntoActiveBlock( - rebased.blocks, - payload.text ?? - rebased.documentBlocks.map(_copyTextForBlock).join('\n\n'), - ); - return inserted - ? ClipboardPasteResult.inserted - : ClipboardPasteResult.unsupported; - } } - final text = payload.text ?? payload.sourceText; - if (text == null) return ClipboardPasteResult.unsupported; - final inserted = await _pastePlainTextIntoActiveBlock(textOverride: text); - return inserted - ? ClipboardPasteResult.inserted - : ClipboardPasteResult.staleTarget; - } - - bool _hasUsableClipboardHtmlContent(WysiwygClipboardFragment fragment) { - return fragment.documentBlocks.any( - (block) => - block.plainText.trim().isNotEmpty || - block.kind == BusyBlockKind.image || - block.kind == BusyBlockKind.video || - block.kind == BusyBlockKind.thematicBreak || - block.kind == BusyBlockKind.table, - ); + return outcome.result; } Future<({WysiwygClipboardFragment fragment, List assets})?> _prepareRetainedClipboardMedia( WysiwygClipboardFragment fragment, - BusyMarkClipboardPayload payload, + BusyMarkClipboardSnapshot snapshot, _ClipboardTarget target, ) async { final destinations = {}; final assets = []; try { for (final entry in fragment.mediaPaths.entries) { - final bytes = payload.mediaBytes[entry.key]; + final bytes = snapshot.mediaBytes[entry.key]; if (bytes == null || bytes.isEmpty) { await _deleteUncommittedClipboardAssets(assets); return null; @@ -6652,14 +7255,42 @@ class _BusyMarkWysiwygEditorState extends State { return (bytes: Map.unmodifiable(result), complete: true); } - _ClipboardTarget _captureClipboardTarget() => _ClipboardTarget( - document: _captureDialogTarget(), - documentId: _documentId, - activeBlockId: _activeBlockId, - activeCellId: _activeCellId, - selection: _documentSelection, - textSelection: _activeTextTarget()?.controller.selection, - ); + bool _hasActiveComposition(TextEditingController controller) { + final composing = controller.value.composing; + return composing.isValid && + composing.isNormalized && + !composing.isCollapsed && + composing.end <= controller.text.length; + } + + bool get _hasActiveClipboardComposition { + final targetIds = { + if (_activeBlockId case final id?) id, + if (_activeCellId case final id?) id, + if (_documentSelection?.anchor.blockId case final id?) id, + if (_documentSelection?.extent.blockId case final id?) id, + }; + for (final id in targetIds) { + final controller = _tableCellControllers[id] ?? _textControllers[id]; + if (controller != null && _hasActiveComposition(controller)) { + return true; + } + } + return false; + } + + _ClipboardTarget _captureClipboardTarget() { + final textTarget = _activeTextTarget(); + return _ClipboardTarget( + document: _captureDialogTarget(), + documentId: _documentId, + activeBlockId: _activeBlockId, + activeCellId: _activeCellId, + selection: _documentSelection, + textSelection: textTarget?.controller.selection, + composing: textTarget?.controller.value.composing, + ); + } bool _isClipboardTargetCurrent(_ClipboardTarget target) => _isDialogTargetCurrent(target.document) && @@ -6667,7 +7298,9 @@ class _BusyMarkWysiwygEditorState extends State { target.activeBlockId == _activeBlockId && target.activeCellId == _activeCellId && target.selection == _documentSelection && - target.textSelection == _activeTextTarget()?.controller.selection; + target.textSelection == _activeTextTarget()?.controller.selection && + target.composing == _activeTextTarget()?.controller.value.composing && + !_hasActiveClipboardComposition; List<_SelectedTextRange> _withoutEmptySelectionEndpoints( List<_SelectedTextRange> ranges, @@ -6978,6 +7611,7 @@ class _ClipboardTarget { required this.activeCellId, required this.selection, required this.textSelection, + required this.composing, }); final _WysiwygDialogTarget document; final String documentId; @@ -6985,6 +7619,7 @@ class _ClipboardTarget { final String? activeCellId; final _DocumentTextSelection? selection; final TextSelection? textSelection; + final TextRange? composing; } class _WysiwygClipboardInsertionTarget @@ -6993,7 +7628,7 @@ class _WysiwygClipboardInsertionTarget BusyMarkClipboardInsertionCapabilities { const _WysiwygClipboardInsertionTarget(this.state); - final _BusyMarkWysiwygEditorState state; + final BusyMarkWysiwygEditorState state; @override String get documentId => state._documentId; @@ -7011,68 +7646,59 @@ class _WysiwygClipboardInsertionTarget } @override - bool get editable => state.mounted; + bool get editable => state.mounted && !state._hasActiveClipboardComposition; @override - bool canPaste(BusyMarkClipboardPayload payload, {required bool plainText}) { + bool canPaste( + BusyMarkClipboardPayload payload, { + required BusyMarkPasteMode mode, + }) { if (!editable) return false; - if (plainText) return payload.hasMeaningfulTextRepresentation; - return switch (payload.kind) { - BusyMarkClipboardContentKind.image => - payload.imageBytes?.isNotEmpty == true, - BusyMarkClipboardContentKind.richText => _canPasteRichPayload(payload), - BusyMarkClipboardContentKind.text => - payload.text != null || payload.sourceText != null, - }; - } - - bool _canPasteRichPayload(BusyMarkClipboardPayload payload) { - if (!payload.mediaComplete) return false; - final encoded = payload.richFragment; - final fragment = encoded == null - ? null - : WysiwygClipboardFragment.decode(encoded); - if (encoded != null && fragment == null) { - return payload.html != null || - payload.text != null || - payload.sourceText != null; - } - if (fragment != null && fragment.mediaPaths.isNotEmpty) { - return fragment.mediaPaths.entries.every((entry) { - final bytes = payload.mediaBytes[entry.key]; - return bytes != null && - state.widget.assetIngestionService.canIngestMediaBytes( - bytes: bytes, - suggestedFileName: p.basename(entry.value), - ); - }); - } - return fragment != null || - payload.html != null || - payload.text != null || - payload.sourceText != null; + final snapshot = BusyMarkClipboardSnapshot.fromPayload(payload); + final plan = const BusyMarkClipboardPasteResolver().resolve( + snapshot: snapshot, + mode: mode, + destination: BusyMarkPasteDestination.editor, + markdownMode: state._documentController.document.mode, + ); + return plan.candidates.any((candidate) { + if (candidate is BusyMarkImagePasteCandidate) { + return state.widget.assetIngestionService.canIngestMediaBytes( + bytes: candidate.bytes, + suggestedFileName: candidate.displayName ?? 'clipboard-image.png', + ); + } + if (candidate is! BusyMarkStructuredPasteCandidate || + candidate.fragment.mediaPaths.isEmpty) { + return true; + } + return snapshot.mediaComplete && + candidate.fragment.mediaPaths.entries.every((entry) { + final bytes = snapshot.mediaBytes[entry.key]; + return bytes != null && + state.widget.assetIngestionService.canIngestMediaBytes( + bytes: bytes, + suggestedFileName: p.basename(entry.value), + ); + }); + }); } @override Future paste( BusyMarkClipboardPayload payload, { - required bool plainText, - }) => state._pasteHistoryPayload(payload, plainText: plainText); + required BusyMarkPasteMode mode, + }) => state._pasteHistoryPayload(payload, mode: mode); @override - void requestEditorFocus() { - final target = state._activeTextTarget(); - final blockId = target?.targetId ?? state._activeBlockId; - if (blockId != null) { - state._focusBlockAfterFrame( - blockId, - offset: - target?.controller.selection.extentOffset ?? - target?.controller.text.length ?? - 0, - ); - } - } + void requestEditorFocus() => state._requestEditorFocusAfterHistoryPaste(); +} + +class _PendingTextFocus { + const _PendingTextFocus({required this.targetId, required this.offset}); + + final String targetId; + final int offset; } String _clipboardImageMimeType(String path) => @@ -7090,6 +7716,7 @@ enum _DocumentSelectionMenuAction { copy, copyPlainText, paste, + pastePlainText, selectAll, refineWithAi, clipboardHistory, @@ -7112,6 +7739,8 @@ class _ContinuousTextEdit { final String group; } +enum _WysiwygTextEditOrigin { userTyping, paste } + class _WysiwygSourceTarget { const _WysiwygSourceTarget({ required this.block, @@ -7362,7 +7991,9 @@ class _EditorShortcutIntent extends Intent { } class _PasteTextIntent extends Intent { - const _PasteTextIntent(); + const _PasteTextIntent(this.mode); + + final BusyMarkPasteMode mode; } class _SelectAllTextIntent extends Intent { @@ -7427,10 +8058,84 @@ String? _imageSourceFromInline(BusyInline inline) { } class _ImageDialogResult { - const _ImageDialogResult({required this.source, required this.alt}); + const _ImageDialogResult({ + required this.source, + required this.alt, + this.asset, + }); final String source; final String alt; + final IngestedAsset? asset; +} + +class _ImageAssetTransaction { + _ImageAssetTransaction({required this.service, required this.request}); + + final AssetIngestionService service; + final AssetIngestionRequest request; + final List _assets = []; + bool _closed = false; + + void register(IngestedAsset asset) { + if (_assets.any((candidate) => identical(candidate, asset))) return; + if (_closed) { + unawaited(service.rollback(asset)); + return; + } + _assets.add(asset); + } + + IngestedAsset? assetForMarkdownPath(String markdownPath) { + for (final asset in _assets.reversed) { + if (asset.markdownPath == markdownPath) return asset; + } + return null; + } + + Future ingestSelectedImage(String sourcePath) async { + final asset = await service.ingestFile( + sourcePath: sourcePath, + request: request, + origin: AssetIngestionOrigin.imagePicker, + ); + if (_closed) { + await service.rollback(asset); + return asset; + } + register(asset); + return asset; + } + + Future rollbackAll() async { + if (_closed) return; + _closed = true; + await service.rollbackAll(_assets); + } + + Future commitSelected(IngestedAsset? selected) async { + if (_closed) return; + _closed = true; + Object? finalizationError; + StackTrace? finalizationStack; + if (selected != null && + _assets.any((asset) => identical(asset, selected))) { + try { + await service.commit(selected); + } on Object catch (error, stack) { + // The document already references this file. Preserve the file and + // its pending record; only unused alternatives remain rollback-safe. + finalizationError = error; + finalizationStack = stack; + } + } + await service.rollbackAll( + _assets.where((asset) => !identical(asset, selected)), + ); + if (finalizationError != null) { + Error.throwWithStackTrace(finalizationError, finalizationStack!); + } + } } abstract final class BusyMarkImageDialogKeys { @@ -7448,6 +8153,8 @@ class _ImageDialog extends StatefulWidget { this.initialAlt = '', required this.submitLabel, required this.ingestSelectedImage, + required this.findSelectedAsset, + this.initialAsset, this.onSaveRequired, }); @@ -7455,7 +8162,9 @@ class _ImageDialog extends StatefulWidget { final String initialSource; final String initialAlt; final String submitLabel; - final Future Function(String sourcePath) ingestSelectedImage; + final IngestedAsset? initialAsset; + final Future Function(String sourcePath) ingestSelectedImage; + final IngestedAsset? Function(String markdownPath) findSelectedAsset; final VoidCallback? onSaveRequired; @override @@ -7466,12 +8175,14 @@ class _ImageDialogState extends State<_ImageDialog> { final _sourceController = TextEditingController(); final _altController = TextEditingController(); String? _errorMessage; + IngestedAsset? _selectedAsset; @override void initState() { super.initState(); _sourceController.text = widget.initialSource; _altController.text = widget.initialAlt; + _selectedAsset = widget.initialAsset; _sourceController.addListener(_handleSourceChanged); } @@ -7549,6 +8260,10 @@ class _ImageDialogState extends State<_ImageDialog> { bool get _canSubmit => _sourceController.text.trim().isNotEmpty; void _handleSourceChanged() { + final source = _sourceController.text.trim(); + if (source != _selectedAsset?.markdownPath) { + _selectedAsset = widget.findSelectedAsset(source); + } if (mounted) { setState(() {}); } @@ -7567,11 +8282,12 @@ class _ImageDialogState extends State<_ImageDialog> { return; } try { - final markdownPath = await widget.ingestSelectedImage(file.path); + final asset = await widget.ingestSelectedImage(file.path); if (!mounted) { return; } - _sourceController.text = markdownPath; + _selectedAsset = asset; + _sourceController.text = asset.markdownPath; if (_altController.text.trim().isEmpty) { _altController.text = p.basenameWithoutExtension(file.name); } @@ -7596,7 +8312,11 @@ class _ImageDialogState extends State<_ImageDialog> { } Navigator.pop( context, - _ImageDialogResult(source: source, alt: _altController.text.trim()), + _ImageDialogResult( + source: source, + alt: _altController.text.trim(), + asset: source == _selectedAsset?.markdownPath ? _selectedAsset : null, + ), ); } } diff --git a/lib/src/editor/wysiwyg/wysiwyg_inline_controller.dart b/lib/src/editor/wysiwyg/wysiwyg_inline_controller.dart index e647446a..0e91fbeb 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_inline_controller.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_inline_controller.dart @@ -39,6 +39,46 @@ String busyMarkWysiwygEditableText(BusyBlock block) { return source.replaceFirst(RegExp(r'(?:\r\n|\r|\n)$'), ''); } +/// Maps an inline Markdown source boundary back to the block's semantic text +/// coordinate. Math-bearing fields use source coordinates while the document +/// insertion APIs and ordinary fields use semantic coordinates. +int busyMarkWysiwygTextOffsetForSourceOffset( + BusyBlock block, + int sourceOffset, +) { + final source = busyMarkWysiwygEditableText(block); + final target = sourceOffset.clamp(0, source.length).toInt(); + final textLength = block.plainText.length; + var low = 0; + var high = textLength; + var bestTextOffset = 0; + var bestSourceOffset = 0; + while (low <= high) { + final textOffset = low + ((high - low) ~/ 2); + final mapped = const BusyMarkMarkdownSerializer() + .serializeInlineFragmentAtTextOffset( + block.inlines, + textOffset: textOffset, + atBlockStart: true, + readableHardBreakRuns: true, + ) + .sourceOffset; + if ((mapped - target).abs() < (bestSourceOffset - target).abs() || + ((mapped - target).abs() == (bestSourceOffset - target).abs() && + mapped <= target)) { + bestTextOffset = textOffset; + bestSourceOffset = mapped; + } + if (mapped == target) return textOffset; + if (mapped < target) { + low = textOffset + 1; + } else { + high = textOffset - 1; + } + } + return bestTextOffset; +} + class BusyInlineStyleRange { const BusyInlineStyleRange({ required this.start, diff --git a/lib/src/git/presentation/git_sidebar_tab.dart b/lib/src/git/presentation/git_sidebar_tab.dart index 387f63a2..aedede2c 100644 --- a/lib/src/git/presentation/git_sidebar_tab.dart +++ b/lib/src/git/presentation/git_sidebar_tab.dart @@ -348,22 +348,19 @@ class _GitResetDialogState extends State<_GitResetDialog> { children: [ Text(context.l10n.gitResetCurrentBranchMessage(widget.branch, commit)), const SizedBox(height: BusyMarkSpacing.md), - RadioGroup( - groupValue: _mode, - onChanged: (mode) => setState(() => _mode = mode), - child: Column( - children: [ - for (final mode in GitResetMode.values) - RadioListTile( - key: ValueKey('git-reset-mode-${mode.name}'), - value: mode, - title: Text(_resetModeLabel(context, mode)), - subtitle: Text(_resetModeDescription(context, mode)), - contentPadding: EdgeInsets.zero, - controlAffinity: ListTileControlAffinity.leading, - ), - ], - ), + Column( + children: [ + for (final mode in GitResetMode.values) + BusyMarkRadioButton( + key: ValueKey('git-reset-mode-${mode.name}'), + value: mode, + groupValue: _mode, + onChanged: (mode) => setState(() => _mode = mode), + title: Text(_resetModeLabel(context, mode)), + subtitle: Text(_resetModeDescription(context, mode)), + contentPadding: EdgeInsets.zero, + ), + ], ), ], ); diff --git a/lib/src/local_history/local_history_controller.dart b/lib/src/local_history/local_history_controller.dart index 5c5d8b73..25a33b1f 100644 --- a/lib/src/local_history/local_history_controller.dart +++ b/lib/src/local_history/local_history_controller.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter/foundation.dart' show listEquals; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; @@ -361,7 +362,10 @@ class LocalHistoryController extends Notifier { final promotion = _pendingUntitledPromotions[snapshot.bufferId]; if (promotion != null) { if (!_sameOptionalPath(snapshot.path, promotion.destinationPath)) { - _setWarning(LocalHistoryWarningKind.pathChange); + _setWarning( + LocalHistoryWarningKind.pathChange, + promotion.destinationPath, + ); return; } if (!await _completePendingUntitledPromotion( @@ -610,6 +614,24 @@ class LocalHistoryController extends Notifier { )) { return true; } + if (source.untitled && !destinationExisted) { + try { + // The successful filesystem operation proved that this pathname + // was vacant. Retire any stale live owner before promotion or a + // path-only capture can resolve the new file's identity. + await _store.markDeleted(destinationPath, recursive: false); + } on Object catch (error) { + _setWarning(LocalHistoryWarningKind.pathChange, error.toString()); + return false; + } + if (!_operationIsCurrent( + source.bufferId, + historyGeneration, + bufferGeneration, + )) { + return true; + } + } // A named-file Save As is a fork. Resolve an earlier untitled-to-source // promotion before recording the destination. If storage is still // unavailable, detach that source association from the buffer so it can @@ -768,6 +790,7 @@ class LocalHistoryController extends Notifier { final document = state.snapshot.documents .where( (candidate) => + !candidate.deleted && candidate.currentPath != null && p.equals(candidate.currentPath!, destinationPath), ) @@ -780,7 +803,7 @@ class LocalHistoryController extends Notifier { _documentIdsByBuffer.remove(source.bufferId); } if (retainedSourcePromotion) { - _setWarning(LocalHistoryWarningKind.pathChange); + _setWarning(LocalHistoryWarningKind.pathChange, source.path); } return captured; } @@ -1033,6 +1056,7 @@ class LocalHistoryController extends Notifier { final byPath = state.snapshot.documents .where( (document) => + !document.deleted && buffer.filePath != null && document.currentPath != null && p.equals(document.currentPath!, buffer.filePath!), @@ -1136,13 +1160,23 @@ class LocalHistoryController extends Notifier { await refresh(); if (!ref.mounted) return; final normalized = p.normalize(path); - final document = state.snapshot.documents.where((candidate) { - final current = candidate.currentPath; - return (current != null && p.equals(current, normalized)) || - candidate.historicalPaths.any( - (historical) => p.equals(historical, normalized), - ); - }).firstOrNull; + final activeDocument = state.snapshot.documents + .where( + (candidate) => + !candidate.deleted && + candidate.currentPath != null && + p.equals(candidate.currentPath!, normalized), + ) + .firstOrNull; + final document = + activeDocument ?? + state.snapshot.documents.where((candidate) { + final current = candidate.currentPath; + return (current != null && p.equals(current, normalized)) || + candidate.historicalPaths.any( + (historical) => p.equals(historical, normalized), + ); + }).firstOrNull; if (document != null) selectDocument(document.id); } @@ -1296,6 +1330,8 @@ class LocalHistoryController extends Notifier { // prevents a fast edit from scheduling a baseline under a competing file // identity while the promotion retry is still in progress. _pendingUntitledPromotions.remove(match.key); + final failure = _captureFailures.remove(match.key); + if (failure != null) _captureFailures[snapshot.bufferId] = failure; final adopted = match.value.forBuffer(snapshot.bufferId); _pendingUntitledPromotions[snapshot.bufferId] = adopted; final pending = _pending.remove(match.key); @@ -1312,6 +1348,8 @@ class LocalHistoryController extends Notifier { final promotion = _pendingUntitledPromotions.remove(bufferId); if (promotion == null) return; final detachedBufferId = 'history-promotion:${promotion.documentId}'; + final failure = _captureFailures.remove(bufferId); + if (failure != null) _captureFailures[detachedBufferId] = failure; _pendingUntitledPromotions[detachedBufferId] = promotion.forBuffer( detachedBufferId, ); @@ -1358,7 +1396,10 @@ class LocalHistoryController extends Notifier { final promotion = _pendingUntitledPromotions[snapshot.bufferId]; if (promotion != null) { if (!_sameOptionalPath(snapshot.path, promotion.destinationPath)) { - _setWarning(LocalHistoryWarningKind.pathChange); + _setWarning( + LocalHistoryWarningKind.pathChange, + promotion.destinationPath, + ); return false; } if (!await _completePendingUntitledPromotion( @@ -1473,11 +1514,21 @@ class LocalHistoryController extends Notifier { return true; } try { + final staleOwner = await _stalePromotionOwner(promotion); + if (!_operationIsCurrent( + bufferId, + promotionHistoryGeneration, + promotionBufferGeneration, + ) || + !identical(_pendingUntitledPromotions[bufferId], promotion)) { + return true; + } final document = await _store.promoteUntitledDocument( documentId: promotion.documentId, destinationPath: promotion.destinationPath, displayName: promotion.displayName, updatedAt: _clock().toUtc(), + staleDestinationOwner: staleOwner, ); if (!_operationIsCurrent( bufferId, @@ -1488,11 +1539,12 @@ class LocalHistoryController extends Notifier { return true; } if (document == null) { - _captureFailures[bufferId] = const _LocalHistoryCaptureFailure( + _captureFailures[bufferId] = _LocalHistoryCaptureFailure( + detail: promotion.destinationPath, retryable: false, stage: _LocalHistoryFailureStage.promotion, ); - _setWarning(LocalHistoryWarningKind.pathChange); + _showCaptureFailure(); return false; } _documentIdsByBuffer[bufferId] = document.id; @@ -1530,6 +1582,48 @@ class LocalHistoryController extends Notifier { } } + Future _stalePromotionOwner( + LocalHistoryPendingIdentityPromotion promotion, + ) async { + // Pending promotions are recorded only after a successful first save to a + // vacant pathname. Older versions did not retire stale pathname owners. + // Recover those sessions only with evidence that the saved file is still + // this lineage; never claim a replacement written since that save. + final snapshot = await _store.load(); + final document = snapshot.documents + .where((d) => d.id == promotion.documentId) + .firstOrNull; + if (document == null || + !document.untitled || + document.currentPath != null) { + return null; + } + final owner = snapshot.documents + .where( + (d) => + !d.deleted && + d.id != document.id && + d.currentPath != null && + p.equals(d.currentPath!, promotion.destinationPath), + ) + .firstOrNull; + if (owner == null || !owner.updatedAt.isBefore(document.updatedAt)) { + return null; + } + final summary = snapshot.revisionsFor(document.id).firstOrNull; + if (summary == null) return null; + final revision = await _store.readRevision(summary.id); + if (revision == null) return null; + try { + final bytes = await File(promotion.destinationPath).readAsBytes(); + return listEquals(bytes, revision.format.encode(revision.source)) + ? owner + : null; + } on FileSystemException { + return null; + } + } + Future _enqueue(String bufferId, Future Function() operation) { final prior = _bufferQueues[bufferId] ?? Future.value(); final result = prior.then((_) => operation()); @@ -1730,7 +1824,7 @@ class LocalHistoryController extends Notifier { void _showCaptureFailure() { final failure = _captureFailures.values.firstOrNull; if (failure != null) { - _setWarning(LocalHistoryWarningKind.capture, failure.detail); + _setWarning(failure.warningKind, failure.detail); } } @@ -1767,6 +1861,7 @@ class LocalHistoryController extends Notifier { final byPath = snapshot.documents .where( (document) => + !document.deleted && document.currentPath != null && p.equals(document.currentPath!, scope.path!), ) @@ -1789,7 +1884,7 @@ class LocalHistoryController extends Notifier { var selectedRevision = state.selectedRevision; var effectiveWarning = _captureFailures.isNotEmpty ? LocalHistoryWarning( - LocalHistoryWarningKind.capture, + _captureFailures.values.first.warningKind, detail: _captureFailures.values.first.detail, ) : warning; @@ -1943,6 +2038,11 @@ class _LocalHistoryCaptureFailure { final String? detail; final bool retryable; final _LocalHistoryFailureStage stage; + + LocalHistoryWarningKind get warningKind => switch (stage) { + _LocalHistoryFailureStage.capture => LocalHistoryWarningKind.capture, + _LocalHistoryFailureStage.promotion => LocalHistoryWarningKind.pathChange, + }; } enum _LocalHistoryFailureStage { capture, promotion } diff --git a/lib/src/local_history/local_history_panel.dart b/lib/src/local_history/local_history_panel.dart index 0013c9da..86f53f2f 100644 --- a/lib/src/local_history/local_history_panel.dart +++ b/lib/src/local_history/local_history_panel.dart @@ -120,7 +120,8 @@ class _LocalHistoryPanelState extends ConsumerState { selected != null && activeBuffer != null && (selected.id == activeHistoryDocumentId || - (selected.currentPath != null && + (!selected.deleted && + selected.currentPath != null && activeBuffer.filePath != null && p.equals(selected.currentPath!, activeBuffer.filePath!))); final selectedMatchesVisibleScope = diff --git a/lib/src/local_history/local_history_store.dart b/lib/src/local_history/local_history_store.dart index 7c1bc97d..5ee68f20 100644 --- a/lib/src/local_history/local_history_store.dart +++ b/lib/src/local_history/local_history_store.dart @@ -26,11 +26,15 @@ abstract interface class LocalHistoryStore { /// /// Returns the updated document, or `null` when the requested identity is /// missing or is no longer eligible for this transition. + /// [staleDestinationOwner] is only supplied after verifying a retained + /// successful save against the current file. Its identity and timestamp are + /// rechecked under the store lock before retiring it in the same index write. Future promoteUntitledDocument({ required String documentId, required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }); Future remapPath(String sourcePath, String destinationPath); @@ -194,9 +198,10 @@ class FileLocalHistoryStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) => _serialized((root) async { return _withFileLock(root, () async { - final index = await _loadIndexUnlocked(root, repair: true); + var index = await _loadIndexUnlocked(root, repair: true); final document = index.documents .where((candidate) => candidate.id == documentId) .firstOrNull; @@ -210,11 +215,19 @@ class FileLocalHistoryStore implements LocalHistoryStore { .where( (candidate) => candidate.id != document.id && - candidate.currentPath != null && - p.equals(candidate.currentPath!, destination), + _ownsActivePath(candidate, destination), ) .firstOrNull; - if (destinationOwner != null) return null; + if (destinationOwner != null) { + if (!_canRetirePromotionOwner( + document, + destinationOwner, + staleDestinationOwner, + )) { + return null; + } + index = index.withDocument(destinationOwner.copyWith(deleted: true)); + } final promoted = document.copyWith( displayName: displayName, currentPath: destination, @@ -234,6 +247,7 @@ class FileLocalHistoryStore implements LocalHistoryStore { @override Future remapPath(String sourcePath, String destinationPath) => _mutateDocuments((document) { + if (document.deleted) return document; final current = document.currentPath; if (current == null) return document; final mapped = _remap(current, sourcePath, destinationPath); @@ -246,7 +260,6 @@ class FileLocalHistoryStore implements LocalHistoryStore { current, mapped, ]), - deleted: false, updatedAt: DateTime.now().toUtc(), ); }); @@ -749,14 +762,28 @@ LocalHistoryDocument? _resolveDocument( final path = request.path; if (path == null) return null; return documents - .where( - (document) => - document.currentPath != null && - p.equals(document.currentPath!, path), - ) + .where((document) => _ownsActivePath(document, path)) .firstOrNull; } +// The controller verifies the successfully saved bytes before requesting this +// repair. Recheck the exact owner under the store lock: a later capture or a +// different owner must not be retired by an old session's promotion retry. +bool _canRetirePromotionOwner( + LocalHistoryDocument document, + LocalHistoryDocument owner, + LocalHistoryDocument? expectedOwner, +) => + expectedOwner != null && + owner.id == expectedOwner.id && + owner.updatedAt == expectedOwner.updatedAt && + owner.updatedAt.isBefore(document.updatedAt); + +bool _ownsActivePath(LocalHistoryDocument document, String path) => + !document.deleted && + document.currentPath != null && + p.equals(document.currentPath!, path); + LocalHistoryDocument _updatedDocument( LocalHistoryDocument document, LocalHistoryCaptureRequest request, { @@ -974,6 +1001,7 @@ class MemoryLocalHistoryStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) async { final document = _documents[documentId]; if (document == null) return null; @@ -986,11 +1014,21 @@ class MemoryLocalHistoryStore implements LocalHistoryStore { .where( (candidate) => candidate.id != document.id && - candidate.currentPath != null && - p.equals(candidate.currentPath!, destination), + _ownsActivePath(candidate, destination), ) .firstOrNull; - if (destinationOwner != null) return null; + if (destinationOwner != null) { + if (!_canRetirePromotionOwner( + document, + destinationOwner, + staleDestinationOwner, + )) { + return null; + } + _documents[destinationOwner.id] = destinationOwner.copyWith( + deleted: true, + ); + } final promoted = document.copyWith( displayName: displayName, currentPath: destination, @@ -1006,6 +1044,7 @@ class MemoryLocalHistoryStore implements LocalHistoryStore { @override Future remapPath(String sourcePath, String destinationPath) async { for (final entry in _documents.entries.toList()) { + if (entry.value.deleted) continue; final current = entry.value.currentPath; final mapped = current == null ? null @@ -1019,7 +1058,6 @@ class MemoryLocalHistoryStore implements LocalHistoryStore { current!, mapped, ]), - deleted: false, ); } } diff --git a/lib/src/markdown/busymark_document.dart b/lib/src/markdown/busymark_document.dart index e9284a17..0827e790 100644 --- a/lib/src/markdown/busymark_document.dart +++ b/lib/src/markdown/busymark_document.dart @@ -5,6 +5,10 @@ import 'markdown_model.dart'; /// Marks an empty WYSIWYG paragraph that must remain a source blank line. const busyMarkPreserveEmptyParagraphAttribute = 'preserveEmptyParagraph'; +/// Marks text whose trailing or whitespace-only content was accepted as an +/// intentional edit and must not be removed by document-level canonicalization. +const busyMarkPreserveTextWhitespaceAttribute = 'preserveTextWhitespace'; + /// Marks the editor-only paragraph after a terminal non-paragraph block. /// /// The Markdown serializer ignores this block while it is empty. The marker is diff --git a/lib/src/markdown/busymark_markdown_serializer.dart b/lib/src/markdown/busymark_markdown_serializer.dart index 8397b6b8..f63c3e84 100644 --- a/lib/src/markdown/busymark_markdown_serializer.dart +++ b/lib/src/markdown/busymark_markdown_serializer.dart @@ -2,9 +2,196 @@ import '../core/source_span.dart'; import 'busymark_document.dart'; import 'math_syntax.dart'; +class BusyMarkSerializedInlineFragment { + const BusyMarkSerializedInlineFragment({ + required this.source, + required this.sourceOffset, + this.lineBreakSourceOffsets = const {}, + this.textAtoms = const [], + }); + + final String source; + final int sourceOffset; + final Map lineBreakSourceOffsets; + final List textAtoms; +} + +class BusyMarkSerializedTextAtom { + const BusyMarkSerializedTextAtom({ + required this.inlinePath, + required this.text, + required this.textStart, + required this.textEnd, + required this.sourceStart, + required this.sourceEnd, + required this.escaped, + }); + + final List inlinePath; + final String text; + final int textStart; + final int textEnd; + final int sourceStart; + final int sourceEnd; + final bool escaped; +} + +class BusyMarkInlineLineBreakOffset { + const BusyMarkInlineLineBreakOffset({required this.textOffset}); + + final int textOffset; +} + +/// Reports one callback per complete metadata-producing inline traversal. +/// +/// The value is the emitted source length and is useful for deterministic +/// regression checks that traversal work remains proportional to the fragment. +void Function(int emittedCharacters)? debugBusyMarkInlineSerializationTraversal; +void Function(int visitedNodes)? debugBusyMarkInlineSerializationVisitedNodes; + +class BusyMarkInlineDelimiter { + const BusyMarkInlineDelimiter({required this.opening, required this.closing}); + + final String opening; + final String closing; +} + class BusyMarkMarkdownSerializer { const BusyMarkMarkdownSerializer(); + /// Serializes an inline fragment without document-level trimming or a final + /// newline. This is also the single entry point for context-sensitive inline + /// escaping used by clipboard insertion. + String serializeInlineFragment( + List inlines, { + bool tableCell = false, + bool atBlockStart = false, + bool readableHardBreakRuns = true, + }) { + final source = _inlineMarkdown( + inlines, + tableCell: tableCell, + atBlockStart: atBlockStart, + readableHardBreakRuns: readableHardBreakRuns, + ); + return tableCell ? source.replaceAll('|', r'\|') : source; + } + + /// Serializes [inlines] without altering their semantic adjacency and maps + /// a plain-text boundary to its resulting source offset. + BusyMarkSerializedInlineFragment serializeInlineFragmentAtTextOffset( + List inlines, { + required int textOffset, + bool tableCell = false, + bool atBlockStart = false, + bool readableHardBreakRuns = true, + Map delimiterOverrides = const {}, + }) { + return serializeInlineFragmentWithOffsets( + inlines, + textOffset: textOffset, + tableCell: tableCell, + atBlockStart: atBlockStart, + readableHardBreakRuns: readableHardBreakRuns, + delimiterOverrides: delimiterOverrides, + ); + } + + BusyMarkSerializedInlineFragment serializeInlineFragmentWithOffsets( + List inlines, { + required int textOffset, + Iterable lineBreakOffsets = const [], + bool tableCell = false, + bool atBlockStart = false, + bool readableHardBreakRuns = true, + Map delimiterOverrides = const {}, + }) { + final requestedOffsets = {textOffset}; + final lineBreaksByBoundary = >{}; + for (final lineBreak in lineBreakOffsets) { + final boundary = lineBreak.textOffset + 1; + requestedOffsets.add(boundary); + lineBreaksByBoundary.putIfAbsent(boundary, () => []).add(lineBreak); + } + final metrics = _InlineTraversalMetrics(); + var result = _inlineMarkdownAtTextOffsets( + inlines, + textOffsets: requestedOffsets, + tableCell: tableCell, + atBlockStart: atBlockStart, + readableHardBreakRuns: readableHardBreakRuns, + delimiterOverrides: delimiterOverrides, + metrics: metrics, + ); + if (tableCell) { + result = _escapeTablePipesWithOffsets(result); + } + final mappedLineBreaks = {}; + for (final entry in lineBreaksByBoundary.entries) { + final sourceOffset = result.lineBreakSourceOffsets[entry.key]; + if (sourceOffset == null) continue; + for (final lineBreak in entry.value) { + mappedLineBreaks[lineBreak] = sourceOffset; + } + } + debugBusyMarkInlineSerializationTraversal?.call(result.source.length); + debugBusyMarkInlineSerializationVisitedNodes?.call(metrics.visitedNodes); + return BusyMarkSerializedInlineFragment( + source: result.source, + sourceOffset: result.sourceOffsets[textOffset] ?? result.source.length, + lineBreakSourceOffsets: Map.unmodifiable(mappedLineBreaks), + textAtoms: List.unmodifiable(result.textAtoms), + ); + } + + _InlineSerialization _escapeTablePipesWithOffsets( + _InlineSerialization serialization, + ) { + final requested = { + ...serialization.sourceOffsets.values, + ...serialization.lineBreakSourceOffsets.values, + for (final atom in serialization.textAtoms) ...[ + atom.sourceStart, + atom.sourceEnd, + ], + }; + final translated = {}; + final source = StringBuffer(); + for (var index = 0; index <= serialization.source.length; index++) { + if (requested.contains(index)) translated[index] = source.length; + if (index == serialization.source.length) break; + final character = serialization.source[index]; + if (character == '|') source.write(r'\'); + source.write(character); + } + return _InlineSerialization( + source: source.toString(), + sourceOffsets: { + for (final entry in serialization.sourceOffsets.entries) + entry.key: translated[entry.value]!, + }, + lineBreakSourceOffsets: { + for (final entry in serialization.lineBreakSourceOffsets.entries) + entry.key: translated[entry.value]!, + }, + textAtoms: [ + for (final atom in serialization.textAtoms) + BusyMarkSerializedTextAtom( + inlinePath: atom.inlinePath, + text: atom.text, + textStart: atom.textStart, + textEnd: atom.textEnd, + sourceStart: translated[atom.sourceStart]!, + sourceEnd: translated[atom.sourceEnd]!, + escaped: + atom.escaped || + translated[atom.sourceEnd]! - translated[atom.sourceStart]! != + atom.sourceEnd - atom.sourceStart, + ), + ], + ); + } + String serialize(BusyDocument document) { final patched = _serializeByPatchingSource(document); if (patched != null) { @@ -24,8 +211,10 @@ class BusyMarkMarkdownSerializer { continue; } final source = serializeBlock(block); - if (source.trim().isNotEmpty) { - chunks.add(source.trimRight()); + final preserveWhitespace = _requiresTextWhitespacePreservation(block); + if (source.trim().isNotEmpty || + (preserveWhitespace && source.isNotEmpty)) { + chunks.add(preserveWhitespace ? source : source.trimRight()); } } return _joinDocumentChunks(chunks); @@ -138,7 +327,11 @@ class BusyMarkMarkdownSerializer { } buffer ..write(source.substring(offset, span.startOffset)) - ..write(serializeBlock(block).trimRight()); + ..write( + _requiresTextWhitespacePreservation(block) + ? serializeBlock(block) + : serializeBlock(block).trimRight(), + ); offset = span.endOffset; } buffer.write(source.substring(offset)); @@ -264,17 +457,40 @@ class BusyMarkMarkdownSerializer { if (contentPrefix != null) contentPrefix, if (text.isNotEmpty) text, ].join(' '); + final indentation = marker.length + 1; + final children = <({BusyBlock block, String source})>[ + for (final child in block.children) + if (serializeBlock(child) case final source + when source.trim().isNotEmpty || + (_requiresTextWhitespacePreservation(child) && + source.isNotEmpty)) + (block: child, source: source), + ]; + if (content.isEmpty && children.isNotEmpty) { + final first = children.removeAt(0).source.split('\n'); + final source = StringBuffer('$marker ${first.first}'); + for (final line in first.skip(1)) { + source + ..write('\n') + ..write(line.isEmpty ? '' : '${' ' * indentation}$line'); + } + for (final child in children) { + source.write( + child.block.kind == BusyBlockKind.paragraph ? '\n\n' : '\n', + ); + source.write(_indentBlock(child.source, indentation)); + } + return source.toString(); + } final line = content.isEmpty ? marker : '$marker $content'; - if (block.children.isEmpty) { - return line; + if (children.isEmpty) return line; + final source = StringBuffer(line); + for (final child in children) { + final nested = child.source; + source.write(child.block.kind == BusyBlockKind.paragraph ? '\n\n' : '\n'); + source.write(_indentBlock(nested, indentation)); } - final indentation = marker.length + 1; - final nested = block.children - .map(serializeBlock) - .where((source) => source.trim().isNotEmpty) - .map((source) => _indentBlock(source, indentation)) - .join('\n'); - return nested.isEmpty ? line : '$line\n$nested'; + return source.toString(); } String _indentBlock(String source, int width) { @@ -341,6 +557,12 @@ class BusyMarkMarkdownSerializer { return block.dirty || block.children.any(_hasDirtyContent); } + bool _requiresTextWhitespacePreservation(BusyBlock block) { + return block.attributes[busyMarkPreserveTextWhitespaceAttribute] == + 'true' || + block.children.any(_requiresTextWhitespacePreservation); + } + String _blockquote(BusyBlock block) { final text = block.children.isEmpty ? _inlineMarkdown(block.inlines, readableHardBreakRuns: true) @@ -415,10 +637,11 @@ class BusyMarkMarkdownSerializer { } String _tableCellMarkdown(BusyBlock cell) { - return _inlineMarkdown( + return serializeInlineFragment( cell.inlines, tableCell: true, - ).replaceAll('|', r'\|'); + readableHardBreakRuns: false, + ); } String _writersideAdmonition(BusyBlock block) { @@ -457,102 +680,225 @@ class BusyMarkMarkdownSerializer { .replaceAll('>', '>'); } - String _inlineMarkdown( + _InlineSerialization _inlineMarkdownAtTextOffsets( List inlines, { - bool tableCell = false, - bool atBlockStart = false, - bool readableHardBreakRuns = false, + required Set textOffsets, + required bool tableCell, + required bool atBlockStart, + required bool readableHardBreakRuns, + required Map delimiterOverrides, + required _InlineTraversalMetrics metrics, + List pathPrefix = const [], + int textBase = 0, }) { + final totalTextLength = inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final targets = { + for (final offset in textOffsets) + offset.clamp(0, totalTextLength).toInt(), + }; final buffer = StringBuffer(); + var consumedText = 0; + final sourceOffsets = {}; + final lineBreakSourceOffsets = {}; + final textAtoms = []; var nextAtBlockStart = atBlockStart; + final sortedTargets = targets.toList()..sort(); + var targetCursor = 0; for (var index = 0; index < inlines.length; index++) { final inline = inlines[index]; + metrics.visitedNodes += 1; if (inline.kind == BusyInlineKind.hardBreak) { var runEnd = index + 1; while (runEnd < inlines.length && inlines[runEnd].kind == BusyInlineKind.hardBreak) { runEnd += 1; } - final count = runEnd - index; - if (count > 1) { - if (readableHardBreakRuns && !tableCell) { - final startsBlock = buffer.isEmpty; - if (!startsBlock && !nextAtBlockStart) { - buffer.write('\n'); - } - if (startsBlock) { - // Two tags on the marker-only first line keep CommonMark from - // treating a leading
as a raw HTML block. - buffer.write('

'); - for (var marker = 2; marker < count; marker++) { - buffer.write('\n
'); - } - } else { - buffer.write(List.filled(count, '
').join('\n')); + final run = inlines.sublist(index, runEnd); + metrics.visitedNodes += run.length - 1; + final runTextLength = run.fold( + 0, + (length, item) => length + item.plainText.length, + ); + final runSerialization = _serializeHardBreakRun( + count: run.length, + startsBlock: buffer.isEmpty, + hasFollowingContent: runEnd < inlines.length, + tableCell: tableCell, + nextAtBlockStart: nextAtBlockStart, + readableHardBreakRuns: readableHardBreakRuns, + ); + var breakIndex = 0; + var breakTextEnd = run.first.plainText.length; + while (targetCursor < sortedTargets.length && + sortedTargets[targetCursor] <= consumedText + runTextLength) { + final target = sortedTargets[targetCursor++]; + if (target == consumedText) { + sourceOffsets[target] = buffer.length; + } else if (target <= consumedText + runTextLength) { + final localTarget = target - consumedText; + while (breakIndex + 1 < run.length && localTarget > breakTextEnd) { + breakIndex += 1; + breakTextEnd += run[breakIndex].plainText.length; } - final hasFollowingContent = runEnd < inlines.length; - if (hasFollowingContent) { - buffer.write('\n'); + sourceOffsets[target] = + buffer.length + + runSerialization.boundarySourceOffsets[breakIndex]; + final lineBreakSourceOffset = + runSerialization.lineBreakSourceOffsets[breakIndex]; + if (localTarget == breakTextEnd && lineBreakSourceOffset != null) { + lineBreakSourceOffsets[target] = + buffer.length + lineBreakSourceOffset; } - nextAtBlockStart = hasFollowingContent; - } else { - // Physical newlines cannot safely occur in headings or table - // cells. Keep their repeated breaks in compact inline HTML. - buffer.write(List.filled(count, '
').join()); - nextAtBlockStart = false; } - index = runEnd - 1; - continue; } + buffer.write(runSerialization.source); + var runTextStart = textBase + consumedText; + var runSourceStart = buffer.length - runSerialization.source.length; + for (var runIndex = 0; runIndex < run.length; runIndex++) { + final runText = run[runIndex].plainText; + final runSourceEnd = + buffer.length - + runSerialization.source.length + + runSerialization.boundarySourceOffsets[runIndex]; + textAtoms.add( + BusyMarkSerializedTextAtom( + inlinePath: [...pathPrefix, index + runIndex], + text: runText, + textStart: runTextStart, + textEnd: runTextStart + runText.length, + sourceStart: runSourceStart, + sourceEnd: runSourceEnd, + escaped: true, + ), + ); + runTextStart += runText.length; + runSourceStart = runSourceEnd; + } + consumedText += runTextLength; + nextAtBlockStart = runSerialization.source.endsWith('\n'); + index = runEnd - 1; + continue; } - final source = _inline( + final length = inline.plainText.length; + final localOffsets = {}; + while (targetCursor < sortedTargets.length && + sortedTargets[targetCursor] <= consumedText + length) { + localOffsets.add(sortedTargets[targetCursor++] - consumedText); + } + final result = _inlineAtTextOffsets( inline, + textOffsets: localOffsets, tableCell: tableCell, atBlockStart: nextAtBlockStart, readableHardBreakRuns: readableHardBreakRuns, followedByLink: index + 1 < inlines.length && inlines[index + 1].kind == BusyInlineKind.link, + delimiterOverrides: delimiterOverrides, + metrics: metrics, + inlinePath: [...pathPrefix, index], + textBase: textBase + consumedText, ); - buffer.write(source); - if (source.isNotEmpty) { - nextAtBlockStart = source.endsWith('\n'); + for (final entry in result.sourceOffsets.entries) { + sourceOffsets.putIfAbsent( + consumedText + entry.key, + () => buffer.length + entry.value, + ); + } + for (final entry in result.lineBreakSourceOffsets.entries) { + lineBreakSourceOffsets[consumedText + entry.key] = + buffer.length + entry.value; + } + for (final atom in result.textAtoms) { + textAtoms.add( + BusyMarkSerializedTextAtom( + inlinePath: atom.inlinePath, + text: atom.text, + textStart: atom.textStart, + textEnd: atom.textEnd, + sourceStart: buffer.length + atom.sourceStart, + sourceEnd: buffer.length + atom.sourceEnd, + escaped: atom.escaped, + ), + ); + } + buffer.write(result.source); + consumedText += length; + if (result.source.isNotEmpty) { + nextAtBlockStart = result.source.endsWith('\n'); } } - return buffer.toString(); + return _InlineSerialization( + source: buffer.toString(), + sourceOffsets: { + for (final target in targets) + target: sourceOffsets[target] ?? buffer.length, + }, + lineBreakSourceOffsets: lineBreakSourceOffsets, + textAtoms: textAtoms, + ); } - String _inline( + _InlineSerialization _inlineAtTextOffsets( BusyInline inline, { - bool tableCell = false, - bool atBlockStart = false, - bool readableHardBreakRuns = false, - bool followedByLink = false, + required Set textOffsets, + required bool tableCell, + required bool atBlockStart, + required bool readableHardBreakRuns, + required bool followedByLink, + required Map delimiterOverrides, + required _InlineTraversalMetrics metrics, + required List inlinePath, + required int textBase, }) { - final children = inline.children.isEmpty - ? _escapeInlineText(inline.text, atBlockStart: atBlockStart) - : _inlineMarkdown( + final length = inline.plainText.length; + final targets = { + for (final offset in textOffsets) offset.clamp(0, length).toInt(), + }; + final childReadableHardBreakRuns = inline.kind == BusyInlineKind.underline + ? false + : readableHardBreakRuns; + final childResult = inline.children.isEmpty + ? null + : _inlineMarkdownAtTextOffsets( inline.children, + textOffsets: targets, tableCell: tableCell, - readableHardBreakRuns: readableHardBreakRuns, + atBlockStart: false, + readableHardBreakRuns: childReadableHardBreakRuns, + delimiterOverrides: delimiterOverrides, + metrics: metrics, + pathPrefix: inlinePath, + textBase: textBase, ); - return switch (inline.kind) { + final children = inline.children.isEmpty + ? _escapeInlineText(inline.text, atBlockStart: atBlockStart) + : childResult!.source; + final delimiter = delimiterOverrides[inline.kind]; + final source = switch (inline.kind) { BusyInlineKind.text => _escapeInlineText( inline.text, atBlockStart: atBlockStart, escapeTrailingBang: followedByLink, ), BusyInlineKind.math => _mathInline(inline), - BusyInlineKind.strong => '**$children**', - BusyInlineKind.emphasis => '*$children*', - BusyInlineKind.underline => '$children', - BusyInlineKind.strikethrough => '~~$children~~', + BusyInlineKind.strong => + '${delimiter?.opening ?? '**'}$children${delimiter?.closing ?? '**'}', + BusyInlineKind.emphasis => + '${delimiter?.opening ?? '*'}$children${delimiter?.closing ?? '*'}', + BusyInlineKind.underline => + '${delimiter?.opening ?? ''}$children${delimiter?.closing ?? ''}', + BusyInlineKind.strikethrough => + '${delimiter?.opening ?? '~~'}$children${delimiter?.closing ?? '~~'}', BusyInlineKind.code => tableCell && _tableCodeNeedsHtml(inline.text) ? _htmlCodeSpan(inline.text) : _codeSpan(inline.text), BusyInlineKind.link => - '[${children.isEmpty ? inline.text : children}](${inline.destination ?? ''})', + '[${children.isEmpty ? inline.text : children}](${_linkTarget(inline)})', BusyInlineKind.image => '![${_escapeInlineText(inline.text)}](${inline.destination ?? ''})', BusyInlineKind.softBreak => ' ', @@ -560,6 +906,236 @@ class BusyMarkMarkdownSerializer { BusyInlineKind.writersideVariable => '%${inline.text}%', BusyInlineKind.html || BusyInlineKind.unknown => inline.text, }; + final escapedTextOffsets = inline.kind == BusyInlineKind.text + ? _escapedInlineTextOffsets( + inline.text, + targets, + atBlockStart: atBlockStart, + escapeTrailingBang: followedByLink, + ) + : const {}; + final openingLength = + delimiter?.opening.length ?? + switch (inline.kind) { + BusyInlineKind.strong || BusyInlineKind.strikethrough => 2, + BusyInlineKind.underline => 3, + BusyInlineKind.emphasis => 1, + _ => 0, + }; + final sourceOffsets = {}; + for (final target in targets) { + sourceOffsets[target] = target == 0 + ? 0 + : target == length + ? source.length + : switch (inline.kind) { + BusyInlineKind.text => escapedTextOffsets[target]!, + BusyInlineKind.strong || + BusyInlineKind.emphasis || + BusyInlineKind.underline || + BusyInlineKind.strikethrough => + openingLength + (childResult?.sourceOffsets[target] ?? 0), + BusyInlineKind.link => + 1 + (childResult?.sourceOffsets[target] ?? 0), + _ => source.length, + }; + } + final lineBreakSourceOffsets = {}; + if (inline.kind == BusyInlineKind.text) { + for (final target in targets) { + if (target > 0 && inline.text.codeUnitAt(target - 1) == 0x0a) { + lineBreakSourceOffsets[target] = sourceOffsets[target]! - 1; + } + } + } else if (childResult != null) { + final childOpeningLength = inline.kind == BusyInlineKind.link + ? 1 + : openingLength; + for (final entry in childResult.lineBreakSourceOffsets.entries) { + lineBreakSourceOffsets[entry.key] = childOpeningLength + entry.value; + } + } + final textAtoms = []; + if (inline.kind == BusyInlineKind.text || + (inline.kind == BusyInlineKind.link && inline.children.isEmpty) || + inline.kind == BusyInlineKind.image) { + final value = inline.text; + final prefix = switch (inline.kind) { + BusyInlineKind.link => 1, + BusyInlineKind.image => 2, + _ => 0, + }; + final escapedOffsets = _escapedInlineTextOffsets( + value, + {for (var index = 0; index <= value.length; index++) index}, + atBlockStart: inline.kind == BusyInlineKind.text && atBlockStart, + escapeTrailingBang: + inline.kind == BusyInlineKind.text && followedByLink, + ); + var offset = 0; + for (final rune in value.runes) { + final width = rune > 0xffff ? 2 : 1; + final sourceStart = prefix + escapedOffsets[offset]!; + final sourceEnd = prefix + escapedOffsets[offset + width]!; + textAtoms.add( + BusyMarkSerializedTextAtom( + inlinePath: inlinePath, + text: value.substring(offset, offset + width), + textStart: textBase + offset, + textEnd: textBase + offset + width, + sourceStart: sourceStart, + sourceEnd: sourceEnd, + escaped: sourceEnd - sourceStart != width, + ), + ); + offset += width; + } + } else if (childResult != null) { + final prefix = inline.kind == BusyInlineKind.link ? 1 : openingLength; + for (final atom in childResult.textAtoms) { + textAtoms.add( + BusyMarkSerializedTextAtom( + inlinePath: atom.inlinePath, + text: atom.text, + textStart: atom.textStart, + textEnd: atom.textEnd, + sourceStart: prefix + atom.sourceStart, + sourceEnd: prefix + atom.sourceEnd, + escaped: atom.escaped, + ), + ); + } + } else if (inline.kind == BusyInlineKind.softBreak) { + textAtoms.add( + BusyMarkSerializedTextAtom( + inlinePath: inlinePath, + text: inline.text, + textStart: textBase, + textEnd: textBase + inline.text.length, + sourceStart: 0, + sourceEnd: source.length, + escaped: inline.text != source, + ), + ); + } + return _InlineSerialization( + source: source, + sourceOffsets: sourceOffsets, + lineBreakSourceOffsets: lineBreakSourceOffsets, + textAtoms: textAtoms, + ); + } + + _HardBreakRunSerialization _serializeHardBreakRun({ + required int count, + required bool startsBlock, + required bool hasFollowingContent, + required bool tableCell, + required bool nextAtBlockStart, + required bool readableHardBreakRuns, + }) { + if (count == 1 && readableHardBreakRuns && !tableCell) { + return const _HardBreakRunSerialization( + source: ' \n', + boundarySourceOffsets: [3], + lineBreakSourceOffsets: [2], + ); + } + if (!readableHardBreakRuns || tableCell) { + return _HardBreakRunSerialization( + source: List.filled(count, '
').join(), + boundarySourceOffsets: [ + for (var index = 1; index <= count; index++) 4 * index, + ], + lineBreakSourceOffsets: List.filled(count, null), + ); + } + final buffer = StringBuffer(); + if (!startsBlock && !nextAtBlockStart) buffer.write('\n'); + final boundarySourceOffsets = []; + final lineBreakSourceOffsets = []; + for (var index = 0; index < count; index++) { + buffer.write('
'); + // The semantic boundary is after the tag. A following newline only + // lays out the readable source and must not move the editing caret. + boundarySourceOffsets.add(buffer.length); + final hasNext = index + 1 < count; + final emitsLayoutBreak = startsBlock + ? index > 0 && (hasNext || hasFollowingContent) + : hasNext || hasFollowingContent; + if (emitsLayoutBreak) { + lineBreakSourceOffsets.add(buffer.length); + buffer.write('\n'); + } else { + lineBreakSourceOffsets.add(null); + } + } + return _HardBreakRunSerialization( + source: buffer.toString(), + boundarySourceOffsets: boundarySourceOffsets, + lineBreakSourceOffsets: lineBreakSourceOffsets, + ); + } + + Map _escapedInlineTextOffsets( + String value, + Set offsets, { + required bool atBlockStart, + required bool escapeTrailingBang, + }) { + final blockMarkerOffsets = _blockMarkerEscapeOffsets( + value, + atBlockStart: atBlockStart, + ); + final targets = offsets.toList()..sort(); + final result = {}; + var sourceOffset = 0; + var targetIndex = 0; + for (var index = 0; index <= value.length; index++) { + while (targetIndex < targets.length && targets[targetIndex] == index) { + result[targets[targetIndex]] = sourceOffset; + targetIndex += 1; + } + if (index == value.length) break; + final unit = value.codeUnitAt(index); + if (_inlineSyntaxCharacters.contains(unit) || + (escapeTrailingBang && unit == 0x21 && index == value.length - 1) || + blockMarkerOffsets.contains(index)) { + sourceOffset += 1; + } + sourceOffset += 1; + } + return result; + } + + String _inlineMarkdown( + List inlines, { + bool tableCell = false, + bool atBlockStart = false, + bool readableHardBreakRuns = false, + }) { + return _inlineMarkdownAtTextOffsets( + inlines, + textOffsets: const {}, + tableCell: tableCell, + atBlockStart: atBlockStart, + readableHardBreakRuns: readableHardBreakRuns, + delimiterOverrides: const {}, + metrics: _InlineTraversalMetrics(), + ).source; + } + + String _linkTarget(BusyInline inline) { + final destination = inline.destination ?? ''; + final title = inline.attributes['title']; + if (title == null || title.isEmpty) return destination; + final escapedTitle = title + .replaceAll('&', '&') + .replaceAll('\\', '\') + .replaceAll('"', '\\"') + .replaceAll('\r', ' ') + .replaceAll('\n', ' '); + return '$destination "$escapedTitle"'; } String _mathInline(BusyInline inline) { @@ -721,6 +1297,36 @@ class BusyMarkMarkdownSerializer { }; } +class _InlineSerialization { + const _InlineSerialization({ + required this.source, + this.sourceOffsets = const {}, + this.lineBreakSourceOffsets = const {}, + this.textAtoms = const [], + }); + + final String source; + final Map sourceOffsets; + final Map lineBreakSourceOffsets; + final List textAtoms; +} + +class _HardBreakRunSerialization { + const _HardBreakRunSerialization({ + required this.source, + required this.boundarySourceOffsets, + required this.lineBreakSourceOffsets, + }); + + final String source; + final List boundarySourceOffsets; + final List lineBreakSourceOffsets; +} + +class _InlineTraversalMetrics { + int visitedNodes = 0; +} + extension _FirstOrNull on Iterable { T? get firstOrNull => isEmpty ? null : first; } diff --git a/lib/src/markdown/markdown_ast_adapter.dart b/lib/src/markdown/markdown_ast_adapter.dart index fe84956e..219e98ae 100644 --- a/lib/src/markdown/markdown_ast_adapter.dart +++ b/lib/src/markdown/markdown_ast_adapter.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:markdown/markdown.dart' as md; import 'package:xml/xml.dart'; @@ -6,6 +8,7 @@ import 'busymark_document.dart'; import 'markdown_fence.dart'; import 'markdown_front_matter.dart'; import 'markdown_model.dart'; +import 'markdown_source_annotation.dart'; import 'math_syntax.dart'; import 'raw_html_adapter.dart'; import 'raw_html_policy.dart'; @@ -14,6 +17,27 @@ import '../writerside/writerside_schema.dart'; const _rawHtmlAdapter = RawHtmlAdapter(); +/// Reports source-boundary entries inspected while building the reusable +/// lookahead for a mapped Markdown sibling list. Tests use this to guard the +/// complete AST mapping path against per-node forward rescans. +void Function(int inspections)? debugBusyMarkSourceMappingBoundaryInspections; + +/// Reports genuine source-text fallback searches after exact mapped ranges, +/// exact text, and cached sibling boundaries could not resolve a node. +void Function()? debugBusyMarkSourceMappingFallbackSearchCalls; + +/// Reports the half-open source interval permitted for each fallback search. +void Function(int start, int end)? +debugBusyMarkSourceMappingFallbackSearchRanges; + +String _decodeMarkdownAttribute(String value) => value + .replaceAll('\', '\\') + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('&', '&'); + class MarkdownAstAdapter { const MarkdownAstAdapter(); @@ -269,6 +293,19 @@ class MarkdownAstAdapter { if (text.isEmpty) { return const []; } + if (RegExp(r'^(?:\s*)+$').hasMatch(text)) { + // Block comments are authored markup, not an editable prose field. + // Preserve them verbatim, including when another block is serialized. + return [ + BusyBlock( + id: nextId(), + kind: BusyBlockKind.htmlBlock, + rawSource: rawText, + preserveRaw: true, + attributes: const {'sourceFormat': 'html'}, + ), + ]; + } if (mode == MarkdownMode.writersideMarkdown) { final writerside = _writersideBlockFromText( rawText, @@ -602,18 +639,26 @@ class MarkdownAstAdapter { final contentChildren = _withoutTaskCheckbox(itemChildren); final nestedBlocks = []; final inlineNodes = []; + var hasPrimaryContent = false; for (final child in contentChildren) { - if (child is md.Element && + final blockChild = + child is md.Element && (child.tag == 'ul' || child.tag == 'ol' || child.tag == 'blockquote' || child.tag == 'pre' || - child.tag == 'table')) { + child.tag == 'table' || + child.tag == 'hr' || + RegExp(r'^h[1-6]$').hasMatch(child.tag) || + (child.tag == 'p' && + (hasPrimaryContent || nestedBlocks.isNotEmpty))); + if (blockChild) { nestedBlocks.addAll( _blocksFromNode(child, nextId: nextId, mode: mode), ); } else { inlineNodes.add(child); + hasPrimaryContent = true; } } final attributes = { @@ -639,11 +684,143 @@ class MarkdownAstAdapter { return result; } - List _inlinesFromNodes(Iterable nodes) { - return [for (final node in nodes) ..._inlineFromNode(node)]; + /// Runs the ordinary semantic converter with optional source annotations. + /// Mapping owns the parser policy; this method owns the single set of + /// Markdown-node-to-BusyMark semantic switches. + List convertInlineNodes( + Iterable nodes, { + Map? sourceMappings, + String? mappingSource, + int mappingStart = 0, + int? mappingEnd, + Iterable ignoredPositionMarkers = const [], + }) => _inlinesFromNodes( + nodes, + sourceMappings: sourceMappings, + mappingSource: mappingSource, + mappingStart: mappingStart, + mappingEnd: mappingEnd, + ignoredPositionMarkers: ignoredPositionMarkers, + ); + + List _inlinesFromNodes( + Iterable nodes, { + Map? sourceMappings, + String? mappingSource, + int mappingStart = 0, + int? mappingEnd, + Iterable ignoredPositionMarkers = const [], + }) { + final values = nodes.toList(growable: false); + if (sourceMappings == null || mappingSource == null) { + return [for (final node in values) ..._inlineFromNode(node)]; + } + final end = (mappingEnd ?? mappingSource.length) + .clamp(mappingStart, mappingSource.length) + .toInt(); + final ranges = [for (final node in values) _sourceMappingOffsets(node)]; + final nextMappedStarts = List.filled(values.length, null); + final nextTextIndices = List.filled(values.length, null); + int? nextMappedStart; + int? nextTextIndex; + for (var index = values.length - 1; index >= 0; index--) { + nextMappedStarts[index] = nextMappedStart; + nextTextIndices[index] = nextTextIndex; + final range = ranges[index]; + if (range != null) nextMappedStart = range.start; + final node = values[index]; + if (node is md.Text && node.text.isNotEmpty) nextTextIndex = index; + } + debugBusyMarkSourceMappingBoundaryInspections?.call(values.length); + final result = []; + final fallbackTextStarts = List.filled(values.length, null); + var cursor = mappingStart.clamp(0, end).toInt(); + for (var index = 0; index < values.length; index++) { + final node = values[index]; + final range = ranges[index]; + final exactRange = + range != null && + range.start >= mappingStart && + range.start >= cursor && + range.end >= range.start && + range.end <= end + ? range + : null; + final cachedFallbackStart = fallbackTextStarts[index]; + final nodeStart = + (exactRange?.start ?? + (cachedFallbackStart != null && + cachedFallbackStart >= cursor && + cachedFallbackStart <= end + ? cachedFallbackStart + : cursor)) + .clamp(mappingStart, end) + .toInt(); + final exactTextEnd = + node is md.Text && + nodeStart + node.text.length <= end && + mappingSource.startsWith(node.text, nodeStart) + ? nodeStart + node.text.length + : null; + final nextMappedBoundary = nextMappedStarts[index]; + final cachedMappedEnd = + nextMappedBoundary != null && + nextMappedBoundary >= nodeStart && + nextMappedBoundary <= end + ? nextMappedBoundary + : null; + int? fallbackTextEnd; + final candidateIndex = nextTextIndices[index]; + if (exactRange == null && + exactTextEnd == null && + cachedMappedEnd == null && + candidateIndex != null) { + final reused = fallbackTextStarts[candidateIndex]; + if (reused != null && reused >= nodeStart && reused <= end) { + fallbackTextEnd = reused; + } else { + final candidate = values[candidateIndex] as md.Text; + debugBusyMarkSourceMappingFallbackSearchCalls?.call(); + debugBusyMarkSourceMappingFallbackSearchRanges?.call(nodeStart, end); + final relative = mappingSource + .substring(nodeStart, end) + .indexOf(candidate.text); + if (relative >= 0) { + fallbackTextEnd = nodeStart + relative; + fallbackTextStarts[candidateIndex] = fallbackTextEnd; + } + } + } + final nodeEnd = + (exactRange?.end ?? + exactTextEnd ?? + cachedMappedEnd ?? + fallbackTextEnd ?? + end) + .clamp(nodeStart, end); + result.addAll( + _inlineFromNode( + node, + sourceMappings: sourceMappings, + mappingSource: mappingSource, + mappingStart: nodeStart, + mappingEnd: nodeEnd, + ignoredPositionMarkers: ignoredPositionMarkers, + ), + ); + cursor = math.max(cursor, nodeEnd); + } + return result; } - List _inlineFromNode(md.Node node) { + List _inlineFromNode( + md.Node node, { + Map? sourceMappings, + String? mappingSource, + int? mappingStart, + int? mappingEnd, + Iterable ignoredPositionMarkers = const [], + }) { if (node is md.Element && node.attributes[writersideLiteralPercentAttribute] == 'true') { return const [ @@ -660,17 +837,86 @@ class MarkdownAstAdapter { } final htmlInlines = _rawHtmlAdapter.parseRawHtmlInlineFragment(node.text); if (htmlInlines != null) { + if (sourceMappings != null && + mappingSource != null && + mappingStart != null && + mappingEnd != null) { + final rawSource = mappingSource.substring(mappingStart, mappingEnd); + final mappedHtml = _rawHtmlAdapter + .parseRawHtmlInlineFragmentWithMetadata( + node.text, + sourceText: rawSource, + ignoredPositionMarkers: ignoredPositionMarkers, + ); + if (mappedHtml != null) { + for (final entry in mappedHtml.ranges.entries) { + final range = entry.value; + sourceMappings[entry.key] = BusyMarkMappedInlineRange( + start: mappingStart + range.start, + end: mappingStart + range.end, + opening: range.opening, + closing: range.closing, + isSourceLineBreak: entry.key.kind == BusyInlineKind.hardBreak, + sourceLineBreakOffset: range.sourceLineBreakOffset == null + ? null + : mappingStart + range.sourceLineBreakOffset!, + ); + } + return mappedHtml.inlines; + } + } return htmlInlines; } + if (sourceMappings != null && + mappingSource != null && + mappingStart != null && + mappingEnd != null && + node.text.contains('\n')) { + return _mappedTextWithLineBreaks( + node.text, + mappingSource.substring(mappingStart, mappingEnd), + mappingStart, + sourceMappings, + ); + } return [BusyInline(kind: BusyInlineKind.text, text: node.text)]; } if (node is! md.Element) { return [BusyInline(kind: BusyInlineKind.unknown, text: node.textContent)]; } final tag = node.tag.toLowerCase(); - final children = _inlinesFromNodes(node.children ?? const []); + final mappedStart = int.tryParse( + node.attributes[busyMarkSourceMappingStartAttribute] ?? '', + ); + final mappedEnd = int.tryParse( + node.attributes[busyMarkSourceMappingEndAttribute] ?? '', + ); + final labelStart = int.tryParse( + node.attributes[busyMarkSourceMappingLabelStartAttribute] ?? '', + ); + final labelEnd = int.tryParse( + node.attributes[busyMarkSourceMappingLabelEndAttribute] ?? '', + ); + final opening = node.attributes[busyMarkSourceMappingOpeningAttribute]; + final closing = node.attributes[busyMarkSourceMappingClosingAttribute]; + final childStart = + labelStart ?? + (mappedStart == null + ? mappingStart + : mappedStart + (opening?.length ?? 0)); + final childEnd = + labelEnd ?? + (mappedEnd == null ? mappingEnd : mappedEnd - (closing?.length ?? 0)); + final children = _inlinesFromNodes( + node.children ?? const [], + sourceMappings: sourceMappings, + mappingSource: mappingSource, + mappingStart: childStart ?? 0, + mappingEnd: childEnd, + ignoredPositionMarkers: ignoredPositionMarkers, + ); final text = node.textContent; - return switch (tag) { + final inlines = switch (tag) { busyMarkMathInlineTag => [ BusyInline( kind: BusyInlineKind.math, @@ -711,7 +957,13 @@ class MarkdownAstAdapter { text: text, destination: node.attributes['href'], children: children, - attributes: node.attributes, + attributes: { + for (final entry in node.attributes.entries) + if (!entry.key.startsWith('data-busymark-source-')) + entry.key: entry.value, + if (node.attributes['title'] case final title?) + 'title': _decodeMarkdownAttribute(title), + }, ), ], 'img' => [ @@ -722,7 +974,10 @@ class MarkdownAstAdapter { attributes: node.attributes, ), ], - 'br' => const [BusyInline(kind: BusyInlineKind.hardBreak, text: '\n')], + // Source mappings are keyed by inline identity. Each parser occurrence + // therefore needs its own object even though every hard break has the + // same semantic value. + 'br' => [BusyInline(kind: BusyInlineKind.hardBreak, text: '\n')], 'var' => [ BusyInline( kind: BusyInlineKind.writersideVariable, @@ -740,6 +995,84 @@ class MarkdownAstAdapter { ...children, ], }; + if (sourceMappings != null && inlines.length == 1) { + if (mappedStart != null && mappedEnd != null) { + sourceMappings[inlines.single] = BusyMarkMappedInlineRange( + start: mappedStart, + end: mappedEnd, + opening: node.attributes[busyMarkSourceMappingOpeningAttribute], + closing: node.attributes[busyMarkSourceMappingClosingAttribute], + labelStart: labelStart, + labelEnd: labelEnd, + isAutolink: + node.attributes[busyMarkSourceMappingAutolinkAttribute] == 'true', + isReference: + node.attributes[busyMarkSourceMappingReferenceAttribute] == + 'true', + isSourceLineBreak: + node.attributes[busyMarkSourceMappingLineBreakAttribute] == + 'true', + sourceLineBreakOffset: int.tryParse( + node.attributes[busyMarkSourceMappingLineBreakOffsetAttribute] ?? + '', + ), + ); + } + } + return inlines; + } + + ({int start, int end})? _sourceMappingOffsets(md.Node node) { + if (node is! md.Element) return null; + final start = int.tryParse( + node.attributes[busyMarkSourceMappingStartAttribute] ?? '', + ); + final end = int.tryParse( + node.attributes[busyMarkSourceMappingEndAttribute] ?? '', + ); + return start == null || end == null ? null : (start: start, end: end); + } + + List _mappedTextWithLineBreaks( + String semanticText, + String rawSource, + int sourceBase, + Map sourceMappings, + ) { + final result = []; + var semanticStart = 0; + var rawStart = 0; + for (final match in RegExp('\n').allMatches(semanticText)) { + if (match.start > semanticStart) { + result.add( + BusyInline( + kind: BusyInlineKind.text, + text: semanticText.substring(semanticStart, match.start), + ), + ); + } + final rawLineFeed = rawSource.indexOf('\n', rawStart); + final lineBreak = BusyInline(kind: BusyInlineKind.text, text: '\n'); + result.add(lineBreak); + if (rawLineFeed >= 0) { + sourceMappings[lineBreak] = BusyMarkMappedInlineRange( + start: sourceBase + rawLineFeed, + end: sourceBase + rawLineFeed + 1, + isSourceLineBreak: true, + ); + rawStart = rawLineFeed + 1; + } + semanticStart = match.end; + } + if (semanticStart < semanticText.length) { + result.add( + BusyInline( + kind: BusyInlineKind.text, + text: semanticText.substring(semanticStart), + ), + ); + } + return result; } BusyBlock? _imageBlockFromParagraph( diff --git a/lib/src/markdown/markdown_parser.dart b/lib/src/markdown/markdown_parser.dart index dec5cc16..09de5320 100644 --- a/lib/src/markdown/markdown_parser.dart +++ b/lib/src/markdown/markdown_parser.dart @@ -32,6 +32,24 @@ class MarkdownParser { /// editor and source serializer retain their existing projection by default. final bool preserveHtmlSemantics; + /// Exposes the lossless scanner's positioned block/container slices for + /// side-effect-free projections such as spelling. Callers receive authored + /// source positions; no reference validation or publication expansion is + /// performed. + List positionedSourceChunks({ + required String filePath, + required String source, + MarkdownMode mode = MarkdownMode.commonMark, + }) => [ + for (final chunk in _scannedBlockSources(filePath, source, mode: mode)) + MarkdownPositionedSourceChunk( + rawSource: chunk.rawSource, + span: chunk.span, + sourceOnly: chunk.sourceOnly, + protectsEdits: chunk.protectEdits, + ), + ]; + List parseInlineFragment({ required String source, MarkdownMode mode = MarkdownMode.commonMark, @@ -1882,6 +1900,20 @@ class MarkdownParser { } } +final class MarkdownPositionedSourceChunk { + const MarkdownPositionedSourceChunk({ + required this.rawSource, + required this.span, + required this.sourceOnly, + required this.protectsEdits, + }); + + final String rawSource; + final SourceSpan span; + final bool sourceOnly; + final bool protectsEdits; +} + class _AstInlineReferences { const _AstInlineReferences({required this.links, required this.images}); diff --git a/lib/src/markdown/markdown_source_annotation.dart b/lib/src/markdown/markdown_source_annotation.dart new file mode 100644 index 00000000..38818ae7 --- /dev/null +++ b/lib/src/markdown/markdown_source_annotation.dart @@ -0,0 +1,76 @@ +import 'busymark_document.dart'; + +const busyMarkSourceMappingStartAttribute = 'data-busymark-source-start'; +const busyMarkSourceMappingEndAttribute = 'data-busymark-source-end'; +const busyMarkSourceMappingOpeningAttribute = 'data-busymark-source-opening'; +const busyMarkSourceMappingClosingAttribute = 'data-busymark-source-closing'; +const busyMarkSourceMappingLabelStartAttribute = + 'data-busymark-source-label-start'; +const busyMarkSourceMappingLabelEndAttribute = 'data-busymark-source-label-end'; +const busyMarkSourceMappingAutolinkAttribute = 'data-busymark-source-autolink'; +const busyMarkSourceMappingReferenceAttribute = + 'data-busymark-source-reference'; +const busyMarkSourceMappingLineBreakAttribute = + 'data-busymark-source-line-break'; +const busyMarkSourceMappingLineBreakOffsetAttribute = + 'data-busymark-source-line-break-offset'; + +class BusyMarkMappedInlineRange { + const BusyMarkMappedInlineRange({ + required this.start, + required this.end, + this.opening, + this.closing, + this.labelStart, + this.labelEnd, + this.lineBreaks = const [], + this.originalInline, + this.isAutolink = false, + this.isReference = false, + this.isSourceLineBreak = false, + this.sourceLineBreakOffset, + }); + + final int start; + final int end; + final String? opening; + final String? closing; + final int? labelStart; + final int? labelEnd; + final List lineBreaks; + final BusyInline? originalInline; + final bool isAutolink; + final bool isReference; + final bool isSourceLineBreak; + final int? sourceLineBreakOffset; +} + +class BusyMarkMappedSourceLineBreak { + const BusyMarkMappedSourceLineBreak({ + required this.textOffset, + required this.lineEnding, + required this.continuationPrefix, + this.sourceOffset, + }); + + final int textOffset; + final String lineEnding; + final String continuationPrefix; + final int? sourceOffset; +} + +class BusyMarkMappedInlineParse { + BusyMarkMappedInlineParse({ + required this.inlines, + required Map ranges, + this.positionRecordsComplete = true, + this.sourceStart, + this.sourceEnd, + }) : ranges = Map.unmodifiable(ranges); + + final List inlines; + final Map ranges; + final bool positionRecordsComplete; + final int? sourceStart; + final int? sourceEnd; +} diff --git a/lib/src/markdown/markdown_source_map.dart b/lib/src/markdown/markdown_source_map.dart new file mode 100644 index 00000000..ebbc6ffc --- /dev/null +++ b/lib/src/markdown/markdown_source_map.dart @@ -0,0 +1,1231 @@ +import 'dart:math' as math; + +import 'package:markdown/markdown.dart' as md; + +import 'busymark_document.dart'; +import 'markdown_ast_adapter.dart'; +import 'markdown_model.dart'; +import 'markdown_source_annotation.dart'; +import 'math_syntax.dart'; + +export 'markdown_source_annotation.dart'; + +void _setSourceMappingAttributes( + md.Element element, { + required int start, + required int end, + String? opening, + String? closing, + int? labelStart, + int? labelEnd, + bool isAutolink = false, + bool isReference = false, + bool isSourceLineBreak = false, + int? sourceLineBreakOffset, +}) { + element.attributes[busyMarkSourceMappingStartAttribute] = '$start'; + element.attributes[busyMarkSourceMappingEndAttribute] = '$end'; + if (opening != null) { + element.attributes[busyMarkSourceMappingOpeningAttribute] = opening; + } + if (closing != null) { + element.attributes[busyMarkSourceMappingClosingAttribute] = closing; + } + if (labelStart != null) { + element.attributes[busyMarkSourceMappingLabelStartAttribute] = + '$labelStart'; + } + if (labelEnd != null) { + element.attributes[busyMarkSourceMappingLabelEndAttribute] = '$labelEnd'; + } + if (isAutolink) { + element.attributes[busyMarkSourceMappingAutolinkAttribute] = 'true'; + } + if (isReference) { + element.attributes[busyMarkSourceMappingReferenceAttribute] = 'true'; + } + if (isSourceLineBreak) { + element.attributes[busyMarkSourceMappingLineBreakAttribute] = 'true'; + } + if (sourceLineBreakOffset != null) { + element.attributes[busyMarkSourceMappingLineBreakOffsetAttribute] = + '$sourceLineBreakOffset'; + } +} + +class _SourceMappingDelimiterPosition { + _SourceMappingDelimiterPosition(this.start, this.end); + + int start; + int end; +} + +class _SourceMappingDelimiterSyntax extends md.DelimiterSyntax { + _SourceMappingDelimiterSyntax.asterisk() + : super( + r'\*+', + requiresDelimiterRun: true, + allowIntraWord: true, + tags: [md.DelimiterTag('em', 1), md.DelimiterTag('strong', 2)], + startCharacter: 0x2a, + ); + + _SourceMappingDelimiterSyntax.underscore() + : super( + '_+', + requiresDelimiterRun: true, + tags: [md.DelimiterTag('em', 1), md.DelimiterTag('strong', 2)], + startCharacter: 0x5f, + ); + + _SourceMappingDelimiterSyntax.strikethrough() + : super( + '~+', + requiresDelimiterRun: true, + allowIntraWord: true, + tags: [md.DelimiterTag('del', 1), md.DelimiterTag('del', 2)], + startCharacter: 0x7e, + ); + + final Expando<_SourceMappingDelimiterPosition> _positions = Expando(); + + @override + bool onMatch(md.InlineParser parser, Match match) { + final runLength = match.group(0)!.length; + final matchStart = parser.pos; + final matchEnd = parser.pos + runLength; + final text = md.Text(parser.source.substring(matchStart, matchEnd)); + final delimiter = md.DelimiterRun.tryParse( + parser, + matchStart, + matchEnd, + syntax: this, + node: text, + allowIntraWord: allowIntraWord, + tags: List.of(tags ?? const []), + ); + if (delimiter == null) { + parser.advanceBy(runLength); + return false; + } + _positions[delimiter] = _SourceMappingDelimiterPosition( + matchStart, + matchEnd, + ); + parser.pushDelimiter(delimiter); + parser.addNode(text); + return true; + } + + @override + Iterable? close( + md.InlineParser parser, + md.Delimiter opener, + md.Delimiter closer, { + required String tag, + required List Function() getChildren, + }) { + final indicatorLength = opener is md.DelimiterRun + ? opener.tags + .lastWhere( + (candidate) => + candidate.tag == tag && + opener.length >= candidate.indicatorLength && + closer.length >= candidate.indicatorLength, + ) + .indicatorLength + : 1; + final openerPosition = _positions[opener]; + final closerPosition = _positions[closer]; + final element = md.Element(tag, getChildren()); + if (openerPosition != null && closerPosition != null) { + // CommonMark consumes opening delimiters from the right edge of their + // run, and closing delimiters from the left edge. Any unused characters + // on the other side remain literal source outside this element. + final openingStart = openerPosition.end - indicatorLength; + final closingEnd = closerPosition.start + indicatorLength; + final opening = parser.source.substring(openingStart, openerPosition.end); + final closing = parser.source.substring(closerPosition.start, closingEnd); + _setSourceMappingAttributes( + element, + start: openingStart, + end: closingEnd, + opening: opening, + closing: closing, + ); + openerPosition.end = openingStart; + closerPosition.start += indicatorLength; + } + return [element]; + } +} + +class _SourceMappingLinkSyntax extends md.LinkSyntax { + @override + Iterable? close( + md.InlineParser parser, + covariant md.SimpleDelimiter opener, + md.Delimiter? closer, { + String? tag, + required List Function() getChildren, + }) { + final labelEnd = parser.pos; + final result = super.close( + parser, + opener, + closer, + tag: tag, + getChildren: getChildren, + ); + if (result == null) return null; + final nodes = result.toList(growable: false); + final isReference = + labelEnd + 1 >= parser.source.length || + parser.source.codeUnitAt(labelEnd + 1) != 0x28; + for (final node in nodes.whereType()) { + if (node.tag != 'a') continue; + _setSourceMappingAttributes( + node, + start: opener.endPos - 1, + end: parser.pos + 1, + labelStart: opener.endPos, + labelEnd: labelEnd, + isReference: isReference, + ); + } + return nodes; + } +} + +class _SourceMappingAutolinkSyntax extends md.InlineSyntax { + _SourceMappingAutolinkSyntax() + : super(r'<(([a-zA-Z][a-zA-Z\-\+\.]+):(?://)?[^\s>]*)>'); + + @override + bool onMatch(md.InlineParser parser, Match match) { + final start = parser.pos; + final parsed = md.Document( + encodeHtml: parser.encodeHtml, + ).parseInline(match[0]!); + if (parsed.singleOrNull case md.Element anchor) { + _setSourceMappingAttributes( + anchor, + start: start, + end: start + match[0]!.length, + labelStart: start + 1, + labelEnd: start + match[0]!.length - 1, + isAutolink: true, + ); + parser.addNode(anchor); + return true; + } + return false; + } +} + +class _SourceMappingEmailAutolinkSyntax extends md.InlineSyntax { + _SourceMappingEmailAutolinkSyntax() : super(r'<([^\s<>@]+@[^\s<>@]+)>'); + + Map _approvedOriginals = const {}; + + void approveOriginals(Map originals) { + _approvedOriginals = Map.unmodifiable(originals); + } + + String _rangeKey(int start, int end) => '$start:$end'; + + @override + bool tryMatch(md.InlineParser parser, [int? startMatchPos]) { + startMatchPos ??= parser.pos; + final match = pattern.matchAsPrefix(parser.source, startMatchPos); + if (match == null) return false; + final start = parser.pos; + final parsed = md.Document( + encodeHtml: parser.encodeHtml, + ).parseInline(match[0]!); + final parsedAnchor = parsed.singleOrNull; + final approved = + _approvedOriginals[_rangeKey(start, start + match[0]!.length)]; + md.Element? anchor; + if (parsedAnchor is md.Element && parsedAnchor.tag == 'a') { + anchor = parsedAnchor; + } else if (approved != null) { + anchor = md.Element.text('a', match[1]!); + anchor.attributes.addAll(approved.attributes); + } + if (approved != null && anchor != null) { + anchor.attributes['href'] = + approved.destination ?? approved.attributes['href'] ?? ''; + } + if (anchor == null || anchor.tag != 'a') return false; + parser.writeText(); + _setSourceMappingAttributes( + anchor, + start: start, + end: start + match[0]!.length, + labelStart: start + 1, + labelEnd: start + match[0]!.length - 1, + isAutolink: true, + ); + parser.addNode(anchor); + parser.consume(match[0]!.length); + return true; + } + + @override + bool onMatch(md.InlineParser parser, Match match) => + throw UnsupportedError('tryMatch performs authoritative email mapping'); +} + +class _SourceMappingHardLineBreakSyntax extends md.LineBreakSyntax { + @override + bool onMatch(md.InlineParser parser, Match match) { + final element = md.Element.empty('br'); + _setSourceMappingAttributes( + element, + start: parser.pos, + end: match.end, + isSourceLineBreak: true, + ); + parser.addNode(element); + return true; + } +} + +class _SourceMappingCodeSyntax extends md.CodeSyntax { + @override + bool onMatch(md.InlineParser parser, Match match) { + final start = parser.pos; + final parsed = md.Document( + encodeHtml: parser.encodeHtml, + ).parseInline(match[0]!); + final node = parsed.singleOrNull; + if (node is! md.Element || node.tag != 'code') return false; + _setSourceMappingAttributes( + node, + start: start, + end: start + match[0]!.length, + ); + parser.addNode(node); + return true; + } +} + +List _sourceMappingInlineSyntaxes( + _SourceMappingEmailAutolinkSyntax emailSyntax, +) { + return [ + _SourceMappingCodeSyntax(), + emailSyntax, + _SourceMappingAutolinkSyntax(), + _SourceMappingLinkSyntax(), + _SourceMappingDelimiterSyntax.asterisk(), + _SourceMappingDelimiterSyntax.underscore(), + _SourceMappingDelimiterSyntax.strikethrough(), + _SourceMappingHardLineBreakSyntax(), + ]; +} + +class BusyMarkInlineParserContext { + BusyMarkInlineParserContext._({ + required md.Document document, + required md.Document mappingDocument, + required Map referenceDefinitions, + required _SourceMappingEmailAutolinkSyntax emailSyntax, + }) : _document = document, + _mappingDocument = mappingDocument, + _referenceDefinitions = referenceDefinitions, + _emailSyntax = emailSyntax; + + final md.Document _document; + final md.Document _mappingDocument; + final Map _referenceDefinitions; + final _SourceMappingEmailAutolinkSyntax _emailSyntax; + + int parseInvocations = 0; + + void _addReferenceLabelMarkerVariants( + md.Document document, + String source, + Iterable markers, + ) { + final markerList = markers.where((marker) => marker.isNotEmpty).toList(); + if (markerList.isEmpty || _referenceDefinitions.isEmpty) return; + final original = StringBuffer(); + final insertions = <({int offset, String marker})>[]; + var sourceOffset = 0; + while (sourceOffset < source.length) { + String? matchedMarker; + for (final marker in markerList) { + if (source.startsWith(marker, sourceOffset)) { + matchedMarker = marker; + break; + } + } + if (matchedMarker != null) { + insertions.add((offset: original.length, marker: matchedMarker)); + sourceOffset += matchedMarker.length; + } else { + original.writeCharCode(source.codeUnitAt(sourceOffset)); + sourceOffset += 1; + } + } + if (insertions.isEmpty) return; + + final originalSource = original.toString(); + final ranges = Map.identity(); + parseInvocations += 1; + final inlines = const MarkdownAstAdapter().convertInlineNodes( + _mappingDocument.parseInline(originalSource), + sourceMappings: ranges, + mappingSource: originalSource, + ); + + void addVariants(List siblings) { + for (final inline in siblings) { + final range = ranges[inline]; + final labelStart = range?.labelStart; + final labelEnd = range?.labelEnd; + if (inline.kind == BusyInlineKind.link && + labelStart != null && + labelEnd != null) { + final originalLabel = originalSource.substring(labelStart, labelEnd); + final normalizedLabel = busyMarkParserReferenceLabel(originalLabel); + final reference = normalizedLabel == null + ? null + : _referenceDefinitions[normalizedLabel]; + final labelInsertions = insertions + .where( + (insertion) => + insertion.offset >= labelStart && + insertion.offset <= labelEnd, + ) + .toList(growable: false); + if (reference != null && labelInsertions.isNotEmpty) { + final markedLabel = StringBuffer(); + var offset = labelStart; + for (final insertion in labelInsertions) { + markedLabel.write( + originalSource.substring(offset, insertion.offset), + ); + markedLabel.write(insertion.marker); + offset = insertion.offset; + } + markedLabel.write(originalSource.substring(offset, labelEnd)); + final label = markedLabel.toString(); + final normalizedMarkedLabel = busyMarkParserReferenceLabel(label); + if (normalizedMarkedLabel != null) { + document.linkReferences[normalizedMarkedLabel] = md.LinkReference( + label, + reference.destination, + reference.title, + ); + } + } + } + addVariants(inline.children); + } + } + + addVariants(inlines); + } + + List parse( + String source, { + Iterable ignoredReferenceLabelMarkers = const [], + }) { + _addReferenceLabelMarkerVariants( + _document, + source, + ignoredReferenceLabelMarkers, + ); + parseInvocations += 1; + return const MarkdownAstAdapter().convertInlineNodes( + _document.parseInline(source), + ); + } + + BusyMarkMappedInlineParse parseMapped( + String source, { + Iterable ignoredReferenceLabelMarkers = const [], + }) { + final markers = ignoredReferenceLabelMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + BusyMarkMappedInlineParse? original; + final originalSemantics = Map.identity(); + List<({int start, int end})> markerSpans = const []; + if (markers.isNotEmpty) { + final buffer = StringBuffer(); + final spans = <({int start, int end})>[]; + var offset = 0; + while (offset < source.length) { + final marker = markers.firstWhere( + (candidate) => source.startsWith(candidate, offset), + orElse: () => '', + ); + if (marker.isEmpty) { + buffer.writeCharCode(source.codeUnitAt(offset)); + offset += 1; + } else { + spans.add((start: offset, end: offset + marker.length)); + offset += marker.length; + } + } + markerSpans = spans; + _emailSyntax.approveOriginals(const {}); + parseInvocations += 1; + final originalRanges = + Map.identity(); + final originalInlines = const MarkdownAstAdapter().convertInlineNodes( + _mappingDocument.parseInline(buffer.toString()), + sourceMappings: originalRanges, + mappingSource: buffer.toString(), + ); + parseInvocations += 1; + final semanticInlines = const MarkdownAstAdapter().convertInlineNodes( + _document.parseInline(buffer.toString()), + ); + + bool sameStructuralIdentity(BusyInline positioned, BusyInline semantic) { + if (positioned.kind != semantic.kind || + positioned.plainText != semantic.plainText || + positioned.destination != semantic.destination || + positioned.attributes.length != semantic.attributes.length) { + return false; + } + for (final entry in positioned.attributes.entries) { + if (semantic.attributes[entry.key] != entry.value) return false; + } + return true; + } + + String structuralKey(BusyInline inline) { + final attributes = inline.attributes.entries.toList() + ..sort((left, right) => left.key.compareTo(right.key)); + final buffer = StringBuffer('${inline.kind.index};') + ..write('${inline.plainText.length}:${inline.plainText};') + ..write( + inline.destination == null + ? '-;' + : '${inline.destination!.length}:${inline.destination};', + ); + for (final attribute in attributes) { + buffer + ..write('${attribute.key.length}:${attribute.key}=') + ..write('${attribute.value.length}:${attribute.value};'); + } + return buffer.toString(); + } + + void associateOriginals( + List positioned, + List semantic, + ) { + final semanticByIdentity = >{}; + for (final semanticInline in semantic) { + semanticByIdentity + .putIfAbsent(structuralKey(semanticInline), () => []) + .add(semanticInline); + } + final consumedByIdentity = {}; + for (final positionedInline in positioned) { + final identity = structuralKey(positionedInline); + final candidates = semanticByIdentity[identity]; + final candidateIndex = consumedByIdentity[identity] ?? 0; + if (candidates == null || candidateIndex >= candidates.length) { + continue; + } + final semanticInline = candidates[candidateIndex]; + consumedByIdentity[identity] = candidateIndex + 1; + if (!sameStructuralIdentity(positionedInline, semanticInline)) { + continue; + } + if (originalRanges.containsKey(positionedInline)) { + originalSemantics[positionedInline] = semanticInline; + } + associateOriginals( + positionedInline.children, + semanticInline.children, + ); + } + } + + associateOriginals(originalInlines, semanticInlines); + original = BusyMarkMappedInlineParse( + inlines: originalInlines, + ranges: originalRanges, + ); + + int markedOffsetForOriginal(int originalOffset, {required bool end}) { + var inserted = 0; + for (final span in markerSpans) { + final insertionOffset = span.start - inserted; + if (insertionOffset > originalOffset || + (!end && insertionOffset == originalOffset)) { + break; + } + inserted += span.end - span.start; + } + return originalOffset + inserted; + } + + final approvedEmails = {}; + for (final entry in originalRanges.entries) { + final semantic = originalSemantics[entry.key]; + final range = entry.value; + if (semantic == null || + !range.isAutolink || + !(semantic.destination?.startsWith('mailto:') ?? false)) { + continue; + } + final start = markedOffsetForOriginal(range.start, end: false); + final end = markedOffsetForOriginal(range.end, end: true); + approvedEmails['$start:$end'] = semantic; + } + _emailSyntax.approveOriginals(approvedEmails); + } else { + _emailSyntax.approveOriginals(const {}); + } + _addReferenceLabelMarkerVariants(_mappingDocument, source, markers); + parseInvocations += 1; + final ranges = Map.identity(); + final inlines = const MarkdownAstAdapter().convertInlineNodes( + _mappingDocument.parseInline(source), + sourceMappings: ranges, + mappingSource: source, + ignoredPositionMarkers: markers, + ); + if (original == null) { + return BusyMarkMappedInlineParse( + inlines: inlines, + ranges: ranges, + sourceStart: 0, + sourceEnd: source.length, + ); + } + + int originalOffsetFor(int markedOffset) { + var removed = 0; + for (final span in markerSpans) { + if (markedOffset <= span.start) break; + removed += math.min(markedOffset, span.end) - span.start; + } + return markedOffset - removed; + } + + String key(BusyInline inline, BusyMarkMappedInlineRange range) => + '${inline.kind.index}:${range.start}:${range.end}'; + final originalsByRange = {}; + for (final entry in original.ranges.entries) { + final semantic = originalSemantics[entry.key]; + if (semantic != null) { + originalsByRange[key(entry.key, entry.value)] = semantic; + } + } + final reconciledRanges = + Map.identity(); + + BusyInline reconcile(BusyInline mapped) { + final mappedRange = ranges[mapped]; + BusyInline? semantic; + if (mappedRange != null) { + final originalRange = BusyMarkMappedInlineRange( + start: originalOffsetFor(mappedRange.start), + end: originalOffsetFor(mappedRange.end), + ); + semantic = originalsByRange[key(mapped, originalRange)]; + } + final children = [for (final child in mapped.children) reconcile(child)]; + final result = mapped.copyWith( + destination: semantic?.destination, + attributes: semantic?.attributes, + children: mapped.children.isEmpty ? mapped.children : children, + ); + if (mappedRange != null) { + reconciledRanges[result] = BusyMarkMappedInlineRange( + start: mappedRange.start, + end: mappedRange.end, + opening: mappedRange.opening, + closing: mappedRange.closing, + labelStart: mappedRange.labelStart, + labelEnd: mappedRange.labelEnd, + lineBreaks: mappedRange.lineBreaks, + originalInline: semantic, + isAutolink: mappedRange.isAutolink, + isReference: mappedRange.isReference, + isSourceLineBreak: mappedRange.isSourceLineBreak, + sourceLineBreakOffset: mappedRange.sourceLineBreakOffset, + ); + } + return result; + } + + final reconciled = [for (final inline in inlines) reconcile(inline)]; + final complete = markers.every( + (marker) => reconciled.any((inline) => inline.plainText.contains(marker)), + ); + if (!complete || + !_sameSemanticsIgnoringMarkers(reconciled, original.inlines, markers)) { + final originalRangesWithSemantics = + Map.identity(); + for (final entry in original.ranges.entries) { + final range = entry.value; + originalRangesWithSemantics[entry.key] = BusyMarkMappedInlineRange( + start: range.start, + end: range.end, + opening: range.opening, + closing: range.closing, + labelStart: range.labelStart, + labelEnd: range.labelEnd, + lineBreaks: range.lineBreaks, + originalInline: originalSemantics[entry.key], + isAutolink: range.isAutolink, + isReference: range.isReference, + isSourceLineBreak: range.isSourceLineBreak, + sourceLineBreakOffset: range.sourceLineBreakOffset, + ); + } + return BusyMarkMappedInlineParse( + inlines: original.inlines, + ranges: originalRangesWithSemantics, + positionRecordsComplete: false, + sourceStart: 0, + sourceEnd: source.length, + ); + } + return BusyMarkMappedInlineParse( + inlines: reconciled, + ranges: reconciledRanges, + sourceStart: 0, + sourceEnd: source.length, + ); + } + + /// Runs the block grammar first, then maps its logical inline content back + /// to [source]. Container markers therefore remain source structure rather + /// than becoming semantic inline text. + BusyMarkMappedInlineParse? parseMappedBlock( + String source, { + required int sourceStart, + required int sourceEnd, + Iterable ignoredReferenceLabelMarkers = const [], + }) { + final markers = ignoredReferenceLabelMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + if (markers.isEmpty) return null; + final sourceLines = _mappedSourceLines(source); + if (sourceLines.isEmpty) return null; + final nodes = md.BlockParser([ + for (final line in sourceLines) md.Line(line.content), + ], _mappingDocument).parseLines(); + final candidates = []; + + void findUnparsed(Iterable values) { + for (final node in values) { + if (node is md.UnparsedContent) { + if (markers.every(node.textContent.contains)) candidates.add(node); + } else if (node is md.Element && node.children != null) { + findUnparsed(node.children!); + } + } + } + + findUnparsed(nodes); + for (final candidate in candidates) { + final projection = _MappedBlockInlineProjection.tryCreate( + source, + sourceLines, + candidate.textContent, + markers.first, + ); + if (projection == null || + !markers.every((marker) { + final offset = candidate.textContent.indexOf(marker); + if (offset < 0) return false; + final rawOffset = projection.rawStartFor(offset); + return rawOffset >= sourceStart && rawOffset <= sourceEnd; + })) { + continue; + } + final mapped = parseMapped( + candidate.textContent, + ignoredReferenceLabelMarkers: markers, + ); + return _translateBlockProjection(mapped, projection); + } + return null; + } + + /// Maps every inline-content candidate in an authored block/container slice + /// without injecting a position marker. Candidates and repeated text are + /// resolved monotonically in physical source order. + List parsePositionedBlocks( + String source, { + int sourceStart = 0, + int? sourceEnd, + }) { + if (source.isEmpty) return const []; + final boundedStart = sourceStart.clamp(0, source.length).toInt(); + final boundedEnd = (sourceEnd ?? source.length) + .clamp(boundedStart, source.length) + .toInt(); + final sourceLines = _mappedSourceLines(source); + if (sourceLines.isEmpty) return const []; + final nodes = md.BlockParser([ + for (final line in sourceLines) md.Line(line.content), + ], _mappingDocument).parseLines(); + final candidates = []; + + void collect(Iterable values) { + for (final node in values) { + if (node is md.UnparsedContent) { + if (node.textContent.isNotEmpty) candidates.add(node.textContent); + } else if (node is md.Text) { + // Block HTML is deliberately retained as raw text by package: + // markdown. It still contains authored prose and must be routed + // through BusyMark's mapped inline/HTML scanner. + if (node.textContent.isNotEmpty) candidates.add(node.textContent); + } else if (node is md.Element && node.children != null) { + collect(node.children!); + } + } + } + + collect(nodes); + final result = []; + var cursor = boundedStart; + for (final candidate in candidates) { + final projection = _MappedBlockInlineProjection.tryCreatePositioned( + source, + sourceLines, + candidate, + minimumSourceOffset: cursor, + maximumSourceOffset: boundedEnd, + ); + if (projection == null) continue; + result.add(_translateBlockProjection(parseMapped(candidate), projection)); + cursor = projection.rawEnd; + } + return List.unmodifiable(result); + } + + BusyMarkMappedInlineParse _translateBlockProjection( + BusyMarkMappedInlineParse mapped, + _MappedBlockInlineProjection projection, + ) { + final ranges = Map.identity(); + for (final entry in mapped.ranges.entries) { + final range = entry.value; + final lineBreaks = []; + + void collectLineBreaks(BusyInline inline, int textOffset) { + final inlineRange = mapped.ranges[inline]; + if (inlineRange?.isSourceLineBreak ?? false) { + final projected = projection.lineBreakAt( + inlineRange!.sourceLineBreakOffset ?? inlineRange.end - 1, + ); + if (projected != null) { + lineBreaks.add( + BusyMarkMappedSourceLineBreak( + textOffset: textOffset, + lineEnding: projected.lineEnding, + continuationPrefix: projected.continuationPrefix, + sourceOffset: projected.sourceOffset, + ), + ); + } + return; + } + var childOffset = textOffset; + for (final child in inline.children) { + collectLineBreaks(child, childOffset); + childOffset += child.plainText.length; + } + } + + collectLineBreaks(entry.key, 0); + ranges[entry.key] = BusyMarkMappedInlineRange( + start: projection.rawStartFor(range.start), + end: projection.rawEndFor(range.end), + opening: range.opening, + closing: range.closing, + labelStart: range.labelStart == null + ? null + : projection.rawStartFor(range.labelStart!), + labelEnd: range.labelEnd == null + ? null + : projection.rawStartFor(range.labelEnd!), + lineBreaks: lineBreaks, + originalInline: range.originalInline, + isAutolink: range.isAutolink, + isReference: range.isReference, + isSourceLineBreak: range.isSourceLineBreak, + sourceLineBreakOffset: range.sourceLineBreakOffset == null + ? null + : projection.rawStartFor(range.sourceLineBreakOffset!), + ); + } + return BusyMarkMappedInlineParse( + inlines: mapped.inlines, + ranges: ranges, + positionRecordsComplete: mapped.positionRecordsComplete, + sourceStart: projection.rawStart, + sourceEnd: projection.rawEnd, + ); + } +} + +bool _sameSemanticsIgnoringMarkers( + List left, + List right, + List markers, +) { + String clean(String value) { + var result = value; + for (final marker in markers) { + result = result.replaceAll(marker, ''); + } + return result; + } + + String encodeValue(String? value) => + value == null ? '-' : '${value.length}:$value'; + + late String Function(List) encodeSiblings; + + String encodeInline(BusyInline inline) { + final attributes = inline.attributes.entries.toList() + ..sort((left, right) => left.key.compareTo(right.key)); + final children = encodeSiblings(inline.children); + final text = inline.children.isEmpty ? clean(inline.text) : ''; + return '${inline.kind.index};${encodeValue(text)};' + '${encodeValue(inline.destination)};' + '${attributes.map((entry) => '${encodeValue(entry.key)}=${encodeValue(entry.value)}').join()};' + '{$children}'; + } + + encodeSiblings = (List inlines) { + final result = StringBuffer(); + String? pendingText; + Map? pendingAttributes; + + void flushText() { + if (pendingText == null) return; + result.write( + encodeInline( + BusyInline( + kind: BusyInlineKind.text, + text: pendingText!, + attributes: pendingAttributes!, + ), + ), + ); + pendingText = null; + pendingAttributes = null; + } + + for (final inline in inlines) { + if (inline.kind == BusyInlineKind.text && inline.children.isEmpty) { + final text = clean(inline.text); + if (text.isEmpty) continue; + if (pendingText != null && + _sameStringMap(pendingAttributes!, inline.attributes)) { + pendingText = '$pendingText$text'; + } else { + flushText(); + pendingText = text; + pendingAttributes = inline.attributes; + } + } else { + flushText(); + result.write(encodeInline(inline)); + } + } + flushText(); + return result.toString(); + }; + + return encodeSiblings(left) == encodeSiblings(right); +} + +bool _sameStringMap(Map left, Map right) { + if (left.length != right.length) return false; + return left.entries.every((entry) => right[entry.key] == entry.value); +} + +class _MappedSourceLine { + const _MappedSourceLine({ + required this.content, + required this.contentStart, + required this.contentEnd, + required this.end, + }); + + final String content; + final int contentStart; + final int contentEnd; + final int end; +} + +List<_MappedSourceLine> _mappedSourceLines(String source) { + final lines = <_MappedSourceLine>[]; + var start = 0; + while (start < source.length) { + var contentEnd = start; + while (contentEnd < source.length && + source.codeUnitAt(contentEnd) != 0x0a && + source.codeUnitAt(contentEnd) != 0x0d) { + contentEnd += 1; + } + var end = contentEnd; + if (end < source.length) { + if (source.codeUnitAt(end) == 0x0d && + end + 1 < source.length && + source.codeUnitAt(end + 1) == 0x0a) { + end += 2; + } else { + end += 1; + } + } + lines.add( + _MappedSourceLine( + content: source.substring(start, contentEnd), + contentStart: start, + contentEnd: contentEnd, + end: end, + ), + ); + start = end; + } + return lines; +} + +class _MappedBlockInlineProjection { + _MappedBlockInlineProjection({ + required this.source, + required this.rawOffsets, + required this.logicalLineStarts, + required this.rawLineStarts, + required this.sourceLines, + required this.firstSourceLine, + }); + + static _MappedBlockInlineProjection? tryCreate( + String source, + List<_MappedSourceLine> sourceLines, + String logicalSource, + String anchor, + ) { + if (logicalSource.isEmpty) return null; + final logicalLines = logicalSource.split('\n'); + final logicalAnchor = logicalSource.indexOf(anchor); + final rawAnchor = source.indexOf(anchor); + if (logicalAnchor < 0 || rawAnchor < 0) return null; + final logicalAnchorLine = '\n' + .allMatches(logicalSource.substring(0, logicalAnchor)) + .length; + final rawAnchorLine = sourceLines.indexWhere( + (line) => rawAnchor >= line.contentStart && rawAnchor < line.end, + ); + final firstSourceLine = rawAnchorLine - logicalAnchorLine; + if (rawAnchorLine < 0 || + firstSourceLine < 0 || + firstSourceLine + logicalLines.length > sourceLines.length) { + return null; + } + + final positions = []; + for (var index = 0; index < logicalLines.length; index++) { + final logicalLine = logicalLines[index]; + final sourceLine = sourceLines[firstSourceLine + index]; + final position = sourceLine.content.indexOf(logicalLine); + if (position < 0) return null; + positions.add(sourceLine.contentStart + position); + } + + final rawOffsets = []; + final logicalLineStarts = []; + for (var index = 0; index < logicalLines.length; index++) { + logicalLineStarts.add(rawOffsets.length); + final lineStart = positions[index]; + for ( + var character = 0; + character < logicalLines[index].length; + character++ + ) { + rawOffsets.add(lineStart + character); + } + if (index + 1 < logicalLines.length) { + final sourceLine = sourceLines[firstSourceLine + index]; + if (sourceLine.end == sourceLine.contentEnd) return null; + rawOffsets.add(sourceLine.end - 1); + } + } + if (rawOffsets.length != logicalSource.length) return null; + return _MappedBlockInlineProjection( + source: source, + rawOffsets: rawOffsets, + logicalLineStarts: logicalLineStarts, + rawLineStarts: positions, + sourceLines: sourceLines, + firstSourceLine: firstSourceLine, + ); + } + + static _MappedBlockInlineProjection? tryCreatePositioned( + String source, + List<_MappedSourceLine> sourceLines, + String logicalSource, { + required int minimumSourceOffset, + required int maximumSourceOffset, + }) { + if (logicalSource.isEmpty || sourceLines.isEmpty) return null; + final logicalLines = logicalSource.split('\n'); + for ( + var firstSourceLine = 0; + firstSourceLine + logicalLines.length <= sourceLines.length; + firstSourceLine++ + ) { + final positions = []; + var valid = true; + for (var index = 0; index < logicalLines.length; index++) { + final sourceLine = sourceLines[firstSourceLine + index]; + final searchFrom = index == 0 + ? math.max(0, minimumSourceOffset - sourceLine.contentStart) + : 0; + if (searchFrom > sourceLine.content.length) { + valid = false; + break; + } + final position = sourceLine.content.indexOf( + logicalLines[index], + searchFrom, + ); + final rawPosition = sourceLine.contentStart + position; + if (position < 0 || + rawPosition < minimumSourceOffset || + rawPosition + logicalLines[index].length > maximumSourceOffset) { + valid = false; + break; + } + positions.add(rawPosition); + } + if (!valid) continue; + return _fromLinePositions( + source, + sourceLines, + logicalLines, + positions, + firstSourceLine, + ); + } + return null; + } + + static _MappedBlockInlineProjection? _fromLinePositions( + String source, + List<_MappedSourceLine> sourceLines, + List logicalLines, + List positions, + int firstSourceLine, + ) { + final rawOffsets = []; + final logicalLineStarts = []; + for (var index = 0; index < logicalLines.length; index++) { + logicalLineStarts.add(rawOffsets.length); + final lineStart = positions[index]; + for ( + var character = 0; + character < logicalLines[index].length; + character++ + ) { + rawOffsets.add(lineStart + character); + } + if (index + 1 < logicalLines.length) { + final sourceLine = sourceLines[firstSourceLine + index]; + if (sourceLine.end == sourceLine.contentEnd) return null; + rawOffsets.add(sourceLine.end - 1); + } + } + if (rawOffsets.length != logicalLines.join('\n').length || + rawOffsets.isEmpty) { + return null; + } + return _MappedBlockInlineProjection( + source: source, + rawOffsets: rawOffsets, + logicalLineStarts: logicalLineStarts, + rawLineStarts: positions, + sourceLines: sourceLines, + firstSourceLine: firstSourceLine, + ); + } + + final String source; + final List rawOffsets; + final List logicalLineStarts; + final List rawLineStarts; + final List<_MappedSourceLine> sourceLines; + final int firstSourceLine; + int get rawStart => rawOffsets.first; + int get rawEnd => rawOffsets.last + 1; + late final Map + _lineBreaksByLogicalOffset = _createLineBreaksByLogicalOffset(); + + int rawStartFor(int offset) { + if (offset < rawOffsets.length) return rawOffsets[offset]; + return rawOffsets.last + 1; + } + + int rawEndFor(int offset) { + if (offset <= 0) return rawOffsets.first; + return rawOffsets[offset - 1] + 1; + } + + BusyMarkMappedSourceLineBreak? lineBreakAt(int logicalOffset) { + return _lineBreaksByLogicalOffset[logicalOffset]; + } + + Map _createLineBreaksByLogicalOffset() { + final result = {}; + for (var line = 0; line + 1 < logicalLineStarts.length; line++) { + final newlineOffset = logicalLineStarts[line + 1] - 1; + final sourceLine = sourceLines[firstSourceLine + line]; + final nextRawOffset = rawLineStarts[line + 1]; + result[newlineOffset] = BusyMarkMappedSourceLineBreak( + textOffset: newlineOffset, + lineEnding: source.substring(sourceLine.contentEnd, sourceLine.end), + continuationPrefix: source.substring(sourceLine.end, nextRawOffset), + sourceOffset: sourceLine.contentEnd, + ); + } + return Map.unmodifiable(result); + } +} + +class MarkdownSourceMapper { + const MarkdownSourceMapper(); + + BusyMarkInlineParserContext createInlineParserContext({ + required String documentSource, + required MarkdownMode mode, + }) { + final referenceDocument = busyMarkMarkdownDocument(mode) + ..parse(documentSource); + final document = busyMarkMarkdownDocument(mode) + ..linkReferences.addAll(referenceDocument.linkReferences); + final emailSyntax = _SourceMappingEmailAutolinkSyntax(); + final mappingDocument = busyMarkMarkdownDocument( + mode, + leadingInlineSyntaxes: _sourceMappingInlineSyntaxes(emailSyntax), + )..linkReferences.addAll(referenceDocument.linkReferences); + return BusyMarkInlineParserContext._( + document: document, + mappingDocument: mappingDocument, + referenceDefinitions: Map.unmodifiable(referenceDocument.linkReferences), + emailSyntax: emailSyntax, + ); + } +} diff --git a/lib/src/markdown/markdown_source_structure.dart b/lib/src/markdown/markdown_source_structure.dart new file mode 100644 index 00000000..cae83e4b --- /dev/null +++ b/lib/src/markdown/markdown_source_structure.dart @@ -0,0 +1,150 @@ +import '../core/source_span.dart'; +import 'busymark_document.dart'; + +class BusyMarkMarkdownTableCellRegion { + const BusyMarkMarkdownTableCellRegion({ + required this.table, + required this.cell, + required this.row, + required this.column, + required this.span, + }); + + final BusyBlock table; + final BusyBlock cell; + final int row; + final int column; + final SourceSpan span; +} + +class BusyMarkSourceLineBounds { + const BusyMarkSourceLineBounds({required this.start, required this.end}); + + final int start; + final int end; +} + +/// Returns the physical line containing an insertion position. +/// +/// The preceding line break is searched strictly before [offset]. A position +/// on a line feed therefore belongs to the line ending there, while a position +/// immediately after it belongs to the following line. +BusyMarkSourceLineBounds busyMarkSourceLineBounds(String source, int offset) { + final position = offset.clamp(0, source.length).toInt(); + final precedingBreak = position == 0 + ? -1 + : source.lastIndexOf('\n', position - 1); + final followingBreak = source.indexOf('\n', position); + return BusyMarkSourceLineBounds( + start: precedingBreak + 1, + end: followingBreak < 0 ? source.length : followingBreak, + ); +} + +/// Maps modeled Markdown table cells back to their exact source content spans. +/// Pipes escaped with a backslash remain cell content rather than delimiters. +List busyMarkMarkdownTableCellRegions({ + required String source, + required BusyBlock table, +}) { + final tableSpan = table.sourceSpan; + if (tableSpan == null || + tableSpan.startOffset < 0 || + tableSpan.endOffset > source.length) { + return const []; + } + final raw = source.substring(tableSpan.startOffset, tableSpan.endOffset); + final lines = <({String text, int offset})>[]; + var offset = 0; + for (final rawLine in raw.split(RegExp('(?<=\n)'))) { + var text = rawLine; + if (text.endsWith('\n')) text = text.substring(0, text.length - 1); + if (text.endsWith('\r')) text = text.substring(0, text.length - 1); + lines.add((text: text, offset: offset)); + offset += rawLine.length; + } + final regions = []; + for (final (rowIndex, row) in table.children.indexed) { + final lineIndex = rowIndex == 0 ? 0 : rowIndex + 1; + if (lineIndex >= lines.length) break; + final line = lines[lineIndex]; + final spans = busyMarkMarkdownTableCellSpans(line.text); + for (final (column, cell) in row.children.indexed) { + if (column >= spans.length) break; + final local = spans[column]; + regions.add( + BusyMarkMarkdownTableCellRegion( + table: table, + cell: cell, + row: rowIndex, + column: column, + span: SourceSpan.fromOffsets( + filePath: tableSpan.filePath, + source: source, + startOffset: tableSpan.startOffset + line.offset + local.start, + endOffset: tableSpan.startOffset + line.offset + local.end, + ), + ), + ); + } + } + return regions; +} + +/// Returns absolute-within-line content spans without treating indentation +/// outside an optional leading pipe as a table cell. +List<({int start, int end})> busyMarkMarkdownTableCellSpans(String line) { + final delimiters = []; + var escaped = false; + for (var index = 0; index < line.length; index++) { + final codeUnit = line.codeUnitAt(index); + if (codeUnit == 0x5c && !escaped) { + escaped = true; + continue; + } + if (codeUnit == 0x7c && !escaped) delimiters.add(index); + escaped = false; + } + var meaningfulStart = 0; + while (meaningfulStart < line.length && + _horizontalWhitespace(line.codeUnitAt(meaningfulStart))) { + meaningfulStart++; + } + var meaningfulEnd = line.length; + while (meaningfulEnd > meaningfulStart && + _horizontalWhitespace(line.codeUnitAt(meaningfulEnd - 1))) { + meaningfulEnd--; + } + final hasLeadingOuterPipe = + meaningfulStart < meaningfulEnd && delimiters.contains(meaningfulStart); + final hasTrailingOuterPipe = + meaningfulEnd > meaningfulStart && delimiters.contains(meaningfulEnd - 1); + final contentStart = hasLeadingOuterPipe ? meaningfulStart : 0; + final contentEnd = hasTrailingOuterPipe ? meaningfulEnd : line.length; + final contentDelimiters = delimiters + .where((offset) => offset >= contentStart && offset < contentEnd) + .toList(growable: false); + final boundaries = [contentStart, ...contentDelimiters, contentEnd]; + final spans = <({int start, int end})>[]; + for (var index = 0; index < boundaries.length - 1; index++) { + if (index == 0 && hasLeadingOuterPipe) { + continue; + } + if (index == boundaries.length - 2 && hasTrailingOuterPipe) { + continue; + } + var start = boundaries[index] + (index == 0 ? 0 : 1); + var end = boundaries[index + 1]; + while (start < end && _horizontalWhitespace(line.codeUnitAt(start))) { + start++; + } + while (end > start && _horizontalWhitespace(line.codeUnitAt(end - 1))) { + end--; + } + spans.add((start: start, end: end)); + } + return spans; +} + +bool _horizontalWhitespace(int codeUnit) => + codeUnit == 0x20 || codeUnit == 0x09; diff --git a/lib/src/markdown/math_syntax.dart b/lib/src/markdown/math_syntax.dart index 3ae29ec0..7d5ae86c 100644 --- a/lib/src/markdown/math_syntax.dart +++ b/lib/src/markdown/math_syntax.dart @@ -1,6 +1,7 @@ import 'package:markdown/markdown.dart' as md; import 'markdown_model.dart'; +import 'markdown_source_annotation.dart'; import 'writerside_variable_syntax.dart'; const busyMarkMathInlineTag = 'busymark-math-inline'; @@ -27,10 +28,14 @@ BusyMathSourceForm busyMathSourceFormFromName(String? value) { ); } -md.Document busyMarkMarkdownDocument(MarkdownMode mode) { +md.Document busyMarkMarkdownDocument( + MarkdownMode mode, { + Iterable leadingInlineSyntaxes = const [], +}) { return md.Document( blockSyntaxes: const [BusyDisplayMathSyntax()], inlineSyntaxes: [ + ...leadingInlineSyntaxes, if (mode == MarkdownMode.writersideMarkdown) WritersideLiteralPercentSyntax(), BusyDollarMathSyntax(), @@ -41,6 +46,14 @@ md.Document busyMarkMarkdownDocument(MarkdownMode mode) { ); } +/// Returns the exact key the pinned Markdown parser registers for [label]. +/// This deliberately uses the parser rather than maintaining a second +/// whitespace or Unicode case-folding implementation in BusyMark. +String? busyMarkParserReferenceLabel(String label) { + final document = md.Document(encodeHtml: false)..parse('[$label]: /'); + return document.linkReferences.keys.singleOrNull; +} + class BusyDollarMathSyntax extends md.InlineSyntax { BusyDollarMathSyntax() : super(r'\$', startCharacter: 0x24); @@ -65,6 +78,8 @@ class BusyDollarMathSyntax extends md.InlineSyntax { expression, BusyMathSourceForm.githubDollarBacktick, display: false, + sourceStart: start, + sourceEnd: end + 2, ), ); parser.consume(end + 2 - start); @@ -91,6 +106,8 @@ class BusyDollarMathSyntax extends md.InlineSyntax { expression, BusyMathSourceForm.dollarInline, display: false, + sourceStart: start, + sourceEnd: end + 1, ), ); parser.consume(end + 1 - start); @@ -188,6 +205,8 @@ class BusyWritersideMathSyntax extends md.InlineSyntax { BusyMathSourceForm.writersideElement, display: false, rawExpression: rawExpression, + sourceStart: match.start, + sourceEnd: closeEnd, ), ); parser.consume(closeEnd - match.start); @@ -280,6 +299,8 @@ md.Element _mathElement( BusyMathSourceForm sourceForm, { required bool display, String? rawExpression, + int? sourceStart, + int? sourceEnd, }) { return md.Element.text(tag, expression) ..attributes[busyMarkMathExpressionAttribute] = expression @@ -288,6 +309,9 @@ md.Element _mathElement( ..attributes.addAll({ if (rawExpression != null) busyMarkMathRawExpressionAttribute: rawExpression, + if (sourceStart != null) + busyMarkSourceMappingStartAttribute: '$sourceStart', + if (sourceEnd != null) busyMarkSourceMappingEndAttribute: '$sourceEnd', }); } diff --git a/lib/src/markdown/raw_html_adapter.dart b/lib/src/markdown/raw_html_adapter.dart index 236294be..66063c57 100644 --- a/lib/src/markdown/raw_html_adapter.dart +++ b/lib/src/markdown/raw_html_adapter.dart @@ -1,10 +1,22 @@ import 'package:html/dom.dart' as html; import 'package:html/parser.dart' as html_parser; +// The public parser does not expose authored closing-tag spans. Its tokenizer +// is the parser's own location-aware boundary source, not a second HTML parser. +// ignore: implementation_imports +import 'package:html/src/token.dart' as html_token; +// ignore: implementation_imports +import 'package:html/src/tokenizer.dart' as html_tokenizer; import '../core/path_utils.dart'; import 'busymark_document.dart'; import 'raw_html_policy.dart'; +/// Reports one indexed ownership lookup per semantic HTML break while source +/// metadata is collected. Tests use this to guard against per-break rescans. +void Function(int lookups)? debugBusyMarkStandaloneBreakLayoutLookups; + +final RegExp _htmlWhitespaceUnit = RegExp(r'\s'); + class RawHtmlBlockParseResult { const RawHtmlBlockParseResult({required this.safe, this.blocks = const []}); @@ -12,6 +24,32 @@ class RawHtmlBlockParseResult { final List blocks; } +class RawHtmlInlineSourceRange { + const RawHtmlInlineSourceRange({ + required this.start, + required this.end, + this.opening, + this.closing, + this.sourceLineBreakOffset, + }); + + final int start; + final int end; + final String? opening; + final String? closing; + final int? sourceLineBreakOffset; +} + +class RawHtmlInlineParseResult { + RawHtmlInlineParseResult({ + required this.inlines, + required Map ranges, + }) : ranges = Map.unmodifiable(ranges); + + final List inlines; + final Map ranges; +} + class RawHtmlAdapter { const RawHtmlAdapter(); @@ -40,10 +78,50 @@ class RawHtmlAdapter { } List? parseRawHtmlInlineFragment(String text) { + if (!_mayContainHtml(text)) return null; + final normalized = _HtmlSourceProjection.create( + text, + standaloneBreakLayoutRemovals(text), + ).normalized; + final fragment = _parseFragment(normalized); + if (fragment == null) return null; + final elementScan = _HtmlElementScanState(); + if (!_hasElement(fragment.nodes, state: elementScan) || + !_isSafeFragment(fragment, inlineOnly: true)) { + return null; + } + return _trimInlineEdges(_inlinesFromNodes(fragment.nodes)); + } + + /// Parses a complete safe inline HTML fragment and records the authored + /// occurrence occupied by each semantic inline element. + /// + /// The HTML parser's element span covers its opening tag, not necessarily + /// its closing tag. Closing extents are therefore paired from the same HTML + /// tokenizer that feeds the parser. Repaired or inferred DOM nodes without + /// authored spans deliberately receive no source range. + RawHtmlInlineParseResult? parseRawHtmlInlineFragmentWithMetadata( + String text, { + String? sourceText, + Iterable ignoredPositionMarkers = const [], + }) { if (!_mayContainHtml(text)) { return null; } - final fragment = _parseFragment(_normalizeStandaloneBreakLayout(text)); + final source = sourceText ?? text; + final positionMarkers = ignoredPositionMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + final layoutRemovals = _mappedStandaloneBreakLayoutRemovals( + source, + positionMarkers, + ); + final projection = _HtmlSourceProjection.create( + source, + layoutRemovals, + parserText: text, + ); + final fragment = _parseFragment(projection.normalized, generateSpans: true); if (fragment == null) { return null; } @@ -54,37 +132,179 @@ class RawHtmlAdapter { if (!_isSafeFragment(fragment, inlineOnly: true)) { return null; } - return _trimInlineEdges(_inlinesFromNodes(fragment.nodes)); + final context = _RawHtmlInlineMappingContext( + projection: projection, + authoredClosingsByOpeningStart: _authoredElementClosingsByOpeningStart( + projection.normalized, + ), + layout: _StandaloneBreakLayoutIndex(layoutRemovals), + positionMarkers: positionMarkers, + ); + return RawHtmlInlineParseResult( + inlines: _trimInlineEdges( + _inlinesFromNodes(fragment.nodes, mapping: context), + ranges: context.ranges, + ignoredPositionMarkers: positionMarkers, + ), + ranges: context.ranges, + ); } - String _normalizeStandaloneBreakLayout(String source) { - if (!source.contains('\n') && !source.contains('\r')) { - return source; - } - // A CommonMark soft line ending immediately beside an inline
is - // layout whitespace, not another visible break. Remove only those source - // line endings before HTML whitespace collapsing so marker-only lines do - // not add spaces to the editable document model. Explicit indentation - // after a marker line remains intact. - return source - .replaceAll( - RegExp(r'\r?\n[ \t]*(?=)', caseSensitive: false), - '', - ) - .replaceAllMapped( - RegExp(r'()\r?\n', caseSensitive: false), - (match) => match.group(1)!, - ); + List<({int start, int end, int lineFeedOffset})> + _mappedStandaloneBreakLayoutRemovals( + String source, + Iterable ignoredMarkers, + ) { + final markers = ignoredMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + if (markers.isEmpty) return standaloneBreakLayoutRemovals(source); + final unmarked = StringBuffer(); + final starts = []; + final ends = []; + var offset = 0; + while (offset < source.length) { + final marker = markers.firstWhere( + (candidate) => source.startsWith(candidate, offset), + orElse: () => '', + ); + if (marker.isNotEmpty) { + offset += marker.length; + continue; + } + unmarked.writeCharCode(source.codeUnitAt(offset)); + starts.add(offset); + ends.add(offset + 1); + offset += 1; + } + final removals = standaloneBreakLayoutRemovals(unmarked.toString()); + return [ + for (final removal in removals) + if (removal.start < starts.length && removal.end > 0) + ( + start: starts[removal.start], + end: ends[removal.end - 1], + lineFeedOffset: starts[removal.lineFeedOffset], + ), + ]; + } + + /// Source ranges which are layout around standalone `
` tags rather + /// than additional semantic line breaks. + /// + /// Source mapping consumes these exact ranges while recording the real + /// `
` occurrence separately. Keeping this classification here ensures + /// mapped parsing and ordinary raw-HTML parsing use the same rule. + List<({int start, int end, int lineFeedOffset})> + standaloneBreakLayoutRemovals(String source) { + final byLineFeed = {}; + + void add(int start, int end) { + final lineFeedOffset = source.indexOf('\n', start); + if (lineFeedOffset < 0 || lineFeedOffset >= end) return; + final existing = byLineFeed[lineFeedOffset]; + byLineFeed[lineFeedOffset] = ( + start: existing == null + ? start + : existing.start < start + ? existing.start + : start, + end: existing == null + ? end + : existing.end > end + ? existing.end + : end, + lineFeedOffset: lineFeedOffset, + ); + } + + // Token spans, rather than a lexical `
` search, decide which text is + // an actual HTML break. Tag-looking attribute values and comments must not + // alter whitespace classification. + final tokenizer = html_tokenizer.HtmlTokenizer(source, generateSpans: true); + while (tokenizer.moveNext()) { + final token = tokenizer.current; + final span = token.span; + if (token is! html_token.StartTagToken || + token.name?.toLowerCase() != 'br' || + span == null) { + continue; + } + var before = span.start.offset; + while (before > 0) { + final unit = source.codeUnitAt(before - 1); + if (unit != 0x20 && unit != 0x09) break; + before -= 1; + } + if (before > 0 && source.codeUnitAt(before - 1) == 0x0a) { + var lineStart = before - 1; + if (lineStart > 0 && source.codeUnitAt(lineStart - 1) == 0x0d) { + lineStart -= 1; + } + add(lineStart, span.start.offset); + } + + final after = span.end.offset; + if (after < source.length && source.codeUnitAt(after) == 0x0a) { + add(after, after + 1); + } else if (after + 1 < source.length && + source.codeUnitAt(after) == 0x0d && + source.codeUnitAt(after + 1) == 0x0a) { + add(after, after + 2); + } + } + final result = byLineFeed.values.toList() + ..sort((left, right) => left.start.compareTo(right.start)); + return result; } - html.DocumentFragment? _parseFragment(String source) { + html.DocumentFragment? _parseFragment( + String source, { + bool generateSpans = false, + }) { try { - return html_parser.parseFragment(source); + return html_parser.parseFragment(source, generateSpans: generateSpans); } on Object { return null; } } + Map _authoredElementClosingsByOpeningStart( + String source, + ) { + final closings = {}; + final stack = <({String name, int start})>[]; + final tokenizer = html_tokenizer.HtmlTokenizer(source, generateSpans: true); + while (tokenizer.moveNext()) { + final token = tokenizer.current; + final span = token.span; + if (span == null) continue; + if (token is html_token.StartTagToken) { + final name = token.name?.toLowerCase() ?? ''; + if (token.selfClosing || voidHtmlTags.contains(name)) { + closings[span.start.offset] = ( + start: span.end.offset, + end: span.end.offset, + ); + } else { + stack.add((name: name, start: span.start.offset)); + } + continue; + } + if (token is! html_token.EndTagToken) continue; + final name = token.name?.toLowerCase() ?? ''; + final match = stack.lastIndexWhere((entry) => entry.name == name); + if (match < 0) continue; + final opening = stack[match]; + stack.removeRange(match, stack.length); + closings[opening.start] = ( + start: span.start.offset, + end: span.end.offset, + ); + } + return closings; + } + bool _isSafeFragment( html.Node node, { required bool inlineOnly, @@ -577,33 +797,50 @@ class RawHtmlAdapter { ); } - List _inlinesFromNodes(Iterable nodes) { - return [for (final node in nodes) ..._inlineFromNode(node)]; + List _inlinesFromNodes( + Iterable nodes, { + _RawHtmlInlineMappingContext? mapping, + }) { + return [ + for (final node in nodes) ..._inlineFromNode(node, mapping: mapping), + ]; } - List _inlineFromNode(html.Node node) { + List _inlineFromNode( + html.Node node, { + _RawHtmlInlineMappingContext? mapping, + }) { if (node is html.Text) { if (node.data.isEmpty) { return const []; } - final text = _collapseHtmlWhitespace(node.data); - if (text.trim().isEmpty) { - return const []; - } + final text = _collapseHtmlWhitespace( + node.data, + ignoredPositionMarkers: mapping?.positionMarkers ?? const [], + ); return [BusyInline(kind: BusyInlineKind.text, text: text)]; } if (node is html.Element) { - return _inlineFromElement(node); + return _inlineFromElement(node, mapping: mapping); } return const []; } - List _inlineFromElement(html.Element element) { + List _inlineFromElement( + html.Element element, { + _RawHtmlInlineMappingContext? mapping, + }) { final tag = element.localName?.toLowerCase() ?? ''; final attributes = sanitizeHtmlAttributes(tag, element.attributes) ?? {}; - final children = _trimInlineEdges(_inlinesFromNodes(element.nodes)); + // Whitespace inside an inline wrapper separates it from adjacent content. + // Only the containing block/fragment may trim its outer edges. + final children = _inlinesFromNodes(element.nodes, mapping: mapping); final text = _plainText(children); - return switch (tag) { + if (text.trim().isEmpty && + const {'strong', 'b', 'em', 'i', 'u', 's', 'del'}.contains(tag)) { + return children; + } + final List result = switch (tag) { 'strong' || 'b' => [ BusyInline(kind: BusyInlineKind.strong, text: text, children: children), ], @@ -656,7 +893,7 @@ class RawHtmlAdapter { attributes: attributes, ), ], - 'br' => const [BusyInline(kind: BusyInlineKind.hardBreak, text: '\n')], + 'br' => [BusyInline(kind: BusyInlineKind.hardBreak, text: '\n')], 'wbr' => const [], _ => children.isEmpty @@ -670,20 +907,65 @@ class RawHtmlAdapter { ] : children, }; + final span = element.sourceSpan; + if (mapping != null && span != null && result.length == 1) { + final normalizedStart = span.start.offset; + final authoredClosing = + mapping.authoredClosingsByOpeningStart[normalizedStart]; + final normalizedEnd = authoredClosing?.end ?? span.end.offset; + final start = mapping.projection.rawStartFor(normalizedStart); + final end = mapping.projection.rawEndFor(normalizedEnd); + final openingEnd = mapping.projection.rawEndFor(span.end.offset); + final closingStart = authoredClosing == null + ? null + : mapping.projection.rawStartFor(authoredClosing.start); + mapping.ranges[result.single] = RawHtmlInlineSourceRange( + start: start, + end: end, + opening: mapping.projection.source.substring(start, openingEnd), + closing: closingStart == null || closingStart >= end + ? null + : mapping.projection.source.substring(closingStart, end), + sourceLineBreakOffset: tag == 'br' + ? mapping.layout.claimForBreak(start, end) + : null, + ); + } + return result; } - List _trimInlineEdges(List inlines) { + List _trimInlineEdges( + List inlines, { + Map? ranges, + Iterable ignoredPositionMarkers = const [], + }) { if (inlines.isEmpty) { return const []; } final result = [...inlines]; if (result.first.kind == BusyInlineKind.text) { - result[0] = result.first.copyWith(text: result.first.text.trimLeft()); + final previous = result.first; + result[0] = previous.copyWith( + text: _trimHtmlTextEdge( + previous.text, + ignoredPositionMarkers, + left: true, + ), + ); + final range = ranges?.remove(previous); + if (range != null) ranges![result[0]] = range; } if (result.last.kind == BusyInlineKind.text) { - result[result.length - 1] = result.last.copyWith( - text: result.last.text.trimRight(), + final previous = result.last; + result[result.length - 1] = previous.copyWith( + text: _trimHtmlTextEdge( + previous.text, + ignoredPositionMarkers, + left: false, + ), ); + final range = ranges?.remove(previous); + if (range != null) ranges![result.last] = range; } return [ for (final inline in result) @@ -706,8 +988,91 @@ class RawHtmlAdapter { inlines.add(BusyInline(kind: BusyInlineKind.text, text: text)); } - String _collapseHtmlWhitespace(String value) { - return value.replaceAll(RegExp(r'\s+'), ' '); + String _collapseHtmlWhitespace( + String value, { + Iterable ignoredPositionMarkers = const [], + }) { + final markers = ignoredPositionMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + if (markers.isEmpty) return value.replaceAll(RegExp(r'\s+'), ' '); + + final result = StringBuffer(); + var inWhitespace = false; + var offset = 0; + while (offset < value.length) { + final marker = markers.firstWhere( + (candidate) => value.startsWith(candidate, offset), + orElse: () => '', + ); + if (marker.isNotEmpty) { + // Position records are zero-width for HTML whitespace processing. + // Keeping [inWhitespace] unchanged projects a position within a + // collapsed run to the boundary selected by its authored offset. + result.write(marker); + offset += marker.length; + continue; + } + final unit = String.fromCharCode(value.codeUnitAt(offset)); + if (_htmlWhitespaceUnit.hasMatch(unit)) { + if (!inWhitespace) result.write(' '); + inWhitespace = true; + } else { + result.writeCharCode(value.codeUnitAt(offset)); + inWhitespace = false; + } + offset += 1; + } + return result.toString(); + } + + String _trimHtmlTextEdge( + String value, + Iterable ignoredPositionMarkers, { + required bool left, + }) { + final markers = ignoredPositionMarkers + .where((marker) => marker.isNotEmpty) + .toList(growable: false); + if (markers.isEmpty) return left ? value.trimLeft() : value.trimRight(); + + final unmarked = StringBuffer(); + var offset = 0; + while (offset < value.length) { + final marker = markers.firstWhere( + (candidate) => value.startsWith(candidate, offset), + orElse: () => '', + ); + if (marker.isNotEmpty) { + offset += marker.length; + } else { + unmarked.writeCharCode(value.codeUnitAt(offset)); + offset += 1; + } + } + final plain = unmarked.toString(); + final keptStart = left ? plain.length - plain.trimLeft().length : 0; + final keptEnd = left ? plain.length : plain.trimRight().length; + final result = StringBuffer(); + var plainOffset = 0; + offset = 0; + while (offset < value.length) { + final marker = markers.firstWhere( + (candidate) => value.startsWith(candidate, offset), + orElse: () => '', + ); + if (marker.isNotEmpty) { + result.write(marker); + offset += marker.length; + continue; + } + if (plainOffset >= keptStart && plainOffset < keptEnd) { + result.writeCharCode(value.codeUnitAt(offset)); + } + plainOffset += 1; + offset += 1; + } + return result.toString(); } String _plainTextFromNodes(Iterable nodes) { @@ -754,6 +1119,147 @@ class RawHtmlAdapter { } } +class _RawHtmlInlineMappingContext { + _RawHtmlInlineMappingContext({ + required this.projection, + required this.authoredClosingsByOpeningStart, + required this.layout, + required this.positionMarkers, + }); + + final _HtmlSourceProjection projection; + final Map authoredClosingsByOpeningStart; + final _StandaloneBreakLayoutIndex layout; + final List positionMarkers; + final Map ranges = Map.identity(); +} + +class _HtmlSourceProjection { + const _HtmlSourceProjection({ + required this.source, + required this.normalized, + required this.rawStarts, + required this.rawEnds, + required this.rawLength, + }); + + factory _HtmlSourceProjection.create( + String source, + List<({int start, int end, int lineFeedOffset})> removals, { + String? parserText, + }) { + final parsed = parserText ?? source; + final parsedRawStarts = []; + final parsedRawEnds = []; + var rawOffset = 0; + for (var parsedOffset = 0; parsedOffset < parsed.length; parsedOffset++) { + final unit = parsed.codeUnitAt(parsedOffset); + if (rawOffset < source.length && source.codeUnitAt(rawOffset) == unit) { + parsedRawStarts.add(rawOffset); + parsedRawEnds.add(rawOffset + 1); + rawOffset += 1; + continue; + } + if (rawOffset + 1 < source.length && + source.codeUnitAt(rawOffset) == 0x5c && + source.codeUnitAt(rawOffset + 1) == unit) { + parsedRawStarts.add(rawOffset); + parsedRawEnds.add(rawOffset + 2); + rawOffset += 2; + continue; + } + if (unit == 0x0a && + rawOffset + 1 < source.length && + source.codeUnitAt(rawOffset) == 0x0d && + source.codeUnitAt(rawOffset + 1) == 0x0a) { + parsedRawStarts.add(rawOffset); + parsedRawEnds.add(rawOffset + 2); + rawOffset += 2; + continue; + } + final found = source.indexOf(String.fromCharCode(unit), rawOffset); + if (found >= 0) { + parsedRawStarts.add(found); + parsedRawEnds.add(found + 1); + rawOffset = found + 1; + } else { + final boundary = rawOffset.clamp(0, source.length).toInt(); + parsedRawStarts.add(boundary); + parsedRawEnds.add(boundary); + } + } + final normalized = StringBuffer(); + final rawStarts = []; + final rawEnds = []; + var removalIndex = 0; + for (var offset = 0; offset < parsed.length; offset++) { + final start = parsedRawStarts[offset]; + final end = parsedRawEnds[offset]; + while (removalIndex < removals.length && + removals[removalIndex].end <= start) { + removalIndex += 1; + } + if (removalIndex < removals.length && + start >= removals[removalIndex].start && + end <= removals[removalIndex].end) { + continue; + } + normalized.writeCharCode(parsed.codeUnitAt(offset)); + rawStarts.add(start); + rawEnds.add(end); + } + return _HtmlSourceProjection( + source: source, + normalized: normalized.toString(), + rawStarts: rawStarts, + rawEnds: rawEnds, + rawLength: source.length, + ); + } + + final String source; + final String normalized; + final List rawStarts; + final List rawEnds; + final int rawLength; + + int rawStartFor(int offset) { + if (rawStarts.isEmpty || offset >= rawStarts.length) return rawLength; + if (offset <= 0) return rawStarts.first; + return rawStarts[offset]; + } + + int rawEndFor(int offset) { + if (rawEnds.isEmpty || offset <= 0) return 0; + if (offset > rawEnds.length) return rawLength; + return rawEnds[offset - 1]; + } +} + +class _StandaloneBreakLayoutIndex { + _StandaloneBreakLayoutIndex( + List<({int start, int end, int lineFeedOffset})> removals, + ) : _afterTag = { + for (final removal in removals) removal.start: removal.lineFeedOffset, + }, + _beforeTag = { + for (final removal in removals) removal.end: removal.lineFeedOffset, + }; + + final Map _afterTag; + final Map _beforeTag; + final Set _claimedLineFeeds = {}; + + int? claimForBreak(int start, int end) { + debugBusyMarkStandaloneBreakLayoutLookups?.call(1); + final after = _afterTag[end]; + if (after != null && _claimedLineFeeds.add(after)) return after; + final before = _beforeTag[start]; + if (before != null && _claimedLineFeeds.add(before)) return before; + return null; + } +} + class _HtmlWalkState { var nodes = 0; diff --git a/lib/src/platform/native_menu_service.dart b/lib/src/platform/native_menu_service.dart index 090de857..fae6e370 100644 --- a/lib/src/platform/native_menu_service.dart +++ b/lib/src/platform/native_menu_service.dart @@ -28,6 +28,7 @@ final class NativeMenuEntry { this.enabled = true, this.checkable = false, this.selected = false, + this.mutuallyExclusive = false, }) : separator = false, children = null; @@ -40,6 +41,7 @@ final class NativeMenuEntry { shortcut = null, checkable = false, selected = false, + mutuallyExclusive = false, separator = false; const NativeMenuEntry.separator() @@ -50,6 +52,7 @@ final class NativeMenuEntry { enabled = false, checkable = false, selected = false, + mutuallyExclusive = false, separator = true, children = null; @@ -60,6 +63,7 @@ final class NativeMenuEntry { final bool enabled; final bool checkable; final bool selected; + final bool mutuallyExclusive; final bool separator; final List? children; @@ -72,6 +76,7 @@ final class NativeMenuEntry { 'enabled': enabled, 'checkable': checkable, 'selected': selected, + 'mutuallyExclusive': mutuallyExclusive, 'separator': separator, if (children != null) 'children': [for (final child in children!) child._toPlatformMap()], diff --git a/lib/src/spellcheck/markdown_spelling_projection.dart b/lib/src/spellcheck/markdown_spelling_projection.dart new file mode 100644 index 00000000..7171935d --- /dev/null +++ b/lib/src/spellcheck/markdown_spelling_projection.dart @@ -0,0 +1,1263 @@ +import 'dart:math' as math; + +import 'package:html/parser.dart' as html; + +import '../core/source_span.dart'; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_fence.dart'; +import '../markdown/markdown_model.dart'; +import '../markdown/markdown_parser.dart'; +import '../markdown/markdown_source_map.dart'; +import '../markdown/markdown_source_structure.dart'; +import 'spelling_projection.dart'; +import 'spelling_text_patterns.dart'; + +final class MarkdownSpellingProjector { + const MarkdownSpellingProjector({this.parser = const MarkdownParser()}); + + final MarkdownParser parser; + + SpellingProjectionResult project({ + required String filePath, + required String source, + required MarkdownMode mode, + required String languageId, + required SpellingSnapshotIdentity snapshot, + SpellingSourceContext proseContext = SpellingSourceContext.markdownProse, + }) { + final parsed = parser.parse( + filePath: filePath, + source: source, + mode: mode, + validateLocalReferences: false, + ); + final chunks = parser.positionedSourceChunks( + filePath: filePath, + source: source, + mode: mode, + ); + final inlineParser = const MarkdownSourceMapper().createInlineParserContext( + documentSource: source, + mode: mode, + ); + final excludedBlockSpans = [ + ...parsed.codeBlocks.map((block) => block.span), + for (final block in _walkBlocks(parsed.busyDocument.blocks)) + if ((block.kind == BusyBlockKind.math || + block.kind == BusyBlockKind.codeBlock) && + block.sourceSpan != null) + block.sourceSpan!, + ]; + final fencedCodeSpans = _fencedCodeSpans(source); + final footnoteLabels = {}; + void collectFootnotes(BusyInline inline) { + final destination = inline.destination; + if (inline.kind == BusyInlineKind.link && + (inline.attributes['id']?.startsWith('fnref-') ?? false) && + destination != null && + destination.startsWith('#fn-')) { + footnoteLabels.add( + Uri.decodeComponent(destination.substring(4)).toLowerCase(), + ); + } + for (final child in inline.children) { + collectFootnotes(child); + } + } + + for (final block in _walkBlocks(parsed.busyDocument.blocks)) { + for (final inline in block.inlines) { + collectFootnotes(inline); + } + } + final tables = [ + for (final block in _walkBlocks(parsed.busyDocument.blocks)) + if (block.kind == BusyBlockKind.table && + !block.attributes.containsKey('header')) + block, + ]; + final runs = []; + final multilineHtmlSpans = _multilineHtmlSpans(source, 0, source.length); + var complete = true; + var sequence = 0; + + void addMapped( + int mappedStart, + int mappedEnd, + BusyMarkMappedInlineParse mapped, { + required int sourceBase, + required int sourceLimit, + required bool stripBlockSyntax, + required SpellingSourceContext context, + }) { + final multilineHtml = multilineHtmlSpans; + final formattingSyntax = _formattingSyntaxSpans([ + mapped, + ], sourceBase: sourceBase); + final opaqueSyntax = <_SourceInterval>[ + ..._opaqueSyntaxSpans([mapped], sourceBase: sourceBase), + for (final span in excludedBlockSpans) + if (span.startOffset < sourceLimit && span.endOffset > sourceBase) + _SourceInterval(span.startOffset, span.endOffset), + for (final span in fencedCodeSpans) + if (span.start < sourceLimit && span.end > sourceBase) span, + if (mode == MarkdownMode.writersideMarkdown) + for (final variable in parsed.variables) + if (variable.span.startOffset < sourceLimit && + variable.span.endOffset > sourceBase) + _SourceInterval( + variable.span.startOffset, + variable.span.endOffset, + ), + for (final html in multilineHtml) + _SourceInterval(html.opaqueStart, html.opaqueEnd), + ]..sort((left, right) => left.start.compareTo(right.start)); + final scanner = _MarkdownProseScanner( + source: source, + start: mappedStart, + end: mappedEnd, + context: context, + stripBlockSyntax: stripBlockSyntax, + footnoteLabels: footnoteLabels, + formattingSyntax: formattingSyntax, + formattingWrappers: _formattingWrappers([ + mapped, + ], sourceBase: sourceBase), + opaqueSyntax: opaqueSyntax, + ); + final groups = + <_EmissionGroup>[ + ...scanner.scan(), + for (final html in multilineHtml) + if (html.tagStart >= mappedStart && html.tagStart < mappedEnd) + for (final attribute in html.readableAttributes) + ..._MarkdownProseScanner( + source: source, + start: attribute.start, + end: attribute.end, + context: attribute.context, + stripBlockSyntax: false, + ).scan(), + ]..sort((left, right) { + final leftStart = left.atoms.firstOrNull?.sourceStart ?? 0; + final rightStart = right.atoms.firstOrNull?.sourceStart ?? 0; + return leftStart.compareTo(rightStart); + }); + complete = complete && scanner.complete; + for (final group in groups) { + if (group.text.trim().isEmpty) continue; + final run = SpellingProseRun( + id: 'markdown:${sequence++}:$mappedStart', + text: group.text, + languageId: languageId, + atoms: List.unmodifiable(group.atoms), + target: SpellingSourceTarget(filePath: filePath), + snapshot: snapshot, + formattingWrappers: group.formattingWrappers, + complete: scanner.complete, + tokenizationContext: group.tokenizationContext, + tokenizationContextStart: group.tokenizationContextStart, + ); + if (!run.hasValidMapping) { + complete = false; + continue; + } + runs.add(run); + } + } + + void addScanned( + int start, + int end, { + required SpellingSourceContext context, + bool stripBlockSyntax = true, + }) { + if (start < 0 || end > source.length || end <= start) { + complete = false; + return; + } + final slice = source.substring(start, end); + final mapped = stripBlockSyntax + ? inlineParser.parsePositionedBlocks(slice) + : [inlineParser.parseMapped(slice)]; + if (stripBlockSyntax && mapped.isNotEmpty) { + for (final semanticLeaf in mapped) { + final leafStart = semanticLeaf.sourceStart; + final leafEnd = semanticLeaf.sourceEnd; + if (leafStart == null || leafEnd == null) { + complete = false; + continue; + } + if (leafEnd <= leafStart) continue; + addMapped( + start + leafStart, + start + leafEnd, + semanticLeaf, + sourceBase: start, + sourceLimit: end, + stripBlockSyntax: true, + context: context, + ); + } + return; + } + if (stripBlockSyntax && mapped.isEmpty) return; + addMapped( + start, + end, + mapped.single, + sourceBase: start, + sourceLimit: end, + stripBlockSyntax: false, + context: context, + ); + } + + final consumedTables = {}; + for (final chunk in chunks) { + if (chunk.sourceOnly || + excludedBlockSpans.any((span) => _contains(span, chunk.span)) || + fencedCodeSpans.any( + (span) => + span.start <= chunk.span.startOffset && + span.end >= chunk.span.endOffset, + ) || + _startsExcludedBlock(chunk.rawSource)) { + continue; + } + if (chunk.rawSource.trimLeft().startsWith(r'$$')) { + final local = parser + .parse( + filePath: filePath, + source: chunk.rawSource, + mode: mode, + validateLocalReferences: false, + ) + .busyDocument + .blocks; + if (local.length == 1 && local.single.kind == BusyBlockKind.math) { + continue; + } + } + var table = tables.where((candidate) { + final span = candidate.sourceSpan; + return span != null && _sameSpan(span, chunk.span); + }).firstOrNull; + if (table == null && + tables.any((candidate) => candidate.sourceSpan == null) && + chunk.rawSource.contains('|')) { + // A document-wide AST/scanner mismatch can omit spans from otherwise + // ordinary tables. Reparse the already-positioned slice to establish + // its structure; never match a table to source by its cell text. + final local = parser + .parse( + filePath: filePath, + source: chunk.rawSource, + mode: mode, + validateLocalReferences: false, + ) + .busyDocument + .blocks; + if (local.length == 1 && local.single.kind == BusyBlockKind.table) { + table = local.single.copyWith(sourceSpan: chunk.span); + } + } + if (table != null) { + if (!consumedTables.add( + '${chunk.span.startOffset}:${chunk.span.endOffset}', + )) { + continue; + } + final regions = busyMarkMarkdownTableCellRegions( + source: source, + table: table, + ); + if (regions.isEmpty && table.children.isNotEmpty) complete = false; + for (final region in regions) { + addScanned( + region.span.startOffset, + region.span.endOffset, + context: SpellingSourceContext.markdownTableCell, + stripBlockSyntax: false, + ); + } + continue; + } + addScanned( + chunk.span.startOffset, + chunk.span.endOffset, + context: proseContext, + ); + } + return SpellingProjectionResult( + runs: List.unmodifiable(runs), + complete: complete, + message: complete ? null : 'Some Markdown regions could not be mapped.', + ); + } +} + +Iterable _walkBlocks(Iterable blocks) sync* { + for (final block in blocks) { + yield block; + yield* _walkBlocks(block.children); + } +} + +bool _contains(SourceSpan outer, SourceSpan inner) => + outer.startOffset <= inner.startOffset && + outer.endOffset >= inner.endOffset; + +bool _sameSpan(SourceSpan left, SourceSpan right) => + left.startOffset == right.startOffset && left.endOffset == right.endOffset; + +bool _startsExcludedBlock(String raw) { + final trimmed = raw.trimLeft().replaceFirst(RegExp(r'^(?:>[ \t]*)+'), ''); + return RegExp(r'^(?:```|~~~)').hasMatch(trimmed) || + RegExp( + r'^(?:', cursor + 4); + _barrier(); + _opaqueEnd = close < 0 || close >= end ? end : close + 3; + if (close < 0 || close >= end) complete = false; + continue; + } + var address = spellingPlainAddress.matchAsPrefix(source, cursor); + // A link label's boundary can fall inside a greedy URL match (the next + // character is its closing bracket). Recheck only that bounded label. + var addressEnd = address?.end; + if (address != null && address.end > rangeEnd) { + address = spellingPlainAddress.matchAsPrefix( + source.substring(cursor, rangeEnd), + ); + addressEnd = address == null ? null : cursor + address.end; + } + if (address != null) { + _barrier(); + cursor = addressEnd!; + continue; + } + final unit = source.codeUnitAt(cursor); + if (unit == 0x5c && + cursor + 1 < rangeEnd && + _commonMarkEscapableAsciiPunctuation(source.codeUnitAt(cursor + 1))) { + final escaped = source.substring(cursor + 1, cursor + 2); + _emit( + escaped, + cursor, + cursor + 2, + SpellingTransformationKind.markdownEscape, + ); + cursor += 2; + continue; + } + if (unit == 0x26) { + final entity = _entity.matchAsPrefix(source, cursor); + if (entity != null && entity.end <= rangeEnd) { + final raw = entity.group(0)!; + final decoded = html.parseFragment(raw).text ?? ''; + if (decoded != raw && decoded.isNotEmpty) { + _emit( + decoded, + cursor, + entity.end, + SpellingTransformationKind.entity, + ); + cursor = entity.end; + continue; + } + } + } + if (unit == 0x21 && + cursor + 1 < rangeEnd && + source.codeUnitAt(cursor + 1) == 0x5b) { + final imageEnd = _scanLinkOrImage(cursor, rangeEnd, image: true); + if (imageEnd != null) { + cursor = imageEnd; + continue; + } + } + if (unit == 0x5b) { + final linkEnd = _scanLinkOrImage(cursor, rangeEnd, image: false); + if (linkEnd != null) { + cursor = linkEnd; + continue; + } + } + if (unit == 0x3c) { + final tagCandidate = _isHtmlTagCandidate(cursor); + final autolinkCandidate = _isAutolinkCandidate(cursor); + if (tagCandidate || autolinkCandidate) { + final close = _htmlTagEnd(cursor); + if (close < 0) { + if (tagCandidate) complete = false; + } else { + final raw = source.substring(cursor, close + 1); + if (_autolink.hasMatch(raw) || _emailAutolink.hasMatch(raw)) { + _barrier(); + if (close >= rangeEnd) _opaqueEnd = close + 1; + cursor = math.min(rangeEnd, close + 1); + continue; + } + final parsedTag = RegExp( + r'^<\s*(/?)\s*([A-Za-z][A-Za-z0-9:-]*)\b', + ).firstMatch(raw); + final closingTag = parsedTag?.group(1)?.isNotEmpty ?? false; + final tag = parsedTag?.group(2)?.toLowerCase(); + if (!closingTag && + tag != null && + _opaqueHtmlElements.contains(tag) && + !raw.trimRight().endsWith('/>')) { + final closing = RegExp( + '', + caseSensitive: false, + ).firstMatch(source.substring(close + 1, end)); + _barrier(); + if (closing == null) { + complete = false; + _opaqueEnd = end; + } else { + _opaqueEnd = close + 1 + closing.end; + } + continue; + } + final semanticBoundary = + tag == 'br' || + tag == 'hr' || + tag != null && _blockHtmlElements.contains(tag); + if (semanticBoundary) _barrier(); + if (!closingTag) _scanHumanReadableAttributes(cursor, close + 1); + if (semanticBoundary) _barrier(); + if (close >= rangeEnd) _opaqueEnd = close + 1; + cursor = math.min(rangeEnd, close + 1); + continue; + } + } + } + final rune = _codePointAt(source, cursor); + final width = rune > 0xffff ? 2 : 1; + _emit( + source.substring(cursor, cursor + width), + cursor, + cursor + width, + SpellingTransformationKind.identity, + ); + cursor += width; + } + } + + bool _isHtmlTagCandidate(int start) { + if (start + 1 >= end) return false; + final tail = source.substring(start, math.min(end, start + 128)); + return RegExp(r'^|$)').hasMatch(tail) || + RegExp(r'^<(?:!|\?)').hasMatch(tail); + } + + bool _isAutolinkCandidate(int start) { + if (start + 1 >= end) return false; + final tail = source.substring(start, math.min(end, start + 256)); + return RegExp(r'^<[A-Za-z][A-Za-z0-9+.-]*:').hasMatch(tail) || + RegExp(r'^<[^\s<>@]+@').hasMatch(tail); + } + + int _htmlTagEnd(int start) { + int? quote; + for (var cursor = start + 1; cursor < end; cursor++) { + final unit = source.codeUnitAt(cursor); + if (quote != null) { + if (unit == quote) quote = null; + } else if (unit == 0x22 || unit == 0x27) { + quote = unit; + } else if (unit == 0x3e) { + return cursor; + } + } + return -1; + } + + int? _scanLinkOrImage(int cursor, int rangeEnd, {required bool image}) { + final opening = cursor + (image ? 1 : 0); + final labelEnd = _matchingBracket(opening, rangeEnd, 0x5b, 0x5d); + if (labelEnd == null) return null; + final afterLabel = labelEnd + 1; + final label = source.substring(opening + 1, labelEnd); + if (!image && + label.startsWith('^') && + footnoteLabels.contains(label.substring(1).toLowerCase())) { + _barrier(); + return afterLabel; + } + var syntaxEnd = afterLabel; + int? titleStart; + int? titleEnd; + SpellingSourceContext? titleContext; + if (afterLabel < rangeEnd && source.codeUnitAt(afterLabel) == 0x28) { + final destinationEnd = _matchingBracket(afterLabel, rangeEnd, 0x28, 0x29); + if (destinationEnd == null) return null; + syntaxEnd = destinationEnd + 1; + final inside = source.substring(afterLabel + 1, destinationEnd); + final title = _trailingLinkTitle(inside); + if (title != null) { + titleContext = title.quote == "'" + ? SpellingSourceContext.markdownSingleQuotedTitle + : SpellingSourceContext.markdownDoubleQuotedTitle; + // The value ends immediately before the closing quote. Derive its + // range from those parsed boundaries rather than searching for its + // contents, which may also occur in the destination. + titleStart = afterLabel + 1 + title.start; + titleEnd = afterLabel + 1 + title.end; + } + } else if (afterLabel < rangeEnd && source.codeUnitAt(afterLabel) == 0x5b) { + final referenceEnd = source.indexOf(']', afterLabel + 1); + if (referenceEnd < 0 || referenceEnd >= rangeEnd) return null; + syntaxEnd = referenceEnd + 1; + } else if (image) { + return null; + } + + if (image) _barrier(); + _scanInline(opening + 1, labelEnd); + if (image) _barrier(); + if (titleStart != null && titleEnd != null && titleEnd > titleStart) { + _barrier(); + final scanner = _MarkdownProseScanner( + source: source, + start: titleStart, + end: titleEnd, + context: titleContext!, + stripBlockSyntax: false, + ); + _groups.addAll(scanner.scan()); + complete = complete && scanner.complete; + _barrier(); + } + return syntaxEnd; + } + + void _scanHumanReadableAttributes(int tagStart, int tagEnd) { + final raw = source.substring(tagStart, tagEnd); + for (final match in _humanAttribute.allMatches(raw)) { + final name = match.group(1)!.toLowerCase(); + if (!_humanAttributeNames.contains(name)) continue; + final quote = match.group(2)!; + final value = match.group(3)!; + // The capture ends with the closing quote, so this is the exact quoted + // value boundary even when [value] also occurs in the attribute name or + // in an earlier attribute. + final valueStart = tagStart + match.end - 1 - value.length; + final savedContext = quote == "'" + ? SpellingSourceContext.xmlSingleQuotedAttribute + : SpellingSourceContext.xmlDoubleQuotedAttribute; + _barrier(); + final scanner = _MarkdownProseScanner( + source: source, + start: valueStart, + end: valueStart + value.length, + context: savedContext, + stripBlockSyntax: false, + ); + _groups.addAll(scanner.scan()); + complete = complete && scanner.complete; + _barrier(); + } + } + + void _emit( + String logical, + int sourceStart, + int sourceEnd, + SpellingTransformationKind transformation, { + String? tokenizationLogical, + }) { + if (logical.isEmpty) return; + _tokenizationContextStart ??= _tokenizationContext.length; + final logicalStart = _text.length; + _text.write(logical); + _tokenizationContext.write(tokenizationLogical ?? logical); + _atoms.add( + SpellingSourceAtom( + logicalText: logical, + logicalStart: logicalStart, + logicalEnd: _text.length, + sourceStart: sourceStart, + sourceEnd: sourceEnd, + transformation: transformation, + context: context, + ), + ); + } + + void _barrier() { + _flush(); + if (_tokenizationContext.isNotEmpty && + !_tokenizationContext.toString().endsWith(' ')) { + _tokenizationContext.write(' '); + } + } + + void _flush() { + if (_text.isNotEmpty) { + final wrappers = []; + for (final wrapper in formattingWrappers) { + final contained = _atoms + .where( + (atom) => + atom.sourceStart >= wrapper.contentStart && + atom.sourceEnd <= wrapper.contentEnd, + ) + .toList(growable: false); + if (contained.isEmpty) continue; + wrappers.add( + SpellingFormattingWrapper( + logicalStart: contained.first.logicalStart, + logicalEnd: contained.last.logicalEnd, + openingStart: wrapper.opening.start, + openingEnd: wrapper.opening.end, + closingStart: wrapper.closing.start, + closingEnd: wrapper.closing.end, + structuralKind: wrapper.kind, + removableWhenLogicallyEmpty: + !opaqueSyntax.any( + (opaque) => + opaque.start < wrapper.contentEnd && + opaque.end > wrapper.contentStart, + ) && + _coversSourceRange(wrapper.contentStart, wrapper.contentEnd, [ + for (final atom in contained) + _SourceInterval(atom.sourceStart, atom.sourceEnd), + for (final syntax in formattingSyntax) + if (syntax.start < wrapper.contentEnd && + syntax.end > wrapper.contentStart) + syntax, + ]), + ), + ); + } + _groups.add( + _PendingEmissionGroup( + text: _text.toString(), + atoms: _atoms, + formattingWrappers: List.unmodifiable(wrappers), + tokenizationContextStart: _tokenizationContextStart!, + ), + ); + } + _text = StringBuffer(); + _atoms = []; + _tokenizationContextStart = null; + } + + List<({int start, int contentEnd})> _lines() { + final result = <({int start, int contentEnd})>[]; + var cursor = start; + while (cursor < end) { + var contentEnd = cursor; + while (contentEnd < end && + source.codeUnitAt(contentEnd) != 0x0a && + source.codeUnitAt(contentEnd) != 0x0d) { + contentEnd++; + } + result.add((start: cursor, contentEnd: contentEnd)); + if (contentEnd >= end) break; + cursor = contentEnd + 1; + if (source.codeUnitAt(contentEnd) == 0x0d && + cursor < end && + source.codeUnitAt(cursor) == 0x0a) { + cursor++; + } + } + return result; + } + + int? _formattingEndAt(int offset) { + for (final span in formattingSyntax) { + if (span.start == offset) return span.end; + if (span.start > offset) return null; + } + return null; + } + + int? _opaqueEndAt(int offset) { + for (final span in opaqueSyntax) { + if (offset >= span.start && offset < span.end) return span.end; + if (span.start > offset) return null; + } + return null; + } + + int? _matchingBracket(int start, int end, int opening, int closing) { + if (start >= end || source.codeUnitAt(start) != opening) return null; + var depth = 0; + for (var cursor = start; cursor < end; cursor++) { + if (source.codeUnitAt(cursor) == 0x5c) { + cursor++; + continue; + } + final unit = source.codeUnitAt(cursor); + if (unit == opening) depth++; + if (unit == closing && --depth == 0) return cursor; + } + return null; + } +} + +final class _SourceInterval { + const _SourceInterval(this.start, this.end); + + final int start; + final int end; +} + +final class _MultilineHtmlSpan { + const _MultilineHtmlSpan({ + required this.tagStart, + required this.opaqueStart, + required this.opaqueEnd, + required this.readableAttributes, + }); + + final int tagStart; + final int opaqueStart; + final int opaqueEnd; + final List<_HtmlReadableAttribute> readableAttributes; +} + +final class _HtmlReadableAttribute { + const _HtmlReadableAttribute({ + required this.start, + required this.end, + required this.context, + }); + + final int start; + final int end; + final SpellingSourceContext context; +} + +List<_MultilineHtmlSpan> _multilineHtmlSpans( + String source, + int start, + int end, +) { + final result = <_MultilineHtmlSpan>[]; + var cursor = start; + while (cursor < end) { + final opening = source.indexOf('<', cursor); + if (opening < 0 || opening >= end) break; + final candidate = RegExp( + r'^|$)', + ).hasMatch(source.substring(opening, math.min(end, opening + 128))); + if (!candidate) { + cursor = opening + 1; + continue; + } + int? quote; + var close = -1; + for (var index = opening + 1; index < end; index++) { + final unit = source.codeUnitAt(index); + if (quote != null) { + if (unit == quote) quote = null; + } else if (unit == 0x22 || unit == 0x27) { + quote = unit; + } else if (unit == 0x3e) { + close = index; + break; + } + } + if (close < 0) break; + final raw = source.substring(opening, close + 1); + if (!raw.contains(RegExp(r'[\r\n]'))) { + cursor = close + 1; + continue; + } + final parsed = RegExp( + r'^<\s*(/?)\s*([A-Za-z][A-Za-z0-9:-]*)\b', + ).firstMatch(raw); + final closing = parsed?.group(1)?.isNotEmpty ?? false; + final tag = parsed?.group(2)?.toLowerCase(); + var opaqueEnd = close + 1; + if (!closing && + tag != null && + _opaqueHtmlElements.contains(tag) && + !raw.trimRight().endsWith('/>')) { + final closingMatch = RegExp( + '', + caseSensitive: false, + ).firstMatch(source.substring(close + 1, end)); + opaqueEnd = closingMatch == null ? end : close + 1 + closingMatch.end; + } + final attributes = <_HtmlReadableAttribute>[]; + if (!closing && (tag == null || !_opaqueHtmlElements.contains(tag))) { + for (final match in _humanAttribute.allMatches(raw)) { + if (!_humanAttributeNames.contains(match.group(1)!.toLowerCase())) { + continue; + } + final value = match.group(3)!; + final valueStart = opening + match.end - 1 - value.length; + attributes.add( + _HtmlReadableAttribute( + start: valueStart, + end: valueStart + value.length, + context: match.group(2) == "'" + ? SpellingSourceContext.xmlSingleQuotedAttribute + : SpellingSourceContext.xmlDoubleQuotedAttribute, + ), + ); + } + } + result.add( + _MultilineHtmlSpan( + tagStart: opening, + opaqueStart: opening, + opaqueEnd: opaqueEnd, + readableAttributes: List.unmodifiable(attributes), + ), + ); + cursor = opaqueEnd; + } + return List.unmodifiable(result); +} + +({int start, int end, String quote})? _trailingLinkTitle(String value) { + var closing = value.length - 1; + while (closing >= 0 && _horizontalWhitespace(value.codeUnitAt(closing))) { + closing--; + } + if (closing < 0 || (value[closing] != '"' && value[closing] != "'")) { + return null; + } + final quote = value[closing]; + bool escaped(int offset) { + var slashes = 0; + for ( + var cursor = offset - 1; + cursor >= 0 && value.codeUnitAt(cursor) == 0x5c; + cursor-- + ) { + slashes++; + } + return slashes.isOdd; + } + + for (var opening = closing - 1; opening >= 0; opening--) { + if (value[opening] != quote || escaped(opening)) continue; + if (opening > 0 && !_horizontalWhitespace(value.codeUnitAt(opening - 1))) { + continue; + } + return (start: opening + 1, end: closing, quote: quote); + } + return null; +} + +final class _RawFormattingWrapper { + const _RawFormattingWrapper({ + required this.kind, + required this.opening, + required this.contentStart, + required this.contentEnd, + required this.closing, + }); + + final String kind; + final _SourceInterval opening; + final int contentStart; + final int contentEnd; + final _SourceInterval closing; +} + +List<_SourceInterval> _formattingSyntaxSpans( + Iterable parses, { + required int sourceBase, +}) { + final spans = <_SourceInterval>[]; + for (final parse in parses) { + for (final entry in parse.ranges.entries) { + if (!_formattingInlineKinds.contains(entry.key.kind)) continue; + final range = entry.value; + final opening = range.opening; + final closing = range.closing; + if (opening != null && opening.isNotEmpty) { + spans.add( + _SourceInterval( + sourceBase + range.start, + sourceBase + range.start + opening.length, + ), + ); + } + if (closing != null && closing.isNotEmpty) { + spans.add( + _SourceInterval( + sourceBase + range.end - closing.length, + sourceBase + range.end, + ), + ); + } + } + } + spans.sort((left, right) => left.start.compareTo(right.start)); + return List.unmodifiable(spans); +} + +List<_RawFormattingWrapper> _formattingWrappers( + Iterable parses, { + required int sourceBase, +}) { + final wrappers = <_RawFormattingWrapper>[]; + for (final parse in parses) { + for (final entry in parse.ranges.entries) { + if (!_formattingInlineKinds.contains(entry.key.kind)) continue; + final range = entry.value; + final opening = range.opening; + final closing = range.closing; + if (opening == null || + opening.isEmpty || + closing == null || + closing.isEmpty) { + continue; + } + final openingStart = sourceBase + range.start; + final openingEnd = openingStart + opening.length; + final closingEnd = sourceBase + range.end; + final closingStart = closingEnd - closing.length; + if (openingEnd > closingStart) continue; + wrappers.add( + _RawFormattingWrapper( + kind: entry.key.kind.name, + opening: _SourceInterval(openingStart, openingEnd), + contentStart: openingEnd, + contentEnd: closingStart, + closing: _SourceInterval(closingStart, closingEnd), + ), + ); + } + } + wrappers.sort( + (left, right) => left.opening.start.compareTo(right.opening.start), + ); + return List.unmodifiable(wrappers); +} + +List<_SourceInterval> _opaqueSyntaxSpans( + Iterable parses, { + required int sourceBase, +}) { + final spans = <_SourceInterval>[]; + for (final parse in parses) { + for (final entry in parse.ranges.entries) { + if (!_opaqueInlineKinds.contains(entry.key.kind)) continue; + final range = entry.value; + spans.add( + _SourceInterval(sourceBase + range.start, sourceBase + range.end), + ); + } + } + spans.sort((left, right) => left.start.compareTo(right.start)); + return List.unmodifiable(spans); +} + +const _formattingInlineKinds = { + BusyInlineKind.strong, + BusyInlineKind.emphasis, + BusyInlineKind.strikethrough, + BusyInlineKind.underline, +}; + +const _opaqueInlineKinds = { + BusyInlineKind.code, + BusyInlineKind.math, + BusyInlineKind.writersideVariable, +}; + +const _opaqueHtmlElements = {'code', 'pre', 'script', 'style'}; + +const _blockHtmlElements = { + 'address', + 'article', + 'aside', + 'blockquote', + 'body', + 'details', + 'dialog', + 'div', + 'dl', + 'dt', + 'dd', + 'fieldset', + 'figcaption', + 'figure', + 'footer', + 'form', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'header', + 'html', + 'li', + 'main', + 'nav', + 'ol', + 'p', + 'section', + 'summary', + 'table', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr', + 'ul', +}; + +bool _commonMarkEscapableAsciiPunctuation(int unit) => + (unit >= 0x21 && unit <= 0x2f) || + (unit >= 0x3a && unit <= 0x40) || + (unit >= 0x5b && unit <= 0x60) || + (unit >= 0x7b && unit <= 0x7e); + +bool _horizontalWhitespace(int unit) => unit == 0x20 || unit == 0x09; + +bool _coversSourceRange(int start, int end, List<_SourceInterval> intervals) { + if (start >= end) return true; + final ordered = [...intervals] + ..sort((left, right) => left.start.compareTo(right.start)); + var cursor = start; + for (final interval in ordered) { + if (interval.end <= cursor || interval.start >= end) continue; + if (interval.start > cursor) return false; + cursor = math.max(cursor, interval.end); + if (cursor >= end) return true; + } + return false; +} + +bool _isSetextOrThematic(String line) { + final trimmed = line.trim(); + return RegExp(r'^(?:=+|-+)$').hasMatch(trimmed) || + RegExp(r'^(?:\*\s*){3,}$').hasMatch(trimmed) || + RegExp(r'^(?:_\s*){3,}$').hasMatch(trimmed); +} + +final RegExp _blockPrefix = RegExp( + r'^[ \t]{0,3}(?:(?:>[ \t]?)+)?(?:(?:[-+*]|\d+[.)])[ \t]+(?:\[[ xX]\][ \t]+)?)?', +); +final RegExp _entity = RegExp( + r'&(?:#[0-9]{1,7}|#[xX][0-9A-Fa-f]{1,6}|[A-Za-z][A-Za-z0-9]{1,31});', +); +final RegExp _autolink = RegExp(r'^<[A-Za-z][A-Za-z0-9+.-]*:[^ <>]*>$'); +final RegExp _emailAutolink = RegExp(r'^<[^ <>@]+@[^ <>@]+>$'); +final RegExp _humanAttribute = RegExp( + r'''\b([A-Za-z_:][-A-Za-z0-9_:.]*)\s*=\s*(["'])(.*?)\2''', + dotAll: true, +); +const _humanAttributeNames = { + 'alt', + 'title', + 'summary', + 'tooltip', + 'switcher-label', +}; + +int _codePointAt(String value, int offset) { + final first = value.codeUnitAt(offset); + if (first >= 0xd800 && first <= 0xdbff && offset + 1 < value.length) { + final second = value.codeUnitAt(offset + 1); + if (second >= 0xdc00 && second <= 0xdfff) { + return 0x10000 + ((first - 0xd800) << 10) + second - 0xdc00; + } + } + return first; +} diff --git a/lib/src/spellcheck/spelling_catalog.dart b/lib/src/spellcheck/spelling_catalog.dart new file mode 100644 index 00000000..cf1f059b --- /dev/null +++ b/lib/src/spellcheck/spelling_catalog.dart @@ -0,0 +1,541 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; + +enum SpellingDictionaryInstallationKind { downloaded, imported } + +final class SpellingInvalidDictionaryInstallation { + const SpellingInvalidDictionaryInstallation({ + required this.directoryPath, + required this.kind, + required this.error, + this.resourceId, + this.id, + }); + + final String directoryPath; + final SpellingDictionaryInstallationKind kind; + final String error; + final String? resourceId; + final String? id; + + bool matches(String value) => + resourceId == value || id == value || p.basename(directoryPath) == value; +} + +/// Metadata for an immutable dictionary resource BusyMark can acquire. +/// +/// Availability never implies that the pair is installed locally. +final class SpellingDictionaryResource { + const SpellingDictionaryResource({ + required this.resourceId, + required this.id, + required this.locales, + required this.label, + required this.affSourcePath, + required this.dicSourcePath, + required this.affDownloadUrl, + required this.dicDownloadUrl, + required this.affSize, + required this.dicSize, + required this.affSha256, + required this.dicSha256, + required this.sourceRevision, + required this.knownValidProbe, + this.licenseDirectory, + }); + + factory SpellingDictionaryResource.fromJson(Map json) { + String requiredString(String key) { + final value = json[key]?.toString().trim(); + if (value == null || value.isEmpty) { + throw FormatException('Dictionary resource is missing $key.'); + } + return value; + } + + int requiredSize(String key) { + final value = json[key]; + final size = value is int ? value : int.tryParse(value?.toString() ?? ''); + if (size == null || size <= 0) { + throw FormatException('Dictionary resource has an invalid $key.'); + } + return size; + } + + final affUrl = Uri.parse(requiredString('affDownloadUrl')); + final dicUrl = Uri.parse(requiredString('dicDownloadUrl')); + if (affUrl.scheme != 'https' || dicUrl.scheme != 'https') { + throw const FormatException('Dictionary downloads must use HTTPS.'); + } + return SpellingDictionaryResource( + resourceId: requiredString('resourceId'), + id: requiredString('id'), + locales: _requiredLocales(json), + label: requiredString('label'), + affSourcePath: _safeRelative(requiredString('affSourcePath')), + dicSourcePath: _safeRelative(requiredString('dicSourcePath')), + affDownloadUrl: affUrl, + dicDownloadUrl: dicUrl, + affSize: requiredSize('affSize'), + dicSize: requiredSize('dicSize'), + affSha256: requiredString('affSha256'), + dicSha256: requiredString('dicSha256'), + sourceRevision: requiredString('sourceRevision'), + knownValidProbe: requiredString('knownValidProbe'), + licenseDirectory: json['licenseDirectory']?.toString(), + ); + } + + final String resourceId; + final String id; + final List locales; + final String label; + final String affSourcePath; + final String dicSourcePath; + final Uri affDownloadUrl; + final Uri dicDownloadUrl; + final int affSize; + final int dicSize; + final String affSha256; + final String dicSha256; + final String sourceRevision; + + /// A catalog-owned word that must be accepted by this exact resource. + final String knownValidProbe; + final String? licenseDirectory; + + int get downloadSize => affSize + dicSize; + String get fingerprint => '$affSha256:$dicSha256'; + bool supports(String languageId) => + id == languageId || locales.contains(languageId); +} + +/// A validated pair published in application-managed persistent storage. +final class SpellingDictionaryInstallation { + const SpellingDictionaryInstallation({ + required this.resourceId, + required this.id, + required this.locales, + required this.label, + required this.affPath, + required this.dicPath, + required this.affSha256, + required this.dicSha256, + required this.kind, + required this.directoryPath, + required this.sourceRevision, + }); + + factory SpellingDictionaryInstallation.fromJson( + Map json, { + required String rootPath, + }) { + String requiredString(String key) { + final value = json[key]?.toString().trim(); + if (value == null || value.isEmpty) { + throw FormatException('Dictionary installation is missing $key.'); + } + return value; + } + + String installedPath(String key) => + p.normalize(p.join(rootPath, _safeRelative(requiredString(key)))); + return SpellingDictionaryInstallation( + resourceId: requiredString('resourceId'), + id: requiredString('id'), + locales: _requiredLocales(json), + label: requiredString('label'), + affPath: installedPath('affPath'), + dicPath: installedPath('dicPath'), + affSha256: requiredString('affSha256'), + dicSha256: requiredString('dicSha256'), + kind: SpellingDictionaryInstallationKind.values.byName( + requiredString('kind'), + ), + directoryPath: p.normalize(p.absolute(rootPath)), + sourceRevision: requiredString('sourceRevision'), + ); + } + + final String resourceId; + final String id; + final List locales; + final String label; + final String affPath; + final String dicPath; + final String affSha256; + final String dicSha256; + final SpellingDictionaryInstallationKind kind; + final String directoryPath; + final String sourceRevision; + + String get fingerprint => '$affSha256:$dicSha256'; + bool get imported => kind == SpellingDictionaryInstallationKind.imported; + bool supports(String languageId) => + id == languageId || locales.contains(languageId); +} + +/// One language-selector row combining available metadata with local state. +final class SpellingDictionaryEntry { + const SpellingDictionaryEntry({ + required this.id, + required this.locales, + required this.label, + required this.resource, + required this.installation, + }); + + final String id; + final List locales; + final String label; + final SpellingDictionaryResource? resource; + final SpellingDictionaryInstallation? installation; + + bool get installed => installation != null; + bool get imported => installation?.imported ?? false; +} + +final class SpellingDictionaryCatalog { + const SpellingDictionaryCatalog({ + required this.availableEntries, + required this.installations, + required this.unavailableEntries, + this.invalidInstallations = const [], + }); + + final List availableEntries; + final List installations; + final Map unavailableEntries; + final List invalidInstallations; + + List get entries { + final result = [ + for (final resource in availableEntries) + SpellingDictionaryEntry( + id: resource.id, + locales: resource.locales, + label: resource.label, + resource: resource, + installation: installationForResource(resource.resourceId), + ), + for (final installation in installations) + if (installation.imported) + SpellingDictionaryEntry( + id: installation.id, + locales: installation.locales, + label: installation.label, + resource: null, + installation: installation, + ), + ]..sort((left, right) => left.label.compareTo(right.label)); + return List.unmodifiable(result); + } + + SpellingDictionaryResource? availableById(String id) { + for (final entry in availableEntries) { + if (entry.supports(id)) return entry; + } + return null; + } + + SpellingDictionaryInstallation? installedById(String id) { + for (final installation in installations) { + if (installation.id == id) return installation; + } + for (final installation in installations) { + if (installation.locales.contains(id)) return installation; + } + final available = availableById(id); + if (available != null) { + return installationForResource(available.resourceId); + } + return null; + } + + SpellingInvalidDictionaryInstallation? invalidById(String id) { + for (final installation in invalidInstallations) { + if (installation.matches(id)) return installation; + } + final resource = availableById(id); + if (resource != null) { + for (final installation in invalidInstallations) { + if (installation.resourceId == resource.resourceId || + p.basename(installation.directoryPath) == + safeSpellingCatalogResourceName(resource.resourceId)) { + return installation; + } + } + } + return null; + } + + SpellingDictionaryInstallation? installationForResource( + String resourceId, { + SpellingDictionaryInstallationKind? kind, + }) { + for (final installation in installations) { + if (installation.resourceId == resourceId && + (kind == null || installation.kind == kind)) { + return installation; + } + } + return null; + } + + SpellingDictionaryEntry? byId(String id) { + for (final entry in entries) { + if (entry.id == id) return entry; + } + for (final entry in entries) { + if (entry.locales.contains(id)) return entry; + } + return null; + } + + static Future load({ + required String bundledRoot, + String? downloadedRoot, + String? importedRoot, + bool verifyChecksums = true, + }) async { + final available = []; + final installations = []; + final invalidInstallations = []; + final unavailable = {}; + await _loadAvailableManifest( + File(p.join(bundledRoot, 'dictionaries.json')), + entries: available, + unavailable: unavailable, + ); + await _loadInstallations( + downloadedRoot, + expectedKind: SpellingDictionaryInstallationKind.downloaded, + available: available, + verifyChecksums: verifyChecksums, + entries: installations, + unavailable: unavailable, + invalidEntries: invalidInstallations, + ); + await _loadInstallations( + importedRoot, + expectedKind: SpellingDictionaryInstallationKind.imported, + available: available, + verifyChecksums: verifyChecksums, + entries: installations, + unavailable: unavailable, + invalidEntries: invalidInstallations, + ); + available.sort((left, right) => left.label.compareTo(right.label)); + installations.sort((left, right) => left.label.compareTo(right.label)); + return SpellingDictionaryCatalog( + availableEntries: List.unmodifiable(available), + installations: List.unmodifiable(installations), + unavailableEntries: Map.unmodifiable(unavailable), + invalidInstallations: List.unmodifiable(invalidInstallations), + ); + } + + static Future _loadAvailableManifest( + File manifest, { + required List entries, + required Map unavailable, + }) async { + if (!await manifest.exists()) { + unavailable[manifest.path] = 'Dictionary catalog is unavailable.'; + return; + } + try { + final decoded = jsonDecode(await manifest.readAsString()); + if (decoded is! Map || decoded['schemaVersion'] != 2) { + throw const FormatException('Unsupported dictionary catalog.'); + } + final dictionaries = decoded['dictionaries']; + if (dictionaries is! List) { + throw const FormatException('Dictionary catalog has no entries.'); + } + final resourceIds = {}; + final dictionaryIds = {}; + for (final value in dictionaries.whereType()) { + final json = value.cast(); + final id = json['id']?.toString() ?? manifest.path; + try { + final entry = SpellingDictionaryResource.fromJson(json); + if (!resourceIds.add(entry.resourceId)) { + throw FormatException( + 'Duplicate dictionary resource ${entry.resourceId}.', + ); + } + if (!dictionaryIds.add(entry.id)) { + throw FormatException('Duplicate dictionary ID ${entry.id}.'); + } + entries.add(entry); + } on Object catch (error) { + unavailable[id] = error.toString(); + } + } + } on Object catch (error) { + unavailable[manifest.path] = error.toString(); + } + } + + static Future _loadInstallations( + String? rootPath, { + required SpellingDictionaryInstallationKind expectedKind, + required List available, + required bool verifyChecksums, + required List entries, + required Map unavailable, + required List invalidEntries, + }) async { + if (rootPath == null) return; + final root = Directory(rootPath); + if (!await root.exists()) return; + await for (final entity in root.list()) { + if (entity is! Directory || p.basename(entity.path).startsWith('.')) { + continue; + } + final manifest = File(p.join(entity.path, 'manifest.json')); + String? resourceId; + String? id; + try { + if (!await manifest.exists()) { + throw const FormatException('Installation manifest is missing.'); + } + final decoded = jsonDecode(await manifest.readAsString()); + if (decoded is! Map || decoded['schemaVersion'] != 1) { + throw const FormatException('Unsupported installation manifest.'); + } + resourceId = decoded['resourceId']?.toString(); + id = decoded['id']?.toString(); + final installation = SpellingDictionaryInstallation.fromJson( + decoded.cast(), + rootPath: entity.path, + ); + resourceId = installation.resourceId; + id = installation.id; + if (installation.kind != expectedKind) { + throw const FormatException('Dictionary installation kind mismatch.'); + } + if (expectedKind == SpellingDictionaryInstallationKind.downloaded) { + final resource = available + .where( + (candidate) => candidate.resourceId == installation.resourceId, + ) + .firstOrNull; + if (resource == null || + resource.affSha256 != installation.affSha256 || + resource.dicSha256 != installation.dicSha256 || + resource.sourceRevision != installation.sourceRevision) { + throw const FormatException( + 'Downloaded dictionary does not match the shipped catalog.', + ); + } + } + if (entries.any( + (candidate) => candidate.resourceId == installation.resourceId, + )) { + throw FormatException( + 'Duplicate installed resource ${installation.resourceId}.', + ); + } + await _validateInstallationFiles( + installation, + verifyChecksums: verifyChecksums, + ); + entries.add(installation); + } on Object catch (error) { + unavailable[entity.path] = error.toString(); + invalidEntries.add( + SpellingInvalidDictionaryInstallation( + directoryPath: p.normalize(p.absolute(entity.path)), + kind: expectedKind, + error: error.toString(), + resourceId: resourceId, + id: id, + ), + ); + } + } + } +} + +String safeSpellingCatalogResourceName(String value) => + value.replaceAll(RegExp(r'[^A-Za-z0-9_.-]'), '_'); + +final class SpellingResourceLocator { + const SpellingResourceLocator({this.environment, this.resolvedExecutable}); + + final Map? environment; + final String? resolvedExecutable; + + String? locate() { + final processEnvironment = environment ?? Platform.environment; + final executableDirectory = p.dirname( + resolvedExecutable ?? Platform.resolvedExecutable, + ); + final candidates = [ + if (processEnvironment['BUSYMARK_SPELLING_PATH'] case final override?) + override, + if (processEnvironment['SNAP'] case final snapRoot?) + p.join(snapRoot, 'share', 'busymark', 'spelling'), + p.join(executableDirectory, 'share', 'busymark', 'spelling'), + p.normalize( + p.join(executableDirectory, '..', 'share', 'busymark', 'spelling'), + ), + p.join(executableDirectory, 'data', 'flutter_assets', 'spelling'), + ]; + for (final candidate in candidates) { + try { + final manifest = File(p.join(candidate, 'dictionaries.json')); + if (manifest.statSync().type == FileSystemEntityType.file) { + return p.normalize(p.absolute(candidate)); + } + } on FileSystemException { + // Continue through deterministic application-bundle locations. + } + } + return null; + } +} + +List _requiredLocales(Map json) { + final locales = + (json['locales'] as List?) + ?.map((value) => value.toString().trim()) + .where((value) => value.isNotEmpty) + .toList(growable: false) ?? + const []; + if (locales.isEmpty) { + throw const FormatException('Dictionary entry has no locale tags.'); + } + return List.unmodifiable(locales); +} + +String _safeRelative(String value) { + if (p.isAbsolute(value) || p.split(value).contains('..')) { + throw const FormatException('Dictionary path must remain relative.'); + } + return p.posix.joinAll(p.posix.split(value)); +} + +Future _validateInstallationFiles( + SpellingDictionaryInstallation installation, { + required bool verifyChecksums, +}) async { + for (final path in [installation.affPath, installation.dicPath]) { + final stat = await File(path).stat(); + if (stat.type != FileSystemEntityType.file) { + throw FileSystemException('Dictionary resource is missing', path); + } + } + if (!verifyChecksums) return; + final aff = await sha256.bind(File(installation.affPath).openRead()).first; + final dic = await sha256.bind(File(installation.dicPath).openRead()).first; + if (aff.toString() != installation.affSha256 || + dic.toString() != installation.dicSha256) { + throw const FormatException('Dictionary resource checksum mismatch.'); + } +} diff --git a/lib/src/spellcheck/spelling_coordinator.dart b/lib/src/spellcheck/spelling_coordinator.dart new file mode 100644 index 00000000..02554f31 --- /dev/null +++ b/lib/src/spellcheck/spelling_coordinator.dart @@ -0,0 +1,672 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:flutter/foundation.dart'; +import 'package:unorm_dart/unorm_dart.dart' as unicode; + +import 'spelling_projection.dart'; +import 'spelling_worker.dart'; + +typedef SpellingSuggestionLookup = + Future> Function(SpellingEngineContext context, String word); + +enum SpellingPresentationStatus { + languageRequired, + checking, + ready, + dictionaryNotInstalled, + dictionaryUnavailable, + failure, + incomplete, + disabled, +} + +final class SpellingPresentationState { + const SpellingPresentationState({ + required this.status, + required this.occurrences, + required this.complete, + this.message, + }); + + const SpellingPresentationState.languageRequired() + : this( + status: SpellingPresentationStatus.languageRequired, + occurrences: const [], + complete: false, + ); + + final SpellingPresentationStatus status; + final List occurrences; + final bool complete; + final String? message; +} + +final class SpellingAnnotation { + const SpellingAnnotation({ + required this.occurrenceId, + required this.start, + required this.end, + required this.target, + }); + + final String occurrenceId; + final int start; + final int end; + final SpellingEditorTarget target; +} + +final class SpellingCheckRequest { + const SpellingCheckRequest({ + required this.snapshot, + required this.engineContext, + required this.project, + this.automatic = true, + }); + + final SpellingSnapshotIdentity snapshot; + final SpellingEngineContext engineContext; + final Future Function() project; + final bool automatic; +} + +/// Coordinates a reusable worker with one running check and only the newest +/// pending snapshot. Results live outside document state and never dirty it. +final class SpellingCoordinator extends ChangeNotifier { + SpellingCoordinator._(this._worker, this._suggestionLookup); + + static Future start({ + SpellingSuggestionLookup? suggestionLookup, + }) async => + SpellingCoordinator._(await SpellingWorker.start(), suggestionLookup); + + final SpellingWorker _worker; + final SpellingSuggestionLookup? _suggestionLookup; + Timer? _debounce; + _PendingSpellingCheck? _pending; + int _presentationGeneration = 0; + bool _running = false; + bool _closed = false; + final List<_IgnoredOccurrence> _ignoredOccurrences = []; + final Map> _ignoredDocumentWords = {}; + final LinkedHashMap> _runResultCache = + LinkedHashMap(); + + SpellingPresentationState _state = + const SpellingPresentationState.languageRequired(); + SpellingPresentationState get state => _state; + + List get misspellings => _state.occurrences + .where((item) => item.outcome == SpellingCheckOutcome.rejected) + .toList(growable: false); + + List get annotations { + final result = []; + for (final occurrence in misspellings) { + if (_suppressed(occurrence)) continue; + final intervals = occurrence.run.target is SpellingSourceTarget + ? occurrence.sourceIntervals + : occurrence.fieldIntervals; + for (final interval in intervals) { + result.add( + SpellingAnnotation( + occurrenceId: occurrence.id, + start: interval.start, + end: interval.end, + target: occurrence.run.target, + ), + ); + } + } + return List.unmodifiable(result); + } + + void schedule( + SpellingCheckRequest request, { + Duration debounce = const Duration(milliseconds: 250), + }) { + if (_closed) return; + _pending?.complete(); + _pending = _PendingSpellingCheck(request); + _presentationGeneration++; + _worker.cancelChecks(); + _debounce?.cancel(); + _setState( + SpellingPresentationState( + status: SpellingPresentationStatus.checking, + occurrences: const [], + complete: false, + message: _state.message, + ), + ); + _debounce = Timer(debounce, _drain); + } + + Future checkNow(SpellingCheckRequest request) async { + if (_closed) return; + _pending?.complete(); + final pending = _PendingSpellingCheck(request, waitForCompletion: true); + _pending = pending; + _presentationGeneration++; + _worker.cancelChecks(); + _debounce?.cancel(); + _setState( + const SpellingPresentationState( + status: SpellingPresentationStatus.checking, + occurrences: [], + complete: false, + ), + ); + unawaited(_drain()); + await pending.completed; + } + + void showLanguageRequired() { + _cancelPresentation(); + _setState(const SpellingPresentationState.languageRequired()); + } + + void showDictionaryUnavailable(String languageId) { + _cancelPresentation(); + _setState( + SpellingPresentationState( + status: SpellingPresentationStatus.dictionaryUnavailable, + occurrences: const [], + complete: false, + message: languageId, + ), + ); + } + + void showDictionaryNotInstalled(String languageId) { + _cancelPresentation(); + _setState( + SpellingPresentationState( + status: SpellingPresentationStatus.dictionaryNotInstalled, + occurrences: const [], + complete: false, + message: languageId, + ), + ); + } + + void disablePresentation() { + _cancelPresentation(); + _setState( + const SpellingPresentationState( + status: SpellingPresentationStatus.disabled, + occurrences: [], + complete: false, + ), + ); + } + + SpellingOccurrence? occurrenceAtSource(int offset) { + for (final occurrence in misspellings) { + if (_suppressed(occurrence)) continue; + if (occurrence.sourceIntervals.any((range) => range.contains(offset))) { + return occurrence; + } + } + return null; + } + + SpellingOccurrence? occurrenceAtField({ + required SpellingEditorTarget target, + required int offset, + }) { + for (final occurrence in misspellings) { + if (_suppressed(occurrence) || + !_sameTarget(occurrence.run.target, target)) { + continue; + } + if (occurrence.fieldIntervals.any((range) => range.contains(offset))) { + return occurrence; + } + } + return null; + } + + Future> suggestions( + SpellingOccurrence occurrence, { + required SpellingEngineContext context, + }) async { + if (!isCurrent(occurrence)) { + throw StateError('The spelling occurrence is stale.'); + } + if (context.languageId != occurrence.run.languageId) { + throw StateError('The spelling dictionary context changed.'); + } + final result = + await (_suggestionLookup?.call(context, occurrence.word) ?? + _worker.suggestions(context: context, word: occurrence.word)); + if (!isCurrent(occurrence)) { + throw StateError('The spelling occurrence became stale.'); + } + return result; + } + + Future validateDictionary({ + required String affPath, + required String dicPath, + String? knownValidProbe, + }) => _worker.validateDictionary( + affPath: affPath, + dicPath: dicPath, + knownValidProbe: knownValidProbe, + ); + + Future releaseDictionary() => _worker.releaseDictionary(); + + Future project(SpellingProjectionJob job) => + _worker.project(job); + + bool isCurrent(SpellingOccurrence occurrence) => + misspellings.any( + (candidate) => + candidate.id == occurrence.id && + candidate.run.snapshot == occurrence.run.snapshot && + candidate.run.languageId == occurrence.run.languageId && + candidate.word == occurrence.word, + ) && + !_suppressed(occurrence); + + void ignoreOnce(SpellingOccurrence occurrence) { + if (!isCurrent(occurrence)) return; + _ignoredOccurrences.removeWhere((item) => item.matches(occurrence)); + _ignoredOccurrences.add(_IgnoredOccurrence.fromOccurrence(occurrence)); + notifyListeners(); + } + + void ignoreAllInDocument(SpellingOccurrence occurrence) { + if (!isCurrent(occurrence)) return; + _ignoredDocumentWords + .putIfAbsent( + '${occurrence.run.snapshot.bufferId}\u0000${occurrence.run.languageId}', + () => {}, + ) + .add(_temporaryWordKey(occurrence.word)); + notifyListeners(); + } + + void closeBuffer(String bufferId) { + _ignoredDocumentWords.removeWhere( + (key, _) => key.startsWith('$bufferId\u0000'), + ); + _ignoredOccurrences.removeWhere((item) => item.bufferId == bufferId); + } + + /// Drops position-bound suppressions when document contents are replaced + /// without an exact edit transaction (for example, a disk reload). + void invalidateBufferAnchors(String bufferId) { + _ignoredOccurrences.removeWhere((item) => item.bufferId == bufferId); + } + + /// Translates source anchors across a known exact edit. An overlapping edit + /// invalidates Ignore Once instead of guessing a new occurrence. + void translateSourceEdit({ + required String bufferId, + required int start, + required int oldEnd, + required int newEnd, + }) { + final delta = newEnd - oldEnd; + for (var index = _ignoredOccurrences.length - 1; index >= 0; index--) { + final item = _ignoredOccurrences[index]; + if (item.bufferId != bufferId || item.sourceStart == null) continue; + if (item.sourceEnd! > start && item.sourceStart! < oldEnd) { + _ignoredOccurrences.removeAt(index); + } else if (item.sourceStart! >= oldEnd) { + _ignoredOccurrences[index] = item.shifted(delta); + } + } + } + + Future _drain() async { + if (_running || _closed) return; + _running = true; + try { + while (_pending != null) { + final pending = _pending!; + final request = pending.request; + _pending = null; + final generation = _presentationGeneration; + try { + final projection = await request.project(); + if (_closed || generation != _presentationGeneration) continue; + final occurrences = []; + final uncheckedRuns = []; + for (final run in projection.runs) { + final cached = _takeCachedRun(request.engineContext, run); + if (cached == null) { + uncheckedRuns.add(run); + } else { + occurrences.addAll( + cached + .map((item) => item.bind(run)) + .whereType(), + ); + } + } + if (_closed || generation != _presentationGeneration) continue; + if (occurrences.isNotEmpty) { + _publishProgress(occurrences, projection.message); + } + var nativeComplete = true; + String? nativeError; + const batchSize = 12; + for ( + var start = 0; + start < uncheckedRuns.length; + start += batchSize + ) { + final end = (start + batchSize) + .clamp(0, uncheckedRuns.length) + .toInt(); + final batch = uncheckedRuns.sublist(start, end); + final result = await _worker.check( + context: request.engineContext, + runs: batch, + ); + if (_closed || + generation != _presentationGeneration || + result.cancelled) { + break; + } + occurrences.addAll(result.occurrences); + nativeComplete = nativeComplete && result.complete; + nativeError ??= result.error; + if (result.complete) { + for (final run in batch) { + _cacheRunResult( + request.engineContext, + run, + result.occurrences.where( + (occurrence) => identical(occurrence.run, run), + ), + ); + } + } + _publishProgress(occurrences, nativeError ?? projection.message); + } + if (_closed || generation != _presentationGeneration) continue; + final rejected = _orderedRejected(occurrences, projection.runs); + final complete = projection.complete && nativeComplete; + _setState( + SpellingPresentationState( + status: complete + ? SpellingPresentationStatus.ready + : SpellingPresentationStatus.incomplete, + occurrences: rejected, + complete: complete, + message: nativeError ?? projection.message, + ), + ); + } on Object catch (error) { + if (!_closed && generation == _presentationGeneration) { + _setState( + SpellingPresentationState( + status: SpellingPresentationStatus.failure, + occurrences: const [], + complete: false, + message: error.toString(), + ), + ); + } + } finally { + pending.complete(); + } + } + } finally { + _running = false; + if (_pending != null && !_closed) unawaited(_drain()); + } + } + + bool _suppressed(SpellingOccurrence occurrence) { + if (_ignoredOccurrences.any((item) => item.matches(occurrence))) { + return true; + } + final words = + _ignoredDocumentWords['${occurrence.run.snapshot.bufferId}\u0000${occurrence.run.languageId}']; + return words?.contains(_temporaryWordKey(occurrence.word)) ?? false; + } + + void _publishProgress(List occurrences, String? message) { + _setState( + SpellingPresentationState( + status: SpellingPresentationStatus.checking, + occurrences: _orderedRejected( + occurrences, + occurrences.map((occurrence) => occurrence.run).toList(), + ), + complete: false, + message: message, + ), + ); + } + + List _orderedRejected( + Iterable occurrences, + List runs, + ) { + final order = { + for (final (index, run) in runs.indexed) run: index, + }; + final rejected = occurrences + .where((item) => item.outcome == SpellingCheckOutcome.rejected) + .toList(); + rejected.sort((left, right) { + final byRun = (order[left.run] ?? 0).compareTo(order[right.run] ?? 0); + return byRun != 0 + ? byRun + : left.logicalStart.compareTo(right.logicalStart); + }); + return List.unmodifiable(rejected); + } + + List<_CachedRunOccurrence>? _takeCachedRun( + SpellingEngineContext context, + SpellingProseRun run, + ) { + final key = _runCacheKey(context, run); + final cached = _runResultCache.remove(key); + if (cached == null) return null; + _runResultCache[key] = cached; + return cached; + } + + void _cacheRunResult( + SpellingEngineContext context, + SpellingProseRun run, + Iterable occurrences, + ) { + final key = _runCacheKey(context, run); + _runResultCache.remove(key); + _runResultCache[key] = List.unmodifiable( + occurrences.map(_CachedRunOccurrence.fromOccurrence), + ); + while (_runResultCache.length > 512) { + _runResultCache.remove(_runResultCache.keys.first); + } + } + + void _cancelPresentation() { + _presentationGeneration++; + _pending?.complete(); + _pending = null; + _debounce?.cancel(); + _worker.cancelChecks(); + } + + void _setState(SpellingPresentationState state) { + _state = state; + notifyListeners(); + } + + @override + void dispose() { + if (_closed) return; + _closed = true; + _pending?.complete(); + _pending = null; + _debounce?.cancel(); + _worker.cancelChecks(); + unawaited(_worker.close()); + super.dispose(); + } +} + +final class _PendingSpellingCheck { + _PendingSpellingCheck(this.request, {bool waitForCompletion = false}) + : _completer = waitForCompletion ? Completer() : null; + + final SpellingCheckRequest request; + final Completer? _completer; + + Future get completed => _completer?.future ?? Future.value(); + + void complete() { + if (!(_completer?.isCompleted ?? true)) _completer!.complete(); + } +} + +String _temporaryWordKey(String word) => unicode.nfc(word).toLowerCase(); + +String _runCacheKey(SpellingEngineContext context, SpellingProseRun run) => + '${context.identity}\u0000${run.languageId}\u0000' + '${run.tokenizationContextStart}\u0000${run.tokenizationContext}'; + +final class _CachedRunOccurrence { + const _CachedRunOccurrence({ + required this.logicalStart, + required this.logicalEnd, + required this.outcome, + }); + + factory _CachedRunOccurrence.fromOccurrence(SpellingOccurrence occurrence) => + _CachedRunOccurrence( + logicalStart: occurrence.logicalStart, + logicalEnd: occurrence.logicalEnd, + outcome: occurrence.outcome, + ); + + final int logicalStart; + final int logicalEnd; + final SpellingCheckOutcome outcome; + + SpellingOccurrence? bind(SpellingProseRun run) { + if (logicalStart < 0 || + logicalEnd <= logicalStart || + logicalEnd > run.text.length) { + return null; + } + final word = run.text.substring(logicalStart, logicalEnd); + return SpellingOccurrence( + id: + '${run.snapshot.bufferId}:${run.snapshot.contentRevision}:' + '${run.snapshot.documentKind.name}:' + '${run.snapshot.contextGeneration}:${run.languageId}:' + '${run.id}:$logicalStart:$logicalEnd', + run: run, + logicalStart: logicalStart, + logicalEnd: logicalEnd, + word: word, + outcome: outcome, + ); + } +} + +final class _IgnoredOccurrence { + const _IgnoredOccurrence({ + required this.bufferId, + required this.languageId, + required this.word, + required this.target, + required this.sourceStart, + required this.sourceEnd, + required this.fieldStart, + required this.fieldEnd, + }); + + factory _IgnoredOccurrence.fromOccurrence(SpellingOccurrence occurrence) => + _IgnoredOccurrence( + bufferId: occurrence.run.snapshot.bufferId, + languageId: occurrence.run.languageId, + word: occurrence.word, + target: occurrence.run.target, + sourceStart: occurrence.sourceStart, + sourceEnd: occurrence.sourceEnd, + fieldStart: occurrence.fieldStart, + fieldEnd: occurrence.fieldEnd, + ); + + final String bufferId; + final String languageId; + final String word; + final SpellingEditorTarget target; + final int? sourceStart; + final int? sourceEnd; + final int? fieldStart; + final int? fieldEnd; + + bool matches(SpellingOccurrence occurrence) { + if (bufferId != occurrence.run.snapshot.bufferId || + languageId != occurrence.run.languageId || + word != occurrence.word) { + return false; + } + if (sourceStart != null && sourceEnd != null) { + return sourceStart == occurrence.sourceStart && + sourceEnd == occurrence.sourceEnd; + } + return _sameTarget(target, occurrence.run.target) && + fieldStart == occurrence.fieldStart && + fieldEnd == occurrence.fieldEnd; + } + + _IgnoredOccurrence shifted(int delta) => _IgnoredOccurrence( + bufferId: bufferId, + languageId: languageId, + word: word, + target: target, + sourceStart: sourceStart == null ? null : sourceStart! + delta, + sourceEnd: sourceEnd == null ? null : sourceEnd! + delta, + fieldStart: fieldStart, + fieldEnd: fieldEnd, + ); +} + +bool _sameTarget(SpellingEditorTarget left, SpellingEditorTarget right) { + return switch ((left, right)) { + ( + SpellingSourceTarget(:final filePath), + SpellingSourceTarget(filePath: final other), + ) => + filePath == other, + ( + SpellingRichBlockTarget(:final blockId, :final documentGeneration), + SpellingRichBlockTarget( + blockId: final otherBlock, + documentGeneration: final otherGeneration, + ), + ) => + blockId == otherBlock && documentGeneration == otherGeneration, + ( + SpellingRichTableCellTarget( + :final tableBlockId, + :final cellId, + :final documentGeneration, + ), + SpellingRichTableCellTarget( + tableBlockId: final otherTable, + cellId: final otherCell, + documentGeneration: final otherGeneration, + ), + ) => + tableBlockId == otherTable && + cellId == otherCell && + documentGeneration == otherGeneration, + _ => false, + }; +} diff --git a/lib/src/spellcheck/spelling_dictionary_downloader.dart b/lib/src/spellcheck/spelling_dictionary_downloader.dart new file mode 100644 index 00000000..3cc946f2 --- /dev/null +++ b/lib/src/spellcheck/spelling_dictionary_downloader.dart @@ -0,0 +1,216 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'spelling_catalog.dart'; +import 'spelling_dictionary_installer.dart'; + +final class SpellingDictionaryDownloadCancelled implements Exception { + const SpellingDictionaryDownloadCancelled(); + + @override + String toString() => 'Dictionary installation was cancelled.'; +} + +final class SpellingDictionaryDownloadCancellation { + bool _cancelled = false; + final List _callbacks = []; + + bool get isCancelled => _cancelled; + + void cancel() { + if (_cancelled) return; + _cancelled = true; + for (final callback in _callbacks.toList(growable: false)) { + callback(); + } + _callbacks.clear(); + } + + void throwIfCancelled() { + if (_cancelled) throw const SpellingDictionaryDownloadCancelled(); + } + + void register(void Function() callback) { + if (_cancelled) { + callback(); + } else { + _callbacks.add(callback); + } + } + + void unregister(void Function() callback) => _callbacks.remove(callback); +} + +typedef SpellingDictionaryDownloadProgress = + void Function(int receivedBytes, int totalBytes); + +typedef SpellingDictionaryFileDownload = + Future Function({ + required Uri source, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, + }); + +/// Downloads exactly one catalog pair and publishes it through the shared pair +/// installer used by local imports. +final class SpellingDictionaryDownloader { + const SpellingDictionaryDownloader({ + this.installer = const SpellingDictionaryPairInstaller(), + this.downloadFile = _downloadFile, + }); + + final SpellingDictionaryPairInstaller installer; + final SpellingDictionaryFileDownload downloadFile; + + Future install({ + required SpellingDictionaryResource resource, + required String downloadedRoot, + required Future Function( + String affPath, + String dicPath, + String? knownValidProbe, + ) + validateNativePair, + required SpellingDictionaryDownloadCancellation cancellation, + required SpellingDictionaryDownloadProgress onProgress, + bool replaceExisting = false, + }) async { + cancellation.throwIfCancelled(); + final root = Directory(p.normalize(p.absolute(downloadedRoot))); + await root.create(recursive: true); + final downloadStage = await root.createTemp('.busymark-download-'); + final aff = File(p.join(downloadStage.path, 'download.aff')); + final dic = File(p.join(downloadStage.path, 'download.dic')); + var affReceived = 0; + var dicReceived = 0; + void publishProgress() => + onProgress(affReceived + dicReceived, resource.downloadSize); + try { + await downloadFile( + source: resource.affDownloadUrl, + destination: aff, + expectedBytes: resource.affSize, + cancellation: cancellation, + onProgress: (received) { + affReceived = received; + publishProgress(); + }, + ); + cancellation.throwIfCancelled(); + await downloadFile( + source: resource.dicDownloadUrl, + destination: dic, + expectedBytes: resource.dicSize, + cancellation: cancellation, + onProgress: (received) { + dicReceived = received; + publishProgress(); + }, + ); + cancellation.throwIfCancelled(); + return await installer.install( + affSource: aff, + dicSource: dic, + spec: SpellingDictionaryInstallSpec.downloaded(resource), + destinationRoot: root.path, + validateNativePair: validateNativePair, + cancellationGuard: cancellation.throwIfCancelled, + replaceExisting: replaceExisting, + ); + } finally { + if (await downloadStage.exists()) { + await downloadStage.delete(recursive: true); + } + } + } +} + +Future _downloadFile({ + required Uri source, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, +}) async { + const inactivityTimeout = Duration(seconds: 15); + if (source.scheme != 'https') { + throw const FormatException('Dictionary downloads must use HTTPS.'); + } + final client = HttpClient()..autoUncompress = false; + void abort() => client.close(force: true); + cancellation.register(abort); + try { + cancellation.throwIfCancelled(); + final request = await client.getUrl(source).timeout(inactivityTimeout); + request.headers.set(HttpHeaders.acceptEncodingHeader, 'identity'); + final response = await request.close().timeout(inactivityTimeout); + if (response.statusCode != HttpStatus.ok) { + throw HttpException( + 'Dictionary download returned HTTP ${response.statusCode}.', + uri: source, + ); + } + final declaredLength = response.contentLength; + if (declaredLength >= 0 && declaredLength != expectedBytes) { + throw const FormatException( + 'Dictionary download size does not match its catalog.', + ); + } + await receiveSpellingDictionaryBody( + bytes: response, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + inactivityTimeout: inactivityTimeout, + ); + } on Object { + if (cancellation.isCancelled) { + throw const SpellingDictionaryDownloadCancelled(); + } + rethrow; + } finally { + cancellation.unregister(abort); + client.close(force: true); + } +} + +/// Receives one response body with a deadline that resets after every chunk. +/// Kept separate so stalled-transfer behavior can be exercised without a +/// public network dependency. +Future receiveSpellingDictionaryBody({ + required Stream> bytes, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, + Duration inactivityTimeout = const Duration(seconds: 15), +}) async { + IOSink? sink; + try { + sink = destination.openWrite(); + var received = 0; + await for (final chunk in bytes.timeout(inactivityTimeout)) { + cancellation.throwIfCancelled(); + received += chunk.length; + if (received > expectedBytes) { + throw const FormatException('Dictionary download exceeded its size.'); + } + sink.add(chunk); + onProgress(received); + } + await sink.flush(); + await sink.close(); + sink = null; + cancellation.throwIfCancelled(); + if (received != expectedBytes) { + throw const FormatException('Dictionary download was incomplete.'); + } + } finally { + await sink?.close(); + } +} diff --git a/lib/src/spellcheck/spelling_dictionary_importer.dart b/lib/src/spellcheck/spelling_dictionary_importer.dart new file mode 100644 index 00000000..8b2dc843 --- /dev/null +++ b/lib/src/spellcheck/spelling_dictionary_importer.dart @@ -0,0 +1,68 @@ +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; + +import 'spelling_catalog.dart'; +import 'spelling_dictionary_installer.dart'; +import 'spelling_language.dart'; + +final class SpellingDictionaryImporter { + const SpellingDictionaryImporter({ + this.installer = const SpellingDictionaryPairInstaller(), + }); + + final SpellingDictionaryPairInstaller installer; + + Future import({ + required String affPath, + required String dicPath, + required String languageId, + required String displayLabel, + required String importedRoot, + required Future Function( + String affPath, + String dicPath, + String? knownValidProbe, + ) + validateNativePair, + }) async { + final language = normalizeSpellingLanguageId(languageId); + if (language == null || !_languageTag.hasMatch(language)) { + throw const FormatException('Choose an explicit valid language tag.'); + } + final aff = File(p.normalize(p.absolute(affPath))); + final dic = File(p.normalize(p.absolute(dicPath))); + if (p.basenameWithoutExtension(aff.path) != + p.basenameWithoutExtension(dic.path)) { + throw const FormatException( + 'The .aff and .dic files must have the same base name.', + ); + } + final affStat = await aff.stat(); + final dicStat = await dic.stat(); + final affChecksum = await sha256.bind(aff.openRead()).first; + final dicChecksum = await sha256.bind(dic.openRead()).first; + final spec = SpellingDictionaryInstallSpec( + resourceId: language, + id: language, + locales: [language], + label: displayLabel.trim().isEmpty ? language : displayLabel.trim(), + sourceRevision: 'local-import', + affSha256: affChecksum.toString(), + dicSha256: dicChecksum.toString(), + affSize: affStat.size, + dicSize: dicStat.size, + kind: SpellingDictionaryInstallationKind.imported, + ); + return installer.install( + affSource: aff, + dicSource: dic, + spec: spec, + destinationRoot: importedRoot, + validateNativePair: validateNativePair, + ); + } +} + +final RegExp _languageTag = RegExp(r'^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$'); diff --git a/lib/src/spellcheck/spelling_dictionary_installer.dart b/lib/src/spellcheck/spelling_dictionary_installer.dart new file mode 100644 index 00000000..6c11c908 --- /dev/null +++ b/lib/src/spellcheck/spelling_dictionary_installer.dart @@ -0,0 +1,341 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; + +import 'spelling_catalog.dart'; + +const int maximumSpellingAffixBytes = 16 * 1024 * 1024; +const int maximumSpellingDictionaryBytes = 256 * 1024 * 1024; + +final class SpellingDictionaryInstallSpec { + const SpellingDictionaryInstallSpec({ + required this.resourceId, + required this.id, + required this.locales, + required this.label, + required this.sourceRevision, + required this.affSha256, + required this.dicSha256, + required this.affSize, + required this.dicSize, + required this.kind, + this.knownValidProbe, + }); + + factory SpellingDictionaryInstallSpec.downloaded( + SpellingDictionaryResource resource, + ) => SpellingDictionaryInstallSpec( + resourceId: resource.resourceId, + id: resource.id, + locales: resource.locales, + label: resource.label, + sourceRevision: resource.sourceRevision, + affSha256: resource.affSha256, + dicSha256: resource.dicSha256, + affSize: resource.affSize, + dicSize: resource.dicSize, + kind: SpellingDictionaryInstallationKind.downloaded, + knownValidProbe: resource.knownValidProbe, + ); + + final String resourceId; + final String id; + final List locales; + final String label; + final String sourceRevision; + final String affSha256; + final String dicSha256; + final int affSize; + final int dicSize; + final SpellingDictionaryInstallationKind kind; + final String? knownValidProbe; +} + +/// Validates and atomically publishes a complete affix/dictionary pair. +/// +/// Downloads and local imports intentionally share this path. A published +/// directory is always complete and native-loadable; staging directories are +/// ignored by catalog discovery and removed after failure or cancellation. +final class SpellingDictionaryPairInstaller { + const SpellingDictionaryPairInstaller({this.onCommitted}); + + /// Observes the commit point after the staged directory becomes the + /// published installation. The callback must not throw. + final void Function(SpellingDictionaryInstallation installation)? onCommitted; + + Future install({ + required File affSource, + required File dicSource, + required SpellingDictionaryInstallSpec spec, + required String destinationRoot, + required Future Function( + String affPath, + String dicPath, + String? knownValidProbe, + ) + validateNativePair, + void Function()? cancellationGuard, + bool replaceExisting = false, + }) async { + cancellationGuard?.call(); + await validateSpellingDictionaryPair( + affSource: affSource, + dicSource: dicSource, + expectedAffSize: spec.affSize, + expectedDicSize: spec.dicSize, + expectedAffSha256: spec.affSha256, + expectedDicSha256: spec.dicSha256, + ); + final root = Directory(p.normalize(p.absolute(destinationRoot))); + await root.create(recursive: true); + final destination = Directory( + p.join(root.path, safeSpellingResourceName(spec.resourceId)), + ); + if (!p.isWithin(root.path, destination.path)) { + throw StateError('Dictionary installation escaped its storage root.'); + } + if (await destination.exists() && !replaceExisting) { + throw FileSystemException( + 'This dictionary resource is already installed', + destination.path, + ); + } + final staging = await root.createTemp('.busymark-dictionary-'); + final stagedAff = File(p.join(staging.path, 'dictionary.aff')); + final stagedDic = File(p.join(staging.path, 'dictionary.dic')); + try { + await affSource.copy(stagedAff.path); + await dicSource.copy(stagedDic.path); + await validateSpellingDictionaryPair( + affSource: stagedAff, + dicSource: stagedDic, + expectedAffSize: spec.affSize, + expectedDicSize: spec.dicSize, + expectedAffSha256: spec.affSha256, + expectedDicSha256: spec.dicSha256, + ); + cancellationGuard?.call(); + final encoding = (await validateNativePair( + stagedAff.path, + stagedDic.path, + spec.knownValidProbe, + )).trim(); + if (encoding.isEmpty) { + throw const FormatException('Dictionary declares no usable encoding.'); + } + cancellationGuard?.call(); + final manifest = { + 'schemaVersion': 1, + 'kind': spec.kind.name, + 'resourceId': spec.resourceId, + 'id': spec.id, + 'locales': spec.locales, + 'label': spec.label, + 'sourceRevision': spec.sourceRevision, + 'affPath': 'dictionary.aff', + 'dicPath': 'dictionary.dic', + 'affSha256': spec.affSha256, + 'dicSha256': spec.dicSha256, + }; + await File(p.join(staging.path, 'manifest.json')).writeAsString( + '${const JsonEncoder.withIndent(' ').convert(manifest)}\n', + flush: true, + ); + cancellationGuard?.call(); + Directory? replaced; + if (await destination.exists()) { + replaced = Directory( + p.join( + root.path, + '.busymark-replaced-${safeSpellingResourceName(spec.resourceId)}-' + '${DateTime.now().microsecondsSinceEpoch}', + ), + ); + await destination.rename(replaced.path); + } + try { + await staging.rename(destination.path); + } on Object { + if (replaced != null && await replaced.exists()) { + await replaced.rename(destination.path); + } + rethrow; + } + final installation = SpellingDictionaryInstallation( + resourceId: spec.resourceId, + id: spec.id, + locales: List.unmodifiable(spec.locales), + label: spec.label, + affPath: p.join(destination.path, 'dictionary.aff'), + dicPath: p.join(destination.path, 'dictionary.dic'), + affSha256: spec.affSha256, + dicSha256: spec.dicSha256, + kind: spec.kind, + directoryPath: destination.path, + sourceRevision: spec.sourceRevision, + ); + onCommitted?.call(installation); + if (replaced != null && await replaced.exists()) { + await replaced.delete(recursive: true); + } + return installation; + } finally { + if (await staging.exists()) { + await staging.delete(recursive: true); + } + } + } + + Future remove({ + required SpellingDictionaryInstallation installation, + required String installationRoot, + }) async { + final root = p.normalize(p.absolute(installationRoot)); + final target = p.normalize(p.absolute(installation.directoryPath)); + if (!p.isWithin(root, target) || p.equals(root, target)) { + throw StateError('Dictionary removal escaped its storage root.'); + } + final directory = Directory(target); + if (await directory.exists()) await directory.delete(recursive: true); + } + + Future removeInvalid({ + required SpellingInvalidDictionaryInstallation installation, + required String installationRoot, + }) async { + final root = p.normalize(p.absolute(installationRoot)); + final target = p.normalize(p.absolute(installation.directoryPath)); + if (!p.isWithin(root, target) || p.equals(root, target)) { + throw StateError('Dictionary removal escaped its storage root.'); + } + final directory = Directory(target); + if (await directory.exists()) await directory.delete(recursive: true); + } +} + +Future validateSpellingDictionaryPair({ + required File affSource, + required File dicSource, + required int expectedAffSize, + required int expectedDicSize, + required String expectedAffSha256, + required String expectedDicSha256, +}) async { + await _validateFile( + affSource, + maximumSpellingAffixBytes, + expectedAffSize, + '.aff', + ); + await _validateFile( + dicSource, + maximumSpellingDictionaryBytes, + expectedDicSize, + '.dic', + ); + final affChecksum = await sha256.bind(affSource.openRead()).first; + final dicChecksum = await sha256.bind(dicSource.openRead()).first; + if (affChecksum.toString() != expectedAffSha256 || + dicChecksum.toString() != expectedDicSha256) { + throw const FormatException('Dictionary resource checksum mismatch.'); + } + _validateAffixMetadata( + await affSource + .openRead(0, 64 * 1024) + .fold>([], (bytes, part) => bytes..addAll(part)), + ); + final prefix = await dicSource + .openRead(0, 4096) + .fold>([], (bytes, part) => bytes..addAll(part)); + final declaredRecords = _validateDictionaryHeader(prefix); + await _validateDictionaryRecords(dicSource, declaredRecords); +} + +Future _validateFile( + File file, + int maximumBytes, + int expectedBytes, + String extension, +) async { + final stat = await file.stat(); + if (stat.type != FileSystemEntityType.file || + !file.path.toLowerCase().endsWith(extension)) { + throw FileSystemException('Expected a readable $extension file', file.path); + } + if (stat.size <= 0 || + stat.size > maximumBytes || + stat.size != expectedBytes) { + throw FileSystemException( + 'Dictionary resource has an invalid size', + file.path, + ); + } + await file.openRead(0, 1).drain(); +} + +void _validateAffixMetadata(List bytes) { + final prefix = latin1.decode(bytes, allowInvalid: true); + final set = RegExp( + r'^\s*SET\s+([^\s#]+)', + multiLine: true, + caseSensitive: false, + ).firstMatch(prefix); + if (set == null || set.group(1)!.trim().isEmpty) { + throw const FormatException('The .aff file has no SET encoding directive.'); + } +} + +int _validateDictionaryHeader(List bytes) { + final newline = bytes.indexOf(0x0a); + var headerBytes = bytes + .take(newline < 0 ? bytes.length : newline) + .toList(growable: false); + if (headerBytes.length >= 3 && + headerBytes[0] == 0xef && + headerBytes[1] == 0xbb && + headerBytes[2] == 0xbf) { + headerBytes = headerBytes.sublist(3); + } + final header = ascii.decode(headerBytes, allowInvalid: false).trim(); + // A few established Hunspell dictionaries append a numeric, tab-separated + // format revision to the advisory record count (for example `465928\t1`). + // Accept only that well-defined suffix, not arbitrary trailing metadata. + final match = RegExp(r'^([0-9]+)(?:[ \t]+[0-9]+)?$').firstMatch(header); + final count = match == null ? null : int.tryParse(match.group(1)!); + if (count == null || count <= 0) { + throw const FormatException('The .dic header is not a word count.'); + } + return count; +} + +Future _validateDictionaryRecords(File file, int declaredRecords) async { + var line = 0; + var records = 0; + var hasContent = false; + await for (final bytes in file.openRead()) { + for (final byte in bytes) { + if (byte == 0x0a) { + if (line > 0 && hasContent) records++; + line++; + hasContent = false; + } else if (line > 0 && byte != 0x0d && byte != 0x20 && byte != 0x09) { + hasContent = true; + } + } + } + if (line > 0 && hasContent) records++; + // The header is advisory and upstream dictionaries can legitimately drift + // from their physical line count. Native validation subsequently proves + // that the loaded engine accepts a real entry (and, for catalog resources, + // the resource-specific known-valid probe). + if (records == 0) { + throw FormatException( + 'The .dic file declares $declaredRecords records but contains none.', + ); + } +} + +String safeSpellingResourceName(String value) => + value.replaceAll(RegExp(r'[^A-Za-z0-9_.-]'), '_'); diff --git a/lib/src/spellcheck/spelling_inline_projection.dart b/lib/src/spellcheck/spelling_inline_projection.dart new file mode 100644 index 00000000..bc2f63d6 --- /dev/null +++ b/lib/src/spellcheck/spelling_inline_projection.dart @@ -0,0 +1,227 @@ +import '../markdown/busymark_document.dart'; +import 'spelling_projection.dart'; +import 'spelling_text_patterns.dart'; + +final class SpellingInlineProjection { + const SpellingInlineProjection({ + required this.text, + required this.atoms, + String? tokenizationContext, + this.tokenizationContextStart = 0, + }) : _tokenizationContext = tokenizationContext; + + final String text; + final List atoms; + final String? _tokenizationContext; + String get tokenizationContext => _tokenizationContext ?? text; + final int tokenizationContextStart; +} + +final class _PendingInlineProjection { + const _PendingInlineProjection({ + required this.text, + required this.atoms, + required this.tokenizationContextStart, + }); + + final String text; + final List atoms; + final int tokenizationContextStart; +} + +/// Projects editable rich-text leaves while keeping a stable tree address for +/// every emitted atom. Formatting and link containers are transparent; code, +/// math, variables, and embedded HTML form barriers and are omitted. +List projectSpellingInlineRuns({ + required List inlines, + required int sourceBase, + SpellingSourceContext context = SpellingSourceContext.markdownProse, +}) { + final pendingRuns = <_PendingInlineProjection>[]; + var text = StringBuffer(); + final tokenizationContext = StringBuffer(); + int? tokenizationContextStart; + var atoms = []; + var fieldOffset = 0; + + void flush() { + if (text.isNotEmpty && text.toString().trim().isNotEmpty) { + pendingRuns.add( + _PendingInlineProjection( + text: text.toString(), + atoms: List.unmodifiable(atoms), + tokenizationContextStart: tokenizationContextStart!, + ), + ); + } + text = StringBuffer(); + atoms = []; + tokenizationContextStart = null; + } + + void barrier() { + flush(); + if (tokenizationContext.isNotEmpty && + !tokenizationContext.toString().endsWith(' ')) { + tokenizationContext.write(' '); + } + } + + void emitLeaf( + BusyInline inline, + List path, { + String? logicalText, + String? tokenizationText, + SpellingTransformationKind transformation = + SpellingTransformationKind.identity, + }) { + final fieldValue = inline.text; + final value = logicalText ?? fieldValue; + if (value.isEmpty) return; + tokenizationContextStart ??= tokenizationContext.length; + final logicalStart = text.length; + text.write(value); + tokenizationContext.write(tokenizationText ?? value); + atoms.add( + SpellingSourceAtom( + logicalText: value, + logicalStart: logicalStart, + logicalEnd: text.length, + // Current-source locations are added from serializer metadata. A + // negative interval cannot be mistaken for a source offset meanwhile. + sourceStart: sourceBase < 0 ? -1 : sourceBase + fieldOffset, + sourceEnd: sourceBase < 0 + ? -1 + : sourceBase + fieldOffset + fieldValue.length, + fieldStart: fieldOffset, + fieldEnd: fieldOffset + fieldValue.length, + richLeafPath: List.unmodifiable(path), + transformation: transformation, + context: context, + ), + ); + fieldOffset += fieldValue.length; + } + + void visit(BusyInline inline, List path) { + if (inline.kind == BusyInlineKind.link && + (inline.attributes['id']?.startsWith('fnref-') ?? false) && + (inline.destination?.startsWith('#fn-') ?? false)) { + barrier(); + fieldOffset += inline.plainText.length; + return; + } + switch (inline.kind) { + case BusyInlineKind.math: + case BusyInlineKind.code: + case BusyInlineKind.html: + case BusyInlineKind.writersideVariable: + case BusyInlineKind.unknown: + barrier(); + fieldOffset += inline.plainText.length; + return; + case BusyInlineKind.image: + barrier(); + emitLeaf(inline, path); + barrier(); + return; + case BusyInlineKind.softBreak: + case BusyInlineKind.hardBreak: + emitLeaf( + inline, + path, + logicalText: ' ', + tokenizationText: '\n', + transformation: SpellingTransformationKind.lineBreak, + ); + return; + case BusyInlineKind.text: + case BusyInlineKind.strong: + case BusyInlineKind.emphasis: + case BusyInlineKind.underline: + case BusyInlineKind.strikethrough: + case BusyInlineKind.link: + if (inline.children.isEmpty) { + var cursor = 0; + for (final address in spellingPlainAddress.allMatches(inline.text)) { + if (address.start > cursor) { + emitLeaf( + inline.copyWith( + text: inline.text.substring(cursor, address.start), + ), + path, + ); + } + barrier(); + fieldOffset += address.end - address.start; + cursor = address.end; + } + if (cursor < inline.text.length) { + emitLeaf( + inline.copyWith(text: inline.text.substring(cursor)), + path, + ); + } + return; + } + for (final (index, child) in inline.children.indexed) { + visit(child, [...path, index]); + } + } + } + + for (final (index, inline) in inlines.indexed) { + visit(inline, [index]); + } + flush(); + final contextText = tokenizationContext.toString(); + return List.unmodifiable([ + for (final run in pendingRuns) + SpellingInlineProjection( + text: run.text, + atoms: run.atoms, + tokenizationContext: contextText, + tokenizationContextStart: run.tokenizationContextStart, + ), + ]); +} + +SpellingInlineProjection projectSpellingInlines({ + required List inlines, + required int sourceBase, + SpellingSourceContext context = SpellingSourceContext.markdownProse, +}) { + final runs = projectSpellingInlineRuns( + inlines: inlines, + sourceBase: sourceBase, + context: context, + ); + if (runs.isEmpty) { + return const SpellingInlineProjection(text: '', atoms: []); + } + if (runs.length == 1) return runs.single; + final text = StringBuffer(); + final atoms = []; + for (final run in runs) { + if (text.isNotEmpty) text.write(' '); + final base = text.length; + text.write(run.text); + for (final atom in run.atoms) { + atoms.add( + SpellingSourceAtom( + logicalText: atom.logicalText, + logicalStart: base + atom.logicalStart, + logicalEnd: base + atom.logicalEnd, + sourceStart: atom.sourceStart, + sourceEnd: atom.sourceEnd, + fieldStart: atom.fieldStart, + fieldEnd: atom.fieldEnd, + richLeafPath: atom.richLeafPath, + transformation: atom.transformation, + context: atom.context, + ), + ); + } + } + return SpellingInlineProjection(text: text.toString(), atoms: atoms); +} diff --git a/lib/src/spellcheck/spelling_language.dart b/lib/src/spellcheck/spelling_language.dart new file mode 100644 index 00000000..605a233e --- /dev/null +++ b/lib/src/spellcheck/spelling_language.dart @@ -0,0 +1,58 @@ +enum SpellingLanguageOverrideKind { inherit, disabled, selected } + +/// A nullable language cannot distinguish inheritance from an explicit +/// document-level opt-out, so the document state stores both parts. +final class SpellingLanguageOverride { + const SpellingLanguageOverride.inherit() + : kind = SpellingLanguageOverrideKind.inherit, + languageId = null; + + const SpellingLanguageOverride.disabled() + : kind = SpellingLanguageOverrideKind.disabled, + languageId = null; + + const SpellingLanguageOverride.selected(String this.languageId) + : kind = SpellingLanguageOverrideKind.selected; + + final SpellingLanguageOverrideKind kind; + final String? languageId; + + bool get checksSpelling => kind != SpellingLanguageOverrideKind.disabled; + + Map toJson() => { + 'kind': kind.name, + if (languageId != null) 'languageId': languageId, + }; + + factory SpellingLanguageOverride.fromJson(Object? value) { + if (value is! Map) return const SpellingLanguageOverride.inherit(); + final json = value.cast(); + final kind = SpellingLanguageOverrideKind.values.firstWhere( + (candidate) => candidate.name == json['kind'], + orElse: () => SpellingLanguageOverrideKind.inherit, + ); + final language = json['languageId']?.toString().trim(); + return switch (kind) { + SpellingLanguageOverrideKind.disabled => + const SpellingLanguageOverride.disabled(), + SpellingLanguageOverrideKind.selected + when language != null && language.isNotEmpty => + SpellingLanguageOverride.selected(language), + _ => const SpellingLanguageOverride.inherit(), + }; + } + + @override + bool operator ==(Object other) => + other is SpellingLanguageOverride && + other.kind == kind && + other.languageId == languageId; + + @override + int get hashCode => Object.hash(kind, languageId); +} + +String? normalizeSpellingLanguageId(Object? value) { + final trimmed = value?.toString().trim(); + return trimmed == null || trimmed.isEmpty ? null : trimmed; +} diff --git a/lib/src/spellcheck/spelling_projection.dart b/lib/src/spellcheck/spelling_projection.dart new file mode 100644 index 00000000..4d80b6e1 --- /dev/null +++ b/lib/src/spellcheck/spelling_projection.dart @@ -0,0 +1,366 @@ +import '../workspace/workspace_model.dart'; + +enum SpellingTransformationKind { + identity, + markdownEscape, + entity, + lineBreak, + xmlCdata, + serializerEscape, +} + +enum SpellingSourceContext { + markdownProse, + markdownTableCell, + markdownSingleQuotedTitle, + markdownDoubleQuotedTitle, + xmlText, + xmlSingleQuotedAttribute, + xmlDoubleQuotedAttribute, + xmlCdata, +} + +/// Identifies the exact document version against which a projection was made. +final class SpellingSnapshotIdentity { + const SpellingSnapshotIdentity({ + required this.bufferId, + required this.contentRevision, + required this.documentKind, + required this.contextGeneration, + }); + + final String bufferId; + final int contentRevision; + final DocumentKind documentKind; + final int contextGeneration; + + @override + bool operator ==(Object other) => + other is SpellingSnapshotIdentity && + other.bufferId == bufferId && + other.contentRevision == contentRevision && + other.documentKind == documentKind && + other.contextGeneration == contextGeneration; + + @override + int get hashCode => + Object.hash(bufferId, contentRevision, documentKind, contextGeneration); +} + +sealed class SpellingEditorTarget { + const SpellingEditorTarget(); +} + +final class SpellingSourceTarget extends SpellingEditorTarget { + const SpellingSourceTarget({required this.filePath}); + + final String filePath; +} + +final class SpellingRichBlockTarget extends SpellingEditorTarget { + const SpellingRichBlockTarget({ + required this.blockId, + required this.documentGeneration, + }); + + final String blockId; + final int documentGeneration; +} + +final class SpellingRichTableCellTarget extends SpellingEditorTarget { + const SpellingRichTableCellTarget({ + required this.tableBlockId, + required this.cellId, + required this.documentGeneration, + }); + + final String tableBlockId; + final String cellId; + final int documentGeneration; +} + +/// One indivisible authored representation of logical prose. +/// +/// A Markdown entity, for example, is represented by a single atom whose +/// source interval can be longer than its logical text. Replacement planning +/// therefore never overwrites part of an encoded atom. +final class SpellingSourceAtom { + const SpellingSourceAtom({ + required this.logicalText, + required this.logicalStart, + required this.logicalEnd, + required this.sourceStart, + required this.sourceEnd, + required this.transformation, + required this.context, + this.fieldStart, + this.fieldEnd, + this.richLeafPath, + }); + + final String logicalText; + final int logicalStart; + final int logicalEnd; + final int sourceStart; + final int sourceEnd; + final int? fieldStart; + final int? fieldEnd; + final List? richLeafPath; + final SpellingTransformationKind transformation; + final SpellingSourceContext context; + + bool intersectsLogical(int start, int end) => + logicalStart < end && logicalEnd > start; + + /// Maps a logical subrange through this atom without widening a linear + /// representation (plain text and CDATA) to the complete atom. Encoded + /// units remain indivisible because replacing only part of an entity or an + /// escape would corrupt its authored representation. + SpellingMappedInterval? sourceIntervalFor(int start, int end) => + _mappedIntervalFor( + start, + end, + mappedStart: sourceStart, + mappedEnd: sourceEnd, + ); + + SpellingMappedInterval? fieldIntervalFor(int start, int end) { + final startOffset = fieldStart; + final endOffset = fieldEnd; + if (startOffset == null || endOffset == null) return null; + return _mappedIntervalFor( + start, + end, + mappedStart: startOffset, + mappedEnd: endOffset, + ); + } + + SpellingMappedInterval? _mappedIntervalFor( + int start, + int end, { + required int mappedStart, + required int mappedEnd, + }) { + if (mappedStart < 0 || mappedEnd < mappedStart) return null; + final overlapStart = start > logicalStart ? start : logicalStart; + final overlapEnd = end < logicalEnd ? end : logicalEnd; + if (overlapEnd <= overlapStart) return null; + final linear = switch (transformation) { + SpellingTransformationKind.identity || + SpellingTransformationKind.xmlCdata => + mappedEnd - mappedStart == logicalEnd - logicalStart, + _ => false, + }; + return SpellingMappedInterval( + start: linear ? mappedStart + overlapStart - logicalStart : mappedStart, + end: linear ? mappedStart + overlapEnd - logicalStart : mappedEnd, + ); + } +} + +final class SpellingMappedInterval { + const SpellingMappedInterval({required this.start, required this.end}); + + final int start; + final int end; + + bool contains(int offset) => offset >= start && offset < end; +} + +/// Authored delimiters surrounding a formatted logical interval. +/// +/// These intervals let an exact source correction remove an emphasis-like +/// container when deleting its complete contents. They are deliberately kept +/// separate from text atoms: delimiters produce no logical characters. +final class SpellingFormattingWrapper { + const SpellingFormattingWrapper({ + required this.logicalStart, + required this.logicalEnd, + required this.openingStart, + required this.openingEnd, + required this.closingStart, + required this.closingEnd, + this.removableWhenLogicallyEmpty = true, + this.fieldOpeningStart, + this.fieldOpeningEnd, + this.fieldClosingStart, + this.fieldClosingEnd, + this.structuralKind, + }); + + final int logicalStart; + final int logicalEnd; + final int openingStart; + final int openingEnd; + final int closingStart; + final int closingEnd; + final bool removableWhenLogicallyEmpty; + final int? fieldOpeningStart; + final int? fieldOpeningEnd; + final int? fieldClosingStart; + final int? fieldClosingEnd; + final String? structuralKind; +} + +final class SpellingProseRun { + const SpellingProseRun({ + required this.id, + required this.text, + required this.languageId, + required this.atoms, + required this.target, + required this.snapshot, + this.formattingWrappers = const [], + this.complete = true, + String? tokenizationContext, + this.tokenizationContextStart = 0, + }) : _tokenizationContext = tokenizationContext; + + final String id; + final String text; + final String languageId; + final List atoms; + final SpellingEditorTarget target; + final SpellingSnapshotIdentity snapshot; + final List formattingWrappers; + final bool complete; + final String? _tokenizationContext; + + /// Semantic prose surrounding [text], used only to classify token edges. + /// Context-only characters never participate in source replacement. + String get tokenizationContext => _tokenizationContext ?? text; + + /// UTF-16 interval occupied by [text] inside [tokenizationContext]. + final int tokenizationContextStart; + int get tokenizationContextEnd => tokenizationContextStart + text.length; + + bool get hasValidMapping { + if (tokenizationContextStart < 0 || + tokenizationContextEnd > tokenizationContext.length || + !_sameTokenizationCore( + tokenizationContext.substring( + tokenizationContextStart, + tokenizationContextEnd, + ), + text, + )) { + return false; + } + if (atoms.isEmpty) return text.isEmpty; + final reconstructed = StringBuffer(); + var offset = 0; + for (final atom in atoms) { + if (atom.logicalStart != offset || atom.logicalEnd < atom.logicalStart) { + return false; + } + reconstructed.write(atom.logicalText); + offset = atom.logicalEnd; + } + return offset == text.length && reconstructed.toString() == text; + } +} + +bool _sameTokenizationCore(String context, String text) { + if (context.length != text.length) return false; + for (var index = 0; index < text.length; index++) { + final contextUnit = context.codeUnitAt(index); + final textUnit = text.codeUnitAt(index); + if (contextUnit == textUnit) continue; + if ((contextUnit == 0x0a || contextUnit == 0x0d) && textUnit == 0x20) { + continue; + } + return false; + } + return true; +} + +enum SpellingCheckOutcome { accepted, rejected, unchecked } + +final class SpellingOccurrence { + const SpellingOccurrence({ + required this.id, + required this.run, + required this.logicalStart, + required this.logicalEnd, + required this.word, + required this.outcome, + this.error, + }); + + final String id; + final SpellingProseRun run; + final int logicalStart; + final int logicalEnd; + final String word; + final SpellingCheckOutcome outcome; + final String? error; + + Iterable get atoms => run.atoms.where( + (atom) => atom.intersectsLogical(logicalStart, logicalEnd), + ); + + List get sourceIntervals => _coalesceIntervals([ + for (final atom in atoms) + if (atom.sourceIntervalFor(logicalStart, logicalEnd) case final range?) + range, + ]); + + List get fieldIntervals => _coalesceIntervals([ + for (final atom in atoms) + if (atom.fieldIntervalFor(logicalStart, logicalEnd) case final range?) + range, + ]); + + int? get sourceStart { + final offsets = sourceIntervals.map((range) => range.start); + return offsets.isEmpty ? null : offsets.reduce((a, b) => a < b ? a : b); + } + + int? get sourceEnd { + final offsets = sourceIntervals.map((range) => range.end); + return offsets.isEmpty ? null : offsets.reduce((a, b) => a > b ? a : b); + } + + int? get fieldStart { + final offsets = fieldIntervals.map((range) => range.start); + return offsets.isEmpty ? null : offsets.reduce((a, b) => a < b ? a : b); + } + + int? get fieldEnd { + final offsets = fieldIntervals.map((range) => range.end); + return offsets.isEmpty ? null : offsets.reduce((a, b) => a > b ? a : b); + } +} + +List _coalesceIntervals( + List intervals, +) { + if (intervals.length < 2) return List.unmodifiable(intervals); + intervals.sort((left, right) => left.start.compareTo(right.start)); + final result = []; + for (final interval in intervals) { + final previous = result.lastOrNull; + if (previous != null && interval.start <= previous.end) { + result[result.length - 1] = SpellingMappedInterval( + start: previous.start, + end: interval.end > previous.end ? interval.end : previous.end, + ); + } else { + result.add(interval); + } + } + return List.unmodifiable(result); +} + +final class SpellingProjectionResult { + const SpellingProjectionResult({ + required this.runs, + required this.complete, + this.message, + }); + + final List runs; + final bool complete; + final String? message; +} diff --git a/lib/src/spellcheck/spelling_release_smoke.dart b/lib/src/spellcheck/spelling_release_smoke.dart new file mode 100644 index 00000000..e1c4b7a2 --- /dev/null +++ b/lib/src/spellcheck/spelling_release_smoke.dart @@ -0,0 +1,707 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'package:crypto/crypto.dart'; + +import '../../l10n/generated/app_localizations.dart'; +import '../app/app_settings.dart'; +import '../core/diagnostic.dart'; +import '../editor/source/source_editor.dart'; +import '../editor/source/source_search.dart'; +import '../editor/source_language.dart'; +import '../editor/wysiwyg/wysiwyg_block_widgets.dart'; +import '../editor/wysiwyg/wysiwyg_editor.dart'; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_model.dart'; +import '../markdown/markdown_parser.dart'; +import '../workspace/workspace_controller.dart'; +import '../workspace/document_buffer.dart'; +import '../workspace/workspace_model.dart'; +import 'markdown_spelling_projection.dart'; +import 'spelling_catalog.dart'; +import 'spelling_coordinator.dart'; +import 'spelling_dictionary_downloader.dart'; +import 'spelling_language.dart'; +import 'spelling_projection.dart'; +import 'spelling_replacement.dart'; +import 'spelling_session_controller.dart'; +import 'spelling_word_store.dart'; +import 'spelling_worker.dart'; +import 'wysiwyg_spelling_projection.dart'; + +const spellingReleaseSmokeArgument = '--spelling-release-smoke='; + +String? spellingReleaseSmokeReportPath( + Iterable arguments, { + Map? environment, +}) { + if ((environment ?? Platform.environment)['BUSYMARK_RELEASE_SMOKE'] != '1') { + return null; + } + for (final argument in arguments) { + if (!argument.startsWith(spellingReleaseSmokeArgument)) continue; + final path = argument.substring(spellingReleaseSmokeArgument.length); + return path.trim().isEmpty ? null : path; + } + return null; +} + +/// Exercises spelling through the installed executable, editor widgets, and +/// bundle. +/// +/// This deliberately resolves no host dictionary path. It covers the bundled +/// native asset, real dictionary, Source and WYSIWYG transaction paths, +/// workspace undo/redo, and the normal personal-word storage path. +Future runSpellingReleaseSmoke(String reportPath) async { + final reportFile = File(p.normalize(p.absolute(reportPath))); + await reportFile.parent.create(recursive: true); + SpellingWorker? worker; + final checks = {}; + try { + final bundledRoot = const SpellingResourceLocator().locate(); + if (bundledRoot == null) { + throw StateError('Installed spelling resources were not found.'); + } + checks['resourceRoot'] = bundledRoot; + await _verifyInstalledSpellingInventory(bundledRoot); + checks['resourceChecksumInventory'] = true; + final nativeNoticeRoot = Directory( + p.normalize( + p.join(bundledRoot, '..', '..', 'licenses', 'busymark-spellcheck'), + ), + ); + for (final relative in [ + 'Apache-2.0.txt', + 'DEPENDENCIES.md', + p.join('hunspell', 'COPYING'), + p.join('hunspell', 'COPYING.LESSER'), + p.join('hunspell', 'COPYING.MPL'), + p.join('hunspell', 'license.hunspell'), + p.join('hunspell', 'license.myspell'), + ]) { + if (!await File(p.join(nativeNoticeRoot.path, relative)).exists()) { + throw StateError( + 'Installed native dependency notice is missing: $relative', + ); + } + } + checks['nativeDependencyNotices'] = true; + final catalog = await SpellingDictionaryCatalog.load( + bundledRoot: bundledRoot, + verifyChecksums: true, + ); + checks['availableDictionaryCount'] = catalog.availableEntries.length; + final bundledPairs = await Directory(bundledRoot) + .list(recursive: true) + .where( + (entity) => + entity is File && + (entity.path.endsWith('.aff') || entity.path.endsWith('.dic')), + ) + .length; + checks['bundledDictionaryFileCount'] = bundledPairs; + if (bundledPairs != 0) { + throw StateError('The installed package contains language pairs.'); + } + final englishResource = catalog.availableById('en-US'); + if (englishResource == null) { + throw StateError('The en-US resource is absent from the catalog.'); + } + final support = await getApplicationSupportDirectory(); + final dictionaryRoot = resolveSpellingDictionaryStorageRoot( + applicationSupportRoot: support.path, + ); + final downloadedRoot = p.join(dictionaryRoot, 'downloaded'); + worker = await SpellingWorker.start(); + var installedDuringRun = false; + var installedCatalog = await SpellingDictionaryCatalog.load( + bundledRoot: bundledRoot, + downloadedRoot: downloadedRoot, + ); + if (installedCatalog.installedById('en-US') == null) { + await const SpellingDictionaryDownloader().install( + resource: englishResource, + downloadedRoot: downloadedRoot, + validateNativePair: (aff, dic, probe) => worker!.validateDictionary( + affPath: aff, + dicPath: dic, + knownValidProbe: probe, + ), + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_, _) {}, + ); + installedDuringRun = true; + installedCatalog = await SpellingDictionaryCatalog.load( + bundledRoot: bundledRoot, + downloadedRoot: downloadedRoot, + ); + } + final english = installedCatalog.installedById('en-US'); + if (english == null) { + throw StateError('The installed en-US dictionary is unavailable.'); + } + checks['dictionaryInstalledDuringRun'] = installedDuringRun; + checks['installedDictionaryCount'] = installedCatalog.installations.length; + if (installedCatalog.installations.length != 1) { + throw StateError('The smoke profile did not contain exactly one pair.'); + } + + final session = SpellingSessionController( + bundledRoot: bundledRoot, + applicationSupportRoot: support.path, + dictionaryStorageRoot: dictionaryRoot, + ); + try { + final settings = AppSettings.defaults().copyWith( + automaticSpelling: true, + defaultSpellingLanguage: null, + ); + final unresolved = DocumentBuffer.untitled( + id: 'release-language-transition', + name: 'release-language-transition.md', + text: 'helo', + ); + final richDocument = const MarkdownParser() + .parse( + filePath: unresolved.id, + source: unresolved.text, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + SpellingSessionInput input( + DocumentBuffer buffer, { + BusyDocument? document, + }) => SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + richDocument: document, + ); + session.update(input(unresolved)); + await _waitForSpellingState( + session, + (state) => state.status == SpellingPresentationStatus.languageRequired, + ); + final selected = unresolved.copyWith( + editorState: unresolved.editorState.copyWith( + spellingLanguage: const SpellingLanguageOverride.selected('en-US'), + ), + ); + session.update(input(selected, document: richDocument)); + await _waitForSpellingState(session, (state) { + return state.status != SpellingPresentationStatus.languageRequired && + state.status != SpellingPresentationStatus.checking; + }); + final richOccurrence = session.misspellings.singleOrNull; + final richAnnotation = session.annotations.singleOrNull; + if (session.state.status != SpellingPresentationStatus.ready || + !session.state.complete || + richOccurrence?.word != 'helo' || + richAnnotation == null) { + throw StateError( + 'Installed dictionary session transition failed: ' + '${session.state.status}, complete=${session.state.complete}, ' + 'message=${session.state.message}, ' + 'misspellings=${session.misspellings.length}, ' + 'annotations=${session.annotations.length}.', + ); + } + checks['sessionLanguageTransition'] = true; + + final richTarget = richAnnotation.target; + if (richTarget is! SpellingRichBlockTarget) { + throw StateError( + 'The real rich session produced ${richTarget.runtimeType}.', + ); + } + final richKey = GlobalKey(); + await _mountSmokeEditor( + BusyMarkWysiwygEditor( + key: richKey, + document: richDocument, + documentId: selected.id, + contentRevision: selected.revision, + spellingAnnotations: [richAnnotation], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + ), + ); + final mountedRichBlock = _mountedWidgets() + .singleWhere((field) => field.block.id == richTarget.blockId); + if (richTarget.documentGeneration != + richKey.currentState?.spellingDocumentGeneration || + mountedRichBlock.spellingRanges.length != 1 || + mountedRichBlock.spellingRanges.single != + const TextRange(start: 0, end: 4) || + !_hasMountedSpellingPainter('_SpellingUnderlinePainter')) { + throw StateError( + 'The real rich annotation did not mount its underline: ' + 'target=${richTarget.blockId}/${richTarget.documentGeneration}, ' + 'mounted=${mountedRichBlock.block.id}/' + '${richKey.currentState?.spellingDocumentGeneration}, ' + 'ranges=${mountedRichBlock.spellingRanges}.', + ); + } + checks['realRichUnderline'] = true; + await _unmountSmokeEditor(); + + session.update(input(selected)); + await _waitForSpellingState(session, (state) { + return state.status == SpellingPresentationStatus.ready && + session.annotations.singleOrNull?.target is SpellingSourceTarget; + }); + final sourceOccurrence = session.misspellings.singleOrNull; + final sourceAnnotation = session.annotations.singleOrNull; + if (session.state.status != SpellingPresentationStatus.ready || + !session.state.complete || + sourceOccurrence?.word != 'helo' || + sourceAnnotation == null || + sourceAnnotation.target is! SpellingSourceTarget || + sourceAnnotation.start != 0 || + sourceAnnotation.end != 4) { + throw StateError( + 'The real Source session did not publish the expected annotation.', + ); + } + await _mountSmokeEditor( + BusyMarkSourceEditor( + text: selected.text, + language: SourceSyntaxLanguage.markdown, + filePath: null, + documentId: selected.id, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + editRevision: selected.revision, + spellingAnnotations: [sourceAnnotation], + ), + ); + if (!_hasMountedSpellingPainter('_SourceSpellingPainter')) { + throw StateError( + 'The real Source annotation did not mount its underline overlay.', + ); + } + checks['realSourceUnderline'] = true; + await _unmountSmokeEditor(); + + final quotedFence = selected.copyWith( + text: '''> ```java +> zzzzquotedcode +> ``` + +helo +''', + revision: selected.revision + 1, + ); + session.update(input(quotedFence)); + await _waitForSpellingState(session, (state) { + return state.status == SpellingPresentationStatus.ready && + state.complete && + session.misspellings.any( + (occurrence) => + occurrence.run.snapshot.contentRevision == + quotedFence.revision, + ); + }); + final quotedWords = session.misspellings + .map((occurrence) => occurrence.word) + .toList(growable: false); + if (quotedWords.length != 1 || quotedWords.single != 'helo') { + throw StateError( + 'Quoted fenced code leaked into real spelling prose: $quotedWords.', + ); + } + checks['quotedFencedCodeExcluded'] = true; + } finally { + session.dispose(); + } + + const source = 'This is helo.\n'; + final container = ProviderContainer(); + final workspace = container.read(workspaceControllerProvider.notifier); + await workspace.createMarkdownFile(); + workspace.updateActiveText(source); + var buffer = container.read(workspaceControllerProvider).activeBuffer!; + final snapshot = SpellingSnapshotIdentity( + bufferId: buffer.id, + contentRevision: buffer.revision, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + final projection = const MarkdownSpellingProjector().project( + filePath: buffer.id, + source: source, + mode: MarkdownMode.gfm, + languageId: 'en-US', + snapshot: snapshot, + ); + final context = SpellingEngineContext( + languageId: english.id, + affPath: english.affPath, + dicPath: english.dicPath, + baseFingerprint: english.fingerprint, + personalRevision: 0, + projectIdentity: null, + projectRevision: 0, + customWords: const [], + ); + final checked = await worker.check(context: context, runs: projection.runs); + final occurrence = checked.occurrences.singleWhere( + (candidate) => + candidate.word == 'helo' && + candidate.outcome == SpellingCheckOutcome.rejected, + ); + final suggestions = await worker.suggestions( + context: context, + word: occurrence.word, + ); + if (!suggestions.contains('hello')) { + throw StateError('The installed dictionary did not suggest hello.'); + } + checks['rejectedWord'] = occurrence.word; + checks['suggestion'] = 'hello'; + + final preparedSource = await prepareSpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + source: source, + ); + final corrected = preparedSource.replacementSource!; + if (corrected != 'This is hello.\n') { + throw StateError('The exact source correction changed unexpected text.'); + } + final sourceKey = GlobalKey(); + await _mountSmokeEditor( + BusyMarkSourceEditor( + key: sourceKey, + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: null, + documentId: buffer.id, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onTransactionalChanged: + (text, sourceFilePath, previousSelection, selection, undoGroup) => + workspace.updateActiveSourceText( + text, + sourceFilePath: sourceFilePath, + previousSelection: previousSelection, + selection: selection, + undoGroup: undoGroup, + ), + onOpenSearch: () {}, + onCloseSearch: () {}, + editRevision: buffer.revision, + initialSelection: const TextSelection(baseOffset: 8, extentOffset: 12), + spellingAnnotations: [_annotationFor(occurrence)], + ), + ); + if (sourceKey.currentState?.applyPreparedSpellingCorrection( + occurrence: occurrence, + plan: preparedSource.plan, + expectedSource: source, + replacementSource: corrected, + ) != + true) { + throw StateError('The installed Source editor rejected the correction.'); + } + await _settleSmokeFrames(); + buffer = container.read(workspaceControllerProvider).activeBuffer!; + if (buffer.text != corrected || + buffer.editorState.selection != + const TextSelection.collapsed(offset: 13)) { + throw StateError('The Source editor did not publish its transaction.'); + } + if (!workspace.undoActiveBuffer() || + container.read(workspaceControllerProvider).activeBuffer?.text != + source || + container + .read(workspaceControllerProvider) + .activeBuffer + ?.editorState + .selection != + const TextSelection(baseOffset: 8, extentOffset: 12) || + !workspace.redoActiveBuffer() || + container.read(workspaceControllerProvider).activeBuffer?.text != + corrected || + container + .read(workspaceControllerProvider) + .activeBuffer + ?.editorState + .selection != + const TextSelection.collapsed(offset: 13)) { + throw StateError( + 'Workspace undo/redo did not retain the Source correction selection.', + ); + } + checks['correctedSource'] = corrected; + checks['sourceEditorTransaction'] = true; + checks['workspaceHistoryRoundTrip'] = true; + + await _exerciseRichEditor( + container: container, + workspace: workspace, + worker: worker, + context: context, + source: '**helo**\n', + expected: '**hello**\n', + expectedTarget: SpellingRichBlockTarget, + ); + checks['formattedRichEditorTransaction'] = true; + await _exerciseRichEditor( + container: container, + workspace: workspace, + worker: worker, + context: context, + source: '| Heading |\n| --- |\n| helo |\n', + expected: '| Heading |\n| --- |\n| hello |\n', + expectedTarget: SpellingRichTableCellTarget, + ); + checks['tableCellEditorTransaction'] = true; + + final personalFile = p.join(support.path, 'spelling', 'personal.json'); + final store = SpellingWordStore(filePath: personalFile); + final before = await store.read(); + final hadPersistedWord = before + .wordsFor('en-US') + .contains('BusyMarkReleaseTerm'); + await store.addWord('en-US', 'BusyMarkReleaseTerm'); + final restarted = await SpellingWordStore(filePath: personalFile).read(); + if (!restarted.wordsFor('en-US').contains('BusyMarkReleaseTerm')) { + throw StateError('The personal word did not survive store restart.'); + } + checks['personalWordPersisted'] = true; + checks['personalWordPresentBeforeRun'] = hadPersistedWord; + + await _unmountSmokeEditor(); + container.dispose(); + + await _writeReport(reportFile, {'ok': true, 'checks': checks}); + return 0; + } on Object catch (error, stackTrace) { + await _writeReport(reportFile, { + 'ok': false, + 'checks': checks, + 'error': error.toString(), + 'stackTrace': stackTrace.toString(), + }); + return 1; + } finally { + await worker?.close(); + } +} + +Future _verifyInstalledSpellingInventory(String root) async { + final inventory = File(p.join(root, 'CHECKSUMS.sha256')); + if (!await inventory.exists()) { + throw StateError('Installed spelling checksum inventory is missing.'); + } + for (final line in await inventory.readAsLines()) { + if (line.trim().isEmpty) continue; + final match = RegExp(r'^([0-9a-f]{64}) (.+)$').firstMatch(line); + if (match == null) { + throw StateError('Installed spelling checksum inventory is malformed.'); + } + final file = File(p.join(root, match.group(2)!)); + if (!await file.exists() || + (await sha256.bind(file.openRead()).first).toString() != + match.group(1)) { + throw StateError( + 'Installed spelling resource failed checksum: ${match.group(2)}', + ); + } + } +} + +Future _waitForSpellingState( + SpellingSessionController controller, + bool Function(SpellingPresentationState state) condition, +) async { + final elapsed = Stopwatch()..start(); + while (!condition(controller.state)) { + if (elapsed.elapsed > const Duration(seconds: 15)) { + throw TimeoutException( + 'Spelling session did not settle: ${controller.state.status}, ' + 'message=${controller.state.message}.', + ); + } + await Future.delayed(const Duration(milliseconds: 25)); + } +} + +Future _exerciseRichEditor({ + required ProviderContainer container, + required WorkspaceController workspace, + required SpellingWorker worker, + required SpellingEngineContext context, + required String source, + required String expected, + required Type expectedTarget, +}) async { + workspace.updateActiveText(source); + final buffer = container.read(workspaceControllerProvider).activeBuffer!; + final document = const MarkdownParser() + .parse( + filePath: buffer.id, + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final snapshot = SpellingSnapshotIdentity( + bufferId: buffer.id, + contentRevision: buffer.revision, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: context.languageId, + snapshot: snapshot, + documentGeneration: 0, + ); + if (!projection.complete) { + throw StateError(projection.message ?? 'Rich projection was incomplete.'); + } + final checked = await worker.check(context: context, runs: projection.runs); + final occurrence = checked.occurrences.singleWhere( + (candidate) => + candidate.word == 'helo' && + candidate.run.target.runtimeType == expectedTarget, + ); + final key = GlobalKey(); + var publishedDocument = document; + await _mountSmokeEditor( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: buffer.id, + contentRevision: buffer.revision, + useExternalUndoHistory: true, + spellingAnnotations: [_annotationFor(occurrence)], + onDocumentChanged: (value) => publishedDocument = value, + onSourceChanged: (_, _) {}, + onSpellingSourceChanged: (_, value, before, after) => + workspace.updateActiveWysiwygText( + value, + document: publishedDocument, + previousWysiwygState: before, + wysiwygState: after, + ), + ), + ); + final field = key.currentState?.spellingFieldSnapshot(occurrence); + if (field == null) { + throw StateError('The installed rich editor did not expose its field.'); + } + final prepared = await prepareSpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + field: field, + ); + if (key.currentState?.applyPreparedSpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + plan: prepared.plan, + expectedFieldText: field, + preparedFieldText: prepared.replacementField, + ) != + true) { + throw StateError('The installed rich editor rejected a correction.'); + } + await _settleSmokeFrames(); + if (container.read(workspaceControllerProvider).activeBuffer?.text != + expected) { + throw StateError('The rich correction changed unexpected source.'); + } + if (!workspace.undoActiveBuffer() || + container.read(workspaceControllerProvider).activeBuffer?.text != + source || + !workspace.redoActiveBuffer() || + container.read(workspaceControllerProvider).activeBuffer?.text != + expected) { + throw StateError('Rich editor correction failed workspace undo/redo.'); + } +} + +SpellingAnnotation _annotationFor(SpellingOccurrence occurrence) => + SpellingAnnotation( + occurrenceId: occurrence.id, + start: occurrence.run.target is SpellingSourceTarget + ? occurrence.sourceStart! + : occurrence.fieldStart!, + end: occurrence.run.target is SpellingSourceTarget + ? occurrence.sourceEnd! + : occurrence.fieldEnd!, + target: occurrence.run.target, + ); + +Future _mountSmokeEditor(Widget editor) async { + runApp( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold(body: SizedBox(width: 1000, height: 700, child: editor)), + ), + ); + await _settleSmokeFrames(); +} + +Future _unmountSmokeEditor() async { + runApp(const SizedBox.shrink()); + await _settleSmokeFrames(); +} + +List _mountedWidgets() { + final widgets = []; + void visit(Element element) { + final widget = element.widget; + if (widget is T) widgets.add(widget); + element.visitChildElements(visit); + } + + WidgetsBinding.instance.rootElement?.visitChildElements(visit); + return widgets; +} + +bool _hasMountedSpellingPainter(String typeName) { + return _mountedWidgets().any( + (paint) => + paint.painter?.runtimeType.toString() == typeName || + paint.foregroundPainter?.runtimeType.toString() == typeName, + ); +} + +Future _settleSmokeFrames() async { + for (var index = 0; index < 3; index++) { + await WidgetsBinding.instance.endOfFrame.timeout( + const Duration(seconds: 5), + ); + await Future.delayed(const Duration(milliseconds: 20)); + } +} + +Future _writeReport(File file, Map report) => + file.writeAsString( + '${const JsonEncoder.withIndent(' ').convert(report)}\n', + flush: true, + ); diff --git a/lib/src/spellcheck/spelling_replacement.dart b/lib/src/spellcheck/spelling_replacement.dart new file mode 100644 index 00000000..de1c4b07 --- /dev/null +++ b/lib/src/spellcheck/spelling_replacement.dart @@ -0,0 +1,839 @@ +import 'dart:isolate'; + +import 'package:characters/characters.dart'; +import 'package:unorm_dart/unorm_dart.dart' as unicode; + +import '../markdown/markdown_model.dart'; +import '../workspace/workspace_model.dart'; +import 'markdown_spelling_projection.dart'; +import 'spelling_projection.dart'; +import 'writerside_spelling_projection.dart'; + +final class SpellingSourceEdit { + const SpellingSourceEdit({ + required this.start, + required this.end, + required this.replacement, + }); + + final int start; + final int end; + final String replacement; +} + +final class SpellingRichLeafEdit { + const SpellingRichLeafEdit({ + required this.path, + required this.start, + required this.end, + required this.replacement, + }); + + final List path; + final int start; + final int end; + final String replacement; +} + +final class SpellingFieldEdit { + const SpellingFieldEdit({ + required this.start, + required this.end, + required this.replacement, + }); + + final int start; + final int end; + final String replacement; +} + +final class SpellingReplacementPlan { + const SpellingReplacementPlan({ + required this.originalWord, + required this.suggestion, + required this.sourceEdits, + required this.richLeafEdits, + required this.fieldEdits, + required this.snapshot, + required this.languageId, + this.sourceTargetStart, + this.sourceTargetEnd, + this.fieldTargetStart, + this.fieldTargetEnd, + }); + + final String originalWord; + final String suggestion; + final List sourceEdits; + final List richLeafEdits; + final List fieldEdits; + final SpellingSnapshotIdentity snapshot; + final String languageId; + final int? sourceTargetStart; + final int? sourceTargetEnd; + final int? fieldTargetStart; + final int? fieldTargetEnd; + + String applyToSource(String source) { + var result = source; + final edits = [...sourceEdits] + ..sort((left, right) => right.start.compareTo(left.start)); + for (final edit in edits) { + if (edit.start < 0 || edit.end < edit.start || edit.end > result.length) { + throw StateError('Spelling source edit is outside the guarded source.'); + } + result = result.replaceRange(edit.start, edit.end, edit.replacement); + } + if (!_sourceResultMatches(result)) { + throw StateError( + 'The spelling correction did not preserve the projected source ' + 'structure.', + ); + } + return result; + } + + bool _sourceResultMatches(String source) { + final originalStart = sourceTargetStart; + final originalEnd = sourceTargetEnd; + if (originalStart == null || originalEnd == null) return true; + final start = _translateSourceBoundary(originalStart, sourceEdits); + final end = _translateSourceBoundary(originalEnd, sourceEdits); + if (start < 0 || end < start || end > source.length) return false; + // Parser context can cross blank lines through containers, HTML, link + // definitions, and other block syntax. Production correction preparation + // runs off the UI isolate, so validate against the authoritative complete + // snapshot rather than guessing a smaller parsing boundary. + final validationSource = source; + final localStart = start; + final localEnd = end; + final projection = switch (snapshot.documentKind) { + DocumentKind.writersideXmlTopic => + const WritersideXmlSpellingProjector().project( + filePath: 'spelling-validation.topic', + source: validationSource, + languageId: languageId, + snapshot: snapshot, + ), + DocumentKind.markdown || DocumentKind.writersideMarkdownTopic => + const MarkdownSpellingProjector().project( + filePath: 'spelling-validation.md', + source: validationSource, + mode: snapshot.documentKind == DocumentKind.writersideMarkdownTopic + ? MarkdownMode.writersideMarkdown + : MarkdownMode.commonMark, + languageId: languageId, + snapshot: snapshot, + ), + _ => null, + }; + if (projection == null) return true; + return _projectionContainsReplacement( + projection, + mappedSource: validationSource, + targetStart: localStart, + targetEnd: localEnd, + markdown: snapshot.documentKind != DocumentKind.writersideXmlTopic, + ); + } + + String applyToField(String fieldSource) { + var result = fieldSource; + final edits = [...fieldEdits] + ..sort((left, right) => right.start.compareTo(left.start)); + for (final edit in edits) { + if (edit.start < 0 || edit.end < edit.start || edit.end > result.length) { + throw StateError('Spelling field edit is outside the guarded field.'); + } + result = result.replaceRange(edit.start, edit.end, edit.replacement); + } + final originalStart = fieldTargetStart; + final originalEnd = fieldTargetEnd; + if (originalStart == null || originalEnd == null) return result; + final start = _translateFieldBoundary(originalStart, fieldEdits); + final end = _translateFieldBoundary(originalEnd, fieldEdits); + if (start < 0 || end < start || end > result.length) { + throw StateError('Spelling field result has invalid target bounds.'); + } + final projection = const MarkdownSpellingProjector().project( + filePath: 'spelling-field-validation.md', + source: result, + mode: snapshot.documentKind == DocumentKind.writersideMarkdownTopic + ? MarkdownMode.writersideMarkdown + : MarkdownMode.commonMark, + languageId: languageId, + snapshot: snapshot, + ); + if (!_projectionContainsReplacement( + projection, + mappedSource: result, + targetStart: start, + targetEnd: end, + markdown: true, + )) { + throw StateError( + 'The spelling correction did not preserve the projected field ' + 'structure.', + ); + } + return result; + } + + bool _projectionContainsReplacement( + SpellingProjectionResult projection, { + required String mappedSource, + required int targetStart, + required int targetEnd, + required bool markdown, + }) { + for (final run in projection.runs) { + for (final range in _canonicallyEquivalentRanges(run.text, suggestion)) { + final candidate = SpellingOccurrence( + id: 'validation', + run: run, + logicalStart: range.start, + logicalEnd: range.end, + word: run.text.substring(range.start, range.end), + outcome: SpellingCheckOutcome.rejected, + ); + final intervals = candidate.sourceIntervals; + final trailingGap = intervals.isEmpty || intervals.last.end > targetEnd + ? '' + : mappedSource.substring(intervals.last.end, targetEnd); + final markdownWrapperGap = + markdown && + intervals.isNotEmpty && + intervals.last.end < targetEnd && + RegExp(r'^[*_~]+$').hasMatch(trailingGap); + if (intervals.isNotEmpty && + intervals.first.start == targetStart && + (intervals.last.end == targetEnd || markdownWrapperGap)) { + return true; + } + } + } + return false; + } + + /// Translates the end of the final source edit into the resulting source. + /// + /// This is intentionally based on encoded replacements rather than the + /// Unicode length of [suggestion]: Markdown/XML escaping may make those + /// lengths different. + int? get resultingSourceCaret => _resultingCaretForSourceEdits(sourceEdits); + + /// Translates the end of the final editable-field edit into the resulting + /// field. This is used by Markdown-source fields containing inline math. + int? get resultingFieldCaret => _resultingCaretForFieldEdits(fieldEdits); + + int translateSourceOffset(int offset) => + _translateSourceBoundary(offset, sourceEdits); + + int translateFieldOffset(int offset) => + _translateFieldBoundary(offset, fieldEdits); +} + +/// Performs parser-backed correction planning and validation away from the UI +/// isolate. Editors must still verify the captured source or field snapshot +/// synchronously immediately before committing the returned transaction. +Future< + ({ + SpellingReplacementPlan plan, + String? replacementSource, + String? replacementField, + }) +> +prepareSpellingCorrection({ + required SpellingOccurrence occurrence, + required String suggestion, + String? source, + String? field, +}) => Isolate.run(() { + final plan = const SpellingReplacementPlanner().build( + occurrence: occurrence, + suggestion: suggestion, + ); + return ( + plan: plan, + replacementSource: source == null ? null : plan.applyToSource(source), + replacementField: field == null || plan.fieldEdits.isEmpty + ? null + : plan.applyToField(field), + ); +}); + +Iterable<({int start, int end})> _canonicallyEquivalentRanges( + String text, + String expected, +) sync* { + final expectedClusters = expected.characters.toList(growable: false); + if (expectedClusters.isEmpty) return; + final clusters = text.characters.toList(growable: false); + if (clusters.length < expectedClusters.length) return; + final offsets = [0]; + for (final cluster in clusters) { + offsets.add(offsets.last + cluster.length); + } + final normalizedExpected = unicode.nfc(expected); + for ( + var index = 0; + index + expectedClusters.length <= clusters.length; + index++ + ) { + final candidate = clusters.skip(index).take(expectedClusters.length).join(); + if (unicode.nfc(candidate) == normalizedExpected) { + yield ( + start: offsets[index], + end: offsets[index + expectedClusters.length], + ); + } + } +} + +int? _resultingCaretForSourceEdits(List edits) { + if (edits.isEmpty) return null; + final sorted = [...edits] + ..sort((left, right) => left.start.compareTo(right.start)); + var delta = 0; + var caret = 0; + for (final edit in sorted) { + caret = edit.start + delta + edit.replacement.length; + delta += edit.replacement.length - (edit.end - edit.start); + } + return caret; +} + +int? _resultingCaretForFieldEdits(List edits) { + if (edits.isEmpty) return null; + final sorted = [...edits] + ..sort((left, right) => left.start.compareTo(right.start)); + var delta = 0; + var caret = 0; + for (final edit in sorted) { + caret = edit.start + delta + edit.replacement.length; + delta += edit.replacement.length - (edit.end - edit.start); + } + return caret; +} + +final class SpellingReplacementPlanner { + const SpellingReplacementPlanner(); + + SpellingReplacementPlan build({ + required SpellingOccurrence occurrence, + required String suggestion, + }) { + if (occurrence.outcome != SpellingCheckOutcome.rejected) { + throw StateError('Only a verified rejected occurrence can be replaced.'); + } + final atoms = occurrence.atoms.toList(growable: false); + if (atoms.isEmpty || suggestion.isEmpty) { + throw StateError('The correction target is not replaceable.'); + } + if (occurrence.run.text.substring( + occurrence.logicalStart, + occurrence.logicalEnd, + ) != + occurrence.word) { + throw StateError('The correction word no longer matches its projection.'); + } + + final originalClusters = _clusters(occurrence.word); + final suggestionClusters = _clusters(suggestion); + if (originalClusters.isEmpty) { + throw StateError('An empty occurrence cannot be corrected.'); + } + final ownership = []; + for (final cluster in originalClusters) { + final globalOffset = occurrence.logicalStart + cluster.start; + final owner = atoms.indexWhere( + (atom) => + atom.logicalStart <= globalOffset && atom.logicalEnd > globalOffset, + ); + if (owner < 0) { + throw StateError('A grapheme has no mapped authored-source atom.'); + } + ownership.add(owner); + } + final aligned = _align(originalClusters, suggestionClusters); + final assigned = {}; + var previousOriginal = -1; + for (final operation in aligned) { + switch (operation.kind) { + case _AlignmentKind.equal: + case _AlignmentKind.substitute: + final originalIndex = operation.originalIndex!; + final owner = ownership[originalIndex]; + assigned + .putIfAbsent(owner, StringBuffer.new) + .write( + operation.kind == _AlignmentKind.equal + ? originalClusters[originalIndex].text + : suggestionClusters[operation.suggestionIndex!].text, + ); + previousOriginal = originalIndex; + case _AlignmentKind.delete: + previousOriginal = operation.originalIndex!; + case _AlignmentKind.insert: + final nextOriginal = operation.originalIndex; + final ownerIndex = previousOriginal >= 0 + ? previousOriginal + : (nextOriginal ?? 0).clamp(0, ownership.length - 1); + assigned + .putIfAbsent(ownership[ownerIndex], StringBuffer.new) + .write(suggestionClusters[operation.suggestionIndex!].text); + } + } + + final sourceEdits = []; + final fieldEdits = []; + final richGroups = {}; + for (final (index, atom) in atoms.indexed) { + final overlapStart = occurrence.logicalStart > atom.logicalStart + ? occurrence.logicalStart + : atom.logicalStart; + final overlapEnd = occurrence.logicalEnd < atom.logicalEnd + ? occurrence.logicalEnd + : atom.logicalEnd; + if (overlapEnd <= overlapStart) continue; + final localStart = overlapStart - atom.logicalStart; + final localEnd = overlapEnd - atom.logicalStart; + final replacement = assigned[index]?.toString() ?? ''; + + if (atom.sourceStart >= 0) { + final mapped = atom.sourceIntervalFor(overlapStart, overlapEnd); + final linearAtom = switch (atom.transformation) { + SpellingTransformationKind.identity || + SpellingTransformationKind.xmlCdata => + atom.sourceEnd - atom.sourceStart == atom.logicalText.length, + _ => false, + }; + if (linearAtom) { + sourceEdits.add( + SpellingSourceEdit( + start: mapped!.start, + end: mapped.end, + replacement: _encode(replacement, atom.context), + ), + ); + } else { + final rebuilt = + atom.logicalText.substring(0, localStart) + + replacement + + atom.logicalText.substring(localEnd); + sourceEdits.add( + SpellingSourceEdit( + start: atom.sourceStart, + end: atom.sourceEnd, + replacement: _encode(rebuilt, atom.context), + ), + ); + } + } + + final path = atom.richLeafPath; + final fieldStart = atom.fieldStart; + final fieldEnd = atom.fieldEnd; + if (path != null && fieldStart != null && fieldEnd != null) { + final key = path.join('.'); + final accumulator = richGroups.putIfAbsent( + key, + () => _RichEditAccumulator(path), + ); + accumulator.add( + start: fieldStart + localStart, + end: fieldStart + localEnd, + replacement: replacement, + ); + } else if (fieldStart != null && fieldEnd != null) { + final mapped = atom.fieldIntervalFor(overlapStart, overlapEnd); + final linearAtom = switch (atom.transformation) { + SpellingTransformationKind.identity || + SpellingTransformationKind.xmlCdata => + fieldEnd - fieldStart == atom.logicalText.length, + _ => false, + }; + if (linearAtom) { + fieldEdits.add( + SpellingFieldEdit( + start: mapped!.start, + end: mapped.end, + replacement: _encode(replacement, atom.context), + ), + ); + } else { + final rebuilt = + atom.logicalText.substring(0, localStart) + + replacement + + atom.logicalText.substring(localEnd); + fieldEdits.add( + SpellingFieldEdit( + start: fieldStart, + end: fieldEnd, + replacement: _encode(rebuilt, atom.context), + ), + ); + } + } + } + for (final wrapper in occurrence.run.formattingWrappers) { + if (!wrapper.removableWhenLogicallyEmpty) continue; + if (occurrence.logicalStart > wrapper.logicalStart || + occurrence.logicalEnd < wrapper.logicalEnd) { + continue; + } + final ownedAtomIndexes = [ + for (final (index, atom) in atoms.indexed) + if (atom.logicalStart >= wrapper.logicalStart && + atom.logicalEnd <= wrapper.logicalEnd) + index, + ]; + if (ownedAtomIndexes.isEmpty) continue; + final remaining = StringBuffer(); + for (final index in ownedAtomIndexes) { + remaining.write(assigned[index] ?? ''); + } + if (remaining.isNotEmpty) continue; + if (wrapper.openingStart >= 0 && wrapper.closingStart >= 0) { + sourceEdits + ..add( + SpellingSourceEdit( + start: wrapper.openingStart, + end: wrapper.openingEnd, + replacement: '', + ), + ) + ..add( + SpellingSourceEdit( + start: wrapper.closingStart, + end: wrapper.closingEnd, + replacement: '', + ), + ); + } + final fieldOpeningStart = wrapper.fieldOpeningStart; + final fieldOpeningEnd = wrapper.fieldOpeningEnd; + final fieldClosingStart = wrapper.fieldClosingStart; + final fieldClosingEnd = wrapper.fieldClosingEnd; + if (fieldOpeningStart != null && + fieldOpeningEnd != null && + fieldClosingStart != null && + fieldClosingEnd != null) { + fieldEdits + ..add( + SpellingFieldEdit( + start: fieldOpeningStart, + end: fieldOpeningEnd, + replacement: '', + ), + ) + ..add( + SpellingFieldEdit( + start: fieldClosingStart, + end: fieldClosingEnd, + replacement: '', + ), + ); + } + } + final richEdits = [ + for (final accumulator in richGroups.values) accumulator.build(), + ]..sort((left, right) => _comparePaths(left.path, right.path)); + + final reconstructed = StringBuffer(); + for (var index = 0; index < atoms.length; index++) { + reconstructed.write(assigned[index] ?? ''); + } + final reconstructedSuggestion = reconstructed.toString(); + if (unicode.nfc(reconstructedSuggestion) != unicode.nfc(suggestion)) { + throw StateError( + 'The correction plan produced "$reconstructedSuggestion" instead of ' + 'the selected suggestion.', + ); + } + final sourceOffsets = occurrence.sourceIntervals; + final fieldOffsets = occurrence.fieldIntervals; + return SpellingReplacementPlan( + originalWord: occurrence.word, + suggestion: suggestion, + sourceEdits: _coalesceSourceEdits(sourceEdits), + richLeafEdits: List.unmodifiable(richEdits), + fieldEdits: _coalesceFieldEdits(fieldEdits), + snapshot: occurrence.run.snapshot, + languageId: occurrence.run.languageId, + sourceTargetStart: sourceOffsets.isEmpty + ? null + : sourceOffsets + .map((range) => range.start) + .reduce((left, right) => left < right ? left : right), + sourceTargetEnd: sourceOffsets.isEmpty + ? null + : sourceOffsets + .map((range) => range.end) + .reduce((left, right) => left > right ? left : right), + fieldTargetStart: fieldOffsets.isEmpty + ? null + : fieldOffsets + .map((range) => range.start) + .reduce((left, right) => left < right ? left : right), + fieldTargetEnd: fieldOffsets.isEmpty + ? null + : fieldOffsets + .map((range) => range.end) + .reduce((left, right) => left > right ? left : right), + ); + } +} + +int _translateSourceBoundary(int offset, List edits) { + var translated = offset; + for (final edit in edits) { + if (edit.end <= offset) { + translated += edit.replacement.length - (edit.end - edit.start); + } else if (edit.start < offset && edit.end > offset) { + translated = edit.start + edit.replacement.length; + } + } + return translated; +} + +int _translateFieldBoundary(int offset, List edits) { + var translated = offset; + for (final edit in edits) { + if (edit.end <= offset) { + translated += edit.replacement.length - (edit.end - edit.start); + } else if (edit.start < offset && edit.end > offset) { + translated = edit.start + edit.replacement.length; + } + } + return translated; +} + +List _coalesceFieldEdits(List edits) { + if (edits.length < 2) return List.unmodifiable(edits); + final sorted = [...edits] + ..sort((left, right) => left.start.compareTo(right.start)); + final result = []; + for (final edit in sorted) { + final previous = result.lastOrNull; + if (previous != null && edit.start < previous.end) { + if (edit.start == previous.start && + edit.end == previous.end && + edit.replacement == previous.replacement) { + continue; + } + throw StateError('Overlapping spelling source edits are unsafe.'); + } + if (previous != null && previous.end == edit.start) { + result[result.length - 1] = SpellingFieldEdit( + start: previous.start, + end: edit.end, + replacement: previous.replacement + edit.replacement, + ); + } else { + result.add(edit); + } + } + return List.unmodifiable(result); +} + +String _encode(String value, SpellingSourceContext context) { + return switch (context) { + SpellingSourceContext.markdownProse => value.replaceAllMapped( + RegExp(r'([\\`*_{}\[\]()<>#+.!|])'), + (match) => '\\${match.group(1)}', + ), + SpellingSourceContext.markdownTableCell => value.replaceAllMapped( + RegExp(r'([\\`*_{}\[\]()<>#+.!|])'), + (match) => '\\${match.group(1)}', + ), + SpellingSourceContext.markdownSingleQuotedTitle => + value.replaceAll(r'\', r'\\').replaceAll("'", r"\'"), + SpellingSourceContext.markdownDoubleQuotedTitle => + value.replaceAll(r'\', r'\\').replaceAll('"', r'\"'), + SpellingSourceContext.xmlText => + value + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>'), + SpellingSourceContext.xmlSingleQuotedAttribute => + value + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll("'", '''), + SpellingSourceContext.xmlDoubleQuotedAttribute => + value + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('"', '"'), + SpellingSourceContext.xmlCdata => value.replaceAll( + ']]>', + ']]]]>', + ), + }; +} + +List _coalesceSourceEdits(List edits) { + if (edits.length < 2) return List.unmodifiable(edits); + final sorted = [...edits] + ..sort((left, right) => left.start.compareTo(right.start)); + final result = []; + for (final edit in sorted) { + final previous = result.lastOrNull; + if (previous != null && previous.end == edit.start) { + result[result.length - 1] = SpellingSourceEdit( + start: previous.start, + end: edit.end, + replacement: previous.replacement + edit.replacement, + ); + } else { + result.add(edit); + } + } + return List.unmodifiable(result); +} + +final class _RichEditAccumulator { + _RichEditAccumulator(this.path); + + final List path; + int? start; + int? end; + final replacement = StringBuffer(); + + void add({ + required int start, + required int end, + required String replacement, + }) { + this.start = this.start == null || start < this.start! ? start : this.start; + this.end = this.end == null || end > this.end! ? end : this.end; + this.replacement.write(replacement); + } + + SpellingRichLeafEdit build() => SpellingRichLeafEdit( + path: List.unmodifiable(path), + start: start!, + end: end!, + replacement: replacement.toString(), + ); +} + +int _comparePaths(List left, List right) { + for (var index = 0; index < left.length && index < right.length; index++) { + final result = left[index].compareTo(right[index]); + if (result != 0) return result; + } + return left.length.compareTo(right.length); +} + +final class _Cluster { + const _Cluster(this.text, this.start, this.end); + final String text; + final int start; + final int end; +} + +List<_Cluster> _clusters(String text) { + final result = <_Cluster>[]; + var offset = 0; + for (final cluster in text.characters) { + result.add(_Cluster(cluster, offset, offset + cluster.length)); + offset += cluster.length; + } + return result; +} + +enum _AlignmentKind { equal, substitute, delete, insert } + +final class _AlignmentOperation { + const _AlignmentOperation( + this.kind, { + this.originalIndex, + this.suggestionIndex, + }); + final _AlignmentKind kind; + final int? originalIndex; + final int? suggestionIndex; +} + +List<_AlignmentOperation> _align( + List<_Cluster> original, + List<_Cluster> suggestion, +) { + final costs = List.generate( + original.length + 1, + (_) => List.filled(suggestion.length + 1, 0), + ); + for (var index = original.length; index >= 0; index--) { + costs[index][suggestion.length] = original.length - index; + } + for (var index = suggestion.length; index >= 0; index--) { + costs[original.length][index] = suggestion.length - index; + } + for (var i = original.length - 1; i >= 0; i--) { + for (var j = suggestion.length - 1; j >= 0; j--) { + if (unicode.nfc(original[i].text) == unicode.nfc(suggestion[j].text)) { + costs[i][j] = costs[i + 1][j + 1]; + } else { + final substitute = 1 + costs[i + 1][j + 1]; + final delete = 1 + costs[i + 1][j]; + final insert = 1 + costs[i][j + 1]; + costs[i][j] = [ + substitute, + delete, + insert, + ].reduce((left, right) => left < right ? left : right); + } + } + } + final operations = <_AlignmentOperation>[]; + var i = 0; + var j = 0; + while (i < original.length || j < suggestion.length) { + if (i < original.length && + j < suggestion.length && + unicode.nfc(original[i].text) == unicode.nfc(suggestion[j].text)) { + operations.add( + _AlignmentOperation( + _AlignmentKind.equal, + originalIndex: i, + suggestionIndex: j, + ), + ); + i++; + j++; + continue; + } + final current = costs[i][j]; + // Deterministic tie-breaking: substitution, then deletion, then insertion. + if (i < original.length && + j < suggestion.length && + current == 1 + costs[i + 1][j + 1]) { + operations.add( + _AlignmentOperation( + _AlignmentKind.substitute, + originalIndex: i, + suggestionIndex: j, + ), + ); + i++; + j++; + } else if (i < original.length && current == 1 + costs[i + 1][j]) { + operations.add( + _AlignmentOperation(_AlignmentKind.delete, originalIndex: i), + ); + i++; + } else { + operations.add( + _AlignmentOperation( + _AlignmentKind.insert, + originalIndex: i < original.length ? i : null, + suggestionIndex: j, + ), + ); + j++; + } + } + return operations; +} diff --git a/lib/src/spellcheck/spelling_session_controller.dart b/lib/src/spellcheck/spelling_session_controller.dart new file mode 100644 index 00000000..b331722e --- /dev/null +++ b/lib/src/spellcheck/spelling_session_controller.dart @@ -0,0 +1,1239 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/legacy.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; + +import '../app/app_settings.dart'; +import '../core/atomic_file_writer.dart'; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_model.dart'; +import '../workspace/document_buffer.dart'; +import '../workspace/workspace_model.dart'; +import 'spelling_catalog.dart'; +import 'spelling_coordinator.dart'; +import 'spelling_dictionary_downloader.dart'; +import 'spelling_dictionary_importer.dart'; +import 'spelling_dictionary_installer.dart'; +import 'spelling_language.dart'; +import 'spelling_projection.dart'; +import 'spelling_word_store.dart'; +import 'spelling_worker.dart'; + +typedef SpellingCoordinatorStarter = Future Function(); +typedef SpellingWordStoreFactory = + SpellingWordStore Function({ + required String filePath, + required bool projectStore, + }); +typedef SpellingWordStoreReader = + Future Function(SpellingWordStore store); + +SpellingWordStore _createSpellingWordStore({ + required String filePath, + required bool projectStore, +}) => SpellingWordStore(filePath: filePath, projectStore: projectStore); + +Future _readSpellingWordStore( + SpellingWordStore store, +) => store.read(); + +final spellingSessionControllerProvider = + ChangeNotifierProvider((ref) { + return SpellingSessionController( + applicationSupportRoot: Platform.environment.containsKey('FLUTTER_TEST') + ? p.join(Directory.systemTemp.path, 'busymark-spelling-tests-$pid') + : null, + ); + }); + +enum SpellingDictionaryInstallPhase { downloading, validating, failed } + +final class SpellingDictionaryInstallStatus { + const SpellingDictionaryInstallStatus({ + required this.resourceId, + required this.phase, + required this.receivedBytes, + required this.totalBytes, + this.error, + }); + + final String resourceId; + final SpellingDictionaryInstallPhase phase; + final int receivedBytes; + final int totalBytes; + final String? error; + + double? get progress => + totalBytes <= 0 ? null : (receivedBytes / totalBytes).clamp(0.0, 1.0); +} + +/// Application-side owner for the one reusable native spelling worker. +/// +/// This class deliberately owns presentation state rather than putting +/// annotations in [DocumentBuffer]. Checking therefore cannot dirty a buffer, +/// create history, serialize a rich document, or trigger autosave. +final class SpellingSessionController extends ChangeNotifier { + SpellingSessionController({ + this.bundledRoot, + this.applicationSupportRoot, + this.dictionaryStorageRoot, + this.environment, + this.verifyDictionaryChecksums = true, + this.dictionaryDownloader = const SpellingDictionaryDownloader(), + this.dictionaryInstaller = const SpellingDictionaryPairInstaller(), + SpellingCoordinatorStarter? coordinatorStarter, + SpellingWordStoreFactory? wordStoreFactory, + SpellingWordStoreReader? wordStoreReader, + }) : coordinatorStarter = coordinatorStarter ?? SpellingCoordinator.start, + wordStoreFactory = wordStoreFactory ?? _createSpellingWordStore, + wordStoreReader = wordStoreReader ?? _readSpellingWordStore; + + final String? bundledRoot; + final String? applicationSupportRoot; + final String? dictionaryStorageRoot; + final Map? environment; + final bool verifyDictionaryChecksums; + final SpellingDictionaryDownloader dictionaryDownloader; + final SpellingDictionaryPairInstaller dictionaryInstaller; + final SpellingCoordinatorStarter coordinatorStarter; + final SpellingWordStoreFactory wordStoreFactory; + final SpellingWordStoreReader wordStoreReader; + + SpellingCoordinator? _coordinator; + Future? _coordinatorStartup; + SpellingDictionaryCatalog? _catalog; + SpellingWordStore? _personalStore; + SpellingWordStore? _projectStore; + SpellingWordStoreSnapshot _personalWords = const SpellingWordStoreSnapshot( + revision: 0, + wordsByLanguage: {}, + ); + SpellingWordStoreSnapshot _projectWords = const SpellingWordStoreSnapshot( + revision: 0, + wordsByLanguage: {}, + ); + SpellingPresentationState _localState = + const SpellingPresentationState.languageRequired(); + SpellingEngineContext? _engineContext; + SpellingSessionInput? _latestInput; + String? _projectRoot; + Workspace? _settingsWorkspace; + String? _supportRoot; + String? _resolvedDictionaryStorageRoot; + bool _personalStorageInitialized = false; + bool _projectStorageInitialized = false; + Future<({SpellingWordStore store, SpellingWordStoreSnapshot snapshot})>? + _personalStorageLoad; + String? _requestedProjectRoot; + int _projectStorageGeneration = 0; + String _scheduledIdentity = ''; + String _contextIdentity = ''; + int _contextGeneration = 0; + int _operation = 0; + bool _disposed = false; + bool _manualReviewActive = false; + Set _openBufferIds = const {}; + SpellingDictionaryDownloadCancellation? _dictionaryDownloadCancellation; + SpellingDictionaryInstallStatus? _dictionaryInstallStatus; + bool _presentationUsesLocalState = true; + StreamSubscription? _projectStoreWatcher; + Timer? _projectStoreReloadDebounce; + String? _watchedProjectFile; + String? _watchedProjectDirectory; + int _projectWatcherGeneration = 0; + + SpellingPresentationState get state => _presentationUsesLocalState + ? _localState + : (_coordinator?.state ?? _localState); + List get annotations => _presentationUsesLocalState + ? const [] + : _coordinator?.annotations ?? const []; + List get misspellings => _presentationUsesLocalState + ? const [] + : _coordinator?.misspellings ?? const []; + SpellingDictionaryCatalog? get catalog => _catalog; + SpellingDictionaryInstallStatus? get dictionaryInstallStatus => + _dictionaryInstallStatus; + String? get effectiveLanguage => _engineContext?.languageId; + bool get hasProjectScope => _projectStore != null; + SpellingWordStoreSnapshot get personalWords => _personalWords; + SpellingWordStoreSnapshot get projectWords => _projectWords; + + Future prepareSettings(Workspace? workspace) async { + _settingsWorkspace = workspace; + await _initializeStorage(workspace); + if (!_disposed) notifyListeners(); + } + + void update(SpellingSessionInput input) { + final identity = input.identity; + if (identity == _scheduledIdentity) { + // An equivalent rebuild must not replace the object tracked by an + // in-flight initialization operation. Its immutable identity already + // represents this snapshot. + return; + } + _latestInput = input; + _scheduledIdentity = identity; + final operation = ++_operation; + _invalidatePresentation(); + unawaited( + _prepareAndSchedule( + input, + operation: operation, + manual: _manualReviewActive, + ), + ); + } + + Future checkNow(SpellingSessionInput input) async { + _manualReviewActive = true; + _latestInput = input; + _scheduledIdentity = input.identity; + final operation = ++_operation; + _invalidatePresentation(); + await _prepareAndSchedule(input, operation: operation, manual: true); + } + + void endManualReview() { + if (!_manualReviewActive) return; + _manualReviewActive = false; + _scheduledIdentity = ''; + final input = _latestInput; + if (input != null) update(input.refreshed()); + } + + Future> suggestions(SpellingOccurrence occurrence) async { + final coordinator = _coordinator; + final context = _engineContext; + if (coordinator == null || context == null) { + throw StateError('Dictionary unavailable.'); + } + if (!isCurrent(occurrence)) { + throw StateError('The spelling occurrence is stale.'); + } + final contextIdentity = context.identity; + final result = await coordinator.suggestions(occurrence, context: context); + if (!isCurrent(occurrence) || _engineContext?.identity != contextIdentity) { + throw StateError('The spelling occurrence became stale.'); + } + return result; + } + + bool isCurrent(SpellingOccurrence occurrence) => + !_presentationUsesLocalState && + occurrence.run.snapshot.bufferId == _latestInput?.buffer.id && + occurrence.run.snapshot.contentRevision == + _latestInput?.buffer.revision && + occurrence.run.snapshot.documentKind == _latestInput?.documentKind && + occurrence.run.snapshot.contextGeneration == _contextGeneration && + occurrence.run.languageId == _engineContext?.languageId && + (_coordinator?.isCurrent(occurrence) ?? false); + + SpellingOccurrence? occurrenceAtSource(int offset) => + _presentationUsesLocalState + ? null + : _coordinator?.occurrenceAtSource(offset); + + SpellingOccurrence? occurrenceAtField({ + required SpellingEditorTarget target, + required int offset, + }) => _presentationUsesLocalState + ? null + : _coordinator?.occurrenceAtField(target: target, offset: offset); + + void ignoreOnce(SpellingOccurrence occurrence) { + if (isCurrent(occurrence)) _coordinator?.ignoreOnce(occurrence); + } + + void ignoreAllInDocument(SpellingOccurrence occurrence) { + if (isCurrent(occurrence)) _coordinator?.ignoreAllInDocument(occurrence); + } + + Future addPersonalWord(SpellingOccurrence occurrence) async { + _requireCurrent(occurrence); + final store = _personalStore; + if (store == null) throw StateError('Personal dictionary is unavailable.'); + late final SpellingWordStoreSnapshot updated; + try { + updated = await store.addWord(occurrence.run.languageId, occurrence.word); + } on AtomicFileChangedException catch (error, stackTrace) { + await _reconcilePersonalStoreConflict(store); + Error.throwWithStackTrace(error, stackTrace); + } + if (!identical(store, _personalStore)) return; + _personalWords = updated; + await _refreshAfterPersistentChange(); + } + + Future addProjectWord(SpellingOccurrence occurrence) async { + _requireCurrent(occurrence); + final store = _projectStore; + if (store == null) { + throw StateError('This document is not associated with a project.'); + } + final projectRoot = _projectRoot; + late final SpellingWordStoreSnapshot updated; + try { + updated = await store.addWord(occurrence.run.languageId, occurrence.word); + } on AtomicFileChangedException catch (error, stackTrace) { + await _reconcileProjectStoreConflict(store, projectRoot); + Error.throwWithStackTrace(error, stackTrace); + } + if (!identical(store, _projectStore) || projectRoot != _projectRoot) return; + _projectWords = updated; + await _refreshAfterPersistentChange(); + } + + Future removePersonalWord(String languageId, String word) async { + final store = _personalStore; + if (store == null) throw StateError('Personal dictionary is unavailable.'); + late final SpellingWordStoreSnapshot updated; + try { + updated = await store.removeWord(languageId, word); + } on AtomicFileChangedException catch (error, stackTrace) { + await _reconcilePersonalStoreConflict(store); + Error.throwWithStackTrace(error, stackTrace); + } + if (!identical(store, _personalStore)) return; + _personalWords = updated; + await _refreshAfterPersistentChange(); + } + + Future removeProjectWord(String languageId, String word) async { + final store = _projectStore; + if (store == null) throw StateError('Project dictionary is unavailable.'); + final projectRoot = _projectRoot; + late final SpellingWordStoreSnapshot updated; + try { + updated = await store.removeWord(languageId, word); + } on AtomicFileChangedException catch (error, stackTrace) { + await _reconcileProjectStoreConflict(store, projectRoot); + Error.throwWithStackTrace(error, stackTrace); + } + if (!identical(store, _projectStore) || projectRoot != _projectRoot) return; + _projectWords = updated; + await _refreshAfterPersistentChange(); + } + + Future importDictionary({ + required String affPath, + required String dicPath, + required String languageId, + required String displayLabel, + }) async { + await _ensureStorageRoot(); + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + final normalizedLanguage = normalizeSpellingLanguageId(languageId); + if (normalizedLanguage == null) { + throw const FormatException('Choose an explicit valid language tag.'); + } + final collision = + _catalog?.installations.any( + (installation) => installation.resourceId == normalizedLanguage, + ) ?? + false; + final invalidCollision = + _catalog?.invalidInstallations.any( + (installation) => + installation.resourceId == normalizedLanguage || + installation.id == normalizedLanguage, + ) ?? + false; + if (collision || invalidCollision) { + throw StateError( + 'A dictionary installation already uses $normalizedLanguage. ' + 'Remove it before importing a replacement.', + ); + } + final dictionaryRoot = await _ensureDictionaryStorageRoot(); + await _ensureCoordinator(); + final coordinator = _coordinator; + if (coordinator == null) { + throw StateError('The spelling service is unavailable.'); + } + await const SpellingDictionaryImporter().import( + affPath: affPath, + dicPath: dicPath, + languageId: languageId, + displayLabel: displayLabel, + importedRoot: p.join(dictionaryRoot, 'imported'), + validateNativePair: (aff, dic, probe) => coordinator.validateDictionary( + affPath: aff, + dicPath: dic, + knownValidProbe: probe, + ), + ); + await _reloadCatalogAndRefresh(); + } + + Future removeImportedDictionary(String languageId) async { + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + final installation = _catalog?.installedById(languageId); + if (installation != null && installation.imported) { + await _releaseAndRemoveInstallation(installation); + return; + } + final invalid = _catalog?.invalidById(languageId); + if (invalid != null && + invalid.kind == SpellingDictionaryInstallationKind.imported) { + await _releaseAndRemoveInvalidInstallation(invalid); + } + } + + Future removeInvalidDictionary( + SpellingInvalidDictionaryInstallation installation, + ) async { + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + final current = + _catalog?.invalidInstallations.any( + (candidate) => + candidate.directoryPath == installation.directoryPath && + candidate.kind == installation.kind, + ) ?? + false; + if (!current) return; + await _releaseAndRemoveInvalidInstallation(installation); + } + + Future installDictionary(String languageId) async { + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + final catalog = _catalog; + final resource = catalog?.availableById(languageId); + if (resource == null) { + throw StateError('Dictionary resource is not in the shipped catalog.'); + } + final existing = catalog!.installationForResource(resource.resourceId); + if (existing != null) { + if (existing.kind == SpellingDictionaryInstallationKind.downloaded) { + return; + } + throw StateError( + 'Remove the local import before installing the catalog dictionary.', + ); + } + final invalidInstallation = catalog.invalidInstallations + .where( + (candidate) => + candidate.kind == SpellingDictionaryInstallationKind.downloaded && + (candidate.resourceId == resource.resourceId || + candidate.matches(resource.resourceId)), + ) + .firstOrNull; + if (_dictionaryDownloadCancellation != null) { + throw StateError('Another dictionary installation is in progress.'); + } + final dictionaryRoot = await _ensureDictionaryStorageRoot(); + await _ensureCoordinator(); + final coordinator = _coordinator; + if (coordinator == null) { + throw StateError('The spelling service is unavailable.'); + } + final cancellation = SpellingDictionaryDownloadCancellation(); + _dictionaryDownloadCancellation = cancellation; + _dictionaryInstallStatus = SpellingDictionaryInstallStatus( + resourceId: resource.resourceId, + phase: SpellingDictionaryInstallPhase.downloading, + receivedBytes: 0, + totalBytes: resource.downloadSize, + ); + notifyListeners(); + try { + await dictionaryDownloader.install( + resource: resource, + downloadedRoot: p.join(dictionaryRoot, 'downloaded'), + validateNativePair: (aff, dic, probe) => coordinator.validateDictionary( + affPath: aff, + dicPath: dic, + knownValidProbe: probe, + ), + cancellation: cancellation, + onProgress: (received, total) { + if (_disposed || + !identical(_dictionaryDownloadCancellation, cancellation)) { + return; + } + _dictionaryInstallStatus = SpellingDictionaryInstallStatus( + resourceId: resource.resourceId, + phase: received >= total + ? SpellingDictionaryInstallPhase.validating + : SpellingDictionaryInstallPhase.downloading, + receivedBytes: received, + totalBytes: total, + ); + notifyListeners(); + }, + replaceExisting: invalidInstallation != null, + ); + _dictionaryInstallStatus = null; + await _reloadCatalogAndRefresh(); + } on SpellingDictionaryDownloadCancelled { + _dictionaryInstallStatus = null; + if (!_disposed) notifyListeners(); + } on Object catch (error) { + _dictionaryInstallStatus = SpellingDictionaryInstallStatus( + resourceId: resource.resourceId, + phase: SpellingDictionaryInstallPhase.failed, + receivedBytes: _dictionaryInstallStatus?.receivedBytes ?? 0, + totalBytes: resource.downloadSize, + error: error.toString(), + ); + if (!_disposed) notifyListeners(); + rethrow; + } finally { + if (identical(_dictionaryDownloadCancellation, cancellation)) { + _dictionaryDownloadCancellation = null; + } + } + } + + void cancelDictionaryInstallation() { + _dictionaryDownloadCancellation?.cancel(); + } + + Future retryDictionaryInstallation() async { + final status = _dictionaryInstallStatus; + if (status == null || + status.phase != SpellingDictionaryInstallPhase.failed) { + return; + } + _dictionaryInstallStatus = null; + final resource = _catalog?.availableEntries + .where((entry) => entry.resourceId == status.resourceId) + .firstOrNull; + if (resource == null) return; + await installDictionary(resource.id); + } + + Future removeDownloadedDictionary(String languageId) async { + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + final catalog = _catalog; + final resource = catalog?.availableById(languageId); + final installation = resource == null + ? catalog?.installations + .where( + (candidate) => + candidate.kind == + SpellingDictionaryInstallationKind.downloaded && + (candidate.id == languageId || + candidate.locales.contains(languageId)), + ) + .firstOrNull + : catalog?.installationForResource( + resource.resourceId, + kind: SpellingDictionaryInstallationKind.downloaded, + ); + if (installation != null) { + await _releaseAndRemoveInstallation(installation); + return; + } + final invalid = catalog?.invalidInstallations + .where( + (candidate) => + candidate.kind == SpellingDictionaryInstallationKind.downloaded && + (candidate.matches(languageId) || + resource != null && + candidate.resourceId == resource.resourceId), + ) + .firstOrNull; + if (invalid != null && + invalid.kind == SpellingDictionaryInstallationKind.downloaded) { + await _releaseAndRemoveInvalidInstallation(invalid); + } + } + + Future setProjectLanguage(String? languageId) async { + final store = _projectStore; + if (store == null) { + throw StateError('This workspace has no project spelling scope.'); + } + final projectRoot = _projectRoot; + late final SpellingWordStoreSnapshot updated; + try { + updated = await store.setProjectLanguage(languageId); + } on AtomicFileChangedException catch (error, stackTrace) { + await _reconcileProjectStoreConflict(store, projectRoot); + Error.throwWithStackTrace(error, stackTrace); + } + if (!identical(store, _projectStore) || projectRoot != _projectRoot) return; + _projectWords = updated; + await _refreshAfterPersistentChange(); + } + + Future _reconcilePersonalStoreConflict(SpellingWordStore store) async { + if (!identical(store, _personalStore)) return; + try { + final actual = await wordStoreReader(store); + if (!identical(store, _personalStore)) return; + _personalWords = actual; + await _refreshAfterPersistentChange(); + } on Object { + // Reconciliation is best effort; the publication conflict remains the + // caller-visible failure and must retain its recovery-path detail. + } + } + + Future _reconcileProjectStoreConflict( + SpellingWordStore store, + String? projectRoot, + ) async { + if (!identical(store, _projectStore) || projectRoot != _projectRoot) return; + try { + final actual = await wordStoreReader(store); + if (!identical(store, _projectStore) || projectRoot != _projectRoot) { + return; + } + _projectWords = actual; + await _refreshAfterPersistentChange(); + } on Object { + // Preserve the original typed conflict for the initiating UI. + } + } + + void closeBuffer(String bufferId) => _coordinator?.closeBuffer(bufferId); + + void invalidateBufferAnchors(String bufferId) => + _coordinator?.invalidateBufferAnchors(bufferId); + + /// Clears document-session ignores only for buffers that actually left the + /// workspace. Merely activating another tab must retain them. + void synchronizeOpenBuffers(Iterable bufferIds) { + final next = Set.unmodifiable(bufferIds); + for (final previous in _openBufferIds) { + if (!next.contains(previous)) _coordinator?.closeBuffer(previous); + } + _openBufferIds = next; + } + + void translateSourceEdit({ + required String bufferId, + required int start, + required int oldEnd, + required int newEnd, + }) => _coordinator?.translateSourceEdit( + bufferId: bufferId, + start: start, + oldEnd: oldEnd, + newEnd: newEnd, + ); + + Future _prepareAndSchedule( + SpellingSessionInput input, { + required int operation, + bool manual = false, + }) async { + final override = input.buffer.editorState.spellingLanguage; + if (override.kind == SpellingLanguageOverrideKind.disabled) { + _showDisabled(); + return; + } + if (!manual && !input.settings.automaticSpelling) { + _showDisabled(); + return; + } + if (!input.documentKind.supportsSpelling) { + _showDisabled(); + return; + } + try { + await _initializeStorage(input.workspace); + if (!_isOperationCurrent(operation, input)) return; + final languageId = resolveSpellingLanguageId( + override: override, + projectLanguage: _projectWords.projectLanguage, + defaultLanguage: input.settings.defaultSpellingLanguage, + ); + if (languageId == null) { + _showLanguageRequired(); + return; + } + final entry = _catalog?.byId(languageId); + if (entry == null) { + await _ensureCoordinator(); + if (!_isOperationCurrent(operation, input)) return; + _presentationUsesLocalState = false; + _coordinator!.showDictionaryUnavailable(languageId); + return; + } + final installation = entry.installation; + if (installation == null) { + await _ensureCoordinator(); + if (!_isOperationCurrent(operation, input)) return; + _engineContext = null; + _presentationUsesLocalState = false; + _coordinator!.showDictionaryNotInstalled(languageId); + return; + } + final customWords = { + ..._personalWords.wordsFor(languageId), + ..._projectWords.wordsFor(languageId), + }.toList(growable: false); + final nextEngineContext = SpellingEngineContext( + languageId: languageId, + affPath: installation.affPath, + dicPath: installation.dicPath, + baseFingerprint: installation.fingerprint, + personalRevision: _personalWords.revision, + projectIdentity: _projectRoot, + projectRevision: _projectWords.revision, + customWords: customWords, + ); + if (nextEngineContext.identity != _contextIdentity) { + _contextIdentity = nextEngineContext.identity; + _contextGeneration++; + } + _engineContext = nextEngineContext; + final snapshot = SpellingSnapshotIdentity( + bufferId: input.buffer.id, + contentRevision: input.buffer.revision, + documentKind: input.documentKind, + contextGeneration: _contextGeneration, + ); + final request = SpellingCheckRequest( + snapshot: snapshot, + engineContext: _engineContext!, + automatic: !manual, + project: () => _projectOnWorker(input, languageId, snapshot), + ); + await _ensureCoordinator(); + if (!_isOperationCurrent(operation, input)) return; + if (manual) { + _presentationUsesLocalState = false; + await _coordinator!.checkNow(request); + } else { + _presentationUsesLocalState = false; + _coordinator!.schedule(request); + } + } on Object catch (error) { + if (!_isOperationCurrent(operation, input)) return; + _localState = SpellingPresentationState( + status: SpellingPresentationStatus.failure, + occurrences: const [], + complete: false, + message: error.toString(), + ); + _presentationUsesLocalState = true; + notifyListeners(); + } + } + + Future _projectOnWorker( + SpellingSessionInput input, + String languageId, + SpellingSnapshotIdentity snapshot, + ) { + final coordinator = _coordinator; + if (coordinator == null) { + throw StateError('The spelling worker is unavailable.'); + } + return coordinator.project( + SpellingProjectionJob( + filePath: input.buffer.filePath ?? input.buffer.id, + source: input.buffer.text, + documentKind: input.documentKind, + markdownMode: input.markdownMode, + languageId: languageId, + snapshot: snapshot, + richDocument: input.richDocument, + richDocumentGeneration: input.richDocumentGeneration, + ), + ); + } + + Future _initializeStorage(Workspace? workspace) async { + final supportRoot = await _ensureStorageRoot(); + if (!_personalStorageInitialized) { + final load = _personalStorageLoad ??= () async { + final store = wordStoreFactory( + filePath: p.join(supportRoot, 'spelling', 'personal.json'), + projectStore: false, + ); + return (store: store, snapshot: await wordStoreReader(store)); + }(); + final loaded = await load; + if (!_disposed && !_personalStorageInitialized) { + _personalStore = loaded.store; + _personalWords = loaded.snapshot; + _personalStorageInitialized = true; + } + } + + final nextProjectRoot = _projectScopeRoot(workspace); + _requestedProjectRoot = nextProjectRoot; + final projectGeneration = ++_projectStorageGeneration; + final nextProjectStore = nextProjectRoot == null + ? null + : _projectStorageInitialized && _projectRoot == nextProjectRoot + ? _projectStore + : wordStoreFactory( + filePath: p.join(nextProjectRoot, '.busymark', 'spelling.json'), + projectStore: true, + ); + final nextProjectWords = + (nextProjectStore == null + ? null + : await wordStoreReader(nextProjectStore)) ?? + const SpellingWordStoreSnapshot(revision: 0, wordsByLanguage: {}); + if (!_disposed && + projectGeneration == _projectStorageGeneration && + _requestedProjectRoot == nextProjectRoot) { + _projectRoot = nextProjectRoot; + _projectStore = nextProjectStore; + _projectWords = nextProjectWords; + _projectStorageInitialized = true; + _watchProjectStore(nextProjectRoot, nextProjectStore?.filePath); + } + + // Available metadata is shipped with BusyMark. Only application-managed + // installations are opened and checksum-verified. + if (_catalog == null) { + final resourceRoot = + bundledRoot ?? const SpellingResourceLocator().locate(); + if (resourceRoot == null) { + _catalog = const SpellingDictionaryCatalog( + availableEntries: [], + installations: [], + unavailableEntries: { + 'bundle': 'Dictionary catalog metadata is unavailable.', + }, + ); + } else { + final dictionaryRoot = await _ensureDictionaryStorageRoot(); + _catalog = await SpellingDictionaryCatalog.load( + bundledRoot: resourceRoot, + downloadedRoot: p.join(dictionaryRoot, 'downloaded'), + importedRoot: p.join(dictionaryRoot, 'imported'), + verifyChecksums: verifyDictionaryChecksums, + ); + } + } + } + + Future _ensureStorageRoot() async { + final existing = _supportRoot; + if (existing != null) return existing; + final resolved = + applicationSupportRoot ?? (await getApplicationSupportDirectory()).path; + _supportRoot = resolved; + return resolved; + } + + Future _ensureDictionaryStorageRoot() async { + final existing = _resolvedDictionaryStorageRoot; + if (existing != null) return existing; + _resolvedDictionaryStorageRoot = resolveSpellingDictionaryStorageRoot( + applicationSupportRoot: await _ensureStorageRoot(), + dictionaryStorageRoot: dictionaryStorageRoot, + environment: environment, + ); + return _resolvedDictionaryStorageRoot!; + } + + Future _releaseAndRemoveInstallation( + SpellingDictionaryInstallation installation, + ) async { + final coordinator = _coordinator; + if (coordinator != null) { + coordinator.disablePresentation(); + await coordinator.releaseDictionary(); + } + _engineContext = null; + _contextIdentity = ''; + final dictionaryRoot = await _ensureDictionaryStorageRoot(); + final root = p.join( + dictionaryRoot, + installation.imported ? 'imported' : 'downloaded', + ); + await dictionaryInstaller.remove( + installation: installation, + installationRoot: root, + ); + await _reloadCatalogAndRefresh(); + } + + Future _releaseAndRemoveInvalidInstallation( + SpellingInvalidDictionaryInstallation installation, + ) async { + final coordinator = _coordinator; + if (coordinator != null) { + coordinator.disablePresentation(); + await coordinator.releaseDictionary(); + } + _engineContext = null; + _contextIdentity = ''; + final dictionaryRoot = await _ensureDictionaryStorageRoot(); + final root = p.join( + dictionaryRoot, + installation.kind == SpellingDictionaryInstallationKind.imported + ? 'imported' + : 'downloaded', + ); + await dictionaryInstaller.removeInvalid( + installation: installation, + installationRoot: root, + ); + await _reloadCatalogAndRefresh(); + } + + Future _reloadCatalogAndRefresh() async { + _catalog = null; + await _initializeStorage(_latestInput?.workspace ?? _settingsWorkspace); + if (!_disposed) notifyListeners(); + await _refreshAfterPersistentChange(); + } + + Future _ensureCoordinator() async { + if (_coordinator != null) return; + final startup = _coordinatorStartup ??= coordinatorStarter(); + late final SpellingCoordinator coordinator; + try { + coordinator = await startup; + } on Object { + if (identical(_coordinatorStartup, startup)) _coordinatorStartup = null; + rethrow; + } + if (_disposed) { + coordinator.dispose(); + return; + } + if (_coordinator == null) { + _coordinator = coordinator..addListener(_forwardCoordinatorChange); + } else if (!identical(_coordinator, coordinator)) { + coordinator.dispose(); + } + } + + void _watchProjectStore(String? projectRoot, String? filePath) { + final normalizedFile = filePath == null + ? null + : p.normalize(p.absolute(filePath)); + if (_watchedProjectFile == normalizedFile && _projectStoreWatcher != null) { + return; + } + _watchedProjectFile = normalizedFile; + _projectStoreReloadDebounce?.cancel(); + _projectStoreReloadDebounce = null; + _installProjectStoreWatcher(projectRoot, normalizedFile); + } + + void _installProjectStoreWatcher( + String? projectRoot, + String? normalizedFile, + ) { + final generation = ++_projectWatcherGeneration; + unawaited(_projectStoreWatcher?.cancel()); + _projectStoreWatcher = null; + _watchedProjectDirectory = null; + if (projectRoot == null || normalizedFile == null || _disposed) return; + + final desiredParent = p.dirname(normalizedFile); + var watchedDirectory = desiredParent; + while (!Directory(watchedDirectory).existsSync()) { + final parent = p.dirname(watchedDirectory); + if (parent == watchedDirectory || + !p.isWithin(p.normalize(p.absolute(projectRoot)), parent) && + p.normalize(p.absolute(projectRoot)) != parent) { + watchedDirectory = p.normalize(p.absolute(projectRoot)); + break; + } + watchedDirectory = parent; + } + if (!Directory(watchedDirectory).existsSync()) return; + _watchedProjectDirectory = watchedDirectory; + + late final StreamSubscription subscription; + var reattachRequired = false; + void reinstallAndReload({bool forceReattach = false}) { + if (_disposed || + generation != _projectWatcherGeneration || + _watchedProjectFile != normalizedFile) { + return; + } + reattachRequired = reattachRequired || forceReattach; + _projectStoreReloadDebounce?.cancel(); + _projectStoreReloadDebounce = Timer( + const Duration(milliseconds: 100), + () { + if (_disposed || generation != _projectWatcherGeneration) return; + final parentNowExists = Directory(desiredParent).existsSync(); + final shouldReattach = + reattachRequired || + _projectStoreWatcher == null || + parentNowExists && _watchedProjectDirectory != desiredParent; + reattachRequired = false; + if (shouldReattach) { + _installProjectStoreWatcher(projectRoot, normalizedFile); + } + unawaited(_reloadProjectWordsFromDisk()); + }, + ); + } + + subscription = Directory(watchedDirectory).watch().listen( + (event) { + bool touchesProjectStore(String rawPath) { + final eventPath = p.normalize(p.absolute(rawPath)); + return eventPath == normalizedFile || + eventPath == desiredParent || + p.isWithin(eventPath, normalizedFile) || + p.isWithin(eventPath, desiredParent); + } + + final relevant = + touchesProjectStore(event.path) || + event is FileSystemMoveEvent && + event.destination != null && + touchesProjectStore(event.destination!); + if (relevant) reinstallAndReload(); + }, + onError: (_) { + if (identical(_projectStoreWatcher, subscription)) { + _projectStoreWatcher = null; + reinstallAndReload(forceReattach: true); + } + }, + onDone: () { + if (identical(_projectStoreWatcher, subscription)) { + _projectStoreWatcher = null; + reinstallAndReload(forceReattach: true); + } + }, + ); + _projectStoreWatcher = subscription; + } + + Future _reloadProjectWordsFromDisk() async { + final store = _projectStore; + final root = _projectRoot; + if (_disposed || store == null || root == null) return; + try { + final snapshot = await wordStoreReader(store); + if (_disposed || + !identical(store, _projectStore) || + root != _projectRoot) { + return; + } + if (_sameWordStoreSnapshot(snapshot, _projectWords)) return; + _projectWords = snapshot; + await _refreshAfterPersistentChange(); + } on Object catch (error) { + if (_disposed || + !identical(store, _projectStore) || + root != _projectRoot) { + return; + } + _localState = SpellingPresentationState( + status: SpellingPresentationStatus.failure, + occurrences: const [], + complete: false, + message: error.toString(), + ); + _presentationUsesLocalState = true; + notifyListeners(); + } + } + + void _forwardCoordinatorChange() => notifyListeners(); + + void _showLanguageRequired() { + if (_coordinator case final coordinator?) { + _presentationUsesLocalState = false; + coordinator.showLanguageRequired(); + } else { + _localState = const SpellingPresentationState.languageRequired(); + notifyListeners(); + } + } + + void _showDisabled() { + if (_coordinator case final coordinator?) { + _presentationUsesLocalState = false; + coordinator.disablePresentation(); + } else { + _localState = const SpellingPresentationState( + status: SpellingPresentationStatus.disabled, + occurrences: [], + complete: false, + ); + notifyListeners(); + } + } + + bool _isOperationCurrent(int operation, SpellingSessionInput input) => + !_disposed && + operation == _operation && + _latestInput?.identity == input.identity; + + void _requireCurrent(SpellingOccurrence occurrence) { + if (!isCurrent(occurrence)) { + throw StateError('The spelling occurrence is stale.'); + } + } + + Future _refreshAfterPersistentChange() async { + _scheduledIdentity = ''; + final input = _latestInput; + if (input == null) { + if (!_disposed) notifyListeners(); + return; + } + final refreshed = input.refreshed(); + _latestInput = refreshed; + if (_manualReviewActive) { + _invalidatePresentation(); + final operation = ++_operation; + await _prepareAndSchedule(refreshed, operation: operation, manual: true); + } else { + update(refreshed); + } + } + + void _invalidatePresentation() { + _engineContext = null; + _presentationUsesLocalState = true; + _localState = const SpellingPresentationState( + status: SpellingPresentationStatus.checking, + occurrences: [], + complete: false, + ); + notifyListeners(); + } + + @override + void dispose() { + if (_disposed) return; + _disposed = true; + _operation++; + _dictionaryDownloadCancellation?.cancel(); + _projectStoreReloadDebounce?.cancel(); + unawaited(_projectStoreWatcher?.cancel()); + final coordinator = _coordinator; + if (coordinator != null) { + coordinator.removeListener(_forwardCoordinatorChange); + coordinator.dispose(); + } + super.dispose(); + } +} + +String resolveSpellingDictionaryStorageRoot({ + required String applicationSupportRoot, + String? dictionaryStorageRoot, + Map? environment, +}) { + final processEnvironment = environment ?? Platform.environment; + final snapCommon = processEnvironment['SNAP_USER_COMMON']?.trim(); + final configuredRoot = processEnvironment['BUSYMARK_SPELLING_INSTALL_ROOT'] + ?.trim(); + final resolved = + dictionaryStorageRoot ?? + (configuredRoot != null && configuredRoot.isNotEmpty + ? configuredRoot + : snapCommon != null && snapCommon.isNotEmpty + ? p.join(snapCommon, 'spelling', 'dictionaries') + : p.join(applicationSupportRoot, 'spelling', 'dictionaries')); + return p.normalize(p.absolute(resolved)); +} + +final class SpellingSessionInput { + const SpellingSessionInput({ + required this.buffer, + required this.workspace, + required this.settings, + required this.documentKind, + required this.markdownMode, + this.richDocument, + this.richDocumentGeneration = 0, + this.refreshToken = 0, + }); + + final DocumentBuffer buffer; + final Workspace? workspace; + final AppSettings settings; + final DocumentKind documentKind; + final MarkdownMode markdownMode; + final BusyDocument? richDocument; + final int richDocumentGeneration; + final int refreshToken; + + String get identity => [ + buffer.id, + buffer.filePath ?? '', + buffer.revision, + buffer.editorState.spellingLanguage.kind.name, + buffer.editorState.spellingLanguage.languageId ?? '', + workspace?.id ?? '', + settings.automaticSpelling, + settings.defaultSpellingLanguage ?? '', + documentKind.name, + richDocument == null ? 'source' : 'rich', + richDocumentGeneration, + refreshToken, + ].join('\u0000'); + + SpellingSessionInput refreshed() => SpellingSessionInput( + buffer: buffer, + workspace: workspace, + settings: settings, + documentKind: documentKind, + markdownMode: markdownMode, + richDocument: richDocument, + richDocumentGeneration: richDocumentGeneration, + refreshToken: refreshToken + 1, + ); + + SpellingSessionInput withRichDocumentGeneration(int generation) => + SpellingSessionInput( + buffer: buffer, + workspace: workspace, + settings: settings, + documentKind: documentKind, + markdownMode: markdownMode, + richDocument: richDocument, + richDocumentGeneration: generation, + refreshToken: refreshToken, + ); +} + +String? resolveSpellingLanguageId({ + required SpellingLanguageOverride override, + required String? projectLanguage, + required String? defaultLanguage, +}) { + return switch (override.kind) { + SpellingLanguageOverrideKind.selected => override.languageId, + SpellingLanguageOverrideKind.inherit => projectLanguage ?? defaultLanguage, + SpellingLanguageOverrideKind.disabled => null, + }; +} + +bool _sameWordStoreSnapshot( + SpellingWordStoreSnapshot left, + SpellingWordStoreSnapshot right, +) { + if (left.revision != right.revision || + left.projectLanguage != right.projectLanguage || + left.wordsByLanguage.length != right.wordsByLanguage.length) { + return false; + } + for (final entry in left.wordsByLanguage.entries) { + final other = right.wordsByLanguage[entry.key]; + if (other == null || other.length != entry.value.length) return false; + for (var index = 0; index < other.length; index++) { + if (entry.value[index].key != other[index].key || + entry.value[index].display != other[index].display) { + return false; + } + } + } + return true; +} + +String? _projectScopeRoot(Workspace? workspace) => switch (workspace?.kind) { + WorkspaceKind.markdownFolder || + WorkspaceKind.writersideModule => workspace!.rootPath, + _ => null, +}; diff --git a/lib/src/spellcheck/spelling_text_patterns.dart b/lib/src/spellcheck/spelling_text_patterns.dart new file mode 100644 index 00000000..262b5dbd --- /dev/null +++ b/lib/src/spellcheck/spelling_text_patterns.dart @@ -0,0 +1,5 @@ +/// Visible addresses are not prose in either Source or rich editor fields. +final spellingPlainAddress = RegExp( + r'''(?:https?|ftp)://[^\s<>()]+|www\.[^\s<>()]+|[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}''', + caseSensitive: false, +); diff --git a/lib/src/spellcheck/spelling_word_store.dart b/lib/src/spellcheck/spelling_word_store.dart new file mode 100644 index 00000000..fcfed70a --- /dev/null +++ b/lib/src/spellcheck/spelling_word_store.dart @@ -0,0 +1,345 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:crypto/crypto.dart'; +import 'package:unorm_dart/unorm_dart.dart' as unicode; + +import '../core/atomic_file_writer.dart'; +import 'spelling_language.dart'; + +final class SpellingWordEntry { + const SpellingWordEntry({required this.key, required this.display}); + + final String key; + final String display; + + Map toJson() => {'key': key, 'display': display}; +} + +final class SpellingWordStoreSnapshot { + const SpellingWordStoreSnapshot({ + required this.revision, + required this.wordsByLanguage, + this.projectLanguage, + }); + + final int revision; + final Map> wordsByLanguage; + final String? projectLanguage; + + Iterable wordsFor(String languageId) => + wordsByLanguage[languageId]?.map((entry) => entry.display) ?? const []; +} + +/// A serialized, atomic JSON word store. Each mutation rereads the current +/// file, so independent external additions and removals are not overwritten by +/// a stale in-memory snapshot. +final class SpellingWordStore { + SpellingWordStore({ + required this.filePath, + this.projectStore = false, + AtomicFileWriter writer = const AtomicFileWriter(), + }) : _writer = writer; + + final String filePath; + final bool projectStore; + final AtomicFileWriter _writer; + static final Map> _writeTails = {}; + + Future read() async { + final file = File(filePath); + if (!await file.exists()) { + return const SpellingWordStoreSnapshot(revision: 0, wordsByLanguage: {}); + } + try { + final decoded = jsonDecode(await file.readAsString()); + if (decoded is! Map || decoded['schemaVersion'] != 1) { + throw const FormatException('Unsupported spelling word-store schema.'); + } + final words = >{}; + final rawWords = decoded['words']; + if (rawWords is Map) { + for (final entry in rawWords.entries) { + final language = normalizeSpellingLanguageId(entry.key); + if (language == null || entry.value is! List) continue; + final values = []; + for (final item in (entry.value as List)) { + if (item is String) { + final display = _validatedSpellingWord(item); + if (!values.any( + (entry) => entry.key == normalizeSpellingWordKey(display), + )) { + values.add( + SpellingWordEntry( + key: normalizeSpellingWordKey(display), + display: display, + ), + ); + } + } else if (item is Map) { + final display = _validatedSpellingWord( + item['display']?.toString() ?? '', + ); + final key = normalizeSpellingWordKey(display); + if (!values.any((entry) => entry.key == key)) { + values.add(SpellingWordEntry(key: key, display: display)); + } + } + } + values.sort((left, right) => left.display.compareTo(right.display)); + words[language] = List.unmodifiable(values); + } + } + return SpellingWordStoreSnapshot( + revision: (decoded['revision'] as num?)?.toInt() ?? 0, + projectLanguage: normalizeSpellingLanguageId( + decoded['projectLanguage'], + ), + wordsByLanguage: Map.unmodifiable(words), + ); + } on FormatException { + rethrow; + } on Object catch (error) { + throw FormatException('Could not read spelling words: $error'); + } + } + + Future addWord(String languageId, String word) => + _mutate((snapshot) { + final display = _validatedSpellingWord(word); + final key = normalizeSpellingWordKey(display); + final words = _mutableWords(snapshot); + final language = words.putIfAbsent( + normalizeSpellingLanguageId(languageId) ?? languageId, + () => [], + ); + if (!language.any((entry) => entry.key == key)) { + language.add(SpellingWordEntry(key: key, display: display)); + } + return SpellingWordStoreSnapshot( + revision: snapshot.revision + 1, + projectLanguage: snapshot.projectLanguage, + wordsByLanguage: words, + ); + }); + + Future removeWord( + String languageId, + String word, + ) => _mutate((snapshot) { + final words = _mutableWords(snapshot); + words[normalizeSpellingLanguageId(languageId) ?? languageId]?.removeWhere( + (entry) => entry.key == normalizeSpellingWordKey(word), + ); + return SpellingWordStoreSnapshot( + revision: snapshot.revision + 1, + projectLanguage: snapshot.projectLanguage, + wordsByLanguage: words, + ); + }); + + Future setProjectLanguage(String? languageId) { + if (!projectStore) { + throw StateError('Personal word stores do not have a project language.'); + } + return _mutate( + (snapshot) => SpellingWordStoreSnapshot( + revision: snapshot.revision + 1, + projectLanguage: normalizeSpellingLanguageId(languageId), + wordsByLanguage: _mutableWords(snapshot), + ), + ); + } + + Future _mutate( + SpellingWordStoreSnapshot Function(SpellingWordStoreSnapshot) change, + ) { + final identity = _canonicalStoreIdentity(filePath); + final completer = Completer(); + final previous = _writeTails[identity] ?? Future.value(); + final operation = previous.catchError((_) {}).then((_) async { + try { + final lockFile = File('$identity.lock'); + final lockParent = lockFile.parent; + if (!await lockParent.exists()) { + await lockParent.create(recursive: true); + } + final lock = await lockFile.open(mode: FileMode.append); + try { + await _acquireExclusiveLock(lock); + for (var attempt = 0; attempt < 3; attempt++) { + final beforeRead = await _fileIdentity(); + final current = await read(); + final updated = change(current); + if (await _fileIdentity() != beforeRead) continue; + try { + await _publish(updated, expectedIdentity: beforeRead); + } on _SpellingWordStoreConflict catch (_) { + continue; + } on AtomicFileChangedException catch (error) { + // A recovery path means publication ownership became uncertain + // after an exchange. Retrying could overwrite either BusyMark's + // proposal or a newer external version, so surface the conflict. + if (error.recoveryPath != null) rethrow; + continue; + } + final published = await read(); + if (!_sameSnapshot(published, updated)) continue; + completer.complete(published); + return; + } + throw const FileSystemException( + 'Spelling words changed repeatedly during publication.', + ); + } finally { + try { + await lock.unlock(); + } finally { + await lock.close(); + } + } + } on Object catch (error, stackTrace) { + completer.completeError(error, stackTrace); + } + }); + _writeTails[identity] = operation; + operation.whenComplete(() { + if (identical(_writeTails[identity], operation)) { + _writeTails.remove(identity); + } + }); + return completer.future; + } + + Future _fileIdentity() async { + return _identityForFile(File(filePath)); + } + + Future _publish( + SpellingWordStoreSnapshot snapshot, { + required String expectedIdentity, + }) async { + final parent = Directory(p.dirname(filePath)); + if (!await parent.exists()) await parent.create(recursive: true); + final json = { + 'schemaVersion': 1, + 'revision': snapshot.revision, + if (projectStore) 'projectLanguage': snapshot.projectLanguage, + 'words': { + for (final entry in snapshot.wordsByLanguage.entries) + entry.key: [ + for (final word + in entry.value..sort( + (left, right) => left.display.compareTo(right.display), + )) + word.toJson(), + ], + }, + }; + await _writer.writeBytes( + filePath, + utf8.encode('${const JsonEncoder.withIndent(' ').convert(json)}\n'), + overwrite: true, + beforePublish: () async { + if (await _fileIdentity() != expectedIdentity) { + throw const _SpellingWordStoreConflict(); + } + }, + acceptReplaced: (replacedPath) async { + if (expectedIdentity == 'missing') return false; + return await _identityForFile(File(replacedPath)) == expectedIdentity; + }, + ); + } +} + +Future _identityForFile(File file) async { + if (!await file.exists()) return 'missing'; + return (await sha256.bind(file.openRead()).first).toString(); +} + +bool _sameSnapshot( + SpellingWordStoreSnapshot left, + SpellingWordStoreSnapshot right, +) { + if (left.revision != right.revision || + left.projectLanguage != right.projectLanguage || + left.wordsByLanguage.length != right.wordsByLanguage.length) { + return false; + } + for (final entry in left.wordsByLanguage.entries) { + final other = right.wordsByLanguage[entry.key]; + if (other == null || other.length != entry.value.length) return false; + for (var index = 0; index < other.length; index++) { + if (other[index].key != entry.value[index].key || + other[index].display != entry.value[index].display) { + return false; + } + } + } + return true; +} + +Future _acquireExclusiveLock(RandomAccessFile file) async { + final stopwatch = Stopwatch()..start(); + while (true) { + try { + await file.lock(FileLock.exclusive); + return; + } on FileSystemException catch (error) { + // Linux reports a contended advisory lock as EAGAIN instead of waiting. + // Retry it so the lock covers the complete read/merge/publish transaction + // across independent BusyMark processes. + if (error.osError?.errorCode != 11 || + stopwatch.elapsed >= const Duration(seconds: 30)) { + rethrow; + } + await Future.delayed(const Duration(milliseconds: 10)); + } + } +} + +final class _SpellingWordStoreConflict implements Exception { + const _SpellingWordStoreConflict(); +} + +Map> _mutableWords( + SpellingWordStoreSnapshot snapshot, +) => { + for (final entry in snapshot.wordsByLanguage.entries) + entry.key: [...entry.value], +}; + +String normalizeSpellingWordKey(String word) => unicode.nfc(word.trim()); + +String _canonicalStoreIdentity(String filePath) { + final absolute = p.normalize(p.absolute(filePath)); + try { + return File(absolute).resolveSymbolicLinksSync(); + } on FileSystemException { + try { + return p.join( + Directory(p.dirname(absolute)).resolveSymbolicLinksSync(), + p.basename(absolute), + ); + } on FileSystemException { + return absolute; + } + } +} + +String _validatedSpellingWord(String word) { + final normalized = unicode.nfc(word.trim()); + if (normalized.isEmpty || + normalized.runes.length > 256 || + RegExp(r'[\u0000-\u001f\u007f-\u009f]').hasMatch(normalized)) { + throw ArgumentError.value( + word, + 'word', + 'Invalid persistent spelling word.', + ); + } + return normalized; +} diff --git a/lib/src/spellcheck/spelling_worker.dart b/lib/src/spellcheck/spelling_worker.dart new file mode 100644 index 00000000..19cbf059 --- /dev/null +++ b/lib/src/spellcheck/spelling_worker.dart @@ -0,0 +1,1353 @@ +import 'dart:async'; +import 'dart:collection'; +import 'dart:isolate'; + +import 'package:busymark_spellcheck_native/busymark_spellcheck_native.dart'; +import 'package:unorm_dart/unorm_dart.dart' as unicode; + +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_model.dart'; +import '../workspace/workspace_model.dart'; +import 'markdown_spelling_projection.dart'; +import 'spelling_projection.dart'; +import 'writerside_spelling_projection.dart'; +import 'wysiwyg_spelling_projection.dart'; + +final class SpellingProjectionJob { + const SpellingProjectionJob({ + required this.filePath, + required this.source, + required this.documentKind, + required this.markdownMode, + required this.languageId, + required this.snapshot, + this.richDocument, + this.richDocumentGeneration = 0, + }); + + final String filePath; + final String source; + final DocumentKind documentKind; + final MarkdownMode markdownMode; + final String languageId; + final SpellingSnapshotIdentity snapshot; + final BusyDocument? richDocument; + final int richDocumentGeneration; + + Map toMessage() => { + 'filePath': filePath, + 'source': source, + 'documentKind': documentKind.name, + 'markdownMode': markdownMode.name, + 'languageId': languageId, + 'snapshot': snapshot, + 'richDocument': richDocument, + 'richDocumentGeneration': richDocumentGeneration, + }; +} + +final class SpellingEngineContext { + const SpellingEngineContext({ + required this.languageId, + required this.affPath, + required this.dicPath, + required this.baseFingerprint, + required this.personalRevision, + required this.projectIdentity, + required this.projectRevision, + required this.customWords, + }); + + final String languageId; + final String affPath; + final String dicPath; + final String baseFingerprint; + final int personalRevision; + final String? projectIdentity; + final int projectRevision; + final List customWords; + + String get identity { + final effectiveWords = [...customWords]..sort(); + return [ + languageId, + baseFingerprint, + personalRevision, + projectIdentity ?? '', + projectRevision, + for (final word in effectiveWords) '${word.length}:$word', + ].join('\u0000'); + } + + Map toMessage() => { + 'languageId': languageId, + 'affPath': affPath, + 'dicPath': dicPath, + 'baseFingerprint': baseFingerprint, + 'personalRevision': personalRevision, + 'projectIdentity': projectIdentity, + 'projectRevision': projectRevision, + 'customWords': customWords, + 'identity': identity, + }; +} + +final class SpellingWorkerResult { + const SpellingWorkerResult({ + required this.requestId, + required this.occurrences, + required this.cancelled, + required this.complete, + this.error, + }); + + final int requestId; + final List occurrences; + final bool cancelled; + final bool complete; + final String? error; +} + +/// One reusable spelling isolate. It owns the only active native handle and +/// keeps at most one running request plus the newest pending replacement. +final class SpellingWorker { + SpellingWorker._( + this._isolate, + this._sendPort, + this._receivePort, + Stream responses, + ) { + _subscription = responses.listen(_handleMessage); + } + + final Isolate _isolate; + final SendPort _sendPort; + final ReceivePort _receivePort; + late final StreamSubscription _subscription; + final Map>> _pending = {}; + int _nextRequest = 1; + bool _closed = false; + + static Future start() async { + final receive = ReceivePort(); + final responses = receive.asBroadcastStream(); + final isolate = await Isolate.spawn(_spellingWorkerMain, receive.sendPort); + final first = await responses.first; + if (first is! SendPort) { + receive.close(); + isolate.kill(priority: Isolate.immediate); + throw StateError('Spelling worker did not initialize.'); + } + return SpellingWorker._(isolate, first, receive, responses); + } + + Future check({ + required SpellingEngineContext context, + required List runs, + }) async { + _requireOpen(); + final requestId = _nextRequest++; + final response = _request({ + 'type': 'check', + 'requestId': requestId, + 'context': context.toMessage(), + 'runs': [ + for (var index = 0; index < runs.length; index++) + { + 'index': index, + 'text': runs[index].text, + 'tokenizationContext': runs[index].tokenizationContext, + 'tokenizationContextStart': runs[index].tokenizationContextStart, + }, + ], + }); + final message = await response; + final occurrences = []; + for (final value in (message['occurrences'] as List? ?? const [])) { + if (value is! Map) continue; + final data = value.cast(); + final runIndex = data['runIndex'] as int; + if (runIndex < 0 || runIndex >= runs.length) continue; + final run = runs[runIndex]; + final start = data['start'] as int; + final end = data['end'] as int; + if (start < 0 || end < start || end > run.text.length) continue; + final outcome = switch (data['outcome']) { + 'accepted' => SpellingCheckOutcome.accepted, + 'rejected' => SpellingCheckOutcome.rejected, + _ => SpellingCheckOutcome.unchecked, + }; + final word = run.text.substring(start, end); + occurrences.add( + SpellingOccurrence( + id: + '${run.snapshot.bufferId}:${run.snapshot.contentRevision}:' + '${run.snapshot.documentKind.name}:' + '${run.snapshot.contextGeneration}:${run.languageId}:' + '${run.id}:$start:$end', + run: run, + logicalStart: start, + logicalEnd: end, + word: word, + outcome: outcome, + error: data['error']?.toString(), + ), + ); + } + return SpellingWorkerResult( + requestId: requestId, + occurrences: List.unmodifiable(occurrences), + cancelled: message['cancelled'] == true, + complete: message['complete'] == true, + error: message['error']?.toString(), + ); + } + + Future project(SpellingProjectionJob job) async { + _requireOpen(); + final message = await _request({ + 'type': 'project', + 'requestId': _nextRequest++, + 'job': job.toMessage(), + }); + final projection = message['projection']; + if (projection is! SpellingProjectionResult) { + throw StateError('Spelling worker returned an invalid projection.'); + } + return projection; + } + + Future> suggestions({ + required SpellingEngineContext context, + required String word, + }) async { + _requireOpen(); + final message = await _request({ + 'type': 'suggest', + 'requestId': _nextRequest++, + 'context': context.toMessage(), + 'word': word, + }); + final values = message['suggestions']; + if (values is! List) return const []; + return List.unmodifiable(values.map((value) => value.toString())); + } + + Future validateDictionary({ + required String affPath, + required String dicPath, + String? knownValidProbe, + }) async { + _requireOpen(); + final message = await _request({ + 'type': 'validate', + 'requestId': _nextRequest++, + 'affPath': affPath, + 'dicPath': dicPath, + if (knownValidProbe != null) 'knownValidProbe': knownValidProbe, + }); + return message['encoding']?.toString() ?? ''; + } + + /// Releases the active native handle before an installed pair is removed. + Future releaseDictionary() async { + _requireOpen(); + await _request({'type': 'releaseDictionary'}); + } + + void cancelChecks() { + if (!_closed) _sendPort.send({'type': 'cancel'}); + } + + Future close() async { + if (_closed) return; + _closed = true; + final response = _request({'type': 'close'}, allowClosed: true); + try { + await response.timeout(const Duration(seconds: 2)); + } finally { + for (final completer in _pending.values) { + if (!completer.isCompleted) { + completer.completeError(StateError('Spelling worker closed.')); + } + } + _pending.clear(); + await _subscription.cancel(); + _receivePort.close(); + _isolate.kill(priority: Isolate.immediate); + } + } + + Future> _request( + Map message, { + bool allowClosed = false, + }) { + if (!allowClosed) _requireOpen(); + final requestId = message['requestId'] as int? ?? _nextRequest++; + message['requestId'] = requestId; + final completer = Completer>(); + _pending[requestId] = completer; + _sendPort.send(message); + return completer.future; + } + + void _handleMessage(Object? value) { + if (value is! Map) return; + final message = value.cast(); + final requestId = message['requestId']; + if (requestId is! int) return; + final completer = _pending.remove(requestId); + if (completer == null || completer.isCompleted) return; + if (message['fatal'] == true) { + completer.completeError( + StateError(message['error']?.toString() ?? 'Spelling worker failed.'), + ); + } else { + completer.complete(message); + } + } + + void _requireOpen() { + if (_closed) throw StateError('Spelling worker is closed.'); + } +} + +void _spellingWorkerMain(SendPort mainPort) { + final commands = ReceivePort(); + mainPort.send(commands.sendPort); + final runtime = _WorkerRuntime(mainPort); + commands.listen(runtime.receive); +} + +final class _WorkerRuntime { + _WorkerRuntime(this.mainPort); + + final SendPort mainPort; + NativeSpellDictionary? _dictionary; + String? _contextIdentity; + final LinkedHashMap _wordCache = LinkedHashMap(); + Map? _newestCheck; + final List> _sideRequestQueue = []; + final LinkedHashMap _projectionCache = + LinkedHashMap(); + bool _busy = false; + int _cancelGeneration = 0; + + void receive(Object? value) { + if (value is! Map) return; + final message = value.cast(); + switch (message['type']) { + case 'check': + _cancelGeneration++; + final replaced = _newestCheck; + if (replaced != null) { + mainPort.send({ + 'requestId': replaced['requestId'], + 'occurrences': const [], + 'cancelled': true, + 'complete': false, + }); + } + _newestCheck = message; + if (!_busy) unawaited(_drain()); + return; + case 'suggest': + while (_sideRequestQueue + .where((item) => item['type'] == 'suggest') + .length >= + _maximumPendingSuggestions) { + final index = _sideRequestQueue.indexWhere( + (item) => item['type'] == 'suggest', + ); + if (index < 0) break; + final obsolete = _sideRequestQueue.removeAt(index); + mainPort.send({ + 'requestId': obsolete['requestId'], + 'fatal': true, + 'error': 'The pending spelling suggestion became obsolete.', + }); + } + _sideRequestQueue.add(message); + if (!_busy) unawaited(_drain()); + return; + case 'validate': + case 'project': + case 'releaseDictionary': + _sideRequestQueue.add(message); + if (!_busy) unawaited(_drain()); + return; + case 'cancel': + _cancelGeneration++; + final pending = _newestCheck; + _newestCheck = null; + if (pending != null) { + mainPort.send({ + 'requestId': pending['requestId'], + 'occurrences': const [], + 'cancelled': true, + 'complete': false, + }); + } + return; + case 'close': + _cancelGeneration++; + _newestCheck = null; + _disposeDictionary(); + mainPort.send({'requestId': message['requestId'], 'closed': true}); + Isolate.exit(); + } + } + + Future _drain() async { + _busy = true; + try { + while (_newestCheck != null || _sideRequestQueue.isNotEmpty) { + if (_newestCheck case final request?) { + _newestCheck = null; + final generation = _cancelGeneration; + await _check(request, generation); + } else { + final request = _sideRequestQueue.removeAt(0); + if (request['type'] == 'validate') { + await _validateDictionary(request); + } else if (request['type'] == 'project') { + await _project(request); + } else if (request['type'] == 'releaseDictionary') { + _disposeDictionary(); + mainPort.send({ + 'requestId': request['requestId'], + 'released': true, + }); + } else { + await _suggest(request); + } + } + } + } finally { + _busy = false; + if ((_newestCheck != null || _sideRequestQueue.isNotEmpty) && !_busy) { + unawaited(_drain()); + } + } + } + + Future _check(Map request, int generation) async { + final requestId = request['requestId'] as int; + final occurrences = >[]; + var complete = true; + String? firstError; + try { + final context = (request['context'] as Map).cast(); + final dictionary = _ensureDictionary(context); + final language = context['languageId'].toString(); + final runs = request['runs'] as List; + var wordsSinceYield = 0; + for (var runCursor = 0; runCursor < runs.length; runCursor++) { + if (generation != _cancelGeneration) { + mainPort.send({ + 'requestId': requestId, + 'occurrences': occurrences, + 'cancelled': true, + 'complete': false, + }); + return; + } + final run = (runs[runCursor] as Map).cast(); + final runIndex = run['index'] as int; + final text = run['text'].toString(); + final tokenizationContext = run['tokenizationContext'].toString(); + final tokenizationContextStart = run['tokenizationContextStart'] as int; + final quotationPunctuation = _quotationPunctuationOffsets( + tokenizationContext, + ); + try { + for (final chunk in _boundedProseChunks( + text, + dictionary: dictionary, + language: language, + )) { + if (chunk.error case final error?) { + complete = false; + firstError ??= error; + occurrences.add({ + 'runIndex': runIndex, + 'start': chunk.utf16Start, + 'end': chunk.utf16Start + chunk.text.length, + 'outcome': 'unchecked', + 'error': error, + }); + continue; + } + final utf16Boundaries = _codePointToUtf16Boundaries(chunk.text); + late final List tokens; + try { + tokens = dictionary.tokenize(chunk.text, language: language); + } on Object catch (error) { + complete = false; + firstError ??= error.toString(); + occurrences.add({ + 'runIndex': runIndex, + 'start': chunk.utf16Start, + 'end': chunk.utf16Start + chunk.text.length, + 'outcome': 'unchecked', + 'error': error.toString(), + }); + continue; + } + for (final token in tokens) { + if (generation != _cancelGeneration) { + mainPort.send({ + 'requestId': requestId, + 'occurrences': occurrences, + 'cancelled': true, + 'complete': false, + }); + return; + } + if (token.characterStart >= utf16Boundaries.length || + token.characterEnd >= utf16Boundaries.length) { + complete = false; + const error = 'Native token boundary is invalid.'; + firstError ??= error; + occurrences.add({ + 'runIndex': runIndex, + 'start': chunk.utf16Start, + 'end': chunk.utf16Start + chunk.text.length, + 'outcome': 'unchecked', + 'error': error, + }); + continue; + } + var start = + chunk.utf16Start + utf16Boundaries[token.characterStart]; + var end = chunk.utf16Start + utf16Boundaries[token.characterEnd]; + while (start < end && + quotationPunctuation.contains( + tokenizationContextStart + start, + )) { + start += _utf16WidthAt(text, start); + } + while (end > start) { + final edge = _previousCodePointStart(text, end); + if (!quotationPunctuation.contains( + tokenizationContextStart + edge, + )) { + break; + } + end = edge; + } + if (end <= start) continue; + final word = text.substring(start, end); + final cacheKey = + '${context['identity'] ?? _contextIdentity}\u0000${unicode.nfc(word)}'; + var outcome = _wordCache.remove(cacheKey); + if (outcome == null) { + try { + outcome = dictionary.check(word) == NativeSpellResult.accepted + ? 'accepted' + : 'rejected'; + } on Object catch (error) { + complete = false; + firstError ??= error.toString(); + occurrences.add({ + 'runIndex': runIndex, + 'start': start, + 'end': end, + 'outcome': 'unchecked', + 'error': error.toString(), + }); + continue; + } + } + _wordCache[cacheKey] = outcome; + while (_wordCache.length > _maximumCachedWords) { + _wordCache.remove(_wordCache.keys.first); + } + if (outcome == 'rejected') { + occurrences.add({ + 'runIndex': runIndex, + 'start': start, + 'end': end, + 'outcome': outcome, + }); + } + wordsSinceYield++; + if (wordsSinceYield >= _wordBatchSize) { + wordsSinceYield = 0; + await Future.delayed(Duration.zero); + await _serviceSuggestionsDuringCheck(); + } + } + } + } on Object catch (error) { + complete = false; + firstError ??= error.toString(); + occurrences.add({ + 'runIndex': runIndex, + 'start': 0, + 'end': 0, + 'outcome': 'unchecked', + 'error': error.toString(), + }); + } + if (runCursor % 8 == 7) { + await Future.delayed(Duration.zero); + } + } + mainPort.send({ + 'requestId': requestId, + 'occurrences': occurrences, + 'cancelled': false, + 'complete': complete, + if (firstError != null) 'error': firstError, + }); + } on Object catch (error) { + mainPort.send({ + 'requestId': requestId, + 'occurrences': occurrences, + 'cancelled': false, + 'complete': false, + 'error': error.toString(), + }); + } + } + + Future _suggest(Map request) async { + try { + final context = (request['context'] as Map).cast(); + final dictionary = _ensureDictionary(context); + final suggestions = dictionary.suggest(request['word'].toString()); + mainPort.send({ + 'requestId': request['requestId'], + 'suggestions': suggestions, + }); + } on Object catch (error) { + mainPort.send({ + 'requestId': request['requestId'], + 'fatal': true, + 'error': error.toString(), + }); + } + } + + Future _serviceSuggestionsDuringCheck() async { + while (true) { + final index = _sideRequestQueue.indexWhere( + (request) => request['type'] == 'suggest', + ); + if (index < 0) return; + final request = _sideRequestQueue.removeAt(index); + final context = (request['context'] as Map).cast(); + if (context['identity'] != _contextIdentity) { + mainPort.send({ + 'requestId': request['requestId'], + 'fatal': true, + 'error': 'The spelling suggestion context became obsolete.', + }); + continue; + } + await _suggest(request); + } + } + + Future _project(Map request) async { + try { + final job = (request['job'] as Map).cast(); + final snapshot = job['snapshot']; + if (snapshot is! SpellingSnapshotIdentity) { + throw const FormatException('Projection snapshot is unavailable.'); + } + final documentKind = DocumentKind.values.byName( + job['documentKind'].toString(), + ); + final markdownMode = MarkdownMode.values.byName( + job['markdownMode'].toString(), + ); + final filePath = job['filePath'].toString(); + final source = job['source'].toString(); + final languageId = job['languageId'].toString(); + final richDocument = job['richDocument']; + final cacheKey = + '${snapshot.bufferId}\u0000$filePath\u0000${documentKind.name}\u0000' + '${richDocument == null ? 'source' : 'rich'}'; + final previous = _projectionCache.remove(cacheKey); + SpellingProjectionResult projection; + if (previous != null && + previous.source == source && + previous.filePath == filePath && + previous.markdownMode == markdownMode && + previous.languageId == languageId && + previous.richDocumentGeneration == + (job['richDocumentGeneration'] as int)) { + projection = _rebindProjection( + previous.projection, + snapshot, + filePath: filePath, + ); + } else if (richDocument == null && + previous != null && + (documentKind == DocumentKind.markdown || + documentKind == DocumentKind.writersideMarkdownTopic) && + previous.markdownMode == markdownMode && + previous.languageId == languageId) { + projection = + _incrementalPlainMarkdownProjection( + previous: previous, + source: source, + filePath: filePath, + mode: markdownMode, + languageId: languageId, + snapshot: snapshot, + ) ?? + const MarkdownSpellingProjector().project( + filePath: filePath, + source: source, + mode: markdownMode, + languageId: languageId, + snapshot: snapshot, + ); + } else { + projection = richDocument is BusyDocument + ? const WysiwygSpellingProjector().project( + document: richDocument, + languageId: languageId, + snapshot: snapshot, + documentGeneration: job['richDocumentGeneration'] as int, + ) + : switch (documentKind) { + DocumentKind.markdown || DocumentKind.writersideMarkdownTopic => + const MarkdownSpellingProjector().project( + filePath: filePath, + source: source, + mode: markdownMode, + languageId: languageId, + snapshot: snapshot, + ), + DocumentKind.writersideXmlTopic => + const WritersideXmlSpellingProjector().project( + filePath: filePath, + source: source, + languageId: languageId, + snapshot: snapshot, + ), + _ => const SpellingProjectionResult(runs: [], complete: true), + }; + } + _projectionCache[cacheKey] = _ProjectionCacheEntry( + source: source, + filePath: filePath, + markdownMode: markdownMode, + languageId: languageId, + richDocumentGeneration: job['richDocumentGeneration'] as int, + projection: projection, + ); + while (_projectionCache.length > 8) { + _projectionCache.remove(_projectionCache.keys.first); + } + mainPort.send({ + 'requestId': request['requestId'], + 'projection': projection, + }); + } on Object catch (error) { + mainPort.send({ + 'requestId': request['requestId'], + 'fatal': true, + 'error': error.toString(), + }); + } + } + + Future _validateDictionary(Map request) async { + _disposeDictionary(); + try { + final dictionary = NativeSpellDictionary.open( + affPath: request['affPath'].toString(), + dicPath: request['dicPath'].toString(), + ); + try { + final encoding = dictionary.encoding.trim(); + if (encoding.isEmpty) { + throw const FormatException( + 'Dictionary declares no usable encoding.', + ); + } + final knownValidProbe = request['knownValidProbe']?.toString(); + if (knownValidProbe != null && + knownValidProbe.isNotEmpty && + dictionary.check(knownValidProbe) != NativeSpellResult.accepted) { + throw FormatException( + 'Dictionary rejected its catalog validation probe.', + ); + } + mainPort.send({ + 'requestId': request['requestId'], + 'encoding': encoding, + }); + } finally { + dictionary.close(); + } + } on Object catch (error) { + mainPort.send({ + 'requestId': request['requestId'], + 'fatal': true, + 'error': error.toString(), + }); + } + } + + NativeSpellDictionary _ensureDictionary(Map context) { + final identity = context['identity'].toString(); + if (_dictionary != null && _contextIdentity == identity) { + return _dictionary!; + } + _disposeDictionary(); + final dictionary = NativeSpellDictionary.open( + affPath: context['affPath'].toString(), + dicPath: context['dicPath'].toString(), + ); + try { + for (final word in (context['customWords'] as List? ?? const [])) { + dictionary.add(word.toString()); + } + } on Object { + dictionary.close(); + rethrow; + } + _dictionary = dictionary; + _contextIdentity = identity; + _wordCache.clear(); + return dictionary; + } + + void _disposeDictionary() { + _dictionary?.close(); + _dictionary = null; + _contextIdentity = null; + _wordCache.clear(); + } +} + +final class _ProjectionCacheEntry { + const _ProjectionCacheEntry({ + required this.source, + required this.filePath, + required this.markdownMode, + required this.languageId, + required this.richDocumentGeneration, + required this.projection, + }); + + final String source; + final String filePath; + final MarkdownMode markdownMode; + final String languageId; + final int richDocumentGeneration; + final SpellingProjectionResult projection; +} + +SpellingProjectionResult _rebindProjection( + SpellingProjectionResult projection, + SpellingSnapshotIdentity snapshot, { + required String filePath, +}) => SpellingProjectionResult( + runs: List.unmodifiable([ + for (final (index, run) in projection.runs.indexed) + _copyProjectedRun( + run, + id: 'cached:$index', + snapshot: snapshot, + sourceDelta: 0, + filePath: filePath, + ), + ]), + complete: projection.complete, + message: projection.message, +); + +SpellingProjectionResult? _incrementalPlainMarkdownProjection({ + required _ProjectionCacheEntry previous, + required String source, + required String filePath, + required MarkdownMode mode, + required String languageId, + required SpellingSnapshotIdentity snapshot, +}) { + final oldSource = previous.source; + var prefix = 0; + final shared = oldSource.length < source.length + ? oldSource.length + : source.length; + while (prefix < shared && + oldSource.codeUnitAt(prefix) == source.codeUnitAt(prefix)) { + prefix++; + } + var oldSuffix = oldSource.length; + var newSuffix = source.length; + while (oldSuffix > prefix && + newSuffix > prefix && + oldSource.codeUnitAt(oldSuffix - 1) == source.codeUnitAt(newSuffix - 1)) { + oldSuffix--; + newSuffix--; + } + final oldRegion = _singleLineParagraphRegion(oldSource, prefix, oldSuffix); + final newRegion = _singleLineParagraphRegion(source, prefix, newSuffix); + if (oldRegion == null || newRegion == null) return null; + final oldFragment = oldSource.substring(oldRegion.start, oldRegion.end); + final newFragment = source.substring(newRegion.start, newRegion.end); + if (!_plainMarkdownParagraph(oldFragment) || + !_plainMarkdownParagraph(newFragment)) { + return null; + } + final owners = <({SpellingProseRun run, int start, int end})>[]; + for (final run in previous.projection.runs) { + final bounds = _projectedRunSourceBounds(run); + if (bounds == null) return null; + final ownsChange = oldSuffix == prefix + ? bounds.start <= prefix && prefix <= bounds.end + : bounds.start <= prefix && bounds.end >= oldSuffix; + if (ownsChange) { + owners.add((run: run, start: bounds.start, end: bounds.end)); + } + } + // Parsing an isolated line is safe only when the prior full projection says + // the edit belongs to one eligible prose leaf. An excluded or ambiguous + // region (fences, comments, front matter, HTML, or nested containers) must + // be projected with its complete parser context. + if (owners.length != 1 || + owners.single.start < oldRegion.start || + owners.single.end > oldRegion.end) { + return null; + } + final delta = newRegion.end - oldRegion.end; + final before = []; + final after = []; + for (final run in previous.projection.runs) { + final bounds = _projectedRunSourceBounds(run); + if (bounds == null) return null; + if (bounds.end <= oldRegion.start) { + before.add(run); + } else if (bounds.start >= oldRegion.end) { + after.add(run); + } else if (bounds.start < oldRegion.start || bounds.end > oldRegion.end) { + return null; + } + } + final changed = const MarkdownSpellingProjector().project( + filePath: filePath, + source: newFragment, + mode: mode, + languageId: languageId, + snapshot: snapshot, + ); + if (!changed.complete) return null; + final combined = [ + for (final run in before) + _copyProjectedRun( + run, + id: '', + snapshot: snapshot, + sourceDelta: 0, + filePath: filePath, + ), + for (final run in changed.runs) + _copyProjectedRun( + run, + id: '', + snapshot: snapshot, + sourceDelta: newRegion.start, + filePath: filePath, + ), + for (final run in after) + _copyProjectedRun( + run, + id: '', + snapshot: snapshot, + sourceDelta: delta, + filePath: filePath, + ), + ]; + return SpellingProjectionResult( + runs: List.unmodifiable([ + for (final (index, run) in combined.indexed) + SpellingProseRun( + id: 'incremental:$index', + text: run.text, + languageId: run.languageId, + atoms: run.atoms, + target: run.target, + snapshot: run.snapshot, + formattingWrappers: run.formattingWrappers, + complete: run.complete, + tokenizationContext: run.tokenizationContext, + tokenizationContextStart: run.tokenizationContextStart, + ), + ]), + complete: previous.projection.complete, + message: previous.projection.message, + ); +} + +({int start, int end})? _singleLineParagraphRegion( + String source, + int changedStart, + int changedEnd, +) { + var start = 0; + var end = source.length; + for (final separator in RegExp(r'\r?\n[ \t]*\r?\n').allMatches(source)) { + if (separator.end <= changedStart) { + start = separator.end; + } else if (separator.start >= changedEnd) { + end = separator.start; + break; + } + } + if (source.substring(start, end).contains(RegExp(r'[\r\n]'))) return null; + return (start: start, end: end); +} + +bool _plainMarkdownParagraph(String value) { + if (RegExp(r'[`~$<>{}\[\]\\*_#|%&]').hasMatch(value)) return false; + if (RegExp(r'^(?: {4}|\t)').hasMatch(value)) return false; + if (RegExp(r'^\s*(?:>|[-+*]\s|\d+[.)]\s|---(?:\s|$))').hasMatch(value)) { + return false; + } + return true; +} + +({int start, int end})? _projectedRunSourceBounds(SpellingProseRun run) { + final atoms = run.atoms.where((atom) => atom.sourceStart >= 0).toList(); + if (atoms.length != run.atoms.length || atoms.isEmpty) return null; + var start = atoms.first.sourceStart; + var end = atoms.first.sourceEnd; + for (final atom in atoms.skip(1)) { + if (atom.sourceStart < start) start = atom.sourceStart; + if (atom.sourceEnd > end) end = atom.sourceEnd; + } + return (start: start, end: end); +} + +SpellingProseRun _copyProjectedRun( + SpellingProseRun run, { + required String id, + required SpellingSnapshotIdentity snapshot, + required int sourceDelta, + String? filePath, +}) => SpellingProseRun( + id: id.isEmpty ? run.id : id, + text: run.text, + languageId: run.languageId, + atoms: List.unmodifiable([ + for (final atom in run.atoms) + SpellingSourceAtom( + logicalText: atom.logicalText, + logicalStart: atom.logicalStart, + logicalEnd: atom.logicalEnd, + sourceStart: atom.sourceStart < 0 + ? atom.sourceStart + : atom.sourceStart + sourceDelta, + sourceEnd: atom.sourceEnd < 0 + ? atom.sourceEnd + : atom.sourceEnd + sourceDelta, + transformation: atom.transformation, + context: atom.context, + fieldStart: atom.fieldStart, + fieldEnd: atom.fieldEnd, + richLeafPath: atom.richLeafPath, + ), + ]), + target: switch (run.target) { + SpellingSourceTarget() when filePath != null => SpellingSourceTarget( + filePath: filePath, + ), + final target => target, + }, + snapshot: snapshot, + formattingWrappers: List.unmodifiable([ + for (final wrapper in run.formattingWrappers) + SpellingFormattingWrapper( + logicalStart: wrapper.logicalStart, + logicalEnd: wrapper.logicalEnd, + openingStart: wrapper.openingStart < 0 + ? wrapper.openingStart + : wrapper.openingStart + sourceDelta, + openingEnd: wrapper.openingEnd < 0 + ? wrapper.openingEnd + : wrapper.openingEnd + sourceDelta, + closingStart: wrapper.closingStart < 0 + ? wrapper.closingStart + : wrapper.closingStart + sourceDelta, + closingEnd: wrapper.closingEnd < 0 + ? wrapper.closingEnd + : wrapper.closingEnd + sourceDelta, + removableWhenLogicallyEmpty: wrapper.removableWhenLogicallyEmpty, + fieldOpeningStart: wrapper.fieldOpeningStart, + fieldOpeningEnd: wrapper.fieldOpeningEnd, + fieldClosingStart: wrapper.fieldClosingStart, + fieldClosingEnd: wrapper.fieldClosingEnd, + structuralKind: wrapper.structuralKind, + ), + ]), + complete: run.complete, + tokenizationContext: run.tokenizationContext, + tokenizationContextStart: run.tokenizationContextStart, +); + +const _maximumProseChunkBytes = 48 * 1024; +const _maximumCachedWords = 8192; +const _wordBatchSize = 256; +const _maximumPendingSuggestions = 32; + +Set _quotationPunctuationOffsets(String text) { + final result = {}; + int? straightOpening; + int? curlyOpening; + var offset = 0; + while (offset < text.length) { + final rune = _codePointAtUtf16(text, offset); + final width = rune > 0xffff ? 2 : 1; + if (rune == 0x0a || rune == 0x0d) { + straightOpening = null; + curlyOpening = null; + offset += width; + continue; + } + if (rune != 0x27 && rune != 0x2018 && rune != 0x2019) { + offset += width; + continue; + } + final previousWord = _wordCharacterBefore(text, offset); + final nextWord = _wordCharacterAt(text, offset + width); + if (rune != 0x2018 && previousWord && nextWord) { + offset += width; + continue; + } + if (rune == 0x2018) { + result.add(offset); + curlyOpening = offset; + } else if (rune == 0x2019) { + if (curlyOpening != null) { + result.add(curlyOpening); + result.add(offset); + curlyOpening = null; + } + } else { + final opens = !previousWord && nextWord; + final closes = previousWord && !nextWord; + if (straightOpening != null && closes) { + result.add(straightOpening); + result.add(offset); + straightOpening = null; + } else { + straightOpening = opens ? offset : null; + } + } + offset += width; + } + return result; +} + +bool _wordCharacterBefore(String text, int offset) => + offset > 0 && + _isWordCharacter( + _codePointAtUtf16(text, _previousCodePointStart(text, offset)), + ); + +bool _wordCharacterAt(String text, int offset) => + offset < text.length && _isWordCharacter(_codePointAtUtf16(text, offset)); + +bool _isWordCharacter(int rune) { + if ((rune >= 0x41 && rune <= 0x5a) || + (rune >= 0x61 && rune <= 0x7a) || + _isCombiningMark(rune)) { + return true; + } + final character = String.fromCharCode(rune); + return character.toLowerCase() != character.toUpperCase(); +} + +bool _isCombiningMark(int rune) => + (rune >= 0x0300 && rune <= 0x036f) || + (rune >= 0x1ab0 && rune <= 0x1aff) || + (rune >= 0x1dc0 && rune <= 0x1dff) || + (rune >= 0x20d0 && rune <= 0x20ff) || + (rune >= 0xfe20 && rune <= 0xfe2f); + +int _utf16WidthAt(String text, int offset) => + _codePointAtUtf16(text, offset) > 0xffff ? 2 : 1; + +int _previousCodePointStart(String text, int offset) { + var start = offset - 1; + if (start > 0) { + final unit = text.codeUnitAt(start); + final previous = text.codeUnitAt(start - 1); + if (unit >= 0xdc00 && + unit <= 0xdfff && + previous >= 0xd800 && + previous <= 0xdbff) { + start--; + } + } + return start; +} + +final class _ProseChunk { + const _ProseChunk({required this.text, required this.utf16Start, this.error}); + + final String text; + final int utf16Start; + final String? error; +} + +Iterable<_ProseChunk> _boundedProseChunks( + String text, { + required NativeSpellDictionary dictionary, + required String language, +}) sync* { + var start = 0; + while (start < text.length) { + var cursor = start; + var bytes = 0; + int? lastWhitespaceBoundary; + while (cursor < text.length) { + final rune = _codePointAtUtf16(text, cursor); + final width = rune > 0xffff ? 2 : 1; + final encodedWidth = rune <= 0x7f + ? 1 + : rune <= 0x7ff + ? 2 + : rune <= 0xffff + ? 3 + : 4; + if (bytes + encodedWidth > _maximumProseChunkBytes) break; + bytes += encodedWidth; + cursor += width; + if (_unicodeWhitespace.hasMatch(String.fromCharCode(rune))) { + lastWhitespaceBoundary = cursor; + } + } + if (cursor >= text.length) { + yield _ProseChunk(text: text.substring(start), utf16Start: start); + break; + } + var end = lastWhitespaceBoundary != null && lastWhitespaceBoundary > start + ? lastWhitespaceBoundary + : null; + if (end == null) { + // Ask the same Pango-backed tokenizer used for checking where the last + // complete candidate begins. Ending immediately before that candidate + // is safe even for scripts that do not separate words with spaces. An + // artificial end-of-probe word boundary is deliberately not trusted. + final probe = text.substring(start, cursor); + final boundaries = _codePointToUtf16Boundaries(probe); + final tokens = dictionary.tokenize(probe, language: language); + for (final token in tokens.reversed) { + if (token.characterStart > 0 && + token.characterStart < boundaries.length) { + end = start + boundaries[token.characterStart]; + break; + } + } + if (end == null) { + for (final token in tokens.reversed) { + if (token.characterEnd > 0 && + token.characterEnd < boundaries.length - 1) { + end = start + boundaries[token.characterEnd]; + break; + } + } + } + // Pango found no candidate at all, so the probe cannot cut a spelling + // token even though it contains no whitespace (for example a long run + // of non-word punctuation). + if (end == null && tokens.isEmpty) end = cursor; + } + end ??= start; + if (end <= start) { + final tokenEnd = _oversizedTokenEnd( + text, + start: start, + firstProbeEnd: cursor, + dictionary: dictionary, + language: language, + ); + yield _ProseChunk( + text: text.substring(start, tokenEnd), + utf16Start: start, + error: 'A spelling token exceeds the bounded native input size.', + ); + start = tokenEnd; + continue; + } + yield _ProseChunk(text: text.substring(start, end), utf16Start: start); + start = end; + } +} + +int _oversizedTokenEnd( + String text, { + required int start, + required int firstProbeEnd, + required NativeSpellDictionary dictionary, + required String language, +}) { + var probeStart = firstProbeEnd; + while (probeStart < text.length) { + var probeEnd = probeStart; + var bytes = 0; + while (probeEnd < text.length) { + final rune = _codePointAtUtf16(text, probeEnd); + final width = rune > 0xffff ? 2 : 1; + final encodedWidth = rune <= 0x7f + ? 1 + : rune <= 0x7ff + ? 2 + : rune <= 0xffff + ? 3 + : 4; + if (bytes + encodedWidth > _maximumProseChunkBytes) break; + bytes += encodedWidth; + probeEnd += width; + } + if (probeEnd <= probeStart) break; + final probe = text.substring(probeStart, probeEnd); + final boundaries = _codePointToUtf16Boundaries(probe); + final tokens = dictionary.tokenize(probe, language: language); + if (tokens.isEmpty || tokens.first.characterStart > 0) { + return probeStart; + } + final first = tokens.first; + if (first.characterEnd < boundaries.length - 1) { + return probeStart + boundaries[first.characterEnd]; + } + if (probeEnd == text.length) return text.length; + probeStart = probeEnd; + } + // Defensive progress for an invalid tokenizer response. This remains + // bounded to the first native-safe probe rather than consuming a complete + // whitespace-delimited segment and hiding later punctuation-separated words. + return firstProbeEnd > start ? firstProbeEnd : text.length; +} + +final RegExp _unicodeWhitespace = RegExp(r'^\s$', unicode: true); + +int _codePointAtUtf16(String text, int offset) { + final first = text.codeUnitAt(offset); + if (first >= 0xd800 && first <= 0xdbff && offset + 1 < text.length) { + final second = text.codeUnitAt(offset + 1); + if (second >= 0xdc00 && second <= 0xdfff) { + return 0x10000 + ((first - 0xd800) << 10) + (second - 0xdc00); + } + } + return first; +} + +List _codePointToUtf16Boundaries(String text) { + final boundaries = [0]; + var offset = 0; + for (final rune in text.runes) { + offset += rune > 0xffff ? 2 : 1; + boundaries.add(offset); + } + return boundaries; +} diff --git a/lib/src/spellcheck/writerside_spelling_projection.dart b/lib/src/spellcheck/writerside_spelling_projection.dart new file mode 100644 index 00000000..557a79d3 --- /dev/null +++ b/lib/src/spellcheck/writerside_spelling_projection.dart @@ -0,0 +1,431 @@ +import 'package:html/parser.dart' as html; + +import '../writerside/writerside_document.dart'; +import '../writerside/writerside_document_parser.dart'; +import '../writerside/writerside_schema.dart'; +import 'spelling_projection.dart'; + +final class WritersideXmlSpellingProjector { + const WritersideXmlSpellingProjector({ + this.parser = const WritersideDocumentParser(), + }); + + final WritersideDocumentParser parser; + + SpellingProjectionResult project({ + required String filePath, + required String source, + required String languageId, + required SpellingSnapshotIdentity snapshot, + }) { + final document = parser.parseXml(filePath: filePath, source: source); + if (!document.isWellFormed) { + return const SpellingProjectionResult( + runs: [], + complete: false, + message: null, + ); + } + final builder = _XmlProjectionBuilder( + filePath: filePath, + source: source, + languageId: languageId, + snapshot: snapshot, + ); + for (final node in document.nodes) { + builder.visit(node, eligible: false); + } + builder.flush(); + return SpellingProjectionResult( + runs: List.unmodifiable(builder.runs), + complete: builder.complete, + message: builder.complete + ? null + : 'Some XML prose could not be mapped exactly.', + ); + } +} + +final class _XmlProjectionBuilder { + _XmlProjectionBuilder({ + required this.filePath, + required this.source, + required this.languageId, + required this.snapshot, + }); + + final String filePath; + final String source; + final String languageId; + final SpellingSnapshotIdentity snapshot; + final List runs = []; + var complete = true; + var _sequence = 0; + StringBuffer _text = StringBuffer(); + StringBuffer _tokenizationContext = StringBuffer(); + List _atoms = []; + final List<_PendingXmlRun> _pendingRuns = []; + int? _tokenizationContextStart; + + void visit(WritersideDocumentNode node, {required bool eligible}) { + if (node is WritersideTextNode) { + if (eligible) _appendTextNode(node); + return; + } + if (node is WritersideRawNode) return; + if (node is WritersideMarkdownBlockNode) { + // XML topics are projected from physical XML nodes only. Reusable + // Markdown snippets are parsed in their own physical document. + return; + } + final element = node as WritersideElementNode; + final kind = element.semanticKind; + final elementEligible = _eligibleKinds.contains(kind); + final inline = _inlineKinds.contains(kind); + if (!inline) flush(); + _appendAttributes(element); + if (kind == WritersideSemanticKind.lineBreak) { + _emit( + ' ', + element.span.startOffset, + element.span.endOffset, + SpellingTransformationKind.lineBreak, + SpellingSourceContext.xmlText, + tokenizationLogical: '\n', + ); + return; + } + if (elementEligible) { + for (final child in element.children) { + visit(child, eligible: true); + } + } else { + // Excluded technical elements form hard barriers; their descendants do + // not get joined to authored prose around them. + if (inline) { + _barrier(); + } else { + flush(); + } + } + if (!inline) flush(); + } + + void _appendTextNode(WritersideTextNode node) { + final raw = node.rawSource; + if (raw.startsWith('')) { + final contentStart = node.span.startOffset + ''.length; + final content = source.substring(contentStart, contentEnd); + _appendCdata(content, contentStart); + if (content != node.text) complete = false; + return; + } + _appendEncoded( + raw: raw, + sourceStart: node.span.startOffset, + expected: node.text, + context: SpellingSourceContext.xmlText, + ); + } + + void _appendAttributes(WritersideElementNode element) { + for (final name in _humanReadableAttributes) { + final value = element.attributes[name]; + final span = element.attributeSpans[name]; + if (value == null || span == null || value.trim().isEmpty) continue; + flush(); + final quoteOffset = span.startOffset - 1; + final quote = quoteOffset >= 0 ? source[quoteOffset] : '"'; + _appendEncoded( + raw: source.substring(span.startOffset, span.endOffset), + sourceStart: span.startOffset, + expected: value, + context: quote == "'" + ? SpellingSourceContext.xmlSingleQuotedAttribute + : SpellingSourceContext.xmlDoubleQuotedAttribute, + ); + flush(); + } + } + + void _appendEncoded({ + required String raw, + required int sourceStart, + required String expected, + required SpellingSourceContext context, + }) { + final decoded = html.parseFragment(raw).text ?? ''; + if (decoded != expected) { + complete = false; + return; + } + final units = <_EncodedUnit>[]; + final decodedText = StringBuffer(); + var cursor = 0; + while (cursor < raw.length) { + if (raw.codeUnitAt(cursor) == 0x26) { + final match = _xmlEntity.matchAsPrefix(raw, cursor); + if (match != null) { + final encoded = match.group(0)!; + final entityText = html.parseFragment(encoded).text ?? ''; + if (entityText != encoded && entityText.isNotEmpty) { + final logicalStart = decodedText.length; + decodedText.write(entityText); + units.add( + _EncodedUnit( + logical: entityText, + logicalStart: logicalStart, + logicalEnd: decodedText.length, + sourceStart: sourceStart + cursor, + sourceEnd: sourceStart + match.end, + transformation: SpellingTransformationKind.entity, + ), + ); + cursor = match.end; + continue; + } + } + } + final rune = _codePointAt(raw, cursor); + final width = rune > 0xffff ? 2 : 1; + final logical = raw.substring(cursor, cursor + width); + final logicalStart = decodedText.length; + decodedText.write(logical); + units.add( + _EncodedUnit( + logical: logical, + logicalStart: logicalStart, + logicalEnd: decodedText.length, + sourceStart: sourceStart + cursor, + sourceEnd: sourceStart + cursor + width, + transformation: SpellingTransformationKind.identity, + ), + ); + cursor += width; + } + final variables = [ + for (final match in _writersideVariable.allMatches( + decodedText.toString(), + )) + if (match.group(1) == null) (start: match.start, end: match.end), + ]; + for (final unit in units) { + final variable = variables.any( + (range) => + range.start < unit.logicalEnd && range.end > unit.logicalStart, + ); + if (variable) { + _barrier(); + continue; + } + _emit( + unit.logical, + unit.sourceStart, + unit.sourceEnd, + unit.transformation, + context, + ); + } + } + + void _appendCdata(String content, int sourceStart) { + var cursor = 0; + for (final variable in _writersideVariable.allMatches(content)) { + if (variable.group(1) != null) continue; + if (variable.start > cursor) { + _emit( + content.substring(cursor, variable.start), + sourceStart + cursor, + sourceStart + variable.start, + SpellingTransformationKind.xmlCdata, + SpellingSourceContext.xmlCdata, + ); + } + _barrier(); + cursor = variable.end; + } + if (cursor < content.length) { + _emit( + content.substring(cursor), + sourceStart + cursor, + sourceStart + content.length, + SpellingTransformationKind.xmlCdata, + SpellingSourceContext.xmlCdata, + ); + } + } + + void _emit( + String logical, + int sourceStart, + int sourceEnd, + SpellingTransformationKind transformation, + SpellingSourceContext context, { + String? tokenizationLogical, + }) { + if (logical.isEmpty) return; + _tokenizationContextStart ??= _tokenizationContext.length; + final logicalStart = _text.length; + _text.write(logical); + _tokenizationContext.write(tokenizationLogical ?? logical); + _atoms.add( + SpellingSourceAtom( + logicalText: logical, + logicalStart: logicalStart, + logicalEnd: _text.length, + sourceStart: sourceStart, + sourceEnd: sourceEnd, + transformation: transformation, + context: context, + ), + ); + } + + void _flushRun() { + if (_text.isNotEmpty && _text.toString().trim().isNotEmpty) { + _pendingRuns.add( + _PendingXmlRun( + text: _text.toString(), + atoms: List.unmodifiable(_atoms), + tokenizationContextStart: _tokenizationContextStart!, + ), + ); + } + _text = StringBuffer(); + _atoms = []; + _tokenizationContextStart = null; + } + + void _barrier() { + _flushRun(); + if (_tokenizationContext.isNotEmpty && + !_tokenizationContext.toString().endsWith(' ')) { + _tokenizationContext.write(' '); + } + } + + void flush() { + _flushRun(); + final contextText = _tokenizationContext.toString(); + for (final pending in _pendingRuns) { + final run = SpellingProseRun( + id: 'writerside-xml:${_sequence++}', + text: pending.text, + languageId: languageId, + atoms: pending.atoms, + target: SpellingSourceTarget(filePath: filePath), + snapshot: snapshot, + tokenizationContext: contextText, + tokenizationContextStart: pending.tokenizationContextStart, + ); + if (run.hasValidMapping) { + runs.add(run); + } else { + complete = false; + } + } + _pendingRuns.clear(); + _tokenizationContext = StringBuffer(); + } +} + +final class _PendingXmlRun { + const _PendingXmlRun({ + required this.text, + required this.atoms, + required this.tokenizationContextStart, + }); + + final String text; + final List atoms; + final int tokenizationContextStart; +} + +final class _EncodedUnit { + const _EncodedUnit({ + required this.logical, + required this.logicalStart, + required this.logicalEnd, + required this.sourceStart, + required this.sourceEnd, + required this.transformation, + }); + + final String logical; + final int logicalStart; + final int logicalEnd; + final int sourceStart; + final int sourceEnd; + final SpellingTransformationKind transformation; +} + +const _humanReadableAttributes = { + 'title', + 'alt', + 'summary', + 'tooltip', + 'switcher-label', + 'author', +}; + +const _inlineKinds = { + WritersideSemanticKind.link, + WritersideSemanticKind.strong, + WritersideSemanticKind.emphasis, + WritersideSemanticKind.control, + WritersideSemanticKind.tooltip, + WritersideSemanticKind.lineBreak, +}; + +const _eligibleKinds = { + WritersideSemanticKind.topic, + WritersideSemanticKind.paragraph, + WritersideSemanticKind.chapter, + WritersideSemanticKind.title, + WritersideSemanticKind.list, + WritersideSemanticKind.listItem, + WritersideSemanticKind.table, + WritersideSemanticKind.tableRow, + WritersideSemanticKind.tableCell, + WritersideSemanticKind.link, + WritersideSemanticKind.control, + WritersideSemanticKind.image, + WritersideSemanticKind.procedure, + WritersideSemanticKind.step, + WritersideSemanticKind.note, + WritersideSemanticKind.tip, + WritersideSemanticKind.warning, + WritersideSemanticKind.quote, + WritersideSemanticKind.tabs, + WritersideSemanticKind.tab, + WritersideSemanticKind.definitionList, + WritersideSemanticKind.definition, + WritersideSemanticKind.tooltip, + WritersideSemanticKind.strong, + WritersideSemanticKind.emphasis, + WritersideSemanticKind.snippet, + WritersideSemanticKind.condition, + WritersideSemanticKind.lineBreak, + WritersideSemanticKind.container, + WritersideSemanticKind.startingPage, + WritersideSemanticKind.section, + WritersideSemanticKind.card, + WritersideSemanticKind.seealso, +}; + +final RegExp _xmlEntity = RegExp( + r'&(?:#[0-9]{1,7}|#[xX][0-9A-Fa-f]{1,6}|[A-Za-z][A-Za-z0-9]{1,31});', +); +final RegExp _writersideVariable = RegExp(r'%(\\)?([A-Za-z_][A-Za-z0-9_.-]*)%'); + +int _codePointAt(String value, int offset) { + final first = value.codeUnitAt(offset); + if (first >= 0xd800 && first <= 0xdbff && offset + 1 < value.length) { + final second = value.codeUnitAt(offset + 1); + if (second >= 0xdc00 && second <= 0xdfff) { + return 0x10000 + ((first - 0xd800) << 10) + second - 0xdc00; + } + } + return first; +} diff --git a/lib/src/spellcheck/wysiwyg_spelling_projection.dart b/lib/src/spellcheck/wysiwyg_spelling_projection.dart new file mode 100644 index 00000000..ded1eada --- /dev/null +++ b/lib/src/spellcheck/wysiwyg_spelling_projection.dart @@ -0,0 +1,672 @@ +import '../editor/wysiwyg/wysiwyg_inline_controller.dart'; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_parser.dart'; +import '../markdown/markdown_source_structure.dart'; +import 'markdown_spelling_projection.dart'; +import 'spelling_inline_projection.dart'; +import 'spelling_projection.dart'; + +final class WysiwygSpellingProjector { + const WysiwygSpellingProjector(); + + SpellingProjectionResult project({ + required BusyDocument document, + required String languageId, + required SpellingSnapshotIdentity snapshot, + required int documentGeneration, + }) { + final richRuns = []; + final fieldKeysByTarget = {}; + var sequence = 0; + var complete = true; + + void addOrdinary(BusyBlock block, SpellingEditorTarget target) { + for (final projection in projectSpellingInlineRuns( + inlines: block.inlines, + sourceBase: -1, + context: target is SpellingRichTableCellTarget + ? SpellingSourceContext.markdownTableCell + : SpellingSourceContext.markdownProse, + )) { + final run = SpellingProseRun( + id: 'wysiwyg:${sequence++}:${block.id}', + text: projection.text, + languageId: languageId, + atoms: projection.atoms, + target: target, + snapshot: snapshot, + tokenizationContext: projection.tokenizationContext, + tokenizationContextStart: projection.tokenizationContextStart, + ); + if (run.hasValidMapping) { + richRuns.add(run); + } else { + complete = false; + } + } + } + + void addMathSource(BusyBlock block, SpellingEditorTarget target) { + final fieldText = busyMarkWysiwygEditableText(block); + final projected = const MarkdownSpellingProjector().project( + filePath: document.filePath, + source: fieldText, + mode: document.mode, + languageId: languageId, + snapshot: snapshot, + proseContext: target is SpellingRichTableCellTarget + ? SpellingSourceContext.markdownTableCell + : SpellingSourceContext.markdownProse, + ); + complete = complete && projected.complete; + for (final sourceRun in projected.runs) { + richRuns.add( + SpellingProseRun( + id: 'wysiwyg-math:${sequence++}:${block.id}', + text: sourceRun.text, + languageId: languageId, + atoms: [ + for (final atom in sourceRun.atoms) + SpellingSourceAtom( + logicalText: atom.logicalText, + logicalStart: atom.logicalStart, + logicalEnd: atom.logicalEnd, + sourceStart: -1, + sourceEnd: -1, + fieldStart: atom.sourceStart, + fieldEnd: atom.sourceEnd, + transformation: atom.transformation, + context: atom.context, + ), + ], + target: target, + snapshot: snapshot, + formattingWrappers: [ + for (final wrapper in sourceRun.formattingWrappers) + SpellingFormattingWrapper( + logicalStart: wrapper.logicalStart, + logicalEnd: wrapper.logicalEnd, + openingStart: -1, + openingEnd: -1, + closingStart: -1, + closingEnd: -1, + removableWhenLogicallyEmpty: + wrapper.removableWhenLogicallyEmpty, + fieldOpeningStart: wrapper.openingStart, + fieldOpeningEnd: wrapper.openingEnd, + fieldClosingStart: wrapper.closingStart, + fieldClosingEnd: wrapper.closingEnd, + structuralKind: wrapper.structuralKind, + ), + ], + complete: sourceRun.complete, + tokenizationContext: sourceRun.tokenizationContext, + tokenizationContextStart: sourceRun.tokenizationContextStart, + ), + ); + } + } + + void visit(BusyBlock block, List path) { + if (block.isGenerated || + block.isSourceProtected || + block.isSourceOnly || + !_eligibleBlockKinds.contains(block.kind)) { + return; + } + if (block.kind == BusyBlockKind.table) { + for (final (rowIndex, row) in block.children.indexed) { + for (final (columnIndex, cell) in row.children.indexed) { + final target = SpellingRichTableCellTarget( + tableBlockId: block.id, + cellId: cell.id, + documentGeneration: documentGeneration, + ); + fieldKeysByTarget[_targetIdentity(target)] = + '${path.join('.')}:table:$rowIndex:$columnIndex'; + if (busyMarkWysiwygBlockContainsMath(cell)) { + addMathSource(cell, target); + } else { + addOrdinary(cell, target); + } + } + } + return; + } + if (block.inlines.isNotEmpty) { + final target = SpellingRichBlockTarget( + blockId: block.id, + documentGeneration: documentGeneration, + ); + fieldKeysByTarget[_targetIdentity(target)] = '${path.join('.')}:block'; + if (busyMarkWysiwygBlockContainsMath(block)) { + addMathSource(block, target); + } else { + addOrdinary(block, target); + } + } + for (final (index, child) in block.children.indexed) { + visit(child, [...path, index]); + } + } + + for (final (index, block) in document.blocks.indexed) { + visit(block, [index]); + } + final source = document.source; + if (source == null) { + return SpellingProjectionResult( + runs: List.unmodifiable(richRuns), + complete: complete, + message: complete ? null : 'Some rich-text fields could not be mapped.', + ); + } + + final sourceProjection = const MarkdownSpellingProjector().project( + filePath: document.filePath, + source: source, + mode: document.mode, + languageId: languageId, + snapshot: snapshot, + ); + final currentDocument = const MarkdownParser() + .parse( + filePath: document.filePath, + source: source, + mode: document.mode, + validateLocalReferences: false, + ) + .busyDocument; + var merged = _mergeCurrentSourceMappings( + richRuns: richRuns, + sourceRuns: sourceProjection.runs, + fieldKeysByTarget: fieldKeysByTarget, + sourceRegions: _sourceFieldRegions(source, currentDocument.blocks), + ); + if (!merged.allRichRunsMapped) { + // The parser deliberately omits some block spans when its lossless + // scanner and AST have different container shapes (e.g. nested lists). + // Live editor-only empty paragraphs can also shift tree paths. In that + // case require an exact, complete ordered correspondence of prose runs; + // never search ahead for matching text or publish a partial guessed + // pairing. Repeated words retain their occurrence order and provenance. + final ordered = _mergeFieldMappings( + richRuns: richRuns, + sourceRuns: sourceProjection.runs, + sourceOnlyRegions: _sourceOnlyRegions(currentDocument.blocks), + ); + if (ordered.allRichRunsMapped) merged = ordered; + } + // document.source is the source already committed by the workspace. Dirty + // blocks can retain pre-edit spans; serializing this rebased tree a second + // time is not a validity check and can apply the same edit twice. Validate + // the complete rich/source correspondence instead. + complete = + complete && sourceProjection.complete && merged.allRichRunsMapped; + return SpellingProjectionResult( + runs: merged.runs, + complete: complete, + message: complete + ? null + : 'Some rich-text fields could not be mapped to the current source.', + ); + } +} + +final class _MergedRichProjection { + const _MergedRichProjection({ + required this.runs, + required this.allRichRunsMapped, + }); + + final List runs; + final bool allRichRunsMapped; +} + +/// Pairs the live rich fields with the current authored source in source +/// order. Extra source runs (for example a link title with no rich field) stay +/// source targets, while matched runs retain both their exact source atoms and +/// their rich leaf addresses. +_MergedRichProjection _mergeCurrentSourceMappings({ + required List richRuns, + required List sourceRuns, + required Map fieldKeysByTarget, + required List<_SourceFieldRegion> sourceRegions, +}) { + final richByField = >{}; + for (final run in richRuns) { + final key = fieldKeysByTarget[_targetIdentity(run.target)]; + if (key == null) continue; + richByField.putIfAbsent(key, () => []).add(run); + } + final sourceByField = >{}; + final sourceFieldKeys = {}; + for (final run in sourceRuns) { + int? start; + int? end; + for (final atom in run.atoms) { + if (atom.sourceStart < 0 || atom.sourceEnd < 0) continue; + start = start == null || atom.sourceStart < start + ? atom.sourceStart + : start; + end = end == null || atom.sourceEnd > end ? atom.sourceEnd : end; + } + if (start == null || end == null) continue; + _SourceFieldRegion? region; + for (final candidate in sourceRegions) { + if (candidate.start > start || candidate.end < end) continue; + if (region == null || + candidate.end - candidate.start < region.end - region.start) { + region = candidate; + } + } + if (region == null) continue; + sourceFieldKeys[run] = region.key; + sourceByField.putIfAbsent(region.key, () => []).add(run); + } + + final mergedByField = {}; + var allRichRunsMapped = true; + for (final entry in richByField.entries) { + final merged = _mergeFieldMappings( + richRuns: entry.value, + sourceRuns: sourceByField[entry.key] ?? const [], + ); + mergedByField[entry.key] = merged; + allRichRunsMapped = allRichRunsMapped && merged.allRichRunsMapped; + } + + final result = []; + final emittedFields = {}; + for (final sourceRun in sourceRuns) { + final key = sourceFieldKeys[sourceRun]; + if (key == null || !richByField.containsKey(key)) { + result.add(sourceRun); + } else if (emittedFields.add(key)) { + result.addAll(mergedByField[key]!.runs); + } + } + for (final entry in richByField.entries) { + if (emittedFields.add(entry.key)) { + result.addAll(mergedByField[entry.key]!.runs); + allRichRunsMapped = false; + } + } + return _MergedRichProjection( + runs: List.unmodifiable(result), + allRichRunsMapped: allRichRunsMapped, + ); +} + +_MergedRichProjection _mergeFieldMappings({ + required List richRuns, + required List sourceRuns, + List<({int start, int end})> sourceOnlyRegions = const [], +}) { + final result = []; + var richCursor = 0; + var complete = true; + for (var sourceRun in sourceRuns) { + if (_sourceOnlyMetadataRun(sourceRun) || + sourceOnlyRegions.any( + (region) => sourceRun.atoms.every( + (atom) => + atom.sourceStart >= region.start && + atom.sourceEnd <= region.end, + ), + )) { + result.add(sourceRun); + continue; + } + var richRun = richCursor < richRuns.length ? richRuns[richCursor] : null; + if (richRun == null) { + complete = false; + result.add(sourceRun); + continue; + } + // Field identity and run ordinal establish provenance. Text equality is + // only an integrity check; a mismatch consumes this pair so it cannot + // cascade into duplicate/falsely matched runs later in the field. + richCursor++; + if (sourceRun.text != richRun.text && + sourceRun.text.trim() == richRun.text.trim()) { + // Boundary HTML breaks can be represented as rich whitespace atoms + // but blank lines/indentation in Source. Ignore only that boundary space; + // all prose and its source/field intervals must still match exactly. + sourceRun = _withoutBoundaryWhitespace(sourceRun); + richRun = _withoutBoundaryWhitespace(richRun); + } + if (!_compatibleRuns(sourceRun, richRun)) { + complete = false; + result.add(sourceRun); + continue; + } + final mergedAtoms = _mergeRunAtoms(sourceRun, richRun); + if (mergedAtoms == null) { + complete = false; + result.add(sourceRun); + continue; + } + result.add( + SpellingProseRun( + id: richRun.id, + text: richRun.text, + languageId: richRun.languageId, + atoms: mergedAtoms, + target: richRun.target, + snapshot: richRun.snapshot, + formattingWrappers: _mergeFormattingWrappers( + sourceRun.formattingWrappers, + richRun.formattingWrappers, + ), + complete: sourceRun.complete && richRun.complete, + tokenizationContext: sourceRun.tokenizationContext, + tokenizationContextStart: sourceRun.tokenizationContextStart, + ), + ); + } + if (richCursor < richRuns.length) { + complete = false; + result.addAll(richRuns.skip(richCursor)); + } + return _MergedRichProjection( + runs: List.unmodifiable(result), + allRichRunsMapped: complete, + ); +} + +// Source-only content (for example protected raw HTML) is still checked, but +// it has no editable rich field and must not consume the next rich run. Only +// current parser-provided intervals establish that distinction. +List<({int start, int end})> _sourceOnlyRegions(List blocks) { + final result = <({int start, int end})>[]; + void visit(BusyBlock block) { + if (!_eligibleBlockKinds.contains(block.kind) || + block.isSourceProtected || + block.isGenerated || + block.isSourceOnly) { + final span = block.sourceSpan; + if (span != null) { + result.add((start: span.startOffset, end: span.endOffset)); + } + return; + } + for (final child in block.children) { + visit(child); + } + } + + for (final block in blocks) { + visit(block); + } + return result; +} + +SpellingProseRun _withoutBoundaryWhitespace(SpellingProseRun run) { + final text = run.text.trim(); + if (text == run.text) return run; + final start = run.text.length - run.text.trimLeft().length; + final end = start + text.length; + final atoms = []; + for (final atom in run.atoms) { + if (atom.logicalEnd <= start) continue; + if (atom.logicalStart >= end) break; + final keptStart = atom.logicalStart.clamp(start, end); + final keptEnd = atom.logicalEnd.clamp(start, end); + final source = atom.sourceIntervalFor(keptStart, keptEnd); + final field = atom.fieldIntervalFor(keptStart, keptEnd); + atoms.add( + SpellingSourceAtom( + logicalText: atom.logicalText.substring( + keptStart - atom.logicalStart, + keptEnd - atom.logicalStart, + ), + logicalStart: keptStart - start, + logicalEnd: keptEnd - start, + sourceStart: source?.start ?? -1, + sourceEnd: source?.end ?? -1, + fieldStart: field?.start, + fieldEnd: field?.end, + richLeafPath: atom.richLeafPath, + transformation: atom.transformation, + context: atom.context, + ), + ); + } + return SpellingProseRun( + id: run.id, + text: text, + languageId: run.languageId, + atoms: atoms, + target: run.target, + snapshot: run.snapshot, + formattingWrappers: [ + for (final wrapper in run.formattingWrappers) + if (wrapper.logicalStart < end && wrapper.logicalEnd > start) + SpellingFormattingWrapper( + logicalStart: wrapper.logicalStart.clamp(start, end) - start, + logicalEnd: wrapper.logicalEnd.clamp(start, end) - start, + openingStart: wrapper.openingStart, + openingEnd: wrapper.openingEnd, + closingStart: wrapper.closingStart, + closingEnd: wrapper.closingEnd, + removableWhenLogicallyEmpty: wrapper.removableWhenLogicallyEmpty, + fieldOpeningStart: wrapper.fieldOpeningStart, + fieldOpeningEnd: wrapper.fieldOpeningEnd, + fieldClosingStart: wrapper.fieldClosingStart, + fieldClosingEnd: wrapper.fieldClosingEnd, + structuralKind: wrapper.structuralKind, + ), + ], + complete: run.complete, + tokenizationContext: run.tokenizationContext, + tokenizationContextStart: run.tokenizationContextStart + start, + ); +} + +bool _sourceOnlyMetadataRun(SpellingProseRun run) { + if (run.atoms.isEmpty) return false; + return run.atoms.every( + (atom) => switch (atom.context) { + SpellingSourceContext.markdownSingleQuotedTitle || + SpellingSourceContext.markdownDoubleQuotedTitle || + SpellingSourceContext.xmlSingleQuotedAttribute || + SpellingSourceContext.xmlDoubleQuotedAttribute => true, + _ => false, + }, + ); +} + +bool _compatibleRuns(SpellingProseRun source, SpellingProseRun rich) { + if (source.text != rich.text || + source.languageId != rich.languageId || + source.atoms.isEmpty || + rich.atoms.isEmpty) { + return false; + } + return source.atoms.first.context == rich.atoms.first.context; +} + +List? _mergeRunAtoms( + SpellingProseRun source, + SpellingProseRun rich, +) { + final result = []; + var richCursor = 0; + for (final sourceAtom in source.atoms) { + while (richCursor < rich.atoms.length && + rich.atoms[richCursor].logicalEnd <= sourceAtom.logicalStart) { + richCursor++; + } + if (richCursor >= rich.atoms.length) return null; + final richAtom = rich.atoms[richCursor]; + if (richAtom.logicalStart > sourceAtom.logicalStart || + richAtom.logicalEnd < sourceAtom.logicalEnd) { + return null; + } + final fieldRange = richAtom.fieldIntervalFor( + sourceAtom.logicalStart, + sourceAtom.logicalEnd, + ); + if (fieldRange == null) return null; + result.add( + SpellingSourceAtom( + logicalText: sourceAtom.logicalText, + logicalStart: sourceAtom.logicalStart, + logicalEnd: sourceAtom.logicalEnd, + sourceStart: sourceAtom.sourceStart, + sourceEnd: sourceAtom.sourceEnd, + fieldStart: fieldRange.start, + fieldEnd: fieldRange.end, + richLeafPath: richAtom.richLeafPath, + transformation: sourceAtom.transformation, + context: sourceAtom.context, + ), + ); + } + return List.unmodifiable(result); +} + +List _mergeFormattingWrappers( + List source, + List field, +) { + final used = {}; + return List.unmodifiable([ + for (final sourceWrapper in source) + if (_matchingFieldWrapper(sourceWrapper, field, used) + case final fieldWrapper?) + SpellingFormattingWrapper( + logicalStart: sourceWrapper.logicalStart, + logicalEnd: sourceWrapper.logicalEnd, + openingStart: sourceWrapper.openingStart, + openingEnd: sourceWrapper.openingEnd, + closingStart: sourceWrapper.closingStart, + closingEnd: sourceWrapper.closingEnd, + removableWhenLogicallyEmpty: + sourceWrapper.removableWhenLogicallyEmpty && + fieldWrapper.removableWhenLogicallyEmpty, + fieldOpeningStart: fieldWrapper.fieldOpeningStart, + fieldOpeningEnd: fieldWrapper.fieldOpeningEnd, + fieldClosingStart: fieldWrapper.fieldClosingStart, + fieldClosingEnd: fieldWrapper.fieldClosingEnd, + structuralKind: sourceWrapper.structuralKind, + ) + else + sourceWrapper, + ]); +} + +SpellingFormattingWrapper? _matchingFieldWrapper( + SpellingFormattingWrapper source, + List field, + Set used, +) { + int? fallback; + for (var index = 0; index < field.length; index++) { + if (used.contains(index)) continue; + final candidate = field[index]; + if (candidate.logicalStart != source.logicalStart || + candidate.logicalEnd != source.logicalEnd) { + continue; + } + fallback ??= index; + final sameKind = candidate.structuralKind == source.structuralKind; + final sameDelimiterShape = + candidate.fieldOpeningEnd! - candidate.fieldOpeningStart! == + source.openingEnd - source.openingStart && + candidate.fieldClosingEnd! - candidate.fieldClosingStart! == + source.closingEnd - source.closingStart; + if (sameKind && sameDelimiterShape) { + used.add(index); + return candidate; + } + } + if (fallback case final index?) { + used.add(index); + return field[index]; + } + return null; +} + +final class _SourceFieldRegion { + const _SourceFieldRegion({ + required this.key, + required this.start, + required this.end, + }); + + final String key; + final int start; + final int end; +} + +List<_SourceFieldRegion> _sourceFieldRegions( + String source, + List blocks, +) { + final result = <_SourceFieldRegion>[]; + + void visit(BusyBlock block, List path) { + if (block.isGenerated || + block.isSourceProtected || + block.isSourceOnly || + !_eligibleBlockKinds.contains(block.kind)) { + return; + } + if (block.kind == BusyBlockKind.table) { + for (final region in busyMarkMarkdownTableCellRegions( + source: source, + table: block, + )) { + result.add( + _SourceFieldRegion( + key: '${path.join('.')}:table:${region.row}:${region.column}', + start: region.span.startOffset, + end: region.span.endOffset, + ), + ); + } + return; + } + final span = block.sourceSpan; + if (block.inlines.isNotEmpty && span != null) { + result.add( + _SourceFieldRegion( + key: '${path.join('.')}:block', + start: span.startOffset, + end: span.endOffset, + ), + ); + } + for (final (index, child) in block.children.indexed) { + visit(child, [...path, index]); + } + } + + for (final (index, block) in blocks.indexed) { + visit(block, [index]); + } + return List.unmodifiable(result); +} + +String _targetIdentity(SpellingEditorTarget target) => switch (target) { + SpellingRichBlockTarget(:final blockId) => 'block:$blockId', + SpellingRichTableCellTarget(:final tableBlockId, :final cellId) => + 'table:$tableBlockId:$cellId', + SpellingSourceTarget(:final filePath) => 'source:$filePath', +}; + +const _eligibleBlockKinds = { + BusyBlockKind.heading, + BusyBlockKind.paragraph, + BusyBlockKind.unorderedListItem, + BusyBlockKind.orderedListItem, + BusyBlockKind.taskListItem, + BusyBlockKind.blockquote, + BusyBlockKind.image, + BusyBlockKind.table, + BusyBlockKind.writersideAdmonition, + BusyBlockKind.writersideTabs, + BusyBlockKind.writersideProcedure, +}; diff --git a/lib/src/workspace/document_buffer.dart b/lib/src/workspace/document_buffer.dart index 42bab8ec..b922e0f3 100644 --- a/lib/src/workspace/document_buffer.dart +++ b/lib/src/workspace/document_buffer.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import '../app/app_settings.dart'; import '../editor/source/source_search.dart'; import '../editor/wysiwyg/wysiwyg_session_state.dart'; +import '../spellcheck/spelling_language.dart'; import 'text_format_metadata.dart'; import 'workspace_file_snapshot.dart'; @@ -13,10 +14,15 @@ const Object _bufferUnset = Object(); enum DocumentDiskState { present, changed, deleted, conflict } class DocumentHistoryState { - const DocumentHistoryState({required this.text, required this.selection}); + const DocumentHistoryState({ + required this.text, + required this.selection, + this.wysiwygState = const WysiwygEditorSessionState(), + }); final String text; final TextSelection selection; + final WysiwygEditorSessionState wysiwygState; } class DocumentUndoState { @@ -74,6 +80,7 @@ class DocumentEditorState { this.searchReplacement = '', this.undoState = const DocumentUndoState(), this.wysiwygState = const WysiwygEditorSessionState(), + this.spellingLanguage = const SpellingLanguageOverride.inherit(), }); final DocumentViewModePreference mode; @@ -84,6 +91,7 @@ class DocumentEditorState { final String searchReplacement; final DocumentUndoState undoState; final WysiwygEditorSessionState wysiwygState; + final SpellingLanguageOverride spellingLanguage; DocumentEditorState copyWith({ DocumentViewModePreference? mode, @@ -94,6 +102,7 @@ class DocumentEditorState { String? searchReplacement, DocumentUndoState? undoState, WysiwygEditorSessionState? wysiwygState, + SpellingLanguageOverride? spellingLanguage, }) { return DocumentEditorState( mode: mode ?? this.mode, @@ -106,6 +115,7 @@ class DocumentEditorState { searchReplacement: searchReplacement ?? this.searchReplacement, undoState: undoState ?? this.undoState, wysiwygState: wysiwygState ?? this.wysiwygState, + spellingLanguage: spellingLanguage ?? this.spellingLanguage, ); } @@ -121,6 +131,7 @@ class DocumentEditorState { 'searchRegex': searchOptions.regex, 'searchReplacement': searchReplacement, 'wysiwygState': wysiwygState.toJson(), + 'spellingLanguage': spellingLanguage.toJson(), }; factory DocumentEditorState.fromJson(Map json) { @@ -149,6 +160,9 @@ class DocumentEditorState { wysiwygState: WysiwygEditorSessionState.fromJson( (json['wysiwygState'] as Map?)?.cast() ?? const {}, ), + spellingLanguage: SpellingLanguageOverride.fromJson( + json['spellingLanguage'], + ), ); } } @@ -234,6 +248,8 @@ class DocumentBuffer { String? undoGroup, TextSelection? previousSelection, TextSelection? nextSelection, + WysiwygEditorSessionState? previousWysiwygState, + WysiwygEditorSessionState? nextWysiwygState, }) { if (nextText == text) { return this; @@ -253,8 +269,13 @@ class DocumentBuffer { revision: revision + 1, editorState: editorState.copyWith( selection: updatedSelection, + wysiwygState: nextWysiwygState ?? editorState.wysiwygState, undoState: editorState.undoState.push( - DocumentHistoryState(text: text, selection: historicalSelection), + DocumentHistoryState( + text: text, + selection: historicalSelection, + wysiwygState: previousWysiwygState ?? editorState.wysiwygState, + ), group: undoGroup, ), ), diff --git a/lib/src/workspace/presentation/document_format_indicator.dart b/lib/src/workspace/presentation/document_format_indicator.dart index a05d8190..8c8909bd 100644 --- a/lib/src/workspace/presentation/document_format_indicator.dart +++ b/lib/src/workspace/presentation/document_format_indicator.dart @@ -4,7 +4,7 @@ import '../../app/busymark_design.dart'; import '../../app/localization.dart'; import '../text_format_metadata.dart'; -/// Compact active-document format status for the pane header. +/// Compact active-document format status for the document status strip. /// /// Encoding and final-newline details stay available without recreating the /// old full-width footer. A BOM is included in the visible label because its diff --git a/lib/src/workspace/presentation/document_status_bar.dart b/lib/src/workspace/presentation/document_status_bar.dart new file mode 100644 index 00000000..123ea63b --- /dev/null +++ b/lib/src/workspace/presentation/document_status_bar.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; + +import '../../app/busymark_design.dart'; +import '../text_format_metadata.dart'; +import 'document_format_indicator.dart'; + +class BusyMarkDocumentStatusBar extends StatelessWidget { + const BusyMarkDocumentStatusBar({ + super.key, + required this.format, + this.spellingLabel, + this.spellingTooltip, + this.onSpellingPressed, + }); + + final TextFormatMetadata format; + final String? spellingLabel; + final String? spellingTooltip; + final VoidCallback? onSpellingPressed; + + @override + Widget build(BuildContext context) { + final colors = BusyMarkSurfaceColors.of(context); + return DecoratedBox( + key: const ValueKey('document-status-bar'), + decoration: BoxDecoration( + color: colors.headerbarFlat, + border: Border(top: BorderSide(color: colors.subtleBorder)), + ), + child: SizedBox( + height: BusyMarkSizes.documentStatusBarHeight, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: BusyMarkSpacing.xs), + child: Row( + children: [ + if (spellingLabel case final label?) + Expanded( + child: Align( + alignment: AlignmentDirectional.centerStart, + child: _DocumentStatusAction( + label: label, + tooltip: spellingTooltip, + onPressed: onSpellingPressed, + ), + ), + ) + else + const Spacer(), + BusyMarkDocumentFormatIndicator(format: format), + ], + ), + ), + ), + ); + } +} + +class _DocumentStatusAction extends StatelessWidget { + const _DocumentStatusAction({ + required this.label, + required this.tooltip, + required this.onPressed, + }); + + final String label; + final String? tooltip; + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + final colors = BusyMarkSurfaceColors.of(context); + Widget action = Semantics( + key: const ValueKey('document-spelling-language-status'), + button: true, + enabled: onPressed != null, + child: Material( + color: BusyMarkLinuxPalette.transparent, + child: InkWell( + onTap: onPressed, + borderRadius: BorderRadius.circular(BusyMarkRadius.sm), + hoverColor: busyMarkRowHoverColor(context), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: BusyMarkSpacing.sm, + vertical: BusyMarkSpacing.xxs, + ), + child: Text( + label, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.ellipsis, + style: Theme.of( + context, + ).textTheme.labelSmall?.copyWith(color: colors.mutedForeground), + ), + ), + ), + ), + ); + if (tooltip case final message?) { + action = Tooltip(message: message, child: action); + } + return action; + } +} diff --git a/lib/src/workspace/presentation/settings_screen.dart b/lib/src/workspace/presentation/settings_screen.dart index b91ac60e..1fea4ab9 100644 --- a/lib/src/workspace/presentation/settings_screen.dart +++ b/lib/src/workspace/presentation/settings_screen.dart @@ -1,7 +1,10 @@ import 'dart:async'; +import 'dart:convert'; +import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import '../../../l10n/generated/app_localizations.dart'; @@ -17,10 +20,16 @@ import '../../app/busymark_design.dart'; import '../../app/busymark_glyphs.dart'; import '../../app/busymark_main_menu.dart'; import '../../app/busymark_shortcuts.dart'; +import '../../app/busymark_toast.dart'; import '../../app/localization.dart'; import '../../app/window_control_service.dart'; +import '../../core/atomic_file_writer.dart'; import '../../feedback/presentation/feedback_dialog.dart'; import '../../platform/linux_header_bar_service.dart'; +import '../../spellcheck/spelling_catalog.dart'; +import '../../spellcheck/spelling_session_controller.dart'; +import '../../spellcheck/spelling_word_store.dart'; +import '../workspace_controller.dart'; class SettingsScreen extends ConsumerStatefulWidget { const SettingsScreen({ @@ -38,6 +47,8 @@ class SettingsScreen extends ConsumerStatefulWidget { class _SettingsScreenState extends ConsumerState { late SettingsPage _page = widget.initialPage; + String? _preparedSpellingWorkspaceId; + bool _preparingSpelling = false; @override void didUpdateWidget(covariant SettingsScreen oldWidget) { @@ -52,6 +63,28 @@ class _SettingsScreenState extends ConsumerState { final l10n = AppLocalizations.of(context); final settings = ref.watch(appSettingsControllerProvider); final controller = ref.read(appSettingsControllerProvider.notifier); + final spelling = ref.watch(spellingSessionControllerProvider); + final workspace = ref.watch( + workspaceControllerProvider.select((state) => state.workspace), + ); + final spellingCatalog = spelling.catalog; + final importedDictionaries = + spellingCatalog?.installations + .where((entry) => entry.imported) + .toList(growable: false) ?? + const []; + final invalidImportedDictionaries = + spellingCatalog?.invalidInstallations + .where( + (entry) => + entry.kind == SpellingDictionaryInstallationKind.imported, + ) + .toList(growable: false) ?? + const []; + final spellingResources = + spellingCatalog?.availableEntries ?? + const []; + _prepareSpellingSettings(spelling, workspace?.id); final colors = BusyMarkSurfaceColors.of(context); final headerBar = ref.watch(linuxHeaderBarServiceProvider); final useNativeHeaderBar = headerBar.usesNativeHeaderBar; @@ -76,37 +109,203 @@ class _SettingsScreenState extends ConsumerState { ), ], ), - SettingsPage.editor => BusyMarkGroupedList( - title: l10n.editor, - filled: true, + SettingsPage.editor => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - BusyMarkSwitchRow( - title: l10n.autoSave, - subtitle: l10n.autoSaveDescription, - value: settings.autoSave, - onChanged: controller.setAutoSave, - leading: const Icon(BusyMarkGlyphs.save), + BusyMarkGroupedList( + title: l10n.editor, + filled: true, + children: [ + BusyMarkSwitchRow( + title: l10n.autoSave, + subtitle: l10n.autoSaveDescription, + value: settings.autoSave, + onChanged: controller.setAutoSave, + leading: const Icon(BusyMarkGlyphs.save), + ), + BusyMarkSwitchRow( + title: l10n.wordWrap, + subtitle: l10n.wordWrapDescription, + value: settings.wordWrap, + onChanged: controller.setWordWrap, + leading: Icon( + BusyMarkGlyphs.wordWrapFor(Directionality.of(context)), + ), + ), + _EditorFontSizeRow( + value: settings.editorFontSize, + onChanged: controller.setEditorFontSize, + ), + ], ), - BusyMarkSwitchRow( - title: l10n.wordWrap, - value: settings.wordWrap, - onChanged: controller.setWordWrap, - leading: Icon( - BusyMarkGlyphs.wordWrapFor(Directionality.of(context)), - ), + BusyMarkGroupedList( + title: l10n.settingsEditingButtonsSectionTitle, + filled: true, + children: [ + _EditorToolbarPlacementRow( + selected: settings.editorToolbarPlacement, + onChanged: controller.setEditorToolbarPlacement, + ), + _EditorToolbarDirectionRow( + selected: settings.editorToolbarDirection, + onChanged: controller.setEditorToolbarDirection, + ), + ], ), - _EditorFontSizeRow( - value: settings.editorFontSize, - onChanged: controller.setEditorFontSize, + BusyMarkGroupedList( + title: l10n.spelling, + filled: true, + children: [ + BusyMarkSwitchRow( + title: l10n.automaticSpelling, + value: settings.automaticSpelling, + onChanged: controller.setAutomaticSpelling, + leading: const Icon(BusyMarkGlyphs.diagnostics), + ), + _SpellingLanguageRow( + title: l10n.defaultSpellingLanguage, + selected: settings.defaultSpellingLanguage, + catalogEntries: spelling.catalog?.entries ?? const [], + unsetLabel: l10n.chooseSpellingLanguage, + onChanged: (value) => unawaited( + _setDefaultSpellingLanguage( + context, + spelling, + controller, + value, + ), + ), + ), + _SpellingLanguageRow( + title: l10n.projectSpellingLanguage, + selected: spelling.projectWords.projectLanguage, + catalogEntries: spelling.catalog?.entries ?? const [], + unsetLabel: l10n.inheritSpellingLanguage, + enabled: spelling.hasProjectScope, + onChanged: (value) => unawaited( + _setProjectSpellingLanguage(context, spelling, value), + ), + ), + ], + ), + BusyMarkGroupedList( + title: l10n.settingsDictionariesSectionTitle, + filled: true, + children: [ + BusyMarkActionRow( + key: const ValueKey('settings-spelling-dictionaries'), + title: l10n.spellingDictionaries, + subtitle: l10n.spellingDictionariesDescription, + leading: const Icon(BusyMarkGlyphs.symbols), + trailing: Icon( + BusyMarkGlyphs.forwardFor(Directionality.of(context)), + ), + onTap: () => _selectPage(SettingsPage.spellingDictionaries), + ), + _SpellingWordStoreRow( + title: l10n.personalSpellingDictionary, + snapshot: spelling.personalWords, + onRemove: spelling.removePersonalWord, + ), + _SpellingWordStoreRow( + title: l10n.projectSpellingDictionary, + snapshot: spelling.projectWords, + enabled: spelling.hasProjectScope, + onRemove: spelling.removeProjectWord, + ), + ], ), - _EditorToolbarPlacementRow( - selected: settings.editorToolbarPlacement, - onChanged: controller.setEditorToolbarPlacement, + ], + ), + SettingsPage.spellingDictionaries => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + BusyMarkGroupedList( + title: l10n.availableSpellingDictionaries, + filled: true, + children: [ + for (final resource in spellingResources) + _SpellingDictionaryResourceRow( + resource: resource, + installed: + spellingCatalog?.installationForResource( + resource.resourceId, + kind: SpellingDictionaryInstallationKind.downloaded, + ) != + null, + status: spelling.dictionaryInstallStatus, + onInstall: () => unawaited( + _installSpellingDictionary(context, spelling, resource.id), + ), + onRemove: () => unawaited( + _removeDownloadedSpellingDictionary( + context, + spelling, + resource.id, + ), + ), + onCancel: spelling.cancelDictionaryInstallation, + onRetry: () => + unawaited(_retrySpellingDictionary(context, spelling)), + ), + ], ), - _EditorToolbarDirectionRow( - selected: settings.editorToolbarDirection, - onChanged: controller.setEditorToolbarDirection, + BusyMarkGroupedList( + title: l10n.customSpellingDictionaries, + filled: true, + children: [ + BusyMarkActionRow( + key: const ValueKey('import-spelling-dictionary'), + title: l10n.importSpellingDictionary, + leading: const Icon(BusyMarkGlyphs.add), + onTap: () => + unawaited(_importSpellingDictionary(context, spelling)), + ), + for (final entry in importedDictionaries) + BusyMarkActionRow( + title: entry.label, + subtitle: entry.id, + leading: const Icon(BusyMarkGlyphs.symbols), + trailing: BusyMarkCompactIconButton( + tooltip: l10n.removeAction, + icon: BusyMarkGlyphs.delete, + foregroundColor: Theme.of(context).colorScheme.error, + onPressed: () => unawaited( + _removeImportedSpellingDictionary( + context, + spelling, + entry.id, + ), + ), + ), + ), + ], ), + if (invalidImportedDictionaries.isNotEmpty) + BusyMarkGroupedList( + title: l10n.spellingDictionaryProblems, + filled: true, + children: [ + for (final entry in invalidImportedDictionaries) + BusyMarkActionRow( + title: entry.id ?? entry.resourceId ?? entry.directoryPath, + subtitle: entry.error, + leading: const Icon(BusyMarkGlyphs.warning), + trailing: BusyMarkCompactIconButton( + tooltip: l10n.removeAction, + icon: BusyMarkGlyphs.delete, + foregroundColor: Theme.of(context).colorScheme.error, + onPressed: () => unawaited( + _removeInvalidSpellingDictionary( + context, + spelling, + entry, + ), + ), + ), + ), + ], + ), ], ), SettingsPage.validation => BusyMarkGroupedList( @@ -121,83 +320,95 @@ class _SettingsScreenState extends ConsumerState { ), ], ), - SettingsPage.history => BusyMarkGroupedList( - title: l10n.settingsHistory, - filled: true, + SettingsPage.history => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - BusyMarkSwitchRow( - title: l10n.settingsClipboardHistoryTitle, - subtitle: l10n.settingsClipboardHistoryDescription, - value: settings.clipboardHistoryEnabled, - onChanged: controller.setClipboardHistoryEnabled, - leading: const Icon(BusyMarkGlyphs.copy), - ), - BusyMarkSwitchRow( - title: l10n.settingsLocalHistoryTitle, - subtitle: l10n.settingsLocalHistoryDescription, - value: settings.localHistoryRecordingEnabled, - onChanged: controller.setLocalHistoryRecordingEnabled, - leading: const Icon(BusyMarkGlyphs.documentHistory), - ), - _HistoryNumberRow( - title: l10n.settingsHistoryCheckpoint, - value: settings.localHistoryCheckpointSeconds, - choices: const [30, 60, 120, 300, 600], - format: l10n.settingsSecondsValue, - enabled: settings.localHistoryRecordingEnabled, - onChanged: controller.setLocalHistoryCheckpointSeconds, - ), - _HistoryNumberRow( - title: l10n.settingsHistoryRetention, - value: settings.localHistoryRetentionDays, - choices: const [7, 30, 90, 365], - format: l10n.settingsDaysValue, - enabled: settings.localHistoryRecordingEnabled, - onChanged: controller.setLocalHistoryRetentionDays, - ), - _HistoryNumberRow( - title: l10n.settingsHistoryStorage, - value: settings.localHistoryMaximumStorageMiB, - choices: const [128, 256, 512, 1024, 2048, 4096], - format: l10n.settingsMebibytesValue, - enabled: settings.localHistoryRecordingEnabled, - onChanged: controller.setLocalHistoryMaximumStorageMiB, + BusyMarkGroupedList( + title: l10n.settingsHistory, + filled: true, + children: [ + BusyMarkSwitchRow( + title: l10n.settingsClipboardHistoryTitle, + subtitle: l10n.settingsClipboardHistoryDescription, + value: settings.clipboardHistoryEnabled, + onChanged: controller.setClipboardHistoryEnabled, + leading: const Icon(BusyMarkGlyphs.copy), + ), + BusyMarkSwitchRow( + title: l10n.settingsLocalHistoryTitle, + subtitle: l10n.settingsLocalHistoryDescription, + value: settings.localHistoryRecordingEnabled, + onChanged: controller.setLocalHistoryRecordingEnabled, + leading: const Icon(BusyMarkGlyphs.documentHistory), + ), + _HistoryNumberRow( + title: l10n.settingsHistoryCheckpoint, + value: settings.localHistoryCheckpointSeconds, + choices: const [30, 60, 120, 300, 600], + format: l10n.settingsSecondsValue, + enabled: settings.localHistoryRecordingEnabled, + onChanged: controller.setLocalHistoryCheckpointSeconds, + ), + _HistoryNumberRow( + title: l10n.settingsHistoryRetention, + value: settings.localHistoryRetentionDays, + choices: const [7, 30, 90, 365], + format: l10n.settingsDaysValue, + enabled: settings.localHistoryRecordingEnabled, + onChanged: controller.setLocalHistoryRetentionDays, + ), + _HistoryNumberRow( + title: l10n.settingsHistoryStorage, + value: settings.localHistoryMaximumStorageMiB, + choices: const [128, 256, 512, 1024, 2048, 4096], + format: l10n.settingsMebibytesValue, + enabled: settings.localHistoryRecordingEnabled, + onChanged: controller.setLocalHistoryMaximumStorageMiB, + ), + BusyMarkActionRow( + title: l10n.settingsHistoryExcludedPaths, + subtitle: settings.localHistoryExcludedPaths.isEmpty + ? l10n.settingsHistoryExcludedPathsHint + : settings.localHistoryExcludedPaths.join('\n'), + leading: const Icon(BusyMarkGlyphs.folder), + onTap: () => _editHistoryExcludedPaths( + context, + settings.localHistoryExcludedPaths, + controller.setLocalHistoryExcludedPaths, + ), + ), + BusyMarkActionRow( + title: l10n.clearRecentWorkspaces, + leading: const Icon(BusyMarkGlyphs.clearAll), + destructive: true, + onTap: controller.clearRecentWorkspaces, + ), + ], ), - BusyMarkActionRow( - title: l10n.settingsHistoryExcludedPaths, - subtitle: settings.localHistoryExcludedPaths.isEmpty - ? l10n.settingsHistoryExcludedPathsHint - : settings.localHistoryExcludedPaths.join('\n'), - leading: const Icon(BusyMarkGlyphs.folder), - onTap: () => _editHistoryExcludedPaths( - context, - settings.localHistoryExcludedPaths, - controller.setLocalHistoryExcludedPaths, - ), + BusyMarkGroupedList( + title: l10n.settingsWindowSectionTitle, + filled: true, + children: [ + BusyMarkSwitchRow( + title: l10n.settingsReopenWorkspaceOnStartupTitle, + subtitle: l10n.settingsReopenWorkspaceOnStartupDescription, + value: settings.reopenPreviousWorkspaceOnStartup, + onChanged: controller.setReopenPreviousWorkspaceOnStartup, + leading: const Icon(BusyMarkGlyphs.history), + ), + BusyMarkSwitchRow( + title: l10n.settingsConfirmCloseWithUnsavedChangesTitle, + subtitle: + l10n.settingsConfirmCloseWithUnsavedChangesDescription, + value: settings.confirmCloseWithUnsavedChanges, + onChanged: controller.setConfirmCloseWithUnsavedChanges, + leading: const Icon(BusyMarkGlyphs.warning), + ), + ], ), ], ), SettingsPage.ai => const _AiSettingsPage(), - SettingsPage.window => BusyMarkGroupedList( - title: l10n.settingsWindowSectionTitle, - filled: true, - children: [ - BusyMarkSwitchRow( - title: l10n.settingsReopenWorkspaceOnStartupTitle, - subtitle: l10n.settingsReopenWorkspaceOnStartupDescription, - value: settings.reopenPreviousWorkspaceOnStartup, - onChanged: controller.setReopenPreviousWorkspaceOnStartup, - leading: const Icon(BusyMarkGlyphs.history), - ), - BusyMarkSwitchRow( - title: l10n.settingsConfirmCloseWithUnsavedChangesTitle, - subtitle: l10n.settingsConfirmCloseWithUnsavedChangesDescription, - value: settings.confirmCloseWithUnsavedChanges, - onChanged: controller.setConfirmCloseWithUnsavedChanges, - leading: const Icon(BusyMarkGlyphs.warning), - ), - ], - ), SettingsPage.privacy => BusyMarkGroupedList( title: l10n.privacy, filled: true, @@ -225,18 +436,6 @@ class _SettingsScreenState extends ConsumerState { ), ], ), - SettingsPage.advanced => BusyMarkGroupedList( - title: l10n.advanced, - filled: true, - children: [ - BusyMarkActionRow( - title: l10n.clearRecentWorkspaces, - leading: const Icon(BusyMarkGlyphs.clearAll), - destructive: true, - onTap: controller.clearRecentWorkspaces, - ), - ], - ), }; return LayoutBuilder( @@ -278,7 +477,7 @@ class _SettingsScreenState extends ConsumerState { 0, ), child: _SettingsPageSelector( - selected: _page, + selected: _settingsNavigationSelection(_page), onSelected: _selectPage, ), ), @@ -300,7 +499,7 @@ class _SettingsScreenState extends ConsumerState { SizedBox( width: BusyMarkSizes.sidebarWidth, child: _SettingsSidebar( - selected: _page, + selected: _settingsNavigationSelection(_page), onSelected: _selectPage, ), ), @@ -309,24 +508,55 @@ class _SettingsScreenState extends ConsumerState { ) : content; - return HeaderBarConfigurationPublisher( - synchronizer: headerBar.configurationSynchronizer, - configuration: headerConfiguration, - enabled: headerBar.isAvailable, - child: Scaffold(backgroundColor: colors.view, body: body), + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + if (!didPop) _goBack(); + }, + child: HeaderBarConfigurationPublisher( + synchronizer: headerBar.configurationSynchronizer, + configuration: headerConfiguration, + enabled: headerBar.isAvailable, + child: Scaffold(backgroundColor: colors.view, body: body), + ), ); }, ); } + void _prepareSpellingSettings( + SpellingSessionController spelling, + String? workspaceId, + ) { + if (_preparingSpelling || + (_preparedSpellingWorkspaceId == workspaceId && + spelling.catalog != null)) { + return; + } + _preparingSpelling = true; + WidgetsBinding.instance.addPostFrameCallback((_) async { + try { + await spelling.prepareSettings( + ref.read(workspaceControllerProvider).workspace, + ); + _preparedSpellingWorkspaceId = workspaceId; + } finally { + _preparingSpelling = false; + if (mounted) setState(() {}); + } + }); + } + void _goBack() { + if (_page == SettingsPage.spellingDictionaries) { + _selectPage(SettingsPage.editor); + return; + } context.go(widget.returnTarget.location); } void _selectPage(SettingsPage page) { - if (_page != page) { - setState(() => _page = page); - } + if (_page != page) setState(() => _page = page); final router = GoRouter.maybeOf(context); final uri = router?.state.uri; if (router == null || uri == null || uri.path != settingsRoutePath) { @@ -420,6 +650,510 @@ class _SettingsScreenState extends ConsumerState { } } +class _SpellingLanguageRow extends StatefulWidget { + const _SpellingLanguageRow({ + required this.title, + required this.selected, + required this.catalogEntries, + required this.unsetLabel, + required this.onChanged, + this.enabled = true, + }); + + final String title; + final String? selected; + final List catalogEntries; + final String unsetLabel; + final bool enabled; + final ValueChanged onChanged; + + @override + State<_SpellingLanguageRow> createState() => _SpellingLanguageRowState(); +} + +class _SpellingLanguageRowState extends State<_SpellingLanguageRow> { + static const _unset = ''; + late final Future> _catalog = + _loadCatalog(); + + Future> _loadCatalog() async { + final source = await rootBundle.loadString( + 'assets/spelling/dictionaries.json', + ); + final decoded = jsonDecode(source); + final values = decoded is Map ? decoded['dictionaries'] : null; + if (values is! List) return const []; + return [ + for (final value in values.whereType()) + if (value['id'] case final String id when id.trim().isNotEmpty) + ( + id: id, + label: value['label']?.toString().trim().isNotEmpty == true + ? value['label'].toString() + : id, + ), + ]; + } + + @override + Widget build(BuildContext context) { + return FutureBuilder>( + future: _catalog, + builder: (context, snapshot) { + final dictionariesById = { + for (final entry in snapshot.data ?? const []) entry.id: entry, + for (final entry in widget.catalogEntries) + entry.id: (id: entry.id, label: entry.label), + }; + final dictionaries = dictionariesById.values.toList() + ..sort((left, right) => left.label.compareTo(right.label)); + final selected = widget.selected ?? _unset; + final selectedLabel = dictionaries + .where((entry) => entry.id == widget.selected) + .map((entry) => entry.label) + .firstOrNull; + return BusyMarkActionRow( + title: widget.title, + enabled: widget.enabled, + leading: const Icon(BusyMarkGlyphs.symbols), + trailing: SizedBox( + width: BusyMarkSizes.controlRowWidth, + child: BusyMarkPopupSelector( + value: selected, + label: selectedLabel ?? widget.unsetLabel, + tooltip: widget.title, + enabled: + widget.enabled && + snapshot.connectionState == ConnectionState.done, + options: [ + BusyMarkPopupSelectorOption( + value: _unset, + label: widget.unsetLabel, + ), + for (final dictionary in dictionaries) + BusyMarkPopupSelectorOption( + value: dictionary.id, + label: dictionary.label, + ), + ], + onSelected: (value) { + widget.onChanged(value == _unset ? null : value); + }, + ), + ), + ); + }, + ); + } +} + +class _SpellingDictionaryResourceRow extends StatelessWidget { + const _SpellingDictionaryResourceRow({ + required this.resource, + required this.installed, + required this.status, + required this.onInstall, + required this.onRemove, + required this.onCancel, + required this.onRetry, + }); + + final SpellingDictionaryResource resource; + final bool installed; + final SpellingDictionaryInstallStatus? status; + final VoidCallback onInstall; + final VoidCallback onRemove; + final VoidCallback onCancel; + final VoidCallback onRetry; + + @override + Widget build(BuildContext context) { + final active = status?.resourceId == resource.resourceId ? status : null; + final size = _formatDictionarySize(resource.downloadSize); + final subtitle = switch (active?.phase) { + SpellingDictionaryInstallPhase.downloading => + context.l10n.spellingDictionaryDownloading(size), + SpellingDictionaryInstallPhase.validating => + context.l10n.spellingDictionaryValidating, + SpellingDictionaryInstallPhase.failed => + context.l10n.spellingDictionaryInstallFailed, + null => + installed + ? context.l10n.spellingDictionaryInstalled + : context.l10n.spellingDictionaryNotInstalledWithSize(size), + }; + final progress = active?.phase == SpellingDictionaryInstallPhase.downloading + ? active?.progress + : null; + final action = switch (active?.phase) { + SpellingDictionaryInstallPhase.downloading || + SpellingDictionaryInstallPhase.validating => onCancel, + SpellingDictionaryInstallPhase.failed => onRetry, + null => installed ? onRemove : onInstall, + }; + final icon = switch (active?.phase) { + SpellingDictionaryInstallPhase.downloading || + SpellingDictionaryInstallPhase.validating => BusyMarkGlyphs.windowClose, + SpellingDictionaryInstallPhase.failed => BusyMarkGlyphs.refresh, + null => installed ? BusyMarkGlyphs.delete : BusyMarkGlyphs.pull, + }; + final tooltip = switch (active?.phase) { + SpellingDictionaryInstallPhase.downloading || + SpellingDictionaryInstallPhase.validating => + context.l10n.cancelSpellingDictionaryInstall, + SpellingDictionaryInstallPhase.failed => + context.l10n.retrySpellingDictionaryInstall, + null => + installed + ? context.l10n.removeSpellingDictionary + : context.l10n.installSpellingDictionary, + }; + return BusyMarkActionRow( + title: resource.label, + subtitleWidget: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(subtitle, maxLines: 1, overflow: TextOverflow.ellipsis), + if (active != null && + active.phase != SpellingDictionaryInstallPhase.failed) + Padding( + padding: const EdgeInsets.only(top: 4), + child: LinearProgressIndicator(value: progress), + ), + ], + ), + leading: const Icon(BusyMarkGlyphs.symbols), + trailing: BusyMarkCompactIconButton( + tooltip: tooltip, + icon: icon, + foregroundColor: installed && active == null + ? Theme.of(context).colorScheme.error + : null, + onPressed: action, + ), + ); + } +} + +String _formatDictionarySize(int bytes) { + final mebibytes = bytes / (1024 * 1024); + return mebibytes >= 10 + ? '${mebibytes.toStringAsFixed(0)} MiB' + : '${mebibytes.toStringAsFixed(1)} MiB'; +} + +Future _setDefaultSpellingLanguage( + BuildContext context, + SpellingSessionController spelling, + AppSettingsController controller, + String? languageId, +) async { + if (languageId != null && + !await _offerSpellingDictionaryInstall(context, spelling, languageId)) { + return; + } + if (context.mounted) { + await controller.setDefaultSpellingLanguage(languageId); + } +} + +Future _setProjectSpellingLanguage( + BuildContext context, + SpellingSessionController spelling, + String? languageId, +) async { + if (languageId != null && + !await _offerSpellingDictionaryInstall(context, spelling, languageId)) { + return; + } + if (!context.mounted) return; + try { + await spelling.setProjectLanguage(languageId); + } on Object catch (error) { + if (context.mounted) _showSpellingSettingsFailure(context, error); + } +} + +class _SpellingWordStoreRow extends StatelessWidget { + const _SpellingWordStoreRow({ + required this.title, + required this.snapshot, + required this.onRemove, + this.enabled = true, + }); + + final String title; + final SpellingWordStoreSnapshot snapshot; + final bool enabled; + final Future Function(String languageId, String word) onRemove; + + @override + Widget build(BuildContext context) { + final count = snapshot.wordsByLanguage.values.fold( + 0, + (total, words) => total + words.length, + ); + return BusyMarkActionRow( + title: title, + subtitle: count == 0 ? context.l10n.noResults : count.toString(), + enabled: enabled, + leading: const Icon(BusyMarkGlyphs.symbols), + onTap: () => + unawaited(_showSpellingWords(context, title, snapshot, onRemove)), + ); + } +} + +Future _importSpellingDictionary( + BuildContext context, + SpellingSessionController spelling, +) async { + final selected = await openFiles( + acceptedTypeGroups: [ + XTypeGroup( + label: context.l10n.spelling, + extensions: const ['aff', 'dic'], + ), + ], + ); + if (!context.mounted || selected.isEmpty) return; + final affFiles = selected + .where((file) => file.path.toLowerCase().endsWith('.aff')) + .toList(growable: false); + final dicFiles = selected + .where((file) => file.path.toLowerCase().endsWith('.dic')) + .toList(growable: false); + if (affFiles.length != 1 || dicFiles.length != 1) { + _showSpellingSettingsFailure(context); + return; + } + final languageController = TextEditingController(); + final languageId = await showBusyMarkModalDialog( + context, + barrierDismissible: false, + builder: (dialogContext) => BusyMarkDialogShell( + title: dialogContext.l10n.importSpellingDictionary, + closable: false, + actions: [ + BusyMarkDialogButton( + label: dialogContext.l10n.cancel, + onPressed: () => Navigator.pop(dialogContext), + ), + BusyMarkDialogButton( + label: dialogContext.l10n.save, + suggested: true, + onPressed: () { + final value = languageController.text.trim(); + if (value.isNotEmpty) Navigator.pop(dialogContext, value); + }, + ), + ], + children: [ + BusyMarkFloatingTextEntry( + label: dialogContext.l10n.language, + controller: languageController, + hintText: 'en-US', + autofocus: true, + textInputAction: TextInputAction.done, + minLines: 1, + maxLines: 1, + onSubmitted: (value) { + final trimmed = value.trim(); + if (trimmed.isNotEmpty) Navigator.pop(dialogContext, trimmed); + }, + ), + ], + ), + ); + // DialogRoute completes its result before its exit transition unmounts the + // native text entry, so keep the controller alive through that transition. + await Future.delayed(kThemeAnimationDuration); + await WidgetsBinding.instance.endOfFrame; + languageController.dispose(); + if (!context.mounted || languageId == null) return; + try { + await spelling.importDictionary( + affPath: affFiles.single.path, + dicPath: dicFiles.single.path, + languageId: languageId, + displayLabel: languageId, + ); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _removeImportedSpellingDictionary( + BuildContext context, + SpellingSessionController spelling, + String languageId, +) async { + try { + await spelling.removeImportedDictionary(languageId); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _removeInvalidSpellingDictionary( + BuildContext context, + SpellingSessionController spelling, + SpellingInvalidDictionaryInstallation installation, +) async { + try { + await spelling.removeInvalidDictionary(installation); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _installSpellingDictionary( + BuildContext context, + SpellingSessionController spelling, + String languageId, +) async { + try { + await spelling.installDictionary(languageId); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _offerSpellingDictionaryInstall( + BuildContext context, + SpellingSessionController spelling, + String languageId, +) async { + final catalog = spelling.catalog; + if (catalog?.installedById(languageId) != null) return true; + final resource = catalog?.availableById(languageId); + if (resource == null) return false; + final accepted = await showBusyMarkModalDialog( + context, + builder: (dialogContext) => BusyMarkDialogShell( + title: dialogContext.l10n.spellingDictionaryNotInstalled, + actions: [ + BusyMarkDialogButton( + label: dialogContext.l10n.cancel, + onPressed: () => Navigator.pop(dialogContext, false), + ), + BusyMarkDialogButton( + label: dialogContext.l10n.installSpellingDictionary, + suggested: true, + onPressed: () => Navigator.pop(dialogContext, true), + ), + ], + children: [ + Text( + dialogContext.l10n.spellingDictionaryInstallPrompt( + resource.label, + _formatDictionarySize(resource.downloadSize), + ), + ), + ], + ), + ); + if (accepted != true || !context.mounted) return false; + try { + await spelling.installDictionary(languageId); + } on Object catch (error) { + if (context.mounted) _showSpellingSettingsFailure(context, error); + return false; + } + return spelling.catalog?.installedById(languageId) != null; +} + +Future _retrySpellingDictionary( + BuildContext context, + SpellingSessionController spelling, +) async { + try { + await spelling.retryDictionaryInstallation(); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _removeDownloadedSpellingDictionary( + BuildContext context, + SpellingSessionController spelling, + String languageId, +) async { + try { + await spelling.removeDownloadedDictionary(languageId); + } on Object { + if (context.mounted) _showSpellingSettingsFailure(context); + } +} + +Future _showSpellingWords( + BuildContext context, + String title, + SpellingWordStoreSnapshot snapshot, + Future Function(String languageId, String word) remove, +) async { + final words = [ + for (final entry in snapshot.wordsByLanguage.entries) + for (final word in entry.value) (language: entry.key, word: word.display), + ]; + await showBusyMarkModalDialog( + context, + builder: (dialogContext) => BusyMarkDialogShell( + title: title, + actions: [ + BusyMarkDialogButton( + label: dialogContext.l10n.close, + onPressed: () => Navigator.pop(dialogContext), + ), + ], + children: [ + if (words.isEmpty) Text(dialogContext.l10n.noResults), + for (final entry in words) + BusyMarkActionRow( + title: entry.word, + subtitle: entry.language, + leading: const Icon(BusyMarkGlyphs.symbols), + trailing: const Icon(BusyMarkGlyphs.delete), + tooltip: dialogContext.l10n.removeAction, + destructive: true, + onTap: () async { + try { + await remove(entry.language, entry.word); + if (dialogContext.mounted) Navigator.pop(dialogContext); + } on Object catch (error) { + if (dialogContext.mounted) { + _showSpellingSettingsFailure(dialogContext, error); + } + } + }, + ), + ], + ), + ); +} + +void _showSpellingSettingsFailure(BuildContext context, [Object? error]) { + if (error is AtomicFileChangedException && error.recoveryPath != null) { + final recoveryPath = error.recoveryPath!; + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingDictionaryRecoveryConflict, + actionLabel: context.l10n.copyPath, + onAction: () => + unawaited(Clipboard.setData(ClipboardData(text: recoveryPath))), + duration: Duration.zero, + priority: BusyMarkToastPriority.high, + ); + return; + } + BusyMarkToastOverlay.show( + context, + message: context.l10n.commandUnavailableInContext, + priority: BusyMarkToastPriority.high, + ); +} + class _HistoryNumberRow extends StatelessWidget { const _HistoryNumberRow({ required this.title, @@ -440,22 +1174,17 @@ class _HistoryNumberRow extends StatelessWidget { @override Widget build(BuildContext context) { final values = {...choices, value}.toList()..sort(); - return BusyMarkActionRow( + return BusyMarkComboRow( title: title, + values: values, + selected: value, + labelFor: format, enabled: enabled, leading: const Icon(BusyMarkGlyphs.history), - trailing: DropdownButton( - value: value, - onChanged: enabled - ? (next) { - if (next != null) unawaited(onChanged(next)); - } - : null, - items: [ - for (final choice in values) - DropdownMenuItem(value: choice, child: Text(format(choice))), - ], - ), + tooltip: title, + onSelected: (next) { + if (next != value) unawaited(onChanged(next)); + }, ); } } @@ -505,23 +1234,41 @@ Future _editHistoryExcludedPaths( enum SettingsPage { appearance, editor, + spellingDictionaries, validation, history, ai, - window, privacy, - advanced, +} + +const _primarySettingsPages = [ + SettingsPage.appearance, + SettingsPage.editor, + SettingsPage.validation, + SettingsPage.history, + SettingsPage.ai, + SettingsPage.privacy, +]; + +SettingsPage _settingsNavigationSelection(SettingsPage page) { + return switch (page) { + SettingsPage.spellingDictionaries => SettingsPage.editor, + _ => page, + }; } SettingsPage settingsPageFromRouteValue(String? value) { return switch (value) { 'editor' => SettingsPage.editor, + 'spellingDictionaries' => SettingsPage.spellingDictionaries, 'validation' => SettingsPage.validation, 'history' => SettingsPage.history, 'ai' => SettingsPage.ai, - 'window' => SettingsPage.window, + // Preserve links to the former Window settings page. + 'window' => SettingsPage.history, 'privacy' => SettingsPage.privacy, - 'advanced' => SettingsPage.advanced, + // Preserve links to the former Advanced settings page. + 'advanced' => SettingsPage.history, _ => SettingsPage.appearance, }; } @@ -533,12 +1280,11 @@ String _settingsPageLabel(BuildContext context, SettingsPage page) { return switch (page) { SettingsPage.appearance => l10n.appearance, SettingsPage.editor => l10n.editor, + SettingsPage.spellingDictionaries => l10n.spellingDictionaries, SettingsPage.validation => l10n.validation, SettingsPage.history => l10n.settingsHistory, SettingsPage.ai => l10n.ai, - SettingsPage.window => l10n.settingsWindowSectionTitle, SettingsPage.privacy => l10n.privacy, - SettingsPage.advanced => l10n.advanced, }; } @@ -546,12 +1292,11 @@ IconData _settingsPageIcon(SettingsPage page) { return switch (page) { SettingsPage.appearance => BusyMarkGlyphs.appearance, SettingsPage.editor => BusyMarkGlyphs.editorView, + SettingsPage.spellingDictionaries => BusyMarkGlyphs.symbols, SettingsPage.validation => BusyMarkGlyphs.diagnostics, SettingsPage.history => BusyMarkGlyphs.documentHistory, SettingsPage.ai => BusyMarkGlyphs.ai, - SettingsPage.window => BusyMarkGlyphs.desktop, SettingsPage.privacy => BusyMarkGlyphs.privacy, - SettingsPage.advanced => BusyMarkGlyphs.settings, }; } @@ -566,7 +1311,7 @@ class _SettingsSidebar extends StatelessWidget { return BusyMarkSidebarSurface( child: BusyMarkSidebarNavigation( children: [ - for (final page in SettingsPage.values) + for (final page in _primarySettingsPages) BusyMarkSidebarNavigationTile( key: ValueKey('settings-navigation-${page.name}'), selected: page == selected, @@ -598,7 +1343,7 @@ class _SettingsPageSelector extends StatelessWidget { tooltip: _settingsPageLabel(context, selected), fallbackMenuWidth: BusyMarkSizes.languagePopupMaxWidth, items: [ - for (final page in SettingsPage.values) + for (final page in _primarySettingsPages) BusyMarkPopupMenuItem( value: page, label: _settingsPageLabel(context, page), diff --git a/lib/src/workspace/presentation/welcome_screen.dart b/lib/src/workspace/presentation/welcome_screen.dart index 52470890..32496f44 100644 --- a/lib/src/workspace/presentation/welcome_screen.dart +++ b/lib/src/workspace/presentation/welcome_screen.dart @@ -379,8 +379,10 @@ class _WelcomeScreenState extends ConsumerState { if (!safe) { return; } - await ref.read(workspaceControllerProvider.notifier).createMarkdownFile(); - if (mounted) { + final created = await ref + .read(workspaceControllerProvider.notifier) + .createMarkdownWorkspace(); + if (created && mounted) { context.go('/workspace'); } } diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index b3cfd02b..7efa3de5 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -35,6 +35,7 @@ import '../../app/command_registry.dart'; import '../../app/localization.dart'; import '../../app/window_control_service.dart'; import '../../core/busymark_exception.dart'; +import '../../core/atomic_file_writer.dart'; import '../../core/diagnostic.dart'; import '../../core/diagnostic_localizations.dart'; import '../../core/path_utils.dart' @@ -51,6 +52,7 @@ import '../../editor/document_surface.dart'; import '../../editor/document_text_geometry.dart'; import '../../editor/document_text_direction.dart'; import '../../editor/document_thematic_break.dart'; +import '../../editor/editor_text_context_menu.dart'; import '../../editor/markdown_image_view.dart'; import '../../editor/source/source_controller.dart'; import '../../editor/source/source_autocomplete.dart'; @@ -81,6 +83,11 @@ import '../../platform/linux_header_bar_service.dart'; import '../../platform/native_writerside_dialog_service.dart'; import '../../search/search_replace_service.dart'; import '../../search/workspace_search_scope.dart'; +import '../../spellcheck/spelling_session_controller.dart'; +import '../../spellcheck/spelling_projection.dart'; +import '../../spellcheck/spelling_coordinator.dart'; +import '../../spellcheck/spelling_language.dart'; +import '../../spellcheck/spelling_replacement.dart'; import '../../visualization/visualization_card.dart'; import '../../visualization/visualization_models.dart'; import '../../writerside/writerside_model.dart'; @@ -95,7 +102,7 @@ import '../../writerside/writerside_topic_removal_service.dart'; import '../../writerside/writerside_video.dart'; import '../workspace_controller.dart'; import '../document_buffer.dart'; -import 'document_format_indicator.dart'; +import 'document_status_bar.dart'; import '../text_format_metadata.dart'; import '../workspace_glyphs.dart'; import '../workspace_model.dart'; @@ -400,6 +407,7 @@ class _SidebarShortcutRequestController extends Notifier<_SidebarTab?> { class _OutlineNavigationTarget { const _OutlineNavigationTarget({ required this.workspaceId, + required this.bufferId, required this.filePath, required this.headingId, required this.line, @@ -407,6 +415,7 @@ class _OutlineNavigationTarget { }); final String workspaceId; + final String bufferId; final String? filePath; final String headingId; final int? line; @@ -416,6 +425,7 @@ class _OutlineNavigationTarget { class _OutlineViewportTarget { const _OutlineViewportTarget({ required this.workspaceId, + required this.bufferId, required this.filePath, required this.headingId, required this.sourceStartOffset, @@ -423,6 +433,7 @@ class _OutlineViewportTarget { }); final String workspaceId; + final String bufferId; final String? filePath; final String? headingId; final int? sourceStartOffset; @@ -430,6 +441,7 @@ class _OutlineViewportTarget { bool sameLocationAs(_OutlineViewportTarget other) { return workspaceId == other.workspaceId && + bufferId == other.bufferId && filePath == other.filePath && headingId == other.headingId && sourceStartOffset == other.sourceStartOffset && @@ -567,10 +579,8 @@ bool _workspaceSearchInputsChanged( if (previousWorkspace == null || nextWorkspace == null) { return previousWorkspace != nextWorkspace; } - final previousActivePath = - previousWorkspace.activeFilePath ?? previousWorkspace.markdown?.filePath; - final nextActivePath = - nextWorkspace.activeFilePath ?? nextWorkspace.markdown?.filePath; + final previousActivePath = previous.activeBuffer?.filePath; + final nextActivePath = next.activeBuffer?.filePath; return previousActivePath != nextActivePath || !_sameWorkspaceSearchFiles(previousWorkspace.files, nextWorkspace.files); } @@ -805,8 +815,8 @@ class WorkspaceScreen extends ConsumerWidget { }); } final title = state.isDirty - ? '*${_activeFileName(context, workspace)}' - : _activeFileName(context, workspace); + ? '*${_activeFileName(context, workspace, state.activeBuffer)}' + : _activeFileName(context, workspace, state.activeBuffer); final hasSidebar = _hasWorkspaceSidebar(workspace); final headerConfiguration = HeaderBarConfigurationDefaults.of(context) .copyWith( @@ -926,7 +936,11 @@ class WorkspaceScreen extends ConsumerWidget { onEscape: () => _closeSearch(ref), ) : _HeaderTitle( - title: _activeFileName(context, workspace), + title: _activeFileName( + context, + workspace, + state.activeBuffer, + ), subtitle: _workspaceKindLabel( context, workspace.kind, @@ -1018,7 +1032,12 @@ class WorkspaceScreen extends ConsumerWidget { ), body: Column( children: [ - if (state.message != null) + // The recovered document already has a review banner with + // actions. Keep other messages, including recovery damage. + if (state.message != null && + !(state.message!.code == + WorkspaceMessageCode.recoveryRestored && + state.activeBuffer?.recovered == true)) BusyMarkStatusBox( message: localizeWorkspaceMessage( context, @@ -1091,7 +1110,8 @@ class WorkspaceScreen extends ConsumerWidget { } void _selectSidebarShortcut(WidgetRef ref, _SidebarTab tab) { - final workspace = ref.read(workspaceControllerProvider).workspace; + final state = ref.read(workspaceControllerProvider); + final workspace = state.workspace; if (workspace == null || !_sidebarTabsFor(workspace.kind).contains(tab)) { return; } @@ -1221,15 +1241,16 @@ class WorkspaceScreen extends ConsumerWidget { } } - String _activeFileName(BuildContext context, Workspace workspace) { - final path = workspace.activeFilePath ?? workspace.markdown?.filePath; + String _activeFileName( + BuildContext context, + Workspace workspace, + DocumentBuffer? buffer, + ) { + final path = buffer?.filePath; if (path == null || path.isEmpty) { - return switch (workspace.kind) { - WorkspaceKind.markdownFolder || - WorkspaceKind.writersideModule => context.l10n.noOpenFile, - WorkspaceKind.untitledMarkdown || - WorkspaceKind.singleMarkdown => context.l10n.untitledMarkdownFileName, - }; + return buffer == null + ? context.l10n.noOpenFile + : context.l10n.untitledMarkdownFileName; } return p.basename(path); } @@ -1293,12 +1314,13 @@ class WorkspaceScreen extends ConsumerWidget { WidgetRef ref, _WorkspaceSearchResult result, ) async { - final workspace = ref.read(workspaceControllerProvider).workspace; + final state = ref.read(workspaceControllerProvider); + final workspace = state.workspace; final searchOptions = ref.read(_workspaceSearchProvider).options; if (workspace == null) { return; } - final activePath = workspace.activeFilePath ?? workspace.markdown?.filePath; + final activePath = state.activeBuffer?.filePath; if (activePath != result.filePath) { final opened = await ref .read(workspaceControllerProvider.notifier) @@ -2253,6 +2275,9 @@ class _SidebarState extends ConsumerState<_Sidebar> { ), _SidebarTab.outline => _OutlineTab( workspace: widget.workspace, + bufferId: ref + .watch(workspaceControllerProvider) + .activeBufferId, headings: widget.outline, ), _SidebarTab.git => GitSidebarTab( @@ -2320,9 +2345,13 @@ class _SidebarState extends ConsumerState<_Sidebar> { Future _refineActiveDocumentWithAi(BuildContext context) async { final state = ref.read(workspaceControllerProvider); final workspace = state.workspace; + final buffer = state.activeBuffer; if (workspace == null || - !(_activeWorkspaceDocumentKind(workspace)?.supportsAiMarkdownEditing ?? - false) || + buffer == null || + !resolveWorkspaceDocumentContext( + workspace, + buffer, + ).kind.supportsAiMarkdownEditing || state.activeText.isEmpty) { return; } @@ -9253,10 +9282,12 @@ Future _refineActiveSourceRangesWithAi( } final state = ref.read(workspaceControllerProvider); final workspace = state.workspace; - if (workspace == null) { + final buffer = state.activeBuffer; + if (workspace == null || buffer == null) { return false; } - final path = workspace.activeFilePath ?? workspace.markdown?.filePath; + final path = buffer.filePath; + final bufferId = buffer.id; final source = state.activeText; final start = requestedRange.fullDocument ? 0 : requestedRange.start; final end = requestedRange.fullDocument @@ -9276,7 +9307,7 @@ Future _refineActiveSourceRangesWithAi( sourceRevision: ref .read(workspaceControllerProvider.notifier) .editRevision, - targetId: path ?? 'untitled', + targetId: bufferId, documentPath: path, blockTargetAvailable: false, ), @@ -9299,6 +9330,7 @@ Future _refineActiveSourceRangesWithAi( !_isSameActiveDocument( ref.read(workspaceControllerProvider), workspaceId: workspace.id, + bufferId: bufferId, activePath: path, source: source, )) { @@ -9319,9 +9351,14 @@ Future _refineActiveSourceRangesWithAi( } class _OutlineTab extends ConsumerStatefulWidget { - const _OutlineTab({required this.workspace, required this.headings}); + const _OutlineTab({ + required this.workspace, + required this.bufferId, + required this.headings, + }); final Workspace workspace; + final String? bufferId; final List headings; @override @@ -9344,6 +9381,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { super.initState(); _outlineStateKey = _outlineStateSignature( widget.workspace, + widget.bufferId, widget.headings, ); _expandedNodeKeys = _initialExpandedOutlineNodeKeys(widget.headings); @@ -9352,7 +9390,11 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { @override void didUpdateWidget(covariant _OutlineTab oldWidget) { super.didUpdateWidget(oldWidget); - final nextKey = _outlineStateSignature(widget.workspace, widget.headings); + final nextKey = _outlineStateSignature( + widget.workspace, + widget.bufferId, + widget.headings, + ); if (nextKey != _outlineStateKey) { _outlineStateKey = nextKey; _expandedNodeKeys = _initialExpandedOutlineNodeKeys(widget.headings); @@ -9463,19 +9505,18 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { ) async { final initialState = ref.read(workspaceControllerProvider); final workspace = initialState.workspace; - if (workspace == null) { + final buffer = initialState.activeBuffer; + if (workspace == null || buffer == null) { return; } final workspaceId = workspace.id; - final activePath = workspace.activeFilePath ?? workspace.markdown?.filePath; - final source = initialState.activeText; - final mode = - workspace.markdown?.mode ?? - (workspace.kind == WorkspaceKind.writersideModule - ? MarkdownMode.writersideMarkdown - : MarkdownMode.commonMark); + final bufferId = buffer.id; + final documentContext = resolveWorkspaceDocumentContext(workspace, buffer); + final activePath = documentContext.diskPath; + final source = buffer.text; + final mode = documentContext.markdownMode; final parsed = await const MarkdownParser().parseAsync( - filePath: activePath ?? 'untitled.md', + filePath: documentContext.parserPath, source: source, mode: mode, workspaceRoot: workspace.rootPath, @@ -9485,6 +9526,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { !_isSameActiveDocument( ref.read(workspaceControllerProvider), workspaceId: workspaceId, + bufferId: bufferId, activePath: activePath, source: source, )) { @@ -9553,6 +9595,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { !_isSameActiveDocument( ref.read(workspaceControllerProvider), workspaceId: workspaceId, + bufferId: bufferId, activePath: activePath, source: source, )) { @@ -9577,6 +9620,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { final viewportTarget = ref.watch(_outlineViewportTargetProvider); final activeNodeKey = _activeVisibleOutlineNodeKey( workspace: widget.workspace, + bufferId: widget.bufferId, headings: headings, entries: entries, target: viewportTarget, @@ -9634,6 +9678,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { _setOutlineViewportTarget( ref, workspace: widget.workspace, + bufferId: widget.bufferId, heading: heading, ); ref @@ -9641,6 +9686,7 @@ class _OutlineTabState extends ConsumerState<_OutlineTab> { .set( _OutlineNavigationTarget( workspaceId: widget.workspace.id, + bufferId: widget.bufferId ?? '', filePath: widget.workspace.activeFilePath, headingId: heading.id, line: heading.sourceStartLine, @@ -9820,14 +9866,15 @@ int _resolveParsedOutlineHeadingIndex( bool _isSameActiveDocument( WorkspaceState state, { required String workspaceId, + required String bufferId, required String? activePath, required String source, }) { final workspace = state.workspace; return workspace?.id == workspaceId && - (workspace?.activeFilePath ?? workspace?.markdown?.filePath) == - activePath && - state.activeText == source; + state.activeBuffer?.id == bufferId && + state.activeBuffer?.filePath == activePath && + state.activeBuffer?.text == source; } Future _confirmDeleteOutlineSection( @@ -9863,6 +9910,7 @@ Future _confirmDeleteOutlineSection( void _setOutlineViewportTarget( WidgetRef ref, { required Workspace workspace, + required String? bufferId, required DocumentOutlineHeading? heading, }) { ref @@ -9870,7 +9918,8 @@ void _setOutlineViewportTarget( .set( _OutlineViewportTarget( workspaceId: workspace.id, - filePath: workspace.activeFilePath ?? workspace.markdown?.filePath, + bufferId: bufferId ?? '', + filePath: workspace.activeFilePath, headingId: heading?.id, sourceStartOffset: heading?.sourceStartOffset, editorBlockId: heading?.editorBlockId, @@ -9880,14 +9929,15 @@ void _setOutlineViewportTarget( String? _activeVisibleOutlineNodeKey({ required Workspace workspace, + required String? bufferId, required List headings, required List<_OutlineTreeEntry> entries, required _OutlineViewportTarget? target, }) { if (target == null || target.workspaceId != workspace.id || - target.filePath != - (workspace.activeFilePath ?? workspace.markdown?.filePath)) { + target.bufferId != bufferId || + target.filePath != workspace.activeFilePath) { return headings.isEmpty ? null : _outlineNodeKey(headings.first); } final targetIndex = _outlineViewportHeadingIndex(headings, target); @@ -9939,16 +9989,31 @@ List _activeDocumentOutline(WorkspaceState state) { final workspace = state.workspace; if (liveOutline != null && workspace != null && - liveOutline.matches(workspace, state.activeText)) { + liveOutline.matches(workspace, state.activeBuffer, state.activeText)) { return liveOutline.headings; } final preview = state.preview; if (preview != null) { return preview.outline; } + final buffer = state.activeBuffer; + final markdown = workspace?.markdown; + if (workspace == null || markdown == null) return const []; + if (buffer == null) { + if (state.documentBuffers.isNotEmpty) return const []; + return [ + for (final heading in markdown.headings) + DocumentOutlineHeading.fromMarkdown(heading), + ]; + } + final context = resolveWorkspaceDocumentContext(workspace, buffer); + if (!p.equals(markdown.filePath, context.parserPath) || + markdown.source != buffer.text || + markdown.mode != context.markdownMode) { + return const []; + } return [ - for (final heading - in state.workspace?.markdown?.headings ?? const []) + for (final heading in markdown.headings) DocumentOutlineHeading.fromMarkdown(heading), ]; } @@ -10056,11 +10121,13 @@ String _outlineNodeKey(DocumentOutlineHeading heading) { String _outlineStateSignature( Workspace workspace, + String? bufferId, List headings, ) { return [ workspace.id, - workspace.activeFilePath ?? workspace.markdown?.filePath ?? '', + bufferId ?? '', + workspace.activeFilePath ?? '', for (final heading in headings) [ heading.id, @@ -10166,6 +10233,7 @@ class _EditorTabStrip extends ConsumerWidget { } final colors = BusyMarkSurfaceColors.of(context); return DecoratedBox( + key: const ValueKey('editor-tab-strip'), decoration: BoxDecoration( color: colors.headerbarFlat, border: Border(bottom: BorderSide(color: colors.subtleBorder)), @@ -10208,12 +10276,6 @@ class _EditorTabStrip extends ConsumerWidget { itemCount: entries.length, ), ), - if (gitState.selectedDiffForDisplay == null && - localHistoryState.selectedRevision == null) - if (state.activeBuffer case final buffer?) ...[ - BusyMarkDocumentFormatIndicator(format: buffer.format), - const SizedBox(width: BusyMarkSpacing.xs), - ], ], ), ), @@ -11694,6 +11756,18 @@ class _EditorPreviewSplit extends ConsumerStatefulWidget { _EditorPreviewSplitState(); } +final class _SpellingBannerPresentation { + const _SpellingBannerPresentation({ + required this.title, + this.actionLabel, + this.onAction, + }); + + final String title; + final String? actionLabel; + final VoidCallback? onAction; +} + class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { final _previewScrollController = ItemScrollController(); final _previewItemPositionsListener = ItemPositionsListener.create(); @@ -11701,23 +11775,34 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { List<_PositionedOutlineHeading> _previewOutlineStops = const []; _SourceNavigationTarget? _lastSourceNavigationTarget; final _sourceEditorKey = GlobalKey(); + final _wysiwygEditorKey = GlobalKey(); + late final SpellingSessionController _spelling; final _previewBlockContexts = {}; String _lastPath = ''; var _previewSearchScrollRequest = 0; BusyDocument? _cachedWysiwygDocument; + String? _cachedWysiwygBufferId; String? _cachedWysiwygPath; String? _cachedWysiwygSource; + MarkdownMode? _cachedWysiwygMode; String? _wysiwygScrollHeadingId; String? _wysiwygScrollBlockId; String? _wysiwygSearchQuery; BusyMarkWysiwygSourceRange? _wysiwygSearchRange; var _wysiwygScrollRequest = 0; var _lastSearchNavigationRequest = 0; + String? _pendingSpellingInputIdentity; + SpellingSessionInput? _currentSpellingInput; @override void initState() { super.initState(); - _lastPath = widget.state.workspace?.activeFilePath ?? ''; + _spelling = ref.read(spellingSessionControllerProvider) + ..addListener(_handleSpellingChanged); + _spelling.synchronizeOpenBuffers( + widget.state.documentBuffers.map((buffer) => buffer.id), + ); + _lastPath = widget.state.activeBuffer?.filePath ?? ''; _previewItemPositionsListener.itemPositions.addListener( _handlePreviewVisibleItemsChanged, ); @@ -11728,17 +11813,48 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { _previewItemPositionsListener.itemPositions.removeListener( _handlePreviewVisibleItemsChanged, ); + _spelling.removeListener(_handleSpellingChanged); super.dispose(); } + void _handleSpellingChanged() { + if (mounted) setState(() {}); + } + @override void didUpdateWidget(covariant _EditorPreviewSplit oldWidget) { super.didUpdateWidget(oldWidget); - final path = widget.state.workspace?.activeFilePath ?? ''; - if (path != _lastPath) { + final previousBuffer = oldWidget.state.activeBuffer; + final nextBuffer = widget.state.activeBuffer; + if (previousBuffer != null && + nextBuffer != null && + previousBuffer.id == nextBuffer.id && + previousBuffer.text != nextBuffer.text) { + if (identical( + previousBuffer.editorState.undoState, + nextBuffer.editorState.undoState, + )) { + _spelling.invalidateBufferAnchors(nextBuffer.id); + } else { + _translateSpellingAnchors( + nextBuffer.text, + previousText: previousBuffer.text, + bufferId: nextBuffer.id, + ); + } + } + _spelling.synchronizeOpenBuffers( + widget.state.documentBuffers.map((buffer) => buffer.id), + ); + final path = widget.state.activeBuffer?.filePath ?? ''; + if (path != _lastPath || previousBuffer?.id != nextBuffer?.id) { _lastPath = path; _clearWysiwygCache(); _previewBlockContexts.clear(); + _outlineStopsPreview = null; + _previewOutlineStops = const []; + _previewSearchScrollRequest = 0; + _lastSearchNavigationRequest = 0; _wysiwygScrollHeadingId = null; _wysiwygScrollBlockId = null; _wysiwygSearchQuery = null; @@ -11795,7 +11911,12 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { if (!mounted || workspace == null) { return; } - _setOutlineViewportTarget(ref, workspace: workspace, heading: heading); + _setOutlineViewportTarget( + ref, + workspace: workspace, + bufferId: widget.state.activeBufferId, + heading: heading, + ); } @override @@ -11807,6 +11928,7 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { final workspace = widget.state.workspace; if (workspace == null || next.workspaceId != workspace.id || + next.bufferId != widget.state.activeBufferId || next.filePath != workspace.activeFilePath) { return; } @@ -11837,6 +11959,23 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { final sourceVisible = widget.viewMode != DocumentViewModePreference.preview && !wysiwygVisible; + final activeBuffer = widget.state.activeBuffer; + final documentKind = _activeDocumentKind(widget.state.workspace); + final spellingSupported = documentKind?.supportsSpelling ?? false; + if (activeBuffer != null) { + _scheduleSpelling( + SpellingSessionInput( + buffer: activeBuffer, + workspace: widget.state.workspace, + settings: settings, + documentKind: documentKind ?? DocumentKind.unknown, + markdownMode: _sourceMarkdownMode(widget.state.workspace), + richDocument: wysiwygVisible ? wysiwygDocument : null, + richDocumentGeneration: + _wysiwygEditorKey.currentState?.spellingDocumentGeneration ?? 0, + ), + ); + } final sourceTarget = ref.watch(_sourceNavigationTargetProvider); if (sourceVisible && sourceTarget != null && @@ -11878,7 +12017,17 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { ); final activeEditorPath = _activeEditorPath(); final searchState = ref.watch(_workspaceSearchProvider); - final activeBuffer = widget.state.activeBuffer; + final spellingBannerPresentation = + activeBuffer != null && + spellingSupported && + settings.automaticSpelling && + activeBuffer.editorState.spellingLanguage.kind != + SpellingLanguageOverrideKind.disabled + ? _spellingBannerPresentation(context) + : null; + final spellingLabel = activeBuffer != null && spellingSupported + ? _spellingStatusLabel(context, activeBuffer, settings) + : null; return DecoratedBox( decoration: BoxDecoration(color: colors.view), child: Column( @@ -11927,337 +12076,463 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { ), onSaveAs: () => unawaited(saveActiveToNewLocation(context, ref)), ), + if (activeBuffer != null) + BusyMarkBanner( + key: const ValueKey('spelling-banner'), + title: spellingBannerPresentation?.title ?? '', + actionLabel: spellingBannerPresentation?.actionLabel, + onAction: spellingBannerPresentation?.onAction, + revealed: spellingBannerPresentation != null, + ), Expanded( - child: Row( + child: Stack( children: [ - if (wysiwygVisible) - Expanded( - key: const ValueKey('document-wysiwyg-pane'), - child: BusyMarkWysiwygEditor( - document: wysiwygDocument, - documentId: activeBuffer?.id, - clipboardInsertionRegistry: ref.read( - clipboardInsertionRegistryProvider, - ), - onClipboardCaptured: ref - .read(clipboardHistoryControllerProvider.notifier) - .retain, - initialSessionState: - activeBuffer?.editorState.wysiwygState ?? - const WysiwygEditorSessionState(), - useExternalUndoHistory: true, - onSessionChanged: (documentId, session) { - final latest = ref - .read(workspaceControllerProvider) - .documentBuffers - .where((buffer) => buffer.id == documentId) - .firstOrNull; - if (latest == null || - _sameWysiwygSession( - latest.editorState.wysiwygState, - session, - )) { - return; - } - ref - .read(workspaceControllerProvider.notifier) - .updateDocumentEditorState( - documentId, - latest.editorState.copyWith( - wysiwygState: session, - ), - ); - }, - headerBarService: headerBar, - workspaceRoot: _imageWorkspaceRoot( - widget.state.workspace, - ), - writersideRoot: - widget.state.workspace?.writersideModule?.rootPath, - imagesDir: - widget - .state - .workspace - ?.writersideModule - ?.effectiveImagesDir ?? - 'images', - assetWorkspaceKind: - switch (widget.state.workspace?.kind) { - WorkspaceKind.writersideModule => - AssetWorkspaceKind.writerside, - WorkspaceKind.markdownFolder => - AssetWorkspaceKind.markdownWorkspace, - WorkspaceKind.singleMarkdown => - AssetWorkspaceKind.standalone, - WorkspaceKind.untitledMarkdown || - null => AssetWorkspaceKind.standalone, - }, - onAssetSaveRequired: () => - unawaited(saveActiveToNewLocation(context, ref)), - allowRemoteImages: allowRemoteImages, - onRemoteImageBlocked: () => - unawaited(_showRemoteImagesPrompt(context, ref)), - onDocumentChanged: _cacheWysiwygDocument, - onSourceChanged: _handleWysiwygSourceChanged, - onTransactionalSourceChanged: _handleWysiwygSourceChanged, - toolbarPlacement: widget.editorToolbarPlacement, - toolbarDirection: widget.editorToolbarDirection, - onToolbarPlacementChanged: ref - .read(appSettingsControllerProvider.notifier) - .setEditorToolbarPlacement, - onToolbarDirectionChanged: ref - .read(appSettingsControllerProvider.notifier) - .setEditorToolbarDirection, - scrollToHeadingId: _wysiwygScrollHeadingId, - scrollToBlockId: _wysiwygScrollBlockId, - scrollToSearchQuery: _wysiwygSearchQuery, - scrollToSourceRange: _wysiwygSearchRange, - scrollRequest: _wysiwygScrollRequest, - onVisibleHeadingChanged: - _handleWysiwygVisibleHeadingChanged, - documentLayout: standaloneDocumentLayout, - visualizationRevision: ref - .read(workspaceControllerProvider.notifier) - .editRevision, - onOpenSearch: () => ref - .read(workspaceSearchOpenRequestProvider.notifier) - .request(), - onCloseSearch: () => ref - .read(workspaceSearchCloseRequestProvider.notifier) - .request(), - onUndo: () => ref - .read(workspaceControllerProvider.notifier) - .undoActiveBuffer(), - onRedo: () => ref - .read(workspaceControllerProvider.notifier) - .redoActiveBuffer(), - onAiEdit: - (_activeDocumentKind( - widget.state.workspace, - )?.supportsAiMarkdownEditing ?? - false) - ? (snapshot) => - showBusyMarkAiEdit(context, ref, snapshot) - : null, - onMathDiagnostic: (expressionId, code, sourceSpan) => ref - .read(workspaceControllerProvider.notifier) - .updateMathRenderDiagnostic( - expressionId: expressionId, - code: code, - sourceSpan: sourceSpan, - expectedRevision: activeBuffer?.revision, - expectedFilePath: activeBuffer?.filePath, - ), - ), - ), - if (sourceVisible) - Expanded( - key: const ValueKey('document-source-pane'), - child: BusyMarkSourceEditor( - key: _sourceEditorKey, - text: widget.state.activeText, - language: _sourceSyntaxLanguage(widget.state.workspace), - filePath: activeEditorPath, - documentId: activeBuffer?.id, - clipboardInsertionRegistry: ref.read( - clipboardInsertionRegistryProvider, - ), - onClipboardCaptured: ref - .read(clipboardHistoryControllerProvider.notifier) - .retain, - workspaceRoot: _imageWorkspaceRoot( - widget.state.workspace, - ), - writersideRoot: - widget.state.workspace?.writersideModule?.rootPath, - imagesDir: - widget - .state - .workspace - ?.writersideModule - ?.effectiveImagesDir ?? - 'images', - assetWorkspaceKind: - switch (widget.state.workspace?.kind) { - WorkspaceKind.writersideModule => - AssetWorkspaceKind.writerside, - WorkspaceKind.markdownFolder => - AssetWorkspaceKind.markdownWorkspace, - WorkspaceKind.singleMarkdown => - AssetWorkspaceKind.standalone, - WorkspaceKind.untitledMarkdown || - null => AssetWorkspaceKind.standalone, - }, - onAssetSaveRequired: () => - unawaited(saveActiveToNewLocation(context, ref)), - diagnostics: - widget.state.workspace?.allDiagnostics ?? - const [], - onSymbolAction: - widget.state.workspace?.writersideProject == null - ? null - : (action, offset) => - unawaited(_handleSymbolAction(action, offset)), - autocompleteContext: _sourceAutocompleteContext( - widget.state.workspace, - ), - editorFontSize: widget.editorFontSize, - wordWrap: widget.wordWrap, - searchActive: searchState.active, - searchOptions: searchState.options, - searchReplacement: - activeBuffer?.editorState.searchReplacement ?? '', - onSearchReplacementChanged: activeBuffer == null - ? null - : (replacement) { - final latest = ref - .read(workspaceControllerProvider) - .documentBuffers - .where( - (candidate) => - candidate.id == activeBuffer.id, - ) - .firstOrNull; - if (latest != null) { - ref - .read(workspaceControllerProvider.notifier) - .updateDocumentEditorState( - latest.id, - latest.editorState.copyWith( - searchReplacement: replacement, - ), - ); - } - }, - onSearchOptionsChanged: (options) { - final current = ref.read(_workspaceSearchProvider); - ref - .read(_workspaceSearchProvider.notifier) - .set(current.withOptions(options)); - }, - initialSelection: activeBuffer?.editorState.selection, - initialScrollOffset: - activeBuffer?.editorState.scrollOffset ?? 0, - initialFoldedRegionKeys: - activeBuffer?.editorState.foldedRegionKeys ?? - const {}, - onSessionChanged: activeBuffer == null - ? null - : (selection, scrollOffset, foldedRegionKeys) { + Positioned.fill( + child: Row( + children: [ + if (wysiwygVisible) + Expanded( + key: const ValueKey('document-wysiwyg-pane'), + child: BusyMarkWysiwygEditor( + key: _wysiwygEditorKey, + document: wysiwygDocument, + documentId: activeBuffer?.id, + contentRevision: activeBuffer?.revision, + spellingAnnotations: _spelling.annotations, + onCheckSpelling: () => + unawaited(_openSpellingReview()), + readSpellingMenuItems: _prepareRichSpellingMenu, + clipboardInsertionRegistry: ref.read( + clipboardInsertionRegistryProvider, + ), + onClipboardCaptured: ref + .read( + clipboardHistoryControllerProvider.notifier, + ) + .retain, + initialSessionState: + activeBuffer?.editorState.wysiwygState ?? + const WysiwygEditorSessionState(), + useExternalUndoHistory: true, + onSessionChanged: (documentId, session) { final latest = ref .read(workspaceControllerProvider) .documentBuffers - .where( - (candidate) => - candidate.id == activeBuffer.id, - ) + .where((buffer) => buffer.id == documentId) .firstOrNull; if (latest == null || - _sameSourceSession( - latest.editorState, - selection, - scrollOffset, - foldedRegionKeys, + _sameWysiwygSession( + latest.editorState.wysiwygState, + session, )) { return; } ref .read(workspaceControllerProvider.notifier) .updateDocumentEditorState( - latest.id, + documentId, latest.editorState.copyWith( - selection: selection, - scrollOffset: scrollOffset, - foldedRegionKeys: foldedRegionKeys, + wysiwygState: session, ), ); }, - onOpenSearch: () => ref - .read(workspaceSearchOpenRequestProvider.notifier) - .request(), - onCloseSearch: () => ref - .read(workspaceSearchCloseRequestProvider.notifier) - .request(), - onVisibleLineChanged: _handleSourceVisibleLineChanged, - onChanged: _handleSourceChanged, - onTransactionalChanged: _handleTransactionalSourceChanged, - onUndo: () { - final controller = ref.read( - workspaceControllerProvider.notifier, - ); - if (!controller.undoActiveBuffer()) { - return null; - } - final buffer = ref - .read(workspaceControllerProvider) - .activeBuffer; - return buffer == null - ? null - : TextEditingValue( - text: buffer.text, - selection: buffer.editorState.selection, + headerBarService: headerBar, + workspaceRoot: _imageWorkspaceRoot( + widget.state.workspace, + ), + writersideRoot: widget + .state + .workspace + ?.writersideModule + ?.rootPath, + imagesDir: + widget + .state + .workspace + ?.writersideModule + ?.effectiveImagesDir ?? + 'images', + assetWorkspaceKind: + switch (widget.state.workspace?.kind) { + WorkspaceKind.writersideModule => + AssetWorkspaceKind.writerside, + WorkspaceKind.markdownFolder => + AssetWorkspaceKind.markdownWorkspace, + WorkspaceKind.singleMarkdown => + AssetWorkspaceKind.standalone, + WorkspaceKind.untitledMarkdown || + null => AssetWorkspaceKind.standalone, + }, + onAssetSaveRequired: () => unawaited( + saveActiveToNewLocation(context, ref), + ), + allowRemoteImages: allowRemoteImages, + onRemoteImageBlocked: () => unawaited( + _showRemoteImagesPrompt(context, ref), + ), + onDocumentChanged: (document) => + _cacheWysiwygDocument( + activeBuffer?.id, + document, + ), + onSourceChanged: (filePath, value) => + _handleWysiwygSourceChanged( + activeBuffer?.id, + filePath, + value, + ), + onTransactionalSourceChanged: + (filePath, value, [undoGroup]) => + _handleWysiwygSourceChanged( + activeBuffer?.id, + filePath, + value, + undoGroup, + ), + onSpellingSourceChanged: + (filePath, value, before, after) => + _handleWysiwygSpellingSourceChanged( + activeBuffer?.id, + filePath, + value, + before, + after, + ), + toolbarPlacement: widget.editorToolbarPlacement, + toolbarDirection: widget.editorToolbarDirection, + onToolbarPlacementChanged: ref + .read(appSettingsControllerProvider.notifier) + .setEditorToolbarPlacement, + onToolbarDirectionChanged: ref + .read(appSettingsControllerProvider.notifier) + .setEditorToolbarDirection, + scrollToHeadingId: _wysiwygScrollHeadingId, + scrollToBlockId: _wysiwygScrollBlockId, + scrollToSearchQuery: _wysiwygSearchQuery, + scrollToSourceRange: _wysiwygSearchRange, + scrollRequest: _wysiwygScrollRequest, + onVisibleHeadingChanged: + _handleWysiwygVisibleHeadingChanged, + documentLayout: standaloneDocumentLayout, + visualizationRevision: ref + .read(workspaceControllerProvider.notifier) + .editRevision, + onOpenSearch: () => ref + .read( + workspaceSearchOpenRequestProvider.notifier, + ) + .request(), + onCloseSearch: () => ref + .read( + workspaceSearchCloseRequestProvider.notifier, + ) + .request(), + onUndo: () => ref + .read(workspaceControllerProvider.notifier) + .undoActiveBuffer(), + onRedo: () => ref + .read(workspaceControllerProvider.notifier) + .redoActiveBuffer(), + onAiEdit: + (_activeDocumentKind( + widget.state.workspace, + )?.supportsAiMarkdownEditing ?? + false) + ? (snapshot) => + showBusyMarkAiEdit(context, ref, snapshot) + : null, + onMathDiagnostic: + (expressionId, code, sourceSpan) => ref + .read(workspaceControllerProvider.notifier) + .updateMathRenderDiagnostic( + expressionId: expressionId, + code: code, + sourceSpan: sourceSpan, + expectedRevision: activeBuffer?.revision, + expectedFilePath: activeBuffer?.filePath, + ), + ), + ), + if (sourceVisible) + Expanded( + key: const ValueKey('document-source-pane'), + child: BusyMarkSourceEditor( + key: _sourceEditorKey, + text: widget.state.activeText, + language: _sourceSyntaxLanguage( + widget.state.workspace, + ), + documentFormat: _sourceDocumentFormat( + widget.state.workspace, + ), + markdownMode: _sourceMarkdownMode( + widget.state.workspace, + ), + filePath: activeEditorPath, + documentId: activeBuffer?.id, + clipboardInsertionRegistry: ref.read( + clipboardInsertionRegistryProvider, + ), + onClipboardCaptured: ref + .read( + clipboardHistoryControllerProvider.notifier, + ) + .retain, + workspaceRoot: _imageWorkspaceRoot( + widget.state.workspace, + ), + writersideRoot: widget + .state + .workspace + ?.writersideModule + ?.rootPath, + imagesDir: + widget + .state + .workspace + ?.writersideModule + ?.effectiveImagesDir ?? + 'images', + assetWorkspaceKind: + switch (widget.state.workspace?.kind) { + WorkspaceKind.writersideModule => + AssetWorkspaceKind.writerside, + WorkspaceKind.markdownFolder => + AssetWorkspaceKind.markdownWorkspace, + WorkspaceKind.singleMarkdown => + AssetWorkspaceKind.standalone, + WorkspaceKind.untitledMarkdown || + null => AssetWorkspaceKind.standalone, + }, + onAssetSaveRequired: () => unawaited( + saveActiveToNewLocation(context, ref), + ), + spellingAnnotations: _spelling.annotations, + onCheckSpelling: () => + unawaited(_openSpellingReview()), + readSpellingMenuItems: _prepareSourceSpellingMenu, + diagnostics: + widget.state.workspace?.allDiagnostics ?? + const [], + onSymbolAction: + widget.state.workspace?.writersideProject == + null + ? null + : (action, offset) => unawaited( + _handleSymbolAction(action, offset), + ), + autocompleteContext: _sourceAutocompleteContext( + widget.state.workspace, + ), + editorFontSize: widget.editorFontSize, + wordWrap: widget.wordWrap, + searchActive: searchState.active, + searchOptions: searchState.options, + searchReplacement: + activeBuffer?.editorState.searchReplacement ?? + '', + onSearchReplacementChanged: activeBuffer == null + ? null + : (replacement) { + final latest = ref + .read(workspaceControllerProvider) + .documentBuffers + .where( + (candidate) => + candidate.id == activeBuffer.id, + ) + .firstOrNull; + if (latest != null) { + ref + .read( + workspaceControllerProvider + .notifier, + ) + .updateDocumentEditorState( + latest.id, + latest.editorState.copyWith( + searchReplacement: replacement, + ), + ); + } + }, + onSearchOptionsChanged: (options) { + final current = ref.read( + _workspaceSearchProvider, ); - }, - onRedo: () { - final controller = ref.read( - workspaceControllerProvider.notifier, - ); - if (!controller.redoActiveBuffer()) { - return null; - } - final buffer = ref - .read(workspaceControllerProvider) - .activeBuffer; - return buffer == null - ? null - : TextEditingValue( - text: buffer.text, - selection: buffer.editorState.selection, + ref + .read(_workspaceSearchProvider.notifier) + .set(current.withOptions(options)); + }, + initialSelection: + activeBuffer?.editorState.selection, + initialScrollOffset: + activeBuffer?.editorState.scrollOffset ?? 0, + initialFoldedRegionKeys: + activeBuffer?.editorState.foldedRegionKeys ?? + const {}, + onSessionChanged: activeBuffer == null + ? null + : (selection, scrollOffset, foldedRegionKeys) { + final latest = ref + .read(workspaceControllerProvider) + .documentBuffers + .where( + (candidate) => + candidate.id == activeBuffer.id, + ) + .firstOrNull; + if (latest == null || + _sameSourceSession( + latest.editorState, + selection, + scrollOffset, + foldedRegionKeys, + )) { + return; + } + ref + .read( + workspaceControllerProvider.notifier, + ) + .updateDocumentEditorState( + latest.id, + latest.editorState.copyWith( + selection: selection, + scrollOffset: scrollOffset, + foldedRegionKeys: foldedRegionKeys, + ), + ); + }, + onOpenSearch: () => ref + .read( + workspaceSearchOpenRequestProvider.notifier, + ) + .request(), + onCloseSearch: () => ref + .read( + workspaceSearchCloseRequestProvider.notifier, + ) + .request(), + onVisibleLineChanged: + _handleSourceVisibleLineChanged, + onChanged: (value, sourceFilePath) => + _handleSourceChanged( + activeBuffer?.id, + value, + sourceFilePath, + ), + onTransactionalChanged: + ( + value, + sourceFilePath, + previousSelection, + selection, + undoGroup, + ) => _handleTransactionalSourceChanged( + activeBuffer?.id, + value, + sourceFilePath, + previousSelection, + selection, + undoGroup, + ), + onUndo: () { + final controller = ref.read( + workspaceControllerProvider.notifier, ); - }, - editRevision: ref - .read(workspaceControllerProvider.notifier) - .editRevision, - onAiEdit: - (_activeDocumentKind( - widget.state.workspace, - )?.supportsAiMarkdownEditing ?? - false) - ? (snapshot) => - showBusyMarkAiEdit(context, ref, snapshot) - : null, - ), - ), - if (sourceVisible && previewVisible) - VerticalDivider( - width: BusyMarkStroke.hairline, - color: colors.subtleBorder, - ), - if (previewVisible) - Expanded( - key: const ValueKey('document-preview-pane'), - child: _PreviewPane( - preview: widget.state.preview, - workspace: widget.state.workspace, - activeSource: widget.state.activeText, - editRevision: ref - .read(workspaceControllerProvider.notifier) - .editRevision, - visualizationsEnabled: true, - onVisualizationDiagnostic: _openVisualizationSourceLine, - onEditVisualizationSource: _openVisualizationSourceLine, - controller: _previewScrollController, - itemPositionsListener: _previewItemPositionsListener, - onBlockContextAvailable: _rememberPreviewBlockContext, - onBlockContextUnavailable: _forgetPreviewBlockContext, - documentLayout: sourceVisible - ? BusyMarkDocumentLayoutSpec.splitPreview - : standaloneDocumentLayout, - ), + if (!controller.undoActiveBuffer()) { + return null; + } + final buffer = ref + .read(workspaceControllerProvider) + .activeBuffer; + return buffer == null + ? null + : TextEditingValue( + text: buffer.text, + selection: buffer.editorState.selection, + ); + }, + onRedo: () { + final controller = ref.read( + workspaceControllerProvider.notifier, + ); + if (!controller.redoActiveBuffer()) { + return null; + } + final buffer = ref + .read(workspaceControllerProvider) + .activeBuffer; + return buffer == null + ? null + : TextEditingValue( + text: buffer.text, + selection: buffer.editorState.selection, + ); + }, + editRevision: ref + .read(workspaceControllerProvider.notifier) + .editRevision, + onAiEdit: + (_activeDocumentKind( + widget.state.workspace, + )?.supportsAiMarkdownEditing ?? + false) + ? (snapshot) => + showBusyMarkAiEdit(context, ref, snapshot) + : null, + ), + ), + if (sourceVisible && previewVisible) + VerticalDivider( + width: BusyMarkStroke.hairline, + color: colors.subtleBorder, + ), + if (previewVisible) + Expanded( + key: const ValueKey('document-preview-pane'), + child: _PreviewPane( + preview: widget.state.preview, + workspace: widget.state.workspace, + activeSource: widget.state.activeText, + editRevision: ref + .read(workspaceControllerProvider.notifier) + .editRevision, + visualizationsEnabled: true, + onVisualizationDiagnostic: + _openVisualizationSourceLine, + onEditVisualizationSource: + _openVisualizationSourceLine, + controller: _previewScrollController, + itemPositionsListener: + _previewItemPositionsListener, + onBlockContextAvailable: + _rememberPreviewBlockContext, + onBlockContextUnavailable: + _forgetPreviewBlockContext, + documentLayout: sourceVisible + ? BusyMarkDocumentLayoutSpec.splitPreview + : standaloneDocumentLayout, + ), + ), + ], ), + ), ], ), ), + if (activeBuffer != null) + BusyMarkDocumentStatusBar( + format: activeBuffer.format, + spellingLabel: spellingLabel, + spellingTooltip: spellingSupported + ? context.l10n.chooseSpellingLanguage + : null, + onSpellingPressed: spellingSupported + ? () => unawaited(_chooseDocumentSpellingLanguage()) + : null, + ), ], ), ); @@ -12372,24 +12647,15 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { } } - void _handleSourceChanged(String value, String? sourceFilePath) { - final activePath = _activeEditorPath(); - if (sourceFilePath != null && sourceFilePath != activePath) { - return; - } - _clearWysiwygCache(); - ref - .read(workspaceControllerProvider.notifier) - .updateActiveText(value, sourceFilePath: sourceFilePath ?? activePath); - } - - void _handleTransactionalSourceChanged( + void _handleSourceChanged( + String? expectedBufferId, String value, String? sourceFilePath, - TextSelection previousSelection, - TextSelection selection, - String? undoGroup, ) { + if (expectedBufferId == null || + widget.state.activeBuffer?.id != expectedBufferId) { + return; + } final activePath = _activeEditorPath(); if (sourceFilePath != null && sourceFilePath != activePath) { return; @@ -12397,54 +12663,775 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { _clearWysiwygCache(); ref .read(workspaceControllerProvider.notifier) - .updateActiveSourceText( + .updateActiveText( value, + sourceBufferId: expectedBufferId, sourceFilePath: sourceFilePath ?? activePath, - previousSelection: previousSelection, - selection: selection, - undoGroup: undoGroup, ); } - void _handleWysiwygSourceChanged( - String filePath, - String value, [ - String? undoGroup, - ]) { - if (filePath != _activeEditorPath()) { + void _scheduleSpelling(SpellingSessionInput input) { + if (_pendingSpellingInputIdentity == input.identity) return; + _pendingSpellingInputIdentity = input.identity; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted || _pendingSpellingInputIdentity != input.identity) return; + _pendingSpellingInputIdentity = null; + final currentInput = input.withRichDocumentGeneration( + _wysiwygEditorKey.currentState?.spellingDocumentGeneration ?? + input.richDocumentGeneration, + ); + _currentSpellingInput = currentInput; + _spelling.update(currentInput); + }); + } + + Future _openSpellingReview() async { + var input = _currentSpellingInput; + if (input == null) return; + if (input.buffer.editorState.spellingLanguage.kind == + SpellingLanguageOverrideKind.disabled) { + if (!await _chooseDocumentSpellingLanguage()) return; + await WidgetsBinding.instance.endOfFrame; + if (!mounted) return; + input = _currentSpellingInput; + if (input == null) return; + } + await _spelling.checkNow( + input.withRichDocumentGeneration( + _wysiwygEditorKey.currentState?.spellingDocumentGeneration ?? + input.richDocumentGeneration, + ), + ); + if (!mounted) return; + final state = _spelling.state; + if (state.status == SpellingPresentationStatus.languageRequired) { + _spelling.endManualReview(); + if (await _chooseDocumentSpellingLanguage()) { + await WidgetsBinding.instance.endOfFrame; + if (mounted) unawaited(_openSpellingReview()); + } return; } - final document = _cachedWysiwygDocument; - final controller = ref.read(workspaceControllerProvider.notifier); - if (document == null || - document.filePath != filePath || - document.source != value) { - controller.updateActiveText(value, sourceFilePath: filePath); + if (state.status == SpellingPresentationStatus.dictionaryUnavailable) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingDictionaryUnavailable, + priority: BusyMarkToastPriority.high, + ); + _spelling.endManualReview(); return; } - controller.updateActiveWysiwygText( - value, - document: document, - sourceFilePath: filePath, - undoGroup: undoGroup, - ); + if (state.status == SpellingPresentationStatus.dictionaryNotInstalled) { + final languageId = state.message; + _spelling.endManualReview(); + if (languageId != null && + await _offerDocumentDictionaryInstall(languageId)) { + await WidgetsBinding.instance.endOfFrame; + if (mounted) unawaited(_openSpellingReview()); + } + return; + } + if (state.status == SpellingPresentationStatus.failure) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingCheckFailed, + priority: BusyMarkToastPriority.high, + ); + _spelling.endManualReview(); + return; + } + if (!state.complete && + state.status != SpellingPresentationStatus.checking) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingCheckIncomplete, + priority: BusyMarkToastPriority.high, + ); + _spelling.endManualReview(); + return; + } + if (state.occurrences.isEmpty && state.complete) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.noSpellingErrors, + ); + _spelling.endManualReview(); + return; + } + var initialIndex = 0; + if (input.richDocument != null) { + initialIndex = + _wysiwygEditorKey.currentState?.spellingReviewStartIndex( + _spelling.misspellings, + ) ?? + 0; + } else { + final caret = _sourceEditorKey.currentState?.spellingCaretOffset ?? 0; + final afterCaret = _spelling.misspellings.indexWhere( + (occurrence) => (occurrence.sourceStart ?? -1) >= caret, + ); + if (afterCaret >= 0) initialIndex = afterCaret; + } + var reopenForLanguage = false; + try { + if (_spelling.misspellings.isNotEmpty) { + _revealSpellingOccurrence(_spelling.misspellings[initialIndex]); + } + reopenForLanguage = + await showBusyMarkModalDialog( + context, + builder: (context) => BusyMarkSpellingReviewDialog( + spelling: _spelling, + initialIndex: initialIndex, + onReveal: _revealSpellingOccurrence, + onCorrect: _applySpellingCorrection, + onChooseLanguage: _chooseDocumentSpellingLanguage, + ), + ) ?? + false; + } finally { + _spelling.endManualReview(); + _restoreActiveEditorFocus(); + } + if (reopenForLanguage) { + await WidgetsBinding.instance.endOfFrame; + if (mounted) unawaited(_openSpellingReview()); + } } - void _cacheWysiwygDocument(BusyDocument document) { - _cachedWysiwygDocument = document; - _cachedWysiwygPath = document.filePath; - _cachedWysiwygSource = document.source; + _SpellingBannerPresentation? _spellingBannerPresentation( + BuildContext context, + ) { + final state = _spelling.state; + switch (state.status) { + case SpellingPresentationStatus.languageRequired: + return null; + case SpellingPresentationStatus.dictionaryNotInstalled: + final languageId = state.message; + final resource = languageId == null + ? null + : _spelling.catalog?.availableById(languageId); + final installStatus = _spelling.dictionaryInstallStatus; + final installing = + resource != null && + installStatus?.resourceId == resource.resourceId && + installStatus?.phase != SpellingDictionaryInstallPhase.failed; + return _SpellingBannerPresentation( + title: resource == null + ? context.l10n.spellingDictionaryNotInstalled + : context.l10n.spellingDictionaryNotInstalledForLanguage( + resource.label, + ), + actionLabel: context.l10n.installSpellingDictionary, + onAction: languageId == null || resource == null || installing + ? null + : () => unawaited(_installDocumentDictionary(languageId)), + ); + case SpellingPresentationStatus.dictionaryUnavailable: + return _SpellingBannerPresentation( + title: context.l10n.spellingDictionaryUnavailable, + actionLabel: context.l10n.chooseSpellingLanguage, + onAction: () => unawaited(_chooseDocumentSpellingLanguage()), + ); + case SpellingPresentationStatus.checking: + case SpellingPresentationStatus.ready: + case SpellingPresentationStatus.disabled: + return null; + case SpellingPresentationStatus.failure: + return _SpellingBannerPresentation( + title: context.l10n.spellingCheckFailed, + ); + case SpellingPresentationStatus.incomplete: + return _SpellingBannerPresentation( + title: context.l10n.spellingCheckIncomplete, + ); + } + } + + String _spellingStatusLabel( + BuildContext context, + DocumentBuffer buffer, + AppSettings settings, + ) { + final override = buffer.editorState.spellingLanguage; + if (!settings.automaticSpelling || + override.kind == SpellingLanguageOverrideKind.disabled) { + return context.l10n.spellingOffStatus; + } + final languageId = resolveSpellingLanguageId( + override: override, + projectLanguage: _spelling.projectWords.projectLanguage, + defaultLanguage: settings.defaultSpellingLanguage, + ); + if (languageId == null) { + return context.l10n.spellingLanguageUnsetStatus; + } + return _spelling.catalog?.byId(languageId)?.label ?? languageId; + } + + void _revealSpellingOccurrence(SpellingOccurrence occurrence) { + if (occurrence.run.target is SpellingSourceTarget) { + final sourceEditor = _sourceEditorKey.currentState; + if (sourceEditor != null) { + sourceEditor.revealSpellingOccurrence(occurrence); + } else { + unawaited(_revealSourceSpellingOccurrence(occurrence)); + } + } else { + _wysiwygEditorKey.currentState?.revealSpellingOccurrence(occurrence); + } + } + + Future _revealSourceSpellingOccurrence( + SpellingOccurrence occurrence, + ) async { + final bufferId = occurrence.run.snapshot.bufferId; + await ref + .read(appSettingsControllerProvider.notifier) + .setDocumentViewMode(DocumentViewModePreference.source); + await WidgetsBinding.instance.endOfFrame; + if (!mounted || + ref.read(workspaceControllerProvider).activeBuffer?.id != bufferId || + !_spelling.isCurrent(occurrence)) { + return; + } + _sourceEditorKey.currentState?.revealSpellingOccurrence(occurrence); + } + + Future _applySpellingCorrection( + SpellingOccurrence occurrence, + String suggestion, + ) async { + if (!_spelling.isCurrent(occurrence)) return null; + final sourceEditor = _sourceEditorKey.currentState; + final richEditor = _wysiwygEditorKey.currentState; + final source = occurrence.run.target is SpellingSourceTarget + ? sourceEditor?.spellingSourceSnapshot(occurrence) + : null; + final field = occurrence.run.target is SpellingSourceTarget + ? null + : richEditor?.spellingFieldSnapshot(occurrence); + if (source == null && field == null) return null; + try { + final prepared = await prepareSpellingCorrection( + occurrence: occurrence, + suggestion: suggestion, + source: source, + field: field, + ); + if (!mounted || !_spelling.isCurrent(occurrence)) return null; + final beforeBuffer = ref.read(workspaceControllerProvider).activeBuffer; + if (beforeBuffer == null || + beforeBuffer.id != occurrence.run.snapshot.bufferId || + beforeBuffer.revision != occurrence.run.snapshot.contentRevision) { + return null; + } + final plan = prepared.plan; + final applied = occurrence.run.target is SpellingSourceTarget + ? sourceEditor?.applyPreparedSpellingCorrection( + occurrence: occurrence, + plan: plan, + expectedSource: source!, + replacementSource: prepared.replacementSource!, + ) ?? + false + : richEditor?.applyPreparedSpellingCorrection( + occurrence: occurrence, + suggestion: suggestion, + plan: plan, + expectedFieldText: field!, + preparedFieldText: prepared.replacementField, + ) ?? + false; + if (!applied) return null; + final afterBuffer = ref.read(workspaceControllerProvider).activeBuffer; + if (afterBuffer == null || + afterBuffer.id != beforeBuffer.id || + afterBuffer.revision != beforeBuffer.revision + 1 || + afterBuffer.text == beforeBuffer.text) { + return null; + } + final sourceStart = occurrence.sourceStart; + final sourceEnd = occurrence.sourceEnd; + if (sourceStart != null && sourceEnd != null) { + final committed = busyMarkMinimalSourceEdit( + beforeBuffer.text, + afterBuffer.text, + ); + return SpellingReviewCorrection( + coordinateScope: _reviewCoordinateScope(occurrence), + start: committed.start, + oldEnd: committed.oldEnd, + newEnd: committed.newEnd, + ); + } + final fieldStart = occurrence.fieldStart; + final fieldEnd = occurrence.fieldEnd; + if (fieldStart == null || fieldEnd == null) return null; + return SpellingReviewCorrection( + coordinateScope: _reviewCoordinateScope(occurrence), + start: fieldStart, + oldEnd: fieldEnd, + newEnd: plan.translateFieldOffset(fieldEnd), + ); + } on Object { + return null; + } + } + + void _restoreActiveEditorFocus() { + final input = _currentSpellingInput; + if (input?.richDocument != null) { + _wysiwygEditorKey.currentState?.restoreSpellingFocus(); + } else { + _sourceEditorKey.currentState?.restoreSpellingFocus(); + } + } + + Future> _prepareSourceSpellingMenu( + int offset, + ) { + final occurrence = _spelling.occurrenceAtSource(offset); + return _prepareSpellingMenu(occurrence); + } + + Future> _prepareRichSpellingMenu( + SpellingEditorTarget target, + int offset, + ) { + final occurrence = _spelling.occurrenceAtField( + target: target, + offset: offset, + ); + return _prepareSpellingMenu(occurrence); + } + + Future> _prepareSpellingMenu( + SpellingOccurrence? captured, + ) async { + if (captured == null) return const []; + List? suggestions; + try { + suggestions = await _spelling.suggestions(captured); + } on Object { + suggestions = null; + } + if (!mounted || !_spelling.isCurrent(captured)) return const []; + + void ifCurrent(VoidCallback action) { + if (_spelling.isCurrent(captured)) action(); + } + + return [ + if (suggestions == null) + BusyMarkEditorSpellingMenuItem( + label: context.l10n.spellingWordCheckFailed, + onSelected: () {}, + enabled: false, + ) + else if (suggestions.isEmpty) + BusyMarkEditorSpellingMenuItem( + label: context.l10n.noSpellingSuggestions, + onSelected: () {}, + enabled: false, + ) + else + for (final suggestion in suggestions.take(8)) + BusyMarkEditorSpellingMenuItem( + label: suggestion, + suggestion: true, + onSelected: () => ifCurrent( + () => unawaited(_applySpellingCorrection(captured, suggestion)), + ), + ), + BusyMarkEditorSpellingMenuItem( + label: context.l10n.ignoreSpellingOnce, + onSelected: () => ifCurrent(() => _spelling.ignoreOnce(captured)), + ), + BusyMarkEditorSpellingMenuItem( + label: context.l10n.ignoreSpellingDocument, + onSelected: () => + ifCurrent(() => _spelling.ignoreAllInDocument(captured)), + ), + BusyMarkEditorSpellingMenuItem( + label: context.l10n.addPersonalSpellingWord, + onSelected: () => ifCurrent( + () => unawaited(_persistSpellingWord(captured, project: false)), + ), + ), + BusyMarkEditorSpellingMenuItem( + label: context.l10n.addProjectSpellingWord, + enabled: _spelling.hasProjectScope, + onSelected: () => ifCurrent( + () => unawaited(_persistSpellingWord(captured, project: true)), + ), + ), + _documentSpellingLanguageMenuItem(), + ]; + } + + BusyMarkEditorSpellingMenuItem _documentSpellingLanguageMenuItem() { + final buffer = ref.read(workspaceControllerProvider).activeBuffer; + final current = buffer?.editorState.spellingLanguage; + final entries = _spelling.catalog?.entries ?? const []; + BusyMarkEditorSpellingMenuItem choice( + String label, + SpellingLanguageOverride requested, + ) { + return BusyMarkEditorSpellingMenuItem( + label: label, + checked: current == requested, + mutuallyExclusive: true, + onSelected: () => unawaited( + _applyDocumentSpellingLanguage( + requested, + expectedBufferId: buffer?.id, + ), + ), + ); + } + + return BusyMarkEditorSpellingMenuItem.submenu( + label: context.l10n.chooseSpellingLanguage, + children: [ + choice( + context.l10n.inheritSpellingLanguage, + const SpellingLanguageOverride.inherit(), + ), + choice( + context.l10n.disableDocumentSpelling, + const SpellingLanguageOverride.disabled(), + ), + if (entries.isNotEmpty) const BusyMarkEditorSpellingMenuItem.divider(), + for (final entry in entries) + choice(entry.label, SpellingLanguageOverride.selected(entry.id)), + ], + ); + } + + Future _persistSpellingWord( + SpellingOccurrence occurrence, { + required bool project, + }) async { + try { + if (project) { + await _spelling.addProjectWord(occurrence); + } else { + await _spelling.addPersonalWord(occurrence); + } + } on Object catch (error) { + if (!mounted) return; + _showSpellingPersistenceFailure(context, error); + } + } + + Future _chooseDocumentSpellingLanguage() async { + final initial = ref.read(workspaceControllerProvider).activeBuffer; + if (initial == null) return false; + + await _spelling.prepareSettings(widget.state.workspace); + if (!mounted) return false; + + final buffer = ref.read(workspaceControllerProvider).activeBuffer; + if (buffer == null || buffer.id != initial.id) return false; + final entries = _spelling.catalog?.entries ?? const []; + if (entries.isEmpty) return false; + final current = buffer.editorState.spellingLanguage; + Widget selectedIcon(SpellingLanguageOverride candidate) { + return candidate == current + ? const Icon(BusyMarkGlyphs.check, size: BusyMarkSizes.iconSm) + : const SizedBox(width: BusyMarkSizes.iconSm); + } + + final selected = await showBusyMarkModalDialog( + context, + builder: (dialogContext) => BusyMarkDialogShell( + title: dialogContext.l10n.chooseSpellingLanguage, + children: [ + BusyMarkGroupedList( + filled: true, + children: [ + BusyMarkActionRow( + title: dialogContext.l10n.inheritSpellingLanguage, + trailing: selectedIcon( + const SpellingLanguageOverride.inherit(), + ), + onTap: () => Navigator.of( + dialogContext, + ).pop(const SpellingLanguageOverride.inherit()), + ), + BusyMarkActionRow( + title: dialogContext.l10n.disableDocumentSpelling, + trailing: selectedIcon( + const SpellingLanguageOverride.disabled(), + ), + onTap: () => Navigator.of( + dialogContext, + ).pop(const SpellingLanguageOverride.disabled()), + ), + for (final entry in entries) + BusyMarkActionRow( + title: entry.label, + trailing: selectedIcon( + SpellingLanguageOverride.selected(entry.id), + ), + onTap: () => Navigator.of( + dialogContext, + ).pop(SpellingLanguageOverride.selected(entry.id)), + ), + ], + ), + ], + ), + ); + if (!mounted || selected == null) return false; + final applied = await _applyDocumentSpellingLanguage( + selected, + expectedBufferId: buffer.id, + ); + return applied && selected.kind != SpellingLanguageOverrideKind.disabled; + } + + Future _applyDocumentSpellingLanguage( + SpellingLanguageOverride requested, { + String? expectedBufferId, + }) async { + final buffer = ref.read(workspaceControllerProvider).activeBuffer; + if (buffer == null || + (expectedBufferId != null && buffer.id != expectedBufferId)) { + return false; + } + final selectedLanguageId = requested.languageId; + if (requested.kind == SpellingLanguageOverrideKind.selected && + selectedLanguageId != null && + _spelling.catalog?.installedById(selectedLanguageId) == null && + !await _offerDocumentDictionaryInstall(selectedLanguageId)) { + return false; + } + if (!mounted) return false; + final latest = ref.read(workspaceControllerProvider).activeBuffer; + if (latest == null || latest.id != buffer.id) return false; + ref + .read(workspaceControllerProvider.notifier) + .updateDocumentEditorState( + latest.id, + latest.editorState.copyWith(spellingLanguage: requested), + ); + return true; + } + + Future _offerDocumentDictionaryInstall(String languageId) async { + if (_spelling.catalog?.installedById(languageId) != null) return true; + final resource = _spelling.catalog?.availableById(languageId); + if (resource == null) return false; + if (_spelling.catalog?.installationForResource(resource.resourceId) != + null) { + return true; + } + final mebibytes = resource.downloadSize / (1024 * 1024); + final size = mebibytes >= 10 + ? '${mebibytes.toStringAsFixed(0)} MiB' + : '${mebibytes.toStringAsFixed(1)} MiB'; + final accepted = await showBusyMarkModalDialog( + context, + builder: (dialogContext) => BusyMarkDialogShell( + title: dialogContext.l10n.spellingDictionaryNotInstalled, + actions: [ + BusyMarkDialogButton( + label: dialogContext.l10n.cancel, + onPressed: () => Navigator.pop(dialogContext, false), + ), + BusyMarkDialogButton( + label: dialogContext.l10n.installSpellingDictionary, + suggested: true, + onPressed: () => Navigator.pop(dialogContext, true), + ), + ], + children: [ + Text( + dialogContext.l10n.spellingDictionaryInstallPrompt( + resource.label, + size, + ), + ), + ], + ), + ); + if (!mounted || accepted != true) return false; + return _installDocumentDictionary(languageId); + } + + Future _installDocumentDictionary(String languageId) async { + if (_spelling.catalog?.installedById(languageId) != null) return true; + if (_spelling.catalog?.availableById(languageId) == null) return false; + try { + await _spelling.installDictionary(languageId); + return mounted && _spelling.catalog?.installedById(languageId) != null; + } on Object { + if (mounted) { + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingDictionaryInstallFailed, + priority: BusyMarkToastPriority.high, + ); + } + return false; + } + } + + void _handleTransactionalSourceChanged( + String? expectedBufferId, + String value, + String? sourceFilePath, + TextSelection previousSelection, + TextSelection selection, + String? undoGroup, + ) { + if (expectedBufferId == null || + widget.state.activeBuffer?.id != expectedBufferId) { + return; + } + final activePath = _activeEditorPath(); + if (sourceFilePath != null && sourceFilePath != activePath) { + return; + } + _clearWysiwygCache(); + ref + .read(workspaceControllerProvider.notifier) + .updateActiveSourceText( + value, + sourceBufferId: expectedBufferId, + sourceFilePath: sourceFilePath ?? activePath, + previousSelection: previousSelection, + selection: selection, + undoGroup: undoGroup, + ); + } + + void _handleWysiwygSourceChanged( + String? expectedBufferId, + String filePath, + String value, [ + String? undoGroup, + ]) { + if (expectedBufferId == null || + widget.state.activeBuffer?.id != expectedBufferId || + filePath != _activeEditorPath()) { + return; + } + final document = _cachedWysiwygDocument; + final controller = ref.read(workspaceControllerProvider.notifier); + if (document == null || + document.filePath != filePath || + document.source != value) { + controller.updateActiveText( + value, + sourceBufferId: expectedBufferId, + sourceFilePath: filePath, + ); + return; + } + controller.updateActiveWysiwygText( + value, + document: document, + sourceBufferId: expectedBufferId, + sourceFilePath: filePath, + undoGroup: undoGroup, + ); + _cacheCommittedWysiwygDocument(expectedBufferId, document); + } + + void _handleWysiwygSpellingSourceChanged( + String? expectedBufferId, + String filePath, + String value, + WysiwygEditorSessionState beforeSession, + WysiwygEditorSessionState afterSession, + ) { + if (expectedBufferId == null || + widget.state.activeBuffer?.id != expectedBufferId || + filePath != _activeEditorPath()) { + return; + } + final document = _cachedWysiwygDocument; + final controller = ref.read(workspaceControllerProvider.notifier); + if (document == null || + document.filePath != filePath || + document.source != value) { + // A spelling transaction must retain its structured document and rich + // selections. Refuse a stale cache instead of taking the generic source + // path and losing that state. + return; + } + controller.updateActiveWysiwygText( + value, + document: document, + sourceBufferId: expectedBufferId, + sourceFilePath: filePath, + undoGroup: null, + previousWysiwygState: beforeSession, + wysiwygState: afterSession, + ); + _cacheCommittedWysiwygDocument(expectedBufferId, document); + } + + void _cacheCommittedWysiwygDocument(String bufferId, BusyDocument document) { + final committed = ref.read(workspaceControllerProvider).activeBuffer; + if (committed == null || committed.id != bufferId) return; + // Workspace final-newline policy can change the emitted Markdown. Rebind + // the live tree to that committed source, retaining its editor block IDs. + // Reparsing here would give spelling targets IDs the mounted editor never + // adopted while handling its own synchronous edit. + _cacheWysiwygDocument(bufferId, document.copyWith(source: committed.text)); + } + + void _translateSpellingAnchors( + String value, { + String? previousText, + String? bufferId, + }) { + final buffer = ref.read(workspaceControllerProvider).activeBuffer; + if (buffer == null && (previousText == null || bufferId == null)) return; + final previous = previousText ?? buffer!.text; + final resolvedBufferId = bufferId ?? buffer!.id; + if (previous == value) return; + final committed = busyMarkMinimalSourceEdit(previous, value); + _spelling.translateSourceEdit( + bufferId: resolvedBufferId, + start: committed.start, + oldEnd: committed.oldEnd, + newEnd: committed.newEnd, + ); + } + + void _cacheWysiwygDocument(String? expectedBufferId, BusyDocument document) { + final workspace = widget.state.workspace; + final buffer = widget.state.activeBuffer; + if (workspace == null || buffer == null || buffer.id != expectedBufferId) { + return; + } + final context = resolveWorkspaceDocumentContext(workspace, buffer); + _cachedWysiwygDocument = document; + _cachedWysiwygBufferId = buffer.id; + _cachedWysiwygPath = document.filePath; + _cachedWysiwygSource = document.source; + _cachedWysiwygMode = context.markdownMode; } void _clearWysiwygCache() { _cachedWysiwygDocument = null; + _cachedWysiwygBufferId = null; _cachedWysiwygPath = null; _cachedWysiwygSource = null; + _cachedWysiwygMode = null; } String? _activeEditorPath() { final workspace = widget.state.workspace; - return workspace?.activeFilePath ?? workspace?.markdown?.filePath; + final buffer = widget.state.activeBuffer; + return workspace == null || buffer == null + ? null + : resolveWorkspaceDocumentContext(workspace, buffer).parserPath; } SourceSyntaxLanguage _sourceSyntaxLanguage(Workspace? workspace) { @@ -12465,6 +13452,31 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { }; } + SourceDocumentFormat _sourceDocumentFormat(Workspace? workspace) { + return switch (_activeDocumentKind(workspace)) { + DocumentKind.markdown || + DocumentKind.writersideMarkdownTopic => SourceDocumentFormat.markdown, + DocumentKind.writersideXmlTopic => + SourceDocumentFormat.writersideXmlTopic, + DocumentKind.tree || + DocumentKind.config || + DocumentKind.variables || + DocumentKind.categories => SourceDocumentFormat.genericXml, + DocumentKind.gitIgnore || + DocumentKind.resource || + DocumentKind.unknown || + DocumentKind.image || + null => SourceDocumentFormat.plainText, + }; + } + + MarkdownMode _sourceMarkdownMode(Workspace? workspace) { + final buffer = widget.state.activeBuffer; + return workspace == null || buffer == null + ? MarkdownMode.commonMark + : resolveWorkspaceDocumentContext(workspace, buffer).markdownMode; + } + Future _handleSymbolAction( SourceSymbolAction action, int offset, @@ -12613,10 +13625,11 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { } DocumentKind? _activeDocumentKind(Workspace? workspace) { - if (workspace == null) { + final buffer = widget.state.activeBuffer; + if (workspace == null || buffer == null) { return null; } - return _activeWorkspaceDocumentKind(workspace); + return resolveWorkspaceDocumentContext(workspace, buffer).kind; } void _scrollToOutlineTarget(_OutlineNavigationTarget target) { @@ -12644,8 +13657,7 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { ref.read(_searchNavigationTargetProvider)?.request != target.request || _lastSearchNavigationRequest == target.request || - (target.filePath != widget.state.workspace?.activeFilePath && - target.filePath != widget.state.workspace?.markdown?.filePath)) { + target.filePath != widget.state.activeBuffer?.filePath) { return; } _lastSearchNavigationRequest = target.request; @@ -12899,44 +13911,49 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { BusyDocument? _wysiwygDocument() { final workspace = widget.state.workspace; - final activePath = - workspace?.activeFilePath ?? workspace?.markdown?.filePath; - if (workspace == null || activePath == null) { + final buffer = widget.state.activeBuffer; + if (workspace == null || buffer == null) { return null; } - if (_cachedWysiwygPath == activePath && - _cachedWysiwygSource == widget.state.activeText) { + final context = resolveWorkspaceDocumentContext(workspace, buffer); + final activePath = context.parserPath; + if (_cachedWysiwygBufferId == buffer.id && + _cachedWysiwygPath == activePath && + _cachedWysiwygSource == buffer.text && + _cachedWysiwygMode == context.markdownMode) { return _cachedWysiwygDocument; } final currentMarkdown = workspace.markdown; if (currentMarkdown != null && p.equals(currentMarkdown.filePath, activePath) && - currentMarkdown.source == widget.state.activeText) { + currentMarkdown.source == buffer.text && + currentMarkdown.mode == context.markdownMode) { final document = currentMarkdown.busyDocument; _cachedWysiwygDocument = document; + _cachedWysiwygBufferId = buffer.id; _cachedWysiwygPath = activePath; - _cachedWysiwygSource = widget.state.activeText; + _cachedWysiwygSource = buffer.text; + _cachedWysiwygMode = context.markdownMode; return document; } - final mode = workspace.kind == WorkspaceKind.writersideModule - ? MarkdownMode.writersideMarkdown - : MarkdownMode.commonMark; try { final document = const MarkdownParser() .parse( filePath: activePath, - source: widget.state.activeText, - mode: mode, + source: buffer.text, + mode: context.markdownMode, workspaceRoot: workspace.rootPath, validateLocalReferences: false, ) .busyDocument; _cachedWysiwygDocument = document; + _cachedWysiwygBufferId = buffer.id; _cachedWysiwygPath = activePath; - _cachedWysiwygSource = widget.state.activeText; + _cachedWysiwygSource = buffer.text; + _cachedWysiwygMode = context.markdownMode; return document; } on Object { - return workspace.markdown?.busyDocument; + return null; } } } @@ -14532,8 +15549,7 @@ String? _imageWorkspaceRoot(Workspace? workspace) { if (module == null) { return workspace.rootPath; } - final activeFilePath = - workspace.activeFilePath ?? workspace.markdown?.filePath; + final activeFilePath = workspace.activeFilePath; if (activeFilePath == null) { return null; } @@ -15207,7 +16223,7 @@ void _navigatePreviewAnchor( } final state = ref.read(workspaceControllerProvider); final workspace = state.workspace; - final activePath = workspace?.activeFilePath ?? workspace?.markdown?.filePath; + final activePath = state.activeBuffer?.filePath; if (workspace == null || activePath != filePath) { return; } @@ -15246,6 +16262,7 @@ void _navigatePreviewAnchor( .set( _OutlineNavigationTarget( workspaceId: workspace.id, + bufferId: state.activeBufferId ?? '', filePath: workspace.activeFilePath, headingId: heading?.id ?? element!.attributes['id']!, line: heading?.sourceStartLine ?? element?.sourceStartLine, @@ -15507,6 +16524,643 @@ class _SearchSidebar extends StatelessWidget { } } +@visibleForTesting +final class SpellingReviewCorrection { + const SpellingReviewCorrection({ + required this.coordinateScope, + required this.start, + required this.oldEnd, + required this.newEnd, + }); + + final String coordinateScope; + final int start; + final int oldEnd; + final int newEnd; +} + +/// Returns the one bounding edit that transforms [before] into [after]. +/// +/// Review anchors deliberately use the source committed by the editor rather +/// than the narrower edit that was planned before rich serialization. +@visibleForTesting +({int start, int oldEnd, int newEnd}) busyMarkMinimalSourceEdit( + String before, + String after, +) { + final sharedLength = math.min(before.length, after.length); + var start = 0; + while (start < sharedLength && + before.codeUnitAt(start) == after.codeUnitAt(start)) { + start++; + } + var oldEnd = before.length; + var newEnd = after.length; + while (oldEnd > start && + newEnd > start && + before.codeUnitAt(oldEnd - 1) == after.codeUnitAt(newEnd - 1)) { + oldEnd--; + newEnd--; + } + return (start: start, oldEnd: oldEnd, newEnd: newEnd); +} + +@visibleForTesting +class BusyMarkSpellingReviewDialog extends StatefulWidget { + const BusyMarkSpellingReviewDialog({ + required this.spelling, + required this.initialIndex, + required this.onReveal, + required this.onCorrect, + required this.onChooseLanguage, + }); + + final SpellingSessionController spelling; + final int initialIndex; + final ValueChanged onReveal; + final Future Function( + SpellingOccurrence occurrence, + String suggestion, + ) + onCorrect; + final Future Function() onChooseLanguage; + + @override + State createState() => + _SpellingReviewDialogState(); +} + +class _SpellingReviewDialogState extends State { + late int _index = widget.initialIndex; + final List<_SpellingReviewVisit> _visited = []; + String? _currentOccurrenceId; + int? _advanceAnchor; + String? _advanceScope; + String? _bufferId; + bool _actionInProgress = false; + bool _closing = false; + final _dialogFocus = FocusNode(debugLabel: 'Spelling review dialog'); + String? _suggestionOccurrenceId; + Future>? _suggestions; + + List get _occurrences { + final result = widget.spelling.misspellings + .where( + (occurrence) => + widget.spelling.isCurrent(occurrence) && + (_bufferId == null || + occurrence.run.snapshot.bufferId == _bufferId), + ) + .toList(growable: false); + final originalOrder = { + for (final (index, occurrence) in result.indexed) occurrence: index, + }; + result.sort((left, right) { + final leftSource = left.sourceStart; + final rightSource = right.sourceStart; + if (leftSource != null && rightSource != null) { + return leftSource.compareTo(rightSource); + } + return originalOrder[left]!.compareTo(originalOrder[right]!); + }); + return result; + } + + @override + void initState() { + super.initState(); + _bufferId = widget.spelling.misspellings.firstOrNull?.run.snapshot.bufferId; + final occurrences = _occurrences; + if (occurrences.isNotEmpty) { + _index = _index.clamp(0, occurrences.length - 1).toInt(); + _currentOccurrenceId = occurrences[_index].id; + } + widget.spelling.addListener(_handleSpellingChanged); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) _dialogFocus.requestFocus(); + }); + } + + @override + void dispose() { + widget.spelling.removeListener(_handleSpellingChanged); + _dialogFocus.dispose(); + super.dispose(); + } + + void _handleSpellingChanged() { + if (!mounted || _closing) return; + final occurrences = _occurrences; + final state = widget.spelling.state; + if (_actionInProgress) { + setState(() {}); + return; + } + if (state.status == SpellingPresentationStatus.ready && state.complete) { + if (occurrences.isEmpty) { + _requestClose(); + return; + } + final current = occurrences.indexWhere( + (occurrence) => occurrence.id == _currentOccurrenceId, + ); + if (current >= 0) { + _index = current; + } else if (!_selectNextUnvisited(occurrences)) { + _requestClose(); + return; + } + } + final occurrence = _selectedOccurrence(occurrences); + if (_suggestionOccurrenceId != occurrence?.id) { + _suggestionOccurrenceId = null; + _suggestions = null; + } + setState(() {}); + } + + void _move(int delta) { + if (_closing || _actionInProgress) return; + final occurrences = _occurrences; + if (occurrences.isEmpty) return; + final current = _selectedOccurrence(occurrences); + if (current == null) return; + if (delta > 0) _recordVisited(current); + if (delta > 0) { + if (!_selectNextUnvisited(occurrences)) { + _requestClose(); + return; + } + } else { + _index = (_index - 1) % occurrences.length; + if (_index < 0) _index += occurrences.length; + _currentOccurrenceId = occurrences[_index].id; + } + setState(() { + _suggestionOccurrenceId = null; + _suggestions = null; + }); + widget.onReveal(occurrences[_index]); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted && !_closing) _dialogFocus.requestFocus(); + }); + } + + void _requestClose({bool reopenForLanguage = false}) { + if (!mounted || _closing) return; + _closing = true; + Navigator.of(context).pop(reopenForLanguage ? true : null); + } + + void _finishRemovedOccurrence(SpellingOccurrence removed) { + _recordVisited(removed); + final occurrences = _occurrences; + if (occurrences.isEmpty) { + final state = widget.spelling.state; + if (state.status == SpellingPresentationStatus.ready && state.complete) { + _requestClose(); + return; + } + setState(() {}); + return; + } + if (!_selectNextUnvisited(occurrences)) { + _requestClose(); + return; + } + widget.onReveal(occurrences[_index]); + setState(() { + _suggestionOccurrenceId = null; + _suggestions = null; + }); + } + + void _recordVisited(SpellingOccurrence occurrence) { + final visit = _SpellingReviewVisit.fromOccurrence(occurrence); + if (!_visited.any((candidate) => candidate.matches(occurrence))) { + _visited.add(visit); + } + _advanceAnchor = _reviewCoordinateEnd(occurrence); + _advanceScope = _reviewCoordinateScope(occurrence); + _currentOccurrenceId = null; + } + + SpellingOccurrence? _selectedOccurrence( + List occurrences, + ) { + if (occurrences.isEmpty) return null; + final selected = occurrences.indexWhere( + (occurrence) => occurrence.id == _currentOccurrenceId, + ); + if (selected < 0) return null; + _index = selected; + return occurrences[selected]; + } + + void _translateReviewState(SpellingReviewCorrection correction) { + final delta = correction.newEnd - correction.oldEnd; + _visited.removeWhere( + (visit) => + visit.coordinateScope == correction.coordinateScope && + visit.offset >= correction.start && + visit.offset < correction.oldEnd, + ); + for (final visit in _visited) { + if (visit.coordinateScope == correction.coordinateScope && + visit.offset >= correction.oldEnd) { + visit.offset += delta; + } + } + if (_advanceScope == correction.coordinateScope && + _advanceAnchor != null && + _advanceAnchor! >= correction.oldEnd) { + _advanceAnchor = _advanceAnchor! + delta; + } + } + + bool _selectNextUnvisited(List occurrences) { + final anchor = _advanceAnchor; + final candidates = [ + for (var index = 0; index < occurrences.length; index++) + if (!_visited.any((visit) => visit.matches(occurrences[index]))) index, + ]; + if (candidates.isEmpty) return false; + _index = anchor == null + ? candidates.first + : candidates.firstWhere( + (index) => + _reviewCoordinateScope(occurrences[index]) == _advanceScope && + _reviewCoordinateStart(occurrences[index]) >= anchor, + orElse: () => candidates.first, + ); + _currentOccurrenceId = occurrences[_index].id; + widget.onReveal(occurrences[_index]); + return true; + } + + Future> _suggestionsFor(SpellingOccurrence occurrence) { + if (_suggestionOccurrenceId != occurrence.id || _suggestions == null) { + _suggestionOccurrenceId = occurrence.id; + _suggestions = widget.spelling.suggestions(occurrence); + } + return _suggestions!; + } + + void _ignore( + SpellingOccurrence occurrence, + void Function(SpellingOccurrence occurrence) action, + ) { + if (_closing || + _actionInProgress || + !widget.spelling.isCurrent(occurrence)) { + return; + } + setState(() => _actionInProgress = true); + action(occurrence); + if (!mounted || _closing) return; + final removed = !widget.spelling.isCurrent(occurrence); + _actionInProgress = false; + if (removed) { + _finishRemovedOccurrence(occurrence); + } else { + setState(() {}); + } + } + + Future _persist( + Future Function(SpellingOccurrence occurrence) action, + SpellingOccurrence occurrence, + ) async { + if (_closing || _actionInProgress) return; + setState(() => _actionInProgress = true); + try { + await action(occurrence); + if (mounted && !_closing) { + _actionInProgress = false; + _finishRemovedOccurrence(occurrence); + } + } on Object catch (error) { + if (!mounted || _closing) return; + _actionInProgress = false; + _reconcileFailedAction(occurrence); + _showSpellingPersistenceFailure(context, error); + } + } + + void _reconcileFailedAction(SpellingOccurrence failed) { + final occurrences = _occurrences; + final failedScope = _reviewCoordinateScope(failed); + final failedStart = _reviewCoordinateStart(failed); + final equivalent = occurrences.indexWhere( + (occurrence) => + _reviewCoordinateScope(occurrence) == failedScope && + _reviewCoordinateStart(occurrence) == failedStart && + occurrence.word == failed.word, + ); + if (equivalent >= 0) { + _index = equivalent; + _currentOccurrenceId = occurrences[equivalent].id; + } else if (occurrences.isNotEmpty) { + _selectNextUnvisited(occurrences); + } + _suggestionOccurrenceId = null; + _suggestions = null; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final occurrences = _occurrences; + final state = widget.spelling.state; + final occurrence = _selectedOccurrence(occurrences); + return Focus( + focusNode: _dialogFocus, + autofocus: true, + onKeyEvent: (_, event) { + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.escape) { + _requestClose(); + return KeyEventResult.handled; + } + return KeyEventResult.ignored; + }, + child: AlertDialog( + title: Text(context.l10n.checkSpelling), + content: SizedBox( + width: 480, + child: occurrence == null + ? Padding( + padding: const EdgeInsets.all(BusyMarkSpacing.lg), + child: state.status == SpellingPresentationStatus.checking + ? Center( + child: Semantics( + label: context.l10n.spellingChecking, + child: const CircularProgressIndicator(), + ), + ) + : Text(_spellingEmptyStateMessage(context, state)), + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Semantics( + liveRegion: true, + child: Text( + occurrence.word, + style: Theme.of(context).textTheme.headlineSmall, + ), + ), + const SizedBox(height: BusyMarkSpacing.xs), + Text( + _spellingContext(occurrence), + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: BusyMarkSpacing.md), + FutureBuilder>( + future: _suggestionsFor(occurrence), + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return const Center( + child: CircularProgressIndicator(), + ); + } + if (snapshot.hasError) { + return Text(context.l10n.spellingWordCheckFailed); + } + final suggestions = snapshot.data ?? const []; + if (suggestions.isEmpty) { + return Text(context.l10n.noSpellingSuggestions); + } + return Wrap( + spacing: BusyMarkSpacing.sm, + runSpacing: BusyMarkSpacing.sm, + children: [ + for (final suggestion in suggestions.take(8)) + BusyMarkPushButton.standard( + onPressed: _actionInProgress || _closing + ? null + : () async { + setState( + () => _actionInProgress = true, + ); + final correction = await widget + .onCorrect(occurrence, suggestion); + if (!mounted || _closing) return; + _actionInProgress = false; + if (correction != null) { + _recordVisited(occurrence); + _translateReviewState(correction); + _suggestionOccurrenceId = null; + _suggestions = null; + final occurrences = _occurrences; + if (occurrences.isEmpty) { + final state = widget.spelling.state; + if (state.status == + SpellingPresentationStatus + .ready && + state.complete) { + _requestClose(); + return; + } + } else if (!_selectNextUnvisited( + occurrences, + )) { + _requestClose(); + return; + } + } + setState(() {}); + }, + child: Text(suggestion), + ), + ], + ); + }, + ), + const SizedBox(height: BusyMarkSpacing.md), + Wrap( + spacing: BusyMarkSpacing.sm, + runSpacing: BusyMarkSpacing.sm, + children: [ + TextButton( + onPressed: _actionInProgress || _closing + ? null + : () => _ignore( + occurrence, + widget.spelling.ignoreOnce, + ), + child: Text(context.l10n.ignoreSpellingOnce), + ), + TextButton( + onPressed: _actionInProgress || _closing + ? null + : () => _ignore( + occurrence, + widget.spelling.ignoreAllInDocument, + ), + child: Text(context.l10n.ignoreSpellingDocument), + ), + TextButton( + onPressed: _actionInProgress || _closing + ? null + : () => unawaited( + _persist( + widget.spelling.addPersonalWord, + occurrence, + ), + ), + child: Text(context.l10n.addPersonalSpellingWord), + ), + TextButton( + onPressed: + widget.spelling.hasProjectScope && + !_actionInProgress && + !_closing + ? () => unawaited( + _persist( + widget.spelling.addProjectWord, + occurrence, + ), + ) + : null, + child: Text(context.l10n.addProjectSpellingWord), + ), + ], + ), + ], + ), + ), + actions: [ + if (occurrence != null) ...[ + TextButton( + onPressed: _actionInProgress || _closing + ? null + : () async { + setState(() => _actionInProgress = true); + final selected = await widget.onChooseLanguage(); + if (!mounted || _closing) return; + _actionInProgress = false; + if (selected) { + _requestClose(reopenForLanguage: true); + } else { + _handleSpellingChanged(); + } + }, + child: Text(context.l10n.chooseSpellingLanguage), + ), + TextButton( + onPressed: _actionInProgress || _closing ? null : () => _move(-1), + child: Text(context.l10n.sourceSearchPreviousMatch), + ), + TextButton( + onPressed: _actionInProgress || _closing ? null : () => _move(1), + child: Text(context.l10n.sourceSearchNextMatch), + ), + ], + TextButton( + autofocus: true, + onPressed: _closing ? null : _requestClose, + child: Text(context.l10n.close), + ), + ], + ), + ); + } +} + +void _showSpellingPersistenceFailure(BuildContext context, Object error) { + if (error is AtomicFileChangedException && error.recoveryPath != null) { + final recoveryPath = error.recoveryPath!; + BusyMarkToastOverlay.show( + context, + message: context.l10n.spellingDictionaryRecoveryConflict, + actionLabel: context.l10n.copyPath, + onAction: () => + unawaited(Clipboard.setData(ClipboardData(text: recoveryPath))), + duration: Duration.zero, + priority: BusyMarkToastPriority.high, + ); + return; + } + BusyMarkToastOverlay.show( + context, + message: context.l10n.commandUnavailableInContext, + priority: BusyMarkToastPriority.high, + ); +} + +String _spellingContext(SpellingOccurrence occurrence) { + final text = occurrence.run.text; + final start = math.max(0, occurrence.logicalStart - 40); + final end = math.min(text.length, occurrence.logicalEnd + 40); + return text.substring(start, end).replaceAll(RegExp(r'\s+'), ' ').trim(); +} + +String _reviewTargetIdentity(SpellingOccurrence occurrence) => + switch (occurrence.run.target) { + SpellingSourceTarget(:final filePath) => 'source:$filePath', + SpellingRichBlockTarget(:final blockId) => 'block:$blockId', + SpellingRichTableCellTarget(:final tableBlockId, :final cellId) => + 'cell:$tableBlockId:$cellId', + }; + +String _reviewCoordinateScope(SpellingOccurrence occurrence) => + occurrence.sourceStart != null && occurrence.sourceEnd != null + ? 'document:${occurrence.run.snapshot.bufferId}' + : 'field:${_reviewTargetIdentity(occurrence)}'; + +int _reviewCoordinateStart(SpellingOccurrence occurrence) => + occurrence.sourceStart ?? occurrence.fieldStart ?? -1; + +int? _reviewCoordinateEnd(SpellingOccurrence occurrence) => + occurrence.sourceEnd ?? occurrence.fieldEnd; + +final class _SpellingReviewVisit { + _SpellingReviewVisit({ + required this.coordinateScope, + required this.offset, + required this.word, + }); + + factory _SpellingReviewVisit.fromOccurrence(SpellingOccurrence occurrence) => + _SpellingReviewVisit( + coordinateScope: _reviewCoordinateScope(occurrence), + offset: _reviewCoordinateStart(occurrence), + word: occurrence.word, + ); + + final String coordinateScope; + int offset; + final String word; + + bool matches(SpellingOccurrence occurrence) => + coordinateScope == _reviewCoordinateScope(occurrence) && + offset == _reviewCoordinateStart(occurrence) && + word == occurrence.word; +} + +String _spellingEmptyStateMessage( + BuildContext context, + SpellingPresentationState state, +) => switch (state.status) { + SpellingPresentationStatus.ready when state.complete => + context.l10n.noSpellingErrors, + SpellingPresentationStatus.failure => context.l10n.spellingCheckFailed, + SpellingPresentationStatus.incomplete => context.l10n.spellingCheckIncomplete, + SpellingPresentationStatus.dictionaryNotInstalled => + context.l10n.spellingDictionaryNotInstalled, + SpellingPresentationStatus.dictionaryUnavailable => + context.l10n.spellingDictionaryUnavailable, + SpellingPresentationStatus.languageRequired => + context.l10n.chooseSpellingLanguage, + SpellingPresentationStatus.disabled => + context.l10n.commandUnavailableInContext, + SpellingPresentationStatus.checking => context.l10n.spellingChecking, + SpellingPresentationStatus.ready => context.l10n.spellingCheckIncomplete, +}; + class _WorkspaceReplacementProgress extends StatefulWidget { const _WorkspaceReplacementProgress({ required this.future, @@ -15935,8 +17589,7 @@ Future<_WorkspaceSearchOutcome> _loadWorkspaceSearchMatches( String? text; if (buffer != null) { text = buffer.text; - } else if (file.absolutePath == - (workspace.activeFilePath ?? workspace.markdown?.filePath)) { + } else if (file.absolutePath == state.activeBuffer?.filePath) { text = state.activeText; } else if (file.size > _maxWorkspaceSearchFileBytes) { skippedFiles.add(file.relativePath); @@ -16221,22 +17874,6 @@ class _DiagnosticRow extends ConsumerWidget { } } -DocumentKind? _activeWorkspaceDocumentKind(Workspace workspace) { - final activePath = workspace.activeFilePath ?? workspace.markdown?.filePath; - if (activePath == null) { - return null; - } - for (final file in workspace.files) { - if (file.absolutePath == activePath) { - return file.kind; - } - } - return workspace.kind == WorkspaceKind.untitledMarkdown || - workspace.kind == WorkspaceKind.singleMarkdown - ? DocumentKind.markdown - : null; -} - IconData _diagnosticIconForSeverity(DiagnosticSeverity severity) { return switch (severity) { DiagnosticSeverity.error => BusyMarkGlyphs.error, diff --git a/lib/src/workspace/presentation/writerside_template_dialogs.dart b/lib/src/workspace/presentation/writerside_template_dialogs.dart index a294890e..994eb7f5 100644 --- a/lib/src/workspace/presentation/writerside_template_dialogs.dart +++ b/lib/src/workspace/presentation/writerside_template_dialogs.dart @@ -329,7 +329,7 @@ class _TemplateDialogState extends ConsumerState { Text(context.l10n.tocTemplateFormat), for (final extension in ['md', 'topic']) IntrinsicWidth( - child: YaruRadioButton( + child: BusyMarkRadioButton( key: ValueKey( 'template-format-$extension', ), diff --git a/lib/src/workspace/workspace_controller.dart b/lib/src/workspace/workspace_controller.dart index a3833779..58850970 100644 --- a/lib/src/workspace/workspace_controller.dart +++ b/lib/src/workspace/workspace_controller.dart @@ -13,6 +13,7 @@ import '../core/busymark_exception.dart'; import '../core/diagnostic.dart'; import '../core/source_span.dart'; import '../core/path_utils.dart' show isTextDocumentationPath; +import '../editor/wysiwyg/wysiwyg_session_state.dart'; import '../markdown/busymark_document.dart'; import '../markdown/document_outline.dart'; import '../markdown/preview_model.dart'; @@ -432,12 +433,12 @@ class WorkspaceController extends Notifier { ); final reparsed = await _reparseWithDocumentBuffers( nextWorkspace, - active.text, + active, buffers: buffers, ); state = WorkspaceState( workspace: reparsed, - preview: _safePreview(reparsed, active.text), + preview: _safePreview(reparsed, active), documentBuffers: buffers, activeBufferId: active.id, message: recovery.readErrors > 0 @@ -827,15 +828,12 @@ class WorkspaceController extends Notifier { final workspace = state.workspace!.copyWith( activeFileSnapshot: disk.snapshot, ); - final reparsed = await _reparseWithDocumentBuffers( - workspace, - disk.text, - ); + final reparsed = await _reparseWithDocumentBuffers(workspace, reloaded); if (state.activeBufferId == reloaded.id && state.activeBuffer?.revision == reloaded.revision) { state = state.copyWith( workspace: reparsed, - preview: _safePreview(reparsed, disk.text), + preview: _safePreview(reparsed, reloaded), ); _recordActivePreviewRevision(); } @@ -968,7 +966,7 @@ class WorkspaceController extends Notifier { )) { final reparsed = await _reparseWithDocumentBuffers( derivedWorkspace, - remapped.text, + remapped, ); if (_canPublishActiveDerivedContent( operationRevision: derivedOperationRevision, @@ -983,7 +981,7 @@ class WorkspaceController extends Notifier { activeFileSnapshot: remapped.diskSnapshot, openFilePaths: state.workspace!.openFilePaths, ), - preview: _safePreview(reparsed, remapped.text), + preview: _safePreview(reparsed, remapped), ); _recordActivePreviewRevision(); } @@ -1070,7 +1068,7 @@ class WorkspaceController extends Notifier { )) { final workspace = await _reparseWithDocumentBuffers( derivedWorkspace.copyWith(activeFileSnapshot: disk.snapshot), - disk.text, + reloaded, ); if (_canPublishActiveDerivedContent( operationRevision: derivedOperationRevision, @@ -1082,7 +1080,7 @@ class WorkspaceController extends Notifier { )) { state = state.copyWith( workspace: workspace, - preview: _safePreview(workspace, disk.text), + preview: _safePreview(workspace, reloaded), ); _recordActivePreviewRevision(); } @@ -1150,6 +1148,7 @@ class WorkspaceController extends Notifier { return _isCurrentActiveDocument( target.documentRevision, workspaceId: target.workspaceId, + bufferId: target.bufferId, activeFilePath: target.path, ) && workspace != null && @@ -1159,20 +1158,46 @@ class WorkspaceController extends Notifier { _sameFileSnapshot(state.activeBuffer?.diskSnapshot, target.snapshot); } - Future createMarkdownFile() async { + /// Starts a document from Welcome, replacing the previous workspace only + /// after its buffers have been resolved and their history has been flushed. + Future createMarkdownWorkspace() async { + final previous = state; + final previousOperation = _activeDocumentRevision; + if (previous.hasUnsavedChanges || previous.isLoading) return false; + final historySettled = await _localHistory.flushAll( + previous.documentBuffers, + ); + if (!ref.mounted) return false; + final liveBuffers = state.documentBuffers; + if (_activeDocumentRevision != previousOperation || + !identical(state.workspace, previous.workspace) || + liveBuffers.length != previous.documentBuffers.length || + liveBuffers.indexed.any( + (entry) => !identical(entry.$2, previous.documentBuffers[entry.$1]), + )) { + return false; + } _cancelPendingDerivedRefresh(); + _cancelAllAutoSaves(); _invalidateActiveDocumentOperations(); + state = const WorkspaceState(); + for (final buffer in previous.documentBuffers) { + _localHistory.handleBufferClosed( + buffer.id, + historySettled: historySettled, + ); + } + await createMarkdownFile(); + return true; + } + + Future createMarkdownFile() async { + _cancelPendingDerivedRefresh(); + final operationRevision = _invalidateActiveDocumentOperations(); _resetSaveTracking(dirty: true); final viewModeChange = _showEditorForNewFile(); final currentWorkspace = state.workspace; final untitledWorkspace = _service.createUntitledMarkdown(); - final workspace = currentWorkspace == null - ? untitledWorkspace - : currentWorkspace.copyWith( - activeFilePath: null, - activeFileSnapshot: null, - markdown: untitledWorkspace.markdown, - ); final sequence = ++_untitledSequence; final buffer = DocumentBuffer.untitled( id: 'untitled:${DateTime.now().microsecondsSinceEpoch}:$sequence', @@ -1183,18 +1208,45 @@ class WorkspaceController extends Notifier { ? DocumentViewModePreference.editor : _settingsController.state.documentViewMode, ); + final buffers = [...state.documentBuffers, buffer]; + final workspace = currentWorkspace == null + ? untitledWorkspace.copyWith(markdown: null) + : currentWorkspace.copyWith( + activeFilePath: null, + activeFileSnapshot: null, + markdown: null, + ); state = WorkspaceState( workspace: workspace, - preview: _safePreview(workspace, ''), - documentBuffers: [...state.documentBuffers, buffer], + preview: _safePreview(workspace, buffer), + documentBuffers: buffers, activeBufferId: buffer.id, isLoading: false, ); unawaited(_localHistory.observeOpened(buffer)); _recordActivePreviewRevision(); - await _startMonitoring(workspace); _schedulePersistence(); await viewModeChange; + final reparsed = await _reparseWithDocumentBuffers( + workspace, + buffer, + buffers: buffers, + ); + if (_canPublishActiveDerivedContent( + operationRevision: operationRevision, + workspaceId: workspace.id, + bufferId: buffer.id, + path: null, + revision: buffer.revision, + source: buffer.text, + )) { + state = state.copyWith( + workspace: reparsed, + preview: _safePreview(reparsed, buffer), + ); + _recordActivePreviewRevision(); + } + await _startMonitoring(state.workspace ?? workspace); } Future openPath(String path) async { @@ -1214,10 +1266,6 @@ class WorkspaceController extends Notifier { final loadedWorkspace = load == null ? workspace : workspace.copyWith(activeFileSnapshot: load.snapshot); - final preview = _safePreview(loadedWorkspace, text); - if (!_isCurrentActiveDocumentOperation(operationRevision)) { - return; - } final buffer = load == null || active == null ? null : _fileBuffer( @@ -1225,6 +1273,12 @@ class WorkspaceController extends Notifier { load, mode: _settingsController.state.documentViewMode, ); + final preview = buffer == null + ? null + : _safePreview(loadedWorkspace, buffer); + if (!_isCurrentActiveDocumentOperation(operationRevision)) { + return; + } state = WorkspaceState( workspace: loadedWorkspace, activeText: text, @@ -1282,10 +1336,6 @@ class WorkspaceController extends Notifier { final loadedWorkspace = load == null ? workspace : workspace.copyWith(activeFileSnapshot: load.snapshot); - final preview = _safePreview(loadedWorkspace, text); - if (!_isCurrentActiveDocumentOperation(operationRevision)) { - return false; - } final buffer = load == null || active == null ? null : _fileBuffer( @@ -1293,6 +1343,12 @@ class WorkspaceController extends Notifier { load, mode: _settingsController.state.documentViewMode, ); + final preview = buffer == null + ? null + : _safePreview(loadedWorkspace, buffer); + if (!_isCurrentActiveDocumentOperation(operationRevision)) { + return false; + } state = WorkspaceState( workspace: loadedWorkspace, activeText: text, @@ -2376,20 +2432,20 @@ class WorkspaceController extends Notifier { state.workspace?.id != workspaceId) { return false; } + final buffer = _fileBuffer( + path, + load, + mode: _settingsController.state.documentViewMode, + ); final reparsed = await _reparseWithDocumentBuffers( nextWorkspace, - load.text, + buffer, buffers: buffers, ); if (!_isCurrentActiveDocumentOperation(operationRevision) || state.workspace?.id != workspaceId) { return false; } - final buffer = _fileBuffer( - path, - load, - mode: _settingsController.state.documentViewMode, - ); final liveBuffers = state.documentBuffers; if (liveBuffers.any( (candidate) => @@ -2410,7 +2466,7 @@ class WorkspaceController extends Notifier { state = state.copyWith( workspace: publishedWorkspace, activeText: load.text, - preview: _safePreview(publishedWorkspace, load.text), + preview: _safePreview(publishedWorkspace, buffer), documentBuffers: reconciledBuffers, activeBufferId: buffer.id, clearMessage: true, @@ -2483,12 +2539,12 @@ class WorkspaceController extends Notifier { activeFilePath: buffer.filePath, activeFileSnapshot: buffer.diskSnapshot, openFilePaths: openFilePaths, - markdown: buffer.filePath == null ? workspace.markdown : null, + markdown: null, ); var parsedBuffer = buffer; var reparsed = await _reparseWithDocumentBuffers( nextWorkspace, - parsedBuffer.text, + parsedBuffer, buffers: documentBuffers, ); if (!_isCurrentActiveDocumentOperation(operationRevision)) { @@ -2504,7 +2560,7 @@ class WorkspaceController extends Notifier { parsedBuffer = liveBuffer; reparsed = await _reparseWithDocumentBuffers( nextWorkspace, - parsedBuffer.text, + parsedBuffer, buffers: documentBuffers, ); if (!_isCurrentActiveDocumentOperation(operationRevision) || @@ -2550,7 +2606,7 @@ class WorkspaceController extends Notifier { state = state.copyWith( workspace: publishedWorkspace, preview: sourceStayedCurrent - ? _safePreview(publishedWorkspace, liveBuffer.text) + ? _safePreview(publishedWorkspace, liveBuffer) : null, documentBuffers: reconciledBuffers, activeBufferId: liveBuffer.id, @@ -2754,6 +2810,7 @@ class WorkspaceController extends Notifier { final current = DocumentHistoryState( text: buffer.text, selection: buffer.editorState.selection, + wysiwygState: buffer.editorState.wysiwygState, ); final next = buffer.copyWith( text: target.text, @@ -2764,6 +2821,7 @@ class WorkspaceController extends Notifier { revision: buffer.revision + 1, editorState: buffer.editorState.copyWith( selection: target.selection, + wysiwygState: target.wysiwygState, undoState: undo.afterUndo(current), ), ); @@ -2790,6 +2848,7 @@ class WorkspaceController extends Notifier { final current = DocumentHistoryState( text: buffer.text, selection: buffer.editorState.selection, + wysiwygState: buffer.editorState.wysiwygState, ); final next = buffer.copyWith( text: target.text, @@ -2800,6 +2859,7 @@ class WorkspaceController extends Notifier { revision: buffer.revision + 1, editorState: buffer.editorState.copyWith( selection: target.selection, + wysiwygState: target.wysiwygState, undoState: undo.afterRedo(current), ), ); @@ -2816,9 +2876,14 @@ class WorkspaceController extends Notifier { return true; } - void updateActiveText(String text, {String? sourceFilePath}) { + void updateActiveText( + String text, { + String? sourceBufferId, + String? sourceFilePath, + }) { _updateActiveText( text, + sourceBufferId: sourceBufferId, sourceFilePath: sourceFilePath, rebuildPreview: state.activeBuffer?.editorState.mode != @@ -2828,6 +2893,7 @@ class WorkspaceController extends Notifier { void updateActiveSourceText( String text, { + String? sourceBufferId, String? sourceFilePath, required TextSelection previousSelection, required TextSelection selection, @@ -2835,6 +2901,7 @@ class WorkspaceController extends Notifier { }) { _updateActiveText( text, + sourceBufferId: sourceBufferId, sourceFilePath: sourceFilePath, rebuildPreview: _activeModeShowsPreview, previousSelection: previousSelection, @@ -2848,16 +2915,22 @@ class WorkspaceController extends Notifier { void updateActiveWysiwygText( String text, { required BusyDocument document, + String? sourceBufferId, String? sourceFilePath, String? undoGroup, + WysiwygEditorSessionState? previousWysiwygState, + WysiwygEditorSessionState? wysiwygState, }) { _updateActiveText( text, + sourceBufferId: sourceBufferId, sourceFilePath: sourceFilePath, rebuildPreview: false, liveOutline: document.outline, preserveFinalNewline: true, undoGroup: undoGroup, + previousWysiwygState: previousWysiwygState, + wysiwygState: wysiwygState, ); } @@ -2910,22 +2983,19 @@ class WorkspaceController extends Notifier { activeFileSnapshot: load.snapshot, openFilePaths: _openFileTabPaths(selected, path), ); - final reparsed = await _reparseWithDocumentBuffers( - nextWorkspace, - load.text, - ); - if (!_isCurrentActiveDocumentOperation(operationRevision)) { - return false; - } final buffer = _fileBuffer( path, load, mode: _settingsController.state.documentViewMode, ); + final reparsed = await _reparseWithDocumentBuffers(nextWorkspace, buffer); + if (!_isCurrentActiveDocumentOperation(operationRevision)) { + return false; + } final buffers = [...state.documentBuffers, buffer]; state = state.copyWith( workspace: reparsed, - preview: _safePreview(reparsed, load.text), + preview: _safePreview(reparsed, buffer), documentBuffers: buffers, activeBufferId: buffer.id, clearMessage: true, @@ -2950,23 +3020,26 @@ class WorkspaceController extends Notifier { void _updateActiveText( String text, { required bool rebuildPreview, + String? sourceBufferId, String? sourceFilePath, List? liveOutline, bool preserveFinalNewline = false, TextSelection? previousSelection, TextSelection? selection, String? undoGroup, + WysiwygEditorSessionState? previousWysiwygState, + WysiwygEditorSessionState? wysiwygState, }) { final workspace = state.workspace; - final activeEditorPath = - workspace?.activeFilePath ?? workspace?.markdown?.filePath; - if (sourceFilePath != null && activeEditorPath != sourceFilePath) { - return; - } final activeBuffer = state.activeBuffer; if (activeBuffer == null) { return; } + if (sourceBufferId != null && activeBuffer.id != sourceBufferId) return; + final activeEditorPath = workspace == null + ? activeBuffer.filePath + : resolveWorkspaceDocumentContext(workspace, activeBuffer).parserPath; + if (sourceFilePath != null && activeEditorPath != sourceFilePath) return; final effectiveText = preserveFinalNewline ? _withFinalNewlinePolicy(text, activeBuffer.format.hasFinalNewline) : text; @@ -2975,6 +3048,8 @@ class WorkspaceController extends Notifier { undoGroup: undoGroup, previousSelection: previousSelection, nextSelection: selection, + previousWysiwygState: previousWysiwygState, + nextWysiwygState: wysiwygState, ); if (identical(nextBuffer, activeBuffer)) { return; @@ -2993,7 +3068,8 @@ class WorkspaceController extends Notifier { ? null : ActiveDocumentOutline( workspaceId: workspace.id, - filePath: workspace.activeFilePath, + bufferId: nextBuffer.id, + filePath: nextBuffer.filePath, source: text, headings: liveOutline, ), @@ -3104,23 +3180,24 @@ class WorkspaceController extends Notifier { final editRevision = buffer.revision; final operationRevision = _activeDocumentRevision; try { - final reparsed = await _reparseWithDocumentBuffers(workspace, text); - if (!_isCurrentActiveDocument( - operationRevision, - workspaceId: workspaceId, - activeFilePath: activeFilePath, - ) || - state.activeBuffer?.id != bufferId || - state.activeText != text || - state.activeBuffer?.revision != editRevision) { + final reparsed = await _reparseWithDocumentBuffers(workspace, buffer); + if (!_canPublishActiveDerivedContent( + operationRevision: operationRevision, + workspaceId: workspaceId, + bufferId: bufferId, + path: activeFilePath, + revision: editRevision, + source: text, + )) { return; } state = state.copyWith( liveOutline: ActiveDocumentOutline( workspaceId: workspaceId, + bufferId: bufferId, filePath: activeFilePath, source: text, - headings: _service.activeDocumentOutline(reparsed), + headings: _service.documentOutline(reparsed, buffer), ), ); } on Object catch (error, stackTrace) { @@ -3135,24 +3212,30 @@ class WorkspaceController extends Notifier { Future _refreshActivePreview() async { final workspace = state.workspace; - if (workspace == null) { + final buffer = state.activeBuffer; + if (workspace == null || buffer == null) { return; } final workspaceId = workspace.id; - final activeFilePath = workspace.activeFilePath; - final text = state.activeText; - final editRevision = state.activeBuffer?.revision ?? _editRevision; + final activeFilePath = buffer.filePath; + final bufferId = buffer.id; + final text = buffer.text; + final editRevision = buffer.revision; final operationRevision = _activeDocumentRevision; try { - final reparsed = await _reparseWithDocumentBuffers(workspace, text); - final preview = await _service.buildPreviewAsync(reparsed, text); - if (!_isCurrentActiveDocument( - operationRevision, - workspaceId: workspaceId, - activeFilePath: activeFilePath, - ) || - state.activeText != text || - state.activeBuffer?.revision != editRevision) { + final reparsed = await _reparseWithDocumentBuffers(workspace, buffer); + final preview = await _service.buildDocumentPreviewAsync( + reparsed, + buffer, + ); + if (!_canPublishActiveDerivedContent( + operationRevision: operationRevision, + workspaceId: workspaceId, + bufferId: bufferId, + path: activeFilePath, + revision: editRevision, + source: text, + )) { return; } // Preview remains live when validate-on-edit is disabled, but the parsed @@ -3338,8 +3421,18 @@ class WorkspaceController extends Notifier { state.activeBufferId != bufferId) { return; } + final targetBuffer = state.activeBuffer; + if (targetBuffer == null || + targetBuffer.id != bufferId || + targetBuffer.revision != editRevision || + targetBuffer.text != text) { + return; + } try { - final reparsed = await _reparseWithDocumentBuffers(workspace, text); + final reparsed = await _reparseWithDocumentBuffers( + workspace, + targetBuffer, + ); final currentWorkspace = state.workspace; final currentBuffer = state.documentBuffers .where((buffer) => buffer.id == bufferId) @@ -3360,7 +3453,7 @@ class WorkspaceController extends Notifier { ); state = state.copyWith( workspace: nextWorkspace, - preview: _safePreview(nextWorkspace, text), + preview: _safePreview(nextWorkspace, currentBuffer), ); _recordActivePreviewRevision(); } on Object catch (error, stackTrace) { @@ -4330,9 +4423,8 @@ class WorkspaceController extends Notifier { )) { continue; } - final exists = workspace.kind == WorkspaceKind.singleMarkdown - ? await _service.pathExists(path) - : existingFiles.containsKey(path); + final exists = + existingFiles.containsKey(path) || await _service.pathExists(path); if (!_isCurrentWorkspaceRefresh(refreshRevision, workspace.id)) { return false; } @@ -4472,7 +4564,7 @@ class WorkspaceController extends Notifier { workspace: publishedWorkspace, preview: activeBuffer == null ? null - : _safePreview(publishedWorkspace, activeBuffer.text), + : _safePreview(publishedWorkspace, activeBuffer), documentBuffers: buffers, activeBufferId: activeBuffer?.id, isLoading: false, @@ -4568,7 +4660,7 @@ class WorkspaceController extends Notifier { ? Future.value(nextWorkspace.copyWith(markdown: null)) : _reparseWithDocumentBuffers( nextWorkspace, - activeBuffer.text, + activeBuffer, buffers: buffers, ); } @@ -4709,16 +4801,17 @@ class WorkspaceController extends Notifier { Future _reparseWithDocumentBuffers( Workspace workspace, - String source, { + DocumentBuffer target, { Iterable? buffers, }) async { + final sourceBuffers = buffers ?? state.documentBuffers; final overlaid = await _service.withDocumentSources(workspace, { - for (final buffer in buffers ?? state.documentBuffers) + for (final buffer in sourceBuffers) if (buffer.filePath != null) buffer.filePath!: buffer.text, - // Disk reloads and newly opened files may not yet be in the buffer list. - if (workspace.activeFilePath case final path?) path: source, + // Disk reloads and newly opened/saved files may not be in the list yet. + if (target.filePath case final path?) path: target.text, }); - return _service.reparseActive(overlaid, source); + return _service.reparseDocument(overlaid, target); } Future validateActive() async { @@ -4751,16 +4844,17 @@ class WorkspaceController extends Notifier { required bool rebuildPreview, }) async { final workspace = state.workspace; - if (workspace == null) { + final targetBuffer = state.activeBuffer; + if (workspace == null || targetBuffer == null) { return const ValidationOutcome(status: ValidationStatus.unavailable); } final sequence = ++_validationSequence; final buffers = List.of(state.documentBuffers); - final bufferId = state.activeBuffer?.id; + final bufferId = targetBuffer.id; final workspaceId = workspace.id; - final activeFilePath = workspace.activeFilePath; - final text = state.activeText; - final editRevision = state.activeBuffer?.revision ?? _editRevision; + final activeFilePath = targetBuffer.filePath; + final text = targetBuffer.text; + final editRevision = targetBuffer.revision; final operationRevision = _activeDocumentRevision; ValidationOutcome outcome(ValidationStatus status) => ValidationOutcome( status: status, @@ -4773,13 +4867,14 @@ class WorkspaceController extends Notifier { bool current() => ref.mounted && sequence == _validationSequence && - _isCurrentActiveDocument( - operationRevision, + _canPublishActiveDerivedContent( + operationRevision: operationRevision, workspaceId: workspaceId, - activeFilePath: activeFilePath, + bufferId: bufferId, + path: activeFilePath, + revision: editRevision, + source: text, ) && - state.activeText == text && - (state.activeBuffer?.revision ?? _editRevision) == editRevision && buffers.length == state.documentBuffers.length && buffers.every( (buffer) => state.documentBuffers.any( @@ -4793,7 +4888,7 @@ class WorkspaceController extends Notifier { try { final reparsed = await _reparseWithDocumentBuffers( workspace, - text, + targetBuffer, buffers: buffers, ); final currentWorkspace = state.workspace; @@ -4810,7 +4905,7 @@ class WorkspaceController extends Notifier { if (rebuildPreview) { state = state.copyWith( workspace: validatedWorkspace, - preview: _safePreview(reparsed, text), + preview: _safePreview(reparsed, targetBuffer), clearMessage: true, ); _recordActivePreviewRevision(); @@ -4819,9 +4914,13 @@ class WorkspaceController extends Notifier { workspace: validatedWorkspace, liveOutline: ActiveDocumentOutline( workspaceId: validatedWorkspace.id, - filePath: validatedWorkspace.activeFilePath, + bufferId: bufferId, + filePath: targetBuffer.filePath, source: text, - headings: _service.activeDocumentOutline(validatedWorkspace), + headings: _service.documentOutline( + validatedWorkspace, + targetBuffer, + ), ), clearMessage: true, ); @@ -4841,15 +4940,15 @@ class WorkspaceController extends Notifier { } } - PreviewDocument? _safePreview(Workspace workspace, String text) { + PreviewDocument? _safePreview(Workspace workspace, DocumentBuffer buffer) { try { - return _service.buildPreview(workspace, text); + return _service.buildDocumentPreview(workspace, buffer); } on Object { return PreviewDocument( title: '', modeLabel: '', compatibility: '', - blocks: [PreviewBlock(kind: PreviewBlockKind.code, text: text)], + blocks: [PreviewBlock(kind: PreviewBlockKind.code, text: buffer.text)], ); } } @@ -5013,6 +5112,7 @@ class WorkspaceController extends Notifier { bool _isCurrentActiveDocument( int operationRevision, { required String? workspaceId, + required String bufferId, required String? activeFilePath, }) { if (!ref.mounted) return false; @@ -5020,7 +5120,8 @@ class WorkspaceController extends Notifier { return operationRevision == _activeDocumentRevision && workspace != null && workspace.id == workspaceId && - workspace.activeFilePath == activeFilePath; + workspace.activeFilePath == activeFilePath && + state.activeBufferId == bufferId; } bool _canPublishActiveDerivedContent({ @@ -5035,6 +5136,7 @@ class WorkspaceController extends Notifier { return _isCurrentActiveDocument( operationRevision, workspaceId: workspaceId, + bufferId: bufferId, activeFilePath: path, ) && state.activeBufferId == bufferId && diff --git a/lib/src/workspace/workspace_model.dart b/lib/src/workspace/workspace_model.dart index b8bfe265..dffb99ef 100644 --- a/lib/src/workspace/workspace_model.dart +++ b/lib/src/workspace/workspace_model.dart @@ -46,26 +46,192 @@ extension DocumentKindAiSupport on DocumentKind { this == DocumentKind.writersideMarkdownTopic; } +extension DocumentKindSpellingSupport on DocumentKind { + bool get supportsSpelling => + this == DocumentKind.markdown || + this == DocumentKind.writersideMarkdownTopic || + this == DocumentKind.writersideXmlTopic; +} + class ActiveDocumentOutline { const ActiveDocumentOutline({ required this.workspaceId, + required this.bufferId, required this.filePath, required this.source, required this.headings, }); final String workspaceId; + final String bufferId; final String? filePath; final String source; final List headings; - bool matches(Workspace workspace, String activeSource) { + bool matches( + Workspace workspace, + DocumentBuffer? activeBuffer, + String activeSource, + ) { return workspaceId == workspace.id && - filePath == workspace.activeFilePath && + activeBuffer != null && + bufferId == activeBuffer.id && + filePath == activeBuffer.filePath && source == activeSource; } } +/// Derived routing information for one editor buffer in its workspace. +/// +/// A workspace describes the open project/container. This context describes +/// the actual document being edited and must therefore always be resolved from +/// a concrete [DocumentBuffer]. +class WorkspaceDocumentContext { + const WorkspaceDocumentContext({ + required this.kind, + required this.markdownMode, + required this.diskPath, + required this.parserPath, + this.writersideModule, + this.writersideTopic, + }); + + final DocumentKind kind; + final MarkdownMode markdownMode; + final String? diskPath; + final String parserPath; + final WritersideModule? writersideModule; + final WritersideTopic? writersideTopic; + + bool get isWritersideOwned => + writersideTopic != null || + (diskPath != null && + writersideModule != null && + kind != DocumentKind.markdown && + kind != DocumentKind.unknown && + kind != DocumentKind.image && + kind != DocumentKind.gitIgnore); +} + +/// Resolves the effective document type independently of [Workspace.kind]. +WorkspaceDocumentContext resolveWorkspaceDocumentContext( + Workspace workspace, + DocumentBuffer buffer, +) { + final path = buffer.filePath; + if (path == null) { + return const WorkspaceDocumentContext( + kind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + diskPath: null, + parserPath: '', + ); + } + + final normalizedPath = normalizePath(path); + final projectModules = workspace.writersideProject?.modules; + final modules = [ + if (projectModules != null) ...projectModules, + if (projectModules == null) + if (workspace.writersideModule case final module?) module, + ]; + for (final module in modules) { + for (final topic in module.topics) { + if (!p.equals(normalizePath(topic.filePath), normalizedPath)) continue; + return WorkspaceDocumentContext( + kind: topic.format == WritersideTopicFormat.markdown + ? DocumentKind.writersideMarkdownTopic + : DocumentKind.writersideXmlTopic, + markdownMode: topic.format == WritersideTopicFormat.markdown + ? MarkdownMode.writersideMarkdown + : MarkdownMode.commonMark, + diskPath: path, + parserPath: path, + writersideModule: module, + writersideTopic: topic, + ); + } + } + + final inventoryKind = workspace.files + .where( + (file) => p.equals(normalizePath(file.absolutePath), normalizedPath), + ) + .map((file) => file.kind) + .firstOrNull; + final kind = inventoryKind ?? documentKindForPath(path); + final owningModule = modules + .where((module) => _isWritersideOwnedFile(module, normalizedPath)) + .firstOrNull; + return WorkspaceDocumentContext( + kind: kind, + markdownMode: MarkdownMode.commonMark, + diskPath: path, + parserPath: path, + writersideModule: owningModule, + ); +} + +/// Existing path/name classification shared by scanning and document routing. +DocumentKind documentKindForPath(String path) { + final extension = p.extension(path).toLowerCase(); + final basename = p.basename(path); + if (basename == '.gitignore') return DocumentKind.gitIgnore; + if (extension == '.md' || extension == '.markdown') { + return DocumentKind.markdown; + } + if (extension == '.topic') return DocumentKind.writersideXmlTopic; + if (extension == '.tree') return DocumentKind.tree; + if (extension == '.cfg' || + basename == 'writerside.cfg' || + basename == 'project.ihp') { + return DocumentKind.config; + } + if (basename == 'v.list') return DocumentKind.variables; + if (basename == 'c.list') return DocumentKind.categories; + if ({'.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp'}.contains(extension)) { + return DocumentKind.image; + } + return isTextDocumentationPath(path) + ? DocumentKind.resource + : DocumentKind.unknown; +} + +bool _isWritersideOwnedFile(WritersideModule module, String path) { + final config = module.config; + final configured = { + config.filePath, + for (final source in module.sourceFiles.values) + if (source.path case final sourcePath?) sourcePath, + for (final source in module.referenceData.sources.values) + if (source.path case final sourcePath?) sourcePath, + for (final instance in module.instances) instance.sourceTreePath, + for (final instance in config.instances) + _writersideConfiguredPath(module.rootPath, instance.src), + if (config.varsFile case final configuredPath?) + _writersideConfiguredPath(module.rootPath, configuredPath), + if (config.categoriesFile case final configuredPath?) + _writersideConfiguredPath(module.rootPath, configuredPath), + if (config.instanceGroupsFile case final configuredPath?) + _writersideConfiguredPath(module.rootPath, configuredPath), + _writersideConfiguredPath( + module.rootPath, + p.join(config.buildConfigDir, 'buildprofiles.xml'), + ), + }; + return configured.any( + (candidate) => p.equals(normalizePath(candidate), path), + ); +} + +String _writersideConfiguredPath(String rootPath, String configuredPath) { + return normalizePath( + p.isAbsolute(configuredPath) + ? configuredPath + : p.join(rootPath, configuredPath), + ); +} + class DocumentFile { const DocumentFile({ required this.absolutePath, diff --git a/lib/src/workspace/workspace_service.dart b/lib/src/workspace/workspace_service.dart index 851ef6fc..e6c4bce8 100644 --- a/lib/src/workspace/workspace_service.dart +++ b/lib/src/workspace/workspace_service.dart @@ -32,6 +32,7 @@ import '../writerside/writerside_toc_presentation.dart'; import '../writerside/writerside_title_editor.dart'; import '../writerside/writerside_parsers.dart'; import '../writerside/writerside_document_parser.dart'; +import 'document_buffer.dart'; class WritersideTitleEditSession { const WritersideTitleEditSession({ @@ -1980,21 +1981,17 @@ class WorkspaceService { ); } - Future reparseActive(Workspace workspace, String source) async { - final active = workspace.activeFilePath ?? workspace.markdown?.filePath; - if (active == null) { - return workspace; - } - if (workspace.kind == WorkspaceKind.writersideModule) { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + final context = resolveWorkspaceDocumentContext(workspace, buffer); + final active = context.diskPath; + final module = context.writersideModule; + if (active != null && module != null && context.isWritersideOwned) { final project = workspace.writersideProject; final owner = project?.modulesByOrigin.entries - .where( - (entry) => - entry.value.topics.any( - (topic) => p.equals(topic.filePath, active), - ) || - _isWritersideProjectFile(entry.value, active), - ) + .where((entry) => p.equals(entry.value.rootPath, module.rootPath)) .firstOrNull; if (owner != null && !p.equals( @@ -2006,33 +2003,30 @@ class WorkspaceService { writersideProject: project!.withSelection(moduleId: owner.key), ); } - final module = workspace.writersideModule; - final topic = module?.topics - .where((item) => item.filePath == active) - .firstOrNull; - if (module != null && - (topic != null || _isWritersideProjectFile(module, active))) { - final updatedModule = await writersideService.load( - module.rootPath, - options: _useWorkspaceScanOptionsForWriterside ? scanOptions : null, - sourceOverrides: { - ...module.sourceOverrides, - normalizePath(active): source, - }, - ); - return _workspaceWithReparsedWritersideModule( - workspace, - module, - updatedModule, - rediscoverFileSymbols: p.equals(active, module.config.filePath), - ); - } - return workspace; + final selectedModule = workspace.writersideModule ?? module; + final updatedModule = await writersideService.load( + selectedModule.rootPath, + options: _useWorkspaceScanOptionsForWriterside ? scanOptions : null, + sourceOverrides: { + ...selectedModule.sourceOverrides, + normalizePath(active): buffer.text, + }, + ); + return _workspaceWithReparsedWritersideModule( + workspace, + selectedModule, + updatedModule, + activePath: active, + rediscoverFileSymbols: p.equals(active, selectedModule.config.filePath), + ); + } + if (context.kind != DocumentKind.markdown) { + return workspace.copyWith(markdown: null); } final markdown = await markdownParser.parseAsync( - filePath: active, - source: source, - mode: MarkdownMode.commonMark, + filePath: context.parserPath, + source: buffer.text, + mode: context.markdownMode, workspaceRoot: workspace.rootPath, sourceOverrides: workspace.sourceOverrides, ); @@ -2040,7 +2034,7 @@ class WorkspaceService { markdown: markdown, diagnostics: sortDiagnostics([ for (final diagnostic in workspace.diagnostics) - if (!p.equals(diagnostic.filePath, active) || + if (!p.equals(diagnostic.filePath, context.parserPath) || !diagnostic.code.startsWith('markdown.')) diagnostic, ...markdown.diagnostics, @@ -2052,6 +2046,7 @@ class WorkspaceService { Workspace workspace, WritersideModule previousModule, WritersideModule updatedModule, { + required String activePath, required bool rediscoverFileSymbols, }) async { final previousProject = workspace.writersideProject; @@ -2072,9 +2067,7 @@ class WorkspaceService { ]; return workspace.copyWith( markdown: updatedModule.topics - .where( - (topic) => p.equals(topic.filePath, workspace.activeFilePath ?? ''), - ) + .where((topic) => p.equals(topic.filePath, activePath)) .firstOrNull ?.markdown, writersideModule: updatedProject?.activeModule ?? updatedModule, @@ -2087,39 +2080,6 @@ class WorkspaceService { ); } - bool _isWritersideProjectFile(WritersideModule module, String filePath) { - final config = module.config; - final candidates = { - config.filePath, - for (final source in module.sourceFiles.values) - if (source.path case final path?) path, - for (final source in module.referenceData.sources.values) - if (source.path case final path?) path, - for (final instance in module.instances) instance.sourceTreePath, - for (final instance in config.instances) - _moduleConfiguredPath(module.rootPath, instance.src), - if (config.varsFile case final path?) - _moduleConfiguredPath(module.rootPath, path), - if (config.categoriesFile case final path?) - _moduleConfiguredPath(module.rootPath, path), - if (config.instanceGroupsFile case final path?) - _moduleConfiguredPath(module.rootPath, path), - _moduleConfiguredPath( - module.rootPath, - p.join(config.buildConfigDir, 'buildprofiles.xml'), - ), - }; - return candidates.any((candidate) => p.equals(candidate, filePath)); - } - - String _moduleConfiguredPath(String rootPath, String configuredPath) { - return normalizePath( - p.isAbsolute(configuredPath) - ? configuredPath - : p.join(rootPath, configuredPath), - ); - } - bool _isProjectDiagnostic( WritersideProject? project, Diagnostic diagnostic, @@ -2129,82 +2089,94 @@ class WorkspaceService { ) ?? false; - PreviewDocument? buildPreview(Workspace workspace, String source) { - final active = workspace.activeFilePath ?? workspace.markdown?.filePath; - if (active == null) { - return null; + PreviewDocument? buildDocumentPreview( + Workspace workspace, + DocumentBuffer buffer, + ) { + final context = resolveWorkspaceDocumentContext(workspace, buffer); + if (context.isWritersideOwned) { + return _buildWritersidePreview(workspace, context, buffer.text); } - if (workspace.kind == WorkspaceKind.writersideModule) { - return _buildWritersidePreview(workspace, active, source); + if (context.kind != DocumentKind.markdown) { + return null; } final currentMarkdown = workspace.markdown; if (currentMarkdown != null && - p.equals(currentMarkdown.filePath, active) && - currentMarkdown.source == source) { + p.equals(currentMarkdown.filePath, context.parserPath) && + currentMarkdown.source == buffer.text && + currentMarkdown.mode == context.markdownMode) { return previewBuilder.build(currentMarkdown); } final parsed = markdownParser.parse( - filePath: active, - source: source, - mode: MarkdownMode.commonMark, + filePath: context.parserPath, + source: buffer.text, + mode: context.markdownMode, workspaceRoot: workspace.rootPath, validateLocalReferences: false, ); return previewBuilder.build(parsed); } - List activeDocumentOutline(Workspace workspace) { - final active = workspace.activeFilePath ?? workspace.markdown?.filePath; - if (active == null) { - return const []; - } + List documentOutline( + Workspace workspace, + DocumentBuffer buffer, + ) { + final context = resolveWorkspaceDocumentContext(workspace, buffer); final markdown = workspace.markdown; - if (markdown != null && p.equals(markdown.filePath, active)) { + if (context.kind == DocumentKind.markdown && + markdown != null && + p.equals(markdown.filePath, context.parserPath) && + markdown.source == buffer.text && + markdown.mode == context.markdownMode) { return List.unmodifiable([ for (final heading in markdown.headings) DocumentOutlineHeading.fromMarkdown(heading), ]); } - if (workspace.kind != WorkspaceKind.writersideModule) { - return const []; + if (context.kind == DocumentKind.markdown) { + final parsed = markdownParser.parse( + filePath: context.parserPath, + source: buffer.text, + mode: context.markdownMode, + workspaceRoot: workspace.rootPath, + validateLocalReferences: false, + ); + return List.unmodifiable([ + for (final heading in parsed.headings) + DocumentOutlineHeading.fromMarkdown(heading), + ]); } - final topic = workspace.writersideModule?.topics - .where((candidate) => p.equals(candidate.filePath, active)) - .firstOrNull; - if (topic == null) { + if (context.writersideTopic == null) { return const []; } - return _buildWritersideDocument( - workspace, - active, - topic.document.source, - )?.outline ?? + return _buildWritersideDocument(workspace, context, buffer.text)?.outline ?? const []; } /// Builds preview data without running Markdown parsing on Flutter's UI /// isolate. An already-current workspace parse is reused when available. - Future buildPreviewAsync( + Future buildDocumentPreviewAsync( Workspace workspace, - String source, + DocumentBuffer buffer, ) async { - final active = workspace.activeFilePath ?? workspace.markdown?.filePath; - if (active == null) { - return null; + final context = resolveWorkspaceDocumentContext(workspace, buffer); + if (context.isWritersideOwned) { + return _buildWritersidePreview(workspace, context, buffer.text); } - if (workspace.kind == WorkspaceKind.writersideModule) { - return _buildWritersidePreview(workspace, active, source); + if (context.kind != DocumentKind.markdown) { + return null; } final currentMarkdown = workspace.markdown; if (currentMarkdown != null && - p.equals(currentMarkdown.filePath, active) && - currentMarkdown.source == source) { + p.equals(currentMarkdown.filePath, context.parserPath) && + currentMarkdown.source == buffer.text && + currentMarkdown.mode == context.markdownMode) { return previewBuilder.build(currentMarkdown); } final parsed = await markdownParser.parseAsync( - filePath: active, - source: source, - mode: MarkdownMode.commonMark, + filePath: context.parserPath, + source: buffer.text, + mode: context.markdownMode, workspaceRoot: workspace.rootPath, validateLocalReferences: false, ); @@ -2213,15 +2185,15 @@ class WorkspaceService { PreviewDocument? _buildWritersidePreview( Workspace workspace, - String active, + WorkspaceDocumentContext context, String source, ) { - final document = _buildWritersideDocument(workspace, active, source); + final document = _buildWritersideDocument(workspace, context, source); if (document != null) { return const BusyMarkPreviewBuilder().build(document); } return PreviewDocument( - title: p.basename(active), + title: p.basename(context.parserPath), modeLabel: '', compatibility: '', blocks: [PreviewBlock(kind: PreviewBlockKind.code, text: source)], @@ -2230,17 +2202,13 @@ class WorkspaceService { BusyDocument? _buildWritersideDocument( Workspace workspace, - String active, + WorkspaceDocumentContext context, String source, ) { - final module = workspace.writersideModule; - if (module == null) { - return null; - } - final originalTopic = module.topics - .where((item) => item.filePath == active) - .firstOrNull; - if (originalTopic == null) { + final module = context.writersideModule; + final originalTopic = context.writersideTopic; + final active = context.diskPath; + if (module == null || originalTopic == null || active == null) { return null; } final topic = originalTopic.document.source == source @@ -2256,8 +2224,14 @@ class WorkspaceService { source: source, topicsRoot: originalTopic.topicRoot, ); + final project = workspace.writersideProject; + final selectedProjectInstance = + project != null && + p.equals(project.activeModule?.rootPath ?? '', module.rootPath) + ? project.activeInstance + : null; final instance = - workspace.writersideProject?.activeInstance ?? + selectedProjectInstance ?? module.instances .where( (candidate) => @@ -2276,7 +2250,7 @@ class WorkspaceService { topic: topic, instance: instance, modulesByOrigin: - workspace.writersideProject?.modulesByOrigin ?? + project?.modulesByOrigin ?? {if (module.config.moduleName case final name?) name: module}, ), ); @@ -2445,7 +2419,7 @@ class WorkspaceService { return DocumentFile( absolutePath: path, relativePath: normalizedRelative(rootPath, path), - kind: _documentKind(path), + kind: documentKindForPath(path), size: stat.size, lastModified: stat.modified, ); @@ -2517,46 +2491,6 @@ class WorkspaceService { } } - DocumentKind _documentKind(String path) { - final extension = p.extension(path).toLowerCase(); - if (p.basename(path) == '.gitignore') { - return DocumentKind.gitIgnore; - } - if (extension == '.md' || extension == '.markdown') { - return DocumentKind.markdown; - } - if (extension == '.topic') { - return DocumentKind.writersideXmlTopic; - } - if (extension == '.tree') { - return DocumentKind.tree; - } - if (extension == '.cfg' || - p.basename(path) == 'writerside.cfg' || - p.basename(path) == 'project.ihp') { - return DocumentKind.config; - } - if (p.basename(path) == 'v.list') { - return DocumentKind.variables; - } - if (p.basename(path) == 'c.list') { - return DocumentKind.categories; - } - if ({ - '.png', - '.jpg', - '.jpeg', - '.gif', - '.svg', - '.webp', - }.contains(extension)) { - return DocumentKind.image; - } - return isTextDocumentationPath(path) - ? DocumentKind.resource - : DocumentKind.unknown; - } - WorkspaceScanOptions get _workspaceDisplayScanOptions => WorkspaceScanOptions( maxParsedFileBytes: scanOptions.maxParsedFileBytes, maxParsedDocuments: scanOptions.maxParsedDocuments, diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 55fb617a..0eeeef62 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -246,6 +246,30 @@ install(DIRECTORY "${VISUALIZATION_WEB_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/busymark/visualization" COMPONENT Runtime) +# The ordinary package contains catalog metadata and licensing only. Language +# pairs are installed explicitly into persistent application data. +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../assets/spelling/" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/busymark/spelling" + COMPONENT Runtime + PATTERN "*.aff" EXCLUDE + PATTERN "*.dic" EXCLUDE) + +# Native-code dependency notices must travel with the relocatable application; +# references to source-tree paths are not sufficient in a packaged install. +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/../packages/busymark_spellcheck_native/LICENSE" + "${CMAKE_CURRENT_SOURCE_DIR}/../packages/busymark_spellcheck_native/DEPENDENCIES.md" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/licenses/busymark-spellcheck" + COMPONENT Runtime) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/licenses/busymark-spellcheck" + RENAME "Apache-2.0.txt" + COMPONENT Runtime) +install(DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}/../packages/busymark_spellcheck_native/third_party/hunspell/licenses/" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/licenses/busymark-spellcheck/hunspell" + COMPONENT Runtime) + install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) diff --git a/linux/io.busystack.busymark.metainfo.xml b/linux/io.busystack.busymark.metainfo.xml index 5cdbda3c..e76cdb5c 100644 --- a/linux/io.busystack.busymark.metainfo.xml +++ b/linux/io.busystack.busymark.metainfo.xml @@ -87,6 +87,7 @@ https://github.com/busystack/busymark/issues + diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index a33eeb0d..9f5a6b80 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -2248,7 +2248,6 @@ struct NativeMenuHandlerData; struct NativeMenuSession { NativeMenuHandlerData* owner; gint64 id; - size_t entry_count; GtkWidget* menu; GMenu* model; GSimpleActionGroup* action_group; @@ -2362,25 +2361,17 @@ static void native_menu_action_activated_cb(GSimpleAction* action, 1; } -static void native_menu_selection_activated_cb(GSimpleAction* action, - GVariant* parameter, - gpointer user_data) { - if (parameter == nullptr || - !g_variant_is_of_type(parameter, G_VARIANT_TYPE_STRING)) { - return; - } - const gchar* target = g_variant_get_string(parameter, nullptr); - gchar* end = nullptr; - const guint64 parsed = g_ascii_strtoull(target, &end, 10); - auto* session = static_cast(user_data); - if (target[0] == '\0' || end == nullptr || *end != '\0' || - parsed > static_cast(G_MAXINT) || - parsed >= session->entry_count) { +static void native_menu_check_activated_cb(GSimpleAction* action, + GVariant*, + gpointer user_data) { + g_autoptr(GVariant) state = g_action_get_state(G_ACTION(action)); + if (state == nullptr || + !g_variant_is_of_type(state, G_VARIANT_TYPE_BOOLEAN)) { return; } - - g_simple_action_set_state(action, parameter); - session->pending_selected_index = static_cast(parsed); + g_simple_action_set_state( + action, g_variant_new_boolean(!g_variant_get_boolean(state))); + native_menu_action_activated_cb(action, nullptr, user_data); } static gboolean native_menu_dismiss_active(NativeMenuHandlerData* data, @@ -2576,6 +2567,7 @@ static gboolean validate_native_menu_entries(FlValue* entries, gboolean enabled = TRUE; gboolean checkable = FALSE; gboolean selected = FALSE; + gboolean mutually_exclusive = FALSE; if (entry == nullptr || fl_value_get_type(entry) != FL_VALUE_TYPE_MAP || !fl_lookup_optional_bool_with_default(entry, "separator", FALSE, &separator) || @@ -2585,6 +2577,9 @@ static gboolean validate_native_menu_entries(FlValue* entries, &checkable) || !fl_lookup_optional_bool_with_default(entry, "selected", FALSE, &selected) || + !fl_lookup_optional_bool_with_default(entry, "mutuallyExclusive", + FALSE, + &mutually_exclusive) || (!separator && fl_lookup_string_arg(entry, "label") == nullptr) || (fl_value_lookup_string(entry, "icon") != nullptr && fl_value_get_type(fl_value_lookup_string(entry, "icon")) != @@ -2610,7 +2605,7 @@ static gboolean validate_native_menu_entries(FlValue* entries, if (!separator) { command_count++; } - if (!separator && checkable) { + if (!separator && checkable && mutually_exclusive) { if (!in_checkable_run) { checkable_run_selected_count = 0; checkable_run_has_disabled_entry = FALSE; @@ -2677,14 +2672,13 @@ static void build_native_menu_model(FlValue* entries, section_length = 0; }; - for (size_t index = 0; index < fl_value_get_length(entries);) { + for (size_t index = 0; index < fl_value_get_length(entries); index++) { FlValue* entry = fl_value_get_list_value(entries, index); gboolean separator = FALSE; fl_lookup_optional_bool_with_default(entry, "separator", FALSE, &separator); if (separator) { flush_section(); - index++; (*next_index)++; continue; } @@ -2715,84 +2709,22 @@ static void build_native_menu_model(FlValue* entries, g_menu_item_new_submenu(literal_label, G_MENU_MODEL(submenu)); g_menu_append_item(section, item); section_length++; - index++; continue; } - if (checkable) { - const size_t run_start = index; - size_t run_end = run_start; - g_autofree gchar* selected_target = g_strdup(""); - while (run_end < fl_value_get_length(entries)) { - FlValue* run_entry = fl_value_get_list_value(entries, run_end); - gboolean run_separator = FALSE; - gboolean run_checkable = FALSE; - gboolean run_selected = FALSE; - fl_lookup_optional_bool_with_default( - run_entry, "separator", FALSE, &run_separator); - fl_lookup_optional_bool_with_default( - run_entry, "checkable", FALSE, &run_checkable); - if (run_separator || !run_checkable) { - break; - } - fl_lookup_optional_bool_with_default( - run_entry, "selected", FALSE, &run_selected); - if (run_selected) { - g_free(selected_target); - selected_target = g_strdup_printf("%zu", entry_index + run_end - run_start); - } - run_end++; - } - - g_autofree gchar* group_action_name = - g_strdup_printf("select-group-%zu", entry_index); - GSimpleAction* group_action = g_simple_action_new_stateful( - group_action_name, G_VARIANT_TYPE_STRING, - g_variant_new_string(selected_target)); - g_simple_action_set_enabled(group_action, ancestors_enabled); - g_signal_connect(group_action, "activate", - G_CALLBACK(native_menu_selection_activated_cb), - session); - g_action_map_add_action(G_ACTION_MAP(session->action_group), - G_ACTION(group_action)); - g_autofree gchar* detailed_group_action = g_strdup_printf( - "%s.%s", kNativeMenuActionNamespace, group_action_name); - - for (size_t run_index = run_start; run_index < run_end; run_index++) { - FlValue* run_entry = fl_value_get_list_value(entries, run_index); - const gchar* run_label = fl_lookup_string_arg(run_entry, "label"); - g_autofree gchar* run_literal_label = - escape_native_menu_label(run_label); - const gchar* run_icon = fl_lookup_string_arg(run_entry, "icon"); - const gchar* run_shortcut = - fl_lookup_string_arg(run_entry, "shortcut"); - g_autofree gchar* target = g_strdup_printf("%zu", entry_index + run_index - run_start); - g_autoptr(GMenuItem) item = g_menu_item_new(run_literal_label, nullptr); - g_menu_item_set_action_and_target_value( - item, detailed_group_action, g_variant_new_string(target)); - if (run_icon != nullptr && run_icon[0] != '\0') { - g_autoptr(GIcon) icon = - create_native_menu_icon(run_icon, run_entry); - g_menu_item_set_icon(item, icon); - } - if (run_shortcut != nullptr && run_shortcut[0] != '\0') { - set_menu_item_accelerator(item, run_shortcut); - } - g_menu_append_item(section, item); - section_length++; - } - g_object_unref(group_action); - *next_index += run_end - run_start - 1; - index = run_end; - continue; - } - g_autofree gchar* action_name = g_strdup_printf("select-%zu", entry_index); - GSimpleAction* action = g_simple_action_new(action_name, nullptr); + GSimpleAction* action = checkable + ? g_simple_action_new_stateful( + action_name, nullptr, + g_variant_new_boolean(selected)) + : g_simple_action_new(action_name, nullptr); g_simple_action_set_enabled(action, ancestors_enabled && enabled); g_object_set_data(G_OBJECT(action), kNativeMenuActionIndexKey, GINT_TO_POINTER(static_cast(entry_index) + 1)); - g_signal_connect(action, "activate", - G_CALLBACK(native_menu_action_activated_cb), session); + g_signal_connect( + action, "activate", + G_CALLBACK(checkable ? native_menu_check_activated_cb + : native_menu_action_activated_cb), + session); g_action_map_add_action(G_ACTION_MAP(session->action_group), G_ACTION(action)); @@ -2810,7 +2742,6 @@ static void build_native_menu_model(FlValue* entries, g_menu_append_item(section, item); g_object_unref(action); section_length++; - index++; } flush_section(); g_object_unref(section); @@ -2945,7 +2876,6 @@ static void show_native_menu(NativeMenuHandlerData* data, auto* session = g_new0(NativeMenuSession, 1); session->owner = data; session->id = session_id; - session->entry_count = entry_count; session->pending_selected_index = -1; session->method_call = FL_METHOD_CALL(g_object_ref(G_OBJECT(method_call))); diff --git a/packages/busymark_spellcheck_native/.gitignore b/packages/busymark_spellcheck_native/.gitignore new file mode 100644 index 00000000..dd5eb989 --- /dev/null +++ b/packages/busymark_spellcheck_native/.gitignore @@ -0,0 +1,31 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.flutter-plugins-dependencies +/build/ +/coverage/ diff --git a/packages/busymark_spellcheck_native/.metadata b/packages/busymark_spellcheck_native/.metadata new file mode 100644 index 00000000..b56245c8 --- /dev/null +++ b/packages/busymark_spellcheck_native/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "9584c6713b324636289d067944a46fd6b49df14b" + channel: "stable" + +project_type: package_ffi + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: android + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: ios + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: linux + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: macos + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: web + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + - platform: windows + create_revision: 9584c6713b324636289d067944a46fd6b49df14b + base_revision: 9584c6713b324636289d067944a46fd6b49df14b + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/busymark_spellcheck_native/CHANGELOG.md b/packages/busymark_spellcheck_native/CHANGELOG.md new file mode 100644 index 00000000..a6258a1d --- /dev/null +++ b/packages/busymark_spellcheck_native/CHANGELOG.md @@ -0,0 +1,4 @@ +## 0.0.1 + +* Add the pinned Hunspell 1.7.3 engine, generated FFI bindings, strict charset + conversion, Unicode word boundaries, suggestions, and custom-word support. diff --git a/packages/busymark_spellcheck_native/DEPENDENCIES.md b/packages/busymark_spellcheck_native/DEPENDENCIES.md new file mode 100644 index 00000000..0d4b7571 --- /dev/null +++ b/packages/busymark_spellcheck_native/DEPENDENCIES.md @@ -0,0 +1,14 @@ +# Native dependency inputs + +BusyMark embeds Hunspell instead of using a host installation. + +- Engine: Hunspell 1.7.3 +- Revision: `v1.7.3` (`c5f98152a274e25b5107101104bef632b83a0cc9`) +- Source: `https://github.com/hunspell/hunspell/archive/refs/tags/v1.7.3.tar.gz` +- SHA-256: `933be3dac6fd55f6e752331a170efb7e33800e40fae1156d8434cc8c85379a1b` +- Vendored component: `third_party/hunspell/src/hunspell/` plus upstream + license files + +The package build hook compiles the vendored engine and BusyMark wrapper into +one bundled native code asset. Pango and GLib come from the GTK SDK/runtime used +to build and run BusyMark. diff --git a/packages/busymark_spellcheck_native/LICENSE b/packages/busymark_spellcheck_native/LICENSE new file mode 100644 index 00000000..3b739a69 --- /dev/null +++ b/packages/busymark_spellcheck_native/LICENSE @@ -0,0 +1,7 @@ +BusyMark's native spelling package is distributed under the Apache License, +Version 2.0. The complete license text is in the repository root at +`../../LICENSE`. + +The embedded Hunspell sources retain their upstream MPL/LGPL/GPL tri-license. +Those license texts and notices are in `third_party/hunspell/licenses/` and are +not replaced by BusyMark's Apache license. diff --git a/packages/busymark_spellcheck_native/README.md b/packages/busymark_spellcheck_native/README.md new file mode 100644 index 00000000..28e98da4 --- /dev/null +++ b/packages/busymark_spellcheck_native/README.md @@ -0,0 +1,47 @@ +# busymark_spellcheck_native + +BusyMark local Hunspell and Unicode spell-checking native component. + +## Building + +The package uses a Dart native-assets build hook to compile its C wrapper and +the vendored, checksum-pinned Hunspell 1.7.3 sources. It links to Pango and GLib +from the same GTK SDK/runtime as BusyMark. It does not invoke an executable or +use a host-installed Hunspell library or dictionary. + +## Project structure + +This template uses the following structure: + +* `src`: Contains the native source code, and a CmakeFile.txt file for building + that source code into a dynamic library. + +* `lib`: Contains the Dart code that defines the API of the plugin, and which + calls into the native code using `dart:ffi`. + +* `hook`: Contains `build.dart`, which performs the native-assets build. + +## Building and bundling native code + +`build.dart` does the building of native components. + +Bundling is done by Flutter based on the output from `build.dart`. + +## Binding to native code + +To use the native code, bindings in Dart are needed. +To avoid writing these by hand, they are generated from the header file +(`src/busymark_spellcheck_native.h`) by `package:ffigen`. +Regenerate the bindings by running `dart run ffigen --config ffigen.yaml`. + +## Invoking native code + +Very short-running native functions can be directly invoked from any isolate. +BusyMark owns handles on its long-lived spelling isolate. Callers copy returned +suggestions into Dart strings before the wrapper releases their native storage. + +## Flutter help + +For help getting started with Flutter, view our +[online documentation](https://docs.flutter.dev), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/busymark_spellcheck_native/analysis_options.yaml b/packages/busymark_spellcheck_native/analysis_options.yaml new file mode 100644 index 00000000..ff39a72e --- /dev/null +++ b/packages/busymark_spellcheck_native/analysis_options.yaml @@ -0,0 +1,14 @@ +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: + - build/** + - android/** + - ios/** + - web/** + - windows/** + - macos/** + - linux/** + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/busymark_spellcheck_native/ffigen.yaml b/packages/busymark_spellcheck_native/ffigen.yaml new file mode 100644 index 00000000..4ef742a3 --- /dev/null +++ b/packages/busymark_spellcheck_native/ffigen.yaml @@ -0,0 +1,25 @@ +# Run with `dart run ffigen --config ffigen.yaml`. +name: BusymarkSpellcheckNativeBindings +description: | + Bindings for `src/busymark_spellcheck_native.h`. + + Regenerate bindings with `dart run ffigen --config ffigen.yaml`. +output: 'lib/busymark_spellcheck_native_bindings_generated.dart' +headers: + entry-points: + - 'src/busymark_spellcheck_native.h' + include-directives: + - 'src/busymark_spellcheck_native.h' +ffi-native: +functions: + include: + - 'busy_spell_.*' +structs: + include: + - 'BusySpellTokenRange' +enums: + include: + - 'BusySpellStatus' +comments: + style: any + length: full diff --git a/packages/busymark_spellcheck_native/hook/build.dart b/packages/busymark_spellcheck_native/hook/build.dart new file mode 100644 index 00000000..3d067609 --- /dev/null +++ b/packages/busymark_spellcheck_native/hook/build.dart @@ -0,0 +1,55 @@ +import 'dart:io'; + +import 'package:code_assets/code_assets.dart'; +import 'package:native_toolchain_c/native_toolchain_c.dart'; +import 'package:hooks/hooks.dart'; + +void main(List args) async { + await build(args, (input, output) async { + if (input.config.code.targetOS != OS.linux) { + throw UnsupportedError( + 'BusyMark spelling currently targets the GTK Linux application.', + ); + } + final pkgConfig = await Process.run('pkg-config', [ + '--cflags', + 'pango', + 'glib-2.0', + ]); + if (pkgConfig.exitCode != 0) { + throw StateError( + 'Pango/GLib development files are required: ${pkgConfig.stderr}', + ); + } + final cflags = (pkgConfig.stdout as String) + .trim() + .split(RegExp(r'\s+')) + .where((value) => value.isNotEmpty) + .toList(); + final packageName = input.packageName; + final cbuilder = CBuilder.library( + name: packageName, + assetName: '${packageName}_bindings_generated.dart', + sources: [ + 'src/$packageName.cpp', + 'third_party/hunspell/src/hunspell/affentry.cxx', + 'third_party/hunspell/src/hunspell/affixmgr.cxx', + 'third_party/hunspell/src/hunspell/csutil.cxx', + 'third_party/hunspell/src/hunspell/filemgr.cxx', + 'third_party/hunspell/src/hunspell/hashmgr.cxx', + 'third_party/hunspell/src/hunspell/hunspell.cxx', + 'third_party/hunspell/src/hunspell/hunzip.cxx', + 'third_party/hunspell/src/hunspell/phonet.cxx', + 'third_party/hunspell/src/hunspell/replist.cxx', + 'third_party/hunspell/src/hunspell/suggestmgr.cxx', + ], + includes: ['src', 'third_party/hunspell/src/hunspell'], + flags: cflags, + libraries: ['pango-1.0', 'gobject-2.0', 'glib-2.0'], + language: .cpp, + std: 'c++20', + defines: const {'BUILDING_LIBHUNSPELL': null}, + ); + await cbuilder.run(input: input, output: output); + }); +} diff --git a/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native.dart b/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native.dart new file mode 100644 index 00000000..8248678a --- /dev/null +++ b/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native.dart @@ -0,0 +1,3 @@ +library; + +export 'src/native_dictionary.dart'; diff --git a/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native_bindings_generated.dart b/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native_bindings_generated.dart new file mode 100644 index 00000000..68557a2d --- /dev/null +++ b/packages/busymark_spellcheck_native/lib/busymark_spellcheck_native_bindings_generated.dart @@ -0,0 +1,146 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint, unused_import +import 'dart:ffi' as ffi; + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer>, + ffi.Pointer>, + ) +>() +external int busy_spell_open( + ffi.Pointer aff_path_utf8, + ffi.Pointer dic_path_utf8, + ffi.Pointer> out_handle, + ffi.Pointer> out_error, +); + +@ffi.Native)>() +external void busy_spell_close(ffi.Pointer handle); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer>, + ) +>() +external int busy_spell_check( + ffi.Pointer handle, + ffi.Pointer word_utf8, + ffi.Pointer> out_error, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer>>, + ffi.Pointer, + ffi.Pointer>, + ) +>() +external int busy_spell_suggest( + ffi.Pointer handle, + ffi.Pointer word_utf8, + ffi.Pointer>> out_items, + ffi.Pointer out_count, + ffi.Pointer> out_error, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer>, + ) +>() +external int busy_spell_add( + ffi.Pointer handle, + ffi.Pointer word_utf8, + ffi.Pointer> out_error, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer>, + ffi.Pointer>, + ) +>() +external int busy_spell_dictionary_encoding( + ffi.Pointer handle, + ffi.Pointer> out_encoding, + ffi.Pointer> out_error, +); + +/// Calls Pango with the complete UTF-8 prose run. The C bitfield attributes are +/// copied into stable byte/character ranges rather than exposed through FFI. +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer>, + ffi.Pointer, + ffi.Pointer>, + ) +>() +external int busy_spell_tokenize( + ffi.Pointer handle, + ffi.Pointer prose_utf8, + ffi.Pointer language_utf8, + ffi.Pointer> out_ranges, + ffi.Pointer out_count, + ffi.Pointer> out_error, +); + +@ffi.Native>, ffi.Size)>() +external void busy_spell_free_suggestions( + ffi.Pointer> items, + int count, +); + +@ffi.Native)>() +external void busy_spell_free_token_ranges( + ffi.Pointer ranges, +); + +@ffi.Native)>() +external void busy_spell_free_string(ffi.Pointer value); + +final class BusySpellHandle extends ffi.Opaque {} + +final class BusySpellTokenRange extends ffi.Struct { + @ffi.Uint32() + external int utf8_start; + + @ffi.Uint32() + external int utf8_end; + + @ffi.Uint32() + external int character_start; + + @ffi.Uint32() + external int character_end; +} + +enum BusySpellStatus { + BUSY_SPELL_ERROR(-1), + BUSY_SPELL_REJECTED(0), + BUSY_SPELL_ACCEPTED(1); + + final int value; + const BusySpellStatus(this.value); + + static BusySpellStatus fromValue(int value) => switch (value) { + -1 => BUSY_SPELL_ERROR, + 0 => BUSY_SPELL_REJECTED, + 1 => BUSY_SPELL_ACCEPTED, + _ => throw ArgumentError('Unknown value for BusySpellStatus: $value'), + }; +} diff --git a/packages/busymark_spellcheck_native/lib/src/native_dictionary.dart b/packages/busymark_spellcheck_native/lib/src/native_dictionary.dart new file mode 100644 index 00000000..a979ea7d --- /dev/null +++ b/packages/busymark_spellcheck_native/lib/src/native_dictionary.dart @@ -0,0 +1,260 @@ +import 'dart:convert'; +import 'dart:ffi' as ffi; + +import 'package:ffi/ffi.dart'; + +import '../busymark_spellcheck_native_bindings_generated.dart' as bindings; + +enum NativeSpellResult { accepted, rejected } + +final class NativeSpellException implements Exception { + const NativeSpellException(this.message); + + final String message; + + @override + String toString() => 'NativeSpellException: $message'; +} + +final class NativeWordRange { + const NativeWordRange({ + required this.utf8Start, + required this.utf8End, + required this.characterStart, + required this.characterEnd, + }); + + final int utf8Start; + final int utf8End; + final int characterStart; + final int characterEnd; +} + +/// Owns one native Hunspell handle. Instances stay in the spelling worker +/// isolate; no pointer is exposed through the application API. +final class NativeSpellDictionary { + NativeSpellDictionary._(this._handle); + + factory NativeSpellDictionary.open({ + required String affPath, + required String dicPath, + }) { + final aff = affPath.toNativeUtf8(); + final dic = dicPath.toNativeUtf8(); + final outHandle = calloc>(); + final outError = calloc>(); + try { + final status = bindings.busy_spell_open( + aff.cast(), + dic.cast(), + outHandle, + outError, + ); + if (status == bindings.BusySpellStatus.BUSY_SPELL_ERROR.value || + outHandle.value == ffi.nullptr) { + throw NativeSpellException(_takeError(outError)); + } + return NativeSpellDictionary._(outHandle.value); + } finally { + malloc.free(aff); + malloc.free(dic); + _freePendingError(outError); + calloc.free(outError); + calloc.free(outHandle); + } + } + + ffi.Pointer _handle; + + bool get isClosed => _handle == ffi.nullptr; + + String get encoding { + _requireOpen(); + final outValue = calloc>(); + final outError = calloc>(); + try { + final status = bindings.busy_spell_dictionary_encoding( + _handle, + outValue, + outError, + ); + if (status == bindings.BusySpellStatus.BUSY_SPELL_ERROR.value || + outValue.value == ffi.nullptr) { + throw NativeSpellException(_takeError(outError)); + } + return outValue.value.cast().toDartString(); + } finally { + if (outValue.value != ffi.nullptr) { + bindings.busy_spell_free_string(outValue.value); + } + _freePendingError(outError); + calloc.free(outValue); + calloc.free(outError); + } + } + + NativeSpellResult check(String word) { + _requireOpen(); + final nativeWord = word.toNativeUtf8(); + final outError = calloc>(); + try { + final result = bindings.busy_spell_check( + _handle, + nativeWord.cast(), + outError, + ); + if (result == bindings.BusySpellStatus.BUSY_SPELL_ACCEPTED.value) { + return NativeSpellResult.accepted; + } + if (result == bindings.BusySpellStatus.BUSY_SPELL_REJECTED.value) { + return NativeSpellResult.rejected; + } + throw NativeSpellException(_takeError(outError)); + } finally { + malloc.free(nativeWord); + _freePendingError(outError); + calloc.free(outError); + } + } + + List suggest(String word) { + _requireOpen(); + final nativeWord = word.toNativeUtf8(); + final outItems = calloc>>(); + final outCount = calloc(); + final outError = calloc>(); + try { + final status = bindings.busy_spell_suggest( + _handle, + nativeWord.cast(), + outItems, + outCount, + outError, + ); + if (status == bindings.BusySpellStatus.BUSY_SPELL_ERROR.value) { + throw NativeSpellException(_takeError(outError)); + } + return List.generate( + outCount.value, + (index) => outItems.value[index].cast().toDartString(), + growable: false, + ); + } finally { + if (outItems.value != ffi.nullptr) { + bindings.busy_spell_free_suggestions(outItems.value, outCount.value); + } + _freePendingError(outError); + malloc.free(nativeWord); + calloc.free(outItems); + calloc.free(outCount); + calloc.free(outError); + } + } + + void add(String word) { + _requireOpen(); + final nativeWord = word.toNativeUtf8(); + final outError = calloc>(); + try { + final status = bindings.busy_spell_add( + _handle, + nativeWord.cast(), + outError, + ); + if (status == bindings.BusySpellStatus.BUSY_SPELL_ERROR.value) { + throw NativeSpellException(_takeError(outError)); + } + } finally { + malloc.free(nativeWord); + _freePendingError(outError); + calloc.free(outError); + } + } + + List tokenize(String prose, {required String language}) { + _requireOpen(); + final nativeProse = prose.toNativeUtf8(); + final nativeLanguage = language.toNativeUtf8(); + final outRanges = calloc>(); + final outCount = calloc(); + final outError = calloc>(); + try { + final status = bindings.busy_spell_tokenize( + _handle, + nativeProse.cast(), + nativeLanguage.cast(), + outRanges, + outCount, + outError, + ); + if (status == bindings.BusySpellStatus.BUSY_SPELL_ERROR.value) { + throw NativeSpellException(_takeError(outError)); + } + return List.generate(outCount.value, (index) { + final range = outRanges.value[index]; + return NativeWordRange( + utf8Start: range.utf8_start, + utf8End: range.utf8_end, + characterStart: range.character_start, + characterEnd: range.character_end, + ); + }, growable: false); + } finally { + if (outRanges.value != ffi.nullptr) { + bindings.busy_spell_free_token_ranges(outRanges.value); + } + _freePendingError(outError); + malloc.free(nativeProse); + malloc.free(nativeLanguage); + calloc.free(outRanges); + calloc.free(outCount); + calloc.free(outError); + } + } + + void close() { + if (_handle == ffi.nullptr) return; + bindings.busy_spell_close(_handle); + _handle = ffi.nullptr; + } + + void _requireOpen() { + if (isClosed) { + throw const NativeSpellException('Dictionary handle is closed'); + } + } + + static String _takeError(ffi.Pointer> outError) { + if (outError.value == ffi.nullptr) return 'Unknown native spelling error'; + final message = outError.value.cast().toDartString(); + bindings.busy_spell_free_string(outError.value); + outError.value = ffi.nullptr; + return message; + } + + static void _freePendingError(ffi.Pointer> outError) { + if (outError.value == ffi.nullptr) return; + bindings.busy_spell_free_string(outError.value); + outError.value = ffi.nullptr; + } +} + +/// Explicit UTF-8 byte-to-Dart UTF-16 mapping for offsets returned by Pango. +List nativeUtf8BoundaryToUtf16(String text) { + final mapping = List.filled(utf8.encode(text).length + 1, -1); + var byteOffset = 0; + var utf16Offset = 0; + mapping[0] = 0; + for (final rune in text.runes) { + byteOffset += rune <= 0x7f + ? 1 + : rune <= 0x7ff + ? 2 + : rune <= 0xffff + ? 3 + : 4; + utf16Offset += rune > 0xffff ? 2 : 1; + mapping[byteOffset] = utf16Offset; + } + return mapping; +} diff --git a/packages/busymark_spellcheck_native/pubspec.yaml b/packages/busymark_spellcheck_native/pubspec.yaml new file mode 100644 index 00000000..c95342ca --- /dev/null +++ b/packages/busymark_spellcheck_native/pubspec.yaml @@ -0,0 +1,17 @@ +name: busymark_spellcheck_native +description: "BusyMark local Hunspell and Unicode spell-checking native component." +version: 0.1.0 + +environment: + sdk: ">=3.12.1 <4.0.0" + +dependencies: + code_assets: ^1.1.0 + hooks: ^2.0.0 + native_toolchain_c: ^0.19.0 + ffi: ^2.2.0 + +dev_dependencies: + ffigen: ^20.1.1 + flutter_lints: ^6.0.0 + test: ^1.28.0 diff --git a/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.cpp b/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.cpp new file mode 100644 index 00000000..dfc7d240 --- /dev/null +++ b/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.cpp @@ -0,0 +1,633 @@ +#include "busymark_spellcheck_native.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hunspell.h" + +namespace { + +constexpr size_t kMaximumInputBytes = 64 * 1024; + +struct GFree { + void operator()(void* value) const { g_free(value); } +}; + +template +using GOwned = std::unique_ptr; + +struct BusySpellHandleImpl { + Hunhandle* hunspell = nullptr; + std::string encoding; + std::unordered_set word_chars; + + ~BusySpellHandleImpl() { + if (hunspell != nullptr) Hunspell_destroy(hunspell); + } +}; + +struct HunspellSuggestionOwner { + explicit HunspellSuggestionOwner(Hunhandle* value) : hunspell(value) {} + + Hunhandle* hunspell; + char** items = nullptr; + int count = 0; + + ~HunspellSuggestionOwner() { + if (items != nullptr) Hunspell_free_list(hunspell, &items, count); + } +}; + +void set_error(char** out_error, const char* message) { + if (out_error != nullptr) { + *out_error = g_strdup(message == nullptr ? "Unknown spelling error" : message); + } +} + +void set_exception(char** out_error, const char* operation) { + try { + throw; + } catch (const std::exception& error) { + if (out_error != nullptr) { + *out_error = g_strdup_printf("%s: %s", operation, error.what()); + } + } catch (...) { + if (out_error != nullptr) { + *out_error = g_strdup_printf("%s: unknown native exception", operation); + } + } +} + +bool validate_utf8_input(const char* value, char** out_error) { + if (value == nullptr) { + set_error(out_error, "Missing UTF-8 input"); + return false; + } + const size_t length = std::strlen(value); + if (length > kMaximumInputBytes) { + set_error(out_error, "Spelling input exceeds the native safety limit"); + return false; + } + if (!g_utf8_validate(value, static_cast(length), nullptr)) { + set_error(out_error, "Spelling input is not valid UTF-8"); + return false; + } + return true; +} + +GOwned normalize_nfc(const char* value, char** out_error) { + if (!validate_utf8_input(value, out_error)) return GOwned(nullptr); + auto* normalized = g_utf8_normalize(value, -1, G_NORMALIZE_NFC); + if (normalized == nullptr) set_error(out_error, "Could not normalize spelling input"); + return GOwned(normalized); +} + +GOwned convert_text(const char* value, + const char* target, + const char* source, + char** out_error) { + GError* conversion_error = nullptr; + auto* converted = g_convert(value, -1, target, source, nullptr, nullptr, + &conversion_error); + if (converted == nullptr && out_error != nullptr) { + *out_error = g_strdup_printf( + "Could not convert spelling text from %s to %s: %s", source, target, + conversion_error == nullptr ? "unknown conversion error" + : conversion_error->message); + } + if (conversion_error != nullptr) g_error_free(conversion_error); + return GOwned(converted); +} + +GOwned to_dictionary(BusySpellHandleImpl* handle, + const char* value, + char** out_error) { + auto normalized = normalize_nfc(value, out_error); + if (!normalized) return GOwned(nullptr); + return convert_text(normalized.get(), handle->encoding.c_str(), "UTF-8", + out_error); +} + +GOwned from_dictionary(BusySpellHandleImpl* handle, + const char* value, + char** out_error) { + return convert_text(value, "UTF-8", handle->encoding.c_str(), out_error); +} + +std::string trim_ascii(std::string value) { + const auto first = value.find_first_not_of(" \t\r\n"); + if (first == std::string::npos) return {}; + const auto last = value.find_last_not_of(" \t\r\n"); + return value.substr(first, last - first + 1); +} + +void load_word_chars(BusySpellHandleImpl* handle, const char* aff_path) { + std::ifstream input(aff_path, std::ios::binary); + std::string raw; + while (std::getline(input, raw)) { + raw = trim_ascii(raw); + constexpr auto directive = "WORDCHARS"; + constexpr auto directive_length = std::char_traits::length(directive); + if (raw.rfind(directive, 0) != 0 || raw.size() <= directive_length || + (raw[directive_length] != ' ' && raw[directive_length] != '\t')) { + continue; + } + raw = trim_ascii(raw.substr(directive_length)); + if (raw.empty()) return; + char* ignored_error = nullptr; + auto utf8 = convert_text(raw.c_str(), "UTF-8", handle->encoding.c_str(), + &ignored_error); + g_free(ignored_error); + if (!utf8) return; + for (const gchar* cursor = utf8.get(); *cursor != '\0'; + cursor = g_utf8_next_char(cursor)) { + handle->word_chars.insert(g_utf8_get_char(cursor)); + } + return; + } +} + +bool is_join_character(BusySpellHandleImpl* handle, gunichar character) { + return character == '\'' || character == 0x2019 || character == '-' || + character == 0x2010 || character == 0x2011 || character == 0x200c || + character == 0x200d || handle->word_chars.contains(character); +} + +bool is_apostrophe(gunichar character) { + return character == '\'' || character == 0x2018 || character == 0x2019; +} + +bool is_quote_pair(gunichar opening, gunichar closing) { + return (opening == '\'' && closing == '\'') || + (opening == 0x2018 && closing == 0x2019); +} + +bool is_word_character(gunichar character); + +bool is_lexical_apostrophe(const char* text, + const std::vector& offsets, + guint index) { + if (index == 0 || index + 1 >= offsets.size() - 1) return false; + return is_word_character(g_utf8_get_char(text + offsets[index - 1])) && + is_word_character(g_utf8_get_char(text + offsets[index + 1])); +} + +bool is_opening_quote_at(const char* text, + const std::vector& offsets, + guint index) { + const auto character = g_utf8_get_char(text + offsets[index]); + if (character == 0x2018) return true; + if (character != '\'' || index + 1 >= offsets.size() - 1) return false; + const bool follows_boundary = + index == 0 || + !is_word_character(g_utf8_get_char(text + offsets[index - 1])); + return follows_boundary && + is_word_character(g_utf8_get_char(text + offsets[index + 1])); +} + +bool is_closing_quote_at(const char* text, + const std::vector& offsets, + guint index) { + const auto character = g_utf8_get_char(text + offsets[index]); + if (character == 0x2019) return true; + if (character != '\'' || index == 0) return false; + const bool precedes_boundary = + index + 1 >= offsets.size() - 1 || + !is_word_character(g_utf8_get_char(text + offsets[index + 1])); + return precedes_boundary; +} + +bool has_closing_quote(const char* text, + const std::vector& offsets, + guint from, + gunichar opening) { + for (guint index = from; index < offsets.size() - 1; ++index) { + const auto character = g_utf8_get_char(text + offsets[index]); + if (character == '\n' || character == '\r') return false; + if (is_apostrophe(character) && + !is_lexical_apostrophe(text, offsets, index)) { + // The nearest non-lexical quote closes this span or terminates it. Do + // not pair across a separate quotation or a lexical elision. + return is_closing_quote_at(text, offsets, index) && + is_quote_pair(opening, character); + } + } + return false; +} + +bool has_opening_quote(const char* text, + const std::vector& offsets, + guint before, + gunichar closing) { + for (guint index = before; index > 0; --index) { + const guint candidate = index - 1; + const auto character = g_utf8_get_char(text + offsets[candidate]); + if (character == '\n' || character == '\r') return false; + if (is_apostrophe(character) && + !is_lexical_apostrophe(text, offsets, candidate)) { + return is_opening_quote_at(text, offsets, candidate) && + is_quote_pair(character, closing); + } + } + return false; +} + +// Pango supplies Unicode word boundaries. Only dictionary-specific word +// characters should extend those boundaries unconditionally. Apostrophes are +// also useful for lexical elisions and possessives, but a matching pair around +// the Pango candidate is quotation punctuation and must stay outside the +// correction target. Generic hyphens remain internal joiners only. +bool edge_can_extend(BusySpellHandleImpl* handle, + const char* text, + const std::vector& offsets, + guint candidate_start, + guint candidate_end, + guint index, + bool leading) { + const auto character = g_utf8_get_char(text + offsets[index]); + if (handle->word_chars.contains(character) && !is_apostrophe(character)) { + return true; + } + if (!is_apostrophe(character) || character == 0x2018) return false; + if (leading) { + // U+2019 is the apostrophe used by typographic leading elisions. Curly + // quotation spans use U+2018 as their opening punctuation. + if (character == 0x2019) return index + 1 == candidate_start; + if (candidate_end < offsets.size() - 1 && + is_quote_pair(character, + g_utf8_get_char(text + offsets[candidate_end]))) { + return false; + } + if (has_closing_quote(text, offsets, candidate_end, character)) { + return false; + } + return index + 1 == candidate_start; + } + if (candidate_start > 0 && + is_quote_pair(g_utf8_get_char(text + offsets[candidate_start - 1]), + character)) { + return false; + } + if (has_opening_quote(text, offsets, candidate_start, character)) { + return false; + } + return index == candidate_end; +} + +bool is_word_character(gunichar character) { + return g_unichar_isalpha(character) || g_unichar_ismark(character); +} + +struct Candidate { + guint start; + guint end; +}; + +std::vector character_byte_offsets(const char* text) { + std::vector result{0}; + const char* cursor = text; + while (*cursor != '\0') { + cursor = g_utf8_next_char(cursor); + result.push_back(static_cast(cursor - text)); + } + return result; +} + +bool separator_can_join(BusySpellHandleImpl* handle, + const char* text, + const std::vector& offsets, + guint from, + guint to) { + if (from >= to || from == 0 || to >= offsets.size() - 1) return false; + for (guint index = from; index < to; ++index) { + if (!is_join_character(handle, g_utf8_get_char(text + offsets[index]))) { + return false; + } + } + return is_word_character(g_utf8_get_char(text + offsets[from - 1])) && + is_word_character(g_utf8_get_char(text + offsets[to])); +} + +bool supported_encoding(const char* encoding) { + GIConv to_dictionary = g_iconv_open(encoding, "UTF-8"); + if (to_dictionary == reinterpret_cast(-1)) return false; + g_iconv_close(to_dictionary); + GIConv from_dictionary = g_iconv_open("UTF-8", encoding); + if (from_dictionary == reinterpret_cast(-1)) return false; + g_iconv_close(from_dictionary); + return true; +} + +bool has_loadable_dictionary_entry(const char* dic_path, + char** out_error) { + std::ifstream input(dic_path, std::ios::binary); + std::string raw; + if (!std::getline(input, raw)) { + set_error(out_error, "Dictionary has no record count"); + return false; + } + raw = trim_ascii(raw); + if (raw.size() >= 3 && static_cast(raw[0]) == 0xef && + static_cast(raw[1]) == 0xbb && + static_cast(raw[2]) == 0xbf) { + raw.erase(0, 3); + } + char* count_end = nullptr; + const auto declared = std::strtoull(raw.c_str(), &count_end, 10); + if (count_end == raw.c_str() || declared == 0) { + set_error(out_error, "Dictionary declares no usable records"); + return false; + } + // Some established Hunspell dictionaries append a tab-separated format + // revision to the record count. It is metadata, not another dictionary + // entry; accept only an all-numeric suffix so arbitrary malformed headers + // do not pass structural validation. + while (*count_end == ' ' || *count_end == '\t') ++count_end; + while (*count_end >= '0' && *count_end <= '9') ++count_end; + if (*count_end != '\0') { + set_error(out_error, "Dictionary has a malformed record count"); + return false; + } + + size_t records = 0; + while (std::getline(input, raw)) { + if (!raw.empty() && raw.back() == '\r') raw.pop_back(); + if (raw.empty()) continue; + ++records; + } + // Hunspell accepts long-lived dictionaries whose advisory count has drifted + // from the physical line count (for example the pinned French resource). + // The security/correctness invariant here is that a positive claim is backed + // by at least one real record. A bare record need not itself be accepted: + // NEEDAFFIX dictionaries deliberately contain stems that become valid only + // after an affix rule is applied. Catalog resources are additionally tested + // with their language-specific known-valid probes by the Dart worker. + if (records == 0) { + set_error(out_error, "Dictionary contains no records"); + return false; + } + return true; +} + +} // namespace + +struct BusySpellHandle : BusySpellHandleImpl {}; + +int busy_spell_open(const char* aff_path_utf8, + const char* dic_path_utf8, + BusySpellHandle** out_handle, + char** out_error) { + if (out_handle != nullptr) *out_handle = nullptr; + if (out_error != nullptr) *out_error = nullptr; + if (out_handle == nullptr || aff_path_utf8 == nullptr || + dic_path_utf8 == nullptr) { + set_error(out_error, "Dictionary paths and output handle are required"); + return BUSY_SPELL_ERROR; + } + if (!g_file_test(aff_path_utf8, G_FILE_TEST_IS_REGULAR) || + !g_file_test(dic_path_utf8, G_FILE_TEST_IS_REGULAR) || + g_access(aff_path_utf8, R_OK) != 0 || g_access(dic_path_utf8, R_OK) != 0) { + set_error(out_error, "Dictionary pair is missing or unreadable"); + return BUSY_SPELL_ERROR; + } + try { + auto handle = std::make_unique(); + handle->hunspell = Hunspell_create(aff_path_utf8, dic_path_utf8); + if (handle->hunspell == nullptr) { + set_error(out_error, "Hunspell could not open the dictionary pair"); + return BUSY_SPELL_ERROR; + } + const char* encoding = Hunspell_get_dic_encoding(handle->hunspell); + if (encoding == nullptr || *encoding == '\0' || !supported_encoding(encoding)) { + set_error(out_error, "Dictionary declares an unsupported encoding"); + return BUSY_SPELL_ERROR; + } + handle->encoding = encoding; + if (!has_loadable_dictionary_entry(dic_path_utf8, out_error)) { + return BUSY_SPELL_ERROR; + } + load_word_chars(handle.get(), aff_path_utf8); + *out_handle = handle.release(); + return BUSY_SPELL_ACCEPTED; + } catch (...) { + set_exception(out_error, "Could not open dictionary"); + return BUSY_SPELL_ERROR; + } +} + +void busy_spell_close(BusySpellHandle* handle) { + try { + delete handle; + } catch (...) { + } +} + +int busy_spell_check(BusySpellHandle* handle, + const char* word_utf8, + char** out_error) { + if (out_error != nullptr) *out_error = nullptr; + if (handle == nullptr) { + set_error(out_error, "Dictionary handle is closed"); + return BUSY_SPELL_ERROR; + } + try { + auto encoded = to_dictionary(handle, word_utf8, out_error); + if (!encoded) return BUSY_SPELL_ERROR; + return Hunspell_spell(handle->hunspell, encoded.get()) == 0 + ? BUSY_SPELL_REJECTED + : BUSY_SPELL_ACCEPTED; + } catch (...) { + set_exception(out_error, "Could not check word"); + return BUSY_SPELL_ERROR; + } +} + +int busy_spell_suggest(BusySpellHandle* handle, + const char* word_utf8, + char*** out_items, + size_t* out_count, + char** out_error) { + if (out_items != nullptr) *out_items = nullptr; + if (out_count != nullptr) *out_count = 0; + if (out_error != nullptr) *out_error = nullptr; + if (handle == nullptr || out_items == nullptr || out_count == nullptr) { + set_error(out_error, "Dictionary handle and suggestion outputs are required"); + return BUSY_SPELL_ERROR; + } + try { + auto encoded = to_dictionary(handle, word_utf8, out_error); + if (!encoded) return BUSY_SPELL_ERROR; + HunspellSuggestionOwner hunspell_items(handle->hunspell); + const int count = Hunspell_suggest(handle->hunspell, &hunspell_items.items, + encoded.get()); + if (count < 0) { + set_error(out_error, "Hunspell suggestion generation failed"); + return BUSY_SPELL_ERROR; + } + hunspell_items.count = count; + std::vector> copied; + copied.reserve(static_cast(count)); + for (int index = 0; index < count; ++index) { + auto value = from_dictionary(handle, hunspell_items.items[index], out_error); + if (!value) { + return BUSY_SPELL_ERROR; + } + copied.push_back(std::move(value)); + } + if (!copied.empty()) { + auto** result = static_cast(g_malloc_n(copied.size(), sizeof(char*))); + for (size_t index = 0; index < copied.size(); ++index) { + result[index] = copied[index].release(); + } + *out_items = result; + *out_count = copied.size(); + } + return BUSY_SPELL_ACCEPTED; + } catch (...) { + set_exception(out_error, "Could not generate suggestions"); + return BUSY_SPELL_ERROR; + } +} + +int busy_spell_add(BusySpellHandle* handle, + const char* word_utf8, + char** out_error) { + if (out_error != nullptr) *out_error = nullptr; + if (handle == nullptr) { + set_error(out_error, "Dictionary handle is closed"); + return BUSY_SPELL_ERROR; + } + try { + auto encoded = to_dictionary(handle, word_utf8, out_error); + if (!encoded) return BUSY_SPELL_ERROR; + if (Hunspell_add(handle->hunspell, encoded.get()) != 0) { + set_error(out_error, "Hunspell could not add the custom word"); + return BUSY_SPELL_ERROR; + } + return BUSY_SPELL_ACCEPTED; + } catch (...) { + set_exception(out_error, "Could not add custom word"); + return BUSY_SPELL_ERROR; + } +} + +int busy_spell_dictionary_encoding(BusySpellHandle* handle, + char** out_encoding, + char** out_error) { + if (out_encoding != nullptr) *out_encoding = nullptr; + if (out_error != nullptr) *out_error = nullptr; + if (handle == nullptr || out_encoding == nullptr) { + set_error(out_error, "Dictionary handle and encoding output are required"); + return BUSY_SPELL_ERROR; + } + *out_encoding = g_strdup(handle->encoding.c_str()); + return BUSY_SPELL_ACCEPTED; +} + +int busy_spell_tokenize(BusySpellHandle* handle, + const char* prose_utf8, + const char* language_utf8, + BusySpellTokenRange** out_ranges, + size_t* out_count, + char** out_error) { + if (out_ranges != nullptr) *out_ranges = nullptr; + if (out_count != nullptr) *out_count = 0; + if (out_error != nullptr) *out_error = nullptr; + if (handle == nullptr || out_ranges == nullptr || out_count == nullptr) { + set_error(out_error, "Dictionary handle and token outputs are required"); + return BUSY_SPELL_ERROR; + } + if (!validate_utf8_input(prose_utf8, out_error)) return BUSY_SPELL_ERROR; + try { + const auto offsets = character_byte_offsets(prose_utf8); + const int character_count = static_cast(offsets.size() - 1); + std::vector attributes(static_cast(character_count + 1)); + PangoLanguage* language = nullptr; + if (language_utf8 != nullptr && *language_utf8 != '\0') { + language = pango_language_from_string(language_utf8); + } + pango_get_log_attrs(prose_utf8, static_cast(std::strlen(prose_utf8)), + -1, language, attributes.data(), character_count + 1); + + std::vector candidates; + for (guint index = 0; index < static_cast(character_count); ++index) { + if (!attributes[index].is_word_start) continue; + guint end = index + 1; + while (end <= static_cast(character_count) && + !attributes[end].is_word_end) { + ++end; + } + if (end > static_cast(character_count)) break; + const guint pango_start = index; + const guint pango_end = end; + while (index > 0 && + edge_can_extend(handle, prose_utf8, offsets, pango_start, + pango_end, index - 1, true)) { + --index; + } + while (end < static_cast(character_count) && + edge_can_extend(handle, prose_utf8, offsets, pango_start, + pango_end, end, false)) { + ++end; + } + bool contains_letter = false; + for (guint cursor = index; cursor < end; ++cursor) { + if (is_word_character(g_utf8_get_char(prose_utf8 + offsets[cursor]))) { + contains_letter = true; + break; + } + } + if (contains_letter) candidates.push_back({index, end}); + index = end - 1; + } + + std::vector merged; + for (const auto candidate : candidates) { + if (!merged.empty() && + (candidate.start <= merged.back().end || + separator_can_join(handle, prose_utf8, offsets, merged.back().end, + candidate.start))) { + merged.back().end = std::max(merged.back().end, candidate.end); + } else { + merged.push_back(candidate); + } + } + if (!merged.empty()) { + auto* result = static_cast( + g_malloc_n(merged.size(), sizeof(BusySpellTokenRange))); + for (size_t index = 0; index < merged.size(); ++index) { + result[index] = {offsets[merged[index].start], offsets[merged[index].end], + merged[index].start, merged[index].end}; + } + *out_ranges = result; + *out_count = merged.size(); + } + return BUSY_SPELL_ACCEPTED; + } catch (...) { + set_exception(out_error, "Could not tokenize prose"); + return BUSY_SPELL_ERROR; + } +} + +void busy_spell_free_suggestions(char** items, size_t count) { + if (items == nullptr) return; + for (size_t index = 0; index < count; ++index) g_free(items[index]); + g_free(items); +} + +void busy_spell_free_token_ranges(BusySpellTokenRange* ranges) { g_free(ranges); } + +void busy_spell_free_string(char* value) { g_free(value); } diff --git a/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.h b/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.h new file mode 100644 index 00000000..df35bb4b --- /dev/null +++ b/packages/busymark_spellcheck_native/src/busymark_spellcheck_native.h @@ -0,0 +1,64 @@ +#include +#include + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BusySpellHandle BusySpellHandle; + +typedef struct BusySpellTokenRange { + uint32_t utf8_start; + uint32_t utf8_end; + uint32_t character_start; + uint32_t character_end; +} BusySpellTokenRange; + +enum BusySpellStatus { + BUSY_SPELL_ERROR = -1, + BUSY_SPELL_REJECTED = 0, + BUSY_SPELL_ACCEPTED = 1, +}; + +FFI_PLUGIN_EXPORT int busy_spell_open(const char* aff_path_utf8, + const char* dic_path_utf8, + BusySpellHandle** out_handle, + char** out_error); +FFI_PLUGIN_EXPORT void busy_spell_close(BusySpellHandle* handle); +FFI_PLUGIN_EXPORT int busy_spell_check(BusySpellHandle* handle, + const char* word_utf8, + char** out_error); +FFI_PLUGIN_EXPORT int busy_spell_suggest(BusySpellHandle* handle, + const char* word_utf8, + char*** out_items, + size_t* out_count, + char** out_error); +FFI_PLUGIN_EXPORT int busy_spell_add(BusySpellHandle* handle, + const char* word_utf8, + char** out_error); +FFI_PLUGIN_EXPORT int busy_spell_dictionary_encoding(BusySpellHandle* handle, + char** out_encoding, + char** out_error); + +/// Calls Pango with the complete UTF-8 prose run. The C bitfield attributes are +/// copied into stable byte/character ranges rather than exposed through FFI. +FFI_PLUGIN_EXPORT int busy_spell_tokenize(BusySpellHandle* handle, + const char* prose_utf8, + const char* language_utf8, + BusySpellTokenRange** out_ranges, + size_t* out_count, + char** out_error); + +FFI_PLUGIN_EXPORT void busy_spell_free_suggestions(char** items, size_t count); +FFI_PLUGIN_EXPORT void busy_spell_free_token_ranges(BusySpellTokenRange* ranges); +FFI_PLUGIN_EXPORT void busy_spell_free_string(char* value); + +#ifdef __cplusplus +} +#endif diff --git a/packages/busymark_spellcheck_native/test/busymark_spellcheck_native_test.dart b/packages/busymark_spellcheck_native/test/busymark_spellcheck_native_test.dart new file mode 100644 index 00000000..b2a37bb8 --- /dev/null +++ b/packages/busymark_spellcheck_native/test/busymark_spellcheck_native_test.dart @@ -0,0 +1,182 @@ +import 'dart:io'; + +import 'package:busymark_spellcheck_native/busymark_spellcheck_native.dart'; +import 'package:test/test.dart'; + +void main() { + late NativeSpellDictionary dictionary; + + String fixturePath(String name) { + final local = File('test/fixtures/$name'); + if (local.existsSync()) return local.absolute.path; + return File( + 'packages/busymark_spellcheck_native/test/fixtures/$name', + ).absolute.path; + } + + setUp(() { + dictionary = NativeSpellDictionary.open( + affPath: fixturePath('test.aff'), + dicPath: fixturePath('test.dic'), + ); + }); + + tearDown(() => dictionary.close()); + + test('checks roots, affixes, compounds, and casing', () { + expect(dictionary.encoding, 'UTF-8'); + expect(dictionary.check('hello'), NativeSpellResult.accepted); + expect(dictionary.check('hellos'), NativeSpellResult.accepted); + expect(dictionary.check('sunflower'), NativeSpellResult.accepted); + expect(dictionary.check('BusyMark'), NativeSpellResult.accepted); + expect(dictionary.check('busymark'), NativeSpellResult.rejected); + expect(dictionary.check('helo'), NativeSpellResult.rejected); + }); + + test('copies suggestions before releasing the Hunspell list', () { + expect(dictionary.suggest('helo'), contains('hello')); + }); + + test('custom words participate in checking and suggestions', () { + expect(dictionary.check('busystack'), NativeSpellResult.rejected); + dictionary.add('busystack'); + expect(dictionary.check('busystack'), NativeSpellResult.accepted); + expect(dictionary.suggest('busystak'), contains('busystack')); + }); + + test('tokenization reports UTF-8 and character boundaries separately', () { + const prose = '😀 helo café don’t state-of-the-art'; + final ranges = dictionary.tokenize(prose, language: 'en-US'); + final utf16 = nativeUtf8BoundaryToUtf16(prose); + final words = [ + for (final range in ranges) + prose.substring(utf16[range.utf8Start], utf16[range.utf8End]), + ]; + expect(words, ['helo', 'café', 'don’t', 'state-of-the-art']); + }); + + test('dictionary word characters do not absorb quotation punctuation', () { + const prose = + "C++ C# +lead trail# -dash dash- 'quoted' ‘curly’ -hyphen- " + "don't ’tis dogs’ café"; + final ranges = dictionary.tokenize(prose, language: 'en-US'); + final utf16 = nativeUtf8BoundaryToUtf16(prose); + final words = [ + for (final range in ranges) + prose.substring(utf16[range.utf8Start], utf16[range.utf8End]), + ]; + + expect(words, [ + 'C++', + 'C#', + '+lead', + 'trail#', + '-dash', + 'dash-', + 'quoted', + 'curly', + '-hyphen-', + "don't", + '’tis', + 'dogs’', + 'café', + ]); + expect(dictionary.check('C++'), NativeSpellResult.accepted); + expect(dictionary.check('C#'), NativeSpellResult.accepted); + expect(dictionary.check('-dash'), NativeSpellResult.accepted); + expect(dictionary.check('dash-'), NativeSpellResult.accepted); + }); + + test('quotation punctuation stays outside tokens across phrases', () { + const prose = "'helo world' ‘hello wrld’ 'don't wrld,'"; + final ranges = dictionary.tokenize(prose, language: 'en-US'); + final utf16 = nativeUtf8BoundaryToUtf16(prose); + final words = [ + for (final range in ranges) + prose.substring(utf16[range.utf8Start], utf16[range.utf8End]), + ]; + + expect(words, ['helo', 'world', 'hello', 'wrld', "don't", 'wrld']); + for (final word in words) { + expect(word, isNot(startsWith("'"))); + expect(word, isNot(endsWith("'"))); + expect(word, isNot(startsWith('‘'))); + expect(word, isNot(endsWith('’'))); + expect(word, isNot(endsWith(','))); + } + }); + + test('standalone elisions and possessives retain lexical apostrophes', () { + for (final prose in ["'tis", '’tis', "dogs'", 'dogs’']) { + final range = dictionary.tokenize(prose, language: 'en-US').single; + final utf16 = nativeUtf8BoundaryToUtf16(prose); + expect( + prose.substring(utf16[range.utf8Start], utf16[range.utf8End]), + prose, + ); + } + }); + + test('closed handles report an unchecked failure', () { + dictionary.close(); + expect( + () => dictionary.check('word'), + throwsA(isA()), + ); + }); + + test('missing dictionary is reported without leaking a handle', () { + expect( + () => NativeSpellDictionary.open( + affPath: '/missing/test.aff', + dicPath: '/missing/test.dic', + ), + throwsA(isA()), + ); + }); + + test('rejects a dictionary that claims records but loads none', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-empty-dictionary-', + ); + addTearDown(() => temporary.delete(recursive: true)); + final aff = File('${temporary.path}/empty.aff'); + final dic = File('${temporary.path}/empty.dic'); + await aff.writeAsString('SET UTF-8\n'); + await dic.writeAsString('1\n'); + + expect( + () => NativeSpellDictionary.open(affPath: aff.path, dicPath: dic.path), + throwsA( + isA().having( + (error) => error.message, + 'message', + contains('no records'), + ), + ), + ); + }); + + test('accepts a valid dictionary whose stems require affixes', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-need-affix-dictionary-', + ); + addTearDown(() => temporary.delete(recursive: true)); + final aff = File('${temporary.path}/need-affix.aff'); + final dic = File('${temporary.path}/need-affix.dic'); + await aff.writeAsString('''SET UTF-8 +NEEDAFFIX X +SFX S Y 1 +SFX S 0 s . +'''); + await dic.writeAsString('1\ncat/XS\n'); + + final affixOnly = NativeSpellDictionary.open( + affPath: aff.path, + dicPath: dic.path, + ); + addTearDown(affixOnly.close); + expect(affixOnly.check('cat'), NativeSpellResult.rejected); + expect(affixOnly.check('cats'), NativeSpellResult.accepted); + }); +} diff --git a/packages/busymark_spellcheck_native/test/fixtures/test.aff b/packages/busymark_spellcheck_native/test/fixtures/test.aff new file mode 100644 index 00000000..62d289ae --- /dev/null +++ b/packages/busymark_spellcheck_native/test/fixtures/test.aff @@ -0,0 +1,9 @@ +SET UTF-8 +TRY etaoinshrdlucmfwypvbgkjqxz +WORDCHARS ’-+# +REP 1 +REP helo hello +SFX S Y 1 +SFX S 0 s . +COMPOUNDMIN 3 +COMPOUNDFLAG C diff --git a/packages/busymark_spellcheck_native/test/fixtures/test.dic b/packages/busymark_spellcheck_native/test/fixtures/test.dic new file mode 100644 index 00000000..34321598 --- /dev/null +++ b/packages/busymark_spellcheck_native/test/fixtures/test.dic @@ -0,0 +1,12 @@ +11 +hello/S +world +sun/C +flower/C +BusyMark +C++ +C# ++lead +trail# +-dash +dash- diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/ARCHIVE.sha256 b/packages/busymark_spellcheck_native/third_party/hunspell/ARCHIVE.sha256 new file mode 100644 index 00000000..5770c664 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/ARCHIVE.sha256 @@ -0,0 +1 @@ +933be3dac6fd55f6e752331a170efb7e33800e40fae1156d8434cc8c85379a1b diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/REVISION b/packages/busymark_spellcheck_native/third_party/hunspell/REVISION new file mode 100644 index 00000000..eeeaad15 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/REVISION @@ -0,0 +1 @@ +c5f98152a274e25b5107101104bef632b83a0cc9 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING new file mode 100644 index 00000000..1f963da0 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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. + diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.LESSER b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.LESSER new file mode 100644 index 00000000..67cd97bb --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.LESSER @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. 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 not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the 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 +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 library 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 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.MPL b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.MPL new file mode 100644 index 00000000..7714141d --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/COPYING.MPL @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``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 ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.hunspell b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.hunspell new file mode 100644 index 00000000..fad5a162 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.hunspell @@ -0,0 +1,54 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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. + * + * ***** END LICENSE BLOCK ***** */ diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.myspell b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.myspell new file mode 100644 index 00000000..2da53307 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/licenses/license.myspell @@ -0,0 +1,61 @@ +/* + * 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. + * + * + * NOTE: A special thanks and credit goes to Geoff Kuenning + * the creator of ispell. MySpell's affix algorithms were + * based on those of ispell which should be noted is + * copyright Geoff Kuenning et.al. and now available + * under a BSD style license. For more information on ispell + * and affix compression in general, please see: + * http://www.cs.ucla.edu/ficus-members/geoff/ispell.html + * (the home page for ispell) + * + * An almost complete rewrite of MySpell for use by + * the Mozilla project has been developed by David Einstein + * (Deinst@world.std.com). David and I are now + * working on parallel development tracks to help + * our respective projects (Mozilla and OpenOffice.org + * and we will maintain full affix file and dictionary + * file compatibility and work on merging our versions + * of MySpell back into a single tree. David has been + * a significant help in improving MySpell. + * + * Special thanks also go to La'szlo' Ne'meth + * who is the author of the + * Hungarian dictionary and who developed and contributed + * the code to support compound words in MySpell + * and fixed numerous problems with the encoding + * case conversion tables. + * + */ diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/Makefile.am b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/Makefile.am new file mode 100644 index 00000000..3ccffef9 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/Makefile.am @@ -0,0 +1,23 @@ +lib_LTLIBRARIES = libhunspell-1.7.la +libhunspell_1_7_includedir = $(includedir)/hunspell +libhunspell_1_7_la_SOURCES=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 \ + phonet.cxx phonet.hxx replist.cxx replist.hxx \ + suggestmgr.cxx suggestmgr.hxx utf_info.hxx w_char.hxx +nodist_libhunspell_1_7_la_SOURCES=hunvisapi.h + + +libhunspell_1_7_include_HEADERS=hunspell.hxx hunspell.h hunvisapi.h \ + w_char.hxx atypes.hxx + +# libtool version-info: current:revision:age +# - source changed, no API change: r += 1 +# - public API added: c += 1; r = 0; a += 1 +# - public API removed or signature change: c += 1; r = 0; a = 0 +# Linux SONAME suffix is (current - age). See RELEASING.md. +libhunspell_1_7_la_LDFLAGS=-no-undefined -version-info 1:0:1 + +AM_CXXFLAGS=$(CFLAG_VISIBILITY) -DBUILDING_LIBHUNSPELL $(HUNSPELL_STATIC_DEFINE) diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.cxx new file mode 100644 index 00000000..31561454 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.cxx @@ -0,0 +1,988 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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) + delete[] c.l.conds2; + if (morphcode && !(opts & aeALIASM)) + delete[] morphcode; + if (contclass && !(opts & aeALIASF)) + delete[] contclass; +} + +PfxEntry::PfxEntry(AffixMgr* pmgr) + // register affix manager + : pmyMgr(pmgr) + , next(nullptr) + , nexteq(nullptr) + , nextne(nullptr) + , flgnxt(nullptr) {} + +// 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.empty() || + (len >= 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 nullptr; + return *p ? p : nullptr; + } + return nullptr; +} + +inline int PfxEntry::test_condition(const std::string& s) { + size_t st = 0; + size_t pos = std::string::npos; // 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 (true) { + 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 (bool(neg) == bool(ingroup)) + return 0; + pos = std::string::npos; + p = nextchar(p); + // skip the next character + if (!ingroup && st < s.size()) { + ++st; + while ((opts & aeUTF8) && st < s.size() && (s[st] & 0xc0) == 0x80) + ++st; + } + if (st == s.size() && p) + return 0; // word <= condition + break; + } + case '.': + if (pos == std::string::npos) { // dots are not metacharacters in groups: [.] + p = nextchar(p); + // skip the next character + ++st; + while ((opts & aeUTF8) && st < s.size() && (s[st] & 0xc0) == 0x80) + ++st; + if (st == s.size() && p) + return 0; // word <= condition + break; + } + /* FALLTHROUGH */ + default: { + if (st < s.size() && s[st] == *p) { + ++st; + p = nextchar(p); + if ((opts & aeUTF8) && (s[st - 1] & 0x80)) { // multibyte + while (p && (*p & 0xc0) == 0x80) { // character + if (st >= s.size() || *p != s[st]) { + if (pos == std::string::npos) + return 0; + st = pos; + break; + } + p = nextchar(p); + ++st; + } + if (pos != std::string::npos && st != pos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != nullptr)) { + } + } + } else if (pos != std::string::npos) { + ingroup = true; + while (p && *p != ']' && ((p = nextchar(p)) != nullptr)) { + } + } + } else if (pos != std::string::npos) { // group + p = nextchar(p); + } else + return 0; + } + } + if (!p) + return 1; + } +} + +// check if this prefix entry matches +struct hentry* PfxEntry::checkword(const std::string& word, + int start, + 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, start + appnd.size(), 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 check if resulting + // root word in the dictionary + + if (test_condition(tmpword)) { + tmpl += strip.size(); + if ((he = pmyMgr->lookup(tmpword.c_str(), tmpword.size())) != nullptr) { + 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, 0, tmpl, aeXPRODUCT, this, + FLAG_NULL, needflag, in_compound); + if (he) + return he; + } + } + } + return nullptr; +} + +// check if this prefix entry matches +struct hentry* PfxEntry::check_twosfx(const std::string& word, + int start, + 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, start + appnd.size(), 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 check if resulting + // root word in the dictionary + + if (test_condition(tmpword)) { + 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, 0, tmpl, aeXPRODUCT, this, + needflag); + if (he) + return he; + } + } + } + return nullptr; +} + +// check if this prefix entry matches +std::string PfxEntry::check_twosfx_morph(const std::string& word, + int start, + 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, start + appnd.size(), 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 check if resulting + // root word in the dictionary + + if (test_condition(tmpword)) { + 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, 0, tmpl, + aeXPRODUCT, + this, needflag); + } + } + } + return result; +} + +// check if this prefix entry matches +std::string PfxEntry::check_morph(const std::string& word, + int start, + 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, start + appnd.size(), 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 check if resulting + // root word in the dictionary + + if (test_condition(tmpword)) { + tmpl += strip.size(); + struct hentry* he; // hash entry of root word or NULL + if ((he = pmyMgr->lookup(tmpword.c_str(), tmpword.size())) != nullptr) { + 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.push_back(MSEP_FLD); + result.append(morphcode); + } else + result.append(getKey()); + if (!HENTRY_FIND(he, MORPH_STEM)) { + result.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(he)); + } + // store the pointer of the hash entry + if (HENTRY_DATA(he)) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(he)); + } else { + // return with debug information + std::string flag = pmyMgr->encode_flag(getFlag()); + result.push_back(MSEP_FLD); + result.append(MORPH_FLAG); + result.append(flag); + } + result.push_back(MSEP_REC); + } + 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, 0, tmpl, aeXPRODUCT, this, + FLAG_NULL, needflag); + if (!st.empty()) { + result.append(st); + } + } + } + } + + return result; +} + +SfxEntry::SfxEntry(AffixMgr* pmgr) + : pmyMgr(pmgr) // register affix manager + , next(nullptr) + , nexteq(nullptr) + , nextne(nullptr) + , flgnxt(nullptr) + , l_morph(nullptr) + , r_morph(nullptr) + , eq_morph(nullptr) {} + +// 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.empty() || + (len >= strip.size() && strcmp(word + len - strip.size(), strip.c_str()) == 0))) { + result.assign(word, len); + /* 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 nullptr; + return *p ? p : nullptr; + } + return nullptr; +} + +inline int SfxEntry::test_condition(const char* st, const char* beg) { + const char* pos = nullptr; // 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 (true) { + 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 = nullptr; + 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)) != nullptr)) { + } + 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)) != nullptr)) { + } + // 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 std::string& word, + int start, + 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 nullptr; + + // 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, start, tmpl); + if (!strip.empty()) { + 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.c_str() + start, tmpword, aflag); +#endif + if ((he = pmyMgr->lookup(tmpstring.c_str(), tmpstring.size())) != nullptr) { + 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 nullptr; +} + +// see if two-level suffix is present in the word +struct hentry* SfxEntry::check_twosfx(const std::string& word, + int start, + 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 nullptr; + + // 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, start); + 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, 0, tmpl, 0, nullptr, (FLAG)aflag, needflag, IN_CPD_NOT); + else + he = pmyMgr->suffix_check(tmpword, 0, tmpl, optflags, ppfx, + (FLAG)aflag, needflag, IN_CPD_NOT); + } else { + he = pmyMgr->suffix_check(tmpword, 0, tmpl, 0, nullptr, (FLAG)aflag, needflag, IN_CPD_NOT); + } + if (he) + return he; + } + } + return nullptr; +} + +// see if two-level suffix is present in the word +std::string SfxEntry::check_twosfx_morph(const std::string& word, + int start, + 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, start); + 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, 0, tmpl, 0, nullptr, aflag, needflag); + if (!st.empty()) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.push_back(MSEP_FLD); + } + result.append(st); + mychomp(result); + } + } else { + std::string st = pmyMgr->suffix_check_morph(tmpword, 0, tmpl, optflags, ppfx, aflag, + needflag); + if (!st.empty()) { + result.append(st); + mychomp(result); + } + } + } else { + std::string st = pmyMgr->suffix_check_morph(tmpword, 0, tmpl, 0, nullptr, 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 nullptr; +} + +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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.hxx new file mode 100644 index 00000000..01002f87 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affentry.hxx @@ -0,0 +1,228 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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: + AffixMgr* pmyMgr; + + PfxEntry* next; + PfxEntry* nexteq; + PfxEntry* nextne; + PfxEntry* flgnxt; + + public: + explicit PfxEntry(AffixMgr* pmgr); + PfxEntry(const PfxEntry&) = delete; + PfxEntry& operator=(const PfxEntry&) = delete; + + bool allowCross() const { return ((opts & aeXPRODUCT) != 0); } + struct hentry* checkword(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + struct hentry* check_twosfx(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + std::string check_morph(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + + std::string check_twosfx_morph(const std::string& word, + int start, + 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 int getKeyLen() { return appnd.size(); } + + inline const char* getMorph() { return morphcode; } + + inline const unsigned short* getCont() { return contclass; } + inline unsigned 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 std::string& 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 std::string& word, + int start, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag, + const FLAG badflag); + + struct hentry* check_twosfx(const std::string& word, + int start, + int len, + int optflags, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + std::string check_twosfx_morph(const std::string& word, + int start, + 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 unsigned short getContLen() { return contclasslen; } + inline const char* getAffix() { return appnd.c_str(); } + + inline int 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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.cxx new file mode 100644 index 00000000..7ca17bb6 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.cxx @@ -0,0 +1,4824 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 +#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].get()) { + + // register hash manager and load affix data from aff file + csconv = nullptr; + utf8 = 0; + complexprefixes = 0; + parsedmaptable = false; + parsedbreaktable = false; + iconvtable = nullptr; + oconvtable = nullptr; + // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN) + simplifiedcpd = 0; + parsedcheckcpd = false; + parseddefcpd = false; + phone = nullptr; + 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 = nullptr; // previous prefix for counting syllables of the prefix BUG + sfxappnd = nullptr; // 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 = nullptr; + pfx = nullptr; + + for (int i = 0; i < SETSIZE; i++) { + pStart[i] = nullptr; + sStart[i] = nullptr; + pFlag[i] = nullptr; + sFlag[i] = nullptr; + } + + memset(contclasses, 0, CONTSIZE * sizeof(char)); + + if (parse_file(affpath, key)) { + fprintf(stderr, "Failure loading aff file %s\n", affpath); + } + + /* 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.emplace_back("-"); + breaktable.emplace_back("^-"); + breaktable.emplace_back("-$"); + parsedbreaktable = true; + } + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + // not entirely sure this is invalid, so only for fuzzing for now + if (iconvtable && !iconvtable->check_against_breaktable(breaktable)) { + delete iconvtable; + iconvtable = nullptr; + } +#endif + + if (cpdmin == -1) + cpdmin = MINCPDLEN; +} + +AffixMgr::~AffixMgr() { + // pass through linked prefix entries and clean up + for (int i = 0; i < SETSIZE; i++) { + pFlag[i] = nullptr; + PfxEntry* ptr = pStart[i]; + PfxEntry* nptr = nullptr; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + } + } + + // pass through linked suffix entries and clean up + for (int j = 0; j < SETSIZE; j++) { + sFlag[j] = nullptr; + SfxEntry* ptr = sStart[j]; + SfxEntry* nptr = nullptr; + while (ptr) { + nptr = ptr->getNext(); + delete (ptr); + ptr = nptr; + } + sStart[j] = nullptr; + } + + 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 = nullptr; + cpdmin = 0; + cpdmaxsyllable = 0; + 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); + + // 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; + } + } + + /* 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 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(); + + 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 auto 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 (*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(nullptr); + ep->setNextNE(nullptr); + + 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 = nullptr; + 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 auto 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 (*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(nullptr); + ep->setNextNE(nullptr); + + 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 = nullptr; + 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], nullptr); + } + 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], nullptr); + } + 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 != nullptr; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + for (; nptr != nullptr; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(nullptr); + 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 != nullptr; ptr = ptr->getNext()) { + PfxEntry* nptr = ptr->getNext(); + PfxEntry* mptr = nullptr; + for (; nptr != nullptr; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(nullptr); + } + } + 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 != nullptr; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + for (; nptr != nullptr; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + } + ptr->setNextNE(nptr); + ptr->setNextEQ(nullptr); + 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 != nullptr; ptr = ptr->getNext()) { + SfxEntry* nptr = ptr->getNext(); + SfxEntry* mptr = nullptr; + for (; nptr != nullptr; nptr = nptr->getNext()) { + if (!isSubset(ptr->getKey(), nptr->getKey())) + break; + mptr = nptr; + } + if (mptr) + mptr->setNextNE(nullptr); + } + } + return 0; +} + +// add flags to the result for dictionary debugging +std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) { + std::string st = encode_flag(flag); + result.push_back(MSEP_FLD); + result.append(MORPH_FLAG); + result.append(st); + return result; +} + +// calculate the character length of the condition +int AffixMgr::condlen(const std::string& s) { + int l = 0; + bool group = false; + auto st = s.begin(), end = s.end(); + while (st != end) { + if (*st == '[') { + group = true; + l++; + } else if (*st == ']') + group = false; + else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80)))) + l++; + ++st; + } + return l; +} + +int AffixMgr::encodeit(AffEntry& entry, const std::string& cs) { + if (cs.compare(".") != 0) { + entry.numconds = (char)condlen(cs); + const size_t cslen = cs.size(); + const size_t short_part = std::min(MAXCONDLEN, cslen); + memcpy(entry.c.conds, cs.data(), 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; + size_t remaining = cs.size() - MAXCONDLEN_1; + entry.c.l.conds2 = new char[1 + remaining]; + memcpy(entry.c.l.conds2, cs.data() + MAXCONDLEN_1, remaining); + entry.c.l.conds2[remaining] = 0; + } + } 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') && (*s2 != '\0')) { + s1++; + s2++; + } + return (*s1 == '\0'); +} + +// check word for prefixes +struct hentry* AffixMgr::prefix_check(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = nullptr; + + pfx = nullptr; + pfxappnd = nullptr; + sfxappnd = nullptr; + 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, start, 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 = word[start]; + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word.c_str() + start)) { + 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, start, len, in_compound, needflag); + if (rv) { + pfx = pptr; // BUG: pfx not stateless + return rv; + } + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return nullptr; +} + +// check word for prefixes and two-level suffixes +struct hentry* AffixMgr::prefix_check_twosfx(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag) { + struct hentry* rv = nullptr; + + pfx = nullptr; + sfxappnd = nullptr; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + + while (pe) { + rv = pe->check_twosfx(word, start, len, in_compound, needflag); + if (rv) + return rv; + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = word[start]; + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word.c_str() + start)) { + rv = pptr->check_twosfx(word, start, len, in_compound, needflag); + if (rv) { + pfx = pptr; + return rv; + } + pptr = pptr->getNextEQ(); + } else { + pptr = pptr->getNextNE(); + } + } + + return nullptr; +} + +// check word for prefixes and morph +std::string AffixMgr::prefix_check_morph(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag) { + + std::string result; + + pfx = nullptr; + sfxappnd = nullptr; + sfxextra = 0; + + // first handle the special case of 0 length prefixes + PfxEntry* pe = pStart[0]; + while (pe) { + std::string st = pe->check_morph(word, start, len, in_compound, needflag); + if (!st.empty()) { + result.append(st); + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = word[start]; + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word.c_str() + start)) { + std::string st = pptr->check_morph(word, start, 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 std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag) { + std::string result; + + pfx = nullptr; + sfxappnd = nullptr; + 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, start, len, in_compound, needflag); + if (!st.empty()) { + result.append(st); + } + pe = pe->getNext(); + } + + // now handle the general case + unsigned char sp = word[start]; + PfxEntry* pptr = pStart[sp]; + + while (pptr) { + if (isSubset(pptr->getKey(), word.c_str() + start)) { + std::string st = pptr->check_twosfx_morph(word, start, 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 std::string& in_word, int wl) { + + if ((wl < 2) || get_reptable().empty()) + return 0; + + std::string word(in_word, 0, wl); + + for (const auto& i : get_reptable()) { + // use only available mid patterns + if (!i.outstrings[0].empty()) { + size_t r = 0; + const size_t lenp = i.pattern.size(); + // search every occurence of the pattern in the word + while ((r = word.find(i.pattern, r)) != std::string::npos) { + std::string candidate(word); + candidate.replace(r, lenp, i.outstrings[0]); + if (candidate_check(candidate)) + return 1; + ++r; // search for the next letter + } + } + } + + return 0; +} + +// forbid compound words, if they are in the dictionary as a +// word pair separated by space +int AffixMgr::cpdwordpair_check(const std::string& word, int wl) { + if (wl > 2) { + std::string candidate(word, 0, wl); + for (size_t i = 1; i < candidate.size(); i++) { + // go to end of the UTF-8 character + if (utf8 && ((candidate[i] & 0xc0) == 0x80)) + continue; + candidate.insert(i, 1, ' '); + if (candidate_check(candidate)) + return 1; + candidate.erase(i, 1); + } + } + + return 0; +} + +// forbid compoundings when there are special patterns at word bound +int AffixMgr::cpdpat_check(const std::string& word, + size_t pos, + hentry* r1, + hentry* r2, + const char /*affixed*/) { + for (auto& i : checkcpdtable) { + size_t len; + if (isSubset(i.pattern2.c_str(), word.c_str() + pos) && + (!r1 || !i.cond || + (r1->astr && TESTAFF(r1->astr, i.cond, r1->alen))) && + (!r2 || !i.cond2 || + (r2->astr && TESTAFF(r2->astr, i.cond2, r2->alen))) && + // zero length pattern => only TESTAFF + // zero pattern (0/flag) => unmodified stem (zero affixes allowed) + (i.pattern.empty() || + ((i.pattern[0] == '0' && r1->blen <= pos && + strncmp(word.c_str() + pos - r1->blen, r1->word, r1->blen) == 0) || + (i.pattern[0] != '0' && + ((len = i.pattern.size()) != 0) && len <= pos && + strncmp(word.c_str() + pos - len, 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 std::string& word, int pos) { + if (utf8) { + const char* p; + const char* wordp = word.c_str(); + for (p = wordp + pos - 1; p > wordp && (*p & 0xc0) == 0x80; p--) + ; + std::string pair(p); + std::vector pair_u; + u8_u16(pair_u, pair); + unsigned short a = pair_u.size() > 1 ? (unsigned short)pair_u[1] : 0, + b = !pair_u.empty() ? (unsigned short)pair_u[0] : 0; + if (((unicodetoupper(a, langnum) == a && unicodetolower(a, langnum) != a) || + (unicodetoupper(b, langnum) == b && unicodetolower(b, langnum) != b)) && + (a != '-') && (b != '-')) + return 1; + } else { + const unsigned char a = word[pos - 1], 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, + short maxwordnum, + hentry* rv, + hentry** def, + char all) { + int w = 0; + + if (!*words) { + w = 1; + *words = def; + } + + if (!*words) { + return 0; + } + + if (wnum >= maxwordnum) { + if (w) + *words = nullptr; + return 0; + } + + std::vector btinfo(1); + + short bt = 0; + + (*words)[wnum] = rv; + + // has the last word COMPOUNDRULE flag? + if (rv->alen == 0) { + (*words)[wnum] = nullptr; + if (w) + *words = nullptr; + return 0; + } + int ok = 0; + for (auto& i : defcpdtable) { + for (auto& j : i) { + if (j != '*' && j != '?' && + TESTAFF(rv->astr, j, rv->alen)) { + ok = 1; + break; + } + } + } + if (ok == 0) { + (*words)[wnum] = nullptr; + if (w) + *words = nullptr; + return 0; + } + + for (auto& i : defcpdtable) { + size_t pp = 0; // pattern position + signed short wp = 0; // "words" position + int ok2 = 1; + ok = 1; + do { + while ((pp < i.size()) && (wp <= wnum)) { + if (((pp + 1) < i.size()) && + ((i[pp + 1] == '*') || + (i[pp + 1] == '?'))) { + int wend = (i[pp + 1] == '?') ? wp : wnum; + ok2 = 1; + pp += 2; + btinfo[bt].btpp = pp; + btinfo[bt].btwp = wp; + while (wp <= wend) { + if (!(*words)[wp] || + !(*words)[wp]->alen || + !TESTAFF((*words)[wp]->astr, 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, i[pp], + (*words)[wp]->alen)) { + ok = 0; + break; + } + pp++; + wp++; + if ((i.size() == pp) && !(wp > wnum)) + ok = 0; + } + } + if (ok && ok2) { + size_t r = pp; + while ((i.size() > r) && ((r + 1) < i.size()) && + ((i[r + 1] == '*') || + (i[r + 1] == '?'))) + r += 2; + if (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 || (i.size() <= pp))) + return 1; + + // check zero ending + while (ok && ok2 && (i.size() > pp) && + ((pp + 1) < i.size()) && + ((i[pp + 1] == '*') || + (i[pp + 1] == '?'))) + pp += 2; + if (ok && ok2 && (i.size() <= pp)) + return 1; + } + (*words)[wnum] = nullptr; + if (w) + *words = nullptr; + return 0; +} + +inline int AffixMgr::candidate_check(const std::string& word) { + + struct hentry* rv = lookup(word.c_str(), word.size()); + if (rv) + return 1; + + // rv = prefix_check(word,0,len,1); + // if (rv) return 1; + + rv = affix_check(word, 0, word.size()); + 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) { + num = (short)std::count_if(word.begin(), word.end(), + [&](char c) { + return std::binary_search(cpdvowels.begin(), cpdvowels.end(), c); + }); + } else if (!cpdvowels_utf16.empty()) { + std::vector w; + u8_u16(w, word); + num = (short)std::count_if(w.begin(), w.end(), + [&](w_char wc) { + return std::binary_search(cpdvowels_utf16.begin(), cpdvowels_utf16.end(), wc); + }); + } + + return num; +} + +void AffixMgr::setcminmax(size_t* cmin, size_t* cmax, const char* word, size_t 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 = nullptr, + hentry** rwords = nullptr, + char hu_mov_rule = 0, + char is_sug = 0, + int* info = nullptr) { + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + hentry *rv = nullptr, *rv_first; + std::string st; + char ch = '\0', affixed; + size_t cmin, cmax; + int striple = 0, soldi = 0, oldcmin = 0, oldcmax = 0, oldlen = 0, checkedstriple = 0; + hentry** oldwords = words; + size_t scpd = 0, len = word.size(); + + // protect subsequent words[wnum + 1] reads and any recursion + if (wnum + 1 >= maxwordnum) + return nullptr; + + int checked_prefix; + + // add a time limit to handle possible + // combinatorical explosion of the overlapping words + + HUNSPELL_THREAD_LOCAL std::chrono::steady_clock::time_point clock_time_start; + HUNSPELL_THREAD_LOCAL bool timelimit_exceeded; + + // get the current time + std::chrono::steady_clock::time_point clock_now = std::chrono::steady_clock::now(); + + if (wnum == 0) { + // set the start time + clock_time_start = clock_now; + timelimit_exceeded = false; + } + else if (clock_now - clock_time_start > TIMELIMIT_MS) + timelimit_exceeded = true; + + setcminmax(&cmin, &cmax, word.c_str(), len); + + st.assign(word); + + for (size_t 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 nullptr; + } + + words = oldwords; + int onlycpdrule = (words) ? 1 : 0; + + do { // onlycpdrule loop + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + do { // simplified checkcompoundpattern loop + + if (timelimit_exceeded || + std::chrono::steady_clock::now() - clock_time_start > TIMELIMIT_MS) { + timelimit_exceeded = true; + return nullptr; + } + + if (scpd > 0) { + for (; scpd <= checkcpdtable.size() && + (checkcpdtable[scpd - 1].pattern3.empty() || + i > word.size() || + word.compare(i, checkcpdtable[scpd - 1].pattern3.size(), checkcpdtable[scpd - 1].pattern3) != 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; + } + + if (i >= st.size()) + return nullptr; + + ch = st[i]; + st[i] = '\0'; + + sfx = nullptr; + pfx = nullptr; + + // FIRST WORD + + affixed = 1; + rv = lookup(st.c_str(), i); // perhaps without prefix + + // forbid dictionary stems with COMPOUNDFORBIDFLAG in + // compound words, overriding the effect of COMPOUNDPERMITFLAG + if ((rv) && compoundforbidflag && + TESTAFF(rv->astr, compoundforbidflag, rv->alen) && !hu_mov_rule) { + bool would_continue = !onlycpdrule && simplifiedcpd; + if (!scpd && would_continue) { + // given the while conditions that continue jumps to, this situation + // never ends + HUNSPELL_WARNING(stderr, "break infinite loop\n"); + break; + } + + if (scpd > 0 && would_continue) { + // under these conditions we loop again, but the assumption above + // appears to be that cmin and cmax are the original values they + // had in the outside loop + cmin = oldcmin; + cmax = oldcmax; + } + continue; + } + + // 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, maxwordnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, maxwordnum, 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, 0, i, + hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())) || + (compoundend && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = nullptr; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, + compoundbegin))) || // twofold suffixes + compound + (rv = prefix_check(st, 0, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, + compoundmiddle))) || // twofold suffixes + compound + (rv = prefix_check(st, 0, 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 = nullptr; + } + + // 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 = nullptr; + } + + // 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 = nullptr; + } + + // 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 nullptr; + } + + // 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 && i < word.size() && // 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 && i < word.size() && + cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && + (rv = affix_check(st, 0, 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 && i <= word.size() && word[i - 1] == word[i - 2]) + striple = 1; + } + + rv = lookup(st.c_str() + i, st.size() - 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, maxwordnum, rv, nullptr, 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 && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = nullptr; + + 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 nullptr; + + // 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 || + (i < word.size() && !cpdpat_check(word, 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, len)) || + cpdwordpair_check(word, len)) + return nullptr; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = nullptr; + sfxflag = FLAG_NULL; + rv = (compoundflag && !onlycpdrule && i < word.size()) ? affix_check(word, i, word.size() - i, compoundflag, IN_CPD_END) + : nullptr; + if (!rv && compoundend && !onlycpdrule) { + sfx = nullptr; + pfx = nullptr; + if (i < word.size()) + rv = affix_check(word, i, word.size() - i, compoundend, IN_CPD_END); + } + + if (!rv && !defcpdtable.empty() && words) { + if (i < word.size()) + rv = affix_check(word, i, word.size() - i, 0, IN_CPD_END); + if (rv && defcpd_check(&words, wnum + 1, maxwordnum, rv, nullptr, 1)) + return rv_first; + rv = nullptr; + } + + // 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 = nullptr; + + // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds) + if (rv && !checkcpdtable.empty() && scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) + rv = nullptr; + + // 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 = nullptr; + } + + // check FORCEUCASE + if (rv && forceucase && + (TESTAFF(rv->astr, forceucase, rv->alen)) && + !(info && *info & SPELL_ORIGCAP)) + rv = nullptr; + + // 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 nullptr; + + // 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) { + if (i < word.size()) { + // calculate syllable number of the word + numsyllable += get_syllable(word.substr(i)); + } + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= short(get_syllable(tmp) + sfxextra); + } else { + numsyllable -= short(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, len)) || + cpdwordpair_check(word, len)) + return nullptr; + return rv_first; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word is a compound word (recursive call) + // (only if SPELL_COMPOUND_2 is not set and maxwordnum is not exceeded) + if ((!info || !(*info & SPELL_COMPOUND_2)) && wordnum + 2 < maxwordnum && wnum + 1 < maxwordnum) { + rv = compound_check(st.substr(i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + is_sug, info); + + if (rv && !checkcpdtable.empty() && i < word.size() && + ((scpd == 0 && + cpdpat_check(word, i, rv_first, rv, affixed)) || + (scpd != 0 && + !cpdpat_check(word, i, rv_first, rv, affixed)))) + rv = nullptr; + } else { + rv = nullptr; + } + if (rv) { + // forbid compound word, if it is a non-compound word with typical + // fault, or a dictionary word pair + + if (cpdwordpair_check(word, len)) + return nullptr; + + if (checkcompoundrep || forbiddenword) { + + if (checkcompoundrep && cpdrep_check(word, len)) + return nullptr; + + // check first part + if (i < word.size() && word.compare(i, rv->blen, rv->word, rv->blen) == 0) { + char r = st[i + rv->blen]; + st[i + rv->blen] = '\0'; + + if ((checkcompoundrep && cpdrep_check(st, i + rv->blen)) || + cpdwordpair_check(st, i + rv->blen)) { + st[ + i + rv->blen] = r; + continue; + } + + if (forbiddenword) { + struct hentry* rv2 = lookup(word.c_str(), word.size()); + if (!rv2 && len <= word.size()) + rv2 = affix_check(word, 0, len); + if (rv2 && rv2->astr && + TESTAFF(rv2->astr, forbiddenword, rv2->alen) && + (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) { + return nullptr; + } + } + 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; + len = oldlen; + cmin = oldcmin; + cmax = oldcmax; + } else + st[i] = ch; + + } while (!defcpdtable.empty() && oldwordnum == 0 && + onlycpdrule++ < 1); // end of onlycpd loop + } + + return nullptr; +} + +// check if compound word is correctly spelled +// hu_mov_rule = spec. Hungarian rule (XXX) +int AffixMgr::compound_check_morph(const std::string& word, + short wordnum, + short numsyllable, + short maxwordnum, + short wnum, + hentry** words, + hentry** rwords, + char hu_mov_rule, + std::string& result, + const std::string* partresult) { + short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2; + hentry *rv = nullptr, *rv_first; + std::string st, presult; + char ch, affixed = 0; + int checked_prefix, ok = 0; + size_t cmin, cmax; + hentry** oldwords = words; + size_t len = word.size(); + + // protect subsequent words[wnum + 1] reads and any recursion + if (wnum + 1 >= maxwordnum) + return 0; + + // add a time limit to handle possible + // combinatorical explosion of the overlapping words + + HUNSPELL_THREAD_LOCAL std::chrono::steady_clock::time_point clock_time_start; + HUNSPELL_THREAD_LOCAL bool timelimit_exceeded; + + // get the current time + std::chrono::steady_clock::time_point clock_now = std::chrono::steady_clock::now(); + + if (wnum == 0) { + // set the start time + clock_time_start = clock_now; + timelimit_exceeded = false; + } + else if (clock_now - clock_time_start > TIMELIMIT_MS) + timelimit_exceeded = true; + + setcminmax(&cmin, &cmax, word.c_str(), len); + + st.assign(word); + + for (size_t 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 + + if (timelimit_exceeded) + return 0; + + oldnumsyllable = numsyllable; + oldwordnum = wordnum; + checked_prefix = 0; + + if (i >= st.size()) + return 0; + + ch = st[i]; + st[i] = '\0'; + sfx = nullptr; + + // FIRST WORD + + affixed = 1; + + presult.clear(); + if (partresult) + presult.append(*partresult); + + rv = lookup(st.c_str(), i); // perhaps without prefix + + // forbid dictionary stems with COMPOUNDFORBIDFLAG in + // compound words, overriding the effect of COMPOUNDPERMITFLAG + if ((rv) && compoundforbidflag && + TESTAFF(rv->astr, compoundforbidflag, rv->alen) && !hu_mov_rule) + continue; + + // 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, maxwordnum, rv, rwords, 0)) || + (words && + defcpd_check(&words, wnum, maxwordnum, 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, 0, i); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + presult.push_back(MSEP_FLD); + presult.append(MORPH_STEM); + presult.append(st, 0, i); + } + if (HENTRY_DATA(rv)) { + presult.push_back(MSEP_FLD); + presult.append(HENTRY_DATA2(rv)); + } + } + + if (!rv) { + if (compoundflag && + !(rv = + prefix_check(st, 0, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, + compoundflag))) { + if (((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, compoundflag)))) && + !hu_mov_rule && sfx->getCont() && + ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, sfx->getContLen())) || + (compoundend && TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) { + rv = nullptr; + } + } + + if (rv || + (((wordnum == 0) && compoundbegin && + ((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, + compoundbegin))) || // twofold suffix+compound + (rv = prefix_check(st, 0, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundbegin)))) || + ((wordnum > 0) && compoundmiddle && + ((rv = suffix_check(st, 0, i, 0, nullptr, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) || + (compoundmoresuffixes && (rv = suffix_check_twosfx(st, 0, i, 0, nullptr, + compoundmiddle))) || // twofold suffix+compound + (rv = prefix_check(st, 0, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundmiddle)))))) { + std::string p; + if (compoundflag) + p = affix_check_morph(st, 0, i, compoundflag); + if (p.empty()) { + if ((wordnum == 0) && compoundbegin) { + p = affix_check_morph(st, 0, i, compoundbegin); + } else if ((wordnum > 0) && compoundmiddle) { + p = affix_check_morph(st, 0, i, compoundmiddle); + } + } + if (!p.empty()) { + presult.push_back(MSEP_FLD); + presult.append(MORPH_PART); + presult.append(st, 0, i); + 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 = nullptr; + } + + // 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, nullptr, affixed)) || + (checkcompoundcase && !words && cpdcase_check(word, i)))) + // LANG_hu section: spec. Hungarian rule + || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && (rv = affix_check(st, 0, 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.c_str() + i, word.size() - 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, maxwordnum, rv, nullptr, 1))))) { + rv = rv->next_homonym; + } + + if (rv && words && words[wnum + 1]) { + result.append(presult); + result.push_back(MSEP_FLD); + result.append(MORPH_PART); + result.append(word, i, word.size()); + if (complexprefixes && HENTRY_DATA(rv)) + result.append(HENTRY_DATA2(rv)); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + result.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(rv)); + } + // store the pointer of the hash entry + if (!complexprefixes && HENTRY_DATA(rv)) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(rv)); + } + result.push_back(MSEP_REC); + 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.push_back(MSEP_FLD); + result.append(MORPH_PART); + result.append(word, i, word.size()); + + if (HENTRY_DATA(rv)) { + if (complexprefixes) + result.append(HENTRY_DATA2(rv)); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + result.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(rv)); + } + // store the pointer of the hash entry + if (!complexprefixes) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(rv)); + } + } + result.push_back(MSEP_REC); + ok = 1; + } + + numsyllable = oldnumsyllable2; + wordnum = oldwordnum2; + + // perhaps second word has prefix or/and suffix + sfx = nullptr; + sfxflag = FLAG_NULL; + + if (compoundflag && !onlycpdrule) + rv = affix_check(word, i, word.size() - i, compoundflag); + else + rv = nullptr; + + if (!rv && compoundend && !onlycpdrule) { + sfx = nullptr; + pfx = nullptr; + rv = affix_check(word, i, word.size() - i, compoundend); + } + + if (!rv && !defcpdtable.empty() && words) { + rv = affix_check(word, i, word.size() - i, 0, IN_CPD_END); + if (rv && words && defcpd_check(&words, wnum + 1, maxwordnum, rv, nullptr, 1)) { + std::string m; + if (compoundflag) + m = affix_check_morph(word, i, word.size() - i, compoundflag); + if (m.empty() && compoundend) { + m = affix_check_morph(word, i, word.size() - i, compoundend); + } + result.append(presult); + if (!m.empty()) { + result.push_back(MSEP_FLD); + result.append(MORPH_PART); + result.append(word, i, word.size()); + line_uniq_app(m, MSEP_REC); + result.append(m); + } + result.push_back(MSEP_REC); + 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 = nullptr; + } + + // 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.c_str() + i); + + // - affix syllable num. + // XXX only second suffix (inflections, not derivations) + if (sfxappnd) { + std::string tmp(sfxappnd); + reverseword(tmp); + numsyllable -= short(get_syllable(tmp) + sfxextra); + } else { + numsyllable -= short(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, word.size() - i, compoundflag); + if (m.empty() && compoundend) { + m = affix_check_morph(word, i, word.size() - i, compoundend); + } + result.append(presult); + if (!m.empty()) { + result.push_back(MSEP_FLD); + result.append(MORPH_PART); + result.append(word, i, word.size()); + line_uniq_app(m, MSEP_REC); + result.push_back(MSEP_FLD); + 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) && (wnum + 1 < maxwordnum) && (ok == 0)) { + compound_check_morph(word.substr(i), wordnum + 1, + numsyllable, maxwordnum, wnum + 1, words, rwords, 0, + result, &presult); + } else { + rv = nullptr; + } + } + 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 std::string& word, + int start, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + struct hentry* rv = nullptr; + 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, start, 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 nullptr; // FULLSTRIP + unsigned char sp = word[start + len - 1]; + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word.c_str() + start + 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, start, 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 nullptr; +} + +// check word for two-level suffixes +struct hentry* AffixMgr::suffix_check_twosfx(const std::string& word, + int start, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag) { + struct hentry* rv = nullptr; + + // first handle the special case of 0 length suffixes + SfxEntry* se = sStart[0]; + while (se) { + if (contclasses[se->getFlag()]) { + rv = se->check_twosfx(word, start, len, sfxopts, ppfx, needflag); + if (rv) + return rv; + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return nullptr; // FULLSTRIP + unsigned char sp = word[start + len - 1]; + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word.c_str() + start + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + rv = sptr->check_twosfx(word, start, 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 nullptr; +} + +// check word for two-level suffixes and morph +std::string AffixMgr::suffix_check_twosfx_morph(const std::string& word, + int start, + 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, start, len, sfxopts, ppfx, needflag); + if (!st.empty()) { + if (ppfx) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.push_back(MSEP_FLD); + } else + debugflag(result, ppfx->getFlag()); + } + result.append(st); + if (se->getMorph()) { + result.push_back(MSEP_FLD); + result.append(se->getMorph()); + } else + debugflag(result, se->getFlag()); + result.push_back(MSEP_REC); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return { }; // FULLSTRIP + unsigned char sp = word[start + len - 1]; + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word.c_str() + start + len - 1, len)) { + if (contclasses[sptr->getFlag()]) { + std::string st = sptr->check_twosfx_morph(word, start, 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.push_back(MSEP_FLD); + result3.append(sptr->getMorph()); + } else + debugflag(result3, sptr->getFlag()); + strlinecat(result2, result3); + result2.push_back(MSEP_REC); + result.append(result2); + } + } + sptr = sptr->getNextEQ(); + } else { + sptr = sptr->getNextNE(); + } + } + + return result; +} + +std::string AffixMgr::suffix_check_morph(const std::string& word, + int start, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG cclass, + const FLAG needflag, + char in_compound) { + std::string result; + + struct hentry* rv = nullptr; + + 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, start, len, sfxopts, ppfx, cclass, + needflag, FLAG_NULL); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.push_back(MSEP_FLD); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + result.append(HENTRY_DATA2(rv)); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + result.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(rv)); + } + + if (!complexprefixes && HENTRY_DATA(rv)) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(rv)); + } + if (se->getMorph()) { + result.push_back(MSEP_FLD); + result.append(se->getMorph()); + } else + debugflag(result, se->getFlag()); + result.push_back(MSEP_REC); + rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag); + } + } + se = se->getNext(); + } + + // now handle the general case + if (len == 0) + return { }; // FULLSTRIP + unsigned char sp = word[start + len - 1]; + SfxEntry* sptr = sStart[sp]; + + while (sptr) { + if (isRevSubset(sptr->getKey(), word.c_str() + start + 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, start, len, sfxopts, ppfx, cclass, + needflag, FLAG_NULL); + while (rv) { + if (ppfx) { + if (ppfx->getMorph()) { + result.append(ppfx->getMorph()); + result.push_back(MSEP_FLD); + } else + debugflag(result, ppfx->getFlag()); + } + if (complexprefixes && HENTRY_DATA(rv)) + result.append(HENTRY_DATA2(rv)); + if (!HENTRY_FIND(rv, MORPH_STEM)) { + result.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(HENTRY_WORD(rv)); + } + + if (!complexprefixes && HENTRY_DATA(rv)) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(rv)); + } + + if (sptr->getMorph()) { + result.push_back(MSEP_FLD); + result.append(sptr->getMorph()); + } else + debugflag(result, sptr->getFlag()); + result.push_back(MSEP_REC); + 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 std::string& word, + int start, + int len, + const FLAG needflag, + char in_compound) { + + // check all prefixes (also crossed with suffixes if allowed) + struct hentry* rv = prefix_check(word, start, len, in_compound, needflag); + if (rv) + return rv; + + // if still not found check all suffixes + rv = suffix_check(word, start, len, 0, nullptr, FLAG_NULL, needflag, in_compound); + + if (havecontclass) { + sfx = nullptr; + pfx = nullptr; + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = suffix_check_twosfx(word, start, len, 0, nullptr, needflag); + + if (rv) + return rv; + // if still not found check all two-level suffixes + rv = prefix_check_twosfx(word, start, len, IN_CPD_NOT, needflag); + } + + return rv; +} + +// check if word with affixes is correctly spelled +std::string AffixMgr::affix_check_morph(const std::string& word, + int start, + 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, start, len, in_compound); + if (!st.empty()) { + result.append(st); + } + + // if still not found check all suffixes + st = suffix_check_morph(word, start, len, 0, nullptr, '\0', needflag, in_compound); + if (!st.empty()) { + result.append(st); + } + + if (havecontclass) { + sfx = nullptr; + pfx = nullptr; + // if still not found check all two-level suffixes + st = suffix_check_twosfx_morph(word, start, len, 0, nullptr, needflag); + if (!st.empty()) { + result.append(st); + } + + // if still not found check all two-level suffixes + st = prefix_check_twosfx_morph(word, start, 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, 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 = nullptr; + } + 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); + 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 = nullptr; + } + 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); + } + 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 {}; + + // check substandard flag + if (TESTAFF(ap, substandard, al)) + return {}; + + 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.push_back(MSEP_FLD); + stemmorphcatpos = mymorph.size(); + } else { + stemmorphcatpos = std::string::npos; + } + + for (int i = 0; i < al; i++) { + const auto 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(), newword.size()); // 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 { }; +} + +namespace { + // replaces strdup with ansi version + char* mystrdup(const char* s) { + char* d = nullptr; + if (s) { + size_t sl = strlen(s) + 1; + d = new char[sl]; + memcpy(d, s, sl); + } + return d; + } +} + +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); + wlst[nh].allow = false; + wlst[nh].orig = nullptr; + nh++; + // add special phonetic version + if (phon && (nh < maxn)) { + wlst[nh].word = mystrdup(phon); + wlst[nh].allow = false; + wlst[nh].orig = mystrdup(ts); + nh++; + } + } + + // handle suffixes + for (int i = 0; i < al; i++) { + const auto 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 = nullptr; + 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()); + wlst[nh].allow = false; + wlst[nh].orig = mystrdup(newword.c_str()); + 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 auto 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 = nullptr; + nh++; + } + } + } + cptr = cptr->getFlgNxt(); + } + } + } + + // now handle pure prefixes + for (int m = 0; m < al; m++) { + const auto 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 = nullptr; + nh++; + } + } + } + ptr = ptr->getFlgNxt(); + } + } + + return nh; +} + +// return replacing table +const std::vector& AffixMgr::get_reptable() const { + return pHMgr->get_reptable(); +} + +// return iconv table +RepList* AffixMgr::get_iconvtable() const { + if (!iconvtable) + return nullptr; + return iconvtable; +} + +// return oconv table +RepList* AffixMgr::get_oconvtable() const { + if (!oconvtable) + return nullptr; + return oconvtable; +} + +// return replacing table +struct phonetable* AffixMgr::get_phonetable() const { + if (!phone) + return nullptr; + 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; +} + +std::string 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 nullptr; + 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 +const std::string& AffixMgr::get_key_string() { + if (keystring.empty()) + keystring = SPELL_KEYSTRING; + return keystring; +} + +// return the preferred try string for suggestions +const std::string& AffixMgr::get_try_string() const { + return trystring; +} + +// 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 substandard root/affix control flag +FLAG AffixMgr::get_substandard() const { + return substandard; +} + +// 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, size_t len) { + struct hentry* he = nullptr; + for (size_t i = 0; i < alldic.size() && !he; ++i) { + he = alldic[i]->lookup(word, len); + } + 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() const { + return maxngramsugs; +} + +int AffixMgr::get_maxcpdsugs() const { + return maxcpdsugs; +} + +int AffixMgr::get_maxdiff() const { + return maxdiff; +} + +int AffixMgr::get_onlymaxdiff() const { + return onlymaxdiff; +} + +// return nosplitsugs +int AffixMgr::get_nosplitsugs() const { + return nosplitsugs; +} + +// return sugswithdots +int AffixMgr::get_sugswithdots() 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); + 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; + auto iter = line.begin(), 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; +} + +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; + auto iter = line.begin(), 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 = nullptr; + 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; + } + std::unique_ptr new_phone; + int num = -1; + int i = 0; + int np = 0; + auto iter = line.begin(), 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; + } + new_phone.reset(new phonetable); + new_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 = new_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: { + new_phone->rules.emplace_back(start_piece, iter); + break; + } + case 2: { + new_phone->rules.emplace_back(start_piece, iter); + mystrrep(new_phone->rules.back(), "_", ""); + break; + } + default: + break; + } + ++i; + } + start_piece = mystrsep(nl, iter); + } + if (new_phone->rules.size() != old_size + 2) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return false; + } + } + new_phone->rules.emplace_back(""); + new_phone->rules.emplace_back(""); + init_phonet_hash(*new_phone); + phone = new_phone.release(); + 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; + auto iter = line.begin(), 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(std::min(numcheckcpd, 16384)); + 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.emplace_back(); + 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()); + checkcpdtable.clear(); + 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); + } + 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); + } + 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; + auto iter = line.begin(), 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(std::min(numdefcpd, 16384)); + 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.emplace_back(); + 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 (auto k = start_piece; k != iter; ++k) { + auto chb = k, che = k + 1; + if (*k == '(') { + auto 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; + auto iter = line.begin(), 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(std::min(nummap, 16384)); + 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.emplace_back(); + 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 (auto k = start_piece; k != iter; ++k) { + auto chb = k, che = k + 1; + if (*k == '(') { + auto 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; + } + } + if (chb == che) { + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + } + + maptable.back().emplace_back(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; + auto iter = line.begin(), 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(std::min(numbreak, 16384)); + 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.emplace_back(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; + // iterate backwards; k wraps to npos (SIZE_MAX) when decremented past 0 + for (size_t k = piece.size() - 1; k != std::string::npos; --k) { + switch (piece[k]) { + case '[': { + if (neg) + piece[k + 1] = '['; + else + piece[k] = ']'; + break; + } + case ']': { + piece[k] = '['; + if (neg) + piece[k + 1] = '^'; + neg = 0; + break; + } + case '^': { + if (piece[k + 1] == ']') + neg = 1; + else if (neg) + piece[k + 1] = piece[k]; + break; + } + default: { + if (neg) + piece[k + 1] = piece[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(std::min(numents, 16384)); + + 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() ? nullptr : entries[0]; } + + ~entries_container() { + for (auto& entry : entries) { + delete entry; + } + } + + 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; + auto iter = line.begin(), 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)); + 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))) { + std::string err = pHMgr->encode_flag(aflag); + HUNSPELL_WARNING(stderr, "error: line %d: affix %s: bad entry number\n", + af->getlinenum(), err.c_str()); + 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) { + std::string err = pHMgr->encode_flag(aflag); + HUNSPELL_WARNING(stderr, "error: line %d: affix %s: missing data\n", + af->getlinenum(), err.c_str()); + 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) != aflag) { + std::string err = pHMgr->encode_flag(aflag); + HUNSPELL_WARNING(stderr, + "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err.c_str()); + 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 = nullptr; + entry->contclass = nullptr; + 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() && !has_no_ignored_chars(entry->appnd, ignorechars)) { + 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, 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() && !has_no_ignored_chars(entry->appnd, ignorechars)) { + 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, chunk, + af->getlinenum())) + chunk = "."; + if (at == 'S') { + reverseword(chunk); + reverse_condition(chunk); + } + if (encodeit(*entry, chunk)) + 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()); + } + break; + } + default: + break; + } + i++; + start_piece = mystrsep(nl, iter); + } + // check to make sure we parsed enough pieces + if (np < 4) { + std::string err = pHMgr->encode_flag(aflag); + HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n", + af->getlinenum(), err.c_str()); + 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 + auto start = affentries.begin(), end = affentries.end(); + for (auto affentry = start; affentry != end; ++affentry) { + if (at == 'P') { + build_pfxtree(dynamic_cast(*affentry)); + } else { + build_sfxtree(dynamic_cast(*affentry)); + } + } + + //contents belong to AffixMgr now + affentries.release(); + + return true; +} + +int AffixMgr::redundant_condition(char ft, + const std::string& strip, + const std::string& cond, + int linenum) { + int stripl = strip.size(), condl = cond.size(), i, j, neg, in; + if (ft == 'P') { // prefix + if (strip.compare(0, condl, cond) == 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.c_str()); + 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) && strip.compare(stripl - condl, std::string::npos, 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 if (j > 0) { + 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.c_str()); + 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 std::string& root_word) { + std::vector slst; + short unsigned* start_ptr = suff; + for (auto ptr : sStart) { + 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, 0, nw.size(), 0, nullptr, 0, 0, 0); + if (ht) { + slst.push_back(std::move(nw)); + } + } + suff++; + } + ptr = ptr->getNext(); + } + } + return slst; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.hxx new file mode 100644 index 00000000..a6061092 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/affixmgr.hxx @@ -0,0 +1,379 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 + +#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; + const 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; + 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 = nullptr); + ~AffixMgr(); + struct hentry* affix_check(const std::string& word, + int start, + int len, + const unsigned short needflag = (unsigned short)0, + char in_compound = IN_CPD_NOT); + struct hentry* prefix_check(const std::string& word, + int start, + 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 std::string& word, + int start, + 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 std::string& word, + int start, + 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 std::string& word, + int start, + int len, + int sfxopts, + PfxEntry* ppfx, + const FLAG needflag = FLAG_NULL); + + std::string affix_check_morph(const std::string& word, + int start, + int len, + const FLAG needflag = FLAG_NULL, + char in_compound = IN_CPD_NOT); + std::string prefix_check_morph(const std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + std::string suffix_check_morph(const std::string& word, + int start, + 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 std::string& word, + int start, + int len, + char in_compound, + const FLAG needflag = FLAG_NULL); + std::string suffix_check_twosfx_morph(const std::string& word, + int start, + 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 std::string& word, int len); + int cpdwordpair_check(const std::string& word, int len); + int cpdpat_check(const std::string& word, + size_t len, + hentry* r1, + hentry* r2, + const char affixed); + int defcpd_check(hentry*** words, + short wnum, + short maxwordnum, + hentry* rv, + hentry** rwords, + char all); + int cpdcase_check(const std::string& word, int len); + inline int candidate_check(const std::string& word); + void setcminmax(size_t* cmin, size_t* cmax, const char* word, size_t 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 std::string& word, + 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 std::string& root_word); + + struct hentry* lookup(const char* word, size_t len); + 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; + const std::string& get_key_string(); + const std::string& 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_substandard() 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() const; + FLAG get_keepcase() const; + FLAG get_forceucase() const; + FLAG get_warn() const; + int get_forbidwarn() const; + int get_checksharps() const; + std::string 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_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 std::string& s); + int encodeit(AffEntry& entry, const std::string& 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 std::string& strip, const std::string& cond, int); + void finishFileMgr(FileMgr* afflst); +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/atypes.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/atypes.hxx new file mode 100644 index 00000000..86ea4c7c --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/atypes.hxx @@ -0,0 +1,137 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 +#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) // the result is a compound word +#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 SPELL_COMPOUND_2 (1 << 7) // permit only 2 dictionary words in the compound +#define SPELL_BEST_SUG (1 << 8) // limit suggestions for the best ones, i.e. ph: + +#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)) + +// timelimit: max. ~1/4 sec wall time for a suggestion, including max. +// ~1/10 sec for a case sensitive plain or compound word suggestion, +// within ~1/20 sec long time consuming suggestion functions +#define TIMELIMIT_GLOBAL_MS std::chrono::milliseconds(250) +#define TIMELIMIT_SUGGESTION_MS std::chrono::milliseconds(100) +#define TIMELIMIT_MS std::chrono::milliseconds(50) +#define MINTIMER 100 +#define MAXPLUSTIMER 100 + +struct guessword { + char* word; + bool allow; + char* orig; + guessword() + : word(nullptr) + , allow(false) + , orig(nullptr) + { + } +}; + +using mapentry = std::vector; +using flagentry = std::vector; + +struct patentry { + std::string pattern; + std::string pattern2; + std::string pattern3; + FLAG cond; + FLAG cond2; + patentry() + : cond(FLAG_NULL) + , cond2(FLAG_NULL) { + } +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/baseaffix.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/baseaffix.hxx new file mode 100644 index 00000000..f4bd85e1 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/baseaffix.hxx @@ -0,0 +1,72 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 { + public: + AffEntry() + : numconds(0) + , opts(0) + , aflag(0) + , morphcode(nullptr) + , contclass(nullptr) + , contclasslen(0) {} + AffEntry(const AffEntry&) = delete; + AffEntry& operator=(const AffEntry&) = delete; + 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; + unsigned short contclasslen; +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.cxx new file mode 100644 index 00000000..24d0d799 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.cxx @@ -0,0 +1,2659 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#include +#endif + +#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" +#endif +#endif + +#ifdef MOZILLA_CLIENT +#include "nsCOMPtr.h" +#include "nsUnicharUtils.h" +#include "mozilla/Encoding.h" + +using namespace mozilla; +#endif + +#ifndef MOZILLA_CLIENT +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); +} +#endif + +std::string& u16_u8(std::string& dest, const std::vector& src) { + dest.clear(); + dest.reserve(src.size()); + auto u2 = src.begin(), 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, bool only_convert_first_letter) { + // faster to oversize initially, assign to elements and resize to what's used + // than to reserve and push_back + dest.resize(only_convert_first_letter ? 1 : src.size()); + auto u16 = dest.begin(); + auto u8 = src.begin(), 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 < u8_max && (*(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 < u8_max && (*(u8 + 1) & 0xc0) == 0x80) { + u2.h = ((*u8 & 0x0f) << 4) + ((*(u8 + 1) & 0x3f) >> 2); + ++u8; + if (u8 + 1 < u8_max && (*(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; + } + default: { // 4 or more byte UTF-8 codes + assert(((*u8) & 0xf0) == 0xf0 && "can only be 0xf0"); + 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; + *u16++ = u2; + dest.resize(u16 - dest.begin()); + return -1; + } + } + *u16++ = u2; + if (only_convert_first_letter) + break; + ++u8; + } + + int size = u16 - dest.begin(); + dest.resize(size); + return size; +} + +namespace { +class is_any_of { + public: + explicit is_any_of(const std::string& in) : chars(in) {} + + bool operator()(char c) const { 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) { + auto 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 + auto sp = start; + while (sp != end && op(*sp)) + ++sp; + + auto dp = sp; + while (dp != end && !op(*dp)) + ++dp; + + start = dp; + return sp; +} + +// 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 (auto& line : lines) { + text.append(line); + 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 (const char c : beg) { + 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::reverse(word.begin(), word.end()); //1st step: we reverse the string + + //2nd step: we process each multibyte character and reverse it + for (auto it = word.rbegin(); it != word.rend(); ) { + switch ((*it) & 0xf0) { + case 0x00: + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: + //one byte + ++it; + 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(word.begin(), it.base()) - 1), + word.c_str()); + ++it; + break; + case 0xc0: + case 0xd0: { + //two bytes + if (std::distance(it, word.rend()) >= 2) { + std::iter_swap(it, it + 1); + it += 2; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing character at the end\n%s\n", + word.c_str()); + ++it; + } + break; + } + case 0xe0: { + //three bytes + if (std::distance(it, word.rend()) >= 3) { + std::iter_swap(it, it + 2); + it += 3; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing character at the end\n%s\n", + word.c_str()); + ++it; + } + break; + } + default: { + // 4 or more byte UTF-8 codes + if (std::distance(it, word.rend()) >= 4) { + std::iter_swap(it, it + 3); + std::iter_swap(it + 1, it + 2); + it += 4; + } else { + HUNSPELL_WARNING(stderr, + "UTF-8 encoding error. Missing character at the end\n%s\n", + word.c_str()); + ++it; + } + break; + } + } + } + return word.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) { + assert(nIndex >= 0 && nIndex <= 255); + return csconv[nIndex].cupper; +} + +unsigned char clower(const struct cs_info* csconv, int nIndex) { + assert(nIndex >= 0 && nIndex <= 255); + return csconv[nIndex].clower; +} + +unsigned char ccase(const struct cs_info* csconv, int nIndex) { + assert(nIndex >= 0 && nIndex <= 255); + return csconv[nIndex].ccase; +} +} + +w_char upper_utf(w_char u, int langnum) { + +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + +//with these optimizations, msvc can optimize this function to one jmp instruction +//but g++ remains in five instructions +//maybe use inline asm for g++? + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + return std::bit_cast(unicodetoupper((unsigned short)u, langnum)); +#else + const auto us = unicodetoupper((unsigned short)u, langnum); + memcpy(&u, &us, sizeof(unsigned short)); + return u; +#endif + +#else + const auto us = unicodetoupper((unsigned short)u, langnum); + u.h = (unsigned char)(us >> 8); + u.l = (unsigned char)(us & 0xff); + return u; +#endif +} + +w_char lower_utf(w_char u, int langnum) { + +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + +//with these optimizations, msvc can optimize this function to one jmp instruction +//but g++ remains in five instructions +//maybe use inline asm for g++? + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + return std::bit_cast(unicodetolower((unsigned short)u, langnum)); +#else + const auto us = unicodetolower((unsigned short)u, langnum); + memcpy(&u, &us, sizeof(unsigned short)); + return u; +#endif + +#else + const auto us = unicodetolower((unsigned short)u, langnum); + u.h = (unsigned char)(us >> 8); + u.l = (unsigned char)(us & 0xff); + return u; +#endif +} + +// convert std::string to all caps +std::string& mkallcap(std::string& s, const struct cs_info* csconv) { + for (char& aI : s) { + 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 (char& aI : s) { + aI = clower(csconv, static_cast(aI)); + } + return s; +} + +std::vector& mkallsmall_utf(std::vector& u, int langnum) { + for (auto& i : u) { + i = lower_utf(i, langnum); + } + return u; +} + +std::vector& mkallcap_utf(std::vector& u, int langnum) { + for (auto& i : u) { + i = upper_utf(i, langnum); + } + 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()) { + u[0] = upper_utf(u[0], langnum); + } + 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()) { + u[0] = lower_utf(u[0], langnum); + } + 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 + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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}}; + +const 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; + const struct cs_info* cs_table; +}; + +const 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'; +} + +const struct cs_info* get_current_cs(const std::string& es) { + char* normalized_encoding = new char[es.size() + 1]; + toAsciiLowerAndRemoveNonAlphanumeric(es.c_str(), normalized_encoding); + + const struct cs_info* ccs = nullptr; + for (const auto& encd : encds) { + if (strcmp(normalized_encoding, encd.enc_name) == 0) { + ccs = encd.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. +const 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; + } + + auto encoding = Encoding::ForLabelNoReplacement(es); + if (!encoding) { + return ccs; + } + auto encoder = encoding->NewEncoder(); + auto decoder = encoding->NewDecoderWithoutBOMHandling(); + + 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. + uint8_t lower, upper; + do { + if (i == 0) + break; + uint8_t source = uint8_t(i); + char16_t uni[2]; + char16_t uniCased; + uint8_t destination[4]; + auto src1 = MakeSpan(&source, 1); + auto dst1 = MakeSpan(uni); + auto src2 = MakeSpan(&uniCased, 1); + auto dst2 = MakeSpan(destination); + + uint32_t result; + size_t read; + size_t written; + Tie(result, read, written) = + decoder->DecodeToUTF16WithoutReplacement(src1, dst1, true); + if (result != kInputEmpty || read != 1 || written != 1) { + break; + } + + uniCased = ToLowerCase(uni[0]); + Tie(result, read, written) = + encoder->EncodeFromUTF16WithoutReplacement(src2, dst2, true); + if (result != kInputEmpty || read != 1 || written != 1) { + break; + } + lower = destination[0]; + + uniCased = ToUpperCase(uni[0]); + Tie(result, read, written) = + encoder->EncodeFromUTF16WithoutReplacement(src2, dst2, true); + if (result != kInputEmpty || read != 1 || written != 1) { + break; + } + upper = destination[0]; + + success = true; + } while (0); + + encoding->NewEncoderInto(*encoder); + encoding->NewDecoderWithoutBOMHandlingInto(*decoder); + + 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) { + const 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; +}; + +const 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) { + for (const auto& i : lang2enc) { + if (strcmp(lang.c_str(), i.lang) == 0) { + return i.num; + } + } + return LANG_xx; +} + +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[c].cupper; +#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[c].clower; +#endif +#endif +} + +int unicodeisalpha(unsigned short c) { +#ifdef OPENOFFICEORG + return u_isalpha(c); +#else + return utf_tbl[c].cletter; +#endif +} + +/* get type of capitalization */ +int get_captype(const std::string& word, const 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 == nullptr) + return NOCAP; + for (char q : word) { + const auto nIndex = static_cast(q); + if (ccase(csconv, nIndex)) + ncap++; + if (cupper(csconv, nIndex) == clower(csconv, nIndex)) + nneutral++; + } + if (ncap) { + const auto 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; + + auto it = word.begin(), it_end = word.end(); + while (it != it_end) { + const auto idx = (unsigned short)*it; + const auto lwridx = unicodetolower(idx, langnum); + if (idx != lwridx) + ncap++; + if (unicodetoupper(idx, langnum) == lwridx) + nneutral++; + ++it; + } + if (ncap) { + const auto idx = (unsigned short)word[0]; + 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); + + std::copy_if(w.begin(), w.end(), std::back_inserter(w2), + [&ignored_chars](w_char wc) { + return !std::binary_search(ignored_chars.begin(), ignored_chars.end(), wc); + }); + + 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; + auto iter = line.begin(), 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; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.hxx new file mode 100644 index 00000000..ded10b81 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/csutil.hxx @@ -0,0 +1,323 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 +#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, + bool only_convert_first_letter = false); + +// remove end of line char(s) +LIBHUNSPELL_DLL_EXPORTED void mychomp(std::string& 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 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 const 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, const 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); + + +// to avoid unnecessary string copies and Unicode conversions +// we simply check the ignored_chars characters in the word +// (in the case of UTF-8 encoded strings, "false" means +// "likely false", if ignored_chars characters are not ASCII) +inline bool has_no_ignored_chars(const std::string& word, + const std::string& ignored_chars) { + return std::all_of(ignored_chars.begin(), ignored_chars.end(), + [&word](char ic) { return word.find(ic) == std::string::npos; }); +} + +// hash entry macros +inline char* HENTRY_DATA(struct hentry* h) { + char* ret; + if (!(h->var & H_OPT)) + ret = nullptr; + 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 & H_OPT)) + ret = nullptr; + 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 & H_OPT)) + 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) { + char* data = HENTRY_DATA(h); + return data ? strstr(data, p) : nullptr; +} + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.cxx new file mode 100644 index 00000000..c5064ab2 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.cxx @@ -0,0 +1,121 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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(nullptr) + , linenum(0) { + in[0] = '\0'; + + if (!file || !strlen(file)) + return; + 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 && hin->is_open()) { + ret = hin->getline(dest); + } + if (!ret) { + --linenum; + } + return ret; +} + +int FileMgr::getlinenum() { + return linenum; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.hxx new file mode 100644 index 00000000..0603b7d7 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/filemgr.hxx @@ -0,0 +1,96 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 { + 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 = nullptr); + FileMgr(const FileMgr&) = delete; + FileMgr& operator=(const FileMgr&) = delete; + ~FileMgr(); + bool getline(std::string&); + int getlinenum(); +}; +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.cxx new file mode 100644 index 00000000..d0d5816f --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.cxx @@ -0,0 +1,1414 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#include +#endif + +#include "hashmgr.hxx" +#include "csutil.hxx" +#include "atypes.hxx" +#include "langnum.hxx" + +// build a hash table from a munched word list + +HashMgr::HashMgr(const char* tpath, const char* apath, const char* key) + : flag_mode(FLAG_CHAR) + , complexprefixes(0) + , utf8(0) + , forbiddenword(FORBIDDENWORD) // forbidden word signing flag + , langnum(0) + , csconv(nullptr) { + load_config(apath, key); + if (!csconv) + csconv = get_current_cs(SPELL_ENCODING); + int ec = load_tables(tpath, key); + if (ec) { + /* error condition - what should we do here */ + fprintf(stderr, "Hash Manager Error : %d\n", ec); + free_table(); + //keep table size to 1 to fix possible division with zero + tableptr.resize(1, nullptr); + } +} + +void HashMgr::release_flags(unsigned short* astr, bool owned) { + if (owned) + delete[] astr; +} + +void HashMgr::free_table() { + // now pass through hash table freeing up everything + // go through column by column of the table + for (auto ptr : tableptr) { + hentry* nt = nullptr; + while (ptr) { + nt = ptr->next; + release_flags(ptr->astr, ptr->var & H_OPT_OWNFLAGS); + free(ptr); + ptr = nt; + } + } + tableptr.clear(); +} + +HashMgr::~HashMgr() { + free_table(); + + for (auto& j : aliasf) + delete[] j; + aliasf.clear(); + + for (auto& j : aliasm) + delete[] j; + aliasm.clear(); + +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +// lookup a root word in the hashtable + +struct hentry* HashMgr::lookup(const char* word, size_t len) const { + struct hentry* dp = tableptr[hash(word, len)]; + if (!dp) + return nullptr; + for (; dp != nullptr; dp = dp->next) { + if (strcmp(word, dp->word) == 0) + return dp; + } + return nullptr; +} + +// 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, + int captype, + bool own_aff) { + + if (al > std::numeric_limits::max()) { + HUNSPELL_WARNING(stderr, "error: affix len %d is over max limit\n", al); + release_flags(aff, own_aff); + return 1; + } + + const std::string* word = &in_word; + const std::string* desc = in_desc; + + std::string* word_copy = nullptr; + std::string* desc_copy = nullptr; + if ((!ignorechars.empty() && !has_no_ignored_chars(in_word, ignorechars)) || 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.empty()) { + 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; + } + + // limit of hp->blen + if (word->size() > std::numeric_limits::max()) { + HUNSPELL_WARNING(stderr, "error: word len %ld is over max limit\n", word->size()); + delete desc_copy; + delete word_copy; + release_flags(aff, own_aff); + return 1; + } + + bool upcasehomonym = false; + int descl = desc ? (!aliasm.empty() ? sizeof(char*) : desc->size() + 1) : 0; + // variable-length hash record with word and optional fields + auto hp = + (struct hentry*)malloc(sizeof(struct hentry) + word->size() + descl); + if (!hp) { + delete desc_copy; + delete word_copy; + release_flags(aff, own_aff); + return 1; + } + + char* hpw = hp->word; + memcpy(hpw, word->data(), word->size()); + hpw[word->size()] = 0; + + int i = hash(hpw, word->size()); + + hp->blen = (unsigned short)word->size(); + hp->clen = (unsigned short)wcl; + hp->alen = (short)al; + hp->astr = aff; + hp->next = nullptr; + hp->next_homonym = nullptr; + hp->var = (captype == INITCAP) ? H_OPT_INITCAP : 0; + if (own_aff) + hp->var |= H_OPT_OWNFLAGS; + + // store the description string or its pointer + if (desc) { + hp->var |= H_OPT; + if (!aliasm.empty()) { + 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 (HENTRY_FIND(hp, MORPH_PHON)) { + hp->var |= H_OPT_PHON; + // store ph: fields (pronounciation, misspellings, old orthography etc.) + // of a morphological description in reptable to use in REP replacements. + size_t predicted = tableptr.size() / MORPH_PHON_RATIO; + if (reptable.capacity() < predicted) + reptable.reserve(predicted); + std::string fields = HENTRY_DATA(hp); + std::string::const_iterator iter = fields.begin(), start_piece = mystrsep(fields, iter); + while (start_piece != fields.end()) { + if (std::string(start_piece, iter).find(MORPH_PHON) == 0) { + std::string ph = std::string(start_piece, iter).substr(sizeof MORPH_PHON - 1); + if (!ph.empty()) { + std::vector w; + size_t strippatt; + std::string wordpart; + // dictionary based REP replacement, separated by "->" + // for example "pretty ph:prity ph:priti->pretti" to handle + // both prity -> pretty and pritier -> prettiest suggestions. + if (((strippatt = ph.find("->")) != std::string::npos) && + (strippatt > 0) && (strippatt < ph.size() - 2)) { + wordpart = ph.substr(strippatt + 2); + ph.erase(ph.begin() + strippatt, ph.end()); + } else + wordpart = in_word; + // when the ph: field ends with the character *, + // strip last character of the pattern and the replacement + // to match in REP suggestions also at character changes, + // for example, "pretty ph:prity*" results "prit->prett" + // REP replacement instead of "prity->pretty", to get + // prity->pretty and pritiest->prettiest suggestions. + if (ph.at(ph.size()-1) == '*') { + strippatt = 1; + size_t stripword = 0; + if (utf8) { + while ((strippatt < ph.size()) && + ((ph.at(ph.size()-strippatt-1) & 0xc0) == 0x80)) + ++strippatt; + while ((stripword < wordpart.size()) && + ((wordpart.at(wordpart.size()-stripword-1) & 0xc0) == 0x80)) + ++stripword; + } + ++strippatt; + ++stripword; + if ((ph.size() > strippatt) && (wordpart.size() > stripword)) { + ph.erase(ph.size()-strippatt, strippatt); + wordpart.erase(wordpart.size()-stripword, stripword); + } + } + // capitalize lowercase pattern for capitalized words to support + // good suggestions also for capitalized misspellings, eg. + // Wednesday ph:wendsay + // results wendsay -> Wednesday and Wendsay -> Wednesday, too. + if (captype == INITCAP) { + std::string ph_capitalized; + if (utf8) { + u8_u16(w, ph); + if (get_captype_utf8(w, langnum) == NOCAP) { + mkinitcap_utf(w, langnum); + u16_u8(ph_capitalized, w); + } + } else if (get_captype(ph, csconv) == NOCAP) + mkinitcap(ph_capitalized, csconv); + + if (!ph_capitalized.empty()) { + // add also lowercase word in the case of German or + // Hungarian to support lowercase suggestions lowercased by + // compound word generation or derivational suffixes + // (for example by adjectival suffix "-i" of geographical + // names in Hungarian: + // Massachusetts ph:messzecsuzec + // messzecsuzeci -> massachusettsi (adjective) + // For lowercasing by conditional PFX rules, see + // tests/germancompounding test example or the + // Hungarian dictionary.) + if (langnum == LANG_de || langnum == LANG_hu) { + std::string wordpart_lower(wordpart); + if (utf8) { + u8_u16(w, wordpart_lower); + mkallsmall_utf(w, langnum); + u16_u8(wordpart_lower, w); + } else { + mkallsmall(wordpart_lower, csconv); + } + reptable.emplace_back(); + reptable.back().pattern.assign(ph); + reptable.back().outstrings[0].assign(wordpart_lower); + } + reptable.emplace_back(); + reptable.back().pattern.assign(ph_capitalized); + reptable.back().outstrings[0].assign(wordpart); + } + } + reptable.emplace_back(); + reptable.back().pattern.assign(ph); + reptable.back().outstrings[0].assign(wordpart); + } + } + start_piece = mystrsep(fields, iter); + } + } + } + + struct hentry* dp = tableptr[i]; + if (!dp) { + tableptr[i] = hp; + delete desc_copy; + delete word_copy; + return 0; + } + while (dp->next != nullptr) { + 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)) { + release_flags(dp->astr, dp->var & H_OPT_OWNFLAGS); + dp->astr = hp->astr; + dp->alen = hp->alen; + dp->var &= ~H_OPT_OWNFLAGS; + dp->var |= (hp->var & H_OPT_OWNFLAGS); + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else if (!dp->astr && dp->alen == 0 && + !hp->astr && hp->alen == 0) { + // word already exists with no flags, skip duplicate + release_flags(hp->astr, hp->var & H_OPT_OWNFLAGS); + 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)) { + release_flags(dp->astr, dp->var & H_OPT_OWNFLAGS); + dp->astr = hp->astr; + dp->alen = hp->alen; + dp->var &= ~H_OPT_OWNFLAGS; + dp->var |= (hp->var & H_OPT_OWNFLAGS); + free(hp); + delete desc_copy; + delete word_copy; + return 0; + } else if (!dp->astr && dp->alen == 0 && + !hp->astr && hp->alen == 0) { + // word already exists with no flags, skip duplicate + release_flags(hp->astr, hp->var & H_OPT_OWNFLAGS); + 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 + release_flags(hp->astr, hp->var & H_OPT_OWNFLAGS); + 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 == nullptr) + 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 = new unsigned short[flagslen + 1]; + flags2[flagslen] = ONLYUPCASEFLAG; + if (flagslen) { + memcpy(flags2, flags, flagslen * sizeof(unsigned short)); + std::sort(flags2, flags2 + flagslen + 1); + } + 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, INITCAP, 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, INITCAP, 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(), word.size()); + while (dp) { + if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { + auto flags = new unsigned short[dp->alen + 1]; + for (int i = 0; i < dp->alen; i++) + flags[i] = dp->astr[i]; + flags[dp->alen] = forbiddenword; + release_flags(dp->astr, dp->var & H_OPT_OWNFLAGS); + dp->astr = flags; + dp->alen++; + dp->var |= H_OPT_OWNFLAGS; + std::sort(flags, flags + dp->alen); + } + dp = dp->next_homonym; + } + return 0; +} + +/* remove forbidden flag to add a personal word to the hash */ +void HashMgr::remove_forbidden_flag(const std::string& word) { + struct hentry* dp = lookup(word.c_str(), word.size()); + if (!dp) + return; + while (dp) { + if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { + if (dp->alen == 1) { + release_flags(dp->astr, dp->var & H_OPT_OWNFLAGS); + dp->astr = nullptr; + dp->alen = 0; + dp->var &= ~H_OPT_OWNFLAGS; + } else { + auto newflags = new unsigned short[dp->alen - 1]; + int j = 0; + for (int i = 0; i < dp->alen; i++) { + if (dp->astr[i] != forbiddenword) + newflags[j++] = dp->astr[i]; + } + release_flags(dp->astr, dp->var & H_OPT_OWNFLAGS); + dp->astr = newflags; + dp->alen = (short)j; + dp->var |= H_OPT_OWNFLAGS; + } + } + dp = dp->next_homonym; + } +} + +// add a custom dic. word to the hash table (public) +int HashMgr::add(const std::string& word) { + remove_forbidden_flag(word); + int captype, al = 0; + unsigned short* flags = nullptr; + int wcl = get_clen_and_captype(word, &captype); + if (add_word(word, wcl, flags, al, nullptr, false, captype, true)) + return 1; + return add_hidden_capitalized_word(word, wcl, flags, al, nullptr, captype); +} + +int HashMgr::add_with_flags(const std::string& word, const std::string& flags, const std::string& desc) { + remove_forbidden_flag(word); + int captype; + unsigned short *df; + int al = decode_flags(&df, flags, nullptr); + int wcl = get_clen_and_captype(word, &captype); + if (add_word(word, wcl, df, al, &desc, false, captype, true)) + return 1; + return add_hidden_capitalized_word(word, wcl, df, al, &desc, captype); +} + +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(), example.size()); + remove_forbidden_flag(word); + if (dp && dp->astr) { + int captype; + int wcl = get_clen_and_captype(word, &captype); + auto flags = new unsigned short[dp->alen]; + memcpy(flags, dp->astr, dp->alen * sizeof(unsigned short)); + if (add_word(word, wcl, flags, dp->alen, nullptr, false, captype, true)) + return 1; + return add_hidden_capitalized_word(word, wcl, flags, dp->alen, nullptr, 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 != nullptr) + return hp->next; + for (col++; col < (int)tableptr.size(); ++col) { + if (tableptr[col]) + return tableptr[col]; + } + // null at end and reset to start + col = -1; + return nullptr; +} + +// 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); + + // first read the first line of file to get hash table size + std::string ts; + if (!dict->getline(ts)) { + fprintf(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); + } + + int tablesize = atoi(ts.c_str()); + + const int nExtra = 5 + USERWORD; +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + const int max_allowed = (std::numeric_limits::max() - 1 - nExtra) / int(sizeof(struct hentry*)); +#else + const int max_allowed = (10000 - 1 - nExtra) / int(sizeof(struct hentry*)); +#endif + + if (tablesize <= 0 || tablesize >= max_allowed) { + fprintf(stderr, + "error: %s: line 1: missing or bad word count in the dic file\n", + tpath); + delete dict; + return 4; + } + tablesize += nExtra; + if ((tablesize & 1) == 0) + tablesize++; + + // allocate the hash table + tableptr.resize(tablesize, nullptr); + + // loop through all words on much list and add to hash + // table and create word and affix strings + + std::vector workbuf; + + int nLineCount(0); + while (dict->getline(ts)) { + ++nLineCount; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // limit words loaded to avoid O(n^2) hash chain walk timeout + if (nLineCount >= tablesize) + break; +#endif + 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.empty()) { + 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, 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 = nullptr; + } + + int captype; + int wcl = get_clen_and_captype(ts, &captype, workbuf); + const std::string* dp_str = dp.empty() ? nullptr : &dp; + // add the word and its index plus its capitalized form optionally + bool own = aliasf.empty(); + if (add_word(ts, wcl, flags, al, dp_str, false, captype, own) || + add_hidden_capitalized_word(ts, wcl, flags, al, dp_str, captype)) { + delete dict; + return 5; + } + } + + int ret(0); + + // reject ludicrous tablesizes + if (tablesize > 8192 + nExtra && tablesize > nLineCount * 10 + nExtra) { + HUNSPELL_WARNING(stderr, ".dic initial approximate word count line value of %d is too large for %d lines\n", tablesize, nLineCount); + ret = 3; + } + + delete dict; + return ret; +} + +// the hash function is a simple load and rotate +// algorithm borrowed +int HashMgr::hash(const char* word, size_t len) const { + unsigned long hv = 0; + size_t i = 0; + while (i < 4 && i < len) + hv = (hv << 8) | word[i++]; + while (i < len) { + ROTATE(hv, ROTATE_LEN); + hv ^= word[i++]; + } + return (unsigned long)hv % tableptr.size(); +} + +int HashMgr::decode_flags(unsigned short** result, const std::string& flags, FileMgr* af) const { + int len; + if (flags.empty()) { + *result = nullptr; + return 0; + } + switch (flag_mode) { + case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) + len = flags.size(); + if ((len & 1) == 1 && af != nullptr) + HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", + af->getlinenum()); + len >>= 1; + *result = new unsigned short[len]; + for (int i = 0; i < len; i++) { + unsigned short flag = ((unsigned short)((unsigned char)flags[i << 1]) << 8) | + ((unsigned short)((unsigned char)flags[(i << 1) | 1])); + + (*result)[i] = flag; + } + break; + } + case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 + // 23 233) + len = int(1 + std::count_if(flags.begin(), flags.end(), [](char c) { return c == ','; })); + *result = new unsigned short[len]; + unsigned short* dest = *result; + const char* src = flags.c_str(); + for (size_t p = 0; p < flags.size(); ++p) { + if (flags[p] == ',') { + int i = atoi(src); + if ((i > std::numeric_limits::max() || i < 0) && af != nullptr) { + HUNSPELL_WARNING( + stderr, "error: line %d: flag id %d is out of range\n", + af->getlinenum(), i); + i = 0; + } + *dest = (unsigned short)i; + if (*dest == 0 && af != nullptr) + HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", + af->getlinenum()); + src = flags.c_str() + p + 1; + dest++; + } + } + int i = atoi(src); + if ((i > std::numeric_limits::max() || i < 0) && af) { + HUNSPELL_WARNING(stderr, + "error: line %d: flag id %d is out of range\n", + af->getlinenum(), i); + i = 0; + } + *dest = (unsigned short)i; + if (*dest == 0 && af) + 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 = new unsigned short[len]; +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + memcpy(*result, w.data(), len * sizeof(unsigned short)); +#else + unsigned short* dest = *result; + for (const w_char wc : w) { + *dest = (unsigned short)wc; + dest++; + } +#endif + break; + } + default: { // Ispell's one-character flags (erfg -> e r f g) + len = flags.size(); + *result = new unsigned short[len]; + unsigned short* dest = *result; + for (const char flag : flags) { + *dest = (unsigned char)flag; + 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 & 1) == 1) + HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", + af->getlinenum()); + len >>= 1; + size_t origsize = result.size(); + result.resize(origsize + len); + for (size_t i = 0; i < len; ++i) { + result[origsize + i] = ((unsigned short)((unsigned char)flags[i << 1]) << 8) | + ((unsigned short)((unsigned char)flags[(i << 1) | 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 > std::numeric_limits::max() || i < 0) { + HUNSPELL_WARNING( + stderr, "error: line %d: flag id %d is out of range\n", + af->getlinenum(), i); + i = 0; + } + 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 > std::numeric_limits::max() || i < 0) { + HUNSPELL_WARNING(stderr, + "error: line %d: flag id %d is out of range\n", + af->getlinenum(), i); + i = 0; + } + 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(), origsize = result.size(); + result.resize(origsize + len); +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + memcpy(result.data() + origsize, w.data(), len * sizeof(short)); +#else + for (size_t i = 0; i < len; ++i) + result[origsize + i] = (unsigned short)w[i]; +#endif + break; + } + default: { // Ispell's one-character flags (erfg -> e r f g) + result.reserve(flags.size()); + for (const char flag : flags) { + result.push_back((unsigned char)flag); + } + } + } + return true; +} + +unsigned short HashMgr::decode_flag(const std::string& f) const { + unsigned short s = 0; + int i; + switch (flag_mode) { + case FLAG_LONG: + if (f.size() >= 2) + s = ((unsigned short)((unsigned char)f[0]) << 8) | ((unsigned short)((unsigned char)f[1])); + break; + case FLAG_NUM: + i = atoi(f.c_str()); + if (i > std::numeric_limits::max() || i < 0) { + HUNSPELL_WARNING(stderr, "error: flag id %d is out of range\n", i); + i = 0; + } + s = (unsigned short)i; + break; + case FLAG_UNI: { + std::vector w; + u8_u16(w, f); + if (!w.empty()) + s = (unsigned short)w[0]; + break; + } + default: + if (!f.empty()) + s = (unsigned char)f[0]; + } + if (s == 0) + HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); + return s; +} + +std::string HashMgr::encode_flag(unsigned short f) const { + if (f == 0) + return "(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) { + ch = std::to_string(f); + } else if (flag_mode == FLAG_UNI) { + +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + auto wc = std::bit_cast(f); +#else + w_char wc; + memcpy(&wc, &f, sizeof(unsigned short)); +#endif + +#else + w_char wc; + wc.h = (unsigned char)(f >> 8); + wc.l = (unsigned char)(f & 0xff); +#endif + const std::vector w = { wc }; + u16_u8(ch, w); + } else { + ch.push_back((unsigned char)(f)); + } + return ch; +} + +// 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); + + // 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); + } + + 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; + } 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; + + /* parse in the typical fault correcting table */ + if (line.compare(0, 3, "REP", 3) == 0) { + if (!parse_reptable(line, afflst)) { + delete afflst; + return 1; + } + } + + // don't check the full affix file, yet + if (((line.compare(0, 3, "SFX", 3) == 0) || + (line.compare(0, 3, "PFX", 3) == 0)) && + line.size() > 3 && isspace(line[3]) && + !reptable.empty()) // (REP table is in the end of Afrikaans aff file) + break; + } + + delete afflst; + return 0; +} + +/* parse in the ALIAS table */ +bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) { + if (!aliasf.empty()) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return false; + } + int i = 0, np = 0, numaliasf = 0; + auto iter = line.begin(), 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) { + aliasf.clear(); + aliasflen.clear(); + HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", + af->getlinenum()); + return false; + } + aliasf.reserve(std::min(numaliasf, 16384)); + aliasflen.reserve(std::min(numaliasf, 16384)); + np++; + break; + } + default: + break; + } + ++i; + start_piece = mystrsep(line, iter); + } + if (np != 2) { + aliasf.clear(); + aliasflen.clear(); + 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; + unsigned short* alias = nullptr; + unsigned aliaslen = 0; + i = 0; + if (af->getline(nl)) { + mychomp(nl); + iter = nl.begin(); + start_piece = mystrsep(nl, iter); + bool errored = false; + while (!errored && start_piece != nl.end()) { + switch (i) { + case 0: { + if (nl.compare(start_piece - nl.begin(), 2, "AF", 2) != 0) { + errored = true; + break; + } + break; + } + case 1: { + std::string piece(start_piece, iter); + aliaslen = + (unsigned short)decode_flags(&alias, piece, af); + std::sort(alias, alias + aliaslen); + break; + } + default: + break; + } + ++i; + start_piece = mystrsep(nl, iter); + } + } + if (!alias) { + for (int k = 0; k < j; ++k) { + delete[] aliasf[k]; + } + aliasf.clear(); + aliasflen.clear(); + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return false; + } + + aliasf.push_back(alias); + aliasflen.push_back(aliaslen); + } + return true; +} + +int HashMgr::is_aliasf() const { + return !aliasf.empty(); +} + +int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) const { + if (index > 0 && static_cast(index) <= aliasflen.size()) { + *fvec = aliasf[index - 1]; + return aliasflen[index - 1]; + } + HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", + af->getlinenum(), index); + *fvec = nullptr; + return 0; +} + +/* parse morph alias definitions */ +bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) { + if (!aliasm.empty()) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return false; + } + int i = 0, np = 0, numaliasm = 0; + auto iter = line.begin(), 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.reserve(std::min(numaliasm, 16384)); + np++; + break; + } + default: + break; + } + ++i; + start_piece = mystrsep(line, iter); + } + if (np != 2) { + aliasm.clear(); + 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; + char* alias = nullptr; + if (af->getline(nl)) { + mychomp(nl); + iter = nl.begin(); + i = 0; + start_piece = mystrsep(nl, iter); + bool errored = false; + while (!errored && start_piece != nl.end()) { + switch (i) { + case 0: { + if (nl.compare(start_piece - nl.begin(), 2, "AM", 2) != 0) { + errored = true; + break; + } + 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); + } + size_t sl = chunk.size() + 1; + alias = new char[sl]; + memcpy(alias, chunk.c_str(), sl); + break; + } + default: + break; + } + ++i; + start_piece = mystrsep(nl, iter); + } + } + if (!alias) { + for (int k = 0; k < j; ++k) { + delete[] aliasm[k]; + } + aliasm.clear(); + HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", + af->getlinenum()); + return false; + } + aliasm.push_back(alias); + } + return true; +} + +int HashMgr::is_aliasm() const { + return !aliasm.empty(); +} + +char* HashMgr::get_aliasm(int index) const { + if (index > 0 && static_cast(index) <= aliasm.size()) + return aliasm[index - 1]; + HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); + return nullptr; +} + +/* parse in the typical fault correcting table */ +bool HashMgr::parse_reptable(const std::string& line, FileMgr* af) { + if (!reptable.empty()) { + HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", + af->getlinenum()); + return false; + } + int numrep = -1, i = 0, np = 0; + auto iter = line.begin(), 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(std::min(numrep, 16384)); + 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; + reptable.emplace_back(); + int type = 0; + if (af->getline(nl)) { + mychomp(nl); + iter = nl.begin(); + i = 0; + start_piece = mystrsep(nl, iter); + bool errored = false; + while (!errored && start_piece != nl.end()) { + switch (i) { + case 0: { + if (nl.compare(start_piece - nl.begin(), 3, "REP", 3) != 0) { + errored = true; + break; + } + 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; +} + +// return replacing table +const std::vector& HashMgr::get_reptable() const { + return reptable; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.hxx new file mode 100644 index 00000000..1c31eb04 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hashmgr.hxx @@ -0,0 +1,159 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 }; + +// morphological description of a dictionary item can contain +// arbitrary number "ph:" (MORPH_PHON) fields to store typical +// phonetic or other misspellings of that word. +// ratio of lines/lines with "ph:" in the dic file: 1/MORPH_PHON_RATIO +#define MORPH_PHON_RATIO 500 + +class HashMgr { + std::vector tableptr; + flag flag_mode; + int complexprefixes; + int utf8; + unsigned short forbiddenword; + int langnum; + std::string enc; + std::string lang; + const struct cs_info* csconv; + std::string ignorechars; + std::vector ignorechars_utf16; + std::vector aliasf; // flag vector `compression' with aliases + std::vector aliasflen; + std::vector aliasm; // morphological desciption `compression' with aliases + // reptable created from REP table of aff file and from "ph:" fields + // of the dic file. It contains phonetic and other common misspellings + // (letters, letter groups and words) for better suggestions + std::vector reptable; + + public: + HashMgr(const char* tpath, const char* apath, const char* key = nullptr); + ~HashMgr(); + + struct hentry* lookup(const char* word, size_t len) const; + int hash(const char* word, size_t len) const; + struct hentry* walk_hashtable(int& col, struct hentry* hp) const; + + int add(const std::string& word); + int add_with_flags(const std::string& word, const std::string& flags, const std::string& desc = ""); + 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 std::string& flag) const; + std::string 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; + const std::vector& get_reptable() 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 captype, + bool own_aff); + 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); + bool parse_reptable(const std::string& line, FileMgr* af); + void remove_forbidden_flag(const std::string& word); + void free_table(); + void release_flags(unsigned short* astr, bool owned); +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/htypes.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/htypes.hxx new file mode 100644 index 00000000..be0396ab --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/htypes.hxx @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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) // is there optional morphological data? +#define H_OPT_ALIASM (1 << 1) // using alias compression? +#define H_OPT_PHON (1 << 2) // is there ph: field in the morphological data? +#define H_OPT_INITCAP (1 << 3) // is dictionary word capitalized? +#define H_OPT_OWNFLAGS (1 << 4) // astr is independently allocated? + +// see also csutil.hxx +#define HENTRY_WORD(h) &(h->word[0]) + +// approx. number of user defined words +#define USERWORD 1000 + +#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +# define HUNSPELL_THREAD_LOCAL thread_local +#else +# define HUNSPELL_THREAD_LOCAL static +#endif + +struct hentry { + unsigned short blen; // word length in bytes + unsigned short 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; // bit vector of H_OPT hentry options + char word[1]; // variable-length word (8-bit or UTF-8 encoding) +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.cxx new file mode 100644 index 00000000..83fcf9a5 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.cxx @@ -0,0 +1,2384 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 "affixmgr.hxx" +#include "hunspell.hxx" +#include "suggestmgr.hxx" +#include "hunspell.h" +#include "csutil.hxx" + +#include +#include +#include + +#define MAXWORDUTF8LEN (MAXWORDLEN * 3) + +class HunspellImpl +{ +public: + HunspellImpl(const char* affpath, const char* dpath, const char* key = nullptr); + HunspellImpl(const HunspellImpl&) = delete; + HunspellImpl& operator=(const HunspellImpl&) = delete; + ~HunspellImpl(); + int add_dic(const char* dpath, const char* key = nullptr); + 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, + std::vector& candidate_stack, + int* info = nullptr, + std::string* root = nullptr, + std::chrono::steady_clock::time_point suggest_start = std::chrono::steady_clock::time_point::max()); + std::vector suggest(const std::string& word); + std::vector suggest(const std::string& word, + std::vector& suggest_candidate_stack, + std::chrono::steady_clock::time_point suggest_start); + 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_flags(const std::string& word, const std::string& flags, const std::string& desc = ""); + 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 = nullptr, char** root = nullptr); + 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: + std::vector> m_HMgrs; + std::unique_ptr pAMgr; // pAMgr depends on m_HMgrs + std::unique_ptr pSMgr; // pSMgr depends on pAMgr + std::string affixpath; + std::string encoding; + const struct cs_info* csconv; + int langnum; + int utf8; + int complexprefixes; + std::vector wordbreak; + +private: + std::vector analyze_internal(const std::string& word); + bool spell_internal(const std::string& word, + std::vector& candidate_stack, + int* info = nullptr, + std::string* root = nullptr, + std::chrono::steady_clock::time_point suggest_start = std::chrono::steady_clock::time_point::max()); + std::vector suggest_internal(const std::string& word, + std::vector& spell_candidate_stack, + std::vector& suggest_candidate_stack, + bool& capitalized, size_t& abbreviated, int& captype, + std::chrono::steady_clock::time_point suggest_start); + 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 clean_ignore(std::string& dest, const std::string& src); + 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::chrono::steady_clock::time_point suggest_start = std::chrono::steady_clock::time_point::max()); + 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, + std::chrono::steady_clock::time_point suggest_start = std::chrono::steady_clock::time_point::max()); + 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 std::string& par, std::string::size_type pos); + std::string::size_type get_xml_pos(const std::string& s, std::string::size_type pos, const char* attr); + std::vector get_xml_list(const std::string& list, std::string::size_type pos, const char* tag); + int check_xml_par(const std::string& q, std::string::size_type pos, const char* attr, const char* value); +}; + +HunspellImpl::HunspellImpl(const char* affpath, const char* dpath, const char* key) + : affixpath(affpath) { + csconv = nullptr; + utf8 = 0; + complexprefixes = 0; + + /* first set up the hash manager */ + m_HMgrs.push_back(std::unique_ptr(new HashMgr(dpath, affpath, key))); + + /* next set up the affix manager */ + /* it needs access to the hash manager lookup methods */ + pAMgr.reset(new AffixMgr(affpath, m_HMgrs, key)); + + /* get the preferred try string and the dictionary */ + /* encoding from the Affix Manager for that dictionary */ + std::string 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.reset(new SuggestMgr(try_string, MAXSUGGESTION, pAMgr.get())); +} + +HunspellImpl::~HunspellImpl() { +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif + csconv = nullptr; +} + +// load extra dictionaries +int HunspellImpl::add_dic(const char* dpath, const char* key) { + m_HMgrs.push_back(std::unique_ptr(new HashMgr(dpath, affixpath.c_str(), key))); + return 0; +} + + +// make a copy of src at dest while removing all characters +// specified in IGNORE rule +void HunspellImpl::clean_ignore(std::string& dest, + const std::string& src) { + dest.clear(); + dest.assign(src); + const char* ignoredchars = pAMgr ? pAMgr->get_ignore() : nullptr; + if (ignoredchars != nullptr) { + if (utf8) { + const std::vector& ignoredchars_utf16 = + pAMgr->get_ignore_utf16(); + remove_ignored_chars_utf(dest, ignoredchars_utf16); + } else { + remove_ignored_chars(dest, ignoredchars); + } + } +} + + +// 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(); + + // remove IGNORE characters from the string + std::string w2; + clean_ignore(w2, src); + + const char* q = w2.c_str(); + int nl = (int)w2.size(); + + // first skip over any leading blanks + while (*q == ' ') { + ++q; + nl--; + } + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + + 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, nl = (int)src.size(); + + // first skip over any leading blanks + while (*q == ' ') { + ++q; + nl--; + } + + // now strip off any trailing periods (recording their presence) + *pabbrev = 0; + + 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 (auto& wc : t) { + const auto idx = (unsigned short)wc; + const auto low = unicodetolower(idx, langnum); + if (idx != low) + ncap++; + if (unicodetoupper(idx, langnum) == low) + nneutral++; + } + u16_u8(dest, t); + if (ncap) { + const auto idx = (unsigned short)t[0]; + 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, + std::chrono::steady_clock::time_point suggest_start) { + 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, suggest_start); + if (h) + return h; + base[pos] = 's'; + base[pos + 1] = 's'; + h = spellsharps(base, pos + 2, n + 1, repnum, info, root, suggest_start); + if (h) + return h; + } else if (repnum > 0) { + if (utf8) + return checkword(base, info, root, suggest_start); + std::string tmp(sharps_u8_l1(base)); + return checkword(tmp, info, root, suggest_start); + } + return nullptr; +} + +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, std::vector& candidate_stack, + int* info, std::string* root, + std::chrono::steady_clock::time_point suggest_start) { + // something very broken if spell ends up calling itself with the same word + if (std::find(candidate_stack.begin(), candidate_stack.end(), word) != candidate_stack.end()) + return false; + + // ofz#42529814 prevent deeply nested wordbreak recursion + if (candidate_stack.size() >= MAXBREAKDEPTH) + return false; + + candidate_stack.push_back(word); + bool r = spell_internal(word, candidate_stack, info, root, suggest_start); + candidate_stack.pop_back(); + + if (r && root) { + // output conversion + RepList* rl = (pAMgr) ? pAMgr->get_oconvtable() : nullptr; + if (rl) { + std::string wspace; + if (rl->conv(*root, wspace)) { + *root = std::move(wspace); + } + } + } + return r; +} + +bool HunspellImpl::spell_internal(const std::string& word, std::vector& candidate_stack, + int* info, std::string* root, + std::chrono::steady_clock::time_point suggest_start) { + struct hentry* rv = nullptr; + + 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() : nullptr; + { + 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 defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + if (wl > 32768) + return false; +#endif + +#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, suggest_start); + if ((abbv) && !(rv)) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer, info, root, suggest_start); + } + break; + case ALLCAP: { + *info |= SPELL_ORIGCAP; + rv = checkword(scw, info, root, suggest_start); + if (rv) + break; + if (abbv) { + std::string u8buffer(scw); + u8buffer.push_back('.'); + rv = checkword(u8buffer, info, root, suggest_start); + 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), 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 = std::move(part1u); + sunicw.insert(sunicw.end(), part2u.begin(), part2u.end()); + rv = checkword(scw, info, root, suggest_start); + if (rv) + break; + } else { + mkinitcap2(part2, sunicw); + scw = part1 + part2; + rv = checkword(scw, info, root, suggest_start); + if (rv) + break; + } + mkinitcap2(scw, sunicw); + rv = checkword(scw, info, root, suggest_start); + 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, suggest_start); + if (!rv) { + mkinitcap2(scw, sunicw); + rv = spellsharps(scw, 0, 0, 0, info, root, suggest_start); + } + if ((abbv) && !(rv)) { + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root, suggest_start); + if (!rv) { + u8buffer = std::string(scw); + u8buffer.push_back('.'); + rv = spellsharps(u8buffer, 0, 0, 0, info, root, suggest_start); + } + } + 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, suggest_start); + 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 = nullptr; + break; + } + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = nullptr; + 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, suggest_start); + if (abbv && !rv) { + u8buffer.push_back('.'); + rv = checkword(u8buffer, info, root, suggest_start); + if (!rv) { + u8buffer = scw; + u8buffer.push_back('.'); + if (captype == INITCAP) + *info |= SPELL_INITCAP; + rv = checkword(u8buffer, info, root, suggest_start); + if (captype == INITCAP) + *info &= ~SPELL_INITCAP; + if (rv && is_keepcase(rv) && (captype == ALLCAP)) + rv = nullptr; + 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 = nullptr; + 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 (auto& j : wordbreak) { + size_t pos = 0; + while ((pos = scw.find(j, pos)) != std::string::npos) { + ++nbr; + pos += j.size(); + } + } + if (nbr >= MAXBREAKDEPTH) + return false; + + // check boundary patterns (^begin and end$) + for (auto& j : wordbreak) { + size_t plen = j.size(); + if (plen == 1 || plen > wl) + continue; + + if (j[0] == '^' && scw.compare(0, plen - 1, j, 1, plen - 1) == 0 && + spell(scw.substr(plen - 1), candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + return true; + } + + if (j[plen - 1] == '$' && + scw.compare(wl - plen + 1, plen - 1, j, 0, plen - 1) == 0) { + std::string suffix(scw.substr(wl - plen + 1)); + scw.resize(wl - plen + 1); + if (spell(scw, candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + return true; + } + scw.append(suffix); + } + } + + // other patterns + for (auto& j : wordbreak) { + size_t plen = j.size(); + size_t found = scw.find(j); + if ((found > 0) && (found < wl - plen)) { + size_t found2 = scw.find(j, found + 1); + // try to break at the second occurance + // to recognize dictionary words with wordbreak + if (found2 > 0 && (found2 < wl - plen)) + found = found2; + std::string substring(scw.substr(found + plen)); + if (!spell(substring, candidate_stack, nullptr, nullptr, suggest_start)) + continue; + std::string suffix(scw.substr(found)); + scw.resize(found); + // examine 2 sides of the break point + if (spell(scw, candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + return true; + } + scw.append(suffix); + + // LANG_hu: spec. dash rule + if (langnum == LANG_hu && j == "-") { + suffix = scw.substr(found + 1); + scw.resize(found + 1); + if (spell(scw, candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + return true; // check the first part with dash + } + scw.append(suffix); + } + // end of LANG specific region + } + } + + // other patterns (break at first break point) + for (auto& j : wordbreak) { + size_t plen = j.size(), found = scw.find(j); + if ((found > 0) && (found < wl - plen)) { + if (!spell(scw.substr(found + plen), candidate_stack, nullptr, nullptr, suggest_start)) + continue; + std::string suffix(scw.substr(found)); + scw.resize(found); + // examine 2 sides of the break point + if (spell(scw, candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + return true; + } + scw.append(suffix); + + // LANG_hu: spec. dash rule + if (langnum == LANG_hu && j == "-") { + suffix = scw.substr(found + 1); + scw.resize(found + 1); + if (spell(scw, candidate_stack, nullptr, nullptr, suggest_start)) { + *info |= SPELL_COMPOUND; + 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, + std::chrono::steady_clock::time_point suggest_start) { + // check overall suggest time limit + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return nullptr; + + std::string word; + + // remove IGNORE characters from the string + clean_ignore(word, w); + + if (word.empty()) + return nullptr; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + if (utf8) + reverseword_utf(word); + else + reverseword(word); + } + + int len = word.size(); + + // look word in hash table + struct hentry* he = nullptr; + for (size_t i = 0; (i < m_HMgrs.size()) && !he; ++i) { + he = m_HMgrs[i]->lookup(word.c_str(), word.size()); + + // 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 nullptr; + } + + // 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, 0, 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 = nullptr; + } + + if (he) { + if ((he->astr) && (pAMgr) && + TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) { + if (info) + *info |= SPELL_FORBIDDEN; + return nullptr; + } + 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 + + // first allow only 2 words in the compound + int setinfo = SPELL_COMPOUND_2; + if (info) + setinfo |= *info; + he = pAMgr->compound_check(word, 0, 0, 100, 0, nullptr, (hentry**)&rwords, 0, 0, &setinfo); + if (info) + *info = setinfo & ~SPELL_COMPOUND_2; + // if not 2-word compoud word, try with 3 or more words + // (only if original info didn't forbid it) + if (!he && info && !(*info & SPELL_COMPOUND_2)) { + *info &= ~SPELL_COMPOUND_2; + he = pAMgr->compound_check(word, 0, 0, 100, 0, nullptr, (hentry**)&rwords, 0, 0, info); + // accept the compound with 3 or more words only if it is + // - not a dictionary word with a typo and + // - not two words written separately, + // - or if it's an arbitrary number accepted by compound rules (e.g. 999%) + if (he && !isdigit(word[0])) + { + std::vector slst; + if (pSMgr->suggest(slst, word, nullptr, /*test_simplesug=*/true)) + he = nullptr; + } + } + + // LANG_hu section: `moving rule' with last dash + if ((!he) && (langnum == LANG_hu) && (word[len - 1] == '-')) { + std::string dup(word, 0, len - 1); + he = pAMgr->compound_check(dup, -5, 0, 100, 0, nullptr, (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; +} + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) +#define MAX_CANDIDATE_STACK_DEPTH 512 +#else +#define MAX_CANDIDATE_STACK_DEPTH 2048 +#endif + +std::vector HunspellImpl::suggest(const std::string& word, std::vector& suggest_candidate_stack, std::chrono::steady_clock::time_point suggest_start) { + + if (suggest_candidate_stack.size() > MAX_CANDIDATE_STACK_DEPTH || // apply a fairly arbitrary depth limit + // something very broken if suggest ends up calling itself with the same word + std::find(suggest_candidate_stack.begin(), suggest_candidate_stack.end(), word) != suggest_candidate_stack.end()) { + return { }; + } + + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return { }; + + bool capwords; + size_t abbv; + int captype; + std::vector spell_candidate_stack; + suggest_candidate_stack.push_back(word); + std::vector slst = suggest_internal(word, spell_candidate_stack, suggest_candidate_stack, + capwords, abbv, captype, suggest_start); + suggest_candidate_stack.pop_back(); + // word reversing wrapper for complex prefixes + if (complexprefixes) { + for (auto& j : slst) { + if (utf8) + reverseword_utf(j); + else + reverseword(j); + } + } + + // capitalize + if (capwords) { + for (auto& j : slst) { + std::string capitalized(j); + mkinitcap(capitalized); + if (capitalized == word) + continue; // capitalizing would just reproduce the misspelled word + j = std::move(capitalized); + } + } + + // expand suggestions with dot(s) + if (abbv && pAMgr && pAMgr->get_sugswithdots() && word.size() >= abbv) { + for (auto& 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], spell_candidate_stack, nullptr, nullptr, suggest_start)) { + std::string s; + std::vector w; + if (utf8) { + u8_u16(w, slst[j]); + } else { + s = slst[j]; + } + mkallsmall2(s, w); + if (spell(s, spell_candidate_stack, nullptr, nullptr, suggest_start)) { + slst[l] = std::move(s); + ++l; + } else { + mkinitcap2(s, w); + if (spell(s, spell_candidate_stack, nullptr, nullptr, suggest_start)) { + slst[l] = std::move(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 + RepList* rl = (pAMgr) ? pAMgr->get_oconvtable() : nullptr; + if (rl) { + size_t l = 0; + for (size_t i = 0; i < slst.size(); ++i) { + std::string wspace; + if (rl->conv(slst[i], wspace)) { + slst[i] = std::move(wspace); + } + // gh#1002: OCONV can map a generated form back to the input word + // (e.g. "románórum" -> "romanórum" when the user typed "romanórum"), + // leaving the misspelled word as its own suggestion. + if (slst[i] == word) + continue; + if (l != i) + slst[l] = std::move(slst[i]); + ++l; + } + slst.resize(l); + } + return slst; +} + +std::vector HunspellImpl::suggest(const std::string& word) { + std::vector suggest_candidate_stack; + auto suggest_start = std::chrono::steady_clock::now(); + return suggest(word, suggest_candidate_stack, suggest_start); +} + +std::vector HunspellImpl::suggest_internal(const std::string& word, + std::vector& spell_candidate_stack, + std::vector& suggest_candidate_stack, + bool& capwords, size_t& abbv, int& captype, + std::chrono::steady_clock::time_point suggest_start) { + captype = NOCAP; + abbv = 0; + capwords = false; + + 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; + } + size_t wl = 0; + + std::string scw; + std::vector sunicw; + + // input conversion + RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : nullptr; + { + 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; + +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + if (wl > 32768) + return slst; +#endif + } + + bool good = false; + + // check capitalized form for FORCEUCASE + if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) { + int info = SPELL_ORIGCAP; + if (checkword(scw, &info, nullptr, suggest_start)) { + std::string form(std::move(scw)); + mkinitcap(form); + slst.push_back(std::move(form)); + return slst; + } + } + + switch (captype) { + case NOCAP: { + good |= pSMgr->suggest(slst, scw, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + if (abbv) { + std::string wspace(scw); + wspace.push_back('.'); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + } + break; + } + + case INITCAP: { + capwords = true; + good |= pSMgr->suggest(slst, scw, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + break; + } + case HUHINITCAP: + capwords = true; + /* FALLTHROUGH */ + case HUHCAP: { + good |= pSMgr->suggest(slst, scw, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + // 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); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + } + wspace = scw; + mkallsmall2(wspace, sunicw); + if (spell(wspace, spell_candidate_stack, nullptr, nullptr, suggest_start)) + insert_sug(slst, wspace); + size_t prevns = slst.size(); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + if (captype == HUHINITCAP) { + mkinitcap2(wspace, sunicw); + if (spell(wspace, spell_candidate_stack, nullptr, nullptr, suggest_start)) + insert_sug(slst, wspace); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + } + // 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) != 0) { + 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); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + if (pAMgr && pAMgr->get_keepcase() && spell(wspace, spell_candidate_stack, nullptr, nullptr, suggest_start)) + insert_sug(slst, wspace); + mkinitcap2(wspace, sunicw); + good |= pSMgr->suggest(slst, wspace, &onlycmpdsug); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + for (auto& j : slst) { + mkallcap(j); + if (pAMgr && pAMgr->get_checksharps()) { + if (utf8) { + mystrrep(j, "\xC3\x9F", "SS"); + } else { + mystrrep(j, "\xDF", "SS"); + } + } + } + break; + } + } + + // LANG_hu section: replace '-' with ' ' in Hungarian + if (langnum == LANG_hu) { + for (auto& j : slst) { + size_t pos = j.find('-'); + if (pos != std::string::npos) { + int info; + std::string w(j.substr(0, pos)); + w.append(j.substr(pos + 1)); + (void)spell(w, spell_candidate_stack, &info, nullptr, suggest_start); + if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) { + j[pos] = ' '; + } else + j[pos] = '-'; + } + } + } + // END OF LANG_hu section + // try ngram approach since found nothing good suggestion + if (!good && pAMgr && (slst.empty() || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0)) { + switch (captype) { + case NOCAP: { + pSMgr->ngsuggest(slst, scw.c_str(), m_HMgrs, NOCAP); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + break; + } + /* FALLTHROUGH */ + case HUHINITCAP: + capwords = true; + /* FALLTHROUGH */ + case HUHCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs, HUHCAP); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + break; + } + case INITCAP: { + capwords = true; + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs, INITCAP); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + break; + } + case ALLCAP: { + std::string wspace(scw); + mkallsmall2(wspace, sunicw); + size_t oldns = slst.size(); + pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs, ALLCAP); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + for (size_t j = oldns; j < slst.size(); ++j) { + mkallcap(slst[j]); + } + break; + } + } + } + + // try dash suggestion (Afo-American -> Afro-American) + // Note: LibreOffice was modified to treat dashes as word + // characters to check "scot-free" etc. word forms, but + // we need to handle suggestions for "Afo-American", etc., + // while "Afro-American" is missing from the dictionary. + // TODO avoid possible overgeneration + 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 (!good && nodashsug && !last) { + if (dash_pos == scw.size()) + last = true; + std::string chunk = scw.substr(prev_pos, dash_pos - prev_pos); + if (chunk != word && !spell(chunk, spell_candidate_stack, nullptr, nullptr, suggest_start)) { + std::vector nlst = suggest(chunk, suggest_candidate_stack, suggest_start); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_GLOBAL_MS) + return slst; + for (auto 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, nullptr, suggest_start); + 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(); + } + } + 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 (const auto& i : desc) { + std::string result; + + // add compound word parts (except the last one) + const char* s = 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 (auto& k : pl) { + // add derivational suffixes + if (k.find(MORPH_DERI_SFX) != std::string::npos) { + // remove inflectional suffixes + const size_t is = k.find(MORPH_INFL_SFX); + if (is != std::string::npos) + k.resize(is); + std::vector singlepl; + singlepl.push_back(k); + std::string sg = pSMgr->suggest_gen(singlepl, k); + if (!sg.empty()) { + std::vector gen = line_tok(sg, MSEP_REC); + for (auto& j : gen) { + result2.push_back(MSEP_REC); + result2.append(result); + result2.append(j); + } + } + } else { + result2.push_back(MSEP_REC); + result2.append(result); + if (k.find(MORPH_SURF_PFX) != std::string::npos) { + std::string field; + copy_field(field, k, MORPH_SURF_PFX); + result2.append(field); + } + std::string field; + copy_field(field, 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_flags(const std::string& word, const std::string& flags, const std::string& desc) { + if (!m_HMgrs.empty()) + return m_HMgrs[0]->add_with_flags(word, flags, desc); + 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() { + // Preserve pre-1.7.3 ABI: returned pointer is now to read-only data, + // but the public signature still says non-const. Callers must not + // write through it. + return const_cast(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 = analyze_internal(word); + // output conversion + RepList* rl = (pAMgr) ? pAMgr->get_oconvtable() : nullptr; + if (rl) { + for (size_t i = 0; rl && i < slst.size(); ++i) { + std::string wspace; + if (rl->conv(slst[i], wspace)) { + slst[i] = std::move(wspace); + } + } + } + return slst; +} + +std::vector HunspellImpl::analyze_internal(const std::string& word) { + std::vector candidate_stack, 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() : nullptr; + { + 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), nullptr, nullptr))) { + 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), part2 = scw.substr(dash_pos + 1); + + // examine 2 sides of the dash + if (part2.empty()) { // base word ending with dash + if (spell(part1, candidate_stack)) { + 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, candidate_stack) && (spell("-e", candidate_stack))) { + 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, candidate_stack); + part1.erase(part1.size() - 1); + if (nresult && spell(part2, candidate_stack) && + ((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, nullptr, nullptr)) { + 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, abbv = 0; + std::string cw; + cleanword(cw, word, &captype, &abbv); + std::string result; + + for (const auto& i : pl) { + cat_result(result, pSMgr->suggest_gen(pl2, 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 (auto& str : slst) { + mkinitcap(str); + } + } + + // temporary filtering of prefix related errors (eg. + // generate("undrinkable", "eats") --> "undrinkables" and "*undrinks") + auto it = slst.begin(); + while (it != slst.end()) { + std::vector candidate_stack; + if (!spell(*it, candidate_stack)) { + 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 std::string& in_par, std::string::size_type pos) { + std::string dest; + if (pos == std::string::npos) + return dest; + const char* par = in_par.c_str() + pos; + 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() : nullptr; + if (rl) { + return rl->conv(word, dest); + } + dest.assign(word); + return false; +} + +// return the beginning of the element (attr == NULL) or the attribute +std::string::size_type HunspellImpl::get_xml_pos(const std::string& s, std::string::size_type pos, const char* attr) { + if (pos == std::string::npos) + return std::string::npos; + + std::string::size_type endpos = s.find('>', pos); + if (attr == nullptr) + return endpos; + while (true) { + pos = s.find(attr, pos); + if (pos == std::string::npos || pos >= endpos) + return std::string::npos; + if (pos == 0 || s[pos - 1] == ' ' || s[pos - 1] == '\n') + break; + pos += strlen(attr); + } + return pos + strlen(attr); +} + +int HunspellImpl::check_xml_par(const std::string& q, std::string::size_type pos, + const char* attr, + const char* value) { + const std::string cw = get_xml_par(q, get_xml_pos(q, pos, attr)); + return cw == value ? 1 : 0; +} + +std::vector HunspellImpl::get_xml_list(const std::string& list, std::string::size_type pos, const char* tag) { + std::vector slst; + if (pos == std::string::npos) + return slst; + while (true) { + pos = list.find(tag, pos); + if (pos == std::string::npos) + break; + std::string cw = get_xml_par(list, pos + strlen(tag) - 1); + if (cw.empty()) { + break; + } + slst.push_back(std::move(cw)); + ++pos; + } + return slst; +} + +std::vector HunspellImpl::spellml(const std::string& in_word) { + std::vector slst; + + std::string::size_type qpos = in_word.find("', qpos); + if (q2pos == std::string::npos) + return slst; // bad XML input + + q2pos = in_word.find("', q2pos)); + if (!cw.empty()) + slst = analyze(cw); + if (slst.empty()) + return slst; + // convert the result to ana1ana2 format + std::string r; + r.append(""); + for (auto entry : slst) { + r.append(""); + + mystrrep(entry, "\t", " "); + mystrrep(entry, "&", "&"); + mystrrep(entry, "<", "<"); + r.append(entry); + + r.append(""); + } + r.append(""); + slst.clear(); + slst.push_back(std::move(r)); + return slst; + } else if (check_xml_par(in_word, qpos, "type=", "stem")) { + std::string cw = get_xml_par(in_word, in_word.find('>', q2pos)); + if (!cw.empty()) + return stem(cw); + } else if (check_xml_par(in_word, qpos, "type=", "generate")) { + std::string cw = get_xml_par(in_word, in_word.find('>', q2pos)); + if (cw.empty()) + return slst; + std::string::size_type q3pos = in_word.find("', q3pos)); + if (!cw2.empty()) { + return generate(cw, cw2); + } + } else { + q2pos = in_word.find(" slst2 = get_xml_list(in_word, in_word.find('>', q2pos), ""); + if (!slst2.empty()) { + slst = generate(cw, slst2); + uniqlist(slst); + return slst; + } + } + } + } else if (check_xml_par(in_word, qpos, "type=", "add")) { + std::string cw = get_xml_par(in_word, in_word.find('>', q2pos)); + if (cw.empty()) + return slst; + std::string::size_type q3pos = in_word.find("', q3pos)); + 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 = nullptr; + int len; + std::string w2; + const char* word; + const char* ignoredchars = pAMgr->get_ignore(); + if (ignoredchars != nullptr) { + 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(); + len = (int)w2.size(); + } else { + word = root_word.c_str(); + len = (int)root_word.size(); + } + + if (!len) + return slst; + + for (size_t i = 0; (i < m_HMgrs.size()) && !he; ++i) { + he = m_HMgrs[i]->lookup(word, len); + } + if (he) { + slst = pAMgr->get_suffix_words(he->astr, he->alen, root_word); + } + return slst; +} + +namespace { + // using malloc because this is for the c-api where the callers + // expect to be able to use free + char* stringdup(const std::string& s) { + size_t sl = s.size() + 1; + char* d = (char*)malloc(sl); + if (d) + memcpy(d, s.c_str(), sl); + return d; + } + + int munge_vector(char*** slst, const std::vector& items) { + if (items.empty()) { + *slst = nullptr; + return 0; + } else { + *slst = new char*[items.size()]; + for (size_t i = 0; i < items.size(); ++i) + (*slst)[i] = stringdup(items[i]); + } + return items.size(); + } +} + +int HunspellImpl::spell(const char* word, int* info, char** root) { + std::string sroot; + std::vector candidate_stack; + bool ret = spell(word, candidate_stack, info, root ? &sroot : nullptr); + if (root) { + if (sroot.empty()) { + *root = nullptr; + } else { + *root = stringdup(sroot); + } + } + 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]); + delete[] *slst; + *slst = nullptr; + } +} + +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; + morph.reserve(n); + for (int i = 0; i < n; ++i) morph.emplace_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; + morph.reserve(pln); + for (int i = 0; i < pln; ++i) morph.emplace_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) { + std::vector candidate_stack; + return m_Impl->spell(word, candidate_stack, info, root, + std::chrono::steady_clock::now()); +} + +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_flags(const std::string& word, const std::string& flags, const std::string& desc) { + return m_Impl->add_with_flags(word, flags, desc); +} + +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_suffix_suggest(Hunhandle* pHunspell, char*** slst, const char* root_word) { + return reinterpret_cast(pHunspell)->suffix_suggest(slst, root_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); +} + +int Hunspell_add_with_flags(Hunhandle* pHunspell, const char* word, const char* flags, const char* desc) { + return reinterpret_cast(pHunspell)->add_with_flags(word, flags, desc); +} + +/* 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); +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.h b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.h new file mode 100644 index 00000000..769b0929 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.h @@ -0,0 +1,178 @@ +/* ***** 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); + +/* 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.) + */ +LIBHUNSPELL_DLL_EXPORTED int Hunspell_suffix_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); + + +LIBHUNSPELL_DLL_EXPORTED int Hunspell_add_with_flags(Hunhandle* pHunspell, + const char* word, const char* flags, const char* desc); + +/* 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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.hxx new file mode 100644 index 00000000..6980bd95 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunspell.hxx @@ -0,0 +1,233 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 "" + +#ifndef MAXSUGGESTION +#define MAXSUGGESTION 15 +#endif + +#define MAXSHARPS 5 +#define MAXBREAKDEPTH 10 + +#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: + 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 = nullptr); + Hunspell(const Hunspell&) = delete; + Hunspell& operator=(const Hunspell&) = delete; + ~Hunspell(); + + /* load extra dictionaries (only dic files) */ + int add_dic(const char* dpath, const char* key = nullptr); + + /* 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 = nullptr, std::string* root = nullptr); + H_DEPRECATED int spell(const char* word, int* info = nullptr, char** root = nullptr); + + /* 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); + + int add_with_flags(const std::string& word, const std::string& flags, const std::string& desc = ""); + + /* 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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h new file mode 100644 index 00000000..ed0a502b --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h @@ -0,0 +1,18 @@ +#ifndef HUNSPELL_VISIBILITY_H_ +#define HUNSPELL_VISIBILITY_H_ + +#if defined(HUNSPELL_STATIC) +# define LIBHUNSPELL_DLL_EXPORTED +#elif defined(_WIN32) +# if defined(BUILDING_LIBHUNSPELL) +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllexport) +# else +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBHUNSPELL) && 1 +# define LIBHUNSPELL_DLL_EXPORTED __attribute__((__visibility__("default"))) +#else +# define LIBHUNSPELL_DLL_EXPORTED +#endif + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h.in b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h.in new file mode 100644 index 00000000..d8bacc67 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunvisapi.h.in @@ -0,0 +1,18 @@ +#ifndef HUNSPELL_VISIBILITY_H_ +#define HUNSPELL_VISIBILITY_H_ + +#if defined(HUNSPELL_STATIC) +# define LIBHUNSPELL_DLL_EXPORTED +#elif defined(_WIN32) +# if defined(BUILDING_LIBHUNSPELL) +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllexport) +# else +# define LIBHUNSPELL_DLL_EXPORTED __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBHUNSPELL) && @HAVE_VISIBILITY@ +# define LIBHUNSPELL_DLL_EXPORTED __attribute__((__visibility__("default"))) +#else +# define LIBHUNSPELL_DLL_EXPORTED +#endif + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.cxx new file mode 100644 index 00000000..45141a9f --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.cxx @@ -0,0 +1,269 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 std::string& par) { + fprintf(stderr, err, par.c_str()); + 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 = file; + if (getcode(key) == -1) + bufsiz = -1; + else + bufsiz = getbuf(); +} + +int Hunzip::getcode(const char* key) { + unsigned char c[2]; + int i, j, n, allocatedbit = BASEBITREC; + const char* enc = key; + + if (filename.empty()) + return -1; + + myopen(fin, filename.c_str(), 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 = nullptr; + + // 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 >> 3) + 1)) + return fail(MSG_FORMAT, filename); + if (key) + for (j = 0; j <= (l >> 3); j++) { + if (*(++enc) == '\0') + enc = key; + in[j] ^= *enc; + } + int p = 0; + for (j = 0; j < l; j++) { + int b = (in[(j >> 3)] & (1 << (7 - (j & 7)))) ? 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() = default; + +int Hunzip::getbuf() { + int p = 0; + int o = 0; + do { + if (inc == 0) { + fin.read(in, BUFSIZE); + inbits = int(fin.gcount() << 3); + } + for (; inc < inbits; inc++) { + int b = (in[inc >> 3] & (1 << (7 - (inc & 7)))) ? 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::is_open() { + return fin.is_open(); +} + +bool Hunzip::getline(std::string& dest) { + char linebuf[BUFSIZE]; + int l = 0, eol = 0, left = 0, right = 0; + if (bufsiz == -1) + return false; + // Stop one byte before BUFSIZE so the post-loop linebuf[l] = '\0' below + // (and the right-suffix path) always have room for the terminator without + // overflowing the stack buffer. + while (l < bufsiz && l < BUFSIZE - 1 && !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 = static_cast(out[outc]); + linebuf[l - 1] = '\n'; + eol = 1; + } + } + if (++outc == bufsiz) { + outc = 0; + bufsiz = fin.is_open() ? getbuf() : -1; + } + } + // append suffix from previous line + if (right) { + size_t prev_len = strlen(line); + size_t n = right + 1; + if (prev_len < n || l + n >= BUFSIZE) + return false; + strcpy(linebuf + l - 1, line + prev_len - n); + } else { + linebuf[l] = '\0'; + } + + // copy into line with left-offset from previous line preserved + if (left + strlen(linebuf) >= sizeof(line)) + return false; + strcpy(line + left, linebuf); + dest.assign(line); + return true; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.hxx new file mode 100644 index 00000000..319b4f77 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/hunzip.hxx @@ -0,0 +1,85 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 { + protected: + std::string 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 std::string& par); + + public: + Hunzip(const char* filename, const char* key = nullptr); + Hunzip(const Hunzip&) = delete; + Hunzip& operator=(const Hunzip&) = delete; + ~Hunzip(); + bool is_open(); + bool getline(std::string& dest); +}; + +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/langnum.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/langnum.hxx new file mode 100644 index 00000000..39e63efd --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/langnum.hxx @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.cxx new file mode 100644 index 00000000..fa548371 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.cxx @@ -0,0 +1,260 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + 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, see + . + + Changelog: + + 2000-01-05 Bjoern Jacke + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth + Porting from Aspell to Hunspell using C-like structs +*/ + +#include +#include +#include +#include + +#include "csutil.hxx" +#include "phonet.hxx" + +void init_phonet_hash(phonetable& parms) { + memset(parms.hash, 0xff, HASHSIZE * sizeof(int)); + + 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, k0, n0, p0 = -333; + char c; + using uchar = unsigned char; + + size_t len = inword.size(); + if (len > MAXPHONETUTF8LEN) + return {}; + 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) == nullptr) { + k++; + s++; + } + if (*s == '(') { + /** check letters in "(..)" **/ + if (myisalpha(word[i + k]) // ...could be implied? + && strchr(s + 1, word[i + k]) != nullptr) { + k++; + while (*s && *s != ')') + s++; + if (*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) == nullptr) { + k0++; + s++; + } + if (*s == '(') { + /** check letters **/ + if (myisalpha(word[i + k0]) && strchr(s + 1, word[i + k0]) != nullptr) { + 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, '<') != nullptr) ? 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, "^^") != nullptr) { + 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" **/ diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.hxx new file mode 100644 index 00000000..2d58b3ba --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/phonet.hxx @@ -0,0 +1,50 @@ +/* phonetic.c - generic replacement aglogithms for phonetic transformation + Copyright (C) 2000 Bjoern Jacke + + 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, see + . + + Changelog: + + 2000-01-05 Bjoern Jacke + Initial Release insprired by the article about phonetic + transformations out of c't 25/1999 + + 2007-07-26 Bjoern Jacke + Released under MPL/GPL/LGPL tri-license for Hunspell + + 2007-08-23 Laszlo Nemeth + Porting from Aspell to Hunspell using C-like structs +*/ + +#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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.cxx new file mode 100644 index 00000000..8325bd8f --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.cxx @@ -0,0 +1,205 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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.reserve(std::min(n, 16384)); +} + +RepList::~RepList() { + for (auto& i : dat) { + delete i; + } +} + +int RepList::find(const char* word) { + int p1 = 0; + int p2 = dat.size() - 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 size_t wordlen, int ind, bool atstart) { + int type = atstart ? 1 : 0; + if (wordlen == 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 (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; + r->pattern = std::move(pat1); + r->outstrings[type] = pat2; + mystrrep(r->outstrings[type], "_", " "); + dat.push_back(r); + // sort to the right place in the list + size_t i; + for (i = dat.size() - 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(); + + const 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); + + bool empty = n < 0; + if (empty) { + dest.push_back(word[i]); + continue; + } + + std::string l = replace(wordlen - i, n, i == 0); + if (l.empty()) { + dest.push_back(word[i]); + continue; + } + + dest.append(l); + if (!dat[n]->pattern.empty()) { + i += dat[n]->pattern.size() - 1; + } + change = true; + } + + return change; +} + +bool RepList::check_against_breaktable(const std::vector& breaktable) const { + for (const auto i : dat) { + for (auto& outstring : i->outstrings) { + for (const auto& str : breaktable) { + if (outstring.find(str) != std::string::npos) { + return false; + } + } + } + } + + return true; +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.hxx new file mode 100644 index 00000000..e3462b9f --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/replist.hxx @@ -0,0 +1,96 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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: + std::vector dat; + public: + explicit RepList(int n); + RepList(const RepList&) = delete; + RepList& operator=(const RepList&) = delete; + ~RepList(); + + bool check_against_breaktable(const std::vector& breaktable) const; + + int add(const std::string& pat1, const std::string& pat2); + int find(const char* word); + std::string replace(const size_t wordlen, int n, bool atstart); + bool conv(const std::string& word, std::string& dest); +}; +#endif diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.cxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.cxx new file mode 100644 index 00000000..f7cb1da3 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.cxx @@ -0,0 +1,2323 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 "suggestmgr.hxx" +#include "hunspell.hxx" +#include "htypes.hxx" +#include "csutil.hxx" + +const w_char W_VLINE = {'\0', '|'}; + +#define MAX_CHAR_DISTANCE 4 +#define MAXWORDUTF8LEN (MAXWORDLEN * 3) + +SuggestMgr::SuggestMgr(const std::string& tryme, unsigned int maxn, AffixMgr* aptr) { + // register affix manager and check in string of chars to + // try when building candidate suggestions + pAMgr = aptr; + + csconv = nullptr; + + ckeyl = 0; + + ctryl = 0; + + 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.empty()) { + if (utf8) { + int len = u8_u16(ckey_utf, ckey); + if (len != -1) { + ckeyl = len; + } + } else { + ckeyl = ckey.size(); + } + } + + ctry = tryme; + if (!ctry.empty()) { + if (utf8) { + int len = u8_u16(ctry_utf, ctry); + if (len != -1) { + ctryl = len; + } + } else { + ctryl = ctry.size(); + } + } + + // language with possible dash usage + // (latin letters or dash in TRY characters) + lang_with_dash_usage = ctry.find('-') != std::string::npos || + ctry.find('a') != std::string::npos; +} + +SuggestMgr::~SuggestMgr() { + pAMgr = nullptr; + ckeyl = 0; + ctryl = 0; + maxSug = 0; +#ifdef MOZILLA_CLIENT + delete[] csconv; +#endif +} + +void SuggestMgr::testsug(std::vector& wlst, + const std::string& candidate, + int cpdsuggest, + int* timer, + std::chrono::steady_clock::time_point* timelimit, + int& info) { + if (wlst.size() == maxSug) + return; + + const int cwrd = std::find(wlst.begin(), wlst.end(), candidate) != wlst.end() ? 0 : 1; + + if (cwrd) { + if (int result = checkword(candidate, cpdsuggest, timer, timelimit)) { + // compound word in the dictionary + if (cpdsuggest == 0 && result >= 2) + info |= SPELL_COMPOUND; + 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) + * return value: true, if there is a good suggestion + * (REP, ph: or a dictionary word pair) + */ +bool SuggestMgr::suggest(std::vector& slst, + const std::string& w, + int* onlycompoundsug, bool test_simplesug) { + int nocompoundtwowords = 0; // no second or third loops, see below + std::vector word_utf; + size_t nsugorig = slst.size(), oldSug = 0; + std::string w2; + bool good_suggestion = false; + + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + } + + const std::string& word = complexprefixes ? w2 : w; + + suggest_start = std::chrono::steady_clock::now(); + + if (utf8) { + int wl = u8_u16(word_utf, word); + if (wl == -1) { + return false; + } + } + + // three loops: + // - the first without compounding, + // - the second one with 2-word compounding, + // - the third one with 3-or-more-word compounding + // Run second and third loops only if: + // - no ~good suggestion in the first loop + // - not for testing compound words with 3 or more words (test_simplesug == false) + int info = 0; + for (int cpdsuggest = 0; cpdsuggest < 3 && nocompoundtwowords == 0; cpdsuggest++) { + + // limit compound suggestion + if (cpdsuggest > 0) + oldSug = slst.size(); + + // suggestions for an uppercase word (html -> HTML) + if (slst.size() < maxSug) { + size_t i = slst.size(); + if (utf8) + capchars_utf(slst, word_utf, cpdsuggest, info); + else + capchars(slst, word, cpdsuggest, info); + if (slst.size() > i) + good_suggestion = true; + } + + // perhaps we made a typical fault of spelling + if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { + size_t i = slst.size(); + replchars(slst, word, cpdsuggest, info); + if (slst.size() > i) { + good_suggestion = true; + if (info & SPELL_BEST_SUG) + return true; + } + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // perhaps we made chose the wrong char from a related set + if ((slst.size() < maxSug) && + (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { + mapchars(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // only suggest compound words when no other ~good 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, cpdsuggest, info); + else + swapchar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // 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, cpdsuggest, info); + else + longswapchar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // 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, cpdsuggest, info); + else + badcharkey(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // 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, cpdsuggest, info); + else + extrachar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // did we forgot a char + if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { + if (utf8) + forgotchar_utf(slst, word_utf, cpdsuggest, info); + else + forgotchar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // did we move a char + if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { + if (utf8) + movechar_utf(slst, word_utf, cpdsuggest, info); + else + movechar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // 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, cpdsuggest, info); + else + badchar(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // did we double two characters + if ((slst.size() < maxSug) && (!cpdsuggest || (slst.size() < oldSug + maxcpdsugs))) { + if (utf8) + doubletwochars_utf(slst, word_utf, cpdsuggest, info); + else + doubletwochars(slst, word, cpdsuggest, info); + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + if (test_simplesug && slst.size()) + return true; + + // perhaps we forgot to hit space and two words ran together + // (dictionary word pairs have top priority here, so + // we always suggest them, in despite of nosplitsugs, and + // drop compound word and other suggestions) + if (!cpdsuggest || (!nosplitsugs && slst.size() < oldSug + maxcpdsugs)) { + good_suggestion = twowords(slst, word, cpdsuggest, good_suggestion, info); + + if (info & SPELL_BEST_SUG) + return true; + } + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return good_suggestion; + + // testing returns after the first loop + if (test_simplesug) + return slst.size() > 0; + + // don't need third loop, if the second loop was successful or + // the first loop found a dictionary-based compound word + // (we don't need more, likely worse and false 3-or-more-word compound words) + if (cpdsuggest == 1 && (slst.size() > oldSug || (info & SPELL_COMPOUND))) + nocompoundtwowords = 1; + + } // repeating ``for'' statement compounding support + + if (!nocompoundtwowords && (!slst.empty()) && onlycompoundsug) + *onlycompoundsug = 1; + + return good_suggestion; +} + +// suggestions for an uppercase word (html -> HTML) +void SuggestMgr::capchars_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + std::vector candidate_utf(word); + mkallcap_utf(candidate_utf, langnum); + std::string candidate; + u16_u8(candidate, candidate_utf); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); +} + +// suggestions for an uppercase word (html -> HTML) +void SuggestMgr::capchars(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + std::string candidate(word); + mkallcap(candidate, csconv); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); +} + +// suggestions for when chose the wrong char out of a related set +int SuggestMgr::mapchars(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + std::string candidate; + std::chrono::steady_clock::time_point timelimit; + int timer; + + if (word.size() < 2 || !pAMgr) + return wlst.size(); + + const std::vector& maptable = pAMgr->get_maptable(); + if (maptable.empty()) + return wlst.size(); + + timelimit = std::chrono::steady_clock::now(); + timer = MINTIMER; + return map_related(word, candidate, 0, wlst, cpdsuggest, + maptable, &timer, &timelimit, 0, info); +} + +int SuggestMgr::map_related(const std::string& word, + std::string& candidate, + size_t wn, + std::vector& wlst, + int cpdsuggest, + const std::vector& maptable, + int* timer, + std::chrono::steady_clock::time_point* timelimit, + int depth, int& info) { + if (word.size() == wn) { + if (candidate == word) + return wlst.size(); + const int cwrd = std::find(wlst.begin(), wlst.end(), candidate) != wlst.end() ? 0 : 1; + if ((cwrd) && checkword(candidate, cpdsuggest, timer, timelimit)) { + if (wlst.size() < maxSug) { + wlst.push_back(candidate); + } + } + return wlst.size(); + } + + if (depth > 0x3F00) { + *timer = 0; + 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 (len && word.compare(wn, len, maptable[j][k]) == 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, depth + 1, info); + if (!(*timer)) + return wlst.size(); + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) { + *timer = 0; + return wlst.size(); + } + } + } + } + } + if (!in_map) { + candidate.push_back(word[wn]); + map_related(word, candidate, wn + 1, wlst, cpdsuggest, + maptable, timer, timelimit, depth + 1, info); + } + 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 std::string& word, + int cpdsuggest, int& info) { + std::string candidate; + int wl = word.size(); + if (wl < 2 || !pAMgr) + return wlst.size(); + const std::vector& reptable = pAMgr->get_reptable(); + auto replchars_start = std::chrono::steady_clock::now(); + for (const auto& entry : reptable) { + size_t r = 0; + // search every occurence of the pattern in the word + while ((r = word.find(entry.pattern, r)) != std::string::npos) { + if (std::chrono::steady_clock::now() - replchars_start > TIMELIMIT_SUGGESTION_MS) + return wlst.size(); + int type = (r == 0) ? 1 : 0; + if (r + entry.pattern.size() == word.size()) + type += 2; + while (type && entry.outstrings[type].empty()) + type = (type == 2 && r != 0) ? 0 : type - 1; + const std::string&out = entry.outstrings[type]; + if (out.empty()) { + ++r; + continue; + } + candidate.assign(word, 0, r); + candidate.append(entry.outstrings[type]); + candidate.append(word, r + entry.pattern.size(), std::string::npos); + size_t sp = candidate.find(' '); + size_t oldns = wlst.size(); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + if (oldns < wlst.size()) { + // REP suggestions are the best, don't search other type of suggestions + info |= SPELL_BEST_SUG; + } + + // check REP suggestions with space + 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, nullptr, nullptr)) { + oldns = wlst.size(); + std::string post_chunk = candidate.substr(sp + 1); + testsug(wlst, post_chunk, cpdsuggest, nullptr, nullptr, info); + 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 +// (for example vacation -> vacacation) +// The recognized pattern with regex back-references: +// "(.)(.)\1\2\1" or "..(.)(.)\1\2" + +int SuggestMgr::doubletwochars(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + size_t wl = word.size(); + if (wl < 5 || !pAMgr) + return wlst.size(); + + int state = 0; + for (size_t i = 2; i < wl; ++i) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3 || (state == 2 && i >= 4)) { + auto word_iter = word.begin(); + std::string candidate(word_iter, word_iter + i - 1); + candidate.insert(candidate.end(), word_iter + i + 1, word.end()); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + state = 0; + } + } else { + state = 0; + } + } + return wlst.size(); +} + +// perhaps we doubled two characters +// (for example vacation -> vacacation) +// The recognized pattern with regex back-references: +// "(.)(.)\1\2\1" or "..(.)(.)\1\2" + +int SuggestMgr::doubletwochars_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + size_t wl = word.size(); + int state = 0; + if (wl < 5 || !pAMgr) + return wlst.size(); + for (size_t i = 2; i < wl; ++i) { + if (word[i] == word[i - 2]) { + state++; + if (state == 3 || (state == 2 && i >= 4)) { + auto word_iter = word.begin(); + std::vector candidate_utf(word_iter, word_iter + i - 1); + candidate_utf.insert(candidate_utf.end(), word_iter + i + 1, word.end()); + std::string candidate; + u16_u8(candidate, candidate_utf); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + 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 std::string& word, + int cpdsuggest, int& info) { + 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, wl = candidate.size(); i < wl; ++i) { + char tmpc = candidate[i]; + // check with uppercase letters + candidate[i] = csconv[((unsigned char)tmpc)].cupper; + if (tmpc != candidate[i]) { + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + candidate[i] = tmpc; + } + // check neighbor characters in keyboard string + if (ckey.empty()) + continue; + size_t loc = 0; + while ((loc < ckeyl) && ckey[loc] != tmpc) + ++loc; + while (loc < ckeyl) { + if ((loc > 0) && ckey[loc - 1] != '|') { + candidate[i] = ckey[loc - 1]; + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + } + if (((loc + 1) < ckeyl) && (ckey[loc + 1] != '|')) { + candidate[i] = ckey[loc + 1]; + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + } + do { + loc++; + } while ((loc < ckeyl) && ckey[loc] != 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 std::vector& word, + int cpdsuggest, int& info) { + std::string candidate; + std::vector candidate_utf(word); + // 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 i = 0, wl = word.size(); 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, nullptr, nullptr, info); + candidate_utf[i] = tmpc; + } + // check neighbor characters in keyboard string + if (ckey_utf.empty()) + 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, nullptr, nullptr, info); + } + 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, nullptr, nullptr, info); + } + 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 std::string& word, + int cpdsuggest, int& info) { + std::string candidate(word); + std::chrono::steady_clock::time_point timelimit = std::chrono::steady_clock::now(); + 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 (auto 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, info); + 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 std::vector& word, + int cpdsuggest, int& info) { + std::vector candidate_utf(word); + std::string candidate; + std::chrono::steady_clock::time_point timelimit = std::chrono::steady_clock::now(); + 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 (auto aI = candidate_utf.rbegin(), aEnd = candidate_utf.rend(); aI != aEnd; ++aI) { + w_char tmpc = *aI; + if (tmpc == ctry_utf[j]) + continue; + *aI = ctry_utf[j]; + u16_u8(candidate, candidate_utf); + testsug(wlst, candidate, cpdsuggest, &timer, &timelimit, info); + if (!timer) + return wlst.size(); + *aI = tmpc; + } + } + return wlst.size(); +} + +// error is word has an extra letter it does not need +int SuggestMgr::extrachar_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + std::vector candidate_utf(word); + 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, nullptr, nullptr, info); + 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 std::string& word, + int cpdsuggest, int& info) { + 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, nullptr, nullptr, info); + candidate.insert(candidate.begin() + index, tmpc); + } + return wlst.size(); +} + +// error is missing a letter it needs +int SuggestMgr::forgotchar(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + std::string candidate(word); + std::chrono::steady_clock::time_point timelimit = std::chrono::steady_clock::now(); + 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, info); + 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 std::vector& word, + int cpdsuggest, int& info) { + std::vector candidate_utf(word); + std::chrono::steady_clock::time_point timelimit = std::chrono::steady_clock::now(); + 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, info); + if (!timer) + return wlst.size(); + candidate_utf.erase(candidate_utf.begin() + index); + } + } + return wlst.size(); +} + +/* error is should have been two words + * return value is true, if there is a dictionary word pair, + * or there was already a good suggestion before calling + * this function. + */ +bool SuggestMgr::twowords(std::vector& wlst, + const std::string& word, + int cpdsuggest, + bool good, int& info) { + int c2, forbidden = 0, cwrd, wl = word.size(); + if (wl < 3) + return false; + + if (langnum == LANG_hu) + forbidden = check_forbidden(word); + + char* candidate = new char[wl + 2]; + memcpy(candidate + 1, word.data(), wl); + candidate[wl + 1] = 0; + + // 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 + + // Suggest only word pairs, if they are listed in the dictionary. + // For example, adding "a lot" to the English dic file will + // result only "alot" -> "a lot" suggestion instead of + // "alto, slot, alt, lot, allot, aloft, aloe, clot, plot, blot, a lot". + // Note: using "ph:alot" keeps the other suggestions: + // a lot ph:alot + // alot -> a lot, alto, slot... + *p = ' '; + if (!cpdsuggest && checkword(candidate, cpdsuggest, nullptr, nullptr)) { + // best solution + info |= SPELL_BEST_SUG; + + // remove not word pair suggestions + if (!good) { + good = true; + wlst.clear(); + } + + wlst.insert(wlst.begin(), candidate); + } + + // word pairs with dash? + if (lang_with_dash_usage) { + *p = '-'; + + if (!cpdsuggest && checkword(candidate, cpdsuggest, nullptr, nullptr)) { + // best solution + info |= SPELL_BEST_SUG; + + // remove not word pair suggestions + if (!good) { + good = true; + wlst.clear(); + } + wlst.insert(wlst.begin(), candidate); + } + } + + if (wlst.size() < maxSug && !nosplitsugs && !good) { + *p = '\0'; + int c1 = checkword(candidate, cpdsuggest, nullptr, nullptr); + if (c1) { + c2 = checkword((p + 1), cpdsuggest, nullptr, nullptr); + if (c2) { + // spec. Hungarian code (TODO 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 = '-'; + else + *p = ' '; + + cwrd = std::find(wlst.begin(), wlst.end(), candidate) != wlst.end() ? 0 : 1; + + if (cwrd && (wlst.size() < maxSug)) + wlst.emplace_back(candidate); + + // add two word suggestion with dash, depending on the language + // Note that cwrd doesn't modified for REP twoword sugg. + if ( !nosplitsugs && lang_with_dash_usage && + mystrlen(p + 1) > 1 && mystrlen(candidate) - mystrlen(p) > 1) { + *p = '-'; + for (auto& k : wlst) { + if (k == candidate) { + cwrd = 0; + break; + } + } + + if ((wlst.size() < maxSug) && cwrd) + wlst.emplace_back(candidate); + } + } + } + } + } + delete[] candidate; + return good; +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + if (word.size() < 2) + return wlst.size(); + + std::string candidate(word); + + // 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, nullptr, nullptr, info); + 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, nullptr, nullptr, info); + if (candidate.size() == 5) { + candidate[0] = word[0]; + candidate[1] = word[2]; + candidate[2] = word[1]; + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + } + } + + return wlst.size(); +} + +// error is adjacent letter were swapped +int SuggestMgr::swapchar_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + if (word.size() < 2) + return wlst.size(); + + std::vector candidate_utf(word); + + 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, nullptr, nullptr, info); + 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, nullptr, nullptr, info); + 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, nullptr, nullptr, info); + } + } + return wlst.size(); +} + +// error is not adjacent letter were swapped +int SuggestMgr::longswapchar(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + std::string candidate(word); + // try swapping not adjacent chars one by one + for (auto p = candidate.begin(); p < candidate.end(); ++p) { + for (auto q = candidate.begin(); q < candidate.end(); ++q) { + const auto distance = std::abs(std::distance(q, p)); + if (distance > 1 && distance <= MAX_CHAR_DISTANCE && *p != *q) { + std::swap(*p, *q); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + std::swap(*p, *q); + } + } + } + return wlst.size(); +} + +// error is adjacent letter were swapped +int SuggestMgr::longswapchar_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + std::vector candidate_utf(word); + // try swapping not adjacent chars + for (auto p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (auto q = candidate_utf.begin(); q < candidate_utf.end(); ++q) { + const auto distance = std::abs(std::distance(q, p)); + if (distance > 1 && distance <= MAX_CHAR_DISTANCE && *p != *q) { + std::swap(*p, *q); + std::string candidate; + u16_u8(candidate, candidate_utf); + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + std::swap(*p, *q); + } + } + } + return wlst.size(); +} + +// error is a letter was moved +int SuggestMgr::movechar(std::vector& wlst, + const std::string& word, + int cpdsuggest, int& info) { + if (word.size() < 2) + return wlst.size(); + + std::string candidate(word); + + // try moving a char + for (auto p = candidate.begin(); p < candidate.end(); ++p) { + for (auto q = p + 1; q < candidate.end() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + } + const auto word_iter = word.begin(); + std::copy_n(word_iter, candidate.size(), candidate.begin()); + } + + for (auto p = candidate.rbegin(), pEnd = candidate.rend() - 1; p != pEnd; ++p) { + for (auto q = p + 1, qEnd = candidate.rend(); q != qEnd && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++q) { + std::swap(*q, *(q - 1)); + if (std::distance(p, q) < 2) + continue; // omit swap char + testsug(wlst, candidate, cpdsuggest, nullptr, nullptr, info); + } + const auto word_iter = word.begin(); + std::copy_n(word_iter, candidate.size(), candidate.begin()); + } + + return wlst.size(); +} + +// error is a letter was moved +int SuggestMgr::movechar_utf(std::vector& wlst, + const std::vector& word, + int cpdsuggest, int& info) { + if (word.size() < 2) + return wlst.size(); + + std::vector candidate_utf(word); + + // try moving a char + for (auto p = candidate_utf.begin(); p < candidate_utf.end(); ++p) { + for (auto q = p + 1; q < candidate_utf.end() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++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, nullptr, nullptr, info); + } + const auto word_iter = word.begin(); + std::copy_n(word_iter, candidate_utf.size(), candidate_utf.begin()); + } + + for (auto p = candidate_utf.rbegin(); p < candidate_utf.rend(); ++p) { + for (auto q = p + 1; q < candidate_utf.rend() && std::distance(p, q) <= MAX_CHAR_DISTANCE; ++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, nullptr, nullptr, info); + } + const auto word_iter = word.begin(); + std::copy_n(word_iter, candidate_utf.size(), candidate_utf.begin()); + } + + return wlst.size(); +} + +namespace +{ + class ngsuggest_guard + { + bool m_nonbmp; + const cs_info* m_origconv; + int* m_utf8; + const cs_info** m_csconv; + + public: + + ngsuggest_guard(bool nonbmp, const cs_info* origconv, int* utf8, const cs_info** csconv) + : m_nonbmp(nonbmp) + , m_origconv(origconv) + , m_utf8(utf8) + , m_csconv(csconv) + { + } + + ~ngsuggest_guard() + { + if (m_nonbmp) { + *m_csconv = m_origconv; + *m_utf8 = 1; + } + } + }; +} + +// generate a set of suggestions for very poorly spelled words +void SuggestMgr::ngsuggest(std::vector& wlst, + const char* w, + const std::vector>& rHMgr, + int captype) { + int lval, sc, lp, lpphon, 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] = nullptr; + scores[i] = -100 * i; + rootsphon[i] = nullptr; + scoresphon[i] = -100 * i; + } + bool has_roots = false; + bool has_rootsphon = false; + lp = MAX_ROOTS - 1; + lpphon = MAX_ROOTS - 1; + int low = NGRAM_LOWERING; + + std::string w2; + const char* word = w; + + int nc; + // word reversing wrapper for complex prefixes + if (complexprefixes) { + w2.assign(w); + if (utf8) + reverseword_utf(w2); + else + reverseword(w2); + word = w2.c_str(); + nc = (int)w2.size(); + } else { + nc = (int)strlen(word); + } + + std::vector u8; + int n = (utf8) ? u8_u16(u8, word) : nc; + + // set character based ngram suggestion for words with non-BMP Unicode + // characters + const struct cs_info* origconv = csconv; + if (n == -1) { + utf8 = 0; // XXX not state-free + if (!csconv) + csconv = get_current_cs("iso88591"); // XXX not state-free + n = nc; + nonbmp = 1; + low = 0; + } + ngsuggest_guard restore_state(nonbmp, origconv, &utf8, &csconv); + int max_word_len = (utf8) ? MAXWORDUTF8LEN : MAXWORDLEN; + // ofz#59067 a replist entry can generate a very long word, abandon + // ngram if that odd-edge case arises + if (n > max_word_len * 4) + return; + + struct hentry* hp = nullptr; + int col = -1; + phonetable* ph = (pAMgr) ? pAMgr->get_phonetable() : nullptr; + 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 (const auto& i : rHMgr) { + while (nullptr != (hp = i->walk_hashtable(col, hp))) { + // skip exceptions + if ( + // skip it, if the word length different by 5 or + // more characters (to avoid strange suggestions) + // (except Unicode characters over BMP) + (((abs(n - hp->clen) > 4) && !nonbmp)) || + // don't suggest capitalized dictionary words for + // lower case misspellings in ngram suggestions, except + // - PHONE usage, or + // - in the case of German, where not only proper + // nouns are capitalized, or + // - the capitalized word has special pronunciation + ((captype == NOCAP) && (hp->var & H_OPT_INITCAP) && + !ph && (langnum != LANG_de) && !(hp->var & H_OPT_PHON)) || + // or it has one of the following special flags + ((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 pronunciation + 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; + has_roots = true; + 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); + has_rootsphon = true; + lval = scphon; + for (int j = 0; j < MAX_ROOTS; j++) + if (scoresphon[j] < lval) { + lpphon = j; + lval = scoresphon[j]; + } + } + } + } + + if (!has_roots && !has_rootsphon) { + // with no roots there will be no guesses and no point running + // ngram + return; + } + + // 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] = nullptr; + guessorig[i] = nullptr; + gscore[i] = -100 * i; + } + + lp = MAX_GUESS - 1; + + std::vector glst(MAX_WORDS); + + for (auto& root : roots) { + if (root) { + struct hentry* rp = root; + + f.clear(); + const char* field = nullptr; + if ((rp->var & H_OPT_PHON) && copy_field(f, HENTRY_DATA(rp), MORPH_PHON)) + field = f.c_str(); + int nw = pAMgr->expand_rootword( + glst.data(), 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]) { + delete[] guess[lp]; + if (guessorig[lp]) { + delete[] guessorig[lp]; + guessorig[lp] = nullptr; + } + } + 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 { + delete[] glst[k].word; + delete[] glst[k].orig; + } + } else { + delete[] glst[k].word; + delete[] glst[k].orig; + } + } + } + } + glst.clear(); + + // 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], nullptr, &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], nullptr, &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())) { + delete[] guess[i]; + delete[] guessorig[i]; + continue; + } + } + for (auto& j : wlst) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if ((!guessorig[i] && strstr(guess[i], j.c_str())) || (guessorig[i] && strstr(guessorig[i], j.c_str())) || + // check forbidden words + !checkword(guess[i], 0, nullptr, nullptr)) { + unique = 0; + break; + } + } + if (unique) { + if (guessorig[i]) { + wlst.emplace_back(guessorig[i]); + } else { + wlst.emplace_back(guess[i]); + } + } + delete[] guess[i]; + delete[] guessorig[i]; + } else { + delete[] guess[i]; + delete[] guessorig[i]; + } + } + } + + oldns = wlst.size(); + if (ph) + for (auto& i : rootsphon) { + if (i) { + if ((wlst.size() < oldns + MAXPHONSUGS) && (wlst.size() < maxSug)) { + int unique = 1; + for (auto& j : wlst) { + // don't suggest previous suggestions or a previous suggestion with + // prefixes or affixes + if (strstr(i, j.c_str()) || + // check forbidden words + !checkword(i, 0, nullptr, nullptr)) { + unique = 0; + break; + } + } + if (unique) { + wlst.emplace_back(i); + } + } + } + } +} + +// 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, + std::chrono::steady_clock::time_point* timelimit) { + // check overall suggestion time limit + if (std::chrono::steady_clock::now() - suggest_start > TIMELIMIT_SUGGESTION_MS) + return 0; + + // check time limit + if (timer) { + (*timer)--; + if (!(*timer) && timelimit) { + if (std::chrono::steady_clock::now() - *timelimit > TIMELIMIT_MS) + return 0; + *timer = MAXPLUSTIMER; + } + } + + if (pAMgr) { + struct hentry* rv = nullptr; + int nosuffix = 0; + + if (cpdsuggest >= 1) { + if (pAMgr->get_compound()) { + struct hentry* rv2 = nullptr; + struct hentry* rwords[100]; // buffer for COMPOUND pattern checking + int info = (cpdsuggest == 1) ? SPELL_COMPOUND_2 : 0; + rv = pAMgr->compound_check(word, 0, 0, 100, 0, nullptr, (hentry**)&rwords, 0, 1, &info); // EXT + // TODO filter 3-word or more compound words, as in spell() + // (it's too slow to call suggest() here for all possible compound words) + if (rv && + (!(rv2 = pAMgr->lookup(word.c_str(), word.size())) || !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(), word.size()); + + if (rv) { + if ((rv->astr) && + (TESTAFF(rv->astr, pAMgr->get_forbiddenword(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_nosuggest(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_substandard(), 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, 0, word.size(), + 0); // only prefix, and prefix + suffix XXX + + if (rv) { + nosuffix = 1; + } else { + rv = pAMgr->suffix_check(word, 0, word.size(), 0, nullptr, FLAG_NULL, FLAG_NULL, IN_CPD_NOT); // only suffix + } + + if (!rv && pAMgr->have_contclass()) { + rv = pAMgr->suffix_check_twosfx(word, 0, word.size(), 0, nullptr, FLAG_NULL); + if (!rv) + rv = pAMgr->prefix_check_twosfx(word, 0, word.size(), 0, 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 std::string& word) { + if (pAMgr) { + struct hentry* rv = pAMgr->lookup(word.c_str(), word.size()); + if (rv && rv->astr && + (TESTAFF(rv->astr, pAMgr->get_needaffix(), rv->alen) || + TESTAFF(rv->astr, pAMgr->get_onlyincompound(), rv->alen))) + rv = nullptr; + size_t len = word.size(); + if (!(pAMgr->prefix_check(word, 0, len, 1))) + rv = pAMgr->suffix_check(word, 0, len, 0, nullptr, 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 = nullptr; + + if (!pAMgr) + return {}; + + 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(), w.size()); + + 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.push_back(MSEP_FLD); + result.append(MORPH_STEM); + result.append(w); + } + if (HENTRY_DATA(rv)) { + result.push_back(MSEP_FLD); + result.append(HENTRY_DATA2(rv)); + } + result.push_back(MSEP_REC); + } + rv = rv->next_homonym; + } + + std::string st = pAMgr->affix_check_morph(w, 0, 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, 0, 0, 100, 0, nullptr, (hentry**)&rwords, 0, result, nullptr); + } + + 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.push_back(MSEP_REC); + } + } + + // check all allomorphs + char* p = nullptr; + 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(), allomorph.size()); + 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.push_back(MSEP_REC); + } + } + } + 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 {}; + + const char* pattern = in_pattern.c_str(); + std::string result2; + std::string newpattern; + struct hentry* rv = nullptr; + + // search affixed forms with and without derivational suffixes + while (true) { + for (const auto& k : desc) { + std::string result; + + // add compound word parts (except the last one) + const char* s = 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 (auto& i : pl) { + // remove inflectional and terminal suffixes + size_t is = i.find(MORPH_INFL_SFX); + if (is != std::string::npos) + i.resize(is); + size_t ts = i.find(MORPH_TERM_SFX); + while (ts != std::string::npos) { + i[ts] = '_'; + ts = 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(), tok.size()); + while (rv) { + std::string newpat(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 (auto& j : gen) { + result2.push_back(MSEP_REC); + result2.append(result); + if (i.find(MORPH_SURF_PFX) != std::string::npos) { + std::string field; + copy_field(field, i, MORPH_SURF_PFX); + result2.append(field); + } + result2.append(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, ns, 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++) { + if (su1[i + k] != su2[l + k]) + break; + } + if (k == j) { + ns++; + break; + } + } + if (k != j && opt & NGRAM_WEIGHTED) { + ns--; + 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, ns, l1, 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--; + 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(), l2 = su2.size(); + // decapitalize dictionary word + if (complexprefixes) { + if (l1 && l2 && su1[l1 - 1] == su2[l2 - 1]) + return 1; + } else { + unsigned short idx = su2.empty() ? 0 : (unsigned short)(su2[0]), + otheridx = su1.empty() ? 0 : (unsigned short)(su1[0]); + if (otheridx != idx && (otheridx != unicodetolower(idx, langnum))) + return 0; + int i; + for (i = 1; (i < l1) && (i < l2) && (su1[i] == su2[i]); + 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), l2 = strlen(s2); + if (l1 && l1 <= l2 && s1[l1 - 1] == s2[l2 - 1]) + return 1; + } else if (csconv) { + const char* olds = s1; + // decapitalise dictionary word + if ((*s1 != *s2) && (((unsigned char)*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, diff = 0, diffpos[2]; + *is_swap = 0; + if (utf8) { + std::vector su1; + std::vector su2; + int l1 = u8_u16(su1, s1), 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++; + } +} + +// longest common subsequence +char* SuggestMgr::lcs(const char* s, + const char* s2, + int* l1, + int* l2) { + int n, m, i, j; + std::vector su; + std::vector su2; + if (utf8) { + m = u8_u16(su, s); + n = u8_u16(su2, s2); + } else { + m = strlen(s); + n = strlen(s2); + } + if (m <= 0 || n <= 0) { + *l1 = 0; + *l2 = 0; + return nullptr; + } + char* c = new char[(m + 1) * (n + 1)](); + char* b = new char[(m + 1) * (n + 1)](); + 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; + } + } + } + delete[] c; + *l1 = m; + *l2 = n; + return b; +} + +int SuggestMgr::lcslen(const char* s, const char* s2) { + int m, n, len = 0; + char* result = lcs(s, s2, &m, &n); + if (!result) + return 0; + int 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--; + } + delete[] result; + return len; +} + +int SuggestMgr::lcslen(const std::string& s, const std::string& s2) { + return lcslen(s.c_str(), s2.c_str()); +} diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.hxx new file mode 100644 index 00000000..ecbc8da4 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/suggestmgr.hxx @@ -0,0 +1,191 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 + +#define NGRAM_LONGER_WORSE (1 << 0) +#define NGRAM_ANY_MISMATCH (1 << 1) +#define NGRAM_LOWERING (1 << 2) +#define NGRAM_WEIGHTED (1 << 3) + +#include + +#include "atypes.hxx" +#include "affixmgr.hxx" +#include "hashmgr.hxx" +#include "langnum.hxx" + +enum { LCS_UP, LCS_LEFT, LCS_UPLEFT }; + +class SuggestMgr { + private: + std::string ckey; + size_t ckeyl; + std::vector ckey_utf; + + std::string ctry; + size_t ctryl; + std::vector ctry_utf; + bool lang_with_dash_usage; + + AffixMgr* pAMgr; + unsigned int maxSug; + const struct cs_info* csconv; + int utf8; + int langnum; + int nosplitsugs; + int maxngramsugs; + int maxcpdsugs; + int complexprefixes; + std::chrono::steady_clock::time_point suggest_start; + + public: + SuggestMgr(const std::string& tryme, unsigned int maxn, AffixMgr* aptr); + SuggestMgr(const SuggestMgr&) = delete; + SuggestMgr& operator=(const SuggestMgr&) = delete; + ~SuggestMgr(); + + bool suggest(std::vector& slst, const std::string& word, int* onlycmpdsug, + // for testing compound words formed from 3 or more words: + // if test_simplesug == true, suggest() doesn't suggest compound words, + // and it returns with true at the first suggestion found + bool test_simplesug = false); + void ngsuggest(std::vector& slst, const char* word, const std::vector>& rHMgr, int captype); + + 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, + std::chrono::steady_clock::time_point* timelimit, + int& info); + int checkword(const std::string& word, int, int*, std::chrono::steady_clock::time_point*); + int check_forbidden(const std::string&); + + void capchars(std::vector&, const std::string&, int, int&); + int replchars(std::vector&, const std::string&, int, int&); + int doubletwochars(std::vector&, const std::string&, int, int&); + int forgotchar(std::vector&, const std::string&, int, int&); + int swapchar(std::vector&, const std::string&, int, int&); + int longswapchar(std::vector&, const std::string&, int, int&); + int movechar(std::vector&, const std::string&, int, int&); + int extrachar(std::vector&, const std::string&, int, int&); + int badcharkey(std::vector&, const std::string&, int, int&); + int badchar(std::vector&, const std::string&, int, int&); + bool twowords(std::vector&, const std::string&, int, bool, int&); + + void capchars_utf(std::vector&, const std::vector&, int, int&); + int doubletwochars_utf(std::vector&, const std::vector&, int, int&); + int forgotchar_utf(std::vector&, const std::vector&, int, int&); + int extrachar_utf(std::vector&, const std::vector&, int, int&); + int badcharkey_utf(std::vector&, const std::vector&, int, int&); + int badchar_utf(std::vector&, const std::vector&, int, int&); + int swapchar_utf(std::vector&, const std::vector&, int, int&); + int longswapchar_utf(std::vector&, const std::vector&, int, int&); + int movechar_utf(std::vector&, const std::vector&, int, int&); + + int mapchars(std::vector&, const std::string&, int, int&); + int map_related(const std::string&, + std::string&, + size_t, + std::vector& wlst, + int, + const std::vector&, + int*, + std::chrono::steady_clock::time_point*, + int depth, + int& info); + 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); + char* lcs(const char* s, const char* s2, int* l1, int* l2); + 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 diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/utf_info.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/utf_info.hxx new file mode 100644 index 00000000..86768c31 --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/utf_info.hxx @@ -0,0 +1,65585 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 { + bool cletter; + unsigned short cupper; + unsigned short clower; +}; + +/* fields: Unicode isletter, toupper, tolower */ +// clang-format off +static const struct unicode_info utf_tbl[] = { +/* 0x0000 */ { false, 0x0000, 0x0000 }, +/* 0x0001 */ { false, 0x0001, 0x0001 }, +/* 0x0002 */ { false, 0x0002, 0x0002 }, +/* 0x0003 */ { false, 0x0003, 0x0003 }, +/* 0x0004 */ { false, 0x0004, 0x0004 }, +/* 0x0005 */ { false, 0x0005, 0x0005 }, +/* 0x0006 */ { false, 0x0006, 0x0006 }, +/* 0x0007 */ { false, 0x0007, 0x0007 }, +/* 0x0008 */ { false, 0x0008, 0x0008 }, +/* 0x0009 */ { false, 0x0009, 0x0009 }, +/* 0x000a */ { false, 0x000a, 0x000a }, +/* 0x000b */ { false, 0x000b, 0x000b }, +/* 0x000c */ { false, 0x000c, 0x000c }, +/* 0x000d */ { false, 0x000d, 0x000d }, +/* 0x000e */ { false, 0x000e, 0x000e }, +/* 0x000f */ { false, 0x000f, 0x000f }, +/* 0x0010 */ { false, 0x0010, 0x0010 }, +/* 0x0011 */ { false, 0x0011, 0x0011 }, +/* 0x0012 */ { false, 0x0012, 0x0012 }, +/* 0x0013 */ { false, 0x0013, 0x0013 }, +/* 0x0014 */ { false, 0x0014, 0x0014 }, +/* 0x0015 */ { false, 0x0015, 0x0015 }, +/* 0x0016 */ { false, 0x0016, 0x0016 }, +/* 0x0017 */ { false, 0x0017, 0x0017 }, +/* 0x0018 */ { false, 0x0018, 0x0018 }, +/* 0x0019 */ { false, 0x0019, 0x0019 }, +/* 0x001a */ { false, 0x001a, 0x001a }, +/* 0x001b */ { false, 0x001b, 0x001b }, +/* 0x001c */ { false, 0x001c, 0x001c }, +/* 0x001d */ { false, 0x001d, 0x001d }, +/* 0x001e */ { false, 0x001e, 0x001e }, +/* 0x001f */ { false, 0x001f, 0x001f }, +/* 0x0020 */ { false, 0x0020, 0x0020 }, +/* 0x0021 */ { false, 0x0021, 0x0021 }, +/* 0x0022 */ { false, 0x0022, 0x0022 }, +/* 0x0023 */ { false, 0x0023, 0x0023 }, +/* 0x0024 */ { false, 0x0024, 0x0024 }, +/* 0x0025 */ { false, 0x0025, 0x0025 }, +/* 0x0026 */ { false, 0x0026, 0x0026 }, +/* 0x0027 */ { false, 0x0027, 0x0027 }, +/* 0x0028 */ { false, 0x0028, 0x0028 }, +/* 0x0029 */ { false, 0x0029, 0x0029 }, +/* 0x002a */ { false, 0x002a, 0x002a }, +/* 0x002b */ { false, 0x002b, 0x002b }, +/* 0x002c */ { false, 0x002c, 0x002c }, +/* 0x002d */ { false, 0x002d, 0x002d }, +/* 0x002e */ { false, 0x002e, 0x002e }, +/* 0x002f */ { false, 0x002f, 0x002f }, +/* 0x0030 */ { false, 0x0030, 0x0030 }, +/* 0x0031 */ { false, 0x0031, 0x0031 }, +/* 0x0032 */ { false, 0x0032, 0x0032 }, +/* 0x0033 */ { false, 0x0033, 0x0033 }, +/* 0x0034 */ { false, 0x0034, 0x0034 }, +/* 0x0035 */ { false, 0x0035, 0x0035 }, +/* 0x0036 */ { false, 0x0036, 0x0036 }, +/* 0x0037 */ { false, 0x0037, 0x0037 }, +/* 0x0038 */ { false, 0x0038, 0x0038 }, +/* 0x0039 */ { false, 0x0039, 0x0039 }, +/* 0x003a */ { false, 0x003a, 0x003a }, +/* 0x003b */ { false, 0x003b, 0x003b }, +/* 0x003c */ { false, 0x003c, 0x003c }, +/* 0x003d */ { false, 0x003d, 0x003d }, +/* 0x003e */ { false, 0x003e, 0x003e }, +/* 0x003f */ { false, 0x003f, 0x003f }, +/* 0x0040 */ { false, 0x0040, 0x0040 }, +/* 0x0041 */ { true, 0x0041, 0x0061 }, +/* 0x0042 */ { true, 0x0042, 0x0062 }, +/* 0x0043 */ { true, 0x0043, 0x0063 }, +/* 0x0044 */ { true, 0x0044, 0x0064 }, +/* 0x0045 */ { true, 0x0045, 0x0065 }, +/* 0x0046 */ { true, 0x0046, 0x0066 }, +/* 0x0047 */ { true, 0x0047, 0x0067 }, +/* 0x0048 */ { true, 0x0048, 0x0068 }, +/* 0x0049 */ { true, 0x0049, 0x0069 }, +/* 0x004a */ { true, 0x004a, 0x006a }, +/* 0x004b */ { true, 0x004b, 0x006b }, +/* 0x004c */ { true, 0x004c, 0x006c }, +/* 0x004d */ { true, 0x004d, 0x006d }, +/* 0x004e */ { true, 0x004e, 0x006e }, +/* 0x004f */ { true, 0x004f, 0x006f }, +/* 0x0050 */ { true, 0x0050, 0x0070 }, +/* 0x0051 */ { true, 0x0051, 0x0071 }, +/* 0x0052 */ { true, 0x0052, 0x0072 }, +/* 0x0053 */ { true, 0x0053, 0x0073 }, +/* 0x0054 */ { true, 0x0054, 0x0074 }, +/* 0x0055 */ { true, 0x0055, 0x0075 }, +/* 0x0056 */ { true, 0x0056, 0x0076 }, +/* 0x0057 */ { true, 0x0057, 0x0077 }, +/* 0x0058 */ { true, 0x0058, 0x0078 }, +/* 0x0059 */ { true, 0x0059, 0x0079 }, +/* 0x005a */ { true, 0x005a, 0x007a }, +/* 0x005b */ { false, 0x005b, 0x005b }, +/* 0x005c */ { false, 0x005c, 0x005c }, +/* 0x005d */ { false, 0x005d, 0x005d }, +/* 0x005e */ { false, 0x005e, 0x005e }, +/* 0x005f */ { false, 0x005f, 0x005f }, +/* 0x0060 */ { false, 0x0060, 0x0060 }, +/* 0x0061 */ { true, 0x0041, 0x0061 }, +/* 0x0062 */ { true, 0x0042, 0x0062 }, +/* 0x0063 */ { true, 0x0043, 0x0063 }, +/* 0x0064 */ { true, 0x0044, 0x0064 }, +/* 0x0065 */ { true, 0x0045, 0x0065 }, +/* 0x0066 */ { true, 0x0046, 0x0066 }, +/* 0x0067 */ { true, 0x0047, 0x0067 }, +/* 0x0068 */ { true, 0x0048, 0x0068 }, +/* 0x0069 */ { true, 0x0049, 0x0069 }, +/* 0x006a */ { true, 0x004a, 0x006a }, +/* 0x006b */ { true, 0x004b, 0x006b }, +/* 0x006c */ { true, 0x004c, 0x006c }, +/* 0x006d */ { true, 0x004d, 0x006d }, +/* 0x006e */ { true, 0x004e, 0x006e }, +/* 0x006f */ { true, 0x004f, 0x006f }, +/* 0x0070 */ { true, 0x0050, 0x0070 }, +/* 0x0071 */ { true, 0x0051, 0x0071 }, +/* 0x0072 */ { true, 0x0052, 0x0072 }, +/* 0x0073 */ { true, 0x0053, 0x0073 }, +/* 0x0074 */ { true, 0x0054, 0x0074 }, +/* 0x0075 */ { true, 0x0055, 0x0075 }, +/* 0x0076 */ { true, 0x0056, 0x0076 }, +/* 0x0077 */ { true, 0x0057, 0x0077 }, +/* 0x0078 */ { true, 0x0058, 0x0078 }, +/* 0x0079 */ { true, 0x0059, 0x0079 }, +/* 0x007a */ { true, 0x005a, 0x007a }, +/* 0x007b */ { false, 0x007b, 0x007b }, +/* 0x007c */ { false, 0x007c, 0x007c }, +/* 0x007d */ { false, 0x007d, 0x007d }, +/* 0x007e */ { false, 0x007e, 0x007e }, +/* 0x007f */ { false, 0x007f, 0x007f }, +/* 0x0080 */ { false, 0x0080, 0x0080 }, +/* 0x0081 */ { false, 0x0081, 0x0081 }, +/* 0x0082 */ { false, 0x0082, 0x0082 }, +/* 0x0083 */ { false, 0x0083, 0x0083 }, +/* 0x0084 */ { false, 0x0084, 0x0084 }, +/* 0x0085 */ { false, 0x0085, 0x0085 }, +/* 0x0086 */ { false, 0x0086, 0x0086 }, +/* 0x0087 */ { false, 0x0087, 0x0087 }, +/* 0x0088 */ { false, 0x0088, 0x0088 }, +/* 0x0089 */ { false, 0x0089, 0x0089 }, +/* 0x008a */ { false, 0x008a, 0x008a }, +/* 0x008b */ { false, 0x008b, 0x008b }, +/* 0x008c */ { false, 0x008c, 0x008c }, +/* 0x008d */ { false, 0x008d, 0x008d }, +/* 0x008e */ { false, 0x008e, 0x008e }, +/* 0x008f */ { false, 0x008f, 0x008f }, +/* 0x0090 */ { false, 0x0090, 0x0090 }, +/* 0x0091 */ { false, 0x0091, 0x0091 }, +/* 0x0092 */ { false, 0x0092, 0x0092 }, +/* 0x0093 */ { false, 0x0093, 0x0093 }, +/* 0x0094 */ { false, 0x0094, 0x0094 }, +/* 0x0095 */ { false, 0x0095, 0x0095 }, +/* 0x0096 */ { false, 0x0096, 0x0096 }, +/* 0x0097 */ { false, 0x0097, 0x0097 }, +/* 0x0098 */ { false, 0x0098, 0x0098 }, +/* 0x0099 */ { false, 0x0099, 0x0099 }, +/* 0x009a */ { false, 0x009a, 0x009a }, +/* 0x009b */ { false, 0x009b, 0x009b }, +/* 0x009c */ { false, 0x009c, 0x009c }, +/* 0x009d */ { false, 0x009d, 0x009d }, +/* 0x009e */ { false, 0x009e, 0x009e }, +/* 0x009f */ { false, 0x009f, 0x009f }, +/* 0x00a0 */ { false, 0x00a0, 0x00a0 }, +/* 0x00a1 */ { false, 0x00a1, 0x00a1 }, +/* 0x00a2 */ { false, 0x00a2, 0x00a2 }, +/* 0x00a3 */ { false, 0x00a3, 0x00a3 }, +/* 0x00a4 */ { false, 0x00a4, 0x00a4 }, +/* 0x00a5 */ { false, 0x00a5, 0x00a5 }, +/* 0x00a6 */ { false, 0x00a6, 0x00a6 }, +/* 0x00a7 */ { false, 0x00a7, 0x00a7 }, +/* 0x00a8 */ { false, 0x00a8, 0x00a8 }, +/* 0x00a9 */ { false, 0x00a9, 0x00a9 }, +/* 0x00aa */ { true, 0x00aa, 0x00aa }, +/* 0x00ab */ { false, 0x00ab, 0x00ab }, +/* 0x00ac */ { false, 0x00ac, 0x00ac }, +/* 0x00ad */ { false, 0x00ad, 0x00ad }, +/* 0x00ae */ { false, 0x00ae, 0x00ae }, +/* 0x00af */ { false, 0x00af, 0x00af }, +/* 0x00b0 */ { false, 0x00b0, 0x00b0 }, +/* 0x00b1 */ { false, 0x00b1, 0x00b1 }, +/* 0x00b2 */ { false, 0x00b2, 0x00b2 }, +/* 0x00b3 */ { false, 0x00b3, 0x00b3 }, +/* 0x00b4 */ { false, 0x00b4, 0x00b4 }, +/* 0x00b5 */ { true, 0x039c, 0x00b5 }, +/* 0x00b6 */ { false, 0x00b6, 0x00b6 }, +/* 0x00b7 */ { false, 0x00b7, 0x00b7 }, +/* 0x00b8 */ { false, 0x00b8, 0x00b8 }, +/* 0x00b9 */ { false, 0x00b9, 0x00b9 }, +/* 0x00ba */ { true, 0x00ba, 0x00ba }, +/* 0x00bb */ { false, 0x00bb, 0x00bb }, +/* 0x00bc */ { false, 0x00bc, 0x00bc }, +/* 0x00bd */ { false, 0x00bd, 0x00bd }, +/* 0x00be */ { false, 0x00be, 0x00be }, +/* 0x00bf */ { false, 0x00bf, 0x00bf }, +/* 0x00c0 */ { true, 0x00c0, 0x00e0 }, +/* 0x00c1 */ { true, 0x00c1, 0x00e1 }, +/* 0x00c2 */ { true, 0x00c2, 0x00e2 }, +/* 0x00c3 */ { true, 0x00c3, 0x00e3 }, +/* 0x00c4 */ { true, 0x00c4, 0x00e4 }, +/* 0x00c5 */ { true, 0x00c5, 0x00e5 }, +/* 0x00c6 */ { true, 0x00c6, 0x00e6 }, +/* 0x00c7 */ { true, 0x00c7, 0x00e7 }, +/* 0x00c8 */ { true, 0x00c8, 0x00e8 }, +/* 0x00c9 */ { true, 0x00c9, 0x00e9 }, +/* 0x00ca */ { true, 0x00ca, 0x00ea }, +/* 0x00cb */ { true, 0x00cb, 0x00eb }, +/* 0x00cc */ { true, 0x00cc, 0x00ec }, +/* 0x00cd */ { true, 0x00cd, 0x00ed }, +/* 0x00ce */ { true, 0x00ce, 0x00ee }, +/* 0x00cf */ { true, 0x00cf, 0x00ef }, +/* 0x00d0 */ { true, 0x00d0, 0x00f0 }, +/* 0x00d1 */ { true, 0x00d1, 0x00f1 }, +/* 0x00d2 */ { true, 0x00d2, 0x00f2 }, +/* 0x00d3 */ { true, 0x00d3, 0x00f3 }, +/* 0x00d4 */ { true, 0x00d4, 0x00f4 }, +/* 0x00d5 */ { true, 0x00d5, 0x00f5 }, +/* 0x00d6 */ { true, 0x00d6, 0x00f6 }, +/* 0x00d7 */ { false, 0x00d7, 0x00d7 }, +/* 0x00d8 */ { true, 0x00d8, 0x00f8 }, +/* 0x00d9 */ { true, 0x00d9, 0x00f9 }, +/* 0x00da */ { true, 0x00da, 0x00fa }, +/* 0x00db */ { true, 0x00db, 0x00fb }, +/* 0x00dc */ { true, 0x00dc, 0x00fc }, +/* 0x00dd */ { true, 0x00dd, 0x00fd }, +/* 0x00de */ { true, 0x00de, 0x00fe }, +/* 0x00df */ { true, 0x00df, 0x00df }, +/* 0x00e0 */ { true, 0x00c0, 0x00e0 }, +/* 0x00e1 */ { true, 0x00c1, 0x00e1 }, +/* 0x00e2 */ { true, 0x00c2, 0x00e2 }, +/* 0x00e3 */ { true, 0x00c3, 0x00e3 }, +/* 0x00e4 */ { true, 0x00c4, 0x00e4 }, +/* 0x00e5 */ { true, 0x00c5, 0x00e5 }, +/* 0x00e6 */ { true, 0x00c6, 0x00e6 }, +/* 0x00e7 */ { true, 0x00c7, 0x00e7 }, +/* 0x00e8 */ { true, 0x00c8, 0x00e8 }, +/* 0x00e9 */ { true, 0x00c9, 0x00e9 }, +/* 0x00ea */ { true, 0x00ca, 0x00ea }, +/* 0x00eb */ { true, 0x00cb, 0x00eb }, +/* 0x00ec */ { true, 0x00cc, 0x00ec }, +/* 0x00ed */ { true, 0x00cd, 0x00ed }, +/* 0x00ee */ { true, 0x00ce, 0x00ee }, +/* 0x00ef */ { true, 0x00cf, 0x00ef }, +/* 0x00f0 */ { true, 0x00d0, 0x00f0 }, +/* 0x00f1 */ { true, 0x00d1, 0x00f1 }, +/* 0x00f2 */ { true, 0x00d2, 0x00f2 }, +/* 0x00f3 */ { true, 0x00d3, 0x00f3 }, +/* 0x00f4 */ { true, 0x00d4, 0x00f4 }, +/* 0x00f5 */ { true, 0x00d5, 0x00f5 }, +/* 0x00f6 */ { true, 0x00d6, 0x00f6 }, +/* 0x00f7 */ { false, 0x00f7, 0x00f7 }, +/* 0x00f8 */ { true, 0x00d8, 0x00f8 }, +/* 0x00f9 */ { true, 0x00d9, 0x00f9 }, +/* 0x00fa */ { true, 0x00da, 0x00fa }, +/* 0x00fb */ { true, 0x00db, 0x00fb }, +/* 0x00fc */ { true, 0x00dc, 0x00fc }, +/* 0x00fd */ { true, 0x00dd, 0x00fd }, +/* 0x00fe */ { true, 0x00de, 0x00fe }, +/* 0x00ff */ { true, 0x0178, 0x00ff }, +/* 0x0100 */ { true, 0x0100, 0x0101 }, +/* 0x0101 */ { true, 0x0100, 0x0101 }, +/* 0x0102 */ { true, 0x0102, 0x0103 }, +/* 0x0103 */ { true, 0x0102, 0x0103 }, +/* 0x0104 */ { true, 0x0104, 0x0105 }, +/* 0x0105 */ { true, 0x0104, 0x0105 }, +/* 0x0106 */ { true, 0x0106, 0x0107 }, +/* 0x0107 */ { true, 0x0106, 0x0107 }, +/* 0x0108 */ { true, 0x0108, 0x0109 }, +/* 0x0109 */ { true, 0x0108, 0x0109 }, +/* 0x010a */ { true, 0x010a, 0x010b }, +/* 0x010b */ { true, 0x010a, 0x010b }, +/* 0x010c */ { true, 0x010c, 0x010d }, +/* 0x010d */ { true, 0x010c, 0x010d }, +/* 0x010e */ { true, 0x010e, 0x010f }, +/* 0x010f */ { true, 0x010e, 0x010f }, +/* 0x0110 */ { true, 0x0110, 0x0111 }, +/* 0x0111 */ { true, 0x0110, 0x0111 }, +/* 0x0112 */ { true, 0x0112, 0x0113 }, +/* 0x0113 */ { true, 0x0112, 0x0113 }, +/* 0x0114 */ { true, 0x0114, 0x0115 }, +/* 0x0115 */ { true, 0x0114, 0x0115 }, +/* 0x0116 */ { true, 0x0116, 0x0117 }, +/* 0x0117 */ { true, 0x0116, 0x0117 }, +/* 0x0118 */ { true, 0x0118, 0x0119 }, +/* 0x0119 */ { true, 0x0118, 0x0119 }, +/* 0x011a */ { true, 0x011a, 0x011b }, +/* 0x011b */ { true, 0x011a, 0x011b }, +/* 0x011c */ { true, 0x011c, 0x011d }, +/* 0x011d */ { true, 0x011c, 0x011d }, +/* 0x011e */ { true, 0x011e, 0x011f }, +/* 0x011f */ { true, 0x011e, 0x011f }, +/* 0x0120 */ { true, 0x0120, 0x0121 }, +/* 0x0121 */ { true, 0x0120, 0x0121 }, +/* 0x0122 */ { true, 0x0122, 0x0123 }, +/* 0x0123 */ { true, 0x0122, 0x0123 }, +/* 0x0124 */ { true, 0x0124, 0x0125 }, +/* 0x0125 */ { true, 0x0124, 0x0125 }, +/* 0x0126 */ { true, 0x0126, 0x0127 }, +/* 0x0127 */ { true, 0x0126, 0x0127 }, +/* 0x0128 */ { true, 0x0128, 0x0129 }, +/* 0x0129 */ { true, 0x0128, 0x0129 }, +/* 0x012a */ { true, 0x012a, 0x012b }, +/* 0x012b */ { true, 0x012a, 0x012b }, +/* 0x012c */ { true, 0x012c, 0x012d }, +/* 0x012d */ { true, 0x012c, 0x012d }, +/* 0x012e */ { true, 0x012e, 0x012f }, +/* 0x012f */ { true, 0x012e, 0x012f }, +/* 0x0130 */ { true, 0x0130, 0x0069 }, +/* 0x0131 */ { true, 0x0049, 0x0131 }, +/* 0x0132 */ { true, 0x0132, 0x0133 }, +/* 0x0133 */ { true, 0x0132, 0x0133 }, +/* 0x0134 */ { true, 0x0134, 0x0135 }, +/* 0x0135 */ { true, 0x0134, 0x0135 }, +/* 0x0136 */ { true, 0x0136, 0x0137 }, +/* 0x0137 */ { true, 0x0136, 0x0137 }, +/* 0x0138 */ { true, 0x0138, 0x0138 }, +/* 0x0139 */ { true, 0x0139, 0x013a }, +/* 0x013a */ { true, 0x0139, 0x013a }, +/* 0x013b */ { true, 0x013b, 0x013c }, +/* 0x013c */ { true, 0x013b, 0x013c }, +/* 0x013d */ { true, 0x013d, 0x013e }, +/* 0x013e */ { true, 0x013d, 0x013e }, +/* 0x013f */ { true, 0x013f, 0x0140 }, +/* 0x0140 */ { true, 0x013f, 0x0140 }, +/* 0x0141 */ { true, 0x0141, 0x0142 }, +/* 0x0142 */ { true, 0x0141, 0x0142 }, +/* 0x0143 */ { true, 0x0143, 0x0144 }, +/* 0x0144 */ { true, 0x0143, 0x0144 }, +/* 0x0145 */ { true, 0x0145, 0x0146 }, +/* 0x0146 */ { true, 0x0145, 0x0146 }, +/* 0x0147 */ { true, 0x0147, 0x0148 }, +/* 0x0148 */ { true, 0x0147, 0x0148 }, +/* 0x0149 */ { true, 0x0149, 0x0149 }, +/* 0x014a */ { true, 0x014a, 0x014b }, +/* 0x014b */ { true, 0x014a, 0x014b }, +/* 0x014c */ { true, 0x014c, 0x014d }, +/* 0x014d */ { true, 0x014c, 0x014d }, +/* 0x014e */ { true, 0x014e, 0x014f }, +/* 0x014f */ { true, 0x014e, 0x014f }, +/* 0x0150 */ { true, 0x0150, 0x0151 }, +/* 0x0151 */ { true, 0x0150, 0x0151 }, +/* 0x0152 */ { true, 0x0152, 0x0153 }, +/* 0x0153 */ { true, 0x0152, 0x0153 }, +/* 0x0154 */ { true, 0x0154, 0x0155 }, +/* 0x0155 */ { true, 0x0154, 0x0155 }, +/* 0x0156 */ { true, 0x0156, 0x0157 }, +/* 0x0157 */ { true, 0x0156, 0x0157 }, +/* 0x0158 */ { true, 0x0158, 0x0159 }, +/* 0x0159 */ { true, 0x0158, 0x0159 }, +/* 0x015a */ { true, 0x015a, 0x015b }, +/* 0x015b */ { true, 0x015a, 0x015b }, +/* 0x015c */ { true, 0x015c, 0x015d }, +/* 0x015d */ { true, 0x015c, 0x015d }, +/* 0x015e */ { true, 0x015e, 0x015f }, +/* 0x015f */ { true, 0x015e, 0x015f }, +/* 0x0160 */ { true, 0x0160, 0x0161 }, +/* 0x0161 */ { true, 0x0160, 0x0161 }, +/* 0x0162 */ { true, 0x0162, 0x0163 }, +/* 0x0163 */ { true, 0x0162, 0x0163 }, +/* 0x0164 */ { true, 0x0164, 0x0165 }, +/* 0x0165 */ { true, 0x0164, 0x0165 }, +/* 0x0166 */ { true, 0x0166, 0x0167 }, +/* 0x0167 */ { true, 0x0166, 0x0167 }, +/* 0x0168 */ { true, 0x0168, 0x0169 }, +/* 0x0169 */ { true, 0x0168, 0x0169 }, +/* 0x016a */ { true, 0x016a, 0x016b }, +/* 0x016b */ { true, 0x016a, 0x016b }, +/* 0x016c */ { true, 0x016c, 0x016d }, +/* 0x016d */ { true, 0x016c, 0x016d }, +/* 0x016e */ { true, 0x016e, 0x016f }, +/* 0x016f */ { true, 0x016e, 0x016f }, +/* 0x0170 */ { true, 0x0170, 0x0171 }, +/* 0x0171 */ { true, 0x0170, 0x0171 }, +/* 0x0172 */ { true, 0x0172, 0x0173 }, +/* 0x0173 */ { true, 0x0172, 0x0173 }, +/* 0x0174 */ { true, 0x0174, 0x0175 }, +/* 0x0175 */ { true, 0x0174, 0x0175 }, +/* 0x0176 */ { true, 0x0176, 0x0177 }, +/* 0x0177 */ { true, 0x0176, 0x0177 }, +/* 0x0178 */ { true, 0x0178, 0x00ff }, +/* 0x0179 */ { true, 0x0179, 0x017a }, +/* 0x017a */ { true, 0x0179, 0x017a }, +/* 0x017b */ { true, 0x017b, 0x017c }, +/* 0x017c */ { true, 0x017b, 0x017c }, +/* 0x017d */ { true, 0x017d, 0x017e }, +/* 0x017e */ { true, 0x017d, 0x017e }, +/* 0x017f */ { true, 0x0053, 0x017f }, +/* 0x0180 */ { true, 0x0180, 0x0180 }, +/* 0x0181 */ { true, 0x0181, 0x0253 }, +/* 0x0182 */ { true, 0x0182, 0x0183 }, +/* 0x0183 */ { true, 0x0182, 0x0183 }, +/* 0x0184 */ { true, 0x0184, 0x0185 }, +/* 0x0185 */ { true, 0x0184, 0x0185 }, +/* 0x0186 */ { true, 0x0186, 0x0254 }, +/* 0x0187 */ { true, 0x0187, 0x0188 }, +/* 0x0188 */ { true, 0x0187, 0x0188 }, +/* 0x0189 */ { true, 0x0189, 0x0256 }, +/* 0x018a */ { true, 0x018a, 0x0257 }, +/* 0x018b */ { true, 0x018b, 0x018c }, +/* 0x018c */ { true, 0x018b, 0x018c }, +/* 0x018d */ { true, 0x018d, 0x018d }, +/* 0x018e */ { true, 0x018e, 0x01dd }, +/* 0x018f */ { true, 0x018f, 0x0259 }, +/* 0x0190 */ { true, 0x0190, 0x025b }, +/* 0x0191 */ { true, 0x0191, 0x0192 }, +/* 0x0192 */ { true, 0x0191, 0x0192 }, +/* 0x0193 */ { true, 0x0193, 0x0260 }, +/* 0x0194 */ { true, 0x0194, 0x0263 }, +/* 0x0195 */ { true, 0x01f6, 0x0195 }, +/* 0x0196 */ { true, 0x0196, 0x0269 }, +/* 0x0197 */ { true, 0x0197, 0x0268 }, +/* 0x0198 */ { true, 0x0198, 0x0199 }, +/* 0x0199 */ { true, 0x0198, 0x0199 }, +/* 0x019a */ { true, 0x023d, 0x019a }, +/* 0x019b */ { true, 0x019b, 0x019b }, +/* 0x019c */ { true, 0x019c, 0x026f }, +/* 0x019d */ { true, 0x019d, 0x0272 }, +/* 0x019e */ { true, 0x0220, 0x019e }, +/* 0x019f */ { true, 0x019f, 0x0275 }, +/* 0x01a0 */ { true, 0x01a0, 0x01a1 }, +/* 0x01a1 */ { true, 0x01a0, 0x01a1 }, +/* 0x01a2 */ { true, 0x01a2, 0x01a3 }, +/* 0x01a3 */ { true, 0x01a2, 0x01a3 }, +/* 0x01a4 */ { true, 0x01a4, 0x01a5 }, +/* 0x01a5 */ { true, 0x01a4, 0x01a5 }, +/* 0x01a6 */ { true, 0x01a6, 0x0280 }, +/* 0x01a7 */ { true, 0x01a7, 0x01a8 }, +/* 0x01a8 */ { true, 0x01a7, 0x01a8 }, +/* 0x01a9 */ { true, 0x01a9, 0x0283 }, +/* 0x01aa */ { true, 0x01aa, 0x01aa }, +/* 0x01ab */ { true, 0x01ab, 0x01ab }, +/* 0x01ac */ { true, 0x01ac, 0x01ad }, +/* 0x01ad */ { true, 0x01ac, 0x01ad }, +/* 0x01ae */ { true, 0x01ae, 0x0288 }, +/* 0x01af */ { true, 0x01af, 0x01b0 }, +/* 0x01b0 */ { true, 0x01af, 0x01b0 }, +/* 0x01b1 */ { true, 0x01b1, 0x028a }, +/* 0x01b2 */ { true, 0x01b2, 0x028b }, +/* 0x01b3 */ { true, 0x01b3, 0x01b4 }, +/* 0x01b4 */ { true, 0x01b3, 0x01b4 }, +/* 0x01b5 */ { true, 0x01b5, 0x01b6 }, +/* 0x01b6 */ { true, 0x01b5, 0x01b6 }, +/* 0x01b7 */ { true, 0x01b7, 0x0292 }, +/* 0x01b8 */ { true, 0x01b8, 0x01b9 }, +/* 0x01b9 */ { true, 0x01b8, 0x01b9 }, +/* 0x01ba */ { true, 0x01ba, 0x01ba }, +/* 0x01bb */ { true, 0x01bb, 0x01bb }, +/* 0x01bc */ { true, 0x01bc, 0x01bd }, +/* 0x01bd */ { true, 0x01bc, 0x01bd }, +/* 0x01be */ { true, 0x01be, 0x01be }, +/* 0x01bf */ { true, 0x01f7, 0x01bf }, +/* 0x01c0 */ { true, 0x01c0, 0x01c0 }, +/* 0x01c1 */ { true, 0x01c1, 0x01c1 }, +/* 0x01c2 */ { true, 0x01c2, 0x01c2 }, +/* 0x01c3 */ { true, 0x01c3, 0x01c3 }, +/* 0x01c4 */ { true, 0x01c4, 0x01c6 }, +/* 0x01c5 */ { true, 0x01c4, 0x01c6 }, +/* 0x01c6 */ { true, 0x01c4, 0x01c6 }, +/* 0x01c7 */ { true, 0x01c7, 0x01c9 }, +/* 0x01c8 */ { true, 0x01c7, 0x01c9 }, +/* 0x01c9 */ { true, 0x01c7, 0x01c9 }, +/* 0x01ca */ { true, 0x01ca, 0x01cc }, +/* 0x01cb */ { true, 0x01ca, 0x01cc }, +/* 0x01cc */ { true, 0x01ca, 0x01cc }, +/* 0x01cd */ { true, 0x01cd, 0x01ce }, +/* 0x01ce */ { true, 0x01cd, 0x01ce }, +/* 0x01cf */ { true, 0x01cf, 0x01d0 }, +/* 0x01d0 */ { true, 0x01cf, 0x01d0 }, +/* 0x01d1 */ { true, 0x01d1, 0x01d2 }, +/* 0x01d2 */ { true, 0x01d1, 0x01d2 }, +/* 0x01d3 */ { true, 0x01d3, 0x01d4 }, +/* 0x01d4 */ { true, 0x01d3, 0x01d4 }, +/* 0x01d5 */ { true, 0x01d5, 0x01d6 }, +/* 0x01d6 */ { true, 0x01d5, 0x01d6 }, +/* 0x01d7 */ { true, 0x01d7, 0x01d8 }, +/* 0x01d8 */ { true, 0x01d7, 0x01d8 }, +/* 0x01d9 */ { true, 0x01d9, 0x01da }, +/* 0x01da */ { true, 0x01d9, 0x01da }, +/* 0x01db */ { true, 0x01db, 0x01dc }, +/* 0x01dc */ { true, 0x01db, 0x01dc }, +/* 0x01dd */ { true, 0x018e, 0x01dd }, +/* 0x01de */ { true, 0x01de, 0x01df }, +/* 0x01df */ { true, 0x01de, 0x01df }, +/* 0x01e0 */ { true, 0x01e0, 0x01e1 }, +/* 0x01e1 */ { true, 0x01e0, 0x01e1 }, +/* 0x01e2 */ { true, 0x01e2, 0x01e3 }, +/* 0x01e3 */ { true, 0x01e2, 0x01e3 }, +/* 0x01e4 */ { true, 0x01e4, 0x01e5 }, +/* 0x01e5 */ { true, 0x01e4, 0x01e5 }, +/* 0x01e6 */ { true, 0x01e6, 0x01e7 }, +/* 0x01e7 */ { true, 0x01e6, 0x01e7 }, +/* 0x01e8 */ { true, 0x01e8, 0x01e9 }, +/* 0x01e9 */ { true, 0x01e8, 0x01e9 }, +/* 0x01ea */ { true, 0x01ea, 0x01eb }, +/* 0x01eb */ { true, 0x01ea, 0x01eb }, +/* 0x01ec */ { true, 0x01ec, 0x01ed }, +/* 0x01ed */ { true, 0x01ec, 0x01ed }, +/* 0x01ee */ { true, 0x01ee, 0x01ef }, +/* 0x01ef */ { true, 0x01ee, 0x01ef }, +/* 0x01f0 */ { true, 0x01f0, 0x01f0 }, +/* 0x01f1 */ { true, 0x01f1, 0x01f3 }, +/* 0x01f2 */ { true, 0x01f1, 0x01f3 }, +/* 0x01f3 */ { true, 0x01f1, 0x01f3 }, +/* 0x01f4 */ { true, 0x01f4, 0x01f5 }, +/* 0x01f5 */ { true, 0x01f4, 0x01f5 }, +/* 0x01f6 */ { true, 0x01f6, 0x0195 }, +/* 0x01f7 */ { true, 0x01f7, 0x01bf }, +/* 0x01f8 */ { true, 0x01f8, 0x01f9 }, +/* 0x01f9 */ { true, 0x01f8, 0x01f9 }, +/* 0x01fa */ { true, 0x01fa, 0x01fb }, +/* 0x01fb */ { true, 0x01fa, 0x01fb }, +/* 0x01fc */ { true, 0x01fc, 0x01fd }, +/* 0x01fd */ { true, 0x01fc, 0x01fd }, +/* 0x01fe */ { true, 0x01fe, 0x01ff }, +/* 0x01ff */ { true, 0x01fe, 0x01ff }, +/* 0x0200 */ { true, 0x0200, 0x0201 }, +/* 0x0201 */ { true, 0x0200, 0x0201 }, +/* 0x0202 */ { true, 0x0202, 0x0203 }, +/* 0x0203 */ { true, 0x0202, 0x0203 }, +/* 0x0204 */ { true, 0x0204, 0x0205 }, +/* 0x0205 */ { true, 0x0204, 0x0205 }, +/* 0x0206 */ { true, 0x0206, 0x0207 }, +/* 0x0207 */ { true, 0x0206, 0x0207 }, +/* 0x0208 */ { true, 0x0208, 0x0209 }, +/* 0x0209 */ { true, 0x0208, 0x0209 }, +/* 0x020a */ { true, 0x020a, 0x020b }, +/* 0x020b */ { true, 0x020a, 0x020b }, +/* 0x020c */ { true, 0x020c, 0x020d }, +/* 0x020d */ { true, 0x020c, 0x020d }, +/* 0x020e */ { true, 0x020e, 0x020f }, +/* 0x020f */ { true, 0x020e, 0x020f }, +/* 0x0210 */ { true, 0x0210, 0x0211 }, +/* 0x0211 */ { true, 0x0210, 0x0211 }, +/* 0x0212 */ { true, 0x0212, 0x0213 }, +/* 0x0213 */ { true, 0x0212, 0x0213 }, +/* 0x0214 */ { true, 0x0214, 0x0215 }, +/* 0x0215 */ { true, 0x0214, 0x0215 }, +/* 0x0216 */ { true, 0x0216, 0x0217 }, +/* 0x0217 */ { true, 0x0216, 0x0217 }, +/* 0x0218 */ { true, 0x0218, 0x0219 }, +/* 0x0219 */ { true, 0x0218, 0x0219 }, +/* 0x021a */ { true, 0x021a, 0x021b }, +/* 0x021b */ { true, 0x021a, 0x021b }, +/* 0x021c */ { true, 0x021c, 0x021d }, +/* 0x021d */ { true, 0x021c, 0x021d }, +/* 0x021e */ { true, 0x021e, 0x021f }, +/* 0x021f */ { true, 0x021e, 0x021f }, +/* 0x0220 */ { true, 0x0220, 0x019e }, +/* 0x0221 */ { true, 0x0221, 0x0221 }, +/* 0x0222 */ { true, 0x0222, 0x0223 }, +/* 0x0223 */ { true, 0x0222, 0x0223 }, +/* 0x0224 */ { true, 0x0224, 0x0225 }, +/* 0x0225 */ { true, 0x0224, 0x0225 }, +/* 0x0226 */ { true, 0x0226, 0x0227 }, +/* 0x0227 */ { true, 0x0226, 0x0227 }, +/* 0x0228 */ { true, 0x0228, 0x0229 }, +/* 0x0229 */ { true, 0x0228, 0x0229 }, +/* 0x022a */ { true, 0x022a, 0x022b }, +/* 0x022b */ { true, 0x022a, 0x022b }, +/* 0x022c */ { true, 0x022c, 0x022d }, +/* 0x022d */ { true, 0x022c, 0x022d }, +/* 0x022e */ { true, 0x022e, 0x022f }, +/* 0x022f */ { true, 0x022e, 0x022f }, +/* 0x0230 */ { true, 0x0230, 0x0231 }, +/* 0x0231 */ { true, 0x0230, 0x0231 }, +/* 0x0232 */ { true, 0x0232, 0x0233 }, +/* 0x0233 */ { true, 0x0232, 0x0233 }, +/* 0x0234 */ { true, 0x0234, 0x0234 }, +/* 0x0235 */ { true, 0x0235, 0x0235 }, +/* 0x0236 */ { true, 0x0236, 0x0236 }, +/* 0x0237 */ { true, 0x0237, 0x0237 }, +/* 0x0238 */ { true, 0x0238, 0x0238 }, +/* 0x0239 */ { true, 0x0239, 0x0239 }, +/* 0x023a */ { true, 0x023a, 0x023a }, +/* 0x023b */ { true, 0x023b, 0x023c }, +/* 0x023c */ { true, 0x023b, 0x023c }, +/* 0x023d */ { true, 0x023d, 0x019a }, +/* 0x023e */ { true, 0x023e, 0x023e }, +/* 0x023f */ { true, 0x023f, 0x023f }, +/* 0x0240 */ { true, 0x0240, 0x0240 }, +/* 0x0241 */ { true, 0x0241, 0x0294 }, +/* 0x0242 */ { false, 0x0242, 0x0242 }, +/* 0x0243 */ { false, 0x0243, 0x0243 }, +/* 0x0244 */ { false, 0x0244, 0x0244 }, +/* 0x0245 */ { false, 0x0245, 0x0245 }, +/* 0x0246 */ { false, 0x0246, 0x0246 }, +/* 0x0247 */ { false, 0x0247, 0x0247 }, +/* 0x0248 */ { false, 0x0248, 0x0248 }, +/* 0x0249 */ { false, 0x0249, 0x0249 }, +/* 0x024a */ { false, 0x024a, 0x024a }, +/* 0x024b */ { false, 0x024b, 0x024b }, +/* 0x024c */ { false, 0x024c, 0x024c }, +/* 0x024d */ { false, 0x024d, 0x024d }, +/* 0x024e */ { false, 0x024e, 0x024e }, +/* 0x024f */ { false, 0x024f, 0x024f }, +/* 0x0250 */ { true, 0x0250, 0x0250 }, +/* 0x0251 */ { true, 0x0251, 0x0251 }, +/* 0x0252 */ { true, 0x0252, 0x0252 }, +/* 0x0253 */ { true, 0x0181, 0x0253 }, +/* 0x0254 */ { true, 0x0186, 0x0254 }, +/* 0x0255 */ { true, 0x0255, 0x0255 }, +/* 0x0256 */ { true, 0x0189, 0x0256 }, +/* 0x0257 */ { true, 0x018a, 0x0257 }, +/* 0x0258 */ { true, 0x0258, 0x0258 }, +/* 0x0259 */ { true, 0x018f, 0x0259 }, +/* 0x025a */ { true, 0x025a, 0x025a }, +/* 0x025b */ { true, 0x0190, 0x025b }, +/* 0x025c */ { true, 0x025c, 0x025c }, +/* 0x025d */ { true, 0x025d, 0x025d }, +/* 0x025e */ { true, 0x025e, 0x025e }, +/* 0x025f */ { true, 0x025f, 0x025f }, +/* 0x0260 */ { true, 0x0193, 0x0260 }, +/* 0x0261 */ { true, 0x0261, 0x0261 }, +/* 0x0262 */ { true, 0x0262, 0x0262 }, +/* 0x0263 */ { true, 0x0194, 0x0263 }, +/* 0x0264 */ { true, 0x0264, 0x0264 }, +/* 0x0265 */ { true, 0x0265, 0x0265 }, +/* 0x0266 */ { true, 0x0266, 0x0266 }, +/* 0x0267 */ { true, 0x0267, 0x0267 }, +/* 0x0268 */ { true, 0x0197, 0x0268 }, +/* 0x0269 */ { true, 0x0196, 0x0269 }, +/* 0x026a */ { true, 0x026a, 0x026a }, +/* 0x026b */ { true, 0x026b, 0x026b }, +/* 0x026c */ { true, 0x026c, 0x026c }, +/* 0x026d */ { true, 0x026d, 0x026d }, +/* 0x026e */ { true, 0x026e, 0x026e }, +/* 0x026f */ { true, 0x019c, 0x026f }, +/* 0x0270 */ { true, 0x0270, 0x0270 }, +/* 0x0271 */ { true, 0x0271, 0x0271 }, +/* 0x0272 */ { true, 0x019d, 0x0272 }, +/* 0x0273 */ { true, 0x0273, 0x0273 }, +/* 0x0274 */ { true, 0x0274, 0x0274 }, +/* 0x0275 */ { true, 0x019f, 0x0275 }, +/* 0x0276 */ { true, 0x0276, 0x0276 }, +/* 0x0277 */ { true, 0x0277, 0x0277 }, +/* 0x0278 */ { true, 0x0278, 0x0278 }, +/* 0x0279 */ { true, 0x0279, 0x0279 }, +/* 0x027a */ { true, 0x027a, 0x027a }, +/* 0x027b */ { true, 0x027b, 0x027b }, +/* 0x027c */ { true, 0x027c, 0x027c }, +/* 0x027d */ { true, 0x027d, 0x027d }, +/* 0x027e */ { true, 0x027e, 0x027e }, +/* 0x027f */ { true, 0x027f, 0x027f }, +/* 0x0280 */ { true, 0x01a6, 0x0280 }, +/* 0x0281 */ { true, 0x0281, 0x0281 }, +/* 0x0282 */ { true, 0x0282, 0x0282 }, +/* 0x0283 */ { true, 0x01a9, 0x0283 }, +/* 0x0284 */ { true, 0x0284, 0x0284 }, +/* 0x0285 */ { true, 0x0285, 0x0285 }, +/* 0x0286 */ { true, 0x0286, 0x0286 }, +/* 0x0287 */ { true, 0x0287, 0x0287 }, +/* 0x0288 */ { true, 0x01ae, 0x0288 }, +/* 0x0289 */ { true, 0x0289, 0x0289 }, +/* 0x028a */ { true, 0x01b1, 0x028a }, +/* 0x028b */ { true, 0x01b2, 0x028b }, +/* 0x028c */ { true, 0x028c, 0x028c }, +/* 0x028d */ { true, 0x028d, 0x028d }, +/* 0x028e */ { true, 0x028e, 0x028e }, +/* 0x028f */ { true, 0x028f, 0x028f }, +/* 0x0290 */ { true, 0x0290, 0x0290 }, +/* 0x0291 */ { true, 0x0291, 0x0291 }, +/* 0x0292 */ { true, 0x01b7, 0x0292 }, +/* 0x0293 */ { true, 0x0293, 0x0293 }, +/* 0x0294 */ { true, 0x0241, 0x0294 }, +/* 0x0295 */ { true, 0x0295, 0x0295 }, +/* 0x0296 */ { true, 0x0296, 0x0296 }, +/* 0x0297 */ { true, 0x0297, 0x0297 }, +/* 0x0298 */ { true, 0x0298, 0x0298 }, +/* 0x0299 */ { true, 0x0299, 0x0299 }, +/* 0x029a */ { true, 0x029a, 0x029a }, +/* 0x029b */ { true, 0x029b, 0x029b }, +/* 0x029c */ { true, 0x029c, 0x029c }, +/* 0x029d */ { true, 0x029d, 0x029d }, +/* 0x029e */ { true, 0x029e, 0x029e }, +/* 0x029f */ { true, 0x029f, 0x029f }, +/* 0x02a0 */ { true, 0x02a0, 0x02a0 }, +/* 0x02a1 */ { true, 0x02a1, 0x02a1 }, +/* 0x02a2 */ { true, 0x02a2, 0x02a2 }, +/* 0x02a3 */ { true, 0x02a3, 0x02a3 }, +/* 0x02a4 */ { true, 0x02a4, 0x02a4 }, +/* 0x02a5 */ { true, 0x02a5, 0x02a5 }, +/* 0x02a6 */ { true, 0x02a6, 0x02a6 }, +/* 0x02a7 */ { true, 0x02a7, 0x02a7 }, +/* 0x02a8 */ { true, 0x02a8, 0x02a8 }, +/* 0x02a9 */ { true, 0x02a9, 0x02a9 }, +/* 0x02aa */ { true, 0x02aa, 0x02aa }, +/* 0x02ab */ { true, 0x02ab, 0x02ab }, +/* 0x02ac */ { true, 0x02ac, 0x02ac }, +/* 0x02ad */ { true, 0x02ad, 0x02ad }, +/* 0x02ae */ { true, 0x02ae, 0x02ae }, +/* 0x02af */ { true, 0x02af, 0x02af }, +/* 0x02b0 */ { true, 0x02b0, 0x02b0 }, +/* 0x02b1 */ { true, 0x02b1, 0x02b1 }, +/* 0x02b2 */ { true, 0x02b2, 0x02b2 }, +/* 0x02b3 */ { true, 0x02b3, 0x02b3 }, +/* 0x02b4 */ { true, 0x02b4, 0x02b4 }, +/* 0x02b5 */ { true, 0x02b5, 0x02b5 }, +/* 0x02b6 */ { true, 0x02b6, 0x02b6 }, +/* 0x02b7 */ { true, 0x02b7, 0x02b7 }, +/* 0x02b8 */ { true, 0x02b8, 0x02b8 }, +/* 0x02b9 */ { true, 0x02b9, 0x02b9 }, +/* 0x02ba */ { true, 0x02ba, 0x02ba }, +/* 0x02bb */ { true, 0x02bb, 0x02bb }, +/* 0x02bc */ { true, 0x02bc, 0x02bc }, +/* 0x02bd */ { true, 0x02bd, 0x02bd }, +/* 0x02be */ { true, 0x02be, 0x02be }, +/* 0x02bf */ { true, 0x02bf, 0x02bf }, +/* 0x02c0 */ { true, 0x02c0, 0x02c0 }, +/* 0x02c1 */ { true, 0x02c1, 0x02c1 }, +/* 0x02c2 */ { false, 0x02c2, 0x02c2 }, +/* 0x02c3 */ { false, 0x02c3, 0x02c3 }, +/* 0x02c4 */ { false, 0x02c4, 0x02c4 }, +/* 0x02c5 */ { false, 0x02c5, 0x02c5 }, +/* 0x02c6 */ { true, 0x02c6, 0x02c6 }, +/* 0x02c7 */ { true, 0x02c7, 0x02c7 }, +/* 0x02c8 */ { true, 0x02c8, 0x02c8 }, +/* 0x02c9 */ { true, 0x02c9, 0x02c9 }, +/* 0x02ca */ { true, 0x02ca, 0x02ca }, +/* 0x02cb */ { true, 0x02cb, 0x02cb }, +/* 0x02cc */ { true, 0x02cc, 0x02cc }, +/* 0x02cd */ { true, 0x02cd, 0x02cd }, +/* 0x02ce */ { true, 0x02ce, 0x02ce }, +/* 0x02cf */ { true, 0x02cf, 0x02cf }, +/* 0x02d0 */ { true, 0x02d0, 0x02d0 }, +/* 0x02d1 */ { true, 0x02d1, 0x02d1 }, +/* 0x02d2 */ { false, 0x02d2, 0x02d2 }, +/* 0x02d3 */ { false, 0x02d3, 0x02d3 }, +/* 0x02d4 */ { false, 0x02d4, 0x02d4 }, +/* 0x02d5 */ { false, 0x02d5, 0x02d5 }, +/* 0x02d6 */ { false, 0x02d6, 0x02d6 }, +/* 0x02d7 */ { false, 0x02d7, 0x02d7 }, +/* 0x02d8 */ { false, 0x02d8, 0x02d8 }, +/* 0x02d9 */ { false, 0x02d9, 0x02d9 }, +/* 0x02da */ { false, 0x02da, 0x02da }, +/* 0x02db */ { false, 0x02db, 0x02db }, +/* 0x02dc */ { false, 0x02dc, 0x02dc }, +/* 0x02dd */ { false, 0x02dd, 0x02dd }, +/* 0x02de */ { false, 0x02de, 0x02de }, +/* 0x02df */ { false, 0x02df, 0x02df }, +/* 0x02e0 */ { true, 0x02e0, 0x02e0 }, +/* 0x02e1 */ { true, 0x02e1, 0x02e1 }, +/* 0x02e2 */ { true, 0x02e2, 0x02e2 }, +/* 0x02e3 */ { true, 0x02e3, 0x02e3 }, +/* 0x02e4 */ { true, 0x02e4, 0x02e4 }, +/* 0x02e5 */ { false, 0x02e5, 0x02e5 }, +/* 0x02e6 */ { false, 0x02e6, 0x02e6 }, +/* 0x02e7 */ { false, 0x02e7, 0x02e7 }, +/* 0x02e8 */ { false, 0x02e8, 0x02e8 }, +/* 0x02e9 */ { false, 0x02e9, 0x02e9 }, +/* 0x02ea */ { false, 0x02ea, 0x02ea }, +/* 0x02eb */ { false, 0x02eb, 0x02eb }, +/* 0x02ec */ { false, 0x02ec, 0x02ec }, +/* 0x02ed */ { false, 0x02ed, 0x02ed }, +/* 0x02ee */ { true, 0x02ee, 0x02ee }, +/* 0x02ef */ { false, 0x02ef, 0x02ef }, +/* 0x02f0 */ { false, 0x02f0, 0x02f0 }, +/* 0x02f1 */ { false, 0x02f1, 0x02f1 }, +/* 0x02f2 */ { false, 0x02f2, 0x02f2 }, +/* 0x02f3 */ { false, 0x02f3, 0x02f3 }, +/* 0x02f4 */ { false, 0x02f4, 0x02f4 }, +/* 0x02f5 */ { false, 0x02f5, 0x02f5 }, +/* 0x02f6 */ { false, 0x02f6, 0x02f6 }, +/* 0x02f7 */ { false, 0x02f7, 0x02f7 }, +/* 0x02f8 */ { false, 0x02f8, 0x02f8 }, +/* 0x02f9 */ { false, 0x02f9, 0x02f9 }, +/* 0x02fa */ { false, 0x02fa, 0x02fa }, +/* 0x02fb */ { false, 0x02fb, 0x02fb }, +/* 0x02fc */ { false, 0x02fc, 0x02fc }, +/* 0x02fd */ { false, 0x02fd, 0x02fd }, +/* 0x02fe */ { false, 0x02fe, 0x02fe }, +/* 0x02ff */ { false, 0x02ff, 0x02ff }, +/* 0x0300 */ { true, 0x0300, 0x0300 }, +/* 0x0301 */ { true, 0x0301, 0x0301 }, +/* 0x0302 */ { true, 0x0302, 0x0302 }, +/* 0x0303 */ { true, 0x0303, 0x0303 }, +/* 0x0304 */ { true, 0x0304, 0x0304 }, +/* 0x0305 */ { true, 0x0305, 0x0305 }, +/* 0x0306 */ { true, 0x0306, 0x0306 }, +/* 0x0307 */ { true, 0x0307, 0x0307 }, +/* 0x0308 */ { true, 0x0308, 0x0308 }, +/* 0x0309 */ { true, 0x0309, 0x0309 }, +/* 0x030a */ { true, 0x030a, 0x030a }, +/* 0x030b */ { true, 0x030b, 0x030b }, +/* 0x030c */ { true, 0x030c, 0x030c }, +/* 0x030d */ { true, 0x030d, 0x030d }, +/* 0x030e */ { true, 0x030e, 0x030e }, +/* 0x030f */ { true, 0x030f, 0x030f }, +/* 0x0310 */ { true, 0x0310, 0x0310 }, +/* 0x0311 */ { true, 0x0311, 0x0311 }, +/* 0x0312 */ { true, 0x0312, 0x0312 }, +/* 0x0313 */ { true, 0x0313, 0x0313 }, +/* 0x0314 */ { true, 0x0314, 0x0314 }, +/* 0x0315 */ { true, 0x0315, 0x0315 }, +/* 0x0316 */ { true, 0x0316, 0x0316 }, +/* 0x0317 */ { true, 0x0317, 0x0317 }, +/* 0x0318 */ { true, 0x0318, 0x0318 }, +/* 0x0319 */ { true, 0x0319, 0x0319 }, +/* 0x031a */ { true, 0x031a, 0x031a }, +/* 0x031b */ { true, 0x031b, 0x031b }, +/* 0x031c */ { true, 0x031c, 0x031c }, +/* 0x031d */ { true, 0x031d, 0x031d }, +/* 0x031e */ { true, 0x031e, 0x031e }, +/* 0x031f */ { true, 0x031f, 0x031f }, +/* 0x0320 */ { true, 0x0320, 0x0320 }, +/* 0x0321 */ { true, 0x0321, 0x0321 }, +/* 0x0322 */ { true, 0x0322, 0x0322 }, +/* 0x0323 */ { true, 0x0323, 0x0323 }, +/* 0x0324 */ { true, 0x0324, 0x0324 }, +/* 0x0325 */ { true, 0x0325, 0x0325 }, +/* 0x0326 */ { true, 0x0326, 0x0326 }, +/* 0x0327 */ { true, 0x0327, 0x0327 }, +/* 0x0328 */ { true, 0x0328, 0x0328 }, +/* 0x0329 */ { true, 0x0329, 0x0329 }, +/* 0x032a */ { true, 0x032a, 0x032a }, +/* 0x032b */ { true, 0x032b, 0x032b }, +/* 0x032c */ { true, 0x032c, 0x032c }, +/* 0x032d */ { true, 0x032d, 0x032d }, +/* 0x032e */ { true, 0x032e, 0x032e }, +/* 0x032f */ { true, 0x032f, 0x032f }, +/* 0x0330 */ { true, 0x0330, 0x0330 }, +/* 0x0331 */ { true, 0x0331, 0x0331 }, +/* 0x0332 */ { true, 0x0332, 0x0332 }, +/* 0x0333 */ { true, 0x0333, 0x0333 }, +/* 0x0334 */ { true, 0x0334, 0x0334 }, +/* 0x0335 */ { true, 0x0335, 0x0335 }, +/* 0x0336 */ { true, 0x0336, 0x0336 }, +/* 0x0337 */ { true, 0x0337, 0x0337 }, +/* 0x0338 */ { true, 0x0338, 0x0338 }, +/* 0x0339 */ { true, 0x0339, 0x0339 }, +/* 0x033a */ { true, 0x033a, 0x033a }, +/* 0x033b */ { true, 0x033b, 0x033b }, +/* 0x033c */ { true, 0x033c, 0x033c }, +/* 0x033d */ { true, 0x033d, 0x033d }, +/* 0x033e */ { true, 0x033e, 0x033e }, +/* 0x033f */ { true, 0x033f, 0x033f }, +/* 0x0340 */ { true, 0x0340, 0x0340 }, +/* 0x0341 */ { true, 0x0341, 0x0341 }, +/* 0x0342 */ { true, 0x0342, 0x0342 }, +/* 0x0343 */ { true, 0x0343, 0x0343 }, +/* 0x0344 */ { true, 0x0344, 0x0344 }, +/* 0x0345 */ { true, 0x0399, 0x0345 }, +/* 0x0346 */ { true, 0x0346, 0x0346 }, +/* 0x0347 */ { true, 0x0347, 0x0347 }, +/* 0x0348 */ { true, 0x0348, 0x0348 }, +/* 0x0349 */ { true, 0x0349, 0x0349 }, +/* 0x034a */ { true, 0x034a, 0x034a }, +/* 0x034b */ { true, 0x034b, 0x034b }, +/* 0x034c */ { true, 0x034c, 0x034c }, +/* 0x034d */ { true, 0x034d, 0x034d }, +/* 0x034e */ { true, 0x034e, 0x034e }, +/* 0x034f */ { true, 0x034f, 0x034f }, +/* 0x0350 */ { true, 0x0350, 0x0350 }, +/* 0x0351 */ { true, 0x0351, 0x0351 }, +/* 0x0352 */ { true, 0x0352, 0x0352 }, +/* 0x0353 */ { true, 0x0353, 0x0353 }, +/* 0x0354 */ { true, 0x0354, 0x0354 }, +/* 0x0355 */ { true, 0x0355, 0x0355 }, +/* 0x0356 */ { true, 0x0356, 0x0356 }, +/* 0x0357 */ { true, 0x0357, 0x0357 }, +/* 0x0358 */ { true, 0x0358, 0x0358 }, +/* 0x0359 */ { true, 0x0359, 0x0359 }, +/* 0x035a */ { true, 0x035a, 0x035a }, +/* 0x035b */ { true, 0x035b, 0x035b }, +/* 0x035c */ { true, 0x035c, 0x035c }, +/* 0x035d */ { true, 0x035d, 0x035d }, +/* 0x035e */ { true, 0x035e, 0x035e }, +/* 0x035f */ { true, 0x035f, 0x035f }, +/* 0x0360 */ { true, 0x0360, 0x0360 }, +/* 0x0361 */ { true, 0x0361, 0x0361 }, +/* 0x0362 */ { true, 0x0362, 0x0362 }, +/* 0x0363 */ { true, 0x0363, 0x0363 }, +/* 0x0364 */ { true, 0x0364, 0x0364 }, +/* 0x0365 */ { true, 0x0365, 0x0365 }, +/* 0x0366 */ { true, 0x0366, 0x0366 }, +/* 0x0367 */ { true, 0x0367, 0x0367 }, +/* 0x0368 */ { true, 0x0368, 0x0368 }, +/* 0x0369 */ { true, 0x0369, 0x0369 }, +/* 0x036a */ { true, 0x036a, 0x036a }, +/* 0x036b */ { true, 0x036b, 0x036b }, +/* 0x036c */ { true, 0x036c, 0x036c }, +/* 0x036d */ { true, 0x036d, 0x036d }, +/* 0x036e */ { true, 0x036e, 0x036e }, +/* 0x036f */ { true, 0x036f, 0x036f }, +/* 0x0370 */ { false, 0x0370, 0x0370 }, +/* 0x0371 */ { false, 0x0371, 0x0371 }, +/* 0x0372 */ { false, 0x0372, 0x0372 }, +/* 0x0373 */ { false, 0x0373, 0x0373 }, +/* 0x0374 */ { false, 0x0374, 0x0374 }, +/* 0x0375 */ { false, 0x0375, 0x0375 }, +/* 0x0376 */ { false, 0x0376, 0x0376 }, +/* 0x0377 */ { false, 0x0377, 0x0377 }, +/* 0x0378 */ { false, 0x0378, 0x0378 }, +/* 0x0379 */ { false, 0x0379, 0x0379 }, +/* 0x037a */ { true, 0x037a, 0x037a }, +/* 0x037b */ { false, 0x037b, 0x037b }, +/* 0x037c */ { false, 0x037c, 0x037c }, +/* 0x037d */ { false, 0x037d, 0x037d }, +/* 0x037e */ { false, 0x037e, 0x037e }, +/* 0x037f */ { false, 0x037f, 0x037f }, +/* 0x0380 */ { false, 0x0380, 0x0380 }, +/* 0x0381 */ { false, 0x0381, 0x0381 }, +/* 0x0382 */ { false, 0x0382, 0x0382 }, +/* 0x0383 */ { false, 0x0383, 0x0383 }, +/* 0x0384 */ { false, 0x0384, 0x0384 }, +/* 0x0385 */ { false, 0x0385, 0x0385 }, +/* 0x0386 */ { true, 0x0386, 0x03ac }, +/* 0x0387 */ { false, 0x0387, 0x0387 }, +/* 0x0388 */ { true, 0x0388, 0x03ad }, +/* 0x0389 */ { true, 0x0389, 0x03ae }, +/* 0x038a */ { true, 0x038a, 0x03af }, +/* 0x038b */ { false, 0x038b, 0x038b }, +/* 0x038c */ { true, 0x038c, 0x03cc }, +/* 0x038d */ { false, 0x038d, 0x038d }, +/* 0x038e */ { true, 0x038e, 0x03cd }, +/* 0x038f */ { true, 0x038f, 0x03ce }, +/* 0x0390 */ { true, 0x0390, 0x0390 }, +/* 0x0391 */ { true, 0x0391, 0x03b1 }, +/* 0x0392 */ { true, 0x0392, 0x03b2 }, +/* 0x0393 */ { true, 0x0393, 0x03b3 }, +/* 0x0394 */ { true, 0x0394, 0x03b4 }, +/* 0x0395 */ { true, 0x0395, 0x03b5 }, +/* 0x0396 */ { true, 0x0396, 0x03b6 }, +/* 0x0397 */ { true, 0x0397, 0x03b7 }, +/* 0x0398 */ { true, 0x0398, 0x03b8 }, +/* 0x0399 */ { true, 0x0399, 0x03b9 }, +/* 0x039a */ { true, 0x039a, 0x03ba }, +/* 0x039b */ { true, 0x039b, 0x03bb }, +/* 0x039c */ { true, 0x039c, 0x03bc }, +/* 0x039d */ { true, 0x039d, 0x03bd }, +/* 0x039e */ { true, 0x039e, 0x03be }, +/* 0x039f */ { true, 0x039f, 0x03bf }, +/* 0x03a0 */ { true, 0x03a0, 0x03c0 }, +/* 0x03a1 */ { true, 0x03a1, 0x03c1 }, +/* 0x03a2 */ { false, 0x03a2, 0x03a2 }, +/* 0x03a3 */ { true, 0x03a3, 0x03c3 }, +/* 0x03a4 */ { true, 0x03a4, 0x03c4 }, +/* 0x03a5 */ { true, 0x03a5, 0x03c5 }, +/* 0x03a6 */ { true, 0x03a6, 0x03c6 }, +/* 0x03a7 */ { true, 0x03a7, 0x03c7 }, +/* 0x03a8 */ { true, 0x03a8, 0x03c8 }, +/* 0x03a9 */ { true, 0x03a9, 0x03c9 }, +/* 0x03aa */ { true, 0x03aa, 0x03ca }, +/* 0x03ab */ { true, 0x03ab, 0x03cb }, +/* 0x03ac */ { true, 0x0386, 0x03ac }, +/* 0x03ad */ { true, 0x0388, 0x03ad }, +/* 0x03ae */ { true, 0x0389, 0x03ae }, +/* 0x03af */ { true, 0x038a, 0x03af }, +/* 0x03b0 */ { true, 0x03b0, 0x03b0 }, +/* 0x03b1 */ { true, 0x0391, 0x03b1 }, +/* 0x03b2 */ { true, 0x0392, 0x03b2 }, +/* 0x03b3 */ { true, 0x0393, 0x03b3 }, +/* 0x03b4 */ { true, 0x0394, 0x03b4 }, +/* 0x03b5 */ { true, 0x0395, 0x03b5 }, +/* 0x03b6 */ { true, 0x0396, 0x03b6 }, +/* 0x03b7 */ { true, 0x0397, 0x03b7 }, +/* 0x03b8 */ { true, 0x0398, 0x03b8 }, +/* 0x03b9 */ { true, 0x0399, 0x03b9 }, +/* 0x03ba */ { true, 0x039a, 0x03ba }, +/* 0x03bb */ { true, 0x039b, 0x03bb }, +/* 0x03bc */ { true, 0x039c, 0x03bc }, +/* 0x03bd */ { true, 0x039d, 0x03bd }, +/* 0x03be */ { true, 0x039e, 0x03be }, +/* 0x03bf */ { true, 0x039f, 0x03bf }, +/* 0x03c0 */ { true, 0x03a0, 0x03c0 }, +/* 0x03c1 */ { true, 0x03a1, 0x03c1 }, +/* 0x03c2 */ { true, 0x03a3, 0x03c2 }, +/* 0x03c3 */ { true, 0x03a3, 0x03c3 }, +/* 0x03c4 */ { true, 0x03a4, 0x03c4 }, +/* 0x03c5 */ { true, 0x03a5, 0x03c5 }, +/* 0x03c6 */ { true, 0x03a6, 0x03c6 }, +/* 0x03c7 */ { true, 0x03a7, 0x03c7 }, +/* 0x03c8 */ { true, 0x03a8, 0x03c8 }, +/* 0x03c9 */ { true, 0x03a9, 0x03c9 }, +/* 0x03ca */ { true, 0x03aa, 0x03ca }, +/* 0x03cb */ { true, 0x03ab, 0x03cb }, +/* 0x03cc */ { true, 0x038c, 0x03cc }, +/* 0x03cd */ { true, 0x038e, 0x03cd }, +/* 0x03ce */ { true, 0x038f, 0x03ce }, +/* 0x03cf */ { false, 0x03cf, 0x03cf }, +/* 0x03d0 */ { true, 0x0392, 0x03d0 }, +/* 0x03d1 */ { true, 0x0398, 0x03d1 }, +/* 0x03d2 */ { true, 0x03d2, 0x03d2 }, +/* 0x03d3 */ { true, 0x03d3, 0x03d3 }, +/* 0x03d4 */ { true, 0x03d4, 0x03d4 }, +/* 0x03d5 */ { true, 0x03a6, 0x03d5 }, +/* 0x03d6 */ { true, 0x03a0, 0x03d6 }, +/* 0x03d7 */ { true, 0x03d7, 0x03d7 }, +/* 0x03d8 */ { true, 0x03d8, 0x03d9 }, +/* 0x03d9 */ { true, 0x03d8, 0x03d9 }, +/* 0x03da */ { true, 0x03da, 0x03db }, +/* 0x03db */ { true, 0x03da, 0x03db }, +/* 0x03dc */ { true, 0x03dc, 0x03dd }, +/* 0x03dd */ { true, 0x03dc, 0x03dd }, +/* 0x03de */ { true, 0x03de, 0x03df }, +/* 0x03df */ { true, 0x03de, 0x03df }, +/* 0x03e0 */ { true, 0x03e0, 0x03e1 }, +/* 0x03e1 */ { true, 0x03e0, 0x03e1 }, +/* 0x03e2 */ { true, 0x03e2, 0x03e3 }, +/* 0x03e3 */ { true, 0x03e2, 0x03e3 }, +/* 0x03e4 */ { true, 0x03e4, 0x03e5 }, +/* 0x03e5 */ { true, 0x03e4, 0x03e5 }, +/* 0x03e6 */ { true, 0x03e6, 0x03e7 }, +/* 0x03e7 */ { true, 0x03e6, 0x03e7 }, +/* 0x03e8 */ { true, 0x03e8, 0x03e9 }, +/* 0x03e9 */ { true, 0x03e8, 0x03e9 }, +/* 0x03ea */ { true, 0x03ea, 0x03eb }, +/* 0x03eb */ { true, 0x03ea, 0x03eb }, +/* 0x03ec */ { true, 0x03ec, 0x03ed }, +/* 0x03ed */ { true, 0x03ec, 0x03ed }, +/* 0x03ee */ { true, 0x03ee, 0x03ef }, +/* 0x03ef */ { true, 0x03ee, 0x03ef }, +/* 0x03f0 */ { true, 0x039a, 0x03f0 }, +/* 0x03f1 */ { true, 0x03a1, 0x03f1 }, +/* 0x03f2 */ { true, 0x03f9, 0x03f2 }, +/* 0x03f3 */ { true, 0x03f3, 0x03f3 }, +/* 0x03f4 */ { true, 0x03f4, 0x03b8 }, +/* 0x03f5 */ { true, 0x0395, 0x03f5 }, +/* 0x03f6 */ { false, 0x03f6, 0x03f6 }, +/* 0x03f7 */ { true, 0x03f7, 0x03f8 }, +/* 0x03f8 */ { true, 0x03f7, 0x03f8 }, +/* 0x03f9 */ { true, 0x03f9, 0x03f2 }, +/* 0x03fa */ { true, 0x03fa, 0x03fb }, +/* 0x03fb */ { true, 0x03fa, 0x03fb }, +/* 0x03fc */ { true, 0x03fc, 0x03fc }, +/* 0x03fd */ { true, 0x03fd, 0x03fd }, +/* 0x03fe */ { true, 0x03fe, 0x03fe }, +/* 0x03ff */ { true, 0x03ff, 0x03ff }, +/* 0x0400 */ { true, 0x0400, 0x0450 }, +/* 0x0401 */ { true, 0x0401, 0x0451 }, +/* 0x0402 */ { true, 0x0402, 0x0452 }, +/* 0x0403 */ { true, 0x0403, 0x0453 }, +/* 0x0404 */ { true, 0x0404, 0x0454 }, +/* 0x0405 */ { true, 0x0405, 0x0455 }, +/* 0x0406 */ { true, 0x0406, 0x0456 }, +/* 0x0407 */ { true, 0x0407, 0x0457 }, +/* 0x0408 */ { true, 0x0408, 0x0458 }, +/* 0x0409 */ { true, 0x0409, 0x0459 }, +/* 0x040a */ { true, 0x040a, 0x045a }, +/* 0x040b */ { true, 0x040b, 0x045b }, +/* 0x040c */ { true, 0x040c, 0x045c }, +/* 0x040d */ { true, 0x040d, 0x045d }, +/* 0x040e */ { true, 0x040e, 0x045e }, +/* 0x040f */ { true, 0x040f, 0x045f }, +/* 0x0410 */ { true, 0x0410, 0x0430 }, +/* 0x0411 */ { true, 0x0411, 0x0431 }, +/* 0x0412 */ { true, 0x0412, 0x0432 }, +/* 0x0413 */ { true, 0x0413, 0x0433 }, +/* 0x0414 */ { true, 0x0414, 0x0434 }, +/* 0x0415 */ { true, 0x0415, 0x0435 }, +/* 0x0416 */ { true, 0x0416, 0x0436 }, +/* 0x0417 */ { true, 0x0417, 0x0437 }, +/* 0x0418 */ { true, 0x0418, 0x0438 }, +/* 0x0419 */ { true, 0x0419, 0x0439 }, +/* 0x041a */ { true, 0x041a, 0x043a }, +/* 0x041b */ { true, 0x041b, 0x043b }, +/* 0x041c */ { true, 0x041c, 0x043c }, +/* 0x041d */ { true, 0x041d, 0x043d }, +/* 0x041e */ { true, 0x041e, 0x043e }, +/* 0x041f */ { true, 0x041f, 0x043f }, +/* 0x0420 */ { true, 0x0420, 0x0440 }, +/* 0x0421 */ { true, 0x0421, 0x0441 }, +/* 0x0422 */ { true, 0x0422, 0x0442 }, +/* 0x0423 */ { true, 0x0423, 0x0443 }, +/* 0x0424 */ { true, 0x0424, 0x0444 }, +/* 0x0425 */ { true, 0x0425, 0x0445 }, +/* 0x0426 */ { true, 0x0426, 0x0446 }, +/* 0x0427 */ { true, 0x0427, 0x0447 }, +/* 0x0428 */ { true, 0x0428, 0x0448 }, +/* 0x0429 */ { true, 0x0429, 0x0449 }, +/* 0x042a */ { true, 0x042a, 0x044a }, +/* 0x042b */ { true, 0x042b, 0x044b }, +/* 0x042c */ { true, 0x042c, 0x044c }, +/* 0x042d */ { true, 0x042d, 0x044d }, +/* 0x042e */ { true, 0x042e, 0x044e }, +/* 0x042f */ { true, 0x042f, 0x044f }, +/* 0x0430 */ { true, 0x0410, 0x0430 }, +/* 0x0431 */ { true, 0x0411, 0x0431 }, +/* 0x0432 */ { true, 0x0412, 0x0432 }, +/* 0x0433 */ { true, 0x0413, 0x0433 }, +/* 0x0434 */ { true, 0x0414, 0x0434 }, +/* 0x0435 */ { true, 0x0415, 0x0435 }, +/* 0x0436 */ { true, 0x0416, 0x0436 }, +/* 0x0437 */ { true, 0x0417, 0x0437 }, +/* 0x0438 */ { true, 0x0418, 0x0438 }, +/* 0x0439 */ { true, 0x0419, 0x0439 }, +/* 0x043a */ { true, 0x041a, 0x043a }, +/* 0x043b */ { true, 0x041b, 0x043b }, +/* 0x043c */ { true, 0x041c, 0x043c }, +/* 0x043d */ { true, 0x041d, 0x043d }, +/* 0x043e */ { true, 0x041e, 0x043e }, +/* 0x043f */ { true, 0x041f, 0x043f }, +/* 0x0440 */ { true, 0x0420, 0x0440 }, +/* 0x0441 */ { true, 0x0421, 0x0441 }, +/* 0x0442 */ { true, 0x0422, 0x0442 }, +/* 0x0443 */ { true, 0x0423, 0x0443 }, +/* 0x0444 */ { true, 0x0424, 0x0444 }, +/* 0x0445 */ { true, 0x0425, 0x0445 }, +/* 0x0446 */ { true, 0x0426, 0x0446 }, +/* 0x0447 */ { true, 0x0427, 0x0447 }, +/* 0x0448 */ { true, 0x0428, 0x0448 }, +/* 0x0449 */ { true, 0x0429, 0x0449 }, +/* 0x044a */ { true, 0x042a, 0x044a }, +/* 0x044b */ { true, 0x042b, 0x044b }, +/* 0x044c */ { true, 0x042c, 0x044c }, +/* 0x044d */ { true, 0x042d, 0x044d }, +/* 0x044e */ { true, 0x042e, 0x044e }, +/* 0x044f */ { true, 0x042f, 0x044f }, +/* 0x0450 */ { true, 0x0400, 0x0450 }, +/* 0x0451 */ { true, 0x0401, 0x0451 }, +/* 0x0452 */ { true, 0x0402, 0x0452 }, +/* 0x0453 */ { true, 0x0403, 0x0453 }, +/* 0x0454 */ { true, 0x0404, 0x0454 }, +/* 0x0455 */ { true, 0x0405, 0x0455 }, +/* 0x0456 */ { true, 0x0406, 0x0456 }, +/* 0x0457 */ { true, 0x0407, 0x0457 }, +/* 0x0458 */ { true, 0x0408, 0x0458 }, +/* 0x0459 */ { true, 0x0409, 0x0459 }, +/* 0x045a */ { true, 0x040a, 0x045a }, +/* 0x045b */ { true, 0x040b, 0x045b }, +/* 0x045c */ { true, 0x040c, 0x045c }, +/* 0x045d */ { true, 0x040d, 0x045d }, +/* 0x045e */ { true, 0x040e, 0x045e }, +/* 0x045f */ { true, 0x040f, 0x045f }, +/* 0x0460 */ { true, 0x0460, 0x0461 }, +/* 0x0461 */ { true, 0x0460, 0x0461 }, +/* 0x0462 */ { true, 0x0462, 0x0463 }, +/* 0x0463 */ { true, 0x0462, 0x0463 }, +/* 0x0464 */ { true, 0x0464, 0x0465 }, +/* 0x0465 */ { true, 0x0464, 0x0465 }, +/* 0x0466 */ { true, 0x0466, 0x0467 }, +/* 0x0467 */ { true, 0x0466, 0x0467 }, +/* 0x0468 */ { true, 0x0468, 0x0469 }, +/* 0x0469 */ { true, 0x0468, 0x0469 }, +/* 0x046a */ { true, 0x046a, 0x046b }, +/* 0x046b */ { true, 0x046a, 0x046b }, +/* 0x046c */ { true, 0x046c, 0x046d }, +/* 0x046d */ { true, 0x046c, 0x046d }, +/* 0x046e */ { true, 0x046e, 0x046f }, +/* 0x046f */ { true, 0x046e, 0x046f }, +/* 0x0470 */ { true, 0x0470, 0x0471 }, +/* 0x0471 */ { true, 0x0470, 0x0471 }, +/* 0x0472 */ { true, 0x0472, 0x0473 }, +/* 0x0473 */ { true, 0x0472, 0x0473 }, +/* 0x0474 */ { true, 0x0474, 0x0475 }, +/* 0x0475 */ { true, 0x0474, 0x0475 }, +/* 0x0476 */ { true, 0x0476, 0x0477 }, +/* 0x0477 */ { true, 0x0476, 0x0477 }, +/* 0x0478 */ { true, 0x0478, 0x0479 }, +/* 0x0479 */ { true, 0x0478, 0x0479 }, +/* 0x047a */ { true, 0x047a, 0x047b }, +/* 0x047b */ { true, 0x047a, 0x047b }, +/* 0x047c */ { true, 0x047c, 0x047d }, +/* 0x047d */ { true, 0x047c, 0x047d }, +/* 0x047e */ { true, 0x047e, 0x047f }, +/* 0x047f */ { true, 0x047e, 0x047f }, +/* 0x0480 */ { true, 0x0480, 0x0481 }, +/* 0x0481 */ { true, 0x0480, 0x0481 }, +/* 0x0482 */ { false, 0x0482, 0x0482 }, +/* 0x0483 */ { true, 0x0483, 0x0483 }, +/* 0x0484 */ { true, 0x0484, 0x0484 }, +/* 0x0485 */ { true, 0x0485, 0x0485 }, +/* 0x0486 */ { true, 0x0486, 0x0486 }, +/* 0x0487 */ { false, 0x0487, 0x0487 }, +/* 0x0488 */ { false, 0x0488, 0x0488 }, +/* 0x0489 */ { false, 0x0489, 0x0489 }, +/* 0x048a */ { true, 0x048a, 0x048b }, +/* 0x048b */ { true, 0x048a, 0x048b }, +/* 0x048c */ { true, 0x048c, 0x048d }, +/* 0x048d */ { true, 0x048c, 0x048d }, +/* 0x048e */ { true, 0x048e, 0x048f }, +/* 0x048f */ { true, 0x048e, 0x048f }, +/* 0x0490 */ { true, 0x0490, 0x0491 }, +/* 0x0491 */ { true, 0x0490, 0x0491 }, +/* 0x0492 */ { true, 0x0492, 0x0493 }, +/* 0x0493 */ { true, 0x0492, 0x0493 }, +/* 0x0494 */ { true, 0x0494, 0x0495 }, +/* 0x0495 */ { true, 0x0494, 0x0495 }, +/* 0x0496 */ { true, 0x0496, 0x0497 }, +/* 0x0497 */ { true, 0x0496, 0x0497 }, +/* 0x0498 */ { true, 0x0498, 0x0499 }, +/* 0x0499 */ { true, 0x0498, 0x0499 }, +/* 0x049a */ { true, 0x049a, 0x049b }, +/* 0x049b */ { true, 0x049a, 0x049b }, +/* 0x049c */ { true, 0x049c, 0x049d }, +/* 0x049d */ { true, 0x049c, 0x049d }, +/* 0x049e */ { true, 0x049e, 0x049f }, +/* 0x049f */ { true, 0x049e, 0x049f }, +/* 0x04a0 */ { true, 0x04a0, 0x04a1 }, +/* 0x04a1 */ { true, 0x04a0, 0x04a1 }, +/* 0x04a2 */ { true, 0x04a2, 0x04a3 }, +/* 0x04a3 */ { true, 0x04a2, 0x04a3 }, +/* 0x04a4 */ { true, 0x04a4, 0x04a5 }, +/* 0x04a5 */ { true, 0x04a4, 0x04a5 }, +/* 0x04a6 */ { true, 0x04a6, 0x04a7 }, +/* 0x04a7 */ { true, 0x04a6, 0x04a7 }, +/* 0x04a8 */ { true, 0x04a8, 0x04a9 }, +/* 0x04a9 */ { true, 0x04a8, 0x04a9 }, +/* 0x04aa */ { true, 0x04aa, 0x04ab }, +/* 0x04ab */ { true, 0x04aa, 0x04ab }, +/* 0x04ac */ { true, 0x04ac, 0x04ad }, +/* 0x04ad */ { true, 0x04ac, 0x04ad }, +/* 0x04ae */ { true, 0x04ae, 0x04af }, +/* 0x04af */ { true, 0x04ae, 0x04af }, +/* 0x04b0 */ { true, 0x04b0, 0x04b1 }, +/* 0x04b1 */ { true, 0x04b0, 0x04b1 }, +/* 0x04b2 */ { true, 0x04b2, 0x04b3 }, +/* 0x04b3 */ { true, 0x04b2, 0x04b3 }, +/* 0x04b4 */ { true, 0x04b4, 0x04b5 }, +/* 0x04b5 */ { true, 0x04b4, 0x04b5 }, +/* 0x04b6 */ { true, 0x04b6, 0x04b7 }, +/* 0x04b7 */ { true, 0x04b6, 0x04b7 }, +/* 0x04b8 */ { true, 0x04b8, 0x04b9 }, +/* 0x04b9 */ { true, 0x04b8, 0x04b9 }, +/* 0x04ba */ { true, 0x04ba, 0x04bb }, +/* 0x04bb */ { true, 0x04ba, 0x04bb }, +/* 0x04bc */ { true, 0x04bc, 0x04bd }, +/* 0x04bd */ { true, 0x04bc, 0x04bd }, +/* 0x04be */ { true, 0x04be, 0x04bf }, +/* 0x04bf */ { true, 0x04be, 0x04bf }, +/* 0x04c0 */ { true, 0x04c0, 0x04c0 }, +/* 0x04c1 */ { true, 0x04c1, 0x04c2 }, +/* 0x04c2 */ { true, 0x04c1, 0x04c2 }, +/* 0x04c3 */ { true, 0x04c3, 0x04c4 }, +/* 0x04c4 */ { true, 0x04c3, 0x04c4 }, +/* 0x04c5 */ { true, 0x04c5, 0x04c6 }, +/* 0x04c6 */ { true, 0x04c5, 0x04c6 }, +/* 0x04c7 */ { true, 0x04c7, 0x04c8 }, +/* 0x04c8 */ { true, 0x04c7, 0x04c8 }, +/* 0x04c9 */ { true, 0x04c9, 0x04ca }, +/* 0x04ca */ { true, 0x04c9, 0x04ca }, +/* 0x04cb */ { true, 0x04cb, 0x04cc }, +/* 0x04cc */ { true, 0x04cb, 0x04cc }, +/* 0x04cd */ { true, 0x04cd, 0x04ce }, +/* 0x04ce */ { true, 0x04cd, 0x04ce }, +/* 0x04cf */ { false, 0x04cf, 0x04cf }, +/* 0x04d0 */ { true, 0x04d0, 0x04d1 }, +/* 0x04d1 */ { true, 0x04d0, 0x04d1 }, +/* 0x04d2 */ { true, 0x04d2, 0x04d3 }, +/* 0x04d3 */ { true, 0x04d2, 0x04d3 }, +/* 0x04d4 */ { true, 0x04d4, 0x04d5 }, +/* 0x04d5 */ { true, 0x04d4, 0x04d5 }, +/* 0x04d6 */ { true, 0x04d6, 0x04d7 }, +/* 0x04d7 */ { true, 0x04d6, 0x04d7 }, +/* 0x04d8 */ { true, 0x04d8, 0x04d9 }, +/* 0x04d9 */ { true, 0x04d8, 0x04d9 }, +/* 0x04da */ { true, 0x04da, 0x04db }, +/* 0x04db */ { true, 0x04da, 0x04db }, +/* 0x04dc */ { true, 0x04dc, 0x04dd }, +/* 0x04dd */ { true, 0x04dc, 0x04dd }, +/* 0x04de */ { true, 0x04de, 0x04df }, +/* 0x04df */ { true, 0x04de, 0x04df }, +/* 0x04e0 */ { true, 0x04e0, 0x04e1 }, +/* 0x04e1 */ { true, 0x04e0, 0x04e1 }, +/* 0x04e2 */ { true, 0x04e2, 0x04e3 }, +/* 0x04e3 */ { true, 0x04e2, 0x04e3 }, +/* 0x04e4 */ { true, 0x04e4, 0x04e5 }, +/* 0x04e5 */ { true, 0x04e4, 0x04e5 }, +/* 0x04e6 */ { true, 0x04e6, 0x04e7 }, +/* 0x04e7 */ { true, 0x04e6, 0x04e7 }, +/* 0x04e8 */ { true, 0x04e8, 0x04e9 }, +/* 0x04e9 */ { true, 0x04e8, 0x04e9 }, +/* 0x04ea */ { true, 0x04ea, 0x04eb }, +/* 0x04eb */ { true, 0x04ea, 0x04eb }, +/* 0x04ec */ { true, 0x04ec, 0x04ed }, +/* 0x04ed */ { true, 0x04ec, 0x04ed }, +/* 0x04ee */ { true, 0x04ee, 0x04ef }, +/* 0x04ef */ { true, 0x04ee, 0x04ef }, +/* 0x04f0 */ { true, 0x04f0, 0x04f1 }, +/* 0x04f1 */ { true, 0x04f0, 0x04f1 }, +/* 0x04f2 */ { true, 0x04f2, 0x04f3 }, +/* 0x04f3 */ { true, 0x04f2, 0x04f3 }, +/* 0x04f4 */ { true, 0x04f4, 0x04f5 }, +/* 0x04f5 */ { true, 0x04f4, 0x04f5 }, +/* 0x04f6 */ { true, 0x04f6, 0x04f7 }, +/* 0x04f7 */ { true, 0x04f6, 0x04f7 }, +/* 0x04f8 */ { true, 0x04f8, 0x04f9 }, +/* 0x04f9 */ { true, 0x04f8, 0x04f9 }, +/* 0x04fa */ { false, 0x04fa, 0x04fa }, +/* 0x04fb */ { false, 0x04fb, 0x04fb }, +/* 0x04fc */ { false, 0x04fc, 0x04fc }, +/* 0x04fd */ { false, 0x04fd, 0x04fd }, +/* 0x04fe */ { false, 0x04fe, 0x04fe }, +/* 0x04ff */ { false, 0x04ff, 0x04ff }, +/* 0x0500 */ { true, 0x0500, 0x0501 }, +/* 0x0501 */ { true, 0x0500, 0x0501 }, +/* 0x0502 */ { true, 0x0502, 0x0503 }, +/* 0x0503 */ { true, 0x0502, 0x0503 }, +/* 0x0504 */ { true, 0x0504, 0x0505 }, +/* 0x0505 */ { true, 0x0504, 0x0505 }, +/* 0x0506 */ { true, 0x0506, 0x0507 }, +/* 0x0507 */ { true, 0x0506, 0x0507 }, +/* 0x0508 */ { true, 0x0508, 0x0509 }, +/* 0x0509 */ { true, 0x0508, 0x0509 }, +/* 0x050a */ { true, 0x050a, 0x050b }, +/* 0x050b */ { true, 0x050a, 0x050b }, +/* 0x050c */ { true, 0x050c, 0x050d }, +/* 0x050d */ { true, 0x050c, 0x050d }, +/* 0x050e */ { true, 0x050e, 0x050f }, +/* 0x050f */ { true, 0x050e, 0x050f }, +/* 0x0510 */ { false, 0x0510, 0x0510 }, +/* 0x0511 */ { false, 0x0511, 0x0511 }, +/* 0x0512 */ { false, 0x0512, 0x0512 }, +/* 0x0513 */ { false, 0x0513, 0x0513 }, +/* 0x0514 */ { false, 0x0514, 0x0514 }, +/* 0x0515 */ { false, 0x0515, 0x0515 }, +/* 0x0516 */ { false, 0x0516, 0x0516 }, +/* 0x0517 */ { false, 0x0517, 0x0517 }, +/* 0x0518 */ { false, 0x0518, 0x0518 }, +/* 0x0519 */ { false, 0x0519, 0x0519 }, +/* 0x051a */ { false, 0x051a, 0x051a }, +/* 0x051b */ { false, 0x051b, 0x051b }, +/* 0x051c */ { false, 0x051c, 0x051c }, +/* 0x051d */ { false, 0x051d, 0x051d }, +/* 0x051e */ { false, 0x051e, 0x051e }, +/* 0x051f */ { false, 0x051f, 0x051f }, +/* 0x0520 */ { false, 0x0520, 0x0520 }, +/* 0x0521 */ { false, 0x0521, 0x0521 }, +/* 0x0522 */ { false, 0x0522, 0x0522 }, +/* 0x0523 */ { false, 0x0523, 0x0523 }, +/* 0x0524 */ { false, 0x0524, 0x0524 }, +/* 0x0525 */ { false, 0x0525, 0x0525 }, +/* 0x0526 */ { false, 0x0526, 0x0526 }, +/* 0x0527 */ { false, 0x0527, 0x0527 }, +/* 0x0528 */ { false, 0x0528, 0x0528 }, +/* 0x0529 */ { false, 0x0529, 0x0529 }, +/* 0x052a */ { false, 0x052a, 0x052a }, +/* 0x052b */ { false, 0x052b, 0x052b }, +/* 0x052c */ { false, 0x052c, 0x052c }, +/* 0x052d */ { false, 0x052d, 0x052d }, +/* 0x052e */ { false, 0x052e, 0x052e }, +/* 0x052f */ { false, 0x052f, 0x052f }, +/* 0x0530 */ { false, 0x0530, 0x0530 }, +/* 0x0531 */ { true, 0x0531, 0x0561 }, +/* 0x0532 */ { true, 0x0532, 0x0562 }, +/* 0x0533 */ { true, 0x0533, 0x0563 }, +/* 0x0534 */ { true, 0x0534, 0x0564 }, +/* 0x0535 */ { true, 0x0535, 0x0565 }, +/* 0x0536 */ { true, 0x0536, 0x0566 }, +/* 0x0537 */ { true, 0x0537, 0x0567 }, +/* 0x0538 */ { true, 0x0538, 0x0568 }, +/* 0x0539 */ { true, 0x0539, 0x0569 }, +/* 0x053a */ { true, 0x053a, 0x056a }, +/* 0x053b */ { true, 0x053b, 0x056b }, +/* 0x053c */ { true, 0x053c, 0x056c }, +/* 0x053d */ { true, 0x053d, 0x056d }, +/* 0x053e */ { true, 0x053e, 0x056e }, +/* 0x053f */ { true, 0x053f, 0x056f }, +/* 0x0540 */ { true, 0x0540, 0x0570 }, +/* 0x0541 */ { true, 0x0541, 0x0571 }, +/* 0x0542 */ { true, 0x0542, 0x0572 }, +/* 0x0543 */ { true, 0x0543, 0x0573 }, +/* 0x0544 */ { true, 0x0544, 0x0574 }, +/* 0x0545 */ { true, 0x0545, 0x0575 }, +/* 0x0546 */ { true, 0x0546, 0x0576 }, +/* 0x0547 */ { true, 0x0547, 0x0577 }, +/* 0x0548 */ { true, 0x0548, 0x0578 }, +/* 0x0549 */ { true, 0x0549, 0x0579 }, +/* 0x054a */ { true, 0x054a, 0x057a }, +/* 0x054b */ { true, 0x054b, 0x057b }, +/* 0x054c */ { true, 0x054c, 0x057c }, +/* 0x054d */ { true, 0x054d, 0x057d }, +/* 0x054e */ { true, 0x054e, 0x057e }, +/* 0x054f */ { true, 0x054f, 0x057f }, +/* 0x0550 */ { true, 0x0550, 0x0580 }, +/* 0x0551 */ { true, 0x0551, 0x0581 }, +/* 0x0552 */ { true, 0x0552, 0x0582 }, +/* 0x0553 */ { true, 0x0553, 0x0583 }, +/* 0x0554 */ { true, 0x0554, 0x0584 }, +/* 0x0555 */ { true, 0x0555, 0x0585 }, +/* 0x0556 */ { true, 0x0556, 0x0586 }, +/* 0x0557 */ { false, 0x0557, 0x0557 }, +/* 0x0558 */ { false, 0x0558, 0x0558 }, +/* 0x0559 */ { true, 0x0559, 0x0559 }, +/* 0x055a */ { false, 0x055a, 0x055a }, +/* 0x055b */ { false, 0x055b, 0x055b }, +/* 0x055c */ { false, 0x055c, 0x055c }, +/* 0x055d */ { false, 0x055d, 0x055d }, +/* 0x055e */ { false, 0x055e, 0x055e }, +/* 0x055f */ { false, 0x055f, 0x055f }, +/* 0x0560 */ { false, 0x0560, 0x0560 }, +/* 0x0561 */ { true, 0x0531, 0x0561 }, +/* 0x0562 */ { true, 0x0532, 0x0562 }, +/* 0x0563 */ { true, 0x0533, 0x0563 }, +/* 0x0564 */ { true, 0x0534, 0x0564 }, +/* 0x0565 */ { true, 0x0535, 0x0565 }, +/* 0x0566 */ { true, 0x0536, 0x0566 }, +/* 0x0567 */ { true, 0x0537, 0x0567 }, +/* 0x0568 */ { true, 0x0538, 0x0568 }, +/* 0x0569 */ { true, 0x0539, 0x0569 }, +/* 0x056a */ { true, 0x053a, 0x056a }, +/* 0x056b */ { true, 0x053b, 0x056b }, +/* 0x056c */ { true, 0x053c, 0x056c }, +/* 0x056d */ { true, 0x053d, 0x056d }, +/* 0x056e */ { true, 0x053e, 0x056e }, +/* 0x056f */ { true, 0x053f, 0x056f }, +/* 0x0570 */ { true, 0x0540, 0x0570 }, +/* 0x0571 */ { true, 0x0541, 0x0571 }, +/* 0x0572 */ { true, 0x0542, 0x0572 }, +/* 0x0573 */ { true, 0x0543, 0x0573 }, +/* 0x0574 */ { true, 0x0544, 0x0574 }, +/* 0x0575 */ { true, 0x0545, 0x0575 }, +/* 0x0576 */ { true, 0x0546, 0x0576 }, +/* 0x0577 */ { true, 0x0547, 0x0577 }, +/* 0x0578 */ { true, 0x0548, 0x0578 }, +/* 0x0579 */ { true, 0x0549, 0x0579 }, +/* 0x057a */ { true, 0x054a, 0x057a }, +/* 0x057b */ { true, 0x054b, 0x057b }, +/* 0x057c */ { true, 0x054c, 0x057c }, +/* 0x057d */ { true, 0x054d, 0x057d }, +/* 0x057e */ { true, 0x054e, 0x057e }, +/* 0x057f */ { true, 0x054f, 0x057f }, +/* 0x0580 */ { true, 0x0550, 0x0580 }, +/* 0x0581 */ { true, 0x0551, 0x0581 }, +/* 0x0582 */ { true, 0x0552, 0x0582 }, +/* 0x0583 */ { true, 0x0553, 0x0583 }, +/* 0x0584 */ { true, 0x0554, 0x0584 }, +/* 0x0585 */ { true, 0x0555, 0x0585 }, +/* 0x0586 */ { true, 0x0556, 0x0586 }, +/* 0x0587 */ { true, 0x0587, 0x0587 }, +/* 0x0588 */ { false, 0x0588, 0x0588 }, +/* 0x0589 */ { false, 0x0589, 0x0589 }, +/* 0x058a */ { false, 0x058a, 0x058a }, +/* 0x058b */ { false, 0x058b, 0x058b }, +/* 0x058c */ { false, 0x058c, 0x058c }, +/* 0x058d */ { false, 0x058d, 0x058d }, +/* 0x058e */ { false, 0x058e, 0x058e }, +/* 0x058f */ { false, 0x058f, 0x058f }, +/* 0x0590 */ { false, 0x0590, 0x0590 }, +/* 0x0591 */ { true, 0x0591, 0x0591 }, +/* 0x0592 */ { true, 0x0592, 0x0592 }, +/* 0x0593 */ { true, 0x0593, 0x0593 }, +/* 0x0594 */ { true, 0x0594, 0x0594 }, +/* 0x0595 */ { true, 0x0595, 0x0595 }, +/* 0x0596 */ { true, 0x0596, 0x0596 }, +/* 0x0597 */ { true, 0x0597, 0x0597 }, +/* 0x0598 */ { true, 0x0598, 0x0598 }, +/* 0x0599 */ { true, 0x0599, 0x0599 }, +/* 0x059a */ { true, 0x059a, 0x059a }, +/* 0x059b */ { true, 0x059b, 0x059b }, +/* 0x059c */ { true, 0x059c, 0x059c }, +/* 0x059d */ { true, 0x059d, 0x059d }, +/* 0x059e */ { true, 0x059e, 0x059e }, +/* 0x059f */ { true, 0x059f, 0x059f }, +/* 0x05a0 */ { true, 0x05a0, 0x05a0 }, +/* 0x05a1 */ { true, 0x05a1, 0x05a1 }, +/* 0x05a2 */ { true, 0x05a2, 0x05a2 }, +/* 0x05a3 */ { true, 0x05a3, 0x05a3 }, +/* 0x05a4 */ { true, 0x05a4, 0x05a4 }, +/* 0x05a5 */ { true, 0x05a5, 0x05a5 }, +/* 0x05a6 */ { true, 0x05a6, 0x05a6 }, +/* 0x05a7 */ { true, 0x05a7, 0x05a7 }, +/* 0x05a8 */ { true, 0x05a8, 0x05a8 }, +/* 0x05a9 */ { true, 0x05a9, 0x05a9 }, +/* 0x05aa */ { true, 0x05aa, 0x05aa }, +/* 0x05ab */ { true, 0x05ab, 0x05ab }, +/* 0x05ac */ { true, 0x05ac, 0x05ac }, +/* 0x05ad */ { true, 0x05ad, 0x05ad }, +/* 0x05ae */ { true, 0x05ae, 0x05ae }, +/* 0x05af */ { true, 0x05af, 0x05af }, +/* 0x05b0 */ { true, 0x05b0, 0x05b0 }, +/* 0x05b1 */ { true, 0x05b1, 0x05b1 }, +/* 0x05b2 */ { true, 0x05b2, 0x05b2 }, +/* 0x05b3 */ { true, 0x05b3, 0x05b3 }, +/* 0x05b4 */ { true, 0x05b4, 0x05b4 }, +/* 0x05b5 */ { true, 0x05b5, 0x05b5 }, +/* 0x05b6 */ { true, 0x05b6, 0x05b6 }, +/* 0x05b7 */ { true, 0x05b7, 0x05b7 }, +/* 0x05b8 */ { true, 0x05b8, 0x05b8 }, +/* 0x05b9 */ { true, 0x05b9, 0x05b9 }, +/* 0x05ba */ { false, 0x05ba, 0x05ba }, +/* 0x05bb */ { true, 0x05bb, 0x05bb }, +/* 0x05bc */ { true, 0x05bc, 0x05bc }, +/* 0x05bd */ { true, 0x05bd, 0x05bd }, +/* 0x05be */ { false, 0x05be, 0x05be }, +/* 0x05bf */ { true, 0x05bf, 0x05bf }, +/* 0x05c0 */ { false, 0x05c0, 0x05c0 }, +/* 0x05c1 */ { true, 0x05c1, 0x05c1 }, +/* 0x05c2 */ { true, 0x05c2, 0x05c2 }, +/* 0x05c3 */ { false, 0x05c3, 0x05c3 }, +/* 0x05c4 */ { true, 0x05c4, 0x05c4 }, +/* 0x05c5 */ { true, 0x05c5, 0x05c5 }, +/* 0x05c6 */ { false, 0x05c6, 0x05c6 }, +/* 0x05c7 */ { true, 0x05c7, 0x05c7 }, +/* 0x05c8 */ { false, 0x05c8, 0x05c8 }, +/* 0x05c9 */ { false, 0x05c9, 0x05c9 }, +/* 0x05ca */ { false, 0x05ca, 0x05ca }, +/* 0x05cb */ { false, 0x05cb, 0x05cb }, +/* 0x05cc */ { false, 0x05cc, 0x05cc }, +/* 0x05cd */ { false, 0x05cd, 0x05cd }, +/* 0x05ce */ { false, 0x05ce, 0x05ce }, +/* 0x05cf */ { false, 0x05cf, 0x05cf }, +/* 0x05d0 */ { true, 0x05d0, 0x05d0 }, +/* 0x05d1 */ { true, 0x05d1, 0x05d1 }, +/* 0x05d2 */ { true, 0x05d2, 0x05d2 }, +/* 0x05d3 */ { true, 0x05d3, 0x05d3 }, +/* 0x05d4 */ { true, 0x05d4, 0x05d4 }, +/* 0x05d5 */ { true, 0x05d5, 0x05d5 }, +/* 0x05d6 */ { true, 0x05d6, 0x05d6 }, +/* 0x05d7 */ { true, 0x05d7, 0x05d7 }, +/* 0x05d8 */ { true, 0x05d8, 0x05d8 }, +/* 0x05d9 */ { true, 0x05d9, 0x05d9 }, +/* 0x05da */ { true, 0x05da, 0x05da }, +/* 0x05db */ { true, 0x05db, 0x05db }, +/* 0x05dc */ { true, 0x05dc, 0x05dc }, +/* 0x05dd */ { true, 0x05dd, 0x05dd }, +/* 0x05de */ { true, 0x05de, 0x05de }, +/* 0x05df */ { true, 0x05df, 0x05df }, +/* 0x05e0 */ { true, 0x05e0, 0x05e0 }, +/* 0x05e1 */ { true, 0x05e1, 0x05e1 }, +/* 0x05e2 */ { true, 0x05e2, 0x05e2 }, +/* 0x05e3 */ { true, 0x05e3, 0x05e3 }, +/* 0x05e4 */ { true, 0x05e4, 0x05e4 }, +/* 0x05e5 */ { true, 0x05e5, 0x05e5 }, +/* 0x05e6 */ { true, 0x05e6, 0x05e6 }, +/* 0x05e7 */ { true, 0x05e7, 0x05e7 }, +/* 0x05e8 */ { true, 0x05e8, 0x05e8 }, +/* 0x05e9 */ { true, 0x05e9, 0x05e9 }, +/* 0x05ea */ { true, 0x05ea, 0x05ea }, +/* 0x05eb */ { false, 0x05eb, 0x05eb }, +/* 0x05ec */ { false, 0x05ec, 0x05ec }, +/* 0x05ed */ { false, 0x05ed, 0x05ed }, +/* 0x05ee */ { false, 0x05ee, 0x05ee }, +/* 0x05ef */ { false, 0x05ef, 0x05ef }, +/* 0x05f0 */ { true, 0x05f0, 0x05f0 }, +/* 0x05f1 */ { true, 0x05f1, 0x05f1 }, +/* 0x05f2 */ { true, 0x05f2, 0x05f2 }, +/* 0x05f3 */ { false, 0x05f3, 0x05f3 }, +/* 0x05f4 */ { false, 0x05f4, 0x05f4 }, +/* 0x05f5 */ { false, 0x05f5, 0x05f5 }, +/* 0x05f6 */ { false, 0x05f6, 0x05f6 }, +/* 0x05f7 */ { false, 0x05f7, 0x05f7 }, +/* 0x05f8 */ { false, 0x05f8, 0x05f8 }, +/* 0x05f9 */ { false, 0x05f9, 0x05f9 }, +/* 0x05fa */ { false, 0x05fa, 0x05fa }, +/* 0x05fb */ { false, 0x05fb, 0x05fb }, +/* 0x05fc */ { false, 0x05fc, 0x05fc }, +/* 0x05fd */ { false, 0x05fd, 0x05fd }, +/* 0x05fe */ { false, 0x05fe, 0x05fe }, +/* 0x05ff */ { false, 0x05ff, 0x05ff }, +/* 0x0600 */ { false, 0x0600, 0x0600 }, +/* 0x0601 */ { false, 0x0601, 0x0601 }, +/* 0x0602 */ { false, 0x0602, 0x0602 }, +/* 0x0603 */ { false, 0x0603, 0x0603 }, +/* 0x0604 */ { false, 0x0604, 0x0604 }, +/* 0x0605 */ { false, 0x0605, 0x0605 }, +/* 0x0606 */ { false, 0x0606, 0x0606 }, +/* 0x0607 */ { false, 0x0607, 0x0607 }, +/* 0x0608 */ { false, 0x0608, 0x0608 }, +/* 0x0609 */ { false, 0x0609, 0x0609 }, +/* 0x060a */ { false, 0x060a, 0x060a }, +/* 0x060b */ { false, 0x060b, 0x060b }, +/* 0x060c */ { false, 0x060c, 0x060c }, +/* 0x060d */ { false, 0x060d, 0x060d }, +/* 0x060e */ { false, 0x060e, 0x060e }, +/* 0x060f */ { false, 0x060f, 0x060f }, +/* 0x0610 */ { true, 0x0610, 0x0610 }, +/* 0x0611 */ { true, 0x0611, 0x0611 }, +/* 0x0612 */ { true, 0x0612, 0x0612 }, +/* 0x0613 */ { true, 0x0613, 0x0613 }, +/* 0x0614 */ { true, 0x0614, 0x0614 }, +/* 0x0615 */ { true, 0x0615, 0x0615 }, +/* 0x0616 */ { false, 0x0616, 0x0616 }, +/* 0x0617 */ { false, 0x0617, 0x0617 }, +/* 0x0618 */ { false, 0x0618, 0x0618 }, +/* 0x0619 */ { false, 0x0619, 0x0619 }, +/* 0x061a */ { false, 0x061a, 0x061a }, +/* 0x061b */ { false, 0x061b, 0x061b }, +/* 0x061c */ { false, 0x061c, 0x061c }, +/* 0x061d */ { false, 0x061d, 0x061d }, +/* 0x061e */ { false, 0x061e, 0x061e }, +/* 0x061f */ { false, 0x061f, 0x061f }, +/* 0x0620 */ { false, 0x0620, 0x0620 }, +/* 0x0621 */ { true, 0x0621, 0x0621 }, +/* 0x0622 */ { true, 0x0622, 0x0622 }, +/* 0x0623 */ { true, 0x0623, 0x0623 }, +/* 0x0624 */ { true, 0x0624, 0x0624 }, +/* 0x0625 */ { true, 0x0625, 0x0625 }, +/* 0x0626 */ { true, 0x0626, 0x0626 }, +/* 0x0627 */ { true, 0x0627, 0x0627 }, +/* 0x0628 */ { true, 0x0628, 0x0628 }, +/* 0x0629 */ { true, 0x0629, 0x0629 }, +/* 0x062a */ { true, 0x062a, 0x062a }, +/* 0x062b */ { true, 0x062b, 0x062b }, +/* 0x062c */ { true, 0x062c, 0x062c }, +/* 0x062d */ { true, 0x062d, 0x062d }, +/* 0x062e */ { true, 0x062e, 0x062e }, +/* 0x062f */ { true, 0x062f, 0x062f }, +/* 0x0630 */ { true, 0x0630, 0x0630 }, +/* 0x0631 */ { true, 0x0631, 0x0631 }, +/* 0x0632 */ { true, 0x0632, 0x0632 }, +/* 0x0633 */ { true, 0x0633, 0x0633 }, +/* 0x0634 */ { true, 0x0634, 0x0634 }, +/* 0x0635 */ { true, 0x0635, 0x0635 }, +/* 0x0636 */ { true, 0x0636, 0x0636 }, +/* 0x0637 */ { true, 0x0637, 0x0637 }, +/* 0x0638 */ { true, 0x0638, 0x0638 }, +/* 0x0639 */ { true, 0x0639, 0x0639 }, +/* 0x063a */ { true, 0x063a, 0x063a }, +/* 0x063b */ { false, 0x063b, 0x063b }, +/* 0x063c */ { false, 0x063c, 0x063c }, +/* 0x063d */ { false, 0x063d, 0x063d }, +/* 0x063e */ { false, 0x063e, 0x063e }, +/* 0x063f */ { false, 0x063f, 0x063f }, +/* 0x0640 */ { true, 0x0640, 0x0640 }, +/* 0x0641 */ { true, 0x0641, 0x0641 }, +/* 0x0642 */ { true, 0x0642, 0x0642 }, +/* 0x0643 */ { true, 0x0643, 0x0643 }, +/* 0x0644 */ { true, 0x0644, 0x0644 }, +/* 0x0645 */ { true, 0x0645, 0x0645 }, +/* 0x0646 */ { true, 0x0646, 0x0646 }, +/* 0x0647 */ { true, 0x0647, 0x0647 }, +/* 0x0648 */ { true, 0x0648, 0x0648 }, +/* 0x0649 */ { true, 0x0649, 0x0649 }, +/* 0x064a */ { true, 0x064a, 0x064a }, +/* 0x064b */ { true, 0x064b, 0x064b }, +/* 0x064c */ { true, 0x064c, 0x064c }, +/* 0x064d */ { true, 0x064d, 0x064d }, +/* 0x064e */ { true, 0x064e, 0x064e }, +/* 0x064f */ { true, 0x064f, 0x064f }, +/* 0x0650 */ { true, 0x0650, 0x0650 }, +/* 0x0651 */ { true, 0x0651, 0x0651 }, +/* 0x0652 */ { true, 0x0652, 0x0652 }, +/* 0x0653 */ { true, 0x0653, 0x0653 }, +/* 0x0654 */ { true, 0x0654, 0x0654 }, +/* 0x0655 */ { true, 0x0655, 0x0655 }, +/* 0x0656 */ { true, 0x0656, 0x0656 }, +/* 0x0657 */ { true, 0x0657, 0x0657 }, +/* 0x0658 */ { true, 0x0658, 0x0658 }, +/* 0x0659 */ { true, 0x0659, 0x0659 }, +/* 0x065a */ { true, 0x065a, 0x065a }, +/* 0x065b */ { true, 0x065b, 0x065b }, +/* 0x065c */ { true, 0x065c, 0x065c }, +/* 0x065d */ { true, 0x065d, 0x065d }, +/* 0x065e */ { true, 0x065e, 0x065e }, +/* 0x065f */ { false, 0x065f, 0x065f }, +/* 0x0660 */ { false, 0x0660, 0x0660 }, +/* 0x0661 */ { false, 0x0661, 0x0661 }, +/* 0x0662 */ { false, 0x0662, 0x0662 }, +/* 0x0663 */ { false, 0x0663, 0x0663 }, +/* 0x0664 */ { false, 0x0664, 0x0664 }, +/* 0x0665 */ { false, 0x0665, 0x0665 }, +/* 0x0666 */ { false, 0x0666, 0x0666 }, +/* 0x0667 */ { false, 0x0667, 0x0667 }, +/* 0x0668 */ { false, 0x0668, 0x0668 }, +/* 0x0669 */ { false, 0x0669, 0x0669 }, +/* 0x066a */ { false, 0x066a, 0x066a }, +/* 0x066b */ { false, 0x066b, 0x066b }, +/* 0x066c */ { false, 0x066c, 0x066c }, +/* 0x066d */ { false, 0x066d, 0x066d }, +/* 0x066e */ { true, 0x066e, 0x066e }, +/* 0x066f */ { true, 0x066f, 0x066f }, +/* 0x0670 */ { true, 0x0670, 0x0670 }, +/* 0x0671 */ { true, 0x0671, 0x0671 }, +/* 0x0672 */ { true, 0x0672, 0x0672 }, +/* 0x0673 */ { true, 0x0673, 0x0673 }, +/* 0x0674 */ { true, 0x0674, 0x0674 }, +/* 0x0675 */ { true, 0x0675, 0x0675 }, +/* 0x0676 */ { true, 0x0676, 0x0676 }, +/* 0x0677 */ { true, 0x0677, 0x0677 }, +/* 0x0678 */ { true, 0x0678, 0x0678 }, +/* 0x0679 */ { true, 0x0679, 0x0679 }, +/* 0x067a */ { true, 0x067a, 0x067a }, +/* 0x067b */ { true, 0x067b, 0x067b }, +/* 0x067c */ { true, 0x067c, 0x067c }, +/* 0x067d */ { true, 0x067d, 0x067d }, +/* 0x067e */ { true, 0x067e, 0x067e }, +/* 0x067f */ { true, 0x067f, 0x067f }, +/* 0x0680 */ { true, 0x0680, 0x0680 }, +/* 0x0681 */ { true, 0x0681, 0x0681 }, +/* 0x0682 */ { true, 0x0682, 0x0682 }, +/* 0x0683 */ { true, 0x0683, 0x0683 }, +/* 0x0684 */ { true, 0x0684, 0x0684 }, +/* 0x0685 */ { true, 0x0685, 0x0685 }, +/* 0x0686 */ { true, 0x0686, 0x0686 }, +/* 0x0687 */ { true, 0x0687, 0x0687 }, +/* 0x0688 */ { true, 0x0688, 0x0688 }, +/* 0x0689 */ { true, 0x0689, 0x0689 }, +/* 0x068a */ { true, 0x068a, 0x068a }, +/* 0x068b */ { true, 0x068b, 0x068b }, +/* 0x068c */ { true, 0x068c, 0x068c }, +/* 0x068d */ { true, 0x068d, 0x068d }, +/* 0x068e */ { true, 0x068e, 0x068e }, +/* 0x068f */ { true, 0x068f, 0x068f }, +/* 0x0690 */ { true, 0x0690, 0x0690 }, +/* 0x0691 */ { true, 0x0691, 0x0691 }, +/* 0x0692 */ { true, 0x0692, 0x0692 }, +/* 0x0693 */ { true, 0x0693, 0x0693 }, +/* 0x0694 */ { true, 0x0694, 0x0694 }, +/* 0x0695 */ { true, 0x0695, 0x0695 }, +/* 0x0696 */ { true, 0x0696, 0x0696 }, +/* 0x0697 */ { true, 0x0697, 0x0697 }, +/* 0x0698 */ { true, 0x0698, 0x0698 }, +/* 0x0699 */ { true, 0x0699, 0x0699 }, +/* 0x069a */ { true, 0x069a, 0x069a }, +/* 0x069b */ { true, 0x069b, 0x069b }, +/* 0x069c */ { true, 0x069c, 0x069c }, +/* 0x069d */ { true, 0x069d, 0x069d }, +/* 0x069e */ { true, 0x069e, 0x069e }, +/* 0x069f */ { true, 0x069f, 0x069f }, +/* 0x06a0 */ { true, 0x06a0, 0x06a0 }, +/* 0x06a1 */ { true, 0x06a1, 0x06a1 }, +/* 0x06a2 */ { true, 0x06a2, 0x06a2 }, +/* 0x06a3 */ { true, 0x06a3, 0x06a3 }, +/* 0x06a4 */ { true, 0x06a4, 0x06a4 }, +/* 0x06a5 */ { true, 0x06a5, 0x06a5 }, +/* 0x06a6 */ { true, 0x06a6, 0x06a6 }, +/* 0x06a7 */ { true, 0x06a7, 0x06a7 }, +/* 0x06a8 */ { true, 0x06a8, 0x06a8 }, +/* 0x06a9 */ { true, 0x06a9, 0x06a9 }, +/* 0x06aa */ { true, 0x06aa, 0x06aa }, +/* 0x06ab */ { true, 0x06ab, 0x06ab }, +/* 0x06ac */ { true, 0x06ac, 0x06ac }, +/* 0x06ad */ { true, 0x06ad, 0x06ad }, +/* 0x06ae */ { true, 0x06ae, 0x06ae }, +/* 0x06af */ { true, 0x06af, 0x06af }, +/* 0x06b0 */ { true, 0x06b0, 0x06b0 }, +/* 0x06b1 */ { true, 0x06b1, 0x06b1 }, +/* 0x06b2 */ { true, 0x06b2, 0x06b2 }, +/* 0x06b3 */ { true, 0x06b3, 0x06b3 }, +/* 0x06b4 */ { true, 0x06b4, 0x06b4 }, +/* 0x06b5 */ { true, 0x06b5, 0x06b5 }, +/* 0x06b6 */ { true, 0x06b6, 0x06b6 }, +/* 0x06b7 */ { true, 0x06b7, 0x06b7 }, +/* 0x06b8 */ { true, 0x06b8, 0x06b8 }, +/* 0x06b9 */ { true, 0x06b9, 0x06b9 }, +/* 0x06ba */ { true, 0x06ba, 0x06ba }, +/* 0x06bb */ { true, 0x06bb, 0x06bb }, +/* 0x06bc */ { true, 0x06bc, 0x06bc }, +/* 0x06bd */ { true, 0x06bd, 0x06bd }, +/* 0x06be */ { true, 0x06be, 0x06be }, +/* 0x06bf */ { true, 0x06bf, 0x06bf }, +/* 0x06c0 */ { true, 0x06c0, 0x06c0 }, +/* 0x06c1 */ { true, 0x06c1, 0x06c1 }, +/* 0x06c2 */ { true, 0x06c2, 0x06c2 }, +/* 0x06c3 */ { true, 0x06c3, 0x06c3 }, +/* 0x06c4 */ { true, 0x06c4, 0x06c4 }, +/* 0x06c5 */ { true, 0x06c5, 0x06c5 }, +/* 0x06c6 */ { true, 0x06c6, 0x06c6 }, +/* 0x06c7 */ { true, 0x06c7, 0x06c7 }, +/* 0x06c8 */ { true, 0x06c8, 0x06c8 }, +/* 0x06c9 */ { true, 0x06c9, 0x06c9 }, +/* 0x06ca */ { true, 0x06ca, 0x06ca }, +/* 0x06cb */ { true, 0x06cb, 0x06cb }, +/* 0x06cc */ { true, 0x06cc, 0x06cc }, +/* 0x06cd */ { true, 0x06cd, 0x06cd }, +/* 0x06ce */ { true, 0x06ce, 0x06ce }, +/* 0x06cf */ { true, 0x06cf, 0x06cf }, +/* 0x06d0 */ { true, 0x06d0, 0x06d0 }, +/* 0x06d1 */ { true, 0x06d1, 0x06d1 }, +/* 0x06d2 */ { true, 0x06d2, 0x06d2 }, +/* 0x06d3 */ { true, 0x06d3, 0x06d3 }, +/* 0x06d4 */ { false, 0x06d4, 0x06d4 }, +/* 0x06d5 */ { true, 0x06d5, 0x06d5 }, +/* 0x06d6 */ { true, 0x06d6, 0x06d6 }, +/* 0x06d7 */ { true, 0x06d7, 0x06d7 }, +/* 0x06d8 */ { true, 0x06d8, 0x06d8 }, +/* 0x06d9 */ { true, 0x06d9, 0x06d9 }, +/* 0x06da */ { true, 0x06da, 0x06da }, +/* 0x06db */ { true, 0x06db, 0x06db }, +/* 0x06dc */ { true, 0x06dc, 0x06dc }, +/* 0x06dd */ { false, 0x06dd, 0x06dd }, +/* 0x06de */ { false, 0x06de, 0x06de }, +/* 0x06df */ { true, 0x06df, 0x06df }, +/* 0x06e0 */ { true, 0x06e0, 0x06e0 }, +/* 0x06e1 */ { true, 0x06e1, 0x06e1 }, +/* 0x06e2 */ { true, 0x06e2, 0x06e2 }, +/* 0x06e3 */ { true, 0x06e3, 0x06e3 }, +/* 0x06e4 */ { true, 0x06e4, 0x06e4 }, +/* 0x06e5 */ { true, 0x06e5, 0x06e5 }, +/* 0x06e6 */ { true, 0x06e6, 0x06e6 }, +/* 0x06e7 */ { true, 0x06e7, 0x06e7 }, +/* 0x06e8 */ { true, 0x06e8, 0x06e8 }, +/* 0x06e9 */ { false, 0x06e9, 0x06e9 }, +/* 0x06ea */ { true, 0x06ea, 0x06ea }, +/* 0x06eb */ { true, 0x06eb, 0x06eb }, +/* 0x06ec */ { true, 0x06ec, 0x06ec }, +/* 0x06ed */ { true, 0x06ed, 0x06ed }, +/* 0x06ee */ { true, 0x06ee, 0x06ee }, +/* 0x06ef */ { true, 0x06ef, 0x06ef }, +/* 0x06f0 */ { false, 0x06f0, 0x06f0 }, +/* 0x06f1 */ { false, 0x06f1, 0x06f1 }, +/* 0x06f2 */ { false, 0x06f2, 0x06f2 }, +/* 0x06f3 */ { false, 0x06f3, 0x06f3 }, +/* 0x06f4 */ { false, 0x06f4, 0x06f4 }, +/* 0x06f5 */ { false, 0x06f5, 0x06f5 }, +/* 0x06f6 */ { false, 0x06f6, 0x06f6 }, +/* 0x06f7 */ { false, 0x06f7, 0x06f7 }, +/* 0x06f8 */ { false, 0x06f8, 0x06f8 }, +/* 0x06f9 */ { false, 0x06f9, 0x06f9 }, +/* 0x06fa */ { true, 0x06fa, 0x06fa }, +/* 0x06fb */ { true, 0x06fb, 0x06fb }, +/* 0x06fc */ { true, 0x06fc, 0x06fc }, +/* 0x06fd */ { false, 0x06fd, 0x06fd }, +/* 0x06fe */ { false, 0x06fe, 0x06fe }, +/* 0x06ff */ { true, 0x06ff, 0x06ff }, +/* 0x0700 */ { false, 0x0700, 0x0700 }, +/* 0x0701 */ { false, 0x0701, 0x0701 }, +/* 0x0702 */ { false, 0x0702, 0x0702 }, +/* 0x0703 */ { false, 0x0703, 0x0703 }, +/* 0x0704 */ { false, 0x0704, 0x0704 }, +/* 0x0705 */ { false, 0x0705, 0x0705 }, +/* 0x0706 */ { false, 0x0706, 0x0706 }, +/* 0x0707 */ { false, 0x0707, 0x0707 }, +/* 0x0708 */ { false, 0x0708, 0x0708 }, +/* 0x0709 */ { false, 0x0709, 0x0709 }, +/* 0x070a */ { false, 0x070a, 0x070a }, +/* 0x070b */ { false, 0x070b, 0x070b }, +/* 0x070c */ { false, 0x070c, 0x070c }, +/* 0x070d */ { false, 0x070d, 0x070d }, +/* 0x070e */ { false, 0x070e, 0x070e }, +/* 0x070f */ { false, 0x070f, 0x070f }, +/* 0x0710 */ { true, 0x0710, 0x0710 }, +/* 0x0711 */ { true, 0x0711, 0x0711 }, +/* 0x0712 */ { true, 0x0712, 0x0712 }, +/* 0x0713 */ { true, 0x0713, 0x0713 }, +/* 0x0714 */ { true, 0x0714, 0x0714 }, +/* 0x0715 */ { true, 0x0715, 0x0715 }, +/* 0x0716 */ { true, 0x0716, 0x0716 }, +/* 0x0717 */ { true, 0x0717, 0x0717 }, +/* 0x0718 */ { true, 0x0718, 0x0718 }, +/* 0x0719 */ { true, 0x0719, 0x0719 }, +/* 0x071a */ { true, 0x071a, 0x071a }, +/* 0x071b */ { true, 0x071b, 0x071b }, +/* 0x071c */ { true, 0x071c, 0x071c }, +/* 0x071d */ { true, 0x071d, 0x071d }, +/* 0x071e */ { true, 0x071e, 0x071e }, +/* 0x071f */ { true, 0x071f, 0x071f }, +/* 0x0720 */ { true, 0x0720, 0x0720 }, +/* 0x0721 */ { true, 0x0721, 0x0721 }, +/* 0x0722 */ { true, 0x0722, 0x0722 }, +/* 0x0723 */ { true, 0x0723, 0x0723 }, +/* 0x0724 */ { true, 0x0724, 0x0724 }, +/* 0x0725 */ { true, 0x0725, 0x0725 }, +/* 0x0726 */ { true, 0x0726, 0x0726 }, +/* 0x0727 */ { true, 0x0727, 0x0727 }, +/* 0x0728 */ { true, 0x0728, 0x0728 }, +/* 0x0729 */ { true, 0x0729, 0x0729 }, +/* 0x072a */ { true, 0x072a, 0x072a }, +/* 0x072b */ { true, 0x072b, 0x072b }, +/* 0x072c */ { true, 0x072c, 0x072c }, +/* 0x072d */ { true, 0x072d, 0x072d }, +/* 0x072e */ { true, 0x072e, 0x072e }, +/* 0x072f */ { true, 0x072f, 0x072f }, +/* 0x0730 */ { true, 0x0730, 0x0730 }, +/* 0x0731 */ { true, 0x0731, 0x0731 }, +/* 0x0732 */ { true, 0x0732, 0x0732 }, +/* 0x0733 */ { true, 0x0733, 0x0733 }, +/* 0x0734 */ { true, 0x0734, 0x0734 }, +/* 0x0735 */ { true, 0x0735, 0x0735 }, +/* 0x0736 */ { true, 0x0736, 0x0736 }, +/* 0x0737 */ { true, 0x0737, 0x0737 }, +/* 0x0738 */ { true, 0x0738, 0x0738 }, +/* 0x0739 */ { true, 0x0739, 0x0739 }, +/* 0x073a */ { true, 0x073a, 0x073a }, +/* 0x073b */ { true, 0x073b, 0x073b }, +/* 0x073c */ { true, 0x073c, 0x073c }, +/* 0x073d */ { true, 0x073d, 0x073d }, +/* 0x073e */ { true, 0x073e, 0x073e }, +/* 0x073f */ { true, 0x073f, 0x073f }, +/* 0x0740 */ { true, 0x0740, 0x0740 }, +/* 0x0741 */ { true, 0x0741, 0x0741 }, +/* 0x0742 */ { true, 0x0742, 0x0742 }, +/* 0x0743 */ { true, 0x0743, 0x0743 }, +/* 0x0744 */ { true, 0x0744, 0x0744 }, +/* 0x0745 */ { true, 0x0745, 0x0745 }, +/* 0x0746 */ { true, 0x0746, 0x0746 }, +/* 0x0747 */ { true, 0x0747, 0x0747 }, +/* 0x0748 */ { true, 0x0748, 0x0748 }, +/* 0x0749 */ { true, 0x0749, 0x0749 }, +/* 0x074a */ { true, 0x074a, 0x074a }, +/* 0x074b */ { false, 0x074b, 0x074b }, +/* 0x074c */ { false, 0x074c, 0x074c }, +/* 0x074d */ { true, 0x074d, 0x074d }, +/* 0x074e */ { true, 0x074e, 0x074e }, +/* 0x074f */ { true, 0x074f, 0x074f }, +/* 0x0750 */ { true, 0x0750, 0x0750 }, +/* 0x0751 */ { true, 0x0751, 0x0751 }, +/* 0x0752 */ { true, 0x0752, 0x0752 }, +/* 0x0753 */ { true, 0x0753, 0x0753 }, +/* 0x0754 */ { true, 0x0754, 0x0754 }, +/* 0x0755 */ { true, 0x0755, 0x0755 }, +/* 0x0756 */ { true, 0x0756, 0x0756 }, +/* 0x0757 */ { true, 0x0757, 0x0757 }, +/* 0x0758 */ { true, 0x0758, 0x0758 }, +/* 0x0759 */ { true, 0x0759, 0x0759 }, +/* 0x075a */ { true, 0x075a, 0x075a }, +/* 0x075b */ { true, 0x075b, 0x075b }, +/* 0x075c */ { true, 0x075c, 0x075c }, +/* 0x075d */ { true, 0x075d, 0x075d }, +/* 0x075e */ { true, 0x075e, 0x075e }, +/* 0x075f */ { true, 0x075f, 0x075f }, +/* 0x0760 */ { true, 0x0760, 0x0760 }, +/* 0x0761 */ { true, 0x0761, 0x0761 }, +/* 0x0762 */ { true, 0x0762, 0x0762 }, +/* 0x0763 */ { true, 0x0763, 0x0763 }, +/* 0x0764 */ { true, 0x0764, 0x0764 }, +/* 0x0765 */ { true, 0x0765, 0x0765 }, +/* 0x0766 */ { true, 0x0766, 0x0766 }, +/* 0x0767 */ { true, 0x0767, 0x0767 }, +/* 0x0768 */ { true, 0x0768, 0x0768 }, +/* 0x0769 */ { true, 0x0769, 0x0769 }, +/* 0x076a */ { true, 0x076a, 0x076a }, +/* 0x076b */ { true, 0x076b, 0x076b }, +/* 0x076c */ { true, 0x076c, 0x076c }, +/* 0x076d */ { true, 0x076d, 0x076d }, +/* 0x076e */ { false, 0x076e, 0x076e }, +/* 0x076f */ { false, 0x076f, 0x076f }, +/* 0x0770 */ { false, 0x0770, 0x0770 }, +/* 0x0771 */ { false, 0x0771, 0x0771 }, +/* 0x0772 */ { false, 0x0772, 0x0772 }, +/* 0x0773 */ { false, 0x0773, 0x0773 }, +/* 0x0774 */ { false, 0x0774, 0x0774 }, +/* 0x0775 */ { false, 0x0775, 0x0775 }, +/* 0x0776 */ { false, 0x0776, 0x0776 }, +/* 0x0777 */ { false, 0x0777, 0x0777 }, +/* 0x0778 */ { false, 0x0778, 0x0778 }, +/* 0x0779 */ { false, 0x0779, 0x0779 }, +/* 0x077a */ { false, 0x077a, 0x077a }, +/* 0x077b */ { false, 0x077b, 0x077b }, +/* 0x077c */ { false, 0x077c, 0x077c }, +/* 0x077d */ { false, 0x077d, 0x077d }, +/* 0x077e */ { false, 0x077e, 0x077e }, +/* 0x077f */ { false, 0x077f, 0x077f }, +/* 0x0780 */ { true, 0x0780, 0x0780 }, +/* 0x0781 */ { true, 0x0781, 0x0781 }, +/* 0x0782 */ { true, 0x0782, 0x0782 }, +/* 0x0783 */ { true, 0x0783, 0x0783 }, +/* 0x0784 */ { true, 0x0784, 0x0784 }, +/* 0x0785 */ { true, 0x0785, 0x0785 }, +/* 0x0786 */ { true, 0x0786, 0x0786 }, +/* 0x0787 */ { true, 0x0787, 0x0787 }, +/* 0x0788 */ { true, 0x0788, 0x0788 }, +/* 0x0789 */ { true, 0x0789, 0x0789 }, +/* 0x078a */ { true, 0x078a, 0x078a }, +/* 0x078b */ { true, 0x078b, 0x078b }, +/* 0x078c */ { true, 0x078c, 0x078c }, +/* 0x078d */ { true, 0x078d, 0x078d }, +/* 0x078e */ { true, 0x078e, 0x078e }, +/* 0x078f */ { true, 0x078f, 0x078f }, +/* 0x0790 */ { true, 0x0790, 0x0790 }, +/* 0x0791 */ { true, 0x0791, 0x0791 }, +/* 0x0792 */ { true, 0x0792, 0x0792 }, +/* 0x0793 */ { true, 0x0793, 0x0793 }, +/* 0x0794 */ { true, 0x0794, 0x0794 }, +/* 0x0795 */ { true, 0x0795, 0x0795 }, +/* 0x0796 */ { true, 0x0796, 0x0796 }, +/* 0x0797 */ { true, 0x0797, 0x0797 }, +/* 0x0798 */ { true, 0x0798, 0x0798 }, +/* 0x0799 */ { true, 0x0799, 0x0799 }, +/* 0x079a */ { true, 0x079a, 0x079a }, +/* 0x079b */ { true, 0x079b, 0x079b }, +/* 0x079c */ { true, 0x079c, 0x079c }, +/* 0x079d */ { true, 0x079d, 0x079d }, +/* 0x079e */ { true, 0x079e, 0x079e }, +/* 0x079f */ { true, 0x079f, 0x079f }, +/* 0x07a0 */ { true, 0x07a0, 0x07a0 }, +/* 0x07a1 */ { true, 0x07a1, 0x07a1 }, +/* 0x07a2 */ { true, 0x07a2, 0x07a2 }, +/* 0x07a3 */ { true, 0x07a3, 0x07a3 }, +/* 0x07a4 */ { true, 0x07a4, 0x07a4 }, +/* 0x07a5 */ { true, 0x07a5, 0x07a5 }, +/* 0x07a6 */ { true, 0x07a6, 0x07a6 }, +/* 0x07a7 */ { true, 0x07a7, 0x07a7 }, +/* 0x07a8 */ { true, 0x07a8, 0x07a8 }, +/* 0x07a9 */ { true, 0x07a9, 0x07a9 }, +/* 0x07aa */ { true, 0x07aa, 0x07aa }, +/* 0x07ab */ { true, 0x07ab, 0x07ab }, +/* 0x07ac */ { true, 0x07ac, 0x07ac }, +/* 0x07ad */ { true, 0x07ad, 0x07ad }, +/* 0x07ae */ { true, 0x07ae, 0x07ae }, +/* 0x07af */ { true, 0x07af, 0x07af }, +/* 0x07b0 */ { true, 0x07b0, 0x07b0 }, +/* 0x07b1 */ { true, 0x07b1, 0x07b1 }, +/* 0x07b2 */ { false, 0x07b2, 0x07b2 }, +/* 0x07b3 */ { false, 0x07b3, 0x07b3 }, +/* 0x07b4 */ { false, 0x07b4, 0x07b4 }, +/* 0x07b5 */ { false, 0x07b5, 0x07b5 }, +/* 0x07b6 */ { false, 0x07b6, 0x07b6 }, +/* 0x07b7 */ { false, 0x07b7, 0x07b7 }, +/* 0x07b8 */ { false, 0x07b8, 0x07b8 }, +/* 0x07b9 */ { false, 0x07b9, 0x07b9 }, +/* 0x07ba */ { false, 0x07ba, 0x07ba }, +/* 0x07bb */ { false, 0x07bb, 0x07bb }, +/* 0x07bc */ { false, 0x07bc, 0x07bc }, +/* 0x07bd */ { false, 0x07bd, 0x07bd }, +/* 0x07be */ { false, 0x07be, 0x07be }, +/* 0x07bf */ { false, 0x07bf, 0x07bf }, +/* 0x07c0 */ { false, 0x07c0, 0x07c0 }, +/* 0x07c1 */ { false, 0x07c1, 0x07c1 }, +/* 0x07c2 */ { false, 0x07c2, 0x07c2 }, +/* 0x07c3 */ { false, 0x07c3, 0x07c3 }, +/* 0x07c4 */ { false, 0x07c4, 0x07c4 }, +/* 0x07c5 */ { false, 0x07c5, 0x07c5 }, +/* 0x07c6 */ { false, 0x07c6, 0x07c6 }, +/* 0x07c7 */ { false, 0x07c7, 0x07c7 }, +/* 0x07c8 */ { false, 0x07c8, 0x07c8 }, +/* 0x07c9 */ { false, 0x07c9, 0x07c9 }, +/* 0x07ca */ { false, 0x07ca, 0x07ca }, +/* 0x07cb */ { false, 0x07cb, 0x07cb }, +/* 0x07cc */ { false, 0x07cc, 0x07cc }, +/* 0x07cd */ { false, 0x07cd, 0x07cd }, +/* 0x07ce */ { false, 0x07ce, 0x07ce }, +/* 0x07cf */ { false, 0x07cf, 0x07cf }, +/* 0x07d0 */ { false, 0x07d0, 0x07d0 }, +/* 0x07d1 */ { false, 0x07d1, 0x07d1 }, +/* 0x07d2 */ { false, 0x07d2, 0x07d2 }, +/* 0x07d3 */ { false, 0x07d3, 0x07d3 }, +/* 0x07d4 */ { false, 0x07d4, 0x07d4 }, +/* 0x07d5 */ { false, 0x07d5, 0x07d5 }, +/* 0x07d6 */ { false, 0x07d6, 0x07d6 }, +/* 0x07d7 */ { false, 0x07d7, 0x07d7 }, +/* 0x07d8 */ { false, 0x07d8, 0x07d8 }, +/* 0x07d9 */ { false, 0x07d9, 0x07d9 }, +/* 0x07da */ { false, 0x07da, 0x07da }, +/* 0x07db */ { false, 0x07db, 0x07db }, +/* 0x07dc */ { false, 0x07dc, 0x07dc }, +/* 0x07dd */ { false, 0x07dd, 0x07dd }, +/* 0x07de */ { false, 0x07de, 0x07de }, +/* 0x07df */ { false, 0x07df, 0x07df }, +/* 0x07e0 */ { false, 0x07e0, 0x07e0 }, +/* 0x07e1 */ { false, 0x07e1, 0x07e1 }, +/* 0x07e2 */ { false, 0x07e2, 0x07e2 }, +/* 0x07e3 */ { false, 0x07e3, 0x07e3 }, +/* 0x07e4 */ { false, 0x07e4, 0x07e4 }, +/* 0x07e5 */ { false, 0x07e5, 0x07e5 }, +/* 0x07e6 */ { false, 0x07e6, 0x07e6 }, +/* 0x07e7 */ { false, 0x07e7, 0x07e7 }, +/* 0x07e8 */ { false, 0x07e8, 0x07e8 }, +/* 0x07e9 */ { false, 0x07e9, 0x07e9 }, +/* 0x07ea */ { false, 0x07ea, 0x07ea }, +/* 0x07eb */ { false, 0x07eb, 0x07eb }, +/* 0x07ec */ { false, 0x07ec, 0x07ec }, +/* 0x07ed */ { false, 0x07ed, 0x07ed }, +/* 0x07ee */ { false, 0x07ee, 0x07ee }, +/* 0x07ef */ { false, 0x07ef, 0x07ef }, +/* 0x07f0 */ { false, 0x07f0, 0x07f0 }, +/* 0x07f1 */ { false, 0x07f1, 0x07f1 }, +/* 0x07f2 */ { false, 0x07f2, 0x07f2 }, +/* 0x07f3 */ { false, 0x07f3, 0x07f3 }, +/* 0x07f4 */ { false, 0x07f4, 0x07f4 }, +/* 0x07f5 */ { false, 0x07f5, 0x07f5 }, +/* 0x07f6 */ { false, 0x07f6, 0x07f6 }, +/* 0x07f7 */ { false, 0x07f7, 0x07f7 }, +/* 0x07f8 */ { false, 0x07f8, 0x07f8 }, +/* 0x07f9 */ { false, 0x07f9, 0x07f9 }, +/* 0x07fa */ { false, 0x07fa, 0x07fa }, +/* 0x07fb */ { false, 0x07fb, 0x07fb }, +/* 0x07fc */ { false, 0x07fc, 0x07fc }, +/* 0x07fd */ { false, 0x07fd, 0x07fd }, +/* 0x07fe */ { false, 0x07fe, 0x07fe }, +/* 0x07ff */ { false, 0x07ff, 0x07ff }, +/* 0x0800 */ { false, 0x0800, 0x0800 }, +/* 0x0801 */ { false, 0x0801, 0x0801 }, +/* 0x0802 */ { false, 0x0802, 0x0802 }, +/* 0x0803 */ { false, 0x0803, 0x0803 }, +/* 0x0804 */ { false, 0x0804, 0x0804 }, +/* 0x0805 */ { false, 0x0805, 0x0805 }, +/* 0x0806 */ { false, 0x0806, 0x0806 }, +/* 0x0807 */ { false, 0x0807, 0x0807 }, +/* 0x0808 */ { false, 0x0808, 0x0808 }, +/* 0x0809 */ { false, 0x0809, 0x0809 }, +/* 0x080a */ { false, 0x080a, 0x080a }, +/* 0x080b */ { false, 0x080b, 0x080b }, +/* 0x080c */ { false, 0x080c, 0x080c }, +/* 0x080d */ { false, 0x080d, 0x080d }, +/* 0x080e */ { false, 0x080e, 0x080e }, +/* 0x080f */ { false, 0x080f, 0x080f }, +/* 0x0810 */ { false, 0x0810, 0x0810 }, +/* 0x0811 */ { false, 0x0811, 0x0811 }, +/* 0x0812 */ { false, 0x0812, 0x0812 }, +/* 0x0813 */ { false, 0x0813, 0x0813 }, +/* 0x0814 */ { false, 0x0814, 0x0814 }, +/* 0x0815 */ { false, 0x0815, 0x0815 }, +/* 0x0816 */ { false, 0x0816, 0x0816 }, +/* 0x0817 */ { false, 0x0817, 0x0817 }, +/* 0x0818 */ { false, 0x0818, 0x0818 }, +/* 0x0819 */ { false, 0x0819, 0x0819 }, +/* 0x081a */ { false, 0x081a, 0x081a }, +/* 0x081b */ { false, 0x081b, 0x081b }, +/* 0x081c */ { false, 0x081c, 0x081c }, +/* 0x081d */ { false, 0x081d, 0x081d }, +/* 0x081e */ { false, 0x081e, 0x081e }, +/* 0x081f */ { false, 0x081f, 0x081f }, +/* 0x0820 */ { false, 0x0820, 0x0820 }, +/* 0x0821 */ { false, 0x0821, 0x0821 }, +/* 0x0822 */ { false, 0x0822, 0x0822 }, +/* 0x0823 */ { false, 0x0823, 0x0823 }, +/* 0x0824 */ { false, 0x0824, 0x0824 }, +/* 0x0825 */ { false, 0x0825, 0x0825 }, +/* 0x0826 */ { false, 0x0826, 0x0826 }, +/* 0x0827 */ { false, 0x0827, 0x0827 }, +/* 0x0828 */ { false, 0x0828, 0x0828 }, +/* 0x0829 */ { false, 0x0829, 0x0829 }, +/* 0x082a */ { false, 0x082a, 0x082a }, +/* 0x082b */ { false, 0x082b, 0x082b }, +/* 0x082c */ { false, 0x082c, 0x082c }, +/* 0x082d */ { false, 0x082d, 0x082d }, +/* 0x082e */ { false, 0x082e, 0x082e }, +/* 0x082f */ { false, 0x082f, 0x082f }, +/* 0x0830 */ { false, 0x0830, 0x0830 }, +/* 0x0831 */ { false, 0x0831, 0x0831 }, +/* 0x0832 */ { false, 0x0832, 0x0832 }, +/* 0x0833 */ { false, 0x0833, 0x0833 }, +/* 0x0834 */ { false, 0x0834, 0x0834 }, +/* 0x0835 */ { false, 0x0835, 0x0835 }, +/* 0x0836 */ { false, 0x0836, 0x0836 }, +/* 0x0837 */ { false, 0x0837, 0x0837 }, +/* 0x0838 */ { false, 0x0838, 0x0838 }, +/* 0x0839 */ { false, 0x0839, 0x0839 }, +/* 0x083a */ { false, 0x083a, 0x083a }, +/* 0x083b */ { false, 0x083b, 0x083b }, +/* 0x083c */ { false, 0x083c, 0x083c }, +/* 0x083d */ { false, 0x083d, 0x083d }, +/* 0x083e */ { false, 0x083e, 0x083e }, +/* 0x083f */ { false, 0x083f, 0x083f }, +/* 0x0840 */ { false, 0x0840, 0x0840 }, +/* 0x0841 */ { false, 0x0841, 0x0841 }, +/* 0x0842 */ { false, 0x0842, 0x0842 }, +/* 0x0843 */ { false, 0x0843, 0x0843 }, +/* 0x0844 */ { false, 0x0844, 0x0844 }, +/* 0x0845 */ { false, 0x0845, 0x0845 }, +/* 0x0846 */ { false, 0x0846, 0x0846 }, +/* 0x0847 */ { false, 0x0847, 0x0847 }, +/* 0x0848 */ { false, 0x0848, 0x0848 }, +/* 0x0849 */ { false, 0x0849, 0x0849 }, +/* 0x084a */ { false, 0x084a, 0x084a }, +/* 0x084b */ { false, 0x084b, 0x084b }, +/* 0x084c */ { false, 0x084c, 0x084c }, +/* 0x084d */ { false, 0x084d, 0x084d }, +/* 0x084e */ { false, 0x084e, 0x084e }, +/* 0x084f */ { false, 0x084f, 0x084f }, +/* 0x0850 */ { false, 0x0850, 0x0850 }, +/* 0x0851 */ { false, 0x0851, 0x0851 }, +/* 0x0852 */ { false, 0x0852, 0x0852 }, +/* 0x0853 */ { false, 0x0853, 0x0853 }, +/* 0x0854 */ { false, 0x0854, 0x0854 }, +/* 0x0855 */ { false, 0x0855, 0x0855 }, +/* 0x0856 */ { false, 0x0856, 0x0856 }, +/* 0x0857 */ { false, 0x0857, 0x0857 }, +/* 0x0858 */ { false, 0x0858, 0x0858 }, +/* 0x0859 */ { false, 0x0859, 0x0859 }, +/* 0x085a */ { false, 0x085a, 0x085a }, +/* 0x085b */ { false, 0x085b, 0x085b }, +/* 0x085c */ { false, 0x085c, 0x085c }, +/* 0x085d */ { false, 0x085d, 0x085d }, +/* 0x085e */ { false, 0x085e, 0x085e }, +/* 0x085f */ { false, 0x085f, 0x085f }, +/* 0x0860 */ { false, 0x0860, 0x0860 }, +/* 0x0861 */ { false, 0x0861, 0x0861 }, +/* 0x0862 */ { false, 0x0862, 0x0862 }, +/* 0x0863 */ { false, 0x0863, 0x0863 }, +/* 0x0864 */ { false, 0x0864, 0x0864 }, +/* 0x0865 */ { false, 0x0865, 0x0865 }, +/* 0x0866 */ { false, 0x0866, 0x0866 }, +/* 0x0867 */ { false, 0x0867, 0x0867 }, +/* 0x0868 */ { false, 0x0868, 0x0868 }, +/* 0x0869 */ { false, 0x0869, 0x0869 }, +/* 0x086a */ { false, 0x086a, 0x086a }, +/* 0x086b */ { false, 0x086b, 0x086b }, +/* 0x086c */ { false, 0x086c, 0x086c }, +/* 0x086d */ { false, 0x086d, 0x086d }, +/* 0x086e */ { false, 0x086e, 0x086e }, +/* 0x086f */ { false, 0x086f, 0x086f }, +/* 0x0870 */ { false, 0x0870, 0x0870 }, +/* 0x0871 */ { false, 0x0871, 0x0871 }, +/* 0x0872 */ { false, 0x0872, 0x0872 }, +/* 0x0873 */ { false, 0x0873, 0x0873 }, +/* 0x0874 */ { false, 0x0874, 0x0874 }, +/* 0x0875 */ { false, 0x0875, 0x0875 }, +/* 0x0876 */ { false, 0x0876, 0x0876 }, +/* 0x0877 */ { false, 0x0877, 0x0877 }, +/* 0x0878 */ { false, 0x0878, 0x0878 }, +/* 0x0879 */ { false, 0x0879, 0x0879 }, +/* 0x087a */ { false, 0x087a, 0x087a }, +/* 0x087b */ { false, 0x087b, 0x087b }, +/* 0x087c */ { false, 0x087c, 0x087c }, +/* 0x087d */ { false, 0x087d, 0x087d }, +/* 0x087e */ { false, 0x087e, 0x087e }, +/* 0x087f */ { false, 0x087f, 0x087f }, +/* 0x0880 */ { false, 0x0880, 0x0880 }, +/* 0x0881 */ { false, 0x0881, 0x0881 }, +/* 0x0882 */ { false, 0x0882, 0x0882 }, +/* 0x0883 */ { false, 0x0883, 0x0883 }, +/* 0x0884 */ { false, 0x0884, 0x0884 }, +/* 0x0885 */ { false, 0x0885, 0x0885 }, +/* 0x0886 */ { false, 0x0886, 0x0886 }, +/* 0x0887 */ { false, 0x0887, 0x0887 }, +/* 0x0888 */ { false, 0x0888, 0x0888 }, +/* 0x0889 */ { false, 0x0889, 0x0889 }, +/* 0x088a */ { false, 0x088a, 0x088a }, +/* 0x088b */ { false, 0x088b, 0x088b }, +/* 0x088c */ { false, 0x088c, 0x088c }, +/* 0x088d */ { false, 0x088d, 0x088d }, +/* 0x088e */ { false, 0x088e, 0x088e }, +/* 0x088f */ { false, 0x088f, 0x088f }, +/* 0x0890 */ { false, 0x0890, 0x0890 }, +/* 0x0891 */ { false, 0x0891, 0x0891 }, +/* 0x0892 */ { false, 0x0892, 0x0892 }, +/* 0x0893 */ { false, 0x0893, 0x0893 }, +/* 0x0894 */ { false, 0x0894, 0x0894 }, +/* 0x0895 */ { false, 0x0895, 0x0895 }, +/* 0x0896 */ { false, 0x0896, 0x0896 }, +/* 0x0897 */ { false, 0x0897, 0x0897 }, +/* 0x0898 */ { false, 0x0898, 0x0898 }, +/* 0x0899 */ { false, 0x0899, 0x0899 }, +/* 0x089a */ { false, 0x089a, 0x089a }, +/* 0x089b */ { false, 0x089b, 0x089b }, +/* 0x089c */ { false, 0x089c, 0x089c }, +/* 0x089d */ { false, 0x089d, 0x089d }, +/* 0x089e */ { false, 0x089e, 0x089e }, +/* 0x089f */ { false, 0x089f, 0x089f }, +/* 0x08a0 */ { false, 0x08a0, 0x08a0 }, +/* 0x08a1 */ { false, 0x08a1, 0x08a1 }, +/* 0x08a2 */ { false, 0x08a2, 0x08a2 }, +/* 0x08a3 */ { false, 0x08a3, 0x08a3 }, +/* 0x08a4 */ { false, 0x08a4, 0x08a4 }, +/* 0x08a5 */ { false, 0x08a5, 0x08a5 }, +/* 0x08a6 */ { false, 0x08a6, 0x08a6 }, +/* 0x08a7 */ { false, 0x08a7, 0x08a7 }, +/* 0x08a8 */ { false, 0x08a8, 0x08a8 }, +/* 0x08a9 */ { false, 0x08a9, 0x08a9 }, +/* 0x08aa */ { false, 0x08aa, 0x08aa }, +/* 0x08ab */ { false, 0x08ab, 0x08ab }, +/* 0x08ac */ { false, 0x08ac, 0x08ac }, +/* 0x08ad */ { false, 0x08ad, 0x08ad }, +/* 0x08ae */ { false, 0x08ae, 0x08ae }, +/* 0x08af */ { false, 0x08af, 0x08af }, +/* 0x08b0 */ { false, 0x08b0, 0x08b0 }, +/* 0x08b1 */ { false, 0x08b1, 0x08b1 }, +/* 0x08b2 */ { false, 0x08b2, 0x08b2 }, +/* 0x08b3 */ { false, 0x08b3, 0x08b3 }, +/* 0x08b4 */ { false, 0x08b4, 0x08b4 }, +/* 0x08b5 */ { false, 0x08b5, 0x08b5 }, +/* 0x08b6 */ { false, 0x08b6, 0x08b6 }, +/* 0x08b7 */ { false, 0x08b7, 0x08b7 }, +/* 0x08b8 */ { false, 0x08b8, 0x08b8 }, +/* 0x08b9 */ { false, 0x08b9, 0x08b9 }, +/* 0x08ba */ { false, 0x08ba, 0x08ba }, +/* 0x08bb */ { false, 0x08bb, 0x08bb }, +/* 0x08bc */ { false, 0x08bc, 0x08bc }, +/* 0x08bd */ { false, 0x08bd, 0x08bd }, +/* 0x08be */ { false, 0x08be, 0x08be }, +/* 0x08bf */ { false, 0x08bf, 0x08bf }, +/* 0x08c0 */ { false, 0x08c0, 0x08c0 }, +/* 0x08c1 */ { false, 0x08c1, 0x08c1 }, +/* 0x08c2 */ { false, 0x08c2, 0x08c2 }, +/* 0x08c3 */ { false, 0x08c3, 0x08c3 }, +/* 0x08c4 */ { false, 0x08c4, 0x08c4 }, +/* 0x08c5 */ { false, 0x08c5, 0x08c5 }, +/* 0x08c6 */ { false, 0x08c6, 0x08c6 }, +/* 0x08c7 */ { false, 0x08c7, 0x08c7 }, +/* 0x08c8 */ { false, 0x08c8, 0x08c8 }, +/* 0x08c9 */ { false, 0x08c9, 0x08c9 }, +/* 0x08ca */ { false, 0x08ca, 0x08ca }, +/* 0x08cb */ { false, 0x08cb, 0x08cb }, +/* 0x08cc */ { false, 0x08cc, 0x08cc }, +/* 0x08cd */ { false, 0x08cd, 0x08cd }, +/* 0x08ce */ { false, 0x08ce, 0x08ce }, +/* 0x08cf */ { false, 0x08cf, 0x08cf }, +/* 0x08d0 */ { false, 0x08d0, 0x08d0 }, +/* 0x08d1 */ { false, 0x08d1, 0x08d1 }, +/* 0x08d2 */ { false, 0x08d2, 0x08d2 }, +/* 0x08d3 */ { false, 0x08d3, 0x08d3 }, +/* 0x08d4 */ { false, 0x08d4, 0x08d4 }, +/* 0x08d5 */ { false, 0x08d5, 0x08d5 }, +/* 0x08d6 */ { false, 0x08d6, 0x08d6 }, +/* 0x08d7 */ { false, 0x08d7, 0x08d7 }, +/* 0x08d8 */ { false, 0x08d8, 0x08d8 }, +/* 0x08d9 */ { false, 0x08d9, 0x08d9 }, +/* 0x08da */ { false, 0x08da, 0x08da }, +/* 0x08db */ { false, 0x08db, 0x08db }, +/* 0x08dc */ { false, 0x08dc, 0x08dc }, +/* 0x08dd */ { false, 0x08dd, 0x08dd }, +/* 0x08de */ { false, 0x08de, 0x08de }, +/* 0x08df */ { false, 0x08df, 0x08df }, +/* 0x08e0 */ { false, 0x08e0, 0x08e0 }, +/* 0x08e1 */ { false, 0x08e1, 0x08e1 }, +/* 0x08e2 */ { false, 0x08e2, 0x08e2 }, +/* 0x08e3 */ { false, 0x08e3, 0x08e3 }, +/* 0x08e4 */ { false, 0x08e4, 0x08e4 }, +/* 0x08e5 */ { false, 0x08e5, 0x08e5 }, +/* 0x08e6 */ { false, 0x08e6, 0x08e6 }, +/* 0x08e7 */ { false, 0x08e7, 0x08e7 }, +/* 0x08e8 */ { false, 0x08e8, 0x08e8 }, +/* 0x08e9 */ { false, 0x08e9, 0x08e9 }, +/* 0x08ea */ { false, 0x08ea, 0x08ea }, +/* 0x08eb */ { false, 0x08eb, 0x08eb }, +/* 0x08ec */ { false, 0x08ec, 0x08ec }, +/* 0x08ed */ { false, 0x08ed, 0x08ed }, +/* 0x08ee */ { false, 0x08ee, 0x08ee }, +/* 0x08ef */ { false, 0x08ef, 0x08ef }, +/* 0x08f0 */ { false, 0x08f0, 0x08f0 }, +/* 0x08f1 */ { false, 0x08f1, 0x08f1 }, +/* 0x08f2 */ { false, 0x08f2, 0x08f2 }, +/* 0x08f3 */ { false, 0x08f3, 0x08f3 }, +/* 0x08f4 */ { false, 0x08f4, 0x08f4 }, +/* 0x08f5 */ { false, 0x08f5, 0x08f5 }, +/* 0x08f6 */ { false, 0x08f6, 0x08f6 }, +/* 0x08f7 */ { false, 0x08f7, 0x08f7 }, +/* 0x08f8 */ { false, 0x08f8, 0x08f8 }, +/* 0x08f9 */ { false, 0x08f9, 0x08f9 }, +/* 0x08fa */ { false, 0x08fa, 0x08fa }, +/* 0x08fb */ { false, 0x08fb, 0x08fb }, +/* 0x08fc */ { false, 0x08fc, 0x08fc }, +/* 0x08fd */ { false, 0x08fd, 0x08fd }, +/* 0x08fe */ { false, 0x08fe, 0x08fe }, +/* 0x08ff */ { false, 0x08ff, 0x08ff }, +/* 0x0900 */ { false, 0x0900, 0x0900 }, +/* 0x0901 */ { true, 0x0901, 0x0901 }, +/* 0x0902 */ { true, 0x0902, 0x0902 }, +/* 0x0903 */ { true, 0x0903, 0x0903 }, +/* 0x0904 */ { true, 0x0904, 0x0904 }, +/* 0x0905 */ { true, 0x0905, 0x0905 }, +/* 0x0906 */ { true, 0x0906, 0x0906 }, +/* 0x0907 */ { true, 0x0907, 0x0907 }, +/* 0x0908 */ { true, 0x0908, 0x0908 }, +/* 0x0909 */ { true, 0x0909, 0x0909 }, +/* 0x090a */ { true, 0x090a, 0x090a }, +/* 0x090b */ { true, 0x090b, 0x090b }, +/* 0x090c */ { true, 0x090c, 0x090c }, +/* 0x090d */ { true, 0x090d, 0x090d }, +/* 0x090e */ { true, 0x090e, 0x090e }, +/* 0x090f */ { true, 0x090f, 0x090f }, +/* 0x0910 */ { true, 0x0910, 0x0910 }, +/* 0x0911 */ { true, 0x0911, 0x0911 }, +/* 0x0912 */ { true, 0x0912, 0x0912 }, +/* 0x0913 */ { true, 0x0913, 0x0913 }, +/* 0x0914 */ { true, 0x0914, 0x0914 }, +/* 0x0915 */ { true, 0x0915, 0x0915 }, +/* 0x0916 */ { true, 0x0916, 0x0916 }, +/* 0x0917 */ { true, 0x0917, 0x0917 }, +/* 0x0918 */ { true, 0x0918, 0x0918 }, +/* 0x0919 */ { true, 0x0919, 0x0919 }, +/* 0x091a */ { true, 0x091a, 0x091a }, +/* 0x091b */ { true, 0x091b, 0x091b }, +/* 0x091c */ { true, 0x091c, 0x091c }, +/* 0x091d */ { true, 0x091d, 0x091d }, +/* 0x091e */ { true, 0x091e, 0x091e }, +/* 0x091f */ { true, 0x091f, 0x091f }, +/* 0x0920 */ { true, 0x0920, 0x0920 }, +/* 0x0921 */ { true, 0x0921, 0x0921 }, +/* 0x0922 */ { true, 0x0922, 0x0922 }, +/* 0x0923 */ { true, 0x0923, 0x0923 }, +/* 0x0924 */ { true, 0x0924, 0x0924 }, +/* 0x0925 */ { true, 0x0925, 0x0925 }, +/* 0x0926 */ { true, 0x0926, 0x0926 }, +/* 0x0927 */ { true, 0x0927, 0x0927 }, +/* 0x0928 */ { true, 0x0928, 0x0928 }, +/* 0x0929 */ { true, 0x0929, 0x0929 }, +/* 0x092a */ { true, 0x092a, 0x092a }, +/* 0x092b */ { true, 0x092b, 0x092b }, +/* 0x092c */ { true, 0x092c, 0x092c }, +/* 0x092d */ { true, 0x092d, 0x092d }, +/* 0x092e */ { true, 0x092e, 0x092e }, +/* 0x092f */ { true, 0x092f, 0x092f }, +/* 0x0930 */ { true, 0x0930, 0x0930 }, +/* 0x0931 */ { true, 0x0931, 0x0931 }, +/* 0x0932 */ { true, 0x0932, 0x0932 }, +/* 0x0933 */ { true, 0x0933, 0x0933 }, +/* 0x0934 */ { true, 0x0934, 0x0934 }, +/* 0x0935 */ { true, 0x0935, 0x0935 }, +/* 0x0936 */ { true, 0x0936, 0x0936 }, +/* 0x0937 */ { true, 0x0937, 0x0937 }, +/* 0x0938 */ { true, 0x0938, 0x0938 }, +/* 0x0939 */ { true, 0x0939, 0x0939 }, +/* 0x093a */ { false, 0x093a, 0x093a }, +/* 0x093b */ { true, 0x093b, 0x093b }, +/* 0x093c */ { true, 0x093c, 0x093c }, +/* 0x093d */ { true, 0x093d, 0x093d }, +/* 0x093e */ { true, 0x093e, 0x093e }, +/* 0x093f */ { true, 0x093f, 0x093f }, +/* 0x0940 */ { true, 0x0940, 0x0940 }, +/* 0x0941 */ { true, 0x0941, 0x0941 }, +/* 0x0942 */ { true, 0x0942, 0x0942 }, +/* 0x0943 */ { true, 0x0943, 0x0943 }, +/* 0x0944 */ { true, 0x0944, 0x0944 }, +/* 0x0945 */ { true, 0x0945, 0x0945 }, +/* 0x0946 */ { true, 0x0946, 0x0946 }, +/* 0x0947 */ { true, 0x0947, 0x0947 }, +/* 0x0948 */ { true, 0x0948, 0x0948 }, +/* 0x0949 */ { true, 0x0949, 0x0949 }, +/* 0x094a */ { true, 0x094a, 0x094a }, +/* 0x094b */ { true, 0x094b, 0x094b }, +/* 0x094c */ { true, 0x094c, 0x094c }, +/* 0x094d */ { true, 0x094d, 0x094d }, +/* 0x094e */ { true, 0x094e, 0x094e }, +/* 0x094f */ { true, 0x094f, 0x094f }, +/* 0x0950 */ { true, 0x0950, 0x0950 }, +/* 0x0951 */ { true, 0x0951, 0x0951 }, +/* 0x0952 */ { true, 0x0952, 0x0952 }, +/* 0x0953 */ { true, 0x0953, 0x0953 }, +/* 0x0954 */ { true, 0x0954, 0x0954 }, +/* 0x0955 */ { false, 0x0955, 0x0955 }, +/* 0x0956 */ { false, 0x0956, 0x0956 }, +/* 0x0957 */ { false, 0x0957, 0x0957 }, +/* 0x0958 */ { true, 0x0958, 0x0958 }, +/* 0x0959 */ { true, 0x0959, 0x0959 }, +/* 0x095a */ { true, 0x095a, 0x095a }, +/* 0x095b */ { true, 0x095b, 0x095b }, +/* 0x095c */ { true, 0x095c, 0x095c }, +/* 0x095d */ { true, 0x095d, 0x095d }, +/* 0x095e */ { true, 0x095e, 0x095e }, +/* 0x095f */ { true, 0x095f, 0x095f }, +/* 0x0960 */ { true, 0x0960, 0x0960 }, +/* 0x0961 */ { true, 0x0961, 0x0961 }, +/* 0x0962 */ { true, 0x0962, 0x0962 }, +/* 0x0963 */ { true, 0x0963, 0x0963 }, +/* 0x0964 */ { false, 0x0964, 0x0964 }, +/* 0x0965 */ { false, 0x0965, 0x0965 }, +/* 0x0966 */ { false, 0x0966, 0x0966 }, +/* 0x0967 */ { false, 0x0967, 0x0967 }, +/* 0x0968 */ { false, 0x0968, 0x0968 }, +/* 0x0969 */ { false, 0x0969, 0x0969 }, +/* 0x096a */ { false, 0x096a, 0x096a }, +/* 0x096b */ { false, 0x096b, 0x096b }, +/* 0x096c */ { false, 0x096c, 0x096c }, +/* 0x096d */ { false, 0x096d, 0x096d }, +/* 0x096e */ { false, 0x096e, 0x096e }, +/* 0x096f */ { false, 0x096f, 0x096f }, +/* 0x0970 */ { false, 0x0970, 0x0970 }, +/* 0x0971 */ { false, 0x0971, 0x0971 }, +/* 0x0972 */ { false, 0x0972, 0x0972 }, +/* 0x0973 */ { false, 0x0973, 0x0973 }, +/* 0x0974 */ { false, 0x0974, 0x0974 }, +/* 0x0975 */ { false, 0x0975, 0x0975 }, +/* 0x0976 */ { false, 0x0976, 0x0976 }, +/* 0x0977 */ { false, 0x0977, 0x0977 }, +/* 0x0978 */ { false, 0x0978, 0x0978 }, +/* 0x0979 */ { false, 0x0979, 0x0979 }, +/* 0x097a */ { false, 0x097a, 0x097a }, +/* 0x097b */ { false, 0x097b, 0x097b }, +/* 0x097c */ { false, 0x097c, 0x097c }, +/* 0x097d */ { true, 0x097d, 0x097d }, +/* 0x097e */ { false, 0x097e, 0x097e }, +/* 0x097f */ { false, 0x097f, 0x097f }, +/* 0x0980 */ { false, 0x0980, 0x0980 }, +/* 0x0981 */ { true, 0x0981, 0x0981 }, +/* 0x0982 */ { true, 0x0982, 0x0982 }, +/* 0x0983 */ { true, 0x0983, 0x0983 }, +/* 0x0984 */ { false, 0x0984, 0x0984 }, +/* 0x0985 */ { true, 0x0985, 0x0985 }, +/* 0x0986 */ { true, 0x0986, 0x0986 }, +/* 0x0987 */ { true, 0x0987, 0x0987 }, +/* 0x0988 */ { true, 0x0988, 0x0988 }, +/* 0x0989 */ { true, 0x0989, 0x0989 }, +/* 0x098a */ { true, 0x098a, 0x098a }, +/* 0x098b */ { true, 0x098b, 0x098b }, +/* 0x098c */ { true, 0x098c, 0x098c }, +/* 0x098d */ { false, 0x098d, 0x098d }, +/* 0x098e */ { false, 0x098e, 0x098e }, +/* 0x098f */ { true, 0x098f, 0x098f }, +/* 0x0990 */ { true, 0x0990, 0x0990 }, +/* 0x0991 */ { false, 0x0991, 0x0991 }, +/* 0x0992 */ { false, 0x0992, 0x0992 }, +/* 0x0993 */ { true, 0x0993, 0x0993 }, +/* 0x0994 */ { true, 0x0994, 0x0994 }, +/* 0x0995 */ { true, 0x0995, 0x0995 }, +/* 0x0996 */ { true, 0x0996, 0x0996 }, +/* 0x0997 */ { true, 0x0997, 0x0997 }, +/* 0x0998 */ { true, 0x0998, 0x0998 }, +/* 0x0999 */ { true, 0x0999, 0x0999 }, +/* 0x099a */ { true, 0x099a, 0x099a }, +/* 0x099b */ { true, 0x099b, 0x099b }, +/* 0x099c */ { true, 0x099c, 0x099c }, +/* 0x099d */ { true, 0x099d, 0x099d }, +/* 0x099e */ { true, 0x099e, 0x099e }, +/* 0x099f */ { true, 0x099f, 0x099f }, +/* 0x09a0 */ { true, 0x09a0, 0x09a0 }, +/* 0x09a1 */ { true, 0x09a1, 0x09a1 }, +/* 0x09a2 */ { true, 0x09a2, 0x09a2 }, +/* 0x09a3 */ { true, 0x09a3, 0x09a3 }, +/* 0x09a4 */ { true, 0x09a4, 0x09a4 }, +/* 0x09a5 */ { true, 0x09a5, 0x09a5 }, +/* 0x09a6 */ { true, 0x09a6, 0x09a6 }, +/* 0x09a7 */ { true, 0x09a7, 0x09a7 }, +/* 0x09a8 */ { true, 0x09a8, 0x09a8 }, +/* 0x09a9 */ { false, 0x09a9, 0x09a9 }, +/* 0x09aa */ { true, 0x09aa, 0x09aa }, +/* 0x09ab */ { true, 0x09ab, 0x09ab }, +/* 0x09ac */ { true, 0x09ac, 0x09ac }, +/* 0x09ad */ { true, 0x09ad, 0x09ad }, +/* 0x09ae */ { true, 0x09ae, 0x09ae }, +/* 0x09af */ { true, 0x09af, 0x09af }, +/* 0x09b0 */ { true, 0x09b0, 0x09b0 }, +/* 0x09b1 */ { false, 0x09b1, 0x09b1 }, +/* 0x09b2 */ { true, 0x09b2, 0x09b2 }, +/* 0x09b3 */ { false, 0x09b3, 0x09b3 }, +/* 0x09b4 */ { false, 0x09b4, 0x09b4 }, +/* 0x09b5 */ { false, 0x09b5, 0x09b5 }, +/* 0x09b6 */ { true, 0x09b6, 0x09b6 }, +/* 0x09b7 */ { true, 0x09b7, 0x09b7 }, +/* 0x09b8 */ { true, 0x09b8, 0x09b8 }, +/* 0x09b9 */ { true, 0x09b9, 0x09b9 }, +/* 0x09ba */ { false, 0x09ba, 0x09ba }, +/* 0x09bb */ { false, 0x09bb, 0x09bb }, +/* 0x09bc */ { true, 0x09bc, 0x09bc }, +/* 0x09bd */ { true, 0x09bd, 0x09bd }, +/* 0x09be */ { true, 0x09be, 0x09be }, +/* 0x09bf */ { true, 0x09bf, 0x09bf }, +/* 0x09c0 */ { true, 0x09c0, 0x09c0 }, +/* 0x09c1 */ { true, 0x09c1, 0x09c1 }, +/* 0x09c2 */ { true, 0x09c2, 0x09c2 }, +/* 0x09c3 */ { true, 0x09c3, 0x09c3 }, +/* 0x09c4 */ { true, 0x09c4, 0x09c4 }, +/* 0x09c5 */ { false, 0x09c5, 0x09c5 }, +/* 0x09c6 */ { false, 0x09c6, 0x09c6 }, +/* 0x09c7 */ { true, 0x09c7, 0x09c7 }, +/* 0x09c8 */ { true, 0x09c8, 0x09c8 }, +/* 0x09c9 */ { false, 0x09c9, 0x09c9 }, +/* 0x09ca */ { false, 0x09ca, 0x09ca }, +/* 0x09cb */ { true, 0x09cb, 0x09cb }, +/* 0x09cc */ { true, 0x09cc, 0x09cc }, +/* 0x09cd */ { true, 0x09cd, 0x09cd }, +/* 0x09ce */ { true, 0x09ce, 0x09ce }, +/* 0x09cf */ { false, 0x09cf, 0x09cf }, +/* 0x09d0 */ { false, 0x09d0, 0x09d0 }, +/* 0x09d1 */ { false, 0x09d1, 0x09d1 }, +/* 0x09d2 */ { false, 0x09d2, 0x09d2 }, +/* 0x09d3 */ { false, 0x09d3, 0x09d3 }, +/* 0x09d4 */ { false, 0x09d4, 0x09d4 }, +/* 0x09d5 */ { false, 0x09d5, 0x09d5 }, +/* 0x09d6 */ { false, 0x09d6, 0x09d6 }, +/* 0x09d7 */ { true, 0x09d7, 0x09d7 }, +/* 0x09d8 */ { false, 0x09d8, 0x09d8 }, +/* 0x09d9 */ { false, 0x09d9, 0x09d9 }, +/* 0x09da */ { false, 0x09da, 0x09da }, +/* 0x09db */ { false, 0x09db, 0x09db }, +/* 0x09dc */ { true, 0x09dc, 0x09dc }, +/* 0x09dd */ { true, 0x09dd, 0x09dd }, +/* 0x09de */ { false, 0x09de, 0x09de }, +/* 0x09df */ { true, 0x09df, 0x09df }, +/* 0x09e0 */ { true, 0x09e0, 0x09e0 }, +/* 0x09e1 */ { true, 0x09e1, 0x09e1 }, +/* 0x09e2 */ { true, 0x09e2, 0x09e2 }, +/* 0x09e3 */ { true, 0x09e3, 0x09e3 }, +/* 0x09e4 */ { false, 0x09e4, 0x09e4 }, +/* 0x09e5 */ { false, 0x09e5, 0x09e5 }, +/* 0x09e6 */ { false, 0x09e6, 0x09e6 }, +/* 0x09e7 */ { false, 0x09e7, 0x09e7 }, +/* 0x09e8 */ { false, 0x09e8, 0x09e8 }, +/* 0x09e9 */ { false, 0x09e9, 0x09e9 }, +/* 0x09ea */ { false, 0x09ea, 0x09ea }, +/* 0x09eb */ { false, 0x09eb, 0x09eb }, +/* 0x09ec */ { false, 0x09ec, 0x09ec }, +/* 0x09ed */ { false, 0x09ed, 0x09ed }, +/* 0x09ee */ { false, 0x09ee, 0x09ee }, +/* 0x09ef */ { false, 0x09ef, 0x09ef }, +/* 0x09f0 */ { true, 0x09f0, 0x09f0 }, +/* 0x09f1 */ { true, 0x09f1, 0x09f1 }, +/* 0x09f2 */ { false, 0x09f2, 0x09f2 }, +/* 0x09f3 */ { false, 0x09f3, 0x09f3 }, +/* 0x09f4 */ { false, 0x09f4, 0x09f4 }, +/* 0x09f5 */ { false, 0x09f5, 0x09f5 }, +/* 0x09f6 */ { false, 0x09f6, 0x09f6 }, +/* 0x09f7 */ { false, 0x09f7, 0x09f7 }, +/* 0x09f8 */ { false, 0x09f8, 0x09f8 }, +/* 0x09f9 */ { false, 0x09f9, 0x09f9 }, +/* 0x09fa */ { false, 0x09fa, 0x09fa }, +/* 0x09fb */ { false, 0x09fb, 0x09fb }, +/* 0x09fc */ { false, 0x09fc, 0x09fc }, +/* 0x09fd */ { false, 0x09fd, 0x09fd }, +/* 0x09fe */ { false, 0x09fe, 0x09fe }, +/* 0x09ff */ { false, 0x09ff, 0x09ff }, +/* 0x0a00 */ { false, 0x0a00, 0x0a00 }, +/* 0x0a01 */ { true, 0x0a01, 0x0a01 }, +/* 0x0a02 */ { true, 0x0a02, 0x0a02 }, +/* 0x0a03 */ { true, 0x0a03, 0x0a03 }, +/* 0x0a04 */ { false, 0x0a04, 0x0a04 }, +/* 0x0a05 */ { true, 0x0a05, 0x0a05 }, +/* 0x0a06 */ { true, 0x0a06, 0x0a06 }, +/* 0x0a07 */ { true, 0x0a07, 0x0a07 }, +/* 0x0a08 */ { true, 0x0a08, 0x0a08 }, +/* 0x0a09 */ { true, 0x0a09, 0x0a09 }, +/* 0x0a0a */ { true, 0x0a0a, 0x0a0a }, +/* 0x0a0b */ { false, 0x0a0b, 0x0a0b }, +/* 0x0a0c */ { false, 0x0a0c, 0x0a0c }, +/* 0x0a0d */ { false, 0x0a0d, 0x0a0d }, +/* 0x0a0e */ { false, 0x0a0e, 0x0a0e }, +/* 0x0a0f */ { true, 0x0a0f, 0x0a0f }, +/* 0x0a10 */ { true, 0x0a10, 0x0a10 }, +/* 0x0a11 */ { false, 0x0a11, 0x0a11 }, +/* 0x0a12 */ { false, 0x0a12, 0x0a12 }, +/* 0x0a13 */ { true, 0x0a13, 0x0a13 }, +/* 0x0a14 */ { true, 0x0a14, 0x0a14 }, +/* 0x0a15 */ { true, 0x0a15, 0x0a15 }, +/* 0x0a16 */ { true, 0x0a16, 0x0a16 }, +/* 0x0a17 */ { true, 0x0a17, 0x0a17 }, +/* 0x0a18 */ { true, 0x0a18, 0x0a18 }, +/* 0x0a19 */ { true, 0x0a19, 0x0a19 }, +/* 0x0a1a */ { true, 0x0a1a, 0x0a1a }, +/* 0x0a1b */ { true, 0x0a1b, 0x0a1b }, +/* 0x0a1c */ { true, 0x0a1c, 0x0a1c }, +/* 0x0a1d */ { true, 0x0a1d, 0x0a1d }, +/* 0x0a1e */ { true, 0x0a1e, 0x0a1e }, +/* 0x0a1f */ { true, 0x0a1f, 0x0a1f }, +/* 0x0a20 */ { true, 0x0a20, 0x0a20 }, +/* 0x0a21 */ { true, 0x0a21, 0x0a21 }, +/* 0x0a22 */ { true, 0x0a22, 0x0a22 }, +/* 0x0a23 */ { true, 0x0a23, 0x0a23 }, +/* 0x0a24 */ { true, 0x0a24, 0x0a24 }, +/* 0x0a25 */ { true, 0x0a25, 0x0a25 }, +/* 0x0a26 */ { true, 0x0a26, 0x0a26 }, +/* 0x0a27 */ { true, 0x0a27, 0x0a27 }, +/* 0x0a28 */ { true, 0x0a28, 0x0a28 }, +/* 0x0a29 */ { false, 0x0a29, 0x0a29 }, +/* 0x0a2a */ { true, 0x0a2a, 0x0a2a }, +/* 0x0a2b */ { true, 0x0a2b, 0x0a2b }, +/* 0x0a2c */ { true, 0x0a2c, 0x0a2c }, +/* 0x0a2d */ { true, 0x0a2d, 0x0a2d }, +/* 0x0a2e */ { true, 0x0a2e, 0x0a2e }, +/* 0x0a2f */ { true, 0x0a2f, 0x0a2f }, +/* 0x0a30 */ { true, 0x0a30, 0x0a30 }, +/* 0x0a31 */ { false, 0x0a31, 0x0a31 }, +/* 0x0a32 */ { true, 0x0a32, 0x0a32 }, +/* 0x0a33 */ { true, 0x0a33, 0x0a33 }, +/* 0x0a34 */ { false, 0x0a34, 0x0a34 }, +/* 0x0a35 */ { true, 0x0a35, 0x0a35 }, +/* 0x0a36 */ { true, 0x0a36, 0x0a36 }, +/* 0x0a37 */ { false, 0x0a37, 0x0a37 }, +/* 0x0a38 */ { true, 0x0a38, 0x0a38 }, +/* 0x0a39 */ { true, 0x0a39, 0x0a39 }, +/* 0x0a3a */ { false, 0x0a3a, 0x0a3a }, +/* 0x0a3b */ { false, 0x0a3b, 0x0a3b }, +/* 0x0a3c */ { true, 0x0a3c, 0x0a3c }, +/* 0x0a3d */ { false, 0x0a3d, 0x0a3d }, +/* 0x0a3e */ { true, 0x0a3e, 0x0a3e }, +/* 0x0a3f */ { true, 0x0a3f, 0x0a3f }, +/* 0x0a40 */ { true, 0x0a40, 0x0a40 }, +/* 0x0a41 */ { true, 0x0a41, 0x0a41 }, +/* 0x0a42 */ { true, 0x0a42, 0x0a42 }, +/* 0x0a43 */ { false, 0x0a43, 0x0a43 }, +/* 0x0a44 */ { false, 0x0a44, 0x0a44 }, +/* 0x0a45 */ { false, 0x0a45, 0x0a45 }, +/* 0x0a46 */ { false, 0x0a46, 0x0a46 }, +/* 0x0a47 */ { true, 0x0a47, 0x0a47 }, +/* 0x0a48 */ { true, 0x0a48, 0x0a48 }, +/* 0x0a49 */ { false, 0x0a49, 0x0a49 }, +/* 0x0a4a */ { false, 0x0a4a, 0x0a4a }, +/* 0x0a4b */ { true, 0x0a4b, 0x0a4b }, +/* 0x0a4c */ { true, 0x0a4c, 0x0a4c }, +/* 0x0a4d */ { true, 0x0a4d, 0x0a4d }, +/* 0x0a4e */ { false, 0x0a4e, 0x0a4e }, +/* 0x0a4f */ { false, 0x0a4f, 0x0a4f }, +/* 0x0a50 */ { false, 0x0a50, 0x0a50 }, +/* 0x0a51 */ { false, 0x0a51, 0x0a51 }, +/* 0x0a52 */ { false, 0x0a52, 0x0a52 }, +/* 0x0a53 */ { false, 0x0a53, 0x0a53 }, +/* 0x0a54 */ { false, 0x0a54, 0x0a54 }, +/* 0x0a55 */ { false, 0x0a55, 0x0a55 }, +/* 0x0a56 */ { false, 0x0a56, 0x0a56 }, +/* 0x0a57 */ { false, 0x0a57, 0x0a57 }, +/* 0x0a58 */ { false, 0x0a58, 0x0a58 }, +/* 0x0a59 */ { true, 0x0a59, 0x0a59 }, +/* 0x0a5a */ { true, 0x0a5a, 0x0a5a }, +/* 0x0a5b */ { true, 0x0a5b, 0x0a5b }, +/* 0x0a5c */ { true, 0x0a5c, 0x0a5c }, +/* 0x0a5d */ { false, 0x0a5d, 0x0a5d }, +/* 0x0a5e */ { true, 0x0a5e, 0x0a5e }, +/* 0x0a5f */ { false, 0x0a5f, 0x0a5f }, +/* 0x0a60 */ { false, 0x0a60, 0x0a60 }, +/* 0x0a61 */ { false, 0x0a61, 0x0a61 }, +/* 0x0a62 */ { false, 0x0a62, 0x0a62 }, +/* 0x0a63 */ { false, 0x0a63, 0x0a63 }, +/* 0x0a64 */ { false, 0x0a64, 0x0a64 }, +/* 0x0a65 */ { false, 0x0a65, 0x0a65 }, +/* 0x0a66 */ { false, 0x0a66, 0x0a66 }, +/* 0x0a67 */ { false, 0x0a67, 0x0a67 }, +/* 0x0a68 */ { false, 0x0a68, 0x0a68 }, +/* 0x0a69 */ { false, 0x0a69, 0x0a69 }, +/* 0x0a6a */ { false, 0x0a6a, 0x0a6a }, +/* 0x0a6b */ { false, 0x0a6b, 0x0a6b }, +/* 0x0a6c */ { false, 0x0a6c, 0x0a6c }, +/* 0x0a6d */ { false, 0x0a6d, 0x0a6d }, +/* 0x0a6e */ { false, 0x0a6e, 0x0a6e }, +/* 0x0a6f */ { false, 0x0a6f, 0x0a6f }, +/* 0x0a70 */ { true, 0x0a70, 0x0a70 }, +/* 0x0a71 */ { true, 0x0a71, 0x0a71 }, +/* 0x0a72 */ { true, 0x0a72, 0x0a72 }, +/* 0x0a73 */ { true, 0x0a73, 0x0a73 }, +/* 0x0a74 */ { true, 0x0a74, 0x0a74 }, +/* 0x0a75 */ { false, 0x0a75, 0x0a75 }, +/* 0x0a76 */ { false, 0x0a76, 0x0a76 }, +/* 0x0a77 */ { false, 0x0a77, 0x0a77 }, +/* 0x0a78 */ { false, 0x0a78, 0x0a78 }, +/* 0x0a79 */ { false, 0x0a79, 0x0a79 }, +/* 0x0a7a */ { false, 0x0a7a, 0x0a7a }, +/* 0x0a7b */ { false, 0x0a7b, 0x0a7b }, +/* 0x0a7c */ { false, 0x0a7c, 0x0a7c }, +/* 0x0a7d */ { false, 0x0a7d, 0x0a7d }, +/* 0x0a7e */ { false, 0x0a7e, 0x0a7e }, +/* 0x0a7f */ { false, 0x0a7f, 0x0a7f }, +/* 0x0a80 */ { false, 0x0a80, 0x0a80 }, +/* 0x0a81 */ { true, 0x0a81, 0x0a81 }, +/* 0x0a82 */ { true, 0x0a82, 0x0a82 }, +/* 0x0a83 */ { true, 0x0a83, 0x0a83 }, +/* 0x0a84 */ { false, 0x0a84, 0x0a84 }, +/* 0x0a85 */ { true, 0x0a85, 0x0a85 }, +/* 0x0a86 */ { true, 0x0a86, 0x0a86 }, +/* 0x0a87 */ { true, 0x0a87, 0x0a87 }, +/* 0x0a88 */ { true, 0x0a88, 0x0a88 }, +/* 0x0a89 */ { true, 0x0a89, 0x0a89 }, +/* 0x0a8a */ { true, 0x0a8a, 0x0a8a }, +/* 0x0a8b */ { true, 0x0a8b, 0x0a8b }, +/* 0x0a8c */ { true, 0x0a8c, 0x0a8c }, +/* 0x0a8d */ { true, 0x0a8d, 0x0a8d }, +/* 0x0a8e */ { false, 0x0a8e, 0x0a8e }, +/* 0x0a8f */ { true, 0x0a8f, 0x0a8f }, +/* 0x0a90 */ { true, 0x0a90, 0x0a90 }, +/* 0x0a91 */ { true, 0x0a91, 0x0a91 }, +/* 0x0a92 */ { false, 0x0a92, 0x0a92 }, +/* 0x0a93 */ { true, 0x0a93, 0x0a93 }, +/* 0x0a94 */ { true, 0x0a94, 0x0a94 }, +/* 0x0a95 */ { true, 0x0a95, 0x0a95 }, +/* 0x0a96 */ { true, 0x0a96, 0x0a96 }, +/* 0x0a97 */ { true, 0x0a97, 0x0a97 }, +/* 0x0a98 */ { true, 0x0a98, 0x0a98 }, +/* 0x0a99 */ { true, 0x0a99, 0x0a99 }, +/* 0x0a9a */ { true, 0x0a9a, 0x0a9a }, +/* 0x0a9b */ { true, 0x0a9b, 0x0a9b }, +/* 0x0a9c */ { true, 0x0a9c, 0x0a9c }, +/* 0x0a9d */ { true, 0x0a9d, 0x0a9d }, +/* 0x0a9e */ { true, 0x0a9e, 0x0a9e }, +/* 0x0a9f */ { true, 0x0a9f, 0x0a9f }, +/* 0x0aa0 */ { true, 0x0aa0, 0x0aa0 }, +/* 0x0aa1 */ { true, 0x0aa1, 0x0aa1 }, +/* 0x0aa2 */ { true, 0x0aa2, 0x0aa2 }, +/* 0x0aa3 */ { true, 0x0aa3, 0x0aa3 }, +/* 0x0aa4 */ { true, 0x0aa4, 0x0aa4 }, +/* 0x0aa5 */ { true, 0x0aa5, 0x0aa5 }, +/* 0x0aa6 */ { true, 0x0aa6, 0x0aa6 }, +/* 0x0aa7 */ { true, 0x0aa7, 0x0aa7 }, +/* 0x0aa8 */ { true, 0x0aa8, 0x0aa8 }, +/* 0x0aa9 */ { false, 0x0aa9, 0x0aa9 }, +/* 0x0aaa */ { true, 0x0aaa, 0x0aaa }, +/* 0x0aab */ { true, 0x0aab, 0x0aab }, +/* 0x0aac */ { true, 0x0aac, 0x0aac }, +/* 0x0aad */ { true, 0x0aad, 0x0aad }, +/* 0x0aae */ { true, 0x0aae, 0x0aae }, +/* 0x0aaf */ { true, 0x0aaf, 0x0aaf }, +/* 0x0ab0 */ { true, 0x0ab0, 0x0ab0 }, +/* 0x0ab1 */ { false, 0x0ab1, 0x0ab1 }, +/* 0x0ab2 */ { true, 0x0ab2, 0x0ab2 }, +/* 0x0ab3 */ { true, 0x0ab3, 0x0ab3 }, +/* 0x0ab4 */ { false, 0x0ab4, 0x0ab4 }, +/* 0x0ab5 */ { true, 0x0ab5, 0x0ab5 }, +/* 0x0ab6 */ { true, 0x0ab6, 0x0ab6 }, +/* 0x0ab7 */ { true, 0x0ab7, 0x0ab7 }, +/* 0x0ab8 */ { true, 0x0ab8, 0x0ab8 }, +/* 0x0ab9 */ { true, 0x0ab9, 0x0ab9 }, +/* 0x0aba */ { false, 0x0aba, 0x0aba }, +/* 0x0abb */ { false, 0x0abb, 0x0abb }, +/* 0x0abc */ { true, 0x0abc, 0x0abc }, +/* 0x0abd */ { true, 0x0abd, 0x0abd }, +/* 0x0abe */ { true, 0x0abe, 0x0abe }, +/* 0x0abf */ { true, 0x0abf, 0x0abf }, +/* 0x0ac0 */ { true, 0x0ac0, 0x0ac0 }, +/* 0x0ac1 */ { true, 0x0ac1, 0x0ac1 }, +/* 0x0ac2 */ { true, 0x0ac2, 0x0ac2 }, +/* 0x0ac3 */ { true, 0x0ac3, 0x0ac3 }, +/* 0x0ac4 */ { true, 0x0ac4, 0x0ac4 }, +/* 0x0ac5 */ { true, 0x0ac5, 0x0ac5 }, +/* 0x0ac6 */ { false, 0x0ac6, 0x0ac6 }, +/* 0x0ac7 */ { true, 0x0ac7, 0x0ac7 }, +/* 0x0ac8 */ { true, 0x0ac8, 0x0ac8 }, +/* 0x0ac9 */ { true, 0x0ac9, 0x0ac9 }, +/* 0x0aca */ { false, 0x0aca, 0x0aca }, +/* 0x0acb */ { true, 0x0acb, 0x0acb }, +/* 0x0acc */ { true, 0x0acc, 0x0acc }, +/* 0x0acd */ { true, 0x0acd, 0x0acd }, +/* 0x0ace */ { false, 0x0ace, 0x0ace }, +/* 0x0acf */ { false, 0x0acf, 0x0acf }, +/* 0x0ad0 */ { true, 0x0ad0, 0x0ad0 }, +/* 0x0ad1 */ { false, 0x0ad1, 0x0ad1 }, +/* 0x0ad2 */ { false, 0x0ad2, 0x0ad2 }, +/* 0x0ad3 */ { false, 0x0ad3, 0x0ad3 }, +/* 0x0ad4 */ { false, 0x0ad4, 0x0ad4 }, +/* 0x0ad5 */ { false, 0x0ad5, 0x0ad5 }, +/* 0x0ad6 */ { false, 0x0ad6, 0x0ad6 }, +/* 0x0ad7 */ { false, 0x0ad7, 0x0ad7 }, +/* 0x0ad8 */ { false, 0x0ad8, 0x0ad8 }, +/* 0x0ad9 */ { false, 0x0ad9, 0x0ad9 }, +/* 0x0ada */ { false, 0x0ada, 0x0ada }, +/* 0x0adb */ { false, 0x0adb, 0x0adb }, +/* 0x0adc */ { false, 0x0adc, 0x0adc }, +/* 0x0add */ { false, 0x0add, 0x0add }, +/* 0x0ade */ { false, 0x0ade, 0x0ade }, +/* 0x0adf */ { false, 0x0adf, 0x0adf }, +/* 0x0ae0 */ { true, 0x0ae0, 0x0ae0 }, +/* 0x0ae1 */ { true, 0x0ae1, 0x0ae1 }, +/* 0x0ae2 */ { true, 0x0ae2, 0x0ae2 }, +/* 0x0ae3 */ { true, 0x0ae3, 0x0ae3 }, +/* 0x0ae4 */ { false, 0x0ae4, 0x0ae4 }, +/* 0x0ae5 */ { false, 0x0ae5, 0x0ae5 }, +/* 0x0ae6 */ { false, 0x0ae6, 0x0ae6 }, +/* 0x0ae7 */ { false, 0x0ae7, 0x0ae7 }, +/* 0x0ae8 */ { false, 0x0ae8, 0x0ae8 }, +/* 0x0ae9 */ { false, 0x0ae9, 0x0ae9 }, +/* 0x0aea */ { false, 0x0aea, 0x0aea }, +/* 0x0aeb */ { false, 0x0aeb, 0x0aeb }, +/* 0x0aec */ { false, 0x0aec, 0x0aec }, +/* 0x0aed */ { false, 0x0aed, 0x0aed }, +/* 0x0aee */ { false, 0x0aee, 0x0aee }, +/* 0x0aef */ { false, 0x0aef, 0x0aef }, +/* 0x0af0 */ { false, 0x0af0, 0x0af0 }, +/* 0x0af1 */ { false, 0x0af1, 0x0af1 }, +/* 0x0af2 */ { false, 0x0af2, 0x0af2 }, +/* 0x0af3 */ { false, 0x0af3, 0x0af3 }, +/* 0x0af4 */ { false, 0x0af4, 0x0af4 }, +/* 0x0af5 */ { false, 0x0af5, 0x0af5 }, +/* 0x0af6 */ { false, 0x0af6, 0x0af6 }, +/* 0x0af7 */ { false, 0x0af7, 0x0af7 }, +/* 0x0af8 */ { false, 0x0af8, 0x0af8 }, +/* 0x0af9 */ { false, 0x0af9, 0x0af9 }, +/* 0x0afa */ { false, 0x0afa, 0x0afa }, +/* 0x0afb */ { false, 0x0afb, 0x0afb }, +/* 0x0afc */ { false, 0x0afc, 0x0afc }, +/* 0x0afd */ { false, 0x0afd, 0x0afd }, +/* 0x0afe */ { false, 0x0afe, 0x0afe }, +/* 0x0aff */ { false, 0x0aff, 0x0aff }, +/* 0x0b00 */ { false, 0x0b00, 0x0b00 }, +/* 0x0b01 */ { true, 0x0b01, 0x0b01 }, +/* 0x0b02 */ { true, 0x0b02, 0x0b02 }, +/* 0x0b03 */ { true, 0x0b03, 0x0b03 }, +/* 0x0b04 */ { false, 0x0b04, 0x0b04 }, +/* 0x0b05 */ { true, 0x0b05, 0x0b05 }, +/* 0x0b06 */ { true, 0x0b06, 0x0b06 }, +/* 0x0b07 */ { true, 0x0b07, 0x0b07 }, +/* 0x0b08 */ { true, 0x0b08, 0x0b08 }, +/* 0x0b09 */ { true, 0x0b09, 0x0b09 }, +/* 0x0b0a */ { true, 0x0b0a, 0x0b0a }, +/* 0x0b0b */ { true, 0x0b0b, 0x0b0b }, +/* 0x0b0c */ { true, 0x0b0c, 0x0b0c }, +/* 0x0b0d */ { false, 0x0b0d, 0x0b0d }, +/* 0x0b0e */ { false, 0x0b0e, 0x0b0e }, +/* 0x0b0f */ { true, 0x0b0f, 0x0b0f }, +/* 0x0b10 */ { true, 0x0b10, 0x0b10 }, +/* 0x0b11 */ { false, 0x0b11, 0x0b11 }, +/* 0x0b12 */ { false, 0x0b12, 0x0b12 }, +/* 0x0b13 */ { true, 0x0b13, 0x0b13 }, +/* 0x0b14 */ { true, 0x0b14, 0x0b14 }, +/* 0x0b15 */ { true, 0x0b15, 0x0b15 }, +/* 0x0b16 */ { true, 0x0b16, 0x0b16 }, +/* 0x0b17 */ { true, 0x0b17, 0x0b17 }, +/* 0x0b18 */ { true, 0x0b18, 0x0b18 }, +/* 0x0b19 */ { true, 0x0b19, 0x0b19 }, +/* 0x0b1a */ { true, 0x0b1a, 0x0b1a }, +/* 0x0b1b */ { true, 0x0b1b, 0x0b1b }, +/* 0x0b1c */ { true, 0x0b1c, 0x0b1c }, +/* 0x0b1d */ { true, 0x0b1d, 0x0b1d }, +/* 0x0b1e */ { true, 0x0b1e, 0x0b1e }, +/* 0x0b1f */ { true, 0x0b1f, 0x0b1f }, +/* 0x0b20 */ { true, 0x0b20, 0x0b20 }, +/* 0x0b21 */ { true, 0x0b21, 0x0b21 }, +/* 0x0b22 */ { true, 0x0b22, 0x0b22 }, +/* 0x0b23 */ { true, 0x0b23, 0x0b23 }, +/* 0x0b24 */ { true, 0x0b24, 0x0b24 }, +/* 0x0b25 */ { true, 0x0b25, 0x0b25 }, +/* 0x0b26 */ { true, 0x0b26, 0x0b26 }, +/* 0x0b27 */ { true, 0x0b27, 0x0b27 }, +/* 0x0b28 */ { true, 0x0b28, 0x0b28 }, +/* 0x0b29 */ { false, 0x0b29, 0x0b29 }, +/* 0x0b2a */ { true, 0x0b2a, 0x0b2a }, +/* 0x0b2b */ { true, 0x0b2b, 0x0b2b }, +/* 0x0b2c */ { true, 0x0b2c, 0x0b2c }, +/* 0x0b2d */ { true, 0x0b2d, 0x0b2d }, +/* 0x0b2e */ { true, 0x0b2e, 0x0b2e }, +/* 0x0b2f */ { true, 0x0b2f, 0x0b2f }, +/* 0x0b30 */ { true, 0x0b30, 0x0b30 }, +/* 0x0b31 */ { false, 0x0b31, 0x0b31 }, +/* 0x0b32 */ { true, 0x0b32, 0x0b32 }, +/* 0x0b33 */ { true, 0x0b33, 0x0b33 }, +/* 0x0b34 */ { false, 0x0b34, 0x0b34 }, +/* 0x0b35 */ { true, 0x0b35, 0x0b35 }, +/* 0x0b36 */ { true, 0x0b36, 0x0b36 }, +/* 0x0b37 */ { true, 0x0b37, 0x0b37 }, +/* 0x0b38 */ { true, 0x0b38, 0x0b38 }, +/* 0x0b39 */ { true, 0x0b39, 0x0b39 }, +/* 0x0b3a */ { false, 0x0b3a, 0x0b3a }, +/* 0x0b3b */ { false, 0x0b3b, 0x0b3b }, +/* 0x0b3c */ { true, 0x0b3c, 0x0b3c }, +/* 0x0b3d */ { true, 0x0b3d, 0x0b3d }, +/* 0x0b3e */ { true, 0x0b3e, 0x0b3e }, +/* 0x0b3f */ { true, 0x0b3f, 0x0b3f }, +/* 0x0b40 */ { true, 0x0b40, 0x0b40 }, +/* 0x0b41 */ { true, 0x0b41, 0x0b41 }, +/* 0x0b42 */ { true, 0x0b42, 0x0b42 }, +/* 0x0b43 */ { true, 0x0b43, 0x0b43 }, +/* 0x0b44 */ { false, 0x0b44, 0x0b44 }, +/* 0x0b45 */ { false, 0x0b45, 0x0b45 }, +/* 0x0b46 */ { false, 0x0b46, 0x0b46 }, +/* 0x0b47 */ { true, 0x0b47, 0x0b47 }, +/* 0x0b48 */ { true, 0x0b48, 0x0b48 }, +/* 0x0b49 */ { false, 0x0b49, 0x0b49 }, +/* 0x0b4a */ { false, 0x0b4a, 0x0b4a }, +/* 0x0b4b */ { true, 0x0b4b, 0x0b4b }, +/* 0x0b4c */ { true, 0x0b4c, 0x0b4c }, +/* 0x0b4d */ { true, 0x0b4d, 0x0b4d }, +/* 0x0b4e */ { false, 0x0b4e, 0x0b4e }, +/* 0x0b4f */ { false, 0x0b4f, 0x0b4f }, +/* 0x0b50 */ { false, 0x0b50, 0x0b50 }, +/* 0x0b51 */ { false, 0x0b51, 0x0b51 }, +/* 0x0b52 */ { false, 0x0b52, 0x0b52 }, +/* 0x0b53 */ { false, 0x0b53, 0x0b53 }, +/* 0x0b54 */ { false, 0x0b54, 0x0b54 }, +/* 0x0b55 */ { false, 0x0b55, 0x0b55 }, +/* 0x0b56 */ { true, 0x0b56, 0x0b56 }, +/* 0x0b57 */ { true, 0x0b57, 0x0b57 }, +/* 0x0b58 */ { false, 0x0b58, 0x0b58 }, +/* 0x0b59 */ { false, 0x0b59, 0x0b59 }, +/* 0x0b5a */ { false, 0x0b5a, 0x0b5a }, +/* 0x0b5b */ { false, 0x0b5b, 0x0b5b }, +/* 0x0b5c */ { true, 0x0b5c, 0x0b5c }, +/* 0x0b5d */ { true, 0x0b5d, 0x0b5d }, +/* 0x0b5e */ { false, 0x0b5e, 0x0b5e }, +/* 0x0b5f */ { true, 0x0b5f, 0x0b5f }, +/* 0x0b60 */ { true, 0x0b60, 0x0b60 }, +/* 0x0b61 */ { true, 0x0b61, 0x0b61 }, +/* 0x0b62 */ { false, 0x0b62, 0x0b62 }, +/* 0x0b63 */ { false, 0x0b63, 0x0b63 }, +/* 0x0b64 */ { false, 0x0b64, 0x0b64 }, +/* 0x0b65 */ { false, 0x0b65, 0x0b65 }, +/* 0x0b66 */ { false, 0x0b66, 0x0b66 }, +/* 0x0b67 */ { false, 0x0b67, 0x0b67 }, +/* 0x0b68 */ { false, 0x0b68, 0x0b68 }, +/* 0x0b69 */ { false, 0x0b69, 0x0b69 }, +/* 0x0b6a */ { false, 0x0b6a, 0x0b6a }, +/* 0x0b6b */ { false, 0x0b6b, 0x0b6b }, +/* 0x0b6c */ { false, 0x0b6c, 0x0b6c }, +/* 0x0b6d */ { false, 0x0b6d, 0x0b6d }, +/* 0x0b6e */ { false, 0x0b6e, 0x0b6e }, +/* 0x0b6f */ { false, 0x0b6f, 0x0b6f }, +/* 0x0b70 */ { false, 0x0b70, 0x0b70 }, +/* 0x0b71 */ { true, 0x0b71, 0x0b71 }, +/* 0x0b72 */ { false, 0x0b72, 0x0b72 }, +/* 0x0b73 */ { false, 0x0b73, 0x0b73 }, +/* 0x0b74 */ { false, 0x0b74, 0x0b74 }, +/* 0x0b75 */ { false, 0x0b75, 0x0b75 }, +/* 0x0b76 */ { false, 0x0b76, 0x0b76 }, +/* 0x0b77 */ { false, 0x0b77, 0x0b77 }, +/* 0x0b78 */ { false, 0x0b78, 0x0b78 }, +/* 0x0b79 */ { false, 0x0b79, 0x0b79 }, +/* 0x0b7a */ { false, 0x0b7a, 0x0b7a }, +/* 0x0b7b */ { false, 0x0b7b, 0x0b7b }, +/* 0x0b7c */ { false, 0x0b7c, 0x0b7c }, +/* 0x0b7d */ { false, 0x0b7d, 0x0b7d }, +/* 0x0b7e */ { false, 0x0b7e, 0x0b7e }, +/* 0x0b7f */ { false, 0x0b7f, 0x0b7f }, +/* 0x0b80 */ { false, 0x0b80, 0x0b80 }, +/* 0x0b81 */ { false, 0x0b81, 0x0b81 }, +/* 0x0b82 */ { true, 0x0b82, 0x0b82 }, +/* 0x0b83 */ { true, 0x0b83, 0x0b83 }, +/* 0x0b84 */ { false, 0x0b84, 0x0b84 }, +/* 0x0b85 */ { true, 0x0b85, 0x0b85 }, +/* 0x0b86 */ { true, 0x0b86, 0x0b86 }, +/* 0x0b87 */ { true, 0x0b87, 0x0b87 }, +/* 0x0b88 */ { true, 0x0b88, 0x0b88 }, +/* 0x0b89 */ { true, 0x0b89, 0x0b89 }, +/* 0x0b8a */ { true, 0x0b8a, 0x0b8a }, +/* 0x0b8b */ { false, 0x0b8b, 0x0b8b }, +/* 0x0b8c */ { false, 0x0b8c, 0x0b8c }, +/* 0x0b8d */ { false, 0x0b8d, 0x0b8d }, +/* 0x0b8e */ { true, 0x0b8e, 0x0b8e }, +/* 0x0b8f */ { true, 0x0b8f, 0x0b8f }, +/* 0x0b90 */ { true, 0x0b90, 0x0b90 }, +/* 0x0b91 */ { false, 0x0b91, 0x0b91 }, +/* 0x0b92 */ { true, 0x0b92, 0x0b92 }, +/* 0x0b93 */ { true, 0x0b93, 0x0b93 }, +/* 0x0b94 */ { true, 0x0b94, 0x0b94 }, +/* 0x0b95 */ { true, 0x0b95, 0x0b95 }, +/* 0x0b96 */ { false, 0x0b96, 0x0b96 }, +/* 0x0b97 */ { false, 0x0b97, 0x0b97 }, +/* 0x0b98 */ { false, 0x0b98, 0x0b98 }, +/* 0x0b99 */ { true, 0x0b99, 0x0b99 }, +/* 0x0b9a */ { true, 0x0b9a, 0x0b9a }, +/* 0x0b9b */ { false, 0x0b9b, 0x0b9b }, +/* 0x0b9c */ { true, 0x0b9c, 0x0b9c }, +/* 0x0b9d */ { false, 0x0b9d, 0x0b9d }, +/* 0x0b9e */ { true, 0x0b9e, 0x0b9e }, +/* 0x0b9f */ { true, 0x0b9f, 0x0b9f }, +/* 0x0ba0 */ { false, 0x0ba0, 0x0ba0 }, +/* 0x0ba1 */ { false, 0x0ba1, 0x0ba1 }, +/* 0x0ba2 */ { false, 0x0ba2, 0x0ba2 }, +/* 0x0ba3 */ { true, 0x0ba3, 0x0ba3 }, +/* 0x0ba4 */ { true, 0x0ba4, 0x0ba4 }, +/* 0x0ba5 */ { false, 0x0ba5, 0x0ba5 }, +/* 0x0ba6 */ { false, 0x0ba6, 0x0ba6 }, +/* 0x0ba7 */ { false, 0x0ba7, 0x0ba7 }, +/* 0x0ba8 */ { true, 0x0ba8, 0x0ba8 }, +/* 0x0ba9 */ { true, 0x0ba9, 0x0ba9 }, +/* 0x0baa */ { true, 0x0baa, 0x0baa }, +/* 0x0bab */ { false, 0x0bab, 0x0bab }, +/* 0x0bac */ { false, 0x0bac, 0x0bac }, +/* 0x0bad */ { false, 0x0bad, 0x0bad }, +/* 0x0bae */ { true, 0x0bae, 0x0bae }, +/* 0x0baf */ { true, 0x0baf, 0x0baf }, +/* 0x0bb0 */ { true, 0x0bb0, 0x0bb0 }, +/* 0x0bb1 */ { true, 0x0bb1, 0x0bb1 }, +/* 0x0bb2 */ { true, 0x0bb2, 0x0bb2 }, +/* 0x0bb3 */ { true, 0x0bb3, 0x0bb3 }, +/* 0x0bb4 */ { true, 0x0bb4, 0x0bb4 }, +/* 0x0bb5 */ { true, 0x0bb5, 0x0bb5 }, +/* 0x0bb6 */ { true, 0x0bb6, 0x0bb6 }, +/* 0x0bb7 */ { true, 0x0bb7, 0x0bb7 }, +/* 0x0bb8 */ { true, 0x0bb8, 0x0bb8 }, +/* 0x0bb9 */ { true, 0x0bb9, 0x0bb9 }, +/* 0x0bba */ { false, 0x0bba, 0x0bba }, +/* 0x0bbb */ { false, 0x0bbb, 0x0bbb }, +/* 0x0bbc */ { false, 0x0bbc, 0x0bbc }, +/* 0x0bbd */ { false, 0x0bbd, 0x0bbd }, +/* 0x0bbe */ { true, 0x0bbe, 0x0bbe }, +/* 0x0bbf */ { true, 0x0bbf, 0x0bbf }, +/* 0x0bc0 */ { true, 0x0bc0, 0x0bc0 }, +/* 0x0bc1 */ { true, 0x0bc1, 0x0bc1 }, +/* 0x0bc2 */ { true, 0x0bc2, 0x0bc2 }, +/* 0x0bc3 */ { false, 0x0bc3, 0x0bc3 }, +/* 0x0bc4 */ { false, 0x0bc4, 0x0bc4 }, +/* 0x0bc5 */ { false, 0x0bc5, 0x0bc5 }, +/* 0x0bc6 */ { true, 0x0bc6, 0x0bc6 }, +/* 0x0bc7 */ { true, 0x0bc7, 0x0bc7 }, +/* 0x0bc8 */ { true, 0x0bc8, 0x0bc8 }, +/* 0x0bc9 */ { false, 0x0bc9, 0x0bc9 }, +/* 0x0bca */ { true, 0x0bca, 0x0bca }, +/* 0x0bcb */ { true, 0x0bcb, 0x0bcb }, +/* 0x0bcc */ { true, 0x0bcc, 0x0bcc }, +/* 0x0bcd */ { true, 0x0bcd, 0x0bcd }, +/* 0x0bce */ { false, 0x0bce, 0x0bce }, +/* 0x0bcf */ { false, 0x0bcf, 0x0bcf }, +/* 0x0bd0 */ { false, 0x0bd0, 0x0bd0 }, +/* 0x0bd1 */ { false, 0x0bd1, 0x0bd1 }, +/* 0x0bd2 */ { false, 0x0bd2, 0x0bd2 }, +/* 0x0bd3 */ { false, 0x0bd3, 0x0bd3 }, +/* 0x0bd4 */ { false, 0x0bd4, 0x0bd4 }, +/* 0x0bd5 */ { false, 0x0bd5, 0x0bd5 }, +/* 0x0bd6 */ { false, 0x0bd6, 0x0bd6 }, +/* 0x0bd7 */ { true, 0x0bd7, 0x0bd7 }, +/* 0x0bd8 */ { false, 0x0bd8, 0x0bd8 }, +/* 0x0bd9 */ { false, 0x0bd9, 0x0bd9 }, +/* 0x0bda */ { false, 0x0bda, 0x0bda }, +/* 0x0bdb */ { false, 0x0bdb, 0x0bdb }, +/* 0x0bdc */ { false, 0x0bdc, 0x0bdc }, +/* 0x0bdd */ { false, 0x0bdd, 0x0bdd }, +/* 0x0bde */ { false, 0x0bde, 0x0bde }, +/* 0x0bdf */ { false, 0x0bdf, 0x0bdf }, +/* 0x0be0 */ { false, 0x0be0, 0x0be0 }, +/* 0x0be1 */ { false, 0x0be1, 0x0be1 }, +/* 0x0be2 */ { false, 0x0be2, 0x0be2 }, +/* 0x0be3 */ { false, 0x0be3, 0x0be3 }, +/* 0x0be4 */ { false, 0x0be4, 0x0be4 }, +/* 0x0be5 */ { false, 0x0be5, 0x0be5 }, +/* 0x0be6 */ { false, 0x0be6, 0x0be6 }, +/* 0x0be7 */ { false, 0x0be7, 0x0be7 }, +/* 0x0be8 */ { false, 0x0be8, 0x0be8 }, +/* 0x0be9 */ { false, 0x0be9, 0x0be9 }, +/* 0x0bea */ { false, 0x0bea, 0x0bea }, +/* 0x0beb */ { false, 0x0beb, 0x0beb }, +/* 0x0bec */ { false, 0x0bec, 0x0bec }, +/* 0x0bed */ { false, 0x0bed, 0x0bed }, +/* 0x0bee */ { false, 0x0bee, 0x0bee }, +/* 0x0bef */ { false, 0x0bef, 0x0bef }, +/* 0x0bf0 */ { false, 0x0bf0, 0x0bf0 }, +/* 0x0bf1 */ { false, 0x0bf1, 0x0bf1 }, +/* 0x0bf2 */ { false, 0x0bf2, 0x0bf2 }, +/* 0x0bf3 */ { false, 0x0bf3, 0x0bf3 }, +/* 0x0bf4 */ { false, 0x0bf4, 0x0bf4 }, +/* 0x0bf5 */ { false, 0x0bf5, 0x0bf5 }, +/* 0x0bf6 */ { false, 0x0bf6, 0x0bf6 }, +/* 0x0bf7 */ { false, 0x0bf7, 0x0bf7 }, +/* 0x0bf8 */ { false, 0x0bf8, 0x0bf8 }, +/* 0x0bf9 */ { false, 0x0bf9, 0x0bf9 }, +/* 0x0bfa */ { false, 0x0bfa, 0x0bfa }, +/* 0x0bfb */ { false, 0x0bfb, 0x0bfb }, +/* 0x0bfc */ { false, 0x0bfc, 0x0bfc }, +/* 0x0bfd */ { false, 0x0bfd, 0x0bfd }, +/* 0x0bfe */ { false, 0x0bfe, 0x0bfe }, +/* 0x0bff */ { false, 0x0bff, 0x0bff }, +/* 0x0c00 */ { false, 0x0c00, 0x0c00 }, +/* 0x0c01 */ { true, 0x0c01, 0x0c01 }, +/* 0x0c02 */ { true, 0x0c02, 0x0c02 }, +/* 0x0c03 */ { true, 0x0c03, 0x0c03 }, +/* 0x0c04 */ { false, 0x0c04, 0x0c04 }, +/* 0x0c05 */ { true, 0x0c05, 0x0c05 }, +/* 0x0c06 */ { true, 0x0c06, 0x0c06 }, +/* 0x0c07 */ { true, 0x0c07, 0x0c07 }, +/* 0x0c08 */ { true, 0x0c08, 0x0c08 }, +/* 0x0c09 */ { true, 0x0c09, 0x0c09 }, +/* 0x0c0a */ { true, 0x0c0a, 0x0c0a }, +/* 0x0c0b */ { true, 0x0c0b, 0x0c0b }, +/* 0x0c0c */ { true, 0x0c0c, 0x0c0c }, +/* 0x0c0d */ { false, 0x0c0d, 0x0c0d }, +/* 0x0c0e */ { true, 0x0c0e, 0x0c0e }, +/* 0x0c0f */ { true, 0x0c0f, 0x0c0f }, +/* 0x0c10 */ { true, 0x0c10, 0x0c10 }, +/* 0x0c11 */ { false, 0x0c11, 0x0c11 }, +/* 0x0c12 */ { true, 0x0c12, 0x0c12 }, +/* 0x0c13 */ { true, 0x0c13, 0x0c13 }, +/* 0x0c14 */ { true, 0x0c14, 0x0c14 }, +/* 0x0c15 */ { true, 0x0c15, 0x0c15 }, +/* 0x0c16 */ { true, 0x0c16, 0x0c16 }, +/* 0x0c17 */ { true, 0x0c17, 0x0c17 }, +/* 0x0c18 */ { true, 0x0c18, 0x0c18 }, +/* 0x0c19 */ { true, 0x0c19, 0x0c19 }, +/* 0x0c1a */ { true, 0x0c1a, 0x0c1a }, +/* 0x0c1b */ { true, 0x0c1b, 0x0c1b }, +/* 0x0c1c */ { true, 0x0c1c, 0x0c1c }, +/* 0x0c1d */ { true, 0x0c1d, 0x0c1d }, +/* 0x0c1e */ { true, 0x0c1e, 0x0c1e }, +/* 0x0c1f */ { true, 0x0c1f, 0x0c1f }, +/* 0x0c20 */ { true, 0x0c20, 0x0c20 }, +/* 0x0c21 */ { true, 0x0c21, 0x0c21 }, +/* 0x0c22 */ { true, 0x0c22, 0x0c22 }, +/* 0x0c23 */ { true, 0x0c23, 0x0c23 }, +/* 0x0c24 */ { true, 0x0c24, 0x0c24 }, +/* 0x0c25 */ { true, 0x0c25, 0x0c25 }, +/* 0x0c26 */ { true, 0x0c26, 0x0c26 }, +/* 0x0c27 */ { true, 0x0c27, 0x0c27 }, +/* 0x0c28 */ { true, 0x0c28, 0x0c28 }, +/* 0x0c29 */ { false, 0x0c29, 0x0c29 }, +/* 0x0c2a */ { true, 0x0c2a, 0x0c2a }, +/* 0x0c2b */ { true, 0x0c2b, 0x0c2b }, +/* 0x0c2c */ { true, 0x0c2c, 0x0c2c }, +/* 0x0c2d */ { true, 0x0c2d, 0x0c2d }, +/* 0x0c2e */ { true, 0x0c2e, 0x0c2e }, +/* 0x0c2f */ { true, 0x0c2f, 0x0c2f }, +/* 0x0c30 */ { true, 0x0c30, 0x0c30 }, +/* 0x0c31 */ { true, 0x0c31, 0x0c31 }, +/* 0x0c32 */ { true, 0x0c32, 0x0c32 }, +/* 0x0c33 */ { true, 0x0c33, 0x0c33 }, +/* 0x0c34 */ { false, 0x0c34, 0x0c34 }, +/* 0x0c35 */ { true, 0x0c35, 0x0c35 }, +/* 0x0c36 */ { true, 0x0c36, 0x0c36 }, +/* 0x0c37 */ { true, 0x0c37, 0x0c37 }, +/* 0x0c38 */ { true, 0x0c38, 0x0c38 }, +/* 0x0c39 */ { true, 0x0c39, 0x0c39 }, +/* 0x0c3a */ { false, 0x0c3a, 0x0c3a }, +/* 0x0c3b */ { false, 0x0c3b, 0x0c3b }, +/* 0x0c3c */ { false, 0x0c3c, 0x0c3c }, +/* 0x0c3d */ { false, 0x0c3d, 0x0c3d }, +/* 0x0c3e */ { true, 0x0c3e, 0x0c3e }, +/* 0x0c3f */ { true, 0x0c3f, 0x0c3f }, +/* 0x0c40 */ { true, 0x0c40, 0x0c40 }, +/* 0x0c41 */ { true, 0x0c41, 0x0c41 }, +/* 0x0c42 */ { true, 0x0c42, 0x0c42 }, +/* 0x0c43 */ { true, 0x0c43, 0x0c43 }, +/* 0x0c44 */ { true, 0x0c44, 0x0c44 }, +/* 0x0c45 */ { false, 0x0c45, 0x0c45 }, +/* 0x0c46 */ { true, 0x0c46, 0x0c46 }, +/* 0x0c47 */ { true, 0x0c47, 0x0c47 }, +/* 0x0c48 */ { true, 0x0c48, 0x0c48 }, +/* 0x0c49 */ { false, 0x0c49, 0x0c49 }, +/* 0x0c4a */ { true, 0x0c4a, 0x0c4a }, +/* 0x0c4b */ { true, 0x0c4b, 0x0c4b }, +/* 0x0c4c */ { true, 0x0c4c, 0x0c4c }, +/* 0x0c4d */ { true, 0x0c4d, 0x0c4d }, +/* 0x0c4e */ { false, 0x0c4e, 0x0c4e }, +/* 0x0c4f */ { false, 0x0c4f, 0x0c4f }, +/* 0x0c50 */ { false, 0x0c50, 0x0c50 }, +/* 0x0c51 */ { false, 0x0c51, 0x0c51 }, +/* 0x0c52 */ { false, 0x0c52, 0x0c52 }, +/* 0x0c53 */ { false, 0x0c53, 0x0c53 }, +/* 0x0c54 */ { false, 0x0c54, 0x0c54 }, +/* 0x0c55 */ { true, 0x0c55, 0x0c55 }, +/* 0x0c56 */ { true, 0x0c56, 0x0c56 }, +/* 0x0c57 */ { false, 0x0c57, 0x0c57 }, +/* 0x0c58 */ { false, 0x0c58, 0x0c58 }, +/* 0x0c59 */ { false, 0x0c59, 0x0c59 }, +/* 0x0c5a */ { false, 0x0c5a, 0x0c5a }, +/* 0x0c5b */ { false, 0x0c5b, 0x0c5b }, +/* 0x0c5c */ { false, 0x0c5c, 0x0c5c }, +/* 0x0c5d */ { false, 0x0c5d, 0x0c5d }, +/* 0x0c5e */ { false, 0x0c5e, 0x0c5e }, +/* 0x0c5f */ { false, 0x0c5f, 0x0c5f }, +/* 0x0c60 */ { true, 0x0c60, 0x0c60 }, +/* 0x0c61 */ { true, 0x0c61, 0x0c61 }, +/* 0x0c62 */ { false, 0x0c62, 0x0c62 }, +/* 0x0c63 */ { false, 0x0c63, 0x0c63 }, +/* 0x0c64 */ { false, 0x0c64, 0x0c64 }, +/* 0x0c65 */ { false, 0x0c65, 0x0c65 }, +/* 0x0c66 */ { false, 0x0c66, 0x0c66 }, +/* 0x0c67 */ { false, 0x0c67, 0x0c67 }, +/* 0x0c68 */ { false, 0x0c68, 0x0c68 }, +/* 0x0c69 */ { false, 0x0c69, 0x0c69 }, +/* 0x0c6a */ { false, 0x0c6a, 0x0c6a }, +/* 0x0c6b */ { false, 0x0c6b, 0x0c6b }, +/* 0x0c6c */ { false, 0x0c6c, 0x0c6c }, +/* 0x0c6d */ { false, 0x0c6d, 0x0c6d }, +/* 0x0c6e */ { false, 0x0c6e, 0x0c6e }, +/* 0x0c6f */ { false, 0x0c6f, 0x0c6f }, +/* 0x0c70 */ { false, 0x0c70, 0x0c70 }, +/* 0x0c71 */ { false, 0x0c71, 0x0c71 }, +/* 0x0c72 */ { false, 0x0c72, 0x0c72 }, +/* 0x0c73 */ { false, 0x0c73, 0x0c73 }, +/* 0x0c74 */ { false, 0x0c74, 0x0c74 }, +/* 0x0c75 */ { false, 0x0c75, 0x0c75 }, +/* 0x0c76 */ { false, 0x0c76, 0x0c76 }, +/* 0x0c77 */ { false, 0x0c77, 0x0c77 }, +/* 0x0c78 */ { false, 0x0c78, 0x0c78 }, +/* 0x0c79 */ { false, 0x0c79, 0x0c79 }, +/* 0x0c7a */ { false, 0x0c7a, 0x0c7a }, +/* 0x0c7b */ { false, 0x0c7b, 0x0c7b }, +/* 0x0c7c */ { false, 0x0c7c, 0x0c7c }, +/* 0x0c7d */ { false, 0x0c7d, 0x0c7d }, +/* 0x0c7e */ { false, 0x0c7e, 0x0c7e }, +/* 0x0c7f */ { false, 0x0c7f, 0x0c7f }, +/* 0x0c80 */ { false, 0x0c80, 0x0c80 }, +/* 0x0c81 */ { false, 0x0c81, 0x0c81 }, +/* 0x0c82 */ { true, 0x0c82, 0x0c82 }, +/* 0x0c83 */ { true, 0x0c83, 0x0c83 }, +/* 0x0c84 */ { false, 0x0c84, 0x0c84 }, +/* 0x0c85 */ { true, 0x0c85, 0x0c85 }, +/* 0x0c86 */ { true, 0x0c86, 0x0c86 }, +/* 0x0c87 */ { true, 0x0c87, 0x0c87 }, +/* 0x0c88 */ { true, 0x0c88, 0x0c88 }, +/* 0x0c89 */ { true, 0x0c89, 0x0c89 }, +/* 0x0c8a */ { true, 0x0c8a, 0x0c8a }, +/* 0x0c8b */ { true, 0x0c8b, 0x0c8b }, +/* 0x0c8c */ { true, 0x0c8c, 0x0c8c }, +/* 0x0c8d */ { false, 0x0c8d, 0x0c8d }, +/* 0x0c8e */ { true, 0x0c8e, 0x0c8e }, +/* 0x0c8f */ { true, 0x0c8f, 0x0c8f }, +/* 0x0c90 */ { true, 0x0c90, 0x0c90 }, +/* 0x0c91 */ { false, 0x0c91, 0x0c91 }, +/* 0x0c92 */ { true, 0x0c92, 0x0c92 }, +/* 0x0c93 */ { true, 0x0c93, 0x0c93 }, +/* 0x0c94 */ { true, 0x0c94, 0x0c94 }, +/* 0x0c95 */ { true, 0x0c95, 0x0c95 }, +/* 0x0c96 */ { true, 0x0c96, 0x0c96 }, +/* 0x0c97 */ { true, 0x0c97, 0x0c97 }, +/* 0x0c98 */ { true, 0x0c98, 0x0c98 }, +/* 0x0c99 */ { true, 0x0c99, 0x0c99 }, +/* 0x0c9a */ { true, 0x0c9a, 0x0c9a }, +/* 0x0c9b */ { true, 0x0c9b, 0x0c9b }, +/* 0x0c9c */ { true, 0x0c9c, 0x0c9c }, +/* 0x0c9d */ { true, 0x0c9d, 0x0c9d }, +/* 0x0c9e */ { true, 0x0c9e, 0x0c9e }, +/* 0x0c9f */ { true, 0x0c9f, 0x0c9f }, +/* 0x0ca0 */ { true, 0x0ca0, 0x0ca0 }, +/* 0x0ca1 */ { true, 0x0ca1, 0x0ca1 }, +/* 0x0ca2 */ { true, 0x0ca2, 0x0ca2 }, +/* 0x0ca3 */ { true, 0x0ca3, 0x0ca3 }, +/* 0x0ca4 */ { true, 0x0ca4, 0x0ca4 }, +/* 0x0ca5 */ { true, 0x0ca5, 0x0ca5 }, +/* 0x0ca6 */ { true, 0x0ca6, 0x0ca6 }, +/* 0x0ca7 */ { true, 0x0ca7, 0x0ca7 }, +/* 0x0ca8 */ { true, 0x0ca8, 0x0ca8 }, +/* 0x0ca9 */ { false, 0x0ca9, 0x0ca9 }, +/* 0x0caa */ { true, 0x0caa, 0x0caa }, +/* 0x0cab */ { true, 0x0cab, 0x0cab }, +/* 0x0cac */ { true, 0x0cac, 0x0cac }, +/* 0x0cad */ { true, 0x0cad, 0x0cad }, +/* 0x0cae */ { true, 0x0cae, 0x0cae }, +/* 0x0caf */ { true, 0x0caf, 0x0caf }, +/* 0x0cb0 */ { true, 0x0cb0, 0x0cb0 }, +/* 0x0cb1 */ { true, 0x0cb1, 0x0cb1 }, +/* 0x0cb2 */ { true, 0x0cb2, 0x0cb2 }, +/* 0x0cb3 */ { true, 0x0cb3, 0x0cb3 }, +/* 0x0cb4 */ { false, 0x0cb4, 0x0cb4 }, +/* 0x0cb5 */ { true, 0x0cb5, 0x0cb5 }, +/* 0x0cb6 */ { true, 0x0cb6, 0x0cb6 }, +/* 0x0cb7 */ { true, 0x0cb7, 0x0cb7 }, +/* 0x0cb8 */ { true, 0x0cb8, 0x0cb8 }, +/* 0x0cb9 */ { true, 0x0cb9, 0x0cb9 }, +/* 0x0cba */ { false, 0x0cba, 0x0cba }, +/* 0x0cbb */ { false, 0x0cbb, 0x0cbb }, +/* 0x0cbc */ { true, 0x0cbc, 0x0cbc }, +/* 0x0cbd */ { true, 0x0cbd, 0x0cbd }, +/* 0x0cbe */ { true, 0x0cbe, 0x0cbe }, +/* 0x0cbf */ { true, 0x0cbf, 0x0cbf }, +/* 0x0cc0 */ { true, 0x0cc0, 0x0cc0 }, +/* 0x0cc1 */ { true, 0x0cc1, 0x0cc1 }, +/* 0x0cc2 */ { true, 0x0cc2, 0x0cc2 }, +/* 0x0cc3 */ { true, 0x0cc3, 0x0cc3 }, +/* 0x0cc4 */ { true, 0x0cc4, 0x0cc4 }, +/* 0x0cc5 */ { false, 0x0cc5, 0x0cc5 }, +/* 0x0cc6 */ { true, 0x0cc6, 0x0cc6 }, +/* 0x0cc7 */ { true, 0x0cc7, 0x0cc7 }, +/* 0x0cc8 */ { true, 0x0cc8, 0x0cc8 }, +/* 0x0cc9 */ { false, 0x0cc9, 0x0cc9 }, +/* 0x0cca */ { true, 0x0cca, 0x0cca }, +/* 0x0ccb */ { true, 0x0ccb, 0x0ccb }, +/* 0x0ccc */ { true, 0x0ccc, 0x0ccc }, +/* 0x0ccd */ { true, 0x0ccd, 0x0ccd }, +/* 0x0cce */ { false, 0x0cce, 0x0cce }, +/* 0x0ccf */ { false, 0x0ccf, 0x0ccf }, +/* 0x0cd0 */ { false, 0x0cd0, 0x0cd0 }, +/* 0x0cd1 */ { false, 0x0cd1, 0x0cd1 }, +/* 0x0cd2 */ { false, 0x0cd2, 0x0cd2 }, +/* 0x0cd3 */ { false, 0x0cd3, 0x0cd3 }, +/* 0x0cd4 */ { false, 0x0cd4, 0x0cd4 }, +/* 0x0cd5 */ { true, 0x0cd5, 0x0cd5 }, +/* 0x0cd6 */ { true, 0x0cd6, 0x0cd6 }, +/* 0x0cd7 */ { false, 0x0cd7, 0x0cd7 }, +/* 0x0cd8 */ { false, 0x0cd8, 0x0cd8 }, +/* 0x0cd9 */ { false, 0x0cd9, 0x0cd9 }, +/* 0x0cda */ { false, 0x0cda, 0x0cda }, +/* 0x0cdb */ { false, 0x0cdb, 0x0cdb }, +/* 0x0cdc */ { false, 0x0cdc, 0x0cdc }, +/* 0x0cdd */ { false, 0x0cdd, 0x0cdd }, +/* 0x0cde */ { true, 0x0cde, 0x0cde }, +/* 0x0cdf */ { false, 0x0cdf, 0x0cdf }, +/* 0x0ce0 */ { true, 0x0ce0, 0x0ce0 }, +/* 0x0ce1 */ { true, 0x0ce1, 0x0ce1 }, +/* 0x0ce2 */ { false, 0x0ce2, 0x0ce2 }, +/* 0x0ce3 */ { false, 0x0ce3, 0x0ce3 }, +/* 0x0ce4 */ { false, 0x0ce4, 0x0ce4 }, +/* 0x0ce5 */ { false, 0x0ce5, 0x0ce5 }, +/* 0x0ce6 */ { false, 0x0ce6, 0x0ce6 }, +/* 0x0ce7 */ { false, 0x0ce7, 0x0ce7 }, +/* 0x0ce8 */ { false, 0x0ce8, 0x0ce8 }, +/* 0x0ce9 */ { false, 0x0ce9, 0x0ce9 }, +/* 0x0cea */ { false, 0x0cea, 0x0cea }, +/* 0x0ceb */ { false, 0x0ceb, 0x0ceb }, +/* 0x0cec */ { false, 0x0cec, 0x0cec }, +/* 0x0ced */ { false, 0x0ced, 0x0ced }, +/* 0x0cee */ { false, 0x0cee, 0x0cee }, +/* 0x0cef */ { false, 0x0cef, 0x0cef }, +/* 0x0cf0 */ { false, 0x0cf0, 0x0cf0 }, +/* 0x0cf1 */ { false, 0x0cf1, 0x0cf1 }, +/* 0x0cf2 */ { false, 0x0cf2, 0x0cf2 }, +/* 0x0cf3 */ { true, 0x0cf3, 0x0cf3 }, +/* 0x0cf4 */ { false, 0x0cf4, 0x0cf4 }, +/* 0x0cf5 */ { false, 0x0cf5, 0x0cf5 }, +/* 0x0cf6 */ { false, 0x0cf6, 0x0cf6 }, +/* 0x0cf7 */ { false, 0x0cf7, 0x0cf7 }, +/* 0x0cf8 */ { false, 0x0cf8, 0x0cf8 }, +/* 0x0cf9 */ { false, 0x0cf9, 0x0cf9 }, +/* 0x0cfa */ { false, 0x0cfa, 0x0cfa }, +/* 0x0cfb */ { false, 0x0cfb, 0x0cfb }, +/* 0x0cfc */ { false, 0x0cfc, 0x0cfc }, +/* 0x0cfd */ { false, 0x0cfd, 0x0cfd }, +/* 0x0cfe */ { false, 0x0cfe, 0x0cfe }, +/* 0x0cff */ { false, 0x0cff, 0x0cff }, +/* 0x0d00 */ { false, 0x0d00, 0x0d00 }, +/* 0x0d01 */ { false, 0x0d01, 0x0d01 }, +/* 0x0d02 */ { true, 0x0d02, 0x0d02 }, +/* 0x0d03 */ { true, 0x0d03, 0x0d03 }, +/* 0x0d04 */ { false, 0x0d04, 0x0d04 }, +/* 0x0d05 */ { true, 0x0d05, 0x0d05 }, +/* 0x0d06 */ { true, 0x0d06, 0x0d06 }, +/* 0x0d07 */ { true, 0x0d07, 0x0d07 }, +/* 0x0d08 */ { true, 0x0d08, 0x0d08 }, +/* 0x0d09 */ { true, 0x0d09, 0x0d09 }, +/* 0x0d0a */ { true, 0x0d0a, 0x0d0a }, +/* 0x0d0b */ { true, 0x0d0b, 0x0d0b }, +/* 0x0d0c */ { true, 0x0d0c, 0x0d0c }, +/* 0x0d0d */ { false, 0x0d0d, 0x0d0d }, +/* 0x0d0e */ { true, 0x0d0e, 0x0d0e }, +/* 0x0d0f */ { true, 0x0d0f, 0x0d0f }, +/* 0x0d10 */ { true, 0x0d10, 0x0d10 }, +/* 0x0d11 */ { false, 0x0d11, 0x0d11 }, +/* 0x0d12 */ { true, 0x0d12, 0x0d12 }, +/* 0x0d13 */ { true, 0x0d13, 0x0d13 }, +/* 0x0d14 */ { true, 0x0d14, 0x0d14 }, +/* 0x0d15 */ { true, 0x0d15, 0x0d15 }, +/* 0x0d16 */ { true, 0x0d16, 0x0d16 }, +/* 0x0d17 */ { true, 0x0d17, 0x0d17 }, +/* 0x0d18 */ { true, 0x0d18, 0x0d18 }, +/* 0x0d19 */ { true, 0x0d19, 0x0d19 }, +/* 0x0d1a */ { true, 0x0d1a, 0x0d1a }, +/* 0x0d1b */ { true, 0x0d1b, 0x0d1b }, +/* 0x0d1c */ { true, 0x0d1c, 0x0d1c }, +/* 0x0d1d */ { true, 0x0d1d, 0x0d1d }, +/* 0x0d1e */ { true, 0x0d1e, 0x0d1e }, +/* 0x0d1f */ { true, 0x0d1f, 0x0d1f }, +/* 0x0d20 */ { true, 0x0d20, 0x0d20 }, +/* 0x0d21 */ { true, 0x0d21, 0x0d21 }, +/* 0x0d22 */ { true, 0x0d22, 0x0d22 }, +/* 0x0d23 */ { true, 0x0d23, 0x0d23 }, +/* 0x0d24 */ { true, 0x0d24, 0x0d24 }, +/* 0x0d25 */ { true, 0x0d25, 0x0d25 }, +/* 0x0d26 */ { true, 0x0d26, 0x0d26 }, +/* 0x0d27 */ { true, 0x0d27, 0x0d27 }, +/* 0x0d28 */ { true, 0x0d28, 0x0d28 }, +/* 0x0d29 */ { false, 0x0d29, 0x0d29 }, +/* 0x0d2a */ { true, 0x0d2a, 0x0d2a }, +/* 0x0d2b */ { true, 0x0d2b, 0x0d2b }, +/* 0x0d2c */ { true, 0x0d2c, 0x0d2c }, +/* 0x0d2d */ { true, 0x0d2d, 0x0d2d }, +/* 0x0d2e */ { true, 0x0d2e, 0x0d2e }, +/* 0x0d2f */ { true, 0x0d2f, 0x0d2f }, +/* 0x0d30 */ { true, 0x0d30, 0x0d30 }, +/* 0x0d31 */ { true, 0x0d31, 0x0d31 }, +/* 0x0d32 */ { true, 0x0d32, 0x0d32 }, +/* 0x0d33 */ { true, 0x0d33, 0x0d33 }, +/* 0x0d34 */ { true, 0x0d34, 0x0d34 }, +/* 0x0d35 */ { true, 0x0d35, 0x0d35 }, +/* 0x0d36 */ { true, 0x0d36, 0x0d36 }, +/* 0x0d37 */ { true, 0x0d37, 0x0d37 }, +/* 0x0d38 */ { true, 0x0d38, 0x0d38 }, +/* 0x0d39 */ { true, 0x0d39, 0x0d39 }, +/* 0x0d3a */ { false, 0x0d3a, 0x0d3a }, +/* 0x0d3b */ { false, 0x0d3b, 0x0d3b }, +/* 0x0d3c */ { false, 0x0d3c, 0x0d3c }, +/* 0x0d3d */ { false, 0x0d3d, 0x0d3d }, +/* 0x0d3e */ { true, 0x0d3e, 0x0d3e }, +/* 0x0d3f */ { true, 0x0d3f, 0x0d3f }, +/* 0x0d40 */ { true, 0x0d40, 0x0d40 }, +/* 0x0d41 */ { true, 0x0d41, 0x0d41 }, +/* 0x0d42 */ { true, 0x0d42, 0x0d42 }, +/* 0x0d43 */ { true, 0x0d43, 0x0d43 }, +/* 0x0d44 */ { false, 0x0d44, 0x0d44 }, +/* 0x0d45 */ { false, 0x0d45, 0x0d45 }, +/* 0x0d46 */ { true, 0x0d46, 0x0d46 }, +/* 0x0d47 */ { true, 0x0d47, 0x0d47 }, +/* 0x0d48 */ { true, 0x0d48, 0x0d48 }, +/* 0x0d49 */ { false, 0x0d49, 0x0d49 }, +/* 0x0d4a */ { true, 0x0d4a, 0x0d4a }, +/* 0x0d4b */ { true, 0x0d4b, 0x0d4b }, +/* 0x0d4c */ { true, 0x0d4c, 0x0d4c }, +/* 0x0d4d */ { true, 0x0d4d, 0x0d4d }, +/* 0x0d4e */ { false, 0x0d4e, 0x0d4e }, +/* 0x0d4f */ { false, 0x0d4f, 0x0d4f }, +/* 0x0d50 */ { false, 0x0d50, 0x0d50 }, +/* 0x0d51 */ { false, 0x0d51, 0x0d51 }, +/* 0x0d52 */ { false, 0x0d52, 0x0d52 }, +/* 0x0d53 */ { false, 0x0d53, 0x0d53 }, +/* 0x0d54 */ { false, 0x0d54, 0x0d54 }, +/* 0x0d55 */ { false, 0x0d55, 0x0d55 }, +/* 0x0d56 */ { false, 0x0d56, 0x0d56 }, +/* 0x0d57 */ { true, 0x0d57, 0x0d57 }, +/* 0x0d58 */ { false, 0x0d58, 0x0d58 }, +/* 0x0d59 */ { false, 0x0d59, 0x0d59 }, +/* 0x0d5a */ { false, 0x0d5a, 0x0d5a }, +/* 0x0d5b */ { false, 0x0d5b, 0x0d5b }, +/* 0x0d5c */ { false, 0x0d5c, 0x0d5c }, +/* 0x0d5d */ { false, 0x0d5d, 0x0d5d }, +/* 0x0d5e */ { false, 0x0d5e, 0x0d5e }, +/* 0x0d5f */ { false, 0x0d5f, 0x0d5f }, +/* 0x0d60 */ { true, 0x0d60, 0x0d60 }, +/* 0x0d61 */ { true, 0x0d61, 0x0d61 }, +/* 0x0d62 */ { false, 0x0d62, 0x0d62 }, +/* 0x0d63 */ { false, 0x0d63, 0x0d63 }, +/* 0x0d64 */ { false, 0x0d64, 0x0d64 }, +/* 0x0d65 */ { false, 0x0d65, 0x0d65 }, +/* 0x0d66 */ { false, 0x0d66, 0x0d66 }, +/* 0x0d67 */ { false, 0x0d67, 0x0d67 }, +/* 0x0d68 */ { false, 0x0d68, 0x0d68 }, +/* 0x0d69 */ { false, 0x0d69, 0x0d69 }, +/* 0x0d6a */ { false, 0x0d6a, 0x0d6a }, +/* 0x0d6b */ { false, 0x0d6b, 0x0d6b }, +/* 0x0d6c */ { false, 0x0d6c, 0x0d6c }, +/* 0x0d6d */ { false, 0x0d6d, 0x0d6d }, +/* 0x0d6e */ { false, 0x0d6e, 0x0d6e }, +/* 0x0d6f */ { false, 0x0d6f, 0x0d6f }, +/* 0x0d70 */ { false, 0x0d70, 0x0d70 }, +/* 0x0d71 */ { false, 0x0d71, 0x0d71 }, +/* 0x0d72 */ { false, 0x0d72, 0x0d72 }, +/* 0x0d73 */ { false, 0x0d73, 0x0d73 }, +/* 0x0d74 */ { false, 0x0d74, 0x0d74 }, +/* 0x0d75 */ { false, 0x0d75, 0x0d75 }, +/* 0x0d76 */ { false, 0x0d76, 0x0d76 }, +/* 0x0d77 */ { false, 0x0d77, 0x0d77 }, +/* 0x0d78 */ { false, 0x0d78, 0x0d78 }, +/* 0x0d79 */ { false, 0x0d79, 0x0d79 }, +/* 0x0d7a */ { false, 0x0d7a, 0x0d7a }, +/* 0x0d7b */ { false, 0x0d7b, 0x0d7b }, +/* 0x0d7c */ { false, 0x0d7c, 0x0d7c }, +/* 0x0d7d */ { false, 0x0d7d, 0x0d7d }, +/* 0x0d7e */ { false, 0x0d7e, 0x0d7e }, +/* 0x0d7f */ { false, 0x0d7f, 0x0d7f }, +/* 0x0d80 */ { false, 0x0d80, 0x0d80 }, +/* 0x0d81 */ { false, 0x0d81, 0x0d81 }, +/* 0x0d82 */ { true, 0x0d82, 0x0d82 }, +/* 0x0d83 */ { true, 0x0d83, 0x0d83 }, +/* 0x0d84 */ { false, 0x0d84, 0x0d84 }, +/* 0x0d85 */ { true, 0x0d85, 0x0d85 }, +/* 0x0d86 */ { true, 0x0d86, 0x0d86 }, +/* 0x0d87 */ { true, 0x0d87, 0x0d87 }, +/* 0x0d88 */ { true, 0x0d88, 0x0d88 }, +/* 0x0d89 */ { true, 0x0d89, 0x0d89 }, +/* 0x0d8a */ { true, 0x0d8a, 0x0d8a }, +/* 0x0d8b */ { true, 0x0d8b, 0x0d8b }, +/* 0x0d8c */ { true, 0x0d8c, 0x0d8c }, +/* 0x0d8d */ { true, 0x0d8d, 0x0d8d }, +/* 0x0d8e */ { true, 0x0d8e, 0x0d8e }, +/* 0x0d8f */ { true, 0x0d8f, 0x0d8f }, +/* 0x0d90 */ { true, 0x0d90, 0x0d90 }, +/* 0x0d91 */ { true, 0x0d91, 0x0d91 }, +/* 0x0d92 */ { true, 0x0d92, 0x0d92 }, +/* 0x0d93 */ { true, 0x0d93, 0x0d93 }, +/* 0x0d94 */ { true, 0x0d94, 0x0d94 }, +/* 0x0d95 */ { true, 0x0d95, 0x0d95 }, +/* 0x0d96 */ { true, 0x0d96, 0x0d96 }, +/* 0x0d97 */ { false, 0x0d97, 0x0d97 }, +/* 0x0d98 */ { false, 0x0d98, 0x0d98 }, +/* 0x0d99 */ { false, 0x0d99, 0x0d99 }, +/* 0x0d9a */ { true, 0x0d9a, 0x0d9a }, +/* 0x0d9b */ { true, 0x0d9b, 0x0d9b }, +/* 0x0d9c */ { true, 0x0d9c, 0x0d9c }, +/* 0x0d9d */ { true, 0x0d9d, 0x0d9d }, +/* 0x0d9e */ { true, 0x0d9e, 0x0d9e }, +/* 0x0d9f */ { true, 0x0d9f, 0x0d9f }, +/* 0x0da0 */ { true, 0x0da0, 0x0da0 }, +/* 0x0da1 */ { true, 0x0da1, 0x0da1 }, +/* 0x0da2 */ { true, 0x0da2, 0x0da2 }, +/* 0x0da3 */ { true, 0x0da3, 0x0da3 }, +/* 0x0da4 */ { true, 0x0da4, 0x0da4 }, +/* 0x0da5 */ { true, 0x0da5, 0x0da5 }, +/* 0x0da6 */ { true, 0x0da6, 0x0da6 }, +/* 0x0da7 */ { true, 0x0da7, 0x0da7 }, +/* 0x0da8 */ { true, 0x0da8, 0x0da8 }, +/* 0x0da9 */ { true, 0x0da9, 0x0da9 }, +/* 0x0daa */ { true, 0x0daa, 0x0daa }, +/* 0x0dab */ { true, 0x0dab, 0x0dab }, +/* 0x0dac */ { true, 0x0dac, 0x0dac }, +/* 0x0dad */ { true, 0x0dad, 0x0dad }, +/* 0x0dae */ { true, 0x0dae, 0x0dae }, +/* 0x0daf */ { true, 0x0daf, 0x0daf }, +/* 0x0db0 */ { true, 0x0db0, 0x0db0 }, +/* 0x0db1 */ { true, 0x0db1, 0x0db1 }, +/* 0x0db2 */ { false, 0x0db2, 0x0db2 }, +/* 0x0db3 */ { true, 0x0db3, 0x0db3 }, +/* 0x0db4 */ { true, 0x0db4, 0x0db4 }, +/* 0x0db5 */ { true, 0x0db5, 0x0db5 }, +/* 0x0db6 */ { true, 0x0db6, 0x0db6 }, +/* 0x0db7 */ { true, 0x0db7, 0x0db7 }, +/* 0x0db8 */ { true, 0x0db8, 0x0db8 }, +/* 0x0db9 */ { true, 0x0db9, 0x0db9 }, +/* 0x0dba */ { true, 0x0dba, 0x0dba }, +/* 0x0dbb */ { true, 0x0dbb, 0x0dbb }, +/* 0x0dbc */ { false, 0x0dbc, 0x0dbc }, +/* 0x0dbd */ { true, 0x0dbd, 0x0dbd }, +/* 0x0dbe */ { false, 0x0dbe, 0x0dbe }, +/* 0x0dbf */ { false, 0x0dbf, 0x0dbf }, +/* 0x0dc0 */ { true, 0x0dc0, 0x0dc0 }, +/* 0x0dc1 */ { true, 0x0dc1, 0x0dc1 }, +/* 0x0dc2 */ { true, 0x0dc2, 0x0dc2 }, +/* 0x0dc3 */ { true, 0x0dc3, 0x0dc3 }, +/* 0x0dc4 */ { true, 0x0dc4, 0x0dc4 }, +/* 0x0dc5 */ { true, 0x0dc5, 0x0dc5 }, +/* 0x0dc6 */ { true, 0x0dc6, 0x0dc6 }, +/* 0x0dc7 */ { false, 0x0dc7, 0x0dc7 }, +/* 0x0dc8 */ { false, 0x0dc8, 0x0dc8 }, +/* 0x0dc9 */ { false, 0x0dc9, 0x0dc9 }, +/* 0x0dca */ { true, 0x0dca, 0x0dca }, +/* 0x0dcb */ { false, 0x0dcb, 0x0dcb }, +/* 0x0dcc */ { false, 0x0dcc, 0x0dcc }, +/* 0x0dcd */ { false, 0x0dcd, 0x0dcd }, +/* 0x0dce */ { false, 0x0dce, 0x0dce }, +/* 0x0dcf */ { true, 0x0dcf, 0x0dcf }, +/* 0x0dd0 */ { true, 0x0dd0, 0x0dd0 }, +/* 0x0dd1 */ { true, 0x0dd1, 0x0dd1 }, +/* 0x0dd2 */ { true, 0x0dd2, 0x0dd2 }, +/* 0x0dd3 */ { true, 0x0dd3, 0x0dd3 }, +/* 0x0dd4 */ { true, 0x0dd4, 0x0dd4 }, +/* 0x0dd5 */ { false, 0x0dd5, 0x0dd5 }, +/* 0x0dd6 */ { true, 0x0dd6, 0x0dd6 }, +/* 0x0dd7 */ { false, 0x0dd7, 0x0dd7 }, +/* 0x0dd8 */ { true, 0x0dd8, 0x0dd8 }, +/* 0x0dd9 */ { true, 0x0dd9, 0x0dd9 }, +/* 0x0dda */ { true, 0x0dda, 0x0dda }, +/* 0x0ddb */ { true, 0x0ddb, 0x0ddb }, +/* 0x0ddc */ { true, 0x0ddc, 0x0ddc }, +/* 0x0ddd */ { true, 0x0ddd, 0x0ddd }, +/* 0x0dde */ { true, 0x0dde, 0x0dde }, +/* 0x0ddf */ { true, 0x0ddf, 0x0ddf }, +/* 0x0de0 */ { false, 0x0de0, 0x0de0 }, +/* 0x0de1 */ { false, 0x0de1, 0x0de1 }, +/* 0x0de2 */ { false, 0x0de2, 0x0de2 }, +/* 0x0de3 */ { false, 0x0de3, 0x0de3 }, +/* 0x0de4 */ { false, 0x0de4, 0x0de4 }, +/* 0x0de5 */ { false, 0x0de5, 0x0de5 }, +/* 0x0de6 */ { false, 0x0de6, 0x0de6 }, +/* 0x0de7 */ { false, 0x0de7, 0x0de7 }, +/* 0x0de8 */ { false, 0x0de8, 0x0de8 }, +/* 0x0de9 */ { false, 0x0de9, 0x0de9 }, +/* 0x0dea */ { false, 0x0dea, 0x0dea }, +/* 0x0deb */ { false, 0x0deb, 0x0deb }, +/* 0x0dec */ { false, 0x0dec, 0x0dec }, +/* 0x0ded */ { false, 0x0ded, 0x0ded }, +/* 0x0dee */ { false, 0x0dee, 0x0dee }, +/* 0x0def */ { false, 0x0def, 0x0def }, +/* 0x0df0 */ { false, 0x0df0, 0x0df0 }, +/* 0x0df1 */ { false, 0x0df1, 0x0df1 }, +/* 0x0df2 */ { true, 0x0df2, 0x0df2 }, +/* 0x0df3 */ { true, 0x0df3, 0x0df3 }, +/* 0x0df4 */ { false, 0x0df4, 0x0df4 }, +/* 0x0df5 */ { false, 0x0df5, 0x0df5 }, +/* 0x0df6 */ { false, 0x0df6, 0x0df6 }, +/* 0x0df7 */ { false, 0x0df7, 0x0df7 }, +/* 0x0df8 */ { false, 0x0df8, 0x0df8 }, +/* 0x0df9 */ { false, 0x0df9, 0x0df9 }, +/* 0x0dfa */ { false, 0x0dfa, 0x0dfa }, +/* 0x0dfb */ { false, 0x0dfb, 0x0dfb }, +/* 0x0dfc */ { false, 0x0dfc, 0x0dfc }, +/* 0x0dfd */ { false, 0x0dfd, 0x0dfd }, +/* 0x0dfe */ { false, 0x0dfe, 0x0dfe }, +/* 0x0dff */ { false, 0x0dff, 0x0dff }, +/* 0x0e00 */ { false, 0x0e00, 0x0e00 }, +/* 0x0e01 */ { true, 0x0e01, 0x0e01 }, +/* 0x0e02 */ { true, 0x0e02, 0x0e02 }, +/* 0x0e03 */ { true, 0x0e03, 0x0e03 }, +/* 0x0e04 */ { true, 0x0e04, 0x0e04 }, +/* 0x0e05 */ { true, 0x0e05, 0x0e05 }, +/* 0x0e06 */ { true, 0x0e06, 0x0e06 }, +/* 0x0e07 */ { true, 0x0e07, 0x0e07 }, +/* 0x0e08 */ { true, 0x0e08, 0x0e08 }, +/* 0x0e09 */ { true, 0x0e09, 0x0e09 }, +/* 0x0e0a */ { true, 0x0e0a, 0x0e0a }, +/* 0x0e0b */ { true, 0x0e0b, 0x0e0b }, +/* 0x0e0c */ { true, 0x0e0c, 0x0e0c }, +/* 0x0e0d */ { true, 0x0e0d, 0x0e0d }, +/* 0x0e0e */ { true, 0x0e0e, 0x0e0e }, +/* 0x0e0f */ { true, 0x0e0f, 0x0e0f }, +/* 0x0e10 */ { true, 0x0e10, 0x0e10 }, +/* 0x0e11 */ { true, 0x0e11, 0x0e11 }, +/* 0x0e12 */ { true, 0x0e12, 0x0e12 }, +/* 0x0e13 */ { true, 0x0e13, 0x0e13 }, +/* 0x0e14 */ { true, 0x0e14, 0x0e14 }, +/* 0x0e15 */ { true, 0x0e15, 0x0e15 }, +/* 0x0e16 */ { true, 0x0e16, 0x0e16 }, +/* 0x0e17 */ { true, 0x0e17, 0x0e17 }, +/* 0x0e18 */ { true, 0x0e18, 0x0e18 }, +/* 0x0e19 */ { true, 0x0e19, 0x0e19 }, +/* 0x0e1a */ { true, 0x0e1a, 0x0e1a }, +/* 0x0e1b */ { true, 0x0e1b, 0x0e1b }, +/* 0x0e1c */ { true, 0x0e1c, 0x0e1c }, +/* 0x0e1d */ { true, 0x0e1d, 0x0e1d }, +/* 0x0e1e */ { true, 0x0e1e, 0x0e1e }, +/* 0x0e1f */ { true, 0x0e1f, 0x0e1f }, +/* 0x0e20 */ { true, 0x0e20, 0x0e20 }, +/* 0x0e21 */ { true, 0x0e21, 0x0e21 }, +/* 0x0e22 */ { true, 0x0e22, 0x0e22 }, +/* 0x0e23 */ { true, 0x0e23, 0x0e23 }, +/* 0x0e24 */ { true, 0x0e24, 0x0e24 }, +/* 0x0e25 */ { true, 0x0e25, 0x0e25 }, +/* 0x0e26 */ { true, 0x0e26, 0x0e26 }, +/* 0x0e27 */ { true, 0x0e27, 0x0e27 }, +/* 0x0e28 */ { true, 0x0e28, 0x0e28 }, +/* 0x0e29 */ { true, 0x0e29, 0x0e29 }, +/* 0x0e2a */ { true, 0x0e2a, 0x0e2a }, +/* 0x0e2b */ { true, 0x0e2b, 0x0e2b }, +/* 0x0e2c */ { true, 0x0e2c, 0x0e2c }, +/* 0x0e2d */ { true, 0x0e2d, 0x0e2d }, +/* 0x0e2e */ { true, 0x0e2e, 0x0e2e }, +/* 0x0e2f */ { true, 0x0e2f, 0x0e2f }, +/* 0x0e30 */ { true, 0x0e30, 0x0e30 }, +/* 0x0e31 */ { true, 0x0e31, 0x0e31 }, +/* 0x0e32 */ { true, 0x0e32, 0x0e32 }, +/* 0x0e33 */ { true, 0x0e33, 0x0e33 }, +/* 0x0e34 */ { true, 0x0e34, 0x0e34 }, +/* 0x0e35 */ { true, 0x0e35, 0x0e35 }, +/* 0x0e36 */ { true, 0x0e36, 0x0e36 }, +/* 0x0e37 */ { true, 0x0e37, 0x0e37 }, +/* 0x0e38 */ { true, 0x0e38, 0x0e38 }, +/* 0x0e39 */ { true, 0x0e39, 0x0e39 }, +/* 0x0e3a */ { true, 0x0e3a, 0x0e3a }, +/* 0x0e3b */ { false, 0x0e3b, 0x0e3b }, +/* 0x0e3c */ { false, 0x0e3c, 0x0e3c }, +/* 0x0e3d */ { false, 0x0e3d, 0x0e3d }, +/* 0x0e3e */ { false, 0x0e3e, 0x0e3e }, +/* 0x0e3f */ { false, 0x0e3f, 0x0e3f }, +/* 0x0e40 */ { true, 0x0e40, 0x0e40 }, +/* 0x0e41 */ { true, 0x0e41, 0x0e41 }, +/* 0x0e42 */ { true, 0x0e42, 0x0e42 }, +/* 0x0e43 */ { true, 0x0e43, 0x0e43 }, +/* 0x0e44 */ { true, 0x0e44, 0x0e44 }, +/* 0x0e45 */ { true, 0x0e45, 0x0e45 }, +/* 0x0e46 */ { true, 0x0e46, 0x0e46 }, +/* 0x0e47 */ { true, 0x0e47, 0x0e47 }, +/* 0x0e48 */ { true, 0x0e48, 0x0e48 }, +/* 0x0e49 */ { true, 0x0e49, 0x0e49 }, +/* 0x0e4a */ { true, 0x0e4a, 0x0e4a }, +/* 0x0e4b */ { true, 0x0e4b, 0x0e4b }, +/* 0x0e4c */ { true, 0x0e4c, 0x0e4c }, +/* 0x0e4d */ { true, 0x0e4d, 0x0e4d }, +/* 0x0e4e */ { true, 0x0e4e, 0x0e4e }, +/* 0x0e4f */ { false, 0x0e4f, 0x0e4f }, +/* 0x0e50 */ { false, 0x0e50, 0x0e50 }, +/* 0x0e51 */ { false, 0x0e51, 0x0e51 }, +/* 0x0e52 */ { false, 0x0e52, 0x0e52 }, +/* 0x0e53 */ { false, 0x0e53, 0x0e53 }, +/* 0x0e54 */ { false, 0x0e54, 0x0e54 }, +/* 0x0e55 */ { false, 0x0e55, 0x0e55 }, +/* 0x0e56 */ { false, 0x0e56, 0x0e56 }, +/* 0x0e57 */ { false, 0x0e57, 0x0e57 }, +/* 0x0e58 */ { false, 0x0e58, 0x0e58 }, +/* 0x0e59 */ { false, 0x0e59, 0x0e59 }, +/* 0x0e5a */ { false, 0x0e5a, 0x0e5a }, +/* 0x0e5b */ { false, 0x0e5b, 0x0e5b }, +/* 0x0e5c */ { false, 0x0e5c, 0x0e5c }, +/* 0x0e5d */ { false, 0x0e5d, 0x0e5d }, +/* 0x0e5e */ { false, 0x0e5e, 0x0e5e }, +/* 0x0e5f */ { false, 0x0e5f, 0x0e5f }, +/* 0x0e60 */ { false, 0x0e60, 0x0e60 }, +/* 0x0e61 */ { false, 0x0e61, 0x0e61 }, +/* 0x0e62 */ { false, 0x0e62, 0x0e62 }, +/* 0x0e63 */ { false, 0x0e63, 0x0e63 }, +/* 0x0e64 */ { false, 0x0e64, 0x0e64 }, +/* 0x0e65 */ { false, 0x0e65, 0x0e65 }, +/* 0x0e66 */ { false, 0x0e66, 0x0e66 }, +/* 0x0e67 */ { false, 0x0e67, 0x0e67 }, +/* 0x0e68 */ { false, 0x0e68, 0x0e68 }, +/* 0x0e69 */ { false, 0x0e69, 0x0e69 }, +/* 0x0e6a */ { false, 0x0e6a, 0x0e6a }, +/* 0x0e6b */ { false, 0x0e6b, 0x0e6b }, +/* 0x0e6c */ { false, 0x0e6c, 0x0e6c }, +/* 0x0e6d */ { false, 0x0e6d, 0x0e6d }, +/* 0x0e6e */ { false, 0x0e6e, 0x0e6e }, +/* 0x0e6f */ { false, 0x0e6f, 0x0e6f }, +/* 0x0e70 */ { false, 0x0e70, 0x0e70 }, +/* 0x0e71 */ { false, 0x0e71, 0x0e71 }, +/* 0x0e72 */ { false, 0x0e72, 0x0e72 }, +/* 0x0e73 */ { false, 0x0e73, 0x0e73 }, +/* 0x0e74 */ { false, 0x0e74, 0x0e74 }, +/* 0x0e75 */ { false, 0x0e75, 0x0e75 }, +/* 0x0e76 */ { false, 0x0e76, 0x0e76 }, +/* 0x0e77 */ { false, 0x0e77, 0x0e77 }, +/* 0x0e78 */ { false, 0x0e78, 0x0e78 }, +/* 0x0e79 */ { false, 0x0e79, 0x0e79 }, +/* 0x0e7a */ { false, 0x0e7a, 0x0e7a }, +/* 0x0e7b */ { false, 0x0e7b, 0x0e7b }, +/* 0x0e7c */ { false, 0x0e7c, 0x0e7c }, +/* 0x0e7d */ { false, 0x0e7d, 0x0e7d }, +/* 0x0e7e */ { false, 0x0e7e, 0x0e7e }, +/* 0x0e7f */ { false, 0x0e7f, 0x0e7f }, +/* 0x0e80 */ { false, 0x0e80, 0x0e80 }, +/* 0x0e81 */ { true, 0x0e81, 0x0e81 }, +/* 0x0e82 */ { true, 0x0e82, 0x0e82 }, +/* 0x0e83 */ { false, 0x0e83, 0x0e83 }, +/* 0x0e84 */ { true, 0x0e84, 0x0e84 }, +/* 0x0e85 */ { false, 0x0e85, 0x0e85 }, +/* 0x0e86 */ { false, 0x0e86, 0x0e86 }, +/* 0x0e87 */ { true, 0x0e87, 0x0e87 }, +/* 0x0e88 */ { true, 0x0e88, 0x0e88 }, +/* 0x0e89 */ { false, 0x0e89, 0x0e89 }, +/* 0x0e8a */ { true, 0x0e8a, 0x0e8a }, +/* 0x0e8b */ { false, 0x0e8b, 0x0e8b }, +/* 0x0e8c */ { false, 0x0e8c, 0x0e8c }, +/* 0x0e8d */ { true, 0x0e8d, 0x0e8d }, +/* 0x0e8e */ { false, 0x0e8e, 0x0e8e }, +/* 0x0e8f */ { false, 0x0e8f, 0x0e8f }, +/* 0x0e90 */ { false, 0x0e90, 0x0e90 }, +/* 0x0e91 */ { false, 0x0e91, 0x0e91 }, +/* 0x0e92 */ { false, 0x0e92, 0x0e92 }, +/* 0x0e93 */ { false, 0x0e93, 0x0e93 }, +/* 0x0e94 */ { true, 0x0e94, 0x0e94 }, +/* 0x0e95 */ { true, 0x0e95, 0x0e95 }, +/* 0x0e96 */ { true, 0x0e96, 0x0e96 }, +/* 0x0e97 */ { true, 0x0e97, 0x0e97 }, +/* 0x0e98 */ { false, 0x0e98, 0x0e98 }, +/* 0x0e99 */ { true, 0x0e99, 0x0e99 }, +/* 0x0e9a */ { true, 0x0e9a, 0x0e9a }, +/* 0x0e9b */ { true, 0x0e9b, 0x0e9b }, +/* 0x0e9c */ { true, 0x0e9c, 0x0e9c }, +/* 0x0e9d */ { true, 0x0e9d, 0x0e9d }, +/* 0x0e9e */ { true, 0x0e9e, 0x0e9e }, +/* 0x0e9f */ { true, 0x0e9f, 0x0e9f }, +/* 0x0ea0 */ { false, 0x0ea0, 0x0ea0 }, +/* 0x0ea1 */ { true, 0x0ea1, 0x0ea1 }, +/* 0x0ea2 */ { true, 0x0ea2, 0x0ea2 }, +/* 0x0ea3 */ { true, 0x0ea3, 0x0ea3 }, +/* 0x0ea4 */ { false, 0x0ea4, 0x0ea4 }, +/* 0x0ea5 */ { true, 0x0ea5, 0x0ea5 }, +/* 0x0ea6 */ { false, 0x0ea6, 0x0ea6 }, +/* 0x0ea7 */ { true, 0x0ea7, 0x0ea7 }, +/* 0x0ea8 */ { false, 0x0ea8, 0x0ea8 }, +/* 0x0ea9 */ { false, 0x0ea9, 0x0ea9 }, +/* 0x0eaa */ { true, 0x0eaa, 0x0eaa }, +/* 0x0eab */ { true, 0x0eab, 0x0eab }, +/* 0x0eac */ { false, 0x0eac, 0x0eac }, +/* 0x0ead */ { true, 0x0ead, 0x0ead }, +/* 0x0eae */ { true, 0x0eae, 0x0eae }, +/* 0x0eaf */ { true, 0x0eaf, 0x0eaf }, +/* 0x0eb0 */ { true, 0x0eb0, 0x0eb0 }, +/* 0x0eb1 */ { true, 0x0eb1, 0x0eb1 }, +/* 0x0eb2 */ { true, 0x0eb2, 0x0eb2 }, +/* 0x0eb3 */ { true, 0x0eb3, 0x0eb3 }, +/* 0x0eb4 */ { true, 0x0eb4, 0x0eb4 }, +/* 0x0eb5 */ { true, 0x0eb5, 0x0eb5 }, +/* 0x0eb6 */ { true, 0x0eb6, 0x0eb6 }, +/* 0x0eb7 */ { true, 0x0eb7, 0x0eb7 }, +/* 0x0eb8 */ { true, 0x0eb8, 0x0eb8 }, +/* 0x0eb9 */ { true, 0x0eb9, 0x0eb9 }, +/* 0x0eba */ { false, 0x0eba, 0x0eba }, +/* 0x0ebb */ { true, 0x0ebb, 0x0ebb }, +/* 0x0ebc */ { true, 0x0ebc, 0x0ebc }, +/* 0x0ebd */ { true, 0x0ebd, 0x0ebd }, +/* 0x0ebe */ { false, 0x0ebe, 0x0ebe }, +/* 0x0ebf */ { false, 0x0ebf, 0x0ebf }, +/* 0x0ec0 */ { true, 0x0ec0, 0x0ec0 }, +/* 0x0ec1 */ { true, 0x0ec1, 0x0ec1 }, +/* 0x0ec2 */ { true, 0x0ec2, 0x0ec2 }, +/* 0x0ec3 */ { true, 0x0ec3, 0x0ec3 }, +/* 0x0ec4 */ { true, 0x0ec4, 0x0ec4 }, +/* 0x0ec5 */ { false, 0x0ec5, 0x0ec5 }, +/* 0x0ec6 */ { true, 0x0ec6, 0x0ec6 }, +/* 0x0ec7 */ { false, 0x0ec7, 0x0ec7 }, +/* 0x0ec8 */ { true, 0x0ec8, 0x0ec8 }, +/* 0x0ec9 */ { true, 0x0ec9, 0x0ec9 }, +/* 0x0eca */ { true, 0x0eca, 0x0eca }, +/* 0x0ecb */ { true, 0x0ecb, 0x0ecb }, +/* 0x0ecc */ { true, 0x0ecc, 0x0ecc }, +/* 0x0ecd */ { true, 0x0ecd, 0x0ecd }, +/* 0x0ece */ { false, 0x0ece, 0x0ece }, +/* 0x0ecf */ { false, 0x0ecf, 0x0ecf }, +/* 0x0ed0 */ { false, 0x0ed0, 0x0ed0 }, +/* 0x0ed1 */ { false, 0x0ed1, 0x0ed1 }, +/* 0x0ed2 */ { false, 0x0ed2, 0x0ed2 }, +/* 0x0ed3 */ { false, 0x0ed3, 0x0ed3 }, +/* 0x0ed4 */ { false, 0x0ed4, 0x0ed4 }, +/* 0x0ed5 */ { false, 0x0ed5, 0x0ed5 }, +/* 0x0ed6 */ { false, 0x0ed6, 0x0ed6 }, +/* 0x0ed7 */ { false, 0x0ed7, 0x0ed7 }, +/* 0x0ed8 */ { false, 0x0ed8, 0x0ed8 }, +/* 0x0ed9 */ { false, 0x0ed9, 0x0ed9 }, +/* 0x0eda */ { false, 0x0eda, 0x0eda }, +/* 0x0edb */ { false, 0x0edb, 0x0edb }, +/* 0x0edc */ { true, 0x0edc, 0x0edc }, +/* 0x0edd */ { true, 0x0edd, 0x0edd }, +/* 0x0ede */ { false, 0x0ede, 0x0ede }, +/* 0x0edf */ { false, 0x0edf, 0x0edf }, +/* 0x0ee0 */ { false, 0x0ee0, 0x0ee0 }, +/* 0x0ee1 */ { false, 0x0ee1, 0x0ee1 }, +/* 0x0ee2 */ { false, 0x0ee2, 0x0ee2 }, +/* 0x0ee3 */ { false, 0x0ee3, 0x0ee3 }, +/* 0x0ee4 */ { false, 0x0ee4, 0x0ee4 }, +/* 0x0ee5 */ { false, 0x0ee5, 0x0ee5 }, +/* 0x0ee6 */ { false, 0x0ee6, 0x0ee6 }, +/* 0x0ee7 */ { false, 0x0ee7, 0x0ee7 }, +/* 0x0ee8 */ { false, 0x0ee8, 0x0ee8 }, +/* 0x0ee9 */ { false, 0x0ee9, 0x0ee9 }, +/* 0x0eea */ { false, 0x0eea, 0x0eea }, +/* 0x0eeb */ { false, 0x0eeb, 0x0eeb }, +/* 0x0eec */ { false, 0x0eec, 0x0eec }, +/* 0x0eed */ { false, 0x0eed, 0x0eed }, +/* 0x0eee */ { false, 0x0eee, 0x0eee }, +/* 0x0eef */ { false, 0x0eef, 0x0eef }, +/* 0x0ef0 */ { false, 0x0ef0, 0x0ef0 }, +/* 0x0ef1 */ { false, 0x0ef1, 0x0ef1 }, +/* 0x0ef2 */ { false, 0x0ef2, 0x0ef2 }, +/* 0x0ef3 */ { false, 0x0ef3, 0x0ef3 }, +/* 0x0ef4 */ { false, 0x0ef4, 0x0ef4 }, +/* 0x0ef5 */ { false, 0x0ef5, 0x0ef5 }, +/* 0x0ef6 */ { false, 0x0ef6, 0x0ef6 }, +/* 0x0ef7 */ { false, 0x0ef7, 0x0ef7 }, +/* 0x0ef8 */ { false, 0x0ef8, 0x0ef8 }, +/* 0x0ef9 */ { false, 0x0ef9, 0x0ef9 }, +/* 0x0efa */ { false, 0x0efa, 0x0efa }, +/* 0x0efb */ { false, 0x0efb, 0x0efb }, +/* 0x0efc */ { false, 0x0efc, 0x0efc }, +/* 0x0efd */ { false, 0x0efd, 0x0efd }, +/* 0x0efe */ { false, 0x0efe, 0x0efe }, +/* 0x0eff */ { false, 0x0eff, 0x0eff }, +/* 0x0f00 */ { true, 0x0f00, 0x0f00 }, +/* 0x0f01 */ { false, 0x0f01, 0x0f01 }, +/* 0x0f02 */ { false, 0x0f02, 0x0f02 }, +/* 0x0f03 */ { false, 0x0f03, 0x0f03 }, +/* 0x0f04 */ { false, 0x0f04, 0x0f04 }, +/* 0x0f05 */ { false, 0x0f05, 0x0f05 }, +/* 0x0f06 */ { false, 0x0f06, 0x0f06 }, +/* 0x0f07 */ { false, 0x0f07, 0x0f07 }, +/* 0x0f08 */ { false, 0x0f08, 0x0f08 }, +/* 0x0f09 */ { false, 0x0f09, 0x0f09 }, +/* 0x0f0a */ { false, 0x0f0a, 0x0f0a }, +/* 0x0f0b */ { false, 0x0f0b, 0x0f0b }, +/* 0x0f0c */ { false, 0x0f0c, 0x0f0c }, +/* 0x0f0d */ { false, 0x0f0d, 0x0f0d }, +/* 0x0f0e */ { false, 0x0f0e, 0x0f0e }, +/* 0x0f0f */ { false, 0x0f0f, 0x0f0f }, +/* 0x0f10 */ { false, 0x0f10, 0x0f10 }, +/* 0x0f11 */ { false, 0x0f11, 0x0f11 }, +/* 0x0f12 */ { false, 0x0f12, 0x0f12 }, +/* 0x0f13 */ { false, 0x0f13, 0x0f13 }, +/* 0x0f14 */ { false, 0x0f14, 0x0f14 }, +/* 0x0f15 */ { false, 0x0f15, 0x0f15 }, +/* 0x0f16 */ { false, 0x0f16, 0x0f16 }, +/* 0x0f17 */ { false, 0x0f17, 0x0f17 }, +/* 0x0f18 */ { true, 0x0f18, 0x0f18 }, +/* 0x0f19 */ { true, 0x0f19, 0x0f19 }, +/* 0x0f1a */ { false, 0x0f1a, 0x0f1a }, +/* 0x0f1b */ { false, 0x0f1b, 0x0f1b }, +/* 0x0f1c */ { false, 0x0f1c, 0x0f1c }, +/* 0x0f1d */ { false, 0x0f1d, 0x0f1d }, +/* 0x0f1e */ { false, 0x0f1e, 0x0f1e }, +/* 0x0f1f */ { false, 0x0f1f, 0x0f1f }, +/* 0x0f20 */ { false, 0x0f20, 0x0f20 }, +/* 0x0f21 */ { false, 0x0f21, 0x0f21 }, +/* 0x0f22 */ { false, 0x0f22, 0x0f22 }, +/* 0x0f23 */ { false, 0x0f23, 0x0f23 }, +/* 0x0f24 */ { false, 0x0f24, 0x0f24 }, +/* 0x0f25 */ { false, 0x0f25, 0x0f25 }, +/* 0x0f26 */ { false, 0x0f26, 0x0f26 }, +/* 0x0f27 */ { false, 0x0f27, 0x0f27 }, +/* 0x0f28 */ { false, 0x0f28, 0x0f28 }, +/* 0x0f29 */ { false, 0x0f29, 0x0f29 }, +/* 0x0f2a */ { false, 0x0f2a, 0x0f2a }, +/* 0x0f2b */ { false, 0x0f2b, 0x0f2b }, +/* 0x0f2c */ { false, 0x0f2c, 0x0f2c }, +/* 0x0f2d */ { false, 0x0f2d, 0x0f2d }, +/* 0x0f2e */ { false, 0x0f2e, 0x0f2e }, +/* 0x0f2f */ { false, 0x0f2f, 0x0f2f }, +/* 0x0f30 */ { false, 0x0f30, 0x0f30 }, +/* 0x0f31 */ { false, 0x0f31, 0x0f31 }, +/* 0x0f32 */ { false, 0x0f32, 0x0f32 }, +/* 0x0f33 */ { false, 0x0f33, 0x0f33 }, +/* 0x0f34 */ { false, 0x0f34, 0x0f34 }, +/* 0x0f35 */ { true, 0x0f35, 0x0f35 }, +/* 0x0f36 */ { false, 0x0f36, 0x0f36 }, +/* 0x0f37 */ { true, 0x0f37, 0x0f37 }, +/* 0x0f38 */ { false, 0x0f38, 0x0f38 }, +/* 0x0f39 */ { true, 0x0f39, 0x0f39 }, +/* 0x0f3a */ { false, 0x0f3a, 0x0f3a }, +/* 0x0f3b */ { false, 0x0f3b, 0x0f3b }, +/* 0x0f3c */ { false, 0x0f3c, 0x0f3c }, +/* 0x0f3d */ { false, 0x0f3d, 0x0f3d }, +/* 0x0f3e */ { true, 0x0f3e, 0x0f3e }, +/* 0x0f3f */ { true, 0x0f3f, 0x0f3f }, +/* 0x0f40 */ { true, 0x0f40, 0x0f40 }, +/* 0x0f41 */ { true, 0x0f41, 0x0f41 }, +/* 0x0f42 */ { true, 0x0f42, 0x0f42 }, +/* 0x0f43 */ { true, 0x0f43, 0x0f43 }, +/* 0x0f44 */ { true, 0x0f44, 0x0f44 }, +/* 0x0f45 */ { true, 0x0f45, 0x0f45 }, +/* 0x0f46 */ { true, 0x0f46, 0x0f46 }, +/* 0x0f47 */ { true, 0x0f47, 0x0f47 }, +/* 0x0f48 */ { false, 0x0f48, 0x0f48 }, +/* 0x0f49 */ { true, 0x0f49, 0x0f49 }, +/* 0x0f4a */ { true, 0x0f4a, 0x0f4a }, +/* 0x0f4b */ { true, 0x0f4b, 0x0f4b }, +/* 0x0f4c */ { true, 0x0f4c, 0x0f4c }, +/* 0x0f4d */ { true, 0x0f4d, 0x0f4d }, +/* 0x0f4e */ { true, 0x0f4e, 0x0f4e }, +/* 0x0f4f */ { true, 0x0f4f, 0x0f4f }, +/* 0x0f50 */ { true, 0x0f50, 0x0f50 }, +/* 0x0f51 */ { true, 0x0f51, 0x0f51 }, +/* 0x0f52 */ { true, 0x0f52, 0x0f52 }, +/* 0x0f53 */ { true, 0x0f53, 0x0f53 }, +/* 0x0f54 */ { true, 0x0f54, 0x0f54 }, +/* 0x0f55 */ { true, 0x0f55, 0x0f55 }, +/* 0x0f56 */ { true, 0x0f56, 0x0f56 }, +/* 0x0f57 */ { true, 0x0f57, 0x0f57 }, +/* 0x0f58 */ { true, 0x0f58, 0x0f58 }, +/* 0x0f59 */ { true, 0x0f59, 0x0f59 }, +/* 0x0f5a */ { true, 0x0f5a, 0x0f5a }, +/* 0x0f5b */ { true, 0x0f5b, 0x0f5b }, +/* 0x0f5c */ { true, 0x0f5c, 0x0f5c }, +/* 0x0f5d */ { true, 0x0f5d, 0x0f5d }, +/* 0x0f5e */ { true, 0x0f5e, 0x0f5e }, +/* 0x0f5f */ { true, 0x0f5f, 0x0f5f }, +/* 0x0f60 */ { true, 0x0f60, 0x0f60 }, +/* 0x0f61 */ { true, 0x0f61, 0x0f61 }, +/* 0x0f62 */ { true, 0x0f62, 0x0f62 }, +/* 0x0f63 */ { true, 0x0f63, 0x0f63 }, +/* 0x0f64 */ { true, 0x0f64, 0x0f64 }, +/* 0x0f65 */ { true, 0x0f65, 0x0f65 }, +/* 0x0f66 */ { true, 0x0f66, 0x0f66 }, +/* 0x0f67 */ { true, 0x0f67, 0x0f67 }, +/* 0x0f68 */ { true, 0x0f68, 0x0f68 }, +/* 0x0f69 */ { true, 0x0f69, 0x0f69 }, +/* 0x0f6a */ { true, 0x0f6a, 0x0f6a }, +/* 0x0f6b */ { false, 0x0f6b, 0x0f6b }, +/* 0x0f6c */ { false, 0x0f6c, 0x0f6c }, +/* 0x0f6d */ { false, 0x0f6d, 0x0f6d }, +/* 0x0f6e */ { false, 0x0f6e, 0x0f6e }, +/* 0x0f6f */ { false, 0x0f6f, 0x0f6f }, +/* 0x0f70 */ { false, 0x0f70, 0x0f70 }, +/* 0x0f71 */ { true, 0x0f71, 0x0f71 }, +/* 0x0f72 */ { true, 0x0f72, 0x0f72 }, +/* 0x0f73 */ { true, 0x0f73, 0x0f73 }, +/* 0x0f74 */ { true, 0x0f74, 0x0f74 }, +/* 0x0f75 */ { true, 0x0f75, 0x0f75 }, +/* 0x0f76 */ { true, 0x0f76, 0x0f76 }, +/* 0x0f77 */ { true, 0x0f77, 0x0f77 }, +/* 0x0f78 */ { true, 0x0f78, 0x0f78 }, +/* 0x0f79 */ { true, 0x0f79, 0x0f79 }, +/* 0x0f7a */ { true, 0x0f7a, 0x0f7a }, +/* 0x0f7b */ { true, 0x0f7b, 0x0f7b }, +/* 0x0f7c */ { true, 0x0f7c, 0x0f7c }, +/* 0x0f7d */ { true, 0x0f7d, 0x0f7d }, +/* 0x0f7e */ { true, 0x0f7e, 0x0f7e }, +/* 0x0f7f */ { true, 0x0f7f, 0x0f7f }, +/* 0x0f80 */ { true, 0x0f80, 0x0f80 }, +/* 0x0f81 */ { true, 0x0f81, 0x0f81 }, +/* 0x0f82 */ { true, 0x0f82, 0x0f82 }, +/* 0x0f83 */ { true, 0x0f83, 0x0f83 }, +/* 0x0f84 */ { true, 0x0f84, 0x0f84 }, +/* 0x0f85 */ { false, 0x0f85, 0x0f85 }, +/* 0x0f86 */ { true, 0x0f86, 0x0f86 }, +/* 0x0f87 */ { true, 0x0f87, 0x0f87 }, +/* 0x0f88 */ { true, 0x0f88, 0x0f88 }, +/* 0x0f89 */ { true, 0x0f89, 0x0f89 }, +/* 0x0f8a */ { true, 0x0f8a, 0x0f8a }, +/* 0x0f8b */ { true, 0x0f8b, 0x0f8b }, +/* 0x0f8c */ { false, 0x0f8c, 0x0f8c }, +/* 0x0f8d */ { false, 0x0f8d, 0x0f8d }, +/* 0x0f8e */ { false, 0x0f8e, 0x0f8e }, +/* 0x0f8f */ { false, 0x0f8f, 0x0f8f }, +/* 0x0f90 */ { true, 0x0f90, 0x0f90 }, +/* 0x0f91 */ { true, 0x0f91, 0x0f91 }, +/* 0x0f92 */ { true, 0x0f92, 0x0f92 }, +/* 0x0f93 */ { true, 0x0f93, 0x0f93 }, +/* 0x0f94 */ { true, 0x0f94, 0x0f94 }, +/* 0x0f95 */ { true, 0x0f95, 0x0f95 }, +/* 0x0f96 */ { true, 0x0f96, 0x0f96 }, +/* 0x0f97 */ { true, 0x0f97, 0x0f97 }, +/* 0x0f98 */ { false, 0x0f98, 0x0f98 }, +/* 0x0f99 */ { true, 0x0f99, 0x0f99 }, +/* 0x0f9a */ { true, 0x0f9a, 0x0f9a }, +/* 0x0f9b */ { true, 0x0f9b, 0x0f9b }, +/* 0x0f9c */ { true, 0x0f9c, 0x0f9c }, +/* 0x0f9d */ { true, 0x0f9d, 0x0f9d }, +/* 0x0f9e */ { true, 0x0f9e, 0x0f9e }, +/* 0x0f9f */ { true, 0x0f9f, 0x0f9f }, +/* 0x0fa0 */ { true, 0x0fa0, 0x0fa0 }, +/* 0x0fa1 */ { true, 0x0fa1, 0x0fa1 }, +/* 0x0fa2 */ { true, 0x0fa2, 0x0fa2 }, +/* 0x0fa3 */ { true, 0x0fa3, 0x0fa3 }, +/* 0x0fa4 */ { true, 0x0fa4, 0x0fa4 }, +/* 0x0fa5 */ { true, 0x0fa5, 0x0fa5 }, +/* 0x0fa6 */ { true, 0x0fa6, 0x0fa6 }, +/* 0x0fa7 */ { true, 0x0fa7, 0x0fa7 }, +/* 0x0fa8 */ { true, 0x0fa8, 0x0fa8 }, +/* 0x0fa9 */ { true, 0x0fa9, 0x0fa9 }, +/* 0x0faa */ { true, 0x0faa, 0x0faa }, +/* 0x0fab */ { true, 0x0fab, 0x0fab }, +/* 0x0fac */ { true, 0x0fac, 0x0fac }, +/* 0x0fad */ { true, 0x0fad, 0x0fad }, +/* 0x0fae */ { true, 0x0fae, 0x0fae }, +/* 0x0faf */ { true, 0x0faf, 0x0faf }, +/* 0x0fb0 */ { true, 0x0fb0, 0x0fb0 }, +/* 0x0fb1 */ { true, 0x0fb1, 0x0fb1 }, +/* 0x0fb2 */ { true, 0x0fb2, 0x0fb2 }, +/* 0x0fb3 */ { true, 0x0fb3, 0x0fb3 }, +/* 0x0fb4 */ { true, 0x0fb4, 0x0fb4 }, +/* 0x0fb5 */ { true, 0x0fb5, 0x0fb5 }, +/* 0x0fb6 */ { true, 0x0fb6, 0x0fb6 }, +/* 0x0fb7 */ { true, 0x0fb7, 0x0fb7 }, +/* 0x0fb8 */ { true, 0x0fb8, 0x0fb8 }, +/* 0x0fb9 */ { true, 0x0fb9, 0x0fb9 }, +/* 0x0fba */ { true, 0x0fba, 0x0fba }, +/* 0x0fbb */ { true, 0x0fbb, 0x0fbb }, +/* 0x0fbc */ { true, 0x0fbc, 0x0fbc }, +/* 0x0fbd */ { false, 0x0fbd, 0x0fbd }, +/* 0x0fbe */ { false, 0x0fbe, 0x0fbe }, +/* 0x0fbf */ { false, 0x0fbf, 0x0fbf }, +/* 0x0fc0 */ { false, 0x0fc0, 0x0fc0 }, +/* 0x0fc1 */ { false, 0x0fc1, 0x0fc1 }, +/* 0x0fc2 */ { false, 0x0fc2, 0x0fc2 }, +/* 0x0fc3 */ { false, 0x0fc3, 0x0fc3 }, +/* 0x0fc4 */ { false, 0x0fc4, 0x0fc4 }, +/* 0x0fc5 */ { false, 0x0fc5, 0x0fc5 }, +/* 0x0fc6 */ { true, 0x0fc6, 0x0fc6 }, +/* 0x0fc7 */ { false, 0x0fc7, 0x0fc7 }, +/* 0x0fc8 */ { false, 0x0fc8, 0x0fc8 }, +/* 0x0fc9 */ { false, 0x0fc9, 0x0fc9 }, +/* 0x0fca */ { false, 0x0fca, 0x0fca }, +/* 0x0fcb */ { false, 0x0fcb, 0x0fcb }, +/* 0x0fcc */ { false, 0x0fcc, 0x0fcc }, +/* 0x0fcd */ { false, 0x0fcd, 0x0fcd }, +/* 0x0fce */ { false, 0x0fce, 0x0fce }, +/* 0x0fcf */ { false, 0x0fcf, 0x0fcf }, +/* 0x0fd0 */ { false, 0x0fd0, 0x0fd0 }, +/* 0x0fd1 */ { false, 0x0fd1, 0x0fd1 }, +/* 0x0fd2 */ { false, 0x0fd2, 0x0fd2 }, +/* 0x0fd3 */ { false, 0x0fd3, 0x0fd3 }, +/* 0x0fd4 */ { false, 0x0fd4, 0x0fd4 }, +/* 0x0fd5 */ { false, 0x0fd5, 0x0fd5 }, +/* 0x0fd6 */ { false, 0x0fd6, 0x0fd6 }, +/* 0x0fd7 */ { false, 0x0fd7, 0x0fd7 }, +/* 0x0fd8 */ { false, 0x0fd8, 0x0fd8 }, +/* 0x0fd9 */ { false, 0x0fd9, 0x0fd9 }, +/* 0x0fda */ { false, 0x0fda, 0x0fda }, +/* 0x0fdb */ { false, 0x0fdb, 0x0fdb }, +/* 0x0fdc */ { false, 0x0fdc, 0x0fdc }, +/* 0x0fdd */ { false, 0x0fdd, 0x0fdd }, +/* 0x0fde */ { false, 0x0fde, 0x0fde }, +/* 0x0fdf */ { false, 0x0fdf, 0x0fdf }, +/* 0x0fe0 */ { false, 0x0fe0, 0x0fe0 }, +/* 0x0fe1 */ { false, 0x0fe1, 0x0fe1 }, +/* 0x0fe2 */ { false, 0x0fe2, 0x0fe2 }, +/* 0x0fe3 */ { false, 0x0fe3, 0x0fe3 }, +/* 0x0fe4 */ { false, 0x0fe4, 0x0fe4 }, +/* 0x0fe5 */ { false, 0x0fe5, 0x0fe5 }, +/* 0x0fe6 */ { false, 0x0fe6, 0x0fe6 }, +/* 0x0fe7 */ { false, 0x0fe7, 0x0fe7 }, +/* 0x0fe8 */ { false, 0x0fe8, 0x0fe8 }, +/* 0x0fe9 */ { false, 0x0fe9, 0x0fe9 }, +/* 0x0fea */ { false, 0x0fea, 0x0fea }, +/* 0x0feb */ { false, 0x0feb, 0x0feb }, +/* 0x0fec */ { false, 0x0fec, 0x0fec }, +/* 0x0fed */ { false, 0x0fed, 0x0fed }, +/* 0x0fee */ { false, 0x0fee, 0x0fee }, +/* 0x0fef */ { false, 0x0fef, 0x0fef }, +/* 0x0ff0 */ { false, 0x0ff0, 0x0ff0 }, +/* 0x0ff1 */ { false, 0x0ff1, 0x0ff1 }, +/* 0x0ff2 */ { false, 0x0ff2, 0x0ff2 }, +/* 0x0ff3 */ { false, 0x0ff3, 0x0ff3 }, +/* 0x0ff4 */ { false, 0x0ff4, 0x0ff4 }, +/* 0x0ff5 */ { false, 0x0ff5, 0x0ff5 }, +/* 0x0ff6 */ { false, 0x0ff6, 0x0ff6 }, +/* 0x0ff7 */ { false, 0x0ff7, 0x0ff7 }, +/* 0x0ff8 */ { false, 0x0ff8, 0x0ff8 }, +/* 0x0ff9 */ { false, 0x0ff9, 0x0ff9 }, +/* 0x0ffa */ { false, 0x0ffa, 0x0ffa }, +/* 0x0ffb */ { false, 0x0ffb, 0x0ffb }, +/* 0x0ffc */ { false, 0x0ffc, 0x0ffc }, +/* 0x0ffd */ { false, 0x0ffd, 0x0ffd }, +/* 0x0ffe */ { false, 0x0ffe, 0x0ffe }, +/* 0x0fff */ { false, 0x0fff, 0x0fff }, +/* 0x1000 */ { true, 0x1000, 0x1000 }, +/* 0x1001 */ { true, 0x1001, 0x1001 }, +/* 0x1002 */ { true, 0x1002, 0x1002 }, +/* 0x1003 */ { true, 0x1003, 0x1003 }, +/* 0x1004 */ { true, 0x1004, 0x1004 }, +/* 0x1005 */ { true, 0x1005, 0x1005 }, +/* 0x1006 */ { true, 0x1006, 0x1006 }, +/* 0x1007 */ { true, 0x1007, 0x1007 }, +/* 0x1008 */ { true, 0x1008, 0x1008 }, +/* 0x1009 */ { true, 0x1009, 0x1009 }, +/* 0x100a */ { true, 0x100a, 0x100a }, +/* 0x100b */ { true, 0x100b, 0x100b }, +/* 0x100c */ { true, 0x100c, 0x100c }, +/* 0x100d */ { true, 0x100d, 0x100d }, +/* 0x100e */ { true, 0x100e, 0x100e }, +/* 0x100f */ { true, 0x100f, 0x100f }, +/* 0x1010 */ { true, 0x1010, 0x1010 }, +/* 0x1011 */ { true, 0x1011, 0x1011 }, +/* 0x1012 */ { true, 0x1012, 0x1012 }, +/* 0x1013 */ { true, 0x1013, 0x1013 }, +/* 0x1014 */ { true, 0x1014, 0x1014 }, +/* 0x1015 */ { true, 0x1015, 0x1015 }, +/* 0x1016 */ { true, 0x1016, 0x1016 }, +/* 0x1017 */ { true, 0x1017, 0x1017 }, +/* 0x1018 */ { true, 0x1018, 0x1018 }, +/* 0x1019 */ { true, 0x1019, 0x1019 }, +/* 0x101a */ { true, 0x101a, 0x101a }, +/* 0x101b */ { true, 0x101b, 0x101b }, +/* 0x101c */ { true, 0x101c, 0x101c }, +/* 0x101d */ { true, 0x101d, 0x101d }, +/* 0x101e */ { true, 0x101e, 0x101e }, +/* 0x101f */ { true, 0x101f, 0x101f }, +/* 0x1020 */ { true, 0x1020, 0x1020 }, +/* 0x1021 */ { true, 0x1021, 0x1021 }, +/* 0x1022 */ { false, 0x1022, 0x1022 }, +/* 0x1023 */ { true, 0x1023, 0x1023 }, +/* 0x1024 */ { true, 0x1024, 0x1024 }, +/* 0x1025 */ { true, 0x1025, 0x1025 }, +/* 0x1026 */ { true, 0x1026, 0x1026 }, +/* 0x1027 */ { true, 0x1027, 0x1027 }, +/* 0x1028 */ { false, 0x1028, 0x1028 }, +/* 0x1029 */ { true, 0x1029, 0x1029 }, +/* 0x102a */ { true, 0x102a, 0x102a }, +/* 0x102b */ { true, 0x102b, 0x102b }, +/* 0x102c */ { true, 0x102c, 0x102c }, +/* 0x102d */ { true, 0x102d, 0x102d }, +/* 0x102e */ { true, 0x102e, 0x102e }, +/* 0x102f */ { true, 0x102f, 0x102f }, +/* 0x1030 */ { true, 0x1030, 0x1030 }, +/* 0x1031 */ { true, 0x1031, 0x1031 }, +/* 0x1032 */ { true, 0x1032, 0x1032 }, +/* 0x1033 */ { false, 0x1033, 0x1033 }, +/* 0x1034 */ { false, 0x1034, 0x1034 }, +/* 0x1035 */ { false, 0x1035, 0x1035 }, +/* 0x1036 */ { true, 0x1036, 0x1036 }, +/* 0x1037 */ { true, 0x1037, 0x1037 }, +/* 0x1038 */ { true, 0x1038, 0x1038 }, +/* 0x1039 */ { true, 0x1039, 0x1039 }, +/* 0x103a */ { false, 0x103a, 0x103a }, +/* 0x103b */ { true, 0x103b, 0x103b }, +/* 0x103c */ { true, 0x103c, 0x103c }, +/* 0x103d */ { false, 0x103d, 0x103d }, +/* 0x103e */ { false, 0x103e, 0x103e }, +/* 0x103f */ { false, 0x103f, 0x103f }, +/* 0x1040 */ { false, 0x1040, 0x1040 }, +/* 0x1041 */ { false, 0x1041, 0x1041 }, +/* 0x1042 */ { false, 0x1042, 0x1042 }, +/* 0x1043 */ { false, 0x1043, 0x1043 }, +/* 0x1044 */ { false, 0x1044, 0x1044 }, +/* 0x1045 */ { false, 0x1045, 0x1045 }, +/* 0x1046 */ { false, 0x1046, 0x1046 }, +/* 0x1047 */ { false, 0x1047, 0x1047 }, +/* 0x1048 */ { false, 0x1048, 0x1048 }, +/* 0x1049 */ { false, 0x1049, 0x1049 }, +/* 0x104a */ { false, 0x104a, 0x104a }, +/* 0x104b */ { false, 0x104b, 0x104b }, +/* 0x104c */ { false, 0x104c, 0x104c }, +/* 0x104d */ { false, 0x104d, 0x104d }, +/* 0x104e */ { false, 0x104e, 0x104e }, +/* 0x104f */ { false, 0x104f, 0x104f }, +/* 0x1050 */ { true, 0x1050, 0x1050 }, +/* 0x1051 */ { true, 0x1051, 0x1051 }, +/* 0x1052 */ { true, 0x1052, 0x1052 }, +/* 0x1053 */ { true, 0x1053, 0x1053 }, +/* 0x1054 */ { true, 0x1054, 0x1054 }, +/* 0x1055 */ { true, 0x1055, 0x1055 }, +/* 0x1056 */ { true, 0x1056, 0x1056 }, +/* 0x1057 */ { true, 0x1057, 0x1057 }, +/* 0x1058 */ { true, 0x1058, 0x1058 }, +/* 0x1059 */ { true, 0x1059, 0x1059 }, +/* 0x105a */ { false, 0x105a, 0x105a }, +/* 0x105b */ { false, 0x105b, 0x105b }, +/* 0x105c */ { false, 0x105c, 0x105c }, +/* 0x105d */ { false, 0x105d, 0x105d }, +/* 0x105e */ { false, 0x105e, 0x105e }, +/* 0x105f */ { false, 0x105f, 0x105f }, +/* 0x1060 */ { false, 0x1060, 0x1060 }, +/* 0x1061 */ { false, 0x1061, 0x1061 }, +/* 0x1062 */ { true, 0x1062, 0x1062 }, +/* 0x1063 */ { true, 0x1063, 0x1063 }, +/* 0x1064 */ { true, 0x1064, 0x1064 }, +/* 0x1065 */ { false, 0x1065, 0x1065 }, +/* 0x1066 */ { false, 0x1066, 0x1066 }, +/* 0x1067 */ { true, 0x1067, 0x1067 }, +/* 0x1068 */ { true, 0x1068, 0x1068 }, +/* 0x1069 */ { true, 0x1069, 0x1069 }, +/* 0x106a */ { true, 0x106a, 0x106a }, +/* 0x106b */ { true, 0x106b, 0x106b }, +/* 0x106c */ { true, 0x106c, 0x106c }, +/* 0x106d */ { true, 0x106d, 0x106d }, +/* 0x106e */ { false, 0x106e, 0x106e }, +/* 0x106f */ { false, 0x106f, 0x106f }, +/* 0x1070 */ { false, 0x1070, 0x1070 }, +/* 0x1071 */ { false, 0x1071, 0x1071 }, +/* 0x1072 */ { false, 0x1072, 0x1072 }, +/* 0x1073 */ { false, 0x1073, 0x1073 }, +/* 0x1074 */ { false, 0x1074, 0x1074 }, +/* 0x1075 */ { false, 0x1075, 0x1075 }, +/* 0x1076 */ { false, 0x1076, 0x1076 }, +/* 0x1077 */ { false, 0x1077, 0x1077 }, +/* 0x1078 */ { false, 0x1078, 0x1078 }, +/* 0x1079 */ { false, 0x1079, 0x1079 }, +/* 0x107a */ { false, 0x107a, 0x107a }, +/* 0x107b */ { false, 0x107b, 0x107b }, +/* 0x107c */ { false, 0x107c, 0x107c }, +/* 0x107d */ { false, 0x107d, 0x107d }, +/* 0x107e */ { false, 0x107e, 0x107e }, +/* 0x107f */ { false, 0x107f, 0x107f }, +/* 0x1080 */ { false, 0x1080, 0x1080 }, +/* 0x1081 */ { false, 0x1081, 0x1081 }, +/* 0x1082 */ { false, 0x1082, 0x1082 }, +/* 0x1083 */ { true, 0x1083, 0x1083 }, +/* 0x1084 */ { true, 0x1084, 0x1084 }, +/* 0x1085 */ { false, 0x1085, 0x1085 }, +/* 0x1086 */ { false, 0x1086, 0x1086 }, +/* 0x1087 */ { true, 0x1087, 0x1087 }, +/* 0x1088 */ { true, 0x1088, 0x1088 }, +/* 0x1089 */ { true, 0x1089, 0x1089 }, +/* 0x108a */ { true, 0x108a, 0x108a }, +/* 0x108b */ { true, 0x108b, 0x108b }, +/* 0x108c */ { true, 0x108c, 0x108c }, +/* 0x108d */ { false, 0x108d, 0x108d }, +/* 0x108e */ { false, 0x108e, 0x108e }, +/* 0x108f */ { true, 0x108f, 0x108f }, +/* 0x1090 */ { false, 0x1090, 0x1090 }, +/* 0x1091 */ { false, 0x1091, 0x1091 }, +/* 0x1092 */ { false, 0x1092, 0x1092 }, +/* 0x1093 */ { false, 0x1093, 0x1093 }, +/* 0x1094 */ { false, 0x1094, 0x1094 }, +/* 0x1095 */ { false, 0x1095, 0x1095 }, +/* 0x1096 */ { false, 0x1096, 0x1096 }, +/* 0x1097 */ { false, 0x1097, 0x1097 }, +/* 0x1098 */ { false, 0x1098, 0x1098 }, +/* 0x1099 */ { false, 0x1099, 0x1099 }, +/* 0x109a */ { true, 0x109a, 0x109a }, +/* 0x109b */ { true, 0x109b, 0x109b }, +/* 0x109c */ { true, 0x109c, 0x109c }, +/* 0x109d */ { false, 0x109d, 0x109d }, +/* 0x109e */ { false, 0x109e, 0x109e }, +/* 0x109f */ { false, 0x109f, 0x109f }, +/* 0x10a0 */ { true, 0x10a0, 0x2d00 }, +/* 0x10a1 */ { true, 0x10a1, 0x2d01 }, +/* 0x10a2 */ { true, 0x10a2, 0x2d02 }, +/* 0x10a3 */ { true, 0x10a3, 0x2d03 }, +/* 0x10a4 */ { true, 0x10a4, 0x2d04 }, +/* 0x10a5 */ { true, 0x10a5, 0x2d05 }, +/* 0x10a6 */ { true, 0x10a6, 0x2d06 }, +/* 0x10a7 */ { true, 0x10a7, 0x2d07 }, +/* 0x10a8 */ { true, 0x10a8, 0x2d08 }, +/* 0x10a9 */ { true, 0x10a9, 0x2d09 }, +/* 0x10aa */ { true, 0x10aa, 0x2d0a }, +/* 0x10ab */ { true, 0x10ab, 0x2d0b }, +/* 0x10ac */ { true, 0x10ac, 0x2d0c }, +/* 0x10ad */ { true, 0x10ad, 0x2d0d }, +/* 0x10ae */ { true, 0x10ae, 0x2d0e }, +/* 0x10af */ { true, 0x10af, 0x2d0f }, +/* 0x10b0 */ { true, 0x10b0, 0x2d10 }, +/* 0x10b1 */ { true, 0x10b1, 0x2d11 }, +/* 0x10b2 */ { true, 0x10b2, 0x2d12 }, +/* 0x10b3 */ { true, 0x10b3, 0x2d13 }, +/* 0x10b4 */ { true, 0x10b4, 0x2d14 }, +/* 0x10b5 */ { true, 0x10b5, 0x2d15 }, +/* 0x10b6 */ { true, 0x10b6, 0x2d16 }, +/* 0x10b7 */ { true, 0x10b7, 0x2d17 }, +/* 0x10b8 */ { true, 0x10b8, 0x2d18 }, +/* 0x10b9 */ { true, 0x10b9, 0x2d19 }, +/* 0x10ba */ { true, 0x10ba, 0x2d1a }, +/* 0x10bb */ { true, 0x10bb, 0x2d1b }, +/* 0x10bc */ { true, 0x10bc, 0x2d1c }, +/* 0x10bd */ { true, 0x10bd, 0x2d1d }, +/* 0x10be */ { true, 0x10be, 0x2d1e }, +/* 0x10bf */ { true, 0x10bf, 0x2d1f }, +/* 0x10c0 */ { true, 0x10c0, 0x2d20 }, +/* 0x10c1 */ { true, 0x10c1, 0x2d21 }, +/* 0x10c2 */ { true, 0x10c2, 0x2d22 }, +/* 0x10c3 */ { true, 0x10c3, 0x2d23 }, +/* 0x10c4 */ { true, 0x10c4, 0x2d24 }, +/* 0x10c5 */ { true, 0x10c5, 0x2d25 }, +/* 0x10c6 */ { false, 0x10c6, 0x10c6 }, +/* 0x10c7 */ { false, 0x10c7, 0x10c7 }, +/* 0x10c8 */ { false, 0x10c8, 0x10c8 }, +/* 0x10c9 */ { false, 0x10c9, 0x10c9 }, +/* 0x10ca */ { false, 0x10ca, 0x10ca }, +/* 0x10cb */ { false, 0x10cb, 0x10cb }, +/* 0x10cc */ { false, 0x10cc, 0x10cc }, +/* 0x10cd */ { false, 0x10cd, 0x10cd }, +/* 0x10ce */ { false, 0x10ce, 0x10ce }, +/* 0x10cf */ { false, 0x10cf, 0x10cf }, +/* 0x10d0 */ { true, 0x10d0, 0x10d0 }, +/* 0x10d1 */ { true, 0x10d1, 0x10d1 }, +/* 0x10d2 */ { true, 0x10d2, 0x10d2 }, +/* 0x10d3 */ { true, 0x10d3, 0x10d3 }, +/* 0x10d4 */ { true, 0x10d4, 0x10d4 }, +/* 0x10d5 */ { true, 0x10d5, 0x10d5 }, +/* 0x10d6 */ { true, 0x10d6, 0x10d6 }, +/* 0x10d7 */ { true, 0x10d7, 0x10d7 }, +/* 0x10d8 */ { true, 0x10d8, 0x10d8 }, +/* 0x10d9 */ { true, 0x10d9, 0x10d9 }, +/* 0x10da */ { true, 0x10da, 0x10da }, +/* 0x10db */ { true, 0x10db, 0x10db }, +/* 0x10dc */ { true, 0x10dc, 0x10dc }, +/* 0x10dd */ { true, 0x10dd, 0x10dd }, +/* 0x10de */ { true, 0x10de, 0x10de }, +/* 0x10df */ { true, 0x10df, 0x10df }, +/* 0x10e0 */ { true, 0x10e0, 0x10e0 }, +/* 0x10e1 */ { true, 0x10e1, 0x10e1 }, +/* 0x10e2 */ { true, 0x10e2, 0x10e2 }, +/* 0x10e3 */ { true, 0x10e3, 0x10e3 }, +/* 0x10e4 */ { true, 0x10e4, 0x10e4 }, +/* 0x10e5 */ { true, 0x10e5, 0x10e5 }, +/* 0x10e6 */ { true, 0x10e6, 0x10e6 }, +/* 0x10e7 */ { true, 0x10e7, 0x10e7 }, +/* 0x10e8 */ { true, 0x10e8, 0x10e8 }, +/* 0x10e9 */ { true, 0x10e9, 0x10e9 }, +/* 0x10ea */ { true, 0x10ea, 0x10ea }, +/* 0x10eb */ { true, 0x10eb, 0x10eb }, +/* 0x10ec */ { true, 0x10ec, 0x10ec }, +/* 0x10ed */ { true, 0x10ed, 0x10ed }, +/* 0x10ee */ { true, 0x10ee, 0x10ee }, +/* 0x10ef */ { true, 0x10ef, 0x10ef }, +/* 0x10f0 */ { true, 0x10f0, 0x10f0 }, +/* 0x10f1 */ { true, 0x10f1, 0x10f1 }, +/* 0x10f2 */ { true, 0x10f2, 0x10f2 }, +/* 0x10f3 */ { true, 0x10f3, 0x10f3 }, +/* 0x10f4 */ { true, 0x10f4, 0x10f4 }, +/* 0x10f5 */ { true, 0x10f5, 0x10f5 }, +/* 0x10f6 */ { true, 0x10f6, 0x10f6 }, +/* 0x10f7 */ { true, 0x10f7, 0x10f7 }, +/* 0x10f8 */ { true, 0x10f8, 0x10f8 }, +/* 0x10f9 */ { true, 0x10f9, 0x10f9 }, +/* 0x10fa */ { true, 0x10fa, 0x10fa }, +/* 0x10fb */ { false, 0x10fb, 0x10fb }, +/* 0x10fc */ { true, 0x10fc, 0x10fc }, +/* 0x10fd */ { false, 0x10fd, 0x10fd }, +/* 0x10fe */ { false, 0x10fe, 0x10fe }, +/* 0x10ff */ { false, 0x10ff, 0x10ff }, +/* 0x1100 */ { true, 0x1100, 0x1100 }, +/* 0x1101 */ { true, 0x1101, 0x1101 }, +/* 0x1102 */ { true, 0x1102, 0x1102 }, +/* 0x1103 */ { true, 0x1103, 0x1103 }, +/* 0x1104 */ { true, 0x1104, 0x1104 }, +/* 0x1105 */ { true, 0x1105, 0x1105 }, +/* 0x1106 */ { true, 0x1106, 0x1106 }, +/* 0x1107 */ { true, 0x1107, 0x1107 }, +/* 0x1108 */ { true, 0x1108, 0x1108 }, +/* 0x1109 */ { true, 0x1109, 0x1109 }, +/* 0x110a */ { true, 0x110a, 0x110a }, +/* 0x110b */ { true, 0x110b, 0x110b }, +/* 0x110c */ { true, 0x110c, 0x110c }, +/* 0x110d */ { true, 0x110d, 0x110d }, +/* 0x110e */ { true, 0x110e, 0x110e }, +/* 0x110f */ { true, 0x110f, 0x110f }, +/* 0x1110 */ { true, 0x1110, 0x1110 }, +/* 0x1111 */ { true, 0x1111, 0x1111 }, +/* 0x1112 */ { true, 0x1112, 0x1112 }, +/* 0x1113 */ { true, 0x1113, 0x1113 }, +/* 0x1114 */ { true, 0x1114, 0x1114 }, +/* 0x1115 */ { true, 0x1115, 0x1115 }, +/* 0x1116 */ { true, 0x1116, 0x1116 }, +/* 0x1117 */ { true, 0x1117, 0x1117 }, +/* 0x1118 */ { true, 0x1118, 0x1118 }, +/* 0x1119 */ { true, 0x1119, 0x1119 }, +/* 0x111a */ { true, 0x111a, 0x111a }, +/* 0x111b */ { true, 0x111b, 0x111b }, +/* 0x111c */ { true, 0x111c, 0x111c }, +/* 0x111d */ { true, 0x111d, 0x111d }, +/* 0x111e */ { true, 0x111e, 0x111e }, +/* 0x111f */ { true, 0x111f, 0x111f }, +/* 0x1120 */ { true, 0x1120, 0x1120 }, +/* 0x1121 */ { true, 0x1121, 0x1121 }, +/* 0x1122 */ { true, 0x1122, 0x1122 }, +/* 0x1123 */ { true, 0x1123, 0x1123 }, +/* 0x1124 */ { true, 0x1124, 0x1124 }, +/* 0x1125 */ { true, 0x1125, 0x1125 }, +/* 0x1126 */ { true, 0x1126, 0x1126 }, +/* 0x1127 */ { true, 0x1127, 0x1127 }, +/* 0x1128 */ { true, 0x1128, 0x1128 }, +/* 0x1129 */ { true, 0x1129, 0x1129 }, +/* 0x112a */ { true, 0x112a, 0x112a }, +/* 0x112b */ { true, 0x112b, 0x112b }, +/* 0x112c */ { true, 0x112c, 0x112c }, +/* 0x112d */ { true, 0x112d, 0x112d }, +/* 0x112e */ { true, 0x112e, 0x112e }, +/* 0x112f */ { true, 0x112f, 0x112f }, +/* 0x1130 */ { true, 0x1130, 0x1130 }, +/* 0x1131 */ { true, 0x1131, 0x1131 }, +/* 0x1132 */ { true, 0x1132, 0x1132 }, +/* 0x1133 */ { true, 0x1133, 0x1133 }, +/* 0x1134 */ { true, 0x1134, 0x1134 }, +/* 0x1135 */ { true, 0x1135, 0x1135 }, +/* 0x1136 */ { true, 0x1136, 0x1136 }, +/* 0x1137 */ { true, 0x1137, 0x1137 }, +/* 0x1138 */ { true, 0x1138, 0x1138 }, +/* 0x1139 */ { true, 0x1139, 0x1139 }, +/* 0x113a */ { true, 0x113a, 0x113a }, +/* 0x113b */ { true, 0x113b, 0x113b }, +/* 0x113c */ { true, 0x113c, 0x113c }, +/* 0x113d */ { true, 0x113d, 0x113d }, +/* 0x113e */ { true, 0x113e, 0x113e }, +/* 0x113f */ { true, 0x113f, 0x113f }, +/* 0x1140 */ { true, 0x1140, 0x1140 }, +/* 0x1141 */ { true, 0x1141, 0x1141 }, +/* 0x1142 */ { true, 0x1142, 0x1142 }, +/* 0x1143 */ { true, 0x1143, 0x1143 }, +/* 0x1144 */ { true, 0x1144, 0x1144 }, +/* 0x1145 */ { true, 0x1145, 0x1145 }, +/* 0x1146 */ { true, 0x1146, 0x1146 }, +/* 0x1147 */ { true, 0x1147, 0x1147 }, +/* 0x1148 */ { true, 0x1148, 0x1148 }, +/* 0x1149 */ { true, 0x1149, 0x1149 }, +/* 0x114a */ { true, 0x114a, 0x114a }, +/* 0x114b */ { true, 0x114b, 0x114b }, +/* 0x114c */ { true, 0x114c, 0x114c }, +/* 0x114d */ { true, 0x114d, 0x114d }, +/* 0x114e */ { true, 0x114e, 0x114e }, +/* 0x114f */ { true, 0x114f, 0x114f }, +/* 0x1150 */ { true, 0x1150, 0x1150 }, +/* 0x1151 */ { true, 0x1151, 0x1151 }, +/* 0x1152 */ { true, 0x1152, 0x1152 }, +/* 0x1153 */ { true, 0x1153, 0x1153 }, +/* 0x1154 */ { true, 0x1154, 0x1154 }, +/* 0x1155 */ { true, 0x1155, 0x1155 }, +/* 0x1156 */ { true, 0x1156, 0x1156 }, +/* 0x1157 */ { true, 0x1157, 0x1157 }, +/* 0x1158 */ { true, 0x1158, 0x1158 }, +/* 0x1159 */ { true, 0x1159, 0x1159 }, +/* 0x115a */ { false, 0x115a, 0x115a }, +/* 0x115b */ { false, 0x115b, 0x115b }, +/* 0x115c */ { false, 0x115c, 0x115c }, +/* 0x115d */ { false, 0x115d, 0x115d }, +/* 0x115e */ { false, 0x115e, 0x115e }, +/* 0x115f */ { true, 0x115f, 0x115f }, +/* 0x1160 */ { true, 0x1160, 0x1160 }, +/* 0x1161 */ { true, 0x1161, 0x1161 }, +/* 0x1162 */ { true, 0x1162, 0x1162 }, +/* 0x1163 */ { true, 0x1163, 0x1163 }, +/* 0x1164 */ { true, 0x1164, 0x1164 }, +/* 0x1165 */ { true, 0x1165, 0x1165 }, +/* 0x1166 */ { true, 0x1166, 0x1166 }, +/* 0x1167 */ { true, 0x1167, 0x1167 }, +/* 0x1168 */ { true, 0x1168, 0x1168 }, +/* 0x1169 */ { true, 0x1169, 0x1169 }, +/* 0x116a */ { true, 0x116a, 0x116a }, +/* 0x116b */ { true, 0x116b, 0x116b }, +/* 0x116c */ { true, 0x116c, 0x116c }, +/* 0x116d */ { true, 0x116d, 0x116d }, +/* 0x116e */ { true, 0x116e, 0x116e }, +/* 0x116f */ { true, 0x116f, 0x116f }, +/* 0x1170 */ { true, 0x1170, 0x1170 }, +/* 0x1171 */ { true, 0x1171, 0x1171 }, +/* 0x1172 */ { true, 0x1172, 0x1172 }, +/* 0x1173 */ { true, 0x1173, 0x1173 }, +/* 0x1174 */ { true, 0x1174, 0x1174 }, +/* 0x1175 */ { true, 0x1175, 0x1175 }, +/* 0x1176 */ { true, 0x1176, 0x1176 }, +/* 0x1177 */ { true, 0x1177, 0x1177 }, +/* 0x1178 */ { true, 0x1178, 0x1178 }, +/* 0x1179 */ { true, 0x1179, 0x1179 }, +/* 0x117a */ { true, 0x117a, 0x117a }, +/* 0x117b */ { true, 0x117b, 0x117b }, +/* 0x117c */ { true, 0x117c, 0x117c }, +/* 0x117d */ { true, 0x117d, 0x117d }, +/* 0x117e */ { true, 0x117e, 0x117e }, +/* 0x117f */ { true, 0x117f, 0x117f }, +/* 0x1180 */ { true, 0x1180, 0x1180 }, +/* 0x1181 */ { true, 0x1181, 0x1181 }, +/* 0x1182 */ { true, 0x1182, 0x1182 }, +/* 0x1183 */ { true, 0x1183, 0x1183 }, +/* 0x1184 */ { true, 0x1184, 0x1184 }, +/* 0x1185 */ { true, 0x1185, 0x1185 }, +/* 0x1186 */ { true, 0x1186, 0x1186 }, +/* 0x1187 */ { true, 0x1187, 0x1187 }, +/* 0x1188 */ { true, 0x1188, 0x1188 }, +/* 0x1189 */ { true, 0x1189, 0x1189 }, +/* 0x118a */ { true, 0x118a, 0x118a }, +/* 0x118b */ { true, 0x118b, 0x118b }, +/* 0x118c */ { true, 0x118c, 0x118c }, +/* 0x118d */ { true, 0x118d, 0x118d }, +/* 0x118e */ { true, 0x118e, 0x118e }, +/* 0x118f */ { true, 0x118f, 0x118f }, +/* 0x1190 */ { true, 0x1190, 0x1190 }, +/* 0x1191 */ { true, 0x1191, 0x1191 }, +/* 0x1192 */ { true, 0x1192, 0x1192 }, +/* 0x1193 */ { true, 0x1193, 0x1193 }, +/* 0x1194 */ { true, 0x1194, 0x1194 }, +/* 0x1195 */ { true, 0x1195, 0x1195 }, +/* 0x1196 */ { true, 0x1196, 0x1196 }, +/* 0x1197 */ { true, 0x1197, 0x1197 }, +/* 0x1198 */ { true, 0x1198, 0x1198 }, +/* 0x1199 */ { true, 0x1199, 0x1199 }, +/* 0x119a */ { true, 0x119a, 0x119a }, +/* 0x119b */ { true, 0x119b, 0x119b }, +/* 0x119c */ { true, 0x119c, 0x119c }, +/* 0x119d */ { true, 0x119d, 0x119d }, +/* 0x119e */ { true, 0x119e, 0x119e }, +/* 0x119f */ { true, 0x119f, 0x119f }, +/* 0x11a0 */ { true, 0x11a0, 0x11a0 }, +/* 0x11a1 */ { true, 0x11a1, 0x11a1 }, +/* 0x11a2 */ { true, 0x11a2, 0x11a2 }, +/* 0x11a3 */ { false, 0x11a3, 0x11a3 }, +/* 0x11a4 */ { false, 0x11a4, 0x11a4 }, +/* 0x11a5 */ { false, 0x11a5, 0x11a5 }, +/* 0x11a6 */ { false, 0x11a6, 0x11a6 }, +/* 0x11a7 */ { false, 0x11a7, 0x11a7 }, +/* 0x11a8 */ { true, 0x11a8, 0x11a8 }, +/* 0x11a9 */ { true, 0x11a9, 0x11a9 }, +/* 0x11aa */ { true, 0x11aa, 0x11aa }, +/* 0x11ab */ { true, 0x11ab, 0x11ab }, +/* 0x11ac */ { true, 0x11ac, 0x11ac }, +/* 0x11ad */ { true, 0x11ad, 0x11ad }, +/* 0x11ae */ { true, 0x11ae, 0x11ae }, +/* 0x11af */ { true, 0x11af, 0x11af }, +/* 0x11b0 */ { true, 0x11b0, 0x11b0 }, +/* 0x11b1 */ { true, 0x11b1, 0x11b1 }, +/* 0x11b2 */ { true, 0x11b2, 0x11b2 }, +/* 0x11b3 */ { true, 0x11b3, 0x11b3 }, +/* 0x11b4 */ { true, 0x11b4, 0x11b4 }, +/* 0x11b5 */ { true, 0x11b5, 0x11b5 }, +/* 0x11b6 */ { true, 0x11b6, 0x11b6 }, +/* 0x11b7 */ { true, 0x11b7, 0x11b7 }, +/* 0x11b8 */ { true, 0x11b8, 0x11b8 }, +/* 0x11b9 */ { true, 0x11b9, 0x11b9 }, +/* 0x11ba */ { true, 0x11ba, 0x11ba }, +/* 0x11bb */ { true, 0x11bb, 0x11bb }, +/* 0x11bc */ { true, 0x11bc, 0x11bc }, +/* 0x11bd */ { true, 0x11bd, 0x11bd }, +/* 0x11be */ { true, 0x11be, 0x11be }, +/* 0x11bf */ { true, 0x11bf, 0x11bf }, +/* 0x11c0 */ { true, 0x11c0, 0x11c0 }, +/* 0x11c1 */ { true, 0x11c1, 0x11c1 }, +/* 0x11c2 */ { true, 0x11c2, 0x11c2 }, +/* 0x11c3 */ { true, 0x11c3, 0x11c3 }, +/* 0x11c4 */ { true, 0x11c4, 0x11c4 }, +/* 0x11c5 */ { true, 0x11c5, 0x11c5 }, +/* 0x11c6 */ { true, 0x11c6, 0x11c6 }, +/* 0x11c7 */ { true, 0x11c7, 0x11c7 }, +/* 0x11c8 */ { true, 0x11c8, 0x11c8 }, +/* 0x11c9 */ { true, 0x11c9, 0x11c9 }, +/* 0x11ca */ { true, 0x11ca, 0x11ca }, +/* 0x11cb */ { true, 0x11cb, 0x11cb }, +/* 0x11cc */ { true, 0x11cc, 0x11cc }, +/* 0x11cd */ { true, 0x11cd, 0x11cd }, +/* 0x11ce */ { true, 0x11ce, 0x11ce }, +/* 0x11cf */ { true, 0x11cf, 0x11cf }, +/* 0x11d0 */ { true, 0x11d0, 0x11d0 }, +/* 0x11d1 */ { true, 0x11d1, 0x11d1 }, +/* 0x11d2 */ { true, 0x11d2, 0x11d2 }, +/* 0x11d3 */ { true, 0x11d3, 0x11d3 }, +/* 0x11d4 */ { true, 0x11d4, 0x11d4 }, +/* 0x11d5 */ { true, 0x11d5, 0x11d5 }, +/* 0x11d6 */ { true, 0x11d6, 0x11d6 }, +/* 0x11d7 */ { true, 0x11d7, 0x11d7 }, +/* 0x11d8 */ { true, 0x11d8, 0x11d8 }, +/* 0x11d9 */ { true, 0x11d9, 0x11d9 }, +/* 0x11da */ { true, 0x11da, 0x11da }, +/* 0x11db */ { true, 0x11db, 0x11db }, +/* 0x11dc */ { true, 0x11dc, 0x11dc }, +/* 0x11dd */ { true, 0x11dd, 0x11dd }, +/* 0x11de */ { true, 0x11de, 0x11de }, +/* 0x11df */ { true, 0x11df, 0x11df }, +/* 0x11e0 */ { true, 0x11e0, 0x11e0 }, +/* 0x11e1 */ { true, 0x11e1, 0x11e1 }, +/* 0x11e2 */ { true, 0x11e2, 0x11e2 }, +/* 0x11e3 */ { true, 0x11e3, 0x11e3 }, +/* 0x11e4 */ { true, 0x11e4, 0x11e4 }, +/* 0x11e5 */ { true, 0x11e5, 0x11e5 }, +/* 0x11e6 */ { true, 0x11e6, 0x11e6 }, +/* 0x11e7 */ { true, 0x11e7, 0x11e7 }, +/* 0x11e8 */ { true, 0x11e8, 0x11e8 }, +/* 0x11e9 */ { true, 0x11e9, 0x11e9 }, +/* 0x11ea */ { true, 0x11ea, 0x11ea }, +/* 0x11eb */ { true, 0x11eb, 0x11eb }, +/* 0x11ec */ { true, 0x11ec, 0x11ec }, +/* 0x11ed */ { true, 0x11ed, 0x11ed }, +/* 0x11ee */ { true, 0x11ee, 0x11ee }, +/* 0x11ef */ { true, 0x11ef, 0x11ef }, +/* 0x11f0 */ { true, 0x11f0, 0x11f0 }, +/* 0x11f1 */ { true, 0x11f1, 0x11f1 }, +/* 0x11f2 */ { true, 0x11f2, 0x11f2 }, +/* 0x11f3 */ { true, 0x11f3, 0x11f3 }, +/* 0x11f4 */ { true, 0x11f4, 0x11f4 }, +/* 0x11f5 */ { true, 0x11f5, 0x11f5 }, +/* 0x11f6 */ { true, 0x11f6, 0x11f6 }, +/* 0x11f7 */ { true, 0x11f7, 0x11f7 }, +/* 0x11f8 */ { true, 0x11f8, 0x11f8 }, +/* 0x11f9 */ { true, 0x11f9, 0x11f9 }, +/* 0x11fa */ { false, 0x11fa, 0x11fa }, +/* 0x11fb */ { false, 0x11fb, 0x11fb }, +/* 0x11fc */ { false, 0x11fc, 0x11fc }, +/* 0x11fd */ { false, 0x11fd, 0x11fd }, +/* 0x11fe */ { false, 0x11fe, 0x11fe }, +/* 0x11ff */ { false, 0x11ff, 0x11ff }, +/* 0x1200 */ { true, 0x1200, 0x1200 }, +/* 0x1201 */ { true, 0x1201, 0x1201 }, +/* 0x1202 */ { true, 0x1202, 0x1202 }, +/* 0x1203 */ { true, 0x1203, 0x1203 }, +/* 0x1204 */ { true, 0x1204, 0x1204 }, +/* 0x1205 */ { true, 0x1205, 0x1205 }, +/* 0x1206 */ { true, 0x1206, 0x1206 }, +/* 0x1207 */ { true, 0x1207, 0x1207 }, +/* 0x1208 */ { true, 0x1208, 0x1208 }, +/* 0x1209 */ { true, 0x1209, 0x1209 }, +/* 0x120a */ { true, 0x120a, 0x120a }, +/* 0x120b */ { true, 0x120b, 0x120b }, +/* 0x120c */ { true, 0x120c, 0x120c }, +/* 0x120d */ { true, 0x120d, 0x120d }, +/* 0x120e */ { true, 0x120e, 0x120e }, +/* 0x120f */ { true, 0x120f, 0x120f }, +/* 0x1210 */ { true, 0x1210, 0x1210 }, +/* 0x1211 */ { true, 0x1211, 0x1211 }, +/* 0x1212 */ { true, 0x1212, 0x1212 }, +/* 0x1213 */ { true, 0x1213, 0x1213 }, +/* 0x1214 */ { true, 0x1214, 0x1214 }, +/* 0x1215 */ { true, 0x1215, 0x1215 }, +/* 0x1216 */ { true, 0x1216, 0x1216 }, +/* 0x1217 */ { true, 0x1217, 0x1217 }, +/* 0x1218 */ { true, 0x1218, 0x1218 }, +/* 0x1219 */ { true, 0x1219, 0x1219 }, +/* 0x121a */ { true, 0x121a, 0x121a }, +/* 0x121b */ { true, 0x121b, 0x121b }, +/* 0x121c */ { true, 0x121c, 0x121c }, +/* 0x121d */ { true, 0x121d, 0x121d }, +/* 0x121e */ { true, 0x121e, 0x121e }, +/* 0x121f */ { true, 0x121f, 0x121f }, +/* 0x1220 */ { true, 0x1220, 0x1220 }, +/* 0x1221 */ { true, 0x1221, 0x1221 }, +/* 0x1222 */ { true, 0x1222, 0x1222 }, +/* 0x1223 */ { true, 0x1223, 0x1223 }, +/* 0x1224 */ { true, 0x1224, 0x1224 }, +/* 0x1225 */ { true, 0x1225, 0x1225 }, +/* 0x1226 */ { true, 0x1226, 0x1226 }, +/* 0x1227 */ { true, 0x1227, 0x1227 }, +/* 0x1228 */ { true, 0x1228, 0x1228 }, +/* 0x1229 */ { true, 0x1229, 0x1229 }, +/* 0x122a */ { true, 0x122a, 0x122a }, +/* 0x122b */ { true, 0x122b, 0x122b }, +/* 0x122c */ { true, 0x122c, 0x122c }, +/* 0x122d */ { true, 0x122d, 0x122d }, +/* 0x122e */ { true, 0x122e, 0x122e }, +/* 0x122f */ { true, 0x122f, 0x122f }, +/* 0x1230 */ { true, 0x1230, 0x1230 }, +/* 0x1231 */ { true, 0x1231, 0x1231 }, +/* 0x1232 */ { true, 0x1232, 0x1232 }, +/* 0x1233 */ { true, 0x1233, 0x1233 }, +/* 0x1234 */ { true, 0x1234, 0x1234 }, +/* 0x1235 */ { true, 0x1235, 0x1235 }, +/* 0x1236 */ { true, 0x1236, 0x1236 }, +/* 0x1237 */ { true, 0x1237, 0x1237 }, +/* 0x1238 */ { true, 0x1238, 0x1238 }, +/* 0x1239 */ { true, 0x1239, 0x1239 }, +/* 0x123a */ { true, 0x123a, 0x123a }, +/* 0x123b */ { true, 0x123b, 0x123b }, +/* 0x123c */ { true, 0x123c, 0x123c }, +/* 0x123d */ { true, 0x123d, 0x123d }, +/* 0x123e */ { true, 0x123e, 0x123e }, +/* 0x123f */ { true, 0x123f, 0x123f }, +/* 0x1240 */ { true, 0x1240, 0x1240 }, +/* 0x1241 */ { true, 0x1241, 0x1241 }, +/* 0x1242 */ { true, 0x1242, 0x1242 }, +/* 0x1243 */ { true, 0x1243, 0x1243 }, +/* 0x1244 */ { true, 0x1244, 0x1244 }, +/* 0x1245 */ { true, 0x1245, 0x1245 }, +/* 0x1246 */ { true, 0x1246, 0x1246 }, +/* 0x1247 */ { true, 0x1247, 0x1247 }, +/* 0x1248 */ { true, 0x1248, 0x1248 }, +/* 0x1249 */ { false, 0x1249, 0x1249 }, +/* 0x124a */ { true, 0x124a, 0x124a }, +/* 0x124b */ { true, 0x124b, 0x124b }, +/* 0x124c */ { true, 0x124c, 0x124c }, +/* 0x124d */ { true, 0x124d, 0x124d }, +/* 0x124e */ { false, 0x124e, 0x124e }, +/* 0x124f */ { false, 0x124f, 0x124f }, +/* 0x1250 */ { true, 0x1250, 0x1250 }, +/* 0x1251 */ { true, 0x1251, 0x1251 }, +/* 0x1252 */ { true, 0x1252, 0x1252 }, +/* 0x1253 */ { true, 0x1253, 0x1253 }, +/* 0x1254 */ { true, 0x1254, 0x1254 }, +/* 0x1255 */ { true, 0x1255, 0x1255 }, +/* 0x1256 */ { true, 0x1256, 0x1256 }, +/* 0x1257 */ { false, 0x1257, 0x1257 }, +/* 0x1258 */ { true, 0x1258, 0x1258 }, +/* 0x1259 */ { false, 0x1259, 0x1259 }, +/* 0x125a */ { true, 0x125a, 0x125a }, +/* 0x125b */ { true, 0x125b, 0x125b }, +/* 0x125c */ { true, 0x125c, 0x125c }, +/* 0x125d */ { true, 0x125d, 0x125d }, +/* 0x125e */ { false, 0x125e, 0x125e }, +/* 0x125f */ { false, 0x125f, 0x125f }, +/* 0x1260 */ { true, 0x1260, 0x1260 }, +/* 0x1261 */ { true, 0x1261, 0x1261 }, +/* 0x1262 */ { true, 0x1262, 0x1262 }, +/* 0x1263 */ { true, 0x1263, 0x1263 }, +/* 0x1264 */ { true, 0x1264, 0x1264 }, +/* 0x1265 */ { true, 0x1265, 0x1265 }, +/* 0x1266 */ { true, 0x1266, 0x1266 }, +/* 0x1267 */ { true, 0x1267, 0x1267 }, +/* 0x1268 */ { true, 0x1268, 0x1268 }, +/* 0x1269 */ { true, 0x1269, 0x1269 }, +/* 0x126a */ { true, 0x126a, 0x126a }, +/* 0x126b */ { true, 0x126b, 0x126b }, +/* 0x126c */ { true, 0x126c, 0x126c }, +/* 0x126d */ { true, 0x126d, 0x126d }, +/* 0x126e */ { true, 0x126e, 0x126e }, +/* 0x126f */ { true, 0x126f, 0x126f }, +/* 0x1270 */ { true, 0x1270, 0x1270 }, +/* 0x1271 */ { true, 0x1271, 0x1271 }, +/* 0x1272 */ { true, 0x1272, 0x1272 }, +/* 0x1273 */ { true, 0x1273, 0x1273 }, +/* 0x1274 */ { true, 0x1274, 0x1274 }, +/* 0x1275 */ { true, 0x1275, 0x1275 }, +/* 0x1276 */ { true, 0x1276, 0x1276 }, +/* 0x1277 */ { true, 0x1277, 0x1277 }, +/* 0x1278 */ { true, 0x1278, 0x1278 }, +/* 0x1279 */ { true, 0x1279, 0x1279 }, +/* 0x127a */ { true, 0x127a, 0x127a }, +/* 0x127b */ { true, 0x127b, 0x127b }, +/* 0x127c */ { true, 0x127c, 0x127c }, +/* 0x127d */ { true, 0x127d, 0x127d }, +/* 0x127e */ { true, 0x127e, 0x127e }, +/* 0x127f */ { true, 0x127f, 0x127f }, +/* 0x1280 */ { true, 0x1280, 0x1280 }, +/* 0x1281 */ { true, 0x1281, 0x1281 }, +/* 0x1282 */ { true, 0x1282, 0x1282 }, +/* 0x1283 */ { true, 0x1283, 0x1283 }, +/* 0x1284 */ { true, 0x1284, 0x1284 }, +/* 0x1285 */ { true, 0x1285, 0x1285 }, +/* 0x1286 */ { true, 0x1286, 0x1286 }, +/* 0x1287 */ { true, 0x1287, 0x1287 }, +/* 0x1288 */ { true, 0x1288, 0x1288 }, +/* 0x1289 */ { false, 0x1289, 0x1289 }, +/* 0x128a */ { true, 0x128a, 0x128a }, +/* 0x128b */ { true, 0x128b, 0x128b }, +/* 0x128c */ { true, 0x128c, 0x128c }, +/* 0x128d */ { true, 0x128d, 0x128d }, +/* 0x128e */ { false, 0x128e, 0x128e }, +/* 0x128f */ { false, 0x128f, 0x128f }, +/* 0x1290 */ { true, 0x1290, 0x1290 }, +/* 0x1291 */ { true, 0x1291, 0x1291 }, +/* 0x1292 */ { true, 0x1292, 0x1292 }, +/* 0x1293 */ { true, 0x1293, 0x1293 }, +/* 0x1294 */ { true, 0x1294, 0x1294 }, +/* 0x1295 */ { true, 0x1295, 0x1295 }, +/* 0x1296 */ { true, 0x1296, 0x1296 }, +/* 0x1297 */ { true, 0x1297, 0x1297 }, +/* 0x1298 */ { true, 0x1298, 0x1298 }, +/* 0x1299 */ { true, 0x1299, 0x1299 }, +/* 0x129a */ { true, 0x129a, 0x129a }, +/* 0x129b */ { true, 0x129b, 0x129b }, +/* 0x129c */ { true, 0x129c, 0x129c }, +/* 0x129d */ { true, 0x129d, 0x129d }, +/* 0x129e */ { true, 0x129e, 0x129e }, +/* 0x129f */ { true, 0x129f, 0x129f }, +/* 0x12a0 */ { true, 0x12a0, 0x12a0 }, +/* 0x12a1 */ { true, 0x12a1, 0x12a1 }, +/* 0x12a2 */ { true, 0x12a2, 0x12a2 }, +/* 0x12a3 */ { true, 0x12a3, 0x12a3 }, +/* 0x12a4 */ { true, 0x12a4, 0x12a4 }, +/* 0x12a5 */ { true, 0x12a5, 0x12a5 }, +/* 0x12a6 */ { true, 0x12a6, 0x12a6 }, +/* 0x12a7 */ { true, 0x12a7, 0x12a7 }, +/* 0x12a8 */ { true, 0x12a8, 0x12a8 }, +/* 0x12a9 */ { true, 0x12a9, 0x12a9 }, +/* 0x12aa */ { true, 0x12aa, 0x12aa }, +/* 0x12ab */ { true, 0x12ab, 0x12ab }, +/* 0x12ac */ { true, 0x12ac, 0x12ac }, +/* 0x12ad */ { true, 0x12ad, 0x12ad }, +/* 0x12ae */ { true, 0x12ae, 0x12ae }, +/* 0x12af */ { true, 0x12af, 0x12af }, +/* 0x12b0 */ { true, 0x12b0, 0x12b0 }, +/* 0x12b1 */ { false, 0x12b1, 0x12b1 }, +/* 0x12b2 */ { true, 0x12b2, 0x12b2 }, +/* 0x12b3 */ { true, 0x12b3, 0x12b3 }, +/* 0x12b4 */ { true, 0x12b4, 0x12b4 }, +/* 0x12b5 */ { true, 0x12b5, 0x12b5 }, +/* 0x12b6 */ { false, 0x12b6, 0x12b6 }, +/* 0x12b7 */ { false, 0x12b7, 0x12b7 }, +/* 0x12b8 */ { true, 0x12b8, 0x12b8 }, +/* 0x12b9 */ { true, 0x12b9, 0x12b9 }, +/* 0x12ba */ { true, 0x12ba, 0x12ba }, +/* 0x12bb */ { true, 0x12bb, 0x12bb }, +/* 0x12bc */ { true, 0x12bc, 0x12bc }, +/* 0x12bd */ { true, 0x12bd, 0x12bd }, +/* 0x12be */ { true, 0x12be, 0x12be }, +/* 0x12bf */ { false, 0x12bf, 0x12bf }, +/* 0x12c0 */ { true, 0x12c0, 0x12c0 }, +/* 0x12c1 */ { false, 0x12c1, 0x12c1 }, +/* 0x12c2 */ { true, 0x12c2, 0x12c2 }, +/* 0x12c3 */ { true, 0x12c3, 0x12c3 }, +/* 0x12c4 */ { true, 0x12c4, 0x12c4 }, +/* 0x12c5 */ { true, 0x12c5, 0x12c5 }, +/* 0x12c6 */ { false, 0x12c6, 0x12c6 }, +/* 0x12c7 */ { false, 0x12c7, 0x12c7 }, +/* 0x12c8 */ { true, 0x12c8, 0x12c8 }, +/* 0x12c9 */ { true, 0x12c9, 0x12c9 }, +/* 0x12ca */ { true, 0x12ca, 0x12ca }, +/* 0x12cb */ { true, 0x12cb, 0x12cb }, +/* 0x12cc */ { true, 0x12cc, 0x12cc }, +/* 0x12cd */ { true, 0x12cd, 0x12cd }, +/* 0x12ce */ { true, 0x12ce, 0x12ce }, +/* 0x12cf */ { true, 0x12cf, 0x12cf }, +/* 0x12d0 */ { true, 0x12d0, 0x12d0 }, +/* 0x12d1 */ { true, 0x12d1, 0x12d1 }, +/* 0x12d2 */ { true, 0x12d2, 0x12d2 }, +/* 0x12d3 */ { true, 0x12d3, 0x12d3 }, +/* 0x12d4 */ { true, 0x12d4, 0x12d4 }, +/* 0x12d5 */ { true, 0x12d5, 0x12d5 }, +/* 0x12d6 */ { true, 0x12d6, 0x12d6 }, +/* 0x12d7 */ { false, 0x12d7, 0x12d7 }, +/* 0x12d8 */ { true, 0x12d8, 0x12d8 }, +/* 0x12d9 */ { true, 0x12d9, 0x12d9 }, +/* 0x12da */ { true, 0x12da, 0x12da }, +/* 0x12db */ { true, 0x12db, 0x12db }, +/* 0x12dc */ { true, 0x12dc, 0x12dc }, +/* 0x12dd */ { true, 0x12dd, 0x12dd }, +/* 0x12de */ { true, 0x12de, 0x12de }, +/* 0x12df */ { true, 0x12df, 0x12df }, +/* 0x12e0 */ { true, 0x12e0, 0x12e0 }, +/* 0x12e1 */ { true, 0x12e1, 0x12e1 }, +/* 0x12e2 */ { true, 0x12e2, 0x12e2 }, +/* 0x12e3 */ { true, 0x12e3, 0x12e3 }, +/* 0x12e4 */ { true, 0x12e4, 0x12e4 }, +/* 0x12e5 */ { true, 0x12e5, 0x12e5 }, +/* 0x12e6 */ { true, 0x12e6, 0x12e6 }, +/* 0x12e7 */ { true, 0x12e7, 0x12e7 }, +/* 0x12e8 */ { true, 0x12e8, 0x12e8 }, +/* 0x12e9 */ { true, 0x12e9, 0x12e9 }, +/* 0x12ea */ { true, 0x12ea, 0x12ea }, +/* 0x12eb */ { true, 0x12eb, 0x12eb }, +/* 0x12ec */ { true, 0x12ec, 0x12ec }, +/* 0x12ed */ { true, 0x12ed, 0x12ed }, +/* 0x12ee */ { true, 0x12ee, 0x12ee }, +/* 0x12ef */ { true, 0x12ef, 0x12ef }, +/* 0x12f0 */ { true, 0x12f0, 0x12f0 }, +/* 0x12f1 */ { true, 0x12f1, 0x12f1 }, +/* 0x12f2 */ { true, 0x12f2, 0x12f2 }, +/* 0x12f3 */ { true, 0x12f3, 0x12f3 }, +/* 0x12f4 */ { true, 0x12f4, 0x12f4 }, +/* 0x12f5 */ { true, 0x12f5, 0x12f5 }, +/* 0x12f6 */ { true, 0x12f6, 0x12f6 }, +/* 0x12f7 */ { true, 0x12f7, 0x12f7 }, +/* 0x12f8 */ { true, 0x12f8, 0x12f8 }, +/* 0x12f9 */ { true, 0x12f9, 0x12f9 }, +/* 0x12fa */ { true, 0x12fa, 0x12fa }, +/* 0x12fb */ { true, 0x12fb, 0x12fb }, +/* 0x12fc */ { true, 0x12fc, 0x12fc }, +/* 0x12fd */ { true, 0x12fd, 0x12fd }, +/* 0x12fe */ { true, 0x12fe, 0x12fe }, +/* 0x12ff */ { true, 0x12ff, 0x12ff }, +/* 0x1300 */ { true, 0x1300, 0x1300 }, +/* 0x1301 */ { true, 0x1301, 0x1301 }, +/* 0x1302 */ { true, 0x1302, 0x1302 }, +/* 0x1303 */ { true, 0x1303, 0x1303 }, +/* 0x1304 */ { true, 0x1304, 0x1304 }, +/* 0x1305 */ { true, 0x1305, 0x1305 }, +/* 0x1306 */ { true, 0x1306, 0x1306 }, +/* 0x1307 */ { true, 0x1307, 0x1307 }, +/* 0x1308 */ { true, 0x1308, 0x1308 }, +/* 0x1309 */ { true, 0x1309, 0x1309 }, +/* 0x130a */ { true, 0x130a, 0x130a }, +/* 0x130b */ { true, 0x130b, 0x130b }, +/* 0x130c */ { true, 0x130c, 0x130c }, +/* 0x130d */ { true, 0x130d, 0x130d }, +/* 0x130e */ { true, 0x130e, 0x130e }, +/* 0x130f */ { true, 0x130f, 0x130f }, +/* 0x1310 */ { true, 0x1310, 0x1310 }, +/* 0x1311 */ { false, 0x1311, 0x1311 }, +/* 0x1312 */ { true, 0x1312, 0x1312 }, +/* 0x1313 */ { true, 0x1313, 0x1313 }, +/* 0x1314 */ { true, 0x1314, 0x1314 }, +/* 0x1315 */ { true, 0x1315, 0x1315 }, +/* 0x1316 */ { false, 0x1316, 0x1316 }, +/* 0x1317 */ { false, 0x1317, 0x1317 }, +/* 0x1318 */ { true, 0x1318, 0x1318 }, +/* 0x1319 */ { true, 0x1319, 0x1319 }, +/* 0x131a */ { true, 0x131a, 0x131a }, +/* 0x131b */ { true, 0x131b, 0x131b }, +/* 0x131c */ { true, 0x131c, 0x131c }, +/* 0x131d */ { true, 0x131d, 0x131d }, +/* 0x131e */ { true, 0x131e, 0x131e }, +/* 0x131f */ { true, 0x131f, 0x131f }, +/* 0x1320 */ { true, 0x1320, 0x1320 }, +/* 0x1321 */ { true, 0x1321, 0x1321 }, +/* 0x1322 */ { true, 0x1322, 0x1322 }, +/* 0x1323 */ { true, 0x1323, 0x1323 }, +/* 0x1324 */ { true, 0x1324, 0x1324 }, +/* 0x1325 */ { true, 0x1325, 0x1325 }, +/* 0x1326 */ { true, 0x1326, 0x1326 }, +/* 0x1327 */ { true, 0x1327, 0x1327 }, +/* 0x1328 */ { true, 0x1328, 0x1328 }, +/* 0x1329 */ { true, 0x1329, 0x1329 }, +/* 0x132a */ { true, 0x132a, 0x132a }, +/* 0x132b */ { true, 0x132b, 0x132b }, +/* 0x132c */ { true, 0x132c, 0x132c }, +/* 0x132d */ { true, 0x132d, 0x132d }, +/* 0x132e */ { true, 0x132e, 0x132e }, +/* 0x132f */ { true, 0x132f, 0x132f }, +/* 0x1330 */ { true, 0x1330, 0x1330 }, +/* 0x1331 */ { true, 0x1331, 0x1331 }, +/* 0x1332 */ { true, 0x1332, 0x1332 }, +/* 0x1333 */ { true, 0x1333, 0x1333 }, +/* 0x1334 */ { true, 0x1334, 0x1334 }, +/* 0x1335 */ { true, 0x1335, 0x1335 }, +/* 0x1336 */ { true, 0x1336, 0x1336 }, +/* 0x1337 */ { true, 0x1337, 0x1337 }, +/* 0x1338 */ { true, 0x1338, 0x1338 }, +/* 0x1339 */ { true, 0x1339, 0x1339 }, +/* 0x133a */ { true, 0x133a, 0x133a }, +/* 0x133b */ { true, 0x133b, 0x133b }, +/* 0x133c */ { true, 0x133c, 0x133c }, +/* 0x133d */ { true, 0x133d, 0x133d }, +/* 0x133e */ { true, 0x133e, 0x133e }, +/* 0x133f */ { true, 0x133f, 0x133f }, +/* 0x1340 */ { true, 0x1340, 0x1340 }, +/* 0x1341 */ { true, 0x1341, 0x1341 }, +/* 0x1342 */ { true, 0x1342, 0x1342 }, +/* 0x1343 */ { true, 0x1343, 0x1343 }, +/* 0x1344 */ { true, 0x1344, 0x1344 }, +/* 0x1345 */ { true, 0x1345, 0x1345 }, +/* 0x1346 */ { true, 0x1346, 0x1346 }, +/* 0x1347 */ { true, 0x1347, 0x1347 }, +/* 0x1348 */ { true, 0x1348, 0x1348 }, +/* 0x1349 */ { true, 0x1349, 0x1349 }, +/* 0x134a */ { true, 0x134a, 0x134a }, +/* 0x134b */ { true, 0x134b, 0x134b }, +/* 0x134c */ { true, 0x134c, 0x134c }, +/* 0x134d */ { true, 0x134d, 0x134d }, +/* 0x134e */ { true, 0x134e, 0x134e }, +/* 0x134f */ { true, 0x134f, 0x134f }, +/* 0x1350 */ { true, 0x1350, 0x1350 }, +/* 0x1351 */ { true, 0x1351, 0x1351 }, +/* 0x1352 */ { true, 0x1352, 0x1352 }, +/* 0x1353 */ { true, 0x1353, 0x1353 }, +/* 0x1354 */ { true, 0x1354, 0x1354 }, +/* 0x1355 */ { true, 0x1355, 0x1355 }, +/* 0x1356 */ { true, 0x1356, 0x1356 }, +/* 0x1357 */ { true, 0x1357, 0x1357 }, +/* 0x1358 */ { true, 0x1358, 0x1358 }, +/* 0x1359 */ { true, 0x1359, 0x1359 }, +/* 0x135a */ { true, 0x135a, 0x135a }, +/* 0x135b */ { false, 0x135b, 0x135b }, +/* 0x135c */ { false, 0x135c, 0x135c }, +/* 0x135d */ { false, 0x135d, 0x135d }, +/* 0x135e */ { false, 0x135e, 0x135e }, +/* 0x135f */ { true, 0x135f, 0x135f }, +/* 0x1360 */ { false, 0x1360, 0x1360 }, +/* 0x1361 */ { false, 0x1361, 0x1361 }, +/* 0x1362 */ { false, 0x1362, 0x1362 }, +/* 0x1363 */ { false, 0x1363, 0x1363 }, +/* 0x1364 */ { false, 0x1364, 0x1364 }, +/* 0x1365 */ { false, 0x1365, 0x1365 }, +/* 0x1366 */ { false, 0x1366, 0x1366 }, +/* 0x1367 */ { false, 0x1367, 0x1367 }, +/* 0x1368 */ { false, 0x1368, 0x1368 }, +/* 0x1369 */ { false, 0x1369, 0x1369 }, +/* 0x136a */ { false, 0x136a, 0x136a }, +/* 0x136b */ { false, 0x136b, 0x136b }, +/* 0x136c */ { false, 0x136c, 0x136c }, +/* 0x136d */ { false, 0x136d, 0x136d }, +/* 0x136e */ { false, 0x136e, 0x136e }, +/* 0x136f */ { false, 0x136f, 0x136f }, +/* 0x1370 */ { false, 0x1370, 0x1370 }, +/* 0x1371 */ { false, 0x1371, 0x1371 }, +/* 0x1372 */ { false, 0x1372, 0x1372 }, +/* 0x1373 */ { false, 0x1373, 0x1373 }, +/* 0x1374 */ { false, 0x1374, 0x1374 }, +/* 0x1375 */ { false, 0x1375, 0x1375 }, +/* 0x1376 */ { false, 0x1376, 0x1376 }, +/* 0x1377 */ { false, 0x1377, 0x1377 }, +/* 0x1378 */ { false, 0x1378, 0x1378 }, +/* 0x1379 */ { false, 0x1379, 0x1379 }, +/* 0x137a */ { false, 0x137a, 0x137a }, +/* 0x137b */ { false, 0x137b, 0x137b }, +/* 0x137c */ { false, 0x137c, 0x137c }, +/* 0x137d */ { false, 0x137d, 0x137d }, +/* 0x137e */ { false, 0x137e, 0x137e }, +/* 0x137f */ { false, 0x137f, 0x137f }, +/* 0x1380 */ { true, 0x1380, 0x1380 }, +/* 0x1381 */ { true, 0x1381, 0x1381 }, +/* 0x1382 */ { true, 0x1382, 0x1382 }, +/* 0x1383 */ { true, 0x1383, 0x1383 }, +/* 0x1384 */ { true, 0x1384, 0x1384 }, +/* 0x1385 */ { true, 0x1385, 0x1385 }, +/* 0x1386 */ { true, 0x1386, 0x1386 }, +/* 0x1387 */ { true, 0x1387, 0x1387 }, +/* 0x1388 */ { true, 0x1388, 0x1388 }, +/* 0x1389 */ { true, 0x1389, 0x1389 }, +/* 0x138a */ { true, 0x138a, 0x138a }, +/* 0x138b */ { true, 0x138b, 0x138b }, +/* 0x138c */ { true, 0x138c, 0x138c }, +/* 0x138d */ { true, 0x138d, 0x138d }, +/* 0x138e */ { true, 0x138e, 0x138e }, +/* 0x138f */ { true, 0x138f, 0x138f }, +/* 0x1390 */ { false, 0x1390, 0x1390 }, +/* 0x1391 */ { false, 0x1391, 0x1391 }, +/* 0x1392 */ { false, 0x1392, 0x1392 }, +/* 0x1393 */ { false, 0x1393, 0x1393 }, +/* 0x1394 */ { false, 0x1394, 0x1394 }, +/* 0x1395 */ { false, 0x1395, 0x1395 }, +/* 0x1396 */ { false, 0x1396, 0x1396 }, +/* 0x1397 */ { false, 0x1397, 0x1397 }, +/* 0x1398 */ { false, 0x1398, 0x1398 }, +/* 0x1399 */ { false, 0x1399, 0x1399 }, +/* 0x139a */ { false, 0x139a, 0x139a }, +/* 0x139b */ { false, 0x139b, 0x139b }, +/* 0x139c */ { false, 0x139c, 0x139c }, +/* 0x139d */ { false, 0x139d, 0x139d }, +/* 0x139e */ { false, 0x139e, 0x139e }, +/* 0x139f */ { false, 0x139f, 0x139f }, +/* 0x13a0 */ { true, 0x13a0, 0x13a0 }, +/* 0x13a1 */ { true, 0x13a1, 0x13a1 }, +/* 0x13a2 */ { true, 0x13a2, 0x13a2 }, +/* 0x13a3 */ { true, 0x13a3, 0x13a3 }, +/* 0x13a4 */ { true, 0x13a4, 0x13a4 }, +/* 0x13a5 */ { true, 0x13a5, 0x13a5 }, +/* 0x13a6 */ { true, 0x13a6, 0x13a6 }, +/* 0x13a7 */ { true, 0x13a7, 0x13a7 }, +/* 0x13a8 */ { true, 0x13a8, 0x13a8 }, +/* 0x13a9 */ { true, 0x13a9, 0x13a9 }, +/* 0x13aa */ { true, 0x13aa, 0x13aa }, +/* 0x13ab */ { true, 0x13ab, 0x13ab }, +/* 0x13ac */ { true, 0x13ac, 0x13ac }, +/* 0x13ad */ { true, 0x13ad, 0x13ad }, +/* 0x13ae */ { true, 0x13ae, 0x13ae }, +/* 0x13af */ { true, 0x13af, 0x13af }, +/* 0x13b0 */ { true, 0x13b0, 0x13b0 }, +/* 0x13b1 */ { true, 0x13b1, 0x13b1 }, +/* 0x13b2 */ { true, 0x13b2, 0x13b2 }, +/* 0x13b3 */ { true, 0x13b3, 0x13b3 }, +/* 0x13b4 */ { true, 0x13b4, 0x13b4 }, +/* 0x13b5 */ { true, 0x13b5, 0x13b5 }, +/* 0x13b6 */ { true, 0x13b6, 0x13b6 }, +/* 0x13b7 */ { true, 0x13b7, 0x13b7 }, +/* 0x13b8 */ { true, 0x13b8, 0x13b8 }, +/* 0x13b9 */ { true, 0x13b9, 0x13b9 }, +/* 0x13ba */ { true, 0x13ba, 0x13ba }, +/* 0x13bb */ { true, 0x13bb, 0x13bb }, +/* 0x13bc */ { true, 0x13bc, 0x13bc }, +/* 0x13bd */ { true, 0x13bd, 0x13bd }, +/* 0x13be */ { true, 0x13be, 0x13be }, +/* 0x13bf */ { true, 0x13bf, 0x13bf }, +/* 0x13c0 */ { true, 0x13c0, 0x13c0 }, +/* 0x13c1 */ { true, 0x13c1, 0x13c1 }, +/* 0x13c2 */ { true, 0x13c2, 0x13c2 }, +/* 0x13c3 */ { true, 0x13c3, 0x13c3 }, +/* 0x13c4 */ { true, 0x13c4, 0x13c4 }, +/* 0x13c5 */ { true, 0x13c5, 0x13c5 }, +/* 0x13c6 */ { true, 0x13c6, 0x13c6 }, +/* 0x13c7 */ { true, 0x13c7, 0x13c7 }, +/* 0x13c8 */ { true, 0x13c8, 0x13c8 }, +/* 0x13c9 */ { true, 0x13c9, 0x13c9 }, +/* 0x13ca */ { true, 0x13ca, 0x13ca }, +/* 0x13cb */ { true, 0x13cb, 0x13cb }, +/* 0x13cc */ { true, 0x13cc, 0x13cc }, +/* 0x13cd */ { true, 0x13cd, 0x13cd }, +/* 0x13ce */ { true, 0x13ce, 0x13ce }, +/* 0x13cf */ { true, 0x13cf, 0x13cf }, +/* 0x13d0 */ { true, 0x13d0, 0x13d0 }, +/* 0x13d1 */ { true, 0x13d1, 0x13d1 }, +/* 0x13d2 */ { true, 0x13d2, 0x13d2 }, +/* 0x13d3 */ { true, 0x13d3, 0x13d3 }, +/* 0x13d4 */ { true, 0x13d4, 0x13d4 }, +/* 0x13d5 */ { true, 0x13d5, 0x13d5 }, +/* 0x13d6 */ { true, 0x13d6, 0x13d6 }, +/* 0x13d7 */ { true, 0x13d7, 0x13d7 }, +/* 0x13d8 */ { true, 0x13d8, 0x13d8 }, +/* 0x13d9 */ { true, 0x13d9, 0x13d9 }, +/* 0x13da */ { true, 0x13da, 0x13da }, +/* 0x13db */ { true, 0x13db, 0x13db }, +/* 0x13dc */ { true, 0x13dc, 0x13dc }, +/* 0x13dd */ { true, 0x13dd, 0x13dd }, +/* 0x13de */ { true, 0x13de, 0x13de }, +/* 0x13df */ { true, 0x13df, 0x13df }, +/* 0x13e0 */ { true, 0x13e0, 0x13e0 }, +/* 0x13e1 */ { true, 0x13e1, 0x13e1 }, +/* 0x13e2 */ { true, 0x13e2, 0x13e2 }, +/* 0x13e3 */ { true, 0x13e3, 0x13e3 }, +/* 0x13e4 */ { true, 0x13e4, 0x13e4 }, +/* 0x13e5 */ { true, 0x13e5, 0x13e5 }, +/* 0x13e6 */ { true, 0x13e6, 0x13e6 }, +/* 0x13e7 */ { true, 0x13e7, 0x13e7 }, +/* 0x13e8 */ { true, 0x13e8, 0x13e8 }, +/* 0x13e9 */ { true, 0x13e9, 0x13e9 }, +/* 0x13ea */ { true, 0x13ea, 0x13ea }, +/* 0x13eb */ { true, 0x13eb, 0x13eb }, +/* 0x13ec */ { true, 0x13ec, 0x13ec }, +/* 0x13ed */ { true, 0x13ed, 0x13ed }, +/* 0x13ee */ { true, 0x13ee, 0x13ee }, +/* 0x13ef */ { true, 0x13ef, 0x13ef }, +/* 0x13f0 */ { true, 0x13f0, 0x13f0 }, +/* 0x13f1 */ { true, 0x13f1, 0x13f1 }, +/* 0x13f2 */ { true, 0x13f2, 0x13f2 }, +/* 0x13f3 */ { true, 0x13f3, 0x13f3 }, +/* 0x13f4 */ { true, 0x13f4, 0x13f4 }, +/* 0x13f5 */ { false, 0x13f5, 0x13f5 }, +/* 0x13f6 */ { false, 0x13f6, 0x13f6 }, +/* 0x13f7 */ { false, 0x13f7, 0x13f7 }, +/* 0x13f8 */ { false, 0x13f8, 0x13f8 }, +/* 0x13f9 */ { false, 0x13f9, 0x13f9 }, +/* 0x13fa */ { false, 0x13fa, 0x13fa }, +/* 0x13fb */ { false, 0x13fb, 0x13fb }, +/* 0x13fc */ { false, 0x13fc, 0x13fc }, +/* 0x13fd */ { false, 0x13fd, 0x13fd }, +/* 0x13fe */ { false, 0x13fe, 0x13fe }, +/* 0x13ff */ { false, 0x13ff, 0x13ff }, +/* 0x1400 */ { false, 0x1400, 0x1400 }, +/* 0x1401 */ { true, 0x1401, 0x1401 }, +/* 0x1402 */ { true, 0x1402, 0x1402 }, +/* 0x1403 */ { true, 0x1403, 0x1403 }, +/* 0x1404 */ { true, 0x1404, 0x1404 }, +/* 0x1405 */ { true, 0x1405, 0x1405 }, +/* 0x1406 */ { true, 0x1406, 0x1406 }, +/* 0x1407 */ { true, 0x1407, 0x1407 }, +/* 0x1408 */ { true, 0x1408, 0x1408 }, +/* 0x1409 */ { true, 0x1409, 0x1409 }, +/* 0x140a */ { true, 0x140a, 0x140a }, +/* 0x140b */ { true, 0x140b, 0x140b }, +/* 0x140c */ { true, 0x140c, 0x140c }, +/* 0x140d */ { true, 0x140d, 0x140d }, +/* 0x140e */ { true, 0x140e, 0x140e }, +/* 0x140f */ { true, 0x140f, 0x140f }, +/* 0x1410 */ { true, 0x1410, 0x1410 }, +/* 0x1411 */ { true, 0x1411, 0x1411 }, +/* 0x1412 */ { true, 0x1412, 0x1412 }, +/* 0x1413 */ { true, 0x1413, 0x1413 }, +/* 0x1414 */ { true, 0x1414, 0x1414 }, +/* 0x1415 */ { true, 0x1415, 0x1415 }, +/* 0x1416 */ { true, 0x1416, 0x1416 }, +/* 0x1417 */ { true, 0x1417, 0x1417 }, +/* 0x1418 */ { true, 0x1418, 0x1418 }, +/* 0x1419 */ { true, 0x1419, 0x1419 }, +/* 0x141a */ { true, 0x141a, 0x141a }, +/* 0x141b */ { true, 0x141b, 0x141b }, +/* 0x141c */ { true, 0x141c, 0x141c }, +/* 0x141d */ { true, 0x141d, 0x141d }, +/* 0x141e */ { true, 0x141e, 0x141e }, +/* 0x141f */ { true, 0x141f, 0x141f }, +/* 0x1420 */ { true, 0x1420, 0x1420 }, +/* 0x1421 */ { true, 0x1421, 0x1421 }, +/* 0x1422 */ { true, 0x1422, 0x1422 }, +/* 0x1423 */ { true, 0x1423, 0x1423 }, +/* 0x1424 */ { true, 0x1424, 0x1424 }, +/* 0x1425 */ { true, 0x1425, 0x1425 }, +/* 0x1426 */ { true, 0x1426, 0x1426 }, +/* 0x1427 */ { true, 0x1427, 0x1427 }, +/* 0x1428 */ { true, 0x1428, 0x1428 }, +/* 0x1429 */ { true, 0x1429, 0x1429 }, +/* 0x142a */ { true, 0x142a, 0x142a }, +/* 0x142b */ { true, 0x142b, 0x142b }, +/* 0x142c */ { true, 0x142c, 0x142c }, +/* 0x142d */ { true, 0x142d, 0x142d }, +/* 0x142e */ { true, 0x142e, 0x142e }, +/* 0x142f */ { true, 0x142f, 0x142f }, +/* 0x1430 */ { true, 0x1430, 0x1430 }, +/* 0x1431 */ { true, 0x1431, 0x1431 }, +/* 0x1432 */ { true, 0x1432, 0x1432 }, +/* 0x1433 */ { true, 0x1433, 0x1433 }, +/* 0x1434 */ { true, 0x1434, 0x1434 }, +/* 0x1435 */ { true, 0x1435, 0x1435 }, +/* 0x1436 */ { true, 0x1436, 0x1436 }, +/* 0x1437 */ { true, 0x1437, 0x1437 }, +/* 0x1438 */ { true, 0x1438, 0x1438 }, +/* 0x1439 */ { true, 0x1439, 0x1439 }, +/* 0x143a */ { true, 0x143a, 0x143a }, +/* 0x143b */ { true, 0x143b, 0x143b }, +/* 0x143c */ { true, 0x143c, 0x143c }, +/* 0x143d */ { true, 0x143d, 0x143d }, +/* 0x143e */ { true, 0x143e, 0x143e }, +/* 0x143f */ { true, 0x143f, 0x143f }, +/* 0x1440 */ { true, 0x1440, 0x1440 }, +/* 0x1441 */ { true, 0x1441, 0x1441 }, +/* 0x1442 */ { true, 0x1442, 0x1442 }, +/* 0x1443 */ { true, 0x1443, 0x1443 }, +/* 0x1444 */ { true, 0x1444, 0x1444 }, +/* 0x1445 */ { true, 0x1445, 0x1445 }, +/* 0x1446 */ { true, 0x1446, 0x1446 }, +/* 0x1447 */ { true, 0x1447, 0x1447 }, +/* 0x1448 */ { true, 0x1448, 0x1448 }, +/* 0x1449 */ { true, 0x1449, 0x1449 }, +/* 0x144a */ { true, 0x144a, 0x144a }, +/* 0x144b */ { true, 0x144b, 0x144b }, +/* 0x144c */ { true, 0x144c, 0x144c }, +/* 0x144d */ { true, 0x144d, 0x144d }, +/* 0x144e */ { true, 0x144e, 0x144e }, +/* 0x144f */ { true, 0x144f, 0x144f }, +/* 0x1450 */ { true, 0x1450, 0x1450 }, +/* 0x1451 */ { true, 0x1451, 0x1451 }, +/* 0x1452 */ { true, 0x1452, 0x1452 }, +/* 0x1453 */ { true, 0x1453, 0x1453 }, +/* 0x1454 */ { true, 0x1454, 0x1454 }, +/* 0x1455 */ { true, 0x1455, 0x1455 }, +/* 0x1456 */ { true, 0x1456, 0x1456 }, +/* 0x1457 */ { true, 0x1457, 0x1457 }, +/* 0x1458 */ { true, 0x1458, 0x1458 }, +/* 0x1459 */ { true, 0x1459, 0x1459 }, +/* 0x145a */ { true, 0x145a, 0x145a }, +/* 0x145b */ { true, 0x145b, 0x145b }, +/* 0x145c */ { true, 0x145c, 0x145c }, +/* 0x145d */ { true, 0x145d, 0x145d }, +/* 0x145e */ { true, 0x145e, 0x145e }, +/* 0x145f */ { true, 0x145f, 0x145f }, +/* 0x1460 */ { true, 0x1460, 0x1460 }, +/* 0x1461 */ { true, 0x1461, 0x1461 }, +/* 0x1462 */ { true, 0x1462, 0x1462 }, +/* 0x1463 */ { true, 0x1463, 0x1463 }, +/* 0x1464 */ { true, 0x1464, 0x1464 }, +/* 0x1465 */ { true, 0x1465, 0x1465 }, +/* 0x1466 */ { true, 0x1466, 0x1466 }, +/* 0x1467 */ { true, 0x1467, 0x1467 }, +/* 0x1468 */ { true, 0x1468, 0x1468 }, +/* 0x1469 */ { true, 0x1469, 0x1469 }, +/* 0x146a */ { true, 0x146a, 0x146a }, +/* 0x146b */ { true, 0x146b, 0x146b }, +/* 0x146c */ { true, 0x146c, 0x146c }, +/* 0x146d */ { true, 0x146d, 0x146d }, +/* 0x146e */ { true, 0x146e, 0x146e }, +/* 0x146f */ { true, 0x146f, 0x146f }, +/* 0x1470 */ { true, 0x1470, 0x1470 }, +/* 0x1471 */ { true, 0x1471, 0x1471 }, +/* 0x1472 */ { true, 0x1472, 0x1472 }, +/* 0x1473 */ { true, 0x1473, 0x1473 }, +/* 0x1474 */ { true, 0x1474, 0x1474 }, +/* 0x1475 */ { true, 0x1475, 0x1475 }, +/* 0x1476 */ { true, 0x1476, 0x1476 }, +/* 0x1477 */ { true, 0x1477, 0x1477 }, +/* 0x1478 */ { true, 0x1478, 0x1478 }, +/* 0x1479 */ { true, 0x1479, 0x1479 }, +/* 0x147a */ { true, 0x147a, 0x147a }, +/* 0x147b */ { true, 0x147b, 0x147b }, +/* 0x147c */ { true, 0x147c, 0x147c }, +/* 0x147d */ { true, 0x147d, 0x147d }, +/* 0x147e */ { true, 0x147e, 0x147e }, +/* 0x147f */ { true, 0x147f, 0x147f }, +/* 0x1480 */ { true, 0x1480, 0x1480 }, +/* 0x1481 */ { true, 0x1481, 0x1481 }, +/* 0x1482 */ { true, 0x1482, 0x1482 }, +/* 0x1483 */ { true, 0x1483, 0x1483 }, +/* 0x1484 */ { true, 0x1484, 0x1484 }, +/* 0x1485 */ { true, 0x1485, 0x1485 }, +/* 0x1486 */ { true, 0x1486, 0x1486 }, +/* 0x1487 */ { true, 0x1487, 0x1487 }, +/* 0x1488 */ { true, 0x1488, 0x1488 }, +/* 0x1489 */ { true, 0x1489, 0x1489 }, +/* 0x148a */ { true, 0x148a, 0x148a }, +/* 0x148b */ { true, 0x148b, 0x148b }, +/* 0x148c */ { true, 0x148c, 0x148c }, +/* 0x148d */ { true, 0x148d, 0x148d }, +/* 0x148e */ { true, 0x148e, 0x148e }, +/* 0x148f */ { true, 0x148f, 0x148f }, +/* 0x1490 */ { true, 0x1490, 0x1490 }, +/* 0x1491 */ { true, 0x1491, 0x1491 }, +/* 0x1492 */ { true, 0x1492, 0x1492 }, +/* 0x1493 */ { true, 0x1493, 0x1493 }, +/* 0x1494 */ { true, 0x1494, 0x1494 }, +/* 0x1495 */ { true, 0x1495, 0x1495 }, +/* 0x1496 */ { true, 0x1496, 0x1496 }, +/* 0x1497 */ { true, 0x1497, 0x1497 }, +/* 0x1498 */ { true, 0x1498, 0x1498 }, +/* 0x1499 */ { true, 0x1499, 0x1499 }, +/* 0x149a */ { true, 0x149a, 0x149a }, +/* 0x149b */ { true, 0x149b, 0x149b }, +/* 0x149c */ { true, 0x149c, 0x149c }, +/* 0x149d */ { true, 0x149d, 0x149d }, +/* 0x149e */ { true, 0x149e, 0x149e }, +/* 0x149f */ { true, 0x149f, 0x149f }, +/* 0x14a0 */ { true, 0x14a0, 0x14a0 }, +/* 0x14a1 */ { true, 0x14a1, 0x14a1 }, +/* 0x14a2 */ { true, 0x14a2, 0x14a2 }, +/* 0x14a3 */ { true, 0x14a3, 0x14a3 }, +/* 0x14a4 */ { true, 0x14a4, 0x14a4 }, +/* 0x14a5 */ { true, 0x14a5, 0x14a5 }, +/* 0x14a6 */ { true, 0x14a6, 0x14a6 }, +/* 0x14a7 */ { true, 0x14a7, 0x14a7 }, +/* 0x14a8 */ { true, 0x14a8, 0x14a8 }, +/* 0x14a9 */ { true, 0x14a9, 0x14a9 }, +/* 0x14aa */ { true, 0x14aa, 0x14aa }, +/* 0x14ab */ { true, 0x14ab, 0x14ab }, +/* 0x14ac */ { true, 0x14ac, 0x14ac }, +/* 0x14ad */ { true, 0x14ad, 0x14ad }, +/* 0x14ae */ { true, 0x14ae, 0x14ae }, +/* 0x14af */ { true, 0x14af, 0x14af }, +/* 0x14b0 */ { true, 0x14b0, 0x14b0 }, +/* 0x14b1 */ { true, 0x14b1, 0x14b1 }, +/* 0x14b2 */ { true, 0x14b2, 0x14b2 }, +/* 0x14b3 */ { true, 0x14b3, 0x14b3 }, +/* 0x14b4 */ { true, 0x14b4, 0x14b4 }, +/* 0x14b5 */ { true, 0x14b5, 0x14b5 }, +/* 0x14b6 */ { true, 0x14b6, 0x14b6 }, +/* 0x14b7 */ { true, 0x14b7, 0x14b7 }, +/* 0x14b8 */ { true, 0x14b8, 0x14b8 }, +/* 0x14b9 */ { true, 0x14b9, 0x14b9 }, +/* 0x14ba */ { true, 0x14ba, 0x14ba }, +/* 0x14bb */ { true, 0x14bb, 0x14bb }, +/* 0x14bc */ { true, 0x14bc, 0x14bc }, +/* 0x14bd */ { true, 0x14bd, 0x14bd }, +/* 0x14be */ { true, 0x14be, 0x14be }, +/* 0x14bf */ { true, 0x14bf, 0x14bf }, +/* 0x14c0 */ { true, 0x14c0, 0x14c0 }, +/* 0x14c1 */ { true, 0x14c1, 0x14c1 }, +/* 0x14c2 */ { true, 0x14c2, 0x14c2 }, +/* 0x14c3 */ { true, 0x14c3, 0x14c3 }, +/* 0x14c4 */ { true, 0x14c4, 0x14c4 }, +/* 0x14c5 */ { true, 0x14c5, 0x14c5 }, +/* 0x14c6 */ { true, 0x14c6, 0x14c6 }, +/* 0x14c7 */ { true, 0x14c7, 0x14c7 }, +/* 0x14c8 */ { true, 0x14c8, 0x14c8 }, +/* 0x14c9 */ { true, 0x14c9, 0x14c9 }, +/* 0x14ca */ { true, 0x14ca, 0x14ca }, +/* 0x14cb */ { true, 0x14cb, 0x14cb }, +/* 0x14cc */ { true, 0x14cc, 0x14cc }, +/* 0x14cd */ { true, 0x14cd, 0x14cd }, +/* 0x14ce */ { true, 0x14ce, 0x14ce }, +/* 0x14cf */ { true, 0x14cf, 0x14cf }, +/* 0x14d0 */ { true, 0x14d0, 0x14d0 }, +/* 0x14d1 */ { true, 0x14d1, 0x14d1 }, +/* 0x14d2 */ { true, 0x14d2, 0x14d2 }, +/* 0x14d3 */ { true, 0x14d3, 0x14d3 }, +/* 0x14d4 */ { true, 0x14d4, 0x14d4 }, +/* 0x14d5 */ { true, 0x14d5, 0x14d5 }, +/* 0x14d6 */ { true, 0x14d6, 0x14d6 }, +/* 0x14d7 */ { true, 0x14d7, 0x14d7 }, +/* 0x14d8 */ { true, 0x14d8, 0x14d8 }, +/* 0x14d9 */ { true, 0x14d9, 0x14d9 }, +/* 0x14da */ { true, 0x14da, 0x14da }, +/* 0x14db */ { true, 0x14db, 0x14db }, +/* 0x14dc */ { true, 0x14dc, 0x14dc }, +/* 0x14dd */ { true, 0x14dd, 0x14dd }, +/* 0x14de */ { true, 0x14de, 0x14de }, +/* 0x14df */ { true, 0x14df, 0x14df }, +/* 0x14e0 */ { true, 0x14e0, 0x14e0 }, +/* 0x14e1 */ { true, 0x14e1, 0x14e1 }, +/* 0x14e2 */ { true, 0x14e2, 0x14e2 }, +/* 0x14e3 */ { true, 0x14e3, 0x14e3 }, +/* 0x14e4 */ { true, 0x14e4, 0x14e4 }, +/* 0x14e5 */ { true, 0x14e5, 0x14e5 }, +/* 0x14e6 */ { true, 0x14e6, 0x14e6 }, +/* 0x14e7 */ { true, 0x14e7, 0x14e7 }, +/* 0x14e8 */ { true, 0x14e8, 0x14e8 }, +/* 0x14e9 */ { true, 0x14e9, 0x14e9 }, +/* 0x14ea */ { true, 0x14ea, 0x14ea }, +/* 0x14eb */ { true, 0x14eb, 0x14eb }, +/* 0x14ec */ { true, 0x14ec, 0x14ec }, +/* 0x14ed */ { true, 0x14ed, 0x14ed }, +/* 0x14ee */ { true, 0x14ee, 0x14ee }, +/* 0x14ef */ { true, 0x14ef, 0x14ef }, +/* 0x14f0 */ { true, 0x14f0, 0x14f0 }, +/* 0x14f1 */ { true, 0x14f1, 0x14f1 }, +/* 0x14f2 */ { true, 0x14f2, 0x14f2 }, +/* 0x14f3 */ { true, 0x14f3, 0x14f3 }, +/* 0x14f4 */ { true, 0x14f4, 0x14f4 }, +/* 0x14f5 */ { true, 0x14f5, 0x14f5 }, +/* 0x14f6 */ { true, 0x14f6, 0x14f6 }, +/* 0x14f7 */ { true, 0x14f7, 0x14f7 }, +/* 0x14f8 */ { true, 0x14f8, 0x14f8 }, +/* 0x14f9 */ { true, 0x14f9, 0x14f9 }, +/* 0x14fa */ { true, 0x14fa, 0x14fa }, +/* 0x14fb */ { true, 0x14fb, 0x14fb }, +/* 0x14fc */ { true, 0x14fc, 0x14fc }, +/* 0x14fd */ { true, 0x14fd, 0x14fd }, +/* 0x14fe */ { true, 0x14fe, 0x14fe }, +/* 0x14ff */ { true, 0x14ff, 0x14ff }, +/* 0x1500 */ { true, 0x1500, 0x1500 }, +/* 0x1501 */ { true, 0x1501, 0x1501 }, +/* 0x1502 */ { true, 0x1502, 0x1502 }, +/* 0x1503 */ { true, 0x1503, 0x1503 }, +/* 0x1504 */ { true, 0x1504, 0x1504 }, +/* 0x1505 */ { true, 0x1505, 0x1505 }, +/* 0x1506 */ { true, 0x1506, 0x1506 }, +/* 0x1507 */ { true, 0x1507, 0x1507 }, +/* 0x1508 */ { true, 0x1508, 0x1508 }, +/* 0x1509 */ { true, 0x1509, 0x1509 }, +/* 0x150a */ { true, 0x150a, 0x150a }, +/* 0x150b */ { true, 0x150b, 0x150b }, +/* 0x150c */ { true, 0x150c, 0x150c }, +/* 0x150d */ { true, 0x150d, 0x150d }, +/* 0x150e */ { true, 0x150e, 0x150e }, +/* 0x150f */ { true, 0x150f, 0x150f }, +/* 0x1510 */ { true, 0x1510, 0x1510 }, +/* 0x1511 */ { true, 0x1511, 0x1511 }, +/* 0x1512 */ { true, 0x1512, 0x1512 }, +/* 0x1513 */ { true, 0x1513, 0x1513 }, +/* 0x1514 */ { true, 0x1514, 0x1514 }, +/* 0x1515 */ { true, 0x1515, 0x1515 }, +/* 0x1516 */ { true, 0x1516, 0x1516 }, +/* 0x1517 */ { true, 0x1517, 0x1517 }, +/* 0x1518 */ { true, 0x1518, 0x1518 }, +/* 0x1519 */ { true, 0x1519, 0x1519 }, +/* 0x151a */ { true, 0x151a, 0x151a }, +/* 0x151b */ { true, 0x151b, 0x151b }, +/* 0x151c */ { true, 0x151c, 0x151c }, +/* 0x151d */ { true, 0x151d, 0x151d }, +/* 0x151e */ { true, 0x151e, 0x151e }, +/* 0x151f */ { true, 0x151f, 0x151f }, +/* 0x1520 */ { true, 0x1520, 0x1520 }, +/* 0x1521 */ { true, 0x1521, 0x1521 }, +/* 0x1522 */ { true, 0x1522, 0x1522 }, +/* 0x1523 */ { true, 0x1523, 0x1523 }, +/* 0x1524 */ { true, 0x1524, 0x1524 }, +/* 0x1525 */ { true, 0x1525, 0x1525 }, +/* 0x1526 */ { true, 0x1526, 0x1526 }, +/* 0x1527 */ { true, 0x1527, 0x1527 }, +/* 0x1528 */ { true, 0x1528, 0x1528 }, +/* 0x1529 */ { true, 0x1529, 0x1529 }, +/* 0x152a */ { true, 0x152a, 0x152a }, +/* 0x152b */ { true, 0x152b, 0x152b }, +/* 0x152c */ { true, 0x152c, 0x152c }, +/* 0x152d */ { true, 0x152d, 0x152d }, +/* 0x152e */ { true, 0x152e, 0x152e }, +/* 0x152f */ { true, 0x152f, 0x152f }, +/* 0x1530 */ { true, 0x1530, 0x1530 }, +/* 0x1531 */ { true, 0x1531, 0x1531 }, +/* 0x1532 */ { true, 0x1532, 0x1532 }, +/* 0x1533 */ { true, 0x1533, 0x1533 }, +/* 0x1534 */ { true, 0x1534, 0x1534 }, +/* 0x1535 */ { true, 0x1535, 0x1535 }, +/* 0x1536 */ { true, 0x1536, 0x1536 }, +/* 0x1537 */ { true, 0x1537, 0x1537 }, +/* 0x1538 */ { true, 0x1538, 0x1538 }, +/* 0x1539 */ { true, 0x1539, 0x1539 }, +/* 0x153a */ { true, 0x153a, 0x153a }, +/* 0x153b */ { true, 0x153b, 0x153b }, +/* 0x153c */ { true, 0x153c, 0x153c }, +/* 0x153d */ { true, 0x153d, 0x153d }, +/* 0x153e */ { true, 0x153e, 0x153e }, +/* 0x153f */ { true, 0x153f, 0x153f }, +/* 0x1540 */ { true, 0x1540, 0x1540 }, +/* 0x1541 */ { true, 0x1541, 0x1541 }, +/* 0x1542 */ { true, 0x1542, 0x1542 }, +/* 0x1543 */ { true, 0x1543, 0x1543 }, +/* 0x1544 */ { true, 0x1544, 0x1544 }, +/* 0x1545 */ { true, 0x1545, 0x1545 }, +/* 0x1546 */ { true, 0x1546, 0x1546 }, +/* 0x1547 */ { true, 0x1547, 0x1547 }, +/* 0x1548 */ { true, 0x1548, 0x1548 }, +/* 0x1549 */ { true, 0x1549, 0x1549 }, +/* 0x154a */ { true, 0x154a, 0x154a }, +/* 0x154b */ { true, 0x154b, 0x154b }, +/* 0x154c */ { true, 0x154c, 0x154c }, +/* 0x154d */ { true, 0x154d, 0x154d }, +/* 0x154e */ { true, 0x154e, 0x154e }, +/* 0x154f */ { true, 0x154f, 0x154f }, +/* 0x1550 */ { true, 0x1550, 0x1550 }, +/* 0x1551 */ { true, 0x1551, 0x1551 }, +/* 0x1552 */ { true, 0x1552, 0x1552 }, +/* 0x1553 */ { true, 0x1553, 0x1553 }, +/* 0x1554 */ { true, 0x1554, 0x1554 }, +/* 0x1555 */ { true, 0x1555, 0x1555 }, +/* 0x1556 */ { true, 0x1556, 0x1556 }, +/* 0x1557 */ { true, 0x1557, 0x1557 }, +/* 0x1558 */ { true, 0x1558, 0x1558 }, +/* 0x1559 */ { true, 0x1559, 0x1559 }, +/* 0x155a */ { true, 0x155a, 0x155a }, +/* 0x155b */ { true, 0x155b, 0x155b }, +/* 0x155c */ { true, 0x155c, 0x155c }, +/* 0x155d */ { true, 0x155d, 0x155d }, +/* 0x155e */ { true, 0x155e, 0x155e }, +/* 0x155f */ { true, 0x155f, 0x155f }, +/* 0x1560 */ { true, 0x1560, 0x1560 }, +/* 0x1561 */ { true, 0x1561, 0x1561 }, +/* 0x1562 */ { true, 0x1562, 0x1562 }, +/* 0x1563 */ { true, 0x1563, 0x1563 }, +/* 0x1564 */ { true, 0x1564, 0x1564 }, +/* 0x1565 */ { true, 0x1565, 0x1565 }, +/* 0x1566 */ { true, 0x1566, 0x1566 }, +/* 0x1567 */ { true, 0x1567, 0x1567 }, +/* 0x1568 */ { true, 0x1568, 0x1568 }, +/* 0x1569 */ { true, 0x1569, 0x1569 }, +/* 0x156a */ { true, 0x156a, 0x156a }, +/* 0x156b */ { true, 0x156b, 0x156b }, +/* 0x156c */ { true, 0x156c, 0x156c }, +/* 0x156d */ { true, 0x156d, 0x156d }, +/* 0x156e */ { true, 0x156e, 0x156e }, +/* 0x156f */ { true, 0x156f, 0x156f }, +/* 0x1570 */ { true, 0x1570, 0x1570 }, +/* 0x1571 */ { true, 0x1571, 0x1571 }, +/* 0x1572 */ { true, 0x1572, 0x1572 }, +/* 0x1573 */ { true, 0x1573, 0x1573 }, +/* 0x1574 */ { true, 0x1574, 0x1574 }, +/* 0x1575 */ { true, 0x1575, 0x1575 }, +/* 0x1576 */ { true, 0x1576, 0x1576 }, +/* 0x1577 */ { true, 0x1577, 0x1577 }, +/* 0x1578 */ { true, 0x1578, 0x1578 }, +/* 0x1579 */ { true, 0x1579, 0x1579 }, +/* 0x157a */ { true, 0x157a, 0x157a }, +/* 0x157b */ { true, 0x157b, 0x157b }, +/* 0x157c */ { true, 0x157c, 0x157c }, +/* 0x157d */ { true, 0x157d, 0x157d }, +/* 0x157e */ { true, 0x157e, 0x157e }, +/* 0x157f */ { true, 0x157f, 0x157f }, +/* 0x1580 */ { true, 0x1580, 0x1580 }, +/* 0x1581 */ { true, 0x1581, 0x1581 }, +/* 0x1582 */ { true, 0x1582, 0x1582 }, +/* 0x1583 */ { true, 0x1583, 0x1583 }, +/* 0x1584 */ { true, 0x1584, 0x1584 }, +/* 0x1585 */ { true, 0x1585, 0x1585 }, +/* 0x1586 */ { true, 0x1586, 0x1586 }, +/* 0x1587 */ { true, 0x1587, 0x1587 }, +/* 0x1588 */ { true, 0x1588, 0x1588 }, +/* 0x1589 */ { true, 0x1589, 0x1589 }, +/* 0x158a */ { true, 0x158a, 0x158a }, +/* 0x158b */ { true, 0x158b, 0x158b }, +/* 0x158c */ { true, 0x158c, 0x158c }, +/* 0x158d */ { true, 0x158d, 0x158d }, +/* 0x158e */ { true, 0x158e, 0x158e }, +/* 0x158f */ { true, 0x158f, 0x158f }, +/* 0x1590 */ { true, 0x1590, 0x1590 }, +/* 0x1591 */ { true, 0x1591, 0x1591 }, +/* 0x1592 */ { true, 0x1592, 0x1592 }, +/* 0x1593 */ { true, 0x1593, 0x1593 }, +/* 0x1594 */ { true, 0x1594, 0x1594 }, +/* 0x1595 */ { true, 0x1595, 0x1595 }, +/* 0x1596 */ { true, 0x1596, 0x1596 }, +/* 0x1597 */ { true, 0x1597, 0x1597 }, +/* 0x1598 */ { true, 0x1598, 0x1598 }, +/* 0x1599 */ { true, 0x1599, 0x1599 }, +/* 0x159a */ { true, 0x159a, 0x159a }, +/* 0x159b */ { true, 0x159b, 0x159b }, +/* 0x159c */ { true, 0x159c, 0x159c }, +/* 0x159d */ { true, 0x159d, 0x159d }, +/* 0x159e */ { true, 0x159e, 0x159e }, +/* 0x159f */ { true, 0x159f, 0x159f }, +/* 0x15a0 */ { true, 0x15a0, 0x15a0 }, +/* 0x15a1 */ { true, 0x15a1, 0x15a1 }, +/* 0x15a2 */ { true, 0x15a2, 0x15a2 }, +/* 0x15a3 */ { true, 0x15a3, 0x15a3 }, +/* 0x15a4 */ { true, 0x15a4, 0x15a4 }, +/* 0x15a5 */ { true, 0x15a5, 0x15a5 }, +/* 0x15a6 */ { true, 0x15a6, 0x15a6 }, +/* 0x15a7 */ { true, 0x15a7, 0x15a7 }, +/* 0x15a8 */ { true, 0x15a8, 0x15a8 }, +/* 0x15a9 */ { true, 0x15a9, 0x15a9 }, +/* 0x15aa */ { true, 0x15aa, 0x15aa }, +/* 0x15ab */ { true, 0x15ab, 0x15ab }, +/* 0x15ac */ { true, 0x15ac, 0x15ac }, +/* 0x15ad */ { true, 0x15ad, 0x15ad }, +/* 0x15ae */ { true, 0x15ae, 0x15ae }, +/* 0x15af */ { true, 0x15af, 0x15af }, +/* 0x15b0 */ { true, 0x15b0, 0x15b0 }, +/* 0x15b1 */ { true, 0x15b1, 0x15b1 }, +/* 0x15b2 */ { true, 0x15b2, 0x15b2 }, +/* 0x15b3 */ { true, 0x15b3, 0x15b3 }, +/* 0x15b4 */ { true, 0x15b4, 0x15b4 }, +/* 0x15b5 */ { true, 0x15b5, 0x15b5 }, +/* 0x15b6 */ { true, 0x15b6, 0x15b6 }, +/* 0x15b7 */ { true, 0x15b7, 0x15b7 }, +/* 0x15b8 */ { true, 0x15b8, 0x15b8 }, +/* 0x15b9 */ { true, 0x15b9, 0x15b9 }, +/* 0x15ba */ { true, 0x15ba, 0x15ba }, +/* 0x15bb */ { true, 0x15bb, 0x15bb }, +/* 0x15bc */ { true, 0x15bc, 0x15bc }, +/* 0x15bd */ { true, 0x15bd, 0x15bd }, +/* 0x15be */ { true, 0x15be, 0x15be }, +/* 0x15bf */ { true, 0x15bf, 0x15bf }, +/* 0x15c0 */ { true, 0x15c0, 0x15c0 }, +/* 0x15c1 */ { true, 0x15c1, 0x15c1 }, +/* 0x15c2 */ { true, 0x15c2, 0x15c2 }, +/* 0x15c3 */ { true, 0x15c3, 0x15c3 }, +/* 0x15c4 */ { true, 0x15c4, 0x15c4 }, +/* 0x15c5 */ { true, 0x15c5, 0x15c5 }, +/* 0x15c6 */ { true, 0x15c6, 0x15c6 }, +/* 0x15c7 */ { true, 0x15c7, 0x15c7 }, +/* 0x15c8 */ { true, 0x15c8, 0x15c8 }, +/* 0x15c9 */ { true, 0x15c9, 0x15c9 }, +/* 0x15ca */ { true, 0x15ca, 0x15ca }, +/* 0x15cb */ { true, 0x15cb, 0x15cb }, +/* 0x15cc */ { true, 0x15cc, 0x15cc }, +/* 0x15cd */ { true, 0x15cd, 0x15cd }, +/* 0x15ce */ { true, 0x15ce, 0x15ce }, +/* 0x15cf */ { true, 0x15cf, 0x15cf }, +/* 0x15d0 */ { true, 0x15d0, 0x15d0 }, +/* 0x15d1 */ { true, 0x15d1, 0x15d1 }, +/* 0x15d2 */ { true, 0x15d2, 0x15d2 }, +/* 0x15d3 */ { true, 0x15d3, 0x15d3 }, +/* 0x15d4 */ { true, 0x15d4, 0x15d4 }, +/* 0x15d5 */ { true, 0x15d5, 0x15d5 }, +/* 0x15d6 */ { true, 0x15d6, 0x15d6 }, +/* 0x15d7 */ { true, 0x15d7, 0x15d7 }, +/* 0x15d8 */ { true, 0x15d8, 0x15d8 }, +/* 0x15d9 */ { true, 0x15d9, 0x15d9 }, +/* 0x15da */ { true, 0x15da, 0x15da }, +/* 0x15db */ { true, 0x15db, 0x15db }, +/* 0x15dc */ { true, 0x15dc, 0x15dc }, +/* 0x15dd */ { true, 0x15dd, 0x15dd }, +/* 0x15de */ { true, 0x15de, 0x15de }, +/* 0x15df */ { true, 0x15df, 0x15df }, +/* 0x15e0 */ { true, 0x15e0, 0x15e0 }, +/* 0x15e1 */ { true, 0x15e1, 0x15e1 }, +/* 0x15e2 */ { true, 0x15e2, 0x15e2 }, +/* 0x15e3 */ { true, 0x15e3, 0x15e3 }, +/* 0x15e4 */ { true, 0x15e4, 0x15e4 }, +/* 0x15e5 */ { true, 0x15e5, 0x15e5 }, +/* 0x15e6 */ { true, 0x15e6, 0x15e6 }, +/* 0x15e7 */ { true, 0x15e7, 0x15e7 }, +/* 0x15e8 */ { true, 0x15e8, 0x15e8 }, +/* 0x15e9 */ { true, 0x15e9, 0x15e9 }, +/* 0x15ea */ { true, 0x15ea, 0x15ea }, +/* 0x15eb */ { true, 0x15eb, 0x15eb }, +/* 0x15ec */ { true, 0x15ec, 0x15ec }, +/* 0x15ed */ { true, 0x15ed, 0x15ed }, +/* 0x15ee */ { true, 0x15ee, 0x15ee }, +/* 0x15ef */ { true, 0x15ef, 0x15ef }, +/* 0x15f0 */ { true, 0x15f0, 0x15f0 }, +/* 0x15f1 */ { true, 0x15f1, 0x15f1 }, +/* 0x15f2 */ { true, 0x15f2, 0x15f2 }, +/* 0x15f3 */ { true, 0x15f3, 0x15f3 }, +/* 0x15f4 */ { true, 0x15f4, 0x15f4 }, +/* 0x15f5 */ { true, 0x15f5, 0x15f5 }, +/* 0x15f6 */ { true, 0x15f6, 0x15f6 }, +/* 0x15f7 */ { true, 0x15f7, 0x15f7 }, +/* 0x15f8 */ { true, 0x15f8, 0x15f8 }, +/* 0x15f9 */ { true, 0x15f9, 0x15f9 }, +/* 0x15fa */ { true, 0x15fa, 0x15fa }, +/* 0x15fb */ { true, 0x15fb, 0x15fb }, +/* 0x15fc */ { true, 0x15fc, 0x15fc }, +/* 0x15fd */ { true, 0x15fd, 0x15fd }, +/* 0x15fe */ { true, 0x15fe, 0x15fe }, +/* 0x15ff */ { true, 0x15ff, 0x15ff }, +/* 0x1600 */ { true, 0x1600, 0x1600 }, +/* 0x1601 */ { true, 0x1601, 0x1601 }, +/* 0x1602 */ { true, 0x1602, 0x1602 }, +/* 0x1603 */ { true, 0x1603, 0x1603 }, +/* 0x1604 */ { true, 0x1604, 0x1604 }, +/* 0x1605 */ { true, 0x1605, 0x1605 }, +/* 0x1606 */ { true, 0x1606, 0x1606 }, +/* 0x1607 */ { true, 0x1607, 0x1607 }, +/* 0x1608 */ { true, 0x1608, 0x1608 }, +/* 0x1609 */ { true, 0x1609, 0x1609 }, +/* 0x160a */ { true, 0x160a, 0x160a }, +/* 0x160b */ { true, 0x160b, 0x160b }, +/* 0x160c */ { true, 0x160c, 0x160c }, +/* 0x160d */ { true, 0x160d, 0x160d }, +/* 0x160e */ { true, 0x160e, 0x160e }, +/* 0x160f */ { true, 0x160f, 0x160f }, +/* 0x1610 */ { true, 0x1610, 0x1610 }, +/* 0x1611 */ { true, 0x1611, 0x1611 }, +/* 0x1612 */ { true, 0x1612, 0x1612 }, +/* 0x1613 */ { true, 0x1613, 0x1613 }, +/* 0x1614 */ { true, 0x1614, 0x1614 }, +/* 0x1615 */ { true, 0x1615, 0x1615 }, +/* 0x1616 */ { true, 0x1616, 0x1616 }, +/* 0x1617 */ { true, 0x1617, 0x1617 }, +/* 0x1618 */ { true, 0x1618, 0x1618 }, +/* 0x1619 */ { true, 0x1619, 0x1619 }, +/* 0x161a */ { true, 0x161a, 0x161a }, +/* 0x161b */ { true, 0x161b, 0x161b }, +/* 0x161c */ { true, 0x161c, 0x161c }, +/* 0x161d */ { true, 0x161d, 0x161d }, +/* 0x161e */ { true, 0x161e, 0x161e }, +/* 0x161f */ { true, 0x161f, 0x161f }, +/* 0x1620 */ { true, 0x1620, 0x1620 }, +/* 0x1621 */ { true, 0x1621, 0x1621 }, +/* 0x1622 */ { true, 0x1622, 0x1622 }, +/* 0x1623 */ { true, 0x1623, 0x1623 }, +/* 0x1624 */ { true, 0x1624, 0x1624 }, +/* 0x1625 */ { true, 0x1625, 0x1625 }, +/* 0x1626 */ { true, 0x1626, 0x1626 }, +/* 0x1627 */ { true, 0x1627, 0x1627 }, +/* 0x1628 */ { true, 0x1628, 0x1628 }, +/* 0x1629 */ { true, 0x1629, 0x1629 }, +/* 0x162a */ { true, 0x162a, 0x162a }, +/* 0x162b */ { true, 0x162b, 0x162b }, +/* 0x162c */ { true, 0x162c, 0x162c }, +/* 0x162d */ { true, 0x162d, 0x162d }, +/* 0x162e */ { true, 0x162e, 0x162e }, +/* 0x162f */ { true, 0x162f, 0x162f }, +/* 0x1630 */ { true, 0x1630, 0x1630 }, +/* 0x1631 */ { true, 0x1631, 0x1631 }, +/* 0x1632 */ { true, 0x1632, 0x1632 }, +/* 0x1633 */ { true, 0x1633, 0x1633 }, +/* 0x1634 */ { true, 0x1634, 0x1634 }, +/* 0x1635 */ { true, 0x1635, 0x1635 }, +/* 0x1636 */ { true, 0x1636, 0x1636 }, +/* 0x1637 */ { true, 0x1637, 0x1637 }, +/* 0x1638 */ { true, 0x1638, 0x1638 }, +/* 0x1639 */ { true, 0x1639, 0x1639 }, +/* 0x163a */ { true, 0x163a, 0x163a }, +/* 0x163b */ { true, 0x163b, 0x163b }, +/* 0x163c */ { true, 0x163c, 0x163c }, +/* 0x163d */ { true, 0x163d, 0x163d }, +/* 0x163e */ { true, 0x163e, 0x163e }, +/* 0x163f */ { true, 0x163f, 0x163f }, +/* 0x1640 */ { true, 0x1640, 0x1640 }, +/* 0x1641 */ { true, 0x1641, 0x1641 }, +/* 0x1642 */ { true, 0x1642, 0x1642 }, +/* 0x1643 */ { true, 0x1643, 0x1643 }, +/* 0x1644 */ { true, 0x1644, 0x1644 }, +/* 0x1645 */ { true, 0x1645, 0x1645 }, +/* 0x1646 */ { true, 0x1646, 0x1646 }, +/* 0x1647 */ { true, 0x1647, 0x1647 }, +/* 0x1648 */ { true, 0x1648, 0x1648 }, +/* 0x1649 */ { true, 0x1649, 0x1649 }, +/* 0x164a */ { true, 0x164a, 0x164a }, +/* 0x164b */ { true, 0x164b, 0x164b }, +/* 0x164c */ { true, 0x164c, 0x164c }, +/* 0x164d */ { true, 0x164d, 0x164d }, +/* 0x164e */ { true, 0x164e, 0x164e }, +/* 0x164f */ { true, 0x164f, 0x164f }, +/* 0x1650 */ { true, 0x1650, 0x1650 }, +/* 0x1651 */ { true, 0x1651, 0x1651 }, +/* 0x1652 */ { true, 0x1652, 0x1652 }, +/* 0x1653 */ { true, 0x1653, 0x1653 }, +/* 0x1654 */ { true, 0x1654, 0x1654 }, +/* 0x1655 */ { true, 0x1655, 0x1655 }, +/* 0x1656 */ { true, 0x1656, 0x1656 }, +/* 0x1657 */ { true, 0x1657, 0x1657 }, +/* 0x1658 */ { true, 0x1658, 0x1658 }, +/* 0x1659 */ { true, 0x1659, 0x1659 }, +/* 0x165a */ { true, 0x165a, 0x165a }, +/* 0x165b */ { true, 0x165b, 0x165b }, +/* 0x165c */ { true, 0x165c, 0x165c }, +/* 0x165d */ { true, 0x165d, 0x165d }, +/* 0x165e */ { true, 0x165e, 0x165e }, +/* 0x165f */ { true, 0x165f, 0x165f }, +/* 0x1660 */ { true, 0x1660, 0x1660 }, +/* 0x1661 */ { true, 0x1661, 0x1661 }, +/* 0x1662 */ { true, 0x1662, 0x1662 }, +/* 0x1663 */ { true, 0x1663, 0x1663 }, +/* 0x1664 */ { true, 0x1664, 0x1664 }, +/* 0x1665 */ { true, 0x1665, 0x1665 }, +/* 0x1666 */ { true, 0x1666, 0x1666 }, +/* 0x1667 */ { true, 0x1667, 0x1667 }, +/* 0x1668 */ { true, 0x1668, 0x1668 }, +/* 0x1669 */ { true, 0x1669, 0x1669 }, +/* 0x166a */ { true, 0x166a, 0x166a }, +/* 0x166b */ { true, 0x166b, 0x166b }, +/* 0x166c */ { true, 0x166c, 0x166c }, +/* 0x166d */ { false, 0x166d, 0x166d }, +/* 0x166e */ { false, 0x166e, 0x166e }, +/* 0x166f */ { true, 0x166f, 0x166f }, +/* 0x1670 */ { true, 0x1670, 0x1670 }, +/* 0x1671 */ { true, 0x1671, 0x1671 }, +/* 0x1672 */ { true, 0x1672, 0x1672 }, +/* 0x1673 */ { true, 0x1673, 0x1673 }, +/* 0x1674 */ { true, 0x1674, 0x1674 }, +/* 0x1675 */ { true, 0x1675, 0x1675 }, +/* 0x1676 */ { true, 0x1676, 0x1676 }, +/* 0x1677 */ { false, 0x1677, 0x1677 }, +/* 0x1678 */ { false, 0x1678, 0x1678 }, +/* 0x1679 */ { false, 0x1679, 0x1679 }, +/* 0x167a */ { false, 0x167a, 0x167a }, +/* 0x167b */ { false, 0x167b, 0x167b }, +/* 0x167c */ { false, 0x167c, 0x167c }, +/* 0x167d */ { false, 0x167d, 0x167d }, +/* 0x167e */ { false, 0x167e, 0x167e }, +/* 0x167f */ { false, 0x167f, 0x167f }, +/* 0x1680 */ { false, 0x1680, 0x1680 }, +/* 0x1681 */ { true, 0x1681, 0x1681 }, +/* 0x1682 */ { true, 0x1682, 0x1682 }, +/* 0x1683 */ { true, 0x1683, 0x1683 }, +/* 0x1684 */ { true, 0x1684, 0x1684 }, +/* 0x1685 */ { true, 0x1685, 0x1685 }, +/* 0x1686 */ { true, 0x1686, 0x1686 }, +/* 0x1687 */ { true, 0x1687, 0x1687 }, +/* 0x1688 */ { true, 0x1688, 0x1688 }, +/* 0x1689 */ { true, 0x1689, 0x1689 }, +/* 0x168a */ { true, 0x168a, 0x168a }, +/* 0x168b */ { true, 0x168b, 0x168b }, +/* 0x168c */ { true, 0x168c, 0x168c }, +/* 0x168d */ { true, 0x168d, 0x168d }, +/* 0x168e */ { true, 0x168e, 0x168e }, +/* 0x168f */ { true, 0x168f, 0x168f }, +/* 0x1690 */ { true, 0x1690, 0x1690 }, +/* 0x1691 */ { true, 0x1691, 0x1691 }, +/* 0x1692 */ { true, 0x1692, 0x1692 }, +/* 0x1693 */ { true, 0x1693, 0x1693 }, +/* 0x1694 */ { true, 0x1694, 0x1694 }, +/* 0x1695 */ { true, 0x1695, 0x1695 }, +/* 0x1696 */ { true, 0x1696, 0x1696 }, +/* 0x1697 */ { true, 0x1697, 0x1697 }, +/* 0x1698 */ { true, 0x1698, 0x1698 }, +/* 0x1699 */ { true, 0x1699, 0x1699 }, +/* 0x169a */ { true, 0x169a, 0x169a }, +/* 0x169b */ { false, 0x169b, 0x169b }, +/* 0x169c */ { false, 0x169c, 0x169c }, +/* 0x169d */ { false, 0x169d, 0x169d }, +/* 0x169e */ { false, 0x169e, 0x169e }, +/* 0x169f */ { false, 0x169f, 0x169f }, +/* 0x16a0 */ { true, 0x16a0, 0x16a0 }, +/* 0x16a1 */ { true, 0x16a1, 0x16a1 }, +/* 0x16a2 */ { true, 0x16a2, 0x16a2 }, +/* 0x16a3 */ { true, 0x16a3, 0x16a3 }, +/* 0x16a4 */ { true, 0x16a4, 0x16a4 }, +/* 0x16a5 */ { true, 0x16a5, 0x16a5 }, +/* 0x16a6 */ { true, 0x16a6, 0x16a6 }, +/* 0x16a7 */ { true, 0x16a7, 0x16a7 }, +/* 0x16a8 */ { true, 0x16a8, 0x16a8 }, +/* 0x16a9 */ { true, 0x16a9, 0x16a9 }, +/* 0x16aa */ { true, 0x16aa, 0x16aa }, +/* 0x16ab */ { true, 0x16ab, 0x16ab }, +/* 0x16ac */ { true, 0x16ac, 0x16ac }, +/* 0x16ad */ { true, 0x16ad, 0x16ad }, +/* 0x16ae */ { true, 0x16ae, 0x16ae }, +/* 0x16af */ { true, 0x16af, 0x16af }, +/* 0x16b0 */ { true, 0x16b0, 0x16b0 }, +/* 0x16b1 */ { true, 0x16b1, 0x16b1 }, +/* 0x16b2 */ { true, 0x16b2, 0x16b2 }, +/* 0x16b3 */ { true, 0x16b3, 0x16b3 }, +/* 0x16b4 */ { true, 0x16b4, 0x16b4 }, +/* 0x16b5 */ { true, 0x16b5, 0x16b5 }, +/* 0x16b6 */ { true, 0x16b6, 0x16b6 }, +/* 0x16b7 */ { true, 0x16b7, 0x16b7 }, +/* 0x16b8 */ { true, 0x16b8, 0x16b8 }, +/* 0x16b9 */ { true, 0x16b9, 0x16b9 }, +/* 0x16ba */ { true, 0x16ba, 0x16ba }, +/* 0x16bb */ { true, 0x16bb, 0x16bb }, +/* 0x16bc */ { true, 0x16bc, 0x16bc }, +/* 0x16bd */ { true, 0x16bd, 0x16bd }, +/* 0x16be */ { true, 0x16be, 0x16be }, +/* 0x16bf */ { true, 0x16bf, 0x16bf }, +/* 0x16c0 */ { true, 0x16c0, 0x16c0 }, +/* 0x16c1 */ { true, 0x16c1, 0x16c1 }, +/* 0x16c2 */ { true, 0x16c2, 0x16c2 }, +/* 0x16c3 */ { true, 0x16c3, 0x16c3 }, +/* 0x16c4 */ { true, 0x16c4, 0x16c4 }, +/* 0x16c5 */ { true, 0x16c5, 0x16c5 }, +/* 0x16c6 */ { true, 0x16c6, 0x16c6 }, +/* 0x16c7 */ { true, 0x16c7, 0x16c7 }, +/* 0x16c8 */ { true, 0x16c8, 0x16c8 }, +/* 0x16c9 */ { true, 0x16c9, 0x16c9 }, +/* 0x16ca */ { true, 0x16ca, 0x16ca }, +/* 0x16cb */ { true, 0x16cb, 0x16cb }, +/* 0x16cc */ { true, 0x16cc, 0x16cc }, +/* 0x16cd */ { true, 0x16cd, 0x16cd }, +/* 0x16ce */ { true, 0x16ce, 0x16ce }, +/* 0x16cf */ { true, 0x16cf, 0x16cf }, +/* 0x16d0 */ { true, 0x16d0, 0x16d0 }, +/* 0x16d1 */ { true, 0x16d1, 0x16d1 }, +/* 0x16d2 */ { true, 0x16d2, 0x16d2 }, +/* 0x16d3 */ { true, 0x16d3, 0x16d3 }, +/* 0x16d4 */ { true, 0x16d4, 0x16d4 }, +/* 0x16d5 */ { true, 0x16d5, 0x16d5 }, +/* 0x16d6 */ { true, 0x16d6, 0x16d6 }, +/* 0x16d7 */ { true, 0x16d7, 0x16d7 }, +/* 0x16d8 */ { true, 0x16d8, 0x16d8 }, +/* 0x16d9 */ { true, 0x16d9, 0x16d9 }, +/* 0x16da */ { true, 0x16da, 0x16da }, +/* 0x16db */ { true, 0x16db, 0x16db }, +/* 0x16dc */ { true, 0x16dc, 0x16dc }, +/* 0x16dd */ { true, 0x16dd, 0x16dd }, +/* 0x16de */ { true, 0x16de, 0x16de }, +/* 0x16df */ { true, 0x16df, 0x16df }, +/* 0x16e0 */ { true, 0x16e0, 0x16e0 }, +/* 0x16e1 */ { true, 0x16e1, 0x16e1 }, +/* 0x16e2 */ { true, 0x16e2, 0x16e2 }, +/* 0x16e3 */ { true, 0x16e3, 0x16e3 }, +/* 0x16e4 */ { true, 0x16e4, 0x16e4 }, +/* 0x16e5 */ { true, 0x16e5, 0x16e5 }, +/* 0x16e6 */ { true, 0x16e6, 0x16e6 }, +/* 0x16e7 */ { true, 0x16e7, 0x16e7 }, +/* 0x16e8 */ { true, 0x16e8, 0x16e8 }, +/* 0x16e9 */ { true, 0x16e9, 0x16e9 }, +/* 0x16ea */ { true, 0x16ea, 0x16ea }, +/* 0x16eb */ { false, 0x16eb, 0x16eb }, +/* 0x16ec */ { false, 0x16ec, 0x16ec }, +/* 0x16ed */ { false, 0x16ed, 0x16ed }, +/* 0x16ee */ { false, 0x16ee, 0x16ee }, +/* 0x16ef */ { false, 0x16ef, 0x16ef }, +/* 0x16f0 */ { false, 0x16f0, 0x16f0 }, +/* 0x16f1 */ { false, 0x16f1, 0x16f1 }, +/* 0x16f2 */ { false, 0x16f2, 0x16f2 }, +/* 0x16f3 */ { false, 0x16f3, 0x16f3 }, +/* 0x16f4 */ { false, 0x16f4, 0x16f4 }, +/* 0x16f5 */ { false, 0x16f5, 0x16f5 }, +/* 0x16f6 */ { false, 0x16f6, 0x16f6 }, +/* 0x16f7 */ { false, 0x16f7, 0x16f7 }, +/* 0x16f8 */ { false, 0x16f8, 0x16f8 }, +/* 0x16f9 */ { false, 0x16f9, 0x16f9 }, +/* 0x16fa */ { false, 0x16fa, 0x16fa }, +/* 0x16fb */ { false, 0x16fb, 0x16fb }, +/* 0x16fc */ { false, 0x16fc, 0x16fc }, +/* 0x16fd */ { false, 0x16fd, 0x16fd }, +/* 0x16fe */ { false, 0x16fe, 0x16fe }, +/* 0x16ff */ { false, 0x16ff, 0x16ff }, +/* 0x1700 */ { true, 0x1700, 0x1700 }, +/* 0x1701 */ { true, 0x1701, 0x1701 }, +/* 0x1702 */ { true, 0x1702, 0x1702 }, +/* 0x1703 */ { true, 0x1703, 0x1703 }, +/* 0x1704 */ { true, 0x1704, 0x1704 }, +/* 0x1705 */ { true, 0x1705, 0x1705 }, +/* 0x1706 */ { true, 0x1706, 0x1706 }, +/* 0x1707 */ { true, 0x1707, 0x1707 }, +/* 0x1708 */ { true, 0x1708, 0x1708 }, +/* 0x1709 */ { true, 0x1709, 0x1709 }, +/* 0x170a */ { true, 0x170a, 0x170a }, +/* 0x170b */ { true, 0x170b, 0x170b }, +/* 0x170c */ { true, 0x170c, 0x170c }, +/* 0x170d */ { false, 0x170d, 0x170d }, +/* 0x170e */ { true, 0x170e, 0x170e }, +/* 0x170f */ { true, 0x170f, 0x170f }, +/* 0x1710 */ { true, 0x1710, 0x1710 }, +/* 0x1711 */ { true, 0x1711, 0x1711 }, +/* 0x1712 */ { true, 0x1712, 0x1712 }, +/* 0x1713 */ { true, 0x1713, 0x1713 }, +/* 0x1714 */ { true, 0x1714, 0x1714 }, +/* 0x1715 */ { true, 0x1715, 0x1715 }, +/* 0x1716 */ { false, 0x1716, 0x1716 }, +/* 0x1717 */ { false, 0x1717, 0x1717 }, +/* 0x1718 */ { false, 0x1718, 0x1718 }, +/* 0x1719 */ { false, 0x1719, 0x1719 }, +/* 0x171a */ { false, 0x171a, 0x171a }, +/* 0x171b */ { false, 0x171b, 0x171b }, +/* 0x171c */ { false, 0x171c, 0x171c }, +/* 0x171d */ { false, 0x171d, 0x171d }, +/* 0x171e */ { false, 0x171e, 0x171e }, +/* 0x171f */ { false, 0x171f, 0x171f }, +/* 0x1720 */ { true, 0x1720, 0x1720 }, +/* 0x1721 */ { true, 0x1721, 0x1721 }, +/* 0x1722 */ { true, 0x1722, 0x1722 }, +/* 0x1723 */ { true, 0x1723, 0x1723 }, +/* 0x1724 */ { true, 0x1724, 0x1724 }, +/* 0x1725 */ { true, 0x1725, 0x1725 }, +/* 0x1726 */ { true, 0x1726, 0x1726 }, +/* 0x1727 */ { true, 0x1727, 0x1727 }, +/* 0x1728 */ { true, 0x1728, 0x1728 }, +/* 0x1729 */ { true, 0x1729, 0x1729 }, +/* 0x172a */ { true, 0x172a, 0x172a }, +/* 0x172b */ { true, 0x172b, 0x172b }, +/* 0x172c */ { true, 0x172c, 0x172c }, +/* 0x172d */ { true, 0x172d, 0x172d }, +/* 0x172e */ { true, 0x172e, 0x172e }, +/* 0x172f */ { true, 0x172f, 0x172f }, +/* 0x1730 */ { true, 0x1730, 0x1730 }, +/* 0x1731 */ { true, 0x1731, 0x1731 }, +/* 0x1732 */ { true, 0x1732, 0x1732 }, +/* 0x1733 */ { true, 0x1733, 0x1733 }, +/* 0x1734 */ { true, 0x1734, 0x1734 }, +/* 0x1735 */ { false, 0x1735, 0x1735 }, +/* 0x1736 */ { false, 0x1736, 0x1736 }, +/* 0x1737 */ { false, 0x1737, 0x1737 }, +/* 0x1738 */ { false, 0x1738, 0x1738 }, +/* 0x1739 */ { false, 0x1739, 0x1739 }, +/* 0x173a */ { false, 0x173a, 0x173a }, +/* 0x173b */ { false, 0x173b, 0x173b }, +/* 0x173c */ { false, 0x173c, 0x173c }, +/* 0x173d */ { false, 0x173d, 0x173d }, +/* 0x173e */ { false, 0x173e, 0x173e }, +/* 0x173f */ { false, 0x173f, 0x173f }, +/* 0x1740 */ { true, 0x1740, 0x1740 }, +/* 0x1741 */ { true, 0x1741, 0x1741 }, +/* 0x1742 */ { true, 0x1742, 0x1742 }, +/* 0x1743 */ { true, 0x1743, 0x1743 }, +/* 0x1744 */ { true, 0x1744, 0x1744 }, +/* 0x1745 */ { true, 0x1745, 0x1745 }, +/* 0x1746 */ { true, 0x1746, 0x1746 }, +/* 0x1747 */ { true, 0x1747, 0x1747 }, +/* 0x1748 */ { true, 0x1748, 0x1748 }, +/* 0x1749 */ { true, 0x1749, 0x1749 }, +/* 0x174a */ { true, 0x174a, 0x174a }, +/* 0x174b */ { true, 0x174b, 0x174b }, +/* 0x174c */ { true, 0x174c, 0x174c }, +/* 0x174d */ { true, 0x174d, 0x174d }, +/* 0x174e */ { true, 0x174e, 0x174e }, +/* 0x174f */ { true, 0x174f, 0x174f }, +/* 0x1750 */ { true, 0x1750, 0x1750 }, +/* 0x1751 */ { true, 0x1751, 0x1751 }, +/* 0x1752 */ { true, 0x1752, 0x1752 }, +/* 0x1753 */ { true, 0x1753, 0x1753 }, +/* 0x1754 */ { false, 0x1754, 0x1754 }, +/* 0x1755 */ { false, 0x1755, 0x1755 }, +/* 0x1756 */ { false, 0x1756, 0x1756 }, +/* 0x1757 */ { false, 0x1757, 0x1757 }, +/* 0x1758 */ { false, 0x1758, 0x1758 }, +/* 0x1759 */ { false, 0x1759, 0x1759 }, +/* 0x175a */ { false, 0x175a, 0x175a }, +/* 0x175b */ { false, 0x175b, 0x175b }, +/* 0x175c */ { false, 0x175c, 0x175c }, +/* 0x175d */ { false, 0x175d, 0x175d }, +/* 0x175e */ { false, 0x175e, 0x175e }, +/* 0x175f */ { false, 0x175f, 0x175f }, +/* 0x1760 */ { true, 0x1760, 0x1760 }, +/* 0x1761 */ { true, 0x1761, 0x1761 }, +/* 0x1762 */ { true, 0x1762, 0x1762 }, +/* 0x1763 */ { true, 0x1763, 0x1763 }, +/* 0x1764 */ { true, 0x1764, 0x1764 }, +/* 0x1765 */ { true, 0x1765, 0x1765 }, +/* 0x1766 */ { true, 0x1766, 0x1766 }, +/* 0x1767 */ { true, 0x1767, 0x1767 }, +/* 0x1768 */ { true, 0x1768, 0x1768 }, +/* 0x1769 */ { true, 0x1769, 0x1769 }, +/* 0x176a */ { true, 0x176a, 0x176a }, +/* 0x176b */ { true, 0x176b, 0x176b }, +/* 0x176c */ { true, 0x176c, 0x176c }, +/* 0x176d */ { false, 0x176d, 0x176d }, +/* 0x176e */ { true, 0x176e, 0x176e }, +/* 0x176f */ { true, 0x176f, 0x176f }, +/* 0x1770 */ { true, 0x1770, 0x1770 }, +/* 0x1771 */ { false, 0x1771, 0x1771 }, +/* 0x1772 */ { true, 0x1772, 0x1772 }, +/* 0x1773 */ { true, 0x1773, 0x1773 }, +/* 0x1774 */ { false, 0x1774, 0x1774 }, +/* 0x1775 */ { false, 0x1775, 0x1775 }, +/* 0x1776 */ { false, 0x1776, 0x1776 }, +/* 0x1777 */ { false, 0x1777, 0x1777 }, +/* 0x1778 */ { false, 0x1778, 0x1778 }, +/* 0x1779 */ { false, 0x1779, 0x1779 }, +/* 0x177a */ { false, 0x177a, 0x177a }, +/* 0x177b */ { false, 0x177b, 0x177b }, +/* 0x177c */ { false, 0x177c, 0x177c }, +/* 0x177d */ { false, 0x177d, 0x177d }, +/* 0x177e */ { false, 0x177e, 0x177e }, +/* 0x177f */ { false, 0x177f, 0x177f }, +/* 0x1780 */ { true, 0x1780, 0x1780 }, +/* 0x1781 */ { true, 0x1781, 0x1781 }, +/* 0x1782 */ { true, 0x1782, 0x1782 }, +/* 0x1783 */ { true, 0x1783, 0x1783 }, +/* 0x1784 */ { true, 0x1784, 0x1784 }, +/* 0x1785 */ { true, 0x1785, 0x1785 }, +/* 0x1786 */ { true, 0x1786, 0x1786 }, +/* 0x1787 */ { true, 0x1787, 0x1787 }, +/* 0x1788 */ { true, 0x1788, 0x1788 }, +/* 0x1789 */ { true, 0x1789, 0x1789 }, +/* 0x178a */ { true, 0x178a, 0x178a }, +/* 0x178b */ { true, 0x178b, 0x178b }, +/* 0x178c */ { true, 0x178c, 0x178c }, +/* 0x178d */ { true, 0x178d, 0x178d }, +/* 0x178e */ { true, 0x178e, 0x178e }, +/* 0x178f */ { true, 0x178f, 0x178f }, +/* 0x1790 */ { true, 0x1790, 0x1790 }, +/* 0x1791 */ { true, 0x1791, 0x1791 }, +/* 0x1792 */ { true, 0x1792, 0x1792 }, +/* 0x1793 */ { true, 0x1793, 0x1793 }, +/* 0x1794 */ { true, 0x1794, 0x1794 }, +/* 0x1795 */ { true, 0x1795, 0x1795 }, +/* 0x1796 */ { true, 0x1796, 0x1796 }, +/* 0x1797 */ { true, 0x1797, 0x1797 }, +/* 0x1798 */ { true, 0x1798, 0x1798 }, +/* 0x1799 */ { true, 0x1799, 0x1799 }, +/* 0x179a */ { true, 0x179a, 0x179a }, +/* 0x179b */ { true, 0x179b, 0x179b }, +/* 0x179c */ { true, 0x179c, 0x179c }, +/* 0x179d */ { true, 0x179d, 0x179d }, +/* 0x179e */ { true, 0x179e, 0x179e }, +/* 0x179f */ { true, 0x179f, 0x179f }, +/* 0x17a0 */ { true, 0x17a0, 0x17a0 }, +/* 0x17a1 */ { true, 0x17a1, 0x17a1 }, +/* 0x17a2 */ { true, 0x17a2, 0x17a2 }, +/* 0x17a3 */ { true, 0x17a3, 0x17a3 }, +/* 0x17a4 */ { true, 0x17a4, 0x17a4 }, +/* 0x17a5 */ { true, 0x17a5, 0x17a5 }, +/* 0x17a6 */ { true, 0x17a6, 0x17a6 }, +/* 0x17a7 */ { true, 0x17a7, 0x17a7 }, +/* 0x17a8 */ { true, 0x17a8, 0x17a8 }, +/* 0x17a9 */ { true, 0x17a9, 0x17a9 }, +/* 0x17aa */ { true, 0x17aa, 0x17aa }, +/* 0x17ab */ { true, 0x17ab, 0x17ab }, +/* 0x17ac */ { true, 0x17ac, 0x17ac }, +/* 0x17ad */ { true, 0x17ad, 0x17ad }, +/* 0x17ae */ { true, 0x17ae, 0x17ae }, +/* 0x17af */ { true, 0x17af, 0x17af }, +/* 0x17b0 */ { true, 0x17b0, 0x17b0 }, +/* 0x17b1 */ { true, 0x17b1, 0x17b1 }, +/* 0x17b2 */ { true, 0x17b2, 0x17b2 }, +/* 0x17b3 */ { true, 0x17b3, 0x17b3 }, +/* 0x17b4 */ { false, 0x17b4, 0x17b4 }, +/* 0x17b5 */ { false, 0x17b5, 0x17b5 }, +/* 0x17b6 */ { true, 0x17b6, 0x17b6 }, +/* 0x17b7 */ { true, 0x17b7, 0x17b7 }, +/* 0x17b8 */ { true, 0x17b8, 0x17b8 }, +/* 0x17b9 */ { true, 0x17b9, 0x17b9 }, +/* 0x17ba */ { true, 0x17ba, 0x17ba }, +/* 0x17bb */ { true, 0x17bb, 0x17bb }, +/* 0x17bc */ { true, 0x17bc, 0x17bc }, +/* 0x17bd */ { true, 0x17bd, 0x17bd }, +/* 0x17be */ { true, 0x17be, 0x17be }, +/* 0x17bf */ { true, 0x17bf, 0x17bf }, +/* 0x17c0 */ { true, 0x17c0, 0x17c0 }, +/* 0x17c1 */ { true, 0x17c1, 0x17c1 }, +/* 0x17c2 */ { true, 0x17c2, 0x17c2 }, +/* 0x17c3 */ { true, 0x17c3, 0x17c3 }, +/* 0x17c4 */ { true, 0x17c4, 0x17c4 }, +/* 0x17c5 */ { true, 0x17c5, 0x17c5 }, +/* 0x17c6 */ { true, 0x17c6, 0x17c6 }, +/* 0x17c7 */ { true, 0x17c7, 0x17c7 }, +/* 0x17c8 */ { true, 0x17c8, 0x17c8 }, +/* 0x17c9 */ { true, 0x17c9, 0x17c9 }, +/* 0x17ca */ { true, 0x17ca, 0x17ca }, +/* 0x17cb */ { true, 0x17cb, 0x17cb }, +/* 0x17cc */ { true, 0x17cc, 0x17cc }, +/* 0x17cd */ { true, 0x17cd, 0x17cd }, +/* 0x17ce */ { true, 0x17ce, 0x17ce }, +/* 0x17cf */ { true, 0x17cf, 0x17cf }, +/* 0x17d0 */ { true, 0x17d0, 0x17d0 }, +/* 0x17d1 */ { true, 0x17d1, 0x17d1 }, +/* 0x17d2 */ { true, 0x17d2, 0x17d2 }, +/* 0x17d3 */ { true, 0x17d3, 0x17d3 }, +/* 0x17d4 */ { false, 0x17d4, 0x17d4 }, +/* 0x17d5 */ { false, 0x17d5, 0x17d5 }, +/* 0x17d6 */ { false, 0x17d6, 0x17d6 }, +/* 0x17d7 */ { true, 0x17d7, 0x17d7 }, +/* 0x17d8 */ { false, 0x17d8, 0x17d8 }, +/* 0x17d9 */ { false, 0x17d9, 0x17d9 }, +/* 0x17da */ { false, 0x17da, 0x17da }, +/* 0x17db */ { false, 0x17db, 0x17db }, +/* 0x17dc */ { true, 0x17dc, 0x17dc }, +/* 0x17dd */ { true, 0x17dd, 0x17dd }, +/* 0x17de */ { false, 0x17de, 0x17de }, +/* 0x17df */ { false, 0x17df, 0x17df }, +/* 0x17e0 */ { false, 0x17e0, 0x17e0 }, +/* 0x17e1 */ { false, 0x17e1, 0x17e1 }, +/* 0x17e2 */ { false, 0x17e2, 0x17e2 }, +/* 0x17e3 */ { false, 0x17e3, 0x17e3 }, +/* 0x17e4 */ { false, 0x17e4, 0x17e4 }, +/* 0x17e5 */ { false, 0x17e5, 0x17e5 }, +/* 0x17e6 */ { false, 0x17e6, 0x17e6 }, +/* 0x17e7 */ { false, 0x17e7, 0x17e7 }, +/* 0x17e8 */ { false, 0x17e8, 0x17e8 }, +/* 0x17e9 */ { false, 0x17e9, 0x17e9 }, +/* 0x17ea */ { false, 0x17ea, 0x17ea }, +/* 0x17eb */ { false, 0x17eb, 0x17eb }, +/* 0x17ec */ { false, 0x17ec, 0x17ec }, +/* 0x17ed */ { false, 0x17ed, 0x17ed }, +/* 0x17ee */ { false, 0x17ee, 0x17ee }, +/* 0x17ef */ { false, 0x17ef, 0x17ef }, +/* 0x17f0 */ { false, 0x17f0, 0x17f0 }, +/* 0x17f1 */ { false, 0x17f1, 0x17f1 }, +/* 0x17f2 */ { false, 0x17f2, 0x17f2 }, +/* 0x17f3 */ { false, 0x17f3, 0x17f3 }, +/* 0x17f4 */ { false, 0x17f4, 0x17f4 }, +/* 0x17f5 */ { false, 0x17f5, 0x17f5 }, +/* 0x17f6 */ { false, 0x17f6, 0x17f6 }, +/* 0x17f7 */ { false, 0x17f7, 0x17f7 }, +/* 0x17f8 */ { false, 0x17f8, 0x17f8 }, +/* 0x17f9 */ { false, 0x17f9, 0x17f9 }, +/* 0x17fa */ { false, 0x17fa, 0x17fa }, +/* 0x17fb */ { false, 0x17fb, 0x17fb }, +/* 0x17fc */ { false, 0x17fc, 0x17fc }, +/* 0x17fd */ { false, 0x17fd, 0x17fd }, +/* 0x17fe */ { false, 0x17fe, 0x17fe }, +/* 0x17ff */ { false, 0x17ff, 0x17ff }, +/* 0x1800 */ { false, 0x1800, 0x1800 }, +/* 0x1801 */ { false, 0x1801, 0x1801 }, +/* 0x1802 */ { false, 0x1802, 0x1802 }, +/* 0x1803 */ { false, 0x1803, 0x1803 }, +/* 0x1804 */ { false, 0x1804, 0x1804 }, +/* 0x1805 */ { false, 0x1805, 0x1805 }, +/* 0x1806 */ { false, 0x1806, 0x1806 }, +/* 0x1807 */ { false, 0x1807, 0x1807 }, +/* 0x1808 */ { false, 0x1808, 0x1808 }, +/* 0x1809 */ { false, 0x1809, 0x1809 }, +/* 0x180a */ { false, 0x180a, 0x180a }, +/* 0x180b */ { true, 0x180b, 0x180b }, +/* 0x180c */ { true, 0x180c, 0x180c }, +/* 0x180d */ { true, 0x180d, 0x180d }, +/* 0x180e */ { false, 0x180e, 0x180e }, +/* 0x180f */ { false, 0x180f, 0x180f }, +/* 0x1810 */ { false, 0x1810, 0x1810 }, +/* 0x1811 */ { false, 0x1811, 0x1811 }, +/* 0x1812 */ { false, 0x1812, 0x1812 }, +/* 0x1813 */ { false, 0x1813, 0x1813 }, +/* 0x1814 */ { false, 0x1814, 0x1814 }, +/* 0x1815 */ { false, 0x1815, 0x1815 }, +/* 0x1816 */ { false, 0x1816, 0x1816 }, +/* 0x1817 */ { false, 0x1817, 0x1817 }, +/* 0x1818 */ { false, 0x1818, 0x1818 }, +/* 0x1819 */ { false, 0x1819, 0x1819 }, +/* 0x181a */ { false, 0x181a, 0x181a }, +/* 0x181b */ { false, 0x181b, 0x181b }, +/* 0x181c */ { false, 0x181c, 0x181c }, +/* 0x181d */ { false, 0x181d, 0x181d }, +/* 0x181e */ { false, 0x181e, 0x181e }, +/* 0x181f */ { false, 0x181f, 0x181f }, +/* 0x1820 */ { true, 0x1820, 0x1820 }, +/* 0x1821 */ { true, 0x1821, 0x1821 }, +/* 0x1822 */ { true, 0x1822, 0x1822 }, +/* 0x1823 */ { true, 0x1823, 0x1823 }, +/* 0x1824 */ { true, 0x1824, 0x1824 }, +/* 0x1825 */ { true, 0x1825, 0x1825 }, +/* 0x1826 */ { true, 0x1826, 0x1826 }, +/* 0x1827 */ { true, 0x1827, 0x1827 }, +/* 0x1828 */ { true, 0x1828, 0x1828 }, +/* 0x1829 */ { true, 0x1829, 0x1829 }, +/* 0x182a */ { true, 0x182a, 0x182a }, +/* 0x182b */ { true, 0x182b, 0x182b }, +/* 0x182c */ { true, 0x182c, 0x182c }, +/* 0x182d */ { true, 0x182d, 0x182d }, +/* 0x182e */ { true, 0x182e, 0x182e }, +/* 0x182f */ { true, 0x182f, 0x182f }, +/* 0x1830 */ { true, 0x1830, 0x1830 }, +/* 0x1831 */ { true, 0x1831, 0x1831 }, +/* 0x1832 */ { true, 0x1832, 0x1832 }, +/* 0x1833 */ { true, 0x1833, 0x1833 }, +/* 0x1834 */ { true, 0x1834, 0x1834 }, +/* 0x1835 */ { true, 0x1835, 0x1835 }, +/* 0x1836 */ { true, 0x1836, 0x1836 }, +/* 0x1837 */ { true, 0x1837, 0x1837 }, +/* 0x1838 */ { true, 0x1838, 0x1838 }, +/* 0x1839 */ { true, 0x1839, 0x1839 }, +/* 0x183a */ { true, 0x183a, 0x183a }, +/* 0x183b */ { true, 0x183b, 0x183b }, +/* 0x183c */ { true, 0x183c, 0x183c }, +/* 0x183d */ { true, 0x183d, 0x183d }, +/* 0x183e */ { true, 0x183e, 0x183e }, +/* 0x183f */ { true, 0x183f, 0x183f }, +/* 0x1840 */ { true, 0x1840, 0x1840 }, +/* 0x1841 */ { true, 0x1841, 0x1841 }, +/* 0x1842 */ { true, 0x1842, 0x1842 }, +/* 0x1843 */ { true, 0x1843, 0x1843 }, +/* 0x1844 */ { true, 0x1844, 0x1844 }, +/* 0x1845 */ { true, 0x1845, 0x1845 }, +/* 0x1846 */ { true, 0x1846, 0x1846 }, +/* 0x1847 */ { true, 0x1847, 0x1847 }, +/* 0x1848 */ { true, 0x1848, 0x1848 }, +/* 0x1849 */ { true, 0x1849, 0x1849 }, +/* 0x184a */ { true, 0x184a, 0x184a }, +/* 0x184b */ { true, 0x184b, 0x184b }, +/* 0x184c */ { true, 0x184c, 0x184c }, +/* 0x184d */ { true, 0x184d, 0x184d }, +/* 0x184e */ { true, 0x184e, 0x184e }, +/* 0x184f */ { true, 0x184f, 0x184f }, +/* 0x1850 */ { true, 0x1850, 0x1850 }, +/* 0x1851 */ { true, 0x1851, 0x1851 }, +/* 0x1852 */ { true, 0x1852, 0x1852 }, +/* 0x1853 */ { true, 0x1853, 0x1853 }, +/* 0x1854 */ { true, 0x1854, 0x1854 }, +/* 0x1855 */ { true, 0x1855, 0x1855 }, +/* 0x1856 */ { true, 0x1856, 0x1856 }, +/* 0x1857 */ { true, 0x1857, 0x1857 }, +/* 0x1858 */ { true, 0x1858, 0x1858 }, +/* 0x1859 */ { true, 0x1859, 0x1859 }, +/* 0x185a */ { true, 0x185a, 0x185a }, +/* 0x185b */ { true, 0x185b, 0x185b }, +/* 0x185c */ { true, 0x185c, 0x185c }, +/* 0x185d */ { true, 0x185d, 0x185d }, +/* 0x185e */ { true, 0x185e, 0x185e }, +/* 0x185f */ { true, 0x185f, 0x185f }, +/* 0x1860 */ { true, 0x1860, 0x1860 }, +/* 0x1861 */ { true, 0x1861, 0x1861 }, +/* 0x1862 */ { true, 0x1862, 0x1862 }, +/* 0x1863 */ { true, 0x1863, 0x1863 }, +/* 0x1864 */ { true, 0x1864, 0x1864 }, +/* 0x1865 */ { true, 0x1865, 0x1865 }, +/* 0x1866 */ { true, 0x1866, 0x1866 }, +/* 0x1867 */ { true, 0x1867, 0x1867 }, +/* 0x1868 */ { true, 0x1868, 0x1868 }, +/* 0x1869 */ { true, 0x1869, 0x1869 }, +/* 0x186a */ { true, 0x186a, 0x186a }, +/* 0x186b */ { true, 0x186b, 0x186b }, +/* 0x186c */ { true, 0x186c, 0x186c }, +/* 0x186d */ { true, 0x186d, 0x186d }, +/* 0x186e */ { true, 0x186e, 0x186e }, +/* 0x186f */ { true, 0x186f, 0x186f }, +/* 0x1870 */ { true, 0x1870, 0x1870 }, +/* 0x1871 */ { true, 0x1871, 0x1871 }, +/* 0x1872 */ { true, 0x1872, 0x1872 }, +/* 0x1873 */ { true, 0x1873, 0x1873 }, +/* 0x1874 */ { true, 0x1874, 0x1874 }, +/* 0x1875 */ { true, 0x1875, 0x1875 }, +/* 0x1876 */ { true, 0x1876, 0x1876 }, +/* 0x1877 */ { true, 0x1877, 0x1877 }, +/* 0x1878 */ { false, 0x1878, 0x1878 }, +/* 0x1879 */ { false, 0x1879, 0x1879 }, +/* 0x187a */ { false, 0x187a, 0x187a }, +/* 0x187b */ { false, 0x187b, 0x187b }, +/* 0x187c */ { false, 0x187c, 0x187c }, +/* 0x187d */ { false, 0x187d, 0x187d }, +/* 0x187e */ { false, 0x187e, 0x187e }, +/* 0x187f */ { false, 0x187f, 0x187f }, +/* 0x1880 */ { true, 0x1880, 0x1880 }, +/* 0x1881 */ { true, 0x1881, 0x1881 }, +/* 0x1882 */ { true, 0x1882, 0x1882 }, +/* 0x1883 */ { true, 0x1883, 0x1883 }, +/* 0x1884 */ { true, 0x1884, 0x1884 }, +/* 0x1885 */ { true, 0x1885, 0x1885 }, +/* 0x1886 */ { true, 0x1886, 0x1886 }, +/* 0x1887 */ { true, 0x1887, 0x1887 }, +/* 0x1888 */ { true, 0x1888, 0x1888 }, +/* 0x1889 */ { true, 0x1889, 0x1889 }, +/* 0x188a */ { true, 0x188a, 0x188a }, +/* 0x188b */ { true, 0x188b, 0x188b }, +/* 0x188c */ { true, 0x188c, 0x188c }, +/* 0x188d */ { true, 0x188d, 0x188d }, +/* 0x188e */ { true, 0x188e, 0x188e }, +/* 0x188f */ { true, 0x188f, 0x188f }, +/* 0x1890 */ { true, 0x1890, 0x1890 }, +/* 0x1891 */ { true, 0x1891, 0x1891 }, +/* 0x1892 */ { true, 0x1892, 0x1892 }, +/* 0x1893 */ { true, 0x1893, 0x1893 }, +/* 0x1894 */ { true, 0x1894, 0x1894 }, +/* 0x1895 */ { true, 0x1895, 0x1895 }, +/* 0x1896 */ { true, 0x1896, 0x1896 }, +/* 0x1897 */ { true, 0x1897, 0x1897 }, +/* 0x1898 */ { true, 0x1898, 0x1898 }, +/* 0x1899 */ { true, 0x1899, 0x1899 }, +/* 0x189a */ { true, 0x189a, 0x189a }, +/* 0x189b */ { true, 0x189b, 0x189b }, +/* 0x189c */ { true, 0x189c, 0x189c }, +/* 0x189d */ { true, 0x189d, 0x189d }, +/* 0x189e */ { true, 0x189e, 0x189e }, +/* 0x189f */ { true, 0x189f, 0x189f }, +/* 0x18a0 */ { true, 0x18a0, 0x18a0 }, +/* 0x18a1 */ { true, 0x18a1, 0x18a1 }, +/* 0x18a2 */ { true, 0x18a2, 0x18a2 }, +/* 0x18a3 */ { true, 0x18a3, 0x18a3 }, +/* 0x18a4 */ { true, 0x18a4, 0x18a4 }, +/* 0x18a5 */ { true, 0x18a5, 0x18a5 }, +/* 0x18a6 */ { true, 0x18a6, 0x18a6 }, +/* 0x18a7 */ { true, 0x18a7, 0x18a7 }, +/* 0x18a8 */ { true, 0x18a8, 0x18a8 }, +/* 0x18a9 */ { true, 0x18a9, 0x18a9 }, +/* 0x18aa */ { false, 0x18aa, 0x18aa }, +/* 0x18ab */ { false, 0x18ab, 0x18ab }, +/* 0x18ac */ { false, 0x18ac, 0x18ac }, +/* 0x18ad */ { false, 0x18ad, 0x18ad }, +/* 0x18ae */ { false, 0x18ae, 0x18ae }, +/* 0x18af */ { false, 0x18af, 0x18af }, +/* 0x18b0 */ { false, 0x18b0, 0x18b0 }, +/* 0x18b1 */ { false, 0x18b1, 0x18b1 }, +/* 0x18b2 */ { false, 0x18b2, 0x18b2 }, +/* 0x18b3 */ { false, 0x18b3, 0x18b3 }, +/* 0x18b4 */ { false, 0x18b4, 0x18b4 }, +/* 0x18b5 */ { false, 0x18b5, 0x18b5 }, +/* 0x18b6 */ { false, 0x18b6, 0x18b6 }, +/* 0x18b7 */ { false, 0x18b7, 0x18b7 }, +/* 0x18b8 */ { false, 0x18b8, 0x18b8 }, +/* 0x18b9 */ { false, 0x18b9, 0x18b9 }, +/* 0x18ba */ { false, 0x18ba, 0x18ba }, +/* 0x18bb */ { false, 0x18bb, 0x18bb }, +/* 0x18bc */ { false, 0x18bc, 0x18bc }, +/* 0x18bd */ { false, 0x18bd, 0x18bd }, +/* 0x18be */ { false, 0x18be, 0x18be }, +/* 0x18bf */ { false, 0x18bf, 0x18bf }, +/* 0x18c0 */ { false, 0x18c0, 0x18c0 }, +/* 0x18c1 */ { false, 0x18c1, 0x18c1 }, +/* 0x18c2 */ { false, 0x18c2, 0x18c2 }, +/* 0x18c3 */ { false, 0x18c3, 0x18c3 }, +/* 0x18c4 */ { false, 0x18c4, 0x18c4 }, +/* 0x18c5 */ { false, 0x18c5, 0x18c5 }, +/* 0x18c6 */ { false, 0x18c6, 0x18c6 }, +/* 0x18c7 */ { false, 0x18c7, 0x18c7 }, +/* 0x18c8 */ { false, 0x18c8, 0x18c8 }, +/* 0x18c9 */ { false, 0x18c9, 0x18c9 }, +/* 0x18ca */ { false, 0x18ca, 0x18ca }, +/* 0x18cb */ { false, 0x18cb, 0x18cb }, +/* 0x18cc */ { false, 0x18cc, 0x18cc }, +/* 0x18cd */ { false, 0x18cd, 0x18cd }, +/* 0x18ce */ { false, 0x18ce, 0x18ce }, +/* 0x18cf */ { false, 0x18cf, 0x18cf }, +/* 0x18d0 */ { false, 0x18d0, 0x18d0 }, +/* 0x18d1 */ { false, 0x18d1, 0x18d1 }, +/* 0x18d2 */ { false, 0x18d2, 0x18d2 }, +/* 0x18d3 */ { false, 0x18d3, 0x18d3 }, +/* 0x18d4 */ { false, 0x18d4, 0x18d4 }, +/* 0x18d5 */ { false, 0x18d5, 0x18d5 }, +/* 0x18d6 */ { false, 0x18d6, 0x18d6 }, +/* 0x18d7 */ { false, 0x18d7, 0x18d7 }, +/* 0x18d8 */ { false, 0x18d8, 0x18d8 }, +/* 0x18d9 */ { false, 0x18d9, 0x18d9 }, +/* 0x18da */ { false, 0x18da, 0x18da }, +/* 0x18db */ { false, 0x18db, 0x18db }, +/* 0x18dc */ { false, 0x18dc, 0x18dc }, +/* 0x18dd */ { false, 0x18dd, 0x18dd }, +/* 0x18de */ { false, 0x18de, 0x18de }, +/* 0x18df */ { false, 0x18df, 0x18df }, +/* 0x18e0 */ { false, 0x18e0, 0x18e0 }, +/* 0x18e1 */ { false, 0x18e1, 0x18e1 }, +/* 0x18e2 */ { false, 0x18e2, 0x18e2 }, +/* 0x18e3 */ { false, 0x18e3, 0x18e3 }, +/* 0x18e4 */ { false, 0x18e4, 0x18e4 }, +/* 0x18e5 */ { false, 0x18e5, 0x18e5 }, +/* 0x18e6 */ { false, 0x18e6, 0x18e6 }, +/* 0x18e7 */ { false, 0x18e7, 0x18e7 }, +/* 0x18e8 */ { false, 0x18e8, 0x18e8 }, +/* 0x18e9 */ { false, 0x18e9, 0x18e9 }, +/* 0x18ea */ { false, 0x18ea, 0x18ea }, +/* 0x18eb */ { false, 0x18eb, 0x18eb }, +/* 0x18ec */ { false, 0x18ec, 0x18ec }, +/* 0x18ed */ { false, 0x18ed, 0x18ed }, +/* 0x18ee */ { false, 0x18ee, 0x18ee }, +/* 0x18ef */ { false, 0x18ef, 0x18ef }, +/* 0x18f0 */ { false, 0x18f0, 0x18f0 }, +/* 0x18f1 */ { false, 0x18f1, 0x18f1 }, +/* 0x18f2 */ { false, 0x18f2, 0x18f2 }, +/* 0x18f3 */ { false, 0x18f3, 0x18f3 }, +/* 0x18f4 */ { false, 0x18f4, 0x18f4 }, +/* 0x18f5 */ { false, 0x18f5, 0x18f5 }, +/* 0x18f6 */ { false, 0x18f6, 0x18f6 }, +/* 0x18f7 */ { false, 0x18f7, 0x18f7 }, +/* 0x18f8 */ { false, 0x18f8, 0x18f8 }, +/* 0x18f9 */ { false, 0x18f9, 0x18f9 }, +/* 0x18fa */ { false, 0x18fa, 0x18fa }, +/* 0x18fb */ { false, 0x18fb, 0x18fb }, +/* 0x18fc */ { false, 0x18fc, 0x18fc }, +/* 0x18fd */ { false, 0x18fd, 0x18fd }, +/* 0x18fe */ { false, 0x18fe, 0x18fe }, +/* 0x18ff */ { false, 0x18ff, 0x18ff }, +/* 0x1900 */ { true, 0x1900, 0x1900 }, +/* 0x1901 */ { true, 0x1901, 0x1901 }, +/* 0x1902 */ { true, 0x1902, 0x1902 }, +/* 0x1903 */ { true, 0x1903, 0x1903 }, +/* 0x1904 */ { true, 0x1904, 0x1904 }, +/* 0x1905 */ { true, 0x1905, 0x1905 }, +/* 0x1906 */ { true, 0x1906, 0x1906 }, +/* 0x1907 */ { true, 0x1907, 0x1907 }, +/* 0x1908 */ { true, 0x1908, 0x1908 }, +/* 0x1909 */ { true, 0x1909, 0x1909 }, +/* 0x190a */ { true, 0x190a, 0x190a }, +/* 0x190b */ { true, 0x190b, 0x190b }, +/* 0x190c */ { true, 0x190c, 0x190c }, +/* 0x190d */ { true, 0x190d, 0x190d }, +/* 0x190e */ { true, 0x190e, 0x190e }, +/* 0x190f */ { true, 0x190f, 0x190f }, +/* 0x1910 */ { true, 0x1910, 0x1910 }, +/* 0x1911 */ { true, 0x1911, 0x1911 }, +/* 0x1912 */ { true, 0x1912, 0x1912 }, +/* 0x1913 */ { true, 0x1913, 0x1913 }, +/* 0x1914 */ { true, 0x1914, 0x1914 }, +/* 0x1915 */ { true, 0x1915, 0x1915 }, +/* 0x1916 */ { true, 0x1916, 0x1916 }, +/* 0x1917 */ { true, 0x1917, 0x1917 }, +/* 0x1918 */ { true, 0x1918, 0x1918 }, +/* 0x1919 */ { true, 0x1919, 0x1919 }, +/* 0x191a */ { true, 0x191a, 0x191a }, +/* 0x191b */ { true, 0x191b, 0x191b }, +/* 0x191c */ { true, 0x191c, 0x191c }, +/* 0x191d */ { false, 0x191d, 0x191d }, +/* 0x191e */ { false, 0x191e, 0x191e }, +/* 0x191f */ { false, 0x191f, 0x191f }, +/* 0x1920 */ { true, 0x1920, 0x1920 }, +/* 0x1921 */ { true, 0x1921, 0x1921 }, +/* 0x1922 */ { true, 0x1922, 0x1922 }, +/* 0x1923 */ { true, 0x1923, 0x1923 }, +/* 0x1924 */ { true, 0x1924, 0x1924 }, +/* 0x1925 */ { true, 0x1925, 0x1925 }, +/* 0x1926 */ { true, 0x1926, 0x1926 }, +/* 0x1927 */ { true, 0x1927, 0x1927 }, +/* 0x1928 */ { true, 0x1928, 0x1928 }, +/* 0x1929 */ { true, 0x1929, 0x1929 }, +/* 0x192a */ { true, 0x192a, 0x192a }, +/* 0x192b */ { true, 0x192b, 0x192b }, +/* 0x192c */ { false, 0x192c, 0x192c }, +/* 0x192d */ { false, 0x192d, 0x192d }, +/* 0x192e */ { false, 0x192e, 0x192e }, +/* 0x192f */ { false, 0x192f, 0x192f }, +/* 0x1930 */ { true, 0x1930, 0x1930 }, +/* 0x1931 */ { true, 0x1931, 0x1931 }, +/* 0x1932 */ { true, 0x1932, 0x1932 }, +/* 0x1933 */ { true, 0x1933, 0x1933 }, +/* 0x1934 */ { true, 0x1934, 0x1934 }, +/* 0x1935 */ { true, 0x1935, 0x1935 }, +/* 0x1936 */ { true, 0x1936, 0x1936 }, +/* 0x1937 */ { true, 0x1937, 0x1937 }, +/* 0x1938 */ { true, 0x1938, 0x1938 }, +/* 0x1939 */ { true, 0x1939, 0x1939 }, +/* 0x193a */ { true, 0x193a, 0x193a }, +/* 0x193b */ { true, 0x193b, 0x193b }, +/* 0x193c */ { false, 0x193c, 0x193c }, +/* 0x193d */ { false, 0x193d, 0x193d }, +/* 0x193e */ { false, 0x193e, 0x193e }, +/* 0x193f */ { false, 0x193f, 0x193f }, +/* 0x1940 */ { false, 0x1940, 0x1940 }, +/* 0x1941 */ { false, 0x1941, 0x1941 }, +/* 0x1942 */ { false, 0x1942, 0x1942 }, +/* 0x1943 */ { false, 0x1943, 0x1943 }, +/* 0x1944 */ { false, 0x1944, 0x1944 }, +/* 0x1945 */ { false, 0x1945, 0x1945 }, +/* 0x1946 */ { false, 0x1946, 0x1946 }, +/* 0x1947 */ { false, 0x1947, 0x1947 }, +/* 0x1948 */ { false, 0x1948, 0x1948 }, +/* 0x1949 */ { false, 0x1949, 0x1949 }, +/* 0x194a */ { false, 0x194a, 0x194a }, +/* 0x194b */ { false, 0x194b, 0x194b }, +/* 0x194c */ { false, 0x194c, 0x194c }, +/* 0x194d */ { false, 0x194d, 0x194d }, +/* 0x194e */ { false, 0x194e, 0x194e }, +/* 0x194f */ { false, 0x194f, 0x194f }, +/* 0x1950 */ { true, 0x1950, 0x1950 }, +/* 0x1951 */ { true, 0x1951, 0x1951 }, +/* 0x1952 */ { true, 0x1952, 0x1952 }, +/* 0x1953 */ { true, 0x1953, 0x1953 }, +/* 0x1954 */ { true, 0x1954, 0x1954 }, +/* 0x1955 */ { true, 0x1955, 0x1955 }, +/* 0x1956 */ { true, 0x1956, 0x1956 }, +/* 0x1957 */ { true, 0x1957, 0x1957 }, +/* 0x1958 */ { true, 0x1958, 0x1958 }, +/* 0x1959 */ { true, 0x1959, 0x1959 }, +/* 0x195a */ { true, 0x195a, 0x195a }, +/* 0x195b */ { true, 0x195b, 0x195b }, +/* 0x195c */ { true, 0x195c, 0x195c }, +/* 0x195d */ { true, 0x195d, 0x195d }, +/* 0x195e */ { true, 0x195e, 0x195e }, +/* 0x195f */ { true, 0x195f, 0x195f }, +/* 0x1960 */ { true, 0x1960, 0x1960 }, +/* 0x1961 */ { true, 0x1961, 0x1961 }, +/* 0x1962 */ { true, 0x1962, 0x1962 }, +/* 0x1963 */ { true, 0x1963, 0x1963 }, +/* 0x1964 */ { true, 0x1964, 0x1964 }, +/* 0x1965 */ { true, 0x1965, 0x1965 }, +/* 0x1966 */ { true, 0x1966, 0x1966 }, +/* 0x1967 */ { true, 0x1967, 0x1967 }, +/* 0x1968 */ { true, 0x1968, 0x1968 }, +/* 0x1969 */ { true, 0x1969, 0x1969 }, +/* 0x196a */ { true, 0x196a, 0x196a }, +/* 0x196b */ { true, 0x196b, 0x196b }, +/* 0x196c */ { true, 0x196c, 0x196c }, +/* 0x196d */ { true, 0x196d, 0x196d }, +/* 0x196e */ { false, 0x196e, 0x196e }, +/* 0x196f */ { false, 0x196f, 0x196f }, +/* 0x1970 */ { true, 0x1970, 0x1970 }, +/* 0x1971 */ { true, 0x1971, 0x1971 }, +/* 0x1972 */ { true, 0x1972, 0x1972 }, +/* 0x1973 */ { true, 0x1973, 0x1973 }, +/* 0x1974 */ { true, 0x1974, 0x1974 }, +/* 0x1975 */ { false, 0x1975, 0x1975 }, +/* 0x1976 */ { false, 0x1976, 0x1976 }, +/* 0x1977 */ { false, 0x1977, 0x1977 }, +/* 0x1978 */ { false, 0x1978, 0x1978 }, +/* 0x1979 */ { false, 0x1979, 0x1979 }, +/* 0x197a */ { false, 0x197a, 0x197a }, +/* 0x197b */ { false, 0x197b, 0x197b }, +/* 0x197c */ { false, 0x197c, 0x197c }, +/* 0x197d */ { false, 0x197d, 0x197d }, +/* 0x197e */ { false, 0x197e, 0x197e }, +/* 0x197f */ { false, 0x197f, 0x197f }, +/* 0x1980 */ { true, 0x1980, 0x1980 }, +/* 0x1981 */ { true, 0x1981, 0x1981 }, +/* 0x1982 */ { true, 0x1982, 0x1982 }, +/* 0x1983 */ { true, 0x1983, 0x1983 }, +/* 0x1984 */ { true, 0x1984, 0x1984 }, +/* 0x1985 */ { true, 0x1985, 0x1985 }, +/* 0x1986 */ { true, 0x1986, 0x1986 }, +/* 0x1987 */ { true, 0x1987, 0x1987 }, +/* 0x1988 */ { true, 0x1988, 0x1988 }, +/* 0x1989 */ { true, 0x1989, 0x1989 }, +/* 0x198a */ { true, 0x198a, 0x198a }, +/* 0x198b */ { true, 0x198b, 0x198b }, +/* 0x198c */ { true, 0x198c, 0x198c }, +/* 0x198d */ { true, 0x198d, 0x198d }, +/* 0x198e */ { true, 0x198e, 0x198e }, +/* 0x198f */ { true, 0x198f, 0x198f }, +/* 0x1990 */ { true, 0x1990, 0x1990 }, +/* 0x1991 */ { true, 0x1991, 0x1991 }, +/* 0x1992 */ { true, 0x1992, 0x1992 }, +/* 0x1993 */ { true, 0x1993, 0x1993 }, +/* 0x1994 */ { true, 0x1994, 0x1994 }, +/* 0x1995 */ { true, 0x1995, 0x1995 }, +/* 0x1996 */ { true, 0x1996, 0x1996 }, +/* 0x1997 */ { true, 0x1997, 0x1997 }, +/* 0x1998 */ { true, 0x1998, 0x1998 }, +/* 0x1999 */ { true, 0x1999, 0x1999 }, +/* 0x199a */ { true, 0x199a, 0x199a }, +/* 0x199b */ { true, 0x199b, 0x199b }, +/* 0x199c */ { true, 0x199c, 0x199c }, +/* 0x199d */ { true, 0x199d, 0x199d }, +/* 0x199e */ { true, 0x199e, 0x199e }, +/* 0x199f */ { true, 0x199f, 0x199f }, +/* 0x19a0 */ { true, 0x19a0, 0x19a0 }, +/* 0x19a1 */ { true, 0x19a1, 0x19a1 }, +/* 0x19a2 */ { true, 0x19a2, 0x19a2 }, +/* 0x19a3 */ { true, 0x19a3, 0x19a3 }, +/* 0x19a4 */ { true, 0x19a4, 0x19a4 }, +/* 0x19a5 */ { true, 0x19a5, 0x19a5 }, +/* 0x19a6 */ { true, 0x19a6, 0x19a6 }, +/* 0x19a7 */ { true, 0x19a7, 0x19a7 }, +/* 0x19a8 */ { true, 0x19a8, 0x19a8 }, +/* 0x19a9 */ { true, 0x19a9, 0x19a9 }, +/* 0x19aa */ { false, 0x19aa, 0x19aa }, +/* 0x19ab */ { false, 0x19ab, 0x19ab }, +/* 0x19ac */ { false, 0x19ac, 0x19ac }, +/* 0x19ad */ { false, 0x19ad, 0x19ad }, +/* 0x19ae */ { false, 0x19ae, 0x19ae }, +/* 0x19af */ { false, 0x19af, 0x19af }, +/* 0x19b0 */ { false, 0x19b0, 0x19b0 }, +/* 0x19b1 */ { false, 0x19b1, 0x19b1 }, +/* 0x19b2 */ { false, 0x19b2, 0x19b2 }, +/* 0x19b3 */ { false, 0x19b3, 0x19b3 }, +/* 0x19b4 */ { false, 0x19b4, 0x19b4 }, +/* 0x19b5 */ { false, 0x19b5, 0x19b5 }, +/* 0x19b6 */ { false, 0x19b6, 0x19b6 }, +/* 0x19b7 */ { false, 0x19b7, 0x19b7 }, +/* 0x19b8 */ { false, 0x19b8, 0x19b8 }, +/* 0x19b9 */ { false, 0x19b9, 0x19b9 }, +/* 0x19ba */ { false, 0x19ba, 0x19ba }, +/* 0x19bb */ { false, 0x19bb, 0x19bb }, +/* 0x19bc */ { false, 0x19bc, 0x19bc }, +/* 0x19bd */ { false, 0x19bd, 0x19bd }, +/* 0x19be */ { false, 0x19be, 0x19be }, +/* 0x19bf */ { false, 0x19bf, 0x19bf }, +/* 0x19c0 */ { false, 0x19c0, 0x19c0 }, +/* 0x19c1 */ { true, 0x19c1, 0x19c1 }, +/* 0x19c2 */ { true, 0x19c2, 0x19c2 }, +/* 0x19c3 */ { true, 0x19c3, 0x19c3 }, +/* 0x19c4 */ { true, 0x19c4, 0x19c4 }, +/* 0x19c5 */ { true, 0x19c5, 0x19c5 }, +/* 0x19c6 */ { true, 0x19c6, 0x19c6 }, +/* 0x19c7 */ { true, 0x19c7, 0x19c7 }, +/* 0x19c8 */ { false, 0x19c8, 0x19c8 }, +/* 0x19c9 */ { false, 0x19c9, 0x19c9 }, +/* 0x19ca */ { false, 0x19ca, 0x19ca }, +/* 0x19cb */ { false, 0x19cb, 0x19cb }, +/* 0x19cc */ { false, 0x19cc, 0x19cc }, +/* 0x19cd */ { false, 0x19cd, 0x19cd }, +/* 0x19ce */ { false, 0x19ce, 0x19ce }, +/* 0x19cf */ { false, 0x19cf, 0x19cf }, +/* 0x19d0 */ { false, 0x19d0, 0x19d0 }, +/* 0x19d1 */ { false, 0x19d1, 0x19d1 }, +/* 0x19d2 */ { false, 0x19d2, 0x19d2 }, +/* 0x19d3 */ { false, 0x19d3, 0x19d3 }, +/* 0x19d4 */ { false, 0x19d4, 0x19d4 }, +/* 0x19d5 */ { false, 0x19d5, 0x19d5 }, +/* 0x19d6 */ { false, 0x19d6, 0x19d6 }, +/* 0x19d7 */ { false, 0x19d7, 0x19d7 }, +/* 0x19d8 */ { false, 0x19d8, 0x19d8 }, +/* 0x19d9 */ { false, 0x19d9, 0x19d9 }, +/* 0x19da */ { false, 0x19da, 0x19da }, +/* 0x19db */ { false, 0x19db, 0x19db }, +/* 0x19dc */ { false, 0x19dc, 0x19dc }, +/* 0x19dd */ { false, 0x19dd, 0x19dd }, +/* 0x19de */ { false, 0x19de, 0x19de }, +/* 0x19df */ { false, 0x19df, 0x19df }, +/* 0x19e0 */ { false, 0x19e0, 0x19e0 }, +/* 0x19e1 */ { false, 0x19e1, 0x19e1 }, +/* 0x19e2 */ { false, 0x19e2, 0x19e2 }, +/* 0x19e3 */ { false, 0x19e3, 0x19e3 }, +/* 0x19e4 */ { false, 0x19e4, 0x19e4 }, +/* 0x19e5 */ { false, 0x19e5, 0x19e5 }, +/* 0x19e6 */ { false, 0x19e6, 0x19e6 }, +/* 0x19e7 */ { false, 0x19e7, 0x19e7 }, +/* 0x19e8 */ { false, 0x19e8, 0x19e8 }, +/* 0x19e9 */ { false, 0x19e9, 0x19e9 }, +/* 0x19ea */ { false, 0x19ea, 0x19ea }, +/* 0x19eb */ { false, 0x19eb, 0x19eb }, +/* 0x19ec */ { false, 0x19ec, 0x19ec }, +/* 0x19ed */ { false, 0x19ed, 0x19ed }, +/* 0x19ee */ { false, 0x19ee, 0x19ee }, +/* 0x19ef */ { false, 0x19ef, 0x19ef }, +/* 0x19f0 */ { false, 0x19f0, 0x19f0 }, +/* 0x19f1 */ { false, 0x19f1, 0x19f1 }, +/* 0x19f2 */ { false, 0x19f2, 0x19f2 }, +/* 0x19f3 */ { false, 0x19f3, 0x19f3 }, +/* 0x19f4 */ { false, 0x19f4, 0x19f4 }, +/* 0x19f5 */ { false, 0x19f5, 0x19f5 }, +/* 0x19f6 */ { false, 0x19f6, 0x19f6 }, +/* 0x19f7 */ { false, 0x19f7, 0x19f7 }, +/* 0x19f8 */ { false, 0x19f8, 0x19f8 }, +/* 0x19f9 */ { false, 0x19f9, 0x19f9 }, +/* 0x19fa */ { false, 0x19fa, 0x19fa }, +/* 0x19fb */ { false, 0x19fb, 0x19fb }, +/* 0x19fc */ { false, 0x19fc, 0x19fc }, +/* 0x19fd */ { false, 0x19fd, 0x19fd }, +/* 0x19fe */ { false, 0x19fe, 0x19fe }, +/* 0x19ff */ { false, 0x19ff, 0x19ff }, +/* 0x1a00 */ { true, 0x1a00, 0x1a00 }, +/* 0x1a01 */ { true, 0x1a01, 0x1a01 }, +/* 0x1a02 */ { true, 0x1a02, 0x1a02 }, +/* 0x1a03 */ { true, 0x1a03, 0x1a03 }, +/* 0x1a04 */ { true, 0x1a04, 0x1a04 }, +/* 0x1a05 */ { true, 0x1a05, 0x1a05 }, +/* 0x1a06 */ { true, 0x1a06, 0x1a06 }, +/* 0x1a07 */ { true, 0x1a07, 0x1a07 }, +/* 0x1a08 */ { true, 0x1a08, 0x1a08 }, +/* 0x1a09 */ { true, 0x1a09, 0x1a09 }, +/* 0x1a0a */ { true, 0x1a0a, 0x1a0a }, +/* 0x1a0b */ { true, 0x1a0b, 0x1a0b }, +/* 0x1a0c */ { true, 0x1a0c, 0x1a0c }, +/* 0x1a0d */ { true, 0x1a0d, 0x1a0d }, +/* 0x1a0e */ { true, 0x1a0e, 0x1a0e }, +/* 0x1a0f */ { true, 0x1a0f, 0x1a0f }, +/* 0x1a10 */ { true, 0x1a10, 0x1a10 }, +/* 0x1a11 */ { true, 0x1a11, 0x1a11 }, +/* 0x1a12 */ { true, 0x1a12, 0x1a12 }, +/* 0x1a13 */ { true, 0x1a13, 0x1a13 }, +/* 0x1a14 */ { true, 0x1a14, 0x1a14 }, +/* 0x1a15 */ { true, 0x1a15, 0x1a15 }, +/* 0x1a16 */ { true, 0x1a16, 0x1a16 }, +/* 0x1a17 */ { true, 0x1a17, 0x1a17 }, +/* 0x1a18 */ { true, 0x1a18, 0x1a18 }, +/* 0x1a19 */ { true, 0x1a19, 0x1a19 }, +/* 0x1a1a */ { true, 0x1a1a, 0x1a1a }, +/* 0x1a1b */ { false, 0x1a1b, 0x1a1b }, +/* 0x1a1c */ { false, 0x1a1c, 0x1a1c }, +/* 0x1a1d */ { false, 0x1a1d, 0x1a1d }, +/* 0x1a1e */ { false, 0x1a1e, 0x1a1e }, +/* 0x1a1f */ { false, 0x1a1f, 0x1a1f }, +/* 0x1a20 */ { false, 0x1a20, 0x1a20 }, +/* 0x1a21 */ { false, 0x1a21, 0x1a21 }, +/* 0x1a22 */ { false, 0x1a22, 0x1a22 }, +/* 0x1a23 */ { false, 0x1a23, 0x1a23 }, +/* 0x1a24 */ { false, 0x1a24, 0x1a24 }, +/* 0x1a25 */ { false, 0x1a25, 0x1a25 }, +/* 0x1a26 */ { false, 0x1a26, 0x1a26 }, +/* 0x1a27 */ { false, 0x1a27, 0x1a27 }, +/* 0x1a28 */ { false, 0x1a28, 0x1a28 }, +/* 0x1a29 */ { false, 0x1a29, 0x1a29 }, +/* 0x1a2a */ { false, 0x1a2a, 0x1a2a }, +/* 0x1a2b */ { false, 0x1a2b, 0x1a2b }, +/* 0x1a2c */ { false, 0x1a2c, 0x1a2c }, +/* 0x1a2d */ { false, 0x1a2d, 0x1a2d }, +/* 0x1a2e */ { false, 0x1a2e, 0x1a2e }, +/* 0x1a2f */ { false, 0x1a2f, 0x1a2f }, +/* 0x1a30 */ { false, 0x1a30, 0x1a30 }, +/* 0x1a31 */ { false, 0x1a31, 0x1a31 }, +/* 0x1a32 */ { false, 0x1a32, 0x1a32 }, +/* 0x1a33 */ { false, 0x1a33, 0x1a33 }, +/* 0x1a34 */ { false, 0x1a34, 0x1a34 }, +/* 0x1a35 */ { false, 0x1a35, 0x1a35 }, +/* 0x1a36 */ { false, 0x1a36, 0x1a36 }, +/* 0x1a37 */ { false, 0x1a37, 0x1a37 }, +/* 0x1a38 */ { false, 0x1a38, 0x1a38 }, +/* 0x1a39 */ { false, 0x1a39, 0x1a39 }, +/* 0x1a3a */ { false, 0x1a3a, 0x1a3a }, +/* 0x1a3b */ { false, 0x1a3b, 0x1a3b }, +/* 0x1a3c */ { false, 0x1a3c, 0x1a3c }, +/* 0x1a3d */ { false, 0x1a3d, 0x1a3d }, +/* 0x1a3e */ { false, 0x1a3e, 0x1a3e }, +/* 0x1a3f */ { false, 0x1a3f, 0x1a3f }, +/* 0x1a40 */ { false, 0x1a40, 0x1a40 }, +/* 0x1a41 */ { false, 0x1a41, 0x1a41 }, +/* 0x1a42 */ { false, 0x1a42, 0x1a42 }, +/* 0x1a43 */ { false, 0x1a43, 0x1a43 }, +/* 0x1a44 */ { false, 0x1a44, 0x1a44 }, +/* 0x1a45 */ { false, 0x1a45, 0x1a45 }, +/* 0x1a46 */ { false, 0x1a46, 0x1a46 }, +/* 0x1a47 */ { false, 0x1a47, 0x1a47 }, +/* 0x1a48 */ { false, 0x1a48, 0x1a48 }, +/* 0x1a49 */ { false, 0x1a49, 0x1a49 }, +/* 0x1a4a */ { false, 0x1a4a, 0x1a4a }, +/* 0x1a4b */ { false, 0x1a4b, 0x1a4b }, +/* 0x1a4c */ { false, 0x1a4c, 0x1a4c }, +/* 0x1a4d */ { false, 0x1a4d, 0x1a4d }, +/* 0x1a4e */ { false, 0x1a4e, 0x1a4e }, +/* 0x1a4f */ { false, 0x1a4f, 0x1a4f }, +/* 0x1a50 */ { false, 0x1a50, 0x1a50 }, +/* 0x1a51 */ { false, 0x1a51, 0x1a51 }, +/* 0x1a52 */ { false, 0x1a52, 0x1a52 }, +/* 0x1a53 */ { false, 0x1a53, 0x1a53 }, +/* 0x1a54 */ { false, 0x1a54, 0x1a54 }, +/* 0x1a55 */ { true, 0x1a55, 0x1a55 }, +/* 0x1a56 */ { false, 0x1a56, 0x1a56 }, +/* 0x1a57 */ { true, 0x1a57, 0x1a57 }, +/* 0x1a58 */ { false, 0x1a58, 0x1a58 }, +/* 0x1a59 */ { false, 0x1a59, 0x1a59 }, +/* 0x1a5a */ { false, 0x1a5a, 0x1a5a }, +/* 0x1a5b */ { false, 0x1a5b, 0x1a5b }, +/* 0x1a5c */ { false, 0x1a5c, 0x1a5c }, +/* 0x1a5d */ { false, 0x1a5d, 0x1a5d }, +/* 0x1a5e */ { false, 0x1a5e, 0x1a5e }, +/* 0x1a5f */ { false, 0x1a5f, 0x1a5f }, +/* 0x1a60 */ { false, 0x1a60, 0x1a60 }, +/* 0x1a61 */ { true, 0x1a61, 0x1a61 }, +/* 0x1a62 */ { false, 0x1a62, 0x1a62 }, +/* 0x1a63 */ { true, 0x1a63, 0x1a63 }, +/* 0x1a64 */ { true, 0x1a64, 0x1a64 }, +/* 0x1a65 */ { false, 0x1a65, 0x1a65 }, +/* 0x1a66 */ { false, 0x1a66, 0x1a66 }, +/* 0x1a67 */ { false, 0x1a67, 0x1a67 }, +/* 0x1a68 */ { false, 0x1a68, 0x1a68 }, +/* 0x1a69 */ { false, 0x1a69, 0x1a69 }, +/* 0x1a6a */ { false, 0x1a6a, 0x1a6a }, +/* 0x1a6b */ { false, 0x1a6b, 0x1a6b }, +/* 0x1a6c */ { false, 0x1a6c, 0x1a6c }, +/* 0x1a6d */ { true, 0x1a6d, 0x1a6d }, +/* 0x1a6e */ { true, 0x1a6e, 0x1a6e }, +/* 0x1a6f */ { true, 0x1a6f, 0x1a6f }, +/* 0x1a70 */ { true, 0x1a70, 0x1a70 }, +/* 0x1a71 */ { true, 0x1a71, 0x1a71 }, +/* 0x1a72 */ { true, 0x1a72, 0x1a72 }, +/* 0x1a73 */ { false, 0x1a73, 0x1a73 }, +/* 0x1a74 */ { false, 0x1a74, 0x1a74 }, +/* 0x1a75 */ { false, 0x1a75, 0x1a75 }, +/* 0x1a76 */ { false, 0x1a76, 0x1a76 }, +/* 0x1a77 */ { false, 0x1a77, 0x1a77 }, +/* 0x1a78 */ { false, 0x1a78, 0x1a78 }, +/* 0x1a79 */ { false, 0x1a79, 0x1a79 }, +/* 0x1a7a */ { false, 0x1a7a, 0x1a7a }, +/* 0x1a7b */ { false, 0x1a7b, 0x1a7b }, +/* 0x1a7c */ { false, 0x1a7c, 0x1a7c }, +/* 0x1a7d */ { false, 0x1a7d, 0x1a7d }, +/* 0x1a7e */ { false, 0x1a7e, 0x1a7e }, +/* 0x1a7f */ { false, 0x1a7f, 0x1a7f }, +/* 0x1a80 */ { false, 0x1a80, 0x1a80 }, +/* 0x1a81 */ { false, 0x1a81, 0x1a81 }, +/* 0x1a82 */ { false, 0x1a82, 0x1a82 }, +/* 0x1a83 */ { false, 0x1a83, 0x1a83 }, +/* 0x1a84 */ { false, 0x1a84, 0x1a84 }, +/* 0x1a85 */ { false, 0x1a85, 0x1a85 }, +/* 0x1a86 */ { false, 0x1a86, 0x1a86 }, +/* 0x1a87 */ { false, 0x1a87, 0x1a87 }, +/* 0x1a88 */ { false, 0x1a88, 0x1a88 }, +/* 0x1a89 */ { false, 0x1a89, 0x1a89 }, +/* 0x1a8a */ { false, 0x1a8a, 0x1a8a }, +/* 0x1a8b */ { false, 0x1a8b, 0x1a8b }, +/* 0x1a8c */ { false, 0x1a8c, 0x1a8c }, +/* 0x1a8d */ { false, 0x1a8d, 0x1a8d }, +/* 0x1a8e */ { false, 0x1a8e, 0x1a8e }, +/* 0x1a8f */ { false, 0x1a8f, 0x1a8f }, +/* 0x1a90 */ { false, 0x1a90, 0x1a90 }, +/* 0x1a91 */ { false, 0x1a91, 0x1a91 }, +/* 0x1a92 */ { false, 0x1a92, 0x1a92 }, +/* 0x1a93 */ { false, 0x1a93, 0x1a93 }, +/* 0x1a94 */ { false, 0x1a94, 0x1a94 }, +/* 0x1a95 */ { false, 0x1a95, 0x1a95 }, +/* 0x1a96 */ { false, 0x1a96, 0x1a96 }, +/* 0x1a97 */ { false, 0x1a97, 0x1a97 }, +/* 0x1a98 */ { false, 0x1a98, 0x1a98 }, +/* 0x1a99 */ { false, 0x1a99, 0x1a99 }, +/* 0x1a9a */ { false, 0x1a9a, 0x1a9a }, +/* 0x1a9b */ { false, 0x1a9b, 0x1a9b }, +/* 0x1a9c */ { false, 0x1a9c, 0x1a9c }, +/* 0x1a9d */ { false, 0x1a9d, 0x1a9d }, +/* 0x1a9e */ { false, 0x1a9e, 0x1a9e }, +/* 0x1a9f */ { false, 0x1a9f, 0x1a9f }, +/* 0x1aa0 */ { false, 0x1aa0, 0x1aa0 }, +/* 0x1aa1 */ { false, 0x1aa1, 0x1aa1 }, +/* 0x1aa2 */ { false, 0x1aa2, 0x1aa2 }, +/* 0x1aa3 */ { false, 0x1aa3, 0x1aa3 }, +/* 0x1aa4 */ { false, 0x1aa4, 0x1aa4 }, +/* 0x1aa5 */ { false, 0x1aa5, 0x1aa5 }, +/* 0x1aa6 */ { false, 0x1aa6, 0x1aa6 }, +/* 0x1aa7 */ { false, 0x1aa7, 0x1aa7 }, +/* 0x1aa8 */ { false, 0x1aa8, 0x1aa8 }, +/* 0x1aa9 */ { false, 0x1aa9, 0x1aa9 }, +/* 0x1aaa */ { false, 0x1aaa, 0x1aaa }, +/* 0x1aab */ { false, 0x1aab, 0x1aab }, +/* 0x1aac */ { false, 0x1aac, 0x1aac }, +/* 0x1aad */ { false, 0x1aad, 0x1aad }, +/* 0x1aae */ { false, 0x1aae, 0x1aae }, +/* 0x1aaf */ { false, 0x1aaf, 0x1aaf }, +/* 0x1ab0 */ { false, 0x1ab0, 0x1ab0 }, +/* 0x1ab1 */ { false, 0x1ab1, 0x1ab1 }, +/* 0x1ab2 */ { false, 0x1ab2, 0x1ab2 }, +/* 0x1ab3 */ { false, 0x1ab3, 0x1ab3 }, +/* 0x1ab4 */ { false, 0x1ab4, 0x1ab4 }, +/* 0x1ab5 */ { false, 0x1ab5, 0x1ab5 }, +/* 0x1ab6 */ { false, 0x1ab6, 0x1ab6 }, +/* 0x1ab7 */ { false, 0x1ab7, 0x1ab7 }, +/* 0x1ab8 */ { false, 0x1ab8, 0x1ab8 }, +/* 0x1ab9 */ { false, 0x1ab9, 0x1ab9 }, +/* 0x1aba */ { false, 0x1aba, 0x1aba }, +/* 0x1abb */ { false, 0x1abb, 0x1abb }, +/* 0x1abc */ { false, 0x1abc, 0x1abc }, +/* 0x1abd */ { false, 0x1abd, 0x1abd }, +/* 0x1abe */ { false, 0x1abe, 0x1abe }, +/* 0x1abf */ { false, 0x1abf, 0x1abf }, +/* 0x1ac0 */ { false, 0x1ac0, 0x1ac0 }, +/* 0x1ac1 */ { false, 0x1ac1, 0x1ac1 }, +/* 0x1ac2 */ { false, 0x1ac2, 0x1ac2 }, +/* 0x1ac3 */ { false, 0x1ac3, 0x1ac3 }, +/* 0x1ac4 */ { false, 0x1ac4, 0x1ac4 }, +/* 0x1ac5 */ { false, 0x1ac5, 0x1ac5 }, +/* 0x1ac6 */ { false, 0x1ac6, 0x1ac6 }, +/* 0x1ac7 */ { false, 0x1ac7, 0x1ac7 }, +/* 0x1ac8 */ { false, 0x1ac8, 0x1ac8 }, +/* 0x1ac9 */ { false, 0x1ac9, 0x1ac9 }, +/* 0x1aca */ { false, 0x1aca, 0x1aca }, +/* 0x1acb */ { false, 0x1acb, 0x1acb }, +/* 0x1acc */ { false, 0x1acc, 0x1acc }, +/* 0x1acd */ { false, 0x1acd, 0x1acd }, +/* 0x1ace */ { false, 0x1ace, 0x1ace }, +/* 0x1acf */ { false, 0x1acf, 0x1acf }, +/* 0x1ad0 */ { false, 0x1ad0, 0x1ad0 }, +/* 0x1ad1 */ { false, 0x1ad1, 0x1ad1 }, +/* 0x1ad2 */ { false, 0x1ad2, 0x1ad2 }, +/* 0x1ad3 */ { false, 0x1ad3, 0x1ad3 }, +/* 0x1ad4 */ { false, 0x1ad4, 0x1ad4 }, +/* 0x1ad5 */ { false, 0x1ad5, 0x1ad5 }, +/* 0x1ad6 */ { false, 0x1ad6, 0x1ad6 }, +/* 0x1ad7 */ { false, 0x1ad7, 0x1ad7 }, +/* 0x1ad8 */ { false, 0x1ad8, 0x1ad8 }, +/* 0x1ad9 */ { false, 0x1ad9, 0x1ad9 }, +/* 0x1ada */ { false, 0x1ada, 0x1ada }, +/* 0x1adb */ { false, 0x1adb, 0x1adb }, +/* 0x1adc */ { false, 0x1adc, 0x1adc }, +/* 0x1add */ { false, 0x1add, 0x1add }, +/* 0x1ade */ { false, 0x1ade, 0x1ade }, +/* 0x1adf */ { false, 0x1adf, 0x1adf }, +/* 0x1ae0 */ { false, 0x1ae0, 0x1ae0 }, +/* 0x1ae1 */ { false, 0x1ae1, 0x1ae1 }, +/* 0x1ae2 */ { false, 0x1ae2, 0x1ae2 }, +/* 0x1ae3 */ { false, 0x1ae3, 0x1ae3 }, +/* 0x1ae4 */ { false, 0x1ae4, 0x1ae4 }, +/* 0x1ae5 */ { false, 0x1ae5, 0x1ae5 }, +/* 0x1ae6 */ { false, 0x1ae6, 0x1ae6 }, +/* 0x1ae7 */ { false, 0x1ae7, 0x1ae7 }, +/* 0x1ae8 */ { false, 0x1ae8, 0x1ae8 }, +/* 0x1ae9 */ { false, 0x1ae9, 0x1ae9 }, +/* 0x1aea */ { false, 0x1aea, 0x1aea }, +/* 0x1aeb */ { false, 0x1aeb, 0x1aeb }, +/* 0x1aec */ { false, 0x1aec, 0x1aec }, +/* 0x1aed */ { false, 0x1aed, 0x1aed }, +/* 0x1aee */ { false, 0x1aee, 0x1aee }, +/* 0x1aef */ { false, 0x1aef, 0x1aef }, +/* 0x1af0 */ { false, 0x1af0, 0x1af0 }, +/* 0x1af1 */ { false, 0x1af1, 0x1af1 }, +/* 0x1af2 */ { false, 0x1af2, 0x1af2 }, +/* 0x1af3 */ { false, 0x1af3, 0x1af3 }, +/* 0x1af4 */ { false, 0x1af4, 0x1af4 }, +/* 0x1af5 */ { false, 0x1af5, 0x1af5 }, +/* 0x1af6 */ { false, 0x1af6, 0x1af6 }, +/* 0x1af7 */ { false, 0x1af7, 0x1af7 }, +/* 0x1af8 */ { false, 0x1af8, 0x1af8 }, +/* 0x1af9 */ { false, 0x1af9, 0x1af9 }, +/* 0x1afa */ { false, 0x1afa, 0x1afa }, +/* 0x1afb */ { false, 0x1afb, 0x1afb }, +/* 0x1afc */ { false, 0x1afc, 0x1afc }, +/* 0x1afd */ { false, 0x1afd, 0x1afd }, +/* 0x1afe */ { false, 0x1afe, 0x1afe }, +/* 0x1aff */ { false, 0x1aff, 0x1aff }, +/* 0x1b00 */ { false, 0x1b00, 0x1b00 }, +/* 0x1b01 */ { false, 0x1b01, 0x1b01 }, +/* 0x1b02 */ { false, 0x1b02, 0x1b02 }, +/* 0x1b03 */ { false, 0x1b03, 0x1b03 }, +/* 0x1b04 */ { true, 0x1b04, 0x1b04 }, +/* 0x1b05 */ { false, 0x1b05, 0x1b05 }, +/* 0x1b06 */ { false, 0x1b06, 0x1b06 }, +/* 0x1b07 */ { false, 0x1b07, 0x1b07 }, +/* 0x1b08 */ { false, 0x1b08, 0x1b08 }, +/* 0x1b09 */ { false, 0x1b09, 0x1b09 }, +/* 0x1b0a */ { false, 0x1b0a, 0x1b0a }, +/* 0x1b0b */ { false, 0x1b0b, 0x1b0b }, +/* 0x1b0c */ { false, 0x1b0c, 0x1b0c }, +/* 0x1b0d */ { false, 0x1b0d, 0x1b0d }, +/* 0x1b0e */ { false, 0x1b0e, 0x1b0e }, +/* 0x1b0f */ { false, 0x1b0f, 0x1b0f }, +/* 0x1b10 */ { false, 0x1b10, 0x1b10 }, +/* 0x1b11 */ { false, 0x1b11, 0x1b11 }, +/* 0x1b12 */ { false, 0x1b12, 0x1b12 }, +/* 0x1b13 */ { false, 0x1b13, 0x1b13 }, +/* 0x1b14 */ { false, 0x1b14, 0x1b14 }, +/* 0x1b15 */ { false, 0x1b15, 0x1b15 }, +/* 0x1b16 */ { false, 0x1b16, 0x1b16 }, +/* 0x1b17 */ { false, 0x1b17, 0x1b17 }, +/* 0x1b18 */ { false, 0x1b18, 0x1b18 }, +/* 0x1b19 */ { false, 0x1b19, 0x1b19 }, +/* 0x1b1a */ { false, 0x1b1a, 0x1b1a }, +/* 0x1b1b */ { false, 0x1b1b, 0x1b1b }, +/* 0x1b1c */ { false, 0x1b1c, 0x1b1c }, +/* 0x1b1d */ { false, 0x1b1d, 0x1b1d }, +/* 0x1b1e */ { false, 0x1b1e, 0x1b1e }, +/* 0x1b1f */ { false, 0x1b1f, 0x1b1f }, +/* 0x1b20 */ { false, 0x1b20, 0x1b20 }, +/* 0x1b21 */ { false, 0x1b21, 0x1b21 }, +/* 0x1b22 */ { false, 0x1b22, 0x1b22 }, +/* 0x1b23 */ { false, 0x1b23, 0x1b23 }, +/* 0x1b24 */ { false, 0x1b24, 0x1b24 }, +/* 0x1b25 */ { false, 0x1b25, 0x1b25 }, +/* 0x1b26 */ { false, 0x1b26, 0x1b26 }, +/* 0x1b27 */ { false, 0x1b27, 0x1b27 }, +/* 0x1b28 */ { false, 0x1b28, 0x1b28 }, +/* 0x1b29 */ { false, 0x1b29, 0x1b29 }, +/* 0x1b2a */ { false, 0x1b2a, 0x1b2a }, +/* 0x1b2b */ { false, 0x1b2b, 0x1b2b }, +/* 0x1b2c */ { false, 0x1b2c, 0x1b2c }, +/* 0x1b2d */ { false, 0x1b2d, 0x1b2d }, +/* 0x1b2e */ { false, 0x1b2e, 0x1b2e }, +/* 0x1b2f */ { false, 0x1b2f, 0x1b2f }, +/* 0x1b30 */ { false, 0x1b30, 0x1b30 }, +/* 0x1b31 */ { false, 0x1b31, 0x1b31 }, +/* 0x1b32 */ { false, 0x1b32, 0x1b32 }, +/* 0x1b33 */ { false, 0x1b33, 0x1b33 }, +/* 0x1b34 */ { false, 0x1b34, 0x1b34 }, +/* 0x1b35 */ { true, 0x1b35, 0x1b35 }, +/* 0x1b36 */ { false, 0x1b36, 0x1b36 }, +/* 0x1b37 */ { false, 0x1b37, 0x1b37 }, +/* 0x1b38 */ { false, 0x1b38, 0x1b38 }, +/* 0x1b39 */ { false, 0x1b39, 0x1b39 }, +/* 0x1b3a */ { false, 0x1b3a, 0x1b3a }, +/* 0x1b3b */ { true, 0x1b3b, 0x1b3b }, +/* 0x1b3c */ { false, 0x1b3c, 0x1b3c }, +/* 0x1b3d */ { true, 0x1b3d, 0x1b3d }, +/* 0x1b3e */ { true, 0x1b3e, 0x1b3e }, +/* 0x1b3f */ { true, 0x1b3f, 0x1b3f }, +/* 0x1b40 */ { true, 0x1b40, 0x1b40 }, +/* 0x1b41 */ { true, 0x1b41, 0x1b41 }, +/* 0x1b42 */ { false, 0x1b42, 0x1b42 }, +/* 0x1b43 */ { true, 0x1b43, 0x1b43 }, +/* 0x1b44 */ { true, 0x1b44, 0x1b44 }, +/* 0x1b45 */ { false, 0x1b45, 0x1b45 }, +/* 0x1b46 */ { false, 0x1b46, 0x1b46 }, +/* 0x1b47 */ { false, 0x1b47, 0x1b47 }, +/* 0x1b48 */ { false, 0x1b48, 0x1b48 }, +/* 0x1b49 */ { false, 0x1b49, 0x1b49 }, +/* 0x1b4a */ { false, 0x1b4a, 0x1b4a }, +/* 0x1b4b */ { false, 0x1b4b, 0x1b4b }, +/* 0x1b4c */ { false, 0x1b4c, 0x1b4c }, +/* 0x1b4d */ { false, 0x1b4d, 0x1b4d }, +/* 0x1b4e */ { false, 0x1b4e, 0x1b4e }, +/* 0x1b4f */ { false, 0x1b4f, 0x1b4f }, +/* 0x1b50 */ { false, 0x1b50, 0x1b50 }, +/* 0x1b51 */ { false, 0x1b51, 0x1b51 }, +/* 0x1b52 */ { false, 0x1b52, 0x1b52 }, +/* 0x1b53 */ { false, 0x1b53, 0x1b53 }, +/* 0x1b54 */ { false, 0x1b54, 0x1b54 }, +/* 0x1b55 */ { false, 0x1b55, 0x1b55 }, +/* 0x1b56 */ { false, 0x1b56, 0x1b56 }, +/* 0x1b57 */ { false, 0x1b57, 0x1b57 }, +/* 0x1b58 */ { false, 0x1b58, 0x1b58 }, +/* 0x1b59 */ { false, 0x1b59, 0x1b59 }, +/* 0x1b5a */ { false, 0x1b5a, 0x1b5a }, +/* 0x1b5b */ { false, 0x1b5b, 0x1b5b }, +/* 0x1b5c */ { false, 0x1b5c, 0x1b5c }, +/* 0x1b5d */ { false, 0x1b5d, 0x1b5d }, +/* 0x1b5e */ { false, 0x1b5e, 0x1b5e }, +/* 0x1b5f */ { false, 0x1b5f, 0x1b5f }, +/* 0x1b60 */ { false, 0x1b60, 0x1b60 }, +/* 0x1b61 */ { false, 0x1b61, 0x1b61 }, +/* 0x1b62 */ { false, 0x1b62, 0x1b62 }, +/* 0x1b63 */ { false, 0x1b63, 0x1b63 }, +/* 0x1b64 */ { false, 0x1b64, 0x1b64 }, +/* 0x1b65 */ { false, 0x1b65, 0x1b65 }, +/* 0x1b66 */ { false, 0x1b66, 0x1b66 }, +/* 0x1b67 */ { false, 0x1b67, 0x1b67 }, +/* 0x1b68 */ { false, 0x1b68, 0x1b68 }, +/* 0x1b69 */ { false, 0x1b69, 0x1b69 }, +/* 0x1b6a */ { false, 0x1b6a, 0x1b6a }, +/* 0x1b6b */ { false, 0x1b6b, 0x1b6b }, +/* 0x1b6c */ { false, 0x1b6c, 0x1b6c }, +/* 0x1b6d */ { false, 0x1b6d, 0x1b6d }, +/* 0x1b6e */ { false, 0x1b6e, 0x1b6e }, +/* 0x1b6f */ { false, 0x1b6f, 0x1b6f }, +/* 0x1b70 */ { false, 0x1b70, 0x1b70 }, +/* 0x1b71 */ { false, 0x1b71, 0x1b71 }, +/* 0x1b72 */ { false, 0x1b72, 0x1b72 }, +/* 0x1b73 */ { false, 0x1b73, 0x1b73 }, +/* 0x1b74 */ { false, 0x1b74, 0x1b74 }, +/* 0x1b75 */ { false, 0x1b75, 0x1b75 }, +/* 0x1b76 */ { false, 0x1b76, 0x1b76 }, +/* 0x1b77 */ { false, 0x1b77, 0x1b77 }, +/* 0x1b78 */ { false, 0x1b78, 0x1b78 }, +/* 0x1b79 */ { false, 0x1b79, 0x1b79 }, +/* 0x1b7a */ { false, 0x1b7a, 0x1b7a }, +/* 0x1b7b */ { false, 0x1b7b, 0x1b7b }, +/* 0x1b7c */ { false, 0x1b7c, 0x1b7c }, +/* 0x1b7d */ { false, 0x1b7d, 0x1b7d }, +/* 0x1b7e */ { false, 0x1b7e, 0x1b7e }, +/* 0x1b7f */ { false, 0x1b7f, 0x1b7f }, +/* 0x1b80 */ { false, 0x1b80, 0x1b80 }, +/* 0x1b81 */ { false, 0x1b81, 0x1b81 }, +/* 0x1b82 */ { true, 0x1b82, 0x1b82 }, +/* 0x1b83 */ { false, 0x1b83, 0x1b83 }, +/* 0x1b84 */ { false, 0x1b84, 0x1b84 }, +/* 0x1b85 */ { false, 0x1b85, 0x1b85 }, +/* 0x1b86 */ { false, 0x1b86, 0x1b86 }, +/* 0x1b87 */ { false, 0x1b87, 0x1b87 }, +/* 0x1b88 */ { false, 0x1b88, 0x1b88 }, +/* 0x1b89 */ { false, 0x1b89, 0x1b89 }, +/* 0x1b8a */ { false, 0x1b8a, 0x1b8a }, +/* 0x1b8b */ { false, 0x1b8b, 0x1b8b }, +/* 0x1b8c */ { false, 0x1b8c, 0x1b8c }, +/* 0x1b8d */ { false, 0x1b8d, 0x1b8d }, +/* 0x1b8e */ { false, 0x1b8e, 0x1b8e }, +/* 0x1b8f */ { false, 0x1b8f, 0x1b8f }, +/* 0x1b90 */ { false, 0x1b90, 0x1b90 }, +/* 0x1b91 */ { false, 0x1b91, 0x1b91 }, +/* 0x1b92 */ { false, 0x1b92, 0x1b92 }, +/* 0x1b93 */ { false, 0x1b93, 0x1b93 }, +/* 0x1b94 */ { false, 0x1b94, 0x1b94 }, +/* 0x1b95 */ { false, 0x1b95, 0x1b95 }, +/* 0x1b96 */ { false, 0x1b96, 0x1b96 }, +/* 0x1b97 */ { false, 0x1b97, 0x1b97 }, +/* 0x1b98 */ { false, 0x1b98, 0x1b98 }, +/* 0x1b99 */ { false, 0x1b99, 0x1b99 }, +/* 0x1b9a */ { false, 0x1b9a, 0x1b9a }, +/* 0x1b9b */ { false, 0x1b9b, 0x1b9b }, +/* 0x1b9c */ { false, 0x1b9c, 0x1b9c }, +/* 0x1b9d */ { false, 0x1b9d, 0x1b9d }, +/* 0x1b9e */ { false, 0x1b9e, 0x1b9e }, +/* 0x1b9f */ { false, 0x1b9f, 0x1b9f }, +/* 0x1ba0 */ { false, 0x1ba0, 0x1ba0 }, +/* 0x1ba1 */ { true, 0x1ba1, 0x1ba1 }, +/* 0x1ba2 */ { false, 0x1ba2, 0x1ba2 }, +/* 0x1ba3 */ { false, 0x1ba3, 0x1ba3 }, +/* 0x1ba4 */ { false, 0x1ba4, 0x1ba4 }, +/* 0x1ba5 */ { false, 0x1ba5, 0x1ba5 }, +/* 0x1ba6 */ { true, 0x1ba6, 0x1ba6 }, +/* 0x1ba7 */ { true, 0x1ba7, 0x1ba7 }, +/* 0x1ba8 */ { false, 0x1ba8, 0x1ba8 }, +/* 0x1ba9 */ { false, 0x1ba9, 0x1ba9 }, +/* 0x1baa */ { true, 0x1baa, 0x1baa }, +/* 0x1bab */ { false, 0x1bab, 0x1bab }, +/* 0x1bac */ { false, 0x1bac, 0x1bac }, +/* 0x1bad */ { false, 0x1bad, 0x1bad }, +/* 0x1bae */ { false, 0x1bae, 0x1bae }, +/* 0x1baf */ { false, 0x1baf, 0x1baf }, +/* 0x1bb0 */ { false, 0x1bb0, 0x1bb0 }, +/* 0x1bb1 */ { false, 0x1bb1, 0x1bb1 }, +/* 0x1bb2 */ { false, 0x1bb2, 0x1bb2 }, +/* 0x1bb3 */ { false, 0x1bb3, 0x1bb3 }, +/* 0x1bb4 */ { false, 0x1bb4, 0x1bb4 }, +/* 0x1bb5 */ { false, 0x1bb5, 0x1bb5 }, +/* 0x1bb6 */ { false, 0x1bb6, 0x1bb6 }, +/* 0x1bb7 */ { false, 0x1bb7, 0x1bb7 }, +/* 0x1bb8 */ { false, 0x1bb8, 0x1bb8 }, +/* 0x1bb9 */ { false, 0x1bb9, 0x1bb9 }, +/* 0x1bba */ { false, 0x1bba, 0x1bba }, +/* 0x1bbb */ { false, 0x1bbb, 0x1bbb }, +/* 0x1bbc */ { false, 0x1bbc, 0x1bbc }, +/* 0x1bbd */ { false, 0x1bbd, 0x1bbd }, +/* 0x1bbe */ { false, 0x1bbe, 0x1bbe }, +/* 0x1bbf */ { false, 0x1bbf, 0x1bbf }, +/* 0x1bc0 */ { false, 0x1bc0, 0x1bc0 }, +/* 0x1bc1 */ { false, 0x1bc1, 0x1bc1 }, +/* 0x1bc2 */ { false, 0x1bc2, 0x1bc2 }, +/* 0x1bc3 */ { false, 0x1bc3, 0x1bc3 }, +/* 0x1bc4 */ { false, 0x1bc4, 0x1bc4 }, +/* 0x1bc5 */ { false, 0x1bc5, 0x1bc5 }, +/* 0x1bc6 */ { false, 0x1bc6, 0x1bc6 }, +/* 0x1bc7 */ { false, 0x1bc7, 0x1bc7 }, +/* 0x1bc8 */ { false, 0x1bc8, 0x1bc8 }, +/* 0x1bc9 */ { false, 0x1bc9, 0x1bc9 }, +/* 0x1bca */ { false, 0x1bca, 0x1bca }, +/* 0x1bcb */ { false, 0x1bcb, 0x1bcb }, +/* 0x1bcc */ { false, 0x1bcc, 0x1bcc }, +/* 0x1bcd */ { false, 0x1bcd, 0x1bcd }, +/* 0x1bce */ { false, 0x1bce, 0x1bce }, +/* 0x1bcf */ { false, 0x1bcf, 0x1bcf }, +/* 0x1bd0 */ { false, 0x1bd0, 0x1bd0 }, +/* 0x1bd1 */ { false, 0x1bd1, 0x1bd1 }, +/* 0x1bd2 */ { false, 0x1bd2, 0x1bd2 }, +/* 0x1bd3 */ { false, 0x1bd3, 0x1bd3 }, +/* 0x1bd4 */ { false, 0x1bd4, 0x1bd4 }, +/* 0x1bd5 */ { false, 0x1bd5, 0x1bd5 }, +/* 0x1bd6 */ { false, 0x1bd6, 0x1bd6 }, +/* 0x1bd7 */ { false, 0x1bd7, 0x1bd7 }, +/* 0x1bd8 */ { false, 0x1bd8, 0x1bd8 }, +/* 0x1bd9 */ { false, 0x1bd9, 0x1bd9 }, +/* 0x1bda */ { false, 0x1bda, 0x1bda }, +/* 0x1bdb */ { false, 0x1bdb, 0x1bdb }, +/* 0x1bdc */ { false, 0x1bdc, 0x1bdc }, +/* 0x1bdd */ { false, 0x1bdd, 0x1bdd }, +/* 0x1bde */ { false, 0x1bde, 0x1bde }, +/* 0x1bdf */ { false, 0x1bdf, 0x1bdf }, +/* 0x1be0 */ { false, 0x1be0, 0x1be0 }, +/* 0x1be1 */ { false, 0x1be1, 0x1be1 }, +/* 0x1be2 */ { false, 0x1be2, 0x1be2 }, +/* 0x1be3 */ { false, 0x1be3, 0x1be3 }, +/* 0x1be4 */ { false, 0x1be4, 0x1be4 }, +/* 0x1be5 */ { false, 0x1be5, 0x1be5 }, +/* 0x1be6 */ { false, 0x1be6, 0x1be6 }, +/* 0x1be7 */ { true, 0x1be7, 0x1be7 }, +/* 0x1be8 */ { false, 0x1be8, 0x1be8 }, +/* 0x1be9 */ { false, 0x1be9, 0x1be9 }, +/* 0x1bea */ { true, 0x1bea, 0x1bea }, +/* 0x1beb */ { true, 0x1beb, 0x1beb }, +/* 0x1bec */ { true, 0x1bec, 0x1bec }, +/* 0x1bed */ { false, 0x1bed, 0x1bed }, +/* 0x1bee */ { true, 0x1bee, 0x1bee }, +/* 0x1bef */ { false, 0x1bef, 0x1bef }, +/* 0x1bf0 */ { false, 0x1bf0, 0x1bf0 }, +/* 0x1bf1 */ { false, 0x1bf1, 0x1bf1 }, +/* 0x1bf2 */ { true, 0x1bf2, 0x1bf2 }, +/* 0x1bf3 */ { true, 0x1bf3, 0x1bf3 }, +/* 0x1bf4 */ { false, 0x1bf4, 0x1bf4 }, +/* 0x1bf5 */ { false, 0x1bf5, 0x1bf5 }, +/* 0x1bf6 */ { false, 0x1bf6, 0x1bf6 }, +/* 0x1bf7 */ { false, 0x1bf7, 0x1bf7 }, +/* 0x1bf8 */ { false, 0x1bf8, 0x1bf8 }, +/* 0x1bf9 */ { false, 0x1bf9, 0x1bf9 }, +/* 0x1bfa */ { false, 0x1bfa, 0x1bfa }, +/* 0x1bfb */ { false, 0x1bfb, 0x1bfb }, +/* 0x1bfc */ { false, 0x1bfc, 0x1bfc }, +/* 0x1bfd */ { false, 0x1bfd, 0x1bfd }, +/* 0x1bfe */ { false, 0x1bfe, 0x1bfe }, +/* 0x1bff */ { false, 0x1bff, 0x1bff }, +/* 0x1c00 */ { false, 0x1c00, 0x1c00 }, +/* 0x1c01 */ { false, 0x1c01, 0x1c01 }, +/* 0x1c02 */ { false, 0x1c02, 0x1c02 }, +/* 0x1c03 */ { false, 0x1c03, 0x1c03 }, +/* 0x1c04 */ { false, 0x1c04, 0x1c04 }, +/* 0x1c05 */ { false, 0x1c05, 0x1c05 }, +/* 0x1c06 */ { false, 0x1c06, 0x1c06 }, +/* 0x1c07 */ { false, 0x1c07, 0x1c07 }, +/* 0x1c08 */ { false, 0x1c08, 0x1c08 }, +/* 0x1c09 */ { false, 0x1c09, 0x1c09 }, +/* 0x1c0a */ { false, 0x1c0a, 0x1c0a }, +/* 0x1c0b */ { false, 0x1c0b, 0x1c0b }, +/* 0x1c0c */ { false, 0x1c0c, 0x1c0c }, +/* 0x1c0d */ { false, 0x1c0d, 0x1c0d }, +/* 0x1c0e */ { false, 0x1c0e, 0x1c0e }, +/* 0x1c0f */ { false, 0x1c0f, 0x1c0f }, +/* 0x1c10 */ { false, 0x1c10, 0x1c10 }, +/* 0x1c11 */ { false, 0x1c11, 0x1c11 }, +/* 0x1c12 */ { false, 0x1c12, 0x1c12 }, +/* 0x1c13 */ { false, 0x1c13, 0x1c13 }, +/* 0x1c14 */ { false, 0x1c14, 0x1c14 }, +/* 0x1c15 */ { false, 0x1c15, 0x1c15 }, +/* 0x1c16 */ { false, 0x1c16, 0x1c16 }, +/* 0x1c17 */ { false, 0x1c17, 0x1c17 }, +/* 0x1c18 */ { false, 0x1c18, 0x1c18 }, +/* 0x1c19 */ { false, 0x1c19, 0x1c19 }, +/* 0x1c1a */ { false, 0x1c1a, 0x1c1a }, +/* 0x1c1b */ { false, 0x1c1b, 0x1c1b }, +/* 0x1c1c */ { false, 0x1c1c, 0x1c1c }, +/* 0x1c1d */ { false, 0x1c1d, 0x1c1d }, +/* 0x1c1e */ { false, 0x1c1e, 0x1c1e }, +/* 0x1c1f */ { false, 0x1c1f, 0x1c1f }, +/* 0x1c20 */ { false, 0x1c20, 0x1c20 }, +/* 0x1c21 */ { false, 0x1c21, 0x1c21 }, +/* 0x1c22 */ { false, 0x1c22, 0x1c22 }, +/* 0x1c23 */ { false, 0x1c23, 0x1c23 }, +/* 0x1c24 */ { true, 0x1c24, 0x1c24 }, +/* 0x1c25 */ { true, 0x1c25, 0x1c25 }, +/* 0x1c26 */ { true, 0x1c26, 0x1c26 }, +/* 0x1c27 */ { true, 0x1c27, 0x1c27 }, +/* 0x1c28 */ { true, 0x1c28, 0x1c28 }, +/* 0x1c29 */ { true, 0x1c29, 0x1c29 }, +/* 0x1c2a */ { true, 0x1c2a, 0x1c2a }, +/* 0x1c2b */ { true, 0x1c2b, 0x1c2b }, +/* 0x1c2c */ { false, 0x1c2c, 0x1c2c }, +/* 0x1c2d */ { false, 0x1c2d, 0x1c2d }, +/* 0x1c2e */ { false, 0x1c2e, 0x1c2e }, +/* 0x1c2f */ { false, 0x1c2f, 0x1c2f }, +/* 0x1c30 */ { false, 0x1c30, 0x1c30 }, +/* 0x1c31 */ { false, 0x1c31, 0x1c31 }, +/* 0x1c32 */ { false, 0x1c32, 0x1c32 }, +/* 0x1c33 */ { false, 0x1c33, 0x1c33 }, +/* 0x1c34 */ { true, 0x1c34, 0x1c34 }, +/* 0x1c35 */ { true, 0x1c35, 0x1c35 }, +/* 0x1c36 */ { false, 0x1c36, 0x1c36 }, +/* 0x1c37 */ { false, 0x1c37, 0x1c37 }, +/* 0x1c38 */ { false, 0x1c38, 0x1c38 }, +/* 0x1c39 */ { false, 0x1c39, 0x1c39 }, +/* 0x1c3a */ { false, 0x1c3a, 0x1c3a }, +/* 0x1c3b */ { false, 0x1c3b, 0x1c3b }, +/* 0x1c3c */ { false, 0x1c3c, 0x1c3c }, +/* 0x1c3d */ { false, 0x1c3d, 0x1c3d }, +/* 0x1c3e */ { false, 0x1c3e, 0x1c3e }, +/* 0x1c3f */ { false, 0x1c3f, 0x1c3f }, +/* 0x1c40 */ { false, 0x1c40, 0x1c40 }, +/* 0x1c41 */ { false, 0x1c41, 0x1c41 }, +/* 0x1c42 */ { false, 0x1c42, 0x1c42 }, +/* 0x1c43 */ { false, 0x1c43, 0x1c43 }, +/* 0x1c44 */ { false, 0x1c44, 0x1c44 }, +/* 0x1c45 */ { false, 0x1c45, 0x1c45 }, +/* 0x1c46 */ { false, 0x1c46, 0x1c46 }, +/* 0x1c47 */ { false, 0x1c47, 0x1c47 }, +/* 0x1c48 */ { false, 0x1c48, 0x1c48 }, +/* 0x1c49 */ { false, 0x1c49, 0x1c49 }, +/* 0x1c4a */ { false, 0x1c4a, 0x1c4a }, +/* 0x1c4b */ { false, 0x1c4b, 0x1c4b }, +/* 0x1c4c */ { false, 0x1c4c, 0x1c4c }, +/* 0x1c4d */ { false, 0x1c4d, 0x1c4d }, +/* 0x1c4e */ { false, 0x1c4e, 0x1c4e }, +/* 0x1c4f */ { false, 0x1c4f, 0x1c4f }, +/* 0x1c50 */ { false, 0x1c50, 0x1c50 }, +/* 0x1c51 */ { false, 0x1c51, 0x1c51 }, +/* 0x1c52 */ { false, 0x1c52, 0x1c52 }, +/* 0x1c53 */ { false, 0x1c53, 0x1c53 }, +/* 0x1c54 */ { false, 0x1c54, 0x1c54 }, +/* 0x1c55 */ { false, 0x1c55, 0x1c55 }, +/* 0x1c56 */ { false, 0x1c56, 0x1c56 }, +/* 0x1c57 */ { false, 0x1c57, 0x1c57 }, +/* 0x1c58 */ { false, 0x1c58, 0x1c58 }, +/* 0x1c59 */ { false, 0x1c59, 0x1c59 }, +/* 0x1c5a */ { false, 0x1c5a, 0x1c5a }, +/* 0x1c5b */ { false, 0x1c5b, 0x1c5b }, +/* 0x1c5c */ { false, 0x1c5c, 0x1c5c }, +/* 0x1c5d */ { false, 0x1c5d, 0x1c5d }, +/* 0x1c5e */ { false, 0x1c5e, 0x1c5e }, +/* 0x1c5f */ { false, 0x1c5f, 0x1c5f }, +/* 0x1c60 */ { false, 0x1c60, 0x1c60 }, +/* 0x1c61 */ { false, 0x1c61, 0x1c61 }, +/* 0x1c62 */ { false, 0x1c62, 0x1c62 }, +/* 0x1c63 */ { false, 0x1c63, 0x1c63 }, +/* 0x1c64 */ { false, 0x1c64, 0x1c64 }, +/* 0x1c65 */ { false, 0x1c65, 0x1c65 }, +/* 0x1c66 */ { false, 0x1c66, 0x1c66 }, +/* 0x1c67 */ { false, 0x1c67, 0x1c67 }, +/* 0x1c68 */ { false, 0x1c68, 0x1c68 }, +/* 0x1c69 */ { false, 0x1c69, 0x1c69 }, +/* 0x1c6a */ { false, 0x1c6a, 0x1c6a }, +/* 0x1c6b */ { false, 0x1c6b, 0x1c6b }, +/* 0x1c6c */ { false, 0x1c6c, 0x1c6c }, +/* 0x1c6d */ { false, 0x1c6d, 0x1c6d }, +/* 0x1c6e */ { false, 0x1c6e, 0x1c6e }, +/* 0x1c6f */ { false, 0x1c6f, 0x1c6f }, +/* 0x1c70 */ { false, 0x1c70, 0x1c70 }, +/* 0x1c71 */ { false, 0x1c71, 0x1c71 }, +/* 0x1c72 */ { false, 0x1c72, 0x1c72 }, +/* 0x1c73 */ { false, 0x1c73, 0x1c73 }, +/* 0x1c74 */ { false, 0x1c74, 0x1c74 }, +/* 0x1c75 */ { false, 0x1c75, 0x1c75 }, +/* 0x1c76 */ { false, 0x1c76, 0x1c76 }, +/* 0x1c77 */ { false, 0x1c77, 0x1c77 }, +/* 0x1c78 */ { false, 0x1c78, 0x1c78 }, +/* 0x1c79 */ { false, 0x1c79, 0x1c79 }, +/* 0x1c7a */ { false, 0x1c7a, 0x1c7a }, +/* 0x1c7b */ { false, 0x1c7b, 0x1c7b }, +/* 0x1c7c */ { false, 0x1c7c, 0x1c7c }, +/* 0x1c7d */ { false, 0x1c7d, 0x1c7d }, +/* 0x1c7e */ { false, 0x1c7e, 0x1c7e }, +/* 0x1c7f */ { false, 0x1c7f, 0x1c7f }, +/* 0x1c80 */ { false, 0x1c80, 0x1c80 }, +/* 0x1c81 */ { false, 0x1c81, 0x1c81 }, +/* 0x1c82 */ { false, 0x1c82, 0x1c82 }, +/* 0x1c83 */ { false, 0x1c83, 0x1c83 }, +/* 0x1c84 */ { false, 0x1c84, 0x1c84 }, +/* 0x1c85 */ { false, 0x1c85, 0x1c85 }, +/* 0x1c86 */ { false, 0x1c86, 0x1c86 }, +/* 0x1c87 */ { false, 0x1c87, 0x1c87 }, +/* 0x1c88 */ { false, 0x1c88, 0x1c88 }, +/* 0x1c89 */ { false, 0x1c89, 0x1c89 }, +/* 0x1c8a */ { false, 0x1c8a, 0x1c8a }, +/* 0x1c8b */ { false, 0x1c8b, 0x1c8b }, +/* 0x1c8c */ { false, 0x1c8c, 0x1c8c }, +/* 0x1c8d */ { false, 0x1c8d, 0x1c8d }, +/* 0x1c8e */ { false, 0x1c8e, 0x1c8e }, +/* 0x1c8f */ { false, 0x1c8f, 0x1c8f }, +/* 0x1c90 */ { false, 0x1c90, 0x1c90 }, +/* 0x1c91 */ { false, 0x1c91, 0x1c91 }, +/* 0x1c92 */ { false, 0x1c92, 0x1c92 }, +/* 0x1c93 */ { false, 0x1c93, 0x1c93 }, +/* 0x1c94 */ { false, 0x1c94, 0x1c94 }, +/* 0x1c95 */ { false, 0x1c95, 0x1c95 }, +/* 0x1c96 */ { false, 0x1c96, 0x1c96 }, +/* 0x1c97 */ { false, 0x1c97, 0x1c97 }, +/* 0x1c98 */ { false, 0x1c98, 0x1c98 }, +/* 0x1c99 */ { false, 0x1c99, 0x1c99 }, +/* 0x1c9a */ { false, 0x1c9a, 0x1c9a }, +/* 0x1c9b */ { false, 0x1c9b, 0x1c9b }, +/* 0x1c9c */ { false, 0x1c9c, 0x1c9c }, +/* 0x1c9d */ { false, 0x1c9d, 0x1c9d }, +/* 0x1c9e */ { false, 0x1c9e, 0x1c9e }, +/* 0x1c9f */ { false, 0x1c9f, 0x1c9f }, +/* 0x1ca0 */ { false, 0x1ca0, 0x1ca0 }, +/* 0x1ca1 */ { false, 0x1ca1, 0x1ca1 }, +/* 0x1ca2 */ { false, 0x1ca2, 0x1ca2 }, +/* 0x1ca3 */ { false, 0x1ca3, 0x1ca3 }, +/* 0x1ca4 */ { false, 0x1ca4, 0x1ca4 }, +/* 0x1ca5 */ { false, 0x1ca5, 0x1ca5 }, +/* 0x1ca6 */ { false, 0x1ca6, 0x1ca6 }, +/* 0x1ca7 */ { false, 0x1ca7, 0x1ca7 }, +/* 0x1ca8 */ { false, 0x1ca8, 0x1ca8 }, +/* 0x1ca9 */ { false, 0x1ca9, 0x1ca9 }, +/* 0x1caa */ { false, 0x1caa, 0x1caa }, +/* 0x1cab */ { false, 0x1cab, 0x1cab }, +/* 0x1cac */ { false, 0x1cac, 0x1cac }, +/* 0x1cad */ { false, 0x1cad, 0x1cad }, +/* 0x1cae */ { false, 0x1cae, 0x1cae }, +/* 0x1caf */ { false, 0x1caf, 0x1caf }, +/* 0x1cb0 */ { false, 0x1cb0, 0x1cb0 }, +/* 0x1cb1 */ { false, 0x1cb1, 0x1cb1 }, +/* 0x1cb2 */ { false, 0x1cb2, 0x1cb2 }, +/* 0x1cb3 */ { false, 0x1cb3, 0x1cb3 }, +/* 0x1cb4 */ { false, 0x1cb4, 0x1cb4 }, +/* 0x1cb5 */ { false, 0x1cb5, 0x1cb5 }, +/* 0x1cb6 */ { false, 0x1cb6, 0x1cb6 }, +/* 0x1cb7 */ { false, 0x1cb7, 0x1cb7 }, +/* 0x1cb8 */ { false, 0x1cb8, 0x1cb8 }, +/* 0x1cb9 */ { false, 0x1cb9, 0x1cb9 }, +/* 0x1cba */ { false, 0x1cba, 0x1cba }, +/* 0x1cbb */ { false, 0x1cbb, 0x1cbb }, +/* 0x1cbc */ { false, 0x1cbc, 0x1cbc }, +/* 0x1cbd */ { false, 0x1cbd, 0x1cbd }, +/* 0x1cbe */ { false, 0x1cbe, 0x1cbe }, +/* 0x1cbf */ { false, 0x1cbf, 0x1cbf }, +/* 0x1cc0 */ { false, 0x1cc0, 0x1cc0 }, +/* 0x1cc1 */ { false, 0x1cc1, 0x1cc1 }, +/* 0x1cc2 */ { false, 0x1cc2, 0x1cc2 }, +/* 0x1cc3 */ { false, 0x1cc3, 0x1cc3 }, +/* 0x1cc4 */ { false, 0x1cc4, 0x1cc4 }, +/* 0x1cc5 */ { false, 0x1cc5, 0x1cc5 }, +/* 0x1cc6 */ { false, 0x1cc6, 0x1cc6 }, +/* 0x1cc7 */ { false, 0x1cc7, 0x1cc7 }, +/* 0x1cc8 */ { false, 0x1cc8, 0x1cc8 }, +/* 0x1cc9 */ { false, 0x1cc9, 0x1cc9 }, +/* 0x1cca */ { false, 0x1cca, 0x1cca }, +/* 0x1ccb */ { false, 0x1ccb, 0x1ccb }, +/* 0x1ccc */ { false, 0x1ccc, 0x1ccc }, +/* 0x1ccd */ { false, 0x1ccd, 0x1ccd }, +/* 0x1cce */ { false, 0x1cce, 0x1cce }, +/* 0x1ccf */ { false, 0x1ccf, 0x1ccf }, +/* 0x1cd0 */ { false, 0x1cd0, 0x1cd0 }, +/* 0x1cd1 */ { false, 0x1cd1, 0x1cd1 }, +/* 0x1cd2 */ { false, 0x1cd2, 0x1cd2 }, +/* 0x1cd3 */ { false, 0x1cd3, 0x1cd3 }, +/* 0x1cd4 */ { false, 0x1cd4, 0x1cd4 }, +/* 0x1cd5 */ { false, 0x1cd5, 0x1cd5 }, +/* 0x1cd6 */ { false, 0x1cd6, 0x1cd6 }, +/* 0x1cd7 */ { false, 0x1cd7, 0x1cd7 }, +/* 0x1cd8 */ { false, 0x1cd8, 0x1cd8 }, +/* 0x1cd9 */ { false, 0x1cd9, 0x1cd9 }, +/* 0x1cda */ { false, 0x1cda, 0x1cda }, +/* 0x1cdb */ { false, 0x1cdb, 0x1cdb }, +/* 0x1cdc */ { false, 0x1cdc, 0x1cdc }, +/* 0x1cdd */ { false, 0x1cdd, 0x1cdd }, +/* 0x1cde */ { false, 0x1cde, 0x1cde }, +/* 0x1cdf */ { false, 0x1cdf, 0x1cdf }, +/* 0x1ce0 */ { false, 0x1ce0, 0x1ce0 }, +/* 0x1ce1 */ { true, 0x1ce1, 0x1ce1 }, +/* 0x1ce2 */ { false, 0x1ce2, 0x1ce2 }, +/* 0x1ce3 */ { false, 0x1ce3, 0x1ce3 }, +/* 0x1ce4 */ { false, 0x1ce4, 0x1ce4 }, +/* 0x1ce5 */ { false, 0x1ce5, 0x1ce5 }, +/* 0x1ce6 */ { false, 0x1ce6, 0x1ce6 }, +/* 0x1ce7 */ { false, 0x1ce7, 0x1ce7 }, +/* 0x1ce8 */ { false, 0x1ce8, 0x1ce8 }, +/* 0x1ce9 */ { false, 0x1ce9, 0x1ce9 }, +/* 0x1cea */ { false, 0x1cea, 0x1cea }, +/* 0x1ceb */ { false, 0x1ceb, 0x1ceb }, +/* 0x1cec */ { false, 0x1cec, 0x1cec }, +/* 0x1ced */ { false, 0x1ced, 0x1ced }, +/* 0x1cee */ { false, 0x1cee, 0x1cee }, +/* 0x1cef */ { false, 0x1cef, 0x1cef }, +/* 0x1cf0 */ { false, 0x1cf0, 0x1cf0 }, +/* 0x1cf1 */ { false, 0x1cf1, 0x1cf1 }, +/* 0x1cf2 */ { false, 0x1cf2, 0x1cf2 }, +/* 0x1cf3 */ { false, 0x1cf3, 0x1cf3 }, +/* 0x1cf4 */ { false, 0x1cf4, 0x1cf4 }, +/* 0x1cf5 */ { false, 0x1cf5, 0x1cf5 }, +/* 0x1cf6 */ { false, 0x1cf6, 0x1cf6 }, +/* 0x1cf7 */ { true, 0x1cf7, 0x1cf7 }, +/* 0x1cf8 */ { false, 0x1cf8, 0x1cf8 }, +/* 0x1cf9 */ { false, 0x1cf9, 0x1cf9 }, +/* 0x1cfa */ { false, 0x1cfa, 0x1cfa }, +/* 0x1cfb */ { false, 0x1cfb, 0x1cfb }, +/* 0x1cfc */ { false, 0x1cfc, 0x1cfc }, +/* 0x1cfd */ { false, 0x1cfd, 0x1cfd }, +/* 0x1cfe */ { false, 0x1cfe, 0x1cfe }, +/* 0x1cff */ { false, 0x1cff, 0x1cff }, +/* 0x1d00 */ { true, 0x1d00, 0x1d00 }, +/* 0x1d01 */ { true, 0x1d01, 0x1d01 }, +/* 0x1d02 */ { true, 0x1d02, 0x1d02 }, +/* 0x1d03 */ { true, 0x1d03, 0x1d03 }, +/* 0x1d04 */ { true, 0x1d04, 0x1d04 }, +/* 0x1d05 */ { true, 0x1d05, 0x1d05 }, +/* 0x1d06 */ { true, 0x1d06, 0x1d06 }, +/* 0x1d07 */ { true, 0x1d07, 0x1d07 }, +/* 0x1d08 */ { true, 0x1d08, 0x1d08 }, +/* 0x1d09 */ { true, 0x1d09, 0x1d09 }, +/* 0x1d0a */ { true, 0x1d0a, 0x1d0a }, +/* 0x1d0b */ { true, 0x1d0b, 0x1d0b }, +/* 0x1d0c */ { true, 0x1d0c, 0x1d0c }, +/* 0x1d0d */ { true, 0x1d0d, 0x1d0d }, +/* 0x1d0e */ { true, 0x1d0e, 0x1d0e }, +/* 0x1d0f */ { true, 0x1d0f, 0x1d0f }, +/* 0x1d10 */ { true, 0x1d10, 0x1d10 }, +/* 0x1d11 */ { true, 0x1d11, 0x1d11 }, +/* 0x1d12 */ { true, 0x1d12, 0x1d12 }, +/* 0x1d13 */ { true, 0x1d13, 0x1d13 }, +/* 0x1d14 */ { true, 0x1d14, 0x1d14 }, +/* 0x1d15 */ { true, 0x1d15, 0x1d15 }, +/* 0x1d16 */ { true, 0x1d16, 0x1d16 }, +/* 0x1d17 */ { true, 0x1d17, 0x1d17 }, +/* 0x1d18 */ { true, 0x1d18, 0x1d18 }, +/* 0x1d19 */ { true, 0x1d19, 0x1d19 }, +/* 0x1d1a */ { true, 0x1d1a, 0x1d1a }, +/* 0x1d1b */ { true, 0x1d1b, 0x1d1b }, +/* 0x1d1c */ { true, 0x1d1c, 0x1d1c }, +/* 0x1d1d */ { true, 0x1d1d, 0x1d1d }, +/* 0x1d1e */ { true, 0x1d1e, 0x1d1e }, +/* 0x1d1f */ { true, 0x1d1f, 0x1d1f }, +/* 0x1d20 */ { true, 0x1d20, 0x1d20 }, +/* 0x1d21 */ { true, 0x1d21, 0x1d21 }, +/* 0x1d22 */ { true, 0x1d22, 0x1d22 }, +/* 0x1d23 */ { true, 0x1d23, 0x1d23 }, +/* 0x1d24 */ { true, 0x1d24, 0x1d24 }, +/* 0x1d25 */ { true, 0x1d25, 0x1d25 }, +/* 0x1d26 */ { true, 0x1d26, 0x1d26 }, +/* 0x1d27 */ { true, 0x1d27, 0x1d27 }, +/* 0x1d28 */ { true, 0x1d28, 0x1d28 }, +/* 0x1d29 */ { true, 0x1d29, 0x1d29 }, +/* 0x1d2a */ { true, 0x1d2a, 0x1d2a }, +/* 0x1d2b */ { true, 0x1d2b, 0x1d2b }, +/* 0x1d2c */ { true, 0x1d2c, 0x1d2c }, +/* 0x1d2d */ { true, 0x1d2d, 0x1d2d }, +/* 0x1d2e */ { true, 0x1d2e, 0x1d2e }, +/* 0x1d2f */ { true, 0x1d2f, 0x1d2f }, +/* 0x1d30 */ { true, 0x1d30, 0x1d30 }, +/* 0x1d31 */ { true, 0x1d31, 0x1d31 }, +/* 0x1d32 */ { true, 0x1d32, 0x1d32 }, +/* 0x1d33 */ { true, 0x1d33, 0x1d33 }, +/* 0x1d34 */ { true, 0x1d34, 0x1d34 }, +/* 0x1d35 */ { true, 0x1d35, 0x1d35 }, +/* 0x1d36 */ { true, 0x1d36, 0x1d36 }, +/* 0x1d37 */ { true, 0x1d37, 0x1d37 }, +/* 0x1d38 */ { true, 0x1d38, 0x1d38 }, +/* 0x1d39 */ { true, 0x1d39, 0x1d39 }, +/* 0x1d3a */ { true, 0x1d3a, 0x1d3a }, +/* 0x1d3b */ { true, 0x1d3b, 0x1d3b }, +/* 0x1d3c */ { true, 0x1d3c, 0x1d3c }, +/* 0x1d3d */ { true, 0x1d3d, 0x1d3d }, +/* 0x1d3e */ { true, 0x1d3e, 0x1d3e }, +/* 0x1d3f */ { true, 0x1d3f, 0x1d3f }, +/* 0x1d40 */ { true, 0x1d40, 0x1d40 }, +/* 0x1d41 */ { true, 0x1d41, 0x1d41 }, +/* 0x1d42 */ { true, 0x1d42, 0x1d42 }, +/* 0x1d43 */ { true, 0x1d43, 0x1d43 }, +/* 0x1d44 */ { true, 0x1d44, 0x1d44 }, +/* 0x1d45 */ { true, 0x1d45, 0x1d45 }, +/* 0x1d46 */ { true, 0x1d46, 0x1d46 }, +/* 0x1d47 */ { true, 0x1d47, 0x1d47 }, +/* 0x1d48 */ { true, 0x1d48, 0x1d48 }, +/* 0x1d49 */ { true, 0x1d49, 0x1d49 }, +/* 0x1d4a */ { true, 0x1d4a, 0x1d4a }, +/* 0x1d4b */ { true, 0x1d4b, 0x1d4b }, +/* 0x1d4c */ { true, 0x1d4c, 0x1d4c }, +/* 0x1d4d */ { true, 0x1d4d, 0x1d4d }, +/* 0x1d4e */ { true, 0x1d4e, 0x1d4e }, +/* 0x1d4f */ { true, 0x1d4f, 0x1d4f }, +/* 0x1d50 */ { true, 0x1d50, 0x1d50 }, +/* 0x1d51 */ { true, 0x1d51, 0x1d51 }, +/* 0x1d52 */ { true, 0x1d52, 0x1d52 }, +/* 0x1d53 */ { true, 0x1d53, 0x1d53 }, +/* 0x1d54 */ { true, 0x1d54, 0x1d54 }, +/* 0x1d55 */ { true, 0x1d55, 0x1d55 }, +/* 0x1d56 */ { true, 0x1d56, 0x1d56 }, +/* 0x1d57 */ { true, 0x1d57, 0x1d57 }, +/* 0x1d58 */ { true, 0x1d58, 0x1d58 }, +/* 0x1d59 */ { true, 0x1d59, 0x1d59 }, +/* 0x1d5a */ { true, 0x1d5a, 0x1d5a }, +/* 0x1d5b */ { true, 0x1d5b, 0x1d5b }, +/* 0x1d5c */ { true, 0x1d5c, 0x1d5c }, +/* 0x1d5d */ { true, 0x1d5d, 0x1d5d }, +/* 0x1d5e */ { true, 0x1d5e, 0x1d5e }, +/* 0x1d5f */ { true, 0x1d5f, 0x1d5f }, +/* 0x1d60 */ { true, 0x1d60, 0x1d60 }, +/* 0x1d61 */ { true, 0x1d61, 0x1d61 }, +/* 0x1d62 */ { true, 0x1d62, 0x1d62 }, +/* 0x1d63 */ { true, 0x1d63, 0x1d63 }, +/* 0x1d64 */ { true, 0x1d64, 0x1d64 }, +/* 0x1d65 */ { true, 0x1d65, 0x1d65 }, +/* 0x1d66 */ { true, 0x1d66, 0x1d66 }, +/* 0x1d67 */ { true, 0x1d67, 0x1d67 }, +/* 0x1d68 */ { true, 0x1d68, 0x1d68 }, +/* 0x1d69 */ { true, 0x1d69, 0x1d69 }, +/* 0x1d6a */ { true, 0x1d6a, 0x1d6a }, +/* 0x1d6b */ { true, 0x1d6b, 0x1d6b }, +/* 0x1d6c */ { true, 0x1d6c, 0x1d6c }, +/* 0x1d6d */ { true, 0x1d6d, 0x1d6d }, +/* 0x1d6e */ { true, 0x1d6e, 0x1d6e }, +/* 0x1d6f */ { true, 0x1d6f, 0x1d6f }, +/* 0x1d70 */ { true, 0x1d70, 0x1d70 }, +/* 0x1d71 */ { true, 0x1d71, 0x1d71 }, +/* 0x1d72 */ { true, 0x1d72, 0x1d72 }, +/* 0x1d73 */ { true, 0x1d73, 0x1d73 }, +/* 0x1d74 */ { true, 0x1d74, 0x1d74 }, +/* 0x1d75 */ { true, 0x1d75, 0x1d75 }, +/* 0x1d76 */ { true, 0x1d76, 0x1d76 }, +/* 0x1d77 */ { true, 0x1d77, 0x1d77 }, +/* 0x1d78 */ { true, 0x1d78, 0x1d78 }, +/* 0x1d79 */ { true, 0x1d79, 0x1d79 }, +/* 0x1d7a */ { true, 0x1d7a, 0x1d7a }, +/* 0x1d7b */ { true, 0x1d7b, 0x1d7b }, +/* 0x1d7c */ { true, 0x1d7c, 0x1d7c }, +/* 0x1d7d */ { true, 0x1d7d, 0x1d7d }, +/* 0x1d7e */ { true, 0x1d7e, 0x1d7e }, +/* 0x1d7f */ { true, 0x1d7f, 0x1d7f }, +/* 0x1d80 */ { true, 0x1d80, 0x1d80 }, +/* 0x1d81 */ { true, 0x1d81, 0x1d81 }, +/* 0x1d82 */ { true, 0x1d82, 0x1d82 }, +/* 0x1d83 */ { true, 0x1d83, 0x1d83 }, +/* 0x1d84 */ { true, 0x1d84, 0x1d84 }, +/* 0x1d85 */ { true, 0x1d85, 0x1d85 }, +/* 0x1d86 */ { true, 0x1d86, 0x1d86 }, +/* 0x1d87 */ { true, 0x1d87, 0x1d87 }, +/* 0x1d88 */ { true, 0x1d88, 0x1d88 }, +/* 0x1d89 */ { true, 0x1d89, 0x1d89 }, +/* 0x1d8a */ { true, 0x1d8a, 0x1d8a }, +/* 0x1d8b */ { true, 0x1d8b, 0x1d8b }, +/* 0x1d8c */ { true, 0x1d8c, 0x1d8c }, +/* 0x1d8d */ { true, 0x1d8d, 0x1d8d }, +/* 0x1d8e */ { true, 0x1d8e, 0x1d8e }, +/* 0x1d8f */ { true, 0x1d8f, 0x1d8f }, +/* 0x1d90 */ { true, 0x1d90, 0x1d90 }, +/* 0x1d91 */ { true, 0x1d91, 0x1d91 }, +/* 0x1d92 */ { true, 0x1d92, 0x1d92 }, +/* 0x1d93 */ { true, 0x1d93, 0x1d93 }, +/* 0x1d94 */ { true, 0x1d94, 0x1d94 }, +/* 0x1d95 */ { true, 0x1d95, 0x1d95 }, +/* 0x1d96 */ { true, 0x1d96, 0x1d96 }, +/* 0x1d97 */ { true, 0x1d97, 0x1d97 }, +/* 0x1d98 */ { true, 0x1d98, 0x1d98 }, +/* 0x1d99 */ { true, 0x1d99, 0x1d99 }, +/* 0x1d9a */ { true, 0x1d9a, 0x1d9a }, +/* 0x1d9b */ { true, 0x1d9b, 0x1d9b }, +/* 0x1d9c */ { true, 0x1d9c, 0x1d9c }, +/* 0x1d9d */ { true, 0x1d9d, 0x1d9d }, +/* 0x1d9e */ { true, 0x1d9e, 0x1d9e }, +/* 0x1d9f */ { true, 0x1d9f, 0x1d9f }, +/* 0x1da0 */ { true, 0x1da0, 0x1da0 }, +/* 0x1da1 */ { true, 0x1da1, 0x1da1 }, +/* 0x1da2 */ { true, 0x1da2, 0x1da2 }, +/* 0x1da3 */ { true, 0x1da3, 0x1da3 }, +/* 0x1da4 */ { true, 0x1da4, 0x1da4 }, +/* 0x1da5 */ { true, 0x1da5, 0x1da5 }, +/* 0x1da6 */ { true, 0x1da6, 0x1da6 }, +/* 0x1da7 */ { true, 0x1da7, 0x1da7 }, +/* 0x1da8 */ { true, 0x1da8, 0x1da8 }, +/* 0x1da9 */ { true, 0x1da9, 0x1da9 }, +/* 0x1daa */ { true, 0x1daa, 0x1daa }, +/* 0x1dab */ { true, 0x1dab, 0x1dab }, +/* 0x1dac */ { true, 0x1dac, 0x1dac }, +/* 0x1dad */ { true, 0x1dad, 0x1dad }, +/* 0x1dae */ { true, 0x1dae, 0x1dae }, +/* 0x1daf */ { true, 0x1daf, 0x1daf }, +/* 0x1db0 */ { true, 0x1db0, 0x1db0 }, +/* 0x1db1 */ { true, 0x1db1, 0x1db1 }, +/* 0x1db2 */ { true, 0x1db2, 0x1db2 }, +/* 0x1db3 */ { true, 0x1db3, 0x1db3 }, +/* 0x1db4 */ { true, 0x1db4, 0x1db4 }, +/* 0x1db5 */ { true, 0x1db5, 0x1db5 }, +/* 0x1db6 */ { true, 0x1db6, 0x1db6 }, +/* 0x1db7 */ { true, 0x1db7, 0x1db7 }, +/* 0x1db8 */ { true, 0x1db8, 0x1db8 }, +/* 0x1db9 */ { true, 0x1db9, 0x1db9 }, +/* 0x1dba */ { true, 0x1dba, 0x1dba }, +/* 0x1dbb */ { true, 0x1dbb, 0x1dbb }, +/* 0x1dbc */ { true, 0x1dbc, 0x1dbc }, +/* 0x1dbd */ { true, 0x1dbd, 0x1dbd }, +/* 0x1dbe */ { true, 0x1dbe, 0x1dbe }, +/* 0x1dbf */ { true, 0x1dbf, 0x1dbf }, +/* 0x1dc0 */ { true, 0x1dc0, 0x1dc0 }, +/* 0x1dc1 */ { true, 0x1dc1, 0x1dc1 }, +/* 0x1dc2 */ { true, 0x1dc2, 0x1dc2 }, +/* 0x1dc3 */ { true, 0x1dc3, 0x1dc3 }, +/* 0x1dc4 */ { false, 0x1dc4, 0x1dc4 }, +/* 0x1dc5 */ { false, 0x1dc5, 0x1dc5 }, +/* 0x1dc6 */ { false, 0x1dc6, 0x1dc6 }, +/* 0x1dc7 */ { false, 0x1dc7, 0x1dc7 }, +/* 0x1dc8 */ { false, 0x1dc8, 0x1dc8 }, +/* 0x1dc9 */ { false, 0x1dc9, 0x1dc9 }, +/* 0x1dca */ { false, 0x1dca, 0x1dca }, +/* 0x1dcb */ { false, 0x1dcb, 0x1dcb }, +/* 0x1dcc */ { false, 0x1dcc, 0x1dcc }, +/* 0x1dcd */ { false, 0x1dcd, 0x1dcd }, +/* 0x1dce */ { false, 0x1dce, 0x1dce }, +/* 0x1dcf */ { false, 0x1dcf, 0x1dcf }, +/* 0x1dd0 */ { false, 0x1dd0, 0x1dd0 }, +/* 0x1dd1 */ { false, 0x1dd1, 0x1dd1 }, +/* 0x1dd2 */ { false, 0x1dd2, 0x1dd2 }, +/* 0x1dd3 */ { false, 0x1dd3, 0x1dd3 }, +/* 0x1dd4 */ { false, 0x1dd4, 0x1dd4 }, +/* 0x1dd5 */ { false, 0x1dd5, 0x1dd5 }, +/* 0x1dd6 */ { false, 0x1dd6, 0x1dd6 }, +/* 0x1dd7 */ { false, 0x1dd7, 0x1dd7 }, +/* 0x1dd8 */ { false, 0x1dd8, 0x1dd8 }, +/* 0x1dd9 */ { false, 0x1dd9, 0x1dd9 }, +/* 0x1dda */ { false, 0x1dda, 0x1dda }, +/* 0x1ddb */ { false, 0x1ddb, 0x1ddb }, +/* 0x1ddc */ { false, 0x1ddc, 0x1ddc }, +/* 0x1ddd */ { false, 0x1ddd, 0x1ddd }, +/* 0x1dde */ { false, 0x1dde, 0x1dde }, +/* 0x1ddf */ { false, 0x1ddf, 0x1ddf }, +/* 0x1de0 */ { false, 0x1de0, 0x1de0 }, +/* 0x1de1 */ { false, 0x1de1, 0x1de1 }, +/* 0x1de2 */ { false, 0x1de2, 0x1de2 }, +/* 0x1de3 */ { false, 0x1de3, 0x1de3 }, +/* 0x1de4 */ { false, 0x1de4, 0x1de4 }, +/* 0x1de5 */ { false, 0x1de5, 0x1de5 }, +/* 0x1de6 */ { false, 0x1de6, 0x1de6 }, +/* 0x1de7 */ { false, 0x1de7, 0x1de7 }, +/* 0x1de8 */ { false, 0x1de8, 0x1de8 }, +/* 0x1de9 */ { false, 0x1de9, 0x1de9 }, +/* 0x1dea */ { false, 0x1dea, 0x1dea }, +/* 0x1deb */ { false, 0x1deb, 0x1deb }, +/* 0x1dec */ { false, 0x1dec, 0x1dec }, +/* 0x1ded */ { false, 0x1ded, 0x1ded }, +/* 0x1dee */ { false, 0x1dee, 0x1dee }, +/* 0x1def */ { false, 0x1def, 0x1def }, +/* 0x1df0 */ { false, 0x1df0, 0x1df0 }, +/* 0x1df1 */ { false, 0x1df1, 0x1df1 }, +/* 0x1df2 */ { false, 0x1df2, 0x1df2 }, +/* 0x1df3 */ { false, 0x1df3, 0x1df3 }, +/* 0x1df4 */ { false, 0x1df4, 0x1df4 }, +/* 0x1df5 */ { false, 0x1df5, 0x1df5 }, +/* 0x1df6 */ { false, 0x1df6, 0x1df6 }, +/* 0x1df7 */ { false, 0x1df7, 0x1df7 }, +/* 0x1df8 */ { false, 0x1df8, 0x1df8 }, +/* 0x1df9 */ { false, 0x1df9, 0x1df9 }, +/* 0x1dfa */ { false, 0x1dfa, 0x1dfa }, +/* 0x1dfb */ { false, 0x1dfb, 0x1dfb }, +/* 0x1dfc */ { false, 0x1dfc, 0x1dfc }, +/* 0x1dfd */ { false, 0x1dfd, 0x1dfd }, +/* 0x1dfe */ { false, 0x1dfe, 0x1dfe }, +/* 0x1dff */ { false, 0x1dff, 0x1dff }, +/* 0x1e00 */ { true, 0x1e00, 0x1e01 }, +/* 0x1e01 */ { true, 0x1e00, 0x1e01 }, +/* 0x1e02 */ { true, 0x1e02, 0x1e03 }, +/* 0x1e03 */ { true, 0x1e02, 0x1e03 }, +/* 0x1e04 */ { true, 0x1e04, 0x1e05 }, +/* 0x1e05 */ { true, 0x1e04, 0x1e05 }, +/* 0x1e06 */ { true, 0x1e06, 0x1e07 }, +/* 0x1e07 */ { true, 0x1e06, 0x1e07 }, +/* 0x1e08 */ { true, 0x1e08, 0x1e09 }, +/* 0x1e09 */ { true, 0x1e08, 0x1e09 }, +/* 0x1e0a */ { true, 0x1e0a, 0x1e0b }, +/* 0x1e0b */ { true, 0x1e0a, 0x1e0b }, +/* 0x1e0c */ { true, 0x1e0c, 0x1e0d }, +/* 0x1e0d */ { true, 0x1e0c, 0x1e0d }, +/* 0x1e0e */ { true, 0x1e0e, 0x1e0f }, +/* 0x1e0f */ { true, 0x1e0e, 0x1e0f }, +/* 0x1e10 */ { true, 0x1e10, 0x1e11 }, +/* 0x1e11 */ { true, 0x1e10, 0x1e11 }, +/* 0x1e12 */ { true, 0x1e12, 0x1e13 }, +/* 0x1e13 */ { true, 0x1e12, 0x1e13 }, +/* 0x1e14 */ { true, 0x1e14, 0x1e15 }, +/* 0x1e15 */ { true, 0x1e14, 0x1e15 }, +/* 0x1e16 */ { true, 0x1e16, 0x1e17 }, +/* 0x1e17 */ { true, 0x1e16, 0x1e17 }, +/* 0x1e18 */ { true, 0x1e18, 0x1e19 }, +/* 0x1e19 */ { true, 0x1e18, 0x1e19 }, +/* 0x1e1a */ { true, 0x1e1a, 0x1e1b }, +/* 0x1e1b */ { true, 0x1e1a, 0x1e1b }, +/* 0x1e1c */ { true, 0x1e1c, 0x1e1d }, +/* 0x1e1d */ { true, 0x1e1c, 0x1e1d }, +/* 0x1e1e */ { true, 0x1e1e, 0x1e1f }, +/* 0x1e1f */ { true, 0x1e1e, 0x1e1f }, +/* 0x1e20 */ { true, 0x1e20, 0x1e21 }, +/* 0x1e21 */ { true, 0x1e20, 0x1e21 }, +/* 0x1e22 */ { true, 0x1e22, 0x1e23 }, +/* 0x1e23 */ { true, 0x1e22, 0x1e23 }, +/* 0x1e24 */ { true, 0x1e24, 0x1e25 }, +/* 0x1e25 */ { true, 0x1e24, 0x1e25 }, +/* 0x1e26 */ { true, 0x1e26, 0x1e27 }, +/* 0x1e27 */ { true, 0x1e26, 0x1e27 }, +/* 0x1e28 */ { true, 0x1e28, 0x1e29 }, +/* 0x1e29 */ { true, 0x1e28, 0x1e29 }, +/* 0x1e2a */ { true, 0x1e2a, 0x1e2b }, +/* 0x1e2b */ { true, 0x1e2a, 0x1e2b }, +/* 0x1e2c */ { true, 0x1e2c, 0x1e2d }, +/* 0x1e2d */ { true, 0x1e2c, 0x1e2d }, +/* 0x1e2e */ { true, 0x1e2e, 0x1e2f }, +/* 0x1e2f */ { true, 0x1e2e, 0x1e2f }, +/* 0x1e30 */ { true, 0x1e30, 0x1e31 }, +/* 0x1e31 */ { true, 0x1e30, 0x1e31 }, +/* 0x1e32 */ { true, 0x1e32, 0x1e33 }, +/* 0x1e33 */ { true, 0x1e32, 0x1e33 }, +/* 0x1e34 */ { true, 0x1e34, 0x1e35 }, +/* 0x1e35 */ { true, 0x1e34, 0x1e35 }, +/* 0x1e36 */ { true, 0x1e36, 0x1e37 }, +/* 0x1e37 */ { true, 0x1e36, 0x1e37 }, +/* 0x1e38 */ { true, 0x1e38, 0x1e39 }, +/* 0x1e39 */ { true, 0x1e38, 0x1e39 }, +/* 0x1e3a */ { true, 0x1e3a, 0x1e3b }, +/* 0x1e3b */ { true, 0x1e3a, 0x1e3b }, +/* 0x1e3c */ { true, 0x1e3c, 0x1e3d }, +/* 0x1e3d */ { true, 0x1e3c, 0x1e3d }, +/* 0x1e3e */ { true, 0x1e3e, 0x1e3f }, +/* 0x1e3f */ { true, 0x1e3e, 0x1e3f }, +/* 0x1e40 */ { true, 0x1e40, 0x1e41 }, +/* 0x1e41 */ { true, 0x1e40, 0x1e41 }, +/* 0x1e42 */ { true, 0x1e42, 0x1e43 }, +/* 0x1e43 */ { true, 0x1e42, 0x1e43 }, +/* 0x1e44 */ { true, 0x1e44, 0x1e45 }, +/* 0x1e45 */ { true, 0x1e44, 0x1e45 }, +/* 0x1e46 */ { true, 0x1e46, 0x1e47 }, +/* 0x1e47 */ { true, 0x1e46, 0x1e47 }, +/* 0x1e48 */ { true, 0x1e48, 0x1e49 }, +/* 0x1e49 */ { true, 0x1e48, 0x1e49 }, +/* 0x1e4a */ { true, 0x1e4a, 0x1e4b }, +/* 0x1e4b */ { true, 0x1e4a, 0x1e4b }, +/* 0x1e4c */ { true, 0x1e4c, 0x1e4d }, +/* 0x1e4d */ { true, 0x1e4c, 0x1e4d }, +/* 0x1e4e */ { true, 0x1e4e, 0x1e4f }, +/* 0x1e4f */ { true, 0x1e4e, 0x1e4f }, +/* 0x1e50 */ { true, 0x1e50, 0x1e51 }, +/* 0x1e51 */ { true, 0x1e50, 0x1e51 }, +/* 0x1e52 */ { true, 0x1e52, 0x1e53 }, +/* 0x1e53 */ { true, 0x1e52, 0x1e53 }, +/* 0x1e54 */ { true, 0x1e54, 0x1e55 }, +/* 0x1e55 */ { true, 0x1e54, 0x1e55 }, +/* 0x1e56 */ { true, 0x1e56, 0x1e57 }, +/* 0x1e57 */ { true, 0x1e56, 0x1e57 }, +/* 0x1e58 */ { true, 0x1e58, 0x1e59 }, +/* 0x1e59 */ { true, 0x1e58, 0x1e59 }, +/* 0x1e5a */ { true, 0x1e5a, 0x1e5b }, +/* 0x1e5b */ { true, 0x1e5a, 0x1e5b }, +/* 0x1e5c */ { true, 0x1e5c, 0x1e5d }, +/* 0x1e5d */ { true, 0x1e5c, 0x1e5d }, +/* 0x1e5e */ { true, 0x1e5e, 0x1e5f }, +/* 0x1e5f */ { true, 0x1e5e, 0x1e5f }, +/* 0x1e60 */ { true, 0x1e60, 0x1e61 }, +/* 0x1e61 */ { true, 0x1e60, 0x1e61 }, +/* 0x1e62 */ { true, 0x1e62, 0x1e63 }, +/* 0x1e63 */ { true, 0x1e62, 0x1e63 }, +/* 0x1e64 */ { true, 0x1e64, 0x1e65 }, +/* 0x1e65 */ { true, 0x1e64, 0x1e65 }, +/* 0x1e66 */ { true, 0x1e66, 0x1e67 }, +/* 0x1e67 */ { true, 0x1e66, 0x1e67 }, +/* 0x1e68 */ { true, 0x1e68, 0x1e69 }, +/* 0x1e69 */ { true, 0x1e68, 0x1e69 }, +/* 0x1e6a */ { true, 0x1e6a, 0x1e6b }, +/* 0x1e6b */ { true, 0x1e6a, 0x1e6b }, +/* 0x1e6c */ { true, 0x1e6c, 0x1e6d }, +/* 0x1e6d */ { true, 0x1e6c, 0x1e6d }, +/* 0x1e6e */ { true, 0x1e6e, 0x1e6f }, +/* 0x1e6f */ { true, 0x1e6e, 0x1e6f }, +/* 0x1e70 */ { true, 0x1e70, 0x1e71 }, +/* 0x1e71 */ { true, 0x1e70, 0x1e71 }, +/* 0x1e72 */ { true, 0x1e72, 0x1e73 }, +/* 0x1e73 */ { true, 0x1e72, 0x1e73 }, +/* 0x1e74 */ { true, 0x1e74, 0x1e75 }, +/* 0x1e75 */ { true, 0x1e74, 0x1e75 }, +/* 0x1e76 */ { true, 0x1e76, 0x1e77 }, +/* 0x1e77 */ { true, 0x1e76, 0x1e77 }, +/* 0x1e78 */ { true, 0x1e78, 0x1e79 }, +/* 0x1e79 */ { true, 0x1e78, 0x1e79 }, +/* 0x1e7a */ { true, 0x1e7a, 0x1e7b }, +/* 0x1e7b */ { true, 0x1e7a, 0x1e7b }, +/* 0x1e7c */ { true, 0x1e7c, 0x1e7d }, +/* 0x1e7d */ { true, 0x1e7c, 0x1e7d }, +/* 0x1e7e */ { true, 0x1e7e, 0x1e7f }, +/* 0x1e7f */ { true, 0x1e7e, 0x1e7f }, +/* 0x1e80 */ { true, 0x1e80, 0x1e81 }, +/* 0x1e81 */ { true, 0x1e80, 0x1e81 }, +/* 0x1e82 */ { true, 0x1e82, 0x1e83 }, +/* 0x1e83 */ { true, 0x1e82, 0x1e83 }, +/* 0x1e84 */ { true, 0x1e84, 0x1e85 }, +/* 0x1e85 */ { true, 0x1e84, 0x1e85 }, +/* 0x1e86 */ { true, 0x1e86, 0x1e87 }, +/* 0x1e87 */ { true, 0x1e86, 0x1e87 }, +/* 0x1e88 */ { true, 0x1e88, 0x1e89 }, +/* 0x1e89 */ { true, 0x1e88, 0x1e89 }, +/* 0x1e8a */ { true, 0x1e8a, 0x1e8b }, +/* 0x1e8b */ { true, 0x1e8a, 0x1e8b }, +/* 0x1e8c */ { true, 0x1e8c, 0x1e8d }, +/* 0x1e8d */ { true, 0x1e8c, 0x1e8d }, +/* 0x1e8e */ { true, 0x1e8e, 0x1e8f }, +/* 0x1e8f */ { true, 0x1e8e, 0x1e8f }, +/* 0x1e90 */ { true, 0x1e90, 0x1e91 }, +/* 0x1e91 */ { true, 0x1e90, 0x1e91 }, +/* 0x1e92 */ { true, 0x1e92, 0x1e93 }, +/* 0x1e93 */ { true, 0x1e92, 0x1e93 }, +/* 0x1e94 */ { true, 0x1e94, 0x1e95 }, +/* 0x1e95 */ { true, 0x1e94, 0x1e95 }, +/* 0x1e96 */ { true, 0x1e96, 0x1e96 }, +/* 0x1e97 */ { true, 0x1e97, 0x1e97 }, +/* 0x1e98 */ { true, 0x1e98, 0x1e98 }, +/* 0x1e99 */ { true, 0x1e99, 0x1e99 }, +/* 0x1e9a */ { true, 0x1e9a, 0x1e9a }, +/* 0x1e9b */ { true, 0x1e60, 0x1e9b }, +/* 0x1e9c */ { false, 0x1e9c, 0x1e9c }, +/* 0x1e9d */ { false, 0x1e9d, 0x1e9d }, +/* 0x1e9e */ { false, 0x1e9e, 0x1e9e }, +/* 0x1e9f */ { false, 0x1e9f, 0x1e9f }, +/* 0x1ea0 */ { true, 0x1ea0, 0x1ea1 }, +/* 0x1ea1 */ { true, 0x1ea0, 0x1ea1 }, +/* 0x1ea2 */ { true, 0x1ea2, 0x1ea3 }, +/* 0x1ea3 */ { true, 0x1ea2, 0x1ea3 }, +/* 0x1ea4 */ { true, 0x1ea4, 0x1ea5 }, +/* 0x1ea5 */ { true, 0x1ea4, 0x1ea5 }, +/* 0x1ea6 */ { true, 0x1ea6, 0x1ea7 }, +/* 0x1ea7 */ { true, 0x1ea6, 0x1ea7 }, +/* 0x1ea8 */ { true, 0x1ea8, 0x1ea9 }, +/* 0x1ea9 */ { true, 0x1ea8, 0x1ea9 }, +/* 0x1eaa */ { true, 0x1eaa, 0x1eab }, +/* 0x1eab */ { true, 0x1eaa, 0x1eab }, +/* 0x1eac */ { true, 0x1eac, 0x1ead }, +/* 0x1ead */ { true, 0x1eac, 0x1ead }, +/* 0x1eae */ { true, 0x1eae, 0x1eaf }, +/* 0x1eaf */ { true, 0x1eae, 0x1eaf }, +/* 0x1eb0 */ { true, 0x1eb0, 0x1eb1 }, +/* 0x1eb1 */ { true, 0x1eb0, 0x1eb1 }, +/* 0x1eb2 */ { true, 0x1eb2, 0x1eb3 }, +/* 0x1eb3 */ { true, 0x1eb2, 0x1eb3 }, +/* 0x1eb4 */ { true, 0x1eb4, 0x1eb5 }, +/* 0x1eb5 */ { true, 0x1eb4, 0x1eb5 }, +/* 0x1eb6 */ { true, 0x1eb6, 0x1eb7 }, +/* 0x1eb7 */ { true, 0x1eb6, 0x1eb7 }, +/* 0x1eb8 */ { true, 0x1eb8, 0x1eb9 }, +/* 0x1eb9 */ { true, 0x1eb8, 0x1eb9 }, +/* 0x1eba */ { true, 0x1eba, 0x1ebb }, +/* 0x1ebb */ { true, 0x1eba, 0x1ebb }, +/* 0x1ebc */ { true, 0x1ebc, 0x1ebd }, +/* 0x1ebd */ { true, 0x1ebc, 0x1ebd }, +/* 0x1ebe */ { true, 0x1ebe, 0x1ebf }, +/* 0x1ebf */ { true, 0x1ebe, 0x1ebf }, +/* 0x1ec0 */ { true, 0x1ec0, 0x1ec1 }, +/* 0x1ec1 */ { true, 0x1ec0, 0x1ec1 }, +/* 0x1ec2 */ { true, 0x1ec2, 0x1ec3 }, +/* 0x1ec3 */ { true, 0x1ec2, 0x1ec3 }, +/* 0x1ec4 */ { true, 0x1ec4, 0x1ec5 }, +/* 0x1ec5 */ { true, 0x1ec4, 0x1ec5 }, +/* 0x1ec6 */ { true, 0x1ec6, 0x1ec7 }, +/* 0x1ec7 */ { true, 0x1ec6, 0x1ec7 }, +/* 0x1ec8 */ { true, 0x1ec8, 0x1ec9 }, +/* 0x1ec9 */ { true, 0x1ec8, 0x1ec9 }, +/* 0x1eca */ { true, 0x1eca, 0x1ecb }, +/* 0x1ecb */ { true, 0x1eca, 0x1ecb }, +/* 0x1ecc */ { true, 0x1ecc, 0x1ecd }, +/* 0x1ecd */ { true, 0x1ecc, 0x1ecd }, +/* 0x1ece */ { true, 0x1ece, 0x1ecf }, +/* 0x1ecf */ { true, 0x1ece, 0x1ecf }, +/* 0x1ed0 */ { true, 0x1ed0, 0x1ed1 }, +/* 0x1ed1 */ { true, 0x1ed0, 0x1ed1 }, +/* 0x1ed2 */ { true, 0x1ed2, 0x1ed3 }, +/* 0x1ed3 */ { true, 0x1ed2, 0x1ed3 }, +/* 0x1ed4 */ { true, 0x1ed4, 0x1ed5 }, +/* 0x1ed5 */ { true, 0x1ed4, 0x1ed5 }, +/* 0x1ed6 */ { true, 0x1ed6, 0x1ed7 }, +/* 0x1ed7 */ { true, 0x1ed6, 0x1ed7 }, +/* 0x1ed8 */ { true, 0x1ed8, 0x1ed9 }, +/* 0x1ed9 */ { true, 0x1ed8, 0x1ed9 }, +/* 0x1eda */ { true, 0x1eda, 0x1edb }, +/* 0x1edb */ { true, 0x1eda, 0x1edb }, +/* 0x1edc */ { true, 0x1edc, 0x1edd }, +/* 0x1edd */ { true, 0x1edc, 0x1edd }, +/* 0x1ede */ { true, 0x1ede, 0x1edf }, +/* 0x1edf */ { true, 0x1ede, 0x1edf }, +/* 0x1ee0 */ { true, 0x1ee0, 0x1ee1 }, +/* 0x1ee1 */ { true, 0x1ee0, 0x1ee1 }, +/* 0x1ee2 */ { true, 0x1ee2, 0x1ee3 }, +/* 0x1ee3 */ { true, 0x1ee2, 0x1ee3 }, +/* 0x1ee4 */ { true, 0x1ee4, 0x1ee5 }, +/* 0x1ee5 */ { true, 0x1ee4, 0x1ee5 }, +/* 0x1ee6 */ { true, 0x1ee6, 0x1ee7 }, +/* 0x1ee7 */ { true, 0x1ee6, 0x1ee7 }, +/* 0x1ee8 */ { true, 0x1ee8, 0x1ee9 }, +/* 0x1ee9 */ { true, 0x1ee8, 0x1ee9 }, +/* 0x1eea */ { true, 0x1eea, 0x1eeb }, +/* 0x1eeb */ { true, 0x1eea, 0x1eeb }, +/* 0x1eec */ { true, 0x1eec, 0x1eed }, +/* 0x1eed */ { true, 0x1eec, 0x1eed }, +/* 0x1eee */ { true, 0x1eee, 0x1eef }, +/* 0x1eef */ { true, 0x1eee, 0x1eef }, +/* 0x1ef0 */ { true, 0x1ef0, 0x1ef1 }, +/* 0x1ef1 */ { true, 0x1ef0, 0x1ef1 }, +/* 0x1ef2 */ { true, 0x1ef2, 0x1ef3 }, +/* 0x1ef3 */ { true, 0x1ef2, 0x1ef3 }, +/* 0x1ef4 */ { true, 0x1ef4, 0x1ef5 }, +/* 0x1ef5 */ { true, 0x1ef4, 0x1ef5 }, +/* 0x1ef6 */ { true, 0x1ef6, 0x1ef7 }, +/* 0x1ef7 */ { true, 0x1ef6, 0x1ef7 }, +/* 0x1ef8 */ { true, 0x1ef8, 0x1ef9 }, +/* 0x1ef9 */ { true, 0x1ef8, 0x1ef9 }, +/* 0x1efa */ { false, 0x1efa, 0x1efa }, +/* 0x1efb */ { false, 0x1efb, 0x1efb }, +/* 0x1efc */ { false, 0x1efc, 0x1efc }, +/* 0x1efd */ { false, 0x1efd, 0x1efd }, +/* 0x1efe */ { false, 0x1efe, 0x1efe }, +/* 0x1eff */ { false, 0x1eff, 0x1eff }, +/* 0x1f00 */ { true, 0x1f08, 0x1f00 }, +/* 0x1f01 */ { true, 0x1f09, 0x1f01 }, +/* 0x1f02 */ { true, 0x1f0a, 0x1f02 }, +/* 0x1f03 */ { true, 0x1f0b, 0x1f03 }, +/* 0x1f04 */ { true, 0x1f0c, 0x1f04 }, +/* 0x1f05 */ { true, 0x1f0d, 0x1f05 }, +/* 0x1f06 */ { true, 0x1f0e, 0x1f06 }, +/* 0x1f07 */ { true, 0x1f0f, 0x1f07 }, +/* 0x1f08 */ { true, 0x1f08, 0x1f00 }, +/* 0x1f09 */ { true, 0x1f09, 0x1f01 }, +/* 0x1f0a */ { true, 0x1f0a, 0x1f02 }, +/* 0x1f0b */ { true, 0x1f0b, 0x1f03 }, +/* 0x1f0c */ { true, 0x1f0c, 0x1f04 }, +/* 0x1f0d */ { true, 0x1f0d, 0x1f05 }, +/* 0x1f0e */ { true, 0x1f0e, 0x1f06 }, +/* 0x1f0f */ { true, 0x1f0f, 0x1f07 }, +/* 0x1f10 */ { true, 0x1f18, 0x1f10 }, +/* 0x1f11 */ { true, 0x1f19, 0x1f11 }, +/* 0x1f12 */ { true, 0x1f1a, 0x1f12 }, +/* 0x1f13 */ { true, 0x1f1b, 0x1f13 }, +/* 0x1f14 */ { true, 0x1f1c, 0x1f14 }, +/* 0x1f15 */ { true, 0x1f1d, 0x1f15 }, +/* 0x1f16 */ { false, 0x1f16, 0x1f16 }, +/* 0x1f17 */ { false, 0x1f17, 0x1f17 }, +/* 0x1f18 */ { true, 0x1f18, 0x1f10 }, +/* 0x1f19 */ { true, 0x1f19, 0x1f11 }, +/* 0x1f1a */ { true, 0x1f1a, 0x1f12 }, +/* 0x1f1b */ { true, 0x1f1b, 0x1f13 }, +/* 0x1f1c */ { true, 0x1f1c, 0x1f14 }, +/* 0x1f1d */ { true, 0x1f1d, 0x1f15 }, +/* 0x1f1e */ { false, 0x1f1e, 0x1f1e }, +/* 0x1f1f */ { false, 0x1f1f, 0x1f1f }, +/* 0x1f20 */ { true, 0x1f28, 0x1f20 }, +/* 0x1f21 */ { true, 0x1f29, 0x1f21 }, +/* 0x1f22 */ { true, 0x1f2a, 0x1f22 }, +/* 0x1f23 */ { true, 0x1f2b, 0x1f23 }, +/* 0x1f24 */ { true, 0x1f2c, 0x1f24 }, +/* 0x1f25 */ { true, 0x1f2d, 0x1f25 }, +/* 0x1f26 */ { true, 0x1f2e, 0x1f26 }, +/* 0x1f27 */ { true, 0x1f2f, 0x1f27 }, +/* 0x1f28 */ { true, 0x1f28, 0x1f20 }, +/* 0x1f29 */ { true, 0x1f29, 0x1f21 }, +/* 0x1f2a */ { true, 0x1f2a, 0x1f22 }, +/* 0x1f2b */ { true, 0x1f2b, 0x1f23 }, +/* 0x1f2c */ { true, 0x1f2c, 0x1f24 }, +/* 0x1f2d */ { true, 0x1f2d, 0x1f25 }, +/* 0x1f2e */ { true, 0x1f2e, 0x1f26 }, +/* 0x1f2f */ { true, 0x1f2f, 0x1f27 }, +/* 0x1f30 */ { true, 0x1f38, 0x1f30 }, +/* 0x1f31 */ { true, 0x1f39, 0x1f31 }, +/* 0x1f32 */ { true, 0x1f3a, 0x1f32 }, +/* 0x1f33 */ { true, 0x1f3b, 0x1f33 }, +/* 0x1f34 */ { true, 0x1f3c, 0x1f34 }, +/* 0x1f35 */ { true, 0x1f3d, 0x1f35 }, +/* 0x1f36 */ { true, 0x1f3e, 0x1f36 }, +/* 0x1f37 */ { true, 0x1f3f, 0x1f37 }, +/* 0x1f38 */ { true, 0x1f38, 0x1f30 }, +/* 0x1f39 */ { true, 0x1f39, 0x1f31 }, +/* 0x1f3a */ { true, 0x1f3a, 0x1f32 }, +/* 0x1f3b */ { true, 0x1f3b, 0x1f33 }, +/* 0x1f3c */ { true, 0x1f3c, 0x1f34 }, +/* 0x1f3d */ { true, 0x1f3d, 0x1f35 }, +/* 0x1f3e */ { true, 0x1f3e, 0x1f36 }, +/* 0x1f3f */ { true, 0x1f3f, 0x1f37 }, +/* 0x1f40 */ { true, 0x1f48, 0x1f40 }, +/* 0x1f41 */ { true, 0x1f49, 0x1f41 }, +/* 0x1f42 */ { true, 0x1f4a, 0x1f42 }, +/* 0x1f43 */ { true, 0x1f4b, 0x1f43 }, +/* 0x1f44 */ { true, 0x1f4c, 0x1f44 }, +/* 0x1f45 */ { true, 0x1f4d, 0x1f45 }, +/* 0x1f46 */ { false, 0x1f46, 0x1f46 }, +/* 0x1f47 */ { false, 0x1f47, 0x1f47 }, +/* 0x1f48 */ { true, 0x1f48, 0x1f40 }, +/* 0x1f49 */ { true, 0x1f49, 0x1f41 }, +/* 0x1f4a */ { true, 0x1f4a, 0x1f42 }, +/* 0x1f4b */ { true, 0x1f4b, 0x1f43 }, +/* 0x1f4c */ { true, 0x1f4c, 0x1f44 }, +/* 0x1f4d */ { true, 0x1f4d, 0x1f45 }, +/* 0x1f4e */ { false, 0x1f4e, 0x1f4e }, +/* 0x1f4f */ { false, 0x1f4f, 0x1f4f }, +/* 0x1f50 */ { true, 0x1f50, 0x1f50 }, +/* 0x1f51 */ { true, 0x1f59, 0x1f51 }, +/* 0x1f52 */ { true, 0x1f52, 0x1f52 }, +/* 0x1f53 */ { true, 0x1f5b, 0x1f53 }, +/* 0x1f54 */ { true, 0x1f54, 0x1f54 }, +/* 0x1f55 */ { true, 0x1f5d, 0x1f55 }, +/* 0x1f56 */ { true, 0x1f56, 0x1f56 }, +/* 0x1f57 */ { true, 0x1f5f, 0x1f57 }, +/* 0x1f58 */ { false, 0x1f58, 0x1f58 }, +/* 0x1f59 */ { true, 0x1f59, 0x1f51 }, +/* 0x1f5a */ { false, 0x1f5a, 0x1f5a }, +/* 0x1f5b */ { true, 0x1f5b, 0x1f53 }, +/* 0x1f5c */ { false, 0x1f5c, 0x1f5c }, +/* 0x1f5d */ { true, 0x1f5d, 0x1f55 }, +/* 0x1f5e */ { false, 0x1f5e, 0x1f5e }, +/* 0x1f5f */ { true, 0x1f5f, 0x1f57 }, +/* 0x1f60 */ { true, 0x1f68, 0x1f60 }, +/* 0x1f61 */ { true, 0x1f69, 0x1f61 }, +/* 0x1f62 */ { true, 0x1f6a, 0x1f62 }, +/* 0x1f63 */ { true, 0x1f6b, 0x1f63 }, +/* 0x1f64 */ { true, 0x1f6c, 0x1f64 }, +/* 0x1f65 */ { true, 0x1f6d, 0x1f65 }, +/* 0x1f66 */ { true, 0x1f6e, 0x1f66 }, +/* 0x1f67 */ { true, 0x1f6f, 0x1f67 }, +/* 0x1f68 */ { true, 0x1f68, 0x1f60 }, +/* 0x1f69 */ { true, 0x1f69, 0x1f61 }, +/* 0x1f6a */ { true, 0x1f6a, 0x1f62 }, +/* 0x1f6b */ { true, 0x1f6b, 0x1f63 }, +/* 0x1f6c */ { true, 0x1f6c, 0x1f64 }, +/* 0x1f6d */ { true, 0x1f6d, 0x1f65 }, +/* 0x1f6e */ { true, 0x1f6e, 0x1f66 }, +/* 0x1f6f */ { true, 0x1f6f, 0x1f67 }, +/* 0x1f70 */ { true, 0x1fba, 0x1f70 }, +/* 0x1f71 */ { true, 0x1fbb, 0x1f71 }, +/* 0x1f72 */ { true, 0x1fc8, 0x1f72 }, +/* 0x1f73 */ { true, 0x1fc9, 0x1f73 }, +/* 0x1f74 */ { true, 0x1fca, 0x1f74 }, +/* 0x1f75 */ { true, 0x1fcb, 0x1f75 }, +/* 0x1f76 */ { true, 0x1fda, 0x1f76 }, +/* 0x1f77 */ { true, 0x1fdb, 0x1f77 }, +/* 0x1f78 */ { true, 0x1ff8, 0x1f78 }, +/* 0x1f79 */ { true, 0x1ff9, 0x1f79 }, +/* 0x1f7a */ { true, 0x1fea, 0x1f7a }, +/* 0x1f7b */ { true, 0x1feb, 0x1f7b }, +/* 0x1f7c */ { true, 0x1ffa, 0x1f7c }, +/* 0x1f7d */ { true, 0x1ffb, 0x1f7d }, +/* 0x1f7e */ { false, 0x1f7e, 0x1f7e }, +/* 0x1f7f */ { false, 0x1f7f, 0x1f7f }, +/* 0x1f80 */ { true, 0x1f88, 0x1f80 }, +/* 0x1f81 */ { true, 0x1f89, 0x1f81 }, +/* 0x1f82 */ { true, 0x1f8a, 0x1f82 }, +/* 0x1f83 */ { true, 0x1f8b, 0x1f83 }, +/* 0x1f84 */ { true, 0x1f8c, 0x1f84 }, +/* 0x1f85 */ { true, 0x1f8d, 0x1f85 }, +/* 0x1f86 */ { true, 0x1f8e, 0x1f86 }, +/* 0x1f87 */ { true, 0x1f8f, 0x1f87 }, +/* 0x1f88 */ { true, 0x1f88, 0x1f80 }, +/* 0x1f89 */ { true, 0x1f89, 0x1f81 }, +/* 0x1f8a */ { true, 0x1f8a, 0x1f82 }, +/* 0x1f8b */ { true, 0x1f8b, 0x1f83 }, +/* 0x1f8c */ { true, 0x1f8c, 0x1f84 }, +/* 0x1f8d */ { true, 0x1f8d, 0x1f85 }, +/* 0x1f8e */ { true, 0x1f8e, 0x1f86 }, +/* 0x1f8f */ { true, 0x1f8f, 0x1f87 }, +/* 0x1f90 */ { true, 0x1f98, 0x1f90 }, +/* 0x1f91 */ { true, 0x1f99, 0x1f91 }, +/* 0x1f92 */ { true, 0x1f9a, 0x1f92 }, +/* 0x1f93 */ { true, 0x1f9b, 0x1f93 }, +/* 0x1f94 */ { true, 0x1f9c, 0x1f94 }, +/* 0x1f95 */ { true, 0x1f9d, 0x1f95 }, +/* 0x1f96 */ { true, 0x1f9e, 0x1f96 }, +/* 0x1f97 */ { true, 0x1f9f, 0x1f97 }, +/* 0x1f98 */ { true, 0x1f98, 0x1f90 }, +/* 0x1f99 */ { true, 0x1f99, 0x1f91 }, +/* 0x1f9a */ { true, 0x1f9a, 0x1f92 }, +/* 0x1f9b */ { true, 0x1f9b, 0x1f93 }, +/* 0x1f9c */ { true, 0x1f9c, 0x1f94 }, +/* 0x1f9d */ { true, 0x1f9d, 0x1f95 }, +/* 0x1f9e */ { true, 0x1f9e, 0x1f96 }, +/* 0x1f9f */ { true, 0x1f9f, 0x1f97 }, +/* 0x1fa0 */ { true, 0x1fa8, 0x1fa0 }, +/* 0x1fa1 */ { true, 0x1fa9, 0x1fa1 }, +/* 0x1fa2 */ { true, 0x1faa, 0x1fa2 }, +/* 0x1fa3 */ { true, 0x1fab, 0x1fa3 }, +/* 0x1fa4 */ { true, 0x1fac, 0x1fa4 }, +/* 0x1fa5 */ { true, 0x1fad, 0x1fa5 }, +/* 0x1fa6 */ { true, 0x1fae, 0x1fa6 }, +/* 0x1fa7 */ { true, 0x1faf, 0x1fa7 }, +/* 0x1fa8 */ { true, 0x1fa8, 0x1fa0 }, +/* 0x1fa9 */ { true, 0x1fa9, 0x1fa1 }, +/* 0x1faa */ { true, 0x1faa, 0x1fa2 }, +/* 0x1fab */ { true, 0x1fab, 0x1fa3 }, +/* 0x1fac */ { true, 0x1fac, 0x1fa4 }, +/* 0x1fad */ { true, 0x1fad, 0x1fa5 }, +/* 0x1fae */ { true, 0x1fae, 0x1fa6 }, +/* 0x1faf */ { true, 0x1faf, 0x1fa7 }, +/* 0x1fb0 */ { true, 0x1fb8, 0x1fb0 }, +/* 0x1fb1 */ { true, 0x1fb9, 0x1fb1 }, +/* 0x1fb2 */ { true, 0x1fb2, 0x1fb2 }, +/* 0x1fb3 */ { true, 0x1fbc, 0x1fb3 }, +/* 0x1fb4 */ { true, 0x1fb4, 0x1fb4 }, +/* 0x1fb5 */ { false, 0x1fb5, 0x1fb5 }, +/* 0x1fb6 */ { true, 0x1fb6, 0x1fb6 }, +/* 0x1fb7 */ { true, 0x1fb7, 0x1fb7 }, +/* 0x1fb8 */ { true, 0x1fb8, 0x1fb0 }, +/* 0x1fb9 */ { true, 0x1fb9, 0x1fb1 }, +/* 0x1fba */ { true, 0x1fba, 0x1f70 }, +/* 0x1fbb */ { true, 0x1fbb, 0x1f71 }, +/* 0x1fbc */ { true, 0x1fbc, 0x1fb3 }, +/* 0x1fbd */ { false, 0x1fbd, 0x1fbd }, +/* 0x1fbe */ { true, 0x0399, 0x1fbe }, +/* 0x1fbf */ { false, 0x1fbf, 0x1fbf }, +/* 0x1fc0 */ { false, 0x1fc0, 0x1fc0 }, +/* 0x1fc1 */ { false, 0x1fc1, 0x1fc1 }, +/* 0x1fc2 */ { true, 0x1fc2, 0x1fc2 }, +/* 0x1fc3 */ { true, 0x1fcc, 0x1fc3 }, +/* 0x1fc4 */ { true, 0x1fc4, 0x1fc4 }, +/* 0x1fc5 */ { false, 0x1fc5, 0x1fc5 }, +/* 0x1fc6 */ { true, 0x1fc6, 0x1fc6 }, +/* 0x1fc7 */ { true, 0x1fc7, 0x1fc7 }, +/* 0x1fc8 */ { true, 0x1fc8, 0x1f72 }, +/* 0x1fc9 */ { true, 0x1fc9, 0x1f73 }, +/* 0x1fca */ { true, 0x1fca, 0x1f74 }, +/* 0x1fcb */ { true, 0x1fcb, 0x1f75 }, +/* 0x1fcc */ { true, 0x1fcc, 0x1fc3 }, +/* 0x1fcd */ { false, 0x1fcd, 0x1fcd }, +/* 0x1fce */ { false, 0x1fce, 0x1fce }, +/* 0x1fcf */ { false, 0x1fcf, 0x1fcf }, +/* 0x1fd0 */ { true, 0x1fd8, 0x1fd0 }, +/* 0x1fd1 */ { true, 0x1fd9, 0x1fd1 }, +/* 0x1fd2 */ { true, 0x1fd2, 0x1fd2 }, +/* 0x1fd3 */ { true, 0x1fd3, 0x1fd3 }, +/* 0x1fd4 */ { false, 0x1fd4, 0x1fd4 }, +/* 0x1fd5 */ { false, 0x1fd5, 0x1fd5 }, +/* 0x1fd6 */ { true, 0x1fd6, 0x1fd6 }, +/* 0x1fd7 */ { true, 0x1fd7, 0x1fd7 }, +/* 0x1fd8 */ { true, 0x1fd8, 0x1fd0 }, +/* 0x1fd9 */ { true, 0x1fd9, 0x1fd1 }, +/* 0x1fda */ { true, 0x1fda, 0x1f76 }, +/* 0x1fdb */ { true, 0x1fdb, 0x1f77 }, +/* 0x1fdc */ { false, 0x1fdc, 0x1fdc }, +/* 0x1fdd */ { false, 0x1fdd, 0x1fdd }, +/* 0x1fde */ { false, 0x1fde, 0x1fde }, +/* 0x1fdf */ { false, 0x1fdf, 0x1fdf }, +/* 0x1fe0 */ { true, 0x1fe8, 0x1fe0 }, +/* 0x1fe1 */ { true, 0x1fe9, 0x1fe1 }, +/* 0x1fe2 */ { true, 0x1fe2, 0x1fe2 }, +/* 0x1fe3 */ { true, 0x1fe3, 0x1fe3 }, +/* 0x1fe4 */ { true, 0x1fe4, 0x1fe4 }, +/* 0x1fe5 */ { true, 0x1fec, 0x1fe5 }, +/* 0x1fe6 */ { true, 0x1fe6, 0x1fe6 }, +/* 0x1fe7 */ { true, 0x1fe7, 0x1fe7 }, +/* 0x1fe8 */ { true, 0x1fe8, 0x1fe0 }, +/* 0x1fe9 */ { true, 0x1fe9, 0x1fe1 }, +/* 0x1fea */ { true, 0x1fea, 0x1f7a }, +/* 0x1feb */ { true, 0x1feb, 0x1f7b }, +/* 0x1fec */ { true, 0x1fec, 0x1fe5 }, +/* 0x1fed */ { false, 0x1fed, 0x1fed }, +/* 0x1fee */ { false, 0x1fee, 0x1fee }, +/* 0x1fef */ { false, 0x1fef, 0x1fef }, +/* 0x1ff0 */ { false, 0x1ff0, 0x1ff0 }, +/* 0x1ff1 */ { false, 0x1ff1, 0x1ff1 }, +/* 0x1ff2 */ { true, 0x1ff2, 0x1ff2 }, +/* 0x1ff3 */ { true, 0x1ffc, 0x1ff3 }, +/* 0x1ff4 */ { true, 0x1ff4, 0x1ff4 }, +/* 0x1ff5 */ { false, 0x1ff5, 0x1ff5 }, +/* 0x1ff6 */ { true, 0x1ff6, 0x1ff6 }, +/* 0x1ff7 */ { true, 0x1ff7, 0x1ff7 }, +/* 0x1ff8 */ { true, 0x1ff8, 0x1f78 }, +/* 0x1ff9 */ { true, 0x1ff9, 0x1f79 }, +/* 0x1ffa */ { true, 0x1ffa, 0x1f7c }, +/* 0x1ffb */ { true, 0x1ffb, 0x1f7d }, +/* 0x1ffc */ { true, 0x1ffc, 0x1ff3 }, +/* 0x1ffd */ { false, 0x1ffd, 0x1ffd }, +/* 0x1ffe */ { false, 0x1ffe, 0x1ffe }, +/* 0x1fff */ { false, 0x1fff, 0x1fff }, +/* 0x2000 */ { false, 0x2000, 0x2000 }, +/* 0x2001 */ { false, 0x2001, 0x2001 }, +/* 0x2002 */ { false, 0x2002, 0x2002 }, +/* 0x2003 */ { false, 0x2003, 0x2003 }, +/* 0x2004 */ { false, 0x2004, 0x2004 }, +/* 0x2005 */ { false, 0x2005, 0x2005 }, +/* 0x2006 */ { false, 0x2006, 0x2006 }, +/* 0x2007 */ { false, 0x2007, 0x2007 }, +/* 0x2008 */ { false, 0x2008, 0x2008 }, +/* 0x2009 */ { false, 0x2009, 0x2009 }, +/* 0x200a */ { false, 0x200a, 0x200a }, +/* 0x200b */ { false, 0x200b, 0x200b }, +/* 0x200c */ { false, 0x200c, 0x200c }, +/* 0x200d */ { false, 0x200d, 0x200d }, +/* 0x200e */ { false, 0x200e, 0x200e }, +/* 0x200f */ { false, 0x200f, 0x200f }, +/* 0x2010 */ { false, 0x2010, 0x2010 }, +/* 0x2011 */ { false, 0x2011, 0x2011 }, +/* 0x2012 */ { false, 0x2012, 0x2012 }, +/* 0x2013 */ { false, 0x2013, 0x2013 }, +/* 0x2014 */ { false, 0x2014, 0x2014 }, +/* 0x2015 */ { false, 0x2015, 0x2015 }, +/* 0x2016 */ { false, 0x2016, 0x2016 }, +/* 0x2017 */ { false, 0x2017, 0x2017 }, +/* 0x2018 */ { false, 0x2018, 0x2018 }, +/* 0x2019 */ { false, 0x2019, 0x2019 }, +/* 0x201a */ { false, 0x201a, 0x201a }, +/* 0x201b */ { false, 0x201b, 0x201b }, +/* 0x201c */ { false, 0x201c, 0x201c }, +/* 0x201d */ { false, 0x201d, 0x201d }, +/* 0x201e */ { false, 0x201e, 0x201e }, +/* 0x201f */ { false, 0x201f, 0x201f }, +/* 0x2020 */ { false, 0x2020, 0x2020 }, +/* 0x2021 */ { false, 0x2021, 0x2021 }, +/* 0x2022 */ { false, 0x2022, 0x2022 }, +/* 0x2023 */ { false, 0x2023, 0x2023 }, +/* 0x2024 */ { false, 0x2024, 0x2024 }, +/* 0x2025 */ { false, 0x2025, 0x2025 }, +/* 0x2026 */ { false, 0x2026, 0x2026 }, +/* 0x2027 */ { false, 0x2027, 0x2027 }, +/* 0x2028 */ { false, 0x2028, 0x2028 }, +/* 0x2029 */ { false, 0x2029, 0x2029 }, +/* 0x202a */ { false, 0x202a, 0x202a }, +/* 0x202b */ { false, 0x202b, 0x202b }, +/* 0x202c */ { false, 0x202c, 0x202c }, +/* 0x202d */ { false, 0x202d, 0x202d }, +/* 0x202e */ { false, 0x202e, 0x202e }, +/* 0x202f */ { false, 0x202f, 0x202f }, +/* 0x2030 */ { false, 0x2030, 0x2030 }, +/* 0x2031 */ { false, 0x2031, 0x2031 }, +/* 0x2032 */ { false, 0x2032, 0x2032 }, +/* 0x2033 */ { false, 0x2033, 0x2033 }, +/* 0x2034 */ { false, 0x2034, 0x2034 }, +/* 0x2035 */ { false, 0x2035, 0x2035 }, +/* 0x2036 */ { false, 0x2036, 0x2036 }, +/* 0x2037 */ { false, 0x2037, 0x2037 }, +/* 0x2038 */ { false, 0x2038, 0x2038 }, +/* 0x2039 */ { false, 0x2039, 0x2039 }, +/* 0x203a */ { false, 0x203a, 0x203a }, +/* 0x203b */ { false, 0x203b, 0x203b }, +/* 0x203c */ { false, 0x203c, 0x203c }, +/* 0x203d */ { false, 0x203d, 0x203d }, +/* 0x203e */ { false, 0x203e, 0x203e }, +/* 0x203f */ { false, 0x203f, 0x203f }, +/* 0x2040 */ { false, 0x2040, 0x2040 }, +/* 0x2041 */ { false, 0x2041, 0x2041 }, +/* 0x2042 */ { false, 0x2042, 0x2042 }, +/* 0x2043 */ { false, 0x2043, 0x2043 }, +/* 0x2044 */ { false, 0x2044, 0x2044 }, +/* 0x2045 */ { false, 0x2045, 0x2045 }, +/* 0x2046 */ { false, 0x2046, 0x2046 }, +/* 0x2047 */ { false, 0x2047, 0x2047 }, +/* 0x2048 */ { false, 0x2048, 0x2048 }, +/* 0x2049 */ { false, 0x2049, 0x2049 }, +/* 0x204a */ { false, 0x204a, 0x204a }, +/* 0x204b */ { false, 0x204b, 0x204b }, +/* 0x204c */ { false, 0x204c, 0x204c }, +/* 0x204d */ { false, 0x204d, 0x204d }, +/* 0x204e */ { false, 0x204e, 0x204e }, +/* 0x204f */ { false, 0x204f, 0x204f }, +/* 0x2050 */ { false, 0x2050, 0x2050 }, +/* 0x2051 */ { false, 0x2051, 0x2051 }, +/* 0x2052 */ { false, 0x2052, 0x2052 }, +/* 0x2053 */ { false, 0x2053, 0x2053 }, +/* 0x2054 */ { false, 0x2054, 0x2054 }, +/* 0x2055 */ { false, 0x2055, 0x2055 }, +/* 0x2056 */ { false, 0x2056, 0x2056 }, +/* 0x2057 */ { false, 0x2057, 0x2057 }, +/* 0x2058 */ { false, 0x2058, 0x2058 }, +/* 0x2059 */ { false, 0x2059, 0x2059 }, +/* 0x205a */ { false, 0x205a, 0x205a }, +/* 0x205b */ { false, 0x205b, 0x205b }, +/* 0x205c */ { false, 0x205c, 0x205c }, +/* 0x205d */ { false, 0x205d, 0x205d }, +/* 0x205e */ { false, 0x205e, 0x205e }, +/* 0x205f */ { false, 0x205f, 0x205f }, +/* 0x2060 */ { false, 0x2060, 0x2060 }, +/* 0x2061 */ { false, 0x2061, 0x2061 }, +/* 0x2062 */ { false, 0x2062, 0x2062 }, +/* 0x2063 */ { false, 0x2063, 0x2063 }, +/* 0x2064 */ { false, 0x2064, 0x2064 }, +/* 0x2065 */ { false, 0x2065, 0x2065 }, +/* 0x2066 */ { false, 0x2066, 0x2066 }, +/* 0x2067 */ { false, 0x2067, 0x2067 }, +/* 0x2068 */ { false, 0x2068, 0x2068 }, +/* 0x2069 */ { false, 0x2069, 0x2069 }, +/* 0x206a */ { false, 0x206a, 0x206a }, +/* 0x206b */ { false, 0x206b, 0x206b }, +/* 0x206c */ { false, 0x206c, 0x206c }, +/* 0x206d */ { false, 0x206d, 0x206d }, +/* 0x206e */ { false, 0x206e, 0x206e }, +/* 0x206f */ { false, 0x206f, 0x206f }, +/* 0x2070 */ { false, 0x2070, 0x2070 }, +/* 0x2071 */ { true, 0x2071, 0x2071 }, +/* 0x2072 */ { false, 0x2072, 0x2072 }, +/* 0x2073 */ { false, 0x2073, 0x2073 }, +/* 0x2074 */ { false, 0x2074, 0x2074 }, +/* 0x2075 */ { false, 0x2075, 0x2075 }, +/* 0x2076 */ { false, 0x2076, 0x2076 }, +/* 0x2077 */ { false, 0x2077, 0x2077 }, +/* 0x2078 */ { false, 0x2078, 0x2078 }, +/* 0x2079 */ { false, 0x2079, 0x2079 }, +/* 0x207a */ { false, 0x207a, 0x207a }, +/* 0x207b */ { false, 0x207b, 0x207b }, +/* 0x207c */ { false, 0x207c, 0x207c }, +/* 0x207d */ { false, 0x207d, 0x207d }, +/* 0x207e */ { false, 0x207e, 0x207e }, +/* 0x207f */ { true, 0x207f, 0x207f }, +/* 0x2080 */ { false, 0x2080, 0x2080 }, +/* 0x2081 */ { false, 0x2081, 0x2081 }, +/* 0x2082 */ { false, 0x2082, 0x2082 }, +/* 0x2083 */ { false, 0x2083, 0x2083 }, +/* 0x2084 */ { false, 0x2084, 0x2084 }, +/* 0x2085 */ { false, 0x2085, 0x2085 }, +/* 0x2086 */ { false, 0x2086, 0x2086 }, +/* 0x2087 */ { false, 0x2087, 0x2087 }, +/* 0x2088 */ { false, 0x2088, 0x2088 }, +/* 0x2089 */ { false, 0x2089, 0x2089 }, +/* 0x208a */ { false, 0x208a, 0x208a }, +/* 0x208b */ { false, 0x208b, 0x208b }, +/* 0x208c */ { false, 0x208c, 0x208c }, +/* 0x208d */ { false, 0x208d, 0x208d }, +/* 0x208e */ { false, 0x208e, 0x208e }, +/* 0x208f */ { false, 0x208f, 0x208f }, +/* 0x2090 */ { true, 0x2090, 0x2090 }, +/* 0x2091 */ { true, 0x2091, 0x2091 }, +/* 0x2092 */ { true, 0x2092, 0x2092 }, +/* 0x2093 */ { true, 0x2093, 0x2093 }, +/* 0x2094 */ { true, 0x2094, 0x2094 }, +/* 0x2095 */ { false, 0x2095, 0x2095 }, +/* 0x2096 */ { false, 0x2096, 0x2096 }, +/* 0x2097 */ { false, 0x2097, 0x2097 }, +/* 0x2098 */ { false, 0x2098, 0x2098 }, +/* 0x2099 */ { false, 0x2099, 0x2099 }, +/* 0x209a */ { false, 0x209a, 0x209a }, +/* 0x209b */ { false, 0x209b, 0x209b }, +/* 0x209c */ { false, 0x209c, 0x209c }, +/* 0x209d */ { false, 0x209d, 0x209d }, +/* 0x209e */ { false, 0x209e, 0x209e }, +/* 0x209f */ { false, 0x209f, 0x209f }, +/* 0x20a0 */ { false, 0x20a0, 0x20a0 }, +/* 0x20a1 */ { false, 0x20a1, 0x20a1 }, +/* 0x20a2 */ { false, 0x20a2, 0x20a2 }, +/* 0x20a3 */ { false, 0x20a3, 0x20a3 }, +/* 0x20a4 */ { false, 0x20a4, 0x20a4 }, +/* 0x20a5 */ { false, 0x20a5, 0x20a5 }, +/* 0x20a6 */ { false, 0x20a6, 0x20a6 }, +/* 0x20a7 */ { false, 0x20a7, 0x20a7 }, +/* 0x20a8 */ { false, 0x20a8, 0x20a8 }, +/* 0x20a9 */ { false, 0x20a9, 0x20a9 }, +/* 0x20aa */ { false, 0x20aa, 0x20aa }, +/* 0x20ab */ { false, 0x20ab, 0x20ab }, +/* 0x20ac */ { false, 0x20ac, 0x20ac }, +/* 0x20ad */ { false, 0x20ad, 0x20ad }, +/* 0x20ae */ { false, 0x20ae, 0x20ae }, +/* 0x20af */ { false, 0x20af, 0x20af }, +/* 0x20b0 */ { false, 0x20b0, 0x20b0 }, +/* 0x20b1 */ { false, 0x20b1, 0x20b1 }, +/* 0x20b2 */ { false, 0x20b2, 0x20b2 }, +/* 0x20b3 */ { false, 0x20b3, 0x20b3 }, +/* 0x20b4 */ { false, 0x20b4, 0x20b4 }, +/* 0x20b5 */ { false, 0x20b5, 0x20b5 }, +/* 0x20b6 */ { false, 0x20b6, 0x20b6 }, +/* 0x20b7 */ { false, 0x20b7, 0x20b7 }, +/* 0x20b8 */ { false, 0x20b8, 0x20b8 }, +/* 0x20b9 */ { false, 0x20b9, 0x20b9 }, +/* 0x20ba */ { false, 0x20ba, 0x20ba }, +/* 0x20bb */ { false, 0x20bb, 0x20bb }, +/* 0x20bc */ { false, 0x20bc, 0x20bc }, +/* 0x20bd */ { false, 0x20bd, 0x20bd }, +/* 0x20be */ { false, 0x20be, 0x20be }, +/* 0x20bf */ { false, 0x20bf, 0x20bf }, +/* 0x20c0 */ { false, 0x20c0, 0x20c0 }, +/* 0x20c1 */ { false, 0x20c1, 0x20c1 }, +/* 0x20c2 */ { false, 0x20c2, 0x20c2 }, +/* 0x20c3 */ { false, 0x20c3, 0x20c3 }, +/* 0x20c4 */ { false, 0x20c4, 0x20c4 }, +/* 0x20c5 */ { false, 0x20c5, 0x20c5 }, +/* 0x20c6 */ { false, 0x20c6, 0x20c6 }, +/* 0x20c7 */ { false, 0x20c7, 0x20c7 }, +/* 0x20c8 */ { false, 0x20c8, 0x20c8 }, +/* 0x20c9 */ { false, 0x20c9, 0x20c9 }, +/* 0x20ca */ { false, 0x20ca, 0x20ca }, +/* 0x20cb */ { false, 0x20cb, 0x20cb }, +/* 0x20cc */ { false, 0x20cc, 0x20cc }, +/* 0x20cd */ { false, 0x20cd, 0x20cd }, +/* 0x20ce */ { false, 0x20ce, 0x20ce }, +/* 0x20cf */ { false, 0x20cf, 0x20cf }, +/* 0x20d0 */ { true, 0x20d0, 0x20d0 }, +/* 0x20d1 */ { true, 0x20d1, 0x20d1 }, +/* 0x20d2 */ { true, 0x20d2, 0x20d2 }, +/* 0x20d3 */ { true, 0x20d3, 0x20d3 }, +/* 0x20d4 */ { true, 0x20d4, 0x20d4 }, +/* 0x20d5 */ { true, 0x20d5, 0x20d5 }, +/* 0x20d6 */ { true, 0x20d6, 0x20d6 }, +/* 0x20d7 */ { true, 0x20d7, 0x20d7 }, +/* 0x20d8 */ { true, 0x20d8, 0x20d8 }, +/* 0x20d9 */ { true, 0x20d9, 0x20d9 }, +/* 0x20da */ { true, 0x20da, 0x20da }, +/* 0x20db */ { true, 0x20db, 0x20db }, +/* 0x20dc */ { true, 0x20dc, 0x20dc }, +/* 0x20dd */ { false, 0x20dd, 0x20dd }, +/* 0x20de */ { false, 0x20de, 0x20de }, +/* 0x20df */ { false, 0x20df, 0x20df }, +/* 0x20e0 */ { false, 0x20e0, 0x20e0 }, +/* 0x20e1 */ { true, 0x20e1, 0x20e1 }, +/* 0x20e2 */ { false, 0x20e2, 0x20e2 }, +/* 0x20e3 */ { false, 0x20e3, 0x20e3 }, +/* 0x20e4 */ { false, 0x20e4, 0x20e4 }, +/* 0x20e5 */ { true, 0x20e5, 0x20e5 }, +/* 0x20e6 */ { true, 0x20e6, 0x20e6 }, +/* 0x20e7 */ { true, 0x20e7, 0x20e7 }, +/* 0x20e8 */ { true, 0x20e8, 0x20e8 }, +/* 0x20e9 */ { true, 0x20e9, 0x20e9 }, +/* 0x20ea */ { true, 0x20ea, 0x20ea }, +/* 0x20eb */ { true, 0x20eb, 0x20eb }, +/* 0x20ec */ { false, 0x20ec, 0x20ec }, +/* 0x20ed */ { false, 0x20ed, 0x20ed }, +/* 0x20ee */ { false, 0x20ee, 0x20ee }, +/* 0x20ef */ { false, 0x20ef, 0x20ef }, +/* 0x20f0 */ { false, 0x20f0, 0x20f0 }, +/* 0x20f1 */ { false, 0x20f1, 0x20f1 }, +/* 0x20f2 */ { false, 0x20f2, 0x20f2 }, +/* 0x20f3 */ { false, 0x20f3, 0x20f3 }, +/* 0x20f4 */ { false, 0x20f4, 0x20f4 }, +/* 0x20f5 */ { false, 0x20f5, 0x20f5 }, +/* 0x20f6 */ { false, 0x20f6, 0x20f6 }, +/* 0x20f7 */ { false, 0x20f7, 0x20f7 }, +/* 0x20f8 */ { false, 0x20f8, 0x20f8 }, +/* 0x20f9 */ { false, 0x20f9, 0x20f9 }, +/* 0x20fa */ { false, 0x20fa, 0x20fa }, +/* 0x20fb */ { false, 0x20fb, 0x20fb }, +/* 0x20fc */ { false, 0x20fc, 0x20fc }, +/* 0x20fd */ { false, 0x20fd, 0x20fd }, +/* 0x20fe */ { false, 0x20fe, 0x20fe }, +/* 0x20ff */ { false, 0x20ff, 0x20ff }, +/* 0x2100 */ { false, 0x2100, 0x2100 }, +/* 0x2101 */ { false, 0x2101, 0x2101 }, +/* 0x2102 */ { true, 0x2102, 0x2102 }, +/* 0x2103 */ { false, 0x2103, 0x2103 }, +/* 0x2104 */ { false, 0x2104, 0x2104 }, +/* 0x2105 */ { false, 0x2105, 0x2105 }, +/* 0x2106 */ { false, 0x2106, 0x2106 }, +/* 0x2107 */ { true, 0x2107, 0x2107 }, +/* 0x2108 */ { false, 0x2108, 0x2108 }, +/* 0x2109 */ { false, 0x2109, 0x2109 }, +/* 0x210a */ { true, 0x210a, 0x210a }, +/* 0x210b */ { true, 0x210b, 0x210b }, +/* 0x210c */ { true, 0x210c, 0x210c }, +/* 0x210d */ { true, 0x210d, 0x210d }, +/* 0x210e */ { true, 0x210e, 0x210e }, +/* 0x210f */ { true, 0x210f, 0x210f }, +/* 0x2110 */ { true, 0x2110, 0x2110 }, +/* 0x2111 */ { true, 0x2111, 0x2111 }, +/* 0x2112 */ { true, 0x2112, 0x2112 }, +/* 0x2113 */ { true, 0x2113, 0x2113 }, +/* 0x2114 */ { false, 0x2114, 0x2114 }, +/* 0x2115 */ { true, 0x2115, 0x2115 }, +/* 0x2116 */ { false, 0x2116, 0x2116 }, +/* 0x2117 */ { false, 0x2117, 0x2117 }, +/* 0x2118 */ { false, 0x2118, 0x2118 }, +/* 0x2119 */ { true, 0x2119, 0x2119 }, +/* 0x211a */ { true, 0x211a, 0x211a }, +/* 0x211b */ { true, 0x211b, 0x211b }, +/* 0x211c */ { true, 0x211c, 0x211c }, +/* 0x211d */ { true, 0x211d, 0x211d }, +/* 0x211e */ { false, 0x211e, 0x211e }, +/* 0x211f */ { false, 0x211f, 0x211f }, +/* 0x2120 */ { false, 0x2120, 0x2120 }, +/* 0x2121 */ { false, 0x2121, 0x2121 }, +/* 0x2122 */ { false, 0x2122, 0x2122 }, +/* 0x2123 */ { false, 0x2123, 0x2123 }, +/* 0x2124 */ { true, 0x2124, 0x2124 }, +/* 0x2125 */ { false, 0x2125, 0x2125 }, +/* 0x2126 */ { true, 0x2126, 0x03c9 }, +/* 0x2127 */ { false, 0x2127, 0x2127 }, +/* 0x2128 */ { true, 0x2128, 0x2128 }, +/* 0x2129 */ { false, 0x2129, 0x2129 }, +/* 0x212a */ { true, 0x212a, 0x006b }, +/* 0x212b */ { true, 0x212b, 0x00e5 }, +/* 0x212c */ { true, 0x212c, 0x212c }, +/* 0x212d */ { true, 0x212d, 0x212d }, +/* 0x212e */ { false, 0x212e, 0x212e }, +/* 0x212f */ { true, 0x212f, 0x212f }, +/* 0x2130 */ { true, 0x2130, 0x2130 }, +/* 0x2131 */ { true, 0x2131, 0x2131 }, +/* 0x2132 */ { false, 0x2132, 0x2132 }, +/* 0x2133 */ { true, 0x2133, 0x2133 }, +/* 0x2134 */ { true, 0x2134, 0x2134 }, +/* 0x2135 */ { true, 0x2135, 0x2135 }, +/* 0x2136 */ { true, 0x2136, 0x2136 }, +/* 0x2137 */ { true, 0x2137, 0x2137 }, +/* 0x2138 */ { true, 0x2138, 0x2138 }, +/* 0x2139 */ { true, 0x2139, 0x2139 }, +/* 0x213a */ { false, 0x213a, 0x213a }, +/* 0x213b */ { false, 0x213b, 0x213b }, +/* 0x213c */ { true, 0x213c, 0x213c }, +/* 0x213d */ { true, 0x213d, 0x213d }, +/* 0x213e */ { true, 0x213e, 0x213e }, +/* 0x213f */ { true, 0x213f, 0x213f }, +/* 0x2140 */ { false, 0x2140, 0x2140 }, +/* 0x2141 */ { false, 0x2141, 0x2141 }, +/* 0x2142 */ { false, 0x2142, 0x2142 }, +/* 0x2143 */ { false, 0x2143, 0x2143 }, +/* 0x2144 */ { false, 0x2144, 0x2144 }, +/* 0x2145 */ { true, 0x2145, 0x2145 }, +/* 0x2146 */ { true, 0x2146, 0x2146 }, +/* 0x2147 */ { true, 0x2147, 0x2147 }, +/* 0x2148 */ { true, 0x2148, 0x2148 }, +/* 0x2149 */ { true, 0x2149, 0x2149 }, +/* 0x214a */ { false, 0x214a, 0x214a }, +/* 0x214b */ { false, 0x214b, 0x214b }, +/* 0x214c */ { false, 0x214c, 0x214c }, +/* 0x214d */ { false, 0x214d, 0x214d }, +/* 0x214e */ { false, 0x214e, 0x214e }, +/* 0x214f */ { false, 0x214f, 0x214f }, +/* 0x2150 */ { false, 0x2150, 0x2150 }, +/* 0x2151 */ { false, 0x2151, 0x2151 }, +/* 0x2152 */ { false, 0x2152, 0x2152 }, +/* 0x2153 */ { false, 0x2153, 0x2153 }, +/* 0x2154 */ { false, 0x2154, 0x2154 }, +/* 0x2155 */ { false, 0x2155, 0x2155 }, +/* 0x2156 */ { false, 0x2156, 0x2156 }, +/* 0x2157 */ { false, 0x2157, 0x2157 }, +/* 0x2158 */ { false, 0x2158, 0x2158 }, +/* 0x2159 */ { false, 0x2159, 0x2159 }, +/* 0x215a */ { false, 0x215a, 0x215a }, +/* 0x215b */ { false, 0x215b, 0x215b }, +/* 0x215c */ { false, 0x215c, 0x215c }, +/* 0x215d */ { false, 0x215d, 0x215d }, +/* 0x215e */ { false, 0x215e, 0x215e }, +/* 0x215f */ { false, 0x215f, 0x215f }, +/* 0x2160 */ { false, 0x2160, 0x2160 }, +/* 0x2161 */ { false, 0x2161, 0x2161 }, +/* 0x2162 */ { false, 0x2162, 0x2162 }, +/* 0x2163 */ { false, 0x2163, 0x2163 }, +/* 0x2164 */ { false, 0x2164, 0x2164 }, +/* 0x2165 */ { false, 0x2165, 0x2165 }, +/* 0x2166 */ { false, 0x2166, 0x2166 }, +/* 0x2167 */ { false, 0x2167, 0x2167 }, +/* 0x2168 */ { false, 0x2168, 0x2168 }, +/* 0x2169 */ { false, 0x2169, 0x2169 }, +/* 0x216a */ { false, 0x216a, 0x216a }, +/* 0x216b */ { false, 0x216b, 0x216b }, +/* 0x216c */ { false, 0x216c, 0x216c }, +/* 0x216d */ { false, 0x216d, 0x216d }, +/* 0x216e */ { false, 0x216e, 0x216e }, +/* 0x216f */ { false, 0x216f, 0x216f }, +/* 0x2170 */ { false, 0x2170, 0x2170 }, +/* 0x2171 */ { false, 0x2171, 0x2171 }, +/* 0x2172 */ { false, 0x2172, 0x2172 }, +/* 0x2173 */ { false, 0x2173, 0x2173 }, +/* 0x2174 */ { false, 0x2174, 0x2174 }, +/* 0x2175 */ { false, 0x2175, 0x2175 }, +/* 0x2176 */ { false, 0x2176, 0x2176 }, +/* 0x2177 */ { false, 0x2177, 0x2177 }, +/* 0x2178 */ { false, 0x2178, 0x2178 }, +/* 0x2179 */ { false, 0x2179, 0x2179 }, +/* 0x217a */ { false, 0x217a, 0x217a }, +/* 0x217b */ { false, 0x217b, 0x217b }, +/* 0x217c */ { false, 0x217c, 0x217c }, +/* 0x217d */ { false, 0x217d, 0x217d }, +/* 0x217e */ { false, 0x217e, 0x217e }, +/* 0x217f */ { false, 0x217f, 0x217f }, +/* 0x2180 */ { false, 0x2180, 0x2180 }, +/* 0x2181 */ { false, 0x2181, 0x2181 }, +/* 0x2182 */ { false, 0x2182, 0x2182 }, +/* 0x2183 */ { false, 0x2183, 0x2183 }, +/* 0x2184 */ { false, 0x2184, 0x2184 }, +/* 0x2185 */ { false, 0x2185, 0x2185 }, +/* 0x2186 */ { false, 0x2186, 0x2186 }, +/* 0x2187 */ { false, 0x2187, 0x2187 }, +/* 0x2188 */ { false, 0x2188, 0x2188 }, +/* 0x2189 */ { false, 0x2189, 0x2189 }, +/* 0x218a */ { false, 0x218a, 0x218a }, +/* 0x218b */ { false, 0x218b, 0x218b }, +/* 0x218c */ { false, 0x218c, 0x218c }, +/* 0x218d */ { false, 0x218d, 0x218d }, +/* 0x218e */ { false, 0x218e, 0x218e }, +/* 0x218f */ { false, 0x218f, 0x218f }, +/* 0x2190 */ { false, 0x2190, 0x2190 }, +/* 0x2191 */ { false, 0x2191, 0x2191 }, +/* 0x2192 */ { false, 0x2192, 0x2192 }, +/* 0x2193 */ { false, 0x2193, 0x2193 }, +/* 0x2194 */ { false, 0x2194, 0x2194 }, +/* 0x2195 */ { false, 0x2195, 0x2195 }, +/* 0x2196 */ { false, 0x2196, 0x2196 }, +/* 0x2197 */ { false, 0x2197, 0x2197 }, +/* 0x2198 */ { false, 0x2198, 0x2198 }, +/* 0x2199 */ { false, 0x2199, 0x2199 }, +/* 0x219a */ { false, 0x219a, 0x219a }, +/* 0x219b */ { false, 0x219b, 0x219b }, +/* 0x219c */ { false, 0x219c, 0x219c }, +/* 0x219d */ { false, 0x219d, 0x219d }, +/* 0x219e */ { false, 0x219e, 0x219e }, +/* 0x219f */ { false, 0x219f, 0x219f }, +/* 0x21a0 */ { false, 0x21a0, 0x21a0 }, +/* 0x21a1 */ { false, 0x21a1, 0x21a1 }, +/* 0x21a2 */ { false, 0x21a2, 0x21a2 }, +/* 0x21a3 */ { false, 0x21a3, 0x21a3 }, +/* 0x21a4 */ { false, 0x21a4, 0x21a4 }, +/* 0x21a5 */ { false, 0x21a5, 0x21a5 }, +/* 0x21a6 */ { false, 0x21a6, 0x21a6 }, +/* 0x21a7 */ { false, 0x21a7, 0x21a7 }, +/* 0x21a8 */ { false, 0x21a8, 0x21a8 }, +/* 0x21a9 */ { false, 0x21a9, 0x21a9 }, +/* 0x21aa */ { false, 0x21aa, 0x21aa }, +/* 0x21ab */ { false, 0x21ab, 0x21ab }, +/* 0x21ac */ { false, 0x21ac, 0x21ac }, +/* 0x21ad */ { false, 0x21ad, 0x21ad }, +/* 0x21ae */ { false, 0x21ae, 0x21ae }, +/* 0x21af */ { false, 0x21af, 0x21af }, +/* 0x21b0 */ { false, 0x21b0, 0x21b0 }, +/* 0x21b1 */ { false, 0x21b1, 0x21b1 }, +/* 0x21b2 */ { false, 0x21b2, 0x21b2 }, +/* 0x21b3 */ { false, 0x21b3, 0x21b3 }, +/* 0x21b4 */ { false, 0x21b4, 0x21b4 }, +/* 0x21b5 */ { false, 0x21b5, 0x21b5 }, +/* 0x21b6 */ { false, 0x21b6, 0x21b6 }, +/* 0x21b7 */ { false, 0x21b7, 0x21b7 }, +/* 0x21b8 */ { false, 0x21b8, 0x21b8 }, +/* 0x21b9 */ { false, 0x21b9, 0x21b9 }, +/* 0x21ba */ { false, 0x21ba, 0x21ba }, +/* 0x21bb */ { false, 0x21bb, 0x21bb }, +/* 0x21bc */ { false, 0x21bc, 0x21bc }, +/* 0x21bd */ { false, 0x21bd, 0x21bd }, +/* 0x21be */ { false, 0x21be, 0x21be }, +/* 0x21bf */ { false, 0x21bf, 0x21bf }, +/* 0x21c0 */ { false, 0x21c0, 0x21c0 }, +/* 0x21c1 */ { false, 0x21c1, 0x21c1 }, +/* 0x21c2 */ { false, 0x21c2, 0x21c2 }, +/* 0x21c3 */ { false, 0x21c3, 0x21c3 }, +/* 0x21c4 */ { false, 0x21c4, 0x21c4 }, +/* 0x21c5 */ { false, 0x21c5, 0x21c5 }, +/* 0x21c6 */ { false, 0x21c6, 0x21c6 }, +/* 0x21c7 */ { false, 0x21c7, 0x21c7 }, +/* 0x21c8 */ { false, 0x21c8, 0x21c8 }, +/* 0x21c9 */ { false, 0x21c9, 0x21c9 }, +/* 0x21ca */ { false, 0x21ca, 0x21ca }, +/* 0x21cb */ { false, 0x21cb, 0x21cb }, +/* 0x21cc */ { false, 0x21cc, 0x21cc }, +/* 0x21cd */ { false, 0x21cd, 0x21cd }, +/* 0x21ce */ { false, 0x21ce, 0x21ce }, +/* 0x21cf */ { false, 0x21cf, 0x21cf }, +/* 0x21d0 */ { false, 0x21d0, 0x21d0 }, +/* 0x21d1 */ { false, 0x21d1, 0x21d1 }, +/* 0x21d2 */ { false, 0x21d2, 0x21d2 }, +/* 0x21d3 */ { false, 0x21d3, 0x21d3 }, +/* 0x21d4 */ { false, 0x21d4, 0x21d4 }, +/* 0x21d5 */ { false, 0x21d5, 0x21d5 }, +/* 0x21d6 */ { false, 0x21d6, 0x21d6 }, +/* 0x21d7 */ { false, 0x21d7, 0x21d7 }, +/* 0x21d8 */ { false, 0x21d8, 0x21d8 }, +/* 0x21d9 */ { false, 0x21d9, 0x21d9 }, +/* 0x21da */ { false, 0x21da, 0x21da }, +/* 0x21db */ { false, 0x21db, 0x21db }, +/* 0x21dc */ { false, 0x21dc, 0x21dc }, +/* 0x21dd */ { false, 0x21dd, 0x21dd }, +/* 0x21de */ { false, 0x21de, 0x21de }, +/* 0x21df */ { false, 0x21df, 0x21df }, +/* 0x21e0 */ { false, 0x21e0, 0x21e0 }, +/* 0x21e1 */ { false, 0x21e1, 0x21e1 }, +/* 0x21e2 */ { false, 0x21e2, 0x21e2 }, +/* 0x21e3 */ { false, 0x21e3, 0x21e3 }, +/* 0x21e4 */ { false, 0x21e4, 0x21e4 }, +/* 0x21e5 */ { false, 0x21e5, 0x21e5 }, +/* 0x21e6 */ { false, 0x21e6, 0x21e6 }, +/* 0x21e7 */ { false, 0x21e7, 0x21e7 }, +/* 0x21e8 */ { false, 0x21e8, 0x21e8 }, +/* 0x21e9 */ { false, 0x21e9, 0x21e9 }, +/* 0x21ea */ { false, 0x21ea, 0x21ea }, +/* 0x21eb */ { false, 0x21eb, 0x21eb }, +/* 0x21ec */ { false, 0x21ec, 0x21ec }, +/* 0x21ed */ { false, 0x21ed, 0x21ed }, +/* 0x21ee */ { false, 0x21ee, 0x21ee }, +/* 0x21ef */ { false, 0x21ef, 0x21ef }, +/* 0x21f0 */ { false, 0x21f0, 0x21f0 }, +/* 0x21f1 */ { false, 0x21f1, 0x21f1 }, +/* 0x21f2 */ { false, 0x21f2, 0x21f2 }, +/* 0x21f3 */ { false, 0x21f3, 0x21f3 }, +/* 0x21f4 */ { false, 0x21f4, 0x21f4 }, +/* 0x21f5 */ { false, 0x21f5, 0x21f5 }, +/* 0x21f6 */ { false, 0x21f6, 0x21f6 }, +/* 0x21f7 */ { false, 0x21f7, 0x21f7 }, +/* 0x21f8 */ { false, 0x21f8, 0x21f8 }, +/* 0x21f9 */ { false, 0x21f9, 0x21f9 }, +/* 0x21fa */ { false, 0x21fa, 0x21fa }, +/* 0x21fb */ { false, 0x21fb, 0x21fb }, +/* 0x21fc */ { false, 0x21fc, 0x21fc }, +/* 0x21fd */ { false, 0x21fd, 0x21fd }, +/* 0x21fe */ { false, 0x21fe, 0x21fe }, +/* 0x21ff */ { false, 0x21ff, 0x21ff }, +/* 0x2200 */ { false, 0x2200, 0x2200 }, +/* 0x2201 */ { false, 0x2201, 0x2201 }, +/* 0x2202 */ { false, 0x2202, 0x2202 }, +/* 0x2203 */ { false, 0x2203, 0x2203 }, +/* 0x2204 */ { false, 0x2204, 0x2204 }, +/* 0x2205 */ { false, 0x2205, 0x2205 }, +/* 0x2206 */ { false, 0x2206, 0x2206 }, +/* 0x2207 */ { false, 0x2207, 0x2207 }, +/* 0x2208 */ { false, 0x2208, 0x2208 }, +/* 0x2209 */ { false, 0x2209, 0x2209 }, +/* 0x220a */ { false, 0x220a, 0x220a }, +/* 0x220b */ { false, 0x220b, 0x220b }, +/* 0x220c */ { false, 0x220c, 0x220c }, +/* 0x220d */ { false, 0x220d, 0x220d }, +/* 0x220e */ { false, 0x220e, 0x220e }, +/* 0x220f */ { false, 0x220f, 0x220f }, +/* 0x2210 */ { false, 0x2210, 0x2210 }, +/* 0x2211 */ { false, 0x2211, 0x2211 }, +/* 0x2212 */ { false, 0x2212, 0x2212 }, +/* 0x2213 */ { false, 0x2213, 0x2213 }, +/* 0x2214 */ { false, 0x2214, 0x2214 }, +/* 0x2215 */ { false, 0x2215, 0x2215 }, +/* 0x2216 */ { false, 0x2216, 0x2216 }, +/* 0x2217 */ { false, 0x2217, 0x2217 }, +/* 0x2218 */ { false, 0x2218, 0x2218 }, +/* 0x2219 */ { false, 0x2219, 0x2219 }, +/* 0x221a */ { false, 0x221a, 0x221a }, +/* 0x221b */ { false, 0x221b, 0x221b }, +/* 0x221c */ { false, 0x221c, 0x221c }, +/* 0x221d */ { false, 0x221d, 0x221d }, +/* 0x221e */ { false, 0x221e, 0x221e }, +/* 0x221f */ { false, 0x221f, 0x221f }, +/* 0x2220 */ { false, 0x2220, 0x2220 }, +/* 0x2221 */ { false, 0x2221, 0x2221 }, +/* 0x2222 */ { false, 0x2222, 0x2222 }, +/* 0x2223 */ { false, 0x2223, 0x2223 }, +/* 0x2224 */ { false, 0x2224, 0x2224 }, +/* 0x2225 */ { false, 0x2225, 0x2225 }, +/* 0x2226 */ { false, 0x2226, 0x2226 }, +/* 0x2227 */ { false, 0x2227, 0x2227 }, +/* 0x2228 */ { false, 0x2228, 0x2228 }, +/* 0x2229 */ { false, 0x2229, 0x2229 }, +/* 0x222a */ { false, 0x222a, 0x222a }, +/* 0x222b */ { false, 0x222b, 0x222b }, +/* 0x222c */ { false, 0x222c, 0x222c }, +/* 0x222d */ { false, 0x222d, 0x222d }, +/* 0x222e */ { false, 0x222e, 0x222e }, +/* 0x222f */ { false, 0x222f, 0x222f }, +/* 0x2230 */ { false, 0x2230, 0x2230 }, +/* 0x2231 */ { false, 0x2231, 0x2231 }, +/* 0x2232 */ { false, 0x2232, 0x2232 }, +/* 0x2233 */ { false, 0x2233, 0x2233 }, +/* 0x2234 */ { false, 0x2234, 0x2234 }, +/* 0x2235 */ { false, 0x2235, 0x2235 }, +/* 0x2236 */ { false, 0x2236, 0x2236 }, +/* 0x2237 */ { false, 0x2237, 0x2237 }, +/* 0x2238 */ { false, 0x2238, 0x2238 }, +/* 0x2239 */ { false, 0x2239, 0x2239 }, +/* 0x223a */ { false, 0x223a, 0x223a }, +/* 0x223b */ { false, 0x223b, 0x223b }, +/* 0x223c */ { false, 0x223c, 0x223c }, +/* 0x223d */ { false, 0x223d, 0x223d }, +/* 0x223e */ { false, 0x223e, 0x223e }, +/* 0x223f */ { false, 0x223f, 0x223f }, +/* 0x2240 */ { false, 0x2240, 0x2240 }, +/* 0x2241 */ { false, 0x2241, 0x2241 }, +/* 0x2242 */ { false, 0x2242, 0x2242 }, +/* 0x2243 */ { false, 0x2243, 0x2243 }, +/* 0x2244 */ { false, 0x2244, 0x2244 }, +/* 0x2245 */ { false, 0x2245, 0x2245 }, +/* 0x2246 */ { false, 0x2246, 0x2246 }, +/* 0x2247 */ { false, 0x2247, 0x2247 }, +/* 0x2248 */ { false, 0x2248, 0x2248 }, +/* 0x2249 */ { false, 0x2249, 0x2249 }, +/* 0x224a */ { false, 0x224a, 0x224a }, +/* 0x224b */ { false, 0x224b, 0x224b }, +/* 0x224c */ { false, 0x224c, 0x224c }, +/* 0x224d */ { false, 0x224d, 0x224d }, +/* 0x224e */ { false, 0x224e, 0x224e }, +/* 0x224f */ { false, 0x224f, 0x224f }, +/* 0x2250 */ { false, 0x2250, 0x2250 }, +/* 0x2251 */ { false, 0x2251, 0x2251 }, +/* 0x2252 */ { false, 0x2252, 0x2252 }, +/* 0x2253 */ { false, 0x2253, 0x2253 }, +/* 0x2254 */ { false, 0x2254, 0x2254 }, +/* 0x2255 */ { false, 0x2255, 0x2255 }, +/* 0x2256 */ { false, 0x2256, 0x2256 }, +/* 0x2257 */ { false, 0x2257, 0x2257 }, +/* 0x2258 */ { false, 0x2258, 0x2258 }, +/* 0x2259 */ { false, 0x2259, 0x2259 }, +/* 0x225a */ { false, 0x225a, 0x225a }, +/* 0x225b */ { false, 0x225b, 0x225b }, +/* 0x225c */ { false, 0x225c, 0x225c }, +/* 0x225d */ { false, 0x225d, 0x225d }, +/* 0x225e */ { false, 0x225e, 0x225e }, +/* 0x225f */ { false, 0x225f, 0x225f }, +/* 0x2260 */ { false, 0x2260, 0x2260 }, +/* 0x2261 */ { false, 0x2261, 0x2261 }, +/* 0x2262 */ { false, 0x2262, 0x2262 }, +/* 0x2263 */ { false, 0x2263, 0x2263 }, +/* 0x2264 */ { false, 0x2264, 0x2264 }, +/* 0x2265 */ { false, 0x2265, 0x2265 }, +/* 0x2266 */ { false, 0x2266, 0x2266 }, +/* 0x2267 */ { false, 0x2267, 0x2267 }, +/* 0x2268 */ { false, 0x2268, 0x2268 }, +/* 0x2269 */ { false, 0x2269, 0x2269 }, +/* 0x226a */ { false, 0x226a, 0x226a }, +/* 0x226b */ { false, 0x226b, 0x226b }, +/* 0x226c */ { false, 0x226c, 0x226c }, +/* 0x226d */ { false, 0x226d, 0x226d }, +/* 0x226e */ { false, 0x226e, 0x226e }, +/* 0x226f */ { false, 0x226f, 0x226f }, +/* 0x2270 */ { false, 0x2270, 0x2270 }, +/* 0x2271 */ { false, 0x2271, 0x2271 }, +/* 0x2272 */ { false, 0x2272, 0x2272 }, +/* 0x2273 */ { false, 0x2273, 0x2273 }, +/* 0x2274 */ { false, 0x2274, 0x2274 }, +/* 0x2275 */ { false, 0x2275, 0x2275 }, +/* 0x2276 */ { false, 0x2276, 0x2276 }, +/* 0x2277 */ { false, 0x2277, 0x2277 }, +/* 0x2278 */ { false, 0x2278, 0x2278 }, +/* 0x2279 */ { false, 0x2279, 0x2279 }, +/* 0x227a */ { false, 0x227a, 0x227a }, +/* 0x227b */ { false, 0x227b, 0x227b }, +/* 0x227c */ { false, 0x227c, 0x227c }, +/* 0x227d */ { false, 0x227d, 0x227d }, +/* 0x227e */ { false, 0x227e, 0x227e }, +/* 0x227f */ { false, 0x227f, 0x227f }, +/* 0x2280 */ { false, 0x2280, 0x2280 }, +/* 0x2281 */ { false, 0x2281, 0x2281 }, +/* 0x2282 */ { false, 0x2282, 0x2282 }, +/* 0x2283 */ { false, 0x2283, 0x2283 }, +/* 0x2284 */ { false, 0x2284, 0x2284 }, +/* 0x2285 */ { false, 0x2285, 0x2285 }, +/* 0x2286 */ { false, 0x2286, 0x2286 }, +/* 0x2287 */ { false, 0x2287, 0x2287 }, +/* 0x2288 */ { false, 0x2288, 0x2288 }, +/* 0x2289 */ { false, 0x2289, 0x2289 }, +/* 0x228a */ { false, 0x228a, 0x228a }, +/* 0x228b */ { false, 0x228b, 0x228b }, +/* 0x228c */ { false, 0x228c, 0x228c }, +/* 0x228d */ { false, 0x228d, 0x228d }, +/* 0x228e */ { false, 0x228e, 0x228e }, +/* 0x228f */ { false, 0x228f, 0x228f }, +/* 0x2290 */ { false, 0x2290, 0x2290 }, +/* 0x2291 */ { false, 0x2291, 0x2291 }, +/* 0x2292 */ { false, 0x2292, 0x2292 }, +/* 0x2293 */ { false, 0x2293, 0x2293 }, +/* 0x2294 */ { false, 0x2294, 0x2294 }, +/* 0x2295 */ { false, 0x2295, 0x2295 }, +/* 0x2296 */ { false, 0x2296, 0x2296 }, +/* 0x2297 */ { false, 0x2297, 0x2297 }, +/* 0x2298 */ { false, 0x2298, 0x2298 }, +/* 0x2299 */ { false, 0x2299, 0x2299 }, +/* 0x229a */ { false, 0x229a, 0x229a }, +/* 0x229b */ { false, 0x229b, 0x229b }, +/* 0x229c */ { false, 0x229c, 0x229c }, +/* 0x229d */ { false, 0x229d, 0x229d }, +/* 0x229e */ { false, 0x229e, 0x229e }, +/* 0x229f */ { false, 0x229f, 0x229f }, +/* 0x22a0 */ { false, 0x22a0, 0x22a0 }, +/* 0x22a1 */ { false, 0x22a1, 0x22a1 }, +/* 0x22a2 */ { false, 0x22a2, 0x22a2 }, +/* 0x22a3 */ { false, 0x22a3, 0x22a3 }, +/* 0x22a4 */ { false, 0x22a4, 0x22a4 }, +/* 0x22a5 */ { false, 0x22a5, 0x22a5 }, +/* 0x22a6 */ { false, 0x22a6, 0x22a6 }, +/* 0x22a7 */ { false, 0x22a7, 0x22a7 }, +/* 0x22a8 */ { false, 0x22a8, 0x22a8 }, +/* 0x22a9 */ { false, 0x22a9, 0x22a9 }, +/* 0x22aa */ { false, 0x22aa, 0x22aa }, +/* 0x22ab */ { false, 0x22ab, 0x22ab }, +/* 0x22ac */ { false, 0x22ac, 0x22ac }, +/* 0x22ad */ { false, 0x22ad, 0x22ad }, +/* 0x22ae */ { false, 0x22ae, 0x22ae }, +/* 0x22af */ { false, 0x22af, 0x22af }, +/* 0x22b0 */ { false, 0x22b0, 0x22b0 }, +/* 0x22b1 */ { false, 0x22b1, 0x22b1 }, +/* 0x22b2 */ { false, 0x22b2, 0x22b2 }, +/* 0x22b3 */ { false, 0x22b3, 0x22b3 }, +/* 0x22b4 */ { false, 0x22b4, 0x22b4 }, +/* 0x22b5 */ { false, 0x22b5, 0x22b5 }, +/* 0x22b6 */ { false, 0x22b6, 0x22b6 }, +/* 0x22b7 */ { false, 0x22b7, 0x22b7 }, +/* 0x22b8 */ { false, 0x22b8, 0x22b8 }, +/* 0x22b9 */ { false, 0x22b9, 0x22b9 }, +/* 0x22ba */ { false, 0x22ba, 0x22ba }, +/* 0x22bb */ { false, 0x22bb, 0x22bb }, +/* 0x22bc */ { false, 0x22bc, 0x22bc }, +/* 0x22bd */ { false, 0x22bd, 0x22bd }, +/* 0x22be */ { false, 0x22be, 0x22be }, +/* 0x22bf */ { false, 0x22bf, 0x22bf }, +/* 0x22c0 */ { false, 0x22c0, 0x22c0 }, +/* 0x22c1 */ { false, 0x22c1, 0x22c1 }, +/* 0x22c2 */ { false, 0x22c2, 0x22c2 }, +/* 0x22c3 */ { false, 0x22c3, 0x22c3 }, +/* 0x22c4 */ { false, 0x22c4, 0x22c4 }, +/* 0x22c5 */ { false, 0x22c5, 0x22c5 }, +/* 0x22c6 */ { false, 0x22c6, 0x22c6 }, +/* 0x22c7 */ { false, 0x22c7, 0x22c7 }, +/* 0x22c8 */ { false, 0x22c8, 0x22c8 }, +/* 0x22c9 */ { false, 0x22c9, 0x22c9 }, +/* 0x22ca */ { false, 0x22ca, 0x22ca }, +/* 0x22cb */ { false, 0x22cb, 0x22cb }, +/* 0x22cc */ { false, 0x22cc, 0x22cc }, +/* 0x22cd */ { false, 0x22cd, 0x22cd }, +/* 0x22ce */ { false, 0x22ce, 0x22ce }, +/* 0x22cf */ { false, 0x22cf, 0x22cf }, +/* 0x22d0 */ { false, 0x22d0, 0x22d0 }, +/* 0x22d1 */ { false, 0x22d1, 0x22d1 }, +/* 0x22d2 */ { false, 0x22d2, 0x22d2 }, +/* 0x22d3 */ { false, 0x22d3, 0x22d3 }, +/* 0x22d4 */ { false, 0x22d4, 0x22d4 }, +/* 0x22d5 */ { false, 0x22d5, 0x22d5 }, +/* 0x22d6 */ { false, 0x22d6, 0x22d6 }, +/* 0x22d7 */ { false, 0x22d7, 0x22d7 }, +/* 0x22d8 */ { false, 0x22d8, 0x22d8 }, +/* 0x22d9 */ { false, 0x22d9, 0x22d9 }, +/* 0x22da */ { false, 0x22da, 0x22da }, +/* 0x22db */ { false, 0x22db, 0x22db }, +/* 0x22dc */ { false, 0x22dc, 0x22dc }, +/* 0x22dd */ { false, 0x22dd, 0x22dd }, +/* 0x22de */ { false, 0x22de, 0x22de }, +/* 0x22df */ { false, 0x22df, 0x22df }, +/* 0x22e0 */ { false, 0x22e0, 0x22e0 }, +/* 0x22e1 */ { false, 0x22e1, 0x22e1 }, +/* 0x22e2 */ { false, 0x22e2, 0x22e2 }, +/* 0x22e3 */ { false, 0x22e3, 0x22e3 }, +/* 0x22e4 */ { false, 0x22e4, 0x22e4 }, +/* 0x22e5 */ { false, 0x22e5, 0x22e5 }, +/* 0x22e6 */ { false, 0x22e6, 0x22e6 }, +/* 0x22e7 */ { false, 0x22e7, 0x22e7 }, +/* 0x22e8 */ { false, 0x22e8, 0x22e8 }, +/* 0x22e9 */ { false, 0x22e9, 0x22e9 }, +/* 0x22ea */ { false, 0x22ea, 0x22ea }, +/* 0x22eb */ { false, 0x22eb, 0x22eb }, +/* 0x22ec */ { false, 0x22ec, 0x22ec }, +/* 0x22ed */ { false, 0x22ed, 0x22ed }, +/* 0x22ee */ { false, 0x22ee, 0x22ee }, +/* 0x22ef */ { false, 0x22ef, 0x22ef }, +/* 0x22f0 */ { false, 0x22f0, 0x22f0 }, +/* 0x22f1 */ { false, 0x22f1, 0x22f1 }, +/* 0x22f2 */ { false, 0x22f2, 0x22f2 }, +/* 0x22f3 */ { false, 0x22f3, 0x22f3 }, +/* 0x22f4 */ { false, 0x22f4, 0x22f4 }, +/* 0x22f5 */ { false, 0x22f5, 0x22f5 }, +/* 0x22f6 */ { false, 0x22f6, 0x22f6 }, +/* 0x22f7 */ { false, 0x22f7, 0x22f7 }, +/* 0x22f8 */ { false, 0x22f8, 0x22f8 }, +/* 0x22f9 */ { false, 0x22f9, 0x22f9 }, +/* 0x22fa */ { false, 0x22fa, 0x22fa }, +/* 0x22fb */ { false, 0x22fb, 0x22fb }, +/* 0x22fc */ { false, 0x22fc, 0x22fc }, +/* 0x22fd */ { false, 0x22fd, 0x22fd }, +/* 0x22fe */ { false, 0x22fe, 0x22fe }, +/* 0x22ff */ { false, 0x22ff, 0x22ff }, +/* 0x2300 */ { false, 0x2300, 0x2300 }, +/* 0x2301 */ { false, 0x2301, 0x2301 }, +/* 0x2302 */ { false, 0x2302, 0x2302 }, +/* 0x2303 */ { false, 0x2303, 0x2303 }, +/* 0x2304 */ { false, 0x2304, 0x2304 }, +/* 0x2305 */ { false, 0x2305, 0x2305 }, +/* 0x2306 */ { false, 0x2306, 0x2306 }, +/* 0x2307 */ { false, 0x2307, 0x2307 }, +/* 0x2308 */ { false, 0x2308, 0x2308 }, +/* 0x2309 */ { false, 0x2309, 0x2309 }, +/* 0x230a */ { false, 0x230a, 0x230a }, +/* 0x230b */ { false, 0x230b, 0x230b }, +/* 0x230c */ { false, 0x230c, 0x230c }, +/* 0x230d */ { false, 0x230d, 0x230d }, +/* 0x230e */ { false, 0x230e, 0x230e }, +/* 0x230f */ { false, 0x230f, 0x230f }, +/* 0x2310 */ { false, 0x2310, 0x2310 }, +/* 0x2311 */ { false, 0x2311, 0x2311 }, +/* 0x2312 */ { false, 0x2312, 0x2312 }, +/* 0x2313 */ { false, 0x2313, 0x2313 }, +/* 0x2314 */ { false, 0x2314, 0x2314 }, +/* 0x2315 */ { false, 0x2315, 0x2315 }, +/* 0x2316 */ { false, 0x2316, 0x2316 }, +/* 0x2317 */ { false, 0x2317, 0x2317 }, +/* 0x2318 */ { false, 0x2318, 0x2318 }, +/* 0x2319 */ { false, 0x2319, 0x2319 }, +/* 0x231a */ { false, 0x231a, 0x231a }, +/* 0x231b */ { false, 0x231b, 0x231b }, +/* 0x231c */ { false, 0x231c, 0x231c }, +/* 0x231d */ { false, 0x231d, 0x231d }, +/* 0x231e */ { false, 0x231e, 0x231e }, +/* 0x231f */ { false, 0x231f, 0x231f }, +/* 0x2320 */ { false, 0x2320, 0x2320 }, +/* 0x2321 */ { false, 0x2321, 0x2321 }, +/* 0x2322 */ { false, 0x2322, 0x2322 }, +/* 0x2323 */ { false, 0x2323, 0x2323 }, +/* 0x2324 */ { false, 0x2324, 0x2324 }, +/* 0x2325 */ { false, 0x2325, 0x2325 }, +/* 0x2326 */ { false, 0x2326, 0x2326 }, +/* 0x2327 */ { false, 0x2327, 0x2327 }, +/* 0x2328 */ { false, 0x2328, 0x2328 }, +/* 0x2329 */ { false, 0x2329, 0x2329 }, +/* 0x232a */ { false, 0x232a, 0x232a }, +/* 0x232b */ { false, 0x232b, 0x232b }, +/* 0x232c */ { false, 0x232c, 0x232c }, +/* 0x232d */ { false, 0x232d, 0x232d }, +/* 0x232e */ { false, 0x232e, 0x232e }, +/* 0x232f */ { false, 0x232f, 0x232f }, +/* 0x2330 */ { false, 0x2330, 0x2330 }, +/* 0x2331 */ { false, 0x2331, 0x2331 }, +/* 0x2332 */ { false, 0x2332, 0x2332 }, +/* 0x2333 */ { false, 0x2333, 0x2333 }, +/* 0x2334 */ { false, 0x2334, 0x2334 }, +/* 0x2335 */ { false, 0x2335, 0x2335 }, +/* 0x2336 */ { false, 0x2336, 0x2336 }, +/* 0x2337 */ { false, 0x2337, 0x2337 }, +/* 0x2338 */ { false, 0x2338, 0x2338 }, +/* 0x2339 */ { false, 0x2339, 0x2339 }, +/* 0x233a */ { false, 0x233a, 0x233a }, +/* 0x233b */ { false, 0x233b, 0x233b }, +/* 0x233c */ { false, 0x233c, 0x233c }, +/* 0x233d */ { false, 0x233d, 0x233d }, +/* 0x233e */ { false, 0x233e, 0x233e }, +/* 0x233f */ { false, 0x233f, 0x233f }, +/* 0x2340 */ { false, 0x2340, 0x2340 }, +/* 0x2341 */ { false, 0x2341, 0x2341 }, +/* 0x2342 */ { false, 0x2342, 0x2342 }, +/* 0x2343 */ { false, 0x2343, 0x2343 }, +/* 0x2344 */ { false, 0x2344, 0x2344 }, +/* 0x2345 */ { false, 0x2345, 0x2345 }, +/* 0x2346 */ { false, 0x2346, 0x2346 }, +/* 0x2347 */ { false, 0x2347, 0x2347 }, +/* 0x2348 */ { false, 0x2348, 0x2348 }, +/* 0x2349 */ { false, 0x2349, 0x2349 }, +/* 0x234a */ { false, 0x234a, 0x234a }, +/* 0x234b */ { false, 0x234b, 0x234b }, +/* 0x234c */ { false, 0x234c, 0x234c }, +/* 0x234d */ { false, 0x234d, 0x234d }, +/* 0x234e */ { false, 0x234e, 0x234e }, +/* 0x234f */ { false, 0x234f, 0x234f }, +/* 0x2350 */ { false, 0x2350, 0x2350 }, +/* 0x2351 */ { false, 0x2351, 0x2351 }, +/* 0x2352 */ { false, 0x2352, 0x2352 }, +/* 0x2353 */ { false, 0x2353, 0x2353 }, +/* 0x2354 */ { false, 0x2354, 0x2354 }, +/* 0x2355 */ { false, 0x2355, 0x2355 }, +/* 0x2356 */ { false, 0x2356, 0x2356 }, +/* 0x2357 */ { false, 0x2357, 0x2357 }, +/* 0x2358 */ { false, 0x2358, 0x2358 }, +/* 0x2359 */ { false, 0x2359, 0x2359 }, +/* 0x235a */ { false, 0x235a, 0x235a }, +/* 0x235b */ { false, 0x235b, 0x235b }, +/* 0x235c */ { false, 0x235c, 0x235c }, +/* 0x235d */ { false, 0x235d, 0x235d }, +/* 0x235e */ { false, 0x235e, 0x235e }, +/* 0x235f */ { false, 0x235f, 0x235f }, +/* 0x2360 */ { false, 0x2360, 0x2360 }, +/* 0x2361 */ { false, 0x2361, 0x2361 }, +/* 0x2362 */ { false, 0x2362, 0x2362 }, +/* 0x2363 */ { false, 0x2363, 0x2363 }, +/* 0x2364 */ { false, 0x2364, 0x2364 }, +/* 0x2365 */ { false, 0x2365, 0x2365 }, +/* 0x2366 */ { false, 0x2366, 0x2366 }, +/* 0x2367 */ { false, 0x2367, 0x2367 }, +/* 0x2368 */ { false, 0x2368, 0x2368 }, +/* 0x2369 */ { false, 0x2369, 0x2369 }, +/* 0x236a */ { false, 0x236a, 0x236a }, +/* 0x236b */ { false, 0x236b, 0x236b }, +/* 0x236c */ { false, 0x236c, 0x236c }, +/* 0x236d */ { false, 0x236d, 0x236d }, +/* 0x236e */ { false, 0x236e, 0x236e }, +/* 0x236f */ { false, 0x236f, 0x236f }, +/* 0x2370 */ { false, 0x2370, 0x2370 }, +/* 0x2371 */ { false, 0x2371, 0x2371 }, +/* 0x2372 */ { false, 0x2372, 0x2372 }, +/* 0x2373 */ { false, 0x2373, 0x2373 }, +/* 0x2374 */ { false, 0x2374, 0x2374 }, +/* 0x2375 */ { false, 0x2375, 0x2375 }, +/* 0x2376 */ { false, 0x2376, 0x2376 }, +/* 0x2377 */ { false, 0x2377, 0x2377 }, +/* 0x2378 */ { false, 0x2378, 0x2378 }, +/* 0x2379 */ { false, 0x2379, 0x2379 }, +/* 0x237a */ { false, 0x237a, 0x237a }, +/* 0x237b */ { false, 0x237b, 0x237b }, +/* 0x237c */ { false, 0x237c, 0x237c }, +/* 0x237d */ { false, 0x237d, 0x237d }, +/* 0x237e */ { false, 0x237e, 0x237e }, +/* 0x237f */ { false, 0x237f, 0x237f }, +/* 0x2380 */ { false, 0x2380, 0x2380 }, +/* 0x2381 */ { false, 0x2381, 0x2381 }, +/* 0x2382 */ { false, 0x2382, 0x2382 }, +/* 0x2383 */ { false, 0x2383, 0x2383 }, +/* 0x2384 */ { false, 0x2384, 0x2384 }, +/* 0x2385 */ { false, 0x2385, 0x2385 }, +/* 0x2386 */ { false, 0x2386, 0x2386 }, +/* 0x2387 */ { false, 0x2387, 0x2387 }, +/* 0x2388 */ { false, 0x2388, 0x2388 }, +/* 0x2389 */ { false, 0x2389, 0x2389 }, +/* 0x238a */ { false, 0x238a, 0x238a }, +/* 0x238b */ { false, 0x238b, 0x238b }, +/* 0x238c */ { false, 0x238c, 0x238c }, +/* 0x238d */ { false, 0x238d, 0x238d }, +/* 0x238e */ { false, 0x238e, 0x238e }, +/* 0x238f */ { false, 0x238f, 0x238f }, +/* 0x2390 */ { false, 0x2390, 0x2390 }, +/* 0x2391 */ { false, 0x2391, 0x2391 }, +/* 0x2392 */ { false, 0x2392, 0x2392 }, +/* 0x2393 */ { false, 0x2393, 0x2393 }, +/* 0x2394 */ { false, 0x2394, 0x2394 }, +/* 0x2395 */ { false, 0x2395, 0x2395 }, +/* 0x2396 */ { false, 0x2396, 0x2396 }, +/* 0x2397 */ { false, 0x2397, 0x2397 }, +/* 0x2398 */ { false, 0x2398, 0x2398 }, +/* 0x2399 */ { false, 0x2399, 0x2399 }, +/* 0x239a */ { false, 0x239a, 0x239a }, +/* 0x239b */ { false, 0x239b, 0x239b }, +/* 0x239c */ { false, 0x239c, 0x239c }, +/* 0x239d */ { false, 0x239d, 0x239d }, +/* 0x239e */ { false, 0x239e, 0x239e }, +/* 0x239f */ { false, 0x239f, 0x239f }, +/* 0x23a0 */ { false, 0x23a0, 0x23a0 }, +/* 0x23a1 */ { false, 0x23a1, 0x23a1 }, +/* 0x23a2 */ { false, 0x23a2, 0x23a2 }, +/* 0x23a3 */ { false, 0x23a3, 0x23a3 }, +/* 0x23a4 */ { false, 0x23a4, 0x23a4 }, +/* 0x23a5 */ { false, 0x23a5, 0x23a5 }, +/* 0x23a6 */ { false, 0x23a6, 0x23a6 }, +/* 0x23a7 */ { false, 0x23a7, 0x23a7 }, +/* 0x23a8 */ { false, 0x23a8, 0x23a8 }, +/* 0x23a9 */ { false, 0x23a9, 0x23a9 }, +/* 0x23aa */ { false, 0x23aa, 0x23aa }, +/* 0x23ab */ { false, 0x23ab, 0x23ab }, +/* 0x23ac */ { false, 0x23ac, 0x23ac }, +/* 0x23ad */ { false, 0x23ad, 0x23ad }, +/* 0x23ae */ { false, 0x23ae, 0x23ae }, +/* 0x23af */ { false, 0x23af, 0x23af }, +/* 0x23b0 */ { false, 0x23b0, 0x23b0 }, +/* 0x23b1 */ { false, 0x23b1, 0x23b1 }, +/* 0x23b2 */ { false, 0x23b2, 0x23b2 }, +/* 0x23b3 */ { false, 0x23b3, 0x23b3 }, +/* 0x23b4 */ { false, 0x23b4, 0x23b4 }, +/* 0x23b5 */ { false, 0x23b5, 0x23b5 }, +/* 0x23b6 */ { false, 0x23b6, 0x23b6 }, +/* 0x23b7 */ { false, 0x23b7, 0x23b7 }, +/* 0x23b8 */ { false, 0x23b8, 0x23b8 }, +/* 0x23b9 */ { false, 0x23b9, 0x23b9 }, +/* 0x23ba */ { false, 0x23ba, 0x23ba }, +/* 0x23bb */ { false, 0x23bb, 0x23bb }, +/* 0x23bc */ { false, 0x23bc, 0x23bc }, +/* 0x23bd */ { false, 0x23bd, 0x23bd }, +/* 0x23be */ { false, 0x23be, 0x23be }, +/* 0x23bf */ { false, 0x23bf, 0x23bf }, +/* 0x23c0 */ { false, 0x23c0, 0x23c0 }, +/* 0x23c1 */ { false, 0x23c1, 0x23c1 }, +/* 0x23c2 */ { false, 0x23c2, 0x23c2 }, +/* 0x23c3 */ { false, 0x23c3, 0x23c3 }, +/* 0x23c4 */ { false, 0x23c4, 0x23c4 }, +/* 0x23c5 */ { false, 0x23c5, 0x23c5 }, +/* 0x23c6 */ { false, 0x23c6, 0x23c6 }, +/* 0x23c7 */ { false, 0x23c7, 0x23c7 }, +/* 0x23c8 */ { false, 0x23c8, 0x23c8 }, +/* 0x23c9 */ { false, 0x23c9, 0x23c9 }, +/* 0x23ca */ { false, 0x23ca, 0x23ca }, +/* 0x23cb */ { false, 0x23cb, 0x23cb }, +/* 0x23cc */ { false, 0x23cc, 0x23cc }, +/* 0x23cd */ { false, 0x23cd, 0x23cd }, +/* 0x23ce */ { false, 0x23ce, 0x23ce }, +/* 0x23cf */ { false, 0x23cf, 0x23cf }, +/* 0x23d0 */ { false, 0x23d0, 0x23d0 }, +/* 0x23d1 */ { false, 0x23d1, 0x23d1 }, +/* 0x23d2 */ { false, 0x23d2, 0x23d2 }, +/* 0x23d3 */ { false, 0x23d3, 0x23d3 }, +/* 0x23d4 */ { false, 0x23d4, 0x23d4 }, +/* 0x23d5 */ { false, 0x23d5, 0x23d5 }, +/* 0x23d6 */ { false, 0x23d6, 0x23d6 }, +/* 0x23d7 */ { false, 0x23d7, 0x23d7 }, +/* 0x23d8 */ { false, 0x23d8, 0x23d8 }, +/* 0x23d9 */ { false, 0x23d9, 0x23d9 }, +/* 0x23da */ { false, 0x23da, 0x23da }, +/* 0x23db */ { false, 0x23db, 0x23db }, +/* 0x23dc */ { false, 0x23dc, 0x23dc }, +/* 0x23dd */ { false, 0x23dd, 0x23dd }, +/* 0x23de */ { false, 0x23de, 0x23de }, +/* 0x23df */ { false, 0x23df, 0x23df }, +/* 0x23e0 */ { false, 0x23e0, 0x23e0 }, +/* 0x23e1 */ { false, 0x23e1, 0x23e1 }, +/* 0x23e2 */ { false, 0x23e2, 0x23e2 }, +/* 0x23e3 */ { false, 0x23e3, 0x23e3 }, +/* 0x23e4 */ { false, 0x23e4, 0x23e4 }, +/* 0x23e5 */ { false, 0x23e5, 0x23e5 }, +/* 0x23e6 */ { false, 0x23e6, 0x23e6 }, +/* 0x23e7 */ { false, 0x23e7, 0x23e7 }, +/* 0x23e8 */ { false, 0x23e8, 0x23e8 }, +/* 0x23e9 */ { false, 0x23e9, 0x23e9 }, +/* 0x23ea */ { false, 0x23ea, 0x23ea }, +/* 0x23eb */ { false, 0x23eb, 0x23eb }, +/* 0x23ec */ { false, 0x23ec, 0x23ec }, +/* 0x23ed */ { false, 0x23ed, 0x23ed }, +/* 0x23ee */ { false, 0x23ee, 0x23ee }, +/* 0x23ef */ { false, 0x23ef, 0x23ef }, +/* 0x23f0 */ { false, 0x23f0, 0x23f0 }, +/* 0x23f1 */ { false, 0x23f1, 0x23f1 }, +/* 0x23f2 */ { false, 0x23f2, 0x23f2 }, +/* 0x23f3 */ { false, 0x23f3, 0x23f3 }, +/* 0x23f4 */ { false, 0x23f4, 0x23f4 }, +/* 0x23f5 */ { false, 0x23f5, 0x23f5 }, +/* 0x23f6 */ { false, 0x23f6, 0x23f6 }, +/* 0x23f7 */ { false, 0x23f7, 0x23f7 }, +/* 0x23f8 */ { false, 0x23f8, 0x23f8 }, +/* 0x23f9 */ { false, 0x23f9, 0x23f9 }, +/* 0x23fa */ { false, 0x23fa, 0x23fa }, +/* 0x23fb */ { false, 0x23fb, 0x23fb }, +/* 0x23fc */ { false, 0x23fc, 0x23fc }, +/* 0x23fd */ { false, 0x23fd, 0x23fd }, +/* 0x23fe */ { false, 0x23fe, 0x23fe }, +/* 0x23ff */ { false, 0x23ff, 0x23ff }, +/* 0x2400 */ { false, 0x2400, 0x2400 }, +/* 0x2401 */ { false, 0x2401, 0x2401 }, +/* 0x2402 */ { false, 0x2402, 0x2402 }, +/* 0x2403 */ { false, 0x2403, 0x2403 }, +/* 0x2404 */ { false, 0x2404, 0x2404 }, +/* 0x2405 */ { false, 0x2405, 0x2405 }, +/* 0x2406 */ { false, 0x2406, 0x2406 }, +/* 0x2407 */ { false, 0x2407, 0x2407 }, +/* 0x2408 */ { false, 0x2408, 0x2408 }, +/* 0x2409 */ { false, 0x2409, 0x2409 }, +/* 0x240a */ { false, 0x240a, 0x240a }, +/* 0x240b */ { false, 0x240b, 0x240b }, +/* 0x240c */ { false, 0x240c, 0x240c }, +/* 0x240d */ { false, 0x240d, 0x240d }, +/* 0x240e */ { false, 0x240e, 0x240e }, +/* 0x240f */ { false, 0x240f, 0x240f }, +/* 0x2410 */ { false, 0x2410, 0x2410 }, +/* 0x2411 */ { false, 0x2411, 0x2411 }, +/* 0x2412 */ { false, 0x2412, 0x2412 }, +/* 0x2413 */ { false, 0x2413, 0x2413 }, +/* 0x2414 */ { false, 0x2414, 0x2414 }, +/* 0x2415 */ { false, 0x2415, 0x2415 }, +/* 0x2416 */ { false, 0x2416, 0x2416 }, +/* 0x2417 */ { false, 0x2417, 0x2417 }, +/* 0x2418 */ { false, 0x2418, 0x2418 }, +/* 0x2419 */ { false, 0x2419, 0x2419 }, +/* 0x241a */ { false, 0x241a, 0x241a }, +/* 0x241b */ { false, 0x241b, 0x241b }, +/* 0x241c */ { false, 0x241c, 0x241c }, +/* 0x241d */ { false, 0x241d, 0x241d }, +/* 0x241e */ { false, 0x241e, 0x241e }, +/* 0x241f */ { false, 0x241f, 0x241f }, +/* 0x2420 */ { false, 0x2420, 0x2420 }, +/* 0x2421 */ { false, 0x2421, 0x2421 }, +/* 0x2422 */ { false, 0x2422, 0x2422 }, +/* 0x2423 */ { false, 0x2423, 0x2423 }, +/* 0x2424 */ { false, 0x2424, 0x2424 }, +/* 0x2425 */ { false, 0x2425, 0x2425 }, +/* 0x2426 */ { false, 0x2426, 0x2426 }, +/* 0x2427 */ { false, 0x2427, 0x2427 }, +/* 0x2428 */ { false, 0x2428, 0x2428 }, +/* 0x2429 */ { false, 0x2429, 0x2429 }, +/* 0x242a */ { false, 0x242a, 0x242a }, +/* 0x242b */ { false, 0x242b, 0x242b }, +/* 0x242c */ { false, 0x242c, 0x242c }, +/* 0x242d */ { false, 0x242d, 0x242d }, +/* 0x242e */ { false, 0x242e, 0x242e }, +/* 0x242f */ { false, 0x242f, 0x242f }, +/* 0x2430 */ { false, 0x2430, 0x2430 }, +/* 0x2431 */ { false, 0x2431, 0x2431 }, +/* 0x2432 */ { false, 0x2432, 0x2432 }, +/* 0x2433 */ { false, 0x2433, 0x2433 }, +/* 0x2434 */ { false, 0x2434, 0x2434 }, +/* 0x2435 */ { false, 0x2435, 0x2435 }, +/* 0x2436 */ { false, 0x2436, 0x2436 }, +/* 0x2437 */ { false, 0x2437, 0x2437 }, +/* 0x2438 */ { false, 0x2438, 0x2438 }, +/* 0x2439 */ { false, 0x2439, 0x2439 }, +/* 0x243a */ { false, 0x243a, 0x243a }, +/* 0x243b */ { false, 0x243b, 0x243b }, +/* 0x243c */ { false, 0x243c, 0x243c }, +/* 0x243d */ { false, 0x243d, 0x243d }, +/* 0x243e */ { false, 0x243e, 0x243e }, +/* 0x243f */ { false, 0x243f, 0x243f }, +/* 0x2440 */ { false, 0x2440, 0x2440 }, +/* 0x2441 */ { false, 0x2441, 0x2441 }, +/* 0x2442 */ { false, 0x2442, 0x2442 }, +/* 0x2443 */ { false, 0x2443, 0x2443 }, +/* 0x2444 */ { false, 0x2444, 0x2444 }, +/* 0x2445 */ { false, 0x2445, 0x2445 }, +/* 0x2446 */ { false, 0x2446, 0x2446 }, +/* 0x2447 */ { false, 0x2447, 0x2447 }, +/* 0x2448 */ { false, 0x2448, 0x2448 }, +/* 0x2449 */ { false, 0x2449, 0x2449 }, +/* 0x244a */ { false, 0x244a, 0x244a }, +/* 0x244b */ { false, 0x244b, 0x244b }, +/* 0x244c */ { false, 0x244c, 0x244c }, +/* 0x244d */ { false, 0x244d, 0x244d }, +/* 0x244e */ { false, 0x244e, 0x244e }, +/* 0x244f */ { false, 0x244f, 0x244f }, +/* 0x2450 */ { false, 0x2450, 0x2450 }, +/* 0x2451 */ { false, 0x2451, 0x2451 }, +/* 0x2452 */ { false, 0x2452, 0x2452 }, +/* 0x2453 */ { false, 0x2453, 0x2453 }, +/* 0x2454 */ { false, 0x2454, 0x2454 }, +/* 0x2455 */ { false, 0x2455, 0x2455 }, +/* 0x2456 */ { false, 0x2456, 0x2456 }, +/* 0x2457 */ { false, 0x2457, 0x2457 }, +/* 0x2458 */ { false, 0x2458, 0x2458 }, +/* 0x2459 */ { false, 0x2459, 0x2459 }, +/* 0x245a */ { false, 0x245a, 0x245a }, +/* 0x245b */ { false, 0x245b, 0x245b }, +/* 0x245c */ { false, 0x245c, 0x245c }, +/* 0x245d */ { false, 0x245d, 0x245d }, +/* 0x245e */ { false, 0x245e, 0x245e }, +/* 0x245f */ { false, 0x245f, 0x245f }, +/* 0x2460 */ { false, 0x2460, 0x2460 }, +/* 0x2461 */ { false, 0x2461, 0x2461 }, +/* 0x2462 */ { false, 0x2462, 0x2462 }, +/* 0x2463 */ { false, 0x2463, 0x2463 }, +/* 0x2464 */ { false, 0x2464, 0x2464 }, +/* 0x2465 */ { false, 0x2465, 0x2465 }, +/* 0x2466 */ { false, 0x2466, 0x2466 }, +/* 0x2467 */ { false, 0x2467, 0x2467 }, +/* 0x2468 */ { false, 0x2468, 0x2468 }, +/* 0x2469 */ { false, 0x2469, 0x2469 }, +/* 0x246a */ { false, 0x246a, 0x246a }, +/* 0x246b */ { false, 0x246b, 0x246b }, +/* 0x246c */ { false, 0x246c, 0x246c }, +/* 0x246d */ { false, 0x246d, 0x246d }, +/* 0x246e */ { false, 0x246e, 0x246e }, +/* 0x246f */ { false, 0x246f, 0x246f }, +/* 0x2470 */ { false, 0x2470, 0x2470 }, +/* 0x2471 */ { false, 0x2471, 0x2471 }, +/* 0x2472 */ { false, 0x2472, 0x2472 }, +/* 0x2473 */ { false, 0x2473, 0x2473 }, +/* 0x2474 */ { false, 0x2474, 0x2474 }, +/* 0x2475 */ { false, 0x2475, 0x2475 }, +/* 0x2476 */ { false, 0x2476, 0x2476 }, +/* 0x2477 */ { false, 0x2477, 0x2477 }, +/* 0x2478 */ { false, 0x2478, 0x2478 }, +/* 0x2479 */ { false, 0x2479, 0x2479 }, +/* 0x247a */ { false, 0x247a, 0x247a }, +/* 0x247b */ { false, 0x247b, 0x247b }, +/* 0x247c */ { false, 0x247c, 0x247c }, +/* 0x247d */ { false, 0x247d, 0x247d }, +/* 0x247e */ { false, 0x247e, 0x247e }, +/* 0x247f */ { false, 0x247f, 0x247f }, +/* 0x2480 */ { false, 0x2480, 0x2480 }, +/* 0x2481 */ { false, 0x2481, 0x2481 }, +/* 0x2482 */ { false, 0x2482, 0x2482 }, +/* 0x2483 */ { false, 0x2483, 0x2483 }, +/* 0x2484 */ { false, 0x2484, 0x2484 }, +/* 0x2485 */ { false, 0x2485, 0x2485 }, +/* 0x2486 */ { false, 0x2486, 0x2486 }, +/* 0x2487 */ { false, 0x2487, 0x2487 }, +/* 0x2488 */ { false, 0x2488, 0x2488 }, +/* 0x2489 */ { false, 0x2489, 0x2489 }, +/* 0x248a */ { false, 0x248a, 0x248a }, +/* 0x248b */ { false, 0x248b, 0x248b }, +/* 0x248c */ { false, 0x248c, 0x248c }, +/* 0x248d */ { false, 0x248d, 0x248d }, +/* 0x248e */ { false, 0x248e, 0x248e }, +/* 0x248f */ { false, 0x248f, 0x248f }, +/* 0x2490 */ { false, 0x2490, 0x2490 }, +/* 0x2491 */ { false, 0x2491, 0x2491 }, +/* 0x2492 */ { false, 0x2492, 0x2492 }, +/* 0x2493 */ { false, 0x2493, 0x2493 }, +/* 0x2494 */ { false, 0x2494, 0x2494 }, +/* 0x2495 */ { false, 0x2495, 0x2495 }, +/* 0x2496 */ { false, 0x2496, 0x2496 }, +/* 0x2497 */ { false, 0x2497, 0x2497 }, +/* 0x2498 */ { false, 0x2498, 0x2498 }, +/* 0x2499 */ { false, 0x2499, 0x2499 }, +/* 0x249a */ { false, 0x249a, 0x249a }, +/* 0x249b */ { false, 0x249b, 0x249b }, +/* 0x249c */ { false, 0x249c, 0x249c }, +/* 0x249d */ { false, 0x249d, 0x249d }, +/* 0x249e */ { false, 0x249e, 0x249e }, +/* 0x249f */ { false, 0x249f, 0x249f }, +/* 0x24a0 */ { false, 0x24a0, 0x24a0 }, +/* 0x24a1 */ { false, 0x24a1, 0x24a1 }, +/* 0x24a2 */ { false, 0x24a2, 0x24a2 }, +/* 0x24a3 */ { false, 0x24a3, 0x24a3 }, +/* 0x24a4 */ { false, 0x24a4, 0x24a4 }, +/* 0x24a5 */ { false, 0x24a5, 0x24a5 }, +/* 0x24a6 */ { false, 0x24a6, 0x24a6 }, +/* 0x24a7 */ { false, 0x24a7, 0x24a7 }, +/* 0x24a8 */ { false, 0x24a8, 0x24a8 }, +/* 0x24a9 */ { false, 0x24a9, 0x24a9 }, +/* 0x24aa */ { false, 0x24aa, 0x24aa }, +/* 0x24ab */ { false, 0x24ab, 0x24ab }, +/* 0x24ac */ { false, 0x24ac, 0x24ac }, +/* 0x24ad */ { false, 0x24ad, 0x24ad }, +/* 0x24ae */ { false, 0x24ae, 0x24ae }, +/* 0x24af */ { false, 0x24af, 0x24af }, +/* 0x24b0 */ { false, 0x24b0, 0x24b0 }, +/* 0x24b1 */ { false, 0x24b1, 0x24b1 }, +/* 0x24b2 */ { false, 0x24b2, 0x24b2 }, +/* 0x24b3 */ { false, 0x24b3, 0x24b3 }, +/* 0x24b4 */ { false, 0x24b4, 0x24b4 }, +/* 0x24b5 */ { false, 0x24b5, 0x24b5 }, +/* 0x24b6 */ { false, 0x24b6, 0x24b6 }, +/* 0x24b7 */ { false, 0x24b7, 0x24b7 }, +/* 0x24b8 */ { false, 0x24b8, 0x24b8 }, +/* 0x24b9 */ { false, 0x24b9, 0x24b9 }, +/* 0x24ba */ { false, 0x24ba, 0x24ba }, +/* 0x24bb */ { false, 0x24bb, 0x24bb }, +/* 0x24bc */ { false, 0x24bc, 0x24bc }, +/* 0x24bd */ { false, 0x24bd, 0x24bd }, +/* 0x24be */ { false, 0x24be, 0x24be }, +/* 0x24bf */ { false, 0x24bf, 0x24bf }, +/* 0x24c0 */ { false, 0x24c0, 0x24c0 }, +/* 0x24c1 */ { false, 0x24c1, 0x24c1 }, +/* 0x24c2 */ { false, 0x24c2, 0x24c2 }, +/* 0x24c3 */ { false, 0x24c3, 0x24c3 }, +/* 0x24c4 */ { false, 0x24c4, 0x24c4 }, +/* 0x24c5 */ { false, 0x24c5, 0x24c5 }, +/* 0x24c6 */ { false, 0x24c6, 0x24c6 }, +/* 0x24c7 */ { false, 0x24c7, 0x24c7 }, +/* 0x24c8 */ { false, 0x24c8, 0x24c8 }, +/* 0x24c9 */ { false, 0x24c9, 0x24c9 }, +/* 0x24ca */ { false, 0x24ca, 0x24ca }, +/* 0x24cb */ { false, 0x24cb, 0x24cb }, +/* 0x24cc */ { false, 0x24cc, 0x24cc }, +/* 0x24cd */ { false, 0x24cd, 0x24cd }, +/* 0x24ce */ { false, 0x24ce, 0x24ce }, +/* 0x24cf */ { false, 0x24cf, 0x24cf }, +/* 0x24d0 */ { false, 0x24d0, 0x24d0 }, +/* 0x24d1 */ { false, 0x24d1, 0x24d1 }, +/* 0x24d2 */ { false, 0x24d2, 0x24d2 }, +/* 0x24d3 */ { false, 0x24d3, 0x24d3 }, +/* 0x24d4 */ { false, 0x24d4, 0x24d4 }, +/* 0x24d5 */ { false, 0x24d5, 0x24d5 }, +/* 0x24d6 */ { false, 0x24d6, 0x24d6 }, +/* 0x24d7 */ { false, 0x24d7, 0x24d7 }, +/* 0x24d8 */ { false, 0x24d8, 0x24d8 }, +/* 0x24d9 */ { false, 0x24d9, 0x24d9 }, +/* 0x24da */ { false, 0x24da, 0x24da }, +/* 0x24db */ { false, 0x24db, 0x24db }, +/* 0x24dc */ { false, 0x24dc, 0x24dc }, +/* 0x24dd */ { false, 0x24dd, 0x24dd }, +/* 0x24de */ { false, 0x24de, 0x24de }, +/* 0x24df */ { false, 0x24df, 0x24df }, +/* 0x24e0 */ { false, 0x24e0, 0x24e0 }, +/* 0x24e1 */ { false, 0x24e1, 0x24e1 }, +/* 0x24e2 */ { false, 0x24e2, 0x24e2 }, +/* 0x24e3 */ { false, 0x24e3, 0x24e3 }, +/* 0x24e4 */ { false, 0x24e4, 0x24e4 }, +/* 0x24e5 */ { false, 0x24e5, 0x24e5 }, +/* 0x24e6 */ { false, 0x24e6, 0x24e6 }, +/* 0x24e7 */ { false, 0x24e7, 0x24e7 }, +/* 0x24e8 */ { false, 0x24e8, 0x24e8 }, +/* 0x24e9 */ { false, 0x24e9, 0x24e9 }, +/* 0x24ea */ { false, 0x24ea, 0x24ea }, +/* 0x24eb */ { false, 0x24eb, 0x24eb }, +/* 0x24ec */ { false, 0x24ec, 0x24ec }, +/* 0x24ed */ { false, 0x24ed, 0x24ed }, +/* 0x24ee */ { false, 0x24ee, 0x24ee }, +/* 0x24ef */ { false, 0x24ef, 0x24ef }, +/* 0x24f0 */ { false, 0x24f0, 0x24f0 }, +/* 0x24f1 */ { false, 0x24f1, 0x24f1 }, +/* 0x24f2 */ { false, 0x24f2, 0x24f2 }, +/* 0x24f3 */ { false, 0x24f3, 0x24f3 }, +/* 0x24f4 */ { false, 0x24f4, 0x24f4 }, +/* 0x24f5 */ { false, 0x24f5, 0x24f5 }, +/* 0x24f6 */ { false, 0x24f6, 0x24f6 }, +/* 0x24f7 */ { false, 0x24f7, 0x24f7 }, +/* 0x24f8 */ { false, 0x24f8, 0x24f8 }, +/* 0x24f9 */ { false, 0x24f9, 0x24f9 }, +/* 0x24fa */ { false, 0x24fa, 0x24fa }, +/* 0x24fb */ { false, 0x24fb, 0x24fb }, +/* 0x24fc */ { false, 0x24fc, 0x24fc }, +/* 0x24fd */ { false, 0x24fd, 0x24fd }, +/* 0x24fe */ { false, 0x24fe, 0x24fe }, +/* 0x24ff */ { false, 0x24ff, 0x24ff }, +/* 0x2500 */ { false, 0x2500, 0x2500 }, +/* 0x2501 */ { false, 0x2501, 0x2501 }, +/* 0x2502 */ { false, 0x2502, 0x2502 }, +/* 0x2503 */ { false, 0x2503, 0x2503 }, +/* 0x2504 */ { false, 0x2504, 0x2504 }, +/* 0x2505 */ { false, 0x2505, 0x2505 }, +/* 0x2506 */ { false, 0x2506, 0x2506 }, +/* 0x2507 */ { false, 0x2507, 0x2507 }, +/* 0x2508 */ { false, 0x2508, 0x2508 }, +/* 0x2509 */ { false, 0x2509, 0x2509 }, +/* 0x250a */ { false, 0x250a, 0x250a }, +/* 0x250b */ { false, 0x250b, 0x250b }, +/* 0x250c */ { false, 0x250c, 0x250c }, +/* 0x250d */ { false, 0x250d, 0x250d }, +/* 0x250e */ { false, 0x250e, 0x250e }, +/* 0x250f */ { false, 0x250f, 0x250f }, +/* 0x2510 */ { false, 0x2510, 0x2510 }, +/* 0x2511 */ { false, 0x2511, 0x2511 }, +/* 0x2512 */ { false, 0x2512, 0x2512 }, +/* 0x2513 */ { false, 0x2513, 0x2513 }, +/* 0x2514 */ { false, 0x2514, 0x2514 }, +/* 0x2515 */ { false, 0x2515, 0x2515 }, +/* 0x2516 */ { false, 0x2516, 0x2516 }, +/* 0x2517 */ { false, 0x2517, 0x2517 }, +/* 0x2518 */ { false, 0x2518, 0x2518 }, +/* 0x2519 */ { false, 0x2519, 0x2519 }, +/* 0x251a */ { false, 0x251a, 0x251a }, +/* 0x251b */ { false, 0x251b, 0x251b }, +/* 0x251c */ { false, 0x251c, 0x251c }, +/* 0x251d */ { false, 0x251d, 0x251d }, +/* 0x251e */ { false, 0x251e, 0x251e }, +/* 0x251f */ { false, 0x251f, 0x251f }, +/* 0x2520 */ { false, 0x2520, 0x2520 }, +/* 0x2521 */ { false, 0x2521, 0x2521 }, +/* 0x2522 */ { false, 0x2522, 0x2522 }, +/* 0x2523 */ { false, 0x2523, 0x2523 }, +/* 0x2524 */ { false, 0x2524, 0x2524 }, +/* 0x2525 */ { false, 0x2525, 0x2525 }, +/* 0x2526 */ { false, 0x2526, 0x2526 }, +/* 0x2527 */ { false, 0x2527, 0x2527 }, +/* 0x2528 */ { false, 0x2528, 0x2528 }, +/* 0x2529 */ { false, 0x2529, 0x2529 }, +/* 0x252a */ { false, 0x252a, 0x252a }, +/* 0x252b */ { false, 0x252b, 0x252b }, +/* 0x252c */ { false, 0x252c, 0x252c }, +/* 0x252d */ { false, 0x252d, 0x252d }, +/* 0x252e */ { false, 0x252e, 0x252e }, +/* 0x252f */ { false, 0x252f, 0x252f }, +/* 0x2530 */ { false, 0x2530, 0x2530 }, +/* 0x2531 */ { false, 0x2531, 0x2531 }, +/* 0x2532 */ { false, 0x2532, 0x2532 }, +/* 0x2533 */ { false, 0x2533, 0x2533 }, +/* 0x2534 */ { false, 0x2534, 0x2534 }, +/* 0x2535 */ { false, 0x2535, 0x2535 }, +/* 0x2536 */ { false, 0x2536, 0x2536 }, +/* 0x2537 */ { false, 0x2537, 0x2537 }, +/* 0x2538 */ { false, 0x2538, 0x2538 }, +/* 0x2539 */ { false, 0x2539, 0x2539 }, +/* 0x253a */ { false, 0x253a, 0x253a }, +/* 0x253b */ { false, 0x253b, 0x253b }, +/* 0x253c */ { false, 0x253c, 0x253c }, +/* 0x253d */ { false, 0x253d, 0x253d }, +/* 0x253e */ { false, 0x253e, 0x253e }, +/* 0x253f */ { false, 0x253f, 0x253f }, +/* 0x2540 */ { false, 0x2540, 0x2540 }, +/* 0x2541 */ { false, 0x2541, 0x2541 }, +/* 0x2542 */ { false, 0x2542, 0x2542 }, +/* 0x2543 */ { false, 0x2543, 0x2543 }, +/* 0x2544 */ { false, 0x2544, 0x2544 }, +/* 0x2545 */ { false, 0x2545, 0x2545 }, +/* 0x2546 */ { false, 0x2546, 0x2546 }, +/* 0x2547 */ { false, 0x2547, 0x2547 }, +/* 0x2548 */ { false, 0x2548, 0x2548 }, +/* 0x2549 */ { false, 0x2549, 0x2549 }, +/* 0x254a */ { false, 0x254a, 0x254a }, +/* 0x254b */ { false, 0x254b, 0x254b }, +/* 0x254c */ { false, 0x254c, 0x254c }, +/* 0x254d */ { false, 0x254d, 0x254d }, +/* 0x254e */ { false, 0x254e, 0x254e }, +/* 0x254f */ { false, 0x254f, 0x254f }, +/* 0x2550 */ { false, 0x2550, 0x2550 }, +/* 0x2551 */ { false, 0x2551, 0x2551 }, +/* 0x2552 */ { false, 0x2552, 0x2552 }, +/* 0x2553 */ { false, 0x2553, 0x2553 }, +/* 0x2554 */ { false, 0x2554, 0x2554 }, +/* 0x2555 */ { false, 0x2555, 0x2555 }, +/* 0x2556 */ { false, 0x2556, 0x2556 }, +/* 0x2557 */ { false, 0x2557, 0x2557 }, +/* 0x2558 */ { false, 0x2558, 0x2558 }, +/* 0x2559 */ { false, 0x2559, 0x2559 }, +/* 0x255a */ { false, 0x255a, 0x255a }, +/* 0x255b */ { false, 0x255b, 0x255b }, +/* 0x255c */ { false, 0x255c, 0x255c }, +/* 0x255d */ { false, 0x255d, 0x255d }, +/* 0x255e */ { false, 0x255e, 0x255e }, +/* 0x255f */ { false, 0x255f, 0x255f }, +/* 0x2560 */ { false, 0x2560, 0x2560 }, +/* 0x2561 */ { false, 0x2561, 0x2561 }, +/* 0x2562 */ { false, 0x2562, 0x2562 }, +/* 0x2563 */ { false, 0x2563, 0x2563 }, +/* 0x2564 */ { false, 0x2564, 0x2564 }, +/* 0x2565 */ { false, 0x2565, 0x2565 }, +/* 0x2566 */ { false, 0x2566, 0x2566 }, +/* 0x2567 */ { false, 0x2567, 0x2567 }, +/* 0x2568 */ { false, 0x2568, 0x2568 }, +/* 0x2569 */ { false, 0x2569, 0x2569 }, +/* 0x256a */ { false, 0x256a, 0x256a }, +/* 0x256b */ { false, 0x256b, 0x256b }, +/* 0x256c */ { false, 0x256c, 0x256c }, +/* 0x256d */ { false, 0x256d, 0x256d }, +/* 0x256e */ { false, 0x256e, 0x256e }, +/* 0x256f */ { false, 0x256f, 0x256f }, +/* 0x2570 */ { false, 0x2570, 0x2570 }, +/* 0x2571 */ { false, 0x2571, 0x2571 }, +/* 0x2572 */ { false, 0x2572, 0x2572 }, +/* 0x2573 */ { false, 0x2573, 0x2573 }, +/* 0x2574 */ { false, 0x2574, 0x2574 }, +/* 0x2575 */ { false, 0x2575, 0x2575 }, +/* 0x2576 */ { false, 0x2576, 0x2576 }, +/* 0x2577 */ { false, 0x2577, 0x2577 }, +/* 0x2578 */ { false, 0x2578, 0x2578 }, +/* 0x2579 */ { false, 0x2579, 0x2579 }, +/* 0x257a */ { false, 0x257a, 0x257a }, +/* 0x257b */ { false, 0x257b, 0x257b }, +/* 0x257c */ { false, 0x257c, 0x257c }, +/* 0x257d */ { false, 0x257d, 0x257d }, +/* 0x257e */ { false, 0x257e, 0x257e }, +/* 0x257f */ { false, 0x257f, 0x257f }, +/* 0x2580 */ { false, 0x2580, 0x2580 }, +/* 0x2581 */ { false, 0x2581, 0x2581 }, +/* 0x2582 */ { false, 0x2582, 0x2582 }, +/* 0x2583 */ { false, 0x2583, 0x2583 }, +/* 0x2584 */ { false, 0x2584, 0x2584 }, +/* 0x2585 */ { false, 0x2585, 0x2585 }, +/* 0x2586 */ { false, 0x2586, 0x2586 }, +/* 0x2587 */ { false, 0x2587, 0x2587 }, +/* 0x2588 */ { false, 0x2588, 0x2588 }, +/* 0x2589 */ { false, 0x2589, 0x2589 }, +/* 0x258a */ { false, 0x258a, 0x258a }, +/* 0x258b */ { false, 0x258b, 0x258b }, +/* 0x258c */ { false, 0x258c, 0x258c }, +/* 0x258d */ { false, 0x258d, 0x258d }, +/* 0x258e */ { false, 0x258e, 0x258e }, +/* 0x258f */ { false, 0x258f, 0x258f }, +/* 0x2590 */ { false, 0x2590, 0x2590 }, +/* 0x2591 */ { false, 0x2591, 0x2591 }, +/* 0x2592 */ { false, 0x2592, 0x2592 }, +/* 0x2593 */ { false, 0x2593, 0x2593 }, +/* 0x2594 */ { false, 0x2594, 0x2594 }, +/* 0x2595 */ { false, 0x2595, 0x2595 }, +/* 0x2596 */ { false, 0x2596, 0x2596 }, +/* 0x2597 */ { false, 0x2597, 0x2597 }, +/* 0x2598 */ { false, 0x2598, 0x2598 }, +/* 0x2599 */ { false, 0x2599, 0x2599 }, +/* 0x259a */ { false, 0x259a, 0x259a }, +/* 0x259b */ { false, 0x259b, 0x259b }, +/* 0x259c */ { false, 0x259c, 0x259c }, +/* 0x259d */ { false, 0x259d, 0x259d }, +/* 0x259e */ { false, 0x259e, 0x259e }, +/* 0x259f */ { false, 0x259f, 0x259f }, +/* 0x25a0 */ { false, 0x25a0, 0x25a0 }, +/* 0x25a1 */ { false, 0x25a1, 0x25a1 }, +/* 0x25a2 */ { false, 0x25a2, 0x25a2 }, +/* 0x25a3 */ { false, 0x25a3, 0x25a3 }, +/* 0x25a4 */ { false, 0x25a4, 0x25a4 }, +/* 0x25a5 */ { false, 0x25a5, 0x25a5 }, +/* 0x25a6 */ { false, 0x25a6, 0x25a6 }, +/* 0x25a7 */ { false, 0x25a7, 0x25a7 }, +/* 0x25a8 */ { false, 0x25a8, 0x25a8 }, +/* 0x25a9 */ { false, 0x25a9, 0x25a9 }, +/* 0x25aa */ { false, 0x25aa, 0x25aa }, +/* 0x25ab */ { false, 0x25ab, 0x25ab }, +/* 0x25ac */ { false, 0x25ac, 0x25ac }, +/* 0x25ad */ { false, 0x25ad, 0x25ad }, +/* 0x25ae */ { false, 0x25ae, 0x25ae }, +/* 0x25af */ { false, 0x25af, 0x25af }, +/* 0x25b0 */ { false, 0x25b0, 0x25b0 }, +/* 0x25b1 */ { false, 0x25b1, 0x25b1 }, +/* 0x25b2 */ { false, 0x25b2, 0x25b2 }, +/* 0x25b3 */ { false, 0x25b3, 0x25b3 }, +/* 0x25b4 */ { false, 0x25b4, 0x25b4 }, +/* 0x25b5 */ { false, 0x25b5, 0x25b5 }, +/* 0x25b6 */ { false, 0x25b6, 0x25b6 }, +/* 0x25b7 */ { false, 0x25b7, 0x25b7 }, +/* 0x25b8 */ { false, 0x25b8, 0x25b8 }, +/* 0x25b9 */ { false, 0x25b9, 0x25b9 }, +/* 0x25ba */ { false, 0x25ba, 0x25ba }, +/* 0x25bb */ { false, 0x25bb, 0x25bb }, +/* 0x25bc */ { false, 0x25bc, 0x25bc }, +/* 0x25bd */ { false, 0x25bd, 0x25bd }, +/* 0x25be */ { false, 0x25be, 0x25be }, +/* 0x25bf */ { false, 0x25bf, 0x25bf }, +/* 0x25c0 */ { false, 0x25c0, 0x25c0 }, +/* 0x25c1 */ { false, 0x25c1, 0x25c1 }, +/* 0x25c2 */ { false, 0x25c2, 0x25c2 }, +/* 0x25c3 */ { false, 0x25c3, 0x25c3 }, +/* 0x25c4 */ { false, 0x25c4, 0x25c4 }, +/* 0x25c5 */ { false, 0x25c5, 0x25c5 }, +/* 0x25c6 */ { false, 0x25c6, 0x25c6 }, +/* 0x25c7 */ { false, 0x25c7, 0x25c7 }, +/* 0x25c8 */ { false, 0x25c8, 0x25c8 }, +/* 0x25c9 */ { false, 0x25c9, 0x25c9 }, +/* 0x25ca */ { false, 0x25ca, 0x25ca }, +/* 0x25cb */ { false, 0x25cb, 0x25cb }, +/* 0x25cc */ { false, 0x25cc, 0x25cc }, +/* 0x25cd */ { false, 0x25cd, 0x25cd }, +/* 0x25ce */ { false, 0x25ce, 0x25ce }, +/* 0x25cf */ { false, 0x25cf, 0x25cf }, +/* 0x25d0 */ { false, 0x25d0, 0x25d0 }, +/* 0x25d1 */ { false, 0x25d1, 0x25d1 }, +/* 0x25d2 */ { false, 0x25d2, 0x25d2 }, +/* 0x25d3 */ { false, 0x25d3, 0x25d3 }, +/* 0x25d4 */ { false, 0x25d4, 0x25d4 }, +/* 0x25d5 */ { false, 0x25d5, 0x25d5 }, +/* 0x25d6 */ { false, 0x25d6, 0x25d6 }, +/* 0x25d7 */ { false, 0x25d7, 0x25d7 }, +/* 0x25d8 */ { false, 0x25d8, 0x25d8 }, +/* 0x25d9 */ { false, 0x25d9, 0x25d9 }, +/* 0x25da */ { false, 0x25da, 0x25da }, +/* 0x25db */ { false, 0x25db, 0x25db }, +/* 0x25dc */ { false, 0x25dc, 0x25dc }, +/* 0x25dd */ { false, 0x25dd, 0x25dd }, +/* 0x25de */ { false, 0x25de, 0x25de }, +/* 0x25df */ { false, 0x25df, 0x25df }, +/* 0x25e0 */ { false, 0x25e0, 0x25e0 }, +/* 0x25e1 */ { false, 0x25e1, 0x25e1 }, +/* 0x25e2 */ { false, 0x25e2, 0x25e2 }, +/* 0x25e3 */ { false, 0x25e3, 0x25e3 }, +/* 0x25e4 */ { false, 0x25e4, 0x25e4 }, +/* 0x25e5 */ { false, 0x25e5, 0x25e5 }, +/* 0x25e6 */ { false, 0x25e6, 0x25e6 }, +/* 0x25e7 */ { false, 0x25e7, 0x25e7 }, +/* 0x25e8 */ { false, 0x25e8, 0x25e8 }, +/* 0x25e9 */ { false, 0x25e9, 0x25e9 }, +/* 0x25ea */ { false, 0x25ea, 0x25ea }, +/* 0x25eb */ { false, 0x25eb, 0x25eb }, +/* 0x25ec */ { false, 0x25ec, 0x25ec }, +/* 0x25ed */ { false, 0x25ed, 0x25ed }, +/* 0x25ee */ { false, 0x25ee, 0x25ee }, +/* 0x25ef */ { false, 0x25ef, 0x25ef }, +/* 0x25f0 */ { false, 0x25f0, 0x25f0 }, +/* 0x25f1 */ { false, 0x25f1, 0x25f1 }, +/* 0x25f2 */ { false, 0x25f2, 0x25f2 }, +/* 0x25f3 */ { false, 0x25f3, 0x25f3 }, +/* 0x25f4 */ { false, 0x25f4, 0x25f4 }, +/* 0x25f5 */ { false, 0x25f5, 0x25f5 }, +/* 0x25f6 */ { false, 0x25f6, 0x25f6 }, +/* 0x25f7 */ { false, 0x25f7, 0x25f7 }, +/* 0x25f8 */ { false, 0x25f8, 0x25f8 }, +/* 0x25f9 */ { false, 0x25f9, 0x25f9 }, +/* 0x25fa */ { false, 0x25fa, 0x25fa }, +/* 0x25fb */ { false, 0x25fb, 0x25fb }, +/* 0x25fc */ { false, 0x25fc, 0x25fc }, +/* 0x25fd */ { false, 0x25fd, 0x25fd }, +/* 0x25fe */ { false, 0x25fe, 0x25fe }, +/* 0x25ff */ { false, 0x25ff, 0x25ff }, +/* 0x2600 */ { false, 0x2600, 0x2600 }, +/* 0x2601 */ { false, 0x2601, 0x2601 }, +/* 0x2602 */ { false, 0x2602, 0x2602 }, +/* 0x2603 */ { false, 0x2603, 0x2603 }, +/* 0x2604 */ { false, 0x2604, 0x2604 }, +/* 0x2605 */ { false, 0x2605, 0x2605 }, +/* 0x2606 */ { false, 0x2606, 0x2606 }, +/* 0x2607 */ { false, 0x2607, 0x2607 }, +/* 0x2608 */ { false, 0x2608, 0x2608 }, +/* 0x2609 */ { false, 0x2609, 0x2609 }, +/* 0x260a */ { false, 0x260a, 0x260a }, +/* 0x260b */ { false, 0x260b, 0x260b }, +/* 0x260c */ { false, 0x260c, 0x260c }, +/* 0x260d */ { false, 0x260d, 0x260d }, +/* 0x260e */ { false, 0x260e, 0x260e }, +/* 0x260f */ { false, 0x260f, 0x260f }, +/* 0x2610 */ { false, 0x2610, 0x2610 }, +/* 0x2611 */ { false, 0x2611, 0x2611 }, +/* 0x2612 */ { false, 0x2612, 0x2612 }, +/* 0x2613 */ { false, 0x2613, 0x2613 }, +/* 0x2614 */ { false, 0x2614, 0x2614 }, +/* 0x2615 */ { false, 0x2615, 0x2615 }, +/* 0x2616 */ { false, 0x2616, 0x2616 }, +/* 0x2617 */ { false, 0x2617, 0x2617 }, +/* 0x2618 */ { false, 0x2618, 0x2618 }, +/* 0x2619 */ { false, 0x2619, 0x2619 }, +/* 0x261a */ { false, 0x261a, 0x261a }, +/* 0x261b */ { false, 0x261b, 0x261b }, +/* 0x261c */ { false, 0x261c, 0x261c }, +/* 0x261d */ { false, 0x261d, 0x261d }, +/* 0x261e */ { false, 0x261e, 0x261e }, +/* 0x261f */ { false, 0x261f, 0x261f }, +/* 0x2620 */ { false, 0x2620, 0x2620 }, +/* 0x2621 */ { false, 0x2621, 0x2621 }, +/* 0x2622 */ { false, 0x2622, 0x2622 }, +/* 0x2623 */ { false, 0x2623, 0x2623 }, +/* 0x2624 */ { false, 0x2624, 0x2624 }, +/* 0x2625 */ { false, 0x2625, 0x2625 }, +/* 0x2626 */ { false, 0x2626, 0x2626 }, +/* 0x2627 */ { false, 0x2627, 0x2627 }, +/* 0x2628 */ { false, 0x2628, 0x2628 }, +/* 0x2629 */ { false, 0x2629, 0x2629 }, +/* 0x262a */ { false, 0x262a, 0x262a }, +/* 0x262b */ { false, 0x262b, 0x262b }, +/* 0x262c */ { false, 0x262c, 0x262c }, +/* 0x262d */ { false, 0x262d, 0x262d }, +/* 0x262e */ { false, 0x262e, 0x262e }, +/* 0x262f */ { false, 0x262f, 0x262f }, +/* 0x2630 */ { false, 0x2630, 0x2630 }, +/* 0x2631 */ { false, 0x2631, 0x2631 }, +/* 0x2632 */ { false, 0x2632, 0x2632 }, +/* 0x2633 */ { false, 0x2633, 0x2633 }, +/* 0x2634 */ { false, 0x2634, 0x2634 }, +/* 0x2635 */ { false, 0x2635, 0x2635 }, +/* 0x2636 */ { false, 0x2636, 0x2636 }, +/* 0x2637 */ { false, 0x2637, 0x2637 }, +/* 0x2638 */ { false, 0x2638, 0x2638 }, +/* 0x2639 */ { false, 0x2639, 0x2639 }, +/* 0x263a */ { false, 0x263a, 0x263a }, +/* 0x263b */ { false, 0x263b, 0x263b }, +/* 0x263c */ { false, 0x263c, 0x263c }, +/* 0x263d */ { false, 0x263d, 0x263d }, +/* 0x263e */ { false, 0x263e, 0x263e }, +/* 0x263f */ { false, 0x263f, 0x263f }, +/* 0x2640 */ { false, 0x2640, 0x2640 }, +/* 0x2641 */ { false, 0x2641, 0x2641 }, +/* 0x2642 */ { false, 0x2642, 0x2642 }, +/* 0x2643 */ { false, 0x2643, 0x2643 }, +/* 0x2644 */ { false, 0x2644, 0x2644 }, +/* 0x2645 */ { false, 0x2645, 0x2645 }, +/* 0x2646 */ { false, 0x2646, 0x2646 }, +/* 0x2647 */ { false, 0x2647, 0x2647 }, +/* 0x2648 */ { false, 0x2648, 0x2648 }, +/* 0x2649 */ { false, 0x2649, 0x2649 }, +/* 0x264a */ { false, 0x264a, 0x264a }, +/* 0x264b */ { false, 0x264b, 0x264b }, +/* 0x264c */ { false, 0x264c, 0x264c }, +/* 0x264d */ { false, 0x264d, 0x264d }, +/* 0x264e */ { false, 0x264e, 0x264e }, +/* 0x264f */ { false, 0x264f, 0x264f }, +/* 0x2650 */ { false, 0x2650, 0x2650 }, +/* 0x2651 */ { false, 0x2651, 0x2651 }, +/* 0x2652 */ { false, 0x2652, 0x2652 }, +/* 0x2653 */ { false, 0x2653, 0x2653 }, +/* 0x2654 */ { false, 0x2654, 0x2654 }, +/* 0x2655 */ { false, 0x2655, 0x2655 }, +/* 0x2656 */ { false, 0x2656, 0x2656 }, +/* 0x2657 */ { false, 0x2657, 0x2657 }, +/* 0x2658 */ { false, 0x2658, 0x2658 }, +/* 0x2659 */ { false, 0x2659, 0x2659 }, +/* 0x265a */ { false, 0x265a, 0x265a }, +/* 0x265b */ { false, 0x265b, 0x265b }, +/* 0x265c */ { false, 0x265c, 0x265c }, +/* 0x265d */ { false, 0x265d, 0x265d }, +/* 0x265e */ { false, 0x265e, 0x265e }, +/* 0x265f */ { false, 0x265f, 0x265f }, +/* 0x2660 */ { false, 0x2660, 0x2660 }, +/* 0x2661 */ { false, 0x2661, 0x2661 }, +/* 0x2662 */ { false, 0x2662, 0x2662 }, +/* 0x2663 */ { false, 0x2663, 0x2663 }, +/* 0x2664 */ { false, 0x2664, 0x2664 }, +/* 0x2665 */ { false, 0x2665, 0x2665 }, +/* 0x2666 */ { false, 0x2666, 0x2666 }, +/* 0x2667 */ { false, 0x2667, 0x2667 }, +/* 0x2668 */ { false, 0x2668, 0x2668 }, +/* 0x2669 */ { false, 0x2669, 0x2669 }, +/* 0x266a */ { false, 0x266a, 0x266a }, +/* 0x266b */ { false, 0x266b, 0x266b }, +/* 0x266c */ { false, 0x266c, 0x266c }, +/* 0x266d */ { false, 0x266d, 0x266d }, +/* 0x266e */ { false, 0x266e, 0x266e }, +/* 0x266f */ { false, 0x266f, 0x266f }, +/* 0x2670 */ { false, 0x2670, 0x2670 }, +/* 0x2671 */ { false, 0x2671, 0x2671 }, +/* 0x2672 */ { false, 0x2672, 0x2672 }, +/* 0x2673 */ { false, 0x2673, 0x2673 }, +/* 0x2674 */ { false, 0x2674, 0x2674 }, +/* 0x2675 */ { false, 0x2675, 0x2675 }, +/* 0x2676 */ { false, 0x2676, 0x2676 }, +/* 0x2677 */ { false, 0x2677, 0x2677 }, +/* 0x2678 */ { false, 0x2678, 0x2678 }, +/* 0x2679 */ { false, 0x2679, 0x2679 }, +/* 0x267a */ { false, 0x267a, 0x267a }, +/* 0x267b */ { false, 0x267b, 0x267b }, +/* 0x267c */ { false, 0x267c, 0x267c }, +/* 0x267d */ { false, 0x267d, 0x267d }, +/* 0x267e */ { false, 0x267e, 0x267e }, +/* 0x267f */ { false, 0x267f, 0x267f }, +/* 0x2680 */ { false, 0x2680, 0x2680 }, +/* 0x2681 */ { false, 0x2681, 0x2681 }, +/* 0x2682 */ { false, 0x2682, 0x2682 }, +/* 0x2683 */ { false, 0x2683, 0x2683 }, +/* 0x2684 */ { false, 0x2684, 0x2684 }, +/* 0x2685 */ { false, 0x2685, 0x2685 }, +/* 0x2686 */ { false, 0x2686, 0x2686 }, +/* 0x2687 */ { false, 0x2687, 0x2687 }, +/* 0x2688 */ { false, 0x2688, 0x2688 }, +/* 0x2689 */ { false, 0x2689, 0x2689 }, +/* 0x268a */ { false, 0x268a, 0x268a }, +/* 0x268b */ { false, 0x268b, 0x268b }, +/* 0x268c */ { false, 0x268c, 0x268c }, +/* 0x268d */ { false, 0x268d, 0x268d }, +/* 0x268e */ { false, 0x268e, 0x268e }, +/* 0x268f */ { false, 0x268f, 0x268f }, +/* 0x2690 */ { false, 0x2690, 0x2690 }, +/* 0x2691 */ { false, 0x2691, 0x2691 }, +/* 0x2692 */ { false, 0x2692, 0x2692 }, +/* 0x2693 */ { false, 0x2693, 0x2693 }, +/* 0x2694 */ { false, 0x2694, 0x2694 }, +/* 0x2695 */ { false, 0x2695, 0x2695 }, +/* 0x2696 */ { false, 0x2696, 0x2696 }, +/* 0x2697 */ { false, 0x2697, 0x2697 }, +/* 0x2698 */ { false, 0x2698, 0x2698 }, +/* 0x2699 */ { false, 0x2699, 0x2699 }, +/* 0x269a */ { false, 0x269a, 0x269a }, +/* 0x269b */ { false, 0x269b, 0x269b }, +/* 0x269c */ { false, 0x269c, 0x269c }, +/* 0x269d */ { false, 0x269d, 0x269d }, +/* 0x269e */ { false, 0x269e, 0x269e }, +/* 0x269f */ { false, 0x269f, 0x269f }, +/* 0x26a0 */ { false, 0x26a0, 0x26a0 }, +/* 0x26a1 */ { false, 0x26a1, 0x26a1 }, +/* 0x26a2 */ { false, 0x26a2, 0x26a2 }, +/* 0x26a3 */ { false, 0x26a3, 0x26a3 }, +/* 0x26a4 */ { false, 0x26a4, 0x26a4 }, +/* 0x26a5 */ { false, 0x26a5, 0x26a5 }, +/* 0x26a6 */ { false, 0x26a6, 0x26a6 }, +/* 0x26a7 */ { false, 0x26a7, 0x26a7 }, +/* 0x26a8 */ { false, 0x26a8, 0x26a8 }, +/* 0x26a9 */ { false, 0x26a9, 0x26a9 }, +/* 0x26aa */ { false, 0x26aa, 0x26aa }, +/* 0x26ab */ { false, 0x26ab, 0x26ab }, +/* 0x26ac */ { false, 0x26ac, 0x26ac }, +/* 0x26ad */ { false, 0x26ad, 0x26ad }, +/* 0x26ae */ { false, 0x26ae, 0x26ae }, +/* 0x26af */ { false, 0x26af, 0x26af }, +/* 0x26b0 */ { false, 0x26b0, 0x26b0 }, +/* 0x26b1 */ { false, 0x26b1, 0x26b1 }, +/* 0x26b2 */ { false, 0x26b2, 0x26b2 }, +/* 0x26b3 */ { false, 0x26b3, 0x26b3 }, +/* 0x26b4 */ { false, 0x26b4, 0x26b4 }, +/* 0x26b5 */ { false, 0x26b5, 0x26b5 }, +/* 0x26b6 */ { false, 0x26b6, 0x26b6 }, +/* 0x26b7 */ { false, 0x26b7, 0x26b7 }, +/* 0x26b8 */ { false, 0x26b8, 0x26b8 }, +/* 0x26b9 */ { false, 0x26b9, 0x26b9 }, +/* 0x26ba */ { false, 0x26ba, 0x26ba }, +/* 0x26bb */ { false, 0x26bb, 0x26bb }, +/* 0x26bc */ { false, 0x26bc, 0x26bc }, +/* 0x26bd */ { false, 0x26bd, 0x26bd }, +/* 0x26be */ { false, 0x26be, 0x26be }, +/* 0x26bf */ { false, 0x26bf, 0x26bf }, +/* 0x26c0 */ { false, 0x26c0, 0x26c0 }, +/* 0x26c1 */ { false, 0x26c1, 0x26c1 }, +/* 0x26c2 */ { false, 0x26c2, 0x26c2 }, +/* 0x26c3 */ { false, 0x26c3, 0x26c3 }, +/* 0x26c4 */ { false, 0x26c4, 0x26c4 }, +/* 0x26c5 */ { false, 0x26c5, 0x26c5 }, +/* 0x26c6 */ { false, 0x26c6, 0x26c6 }, +/* 0x26c7 */ { false, 0x26c7, 0x26c7 }, +/* 0x26c8 */ { false, 0x26c8, 0x26c8 }, +/* 0x26c9 */ { false, 0x26c9, 0x26c9 }, +/* 0x26ca */ { false, 0x26ca, 0x26ca }, +/* 0x26cb */ { false, 0x26cb, 0x26cb }, +/* 0x26cc */ { false, 0x26cc, 0x26cc }, +/* 0x26cd */ { false, 0x26cd, 0x26cd }, +/* 0x26ce */ { false, 0x26ce, 0x26ce }, +/* 0x26cf */ { false, 0x26cf, 0x26cf }, +/* 0x26d0 */ { false, 0x26d0, 0x26d0 }, +/* 0x26d1 */ { false, 0x26d1, 0x26d1 }, +/* 0x26d2 */ { false, 0x26d2, 0x26d2 }, +/* 0x26d3 */ { false, 0x26d3, 0x26d3 }, +/* 0x26d4 */ { false, 0x26d4, 0x26d4 }, +/* 0x26d5 */ { false, 0x26d5, 0x26d5 }, +/* 0x26d6 */ { false, 0x26d6, 0x26d6 }, +/* 0x26d7 */ { false, 0x26d7, 0x26d7 }, +/* 0x26d8 */ { false, 0x26d8, 0x26d8 }, +/* 0x26d9 */ { false, 0x26d9, 0x26d9 }, +/* 0x26da */ { false, 0x26da, 0x26da }, +/* 0x26db */ { false, 0x26db, 0x26db }, +/* 0x26dc */ { false, 0x26dc, 0x26dc }, +/* 0x26dd */ { false, 0x26dd, 0x26dd }, +/* 0x26de */ { false, 0x26de, 0x26de }, +/* 0x26df */ { false, 0x26df, 0x26df }, +/* 0x26e0 */ { false, 0x26e0, 0x26e0 }, +/* 0x26e1 */ { false, 0x26e1, 0x26e1 }, +/* 0x26e2 */ { false, 0x26e2, 0x26e2 }, +/* 0x26e3 */ { false, 0x26e3, 0x26e3 }, +/* 0x26e4 */ { false, 0x26e4, 0x26e4 }, +/* 0x26e5 */ { false, 0x26e5, 0x26e5 }, +/* 0x26e6 */ { false, 0x26e6, 0x26e6 }, +/* 0x26e7 */ { false, 0x26e7, 0x26e7 }, +/* 0x26e8 */ { false, 0x26e8, 0x26e8 }, +/* 0x26e9 */ { false, 0x26e9, 0x26e9 }, +/* 0x26ea */ { false, 0x26ea, 0x26ea }, +/* 0x26eb */ { false, 0x26eb, 0x26eb }, +/* 0x26ec */ { false, 0x26ec, 0x26ec }, +/* 0x26ed */ { false, 0x26ed, 0x26ed }, +/* 0x26ee */ { false, 0x26ee, 0x26ee }, +/* 0x26ef */ { false, 0x26ef, 0x26ef }, +/* 0x26f0 */ { false, 0x26f0, 0x26f0 }, +/* 0x26f1 */ { false, 0x26f1, 0x26f1 }, +/* 0x26f2 */ { false, 0x26f2, 0x26f2 }, +/* 0x26f3 */ { false, 0x26f3, 0x26f3 }, +/* 0x26f4 */ { false, 0x26f4, 0x26f4 }, +/* 0x26f5 */ { false, 0x26f5, 0x26f5 }, +/* 0x26f6 */ { false, 0x26f6, 0x26f6 }, +/* 0x26f7 */ { false, 0x26f7, 0x26f7 }, +/* 0x26f8 */ { false, 0x26f8, 0x26f8 }, +/* 0x26f9 */ { false, 0x26f9, 0x26f9 }, +/* 0x26fa */ { false, 0x26fa, 0x26fa }, +/* 0x26fb */ { false, 0x26fb, 0x26fb }, +/* 0x26fc */ { false, 0x26fc, 0x26fc }, +/* 0x26fd */ { false, 0x26fd, 0x26fd }, +/* 0x26fe */ { false, 0x26fe, 0x26fe }, +/* 0x26ff */ { false, 0x26ff, 0x26ff }, +/* 0x2700 */ { false, 0x2700, 0x2700 }, +/* 0x2701 */ { false, 0x2701, 0x2701 }, +/* 0x2702 */ { false, 0x2702, 0x2702 }, +/* 0x2703 */ { false, 0x2703, 0x2703 }, +/* 0x2704 */ { false, 0x2704, 0x2704 }, +/* 0x2705 */ { false, 0x2705, 0x2705 }, +/* 0x2706 */ { false, 0x2706, 0x2706 }, +/* 0x2707 */ { false, 0x2707, 0x2707 }, +/* 0x2708 */ { false, 0x2708, 0x2708 }, +/* 0x2709 */ { false, 0x2709, 0x2709 }, +/* 0x270a */ { false, 0x270a, 0x270a }, +/* 0x270b */ { false, 0x270b, 0x270b }, +/* 0x270c */ { false, 0x270c, 0x270c }, +/* 0x270d */ { false, 0x270d, 0x270d }, +/* 0x270e */ { false, 0x270e, 0x270e }, +/* 0x270f */ { false, 0x270f, 0x270f }, +/* 0x2710 */ { false, 0x2710, 0x2710 }, +/* 0x2711 */ { false, 0x2711, 0x2711 }, +/* 0x2712 */ { false, 0x2712, 0x2712 }, +/* 0x2713 */ { false, 0x2713, 0x2713 }, +/* 0x2714 */ { false, 0x2714, 0x2714 }, +/* 0x2715 */ { false, 0x2715, 0x2715 }, +/* 0x2716 */ { false, 0x2716, 0x2716 }, +/* 0x2717 */ { false, 0x2717, 0x2717 }, +/* 0x2718 */ { false, 0x2718, 0x2718 }, +/* 0x2719 */ { false, 0x2719, 0x2719 }, +/* 0x271a */ { false, 0x271a, 0x271a }, +/* 0x271b */ { false, 0x271b, 0x271b }, +/* 0x271c */ { false, 0x271c, 0x271c }, +/* 0x271d */ { false, 0x271d, 0x271d }, +/* 0x271e */ { false, 0x271e, 0x271e }, +/* 0x271f */ { false, 0x271f, 0x271f }, +/* 0x2720 */ { false, 0x2720, 0x2720 }, +/* 0x2721 */ { false, 0x2721, 0x2721 }, +/* 0x2722 */ { false, 0x2722, 0x2722 }, +/* 0x2723 */ { false, 0x2723, 0x2723 }, +/* 0x2724 */ { false, 0x2724, 0x2724 }, +/* 0x2725 */ { false, 0x2725, 0x2725 }, +/* 0x2726 */ { false, 0x2726, 0x2726 }, +/* 0x2727 */ { false, 0x2727, 0x2727 }, +/* 0x2728 */ { false, 0x2728, 0x2728 }, +/* 0x2729 */ { false, 0x2729, 0x2729 }, +/* 0x272a */ { false, 0x272a, 0x272a }, +/* 0x272b */ { false, 0x272b, 0x272b }, +/* 0x272c */ { false, 0x272c, 0x272c }, +/* 0x272d */ { false, 0x272d, 0x272d }, +/* 0x272e */ { false, 0x272e, 0x272e }, +/* 0x272f */ { false, 0x272f, 0x272f }, +/* 0x2730 */ { false, 0x2730, 0x2730 }, +/* 0x2731 */ { false, 0x2731, 0x2731 }, +/* 0x2732 */ { false, 0x2732, 0x2732 }, +/* 0x2733 */ { false, 0x2733, 0x2733 }, +/* 0x2734 */ { false, 0x2734, 0x2734 }, +/* 0x2735 */ { false, 0x2735, 0x2735 }, +/* 0x2736 */ { false, 0x2736, 0x2736 }, +/* 0x2737 */ { false, 0x2737, 0x2737 }, +/* 0x2738 */ { false, 0x2738, 0x2738 }, +/* 0x2739 */ { false, 0x2739, 0x2739 }, +/* 0x273a */ { false, 0x273a, 0x273a }, +/* 0x273b */ { false, 0x273b, 0x273b }, +/* 0x273c */ { false, 0x273c, 0x273c }, +/* 0x273d */ { false, 0x273d, 0x273d }, +/* 0x273e */ { false, 0x273e, 0x273e }, +/* 0x273f */ { false, 0x273f, 0x273f }, +/* 0x2740 */ { false, 0x2740, 0x2740 }, +/* 0x2741 */ { false, 0x2741, 0x2741 }, +/* 0x2742 */ { false, 0x2742, 0x2742 }, +/* 0x2743 */ { false, 0x2743, 0x2743 }, +/* 0x2744 */ { false, 0x2744, 0x2744 }, +/* 0x2745 */ { false, 0x2745, 0x2745 }, +/* 0x2746 */ { false, 0x2746, 0x2746 }, +/* 0x2747 */ { false, 0x2747, 0x2747 }, +/* 0x2748 */ { false, 0x2748, 0x2748 }, +/* 0x2749 */ { false, 0x2749, 0x2749 }, +/* 0x274a */ { false, 0x274a, 0x274a }, +/* 0x274b */ { false, 0x274b, 0x274b }, +/* 0x274c */ { false, 0x274c, 0x274c }, +/* 0x274d */ { false, 0x274d, 0x274d }, +/* 0x274e */ { false, 0x274e, 0x274e }, +/* 0x274f */ { false, 0x274f, 0x274f }, +/* 0x2750 */ { false, 0x2750, 0x2750 }, +/* 0x2751 */ { false, 0x2751, 0x2751 }, +/* 0x2752 */ { false, 0x2752, 0x2752 }, +/* 0x2753 */ { false, 0x2753, 0x2753 }, +/* 0x2754 */ { false, 0x2754, 0x2754 }, +/* 0x2755 */ { false, 0x2755, 0x2755 }, +/* 0x2756 */ { false, 0x2756, 0x2756 }, +/* 0x2757 */ { false, 0x2757, 0x2757 }, +/* 0x2758 */ { false, 0x2758, 0x2758 }, +/* 0x2759 */ { false, 0x2759, 0x2759 }, +/* 0x275a */ { false, 0x275a, 0x275a }, +/* 0x275b */ { false, 0x275b, 0x275b }, +/* 0x275c */ { false, 0x275c, 0x275c }, +/* 0x275d */ { false, 0x275d, 0x275d }, +/* 0x275e */ { false, 0x275e, 0x275e }, +/* 0x275f */ { false, 0x275f, 0x275f }, +/* 0x2760 */ { false, 0x2760, 0x2760 }, +/* 0x2761 */ { false, 0x2761, 0x2761 }, +/* 0x2762 */ { false, 0x2762, 0x2762 }, +/* 0x2763 */ { false, 0x2763, 0x2763 }, +/* 0x2764 */ { false, 0x2764, 0x2764 }, +/* 0x2765 */ { false, 0x2765, 0x2765 }, +/* 0x2766 */ { false, 0x2766, 0x2766 }, +/* 0x2767 */ { false, 0x2767, 0x2767 }, +/* 0x2768 */ { false, 0x2768, 0x2768 }, +/* 0x2769 */ { false, 0x2769, 0x2769 }, +/* 0x276a */ { false, 0x276a, 0x276a }, +/* 0x276b */ { false, 0x276b, 0x276b }, +/* 0x276c */ { false, 0x276c, 0x276c }, +/* 0x276d */ { false, 0x276d, 0x276d }, +/* 0x276e */ { false, 0x276e, 0x276e }, +/* 0x276f */ { false, 0x276f, 0x276f }, +/* 0x2770 */ { false, 0x2770, 0x2770 }, +/* 0x2771 */ { false, 0x2771, 0x2771 }, +/* 0x2772 */ { false, 0x2772, 0x2772 }, +/* 0x2773 */ { false, 0x2773, 0x2773 }, +/* 0x2774 */ { false, 0x2774, 0x2774 }, +/* 0x2775 */ { false, 0x2775, 0x2775 }, +/* 0x2776 */ { false, 0x2776, 0x2776 }, +/* 0x2777 */ { false, 0x2777, 0x2777 }, +/* 0x2778 */ { false, 0x2778, 0x2778 }, +/* 0x2779 */ { false, 0x2779, 0x2779 }, +/* 0x277a */ { false, 0x277a, 0x277a }, +/* 0x277b */ { false, 0x277b, 0x277b }, +/* 0x277c */ { false, 0x277c, 0x277c }, +/* 0x277d */ { false, 0x277d, 0x277d }, +/* 0x277e */ { false, 0x277e, 0x277e }, +/* 0x277f */ { false, 0x277f, 0x277f }, +/* 0x2780 */ { false, 0x2780, 0x2780 }, +/* 0x2781 */ { false, 0x2781, 0x2781 }, +/* 0x2782 */ { false, 0x2782, 0x2782 }, +/* 0x2783 */ { false, 0x2783, 0x2783 }, +/* 0x2784 */ { false, 0x2784, 0x2784 }, +/* 0x2785 */ { false, 0x2785, 0x2785 }, +/* 0x2786 */ { false, 0x2786, 0x2786 }, +/* 0x2787 */ { false, 0x2787, 0x2787 }, +/* 0x2788 */ { false, 0x2788, 0x2788 }, +/* 0x2789 */ { false, 0x2789, 0x2789 }, +/* 0x278a */ { false, 0x278a, 0x278a }, +/* 0x278b */ { false, 0x278b, 0x278b }, +/* 0x278c */ { false, 0x278c, 0x278c }, +/* 0x278d */ { false, 0x278d, 0x278d }, +/* 0x278e */ { false, 0x278e, 0x278e }, +/* 0x278f */ { false, 0x278f, 0x278f }, +/* 0x2790 */ { false, 0x2790, 0x2790 }, +/* 0x2791 */ { false, 0x2791, 0x2791 }, +/* 0x2792 */ { false, 0x2792, 0x2792 }, +/* 0x2793 */ { false, 0x2793, 0x2793 }, +/* 0x2794 */ { false, 0x2794, 0x2794 }, +/* 0x2795 */ { false, 0x2795, 0x2795 }, +/* 0x2796 */ { false, 0x2796, 0x2796 }, +/* 0x2797 */ { false, 0x2797, 0x2797 }, +/* 0x2798 */ { false, 0x2798, 0x2798 }, +/* 0x2799 */ { false, 0x2799, 0x2799 }, +/* 0x279a */ { false, 0x279a, 0x279a }, +/* 0x279b */ { false, 0x279b, 0x279b }, +/* 0x279c */ { false, 0x279c, 0x279c }, +/* 0x279d */ { false, 0x279d, 0x279d }, +/* 0x279e */ { false, 0x279e, 0x279e }, +/* 0x279f */ { false, 0x279f, 0x279f }, +/* 0x27a0 */ { false, 0x27a0, 0x27a0 }, +/* 0x27a1 */ { false, 0x27a1, 0x27a1 }, +/* 0x27a2 */ { false, 0x27a2, 0x27a2 }, +/* 0x27a3 */ { false, 0x27a3, 0x27a3 }, +/* 0x27a4 */ { false, 0x27a4, 0x27a4 }, +/* 0x27a5 */ { false, 0x27a5, 0x27a5 }, +/* 0x27a6 */ { false, 0x27a6, 0x27a6 }, +/* 0x27a7 */ { false, 0x27a7, 0x27a7 }, +/* 0x27a8 */ { false, 0x27a8, 0x27a8 }, +/* 0x27a9 */ { false, 0x27a9, 0x27a9 }, +/* 0x27aa */ { false, 0x27aa, 0x27aa }, +/* 0x27ab */ { false, 0x27ab, 0x27ab }, +/* 0x27ac */ { false, 0x27ac, 0x27ac }, +/* 0x27ad */ { false, 0x27ad, 0x27ad }, +/* 0x27ae */ { false, 0x27ae, 0x27ae }, +/* 0x27af */ { false, 0x27af, 0x27af }, +/* 0x27b0 */ { false, 0x27b0, 0x27b0 }, +/* 0x27b1 */ { false, 0x27b1, 0x27b1 }, +/* 0x27b2 */ { false, 0x27b2, 0x27b2 }, +/* 0x27b3 */ { false, 0x27b3, 0x27b3 }, +/* 0x27b4 */ { false, 0x27b4, 0x27b4 }, +/* 0x27b5 */ { false, 0x27b5, 0x27b5 }, +/* 0x27b6 */ { false, 0x27b6, 0x27b6 }, +/* 0x27b7 */ { false, 0x27b7, 0x27b7 }, +/* 0x27b8 */ { false, 0x27b8, 0x27b8 }, +/* 0x27b9 */ { false, 0x27b9, 0x27b9 }, +/* 0x27ba */ { false, 0x27ba, 0x27ba }, +/* 0x27bb */ { false, 0x27bb, 0x27bb }, +/* 0x27bc */ { false, 0x27bc, 0x27bc }, +/* 0x27bd */ { false, 0x27bd, 0x27bd }, +/* 0x27be */ { false, 0x27be, 0x27be }, +/* 0x27bf */ { false, 0x27bf, 0x27bf }, +/* 0x27c0 */ { false, 0x27c0, 0x27c0 }, +/* 0x27c1 */ { false, 0x27c1, 0x27c1 }, +/* 0x27c2 */ { false, 0x27c2, 0x27c2 }, +/* 0x27c3 */ { false, 0x27c3, 0x27c3 }, +/* 0x27c4 */ { false, 0x27c4, 0x27c4 }, +/* 0x27c5 */ { false, 0x27c5, 0x27c5 }, +/* 0x27c6 */ { false, 0x27c6, 0x27c6 }, +/* 0x27c7 */ { false, 0x27c7, 0x27c7 }, +/* 0x27c8 */ { false, 0x27c8, 0x27c8 }, +/* 0x27c9 */ { false, 0x27c9, 0x27c9 }, +/* 0x27ca */ { false, 0x27ca, 0x27ca }, +/* 0x27cb */ { false, 0x27cb, 0x27cb }, +/* 0x27cc */ { false, 0x27cc, 0x27cc }, +/* 0x27cd */ { false, 0x27cd, 0x27cd }, +/* 0x27ce */ { false, 0x27ce, 0x27ce }, +/* 0x27cf */ { false, 0x27cf, 0x27cf }, +/* 0x27d0 */ { false, 0x27d0, 0x27d0 }, +/* 0x27d1 */ { false, 0x27d1, 0x27d1 }, +/* 0x27d2 */ { false, 0x27d2, 0x27d2 }, +/* 0x27d3 */ { false, 0x27d3, 0x27d3 }, +/* 0x27d4 */ { false, 0x27d4, 0x27d4 }, +/* 0x27d5 */ { false, 0x27d5, 0x27d5 }, +/* 0x27d6 */ { false, 0x27d6, 0x27d6 }, +/* 0x27d7 */ { false, 0x27d7, 0x27d7 }, +/* 0x27d8 */ { false, 0x27d8, 0x27d8 }, +/* 0x27d9 */ { false, 0x27d9, 0x27d9 }, +/* 0x27da */ { false, 0x27da, 0x27da }, +/* 0x27db */ { false, 0x27db, 0x27db }, +/* 0x27dc */ { false, 0x27dc, 0x27dc }, +/* 0x27dd */ { false, 0x27dd, 0x27dd }, +/* 0x27de */ { false, 0x27de, 0x27de }, +/* 0x27df */ { false, 0x27df, 0x27df }, +/* 0x27e0 */ { false, 0x27e0, 0x27e0 }, +/* 0x27e1 */ { false, 0x27e1, 0x27e1 }, +/* 0x27e2 */ { false, 0x27e2, 0x27e2 }, +/* 0x27e3 */ { false, 0x27e3, 0x27e3 }, +/* 0x27e4 */ { false, 0x27e4, 0x27e4 }, +/* 0x27e5 */ { false, 0x27e5, 0x27e5 }, +/* 0x27e6 */ { false, 0x27e6, 0x27e6 }, +/* 0x27e7 */ { false, 0x27e7, 0x27e7 }, +/* 0x27e8 */ { false, 0x27e8, 0x27e8 }, +/* 0x27e9 */ { false, 0x27e9, 0x27e9 }, +/* 0x27ea */ { false, 0x27ea, 0x27ea }, +/* 0x27eb */ { false, 0x27eb, 0x27eb }, +/* 0x27ec */ { false, 0x27ec, 0x27ec }, +/* 0x27ed */ { false, 0x27ed, 0x27ed }, +/* 0x27ee */ { false, 0x27ee, 0x27ee }, +/* 0x27ef */ { false, 0x27ef, 0x27ef }, +/* 0x27f0 */ { false, 0x27f0, 0x27f0 }, +/* 0x27f1 */ { false, 0x27f1, 0x27f1 }, +/* 0x27f2 */ { false, 0x27f2, 0x27f2 }, +/* 0x27f3 */ { false, 0x27f3, 0x27f3 }, +/* 0x27f4 */ { false, 0x27f4, 0x27f4 }, +/* 0x27f5 */ { false, 0x27f5, 0x27f5 }, +/* 0x27f6 */ { false, 0x27f6, 0x27f6 }, +/* 0x27f7 */ { false, 0x27f7, 0x27f7 }, +/* 0x27f8 */ { false, 0x27f8, 0x27f8 }, +/* 0x27f9 */ { false, 0x27f9, 0x27f9 }, +/* 0x27fa */ { false, 0x27fa, 0x27fa }, +/* 0x27fb */ { false, 0x27fb, 0x27fb }, +/* 0x27fc */ { false, 0x27fc, 0x27fc }, +/* 0x27fd */ { false, 0x27fd, 0x27fd }, +/* 0x27fe */ { false, 0x27fe, 0x27fe }, +/* 0x27ff */ { false, 0x27ff, 0x27ff }, +/* 0x2800 */ { false, 0x2800, 0x2800 }, +/* 0x2801 */ { false, 0x2801, 0x2801 }, +/* 0x2802 */ { false, 0x2802, 0x2802 }, +/* 0x2803 */ { false, 0x2803, 0x2803 }, +/* 0x2804 */ { false, 0x2804, 0x2804 }, +/* 0x2805 */ { false, 0x2805, 0x2805 }, +/* 0x2806 */ { false, 0x2806, 0x2806 }, +/* 0x2807 */ { false, 0x2807, 0x2807 }, +/* 0x2808 */ { false, 0x2808, 0x2808 }, +/* 0x2809 */ { false, 0x2809, 0x2809 }, +/* 0x280a */ { false, 0x280a, 0x280a }, +/* 0x280b */ { false, 0x280b, 0x280b }, +/* 0x280c */ { false, 0x280c, 0x280c }, +/* 0x280d */ { false, 0x280d, 0x280d }, +/* 0x280e */ { false, 0x280e, 0x280e }, +/* 0x280f */ { false, 0x280f, 0x280f }, +/* 0x2810 */ { false, 0x2810, 0x2810 }, +/* 0x2811 */ { false, 0x2811, 0x2811 }, +/* 0x2812 */ { false, 0x2812, 0x2812 }, +/* 0x2813 */ { false, 0x2813, 0x2813 }, +/* 0x2814 */ { false, 0x2814, 0x2814 }, +/* 0x2815 */ { false, 0x2815, 0x2815 }, +/* 0x2816 */ { false, 0x2816, 0x2816 }, +/* 0x2817 */ { false, 0x2817, 0x2817 }, +/* 0x2818 */ { false, 0x2818, 0x2818 }, +/* 0x2819 */ { false, 0x2819, 0x2819 }, +/* 0x281a */ { false, 0x281a, 0x281a }, +/* 0x281b */ { false, 0x281b, 0x281b }, +/* 0x281c */ { false, 0x281c, 0x281c }, +/* 0x281d */ { false, 0x281d, 0x281d }, +/* 0x281e */ { false, 0x281e, 0x281e }, +/* 0x281f */ { false, 0x281f, 0x281f }, +/* 0x2820 */ { false, 0x2820, 0x2820 }, +/* 0x2821 */ { false, 0x2821, 0x2821 }, +/* 0x2822 */ { false, 0x2822, 0x2822 }, +/* 0x2823 */ { false, 0x2823, 0x2823 }, +/* 0x2824 */ { false, 0x2824, 0x2824 }, +/* 0x2825 */ { false, 0x2825, 0x2825 }, +/* 0x2826 */ { false, 0x2826, 0x2826 }, +/* 0x2827 */ { false, 0x2827, 0x2827 }, +/* 0x2828 */ { false, 0x2828, 0x2828 }, +/* 0x2829 */ { false, 0x2829, 0x2829 }, +/* 0x282a */ { false, 0x282a, 0x282a }, +/* 0x282b */ { false, 0x282b, 0x282b }, +/* 0x282c */ { false, 0x282c, 0x282c }, +/* 0x282d */ { false, 0x282d, 0x282d }, +/* 0x282e */ { false, 0x282e, 0x282e }, +/* 0x282f */ { false, 0x282f, 0x282f }, +/* 0x2830 */ { false, 0x2830, 0x2830 }, +/* 0x2831 */ { false, 0x2831, 0x2831 }, +/* 0x2832 */ { false, 0x2832, 0x2832 }, +/* 0x2833 */ { false, 0x2833, 0x2833 }, +/* 0x2834 */ { false, 0x2834, 0x2834 }, +/* 0x2835 */ { false, 0x2835, 0x2835 }, +/* 0x2836 */ { false, 0x2836, 0x2836 }, +/* 0x2837 */ { false, 0x2837, 0x2837 }, +/* 0x2838 */ { false, 0x2838, 0x2838 }, +/* 0x2839 */ { false, 0x2839, 0x2839 }, +/* 0x283a */ { false, 0x283a, 0x283a }, +/* 0x283b */ { false, 0x283b, 0x283b }, +/* 0x283c */ { false, 0x283c, 0x283c }, +/* 0x283d */ { false, 0x283d, 0x283d }, +/* 0x283e */ { false, 0x283e, 0x283e }, +/* 0x283f */ { false, 0x283f, 0x283f }, +/* 0x2840 */ { false, 0x2840, 0x2840 }, +/* 0x2841 */ { false, 0x2841, 0x2841 }, +/* 0x2842 */ { false, 0x2842, 0x2842 }, +/* 0x2843 */ { false, 0x2843, 0x2843 }, +/* 0x2844 */ { false, 0x2844, 0x2844 }, +/* 0x2845 */ { false, 0x2845, 0x2845 }, +/* 0x2846 */ { false, 0x2846, 0x2846 }, +/* 0x2847 */ { false, 0x2847, 0x2847 }, +/* 0x2848 */ { false, 0x2848, 0x2848 }, +/* 0x2849 */ { false, 0x2849, 0x2849 }, +/* 0x284a */ { false, 0x284a, 0x284a }, +/* 0x284b */ { false, 0x284b, 0x284b }, +/* 0x284c */ { false, 0x284c, 0x284c }, +/* 0x284d */ { false, 0x284d, 0x284d }, +/* 0x284e */ { false, 0x284e, 0x284e }, +/* 0x284f */ { false, 0x284f, 0x284f }, +/* 0x2850 */ { false, 0x2850, 0x2850 }, +/* 0x2851 */ { false, 0x2851, 0x2851 }, +/* 0x2852 */ { false, 0x2852, 0x2852 }, +/* 0x2853 */ { false, 0x2853, 0x2853 }, +/* 0x2854 */ { false, 0x2854, 0x2854 }, +/* 0x2855 */ { false, 0x2855, 0x2855 }, +/* 0x2856 */ { false, 0x2856, 0x2856 }, +/* 0x2857 */ { false, 0x2857, 0x2857 }, +/* 0x2858 */ { false, 0x2858, 0x2858 }, +/* 0x2859 */ { false, 0x2859, 0x2859 }, +/* 0x285a */ { false, 0x285a, 0x285a }, +/* 0x285b */ { false, 0x285b, 0x285b }, +/* 0x285c */ { false, 0x285c, 0x285c }, +/* 0x285d */ { false, 0x285d, 0x285d }, +/* 0x285e */ { false, 0x285e, 0x285e }, +/* 0x285f */ { false, 0x285f, 0x285f }, +/* 0x2860 */ { false, 0x2860, 0x2860 }, +/* 0x2861 */ { false, 0x2861, 0x2861 }, +/* 0x2862 */ { false, 0x2862, 0x2862 }, +/* 0x2863 */ { false, 0x2863, 0x2863 }, +/* 0x2864 */ { false, 0x2864, 0x2864 }, +/* 0x2865 */ { false, 0x2865, 0x2865 }, +/* 0x2866 */ { false, 0x2866, 0x2866 }, +/* 0x2867 */ { false, 0x2867, 0x2867 }, +/* 0x2868 */ { false, 0x2868, 0x2868 }, +/* 0x2869 */ { false, 0x2869, 0x2869 }, +/* 0x286a */ { false, 0x286a, 0x286a }, +/* 0x286b */ { false, 0x286b, 0x286b }, +/* 0x286c */ { false, 0x286c, 0x286c }, +/* 0x286d */ { false, 0x286d, 0x286d }, +/* 0x286e */ { false, 0x286e, 0x286e }, +/* 0x286f */ { false, 0x286f, 0x286f }, +/* 0x2870 */ { false, 0x2870, 0x2870 }, +/* 0x2871 */ { false, 0x2871, 0x2871 }, +/* 0x2872 */ { false, 0x2872, 0x2872 }, +/* 0x2873 */ { false, 0x2873, 0x2873 }, +/* 0x2874 */ { false, 0x2874, 0x2874 }, +/* 0x2875 */ { false, 0x2875, 0x2875 }, +/* 0x2876 */ { false, 0x2876, 0x2876 }, +/* 0x2877 */ { false, 0x2877, 0x2877 }, +/* 0x2878 */ { false, 0x2878, 0x2878 }, +/* 0x2879 */ { false, 0x2879, 0x2879 }, +/* 0x287a */ { false, 0x287a, 0x287a }, +/* 0x287b */ { false, 0x287b, 0x287b }, +/* 0x287c */ { false, 0x287c, 0x287c }, +/* 0x287d */ { false, 0x287d, 0x287d }, +/* 0x287e */ { false, 0x287e, 0x287e }, +/* 0x287f */ { false, 0x287f, 0x287f }, +/* 0x2880 */ { false, 0x2880, 0x2880 }, +/* 0x2881 */ { false, 0x2881, 0x2881 }, +/* 0x2882 */ { false, 0x2882, 0x2882 }, +/* 0x2883 */ { false, 0x2883, 0x2883 }, +/* 0x2884 */ { false, 0x2884, 0x2884 }, +/* 0x2885 */ { false, 0x2885, 0x2885 }, +/* 0x2886 */ { false, 0x2886, 0x2886 }, +/* 0x2887 */ { false, 0x2887, 0x2887 }, +/* 0x2888 */ { false, 0x2888, 0x2888 }, +/* 0x2889 */ { false, 0x2889, 0x2889 }, +/* 0x288a */ { false, 0x288a, 0x288a }, +/* 0x288b */ { false, 0x288b, 0x288b }, +/* 0x288c */ { false, 0x288c, 0x288c }, +/* 0x288d */ { false, 0x288d, 0x288d }, +/* 0x288e */ { false, 0x288e, 0x288e }, +/* 0x288f */ { false, 0x288f, 0x288f }, +/* 0x2890 */ { false, 0x2890, 0x2890 }, +/* 0x2891 */ { false, 0x2891, 0x2891 }, +/* 0x2892 */ { false, 0x2892, 0x2892 }, +/* 0x2893 */ { false, 0x2893, 0x2893 }, +/* 0x2894 */ { false, 0x2894, 0x2894 }, +/* 0x2895 */ { false, 0x2895, 0x2895 }, +/* 0x2896 */ { false, 0x2896, 0x2896 }, +/* 0x2897 */ { false, 0x2897, 0x2897 }, +/* 0x2898 */ { false, 0x2898, 0x2898 }, +/* 0x2899 */ { false, 0x2899, 0x2899 }, +/* 0x289a */ { false, 0x289a, 0x289a }, +/* 0x289b */ { false, 0x289b, 0x289b }, +/* 0x289c */ { false, 0x289c, 0x289c }, +/* 0x289d */ { false, 0x289d, 0x289d }, +/* 0x289e */ { false, 0x289e, 0x289e }, +/* 0x289f */ { false, 0x289f, 0x289f }, +/* 0x28a0 */ { false, 0x28a0, 0x28a0 }, +/* 0x28a1 */ { false, 0x28a1, 0x28a1 }, +/* 0x28a2 */ { false, 0x28a2, 0x28a2 }, +/* 0x28a3 */ { false, 0x28a3, 0x28a3 }, +/* 0x28a4 */ { false, 0x28a4, 0x28a4 }, +/* 0x28a5 */ { false, 0x28a5, 0x28a5 }, +/* 0x28a6 */ { false, 0x28a6, 0x28a6 }, +/* 0x28a7 */ { false, 0x28a7, 0x28a7 }, +/* 0x28a8 */ { false, 0x28a8, 0x28a8 }, +/* 0x28a9 */ { false, 0x28a9, 0x28a9 }, +/* 0x28aa */ { false, 0x28aa, 0x28aa }, +/* 0x28ab */ { false, 0x28ab, 0x28ab }, +/* 0x28ac */ { false, 0x28ac, 0x28ac }, +/* 0x28ad */ { false, 0x28ad, 0x28ad }, +/* 0x28ae */ { false, 0x28ae, 0x28ae }, +/* 0x28af */ { false, 0x28af, 0x28af }, +/* 0x28b0 */ { false, 0x28b0, 0x28b0 }, +/* 0x28b1 */ { false, 0x28b1, 0x28b1 }, +/* 0x28b2 */ { false, 0x28b2, 0x28b2 }, +/* 0x28b3 */ { false, 0x28b3, 0x28b3 }, +/* 0x28b4 */ { false, 0x28b4, 0x28b4 }, +/* 0x28b5 */ { false, 0x28b5, 0x28b5 }, +/* 0x28b6 */ { false, 0x28b6, 0x28b6 }, +/* 0x28b7 */ { false, 0x28b7, 0x28b7 }, +/* 0x28b8 */ { false, 0x28b8, 0x28b8 }, +/* 0x28b9 */ { false, 0x28b9, 0x28b9 }, +/* 0x28ba */ { false, 0x28ba, 0x28ba }, +/* 0x28bb */ { false, 0x28bb, 0x28bb }, +/* 0x28bc */ { false, 0x28bc, 0x28bc }, +/* 0x28bd */ { false, 0x28bd, 0x28bd }, +/* 0x28be */ { false, 0x28be, 0x28be }, +/* 0x28bf */ { false, 0x28bf, 0x28bf }, +/* 0x28c0 */ { false, 0x28c0, 0x28c0 }, +/* 0x28c1 */ { false, 0x28c1, 0x28c1 }, +/* 0x28c2 */ { false, 0x28c2, 0x28c2 }, +/* 0x28c3 */ { false, 0x28c3, 0x28c3 }, +/* 0x28c4 */ { false, 0x28c4, 0x28c4 }, +/* 0x28c5 */ { false, 0x28c5, 0x28c5 }, +/* 0x28c6 */ { false, 0x28c6, 0x28c6 }, +/* 0x28c7 */ { false, 0x28c7, 0x28c7 }, +/* 0x28c8 */ { false, 0x28c8, 0x28c8 }, +/* 0x28c9 */ { false, 0x28c9, 0x28c9 }, +/* 0x28ca */ { false, 0x28ca, 0x28ca }, +/* 0x28cb */ { false, 0x28cb, 0x28cb }, +/* 0x28cc */ { false, 0x28cc, 0x28cc }, +/* 0x28cd */ { false, 0x28cd, 0x28cd }, +/* 0x28ce */ { false, 0x28ce, 0x28ce }, +/* 0x28cf */ { false, 0x28cf, 0x28cf }, +/* 0x28d0 */ { false, 0x28d0, 0x28d0 }, +/* 0x28d1 */ { false, 0x28d1, 0x28d1 }, +/* 0x28d2 */ { false, 0x28d2, 0x28d2 }, +/* 0x28d3 */ { false, 0x28d3, 0x28d3 }, +/* 0x28d4 */ { false, 0x28d4, 0x28d4 }, +/* 0x28d5 */ { false, 0x28d5, 0x28d5 }, +/* 0x28d6 */ { false, 0x28d6, 0x28d6 }, +/* 0x28d7 */ { false, 0x28d7, 0x28d7 }, +/* 0x28d8 */ { false, 0x28d8, 0x28d8 }, +/* 0x28d9 */ { false, 0x28d9, 0x28d9 }, +/* 0x28da */ { false, 0x28da, 0x28da }, +/* 0x28db */ { false, 0x28db, 0x28db }, +/* 0x28dc */ { false, 0x28dc, 0x28dc }, +/* 0x28dd */ { false, 0x28dd, 0x28dd }, +/* 0x28de */ { false, 0x28de, 0x28de }, +/* 0x28df */ { false, 0x28df, 0x28df }, +/* 0x28e0 */ { false, 0x28e0, 0x28e0 }, +/* 0x28e1 */ { false, 0x28e1, 0x28e1 }, +/* 0x28e2 */ { false, 0x28e2, 0x28e2 }, +/* 0x28e3 */ { false, 0x28e3, 0x28e3 }, +/* 0x28e4 */ { false, 0x28e4, 0x28e4 }, +/* 0x28e5 */ { false, 0x28e5, 0x28e5 }, +/* 0x28e6 */ { false, 0x28e6, 0x28e6 }, +/* 0x28e7 */ { false, 0x28e7, 0x28e7 }, +/* 0x28e8 */ { false, 0x28e8, 0x28e8 }, +/* 0x28e9 */ { false, 0x28e9, 0x28e9 }, +/* 0x28ea */ { false, 0x28ea, 0x28ea }, +/* 0x28eb */ { false, 0x28eb, 0x28eb }, +/* 0x28ec */ { false, 0x28ec, 0x28ec }, +/* 0x28ed */ { false, 0x28ed, 0x28ed }, +/* 0x28ee */ { false, 0x28ee, 0x28ee }, +/* 0x28ef */ { false, 0x28ef, 0x28ef }, +/* 0x28f0 */ { false, 0x28f0, 0x28f0 }, +/* 0x28f1 */ { false, 0x28f1, 0x28f1 }, +/* 0x28f2 */ { false, 0x28f2, 0x28f2 }, +/* 0x28f3 */ { false, 0x28f3, 0x28f3 }, +/* 0x28f4 */ { false, 0x28f4, 0x28f4 }, +/* 0x28f5 */ { false, 0x28f5, 0x28f5 }, +/* 0x28f6 */ { false, 0x28f6, 0x28f6 }, +/* 0x28f7 */ { false, 0x28f7, 0x28f7 }, +/* 0x28f8 */ { false, 0x28f8, 0x28f8 }, +/* 0x28f9 */ { false, 0x28f9, 0x28f9 }, +/* 0x28fa */ { false, 0x28fa, 0x28fa }, +/* 0x28fb */ { false, 0x28fb, 0x28fb }, +/* 0x28fc */ { false, 0x28fc, 0x28fc }, +/* 0x28fd */ { false, 0x28fd, 0x28fd }, +/* 0x28fe */ { false, 0x28fe, 0x28fe }, +/* 0x28ff */ { false, 0x28ff, 0x28ff }, +/* 0x2900 */ { false, 0x2900, 0x2900 }, +/* 0x2901 */ { false, 0x2901, 0x2901 }, +/* 0x2902 */ { false, 0x2902, 0x2902 }, +/* 0x2903 */ { false, 0x2903, 0x2903 }, +/* 0x2904 */ { false, 0x2904, 0x2904 }, +/* 0x2905 */ { false, 0x2905, 0x2905 }, +/* 0x2906 */ { false, 0x2906, 0x2906 }, +/* 0x2907 */ { false, 0x2907, 0x2907 }, +/* 0x2908 */ { false, 0x2908, 0x2908 }, +/* 0x2909 */ { false, 0x2909, 0x2909 }, +/* 0x290a */ { false, 0x290a, 0x290a }, +/* 0x290b */ { false, 0x290b, 0x290b }, +/* 0x290c */ { false, 0x290c, 0x290c }, +/* 0x290d */ { false, 0x290d, 0x290d }, +/* 0x290e */ { false, 0x290e, 0x290e }, +/* 0x290f */ { false, 0x290f, 0x290f }, +/* 0x2910 */ { false, 0x2910, 0x2910 }, +/* 0x2911 */ { false, 0x2911, 0x2911 }, +/* 0x2912 */ { false, 0x2912, 0x2912 }, +/* 0x2913 */ { false, 0x2913, 0x2913 }, +/* 0x2914 */ { false, 0x2914, 0x2914 }, +/* 0x2915 */ { false, 0x2915, 0x2915 }, +/* 0x2916 */ { false, 0x2916, 0x2916 }, +/* 0x2917 */ { false, 0x2917, 0x2917 }, +/* 0x2918 */ { false, 0x2918, 0x2918 }, +/* 0x2919 */ { false, 0x2919, 0x2919 }, +/* 0x291a */ { false, 0x291a, 0x291a }, +/* 0x291b */ { false, 0x291b, 0x291b }, +/* 0x291c */ { false, 0x291c, 0x291c }, +/* 0x291d */ { false, 0x291d, 0x291d }, +/* 0x291e */ { false, 0x291e, 0x291e }, +/* 0x291f */ { false, 0x291f, 0x291f }, +/* 0x2920 */ { false, 0x2920, 0x2920 }, +/* 0x2921 */ { false, 0x2921, 0x2921 }, +/* 0x2922 */ { false, 0x2922, 0x2922 }, +/* 0x2923 */ { false, 0x2923, 0x2923 }, +/* 0x2924 */ { false, 0x2924, 0x2924 }, +/* 0x2925 */ { false, 0x2925, 0x2925 }, +/* 0x2926 */ { false, 0x2926, 0x2926 }, +/* 0x2927 */ { false, 0x2927, 0x2927 }, +/* 0x2928 */ { false, 0x2928, 0x2928 }, +/* 0x2929 */ { false, 0x2929, 0x2929 }, +/* 0x292a */ { false, 0x292a, 0x292a }, +/* 0x292b */ { false, 0x292b, 0x292b }, +/* 0x292c */ { false, 0x292c, 0x292c }, +/* 0x292d */ { false, 0x292d, 0x292d }, +/* 0x292e */ { false, 0x292e, 0x292e }, +/* 0x292f */ { false, 0x292f, 0x292f }, +/* 0x2930 */ { false, 0x2930, 0x2930 }, +/* 0x2931 */ { false, 0x2931, 0x2931 }, +/* 0x2932 */ { false, 0x2932, 0x2932 }, +/* 0x2933 */ { false, 0x2933, 0x2933 }, +/* 0x2934 */ { false, 0x2934, 0x2934 }, +/* 0x2935 */ { false, 0x2935, 0x2935 }, +/* 0x2936 */ { false, 0x2936, 0x2936 }, +/* 0x2937 */ { false, 0x2937, 0x2937 }, +/* 0x2938 */ { false, 0x2938, 0x2938 }, +/* 0x2939 */ { false, 0x2939, 0x2939 }, +/* 0x293a */ { false, 0x293a, 0x293a }, +/* 0x293b */ { false, 0x293b, 0x293b }, +/* 0x293c */ { false, 0x293c, 0x293c }, +/* 0x293d */ { false, 0x293d, 0x293d }, +/* 0x293e */ { false, 0x293e, 0x293e }, +/* 0x293f */ { false, 0x293f, 0x293f }, +/* 0x2940 */ { false, 0x2940, 0x2940 }, +/* 0x2941 */ { false, 0x2941, 0x2941 }, +/* 0x2942 */ { false, 0x2942, 0x2942 }, +/* 0x2943 */ { false, 0x2943, 0x2943 }, +/* 0x2944 */ { false, 0x2944, 0x2944 }, +/* 0x2945 */ { false, 0x2945, 0x2945 }, +/* 0x2946 */ { false, 0x2946, 0x2946 }, +/* 0x2947 */ { false, 0x2947, 0x2947 }, +/* 0x2948 */ { false, 0x2948, 0x2948 }, +/* 0x2949 */ { false, 0x2949, 0x2949 }, +/* 0x294a */ { false, 0x294a, 0x294a }, +/* 0x294b */ { false, 0x294b, 0x294b }, +/* 0x294c */ { false, 0x294c, 0x294c }, +/* 0x294d */ { false, 0x294d, 0x294d }, +/* 0x294e */ { false, 0x294e, 0x294e }, +/* 0x294f */ { false, 0x294f, 0x294f }, +/* 0x2950 */ { false, 0x2950, 0x2950 }, +/* 0x2951 */ { false, 0x2951, 0x2951 }, +/* 0x2952 */ { false, 0x2952, 0x2952 }, +/* 0x2953 */ { false, 0x2953, 0x2953 }, +/* 0x2954 */ { false, 0x2954, 0x2954 }, +/* 0x2955 */ { false, 0x2955, 0x2955 }, +/* 0x2956 */ { false, 0x2956, 0x2956 }, +/* 0x2957 */ { false, 0x2957, 0x2957 }, +/* 0x2958 */ { false, 0x2958, 0x2958 }, +/* 0x2959 */ { false, 0x2959, 0x2959 }, +/* 0x295a */ { false, 0x295a, 0x295a }, +/* 0x295b */ { false, 0x295b, 0x295b }, +/* 0x295c */ { false, 0x295c, 0x295c }, +/* 0x295d */ { false, 0x295d, 0x295d }, +/* 0x295e */ { false, 0x295e, 0x295e }, +/* 0x295f */ { false, 0x295f, 0x295f }, +/* 0x2960 */ { false, 0x2960, 0x2960 }, +/* 0x2961 */ { false, 0x2961, 0x2961 }, +/* 0x2962 */ { false, 0x2962, 0x2962 }, +/* 0x2963 */ { false, 0x2963, 0x2963 }, +/* 0x2964 */ { false, 0x2964, 0x2964 }, +/* 0x2965 */ { false, 0x2965, 0x2965 }, +/* 0x2966 */ { false, 0x2966, 0x2966 }, +/* 0x2967 */ { false, 0x2967, 0x2967 }, +/* 0x2968 */ { false, 0x2968, 0x2968 }, +/* 0x2969 */ { false, 0x2969, 0x2969 }, +/* 0x296a */ { false, 0x296a, 0x296a }, +/* 0x296b */ { false, 0x296b, 0x296b }, +/* 0x296c */ { false, 0x296c, 0x296c }, +/* 0x296d */ { false, 0x296d, 0x296d }, +/* 0x296e */ { false, 0x296e, 0x296e }, +/* 0x296f */ { false, 0x296f, 0x296f }, +/* 0x2970 */ { false, 0x2970, 0x2970 }, +/* 0x2971 */ { false, 0x2971, 0x2971 }, +/* 0x2972 */ { false, 0x2972, 0x2972 }, +/* 0x2973 */ { false, 0x2973, 0x2973 }, +/* 0x2974 */ { false, 0x2974, 0x2974 }, +/* 0x2975 */ { false, 0x2975, 0x2975 }, +/* 0x2976 */ { false, 0x2976, 0x2976 }, +/* 0x2977 */ { false, 0x2977, 0x2977 }, +/* 0x2978 */ { false, 0x2978, 0x2978 }, +/* 0x2979 */ { false, 0x2979, 0x2979 }, +/* 0x297a */ { false, 0x297a, 0x297a }, +/* 0x297b */ { false, 0x297b, 0x297b }, +/* 0x297c */ { false, 0x297c, 0x297c }, +/* 0x297d */ { false, 0x297d, 0x297d }, +/* 0x297e */ { false, 0x297e, 0x297e }, +/* 0x297f */ { false, 0x297f, 0x297f }, +/* 0x2980 */ { false, 0x2980, 0x2980 }, +/* 0x2981 */ { false, 0x2981, 0x2981 }, +/* 0x2982 */ { false, 0x2982, 0x2982 }, +/* 0x2983 */ { false, 0x2983, 0x2983 }, +/* 0x2984 */ { false, 0x2984, 0x2984 }, +/* 0x2985 */ { false, 0x2985, 0x2985 }, +/* 0x2986 */ { false, 0x2986, 0x2986 }, +/* 0x2987 */ { false, 0x2987, 0x2987 }, +/* 0x2988 */ { false, 0x2988, 0x2988 }, +/* 0x2989 */ { false, 0x2989, 0x2989 }, +/* 0x298a */ { false, 0x298a, 0x298a }, +/* 0x298b */ { false, 0x298b, 0x298b }, +/* 0x298c */ { false, 0x298c, 0x298c }, +/* 0x298d */ { false, 0x298d, 0x298d }, +/* 0x298e */ { false, 0x298e, 0x298e }, +/* 0x298f */ { false, 0x298f, 0x298f }, +/* 0x2990 */ { false, 0x2990, 0x2990 }, +/* 0x2991 */ { false, 0x2991, 0x2991 }, +/* 0x2992 */ { false, 0x2992, 0x2992 }, +/* 0x2993 */ { false, 0x2993, 0x2993 }, +/* 0x2994 */ { false, 0x2994, 0x2994 }, +/* 0x2995 */ { false, 0x2995, 0x2995 }, +/* 0x2996 */ { false, 0x2996, 0x2996 }, +/* 0x2997 */ { false, 0x2997, 0x2997 }, +/* 0x2998 */ { false, 0x2998, 0x2998 }, +/* 0x2999 */ { false, 0x2999, 0x2999 }, +/* 0x299a */ { false, 0x299a, 0x299a }, +/* 0x299b */ { false, 0x299b, 0x299b }, +/* 0x299c */ { false, 0x299c, 0x299c }, +/* 0x299d */ { false, 0x299d, 0x299d }, +/* 0x299e */ { false, 0x299e, 0x299e }, +/* 0x299f */ { false, 0x299f, 0x299f }, +/* 0x29a0 */ { false, 0x29a0, 0x29a0 }, +/* 0x29a1 */ { false, 0x29a1, 0x29a1 }, +/* 0x29a2 */ { false, 0x29a2, 0x29a2 }, +/* 0x29a3 */ { false, 0x29a3, 0x29a3 }, +/* 0x29a4 */ { false, 0x29a4, 0x29a4 }, +/* 0x29a5 */ { false, 0x29a5, 0x29a5 }, +/* 0x29a6 */ { false, 0x29a6, 0x29a6 }, +/* 0x29a7 */ { false, 0x29a7, 0x29a7 }, +/* 0x29a8 */ { false, 0x29a8, 0x29a8 }, +/* 0x29a9 */ { false, 0x29a9, 0x29a9 }, +/* 0x29aa */ { false, 0x29aa, 0x29aa }, +/* 0x29ab */ { false, 0x29ab, 0x29ab }, +/* 0x29ac */ { false, 0x29ac, 0x29ac }, +/* 0x29ad */ { false, 0x29ad, 0x29ad }, +/* 0x29ae */ { false, 0x29ae, 0x29ae }, +/* 0x29af */ { false, 0x29af, 0x29af }, +/* 0x29b0 */ { false, 0x29b0, 0x29b0 }, +/* 0x29b1 */ { false, 0x29b1, 0x29b1 }, +/* 0x29b2 */ { false, 0x29b2, 0x29b2 }, +/* 0x29b3 */ { false, 0x29b3, 0x29b3 }, +/* 0x29b4 */ { false, 0x29b4, 0x29b4 }, +/* 0x29b5 */ { false, 0x29b5, 0x29b5 }, +/* 0x29b6 */ { false, 0x29b6, 0x29b6 }, +/* 0x29b7 */ { false, 0x29b7, 0x29b7 }, +/* 0x29b8 */ { false, 0x29b8, 0x29b8 }, +/* 0x29b9 */ { false, 0x29b9, 0x29b9 }, +/* 0x29ba */ { false, 0x29ba, 0x29ba }, +/* 0x29bb */ { false, 0x29bb, 0x29bb }, +/* 0x29bc */ { false, 0x29bc, 0x29bc }, +/* 0x29bd */ { false, 0x29bd, 0x29bd }, +/* 0x29be */ { false, 0x29be, 0x29be }, +/* 0x29bf */ { false, 0x29bf, 0x29bf }, +/* 0x29c0 */ { false, 0x29c0, 0x29c0 }, +/* 0x29c1 */ { false, 0x29c1, 0x29c1 }, +/* 0x29c2 */ { false, 0x29c2, 0x29c2 }, +/* 0x29c3 */ { false, 0x29c3, 0x29c3 }, +/* 0x29c4 */ { false, 0x29c4, 0x29c4 }, +/* 0x29c5 */ { false, 0x29c5, 0x29c5 }, +/* 0x29c6 */ { false, 0x29c6, 0x29c6 }, +/* 0x29c7 */ { false, 0x29c7, 0x29c7 }, +/* 0x29c8 */ { false, 0x29c8, 0x29c8 }, +/* 0x29c9 */ { false, 0x29c9, 0x29c9 }, +/* 0x29ca */ { false, 0x29ca, 0x29ca }, +/* 0x29cb */ { false, 0x29cb, 0x29cb }, +/* 0x29cc */ { false, 0x29cc, 0x29cc }, +/* 0x29cd */ { false, 0x29cd, 0x29cd }, +/* 0x29ce */ { false, 0x29ce, 0x29ce }, +/* 0x29cf */ { false, 0x29cf, 0x29cf }, +/* 0x29d0 */ { false, 0x29d0, 0x29d0 }, +/* 0x29d1 */ { false, 0x29d1, 0x29d1 }, +/* 0x29d2 */ { false, 0x29d2, 0x29d2 }, +/* 0x29d3 */ { false, 0x29d3, 0x29d3 }, +/* 0x29d4 */ { false, 0x29d4, 0x29d4 }, +/* 0x29d5 */ { false, 0x29d5, 0x29d5 }, +/* 0x29d6 */ { false, 0x29d6, 0x29d6 }, +/* 0x29d7 */ { false, 0x29d7, 0x29d7 }, +/* 0x29d8 */ { false, 0x29d8, 0x29d8 }, +/* 0x29d9 */ { false, 0x29d9, 0x29d9 }, +/* 0x29da */ { false, 0x29da, 0x29da }, +/* 0x29db */ { false, 0x29db, 0x29db }, +/* 0x29dc */ { false, 0x29dc, 0x29dc }, +/* 0x29dd */ { false, 0x29dd, 0x29dd }, +/* 0x29de */ { false, 0x29de, 0x29de }, +/* 0x29df */ { false, 0x29df, 0x29df }, +/* 0x29e0 */ { false, 0x29e0, 0x29e0 }, +/* 0x29e1 */ { false, 0x29e1, 0x29e1 }, +/* 0x29e2 */ { false, 0x29e2, 0x29e2 }, +/* 0x29e3 */ { false, 0x29e3, 0x29e3 }, +/* 0x29e4 */ { false, 0x29e4, 0x29e4 }, +/* 0x29e5 */ { false, 0x29e5, 0x29e5 }, +/* 0x29e6 */ { false, 0x29e6, 0x29e6 }, +/* 0x29e7 */ { false, 0x29e7, 0x29e7 }, +/* 0x29e8 */ { false, 0x29e8, 0x29e8 }, +/* 0x29e9 */ { false, 0x29e9, 0x29e9 }, +/* 0x29ea */ { false, 0x29ea, 0x29ea }, +/* 0x29eb */ { false, 0x29eb, 0x29eb }, +/* 0x29ec */ { false, 0x29ec, 0x29ec }, +/* 0x29ed */ { false, 0x29ed, 0x29ed }, +/* 0x29ee */ { false, 0x29ee, 0x29ee }, +/* 0x29ef */ { false, 0x29ef, 0x29ef }, +/* 0x29f0 */ { false, 0x29f0, 0x29f0 }, +/* 0x29f1 */ { false, 0x29f1, 0x29f1 }, +/* 0x29f2 */ { false, 0x29f2, 0x29f2 }, +/* 0x29f3 */ { false, 0x29f3, 0x29f3 }, +/* 0x29f4 */ { false, 0x29f4, 0x29f4 }, +/* 0x29f5 */ { false, 0x29f5, 0x29f5 }, +/* 0x29f6 */ { false, 0x29f6, 0x29f6 }, +/* 0x29f7 */ { false, 0x29f7, 0x29f7 }, +/* 0x29f8 */ { false, 0x29f8, 0x29f8 }, +/* 0x29f9 */ { false, 0x29f9, 0x29f9 }, +/* 0x29fa */ { false, 0x29fa, 0x29fa }, +/* 0x29fb */ { false, 0x29fb, 0x29fb }, +/* 0x29fc */ { false, 0x29fc, 0x29fc }, +/* 0x29fd */ { false, 0x29fd, 0x29fd }, +/* 0x29fe */ { false, 0x29fe, 0x29fe }, +/* 0x29ff */ { false, 0x29ff, 0x29ff }, +/* 0x2a00 */ { false, 0x2a00, 0x2a00 }, +/* 0x2a01 */ { false, 0x2a01, 0x2a01 }, +/* 0x2a02 */ { false, 0x2a02, 0x2a02 }, +/* 0x2a03 */ { false, 0x2a03, 0x2a03 }, +/* 0x2a04 */ { false, 0x2a04, 0x2a04 }, +/* 0x2a05 */ { false, 0x2a05, 0x2a05 }, +/* 0x2a06 */ { false, 0x2a06, 0x2a06 }, +/* 0x2a07 */ { false, 0x2a07, 0x2a07 }, +/* 0x2a08 */ { false, 0x2a08, 0x2a08 }, +/* 0x2a09 */ { false, 0x2a09, 0x2a09 }, +/* 0x2a0a */ { false, 0x2a0a, 0x2a0a }, +/* 0x2a0b */ { false, 0x2a0b, 0x2a0b }, +/* 0x2a0c */ { false, 0x2a0c, 0x2a0c }, +/* 0x2a0d */ { false, 0x2a0d, 0x2a0d }, +/* 0x2a0e */ { false, 0x2a0e, 0x2a0e }, +/* 0x2a0f */ { false, 0x2a0f, 0x2a0f }, +/* 0x2a10 */ { false, 0x2a10, 0x2a10 }, +/* 0x2a11 */ { false, 0x2a11, 0x2a11 }, +/* 0x2a12 */ { false, 0x2a12, 0x2a12 }, +/* 0x2a13 */ { false, 0x2a13, 0x2a13 }, +/* 0x2a14 */ { false, 0x2a14, 0x2a14 }, +/* 0x2a15 */ { false, 0x2a15, 0x2a15 }, +/* 0x2a16 */ { false, 0x2a16, 0x2a16 }, +/* 0x2a17 */ { false, 0x2a17, 0x2a17 }, +/* 0x2a18 */ { false, 0x2a18, 0x2a18 }, +/* 0x2a19 */ { false, 0x2a19, 0x2a19 }, +/* 0x2a1a */ { false, 0x2a1a, 0x2a1a }, +/* 0x2a1b */ { false, 0x2a1b, 0x2a1b }, +/* 0x2a1c */ { false, 0x2a1c, 0x2a1c }, +/* 0x2a1d */ { false, 0x2a1d, 0x2a1d }, +/* 0x2a1e */ { false, 0x2a1e, 0x2a1e }, +/* 0x2a1f */ { false, 0x2a1f, 0x2a1f }, +/* 0x2a20 */ { false, 0x2a20, 0x2a20 }, +/* 0x2a21 */ { false, 0x2a21, 0x2a21 }, +/* 0x2a22 */ { false, 0x2a22, 0x2a22 }, +/* 0x2a23 */ { false, 0x2a23, 0x2a23 }, +/* 0x2a24 */ { false, 0x2a24, 0x2a24 }, +/* 0x2a25 */ { false, 0x2a25, 0x2a25 }, +/* 0x2a26 */ { false, 0x2a26, 0x2a26 }, +/* 0x2a27 */ { false, 0x2a27, 0x2a27 }, +/* 0x2a28 */ { false, 0x2a28, 0x2a28 }, +/* 0x2a29 */ { false, 0x2a29, 0x2a29 }, +/* 0x2a2a */ { false, 0x2a2a, 0x2a2a }, +/* 0x2a2b */ { false, 0x2a2b, 0x2a2b }, +/* 0x2a2c */ { false, 0x2a2c, 0x2a2c }, +/* 0x2a2d */ { false, 0x2a2d, 0x2a2d }, +/* 0x2a2e */ { false, 0x2a2e, 0x2a2e }, +/* 0x2a2f */ { false, 0x2a2f, 0x2a2f }, +/* 0x2a30 */ { false, 0x2a30, 0x2a30 }, +/* 0x2a31 */ { false, 0x2a31, 0x2a31 }, +/* 0x2a32 */ { false, 0x2a32, 0x2a32 }, +/* 0x2a33 */ { false, 0x2a33, 0x2a33 }, +/* 0x2a34 */ { false, 0x2a34, 0x2a34 }, +/* 0x2a35 */ { false, 0x2a35, 0x2a35 }, +/* 0x2a36 */ { false, 0x2a36, 0x2a36 }, +/* 0x2a37 */ { false, 0x2a37, 0x2a37 }, +/* 0x2a38 */ { false, 0x2a38, 0x2a38 }, +/* 0x2a39 */ { false, 0x2a39, 0x2a39 }, +/* 0x2a3a */ { false, 0x2a3a, 0x2a3a }, +/* 0x2a3b */ { false, 0x2a3b, 0x2a3b }, +/* 0x2a3c */ { false, 0x2a3c, 0x2a3c }, +/* 0x2a3d */ { false, 0x2a3d, 0x2a3d }, +/* 0x2a3e */ { false, 0x2a3e, 0x2a3e }, +/* 0x2a3f */ { false, 0x2a3f, 0x2a3f }, +/* 0x2a40 */ { false, 0x2a40, 0x2a40 }, +/* 0x2a41 */ { false, 0x2a41, 0x2a41 }, +/* 0x2a42 */ { false, 0x2a42, 0x2a42 }, +/* 0x2a43 */ { false, 0x2a43, 0x2a43 }, +/* 0x2a44 */ { false, 0x2a44, 0x2a44 }, +/* 0x2a45 */ { false, 0x2a45, 0x2a45 }, +/* 0x2a46 */ { false, 0x2a46, 0x2a46 }, +/* 0x2a47 */ { false, 0x2a47, 0x2a47 }, +/* 0x2a48 */ { false, 0x2a48, 0x2a48 }, +/* 0x2a49 */ { false, 0x2a49, 0x2a49 }, +/* 0x2a4a */ { false, 0x2a4a, 0x2a4a }, +/* 0x2a4b */ { false, 0x2a4b, 0x2a4b }, +/* 0x2a4c */ { false, 0x2a4c, 0x2a4c }, +/* 0x2a4d */ { false, 0x2a4d, 0x2a4d }, +/* 0x2a4e */ { false, 0x2a4e, 0x2a4e }, +/* 0x2a4f */ { false, 0x2a4f, 0x2a4f }, +/* 0x2a50 */ { false, 0x2a50, 0x2a50 }, +/* 0x2a51 */ { false, 0x2a51, 0x2a51 }, +/* 0x2a52 */ { false, 0x2a52, 0x2a52 }, +/* 0x2a53 */ { false, 0x2a53, 0x2a53 }, +/* 0x2a54 */ { false, 0x2a54, 0x2a54 }, +/* 0x2a55 */ { false, 0x2a55, 0x2a55 }, +/* 0x2a56 */ { false, 0x2a56, 0x2a56 }, +/* 0x2a57 */ { false, 0x2a57, 0x2a57 }, +/* 0x2a58 */ { false, 0x2a58, 0x2a58 }, +/* 0x2a59 */ { false, 0x2a59, 0x2a59 }, +/* 0x2a5a */ { false, 0x2a5a, 0x2a5a }, +/* 0x2a5b */ { false, 0x2a5b, 0x2a5b }, +/* 0x2a5c */ { false, 0x2a5c, 0x2a5c }, +/* 0x2a5d */ { false, 0x2a5d, 0x2a5d }, +/* 0x2a5e */ { false, 0x2a5e, 0x2a5e }, +/* 0x2a5f */ { false, 0x2a5f, 0x2a5f }, +/* 0x2a60 */ { false, 0x2a60, 0x2a60 }, +/* 0x2a61 */ { false, 0x2a61, 0x2a61 }, +/* 0x2a62 */ { false, 0x2a62, 0x2a62 }, +/* 0x2a63 */ { false, 0x2a63, 0x2a63 }, +/* 0x2a64 */ { false, 0x2a64, 0x2a64 }, +/* 0x2a65 */ { false, 0x2a65, 0x2a65 }, +/* 0x2a66 */ { false, 0x2a66, 0x2a66 }, +/* 0x2a67 */ { false, 0x2a67, 0x2a67 }, +/* 0x2a68 */ { false, 0x2a68, 0x2a68 }, +/* 0x2a69 */ { false, 0x2a69, 0x2a69 }, +/* 0x2a6a */ { false, 0x2a6a, 0x2a6a }, +/* 0x2a6b */ { false, 0x2a6b, 0x2a6b }, +/* 0x2a6c */ { false, 0x2a6c, 0x2a6c }, +/* 0x2a6d */ { false, 0x2a6d, 0x2a6d }, +/* 0x2a6e */ { false, 0x2a6e, 0x2a6e }, +/* 0x2a6f */ { false, 0x2a6f, 0x2a6f }, +/* 0x2a70 */ { false, 0x2a70, 0x2a70 }, +/* 0x2a71 */ { false, 0x2a71, 0x2a71 }, +/* 0x2a72 */ { false, 0x2a72, 0x2a72 }, +/* 0x2a73 */ { false, 0x2a73, 0x2a73 }, +/* 0x2a74 */ { false, 0x2a74, 0x2a74 }, +/* 0x2a75 */ { false, 0x2a75, 0x2a75 }, +/* 0x2a76 */ { false, 0x2a76, 0x2a76 }, +/* 0x2a77 */ { false, 0x2a77, 0x2a77 }, +/* 0x2a78 */ { false, 0x2a78, 0x2a78 }, +/* 0x2a79 */ { false, 0x2a79, 0x2a79 }, +/* 0x2a7a */ { false, 0x2a7a, 0x2a7a }, +/* 0x2a7b */ { false, 0x2a7b, 0x2a7b }, +/* 0x2a7c */ { false, 0x2a7c, 0x2a7c }, +/* 0x2a7d */ { false, 0x2a7d, 0x2a7d }, +/* 0x2a7e */ { false, 0x2a7e, 0x2a7e }, +/* 0x2a7f */ { false, 0x2a7f, 0x2a7f }, +/* 0x2a80 */ { false, 0x2a80, 0x2a80 }, +/* 0x2a81 */ { false, 0x2a81, 0x2a81 }, +/* 0x2a82 */ { false, 0x2a82, 0x2a82 }, +/* 0x2a83 */ { false, 0x2a83, 0x2a83 }, +/* 0x2a84 */ { false, 0x2a84, 0x2a84 }, +/* 0x2a85 */ { false, 0x2a85, 0x2a85 }, +/* 0x2a86 */ { false, 0x2a86, 0x2a86 }, +/* 0x2a87 */ { false, 0x2a87, 0x2a87 }, +/* 0x2a88 */ { false, 0x2a88, 0x2a88 }, +/* 0x2a89 */ { false, 0x2a89, 0x2a89 }, +/* 0x2a8a */ { false, 0x2a8a, 0x2a8a }, +/* 0x2a8b */ { false, 0x2a8b, 0x2a8b }, +/* 0x2a8c */ { false, 0x2a8c, 0x2a8c }, +/* 0x2a8d */ { false, 0x2a8d, 0x2a8d }, +/* 0x2a8e */ { false, 0x2a8e, 0x2a8e }, +/* 0x2a8f */ { false, 0x2a8f, 0x2a8f }, +/* 0x2a90 */ { false, 0x2a90, 0x2a90 }, +/* 0x2a91 */ { false, 0x2a91, 0x2a91 }, +/* 0x2a92 */ { false, 0x2a92, 0x2a92 }, +/* 0x2a93 */ { false, 0x2a93, 0x2a93 }, +/* 0x2a94 */ { false, 0x2a94, 0x2a94 }, +/* 0x2a95 */ { false, 0x2a95, 0x2a95 }, +/* 0x2a96 */ { false, 0x2a96, 0x2a96 }, +/* 0x2a97 */ { false, 0x2a97, 0x2a97 }, +/* 0x2a98 */ { false, 0x2a98, 0x2a98 }, +/* 0x2a99 */ { false, 0x2a99, 0x2a99 }, +/* 0x2a9a */ { false, 0x2a9a, 0x2a9a }, +/* 0x2a9b */ { false, 0x2a9b, 0x2a9b }, +/* 0x2a9c */ { false, 0x2a9c, 0x2a9c }, +/* 0x2a9d */ { false, 0x2a9d, 0x2a9d }, +/* 0x2a9e */ { false, 0x2a9e, 0x2a9e }, +/* 0x2a9f */ { false, 0x2a9f, 0x2a9f }, +/* 0x2aa0 */ { false, 0x2aa0, 0x2aa0 }, +/* 0x2aa1 */ { false, 0x2aa1, 0x2aa1 }, +/* 0x2aa2 */ { false, 0x2aa2, 0x2aa2 }, +/* 0x2aa3 */ { false, 0x2aa3, 0x2aa3 }, +/* 0x2aa4 */ { false, 0x2aa4, 0x2aa4 }, +/* 0x2aa5 */ { false, 0x2aa5, 0x2aa5 }, +/* 0x2aa6 */ { false, 0x2aa6, 0x2aa6 }, +/* 0x2aa7 */ { false, 0x2aa7, 0x2aa7 }, +/* 0x2aa8 */ { false, 0x2aa8, 0x2aa8 }, +/* 0x2aa9 */ { false, 0x2aa9, 0x2aa9 }, +/* 0x2aaa */ { false, 0x2aaa, 0x2aaa }, +/* 0x2aab */ { false, 0x2aab, 0x2aab }, +/* 0x2aac */ { false, 0x2aac, 0x2aac }, +/* 0x2aad */ { false, 0x2aad, 0x2aad }, +/* 0x2aae */ { false, 0x2aae, 0x2aae }, +/* 0x2aaf */ { false, 0x2aaf, 0x2aaf }, +/* 0x2ab0 */ { false, 0x2ab0, 0x2ab0 }, +/* 0x2ab1 */ { false, 0x2ab1, 0x2ab1 }, +/* 0x2ab2 */ { false, 0x2ab2, 0x2ab2 }, +/* 0x2ab3 */ { false, 0x2ab3, 0x2ab3 }, +/* 0x2ab4 */ { false, 0x2ab4, 0x2ab4 }, +/* 0x2ab5 */ { false, 0x2ab5, 0x2ab5 }, +/* 0x2ab6 */ { false, 0x2ab6, 0x2ab6 }, +/* 0x2ab7 */ { false, 0x2ab7, 0x2ab7 }, +/* 0x2ab8 */ { false, 0x2ab8, 0x2ab8 }, +/* 0x2ab9 */ { false, 0x2ab9, 0x2ab9 }, +/* 0x2aba */ { false, 0x2aba, 0x2aba }, +/* 0x2abb */ { false, 0x2abb, 0x2abb }, +/* 0x2abc */ { false, 0x2abc, 0x2abc }, +/* 0x2abd */ { false, 0x2abd, 0x2abd }, +/* 0x2abe */ { false, 0x2abe, 0x2abe }, +/* 0x2abf */ { false, 0x2abf, 0x2abf }, +/* 0x2ac0 */ { false, 0x2ac0, 0x2ac0 }, +/* 0x2ac1 */ { false, 0x2ac1, 0x2ac1 }, +/* 0x2ac2 */ { false, 0x2ac2, 0x2ac2 }, +/* 0x2ac3 */ { false, 0x2ac3, 0x2ac3 }, +/* 0x2ac4 */ { false, 0x2ac4, 0x2ac4 }, +/* 0x2ac5 */ { false, 0x2ac5, 0x2ac5 }, +/* 0x2ac6 */ { false, 0x2ac6, 0x2ac6 }, +/* 0x2ac7 */ { false, 0x2ac7, 0x2ac7 }, +/* 0x2ac8 */ { false, 0x2ac8, 0x2ac8 }, +/* 0x2ac9 */ { false, 0x2ac9, 0x2ac9 }, +/* 0x2aca */ { false, 0x2aca, 0x2aca }, +/* 0x2acb */ { false, 0x2acb, 0x2acb }, +/* 0x2acc */ { false, 0x2acc, 0x2acc }, +/* 0x2acd */ { false, 0x2acd, 0x2acd }, +/* 0x2ace */ { false, 0x2ace, 0x2ace }, +/* 0x2acf */ { false, 0x2acf, 0x2acf }, +/* 0x2ad0 */ { false, 0x2ad0, 0x2ad0 }, +/* 0x2ad1 */ { false, 0x2ad1, 0x2ad1 }, +/* 0x2ad2 */ { false, 0x2ad2, 0x2ad2 }, +/* 0x2ad3 */ { false, 0x2ad3, 0x2ad3 }, +/* 0x2ad4 */ { false, 0x2ad4, 0x2ad4 }, +/* 0x2ad5 */ { false, 0x2ad5, 0x2ad5 }, +/* 0x2ad6 */ { false, 0x2ad6, 0x2ad6 }, +/* 0x2ad7 */ { false, 0x2ad7, 0x2ad7 }, +/* 0x2ad8 */ { false, 0x2ad8, 0x2ad8 }, +/* 0x2ad9 */ { false, 0x2ad9, 0x2ad9 }, +/* 0x2ada */ { false, 0x2ada, 0x2ada }, +/* 0x2adb */ { false, 0x2adb, 0x2adb }, +/* 0x2adc */ { false, 0x2adc, 0x2adc }, +/* 0x2add */ { false, 0x2add, 0x2add }, +/* 0x2ade */ { false, 0x2ade, 0x2ade }, +/* 0x2adf */ { false, 0x2adf, 0x2adf }, +/* 0x2ae0 */ { false, 0x2ae0, 0x2ae0 }, +/* 0x2ae1 */ { false, 0x2ae1, 0x2ae1 }, +/* 0x2ae2 */ { false, 0x2ae2, 0x2ae2 }, +/* 0x2ae3 */ { false, 0x2ae3, 0x2ae3 }, +/* 0x2ae4 */ { false, 0x2ae4, 0x2ae4 }, +/* 0x2ae5 */ { false, 0x2ae5, 0x2ae5 }, +/* 0x2ae6 */ { false, 0x2ae6, 0x2ae6 }, +/* 0x2ae7 */ { false, 0x2ae7, 0x2ae7 }, +/* 0x2ae8 */ { false, 0x2ae8, 0x2ae8 }, +/* 0x2ae9 */ { false, 0x2ae9, 0x2ae9 }, +/* 0x2aea */ { false, 0x2aea, 0x2aea }, +/* 0x2aeb */ { false, 0x2aeb, 0x2aeb }, +/* 0x2aec */ { false, 0x2aec, 0x2aec }, +/* 0x2aed */ { false, 0x2aed, 0x2aed }, +/* 0x2aee */ { false, 0x2aee, 0x2aee }, +/* 0x2aef */ { false, 0x2aef, 0x2aef }, +/* 0x2af0 */ { false, 0x2af0, 0x2af0 }, +/* 0x2af1 */ { false, 0x2af1, 0x2af1 }, +/* 0x2af2 */ { false, 0x2af2, 0x2af2 }, +/* 0x2af3 */ { false, 0x2af3, 0x2af3 }, +/* 0x2af4 */ { false, 0x2af4, 0x2af4 }, +/* 0x2af5 */ { false, 0x2af5, 0x2af5 }, +/* 0x2af6 */ { false, 0x2af6, 0x2af6 }, +/* 0x2af7 */ { false, 0x2af7, 0x2af7 }, +/* 0x2af8 */ { false, 0x2af8, 0x2af8 }, +/* 0x2af9 */ { false, 0x2af9, 0x2af9 }, +/* 0x2afa */ { false, 0x2afa, 0x2afa }, +/* 0x2afb */ { false, 0x2afb, 0x2afb }, +/* 0x2afc */ { false, 0x2afc, 0x2afc }, +/* 0x2afd */ { false, 0x2afd, 0x2afd }, +/* 0x2afe */ { false, 0x2afe, 0x2afe }, +/* 0x2aff */ { false, 0x2aff, 0x2aff }, +/* 0x2b00 */ { false, 0x2b00, 0x2b00 }, +/* 0x2b01 */ { false, 0x2b01, 0x2b01 }, +/* 0x2b02 */ { false, 0x2b02, 0x2b02 }, +/* 0x2b03 */ { false, 0x2b03, 0x2b03 }, +/* 0x2b04 */ { false, 0x2b04, 0x2b04 }, +/* 0x2b05 */ { false, 0x2b05, 0x2b05 }, +/* 0x2b06 */ { false, 0x2b06, 0x2b06 }, +/* 0x2b07 */ { false, 0x2b07, 0x2b07 }, +/* 0x2b08 */ { false, 0x2b08, 0x2b08 }, +/* 0x2b09 */ { false, 0x2b09, 0x2b09 }, +/* 0x2b0a */ { false, 0x2b0a, 0x2b0a }, +/* 0x2b0b */ { false, 0x2b0b, 0x2b0b }, +/* 0x2b0c */ { false, 0x2b0c, 0x2b0c }, +/* 0x2b0d */ { false, 0x2b0d, 0x2b0d }, +/* 0x2b0e */ { false, 0x2b0e, 0x2b0e }, +/* 0x2b0f */ { false, 0x2b0f, 0x2b0f }, +/* 0x2b10 */ { false, 0x2b10, 0x2b10 }, +/* 0x2b11 */ { false, 0x2b11, 0x2b11 }, +/* 0x2b12 */ { false, 0x2b12, 0x2b12 }, +/* 0x2b13 */ { false, 0x2b13, 0x2b13 }, +/* 0x2b14 */ { false, 0x2b14, 0x2b14 }, +/* 0x2b15 */ { false, 0x2b15, 0x2b15 }, +/* 0x2b16 */ { false, 0x2b16, 0x2b16 }, +/* 0x2b17 */ { false, 0x2b17, 0x2b17 }, +/* 0x2b18 */ { false, 0x2b18, 0x2b18 }, +/* 0x2b19 */ { false, 0x2b19, 0x2b19 }, +/* 0x2b1a */ { false, 0x2b1a, 0x2b1a }, +/* 0x2b1b */ { false, 0x2b1b, 0x2b1b }, +/* 0x2b1c */ { false, 0x2b1c, 0x2b1c }, +/* 0x2b1d */ { false, 0x2b1d, 0x2b1d }, +/* 0x2b1e */ { false, 0x2b1e, 0x2b1e }, +/* 0x2b1f */ { false, 0x2b1f, 0x2b1f }, +/* 0x2b20 */ { false, 0x2b20, 0x2b20 }, +/* 0x2b21 */ { false, 0x2b21, 0x2b21 }, +/* 0x2b22 */ { false, 0x2b22, 0x2b22 }, +/* 0x2b23 */ { false, 0x2b23, 0x2b23 }, +/* 0x2b24 */ { false, 0x2b24, 0x2b24 }, +/* 0x2b25 */ { false, 0x2b25, 0x2b25 }, +/* 0x2b26 */ { false, 0x2b26, 0x2b26 }, +/* 0x2b27 */ { false, 0x2b27, 0x2b27 }, +/* 0x2b28 */ { false, 0x2b28, 0x2b28 }, +/* 0x2b29 */ { false, 0x2b29, 0x2b29 }, +/* 0x2b2a */ { false, 0x2b2a, 0x2b2a }, +/* 0x2b2b */ { false, 0x2b2b, 0x2b2b }, +/* 0x2b2c */ { false, 0x2b2c, 0x2b2c }, +/* 0x2b2d */ { false, 0x2b2d, 0x2b2d }, +/* 0x2b2e */ { false, 0x2b2e, 0x2b2e }, +/* 0x2b2f */ { false, 0x2b2f, 0x2b2f }, +/* 0x2b30 */ { false, 0x2b30, 0x2b30 }, +/* 0x2b31 */ { false, 0x2b31, 0x2b31 }, +/* 0x2b32 */ { false, 0x2b32, 0x2b32 }, +/* 0x2b33 */ { false, 0x2b33, 0x2b33 }, +/* 0x2b34 */ { false, 0x2b34, 0x2b34 }, +/* 0x2b35 */ { false, 0x2b35, 0x2b35 }, +/* 0x2b36 */ { false, 0x2b36, 0x2b36 }, +/* 0x2b37 */ { false, 0x2b37, 0x2b37 }, +/* 0x2b38 */ { false, 0x2b38, 0x2b38 }, +/* 0x2b39 */ { false, 0x2b39, 0x2b39 }, +/* 0x2b3a */ { false, 0x2b3a, 0x2b3a }, +/* 0x2b3b */ { false, 0x2b3b, 0x2b3b }, +/* 0x2b3c */ { false, 0x2b3c, 0x2b3c }, +/* 0x2b3d */ { false, 0x2b3d, 0x2b3d }, +/* 0x2b3e */ { false, 0x2b3e, 0x2b3e }, +/* 0x2b3f */ { false, 0x2b3f, 0x2b3f }, +/* 0x2b40 */ { false, 0x2b40, 0x2b40 }, +/* 0x2b41 */ { false, 0x2b41, 0x2b41 }, +/* 0x2b42 */ { false, 0x2b42, 0x2b42 }, +/* 0x2b43 */ { false, 0x2b43, 0x2b43 }, +/* 0x2b44 */ { false, 0x2b44, 0x2b44 }, +/* 0x2b45 */ { false, 0x2b45, 0x2b45 }, +/* 0x2b46 */ { false, 0x2b46, 0x2b46 }, +/* 0x2b47 */ { false, 0x2b47, 0x2b47 }, +/* 0x2b48 */ { false, 0x2b48, 0x2b48 }, +/* 0x2b49 */ { false, 0x2b49, 0x2b49 }, +/* 0x2b4a */ { false, 0x2b4a, 0x2b4a }, +/* 0x2b4b */ { false, 0x2b4b, 0x2b4b }, +/* 0x2b4c */ { false, 0x2b4c, 0x2b4c }, +/* 0x2b4d */ { false, 0x2b4d, 0x2b4d }, +/* 0x2b4e */ { false, 0x2b4e, 0x2b4e }, +/* 0x2b4f */ { false, 0x2b4f, 0x2b4f }, +/* 0x2b50 */ { false, 0x2b50, 0x2b50 }, +/* 0x2b51 */ { false, 0x2b51, 0x2b51 }, +/* 0x2b52 */ { false, 0x2b52, 0x2b52 }, +/* 0x2b53 */ { false, 0x2b53, 0x2b53 }, +/* 0x2b54 */ { false, 0x2b54, 0x2b54 }, +/* 0x2b55 */ { false, 0x2b55, 0x2b55 }, +/* 0x2b56 */ { false, 0x2b56, 0x2b56 }, +/* 0x2b57 */ { false, 0x2b57, 0x2b57 }, +/* 0x2b58 */ { false, 0x2b58, 0x2b58 }, +/* 0x2b59 */ { false, 0x2b59, 0x2b59 }, +/* 0x2b5a */ { false, 0x2b5a, 0x2b5a }, +/* 0x2b5b */ { false, 0x2b5b, 0x2b5b }, +/* 0x2b5c */ { false, 0x2b5c, 0x2b5c }, +/* 0x2b5d */ { false, 0x2b5d, 0x2b5d }, +/* 0x2b5e */ { false, 0x2b5e, 0x2b5e }, +/* 0x2b5f */ { false, 0x2b5f, 0x2b5f }, +/* 0x2b60 */ { false, 0x2b60, 0x2b60 }, +/* 0x2b61 */ { false, 0x2b61, 0x2b61 }, +/* 0x2b62 */ { false, 0x2b62, 0x2b62 }, +/* 0x2b63 */ { false, 0x2b63, 0x2b63 }, +/* 0x2b64 */ { false, 0x2b64, 0x2b64 }, +/* 0x2b65 */ { false, 0x2b65, 0x2b65 }, +/* 0x2b66 */ { false, 0x2b66, 0x2b66 }, +/* 0x2b67 */ { false, 0x2b67, 0x2b67 }, +/* 0x2b68 */ { false, 0x2b68, 0x2b68 }, +/* 0x2b69 */ { false, 0x2b69, 0x2b69 }, +/* 0x2b6a */ { false, 0x2b6a, 0x2b6a }, +/* 0x2b6b */ { false, 0x2b6b, 0x2b6b }, +/* 0x2b6c */ { false, 0x2b6c, 0x2b6c }, +/* 0x2b6d */ { false, 0x2b6d, 0x2b6d }, +/* 0x2b6e */ { false, 0x2b6e, 0x2b6e }, +/* 0x2b6f */ { false, 0x2b6f, 0x2b6f }, +/* 0x2b70 */ { false, 0x2b70, 0x2b70 }, +/* 0x2b71 */ { false, 0x2b71, 0x2b71 }, +/* 0x2b72 */ { false, 0x2b72, 0x2b72 }, +/* 0x2b73 */ { false, 0x2b73, 0x2b73 }, +/* 0x2b74 */ { false, 0x2b74, 0x2b74 }, +/* 0x2b75 */ { false, 0x2b75, 0x2b75 }, +/* 0x2b76 */ { false, 0x2b76, 0x2b76 }, +/* 0x2b77 */ { false, 0x2b77, 0x2b77 }, +/* 0x2b78 */ { false, 0x2b78, 0x2b78 }, +/* 0x2b79 */ { false, 0x2b79, 0x2b79 }, +/* 0x2b7a */ { false, 0x2b7a, 0x2b7a }, +/* 0x2b7b */ { false, 0x2b7b, 0x2b7b }, +/* 0x2b7c */ { false, 0x2b7c, 0x2b7c }, +/* 0x2b7d */ { false, 0x2b7d, 0x2b7d }, +/* 0x2b7e */ { false, 0x2b7e, 0x2b7e }, +/* 0x2b7f */ { false, 0x2b7f, 0x2b7f }, +/* 0x2b80 */ { false, 0x2b80, 0x2b80 }, +/* 0x2b81 */ { false, 0x2b81, 0x2b81 }, +/* 0x2b82 */ { false, 0x2b82, 0x2b82 }, +/* 0x2b83 */ { false, 0x2b83, 0x2b83 }, +/* 0x2b84 */ { false, 0x2b84, 0x2b84 }, +/* 0x2b85 */ { false, 0x2b85, 0x2b85 }, +/* 0x2b86 */ { false, 0x2b86, 0x2b86 }, +/* 0x2b87 */ { false, 0x2b87, 0x2b87 }, +/* 0x2b88 */ { false, 0x2b88, 0x2b88 }, +/* 0x2b89 */ { false, 0x2b89, 0x2b89 }, +/* 0x2b8a */ { false, 0x2b8a, 0x2b8a }, +/* 0x2b8b */ { false, 0x2b8b, 0x2b8b }, +/* 0x2b8c */ { false, 0x2b8c, 0x2b8c }, +/* 0x2b8d */ { false, 0x2b8d, 0x2b8d }, +/* 0x2b8e */ { false, 0x2b8e, 0x2b8e }, +/* 0x2b8f */ { false, 0x2b8f, 0x2b8f }, +/* 0x2b90 */ { false, 0x2b90, 0x2b90 }, +/* 0x2b91 */ { false, 0x2b91, 0x2b91 }, +/* 0x2b92 */ { false, 0x2b92, 0x2b92 }, +/* 0x2b93 */ { false, 0x2b93, 0x2b93 }, +/* 0x2b94 */ { false, 0x2b94, 0x2b94 }, +/* 0x2b95 */ { false, 0x2b95, 0x2b95 }, +/* 0x2b96 */ { false, 0x2b96, 0x2b96 }, +/* 0x2b97 */ { false, 0x2b97, 0x2b97 }, +/* 0x2b98 */ { false, 0x2b98, 0x2b98 }, +/* 0x2b99 */ { false, 0x2b99, 0x2b99 }, +/* 0x2b9a */ { false, 0x2b9a, 0x2b9a }, +/* 0x2b9b */ { false, 0x2b9b, 0x2b9b }, +/* 0x2b9c */ { false, 0x2b9c, 0x2b9c }, +/* 0x2b9d */ { false, 0x2b9d, 0x2b9d }, +/* 0x2b9e */ { false, 0x2b9e, 0x2b9e }, +/* 0x2b9f */ { false, 0x2b9f, 0x2b9f }, +/* 0x2ba0 */ { false, 0x2ba0, 0x2ba0 }, +/* 0x2ba1 */ { false, 0x2ba1, 0x2ba1 }, +/* 0x2ba2 */ { false, 0x2ba2, 0x2ba2 }, +/* 0x2ba3 */ { false, 0x2ba3, 0x2ba3 }, +/* 0x2ba4 */ { false, 0x2ba4, 0x2ba4 }, +/* 0x2ba5 */ { false, 0x2ba5, 0x2ba5 }, +/* 0x2ba6 */ { false, 0x2ba6, 0x2ba6 }, +/* 0x2ba7 */ { false, 0x2ba7, 0x2ba7 }, +/* 0x2ba8 */ { false, 0x2ba8, 0x2ba8 }, +/* 0x2ba9 */ { false, 0x2ba9, 0x2ba9 }, +/* 0x2baa */ { false, 0x2baa, 0x2baa }, +/* 0x2bab */ { false, 0x2bab, 0x2bab }, +/* 0x2bac */ { false, 0x2bac, 0x2bac }, +/* 0x2bad */ { false, 0x2bad, 0x2bad }, +/* 0x2bae */ { false, 0x2bae, 0x2bae }, +/* 0x2baf */ { false, 0x2baf, 0x2baf }, +/* 0x2bb0 */ { false, 0x2bb0, 0x2bb0 }, +/* 0x2bb1 */ { false, 0x2bb1, 0x2bb1 }, +/* 0x2bb2 */ { false, 0x2bb2, 0x2bb2 }, +/* 0x2bb3 */ { false, 0x2bb3, 0x2bb3 }, +/* 0x2bb4 */ { false, 0x2bb4, 0x2bb4 }, +/* 0x2bb5 */ { false, 0x2bb5, 0x2bb5 }, +/* 0x2bb6 */ { false, 0x2bb6, 0x2bb6 }, +/* 0x2bb7 */ { false, 0x2bb7, 0x2bb7 }, +/* 0x2bb8 */ { false, 0x2bb8, 0x2bb8 }, +/* 0x2bb9 */ { false, 0x2bb9, 0x2bb9 }, +/* 0x2bba */ { false, 0x2bba, 0x2bba }, +/* 0x2bbb */ { false, 0x2bbb, 0x2bbb }, +/* 0x2bbc */ { false, 0x2bbc, 0x2bbc }, +/* 0x2bbd */ { false, 0x2bbd, 0x2bbd }, +/* 0x2bbe */ { false, 0x2bbe, 0x2bbe }, +/* 0x2bbf */ { false, 0x2bbf, 0x2bbf }, +/* 0x2bc0 */ { false, 0x2bc0, 0x2bc0 }, +/* 0x2bc1 */ { false, 0x2bc1, 0x2bc1 }, +/* 0x2bc2 */ { false, 0x2bc2, 0x2bc2 }, +/* 0x2bc3 */ { false, 0x2bc3, 0x2bc3 }, +/* 0x2bc4 */ { false, 0x2bc4, 0x2bc4 }, +/* 0x2bc5 */ { false, 0x2bc5, 0x2bc5 }, +/* 0x2bc6 */ { false, 0x2bc6, 0x2bc6 }, +/* 0x2bc7 */ { false, 0x2bc7, 0x2bc7 }, +/* 0x2bc8 */ { false, 0x2bc8, 0x2bc8 }, +/* 0x2bc9 */ { false, 0x2bc9, 0x2bc9 }, +/* 0x2bca */ { false, 0x2bca, 0x2bca }, +/* 0x2bcb */ { false, 0x2bcb, 0x2bcb }, +/* 0x2bcc */ { false, 0x2bcc, 0x2bcc }, +/* 0x2bcd */ { false, 0x2bcd, 0x2bcd }, +/* 0x2bce */ { false, 0x2bce, 0x2bce }, +/* 0x2bcf */ { false, 0x2bcf, 0x2bcf }, +/* 0x2bd0 */ { false, 0x2bd0, 0x2bd0 }, +/* 0x2bd1 */ { false, 0x2bd1, 0x2bd1 }, +/* 0x2bd2 */ { false, 0x2bd2, 0x2bd2 }, +/* 0x2bd3 */ { false, 0x2bd3, 0x2bd3 }, +/* 0x2bd4 */ { false, 0x2bd4, 0x2bd4 }, +/* 0x2bd5 */ { false, 0x2bd5, 0x2bd5 }, +/* 0x2bd6 */ { false, 0x2bd6, 0x2bd6 }, +/* 0x2bd7 */ { false, 0x2bd7, 0x2bd7 }, +/* 0x2bd8 */ { false, 0x2bd8, 0x2bd8 }, +/* 0x2bd9 */ { false, 0x2bd9, 0x2bd9 }, +/* 0x2bda */ { false, 0x2bda, 0x2bda }, +/* 0x2bdb */ { false, 0x2bdb, 0x2bdb }, +/* 0x2bdc */ { false, 0x2bdc, 0x2bdc }, +/* 0x2bdd */ { false, 0x2bdd, 0x2bdd }, +/* 0x2bde */ { false, 0x2bde, 0x2bde }, +/* 0x2bdf */ { false, 0x2bdf, 0x2bdf }, +/* 0x2be0 */ { false, 0x2be0, 0x2be0 }, +/* 0x2be1 */ { false, 0x2be1, 0x2be1 }, +/* 0x2be2 */ { false, 0x2be2, 0x2be2 }, +/* 0x2be3 */ { false, 0x2be3, 0x2be3 }, +/* 0x2be4 */ { false, 0x2be4, 0x2be4 }, +/* 0x2be5 */ { false, 0x2be5, 0x2be5 }, +/* 0x2be6 */ { false, 0x2be6, 0x2be6 }, +/* 0x2be7 */ { false, 0x2be7, 0x2be7 }, +/* 0x2be8 */ { false, 0x2be8, 0x2be8 }, +/* 0x2be9 */ { false, 0x2be9, 0x2be9 }, +/* 0x2bea */ { false, 0x2bea, 0x2bea }, +/* 0x2beb */ { false, 0x2beb, 0x2beb }, +/* 0x2bec */ { false, 0x2bec, 0x2bec }, +/* 0x2bed */ { false, 0x2bed, 0x2bed }, +/* 0x2bee */ { false, 0x2bee, 0x2bee }, +/* 0x2bef */ { false, 0x2bef, 0x2bef }, +/* 0x2bf0 */ { false, 0x2bf0, 0x2bf0 }, +/* 0x2bf1 */ { false, 0x2bf1, 0x2bf1 }, +/* 0x2bf2 */ { false, 0x2bf2, 0x2bf2 }, +/* 0x2bf3 */ { false, 0x2bf3, 0x2bf3 }, +/* 0x2bf4 */ { false, 0x2bf4, 0x2bf4 }, +/* 0x2bf5 */ { false, 0x2bf5, 0x2bf5 }, +/* 0x2bf6 */ { false, 0x2bf6, 0x2bf6 }, +/* 0x2bf7 */ { false, 0x2bf7, 0x2bf7 }, +/* 0x2bf8 */ { false, 0x2bf8, 0x2bf8 }, +/* 0x2bf9 */ { false, 0x2bf9, 0x2bf9 }, +/* 0x2bfa */ { false, 0x2bfa, 0x2bfa }, +/* 0x2bfb */ { false, 0x2bfb, 0x2bfb }, +/* 0x2bfc */ { false, 0x2bfc, 0x2bfc }, +/* 0x2bfd */ { false, 0x2bfd, 0x2bfd }, +/* 0x2bfe */ { false, 0x2bfe, 0x2bfe }, +/* 0x2bff */ { false, 0x2bff, 0x2bff }, +/* 0x2c00 */ { true, 0x2c00, 0x2c30 }, +/* 0x2c01 */ { true, 0x2c01, 0x2c31 }, +/* 0x2c02 */ { true, 0x2c02, 0x2c32 }, +/* 0x2c03 */ { true, 0x2c03, 0x2c33 }, +/* 0x2c04 */ { true, 0x2c04, 0x2c34 }, +/* 0x2c05 */ { true, 0x2c05, 0x2c35 }, +/* 0x2c06 */ { true, 0x2c06, 0x2c36 }, +/* 0x2c07 */ { true, 0x2c07, 0x2c37 }, +/* 0x2c08 */ { true, 0x2c08, 0x2c38 }, +/* 0x2c09 */ { true, 0x2c09, 0x2c39 }, +/* 0x2c0a */ { true, 0x2c0a, 0x2c3a }, +/* 0x2c0b */ { true, 0x2c0b, 0x2c3b }, +/* 0x2c0c */ { true, 0x2c0c, 0x2c3c }, +/* 0x2c0d */ { true, 0x2c0d, 0x2c3d }, +/* 0x2c0e */ { true, 0x2c0e, 0x2c3e }, +/* 0x2c0f */ { true, 0x2c0f, 0x2c3f }, +/* 0x2c10 */ { true, 0x2c10, 0x2c40 }, +/* 0x2c11 */ { true, 0x2c11, 0x2c41 }, +/* 0x2c12 */ { true, 0x2c12, 0x2c42 }, +/* 0x2c13 */ { true, 0x2c13, 0x2c43 }, +/* 0x2c14 */ { true, 0x2c14, 0x2c44 }, +/* 0x2c15 */ { true, 0x2c15, 0x2c45 }, +/* 0x2c16 */ { true, 0x2c16, 0x2c46 }, +/* 0x2c17 */ { true, 0x2c17, 0x2c47 }, +/* 0x2c18 */ { true, 0x2c18, 0x2c48 }, +/* 0x2c19 */ { true, 0x2c19, 0x2c49 }, +/* 0x2c1a */ { true, 0x2c1a, 0x2c4a }, +/* 0x2c1b */ { true, 0x2c1b, 0x2c4b }, +/* 0x2c1c */ { true, 0x2c1c, 0x2c4c }, +/* 0x2c1d */ { true, 0x2c1d, 0x2c4d }, +/* 0x2c1e */ { true, 0x2c1e, 0x2c4e }, +/* 0x2c1f */ { true, 0x2c1f, 0x2c4f }, +/* 0x2c20 */ { true, 0x2c20, 0x2c50 }, +/* 0x2c21 */ { true, 0x2c21, 0x2c51 }, +/* 0x2c22 */ { true, 0x2c22, 0x2c52 }, +/* 0x2c23 */ { true, 0x2c23, 0x2c53 }, +/* 0x2c24 */ { true, 0x2c24, 0x2c54 }, +/* 0x2c25 */ { true, 0x2c25, 0x2c55 }, +/* 0x2c26 */ { true, 0x2c26, 0x2c56 }, +/* 0x2c27 */ { true, 0x2c27, 0x2c57 }, +/* 0x2c28 */ { true, 0x2c28, 0x2c58 }, +/* 0x2c29 */ { true, 0x2c29, 0x2c59 }, +/* 0x2c2a */ { true, 0x2c2a, 0x2c5a }, +/* 0x2c2b */ { true, 0x2c2b, 0x2c5b }, +/* 0x2c2c */ { true, 0x2c2c, 0x2c5c }, +/* 0x2c2d */ { true, 0x2c2d, 0x2c5d }, +/* 0x2c2e */ { true, 0x2c2e, 0x2c5e }, +/* 0x2c2f */ { false, 0x2c2f, 0x2c2f }, +/* 0x2c30 */ { true, 0x2c00, 0x2c30 }, +/* 0x2c31 */ { true, 0x2c01, 0x2c31 }, +/* 0x2c32 */ { true, 0x2c02, 0x2c32 }, +/* 0x2c33 */ { true, 0x2c03, 0x2c33 }, +/* 0x2c34 */ { true, 0x2c04, 0x2c34 }, +/* 0x2c35 */ { true, 0x2c05, 0x2c35 }, +/* 0x2c36 */ { true, 0x2c06, 0x2c36 }, +/* 0x2c37 */ { true, 0x2c07, 0x2c37 }, +/* 0x2c38 */ { true, 0x2c08, 0x2c38 }, +/* 0x2c39 */ { true, 0x2c09, 0x2c39 }, +/* 0x2c3a */ { true, 0x2c0a, 0x2c3a }, +/* 0x2c3b */ { true, 0x2c0b, 0x2c3b }, +/* 0x2c3c */ { true, 0x2c0c, 0x2c3c }, +/* 0x2c3d */ { true, 0x2c0d, 0x2c3d }, +/* 0x2c3e */ { true, 0x2c0e, 0x2c3e }, +/* 0x2c3f */ { true, 0x2c0f, 0x2c3f }, +/* 0x2c40 */ { true, 0x2c10, 0x2c40 }, +/* 0x2c41 */ { true, 0x2c11, 0x2c41 }, +/* 0x2c42 */ { true, 0x2c12, 0x2c42 }, +/* 0x2c43 */ { true, 0x2c13, 0x2c43 }, +/* 0x2c44 */ { true, 0x2c14, 0x2c44 }, +/* 0x2c45 */ { true, 0x2c15, 0x2c45 }, +/* 0x2c46 */ { true, 0x2c16, 0x2c46 }, +/* 0x2c47 */ { true, 0x2c17, 0x2c47 }, +/* 0x2c48 */ { true, 0x2c18, 0x2c48 }, +/* 0x2c49 */ { true, 0x2c19, 0x2c49 }, +/* 0x2c4a */ { true, 0x2c1a, 0x2c4a }, +/* 0x2c4b */ { true, 0x2c1b, 0x2c4b }, +/* 0x2c4c */ { true, 0x2c1c, 0x2c4c }, +/* 0x2c4d */ { true, 0x2c1d, 0x2c4d }, +/* 0x2c4e */ { true, 0x2c1e, 0x2c4e }, +/* 0x2c4f */ { true, 0x2c1f, 0x2c4f }, +/* 0x2c50 */ { true, 0x2c20, 0x2c50 }, +/* 0x2c51 */ { true, 0x2c21, 0x2c51 }, +/* 0x2c52 */ { true, 0x2c22, 0x2c52 }, +/* 0x2c53 */ { true, 0x2c23, 0x2c53 }, +/* 0x2c54 */ { true, 0x2c24, 0x2c54 }, +/* 0x2c55 */ { true, 0x2c25, 0x2c55 }, +/* 0x2c56 */ { true, 0x2c26, 0x2c56 }, +/* 0x2c57 */ { true, 0x2c27, 0x2c57 }, +/* 0x2c58 */ { true, 0x2c28, 0x2c58 }, +/* 0x2c59 */ { true, 0x2c29, 0x2c59 }, +/* 0x2c5a */ { true, 0x2c2a, 0x2c5a }, +/* 0x2c5b */ { true, 0x2c2b, 0x2c5b }, +/* 0x2c5c */ { true, 0x2c2c, 0x2c5c }, +/* 0x2c5d */ { true, 0x2c2d, 0x2c5d }, +/* 0x2c5e */ { true, 0x2c2e, 0x2c5e }, +/* 0x2c5f */ { false, 0x2c5f, 0x2c5f }, +/* 0x2c60 */ { false, 0x2c60, 0x2c60 }, +/* 0x2c61 */ { false, 0x2c61, 0x2c61 }, +/* 0x2c62 */ { false, 0x2c62, 0x2c62 }, +/* 0x2c63 */ { false, 0x2c63, 0x2c63 }, +/* 0x2c64 */ { false, 0x2c64, 0x2c64 }, +/* 0x2c65 */ { false, 0x2c65, 0x2c65 }, +/* 0x2c66 */ { false, 0x2c66, 0x2c66 }, +/* 0x2c67 */ { false, 0x2c67, 0x2c67 }, +/* 0x2c68 */ { false, 0x2c68, 0x2c68 }, +/* 0x2c69 */ { false, 0x2c69, 0x2c69 }, +/* 0x2c6a */ { false, 0x2c6a, 0x2c6a }, +/* 0x2c6b */ { false, 0x2c6b, 0x2c6b }, +/* 0x2c6c */ { false, 0x2c6c, 0x2c6c }, +/* 0x2c6d */ { false, 0x2c6d, 0x2c6d }, +/* 0x2c6e */ { false, 0x2c6e, 0x2c6e }, +/* 0x2c6f */ { false, 0x2c6f, 0x2c6f }, +/* 0x2c70 */ { false, 0x2c70, 0x2c70 }, +/* 0x2c71 */ { false, 0x2c71, 0x2c71 }, +/* 0x2c72 */ { false, 0x2c72, 0x2c72 }, +/* 0x2c73 */ { false, 0x2c73, 0x2c73 }, +/* 0x2c74 */ { false, 0x2c74, 0x2c74 }, +/* 0x2c75 */ { false, 0x2c75, 0x2c75 }, +/* 0x2c76 */ { false, 0x2c76, 0x2c76 }, +/* 0x2c77 */ { false, 0x2c77, 0x2c77 }, +/* 0x2c78 */ { false, 0x2c78, 0x2c78 }, +/* 0x2c79 */ { false, 0x2c79, 0x2c79 }, +/* 0x2c7a */ { false, 0x2c7a, 0x2c7a }, +/* 0x2c7b */ { false, 0x2c7b, 0x2c7b }, +/* 0x2c7c */ { false, 0x2c7c, 0x2c7c }, +/* 0x2c7d */ { false, 0x2c7d, 0x2c7d }, +/* 0x2c7e */ { false, 0x2c7e, 0x2c7e }, +/* 0x2c7f */ { false, 0x2c7f, 0x2c7f }, +/* 0x2c80 */ { true, 0x2c80, 0x2c81 }, +/* 0x2c81 */ { true, 0x2c80, 0x2c81 }, +/* 0x2c82 */ { true, 0x2c82, 0x2c83 }, +/* 0x2c83 */ { true, 0x2c82, 0x2c83 }, +/* 0x2c84 */ { true, 0x2c84, 0x2c85 }, +/* 0x2c85 */ { true, 0x2c84, 0x2c85 }, +/* 0x2c86 */ { true, 0x2c86, 0x2c87 }, +/* 0x2c87 */ { true, 0x2c86, 0x2c87 }, +/* 0x2c88 */ { true, 0x2c88, 0x2c89 }, +/* 0x2c89 */ { true, 0x2c88, 0x2c89 }, +/* 0x2c8a */ { true, 0x2c8a, 0x2c8b }, +/* 0x2c8b */ { true, 0x2c8a, 0x2c8b }, +/* 0x2c8c */ { true, 0x2c8c, 0x2c8d }, +/* 0x2c8d */ { true, 0x2c8c, 0x2c8d }, +/* 0x2c8e */ { true, 0x2c8e, 0x2c8f }, +/* 0x2c8f */ { true, 0x2c8e, 0x2c8f }, +/* 0x2c90 */ { true, 0x2c90, 0x2c91 }, +/* 0x2c91 */ { true, 0x2c90, 0x2c91 }, +/* 0x2c92 */ { true, 0x2c92, 0x2c93 }, +/* 0x2c93 */ { true, 0x2c92, 0x2c93 }, +/* 0x2c94 */ { true, 0x2c94, 0x2c95 }, +/* 0x2c95 */ { true, 0x2c94, 0x2c95 }, +/* 0x2c96 */ { true, 0x2c96, 0x2c97 }, +/* 0x2c97 */ { true, 0x2c96, 0x2c97 }, +/* 0x2c98 */ { true, 0x2c98, 0x2c99 }, +/* 0x2c99 */ { true, 0x2c98, 0x2c99 }, +/* 0x2c9a */ { true, 0x2c9a, 0x2c9b }, +/* 0x2c9b */ { true, 0x2c9a, 0x2c9b }, +/* 0x2c9c */ { true, 0x2c9c, 0x2c9d }, +/* 0x2c9d */ { true, 0x2c9c, 0x2c9d }, +/* 0x2c9e */ { true, 0x2c9e, 0x2c9f }, +/* 0x2c9f */ { true, 0x2c9e, 0x2c9f }, +/* 0x2ca0 */ { true, 0x2ca0, 0x2ca1 }, +/* 0x2ca1 */ { true, 0x2ca0, 0x2ca1 }, +/* 0x2ca2 */ { true, 0x2ca2, 0x2ca3 }, +/* 0x2ca3 */ { true, 0x2ca2, 0x2ca3 }, +/* 0x2ca4 */ { true, 0x2ca4, 0x2ca5 }, +/* 0x2ca5 */ { true, 0x2ca4, 0x2ca5 }, +/* 0x2ca6 */ { true, 0x2ca6, 0x2ca7 }, +/* 0x2ca7 */ { true, 0x2ca6, 0x2ca7 }, +/* 0x2ca8 */ { true, 0x2ca8, 0x2ca9 }, +/* 0x2ca9 */ { true, 0x2ca8, 0x2ca9 }, +/* 0x2caa */ { true, 0x2caa, 0x2cab }, +/* 0x2cab */ { true, 0x2caa, 0x2cab }, +/* 0x2cac */ { true, 0x2cac, 0x2cad }, +/* 0x2cad */ { true, 0x2cac, 0x2cad }, +/* 0x2cae */ { true, 0x2cae, 0x2caf }, +/* 0x2caf */ { true, 0x2cae, 0x2caf }, +/* 0x2cb0 */ { true, 0x2cb0, 0x2cb1 }, +/* 0x2cb1 */ { true, 0x2cb0, 0x2cb1 }, +/* 0x2cb2 */ { true, 0x2cb2, 0x2cb3 }, +/* 0x2cb3 */ { true, 0x2cb2, 0x2cb3 }, +/* 0x2cb4 */ { true, 0x2cb4, 0x2cb5 }, +/* 0x2cb5 */ { true, 0x2cb4, 0x2cb5 }, +/* 0x2cb6 */ { true, 0x2cb6, 0x2cb7 }, +/* 0x2cb7 */ { true, 0x2cb6, 0x2cb7 }, +/* 0x2cb8 */ { true, 0x2cb8, 0x2cb9 }, +/* 0x2cb9 */ { true, 0x2cb8, 0x2cb9 }, +/* 0x2cba */ { true, 0x2cba, 0x2cbb }, +/* 0x2cbb */ { true, 0x2cba, 0x2cbb }, +/* 0x2cbc */ { true, 0x2cbc, 0x2cbd }, +/* 0x2cbd */ { true, 0x2cbc, 0x2cbd }, +/* 0x2cbe */ { true, 0x2cbe, 0x2cbf }, +/* 0x2cbf */ { true, 0x2cbe, 0x2cbf }, +/* 0x2cc0 */ { true, 0x2cc0, 0x2cc1 }, +/* 0x2cc1 */ { true, 0x2cc0, 0x2cc1 }, +/* 0x2cc2 */ { true, 0x2cc2, 0x2cc3 }, +/* 0x2cc3 */ { true, 0x2cc2, 0x2cc3 }, +/* 0x2cc4 */ { true, 0x2cc4, 0x2cc5 }, +/* 0x2cc5 */ { true, 0x2cc4, 0x2cc5 }, +/* 0x2cc6 */ { true, 0x2cc6, 0x2cc7 }, +/* 0x2cc7 */ { true, 0x2cc6, 0x2cc7 }, +/* 0x2cc8 */ { true, 0x2cc8, 0x2cc9 }, +/* 0x2cc9 */ { true, 0x2cc8, 0x2cc9 }, +/* 0x2cca */ { true, 0x2cca, 0x2ccb }, +/* 0x2ccb */ { true, 0x2cca, 0x2ccb }, +/* 0x2ccc */ { true, 0x2ccc, 0x2ccd }, +/* 0x2ccd */ { true, 0x2ccc, 0x2ccd }, +/* 0x2cce */ { true, 0x2cce, 0x2ccf }, +/* 0x2ccf */ { true, 0x2cce, 0x2ccf }, +/* 0x2cd0 */ { true, 0x2cd0, 0x2cd1 }, +/* 0x2cd1 */ { true, 0x2cd0, 0x2cd1 }, +/* 0x2cd2 */ { true, 0x2cd2, 0x2cd3 }, +/* 0x2cd3 */ { true, 0x2cd2, 0x2cd3 }, +/* 0x2cd4 */ { true, 0x2cd4, 0x2cd5 }, +/* 0x2cd5 */ { true, 0x2cd4, 0x2cd5 }, +/* 0x2cd6 */ { true, 0x2cd6, 0x2cd7 }, +/* 0x2cd7 */ { true, 0x2cd6, 0x2cd7 }, +/* 0x2cd8 */ { true, 0x2cd8, 0x2cd9 }, +/* 0x2cd9 */ { true, 0x2cd8, 0x2cd9 }, +/* 0x2cda */ { true, 0x2cda, 0x2cdb }, +/* 0x2cdb */ { true, 0x2cda, 0x2cdb }, +/* 0x2cdc */ { true, 0x2cdc, 0x2cdd }, +/* 0x2cdd */ { true, 0x2cdc, 0x2cdd }, +/* 0x2cde */ { true, 0x2cde, 0x2cdf }, +/* 0x2cdf */ { true, 0x2cde, 0x2cdf }, +/* 0x2ce0 */ { true, 0x2ce0, 0x2ce1 }, +/* 0x2ce1 */ { true, 0x2ce0, 0x2ce1 }, +/* 0x2ce2 */ { true, 0x2ce2, 0x2ce3 }, +/* 0x2ce3 */ { true, 0x2ce2, 0x2ce3 }, +/* 0x2ce4 */ { true, 0x2ce4, 0x2ce4 }, +/* 0x2ce5 */ { false, 0x2ce5, 0x2ce5 }, +/* 0x2ce6 */ { false, 0x2ce6, 0x2ce6 }, +/* 0x2ce7 */ { false, 0x2ce7, 0x2ce7 }, +/* 0x2ce8 */ { false, 0x2ce8, 0x2ce8 }, +/* 0x2ce9 */ { false, 0x2ce9, 0x2ce9 }, +/* 0x2cea */ { false, 0x2cea, 0x2cea }, +/* 0x2ceb */ { false, 0x2ceb, 0x2ceb }, +/* 0x2cec */ { false, 0x2cec, 0x2cec }, +/* 0x2ced */ { false, 0x2ced, 0x2ced }, +/* 0x2cee */ { false, 0x2cee, 0x2cee }, +/* 0x2cef */ { false, 0x2cef, 0x2cef }, +/* 0x2cf0 */ { false, 0x2cf0, 0x2cf0 }, +/* 0x2cf1 */ { false, 0x2cf1, 0x2cf1 }, +/* 0x2cf2 */ { false, 0x2cf2, 0x2cf2 }, +/* 0x2cf3 */ { false, 0x2cf3, 0x2cf3 }, +/* 0x2cf4 */ { false, 0x2cf4, 0x2cf4 }, +/* 0x2cf5 */ { false, 0x2cf5, 0x2cf5 }, +/* 0x2cf6 */ { false, 0x2cf6, 0x2cf6 }, +/* 0x2cf7 */ { false, 0x2cf7, 0x2cf7 }, +/* 0x2cf8 */ { false, 0x2cf8, 0x2cf8 }, +/* 0x2cf9 */ { false, 0x2cf9, 0x2cf9 }, +/* 0x2cfa */ { false, 0x2cfa, 0x2cfa }, +/* 0x2cfb */ { false, 0x2cfb, 0x2cfb }, +/* 0x2cfc */ { false, 0x2cfc, 0x2cfc }, +/* 0x2cfd */ { false, 0x2cfd, 0x2cfd }, +/* 0x2cfe */ { false, 0x2cfe, 0x2cfe }, +/* 0x2cff */ { false, 0x2cff, 0x2cff }, +/* 0x2d00 */ { true, 0x10a0, 0x2d00 }, +/* 0x2d01 */ { true, 0x10a1, 0x2d01 }, +/* 0x2d02 */ { true, 0x10a2, 0x2d02 }, +/* 0x2d03 */ { true, 0x10a3, 0x2d03 }, +/* 0x2d04 */ { true, 0x10a4, 0x2d04 }, +/* 0x2d05 */ { true, 0x10a5, 0x2d05 }, +/* 0x2d06 */ { true, 0x10a6, 0x2d06 }, +/* 0x2d07 */ { true, 0x10a7, 0x2d07 }, +/* 0x2d08 */ { true, 0x10a8, 0x2d08 }, +/* 0x2d09 */ { true, 0x10a9, 0x2d09 }, +/* 0x2d0a */ { true, 0x10aa, 0x2d0a }, +/* 0x2d0b */ { true, 0x10ab, 0x2d0b }, +/* 0x2d0c */ { true, 0x10ac, 0x2d0c }, +/* 0x2d0d */ { true, 0x10ad, 0x2d0d }, +/* 0x2d0e */ { true, 0x10ae, 0x2d0e }, +/* 0x2d0f */ { true, 0x10af, 0x2d0f }, +/* 0x2d10 */ { true, 0x10b0, 0x2d10 }, +/* 0x2d11 */ { true, 0x10b1, 0x2d11 }, +/* 0x2d12 */ { true, 0x10b2, 0x2d12 }, +/* 0x2d13 */ { true, 0x10b3, 0x2d13 }, +/* 0x2d14 */ { true, 0x10b4, 0x2d14 }, +/* 0x2d15 */ { true, 0x10b5, 0x2d15 }, +/* 0x2d16 */ { true, 0x10b6, 0x2d16 }, +/* 0x2d17 */ { true, 0x10b7, 0x2d17 }, +/* 0x2d18 */ { true, 0x10b8, 0x2d18 }, +/* 0x2d19 */ { true, 0x10b9, 0x2d19 }, +/* 0x2d1a */ { true, 0x10ba, 0x2d1a }, +/* 0x2d1b */ { true, 0x10bb, 0x2d1b }, +/* 0x2d1c */ { true, 0x10bc, 0x2d1c }, +/* 0x2d1d */ { true, 0x10bd, 0x2d1d }, +/* 0x2d1e */ { true, 0x10be, 0x2d1e }, +/* 0x2d1f */ { true, 0x10bf, 0x2d1f }, +/* 0x2d20 */ { true, 0x10c0, 0x2d20 }, +/* 0x2d21 */ { true, 0x10c1, 0x2d21 }, +/* 0x2d22 */ { true, 0x10c2, 0x2d22 }, +/* 0x2d23 */ { true, 0x10c3, 0x2d23 }, +/* 0x2d24 */ { true, 0x10c4, 0x2d24 }, +/* 0x2d25 */ { true, 0x10c5, 0x2d25 }, +/* 0x2d26 */ { false, 0x2d26, 0x2d26 }, +/* 0x2d27 */ { false, 0x2d27, 0x2d27 }, +/* 0x2d28 */ { false, 0x2d28, 0x2d28 }, +/* 0x2d29 */ { false, 0x2d29, 0x2d29 }, +/* 0x2d2a */ { false, 0x2d2a, 0x2d2a }, +/* 0x2d2b */ { false, 0x2d2b, 0x2d2b }, +/* 0x2d2c */ { false, 0x2d2c, 0x2d2c }, +/* 0x2d2d */ { false, 0x2d2d, 0x2d2d }, +/* 0x2d2e */ { false, 0x2d2e, 0x2d2e }, +/* 0x2d2f */ { false, 0x2d2f, 0x2d2f }, +/* 0x2d30 */ { true, 0x2d30, 0x2d30 }, +/* 0x2d31 */ { true, 0x2d31, 0x2d31 }, +/* 0x2d32 */ { true, 0x2d32, 0x2d32 }, +/* 0x2d33 */ { true, 0x2d33, 0x2d33 }, +/* 0x2d34 */ { true, 0x2d34, 0x2d34 }, +/* 0x2d35 */ { true, 0x2d35, 0x2d35 }, +/* 0x2d36 */ { true, 0x2d36, 0x2d36 }, +/* 0x2d37 */ { true, 0x2d37, 0x2d37 }, +/* 0x2d38 */ { true, 0x2d38, 0x2d38 }, +/* 0x2d39 */ { true, 0x2d39, 0x2d39 }, +/* 0x2d3a */ { true, 0x2d3a, 0x2d3a }, +/* 0x2d3b */ { true, 0x2d3b, 0x2d3b }, +/* 0x2d3c */ { true, 0x2d3c, 0x2d3c }, +/* 0x2d3d */ { true, 0x2d3d, 0x2d3d }, +/* 0x2d3e */ { true, 0x2d3e, 0x2d3e }, +/* 0x2d3f */ { true, 0x2d3f, 0x2d3f }, +/* 0x2d40 */ { true, 0x2d40, 0x2d40 }, +/* 0x2d41 */ { true, 0x2d41, 0x2d41 }, +/* 0x2d42 */ { true, 0x2d42, 0x2d42 }, +/* 0x2d43 */ { true, 0x2d43, 0x2d43 }, +/* 0x2d44 */ { true, 0x2d44, 0x2d44 }, +/* 0x2d45 */ { true, 0x2d45, 0x2d45 }, +/* 0x2d46 */ { true, 0x2d46, 0x2d46 }, +/* 0x2d47 */ { true, 0x2d47, 0x2d47 }, +/* 0x2d48 */ { true, 0x2d48, 0x2d48 }, +/* 0x2d49 */ { true, 0x2d49, 0x2d49 }, +/* 0x2d4a */ { true, 0x2d4a, 0x2d4a }, +/* 0x2d4b */ { true, 0x2d4b, 0x2d4b }, +/* 0x2d4c */ { true, 0x2d4c, 0x2d4c }, +/* 0x2d4d */ { true, 0x2d4d, 0x2d4d }, +/* 0x2d4e */ { true, 0x2d4e, 0x2d4e }, +/* 0x2d4f */ { true, 0x2d4f, 0x2d4f }, +/* 0x2d50 */ { true, 0x2d50, 0x2d50 }, +/* 0x2d51 */ { true, 0x2d51, 0x2d51 }, +/* 0x2d52 */ { true, 0x2d52, 0x2d52 }, +/* 0x2d53 */ { true, 0x2d53, 0x2d53 }, +/* 0x2d54 */ { true, 0x2d54, 0x2d54 }, +/* 0x2d55 */ { true, 0x2d55, 0x2d55 }, +/* 0x2d56 */ { true, 0x2d56, 0x2d56 }, +/* 0x2d57 */ { true, 0x2d57, 0x2d57 }, +/* 0x2d58 */ { true, 0x2d58, 0x2d58 }, +/* 0x2d59 */ { true, 0x2d59, 0x2d59 }, +/* 0x2d5a */ { true, 0x2d5a, 0x2d5a }, +/* 0x2d5b */ { true, 0x2d5b, 0x2d5b }, +/* 0x2d5c */ { true, 0x2d5c, 0x2d5c }, +/* 0x2d5d */ { true, 0x2d5d, 0x2d5d }, +/* 0x2d5e */ { true, 0x2d5e, 0x2d5e }, +/* 0x2d5f */ { true, 0x2d5f, 0x2d5f }, +/* 0x2d60 */ { true, 0x2d60, 0x2d60 }, +/* 0x2d61 */ { true, 0x2d61, 0x2d61 }, +/* 0x2d62 */ { true, 0x2d62, 0x2d62 }, +/* 0x2d63 */ { true, 0x2d63, 0x2d63 }, +/* 0x2d64 */ { true, 0x2d64, 0x2d64 }, +/* 0x2d65 */ { true, 0x2d65, 0x2d65 }, +/* 0x2d66 */ { false, 0x2d66, 0x2d66 }, +/* 0x2d67 */ { false, 0x2d67, 0x2d67 }, +/* 0x2d68 */ { false, 0x2d68, 0x2d68 }, +/* 0x2d69 */ { false, 0x2d69, 0x2d69 }, +/* 0x2d6a */ { false, 0x2d6a, 0x2d6a }, +/* 0x2d6b */ { false, 0x2d6b, 0x2d6b }, +/* 0x2d6c */ { false, 0x2d6c, 0x2d6c }, +/* 0x2d6d */ { false, 0x2d6d, 0x2d6d }, +/* 0x2d6e */ { false, 0x2d6e, 0x2d6e }, +/* 0x2d6f */ { true, 0x2d6f, 0x2d6f }, +/* 0x2d70 */ { false, 0x2d70, 0x2d70 }, +/* 0x2d71 */ { false, 0x2d71, 0x2d71 }, +/* 0x2d72 */ { false, 0x2d72, 0x2d72 }, +/* 0x2d73 */ { false, 0x2d73, 0x2d73 }, +/* 0x2d74 */ { false, 0x2d74, 0x2d74 }, +/* 0x2d75 */ { false, 0x2d75, 0x2d75 }, +/* 0x2d76 */ { false, 0x2d76, 0x2d76 }, +/* 0x2d77 */ { false, 0x2d77, 0x2d77 }, +/* 0x2d78 */ { false, 0x2d78, 0x2d78 }, +/* 0x2d79 */ { false, 0x2d79, 0x2d79 }, +/* 0x2d7a */ { false, 0x2d7a, 0x2d7a }, +/* 0x2d7b */ { false, 0x2d7b, 0x2d7b }, +/* 0x2d7c */ { false, 0x2d7c, 0x2d7c }, +/* 0x2d7d */ { false, 0x2d7d, 0x2d7d }, +/* 0x2d7e */ { false, 0x2d7e, 0x2d7e }, +/* 0x2d7f */ { false, 0x2d7f, 0x2d7f }, +/* 0x2d80 */ { true, 0x2d80, 0x2d80 }, +/* 0x2d81 */ { true, 0x2d81, 0x2d81 }, +/* 0x2d82 */ { true, 0x2d82, 0x2d82 }, +/* 0x2d83 */ { true, 0x2d83, 0x2d83 }, +/* 0x2d84 */ { true, 0x2d84, 0x2d84 }, +/* 0x2d85 */ { true, 0x2d85, 0x2d85 }, +/* 0x2d86 */ { true, 0x2d86, 0x2d86 }, +/* 0x2d87 */ { true, 0x2d87, 0x2d87 }, +/* 0x2d88 */ { true, 0x2d88, 0x2d88 }, +/* 0x2d89 */ { true, 0x2d89, 0x2d89 }, +/* 0x2d8a */ { true, 0x2d8a, 0x2d8a }, +/* 0x2d8b */ { true, 0x2d8b, 0x2d8b }, +/* 0x2d8c */ { true, 0x2d8c, 0x2d8c }, +/* 0x2d8d */ { true, 0x2d8d, 0x2d8d }, +/* 0x2d8e */ { true, 0x2d8e, 0x2d8e }, +/* 0x2d8f */ { true, 0x2d8f, 0x2d8f }, +/* 0x2d90 */ { true, 0x2d90, 0x2d90 }, +/* 0x2d91 */ { true, 0x2d91, 0x2d91 }, +/* 0x2d92 */ { true, 0x2d92, 0x2d92 }, +/* 0x2d93 */ { true, 0x2d93, 0x2d93 }, +/* 0x2d94 */ { true, 0x2d94, 0x2d94 }, +/* 0x2d95 */ { true, 0x2d95, 0x2d95 }, +/* 0x2d96 */ { true, 0x2d96, 0x2d96 }, +/* 0x2d97 */ { false, 0x2d97, 0x2d97 }, +/* 0x2d98 */ { false, 0x2d98, 0x2d98 }, +/* 0x2d99 */ { false, 0x2d99, 0x2d99 }, +/* 0x2d9a */ { false, 0x2d9a, 0x2d9a }, +/* 0x2d9b */ { false, 0x2d9b, 0x2d9b }, +/* 0x2d9c */ { false, 0x2d9c, 0x2d9c }, +/* 0x2d9d */ { false, 0x2d9d, 0x2d9d }, +/* 0x2d9e */ { false, 0x2d9e, 0x2d9e }, +/* 0x2d9f */ { false, 0x2d9f, 0x2d9f }, +/* 0x2da0 */ { true, 0x2da0, 0x2da0 }, +/* 0x2da1 */ { true, 0x2da1, 0x2da1 }, +/* 0x2da2 */ { true, 0x2da2, 0x2da2 }, +/* 0x2da3 */ { true, 0x2da3, 0x2da3 }, +/* 0x2da4 */ { true, 0x2da4, 0x2da4 }, +/* 0x2da5 */ { true, 0x2da5, 0x2da5 }, +/* 0x2da6 */ { true, 0x2da6, 0x2da6 }, +/* 0x2da7 */ { false, 0x2da7, 0x2da7 }, +/* 0x2da8 */ { true, 0x2da8, 0x2da8 }, +/* 0x2da9 */ { true, 0x2da9, 0x2da9 }, +/* 0x2daa */ { true, 0x2daa, 0x2daa }, +/* 0x2dab */ { true, 0x2dab, 0x2dab }, +/* 0x2dac */ { true, 0x2dac, 0x2dac }, +/* 0x2dad */ { true, 0x2dad, 0x2dad }, +/* 0x2dae */ { true, 0x2dae, 0x2dae }, +/* 0x2daf */ { false, 0x2daf, 0x2daf }, +/* 0x2db0 */ { true, 0x2db0, 0x2db0 }, +/* 0x2db1 */ { true, 0x2db1, 0x2db1 }, +/* 0x2db2 */ { true, 0x2db2, 0x2db2 }, +/* 0x2db3 */ { true, 0x2db3, 0x2db3 }, +/* 0x2db4 */ { true, 0x2db4, 0x2db4 }, +/* 0x2db5 */ { true, 0x2db5, 0x2db5 }, +/* 0x2db6 */ { true, 0x2db6, 0x2db6 }, +/* 0x2db7 */ { false, 0x2db7, 0x2db7 }, +/* 0x2db8 */ { true, 0x2db8, 0x2db8 }, +/* 0x2db9 */ { true, 0x2db9, 0x2db9 }, +/* 0x2dba */ { true, 0x2dba, 0x2dba }, +/* 0x2dbb */ { true, 0x2dbb, 0x2dbb }, +/* 0x2dbc */ { true, 0x2dbc, 0x2dbc }, +/* 0x2dbd */ { true, 0x2dbd, 0x2dbd }, +/* 0x2dbe */ { true, 0x2dbe, 0x2dbe }, +/* 0x2dbf */ { false, 0x2dbf, 0x2dbf }, +/* 0x2dc0 */ { true, 0x2dc0, 0x2dc0 }, +/* 0x2dc1 */ { true, 0x2dc1, 0x2dc1 }, +/* 0x2dc2 */ { true, 0x2dc2, 0x2dc2 }, +/* 0x2dc3 */ { true, 0x2dc3, 0x2dc3 }, +/* 0x2dc4 */ { true, 0x2dc4, 0x2dc4 }, +/* 0x2dc5 */ { true, 0x2dc5, 0x2dc5 }, +/* 0x2dc6 */ { true, 0x2dc6, 0x2dc6 }, +/* 0x2dc7 */ { false, 0x2dc7, 0x2dc7 }, +/* 0x2dc8 */ { true, 0x2dc8, 0x2dc8 }, +/* 0x2dc9 */ { true, 0x2dc9, 0x2dc9 }, +/* 0x2dca */ { true, 0x2dca, 0x2dca }, +/* 0x2dcb */ { true, 0x2dcb, 0x2dcb }, +/* 0x2dcc */ { true, 0x2dcc, 0x2dcc }, +/* 0x2dcd */ { true, 0x2dcd, 0x2dcd }, +/* 0x2dce */ { true, 0x2dce, 0x2dce }, +/* 0x2dcf */ { false, 0x2dcf, 0x2dcf }, +/* 0x2dd0 */ { true, 0x2dd0, 0x2dd0 }, +/* 0x2dd1 */ { true, 0x2dd1, 0x2dd1 }, +/* 0x2dd2 */ { true, 0x2dd2, 0x2dd2 }, +/* 0x2dd3 */ { true, 0x2dd3, 0x2dd3 }, +/* 0x2dd4 */ { true, 0x2dd4, 0x2dd4 }, +/* 0x2dd5 */ { true, 0x2dd5, 0x2dd5 }, +/* 0x2dd6 */ { true, 0x2dd6, 0x2dd6 }, +/* 0x2dd7 */ { false, 0x2dd7, 0x2dd7 }, +/* 0x2dd8 */ { true, 0x2dd8, 0x2dd8 }, +/* 0x2dd9 */ { true, 0x2dd9, 0x2dd9 }, +/* 0x2dda */ { true, 0x2dda, 0x2dda }, +/* 0x2ddb */ { true, 0x2ddb, 0x2ddb }, +/* 0x2ddc */ { true, 0x2ddc, 0x2ddc }, +/* 0x2ddd */ { true, 0x2ddd, 0x2ddd }, +/* 0x2dde */ { true, 0x2dde, 0x2dde }, +/* 0x2ddf */ { false, 0x2ddf, 0x2ddf }, +/* 0x2de0 */ { false, 0x2de0, 0x2de0 }, +/* 0x2de1 */ { false, 0x2de1, 0x2de1 }, +/* 0x2de2 */ { false, 0x2de2, 0x2de2 }, +/* 0x2de3 */ { false, 0x2de3, 0x2de3 }, +/* 0x2de4 */ { false, 0x2de4, 0x2de4 }, +/* 0x2de5 */ { false, 0x2de5, 0x2de5 }, +/* 0x2de6 */ { false, 0x2de6, 0x2de6 }, +/* 0x2de7 */ { false, 0x2de7, 0x2de7 }, +/* 0x2de8 */ { false, 0x2de8, 0x2de8 }, +/* 0x2de9 */ { false, 0x2de9, 0x2de9 }, +/* 0x2dea */ { false, 0x2dea, 0x2dea }, +/* 0x2deb */ { false, 0x2deb, 0x2deb }, +/* 0x2dec */ { false, 0x2dec, 0x2dec }, +/* 0x2ded */ { false, 0x2ded, 0x2ded }, +/* 0x2dee */ { false, 0x2dee, 0x2dee }, +/* 0x2def */ { false, 0x2def, 0x2def }, +/* 0x2df0 */ { false, 0x2df0, 0x2df0 }, +/* 0x2df1 */ { false, 0x2df1, 0x2df1 }, +/* 0x2df2 */ { false, 0x2df2, 0x2df2 }, +/* 0x2df3 */ { false, 0x2df3, 0x2df3 }, +/* 0x2df4 */ { false, 0x2df4, 0x2df4 }, +/* 0x2df5 */ { false, 0x2df5, 0x2df5 }, +/* 0x2df6 */ { false, 0x2df6, 0x2df6 }, +/* 0x2df7 */ { false, 0x2df7, 0x2df7 }, +/* 0x2df8 */ { false, 0x2df8, 0x2df8 }, +/* 0x2df9 */ { false, 0x2df9, 0x2df9 }, +/* 0x2dfa */ { false, 0x2dfa, 0x2dfa }, +/* 0x2dfb */ { false, 0x2dfb, 0x2dfb }, +/* 0x2dfc */ { false, 0x2dfc, 0x2dfc }, +/* 0x2dfd */ { false, 0x2dfd, 0x2dfd }, +/* 0x2dfe */ { false, 0x2dfe, 0x2dfe }, +/* 0x2dff */ { false, 0x2dff, 0x2dff }, +/* 0x2e00 */ { false, 0x2e00, 0x2e00 }, +/* 0x2e01 */ { false, 0x2e01, 0x2e01 }, +/* 0x2e02 */ { false, 0x2e02, 0x2e02 }, +/* 0x2e03 */ { false, 0x2e03, 0x2e03 }, +/* 0x2e04 */ { false, 0x2e04, 0x2e04 }, +/* 0x2e05 */ { false, 0x2e05, 0x2e05 }, +/* 0x2e06 */ { false, 0x2e06, 0x2e06 }, +/* 0x2e07 */ { false, 0x2e07, 0x2e07 }, +/* 0x2e08 */ { false, 0x2e08, 0x2e08 }, +/* 0x2e09 */ { false, 0x2e09, 0x2e09 }, +/* 0x2e0a */ { false, 0x2e0a, 0x2e0a }, +/* 0x2e0b */ { false, 0x2e0b, 0x2e0b }, +/* 0x2e0c */ { false, 0x2e0c, 0x2e0c }, +/* 0x2e0d */ { false, 0x2e0d, 0x2e0d }, +/* 0x2e0e */ { false, 0x2e0e, 0x2e0e }, +/* 0x2e0f */ { false, 0x2e0f, 0x2e0f }, +/* 0x2e10 */ { false, 0x2e10, 0x2e10 }, +/* 0x2e11 */ { false, 0x2e11, 0x2e11 }, +/* 0x2e12 */ { false, 0x2e12, 0x2e12 }, +/* 0x2e13 */ { false, 0x2e13, 0x2e13 }, +/* 0x2e14 */ { false, 0x2e14, 0x2e14 }, +/* 0x2e15 */ { false, 0x2e15, 0x2e15 }, +/* 0x2e16 */ { false, 0x2e16, 0x2e16 }, +/* 0x2e17 */ { false, 0x2e17, 0x2e17 }, +/* 0x2e18 */ { false, 0x2e18, 0x2e18 }, +/* 0x2e19 */ { false, 0x2e19, 0x2e19 }, +/* 0x2e1a */ { false, 0x2e1a, 0x2e1a }, +/* 0x2e1b */ { false, 0x2e1b, 0x2e1b }, +/* 0x2e1c */ { false, 0x2e1c, 0x2e1c }, +/* 0x2e1d */ { false, 0x2e1d, 0x2e1d }, +/* 0x2e1e */ { false, 0x2e1e, 0x2e1e }, +/* 0x2e1f */ { false, 0x2e1f, 0x2e1f }, +/* 0x2e20 */ { false, 0x2e20, 0x2e20 }, +/* 0x2e21 */ { false, 0x2e21, 0x2e21 }, +/* 0x2e22 */ { false, 0x2e22, 0x2e22 }, +/* 0x2e23 */ { false, 0x2e23, 0x2e23 }, +/* 0x2e24 */ { false, 0x2e24, 0x2e24 }, +/* 0x2e25 */ { false, 0x2e25, 0x2e25 }, +/* 0x2e26 */ { false, 0x2e26, 0x2e26 }, +/* 0x2e27 */ { false, 0x2e27, 0x2e27 }, +/* 0x2e28 */ { false, 0x2e28, 0x2e28 }, +/* 0x2e29 */ { false, 0x2e29, 0x2e29 }, +/* 0x2e2a */ { false, 0x2e2a, 0x2e2a }, +/* 0x2e2b */ { false, 0x2e2b, 0x2e2b }, +/* 0x2e2c */ { false, 0x2e2c, 0x2e2c }, +/* 0x2e2d */ { false, 0x2e2d, 0x2e2d }, +/* 0x2e2e */ { false, 0x2e2e, 0x2e2e }, +/* 0x2e2f */ { false, 0x2e2f, 0x2e2f }, +/* 0x2e30 */ { false, 0x2e30, 0x2e30 }, +/* 0x2e31 */ { false, 0x2e31, 0x2e31 }, +/* 0x2e32 */ { false, 0x2e32, 0x2e32 }, +/* 0x2e33 */ { false, 0x2e33, 0x2e33 }, +/* 0x2e34 */ { false, 0x2e34, 0x2e34 }, +/* 0x2e35 */ { false, 0x2e35, 0x2e35 }, +/* 0x2e36 */ { false, 0x2e36, 0x2e36 }, +/* 0x2e37 */ { false, 0x2e37, 0x2e37 }, +/* 0x2e38 */ { false, 0x2e38, 0x2e38 }, +/* 0x2e39 */ { false, 0x2e39, 0x2e39 }, +/* 0x2e3a */ { false, 0x2e3a, 0x2e3a }, +/* 0x2e3b */ { false, 0x2e3b, 0x2e3b }, +/* 0x2e3c */ { false, 0x2e3c, 0x2e3c }, +/* 0x2e3d */ { false, 0x2e3d, 0x2e3d }, +/* 0x2e3e */ { false, 0x2e3e, 0x2e3e }, +/* 0x2e3f */ { false, 0x2e3f, 0x2e3f }, +/* 0x2e40 */ { false, 0x2e40, 0x2e40 }, +/* 0x2e41 */ { false, 0x2e41, 0x2e41 }, +/* 0x2e42 */ { false, 0x2e42, 0x2e42 }, +/* 0x2e43 */ { false, 0x2e43, 0x2e43 }, +/* 0x2e44 */ { false, 0x2e44, 0x2e44 }, +/* 0x2e45 */ { false, 0x2e45, 0x2e45 }, +/* 0x2e46 */ { false, 0x2e46, 0x2e46 }, +/* 0x2e47 */ { false, 0x2e47, 0x2e47 }, +/* 0x2e48 */ { false, 0x2e48, 0x2e48 }, +/* 0x2e49 */ { false, 0x2e49, 0x2e49 }, +/* 0x2e4a */ { false, 0x2e4a, 0x2e4a }, +/* 0x2e4b */ { false, 0x2e4b, 0x2e4b }, +/* 0x2e4c */ { false, 0x2e4c, 0x2e4c }, +/* 0x2e4d */ { false, 0x2e4d, 0x2e4d }, +/* 0x2e4e */ { false, 0x2e4e, 0x2e4e }, +/* 0x2e4f */ { false, 0x2e4f, 0x2e4f }, +/* 0x2e50 */ { false, 0x2e50, 0x2e50 }, +/* 0x2e51 */ { false, 0x2e51, 0x2e51 }, +/* 0x2e52 */ { false, 0x2e52, 0x2e52 }, +/* 0x2e53 */ { false, 0x2e53, 0x2e53 }, +/* 0x2e54 */ { false, 0x2e54, 0x2e54 }, +/* 0x2e55 */ { false, 0x2e55, 0x2e55 }, +/* 0x2e56 */ { false, 0x2e56, 0x2e56 }, +/* 0x2e57 */ { false, 0x2e57, 0x2e57 }, +/* 0x2e58 */ { false, 0x2e58, 0x2e58 }, +/* 0x2e59 */ { false, 0x2e59, 0x2e59 }, +/* 0x2e5a */ { false, 0x2e5a, 0x2e5a }, +/* 0x2e5b */ { false, 0x2e5b, 0x2e5b }, +/* 0x2e5c */ { false, 0x2e5c, 0x2e5c }, +/* 0x2e5d */ { false, 0x2e5d, 0x2e5d }, +/* 0x2e5e */ { false, 0x2e5e, 0x2e5e }, +/* 0x2e5f */ { false, 0x2e5f, 0x2e5f }, +/* 0x2e60 */ { false, 0x2e60, 0x2e60 }, +/* 0x2e61 */ { false, 0x2e61, 0x2e61 }, +/* 0x2e62 */ { false, 0x2e62, 0x2e62 }, +/* 0x2e63 */ { false, 0x2e63, 0x2e63 }, +/* 0x2e64 */ { false, 0x2e64, 0x2e64 }, +/* 0x2e65 */ { false, 0x2e65, 0x2e65 }, +/* 0x2e66 */ { false, 0x2e66, 0x2e66 }, +/* 0x2e67 */ { false, 0x2e67, 0x2e67 }, +/* 0x2e68 */ { false, 0x2e68, 0x2e68 }, +/* 0x2e69 */ { false, 0x2e69, 0x2e69 }, +/* 0x2e6a */ { false, 0x2e6a, 0x2e6a }, +/* 0x2e6b */ { false, 0x2e6b, 0x2e6b }, +/* 0x2e6c */ { false, 0x2e6c, 0x2e6c }, +/* 0x2e6d */ { false, 0x2e6d, 0x2e6d }, +/* 0x2e6e */ { false, 0x2e6e, 0x2e6e }, +/* 0x2e6f */ { false, 0x2e6f, 0x2e6f }, +/* 0x2e70 */ { false, 0x2e70, 0x2e70 }, +/* 0x2e71 */ { false, 0x2e71, 0x2e71 }, +/* 0x2e72 */ { false, 0x2e72, 0x2e72 }, +/* 0x2e73 */ { false, 0x2e73, 0x2e73 }, +/* 0x2e74 */ { false, 0x2e74, 0x2e74 }, +/* 0x2e75 */ { false, 0x2e75, 0x2e75 }, +/* 0x2e76 */ { false, 0x2e76, 0x2e76 }, +/* 0x2e77 */ { false, 0x2e77, 0x2e77 }, +/* 0x2e78 */ { false, 0x2e78, 0x2e78 }, +/* 0x2e79 */ { false, 0x2e79, 0x2e79 }, +/* 0x2e7a */ { false, 0x2e7a, 0x2e7a }, +/* 0x2e7b */ { false, 0x2e7b, 0x2e7b }, +/* 0x2e7c */ { false, 0x2e7c, 0x2e7c }, +/* 0x2e7d */ { false, 0x2e7d, 0x2e7d }, +/* 0x2e7e */ { false, 0x2e7e, 0x2e7e }, +/* 0x2e7f */ { false, 0x2e7f, 0x2e7f }, +/* 0x2e80 */ { false, 0x2e80, 0x2e80 }, +/* 0x2e81 */ { false, 0x2e81, 0x2e81 }, +/* 0x2e82 */ { false, 0x2e82, 0x2e82 }, +/* 0x2e83 */ { false, 0x2e83, 0x2e83 }, +/* 0x2e84 */ { false, 0x2e84, 0x2e84 }, +/* 0x2e85 */ { false, 0x2e85, 0x2e85 }, +/* 0x2e86 */ { false, 0x2e86, 0x2e86 }, +/* 0x2e87 */ { false, 0x2e87, 0x2e87 }, +/* 0x2e88 */ { false, 0x2e88, 0x2e88 }, +/* 0x2e89 */ { false, 0x2e89, 0x2e89 }, +/* 0x2e8a */ { false, 0x2e8a, 0x2e8a }, +/* 0x2e8b */ { false, 0x2e8b, 0x2e8b }, +/* 0x2e8c */ { false, 0x2e8c, 0x2e8c }, +/* 0x2e8d */ { false, 0x2e8d, 0x2e8d }, +/* 0x2e8e */ { false, 0x2e8e, 0x2e8e }, +/* 0x2e8f */ { false, 0x2e8f, 0x2e8f }, +/* 0x2e90 */ { false, 0x2e90, 0x2e90 }, +/* 0x2e91 */ { false, 0x2e91, 0x2e91 }, +/* 0x2e92 */ { false, 0x2e92, 0x2e92 }, +/* 0x2e93 */ { false, 0x2e93, 0x2e93 }, +/* 0x2e94 */ { false, 0x2e94, 0x2e94 }, +/* 0x2e95 */ { false, 0x2e95, 0x2e95 }, +/* 0x2e96 */ { false, 0x2e96, 0x2e96 }, +/* 0x2e97 */ { false, 0x2e97, 0x2e97 }, +/* 0x2e98 */ { false, 0x2e98, 0x2e98 }, +/* 0x2e99 */ { false, 0x2e99, 0x2e99 }, +/* 0x2e9a */ { false, 0x2e9a, 0x2e9a }, +/* 0x2e9b */ { false, 0x2e9b, 0x2e9b }, +/* 0x2e9c */ { false, 0x2e9c, 0x2e9c }, +/* 0x2e9d */ { false, 0x2e9d, 0x2e9d }, +/* 0x2e9e */ { false, 0x2e9e, 0x2e9e }, +/* 0x2e9f */ { false, 0x2e9f, 0x2e9f }, +/* 0x2ea0 */ { false, 0x2ea0, 0x2ea0 }, +/* 0x2ea1 */ { false, 0x2ea1, 0x2ea1 }, +/* 0x2ea2 */ { false, 0x2ea2, 0x2ea2 }, +/* 0x2ea3 */ { false, 0x2ea3, 0x2ea3 }, +/* 0x2ea4 */ { false, 0x2ea4, 0x2ea4 }, +/* 0x2ea5 */ { false, 0x2ea5, 0x2ea5 }, +/* 0x2ea6 */ { false, 0x2ea6, 0x2ea6 }, +/* 0x2ea7 */ { false, 0x2ea7, 0x2ea7 }, +/* 0x2ea8 */ { false, 0x2ea8, 0x2ea8 }, +/* 0x2ea9 */ { false, 0x2ea9, 0x2ea9 }, +/* 0x2eaa */ { false, 0x2eaa, 0x2eaa }, +/* 0x2eab */ { false, 0x2eab, 0x2eab }, +/* 0x2eac */ { false, 0x2eac, 0x2eac }, +/* 0x2ead */ { false, 0x2ead, 0x2ead }, +/* 0x2eae */ { false, 0x2eae, 0x2eae }, +/* 0x2eaf */ { false, 0x2eaf, 0x2eaf }, +/* 0x2eb0 */ { false, 0x2eb0, 0x2eb0 }, +/* 0x2eb1 */ { false, 0x2eb1, 0x2eb1 }, +/* 0x2eb2 */ { false, 0x2eb2, 0x2eb2 }, +/* 0x2eb3 */ { false, 0x2eb3, 0x2eb3 }, +/* 0x2eb4 */ { false, 0x2eb4, 0x2eb4 }, +/* 0x2eb5 */ { false, 0x2eb5, 0x2eb5 }, +/* 0x2eb6 */ { false, 0x2eb6, 0x2eb6 }, +/* 0x2eb7 */ { false, 0x2eb7, 0x2eb7 }, +/* 0x2eb8 */ { false, 0x2eb8, 0x2eb8 }, +/* 0x2eb9 */ { false, 0x2eb9, 0x2eb9 }, +/* 0x2eba */ { false, 0x2eba, 0x2eba }, +/* 0x2ebb */ { false, 0x2ebb, 0x2ebb }, +/* 0x2ebc */ { false, 0x2ebc, 0x2ebc }, +/* 0x2ebd */ { false, 0x2ebd, 0x2ebd }, +/* 0x2ebe */ { false, 0x2ebe, 0x2ebe }, +/* 0x2ebf */ { false, 0x2ebf, 0x2ebf }, +/* 0x2ec0 */ { false, 0x2ec0, 0x2ec0 }, +/* 0x2ec1 */ { false, 0x2ec1, 0x2ec1 }, +/* 0x2ec2 */ { false, 0x2ec2, 0x2ec2 }, +/* 0x2ec3 */ { false, 0x2ec3, 0x2ec3 }, +/* 0x2ec4 */ { false, 0x2ec4, 0x2ec4 }, +/* 0x2ec5 */ { false, 0x2ec5, 0x2ec5 }, +/* 0x2ec6 */ { false, 0x2ec6, 0x2ec6 }, +/* 0x2ec7 */ { false, 0x2ec7, 0x2ec7 }, +/* 0x2ec8 */ { false, 0x2ec8, 0x2ec8 }, +/* 0x2ec9 */ { false, 0x2ec9, 0x2ec9 }, +/* 0x2eca */ { false, 0x2eca, 0x2eca }, +/* 0x2ecb */ { false, 0x2ecb, 0x2ecb }, +/* 0x2ecc */ { false, 0x2ecc, 0x2ecc }, +/* 0x2ecd */ { false, 0x2ecd, 0x2ecd }, +/* 0x2ece */ { false, 0x2ece, 0x2ece }, +/* 0x2ecf */ { false, 0x2ecf, 0x2ecf }, +/* 0x2ed0 */ { false, 0x2ed0, 0x2ed0 }, +/* 0x2ed1 */ { false, 0x2ed1, 0x2ed1 }, +/* 0x2ed2 */ { false, 0x2ed2, 0x2ed2 }, +/* 0x2ed3 */ { false, 0x2ed3, 0x2ed3 }, +/* 0x2ed4 */ { false, 0x2ed4, 0x2ed4 }, +/* 0x2ed5 */ { false, 0x2ed5, 0x2ed5 }, +/* 0x2ed6 */ { false, 0x2ed6, 0x2ed6 }, +/* 0x2ed7 */ { false, 0x2ed7, 0x2ed7 }, +/* 0x2ed8 */ { false, 0x2ed8, 0x2ed8 }, +/* 0x2ed9 */ { false, 0x2ed9, 0x2ed9 }, +/* 0x2eda */ { false, 0x2eda, 0x2eda }, +/* 0x2edb */ { false, 0x2edb, 0x2edb }, +/* 0x2edc */ { false, 0x2edc, 0x2edc }, +/* 0x2edd */ { false, 0x2edd, 0x2edd }, +/* 0x2ede */ { false, 0x2ede, 0x2ede }, +/* 0x2edf */ { false, 0x2edf, 0x2edf }, +/* 0x2ee0 */ { false, 0x2ee0, 0x2ee0 }, +/* 0x2ee1 */ { false, 0x2ee1, 0x2ee1 }, +/* 0x2ee2 */ { false, 0x2ee2, 0x2ee2 }, +/* 0x2ee3 */ { false, 0x2ee3, 0x2ee3 }, +/* 0x2ee4 */ { false, 0x2ee4, 0x2ee4 }, +/* 0x2ee5 */ { false, 0x2ee5, 0x2ee5 }, +/* 0x2ee6 */ { false, 0x2ee6, 0x2ee6 }, +/* 0x2ee7 */ { false, 0x2ee7, 0x2ee7 }, +/* 0x2ee8 */ { false, 0x2ee8, 0x2ee8 }, +/* 0x2ee9 */ { false, 0x2ee9, 0x2ee9 }, +/* 0x2eea */ { false, 0x2eea, 0x2eea }, +/* 0x2eeb */ { false, 0x2eeb, 0x2eeb }, +/* 0x2eec */ { false, 0x2eec, 0x2eec }, +/* 0x2eed */ { false, 0x2eed, 0x2eed }, +/* 0x2eee */ { false, 0x2eee, 0x2eee }, +/* 0x2eef */ { false, 0x2eef, 0x2eef }, +/* 0x2ef0 */ { false, 0x2ef0, 0x2ef0 }, +/* 0x2ef1 */ { false, 0x2ef1, 0x2ef1 }, +/* 0x2ef2 */ { false, 0x2ef2, 0x2ef2 }, +/* 0x2ef3 */ { false, 0x2ef3, 0x2ef3 }, +/* 0x2ef4 */ { false, 0x2ef4, 0x2ef4 }, +/* 0x2ef5 */ { false, 0x2ef5, 0x2ef5 }, +/* 0x2ef6 */ { false, 0x2ef6, 0x2ef6 }, +/* 0x2ef7 */ { false, 0x2ef7, 0x2ef7 }, +/* 0x2ef8 */ { false, 0x2ef8, 0x2ef8 }, +/* 0x2ef9 */ { false, 0x2ef9, 0x2ef9 }, +/* 0x2efa */ { false, 0x2efa, 0x2efa }, +/* 0x2efb */ { false, 0x2efb, 0x2efb }, +/* 0x2efc */ { false, 0x2efc, 0x2efc }, +/* 0x2efd */ { false, 0x2efd, 0x2efd }, +/* 0x2efe */ { false, 0x2efe, 0x2efe }, +/* 0x2eff */ { false, 0x2eff, 0x2eff }, +/* 0x2f00 */ { false, 0x2f00, 0x2f00 }, +/* 0x2f01 */ { false, 0x2f01, 0x2f01 }, +/* 0x2f02 */ { false, 0x2f02, 0x2f02 }, +/* 0x2f03 */ { false, 0x2f03, 0x2f03 }, +/* 0x2f04 */ { false, 0x2f04, 0x2f04 }, +/* 0x2f05 */ { false, 0x2f05, 0x2f05 }, +/* 0x2f06 */ { false, 0x2f06, 0x2f06 }, +/* 0x2f07 */ { false, 0x2f07, 0x2f07 }, +/* 0x2f08 */ { false, 0x2f08, 0x2f08 }, +/* 0x2f09 */ { false, 0x2f09, 0x2f09 }, +/* 0x2f0a */ { false, 0x2f0a, 0x2f0a }, +/* 0x2f0b */ { false, 0x2f0b, 0x2f0b }, +/* 0x2f0c */ { false, 0x2f0c, 0x2f0c }, +/* 0x2f0d */ { false, 0x2f0d, 0x2f0d }, +/* 0x2f0e */ { false, 0x2f0e, 0x2f0e }, +/* 0x2f0f */ { false, 0x2f0f, 0x2f0f }, +/* 0x2f10 */ { false, 0x2f10, 0x2f10 }, +/* 0x2f11 */ { false, 0x2f11, 0x2f11 }, +/* 0x2f12 */ { false, 0x2f12, 0x2f12 }, +/* 0x2f13 */ { false, 0x2f13, 0x2f13 }, +/* 0x2f14 */ { false, 0x2f14, 0x2f14 }, +/* 0x2f15 */ { false, 0x2f15, 0x2f15 }, +/* 0x2f16 */ { false, 0x2f16, 0x2f16 }, +/* 0x2f17 */ { false, 0x2f17, 0x2f17 }, +/* 0x2f18 */ { false, 0x2f18, 0x2f18 }, +/* 0x2f19 */ { false, 0x2f19, 0x2f19 }, +/* 0x2f1a */ { false, 0x2f1a, 0x2f1a }, +/* 0x2f1b */ { false, 0x2f1b, 0x2f1b }, +/* 0x2f1c */ { false, 0x2f1c, 0x2f1c }, +/* 0x2f1d */ { false, 0x2f1d, 0x2f1d }, +/* 0x2f1e */ { false, 0x2f1e, 0x2f1e }, +/* 0x2f1f */ { false, 0x2f1f, 0x2f1f }, +/* 0x2f20 */ { false, 0x2f20, 0x2f20 }, +/* 0x2f21 */ { false, 0x2f21, 0x2f21 }, +/* 0x2f22 */ { false, 0x2f22, 0x2f22 }, +/* 0x2f23 */ { false, 0x2f23, 0x2f23 }, +/* 0x2f24 */ { false, 0x2f24, 0x2f24 }, +/* 0x2f25 */ { false, 0x2f25, 0x2f25 }, +/* 0x2f26 */ { false, 0x2f26, 0x2f26 }, +/* 0x2f27 */ { false, 0x2f27, 0x2f27 }, +/* 0x2f28 */ { false, 0x2f28, 0x2f28 }, +/* 0x2f29 */ { false, 0x2f29, 0x2f29 }, +/* 0x2f2a */ { false, 0x2f2a, 0x2f2a }, +/* 0x2f2b */ { false, 0x2f2b, 0x2f2b }, +/* 0x2f2c */ { false, 0x2f2c, 0x2f2c }, +/* 0x2f2d */ { false, 0x2f2d, 0x2f2d }, +/* 0x2f2e */ { false, 0x2f2e, 0x2f2e }, +/* 0x2f2f */ { false, 0x2f2f, 0x2f2f }, +/* 0x2f30 */ { false, 0x2f30, 0x2f30 }, +/* 0x2f31 */ { false, 0x2f31, 0x2f31 }, +/* 0x2f32 */ { false, 0x2f32, 0x2f32 }, +/* 0x2f33 */ { false, 0x2f33, 0x2f33 }, +/* 0x2f34 */ { false, 0x2f34, 0x2f34 }, +/* 0x2f35 */ { false, 0x2f35, 0x2f35 }, +/* 0x2f36 */ { false, 0x2f36, 0x2f36 }, +/* 0x2f37 */ { false, 0x2f37, 0x2f37 }, +/* 0x2f38 */ { false, 0x2f38, 0x2f38 }, +/* 0x2f39 */ { false, 0x2f39, 0x2f39 }, +/* 0x2f3a */ { false, 0x2f3a, 0x2f3a }, +/* 0x2f3b */ { false, 0x2f3b, 0x2f3b }, +/* 0x2f3c */ { false, 0x2f3c, 0x2f3c }, +/* 0x2f3d */ { false, 0x2f3d, 0x2f3d }, +/* 0x2f3e */ { false, 0x2f3e, 0x2f3e }, +/* 0x2f3f */ { false, 0x2f3f, 0x2f3f }, +/* 0x2f40 */ { false, 0x2f40, 0x2f40 }, +/* 0x2f41 */ { false, 0x2f41, 0x2f41 }, +/* 0x2f42 */ { false, 0x2f42, 0x2f42 }, +/* 0x2f43 */ { false, 0x2f43, 0x2f43 }, +/* 0x2f44 */ { false, 0x2f44, 0x2f44 }, +/* 0x2f45 */ { false, 0x2f45, 0x2f45 }, +/* 0x2f46 */ { false, 0x2f46, 0x2f46 }, +/* 0x2f47 */ { false, 0x2f47, 0x2f47 }, +/* 0x2f48 */ { false, 0x2f48, 0x2f48 }, +/* 0x2f49 */ { false, 0x2f49, 0x2f49 }, +/* 0x2f4a */ { false, 0x2f4a, 0x2f4a }, +/* 0x2f4b */ { false, 0x2f4b, 0x2f4b }, +/* 0x2f4c */ { false, 0x2f4c, 0x2f4c }, +/* 0x2f4d */ { false, 0x2f4d, 0x2f4d }, +/* 0x2f4e */ { false, 0x2f4e, 0x2f4e }, +/* 0x2f4f */ { false, 0x2f4f, 0x2f4f }, +/* 0x2f50 */ { false, 0x2f50, 0x2f50 }, +/* 0x2f51 */ { false, 0x2f51, 0x2f51 }, +/* 0x2f52 */ { false, 0x2f52, 0x2f52 }, +/* 0x2f53 */ { false, 0x2f53, 0x2f53 }, +/* 0x2f54 */ { false, 0x2f54, 0x2f54 }, +/* 0x2f55 */ { false, 0x2f55, 0x2f55 }, +/* 0x2f56 */ { false, 0x2f56, 0x2f56 }, +/* 0x2f57 */ { false, 0x2f57, 0x2f57 }, +/* 0x2f58 */ { false, 0x2f58, 0x2f58 }, +/* 0x2f59 */ { false, 0x2f59, 0x2f59 }, +/* 0x2f5a */ { false, 0x2f5a, 0x2f5a }, +/* 0x2f5b */ { false, 0x2f5b, 0x2f5b }, +/* 0x2f5c */ { false, 0x2f5c, 0x2f5c }, +/* 0x2f5d */ { false, 0x2f5d, 0x2f5d }, +/* 0x2f5e */ { false, 0x2f5e, 0x2f5e }, +/* 0x2f5f */ { false, 0x2f5f, 0x2f5f }, +/* 0x2f60 */ { false, 0x2f60, 0x2f60 }, +/* 0x2f61 */ { false, 0x2f61, 0x2f61 }, +/* 0x2f62 */ { false, 0x2f62, 0x2f62 }, +/* 0x2f63 */ { false, 0x2f63, 0x2f63 }, +/* 0x2f64 */ { false, 0x2f64, 0x2f64 }, +/* 0x2f65 */ { false, 0x2f65, 0x2f65 }, +/* 0x2f66 */ { false, 0x2f66, 0x2f66 }, +/* 0x2f67 */ { false, 0x2f67, 0x2f67 }, +/* 0x2f68 */ { false, 0x2f68, 0x2f68 }, +/* 0x2f69 */ { false, 0x2f69, 0x2f69 }, +/* 0x2f6a */ { false, 0x2f6a, 0x2f6a }, +/* 0x2f6b */ { false, 0x2f6b, 0x2f6b }, +/* 0x2f6c */ { false, 0x2f6c, 0x2f6c }, +/* 0x2f6d */ { false, 0x2f6d, 0x2f6d }, +/* 0x2f6e */ { false, 0x2f6e, 0x2f6e }, +/* 0x2f6f */ { false, 0x2f6f, 0x2f6f }, +/* 0x2f70 */ { false, 0x2f70, 0x2f70 }, +/* 0x2f71 */ { false, 0x2f71, 0x2f71 }, +/* 0x2f72 */ { false, 0x2f72, 0x2f72 }, +/* 0x2f73 */ { false, 0x2f73, 0x2f73 }, +/* 0x2f74 */ { false, 0x2f74, 0x2f74 }, +/* 0x2f75 */ { false, 0x2f75, 0x2f75 }, +/* 0x2f76 */ { false, 0x2f76, 0x2f76 }, +/* 0x2f77 */ { false, 0x2f77, 0x2f77 }, +/* 0x2f78 */ { false, 0x2f78, 0x2f78 }, +/* 0x2f79 */ { false, 0x2f79, 0x2f79 }, +/* 0x2f7a */ { false, 0x2f7a, 0x2f7a }, +/* 0x2f7b */ { false, 0x2f7b, 0x2f7b }, +/* 0x2f7c */ { false, 0x2f7c, 0x2f7c }, +/* 0x2f7d */ { false, 0x2f7d, 0x2f7d }, +/* 0x2f7e */ { false, 0x2f7e, 0x2f7e }, +/* 0x2f7f */ { false, 0x2f7f, 0x2f7f }, +/* 0x2f80 */ { false, 0x2f80, 0x2f80 }, +/* 0x2f81 */ { false, 0x2f81, 0x2f81 }, +/* 0x2f82 */ { false, 0x2f82, 0x2f82 }, +/* 0x2f83 */ { false, 0x2f83, 0x2f83 }, +/* 0x2f84 */ { false, 0x2f84, 0x2f84 }, +/* 0x2f85 */ { false, 0x2f85, 0x2f85 }, +/* 0x2f86 */ { false, 0x2f86, 0x2f86 }, +/* 0x2f87 */ { false, 0x2f87, 0x2f87 }, +/* 0x2f88 */ { false, 0x2f88, 0x2f88 }, +/* 0x2f89 */ { false, 0x2f89, 0x2f89 }, +/* 0x2f8a */ { false, 0x2f8a, 0x2f8a }, +/* 0x2f8b */ { false, 0x2f8b, 0x2f8b }, +/* 0x2f8c */ { false, 0x2f8c, 0x2f8c }, +/* 0x2f8d */ { false, 0x2f8d, 0x2f8d }, +/* 0x2f8e */ { false, 0x2f8e, 0x2f8e }, +/* 0x2f8f */ { false, 0x2f8f, 0x2f8f }, +/* 0x2f90 */ { false, 0x2f90, 0x2f90 }, +/* 0x2f91 */ { false, 0x2f91, 0x2f91 }, +/* 0x2f92 */ { false, 0x2f92, 0x2f92 }, +/* 0x2f93 */ { false, 0x2f93, 0x2f93 }, +/* 0x2f94 */ { false, 0x2f94, 0x2f94 }, +/* 0x2f95 */ { false, 0x2f95, 0x2f95 }, +/* 0x2f96 */ { false, 0x2f96, 0x2f96 }, +/* 0x2f97 */ { false, 0x2f97, 0x2f97 }, +/* 0x2f98 */ { false, 0x2f98, 0x2f98 }, +/* 0x2f99 */ { false, 0x2f99, 0x2f99 }, +/* 0x2f9a */ { false, 0x2f9a, 0x2f9a }, +/* 0x2f9b */ { false, 0x2f9b, 0x2f9b }, +/* 0x2f9c */ { false, 0x2f9c, 0x2f9c }, +/* 0x2f9d */ { false, 0x2f9d, 0x2f9d }, +/* 0x2f9e */ { false, 0x2f9e, 0x2f9e }, +/* 0x2f9f */ { false, 0x2f9f, 0x2f9f }, +/* 0x2fa0 */ { false, 0x2fa0, 0x2fa0 }, +/* 0x2fa1 */ { false, 0x2fa1, 0x2fa1 }, +/* 0x2fa2 */ { false, 0x2fa2, 0x2fa2 }, +/* 0x2fa3 */ { false, 0x2fa3, 0x2fa3 }, +/* 0x2fa4 */ { false, 0x2fa4, 0x2fa4 }, +/* 0x2fa5 */ { false, 0x2fa5, 0x2fa5 }, +/* 0x2fa6 */ { false, 0x2fa6, 0x2fa6 }, +/* 0x2fa7 */ { false, 0x2fa7, 0x2fa7 }, +/* 0x2fa8 */ { false, 0x2fa8, 0x2fa8 }, +/* 0x2fa9 */ { false, 0x2fa9, 0x2fa9 }, +/* 0x2faa */ { false, 0x2faa, 0x2faa }, +/* 0x2fab */ { false, 0x2fab, 0x2fab }, +/* 0x2fac */ { false, 0x2fac, 0x2fac }, +/* 0x2fad */ { false, 0x2fad, 0x2fad }, +/* 0x2fae */ { false, 0x2fae, 0x2fae }, +/* 0x2faf */ { false, 0x2faf, 0x2faf }, +/* 0x2fb0 */ { false, 0x2fb0, 0x2fb0 }, +/* 0x2fb1 */ { false, 0x2fb1, 0x2fb1 }, +/* 0x2fb2 */ { false, 0x2fb2, 0x2fb2 }, +/* 0x2fb3 */ { false, 0x2fb3, 0x2fb3 }, +/* 0x2fb4 */ { false, 0x2fb4, 0x2fb4 }, +/* 0x2fb5 */ { false, 0x2fb5, 0x2fb5 }, +/* 0x2fb6 */ { false, 0x2fb6, 0x2fb6 }, +/* 0x2fb7 */ { false, 0x2fb7, 0x2fb7 }, +/* 0x2fb8 */ { false, 0x2fb8, 0x2fb8 }, +/* 0x2fb9 */ { false, 0x2fb9, 0x2fb9 }, +/* 0x2fba */ { false, 0x2fba, 0x2fba }, +/* 0x2fbb */ { false, 0x2fbb, 0x2fbb }, +/* 0x2fbc */ { false, 0x2fbc, 0x2fbc }, +/* 0x2fbd */ { false, 0x2fbd, 0x2fbd }, +/* 0x2fbe */ { false, 0x2fbe, 0x2fbe }, +/* 0x2fbf */ { false, 0x2fbf, 0x2fbf }, +/* 0x2fc0 */ { false, 0x2fc0, 0x2fc0 }, +/* 0x2fc1 */ { false, 0x2fc1, 0x2fc1 }, +/* 0x2fc2 */ { false, 0x2fc2, 0x2fc2 }, +/* 0x2fc3 */ { false, 0x2fc3, 0x2fc3 }, +/* 0x2fc4 */ { false, 0x2fc4, 0x2fc4 }, +/* 0x2fc5 */ { false, 0x2fc5, 0x2fc5 }, +/* 0x2fc6 */ { false, 0x2fc6, 0x2fc6 }, +/* 0x2fc7 */ { false, 0x2fc7, 0x2fc7 }, +/* 0x2fc8 */ { false, 0x2fc8, 0x2fc8 }, +/* 0x2fc9 */ { false, 0x2fc9, 0x2fc9 }, +/* 0x2fca */ { false, 0x2fca, 0x2fca }, +/* 0x2fcb */ { false, 0x2fcb, 0x2fcb }, +/* 0x2fcc */ { false, 0x2fcc, 0x2fcc }, +/* 0x2fcd */ { false, 0x2fcd, 0x2fcd }, +/* 0x2fce */ { false, 0x2fce, 0x2fce }, +/* 0x2fcf */ { false, 0x2fcf, 0x2fcf }, +/* 0x2fd0 */ { false, 0x2fd0, 0x2fd0 }, +/* 0x2fd1 */ { false, 0x2fd1, 0x2fd1 }, +/* 0x2fd2 */ { false, 0x2fd2, 0x2fd2 }, +/* 0x2fd3 */ { false, 0x2fd3, 0x2fd3 }, +/* 0x2fd4 */ { false, 0x2fd4, 0x2fd4 }, +/* 0x2fd5 */ { false, 0x2fd5, 0x2fd5 }, +/* 0x2fd6 */ { false, 0x2fd6, 0x2fd6 }, +/* 0x2fd7 */ { false, 0x2fd7, 0x2fd7 }, +/* 0x2fd8 */ { false, 0x2fd8, 0x2fd8 }, +/* 0x2fd9 */ { false, 0x2fd9, 0x2fd9 }, +/* 0x2fda */ { false, 0x2fda, 0x2fda }, +/* 0x2fdb */ { false, 0x2fdb, 0x2fdb }, +/* 0x2fdc */ { false, 0x2fdc, 0x2fdc }, +/* 0x2fdd */ { false, 0x2fdd, 0x2fdd }, +/* 0x2fde */ { false, 0x2fde, 0x2fde }, +/* 0x2fdf */ { false, 0x2fdf, 0x2fdf }, +/* 0x2fe0 */ { false, 0x2fe0, 0x2fe0 }, +/* 0x2fe1 */ { false, 0x2fe1, 0x2fe1 }, +/* 0x2fe2 */ { false, 0x2fe2, 0x2fe2 }, +/* 0x2fe3 */ { false, 0x2fe3, 0x2fe3 }, +/* 0x2fe4 */ { false, 0x2fe4, 0x2fe4 }, +/* 0x2fe5 */ { false, 0x2fe5, 0x2fe5 }, +/* 0x2fe6 */ { false, 0x2fe6, 0x2fe6 }, +/* 0x2fe7 */ { false, 0x2fe7, 0x2fe7 }, +/* 0x2fe8 */ { false, 0x2fe8, 0x2fe8 }, +/* 0x2fe9 */ { false, 0x2fe9, 0x2fe9 }, +/* 0x2fea */ { false, 0x2fea, 0x2fea }, +/* 0x2feb */ { false, 0x2feb, 0x2feb }, +/* 0x2fec */ { false, 0x2fec, 0x2fec }, +/* 0x2fed */ { false, 0x2fed, 0x2fed }, +/* 0x2fee */ { false, 0x2fee, 0x2fee }, +/* 0x2fef */ { false, 0x2fef, 0x2fef }, +/* 0x2ff0 */ { false, 0x2ff0, 0x2ff0 }, +/* 0x2ff1 */ { false, 0x2ff1, 0x2ff1 }, +/* 0x2ff2 */ { false, 0x2ff2, 0x2ff2 }, +/* 0x2ff3 */ { false, 0x2ff3, 0x2ff3 }, +/* 0x2ff4 */ { false, 0x2ff4, 0x2ff4 }, +/* 0x2ff5 */ { false, 0x2ff5, 0x2ff5 }, +/* 0x2ff6 */ { false, 0x2ff6, 0x2ff6 }, +/* 0x2ff7 */ { false, 0x2ff7, 0x2ff7 }, +/* 0x2ff8 */ { false, 0x2ff8, 0x2ff8 }, +/* 0x2ff9 */ { false, 0x2ff9, 0x2ff9 }, +/* 0x2ffa */ { false, 0x2ffa, 0x2ffa }, +/* 0x2ffb */ { false, 0x2ffb, 0x2ffb }, +/* 0x2ffc */ { false, 0x2ffc, 0x2ffc }, +/* 0x2ffd */ { false, 0x2ffd, 0x2ffd }, +/* 0x2ffe */ { false, 0x2ffe, 0x2ffe }, +/* 0x2fff */ { false, 0x2fff, 0x2fff }, +/* 0x3000 */ { false, 0x3000, 0x3000 }, +/* 0x3001 */ { false, 0x3001, 0x3001 }, +/* 0x3002 */ { false, 0x3002, 0x3002 }, +/* 0x3003 */ { false, 0x3003, 0x3003 }, +/* 0x3004 */ { false, 0x3004, 0x3004 }, +/* 0x3005 */ { true, 0x3005, 0x3005 }, +/* 0x3006 */ { true, 0x3006, 0x3006 }, +/* 0x3007 */ { false, 0x3007, 0x3007 }, +/* 0x3008 */ { false, 0x3008, 0x3008 }, +/* 0x3009 */ { false, 0x3009, 0x3009 }, +/* 0x300a */ { false, 0x300a, 0x300a }, +/* 0x300b */ { false, 0x300b, 0x300b }, +/* 0x300c */ { false, 0x300c, 0x300c }, +/* 0x300d */ { false, 0x300d, 0x300d }, +/* 0x300e */ { false, 0x300e, 0x300e }, +/* 0x300f */ { false, 0x300f, 0x300f }, +/* 0x3010 */ { false, 0x3010, 0x3010 }, +/* 0x3011 */ { false, 0x3011, 0x3011 }, +/* 0x3012 */ { false, 0x3012, 0x3012 }, +/* 0x3013 */ { false, 0x3013, 0x3013 }, +/* 0x3014 */ { false, 0x3014, 0x3014 }, +/* 0x3015 */ { false, 0x3015, 0x3015 }, +/* 0x3016 */ { false, 0x3016, 0x3016 }, +/* 0x3017 */ { false, 0x3017, 0x3017 }, +/* 0x3018 */ { false, 0x3018, 0x3018 }, +/* 0x3019 */ { false, 0x3019, 0x3019 }, +/* 0x301a */ { false, 0x301a, 0x301a }, +/* 0x301b */ { false, 0x301b, 0x301b }, +/* 0x301c */ { false, 0x301c, 0x301c }, +/* 0x301d */ { false, 0x301d, 0x301d }, +/* 0x301e */ { false, 0x301e, 0x301e }, +/* 0x301f */ { false, 0x301f, 0x301f }, +/* 0x3020 */ { false, 0x3020, 0x3020 }, +/* 0x3021 */ { false, 0x3021, 0x3021 }, +/* 0x3022 */ { false, 0x3022, 0x3022 }, +/* 0x3023 */ { false, 0x3023, 0x3023 }, +/* 0x3024 */ { false, 0x3024, 0x3024 }, +/* 0x3025 */ { false, 0x3025, 0x3025 }, +/* 0x3026 */ { false, 0x3026, 0x3026 }, +/* 0x3027 */ { false, 0x3027, 0x3027 }, +/* 0x3028 */ { false, 0x3028, 0x3028 }, +/* 0x3029 */ { false, 0x3029, 0x3029 }, +/* 0x302a */ { true, 0x302a, 0x302a }, +/* 0x302b */ { true, 0x302b, 0x302b }, +/* 0x302c */ { true, 0x302c, 0x302c }, +/* 0x302d */ { true, 0x302d, 0x302d }, +/* 0x302e */ { true, 0x302e, 0x302e }, +/* 0x302f */ { true, 0x302f, 0x302f }, +/* 0x3030 */ { false, 0x3030, 0x3030 }, +/* 0x3031 */ { true, 0x3031, 0x3031 }, +/* 0x3032 */ { true, 0x3032, 0x3032 }, +/* 0x3033 */ { true, 0x3033, 0x3033 }, +/* 0x3034 */ { true, 0x3034, 0x3034 }, +/* 0x3035 */ { true, 0x3035, 0x3035 }, +/* 0x3036 */ { false, 0x3036, 0x3036 }, +/* 0x3037 */ { false, 0x3037, 0x3037 }, +/* 0x3038 */ { false, 0x3038, 0x3038 }, +/* 0x3039 */ { false, 0x3039, 0x3039 }, +/* 0x303a */ { false, 0x303a, 0x303a }, +/* 0x303b */ { true, 0x303b, 0x303b }, +/* 0x303c */ { true, 0x303c, 0x303c }, +/* 0x303d */ { false, 0x303d, 0x303d }, +/* 0x303e */ { false, 0x303e, 0x303e }, +/* 0x303f */ { false, 0x303f, 0x303f }, +/* 0x3040 */ { false, 0x3040, 0x3040 }, +/* 0x3041 */ { true, 0x3041, 0x3041 }, +/* 0x3042 */ { true, 0x3042, 0x3042 }, +/* 0x3043 */ { true, 0x3043, 0x3043 }, +/* 0x3044 */ { true, 0x3044, 0x3044 }, +/* 0x3045 */ { true, 0x3045, 0x3045 }, +/* 0x3046 */ { true, 0x3046, 0x3046 }, +/* 0x3047 */ { true, 0x3047, 0x3047 }, +/* 0x3048 */ { true, 0x3048, 0x3048 }, +/* 0x3049 */ { true, 0x3049, 0x3049 }, +/* 0x304a */ { true, 0x304a, 0x304a }, +/* 0x304b */ { true, 0x304b, 0x304b }, +/* 0x304c */ { true, 0x304c, 0x304c }, +/* 0x304d */ { true, 0x304d, 0x304d }, +/* 0x304e */ { true, 0x304e, 0x304e }, +/* 0x304f */ { true, 0x304f, 0x304f }, +/* 0x3050 */ { true, 0x3050, 0x3050 }, +/* 0x3051 */ { true, 0x3051, 0x3051 }, +/* 0x3052 */ { true, 0x3052, 0x3052 }, +/* 0x3053 */ { true, 0x3053, 0x3053 }, +/* 0x3054 */ { true, 0x3054, 0x3054 }, +/* 0x3055 */ { true, 0x3055, 0x3055 }, +/* 0x3056 */ { true, 0x3056, 0x3056 }, +/* 0x3057 */ { true, 0x3057, 0x3057 }, +/* 0x3058 */ { true, 0x3058, 0x3058 }, +/* 0x3059 */ { true, 0x3059, 0x3059 }, +/* 0x305a */ { true, 0x305a, 0x305a }, +/* 0x305b */ { true, 0x305b, 0x305b }, +/* 0x305c */ { true, 0x305c, 0x305c }, +/* 0x305d */ { true, 0x305d, 0x305d }, +/* 0x305e */ { true, 0x305e, 0x305e }, +/* 0x305f */ { true, 0x305f, 0x305f }, +/* 0x3060 */ { true, 0x3060, 0x3060 }, +/* 0x3061 */ { true, 0x3061, 0x3061 }, +/* 0x3062 */ { true, 0x3062, 0x3062 }, +/* 0x3063 */ { true, 0x3063, 0x3063 }, +/* 0x3064 */ { true, 0x3064, 0x3064 }, +/* 0x3065 */ { true, 0x3065, 0x3065 }, +/* 0x3066 */ { true, 0x3066, 0x3066 }, +/* 0x3067 */ { true, 0x3067, 0x3067 }, +/* 0x3068 */ { true, 0x3068, 0x3068 }, +/* 0x3069 */ { true, 0x3069, 0x3069 }, +/* 0x306a */ { true, 0x306a, 0x306a }, +/* 0x306b */ { true, 0x306b, 0x306b }, +/* 0x306c */ { true, 0x306c, 0x306c }, +/* 0x306d */ { true, 0x306d, 0x306d }, +/* 0x306e */ { true, 0x306e, 0x306e }, +/* 0x306f */ { true, 0x306f, 0x306f }, +/* 0x3070 */ { true, 0x3070, 0x3070 }, +/* 0x3071 */ { true, 0x3071, 0x3071 }, +/* 0x3072 */ { true, 0x3072, 0x3072 }, +/* 0x3073 */ { true, 0x3073, 0x3073 }, +/* 0x3074 */ { true, 0x3074, 0x3074 }, +/* 0x3075 */ { true, 0x3075, 0x3075 }, +/* 0x3076 */ { true, 0x3076, 0x3076 }, +/* 0x3077 */ { true, 0x3077, 0x3077 }, +/* 0x3078 */ { true, 0x3078, 0x3078 }, +/* 0x3079 */ { true, 0x3079, 0x3079 }, +/* 0x307a */ { true, 0x307a, 0x307a }, +/* 0x307b */ { true, 0x307b, 0x307b }, +/* 0x307c */ { true, 0x307c, 0x307c }, +/* 0x307d */ { true, 0x307d, 0x307d }, +/* 0x307e */ { true, 0x307e, 0x307e }, +/* 0x307f */ { true, 0x307f, 0x307f }, +/* 0x3080 */ { true, 0x3080, 0x3080 }, +/* 0x3081 */ { true, 0x3081, 0x3081 }, +/* 0x3082 */ { true, 0x3082, 0x3082 }, +/* 0x3083 */ { true, 0x3083, 0x3083 }, +/* 0x3084 */ { true, 0x3084, 0x3084 }, +/* 0x3085 */ { true, 0x3085, 0x3085 }, +/* 0x3086 */ { true, 0x3086, 0x3086 }, +/* 0x3087 */ { true, 0x3087, 0x3087 }, +/* 0x3088 */ { true, 0x3088, 0x3088 }, +/* 0x3089 */ { true, 0x3089, 0x3089 }, +/* 0x308a */ { true, 0x308a, 0x308a }, +/* 0x308b */ { true, 0x308b, 0x308b }, +/* 0x308c */ { true, 0x308c, 0x308c }, +/* 0x308d */ { true, 0x308d, 0x308d }, +/* 0x308e */ { true, 0x308e, 0x308e }, +/* 0x308f */ { true, 0x308f, 0x308f }, +/* 0x3090 */ { true, 0x3090, 0x3090 }, +/* 0x3091 */ { true, 0x3091, 0x3091 }, +/* 0x3092 */ { true, 0x3092, 0x3092 }, +/* 0x3093 */ { true, 0x3093, 0x3093 }, +/* 0x3094 */ { true, 0x3094, 0x3094 }, +/* 0x3095 */ { true, 0x3095, 0x3095 }, +/* 0x3096 */ { true, 0x3096, 0x3096 }, +/* 0x3097 */ { false, 0x3097, 0x3097 }, +/* 0x3098 */ { false, 0x3098, 0x3098 }, +/* 0x3099 */ { true, 0x3099, 0x3099 }, +/* 0x309a */ { true, 0x309a, 0x309a }, +/* 0x309b */ { false, 0x309b, 0x309b }, +/* 0x309c */ { false, 0x309c, 0x309c }, +/* 0x309d */ { true, 0x309d, 0x309d }, +/* 0x309e */ { true, 0x309e, 0x309e }, +/* 0x309f */ { true, 0x309f, 0x309f }, +/* 0x30a0 */ { false, 0x30a0, 0x30a0 }, +/* 0x30a1 */ { true, 0x30a1, 0x30a1 }, +/* 0x30a2 */ { true, 0x30a2, 0x30a2 }, +/* 0x30a3 */ { true, 0x30a3, 0x30a3 }, +/* 0x30a4 */ { true, 0x30a4, 0x30a4 }, +/* 0x30a5 */ { true, 0x30a5, 0x30a5 }, +/* 0x30a6 */ { true, 0x30a6, 0x30a6 }, +/* 0x30a7 */ { true, 0x30a7, 0x30a7 }, +/* 0x30a8 */ { true, 0x30a8, 0x30a8 }, +/* 0x30a9 */ { true, 0x30a9, 0x30a9 }, +/* 0x30aa */ { true, 0x30aa, 0x30aa }, +/* 0x30ab */ { true, 0x30ab, 0x30ab }, +/* 0x30ac */ { true, 0x30ac, 0x30ac }, +/* 0x30ad */ { true, 0x30ad, 0x30ad }, +/* 0x30ae */ { true, 0x30ae, 0x30ae }, +/* 0x30af */ { true, 0x30af, 0x30af }, +/* 0x30b0 */ { true, 0x30b0, 0x30b0 }, +/* 0x30b1 */ { true, 0x30b1, 0x30b1 }, +/* 0x30b2 */ { true, 0x30b2, 0x30b2 }, +/* 0x30b3 */ { true, 0x30b3, 0x30b3 }, +/* 0x30b4 */ { true, 0x30b4, 0x30b4 }, +/* 0x30b5 */ { true, 0x30b5, 0x30b5 }, +/* 0x30b6 */ { true, 0x30b6, 0x30b6 }, +/* 0x30b7 */ { true, 0x30b7, 0x30b7 }, +/* 0x30b8 */ { true, 0x30b8, 0x30b8 }, +/* 0x30b9 */ { true, 0x30b9, 0x30b9 }, +/* 0x30ba */ { true, 0x30ba, 0x30ba }, +/* 0x30bb */ { true, 0x30bb, 0x30bb }, +/* 0x30bc */ { true, 0x30bc, 0x30bc }, +/* 0x30bd */ { true, 0x30bd, 0x30bd }, +/* 0x30be */ { true, 0x30be, 0x30be }, +/* 0x30bf */ { true, 0x30bf, 0x30bf }, +/* 0x30c0 */ { true, 0x30c0, 0x30c0 }, +/* 0x30c1 */ { true, 0x30c1, 0x30c1 }, +/* 0x30c2 */ { true, 0x30c2, 0x30c2 }, +/* 0x30c3 */ { true, 0x30c3, 0x30c3 }, +/* 0x30c4 */ { true, 0x30c4, 0x30c4 }, +/* 0x30c5 */ { true, 0x30c5, 0x30c5 }, +/* 0x30c6 */ { true, 0x30c6, 0x30c6 }, +/* 0x30c7 */ { true, 0x30c7, 0x30c7 }, +/* 0x30c8 */ { true, 0x30c8, 0x30c8 }, +/* 0x30c9 */ { true, 0x30c9, 0x30c9 }, +/* 0x30ca */ { true, 0x30ca, 0x30ca }, +/* 0x30cb */ { true, 0x30cb, 0x30cb }, +/* 0x30cc */ { true, 0x30cc, 0x30cc }, +/* 0x30cd */ { true, 0x30cd, 0x30cd }, +/* 0x30ce */ { true, 0x30ce, 0x30ce }, +/* 0x30cf */ { true, 0x30cf, 0x30cf }, +/* 0x30d0 */ { true, 0x30d0, 0x30d0 }, +/* 0x30d1 */ { true, 0x30d1, 0x30d1 }, +/* 0x30d2 */ { true, 0x30d2, 0x30d2 }, +/* 0x30d3 */ { true, 0x30d3, 0x30d3 }, +/* 0x30d4 */ { true, 0x30d4, 0x30d4 }, +/* 0x30d5 */ { true, 0x30d5, 0x30d5 }, +/* 0x30d6 */ { true, 0x30d6, 0x30d6 }, +/* 0x30d7 */ { true, 0x30d7, 0x30d7 }, +/* 0x30d8 */ { true, 0x30d8, 0x30d8 }, +/* 0x30d9 */ { true, 0x30d9, 0x30d9 }, +/* 0x30da */ { true, 0x30da, 0x30da }, +/* 0x30db */ { true, 0x30db, 0x30db }, +/* 0x30dc */ { true, 0x30dc, 0x30dc }, +/* 0x30dd */ { true, 0x30dd, 0x30dd }, +/* 0x30de */ { true, 0x30de, 0x30de }, +/* 0x30df */ { true, 0x30df, 0x30df }, +/* 0x30e0 */ { true, 0x30e0, 0x30e0 }, +/* 0x30e1 */ { true, 0x30e1, 0x30e1 }, +/* 0x30e2 */ { true, 0x30e2, 0x30e2 }, +/* 0x30e3 */ { true, 0x30e3, 0x30e3 }, +/* 0x30e4 */ { true, 0x30e4, 0x30e4 }, +/* 0x30e5 */ { true, 0x30e5, 0x30e5 }, +/* 0x30e6 */ { true, 0x30e6, 0x30e6 }, +/* 0x30e7 */ { true, 0x30e7, 0x30e7 }, +/* 0x30e8 */ { true, 0x30e8, 0x30e8 }, +/* 0x30e9 */ { true, 0x30e9, 0x30e9 }, +/* 0x30ea */ { true, 0x30ea, 0x30ea }, +/* 0x30eb */ { true, 0x30eb, 0x30eb }, +/* 0x30ec */ { true, 0x30ec, 0x30ec }, +/* 0x30ed */ { true, 0x30ed, 0x30ed }, +/* 0x30ee */ { true, 0x30ee, 0x30ee }, +/* 0x30ef */ { true, 0x30ef, 0x30ef }, +/* 0x30f0 */ { true, 0x30f0, 0x30f0 }, +/* 0x30f1 */ { true, 0x30f1, 0x30f1 }, +/* 0x30f2 */ { true, 0x30f2, 0x30f2 }, +/* 0x30f3 */ { true, 0x30f3, 0x30f3 }, +/* 0x30f4 */ { true, 0x30f4, 0x30f4 }, +/* 0x30f5 */ { true, 0x30f5, 0x30f5 }, +/* 0x30f6 */ { true, 0x30f6, 0x30f6 }, +/* 0x30f7 */ { true, 0x30f7, 0x30f7 }, +/* 0x30f8 */ { true, 0x30f8, 0x30f8 }, +/* 0x30f9 */ { true, 0x30f9, 0x30f9 }, +/* 0x30fa */ { true, 0x30fa, 0x30fa }, +/* 0x30fb */ { false, 0x30fb, 0x30fb }, +/* 0x30fc */ { true, 0x30fc, 0x30fc }, +/* 0x30fd */ { true, 0x30fd, 0x30fd }, +/* 0x30fe */ { true, 0x30fe, 0x30fe }, +/* 0x30ff */ { true, 0x30ff, 0x30ff }, +/* 0x3100 */ { false, 0x3100, 0x3100 }, +/* 0x3101 */ { false, 0x3101, 0x3101 }, +/* 0x3102 */ { false, 0x3102, 0x3102 }, +/* 0x3103 */ { false, 0x3103, 0x3103 }, +/* 0x3104 */ { false, 0x3104, 0x3104 }, +/* 0x3105 */ { true, 0x3105, 0x3105 }, +/* 0x3106 */ { true, 0x3106, 0x3106 }, +/* 0x3107 */ { true, 0x3107, 0x3107 }, +/* 0x3108 */ { true, 0x3108, 0x3108 }, +/* 0x3109 */ { true, 0x3109, 0x3109 }, +/* 0x310a */ { true, 0x310a, 0x310a }, +/* 0x310b */ { true, 0x310b, 0x310b }, +/* 0x310c */ { true, 0x310c, 0x310c }, +/* 0x310d */ { true, 0x310d, 0x310d }, +/* 0x310e */ { true, 0x310e, 0x310e }, +/* 0x310f */ { true, 0x310f, 0x310f }, +/* 0x3110 */ { true, 0x3110, 0x3110 }, +/* 0x3111 */ { true, 0x3111, 0x3111 }, +/* 0x3112 */ { true, 0x3112, 0x3112 }, +/* 0x3113 */ { true, 0x3113, 0x3113 }, +/* 0x3114 */ { true, 0x3114, 0x3114 }, +/* 0x3115 */ { true, 0x3115, 0x3115 }, +/* 0x3116 */ { true, 0x3116, 0x3116 }, +/* 0x3117 */ { true, 0x3117, 0x3117 }, +/* 0x3118 */ { true, 0x3118, 0x3118 }, +/* 0x3119 */ { true, 0x3119, 0x3119 }, +/* 0x311a */ { true, 0x311a, 0x311a }, +/* 0x311b */ { true, 0x311b, 0x311b }, +/* 0x311c */ { true, 0x311c, 0x311c }, +/* 0x311d */ { true, 0x311d, 0x311d }, +/* 0x311e */ { true, 0x311e, 0x311e }, +/* 0x311f */ { true, 0x311f, 0x311f }, +/* 0x3120 */ { true, 0x3120, 0x3120 }, +/* 0x3121 */ { true, 0x3121, 0x3121 }, +/* 0x3122 */ { true, 0x3122, 0x3122 }, +/* 0x3123 */ { true, 0x3123, 0x3123 }, +/* 0x3124 */ { true, 0x3124, 0x3124 }, +/* 0x3125 */ { true, 0x3125, 0x3125 }, +/* 0x3126 */ { true, 0x3126, 0x3126 }, +/* 0x3127 */ { true, 0x3127, 0x3127 }, +/* 0x3128 */ { true, 0x3128, 0x3128 }, +/* 0x3129 */ { true, 0x3129, 0x3129 }, +/* 0x312a */ { true, 0x312a, 0x312a }, +/* 0x312b */ { true, 0x312b, 0x312b }, +/* 0x312c */ { true, 0x312c, 0x312c }, +/* 0x312d */ { false, 0x312d, 0x312d }, +/* 0x312e */ { false, 0x312e, 0x312e }, +/* 0x312f */ { false, 0x312f, 0x312f }, +/* 0x3130 */ { false, 0x3130, 0x3130 }, +/* 0x3131 */ { true, 0x3131, 0x3131 }, +/* 0x3132 */ { true, 0x3132, 0x3132 }, +/* 0x3133 */ { true, 0x3133, 0x3133 }, +/* 0x3134 */ { true, 0x3134, 0x3134 }, +/* 0x3135 */ { true, 0x3135, 0x3135 }, +/* 0x3136 */ { true, 0x3136, 0x3136 }, +/* 0x3137 */ { true, 0x3137, 0x3137 }, +/* 0x3138 */ { true, 0x3138, 0x3138 }, +/* 0x3139 */ { true, 0x3139, 0x3139 }, +/* 0x313a */ { true, 0x313a, 0x313a }, +/* 0x313b */ { true, 0x313b, 0x313b }, +/* 0x313c */ { true, 0x313c, 0x313c }, +/* 0x313d */ { true, 0x313d, 0x313d }, +/* 0x313e */ { true, 0x313e, 0x313e }, +/* 0x313f */ { true, 0x313f, 0x313f }, +/* 0x3140 */ { true, 0x3140, 0x3140 }, +/* 0x3141 */ { true, 0x3141, 0x3141 }, +/* 0x3142 */ { true, 0x3142, 0x3142 }, +/* 0x3143 */ { true, 0x3143, 0x3143 }, +/* 0x3144 */ { true, 0x3144, 0x3144 }, +/* 0x3145 */ { true, 0x3145, 0x3145 }, +/* 0x3146 */ { true, 0x3146, 0x3146 }, +/* 0x3147 */ { true, 0x3147, 0x3147 }, +/* 0x3148 */ { true, 0x3148, 0x3148 }, +/* 0x3149 */ { true, 0x3149, 0x3149 }, +/* 0x314a */ { true, 0x314a, 0x314a }, +/* 0x314b */ { true, 0x314b, 0x314b }, +/* 0x314c */ { true, 0x314c, 0x314c }, +/* 0x314d */ { true, 0x314d, 0x314d }, +/* 0x314e */ { true, 0x314e, 0x314e }, +/* 0x314f */ { true, 0x314f, 0x314f }, +/* 0x3150 */ { true, 0x3150, 0x3150 }, +/* 0x3151 */ { true, 0x3151, 0x3151 }, +/* 0x3152 */ { true, 0x3152, 0x3152 }, +/* 0x3153 */ { true, 0x3153, 0x3153 }, +/* 0x3154 */ { true, 0x3154, 0x3154 }, +/* 0x3155 */ { true, 0x3155, 0x3155 }, +/* 0x3156 */ { true, 0x3156, 0x3156 }, +/* 0x3157 */ { true, 0x3157, 0x3157 }, +/* 0x3158 */ { true, 0x3158, 0x3158 }, +/* 0x3159 */ { true, 0x3159, 0x3159 }, +/* 0x315a */ { true, 0x315a, 0x315a }, +/* 0x315b */ { true, 0x315b, 0x315b }, +/* 0x315c */ { true, 0x315c, 0x315c }, +/* 0x315d */ { true, 0x315d, 0x315d }, +/* 0x315e */ { true, 0x315e, 0x315e }, +/* 0x315f */ { true, 0x315f, 0x315f }, +/* 0x3160 */ { true, 0x3160, 0x3160 }, +/* 0x3161 */ { true, 0x3161, 0x3161 }, +/* 0x3162 */ { true, 0x3162, 0x3162 }, +/* 0x3163 */ { true, 0x3163, 0x3163 }, +/* 0x3164 */ { true, 0x3164, 0x3164 }, +/* 0x3165 */ { true, 0x3165, 0x3165 }, +/* 0x3166 */ { true, 0x3166, 0x3166 }, +/* 0x3167 */ { true, 0x3167, 0x3167 }, +/* 0x3168 */ { true, 0x3168, 0x3168 }, +/* 0x3169 */ { true, 0x3169, 0x3169 }, +/* 0x316a */ { true, 0x316a, 0x316a }, +/* 0x316b */ { true, 0x316b, 0x316b }, +/* 0x316c */ { true, 0x316c, 0x316c }, +/* 0x316d */ { true, 0x316d, 0x316d }, +/* 0x316e */ { true, 0x316e, 0x316e }, +/* 0x316f */ { true, 0x316f, 0x316f }, +/* 0x3170 */ { true, 0x3170, 0x3170 }, +/* 0x3171 */ { true, 0x3171, 0x3171 }, +/* 0x3172 */ { true, 0x3172, 0x3172 }, +/* 0x3173 */ { true, 0x3173, 0x3173 }, +/* 0x3174 */ { true, 0x3174, 0x3174 }, +/* 0x3175 */ { true, 0x3175, 0x3175 }, +/* 0x3176 */ { true, 0x3176, 0x3176 }, +/* 0x3177 */ { true, 0x3177, 0x3177 }, +/* 0x3178 */ { true, 0x3178, 0x3178 }, +/* 0x3179 */ { true, 0x3179, 0x3179 }, +/* 0x317a */ { true, 0x317a, 0x317a }, +/* 0x317b */ { true, 0x317b, 0x317b }, +/* 0x317c */ { true, 0x317c, 0x317c }, +/* 0x317d */ { true, 0x317d, 0x317d }, +/* 0x317e */ { true, 0x317e, 0x317e }, +/* 0x317f */ { true, 0x317f, 0x317f }, +/* 0x3180 */ { true, 0x3180, 0x3180 }, +/* 0x3181 */ { true, 0x3181, 0x3181 }, +/* 0x3182 */ { true, 0x3182, 0x3182 }, +/* 0x3183 */ { true, 0x3183, 0x3183 }, +/* 0x3184 */ { true, 0x3184, 0x3184 }, +/* 0x3185 */ { true, 0x3185, 0x3185 }, +/* 0x3186 */ { true, 0x3186, 0x3186 }, +/* 0x3187 */ { true, 0x3187, 0x3187 }, +/* 0x3188 */ { true, 0x3188, 0x3188 }, +/* 0x3189 */ { true, 0x3189, 0x3189 }, +/* 0x318a */ { true, 0x318a, 0x318a }, +/* 0x318b */ { true, 0x318b, 0x318b }, +/* 0x318c */ { true, 0x318c, 0x318c }, +/* 0x318d */ { true, 0x318d, 0x318d }, +/* 0x318e */ { true, 0x318e, 0x318e }, +/* 0x318f */ { false, 0x318f, 0x318f }, +/* 0x3190 */ { false, 0x3190, 0x3190 }, +/* 0x3191 */ { false, 0x3191, 0x3191 }, +/* 0x3192 */ { false, 0x3192, 0x3192 }, +/* 0x3193 */ { false, 0x3193, 0x3193 }, +/* 0x3194 */ { false, 0x3194, 0x3194 }, +/* 0x3195 */ { false, 0x3195, 0x3195 }, +/* 0x3196 */ { false, 0x3196, 0x3196 }, +/* 0x3197 */ { false, 0x3197, 0x3197 }, +/* 0x3198 */ { false, 0x3198, 0x3198 }, +/* 0x3199 */ { false, 0x3199, 0x3199 }, +/* 0x319a */ { false, 0x319a, 0x319a }, +/* 0x319b */ { false, 0x319b, 0x319b }, +/* 0x319c */ { false, 0x319c, 0x319c }, +/* 0x319d */ { false, 0x319d, 0x319d }, +/* 0x319e */ { false, 0x319e, 0x319e }, +/* 0x319f */ { false, 0x319f, 0x319f }, +/* 0x31a0 */ { true, 0x31a0, 0x31a0 }, +/* 0x31a1 */ { true, 0x31a1, 0x31a1 }, +/* 0x31a2 */ { true, 0x31a2, 0x31a2 }, +/* 0x31a3 */ { true, 0x31a3, 0x31a3 }, +/* 0x31a4 */ { true, 0x31a4, 0x31a4 }, +/* 0x31a5 */ { true, 0x31a5, 0x31a5 }, +/* 0x31a6 */ { true, 0x31a6, 0x31a6 }, +/* 0x31a7 */ { true, 0x31a7, 0x31a7 }, +/* 0x31a8 */ { true, 0x31a8, 0x31a8 }, +/* 0x31a9 */ { true, 0x31a9, 0x31a9 }, +/* 0x31aa */ { true, 0x31aa, 0x31aa }, +/* 0x31ab */ { true, 0x31ab, 0x31ab }, +/* 0x31ac */ { true, 0x31ac, 0x31ac }, +/* 0x31ad */ { true, 0x31ad, 0x31ad }, +/* 0x31ae */ { true, 0x31ae, 0x31ae }, +/* 0x31af */ { true, 0x31af, 0x31af }, +/* 0x31b0 */ { true, 0x31b0, 0x31b0 }, +/* 0x31b1 */ { true, 0x31b1, 0x31b1 }, +/* 0x31b2 */ { true, 0x31b2, 0x31b2 }, +/* 0x31b3 */ { true, 0x31b3, 0x31b3 }, +/* 0x31b4 */ { true, 0x31b4, 0x31b4 }, +/* 0x31b5 */ { true, 0x31b5, 0x31b5 }, +/* 0x31b6 */ { true, 0x31b6, 0x31b6 }, +/* 0x31b7 */ { true, 0x31b7, 0x31b7 }, +/* 0x31b8 */ { false, 0x31b8, 0x31b8 }, +/* 0x31b9 */ { false, 0x31b9, 0x31b9 }, +/* 0x31ba */ { false, 0x31ba, 0x31ba }, +/* 0x31bb */ { false, 0x31bb, 0x31bb }, +/* 0x31bc */ { false, 0x31bc, 0x31bc }, +/* 0x31bd */ { false, 0x31bd, 0x31bd }, +/* 0x31be */ { false, 0x31be, 0x31be }, +/* 0x31bf */ { false, 0x31bf, 0x31bf }, +/* 0x31c0 */ { false, 0x31c0, 0x31c0 }, +/* 0x31c1 */ { false, 0x31c1, 0x31c1 }, +/* 0x31c2 */ { false, 0x31c2, 0x31c2 }, +/* 0x31c3 */ { false, 0x31c3, 0x31c3 }, +/* 0x31c4 */ { false, 0x31c4, 0x31c4 }, +/* 0x31c5 */ { false, 0x31c5, 0x31c5 }, +/* 0x31c6 */ { false, 0x31c6, 0x31c6 }, +/* 0x31c7 */ { false, 0x31c7, 0x31c7 }, +/* 0x31c8 */ { false, 0x31c8, 0x31c8 }, +/* 0x31c9 */ { false, 0x31c9, 0x31c9 }, +/* 0x31ca */ { false, 0x31ca, 0x31ca }, +/* 0x31cb */ { false, 0x31cb, 0x31cb }, +/* 0x31cc */ { false, 0x31cc, 0x31cc }, +/* 0x31cd */ { false, 0x31cd, 0x31cd }, +/* 0x31ce */ { false, 0x31ce, 0x31ce }, +/* 0x31cf */ { false, 0x31cf, 0x31cf }, +/* 0x31d0 */ { false, 0x31d0, 0x31d0 }, +/* 0x31d1 */ { false, 0x31d1, 0x31d1 }, +/* 0x31d2 */ { false, 0x31d2, 0x31d2 }, +/* 0x31d3 */ { false, 0x31d3, 0x31d3 }, +/* 0x31d4 */ { false, 0x31d4, 0x31d4 }, +/* 0x31d5 */ { false, 0x31d5, 0x31d5 }, +/* 0x31d6 */ { false, 0x31d6, 0x31d6 }, +/* 0x31d7 */ { false, 0x31d7, 0x31d7 }, +/* 0x31d8 */ { false, 0x31d8, 0x31d8 }, +/* 0x31d9 */ { false, 0x31d9, 0x31d9 }, +/* 0x31da */ { false, 0x31da, 0x31da }, +/* 0x31db */ { false, 0x31db, 0x31db }, +/* 0x31dc */ { false, 0x31dc, 0x31dc }, +/* 0x31dd */ { false, 0x31dd, 0x31dd }, +/* 0x31de */ { false, 0x31de, 0x31de }, +/* 0x31df */ { false, 0x31df, 0x31df }, +/* 0x31e0 */ { false, 0x31e0, 0x31e0 }, +/* 0x31e1 */ { false, 0x31e1, 0x31e1 }, +/* 0x31e2 */ { false, 0x31e2, 0x31e2 }, +/* 0x31e3 */ { false, 0x31e3, 0x31e3 }, +/* 0x31e4 */ { false, 0x31e4, 0x31e4 }, +/* 0x31e5 */ { false, 0x31e5, 0x31e5 }, +/* 0x31e6 */ { false, 0x31e6, 0x31e6 }, +/* 0x31e7 */ { false, 0x31e7, 0x31e7 }, +/* 0x31e8 */ { false, 0x31e8, 0x31e8 }, +/* 0x31e9 */ { false, 0x31e9, 0x31e9 }, +/* 0x31ea */ { false, 0x31ea, 0x31ea }, +/* 0x31eb */ { false, 0x31eb, 0x31eb }, +/* 0x31ec */ { false, 0x31ec, 0x31ec }, +/* 0x31ed */ { false, 0x31ed, 0x31ed }, +/* 0x31ee */ { false, 0x31ee, 0x31ee }, +/* 0x31ef */ { false, 0x31ef, 0x31ef }, +/* 0x31f0 */ { true, 0x31f0, 0x31f0 }, +/* 0x31f1 */ { true, 0x31f1, 0x31f1 }, +/* 0x31f2 */ { true, 0x31f2, 0x31f2 }, +/* 0x31f3 */ { true, 0x31f3, 0x31f3 }, +/* 0x31f4 */ { true, 0x31f4, 0x31f4 }, +/* 0x31f5 */ { true, 0x31f5, 0x31f5 }, +/* 0x31f6 */ { true, 0x31f6, 0x31f6 }, +/* 0x31f7 */ { true, 0x31f7, 0x31f7 }, +/* 0x31f8 */ { true, 0x31f8, 0x31f8 }, +/* 0x31f9 */ { true, 0x31f9, 0x31f9 }, +/* 0x31fa */ { true, 0x31fa, 0x31fa }, +/* 0x31fb */ { true, 0x31fb, 0x31fb }, +/* 0x31fc */ { true, 0x31fc, 0x31fc }, +/* 0x31fd */ { true, 0x31fd, 0x31fd }, +/* 0x31fe */ { true, 0x31fe, 0x31fe }, +/* 0x31ff */ { true, 0x31ff, 0x31ff }, +/* 0x3200 */ { false, 0x3200, 0x3200 }, +/* 0x3201 */ { false, 0x3201, 0x3201 }, +/* 0x3202 */ { false, 0x3202, 0x3202 }, +/* 0x3203 */ { false, 0x3203, 0x3203 }, +/* 0x3204 */ { false, 0x3204, 0x3204 }, +/* 0x3205 */ { false, 0x3205, 0x3205 }, +/* 0x3206 */ { false, 0x3206, 0x3206 }, +/* 0x3207 */ { false, 0x3207, 0x3207 }, +/* 0x3208 */ { false, 0x3208, 0x3208 }, +/* 0x3209 */ { false, 0x3209, 0x3209 }, +/* 0x320a */ { false, 0x320a, 0x320a }, +/* 0x320b */ { false, 0x320b, 0x320b }, +/* 0x320c */ { false, 0x320c, 0x320c }, +/* 0x320d */ { false, 0x320d, 0x320d }, +/* 0x320e */ { false, 0x320e, 0x320e }, +/* 0x320f */ { false, 0x320f, 0x320f }, +/* 0x3210 */ { false, 0x3210, 0x3210 }, +/* 0x3211 */ { false, 0x3211, 0x3211 }, +/* 0x3212 */ { false, 0x3212, 0x3212 }, +/* 0x3213 */ { false, 0x3213, 0x3213 }, +/* 0x3214 */ { false, 0x3214, 0x3214 }, +/* 0x3215 */ { false, 0x3215, 0x3215 }, +/* 0x3216 */ { false, 0x3216, 0x3216 }, +/* 0x3217 */ { false, 0x3217, 0x3217 }, +/* 0x3218 */ { false, 0x3218, 0x3218 }, +/* 0x3219 */ { false, 0x3219, 0x3219 }, +/* 0x321a */ { false, 0x321a, 0x321a }, +/* 0x321b */ { false, 0x321b, 0x321b }, +/* 0x321c */ { false, 0x321c, 0x321c }, +/* 0x321d */ { false, 0x321d, 0x321d }, +/* 0x321e */ { false, 0x321e, 0x321e }, +/* 0x321f */ { false, 0x321f, 0x321f }, +/* 0x3220 */ { false, 0x3220, 0x3220 }, +/* 0x3221 */ { false, 0x3221, 0x3221 }, +/* 0x3222 */ { false, 0x3222, 0x3222 }, +/* 0x3223 */ { false, 0x3223, 0x3223 }, +/* 0x3224 */ { false, 0x3224, 0x3224 }, +/* 0x3225 */ { false, 0x3225, 0x3225 }, +/* 0x3226 */ { false, 0x3226, 0x3226 }, +/* 0x3227 */ { false, 0x3227, 0x3227 }, +/* 0x3228 */ { false, 0x3228, 0x3228 }, +/* 0x3229 */ { false, 0x3229, 0x3229 }, +/* 0x322a */ { false, 0x322a, 0x322a }, +/* 0x322b */ { false, 0x322b, 0x322b }, +/* 0x322c */ { false, 0x322c, 0x322c }, +/* 0x322d */ { false, 0x322d, 0x322d }, +/* 0x322e */ { false, 0x322e, 0x322e }, +/* 0x322f */ { false, 0x322f, 0x322f }, +/* 0x3230 */ { false, 0x3230, 0x3230 }, +/* 0x3231 */ { false, 0x3231, 0x3231 }, +/* 0x3232 */ { false, 0x3232, 0x3232 }, +/* 0x3233 */ { false, 0x3233, 0x3233 }, +/* 0x3234 */ { false, 0x3234, 0x3234 }, +/* 0x3235 */ { false, 0x3235, 0x3235 }, +/* 0x3236 */ { false, 0x3236, 0x3236 }, +/* 0x3237 */ { false, 0x3237, 0x3237 }, +/* 0x3238 */ { false, 0x3238, 0x3238 }, +/* 0x3239 */ { false, 0x3239, 0x3239 }, +/* 0x323a */ { false, 0x323a, 0x323a }, +/* 0x323b */ { false, 0x323b, 0x323b }, +/* 0x323c */ { false, 0x323c, 0x323c }, +/* 0x323d */ { false, 0x323d, 0x323d }, +/* 0x323e */ { false, 0x323e, 0x323e }, +/* 0x323f */ { false, 0x323f, 0x323f }, +/* 0x3240 */ { false, 0x3240, 0x3240 }, +/* 0x3241 */ { false, 0x3241, 0x3241 }, +/* 0x3242 */ { false, 0x3242, 0x3242 }, +/* 0x3243 */ { false, 0x3243, 0x3243 }, +/* 0x3244 */ { false, 0x3244, 0x3244 }, +/* 0x3245 */ { false, 0x3245, 0x3245 }, +/* 0x3246 */ { false, 0x3246, 0x3246 }, +/* 0x3247 */ { false, 0x3247, 0x3247 }, +/* 0x3248 */ { false, 0x3248, 0x3248 }, +/* 0x3249 */ { false, 0x3249, 0x3249 }, +/* 0x324a */ { false, 0x324a, 0x324a }, +/* 0x324b */ { false, 0x324b, 0x324b }, +/* 0x324c */ { false, 0x324c, 0x324c }, +/* 0x324d */ { false, 0x324d, 0x324d }, +/* 0x324e */ { false, 0x324e, 0x324e }, +/* 0x324f */ { false, 0x324f, 0x324f }, +/* 0x3250 */ { false, 0x3250, 0x3250 }, +/* 0x3251 */ { false, 0x3251, 0x3251 }, +/* 0x3252 */ { false, 0x3252, 0x3252 }, +/* 0x3253 */ { false, 0x3253, 0x3253 }, +/* 0x3254 */ { false, 0x3254, 0x3254 }, +/* 0x3255 */ { false, 0x3255, 0x3255 }, +/* 0x3256 */ { false, 0x3256, 0x3256 }, +/* 0x3257 */ { false, 0x3257, 0x3257 }, +/* 0x3258 */ { false, 0x3258, 0x3258 }, +/* 0x3259 */ { false, 0x3259, 0x3259 }, +/* 0x325a */ { false, 0x325a, 0x325a }, +/* 0x325b */ { false, 0x325b, 0x325b }, +/* 0x325c */ { false, 0x325c, 0x325c }, +/* 0x325d */ { false, 0x325d, 0x325d }, +/* 0x325e */ { false, 0x325e, 0x325e }, +/* 0x325f */ { false, 0x325f, 0x325f }, +/* 0x3260 */ { false, 0x3260, 0x3260 }, +/* 0x3261 */ { false, 0x3261, 0x3261 }, +/* 0x3262 */ { false, 0x3262, 0x3262 }, +/* 0x3263 */ { false, 0x3263, 0x3263 }, +/* 0x3264 */ { false, 0x3264, 0x3264 }, +/* 0x3265 */ { false, 0x3265, 0x3265 }, +/* 0x3266 */ { false, 0x3266, 0x3266 }, +/* 0x3267 */ { false, 0x3267, 0x3267 }, +/* 0x3268 */ { false, 0x3268, 0x3268 }, +/* 0x3269 */ { false, 0x3269, 0x3269 }, +/* 0x326a */ { false, 0x326a, 0x326a }, +/* 0x326b */ { false, 0x326b, 0x326b }, +/* 0x326c */ { false, 0x326c, 0x326c }, +/* 0x326d */ { false, 0x326d, 0x326d }, +/* 0x326e */ { false, 0x326e, 0x326e }, +/* 0x326f */ { false, 0x326f, 0x326f }, +/* 0x3270 */ { false, 0x3270, 0x3270 }, +/* 0x3271 */ { false, 0x3271, 0x3271 }, +/* 0x3272 */ { false, 0x3272, 0x3272 }, +/* 0x3273 */ { false, 0x3273, 0x3273 }, +/* 0x3274 */ { false, 0x3274, 0x3274 }, +/* 0x3275 */ { false, 0x3275, 0x3275 }, +/* 0x3276 */ { false, 0x3276, 0x3276 }, +/* 0x3277 */ { false, 0x3277, 0x3277 }, +/* 0x3278 */ { false, 0x3278, 0x3278 }, +/* 0x3279 */ { false, 0x3279, 0x3279 }, +/* 0x327a */ { false, 0x327a, 0x327a }, +/* 0x327b */ { false, 0x327b, 0x327b }, +/* 0x327c */ { false, 0x327c, 0x327c }, +/* 0x327d */ { false, 0x327d, 0x327d }, +/* 0x327e */ { false, 0x327e, 0x327e }, +/* 0x327f */ { false, 0x327f, 0x327f }, +/* 0x3280 */ { false, 0x3280, 0x3280 }, +/* 0x3281 */ { false, 0x3281, 0x3281 }, +/* 0x3282 */ { false, 0x3282, 0x3282 }, +/* 0x3283 */ { false, 0x3283, 0x3283 }, +/* 0x3284 */ { false, 0x3284, 0x3284 }, +/* 0x3285 */ { false, 0x3285, 0x3285 }, +/* 0x3286 */ { false, 0x3286, 0x3286 }, +/* 0x3287 */ { false, 0x3287, 0x3287 }, +/* 0x3288 */ { false, 0x3288, 0x3288 }, +/* 0x3289 */ { false, 0x3289, 0x3289 }, +/* 0x328a */ { false, 0x328a, 0x328a }, +/* 0x328b */ { false, 0x328b, 0x328b }, +/* 0x328c */ { false, 0x328c, 0x328c }, +/* 0x328d */ { false, 0x328d, 0x328d }, +/* 0x328e */ { false, 0x328e, 0x328e }, +/* 0x328f */ { false, 0x328f, 0x328f }, +/* 0x3290 */ { false, 0x3290, 0x3290 }, +/* 0x3291 */ { false, 0x3291, 0x3291 }, +/* 0x3292 */ { false, 0x3292, 0x3292 }, +/* 0x3293 */ { false, 0x3293, 0x3293 }, +/* 0x3294 */ { false, 0x3294, 0x3294 }, +/* 0x3295 */ { false, 0x3295, 0x3295 }, +/* 0x3296 */ { false, 0x3296, 0x3296 }, +/* 0x3297 */ { false, 0x3297, 0x3297 }, +/* 0x3298 */ { false, 0x3298, 0x3298 }, +/* 0x3299 */ { false, 0x3299, 0x3299 }, +/* 0x329a */ { false, 0x329a, 0x329a }, +/* 0x329b */ { false, 0x329b, 0x329b }, +/* 0x329c */ { false, 0x329c, 0x329c }, +/* 0x329d */ { false, 0x329d, 0x329d }, +/* 0x329e */ { false, 0x329e, 0x329e }, +/* 0x329f */ { false, 0x329f, 0x329f }, +/* 0x32a0 */ { false, 0x32a0, 0x32a0 }, +/* 0x32a1 */ { false, 0x32a1, 0x32a1 }, +/* 0x32a2 */ { false, 0x32a2, 0x32a2 }, +/* 0x32a3 */ { false, 0x32a3, 0x32a3 }, +/* 0x32a4 */ { false, 0x32a4, 0x32a4 }, +/* 0x32a5 */ { false, 0x32a5, 0x32a5 }, +/* 0x32a6 */ { false, 0x32a6, 0x32a6 }, +/* 0x32a7 */ { false, 0x32a7, 0x32a7 }, +/* 0x32a8 */ { false, 0x32a8, 0x32a8 }, +/* 0x32a9 */ { false, 0x32a9, 0x32a9 }, +/* 0x32aa */ { false, 0x32aa, 0x32aa }, +/* 0x32ab */ { false, 0x32ab, 0x32ab }, +/* 0x32ac */ { false, 0x32ac, 0x32ac }, +/* 0x32ad */ { false, 0x32ad, 0x32ad }, +/* 0x32ae */ { false, 0x32ae, 0x32ae }, +/* 0x32af */ { false, 0x32af, 0x32af }, +/* 0x32b0 */ { false, 0x32b0, 0x32b0 }, +/* 0x32b1 */ { false, 0x32b1, 0x32b1 }, +/* 0x32b2 */ { false, 0x32b2, 0x32b2 }, +/* 0x32b3 */ { false, 0x32b3, 0x32b3 }, +/* 0x32b4 */ { false, 0x32b4, 0x32b4 }, +/* 0x32b5 */ { false, 0x32b5, 0x32b5 }, +/* 0x32b6 */ { false, 0x32b6, 0x32b6 }, +/* 0x32b7 */ { false, 0x32b7, 0x32b7 }, +/* 0x32b8 */ { false, 0x32b8, 0x32b8 }, +/* 0x32b9 */ { false, 0x32b9, 0x32b9 }, +/* 0x32ba */ { false, 0x32ba, 0x32ba }, +/* 0x32bb */ { false, 0x32bb, 0x32bb }, +/* 0x32bc */ { false, 0x32bc, 0x32bc }, +/* 0x32bd */ { false, 0x32bd, 0x32bd }, +/* 0x32be */ { false, 0x32be, 0x32be }, +/* 0x32bf */ { false, 0x32bf, 0x32bf }, +/* 0x32c0 */ { false, 0x32c0, 0x32c0 }, +/* 0x32c1 */ { false, 0x32c1, 0x32c1 }, +/* 0x32c2 */ { false, 0x32c2, 0x32c2 }, +/* 0x32c3 */ { false, 0x32c3, 0x32c3 }, +/* 0x32c4 */ { false, 0x32c4, 0x32c4 }, +/* 0x32c5 */ { false, 0x32c5, 0x32c5 }, +/* 0x32c6 */ { false, 0x32c6, 0x32c6 }, +/* 0x32c7 */ { false, 0x32c7, 0x32c7 }, +/* 0x32c8 */ { false, 0x32c8, 0x32c8 }, +/* 0x32c9 */ { false, 0x32c9, 0x32c9 }, +/* 0x32ca */ { false, 0x32ca, 0x32ca }, +/* 0x32cb */ { false, 0x32cb, 0x32cb }, +/* 0x32cc */ { false, 0x32cc, 0x32cc }, +/* 0x32cd */ { false, 0x32cd, 0x32cd }, +/* 0x32ce */ { false, 0x32ce, 0x32ce }, +/* 0x32cf */ { false, 0x32cf, 0x32cf }, +/* 0x32d0 */ { false, 0x32d0, 0x32d0 }, +/* 0x32d1 */ { false, 0x32d1, 0x32d1 }, +/* 0x32d2 */ { false, 0x32d2, 0x32d2 }, +/* 0x32d3 */ { false, 0x32d3, 0x32d3 }, +/* 0x32d4 */ { false, 0x32d4, 0x32d4 }, +/* 0x32d5 */ { false, 0x32d5, 0x32d5 }, +/* 0x32d6 */ { false, 0x32d6, 0x32d6 }, +/* 0x32d7 */ { false, 0x32d7, 0x32d7 }, +/* 0x32d8 */ { false, 0x32d8, 0x32d8 }, +/* 0x32d9 */ { false, 0x32d9, 0x32d9 }, +/* 0x32da */ { false, 0x32da, 0x32da }, +/* 0x32db */ { false, 0x32db, 0x32db }, +/* 0x32dc */ { false, 0x32dc, 0x32dc }, +/* 0x32dd */ { false, 0x32dd, 0x32dd }, +/* 0x32de */ { false, 0x32de, 0x32de }, +/* 0x32df */ { false, 0x32df, 0x32df }, +/* 0x32e0 */ { false, 0x32e0, 0x32e0 }, +/* 0x32e1 */ { false, 0x32e1, 0x32e1 }, +/* 0x32e2 */ { false, 0x32e2, 0x32e2 }, +/* 0x32e3 */ { false, 0x32e3, 0x32e3 }, +/* 0x32e4 */ { false, 0x32e4, 0x32e4 }, +/* 0x32e5 */ { false, 0x32e5, 0x32e5 }, +/* 0x32e6 */ { false, 0x32e6, 0x32e6 }, +/* 0x32e7 */ { false, 0x32e7, 0x32e7 }, +/* 0x32e8 */ { false, 0x32e8, 0x32e8 }, +/* 0x32e9 */ { false, 0x32e9, 0x32e9 }, +/* 0x32ea */ { false, 0x32ea, 0x32ea }, +/* 0x32eb */ { false, 0x32eb, 0x32eb }, +/* 0x32ec */ { false, 0x32ec, 0x32ec }, +/* 0x32ed */ { false, 0x32ed, 0x32ed }, +/* 0x32ee */ { false, 0x32ee, 0x32ee }, +/* 0x32ef */ { false, 0x32ef, 0x32ef }, +/* 0x32f0 */ { false, 0x32f0, 0x32f0 }, +/* 0x32f1 */ { false, 0x32f1, 0x32f1 }, +/* 0x32f2 */ { false, 0x32f2, 0x32f2 }, +/* 0x32f3 */ { false, 0x32f3, 0x32f3 }, +/* 0x32f4 */ { false, 0x32f4, 0x32f4 }, +/* 0x32f5 */ { false, 0x32f5, 0x32f5 }, +/* 0x32f6 */ { false, 0x32f6, 0x32f6 }, +/* 0x32f7 */ { false, 0x32f7, 0x32f7 }, +/* 0x32f8 */ { false, 0x32f8, 0x32f8 }, +/* 0x32f9 */ { false, 0x32f9, 0x32f9 }, +/* 0x32fa */ { false, 0x32fa, 0x32fa }, +/* 0x32fb */ { false, 0x32fb, 0x32fb }, +/* 0x32fc */ { false, 0x32fc, 0x32fc }, +/* 0x32fd */ { false, 0x32fd, 0x32fd }, +/* 0x32fe */ { false, 0x32fe, 0x32fe }, +/* 0x32ff */ { false, 0x32ff, 0x32ff }, +/* 0x3300 */ { false, 0x3300, 0x3300 }, +/* 0x3301 */ { false, 0x3301, 0x3301 }, +/* 0x3302 */ { false, 0x3302, 0x3302 }, +/* 0x3303 */ { false, 0x3303, 0x3303 }, +/* 0x3304 */ { false, 0x3304, 0x3304 }, +/* 0x3305 */ { false, 0x3305, 0x3305 }, +/* 0x3306 */ { false, 0x3306, 0x3306 }, +/* 0x3307 */ { false, 0x3307, 0x3307 }, +/* 0x3308 */ { false, 0x3308, 0x3308 }, +/* 0x3309 */ { false, 0x3309, 0x3309 }, +/* 0x330a */ { false, 0x330a, 0x330a }, +/* 0x330b */ { false, 0x330b, 0x330b }, +/* 0x330c */ { false, 0x330c, 0x330c }, +/* 0x330d */ { false, 0x330d, 0x330d }, +/* 0x330e */ { false, 0x330e, 0x330e }, +/* 0x330f */ { false, 0x330f, 0x330f }, +/* 0x3310 */ { false, 0x3310, 0x3310 }, +/* 0x3311 */ { false, 0x3311, 0x3311 }, +/* 0x3312 */ { false, 0x3312, 0x3312 }, +/* 0x3313 */ { false, 0x3313, 0x3313 }, +/* 0x3314 */ { false, 0x3314, 0x3314 }, +/* 0x3315 */ { false, 0x3315, 0x3315 }, +/* 0x3316 */ { false, 0x3316, 0x3316 }, +/* 0x3317 */ { false, 0x3317, 0x3317 }, +/* 0x3318 */ { false, 0x3318, 0x3318 }, +/* 0x3319 */ { false, 0x3319, 0x3319 }, +/* 0x331a */ { false, 0x331a, 0x331a }, +/* 0x331b */ { false, 0x331b, 0x331b }, +/* 0x331c */ { false, 0x331c, 0x331c }, +/* 0x331d */ { false, 0x331d, 0x331d }, +/* 0x331e */ { false, 0x331e, 0x331e }, +/* 0x331f */ { false, 0x331f, 0x331f }, +/* 0x3320 */ { false, 0x3320, 0x3320 }, +/* 0x3321 */ { false, 0x3321, 0x3321 }, +/* 0x3322 */ { false, 0x3322, 0x3322 }, +/* 0x3323 */ { false, 0x3323, 0x3323 }, +/* 0x3324 */ { false, 0x3324, 0x3324 }, +/* 0x3325 */ { false, 0x3325, 0x3325 }, +/* 0x3326 */ { false, 0x3326, 0x3326 }, +/* 0x3327 */ { false, 0x3327, 0x3327 }, +/* 0x3328 */ { false, 0x3328, 0x3328 }, +/* 0x3329 */ { false, 0x3329, 0x3329 }, +/* 0x332a */ { false, 0x332a, 0x332a }, +/* 0x332b */ { false, 0x332b, 0x332b }, +/* 0x332c */ { false, 0x332c, 0x332c }, +/* 0x332d */ { false, 0x332d, 0x332d }, +/* 0x332e */ { false, 0x332e, 0x332e }, +/* 0x332f */ { false, 0x332f, 0x332f }, +/* 0x3330 */ { false, 0x3330, 0x3330 }, +/* 0x3331 */ { false, 0x3331, 0x3331 }, +/* 0x3332 */ { false, 0x3332, 0x3332 }, +/* 0x3333 */ { false, 0x3333, 0x3333 }, +/* 0x3334 */ { false, 0x3334, 0x3334 }, +/* 0x3335 */ { false, 0x3335, 0x3335 }, +/* 0x3336 */ { false, 0x3336, 0x3336 }, +/* 0x3337 */ { false, 0x3337, 0x3337 }, +/* 0x3338 */ { false, 0x3338, 0x3338 }, +/* 0x3339 */ { false, 0x3339, 0x3339 }, +/* 0x333a */ { false, 0x333a, 0x333a }, +/* 0x333b */ { false, 0x333b, 0x333b }, +/* 0x333c */ { false, 0x333c, 0x333c }, +/* 0x333d */ { false, 0x333d, 0x333d }, +/* 0x333e */ { false, 0x333e, 0x333e }, +/* 0x333f */ { false, 0x333f, 0x333f }, +/* 0x3340 */ { false, 0x3340, 0x3340 }, +/* 0x3341 */ { false, 0x3341, 0x3341 }, +/* 0x3342 */ { false, 0x3342, 0x3342 }, +/* 0x3343 */ { false, 0x3343, 0x3343 }, +/* 0x3344 */ { false, 0x3344, 0x3344 }, +/* 0x3345 */ { false, 0x3345, 0x3345 }, +/* 0x3346 */ { false, 0x3346, 0x3346 }, +/* 0x3347 */ { false, 0x3347, 0x3347 }, +/* 0x3348 */ { false, 0x3348, 0x3348 }, +/* 0x3349 */ { false, 0x3349, 0x3349 }, +/* 0x334a */ { false, 0x334a, 0x334a }, +/* 0x334b */ { false, 0x334b, 0x334b }, +/* 0x334c */ { false, 0x334c, 0x334c }, +/* 0x334d */ { false, 0x334d, 0x334d }, +/* 0x334e */ { false, 0x334e, 0x334e }, +/* 0x334f */ { false, 0x334f, 0x334f }, +/* 0x3350 */ { false, 0x3350, 0x3350 }, +/* 0x3351 */ { false, 0x3351, 0x3351 }, +/* 0x3352 */ { false, 0x3352, 0x3352 }, +/* 0x3353 */ { false, 0x3353, 0x3353 }, +/* 0x3354 */ { false, 0x3354, 0x3354 }, +/* 0x3355 */ { false, 0x3355, 0x3355 }, +/* 0x3356 */ { false, 0x3356, 0x3356 }, +/* 0x3357 */ { false, 0x3357, 0x3357 }, +/* 0x3358 */ { false, 0x3358, 0x3358 }, +/* 0x3359 */ { false, 0x3359, 0x3359 }, +/* 0x335a */ { false, 0x335a, 0x335a }, +/* 0x335b */ { false, 0x335b, 0x335b }, +/* 0x335c */ { false, 0x335c, 0x335c }, +/* 0x335d */ { false, 0x335d, 0x335d }, +/* 0x335e */ { false, 0x335e, 0x335e }, +/* 0x335f */ { false, 0x335f, 0x335f }, +/* 0x3360 */ { false, 0x3360, 0x3360 }, +/* 0x3361 */ { false, 0x3361, 0x3361 }, +/* 0x3362 */ { false, 0x3362, 0x3362 }, +/* 0x3363 */ { false, 0x3363, 0x3363 }, +/* 0x3364 */ { false, 0x3364, 0x3364 }, +/* 0x3365 */ { false, 0x3365, 0x3365 }, +/* 0x3366 */ { false, 0x3366, 0x3366 }, +/* 0x3367 */ { false, 0x3367, 0x3367 }, +/* 0x3368 */ { false, 0x3368, 0x3368 }, +/* 0x3369 */ { false, 0x3369, 0x3369 }, +/* 0x336a */ { false, 0x336a, 0x336a }, +/* 0x336b */ { false, 0x336b, 0x336b }, +/* 0x336c */ { false, 0x336c, 0x336c }, +/* 0x336d */ { false, 0x336d, 0x336d }, +/* 0x336e */ { false, 0x336e, 0x336e }, +/* 0x336f */ { false, 0x336f, 0x336f }, +/* 0x3370 */ { false, 0x3370, 0x3370 }, +/* 0x3371 */ { false, 0x3371, 0x3371 }, +/* 0x3372 */ { false, 0x3372, 0x3372 }, +/* 0x3373 */ { false, 0x3373, 0x3373 }, +/* 0x3374 */ { false, 0x3374, 0x3374 }, +/* 0x3375 */ { false, 0x3375, 0x3375 }, +/* 0x3376 */ { false, 0x3376, 0x3376 }, +/* 0x3377 */ { false, 0x3377, 0x3377 }, +/* 0x3378 */ { false, 0x3378, 0x3378 }, +/* 0x3379 */ { false, 0x3379, 0x3379 }, +/* 0x337a */ { false, 0x337a, 0x337a }, +/* 0x337b */ { false, 0x337b, 0x337b }, +/* 0x337c */ { false, 0x337c, 0x337c }, +/* 0x337d */ { false, 0x337d, 0x337d }, +/* 0x337e */ { false, 0x337e, 0x337e }, +/* 0x337f */ { false, 0x337f, 0x337f }, +/* 0x3380 */ { false, 0x3380, 0x3380 }, +/* 0x3381 */ { false, 0x3381, 0x3381 }, +/* 0x3382 */ { false, 0x3382, 0x3382 }, +/* 0x3383 */ { false, 0x3383, 0x3383 }, +/* 0x3384 */ { false, 0x3384, 0x3384 }, +/* 0x3385 */ { false, 0x3385, 0x3385 }, +/* 0x3386 */ { false, 0x3386, 0x3386 }, +/* 0x3387 */ { false, 0x3387, 0x3387 }, +/* 0x3388 */ { false, 0x3388, 0x3388 }, +/* 0x3389 */ { false, 0x3389, 0x3389 }, +/* 0x338a */ { false, 0x338a, 0x338a }, +/* 0x338b */ { false, 0x338b, 0x338b }, +/* 0x338c */ { false, 0x338c, 0x338c }, +/* 0x338d */ { false, 0x338d, 0x338d }, +/* 0x338e */ { false, 0x338e, 0x338e }, +/* 0x338f */ { false, 0x338f, 0x338f }, +/* 0x3390 */ { false, 0x3390, 0x3390 }, +/* 0x3391 */ { false, 0x3391, 0x3391 }, +/* 0x3392 */ { false, 0x3392, 0x3392 }, +/* 0x3393 */ { false, 0x3393, 0x3393 }, +/* 0x3394 */ { false, 0x3394, 0x3394 }, +/* 0x3395 */ { false, 0x3395, 0x3395 }, +/* 0x3396 */ { false, 0x3396, 0x3396 }, +/* 0x3397 */ { false, 0x3397, 0x3397 }, +/* 0x3398 */ { false, 0x3398, 0x3398 }, +/* 0x3399 */ { false, 0x3399, 0x3399 }, +/* 0x339a */ { false, 0x339a, 0x339a }, +/* 0x339b */ { false, 0x339b, 0x339b }, +/* 0x339c */ { false, 0x339c, 0x339c }, +/* 0x339d */ { false, 0x339d, 0x339d }, +/* 0x339e */ { false, 0x339e, 0x339e }, +/* 0x339f */ { false, 0x339f, 0x339f }, +/* 0x33a0 */ { false, 0x33a0, 0x33a0 }, +/* 0x33a1 */ { false, 0x33a1, 0x33a1 }, +/* 0x33a2 */ { false, 0x33a2, 0x33a2 }, +/* 0x33a3 */ { false, 0x33a3, 0x33a3 }, +/* 0x33a4 */ { false, 0x33a4, 0x33a4 }, +/* 0x33a5 */ { false, 0x33a5, 0x33a5 }, +/* 0x33a6 */ { false, 0x33a6, 0x33a6 }, +/* 0x33a7 */ { false, 0x33a7, 0x33a7 }, +/* 0x33a8 */ { false, 0x33a8, 0x33a8 }, +/* 0x33a9 */ { false, 0x33a9, 0x33a9 }, +/* 0x33aa */ { false, 0x33aa, 0x33aa }, +/* 0x33ab */ { false, 0x33ab, 0x33ab }, +/* 0x33ac */ { false, 0x33ac, 0x33ac }, +/* 0x33ad */ { false, 0x33ad, 0x33ad }, +/* 0x33ae */ { false, 0x33ae, 0x33ae }, +/* 0x33af */ { false, 0x33af, 0x33af }, +/* 0x33b0 */ { false, 0x33b0, 0x33b0 }, +/* 0x33b1 */ { false, 0x33b1, 0x33b1 }, +/* 0x33b2 */ { false, 0x33b2, 0x33b2 }, +/* 0x33b3 */ { false, 0x33b3, 0x33b3 }, +/* 0x33b4 */ { false, 0x33b4, 0x33b4 }, +/* 0x33b5 */ { false, 0x33b5, 0x33b5 }, +/* 0x33b6 */ { false, 0x33b6, 0x33b6 }, +/* 0x33b7 */ { false, 0x33b7, 0x33b7 }, +/* 0x33b8 */ { false, 0x33b8, 0x33b8 }, +/* 0x33b9 */ { false, 0x33b9, 0x33b9 }, +/* 0x33ba */ { false, 0x33ba, 0x33ba }, +/* 0x33bb */ { false, 0x33bb, 0x33bb }, +/* 0x33bc */ { false, 0x33bc, 0x33bc }, +/* 0x33bd */ { false, 0x33bd, 0x33bd }, +/* 0x33be */ { false, 0x33be, 0x33be }, +/* 0x33bf */ { false, 0x33bf, 0x33bf }, +/* 0x33c0 */ { false, 0x33c0, 0x33c0 }, +/* 0x33c1 */ { false, 0x33c1, 0x33c1 }, +/* 0x33c2 */ { false, 0x33c2, 0x33c2 }, +/* 0x33c3 */ { false, 0x33c3, 0x33c3 }, +/* 0x33c4 */ { false, 0x33c4, 0x33c4 }, +/* 0x33c5 */ { false, 0x33c5, 0x33c5 }, +/* 0x33c6 */ { false, 0x33c6, 0x33c6 }, +/* 0x33c7 */ { false, 0x33c7, 0x33c7 }, +/* 0x33c8 */ { false, 0x33c8, 0x33c8 }, +/* 0x33c9 */ { false, 0x33c9, 0x33c9 }, +/* 0x33ca */ { false, 0x33ca, 0x33ca }, +/* 0x33cb */ { false, 0x33cb, 0x33cb }, +/* 0x33cc */ { false, 0x33cc, 0x33cc }, +/* 0x33cd */ { false, 0x33cd, 0x33cd }, +/* 0x33ce */ { false, 0x33ce, 0x33ce }, +/* 0x33cf */ { false, 0x33cf, 0x33cf }, +/* 0x33d0 */ { false, 0x33d0, 0x33d0 }, +/* 0x33d1 */ { false, 0x33d1, 0x33d1 }, +/* 0x33d2 */ { false, 0x33d2, 0x33d2 }, +/* 0x33d3 */ { false, 0x33d3, 0x33d3 }, +/* 0x33d4 */ { false, 0x33d4, 0x33d4 }, +/* 0x33d5 */ { false, 0x33d5, 0x33d5 }, +/* 0x33d6 */ { false, 0x33d6, 0x33d6 }, +/* 0x33d7 */ { false, 0x33d7, 0x33d7 }, +/* 0x33d8 */ { false, 0x33d8, 0x33d8 }, +/* 0x33d9 */ { false, 0x33d9, 0x33d9 }, +/* 0x33da */ { false, 0x33da, 0x33da }, +/* 0x33db */ { false, 0x33db, 0x33db }, +/* 0x33dc */ { false, 0x33dc, 0x33dc }, +/* 0x33dd */ { false, 0x33dd, 0x33dd }, +/* 0x33de */ { false, 0x33de, 0x33de }, +/* 0x33df */ { false, 0x33df, 0x33df }, +/* 0x33e0 */ { false, 0x33e0, 0x33e0 }, +/* 0x33e1 */ { false, 0x33e1, 0x33e1 }, +/* 0x33e2 */ { false, 0x33e2, 0x33e2 }, +/* 0x33e3 */ { false, 0x33e3, 0x33e3 }, +/* 0x33e4 */ { false, 0x33e4, 0x33e4 }, +/* 0x33e5 */ { false, 0x33e5, 0x33e5 }, +/* 0x33e6 */ { false, 0x33e6, 0x33e6 }, +/* 0x33e7 */ { false, 0x33e7, 0x33e7 }, +/* 0x33e8 */ { false, 0x33e8, 0x33e8 }, +/* 0x33e9 */ { false, 0x33e9, 0x33e9 }, +/* 0x33ea */ { false, 0x33ea, 0x33ea }, +/* 0x33eb */ { false, 0x33eb, 0x33eb }, +/* 0x33ec */ { false, 0x33ec, 0x33ec }, +/* 0x33ed */ { false, 0x33ed, 0x33ed }, +/* 0x33ee */ { false, 0x33ee, 0x33ee }, +/* 0x33ef */ { false, 0x33ef, 0x33ef }, +/* 0x33f0 */ { false, 0x33f0, 0x33f0 }, +/* 0x33f1 */ { false, 0x33f1, 0x33f1 }, +/* 0x33f2 */ { false, 0x33f2, 0x33f2 }, +/* 0x33f3 */ { false, 0x33f3, 0x33f3 }, +/* 0x33f4 */ { false, 0x33f4, 0x33f4 }, +/* 0x33f5 */ { false, 0x33f5, 0x33f5 }, +/* 0x33f6 */ { false, 0x33f6, 0x33f6 }, +/* 0x33f7 */ { false, 0x33f7, 0x33f7 }, +/* 0x33f8 */ { false, 0x33f8, 0x33f8 }, +/* 0x33f9 */ { false, 0x33f9, 0x33f9 }, +/* 0x33fa */ { false, 0x33fa, 0x33fa }, +/* 0x33fb */ { false, 0x33fb, 0x33fb }, +/* 0x33fc */ { false, 0x33fc, 0x33fc }, +/* 0x33fd */ { false, 0x33fd, 0x33fd }, +/* 0x33fe */ { false, 0x33fe, 0x33fe }, +/* 0x33ff */ { false, 0x33ff, 0x33ff }, +/* 0x3400 */ { true, 0x3400, 0x3400 }, +/* 0x3401 */ { false, 0x3401, 0x3401 }, +/* 0x3402 */ { false, 0x3402, 0x3402 }, +/* 0x3403 */ { false, 0x3403, 0x3403 }, +/* 0x3404 */ { false, 0x3404, 0x3404 }, +/* 0x3405 */ { false, 0x3405, 0x3405 }, +/* 0x3406 */ { false, 0x3406, 0x3406 }, +/* 0x3407 */ { false, 0x3407, 0x3407 }, +/* 0x3408 */ { false, 0x3408, 0x3408 }, +/* 0x3409 */ { false, 0x3409, 0x3409 }, +/* 0x340a */ { false, 0x340a, 0x340a }, +/* 0x340b */ { false, 0x340b, 0x340b }, +/* 0x340c */ { false, 0x340c, 0x340c }, +/* 0x340d */ { false, 0x340d, 0x340d }, +/* 0x340e */ { false, 0x340e, 0x340e }, +/* 0x340f */ { false, 0x340f, 0x340f }, +/* 0x3410 */ { false, 0x3410, 0x3410 }, +/* 0x3411 */ { false, 0x3411, 0x3411 }, +/* 0x3412 */ { false, 0x3412, 0x3412 }, +/* 0x3413 */ { false, 0x3413, 0x3413 }, +/* 0x3414 */ { false, 0x3414, 0x3414 }, +/* 0x3415 */ { false, 0x3415, 0x3415 }, +/* 0x3416 */ { false, 0x3416, 0x3416 }, +/* 0x3417 */ { false, 0x3417, 0x3417 }, +/* 0x3418 */ { false, 0x3418, 0x3418 }, +/* 0x3419 */ { false, 0x3419, 0x3419 }, +/* 0x341a */ { false, 0x341a, 0x341a }, +/* 0x341b */ { false, 0x341b, 0x341b }, +/* 0x341c */ { false, 0x341c, 0x341c }, +/* 0x341d */ { false, 0x341d, 0x341d }, +/* 0x341e */ { false, 0x341e, 0x341e }, +/* 0x341f */ { false, 0x341f, 0x341f }, +/* 0x3420 */ { false, 0x3420, 0x3420 }, +/* 0x3421 */ { false, 0x3421, 0x3421 }, +/* 0x3422 */ { false, 0x3422, 0x3422 }, +/* 0x3423 */ { false, 0x3423, 0x3423 }, +/* 0x3424 */ { false, 0x3424, 0x3424 }, +/* 0x3425 */ { false, 0x3425, 0x3425 }, +/* 0x3426 */ { false, 0x3426, 0x3426 }, +/* 0x3427 */ { false, 0x3427, 0x3427 }, +/* 0x3428 */ { false, 0x3428, 0x3428 }, +/* 0x3429 */ { false, 0x3429, 0x3429 }, +/* 0x342a */ { false, 0x342a, 0x342a }, +/* 0x342b */ { false, 0x342b, 0x342b }, +/* 0x342c */ { false, 0x342c, 0x342c }, +/* 0x342d */ { false, 0x342d, 0x342d }, +/* 0x342e */ { false, 0x342e, 0x342e }, +/* 0x342f */ { false, 0x342f, 0x342f }, +/* 0x3430 */ { false, 0x3430, 0x3430 }, +/* 0x3431 */ { false, 0x3431, 0x3431 }, +/* 0x3432 */ { false, 0x3432, 0x3432 }, +/* 0x3433 */ { false, 0x3433, 0x3433 }, +/* 0x3434 */ { false, 0x3434, 0x3434 }, +/* 0x3435 */ { false, 0x3435, 0x3435 }, +/* 0x3436 */ { false, 0x3436, 0x3436 }, +/* 0x3437 */ { false, 0x3437, 0x3437 }, +/* 0x3438 */ { false, 0x3438, 0x3438 }, +/* 0x3439 */ { false, 0x3439, 0x3439 }, +/* 0x343a */ { false, 0x343a, 0x343a }, +/* 0x343b */ { false, 0x343b, 0x343b }, +/* 0x343c */ { false, 0x343c, 0x343c }, +/* 0x343d */ { false, 0x343d, 0x343d }, +/* 0x343e */ { false, 0x343e, 0x343e }, +/* 0x343f */ { false, 0x343f, 0x343f }, +/* 0x3440 */ { false, 0x3440, 0x3440 }, +/* 0x3441 */ { false, 0x3441, 0x3441 }, +/* 0x3442 */ { false, 0x3442, 0x3442 }, +/* 0x3443 */ { false, 0x3443, 0x3443 }, +/* 0x3444 */ { false, 0x3444, 0x3444 }, +/* 0x3445 */ { false, 0x3445, 0x3445 }, +/* 0x3446 */ { false, 0x3446, 0x3446 }, +/* 0x3447 */ { false, 0x3447, 0x3447 }, +/* 0x3448 */ { false, 0x3448, 0x3448 }, +/* 0x3449 */ { false, 0x3449, 0x3449 }, +/* 0x344a */ { false, 0x344a, 0x344a }, +/* 0x344b */ { false, 0x344b, 0x344b }, +/* 0x344c */ { false, 0x344c, 0x344c }, +/* 0x344d */ { false, 0x344d, 0x344d }, +/* 0x344e */ { false, 0x344e, 0x344e }, +/* 0x344f */ { false, 0x344f, 0x344f }, +/* 0x3450 */ { false, 0x3450, 0x3450 }, +/* 0x3451 */ { false, 0x3451, 0x3451 }, +/* 0x3452 */ { false, 0x3452, 0x3452 }, +/* 0x3453 */ { false, 0x3453, 0x3453 }, +/* 0x3454 */ { false, 0x3454, 0x3454 }, +/* 0x3455 */ { false, 0x3455, 0x3455 }, +/* 0x3456 */ { false, 0x3456, 0x3456 }, +/* 0x3457 */ { false, 0x3457, 0x3457 }, +/* 0x3458 */ { false, 0x3458, 0x3458 }, +/* 0x3459 */ { false, 0x3459, 0x3459 }, +/* 0x345a */ { false, 0x345a, 0x345a }, +/* 0x345b */ { false, 0x345b, 0x345b }, +/* 0x345c */ { false, 0x345c, 0x345c }, +/* 0x345d */ { false, 0x345d, 0x345d }, +/* 0x345e */ { false, 0x345e, 0x345e }, +/* 0x345f */ { false, 0x345f, 0x345f }, +/* 0x3460 */ { false, 0x3460, 0x3460 }, +/* 0x3461 */ { false, 0x3461, 0x3461 }, +/* 0x3462 */ { false, 0x3462, 0x3462 }, +/* 0x3463 */ { false, 0x3463, 0x3463 }, +/* 0x3464 */ { false, 0x3464, 0x3464 }, +/* 0x3465 */ { false, 0x3465, 0x3465 }, +/* 0x3466 */ { false, 0x3466, 0x3466 }, +/* 0x3467 */ { false, 0x3467, 0x3467 }, +/* 0x3468 */ { false, 0x3468, 0x3468 }, +/* 0x3469 */ { false, 0x3469, 0x3469 }, +/* 0x346a */ { false, 0x346a, 0x346a }, +/* 0x346b */ { false, 0x346b, 0x346b }, +/* 0x346c */ { false, 0x346c, 0x346c }, +/* 0x346d */ { false, 0x346d, 0x346d }, +/* 0x346e */ { false, 0x346e, 0x346e }, +/* 0x346f */ { false, 0x346f, 0x346f }, +/* 0x3470 */ { false, 0x3470, 0x3470 }, +/* 0x3471 */ { false, 0x3471, 0x3471 }, +/* 0x3472 */ { false, 0x3472, 0x3472 }, +/* 0x3473 */ { false, 0x3473, 0x3473 }, +/* 0x3474 */ { false, 0x3474, 0x3474 }, +/* 0x3475 */ { false, 0x3475, 0x3475 }, +/* 0x3476 */ { false, 0x3476, 0x3476 }, +/* 0x3477 */ { false, 0x3477, 0x3477 }, +/* 0x3478 */ { false, 0x3478, 0x3478 }, +/* 0x3479 */ { false, 0x3479, 0x3479 }, +/* 0x347a */ { false, 0x347a, 0x347a }, +/* 0x347b */ { false, 0x347b, 0x347b }, +/* 0x347c */ { false, 0x347c, 0x347c }, +/* 0x347d */ { false, 0x347d, 0x347d }, +/* 0x347e */ { false, 0x347e, 0x347e }, +/* 0x347f */ { false, 0x347f, 0x347f }, +/* 0x3480 */ { false, 0x3480, 0x3480 }, +/* 0x3481 */ { false, 0x3481, 0x3481 }, +/* 0x3482 */ { false, 0x3482, 0x3482 }, +/* 0x3483 */ { false, 0x3483, 0x3483 }, +/* 0x3484 */ { false, 0x3484, 0x3484 }, +/* 0x3485 */ { false, 0x3485, 0x3485 }, +/* 0x3486 */ { false, 0x3486, 0x3486 }, +/* 0x3487 */ { false, 0x3487, 0x3487 }, +/* 0x3488 */ { false, 0x3488, 0x3488 }, +/* 0x3489 */ { false, 0x3489, 0x3489 }, +/* 0x348a */ { false, 0x348a, 0x348a }, +/* 0x348b */ { false, 0x348b, 0x348b }, +/* 0x348c */ { false, 0x348c, 0x348c }, +/* 0x348d */ { false, 0x348d, 0x348d }, +/* 0x348e */ { false, 0x348e, 0x348e }, +/* 0x348f */ { false, 0x348f, 0x348f }, +/* 0x3490 */ { false, 0x3490, 0x3490 }, +/* 0x3491 */ { false, 0x3491, 0x3491 }, +/* 0x3492 */ { false, 0x3492, 0x3492 }, +/* 0x3493 */ { false, 0x3493, 0x3493 }, +/* 0x3494 */ { false, 0x3494, 0x3494 }, +/* 0x3495 */ { false, 0x3495, 0x3495 }, +/* 0x3496 */ { false, 0x3496, 0x3496 }, +/* 0x3497 */ { false, 0x3497, 0x3497 }, +/* 0x3498 */ { false, 0x3498, 0x3498 }, +/* 0x3499 */ { false, 0x3499, 0x3499 }, +/* 0x349a */ { false, 0x349a, 0x349a }, +/* 0x349b */ { false, 0x349b, 0x349b }, +/* 0x349c */ { false, 0x349c, 0x349c }, +/* 0x349d */ { false, 0x349d, 0x349d }, +/* 0x349e */ { false, 0x349e, 0x349e }, +/* 0x349f */ { false, 0x349f, 0x349f }, +/* 0x34a0 */ { false, 0x34a0, 0x34a0 }, +/* 0x34a1 */ { false, 0x34a1, 0x34a1 }, +/* 0x34a2 */ { false, 0x34a2, 0x34a2 }, +/* 0x34a3 */ { false, 0x34a3, 0x34a3 }, +/* 0x34a4 */ { false, 0x34a4, 0x34a4 }, +/* 0x34a5 */ { false, 0x34a5, 0x34a5 }, +/* 0x34a6 */ { false, 0x34a6, 0x34a6 }, +/* 0x34a7 */ { false, 0x34a7, 0x34a7 }, +/* 0x34a8 */ { false, 0x34a8, 0x34a8 }, +/* 0x34a9 */ { false, 0x34a9, 0x34a9 }, +/* 0x34aa */ { false, 0x34aa, 0x34aa }, +/* 0x34ab */ { false, 0x34ab, 0x34ab }, +/* 0x34ac */ { false, 0x34ac, 0x34ac }, +/* 0x34ad */ { false, 0x34ad, 0x34ad }, +/* 0x34ae */ { false, 0x34ae, 0x34ae }, +/* 0x34af */ { false, 0x34af, 0x34af }, +/* 0x34b0 */ { false, 0x34b0, 0x34b0 }, +/* 0x34b1 */ { false, 0x34b1, 0x34b1 }, +/* 0x34b2 */ { false, 0x34b2, 0x34b2 }, +/* 0x34b3 */ { false, 0x34b3, 0x34b3 }, +/* 0x34b4 */ { false, 0x34b4, 0x34b4 }, +/* 0x34b5 */ { false, 0x34b5, 0x34b5 }, +/* 0x34b6 */ { false, 0x34b6, 0x34b6 }, +/* 0x34b7 */ { false, 0x34b7, 0x34b7 }, +/* 0x34b8 */ { false, 0x34b8, 0x34b8 }, +/* 0x34b9 */ { false, 0x34b9, 0x34b9 }, +/* 0x34ba */ { false, 0x34ba, 0x34ba }, +/* 0x34bb */ { false, 0x34bb, 0x34bb }, +/* 0x34bc */ { false, 0x34bc, 0x34bc }, +/* 0x34bd */ { false, 0x34bd, 0x34bd }, +/* 0x34be */ { false, 0x34be, 0x34be }, +/* 0x34bf */ { false, 0x34bf, 0x34bf }, +/* 0x34c0 */ { false, 0x34c0, 0x34c0 }, +/* 0x34c1 */ { false, 0x34c1, 0x34c1 }, +/* 0x34c2 */ { false, 0x34c2, 0x34c2 }, +/* 0x34c3 */ { false, 0x34c3, 0x34c3 }, +/* 0x34c4 */ { false, 0x34c4, 0x34c4 }, +/* 0x34c5 */ { false, 0x34c5, 0x34c5 }, +/* 0x34c6 */ { false, 0x34c6, 0x34c6 }, +/* 0x34c7 */ { false, 0x34c7, 0x34c7 }, +/* 0x34c8 */ { false, 0x34c8, 0x34c8 }, +/* 0x34c9 */ { false, 0x34c9, 0x34c9 }, +/* 0x34ca */ { false, 0x34ca, 0x34ca }, +/* 0x34cb */ { false, 0x34cb, 0x34cb }, +/* 0x34cc */ { false, 0x34cc, 0x34cc }, +/* 0x34cd */ { false, 0x34cd, 0x34cd }, +/* 0x34ce */ { false, 0x34ce, 0x34ce }, +/* 0x34cf */ { false, 0x34cf, 0x34cf }, +/* 0x34d0 */ { false, 0x34d0, 0x34d0 }, +/* 0x34d1 */ { false, 0x34d1, 0x34d1 }, +/* 0x34d2 */ { false, 0x34d2, 0x34d2 }, +/* 0x34d3 */ { false, 0x34d3, 0x34d3 }, +/* 0x34d4 */ { false, 0x34d4, 0x34d4 }, +/* 0x34d5 */ { false, 0x34d5, 0x34d5 }, +/* 0x34d6 */ { false, 0x34d6, 0x34d6 }, +/* 0x34d7 */ { false, 0x34d7, 0x34d7 }, +/* 0x34d8 */ { false, 0x34d8, 0x34d8 }, +/* 0x34d9 */ { false, 0x34d9, 0x34d9 }, +/* 0x34da */ { false, 0x34da, 0x34da }, +/* 0x34db */ { false, 0x34db, 0x34db }, +/* 0x34dc */ { false, 0x34dc, 0x34dc }, +/* 0x34dd */ { false, 0x34dd, 0x34dd }, +/* 0x34de */ { false, 0x34de, 0x34de }, +/* 0x34df */ { false, 0x34df, 0x34df }, +/* 0x34e0 */ { false, 0x34e0, 0x34e0 }, +/* 0x34e1 */ { false, 0x34e1, 0x34e1 }, +/* 0x34e2 */ { false, 0x34e2, 0x34e2 }, +/* 0x34e3 */ { false, 0x34e3, 0x34e3 }, +/* 0x34e4 */ { false, 0x34e4, 0x34e4 }, +/* 0x34e5 */ { false, 0x34e5, 0x34e5 }, +/* 0x34e6 */ { false, 0x34e6, 0x34e6 }, +/* 0x34e7 */ { false, 0x34e7, 0x34e7 }, +/* 0x34e8 */ { false, 0x34e8, 0x34e8 }, +/* 0x34e9 */ { false, 0x34e9, 0x34e9 }, +/* 0x34ea */ { false, 0x34ea, 0x34ea }, +/* 0x34eb */ { false, 0x34eb, 0x34eb }, +/* 0x34ec */ { false, 0x34ec, 0x34ec }, +/* 0x34ed */ { false, 0x34ed, 0x34ed }, +/* 0x34ee */ { false, 0x34ee, 0x34ee }, +/* 0x34ef */ { false, 0x34ef, 0x34ef }, +/* 0x34f0 */ { false, 0x34f0, 0x34f0 }, +/* 0x34f1 */ { false, 0x34f1, 0x34f1 }, +/* 0x34f2 */ { false, 0x34f2, 0x34f2 }, +/* 0x34f3 */ { false, 0x34f3, 0x34f3 }, +/* 0x34f4 */ { false, 0x34f4, 0x34f4 }, +/* 0x34f5 */ { false, 0x34f5, 0x34f5 }, +/* 0x34f6 */ { false, 0x34f6, 0x34f6 }, +/* 0x34f7 */ { false, 0x34f7, 0x34f7 }, +/* 0x34f8 */ { false, 0x34f8, 0x34f8 }, +/* 0x34f9 */ { false, 0x34f9, 0x34f9 }, +/* 0x34fa */ { false, 0x34fa, 0x34fa }, +/* 0x34fb */ { false, 0x34fb, 0x34fb }, +/* 0x34fc */ { false, 0x34fc, 0x34fc }, +/* 0x34fd */ { false, 0x34fd, 0x34fd }, +/* 0x34fe */ { false, 0x34fe, 0x34fe }, +/* 0x34ff */ { false, 0x34ff, 0x34ff }, +/* 0x3500 */ { false, 0x3500, 0x3500 }, +/* 0x3501 */ { false, 0x3501, 0x3501 }, +/* 0x3502 */ { false, 0x3502, 0x3502 }, +/* 0x3503 */ { false, 0x3503, 0x3503 }, +/* 0x3504 */ { false, 0x3504, 0x3504 }, +/* 0x3505 */ { false, 0x3505, 0x3505 }, +/* 0x3506 */ { false, 0x3506, 0x3506 }, +/* 0x3507 */ { false, 0x3507, 0x3507 }, +/* 0x3508 */ { false, 0x3508, 0x3508 }, +/* 0x3509 */ { false, 0x3509, 0x3509 }, +/* 0x350a */ { false, 0x350a, 0x350a }, +/* 0x350b */ { false, 0x350b, 0x350b }, +/* 0x350c */ { false, 0x350c, 0x350c }, +/* 0x350d */ { false, 0x350d, 0x350d }, +/* 0x350e */ { false, 0x350e, 0x350e }, +/* 0x350f */ { false, 0x350f, 0x350f }, +/* 0x3510 */ { false, 0x3510, 0x3510 }, +/* 0x3511 */ { false, 0x3511, 0x3511 }, +/* 0x3512 */ { false, 0x3512, 0x3512 }, +/* 0x3513 */ { false, 0x3513, 0x3513 }, +/* 0x3514 */ { false, 0x3514, 0x3514 }, +/* 0x3515 */ { false, 0x3515, 0x3515 }, +/* 0x3516 */ { false, 0x3516, 0x3516 }, +/* 0x3517 */ { false, 0x3517, 0x3517 }, +/* 0x3518 */ { false, 0x3518, 0x3518 }, +/* 0x3519 */ { false, 0x3519, 0x3519 }, +/* 0x351a */ { false, 0x351a, 0x351a }, +/* 0x351b */ { false, 0x351b, 0x351b }, +/* 0x351c */ { false, 0x351c, 0x351c }, +/* 0x351d */ { false, 0x351d, 0x351d }, +/* 0x351e */ { false, 0x351e, 0x351e }, +/* 0x351f */ { false, 0x351f, 0x351f }, +/* 0x3520 */ { false, 0x3520, 0x3520 }, +/* 0x3521 */ { false, 0x3521, 0x3521 }, +/* 0x3522 */ { false, 0x3522, 0x3522 }, +/* 0x3523 */ { false, 0x3523, 0x3523 }, +/* 0x3524 */ { false, 0x3524, 0x3524 }, +/* 0x3525 */ { false, 0x3525, 0x3525 }, +/* 0x3526 */ { false, 0x3526, 0x3526 }, +/* 0x3527 */ { false, 0x3527, 0x3527 }, +/* 0x3528 */ { false, 0x3528, 0x3528 }, +/* 0x3529 */ { false, 0x3529, 0x3529 }, +/* 0x352a */ { false, 0x352a, 0x352a }, +/* 0x352b */ { false, 0x352b, 0x352b }, +/* 0x352c */ { false, 0x352c, 0x352c }, +/* 0x352d */ { false, 0x352d, 0x352d }, +/* 0x352e */ { false, 0x352e, 0x352e }, +/* 0x352f */ { false, 0x352f, 0x352f }, +/* 0x3530 */ { false, 0x3530, 0x3530 }, +/* 0x3531 */ { false, 0x3531, 0x3531 }, +/* 0x3532 */ { false, 0x3532, 0x3532 }, +/* 0x3533 */ { false, 0x3533, 0x3533 }, +/* 0x3534 */ { false, 0x3534, 0x3534 }, +/* 0x3535 */ { false, 0x3535, 0x3535 }, +/* 0x3536 */ { false, 0x3536, 0x3536 }, +/* 0x3537 */ { false, 0x3537, 0x3537 }, +/* 0x3538 */ { false, 0x3538, 0x3538 }, +/* 0x3539 */ { false, 0x3539, 0x3539 }, +/* 0x353a */ { false, 0x353a, 0x353a }, +/* 0x353b */ { false, 0x353b, 0x353b }, +/* 0x353c */ { false, 0x353c, 0x353c }, +/* 0x353d */ { false, 0x353d, 0x353d }, +/* 0x353e */ { false, 0x353e, 0x353e }, +/* 0x353f */ { false, 0x353f, 0x353f }, +/* 0x3540 */ { false, 0x3540, 0x3540 }, +/* 0x3541 */ { false, 0x3541, 0x3541 }, +/* 0x3542 */ { false, 0x3542, 0x3542 }, +/* 0x3543 */ { false, 0x3543, 0x3543 }, +/* 0x3544 */ { false, 0x3544, 0x3544 }, +/* 0x3545 */ { false, 0x3545, 0x3545 }, +/* 0x3546 */ { false, 0x3546, 0x3546 }, +/* 0x3547 */ { false, 0x3547, 0x3547 }, +/* 0x3548 */ { false, 0x3548, 0x3548 }, +/* 0x3549 */ { false, 0x3549, 0x3549 }, +/* 0x354a */ { false, 0x354a, 0x354a }, +/* 0x354b */ { false, 0x354b, 0x354b }, +/* 0x354c */ { false, 0x354c, 0x354c }, +/* 0x354d */ { false, 0x354d, 0x354d }, +/* 0x354e */ { false, 0x354e, 0x354e }, +/* 0x354f */ { false, 0x354f, 0x354f }, +/* 0x3550 */ { false, 0x3550, 0x3550 }, +/* 0x3551 */ { false, 0x3551, 0x3551 }, +/* 0x3552 */ { false, 0x3552, 0x3552 }, +/* 0x3553 */ { false, 0x3553, 0x3553 }, +/* 0x3554 */ { false, 0x3554, 0x3554 }, +/* 0x3555 */ { false, 0x3555, 0x3555 }, +/* 0x3556 */ { false, 0x3556, 0x3556 }, +/* 0x3557 */ { false, 0x3557, 0x3557 }, +/* 0x3558 */ { false, 0x3558, 0x3558 }, +/* 0x3559 */ { false, 0x3559, 0x3559 }, +/* 0x355a */ { false, 0x355a, 0x355a }, +/* 0x355b */ { false, 0x355b, 0x355b }, +/* 0x355c */ { false, 0x355c, 0x355c }, +/* 0x355d */ { false, 0x355d, 0x355d }, +/* 0x355e */ { false, 0x355e, 0x355e }, +/* 0x355f */ { false, 0x355f, 0x355f }, +/* 0x3560 */ { false, 0x3560, 0x3560 }, +/* 0x3561 */ { false, 0x3561, 0x3561 }, +/* 0x3562 */ { false, 0x3562, 0x3562 }, +/* 0x3563 */ { false, 0x3563, 0x3563 }, +/* 0x3564 */ { false, 0x3564, 0x3564 }, +/* 0x3565 */ { false, 0x3565, 0x3565 }, +/* 0x3566 */ { false, 0x3566, 0x3566 }, +/* 0x3567 */ { false, 0x3567, 0x3567 }, +/* 0x3568 */ { false, 0x3568, 0x3568 }, +/* 0x3569 */ { false, 0x3569, 0x3569 }, +/* 0x356a */ { false, 0x356a, 0x356a }, +/* 0x356b */ { false, 0x356b, 0x356b }, +/* 0x356c */ { false, 0x356c, 0x356c }, +/* 0x356d */ { false, 0x356d, 0x356d }, +/* 0x356e */ { false, 0x356e, 0x356e }, +/* 0x356f */ { false, 0x356f, 0x356f }, +/* 0x3570 */ { false, 0x3570, 0x3570 }, +/* 0x3571 */ { false, 0x3571, 0x3571 }, +/* 0x3572 */ { false, 0x3572, 0x3572 }, +/* 0x3573 */ { false, 0x3573, 0x3573 }, +/* 0x3574 */ { false, 0x3574, 0x3574 }, +/* 0x3575 */ { false, 0x3575, 0x3575 }, +/* 0x3576 */ { false, 0x3576, 0x3576 }, +/* 0x3577 */ { false, 0x3577, 0x3577 }, +/* 0x3578 */ { false, 0x3578, 0x3578 }, +/* 0x3579 */ { false, 0x3579, 0x3579 }, +/* 0x357a */ { false, 0x357a, 0x357a }, +/* 0x357b */ { false, 0x357b, 0x357b }, +/* 0x357c */ { false, 0x357c, 0x357c }, +/* 0x357d */ { false, 0x357d, 0x357d }, +/* 0x357e */ { false, 0x357e, 0x357e }, +/* 0x357f */ { false, 0x357f, 0x357f }, +/* 0x3580 */ { false, 0x3580, 0x3580 }, +/* 0x3581 */ { false, 0x3581, 0x3581 }, +/* 0x3582 */ { false, 0x3582, 0x3582 }, +/* 0x3583 */ { false, 0x3583, 0x3583 }, +/* 0x3584 */ { false, 0x3584, 0x3584 }, +/* 0x3585 */ { false, 0x3585, 0x3585 }, +/* 0x3586 */ { false, 0x3586, 0x3586 }, +/* 0x3587 */ { false, 0x3587, 0x3587 }, +/* 0x3588 */ { false, 0x3588, 0x3588 }, +/* 0x3589 */ { false, 0x3589, 0x3589 }, +/* 0x358a */ { false, 0x358a, 0x358a }, +/* 0x358b */ { false, 0x358b, 0x358b }, +/* 0x358c */ { false, 0x358c, 0x358c }, +/* 0x358d */ { false, 0x358d, 0x358d }, +/* 0x358e */ { false, 0x358e, 0x358e }, +/* 0x358f */ { false, 0x358f, 0x358f }, +/* 0x3590 */ { false, 0x3590, 0x3590 }, +/* 0x3591 */ { false, 0x3591, 0x3591 }, +/* 0x3592 */ { false, 0x3592, 0x3592 }, +/* 0x3593 */ { false, 0x3593, 0x3593 }, +/* 0x3594 */ { false, 0x3594, 0x3594 }, +/* 0x3595 */ { false, 0x3595, 0x3595 }, +/* 0x3596 */ { false, 0x3596, 0x3596 }, +/* 0x3597 */ { false, 0x3597, 0x3597 }, +/* 0x3598 */ { false, 0x3598, 0x3598 }, +/* 0x3599 */ { false, 0x3599, 0x3599 }, +/* 0x359a */ { false, 0x359a, 0x359a }, +/* 0x359b */ { false, 0x359b, 0x359b }, +/* 0x359c */ { false, 0x359c, 0x359c }, +/* 0x359d */ { false, 0x359d, 0x359d }, +/* 0x359e */ { false, 0x359e, 0x359e }, +/* 0x359f */ { false, 0x359f, 0x359f }, +/* 0x35a0 */ { false, 0x35a0, 0x35a0 }, +/* 0x35a1 */ { false, 0x35a1, 0x35a1 }, +/* 0x35a2 */ { false, 0x35a2, 0x35a2 }, +/* 0x35a3 */ { false, 0x35a3, 0x35a3 }, +/* 0x35a4 */ { false, 0x35a4, 0x35a4 }, +/* 0x35a5 */ { false, 0x35a5, 0x35a5 }, +/* 0x35a6 */ { false, 0x35a6, 0x35a6 }, +/* 0x35a7 */ { false, 0x35a7, 0x35a7 }, +/* 0x35a8 */ { false, 0x35a8, 0x35a8 }, +/* 0x35a9 */ { false, 0x35a9, 0x35a9 }, +/* 0x35aa */ { false, 0x35aa, 0x35aa }, +/* 0x35ab */ { false, 0x35ab, 0x35ab }, +/* 0x35ac */ { false, 0x35ac, 0x35ac }, +/* 0x35ad */ { false, 0x35ad, 0x35ad }, +/* 0x35ae */ { false, 0x35ae, 0x35ae }, +/* 0x35af */ { false, 0x35af, 0x35af }, +/* 0x35b0 */ { false, 0x35b0, 0x35b0 }, +/* 0x35b1 */ { false, 0x35b1, 0x35b1 }, +/* 0x35b2 */ { false, 0x35b2, 0x35b2 }, +/* 0x35b3 */ { false, 0x35b3, 0x35b3 }, +/* 0x35b4 */ { false, 0x35b4, 0x35b4 }, +/* 0x35b5 */ { false, 0x35b5, 0x35b5 }, +/* 0x35b6 */ { false, 0x35b6, 0x35b6 }, +/* 0x35b7 */ { false, 0x35b7, 0x35b7 }, +/* 0x35b8 */ { false, 0x35b8, 0x35b8 }, +/* 0x35b9 */ { false, 0x35b9, 0x35b9 }, +/* 0x35ba */ { false, 0x35ba, 0x35ba }, +/* 0x35bb */ { false, 0x35bb, 0x35bb }, +/* 0x35bc */ { false, 0x35bc, 0x35bc }, +/* 0x35bd */ { false, 0x35bd, 0x35bd }, +/* 0x35be */ { false, 0x35be, 0x35be }, +/* 0x35bf */ { false, 0x35bf, 0x35bf }, +/* 0x35c0 */ { false, 0x35c0, 0x35c0 }, +/* 0x35c1 */ { false, 0x35c1, 0x35c1 }, +/* 0x35c2 */ { false, 0x35c2, 0x35c2 }, +/* 0x35c3 */ { false, 0x35c3, 0x35c3 }, +/* 0x35c4 */ { false, 0x35c4, 0x35c4 }, +/* 0x35c5 */ { false, 0x35c5, 0x35c5 }, +/* 0x35c6 */ { false, 0x35c6, 0x35c6 }, +/* 0x35c7 */ { false, 0x35c7, 0x35c7 }, +/* 0x35c8 */ { false, 0x35c8, 0x35c8 }, +/* 0x35c9 */ { false, 0x35c9, 0x35c9 }, +/* 0x35ca */ { false, 0x35ca, 0x35ca }, +/* 0x35cb */ { false, 0x35cb, 0x35cb }, +/* 0x35cc */ { false, 0x35cc, 0x35cc }, +/* 0x35cd */ { false, 0x35cd, 0x35cd }, +/* 0x35ce */ { false, 0x35ce, 0x35ce }, +/* 0x35cf */ { false, 0x35cf, 0x35cf }, +/* 0x35d0 */ { false, 0x35d0, 0x35d0 }, +/* 0x35d1 */ { false, 0x35d1, 0x35d1 }, +/* 0x35d2 */ { false, 0x35d2, 0x35d2 }, +/* 0x35d3 */ { false, 0x35d3, 0x35d3 }, +/* 0x35d4 */ { false, 0x35d4, 0x35d4 }, +/* 0x35d5 */ { false, 0x35d5, 0x35d5 }, +/* 0x35d6 */ { false, 0x35d6, 0x35d6 }, +/* 0x35d7 */ { false, 0x35d7, 0x35d7 }, +/* 0x35d8 */ { false, 0x35d8, 0x35d8 }, +/* 0x35d9 */ { false, 0x35d9, 0x35d9 }, +/* 0x35da */ { false, 0x35da, 0x35da }, +/* 0x35db */ { false, 0x35db, 0x35db }, +/* 0x35dc */ { false, 0x35dc, 0x35dc }, +/* 0x35dd */ { false, 0x35dd, 0x35dd }, +/* 0x35de */ { false, 0x35de, 0x35de }, +/* 0x35df */ { false, 0x35df, 0x35df }, +/* 0x35e0 */ { false, 0x35e0, 0x35e0 }, +/* 0x35e1 */ { false, 0x35e1, 0x35e1 }, +/* 0x35e2 */ { false, 0x35e2, 0x35e2 }, +/* 0x35e3 */ { false, 0x35e3, 0x35e3 }, +/* 0x35e4 */ { false, 0x35e4, 0x35e4 }, +/* 0x35e5 */ { false, 0x35e5, 0x35e5 }, +/* 0x35e6 */ { false, 0x35e6, 0x35e6 }, +/* 0x35e7 */ { false, 0x35e7, 0x35e7 }, +/* 0x35e8 */ { false, 0x35e8, 0x35e8 }, +/* 0x35e9 */ { false, 0x35e9, 0x35e9 }, +/* 0x35ea */ { false, 0x35ea, 0x35ea }, +/* 0x35eb */ { false, 0x35eb, 0x35eb }, +/* 0x35ec */ { false, 0x35ec, 0x35ec }, +/* 0x35ed */ { false, 0x35ed, 0x35ed }, +/* 0x35ee */ { false, 0x35ee, 0x35ee }, +/* 0x35ef */ { false, 0x35ef, 0x35ef }, +/* 0x35f0 */ { false, 0x35f0, 0x35f0 }, +/* 0x35f1 */ { false, 0x35f1, 0x35f1 }, +/* 0x35f2 */ { false, 0x35f2, 0x35f2 }, +/* 0x35f3 */ { false, 0x35f3, 0x35f3 }, +/* 0x35f4 */ { false, 0x35f4, 0x35f4 }, +/* 0x35f5 */ { false, 0x35f5, 0x35f5 }, +/* 0x35f6 */ { false, 0x35f6, 0x35f6 }, +/* 0x35f7 */ { false, 0x35f7, 0x35f7 }, +/* 0x35f8 */ { false, 0x35f8, 0x35f8 }, +/* 0x35f9 */ { false, 0x35f9, 0x35f9 }, +/* 0x35fa */ { false, 0x35fa, 0x35fa }, +/* 0x35fb */ { false, 0x35fb, 0x35fb }, +/* 0x35fc */ { false, 0x35fc, 0x35fc }, +/* 0x35fd */ { false, 0x35fd, 0x35fd }, +/* 0x35fe */ { false, 0x35fe, 0x35fe }, +/* 0x35ff */ { false, 0x35ff, 0x35ff }, +/* 0x3600 */ { false, 0x3600, 0x3600 }, +/* 0x3601 */ { false, 0x3601, 0x3601 }, +/* 0x3602 */ { false, 0x3602, 0x3602 }, +/* 0x3603 */ { false, 0x3603, 0x3603 }, +/* 0x3604 */ { false, 0x3604, 0x3604 }, +/* 0x3605 */ { false, 0x3605, 0x3605 }, +/* 0x3606 */ { false, 0x3606, 0x3606 }, +/* 0x3607 */ { false, 0x3607, 0x3607 }, +/* 0x3608 */ { false, 0x3608, 0x3608 }, +/* 0x3609 */ { false, 0x3609, 0x3609 }, +/* 0x360a */ { false, 0x360a, 0x360a }, +/* 0x360b */ { false, 0x360b, 0x360b }, +/* 0x360c */ { false, 0x360c, 0x360c }, +/* 0x360d */ { false, 0x360d, 0x360d }, +/* 0x360e */ { false, 0x360e, 0x360e }, +/* 0x360f */ { false, 0x360f, 0x360f }, +/* 0x3610 */ { false, 0x3610, 0x3610 }, +/* 0x3611 */ { false, 0x3611, 0x3611 }, +/* 0x3612 */ { false, 0x3612, 0x3612 }, +/* 0x3613 */ { false, 0x3613, 0x3613 }, +/* 0x3614 */ { false, 0x3614, 0x3614 }, +/* 0x3615 */ { false, 0x3615, 0x3615 }, +/* 0x3616 */ { false, 0x3616, 0x3616 }, +/* 0x3617 */ { false, 0x3617, 0x3617 }, +/* 0x3618 */ { false, 0x3618, 0x3618 }, +/* 0x3619 */ { false, 0x3619, 0x3619 }, +/* 0x361a */ { false, 0x361a, 0x361a }, +/* 0x361b */ { false, 0x361b, 0x361b }, +/* 0x361c */ { false, 0x361c, 0x361c }, +/* 0x361d */ { false, 0x361d, 0x361d }, +/* 0x361e */ { false, 0x361e, 0x361e }, +/* 0x361f */ { false, 0x361f, 0x361f }, +/* 0x3620 */ { false, 0x3620, 0x3620 }, +/* 0x3621 */ { false, 0x3621, 0x3621 }, +/* 0x3622 */ { false, 0x3622, 0x3622 }, +/* 0x3623 */ { false, 0x3623, 0x3623 }, +/* 0x3624 */ { false, 0x3624, 0x3624 }, +/* 0x3625 */ { false, 0x3625, 0x3625 }, +/* 0x3626 */ { false, 0x3626, 0x3626 }, +/* 0x3627 */ { false, 0x3627, 0x3627 }, +/* 0x3628 */ { false, 0x3628, 0x3628 }, +/* 0x3629 */ { false, 0x3629, 0x3629 }, +/* 0x362a */ { false, 0x362a, 0x362a }, +/* 0x362b */ { false, 0x362b, 0x362b }, +/* 0x362c */ { false, 0x362c, 0x362c }, +/* 0x362d */ { false, 0x362d, 0x362d }, +/* 0x362e */ { false, 0x362e, 0x362e }, +/* 0x362f */ { false, 0x362f, 0x362f }, +/* 0x3630 */ { false, 0x3630, 0x3630 }, +/* 0x3631 */ { false, 0x3631, 0x3631 }, +/* 0x3632 */ { false, 0x3632, 0x3632 }, +/* 0x3633 */ { false, 0x3633, 0x3633 }, +/* 0x3634 */ { false, 0x3634, 0x3634 }, +/* 0x3635 */ { false, 0x3635, 0x3635 }, +/* 0x3636 */ { false, 0x3636, 0x3636 }, +/* 0x3637 */ { false, 0x3637, 0x3637 }, +/* 0x3638 */ { false, 0x3638, 0x3638 }, +/* 0x3639 */ { false, 0x3639, 0x3639 }, +/* 0x363a */ { false, 0x363a, 0x363a }, +/* 0x363b */ { false, 0x363b, 0x363b }, +/* 0x363c */ { false, 0x363c, 0x363c }, +/* 0x363d */ { false, 0x363d, 0x363d }, +/* 0x363e */ { false, 0x363e, 0x363e }, +/* 0x363f */ { false, 0x363f, 0x363f }, +/* 0x3640 */ { false, 0x3640, 0x3640 }, +/* 0x3641 */ { false, 0x3641, 0x3641 }, +/* 0x3642 */ { false, 0x3642, 0x3642 }, +/* 0x3643 */ { false, 0x3643, 0x3643 }, +/* 0x3644 */ { false, 0x3644, 0x3644 }, +/* 0x3645 */ { false, 0x3645, 0x3645 }, +/* 0x3646 */ { false, 0x3646, 0x3646 }, +/* 0x3647 */ { false, 0x3647, 0x3647 }, +/* 0x3648 */ { false, 0x3648, 0x3648 }, +/* 0x3649 */ { false, 0x3649, 0x3649 }, +/* 0x364a */ { false, 0x364a, 0x364a }, +/* 0x364b */ { false, 0x364b, 0x364b }, +/* 0x364c */ { false, 0x364c, 0x364c }, +/* 0x364d */ { false, 0x364d, 0x364d }, +/* 0x364e */ { false, 0x364e, 0x364e }, +/* 0x364f */ { false, 0x364f, 0x364f }, +/* 0x3650 */ { false, 0x3650, 0x3650 }, +/* 0x3651 */ { false, 0x3651, 0x3651 }, +/* 0x3652 */ { false, 0x3652, 0x3652 }, +/* 0x3653 */ { false, 0x3653, 0x3653 }, +/* 0x3654 */ { false, 0x3654, 0x3654 }, +/* 0x3655 */ { false, 0x3655, 0x3655 }, +/* 0x3656 */ { false, 0x3656, 0x3656 }, +/* 0x3657 */ { false, 0x3657, 0x3657 }, +/* 0x3658 */ { false, 0x3658, 0x3658 }, +/* 0x3659 */ { false, 0x3659, 0x3659 }, +/* 0x365a */ { false, 0x365a, 0x365a }, +/* 0x365b */ { false, 0x365b, 0x365b }, +/* 0x365c */ { false, 0x365c, 0x365c }, +/* 0x365d */ { false, 0x365d, 0x365d }, +/* 0x365e */ { false, 0x365e, 0x365e }, +/* 0x365f */ { false, 0x365f, 0x365f }, +/* 0x3660 */ { false, 0x3660, 0x3660 }, +/* 0x3661 */ { false, 0x3661, 0x3661 }, +/* 0x3662 */ { false, 0x3662, 0x3662 }, +/* 0x3663 */ { false, 0x3663, 0x3663 }, +/* 0x3664 */ { false, 0x3664, 0x3664 }, +/* 0x3665 */ { false, 0x3665, 0x3665 }, +/* 0x3666 */ { false, 0x3666, 0x3666 }, +/* 0x3667 */ { false, 0x3667, 0x3667 }, +/* 0x3668 */ { false, 0x3668, 0x3668 }, +/* 0x3669 */ { false, 0x3669, 0x3669 }, +/* 0x366a */ { false, 0x366a, 0x366a }, +/* 0x366b */ { false, 0x366b, 0x366b }, +/* 0x366c */ { false, 0x366c, 0x366c }, +/* 0x366d */ { false, 0x366d, 0x366d }, +/* 0x366e */ { false, 0x366e, 0x366e }, +/* 0x366f */ { false, 0x366f, 0x366f }, +/* 0x3670 */ { false, 0x3670, 0x3670 }, +/* 0x3671 */ { false, 0x3671, 0x3671 }, +/* 0x3672 */ { false, 0x3672, 0x3672 }, +/* 0x3673 */ { false, 0x3673, 0x3673 }, +/* 0x3674 */ { false, 0x3674, 0x3674 }, +/* 0x3675 */ { false, 0x3675, 0x3675 }, +/* 0x3676 */ { false, 0x3676, 0x3676 }, +/* 0x3677 */ { false, 0x3677, 0x3677 }, +/* 0x3678 */ { false, 0x3678, 0x3678 }, +/* 0x3679 */ { false, 0x3679, 0x3679 }, +/* 0x367a */ { false, 0x367a, 0x367a }, +/* 0x367b */ { false, 0x367b, 0x367b }, +/* 0x367c */ { false, 0x367c, 0x367c }, +/* 0x367d */ { false, 0x367d, 0x367d }, +/* 0x367e */ { false, 0x367e, 0x367e }, +/* 0x367f */ { false, 0x367f, 0x367f }, +/* 0x3680 */ { false, 0x3680, 0x3680 }, +/* 0x3681 */ { false, 0x3681, 0x3681 }, +/* 0x3682 */ { false, 0x3682, 0x3682 }, +/* 0x3683 */ { false, 0x3683, 0x3683 }, +/* 0x3684 */ { false, 0x3684, 0x3684 }, +/* 0x3685 */ { false, 0x3685, 0x3685 }, +/* 0x3686 */ { false, 0x3686, 0x3686 }, +/* 0x3687 */ { false, 0x3687, 0x3687 }, +/* 0x3688 */ { false, 0x3688, 0x3688 }, +/* 0x3689 */ { false, 0x3689, 0x3689 }, +/* 0x368a */ { false, 0x368a, 0x368a }, +/* 0x368b */ { false, 0x368b, 0x368b }, +/* 0x368c */ { false, 0x368c, 0x368c }, +/* 0x368d */ { false, 0x368d, 0x368d }, +/* 0x368e */ { false, 0x368e, 0x368e }, +/* 0x368f */ { false, 0x368f, 0x368f }, +/* 0x3690 */ { false, 0x3690, 0x3690 }, +/* 0x3691 */ { false, 0x3691, 0x3691 }, +/* 0x3692 */ { false, 0x3692, 0x3692 }, +/* 0x3693 */ { false, 0x3693, 0x3693 }, +/* 0x3694 */ { false, 0x3694, 0x3694 }, +/* 0x3695 */ { false, 0x3695, 0x3695 }, +/* 0x3696 */ { false, 0x3696, 0x3696 }, +/* 0x3697 */ { false, 0x3697, 0x3697 }, +/* 0x3698 */ { false, 0x3698, 0x3698 }, +/* 0x3699 */ { false, 0x3699, 0x3699 }, +/* 0x369a */ { false, 0x369a, 0x369a }, +/* 0x369b */ { false, 0x369b, 0x369b }, +/* 0x369c */ { false, 0x369c, 0x369c }, +/* 0x369d */ { false, 0x369d, 0x369d }, +/* 0x369e */ { false, 0x369e, 0x369e }, +/* 0x369f */ { false, 0x369f, 0x369f }, +/* 0x36a0 */ { false, 0x36a0, 0x36a0 }, +/* 0x36a1 */ { false, 0x36a1, 0x36a1 }, +/* 0x36a2 */ { false, 0x36a2, 0x36a2 }, +/* 0x36a3 */ { false, 0x36a3, 0x36a3 }, +/* 0x36a4 */ { false, 0x36a4, 0x36a4 }, +/* 0x36a5 */ { false, 0x36a5, 0x36a5 }, +/* 0x36a6 */ { false, 0x36a6, 0x36a6 }, +/* 0x36a7 */ { false, 0x36a7, 0x36a7 }, +/* 0x36a8 */ { false, 0x36a8, 0x36a8 }, +/* 0x36a9 */ { false, 0x36a9, 0x36a9 }, +/* 0x36aa */ { false, 0x36aa, 0x36aa }, +/* 0x36ab */ { false, 0x36ab, 0x36ab }, +/* 0x36ac */ { false, 0x36ac, 0x36ac }, +/* 0x36ad */ { false, 0x36ad, 0x36ad }, +/* 0x36ae */ { false, 0x36ae, 0x36ae }, +/* 0x36af */ { false, 0x36af, 0x36af }, +/* 0x36b0 */ { false, 0x36b0, 0x36b0 }, +/* 0x36b1 */ { false, 0x36b1, 0x36b1 }, +/* 0x36b2 */ { false, 0x36b2, 0x36b2 }, +/* 0x36b3 */ { false, 0x36b3, 0x36b3 }, +/* 0x36b4 */ { false, 0x36b4, 0x36b4 }, +/* 0x36b5 */ { false, 0x36b5, 0x36b5 }, +/* 0x36b6 */ { false, 0x36b6, 0x36b6 }, +/* 0x36b7 */ { false, 0x36b7, 0x36b7 }, +/* 0x36b8 */ { false, 0x36b8, 0x36b8 }, +/* 0x36b9 */ { false, 0x36b9, 0x36b9 }, +/* 0x36ba */ { false, 0x36ba, 0x36ba }, +/* 0x36bb */ { false, 0x36bb, 0x36bb }, +/* 0x36bc */ { false, 0x36bc, 0x36bc }, +/* 0x36bd */ { false, 0x36bd, 0x36bd }, +/* 0x36be */ { false, 0x36be, 0x36be }, +/* 0x36bf */ { false, 0x36bf, 0x36bf }, +/* 0x36c0 */ { false, 0x36c0, 0x36c0 }, +/* 0x36c1 */ { false, 0x36c1, 0x36c1 }, +/* 0x36c2 */ { false, 0x36c2, 0x36c2 }, +/* 0x36c3 */ { false, 0x36c3, 0x36c3 }, +/* 0x36c4 */ { false, 0x36c4, 0x36c4 }, +/* 0x36c5 */ { false, 0x36c5, 0x36c5 }, +/* 0x36c6 */ { false, 0x36c6, 0x36c6 }, +/* 0x36c7 */ { false, 0x36c7, 0x36c7 }, +/* 0x36c8 */ { false, 0x36c8, 0x36c8 }, +/* 0x36c9 */ { false, 0x36c9, 0x36c9 }, +/* 0x36ca */ { false, 0x36ca, 0x36ca }, +/* 0x36cb */ { false, 0x36cb, 0x36cb }, +/* 0x36cc */ { false, 0x36cc, 0x36cc }, +/* 0x36cd */ { false, 0x36cd, 0x36cd }, +/* 0x36ce */ { false, 0x36ce, 0x36ce }, +/* 0x36cf */ { false, 0x36cf, 0x36cf }, +/* 0x36d0 */ { false, 0x36d0, 0x36d0 }, +/* 0x36d1 */ { false, 0x36d1, 0x36d1 }, +/* 0x36d2 */ { false, 0x36d2, 0x36d2 }, +/* 0x36d3 */ { false, 0x36d3, 0x36d3 }, +/* 0x36d4 */ { false, 0x36d4, 0x36d4 }, +/* 0x36d5 */ { false, 0x36d5, 0x36d5 }, +/* 0x36d6 */ { false, 0x36d6, 0x36d6 }, +/* 0x36d7 */ { false, 0x36d7, 0x36d7 }, +/* 0x36d8 */ { false, 0x36d8, 0x36d8 }, +/* 0x36d9 */ { false, 0x36d9, 0x36d9 }, +/* 0x36da */ { false, 0x36da, 0x36da }, +/* 0x36db */ { false, 0x36db, 0x36db }, +/* 0x36dc */ { false, 0x36dc, 0x36dc }, +/* 0x36dd */ { false, 0x36dd, 0x36dd }, +/* 0x36de */ { false, 0x36de, 0x36de }, +/* 0x36df */ { false, 0x36df, 0x36df }, +/* 0x36e0 */ { false, 0x36e0, 0x36e0 }, +/* 0x36e1 */ { false, 0x36e1, 0x36e1 }, +/* 0x36e2 */ { false, 0x36e2, 0x36e2 }, +/* 0x36e3 */ { false, 0x36e3, 0x36e3 }, +/* 0x36e4 */ { false, 0x36e4, 0x36e4 }, +/* 0x36e5 */ { false, 0x36e5, 0x36e5 }, +/* 0x36e6 */ { false, 0x36e6, 0x36e6 }, +/* 0x36e7 */ { false, 0x36e7, 0x36e7 }, +/* 0x36e8 */ { false, 0x36e8, 0x36e8 }, +/* 0x36e9 */ { false, 0x36e9, 0x36e9 }, +/* 0x36ea */ { false, 0x36ea, 0x36ea }, +/* 0x36eb */ { false, 0x36eb, 0x36eb }, +/* 0x36ec */ { false, 0x36ec, 0x36ec }, +/* 0x36ed */ { false, 0x36ed, 0x36ed }, +/* 0x36ee */ { false, 0x36ee, 0x36ee }, +/* 0x36ef */ { false, 0x36ef, 0x36ef }, +/* 0x36f0 */ { false, 0x36f0, 0x36f0 }, +/* 0x36f1 */ { false, 0x36f1, 0x36f1 }, +/* 0x36f2 */ { false, 0x36f2, 0x36f2 }, +/* 0x36f3 */ { false, 0x36f3, 0x36f3 }, +/* 0x36f4 */ { false, 0x36f4, 0x36f4 }, +/* 0x36f5 */ { false, 0x36f5, 0x36f5 }, +/* 0x36f6 */ { false, 0x36f6, 0x36f6 }, +/* 0x36f7 */ { false, 0x36f7, 0x36f7 }, +/* 0x36f8 */ { false, 0x36f8, 0x36f8 }, +/* 0x36f9 */ { false, 0x36f9, 0x36f9 }, +/* 0x36fa */ { false, 0x36fa, 0x36fa }, +/* 0x36fb */ { false, 0x36fb, 0x36fb }, +/* 0x36fc */ { false, 0x36fc, 0x36fc }, +/* 0x36fd */ { false, 0x36fd, 0x36fd }, +/* 0x36fe */ { false, 0x36fe, 0x36fe }, +/* 0x36ff */ { false, 0x36ff, 0x36ff }, +/* 0x3700 */ { false, 0x3700, 0x3700 }, +/* 0x3701 */ { false, 0x3701, 0x3701 }, +/* 0x3702 */ { false, 0x3702, 0x3702 }, +/* 0x3703 */ { false, 0x3703, 0x3703 }, +/* 0x3704 */ { false, 0x3704, 0x3704 }, +/* 0x3705 */ { false, 0x3705, 0x3705 }, +/* 0x3706 */ { false, 0x3706, 0x3706 }, +/* 0x3707 */ { false, 0x3707, 0x3707 }, +/* 0x3708 */ { false, 0x3708, 0x3708 }, +/* 0x3709 */ { false, 0x3709, 0x3709 }, +/* 0x370a */ { false, 0x370a, 0x370a }, +/* 0x370b */ { false, 0x370b, 0x370b }, +/* 0x370c */ { false, 0x370c, 0x370c }, +/* 0x370d */ { false, 0x370d, 0x370d }, +/* 0x370e */ { false, 0x370e, 0x370e }, +/* 0x370f */ { false, 0x370f, 0x370f }, +/* 0x3710 */ { false, 0x3710, 0x3710 }, +/* 0x3711 */ { false, 0x3711, 0x3711 }, +/* 0x3712 */ { false, 0x3712, 0x3712 }, +/* 0x3713 */ { false, 0x3713, 0x3713 }, +/* 0x3714 */ { false, 0x3714, 0x3714 }, +/* 0x3715 */ { false, 0x3715, 0x3715 }, +/* 0x3716 */ { false, 0x3716, 0x3716 }, +/* 0x3717 */ { false, 0x3717, 0x3717 }, +/* 0x3718 */ { false, 0x3718, 0x3718 }, +/* 0x3719 */ { false, 0x3719, 0x3719 }, +/* 0x371a */ { false, 0x371a, 0x371a }, +/* 0x371b */ { false, 0x371b, 0x371b }, +/* 0x371c */ { false, 0x371c, 0x371c }, +/* 0x371d */ { false, 0x371d, 0x371d }, +/* 0x371e */ { false, 0x371e, 0x371e }, +/* 0x371f */ { false, 0x371f, 0x371f }, +/* 0x3720 */ { false, 0x3720, 0x3720 }, +/* 0x3721 */ { false, 0x3721, 0x3721 }, +/* 0x3722 */ { false, 0x3722, 0x3722 }, +/* 0x3723 */ { false, 0x3723, 0x3723 }, +/* 0x3724 */ { false, 0x3724, 0x3724 }, +/* 0x3725 */ { false, 0x3725, 0x3725 }, +/* 0x3726 */ { false, 0x3726, 0x3726 }, +/* 0x3727 */ { false, 0x3727, 0x3727 }, +/* 0x3728 */ { false, 0x3728, 0x3728 }, +/* 0x3729 */ { false, 0x3729, 0x3729 }, +/* 0x372a */ { false, 0x372a, 0x372a }, +/* 0x372b */ { false, 0x372b, 0x372b }, +/* 0x372c */ { false, 0x372c, 0x372c }, +/* 0x372d */ { false, 0x372d, 0x372d }, +/* 0x372e */ { false, 0x372e, 0x372e }, +/* 0x372f */ { false, 0x372f, 0x372f }, +/* 0x3730 */ { false, 0x3730, 0x3730 }, +/* 0x3731 */ { false, 0x3731, 0x3731 }, +/* 0x3732 */ { false, 0x3732, 0x3732 }, +/* 0x3733 */ { false, 0x3733, 0x3733 }, +/* 0x3734 */ { false, 0x3734, 0x3734 }, +/* 0x3735 */ { false, 0x3735, 0x3735 }, +/* 0x3736 */ { false, 0x3736, 0x3736 }, +/* 0x3737 */ { false, 0x3737, 0x3737 }, +/* 0x3738 */ { false, 0x3738, 0x3738 }, +/* 0x3739 */ { false, 0x3739, 0x3739 }, +/* 0x373a */ { false, 0x373a, 0x373a }, +/* 0x373b */ { false, 0x373b, 0x373b }, +/* 0x373c */ { false, 0x373c, 0x373c }, +/* 0x373d */ { false, 0x373d, 0x373d }, +/* 0x373e */ { false, 0x373e, 0x373e }, +/* 0x373f */ { false, 0x373f, 0x373f }, +/* 0x3740 */ { false, 0x3740, 0x3740 }, +/* 0x3741 */ { false, 0x3741, 0x3741 }, +/* 0x3742 */ { false, 0x3742, 0x3742 }, +/* 0x3743 */ { false, 0x3743, 0x3743 }, +/* 0x3744 */ { false, 0x3744, 0x3744 }, +/* 0x3745 */ { false, 0x3745, 0x3745 }, +/* 0x3746 */ { false, 0x3746, 0x3746 }, +/* 0x3747 */ { false, 0x3747, 0x3747 }, +/* 0x3748 */ { false, 0x3748, 0x3748 }, +/* 0x3749 */ { false, 0x3749, 0x3749 }, +/* 0x374a */ { false, 0x374a, 0x374a }, +/* 0x374b */ { false, 0x374b, 0x374b }, +/* 0x374c */ { false, 0x374c, 0x374c }, +/* 0x374d */ { false, 0x374d, 0x374d }, +/* 0x374e */ { false, 0x374e, 0x374e }, +/* 0x374f */ { false, 0x374f, 0x374f }, +/* 0x3750 */ { false, 0x3750, 0x3750 }, +/* 0x3751 */ { false, 0x3751, 0x3751 }, +/* 0x3752 */ { false, 0x3752, 0x3752 }, +/* 0x3753 */ { false, 0x3753, 0x3753 }, +/* 0x3754 */ { false, 0x3754, 0x3754 }, +/* 0x3755 */ { false, 0x3755, 0x3755 }, +/* 0x3756 */ { false, 0x3756, 0x3756 }, +/* 0x3757 */ { false, 0x3757, 0x3757 }, +/* 0x3758 */ { false, 0x3758, 0x3758 }, +/* 0x3759 */ { false, 0x3759, 0x3759 }, +/* 0x375a */ { false, 0x375a, 0x375a }, +/* 0x375b */ { false, 0x375b, 0x375b }, +/* 0x375c */ { false, 0x375c, 0x375c }, +/* 0x375d */ { false, 0x375d, 0x375d }, +/* 0x375e */ { false, 0x375e, 0x375e }, +/* 0x375f */ { false, 0x375f, 0x375f }, +/* 0x3760 */ { false, 0x3760, 0x3760 }, +/* 0x3761 */ { false, 0x3761, 0x3761 }, +/* 0x3762 */ { false, 0x3762, 0x3762 }, +/* 0x3763 */ { false, 0x3763, 0x3763 }, +/* 0x3764 */ { false, 0x3764, 0x3764 }, +/* 0x3765 */ { false, 0x3765, 0x3765 }, +/* 0x3766 */ { false, 0x3766, 0x3766 }, +/* 0x3767 */ { false, 0x3767, 0x3767 }, +/* 0x3768 */ { false, 0x3768, 0x3768 }, +/* 0x3769 */ { false, 0x3769, 0x3769 }, +/* 0x376a */ { false, 0x376a, 0x376a }, +/* 0x376b */ { false, 0x376b, 0x376b }, +/* 0x376c */ { false, 0x376c, 0x376c }, +/* 0x376d */ { false, 0x376d, 0x376d }, +/* 0x376e */ { false, 0x376e, 0x376e }, +/* 0x376f */ { false, 0x376f, 0x376f }, +/* 0x3770 */ { false, 0x3770, 0x3770 }, +/* 0x3771 */ { false, 0x3771, 0x3771 }, +/* 0x3772 */ { false, 0x3772, 0x3772 }, +/* 0x3773 */ { false, 0x3773, 0x3773 }, +/* 0x3774 */ { false, 0x3774, 0x3774 }, +/* 0x3775 */ { false, 0x3775, 0x3775 }, +/* 0x3776 */ { false, 0x3776, 0x3776 }, +/* 0x3777 */ { false, 0x3777, 0x3777 }, +/* 0x3778 */ { false, 0x3778, 0x3778 }, +/* 0x3779 */ { false, 0x3779, 0x3779 }, +/* 0x377a */ { false, 0x377a, 0x377a }, +/* 0x377b */ { false, 0x377b, 0x377b }, +/* 0x377c */ { false, 0x377c, 0x377c }, +/* 0x377d */ { false, 0x377d, 0x377d }, +/* 0x377e */ { false, 0x377e, 0x377e }, +/* 0x377f */ { false, 0x377f, 0x377f }, +/* 0x3780 */ { false, 0x3780, 0x3780 }, +/* 0x3781 */ { false, 0x3781, 0x3781 }, +/* 0x3782 */ { false, 0x3782, 0x3782 }, +/* 0x3783 */ { false, 0x3783, 0x3783 }, +/* 0x3784 */ { false, 0x3784, 0x3784 }, +/* 0x3785 */ { false, 0x3785, 0x3785 }, +/* 0x3786 */ { false, 0x3786, 0x3786 }, +/* 0x3787 */ { false, 0x3787, 0x3787 }, +/* 0x3788 */ { false, 0x3788, 0x3788 }, +/* 0x3789 */ { false, 0x3789, 0x3789 }, +/* 0x378a */ { false, 0x378a, 0x378a }, +/* 0x378b */ { false, 0x378b, 0x378b }, +/* 0x378c */ { false, 0x378c, 0x378c }, +/* 0x378d */ { false, 0x378d, 0x378d }, +/* 0x378e */ { false, 0x378e, 0x378e }, +/* 0x378f */ { false, 0x378f, 0x378f }, +/* 0x3790 */ { false, 0x3790, 0x3790 }, +/* 0x3791 */ { false, 0x3791, 0x3791 }, +/* 0x3792 */ { false, 0x3792, 0x3792 }, +/* 0x3793 */ { false, 0x3793, 0x3793 }, +/* 0x3794 */ { false, 0x3794, 0x3794 }, +/* 0x3795 */ { false, 0x3795, 0x3795 }, +/* 0x3796 */ { false, 0x3796, 0x3796 }, +/* 0x3797 */ { false, 0x3797, 0x3797 }, +/* 0x3798 */ { false, 0x3798, 0x3798 }, +/* 0x3799 */ { false, 0x3799, 0x3799 }, +/* 0x379a */ { false, 0x379a, 0x379a }, +/* 0x379b */ { false, 0x379b, 0x379b }, +/* 0x379c */ { false, 0x379c, 0x379c }, +/* 0x379d */ { false, 0x379d, 0x379d }, +/* 0x379e */ { false, 0x379e, 0x379e }, +/* 0x379f */ { false, 0x379f, 0x379f }, +/* 0x37a0 */ { false, 0x37a0, 0x37a0 }, +/* 0x37a1 */ { false, 0x37a1, 0x37a1 }, +/* 0x37a2 */ { false, 0x37a2, 0x37a2 }, +/* 0x37a3 */ { false, 0x37a3, 0x37a3 }, +/* 0x37a4 */ { false, 0x37a4, 0x37a4 }, +/* 0x37a5 */ { false, 0x37a5, 0x37a5 }, +/* 0x37a6 */ { false, 0x37a6, 0x37a6 }, +/* 0x37a7 */ { false, 0x37a7, 0x37a7 }, +/* 0x37a8 */ { false, 0x37a8, 0x37a8 }, +/* 0x37a9 */ { false, 0x37a9, 0x37a9 }, +/* 0x37aa */ { false, 0x37aa, 0x37aa }, +/* 0x37ab */ { false, 0x37ab, 0x37ab }, +/* 0x37ac */ { false, 0x37ac, 0x37ac }, +/* 0x37ad */ { false, 0x37ad, 0x37ad }, +/* 0x37ae */ { false, 0x37ae, 0x37ae }, +/* 0x37af */ { false, 0x37af, 0x37af }, +/* 0x37b0 */ { false, 0x37b0, 0x37b0 }, +/* 0x37b1 */ { false, 0x37b1, 0x37b1 }, +/* 0x37b2 */ { false, 0x37b2, 0x37b2 }, +/* 0x37b3 */ { false, 0x37b3, 0x37b3 }, +/* 0x37b4 */ { false, 0x37b4, 0x37b4 }, +/* 0x37b5 */ { false, 0x37b5, 0x37b5 }, +/* 0x37b6 */ { false, 0x37b6, 0x37b6 }, +/* 0x37b7 */ { false, 0x37b7, 0x37b7 }, +/* 0x37b8 */ { false, 0x37b8, 0x37b8 }, +/* 0x37b9 */ { false, 0x37b9, 0x37b9 }, +/* 0x37ba */ { false, 0x37ba, 0x37ba }, +/* 0x37bb */ { false, 0x37bb, 0x37bb }, +/* 0x37bc */ { false, 0x37bc, 0x37bc }, +/* 0x37bd */ { false, 0x37bd, 0x37bd }, +/* 0x37be */ { false, 0x37be, 0x37be }, +/* 0x37bf */ { false, 0x37bf, 0x37bf }, +/* 0x37c0 */ { false, 0x37c0, 0x37c0 }, +/* 0x37c1 */ { false, 0x37c1, 0x37c1 }, +/* 0x37c2 */ { false, 0x37c2, 0x37c2 }, +/* 0x37c3 */ { false, 0x37c3, 0x37c3 }, +/* 0x37c4 */ { false, 0x37c4, 0x37c4 }, +/* 0x37c5 */ { false, 0x37c5, 0x37c5 }, +/* 0x37c6 */ { false, 0x37c6, 0x37c6 }, +/* 0x37c7 */ { false, 0x37c7, 0x37c7 }, +/* 0x37c8 */ { false, 0x37c8, 0x37c8 }, +/* 0x37c9 */ { false, 0x37c9, 0x37c9 }, +/* 0x37ca */ { false, 0x37ca, 0x37ca }, +/* 0x37cb */ { false, 0x37cb, 0x37cb }, +/* 0x37cc */ { false, 0x37cc, 0x37cc }, +/* 0x37cd */ { false, 0x37cd, 0x37cd }, +/* 0x37ce */ { false, 0x37ce, 0x37ce }, +/* 0x37cf */ { false, 0x37cf, 0x37cf }, +/* 0x37d0 */ { false, 0x37d0, 0x37d0 }, +/* 0x37d1 */ { false, 0x37d1, 0x37d1 }, +/* 0x37d2 */ { false, 0x37d2, 0x37d2 }, +/* 0x37d3 */ { false, 0x37d3, 0x37d3 }, +/* 0x37d4 */ { false, 0x37d4, 0x37d4 }, +/* 0x37d5 */ { false, 0x37d5, 0x37d5 }, +/* 0x37d6 */ { false, 0x37d6, 0x37d6 }, +/* 0x37d7 */ { false, 0x37d7, 0x37d7 }, +/* 0x37d8 */ { false, 0x37d8, 0x37d8 }, +/* 0x37d9 */ { false, 0x37d9, 0x37d9 }, +/* 0x37da */ { false, 0x37da, 0x37da }, +/* 0x37db */ { false, 0x37db, 0x37db }, +/* 0x37dc */ { false, 0x37dc, 0x37dc }, +/* 0x37dd */ { false, 0x37dd, 0x37dd }, +/* 0x37de */ { false, 0x37de, 0x37de }, +/* 0x37df */ { false, 0x37df, 0x37df }, +/* 0x37e0 */ { false, 0x37e0, 0x37e0 }, +/* 0x37e1 */ { false, 0x37e1, 0x37e1 }, +/* 0x37e2 */ { false, 0x37e2, 0x37e2 }, +/* 0x37e3 */ { false, 0x37e3, 0x37e3 }, +/* 0x37e4 */ { false, 0x37e4, 0x37e4 }, +/* 0x37e5 */ { false, 0x37e5, 0x37e5 }, +/* 0x37e6 */ { false, 0x37e6, 0x37e6 }, +/* 0x37e7 */ { false, 0x37e7, 0x37e7 }, +/* 0x37e8 */ { false, 0x37e8, 0x37e8 }, +/* 0x37e9 */ { false, 0x37e9, 0x37e9 }, +/* 0x37ea */ { false, 0x37ea, 0x37ea }, +/* 0x37eb */ { false, 0x37eb, 0x37eb }, +/* 0x37ec */ { false, 0x37ec, 0x37ec }, +/* 0x37ed */ { false, 0x37ed, 0x37ed }, +/* 0x37ee */ { false, 0x37ee, 0x37ee }, +/* 0x37ef */ { false, 0x37ef, 0x37ef }, +/* 0x37f0 */ { false, 0x37f0, 0x37f0 }, +/* 0x37f1 */ { false, 0x37f1, 0x37f1 }, +/* 0x37f2 */ { false, 0x37f2, 0x37f2 }, +/* 0x37f3 */ { false, 0x37f3, 0x37f3 }, +/* 0x37f4 */ { false, 0x37f4, 0x37f4 }, +/* 0x37f5 */ { false, 0x37f5, 0x37f5 }, +/* 0x37f6 */ { false, 0x37f6, 0x37f6 }, +/* 0x37f7 */ { false, 0x37f7, 0x37f7 }, +/* 0x37f8 */ { false, 0x37f8, 0x37f8 }, +/* 0x37f9 */ { false, 0x37f9, 0x37f9 }, +/* 0x37fa */ { false, 0x37fa, 0x37fa }, +/* 0x37fb */ { false, 0x37fb, 0x37fb }, +/* 0x37fc */ { false, 0x37fc, 0x37fc }, +/* 0x37fd */ { false, 0x37fd, 0x37fd }, +/* 0x37fe */ { false, 0x37fe, 0x37fe }, +/* 0x37ff */ { false, 0x37ff, 0x37ff }, +/* 0x3800 */ { false, 0x3800, 0x3800 }, +/* 0x3801 */ { false, 0x3801, 0x3801 }, +/* 0x3802 */ { false, 0x3802, 0x3802 }, +/* 0x3803 */ { false, 0x3803, 0x3803 }, +/* 0x3804 */ { false, 0x3804, 0x3804 }, +/* 0x3805 */ { false, 0x3805, 0x3805 }, +/* 0x3806 */ { false, 0x3806, 0x3806 }, +/* 0x3807 */ { false, 0x3807, 0x3807 }, +/* 0x3808 */ { false, 0x3808, 0x3808 }, +/* 0x3809 */ { false, 0x3809, 0x3809 }, +/* 0x380a */ { false, 0x380a, 0x380a }, +/* 0x380b */ { false, 0x380b, 0x380b }, +/* 0x380c */ { false, 0x380c, 0x380c }, +/* 0x380d */ { false, 0x380d, 0x380d }, +/* 0x380e */ { false, 0x380e, 0x380e }, +/* 0x380f */ { false, 0x380f, 0x380f }, +/* 0x3810 */ { false, 0x3810, 0x3810 }, +/* 0x3811 */ { false, 0x3811, 0x3811 }, +/* 0x3812 */ { false, 0x3812, 0x3812 }, +/* 0x3813 */ { false, 0x3813, 0x3813 }, +/* 0x3814 */ { false, 0x3814, 0x3814 }, +/* 0x3815 */ { false, 0x3815, 0x3815 }, +/* 0x3816 */ { false, 0x3816, 0x3816 }, +/* 0x3817 */ { false, 0x3817, 0x3817 }, +/* 0x3818 */ { false, 0x3818, 0x3818 }, +/* 0x3819 */ { false, 0x3819, 0x3819 }, +/* 0x381a */ { false, 0x381a, 0x381a }, +/* 0x381b */ { false, 0x381b, 0x381b }, +/* 0x381c */ { false, 0x381c, 0x381c }, +/* 0x381d */ { false, 0x381d, 0x381d }, +/* 0x381e */ { false, 0x381e, 0x381e }, +/* 0x381f */ { false, 0x381f, 0x381f }, +/* 0x3820 */ { false, 0x3820, 0x3820 }, +/* 0x3821 */ { false, 0x3821, 0x3821 }, +/* 0x3822 */ { false, 0x3822, 0x3822 }, +/* 0x3823 */ { false, 0x3823, 0x3823 }, +/* 0x3824 */ { false, 0x3824, 0x3824 }, +/* 0x3825 */ { false, 0x3825, 0x3825 }, +/* 0x3826 */ { false, 0x3826, 0x3826 }, +/* 0x3827 */ { false, 0x3827, 0x3827 }, +/* 0x3828 */ { false, 0x3828, 0x3828 }, +/* 0x3829 */ { false, 0x3829, 0x3829 }, +/* 0x382a */ { false, 0x382a, 0x382a }, +/* 0x382b */ { false, 0x382b, 0x382b }, +/* 0x382c */ { false, 0x382c, 0x382c }, +/* 0x382d */ { false, 0x382d, 0x382d }, +/* 0x382e */ { false, 0x382e, 0x382e }, +/* 0x382f */ { false, 0x382f, 0x382f }, +/* 0x3830 */ { false, 0x3830, 0x3830 }, +/* 0x3831 */ { false, 0x3831, 0x3831 }, +/* 0x3832 */ { false, 0x3832, 0x3832 }, +/* 0x3833 */ { false, 0x3833, 0x3833 }, +/* 0x3834 */ { false, 0x3834, 0x3834 }, +/* 0x3835 */ { false, 0x3835, 0x3835 }, +/* 0x3836 */ { false, 0x3836, 0x3836 }, +/* 0x3837 */ { false, 0x3837, 0x3837 }, +/* 0x3838 */ { false, 0x3838, 0x3838 }, +/* 0x3839 */ { false, 0x3839, 0x3839 }, +/* 0x383a */ { false, 0x383a, 0x383a }, +/* 0x383b */ { false, 0x383b, 0x383b }, +/* 0x383c */ { false, 0x383c, 0x383c }, +/* 0x383d */ { false, 0x383d, 0x383d }, +/* 0x383e */ { false, 0x383e, 0x383e }, +/* 0x383f */ { false, 0x383f, 0x383f }, +/* 0x3840 */ { false, 0x3840, 0x3840 }, +/* 0x3841 */ { false, 0x3841, 0x3841 }, +/* 0x3842 */ { false, 0x3842, 0x3842 }, +/* 0x3843 */ { false, 0x3843, 0x3843 }, +/* 0x3844 */ { false, 0x3844, 0x3844 }, +/* 0x3845 */ { false, 0x3845, 0x3845 }, +/* 0x3846 */ { false, 0x3846, 0x3846 }, +/* 0x3847 */ { false, 0x3847, 0x3847 }, +/* 0x3848 */ { false, 0x3848, 0x3848 }, +/* 0x3849 */ { false, 0x3849, 0x3849 }, +/* 0x384a */ { false, 0x384a, 0x384a }, +/* 0x384b */ { false, 0x384b, 0x384b }, +/* 0x384c */ { false, 0x384c, 0x384c }, +/* 0x384d */ { false, 0x384d, 0x384d }, +/* 0x384e */ { false, 0x384e, 0x384e }, +/* 0x384f */ { false, 0x384f, 0x384f }, +/* 0x3850 */ { false, 0x3850, 0x3850 }, +/* 0x3851 */ { false, 0x3851, 0x3851 }, +/* 0x3852 */ { false, 0x3852, 0x3852 }, +/* 0x3853 */ { false, 0x3853, 0x3853 }, +/* 0x3854 */ { false, 0x3854, 0x3854 }, +/* 0x3855 */ { false, 0x3855, 0x3855 }, +/* 0x3856 */ { false, 0x3856, 0x3856 }, +/* 0x3857 */ { false, 0x3857, 0x3857 }, +/* 0x3858 */ { false, 0x3858, 0x3858 }, +/* 0x3859 */ { false, 0x3859, 0x3859 }, +/* 0x385a */ { false, 0x385a, 0x385a }, +/* 0x385b */ { false, 0x385b, 0x385b }, +/* 0x385c */ { false, 0x385c, 0x385c }, +/* 0x385d */ { false, 0x385d, 0x385d }, +/* 0x385e */ { false, 0x385e, 0x385e }, +/* 0x385f */ { false, 0x385f, 0x385f }, +/* 0x3860 */ { false, 0x3860, 0x3860 }, +/* 0x3861 */ { false, 0x3861, 0x3861 }, +/* 0x3862 */ { false, 0x3862, 0x3862 }, +/* 0x3863 */ { false, 0x3863, 0x3863 }, +/* 0x3864 */ { false, 0x3864, 0x3864 }, +/* 0x3865 */ { false, 0x3865, 0x3865 }, +/* 0x3866 */ { false, 0x3866, 0x3866 }, +/* 0x3867 */ { false, 0x3867, 0x3867 }, +/* 0x3868 */ { false, 0x3868, 0x3868 }, +/* 0x3869 */ { false, 0x3869, 0x3869 }, +/* 0x386a */ { false, 0x386a, 0x386a }, +/* 0x386b */ { false, 0x386b, 0x386b }, +/* 0x386c */ { false, 0x386c, 0x386c }, +/* 0x386d */ { false, 0x386d, 0x386d }, +/* 0x386e */ { false, 0x386e, 0x386e }, +/* 0x386f */ { false, 0x386f, 0x386f }, +/* 0x3870 */ { false, 0x3870, 0x3870 }, +/* 0x3871 */ { false, 0x3871, 0x3871 }, +/* 0x3872 */ { false, 0x3872, 0x3872 }, +/* 0x3873 */ { false, 0x3873, 0x3873 }, +/* 0x3874 */ { false, 0x3874, 0x3874 }, +/* 0x3875 */ { false, 0x3875, 0x3875 }, +/* 0x3876 */ { false, 0x3876, 0x3876 }, +/* 0x3877 */ { false, 0x3877, 0x3877 }, +/* 0x3878 */ { false, 0x3878, 0x3878 }, +/* 0x3879 */ { false, 0x3879, 0x3879 }, +/* 0x387a */ { false, 0x387a, 0x387a }, +/* 0x387b */ { false, 0x387b, 0x387b }, +/* 0x387c */ { false, 0x387c, 0x387c }, +/* 0x387d */ { false, 0x387d, 0x387d }, +/* 0x387e */ { false, 0x387e, 0x387e }, +/* 0x387f */ { false, 0x387f, 0x387f }, +/* 0x3880 */ { false, 0x3880, 0x3880 }, +/* 0x3881 */ { false, 0x3881, 0x3881 }, +/* 0x3882 */ { false, 0x3882, 0x3882 }, +/* 0x3883 */ { false, 0x3883, 0x3883 }, +/* 0x3884 */ { false, 0x3884, 0x3884 }, +/* 0x3885 */ { false, 0x3885, 0x3885 }, +/* 0x3886 */ { false, 0x3886, 0x3886 }, +/* 0x3887 */ { false, 0x3887, 0x3887 }, +/* 0x3888 */ { false, 0x3888, 0x3888 }, +/* 0x3889 */ { false, 0x3889, 0x3889 }, +/* 0x388a */ { false, 0x388a, 0x388a }, +/* 0x388b */ { false, 0x388b, 0x388b }, +/* 0x388c */ { false, 0x388c, 0x388c }, +/* 0x388d */ { false, 0x388d, 0x388d }, +/* 0x388e */ { false, 0x388e, 0x388e }, +/* 0x388f */ { false, 0x388f, 0x388f }, +/* 0x3890 */ { false, 0x3890, 0x3890 }, +/* 0x3891 */ { false, 0x3891, 0x3891 }, +/* 0x3892 */ { false, 0x3892, 0x3892 }, +/* 0x3893 */ { false, 0x3893, 0x3893 }, +/* 0x3894 */ { false, 0x3894, 0x3894 }, +/* 0x3895 */ { false, 0x3895, 0x3895 }, +/* 0x3896 */ { false, 0x3896, 0x3896 }, +/* 0x3897 */ { false, 0x3897, 0x3897 }, +/* 0x3898 */ { false, 0x3898, 0x3898 }, +/* 0x3899 */ { false, 0x3899, 0x3899 }, +/* 0x389a */ { false, 0x389a, 0x389a }, +/* 0x389b */ { false, 0x389b, 0x389b }, +/* 0x389c */ { false, 0x389c, 0x389c }, +/* 0x389d */ { false, 0x389d, 0x389d }, +/* 0x389e */ { false, 0x389e, 0x389e }, +/* 0x389f */ { false, 0x389f, 0x389f }, +/* 0x38a0 */ { false, 0x38a0, 0x38a0 }, +/* 0x38a1 */ { false, 0x38a1, 0x38a1 }, +/* 0x38a2 */ { false, 0x38a2, 0x38a2 }, +/* 0x38a3 */ { false, 0x38a3, 0x38a3 }, +/* 0x38a4 */ { false, 0x38a4, 0x38a4 }, +/* 0x38a5 */ { false, 0x38a5, 0x38a5 }, +/* 0x38a6 */ { false, 0x38a6, 0x38a6 }, +/* 0x38a7 */ { false, 0x38a7, 0x38a7 }, +/* 0x38a8 */ { false, 0x38a8, 0x38a8 }, +/* 0x38a9 */ { false, 0x38a9, 0x38a9 }, +/* 0x38aa */ { false, 0x38aa, 0x38aa }, +/* 0x38ab */ { false, 0x38ab, 0x38ab }, +/* 0x38ac */ { false, 0x38ac, 0x38ac }, +/* 0x38ad */ { false, 0x38ad, 0x38ad }, +/* 0x38ae */ { false, 0x38ae, 0x38ae }, +/* 0x38af */ { false, 0x38af, 0x38af }, +/* 0x38b0 */ { false, 0x38b0, 0x38b0 }, +/* 0x38b1 */ { false, 0x38b1, 0x38b1 }, +/* 0x38b2 */ { false, 0x38b2, 0x38b2 }, +/* 0x38b3 */ { false, 0x38b3, 0x38b3 }, +/* 0x38b4 */ { false, 0x38b4, 0x38b4 }, +/* 0x38b5 */ { false, 0x38b5, 0x38b5 }, +/* 0x38b6 */ { false, 0x38b6, 0x38b6 }, +/* 0x38b7 */ { false, 0x38b7, 0x38b7 }, +/* 0x38b8 */ { false, 0x38b8, 0x38b8 }, +/* 0x38b9 */ { false, 0x38b9, 0x38b9 }, +/* 0x38ba */ { false, 0x38ba, 0x38ba }, +/* 0x38bb */ { false, 0x38bb, 0x38bb }, +/* 0x38bc */ { false, 0x38bc, 0x38bc }, +/* 0x38bd */ { false, 0x38bd, 0x38bd }, +/* 0x38be */ { false, 0x38be, 0x38be }, +/* 0x38bf */ { false, 0x38bf, 0x38bf }, +/* 0x38c0 */ { false, 0x38c0, 0x38c0 }, +/* 0x38c1 */ { false, 0x38c1, 0x38c1 }, +/* 0x38c2 */ { false, 0x38c2, 0x38c2 }, +/* 0x38c3 */ { false, 0x38c3, 0x38c3 }, +/* 0x38c4 */ { false, 0x38c4, 0x38c4 }, +/* 0x38c5 */ { false, 0x38c5, 0x38c5 }, +/* 0x38c6 */ { false, 0x38c6, 0x38c6 }, +/* 0x38c7 */ { false, 0x38c7, 0x38c7 }, +/* 0x38c8 */ { false, 0x38c8, 0x38c8 }, +/* 0x38c9 */ { false, 0x38c9, 0x38c9 }, +/* 0x38ca */ { false, 0x38ca, 0x38ca }, +/* 0x38cb */ { false, 0x38cb, 0x38cb }, +/* 0x38cc */ { false, 0x38cc, 0x38cc }, +/* 0x38cd */ { false, 0x38cd, 0x38cd }, +/* 0x38ce */ { false, 0x38ce, 0x38ce }, +/* 0x38cf */ { false, 0x38cf, 0x38cf }, +/* 0x38d0 */ { false, 0x38d0, 0x38d0 }, +/* 0x38d1 */ { false, 0x38d1, 0x38d1 }, +/* 0x38d2 */ { false, 0x38d2, 0x38d2 }, +/* 0x38d3 */ { false, 0x38d3, 0x38d3 }, +/* 0x38d4 */ { false, 0x38d4, 0x38d4 }, +/* 0x38d5 */ { false, 0x38d5, 0x38d5 }, +/* 0x38d6 */ { false, 0x38d6, 0x38d6 }, +/* 0x38d7 */ { false, 0x38d7, 0x38d7 }, +/* 0x38d8 */ { false, 0x38d8, 0x38d8 }, +/* 0x38d9 */ { false, 0x38d9, 0x38d9 }, +/* 0x38da */ { false, 0x38da, 0x38da }, +/* 0x38db */ { false, 0x38db, 0x38db }, +/* 0x38dc */ { false, 0x38dc, 0x38dc }, +/* 0x38dd */ { false, 0x38dd, 0x38dd }, +/* 0x38de */ { false, 0x38de, 0x38de }, +/* 0x38df */ { false, 0x38df, 0x38df }, +/* 0x38e0 */ { false, 0x38e0, 0x38e0 }, +/* 0x38e1 */ { false, 0x38e1, 0x38e1 }, +/* 0x38e2 */ { false, 0x38e2, 0x38e2 }, +/* 0x38e3 */ { false, 0x38e3, 0x38e3 }, +/* 0x38e4 */ { false, 0x38e4, 0x38e4 }, +/* 0x38e5 */ { false, 0x38e5, 0x38e5 }, +/* 0x38e6 */ { false, 0x38e6, 0x38e6 }, +/* 0x38e7 */ { false, 0x38e7, 0x38e7 }, +/* 0x38e8 */ { false, 0x38e8, 0x38e8 }, +/* 0x38e9 */ { false, 0x38e9, 0x38e9 }, +/* 0x38ea */ { false, 0x38ea, 0x38ea }, +/* 0x38eb */ { false, 0x38eb, 0x38eb }, +/* 0x38ec */ { false, 0x38ec, 0x38ec }, +/* 0x38ed */ { false, 0x38ed, 0x38ed }, +/* 0x38ee */ { false, 0x38ee, 0x38ee }, +/* 0x38ef */ { false, 0x38ef, 0x38ef }, +/* 0x38f0 */ { false, 0x38f0, 0x38f0 }, +/* 0x38f1 */ { false, 0x38f1, 0x38f1 }, +/* 0x38f2 */ { false, 0x38f2, 0x38f2 }, +/* 0x38f3 */ { false, 0x38f3, 0x38f3 }, +/* 0x38f4 */ { false, 0x38f4, 0x38f4 }, +/* 0x38f5 */ { false, 0x38f5, 0x38f5 }, +/* 0x38f6 */ { false, 0x38f6, 0x38f6 }, +/* 0x38f7 */ { false, 0x38f7, 0x38f7 }, +/* 0x38f8 */ { false, 0x38f8, 0x38f8 }, +/* 0x38f9 */ { false, 0x38f9, 0x38f9 }, +/* 0x38fa */ { false, 0x38fa, 0x38fa }, +/* 0x38fb */ { false, 0x38fb, 0x38fb }, +/* 0x38fc */ { false, 0x38fc, 0x38fc }, +/* 0x38fd */ { false, 0x38fd, 0x38fd }, +/* 0x38fe */ { false, 0x38fe, 0x38fe }, +/* 0x38ff */ { false, 0x38ff, 0x38ff }, +/* 0x3900 */ { false, 0x3900, 0x3900 }, +/* 0x3901 */ { false, 0x3901, 0x3901 }, +/* 0x3902 */ { false, 0x3902, 0x3902 }, +/* 0x3903 */ { false, 0x3903, 0x3903 }, +/* 0x3904 */ { false, 0x3904, 0x3904 }, +/* 0x3905 */ { false, 0x3905, 0x3905 }, +/* 0x3906 */ { false, 0x3906, 0x3906 }, +/* 0x3907 */ { false, 0x3907, 0x3907 }, +/* 0x3908 */ { false, 0x3908, 0x3908 }, +/* 0x3909 */ { false, 0x3909, 0x3909 }, +/* 0x390a */ { false, 0x390a, 0x390a }, +/* 0x390b */ { false, 0x390b, 0x390b }, +/* 0x390c */ { false, 0x390c, 0x390c }, +/* 0x390d */ { false, 0x390d, 0x390d }, +/* 0x390e */ { false, 0x390e, 0x390e }, +/* 0x390f */ { false, 0x390f, 0x390f }, +/* 0x3910 */ { false, 0x3910, 0x3910 }, +/* 0x3911 */ { false, 0x3911, 0x3911 }, +/* 0x3912 */ { false, 0x3912, 0x3912 }, +/* 0x3913 */ { false, 0x3913, 0x3913 }, +/* 0x3914 */ { false, 0x3914, 0x3914 }, +/* 0x3915 */ { false, 0x3915, 0x3915 }, +/* 0x3916 */ { false, 0x3916, 0x3916 }, +/* 0x3917 */ { false, 0x3917, 0x3917 }, +/* 0x3918 */ { false, 0x3918, 0x3918 }, +/* 0x3919 */ { false, 0x3919, 0x3919 }, +/* 0x391a */ { false, 0x391a, 0x391a }, +/* 0x391b */ { false, 0x391b, 0x391b }, +/* 0x391c */ { false, 0x391c, 0x391c }, +/* 0x391d */ { false, 0x391d, 0x391d }, +/* 0x391e */ { false, 0x391e, 0x391e }, +/* 0x391f */ { false, 0x391f, 0x391f }, +/* 0x3920 */ { false, 0x3920, 0x3920 }, +/* 0x3921 */ { false, 0x3921, 0x3921 }, +/* 0x3922 */ { false, 0x3922, 0x3922 }, +/* 0x3923 */ { false, 0x3923, 0x3923 }, +/* 0x3924 */ { false, 0x3924, 0x3924 }, +/* 0x3925 */ { false, 0x3925, 0x3925 }, +/* 0x3926 */ { false, 0x3926, 0x3926 }, +/* 0x3927 */ { false, 0x3927, 0x3927 }, +/* 0x3928 */ { false, 0x3928, 0x3928 }, +/* 0x3929 */ { false, 0x3929, 0x3929 }, +/* 0x392a */ { false, 0x392a, 0x392a }, +/* 0x392b */ { false, 0x392b, 0x392b }, +/* 0x392c */ { false, 0x392c, 0x392c }, +/* 0x392d */ { false, 0x392d, 0x392d }, +/* 0x392e */ { false, 0x392e, 0x392e }, +/* 0x392f */ { false, 0x392f, 0x392f }, +/* 0x3930 */ { false, 0x3930, 0x3930 }, +/* 0x3931 */ { false, 0x3931, 0x3931 }, +/* 0x3932 */ { false, 0x3932, 0x3932 }, +/* 0x3933 */ { false, 0x3933, 0x3933 }, +/* 0x3934 */ { false, 0x3934, 0x3934 }, +/* 0x3935 */ { false, 0x3935, 0x3935 }, +/* 0x3936 */ { false, 0x3936, 0x3936 }, +/* 0x3937 */ { false, 0x3937, 0x3937 }, +/* 0x3938 */ { false, 0x3938, 0x3938 }, +/* 0x3939 */ { false, 0x3939, 0x3939 }, +/* 0x393a */ { false, 0x393a, 0x393a }, +/* 0x393b */ { false, 0x393b, 0x393b }, +/* 0x393c */ { false, 0x393c, 0x393c }, +/* 0x393d */ { false, 0x393d, 0x393d }, +/* 0x393e */ { false, 0x393e, 0x393e }, +/* 0x393f */ { false, 0x393f, 0x393f }, +/* 0x3940 */ { false, 0x3940, 0x3940 }, +/* 0x3941 */ { false, 0x3941, 0x3941 }, +/* 0x3942 */ { false, 0x3942, 0x3942 }, +/* 0x3943 */ { false, 0x3943, 0x3943 }, +/* 0x3944 */ { false, 0x3944, 0x3944 }, +/* 0x3945 */ { false, 0x3945, 0x3945 }, +/* 0x3946 */ { false, 0x3946, 0x3946 }, +/* 0x3947 */ { false, 0x3947, 0x3947 }, +/* 0x3948 */ { false, 0x3948, 0x3948 }, +/* 0x3949 */ { false, 0x3949, 0x3949 }, +/* 0x394a */ { false, 0x394a, 0x394a }, +/* 0x394b */ { false, 0x394b, 0x394b }, +/* 0x394c */ { false, 0x394c, 0x394c }, +/* 0x394d */ { false, 0x394d, 0x394d }, +/* 0x394e */ { false, 0x394e, 0x394e }, +/* 0x394f */ { false, 0x394f, 0x394f }, +/* 0x3950 */ { false, 0x3950, 0x3950 }, +/* 0x3951 */ { false, 0x3951, 0x3951 }, +/* 0x3952 */ { false, 0x3952, 0x3952 }, +/* 0x3953 */ { false, 0x3953, 0x3953 }, +/* 0x3954 */ { false, 0x3954, 0x3954 }, +/* 0x3955 */ { false, 0x3955, 0x3955 }, +/* 0x3956 */ { false, 0x3956, 0x3956 }, +/* 0x3957 */ { false, 0x3957, 0x3957 }, +/* 0x3958 */ { false, 0x3958, 0x3958 }, +/* 0x3959 */ { false, 0x3959, 0x3959 }, +/* 0x395a */ { false, 0x395a, 0x395a }, +/* 0x395b */ { false, 0x395b, 0x395b }, +/* 0x395c */ { false, 0x395c, 0x395c }, +/* 0x395d */ { false, 0x395d, 0x395d }, +/* 0x395e */ { false, 0x395e, 0x395e }, +/* 0x395f */ { false, 0x395f, 0x395f }, +/* 0x3960 */ { false, 0x3960, 0x3960 }, +/* 0x3961 */ { false, 0x3961, 0x3961 }, +/* 0x3962 */ { false, 0x3962, 0x3962 }, +/* 0x3963 */ { false, 0x3963, 0x3963 }, +/* 0x3964 */ { false, 0x3964, 0x3964 }, +/* 0x3965 */ { false, 0x3965, 0x3965 }, +/* 0x3966 */ { false, 0x3966, 0x3966 }, +/* 0x3967 */ { false, 0x3967, 0x3967 }, +/* 0x3968 */ { false, 0x3968, 0x3968 }, +/* 0x3969 */ { false, 0x3969, 0x3969 }, +/* 0x396a */ { false, 0x396a, 0x396a }, +/* 0x396b */ { false, 0x396b, 0x396b }, +/* 0x396c */ { false, 0x396c, 0x396c }, +/* 0x396d */ { false, 0x396d, 0x396d }, +/* 0x396e */ { false, 0x396e, 0x396e }, +/* 0x396f */ { false, 0x396f, 0x396f }, +/* 0x3970 */ { false, 0x3970, 0x3970 }, +/* 0x3971 */ { false, 0x3971, 0x3971 }, +/* 0x3972 */ { false, 0x3972, 0x3972 }, +/* 0x3973 */ { false, 0x3973, 0x3973 }, +/* 0x3974 */ { false, 0x3974, 0x3974 }, +/* 0x3975 */ { false, 0x3975, 0x3975 }, +/* 0x3976 */ { false, 0x3976, 0x3976 }, +/* 0x3977 */ { false, 0x3977, 0x3977 }, +/* 0x3978 */ { false, 0x3978, 0x3978 }, +/* 0x3979 */ { false, 0x3979, 0x3979 }, +/* 0x397a */ { false, 0x397a, 0x397a }, +/* 0x397b */ { false, 0x397b, 0x397b }, +/* 0x397c */ { false, 0x397c, 0x397c }, +/* 0x397d */ { false, 0x397d, 0x397d }, +/* 0x397e */ { false, 0x397e, 0x397e }, +/* 0x397f */ { false, 0x397f, 0x397f }, +/* 0x3980 */ { false, 0x3980, 0x3980 }, +/* 0x3981 */ { false, 0x3981, 0x3981 }, +/* 0x3982 */ { false, 0x3982, 0x3982 }, +/* 0x3983 */ { false, 0x3983, 0x3983 }, +/* 0x3984 */ { false, 0x3984, 0x3984 }, +/* 0x3985 */ { false, 0x3985, 0x3985 }, +/* 0x3986 */ { false, 0x3986, 0x3986 }, +/* 0x3987 */ { false, 0x3987, 0x3987 }, +/* 0x3988 */ { false, 0x3988, 0x3988 }, +/* 0x3989 */ { false, 0x3989, 0x3989 }, +/* 0x398a */ { false, 0x398a, 0x398a }, +/* 0x398b */ { false, 0x398b, 0x398b }, +/* 0x398c */ { false, 0x398c, 0x398c }, +/* 0x398d */ { false, 0x398d, 0x398d }, +/* 0x398e */ { false, 0x398e, 0x398e }, +/* 0x398f */ { false, 0x398f, 0x398f }, +/* 0x3990 */ { false, 0x3990, 0x3990 }, +/* 0x3991 */ { false, 0x3991, 0x3991 }, +/* 0x3992 */ { false, 0x3992, 0x3992 }, +/* 0x3993 */ { false, 0x3993, 0x3993 }, +/* 0x3994 */ { false, 0x3994, 0x3994 }, +/* 0x3995 */ { false, 0x3995, 0x3995 }, +/* 0x3996 */ { false, 0x3996, 0x3996 }, +/* 0x3997 */ { false, 0x3997, 0x3997 }, +/* 0x3998 */ { false, 0x3998, 0x3998 }, +/* 0x3999 */ { false, 0x3999, 0x3999 }, +/* 0x399a */ { false, 0x399a, 0x399a }, +/* 0x399b */ { false, 0x399b, 0x399b }, +/* 0x399c */ { false, 0x399c, 0x399c }, +/* 0x399d */ { false, 0x399d, 0x399d }, +/* 0x399e */ { false, 0x399e, 0x399e }, +/* 0x399f */ { false, 0x399f, 0x399f }, +/* 0x39a0 */ { false, 0x39a0, 0x39a0 }, +/* 0x39a1 */ { false, 0x39a1, 0x39a1 }, +/* 0x39a2 */ { false, 0x39a2, 0x39a2 }, +/* 0x39a3 */ { false, 0x39a3, 0x39a3 }, +/* 0x39a4 */ { false, 0x39a4, 0x39a4 }, +/* 0x39a5 */ { false, 0x39a5, 0x39a5 }, +/* 0x39a6 */ { false, 0x39a6, 0x39a6 }, +/* 0x39a7 */ { false, 0x39a7, 0x39a7 }, +/* 0x39a8 */ { false, 0x39a8, 0x39a8 }, +/* 0x39a9 */ { false, 0x39a9, 0x39a9 }, +/* 0x39aa */ { false, 0x39aa, 0x39aa }, +/* 0x39ab */ { false, 0x39ab, 0x39ab }, +/* 0x39ac */ { false, 0x39ac, 0x39ac }, +/* 0x39ad */ { false, 0x39ad, 0x39ad }, +/* 0x39ae */ { false, 0x39ae, 0x39ae }, +/* 0x39af */ { false, 0x39af, 0x39af }, +/* 0x39b0 */ { false, 0x39b0, 0x39b0 }, +/* 0x39b1 */ { false, 0x39b1, 0x39b1 }, +/* 0x39b2 */ { false, 0x39b2, 0x39b2 }, +/* 0x39b3 */ { false, 0x39b3, 0x39b3 }, +/* 0x39b4 */ { false, 0x39b4, 0x39b4 }, +/* 0x39b5 */ { false, 0x39b5, 0x39b5 }, +/* 0x39b6 */ { false, 0x39b6, 0x39b6 }, +/* 0x39b7 */ { false, 0x39b7, 0x39b7 }, +/* 0x39b8 */ { false, 0x39b8, 0x39b8 }, +/* 0x39b9 */ { false, 0x39b9, 0x39b9 }, +/* 0x39ba */ { false, 0x39ba, 0x39ba }, +/* 0x39bb */ { false, 0x39bb, 0x39bb }, +/* 0x39bc */ { false, 0x39bc, 0x39bc }, +/* 0x39bd */ { false, 0x39bd, 0x39bd }, +/* 0x39be */ { false, 0x39be, 0x39be }, +/* 0x39bf */ { false, 0x39bf, 0x39bf }, +/* 0x39c0 */ { false, 0x39c0, 0x39c0 }, +/* 0x39c1 */ { false, 0x39c1, 0x39c1 }, +/* 0x39c2 */ { false, 0x39c2, 0x39c2 }, +/* 0x39c3 */ { false, 0x39c3, 0x39c3 }, +/* 0x39c4 */ { false, 0x39c4, 0x39c4 }, +/* 0x39c5 */ { false, 0x39c5, 0x39c5 }, +/* 0x39c6 */ { false, 0x39c6, 0x39c6 }, +/* 0x39c7 */ { false, 0x39c7, 0x39c7 }, +/* 0x39c8 */ { false, 0x39c8, 0x39c8 }, +/* 0x39c9 */ { false, 0x39c9, 0x39c9 }, +/* 0x39ca */ { false, 0x39ca, 0x39ca }, +/* 0x39cb */ { false, 0x39cb, 0x39cb }, +/* 0x39cc */ { false, 0x39cc, 0x39cc }, +/* 0x39cd */ { false, 0x39cd, 0x39cd }, +/* 0x39ce */ { false, 0x39ce, 0x39ce }, +/* 0x39cf */ { false, 0x39cf, 0x39cf }, +/* 0x39d0 */ { false, 0x39d0, 0x39d0 }, +/* 0x39d1 */ { false, 0x39d1, 0x39d1 }, +/* 0x39d2 */ { false, 0x39d2, 0x39d2 }, +/* 0x39d3 */ { false, 0x39d3, 0x39d3 }, +/* 0x39d4 */ { false, 0x39d4, 0x39d4 }, +/* 0x39d5 */ { false, 0x39d5, 0x39d5 }, +/* 0x39d6 */ { false, 0x39d6, 0x39d6 }, +/* 0x39d7 */ { false, 0x39d7, 0x39d7 }, +/* 0x39d8 */ { false, 0x39d8, 0x39d8 }, +/* 0x39d9 */ { false, 0x39d9, 0x39d9 }, +/* 0x39da */ { false, 0x39da, 0x39da }, +/* 0x39db */ { false, 0x39db, 0x39db }, +/* 0x39dc */ { false, 0x39dc, 0x39dc }, +/* 0x39dd */ { false, 0x39dd, 0x39dd }, +/* 0x39de */ { false, 0x39de, 0x39de }, +/* 0x39df */ { false, 0x39df, 0x39df }, +/* 0x39e0 */ { false, 0x39e0, 0x39e0 }, +/* 0x39e1 */ { false, 0x39e1, 0x39e1 }, +/* 0x39e2 */ { false, 0x39e2, 0x39e2 }, +/* 0x39e3 */ { false, 0x39e3, 0x39e3 }, +/* 0x39e4 */ { false, 0x39e4, 0x39e4 }, +/* 0x39e5 */ { false, 0x39e5, 0x39e5 }, +/* 0x39e6 */ { false, 0x39e6, 0x39e6 }, +/* 0x39e7 */ { false, 0x39e7, 0x39e7 }, +/* 0x39e8 */ { false, 0x39e8, 0x39e8 }, +/* 0x39e9 */ { false, 0x39e9, 0x39e9 }, +/* 0x39ea */ { false, 0x39ea, 0x39ea }, +/* 0x39eb */ { false, 0x39eb, 0x39eb }, +/* 0x39ec */ { false, 0x39ec, 0x39ec }, +/* 0x39ed */ { false, 0x39ed, 0x39ed }, +/* 0x39ee */ { false, 0x39ee, 0x39ee }, +/* 0x39ef */ { false, 0x39ef, 0x39ef }, +/* 0x39f0 */ { false, 0x39f0, 0x39f0 }, +/* 0x39f1 */ { false, 0x39f1, 0x39f1 }, +/* 0x39f2 */ { false, 0x39f2, 0x39f2 }, +/* 0x39f3 */ { false, 0x39f3, 0x39f3 }, +/* 0x39f4 */ { false, 0x39f4, 0x39f4 }, +/* 0x39f5 */ { false, 0x39f5, 0x39f5 }, +/* 0x39f6 */ { false, 0x39f6, 0x39f6 }, +/* 0x39f7 */ { false, 0x39f7, 0x39f7 }, +/* 0x39f8 */ { false, 0x39f8, 0x39f8 }, +/* 0x39f9 */ { false, 0x39f9, 0x39f9 }, +/* 0x39fa */ { false, 0x39fa, 0x39fa }, +/* 0x39fb */ { false, 0x39fb, 0x39fb }, +/* 0x39fc */ { false, 0x39fc, 0x39fc }, +/* 0x39fd */ { false, 0x39fd, 0x39fd }, +/* 0x39fe */ { false, 0x39fe, 0x39fe }, +/* 0x39ff */ { false, 0x39ff, 0x39ff }, +/* 0x3a00 */ { false, 0x3a00, 0x3a00 }, +/* 0x3a01 */ { false, 0x3a01, 0x3a01 }, +/* 0x3a02 */ { false, 0x3a02, 0x3a02 }, +/* 0x3a03 */ { false, 0x3a03, 0x3a03 }, +/* 0x3a04 */ { false, 0x3a04, 0x3a04 }, +/* 0x3a05 */ { false, 0x3a05, 0x3a05 }, +/* 0x3a06 */ { false, 0x3a06, 0x3a06 }, +/* 0x3a07 */ { false, 0x3a07, 0x3a07 }, +/* 0x3a08 */ { false, 0x3a08, 0x3a08 }, +/* 0x3a09 */ { false, 0x3a09, 0x3a09 }, +/* 0x3a0a */ { false, 0x3a0a, 0x3a0a }, +/* 0x3a0b */ { false, 0x3a0b, 0x3a0b }, +/* 0x3a0c */ { false, 0x3a0c, 0x3a0c }, +/* 0x3a0d */ { false, 0x3a0d, 0x3a0d }, +/* 0x3a0e */ { false, 0x3a0e, 0x3a0e }, +/* 0x3a0f */ { false, 0x3a0f, 0x3a0f }, +/* 0x3a10 */ { false, 0x3a10, 0x3a10 }, +/* 0x3a11 */ { false, 0x3a11, 0x3a11 }, +/* 0x3a12 */ { false, 0x3a12, 0x3a12 }, +/* 0x3a13 */ { false, 0x3a13, 0x3a13 }, +/* 0x3a14 */ { false, 0x3a14, 0x3a14 }, +/* 0x3a15 */ { false, 0x3a15, 0x3a15 }, +/* 0x3a16 */ { false, 0x3a16, 0x3a16 }, +/* 0x3a17 */ { false, 0x3a17, 0x3a17 }, +/* 0x3a18 */ { false, 0x3a18, 0x3a18 }, +/* 0x3a19 */ { false, 0x3a19, 0x3a19 }, +/* 0x3a1a */ { false, 0x3a1a, 0x3a1a }, +/* 0x3a1b */ { false, 0x3a1b, 0x3a1b }, +/* 0x3a1c */ { false, 0x3a1c, 0x3a1c }, +/* 0x3a1d */ { false, 0x3a1d, 0x3a1d }, +/* 0x3a1e */ { false, 0x3a1e, 0x3a1e }, +/* 0x3a1f */ { false, 0x3a1f, 0x3a1f }, +/* 0x3a20 */ { false, 0x3a20, 0x3a20 }, +/* 0x3a21 */ { false, 0x3a21, 0x3a21 }, +/* 0x3a22 */ { false, 0x3a22, 0x3a22 }, +/* 0x3a23 */ { false, 0x3a23, 0x3a23 }, +/* 0x3a24 */ { false, 0x3a24, 0x3a24 }, +/* 0x3a25 */ { false, 0x3a25, 0x3a25 }, +/* 0x3a26 */ { false, 0x3a26, 0x3a26 }, +/* 0x3a27 */ { false, 0x3a27, 0x3a27 }, +/* 0x3a28 */ { false, 0x3a28, 0x3a28 }, +/* 0x3a29 */ { false, 0x3a29, 0x3a29 }, +/* 0x3a2a */ { false, 0x3a2a, 0x3a2a }, +/* 0x3a2b */ { false, 0x3a2b, 0x3a2b }, +/* 0x3a2c */ { false, 0x3a2c, 0x3a2c }, +/* 0x3a2d */ { false, 0x3a2d, 0x3a2d }, +/* 0x3a2e */ { false, 0x3a2e, 0x3a2e }, +/* 0x3a2f */ { false, 0x3a2f, 0x3a2f }, +/* 0x3a30 */ { false, 0x3a30, 0x3a30 }, +/* 0x3a31 */ { false, 0x3a31, 0x3a31 }, +/* 0x3a32 */ { false, 0x3a32, 0x3a32 }, +/* 0x3a33 */ { false, 0x3a33, 0x3a33 }, +/* 0x3a34 */ { false, 0x3a34, 0x3a34 }, +/* 0x3a35 */ { false, 0x3a35, 0x3a35 }, +/* 0x3a36 */ { false, 0x3a36, 0x3a36 }, +/* 0x3a37 */ { false, 0x3a37, 0x3a37 }, +/* 0x3a38 */ { false, 0x3a38, 0x3a38 }, +/* 0x3a39 */ { false, 0x3a39, 0x3a39 }, +/* 0x3a3a */ { false, 0x3a3a, 0x3a3a }, +/* 0x3a3b */ { false, 0x3a3b, 0x3a3b }, +/* 0x3a3c */ { false, 0x3a3c, 0x3a3c }, +/* 0x3a3d */ { false, 0x3a3d, 0x3a3d }, +/* 0x3a3e */ { false, 0x3a3e, 0x3a3e }, +/* 0x3a3f */ { false, 0x3a3f, 0x3a3f }, +/* 0x3a40 */ { false, 0x3a40, 0x3a40 }, +/* 0x3a41 */ { false, 0x3a41, 0x3a41 }, +/* 0x3a42 */ { false, 0x3a42, 0x3a42 }, +/* 0x3a43 */ { false, 0x3a43, 0x3a43 }, +/* 0x3a44 */ { false, 0x3a44, 0x3a44 }, +/* 0x3a45 */ { false, 0x3a45, 0x3a45 }, +/* 0x3a46 */ { false, 0x3a46, 0x3a46 }, +/* 0x3a47 */ { false, 0x3a47, 0x3a47 }, +/* 0x3a48 */ { false, 0x3a48, 0x3a48 }, +/* 0x3a49 */ { false, 0x3a49, 0x3a49 }, +/* 0x3a4a */ { false, 0x3a4a, 0x3a4a }, +/* 0x3a4b */ { false, 0x3a4b, 0x3a4b }, +/* 0x3a4c */ { false, 0x3a4c, 0x3a4c }, +/* 0x3a4d */ { false, 0x3a4d, 0x3a4d }, +/* 0x3a4e */ { false, 0x3a4e, 0x3a4e }, +/* 0x3a4f */ { false, 0x3a4f, 0x3a4f }, +/* 0x3a50 */ { false, 0x3a50, 0x3a50 }, +/* 0x3a51 */ { false, 0x3a51, 0x3a51 }, +/* 0x3a52 */ { false, 0x3a52, 0x3a52 }, +/* 0x3a53 */ { false, 0x3a53, 0x3a53 }, +/* 0x3a54 */ { false, 0x3a54, 0x3a54 }, +/* 0x3a55 */ { false, 0x3a55, 0x3a55 }, +/* 0x3a56 */ { false, 0x3a56, 0x3a56 }, +/* 0x3a57 */ { false, 0x3a57, 0x3a57 }, +/* 0x3a58 */ { false, 0x3a58, 0x3a58 }, +/* 0x3a59 */ { false, 0x3a59, 0x3a59 }, +/* 0x3a5a */ { false, 0x3a5a, 0x3a5a }, +/* 0x3a5b */ { false, 0x3a5b, 0x3a5b }, +/* 0x3a5c */ { false, 0x3a5c, 0x3a5c }, +/* 0x3a5d */ { false, 0x3a5d, 0x3a5d }, +/* 0x3a5e */ { false, 0x3a5e, 0x3a5e }, +/* 0x3a5f */ { false, 0x3a5f, 0x3a5f }, +/* 0x3a60 */ { false, 0x3a60, 0x3a60 }, +/* 0x3a61 */ { false, 0x3a61, 0x3a61 }, +/* 0x3a62 */ { false, 0x3a62, 0x3a62 }, +/* 0x3a63 */ { false, 0x3a63, 0x3a63 }, +/* 0x3a64 */ { false, 0x3a64, 0x3a64 }, +/* 0x3a65 */ { false, 0x3a65, 0x3a65 }, +/* 0x3a66 */ { false, 0x3a66, 0x3a66 }, +/* 0x3a67 */ { false, 0x3a67, 0x3a67 }, +/* 0x3a68 */ { false, 0x3a68, 0x3a68 }, +/* 0x3a69 */ { false, 0x3a69, 0x3a69 }, +/* 0x3a6a */ { false, 0x3a6a, 0x3a6a }, +/* 0x3a6b */ { false, 0x3a6b, 0x3a6b }, +/* 0x3a6c */ { false, 0x3a6c, 0x3a6c }, +/* 0x3a6d */ { false, 0x3a6d, 0x3a6d }, +/* 0x3a6e */ { false, 0x3a6e, 0x3a6e }, +/* 0x3a6f */ { false, 0x3a6f, 0x3a6f }, +/* 0x3a70 */ { false, 0x3a70, 0x3a70 }, +/* 0x3a71 */ { false, 0x3a71, 0x3a71 }, +/* 0x3a72 */ { false, 0x3a72, 0x3a72 }, +/* 0x3a73 */ { false, 0x3a73, 0x3a73 }, +/* 0x3a74 */ { false, 0x3a74, 0x3a74 }, +/* 0x3a75 */ { false, 0x3a75, 0x3a75 }, +/* 0x3a76 */ { false, 0x3a76, 0x3a76 }, +/* 0x3a77 */ { false, 0x3a77, 0x3a77 }, +/* 0x3a78 */ { false, 0x3a78, 0x3a78 }, +/* 0x3a79 */ { false, 0x3a79, 0x3a79 }, +/* 0x3a7a */ { false, 0x3a7a, 0x3a7a }, +/* 0x3a7b */ { false, 0x3a7b, 0x3a7b }, +/* 0x3a7c */ { false, 0x3a7c, 0x3a7c }, +/* 0x3a7d */ { false, 0x3a7d, 0x3a7d }, +/* 0x3a7e */ { false, 0x3a7e, 0x3a7e }, +/* 0x3a7f */ { false, 0x3a7f, 0x3a7f }, +/* 0x3a80 */ { false, 0x3a80, 0x3a80 }, +/* 0x3a81 */ { false, 0x3a81, 0x3a81 }, +/* 0x3a82 */ { false, 0x3a82, 0x3a82 }, +/* 0x3a83 */ { false, 0x3a83, 0x3a83 }, +/* 0x3a84 */ { false, 0x3a84, 0x3a84 }, +/* 0x3a85 */ { false, 0x3a85, 0x3a85 }, +/* 0x3a86 */ { false, 0x3a86, 0x3a86 }, +/* 0x3a87 */ { false, 0x3a87, 0x3a87 }, +/* 0x3a88 */ { false, 0x3a88, 0x3a88 }, +/* 0x3a89 */ { false, 0x3a89, 0x3a89 }, +/* 0x3a8a */ { false, 0x3a8a, 0x3a8a }, +/* 0x3a8b */ { false, 0x3a8b, 0x3a8b }, +/* 0x3a8c */ { false, 0x3a8c, 0x3a8c }, +/* 0x3a8d */ { false, 0x3a8d, 0x3a8d }, +/* 0x3a8e */ { false, 0x3a8e, 0x3a8e }, +/* 0x3a8f */ { false, 0x3a8f, 0x3a8f }, +/* 0x3a90 */ { false, 0x3a90, 0x3a90 }, +/* 0x3a91 */ { false, 0x3a91, 0x3a91 }, +/* 0x3a92 */ { false, 0x3a92, 0x3a92 }, +/* 0x3a93 */ { false, 0x3a93, 0x3a93 }, +/* 0x3a94 */ { false, 0x3a94, 0x3a94 }, +/* 0x3a95 */ { false, 0x3a95, 0x3a95 }, +/* 0x3a96 */ { false, 0x3a96, 0x3a96 }, +/* 0x3a97 */ { false, 0x3a97, 0x3a97 }, +/* 0x3a98 */ { false, 0x3a98, 0x3a98 }, +/* 0x3a99 */ { false, 0x3a99, 0x3a99 }, +/* 0x3a9a */ { false, 0x3a9a, 0x3a9a }, +/* 0x3a9b */ { false, 0x3a9b, 0x3a9b }, +/* 0x3a9c */ { false, 0x3a9c, 0x3a9c }, +/* 0x3a9d */ { false, 0x3a9d, 0x3a9d }, +/* 0x3a9e */ { false, 0x3a9e, 0x3a9e }, +/* 0x3a9f */ { false, 0x3a9f, 0x3a9f }, +/* 0x3aa0 */ { false, 0x3aa0, 0x3aa0 }, +/* 0x3aa1 */ { false, 0x3aa1, 0x3aa1 }, +/* 0x3aa2 */ { false, 0x3aa2, 0x3aa2 }, +/* 0x3aa3 */ { false, 0x3aa3, 0x3aa3 }, +/* 0x3aa4 */ { false, 0x3aa4, 0x3aa4 }, +/* 0x3aa5 */ { false, 0x3aa5, 0x3aa5 }, +/* 0x3aa6 */ { false, 0x3aa6, 0x3aa6 }, +/* 0x3aa7 */ { false, 0x3aa7, 0x3aa7 }, +/* 0x3aa8 */ { false, 0x3aa8, 0x3aa8 }, +/* 0x3aa9 */ { false, 0x3aa9, 0x3aa9 }, +/* 0x3aaa */ { false, 0x3aaa, 0x3aaa }, +/* 0x3aab */ { false, 0x3aab, 0x3aab }, +/* 0x3aac */ { false, 0x3aac, 0x3aac }, +/* 0x3aad */ { false, 0x3aad, 0x3aad }, +/* 0x3aae */ { false, 0x3aae, 0x3aae }, +/* 0x3aaf */ { false, 0x3aaf, 0x3aaf }, +/* 0x3ab0 */ { false, 0x3ab0, 0x3ab0 }, +/* 0x3ab1 */ { false, 0x3ab1, 0x3ab1 }, +/* 0x3ab2 */ { false, 0x3ab2, 0x3ab2 }, +/* 0x3ab3 */ { false, 0x3ab3, 0x3ab3 }, +/* 0x3ab4 */ { false, 0x3ab4, 0x3ab4 }, +/* 0x3ab5 */ { false, 0x3ab5, 0x3ab5 }, +/* 0x3ab6 */ { false, 0x3ab6, 0x3ab6 }, +/* 0x3ab7 */ { false, 0x3ab7, 0x3ab7 }, +/* 0x3ab8 */ { false, 0x3ab8, 0x3ab8 }, +/* 0x3ab9 */ { false, 0x3ab9, 0x3ab9 }, +/* 0x3aba */ { false, 0x3aba, 0x3aba }, +/* 0x3abb */ { false, 0x3abb, 0x3abb }, +/* 0x3abc */ { false, 0x3abc, 0x3abc }, +/* 0x3abd */ { false, 0x3abd, 0x3abd }, +/* 0x3abe */ { false, 0x3abe, 0x3abe }, +/* 0x3abf */ { false, 0x3abf, 0x3abf }, +/* 0x3ac0 */ { false, 0x3ac0, 0x3ac0 }, +/* 0x3ac1 */ { false, 0x3ac1, 0x3ac1 }, +/* 0x3ac2 */ { false, 0x3ac2, 0x3ac2 }, +/* 0x3ac3 */ { false, 0x3ac3, 0x3ac3 }, +/* 0x3ac4 */ { false, 0x3ac4, 0x3ac4 }, +/* 0x3ac5 */ { false, 0x3ac5, 0x3ac5 }, +/* 0x3ac6 */ { false, 0x3ac6, 0x3ac6 }, +/* 0x3ac7 */ { false, 0x3ac7, 0x3ac7 }, +/* 0x3ac8 */ { false, 0x3ac8, 0x3ac8 }, +/* 0x3ac9 */ { false, 0x3ac9, 0x3ac9 }, +/* 0x3aca */ { false, 0x3aca, 0x3aca }, +/* 0x3acb */ { false, 0x3acb, 0x3acb }, +/* 0x3acc */ { false, 0x3acc, 0x3acc }, +/* 0x3acd */ { false, 0x3acd, 0x3acd }, +/* 0x3ace */ { false, 0x3ace, 0x3ace }, +/* 0x3acf */ { false, 0x3acf, 0x3acf }, +/* 0x3ad0 */ { false, 0x3ad0, 0x3ad0 }, +/* 0x3ad1 */ { false, 0x3ad1, 0x3ad1 }, +/* 0x3ad2 */ { false, 0x3ad2, 0x3ad2 }, +/* 0x3ad3 */ { false, 0x3ad3, 0x3ad3 }, +/* 0x3ad4 */ { false, 0x3ad4, 0x3ad4 }, +/* 0x3ad5 */ { false, 0x3ad5, 0x3ad5 }, +/* 0x3ad6 */ { false, 0x3ad6, 0x3ad6 }, +/* 0x3ad7 */ { false, 0x3ad7, 0x3ad7 }, +/* 0x3ad8 */ { false, 0x3ad8, 0x3ad8 }, +/* 0x3ad9 */ { false, 0x3ad9, 0x3ad9 }, +/* 0x3ada */ { false, 0x3ada, 0x3ada }, +/* 0x3adb */ { false, 0x3adb, 0x3adb }, +/* 0x3adc */ { false, 0x3adc, 0x3adc }, +/* 0x3add */ { false, 0x3add, 0x3add }, +/* 0x3ade */ { false, 0x3ade, 0x3ade }, +/* 0x3adf */ { false, 0x3adf, 0x3adf }, +/* 0x3ae0 */ { false, 0x3ae0, 0x3ae0 }, +/* 0x3ae1 */ { false, 0x3ae1, 0x3ae1 }, +/* 0x3ae2 */ { false, 0x3ae2, 0x3ae2 }, +/* 0x3ae3 */ { false, 0x3ae3, 0x3ae3 }, +/* 0x3ae4 */ { false, 0x3ae4, 0x3ae4 }, +/* 0x3ae5 */ { false, 0x3ae5, 0x3ae5 }, +/* 0x3ae6 */ { false, 0x3ae6, 0x3ae6 }, +/* 0x3ae7 */ { false, 0x3ae7, 0x3ae7 }, +/* 0x3ae8 */ { false, 0x3ae8, 0x3ae8 }, +/* 0x3ae9 */ { false, 0x3ae9, 0x3ae9 }, +/* 0x3aea */ { false, 0x3aea, 0x3aea }, +/* 0x3aeb */ { false, 0x3aeb, 0x3aeb }, +/* 0x3aec */ { false, 0x3aec, 0x3aec }, +/* 0x3aed */ { false, 0x3aed, 0x3aed }, +/* 0x3aee */ { false, 0x3aee, 0x3aee }, +/* 0x3aef */ { false, 0x3aef, 0x3aef }, +/* 0x3af0 */ { false, 0x3af0, 0x3af0 }, +/* 0x3af1 */ { false, 0x3af1, 0x3af1 }, +/* 0x3af2 */ { false, 0x3af2, 0x3af2 }, +/* 0x3af3 */ { false, 0x3af3, 0x3af3 }, +/* 0x3af4 */ { false, 0x3af4, 0x3af4 }, +/* 0x3af5 */ { false, 0x3af5, 0x3af5 }, +/* 0x3af6 */ { false, 0x3af6, 0x3af6 }, +/* 0x3af7 */ { false, 0x3af7, 0x3af7 }, +/* 0x3af8 */ { false, 0x3af8, 0x3af8 }, +/* 0x3af9 */ { false, 0x3af9, 0x3af9 }, +/* 0x3afa */ { false, 0x3afa, 0x3afa }, +/* 0x3afb */ { false, 0x3afb, 0x3afb }, +/* 0x3afc */ { false, 0x3afc, 0x3afc }, +/* 0x3afd */ { false, 0x3afd, 0x3afd }, +/* 0x3afe */ { false, 0x3afe, 0x3afe }, +/* 0x3aff */ { false, 0x3aff, 0x3aff }, +/* 0x3b00 */ { false, 0x3b00, 0x3b00 }, +/* 0x3b01 */ { false, 0x3b01, 0x3b01 }, +/* 0x3b02 */ { false, 0x3b02, 0x3b02 }, +/* 0x3b03 */ { false, 0x3b03, 0x3b03 }, +/* 0x3b04 */ { false, 0x3b04, 0x3b04 }, +/* 0x3b05 */ { false, 0x3b05, 0x3b05 }, +/* 0x3b06 */ { false, 0x3b06, 0x3b06 }, +/* 0x3b07 */ { false, 0x3b07, 0x3b07 }, +/* 0x3b08 */ { false, 0x3b08, 0x3b08 }, +/* 0x3b09 */ { false, 0x3b09, 0x3b09 }, +/* 0x3b0a */ { false, 0x3b0a, 0x3b0a }, +/* 0x3b0b */ { false, 0x3b0b, 0x3b0b }, +/* 0x3b0c */ { false, 0x3b0c, 0x3b0c }, +/* 0x3b0d */ { false, 0x3b0d, 0x3b0d }, +/* 0x3b0e */ { false, 0x3b0e, 0x3b0e }, +/* 0x3b0f */ { false, 0x3b0f, 0x3b0f }, +/* 0x3b10 */ { false, 0x3b10, 0x3b10 }, +/* 0x3b11 */ { false, 0x3b11, 0x3b11 }, +/* 0x3b12 */ { false, 0x3b12, 0x3b12 }, +/* 0x3b13 */ { false, 0x3b13, 0x3b13 }, +/* 0x3b14 */ { false, 0x3b14, 0x3b14 }, +/* 0x3b15 */ { false, 0x3b15, 0x3b15 }, +/* 0x3b16 */ { false, 0x3b16, 0x3b16 }, +/* 0x3b17 */ { false, 0x3b17, 0x3b17 }, +/* 0x3b18 */ { false, 0x3b18, 0x3b18 }, +/* 0x3b19 */ { false, 0x3b19, 0x3b19 }, +/* 0x3b1a */ { false, 0x3b1a, 0x3b1a }, +/* 0x3b1b */ { false, 0x3b1b, 0x3b1b }, +/* 0x3b1c */ { false, 0x3b1c, 0x3b1c }, +/* 0x3b1d */ { false, 0x3b1d, 0x3b1d }, +/* 0x3b1e */ { false, 0x3b1e, 0x3b1e }, +/* 0x3b1f */ { false, 0x3b1f, 0x3b1f }, +/* 0x3b20 */ { false, 0x3b20, 0x3b20 }, +/* 0x3b21 */ { false, 0x3b21, 0x3b21 }, +/* 0x3b22 */ { false, 0x3b22, 0x3b22 }, +/* 0x3b23 */ { false, 0x3b23, 0x3b23 }, +/* 0x3b24 */ { false, 0x3b24, 0x3b24 }, +/* 0x3b25 */ { false, 0x3b25, 0x3b25 }, +/* 0x3b26 */ { false, 0x3b26, 0x3b26 }, +/* 0x3b27 */ { false, 0x3b27, 0x3b27 }, +/* 0x3b28 */ { false, 0x3b28, 0x3b28 }, +/* 0x3b29 */ { false, 0x3b29, 0x3b29 }, +/* 0x3b2a */ { false, 0x3b2a, 0x3b2a }, +/* 0x3b2b */ { false, 0x3b2b, 0x3b2b }, +/* 0x3b2c */ { false, 0x3b2c, 0x3b2c }, +/* 0x3b2d */ { false, 0x3b2d, 0x3b2d }, +/* 0x3b2e */ { false, 0x3b2e, 0x3b2e }, +/* 0x3b2f */ { false, 0x3b2f, 0x3b2f }, +/* 0x3b30 */ { false, 0x3b30, 0x3b30 }, +/* 0x3b31 */ { false, 0x3b31, 0x3b31 }, +/* 0x3b32 */ { false, 0x3b32, 0x3b32 }, +/* 0x3b33 */ { false, 0x3b33, 0x3b33 }, +/* 0x3b34 */ { false, 0x3b34, 0x3b34 }, +/* 0x3b35 */ { false, 0x3b35, 0x3b35 }, +/* 0x3b36 */ { false, 0x3b36, 0x3b36 }, +/* 0x3b37 */ { false, 0x3b37, 0x3b37 }, +/* 0x3b38 */ { false, 0x3b38, 0x3b38 }, +/* 0x3b39 */ { false, 0x3b39, 0x3b39 }, +/* 0x3b3a */ { false, 0x3b3a, 0x3b3a }, +/* 0x3b3b */ { false, 0x3b3b, 0x3b3b }, +/* 0x3b3c */ { false, 0x3b3c, 0x3b3c }, +/* 0x3b3d */ { false, 0x3b3d, 0x3b3d }, +/* 0x3b3e */ { false, 0x3b3e, 0x3b3e }, +/* 0x3b3f */ { false, 0x3b3f, 0x3b3f }, +/* 0x3b40 */ { false, 0x3b40, 0x3b40 }, +/* 0x3b41 */ { false, 0x3b41, 0x3b41 }, +/* 0x3b42 */ { false, 0x3b42, 0x3b42 }, +/* 0x3b43 */ { false, 0x3b43, 0x3b43 }, +/* 0x3b44 */ { false, 0x3b44, 0x3b44 }, +/* 0x3b45 */ { false, 0x3b45, 0x3b45 }, +/* 0x3b46 */ { false, 0x3b46, 0x3b46 }, +/* 0x3b47 */ { false, 0x3b47, 0x3b47 }, +/* 0x3b48 */ { false, 0x3b48, 0x3b48 }, +/* 0x3b49 */ { false, 0x3b49, 0x3b49 }, +/* 0x3b4a */ { false, 0x3b4a, 0x3b4a }, +/* 0x3b4b */ { false, 0x3b4b, 0x3b4b }, +/* 0x3b4c */ { false, 0x3b4c, 0x3b4c }, +/* 0x3b4d */ { false, 0x3b4d, 0x3b4d }, +/* 0x3b4e */ { false, 0x3b4e, 0x3b4e }, +/* 0x3b4f */ { false, 0x3b4f, 0x3b4f }, +/* 0x3b50 */ { false, 0x3b50, 0x3b50 }, +/* 0x3b51 */ { false, 0x3b51, 0x3b51 }, +/* 0x3b52 */ { false, 0x3b52, 0x3b52 }, +/* 0x3b53 */ { false, 0x3b53, 0x3b53 }, +/* 0x3b54 */ { false, 0x3b54, 0x3b54 }, +/* 0x3b55 */ { false, 0x3b55, 0x3b55 }, +/* 0x3b56 */ { false, 0x3b56, 0x3b56 }, +/* 0x3b57 */ { false, 0x3b57, 0x3b57 }, +/* 0x3b58 */ { false, 0x3b58, 0x3b58 }, +/* 0x3b59 */ { false, 0x3b59, 0x3b59 }, +/* 0x3b5a */ { false, 0x3b5a, 0x3b5a }, +/* 0x3b5b */ { false, 0x3b5b, 0x3b5b }, +/* 0x3b5c */ { false, 0x3b5c, 0x3b5c }, +/* 0x3b5d */ { false, 0x3b5d, 0x3b5d }, +/* 0x3b5e */ { false, 0x3b5e, 0x3b5e }, +/* 0x3b5f */ { false, 0x3b5f, 0x3b5f }, +/* 0x3b60 */ { false, 0x3b60, 0x3b60 }, +/* 0x3b61 */ { false, 0x3b61, 0x3b61 }, +/* 0x3b62 */ { false, 0x3b62, 0x3b62 }, +/* 0x3b63 */ { false, 0x3b63, 0x3b63 }, +/* 0x3b64 */ { false, 0x3b64, 0x3b64 }, +/* 0x3b65 */ { false, 0x3b65, 0x3b65 }, +/* 0x3b66 */ { false, 0x3b66, 0x3b66 }, +/* 0x3b67 */ { false, 0x3b67, 0x3b67 }, +/* 0x3b68 */ { false, 0x3b68, 0x3b68 }, +/* 0x3b69 */ { false, 0x3b69, 0x3b69 }, +/* 0x3b6a */ { false, 0x3b6a, 0x3b6a }, +/* 0x3b6b */ { false, 0x3b6b, 0x3b6b }, +/* 0x3b6c */ { false, 0x3b6c, 0x3b6c }, +/* 0x3b6d */ { false, 0x3b6d, 0x3b6d }, +/* 0x3b6e */ { false, 0x3b6e, 0x3b6e }, +/* 0x3b6f */ { false, 0x3b6f, 0x3b6f }, +/* 0x3b70 */ { false, 0x3b70, 0x3b70 }, +/* 0x3b71 */ { false, 0x3b71, 0x3b71 }, +/* 0x3b72 */ { false, 0x3b72, 0x3b72 }, +/* 0x3b73 */ { false, 0x3b73, 0x3b73 }, +/* 0x3b74 */ { false, 0x3b74, 0x3b74 }, +/* 0x3b75 */ { false, 0x3b75, 0x3b75 }, +/* 0x3b76 */ { false, 0x3b76, 0x3b76 }, +/* 0x3b77 */ { false, 0x3b77, 0x3b77 }, +/* 0x3b78 */ { false, 0x3b78, 0x3b78 }, +/* 0x3b79 */ { false, 0x3b79, 0x3b79 }, +/* 0x3b7a */ { false, 0x3b7a, 0x3b7a }, +/* 0x3b7b */ { false, 0x3b7b, 0x3b7b }, +/* 0x3b7c */ { false, 0x3b7c, 0x3b7c }, +/* 0x3b7d */ { false, 0x3b7d, 0x3b7d }, +/* 0x3b7e */ { false, 0x3b7e, 0x3b7e }, +/* 0x3b7f */ { false, 0x3b7f, 0x3b7f }, +/* 0x3b80 */ { false, 0x3b80, 0x3b80 }, +/* 0x3b81 */ { false, 0x3b81, 0x3b81 }, +/* 0x3b82 */ { false, 0x3b82, 0x3b82 }, +/* 0x3b83 */ { false, 0x3b83, 0x3b83 }, +/* 0x3b84 */ { false, 0x3b84, 0x3b84 }, +/* 0x3b85 */ { false, 0x3b85, 0x3b85 }, +/* 0x3b86 */ { false, 0x3b86, 0x3b86 }, +/* 0x3b87 */ { false, 0x3b87, 0x3b87 }, +/* 0x3b88 */ { false, 0x3b88, 0x3b88 }, +/* 0x3b89 */ { false, 0x3b89, 0x3b89 }, +/* 0x3b8a */ { false, 0x3b8a, 0x3b8a }, +/* 0x3b8b */ { false, 0x3b8b, 0x3b8b }, +/* 0x3b8c */ { false, 0x3b8c, 0x3b8c }, +/* 0x3b8d */ { false, 0x3b8d, 0x3b8d }, +/* 0x3b8e */ { false, 0x3b8e, 0x3b8e }, +/* 0x3b8f */ { false, 0x3b8f, 0x3b8f }, +/* 0x3b90 */ { false, 0x3b90, 0x3b90 }, +/* 0x3b91 */ { false, 0x3b91, 0x3b91 }, +/* 0x3b92 */ { false, 0x3b92, 0x3b92 }, +/* 0x3b93 */ { false, 0x3b93, 0x3b93 }, +/* 0x3b94 */ { false, 0x3b94, 0x3b94 }, +/* 0x3b95 */ { false, 0x3b95, 0x3b95 }, +/* 0x3b96 */ { false, 0x3b96, 0x3b96 }, +/* 0x3b97 */ { false, 0x3b97, 0x3b97 }, +/* 0x3b98 */ { false, 0x3b98, 0x3b98 }, +/* 0x3b99 */ { false, 0x3b99, 0x3b99 }, +/* 0x3b9a */ { false, 0x3b9a, 0x3b9a }, +/* 0x3b9b */ { false, 0x3b9b, 0x3b9b }, +/* 0x3b9c */ { false, 0x3b9c, 0x3b9c }, +/* 0x3b9d */ { false, 0x3b9d, 0x3b9d }, +/* 0x3b9e */ { false, 0x3b9e, 0x3b9e }, +/* 0x3b9f */ { false, 0x3b9f, 0x3b9f }, +/* 0x3ba0 */ { false, 0x3ba0, 0x3ba0 }, +/* 0x3ba1 */ { false, 0x3ba1, 0x3ba1 }, +/* 0x3ba2 */ { false, 0x3ba2, 0x3ba2 }, +/* 0x3ba3 */ { false, 0x3ba3, 0x3ba3 }, +/* 0x3ba4 */ { false, 0x3ba4, 0x3ba4 }, +/* 0x3ba5 */ { false, 0x3ba5, 0x3ba5 }, +/* 0x3ba6 */ { false, 0x3ba6, 0x3ba6 }, +/* 0x3ba7 */ { false, 0x3ba7, 0x3ba7 }, +/* 0x3ba8 */ { false, 0x3ba8, 0x3ba8 }, +/* 0x3ba9 */ { false, 0x3ba9, 0x3ba9 }, +/* 0x3baa */ { false, 0x3baa, 0x3baa }, +/* 0x3bab */ { false, 0x3bab, 0x3bab }, +/* 0x3bac */ { false, 0x3bac, 0x3bac }, +/* 0x3bad */ { false, 0x3bad, 0x3bad }, +/* 0x3bae */ { false, 0x3bae, 0x3bae }, +/* 0x3baf */ { false, 0x3baf, 0x3baf }, +/* 0x3bb0 */ { false, 0x3bb0, 0x3bb0 }, +/* 0x3bb1 */ { false, 0x3bb1, 0x3bb1 }, +/* 0x3bb2 */ { false, 0x3bb2, 0x3bb2 }, +/* 0x3bb3 */ { false, 0x3bb3, 0x3bb3 }, +/* 0x3bb4 */ { false, 0x3bb4, 0x3bb4 }, +/* 0x3bb5 */ { false, 0x3bb5, 0x3bb5 }, +/* 0x3bb6 */ { false, 0x3bb6, 0x3bb6 }, +/* 0x3bb7 */ { false, 0x3bb7, 0x3bb7 }, +/* 0x3bb8 */ { false, 0x3bb8, 0x3bb8 }, +/* 0x3bb9 */ { false, 0x3bb9, 0x3bb9 }, +/* 0x3bba */ { false, 0x3bba, 0x3bba }, +/* 0x3bbb */ { false, 0x3bbb, 0x3bbb }, +/* 0x3bbc */ { false, 0x3bbc, 0x3bbc }, +/* 0x3bbd */ { false, 0x3bbd, 0x3bbd }, +/* 0x3bbe */ { false, 0x3bbe, 0x3bbe }, +/* 0x3bbf */ { false, 0x3bbf, 0x3bbf }, +/* 0x3bc0 */ { false, 0x3bc0, 0x3bc0 }, +/* 0x3bc1 */ { false, 0x3bc1, 0x3bc1 }, +/* 0x3bc2 */ { false, 0x3bc2, 0x3bc2 }, +/* 0x3bc3 */ { false, 0x3bc3, 0x3bc3 }, +/* 0x3bc4 */ { false, 0x3bc4, 0x3bc4 }, +/* 0x3bc5 */ { false, 0x3bc5, 0x3bc5 }, +/* 0x3bc6 */ { false, 0x3bc6, 0x3bc6 }, +/* 0x3bc7 */ { false, 0x3bc7, 0x3bc7 }, +/* 0x3bc8 */ { false, 0x3bc8, 0x3bc8 }, +/* 0x3bc9 */ { false, 0x3bc9, 0x3bc9 }, +/* 0x3bca */ { false, 0x3bca, 0x3bca }, +/* 0x3bcb */ { false, 0x3bcb, 0x3bcb }, +/* 0x3bcc */ { false, 0x3bcc, 0x3bcc }, +/* 0x3bcd */ { false, 0x3bcd, 0x3bcd }, +/* 0x3bce */ { false, 0x3bce, 0x3bce }, +/* 0x3bcf */ { false, 0x3bcf, 0x3bcf }, +/* 0x3bd0 */ { false, 0x3bd0, 0x3bd0 }, +/* 0x3bd1 */ { false, 0x3bd1, 0x3bd1 }, +/* 0x3bd2 */ { false, 0x3bd2, 0x3bd2 }, +/* 0x3bd3 */ { false, 0x3bd3, 0x3bd3 }, +/* 0x3bd4 */ { false, 0x3bd4, 0x3bd4 }, +/* 0x3bd5 */ { false, 0x3bd5, 0x3bd5 }, +/* 0x3bd6 */ { false, 0x3bd6, 0x3bd6 }, +/* 0x3bd7 */ { false, 0x3bd7, 0x3bd7 }, +/* 0x3bd8 */ { false, 0x3bd8, 0x3bd8 }, +/* 0x3bd9 */ { false, 0x3bd9, 0x3bd9 }, +/* 0x3bda */ { false, 0x3bda, 0x3bda }, +/* 0x3bdb */ { false, 0x3bdb, 0x3bdb }, +/* 0x3bdc */ { false, 0x3bdc, 0x3bdc }, +/* 0x3bdd */ { false, 0x3bdd, 0x3bdd }, +/* 0x3bde */ { false, 0x3bde, 0x3bde }, +/* 0x3bdf */ { false, 0x3bdf, 0x3bdf }, +/* 0x3be0 */ { false, 0x3be0, 0x3be0 }, +/* 0x3be1 */ { false, 0x3be1, 0x3be1 }, +/* 0x3be2 */ { false, 0x3be2, 0x3be2 }, +/* 0x3be3 */ { false, 0x3be3, 0x3be3 }, +/* 0x3be4 */ { false, 0x3be4, 0x3be4 }, +/* 0x3be5 */ { false, 0x3be5, 0x3be5 }, +/* 0x3be6 */ { false, 0x3be6, 0x3be6 }, +/* 0x3be7 */ { false, 0x3be7, 0x3be7 }, +/* 0x3be8 */ { false, 0x3be8, 0x3be8 }, +/* 0x3be9 */ { false, 0x3be9, 0x3be9 }, +/* 0x3bea */ { false, 0x3bea, 0x3bea }, +/* 0x3beb */ { false, 0x3beb, 0x3beb }, +/* 0x3bec */ { false, 0x3bec, 0x3bec }, +/* 0x3bed */ { false, 0x3bed, 0x3bed }, +/* 0x3bee */ { false, 0x3bee, 0x3bee }, +/* 0x3bef */ { false, 0x3bef, 0x3bef }, +/* 0x3bf0 */ { false, 0x3bf0, 0x3bf0 }, +/* 0x3bf1 */ { false, 0x3bf1, 0x3bf1 }, +/* 0x3bf2 */ { false, 0x3bf2, 0x3bf2 }, +/* 0x3bf3 */ { false, 0x3bf3, 0x3bf3 }, +/* 0x3bf4 */ { false, 0x3bf4, 0x3bf4 }, +/* 0x3bf5 */ { false, 0x3bf5, 0x3bf5 }, +/* 0x3bf6 */ { false, 0x3bf6, 0x3bf6 }, +/* 0x3bf7 */ { false, 0x3bf7, 0x3bf7 }, +/* 0x3bf8 */ { false, 0x3bf8, 0x3bf8 }, +/* 0x3bf9 */ { false, 0x3bf9, 0x3bf9 }, +/* 0x3bfa */ { false, 0x3bfa, 0x3bfa }, +/* 0x3bfb */ { false, 0x3bfb, 0x3bfb }, +/* 0x3bfc */ { false, 0x3bfc, 0x3bfc }, +/* 0x3bfd */ { false, 0x3bfd, 0x3bfd }, +/* 0x3bfe */ { false, 0x3bfe, 0x3bfe }, +/* 0x3bff */ { false, 0x3bff, 0x3bff }, +/* 0x3c00 */ { false, 0x3c00, 0x3c00 }, +/* 0x3c01 */ { false, 0x3c01, 0x3c01 }, +/* 0x3c02 */ { false, 0x3c02, 0x3c02 }, +/* 0x3c03 */ { false, 0x3c03, 0x3c03 }, +/* 0x3c04 */ { false, 0x3c04, 0x3c04 }, +/* 0x3c05 */ { false, 0x3c05, 0x3c05 }, +/* 0x3c06 */ { false, 0x3c06, 0x3c06 }, +/* 0x3c07 */ { false, 0x3c07, 0x3c07 }, +/* 0x3c08 */ { false, 0x3c08, 0x3c08 }, +/* 0x3c09 */ { false, 0x3c09, 0x3c09 }, +/* 0x3c0a */ { false, 0x3c0a, 0x3c0a }, +/* 0x3c0b */ { false, 0x3c0b, 0x3c0b }, +/* 0x3c0c */ { false, 0x3c0c, 0x3c0c }, +/* 0x3c0d */ { false, 0x3c0d, 0x3c0d }, +/* 0x3c0e */ { false, 0x3c0e, 0x3c0e }, +/* 0x3c0f */ { false, 0x3c0f, 0x3c0f }, +/* 0x3c10 */ { false, 0x3c10, 0x3c10 }, +/* 0x3c11 */ { false, 0x3c11, 0x3c11 }, +/* 0x3c12 */ { false, 0x3c12, 0x3c12 }, +/* 0x3c13 */ { false, 0x3c13, 0x3c13 }, +/* 0x3c14 */ { false, 0x3c14, 0x3c14 }, +/* 0x3c15 */ { false, 0x3c15, 0x3c15 }, +/* 0x3c16 */ { false, 0x3c16, 0x3c16 }, +/* 0x3c17 */ { false, 0x3c17, 0x3c17 }, +/* 0x3c18 */ { false, 0x3c18, 0x3c18 }, +/* 0x3c19 */ { false, 0x3c19, 0x3c19 }, +/* 0x3c1a */ { false, 0x3c1a, 0x3c1a }, +/* 0x3c1b */ { false, 0x3c1b, 0x3c1b }, +/* 0x3c1c */ { false, 0x3c1c, 0x3c1c }, +/* 0x3c1d */ { false, 0x3c1d, 0x3c1d }, +/* 0x3c1e */ { false, 0x3c1e, 0x3c1e }, +/* 0x3c1f */ { false, 0x3c1f, 0x3c1f }, +/* 0x3c20 */ { false, 0x3c20, 0x3c20 }, +/* 0x3c21 */ { false, 0x3c21, 0x3c21 }, +/* 0x3c22 */ { false, 0x3c22, 0x3c22 }, +/* 0x3c23 */ { false, 0x3c23, 0x3c23 }, +/* 0x3c24 */ { false, 0x3c24, 0x3c24 }, +/* 0x3c25 */ { false, 0x3c25, 0x3c25 }, +/* 0x3c26 */ { false, 0x3c26, 0x3c26 }, +/* 0x3c27 */ { false, 0x3c27, 0x3c27 }, +/* 0x3c28 */ { false, 0x3c28, 0x3c28 }, +/* 0x3c29 */ { false, 0x3c29, 0x3c29 }, +/* 0x3c2a */ { false, 0x3c2a, 0x3c2a }, +/* 0x3c2b */ { false, 0x3c2b, 0x3c2b }, +/* 0x3c2c */ { false, 0x3c2c, 0x3c2c }, +/* 0x3c2d */ { false, 0x3c2d, 0x3c2d }, +/* 0x3c2e */ { false, 0x3c2e, 0x3c2e }, +/* 0x3c2f */ { false, 0x3c2f, 0x3c2f }, +/* 0x3c30 */ { false, 0x3c30, 0x3c30 }, +/* 0x3c31 */ { false, 0x3c31, 0x3c31 }, +/* 0x3c32 */ { false, 0x3c32, 0x3c32 }, +/* 0x3c33 */ { false, 0x3c33, 0x3c33 }, +/* 0x3c34 */ { false, 0x3c34, 0x3c34 }, +/* 0x3c35 */ { false, 0x3c35, 0x3c35 }, +/* 0x3c36 */ { false, 0x3c36, 0x3c36 }, +/* 0x3c37 */ { false, 0x3c37, 0x3c37 }, +/* 0x3c38 */ { false, 0x3c38, 0x3c38 }, +/* 0x3c39 */ { false, 0x3c39, 0x3c39 }, +/* 0x3c3a */ { false, 0x3c3a, 0x3c3a }, +/* 0x3c3b */ { false, 0x3c3b, 0x3c3b }, +/* 0x3c3c */ { false, 0x3c3c, 0x3c3c }, +/* 0x3c3d */ { false, 0x3c3d, 0x3c3d }, +/* 0x3c3e */ { false, 0x3c3e, 0x3c3e }, +/* 0x3c3f */ { false, 0x3c3f, 0x3c3f }, +/* 0x3c40 */ { false, 0x3c40, 0x3c40 }, +/* 0x3c41 */ { false, 0x3c41, 0x3c41 }, +/* 0x3c42 */ { false, 0x3c42, 0x3c42 }, +/* 0x3c43 */ { false, 0x3c43, 0x3c43 }, +/* 0x3c44 */ { false, 0x3c44, 0x3c44 }, +/* 0x3c45 */ { false, 0x3c45, 0x3c45 }, +/* 0x3c46 */ { false, 0x3c46, 0x3c46 }, +/* 0x3c47 */ { false, 0x3c47, 0x3c47 }, +/* 0x3c48 */ { false, 0x3c48, 0x3c48 }, +/* 0x3c49 */ { false, 0x3c49, 0x3c49 }, +/* 0x3c4a */ { false, 0x3c4a, 0x3c4a }, +/* 0x3c4b */ { false, 0x3c4b, 0x3c4b }, +/* 0x3c4c */ { false, 0x3c4c, 0x3c4c }, +/* 0x3c4d */ { false, 0x3c4d, 0x3c4d }, +/* 0x3c4e */ { false, 0x3c4e, 0x3c4e }, +/* 0x3c4f */ { false, 0x3c4f, 0x3c4f }, +/* 0x3c50 */ { false, 0x3c50, 0x3c50 }, +/* 0x3c51 */ { false, 0x3c51, 0x3c51 }, +/* 0x3c52 */ { false, 0x3c52, 0x3c52 }, +/* 0x3c53 */ { false, 0x3c53, 0x3c53 }, +/* 0x3c54 */ { false, 0x3c54, 0x3c54 }, +/* 0x3c55 */ { false, 0x3c55, 0x3c55 }, +/* 0x3c56 */ { false, 0x3c56, 0x3c56 }, +/* 0x3c57 */ { false, 0x3c57, 0x3c57 }, +/* 0x3c58 */ { false, 0x3c58, 0x3c58 }, +/* 0x3c59 */ { false, 0x3c59, 0x3c59 }, +/* 0x3c5a */ { false, 0x3c5a, 0x3c5a }, +/* 0x3c5b */ { false, 0x3c5b, 0x3c5b }, +/* 0x3c5c */ { false, 0x3c5c, 0x3c5c }, +/* 0x3c5d */ { false, 0x3c5d, 0x3c5d }, +/* 0x3c5e */ { false, 0x3c5e, 0x3c5e }, +/* 0x3c5f */ { false, 0x3c5f, 0x3c5f }, +/* 0x3c60 */ { false, 0x3c60, 0x3c60 }, +/* 0x3c61 */ { false, 0x3c61, 0x3c61 }, +/* 0x3c62 */ { false, 0x3c62, 0x3c62 }, +/* 0x3c63 */ { false, 0x3c63, 0x3c63 }, +/* 0x3c64 */ { false, 0x3c64, 0x3c64 }, +/* 0x3c65 */ { false, 0x3c65, 0x3c65 }, +/* 0x3c66 */ { false, 0x3c66, 0x3c66 }, +/* 0x3c67 */ { false, 0x3c67, 0x3c67 }, +/* 0x3c68 */ { false, 0x3c68, 0x3c68 }, +/* 0x3c69 */ { false, 0x3c69, 0x3c69 }, +/* 0x3c6a */ { false, 0x3c6a, 0x3c6a }, +/* 0x3c6b */ { false, 0x3c6b, 0x3c6b }, +/* 0x3c6c */ { false, 0x3c6c, 0x3c6c }, +/* 0x3c6d */ { false, 0x3c6d, 0x3c6d }, +/* 0x3c6e */ { false, 0x3c6e, 0x3c6e }, +/* 0x3c6f */ { false, 0x3c6f, 0x3c6f }, +/* 0x3c70 */ { false, 0x3c70, 0x3c70 }, +/* 0x3c71 */ { false, 0x3c71, 0x3c71 }, +/* 0x3c72 */ { false, 0x3c72, 0x3c72 }, +/* 0x3c73 */ { false, 0x3c73, 0x3c73 }, +/* 0x3c74 */ { false, 0x3c74, 0x3c74 }, +/* 0x3c75 */ { false, 0x3c75, 0x3c75 }, +/* 0x3c76 */ { false, 0x3c76, 0x3c76 }, +/* 0x3c77 */ { false, 0x3c77, 0x3c77 }, +/* 0x3c78 */ { false, 0x3c78, 0x3c78 }, +/* 0x3c79 */ { false, 0x3c79, 0x3c79 }, +/* 0x3c7a */ { false, 0x3c7a, 0x3c7a }, +/* 0x3c7b */ { false, 0x3c7b, 0x3c7b }, +/* 0x3c7c */ { false, 0x3c7c, 0x3c7c }, +/* 0x3c7d */ { false, 0x3c7d, 0x3c7d }, +/* 0x3c7e */ { false, 0x3c7e, 0x3c7e }, +/* 0x3c7f */ { false, 0x3c7f, 0x3c7f }, +/* 0x3c80 */ { false, 0x3c80, 0x3c80 }, +/* 0x3c81 */ { false, 0x3c81, 0x3c81 }, +/* 0x3c82 */ { false, 0x3c82, 0x3c82 }, +/* 0x3c83 */ { false, 0x3c83, 0x3c83 }, +/* 0x3c84 */ { false, 0x3c84, 0x3c84 }, +/* 0x3c85 */ { false, 0x3c85, 0x3c85 }, +/* 0x3c86 */ { false, 0x3c86, 0x3c86 }, +/* 0x3c87 */ { false, 0x3c87, 0x3c87 }, +/* 0x3c88 */ { false, 0x3c88, 0x3c88 }, +/* 0x3c89 */ { false, 0x3c89, 0x3c89 }, +/* 0x3c8a */ { false, 0x3c8a, 0x3c8a }, +/* 0x3c8b */ { false, 0x3c8b, 0x3c8b }, +/* 0x3c8c */ { false, 0x3c8c, 0x3c8c }, +/* 0x3c8d */ { false, 0x3c8d, 0x3c8d }, +/* 0x3c8e */ { false, 0x3c8e, 0x3c8e }, +/* 0x3c8f */ { false, 0x3c8f, 0x3c8f }, +/* 0x3c90 */ { false, 0x3c90, 0x3c90 }, +/* 0x3c91 */ { false, 0x3c91, 0x3c91 }, +/* 0x3c92 */ { false, 0x3c92, 0x3c92 }, +/* 0x3c93 */ { false, 0x3c93, 0x3c93 }, +/* 0x3c94 */ { false, 0x3c94, 0x3c94 }, +/* 0x3c95 */ { false, 0x3c95, 0x3c95 }, +/* 0x3c96 */ { false, 0x3c96, 0x3c96 }, +/* 0x3c97 */ { false, 0x3c97, 0x3c97 }, +/* 0x3c98 */ { false, 0x3c98, 0x3c98 }, +/* 0x3c99 */ { false, 0x3c99, 0x3c99 }, +/* 0x3c9a */ { false, 0x3c9a, 0x3c9a }, +/* 0x3c9b */ { false, 0x3c9b, 0x3c9b }, +/* 0x3c9c */ { false, 0x3c9c, 0x3c9c }, +/* 0x3c9d */ { false, 0x3c9d, 0x3c9d }, +/* 0x3c9e */ { false, 0x3c9e, 0x3c9e }, +/* 0x3c9f */ { false, 0x3c9f, 0x3c9f }, +/* 0x3ca0 */ { false, 0x3ca0, 0x3ca0 }, +/* 0x3ca1 */ { false, 0x3ca1, 0x3ca1 }, +/* 0x3ca2 */ { false, 0x3ca2, 0x3ca2 }, +/* 0x3ca3 */ { false, 0x3ca3, 0x3ca3 }, +/* 0x3ca4 */ { false, 0x3ca4, 0x3ca4 }, +/* 0x3ca5 */ { false, 0x3ca5, 0x3ca5 }, +/* 0x3ca6 */ { false, 0x3ca6, 0x3ca6 }, +/* 0x3ca7 */ { false, 0x3ca7, 0x3ca7 }, +/* 0x3ca8 */ { false, 0x3ca8, 0x3ca8 }, +/* 0x3ca9 */ { false, 0x3ca9, 0x3ca9 }, +/* 0x3caa */ { false, 0x3caa, 0x3caa }, +/* 0x3cab */ { false, 0x3cab, 0x3cab }, +/* 0x3cac */ { false, 0x3cac, 0x3cac }, +/* 0x3cad */ { false, 0x3cad, 0x3cad }, +/* 0x3cae */ { false, 0x3cae, 0x3cae }, +/* 0x3caf */ { false, 0x3caf, 0x3caf }, +/* 0x3cb0 */ { false, 0x3cb0, 0x3cb0 }, +/* 0x3cb1 */ { false, 0x3cb1, 0x3cb1 }, +/* 0x3cb2 */ { false, 0x3cb2, 0x3cb2 }, +/* 0x3cb3 */ { false, 0x3cb3, 0x3cb3 }, +/* 0x3cb4 */ { false, 0x3cb4, 0x3cb4 }, +/* 0x3cb5 */ { false, 0x3cb5, 0x3cb5 }, +/* 0x3cb6 */ { false, 0x3cb6, 0x3cb6 }, +/* 0x3cb7 */ { false, 0x3cb7, 0x3cb7 }, +/* 0x3cb8 */ { false, 0x3cb8, 0x3cb8 }, +/* 0x3cb9 */ { false, 0x3cb9, 0x3cb9 }, +/* 0x3cba */ { false, 0x3cba, 0x3cba }, +/* 0x3cbb */ { false, 0x3cbb, 0x3cbb }, +/* 0x3cbc */ { false, 0x3cbc, 0x3cbc }, +/* 0x3cbd */ { false, 0x3cbd, 0x3cbd }, +/* 0x3cbe */ { false, 0x3cbe, 0x3cbe }, +/* 0x3cbf */ { false, 0x3cbf, 0x3cbf }, +/* 0x3cc0 */ { false, 0x3cc0, 0x3cc0 }, +/* 0x3cc1 */ { false, 0x3cc1, 0x3cc1 }, +/* 0x3cc2 */ { false, 0x3cc2, 0x3cc2 }, +/* 0x3cc3 */ { false, 0x3cc3, 0x3cc3 }, +/* 0x3cc4 */ { false, 0x3cc4, 0x3cc4 }, +/* 0x3cc5 */ { false, 0x3cc5, 0x3cc5 }, +/* 0x3cc6 */ { false, 0x3cc6, 0x3cc6 }, +/* 0x3cc7 */ { false, 0x3cc7, 0x3cc7 }, +/* 0x3cc8 */ { false, 0x3cc8, 0x3cc8 }, +/* 0x3cc9 */ { false, 0x3cc9, 0x3cc9 }, +/* 0x3cca */ { false, 0x3cca, 0x3cca }, +/* 0x3ccb */ { false, 0x3ccb, 0x3ccb }, +/* 0x3ccc */ { false, 0x3ccc, 0x3ccc }, +/* 0x3ccd */ { false, 0x3ccd, 0x3ccd }, +/* 0x3cce */ { false, 0x3cce, 0x3cce }, +/* 0x3ccf */ { false, 0x3ccf, 0x3ccf }, +/* 0x3cd0 */ { false, 0x3cd0, 0x3cd0 }, +/* 0x3cd1 */ { false, 0x3cd1, 0x3cd1 }, +/* 0x3cd2 */ { false, 0x3cd2, 0x3cd2 }, +/* 0x3cd3 */ { false, 0x3cd3, 0x3cd3 }, +/* 0x3cd4 */ { false, 0x3cd4, 0x3cd4 }, +/* 0x3cd5 */ { false, 0x3cd5, 0x3cd5 }, +/* 0x3cd6 */ { false, 0x3cd6, 0x3cd6 }, +/* 0x3cd7 */ { false, 0x3cd7, 0x3cd7 }, +/* 0x3cd8 */ { false, 0x3cd8, 0x3cd8 }, +/* 0x3cd9 */ { false, 0x3cd9, 0x3cd9 }, +/* 0x3cda */ { false, 0x3cda, 0x3cda }, +/* 0x3cdb */ { false, 0x3cdb, 0x3cdb }, +/* 0x3cdc */ { false, 0x3cdc, 0x3cdc }, +/* 0x3cdd */ { false, 0x3cdd, 0x3cdd }, +/* 0x3cde */ { false, 0x3cde, 0x3cde }, +/* 0x3cdf */ { false, 0x3cdf, 0x3cdf }, +/* 0x3ce0 */ { false, 0x3ce0, 0x3ce0 }, +/* 0x3ce1 */ { false, 0x3ce1, 0x3ce1 }, +/* 0x3ce2 */ { false, 0x3ce2, 0x3ce2 }, +/* 0x3ce3 */ { false, 0x3ce3, 0x3ce3 }, +/* 0x3ce4 */ { false, 0x3ce4, 0x3ce4 }, +/* 0x3ce5 */ { false, 0x3ce5, 0x3ce5 }, +/* 0x3ce6 */ { false, 0x3ce6, 0x3ce6 }, +/* 0x3ce7 */ { false, 0x3ce7, 0x3ce7 }, +/* 0x3ce8 */ { false, 0x3ce8, 0x3ce8 }, +/* 0x3ce9 */ { false, 0x3ce9, 0x3ce9 }, +/* 0x3cea */ { false, 0x3cea, 0x3cea }, +/* 0x3ceb */ { false, 0x3ceb, 0x3ceb }, +/* 0x3cec */ { false, 0x3cec, 0x3cec }, +/* 0x3ced */ { false, 0x3ced, 0x3ced }, +/* 0x3cee */ { false, 0x3cee, 0x3cee }, +/* 0x3cef */ { false, 0x3cef, 0x3cef }, +/* 0x3cf0 */ { false, 0x3cf0, 0x3cf0 }, +/* 0x3cf1 */ { false, 0x3cf1, 0x3cf1 }, +/* 0x3cf2 */ { false, 0x3cf2, 0x3cf2 }, +/* 0x3cf3 */ { false, 0x3cf3, 0x3cf3 }, +/* 0x3cf4 */ { false, 0x3cf4, 0x3cf4 }, +/* 0x3cf5 */ { false, 0x3cf5, 0x3cf5 }, +/* 0x3cf6 */ { false, 0x3cf6, 0x3cf6 }, +/* 0x3cf7 */ { false, 0x3cf7, 0x3cf7 }, +/* 0x3cf8 */ { false, 0x3cf8, 0x3cf8 }, +/* 0x3cf9 */ { false, 0x3cf9, 0x3cf9 }, +/* 0x3cfa */ { false, 0x3cfa, 0x3cfa }, +/* 0x3cfb */ { false, 0x3cfb, 0x3cfb }, +/* 0x3cfc */ { false, 0x3cfc, 0x3cfc }, +/* 0x3cfd */ { false, 0x3cfd, 0x3cfd }, +/* 0x3cfe */ { false, 0x3cfe, 0x3cfe }, +/* 0x3cff */ { false, 0x3cff, 0x3cff }, +/* 0x3d00 */ { false, 0x3d00, 0x3d00 }, +/* 0x3d01 */ { false, 0x3d01, 0x3d01 }, +/* 0x3d02 */ { false, 0x3d02, 0x3d02 }, +/* 0x3d03 */ { false, 0x3d03, 0x3d03 }, +/* 0x3d04 */ { false, 0x3d04, 0x3d04 }, +/* 0x3d05 */ { false, 0x3d05, 0x3d05 }, +/* 0x3d06 */ { false, 0x3d06, 0x3d06 }, +/* 0x3d07 */ { false, 0x3d07, 0x3d07 }, +/* 0x3d08 */ { false, 0x3d08, 0x3d08 }, +/* 0x3d09 */ { false, 0x3d09, 0x3d09 }, +/* 0x3d0a */ { false, 0x3d0a, 0x3d0a }, +/* 0x3d0b */ { false, 0x3d0b, 0x3d0b }, +/* 0x3d0c */ { false, 0x3d0c, 0x3d0c }, +/* 0x3d0d */ { false, 0x3d0d, 0x3d0d }, +/* 0x3d0e */ { false, 0x3d0e, 0x3d0e }, +/* 0x3d0f */ { false, 0x3d0f, 0x3d0f }, +/* 0x3d10 */ { false, 0x3d10, 0x3d10 }, +/* 0x3d11 */ { false, 0x3d11, 0x3d11 }, +/* 0x3d12 */ { false, 0x3d12, 0x3d12 }, +/* 0x3d13 */ { false, 0x3d13, 0x3d13 }, +/* 0x3d14 */ { false, 0x3d14, 0x3d14 }, +/* 0x3d15 */ { false, 0x3d15, 0x3d15 }, +/* 0x3d16 */ { false, 0x3d16, 0x3d16 }, +/* 0x3d17 */ { false, 0x3d17, 0x3d17 }, +/* 0x3d18 */ { false, 0x3d18, 0x3d18 }, +/* 0x3d19 */ { false, 0x3d19, 0x3d19 }, +/* 0x3d1a */ { false, 0x3d1a, 0x3d1a }, +/* 0x3d1b */ { false, 0x3d1b, 0x3d1b }, +/* 0x3d1c */ { false, 0x3d1c, 0x3d1c }, +/* 0x3d1d */ { false, 0x3d1d, 0x3d1d }, +/* 0x3d1e */ { false, 0x3d1e, 0x3d1e }, +/* 0x3d1f */ { false, 0x3d1f, 0x3d1f }, +/* 0x3d20 */ { false, 0x3d20, 0x3d20 }, +/* 0x3d21 */ { false, 0x3d21, 0x3d21 }, +/* 0x3d22 */ { false, 0x3d22, 0x3d22 }, +/* 0x3d23 */ { false, 0x3d23, 0x3d23 }, +/* 0x3d24 */ { false, 0x3d24, 0x3d24 }, +/* 0x3d25 */ { false, 0x3d25, 0x3d25 }, +/* 0x3d26 */ { false, 0x3d26, 0x3d26 }, +/* 0x3d27 */ { false, 0x3d27, 0x3d27 }, +/* 0x3d28 */ { false, 0x3d28, 0x3d28 }, +/* 0x3d29 */ { false, 0x3d29, 0x3d29 }, +/* 0x3d2a */ { false, 0x3d2a, 0x3d2a }, +/* 0x3d2b */ { false, 0x3d2b, 0x3d2b }, +/* 0x3d2c */ { false, 0x3d2c, 0x3d2c }, +/* 0x3d2d */ { false, 0x3d2d, 0x3d2d }, +/* 0x3d2e */ { false, 0x3d2e, 0x3d2e }, +/* 0x3d2f */ { false, 0x3d2f, 0x3d2f }, +/* 0x3d30 */ { false, 0x3d30, 0x3d30 }, +/* 0x3d31 */ { false, 0x3d31, 0x3d31 }, +/* 0x3d32 */ { false, 0x3d32, 0x3d32 }, +/* 0x3d33 */ { false, 0x3d33, 0x3d33 }, +/* 0x3d34 */ { false, 0x3d34, 0x3d34 }, +/* 0x3d35 */ { false, 0x3d35, 0x3d35 }, +/* 0x3d36 */ { false, 0x3d36, 0x3d36 }, +/* 0x3d37 */ { false, 0x3d37, 0x3d37 }, +/* 0x3d38 */ { false, 0x3d38, 0x3d38 }, +/* 0x3d39 */ { false, 0x3d39, 0x3d39 }, +/* 0x3d3a */ { false, 0x3d3a, 0x3d3a }, +/* 0x3d3b */ { false, 0x3d3b, 0x3d3b }, +/* 0x3d3c */ { false, 0x3d3c, 0x3d3c }, +/* 0x3d3d */ { false, 0x3d3d, 0x3d3d }, +/* 0x3d3e */ { false, 0x3d3e, 0x3d3e }, +/* 0x3d3f */ { false, 0x3d3f, 0x3d3f }, +/* 0x3d40 */ { false, 0x3d40, 0x3d40 }, +/* 0x3d41 */ { false, 0x3d41, 0x3d41 }, +/* 0x3d42 */ { false, 0x3d42, 0x3d42 }, +/* 0x3d43 */ { false, 0x3d43, 0x3d43 }, +/* 0x3d44 */ { false, 0x3d44, 0x3d44 }, +/* 0x3d45 */ { false, 0x3d45, 0x3d45 }, +/* 0x3d46 */ { false, 0x3d46, 0x3d46 }, +/* 0x3d47 */ { false, 0x3d47, 0x3d47 }, +/* 0x3d48 */ { false, 0x3d48, 0x3d48 }, +/* 0x3d49 */ { false, 0x3d49, 0x3d49 }, +/* 0x3d4a */ { false, 0x3d4a, 0x3d4a }, +/* 0x3d4b */ { false, 0x3d4b, 0x3d4b }, +/* 0x3d4c */ { false, 0x3d4c, 0x3d4c }, +/* 0x3d4d */ { false, 0x3d4d, 0x3d4d }, +/* 0x3d4e */ { false, 0x3d4e, 0x3d4e }, +/* 0x3d4f */ { false, 0x3d4f, 0x3d4f }, +/* 0x3d50 */ { false, 0x3d50, 0x3d50 }, +/* 0x3d51 */ { false, 0x3d51, 0x3d51 }, +/* 0x3d52 */ { false, 0x3d52, 0x3d52 }, +/* 0x3d53 */ { false, 0x3d53, 0x3d53 }, +/* 0x3d54 */ { false, 0x3d54, 0x3d54 }, +/* 0x3d55 */ { false, 0x3d55, 0x3d55 }, +/* 0x3d56 */ { false, 0x3d56, 0x3d56 }, +/* 0x3d57 */ { false, 0x3d57, 0x3d57 }, +/* 0x3d58 */ { false, 0x3d58, 0x3d58 }, +/* 0x3d59 */ { false, 0x3d59, 0x3d59 }, +/* 0x3d5a */ { false, 0x3d5a, 0x3d5a }, +/* 0x3d5b */ { false, 0x3d5b, 0x3d5b }, +/* 0x3d5c */ { false, 0x3d5c, 0x3d5c }, +/* 0x3d5d */ { false, 0x3d5d, 0x3d5d }, +/* 0x3d5e */ { false, 0x3d5e, 0x3d5e }, +/* 0x3d5f */ { false, 0x3d5f, 0x3d5f }, +/* 0x3d60 */ { false, 0x3d60, 0x3d60 }, +/* 0x3d61 */ { false, 0x3d61, 0x3d61 }, +/* 0x3d62 */ { false, 0x3d62, 0x3d62 }, +/* 0x3d63 */ { false, 0x3d63, 0x3d63 }, +/* 0x3d64 */ { false, 0x3d64, 0x3d64 }, +/* 0x3d65 */ { false, 0x3d65, 0x3d65 }, +/* 0x3d66 */ { false, 0x3d66, 0x3d66 }, +/* 0x3d67 */ { false, 0x3d67, 0x3d67 }, +/* 0x3d68 */ { false, 0x3d68, 0x3d68 }, +/* 0x3d69 */ { false, 0x3d69, 0x3d69 }, +/* 0x3d6a */ { false, 0x3d6a, 0x3d6a }, +/* 0x3d6b */ { false, 0x3d6b, 0x3d6b }, +/* 0x3d6c */ { false, 0x3d6c, 0x3d6c }, +/* 0x3d6d */ { false, 0x3d6d, 0x3d6d }, +/* 0x3d6e */ { false, 0x3d6e, 0x3d6e }, +/* 0x3d6f */ { false, 0x3d6f, 0x3d6f }, +/* 0x3d70 */ { false, 0x3d70, 0x3d70 }, +/* 0x3d71 */ { false, 0x3d71, 0x3d71 }, +/* 0x3d72 */ { false, 0x3d72, 0x3d72 }, +/* 0x3d73 */ { false, 0x3d73, 0x3d73 }, +/* 0x3d74 */ { false, 0x3d74, 0x3d74 }, +/* 0x3d75 */ { false, 0x3d75, 0x3d75 }, +/* 0x3d76 */ { false, 0x3d76, 0x3d76 }, +/* 0x3d77 */ { false, 0x3d77, 0x3d77 }, +/* 0x3d78 */ { false, 0x3d78, 0x3d78 }, +/* 0x3d79 */ { false, 0x3d79, 0x3d79 }, +/* 0x3d7a */ { false, 0x3d7a, 0x3d7a }, +/* 0x3d7b */ { false, 0x3d7b, 0x3d7b }, +/* 0x3d7c */ { false, 0x3d7c, 0x3d7c }, +/* 0x3d7d */ { false, 0x3d7d, 0x3d7d }, +/* 0x3d7e */ { false, 0x3d7e, 0x3d7e }, +/* 0x3d7f */ { false, 0x3d7f, 0x3d7f }, +/* 0x3d80 */ { false, 0x3d80, 0x3d80 }, +/* 0x3d81 */ { false, 0x3d81, 0x3d81 }, +/* 0x3d82 */ { false, 0x3d82, 0x3d82 }, +/* 0x3d83 */ { false, 0x3d83, 0x3d83 }, +/* 0x3d84 */ { false, 0x3d84, 0x3d84 }, +/* 0x3d85 */ { false, 0x3d85, 0x3d85 }, +/* 0x3d86 */ { false, 0x3d86, 0x3d86 }, +/* 0x3d87 */ { false, 0x3d87, 0x3d87 }, +/* 0x3d88 */ { false, 0x3d88, 0x3d88 }, +/* 0x3d89 */ { false, 0x3d89, 0x3d89 }, +/* 0x3d8a */ { false, 0x3d8a, 0x3d8a }, +/* 0x3d8b */ { false, 0x3d8b, 0x3d8b }, +/* 0x3d8c */ { false, 0x3d8c, 0x3d8c }, +/* 0x3d8d */ { false, 0x3d8d, 0x3d8d }, +/* 0x3d8e */ { false, 0x3d8e, 0x3d8e }, +/* 0x3d8f */ { false, 0x3d8f, 0x3d8f }, +/* 0x3d90 */ { false, 0x3d90, 0x3d90 }, +/* 0x3d91 */ { false, 0x3d91, 0x3d91 }, +/* 0x3d92 */ { false, 0x3d92, 0x3d92 }, +/* 0x3d93 */ { false, 0x3d93, 0x3d93 }, +/* 0x3d94 */ { false, 0x3d94, 0x3d94 }, +/* 0x3d95 */ { false, 0x3d95, 0x3d95 }, +/* 0x3d96 */ { false, 0x3d96, 0x3d96 }, +/* 0x3d97 */ { false, 0x3d97, 0x3d97 }, +/* 0x3d98 */ { false, 0x3d98, 0x3d98 }, +/* 0x3d99 */ { false, 0x3d99, 0x3d99 }, +/* 0x3d9a */ { false, 0x3d9a, 0x3d9a }, +/* 0x3d9b */ { false, 0x3d9b, 0x3d9b }, +/* 0x3d9c */ { false, 0x3d9c, 0x3d9c }, +/* 0x3d9d */ { false, 0x3d9d, 0x3d9d }, +/* 0x3d9e */ { false, 0x3d9e, 0x3d9e }, +/* 0x3d9f */ { false, 0x3d9f, 0x3d9f }, +/* 0x3da0 */ { false, 0x3da0, 0x3da0 }, +/* 0x3da1 */ { false, 0x3da1, 0x3da1 }, +/* 0x3da2 */ { false, 0x3da2, 0x3da2 }, +/* 0x3da3 */ { false, 0x3da3, 0x3da3 }, +/* 0x3da4 */ { false, 0x3da4, 0x3da4 }, +/* 0x3da5 */ { false, 0x3da5, 0x3da5 }, +/* 0x3da6 */ { false, 0x3da6, 0x3da6 }, +/* 0x3da7 */ { false, 0x3da7, 0x3da7 }, +/* 0x3da8 */ { false, 0x3da8, 0x3da8 }, +/* 0x3da9 */ { false, 0x3da9, 0x3da9 }, +/* 0x3daa */ { false, 0x3daa, 0x3daa }, +/* 0x3dab */ { false, 0x3dab, 0x3dab }, +/* 0x3dac */ { false, 0x3dac, 0x3dac }, +/* 0x3dad */ { false, 0x3dad, 0x3dad }, +/* 0x3dae */ { false, 0x3dae, 0x3dae }, +/* 0x3daf */ { false, 0x3daf, 0x3daf }, +/* 0x3db0 */ { false, 0x3db0, 0x3db0 }, +/* 0x3db1 */ { false, 0x3db1, 0x3db1 }, +/* 0x3db2 */ { false, 0x3db2, 0x3db2 }, +/* 0x3db3 */ { false, 0x3db3, 0x3db3 }, +/* 0x3db4 */ { false, 0x3db4, 0x3db4 }, +/* 0x3db5 */ { false, 0x3db5, 0x3db5 }, +/* 0x3db6 */ { false, 0x3db6, 0x3db6 }, +/* 0x3db7 */ { false, 0x3db7, 0x3db7 }, +/* 0x3db8 */ { false, 0x3db8, 0x3db8 }, +/* 0x3db9 */ { false, 0x3db9, 0x3db9 }, +/* 0x3dba */ { false, 0x3dba, 0x3dba }, +/* 0x3dbb */ { false, 0x3dbb, 0x3dbb }, +/* 0x3dbc */ { false, 0x3dbc, 0x3dbc }, +/* 0x3dbd */ { false, 0x3dbd, 0x3dbd }, +/* 0x3dbe */ { false, 0x3dbe, 0x3dbe }, +/* 0x3dbf */ { false, 0x3dbf, 0x3dbf }, +/* 0x3dc0 */ { false, 0x3dc0, 0x3dc0 }, +/* 0x3dc1 */ { false, 0x3dc1, 0x3dc1 }, +/* 0x3dc2 */ { false, 0x3dc2, 0x3dc2 }, +/* 0x3dc3 */ { false, 0x3dc3, 0x3dc3 }, +/* 0x3dc4 */ { false, 0x3dc4, 0x3dc4 }, +/* 0x3dc5 */ { false, 0x3dc5, 0x3dc5 }, +/* 0x3dc6 */ { false, 0x3dc6, 0x3dc6 }, +/* 0x3dc7 */ { false, 0x3dc7, 0x3dc7 }, +/* 0x3dc8 */ { false, 0x3dc8, 0x3dc8 }, +/* 0x3dc9 */ { false, 0x3dc9, 0x3dc9 }, +/* 0x3dca */ { false, 0x3dca, 0x3dca }, +/* 0x3dcb */ { false, 0x3dcb, 0x3dcb }, +/* 0x3dcc */ { false, 0x3dcc, 0x3dcc }, +/* 0x3dcd */ { false, 0x3dcd, 0x3dcd }, +/* 0x3dce */ { false, 0x3dce, 0x3dce }, +/* 0x3dcf */ { false, 0x3dcf, 0x3dcf }, +/* 0x3dd0 */ { false, 0x3dd0, 0x3dd0 }, +/* 0x3dd1 */ { false, 0x3dd1, 0x3dd1 }, +/* 0x3dd2 */ { false, 0x3dd2, 0x3dd2 }, +/* 0x3dd3 */ { false, 0x3dd3, 0x3dd3 }, +/* 0x3dd4 */ { false, 0x3dd4, 0x3dd4 }, +/* 0x3dd5 */ { false, 0x3dd5, 0x3dd5 }, +/* 0x3dd6 */ { false, 0x3dd6, 0x3dd6 }, +/* 0x3dd7 */ { false, 0x3dd7, 0x3dd7 }, +/* 0x3dd8 */ { false, 0x3dd8, 0x3dd8 }, +/* 0x3dd9 */ { false, 0x3dd9, 0x3dd9 }, +/* 0x3dda */ { false, 0x3dda, 0x3dda }, +/* 0x3ddb */ { false, 0x3ddb, 0x3ddb }, +/* 0x3ddc */ { false, 0x3ddc, 0x3ddc }, +/* 0x3ddd */ { false, 0x3ddd, 0x3ddd }, +/* 0x3dde */ { false, 0x3dde, 0x3dde }, +/* 0x3ddf */ { false, 0x3ddf, 0x3ddf }, +/* 0x3de0 */ { false, 0x3de0, 0x3de0 }, +/* 0x3de1 */ { false, 0x3de1, 0x3de1 }, +/* 0x3de2 */ { false, 0x3de2, 0x3de2 }, +/* 0x3de3 */ { false, 0x3de3, 0x3de3 }, +/* 0x3de4 */ { false, 0x3de4, 0x3de4 }, +/* 0x3de5 */ { false, 0x3de5, 0x3de5 }, +/* 0x3de6 */ { false, 0x3de6, 0x3de6 }, +/* 0x3de7 */ { false, 0x3de7, 0x3de7 }, +/* 0x3de8 */ { false, 0x3de8, 0x3de8 }, +/* 0x3de9 */ { false, 0x3de9, 0x3de9 }, +/* 0x3dea */ { false, 0x3dea, 0x3dea }, +/* 0x3deb */ { false, 0x3deb, 0x3deb }, +/* 0x3dec */ { false, 0x3dec, 0x3dec }, +/* 0x3ded */ { false, 0x3ded, 0x3ded }, +/* 0x3dee */ { false, 0x3dee, 0x3dee }, +/* 0x3def */ { false, 0x3def, 0x3def }, +/* 0x3df0 */ { false, 0x3df0, 0x3df0 }, +/* 0x3df1 */ { false, 0x3df1, 0x3df1 }, +/* 0x3df2 */ { false, 0x3df2, 0x3df2 }, +/* 0x3df3 */ { false, 0x3df3, 0x3df3 }, +/* 0x3df4 */ { false, 0x3df4, 0x3df4 }, +/* 0x3df5 */ { false, 0x3df5, 0x3df5 }, +/* 0x3df6 */ { false, 0x3df6, 0x3df6 }, +/* 0x3df7 */ { false, 0x3df7, 0x3df7 }, +/* 0x3df8 */ { false, 0x3df8, 0x3df8 }, +/* 0x3df9 */ { false, 0x3df9, 0x3df9 }, +/* 0x3dfa */ { false, 0x3dfa, 0x3dfa }, +/* 0x3dfb */ { false, 0x3dfb, 0x3dfb }, +/* 0x3dfc */ { false, 0x3dfc, 0x3dfc }, +/* 0x3dfd */ { false, 0x3dfd, 0x3dfd }, +/* 0x3dfe */ { false, 0x3dfe, 0x3dfe }, +/* 0x3dff */ { false, 0x3dff, 0x3dff }, +/* 0x3e00 */ { false, 0x3e00, 0x3e00 }, +/* 0x3e01 */ { false, 0x3e01, 0x3e01 }, +/* 0x3e02 */ { false, 0x3e02, 0x3e02 }, +/* 0x3e03 */ { false, 0x3e03, 0x3e03 }, +/* 0x3e04 */ { false, 0x3e04, 0x3e04 }, +/* 0x3e05 */ { false, 0x3e05, 0x3e05 }, +/* 0x3e06 */ { false, 0x3e06, 0x3e06 }, +/* 0x3e07 */ { false, 0x3e07, 0x3e07 }, +/* 0x3e08 */ { false, 0x3e08, 0x3e08 }, +/* 0x3e09 */ { false, 0x3e09, 0x3e09 }, +/* 0x3e0a */ { false, 0x3e0a, 0x3e0a }, +/* 0x3e0b */ { false, 0x3e0b, 0x3e0b }, +/* 0x3e0c */ { false, 0x3e0c, 0x3e0c }, +/* 0x3e0d */ { false, 0x3e0d, 0x3e0d }, +/* 0x3e0e */ { false, 0x3e0e, 0x3e0e }, +/* 0x3e0f */ { false, 0x3e0f, 0x3e0f }, +/* 0x3e10 */ { false, 0x3e10, 0x3e10 }, +/* 0x3e11 */ { false, 0x3e11, 0x3e11 }, +/* 0x3e12 */ { false, 0x3e12, 0x3e12 }, +/* 0x3e13 */ { false, 0x3e13, 0x3e13 }, +/* 0x3e14 */ { false, 0x3e14, 0x3e14 }, +/* 0x3e15 */ { false, 0x3e15, 0x3e15 }, +/* 0x3e16 */ { false, 0x3e16, 0x3e16 }, +/* 0x3e17 */ { false, 0x3e17, 0x3e17 }, +/* 0x3e18 */ { false, 0x3e18, 0x3e18 }, +/* 0x3e19 */ { false, 0x3e19, 0x3e19 }, +/* 0x3e1a */ { false, 0x3e1a, 0x3e1a }, +/* 0x3e1b */ { false, 0x3e1b, 0x3e1b }, +/* 0x3e1c */ { false, 0x3e1c, 0x3e1c }, +/* 0x3e1d */ { false, 0x3e1d, 0x3e1d }, +/* 0x3e1e */ { false, 0x3e1e, 0x3e1e }, +/* 0x3e1f */ { false, 0x3e1f, 0x3e1f }, +/* 0x3e20 */ { false, 0x3e20, 0x3e20 }, +/* 0x3e21 */ { false, 0x3e21, 0x3e21 }, +/* 0x3e22 */ { false, 0x3e22, 0x3e22 }, +/* 0x3e23 */ { false, 0x3e23, 0x3e23 }, +/* 0x3e24 */ { false, 0x3e24, 0x3e24 }, +/* 0x3e25 */ { false, 0x3e25, 0x3e25 }, +/* 0x3e26 */ { false, 0x3e26, 0x3e26 }, +/* 0x3e27 */ { false, 0x3e27, 0x3e27 }, +/* 0x3e28 */ { false, 0x3e28, 0x3e28 }, +/* 0x3e29 */ { false, 0x3e29, 0x3e29 }, +/* 0x3e2a */ { false, 0x3e2a, 0x3e2a }, +/* 0x3e2b */ { false, 0x3e2b, 0x3e2b }, +/* 0x3e2c */ { false, 0x3e2c, 0x3e2c }, +/* 0x3e2d */ { false, 0x3e2d, 0x3e2d }, +/* 0x3e2e */ { false, 0x3e2e, 0x3e2e }, +/* 0x3e2f */ { false, 0x3e2f, 0x3e2f }, +/* 0x3e30 */ { false, 0x3e30, 0x3e30 }, +/* 0x3e31 */ { false, 0x3e31, 0x3e31 }, +/* 0x3e32 */ { false, 0x3e32, 0x3e32 }, +/* 0x3e33 */ { false, 0x3e33, 0x3e33 }, +/* 0x3e34 */ { false, 0x3e34, 0x3e34 }, +/* 0x3e35 */ { false, 0x3e35, 0x3e35 }, +/* 0x3e36 */ { false, 0x3e36, 0x3e36 }, +/* 0x3e37 */ { false, 0x3e37, 0x3e37 }, +/* 0x3e38 */ { false, 0x3e38, 0x3e38 }, +/* 0x3e39 */ { false, 0x3e39, 0x3e39 }, +/* 0x3e3a */ { false, 0x3e3a, 0x3e3a }, +/* 0x3e3b */ { false, 0x3e3b, 0x3e3b }, +/* 0x3e3c */ { false, 0x3e3c, 0x3e3c }, +/* 0x3e3d */ { false, 0x3e3d, 0x3e3d }, +/* 0x3e3e */ { false, 0x3e3e, 0x3e3e }, +/* 0x3e3f */ { false, 0x3e3f, 0x3e3f }, +/* 0x3e40 */ { false, 0x3e40, 0x3e40 }, +/* 0x3e41 */ { false, 0x3e41, 0x3e41 }, +/* 0x3e42 */ { false, 0x3e42, 0x3e42 }, +/* 0x3e43 */ { false, 0x3e43, 0x3e43 }, +/* 0x3e44 */ { false, 0x3e44, 0x3e44 }, +/* 0x3e45 */ { false, 0x3e45, 0x3e45 }, +/* 0x3e46 */ { false, 0x3e46, 0x3e46 }, +/* 0x3e47 */ { false, 0x3e47, 0x3e47 }, +/* 0x3e48 */ { false, 0x3e48, 0x3e48 }, +/* 0x3e49 */ { false, 0x3e49, 0x3e49 }, +/* 0x3e4a */ { false, 0x3e4a, 0x3e4a }, +/* 0x3e4b */ { false, 0x3e4b, 0x3e4b }, +/* 0x3e4c */ { false, 0x3e4c, 0x3e4c }, +/* 0x3e4d */ { false, 0x3e4d, 0x3e4d }, +/* 0x3e4e */ { false, 0x3e4e, 0x3e4e }, +/* 0x3e4f */ { false, 0x3e4f, 0x3e4f }, +/* 0x3e50 */ { false, 0x3e50, 0x3e50 }, +/* 0x3e51 */ { false, 0x3e51, 0x3e51 }, +/* 0x3e52 */ { false, 0x3e52, 0x3e52 }, +/* 0x3e53 */ { false, 0x3e53, 0x3e53 }, +/* 0x3e54 */ { false, 0x3e54, 0x3e54 }, +/* 0x3e55 */ { false, 0x3e55, 0x3e55 }, +/* 0x3e56 */ { false, 0x3e56, 0x3e56 }, +/* 0x3e57 */ { false, 0x3e57, 0x3e57 }, +/* 0x3e58 */ { false, 0x3e58, 0x3e58 }, +/* 0x3e59 */ { false, 0x3e59, 0x3e59 }, +/* 0x3e5a */ { false, 0x3e5a, 0x3e5a }, +/* 0x3e5b */ { false, 0x3e5b, 0x3e5b }, +/* 0x3e5c */ { false, 0x3e5c, 0x3e5c }, +/* 0x3e5d */ { false, 0x3e5d, 0x3e5d }, +/* 0x3e5e */ { false, 0x3e5e, 0x3e5e }, +/* 0x3e5f */ { false, 0x3e5f, 0x3e5f }, +/* 0x3e60 */ { false, 0x3e60, 0x3e60 }, +/* 0x3e61 */ { false, 0x3e61, 0x3e61 }, +/* 0x3e62 */ { false, 0x3e62, 0x3e62 }, +/* 0x3e63 */ { false, 0x3e63, 0x3e63 }, +/* 0x3e64 */ { false, 0x3e64, 0x3e64 }, +/* 0x3e65 */ { false, 0x3e65, 0x3e65 }, +/* 0x3e66 */ { false, 0x3e66, 0x3e66 }, +/* 0x3e67 */ { false, 0x3e67, 0x3e67 }, +/* 0x3e68 */ { false, 0x3e68, 0x3e68 }, +/* 0x3e69 */ { false, 0x3e69, 0x3e69 }, +/* 0x3e6a */ { false, 0x3e6a, 0x3e6a }, +/* 0x3e6b */ { false, 0x3e6b, 0x3e6b }, +/* 0x3e6c */ { false, 0x3e6c, 0x3e6c }, +/* 0x3e6d */ { false, 0x3e6d, 0x3e6d }, +/* 0x3e6e */ { false, 0x3e6e, 0x3e6e }, +/* 0x3e6f */ { false, 0x3e6f, 0x3e6f }, +/* 0x3e70 */ { false, 0x3e70, 0x3e70 }, +/* 0x3e71 */ { false, 0x3e71, 0x3e71 }, +/* 0x3e72 */ { false, 0x3e72, 0x3e72 }, +/* 0x3e73 */ { false, 0x3e73, 0x3e73 }, +/* 0x3e74 */ { false, 0x3e74, 0x3e74 }, +/* 0x3e75 */ { false, 0x3e75, 0x3e75 }, +/* 0x3e76 */ { false, 0x3e76, 0x3e76 }, +/* 0x3e77 */ { false, 0x3e77, 0x3e77 }, +/* 0x3e78 */ { false, 0x3e78, 0x3e78 }, +/* 0x3e79 */ { false, 0x3e79, 0x3e79 }, +/* 0x3e7a */ { false, 0x3e7a, 0x3e7a }, +/* 0x3e7b */ { false, 0x3e7b, 0x3e7b }, +/* 0x3e7c */ { false, 0x3e7c, 0x3e7c }, +/* 0x3e7d */ { false, 0x3e7d, 0x3e7d }, +/* 0x3e7e */ { false, 0x3e7e, 0x3e7e }, +/* 0x3e7f */ { false, 0x3e7f, 0x3e7f }, +/* 0x3e80 */ { false, 0x3e80, 0x3e80 }, +/* 0x3e81 */ { false, 0x3e81, 0x3e81 }, +/* 0x3e82 */ { false, 0x3e82, 0x3e82 }, +/* 0x3e83 */ { false, 0x3e83, 0x3e83 }, +/* 0x3e84 */ { false, 0x3e84, 0x3e84 }, +/* 0x3e85 */ { false, 0x3e85, 0x3e85 }, +/* 0x3e86 */ { false, 0x3e86, 0x3e86 }, +/* 0x3e87 */ { false, 0x3e87, 0x3e87 }, +/* 0x3e88 */ { false, 0x3e88, 0x3e88 }, +/* 0x3e89 */ { false, 0x3e89, 0x3e89 }, +/* 0x3e8a */ { false, 0x3e8a, 0x3e8a }, +/* 0x3e8b */ { false, 0x3e8b, 0x3e8b }, +/* 0x3e8c */ { false, 0x3e8c, 0x3e8c }, +/* 0x3e8d */ { false, 0x3e8d, 0x3e8d }, +/* 0x3e8e */ { false, 0x3e8e, 0x3e8e }, +/* 0x3e8f */ { false, 0x3e8f, 0x3e8f }, +/* 0x3e90 */ { false, 0x3e90, 0x3e90 }, +/* 0x3e91 */ { false, 0x3e91, 0x3e91 }, +/* 0x3e92 */ { false, 0x3e92, 0x3e92 }, +/* 0x3e93 */ { false, 0x3e93, 0x3e93 }, +/* 0x3e94 */ { false, 0x3e94, 0x3e94 }, +/* 0x3e95 */ { false, 0x3e95, 0x3e95 }, +/* 0x3e96 */ { false, 0x3e96, 0x3e96 }, +/* 0x3e97 */ { false, 0x3e97, 0x3e97 }, +/* 0x3e98 */ { false, 0x3e98, 0x3e98 }, +/* 0x3e99 */ { false, 0x3e99, 0x3e99 }, +/* 0x3e9a */ { false, 0x3e9a, 0x3e9a }, +/* 0x3e9b */ { false, 0x3e9b, 0x3e9b }, +/* 0x3e9c */ { false, 0x3e9c, 0x3e9c }, +/* 0x3e9d */ { false, 0x3e9d, 0x3e9d }, +/* 0x3e9e */ { false, 0x3e9e, 0x3e9e }, +/* 0x3e9f */ { false, 0x3e9f, 0x3e9f }, +/* 0x3ea0 */ { false, 0x3ea0, 0x3ea0 }, +/* 0x3ea1 */ { false, 0x3ea1, 0x3ea1 }, +/* 0x3ea2 */ { false, 0x3ea2, 0x3ea2 }, +/* 0x3ea3 */ { false, 0x3ea3, 0x3ea3 }, +/* 0x3ea4 */ { false, 0x3ea4, 0x3ea4 }, +/* 0x3ea5 */ { false, 0x3ea5, 0x3ea5 }, +/* 0x3ea6 */ { false, 0x3ea6, 0x3ea6 }, +/* 0x3ea7 */ { false, 0x3ea7, 0x3ea7 }, +/* 0x3ea8 */ { false, 0x3ea8, 0x3ea8 }, +/* 0x3ea9 */ { false, 0x3ea9, 0x3ea9 }, +/* 0x3eaa */ { false, 0x3eaa, 0x3eaa }, +/* 0x3eab */ { false, 0x3eab, 0x3eab }, +/* 0x3eac */ { false, 0x3eac, 0x3eac }, +/* 0x3ead */ { false, 0x3ead, 0x3ead }, +/* 0x3eae */ { false, 0x3eae, 0x3eae }, +/* 0x3eaf */ { false, 0x3eaf, 0x3eaf }, +/* 0x3eb0 */ { false, 0x3eb0, 0x3eb0 }, +/* 0x3eb1 */ { false, 0x3eb1, 0x3eb1 }, +/* 0x3eb2 */ { false, 0x3eb2, 0x3eb2 }, +/* 0x3eb3 */ { false, 0x3eb3, 0x3eb3 }, +/* 0x3eb4 */ { false, 0x3eb4, 0x3eb4 }, +/* 0x3eb5 */ { false, 0x3eb5, 0x3eb5 }, +/* 0x3eb6 */ { false, 0x3eb6, 0x3eb6 }, +/* 0x3eb7 */ { false, 0x3eb7, 0x3eb7 }, +/* 0x3eb8 */ { false, 0x3eb8, 0x3eb8 }, +/* 0x3eb9 */ { false, 0x3eb9, 0x3eb9 }, +/* 0x3eba */ { false, 0x3eba, 0x3eba }, +/* 0x3ebb */ { false, 0x3ebb, 0x3ebb }, +/* 0x3ebc */ { false, 0x3ebc, 0x3ebc }, +/* 0x3ebd */ { false, 0x3ebd, 0x3ebd }, +/* 0x3ebe */ { false, 0x3ebe, 0x3ebe }, +/* 0x3ebf */ { false, 0x3ebf, 0x3ebf }, +/* 0x3ec0 */ { false, 0x3ec0, 0x3ec0 }, +/* 0x3ec1 */ { false, 0x3ec1, 0x3ec1 }, +/* 0x3ec2 */ { false, 0x3ec2, 0x3ec2 }, +/* 0x3ec3 */ { false, 0x3ec3, 0x3ec3 }, +/* 0x3ec4 */ { false, 0x3ec4, 0x3ec4 }, +/* 0x3ec5 */ { false, 0x3ec5, 0x3ec5 }, +/* 0x3ec6 */ { false, 0x3ec6, 0x3ec6 }, +/* 0x3ec7 */ { false, 0x3ec7, 0x3ec7 }, +/* 0x3ec8 */ { false, 0x3ec8, 0x3ec8 }, +/* 0x3ec9 */ { false, 0x3ec9, 0x3ec9 }, +/* 0x3eca */ { false, 0x3eca, 0x3eca }, +/* 0x3ecb */ { false, 0x3ecb, 0x3ecb }, +/* 0x3ecc */ { false, 0x3ecc, 0x3ecc }, +/* 0x3ecd */ { false, 0x3ecd, 0x3ecd }, +/* 0x3ece */ { false, 0x3ece, 0x3ece }, +/* 0x3ecf */ { false, 0x3ecf, 0x3ecf }, +/* 0x3ed0 */ { false, 0x3ed0, 0x3ed0 }, +/* 0x3ed1 */ { false, 0x3ed1, 0x3ed1 }, +/* 0x3ed2 */ { false, 0x3ed2, 0x3ed2 }, +/* 0x3ed3 */ { false, 0x3ed3, 0x3ed3 }, +/* 0x3ed4 */ { false, 0x3ed4, 0x3ed4 }, +/* 0x3ed5 */ { false, 0x3ed5, 0x3ed5 }, +/* 0x3ed6 */ { false, 0x3ed6, 0x3ed6 }, +/* 0x3ed7 */ { false, 0x3ed7, 0x3ed7 }, +/* 0x3ed8 */ { false, 0x3ed8, 0x3ed8 }, +/* 0x3ed9 */ { false, 0x3ed9, 0x3ed9 }, +/* 0x3eda */ { false, 0x3eda, 0x3eda }, +/* 0x3edb */ { false, 0x3edb, 0x3edb }, +/* 0x3edc */ { false, 0x3edc, 0x3edc }, +/* 0x3edd */ { false, 0x3edd, 0x3edd }, +/* 0x3ede */ { false, 0x3ede, 0x3ede }, +/* 0x3edf */ { false, 0x3edf, 0x3edf }, +/* 0x3ee0 */ { false, 0x3ee0, 0x3ee0 }, +/* 0x3ee1 */ { false, 0x3ee1, 0x3ee1 }, +/* 0x3ee2 */ { false, 0x3ee2, 0x3ee2 }, +/* 0x3ee3 */ { false, 0x3ee3, 0x3ee3 }, +/* 0x3ee4 */ { false, 0x3ee4, 0x3ee4 }, +/* 0x3ee5 */ { false, 0x3ee5, 0x3ee5 }, +/* 0x3ee6 */ { false, 0x3ee6, 0x3ee6 }, +/* 0x3ee7 */ { false, 0x3ee7, 0x3ee7 }, +/* 0x3ee8 */ { false, 0x3ee8, 0x3ee8 }, +/* 0x3ee9 */ { false, 0x3ee9, 0x3ee9 }, +/* 0x3eea */ { false, 0x3eea, 0x3eea }, +/* 0x3eeb */ { false, 0x3eeb, 0x3eeb }, +/* 0x3eec */ { false, 0x3eec, 0x3eec }, +/* 0x3eed */ { false, 0x3eed, 0x3eed }, +/* 0x3eee */ { false, 0x3eee, 0x3eee }, +/* 0x3eef */ { false, 0x3eef, 0x3eef }, +/* 0x3ef0 */ { false, 0x3ef0, 0x3ef0 }, +/* 0x3ef1 */ { false, 0x3ef1, 0x3ef1 }, +/* 0x3ef2 */ { false, 0x3ef2, 0x3ef2 }, +/* 0x3ef3 */ { false, 0x3ef3, 0x3ef3 }, +/* 0x3ef4 */ { false, 0x3ef4, 0x3ef4 }, +/* 0x3ef5 */ { false, 0x3ef5, 0x3ef5 }, +/* 0x3ef6 */ { false, 0x3ef6, 0x3ef6 }, +/* 0x3ef7 */ { false, 0x3ef7, 0x3ef7 }, +/* 0x3ef8 */ { false, 0x3ef8, 0x3ef8 }, +/* 0x3ef9 */ { false, 0x3ef9, 0x3ef9 }, +/* 0x3efa */ { false, 0x3efa, 0x3efa }, +/* 0x3efb */ { false, 0x3efb, 0x3efb }, +/* 0x3efc */ { false, 0x3efc, 0x3efc }, +/* 0x3efd */ { false, 0x3efd, 0x3efd }, +/* 0x3efe */ { false, 0x3efe, 0x3efe }, +/* 0x3eff */ { false, 0x3eff, 0x3eff }, +/* 0x3f00 */ { false, 0x3f00, 0x3f00 }, +/* 0x3f01 */ { false, 0x3f01, 0x3f01 }, +/* 0x3f02 */ { false, 0x3f02, 0x3f02 }, +/* 0x3f03 */ { false, 0x3f03, 0x3f03 }, +/* 0x3f04 */ { false, 0x3f04, 0x3f04 }, +/* 0x3f05 */ { false, 0x3f05, 0x3f05 }, +/* 0x3f06 */ { false, 0x3f06, 0x3f06 }, +/* 0x3f07 */ { false, 0x3f07, 0x3f07 }, +/* 0x3f08 */ { false, 0x3f08, 0x3f08 }, +/* 0x3f09 */ { false, 0x3f09, 0x3f09 }, +/* 0x3f0a */ { false, 0x3f0a, 0x3f0a }, +/* 0x3f0b */ { false, 0x3f0b, 0x3f0b }, +/* 0x3f0c */ { false, 0x3f0c, 0x3f0c }, +/* 0x3f0d */ { false, 0x3f0d, 0x3f0d }, +/* 0x3f0e */ { false, 0x3f0e, 0x3f0e }, +/* 0x3f0f */ { false, 0x3f0f, 0x3f0f }, +/* 0x3f10 */ { false, 0x3f10, 0x3f10 }, +/* 0x3f11 */ { false, 0x3f11, 0x3f11 }, +/* 0x3f12 */ { false, 0x3f12, 0x3f12 }, +/* 0x3f13 */ { false, 0x3f13, 0x3f13 }, +/* 0x3f14 */ { false, 0x3f14, 0x3f14 }, +/* 0x3f15 */ { false, 0x3f15, 0x3f15 }, +/* 0x3f16 */ { false, 0x3f16, 0x3f16 }, +/* 0x3f17 */ { false, 0x3f17, 0x3f17 }, +/* 0x3f18 */ { false, 0x3f18, 0x3f18 }, +/* 0x3f19 */ { false, 0x3f19, 0x3f19 }, +/* 0x3f1a */ { false, 0x3f1a, 0x3f1a }, +/* 0x3f1b */ { false, 0x3f1b, 0x3f1b }, +/* 0x3f1c */ { false, 0x3f1c, 0x3f1c }, +/* 0x3f1d */ { false, 0x3f1d, 0x3f1d }, +/* 0x3f1e */ { false, 0x3f1e, 0x3f1e }, +/* 0x3f1f */ { false, 0x3f1f, 0x3f1f }, +/* 0x3f20 */ { false, 0x3f20, 0x3f20 }, +/* 0x3f21 */ { false, 0x3f21, 0x3f21 }, +/* 0x3f22 */ { false, 0x3f22, 0x3f22 }, +/* 0x3f23 */ { false, 0x3f23, 0x3f23 }, +/* 0x3f24 */ { false, 0x3f24, 0x3f24 }, +/* 0x3f25 */ { false, 0x3f25, 0x3f25 }, +/* 0x3f26 */ { false, 0x3f26, 0x3f26 }, +/* 0x3f27 */ { false, 0x3f27, 0x3f27 }, +/* 0x3f28 */ { false, 0x3f28, 0x3f28 }, +/* 0x3f29 */ { false, 0x3f29, 0x3f29 }, +/* 0x3f2a */ { false, 0x3f2a, 0x3f2a }, +/* 0x3f2b */ { false, 0x3f2b, 0x3f2b }, +/* 0x3f2c */ { false, 0x3f2c, 0x3f2c }, +/* 0x3f2d */ { false, 0x3f2d, 0x3f2d }, +/* 0x3f2e */ { false, 0x3f2e, 0x3f2e }, +/* 0x3f2f */ { false, 0x3f2f, 0x3f2f }, +/* 0x3f30 */ { false, 0x3f30, 0x3f30 }, +/* 0x3f31 */ { false, 0x3f31, 0x3f31 }, +/* 0x3f32 */ { false, 0x3f32, 0x3f32 }, +/* 0x3f33 */ { false, 0x3f33, 0x3f33 }, +/* 0x3f34 */ { false, 0x3f34, 0x3f34 }, +/* 0x3f35 */ { false, 0x3f35, 0x3f35 }, +/* 0x3f36 */ { false, 0x3f36, 0x3f36 }, +/* 0x3f37 */ { false, 0x3f37, 0x3f37 }, +/* 0x3f38 */ { false, 0x3f38, 0x3f38 }, +/* 0x3f39 */ { false, 0x3f39, 0x3f39 }, +/* 0x3f3a */ { false, 0x3f3a, 0x3f3a }, +/* 0x3f3b */ { false, 0x3f3b, 0x3f3b }, +/* 0x3f3c */ { false, 0x3f3c, 0x3f3c }, +/* 0x3f3d */ { false, 0x3f3d, 0x3f3d }, +/* 0x3f3e */ { false, 0x3f3e, 0x3f3e }, +/* 0x3f3f */ { false, 0x3f3f, 0x3f3f }, +/* 0x3f40 */ { false, 0x3f40, 0x3f40 }, +/* 0x3f41 */ { false, 0x3f41, 0x3f41 }, +/* 0x3f42 */ { false, 0x3f42, 0x3f42 }, +/* 0x3f43 */ { false, 0x3f43, 0x3f43 }, +/* 0x3f44 */ { false, 0x3f44, 0x3f44 }, +/* 0x3f45 */ { false, 0x3f45, 0x3f45 }, +/* 0x3f46 */ { false, 0x3f46, 0x3f46 }, +/* 0x3f47 */ { false, 0x3f47, 0x3f47 }, +/* 0x3f48 */ { false, 0x3f48, 0x3f48 }, +/* 0x3f49 */ { false, 0x3f49, 0x3f49 }, +/* 0x3f4a */ { false, 0x3f4a, 0x3f4a }, +/* 0x3f4b */ { false, 0x3f4b, 0x3f4b }, +/* 0x3f4c */ { false, 0x3f4c, 0x3f4c }, +/* 0x3f4d */ { false, 0x3f4d, 0x3f4d }, +/* 0x3f4e */ { false, 0x3f4e, 0x3f4e }, +/* 0x3f4f */ { false, 0x3f4f, 0x3f4f }, +/* 0x3f50 */ { false, 0x3f50, 0x3f50 }, +/* 0x3f51 */ { false, 0x3f51, 0x3f51 }, +/* 0x3f52 */ { false, 0x3f52, 0x3f52 }, +/* 0x3f53 */ { false, 0x3f53, 0x3f53 }, +/* 0x3f54 */ { false, 0x3f54, 0x3f54 }, +/* 0x3f55 */ { false, 0x3f55, 0x3f55 }, +/* 0x3f56 */ { false, 0x3f56, 0x3f56 }, +/* 0x3f57 */ { false, 0x3f57, 0x3f57 }, +/* 0x3f58 */ { false, 0x3f58, 0x3f58 }, +/* 0x3f59 */ { false, 0x3f59, 0x3f59 }, +/* 0x3f5a */ { false, 0x3f5a, 0x3f5a }, +/* 0x3f5b */ { false, 0x3f5b, 0x3f5b }, +/* 0x3f5c */ { false, 0x3f5c, 0x3f5c }, +/* 0x3f5d */ { false, 0x3f5d, 0x3f5d }, +/* 0x3f5e */ { false, 0x3f5e, 0x3f5e }, +/* 0x3f5f */ { false, 0x3f5f, 0x3f5f }, +/* 0x3f60 */ { false, 0x3f60, 0x3f60 }, +/* 0x3f61 */ { false, 0x3f61, 0x3f61 }, +/* 0x3f62 */ { false, 0x3f62, 0x3f62 }, +/* 0x3f63 */ { false, 0x3f63, 0x3f63 }, +/* 0x3f64 */ { false, 0x3f64, 0x3f64 }, +/* 0x3f65 */ { false, 0x3f65, 0x3f65 }, +/* 0x3f66 */ { false, 0x3f66, 0x3f66 }, +/* 0x3f67 */ { false, 0x3f67, 0x3f67 }, +/* 0x3f68 */ { false, 0x3f68, 0x3f68 }, +/* 0x3f69 */ { false, 0x3f69, 0x3f69 }, +/* 0x3f6a */ { false, 0x3f6a, 0x3f6a }, +/* 0x3f6b */ { false, 0x3f6b, 0x3f6b }, +/* 0x3f6c */ { false, 0x3f6c, 0x3f6c }, +/* 0x3f6d */ { false, 0x3f6d, 0x3f6d }, +/* 0x3f6e */ { false, 0x3f6e, 0x3f6e }, +/* 0x3f6f */ { false, 0x3f6f, 0x3f6f }, +/* 0x3f70 */ { false, 0x3f70, 0x3f70 }, +/* 0x3f71 */ { false, 0x3f71, 0x3f71 }, +/* 0x3f72 */ { false, 0x3f72, 0x3f72 }, +/* 0x3f73 */ { false, 0x3f73, 0x3f73 }, +/* 0x3f74 */ { false, 0x3f74, 0x3f74 }, +/* 0x3f75 */ { false, 0x3f75, 0x3f75 }, +/* 0x3f76 */ { false, 0x3f76, 0x3f76 }, +/* 0x3f77 */ { false, 0x3f77, 0x3f77 }, +/* 0x3f78 */ { false, 0x3f78, 0x3f78 }, +/* 0x3f79 */ { false, 0x3f79, 0x3f79 }, +/* 0x3f7a */ { false, 0x3f7a, 0x3f7a }, +/* 0x3f7b */ { false, 0x3f7b, 0x3f7b }, +/* 0x3f7c */ { false, 0x3f7c, 0x3f7c }, +/* 0x3f7d */ { false, 0x3f7d, 0x3f7d }, +/* 0x3f7e */ { false, 0x3f7e, 0x3f7e }, +/* 0x3f7f */ { false, 0x3f7f, 0x3f7f }, +/* 0x3f80 */ { false, 0x3f80, 0x3f80 }, +/* 0x3f81 */ { false, 0x3f81, 0x3f81 }, +/* 0x3f82 */ { false, 0x3f82, 0x3f82 }, +/* 0x3f83 */ { false, 0x3f83, 0x3f83 }, +/* 0x3f84 */ { false, 0x3f84, 0x3f84 }, +/* 0x3f85 */ { false, 0x3f85, 0x3f85 }, +/* 0x3f86 */ { false, 0x3f86, 0x3f86 }, +/* 0x3f87 */ { false, 0x3f87, 0x3f87 }, +/* 0x3f88 */ { false, 0x3f88, 0x3f88 }, +/* 0x3f89 */ { false, 0x3f89, 0x3f89 }, +/* 0x3f8a */ { false, 0x3f8a, 0x3f8a }, +/* 0x3f8b */ { false, 0x3f8b, 0x3f8b }, +/* 0x3f8c */ { false, 0x3f8c, 0x3f8c }, +/* 0x3f8d */ { false, 0x3f8d, 0x3f8d }, +/* 0x3f8e */ { false, 0x3f8e, 0x3f8e }, +/* 0x3f8f */ { false, 0x3f8f, 0x3f8f }, +/* 0x3f90 */ { false, 0x3f90, 0x3f90 }, +/* 0x3f91 */ { false, 0x3f91, 0x3f91 }, +/* 0x3f92 */ { false, 0x3f92, 0x3f92 }, +/* 0x3f93 */ { false, 0x3f93, 0x3f93 }, +/* 0x3f94 */ { false, 0x3f94, 0x3f94 }, +/* 0x3f95 */ { false, 0x3f95, 0x3f95 }, +/* 0x3f96 */ { false, 0x3f96, 0x3f96 }, +/* 0x3f97 */ { false, 0x3f97, 0x3f97 }, +/* 0x3f98 */ { false, 0x3f98, 0x3f98 }, +/* 0x3f99 */ { false, 0x3f99, 0x3f99 }, +/* 0x3f9a */ { false, 0x3f9a, 0x3f9a }, +/* 0x3f9b */ { false, 0x3f9b, 0x3f9b }, +/* 0x3f9c */ { false, 0x3f9c, 0x3f9c }, +/* 0x3f9d */ { false, 0x3f9d, 0x3f9d }, +/* 0x3f9e */ { false, 0x3f9e, 0x3f9e }, +/* 0x3f9f */ { false, 0x3f9f, 0x3f9f }, +/* 0x3fa0 */ { false, 0x3fa0, 0x3fa0 }, +/* 0x3fa1 */ { false, 0x3fa1, 0x3fa1 }, +/* 0x3fa2 */ { false, 0x3fa2, 0x3fa2 }, +/* 0x3fa3 */ { false, 0x3fa3, 0x3fa3 }, +/* 0x3fa4 */ { false, 0x3fa4, 0x3fa4 }, +/* 0x3fa5 */ { false, 0x3fa5, 0x3fa5 }, +/* 0x3fa6 */ { false, 0x3fa6, 0x3fa6 }, +/* 0x3fa7 */ { false, 0x3fa7, 0x3fa7 }, +/* 0x3fa8 */ { false, 0x3fa8, 0x3fa8 }, +/* 0x3fa9 */ { false, 0x3fa9, 0x3fa9 }, +/* 0x3faa */ { false, 0x3faa, 0x3faa }, +/* 0x3fab */ { false, 0x3fab, 0x3fab }, +/* 0x3fac */ { false, 0x3fac, 0x3fac }, +/* 0x3fad */ { false, 0x3fad, 0x3fad }, +/* 0x3fae */ { false, 0x3fae, 0x3fae }, +/* 0x3faf */ { false, 0x3faf, 0x3faf }, +/* 0x3fb0 */ { false, 0x3fb0, 0x3fb0 }, +/* 0x3fb1 */ { false, 0x3fb1, 0x3fb1 }, +/* 0x3fb2 */ { false, 0x3fb2, 0x3fb2 }, +/* 0x3fb3 */ { false, 0x3fb3, 0x3fb3 }, +/* 0x3fb4 */ { false, 0x3fb4, 0x3fb4 }, +/* 0x3fb5 */ { false, 0x3fb5, 0x3fb5 }, +/* 0x3fb6 */ { false, 0x3fb6, 0x3fb6 }, +/* 0x3fb7 */ { false, 0x3fb7, 0x3fb7 }, +/* 0x3fb8 */ { false, 0x3fb8, 0x3fb8 }, +/* 0x3fb9 */ { false, 0x3fb9, 0x3fb9 }, +/* 0x3fba */ { false, 0x3fba, 0x3fba }, +/* 0x3fbb */ { false, 0x3fbb, 0x3fbb }, +/* 0x3fbc */ { false, 0x3fbc, 0x3fbc }, +/* 0x3fbd */ { false, 0x3fbd, 0x3fbd }, +/* 0x3fbe */ { false, 0x3fbe, 0x3fbe }, +/* 0x3fbf */ { false, 0x3fbf, 0x3fbf }, +/* 0x3fc0 */ { false, 0x3fc0, 0x3fc0 }, +/* 0x3fc1 */ { false, 0x3fc1, 0x3fc1 }, +/* 0x3fc2 */ { false, 0x3fc2, 0x3fc2 }, +/* 0x3fc3 */ { false, 0x3fc3, 0x3fc3 }, +/* 0x3fc4 */ { false, 0x3fc4, 0x3fc4 }, +/* 0x3fc5 */ { false, 0x3fc5, 0x3fc5 }, +/* 0x3fc6 */ { false, 0x3fc6, 0x3fc6 }, +/* 0x3fc7 */ { false, 0x3fc7, 0x3fc7 }, +/* 0x3fc8 */ { false, 0x3fc8, 0x3fc8 }, +/* 0x3fc9 */ { false, 0x3fc9, 0x3fc9 }, +/* 0x3fca */ { false, 0x3fca, 0x3fca }, +/* 0x3fcb */ { false, 0x3fcb, 0x3fcb }, +/* 0x3fcc */ { false, 0x3fcc, 0x3fcc }, +/* 0x3fcd */ { false, 0x3fcd, 0x3fcd }, +/* 0x3fce */ { false, 0x3fce, 0x3fce }, +/* 0x3fcf */ { false, 0x3fcf, 0x3fcf }, +/* 0x3fd0 */ { false, 0x3fd0, 0x3fd0 }, +/* 0x3fd1 */ { false, 0x3fd1, 0x3fd1 }, +/* 0x3fd2 */ { false, 0x3fd2, 0x3fd2 }, +/* 0x3fd3 */ { false, 0x3fd3, 0x3fd3 }, +/* 0x3fd4 */ { false, 0x3fd4, 0x3fd4 }, +/* 0x3fd5 */ { false, 0x3fd5, 0x3fd5 }, +/* 0x3fd6 */ { false, 0x3fd6, 0x3fd6 }, +/* 0x3fd7 */ { false, 0x3fd7, 0x3fd7 }, +/* 0x3fd8 */ { false, 0x3fd8, 0x3fd8 }, +/* 0x3fd9 */ { false, 0x3fd9, 0x3fd9 }, +/* 0x3fda */ { false, 0x3fda, 0x3fda }, +/* 0x3fdb */ { false, 0x3fdb, 0x3fdb }, +/* 0x3fdc */ { false, 0x3fdc, 0x3fdc }, +/* 0x3fdd */ { false, 0x3fdd, 0x3fdd }, +/* 0x3fde */ { false, 0x3fde, 0x3fde }, +/* 0x3fdf */ { false, 0x3fdf, 0x3fdf }, +/* 0x3fe0 */ { false, 0x3fe0, 0x3fe0 }, +/* 0x3fe1 */ { false, 0x3fe1, 0x3fe1 }, +/* 0x3fe2 */ { false, 0x3fe2, 0x3fe2 }, +/* 0x3fe3 */ { false, 0x3fe3, 0x3fe3 }, +/* 0x3fe4 */ { false, 0x3fe4, 0x3fe4 }, +/* 0x3fe5 */ { false, 0x3fe5, 0x3fe5 }, +/* 0x3fe6 */ { false, 0x3fe6, 0x3fe6 }, +/* 0x3fe7 */ { false, 0x3fe7, 0x3fe7 }, +/* 0x3fe8 */ { false, 0x3fe8, 0x3fe8 }, +/* 0x3fe9 */ { false, 0x3fe9, 0x3fe9 }, +/* 0x3fea */ { false, 0x3fea, 0x3fea }, +/* 0x3feb */ { false, 0x3feb, 0x3feb }, +/* 0x3fec */ { false, 0x3fec, 0x3fec }, +/* 0x3fed */ { false, 0x3fed, 0x3fed }, +/* 0x3fee */ { false, 0x3fee, 0x3fee }, +/* 0x3fef */ { false, 0x3fef, 0x3fef }, +/* 0x3ff0 */ { false, 0x3ff0, 0x3ff0 }, +/* 0x3ff1 */ { false, 0x3ff1, 0x3ff1 }, +/* 0x3ff2 */ { false, 0x3ff2, 0x3ff2 }, +/* 0x3ff3 */ { false, 0x3ff3, 0x3ff3 }, +/* 0x3ff4 */ { false, 0x3ff4, 0x3ff4 }, +/* 0x3ff5 */ { false, 0x3ff5, 0x3ff5 }, +/* 0x3ff6 */ { false, 0x3ff6, 0x3ff6 }, +/* 0x3ff7 */ { false, 0x3ff7, 0x3ff7 }, +/* 0x3ff8 */ { false, 0x3ff8, 0x3ff8 }, +/* 0x3ff9 */ { false, 0x3ff9, 0x3ff9 }, +/* 0x3ffa */ { false, 0x3ffa, 0x3ffa }, +/* 0x3ffb */ { false, 0x3ffb, 0x3ffb }, +/* 0x3ffc */ { false, 0x3ffc, 0x3ffc }, +/* 0x3ffd */ { false, 0x3ffd, 0x3ffd }, +/* 0x3ffe */ { false, 0x3ffe, 0x3ffe }, +/* 0x3fff */ { false, 0x3fff, 0x3fff }, +/* 0x4000 */ { false, 0x4000, 0x4000 }, +/* 0x4001 */ { false, 0x4001, 0x4001 }, +/* 0x4002 */ { false, 0x4002, 0x4002 }, +/* 0x4003 */ { false, 0x4003, 0x4003 }, +/* 0x4004 */ { false, 0x4004, 0x4004 }, +/* 0x4005 */ { false, 0x4005, 0x4005 }, +/* 0x4006 */ { false, 0x4006, 0x4006 }, +/* 0x4007 */ { false, 0x4007, 0x4007 }, +/* 0x4008 */ { false, 0x4008, 0x4008 }, +/* 0x4009 */ { false, 0x4009, 0x4009 }, +/* 0x400a */ { false, 0x400a, 0x400a }, +/* 0x400b */ { false, 0x400b, 0x400b }, +/* 0x400c */ { false, 0x400c, 0x400c }, +/* 0x400d */ { false, 0x400d, 0x400d }, +/* 0x400e */ { false, 0x400e, 0x400e }, +/* 0x400f */ { false, 0x400f, 0x400f }, +/* 0x4010 */ { false, 0x4010, 0x4010 }, +/* 0x4011 */ { false, 0x4011, 0x4011 }, +/* 0x4012 */ { false, 0x4012, 0x4012 }, +/* 0x4013 */ { false, 0x4013, 0x4013 }, +/* 0x4014 */ { false, 0x4014, 0x4014 }, +/* 0x4015 */ { false, 0x4015, 0x4015 }, +/* 0x4016 */ { false, 0x4016, 0x4016 }, +/* 0x4017 */ { false, 0x4017, 0x4017 }, +/* 0x4018 */ { false, 0x4018, 0x4018 }, +/* 0x4019 */ { false, 0x4019, 0x4019 }, +/* 0x401a */ { false, 0x401a, 0x401a }, +/* 0x401b */ { false, 0x401b, 0x401b }, +/* 0x401c */ { false, 0x401c, 0x401c }, +/* 0x401d */ { false, 0x401d, 0x401d }, +/* 0x401e */ { false, 0x401e, 0x401e }, +/* 0x401f */ { false, 0x401f, 0x401f }, +/* 0x4020 */ { false, 0x4020, 0x4020 }, +/* 0x4021 */ { false, 0x4021, 0x4021 }, +/* 0x4022 */ { false, 0x4022, 0x4022 }, +/* 0x4023 */ { false, 0x4023, 0x4023 }, +/* 0x4024 */ { false, 0x4024, 0x4024 }, +/* 0x4025 */ { false, 0x4025, 0x4025 }, +/* 0x4026 */ { false, 0x4026, 0x4026 }, +/* 0x4027 */ { false, 0x4027, 0x4027 }, +/* 0x4028 */ { false, 0x4028, 0x4028 }, +/* 0x4029 */ { false, 0x4029, 0x4029 }, +/* 0x402a */ { false, 0x402a, 0x402a }, +/* 0x402b */ { false, 0x402b, 0x402b }, +/* 0x402c */ { false, 0x402c, 0x402c }, +/* 0x402d */ { false, 0x402d, 0x402d }, +/* 0x402e */ { false, 0x402e, 0x402e }, +/* 0x402f */ { false, 0x402f, 0x402f }, +/* 0x4030 */ { false, 0x4030, 0x4030 }, +/* 0x4031 */ { false, 0x4031, 0x4031 }, +/* 0x4032 */ { false, 0x4032, 0x4032 }, +/* 0x4033 */ { false, 0x4033, 0x4033 }, +/* 0x4034 */ { false, 0x4034, 0x4034 }, +/* 0x4035 */ { false, 0x4035, 0x4035 }, +/* 0x4036 */ { false, 0x4036, 0x4036 }, +/* 0x4037 */ { false, 0x4037, 0x4037 }, +/* 0x4038 */ { false, 0x4038, 0x4038 }, +/* 0x4039 */ { false, 0x4039, 0x4039 }, +/* 0x403a */ { false, 0x403a, 0x403a }, +/* 0x403b */ { false, 0x403b, 0x403b }, +/* 0x403c */ { false, 0x403c, 0x403c }, +/* 0x403d */ { false, 0x403d, 0x403d }, +/* 0x403e */ { false, 0x403e, 0x403e }, +/* 0x403f */ { false, 0x403f, 0x403f }, +/* 0x4040 */ { false, 0x4040, 0x4040 }, +/* 0x4041 */ { false, 0x4041, 0x4041 }, +/* 0x4042 */ { false, 0x4042, 0x4042 }, +/* 0x4043 */ { false, 0x4043, 0x4043 }, +/* 0x4044 */ { false, 0x4044, 0x4044 }, +/* 0x4045 */ { false, 0x4045, 0x4045 }, +/* 0x4046 */ { false, 0x4046, 0x4046 }, +/* 0x4047 */ { false, 0x4047, 0x4047 }, +/* 0x4048 */ { false, 0x4048, 0x4048 }, +/* 0x4049 */ { false, 0x4049, 0x4049 }, +/* 0x404a */ { false, 0x404a, 0x404a }, +/* 0x404b */ { false, 0x404b, 0x404b }, +/* 0x404c */ { false, 0x404c, 0x404c }, +/* 0x404d */ { false, 0x404d, 0x404d }, +/* 0x404e */ { false, 0x404e, 0x404e }, +/* 0x404f */ { false, 0x404f, 0x404f }, +/* 0x4050 */ { false, 0x4050, 0x4050 }, +/* 0x4051 */ { false, 0x4051, 0x4051 }, +/* 0x4052 */ { false, 0x4052, 0x4052 }, +/* 0x4053 */ { false, 0x4053, 0x4053 }, +/* 0x4054 */ { false, 0x4054, 0x4054 }, +/* 0x4055 */ { false, 0x4055, 0x4055 }, +/* 0x4056 */ { false, 0x4056, 0x4056 }, +/* 0x4057 */ { false, 0x4057, 0x4057 }, +/* 0x4058 */ { false, 0x4058, 0x4058 }, +/* 0x4059 */ { false, 0x4059, 0x4059 }, +/* 0x405a */ { false, 0x405a, 0x405a }, +/* 0x405b */ { false, 0x405b, 0x405b }, +/* 0x405c */ { false, 0x405c, 0x405c }, +/* 0x405d */ { false, 0x405d, 0x405d }, +/* 0x405e */ { false, 0x405e, 0x405e }, +/* 0x405f */ { false, 0x405f, 0x405f }, +/* 0x4060 */ { false, 0x4060, 0x4060 }, +/* 0x4061 */ { false, 0x4061, 0x4061 }, +/* 0x4062 */ { false, 0x4062, 0x4062 }, +/* 0x4063 */ { false, 0x4063, 0x4063 }, +/* 0x4064 */ { false, 0x4064, 0x4064 }, +/* 0x4065 */ { false, 0x4065, 0x4065 }, +/* 0x4066 */ { false, 0x4066, 0x4066 }, +/* 0x4067 */ { false, 0x4067, 0x4067 }, +/* 0x4068 */ { false, 0x4068, 0x4068 }, +/* 0x4069 */ { false, 0x4069, 0x4069 }, +/* 0x406a */ { false, 0x406a, 0x406a }, +/* 0x406b */ { false, 0x406b, 0x406b }, +/* 0x406c */ { false, 0x406c, 0x406c }, +/* 0x406d */ { false, 0x406d, 0x406d }, +/* 0x406e */ { false, 0x406e, 0x406e }, +/* 0x406f */ { false, 0x406f, 0x406f }, +/* 0x4070 */ { false, 0x4070, 0x4070 }, +/* 0x4071 */ { false, 0x4071, 0x4071 }, +/* 0x4072 */ { false, 0x4072, 0x4072 }, +/* 0x4073 */ { false, 0x4073, 0x4073 }, +/* 0x4074 */ { false, 0x4074, 0x4074 }, +/* 0x4075 */ { false, 0x4075, 0x4075 }, +/* 0x4076 */ { false, 0x4076, 0x4076 }, +/* 0x4077 */ { false, 0x4077, 0x4077 }, +/* 0x4078 */ { false, 0x4078, 0x4078 }, +/* 0x4079 */ { false, 0x4079, 0x4079 }, +/* 0x407a */ { false, 0x407a, 0x407a }, +/* 0x407b */ { false, 0x407b, 0x407b }, +/* 0x407c */ { false, 0x407c, 0x407c }, +/* 0x407d */ { false, 0x407d, 0x407d }, +/* 0x407e */ { false, 0x407e, 0x407e }, +/* 0x407f */ { false, 0x407f, 0x407f }, +/* 0x4080 */ { false, 0x4080, 0x4080 }, +/* 0x4081 */ { false, 0x4081, 0x4081 }, +/* 0x4082 */ { false, 0x4082, 0x4082 }, +/* 0x4083 */ { false, 0x4083, 0x4083 }, +/* 0x4084 */ { false, 0x4084, 0x4084 }, +/* 0x4085 */ { false, 0x4085, 0x4085 }, +/* 0x4086 */ { false, 0x4086, 0x4086 }, +/* 0x4087 */ { false, 0x4087, 0x4087 }, +/* 0x4088 */ { false, 0x4088, 0x4088 }, +/* 0x4089 */ { false, 0x4089, 0x4089 }, +/* 0x408a */ { false, 0x408a, 0x408a }, +/* 0x408b */ { false, 0x408b, 0x408b }, +/* 0x408c */ { false, 0x408c, 0x408c }, +/* 0x408d */ { false, 0x408d, 0x408d }, +/* 0x408e */ { false, 0x408e, 0x408e }, +/* 0x408f */ { false, 0x408f, 0x408f }, +/* 0x4090 */ { false, 0x4090, 0x4090 }, +/* 0x4091 */ { false, 0x4091, 0x4091 }, +/* 0x4092 */ { false, 0x4092, 0x4092 }, +/* 0x4093 */ { false, 0x4093, 0x4093 }, +/* 0x4094 */ { false, 0x4094, 0x4094 }, +/* 0x4095 */ { false, 0x4095, 0x4095 }, +/* 0x4096 */ { false, 0x4096, 0x4096 }, +/* 0x4097 */ { false, 0x4097, 0x4097 }, +/* 0x4098 */ { false, 0x4098, 0x4098 }, +/* 0x4099 */ { false, 0x4099, 0x4099 }, +/* 0x409a */ { false, 0x409a, 0x409a }, +/* 0x409b */ { false, 0x409b, 0x409b }, +/* 0x409c */ { false, 0x409c, 0x409c }, +/* 0x409d */ { false, 0x409d, 0x409d }, +/* 0x409e */ { false, 0x409e, 0x409e }, +/* 0x409f */ { false, 0x409f, 0x409f }, +/* 0x40a0 */ { false, 0x40a0, 0x40a0 }, +/* 0x40a1 */ { false, 0x40a1, 0x40a1 }, +/* 0x40a2 */ { false, 0x40a2, 0x40a2 }, +/* 0x40a3 */ { false, 0x40a3, 0x40a3 }, +/* 0x40a4 */ { false, 0x40a4, 0x40a4 }, +/* 0x40a5 */ { false, 0x40a5, 0x40a5 }, +/* 0x40a6 */ { false, 0x40a6, 0x40a6 }, +/* 0x40a7 */ { false, 0x40a7, 0x40a7 }, +/* 0x40a8 */ { false, 0x40a8, 0x40a8 }, +/* 0x40a9 */ { false, 0x40a9, 0x40a9 }, +/* 0x40aa */ { false, 0x40aa, 0x40aa }, +/* 0x40ab */ { false, 0x40ab, 0x40ab }, +/* 0x40ac */ { false, 0x40ac, 0x40ac }, +/* 0x40ad */ { false, 0x40ad, 0x40ad }, +/* 0x40ae */ { false, 0x40ae, 0x40ae }, +/* 0x40af */ { false, 0x40af, 0x40af }, +/* 0x40b0 */ { false, 0x40b0, 0x40b0 }, +/* 0x40b1 */ { false, 0x40b1, 0x40b1 }, +/* 0x40b2 */ { false, 0x40b2, 0x40b2 }, +/* 0x40b3 */ { false, 0x40b3, 0x40b3 }, +/* 0x40b4 */ { false, 0x40b4, 0x40b4 }, +/* 0x40b5 */ { false, 0x40b5, 0x40b5 }, +/* 0x40b6 */ { false, 0x40b6, 0x40b6 }, +/* 0x40b7 */ { false, 0x40b7, 0x40b7 }, +/* 0x40b8 */ { false, 0x40b8, 0x40b8 }, +/* 0x40b9 */ { false, 0x40b9, 0x40b9 }, +/* 0x40ba */ { false, 0x40ba, 0x40ba }, +/* 0x40bb */ { false, 0x40bb, 0x40bb }, +/* 0x40bc */ { false, 0x40bc, 0x40bc }, +/* 0x40bd */ { false, 0x40bd, 0x40bd }, +/* 0x40be */ { false, 0x40be, 0x40be }, +/* 0x40bf */ { false, 0x40bf, 0x40bf }, +/* 0x40c0 */ { false, 0x40c0, 0x40c0 }, +/* 0x40c1 */ { false, 0x40c1, 0x40c1 }, +/* 0x40c2 */ { false, 0x40c2, 0x40c2 }, +/* 0x40c3 */ { false, 0x40c3, 0x40c3 }, +/* 0x40c4 */ { false, 0x40c4, 0x40c4 }, +/* 0x40c5 */ { false, 0x40c5, 0x40c5 }, +/* 0x40c6 */ { false, 0x40c6, 0x40c6 }, +/* 0x40c7 */ { false, 0x40c7, 0x40c7 }, +/* 0x40c8 */ { false, 0x40c8, 0x40c8 }, +/* 0x40c9 */ { false, 0x40c9, 0x40c9 }, +/* 0x40ca */ { false, 0x40ca, 0x40ca }, +/* 0x40cb */ { false, 0x40cb, 0x40cb }, +/* 0x40cc */ { false, 0x40cc, 0x40cc }, +/* 0x40cd */ { false, 0x40cd, 0x40cd }, +/* 0x40ce */ { false, 0x40ce, 0x40ce }, +/* 0x40cf */ { false, 0x40cf, 0x40cf }, +/* 0x40d0 */ { false, 0x40d0, 0x40d0 }, +/* 0x40d1 */ { false, 0x40d1, 0x40d1 }, +/* 0x40d2 */ { false, 0x40d2, 0x40d2 }, +/* 0x40d3 */ { false, 0x40d3, 0x40d3 }, +/* 0x40d4 */ { false, 0x40d4, 0x40d4 }, +/* 0x40d5 */ { false, 0x40d5, 0x40d5 }, +/* 0x40d6 */ { false, 0x40d6, 0x40d6 }, +/* 0x40d7 */ { false, 0x40d7, 0x40d7 }, +/* 0x40d8 */ { false, 0x40d8, 0x40d8 }, +/* 0x40d9 */ { false, 0x40d9, 0x40d9 }, +/* 0x40da */ { false, 0x40da, 0x40da }, +/* 0x40db */ { false, 0x40db, 0x40db }, +/* 0x40dc */ { false, 0x40dc, 0x40dc }, +/* 0x40dd */ { false, 0x40dd, 0x40dd }, +/* 0x40de */ { false, 0x40de, 0x40de }, +/* 0x40df */ { false, 0x40df, 0x40df }, +/* 0x40e0 */ { false, 0x40e0, 0x40e0 }, +/* 0x40e1 */ { false, 0x40e1, 0x40e1 }, +/* 0x40e2 */ { false, 0x40e2, 0x40e2 }, +/* 0x40e3 */ { false, 0x40e3, 0x40e3 }, +/* 0x40e4 */ { false, 0x40e4, 0x40e4 }, +/* 0x40e5 */ { false, 0x40e5, 0x40e5 }, +/* 0x40e6 */ { false, 0x40e6, 0x40e6 }, +/* 0x40e7 */ { false, 0x40e7, 0x40e7 }, +/* 0x40e8 */ { false, 0x40e8, 0x40e8 }, +/* 0x40e9 */ { false, 0x40e9, 0x40e9 }, +/* 0x40ea */ { false, 0x40ea, 0x40ea }, +/* 0x40eb */ { false, 0x40eb, 0x40eb }, +/* 0x40ec */ { false, 0x40ec, 0x40ec }, +/* 0x40ed */ { false, 0x40ed, 0x40ed }, +/* 0x40ee */ { false, 0x40ee, 0x40ee }, +/* 0x40ef */ { false, 0x40ef, 0x40ef }, +/* 0x40f0 */ { false, 0x40f0, 0x40f0 }, +/* 0x40f1 */ { false, 0x40f1, 0x40f1 }, +/* 0x40f2 */ { false, 0x40f2, 0x40f2 }, +/* 0x40f3 */ { false, 0x40f3, 0x40f3 }, +/* 0x40f4 */ { false, 0x40f4, 0x40f4 }, +/* 0x40f5 */ { false, 0x40f5, 0x40f5 }, +/* 0x40f6 */ { false, 0x40f6, 0x40f6 }, +/* 0x40f7 */ { false, 0x40f7, 0x40f7 }, +/* 0x40f8 */ { false, 0x40f8, 0x40f8 }, +/* 0x40f9 */ { false, 0x40f9, 0x40f9 }, +/* 0x40fa */ { false, 0x40fa, 0x40fa }, +/* 0x40fb */ { false, 0x40fb, 0x40fb }, +/* 0x40fc */ { false, 0x40fc, 0x40fc }, +/* 0x40fd */ { false, 0x40fd, 0x40fd }, +/* 0x40fe */ { false, 0x40fe, 0x40fe }, +/* 0x40ff */ { false, 0x40ff, 0x40ff }, +/* 0x4100 */ { false, 0x4100, 0x4100 }, +/* 0x4101 */ { false, 0x4101, 0x4101 }, +/* 0x4102 */ { false, 0x4102, 0x4102 }, +/* 0x4103 */ { false, 0x4103, 0x4103 }, +/* 0x4104 */ { false, 0x4104, 0x4104 }, +/* 0x4105 */ { false, 0x4105, 0x4105 }, +/* 0x4106 */ { false, 0x4106, 0x4106 }, +/* 0x4107 */ { false, 0x4107, 0x4107 }, +/* 0x4108 */ { false, 0x4108, 0x4108 }, +/* 0x4109 */ { false, 0x4109, 0x4109 }, +/* 0x410a */ { false, 0x410a, 0x410a }, +/* 0x410b */ { false, 0x410b, 0x410b }, +/* 0x410c */ { false, 0x410c, 0x410c }, +/* 0x410d */ { false, 0x410d, 0x410d }, +/* 0x410e */ { false, 0x410e, 0x410e }, +/* 0x410f */ { false, 0x410f, 0x410f }, +/* 0x4110 */ { false, 0x4110, 0x4110 }, +/* 0x4111 */ { false, 0x4111, 0x4111 }, +/* 0x4112 */ { false, 0x4112, 0x4112 }, +/* 0x4113 */ { false, 0x4113, 0x4113 }, +/* 0x4114 */ { false, 0x4114, 0x4114 }, +/* 0x4115 */ { false, 0x4115, 0x4115 }, +/* 0x4116 */ { false, 0x4116, 0x4116 }, +/* 0x4117 */ { false, 0x4117, 0x4117 }, +/* 0x4118 */ { false, 0x4118, 0x4118 }, +/* 0x4119 */ { false, 0x4119, 0x4119 }, +/* 0x411a */ { false, 0x411a, 0x411a }, +/* 0x411b */ { false, 0x411b, 0x411b }, +/* 0x411c */ { false, 0x411c, 0x411c }, +/* 0x411d */ { false, 0x411d, 0x411d }, +/* 0x411e */ { false, 0x411e, 0x411e }, +/* 0x411f */ { false, 0x411f, 0x411f }, +/* 0x4120 */ { false, 0x4120, 0x4120 }, +/* 0x4121 */ { false, 0x4121, 0x4121 }, +/* 0x4122 */ { false, 0x4122, 0x4122 }, +/* 0x4123 */ { false, 0x4123, 0x4123 }, +/* 0x4124 */ { false, 0x4124, 0x4124 }, +/* 0x4125 */ { false, 0x4125, 0x4125 }, +/* 0x4126 */ { false, 0x4126, 0x4126 }, +/* 0x4127 */ { false, 0x4127, 0x4127 }, +/* 0x4128 */ { false, 0x4128, 0x4128 }, +/* 0x4129 */ { false, 0x4129, 0x4129 }, +/* 0x412a */ { false, 0x412a, 0x412a }, +/* 0x412b */ { false, 0x412b, 0x412b }, +/* 0x412c */ { false, 0x412c, 0x412c }, +/* 0x412d */ { false, 0x412d, 0x412d }, +/* 0x412e */ { false, 0x412e, 0x412e }, +/* 0x412f */ { false, 0x412f, 0x412f }, +/* 0x4130 */ { false, 0x4130, 0x4130 }, +/* 0x4131 */ { false, 0x4131, 0x4131 }, +/* 0x4132 */ { false, 0x4132, 0x4132 }, +/* 0x4133 */ { false, 0x4133, 0x4133 }, +/* 0x4134 */ { false, 0x4134, 0x4134 }, +/* 0x4135 */ { false, 0x4135, 0x4135 }, +/* 0x4136 */ { false, 0x4136, 0x4136 }, +/* 0x4137 */ { false, 0x4137, 0x4137 }, +/* 0x4138 */ { false, 0x4138, 0x4138 }, +/* 0x4139 */ { false, 0x4139, 0x4139 }, +/* 0x413a */ { false, 0x413a, 0x413a }, +/* 0x413b */ { false, 0x413b, 0x413b }, +/* 0x413c */ { false, 0x413c, 0x413c }, +/* 0x413d */ { false, 0x413d, 0x413d }, +/* 0x413e */ { false, 0x413e, 0x413e }, +/* 0x413f */ { false, 0x413f, 0x413f }, +/* 0x4140 */ { false, 0x4140, 0x4140 }, +/* 0x4141 */ { false, 0x4141, 0x4141 }, +/* 0x4142 */ { false, 0x4142, 0x4142 }, +/* 0x4143 */ { false, 0x4143, 0x4143 }, +/* 0x4144 */ { false, 0x4144, 0x4144 }, +/* 0x4145 */ { false, 0x4145, 0x4145 }, +/* 0x4146 */ { false, 0x4146, 0x4146 }, +/* 0x4147 */ { false, 0x4147, 0x4147 }, +/* 0x4148 */ { false, 0x4148, 0x4148 }, +/* 0x4149 */ { false, 0x4149, 0x4149 }, +/* 0x414a */ { false, 0x414a, 0x414a }, +/* 0x414b */ { false, 0x414b, 0x414b }, +/* 0x414c */ { false, 0x414c, 0x414c }, +/* 0x414d */ { false, 0x414d, 0x414d }, +/* 0x414e */ { false, 0x414e, 0x414e }, +/* 0x414f */ { false, 0x414f, 0x414f }, +/* 0x4150 */ { false, 0x4150, 0x4150 }, +/* 0x4151 */ { false, 0x4151, 0x4151 }, +/* 0x4152 */ { false, 0x4152, 0x4152 }, +/* 0x4153 */ { false, 0x4153, 0x4153 }, +/* 0x4154 */ { false, 0x4154, 0x4154 }, +/* 0x4155 */ { false, 0x4155, 0x4155 }, +/* 0x4156 */ { false, 0x4156, 0x4156 }, +/* 0x4157 */ { false, 0x4157, 0x4157 }, +/* 0x4158 */ { false, 0x4158, 0x4158 }, +/* 0x4159 */ { false, 0x4159, 0x4159 }, +/* 0x415a */ { false, 0x415a, 0x415a }, +/* 0x415b */ { false, 0x415b, 0x415b }, +/* 0x415c */ { false, 0x415c, 0x415c }, +/* 0x415d */ { false, 0x415d, 0x415d }, +/* 0x415e */ { false, 0x415e, 0x415e }, +/* 0x415f */ { false, 0x415f, 0x415f }, +/* 0x4160 */ { false, 0x4160, 0x4160 }, +/* 0x4161 */ { false, 0x4161, 0x4161 }, +/* 0x4162 */ { false, 0x4162, 0x4162 }, +/* 0x4163 */ { false, 0x4163, 0x4163 }, +/* 0x4164 */ { false, 0x4164, 0x4164 }, +/* 0x4165 */ { false, 0x4165, 0x4165 }, +/* 0x4166 */ { false, 0x4166, 0x4166 }, +/* 0x4167 */ { false, 0x4167, 0x4167 }, +/* 0x4168 */ { false, 0x4168, 0x4168 }, +/* 0x4169 */ { false, 0x4169, 0x4169 }, +/* 0x416a */ { false, 0x416a, 0x416a }, +/* 0x416b */ { false, 0x416b, 0x416b }, +/* 0x416c */ { false, 0x416c, 0x416c }, +/* 0x416d */ { false, 0x416d, 0x416d }, +/* 0x416e */ { false, 0x416e, 0x416e }, +/* 0x416f */ { false, 0x416f, 0x416f }, +/* 0x4170 */ { false, 0x4170, 0x4170 }, +/* 0x4171 */ { false, 0x4171, 0x4171 }, +/* 0x4172 */ { false, 0x4172, 0x4172 }, +/* 0x4173 */ { false, 0x4173, 0x4173 }, +/* 0x4174 */ { false, 0x4174, 0x4174 }, +/* 0x4175 */ { false, 0x4175, 0x4175 }, +/* 0x4176 */ { false, 0x4176, 0x4176 }, +/* 0x4177 */ { false, 0x4177, 0x4177 }, +/* 0x4178 */ { false, 0x4178, 0x4178 }, +/* 0x4179 */ { false, 0x4179, 0x4179 }, +/* 0x417a */ { false, 0x417a, 0x417a }, +/* 0x417b */ { false, 0x417b, 0x417b }, +/* 0x417c */ { false, 0x417c, 0x417c }, +/* 0x417d */ { false, 0x417d, 0x417d }, +/* 0x417e */ { false, 0x417e, 0x417e }, +/* 0x417f */ { false, 0x417f, 0x417f }, +/* 0x4180 */ { false, 0x4180, 0x4180 }, +/* 0x4181 */ { false, 0x4181, 0x4181 }, +/* 0x4182 */ { false, 0x4182, 0x4182 }, +/* 0x4183 */ { false, 0x4183, 0x4183 }, +/* 0x4184 */ { false, 0x4184, 0x4184 }, +/* 0x4185 */ { false, 0x4185, 0x4185 }, +/* 0x4186 */ { false, 0x4186, 0x4186 }, +/* 0x4187 */ { false, 0x4187, 0x4187 }, +/* 0x4188 */ { false, 0x4188, 0x4188 }, +/* 0x4189 */ { false, 0x4189, 0x4189 }, +/* 0x418a */ { false, 0x418a, 0x418a }, +/* 0x418b */ { false, 0x418b, 0x418b }, +/* 0x418c */ { false, 0x418c, 0x418c }, +/* 0x418d */ { false, 0x418d, 0x418d }, +/* 0x418e */ { false, 0x418e, 0x418e }, +/* 0x418f */ { false, 0x418f, 0x418f }, +/* 0x4190 */ { false, 0x4190, 0x4190 }, +/* 0x4191 */ { false, 0x4191, 0x4191 }, +/* 0x4192 */ { false, 0x4192, 0x4192 }, +/* 0x4193 */ { false, 0x4193, 0x4193 }, +/* 0x4194 */ { false, 0x4194, 0x4194 }, +/* 0x4195 */ { false, 0x4195, 0x4195 }, +/* 0x4196 */ { false, 0x4196, 0x4196 }, +/* 0x4197 */ { false, 0x4197, 0x4197 }, +/* 0x4198 */ { false, 0x4198, 0x4198 }, +/* 0x4199 */ { false, 0x4199, 0x4199 }, +/* 0x419a */ { false, 0x419a, 0x419a }, +/* 0x419b */ { false, 0x419b, 0x419b }, +/* 0x419c */ { false, 0x419c, 0x419c }, +/* 0x419d */ { false, 0x419d, 0x419d }, +/* 0x419e */ { false, 0x419e, 0x419e }, +/* 0x419f */ { false, 0x419f, 0x419f }, +/* 0x41a0 */ { false, 0x41a0, 0x41a0 }, +/* 0x41a1 */ { false, 0x41a1, 0x41a1 }, +/* 0x41a2 */ { false, 0x41a2, 0x41a2 }, +/* 0x41a3 */ { false, 0x41a3, 0x41a3 }, +/* 0x41a4 */ { false, 0x41a4, 0x41a4 }, +/* 0x41a5 */ { false, 0x41a5, 0x41a5 }, +/* 0x41a6 */ { false, 0x41a6, 0x41a6 }, +/* 0x41a7 */ { false, 0x41a7, 0x41a7 }, +/* 0x41a8 */ { false, 0x41a8, 0x41a8 }, +/* 0x41a9 */ { false, 0x41a9, 0x41a9 }, +/* 0x41aa */ { false, 0x41aa, 0x41aa }, +/* 0x41ab */ { false, 0x41ab, 0x41ab }, +/* 0x41ac */ { false, 0x41ac, 0x41ac }, +/* 0x41ad */ { false, 0x41ad, 0x41ad }, +/* 0x41ae */ { false, 0x41ae, 0x41ae }, +/* 0x41af */ { false, 0x41af, 0x41af }, +/* 0x41b0 */ { false, 0x41b0, 0x41b0 }, +/* 0x41b1 */ { false, 0x41b1, 0x41b1 }, +/* 0x41b2 */ { false, 0x41b2, 0x41b2 }, +/* 0x41b3 */ { false, 0x41b3, 0x41b3 }, +/* 0x41b4 */ { false, 0x41b4, 0x41b4 }, +/* 0x41b5 */ { false, 0x41b5, 0x41b5 }, +/* 0x41b6 */ { false, 0x41b6, 0x41b6 }, +/* 0x41b7 */ { false, 0x41b7, 0x41b7 }, +/* 0x41b8 */ { false, 0x41b8, 0x41b8 }, +/* 0x41b9 */ { false, 0x41b9, 0x41b9 }, +/* 0x41ba */ { false, 0x41ba, 0x41ba }, +/* 0x41bb */ { false, 0x41bb, 0x41bb }, +/* 0x41bc */ { false, 0x41bc, 0x41bc }, +/* 0x41bd */ { false, 0x41bd, 0x41bd }, +/* 0x41be */ { false, 0x41be, 0x41be }, +/* 0x41bf */ { false, 0x41bf, 0x41bf }, +/* 0x41c0 */ { false, 0x41c0, 0x41c0 }, +/* 0x41c1 */ { false, 0x41c1, 0x41c1 }, +/* 0x41c2 */ { false, 0x41c2, 0x41c2 }, +/* 0x41c3 */ { false, 0x41c3, 0x41c3 }, +/* 0x41c4 */ { false, 0x41c4, 0x41c4 }, +/* 0x41c5 */ { false, 0x41c5, 0x41c5 }, +/* 0x41c6 */ { false, 0x41c6, 0x41c6 }, +/* 0x41c7 */ { false, 0x41c7, 0x41c7 }, +/* 0x41c8 */ { false, 0x41c8, 0x41c8 }, +/* 0x41c9 */ { false, 0x41c9, 0x41c9 }, +/* 0x41ca */ { false, 0x41ca, 0x41ca }, +/* 0x41cb */ { false, 0x41cb, 0x41cb }, +/* 0x41cc */ { false, 0x41cc, 0x41cc }, +/* 0x41cd */ { false, 0x41cd, 0x41cd }, +/* 0x41ce */ { false, 0x41ce, 0x41ce }, +/* 0x41cf */ { false, 0x41cf, 0x41cf }, +/* 0x41d0 */ { false, 0x41d0, 0x41d0 }, +/* 0x41d1 */ { false, 0x41d1, 0x41d1 }, +/* 0x41d2 */ { false, 0x41d2, 0x41d2 }, +/* 0x41d3 */ { false, 0x41d3, 0x41d3 }, +/* 0x41d4 */ { false, 0x41d4, 0x41d4 }, +/* 0x41d5 */ { false, 0x41d5, 0x41d5 }, +/* 0x41d6 */ { false, 0x41d6, 0x41d6 }, +/* 0x41d7 */ { false, 0x41d7, 0x41d7 }, +/* 0x41d8 */ { false, 0x41d8, 0x41d8 }, +/* 0x41d9 */ { false, 0x41d9, 0x41d9 }, +/* 0x41da */ { false, 0x41da, 0x41da }, +/* 0x41db */ { false, 0x41db, 0x41db }, +/* 0x41dc */ { false, 0x41dc, 0x41dc }, +/* 0x41dd */ { false, 0x41dd, 0x41dd }, +/* 0x41de */ { false, 0x41de, 0x41de }, +/* 0x41df */ { false, 0x41df, 0x41df }, +/* 0x41e0 */ { false, 0x41e0, 0x41e0 }, +/* 0x41e1 */ { false, 0x41e1, 0x41e1 }, +/* 0x41e2 */ { false, 0x41e2, 0x41e2 }, +/* 0x41e3 */ { false, 0x41e3, 0x41e3 }, +/* 0x41e4 */ { false, 0x41e4, 0x41e4 }, +/* 0x41e5 */ { false, 0x41e5, 0x41e5 }, +/* 0x41e6 */ { false, 0x41e6, 0x41e6 }, +/* 0x41e7 */ { false, 0x41e7, 0x41e7 }, +/* 0x41e8 */ { false, 0x41e8, 0x41e8 }, +/* 0x41e9 */ { false, 0x41e9, 0x41e9 }, +/* 0x41ea */ { false, 0x41ea, 0x41ea }, +/* 0x41eb */ { false, 0x41eb, 0x41eb }, +/* 0x41ec */ { false, 0x41ec, 0x41ec }, +/* 0x41ed */ { false, 0x41ed, 0x41ed }, +/* 0x41ee */ { false, 0x41ee, 0x41ee }, +/* 0x41ef */ { false, 0x41ef, 0x41ef }, +/* 0x41f0 */ { false, 0x41f0, 0x41f0 }, +/* 0x41f1 */ { false, 0x41f1, 0x41f1 }, +/* 0x41f2 */ { false, 0x41f2, 0x41f2 }, +/* 0x41f3 */ { false, 0x41f3, 0x41f3 }, +/* 0x41f4 */ { false, 0x41f4, 0x41f4 }, +/* 0x41f5 */ { false, 0x41f5, 0x41f5 }, +/* 0x41f6 */ { false, 0x41f6, 0x41f6 }, +/* 0x41f7 */ { false, 0x41f7, 0x41f7 }, +/* 0x41f8 */ { false, 0x41f8, 0x41f8 }, +/* 0x41f9 */ { false, 0x41f9, 0x41f9 }, +/* 0x41fa */ { false, 0x41fa, 0x41fa }, +/* 0x41fb */ { false, 0x41fb, 0x41fb }, +/* 0x41fc */ { false, 0x41fc, 0x41fc }, +/* 0x41fd */ { false, 0x41fd, 0x41fd }, +/* 0x41fe */ { false, 0x41fe, 0x41fe }, +/* 0x41ff */ { false, 0x41ff, 0x41ff }, +/* 0x4200 */ { false, 0x4200, 0x4200 }, +/* 0x4201 */ { false, 0x4201, 0x4201 }, +/* 0x4202 */ { false, 0x4202, 0x4202 }, +/* 0x4203 */ { false, 0x4203, 0x4203 }, +/* 0x4204 */ { false, 0x4204, 0x4204 }, +/* 0x4205 */ { false, 0x4205, 0x4205 }, +/* 0x4206 */ { false, 0x4206, 0x4206 }, +/* 0x4207 */ { false, 0x4207, 0x4207 }, +/* 0x4208 */ { false, 0x4208, 0x4208 }, +/* 0x4209 */ { false, 0x4209, 0x4209 }, +/* 0x420a */ { false, 0x420a, 0x420a }, +/* 0x420b */ { false, 0x420b, 0x420b }, +/* 0x420c */ { false, 0x420c, 0x420c }, +/* 0x420d */ { false, 0x420d, 0x420d }, +/* 0x420e */ { false, 0x420e, 0x420e }, +/* 0x420f */ { false, 0x420f, 0x420f }, +/* 0x4210 */ { false, 0x4210, 0x4210 }, +/* 0x4211 */ { false, 0x4211, 0x4211 }, +/* 0x4212 */ { false, 0x4212, 0x4212 }, +/* 0x4213 */ { false, 0x4213, 0x4213 }, +/* 0x4214 */ { false, 0x4214, 0x4214 }, +/* 0x4215 */ { false, 0x4215, 0x4215 }, +/* 0x4216 */ { false, 0x4216, 0x4216 }, +/* 0x4217 */ { false, 0x4217, 0x4217 }, +/* 0x4218 */ { false, 0x4218, 0x4218 }, +/* 0x4219 */ { false, 0x4219, 0x4219 }, +/* 0x421a */ { false, 0x421a, 0x421a }, +/* 0x421b */ { false, 0x421b, 0x421b }, +/* 0x421c */ { false, 0x421c, 0x421c }, +/* 0x421d */ { false, 0x421d, 0x421d }, +/* 0x421e */ { false, 0x421e, 0x421e }, +/* 0x421f */ { false, 0x421f, 0x421f }, +/* 0x4220 */ { false, 0x4220, 0x4220 }, +/* 0x4221 */ { false, 0x4221, 0x4221 }, +/* 0x4222 */ { false, 0x4222, 0x4222 }, +/* 0x4223 */ { false, 0x4223, 0x4223 }, +/* 0x4224 */ { false, 0x4224, 0x4224 }, +/* 0x4225 */ { false, 0x4225, 0x4225 }, +/* 0x4226 */ { false, 0x4226, 0x4226 }, +/* 0x4227 */ { false, 0x4227, 0x4227 }, +/* 0x4228 */ { false, 0x4228, 0x4228 }, +/* 0x4229 */ { false, 0x4229, 0x4229 }, +/* 0x422a */ { false, 0x422a, 0x422a }, +/* 0x422b */ { false, 0x422b, 0x422b }, +/* 0x422c */ { false, 0x422c, 0x422c }, +/* 0x422d */ { false, 0x422d, 0x422d }, +/* 0x422e */ { false, 0x422e, 0x422e }, +/* 0x422f */ { false, 0x422f, 0x422f }, +/* 0x4230 */ { false, 0x4230, 0x4230 }, +/* 0x4231 */ { false, 0x4231, 0x4231 }, +/* 0x4232 */ { false, 0x4232, 0x4232 }, +/* 0x4233 */ { false, 0x4233, 0x4233 }, +/* 0x4234 */ { false, 0x4234, 0x4234 }, +/* 0x4235 */ { false, 0x4235, 0x4235 }, +/* 0x4236 */ { false, 0x4236, 0x4236 }, +/* 0x4237 */ { false, 0x4237, 0x4237 }, +/* 0x4238 */ { false, 0x4238, 0x4238 }, +/* 0x4239 */ { false, 0x4239, 0x4239 }, +/* 0x423a */ { false, 0x423a, 0x423a }, +/* 0x423b */ { false, 0x423b, 0x423b }, +/* 0x423c */ { false, 0x423c, 0x423c }, +/* 0x423d */ { false, 0x423d, 0x423d }, +/* 0x423e */ { false, 0x423e, 0x423e }, +/* 0x423f */ { false, 0x423f, 0x423f }, +/* 0x4240 */ { false, 0x4240, 0x4240 }, +/* 0x4241 */ { false, 0x4241, 0x4241 }, +/* 0x4242 */ { false, 0x4242, 0x4242 }, +/* 0x4243 */ { false, 0x4243, 0x4243 }, +/* 0x4244 */ { false, 0x4244, 0x4244 }, +/* 0x4245 */ { false, 0x4245, 0x4245 }, +/* 0x4246 */ { false, 0x4246, 0x4246 }, +/* 0x4247 */ { false, 0x4247, 0x4247 }, +/* 0x4248 */ { false, 0x4248, 0x4248 }, +/* 0x4249 */ { false, 0x4249, 0x4249 }, +/* 0x424a */ { false, 0x424a, 0x424a }, +/* 0x424b */ { false, 0x424b, 0x424b }, +/* 0x424c */ { false, 0x424c, 0x424c }, +/* 0x424d */ { false, 0x424d, 0x424d }, +/* 0x424e */ { false, 0x424e, 0x424e }, +/* 0x424f */ { false, 0x424f, 0x424f }, +/* 0x4250 */ { false, 0x4250, 0x4250 }, +/* 0x4251 */ { false, 0x4251, 0x4251 }, +/* 0x4252 */ { false, 0x4252, 0x4252 }, +/* 0x4253 */ { false, 0x4253, 0x4253 }, +/* 0x4254 */ { false, 0x4254, 0x4254 }, +/* 0x4255 */ { false, 0x4255, 0x4255 }, +/* 0x4256 */ { false, 0x4256, 0x4256 }, +/* 0x4257 */ { false, 0x4257, 0x4257 }, +/* 0x4258 */ { false, 0x4258, 0x4258 }, +/* 0x4259 */ { false, 0x4259, 0x4259 }, +/* 0x425a */ { false, 0x425a, 0x425a }, +/* 0x425b */ { false, 0x425b, 0x425b }, +/* 0x425c */ { false, 0x425c, 0x425c }, +/* 0x425d */ { false, 0x425d, 0x425d }, +/* 0x425e */ { false, 0x425e, 0x425e }, +/* 0x425f */ { false, 0x425f, 0x425f }, +/* 0x4260 */ { false, 0x4260, 0x4260 }, +/* 0x4261 */ { false, 0x4261, 0x4261 }, +/* 0x4262 */ { false, 0x4262, 0x4262 }, +/* 0x4263 */ { false, 0x4263, 0x4263 }, +/* 0x4264 */ { false, 0x4264, 0x4264 }, +/* 0x4265 */ { false, 0x4265, 0x4265 }, +/* 0x4266 */ { false, 0x4266, 0x4266 }, +/* 0x4267 */ { false, 0x4267, 0x4267 }, +/* 0x4268 */ { false, 0x4268, 0x4268 }, +/* 0x4269 */ { false, 0x4269, 0x4269 }, +/* 0x426a */ { false, 0x426a, 0x426a }, +/* 0x426b */ { false, 0x426b, 0x426b }, +/* 0x426c */ { false, 0x426c, 0x426c }, +/* 0x426d */ { false, 0x426d, 0x426d }, +/* 0x426e */ { false, 0x426e, 0x426e }, +/* 0x426f */ { false, 0x426f, 0x426f }, +/* 0x4270 */ { false, 0x4270, 0x4270 }, +/* 0x4271 */ { false, 0x4271, 0x4271 }, +/* 0x4272 */ { false, 0x4272, 0x4272 }, +/* 0x4273 */ { false, 0x4273, 0x4273 }, +/* 0x4274 */ { false, 0x4274, 0x4274 }, +/* 0x4275 */ { false, 0x4275, 0x4275 }, +/* 0x4276 */ { false, 0x4276, 0x4276 }, +/* 0x4277 */ { false, 0x4277, 0x4277 }, +/* 0x4278 */ { false, 0x4278, 0x4278 }, +/* 0x4279 */ { false, 0x4279, 0x4279 }, +/* 0x427a */ { false, 0x427a, 0x427a }, +/* 0x427b */ { false, 0x427b, 0x427b }, +/* 0x427c */ { false, 0x427c, 0x427c }, +/* 0x427d */ { false, 0x427d, 0x427d }, +/* 0x427e */ { false, 0x427e, 0x427e }, +/* 0x427f */ { false, 0x427f, 0x427f }, +/* 0x4280 */ { false, 0x4280, 0x4280 }, +/* 0x4281 */ { false, 0x4281, 0x4281 }, +/* 0x4282 */ { false, 0x4282, 0x4282 }, +/* 0x4283 */ { false, 0x4283, 0x4283 }, +/* 0x4284 */ { false, 0x4284, 0x4284 }, +/* 0x4285 */ { false, 0x4285, 0x4285 }, +/* 0x4286 */ { false, 0x4286, 0x4286 }, +/* 0x4287 */ { false, 0x4287, 0x4287 }, +/* 0x4288 */ { false, 0x4288, 0x4288 }, +/* 0x4289 */ { false, 0x4289, 0x4289 }, +/* 0x428a */ { false, 0x428a, 0x428a }, +/* 0x428b */ { false, 0x428b, 0x428b }, +/* 0x428c */ { false, 0x428c, 0x428c }, +/* 0x428d */ { false, 0x428d, 0x428d }, +/* 0x428e */ { false, 0x428e, 0x428e }, +/* 0x428f */ { false, 0x428f, 0x428f }, +/* 0x4290 */ { false, 0x4290, 0x4290 }, +/* 0x4291 */ { false, 0x4291, 0x4291 }, +/* 0x4292 */ { false, 0x4292, 0x4292 }, +/* 0x4293 */ { false, 0x4293, 0x4293 }, +/* 0x4294 */ { false, 0x4294, 0x4294 }, +/* 0x4295 */ { false, 0x4295, 0x4295 }, +/* 0x4296 */ { false, 0x4296, 0x4296 }, +/* 0x4297 */ { false, 0x4297, 0x4297 }, +/* 0x4298 */ { false, 0x4298, 0x4298 }, +/* 0x4299 */ { false, 0x4299, 0x4299 }, +/* 0x429a */ { false, 0x429a, 0x429a }, +/* 0x429b */ { false, 0x429b, 0x429b }, +/* 0x429c */ { false, 0x429c, 0x429c }, +/* 0x429d */ { false, 0x429d, 0x429d }, +/* 0x429e */ { false, 0x429e, 0x429e }, +/* 0x429f */ { false, 0x429f, 0x429f }, +/* 0x42a0 */ { false, 0x42a0, 0x42a0 }, +/* 0x42a1 */ { false, 0x42a1, 0x42a1 }, +/* 0x42a2 */ { false, 0x42a2, 0x42a2 }, +/* 0x42a3 */ { false, 0x42a3, 0x42a3 }, +/* 0x42a4 */ { false, 0x42a4, 0x42a4 }, +/* 0x42a5 */ { false, 0x42a5, 0x42a5 }, +/* 0x42a6 */ { false, 0x42a6, 0x42a6 }, +/* 0x42a7 */ { false, 0x42a7, 0x42a7 }, +/* 0x42a8 */ { false, 0x42a8, 0x42a8 }, +/* 0x42a9 */ { false, 0x42a9, 0x42a9 }, +/* 0x42aa */ { false, 0x42aa, 0x42aa }, +/* 0x42ab */ { false, 0x42ab, 0x42ab }, +/* 0x42ac */ { false, 0x42ac, 0x42ac }, +/* 0x42ad */ { false, 0x42ad, 0x42ad }, +/* 0x42ae */ { false, 0x42ae, 0x42ae }, +/* 0x42af */ { false, 0x42af, 0x42af }, +/* 0x42b0 */ { false, 0x42b0, 0x42b0 }, +/* 0x42b1 */ { false, 0x42b1, 0x42b1 }, +/* 0x42b2 */ { false, 0x42b2, 0x42b2 }, +/* 0x42b3 */ { false, 0x42b3, 0x42b3 }, +/* 0x42b4 */ { false, 0x42b4, 0x42b4 }, +/* 0x42b5 */ { false, 0x42b5, 0x42b5 }, +/* 0x42b6 */ { false, 0x42b6, 0x42b6 }, +/* 0x42b7 */ { false, 0x42b7, 0x42b7 }, +/* 0x42b8 */ { false, 0x42b8, 0x42b8 }, +/* 0x42b9 */ { false, 0x42b9, 0x42b9 }, +/* 0x42ba */ { false, 0x42ba, 0x42ba }, +/* 0x42bb */ { false, 0x42bb, 0x42bb }, +/* 0x42bc */ { false, 0x42bc, 0x42bc }, +/* 0x42bd */ { false, 0x42bd, 0x42bd }, +/* 0x42be */ { false, 0x42be, 0x42be }, +/* 0x42bf */ { false, 0x42bf, 0x42bf }, +/* 0x42c0 */ { false, 0x42c0, 0x42c0 }, +/* 0x42c1 */ { false, 0x42c1, 0x42c1 }, +/* 0x42c2 */ { false, 0x42c2, 0x42c2 }, +/* 0x42c3 */ { false, 0x42c3, 0x42c3 }, +/* 0x42c4 */ { false, 0x42c4, 0x42c4 }, +/* 0x42c5 */ { false, 0x42c5, 0x42c5 }, +/* 0x42c6 */ { false, 0x42c6, 0x42c6 }, +/* 0x42c7 */ { false, 0x42c7, 0x42c7 }, +/* 0x42c8 */ { false, 0x42c8, 0x42c8 }, +/* 0x42c9 */ { false, 0x42c9, 0x42c9 }, +/* 0x42ca */ { false, 0x42ca, 0x42ca }, +/* 0x42cb */ { false, 0x42cb, 0x42cb }, +/* 0x42cc */ { false, 0x42cc, 0x42cc }, +/* 0x42cd */ { false, 0x42cd, 0x42cd }, +/* 0x42ce */ { false, 0x42ce, 0x42ce }, +/* 0x42cf */ { false, 0x42cf, 0x42cf }, +/* 0x42d0 */ { false, 0x42d0, 0x42d0 }, +/* 0x42d1 */ { false, 0x42d1, 0x42d1 }, +/* 0x42d2 */ { false, 0x42d2, 0x42d2 }, +/* 0x42d3 */ { false, 0x42d3, 0x42d3 }, +/* 0x42d4 */ { false, 0x42d4, 0x42d4 }, +/* 0x42d5 */ { false, 0x42d5, 0x42d5 }, +/* 0x42d6 */ { false, 0x42d6, 0x42d6 }, +/* 0x42d7 */ { false, 0x42d7, 0x42d7 }, +/* 0x42d8 */ { false, 0x42d8, 0x42d8 }, +/* 0x42d9 */ { false, 0x42d9, 0x42d9 }, +/* 0x42da */ { false, 0x42da, 0x42da }, +/* 0x42db */ { false, 0x42db, 0x42db }, +/* 0x42dc */ { false, 0x42dc, 0x42dc }, +/* 0x42dd */ { false, 0x42dd, 0x42dd }, +/* 0x42de */ { false, 0x42de, 0x42de }, +/* 0x42df */ { false, 0x42df, 0x42df }, +/* 0x42e0 */ { false, 0x42e0, 0x42e0 }, +/* 0x42e1 */ { false, 0x42e1, 0x42e1 }, +/* 0x42e2 */ { false, 0x42e2, 0x42e2 }, +/* 0x42e3 */ { false, 0x42e3, 0x42e3 }, +/* 0x42e4 */ { false, 0x42e4, 0x42e4 }, +/* 0x42e5 */ { false, 0x42e5, 0x42e5 }, +/* 0x42e6 */ { false, 0x42e6, 0x42e6 }, +/* 0x42e7 */ { false, 0x42e7, 0x42e7 }, +/* 0x42e8 */ { false, 0x42e8, 0x42e8 }, +/* 0x42e9 */ { false, 0x42e9, 0x42e9 }, +/* 0x42ea */ { false, 0x42ea, 0x42ea }, +/* 0x42eb */ { false, 0x42eb, 0x42eb }, +/* 0x42ec */ { false, 0x42ec, 0x42ec }, +/* 0x42ed */ { false, 0x42ed, 0x42ed }, +/* 0x42ee */ { false, 0x42ee, 0x42ee }, +/* 0x42ef */ { false, 0x42ef, 0x42ef }, +/* 0x42f0 */ { false, 0x42f0, 0x42f0 }, +/* 0x42f1 */ { false, 0x42f1, 0x42f1 }, +/* 0x42f2 */ { false, 0x42f2, 0x42f2 }, +/* 0x42f3 */ { false, 0x42f3, 0x42f3 }, +/* 0x42f4 */ { false, 0x42f4, 0x42f4 }, +/* 0x42f5 */ { false, 0x42f5, 0x42f5 }, +/* 0x42f6 */ { false, 0x42f6, 0x42f6 }, +/* 0x42f7 */ { false, 0x42f7, 0x42f7 }, +/* 0x42f8 */ { false, 0x42f8, 0x42f8 }, +/* 0x42f9 */ { false, 0x42f9, 0x42f9 }, +/* 0x42fa */ { false, 0x42fa, 0x42fa }, +/* 0x42fb */ { false, 0x42fb, 0x42fb }, +/* 0x42fc */ { false, 0x42fc, 0x42fc }, +/* 0x42fd */ { false, 0x42fd, 0x42fd }, +/* 0x42fe */ { false, 0x42fe, 0x42fe }, +/* 0x42ff */ { false, 0x42ff, 0x42ff }, +/* 0x4300 */ { false, 0x4300, 0x4300 }, +/* 0x4301 */ { false, 0x4301, 0x4301 }, +/* 0x4302 */ { false, 0x4302, 0x4302 }, +/* 0x4303 */ { false, 0x4303, 0x4303 }, +/* 0x4304 */ { false, 0x4304, 0x4304 }, +/* 0x4305 */ { false, 0x4305, 0x4305 }, +/* 0x4306 */ { false, 0x4306, 0x4306 }, +/* 0x4307 */ { false, 0x4307, 0x4307 }, +/* 0x4308 */ { false, 0x4308, 0x4308 }, +/* 0x4309 */ { false, 0x4309, 0x4309 }, +/* 0x430a */ { false, 0x430a, 0x430a }, +/* 0x430b */ { false, 0x430b, 0x430b }, +/* 0x430c */ { false, 0x430c, 0x430c }, +/* 0x430d */ { false, 0x430d, 0x430d }, +/* 0x430e */ { false, 0x430e, 0x430e }, +/* 0x430f */ { false, 0x430f, 0x430f }, +/* 0x4310 */ { false, 0x4310, 0x4310 }, +/* 0x4311 */ { false, 0x4311, 0x4311 }, +/* 0x4312 */ { false, 0x4312, 0x4312 }, +/* 0x4313 */ { false, 0x4313, 0x4313 }, +/* 0x4314 */ { false, 0x4314, 0x4314 }, +/* 0x4315 */ { false, 0x4315, 0x4315 }, +/* 0x4316 */ { false, 0x4316, 0x4316 }, +/* 0x4317 */ { false, 0x4317, 0x4317 }, +/* 0x4318 */ { false, 0x4318, 0x4318 }, +/* 0x4319 */ { false, 0x4319, 0x4319 }, +/* 0x431a */ { false, 0x431a, 0x431a }, +/* 0x431b */ { false, 0x431b, 0x431b }, +/* 0x431c */ { false, 0x431c, 0x431c }, +/* 0x431d */ { false, 0x431d, 0x431d }, +/* 0x431e */ { false, 0x431e, 0x431e }, +/* 0x431f */ { false, 0x431f, 0x431f }, +/* 0x4320 */ { false, 0x4320, 0x4320 }, +/* 0x4321 */ { false, 0x4321, 0x4321 }, +/* 0x4322 */ { false, 0x4322, 0x4322 }, +/* 0x4323 */ { false, 0x4323, 0x4323 }, +/* 0x4324 */ { false, 0x4324, 0x4324 }, +/* 0x4325 */ { false, 0x4325, 0x4325 }, +/* 0x4326 */ { false, 0x4326, 0x4326 }, +/* 0x4327 */ { false, 0x4327, 0x4327 }, +/* 0x4328 */ { false, 0x4328, 0x4328 }, +/* 0x4329 */ { false, 0x4329, 0x4329 }, +/* 0x432a */ { false, 0x432a, 0x432a }, +/* 0x432b */ { false, 0x432b, 0x432b }, +/* 0x432c */ { false, 0x432c, 0x432c }, +/* 0x432d */ { false, 0x432d, 0x432d }, +/* 0x432e */ { false, 0x432e, 0x432e }, +/* 0x432f */ { false, 0x432f, 0x432f }, +/* 0x4330 */ { false, 0x4330, 0x4330 }, +/* 0x4331 */ { false, 0x4331, 0x4331 }, +/* 0x4332 */ { false, 0x4332, 0x4332 }, +/* 0x4333 */ { false, 0x4333, 0x4333 }, +/* 0x4334 */ { false, 0x4334, 0x4334 }, +/* 0x4335 */ { false, 0x4335, 0x4335 }, +/* 0x4336 */ { false, 0x4336, 0x4336 }, +/* 0x4337 */ { false, 0x4337, 0x4337 }, +/* 0x4338 */ { false, 0x4338, 0x4338 }, +/* 0x4339 */ { false, 0x4339, 0x4339 }, +/* 0x433a */ { false, 0x433a, 0x433a }, +/* 0x433b */ { false, 0x433b, 0x433b }, +/* 0x433c */ { false, 0x433c, 0x433c }, +/* 0x433d */ { false, 0x433d, 0x433d }, +/* 0x433e */ { false, 0x433e, 0x433e }, +/* 0x433f */ { false, 0x433f, 0x433f }, +/* 0x4340 */ { false, 0x4340, 0x4340 }, +/* 0x4341 */ { false, 0x4341, 0x4341 }, +/* 0x4342 */ { false, 0x4342, 0x4342 }, +/* 0x4343 */ { false, 0x4343, 0x4343 }, +/* 0x4344 */ { false, 0x4344, 0x4344 }, +/* 0x4345 */ { false, 0x4345, 0x4345 }, +/* 0x4346 */ { false, 0x4346, 0x4346 }, +/* 0x4347 */ { false, 0x4347, 0x4347 }, +/* 0x4348 */ { false, 0x4348, 0x4348 }, +/* 0x4349 */ { false, 0x4349, 0x4349 }, +/* 0x434a */ { false, 0x434a, 0x434a }, +/* 0x434b */ { false, 0x434b, 0x434b }, +/* 0x434c */ { false, 0x434c, 0x434c }, +/* 0x434d */ { false, 0x434d, 0x434d }, +/* 0x434e */ { false, 0x434e, 0x434e }, +/* 0x434f */ { false, 0x434f, 0x434f }, +/* 0x4350 */ { false, 0x4350, 0x4350 }, +/* 0x4351 */ { false, 0x4351, 0x4351 }, +/* 0x4352 */ { false, 0x4352, 0x4352 }, +/* 0x4353 */ { false, 0x4353, 0x4353 }, +/* 0x4354 */ { false, 0x4354, 0x4354 }, +/* 0x4355 */ { false, 0x4355, 0x4355 }, +/* 0x4356 */ { false, 0x4356, 0x4356 }, +/* 0x4357 */ { false, 0x4357, 0x4357 }, +/* 0x4358 */ { false, 0x4358, 0x4358 }, +/* 0x4359 */ { false, 0x4359, 0x4359 }, +/* 0x435a */ { false, 0x435a, 0x435a }, +/* 0x435b */ { false, 0x435b, 0x435b }, +/* 0x435c */ { false, 0x435c, 0x435c }, +/* 0x435d */ { false, 0x435d, 0x435d }, +/* 0x435e */ { false, 0x435e, 0x435e }, +/* 0x435f */ { false, 0x435f, 0x435f }, +/* 0x4360 */ { false, 0x4360, 0x4360 }, +/* 0x4361 */ { false, 0x4361, 0x4361 }, +/* 0x4362 */ { false, 0x4362, 0x4362 }, +/* 0x4363 */ { false, 0x4363, 0x4363 }, +/* 0x4364 */ { false, 0x4364, 0x4364 }, +/* 0x4365 */ { false, 0x4365, 0x4365 }, +/* 0x4366 */ { false, 0x4366, 0x4366 }, +/* 0x4367 */ { false, 0x4367, 0x4367 }, +/* 0x4368 */ { false, 0x4368, 0x4368 }, +/* 0x4369 */ { false, 0x4369, 0x4369 }, +/* 0x436a */ { false, 0x436a, 0x436a }, +/* 0x436b */ { false, 0x436b, 0x436b }, +/* 0x436c */ { false, 0x436c, 0x436c }, +/* 0x436d */ { false, 0x436d, 0x436d }, +/* 0x436e */ { false, 0x436e, 0x436e }, +/* 0x436f */ { false, 0x436f, 0x436f }, +/* 0x4370 */ { false, 0x4370, 0x4370 }, +/* 0x4371 */ { false, 0x4371, 0x4371 }, +/* 0x4372 */ { false, 0x4372, 0x4372 }, +/* 0x4373 */ { false, 0x4373, 0x4373 }, +/* 0x4374 */ { false, 0x4374, 0x4374 }, +/* 0x4375 */ { false, 0x4375, 0x4375 }, +/* 0x4376 */ { false, 0x4376, 0x4376 }, +/* 0x4377 */ { false, 0x4377, 0x4377 }, +/* 0x4378 */ { false, 0x4378, 0x4378 }, +/* 0x4379 */ { false, 0x4379, 0x4379 }, +/* 0x437a */ { false, 0x437a, 0x437a }, +/* 0x437b */ { false, 0x437b, 0x437b }, +/* 0x437c */ { false, 0x437c, 0x437c }, +/* 0x437d */ { false, 0x437d, 0x437d }, +/* 0x437e */ { false, 0x437e, 0x437e }, +/* 0x437f */ { false, 0x437f, 0x437f }, +/* 0x4380 */ { false, 0x4380, 0x4380 }, +/* 0x4381 */ { false, 0x4381, 0x4381 }, +/* 0x4382 */ { false, 0x4382, 0x4382 }, +/* 0x4383 */ { false, 0x4383, 0x4383 }, +/* 0x4384 */ { false, 0x4384, 0x4384 }, +/* 0x4385 */ { false, 0x4385, 0x4385 }, +/* 0x4386 */ { false, 0x4386, 0x4386 }, +/* 0x4387 */ { false, 0x4387, 0x4387 }, +/* 0x4388 */ { false, 0x4388, 0x4388 }, +/* 0x4389 */ { false, 0x4389, 0x4389 }, +/* 0x438a */ { false, 0x438a, 0x438a }, +/* 0x438b */ { false, 0x438b, 0x438b }, +/* 0x438c */ { false, 0x438c, 0x438c }, +/* 0x438d */ { false, 0x438d, 0x438d }, +/* 0x438e */ { false, 0x438e, 0x438e }, +/* 0x438f */ { false, 0x438f, 0x438f }, +/* 0x4390 */ { false, 0x4390, 0x4390 }, +/* 0x4391 */ { false, 0x4391, 0x4391 }, +/* 0x4392 */ { false, 0x4392, 0x4392 }, +/* 0x4393 */ { false, 0x4393, 0x4393 }, +/* 0x4394 */ { false, 0x4394, 0x4394 }, +/* 0x4395 */ { false, 0x4395, 0x4395 }, +/* 0x4396 */ { false, 0x4396, 0x4396 }, +/* 0x4397 */ { false, 0x4397, 0x4397 }, +/* 0x4398 */ { false, 0x4398, 0x4398 }, +/* 0x4399 */ { false, 0x4399, 0x4399 }, +/* 0x439a */ { false, 0x439a, 0x439a }, +/* 0x439b */ { false, 0x439b, 0x439b }, +/* 0x439c */ { false, 0x439c, 0x439c }, +/* 0x439d */ { false, 0x439d, 0x439d }, +/* 0x439e */ { false, 0x439e, 0x439e }, +/* 0x439f */ { false, 0x439f, 0x439f }, +/* 0x43a0 */ { false, 0x43a0, 0x43a0 }, +/* 0x43a1 */ { false, 0x43a1, 0x43a1 }, +/* 0x43a2 */ { false, 0x43a2, 0x43a2 }, +/* 0x43a3 */ { false, 0x43a3, 0x43a3 }, +/* 0x43a4 */ { false, 0x43a4, 0x43a4 }, +/* 0x43a5 */ { false, 0x43a5, 0x43a5 }, +/* 0x43a6 */ { false, 0x43a6, 0x43a6 }, +/* 0x43a7 */ { false, 0x43a7, 0x43a7 }, +/* 0x43a8 */ { false, 0x43a8, 0x43a8 }, +/* 0x43a9 */ { false, 0x43a9, 0x43a9 }, +/* 0x43aa */ { false, 0x43aa, 0x43aa }, +/* 0x43ab */ { false, 0x43ab, 0x43ab }, +/* 0x43ac */ { false, 0x43ac, 0x43ac }, +/* 0x43ad */ { false, 0x43ad, 0x43ad }, +/* 0x43ae */ { false, 0x43ae, 0x43ae }, +/* 0x43af */ { false, 0x43af, 0x43af }, +/* 0x43b0 */ { false, 0x43b0, 0x43b0 }, +/* 0x43b1 */ { false, 0x43b1, 0x43b1 }, +/* 0x43b2 */ { false, 0x43b2, 0x43b2 }, +/* 0x43b3 */ { false, 0x43b3, 0x43b3 }, +/* 0x43b4 */ { false, 0x43b4, 0x43b4 }, +/* 0x43b5 */ { false, 0x43b5, 0x43b5 }, +/* 0x43b6 */ { false, 0x43b6, 0x43b6 }, +/* 0x43b7 */ { false, 0x43b7, 0x43b7 }, +/* 0x43b8 */ { false, 0x43b8, 0x43b8 }, +/* 0x43b9 */ { false, 0x43b9, 0x43b9 }, +/* 0x43ba */ { false, 0x43ba, 0x43ba }, +/* 0x43bb */ { false, 0x43bb, 0x43bb }, +/* 0x43bc */ { false, 0x43bc, 0x43bc }, +/* 0x43bd */ { false, 0x43bd, 0x43bd }, +/* 0x43be */ { false, 0x43be, 0x43be }, +/* 0x43bf */ { false, 0x43bf, 0x43bf }, +/* 0x43c0 */ { false, 0x43c0, 0x43c0 }, +/* 0x43c1 */ { false, 0x43c1, 0x43c1 }, +/* 0x43c2 */ { false, 0x43c2, 0x43c2 }, +/* 0x43c3 */ { false, 0x43c3, 0x43c3 }, +/* 0x43c4 */ { false, 0x43c4, 0x43c4 }, +/* 0x43c5 */ { false, 0x43c5, 0x43c5 }, +/* 0x43c6 */ { false, 0x43c6, 0x43c6 }, +/* 0x43c7 */ { false, 0x43c7, 0x43c7 }, +/* 0x43c8 */ { false, 0x43c8, 0x43c8 }, +/* 0x43c9 */ { false, 0x43c9, 0x43c9 }, +/* 0x43ca */ { false, 0x43ca, 0x43ca }, +/* 0x43cb */ { false, 0x43cb, 0x43cb }, +/* 0x43cc */ { false, 0x43cc, 0x43cc }, +/* 0x43cd */ { false, 0x43cd, 0x43cd }, +/* 0x43ce */ { false, 0x43ce, 0x43ce }, +/* 0x43cf */ { false, 0x43cf, 0x43cf }, +/* 0x43d0 */ { false, 0x43d0, 0x43d0 }, +/* 0x43d1 */ { false, 0x43d1, 0x43d1 }, +/* 0x43d2 */ { false, 0x43d2, 0x43d2 }, +/* 0x43d3 */ { false, 0x43d3, 0x43d3 }, +/* 0x43d4 */ { false, 0x43d4, 0x43d4 }, +/* 0x43d5 */ { false, 0x43d5, 0x43d5 }, +/* 0x43d6 */ { false, 0x43d6, 0x43d6 }, +/* 0x43d7 */ { false, 0x43d7, 0x43d7 }, +/* 0x43d8 */ { false, 0x43d8, 0x43d8 }, +/* 0x43d9 */ { false, 0x43d9, 0x43d9 }, +/* 0x43da */ { false, 0x43da, 0x43da }, +/* 0x43db */ { false, 0x43db, 0x43db }, +/* 0x43dc */ { false, 0x43dc, 0x43dc }, +/* 0x43dd */ { false, 0x43dd, 0x43dd }, +/* 0x43de */ { false, 0x43de, 0x43de }, +/* 0x43df */ { false, 0x43df, 0x43df }, +/* 0x43e0 */ { false, 0x43e0, 0x43e0 }, +/* 0x43e1 */ { false, 0x43e1, 0x43e1 }, +/* 0x43e2 */ { false, 0x43e2, 0x43e2 }, +/* 0x43e3 */ { false, 0x43e3, 0x43e3 }, +/* 0x43e4 */ { false, 0x43e4, 0x43e4 }, +/* 0x43e5 */ { false, 0x43e5, 0x43e5 }, +/* 0x43e6 */ { false, 0x43e6, 0x43e6 }, +/* 0x43e7 */ { false, 0x43e7, 0x43e7 }, +/* 0x43e8 */ { false, 0x43e8, 0x43e8 }, +/* 0x43e9 */ { false, 0x43e9, 0x43e9 }, +/* 0x43ea */ { false, 0x43ea, 0x43ea }, +/* 0x43eb */ { false, 0x43eb, 0x43eb }, +/* 0x43ec */ { false, 0x43ec, 0x43ec }, +/* 0x43ed */ { false, 0x43ed, 0x43ed }, +/* 0x43ee */ { false, 0x43ee, 0x43ee }, +/* 0x43ef */ { false, 0x43ef, 0x43ef }, +/* 0x43f0 */ { false, 0x43f0, 0x43f0 }, +/* 0x43f1 */ { false, 0x43f1, 0x43f1 }, +/* 0x43f2 */ { false, 0x43f2, 0x43f2 }, +/* 0x43f3 */ { false, 0x43f3, 0x43f3 }, +/* 0x43f4 */ { false, 0x43f4, 0x43f4 }, +/* 0x43f5 */ { false, 0x43f5, 0x43f5 }, +/* 0x43f6 */ { false, 0x43f6, 0x43f6 }, +/* 0x43f7 */ { false, 0x43f7, 0x43f7 }, +/* 0x43f8 */ { false, 0x43f8, 0x43f8 }, +/* 0x43f9 */ { false, 0x43f9, 0x43f9 }, +/* 0x43fa */ { false, 0x43fa, 0x43fa }, +/* 0x43fb */ { false, 0x43fb, 0x43fb }, +/* 0x43fc */ { false, 0x43fc, 0x43fc }, +/* 0x43fd */ { false, 0x43fd, 0x43fd }, +/* 0x43fe */ { false, 0x43fe, 0x43fe }, +/* 0x43ff */ { false, 0x43ff, 0x43ff }, +/* 0x4400 */ { false, 0x4400, 0x4400 }, +/* 0x4401 */ { false, 0x4401, 0x4401 }, +/* 0x4402 */ { false, 0x4402, 0x4402 }, +/* 0x4403 */ { false, 0x4403, 0x4403 }, +/* 0x4404 */ { false, 0x4404, 0x4404 }, +/* 0x4405 */ { false, 0x4405, 0x4405 }, +/* 0x4406 */ { false, 0x4406, 0x4406 }, +/* 0x4407 */ { false, 0x4407, 0x4407 }, +/* 0x4408 */ { false, 0x4408, 0x4408 }, +/* 0x4409 */ { false, 0x4409, 0x4409 }, +/* 0x440a */ { false, 0x440a, 0x440a }, +/* 0x440b */ { false, 0x440b, 0x440b }, +/* 0x440c */ { false, 0x440c, 0x440c }, +/* 0x440d */ { false, 0x440d, 0x440d }, +/* 0x440e */ { false, 0x440e, 0x440e }, +/* 0x440f */ { false, 0x440f, 0x440f }, +/* 0x4410 */ { false, 0x4410, 0x4410 }, +/* 0x4411 */ { false, 0x4411, 0x4411 }, +/* 0x4412 */ { false, 0x4412, 0x4412 }, +/* 0x4413 */ { false, 0x4413, 0x4413 }, +/* 0x4414 */ { false, 0x4414, 0x4414 }, +/* 0x4415 */ { false, 0x4415, 0x4415 }, +/* 0x4416 */ { false, 0x4416, 0x4416 }, +/* 0x4417 */ { false, 0x4417, 0x4417 }, +/* 0x4418 */ { false, 0x4418, 0x4418 }, +/* 0x4419 */ { false, 0x4419, 0x4419 }, +/* 0x441a */ { false, 0x441a, 0x441a }, +/* 0x441b */ { false, 0x441b, 0x441b }, +/* 0x441c */ { false, 0x441c, 0x441c }, +/* 0x441d */ { false, 0x441d, 0x441d }, +/* 0x441e */ { false, 0x441e, 0x441e }, +/* 0x441f */ { false, 0x441f, 0x441f }, +/* 0x4420 */ { false, 0x4420, 0x4420 }, +/* 0x4421 */ { false, 0x4421, 0x4421 }, +/* 0x4422 */ { false, 0x4422, 0x4422 }, +/* 0x4423 */ { false, 0x4423, 0x4423 }, +/* 0x4424 */ { false, 0x4424, 0x4424 }, +/* 0x4425 */ { false, 0x4425, 0x4425 }, +/* 0x4426 */ { false, 0x4426, 0x4426 }, +/* 0x4427 */ { false, 0x4427, 0x4427 }, +/* 0x4428 */ { false, 0x4428, 0x4428 }, +/* 0x4429 */ { false, 0x4429, 0x4429 }, +/* 0x442a */ { false, 0x442a, 0x442a }, +/* 0x442b */ { false, 0x442b, 0x442b }, +/* 0x442c */ { false, 0x442c, 0x442c }, +/* 0x442d */ { false, 0x442d, 0x442d }, +/* 0x442e */ { false, 0x442e, 0x442e }, +/* 0x442f */ { false, 0x442f, 0x442f }, +/* 0x4430 */ { false, 0x4430, 0x4430 }, +/* 0x4431 */ { false, 0x4431, 0x4431 }, +/* 0x4432 */ { false, 0x4432, 0x4432 }, +/* 0x4433 */ { false, 0x4433, 0x4433 }, +/* 0x4434 */ { false, 0x4434, 0x4434 }, +/* 0x4435 */ { false, 0x4435, 0x4435 }, +/* 0x4436 */ { false, 0x4436, 0x4436 }, +/* 0x4437 */ { false, 0x4437, 0x4437 }, +/* 0x4438 */ { false, 0x4438, 0x4438 }, +/* 0x4439 */ { false, 0x4439, 0x4439 }, +/* 0x443a */ { false, 0x443a, 0x443a }, +/* 0x443b */ { false, 0x443b, 0x443b }, +/* 0x443c */ { false, 0x443c, 0x443c }, +/* 0x443d */ { false, 0x443d, 0x443d }, +/* 0x443e */ { false, 0x443e, 0x443e }, +/* 0x443f */ { false, 0x443f, 0x443f }, +/* 0x4440 */ { false, 0x4440, 0x4440 }, +/* 0x4441 */ { false, 0x4441, 0x4441 }, +/* 0x4442 */ { false, 0x4442, 0x4442 }, +/* 0x4443 */ { false, 0x4443, 0x4443 }, +/* 0x4444 */ { false, 0x4444, 0x4444 }, +/* 0x4445 */ { false, 0x4445, 0x4445 }, +/* 0x4446 */ { false, 0x4446, 0x4446 }, +/* 0x4447 */ { false, 0x4447, 0x4447 }, +/* 0x4448 */ { false, 0x4448, 0x4448 }, +/* 0x4449 */ { false, 0x4449, 0x4449 }, +/* 0x444a */ { false, 0x444a, 0x444a }, +/* 0x444b */ { false, 0x444b, 0x444b }, +/* 0x444c */ { false, 0x444c, 0x444c }, +/* 0x444d */ { false, 0x444d, 0x444d }, +/* 0x444e */ { false, 0x444e, 0x444e }, +/* 0x444f */ { false, 0x444f, 0x444f }, +/* 0x4450 */ { false, 0x4450, 0x4450 }, +/* 0x4451 */ { false, 0x4451, 0x4451 }, +/* 0x4452 */ { false, 0x4452, 0x4452 }, +/* 0x4453 */ { false, 0x4453, 0x4453 }, +/* 0x4454 */ { false, 0x4454, 0x4454 }, +/* 0x4455 */ { false, 0x4455, 0x4455 }, +/* 0x4456 */ { false, 0x4456, 0x4456 }, +/* 0x4457 */ { false, 0x4457, 0x4457 }, +/* 0x4458 */ { false, 0x4458, 0x4458 }, +/* 0x4459 */ { false, 0x4459, 0x4459 }, +/* 0x445a */ { false, 0x445a, 0x445a }, +/* 0x445b */ { false, 0x445b, 0x445b }, +/* 0x445c */ { false, 0x445c, 0x445c }, +/* 0x445d */ { false, 0x445d, 0x445d }, +/* 0x445e */ { false, 0x445e, 0x445e }, +/* 0x445f */ { false, 0x445f, 0x445f }, +/* 0x4460 */ { false, 0x4460, 0x4460 }, +/* 0x4461 */ { false, 0x4461, 0x4461 }, +/* 0x4462 */ { false, 0x4462, 0x4462 }, +/* 0x4463 */ { false, 0x4463, 0x4463 }, +/* 0x4464 */ { false, 0x4464, 0x4464 }, +/* 0x4465 */ { false, 0x4465, 0x4465 }, +/* 0x4466 */ { false, 0x4466, 0x4466 }, +/* 0x4467 */ { false, 0x4467, 0x4467 }, +/* 0x4468 */ { false, 0x4468, 0x4468 }, +/* 0x4469 */ { false, 0x4469, 0x4469 }, +/* 0x446a */ { false, 0x446a, 0x446a }, +/* 0x446b */ { false, 0x446b, 0x446b }, +/* 0x446c */ { false, 0x446c, 0x446c }, +/* 0x446d */ { false, 0x446d, 0x446d }, +/* 0x446e */ { false, 0x446e, 0x446e }, +/* 0x446f */ { false, 0x446f, 0x446f }, +/* 0x4470 */ { false, 0x4470, 0x4470 }, +/* 0x4471 */ { false, 0x4471, 0x4471 }, +/* 0x4472 */ { false, 0x4472, 0x4472 }, +/* 0x4473 */ { false, 0x4473, 0x4473 }, +/* 0x4474 */ { false, 0x4474, 0x4474 }, +/* 0x4475 */ { false, 0x4475, 0x4475 }, +/* 0x4476 */ { false, 0x4476, 0x4476 }, +/* 0x4477 */ { false, 0x4477, 0x4477 }, +/* 0x4478 */ { false, 0x4478, 0x4478 }, +/* 0x4479 */ { false, 0x4479, 0x4479 }, +/* 0x447a */ { false, 0x447a, 0x447a }, +/* 0x447b */ { false, 0x447b, 0x447b }, +/* 0x447c */ { false, 0x447c, 0x447c }, +/* 0x447d */ { false, 0x447d, 0x447d }, +/* 0x447e */ { false, 0x447e, 0x447e }, +/* 0x447f */ { false, 0x447f, 0x447f }, +/* 0x4480 */ { false, 0x4480, 0x4480 }, +/* 0x4481 */ { false, 0x4481, 0x4481 }, +/* 0x4482 */ { false, 0x4482, 0x4482 }, +/* 0x4483 */ { false, 0x4483, 0x4483 }, +/* 0x4484 */ { false, 0x4484, 0x4484 }, +/* 0x4485 */ { false, 0x4485, 0x4485 }, +/* 0x4486 */ { false, 0x4486, 0x4486 }, +/* 0x4487 */ { false, 0x4487, 0x4487 }, +/* 0x4488 */ { false, 0x4488, 0x4488 }, +/* 0x4489 */ { false, 0x4489, 0x4489 }, +/* 0x448a */ { false, 0x448a, 0x448a }, +/* 0x448b */ { false, 0x448b, 0x448b }, +/* 0x448c */ { false, 0x448c, 0x448c }, +/* 0x448d */ { false, 0x448d, 0x448d }, +/* 0x448e */ { false, 0x448e, 0x448e }, +/* 0x448f */ { false, 0x448f, 0x448f }, +/* 0x4490 */ { false, 0x4490, 0x4490 }, +/* 0x4491 */ { false, 0x4491, 0x4491 }, +/* 0x4492 */ { false, 0x4492, 0x4492 }, +/* 0x4493 */ { false, 0x4493, 0x4493 }, +/* 0x4494 */ { false, 0x4494, 0x4494 }, +/* 0x4495 */ { false, 0x4495, 0x4495 }, +/* 0x4496 */ { false, 0x4496, 0x4496 }, +/* 0x4497 */ { false, 0x4497, 0x4497 }, +/* 0x4498 */ { false, 0x4498, 0x4498 }, +/* 0x4499 */ { false, 0x4499, 0x4499 }, +/* 0x449a */ { false, 0x449a, 0x449a }, +/* 0x449b */ { false, 0x449b, 0x449b }, +/* 0x449c */ { false, 0x449c, 0x449c }, +/* 0x449d */ { false, 0x449d, 0x449d }, +/* 0x449e */ { false, 0x449e, 0x449e }, +/* 0x449f */ { false, 0x449f, 0x449f }, +/* 0x44a0 */ { false, 0x44a0, 0x44a0 }, +/* 0x44a1 */ { false, 0x44a1, 0x44a1 }, +/* 0x44a2 */ { false, 0x44a2, 0x44a2 }, +/* 0x44a3 */ { false, 0x44a3, 0x44a3 }, +/* 0x44a4 */ { false, 0x44a4, 0x44a4 }, +/* 0x44a5 */ { false, 0x44a5, 0x44a5 }, +/* 0x44a6 */ { false, 0x44a6, 0x44a6 }, +/* 0x44a7 */ { false, 0x44a7, 0x44a7 }, +/* 0x44a8 */ { false, 0x44a8, 0x44a8 }, +/* 0x44a9 */ { false, 0x44a9, 0x44a9 }, +/* 0x44aa */ { false, 0x44aa, 0x44aa }, +/* 0x44ab */ { false, 0x44ab, 0x44ab }, +/* 0x44ac */ { false, 0x44ac, 0x44ac }, +/* 0x44ad */ { false, 0x44ad, 0x44ad }, +/* 0x44ae */ { false, 0x44ae, 0x44ae }, +/* 0x44af */ { false, 0x44af, 0x44af }, +/* 0x44b0 */ { false, 0x44b0, 0x44b0 }, +/* 0x44b1 */ { false, 0x44b1, 0x44b1 }, +/* 0x44b2 */ { false, 0x44b2, 0x44b2 }, +/* 0x44b3 */ { false, 0x44b3, 0x44b3 }, +/* 0x44b4 */ { false, 0x44b4, 0x44b4 }, +/* 0x44b5 */ { false, 0x44b5, 0x44b5 }, +/* 0x44b6 */ { false, 0x44b6, 0x44b6 }, +/* 0x44b7 */ { false, 0x44b7, 0x44b7 }, +/* 0x44b8 */ { false, 0x44b8, 0x44b8 }, +/* 0x44b9 */ { false, 0x44b9, 0x44b9 }, +/* 0x44ba */ { false, 0x44ba, 0x44ba }, +/* 0x44bb */ { false, 0x44bb, 0x44bb }, +/* 0x44bc */ { false, 0x44bc, 0x44bc }, +/* 0x44bd */ { false, 0x44bd, 0x44bd }, +/* 0x44be */ { false, 0x44be, 0x44be }, +/* 0x44bf */ { false, 0x44bf, 0x44bf }, +/* 0x44c0 */ { false, 0x44c0, 0x44c0 }, +/* 0x44c1 */ { false, 0x44c1, 0x44c1 }, +/* 0x44c2 */ { false, 0x44c2, 0x44c2 }, +/* 0x44c3 */ { false, 0x44c3, 0x44c3 }, +/* 0x44c4 */ { false, 0x44c4, 0x44c4 }, +/* 0x44c5 */ { false, 0x44c5, 0x44c5 }, +/* 0x44c6 */ { false, 0x44c6, 0x44c6 }, +/* 0x44c7 */ { false, 0x44c7, 0x44c7 }, +/* 0x44c8 */ { false, 0x44c8, 0x44c8 }, +/* 0x44c9 */ { false, 0x44c9, 0x44c9 }, +/* 0x44ca */ { false, 0x44ca, 0x44ca }, +/* 0x44cb */ { false, 0x44cb, 0x44cb }, +/* 0x44cc */ { false, 0x44cc, 0x44cc }, +/* 0x44cd */ { false, 0x44cd, 0x44cd }, +/* 0x44ce */ { false, 0x44ce, 0x44ce }, +/* 0x44cf */ { false, 0x44cf, 0x44cf }, +/* 0x44d0 */ { false, 0x44d0, 0x44d0 }, +/* 0x44d1 */ { false, 0x44d1, 0x44d1 }, +/* 0x44d2 */ { false, 0x44d2, 0x44d2 }, +/* 0x44d3 */ { false, 0x44d3, 0x44d3 }, +/* 0x44d4 */ { false, 0x44d4, 0x44d4 }, +/* 0x44d5 */ { false, 0x44d5, 0x44d5 }, +/* 0x44d6 */ { false, 0x44d6, 0x44d6 }, +/* 0x44d7 */ { false, 0x44d7, 0x44d7 }, +/* 0x44d8 */ { false, 0x44d8, 0x44d8 }, +/* 0x44d9 */ { false, 0x44d9, 0x44d9 }, +/* 0x44da */ { false, 0x44da, 0x44da }, +/* 0x44db */ { false, 0x44db, 0x44db }, +/* 0x44dc */ { false, 0x44dc, 0x44dc }, +/* 0x44dd */ { false, 0x44dd, 0x44dd }, +/* 0x44de */ { false, 0x44de, 0x44de }, +/* 0x44df */ { false, 0x44df, 0x44df }, +/* 0x44e0 */ { false, 0x44e0, 0x44e0 }, +/* 0x44e1 */ { false, 0x44e1, 0x44e1 }, +/* 0x44e2 */ { false, 0x44e2, 0x44e2 }, +/* 0x44e3 */ { false, 0x44e3, 0x44e3 }, +/* 0x44e4 */ { false, 0x44e4, 0x44e4 }, +/* 0x44e5 */ { false, 0x44e5, 0x44e5 }, +/* 0x44e6 */ { false, 0x44e6, 0x44e6 }, +/* 0x44e7 */ { false, 0x44e7, 0x44e7 }, +/* 0x44e8 */ { false, 0x44e8, 0x44e8 }, +/* 0x44e9 */ { false, 0x44e9, 0x44e9 }, +/* 0x44ea */ { false, 0x44ea, 0x44ea }, +/* 0x44eb */ { false, 0x44eb, 0x44eb }, +/* 0x44ec */ { false, 0x44ec, 0x44ec }, +/* 0x44ed */ { false, 0x44ed, 0x44ed }, +/* 0x44ee */ { false, 0x44ee, 0x44ee }, +/* 0x44ef */ { false, 0x44ef, 0x44ef }, +/* 0x44f0 */ { false, 0x44f0, 0x44f0 }, +/* 0x44f1 */ { false, 0x44f1, 0x44f1 }, +/* 0x44f2 */ { false, 0x44f2, 0x44f2 }, +/* 0x44f3 */ { false, 0x44f3, 0x44f3 }, +/* 0x44f4 */ { false, 0x44f4, 0x44f4 }, +/* 0x44f5 */ { false, 0x44f5, 0x44f5 }, +/* 0x44f6 */ { false, 0x44f6, 0x44f6 }, +/* 0x44f7 */ { false, 0x44f7, 0x44f7 }, +/* 0x44f8 */ { false, 0x44f8, 0x44f8 }, +/* 0x44f9 */ { false, 0x44f9, 0x44f9 }, +/* 0x44fa */ { false, 0x44fa, 0x44fa }, +/* 0x44fb */ { false, 0x44fb, 0x44fb }, +/* 0x44fc */ { false, 0x44fc, 0x44fc }, +/* 0x44fd */ { false, 0x44fd, 0x44fd }, +/* 0x44fe */ { false, 0x44fe, 0x44fe }, +/* 0x44ff */ { false, 0x44ff, 0x44ff }, +/* 0x4500 */ { false, 0x4500, 0x4500 }, +/* 0x4501 */ { false, 0x4501, 0x4501 }, +/* 0x4502 */ { false, 0x4502, 0x4502 }, +/* 0x4503 */ { false, 0x4503, 0x4503 }, +/* 0x4504 */ { false, 0x4504, 0x4504 }, +/* 0x4505 */ { false, 0x4505, 0x4505 }, +/* 0x4506 */ { false, 0x4506, 0x4506 }, +/* 0x4507 */ { false, 0x4507, 0x4507 }, +/* 0x4508 */ { false, 0x4508, 0x4508 }, +/* 0x4509 */ { false, 0x4509, 0x4509 }, +/* 0x450a */ { false, 0x450a, 0x450a }, +/* 0x450b */ { false, 0x450b, 0x450b }, +/* 0x450c */ { false, 0x450c, 0x450c }, +/* 0x450d */ { false, 0x450d, 0x450d }, +/* 0x450e */ { false, 0x450e, 0x450e }, +/* 0x450f */ { false, 0x450f, 0x450f }, +/* 0x4510 */ { false, 0x4510, 0x4510 }, +/* 0x4511 */ { false, 0x4511, 0x4511 }, +/* 0x4512 */ { false, 0x4512, 0x4512 }, +/* 0x4513 */ { false, 0x4513, 0x4513 }, +/* 0x4514 */ { false, 0x4514, 0x4514 }, +/* 0x4515 */ { false, 0x4515, 0x4515 }, +/* 0x4516 */ { false, 0x4516, 0x4516 }, +/* 0x4517 */ { false, 0x4517, 0x4517 }, +/* 0x4518 */ { false, 0x4518, 0x4518 }, +/* 0x4519 */ { false, 0x4519, 0x4519 }, +/* 0x451a */ { false, 0x451a, 0x451a }, +/* 0x451b */ { false, 0x451b, 0x451b }, +/* 0x451c */ { false, 0x451c, 0x451c }, +/* 0x451d */ { false, 0x451d, 0x451d }, +/* 0x451e */ { false, 0x451e, 0x451e }, +/* 0x451f */ { false, 0x451f, 0x451f }, +/* 0x4520 */ { false, 0x4520, 0x4520 }, +/* 0x4521 */ { false, 0x4521, 0x4521 }, +/* 0x4522 */ { false, 0x4522, 0x4522 }, +/* 0x4523 */ { false, 0x4523, 0x4523 }, +/* 0x4524 */ { false, 0x4524, 0x4524 }, +/* 0x4525 */ { false, 0x4525, 0x4525 }, +/* 0x4526 */ { false, 0x4526, 0x4526 }, +/* 0x4527 */ { false, 0x4527, 0x4527 }, +/* 0x4528 */ { false, 0x4528, 0x4528 }, +/* 0x4529 */ { false, 0x4529, 0x4529 }, +/* 0x452a */ { false, 0x452a, 0x452a }, +/* 0x452b */ { false, 0x452b, 0x452b }, +/* 0x452c */ { false, 0x452c, 0x452c }, +/* 0x452d */ { false, 0x452d, 0x452d }, +/* 0x452e */ { false, 0x452e, 0x452e }, +/* 0x452f */ { false, 0x452f, 0x452f }, +/* 0x4530 */ { false, 0x4530, 0x4530 }, +/* 0x4531 */ { false, 0x4531, 0x4531 }, +/* 0x4532 */ { false, 0x4532, 0x4532 }, +/* 0x4533 */ { false, 0x4533, 0x4533 }, +/* 0x4534 */ { false, 0x4534, 0x4534 }, +/* 0x4535 */ { false, 0x4535, 0x4535 }, +/* 0x4536 */ { false, 0x4536, 0x4536 }, +/* 0x4537 */ { false, 0x4537, 0x4537 }, +/* 0x4538 */ { false, 0x4538, 0x4538 }, +/* 0x4539 */ { false, 0x4539, 0x4539 }, +/* 0x453a */ { false, 0x453a, 0x453a }, +/* 0x453b */ { false, 0x453b, 0x453b }, +/* 0x453c */ { false, 0x453c, 0x453c }, +/* 0x453d */ { false, 0x453d, 0x453d }, +/* 0x453e */ { false, 0x453e, 0x453e }, +/* 0x453f */ { false, 0x453f, 0x453f }, +/* 0x4540 */ { false, 0x4540, 0x4540 }, +/* 0x4541 */ { false, 0x4541, 0x4541 }, +/* 0x4542 */ { false, 0x4542, 0x4542 }, +/* 0x4543 */ { false, 0x4543, 0x4543 }, +/* 0x4544 */ { false, 0x4544, 0x4544 }, +/* 0x4545 */ { false, 0x4545, 0x4545 }, +/* 0x4546 */ { false, 0x4546, 0x4546 }, +/* 0x4547 */ { false, 0x4547, 0x4547 }, +/* 0x4548 */ { false, 0x4548, 0x4548 }, +/* 0x4549 */ { false, 0x4549, 0x4549 }, +/* 0x454a */ { false, 0x454a, 0x454a }, +/* 0x454b */ { false, 0x454b, 0x454b }, +/* 0x454c */ { false, 0x454c, 0x454c }, +/* 0x454d */ { false, 0x454d, 0x454d }, +/* 0x454e */ { false, 0x454e, 0x454e }, +/* 0x454f */ { false, 0x454f, 0x454f }, +/* 0x4550 */ { false, 0x4550, 0x4550 }, +/* 0x4551 */ { false, 0x4551, 0x4551 }, +/* 0x4552 */ { false, 0x4552, 0x4552 }, +/* 0x4553 */ { false, 0x4553, 0x4553 }, +/* 0x4554 */ { false, 0x4554, 0x4554 }, +/* 0x4555 */ { false, 0x4555, 0x4555 }, +/* 0x4556 */ { false, 0x4556, 0x4556 }, +/* 0x4557 */ { false, 0x4557, 0x4557 }, +/* 0x4558 */ { false, 0x4558, 0x4558 }, +/* 0x4559 */ { false, 0x4559, 0x4559 }, +/* 0x455a */ { false, 0x455a, 0x455a }, +/* 0x455b */ { false, 0x455b, 0x455b }, +/* 0x455c */ { false, 0x455c, 0x455c }, +/* 0x455d */ { false, 0x455d, 0x455d }, +/* 0x455e */ { false, 0x455e, 0x455e }, +/* 0x455f */ { false, 0x455f, 0x455f }, +/* 0x4560 */ { false, 0x4560, 0x4560 }, +/* 0x4561 */ { false, 0x4561, 0x4561 }, +/* 0x4562 */ { false, 0x4562, 0x4562 }, +/* 0x4563 */ { false, 0x4563, 0x4563 }, +/* 0x4564 */ { false, 0x4564, 0x4564 }, +/* 0x4565 */ { false, 0x4565, 0x4565 }, +/* 0x4566 */ { false, 0x4566, 0x4566 }, +/* 0x4567 */ { false, 0x4567, 0x4567 }, +/* 0x4568 */ { false, 0x4568, 0x4568 }, +/* 0x4569 */ { false, 0x4569, 0x4569 }, +/* 0x456a */ { false, 0x456a, 0x456a }, +/* 0x456b */ { false, 0x456b, 0x456b }, +/* 0x456c */ { false, 0x456c, 0x456c }, +/* 0x456d */ { false, 0x456d, 0x456d }, +/* 0x456e */ { false, 0x456e, 0x456e }, +/* 0x456f */ { false, 0x456f, 0x456f }, +/* 0x4570 */ { false, 0x4570, 0x4570 }, +/* 0x4571 */ { false, 0x4571, 0x4571 }, +/* 0x4572 */ { false, 0x4572, 0x4572 }, +/* 0x4573 */ { false, 0x4573, 0x4573 }, +/* 0x4574 */ { false, 0x4574, 0x4574 }, +/* 0x4575 */ { false, 0x4575, 0x4575 }, +/* 0x4576 */ { false, 0x4576, 0x4576 }, +/* 0x4577 */ { false, 0x4577, 0x4577 }, +/* 0x4578 */ { false, 0x4578, 0x4578 }, +/* 0x4579 */ { false, 0x4579, 0x4579 }, +/* 0x457a */ { false, 0x457a, 0x457a }, +/* 0x457b */ { false, 0x457b, 0x457b }, +/* 0x457c */ { false, 0x457c, 0x457c }, +/* 0x457d */ { false, 0x457d, 0x457d }, +/* 0x457e */ { false, 0x457e, 0x457e }, +/* 0x457f */ { false, 0x457f, 0x457f }, +/* 0x4580 */ { false, 0x4580, 0x4580 }, +/* 0x4581 */ { false, 0x4581, 0x4581 }, +/* 0x4582 */ { false, 0x4582, 0x4582 }, +/* 0x4583 */ { false, 0x4583, 0x4583 }, +/* 0x4584 */ { false, 0x4584, 0x4584 }, +/* 0x4585 */ { false, 0x4585, 0x4585 }, +/* 0x4586 */ { false, 0x4586, 0x4586 }, +/* 0x4587 */ { false, 0x4587, 0x4587 }, +/* 0x4588 */ { false, 0x4588, 0x4588 }, +/* 0x4589 */ { false, 0x4589, 0x4589 }, +/* 0x458a */ { false, 0x458a, 0x458a }, +/* 0x458b */ { false, 0x458b, 0x458b }, +/* 0x458c */ { false, 0x458c, 0x458c }, +/* 0x458d */ { false, 0x458d, 0x458d }, +/* 0x458e */ { false, 0x458e, 0x458e }, +/* 0x458f */ { false, 0x458f, 0x458f }, +/* 0x4590 */ { false, 0x4590, 0x4590 }, +/* 0x4591 */ { false, 0x4591, 0x4591 }, +/* 0x4592 */ { false, 0x4592, 0x4592 }, +/* 0x4593 */ { false, 0x4593, 0x4593 }, +/* 0x4594 */ { false, 0x4594, 0x4594 }, +/* 0x4595 */ { false, 0x4595, 0x4595 }, +/* 0x4596 */ { false, 0x4596, 0x4596 }, +/* 0x4597 */ { false, 0x4597, 0x4597 }, +/* 0x4598 */ { false, 0x4598, 0x4598 }, +/* 0x4599 */ { false, 0x4599, 0x4599 }, +/* 0x459a */ { false, 0x459a, 0x459a }, +/* 0x459b */ { false, 0x459b, 0x459b }, +/* 0x459c */ { false, 0x459c, 0x459c }, +/* 0x459d */ { false, 0x459d, 0x459d }, +/* 0x459e */ { false, 0x459e, 0x459e }, +/* 0x459f */ { false, 0x459f, 0x459f }, +/* 0x45a0 */ { false, 0x45a0, 0x45a0 }, +/* 0x45a1 */ { false, 0x45a1, 0x45a1 }, +/* 0x45a2 */ { false, 0x45a2, 0x45a2 }, +/* 0x45a3 */ { false, 0x45a3, 0x45a3 }, +/* 0x45a4 */ { false, 0x45a4, 0x45a4 }, +/* 0x45a5 */ { false, 0x45a5, 0x45a5 }, +/* 0x45a6 */ { false, 0x45a6, 0x45a6 }, +/* 0x45a7 */ { false, 0x45a7, 0x45a7 }, +/* 0x45a8 */ { false, 0x45a8, 0x45a8 }, +/* 0x45a9 */ { false, 0x45a9, 0x45a9 }, +/* 0x45aa */ { false, 0x45aa, 0x45aa }, +/* 0x45ab */ { false, 0x45ab, 0x45ab }, +/* 0x45ac */ { false, 0x45ac, 0x45ac }, +/* 0x45ad */ { false, 0x45ad, 0x45ad }, +/* 0x45ae */ { false, 0x45ae, 0x45ae }, +/* 0x45af */ { false, 0x45af, 0x45af }, +/* 0x45b0 */ { false, 0x45b0, 0x45b0 }, +/* 0x45b1 */ { false, 0x45b1, 0x45b1 }, +/* 0x45b2 */ { false, 0x45b2, 0x45b2 }, +/* 0x45b3 */ { false, 0x45b3, 0x45b3 }, +/* 0x45b4 */ { false, 0x45b4, 0x45b4 }, +/* 0x45b5 */ { false, 0x45b5, 0x45b5 }, +/* 0x45b6 */ { false, 0x45b6, 0x45b6 }, +/* 0x45b7 */ { false, 0x45b7, 0x45b7 }, +/* 0x45b8 */ { false, 0x45b8, 0x45b8 }, +/* 0x45b9 */ { false, 0x45b9, 0x45b9 }, +/* 0x45ba */ { false, 0x45ba, 0x45ba }, +/* 0x45bb */ { false, 0x45bb, 0x45bb }, +/* 0x45bc */ { false, 0x45bc, 0x45bc }, +/* 0x45bd */ { false, 0x45bd, 0x45bd }, +/* 0x45be */ { false, 0x45be, 0x45be }, +/* 0x45bf */ { false, 0x45bf, 0x45bf }, +/* 0x45c0 */ { false, 0x45c0, 0x45c0 }, +/* 0x45c1 */ { false, 0x45c1, 0x45c1 }, +/* 0x45c2 */ { false, 0x45c2, 0x45c2 }, +/* 0x45c3 */ { false, 0x45c3, 0x45c3 }, +/* 0x45c4 */ { false, 0x45c4, 0x45c4 }, +/* 0x45c5 */ { false, 0x45c5, 0x45c5 }, +/* 0x45c6 */ { false, 0x45c6, 0x45c6 }, +/* 0x45c7 */ { false, 0x45c7, 0x45c7 }, +/* 0x45c8 */ { false, 0x45c8, 0x45c8 }, +/* 0x45c9 */ { false, 0x45c9, 0x45c9 }, +/* 0x45ca */ { false, 0x45ca, 0x45ca }, +/* 0x45cb */ { false, 0x45cb, 0x45cb }, +/* 0x45cc */ { false, 0x45cc, 0x45cc }, +/* 0x45cd */ { false, 0x45cd, 0x45cd }, +/* 0x45ce */ { false, 0x45ce, 0x45ce }, +/* 0x45cf */ { false, 0x45cf, 0x45cf }, +/* 0x45d0 */ { false, 0x45d0, 0x45d0 }, +/* 0x45d1 */ { false, 0x45d1, 0x45d1 }, +/* 0x45d2 */ { false, 0x45d2, 0x45d2 }, +/* 0x45d3 */ { false, 0x45d3, 0x45d3 }, +/* 0x45d4 */ { false, 0x45d4, 0x45d4 }, +/* 0x45d5 */ { false, 0x45d5, 0x45d5 }, +/* 0x45d6 */ { false, 0x45d6, 0x45d6 }, +/* 0x45d7 */ { false, 0x45d7, 0x45d7 }, +/* 0x45d8 */ { false, 0x45d8, 0x45d8 }, +/* 0x45d9 */ { false, 0x45d9, 0x45d9 }, +/* 0x45da */ { false, 0x45da, 0x45da }, +/* 0x45db */ { false, 0x45db, 0x45db }, +/* 0x45dc */ { false, 0x45dc, 0x45dc }, +/* 0x45dd */ { false, 0x45dd, 0x45dd }, +/* 0x45de */ { false, 0x45de, 0x45de }, +/* 0x45df */ { false, 0x45df, 0x45df }, +/* 0x45e0 */ { false, 0x45e0, 0x45e0 }, +/* 0x45e1 */ { false, 0x45e1, 0x45e1 }, +/* 0x45e2 */ { false, 0x45e2, 0x45e2 }, +/* 0x45e3 */ { false, 0x45e3, 0x45e3 }, +/* 0x45e4 */ { false, 0x45e4, 0x45e4 }, +/* 0x45e5 */ { false, 0x45e5, 0x45e5 }, +/* 0x45e6 */ { false, 0x45e6, 0x45e6 }, +/* 0x45e7 */ { false, 0x45e7, 0x45e7 }, +/* 0x45e8 */ { false, 0x45e8, 0x45e8 }, +/* 0x45e9 */ { false, 0x45e9, 0x45e9 }, +/* 0x45ea */ { false, 0x45ea, 0x45ea }, +/* 0x45eb */ { false, 0x45eb, 0x45eb }, +/* 0x45ec */ { false, 0x45ec, 0x45ec }, +/* 0x45ed */ { false, 0x45ed, 0x45ed }, +/* 0x45ee */ { false, 0x45ee, 0x45ee }, +/* 0x45ef */ { false, 0x45ef, 0x45ef }, +/* 0x45f0 */ { false, 0x45f0, 0x45f0 }, +/* 0x45f1 */ { false, 0x45f1, 0x45f1 }, +/* 0x45f2 */ { false, 0x45f2, 0x45f2 }, +/* 0x45f3 */ { false, 0x45f3, 0x45f3 }, +/* 0x45f4 */ { false, 0x45f4, 0x45f4 }, +/* 0x45f5 */ { false, 0x45f5, 0x45f5 }, +/* 0x45f6 */ { false, 0x45f6, 0x45f6 }, +/* 0x45f7 */ { false, 0x45f7, 0x45f7 }, +/* 0x45f8 */ { false, 0x45f8, 0x45f8 }, +/* 0x45f9 */ { false, 0x45f9, 0x45f9 }, +/* 0x45fa */ { false, 0x45fa, 0x45fa }, +/* 0x45fb */ { false, 0x45fb, 0x45fb }, +/* 0x45fc */ { false, 0x45fc, 0x45fc }, +/* 0x45fd */ { false, 0x45fd, 0x45fd }, +/* 0x45fe */ { false, 0x45fe, 0x45fe }, +/* 0x45ff */ { false, 0x45ff, 0x45ff }, +/* 0x4600 */ { false, 0x4600, 0x4600 }, +/* 0x4601 */ { false, 0x4601, 0x4601 }, +/* 0x4602 */ { false, 0x4602, 0x4602 }, +/* 0x4603 */ { false, 0x4603, 0x4603 }, +/* 0x4604 */ { false, 0x4604, 0x4604 }, +/* 0x4605 */ { false, 0x4605, 0x4605 }, +/* 0x4606 */ { false, 0x4606, 0x4606 }, +/* 0x4607 */ { false, 0x4607, 0x4607 }, +/* 0x4608 */ { false, 0x4608, 0x4608 }, +/* 0x4609 */ { false, 0x4609, 0x4609 }, +/* 0x460a */ { false, 0x460a, 0x460a }, +/* 0x460b */ { false, 0x460b, 0x460b }, +/* 0x460c */ { false, 0x460c, 0x460c }, +/* 0x460d */ { false, 0x460d, 0x460d }, +/* 0x460e */ { false, 0x460e, 0x460e }, +/* 0x460f */ { false, 0x460f, 0x460f }, +/* 0x4610 */ { false, 0x4610, 0x4610 }, +/* 0x4611 */ { false, 0x4611, 0x4611 }, +/* 0x4612 */ { false, 0x4612, 0x4612 }, +/* 0x4613 */ { false, 0x4613, 0x4613 }, +/* 0x4614 */ { false, 0x4614, 0x4614 }, +/* 0x4615 */ { false, 0x4615, 0x4615 }, +/* 0x4616 */ { false, 0x4616, 0x4616 }, +/* 0x4617 */ { false, 0x4617, 0x4617 }, +/* 0x4618 */ { false, 0x4618, 0x4618 }, +/* 0x4619 */ { false, 0x4619, 0x4619 }, +/* 0x461a */ { false, 0x461a, 0x461a }, +/* 0x461b */ { false, 0x461b, 0x461b }, +/* 0x461c */ { false, 0x461c, 0x461c }, +/* 0x461d */ { false, 0x461d, 0x461d }, +/* 0x461e */ { false, 0x461e, 0x461e }, +/* 0x461f */ { false, 0x461f, 0x461f }, +/* 0x4620 */ { false, 0x4620, 0x4620 }, +/* 0x4621 */ { false, 0x4621, 0x4621 }, +/* 0x4622 */ { false, 0x4622, 0x4622 }, +/* 0x4623 */ { false, 0x4623, 0x4623 }, +/* 0x4624 */ { false, 0x4624, 0x4624 }, +/* 0x4625 */ { false, 0x4625, 0x4625 }, +/* 0x4626 */ { false, 0x4626, 0x4626 }, +/* 0x4627 */ { false, 0x4627, 0x4627 }, +/* 0x4628 */ { false, 0x4628, 0x4628 }, +/* 0x4629 */ { false, 0x4629, 0x4629 }, +/* 0x462a */ { false, 0x462a, 0x462a }, +/* 0x462b */ { false, 0x462b, 0x462b }, +/* 0x462c */ { false, 0x462c, 0x462c }, +/* 0x462d */ { false, 0x462d, 0x462d }, +/* 0x462e */ { false, 0x462e, 0x462e }, +/* 0x462f */ { false, 0x462f, 0x462f }, +/* 0x4630 */ { false, 0x4630, 0x4630 }, +/* 0x4631 */ { false, 0x4631, 0x4631 }, +/* 0x4632 */ { false, 0x4632, 0x4632 }, +/* 0x4633 */ { false, 0x4633, 0x4633 }, +/* 0x4634 */ { false, 0x4634, 0x4634 }, +/* 0x4635 */ { false, 0x4635, 0x4635 }, +/* 0x4636 */ { false, 0x4636, 0x4636 }, +/* 0x4637 */ { false, 0x4637, 0x4637 }, +/* 0x4638 */ { false, 0x4638, 0x4638 }, +/* 0x4639 */ { false, 0x4639, 0x4639 }, +/* 0x463a */ { false, 0x463a, 0x463a }, +/* 0x463b */ { false, 0x463b, 0x463b }, +/* 0x463c */ { false, 0x463c, 0x463c }, +/* 0x463d */ { false, 0x463d, 0x463d }, +/* 0x463e */ { false, 0x463e, 0x463e }, +/* 0x463f */ { false, 0x463f, 0x463f }, +/* 0x4640 */ { false, 0x4640, 0x4640 }, +/* 0x4641 */ { false, 0x4641, 0x4641 }, +/* 0x4642 */ { false, 0x4642, 0x4642 }, +/* 0x4643 */ { false, 0x4643, 0x4643 }, +/* 0x4644 */ { false, 0x4644, 0x4644 }, +/* 0x4645 */ { false, 0x4645, 0x4645 }, +/* 0x4646 */ { false, 0x4646, 0x4646 }, +/* 0x4647 */ { false, 0x4647, 0x4647 }, +/* 0x4648 */ { false, 0x4648, 0x4648 }, +/* 0x4649 */ { false, 0x4649, 0x4649 }, +/* 0x464a */ { false, 0x464a, 0x464a }, +/* 0x464b */ { false, 0x464b, 0x464b }, +/* 0x464c */ { false, 0x464c, 0x464c }, +/* 0x464d */ { false, 0x464d, 0x464d }, +/* 0x464e */ { false, 0x464e, 0x464e }, +/* 0x464f */ { false, 0x464f, 0x464f }, +/* 0x4650 */ { false, 0x4650, 0x4650 }, +/* 0x4651 */ { false, 0x4651, 0x4651 }, +/* 0x4652 */ { false, 0x4652, 0x4652 }, +/* 0x4653 */ { false, 0x4653, 0x4653 }, +/* 0x4654 */ { false, 0x4654, 0x4654 }, +/* 0x4655 */ { false, 0x4655, 0x4655 }, +/* 0x4656 */ { false, 0x4656, 0x4656 }, +/* 0x4657 */ { false, 0x4657, 0x4657 }, +/* 0x4658 */ { false, 0x4658, 0x4658 }, +/* 0x4659 */ { false, 0x4659, 0x4659 }, +/* 0x465a */ { false, 0x465a, 0x465a }, +/* 0x465b */ { false, 0x465b, 0x465b }, +/* 0x465c */ { false, 0x465c, 0x465c }, +/* 0x465d */ { false, 0x465d, 0x465d }, +/* 0x465e */ { false, 0x465e, 0x465e }, +/* 0x465f */ { false, 0x465f, 0x465f }, +/* 0x4660 */ { false, 0x4660, 0x4660 }, +/* 0x4661 */ { false, 0x4661, 0x4661 }, +/* 0x4662 */ { false, 0x4662, 0x4662 }, +/* 0x4663 */ { false, 0x4663, 0x4663 }, +/* 0x4664 */ { false, 0x4664, 0x4664 }, +/* 0x4665 */ { false, 0x4665, 0x4665 }, +/* 0x4666 */ { false, 0x4666, 0x4666 }, +/* 0x4667 */ { false, 0x4667, 0x4667 }, +/* 0x4668 */ { false, 0x4668, 0x4668 }, +/* 0x4669 */ { false, 0x4669, 0x4669 }, +/* 0x466a */ { false, 0x466a, 0x466a }, +/* 0x466b */ { false, 0x466b, 0x466b }, +/* 0x466c */ { false, 0x466c, 0x466c }, +/* 0x466d */ { false, 0x466d, 0x466d }, +/* 0x466e */ { false, 0x466e, 0x466e }, +/* 0x466f */ { false, 0x466f, 0x466f }, +/* 0x4670 */ { false, 0x4670, 0x4670 }, +/* 0x4671 */ { false, 0x4671, 0x4671 }, +/* 0x4672 */ { false, 0x4672, 0x4672 }, +/* 0x4673 */ { false, 0x4673, 0x4673 }, +/* 0x4674 */ { false, 0x4674, 0x4674 }, +/* 0x4675 */ { false, 0x4675, 0x4675 }, +/* 0x4676 */ { false, 0x4676, 0x4676 }, +/* 0x4677 */ { false, 0x4677, 0x4677 }, +/* 0x4678 */ { false, 0x4678, 0x4678 }, +/* 0x4679 */ { false, 0x4679, 0x4679 }, +/* 0x467a */ { false, 0x467a, 0x467a }, +/* 0x467b */ { false, 0x467b, 0x467b }, +/* 0x467c */ { false, 0x467c, 0x467c }, +/* 0x467d */ { false, 0x467d, 0x467d }, +/* 0x467e */ { false, 0x467e, 0x467e }, +/* 0x467f */ { false, 0x467f, 0x467f }, +/* 0x4680 */ { false, 0x4680, 0x4680 }, +/* 0x4681 */ { false, 0x4681, 0x4681 }, +/* 0x4682 */ { false, 0x4682, 0x4682 }, +/* 0x4683 */ { false, 0x4683, 0x4683 }, +/* 0x4684 */ { false, 0x4684, 0x4684 }, +/* 0x4685 */ { false, 0x4685, 0x4685 }, +/* 0x4686 */ { false, 0x4686, 0x4686 }, +/* 0x4687 */ { false, 0x4687, 0x4687 }, +/* 0x4688 */ { false, 0x4688, 0x4688 }, +/* 0x4689 */ { false, 0x4689, 0x4689 }, +/* 0x468a */ { false, 0x468a, 0x468a }, +/* 0x468b */ { false, 0x468b, 0x468b }, +/* 0x468c */ { false, 0x468c, 0x468c }, +/* 0x468d */ { false, 0x468d, 0x468d }, +/* 0x468e */ { false, 0x468e, 0x468e }, +/* 0x468f */ { false, 0x468f, 0x468f }, +/* 0x4690 */ { false, 0x4690, 0x4690 }, +/* 0x4691 */ { false, 0x4691, 0x4691 }, +/* 0x4692 */ { false, 0x4692, 0x4692 }, +/* 0x4693 */ { false, 0x4693, 0x4693 }, +/* 0x4694 */ { false, 0x4694, 0x4694 }, +/* 0x4695 */ { false, 0x4695, 0x4695 }, +/* 0x4696 */ { false, 0x4696, 0x4696 }, +/* 0x4697 */ { false, 0x4697, 0x4697 }, +/* 0x4698 */ { false, 0x4698, 0x4698 }, +/* 0x4699 */ { false, 0x4699, 0x4699 }, +/* 0x469a */ { false, 0x469a, 0x469a }, +/* 0x469b */ { false, 0x469b, 0x469b }, +/* 0x469c */ { false, 0x469c, 0x469c }, +/* 0x469d */ { false, 0x469d, 0x469d }, +/* 0x469e */ { false, 0x469e, 0x469e }, +/* 0x469f */ { false, 0x469f, 0x469f }, +/* 0x46a0 */ { false, 0x46a0, 0x46a0 }, +/* 0x46a1 */ { false, 0x46a1, 0x46a1 }, +/* 0x46a2 */ { false, 0x46a2, 0x46a2 }, +/* 0x46a3 */ { false, 0x46a3, 0x46a3 }, +/* 0x46a4 */ { false, 0x46a4, 0x46a4 }, +/* 0x46a5 */ { false, 0x46a5, 0x46a5 }, +/* 0x46a6 */ { false, 0x46a6, 0x46a6 }, +/* 0x46a7 */ { false, 0x46a7, 0x46a7 }, +/* 0x46a8 */ { false, 0x46a8, 0x46a8 }, +/* 0x46a9 */ { false, 0x46a9, 0x46a9 }, +/* 0x46aa */ { false, 0x46aa, 0x46aa }, +/* 0x46ab */ { false, 0x46ab, 0x46ab }, +/* 0x46ac */ { false, 0x46ac, 0x46ac }, +/* 0x46ad */ { false, 0x46ad, 0x46ad }, +/* 0x46ae */ { false, 0x46ae, 0x46ae }, +/* 0x46af */ { false, 0x46af, 0x46af }, +/* 0x46b0 */ { false, 0x46b0, 0x46b0 }, +/* 0x46b1 */ { false, 0x46b1, 0x46b1 }, +/* 0x46b2 */ { false, 0x46b2, 0x46b2 }, +/* 0x46b3 */ { false, 0x46b3, 0x46b3 }, +/* 0x46b4 */ { false, 0x46b4, 0x46b4 }, +/* 0x46b5 */ { false, 0x46b5, 0x46b5 }, +/* 0x46b6 */ { false, 0x46b6, 0x46b6 }, +/* 0x46b7 */ { false, 0x46b7, 0x46b7 }, +/* 0x46b8 */ { false, 0x46b8, 0x46b8 }, +/* 0x46b9 */ { false, 0x46b9, 0x46b9 }, +/* 0x46ba */ { false, 0x46ba, 0x46ba }, +/* 0x46bb */ { false, 0x46bb, 0x46bb }, +/* 0x46bc */ { false, 0x46bc, 0x46bc }, +/* 0x46bd */ { false, 0x46bd, 0x46bd }, +/* 0x46be */ { false, 0x46be, 0x46be }, +/* 0x46bf */ { false, 0x46bf, 0x46bf }, +/* 0x46c0 */ { false, 0x46c0, 0x46c0 }, +/* 0x46c1 */ { false, 0x46c1, 0x46c1 }, +/* 0x46c2 */ { false, 0x46c2, 0x46c2 }, +/* 0x46c3 */ { false, 0x46c3, 0x46c3 }, +/* 0x46c4 */ { false, 0x46c4, 0x46c4 }, +/* 0x46c5 */ { false, 0x46c5, 0x46c5 }, +/* 0x46c6 */ { false, 0x46c6, 0x46c6 }, +/* 0x46c7 */ { false, 0x46c7, 0x46c7 }, +/* 0x46c8 */ { false, 0x46c8, 0x46c8 }, +/* 0x46c9 */ { false, 0x46c9, 0x46c9 }, +/* 0x46ca */ { false, 0x46ca, 0x46ca }, +/* 0x46cb */ { false, 0x46cb, 0x46cb }, +/* 0x46cc */ { false, 0x46cc, 0x46cc }, +/* 0x46cd */ { false, 0x46cd, 0x46cd }, +/* 0x46ce */ { false, 0x46ce, 0x46ce }, +/* 0x46cf */ { false, 0x46cf, 0x46cf }, +/* 0x46d0 */ { false, 0x46d0, 0x46d0 }, +/* 0x46d1 */ { false, 0x46d1, 0x46d1 }, +/* 0x46d2 */ { false, 0x46d2, 0x46d2 }, +/* 0x46d3 */ { false, 0x46d3, 0x46d3 }, +/* 0x46d4 */ { false, 0x46d4, 0x46d4 }, +/* 0x46d5 */ { false, 0x46d5, 0x46d5 }, +/* 0x46d6 */ { false, 0x46d6, 0x46d6 }, +/* 0x46d7 */ { false, 0x46d7, 0x46d7 }, +/* 0x46d8 */ { false, 0x46d8, 0x46d8 }, +/* 0x46d9 */ { false, 0x46d9, 0x46d9 }, +/* 0x46da */ { false, 0x46da, 0x46da }, +/* 0x46db */ { false, 0x46db, 0x46db }, +/* 0x46dc */ { false, 0x46dc, 0x46dc }, +/* 0x46dd */ { false, 0x46dd, 0x46dd }, +/* 0x46de */ { false, 0x46de, 0x46de }, +/* 0x46df */ { false, 0x46df, 0x46df }, +/* 0x46e0 */ { false, 0x46e0, 0x46e0 }, +/* 0x46e1 */ { false, 0x46e1, 0x46e1 }, +/* 0x46e2 */ { false, 0x46e2, 0x46e2 }, +/* 0x46e3 */ { false, 0x46e3, 0x46e3 }, +/* 0x46e4 */ { false, 0x46e4, 0x46e4 }, +/* 0x46e5 */ { false, 0x46e5, 0x46e5 }, +/* 0x46e6 */ { false, 0x46e6, 0x46e6 }, +/* 0x46e7 */ { false, 0x46e7, 0x46e7 }, +/* 0x46e8 */ { false, 0x46e8, 0x46e8 }, +/* 0x46e9 */ { false, 0x46e9, 0x46e9 }, +/* 0x46ea */ { false, 0x46ea, 0x46ea }, +/* 0x46eb */ { false, 0x46eb, 0x46eb }, +/* 0x46ec */ { false, 0x46ec, 0x46ec }, +/* 0x46ed */ { false, 0x46ed, 0x46ed }, +/* 0x46ee */ { false, 0x46ee, 0x46ee }, +/* 0x46ef */ { false, 0x46ef, 0x46ef }, +/* 0x46f0 */ { false, 0x46f0, 0x46f0 }, +/* 0x46f1 */ { false, 0x46f1, 0x46f1 }, +/* 0x46f2 */ { false, 0x46f2, 0x46f2 }, +/* 0x46f3 */ { false, 0x46f3, 0x46f3 }, +/* 0x46f4 */ { false, 0x46f4, 0x46f4 }, +/* 0x46f5 */ { false, 0x46f5, 0x46f5 }, +/* 0x46f6 */ { false, 0x46f6, 0x46f6 }, +/* 0x46f7 */ { false, 0x46f7, 0x46f7 }, +/* 0x46f8 */ { false, 0x46f8, 0x46f8 }, +/* 0x46f9 */ { false, 0x46f9, 0x46f9 }, +/* 0x46fa */ { false, 0x46fa, 0x46fa }, +/* 0x46fb */ { false, 0x46fb, 0x46fb }, +/* 0x46fc */ { false, 0x46fc, 0x46fc }, +/* 0x46fd */ { false, 0x46fd, 0x46fd }, +/* 0x46fe */ { false, 0x46fe, 0x46fe }, +/* 0x46ff */ { false, 0x46ff, 0x46ff }, +/* 0x4700 */ { false, 0x4700, 0x4700 }, +/* 0x4701 */ { false, 0x4701, 0x4701 }, +/* 0x4702 */ { false, 0x4702, 0x4702 }, +/* 0x4703 */ { false, 0x4703, 0x4703 }, +/* 0x4704 */ { false, 0x4704, 0x4704 }, +/* 0x4705 */ { false, 0x4705, 0x4705 }, +/* 0x4706 */ { false, 0x4706, 0x4706 }, +/* 0x4707 */ { false, 0x4707, 0x4707 }, +/* 0x4708 */ { false, 0x4708, 0x4708 }, +/* 0x4709 */ { false, 0x4709, 0x4709 }, +/* 0x470a */ { false, 0x470a, 0x470a }, +/* 0x470b */ { false, 0x470b, 0x470b }, +/* 0x470c */ { false, 0x470c, 0x470c }, +/* 0x470d */ { false, 0x470d, 0x470d }, +/* 0x470e */ { false, 0x470e, 0x470e }, +/* 0x470f */ { false, 0x470f, 0x470f }, +/* 0x4710 */ { false, 0x4710, 0x4710 }, +/* 0x4711 */ { false, 0x4711, 0x4711 }, +/* 0x4712 */ { false, 0x4712, 0x4712 }, +/* 0x4713 */ { false, 0x4713, 0x4713 }, +/* 0x4714 */ { false, 0x4714, 0x4714 }, +/* 0x4715 */ { false, 0x4715, 0x4715 }, +/* 0x4716 */ { false, 0x4716, 0x4716 }, +/* 0x4717 */ { false, 0x4717, 0x4717 }, +/* 0x4718 */ { false, 0x4718, 0x4718 }, +/* 0x4719 */ { false, 0x4719, 0x4719 }, +/* 0x471a */ { false, 0x471a, 0x471a }, +/* 0x471b */ { false, 0x471b, 0x471b }, +/* 0x471c */ { false, 0x471c, 0x471c }, +/* 0x471d */ { false, 0x471d, 0x471d }, +/* 0x471e */ { false, 0x471e, 0x471e }, +/* 0x471f */ { false, 0x471f, 0x471f }, +/* 0x4720 */ { false, 0x4720, 0x4720 }, +/* 0x4721 */ { false, 0x4721, 0x4721 }, +/* 0x4722 */ { false, 0x4722, 0x4722 }, +/* 0x4723 */ { false, 0x4723, 0x4723 }, +/* 0x4724 */ { false, 0x4724, 0x4724 }, +/* 0x4725 */ { false, 0x4725, 0x4725 }, +/* 0x4726 */ { false, 0x4726, 0x4726 }, +/* 0x4727 */ { false, 0x4727, 0x4727 }, +/* 0x4728 */ { false, 0x4728, 0x4728 }, +/* 0x4729 */ { false, 0x4729, 0x4729 }, +/* 0x472a */ { false, 0x472a, 0x472a }, +/* 0x472b */ { false, 0x472b, 0x472b }, +/* 0x472c */ { false, 0x472c, 0x472c }, +/* 0x472d */ { false, 0x472d, 0x472d }, +/* 0x472e */ { false, 0x472e, 0x472e }, +/* 0x472f */ { false, 0x472f, 0x472f }, +/* 0x4730 */ { false, 0x4730, 0x4730 }, +/* 0x4731 */ { false, 0x4731, 0x4731 }, +/* 0x4732 */ { false, 0x4732, 0x4732 }, +/* 0x4733 */ { false, 0x4733, 0x4733 }, +/* 0x4734 */ { false, 0x4734, 0x4734 }, +/* 0x4735 */ { false, 0x4735, 0x4735 }, +/* 0x4736 */ { false, 0x4736, 0x4736 }, +/* 0x4737 */ { false, 0x4737, 0x4737 }, +/* 0x4738 */ { false, 0x4738, 0x4738 }, +/* 0x4739 */ { false, 0x4739, 0x4739 }, +/* 0x473a */ { false, 0x473a, 0x473a }, +/* 0x473b */ { false, 0x473b, 0x473b }, +/* 0x473c */ { false, 0x473c, 0x473c }, +/* 0x473d */ { false, 0x473d, 0x473d }, +/* 0x473e */ { false, 0x473e, 0x473e }, +/* 0x473f */ { false, 0x473f, 0x473f }, +/* 0x4740 */ { false, 0x4740, 0x4740 }, +/* 0x4741 */ { false, 0x4741, 0x4741 }, +/* 0x4742 */ { false, 0x4742, 0x4742 }, +/* 0x4743 */ { false, 0x4743, 0x4743 }, +/* 0x4744 */ { false, 0x4744, 0x4744 }, +/* 0x4745 */ { false, 0x4745, 0x4745 }, +/* 0x4746 */ { false, 0x4746, 0x4746 }, +/* 0x4747 */ { false, 0x4747, 0x4747 }, +/* 0x4748 */ { false, 0x4748, 0x4748 }, +/* 0x4749 */ { false, 0x4749, 0x4749 }, +/* 0x474a */ { false, 0x474a, 0x474a }, +/* 0x474b */ { false, 0x474b, 0x474b }, +/* 0x474c */ { false, 0x474c, 0x474c }, +/* 0x474d */ { false, 0x474d, 0x474d }, +/* 0x474e */ { false, 0x474e, 0x474e }, +/* 0x474f */ { false, 0x474f, 0x474f }, +/* 0x4750 */ { false, 0x4750, 0x4750 }, +/* 0x4751 */ { false, 0x4751, 0x4751 }, +/* 0x4752 */ { false, 0x4752, 0x4752 }, +/* 0x4753 */ { false, 0x4753, 0x4753 }, +/* 0x4754 */ { false, 0x4754, 0x4754 }, +/* 0x4755 */ { false, 0x4755, 0x4755 }, +/* 0x4756 */ { false, 0x4756, 0x4756 }, +/* 0x4757 */ { false, 0x4757, 0x4757 }, +/* 0x4758 */ { false, 0x4758, 0x4758 }, +/* 0x4759 */ { false, 0x4759, 0x4759 }, +/* 0x475a */ { false, 0x475a, 0x475a }, +/* 0x475b */ { false, 0x475b, 0x475b }, +/* 0x475c */ { false, 0x475c, 0x475c }, +/* 0x475d */ { false, 0x475d, 0x475d }, +/* 0x475e */ { false, 0x475e, 0x475e }, +/* 0x475f */ { false, 0x475f, 0x475f }, +/* 0x4760 */ { false, 0x4760, 0x4760 }, +/* 0x4761 */ { false, 0x4761, 0x4761 }, +/* 0x4762 */ { false, 0x4762, 0x4762 }, +/* 0x4763 */ { false, 0x4763, 0x4763 }, +/* 0x4764 */ { false, 0x4764, 0x4764 }, +/* 0x4765 */ { false, 0x4765, 0x4765 }, +/* 0x4766 */ { false, 0x4766, 0x4766 }, +/* 0x4767 */ { false, 0x4767, 0x4767 }, +/* 0x4768 */ { false, 0x4768, 0x4768 }, +/* 0x4769 */ { false, 0x4769, 0x4769 }, +/* 0x476a */ { false, 0x476a, 0x476a }, +/* 0x476b */ { false, 0x476b, 0x476b }, +/* 0x476c */ { false, 0x476c, 0x476c }, +/* 0x476d */ { false, 0x476d, 0x476d }, +/* 0x476e */ { false, 0x476e, 0x476e }, +/* 0x476f */ { false, 0x476f, 0x476f }, +/* 0x4770 */ { false, 0x4770, 0x4770 }, +/* 0x4771 */ { false, 0x4771, 0x4771 }, +/* 0x4772 */ { false, 0x4772, 0x4772 }, +/* 0x4773 */ { false, 0x4773, 0x4773 }, +/* 0x4774 */ { false, 0x4774, 0x4774 }, +/* 0x4775 */ { false, 0x4775, 0x4775 }, +/* 0x4776 */ { false, 0x4776, 0x4776 }, +/* 0x4777 */ { false, 0x4777, 0x4777 }, +/* 0x4778 */ { false, 0x4778, 0x4778 }, +/* 0x4779 */ { false, 0x4779, 0x4779 }, +/* 0x477a */ { false, 0x477a, 0x477a }, +/* 0x477b */ { false, 0x477b, 0x477b }, +/* 0x477c */ { false, 0x477c, 0x477c }, +/* 0x477d */ { false, 0x477d, 0x477d }, +/* 0x477e */ { false, 0x477e, 0x477e }, +/* 0x477f */ { false, 0x477f, 0x477f }, +/* 0x4780 */ { false, 0x4780, 0x4780 }, +/* 0x4781 */ { false, 0x4781, 0x4781 }, +/* 0x4782 */ { false, 0x4782, 0x4782 }, +/* 0x4783 */ { false, 0x4783, 0x4783 }, +/* 0x4784 */ { false, 0x4784, 0x4784 }, +/* 0x4785 */ { false, 0x4785, 0x4785 }, +/* 0x4786 */ { false, 0x4786, 0x4786 }, +/* 0x4787 */ { false, 0x4787, 0x4787 }, +/* 0x4788 */ { false, 0x4788, 0x4788 }, +/* 0x4789 */ { false, 0x4789, 0x4789 }, +/* 0x478a */ { false, 0x478a, 0x478a }, +/* 0x478b */ { false, 0x478b, 0x478b }, +/* 0x478c */ { false, 0x478c, 0x478c }, +/* 0x478d */ { false, 0x478d, 0x478d }, +/* 0x478e */ { false, 0x478e, 0x478e }, +/* 0x478f */ { false, 0x478f, 0x478f }, +/* 0x4790 */ { false, 0x4790, 0x4790 }, +/* 0x4791 */ { false, 0x4791, 0x4791 }, +/* 0x4792 */ { false, 0x4792, 0x4792 }, +/* 0x4793 */ { false, 0x4793, 0x4793 }, +/* 0x4794 */ { false, 0x4794, 0x4794 }, +/* 0x4795 */ { false, 0x4795, 0x4795 }, +/* 0x4796 */ { false, 0x4796, 0x4796 }, +/* 0x4797 */ { false, 0x4797, 0x4797 }, +/* 0x4798 */ { false, 0x4798, 0x4798 }, +/* 0x4799 */ { false, 0x4799, 0x4799 }, +/* 0x479a */ { false, 0x479a, 0x479a }, +/* 0x479b */ { false, 0x479b, 0x479b }, +/* 0x479c */ { false, 0x479c, 0x479c }, +/* 0x479d */ { false, 0x479d, 0x479d }, +/* 0x479e */ { false, 0x479e, 0x479e }, +/* 0x479f */ { false, 0x479f, 0x479f }, +/* 0x47a0 */ { false, 0x47a0, 0x47a0 }, +/* 0x47a1 */ { false, 0x47a1, 0x47a1 }, +/* 0x47a2 */ { false, 0x47a2, 0x47a2 }, +/* 0x47a3 */ { false, 0x47a3, 0x47a3 }, +/* 0x47a4 */ { false, 0x47a4, 0x47a4 }, +/* 0x47a5 */ { false, 0x47a5, 0x47a5 }, +/* 0x47a6 */ { false, 0x47a6, 0x47a6 }, +/* 0x47a7 */ { false, 0x47a7, 0x47a7 }, +/* 0x47a8 */ { false, 0x47a8, 0x47a8 }, +/* 0x47a9 */ { false, 0x47a9, 0x47a9 }, +/* 0x47aa */ { false, 0x47aa, 0x47aa }, +/* 0x47ab */ { false, 0x47ab, 0x47ab }, +/* 0x47ac */ { false, 0x47ac, 0x47ac }, +/* 0x47ad */ { false, 0x47ad, 0x47ad }, +/* 0x47ae */ { false, 0x47ae, 0x47ae }, +/* 0x47af */ { false, 0x47af, 0x47af }, +/* 0x47b0 */ { false, 0x47b0, 0x47b0 }, +/* 0x47b1 */ { false, 0x47b1, 0x47b1 }, +/* 0x47b2 */ { false, 0x47b2, 0x47b2 }, +/* 0x47b3 */ { false, 0x47b3, 0x47b3 }, +/* 0x47b4 */ { false, 0x47b4, 0x47b4 }, +/* 0x47b5 */ { false, 0x47b5, 0x47b5 }, +/* 0x47b6 */ { false, 0x47b6, 0x47b6 }, +/* 0x47b7 */ { false, 0x47b7, 0x47b7 }, +/* 0x47b8 */ { false, 0x47b8, 0x47b8 }, +/* 0x47b9 */ { false, 0x47b9, 0x47b9 }, +/* 0x47ba */ { false, 0x47ba, 0x47ba }, +/* 0x47bb */ { false, 0x47bb, 0x47bb }, +/* 0x47bc */ { false, 0x47bc, 0x47bc }, +/* 0x47bd */ { false, 0x47bd, 0x47bd }, +/* 0x47be */ { false, 0x47be, 0x47be }, +/* 0x47bf */ { false, 0x47bf, 0x47bf }, +/* 0x47c0 */ { false, 0x47c0, 0x47c0 }, +/* 0x47c1 */ { false, 0x47c1, 0x47c1 }, +/* 0x47c2 */ { false, 0x47c2, 0x47c2 }, +/* 0x47c3 */ { false, 0x47c3, 0x47c3 }, +/* 0x47c4 */ { false, 0x47c4, 0x47c4 }, +/* 0x47c5 */ { false, 0x47c5, 0x47c5 }, +/* 0x47c6 */ { false, 0x47c6, 0x47c6 }, +/* 0x47c7 */ { false, 0x47c7, 0x47c7 }, +/* 0x47c8 */ { false, 0x47c8, 0x47c8 }, +/* 0x47c9 */ { false, 0x47c9, 0x47c9 }, +/* 0x47ca */ { false, 0x47ca, 0x47ca }, +/* 0x47cb */ { false, 0x47cb, 0x47cb }, +/* 0x47cc */ { false, 0x47cc, 0x47cc }, +/* 0x47cd */ { false, 0x47cd, 0x47cd }, +/* 0x47ce */ { false, 0x47ce, 0x47ce }, +/* 0x47cf */ { false, 0x47cf, 0x47cf }, +/* 0x47d0 */ { false, 0x47d0, 0x47d0 }, +/* 0x47d1 */ { false, 0x47d1, 0x47d1 }, +/* 0x47d2 */ { false, 0x47d2, 0x47d2 }, +/* 0x47d3 */ { false, 0x47d3, 0x47d3 }, +/* 0x47d4 */ { false, 0x47d4, 0x47d4 }, +/* 0x47d5 */ { false, 0x47d5, 0x47d5 }, +/* 0x47d6 */ { false, 0x47d6, 0x47d6 }, +/* 0x47d7 */ { false, 0x47d7, 0x47d7 }, +/* 0x47d8 */ { false, 0x47d8, 0x47d8 }, +/* 0x47d9 */ { false, 0x47d9, 0x47d9 }, +/* 0x47da */ { false, 0x47da, 0x47da }, +/* 0x47db */ { false, 0x47db, 0x47db }, +/* 0x47dc */ { false, 0x47dc, 0x47dc }, +/* 0x47dd */ { false, 0x47dd, 0x47dd }, +/* 0x47de */ { false, 0x47de, 0x47de }, +/* 0x47df */ { false, 0x47df, 0x47df }, +/* 0x47e0 */ { false, 0x47e0, 0x47e0 }, +/* 0x47e1 */ { false, 0x47e1, 0x47e1 }, +/* 0x47e2 */ { false, 0x47e2, 0x47e2 }, +/* 0x47e3 */ { false, 0x47e3, 0x47e3 }, +/* 0x47e4 */ { false, 0x47e4, 0x47e4 }, +/* 0x47e5 */ { false, 0x47e5, 0x47e5 }, +/* 0x47e6 */ { false, 0x47e6, 0x47e6 }, +/* 0x47e7 */ { false, 0x47e7, 0x47e7 }, +/* 0x47e8 */ { false, 0x47e8, 0x47e8 }, +/* 0x47e9 */ { false, 0x47e9, 0x47e9 }, +/* 0x47ea */ { false, 0x47ea, 0x47ea }, +/* 0x47eb */ { false, 0x47eb, 0x47eb }, +/* 0x47ec */ { false, 0x47ec, 0x47ec }, +/* 0x47ed */ { false, 0x47ed, 0x47ed }, +/* 0x47ee */ { false, 0x47ee, 0x47ee }, +/* 0x47ef */ { false, 0x47ef, 0x47ef }, +/* 0x47f0 */ { false, 0x47f0, 0x47f0 }, +/* 0x47f1 */ { false, 0x47f1, 0x47f1 }, +/* 0x47f2 */ { false, 0x47f2, 0x47f2 }, +/* 0x47f3 */ { false, 0x47f3, 0x47f3 }, +/* 0x47f4 */ { false, 0x47f4, 0x47f4 }, +/* 0x47f5 */ { false, 0x47f5, 0x47f5 }, +/* 0x47f6 */ { false, 0x47f6, 0x47f6 }, +/* 0x47f7 */ { false, 0x47f7, 0x47f7 }, +/* 0x47f8 */ { false, 0x47f8, 0x47f8 }, +/* 0x47f9 */ { false, 0x47f9, 0x47f9 }, +/* 0x47fa */ { false, 0x47fa, 0x47fa }, +/* 0x47fb */ { false, 0x47fb, 0x47fb }, +/* 0x47fc */ { false, 0x47fc, 0x47fc }, +/* 0x47fd */ { false, 0x47fd, 0x47fd }, +/* 0x47fe */ { false, 0x47fe, 0x47fe }, +/* 0x47ff */ { false, 0x47ff, 0x47ff }, +/* 0x4800 */ { false, 0x4800, 0x4800 }, +/* 0x4801 */ { false, 0x4801, 0x4801 }, +/* 0x4802 */ { false, 0x4802, 0x4802 }, +/* 0x4803 */ { false, 0x4803, 0x4803 }, +/* 0x4804 */ { false, 0x4804, 0x4804 }, +/* 0x4805 */ { false, 0x4805, 0x4805 }, +/* 0x4806 */ { false, 0x4806, 0x4806 }, +/* 0x4807 */ { false, 0x4807, 0x4807 }, +/* 0x4808 */ { false, 0x4808, 0x4808 }, +/* 0x4809 */ { false, 0x4809, 0x4809 }, +/* 0x480a */ { false, 0x480a, 0x480a }, +/* 0x480b */ { false, 0x480b, 0x480b }, +/* 0x480c */ { false, 0x480c, 0x480c }, +/* 0x480d */ { false, 0x480d, 0x480d }, +/* 0x480e */ { false, 0x480e, 0x480e }, +/* 0x480f */ { false, 0x480f, 0x480f }, +/* 0x4810 */ { false, 0x4810, 0x4810 }, +/* 0x4811 */ { false, 0x4811, 0x4811 }, +/* 0x4812 */ { false, 0x4812, 0x4812 }, +/* 0x4813 */ { false, 0x4813, 0x4813 }, +/* 0x4814 */ { false, 0x4814, 0x4814 }, +/* 0x4815 */ { false, 0x4815, 0x4815 }, +/* 0x4816 */ { false, 0x4816, 0x4816 }, +/* 0x4817 */ { false, 0x4817, 0x4817 }, +/* 0x4818 */ { false, 0x4818, 0x4818 }, +/* 0x4819 */ { false, 0x4819, 0x4819 }, +/* 0x481a */ { false, 0x481a, 0x481a }, +/* 0x481b */ { false, 0x481b, 0x481b }, +/* 0x481c */ { false, 0x481c, 0x481c }, +/* 0x481d */ { false, 0x481d, 0x481d }, +/* 0x481e */ { false, 0x481e, 0x481e }, +/* 0x481f */ { false, 0x481f, 0x481f }, +/* 0x4820 */ { false, 0x4820, 0x4820 }, +/* 0x4821 */ { false, 0x4821, 0x4821 }, +/* 0x4822 */ { false, 0x4822, 0x4822 }, +/* 0x4823 */ { false, 0x4823, 0x4823 }, +/* 0x4824 */ { false, 0x4824, 0x4824 }, +/* 0x4825 */ { false, 0x4825, 0x4825 }, +/* 0x4826 */ { false, 0x4826, 0x4826 }, +/* 0x4827 */ { false, 0x4827, 0x4827 }, +/* 0x4828 */ { false, 0x4828, 0x4828 }, +/* 0x4829 */ { false, 0x4829, 0x4829 }, +/* 0x482a */ { false, 0x482a, 0x482a }, +/* 0x482b */ { false, 0x482b, 0x482b }, +/* 0x482c */ { false, 0x482c, 0x482c }, +/* 0x482d */ { false, 0x482d, 0x482d }, +/* 0x482e */ { false, 0x482e, 0x482e }, +/* 0x482f */ { false, 0x482f, 0x482f }, +/* 0x4830 */ { false, 0x4830, 0x4830 }, +/* 0x4831 */ { false, 0x4831, 0x4831 }, +/* 0x4832 */ { false, 0x4832, 0x4832 }, +/* 0x4833 */ { false, 0x4833, 0x4833 }, +/* 0x4834 */ { false, 0x4834, 0x4834 }, +/* 0x4835 */ { false, 0x4835, 0x4835 }, +/* 0x4836 */ { false, 0x4836, 0x4836 }, +/* 0x4837 */ { false, 0x4837, 0x4837 }, +/* 0x4838 */ { false, 0x4838, 0x4838 }, +/* 0x4839 */ { false, 0x4839, 0x4839 }, +/* 0x483a */ { false, 0x483a, 0x483a }, +/* 0x483b */ { false, 0x483b, 0x483b }, +/* 0x483c */ { false, 0x483c, 0x483c }, +/* 0x483d */ { false, 0x483d, 0x483d }, +/* 0x483e */ { false, 0x483e, 0x483e }, +/* 0x483f */ { false, 0x483f, 0x483f }, +/* 0x4840 */ { false, 0x4840, 0x4840 }, +/* 0x4841 */ { false, 0x4841, 0x4841 }, +/* 0x4842 */ { false, 0x4842, 0x4842 }, +/* 0x4843 */ { false, 0x4843, 0x4843 }, +/* 0x4844 */ { false, 0x4844, 0x4844 }, +/* 0x4845 */ { false, 0x4845, 0x4845 }, +/* 0x4846 */ { false, 0x4846, 0x4846 }, +/* 0x4847 */ { false, 0x4847, 0x4847 }, +/* 0x4848 */ { false, 0x4848, 0x4848 }, +/* 0x4849 */ { false, 0x4849, 0x4849 }, +/* 0x484a */ { false, 0x484a, 0x484a }, +/* 0x484b */ { false, 0x484b, 0x484b }, +/* 0x484c */ { false, 0x484c, 0x484c }, +/* 0x484d */ { false, 0x484d, 0x484d }, +/* 0x484e */ { false, 0x484e, 0x484e }, +/* 0x484f */ { false, 0x484f, 0x484f }, +/* 0x4850 */ { false, 0x4850, 0x4850 }, +/* 0x4851 */ { false, 0x4851, 0x4851 }, +/* 0x4852 */ { false, 0x4852, 0x4852 }, +/* 0x4853 */ { false, 0x4853, 0x4853 }, +/* 0x4854 */ { false, 0x4854, 0x4854 }, +/* 0x4855 */ { false, 0x4855, 0x4855 }, +/* 0x4856 */ { false, 0x4856, 0x4856 }, +/* 0x4857 */ { false, 0x4857, 0x4857 }, +/* 0x4858 */ { false, 0x4858, 0x4858 }, +/* 0x4859 */ { false, 0x4859, 0x4859 }, +/* 0x485a */ { false, 0x485a, 0x485a }, +/* 0x485b */ { false, 0x485b, 0x485b }, +/* 0x485c */ { false, 0x485c, 0x485c }, +/* 0x485d */ { false, 0x485d, 0x485d }, +/* 0x485e */ { false, 0x485e, 0x485e }, +/* 0x485f */ { false, 0x485f, 0x485f }, +/* 0x4860 */ { false, 0x4860, 0x4860 }, +/* 0x4861 */ { false, 0x4861, 0x4861 }, +/* 0x4862 */ { false, 0x4862, 0x4862 }, +/* 0x4863 */ { false, 0x4863, 0x4863 }, +/* 0x4864 */ { false, 0x4864, 0x4864 }, +/* 0x4865 */ { false, 0x4865, 0x4865 }, +/* 0x4866 */ { false, 0x4866, 0x4866 }, +/* 0x4867 */ { false, 0x4867, 0x4867 }, +/* 0x4868 */ { false, 0x4868, 0x4868 }, +/* 0x4869 */ { false, 0x4869, 0x4869 }, +/* 0x486a */ { false, 0x486a, 0x486a }, +/* 0x486b */ { false, 0x486b, 0x486b }, +/* 0x486c */ { false, 0x486c, 0x486c }, +/* 0x486d */ { false, 0x486d, 0x486d }, +/* 0x486e */ { false, 0x486e, 0x486e }, +/* 0x486f */ { false, 0x486f, 0x486f }, +/* 0x4870 */ { false, 0x4870, 0x4870 }, +/* 0x4871 */ { false, 0x4871, 0x4871 }, +/* 0x4872 */ { false, 0x4872, 0x4872 }, +/* 0x4873 */ { false, 0x4873, 0x4873 }, +/* 0x4874 */ { false, 0x4874, 0x4874 }, +/* 0x4875 */ { false, 0x4875, 0x4875 }, +/* 0x4876 */ { false, 0x4876, 0x4876 }, +/* 0x4877 */ { false, 0x4877, 0x4877 }, +/* 0x4878 */ { false, 0x4878, 0x4878 }, +/* 0x4879 */ { false, 0x4879, 0x4879 }, +/* 0x487a */ { false, 0x487a, 0x487a }, +/* 0x487b */ { false, 0x487b, 0x487b }, +/* 0x487c */ { false, 0x487c, 0x487c }, +/* 0x487d */ { false, 0x487d, 0x487d }, +/* 0x487e */ { false, 0x487e, 0x487e }, +/* 0x487f */ { false, 0x487f, 0x487f }, +/* 0x4880 */ { false, 0x4880, 0x4880 }, +/* 0x4881 */ { false, 0x4881, 0x4881 }, +/* 0x4882 */ { false, 0x4882, 0x4882 }, +/* 0x4883 */ { false, 0x4883, 0x4883 }, +/* 0x4884 */ { false, 0x4884, 0x4884 }, +/* 0x4885 */ { false, 0x4885, 0x4885 }, +/* 0x4886 */ { false, 0x4886, 0x4886 }, +/* 0x4887 */ { false, 0x4887, 0x4887 }, +/* 0x4888 */ { false, 0x4888, 0x4888 }, +/* 0x4889 */ { false, 0x4889, 0x4889 }, +/* 0x488a */ { false, 0x488a, 0x488a }, +/* 0x488b */ { false, 0x488b, 0x488b }, +/* 0x488c */ { false, 0x488c, 0x488c }, +/* 0x488d */ { false, 0x488d, 0x488d }, +/* 0x488e */ { false, 0x488e, 0x488e }, +/* 0x488f */ { false, 0x488f, 0x488f }, +/* 0x4890 */ { false, 0x4890, 0x4890 }, +/* 0x4891 */ { false, 0x4891, 0x4891 }, +/* 0x4892 */ { false, 0x4892, 0x4892 }, +/* 0x4893 */ { false, 0x4893, 0x4893 }, +/* 0x4894 */ { false, 0x4894, 0x4894 }, +/* 0x4895 */ { false, 0x4895, 0x4895 }, +/* 0x4896 */ { false, 0x4896, 0x4896 }, +/* 0x4897 */ { false, 0x4897, 0x4897 }, +/* 0x4898 */ { false, 0x4898, 0x4898 }, +/* 0x4899 */ { false, 0x4899, 0x4899 }, +/* 0x489a */ { false, 0x489a, 0x489a }, +/* 0x489b */ { false, 0x489b, 0x489b }, +/* 0x489c */ { false, 0x489c, 0x489c }, +/* 0x489d */ { false, 0x489d, 0x489d }, +/* 0x489e */ { false, 0x489e, 0x489e }, +/* 0x489f */ { false, 0x489f, 0x489f }, +/* 0x48a0 */ { false, 0x48a0, 0x48a0 }, +/* 0x48a1 */ { false, 0x48a1, 0x48a1 }, +/* 0x48a2 */ { false, 0x48a2, 0x48a2 }, +/* 0x48a3 */ { false, 0x48a3, 0x48a3 }, +/* 0x48a4 */ { false, 0x48a4, 0x48a4 }, +/* 0x48a5 */ { false, 0x48a5, 0x48a5 }, +/* 0x48a6 */ { false, 0x48a6, 0x48a6 }, +/* 0x48a7 */ { false, 0x48a7, 0x48a7 }, +/* 0x48a8 */ { false, 0x48a8, 0x48a8 }, +/* 0x48a9 */ { false, 0x48a9, 0x48a9 }, +/* 0x48aa */ { false, 0x48aa, 0x48aa }, +/* 0x48ab */ { false, 0x48ab, 0x48ab }, +/* 0x48ac */ { false, 0x48ac, 0x48ac }, +/* 0x48ad */ { false, 0x48ad, 0x48ad }, +/* 0x48ae */ { false, 0x48ae, 0x48ae }, +/* 0x48af */ { false, 0x48af, 0x48af }, +/* 0x48b0 */ { false, 0x48b0, 0x48b0 }, +/* 0x48b1 */ { false, 0x48b1, 0x48b1 }, +/* 0x48b2 */ { false, 0x48b2, 0x48b2 }, +/* 0x48b3 */ { false, 0x48b3, 0x48b3 }, +/* 0x48b4 */ { false, 0x48b4, 0x48b4 }, +/* 0x48b5 */ { false, 0x48b5, 0x48b5 }, +/* 0x48b6 */ { false, 0x48b6, 0x48b6 }, +/* 0x48b7 */ { false, 0x48b7, 0x48b7 }, +/* 0x48b8 */ { false, 0x48b8, 0x48b8 }, +/* 0x48b9 */ { false, 0x48b9, 0x48b9 }, +/* 0x48ba */ { false, 0x48ba, 0x48ba }, +/* 0x48bb */ { false, 0x48bb, 0x48bb }, +/* 0x48bc */ { false, 0x48bc, 0x48bc }, +/* 0x48bd */ { false, 0x48bd, 0x48bd }, +/* 0x48be */ { false, 0x48be, 0x48be }, +/* 0x48bf */ { false, 0x48bf, 0x48bf }, +/* 0x48c0 */ { false, 0x48c0, 0x48c0 }, +/* 0x48c1 */ { false, 0x48c1, 0x48c1 }, +/* 0x48c2 */ { false, 0x48c2, 0x48c2 }, +/* 0x48c3 */ { false, 0x48c3, 0x48c3 }, +/* 0x48c4 */ { false, 0x48c4, 0x48c4 }, +/* 0x48c5 */ { false, 0x48c5, 0x48c5 }, +/* 0x48c6 */ { false, 0x48c6, 0x48c6 }, +/* 0x48c7 */ { false, 0x48c7, 0x48c7 }, +/* 0x48c8 */ { false, 0x48c8, 0x48c8 }, +/* 0x48c9 */ { false, 0x48c9, 0x48c9 }, +/* 0x48ca */ { false, 0x48ca, 0x48ca }, +/* 0x48cb */ { false, 0x48cb, 0x48cb }, +/* 0x48cc */ { false, 0x48cc, 0x48cc }, +/* 0x48cd */ { false, 0x48cd, 0x48cd }, +/* 0x48ce */ { false, 0x48ce, 0x48ce }, +/* 0x48cf */ { false, 0x48cf, 0x48cf }, +/* 0x48d0 */ { false, 0x48d0, 0x48d0 }, +/* 0x48d1 */ { false, 0x48d1, 0x48d1 }, +/* 0x48d2 */ { false, 0x48d2, 0x48d2 }, +/* 0x48d3 */ { false, 0x48d3, 0x48d3 }, +/* 0x48d4 */ { false, 0x48d4, 0x48d4 }, +/* 0x48d5 */ { false, 0x48d5, 0x48d5 }, +/* 0x48d6 */ { false, 0x48d6, 0x48d6 }, +/* 0x48d7 */ { false, 0x48d7, 0x48d7 }, +/* 0x48d8 */ { false, 0x48d8, 0x48d8 }, +/* 0x48d9 */ { false, 0x48d9, 0x48d9 }, +/* 0x48da */ { false, 0x48da, 0x48da }, +/* 0x48db */ { false, 0x48db, 0x48db }, +/* 0x48dc */ { false, 0x48dc, 0x48dc }, +/* 0x48dd */ { false, 0x48dd, 0x48dd }, +/* 0x48de */ { false, 0x48de, 0x48de }, +/* 0x48df */ { false, 0x48df, 0x48df }, +/* 0x48e0 */ { false, 0x48e0, 0x48e0 }, +/* 0x48e1 */ { false, 0x48e1, 0x48e1 }, +/* 0x48e2 */ { false, 0x48e2, 0x48e2 }, +/* 0x48e3 */ { false, 0x48e3, 0x48e3 }, +/* 0x48e4 */ { false, 0x48e4, 0x48e4 }, +/* 0x48e5 */ { false, 0x48e5, 0x48e5 }, +/* 0x48e6 */ { false, 0x48e6, 0x48e6 }, +/* 0x48e7 */ { false, 0x48e7, 0x48e7 }, +/* 0x48e8 */ { false, 0x48e8, 0x48e8 }, +/* 0x48e9 */ { false, 0x48e9, 0x48e9 }, +/* 0x48ea */ { false, 0x48ea, 0x48ea }, +/* 0x48eb */ { false, 0x48eb, 0x48eb }, +/* 0x48ec */ { false, 0x48ec, 0x48ec }, +/* 0x48ed */ { false, 0x48ed, 0x48ed }, +/* 0x48ee */ { false, 0x48ee, 0x48ee }, +/* 0x48ef */ { false, 0x48ef, 0x48ef }, +/* 0x48f0 */ { false, 0x48f0, 0x48f0 }, +/* 0x48f1 */ { false, 0x48f1, 0x48f1 }, +/* 0x48f2 */ { false, 0x48f2, 0x48f2 }, +/* 0x48f3 */ { false, 0x48f3, 0x48f3 }, +/* 0x48f4 */ { false, 0x48f4, 0x48f4 }, +/* 0x48f5 */ { false, 0x48f5, 0x48f5 }, +/* 0x48f6 */ { false, 0x48f6, 0x48f6 }, +/* 0x48f7 */ { false, 0x48f7, 0x48f7 }, +/* 0x48f8 */ { false, 0x48f8, 0x48f8 }, +/* 0x48f9 */ { false, 0x48f9, 0x48f9 }, +/* 0x48fa */ { false, 0x48fa, 0x48fa }, +/* 0x48fb */ { false, 0x48fb, 0x48fb }, +/* 0x48fc */ { false, 0x48fc, 0x48fc }, +/* 0x48fd */ { false, 0x48fd, 0x48fd }, +/* 0x48fe */ { false, 0x48fe, 0x48fe }, +/* 0x48ff */ { false, 0x48ff, 0x48ff }, +/* 0x4900 */ { false, 0x4900, 0x4900 }, +/* 0x4901 */ { false, 0x4901, 0x4901 }, +/* 0x4902 */ { false, 0x4902, 0x4902 }, +/* 0x4903 */ { false, 0x4903, 0x4903 }, +/* 0x4904 */ { false, 0x4904, 0x4904 }, +/* 0x4905 */ { false, 0x4905, 0x4905 }, +/* 0x4906 */ { false, 0x4906, 0x4906 }, +/* 0x4907 */ { false, 0x4907, 0x4907 }, +/* 0x4908 */ { false, 0x4908, 0x4908 }, +/* 0x4909 */ { false, 0x4909, 0x4909 }, +/* 0x490a */ { false, 0x490a, 0x490a }, +/* 0x490b */ { false, 0x490b, 0x490b }, +/* 0x490c */ { false, 0x490c, 0x490c }, +/* 0x490d */ { false, 0x490d, 0x490d }, +/* 0x490e */ { false, 0x490e, 0x490e }, +/* 0x490f */ { false, 0x490f, 0x490f }, +/* 0x4910 */ { false, 0x4910, 0x4910 }, +/* 0x4911 */ { false, 0x4911, 0x4911 }, +/* 0x4912 */ { false, 0x4912, 0x4912 }, +/* 0x4913 */ { false, 0x4913, 0x4913 }, +/* 0x4914 */ { false, 0x4914, 0x4914 }, +/* 0x4915 */ { false, 0x4915, 0x4915 }, +/* 0x4916 */ { false, 0x4916, 0x4916 }, +/* 0x4917 */ { false, 0x4917, 0x4917 }, +/* 0x4918 */ { false, 0x4918, 0x4918 }, +/* 0x4919 */ { false, 0x4919, 0x4919 }, +/* 0x491a */ { false, 0x491a, 0x491a }, +/* 0x491b */ { false, 0x491b, 0x491b }, +/* 0x491c */ { false, 0x491c, 0x491c }, +/* 0x491d */ { false, 0x491d, 0x491d }, +/* 0x491e */ { false, 0x491e, 0x491e }, +/* 0x491f */ { false, 0x491f, 0x491f }, +/* 0x4920 */ { false, 0x4920, 0x4920 }, +/* 0x4921 */ { false, 0x4921, 0x4921 }, +/* 0x4922 */ { false, 0x4922, 0x4922 }, +/* 0x4923 */ { false, 0x4923, 0x4923 }, +/* 0x4924 */ { false, 0x4924, 0x4924 }, +/* 0x4925 */ { false, 0x4925, 0x4925 }, +/* 0x4926 */ { false, 0x4926, 0x4926 }, +/* 0x4927 */ { false, 0x4927, 0x4927 }, +/* 0x4928 */ { false, 0x4928, 0x4928 }, +/* 0x4929 */ { false, 0x4929, 0x4929 }, +/* 0x492a */ { false, 0x492a, 0x492a }, +/* 0x492b */ { false, 0x492b, 0x492b }, +/* 0x492c */ { false, 0x492c, 0x492c }, +/* 0x492d */ { false, 0x492d, 0x492d }, +/* 0x492e */ { false, 0x492e, 0x492e }, +/* 0x492f */ { false, 0x492f, 0x492f }, +/* 0x4930 */ { false, 0x4930, 0x4930 }, +/* 0x4931 */ { false, 0x4931, 0x4931 }, +/* 0x4932 */ { false, 0x4932, 0x4932 }, +/* 0x4933 */ { false, 0x4933, 0x4933 }, +/* 0x4934 */ { false, 0x4934, 0x4934 }, +/* 0x4935 */ { false, 0x4935, 0x4935 }, +/* 0x4936 */ { false, 0x4936, 0x4936 }, +/* 0x4937 */ { false, 0x4937, 0x4937 }, +/* 0x4938 */ { false, 0x4938, 0x4938 }, +/* 0x4939 */ { false, 0x4939, 0x4939 }, +/* 0x493a */ { false, 0x493a, 0x493a }, +/* 0x493b */ { false, 0x493b, 0x493b }, +/* 0x493c */ { false, 0x493c, 0x493c }, +/* 0x493d */ { false, 0x493d, 0x493d }, +/* 0x493e */ { false, 0x493e, 0x493e }, +/* 0x493f */ { false, 0x493f, 0x493f }, +/* 0x4940 */ { false, 0x4940, 0x4940 }, +/* 0x4941 */ { false, 0x4941, 0x4941 }, +/* 0x4942 */ { false, 0x4942, 0x4942 }, +/* 0x4943 */ { false, 0x4943, 0x4943 }, +/* 0x4944 */ { false, 0x4944, 0x4944 }, +/* 0x4945 */ { false, 0x4945, 0x4945 }, +/* 0x4946 */ { false, 0x4946, 0x4946 }, +/* 0x4947 */ { false, 0x4947, 0x4947 }, +/* 0x4948 */ { false, 0x4948, 0x4948 }, +/* 0x4949 */ { false, 0x4949, 0x4949 }, +/* 0x494a */ { false, 0x494a, 0x494a }, +/* 0x494b */ { false, 0x494b, 0x494b }, +/* 0x494c */ { false, 0x494c, 0x494c }, +/* 0x494d */ { false, 0x494d, 0x494d }, +/* 0x494e */ { false, 0x494e, 0x494e }, +/* 0x494f */ { false, 0x494f, 0x494f }, +/* 0x4950 */ { false, 0x4950, 0x4950 }, +/* 0x4951 */ { false, 0x4951, 0x4951 }, +/* 0x4952 */ { false, 0x4952, 0x4952 }, +/* 0x4953 */ { false, 0x4953, 0x4953 }, +/* 0x4954 */ { false, 0x4954, 0x4954 }, +/* 0x4955 */ { false, 0x4955, 0x4955 }, +/* 0x4956 */ { false, 0x4956, 0x4956 }, +/* 0x4957 */ { false, 0x4957, 0x4957 }, +/* 0x4958 */ { false, 0x4958, 0x4958 }, +/* 0x4959 */ { false, 0x4959, 0x4959 }, +/* 0x495a */ { false, 0x495a, 0x495a }, +/* 0x495b */ { false, 0x495b, 0x495b }, +/* 0x495c */ { false, 0x495c, 0x495c }, +/* 0x495d */ { false, 0x495d, 0x495d }, +/* 0x495e */ { false, 0x495e, 0x495e }, +/* 0x495f */ { false, 0x495f, 0x495f }, +/* 0x4960 */ { false, 0x4960, 0x4960 }, +/* 0x4961 */ { false, 0x4961, 0x4961 }, +/* 0x4962 */ { false, 0x4962, 0x4962 }, +/* 0x4963 */ { false, 0x4963, 0x4963 }, +/* 0x4964 */ { false, 0x4964, 0x4964 }, +/* 0x4965 */ { false, 0x4965, 0x4965 }, +/* 0x4966 */ { false, 0x4966, 0x4966 }, +/* 0x4967 */ { false, 0x4967, 0x4967 }, +/* 0x4968 */ { false, 0x4968, 0x4968 }, +/* 0x4969 */ { false, 0x4969, 0x4969 }, +/* 0x496a */ { false, 0x496a, 0x496a }, +/* 0x496b */ { false, 0x496b, 0x496b }, +/* 0x496c */ { false, 0x496c, 0x496c }, +/* 0x496d */ { false, 0x496d, 0x496d }, +/* 0x496e */ { false, 0x496e, 0x496e }, +/* 0x496f */ { false, 0x496f, 0x496f }, +/* 0x4970 */ { false, 0x4970, 0x4970 }, +/* 0x4971 */ { false, 0x4971, 0x4971 }, +/* 0x4972 */ { false, 0x4972, 0x4972 }, +/* 0x4973 */ { false, 0x4973, 0x4973 }, +/* 0x4974 */ { false, 0x4974, 0x4974 }, +/* 0x4975 */ { false, 0x4975, 0x4975 }, +/* 0x4976 */ { false, 0x4976, 0x4976 }, +/* 0x4977 */ { false, 0x4977, 0x4977 }, +/* 0x4978 */ { false, 0x4978, 0x4978 }, +/* 0x4979 */ { false, 0x4979, 0x4979 }, +/* 0x497a */ { false, 0x497a, 0x497a }, +/* 0x497b */ { false, 0x497b, 0x497b }, +/* 0x497c */ { false, 0x497c, 0x497c }, +/* 0x497d */ { false, 0x497d, 0x497d }, +/* 0x497e */ { false, 0x497e, 0x497e }, +/* 0x497f */ { false, 0x497f, 0x497f }, +/* 0x4980 */ { false, 0x4980, 0x4980 }, +/* 0x4981 */ { false, 0x4981, 0x4981 }, +/* 0x4982 */ { false, 0x4982, 0x4982 }, +/* 0x4983 */ { false, 0x4983, 0x4983 }, +/* 0x4984 */ { false, 0x4984, 0x4984 }, +/* 0x4985 */ { false, 0x4985, 0x4985 }, +/* 0x4986 */ { false, 0x4986, 0x4986 }, +/* 0x4987 */ { false, 0x4987, 0x4987 }, +/* 0x4988 */ { false, 0x4988, 0x4988 }, +/* 0x4989 */ { false, 0x4989, 0x4989 }, +/* 0x498a */ { false, 0x498a, 0x498a }, +/* 0x498b */ { false, 0x498b, 0x498b }, +/* 0x498c */ { false, 0x498c, 0x498c }, +/* 0x498d */ { false, 0x498d, 0x498d }, +/* 0x498e */ { false, 0x498e, 0x498e }, +/* 0x498f */ { false, 0x498f, 0x498f }, +/* 0x4990 */ { false, 0x4990, 0x4990 }, +/* 0x4991 */ { false, 0x4991, 0x4991 }, +/* 0x4992 */ { false, 0x4992, 0x4992 }, +/* 0x4993 */ { false, 0x4993, 0x4993 }, +/* 0x4994 */ { false, 0x4994, 0x4994 }, +/* 0x4995 */ { false, 0x4995, 0x4995 }, +/* 0x4996 */ { false, 0x4996, 0x4996 }, +/* 0x4997 */ { false, 0x4997, 0x4997 }, +/* 0x4998 */ { false, 0x4998, 0x4998 }, +/* 0x4999 */ { false, 0x4999, 0x4999 }, +/* 0x499a */ { false, 0x499a, 0x499a }, +/* 0x499b */ { false, 0x499b, 0x499b }, +/* 0x499c */ { false, 0x499c, 0x499c }, +/* 0x499d */ { false, 0x499d, 0x499d }, +/* 0x499e */ { false, 0x499e, 0x499e }, +/* 0x499f */ { false, 0x499f, 0x499f }, +/* 0x49a0 */ { false, 0x49a0, 0x49a0 }, +/* 0x49a1 */ { false, 0x49a1, 0x49a1 }, +/* 0x49a2 */ { false, 0x49a2, 0x49a2 }, +/* 0x49a3 */ { false, 0x49a3, 0x49a3 }, +/* 0x49a4 */ { false, 0x49a4, 0x49a4 }, +/* 0x49a5 */ { false, 0x49a5, 0x49a5 }, +/* 0x49a6 */ { false, 0x49a6, 0x49a6 }, +/* 0x49a7 */ { false, 0x49a7, 0x49a7 }, +/* 0x49a8 */ { false, 0x49a8, 0x49a8 }, +/* 0x49a9 */ { false, 0x49a9, 0x49a9 }, +/* 0x49aa */ { false, 0x49aa, 0x49aa }, +/* 0x49ab */ { false, 0x49ab, 0x49ab }, +/* 0x49ac */ { false, 0x49ac, 0x49ac }, +/* 0x49ad */ { false, 0x49ad, 0x49ad }, +/* 0x49ae */ { false, 0x49ae, 0x49ae }, +/* 0x49af */ { false, 0x49af, 0x49af }, +/* 0x49b0 */ { false, 0x49b0, 0x49b0 }, +/* 0x49b1 */ { false, 0x49b1, 0x49b1 }, +/* 0x49b2 */ { false, 0x49b2, 0x49b2 }, +/* 0x49b3 */ { false, 0x49b3, 0x49b3 }, +/* 0x49b4 */ { false, 0x49b4, 0x49b4 }, +/* 0x49b5 */ { false, 0x49b5, 0x49b5 }, +/* 0x49b6 */ { false, 0x49b6, 0x49b6 }, +/* 0x49b7 */ { false, 0x49b7, 0x49b7 }, +/* 0x49b8 */ { false, 0x49b8, 0x49b8 }, +/* 0x49b9 */ { false, 0x49b9, 0x49b9 }, +/* 0x49ba */ { false, 0x49ba, 0x49ba }, +/* 0x49bb */ { false, 0x49bb, 0x49bb }, +/* 0x49bc */ { false, 0x49bc, 0x49bc }, +/* 0x49bd */ { false, 0x49bd, 0x49bd }, +/* 0x49be */ { false, 0x49be, 0x49be }, +/* 0x49bf */ { false, 0x49bf, 0x49bf }, +/* 0x49c0 */ { false, 0x49c0, 0x49c0 }, +/* 0x49c1 */ { false, 0x49c1, 0x49c1 }, +/* 0x49c2 */ { false, 0x49c2, 0x49c2 }, +/* 0x49c3 */ { false, 0x49c3, 0x49c3 }, +/* 0x49c4 */ { false, 0x49c4, 0x49c4 }, +/* 0x49c5 */ { false, 0x49c5, 0x49c5 }, +/* 0x49c6 */ { false, 0x49c6, 0x49c6 }, +/* 0x49c7 */ { false, 0x49c7, 0x49c7 }, +/* 0x49c8 */ { false, 0x49c8, 0x49c8 }, +/* 0x49c9 */ { false, 0x49c9, 0x49c9 }, +/* 0x49ca */ { false, 0x49ca, 0x49ca }, +/* 0x49cb */ { false, 0x49cb, 0x49cb }, +/* 0x49cc */ { false, 0x49cc, 0x49cc }, +/* 0x49cd */ { false, 0x49cd, 0x49cd }, +/* 0x49ce */ { false, 0x49ce, 0x49ce }, +/* 0x49cf */ { false, 0x49cf, 0x49cf }, +/* 0x49d0 */ { false, 0x49d0, 0x49d0 }, +/* 0x49d1 */ { false, 0x49d1, 0x49d1 }, +/* 0x49d2 */ { false, 0x49d2, 0x49d2 }, +/* 0x49d3 */ { false, 0x49d3, 0x49d3 }, +/* 0x49d4 */ { false, 0x49d4, 0x49d4 }, +/* 0x49d5 */ { false, 0x49d5, 0x49d5 }, +/* 0x49d6 */ { false, 0x49d6, 0x49d6 }, +/* 0x49d7 */ { false, 0x49d7, 0x49d7 }, +/* 0x49d8 */ { false, 0x49d8, 0x49d8 }, +/* 0x49d9 */ { false, 0x49d9, 0x49d9 }, +/* 0x49da */ { false, 0x49da, 0x49da }, +/* 0x49db */ { false, 0x49db, 0x49db }, +/* 0x49dc */ { false, 0x49dc, 0x49dc }, +/* 0x49dd */ { false, 0x49dd, 0x49dd }, +/* 0x49de */ { false, 0x49de, 0x49de }, +/* 0x49df */ { false, 0x49df, 0x49df }, +/* 0x49e0 */ { false, 0x49e0, 0x49e0 }, +/* 0x49e1 */ { false, 0x49e1, 0x49e1 }, +/* 0x49e2 */ { false, 0x49e2, 0x49e2 }, +/* 0x49e3 */ { false, 0x49e3, 0x49e3 }, +/* 0x49e4 */ { false, 0x49e4, 0x49e4 }, +/* 0x49e5 */ { false, 0x49e5, 0x49e5 }, +/* 0x49e6 */ { false, 0x49e6, 0x49e6 }, +/* 0x49e7 */ { false, 0x49e7, 0x49e7 }, +/* 0x49e8 */ { false, 0x49e8, 0x49e8 }, +/* 0x49e9 */ { false, 0x49e9, 0x49e9 }, +/* 0x49ea */ { false, 0x49ea, 0x49ea }, +/* 0x49eb */ { false, 0x49eb, 0x49eb }, +/* 0x49ec */ { false, 0x49ec, 0x49ec }, +/* 0x49ed */ { false, 0x49ed, 0x49ed }, +/* 0x49ee */ { false, 0x49ee, 0x49ee }, +/* 0x49ef */ { false, 0x49ef, 0x49ef }, +/* 0x49f0 */ { false, 0x49f0, 0x49f0 }, +/* 0x49f1 */ { false, 0x49f1, 0x49f1 }, +/* 0x49f2 */ { false, 0x49f2, 0x49f2 }, +/* 0x49f3 */ { false, 0x49f3, 0x49f3 }, +/* 0x49f4 */ { false, 0x49f4, 0x49f4 }, +/* 0x49f5 */ { false, 0x49f5, 0x49f5 }, +/* 0x49f6 */ { false, 0x49f6, 0x49f6 }, +/* 0x49f7 */ { false, 0x49f7, 0x49f7 }, +/* 0x49f8 */ { false, 0x49f8, 0x49f8 }, +/* 0x49f9 */ { false, 0x49f9, 0x49f9 }, +/* 0x49fa */ { false, 0x49fa, 0x49fa }, +/* 0x49fb */ { false, 0x49fb, 0x49fb }, +/* 0x49fc */ { false, 0x49fc, 0x49fc }, +/* 0x49fd */ { false, 0x49fd, 0x49fd }, +/* 0x49fe */ { false, 0x49fe, 0x49fe }, +/* 0x49ff */ { false, 0x49ff, 0x49ff }, +/* 0x4a00 */ { false, 0x4a00, 0x4a00 }, +/* 0x4a01 */ { false, 0x4a01, 0x4a01 }, +/* 0x4a02 */ { false, 0x4a02, 0x4a02 }, +/* 0x4a03 */ { false, 0x4a03, 0x4a03 }, +/* 0x4a04 */ { false, 0x4a04, 0x4a04 }, +/* 0x4a05 */ { false, 0x4a05, 0x4a05 }, +/* 0x4a06 */ { false, 0x4a06, 0x4a06 }, +/* 0x4a07 */ { false, 0x4a07, 0x4a07 }, +/* 0x4a08 */ { false, 0x4a08, 0x4a08 }, +/* 0x4a09 */ { false, 0x4a09, 0x4a09 }, +/* 0x4a0a */ { false, 0x4a0a, 0x4a0a }, +/* 0x4a0b */ { false, 0x4a0b, 0x4a0b }, +/* 0x4a0c */ { false, 0x4a0c, 0x4a0c }, +/* 0x4a0d */ { false, 0x4a0d, 0x4a0d }, +/* 0x4a0e */ { false, 0x4a0e, 0x4a0e }, +/* 0x4a0f */ { false, 0x4a0f, 0x4a0f }, +/* 0x4a10 */ { false, 0x4a10, 0x4a10 }, +/* 0x4a11 */ { false, 0x4a11, 0x4a11 }, +/* 0x4a12 */ { false, 0x4a12, 0x4a12 }, +/* 0x4a13 */ { false, 0x4a13, 0x4a13 }, +/* 0x4a14 */ { false, 0x4a14, 0x4a14 }, +/* 0x4a15 */ { false, 0x4a15, 0x4a15 }, +/* 0x4a16 */ { false, 0x4a16, 0x4a16 }, +/* 0x4a17 */ { false, 0x4a17, 0x4a17 }, +/* 0x4a18 */ { false, 0x4a18, 0x4a18 }, +/* 0x4a19 */ { false, 0x4a19, 0x4a19 }, +/* 0x4a1a */ { false, 0x4a1a, 0x4a1a }, +/* 0x4a1b */ { false, 0x4a1b, 0x4a1b }, +/* 0x4a1c */ { false, 0x4a1c, 0x4a1c }, +/* 0x4a1d */ { false, 0x4a1d, 0x4a1d }, +/* 0x4a1e */ { false, 0x4a1e, 0x4a1e }, +/* 0x4a1f */ { false, 0x4a1f, 0x4a1f }, +/* 0x4a20 */ { false, 0x4a20, 0x4a20 }, +/* 0x4a21 */ { false, 0x4a21, 0x4a21 }, +/* 0x4a22 */ { false, 0x4a22, 0x4a22 }, +/* 0x4a23 */ { false, 0x4a23, 0x4a23 }, +/* 0x4a24 */ { false, 0x4a24, 0x4a24 }, +/* 0x4a25 */ { false, 0x4a25, 0x4a25 }, +/* 0x4a26 */ { false, 0x4a26, 0x4a26 }, +/* 0x4a27 */ { false, 0x4a27, 0x4a27 }, +/* 0x4a28 */ { false, 0x4a28, 0x4a28 }, +/* 0x4a29 */ { false, 0x4a29, 0x4a29 }, +/* 0x4a2a */ { false, 0x4a2a, 0x4a2a }, +/* 0x4a2b */ { false, 0x4a2b, 0x4a2b }, +/* 0x4a2c */ { false, 0x4a2c, 0x4a2c }, +/* 0x4a2d */ { false, 0x4a2d, 0x4a2d }, +/* 0x4a2e */ { false, 0x4a2e, 0x4a2e }, +/* 0x4a2f */ { false, 0x4a2f, 0x4a2f }, +/* 0x4a30 */ { false, 0x4a30, 0x4a30 }, +/* 0x4a31 */ { false, 0x4a31, 0x4a31 }, +/* 0x4a32 */ { false, 0x4a32, 0x4a32 }, +/* 0x4a33 */ { false, 0x4a33, 0x4a33 }, +/* 0x4a34 */ { false, 0x4a34, 0x4a34 }, +/* 0x4a35 */ { false, 0x4a35, 0x4a35 }, +/* 0x4a36 */ { false, 0x4a36, 0x4a36 }, +/* 0x4a37 */ { false, 0x4a37, 0x4a37 }, +/* 0x4a38 */ { false, 0x4a38, 0x4a38 }, +/* 0x4a39 */ { false, 0x4a39, 0x4a39 }, +/* 0x4a3a */ { false, 0x4a3a, 0x4a3a }, +/* 0x4a3b */ { false, 0x4a3b, 0x4a3b }, +/* 0x4a3c */ { false, 0x4a3c, 0x4a3c }, +/* 0x4a3d */ { false, 0x4a3d, 0x4a3d }, +/* 0x4a3e */ { false, 0x4a3e, 0x4a3e }, +/* 0x4a3f */ { false, 0x4a3f, 0x4a3f }, +/* 0x4a40 */ { false, 0x4a40, 0x4a40 }, +/* 0x4a41 */ { false, 0x4a41, 0x4a41 }, +/* 0x4a42 */ { false, 0x4a42, 0x4a42 }, +/* 0x4a43 */ { false, 0x4a43, 0x4a43 }, +/* 0x4a44 */ { false, 0x4a44, 0x4a44 }, +/* 0x4a45 */ { false, 0x4a45, 0x4a45 }, +/* 0x4a46 */ { false, 0x4a46, 0x4a46 }, +/* 0x4a47 */ { false, 0x4a47, 0x4a47 }, +/* 0x4a48 */ { false, 0x4a48, 0x4a48 }, +/* 0x4a49 */ { false, 0x4a49, 0x4a49 }, +/* 0x4a4a */ { false, 0x4a4a, 0x4a4a }, +/* 0x4a4b */ { false, 0x4a4b, 0x4a4b }, +/* 0x4a4c */ { false, 0x4a4c, 0x4a4c }, +/* 0x4a4d */ { false, 0x4a4d, 0x4a4d }, +/* 0x4a4e */ { false, 0x4a4e, 0x4a4e }, +/* 0x4a4f */ { false, 0x4a4f, 0x4a4f }, +/* 0x4a50 */ { false, 0x4a50, 0x4a50 }, +/* 0x4a51 */ { false, 0x4a51, 0x4a51 }, +/* 0x4a52 */ { false, 0x4a52, 0x4a52 }, +/* 0x4a53 */ { false, 0x4a53, 0x4a53 }, +/* 0x4a54 */ { false, 0x4a54, 0x4a54 }, +/* 0x4a55 */ { false, 0x4a55, 0x4a55 }, +/* 0x4a56 */ { false, 0x4a56, 0x4a56 }, +/* 0x4a57 */ { false, 0x4a57, 0x4a57 }, +/* 0x4a58 */ { false, 0x4a58, 0x4a58 }, +/* 0x4a59 */ { false, 0x4a59, 0x4a59 }, +/* 0x4a5a */ { false, 0x4a5a, 0x4a5a }, +/* 0x4a5b */ { false, 0x4a5b, 0x4a5b }, +/* 0x4a5c */ { false, 0x4a5c, 0x4a5c }, +/* 0x4a5d */ { false, 0x4a5d, 0x4a5d }, +/* 0x4a5e */ { false, 0x4a5e, 0x4a5e }, +/* 0x4a5f */ { false, 0x4a5f, 0x4a5f }, +/* 0x4a60 */ { false, 0x4a60, 0x4a60 }, +/* 0x4a61 */ { false, 0x4a61, 0x4a61 }, +/* 0x4a62 */ { false, 0x4a62, 0x4a62 }, +/* 0x4a63 */ { false, 0x4a63, 0x4a63 }, +/* 0x4a64 */ { false, 0x4a64, 0x4a64 }, +/* 0x4a65 */ { false, 0x4a65, 0x4a65 }, +/* 0x4a66 */ { false, 0x4a66, 0x4a66 }, +/* 0x4a67 */ { false, 0x4a67, 0x4a67 }, +/* 0x4a68 */ { false, 0x4a68, 0x4a68 }, +/* 0x4a69 */ { false, 0x4a69, 0x4a69 }, +/* 0x4a6a */ { false, 0x4a6a, 0x4a6a }, +/* 0x4a6b */ { false, 0x4a6b, 0x4a6b }, +/* 0x4a6c */ { false, 0x4a6c, 0x4a6c }, +/* 0x4a6d */ { false, 0x4a6d, 0x4a6d }, +/* 0x4a6e */ { false, 0x4a6e, 0x4a6e }, +/* 0x4a6f */ { false, 0x4a6f, 0x4a6f }, +/* 0x4a70 */ { false, 0x4a70, 0x4a70 }, +/* 0x4a71 */ { false, 0x4a71, 0x4a71 }, +/* 0x4a72 */ { false, 0x4a72, 0x4a72 }, +/* 0x4a73 */ { false, 0x4a73, 0x4a73 }, +/* 0x4a74 */ { false, 0x4a74, 0x4a74 }, +/* 0x4a75 */ { false, 0x4a75, 0x4a75 }, +/* 0x4a76 */ { false, 0x4a76, 0x4a76 }, +/* 0x4a77 */ { false, 0x4a77, 0x4a77 }, +/* 0x4a78 */ { false, 0x4a78, 0x4a78 }, +/* 0x4a79 */ { false, 0x4a79, 0x4a79 }, +/* 0x4a7a */ { false, 0x4a7a, 0x4a7a }, +/* 0x4a7b */ { false, 0x4a7b, 0x4a7b }, +/* 0x4a7c */ { false, 0x4a7c, 0x4a7c }, +/* 0x4a7d */ { false, 0x4a7d, 0x4a7d }, +/* 0x4a7e */ { false, 0x4a7e, 0x4a7e }, +/* 0x4a7f */ { false, 0x4a7f, 0x4a7f }, +/* 0x4a80 */ { false, 0x4a80, 0x4a80 }, +/* 0x4a81 */ { false, 0x4a81, 0x4a81 }, +/* 0x4a82 */ { false, 0x4a82, 0x4a82 }, +/* 0x4a83 */ { false, 0x4a83, 0x4a83 }, +/* 0x4a84 */ { false, 0x4a84, 0x4a84 }, +/* 0x4a85 */ { false, 0x4a85, 0x4a85 }, +/* 0x4a86 */ { false, 0x4a86, 0x4a86 }, +/* 0x4a87 */ { false, 0x4a87, 0x4a87 }, +/* 0x4a88 */ { false, 0x4a88, 0x4a88 }, +/* 0x4a89 */ { false, 0x4a89, 0x4a89 }, +/* 0x4a8a */ { false, 0x4a8a, 0x4a8a }, +/* 0x4a8b */ { false, 0x4a8b, 0x4a8b }, +/* 0x4a8c */ { false, 0x4a8c, 0x4a8c }, +/* 0x4a8d */ { false, 0x4a8d, 0x4a8d }, +/* 0x4a8e */ { false, 0x4a8e, 0x4a8e }, +/* 0x4a8f */ { false, 0x4a8f, 0x4a8f }, +/* 0x4a90 */ { false, 0x4a90, 0x4a90 }, +/* 0x4a91 */ { false, 0x4a91, 0x4a91 }, +/* 0x4a92 */ { false, 0x4a92, 0x4a92 }, +/* 0x4a93 */ { false, 0x4a93, 0x4a93 }, +/* 0x4a94 */ { false, 0x4a94, 0x4a94 }, +/* 0x4a95 */ { false, 0x4a95, 0x4a95 }, +/* 0x4a96 */ { false, 0x4a96, 0x4a96 }, +/* 0x4a97 */ { false, 0x4a97, 0x4a97 }, +/* 0x4a98 */ { false, 0x4a98, 0x4a98 }, +/* 0x4a99 */ { false, 0x4a99, 0x4a99 }, +/* 0x4a9a */ { false, 0x4a9a, 0x4a9a }, +/* 0x4a9b */ { false, 0x4a9b, 0x4a9b }, +/* 0x4a9c */ { false, 0x4a9c, 0x4a9c }, +/* 0x4a9d */ { false, 0x4a9d, 0x4a9d }, +/* 0x4a9e */ { false, 0x4a9e, 0x4a9e }, +/* 0x4a9f */ { false, 0x4a9f, 0x4a9f }, +/* 0x4aa0 */ { false, 0x4aa0, 0x4aa0 }, +/* 0x4aa1 */ { false, 0x4aa1, 0x4aa1 }, +/* 0x4aa2 */ { false, 0x4aa2, 0x4aa2 }, +/* 0x4aa3 */ { false, 0x4aa3, 0x4aa3 }, +/* 0x4aa4 */ { false, 0x4aa4, 0x4aa4 }, +/* 0x4aa5 */ { false, 0x4aa5, 0x4aa5 }, +/* 0x4aa6 */ { false, 0x4aa6, 0x4aa6 }, +/* 0x4aa7 */ { false, 0x4aa7, 0x4aa7 }, +/* 0x4aa8 */ { false, 0x4aa8, 0x4aa8 }, +/* 0x4aa9 */ { false, 0x4aa9, 0x4aa9 }, +/* 0x4aaa */ { false, 0x4aaa, 0x4aaa }, +/* 0x4aab */ { false, 0x4aab, 0x4aab }, +/* 0x4aac */ { false, 0x4aac, 0x4aac }, +/* 0x4aad */ { false, 0x4aad, 0x4aad }, +/* 0x4aae */ { false, 0x4aae, 0x4aae }, +/* 0x4aaf */ { false, 0x4aaf, 0x4aaf }, +/* 0x4ab0 */ { false, 0x4ab0, 0x4ab0 }, +/* 0x4ab1 */ { false, 0x4ab1, 0x4ab1 }, +/* 0x4ab2 */ { false, 0x4ab2, 0x4ab2 }, +/* 0x4ab3 */ { false, 0x4ab3, 0x4ab3 }, +/* 0x4ab4 */ { false, 0x4ab4, 0x4ab4 }, +/* 0x4ab5 */ { false, 0x4ab5, 0x4ab5 }, +/* 0x4ab6 */ { false, 0x4ab6, 0x4ab6 }, +/* 0x4ab7 */ { false, 0x4ab7, 0x4ab7 }, +/* 0x4ab8 */ { false, 0x4ab8, 0x4ab8 }, +/* 0x4ab9 */ { false, 0x4ab9, 0x4ab9 }, +/* 0x4aba */ { false, 0x4aba, 0x4aba }, +/* 0x4abb */ { false, 0x4abb, 0x4abb }, +/* 0x4abc */ { false, 0x4abc, 0x4abc }, +/* 0x4abd */ { false, 0x4abd, 0x4abd }, +/* 0x4abe */ { false, 0x4abe, 0x4abe }, +/* 0x4abf */ { false, 0x4abf, 0x4abf }, +/* 0x4ac0 */ { false, 0x4ac0, 0x4ac0 }, +/* 0x4ac1 */ { false, 0x4ac1, 0x4ac1 }, +/* 0x4ac2 */ { false, 0x4ac2, 0x4ac2 }, +/* 0x4ac3 */ { false, 0x4ac3, 0x4ac3 }, +/* 0x4ac4 */ { false, 0x4ac4, 0x4ac4 }, +/* 0x4ac5 */ { false, 0x4ac5, 0x4ac5 }, +/* 0x4ac6 */ { false, 0x4ac6, 0x4ac6 }, +/* 0x4ac7 */ { false, 0x4ac7, 0x4ac7 }, +/* 0x4ac8 */ { false, 0x4ac8, 0x4ac8 }, +/* 0x4ac9 */ { false, 0x4ac9, 0x4ac9 }, +/* 0x4aca */ { false, 0x4aca, 0x4aca }, +/* 0x4acb */ { false, 0x4acb, 0x4acb }, +/* 0x4acc */ { false, 0x4acc, 0x4acc }, +/* 0x4acd */ { false, 0x4acd, 0x4acd }, +/* 0x4ace */ { false, 0x4ace, 0x4ace }, +/* 0x4acf */ { false, 0x4acf, 0x4acf }, +/* 0x4ad0 */ { false, 0x4ad0, 0x4ad0 }, +/* 0x4ad1 */ { false, 0x4ad1, 0x4ad1 }, +/* 0x4ad2 */ { false, 0x4ad2, 0x4ad2 }, +/* 0x4ad3 */ { false, 0x4ad3, 0x4ad3 }, +/* 0x4ad4 */ { false, 0x4ad4, 0x4ad4 }, +/* 0x4ad5 */ { false, 0x4ad5, 0x4ad5 }, +/* 0x4ad6 */ { false, 0x4ad6, 0x4ad6 }, +/* 0x4ad7 */ { false, 0x4ad7, 0x4ad7 }, +/* 0x4ad8 */ { false, 0x4ad8, 0x4ad8 }, +/* 0x4ad9 */ { false, 0x4ad9, 0x4ad9 }, +/* 0x4ada */ { false, 0x4ada, 0x4ada }, +/* 0x4adb */ { false, 0x4adb, 0x4adb }, +/* 0x4adc */ { false, 0x4adc, 0x4adc }, +/* 0x4add */ { false, 0x4add, 0x4add }, +/* 0x4ade */ { false, 0x4ade, 0x4ade }, +/* 0x4adf */ { false, 0x4adf, 0x4adf }, +/* 0x4ae0 */ { false, 0x4ae0, 0x4ae0 }, +/* 0x4ae1 */ { false, 0x4ae1, 0x4ae1 }, +/* 0x4ae2 */ { false, 0x4ae2, 0x4ae2 }, +/* 0x4ae3 */ { false, 0x4ae3, 0x4ae3 }, +/* 0x4ae4 */ { false, 0x4ae4, 0x4ae4 }, +/* 0x4ae5 */ { false, 0x4ae5, 0x4ae5 }, +/* 0x4ae6 */ { false, 0x4ae6, 0x4ae6 }, +/* 0x4ae7 */ { false, 0x4ae7, 0x4ae7 }, +/* 0x4ae8 */ { false, 0x4ae8, 0x4ae8 }, +/* 0x4ae9 */ { false, 0x4ae9, 0x4ae9 }, +/* 0x4aea */ { false, 0x4aea, 0x4aea }, +/* 0x4aeb */ { false, 0x4aeb, 0x4aeb }, +/* 0x4aec */ { false, 0x4aec, 0x4aec }, +/* 0x4aed */ { false, 0x4aed, 0x4aed }, +/* 0x4aee */ { false, 0x4aee, 0x4aee }, +/* 0x4aef */ { false, 0x4aef, 0x4aef }, +/* 0x4af0 */ { false, 0x4af0, 0x4af0 }, +/* 0x4af1 */ { false, 0x4af1, 0x4af1 }, +/* 0x4af2 */ { false, 0x4af2, 0x4af2 }, +/* 0x4af3 */ { false, 0x4af3, 0x4af3 }, +/* 0x4af4 */ { false, 0x4af4, 0x4af4 }, +/* 0x4af5 */ { false, 0x4af5, 0x4af5 }, +/* 0x4af6 */ { false, 0x4af6, 0x4af6 }, +/* 0x4af7 */ { false, 0x4af7, 0x4af7 }, +/* 0x4af8 */ { false, 0x4af8, 0x4af8 }, +/* 0x4af9 */ { false, 0x4af9, 0x4af9 }, +/* 0x4afa */ { false, 0x4afa, 0x4afa }, +/* 0x4afb */ { false, 0x4afb, 0x4afb }, +/* 0x4afc */ { false, 0x4afc, 0x4afc }, +/* 0x4afd */ { false, 0x4afd, 0x4afd }, +/* 0x4afe */ { false, 0x4afe, 0x4afe }, +/* 0x4aff */ { false, 0x4aff, 0x4aff }, +/* 0x4b00 */ { false, 0x4b00, 0x4b00 }, +/* 0x4b01 */ { false, 0x4b01, 0x4b01 }, +/* 0x4b02 */ { false, 0x4b02, 0x4b02 }, +/* 0x4b03 */ { false, 0x4b03, 0x4b03 }, +/* 0x4b04 */ { false, 0x4b04, 0x4b04 }, +/* 0x4b05 */ { false, 0x4b05, 0x4b05 }, +/* 0x4b06 */ { false, 0x4b06, 0x4b06 }, +/* 0x4b07 */ { false, 0x4b07, 0x4b07 }, +/* 0x4b08 */ { false, 0x4b08, 0x4b08 }, +/* 0x4b09 */ { false, 0x4b09, 0x4b09 }, +/* 0x4b0a */ { false, 0x4b0a, 0x4b0a }, +/* 0x4b0b */ { false, 0x4b0b, 0x4b0b }, +/* 0x4b0c */ { false, 0x4b0c, 0x4b0c }, +/* 0x4b0d */ { false, 0x4b0d, 0x4b0d }, +/* 0x4b0e */ { false, 0x4b0e, 0x4b0e }, +/* 0x4b0f */ { false, 0x4b0f, 0x4b0f }, +/* 0x4b10 */ { false, 0x4b10, 0x4b10 }, +/* 0x4b11 */ { false, 0x4b11, 0x4b11 }, +/* 0x4b12 */ { false, 0x4b12, 0x4b12 }, +/* 0x4b13 */ { false, 0x4b13, 0x4b13 }, +/* 0x4b14 */ { false, 0x4b14, 0x4b14 }, +/* 0x4b15 */ { false, 0x4b15, 0x4b15 }, +/* 0x4b16 */ { false, 0x4b16, 0x4b16 }, +/* 0x4b17 */ { false, 0x4b17, 0x4b17 }, +/* 0x4b18 */ { false, 0x4b18, 0x4b18 }, +/* 0x4b19 */ { false, 0x4b19, 0x4b19 }, +/* 0x4b1a */ { false, 0x4b1a, 0x4b1a }, +/* 0x4b1b */ { false, 0x4b1b, 0x4b1b }, +/* 0x4b1c */ { false, 0x4b1c, 0x4b1c }, +/* 0x4b1d */ { false, 0x4b1d, 0x4b1d }, +/* 0x4b1e */ { false, 0x4b1e, 0x4b1e }, +/* 0x4b1f */ { false, 0x4b1f, 0x4b1f }, +/* 0x4b20 */ { false, 0x4b20, 0x4b20 }, +/* 0x4b21 */ { false, 0x4b21, 0x4b21 }, +/* 0x4b22 */ { false, 0x4b22, 0x4b22 }, +/* 0x4b23 */ { false, 0x4b23, 0x4b23 }, +/* 0x4b24 */ { false, 0x4b24, 0x4b24 }, +/* 0x4b25 */ { false, 0x4b25, 0x4b25 }, +/* 0x4b26 */ { false, 0x4b26, 0x4b26 }, +/* 0x4b27 */ { false, 0x4b27, 0x4b27 }, +/* 0x4b28 */ { false, 0x4b28, 0x4b28 }, +/* 0x4b29 */ { false, 0x4b29, 0x4b29 }, +/* 0x4b2a */ { false, 0x4b2a, 0x4b2a }, +/* 0x4b2b */ { false, 0x4b2b, 0x4b2b }, +/* 0x4b2c */ { false, 0x4b2c, 0x4b2c }, +/* 0x4b2d */ { false, 0x4b2d, 0x4b2d }, +/* 0x4b2e */ { false, 0x4b2e, 0x4b2e }, +/* 0x4b2f */ { false, 0x4b2f, 0x4b2f }, +/* 0x4b30 */ { false, 0x4b30, 0x4b30 }, +/* 0x4b31 */ { false, 0x4b31, 0x4b31 }, +/* 0x4b32 */ { false, 0x4b32, 0x4b32 }, +/* 0x4b33 */ { false, 0x4b33, 0x4b33 }, +/* 0x4b34 */ { false, 0x4b34, 0x4b34 }, +/* 0x4b35 */ { false, 0x4b35, 0x4b35 }, +/* 0x4b36 */ { false, 0x4b36, 0x4b36 }, +/* 0x4b37 */ { false, 0x4b37, 0x4b37 }, +/* 0x4b38 */ { false, 0x4b38, 0x4b38 }, +/* 0x4b39 */ { false, 0x4b39, 0x4b39 }, +/* 0x4b3a */ { false, 0x4b3a, 0x4b3a }, +/* 0x4b3b */ { false, 0x4b3b, 0x4b3b }, +/* 0x4b3c */ { false, 0x4b3c, 0x4b3c }, +/* 0x4b3d */ { false, 0x4b3d, 0x4b3d }, +/* 0x4b3e */ { false, 0x4b3e, 0x4b3e }, +/* 0x4b3f */ { false, 0x4b3f, 0x4b3f }, +/* 0x4b40 */ { false, 0x4b40, 0x4b40 }, +/* 0x4b41 */ { false, 0x4b41, 0x4b41 }, +/* 0x4b42 */ { false, 0x4b42, 0x4b42 }, +/* 0x4b43 */ { false, 0x4b43, 0x4b43 }, +/* 0x4b44 */ { false, 0x4b44, 0x4b44 }, +/* 0x4b45 */ { false, 0x4b45, 0x4b45 }, +/* 0x4b46 */ { false, 0x4b46, 0x4b46 }, +/* 0x4b47 */ { false, 0x4b47, 0x4b47 }, +/* 0x4b48 */ { false, 0x4b48, 0x4b48 }, +/* 0x4b49 */ { false, 0x4b49, 0x4b49 }, +/* 0x4b4a */ { false, 0x4b4a, 0x4b4a }, +/* 0x4b4b */ { false, 0x4b4b, 0x4b4b }, +/* 0x4b4c */ { false, 0x4b4c, 0x4b4c }, +/* 0x4b4d */ { false, 0x4b4d, 0x4b4d }, +/* 0x4b4e */ { false, 0x4b4e, 0x4b4e }, +/* 0x4b4f */ { false, 0x4b4f, 0x4b4f }, +/* 0x4b50 */ { false, 0x4b50, 0x4b50 }, +/* 0x4b51 */ { false, 0x4b51, 0x4b51 }, +/* 0x4b52 */ { false, 0x4b52, 0x4b52 }, +/* 0x4b53 */ { false, 0x4b53, 0x4b53 }, +/* 0x4b54 */ { false, 0x4b54, 0x4b54 }, +/* 0x4b55 */ { false, 0x4b55, 0x4b55 }, +/* 0x4b56 */ { false, 0x4b56, 0x4b56 }, +/* 0x4b57 */ { false, 0x4b57, 0x4b57 }, +/* 0x4b58 */ { false, 0x4b58, 0x4b58 }, +/* 0x4b59 */ { false, 0x4b59, 0x4b59 }, +/* 0x4b5a */ { false, 0x4b5a, 0x4b5a }, +/* 0x4b5b */ { false, 0x4b5b, 0x4b5b }, +/* 0x4b5c */ { false, 0x4b5c, 0x4b5c }, +/* 0x4b5d */ { false, 0x4b5d, 0x4b5d }, +/* 0x4b5e */ { false, 0x4b5e, 0x4b5e }, +/* 0x4b5f */ { false, 0x4b5f, 0x4b5f }, +/* 0x4b60 */ { false, 0x4b60, 0x4b60 }, +/* 0x4b61 */ { false, 0x4b61, 0x4b61 }, +/* 0x4b62 */ { false, 0x4b62, 0x4b62 }, +/* 0x4b63 */ { false, 0x4b63, 0x4b63 }, +/* 0x4b64 */ { false, 0x4b64, 0x4b64 }, +/* 0x4b65 */ { false, 0x4b65, 0x4b65 }, +/* 0x4b66 */ { false, 0x4b66, 0x4b66 }, +/* 0x4b67 */ { false, 0x4b67, 0x4b67 }, +/* 0x4b68 */ { false, 0x4b68, 0x4b68 }, +/* 0x4b69 */ { false, 0x4b69, 0x4b69 }, +/* 0x4b6a */ { false, 0x4b6a, 0x4b6a }, +/* 0x4b6b */ { false, 0x4b6b, 0x4b6b }, +/* 0x4b6c */ { false, 0x4b6c, 0x4b6c }, +/* 0x4b6d */ { false, 0x4b6d, 0x4b6d }, +/* 0x4b6e */ { false, 0x4b6e, 0x4b6e }, +/* 0x4b6f */ { false, 0x4b6f, 0x4b6f }, +/* 0x4b70 */ { false, 0x4b70, 0x4b70 }, +/* 0x4b71 */ { false, 0x4b71, 0x4b71 }, +/* 0x4b72 */ { false, 0x4b72, 0x4b72 }, +/* 0x4b73 */ { false, 0x4b73, 0x4b73 }, +/* 0x4b74 */ { false, 0x4b74, 0x4b74 }, +/* 0x4b75 */ { false, 0x4b75, 0x4b75 }, +/* 0x4b76 */ { false, 0x4b76, 0x4b76 }, +/* 0x4b77 */ { false, 0x4b77, 0x4b77 }, +/* 0x4b78 */ { false, 0x4b78, 0x4b78 }, +/* 0x4b79 */ { false, 0x4b79, 0x4b79 }, +/* 0x4b7a */ { false, 0x4b7a, 0x4b7a }, +/* 0x4b7b */ { false, 0x4b7b, 0x4b7b }, +/* 0x4b7c */ { false, 0x4b7c, 0x4b7c }, +/* 0x4b7d */ { false, 0x4b7d, 0x4b7d }, +/* 0x4b7e */ { false, 0x4b7e, 0x4b7e }, +/* 0x4b7f */ { false, 0x4b7f, 0x4b7f }, +/* 0x4b80 */ { false, 0x4b80, 0x4b80 }, +/* 0x4b81 */ { false, 0x4b81, 0x4b81 }, +/* 0x4b82 */ { false, 0x4b82, 0x4b82 }, +/* 0x4b83 */ { false, 0x4b83, 0x4b83 }, +/* 0x4b84 */ { false, 0x4b84, 0x4b84 }, +/* 0x4b85 */ { false, 0x4b85, 0x4b85 }, +/* 0x4b86 */ { false, 0x4b86, 0x4b86 }, +/* 0x4b87 */ { false, 0x4b87, 0x4b87 }, +/* 0x4b88 */ { false, 0x4b88, 0x4b88 }, +/* 0x4b89 */ { false, 0x4b89, 0x4b89 }, +/* 0x4b8a */ { false, 0x4b8a, 0x4b8a }, +/* 0x4b8b */ { false, 0x4b8b, 0x4b8b }, +/* 0x4b8c */ { false, 0x4b8c, 0x4b8c }, +/* 0x4b8d */ { false, 0x4b8d, 0x4b8d }, +/* 0x4b8e */ { false, 0x4b8e, 0x4b8e }, +/* 0x4b8f */ { false, 0x4b8f, 0x4b8f }, +/* 0x4b90 */ { false, 0x4b90, 0x4b90 }, +/* 0x4b91 */ { false, 0x4b91, 0x4b91 }, +/* 0x4b92 */ { false, 0x4b92, 0x4b92 }, +/* 0x4b93 */ { false, 0x4b93, 0x4b93 }, +/* 0x4b94 */ { false, 0x4b94, 0x4b94 }, +/* 0x4b95 */ { false, 0x4b95, 0x4b95 }, +/* 0x4b96 */ { false, 0x4b96, 0x4b96 }, +/* 0x4b97 */ { false, 0x4b97, 0x4b97 }, +/* 0x4b98 */ { false, 0x4b98, 0x4b98 }, +/* 0x4b99 */ { false, 0x4b99, 0x4b99 }, +/* 0x4b9a */ { false, 0x4b9a, 0x4b9a }, +/* 0x4b9b */ { false, 0x4b9b, 0x4b9b }, +/* 0x4b9c */ { false, 0x4b9c, 0x4b9c }, +/* 0x4b9d */ { false, 0x4b9d, 0x4b9d }, +/* 0x4b9e */ { false, 0x4b9e, 0x4b9e }, +/* 0x4b9f */ { false, 0x4b9f, 0x4b9f }, +/* 0x4ba0 */ { false, 0x4ba0, 0x4ba0 }, +/* 0x4ba1 */ { false, 0x4ba1, 0x4ba1 }, +/* 0x4ba2 */ { false, 0x4ba2, 0x4ba2 }, +/* 0x4ba3 */ { false, 0x4ba3, 0x4ba3 }, +/* 0x4ba4 */ { false, 0x4ba4, 0x4ba4 }, +/* 0x4ba5 */ { false, 0x4ba5, 0x4ba5 }, +/* 0x4ba6 */ { false, 0x4ba6, 0x4ba6 }, +/* 0x4ba7 */ { false, 0x4ba7, 0x4ba7 }, +/* 0x4ba8 */ { false, 0x4ba8, 0x4ba8 }, +/* 0x4ba9 */ { false, 0x4ba9, 0x4ba9 }, +/* 0x4baa */ { false, 0x4baa, 0x4baa }, +/* 0x4bab */ { false, 0x4bab, 0x4bab }, +/* 0x4bac */ { false, 0x4bac, 0x4bac }, +/* 0x4bad */ { false, 0x4bad, 0x4bad }, +/* 0x4bae */ { false, 0x4bae, 0x4bae }, +/* 0x4baf */ { false, 0x4baf, 0x4baf }, +/* 0x4bb0 */ { false, 0x4bb0, 0x4bb0 }, +/* 0x4bb1 */ { false, 0x4bb1, 0x4bb1 }, +/* 0x4bb2 */ { false, 0x4bb2, 0x4bb2 }, +/* 0x4bb3 */ { false, 0x4bb3, 0x4bb3 }, +/* 0x4bb4 */ { false, 0x4bb4, 0x4bb4 }, +/* 0x4bb5 */ { false, 0x4bb5, 0x4bb5 }, +/* 0x4bb6 */ { false, 0x4bb6, 0x4bb6 }, +/* 0x4bb7 */ { false, 0x4bb7, 0x4bb7 }, +/* 0x4bb8 */ { false, 0x4bb8, 0x4bb8 }, +/* 0x4bb9 */ { false, 0x4bb9, 0x4bb9 }, +/* 0x4bba */ { false, 0x4bba, 0x4bba }, +/* 0x4bbb */ { false, 0x4bbb, 0x4bbb }, +/* 0x4bbc */ { false, 0x4bbc, 0x4bbc }, +/* 0x4bbd */ { false, 0x4bbd, 0x4bbd }, +/* 0x4bbe */ { false, 0x4bbe, 0x4bbe }, +/* 0x4bbf */ { false, 0x4bbf, 0x4bbf }, +/* 0x4bc0 */ { false, 0x4bc0, 0x4bc0 }, +/* 0x4bc1 */ { false, 0x4bc1, 0x4bc1 }, +/* 0x4bc2 */ { false, 0x4bc2, 0x4bc2 }, +/* 0x4bc3 */ { false, 0x4bc3, 0x4bc3 }, +/* 0x4bc4 */ { false, 0x4bc4, 0x4bc4 }, +/* 0x4bc5 */ { false, 0x4bc5, 0x4bc5 }, +/* 0x4bc6 */ { false, 0x4bc6, 0x4bc6 }, +/* 0x4bc7 */ { false, 0x4bc7, 0x4bc7 }, +/* 0x4bc8 */ { false, 0x4bc8, 0x4bc8 }, +/* 0x4bc9 */ { false, 0x4bc9, 0x4bc9 }, +/* 0x4bca */ { false, 0x4bca, 0x4bca }, +/* 0x4bcb */ { false, 0x4bcb, 0x4bcb }, +/* 0x4bcc */ { false, 0x4bcc, 0x4bcc }, +/* 0x4bcd */ { false, 0x4bcd, 0x4bcd }, +/* 0x4bce */ { false, 0x4bce, 0x4bce }, +/* 0x4bcf */ { false, 0x4bcf, 0x4bcf }, +/* 0x4bd0 */ { false, 0x4bd0, 0x4bd0 }, +/* 0x4bd1 */ { false, 0x4bd1, 0x4bd1 }, +/* 0x4bd2 */ { false, 0x4bd2, 0x4bd2 }, +/* 0x4bd3 */ { false, 0x4bd3, 0x4bd3 }, +/* 0x4bd4 */ { false, 0x4bd4, 0x4bd4 }, +/* 0x4bd5 */ { false, 0x4bd5, 0x4bd5 }, +/* 0x4bd6 */ { false, 0x4bd6, 0x4bd6 }, +/* 0x4bd7 */ { false, 0x4bd7, 0x4bd7 }, +/* 0x4bd8 */ { false, 0x4bd8, 0x4bd8 }, +/* 0x4bd9 */ { false, 0x4bd9, 0x4bd9 }, +/* 0x4bda */ { false, 0x4bda, 0x4bda }, +/* 0x4bdb */ { false, 0x4bdb, 0x4bdb }, +/* 0x4bdc */ { false, 0x4bdc, 0x4bdc }, +/* 0x4bdd */ { false, 0x4bdd, 0x4bdd }, +/* 0x4bde */ { false, 0x4bde, 0x4bde }, +/* 0x4bdf */ { false, 0x4bdf, 0x4bdf }, +/* 0x4be0 */ { false, 0x4be0, 0x4be0 }, +/* 0x4be1 */ { false, 0x4be1, 0x4be1 }, +/* 0x4be2 */ { false, 0x4be2, 0x4be2 }, +/* 0x4be3 */ { false, 0x4be3, 0x4be3 }, +/* 0x4be4 */ { false, 0x4be4, 0x4be4 }, +/* 0x4be5 */ { false, 0x4be5, 0x4be5 }, +/* 0x4be6 */ { false, 0x4be6, 0x4be6 }, +/* 0x4be7 */ { false, 0x4be7, 0x4be7 }, +/* 0x4be8 */ { false, 0x4be8, 0x4be8 }, +/* 0x4be9 */ { false, 0x4be9, 0x4be9 }, +/* 0x4bea */ { false, 0x4bea, 0x4bea }, +/* 0x4beb */ { false, 0x4beb, 0x4beb }, +/* 0x4bec */ { false, 0x4bec, 0x4bec }, +/* 0x4bed */ { false, 0x4bed, 0x4bed }, +/* 0x4bee */ { false, 0x4bee, 0x4bee }, +/* 0x4bef */ { false, 0x4bef, 0x4bef }, +/* 0x4bf0 */ { false, 0x4bf0, 0x4bf0 }, +/* 0x4bf1 */ { false, 0x4bf1, 0x4bf1 }, +/* 0x4bf2 */ { false, 0x4bf2, 0x4bf2 }, +/* 0x4bf3 */ { false, 0x4bf3, 0x4bf3 }, +/* 0x4bf4 */ { false, 0x4bf4, 0x4bf4 }, +/* 0x4bf5 */ { false, 0x4bf5, 0x4bf5 }, +/* 0x4bf6 */ { false, 0x4bf6, 0x4bf6 }, +/* 0x4bf7 */ { false, 0x4bf7, 0x4bf7 }, +/* 0x4bf8 */ { false, 0x4bf8, 0x4bf8 }, +/* 0x4bf9 */ { false, 0x4bf9, 0x4bf9 }, +/* 0x4bfa */ { false, 0x4bfa, 0x4bfa }, +/* 0x4bfb */ { false, 0x4bfb, 0x4bfb }, +/* 0x4bfc */ { false, 0x4bfc, 0x4bfc }, +/* 0x4bfd */ { false, 0x4bfd, 0x4bfd }, +/* 0x4bfe */ { false, 0x4bfe, 0x4bfe }, +/* 0x4bff */ { false, 0x4bff, 0x4bff }, +/* 0x4c00 */ { false, 0x4c00, 0x4c00 }, +/* 0x4c01 */ { false, 0x4c01, 0x4c01 }, +/* 0x4c02 */ { false, 0x4c02, 0x4c02 }, +/* 0x4c03 */ { false, 0x4c03, 0x4c03 }, +/* 0x4c04 */ { false, 0x4c04, 0x4c04 }, +/* 0x4c05 */ { false, 0x4c05, 0x4c05 }, +/* 0x4c06 */ { false, 0x4c06, 0x4c06 }, +/* 0x4c07 */ { false, 0x4c07, 0x4c07 }, +/* 0x4c08 */ { false, 0x4c08, 0x4c08 }, +/* 0x4c09 */ { false, 0x4c09, 0x4c09 }, +/* 0x4c0a */ { false, 0x4c0a, 0x4c0a }, +/* 0x4c0b */ { false, 0x4c0b, 0x4c0b }, +/* 0x4c0c */ { false, 0x4c0c, 0x4c0c }, +/* 0x4c0d */ { false, 0x4c0d, 0x4c0d }, +/* 0x4c0e */ { false, 0x4c0e, 0x4c0e }, +/* 0x4c0f */ { false, 0x4c0f, 0x4c0f }, +/* 0x4c10 */ { false, 0x4c10, 0x4c10 }, +/* 0x4c11 */ { false, 0x4c11, 0x4c11 }, +/* 0x4c12 */ { false, 0x4c12, 0x4c12 }, +/* 0x4c13 */ { false, 0x4c13, 0x4c13 }, +/* 0x4c14 */ { false, 0x4c14, 0x4c14 }, +/* 0x4c15 */ { false, 0x4c15, 0x4c15 }, +/* 0x4c16 */ { false, 0x4c16, 0x4c16 }, +/* 0x4c17 */ { false, 0x4c17, 0x4c17 }, +/* 0x4c18 */ { false, 0x4c18, 0x4c18 }, +/* 0x4c19 */ { false, 0x4c19, 0x4c19 }, +/* 0x4c1a */ { false, 0x4c1a, 0x4c1a }, +/* 0x4c1b */ { false, 0x4c1b, 0x4c1b }, +/* 0x4c1c */ { false, 0x4c1c, 0x4c1c }, +/* 0x4c1d */ { false, 0x4c1d, 0x4c1d }, +/* 0x4c1e */ { false, 0x4c1e, 0x4c1e }, +/* 0x4c1f */ { false, 0x4c1f, 0x4c1f }, +/* 0x4c20 */ { false, 0x4c20, 0x4c20 }, +/* 0x4c21 */ { false, 0x4c21, 0x4c21 }, +/* 0x4c22 */ { false, 0x4c22, 0x4c22 }, +/* 0x4c23 */ { false, 0x4c23, 0x4c23 }, +/* 0x4c24 */ { false, 0x4c24, 0x4c24 }, +/* 0x4c25 */ { false, 0x4c25, 0x4c25 }, +/* 0x4c26 */ { false, 0x4c26, 0x4c26 }, +/* 0x4c27 */ { false, 0x4c27, 0x4c27 }, +/* 0x4c28 */ { false, 0x4c28, 0x4c28 }, +/* 0x4c29 */ { false, 0x4c29, 0x4c29 }, +/* 0x4c2a */ { false, 0x4c2a, 0x4c2a }, +/* 0x4c2b */ { false, 0x4c2b, 0x4c2b }, +/* 0x4c2c */ { false, 0x4c2c, 0x4c2c }, +/* 0x4c2d */ { false, 0x4c2d, 0x4c2d }, +/* 0x4c2e */ { false, 0x4c2e, 0x4c2e }, +/* 0x4c2f */ { false, 0x4c2f, 0x4c2f }, +/* 0x4c30 */ { false, 0x4c30, 0x4c30 }, +/* 0x4c31 */ { false, 0x4c31, 0x4c31 }, +/* 0x4c32 */ { false, 0x4c32, 0x4c32 }, +/* 0x4c33 */ { false, 0x4c33, 0x4c33 }, +/* 0x4c34 */ { false, 0x4c34, 0x4c34 }, +/* 0x4c35 */ { false, 0x4c35, 0x4c35 }, +/* 0x4c36 */ { false, 0x4c36, 0x4c36 }, +/* 0x4c37 */ { false, 0x4c37, 0x4c37 }, +/* 0x4c38 */ { false, 0x4c38, 0x4c38 }, +/* 0x4c39 */ { false, 0x4c39, 0x4c39 }, +/* 0x4c3a */ { false, 0x4c3a, 0x4c3a }, +/* 0x4c3b */ { false, 0x4c3b, 0x4c3b }, +/* 0x4c3c */ { false, 0x4c3c, 0x4c3c }, +/* 0x4c3d */ { false, 0x4c3d, 0x4c3d }, +/* 0x4c3e */ { false, 0x4c3e, 0x4c3e }, +/* 0x4c3f */ { false, 0x4c3f, 0x4c3f }, +/* 0x4c40 */ { false, 0x4c40, 0x4c40 }, +/* 0x4c41 */ { false, 0x4c41, 0x4c41 }, +/* 0x4c42 */ { false, 0x4c42, 0x4c42 }, +/* 0x4c43 */ { false, 0x4c43, 0x4c43 }, +/* 0x4c44 */ { false, 0x4c44, 0x4c44 }, +/* 0x4c45 */ { false, 0x4c45, 0x4c45 }, +/* 0x4c46 */ { false, 0x4c46, 0x4c46 }, +/* 0x4c47 */ { false, 0x4c47, 0x4c47 }, +/* 0x4c48 */ { false, 0x4c48, 0x4c48 }, +/* 0x4c49 */ { false, 0x4c49, 0x4c49 }, +/* 0x4c4a */ { false, 0x4c4a, 0x4c4a }, +/* 0x4c4b */ { false, 0x4c4b, 0x4c4b }, +/* 0x4c4c */ { false, 0x4c4c, 0x4c4c }, +/* 0x4c4d */ { false, 0x4c4d, 0x4c4d }, +/* 0x4c4e */ { false, 0x4c4e, 0x4c4e }, +/* 0x4c4f */ { false, 0x4c4f, 0x4c4f }, +/* 0x4c50 */ { false, 0x4c50, 0x4c50 }, +/* 0x4c51 */ { false, 0x4c51, 0x4c51 }, +/* 0x4c52 */ { false, 0x4c52, 0x4c52 }, +/* 0x4c53 */ { false, 0x4c53, 0x4c53 }, +/* 0x4c54 */ { false, 0x4c54, 0x4c54 }, +/* 0x4c55 */ { false, 0x4c55, 0x4c55 }, +/* 0x4c56 */ { false, 0x4c56, 0x4c56 }, +/* 0x4c57 */ { false, 0x4c57, 0x4c57 }, +/* 0x4c58 */ { false, 0x4c58, 0x4c58 }, +/* 0x4c59 */ { false, 0x4c59, 0x4c59 }, +/* 0x4c5a */ { false, 0x4c5a, 0x4c5a }, +/* 0x4c5b */ { false, 0x4c5b, 0x4c5b }, +/* 0x4c5c */ { false, 0x4c5c, 0x4c5c }, +/* 0x4c5d */ { false, 0x4c5d, 0x4c5d }, +/* 0x4c5e */ { false, 0x4c5e, 0x4c5e }, +/* 0x4c5f */ { false, 0x4c5f, 0x4c5f }, +/* 0x4c60 */ { false, 0x4c60, 0x4c60 }, +/* 0x4c61 */ { false, 0x4c61, 0x4c61 }, +/* 0x4c62 */ { false, 0x4c62, 0x4c62 }, +/* 0x4c63 */ { false, 0x4c63, 0x4c63 }, +/* 0x4c64 */ { false, 0x4c64, 0x4c64 }, +/* 0x4c65 */ { false, 0x4c65, 0x4c65 }, +/* 0x4c66 */ { false, 0x4c66, 0x4c66 }, +/* 0x4c67 */ { false, 0x4c67, 0x4c67 }, +/* 0x4c68 */ { false, 0x4c68, 0x4c68 }, +/* 0x4c69 */ { false, 0x4c69, 0x4c69 }, +/* 0x4c6a */ { false, 0x4c6a, 0x4c6a }, +/* 0x4c6b */ { false, 0x4c6b, 0x4c6b }, +/* 0x4c6c */ { false, 0x4c6c, 0x4c6c }, +/* 0x4c6d */ { false, 0x4c6d, 0x4c6d }, +/* 0x4c6e */ { false, 0x4c6e, 0x4c6e }, +/* 0x4c6f */ { false, 0x4c6f, 0x4c6f }, +/* 0x4c70 */ { false, 0x4c70, 0x4c70 }, +/* 0x4c71 */ { false, 0x4c71, 0x4c71 }, +/* 0x4c72 */ { false, 0x4c72, 0x4c72 }, +/* 0x4c73 */ { false, 0x4c73, 0x4c73 }, +/* 0x4c74 */ { false, 0x4c74, 0x4c74 }, +/* 0x4c75 */ { false, 0x4c75, 0x4c75 }, +/* 0x4c76 */ { false, 0x4c76, 0x4c76 }, +/* 0x4c77 */ { false, 0x4c77, 0x4c77 }, +/* 0x4c78 */ { false, 0x4c78, 0x4c78 }, +/* 0x4c79 */ { false, 0x4c79, 0x4c79 }, +/* 0x4c7a */ { false, 0x4c7a, 0x4c7a }, +/* 0x4c7b */ { false, 0x4c7b, 0x4c7b }, +/* 0x4c7c */ { false, 0x4c7c, 0x4c7c }, +/* 0x4c7d */ { false, 0x4c7d, 0x4c7d }, +/* 0x4c7e */ { false, 0x4c7e, 0x4c7e }, +/* 0x4c7f */ { false, 0x4c7f, 0x4c7f }, +/* 0x4c80 */ { false, 0x4c80, 0x4c80 }, +/* 0x4c81 */ { false, 0x4c81, 0x4c81 }, +/* 0x4c82 */ { false, 0x4c82, 0x4c82 }, +/* 0x4c83 */ { false, 0x4c83, 0x4c83 }, +/* 0x4c84 */ { false, 0x4c84, 0x4c84 }, +/* 0x4c85 */ { false, 0x4c85, 0x4c85 }, +/* 0x4c86 */ { false, 0x4c86, 0x4c86 }, +/* 0x4c87 */ { false, 0x4c87, 0x4c87 }, +/* 0x4c88 */ { false, 0x4c88, 0x4c88 }, +/* 0x4c89 */ { false, 0x4c89, 0x4c89 }, +/* 0x4c8a */ { false, 0x4c8a, 0x4c8a }, +/* 0x4c8b */ { false, 0x4c8b, 0x4c8b }, +/* 0x4c8c */ { false, 0x4c8c, 0x4c8c }, +/* 0x4c8d */ { false, 0x4c8d, 0x4c8d }, +/* 0x4c8e */ { false, 0x4c8e, 0x4c8e }, +/* 0x4c8f */ { false, 0x4c8f, 0x4c8f }, +/* 0x4c90 */ { false, 0x4c90, 0x4c90 }, +/* 0x4c91 */ { false, 0x4c91, 0x4c91 }, +/* 0x4c92 */ { false, 0x4c92, 0x4c92 }, +/* 0x4c93 */ { false, 0x4c93, 0x4c93 }, +/* 0x4c94 */ { false, 0x4c94, 0x4c94 }, +/* 0x4c95 */ { false, 0x4c95, 0x4c95 }, +/* 0x4c96 */ { false, 0x4c96, 0x4c96 }, +/* 0x4c97 */ { false, 0x4c97, 0x4c97 }, +/* 0x4c98 */ { false, 0x4c98, 0x4c98 }, +/* 0x4c99 */ { false, 0x4c99, 0x4c99 }, +/* 0x4c9a */ { false, 0x4c9a, 0x4c9a }, +/* 0x4c9b */ { false, 0x4c9b, 0x4c9b }, +/* 0x4c9c */ { false, 0x4c9c, 0x4c9c }, +/* 0x4c9d */ { false, 0x4c9d, 0x4c9d }, +/* 0x4c9e */ { false, 0x4c9e, 0x4c9e }, +/* 0x4c9f */ { false, 0x4c9f, 0x4c9f }, +/* 0x4ca0 */ { false, 0x4ca0, 0x4ca0 }, +/* 0x4ca1 */ { false, 0x4ca1, 0x4ca1 }, +/* 0x4ca2 */ { false, 0x4ca2, 0x4ca2 }, +/* 0x4ca3 */ { false, 0x4ca3, 0x4ca3 }, +/* 0x4ca4 */ { false, 0x4ca4, 0x4ca4 }, +/* 0x4ca5 */ { false, 0x4ca5, 0x4ca5 }, +/* 0x4ca6 */ { false, 0x4ca6, 0x4ca6 }, +/* 0x4ca7 */ { false, 0x4ca7, 0x4ca7 }, +/* 0x4ca8 */ { false, 0x4ca8, 0x4ca8 }, +/* 0x4ca9 */ { false, 0x4ca9, 0x4ca9 }, +/* 0x4caa */ { false, 0x4caa, 0x4caa }, +/* 0x4cab */ { false, 0x4cab, 0x4cab }, +/* 0x4cac */ { false, 0x4cac, 0x4cac }, +/* 0x4cad */ { false, 0x4cad, 0x4cad }, +/* 0x4cae */ { false, 0x4cae, 0x4cae }, +/* 0x4caf */ { false, 0x4caf, 0x4caf }, +/* 0x4cb0 */ { false, 0x4cb0, 0x4cb0 }, +/* 0x4cb1 */ { false, 0x4cb1, 0x4cb1 }, +/* 0x4cb2 */ { false, 0x4cb2, 0x4cb2 }, +/* 0x4cb3 */ { false, 0x4cb3, 0x4cb3 }, +/* 0x4cb4 */ { false, 0x4cb4, 0x4cb4 }, +/* 0x4cb5 */ { false, 0x4cb5, 0x4cb5 }, +/* 0x4cb6 */ { false, 0x4cb6, 0x4cb6 }, +/* 0x4cb7 */ { false, 0x4cb7, 0x4cb7 }, +/* 0x4cb8 */ { false, 0x4cb8, 0x4cb8 }, +/* 0x4cb9 */ { false, 0x4cb9, 0x4cb9 }, +/* 0x4cba */ { false, 0x4cba, 0x4cba }, +/* 0x4cbb */ { false, 0x4cbb, 0x4cbb }, +/* 0x4cbc */ { false, 0x4cbc, 0x4cbc }, +/* 0x4cbd */ { false, 0x4cbd, 0x4cbd }, +/* 0x4cbe */ { false, 0x4cbe, 0x4cbe }, +/* 0x4cbf */ { false, 0x4cbf, 0x4cbf }, +/* 0x4cc0 */ { false, 0x4cc0, 0x4cc0 }, +/* 0x4cc1 */ { false, 0x4cc1, 0x4cc1 }, +/* 0x4cc2 */ { false, 0x4cc2, 0x4cc2 }, +/* 0x4cc3 */ { false, 0x4cc3, 0x4cc3 }, +/* 0x4cc4 */ { false, 0x4cc4, 0x4cc4 }, +/* 0x4cc5 */ { false, 0x4cc5, 0x4cc5 }, +/* 0x4cc6 */ { false, 0x4cc6, 0x4cc6 }, +/* 0x4cc7 */ { false, 0x4cc7, 0x4cc7 }, +/* 0x4cc8 */ { false, 0x4cc8, 0x4cc8 }, +/* 0x4cc9 */ { false, 0x4cc9, 0x4cc9 }, +/* 0x4cca */ { false, 0x4cca, 0x4cca }, +/* 0x4ccb */ { false, 0x4ccb, 0x4ccb }, +/* 0x4ccc */ { false, 0x4ccc, 0x4ccc }, +/* 0x4ccd */ { false, 0x4ccd, 0x4ccd }, +/* 0x4cce */ { false, 0x4cce, 0x4cce }, +/* 0x4ccf */ { false, 0x4ccf, 0x4ccf }, +/* 0x4cd0 */ { false, 0x4cd0, 0x4cd0 }, +/* 0x4cd1 */ { false, 0x4cd1, 0x4cd1 }, +/* 0x4cd2 */ { false, 0x4cd2, 0x4cd2 }, +/* 0x4cd3 */ { false, 0x4cd3, 0x4cd3 }, +/* 0x4cd4 */ { false, 0x4cd4, 0x4cd4 }, +/* 0x4cd5 */ { false, 0x4cd5, 0x4cd5 }, +/* 0x4cd6 */ { false, 0x4cd6, 0x4cd6 }, +/* 0x4cd7 */ { false, 0x4cd7, 0x4cd7 }, +/* 0x4cd8 */ { false, 0x4cd8, 0x4cd8 }, +/* 0x4cd9 */ { false, 0x4cd9, 0x4cd9 }, +/* 0x4cda */ { false, 0x4cda, 0x4cda }, +/* 0x4cdb */ { false, 0x4cdb, 0x4cdb }, +/* 0x4cdc */ { false, 0x4cdc, 0x4cdc }, +/* 0x4cdd */ { false, 0x4cdd, 0x4cdd }, +/* 0x4cde */ { false, 0x4cde, 0x4cde }, +/* 0x4cdf */ { false, 0x4cdf, 0x4cdf }, +/* 0x4ce0 */ { false, 0x4ce0, 0x4ce0 }, +/* 0x4ce1 */ { false, 0x4ce1, 0x4ce1 }, +/* 0x4ce2 */ { false, 0x4ce2, 0x4ce2 }, +/* 0x4ce3 */ { false, 0x4ce3, 0x4ce3 }, +/* 0x4ce4 */ { false, 0x4ce4, 0x4ce4 }, +/* 0x4ce5 */ { false, 0x4ce5, 0x4ce5 }, +/* 0x4ce6 */ { false, 0x4ce6, 0x4ce6 }, +/* 0x4ce7 */ { false, 0x4ce7, 0x4ce7 }, +/* 0x4ce8 */ { false, 0x4ce8, 0x4ce8 }, +/* 0x4ce9 */ { false, 0x4ce9, 0x4ce9 }, +/* 0x4cea */ { false, 0x4cea, 0x4cea }, +/* 0x4ceb */ { false, 0x4ceb, 0x4ceb }, +/* 0x4cec */ { false, 0x4cec, 0x4cec }, +/* 0x4ced */ { false, 0x4ced, 0x4ced }, +/* 0x4cee */ { false, 0x4cee, 0x4cee }, +/* 0x4cef */ { false, 0x4cef, 0x4cef }, +/* 0x4cf0 */ { false, 0x4cf0, 0x4cf0 }, +/* 0x4cf1 */ { false, 0x4cf1, 0x4cf1 }, +/* 0x4cf2 */ { false, 0x4cf2, 0x4cf2 }, +/* 0x4cf3 */ { false, 0x4cf3, 0x4cf3 }, +/* 0x4cf4 */ { false, 0x4cf4, 0x4cf4 }, +/* 0x4cf5 */ { false, 0x4cf5, 0x4cf5 }, +/* 0x4cf6 */ { false, 0x4cf6, 0x4cf6 }, +/* 0x4cf7 */ { false, 0x4cf7, 0x4cf7 }, +/* 0x4cf8 */ { false, 0x4cf8, 0x4cf8 }, +/* 0x4cf9 */ { false, 0x4cf9, 0x4cf9 }, +/* 0x4cfa */ { false, 0x4cfa, 0x4cfa }, +/* 0x4cfb */ { false, 0x4cfb, 0x4cfb }, +/* 0x4cfc */ { false, 0x4cfc, 0x4cfc }, +/* 0x4cfd */ { false, 0x4cfd, 0x4cfd }, +/* 0x4cfe */ { false, 0x4cfe, 0x4cfe }, +/* 0x4cff */ { false, 0x4cff, 0x4cff }, +/* 0x4d00 */ { false, 0x4d00, 0x4d00 }, +/* 0x4d01 */ { false, 0x4d01, 0x4d01 }, +/* 0x4d02 */ { false, 0x4d02, 0x4d02 }, +/* 0x4d03 */ { false, 0x4d03, 0x4d03 }, +/* 0x4d04 */ { false, 0x4d04, 0x4d04 }, +/* 0x4d05 */ { false, 0x4d05, 0x4d05 }, +/* 0x4d06 */ { false, 0x4d06, 0x4d06 }, +/* 0x4d07 */ { false, 0x4d07, 0x4d07 }, +/* 0x4d08 */ { false, 0x4d08, 0x4d08 }, +/* 0x4d09 */ { false, 0x4d09, 0x4d09 }, +/* 0x4d0a */ { false, 0x4d0a, 0x4d0a }, +/* 0x4d0b */ { false, 0x4d0b, 0x4d0b }, +/* 0x4d0c */ { false, 0x4d0c, 0x4d0c }, +/* 0x4d0d */ { false, 0x4d0d, 0x4d0d }, +/* 0x4d0e */ { false, 0x4d0e, 0x4d0e }, +/* 0x4d0f */ { false, 0x4d0f, 0x4d0f }, +/* 0x4d10 */ { false, 0x4d10, 0x4d10 }, +/* 0x4d11 */ { false, 0x4d11, 0x4d11 }, +/* 0x4d12 */ { false, 0x4d12, 0x4d12 }, +/* 0x4d13 */ { false, 0x4d13, 0x4d13 }, +/* 0x4d14 */ { false, 0x4d14, 0x4d14 }, +/* 0x4d15 */ { false, 0x4d15, 0x4d15 }, +/* 0x4d16 */ { false, 0x4d16, 0x4d16 }, +/* 0x4d17 */ { false, 0x4d17, 0x4d17 }, +/* 0x4d18 */ { false, 0x4d18, 0x4d18 }, +/* 0x4d19 */ { false, 0x4d19, 0x4d19 }, +/* 0x4d1a */ { false, 0x4d1a, 0x4d1a }, +/* 0x4d1b */ { false, 0x4d1b, 0x4d1b }, +/* 0x4d1c */ { false, 0x4d1c, 0x4d1c }, +/* 0x4d1d */ { false, 0x4d1d, 0x4d1d }, +/* 0x4d1e */ { false, 0x4d1e, 0x4d1e }, +/* 0x4d1f */ { false, 0x4d1f, 0x4d1f }, +/* 0x4d20 */ { false, 0x4d20, 0x4d20 }, +/* 0x4d21 */ { false, 0x4d21, 0x4d21 }, +/* 0x4d22 */ { false, 0x4d22, 0x4d22 }, +/* 0x4d23 */ { false, 0x4d23, 0x4d23 }, +/* 0x4d24 */ { false, 0x4d24, 0x4d24 }, +/* 0x4d25 */ { false, 0x4d25, 0x4d25 }, +/* 0x4d26 */ { false, 0x4d26, 0x4d26 }, +/* 0x4d27 */ { false, 0x4d27, 0x4d27 }, +/* 0x4d28 */ { false, 0x4d28, 0x4d28 }, +/* 0x4d29 */ { false, 0x4d29, 0x4d29 }, +/* 0x4d2a */ { false, 0x4d2a, 0x4d2a }, +/* 0x4d2b */ { false, 0x4d2b, 0x4d2b }, +/* 0x4d2c */ { false, 0x4d2c, 0x4d2c }, +/* 0x4d2d */ { false, 0x4d2d, 0x4d2d }, +/* 0x4d2e */ { false, 0x4d2e, 0x4d2e }, +/* 0x4d2f */ { false, 0x4d2f, 0x4d2f }, +/* 0x4d30 */ { false, 0x4d30, 0x4d30 }, +/* 0x4d31 */ { false, 0x4d31, 0x4d31 }, +/* 0x4d32 */ { false, 0x4d32, 0x4d32 }, +/* 0x4d33 */ { false, 0x4d33, 0x4d33 }, +/* 0x4d34 */ { false, 0x4d34, 0x4d34 }, +/* 0x4d35 */ { false, 0x4d35, 0x4d35 }, +/* 0x4d36 */ { false, 0x4d36, 0x4d36 }, +/* 0x4d37 */ { false, 0x4d37, 0x4d37 }, +/* 0x4d38 */ { false, 0x4d38, 0x4d38 }, +/* 0x4d39 */ { false, 0x4d39, 0x4d39 }, +/* 0x4d3a */ { false, 0x4d3a, 0x4d3a }, +/* 0x4d3b */ { false, 0x4d3b, 0x4d3b }, +/* 0x4d3c */ { false, 0x4d3c, 0x4d3c }, +/* 0x4d3d */ { false, 0x4d3d, 0x4d3d }, +/* 0x4d3e */ { false, 0x4d3e, 0x4d3e }, +/* 0x4d3f */ { false, 0x4d3f, 0x4d3f }, +/* 0x4d40 */ { false, 0x4d40, 0x4d40 }, +/* 0x4d41 */ { false, 0x4d41, 0x4d41 }, +/* 0x4d42 */ { false, 0x4d42, 0x4d42 }, +/* 0x4d43 */ { false, 0x4d43, 0x4d43 }, +/* 0x4d44 */ { false, 0x4d44, 0x4d44 }, +/* 0x4d45 */ { false, 0x4d45, 0x4d45 }, +/* 0x4d46 */ { false, 0x4d46, 0x4d46 }, +/* 0x4d47 */ { false, 0x4d47, 0x4d47 }, +/* 0x4d48 */ { false, 0x4d48, 0x4d48 }, +/* 0x4d49 */ { false, 0x4d49, 0x4d49 }, +/* 0x4d4a */ { false, 0x4d4a, 0x4d4a }, +/* 0x4d4b */ { false, 0x4d4b, 0x4d4b }, +/* 0x4d4c */ { false, 0x4d4c, 0x4d4c }, +/* 0x4d4d */ { false, 0x4d4d, 0x4d4d }, +/* 0x4d4e */ { false, 0x4d4e, 0x4d4e }, +/* 0x4d4f */ { false, 0x4d4f, 0x4d4f }, +/* 0x4d50 */ { false, 0x4d50, 0x4d50 }, +/* 0x4d51 */ { false, 0x4d51, 0x4d51 }, +/* 0x4d52 */ { false, 0x4d52, 0x4d52 }, +/* 0x4d53 */ { false, 0x4d53, 0x4d53 }, +/* 0x4d54 */ { false, 0x4d54, 0x4d54 }, +/* 0x4d55 */ { false, 0x4d55, 0x4d55 }, +/* 0x4d56 */ { false, 0x4d56, 0x4d56 }, +/* 0x4d57 */ { false, 0x4d57, 0x4d57 }, +/* 0x4d58 */ { false, 0x4d58, 0x4d58 }, +/* 0x4d59 */ { false, 0x4d59, 0x4d59 }, +/* 0x4d5a */ { false, 0x4d5a, 0x4d5a }, +/* 0x4d5b */ { false, 0x4d5b, 0x4d5b }, +/* 0x4d5c */ { false, 0x4d5c, 0x4d5c }, +/* 0x4d5d */ { false, 0x4d5d, 0x4d5d }, +/* 0x4d5e */ { false, 0x4d5e, 0x4d5e }, +/* 0x4d5f */ { false, 0x4d5f, 0x4d5f }, +/* 0x4d60 */ { false, 0x4d60, 0x4d60 }, +/* 0x4d61 */ { false, 0x4d61, 0x4d61 }, +/* 0x4d62 */ { false, 0x4d62, 0x4d62 }, +/* 0x4d63 */ { false, 0x4d63, 0x4d63 }, +/* 0x4d64 */ { false, 0x4d64, 0x4d64 }, +/* 0x4d65 */ { false, 0x4d65, 0x4d65 }, +/* 0x4d66 */ { false, 0x4d66, 0x4d66 }, +/* 0x4d67 */ { false, 0x4d67, 0x4d67 }, +/* 0x4d68 */ { false, 0x4d68, 0x4d68 }, +/* 0x4d69 */ { false, 0x4d69, 0x4d69 }, +/* 0x4d6a */ { false, 0x4d6a, 0x4d6a }, +/* 0x4d6b */ { false, 0x4d6b, 0x4d6b }, +/* 0x4d6c */ { false, 0x4d6c, 0x4d6c }, +/* 0x4d6d */ { false, 0x4d6d, 0x4d6d }, +/* 0x4d6e */ { false, 0x4d6e, 0x4d6e }, +/* 0x4d6f */ { false, 0x4d6f, 0x4d6f }, +/* 0x4d70 */ { false, 0x4d70, 0x4d70 }, +/* 0x4d71 */ { false, 0x4d71, 0x4d71 }, +/* 0x4d72 */ { false, 0x4d72, 0x4d72 }, +/* 0x4d73 */ { false, 0x4d73, 0x4d73 }, +/* 0x4d74 */ { false, 0x4d74, 0x4d74 }, +/* 0x4d75 */ { false, 0x4d75, 0x4d75 }, +/* 0x4d76 */ { false, 0x4d76, 0x4d76 }, +/* 0x4d77 */ { false, 0x4d77, 0x4d77 }, +/* 0x4d78 */ { false, 0x4d78, 0x4d78 }, +/* 0x4d79 */ { false, 0x4d79, 0x4d79 }, +/* 0x4d7a */ { false, 0x4d7a, 0x4d7a }, +/* 0x4d7b */ { false, 0x4d7b, 0x4d7b }, +/* 0x4d7c */ { false, 0x4d7c, 0x4d7c }, +/* 0x4d7d */ { false, 0x4d7d, 0x4d7d }, +/* 0x4d7e */ { false, 0x4d7e, 0x4d7e }, +/* 0x4d7f */ { false, 0x4d7f, 0x4d7f }, +/* 0x4d80 */ { false, 0x4d80, 0x4d80 }, +/* 0x4d81 */ { false, 0x4d81, 0x4d81 }, +/* 0x4d82 */ { false, 0x4d82, 0x4d82 }, +/* 0x4d83 */ { false, 0x4d83, 0x4d83 }, +/* 0x4d84 */ { false, 0x4d84, 0x4d84 }, +/* 0x4d85 */ { false, 0x4d85, 0x4d85 }, +/* 0x4d86 */ { false, 0x4d86, 0x4d86 }, +/* 0x4d87 */ { false, 0x4d87, 0x4d87 }, +/* 0x4d88 */ { false, 0x4d88, 0x4d88 }, +/* 0x4d89 */ { false, 0x4d89, 0x4d89 }, +/* 0x4d8a */ { false, 0x4d8a, 0x4d8a }, +/* 0x4d8b */ { false, 0x4d8b, 0x4d8b }, +/* 0x4d8c */ { false, 0x4d8c, 0x4d8c }, +/* 0x4d8d */ { false, 0x4d8d, 0x4d8d }, +/* 0x4d8e */ { false, 0x4d8e, 0x4d8e }, +/* 0x4d8f */ { false, 0x4d8f, 0x4d8f }, +/* 0x4d90 */ { false, 0x4d90, 0x4d90 }, +/* 0x4d91 */ { false, 0x4d91, 0x4d91 }, +/* 0x4d92 */ { false, 0x4d92, 0x4d92 }, +/* 0x4d93 */ { false, 0x4d93, 0x4d93 }, +/* 0x4d94 */ { false, 0x4d94, 0x4d94 }, +/* 0x4d95 */ { false, 0x4d95, 0x4d95 }, +/* 0x4d96 */ { false, 0x4d96, 0x4d96 }, +/* 0x4d97 */ { false, 0x4d97, 0x4d97 }, +/* 0x4d98 */ { false, 0x4d98, 0x4d98 }, +/* 0x4d99 */ { false, 0x4d99, 0x4d99 }, +/* 0x4d9a */ { false, 0x4d9a, 0x4d9a }, +/* 0x4d9b */ { false, 0x4d9b, 0x4d9b }, +/* 0x4d9c */ { false, 0x4d9c, 0x4d9c }, +/* 0x4d9d */ { false, 0x4d9d, 0x4d9d }, +/* 0x4d9e */ { false, 0x4d9e, 0x4d9e }, +/* 0x4d9f */ { false, 0x4d9f, 0x4d9f }, +/* 0x4da0 */ { false, 0x4da0, 0x4da0 }, +/* 0x4da1 */ { false, 0x4da1, 0x4da1 }, +/* 0x4da2 */ { false, 0x4da2, 0x4da2 }, +/* 0x4da3 */ { false, 0x4da3, 0x4da3 }, +/* 0x4da4 */ { false, 0x4da4, 0x4da4 }, +/* 0x4da5 */ { false, 0x4da5, 0x4da5 }, +/* 0x4da6 */ { false, 0x4da6, 0x4da6 }, +/* 0x4da7 */ { false, 0x4da7, 0x4da7 }, +/* 0x4da8 */ { false, 0x4da8, 0x4da8 }, +/* 0x4da9 */ { false, 0x4da9, 0x4da9 }, +/* 0x4daa */ { false, 0x4daa, 0x4daa }, +/* 0x4dab */ { false, 0x4dab, 0x4dab }, +/* 0x4dac */ { false, 0x4dac, 0x4dac }, +/* 0x4dad */ { false, 0x4dad, 0x4dad }, +/* 0x4dae */ { false, 0x4dae, 0x4dae }, +/* 0x4daf */ { false, 0x4daf, 0x4daf }, +/* 0x4db0 */ { false, 0x4db0, 0x4db0 }, +/* 0x4db1 */ { false, 0x4db1, 0x4db1 }, +/* 0x4db2 */ { false, 0x4db2, 0x4db2 }, +/* 0x4db3 */ { false, 0x4db3, 0x4db3 }, +/* 0x4db4 */ { false, 0x4db4, 0x4db4 }, +/* 0x4db5 */ { true, 0x4db5, 0x4db5 }, +/* 0x4db6 */ { false, 0x4db6, 0x4db6 }, +/* 0x4db7 */ { false, 0x4db7, 0x4db7 }, +/* 0x4db8 */ { false, 0x4db8, 0x4db8 }, +/* 0x4db9 */ { false, 0x4db9, 0x4db9 }, +/* 0x4dba */ { false, 0x4dba, 0x4dba }, +/* 0x4dbb */ { false, 0x4dbb, 0x4dbb }, +/* 0x4dbc */ { false, 0x4dbc, 0x4dbc }, +/* 0x4dbd */ { false, 0x4dbd, 0x4dbd }, +/* 0x4dbe */ { false, 0x4dbe, 0x4dbe }, +/* 0x4dbf */ { false, 0x4dbf, 0x4dbf }, +/* 0x4dc0 */ { false, 0x4dc0, 0x4dc0 }, +/* 0x4dc1 */ { false, 0x4dc1, 0x4dc1 }, +/* 0x4dc2 */ { false, 0x4dc2, 0x4dc2 }, +/* 0x4dc3 */ { false, 0x4dc3, 0x4dc3 }, +/* 0x4dc4 */ { false, 0x4dc4, 0x4dc4 }, +/* 0x4dc5 */ { false, 0x4dc5, 0x4dc5 }, +/* 0x4dc6 */ { false, 0x4dc6, 0x4dc6 }, +/* 0x4dc7 */ { false, 0x4dc7, 0x4dc7 }, +/* 0x4dc8 */ { false, 0x4dc8, 0x4dc8 }, +/* 0x4dc9 */ { false, 0x4dc9, 0x4dc9 }, +/* 0x4dca */ { false, 0x4dca, 0x4dca }, +/* 0x4dcb */ { false, 0x4dcb, 0x4dcb }, +/* 0x4dcc */ { false, 0x4dcc, 0x4dcc }, +/* 0x4dcd */ { false, 0x4dcd, 0x4dcd }, +/* 0x4dce */ { false, 0x4dce, 0x4dce }, +/* 0x4dcf */ { false, 0x4dcf, 0x4dcf }, +/* 0x4dd0 */ { false, 0x4dd0, 0x4dd0 }, +/* 0x4dd1 */ { false, 0x4dd1, 0x4dd1 }, +/* 0x4dd2 */ { false, 0x4dd2, 0x4dd2 }, +/* 0x4dd3 */ { false, 0x4dd3, 0x4dd3 }, +/* 0x4dd4 */ { false, 0x4dd4, 0x4dd4 }, +/* 0x4dd5 */ { false, 0x4dd5, 0x4dd5 }, +/* 0x4dd6 */ { false, 0x4dd6, 0x4dd6 }, +/* 0x4dd7 */ { false, 0x4dd7, 0x4dd7 }, +/* 0x4dd8 */ { false, 0x4dd8, 0x4dd8 }, +/* 0x4dd9 */ { false, 0x4dd9, 0x4dd9 }, +/* 0x4dda */ { false, 0x4dda, 0x4dda }, +/* 0x4ddb */ { false, 0x4ddb, 0x4ddb }, +/* 0x4ddc */ { false, 0x4ddc, 0x4ddc }, +/* 0x4ddd */ { false, 0x4ddd, 0x4ddd }, +/* 0x4dde */ { false, 0x4dde, 0x4dde }, +/* 0x4ddf */ { false, 0x4ddf, 0x4ddf }, +/* 0x4de0 */ { false, 0x4de0, 0x4de0 }, +/* 0x4de1 */ { false, 0x4de1, 0x4de1 }, +/* 0x4de2 */ { false, 0x4de2, 0x4de2 }, +/* 0x4de3 */ { false, 0x4de3, 0x4de3 }, +/* 0x4de4 */ { false, 0x4de4, 0x4de4 }, +/* 0x4de5 */ { false, 0x4de5, 0x4de5 }, +/* 0x4de6 */ { false, 0x4de6, 0x4de6 }, +/* 0x4de7 */ { false, 0x4de7, 0x4de7 }, +/* 0x4de8 */ { false, 0x4de8, 0x4de8 }, +/* 0x4de9 */ { false, 0x4de9, 0x4de9 }, +/* 0x4dea */ { false, 0x4dea, 0x4dea }, +/* 0x4deb */ { false, 0x4deb, 0x4deb }, +/* 0x4dec */ { false, 0x4dec, 0x4dec }, +/* 0x4ded */ { false, 0x4ded, 0x4ded }, +/* 0x4dee */ { false, 0x4dee, 0x4dee }, +/* 0x4def */ { false, 0x4def, 0x4def }, +/* 0x4df0 */ { false, 0x4df0, 0x4df0 }, +/* 0x4df1 */ { false, 0x4df1, 0x4df1 }, +/* 0x4df2 */ { false, 0x4df2, 0x4df2 }, +/* 0x4df3 */ { false, 0x4df3, 0x4df3 }, +/* 0x4df4 */ { false, 0x4df4, 0x4df4 }, +/* 0x4df5 */ { false, 0x4df5, 0x4df5 }, +/* 0x4df6 */ { false, 0x4df6, 0x4df6 }, +/* 0x4df7 */ { false, 0x4df7, 0x4df7 }, +/* 0x4df8 */ { false, 0x4df8, 0x4df8 }, +/* 0x4df9 */ { false, 0x4df9, 0x4df9 }, +/* 0x4dfa */ { false, 0x4dfa, 0x4dfa }, +/* 0x4dfb */ { false, 0x4dfb, 0x4dfb }, +/* 0x4dfc */ { false, 0x4dfc, 0x4dfc }, +/* 0x4dfd */ { false, 0x4dfd, 0x4dfd }, +/* 0x4dfe */ { false, 0x4dfe, 0x4dfe }, +/* 0x4dff */ { false, 0x4dff, 0x4dff }, +/* 0x4e00 */ { true, 0x4e00, 0x4e00 }, +/* 0x4e01 */ { false, 0x4e01, 0x4e01 }, +/* 0x4e02 */ { false, 0x4e02, 0x4e02 }, +/* 0x4e03 */ { false, 0x4e03, 0x4e03 }, +/* 0x4e04 */ { false, 0x4e04, 0x4e04 }, +/* 0x4e05 */ { false, 0x4e05, 0x4e05 }, +/* 0x4e06 */ { false, 0x4e06, 0x4e06 }, +/* 0x4e07 */ { false, 0x4e07, 0x4e07 }, +/* 0x4e08 */ { false, 0x4e08, 0x4e08 }, +/* 0x4e09 */ { false, 0x4e09, 0x4e09 }, +/* 0x4e0a */ { false, 0x4e0a, 0x4e0a }, +/* 0x4e0b */ { false, 0x4e0b, 0x4e0b }, +/* 0x4e0c */ { false, 0x4e0c, 0x4e0c }, +/* 0x4e0d */ { false, 0x4e0d, 0x4e0d }, +/* 0x4e0e */ { false, 0x4e0e, 0x4e0e }, +/* 0x4e0f */ { false, 0x4e0f, 0x4e0f }, +/* 0x4e10 */ { false, 0x4e10, 0x4e10 }, +/* 0x4e11 */ { false, 0x4e11, 0x4e11 }, +/* 0x4e12 */ { false, 0x4e12, 0x4e12 }, +/* 0x4e13 */ { false, 0x4e13, 0x4e13 }, +/* 0x4e14 */ { false, 0x4e14, 0x4e14 }, +/* 0x4e15 */ { false, 0x4e15, 0x4e15 }, +/* 0x4e16 */ { false, 0x4e16, 0x4e16 }, +/* 0x4e17 */ { false, 0x4e17, 0x4e17 }, +/* 0x4e18 */ { false, 0x4e18, 0x4e18 }, +/* 0x4e19 */ { false, 0x4e19, 0x4e19 }, +/* 0x4e1a */ { false, 0x4e1a, 0x4e1a }, +/* 0x4e1b */ { false, 0x4e1b, 0x4e1b }, +/* 0x4e1c */ { false, 0x4e1c, 0x4e1c }, +/* 0x4e1d */ { false, 0x4e1d, 0x4e1d }, +/* 0x4e1e */ { false, 0x4e1e, 0x4e1e }, +/* 0x4e1f */ { false, 0x4e1f, 0x4e1f }, +/* 0x4e20 */ { false, 0x4e20, 0x4e20 }, +/* 0x4e21 */ { false, 0x4e21, 0x4e21 }, +/* 0x4e22 */ { false, 0x4e22, 0x4e22 }, +/* 0x4e23 */ { false, 0x4e23, 0x4e23 }, +/* 0x4e24 */ { false, 0x4e24, 0x4e24 }, +/* 0x4e25 */ { false, 0x4e25, 0x4e25 }, +/* 0x4e26 */ { false, 0x4e26, 0x4e26 }, +/* 0x4e27 */ { false, 0x4e27, 0x4e27 }, +/* 0x4e28 */ { false, 0x4e28, 0x4e28 }, +/* 0x4e29 */ { false, 0x4e29, 0x4e29 }, +/* 0x4e2a */ { false, 0x4e2a, 0x4e2a }, +/* 0x4e2b */ { false, 0x4e2b, 0x4e2b }, +/* 0x4e2c */ { false, 0x4e2c, 0x4e2c }, +/* 0x4e2d */ { false, 0x4e2d, 0x4e2d }, +/* 0x4e2e */ { false, 0x4e2e, 0x4e2e }, +/* 0x4e2f */ { false, 0x4e2f, 0x4e2f }, +/* 0x4e30 */ { false, 0x4e30, 0x4e30 }, +/* 0x4e31 */ { false, 0x4e31, 0x4e31 }, +/* 0x4e32 */ { false, 0x4e32, 0x4e32 }, +/* 0x4e33 */ { false, 0x4e33, 0x4e33 }, +/* 0x4e34 */ { false, 0x4e34, 0x4e34 }, +/* 0x4e35 */ { false, 0x4e35, 0x4e35 }, +/* 0x4e36 */ { false, 0x4e36, 0x4e36 }, +/* 0x4e37 */ { false, 0x4e37, 0x4e37 }, +/* 0x4e38 */ { false, 0x4e38, 0x4e38 }, +/* 0x4e39 */ { false, 0x4e39, 0x4e39 }, +/* 0x4e3a */ { false, 0x4e3a, 0x4e3a }, +/* 0x4e3b */ { false, 0x4e3b, 0x4e3b }, +/* 0x4e3c */ { false, 0x4e3c, 0x4e3c }, +/* 0x4e3d */ { false, 0x4e3d, 0x4e3d }, +/* 0x4e3e */ { false, 0x4e3e, 0x4e3e }, +/* 0x4e3f */ { false, 0x4e3f, 0x4e3f }, +/* 0x4e40 */ { false, 0x4e40, 0x4e40 }, +/* 0x4e41 */ { false, 0x4e41, 0x4e41 }, +/* 0x4e42 */ { false, 0x4e42, 0x4e42 }, +/* 0x4e43 */ { false, 0x4e43, 0x4e43 }, +/* 0x4e44 */ { false, 0x4e44, 0x4e44 }, +/* 0x4e45 */ { false, 0x4e45, 0x4e45 }, +/* 0x4e46 */ { false, 0x4e46, 0x4e46 }, +/* 0x4e47 */ { false, 0x4e47, 0x4e47 }, +/* 0x4e48 */ { false, 0x4e48, 0x4e48 }, +/* 0x4e49 */ { false, 0x4e49, 0x4e49 }, +/* 0x4e4a */ { false, 0x4e4a, 0x4e4a }, +/* 0x4e4b */ { false, 0x4e4b, 0x4e4b }, +/* 0x4e4c */ { false, 0x4e4c, 0x4e4c }, +/* 0x4e4d */ { false, 0x4e4d, 0x4e4d }, +/* 0x4e4e */ { false, 0x4e4e, 0x4e4e }, +/* 0x4e4f */ { false, 0x4e4f, 0x4e4f }, +/* 0x4e50 */ { false, 0x4e50, 0x4e50 }, +/* 0x4e51 */ { false, 0x4e51, 0x4e51 }, +/* 0x4e52 */ { false, 0x4e52, 0x4e52 }, +/* 0x4e53 */ { false, 0x4e53, 0x4e53 }, +/* 0x4e54 */ { false, 0x4e54, 0x4e54 }, +/* 0x4e55 */ { false, 0x4e55, 0x4e55 }, +/* 0x4e56 */ { false, 0x4e56, 0x4e56 }, +/* 0x4e57 */ { false, 0x4e57, 0x4e57 }, +/* 0x4e58 */ { false, 0x4e58, 0x4e58 }, +/* 0x4e59 */ { false, 0x4e59, 0x4e59 }, +/* 0x4e5a */ { false, 0x4e5a, 0x4e5a }, +/* 0x4e5b */ { false, 0x4e5b, 0x4e5b }, +/* 0x4e5c */ { false, 0x4e5c, 0x4e5c }, +/* 0x4e5d */ { false, 0x4e5d, 0x4e5d }, +/* 0x4e5e */ { false, 0x4e5e, 0x4e5e }, +/* 0x4e5f */ { false, 0x4e5f, 0x4e5f }, +/* 0x4e60 */ { false, 0x4e60, 0x4e60 }, +/* 0x4e61 */ { false, 0x4e61, 0x4e61 }, +/* 0x4e62 */ { false, 0x4e62, 0x4e62 }, +/* 0x4e63 */ { false, 0x4e63, 0x4e63 }, +/* 0x4e64 */ { false, 0x4e64, 0x4e64 }, +/* 0x4e65 */ { false, 0x4e65, 0x4e65 }, +/* 0x4e66 */ { false, 0x4e66, 0x4e66 }, +/* 0x4e67 */ { false, 0x4e67, 0x4e67 }, +/* 0x4e68 */ { false, 0x4e68, 0x4e68 }, +/* 0x4e69 */ { false, 0x4e69, 0x4e69 }, +/* 0x4e6a */ { false, 0x4e6a, 0x4e6a }, +/* 0x4e6b */ { false, 0x4e6b, 0x4e6b }, +/* 0x4e6c */ { false, 0x4e6c, 0x4e6c }, +/* 0x4e6d */ { false, 0x4e6d, 0x4e6d }, +/* 0x4e6e */ { false, 0x4e6e, 0x4e6e }, +/* 0x4e6f */ { false, 0x4e6f, 0x4e6f }, +/* 0x4e70 */ { false, 0x4e70, 0x4e70 }, +/* 0x4e71 */ { false, 0x4e71, 0x4e71 }, +/* 0x4e72 */ { false, 0x4e72, 0x4e72 }, +/* 0x4e73 */ { false, 0x4e73, 0x4e73 }, +/* 0x4e74 */ { false, 0x4e74, 0x4e74 }, +/* 0x4e75 */ { false, 0x4e75, 0x4e75 }, +/* 0x4e76 */ { false, 0x4e76, 0x4e76 }, +/* 0x4e77 */ { false, 0x4e77, 0x4e77 }, +/* 0x4e78 */ { false, 0x4e78, 0x4e78 }, +/* 0x4e79 */ { false, 0x4e79, 0x4e79 }, +/* 0x4e7a */ { false, 0x4e7a, 0x4e7a }, +/* 0x4e7b */ { false, 0x4e7b, 0x4e7b }, +/* 0x4e7c */ { false, 0x4e7c, 0x4e7c }, +/* 0x4e7d */ { false, 0x4e7d, 0x4e7d }, +/* 0x4e7e */ { false, 0x4e7e, 0x4e7e }, +/* 0x4e7f */ { false, 0x4e7f, 0x4e7f }, +/* 0x4e80 */ { false, 0x4e80, 0x4e80 }, +/* 0x4e81 */ { false, 0x4e81, 0x4e81 }, +/* 0x4e82 */ { false, 0x4e82, 0x4e82 }, +/* 0x4e83 */ { false, 0x4e83, 0x4e83 }, +/* 0x4e84 */ { false, 0x4e84, 0x4e84 }, +/* 0x4e85 */ { false, 0x4e85, 0x4e85 }, +/* 0x4e86 */ { false, 0x4e86, 0x4e86 }, +/* 0x4e87 */ { false, 0x4e87, 0x4e87 }, +/* 0x4e88 */ { false, 0x4e88, 0x4e88 }, +/* 0x4e89 */ { false, 0x4e89, 0x4e89 }, +/* 0x4e8a */ { false, 0x4e8a, 0x4e8a }, +/* 0x4e8b */ { false, 0x4e8b, 0x4e8b }, +/* 0x4e8c */ { false, 0x4e8c, 0x4e8c }, +/* 0x4e8d */ { false, 0x4e8d, 0x4e8d }, +/* 0x4e8e */ { false, 0x4e8e, 0x4e8e }, +/* 0x4e8f */ { false, 0x4e8f, 0x4e8f }, +/* 0x4e90 */ { false, 0x4e90, 0x4e90 }, +/* 0x4e91 */ { false, 0x4e91, 0x4e91 }, +/* 0x4e92 */ { false, 0x4e92, 0x4e92 }, +/* 0x4e93 */ { false, 0x4e93, 0x4e93 }, +/* 0x4e94 */ { false, 0x4e94, 0x4e94 }, +/* 0x4e95 */ { false, 0x4e95, 0x4e95 }, +/* 0x4e96 */ { false, 0x4e96, 0x4e96 }, +/* 0x4e97 */ { false, 0x4e97, 0x4e97 }, +/* 0x4e98 */ { false, 0x4e98, 0x4e98 }, +/* 0x4e99 */ { false, 0x4e99, 0x4e99 }, +/* 0x4e9a */ { false, 0x4e9a, 0x4e9a }, +/* 0x4e9b */ { false, 0x4e9b, 0x4e9b }, +/* 0x4e9c */ { false, 0x4e9c, 0x4e9c }, +/* 0x4e9d */ { false, 0x4e9d, 0x4e9d }, +/* 0x4e9e */ { false, 0x4e9e, 0x4e9e }, +/* 0x4e9f */ { false, 0x4e9f, 0x4e9f }, +/* 0x4ea0 */ { false, 0x4ea0, 0x4ea0 }, +/* 0x4ea1 */ { false, 0x4ea1, 0x4ea1 }, +/* 0x4ea2 */ { false, 0x4ea2, 0x4ea2 }, +/* 0x4ea3 */ { false, 0x4ea3, 0x4ea3 }, +/* 0x4ea4 */ { false, 0x4ea4, 0x4ea4 }, +/* 0x4ea5 */ { false, 0x4ea5, 0x4ea5 }, +/* 0x4ea6 */ { false, 0x4ea6, 0x4ea6 }, +/* 0x4ea7 */ { false, 0x4ea7, 0x4ea7 }, +/* 0x4ea8 */ { false, 0x4ea8, 0x4ea8 }, +/* 0x4ea9 */ { false, 0x4ea9, 0x4ea9 }, +/* 0x4eaa */ { false, 0x4eaa, 0x4eaa }, +/* 0x4eab */ { false, 0x4eab, 0x4eab }, +/* 0x4eac */ { false, 0x4eac, 0x4eac }, +/* 0x4ead */ { false, 0x4ead, 0x4ead }, +/* 0x4eae */ { false, 0x4eae, 0x4eae }, +/* 0x4eaf */ { false, 0x4eaf, 0x4eaf }, +/* 0x4eb0 */ { false, 0x4eb0, 0x4eb0 }, +/* 0x4eb1 */ { false, 0x4eb1, 0x4eb1 }, +/* 0x4eb2 */ { false, 0x4eb2, 0x4eb2 }, +/* 0x4eb3 */ { false, 0x4eb3, 0x4eb3 }, +/* 0x4eb4 */ { false, 0x4eb4, 0x4eb4 }, +/* 0x4eb5 */ { false, 0x4eb5, 0x4eb5 }, +/* 0x4eb6 */ { false, 0x4eb6, 0x4eb6 }, +/* 0x4eb7 */ { false, 0x4eb7, 0x4eb7 }, +/* 0x4eb8 */ { false, 0x4eb8, 0x4eb8 }, +/* 0x4eb9 */ { false, 0x4eb9, 0x4eb9 }, +/* 0x4eba */ { false, 0x4eba, 0x4eba }, +/* 0x4ebb */ { false, 0x4ebb, 0x4ebb }, +/* 0x4ebc */ { false, 0x4ebc, 0x4ebc }, +/* 0x4ebd */ { false, 0x4ebd, 0x4ebd }, +/* 0x4ebe */ { false, 0x4ebe, 0x4ebe }, +/* 0x4ebf */ { false, 0x4ebf, 0x4ebf }, +/* 0x4ec0 */ { false, 0x4ec0, 0x4ec0 }, +/* 0x4ec1 */ { false, 0x4ec1, 0x4ec1 }, +/* 0x4ec2 */ { false, 0x4ec2, 0x4ec2 }, +/* 0x4ec3 */ { false, 0x4ec3, 0x4ec3 }, +/* 0x4ec4 */ { false, 0x4ec4, 0x4ec4 }, +/* 0x4ec5 */ { false, 0x4ec5, 0x4ec5 }, +/* 0x4ec6 */ { false, 0x4ec6, 0x4ec6 }, +/* 0x4ec7 */ { false, 0x4ec7, 0x4ec7 }, +/* 0x4ec8 */ { false, 0x4ec8, 0x4ec8 }, +/* 0x4ec9 */ { false, 0x4ec9, 0x4ec9 }, +/* 0x4eca */ { false, 0x4eca, 0x4eca }, +/* 0x4ecb */ { false, 0x4ecb, 0x4ecb }, +/* 0x4ecc */ { false, 0x4ecc, 0x4ecc }, +/* 0x4ecd */ { false, 0x4ecd, 0x4ecd }, +/* 0x4ece */ { false, 0x4ece, 0x4ece }, +/* 0x4ecf */ { false, 0x4ecf, 0x4ecf }, +/* 0x4ed0 */ { false, 0x4ed0, 0x4ed0 }, +/* 0x4ed1 */ { false, 0x4ed1, 0x4ed1 }, +/* 0x4ed2 */ { false, 0x4ed2, 0x4ed2 }, +/* 0x4ed3 */ { false, 0x4ed3, 0x4ed3 }, +/* 0x4ed4 */ { false, 0x4ed4, 0x4ed4 }, +/* 0x4ed5 */ { false, 0x4ed5, 0x4ed5 }, +/* 0x4ed6 */ { false, 0x4ed6, 0x4ed6 }, +/* 0x4ed7 */ { false, 0x4ed7, 0x4ed7 }, +/* 0x4ed8 */ { false, 0x4ed8, 0x4ed8 }, +/* 0x4ed9 */ { false, 0x4ed9, 0x4ed9 }, +/* 0x4eda */ { false, 0x4eda, 0x4eda }, +/* 0x4edb */ { false, 0x4edb, 0x4edb }, +/* 0x4edc */ { false, 0x4edc, 0x4edc }, +/* 0x4edd */ { false, 0x4edd, 0x4edd }, +/* 0x4ede */ { false, 0x4ede, 0x4ede }, +/* 0x4edf */ { false, 0x4edf, 0x4edf }, +/* 0x4ee0 */ { false, 0x4ee0, 0x4ee0 }, +/* 0x4ee1 */ { false, 0x4ee1, 0x4ee1 }, +/* 0x4ee2 */ { false, 0x4ee2, 0x4ee2 }, +/* 0x4ee3 */ { false, 0x4ee3, 0x4ee3 }, +/* 0x4ee4 */ { false, 0x4ee4, 0x4ee4 }, +/* 0x4ee5 */ { false, 0x4ee5, 0x4ee5 }, +/* 0x4ee6 */ { false, 0x4ee6, 0x4ee6 }, +/* 0x4ee7 */ { false, 0x4ee7, 0x4ee7 }, +/* 0x4ee8 */ { false, 0x4ee8, 0x4ee8 }, +/* 0x4ee9 */ { false, 0x4ee9, 0x4ee9 }, +/* 0x4eea */ { false, 0x4eea, 0x4eea }, +/* 0x4eeb */ { false, 0x4eeb, 0x4eeb }, +/* 0x4eec */ { false, 0x4eec, 0x4eec }, +/* 0x4eed */ { false, 0x4eed, 0x4eed }, +/* 0x4eee */ { false, 0x4eee, 0x4eee }, +/* 0x4eef */ { false, 0x4eef, 0x4eef }, +/* 0x4ef0 */ { false, 0x4ef0, 0x4ef0 }, +/* 0x4ef1 */ { false, 0x4ef1, 0x4ef1 }, +/* 0x4ef2 */ { false, 0x4ef2, 0x4ef2 }, +/* 0x4ef3 */ { false, 0x4ef3, 0x4ef3 }, +/* 0x4ef4 */ { false, 0x4ef4, 0x4ef4 }, +/* 0x4ef5 */ { false, 0x4ef5, 0x4ef5 }, +/* 0x4ef6 */ { false, 0x4ef6, 0x4ef6 }, +/* 0x4ef7 */ { false, 0x4ef7, 0x4ef7 }, +/* 0x4ef8 */ { false, 0x4ef8, 0x4ef8 }, +/* 0x4ef9 */ { false, 0x4ef9, 0x4ef9 }, +/* 0x4efa */ { false, 0x4efa, 0x4efa }, +/* 0x4efb */ { false, 0x4efb, 0x4efb }, +/* 0x4efc */ { false, 0x4efc, 0x4efc }, +/* 0x4efd */ { false, 0x4efd, 0x4efd }, +/* 0x4efe */ { false, 0x4efe, 0x4efe }, +/* 0x4eff */ { false, 0x4eff, 0x4eff }, +/* 0x4f00 */ { false, 0x4f00, 0x4f00 }, +/* 0x4f01 */ { false, 0x4f01, 0x4f01 }, +/* 0x4f02 */ { false, 0x4f02, 0x4f02 }, +/* 0x4f03 */ { false, 0x4f03, 0x4f03 }, +/* 0x4f04 */ { false, 0x4f04, 0x4f04 }, +/* 0x4f05 */ { false, 0x4f05, 0x4f05 }, +/* 0x4f06 */ { false, 0x4f06, 0x4f06 }, +/* 0x4f07 */ { false, 0x4f07, 0x4f07 }, +/* 0x4f08 */ { false, 0x4f08, 0x4f08 }, +/* 0x4f09 */ { false, 0x4f09, 0x4f09 }, +/* 0x4f0a */ { false, 0x4f0a, 0x4f0a }, +/* 0x4f0b */ { false, 0x4f0b, 0x4f0b }, +/* 0x4f0c */ { false, 0x4f0c, 0x4f0c }, +/* 0x4f0d */ { false, 0x4f0d, 0x4f0d }, +/* 0x4f0e */ { false, 0x4f0e, 0x4f0e }, +/* 0x4f0f */ { false, 0x4f0f, 0x4f0f }, +/* 0x4f10 */ { false, 0x4f10, 0x4f10 }, +/* 0x4f11 */ { false, 0x4f11, 0x4f11 }, +/* 0x4f12 */ { false, 0x4f12, 0x4f12 }, +/* 0x4f13 */ { false, 0x4f13, 0x4f13 }, +/* 0x4f14 */ { false, 0x4f14, 0x4f14 }, +/* 0x4f15 */ { false, 0x4f15, 0x4f15 }, +/* 0x4f16 */ { false, 0x4f16, 0x4f16 }, +/* 0x4f17 */ { false, 0x4f17, 0x4f17 }, +/* 0x4f18 */ { false, 0x4f18, 0x4f18 }, +/* 0x4f19 */ { false, 0x4f19, 0x4f19 }, +/* 0x4f1a */ { false, 0x4f1a, 0x4f1a }, +/* 0x4f1b */ { false, 0x4f1b, 0x4f1b }, +/* 0x4f1c */ { false, 0x4f1c, 0x4f1c }, +/* 0x4f1d */ { false, 0x4f1d, 0x4f1d }, +/* 0x4f1e */ { false, 0x4f1e, 0x4f1e }, +/* 0x4f1f */ { false, 0x4f1f, 0x4f1f }, +/* 0x4f20 */ { false, 0x4f20, 0x4f20 }, +/* 0x4f21 */ { false, 0x4f21, 0x4f21 }, +/* 0x4f22 */ { false, 0x4f22, 0x4f22 }, +/* 0x4f23 */ { false, 0x4f23, 0x4f23 }, +/* 0x4f24 */ { false, 0x4f24, 0x4f24 }, +/* 0x4f25 */ { false, 0x4f25, 0x4f25 }, +/* 0x4f26 */ { false, 0x4f26, 0x4f26 }, +/* 0x4f27 */ { false, 0x4f27, 0x4f27 }, +/* 0x4f28 */ { false, 0x4f28, 0x4f28 }, +/* 0x4f29 */ { false, 0x4f29, 0x4f29 }, +/* 0x4f2a */ { false, 0x4f2a, 0x4f2a }, +/* 0x4f2b */ { false, 0x4f2b, 0x4f2b }, +/* 0x4f2c */ { false, 0x4f2c, 0x4f2c }, +/* 0x4f2d */ { false, 0x4f2d, 0x4f2d }, +/* 0x4f2e */ { false, 0x4f2e, 0x4f2e }, +/* 0x4f2f */ { false, 0x4f2f, 0x4f2f }, +/* 0x4f30 */ { false, 0x4f30, 0x4f30 }, +/* 0x4f31 */ { false, 0x4f31, 0x4f31 }, +/* 0x4f32 */ { false, 0x4f32, 0x4f32 }, +/* 0x4f33 */ { false, 0x4f33, 0x4f33 }, +/* 0x4f34 */ { false, 0x4f34, 0x4f34 }, +/* 0x4f35 */ { false, 0x4f35, 0x4f35 }, +/* 0x4f36 */ { false, 0x4f36, 0x4f36 }, +/* 0x4f37 */ { false, 0x4f37, 0x4f37 }, +/* 0x4f38 */ { false, 0x4f38, 0x4f38 }, +/* 0x4f39 */ { false, 0x4f39, 0x4f39 }, +/* 0x4f3a */ { false, 0x4f3a, 0x4f3a }, +/* 0x4f3b */ { false, 0x4f3b, 0x4f3b }, +/* 0x4f3c */ { false, 0x4f3c, 0x4f3c }, +/* 0x4f3d */ { false, 0x4f3d, 0x4f3d }, +/* 0x4f3e */ { false, 0x4f3e, 0x4f3e }, +/* 0x4f3f */ { false, 0x4f3f, 0x4f3f }, +/* 0x4f40 */ { false, 0x4f40, 0x4f40 }, +/* 0x4f41 */ { false, 0x4f41, 0x4f41 }, +/* 0x4f42 */ { false, 0x4f42, 0x4f42 }, +/* 0x4f43 */ { false, 0x4f43, 0x4f43 }, +/* 0x4f44 */ { false, 0x4f44, 0x4f44 }, +/* 0x4f45 */ { false, 0x4f45, 0x4f45 }, +/* 0x4f46 */ { false, 0x4f46, 0x4f46 }, +/* 0x4f47 */ { false, 0x4f47, 0x4f47 }, +/* 0x4f48 */ { false, 0x4f48, 0x4f48 }, +/* 0x4f49 */ { false, 0x4f49, 0x4f49 }, +/* 0x4f4a */ { false, 0x4f4a, 0x4f4a }, +/* 0x4f4b */ { false, 0x4f4b, 0x4f4b }, +/* 0x4f4c */ { false, 0x4f4c, 0x4f4c }, +/* 0x4f4d */ { false, 0x4f4d, 0x4f4d }, +/* 0x4f4e */ { false, 0x4f4e, 0x4f4e }, +/* 0x4f4f */ { false, 0x4f4f, 0x4f4f }, +/* 0x4f50 */ { false, 0x4f50, 0x4f50 }, +/* 0x4f51 */ { false, 0x4f51, 0x4f51 }, +/* 0x4f52 */ { false, 0x4f52, 0x4f52 }, +/* 0x4f53 */ { false, 0x4f53, 0x4f53 }, +/* 0x4f54 */ { false, 0x4f54, 0x4f54 }, +/* 0x4f55 */ { false, 0x4f55, 0x4f55 }, +/* 0x4f56 */ { false, 0x4f56, 0x4f56 }, +/* 0x4f57 */ { false, 0x4f57, 0x4f57 }, +/* 0x4f58 */ { false, 0x4f58, 0x4f58 }, +/* 0x4f59 */ { false, 0x4f59, 0x4f59 }, +/* 0x4f5a */ { false, 0x4f5a, 0x4f5a }, +/* 0x4f5b */ { false, 0x4f5b, 0x4f5b }, +/* 0x4f5c */ { false, 0x4f5c, 0x4f5c }, +/* 0x4f5d */ { false, 0x4f5d, 0x4f5d }, +/* 0x4f5e */ { false, 0x4f5e, 0x4f5e }, +/* 0x4f5f */ { false, 0x4f5f, 0x4f5f }, +/* 0x4f60 */ { false, 0x4f60, 0x4f60 }, +/* 0x4f61 */ { false, 0x4f61, 0x4f61 }, +/* 0x4f62 */ { false, 0x4f62, 0x4f62 }, +/* 0x4f63 */ { false, 0x4f63, 0x4f63 }, +/* 0x4f64 */ { false, 0x4f64, 0x4f64 }, +/* 0x4f65 */ { false, 0x4f65, 0x4f65 }, +/* 0x4f66 */ { false, 0x4f66, 0x4f66 }, +/* 0x4f67 */ { false, 0x4f67, 0x4f67 }, +/* 0x4f68 */ { false, 0x4f68, 0x4f68 }, +/* 0x4f69 */ { false, 0x4f69, 0x4f69 }, +/* 0x4f6a */ { false, 0x4f6a, 0x4f6a }, +/* 0x4f6b */ { false, 0x4f6b, 0x4f6b }, +/* 0x4f6c */ { false, 0x4f6c, 0x4f6c }, +/* 0x4f6d */ { false, 0x4f6d, 0x4f6d }, +/* 0x4f6e */ { false, 0x4f6e, 0x4f6e }, +/* 0x4f6f */ { false, 0x4f6f, 0x4f6f }, +/* 0x4f70 */ { false, 0x4f70, 0x4f70 }, +/* 0x4f71 */ { false, 0x4f71, 0x4f71 }, +/* 0x4f72 */ { false, 0x4f72, 0x4f72 }, +/* 0x4f73 */ { false, 0x4f73, 0x4f73 }, +/* 0x4f74 */ { false, 0x4f74, 0x4f74 }, +/* 0x4f75 */ { false, 0x4f75, 0x4f75 }, +/* 0x4f76 */ { false, 0x4f76, 0x4f76 }, +/* 0x4f77 */ { false, 0x4f77, 0x4f77 }, +/* 0x4f78 */ { false, 0x4f78, 0x4f78 }, +/* 0x4f79 */ { false, 0x4f79, 0x4f79 }, +/* 0x4f7a */ { false, 0x4f7a, 0x4f7a }, +/* 0x4f7b */ { false, 0x4f7b, 0x4f7b }, +/* 0x4f7c */ { false, 0x4f7c, 0x4f7c }, +/* 0x4f7d */ { false, 0x4f7d, 0x4f7d }, +/* 0x4f7e */ { false, 0x4f7e, 0x4f7e }, +/* 0x4f7f */ { false, 0x4f7f, 0x4f7f }, +/* 0x4f80 */ { false, 0x4f80, 0x4f80 }, +/* 0x4f81 */ { false, 0x4f81, 0x4f81 }, +/* 0x4f82 */ { false, 0x4f82, 0x4f82 }, +/* 0x4f83 */ { false, 0x4f83, 0x4f83 }, +/* 0x4f84 */ { false, 0x4f84, 0x4f84 }, +/* 0x4f85 */ { false, 0x4f85, 0x4f85 }, +/* 0x4f86 */ { false, 0x4f86, 0x4f86 }, +/* 0x4f87 */ { false, 0x4f87, 0x4f87 }, +/* 0x4f88 */ { false, 0x4f88, 0x4f88 }, +/* 0x4f89 */ { false, 0x4f89, 0x4f89 }, +/* 0x4f8a */ { false, 0x4f8a, 0x4f8a }, +/* 0x4f8b */ { false, 0x4f8b, 0x4f8b }, +/* 0x4f8c */ { false, 0x4f8c, 0x4f8c }, +/* 0x4f8d */ { false, 0x4f8d, 0x4f8d }, +/* 0x4f8e */ { false, 0x4f8e, 0x4f8e }, +/* 0x4f8f */ { false, 0x4f8f, 0x4f8f }, +/* 0x4f90 */ { false, 0x4f90, 0x4f90 }, +/* 0x4f91 */ { false, 0x4f91, 0x4f91 }, +/* 0x4f92 */ { false, 0x4f92, 0x4f92 }, +/* 0x4f93 */ { false, 0x4f93, 0x4f93 }, +/* 0x4f94 */ { false, 0x4f94, 0x4f94 }, +/* 0x4f95 */ { false, 0x4f95, 0x4f95 }, +/* 0x4f96 */ { false, 0x4f96, 0x4f96 }, +/* 0x4f97 */ { false, 0x4f97, 0x4f97 }, +/* 0x4f98 */ { false, 0x4f98, 0x4f98 }, +/* 0x4f99 */ { false, 0x4f99, 0x4f99 }, +/* 0x4f9a */ { false, 0x4f9a, 0x4f9a }, +/* 0x4f9b */ { false, 0x4f9b, 0x4f9b }, +/* 0x4f9c */ { false, 0x4f9c, 0x4f9c }, +/* 0x4f9d */ { false, 0x4f9d, 0x4f9d }, +/* 0x4f9e */ { false, 0x4f9e, 0x4f9e }, +/* 0x4f9f */ { false, 0x4f9f, 0x4f9f }, +/* 0x4fa0 */ { false, 0x4fa0, 0x4fa0 }, +/* 0x4fa1 */ { false, 0x4fa1, 0x4fa1 }, +/* 0x4fa2 */ { false, 0x4fa2, 0x4fa2 }, +/* 0x4fa3 */ { false, 0x4fa3, 0x4fa3 }, +/* 0x4fa4 */ { false, 0x4fa4, 0x4fa4 }, +/* 0x4fa5 */ { false, 0x4fa5, 0x4fa5 }, +/* 0x4fa6 */ { false, 0x4fa6, 0x4fa6 }, +/* 0x4fa7 */ { false, 0x4fa7, 0x4fa7 }, +/* 0x4fa8 */ { false, 0x4fa8, 0x4fa8 }, +/* 0x4fa9 */ { false, 0x4fa9, 0x4fa9 }, +/* 0x4faa */ { false, 0x4faa, 0x4faa }, +/* 0x4fab */ { false, 0x4fab, 0x4fab }, +/* 0x4fac */ { false, 0x4fac, 0x4fac }, +/* 0x4fad */ { false, 0x4fad, 0x4fad }, +/* 0x4fae */ { false, 0x4fae, 0x4fae }, +/* 0x4faf */ { false, 0x4faf, 0x4faf }, +/* 0x4fb0 */ { false, 0x4fb0, 0x4fb0 }, +/* 0x4fb1 */ { false, 0x4fb1, 0x4fb1 }, +/* 0x4fb2 */ { false, 0x4fb2, 0x4fb2 }, +/* 0x4fb3 */ { false, 0x4fb3, 0x4fb3 }, +/* 0x4fb4 */ { false, 0x4fb4, 0x4fb4 }, +/* 0x4fb5 */ { false, 0x4fb5, 0x4fb5 }, +/* 0x4fb6 */ { false, 0x4fb6, 0x4fb6 }, +/* 0x4fb7 */ { false, 0x4fb7, 0x4fb7 }, +/* 0x4fb8 */ { false, 0x4fb8, 0x4fb8 }, +/* 0x4fb9 */ { false, 0x4fb9, 0x4fb9 }, +/* 0x4fba */ { false, 0x4fba, 0x4fba }, +/* 0x4fbb */ { false, 0x4fbb, 0x4fbb }, +/* 0x4fbc */ { false, 0x4fbc, 0x4fbc }, +/* 0x4fbd */ { false, 0x4fbd, 0x4fbd }, +/* 0x4fbe */ { false, 0x4fbe, 0x4fbe }, +/* 0x4fbf */ { false, 0x4fbf, 0x4fbf }, +/* 0x4fc0 */ { false, 0x4fc0, 0x4fc0 }, +/* 0x4fc1 */ { false, 0x4fc1, 0x4fc1 }, +/* 0x4fc2 */ { false, 0x4fc2, 0x4fc2 }, +/* 0x4fc3 */ { false, 0x4fc3, 0x4fc3 }, +/* 0x4fc4 */ { false, 0x4fc4, 0x4fc4 }, +/* 0x4fc5 */ { false, 0x4fc5, 0x4fc5 }, +/* 0x4fc6 */ { false, 0x4fc6, 0x4fc6 }, +/* 0x4fc7 */ { false, 0x4fc7, 0x4fc7 }, +/* 0x4fc8 */ { false, 0x4fc8, 0x4fc8 }, +/* 0x4fc9 */ { false, 0x4fc9, 0x4fc9 }, +/* 0x4fca */ { false, 0x4fca, 0x4fca }, +/* 0x4fcb */ { false, 0x4fcb, 0x4fcb }, +/* 0x4fcc */ { false, 0x4fcc, 0x4fcc }, +/* 0x4fcd */ { false, 0x4fcd, 0x4fcd }, +/* 0x4fce */ { false, 0x4fce, 0x4fce }, +/* 0x4fcf */ { false, 0x4fcf, 0x4fcf }, +/* 0x4fd0 */ { false, 0x4fd0, 0x4fd0 }, +/* 0x4fd1 */ { false, 0x4fd1, 0x4fd1 }, +/* 0x4fd2 */ { false, 0x4fd2, 0x4fd2 }, +/* 0x4fd3 */ { false, 0x4fd3, 0x4fd3 }, +/* 0x4fd4 */ { false, 0x4fd4, 0x4fd4 }, +/* 0x4fd5 */ { false, 0x4fd5, 0x4fd5 }, +/* 0x4fd6 */ { false, 0x4fd6, 0x4fd6 }, +/* 0x4fd7 */ { false, 0x4fd7, 0x4fd7 }, +/* 0x4fd8 */ { false, 0x4fd8, 0x4fd8 }, +/* 0x4fd9 */ { false, 0x4fd9, 0x4fd9 }, +/* 0x4fda */ { false, 0x4fda, 0x4fda }, +/* 0x4fdb */ { false, 0x4fdb, 0x4fdb }, +/* 0x4fdc */ { false, 0x4fdc, 0x4fdc }, +/* 0x4fdd */ { false, 0x4fdd, 0x4fdd }, +/* 0x4fde */ { false, 0x4fde, 0x4fde }, +/* 0x4fdf */ { false, 0x4fdf, 0x4fdf }, +/* 0x4fe0 */ { false, 0x4fe0, 0x4fe0 }, +/* 0x4fe1 */ { false, 0x4fe1, 0x4fe1 }, +/* 0x4fe2 */ { false, 0x4fe2, 0x4fe2 }, +/* 0x4fe3 */ { false, 0x4fe3, 0x4fe3 }, +/* 0x4fe4 */ { false, 0x4fe4, 0x4fe4 }, +/* 0x4fe5 */ { false, 0x4fe5, 0x4fe5 }, +/* 0x4fe6 */ { false, 0x4fe6, 0x4fe6 }, +/* 0x4fe7 */ { false, 0x4fe7, 0x4fe7 }, +/* 0x4fe8 */ { false, 0x4fe8, 0x4fe8 }, +/* 0x4fe9 */ { false, 0x4fe9, 0x4fe9 }, +/* 0x4fea */ { false, 0x4fea, 0x4fea }, +/* 0x4feb */ { false, 0x4feb, 0x4feb }, +/* 0x4fec */ { false, 0x4fec, 0x4fec }, +/* 0x4fed */ { false, 0x4fed, 0x4fed }, +/* 0x4fee */ { false, 0x4fee, 0x4fee }, +/* 0x4fef */ { false, 0x4fef, 0x4fef }, +/* 0x4ff0 */ { false, 0x4ff0, 0x4ff0 }, +/* 0x4ff1 */ { false, 0x4ff1, 0x4ff1 }, +/* 0x4ff2 */ { false, 0x4ff2, 0x4ff2 }, +/* 0x4ff3 */ { false, 0x4ff3, 0x4ff3 }, +/* 0x4ff4 */ { false, 0x4ff4, 0x4ff4 }, +/* 0x4ff5 */ { false, 0x4ff5, 0x4ff5 }, +/* 0x4ff6 */ { false, 0x4ff6, 0x4ff6 }, +/* 0x4ff7 */ { false, 0x4ff7, 0x4ff7 }, +/* 0x4ff8 */ { false, 0x4ff8, 0x4ff8 }, +/* 0x4ff9 */ { false, 0x4ff9, 0x4ff9 }, +/* 0x4ffa */ { false, 0x4ffa, 0x4ffa }, +/* 0x4ffb */ { false, 0x4ffb, 0x4ffb }, +/* 0x4ffc */ { false, 0x4ffc, 0x4ffc }, +/* 0x4ffd */ { false, 0x4ffd, 0x4ffd }, +/* 0x4ffe */ { false, 0x4ffe, 0x4ffe }, +/* 0x4fff */ { false, 0x4fff, 0x4fff }, +/* 0x5000 */ { false, 0x5000, 0x5000 }, +/* 0x5001 */ { false, 0x5001, 0x5001 }, +/* 0x5002 */ { false, 0x5002, 0x5002 }, +/* 0x5003 */ { false, 0x5003, 0x5003 }, +/* 0x5004 */ { false, 0x5004, 0x5004 }, +/* 0x5005 */ { false, 0x5005, 0x5005 }, +/* 0x5006 */ { false, 0x5006, 0x5006 }, +/* 0x5007 */ { false, 0x5007, 0x5007 }, +/* 0x5008 */ { false, 0x5008, 0x5008 }, +/* 0x5009 */ { false, 0x5009, 0x5009 }, +/* 0x500a */ { false, 0x500a, 0x500a }, +/* 0x500b */ { false, 0x500b, 0x500b }, +/* 0x500c */ { false, 0x500c, 0x500c }, +/* 0x500d */ { false, 0x500d, 0x500d }, +/* 0x500e */ { false, 0x500e, 0x500e }, +/* 0x500f */ { false, 0x500f, 0x500f }, +/* 0x5010 */ { false, 0x5010, 0x5010 }, +/* 0x5011 */ { false, 0x5011, 0x5011 }, +/* 0x5012 */ { false, 0x5012, 0x5012 }, +/* 0x5013 */ { false, 0x5013, 0x5013 }, +/* 0x5014 */ { false, 0x5014, 0x5014 }, +/* 0x5015 */ { false, 0x5015, 0x5015 }, +/* 0x5016 */ { false, 0x5016, 0x5016 }, +/* 0x5017 */ { false, 0x5017, 0x5017 }, +/* 0x5018 */ { false, 0x5018, 0x5018 }, +/* 0x5019 */ { false, 0x5019, 0x5019 }, +/* 0x501a */ { false, 0x501a, 0x501a }, +/* 0x501b */ { false, 0x501b, 0x501b }, +/* 0x501c */ { false, 0x501c, 0x501c }, +/* 0x501d */ { false, 0x501d, 0x501d }, +/* 0x501e */ { false, 0x501e, 0x501e }, +/* 0x501f */ { false, 0x501f, 0x501f }, +/* 0x5020 */ { false, 0x5020, 0x5020 }, +/* 0x5021 */ { false, 0x5021, 0x5021 }, +/* 0x5022 */ { false, 0x5022, 0x5022 }, +/* 0x5023 */ { false, 0x5023, 0x5023 }, +/* 0x5024 */ { false, 0x5024, 0x5024 }, +/* 0x5025 */ { false, 0x5025, 0x5025 }, +/* 0x5026 */ { false, 0x5026, 0x5026 }, +/* 0x5027 */ { false, 0x5027, 0x5027 }, +/* 0x5028 */ { false, 0x5028, 0x5028 }, +/* 0x5029 */ { false, 0x5029, 0x5029 }, +/* 0x502a */ { false, 0x502a, 0x502a }, +/* 0x502b */ { false, 0x502b, 0x502b }, +/* 0x502c */ { false, 0x502c, 0x502c }, +/* 0x502d */ { false, 0x502d, 0x502d }, +/* 0x502e */ { false, 0x502e, 0x502e }, +/* 0x502f */ { false, 0x502f, 0x502f }, +/* 0x5030 */ { false, 0x5030, 0x5030 }, +/* 0x5031 */ { false, 0x5031, 0x5031 }, +/* 0x5032 */ { false, 0x5032, 0x5032 }, +/* 0x5033 */ { false, 0x5033, 0x5033 }, +/* 0x5034 */ { false, 0x5034, 0x5034 }, +/* 0x5035 */ { false, 0x5035, 0x5035 }, +/* 0x5036 */ { false, 0x5036, 0x5036 }, +/* 0x5037 */ { false, 0x5037, 0x5037 }, +/* 0x5038 */ { false, 0x5038, 0x5038 }, +/* 0x5039 */ { false, 0x5039, 0x5039 }, +/* 0x503a */ { false, 0x503a, 0x503a }, +/* 0x503b */ { false, 0x503b, 0x503b }, +/* 0x503c */ { false, 0x503c, 0x503c }, +/* 0x503d */ { false, 0x503d, 0x503d }, +/* 0x503e */ { false, 0x503e, 0x503e }, +/* 0x503f */ { false, 0x503f, 0x503f }, +/* 0x5040 */ { false, 0x5040, 0x5040 }, +/* 0x5041 */ { false, 0x5041, 0x5041 }, +/* 0x5042 */ { false, 0x5042, 0x5042 }, +/* 0x5043 */ { false, 0x5043, 0x5043 }, +/* 0x5044 */ { false, 0x5044, 0x5044 }, +/* 0x5045 */ { false, 0x5045, 0x5045 }, +/* 0x5046 */ { false, 0x5046, 0x5046 }, +/* 0x5047 */ { false, 0x5047, 0x5047 }, +/* 0x5048 */ { false, 0x5048, 0x5048 }, +/* 0x5049 */ { false, 0x5049, 0x5049 }, +/* 0x504a */ { false, 0x504a, 0x504a }, +/* 0x504b */ { false, 0x504b, 0x504b }, +/* 0x504c */ { false, 0x504c, 0x504c }, +/* 0x504d */ { false, 0x504d, 0x504d }, +/* 0x504e */ { false, 0x504e, 0x504e }, +/* 0x504f */ { false, 0x504f, 0x504f }, +/* 0x5050 */ { false, 0x5050, 0x5050 }, +/* 0x5051 */ { false, 0x5051, 0x5051 }, +/* 0x5052 */ { false, 0x5052, 0x5052 }, +/* 0x5053 */ { false, 0x5053, 0x5053 }, +/* 0x5054 */ { false, 0x5054, 0x5054 }, +/* 0x5055 */ { false, 0x5055, 0x5055 }, +/* 0x5056 */ { false, 0x5056, 0x5056 }, +/* 0x5057 */ { false, 0x5057, 0x5057 }, +/* 0x5058 */ { false, 0x5058, 0x5058 }, +/* 0x5059 */ { false, 0x5059, 0x5059 }, +/* 0x505a */ { false, 0x505a, 0x505a }, +/* 0x505b */ { false, 0x505b, 0x505b }, +/* 0x505c */ { false, 0x505c, 0x505c }, +/* 0x505d */ { false, 0x505d, 0x505d }, +/* 0x505e */ { false, 0x505e, 0x505e }, +/* 0x505f */ { false, 0x505f, 0x505f }, +/* 0x5060 */ { false, 0x5060, 0x5060 }, +/* 0x5061 */ { false, 0x5061, 0x5061 }, +/* 0x5062 */ { false, 0x5062, 0x5062 }, +/* 0x5063 */ { false, 0x5063, 0x5063 }, +/* 0x5064 */ { false, 0x5064, 0x5064 }, +/* 0x5065 */ { false, 0x5065, 0x5065 }, +/* 0x5066 */ { false, 0x5066, 0x5066 }, +/* 0x5067 */ { false, 0x5067, 0x5067 }, +/* 0x5068 */ { false, 0x5068, 0x5068 }, +/* 0x5069 */ { false, 0x5069, 0x5069 }, +/* 0x506a */ { false, 0x506a, 0x506a }, +/* 0x506b */ { false, 0x506b, 0x506b }, +/* 0x506c */ { false, 0x506c, 0x506c }, +/* 0x506d */ { false, 0x506d, 0x506d }, +/* 0x506e */ { false, 0x506e, 0x506e }, +/* 0x506f */ { false, 0x506f, 0x506f }, +/* 0x5070 */ { false, 0x5070, 0x5070 }, +/* 0x5071 */ { false, 0x5071, 0x5071 }, +/* 0x5072 */ { false, 0x5072, 0x5072 }, +/* 0x5073 */ { false, 0x5073, 0x5073 }, +/* 0x5074 */ { false, 0x5074, 0x5074 }, +/* 0x5075 */ { false, 0x5075, 0x5075 }, +/* 0x5076 */ { false, 0x5076, 0x5076 }, +/* 0x5077 */ { false, 0x5077, 0x5077 }, +/* 0x5078 */ { false, 0x5078, 0x5078 }, +/* 0x5079 */ { false, 0x5079, 0x5079 }, +/* 0x507a */ { false, 0x507a, 0x507a }, +/* 0x507b */ { false, 0x507b, 0x507b }, +/* 0x507c */ { false, 0x507c, 0x507c }, +/* 0x507d */ { false, 0x507d, 0x507d }, +/* 0x507e */ { false, 0x507e, 0x507e }, +/* 0x507f */ { false, 0x507f, 0x507f }, +/* 0x5080 */ { false, 0x5080, 0x5080 }, +/* 0x5081 */ { false, 0x5081, 0x5081 }, +/* 0x5082 */ { false, 0x5082, 0x5082 }, +/* 0x5083 */ { false, 0x5083, 0x5083 }, +/* 0x5084 */ { false, 0x5084, 0x5084 }, +/* 0x5085 */ { false, 0x5085, 0x5085 }, +/* 0x5086 */ { false, 0x5086, 0x5086 }, +/* 0x5087 */ { false, 0x5087, 0x5087 }, +/* 0x5088 */ { false, 0x5088, 0x5088 }, +/* 0x5089 */ { false, 0x5089, 0x5089 }, +/* 0x508a */ { false, 0x508a, 0x508a }, +/* 0x508b */ { false, 0x508b, 0x508b }, +/* 0x508c */ { false, 0x508c, 0x508c }, +/* 0x508d */ { false, 0x508d, 0x508d }, +/* 0x508e */ { false, 0x508e, 0x508e }, +/* 0x508f */ { false, 0x508f, 0x508f }, +/* 0x5090 */ { false, 0x5090, 0x5090 }, +/* 0x5091 */ { false, 0x5091, 0x5091 }, +/* 0x5092 */ { false, 0x5092, 0x5092 }, +/* 0x5093 */ { false, 0x5093, 0x5093 }, +/* 0x5094 */ { false, 0x5094, 0x5094 }, +/* 0x5095 */ { false, 0x5095, 0x5095 }, +/* 0x5096 */ { false, 0x5096, 0x5096 }, +/* 0x5097 */ { false, 0x5097, 0x5097 }, +/* 0x5098 */ { false, 0x5098, 0x5098 }, +/* 0x5099 */ { false, 0x5099, 0x5099 }, +/* 0x509a */ { false, 0x509a, 0x509a }, +/* 0x509b */ { false, 0x509b, 0x509b }, +/* 0x509c */ { false, 0x509c, 0x509c }, +/* 0x509d */ { false, 0x509d, 0x509d }, +/* 0x509e */ { false, 0x509e, 0x509e }, +/* 0x509f */ { false, 0x509f, 0x509f }, +/* 0x50a0 */ { false, 0x50a0, 0x50a0 }, +/* 0x50a1 */ { false, 0x50a1, 0x50a1 }, +/* 0x50a2 */ { false, 0x50a2, 0x50a2 }, +/* 0x50a3 */ { false, 0x50a3, 0x50a3 }, +/* 0x50a4 */ { false, 0x50a4, 0x50a4 }, +/* 0x50a5 */ { false, 0x50a5, 0x50a5 }, +/* 0x50a6 */ { false, 0x50a6, 0x50a6 }, +/* 0x50a7 */ { false, 0x50a7, 0x50a7 }, +/* 0x50a8 */ { false, 0x50a8, 0x50a8 }, +/* 0x50a9 */ { false, 0x50a9, 0x50a9 }, +/* 0x50aa */ { false, 0x50aa, 0x50aa }, +/* 0x50ab */ { false, 0x50ab, 0x50ab }, +/* 0x50ac */ { false, 0x50ac, 0x50ac }, +/* 0x50ad */ { false, 0x50ad, 0x50ad }, +/* 0x50ae */ { false, 0x50ae, 0x50ae }, +/* 0x50af */ { false, 0x50af, 0x50af }, +/* 0x50b0 */ { false, 0x50b0, 0x50b0 }, +/* 0x50b1 */ { false, 0x50b1, 0x50b1 }, +/* 0x50b2 */ { false, 0x50b2, 0x50b2 }, +/* 0x50b3 */ { false, 0x50b3, 0x50b3 }, +/* 0x50b4 */ { false, 0x50b4, 0x50b4 }, +/* 0x50b5 */ { false, 0x50b5, 0x50b5 }, +/* 0x50b6 */ { false, 0x50b6, 0x50b6 }, +/* 0x50b7 */ { false, 0x50b7, 0x50b7 }, +/* 0x50b8 */ { false, 0x50b8, 0x50b8 }, +/* 0x50b9 */ { false, 0x50b9, 0x50b9 }, +/* 0x50ba */ { false, 0x50ba, 0x50ba }, +/* 0x50bb */ { false, 0x50bb, 0x50bb }, +/* 0x50bc */ { false, 0x50bc, 0x50bc }, +/* 0x50bd */ { false, 0x50bd, 0x50bd }, +/* 0x50be */ { false, 0x50be, 0x50be }, +/* 0x50bf */ { false, 0x50bf, 0x50bf }, +/* 0x50c0 */ { false, 0x50c0, 0x50c0 }, +/* 0x50c1 */ { false, 0x50c1, 0x50c1 }, +/* 0x50c2 */ { false, 0x50c2, 0x50c2 }, +/* 0x50c3 */ { false, 0x50c3, 0x50c3 }, +/* 0x50c4 */ { false, 0x50c4, 0x50c4 }, +/* 0x50c5 */ { false, 0x50c5, 0x50c5 }, +/* 0x50c6 */ { false, 0x50c6, 0x50c6 }, +/* 0x50c7 */ { false, 0x50c7, 0x50c7 }, +/* 0x50c8 */ { false, 0x50c8, 0x50c8 }, +/* 0x50c9 */ { false, 0x50c9, 0x50c9 }, +/* 0x50ca */ { false, 0x50ca, 0x50ca }, +/* 0x50cb */ { false, 0x50cb, 0x50cb }, +/* 0x50cc */ { false, 0x50cc, 0x50cc }, +/* 0x50cd */ { false, 0x50cd, 0x50cd }, +/* 0x50ce */ { false, 0x50ce, 0x50ce }, +/* 0x50cf */ { false, 0x50cf, 0x50cf }, +/* 0x50d0 */ { false, 0x50d0, 0x50d0 }, +/* 0x50d1 */ { false, 0x50d1, 0x50d1 }, +/* 0x50d2 */ { false, 0x50d2, 0x50d2 }, +/* 0x50d3 */ { false, 0x50d3, 0x50d3 }, +/* 0x50d4 */ { false, 0x50d4, 0x50d4 }, +/* 0x50d5 */ { false, 0x50d5, 0x50d5 }, +/* 0x50d6 */ { false, 0x50d6, 0x50d6 }, +/* 0x50d7 */ { false, 0x50d7, 0x50d7 }, +/* 0x50d8 */ { false, 0x50d8, 0x50d8 }, +/* 0x50d9 */ { false, 0x50d9, 0x50d9 }, +/* 0x50da */ { false, 0x50da, 0x50da }, +/* 0x50db */ { false, 0x50db, 0x50db }, +/* 0x50dc */ { false, 0x50dc, 0x50dc }, +/* 0x50dd */ { false, 0x50dd, 0x50dd }, +/* 0x50de */ { false, 0x50de, 0x50de }, +/* 0x50df */ { false, 0x50df, 0x50df }, +/* 0x50e0 */ { false, 0x50e0, 0x50e0 }, +/* 0x50e1 */ { false, 0x50e1, 0x50e1 }, +/* 0x50e2 */ { false, 0x50e2, 0x50e2 }, +/* 0x50e3 */ { false, 0x50e3, 0x50e3 }, +/* 0x50e4 */ { false, 0x50e4, 0x50e4 }, +/* 0x50e5 */ { false, 0x50e5, 0x50e5 }, +/* 0x50e6 */ { false, 0x50e6, 0x50e6 }, +/* 0x50e7 */ { false, 0x50e7, 0x50e7 }, +/* 0x50e8 */ { false, 0x50e8, 0x50e8 }, +/* 0x50e9 */ { false, 0x50e9, 0x50e9 }, +/* 0x50ea */ { false, 0x50ea, 0x50ea }, +/* 0x50eb */ { false, 0x50eb, 0x50eb }, +/* 0x50ec */ { false, 0x50ec, 0x50ec }, +/* 0x50ed */ { false, 0x50ed, 0x50ed }, +/* 0x50ee */ { false, 0x50ee, 0x50ee }, +/* 0x50ef */ { false, 0x50ef, 0x50ef }, +/* 0x50f0 */ { false, 0x50f0, 0x50f0 }, +/* 0x50f1 */ { false, 0x50f1, 0x50f1 }, +/* 0x50f2 */ { false, 0x50f2, 0x50f2 }, +/* 0x50f3 */ { false, 0x50f3, 0x50f3 }, +/* 0x50f4 */ { false, 0x50f4, 0x50f4 }, +/* 0x50f5 */ { false, 0x50f5, 0x50f5 }, +/* 0x50f6 */ { false, 0x50f6, 0x50f6 }, +/* 0x50f7 */ { false, 0x50f7, 0x50f7 }, +/* 0x50f8 */ { false, 0x50f8, 0x50f8 }, +/* 0x50f9 */ { false, 0x50f9, 0x50f9 }, +/* 0x50fa */ { false, 0x50fa, 0x50fa }, +/* 0x50fb */ { false, 0x50fb, 0x50fb }, +/* 0x50fc */ { false, 0x50fc, 0x50fc }, +/* 0x50fd */ { false, 0x50fd, 0x50fd }, +/* 0x50fe */ { false, 0x50fe, 0x50fe }, +/* 0x50ff */ { false, 0x50ff, 0x50ff }, +/* 0x5100 */ { false, 0x5100, 0x5100 }, +/* 0x5101 */ { false, 0x5101, 0x5101 }, +/* 0x5102 */ { false, 0x5102, 0x5102 }, +/* 0x5103 */ { false, 0x5103, 0x5103 }, +/* 0x5104 */ { false, 0x5104, 0x5104 }, +/* 0x5105 */ { false, 0x5105, 0x5105 }, +/* 0x5106 */ { false, 0x5106, 0x5106 }, +/* 0x5107 */ { false, 0x5107, 0x5107 }, +/* 0x5108 */ { false, 0x5108, 0x5108 }, +/* 0x5109 */ { false, 0x5109, 0x5109 }, +/* 0x510a */ { false, 0x510a, 0x510a }, +/* 0x510b */ { false, 0x510b, 0x510b }, +/* 0x510c */ { false, 0x510c, 0x510c }, +/* 0x510d */ { false, 0x510d, 0x510d }, +/* 0x510e */ { false, 0x510e, 0x510e }, +/* 0x510f */ { false, 0x510f, 0x510f }, +/* 0x5110 */ { false, 0x5110, 0x5110 }, +/* 0x5111 */ { false, 0x5111, 0x5111 }, +/* 0x5112 */ { false, 0x5112, 0x5112 }, +/* 0x5113 */ { false, 0x5113, 0x5113 }, +/* 0x5114 */ { false, 0x5114, 0x5114 }, +/* 0x5115 */ { false, 0x5115, 0x5115 }, +/* 0x5116 */ { false, 0x5116, 0x5116 }, +/* 0x5117 */ { false, 0x5117, 0x5117 }, +/* 0x5118 */ { false, 0x5118, 0x5118 }, +/* 0x5119 */ { false, 0x5119, 0x5119 }, +/* 0x511a */ { false, 0x511a, 0x511a }, +/* 0x511b */ { false, 0x511b, 0x511b }, +/* 0x511c */ { false, 0x511c, 0x511c }, +/* 0x511d */ { false, 0x511d, 0x511d }, +/* 0x511e */ { false, 0x511e, 0x511e }, +/* 0x511f */ { false, 0x511f, 0x511f }, +/* 0x5120 */ { false, 0x5120, 0x5120 }, +/* 0x5121 */ { false, 0x5121, 0x5121 }, +/* 0x5122 */ { false, 0x5122, 0x5122 }, +/* 0x5123 */ { false, 0x5123, 0x5123 }, +/* 0x5124 */ { false, 0x5124, 0x5124 }, +/* 0x5125 */ { false, 0x5125, 0x5125 }, +/* 0x5126 */ { false, 0x5126, 0x5126 }, +/* 0x5127 */ { false, 0x5127, 0x5127 }, +/* 0x5128 */ { false, 0x5128, 0x5128 }, +/* 0x5129 */ { false, 0x5129, 0x5129 }, +/* 0x512a */ { false, 0x512a, 0x512a }, +/* 0x512b */ { false, 0x512b, 0x512b }, +/* 0x512c */ { false, 0x512c, 0x512c }, +/* 0x512d */ { false, 0x512d, 0x512d }, +/* 0x512e */ { false, 0x512e, 0x512e }, +/* 0x512f */ { false, 0x512f, 0x512f }, +/* 0x5130 */ { false, 0x5130, 0x5130 }, +/* 0x5131 */ { false, 0x5131, 0x5131 }, +/* 0x5132 */ { false, 0x5132, 0x5132 }, +/* 0x5133 */ { false, 0x5133, 0x5133 }, +/* 0x5134 */ { false, 0x5134, 0x5134 }, +/* 0x5135 */ { false, 0x5135, 0x5135 }, +/* 0x5136 */ { false, 0x5136, 0x5136 }, +/* 0x5137 */ { false, 0x5137, 0x5137 }, +/* 0x5138 */ { false, 0x5138, 0x5138 }, +/* 0x5139 */ { false, 0x5139, 0x5139 }, +/* 0x513a */ { false, 0x513a, 0x513a }, +/* 0x513b */ { false, 0x513b, 0x513b }, +/* 0x513c */ { false, 0x513c, 0x513c }, +/* 0x513d */ { false, 0x513d, 0x513d }, +/* 0x513e */ { false, 0x513e, 0x513e }, +/* 0x513f */ { false, 0x513f, 0x513f }, +/* 0x5140 */ { false, 0x5140, 0x5140 }, +/* 0x5141 */ { false, 0x5141, 0x5141 }, +/* 0x5142 */ { false, 0x5142, 0x5142 }, +/* 0x5143 */ { false, 0x5143, 0x5143 }, +/* 0x5144 */ { false, 0x5144, 0x5144 }, +/* 0x5145 */ { false, 0x5145, 0x5145 }, +/* 0x5146 */ { false, 0x5146, 0x5146 }, +/* 0x5147 */ { false, 0x5147, 0x5147 }, +/* 0x5148 */ { false, 0x5148, 0x5148 }, +/* 0x5149 */ { false, 0x5149, 0x5149 }, +/* 0x514a */ { false, 0x514a, 0x514a }, +/* 0x514b */ { false, 0x514b, 0x514b }, +/* 0x514c */ { false, 0x514c, 0x514c }, +/* 0x514d */ { false, 0x514d, 0x514d }, +/* 0x514e */ { false, 0x514e, 0x514e }, +/* 0x514f */ { false, 0x514f, 0x514f }, +/* 0x5150 */ { false, 0x5150, 0x5150 }, +/* 0x5151 */ { false, 0x5151, 0x5151 }, +/* 0x5152 */ { false, 0x5152, 0x5152 }, +/* 0x5153 */ { false, 0x5153, 0x5153 }, +/* 0x5154 */ { false, 0x5154, 0x5154 }, +/* 0x5155 */ { false, 0x5155, 0x5155 }, +/* 0x5156 */ { false, 0x5156, 0x5156 }, +/* 0x5157 */ { false, 0x5157, 0x5157 }, +/* 0x5158 */ { false, 0x5158, 0x5158 }, +/* 0x5159 */ { false, 0x5159, 0x5159 }, +/* 0x515a */ { false, 0x515a, 0x515a }, +/* 0x515b */ { false, 0x515b, 0x515b }, +/* 0x515c */ { false, 0x515c, 0x515c }, +/* 0x515d */ { false, 0x515d, 0x515d }, +/* 0x515e */ { false, 0x515e, 0x515e }, +/* 0x515f */ { false, 0x515f, 0x515f }, +/* 0x5160 */ { false, 0x5160, 0x5160 }, +/* 0x5161 */ { false, 0x5161, 0x5161 }, +/* 0x5162 */ { false, 0x5162, 0x5162 }, +/* 0x5163 */ { false, 0x5163, 0x5163 }, +/* 0x5164 */ { false, 0x5164, 0x5164 }, +/* 0x5165 */ { false, 0x5165, 0x5165 }, +/* 0x5166 */ { false, 0x5166, 0x5166 }, +/* 0x5167 */ { false, 0x5167, 0x5167 }, +/* 0x5168 */ { false, 0x5168, 0x5168 }, +/* 0x5169 */ { false, 0x5169, 0x5169 }, +/* 0x516a */ { false, 0x516a, 0x516a }, +/* 0x516b */ { false, 0x516b, 0x516b }, +/* 0x516c */ { false, 0x516c, 0x516c }, +/* 0x516d */ { false, 0x516d, 0x516d }, +/* 0x516e */ { false, 0x516e, 0x516e }, +/* 0x516f */ { false, 0x516f, 0x516f }, +/* 0x5170 */ { false, 0x5170, 0x5170 }, +/* 0x5171 */ { false, 0x5171, 0x5171 }, +/* 0x5172 */ { false, 0x5172, 0x5172 }, +/* 0x5173 */ { false, 0x5173, 0x5173 }, +/* 0x5174 */ { false, 0x5174, 0x5174 }, +/* 0x5175 */ { false, 0x5175, 0x5175 }, +/* 0x5176 */ { false, 0x5176, 0x5176 }, +/* 0x5177 */ { false, 0x5177, 0x5177 }, +/* 0x5178 */ { false, 0x5178, 0x5178 }, +/* 0x5179 */ { false, 0x5179, 0x5179 }, +/* 0x517a */ { false, 0x517a, 0x517a }, +/* 0x517b */ { false, 0x517b, 0x517b }, +/* 0x517c */ { false, 0x517c, 0x517c }, +/* 0x517d */ { false, 0x517d, 0x517d }, +/* 0x517e */ { false, 0x517e, 0x517e }, +/* 0x517f */ { false, 0x517f, 0x517f }, +/* 0x5180 */ { false, 0x5180, 0x5180 }, +/* 0x5181 */ { false, 0x5181, 0x5181 }, +/* 0x5182 */ { false, 0x5182, 0x5182 }, +/* 0x5183 */ { false, 0x5183, 0x5183 }, +/* 0x5184 */ { false, 0x5184, 0x5184 }, +/* 0x5185 */ { false, 0x5185, 0x5185 }, +/* 0x5186 */ { false, 0x5186, 0x5186 }, +/* 0x5187 */ { false, 0x5187, 0x5187 }, +/* 0x5188 */ { false, 0x5188, 0x5188 }, +/* 0x5189 */ { false, 0x5189, 0x5189 }, +/* 0x518a */ { false, 0x518a, 0x518a }, +/* 0x518b */ { false, 0x518b, 0x518b }, +/* 0x518c */ { false, 0x518c, 0x518c }, +/* 0x518d */ { false, 0x518d, 0x518d }, +/* 0x518e */ { false, 0x518e, 0x518e }, +/* 0x518f */ { false, 0x518f, 0x518f }, +/* 0x5190 */ { false, 0x5190, 0x5190 }, +/* 0x5191 */ { false, 0x5191, 0x5191 }, +/* 0x5192 */ { false, 0x5192, 0x5192 }, +/* 0x5193 */ { false, 0x5193, 0x5193 }, +/* 0x5194 */ { false, 0x5194, 0x5194 }, +/* 0x5195 */ { false, 0x5195, 0x5195 }, +/* 0x5196 */ { false, 0x5196, 0x5196 }, +/* 0x5197 */ { false, 0x5197, 0x5197 }, +/* 0x5198 */ { false, 0x5198, 0x5198 }, +/* 0x5199 */ { false, 0x5199, 0x5199 }, +/* 0x519a */ { false, 0x519a, 0x519a }, +/* 0x519b */ { false, 0x519b, 0x519b }, +/* 0x519c */ { false, 0x519c, 0x519c }, +/* 0x519d */ { false, 0x519d, 0x519d }, +/* 0x519e */ { false, 0x519e, 0x519e }, +/* 0x519f */ { false, 0x519f, 0x519f }, +/* 0x51a0 */ { false, 0x51a0, 0x51a0 }, +/* 0x51a1 */ { false, 0x51a1, 0x51a1 }, +/* 0x51a2 */ { false, 0x51a2, 0x51a2 }, +/* 0x51a3 */ { false, 0x51a3, 0x51a3 }, +/* 0x51a4 */ { false, 0x51a4, 0x51a4 }, +/* 0x51a5 */ { false, 0x51a5, 0x51a5 }, +/* 0x51a6 */ { false, 0x51a6, 0x51a6 }, +/* 0x51a7 */ { false, 0x51a7, 0x51a7 }, +/* 0x51a8 */ { false, 0x51a8, 0x51a8 }, +/* 0x51a9 */ { false, 0x51a9, 0x51a9 }, +/* 0x51aa */ { false, 0x51aa, 0x51aa }, +/* 0x51ab */ { false, 0x51ab, 0x51ab }, +/* 0x51ac */ { false, 0x51ac, 0x51ac }, +/* 0x51ad */ { false, 0x51ad, 0x51ad }, +/* 0x51ae */ { false, 0x51ae, 0x51ae }, +/* 0x51af */ { false, 0x51af, 0x51af }, +/* 0x51b0 */ { false, 0x51b0, 0x51b0 }, +/* 0x51b1 */ { false, 0x51b1, 0x51b1 }, +/* 0x51b2 */ { false, 0x51b2, 0x51b2 }, +/* 0x51b3 */ { false, 0x51b3, 0x51b3 }, +/* 0x51b4 */ { false, 0x51b4, 0x51b4 }, +/* 0x51b5 */ { false, 0x51b5, 0x51b5 }, +/* 0x51b6 */ { false, 0x51b6, 0x51b6 }, +/* 0x51b7 */ { false, 0x51b7, 0x51b7 }, +/* 0x51b8 */ { false, 0x51b8, 0x51b8 }, +/* 0x51b9 */ { false, 0x51b9, 0x51b9 }, +/* 0x51ba */ { false, 0x51ba, 0x51ba }, +/* 0x51bb */ { false, 0x51bb, 0x51bb }, +/* 0x51bc */ { false, 0x51bc, 0x51bc }, +/* 0x51bd */ { false, 0x51bd, 0x51bd }, +/* 0x51be */ { false, 0x51be, 0x51be }, +/* 0x51bf */ { false, 0x51bf, 0x51bf }, +/* 0x51c0 */ { false, 0x51c0, 0x51c0 }, +/* 0x51c1 */ { false, 0x51c1, 0x51c1 }, +/* 0x51c2 */ { false, 0x51c2, 0x51c2 }, +/* 0x51c3 */ { false, 0x51c3, 0x51c3 }, +/* 0x51c4 */ { false, 0x51c4, 0x51c4 }, +/* 0x51c5 */ { false, 0x51c5, 0x51c5 }, +/* 0x51c6 */ { false, 0x51c6, 0x51c6 }, +/* 0x51c7 */ { false, 0x51c7, 0x51c7 }, +/* 0x51c8 */ { false, 0x51c8, 0x51c8 }, +/* 0x51c9 */ { false, 0x51c9, 0x51c9 }, +/* 0x51ca */ { false, 0x51ca, 0x51ca }, +/* 0x51cb */ { false, 0x51cb, 0x51cb }, +/* 0x51cc */ { false, 0x51cc, 0x51cc }, +/* 0x51cd */ { false, 0x51cd, 0x51cd }, +/* 0x51ce */ { false, 0x51ce, 0x51ce }, +/* 0x51cf */ { false, 0x51cf, 0x51cf }, +/* 0x51d0 */ { false, 0x51d0, 0x51d0 }, +/* 0x51d1 */ { false, 0x51d1, 0x51d1 }, +/* 0x51d2 */ { false, 0x51d2, 0x51d2 }, +/* 0x51d3 */ { false, 0x51d3, 0x51d3 }, +/* 0x51d4 */ { false, 0x51d4, 0x51d4 }, +/* 0x51d5 */ { false, 0x51d5, 0x51d5 }, +/* 0x51d6 */ { false, 0x51d6, 0x51d6 }, +/* 0x51d7 */ { false, 0x51d7, 0x51d7 }, +/* 0x51d8 */ { false, 0x51d8, 0x51d8 }, +/* 0x51d9 */ { false, 0x51d9, 0x51d9 }, +/* 0x51da */ { false, 0x51da, 0x51da }, +/* 0x51db */ { false, 0x51db, 0x51db }, +/* 0x51dc */ { false, 0x51dc, 0x51dc }, +/* 0x51dd */ { false, 0x51dd, 0x51dd }, +/* 0x51de */ { false, 0x51de, 0x51de }, +/* 0x51df */ { false, 0x51df, 0x51df }, +/* 0x51e0 */ { false, 0x51e0, 0x51e0 }, +/* 0x51e1 */ { false, 0x51e1, 0x51e1 }, +/* 0x51e2 */ { false, 0x51e2, 0x51e2 }, +/* 0x51e3 */ { false, 0x51e3, 0x51e3 }, +/* 0x51e4 */ { false, 0x51e4, 0x51e4 }, +/* 0x51e5 */ { false, 0x51e5, 0x51e5 }, +/* 0x51e6 */ { false, 0x51e6, 0x51e6 }, +/* 0x51e7 */ { false, 0x51e7, 0x51e7 }, +/* 0x51e8 */ { false, 0x51e8, 0x51e8 }, +/* 0x51e9 */ { false, 0x51e9, 0x51e9 }, +/* 0x51ea */ { false, 0x51ea, 0x51ea }, +/* 0x51eb */ { false, 0x51eb, 0x51eb }, +/* 0x51ec */ { false, 0x51ec, 0x51ec }, +/* 0x51ed */ { false, 0x51ed, 0x51ed }, +/* 0x51ee */ { false, 0x51ee, 0x51ee }, +/* 0x51ef */ { false, 0x51ef, 0x51ef }, +/* 0x51f0 */ { false, 0x51f0, 0x51f0 }, +/* 0x51f1 */ { false, 0x51f1, 0x51f1 }, +/* 0x51f2 */ { false, 0x51f2, 0x51f2 }, +/* 0x51f3 */ { false, 0x51f3, 0x51f3 }, +/* 0x51f4 */ { false, 0x51f4, 0x51f4 }, +/* 0x51f5 */ { false, 0x51f5, 0x51f5 }, +/* 0x51f6 */ { false, 0x51f6, 0x51f6 }, +/* 0x51f7 */ { false, 0x51f7, 0x51f7 }, +/* 0x51f8 */ { false, 0x51f8, 0x51f8 }, +/* 0x51f9 */ { false, 0x51f9, 0x51f9 }, +/* 0x51fa */ { false, 0x51fa, 0x51fa }, +/* 0x51fb */ { false, 0x51fb, 0x51fb }, +/* 0x51fc */ { false, 0x51fc, 0x51fc }, +/* 0x51fd */ { false, 0x51fd, 0x51fd }, +/* 0x51fe */ { false, 0x51fe, 0x51fe }, +/* 0x51ff */ { false, 0x51ff, 0x51ff }, +/* 0x5200 */ { false, 0x5200, 0x5200 }, +/* 0x5201 */ { false, 0x5201, 0x5201 }, +/* 0x5202 */ { false, 0x5202, 0x5202 }, +/* 0x5203 */ { false, 0x5203, 0x5203 }, +/* 0x5204 */ { false, 0x5204, 0x5204 }, +/* 0x5205 */ { false, 0x5205, 0x5205 }, +/* 0x5206 */ { false, 0x5206, 0x5206 }, +/* 0x5207 */ { false, 0x5207, 0x5207 }, +/* 0x5208 */ { false, 0x5208, 0x5208 }, +/* 0x5209 */ { false, 0x5209, 0x5209 }, +/* 0x520a */ { false, 0x520a, 0x520a }, +/* 0x520b */ { false, 0x520b, 0x520b }, +/* 0x520c */ { false, 0x520c, 0x520c }, +/* 0x520d */ { false, 0x520d, 0x520d }, +/* 0x520e */ { false, 0x520e, 0x520e }, +/* 0x520f */ { false, 0x520f, 0x520f }, +/* 0x5210 */ { false, 0x5210, 0x5210 }, +/* 0x5211 */ { false, 0x5211, 0x5211 }, +/* 0x5212 */ { false, 0x5212, 0x5212 }, +/* 0x5213 */ { false, 0x5213, 0x5213 }, +/* 0x5214 */ { false, 0x5214, 0x5214 }, +/* 0x5215 */ { false, 0x5215, 0x5215 }, +/* 0x5216 */ { false, 0x5216, 0x5216 }, +/* 0x5217 */ { false, 0x5217, 0x5217 }, +/* 0x5218 */ { false, 0x5218, 0x5218 }, +/* 0x5219 */ { false, 0x5219, 0x5219 }, +/* 0x521a */ { false, 0x521a, 0x521a }, +/* 0x521b */ { false, 0x521b, 0x521b }, +/* 0x521c */ { false, 0x521c, 0x521c }, +/* 0x521d */ { false, 0x521d, 0x521d }, +/* 0x521e */ { false, 0x521e, 0x521e }, +/* 0x521f */ { false, 0x521f, 0x521f }, +/* 0x5220 */ { false, 0x5220, 0x5220 }, +/* 0x5221 */ { false, 0x5221, 0x5221 }, +/* 0x5222 */ { false, 0x5222, 0x5222 }, +/* 0x5223 */ { false, 0x5223, 0x5223 }, +/* 0x5224 */ { false, 0x5224, 0x5224 }, +/* 0x5225 */ { false, 0x5225, 0x5225 }, +/* 0x5226 */ { false, 0x5226, 0x5226 }, +/* 0x5227 */ { false, 0x5227, 0x5227 }, +/* 0x5228 */ { false, 0x5228, 0x5228 }, +/* 0x5229 */ { false, 0x5229, 0x5229 }, +/* 0x522a */ { false, 0x522a, 0x522a }, +/* 0x522b */ { false, 0x522b, 0x522b }, +/* 0x522c */ { false, 0x522c, 0x522c }, +/* 0x522d */ { false, 0x522d, 0x522d }, +/* 0x522e */ { false, 0x522e, 0x522e }, +/* 0x522f */ { false, 0x522f, 0x522f }, +/* 0x5230 */ { false, 0x5230, 0x5230 }, +/* 0x5231 */ { false, 0x5231, 0x5231 }, +/* 0x5232 */ { false, 0x5232, 0x5232 }, +/* 0x5233 */ { false, 0x5233, 0x5233 }, +/* 0x5234 */ { false, 0x5234, 0x5234 }, +/* 0x5235 */ { false, 0x5235, 0x5235 }, +/* 0x5236 */ { false, 0x5236, 0x5236 }, +/* 0x5237 */ { false, 0x5237, 0x5237 }, +/* 0x5238 */ { false, 0x5238, 0x5238 }, +/* 0x5239 */ { false, 0x5239, 0x5239 }, +/* 0x523a */ { false, 0x523a, 0x523a }, +/* 0x523b */ { false, 0x523b, 0x523b }, +/* 0x523c */ { false, 0x523c, 0x523c }, +/* 0x523d */ { false, 0x523d, 0x523d }, +/* 0x523e */ { false, 0x523e, 0x523e }, +/* 0x523f */ { false, 0x523f, 0x523f }, +/* 0x5240 */ { false, 0x5240, 0x5240 }, +/* 0x5241 */ { false, 0x5241, 0x5241 }, +/* 0x5242 */ { false, 0x5242, 0x5242 }, +/* 0x5243 */ { false, 0x5243, 0x5243 }, +/* 0x5244 */ { false, 0x5244, 0x5244 }, +/* 0x5245 */ { false, 0x5245, 0x5245 }, +/* 0x5246 */ { false, 0x5246, 0x5246 }, +/* 0x5247 */ { false, 0x5247, 0x5247 }, +/* 0x5248 */ { false, 0x5248, 0x5248 }, +/* 0x5249 */ { false, 0x5249, 0x5249 }, +/* 0x524a */ { false, 0x524a, 0x524a }, +/* 0x524b */ { false, 0x524b, 0x524b }, +/* 0x524c */ { false, 0x524c, 0x524c }, +/* 0x524d */ { false, 0x524d, 0x524d }, +/* 0x524e */ { false, 0x524e, 0x524e }, +/* 0x524f */ { false, 0x524f, 0x524f }, +/* 0x5250 */ { false, 0x5250, 0x5250 }, +/* 0x5251 */ { false, 0x5251, 0x5251 }, +/* 0x5252 */ { false, 0x5252, 0x5252 }, +/* 0x5253 */ { false, 0x5253, 0x5253 }, +/* 0x5254 */ { false, 0x5254, 0x5254 }, +/* 0x5255 */ { false, 0x5255, 0x5255 }, +/* 0x5256 */ { false, 0x5256, 0x5256 }, +/* 0x5257 */ { false, 0x5257, 0x5257 }, +/* 0x5258 */ { false, 0x5258, 0x5258 }, +/* 0x5259 */ { false, 0x5259, 0x5259 }, +/* 0x525a */ { false, 0x525a, 0x525a }, +/* 0x525b */ { false, 0x525b, 0x525b }, +/* 0x525c */ { false, 0x525c, 0x525c }, +/* 0x525d */ { false, 0x525d, 0x525d }, +/* 0x525e */ { false, 0x525e, 0x525e }, +/* 0x525f */ { false, 0x525f, 0x525f }, +/* 0x5260 */ { false, 0x5260, 0x5260 }, +/* 0x5261 */ { false, 0x5261, 0x5261 }, +/* 0x5262 */ { false, 0x5262, 0x5262 }, +/* 0x5263 */ { false, 0x5263, 0x5263 }, +/* 0x5264 */ { false, 0x5264, 0x5264 }, +/* 0x5265 */ { false, 0x5265, 0x5265 }, +/* 0x5266 */ { false, 0x5266, 0x5266 }, +/* 0x5267 */ { false, 0x5267, 0x5267 }, +/* 0x5268 */ { false, 0x5268, 0x5268 }, +/* 0x5269 */ { false, 0x5269, 0x5269 }, +/* 0x526a */ { false, 0x526a, 0x526a }, +/* 0x526b */ { false, 0x526b, 0x526b }, +/* 0x526c */ { false, 0x526c, 0x526c }, +/* 0x526d */ { false, 0x526d, 0x526d }, +/* 0x526e */ { false, 0x526e, 0x526e }, +/* 0x526f */ { false, 0x526f, 0x526f }, +/* 0x5270 */ { false, 0x5270, 0x5270 }, +/* 0x5271 */ { false, 0x5271, 0x5271 }, +/* 0x5272 */ { false, 0x5272, 0x5272 }, +/* 0x5273 */ { false, 0x5273, 0x5273 }, +/* 0x5274 */ { false, 0x5274, 0x5274 }, +/* 0x5275 */ { false, 0x5275, 0x5275 }, +/* 0x5276 */ { false, 0x5276, 0x5276 }, +/* 0x5277 */ { false, 0x5277, 0x5277 }, +/* 0x5278 */ { false, 0x5278, 0x5278 }, +/* 0x5279 */ { false, 0x5279, 0x5279 }, +/* 0x527a */ { false, 0x527a, 0x527a }, +/* 0x527b */ { false, 0x527b, 0x527b }, +/* 0x527c */ { false, 0x527c, 0x527c }, +/* 0x527d */ { false, 0x527d, 0x527d }, +/* 0x527e */ { false, 0x527e, 0x527e }, +/* 0x527f */ { false, 0x527f, 0x527f }, +/* 0x5280 */ { false, 0x5280, 0x5280 }, +/* 0x5281 */ { false, 0x5281, 0x5281 }, +/* 0x5282 */ { false, 0x5282, 0x5282 }, +/* 0x5283 */ { false, 0x5283, 0x5283 }, +/* 0x5284 */ { false, 0x5284, 0x5284 }, +/* 0x5285 */ { false, 0x5285, 0x5285 }, +/* 0x5286 */ { false, 0x5286, 0x5286 }, +/* 0x5287 */ { false, 0x5287, 0x5287 }, +/* 0x5288 */ { false, 0x5288, 0x5288 }, +/* 0x5289 */ { false, 0x5289, 0x5289 }, +/* 0x528a */ { false, 0x528a, 0x528a }, +/* 0x528b */ { false, 0x528b, 0x528b }, +/* 0x528c */ { false, 0x528c, 0x528c }, +/* 0x528d */ { false, 0x528d, 0x528d }, +/* 0x528e */ { false, 0x528e, 0x528e }, +/* 0x528f */ { false, 0x528f, 0x528f }, +/* 0x5290 */ { false, 0x5290, 0x5290 }, +/* 0x5291 */ { false, 0x5291, 0x5291 }, +/* 0x5292 */ { false, 0x5292, 0x5292 }, +/* 0x5293 */ { false, 0x5293, 0x5293 }, +/* 0x5294 */ { false, 0x5294, 0x5294 }, +/* 0x5295 */ { false, 0x5295, 0x5295 }, +/* 0x5296 */ { false, 0x5296, 0x5296 }, +/* 0x5297 */ { false, 0x5297, 0x5297 }, +/* 0x5298 */ { false, 0x5298, 0x5298 }, +/* 0x5299 */ { false, 0x5299, 0x5299 }, +/* 0x529a */ { false, 0x529a, 0x529a }, +/* 0x529b */ { false, 0x529b, 0x529b }, +/* 0x529c */ { false, 0x529c, 0x529c }, +/* 0x529d */ { false, 0x529d, 0x529d }, +/* 0x529e */ { false, 0x529e, 0x529e }, +/* 0x529f */ { false, 0x529f, 0x529f }, +/* 0x52a0 */ { false, 0x52a0, 0x52a0 }, +/* 0x52a1 */ { false, 0x52a1, 0x52a1 }, +/* 0x52a2 */ { false, 0x52a2, 0x52a2 }, +/* 0x52a3 */ { false, 0x52a3, 0x52a3 }, +/* 0x52a4 */ { false, 0x52a4, 0x52a4 }, +/* 0x52a5 */ { false, 0x52a5, 0x52a5 }, +/* 0x52a6 */ { false, 0x52a6, 0x52a6 }, +/* 0x52a7 */ { false, 0x52a7, 0x52a7 }, +/* 0x52a8 */ { false, 0x52a8, 0x52a8 }, +/* 0x52a9 */ { false, 0x52a9, 0x52a9 }, +/* 0x52aa */ { false, 0x52aa, 0x52aa }, +/* 0x52ab */ { false, 0x52ab, 0x52ab }, +/* 0x52ac */ { false, 0x52ac, 0x52ac }, +/* 0x52ad */ { false, 0x52ad, 0x52ad }, +/* 0x52ae */ { false, 0x52ae, 0x52ae }, +/* 0x52af */ { false, 0x52af, 0x52af }, +/* 0x52b0 */ { false, 0x52b0, 0x52b0 }, +/* 0x52b1 */ { false, 0x52b1, 0x52b1 }, +/* 0x52b2 */ { false, 0x52b2, 0x52b2 }, +/* 0x52b3 */ { false, 0x52b3, 0x52b3 }, +/* 0x52b4 */ { false, 0x52b4, 0x52b4 }, +/* 0x52b5 */ { false, 0x52b5, 0x52b5 }, +/* 0x52b6 */ { false, 0x52b6, 0x52b6 }, +/* 0x52b7 */ { false, 0x52b7, 0x52b7 }, +/* 0x52b8 */ { false, 0x52b8, 0x52b8 }, +/* 0x52b9 */ { false, 0x52b9, 0x52b9 }, +/* 0x52ba */ { false, 0x52ba, 0x52ba }, +/* 0x52bb */ { false, 0x52bb, 0x52bb }, +/* 0x52bc */ { false, 0x52bc, 0x52bc }, +/* 0x52bd */ { false, 0x52bd, 0x52bd }, +/* 0x52be */ { false, 0x52be, 0x52be }, +/* 0x52bf */ { false, 0x52bf, 0x52bf }, +/* 0x52c0 */ { false, 0x52c0, 0x52c0 }, +/* 0x52c1 */ { false, 0x52c1, 0x52c1 }, +/* 0x52c2 */ { false, 0x52c2, 0x52c2 }, +/* 0x52c3 */ { false, 0x52c3, 0x52c3 }, +/* 0x52c4 */ { false, 0x52c4, 0x52c4 }, +/* 0x52c5 */ { false, 0x52c5, 0x52c5 }, +/* 0x52c6 */ { false, 0x52c6, 0x52c6 }, +/* 0x52c7 */ { false, 0x52c7, 0x52c7 }, +/* 0x52c8 */ { false, 0x52c8, 0x52c8 }, +/* 0x52c9 */ { false, 0x52c9, 0x52c9 }, +/* 0x52ca */ { false, 0x52ca, 0x52ca }, +/* 0x52cb */ { false, 0x52cb, 0x52cb }, +/* 0x52cc */ { false, 0x52cc, 0x52cc }, +/* 0x52cd */ { false, 0x52cd, 0x52cd }, +/* 0x52ce */ { false, 0x52ce, 0x52ce }, +/* 0x52cf */ { false, 0x52cf, 0x52cf }, +/* 0x52d0 */ { false, 0x52d0, 0x52d0 }, +/* 0x52d1 */ { false, 0x52d1, 0x52d1 }, +/* 0x52d2 */ { false, 0x52d2, 0x52d2 }, +/* 0x52d3 */ { false, 0x52d3, 0x52d3 }, +/* 0x52d4 */ { false, 0x52d4, 0x52d4 }, +/* 0x52d5 */ { false, 0x52d5, 0x52d5 }, +/* 0x52d6 */ { false, 0x52d6, 0x52d6 }, +/* 0x52d7 */ { false, 0x52d7, 0x52d7 }, +/* 0x52d8 */ { false, 0x52d8, 0x52d8 }, +/* 0x52d9 */ { false, 0x52d9, 0x52d9 }, +/* 0x52da */ { false, 0x52da, 0x52da }, +/* 0x52db */ { false, 0x52db, 0x52db }, +/* 0x52dc */ { false, 0x52dc, 0x52dc }, +/* 0x52dd */ { false, 0x52dd, 0x52dd }, +/* 0x52de */ { false, 0x52de, 0x52de }, +/* 0x52df */ { false, 0x52df, 0x52df }, +/* 0x52e0 */ { false, 0x52e0, 0x52e0 }, +/* 0x52e1 */ { false, 0x52e1, 0x52e1 }, +/* 0x52e2 */ { false, 0x52e2, 0x52e2 }, +/* 0x52e3 */ { false, 0x52e3, 0x52e3 }, +/* 0x52e4 */ { false, 0x52e4, 0x52e4 }, +/* 0x52e5 */ { false, 0x52e5, 0x52e5 }, +/* 0x52e6 */ { false, 0x52e6, 0x52e6 }, +/* 0x52e7 */ { false, 0x52e7, 0x52e7 }, +/* 0x52e8 */ { false, 0x52e8, 0x52e8 }, +/* 0x52e9 */ { false, 0x52e9, 0x52e9 }, +/* 0x52ea */ { false, 0x52ea, 0x52ea }, +/* 0x52eb */ { false, 0x52eb, 0x52eb }, +/* 0x52ec */ { false, 0x52ec, 0x52ec }, +/* 0x52ed */ { false, 0x52ed, 0x52ed }, +/* 0x52ee */ { false, 0x52ee, 0x52ee }, +/* 0x52ef */ { false, 0x52ef, 0x52ef }, +/* 0x52f0 */ { false, 0x52f0, 0x52f0 }, +/* 0x52f1 */ { false, 0x52f1, 0x52f1 }, +/* 0x52f2 */ { false, 0x52f2, 0x52f2 }, +/* 0x52f3 */ { false, 0x52f3, 0x52f3 }, +/* 0x52f4 */ { false, 0x52f4, 0x52f4 }, +/* 0x52f5 */ { false, 0x52f5, 0x52f5 }, +/* 0x52f6 */ { false, 0x52f6, 0x52f6 }, +/* 0x52f7 */ { false, 0x52f7, 0x52f7 }, +/* 0x52f8 */ { false, 0x52f8, 0x52f8 }, +/* 0x52f9 */ { false, 0x52f9, 0x52f9 }, +/* 0x52fa */ { false, 0x52fa, 0x52fa }, +/* 0x52fb */ { false, 0x52fb, 0x52fb }, +/* 0x52fc */ { false, 0x52fc, 0x52fc }, +/* 0x52fd */ { false, 0x52fd, 0x52fd }, +/* 0x52fe */ { false, 0x52fe, 0x52fe }, +/* 0x52ff */ { false, 0x52ff, 0x52ff }, +/* 0x5300 */ { false, 0x5300, 0x5300 }, +/* 0x5301 */ { false, 0x5301, 0x5301 }, +/* 0x5302 */ { false, 0x5302, 0x5302 }, +/* 0x5303 */ { false, 0x5303, 0x5303 }, +/* 0x5304 */ { false, 0x5304, 0x5304 }, +/* 0x5305 */ { false, 0x5305, 0x5305 }, +/* 0x5306 */ { false, 0x5306, 0x5306 }, +/* 0x5307 */ { false, 0x5307, 0x5307 }, +/* 0x5308 */ { false, 0x5308, 0x5308 }, +/* 0x5309 */ { false, 0x5309, 0x5309 }, +/* 0x530a */ { false, 0x530a, 0x530a }, +/* 0x530b */ { false, 0x530b, 0x530b }, +/* 0x530c */ { false, 0x530c, 0x530c }, +/* 0x530d */ { false, 0x530d, 0x530d }, +/* 0x530e */ { false, 0x530e, 0x530e }, +/* 0x530f */ { false, 0x530f, 0x530f }, +/* 0x5310 */ { false, 0x5310, 0x5310 }, +/* 0x5311 */ { false, 0x5311, 0x5311 }, +/* 0x5312 */ { false, 0x5312, 0x5312 }, +/* 0x5313 */ { false, 0x5313, 0x5313 }, +/* 0x5314 */ { false, 0x5314, 0x5314 }, +/* 0x5315 */ { false, 0x5315, 0x5315 }, +/* 0x5316 */ { false, 0x5316, 0x5316 }, +/* 0x5317 */ { false, 0x5317, 0x5317 }, +/* 0x5318 */ { false, 0x5318, 0x5318 }, +/* 0x5319 */ { false, 0x5319, 0x5319 }, +/* 0x531a */ { false, 0x531a, 0x531a }, +/* 0x531b */ { false, 0x531b, 0x531b }, +/* 0x531c */ { false, 0x531c, 0x531c }, +/* 0x531d */ { false, 0x531d, 0x531d }, +/* 0x531e */ { false, 0x531e, 0x531e }, +/* 0x531f */ { false, 0x531f, 0x531f }, +/* 0x5320 */ { false, 0x5320, 0x5320 }, +/* 0x5321 */ { false, 0x5321, 0x5321 }, +/* 0x5322 */ { false, 0x5322, 0x5322 }, +/* 0x5323 */ { false, 0x5323, 0x5323 }, +/* 0x5324 */ { false, 0x5324, 0x5324 }, +/* 0x5325 */ { false, 0x5325, 0x5325 }, +/* 0x5326 */ { false, 0x5326, 0x5326 }, +/* 0x5327 */ { false, 0x5327, 0x5327 }, +/* 0x5328 */ { false, 0x5328, 0x5328 }, +/* 0x5329 */ { false, 0x5329, 0x5329 }, +/* 0x532a */ { false, 0x532a, 0x532a }, +/* 0x532b */ { false, 0x532b, 0x532b }, +/* 0x532c */ { false, 0x532c, 0x532c }, +/* 0x532d */ { false, 0x532d, 0x532d }, +/* 0x532e */ { false, 0x532e, 0x532e }, +/* 0x532f */ { false, 0x532f, 0x532f }, +/* 0x5330 */ { false, 0x5330, 0x5330 }, +/* 0x5331 */ { false, 0x5331, 0x5331 }, +/* 0x5332 */ { false, 0x5332, 0x5332 }, +/* 0x5333 */ { false, 0x5333, 0x5333 }, +/* 0x5334 */ { false, 0x5334, 0x5334 }, +/* 0x5335 */ { false, 0x5335, 0x5335 }, +/* 0x5336 */ { false, 0x5336, 0x5336 }, +/* 0x5337 */ { false, 0x5337, 0x5337 }, +/* 0x5338 */ { false, 0x5338, 0x5338 }, +/* 0x5339 */ { false, 0x5339, 0x5339 }, +/* 0x533a */ { false, 0x533a, 0x533a }, +/* 0x533b */ { false, 0x533b, 0x533b }, +/* 0x533c */ { false, 0x533c, 0x533c }, +/* 0x533d */ { false, 0x533d, 0x533d }, +/* 0x533e */ { false, 0x533e, 0x533e }, +/* 0x533f */ { false, 0x533f, 0x533f }, +/* 0x5340 */ { false, 0x5340, 0x5340 }, +/* 0x5341 */ { false, 0x5341, 0x5341 }, +/* 0x5342 */ { false, 0x5342, 0x5342 }, +/* 0x5343 */ { false, 0x5343, 0x5343 }, +/* 0x5344 */ { false, 0x5344, 0x5344 }, +/* 0x5345 */ { false, 0x5345, 0x5345 }, +/* 0x5346 */ { false, 0x5346, 0x5346 }, +/* 0x5347 */ { false, 0x5347, 0x5347 }, +/* 0x5348 */ { false, 0x5348, 0x5348 }, +/* 0x5349 */ { false, 0x5349, 0x5349 }, +/* 0x534a */ { false, 0x534a, 0x534a }, +/* 0x534b */ { false, 0x534b, 0x534b }, +/* 0x534c */ { false, 0x534c, 0x534c }, +/* 0x534d */ { false, 0x534d, 0x534d }, +/* 0x534e */ { false, 0x534e, 0x534e }, +/* 0x534f */ { false, 0x534f, 0x534f }, +/* 0x5350 */ { false, 0x5350, 0x5350 }, +/* 0x5351 */ { false, 0x5351, 0x5351 }, +/* 0x5352 */ { false, 0x5352, 0x5352 }, +/* 0x5353 */ { false, 0x5353, 0x5353 }, +/* 0x5354 */ { false, 0x5354, 0x5354 }, +/* 0x5355 */ { false, 0x5355, 0x5355 }, +/* 0x5356 */ { false, 0x5356, 0x5356 }, +/* 0x5357 */ { false, 0x5357, 0x5357 }, +/* 0x5358 */ { false, 0x5358, 0x5358 }, +/* 0x5359 */ { false, 0x5359, 0x5359 }, +/* 0x535a */ { false, 0x535a, 0x535a }, +/* 0x535b */ { false, 0x535b, 0x535b }, +/* 0x535c */ { false, 0x535c, 0x535c }, +/* 0x535d */ { false, 0x535d, 0x535d }, +/* 0x535e */ { false, 0x535e, 0x535e }, +/* 0x535f */ { false, 0x535f, 0x535f }, +/* 0x5360 */ { false, 0x5360, 0x5360 }, +/* 0x5361 */ { false, 0x5361, 0x5361 }, +/* 0x5362 */ { false, 0x5362, 0x5362 }, +/* 0x5363 */ { false, 0x5363, 0x5363 }, +/* 0x5364 */ { false, 0x5364, 0x5364 }, +/* 0x5365 */ { false, 0x5365, 0x5365 }, +/* 0x5366 */ { false, 0x5366, 0x5366 }, +/* 0x5367 */ { false, 0x5367, 0x5367 }, +/* 0x5368 */ { false, 0x5368, 0x5368 }, +/* 0x5369 */ { false, 0x5369, 0x5369 }, +/* 0x536a */ { false, 0x536a, 0x536a }, +/* 0x536b */ { false, 0x536b, 0x536b }, +/* 0x536c */ { false, 0x536c, 0x536c }, +/* 0x536d */ { false, 0x536d, 0x536d }, +/* 0x536e */ { false, 0x536e, 0x536e }, +/* 0x536f */ { false, 0x536f, 0x536f }, +/* 0x5370 */ { false, 0x5370, 0x5370 }, +/* 0x5371 */ { false, 0x5371, 0x5371 }, +/* 0x5372 */ { false, 0x5372, 0x5372 }, +/* 0x5373 */ { false, 0x5373, 0x5373 }, +/* 0x5374 */ { false, 0x5374, 0x5374 }, +/* 0x5375 */ { false, 0x5375, 0x5375 }, +/* 0x5376 */ { false, 0x5376, 0x5376 }, +/* 0x5377 */ { false, 0x5377, 0x5377 }, +/* 0x5378 */ { false, 0x5378, 0x5378 }, +/* 0x5379 */ { false, 0x5379, 0x5379 }, +/* 0x537a */ { false, 0x537a, 0x537a }, +/* 0x537b */ { false, 0x537b, 0x537b }, +/* 0x537c */ { false, 0x537c, 0x537c }, +/* 0x537d */ { false, 0x537d, 0x537d }, +/* 0x537e */ { false, 0x537e, 0x537e }, +/* 0x537f */ { false, 0x537f, 0x537f }, +/* 0x5380 */ { false, 0x5380, 0x5380 }, +/* 0x5381 */ { false, 0x5381, 0x5381 }, +/* 0x5382 */ { false, 0x5382, 0x5382 }, +/* 0x5383 */ { false, 0x5383, 0x5383 }, +/* 0x5384 */ { false, 0x5384, 0x5384 }, +/* 0x5385 */ { false, 0x5385, 0x5385 }, +/* 0x5386 */ { false, 0x5386, 0x5386 }, +/* 0x5387 */ { false, 0x5387, 0x5387 }, +/* 0x5388 */ { false, 0x5388, 0x5388 }, +/* 0x5389 */ { false, 0x5389, 0x5389 }, +/* 0x538a */ { false, 0x538a, 0x538a }, +/* 0x538b */ { false, 0x538b, 0x538b }, +/* 0x538c */ { false, 0x538c, 0x538c }, +/* 0x538d */ { false, 0x538d, 0x538d }, +/* 0x538e */ { false, 0x538e, 0x538e }, +/* 0x538f */ { false, 0x538f, 0x538f }, +/* 0x5390 */ { false, 0x5390, 0x5390 }, +/* 0x5391 */ { false, 0x5391, 0x5391 }, +/* 0x5392 */ { false, 0x5392, 0x5392 }, +/* 0x5393 */ { false, 0x5393, 0x5393 }, +/* 0x5394 */ { false, 0x5394, 0x5394 }, +/* 0x5395 */ { false, 0x5395, 0x5395 }, +/* 0x5396 */ { false, 0x5396, 0x5396 }, +/* 0x5397 */ { false, 0x5397, 0x5397 }, +/* 0x5398 */ { false, 0x5398, 0x5398 }, +/* 0x5399 */ { false, 0x5399, 0x5399 }, +/* 0x539a */ { false, 0x539a, 0x539a }, +/* 0x539b */ { false, 0x539b, 0x539b }, +/* 0x539c */ { false, 0x539c, 0x539c }, +/* 0x539d */ { false, 0x539d, 0x539d }, +/* 0x539e */ { false, 0x539e, 0x539e }, +/* 0x539f */ { false, 0x539f, 0x539f }, +/* 0x53a0 */ { false, 0x53a0, 0x53a0 }, +/* 0x53a1 */ { false, 0x53a1, 0x53a1 }, +/* 0x53a2 */ { false, 0x53a2, 0x53a2 }, +/* 0x53a3 */ { false, 0x53a3, 0x53a3 }, +/* 0x53a4 */ { false, 0x53a4, 0x53a4 }, +/* 0x53a5 */ { false, 0x53a5, 0x53a5 }, +/* 0x53a6 */ { false, 0x53a6, 0x53a6 }, +/* 0x53a7 */ { false, 0x53a7, 0x53a7 }, +/* 0x53a8 */ { false, 0x53a8, 0x53a8 }, +/* 0x53a9 */ { false, 0x53a9, 0x53a9 }, +/* 0x53aa */ { false, 0x53aa, 0x53aa }, +/* 0x53ab */ { false, 0x53ab, 0x53ab }, +/* 0x53ac */ { false, 0x53ac, 0x53ac }, +/* 0x53ad */ { false, 0x53ad, 0x53ad }, +/* 0x53ae */ { false, 0x53ae, 0x53ae }, +/* 0x53af */ { false, 0x53af, 0x53af }, +/* 0x53b0 */ { false, 0x53b0, 0x53b0 }, +/* 0x53b1 */ { false, 0x53b1, 0x53b1 }, +/* 0x53b2 */ { false, 0x53b2, 0x53b2 }, +/* 0x53b3 */ { false, 0x53b3, 0x53b3 }, +/* 0x53b4 */ { false, 0x53b4, 0x53b4 }, +/* 0x53b5 */ { false, 0x53b5, 0x53b5 }, +/* 0x53b6 */ { false, 0x53b6, 0x53b6 }, +/* 0x53b7 */ { false, 0x53b7, 0x53b7 }, +/* 0x53b8 */ { false, 0x53b8, 0x53b8 }, +/* 0x53b9 */ { false, 0x53b9, 0x53b9 }, +/* 0x53ba */ { false, 0x53ba, 0x53ba }, +/* 0x53bb */ { false, 0x53bb, 0x53bb }, +/* 0x53bc */ { false, 0x53bc, 0x53bc }, +/* 0x53bd */ { false, 0x53bd, 0x53bd }, +/* 0x53be */ { false, 0x53be, 0x53be }, +/* 0x53bf */ { false, 0x53bf, 0x53bf }, +/* 0x53c0 */ { false, 0x53c0, 0x53c0 }, +/* 0x53c1 */ { false, 0x53c1, 0x53c1 }, +/* 0x53c2 */ { false, 0x53c2, 0x53c2 }, +/* 0x53c3 */ { false, 0x53c3, 0x53c3 }, +/* 0x53c4 */ { false, 0x53c4, 0x53c4 }, +/* 0x53c5 */ { false, 0x53c5, 0x53c5 }, +/* 0x53c6 */ { false, 0x53c6, 0x53c6 }, +/* 0x53c7 */ { false, 0x53c7, 0x53c7 }, +/* 0x53c8 */ { false, 0x53c8, 0x53c8 }, +/* 0x53c9 */ { false, 0x53c9, 0x53c9 }, +/* 0x53ca */ { false, 0x53ca, 0x53ca }, +/* 0x53cb */ { false, 0x53cb, 0x53cb }, +/* 0x53cc */ { false, 0x53cc, 0x53cc }, +/* 0x53cd */ { false, 0x53cd, 0x53cd }, +/* 0x53ce */ { false, 0x53ce, 0x53ce }, +/* 0x53cf */ { false, 0x53cf, 0x53cf }, +/* 0x53d0 */ { false, 0x53d0, 0x53d0 }, +/* 0x53d1 */ { false, 0x53d1, 0x53d1 }, +/* 0x53d2 */ { false, 0x53d2, 0x53d2 }, +/* 0x53d3 */ { false, 0x53d3, 0x53d3 }, +/* 0x53d4 */ { false, 0x53d4, 0x53d4 }, +/* 0x53d5 */ { false, 0x53d5, 0x53d5 }, +/* 0x53d6 */ { false, 0x53d6, 0x53d6 }, +/* 0x53d7 */ { false, 0x53d7, 0x53d7 }, +/* 0x53d8 */ { false, 0x53d8, 0x53d8 }, +/* 0x53d9 */ { false, 0x53d9, 0x53d9 }, +/* 0x53da */ { false, 0x53da, 0x53da }, +/* 0x53db */ { false, 0x53db, 0x53db }, +/* 0x53dc */ { false, 0x53dc, 0x53dc }, +/* 0x53dd */ { false, 0x53dd, 0x53dd }, +/* 0x53de */ { false, 0x53de, 0x53de }, +/* 0x53df */ { false, 0x53df, 0x53df }, +/* 0x53e0 */ { false, 0x53e0, 0x53e0 }, +/* 0x53e1 */ { false, 0x53e1, 0x53e1 }, +/* 0x53e2 */ { false, 0x53e2, 0x53e2 }, +/* 0x53e3 */ { false, 0x53e3, 0x53e3 }, +/* 0x53e4 */ { false, 0x53e4, 0x53e4 }, +/* 0x53e5 */ { false, 0x53e5, 0x53e5 }, +/* 0x53e6 */ { false, 0x53e6, 0x53e6 }, +/* 0x53e7 */ { false, 0x53e7, 0x53e7 }, +/* 0x53e8 */ { false, 0x53e8, 0x53e8 }, +/* 0x53e9 */ { false, 0x53e9, 0x53e9 }, +/* 0x53ea */ { false, 0x53ea, 0x53ea }, +/* 0x53eb */ { false, 0x53eb, 0x53eb }, +/* 0x53ec */ { false, 0x53ec, 0x53ec }, +/* 0x53ed */ { false, 0x53ed, 0x53ed }, +/* 0x53ee */ { false, 0x53ee, 0x53ee }, +/* 0x53ef */ { false, 0x53ef, 0x53ef }, +/* 0x53f0 */ { false, 0x53f0, 0x53f0 }, +/* 0x53f1 */ { false, 0x53f1, 0x53f1 }, +/* 0x53f2 */ { false, 0x53f2, 0x53f2 }, +/* 0x53f3 */ { false, 0x53f3, 0x53f3 }, +/* 0x53f4 */ { false, 0x53f4, 0x53f4 }, +/* 0x53f5 */ { false, 0x53f5, 0x53f5 }, +/* 0x53f6 */ { false, 0x53f6, 0x53f6 }, +/* 0x53f7 */ { false, 0x53f7, 0x53f7 }, +/* 0x53f8 */ { false, 0x53f8, 0x53f8 }, +/* 0x53f9 */ { false, 0x53f9, 0x53f9 }, +/* 0x53fa */ { false, 0x53fa, 0x53fa }, +/* 0x53fb */ { false, 0x53fb, 0x53fb }, +/* 0x53fc */ { false, 0x53fc, 0x53fc }, +/* 0x53fd */ { false, 0x53fd, 0x53fd }, +/* 0x53fe */ { false, 0x53fe, 0x53fe }, +/* 0x53ff */ { false, 0x53ff, 0x53ff }, +/* 0x5400 */ { false, 0x5400, 0x5400 }, +/* 0x5401 */ { false, 0x5401, 0x5401 }, +/* 0x5402 */ { false, 0x5402, 0x5402 }, +/* 0x5403 */ { false, 0x5403, 0x5403 }, +/* 0x5404 */ { false, 0x5404, 0x5404 }, +/* 0x5405 */ { false, 0x5405, 0x5405 }, +/* 0x5406 */ { false, 0x5406, 0x5406 }, +/* 0x5407 */ { false, 0x5407, 0x5407 }, +/* 0x5408 */ { false, 0x5408, 0x5408 }, +/* 0x5409 */ { false, 0x5409, 0x5409 }, +/* 0x540a */ { false, 0x540a, 0x540a }, +/* 0x540b */ { false, 0x540b, 0x540b }, +/* 0x540c */ { false, 0x540c, 0x540c }, +/* 0x540d */ { false, 0x540d, 0x540d }, +/* 0x540e */ { false, 0x540e, 0x540e }, +/* 0x540f */ { false, 0x540f, 0x540f }, +/* 0x5410 */ { false, 0x5410, 0x5410 }, +/* 0x5411 */ { false, 0x5411, 0x5411 }, +/* 0x5412 */ { false, 0x5412, 0x5412 }, +/* 0x5413 */ { false, 0x5413, 0x5413 }, +/* 0x5414 */ { false, 0x5414, 0x5414 }, +/* 0x5415 */ { false, 0x5415, 0x5415 }, +/* 0x5416 */ { false, 0x5416, 0x5416 }, +/* 0x5417 */ { false, 0x5417, 0x5417 }, +/* 0x5418 */ { false, 0x5418, 0x5418 }, +/* 0x5419 */ { false, 0x5419, 0x5419 }, +/* 0x541a */ { false, 0x541a, 0x541a }, +/* 0x541b */ { false, 0x541b, 0x541b }, +/* 0x541c */ { false, 0x541c, 0x541c }, +/* 0x541d */ { false, 0x541d, 0x541d }, +/* 0x541e */ { false, 0x541e, 0x541e }, +/* 0x541f */ { false, 0x541f, 0x541f }, +/* 0x5420 */ { false, 0x5420, 0x5420 }, +/* 0x5421 */ { false, 0x5421, 0x5421 }, +/* 0x5422 */ { false, 0x5422, 0x5422 }, +/* 0x5423 */ { false, 0x5423, 0x5423 }, +/* 0x5424 */ { false, 0x5424, 0x5424 }, +/* 0x5425 */ { false, 0x5425, 0x5425 }, +/* 0x5426 */ { false, 0x5426, 0x5426 }, +/* 0x5427 */ { false, 0x5427, 0x5427 }, +/* 0x5428 */ { false, 0x5428, 0x5428 }, +/* 0x5429 */ { false, 0x5429, 0x5429 }, +/* 0x542a */ { false, 0x542a, 0x542a }, +/* 0x542b */ { false, 0x542b, 0x542b }, +/* 0x542c */ { false, 0x542c, 0x542c }, +/* 0x542d */ { false, 0x542d, 0x542d }, +/* 0x542e */ { false, 0x542e, 0x542e }, +/* 0x542f */ { false, 0x542f, 0x542f }, +/* 0x5430 */ { false, 0x5430, 0x5430 }, +/* 0x5431 */ { false, 0x5431, 0x5431 }, +/* 0x5432 */ { false, 0x5432, 0x5432 }, +/* 0x5433 */ { false, 0x5433, 0x5433 }, +/* 0x5434 */ { false, 0x5434, 0x5434 }, +/* 0x5435 */ { false, 0x5435, 0x5435 }, +/* 0x5436 */ { false, 0x5436, 0x5436 }, +/* 0x5437 */ { false, 0x5437, 0x5437 }, +/* 0x5438 */ { false, 0x5438, 0x5438 }, +/* 0x5439 */ { false, 0x5439, 0x5439 }, +/* 0x543a */ { false, 0x543a, 0x543a }, +/* 0x543b */ { false, 0x543b, 0x543b }, +/* 0x543c */ { false, 0x543c, 0x543c }, +/* 0x543d */ { false, 0x543d, 0x543d }, +/* 0x543e */ { false, 0x543e, 0x543e }, +/* 0x543f */ { false, 0x543f, 0x543f }, +/* 0x5440 */ { false, 0x5440, 0x5440 }, +/* 0x5441 */ { false, 0x5441, 0x5441 }, +/* 0x5442 */ { false, 0x5442, 0x5442 }, +/* 0x5443 */ { false, 0x5443, 0x5443 }, +/* 0x5444 */ { false, 0x5444, 0x5444 }, +/* 0x5445 */ { false, 0x5445, 0x5445 }, +/* 0x5446 */ { false, 0x5446, 0x5446 }, +/* 0x5447 */ { false, 0x5447, 0x5447 }, +/* 0x5448 */ { false, 0x5448, 0x5448 }, +/* 0x5449 */ { false, 0x5449, 0x5449 }, +/* 0x544a */ { false, 0x544a, 0x544a }, +/* 0x544b */ { false, 0x544b, 0x544b }, +/* 0x544c */ { false, 0x544c, 0x544c }, +/* 0x544d */ { false, 0x544d, 0x544d }, +/* 0x544e */ { false, 0x544e, 0x544e }, +/* 0x544f */ { false, 0x544f, 0x544f }, +/* 0x5450 */ { false, 0x5450, 0x5450 }, +/* 0x5451 */ { false, 0x5451, 0x5451 }, +/* 0x5452 */ { false, 0x5452, 0x5452 }, +/* 0x5453 */ { false, 0x5453, 0x5453 }, +/* 0x5454 */ { false, 0x5454, 0x5454 }, +/* 0x5455 */ { false, 0x5455, 0x5455 }, +/* 0x5456 */ { false, 0x5456, 0x5456 }, +/* 0x5457 */ { false, 0x5457, 0x5457 }, +/* 0x5458 */ { false, 0x5458, 0x5458 }, +/* 0x5459 */ { false, 0x5459, 0x5459 }, +/* 0x545a */ { false, 0x545a, 0x545a }, +/* 0x545b */ { false, 0x545b, 0x545b }, +/* 0x545c */ { false, 0x545c, 0x545c }, +/* 0x545d */ { false, 0x545d, 0x545d }, +/* 0x545e */ { false, 0x545e, 0x545e }, +/* 0x545f */ { false, 0x545f, 0x545f }, +/* 0x5460 */ { false, 0x5460, 0x5460 }, +/* 0x5461 */ { false, 0x5461, 0x5461 }, +/* 0x5462 */ { false, 0x5462, 0x5462 }, +/* 0x5463 */ { false, 0x5463, 0x5463 }, +/* 0x5464 */ { false, 0x5464, 0x5464 }, +/* 0x5465 */ { false, 0x5465, 0x5465 }, +/* 0x5466 */ { false, 0x5466, 0x5466 }, +/* 0x5467 */ { false, 0x5467, 0x5467 }, +/* 0x5468 */ { false, 0x5468, 0x5468 }, +/* 0x5469 */ { false, 0x5469, 0x5469 }, +/* 0x546a */ { false, 0x546a, 0x546a }, +/* 0x546b */ { false, 0x546b, 0x546b }, +/* 0x546c */ { false, 0x546c, 0x546c }, +/* 0x546d */ { false, 0x546d, 0x546d }, +/* 0x546e */ { false, 0x546e, 0x546e }, +/* 0x546f */ { false, 0x546f, 0x546f }, +/* 0x5470 */ { false, 0x5470, 0x5470 }, +/* 0x5471 */ { false, 0x5471, 0x5471 }, +/* 0x5472 */ { false, 0x5472, 0x5472 }, +/* 0x5473 */ { false, 0x5473, 0x5473 }, +/* 0x5474 */ { false, 0x5474, 0x5474 }, +/* 0x5475 */ { false, 0x5475, 0x5475 }, +/* 0x5476 */ { false, 0x5476, 0x5476 }, +/* 0x5477 */ { false, 0x5477, 0x5477 }, +/* 0x5478 */ { false, 0x5478, 0x5478 }, +/* 0x5479 */ { false, 0x5479, 0x5479 }, +/* 0x547a */ { false, 0x547a, 0x547a }, +/* 0x547b */ { false, 0x547b, 0x547b }, +/* 0x547c */ { false, 0x547c, 0x547c }, +/* 0x547d */ { false, 0x547d, 0x547d }, +/* 0x547e */ { false, 0x547e, 0x547e }, +/* 0x547f */ { false, 0x547f, 0x547f }, +/* 0x5480 */ { false, 0x5480, 0x5480 }, +/* 0x5481 */ { false, 0x5481, 0x5481 }, +/* 0x5482 */ { false, 0x5482, 0x5482 }, +/* 0x5483 */ { false, 0x5483, 0x5483 }, +/* 0x5484 */ { false, 0x5484, 0x5484 }, +/* 0x5485 */ { false, 0x5485, 0x5485 }, +/* 0x5486 */ { false, 0x5486, 0x5486 }, +/* 0x5487 */ { false, 0x5487, 0x5487 }, +/* 0x5488 */ { false, 0x5488, 0x5488 }, +/* 0x5489 */ { false, 0x5489, 0x5489 }, +/* 0x548a */ { false, 0x548a, 0x548a }, +/* 0x548b */ { false, 0x548b, 0x548b }, +/* 0x548c */ { false, 0x548c, 0x548c }, +/* 0x548d */ { false, 0x548d, 0x548d }, +/* 0x548e */ { false, 0x548e, 0x548e }, +/* 0x548f */ { false, 0x548f, 0x548f }, +/* 0x5490 */ { false, 0x5490, 0x5490 }, +/* 0x5491 */ { false, 0x5491, 0x5491 }, +/* 0x5492 */ { false, 0x5492, 0x5492 }, +/* 0x5493 */ { false, 0x5493, 0x5493 }, +/* 0x5494 */ { false, 0x5494, 0x5494 }, +/* 0x5495 */ { false, 0x5495, 0x5495 }, +/* 0x5496 */ { false, 0x5496, 0x5496 }, +/* 0x5497 */ { false, 0x5497, 0x5497 }, +/* 0x5498 */ { false, 0x5498, 0x5498 }, +/* 0x5499 */ { false, 0x5499, 0x5499 }, +/* 0x549a */ { false, 0x549a, 0x549a }, +/* 0x549b */ { false, 0x549b, 0x549b }, +/* 0x549c */ { false, 0x549c, 0x549c }, +/* 0x549d */ { false, 0x549d, 0x549d }, +/* 0x549e */ { false, 0x549e, 0x549e }, +/* 0x549f */ { false, 0x549f, 0x549f }, +/* 0x54a0 */ { false, 0x54a0, 0x54a0 }, +/* 0x54a1 */ { false, 0x54a1, 0x54a1 }, +/* 0x54a2 */ { false, 0x54a2, 0x54a2 }, +/* 0x54a3 */ { false, 0x54a3, 0x54a3 }, +/* 0x54a4 */ { false, 0x54a4, 0x54a4 }, +/* 0x54a5 */ { false, 0x54a5, 0x54a5 }, +/* 0x54a6 */ { false, 0x54a6, 0x54a6 }, +/* 0x54a7 */ { false, 0x54a7, 0x54a7 }, +/* 0x54a8 */ { false, 0x54a8, 0x54a8 }, +/* 0x54a9 */ { false, 0x54a9, 0x54a9 }, +/* 0x54aa */ { false, 0x54aa, 0x54aa }, +/* 0x54ab */ { false, 0x54ab, 0x54ab }, +/* 0x54ac */ { false, 0x54ac, 0x54ac }, +/* 0x54ad */ { false, 0x54ad, 0x54ad }, +/* 0x54ae */ { false, 0x54ae, 0x54ae }, +/* 0x54af */ { false, 0x54af, 0x54af }, +/* 0x54b0 */ { false, 0x54b0, 0x54b0 }, +/* 0x54b1 */ { false, 0x54b1, 0x54b1 }, +/* 0x54b2 */ { false, 0x54b2, 0x54b2 }, +/* 0x54b3 */ { false, 0x54b3, 0x54b3 }, +/* 0x54b4 */ { false, 0x54b4, 0x54b4 }, +/* 0x54b5 */ { false, 0x54b5, 0x54b5 }, +/* 0x54b6 */ { false, 0x54b6, 0x54b6 }, +/* 0x54b7 */ { false, 0x54b7, 0x54b7 }, +/* 0x54b8 */ { false, 0x54b8, 0x54b8 }, +/* 0x54b9 */ { false, 0x54b9, 0x54b9 }, +/* 0x54ba */ { false, 0x54ba, 0x54ba }, +/* 0x54bb */ { false, 0x54bb, 0x54bb }, +/* 0x54bc */ { false, 0x54bc, 0x54bc }, +/* 0x54bd */ { false, 0x54bd, 0x54bd }, +/* 0x54be */ { false, 0x54be, 0x54be }, +/* 0x54bf */ { false, 0x54bf, 0x54bf }, +/* 0x54c0 */ { false, 0x54c0, 0x54c0 }, +/* 0x54c1 */ { false, 0x54c1, 0x54c1 }, +/* 0x54c2 */ { false, 0x54c2, 0x54c2 }, +/* 0x54c3 */ { false, 0x54c3, 0x54c3 }, +/* 0x54c4 */ { false, 0x54c4, 0x54c4 }, +/* 0x54c5 */ { false, 0x54c5, 0x54c5 }, +/* 0x54c6 */ { false, 0x54c6, 0x54c6 }, +/* 0x54c7 */ { false, 0x54c7, 0x54c7 }, +/* 0x54c8 */ { false, 0x54c8, 0x54c8 }, +/* 0x54c9 */ { false, 0x54c9, 0x54c9 }, +/* 0x54ca */ { false, 0x54ca, 0x54ca }, +/* 0x54cb */ { false, 0x54cb, 0x54cb }, +/* 0x54cc */ { false, 0x54cc, 0x54cc }, +/* 0x54cd */ { false, 0x54cd, 0x54cd }, +/* 0x54ce */ { false, 0x54ce, 0x54ce }, +/* 0x54cf */ { false, 0x54cf, 0x54cf }, +/* 0x54d0 */ { false, 0x54d0, 0x54d0 }, +/* 0x54d1 */ { false, 0x54d1, 0x54d1 }, +/* 0x54d2 */ { false, 0x54d2, 0x54d2 }, +/* 0x54d3 */ { false, 0x54d3, 0x54d3 }, +/* 0x54d4 */ { false, 0x54d4, 0x54d4 }, +/* 0x54d5 */ { false, 0x54d5, 0x54d5 }, +/* 0x54d6 */ { false, 0x54d6, 0x54d6 }, +/* 0x54d7 */ { false, 0x54d7, 0x54d7 }, +/* 0x54d8 */ { false, 0x54d8, 0x54d8 }, +/* 0x54d9 */ { false, 0x54d9, 0x54d9 }, +/* 0x54da */ { false, 0x54da, 0x54da }, +/* 0x54db */ { false, 0x54db, 0x54db }, +/* 0x54dc */ { false, 0x54dc, 0x54dc }, +/* 0x54dd */ { false, 0x54dd, 0x54dd }, +/* 0x54de */ { false, 0x54de, 0x54de }, +/* 0x54df */ { false, 0x54df, 0x54df }, +/* 0x54e0 */ { false, 0x54e0, 0x54e0 }, +/* 0x54e1 */ { false, 0x54e1, 0x54e1 }, +/* 0x54e2 */ { false, 0x54e2, 0x54e2 }, +/* 0x54e3 */ { false, 0x54e3, 0x54e3 }, +/* 0x54e4 */ { false, 0x54e4, 0x54e4 }, +/* 0x54e5 */ { false, 0x54e5, 0x54e5 }, +/* 0x54e6 */ { false, 0x54e6, 0x54e6 }, +/* 0x54e7 */ { false, 0x54e7, 0x54e7 }, +/* 0x54e8 */ { false, 0x54e8, 0x54e8 }, +/* 0x54e9 */ { false, 0x54e9, 0x54e9 }, +/* 0x54ea */ { false, 0x54ea, 0x54ea }, +/* 0x54eb */ { false, 0x54eb, 0x54eb }, +/* 0x54ec */ { false, 0x54ec, 0x54ec }, +/* 0x54ed */ { false, 0x54ed, 0x54ed }, +/* 0x54ee */ { false, 0x54ee, 0x54ee }, +/* 0x54ef */ { false, 0x54ef, 0x54ef }, +/* 0x54f0 */ { false, 0x54f0, 0x54f0 }, +/* 0x54f1 */ { false, 0x54f1, 0x54f1 }, +/* 0x54f2 */ { false, 0x54f2, 0x54f2 }, +/* 0x54f3 */ { false, 0x54f3, 0x54f3 }, +/* 0x54f4 */ { false, 0x54f4, 0x54f4 }, +/* 0x54f5 */ { false, 0x54f5, 0x54f5 }, +/* 0x54f6 */ { false, 0x54f6, 0x54f6 }, +/* 0x54f7 */ { false, 0x54f7, 0x54f7 }, +/* 0x54f8 */ { false, 0x54f8, 0x54f8 }, +/* 0x54f9 */ { false, 0x54f9, 0x54f9 }, +/* 0x54fa */ { false, 0x54fa, 0x54fa }, +/* 0x54fb */ { false, 0x54fb, 0x54fb }, +/* 0x54fc */ { false, 0x54fc, 0x54fc }, +/* 0x54fd */ { false, 0x54fd, 0x54fd }, +/* 0x54fe */ { false, 0x54fe, 0x54fe }, +/* 0x54ff */ { false, 0x54ff, 0x54ff }, +/* 0x5500 */ { false, 0x5500, 0x5500 }, +/* 0x5501 */ { false, 0x5501, 0x5501 }, +/* 0x5502 */ { false, 0x5502, 0x5502 }, +/* 0x5503 */ { false, 0x5503, 0x5503 }, +/* 0x5504 */ { false, 0x5504, 0x5504 }, +/* 0x5505 */ { false, 0x5505, 0x5505 }, +/* 0x5506 */ { false, 0x5506, 0x5506 }, +/* 0x5507 */ { false, 0x5507, 0x5507 }, +/* 0x5508 */ { false, 0x5508, 0x5508 }, +/* 0x5509 */ { false, 0x5509, 0x5509 }, +/* 0x550a */ { false, 0x550a, 0x550a }, +/* 0x550b */ { false, 0x550b, 0x550b }, +/* 0x550c */ { false, 0x550c, 0x550c }, +/* 0x550d */ { false, 0x550d, 0x550d }, +/* 0x550e */ { false, 0x550e, 0x550e }, +/* 0x550f */ { false, 0x550f, 0x550f }, +/* 0x5510 */ { false, 0x5510, 0x5510 }, +/* 0x5511 */ { false, 0x5511, 0x5511 }, +/* 0x5512 */ { false, 0x5512, 0x5512 }, +/* 0x5513 */ { false, 0x5513, 0x5513 }, +/* 0x5514 */ { false, 0x5514, 0x5514 }, +/* 0x5515 */ { false, 0x5515, 0x5515 }, +/* 0x5516 */ { false, 0x5516, 0x5516 }, +/* 0x5517 */ { false, 0x5517, 0x5517 }, +/* 0x5518 */ { false, 0x5518, 0x5518 }, +/* 0x5519 */ { false, 0x5519, 0x5519 }, +/* 0x551a */ { false, 0x551a, 0x551a }, +/* 0x551b */ { false, 0x551b, 0x551b }, +/* 0x551c */ { false, 0x551c, 0x551c }, +/* 0x551d */ { false, 0x551d, 0x551d }, +/* 0x551e */ { false, 0x551e, 0x551e }, +/* 0x551f */ { false, 0x551f, 0x551f }, +/* 0x5520 */ { false, 0x5520, 0x5520 }, +/* 0x5521 */ { false, 0x5521, 0x5521 }, +/* 0x5522 */ { false, 0x5522, 0x5522 }, +/* 0x5523 */ { false, 0x5523, 0x5523 }, +/* 0x5524 */ { false, 0x5524, 0x5524 }, +/* 0x5525 */ { false, 0x5525, 0x5525 }, +/* 0x5526 */ { false, 0x5526, 0x5526 }, +/* 0x5527 */ { false, 0x5527, 0x5527 }, +/* 0x5528 */ { false, 0x5528, 0x5528 }, +/* 0x5529 */ { false, 0x5529, 0x5529 }, +/* 0x552a */ { false, 0x552a, 0x552a }, +/* 0x552b */ { false, 0x552b, 0x552b }, +/* 0x552c */ { false, 0x552c, 0x552c }, +/* 0x552d */ { false, 0x552d, 0x552d }, +/* 0x552e */ { false, 0x552e, 0x552e }, +/* 0x552f */ { false, 0x552f, 0x552f }, +/* 0x5530 */ { false, 0x5530, 0x5530 }, +/* 0x5531 */ { false, 0x5531, 0x5531 }, +/* 0x5532 */ { false, 0x5532, 0x5532 }, +/* 0x5533 */ { false, 0x5533, 0x5533 }, +/* 0x5534 */ { false, 0x5534, 0x5534 }, +/* 0x5535 */ { false, 0x5535, 0x5535 }, +/* 0x5536 */ { false, 0x5536, 0x5536 }, +/* 0x5537 */ { false, 0x5537, 0x5537 }, +/* 0x5538 */ { false, 0x5538, 0x5538 }, +/* 0x5539 */ { false, 0x5539, 0x5539 }, +/* 0x553a */ { false, 0x553a, 0x553a }, +/* 0x553b */ { false, 0x553b, 0x553b }, +/* 0x553c */ { false, 0x553c, 0x553c }, +/* 0x553d */ { false, 0x553d, 0x553d }, +/* 0x553e */ { false, 0x553e, 0x553e }, +/* 0x553f */ { false, 0x553f, 0x553f }, +/* 0x5540 */ { false, 0x5540, 0x5540 }, +/* 0x5541 */ { false, 0x5541, 0x5541 }, +/* 0x5542 */ { false, 0x5542, 0x5542 }, +/* 0x5543 */ { false, 0x5543, 0x5543 }, +/* 0x5544 */ { false, 0x5544, 0x5544 }, +/* 0x5545 */ { false, 0x5545, 0x5545 }, +/* 0x5546 */ { false, 0x5546, 0x5546 }, +/* 0x5547 */ { false, 0x5547, 0x5547 }, +/* 0x5548 */ { false, 0x5548, 0x5548 }, +/* 0x5549 */ { false, 0x5549, 0x5549 }, +/* 0x554a */ { false, 0x554a, 0x554a }, +/* 0x554b */ { false, 0x554b, 0x554b }, +/* 0x554c */ { false, 0x554c, 0x554c }, +/* 0x554d */ { false, 0x554d, 0x554d }, +/* 0x554e */ { false, 0x554e, 0x554e }, +/* 0x554f */ { false, 0x554f, 0x554f }, +/* 0x5550 */ { false, 0x5550, 0x5550 }, +/* 0x5551 */ { false, 0x5551, 0x5551 }, +/* 0x5552 */ { false, 0x5552, 0x5552 }, +/* 0x5553 */ { false, 0x5553, 0x5553 }, +/* 0x5554 */ { false, 0x5554, 0x5554 }, +/* 0x5555 */ { false, 0x5555, 0x5555 }, +/* 0x5556 */ { false, 0x5556, 0x5556 }, +/* 0x5557 */ { false, 0x5557, 0x5557 }, +/* 0x5558 */ { false, 0x5558, 0x5558 }, +/* 0x5559 */ { false, 0x5559, 0x5559 }, +/* 0x555a */ { false, 0x555a, 0x555a }, +/* 0x555b */ { false, 0x555b, 0x555b }, +/* 0x555c */ { false, 0x555c, 0x555c }, +/* 0x555d */ { false, 0x555d, 0x555d }, +/* 0x555e */ { false, 0x555e, 0x555e }, +/* 0x555f */ { false, 0x555f, 0x555f }, +/* 0x5560 */ { false, 0x5560, 0x5560 }, +/* 0x5561 */ { false, 0x5561, 0x5561 }, +/* 0x5562 */ { false, 0x5562, 0x5562 }, +/* 0x5563 */ { false, 0x5563, 0x5563 }, +/* 0x5564 */ { false, 0x5564, 0x5564 }, +/* 0x5565 */ { false, 0x5565, 0x5565 }, +/* 0x5566 */ { false, 0x5566, 0x5566 }, +/* 0x5567 */ { false, 0x5567, 0x5567 }, +/* 0x5568 */ { false, 0x5568, 0x5568 }, +/* 0x5569 */ { false, 0x5569, 0x5569 }, +/* 0x556a */ { false, 0x556a, 0x556a }, +/* 0x556b */ { false, 0x556b, 0x556b }, +/* 0x556c */ { false, 0x556c, 0x556c }, +/* 0x556d */ { false, 0x556d, 0x556d }, +/* 0x556e */ { false, 0x556e, 0x556e }, +/* 0x556f */ { false, 0x556f, 0x556f }, +/* 0x5570 */ { false, 0x5570, 0x5570 }, +/* 0x5571 */ { false, 0x5571, 0x5571 }, +/* 0x5572 */ { false, 0x5572, 0x5572 }, +/* 0x5573 */ { false, 0x5573, 0x5573 }, +/* 0x5574 */ { false, 0x5574, 0x5574 }, +/* 0x5575 */ { false, 0x5575, 0x5575 }, +/* 0x5576 */ { false, 0x5576, 0x5576 }, +/* 0x5577 */ { false, 0x5577, 0x5577 }, +/* 0x5578 */ { false, 0x5578, 0x5578 }, +/* 0x5579 */ { false, 0x5579, 0x5579 }, +/* 0x557a */ { false, 0x557a, 0x557a }, +/* 0x557b */ { false, 0x557b, 0x557b }, +/* 0x557c */ { false, 0x557c, 0x557c }, +/* 0x557d */ { false, 0x557d, 0x557d }, +/* 0x557e */ { false, 0x557e, 0x557e }, +/* 0x557f */ { false, 0x557f, 0x557f }, +/* 0x5580 */ { false, 0x5580, 0x5580 }, +/* 0x5581 */ { false, 0x5581, 0x5581 }, +/* 0x5582 */ { false, 0x5582, 0x5582 }, +/* 0x5583 */ { false, 0x5583, 0x5583 }, +/* 0x5584 */ { false, 0x5584, 0x5584 }, +/* 0x5585 */ { false, 0x5585, 0x5585 }, +/* 0x5586 */ { false, 0x5586, 0x5586 }, +/* 0x5587 */ { false, 0x5587, 0x5587 }, +/* 0x5588 */ { false, 0x5588, 0x5588 }, +/* 0x5589 */ { false, 0x5589, 0x5589 }, +/* 0x558a */ { false, 0x558a, 0x558a }, +/* 0x558b */ { false, 0x558b, 0x558b }, +/* 0x558c */ { false, 0x558c, 0x558c }, +/* 0x558d */ { false, 0x558d, 0x558d }, +/* 0x558e */ { false, 0x558e, 0x558e }, +/* 0x558f */ { false, 0x558f, 0x558f }, +/* 0x5590 */ { false, 0x5590, 0x5590 }, +/* 0x5591 */ { false, 0x5591, 0x5591 }, +/* 0x5592 */ { false, 0x5592, 0x5592 }, +/* 0x5593 */ { false, 0x5593, 0x5593 }, +/* 0x5594 */ { false, 0x5594, 0x5594 }, +/* 0x5595 */ { false, 0x5595, 0x5595 }, +/* 0x5596 */ { false, 0x5596, 0x5596 }, +/* 0x5597 */ { false, 0x5597, 0x5597 }, +/* 0x5598 */ { false, 0x5598, 0x5598 }, +/* 0x5599 */ { false, 0x5599, 0x5599 }, +/* 0x559a */ { false, 0x559a, 0x559a }, +/* 0x559b */ { false, 0x559b, 0x559b }, +/* 0x559c */ { false, 0x559c, 0x559c }, +/* 0x559d */ { false, 0x559d, 0x559d }, +/* 0x559e */ { false, 0x559e, 0x559e }, +/* 0x559f */ { false, 0x559f, 0x559f }, +/* 0x55a0 */ { false, 0x55a0, 0x55a0 }, +/* 0x55a1 */ { false, 0x55a1, 0x55a1 }, +/* 0x55a2 */ { false, 0x55a2, 0x55a2 }, +/* 0x55a3 */ { false, 0x55a3, 0x55a3 }, +/* 0x55a4 */ { false, 0x55a4, 0x55a4 }, +/* 0x55a5 */ { false, 0x55a5, 0x55a5 }, +/* 0x55a6 */ { false, 0x55a6, 0x55a6 }, +/* 0x55a7 */ { false, 0x55a7, 0x55a7 }, +/* 0x55a8 */ { false, 0x55a8, 0x55a8 }, +/* 0x55a9 */ { false, 0x55a9, 0x55a9 }, +/* 0x55aa */ { false, 0x55aa, 0x55aa }, +/* 0x55ab */ { false, 0x55ab, 0x55ab }, +/* 0x55ac */ { false, 0x55ac, 0x55ac }, +/* 0x55ad */ { false, 0x55ad, 0x55ad }, +/* 0x55ae */ { false, 0x55ae, 0x55ae }, +/* 0x55af */ { false, 0x55af, 0x55af }, +/* 0x55b0 */ { false, 0x55b0, 0x55b0 }, +/* 0x55b1 */ { false, 0x55b1, 0x55b1 }, +/* 0x55b2 */ { false, 0x55b2, 0x55b2 }, +/* 0x55b3 */ { false, 0x55b3, 0x55b3 }, +/* 0x55b4 */ { false, 0x55b4, 0x55b4 }, +/* 0x55b5 */ { false, 0x55b5, 0x55b5 }, +/* 0x55b6 */ { false, 0x55b6, 0x55b6 }, +/* 0x55b7 */ { false, 0x55b7, 0x55b7 }, +/* 0x55b8 */ { false, 0x55b8, 0x55b8 }, +/* 0x55b9 */ { false, 0x55b9, 0x55b9 }, +/* 0x55ba */ { false, 0x55ba, 0x55ba }, +/* 0x55bb */ { false, 0x55bb, 0x55bb }, +/* 0x55bc */ { false, 0x55bc, 0x55bc }, +/* 0x55bd */ { false, 0x55bd, 0x55bd }, +/* 0x55be */ { false, 0x55be, 0x55be }, +/* 0x55bf */ { false, 0x55bf, 0x55bf }, +/* 0x55c0 */ { false, 0x55c0, 0x55c0 }, +/* 0x55c1 */ { false, 0x55c1, 0x55c1 }, +/* 0x55c2 */ { false, 0x55c2, 0x55c2 }, +/* 0x55c3 */ { false, 0x55c3, 0x55c3 }, +/* 0x55c4 */ { false, 0x55c4, 0x55c4 }, +/* 0x55c5 */ { false, 0x55c5, 0x55c5 }, +/* 0x55c6 */ { false, 0x55c6, 0x55c6 }, +/* 0x55c7 */ { false, 0x55c7, 0x55c7 }, +/* 0x55c8 */ { false, 0x55c8, 0x55c8 }, +/* 0x55c9 */ { false, 0x55c9, 0x55c9 }, +/* 0x55ca */ { false, 0x55ca, 0x55ca }, +/* 0x55cb */ { false, 0x55cb, 0x55cb }, +/* 0x55cc */ { false, 0x55cc, 0x55cc }, +/* 0x55cd */ { false, 0x55cd, 0x55cd }, +/* 0x55ce */ { false, 0x55ce, 0x55ce }, +/* 0x55cf */ { false, 0x55cf, 0x55cf }, +/* 0x55d0 */ { false, 0x55d0, 0x55d0 }, +/* 0x55d1 */ { false, 0x55d1, 0x55d1 }, +/* 0x55d2 */ { false, 0x55d2, 0x55d2 }, +/* 0x55d3 */ { false, 0x55d3, 0x55d3 }, +/* 0x55d4 */ { false, 0x55d4, 0x55d4 }, +/* 0x55d5 */ { false, 0x55d5, 0x55d5 }, +/* 0x55d6 */ { false, 0x55d6, 0x55d6 }, +/* 0x55d7 */ { false, 0x55d7, 0x55d7 }, +/* 0x55d8 */ { false, 0x55d8, 0x55d8 }, +/* 0x55d9 */ { false, 0x55d9, 0x55d9 }, +/* 0x55da */ { false, 0x55da, 0x55da }, +/* 0x55db */ { false, 0x55db, 0x55db }, +/* 0x55dc */ { false, 0x55dc, 0x55dc }, +/* 0x55dd */ { false, 0x55dd, 0x55dd }, +/* 0x55de */ { false, 0x55de, 0x55de }, +/* 0x55df */ { false, 0x55df, 0x55df }, +/* 0x55e0 */ { false, 0x55e0, 0x55e0 }, +/* 0x55e1 */ { false, 0x55e1, 0x55e1 }, +/* 0x55e2 */ { false, 0x55e2, 0x55e2 }, +/* 0x55e3 */ { false, 0x55e3, 0x55e3 }, +/* 0x55e4 */ { false, 0x55e4, 0x55e4 }, +/* 0x55e5 */ { false, 0x55e5, 0x55e5 }, +/* 0x55e6 */ { false, 0x55e6, 0x55e6 }, +/* 0x55e7 */ { false, 0x55e7, 0x55e7 }, +/* 0x55e8 */ { false, 0x55e8, 0x55e8 }, +/* 0x55e9 */ { false, 0x55e9, 0x55e9 }, +/* 0x55ea */ { false, 0x55ea, 0x55ea }, +/* 0x55eb */ { false, 0x55eb, 0x55eb }, +/* 0x55ec */ { false, 0x55ec, 0x55ec }, +/* 0x55ed */ { false, 0x55ed, 0x55ed }, +/* 0x55ee */ { false, 0x55ee, 0x55ee }, +/* 0x55ef */ { false, 0x55ef, 0x55ef }, +/* 0x55f0 */ { false, 0x55f0, 0x55f0 }, +/* 0x55f1 */ { false, 0x55f1, 0x55f1 }, +/* 0x55f2 */ { false, 0x55f2, 0x55f2 }, +/* 0x55f3 */ { false, 0x55f3, 0x55f3 }, +/* 0x55f4 */ { false, 0x55f4, 0x55f4 }, +/* 0x55f5 */ { false, 0x55f5, 0x55f5 }, +/* 0x55f6 */ { false, 0x55f6, 0x55f6 }, +/* 0x55f7 */ { false, 0x55f7, 0x55f7 }, +/* 0x55f8 */ { false, 0x55f8, 0x55f8 }, +/* 0x55f9 */ { false, 0x55f9, 0x55f9 }, +/* 0x55fa */ { false, 0x55fa, 0x55fa }, +/* 0x55fb */ { false, 0x55fb, 0x55fb }, +/* 0x55fc */ { false, 0x55fc, 0x55fc }, +/* 0x55fd */ { false, 0x55fd, 0x55fd }, +/* 0x55fe */ { false, 0x55fe, 0x55fe }, +/* 0x55ff */ { false, 0x55ff, 0x55ff }, +/* 0x5600 */ { false, 0x5600, 0x5600 }, +/* 0x5601 */ { false, 0x5601, 0x5601 }, +/* 0x5602 */ { false, 0x5602, 0x5602 }, +/* 0x5603 */ { false, 0x5603, 0x5603 }, +/* 0x5604 */ { false, 0x5604, 0x5604 }, +/* 0x5605 */ { false, 0x5605, 0x5605 }, +/* 0x5606 */ { false, 0x5606, 0x5606 }, +/* 0x5607 */ { false, 0x5607, 0x5607 }, +/* 0x5608 */ { false, 0x5608, 0x5608 }, +/* 0x5609 */ { false, 0x5609, 0x5609 }, +/* 0x560a */ { false, 0x560a, 0x560a }, +/* 0x560b */ { false, 0x560b, 0x560b }, +/* 0x560c */ { false, 0x560c, 0x560c }, +/* 0x560d */ { false, 0x560d, 0x560d }, +/* 0x560e */ { false, 0x560e, 0x560e }, +/* 0x560f */ { false, 0x560f, 0x560f }, +/* 0x5610 */ { false, 0x5610, 0x5610 }, +/* 0x5611 */ { false, 0x5611, 0x5611 }, +/* 0x5612 */ { false, 0x5612, 0x5612 }, +/* 0x5613 */ { false, 0x5613, 0x5613 }, +/* 0x5614 */ { false, 0x5614, 0x5614 }, +/* 0x5615 */ { false, 0x5615, 0x5615 }, +/* 0x5616 */ { false, 0x5616, 0x5616 }, +/* 0x5617 */ { false, 0x5617, 0x5617 }, +/* 0x5618 */ { false, 0x5618, 0x5618 }, +/* 0x5619 */ { false, 0x5619, 0x5619 }, +/* 0x561a */ { false, 0x561a, 0x561a }, +/* 0x561b */ { false, 0x561b, 0x561b }, +/* 0x561c */ { false, 0x561c, 0x561c }, +/* 0x561d */ { false, 0x561d, 0x561d }, +/* 0x561e */ { false, 0x561e, 0x561e }, +/* 0x561f */ { false, 0x561f, 0x561f }, +/* 0x5620 */ { false, 0x5620, 0x5620 }, +/* 0x5621 */ { false, 0x5621, 0x5621 }, +/* 0x5622 */ { false, 0x5622, 0x5622 }, +/* 0x5623 */ { false, 0x5623, 0x5623 }, +/* 0x5624 */ { false, 0x5624, 0x5624 }, +/* 0x5625 */ { false, 0x5625, 0x5625 }, +/* 0x5626 */ { false, 0x5626, 0x5626 }, +/* 0x5627 */ { false, 0x5627, 0x5627 }, +/* 0x5628 */ { false, 0x5628, 0x5628 }, +/* 0x5629 */ { false, 0x5629, 0x5629 }, +/* 0x562a */ { false, 0x562a, 0x562a }, +/* 0x562b */ { false, 0x562b, 0x562b }, +/* 0x562c */ { false, 0x562c, 0x562c }, +/* 0x562d */ { false, 0x562d, 0x562d }, +/* 0x562e */ { false, 0x562e, 0x562e }, +/* 0x562f */ { false, 0x562f, 0x562f }, +/* 0x5630 */ { false, 0x5630, 0x5630 }, +/* 0x5631 */ { false, 0x5631, 0x5631 }, +/* 0x5632 */ { false, 0x5632, 0x5632 }, +/* 0x5633 */ { false, 0x5633, 0x5633 }, +/* 0x5634 */ { false, 0x5634, 0x5634 }, +/* 0x5635 */ { false, 0x5635, 0x5635 }, +/* 0x5636 */ { false, 0x5636, 0x5636 }, +/* 0x5637 */ { false, 0x5637, 0x5637 }, +/* 0x5638 */ { false, 0x5638, 0x5638 }, +/* 0x5639 */ { false, 0x5639, 0x5639 }, +/* 0x563a */ { false, 0x563a, 0x563a }, +/* 0x563b */ { false, 0x563b, 0x563b }, +/* 0x563c */ { false, 0x563c, 0x563c }, +/* 0x563d */ { false, 0x563d, 0x563d }, +/* 0x563e */ { false, 0x563e, 0x563e }, +/* 0x563f */ { false, 0x563f, 0x563f }, +/* 0x5640 */ { false, 0x5640, 0x5640 }, +/* 0x5641 */ { false, 0x5641, 0x5641 }, +/* 0x5642 */ { false, 0x5642, 0x5642 }, +/* 0x5643 */ { false, 0x5643, 0x5643 }, +/* 0x5644 */ { false, 0x5644, 0x5644 }, +/* 0x5645 */ { false, 0x5645, 0x5645 }, +/* 0x5646 */ { false, 0x5646, 0x5646 }, +/* 0x5647 */ { false, 0x5647, 0x5647 }, +/* 0x5648 */ { false, 0x5648, 0x5648 }, +/* 0x5649 */ { false, 0x5649, 0x5649 }, +/* 0x564a */ { false, 0x564a, 0x564a }, +/* 0x564b */ { false, 0x564b, 0x564b }, +/* 0x564c */ { false, 0x564c, 0x564c }, +/* 0x564d */ { false, 0x564d, 0x564d }, +/* 0x564e */ { false, 0x564e, 0x564e }, +/* 0x564f */ { false, 0x564f, 0x564f }, +/* 0x5650 */ { false, 0x5650, 0x5650 }, +/* 0x5651 */ { false, 0x5651, 0x5651 }, +/* 0x5652 */ { false, 0x5652, 0x5652 }, +/* 0x5653 */ { false, 0x5653, 0x5653 }, +/* 0x5654 */ { false, 0x5654, 0x5654 }, +/* 0x5655 */ { false, 0x5655, 0x5655 }, +/* 0x5656 */ { false, 0x5656, 0x5656 }, +/* 0x5657 */ { false, 0x5657, 0x5657 }, +/* 0x5658 */ { false, 0x5658, 0x5658 }, +/* 0x5659 */ { false, 0x5659, 0x5659 }, +/* 0x565a */ { false, 0x565a, 0x565a }, +/* 0x565b */ { false, 0x565b, 0x565b }, +/* 0x565c */ { false, 0x565c, 0x565c }, +/* 0x565d */ { false, 0x565d, 0x565d }, +/* 0x565e */ { false, 0x565e, 0x565e }, +/* 0x565f */ { false, 0x565f, 0x565f }, +/* 0x5660 */ { false, 0x5660, 0x5660 }, +/* 0x5661 */ { false, 0x5661, 0x5661 }, +/* 0x5662 */ { false, 0x5662, 0x5662 }, +/* 0x5663 */ { false, 0x5663, 0x5663 }, +/* 0x5664 */ { false, 0x5664, 0x5664 }, +/* 0x5665 */ { false, 0x5665, 0x5665 }, +/* 0x5666 */ { false, 0x5666, 0x5666 }, +/* 0x5667 */ { false, 0x5667, 0x5667 }, +/* 0x5668 */ { false, 0x5668, 0x5668 }, +/* 0x5669 */ { false, 0x5669, 0x5669 }, +/* 0x566a */ { false, 0x566a, 0x566a }, +/* 0x566b */ { false, 0x566b, 0x566b }, +/* 0x566c */ { false, 0x566c, 0x566c }, +/* 0x566d */ { false, 0x566d, 0x566d }, +/* 0x566e */ { false, 0x566e, 0x566e }, +/* 0x566f */ { false, 0x566f, 0x566f }, +/* 0x5670 */ { false, 0x5670, 0x5670 }, +/* 0x5671 */ { false, 0x5671, 0x5671 }, +/* 0x5672 */ { false, 0x5672, 0x5672 }, +/* 0x5673 */ { false, 0x5673, 0x5673 }, +/* 0x5674 */ { false, 0x5674, 0x5674 }, +/* 0x5675 */ { false, 0x5675, 0x5675 }, +/* 0x5676 */ { false, 0x5676, 0x5676 }, +/* 0x5677 */ { false, 0x5677, 0x5677 }, +/* 0x5678 */ { false, 0x5678, 0x5678 }, +/* 0x5679 */ { false, 0x5679, 0x5679 }, +/* 0x567a */ { false, 0x567a, 0x567a }, +/* 0x567b */ { false, 0x567b, 0x567b }, +/* 0x567c */ { false, 0x567c, 0x567c }, +/* 0x567d */ { false, 0x567d, 0x567d }, +/* 0x567e */ { false, 0x567e, 0x567e }, +/* 0x567f */ { false, 0x567f, 0x567f }, +/* 0x5680 */ { false, 0x5680, 0x5680 }, +/* 0x5681 */ { false, 0x5681, 0x5681 }, +/* 0x5682 */ { false, 0x5682, 0x5682 }, +/* 0x5683 */ { false, 0x5683, 0x5683 }, +/* 0x5684 */ { false, 0x5684, 0x5684 }, +/* 0x5685 */ { false, 0x5685, 0x5685 }, +/* 0x5686 */ { false, 0x5686, 0x5686 }, +/* 0x5687 */ { false, 0x5687, 0x5687 }, +/* 0x5688 */ { false, 0x5688, 0x5688 }, +/* 0x5689 */ { false, 0x5689, 0x5689 }, +/* 0x568a */ { false, 0x568a, 0x568a }, +/* 0x568b */ { false, 0x568b, 0x568b }, +/* 0x568c */ { false, 0x568c, 0x568c }, +/* 0x568d */ { false, 0x568d, 0x568d }, +/* 0x568e */ { false, 0x568e, 0x568e }, +/* 0x568f */ { false, 0x568f, 0x568f }, +/* 0x5690 */ { false, 0x5690, 0x5690 }, +/* 0x5691 */ { false, 0x5691, 0x5691 }, +/* 0x5692 */ { false, 0x5692, 0x5692 }, +/* 0x5693 */ { false, 0x5693, 0x5693 }, +/* 0x5694 */ { false, 0x5694, 0x5694 }, +/* 0x5695 */ { false, 0x5695, 0x5695 }, +/* 0x5696 */ { false, 0x5696, 0x5696 }, +/* 0x5697 */ { false, 0x5697, 0x5697 }, +/* 0x5698 */ { false, 0x5698, 0x5698 }, +/* 0x5699 */ { false, 0x5699, 0x5699 }, +/* 0x569a */ { false, 0x569a, 0x569a }, +/* 0x569b */ { false, 0x569b, 0x569b }, +/* 0x569c */ { false, 0x569c, 0x569c }, +/* 0x569d */ { false, 0x569d, 0x569d }, +/* 0x569e */ { false, 0x569e, 0x569e }, +/* 0x569f */ { false, 0x569f, 0x569f }, +/* 0x56a0 */ { false, 0x56a0, 0x56a0 }, +/* 0x56a1 */ { false, 0x56a1, 0x56a1 }, +/* 0x56a2 */ { false, 0x56a2, 0x56a2 }, +/* 0x56a3 */ { false, 0x56a3, 0x56a3 }, +/* 0x56a4 */ { false, 0x56a4, 0x56a4 }, +/* 0x56a5 */ { false, 0x56a5, 0x56a5 }, +/* 0x56a6 */ { false, 0x56a6, 0x56a6 }, +/* 0x56a7 */ { false, 0x56a7, 0x56a7 }, +/* 0x56a8 */ { false, 0x56a8, 0x56a8 }, +/* 0x56a9 */ { false, 0x56a9, 0x56a9 }, +/* 0x56aa */ { false, 0x56aa, 0x56aa }, +/* 0x56ab */ { false, 0x56ab, 0x56ab }, +/* 0x56ac */ { false, 0x56ac, 0x56ac }, +/* 0x56ad */ { false, 0x56ad, 0x56ad }, +/* 0x56ae */ { false, 0x56ae, 0x56ae }, +/* 0x56af */ { false, 0x56af, 0x56af }, +/* 0x56b0 */ { false, 0x56b0, 0x56b0 }, +/* 0x56b1 */ { false, 0x56b1, 0x56b1 }, +/* 0x56b2 */ { false, 0x56b2, 0x56b2 }, +/* 0x56b3 */ { false, 0x56b3, 0x56b3 }, +/* 0x56b4 */ { false, 0x56b4, 0x56b4 }, +/* 0x56b5 */ { false, 0x56b5, 0x56b5 }, +/* 0x56b6 */ { false, 0x56b6, 0x56b6 }, +/* 0x56b7 */ { false, 0x56b7, 0x56b7 }, +/* 0x56b8 */ { false, 0x56b8, 0x56b8 }, +/* 0x56b9 */ { false, 0x56b9, 0x56b9 }, +/* 0x56ba */ { false, 0x56ba, 0x56ba }, +/* 0x56bb */ { false, 0x56bb, 0x56bb }, +/* 0x56bc */ { false, 0x56bc, 0x56bc }, +/* 0x56bd */ { false, 0x56bd, 0x56bd }, +/* 0x56be */ { false, 0x56be, 0x56be }, +/* 0x56bf */ { false, 0x56bf, 0x56bf }, +/* 0x56c0 */ { false, 0x56c0, 0x56c0 }, +/* 0x56c1 */ { false, 0x56c1, 0x56c1 }, +/* 0x56c2 */ { false, 0x56c2, 0x56c2 }, +/* 0x56c3 */ { false, 0x56c3, 0x56c3 }, +/* 0x56c4 */ { false, 0x56c4, 0x56c4 }, +/* 0x56c5 */ { false, 0x56c5, 0x56c5 }, +/* 0x56c6 */ { false, 0x56c6, 0x56c6 }, +/* 0x56c7 */ { false, 0x56c7, 0x56c7 }, +/* 0x56c8 */ { false, 0x56c8, 0x56c8 }, +/* 0x56c9 */ { false, 0x56c9, 0x56c9 }, +/* 0x56ca */ { false, 0x56ca, 0x56ca }, +/* 0x56cb */ { false, 0x56cb, 0x56cb }, +/* 0x56cc */ { false, 0x56cc, 0x56cc }, +/* 0x56cd */ { false, 0x56cd, 0x56cd }, +/* 0x56ce */ { false, 0x56ce, 0x56ce }, +/* 0x56cf */ { false, 0x56cf, 0x56cf }, +/* 0x56d0 */ { false, 0x56d0, 0x56d0 }, +/* 0x56d1 */ { false, 0x56d1, 0x56d1 }, +/* 0x56d2 */ { false, 0x56d2, 0x56d2 }, +/* 0x56d3 */ { false, 0x56d3, 0x56d3 }, +/* 0x56d4 */ { false, 0x56d4, 0x56d4 }, +/* 0x56d5 */ { false, 0x56d5, 0x56d5 }, +/* 0x56d6 */ { false, 0x56d6, 0x56d6 }, +/* 0x56d7 */ { false, 0x56d7, 0x56d7 }, +/* 0x56d8 */ { false, 0x56d8, 0x56d8 }, +/* 0x56d9 */ { false, 0x56d9, 0x56d9 }, +/* 0x56da */ { false, 0x56da, 0x56da }, +/* 0x56db */ { false, 0x56db, 0x56db }, +/* 0x56dc */ { false, 0x56dc, 0x56dc }, +/* 0x56dd */ { false, 0x56dd, 0x56dd }, +/* 0x56de */ { false, 0x56de, 0x56de }, +/* 0x56df */ { false, 0x56df, 0x56df }, +/* 0x56e0 */ { false, 0x56e0, 0x56e0 }, +/* 0x56e1 */ { false, 0x56e1, 0x56e1 }, +/* 0x56e2 */ { false, 0x56e2, 0x56e2 }, +/* 0x56e3 */ { false, 0x56e3, 0x56e3 }, +/* 0x56e4 */ { false, 0x56e4, 0x56e4 }, +/* 0x56e5 */ { false, 0x56e5, 0x56e5 }, +/* 0x56e6 */ { false, 0x56e6, 0x56e6 }, +/* 0x56e7 */ { false, 0x56e7, 0x56e7 }, +/* 0x56e8 */ { false, 0x56e8, 0x56e8 }, +/* 0x56e9 */ { false, 0x56e9, 0x56e9 }, +/* 0x56ea */ { false, 0x56ea, 0x56ea }, +/* 0x56eb */ { false, 0x56eb, 0x56eb }, +/* 0x56ec */ { false, 0x56ec, 0x56ec }, +/* 0x56ed */ { false, 0x56ed, 0x56ed }, +/* 0x56ee */ { false, 0x56ee, 0x56ee }, +/* 0x56ef */ { false, 0x56ef, 0x56ef }, +/* 0x56f0 */ { false, 0x56f0, 0x56f0 }, +/* 0x56f1 */ { false, 0x56f1, 0x56f1 }, +/* 0x56f2 */ { false, 0x56f2, 0x56f2 }, +/* 0x56f3 */ { false, 0x56f3, 0x56f3 }, +/* 0x56f4 */ { false, 0x56f4, 0x56f4 }, +/* 0x56f5 */ { false, 0x56f5, 0x56f5 }, +/* 0x56f6 */ { false, 0x56f6, 0x56f6 }, +/* 0x56f7 */ { false, 0x56f7, 0x56f7 }, +/* 0x56f8 */ { false, 0x56f8, 0x56f8 }, +/* 0x56f9 */ { false, 0x56f9, 0x56f9 }, +/* 0x56fa */ { false, 0x56fa, 0x56fa }, +/* 0x56fb */ { false, 0x56fb, 0x56fb }, +/* 0x56fc */ { false, 0x56fc, 0x56fc }, +/* 0x56fd */ { false, 0x56fd, 0x56fd }, +/* 0x56fe */ { false, 0x56fe, 0x56fe }, +/* 0x56ff */ { false, 0x56ff, 0x56ff }, +/* 0x5700 */ { false, 0x5700, 0x5700 }, +/* 0x5701 */ { false, 0x5701, 0x5701 }, +/* 0x5702 */ { false, 0x5702, 0x5702 }, +/* 0x5703 */ { false, 0x5703, 0x5703 }, +/* 0x5704 */ { false, 0x5704, 0x5704 }, +/* 0x5705 */ { false, 0x5705, 0x5705 }, +/* 0x5706 */ { false, 0x5706, 0x5706 }, +/* 0x5707 */ { false, 0x5707, 0x5707 }, +/* 0x5708 */ { false, 0x5708, 0x5708 }, +/* 0x5709 */ { false, 0x5709, 0x5709 }, +/* 0x570a */ { false, 0x570a, 0x570a }, +/* 0x570b */ { false, 0x570b, 0x570b }, +/* 0x570c */ { false, 0x570c, 0x570c }, +/* 0x570d */ { false, 0x570d, 0x570d }, +/* 0x570e */ { false, 0x570e, 0x570e }, +/* 0x570f */ { false, 0x570f, 0x570f }, +/* 0x5710 */ { false, 0x5710, 0x5710 }, +/* 0x5711 */ { false, 0x5711, 0x5711 }, +/* 0x5712 */ { false, 0x5712, 0x5712 }, +/* 0x5713 */ { false, 0x5713, 0x5713 }, +/* 0x5714 */ { false, 0x5714, 0x5714 }, +/* 0x5715 */ { false, 0x5715, 0x5715 }, +/* 0x5716 */ { false, 0x5716, 0x5716 }, +/* 0x5717 */ { false, 0x5717, 0x5717 }, +/* 0x5718 */ { false, 0x5718, 0x5718 }, +/* 0x5719 */ { false, 0x5719, 0x5719 }, +/* 0x571a */ { false, 0x571a, 0x571a }, +/* 0x571b */ { false, 0x571b, 0x571b }, +/* 0x571c */ { false, 0x571c, 0x571c }, +/* 0x571d */ { false, 0x571d, 0x571d }, +/* 0x571e */ { false, 0x571e, 0x571e }, +/* 0x571f */ { false, 0x571f, 0x571f }, +/* 0x5720 */ { false, 0x5720, 0x5720 }, +/* 0x5721 */ { false, 0x5721, 0x5721 }, +/* 0x5722 */ { false, 0x5722, 0x5722 }, +/* 0x5723 */ { false, 0x5723, 0x5723 }, +/* 0x5724 */ { false, 0x5724, 0x5724 }, +/* 0x5725 */ { false, 0x5725, 0x5725 }, +/* 0x5726 */ { false, 0x5726, 0x5726 }, +/* 0x5727 */ { false, 0x5727, 0x5727 }, +/* 0x5728 */ { false, 0x5728, 0x5728 }, +/* 0x5729 */ { false, 0x5729, 0x5729 }, +/* 0x572a */ { false, 0x572a, 0x572a }, +/* 0x572b */ { false, 0x572b, 0x572b }, +/* 0x572c */ { false, 0x572c, 0x572c }, +/* 0x572d */ { false, 0x572d, 0x572d }, +/* 0x572e */ { false, 0x572e, 0x572e }, +/* 0x572f */ { false, 0x572f, 0x572f }, +/* 0x5730 */ { false, 0x5730, 0x5730 }, +/* 0x5731 */ { false, 0x5731, 0x5731 }, +/* 0x5732 */ { false, 0x5732, 0x5732 }, +/* 0x5733 */ { false, 0x5733, 0x5733 }, +/* 0x5734 */ { false, 0x5734, 0x5734 }, +/* 0x5735 */ { false, 0x5735, 0x5735 }, +/* 0x5736 */ { false, 0x5736, 0x5736 }, +/* 0x5737 */ { false, 0x5737, 0x5737 }, +/* 0x5738 */ { false, 0x5738, 0x5738 }, +/* 0x5739 */ { false, 0x5739, 0x5739 }, +/* 0x573a */ { false, 0x573a, 0x573a }, +/* 0x573b */ { false, 0x573b, 0x573b }, +/* 0x573c */ { false, 0x573c, 0x573c }, +/* 0x573d */ { false, 0x573d, 0x573d }, +/* 0x573e */ { false, 0x573e, 0x573e }, +/* 0x573f */ { false, 0x573f, 0x573f }, +/* 0x5740 */ { false, 0x5740, 0x5740 }, +/* 0x5741 */ { false, 0x5741, 0x5741 }, +/* 0x5742 */ { false, 0x5742, 0x5742 }, +/* 0x5743 */ { false, 0x5743, 0x5743 }, +/* 0x5744 */ { false, 0x5744, 0x5744 }, +/* 0x5745 */ { false, 0x5745, 0x5745 }, +/* 0x5746 */ { false, 0x5746, 0x5746 }, +/* 0x5747 */ { false, 0x5747, 0x5747 }, +/* 0x5748 */ { false, 0x5748, 0x5748 }, +/* 0x5749 */ { false, 0x5749, 0x5749 }, +/* 0x574a */ { false, 0x574a, 0x574a }, +/* 0x574b */ { false, 0x574b, 0x574b }, +/* 0x574c */ { false, 0x574c, 0x574c }, +/* 0x574d */ { false, 0x574d, 0x574d }, +/* 0x574e */ { false, 0x574e, 0x574e }, +/* 0x574f */ { false, 0x574f, 0x574f }, +/* 0x5750 */ { false, 0x5750, 0x5750 }, +/* 0x5751 */ { false, 0x5751, 0x5751 }, +/* 0x5752 */ { false, 0x5752, 0x5752 }, +/* 0x5753 */ { false, 0x5753, 0x5753 }, +/* 0x5754 */ { false, 0x5754, 0x5754 }, +/* 0x5755 */ { false, 0x5755, 0x5755 }, +/* 0x5756 */ { false, 0x5756, 0x5756 }, +/* 0x5757 */ { false, 0x5757, 0x5757 }, +/* 0x5758 */ { false, 0x5758, 0x5758 }, +/* 0x5759 */ { false, 0x5759, 0x5759 }, +/* 0x575a */ { false, 0x575a, 0x575a }, +/* 0x575b */ { false, 0x575b, 0x575b }, +/* 0x575c */ { false, 0x575c, 0x575c }, +/* 0x575d */ { false, 0x575d, 0x575d }, +/* 0x575e */ { false, 0x575e, 0x575e }, +/* 0x575f */ { false, 0x575f, 0x575f }, +/* 0x5760 */ { false, 0x5760, 0x5760 }, +/* 0x5761 */ { false, 0x5761, 0x5761 }, +/* 0x5762 */ { false, 0x5762, 0x5762 }, +/* 0x5763 */ { false, 0x5763, 0x5763 }, +/* 0x5764 */ { false, 0x5764, 0x5764 }, +/* 0x5765 */ { false, 0x5765, 0x5765 }, +/* 0x5766 */ { false, 0x5766, 0x5766 }, +/* 0x5767 */ { false, 0x5767, 0x5767 }, +/* 0x5768 */ { false, 0x5768, 0x5768 }, +/* 0x5769 */ { false, 0x5769, 0x5769 }, +/* 0x576a */ { false, 0x576a, 0x576a }, +/* 0x576b */ { false, 0x576b, 0x576b }, +/* 0x576c */ { false, 0x576c, 0x576c }, +/* 0x576d */ { false, 0x576d, 0x576d }, +/* 0x576e */ { false, 0x576e, 0x576e }, +/* 0x576f */ { false, 0x576f, 0x576f }, +/* 0x5770 */ { false, 0x5770, 0x5770 }, +/* 0x5771 */ { false, 0x5771, 0x5771 }, +/* 0x5772 */ { false, 0x5772, 0x5772 }, +/* 0x5773 */ { false, 0x5773, 0x5773 }, +/* 0x5774 */ { false, 0x5774, 0x5774 }, +/* 0x5775 */ { false, 0x5775, 0x5775 }, +/* 0x5776 */ { false, 0x5776, 0x5776 }, +/* 0x5777 */ { false, 0x5777, 0x5777 }, +/* 0x5778 */ { false, 0x5778, 0x5778 }, +/* 0x5779 */ { false, 0x5779, 0x5779 }, +/* 0x577a */ { false, 0x577a, 0x577a }, +/* 0x577b */ { false, 0x577b, 0x577b }, +/* 0x577c */ { false, 0x577c, 0x577c }, +/* 0x577d */ { false, 0x577d, 0x577d }, +/* 0x577e */ { false, 0x577e, 0x577e }, +/* 0x577f */ { false, 0x577f, 0x577f }, +/* 0x5780 */ { false, 0x5780, 0x5780 }, +/* 0x5781 */ { false, 0x5781, 0x5781 }, +/* 0x5782 */ { false, 0x5782, 0x5782 }, +/* 0x5783 */ { false, 0x5783, 0x5783 }, +/* 0x5784 */ { false, 0x5784, 0x5784 }, +/* 0x5785 */ { false, 0x5785, 0x5785 }, +/* 0x5786 */ { false, 0x5786, 0x5786 }, +/* 0x5787 */ { false, 0x5787, 0x5787 }, +/* 0x5788 */ { false, 0x5788, 0x5788 }, +/* 0x5789 */ { false, 0x5789, 0x5789 }, +/* 0x578a */ { false, 0x578a, 0x578a }, +/* 0x578b */ { false, 0x578b, 0x578b }, +/* 0x578c */ { false, 0x578c, 0x578c }, +/* 0x578d */ { false, 0x578d, 0x578d }, +/* 0x578e */ { false, 0x578e, 0x578e }, +/* 0x578f */ { false, 0x578f, 0x578f }, +/* 0x5790 */ { false, 0x5790, 0x5790 }, +/* 0x5791 */ { false, 0x5791, 0x5791 }, +/* 0x5792 */ { false, 0x5792, 0x5792 }, +/* 0x5793 */ { false, 0x5793, 0x5793 }, +/* 0x5794 */ { false, 0x5794, 0x5794 }, +/* 0x5795 */ { false, 0x5795, 0x5795 }, +/* 0x5796 */ { false, 0x5796, 0x5796 }, +/* 0x5797 */ { false, 0x5797, 0x5797 }, +/* 0x5798 */ { false, 0x5798, 0x5798 }, +/* 0x5799 */ { false, 0x5799, 0x5799 }, +/* 0x579a */ { false, 0x579a, 0x579a }, +/* 0x579b */ { false, 0x579b, 0x579b }, +/* 0x579c */ { false, 0x579c, 0x579c }, +/* 0x579d */ { false, 0x579d, 0x579d }, +/* 0x579e */ { false, 0x579e, 0x579e }, +/* 0x579f */ { false, 0x579f, 0x579f }, +/* 0x57a0 */ { false, 0x57a0, 0x57a0 }, +/* 0x57a1 */ { false, 0x57a1, 0x57a1 }, +/* 0x57a2 */ { false, 0x57a2, 0x57a2 }, +/* 0x57a3 */ { false, 0x57a3, 0x57a3 }, +/* 0x57a4 */ { false, 0x57a4, 0x57a4 }, +/* 0x57a5 */ { false, 0x57a5, 0x57a5 }, +/* 0x57a6 */ { false, 0x57a6, 0x57a6 }, +/* 0x57a7 */ { false, 0x57a7, 0x57a7 }, +/* 0x57a8 */ { false, 0x57a8, 0x57a8 }, +/* 0x57a9 */ { false, 0x57a9, 0x57a9 }, +/* 0x57aa */ { false, 0x57aa, 0x57aa }, +/* 0x57ab */ { false, 0x57ab, 0x57ab }, +/* 0x57ac */ { false, 0x57ac, 0x57ac }, +/* 0x57ad */ { false, 0x57ad, 0x57ad }, +/* 0x57ae */ { false, 0x57ae, 0x57ae }, +/* 0x57af */ { false, 0x57af, 0x57af }, +/* 0x57b0 */ { false, 0x57b0, 0x57b0 }, +/* 0x57b1 */ { false, 0x57b1, 0x57b1 }, +/* 0x57b2 */ { false, 0x57b2, 0x57b2 }, +/* 0x57b3 */ { false, 0x57b3, 0x57b3 }, +/* 0x57b4 */ { false, 0x57b4, 0x57b4 }, +/* 0x57b5 */ { false, 0x57b5, 0x57b5 }, +/* 0x57b6 */ { false, 0x57b6, 0x57b6 }, +/* 0x57b7 */ { false, 0x57b7, 0x57b7 }, +/* 0x57b8 */ { false, 0x57b8, 0x57b8 }, +/* 0x57b9 */ { false, 0x57b9, 0x57b9 }, +/* 0x57ba */ { false, 0x57ba, 0x57ba }, +/* 0x57bb */ { false, 0x57bb, 0x57bb }, +/* 0x57bc */ { false, 0x57bc, 0x57bc }, +/* 0x57bd */ { false, 0x57bd, 0x57bd }, +/* 0x57be */ { false, 0x57be, 0x57be }, +/* 0x57bf */ { false, 0x57bf, 0x57bf }, +/* 0x57c0 */ { false, 0x57c0, 0x57c0 }, +/* 0x57c1 */ { false, 0x57c1, 0x57c1 }, +/* 0x57c2 */ { false, 0x57c2, 0x57c2 }, +/* 0x57c3 */ { false, 0x57c3, 0x57c3 }, +/* 0x57c4 */ { false, 0x57c4, 0x57c4 }, +/* 0x57c5 */ { false, 0x57c5, 0x57c5 }, +/* 0x57c6 */ { false, 0x57c6, 0x57c6 }, +/* 0x57c7 */ { false, 0x57c7, 0x57c7 }, +/* 0x57c8 */ { false, 0x57c8, 0x57c8 }, +/* 0x57c9 */ { false, 0x57c9, 0x57c9 }, +/* 0x57ca */ { false, 0x57ca, 0x57ca }, +/* 0x57cb */ { false, 0x57cb, 0x57cb }, +/* 0x57cc */ { false, 0x57cc, 0x57cc }, +/* 0x57cd */ { false, 0x57cd, 0x57cd }, +/* 0x57ce */ { false, 0x57ce, 0x57ce }, +/* 0x57cf */ { false, 0x57cf, 0x57cf }, +/* 0x57d0 */ { false, 0x57d0, 0x57d0 }, +/* 0x57d1 */ { false, 0x57d1, 0x57d1 }, +/* 0x57d2 */ { false, 0x57d2, 0x57d2 }, +/* 0x57d3 */ { false, 0x57d3, 0x57d3 }, +/* 0x57d4 */ { false, 0x57d4, 0x57d4 }, +/* 0x57d5 */ { false, 0x57d5, 0x57d5 }, +/* 0x57d6 */ { false, 0x57d6, 0x57d6 }, +/* 0x57d7 */ { false, 0x57d7, 0x57d7 }, +/* 0x57d8 */ { false, 0x57d8, 0x57d8 }, +/* 0x57d9 */ { false, 0x57d9, 0x57d9 }, +/* 0x57da */ { false, 0x57da, 0x57da }, +/* 0x57db */ { false, 0x57db, 0x57db }, +/* 0x57dc */ { false, 0x57dc, 0x57dc }, +/* 0x57dd */ { false, 0x57dd, 0x57dd }, +/* 0x57de */ { false, 0x57de, 0x57de }, +/* 0x57df */ { false, 0x57df, 0x57df }, +/* 0x57e0 */ { false, 0x57e0, 0x57e0 }, +/* 0x57e1 */ { false, 0x57e1, 0x57e1 }, +/* 0x57e2 */ { false, 0x57e2, 0x57e2 }, +/* 0x57e3 */ { false, 0x57e3, 0x57e3 }, +/* 0x57e4 */ { false, 0x57e4, 0x57e4 }, +/* 0x57e5 */ { false, 0x57e5, 0x57e5 }, +/* 0x57e6 */ { false, 0x57e6, 0x57e6 }, +/* 0x57e7 */ { false, 0x57e7, 0x57e7 }, +/* 0x57e8 */ { false, 0x57e8, 0x57e8 }, +/* 0x57e9 */ { false, 0x57e9, 0x57e9 }, +/* 0x57ea */ { false, 0x57ea, 0x57ea }, +/* 0x57eb */ { false, 0x57eb, 0x57eb }, +/* 0x57ec */ { false, 0x57ec, 0x57ec }, +/* 0x57ed */ { false, 0x57ed, 0x57ed }, +/* 0x57ee */ { false, 0x57ee, 0x57ee }, +/* 0x57ef */ { false, 0x57ef, 0x57ef }, +/* 0x57f0 */ { false, 0x57f0, 0x57f0 }, +/* 0x57f1 */ { false, 0x57f1, 0x57f1 }, +/* 0x57f2 */ { false, 0x57f2, 0x57f2 }, +/* 0x57f3 */ { false, 0x57f3, 0x57f3 }, +/* 0x57f4 */ { false, 0x57f4, 0x57f4 }, +/* 0x57f5 */ { false, 0x57f5, 0x57f5 }, +/* 0x57f6 */ { false, 0x57f6, 0x57f6 }, +/* 0x57f7 */ { false, 0x57f7, 0x57f7 }, +/* 0x57f8 */ { false, 0x57f8, 0x57f8 }, +/* 0x57f9 */ { false, 0x57f9, 0x57f9 }, +/* 0x57fa */ { false, 0x57fa, 0x57fa }, +/* 0x57fb */ { false, 0x57fb, 0x57fb }, +/* 0x57fc */ { false, 0x57fc, 0x57fc }, +/* 0x57fd */ { false, 0x57fd, 0x57fd }, +/* 0x57fe */ { false, 0x57fe, 0x57fe }, +/* 0x57ff */ { false, 0x57ff, 0x57ff }, +/* 0x5800 */ { false, 0x5800, 0x5800 }, +/* 0x5801 */ { false, 0x5801, 0x5801 }, +/* 0x5802 */ { false, 0x5802, 0x5802 }, +/* 0x5803 */ { false, 0x5803, 0x5803 }, +/* 0x5804 */ { false, 0x5804, 0x5804 }, +/* 0x5805 */ { false, 0x5805, 0x5805 }, +/* 0x5806 */ { false, 0x5806, 0x5806 }, +/* 0x5807 */ { false, 0x5807, 0x5807 }, +/* 0x5808 */ { false, 0x5808, 0x5808 }, +/* 0x5809 */ { false, 0x5809, 0x5809 }, +/* 0x580a */ { false, 0x580a, 0x580a }, +/* 0x580b */ { false, 0x580b, 0x580b }, +/* 0x580c */ { false, 0x580c, 0x580c }, +/* 0x580d */ { false, 0x580d, 0x580d }, +/* 0x580e */ { false, 0x580e, 0x580e }, +/* 0x580f */ { false, 0x580f, 0x580f }, +/* 0x5810 */ { false, 0x5810, 0x5810 }, +/* 0x5811 */ { false, 0x5811, 0x5811 }, +/* 0x5812 */ { false, 0x5812, 0x5812 }, +/* 0x5813 */ { false, 0x5813, 0x5813 }, +/* 0x5814 */ { false, 0x5814, 0x5814 }, +/* 0x5815 */ { false, 0x5815, 0x5815 }, +/* 0x5816 */ { false, 0x5816, 0x5816 }, +/* 0x5817 */ { false, 0x5817, 0x5817 }, +/* 0x5818 */ { false, 0x5818, 0x5818 }, +/* 0x5819 */ { false, 0x5819, 0x5819 }, +/* 0x581a */ { false, 0x581a, 0x581a }, +/* 0x581b */ { false, 0x581b, 0x581b }, +/* 0x581c */ { false, 0x581c, 0x581c }, +/* 0x581d */ { false, 0x581d, 0x581d }, +/* 0x581e */ { false, 0x581e, 0x581e }, +/* 0x581f */ { false, 0x581f, 0x581f }, +/* 0x5820 */ { false, 0x5820, 0x5820 }, +/* 0x5821 */ { false, 0x5821, 0x5821 }, +/* 0x5822 */ { false, 0x5822, 0x5822 }, +/* 0x5823 */ { false, 0x5823, 0x5823 }, +/* 0x5824 */ { false, 0x5824, 0x5824 }, +/* 0x5825 */ { false, 0x5825, 0x5825 }, +/* 0x5826 */ { false, 0x5826, 0x5826 }, +/* 0x5827 */ { false, 0x5827, 0x5827 }, +/* 0x5828 */ { false, 0x5828, 0x5828 }, +/* 0x5829 */ { false, 0x5829, 0x5829 }, +/* 0x582a */ { false, 0x582a, 0x582a }, +/* 0x582b */ { false, 0x582b, 0x582b }, +/* 0x582c */ { false, 0x582c, 0x582c }, +/* 0x582d */ { false, 0x582d, 0x582d }, +/* 0x582e */ { false, 0x582e, 0x582e }, +/* 0x582f */ { false, 0x582f, 0x582f }, +/* 0x5830 */ { false, 0x5830, 0x5830 }, +/* 0x5831 */ { false, 0x5831, 0x5831 }, +/* 0x5832 */ { false, 0x5832, 0x5832 }, +/* 0x5833 */ { false, 0x5833, 0x5833 }, +/* 0x5834 */ { false, 0x5834, 0x5834 }, +/* 0x5835 */ { false, 0x5835, 0x5835 }, +/* 0x5836 */ { false, 0x5836, 0x5836 }, +/* 0x5837 */ { false, 0x5837, 0x5837 }, +/* 0x5838 */ { false, 0x5838, 0x5838 }, +/* 0x5839 */ { false, 0x5839, 0x5839 }, +/* 0x583a */ { false, 0x583a, 0x583a }, +/* 0x583b */ { false, 0x583b, 0x583b }, +/* 0x583c */ { false, 0x583c, 0x583c }, +/* 0x583d */ { false, 0x583d, 0x583d }, +/* 0x583e */ { false, 0x583e, 0x583e }, +/* 0x583f */ { false, 0x583f, 0x583f }, +/* 0x5840 */ { false, 0x5840, 0x5840 }, +/* 0x5841 */ { false, 0x5841, 0x5841 }, +/* 0x5842 */ { false, 0x5842, 0x5842 }, +/* 0x5843 */ { false, 0x5843, 0x5843 }, +/* 0x5844 */ { false, 0x5844, 0x5844 }, +/* 0x5845 */ { false, 0x5845, 0x5845 }, +/* 0x5846 */ { false, 0x5846, 0x5846 }, +/* 0x5847 */ { false, 0x5847, 0x5847 }, +/* 0x5848 */ { false, 0x5848, 0x5848 }, +/* 0x5849 */ { false, 0x5849, 0x5849 }, +/* 0x584a */ { false, 0x584a, 0x584a }, +/* 0x584b */ { false, 0x584b, 0x584b }, +/* 0x584c */ { false, 0x584c, 0x584c }, +/* 0x584d */ { false, 0x584d, 0x584d }, +/* 0x584e */ { false, 0x584e, 0x584e }, +/* 0x584f */ { false, 0x584f, 0x584f }, +/* 0x5850 */ { false, 0x5850, 0x5850 }, +/* 0x5851 */ { false, 0x5851, 0x5851 }, +/* 0x5852 */ { false, 0x5852, 0x5852 }, +/* 0x5853 */ { false, 0x5853, 0x5853 }, +/* 0x5854 */ { false, 0x5854, 0x5854 }, +/* 0x5855 */ { false, 0x5855, 0x5855 }, +/* 0x5856 */ { false, 0x5856, 0x5856 }, +/* 0x5857 */ { false, 0x5857, 0x5857 }, +/* 0x5858 */ { false, 0x5858, 0x5858 }, +/* 0x5859 */ { false, 0x5859, 0x5859 }, +/* 0x585a */ { false, 0x585a, 0x585a }, +/* 0x585b */ { false, 0x585b, 0x585b }, +/* 0x585c */ { false, 0x585c, 0x585c }, +/* 0x585d */ { false, 0x585d, 0x585d }, +/* 0x585e */ { false, 0x585e, 0x585e }, +/* 0x585f */ { false, 0x585f, 0x585f }, +/* 0x5860 */ { false, 0x5860, 0x5860 }, +/* 0x5861 */ { false, 0x5861, 0x5861 }, +/* 0x5862 */ { false, 0x5862, 0x5862 }, +/* 0x5863 */ { false, 0x5863, 0x5863 }, +/* 0x5864 */ { false, 0x5864, 0x5864 }, +/* 0x5865 */ { false, 0x5865, 0x5865 }, +/* 0x5866 */ { false, 0x5866, 0x5866 }, +/* 0x5867 */ { false, 0x5867, 0x5867 }, +/* 0x5868 */ { false, 0x5868, 0x5868 }, +/* 0x5869 */ { false, 0x5869, 0x5869 }, +/* 0x586a */ { false, 0x586a, 0x586a }, +/* 0x586b */ { false, 0x586b, 0x586b }, +/* 0x586c */ { false, 0x586c, 0x586c }, +/* 0x586d */ { false, 0x586d, 0x586d }, +/* 0x586e */ { false, 0x586e, 0x586e }, +/* 0x586f */ { false, 0x586f, 0x586f }, +/* 0x5870 */ { false, 0x5870, 0x5870 }, +/* 0x5871 */ { false, 0x5871, 0x5871 }, +/* 0x5872 */ { false, 0x5872, 0x5872 }, +/* 0x5873 */ { false, 0x5873, 0x5873 }, +/* 0x5874 */ { false, 0x5874, 0x5874 }, +/* 0x5875 */ { false, 0x5875, 0x5875 }, +/* 0x5876 */ { false, 0x5876, 0x5876 }, +/* 0x5877 */ { false, 0x5877, 0x5877 }, +/* 0x5878 */ { false, 0x5878, 0x5878 }, +/* 0x5879 */ { false, 0x5879, 0x5879 }, +/* 0x587a */ { false, 0x587a, 0x587a }, +/* 0x587b */ { false, 0x587b, 0x587b }, +/* 0x587c */ { false, 0x587c, 0x587c }, +/* 0x587d */ { false, 0x587d, 0x587d }, +/* 0x587e */ { false, 0x587e, 0x587e }, +/* 0x587f */ { false, 0x587f, 0x587f }, +/* 0x5880 */ { false, 0x5880, 0x5880 }, +/* 0x5881 */ { false, 0x5881, 0x5881 }, +/* 0x5882 */ { false, 0x5882, 0x5882 }, +/* 0x5883 */ { false, 0x5883, 0x5883 }, +/* 0x5884 */ { false, 0x5884, 0x5884 }, +/* 0x5885 */ { false, 0x5885, 0x5885 }, +/* 0x5886 */ { false, 0x5886, 0x5886 }, +/* 0x5887 */ { false, 0x5887, 0x5887 }, +/* 0x5888 */ { false, 0x5888, 0x5888 }, +/* 0x5889 */ { false, 0x5889, 0x5889 }, +/* 0x588a */ { false, 0x588a, 0x588a }, +/* 0x588b */ { false, 0x588b, 0x588b }, +/* 0x588c */ { false, 0x588c, 0x588c }, +/* 0x588d */ { false, 0x588d, 0x588d }, +/* 0x588e */ { false, 0x588e, 0x588e }, +/* 0x588f */ { false, 0x588f, 0x588f }, +/* 0x5890 */ { false, 0x5890, 0x5890 }, +/* 0x5891 */ { false, 0x5891, 0x5891 }, +/* 0x5892 */ { false, 0x5892, 0x5892 }, +/* 0x5893 */ { false, 0x5893, 0x5893 }, +/* 0x5894 */ { false, 0x5894, 0x5894 }, +/* 0x5895 */ { false, 0x5895, 0x5895 }, +/* 0x5896 */ { false, 0x5896, 0x5896 }, +/* 0x5897 */ { false, 0x5897, 0x5897 }, +/* 0x5898 */ { false, 0x5898, 0x5898 }, +/* 0x5899 */ { false, 0x5899, 0x5899 }, +/* 0x589a */ { false, 0x589a, 0x589a }, +/* 0x589b */ { false, 0x589b, 0x589b }, +/* 0x589c */ { false, 0x589c, 0x589c }, +/* 0x589d */ { false, 0x589d, 0x589d }, +/* 0x589e */ { false, 0x589e, 0x589e }, +/* 0x589f */ { false, 0x589f, 0x589f }, +/* 0x58a0 */ { false, 0x58a0, 0x58a0 }, +/* 0x58a1 */ { false, 0x58a1, 0x58a1 }, +/* 0x58a2 */ { false, 0x58a2, 0x58a2 }, +/* 0x58a3 */ { false, 0x58a3, 0x58a3 }, +/* 0x58a4 */ { false, 0x58a4, 0x58a4 }, +/* 0x58a5 */ { false, 0x58a5, 0x58a5 }, +/* 0x58a6 */ { false, 0x58a6, 0x58a6 }, +/* 0x58a7 */ { false, 0x58a7, 0x58a7 }, +/* 0x58a8 */ { false, 0x58a8, 0x58a8 }, +/* 0x58a9 */ { false, 0x58a9, 0x58a9 }, +/* 0x58aa */ { false, 0x58aa, 0x58aa }, +/* 0x58ab */ { false, 0x58ab, 0x58ab }, +/* 0x58ac */ { false, 0x58ac, 0x58ac }, +/* 0x58ad */ { false, 0x58ad, 0x58ad }, +/* 0x58ae */ { false, 0x58ae, 0x58ae }, +/* 0x58af */ { false, 0x58af, 0x58af }, +/* 0x58b0 */ { false, 0x58b0, 0x58b0 }, +/* 0x58b1 */ { false, 0x58b1, 0x58b1 }, +/* 0x58b2 */ { false, 0x58b2, 0x58b2 }, +/* 0x58b3 */ { false, 0x58b3, 0x58b3 }, +/* 0x58b4 */ { false, 0x58b4, 0x58b4 }, +/* 0x58b5 */ { false, 0x58b5, 0x58b5 }, +/* 0x58b6 */ { false, 0x58b6, 0x58b6 }, +/* 0x58b7 */ { false, 0x58b7, 0x58b7 }, +/* 0x58b8 */ { false, 0x58b8, 0x58b8 }, +/* 0x58b9 */ { false, 0x58b9, 0x58b9 }, +/* 0x58ba */ { false, 0x58ba, 0x58ba }, +/* 0x58bb */ { false, 0x58bb, 0x58bb }, +/* 0x58bc */ { false, 0x58bc, 0x58bc }, +/* 0x58bd */ { false, 0x58bd, 0x58bd }, +/* 0x58be */ { false, 0x58be, 0x58be }, +/* 0x58bf */ { false, 0x58bf, 0x58bf }, +/* 0x58c0 */ { false, 0x58c0, 0x58c0 }, +/* 0x58c1 */ { false, 0x58c1, 0x58c1 }, +/* 0x58c2 */ { false, 0x58c2, 0x58c2 }, +/* 0x58c3 */ { false, 0x58c3, 0x58c3 }, +/* 0x58c4 */ { false, 0x58c4, 0x58c4 }, +/* 0x58c5 */ { false, 0x58c5, 0x58c5 }, +/* 0x58c6 */ { false, 0x58c6, 0x58c6 }, +/* 0x58c7 */ { false, 0x58c7, 0x58c7 }, +/* 0x58c8 */ { false, 0x58c8, 0x58c8 }, +/* 0x58c9 */ { false, 0x58c9, 0x58c9 }, +/* 0x58ca */ { false, 0x58ca, 0x58ca }, +/* 0x58cb */ { false, 0x58cb, 0x58cb }, +/* 0x58cc */ { false, 0x58cc, 0x58cc }, +/* 0x58cd */ { false, 0x58cd, 0x58cd }, +/* 0x58ce */ { false, 0x58ce, 0x58ce }, +/* 0x58cf */ { false, 0x58cf, 0x58cf }, +/* 0x58d0 */ { false, 0x58d0, 0x58d0 }, +/* 0x58d1 */ { false, 0x58d1, 0x58d1 }, +/* 0x58d2 */ { false, 0x58d2, 0x58d2 }, +/* 0x58d3 */ { false, 0x58d3, 0x58d3 }, +/* 0x58d4 */ { false, 0x58d4, 0x58d4 }, +/* 0x58d5 */ { false, 0x58d5, 0x58d5 }, +/* 0x58d6 */ { false, 0x58d6, 0x58d6 }, +/* 0x58d7 */ { false, 0x58d7, 0x58d7 }, +/* 0x58d8 */ { false, 0x58d8, 0x58d8 }, +/* 0x58d9 */ { false, 0x58d9, 0x58d9 }, +/* 0x58da */ { false, 0x58da, 0x58da }, +/* 0x58db */ { false, 0x58db, 0x58db }, +/* 0x58dc */ { false, 0x58dc, 0x58dc }, +/* 0x58dd */ { false, 0x58dd, 0x58dd }, +/* 0x58de */ { false, 0x58de, 0x58de }, +/* 0x58df */ { false, 0x58df, 0x58df }, +/* 0x58e0 */ { false, 0x58e0, 0x58e0 }, +/* 0x58e1 */ { false, 0x58e1, 0x58e1 }, +/* 0x58e2 */ { false, 0x58e2, 0x58e2 }, +/* 0x58e3 */ { false, 0x58e3, 0x58e3 }, +/* 0x58e4 */ { false, 0x58e4, 0x58e4 }, +/* 0x58e5 */ { false, 0x58e5, 0x58e5 }, +/* 0x58e6 */ { false, 0x58e6, 0x58e6 }, +/* 0x58e7 */ { false, 0x58e7, 0x58e7 }, +/* 0x58e8 */ { false, 0x58e8, 0x58e8 }, +/* 0x58e9 */ { false, 0x58e9, 0x58e9 }, +/* 0x58ea */ { false, 0x58ea, 0x58ea }, +/* 0x58eb */ { false, 0x58eb, 0x58eb }, +/* 0x58ec */ { false, 0x58ec, 0x58ec }, +/* 0x58ed */ { false, 0x58ed, 0x58ed }, +/* 0x58ee */ { false, 0x58ee, 0x58ee }, +/* 0x58ef */ { false, 0x58ef, 0x58ef }, +/* 0x58f0 */ { false, 0x58f0, 0x58f0 }, +/* 0x58f1 */ { false, 0x58f1, 0x58f1 }, +/* 0x58f2 */ { false, 0x58f2, 0x58f2 }, +/* 0x58f3 */ { false, 0x58f3, 0x58f3 }, +/* 0x58f4 */ { false, 0x58f4, 0x58f4 }, +/* 0x58f5 */ { false, 0x58f5, 0x58f5 }, +/* 0x58f6 */ { false, 0x58f6, 0x58f6 }, +/* 0x58f7 */ { false, 0x58f7, 0x58f7 }, +/* 0x58f8 */ { false, 0x58f8, 0x58f8 }, +/* 0x58f9 */ { false, 0x58f9, 0x58f9 }, +/* 0x58fa */ { false, 0x58fa, 0x58fa }, +/* 0x58fb */ { false, 0x58fb, 0x58fb }, +/* 0x58fc */ { false, 0x58fc, 0x58fc }, +/* 0x58fd */ { false, 0x58fd, 0x58fd }, +/* 0x58fe */ { false, 0x58fe, 0x58fe }, +/* 0x58ff */ { false, 0x58ff, 0x58ff }, +/* 0x5900 */ { false, 0x5900, 0x5900 }, +/* 0x5901 */ { false, 0x5901, 0x5901 }, +/* 0x5902 */ { false, 0x5902, 0x5902 }, +/* 0x5903 */ { false, 0x5903, 0x5903 }, +/* 0x5904 */ { false, 0x5904, 0x5904 }, +/* 0x5905 */ { false, 0x5905, 0x5905 }, +/* 0x5906 */ { false, 0x5906, 0x5906 }, +/* 0x5907 */ { false, 0x5907, 0x5907 }, +/* 0x5908 */ { false, 0x5908, 0x5908 }, +/* 0x5909 */ { false, 0x5909, 0x5909 }, +/* 0x590a */ { false, 0x590a, 0x590a }, +/* 0x590b */ { false, 0x590b, 0x590b }, +/* 0x590c */ { false, 0x590c, 0x590c }, +/* 0x590d */ { false, 0x590d, 0x590d }, +/* 0x590e */ { false, 0x590e, 0x590e }, +/* 0x590f */ { false, 0x590f, 0x590f }, +/* 0x5910 */ { false, 0x5910, 0x5910 }, +/* 0x5911 */ { false, 0x5911, 0x5911 }, +/* 0x5912 */ { false, 0x5912, 0x5912 }, +/* 0x5913 */ { false, 0x5913, 0x5913 }, +/* 0x5914 */ { false, 0x5914, 0x5914 }, +/* 0x5915 */ { false, 0x5915, 0x5915 }, +/* 0x5916 */ { false, 0x5916, 0x5916 }, +/* 0x5917 */ { false, 0x5917, 0x5917 }, +/* 0x5918 */ { false, 0x5918, 0x5918 }, +/* 0x5919 */ { false, 0x5919, 0x5919 }, +/* 0x591a */ { false, 0x591a, 0x591a }, +/* 0x591b */ { false, 0x591b, 0x591b }, +/* 0x591c */ { false, 0x591c, 0x591c }, +/* 0x591d */ { false, 0x591d, 0x591d }, +/* 0x591e */ { false, 0x591e, 0x591e }, +/* 0x591f */ { false, 0x591f, 0x591f }, +/* 0x5920 */ { false, 0x5920, 0x5920 }, +/* 0x5921 */ { false, 0x5921, 0x5921 }, +/* 0x5922 */ { false, 0x5922, 0x5922 }, +/* 0x5923 */ { false, 0x5923, 0x5923 }, +/* 0x5924 */ { false, 0x5924, 0x5924 }, +/* 0x5925 */ { false, 0x5925, 0x5925 }, +/* 0x5926 */ { false, 0x5926, 0x5926 }, +/* 0x5927 */ { false, 0x5927, 0x5927 }, +/* 0x5928 */ { false, 0x5928, 0x5928 }, +/* 0x5929 */ { false, 0x5929, 0x5929 }, +/* 0x592a */ { false, 0x592a, 0x592a }, +/* 0x592b */ { false, 0x592b, 0x592b }, +/* 0x592c */ { false, 0x592c, 0x592c }, +/* 0x592d */ { false, 0x592d, 0x592d }, +/* 0x592e */ { false, 0x592e, 0x592e }, +/* 0x592f */ { false, 0x592f, 0x592f }, +/* 0x5930 */ { false, 0x5930, 0x5930 }, +/* 0x5931 */ { false, 0x5931, 0x5931 }, +/* 0x5932 */ { false, 0x5932, 0x5932 }, +/* 0x5933 */ { false, 0x5933, 0x5933 }, +/* 0x5934 */ { false, 0x5934, 0x5934 }, +/* 0x5935 */ { false, 0x5935, 0x5935 }, +/* 0x5936 */ { false, 0x5936, 0x5936 }, +/* 0x5937 */ { false, 0x5937, 0x5937 }, +/* 0x5938 */ { false, 0x5938, 0x5938 }, +/* 0x5939 */ { false, 0x5939, 0x5939 }, +/* 0x593a */ { false, 0x593a, 0x593a }, +/* 0x593b */ { false, 0x593b, 0x593b }, +/* 0x593c */ { false, 0x593c, 0x593c }, +/* 0x593d */ { false, 0x593d, 0x593d }, +/* 0x593e */ { false, 0x593e, 0x593e }, +/* 0x593f */ { false, 0x593f, 0x593f }, +/* 0x5940 */ { false, 0x5940, 0x5940 }, +/* 0x5941 */ { false, 0x5941, 0x5941 }, +/* 0x5942 */ { false, 0x5942, 0x5942 }, +/* 0x5943 */ { false, 0x5943, 0x5943 }, +/* 0x5944 */ { false, 0x5944, 0x5944 }, +/* 0x5945 */ { false, 0x5945, 0x5945 }, +/* 0x5946 */ { false, 0x5946, 0x5946 }, +/* 0x5947 */ { false, 0x5947, 0x5947 }, +/* 0x5948 */ { false, 0x5948, 0x5948 }, +/* 0x5949 */ { false, 0x5949, 0x5949 }, +/* 0x594a */ { false, 0x594a, 0x594a }, +/* 0x594b */ { false, 0x594b, 0x594b }, +/* 0x594c */ { false, 0x594c, 0x594c }, +/* 0x594d */ { false, 0x594d, 0x594d }, +/* 0x594e */ { false, 0x594e, 0x594e }, +/* 0x594f */ { false, 0x594f, 0x594f }, +/* 0x5950 */ { false, 0x5950, 0x5950 }, +/* 0x5951 */ { false, 0x5951, 0x5951 }, +/* 0x5952 */ { false, 0x5952, 0x5952 }, +/* 0x5953 */ { false, 0x5953, 0x5953 }, +/* 0x5954 */ { false, 0x5954, 0x5954 }, +/* 0x5955 */ { false, 0x5955, 0x5955 }, +/* 0x5956 */ { false, 0x5956, 0x5956 }, +/* 0x5957 */ { false, 0x5957, 0x5957 }, +/* 0x5958 */ { false, 0x5958, 0x5958 }, +/* 0x5959 */ { false, 0x5959, 0x5959 }, +/* 0x595a */ { false, 0x595a, 0x595a }, +/* 0x595b */ { false, 0x595b, 0x595b }, +/* 0x595c */ { false, 0x595c, 0x595c }, +/* 0x595d */ { false, 0x595d, 0x595d }, +/* 0x595e */ { false, 0x595e, 0x595e }, +/* 0x595f */ { false, 0x595f, 0x595f }, +/* 0x5960 */ { false, 0x5960, 0x5960 }, +/* 0x5961 */ { false, 0x5961, 0x5961 }, +/* 0x5962 */ { false, 0x5962, 0x5962 }, +/* 0x5963 */ { false, 0x5963, 0x5963 }, +/* 0x5964 */ { false, 0x5964, 0x5964 }, +/* 0x5965 */ { false, 0x5965, 0x5965 }, +/* 0x5966 */ { false, 0x5966, 0x5966 }, +/* 0x5967 */ { false, 0x5967, 0x5967 }, +/* 0x5968 */ { false, 0x5968, 0x5968 }, +/* 0x5969 */ { false, 0x5969, 0x5969 }, +/* 0x596a */ { false, 0x596a, 0x596a }, +/* 0x596b */ { false, 0x596b, 0x596b }, +/* 0x596c */ { false, 0x596c, 0x596c }, +/* 0x596d */ { false, 0x596d, 0x596d }, +/* 0x596e */ { false, 0x596e, 0x596e }, +/* 0x596f */ { false, 0x596f, 0x596f }, +/* 0x5970 */ { false, 0x5970, 0x5970 }, +/* 0x5971 */ { false, 0x5971, 0x5971 }, +/* 0x5972 */ { false, 0x5972, 0x5972 }, +/* 0x5973 */ { false, 0x5973, 0x5973 }, +/* 0x5974 */ { false, 0x5974, 0x5974 }, +/* 0x5975 */ { false, 0x5975, 0x5975 }, +/* 0x5976 */ { false, 0x5976, 0x5976 }, +/* 0x5977 */ { false, 0x5977, 0x5977 }, +/* 0x5978 */ { false, 0x5978, 0x5978 }, +/* 0x5979 */ { false, 0x5979, 0x5979 }, +/* 0x597a */ { false, 0x597a, 0x597a }, +/* 0x597b */ { false, 0x597b, 0x597b }, +/* 0x597c */ { false, 0x597c, 0x597c }, +/* 0x597d */ { false, 0x597d, 0x597d }, +/* 0x597e */ { false, 0x597e, 0x597e }, +/* 0x597f */ { false, 0x597f, 0x597f }, +/* 0x5980 */ { false, 0x5980, 0x5980 }, +/* 0x5981 */ { false, 0x5981, 0x5981 }, +/* 0x5982 */ { false, 0x5982, 0x5982 }, +/* 0x5983 */ { false, 0x5983, 0x5983 }, +/* 0x5984 */ { false, 0x5984, 0x5984 }, +/* 0x5985 */ { false, 0x5985, 0x5985 }, +/* 0x5986 */ { false, 0x5986, 0x5986 }, +/* 0x5987 */ { false, 0x5987, 0x5987 }, +/* 0x5988 */ { false, 0x5988, 0x5988 }, +/* 0x5989 */ { false, 0x5989, 0x5989 }, +/* 0x598a */ { false, 0x598a, 0x598a }, +/* 0x598b */ { false, 0x598b, 0x598b }, +/* 0x598c */ { false, 0x598c, 0x598c }, +/* 0x598d */ { false, 0x598d, 0x598d }, +/* 0x598e */ { false, 0x598e, 0x598e }, +/* 0x598f */ { false, 0x598f, 0x598f }, +/* 0x5990 */ { false, 0x5990, 0x5990 }, +/* 0x5991 */ { false, 0x5991, 0x5991 }, +/* 0x5992 */ { false, 0x5992, 0x5992 }, +/* 0x5993 */ { false, 0x5993, 0x5993 }, +/* 0x5994 */ { false, 0x5994, 0x5994 }, +/* 0x5995 */ { false, 0x5995, 0x5995 }, +/* 0x5996 */ { false, 0x5996, 0x5996 }, +/* 0x5997 */ { false, 0x5997, 0x5997 }, +/* 0x5998 */ { false, 0x5998, 0x5998 }, +/* 0x5999 */ { false, 0x5999, 0x5999 }, +/* 0x599a */ { false, 0x599a, 0x599a }, +/* 0x599b */ { false, 0x599b, 0x599b }, +/* 0x599c */ { false, 0x599c, 0x599c }, +/* 0x599d */ { false, 0x599d, 0x599d }, +/* 0x599e */ { false, 0x599e, 0x599e }, +/* 0x599f */ { false, 0x599f, 0x599f }, +/* 0x59a0 */ { false, 0x59a0, 0x59a0 }, +/* 0x59a1 */ { false, 0x59a1, 0x59a1 }, +/* 0x59a2 */ { false, 0x59a2, 0x59a2 }, +/* 0x59a3 */ { false, 0x59a3, 0x59a3 }, +/* 0x59a4 */ { false, 0x59a4, 0x59a4 }, +/* 0x59a5 */ { false, 0x59a5, 0x59a5 }, +/* 0x59a6 */ { false, 0x59a6, 0x59a6 }, +/* 0x59a7 */ { false, 0x59a7, 0x59a7 }, +/* 0x59a8 */ { false, 0x59a8, 0x59a8 }, +/* 0x59a9 */ { false, 0x59a9, 0x59a9 }, +/* 0x59aa */ { false, 0x59aa, 0x59aa }, +/* 0x59ab */ { false, 0x59ab, 0x59ab }, +/* 0x59ac */ { false, 0x59ac, 0x59ac }, +/* 0x59ad */ { false, 0x59ad, 0x59ad }, +/* 0x59ae */ { false, 0x59ae, 0x59ae }, +/* 0x59af */ { false, 0x59af, 0x59af }, +/* 0x59b0 */ { false, 0x59b0, 0x59b0 }, +/* 0x59b1 */ { false, 0x59b1, 0x59b1 }, +/* 0x59b2 */ { false, 0x59b2, 0x59b2 }, +/* 0x59b3 */ { false, 0x59b3, 0x59b3 }, +/* 0x59b4 */ { false, 0x59b4, 0x59b4 }, +/* 0x59b5 */ { false, 0x59b5, 0x59b5 }, +/* 0x59b6 */ { false, 0x59b6, 0x59b6 }, +/* 0x59b7 */ { false, 0x59b7, 0x59b7 }, +/* 0x59b8 */ { false, 0x59b8, 0x59b8 }, +/* 0x59b9 */ { false, 0x59b9, 0x59b9 }, +/* 0x59ba */ { false, 0x59ba, 0x59ba }, +/* 0x59bb */ { false, 0x59bb, 0x59bb }, +/* 0x59bc */ { false, 0x59bc, 0x59bc }, +/* 0x59bd */ { false, 0x59bd, 0x59bd }, +/* 0x59be */ { false, 0x59be, 0x59be }, +/* 0x59bf */ { false, 0x59bf, 0x59bf }, +/* 0x59c0 */ { false, 0x59c0, 0x59c0 }, +/* 0x59c1 */ { false, 0x59c1, 0x59c1 }, +/* 0x59c2 */ { false, 0x59c2, 0x59c2 }, +/* 0x59c3 */ { false, 0x59c3, 0x59c3 }, +/* 0x59c4 */ { false, 0x59c4, 0x59c4 }, +/* 0x59c5 */ { false, 0x59c5, 0x59c5 }, +/* 0x59c6 */ { false, 0x59c6, 0x59c6 }, +/* 0x59c7 */ { false, 0x59c7, 0x59c7 }, +/* 0x59c8 */ { false, 0x59c8, 0x59c8 }, +/* 0x59c9 */ { false, 0x59c9, 0x59c9 }, +/* 0x59ca */ { false, 0x59ca, 0x59ca }, +/* 0x59cb */ { false, 0x59cb, 0x59cb }, +/* 0x59cc */ { false, 0x59cc, 0x59cc }, +/* 0x59cd */ { false, 0x59cd, 0x59cd }, +/* 0x59ce */ { false, 0x59ce, 0x59ce }, +/* 0x59cf */ { false, 0x59cf, 0x59cf }, +/* 0x59d0 */ { false, 0x59d0, 0x59d0 }, +/* 0x59d1 */ { false, 0x59d1, 0x59d1 }, +/* 0x59d2 */ { false, 0x59d2, 0x59d2 }, +/* 0x59d3 */ { false, 0x59d3, 0x59d3 }, +/* 0x59d4 */ { false, 0x59d4, 0x59d4 }, +/* 0x59d5 */ { false, 0x59d5, 0x59d5 }, +/* 0x59d6 */ { false, 0x59d6, 0x59d6 }, +/* 0x59d7 */ { false, 0x59d7, 0x59d7 }, +/* 0x59d8 */ { false, 0x59d8, 0x59d8 }, +/* 0x59d9 */ { false, 0x59d9, 0x59d9 }, +/* 0x59da */ { false, 0x59da, 0x59da }, +/* 0x59db */ { false, 0x59db, 0x59db }, +/* 0x59dc */ { false, 0x59dc, 0x59dc }, +/* 0x59dd */ { false, 0x59dd, 0x59dd }, +/* 0x59de */ { false, 0x59de, 0x59de }, +/* 0x59df */ { false, 0x59df, 0x59df }, +/* 0x59e0 */ { false, 0x59e0, 0x59e0 }, +/* 0x59e1 */ { false, 0x59e1, 0x59e1 }, +/* 0x59e2 */ { false, 0x59e2, 0x59e2 }, +/* 0x59e3 */ { false, 0x59e3, 0x59e3 }, +/* 0x59e4 */ { false, 0x59e4, 0x59e4 }, +/* 0x59e5 */ { false, 0x59e5, 0x59e5 }, +/* 0x59e6 */ { false, 0x59e6, 0x59e6 }, +/* 0x59e7 */ { false, 0x59e7, 0x59e7 }, +/* 0x59e8 */ { false, 0x59e8, 0x59e8 }, +/* 0x59e9 */ { false, 0x59e9, 0x59e9 }, +/* 0x59ea */ { false, 0x59ea, 0x59ea }, +/* 0x59eb */ { false, 0x59eb, 0x59eb }, +/* 0x59ec */ { false, 0x59ec, 0x59ec }, +/* 0x59ed */ { false, 0x59ed, 0x59ed }, +/* 0x59ee */ { false, 0x59ee, 0x59ee }, +/* 0x59ef */ { false, 0x59ef, 0x59ef }, +/* 0x59f0 */ { false, 0x59f0, 0x59f0 }, +/* 0x59f1 */ { false, 0x59f1, 0x59f1 }, +/* 0x59f2 */ { false, 0x59f2, 0x59f2 }, +/* 0x59f3 */ { false, 0x59f3, 0x59f3 }, +/* 0x59f4 */ { false, 0x59f4, 0x59f4 }, +/* 0x59f5 */ { false, 0x59f5, 0x59f5 }, +/* 0x59f6 */ { false, 0x59f6, 0x59f6 }, +/* 0x59f7 */ { false, 0x59f7, 0x59f7 }, +/* 0x59f8 */ { false, 0x59f8, 0x59f8 }, +/* 0x59f9 */ { false, 0x59f9, 0x59f9 }, +/* 0x59fa */ { false, 0x59fa, 0x59fa }, +/* 0x59fb */ { false, 0x59fb, 0x59fb }, +/* 0x59fc */ { false, 0x59fc, 0x59fc }, +/* 0x59fd */ { false, 0x59fd, 0x59fd }, +/* 0x59fe */ { false, 0x59fe, 0x59fe }, +/* 0x59ff */ { false, 0x59ff, 0x59ff }, +/* 0x5a00 */ { false, 0x5a00, 0x5a00 }, +/* 0x5a01 */ { false, 0x5a01, 0x5a01 }, +/* 0x5a02 */ { false, 0x5a02, 0x5a02 }, +/* 0x5a03 */ { false, 0x5a03, 0x5a03 }, +/* 0x5a04 */ { false, 0x5a04, 0x5a04 }, +/* 0x5a05 */ { false, 0x5a05, 0x5a05 }, +/* 0x5a06 */ { false, 0x5a06, 0x5a06 }, +/* 0x5a07 */ { false, 0x5a07, 0x5a07 }, +/* 0x5a08 */ { false, 0x5a08, 0x5a08 }, +/* 0x5a09 */ { false, 0x5a09, 0x5a09 }, +/* 0x5a0a */ { false, 0x5a0a, 0x5a0a }, +/* 0x5a0b */ { false, 0x5a0b, 0x5a0b }, +/* 0x5a0c */ { false, 0x5a0c, 0x5a0c }, +/* 0x5a0d */ { false, 0x5a0d, 0x5a0d }, +/* 0x5a0e */ { false, 0x5a0e, 0x5a0e }, +/* 0x5a0f */ { false, 0x5a0f, 0x5a0f }, +/* 0x5a10 */ { false, 0x5a10, 0x5a10 }, +/* 0x5a11 */ { false, 0x5a11, 0x5a11 }, +/* 0x5a12 */ { false, 0x5a12, 0x5a12 }, +/* 0x5a13 */ { false, 0x5a13, 0x5a13 }, +/* 0x5a14 */ { false, 0x5a14, 0x5a14 }, +/* 0x5a15 */ { false, 0x5a15, 0x5a15 }, +/* 0x5a16 */ { false, 0x5a16, 0x5a16 }, +/* 0x5a17 */ { false, 0x5a17, 0x5a17 }, +/* 0x5a18 */ { false, 0x5a18, 0x5a18 }, +/* 0x5a19 */ { false, 0x5a19, 0x5a19 }, +/* 0x5a1a */ { false, 0x5a1a, 0x5a1a }, +/* 0x5a1b */ { false, 0x5a1b, 0x5a1b }, +/* 0x5a1c */ { false, 0x5a1c, 0x5a1c }, +/* 0x5a1d */ { false, 0x5a1d, 0x5a1d }, +/* 0x5a1e */ { false, 0x5a1e, 0x5a1e }, +/* 0x5a1f */ { false, 0x5a1f, 0x5a1f }, +/* 0x5a20 */ { false, 0x5a20, 0x5a20 }, +/* 0x5a21 */ { false, 0x5a21, 0x5a21 }, +/* 0x5a22 */ { false, 0x5a22, 0x5a22 }, +/* 0x5a23 */ { false, 0x5a23, 0x5a23 }, +/* 0x5a24 */ { false, 0x5a24, 0x5a24 }, +/* 0x5a25 */ { false, 0x5a25, 0x5a25 }, +/* 0x5a26 */ { false, 0x5a26, 0x5a26 }, +/* 0x5a27 */ { false, 0x5a27, 0x5a27 }, +/* 0x5a28 */ { false, 0x5a28, 0x5a28 }, +/* 0x5a29 */ { false, 0x5a29, 0x5a29 }, +/* 0x5a2a */ { false, 0x5a2a, 0x5a2a }, +/* 0x5a2b */ { false, 0x5a2b, 0x5a2b }, +/* 0x5a2c */ { false, 0x5a2c, 0x5a2c }, +/* 0x5a2d */ { false, 0x5a2d, 0x5a2d }, +/* 0x5a2e */ { false, 0x5a2e, 0x5a2e }, +/* 0x5a2f */ { false, 0x5a2f, 0x5a2f }, +/* 0x5a30 */ { false, 0x5a30, 0x5a30 }, +/* 0x5a31 */ { false, 0x5a31, 0x5a31 }, +/* 0x5a32 */ { false, 0x5a32, 0x5a32 }, +/* 0x5a33 */ { false, 0x5a33, 0x5a33 }, +/* 0x5a34 */ { false, 0x5a34, 0x5a34 }, +/* 0x5a35 */ { false, 0x5a35, 0x5a35 }, +/* 0x5a36 */ { false, 0x5a36, 0x5a36 }, +/* 0x5a37 */ { false, 0x5a37, 0x5a37 }, +/* 0x5a38 */ { false, 0x5a38, 0x5a38 }, +/* 0x5a39 */ { false, 0x5a39, 0x5a39 }, +/* 0x5a3a */ { false, 0x5a3a, 0x5a3a }, +/* 0x5a3b */ { false, 0x5a3b, 0x5a3b }, +/* 0x5a3c */ { false, 0x5a3c, 0x5a3c }, +/* 0x5a3d */ { false, 0x5a3d, 0x5a3d }, +/* 0x5a3e */ { false, 0x5a3e, 0x5a3e }, +/* 0x5a3f */ { false, 0x5a3f, 0x5a3f }, +/* 0x5a40 */ { false, 0x5a40, 0x5a40 }, +/* 0x5a41 */ { false, 0x5a41, 0x5a41 }, +/* 0x5a42 */ { false, 0x5a42, 0x5a42 }, +/* 0x5a43 */ { false, 0x5a43, 0x5a43 }, +/* 0x5a44 */ { false, 0x5a44, 0x5a44 }, +/* 0x5a45 */ { false, 0x5a45, 0x5a45 }, +/* 0x5a46 */ { false, 0x5a46, 0x5a46 }, +/* 0x5a47 */ { false, 0x5a47, 0x5a47 }, +/* 0x5a48 */ { false, 0x5a48, 0x5a48 }, +/* 0x5a49 */ { false, 0x5a49, 0x5a49 }, +/* 0x5a4a */ { false, 0x5a4a, 0x5a4a }, +/* 0x5a4b */ { false, 0x5a4b, 0x5a4b }, +/* 0x5a4c */ { false, 0x5a4c, 0x5a4c }, +/* 0x5a4d */ { false, 0x5a4d, 0x5a4d }, +/* 0x5a4e */ { false, 0x5a4e, 0x5a4e }, +/* 0x5a4f */ { false, 0x5a4f, 0x5a4f }, +/* 0x5a50 */ { false, 0x5a50, 0x5a50 }, +/* 0x5a51 */ { false, 0x5a51, 0x5a51 }, +/* 0x5a52 */ { false, 0x5a52, 0x5a52 }, +/* 0x5a53 */ { false, 0x5a53, 0x5a53 }, +/* 0x5a54 */ { false, 0x5a54, 0x5a54 }, +/* 0x5a55 */ { false, 0x5a55, 0x5a55 }, +/* 0x5a56 */ { false, 0x5a56, 0x5a56 }, +/* 0x5a57 */ { false, 0x5a57, 0x5a57 }, +/* 0x5a58 */ { false, 0x5a58, 0x5a58 }, +/* 0x5a59 */ { false, 0x5a59, 0x5a59 }, +/* 0x5a5a */ { false, 0x5a5a, 0x5a5a }, +/* 0x5a5b */ { false, 0x5a5b, 0x5a5b }, +/* 0x5a5c */ { false, 0x5a5c, 0x5a5c }, +/* 0x5a5d */ { false, 0x5a5d, 0x5a5d }, +/* 0x5a5e */ { false, 0x5a5e, 0x5a5e }, +/* 0x5a5f */ { false, 0x5a5f, 0x5a5f }, +/* 0x5a60 */ { false, 0x5a60, 0x5a60 }, +/* 0x5a61 */ { false, 0x5a61, 0x5a61 }, +/* 0x5a62 */ { false, 0x5a62, 0x5a62 }, +/* 0x5a63 */ { false, 0x5a63, 0x5a63 }, +/* 0x5a64 */ { false, 0x5a64, 0x5a64 }, +/* 0x5a65 */ { false, 0x5a65, 0x5a65 }, +/* 0x5a66 */ { false, 0x5a66, 0x5a66 }, +/* 0x5a67 */ { false, 0x5a67, 0x5a67 }, +/* 0x5a68 */ { false, 0x5a68, 0x5a68 }, +/* 0x5a69 */ { false, 0x5a69, 0x5a69 }, +/* 0x5a6a */ { false, 0x5a6a, 0x5a6a }, +/* 0x5a6b */ { false, 0x5a6b, 0x5a6b }, +/* 0x5a6c */ { false, 0x5a6c, 0x5a6c }, +/* 0x5a6d */ { false, 0x5a6d, 0x5a6d }, +/* 0x5a6e */ { false, 0x5a6e, 0x5a6e }, +/* 0x5a6f */ { false, 0x5a6f, 0x5a6f }, +/* 0x5a70 */ { false, 0x5a70, 0x5a70 }, +/* 0x5a71 */ { false, 0x5a71, 0x5a71 }, +/* 0x5a72 */ { false, 0x5a72, 0x5a72 }, +/* 0x5a73 */ { false, 0x5a73, 0x5a73 }, +/* 0x5a74 */ { false, 0x5a74, 0x5a74 }, +/* 0x5a75 */ { false, 0x5a75, 0x5a75 }, +/* 0x5a76 */ { false, 0x5a76, 0x5a76 }, +/* 0x5a77 */ { false, 0x5a77, 0x5a77 }, +/* 0x5a78 */ { false, 0x5a78, 0x5a78 }, +/* 0x5a79 */ { false, 0x5a79, 0x5a79 }, +/* 0x5a7a */ { false, 0x5a7a, 0x5a7a }, +/* 0x5a7b */ { false, 0x5a7b, 0x5a7b }, +/* 0x5a7c */ { false, 0x5a7c, 0x5a7c }, +/* 0x5a7d */ { false, 0x5a7d, 0x5a7d }, +/* 0x5a7e */ { false, 0x5a7e, 0x5a7e }, +/* 0x5a7f */ { false, 0x5a7f, 0x5a7f }, +/* 0x5a80 */ { false, 0x5a80, 0x5a80 }, +/* 0x5a81 */ { false, 0x5a81, 0x5a81 }, +/* 0x5a82 */ { false, 0x5a82, 0x5a82 }, +/* 0x5a83 */ { false, 0x5a83, 0x5a83 }, +/* 0x5a84 */ { false, 0x5a84, 0x5a84 }, +/* 0x5a85 */ { false, 0x5a85, 0x5a85 }, +/* 0x5a86 */ { false, 0x5a86, 0x5a86 }, +/* 0x5a87 */ { false, 0x5a87, 0x5a87 }, +/* 0x5a88 */ { false, 0x5a88, 0x5a88 }, +/* 0x5a89 */ { false, 0x5a89, 0x5a89 }, +/* 0x5a8a */ { false, 0x5a8a, 0x5a8a }, +/* 0x5a8b */ { false, 0x5a8b, 0x5a8b }, +/* 0x5a8c */ { false, 0x5a8c, 0x5a8c }, +/* 0x5a8d */ { false, 0x5a8d, 0x5a8d }, +/* 0x5a8e */ { false, 0x5a8e, 0x5a8e }, +/* 0x5a8f */ { false, 0x5a8f, 0x5a8f }, +/* 0x5a90 */ { false, 0x5a90, 0x5a90 }, +/* 0x5a91 */ { false, 0x5a91, 0x5a91 }, +/* 0x5a92 */ { false, 0x5a92, 0x5a92 }, +/* 0x5a93 */ { false, 0x5a93, 0x5a93 }, +/* 0x5a94 */ { false, 0x5a94, 0x5a94 }, +/* 0x5a95 */ { false, 0x5a95, 0x5a95 }, +/* 0x5a96 */ { false, 0x5a96, 0x5a96 }, +/* 0x5a97 */ { false, 0x5a97, 0x5a97 }, +/* 0x5a98 */ { false, 0x5a98, 0x5a98 }, +/* 0x5a99 */ { false, 0x5a99, 0x5a99 }, +/* 0x5a9a */ { false, 0x5a9a, 0x5a9a }, +/* 0x5a9b */ { false, 0x5a9b, 0x5a9b }, +/* 0x5a9c */ { false, 0x5a9c, 0x5a9c }, +/* 0x5a9d */ { false, 0x5a9d, 0x5a9d }, +/* 0x5a9e */ { false, 0x5a9e, 0x5a9e }, +/* 0x5a9f */ { false, 0x5a9f, 0x5a9f }, +/* 0x5aa0 */ { false, 0x5aa0, 0x5aa0 }, +/* 0x5aa1 */ { false, 0x5aa1, 0x5aa1 }, +/* 0x5aa2 */ { false, 0x5aa2, 0x5aa2 }, +/* 0x5aa3 */ { false, 0x5aa3, 0x5aa3 }, +/* 0x5aa4 */ { false, 0x5aa4, 0x5aa4 }, +/* 0x5aa5 */ { false, 0x5aa5, 0x5aa5 }, +/* 0x5aa6 */ { false, 0x5aa6, 0x5aa6 }, +/* 0x5aa7 */ { false, 0x5aa7, 0x5aa7 }, +/* 0x5aa8 */ { false, 0x5aa8, 0x5aa8 }, +/* 0x5aa9 */ { false, 0x5aa9, 0x5aa9 }, +/* 0x5aaa */ { false, 0x5aaa, 0x5aaa }, +/* 0x5aab */ { false, 0x5aab, 0x5aab }, +/* 0x5aac */ { false, 0x5aac, 0x5aac }, +/* 0x5aad */ { false, 0x5aad, 0x5aad }, +/* 0x5aae */ { false, 0x5aae, 0x5aae }, +/* 0x5aaf */ { false, 0x5aaf, 0x5aaf }, +/* 0x5ab0 */ { false, 0x5ab0, 0x5ab0 }, +/* 0x5ab1 */ { false, 0x5ab1, 0x5ab1 }, +/* 0x5ab2 */ { false, 0x5ab2, 0x5ab2 }, +/* 0x5ab3 */ { false, 0x5ab3, 0x5ab3 }, +/* 0x5ab4 */ { false, 0x5ab4, 0x5ab4 }, +/* 0x5ab5 */ { false, 0x5ab5, 0x5ab5 }, +/* 0x5ab6 */ { false, 0x5ab6, 0x5ab6 }, +/* 0x5ab7 */ { false, 0x5ab7, 0x5ab7 }, +/* 0x5ab8 */ { false, 0x5ab8, 0x5ab8 }, +/* 0x5ab9 */ { false, 0x5ab9, 0x5ab9 }, +/* 0x5aba */ { false, 0x5aba, 0x5aba }, +/* 0x5abb */ { false, 0x5abb, 0x5abb }, +/* 0x5abc */ { false, 0x5abc, 0x5abc }, +/* 0x5abd */ { false, 0x5abd, 0x5abd }, +/* 0x5abe */ { false, 0x5abe, 0x5abe }, +/* 0x5abf */ { false, 0x5abf, 0x5abf }, +/* 0x5ac0 */ { false, 0x5ac0, 0x5ac0 }, +/* 0x5ac1 */ { false, 0x5ac1, 0x5ac1 }, +/* 0x5ac2 */ { false, 0x5ac2, 0x5ac2 }, +/* 0x5ac3 */ { false, 0x5ac3, 0x5ac3 }, +/* 0x5ac4 */ { false, 0x5ac4, 0x5ac4 }, +/* 0x5ac5 */ { false, 0x5ac5, 0x5ac5 }, +/* 0x5ac6 */ { false, 0x5ac6, 0x5ac6 }, +/* 0x5ac7 */ { false, 0x5ac7, 0x5ac7 }, +/* 0x5ac8 */ { false, 0x5ac8, 0x5ac8 }, +/* 0x5ac9 */ { false, 0x5ac9, 0x5ac9 }, +/* 0x5aca */ { false, 0x5aca, 0x5aca }, +/* 0x5acb */ { false, 0x5acb, 0x5acb }, +/* 0x5acc */ { false, 0x5acc, 0x5acc }, +/* 0x5acd */ { false, 0x5acd, 0x5acd }, +/* 0x5ace */ { false, 0x5ace, 0x5ace }, +/* 0x5acf */ { false, 0x5acf, 0x5acf }, +/* 0x5ad0 */ { false, 0x5ad0, 0x5ad0 }, +/* 0x5ad1 */ { false, 0x5ad1, 0x5ad1 }, +/* 0x5ad2 */ { false, 0x5ad2, 0x5ad2 }, +/* 0x5ad3 */ { false, 0x5ad3, 0x5ad3 }, +/* 0x5ad4 */ { false, 0x5ad4, 0x5ad4 }, +/* 0x5ad5 */ { false, 0x5ad5, 0x5ad5 }, +/* 0x5ad6 */ { false, 0x5ad6, 0x5ad6 }, +/* 0x5ad7 */ { false, 0x5ad7, 0x5ad7 }, +/* 0x5ad8 */ { false, 0x5ad8, 0x5ad8 }, +/* 0x5ad9 */ { false, 0x5ad9, 0x5ad9 }, +/* 0x5ada */ { false, 0x5ada, 0x5ada }, +/* 0x5adb */ { false, 0x5adb, 0x5adb }, +/* 0x5adc */ { false, 0x5adc, 0x5adc }, +/* 0x5add */ { false, 0x5add, 0x5add }, +/* 0x5ade */ { false, 0x5ade, 0x5ade }, +/* 0x5adf */ { false, 0x5adf, 0x5adf }, +/* 0x5ae0 */ { false, 0x5ae0, 0x5ae0 }, +/* 0x5ae1 */ { false, 0x5ae1, 0x5ae1 }, +/* 0x5ae2 */ { false, 0x5ae2, 0x5ae2 }, +/* 0x5ae3 */ { false, 0x5ae3, 0x5ae3 }, +/* 0x5ae4 */ { false, 0x5ae4, 0x5ae4 }, +/* 0x5ae5 */ { false, 0x5ae5, 0x5ae5 }, +/* 0x5ae6 */ { false, 0x5ae6, 0x5ae6 }, +/* 0x5ae7 */ { false, 0x5ae7, 0x5ae7 }, +/* 0x5ae8 */ { false, 0x5ae8, 0x5ae8 }, +/* 0x5ae9 */ { false, 0x5ae9, 0x5ae9 }, +/* 0x5aea */ { false, 0x5aea, 0x5aea }, +/* 0x5aeb */ { false, 0x5aeb, 0x5aeb }, +/* 0x5aec */ { false, 0x5aec, 0x5aec }, +/* 0x5aed */ { false, 0x5aed, 0x5aed }, +/* 0x5aee */ { false, 0x5aee, 0x5aee }, +/* 0x5aef */ { false, 0x5aef, 0x5aef }, +/* 0x5af0 */ { false, 0x5af0, 0x5af0 }, +/* 0x5af1 */ { false, 0x5af1, 0x5af1 }, +/* 0x5af2 */ { false, 0x5af2, 0x5af2 }, +/* 0x5af3 */ { false, 0x5af3, 0x5af3 }, +/* 0x5af4 */ { false, 0x5af4, 0x5af4 }, +/* 0x5af5 */ { false, 0x5af5, 0x5af5 }, +/* 0x5af6 */ { false, 0x5af6, 0x5af6 }, +/* 0x5af7 */ { false, 0x5af7, 0x5af7 }, +/* 0x5af8 */ { false, 0x5af8, 0x5af8 }, +/* 0x5af9 */ { false, 0x5af9, 0x5af9 }, +/* 0x5afa */ { false, 0x5afa, 0x5afa }, +/* 0x5afb */ { false, 0x5afb, 0x5afb }, +/* 0x5afc */ { false, 0x5afc, 0x5afc }, +/* 0x5afd */ { false, 0x5afd, 0x5afd }, +/* 0x5afe */ { false, 0x5afe, 0x5afe }, +/* 0x5aff */ { false, 0x5aff, 0x5aff }, +/* 0x5b00 */ { false, 0x5b00, 0x5b00 }, +/* 0x5b01 */ { false, 0x5b01, 0x5b01 }, +/* 0x5b02 */ { false, 0x5b02, 0x5b02 }, +/* 0x5b03 */ { false, 0x5b03, 0x5b03 }, +/* 0x5b04 */ { false, 0x5b04, 0x5b04 }, +/* 0x5b05 */ { false, 0x5b05, 0x5b05 }, +/* 0x5b06 */ { false, 0x5b06, 0x5b06 }, +/* 0x5b07 */ { false, 0x5b07, 0x5b07 }, +/* 0x5b08 */ { false, 0x5b08, 0x5b08 }, +/* 0x5b09 */ { false, 0x5b09, 0x5b09 }, +/* 0x5b0a */ { false, 0x5b0a, 0x5b0a }, +/* 0x5b0b */ { false, 0x5b0b, 0x5b0b }, +/* 0x5b0c */ { false, 0x5b0c, 0x5b0c }, +/* 0x5b0d */ { false, 0x5b0d, 0x5b0d }, +/* 0x5b0e */ { false, 0x5b0e, 0x5b0e }, +/* 0x5b0f */ { false, 0x5b0f, 0x5b0f }, +/* 0x5b10 */ { false, 0x5b10, 0x5b10 }, +/* 0x5b11 */ { false, 0x5b11, 0x5b11 }, +/* 0x5b12 */ { false, 0x5b12, 0x5b12 }, +/* 0x5b13 */ { false, 0x5b13, 0x5b13 }, +/* 0x5b14 */ { false, 0x5b14, 0x5b14 }, +/* 0x5b15 */ { false, 0x5b15, 0x5b15 }, +/* 0x5b16 */ { false, 0x5b16, 0x5b16 }, +/* 0x5b17 */ { false, 0x5b17, 0x5b17 }, +/* 0x5b18 */ { false, 0x5b18, 0x5b18 }, +/* 0x5b19 */ { false, 0x5b19, 0x5b19 }, +/* 0x5b1a */ { false, 0x5b1a, 0x5b1a }, +/* 0x5b1b */ { false, 0x5b1b, 0x5b1b }, +/* 0x5b1c */ { false, 0x5b1c, 0x5b1c }, +/* 0x5b1d */ { false, 0x5b1d, 0x5b1d }, +/* 0x5b1e */ { false, 0x5b1e, 0x5b1e }, +/* 0x5b1f */ { false, 0x5b1f, 0x5b1f }, +/* 0x5b20 */ { false, 0x5b20, 0x5b20 }, +/* 0x5b21 */ { false, 0x5b21, 0x5b21 }, +/* 0x5b22 */ { false, 0x5b22, 0x5b22 }, +/* 0x5b23 */ { false, 0x5b23, 0x5b23 }, +/* 0x5b24 */ { false, 0x5b24, 0x5b24 }, +/* 0x5b25 */ { false, 0x5b25, 0x5b25 }, +/* 0x5b26 */ { false, 0x5b26, 0x5b26 }, +/* 0x5b27 */ { false, 0x5b27, 0x5b27 }, +/* 0x5b28 */ { false, 0x5b28, 0x5b28 }, +/* 0x5b29 */ { false, 0x5b29, 0x5b29 }, +/* 0x5b2a */ { false, 0x5b2a, 0x5b2a }, +/* 0x5b2b */ { false, 0x5b2b, 0x5b2b }, +/* 0x5b2c */ { false, 0x5b2c, 0x5b2c }, +/* 0x5b2d */ { false, 0x5b2d, 0x5b2d }, +/* 0x5b2e */ { false, 0x5b2e, 0x5b2e }, +/* 0x5b2f */ { false, 0x5b2f, 0x5b2f }, +/* 0x5b30 */ { false, 0x5b30, 0x5b30 }, +/* 0x5b31 */ { false, 0x5b31, 0x5b31 }, +/* 0x5b32 */ { false, 0x5b32, 0x5b32 }, +/* 0x5b33 */ { false, 0x5b33, 0x5b33 }, +/* 0x5b34 */ { false, 0x5b34, 0x5b34 }, +/* 0x5b35 */ { false, 0x5b35, 0x5b35 }, +/* 0x5b36 */ { false, 0x5b36, 0x5b36 }, +/* 0x5b37 */ { false, 0x5b37, 0x5b37 }, +/* 0x5b38 */ { false, 0x5b38, 0x5b38 }, +/* 0x5b39 */ { false, 0x5b39, 0x5b39 }, +/* 0x5b3a */ { false, 0x5b3a, 0x5b3a }, +/* 0x5b3b */ { false, 0x5b3b, 0x5b3b }, +/* 0x5b3c */ { false, 0x5b3c, 0x5b3c }, +/* 0x5b3d */ { false, 0x5b3d, 0x5b3d }, +/* 0x5b3e */ { false, 0x5b3e, 0x5b3e }, +/* 0x5b3f */ { false, 0x5b3f, 0x5b3f }, +/* 0x5b40 */ { false, 0x5b40, 0x5b40 }, +/* 0x5b41 */ { false, 0x5b41, 0x5b41 }, +/* 0x5b42 */ { false, 0x5b42, 0x5b42 }, +/* 0x5b43 */ { false, 0x5b43, 0x5b43 }, +/* 0x5b44 */ { false, 0x5b44, 0x5b44 }, +/* 0x5b45 */ { false, 0x5b45, 0x5b45 }, +/* 0x5b46 */ { false, 0x5b46, 0x5b46 }, +/* 0x5b47 */ { false, 0x5b47, 0x5b47 }, +/* 0x5b48 */ { false, 0x5b48, 0x5b48 }, +/* 0x5b49 */ { false, 0x5b49, 0x5b49 }, +/* 0x5b4a */ { false, 0x5b4a, 0x5b4a }, +/* 0x5b4b */ { false, 0x5b4b, 0x5b4b }, +/* 0x5b4c */ { false, 0x5b4c, 0x5b4c }, +/* 0x5b4d */ { false, 0x5b4d, 0x5b4d }, +/* 0x5b4e */ { false, 0x5b4e, 0x5b4e }, +/* 0x5b4f */ { false, 0x5b4f, 0x5b4f }, +/* 0x5b50 */ { false, 0x5b50, 0x5b50 }, +/* 0x5b51 */ { false, 0x5b51, 0x5b51 }, +/* 0x5b52 */ { false, 0x5b52, 0x5b52 }, +/* 0x5b53 */ { false, 0x5b53, 0x5b53 }, +/* 0x5b54 */ { false, 0x5b54, 0x5b54 }, +/* 0x5b55 */ { false, 0x5b55, 0x5b55 }, +/* 0x5b56 */ { false, 0x5b56, 0x5b56 }, +/* 0x5b57 */ { false, 0x5b57, 0x5b57 }, +/* 0x5b58 */ { false, 0x5b58, 0x5b58 }, +/* 0x5b59 */ { false, 0x5b59, 0x5b59 }, +/* 0x5b5a */ { false, 0x5b5a, 0x5b5a }, +/* 0x5b5b */ { false, 0x5b5b, 0x5b5b }, +/* 0x5b5c */ { false, 0x5b5c, 0x5b5c }, +/* 0x5b5d */ { false, 0x5b5d, 0x5b5d }, +/* 0x5b5e */ { false, 0x5b5e, 0x5b5e }, +/* 0x5b5f */ { false, 0x5b5f, 0x5b5f }, +/* 0x5b60 */ { false, 0x5b60, 0x5b60 }, +/* 0x5b61 */ { false, 0x5b61, 0x5b61 }, +/* 0x5b62 */ { false, 0x5b62, 0x5b62 }, +/* 0x5b63 */ { false, 0x5b63, 0x5b63 }, +/* 0x5b64 */ { false, 0x5b64, 0x5b64 }, +/* 0x5b65 */ { false, 0x5b65, 0x5b65 }, +/* 0x5b66 */ { false, 0x5b66, 0x5b66 }, +/* 0x5b67 */ { false, 0x5b67, 0x5b67 }, +/* 0x5b68 */ { false, 0x5b68, 0x5b68 }, +/* 0x5b69 */ { false, 0x5b69, 0x5b69 }, +/* 0x5b6a */ { false, 0x5b6a, 0x5b6a }, +/* 0x5b6b */ { false, 0x5b6b, 0x5b6b }, +/* 0x5b6c */ { false, 0x5b6c, 0x5b6c }, +/* 0x5b6d */ { false, 0x5b6d, 0x5b6d }, +/* 0x5b6e */ { false, 0x5b6e, 0x5b6e }, +/* 0x5b6f */ { false, 0x5b6f, 0x5b6f }, +/* 0x5b70 */ { false, 0x5b70, 0x5b70 }, +/* 0x5b71 */ { false, 0x5b71, 0x5b71 }, +/* 0x5b72 */ { false, 0x5b72, 0x5b72 }, +/* 0x5b73 */ { false, 0x5b73, 0x5b73 }, +/* 0x5b74 */ { false, 0x5b74, 0x5b74 }, +/* 0x5b75 */ { false, 0x5b75, 0x5b75 }, +/* 0x5b76 */ { false, 0x5b76, 0x5b76 }, +/* 0x5b77 */ { false, 0x5b77, 0x5b77 }, +/* 0x5b78 */ { false, 0x5b78, 0x5b78 }, +/* 0x5b79 */ { false, 0x5b79, 0x5b79 }, +/* 0x5b7a */ { false, 0x5b7a, 0x5b7a }, +/* 0x5b7b */ { false, 0x5b7b, 0x5b7b }, +/* 0x5b7c */ { false, 0x5b7c, 0x5b7c }, +/* 0x5b7d */ { false, 0x5b7d, 0x5b7d }, +/* 0x5b7e */ { false, 0x5b7e, 0x5b7e }, +/* 0x5b7f */ { false, 0x5b7f, 0x5b7f }, +/* 0x5b80 */ { false, 0x5b80, 0x5b80 }, +/* 0x5b81 */ { false, 0x5b81, 0x5b81 }, +/* 0x5b82 */ { false, 0x5b82, 0x5b82 }, +/* 0x5b83 */ { false, 0x5b83, 0x5b83 }, +/* 0x5b84 */ { false, 0x5b84, 0x5b84 }, +/* 0x5b85 */ { false, 0x5b85, 0x5b85 }, +/* 0x5b86 */ { false, 0x5b86, 0x5b86 }, +/* 0x5b87 */ { false, 0x5b87, 0x5b87 }, +/* 0x5b88 */ { false, 0x5b88, 0x5b88 }, +/* 0x5b89 */ { false, 0x5b89, 0x5b89 }, +/* 0x5b8a */ { false, 0x5b8a, 0x5b8a }, +/* 0x5b8b */ { false, 0x5b8b, 0x5b8b }, +/* 0x5b8c */ { false, 0x5b8c, 0x5b8c }, +/* 0x5b8d */ { false, 0x5b8d, 0x5b8d }, +/* 0x5b8e */ { false, 0x5b8e, 0x5b8e }, +/* 0x5b8f */ { false, 0x5b8f, 0x5b8f }, +/* 0x5b90 */ { false, 0x5b90, 0x5b90 }, +/* 0x5b91 */ { false, 0x5b91, 0x5b91 }, +/* 0x5b92 */ { false, 0x5b92, 0x5b92 }, +/* 0x5b93 */ { false, 0x5b93, 0x5b93 }, +/* 0x5b94 */ { false, 0x5b94, 0x5b94 }, +/* 0x5b95 */ { false, 0x5b95, 0x5b95 }, +/* 0x5b96 */ { false, 0x5b96, 0x5b96 }, +/* 0x5b97 */ { false, 0x5b97, 0x5b97 }, +/* 0x5b98 */ { false, 0x5b98, 0x5b98 }, +/* 0x5b99 */ { false, 0x5b99, 0x5b99 }, +/* 0x5b9a */ { false, 0x5b9a, 0x5b9a }, +/* 0x5b9b */ { false, 0x5b9b, 0x5b9b }, +/* 0x5b9c */ { false, 0x5b9c, 0x5b9c }, +/* 0x5b9d */ { false, 0x5b9d, 0x5b9d }, +/* 0x5b9e */ { false, 0x5b9e, 0x5b9e }, +/* 0x5b9f */ { false, 0x5b9f, 0x5b9f }, +/* 0x5ba0 */ { false, 0x5ba0, 0x5ba0 }, +/* 0x5ba1 */ { false, 0x5ba1, 0x5ba1 }, +/* 0x5ba2 */ { false, 0x5ba2, 0x5ba2 }, +/* 0x5ba3 */ { false, 0x5ba3, 0x5ba3 }, +/* 0x5ba4 */ { false, 0x5ba4, 0x5ba4 }, +/* 0x5ba5 */ { false, 0x5ba5, 0x5ba5 }, +/* 0x5ba6 */ { false, 0x5ba6, 0x5ba6 }, +/* 0x5ba7 */ { false, 0x5ba7, 0x5ba7 }, +/* 0x5ba8 */ { false, 0x5ba8, 0x5ba8 }, +/* 0x5ba9 */ { false, 0x5ba9, 0x5ba9 }, +/* 0x5baa */ { false, 0x5baa, 0x5baa }, +/* 0x5bab */ { false, 0x5bab, 0x5bab }, +/* 0x5bac */ { false, 0x5bac, 0x5bac }, +/* 0x5bad */ { false, 0x5bad, 0x5bad }, +/* 0x5bae */ { false, 0x5bae, 0x5bae }, +/* 0x5baf */ { false, 0x5baf, 0x5baf }, +/* 0x5bb0 */ { false, 0x5bb0, 0x5bb0 }, +/* 0x5bb1 */ { false, 0x5bb1, 0x5bb1 }, +/* 0x5bb2 */ { false, 0x5bb2, 0x5bb2 }, +/* 0x5bb3 */ { false, 0x5bb3, 0x5bb3 }, +/* 0x5bb4 */ { false, 0x5bb4, 0x5bb4 }, +/* 0x5bb5 */ { false, 0x5bb5, 0x5bb5 }, +/* 0x5bb6 */ { false, 0x5bb6, 0x5bb6 }, +/* 0x5bb7 */ { false, 0x5bb7, 0x5bb7 }, +/* 0x5bb8 */ { false, 0x5bb8, 0x5bb8 }, +/* 0x5bb9 */ { false, 0x5bb9, 0x5bb9 }, +/* 0x5bba */ { false, 0x5bba, 0x5bba }, +/* 0x5bbb */ { false, 0x5bbb, 0x5bbb }, +/* 0x5bbc */ { false, 0x5bbc, 0x5bbc }, +/* 0x5bbd */ { false, 0x5bbd, 0x5bbd }, +/* 0x5bbe */ { false, 0x5bbe, 0x5bbe }, +/* 0x5bbf */ { false, 0x5bbf, 0x5bbf }, +/* 0x5bc0 */ { false, 0x5bc0, 0x5bc0 }, +/* 0x5bc1 */ { false, 0x5bc1, 0x5bc1 }, +/* 0x5bc2 */ { false, 0x5bc2, 0x5bc2 }, +/* 0x5bc3 */ { false, 0x5bc3, 0x5bc3 }, +/* 0x5bc4 */ { false, 0x5bc4, 0x5bc4 }, +/* 0x5bc5 */ { false, 0x5bc5, 0x5bc5 }, +/* 0x5bc6 */ { false, 0x5bc6, 0x5bc6 }, +/* 0x5bc7 */ { false, 0x5bc7, 0x5bc7 }, +/* 0x5bc8 */ { false, 0x5bc8, 0x5bc8 }, +/* 0x5bc9 */ { false, 0x5bc9, 0x5bc9 }, +/* 0x5bca */ { false, 0x5bca, 0x5bca }, +/* 0x5bcb */ { false, 0x5bcb, 0x5bcb }, +/* 0x5bcc */ { false, 0x5bcc, 0x5bcc }, +/* 0x5bcd */ { false, 0x5bcd, 0x5bcd }, +/* 0x5bce */ { false, 0x5bce, 0x5bce }, +/* 0x5bcf */ { false, 0x5bcf, 0x5bcf }, +/* 0x5bd0 */ { false, 0x5bd0, 0x5bd0 }, +/* 0x5bd1 */ { false, 0x5bd1, 0x5bd1 }, +/* 0x5bd2 */ { false, 0x5bd2, 0x5bd2 }, +/* 0x5bd3 */ { false, 0x5bd3, 0x5bd3 }, +/* 0x5bd4 */ { false, 0x5bd4, 0x5bd4 }, +/* 0x5bd5 */ { false, 0x5bd5, 0x5bd5 }, +/* 0x5bd6 */ { false, 0x5bd6, 0x5bd6 }, +/* 0x5bd7 */ { false, 0x5bd7, 0x5bd7 }, +/* 0x5bd8 */ { false, 0x5bd8, 0x5bd8 }, +/* 0x5bd9 */ { false, 0x5bd9, 0x5bd9 }, +/* 0x5bda */ { false, 0x5bda, 0x5bda }, +/* 0x5bdb */ { false, 0x5bdb, 0x5bdb }, +/* 0x5bdc */ { false, 0x5bdc, 0x5bdc }, +/* 0x5bdd */ { false, 0x5bdd, 0x5bdd }, +/* 0x5bde */ { false, 0x5bde, 0x5bde }, +/* 0x5bdf */ { false, 0x5bdf, 0x5bdf }, +/* 0x5be0 */ { false, 0x5be0, 0x5be0 }, +/* 0x5be1 */ { false, 0x5be1, 0x5be1 }, +/* 0x5be2 */ { false, 0x5be2, 0x5be2 }, +/* 0x5be3 */ { false, 0x5be3, 0x5be3 }, +/* 0x5be4 */ { false, 0x5be4, 0x5be4 }, +/* 0x5be5 */ { false, 0x5be5, 0x5be5 }, +/* 0x5be6 */ { false, 0x5be6, 0x5be6 }, +/* 0x5be7 */ { false, 0x5be7, 0x5be7 }, +/* 0x5be8 */ { false, 0x5be8, 0x5be8 }, +/* 0x5be9 */ { false, 0x5be9, 0x5be9 }, +/* 0x5bea */ { false, 0x5bea, 0x5bea }, +/* 0x5beb */ { false, 0x5beb, 0x5beb }, +/* 0x5bec */ { false, 0x5bec, 0x5bec }, +/* 0x5bed */ { false, 0x5bed, 0x5bed }, +/* 0x5bee */ { false, 0x5bee, 0x5bee }, +/* 0x5bef */ { false, 0x5bef, 0x5bef }, +/* 0x5bf0 */ { false, 0x5bf0, 0x5bf0 }, +/* 0x5bf1 */ { false, 0x5bf1, 0x5bf1 }, +/* 0x5bf2 */ { false, 0x5bf2, 0x5bf2 }, +/* 0x5bf3 */ { false, 0x5bf3, 0x5bf3 }, +/* 0x5bf4 */ { false, 0x5bf4, 0x5bf4 }, +/* 0x5bf5 */ { false, 0x5bf5, 0x5bf5 }, +/* 0x5bf6 */ { false, 0x5bf6, 0x5bf6 }, +/* 0x5bf7 */ { false, 0x5bf7, 0x5bf7 }, +/* 0x5bf8 */ { false, 0x5bf8, 0x5bf8 }, +/* 0x5bf9 */ { false, 0x5bf9, 0x5bf9 }, +/* 0x5bfa */ { false, 0x5bfa, 0x5bfa }, +/* 0x5bfb */ { false, 0x5bfb, 0x5bfb }, +/* 0x5bfc */ { false, 0x5bfc, 0x5bfc }, +/* 0x5bfd */ { false, 0x5bfd, 0x5bfd }, +/* 0x5bfe */ { false, 0x5bfe, 0x5bfe }, +/* 0x5bff */ { false, 0x5bff, 0x5bff }, +/* 0x5c00 */ { false, 0x5c00, 0x5c00 }, +/* 0x5c01 */ { false, 0x5c01, 0x5c01 }, +/* 0x5c02 */ { false, 0x5c02, 0x5c02 }, +/* 0x5c03 */ { false, 0x5c03, 0x5c03 }, +/* 0x5c04 */ { false, 0x5c04, 0x5c04 }, +/* 0x5c05 */ { false, 0x5c05, 0x5c05 }, +/* 0x5c06 */ { false, 0x5c06, 0x5c06 }, +/* 0x5c07 */ { false, 0x5c07, 0x5c07 }, +/* 0x5c08 */ { false, 0x5c08, 0x5c08 }, +/* 0x5c09 */ { false, 0x5c09, 0x5c09 }, +/* 0x5c0a */ { false, 0x5c0a, 0x5c0a }, +/* 0x5c0b */ { false, 0x5c0b, 0x5c0b }, +/* 0x5c0c */ { false, 0x5c0c, 0x5c0c }, +/* 0x5c0d */ { false, 0x5c0d, 0x5c0d }, +/* 0x5c0e */ { false, 0x5c0e, 0x5c0e }, +/* 0x5c0f */ { false, 0x5c0f, 0x5c0f }, +/* 0x5c10 */ { false, 0x5c10, 0x5c10 }, +/* 0x5c11 */ { false, 0x5c11, 0x5c11 }, +/* 0x5c12 */ { false, 0x5c12, 0x5c12 }, +/* 0x5c13 */ { false, 0x5c13, 0x5c13 }, +/* 0x5c14 */ { false, 0x5c14, 0x5c14 }, +/* 0x5c15 */ { false, 0x5c15, 0x5c15 }, +/* 0x5c16 */ { false, 0x5c16, 0x5c16 }, +/* 0x5c17 */ { false, 0x5c17, 0x5c17 }, +/* 0x5c18 */ { false, 0x5c18, 0x5c18 }, +/* 0x5c19 */ { false, 0x5c19, 0x5c19 }, +/* 0x5c1a */ { false, 0x5c1a, 0x5c1a }, +/* 0x5c1b */ { false, 0x5c1b, 0x5c1b }, +/* 0x5c1c */ { false, 0x5c1c, 0x5c1c }, +/* 0x5c1d */ { false, 0x5c1d, 0x5c1d }, +/* 0x5c1e */ { false, 0x5c1e, 0x5c1e }, +/* 0x5c1f */ { false, 0x5c1f, 0x5c1f }, +/* 0x5c20 */ { false, 0x5c20, 0x5c20 }, +/* 0x5c21 */ { false, 0x5c21, 0x5c21 }, +/* 0x5c22 */ { false, 0x5c22, 0x5c22 }, +/* 0x5c23 */ { false, 0x5c23, 0x5c23 }, +/* 0x5c24 */ { false, 0x5c24, 0x5c24 }, +/* 0x5c25 */ { false, 0x5c25, 0x5c25 }, +/* 0x5c26 */ { false, 0x5c26, 0x5c26 }, +/* 0x5c27 */ { false, 0x5c27, 0x5c27 }, +/* 0x5c28 */ { false, 0x5c28, 0x5c28 }, +/* 0x5c29 */ { false, 0x5c29, 0x5c29 }, +/* 0x5c2a */ { false, 0x5c2a, 0x5c2a }, +/* 0x5c2b */ { false, 0x5c2b, 0x5c2b }, +/* 0x5c2c */ { false, 0x5c2c, 0x5c2c }, +/* 0x5c2d */ { false, 0x5c2d, 0x5c2d }, +/* 0x5c2e */ { false, 0x5c2e, 0x5c2e }, +/* 0x5c2f */ { false, 0x5c2f, 0x5c2f }, +/* 0x5c30 */ { false, 0x5c30, 0x5c30 }, +/* 0x5c31 */ { false, 0x5c31, 0x5c31 }, +/* 0x5c32 */ { false, 0x5c32, 0x5c32 }, +/* 0x5c33 */ { false, 0x5c33, 0x5c33 }, +/* 0x5c34 */ { false, 0x5c34, 0x5c34 }, +/* 0x5c35 */ { false, 0x5c35, 0x5c35 }, +/* 0x5c36 */ { false, 0x5c36, 0x5c36 }, +/* 0x5c37 */ { false, 0x5c37, 0x5c37 }, +/* 0x5c38 */ { false, 0x5c38, 0x5c38 }, +/* 0x5c39 */ { false, 0x5c39, 0x5c39 }, +/* 0x5c3a */ { false, 0x5c3a, 0x5c3a }, +/* 0x5c3b */ { false, 0x5c3b, 0x5c3b }, +/* 0x5c3c */ { false, 0x5c3c, 0x5c3c }, +/* 0x5c3d */ { false, 0x5c3d, 0x5c3d }, +/* 0x5c3e */ { false, 0x5c3e, 0x5c3e }, +/* 0x5c3f */ { false, 0x5c3f, 0x5c3f }, +/* 0x5c40 */ { false, 0x5c40, 0x5c40 }, +/* 0x5c41 */ { false, 0x5c41, 0x5c41 }, +/* 0x5c42 */ { false, 0x5c42, 0x5c42 }, +/* 0x5c43 */ { false, 0x5c43, 0x5c43 }, +/* 0x5c44 */ { false, 0x5c44, 0x5c44 }, +/* 0x5c45 */ { false, 0x5c45, 0x5c45 }, +/* 0x5c46 */ { false, 0x5c46, 0x5c46 }, +/* 0x5c47 */ { false, 0x5c47, 0x5c47 }, +/* 0x5c48 */ { false, 0x5c48, 0x5c48 }, +/* 0x5c49 */ { false, 0x5c49, 0x5c49 }, +/* 0x5c4a */ { false, 0x5c4a, 0x5c4a }, +/* 0x5c4b */ { false, 0x5c4b, 0x5c4b }, +/* 0x5c4c */ { false, 0x5c4c, 0x5c4c }, +/* 0x5c4d */ { false, 0x5c4d, 0x5c4d }, +/* 0x5c4e */ { false, 0x5c4e, 0x5c4e }, +/* 0x5c4f */ { false, 0x5c4f, 0x5c4f }, +/* 0x5c50 */ { false, 0x5c50, 0x5c50 }, +/* 0x5c51 */ { false, 0x5c51, 0x5c51 }, +/* 0x5c52 */ { false, 0x5c52, 0x5c52 }, +/* 0x5c53 */ { false, 0x5c53, 0x5c53 }, +/* 0x5c54 */ { false, 0x5c54, 0x5c54 }, +/* 0x5c55 */ { false, 0x5c55, 0x5c55 }, +/* 0x5c56 */ { false, 0x5c56, 0x5c56 }, +/* 0x5c57 */ { false, 0x5c57, 0x5c57 }, +/* 0x5c58 */ { false, 0x5c58, 0x5c58 }, +/* 0x5c59 */ { false, 0x5c59, 0x5c59 }, +/* 0x5c5a */ { false, 0x5c5a, 0x5c5a }, +/* 0x5c5b */ { false, 0x5c5b, 0x5c5b }, +/* 0x5c5c */ { false, 0x5c5c, 0x5c5c }, +/* 0x5c5d */ { false, 0x5c5d, 0x5c5d }, +/* 0x5c5e */ { false, 0x5c5e, 0x5c5e }, +/* 0x5c5f */ { false, 0x5c5f, 0x5c5f }, +/* 0x5c60 */ { false, 0x5c60, 0x5c60 }, +/* 0x5c61 */ { false, 0x5c61, 0x5c61 }, +/* 0x5c62 */ { false, 0x5c62, 0x5c62 }, +/* 0x5c63 */ { false, 0x5c63, 0x5c63 }, +/* 0x5c64 */ { false, 0x5c64, 0x5c64 }, +/* 0x5c65 */ { false, 0x5c65, 0x5c65 }, +/* 0x5c66 */ { false, 0x5c66, 0x5c66 }, +/* 0x5c67 */ { false, 0x5c67, 0x5c67 }, +/* 0x5c68 */ { false, 0x5c68, 0x5c68 }, +/* 0x5c69 */ { false, 0x5c69, 0x5c69 }, +/* 0x5c6a */ { false, 0x5c6a, 0x5c6a }, +/* 0x5c6b */ { false, 0x5c6b, 0x5c6b }, +/* 0x5c6c */ { false, 0x5c6c, 0x5c6c }, +/* 0x5c6d */ { false, 0x5c6d, 0x5c6d }, +/* 0x5c6e */ { false, 0x5c6e, 0x5c6e }, +/* 0x5c6f */ { false, 0x5c6f, 0x5c6f }, +/* 0x5c70 */ { false, 0x5c70, 0x5c70 }, +/* 0x5c71 */ { false, 0x5c71, 0x5c71 }, +/* 0x5c72 */ { false, 0x5c72, 0x5c72 }, +/* 0x5c73 */ { false, 0x5c73, 0x5c73 }, +/* 0x5c74 */ { false, 0x5c74, 0x5c74 }, +/* 0x5c75 */ { false, 0x5c75, 0x5c75 }, +/* 0x5c76 */ { false, 0x5c76, 0x5c76 }, +/* 0x5c77 */ { false, 0x5c77, 0x5c77 }, +/* 0x5c78 */ { false, 0x5c78, 0x5c78 }, +/* 0x5c79 */ { false, 0x5c79, 0x5c79 }, +/* 0x5c7a */ { false, 0x5c7a, 0x5c7a }, +/* 0x5c7b */ { false, 0x5c7b, 0x5c7b }, +/* 0x5c7c */ { false, 0x5c7c, 0x5c7c }, +/* 0x5c7d */ { false, 0x5c7d, 0x5c7d }, +/* 0x5c7e */ { false, 0x5c7e, 0x5c7e }, +/* 0x5c7f */ { false, 0x5c7f, 0x5c7f }, +/* 0x5c80 */ { false, 0x5c80, 0x5c80 }, +/* 0x5c81 */ { false, 0x5c81, 0x5c81 }, +/* 0x5c82 */ { false, 0x5c82, 0x5c82 }, +/* 0x5c83 */ { false, 0x5c83, 0x5c83 }, +/* 0x5c84 */ { false, 0x5c84, 0x5c84 }, +/* 0x5c85 */ { false, 0x5c85, 0x5c85 }, +/* 0x5c86 */ { false, 0x5c86, 0x5c86 }, +/* 0x5c87 */ { false, 0x5c87, 0x5c87 }, +/* 0x5c88 */ { false, 0x5c88, 0x5c88 }, +/* 0x5c89 */ { false, 0x5c89, 0x5c89 }, +/* 0x5c8a */ { false, 0x5c8a, 0x5c8a }, +/* 0x5c8b */ { false, 0x5c8b, 0x5c8b }, +/* 0x5c8c */ { false, 0x5c8c, 0x5c8c }, +/* 0x5c8d */ { false, 0x5c8d, 0x5c8d }, +/* 0x5c8e */ { false, 0x5c8e, 0x5c8e }, +/* 0x5c8f */ { false, 0x5c8f, 0x5c8f }, +/* 0x5c90 */ { false, 0x5c90, 0x5c90 }, +/* 0x5c91 */ { false, 0x5c91, 0x5c91 }, +/* 0x5c92 */ { false, 0x5c92, 0x5c92 }, +/* 0x5c93 */ { false, 0x5c93, 0x5c93 }, +/* 0x5c94 */ { false, 0x5c94, 0x5c94 }, +/* 0x5c95 */ { false, 0x5c95, 0x5c95 }, +/* 0x5c96 */ { false, 0x5c96, 0x5c96 }, +/* 0x5c97 */ { false, 0x5c97, 0x5c97 }, +/* 0x5c98 */ { false, 0x5c98, 0x5c98 }, +/* 0x5c99 */ { false, 0x5c99, 0x5c99 }, +/* 0x5c9a */ { false, 0x5c9a, 0x5c9a }, +/* 0x5c9b */ { false, 0x5c9b, 0x5c9b }, +/* 0x5c9c */ { false, 0x5c9c, 0x5c9c }, +/* 0x5c9d */ { false, 0x5c9d, 0x5c9d }, +/* 0x5c9e */ { false, 0x5c9e, 0x5c9e }, +/* 0x5c9f */ { false, 0x5c9f, 0x5c9f }, +/* 0x5ca0 */ { false, 0x5ca0, 0x5ca0 }, +/* 0x5ca1 */ { false, 0x5ca1, 0x5ca1 }, +/* 0x5ca2 */ { false, 0x5ca2, 0x5ca2 }, +/* 0x5ca3 */ { false, 0x5ca3, 0x5ca3 }, +/* 0x5ca4 */ { false, 0x5ca4, 0x5ca4 }, +/* 0x5ca5 */ { false, 0x5ca5, 0x5ca5 }, +/* 0x5ca6 */ { false, 0x5ca6, 0x5ca6 }, +/* 0x5ca7 */ { false, 0x5ca7, 0x5ca7 }, +/* 0x5ca8 */ { false, 0x5ca8, 0x5ca8 }, +/* 0x5ca9 */ { false, 0x5ca9, 0x5ca9 }, +/* 0x5caa */ { false, 0x5caa, 0x5caa }, +/* 0x5cab */ { false, 0x5cab, 0x5cab }, +/* 0x5cac */ { false, 0x5cac, 0x5cac }, +/* 0x5cad */ { false, 0x5cad, 0x5cad }, +/* 0x5cae */ { false, 0x5cae, 0x5cae }, +/* 0x5caf */ { false, 0x5caf, 0x5caf }, +/* 0x5cb0 */ { false, 0x5cb0, 0x5cb0 }, +/* 0x5cb1 */ { false, 0x5cb1, 0x5cb1 }, +/* 0x5cb2 */ { false, 0x5cb2, 0x5cb2 }, +/* 0x5cb3 */ { false, 0x5cb3, 0x5cb3 }, +/* 0x5cb4 */ { false, 0x5cb4, 0x5cb4 }, +/* 0x5cb5 */ { false, 0x5cb5, 0x5cb5 }, +/* 0x5cb6 */ { false, 0x5cb6, 0x5cb6 }, +/* 0x5cb7 */ { false, 0x5cb7, 0x5cb7 }, +/* 0x5cb8 */ { false, 0x5cb8, 0x5cb8 }, +/* 0x5cb9 */ { false, 0x5cb9, 0x5cb9 }, +/* 0x5cba */ { false, 0x5cba, 0x5cba }, +/* 0x5cbb */ { false, 0x5cbb, 0x5cbb }, +/* 0x5cbc */ { false, 0x5cbc, 0x5cbc }, +/* 0x5cbd */ { false, 0x5cbd, 0x5cbd }, +/* 0x5cbe */ { false, 0x5cbe, 0x5cbe }, +/* 0x5cbf */ { false, 0x5cbf, 0x5cbf }, +/* 0x5cc0 */ { false, 0x5cc0, 0x5cc0 }, +/* 0x5cc1 */ { false, 0x5cc1, 0x5cc1 }, +/* 0x5cc2 */ { false, 0x5cc2, 0x5cc2 }, +/* 0x5cc3 */ { false, 0x5cc3, 0x5cc3 }, +/* 0x5cc4 */ { false, 0x5cc4, 0x5cc4 }, +/* 0x5cc5 */ { false, 0x5cc5, 0x5cc5 }, +/* 0x5cc6 */ { false, 0x5cc6, 0x5cc6 }, +/* 0x5cc7 */ { false, 0x5cc7, 0x5cc7 }, +/* 0x5cc8 */ { false, 0x5cc8, 0x5cc8 }, +/* 0x5cc9 */ { false, 0x5cc9, 0x5cc9 }, +/* 0x5cca */ { false, 0x5cca, 0x5cca }, +/* 0x5ccb */ { false, 0x5ccb, 0x5ccb }, +/* 0x5ccc */ { false, 0x5ccc, 0x5ccc }, +/* 0x5ccd */ { false, 0x5ccd, 0x5ccd }, +/* 0x5cce */ { false, 0x5cce, 0x5cce }, +/* 0x5ccf */ { false, 0x5ccf, 0x5ccf }, +/* 0x5cd0 */ { false, 0x5cd0, 0x5cd0 }, +/* 0x5cd1 */ { false, 0x5cd1, 0x5cd1 }, +/* 0x5cd2 */ { false, 0x5cd2, 0x5cd2 }, +/* 0x5cd3 */ { false, 0x5cd3, 0x5cd3 }, +/* 0x5cd4 */ { false, 0x5cd4, 0x5cd4 }, +/* 0x5cd5 */ { false, 0x5cd5, 0x5cd5 }, +/* 0x5cd6 */ { false, 0x5cd6, 0x5cd6 }, +/* 0x5cd7 */ { false, 0x5cd7, 0x5cd7 }, +/* 0x5cd8 */ { false, 0x5cd8, 0x5cd8 }, +/* 0x5cd9 */ { false, 0x5cd9, 0x5cd9 }, +/* 0x5cda */ { false, 0x5cda, 0x5cda }, +/* 0x5cdb */ { false, 0x5cdb, 0x5cdb }, +/* 0x5cdc */ { false, 0x5cdc, 0x5cdc }, +/* 0x5cdd */ { false, 0x5cdd, 0x5cdd }, +/* 0x5cde */ { false, 0x5cde, 0x5cde }, +/* 0x5cdf */ { false, 0x5cdf, 0x5cdf }, +/* 0x5ce0 */ { false, 0x5ce0, 0x5ce0 }, +/* 0x5ce1 */ { false, 0x5ce1, 0x5ce1 }, +/* 0x5ce2 */ { false, 0x5ce2, 0x5ce2 }, +/* 0x5ce3 */ { false, 0x5ce3, 0x5ce3 }, +/* 0x5ce4 */ { false, 0x5ce4, 0x5ce4 }, +/* 0x5ce5 */ { false, 0x5ce5, 0x5ce5 }, +/* 0x5ce6 */ { false, 0x5ce6, 0x5ce6 }, +/* 0x5ce7 */ { false, 0x5ce7, 0x5ce7 }, +/* 0x5ce8 */ { false, 0x5ce8, 0x5ce8 }, +/* 0x5ce9 */ { false, 0x5ce9, 0x5ce9 }, +/* 0x5cea */ { false, 0x5cea, 0x5cea }, +/* 0x5ceb */ { false, 0x5ceb, 0x5ceb }, +/* 0x5cec */ { false, 0x5cec, 0x5cec }, +/* 0x5ced */ { false, 0x5ced, 0x5ced }, +/* 0x5cee */ { false, 0x5cee, 0x5cee }, +/* 0x5cef */ { false, 0x5cef, 0x5cef }, +/* 0x5cf0 */ { false, 0x5cf0, 0x5cf0 }, +/* 0x5cf1 */ { false, 0x5cf1, 0x5cf1 }, +/* 0x5cf2 */ { false, 0x5cf2, 0x5cf2 }, +/* 0x5cf3 */ { false, 0x5cf3, 0x5cf3 }, +/* 0x5cf4 */ { false, 0x5cf4, 0x5cf4 }, +/* 0x5cf5 */ { false, 0x5cf5, 0x5cf5 }, +/* 0x5cf6 */ { false, 0x5cf6, 0x5cf6 }, +/* 0x5cf7 */ { false, 0x5cf7, 0x5cf7 }, +/* 0x5cf8 */ { false, 0x5cf8, 0x5cf8 }, +/* 0x5cf9 */ { false, 0x5cf9, 0x5cf9 }, +/* 0x5cfa */ { false, 0x5cfa, 0x5cfa }, +/* 0x5cfb */ { false, 0x5cfb, 0x5cfb }, +/* 0x5cfc */ { false, 0x5cfc, 0x5cfc }, +/* 0x5cfd */ { false, 0x5cfd, 0x5cfd }, +/* 0x5cfe */ { false, 0x5cfe, 0x5cfe }, +/* 0x5cff */ { false, 0x5cff, 0x5cff }, +/* 0x5d00 */ { false, 0x5d00, 0x5d00 }, +/* 0x5d01 */ { false, 0x5d01, 0x5d01 }, +/* 0x5d02 */ { false, 0x5d02, 0x5d02 }, +/* 0x5d03 */ { false, 0x5d03, 0x5d03 }, +/* 0x5d04 */ { false, 0x5d04, 0x5d04 }, +/* 0x5d05 */ { false, 0x5d05, 0x5d05 }, +/* 0x5d06 */ { false, 0x5d06, 0x5d06 }, +/* 0x5d07 */ { false, 0x5d07, 0x5d07 }, +/* 0x5d08 */ { false, 0x5d08, 0x5d08 }, +/* 0x5d09 */ { false, 0x5d09, 0x5d09 }, +/* 0x5d0a */ { false, 0x5d0a, 0x5d0a }, +/* 0x5d0b */ { false, 0x5d0b, 0x5d0b }, +/* 0x5d0c */ { false, 0x5d0c, 0x5d0c }, +/* 0x5d0d */ { false, 0x5d0d, 0x5d0d }, +/* 0x5d0e */ { false, 0x5d0e, 0x5d0e }, +/* 0x5d0f */ { false, 0x5d0f, 0x5d0f }, +/* 0x5d10 */ { false, 0x5d10, 0x5d10 }, +/* 0x5d11 */ { false, 0x5d11, 0x5d11 }, +/* 0x5d12 */ { false, 0x5d12, 0x5d12 }, +/* 0x5d13 */ { false, 0x5d13, 0x5d13 }, +/* 0x5d14 */ { false, 0x5d14, 0x5d14 }, +/* 0x5d15 */ { false, 0x5d15, 0x5d15 }, +/* 0x5d16 */ { false, 0x5d16, 0x5d16 }, +/* 0x5d17 */ { false, 0x5d17, 0x5d17 }, +/* 0x5d18 */ { false, 0x5d18, 0x5d18 }, +/* 0x5d19 */ { false, 0x5d19, 0x5d19 }, +/* 0x5d1a */ { false, 0x5d1a, 0x5d1a }, +/* 0x5d1b */ { false, 0x5d1b, 0x5d1b }, +/* 0x5d1c */ { false, 0x5d1c, 0x5d1c }, +/* 0x5d1d */ { false, 0x5d1d, 0x5d1d }, +/* 0x5d1e */ { false, 0x5d1e, 0x5d1e }, +/* 0x5d1f */ { false, 0x5d1f, 0x5d1f }, +/* 0x5d20 */ { false, 0x5d20, 0x5d20 }, +/* 0x5d21 */ { false, 0x5d21, 0x5d21 }, +/* 0x5d22 */ { false, 0x5d22, 0x5d22 }, +/* 0x5d23 */ { false, 0x5d23, 0x5d23 }, +/* 0x5d24 */ { false, 0x5d24, 0x5d24 }, +/* 0x5d25 */ { false, 0x5d25, 0x5d25 }, +/* 0x5d26 */ { false, 0x5d26, 0x5d26 }, +/* 0x5d27 */ { false, 0x5d27, 0x5d27 }, +/* 0x5d28 */ { false, 0x5d28, 0x5d28 }, +/* 0x5d29 */ { false, 0x5d29, 0x5d29 }, +/* 0x5d2a */ { false, 0x5d2a, 0x5d2a }, +/* 0x5d2b */ { false, 0x5d2b, 0x5d2b }, +/* 0x5d2c */ { false, 0x5d2c, 0x5d2c }, +/* 0x5d2d */ { false, 0x5d2d, 0x5d2d }, +/* 0x5d2e */ { false, 0x5d2e, 0x5d2e }, +/* 0x5d2f */ { false, 0x5d2f, 0x5d2f }, +/* 0x5d30 */ { false, 0x5d30, 0x5d30 }, +/* 0x5d31 */ { false, 0x5d31, 0x5d31 }, +/* 0x5d32 */ { false, 0x5d32, 0x5d32 }, +/* 0x5d33 */ { false, 0x5d33, 0x5d33 }, +/* 0x5d34 */ { false, 0x5d34, 0x5d34 }, +/* 0x5d35 */ { false, 0x5d35, 0x5d35 }, +/* 0x5d36 */ { false, 0x5d36, 0x5d36 }, +/* 0x5d37 */ { false, 0x5d37, 0x5d37 }, +/* 0x5d38 */ { false, 0x5d38, 0x5d38 }, +/* 0x5d39 */ { false, 0x5d39, 0x5d39 }, +/* 0x5d3a */ { false, 0x5d3a, 0x5d3a }, +/* 0x5d3b */ { false, 0x5d3b, 0x5d3b }, +/* 0x5d3c */ { false, 0x5d3c, 0x5d3c }, +/* 0x5d3d */ { false, 0x5d3d, 0x5d3d }, +/* 0x5d3e */ { false, 0x5d3e, 0x5d3e }, +/* 0x5d3f */ { false, 0x5d3f, 0x5d3f }, +/* 0x5d40 */ { false, 0x5d40, 0x5d40 }, +/* 0x5d41 */ { false, 0x5d41, 0x5d41 }, +/* 0x5d42 */ { false, 0x5d42, 0x5d42 }, +/* 0x5d43 */ { false, 0x5d43, 0x5d43 }, +/* 0x5d44 */ { false, 0x5d44, 0x5d44 }, +/* 0x5d45 */ { false, 0x5d45, 0x5d45 }, +/* 0x5d46 */ { false, 0x5d46, 0x5d46 }, +/* 0x5d47 */ { false, 0x5d47, 0x5d47 }, +/* 0x5d48 */ { false, 0x5d48, 0x5d48 }, +/* 0x5d49 */ { false, 0x5d49, 0x5d49 }, +/* 0x5d4a */ { false, 0x5d4a, 0x5d4a }, +/* 0x5d4b */ { false, 0x5d4b, 0x5d4b }, +/* 0x5d4c */ { false, 0x5d4c, 0x5d4c }, +/* 0x5d4d */ { false, 0x5d4d, 0x5d4d }, +/* 0x5d4e */ { false, 0x5d4e, 0x5d4e }, +/* 0x5d4f */ { false, 0x5d4f, 0x5d4f }, +/* 0x5d50 */ { false, 0x5d50, 0x5d50 }, +/* 0x5d51 */ { false, 0x5d51, 0x5d51 }, +/* 0x5d52 */ { false, 0x5d52, 0x5d52 }, +/* 0x5d53 */ { false, 0x5d53, 0x5d53 }, +/* 0x5d54 */ { false, 0x5d54, 0x5d54 }, +/* 0x5d55 */ { false, 0x5d55, 0x5d55 }, +/* 0x5d56 */ { false, 0x5d56, 0x5d56 }, +/* 0x5d57 */ { false, 0x5d57, 0x5d57 }, +/* 0x5d58 */ { false, 0x5d58, 0x5d58 }, +/* 0x5d59 */ { false, 0x5d59, 0x5d59 }, +/* 0x5d5a */ { false, 0x5d5a, 0x5d5a }, +/* 0x5d5b */ { false, 0x5d5b, 0x5d5b }, +/* 0x5d5c */ { false, 0x5d5c, 0x5d5c }, +/* 0x5d5d */ { false, 0x5d5d, 0x5d5d }, +/* 0x5d5e */ { false, 0x5d5e, 0x5d5e }, +/* 0x5d5f */ { false, 0x5d5f, 0x5d5f }, +/* 0x5d60 */ { false, 0x5d60, 0x5d60 }, +/* 0x5d61 */ { false, 0x5d61, 0x5d61 }, +/* 0x5d62 */ { false, 0x5d62, 0x5d62 }, +/* 0x5d63 */ { false, 0x5d63, 0x5d63 }, +/* 0x5d64 */ { false, 0x5d64, 0x5d64 }, +/* 0x5d65 */ { false, 0x5d65, 0x5d65 }, +/* 0x5d66 */ { false, 0x5d66, 0x5d66 }, +/* 0x5d67 */ { false, 0x5d67, 0x5d67 }, +/* 0x5d68 */ { false, 0x5d68, 0x5d68 }, +/* 0x5d69 */ { false, 0x5d69, 0x5d69 }, +/* 0x5d6a */ { false, 0x5d6a, 0x5d6a }, +/* 0x5d6b */ { false, 0x5d6b, 0x5d6b }, +/* 0x5d6c */ { false, 0x5d6c, 0x5d6c }, +/* 0x5d6d */ { false, 0x5d6d, 0x5d6d }, +/* 0x5d6e */ { false, 0x5d6e, 0x5d6e }, +/* 0x5d6f */ { false, 0x5d6f, 0x5d6f }, +/* 0x5d70 */ { false, 0x5d70, 0x5d70 }, +/* 0x5d71 */ { false, 0x5d71, 0x5d71 }, +/* 0x5d72 */ { false, 0x5d72, 0x5d72 }, +/* 0x5d73 */ { false, 0x5d73, 0x5d73 }, +/* 0x5d74 */ { false, 0x5d74, 0x5d74 }, +/* 0x5d75 */ { false, 0x5d75, 0x5d75 }, +/* 0x5d76 */ { false, 0x5d76, 0x5d76 }, +/* 0x5d77 */ { false, 0x5d77, 0x5d77 }, +/* 0x5d78 */ { false, 0x5d78, 0x5d78 }, +/* 0x5d79 */ { false, 0x5d79, 0x5d79 }, +/* 0x5d7a */ { false, 0x5d7a, 0x5d7a }, +/* 0x5d7b */ { false, 0x5d7b, 0x5d7b }, +/* 0x5d7c */ { false, 0x5d7c, 0x5d7c }, +/* 0x5d7d */ { false, 0x5d7d, 0x5d7d }, +/* 0x5d7e */ { false, 0x5d7e, 0x5d7e }, +/* 0x5d7f */ { false, 0x5d7f, 0x5d7f }, +/* 0x5d80 */ { false, 0x5d80, 0x5d80 }, +/* 0x5d81 */ { false, 0x5d81, 0x5d81 }, +/* 0x5d82 */ { false, 0x5d82, 0x5d82 }, +/* 0x5d83 */ { false, 0x5d83, 0x5d83 }, +/* 0x5d84 */ { false, 0x5d84, 0x5d84 }, +/* 0x5d85 */ { false, 0x5d85, 0x5d85 }, +/* 0x5d86 */ { false, 0x5d86, 0x5d86 }, +/* 0x5d87 */ { false, 0x5d87, 0x5d87 }, +/* 0x5d88 */ { false, 0x5d88, 0x5d88 }, +/* 0x5d89 */ { false, 0x5d89, 0x5d89 }, +/* 0x5d8a */ { false, 0x5d8a, 0x5d8a }, +/* 0x5d8b */ { false, 0x5d8b, 0x5d8b }, +/* 0x5d8c */ { false, 0x5d8c, 0x5d8c }, +/* 0x5d8d */ { false, 0x5d8d, 0x5d8d }, +/* 0x5d8e */ { false, 0x5d8e, 0x5d8e }, +/* 0x5d8f */ { false, 0x5d8f, 0x5d8f }, +/* 0x5d90 */ { false, 0x5d90, 0x5d90 }, +/* 0x5d91 */ { false, 0x5d91, 0x5d91 }, +/* 0x5d92 */ { false, 0x5d92, 0x5d92 }, +/* 0x5d93 */ { false, 0x5d93, 0x5d93 }, +/* 0x5d94 */ { false, 0x5d94, 0x5d94 }, +/* 0x5d95 */ { false, 0x5d95, 0x5d95 }, +/* 0x5d96 */ { false, 0x5d96, 0x5d96 }, +/* 0x5d97 */ { false, 0x5d97, 0x5d97 }, +/* 0x5d98 */ { false, 0x5d98, 0x5d98 }, +/* 0x5d99 */ { false, 0x5d99, 0x5d99 }, +/* 0x5d9a */ { false, 0x5d9a, 0x5d9a }, +/* 0x5d9b */ { false, 0x5d9b, 0x5d9b }, +/* 0x5d9c */ { false, 0x5d9c, 0x5d9c }, +/* 0x5d9d */ { false, 0x5d9d, 0x5d9d }, +/* 0x5d9e */ { false, 0x5d9e, 0x5d9e }, +/* 0x5d9f */ { false, 0x5d9f, 0x5d9f }, +/* 0x5da0 */ { false, 0x5da0, 0x5da0 }, +/* 0x5da1 */ { false, 0x5da1, 0x5da1 }, +/* 0x5da2 */ { false, 0x5da2, 0x5da2 }, +/* 0x5da3 */ { false, 0x5da3, 0x5da3 }, +/* 0x5da4 */ { false, 0x5da4, 0x5da4 }, +/* 0x5da5 */ { false, 0x5da5, 0x5da5 }, +/* 0x5da6 */ { false, 0x5da6, 0x5da6 }, +/* 0x5da7 */ { false, 0x5da7, 0x5da7 }, +/* 0x5da8 */ { false, 0x5da8, 0x5da8 }, +/* 0x5da9 */ { false, 0x5da9, 0x5da9 }, +/* 0x5daa */ { false, 0x5daa, 0x5daa }, +/* 0x5dab */ { false, 0x5dab, 0x5dab }, +/* 0x5dac */ { false, 0x5dac, 0x5dac }, +/* 0x5dad */ { false, 0x5dad, 0x5dad }, +/* 0x5dae */ { false, 0x5dae, 0x5dae }, +/* 0x5daf */ { false, 0x5daf, 0x5daf }, +/* 0x5db0 */ { false, 0x5db0, 0x5db0 }, +/* 0x5db1 */ { false, 0x5db1, 0x5db1 }, +/* 0x5db2 */ { false, 0x5db2, 0x5db2 }, +/* 0x5db3 */ { false, 0x5db3, 0x5db3 }, +/* 0x5db4 */ { false, 0x5db4, 0x5db4 }, +/* 0x5db5 */ { false, 0x5db5, 0x5db5 }, +/* 0x5db6 */ { false, 0x5db6, 0x5db6 }, +/* 0x5db7 */ { false, 0x5db7, 0x5db7 }, +/* 0x5db8 */ { false, 0x5db8, 0x5db8 }, +/* 0x5db9 */ { false, 0x5db9, 0x5db9 }, +/* 0x5dba */ { false, 0x5dba, 0x5dba }, +/* 0x5dbb */ { false, 0x5dbb, 0x5dbb }, +/* 0x5dbc */ { false, 0x5dbc, 0x5dbc }, +/* 0x5dbd */ { false, 0x5dbd, 0x5dbd }, +/* 0x5dbe */ { false, 0x5dbe, 0x5dbe }, +/* 0x5dbf */ { false, 0x5dbf, 0x5dbf }, +/* 0x5dc0 */ { false, 0x5dc0, 0x5dc0 }, +/* 0x5dc1 */ { false, 0x5dc1, 0x5dc1 }, +/* 0x5dc2 */ { false, 0x5dc2, 0x5dc2 }, +/* 0x5dc3 */ { false, 0x5dc3, 0x5dc3 }, +/* 0x5dc4 */ { false, 0x5dc4, 0x5dc4 }, +/* 0x5dc5 */ { false, 0x5dc5, 0x5dc5 }, +/* 0x5dc6 */ { false, 0x5dc6, 0x5dc6 }, +/* 0x5dc7 */ { false, 0x5dc7, 0x5dc7 }, +/* 0x5dc8 */ { false, 0x5dc8, 0x5dc8 }, +/* 0x5dc9 */ { false, 0x5dc9, 0x5dc9 }, +/* 0x5dca */ { false, 0x5dca, 0x5dca }, +/* 0x5dcb */ { false, 0x5dcb, 0x5dcb }, +/* 0x5dcc */ { false, 0x5dcc, 0x5dcc }, +/* 0x5dcd */ { false, 0x5dcd, 0x5dcd }, +/* 0x5dce */ { false, 0x5dce, 0x5dce }, +/* 0x5dcf */ { false, 0x5dcf, 0x5dcf }, +/* 0x5dd0 */ { false, 0x5dd0, 0x5dd0 }, +/* 0x5dd1 */ { false, 0x5dd1, 0x5dd1 }, +/* 0x5dd2 */ { false, 0x5dd2, 0x5dd2 }, +/* 0x5dd3 */ { false, 0x5dd3, 0x5dd3 }, +/* 0x5dd4 */ { false, 0x5dd4, 0x5dd4 }, +/* 0x5dd5 */ { false, 0x5dd5, 0x5dd5 }, +/* 0x5dd6 */ { false, 0x5dd6, 0x5dd6 }, +/* 0x5dd7 */ { false, 0x5dd7, 0x5dd7 }, +/* 0x5dd8 */ { false, 0x5dd8, 0x5dd8 }, +/* 0x5dd9 */ { false, 0x5dd9, 0x5dd9 }, +/* 0x5dda */ { false, 0x5dda, 0x5dda }, +/* 0x5ddb */ { false, 0x5ddb, 0x5ddb }, +/* 0x5ddc */ { false, 0x5ddc, 0x5ddc }, +/* 0x5ddd */ { false, 0x5ddd, 0x5ddd }, +/* 0x5dde */ { false, 0x5dde, 0x5dde }, +/* 0x5ddf */ { false, 0x5ddf, 0x5ddf }, +/* 0x5de0 */ { false, 0x5de0, 0x5de0 }, +/* 0x5de1 */ { false, 0x5de1, 0x5de1 }, +/* 0x5de2 */ { false, 0x5de2, 0x5de2 }, +/* 0x5de3 */ { false, 0x5de3, 0x5de3 }, +/* 0x5de4 */ { false, 0x5de4, 0x5de4 }, +/* 0x5de5 */ { false, 0x5de5, 0x5de5 }, +/* 0x5de6 */ { false, 0x5de6, 0x5de6 }, +/* 0x5de7 */ { false, 0x5de7, 0x5de7 }, +/* 0x5de8 */ { false, 0x5de8, 0x5de8 }, +/* 0x5de9 */ { false, 0x5de9, 0x5de9 }, +/* 0x5dea */ { false, 0x5dea, 0x5dea }, +/* 0x5deb */ { false, 0x5deb, 0x5deb }, +/* 0x5dec */ { false, 0x5dec, 0x5dec }, +/* 0x5ded */ { false, 0x5ded, 0x5ded }, +/* 0x5dee */ { false, 0x5dee, 0x5dee }, +/* 0x5def */ { false, 0x5def, 0x5def }, +/* 0x5df0 */ { false, 0x5df0, 0x5df0 }, +/* 0x5df1 */ { false, 0x5df1, 0x5df1 }, +/* 0x5df2 */ { false, 0x5df2, 0x5df2 }, +/* 0x5df3 */ { false, 0x5df3, 0x5df3 }, +/* 0x5df4 */ { false, 0x5df4, 0x5df4 }, +/* 0x5df5 */ { false, 0x5df5, 0x5df5 }, +/* 0x5df6 */ { false, 0x5df6, 0x5df6 }, +/* 0x5df7 */ { false, 0x5df7, 0x5df7 }, +/* 0x5df8 */ { false, 0x5df8, 0x5df8 }, +/* 0x5df9 */ { false, 0x5df9, 0x5df9 }, +/* 0x5dfa */ { false, 0x5dfa, 0x5dfa }, +/* 0x5dfb */ { false, 0x5dfb, 0x5dfb }, +/* 0x5dfc */ { false, 0x5dfc, 0x5dfc }, +/* 0x5dfd */ { false, 0x5dfd, 0x5dfd }, +/* 0x5dfe */ { false, 0x5dfe, 0x5dfe }, +/* 0x5dff */ { false, 0x5dff, 0x5dff }, +/* 0x5e00 */ { false, 0x5e00, 0x5e00 }, +/* 0x5e01 */ { false, 0x5e01, 0x5e01 }, +/* 0x5e02 */ { false, 0x5e02, 0x5e02 }, +/* 0x5e03 */ { false, 0x5e03, 0x5e03 }, +/* 0x5e04 */ { false, 0x5e04, 0x5e04 }, +/* 0x5e05 */ { false, 0x5e05, 0x5e05 }, +/* 0x5e06 */ { false, 0x5e06, 0x5e06 }, +/* 0x5e07 */ { false, 0x5e07, 0x5e07 }, +/* 0x5e08 */ { false, 0x5e08, 0x5e08 }, +/* 0x5e09 */ { false, 0x5e09, 0x5e09 }, +/* 0x5e0a */ { false, 0x5e0a, 0x5e0a }, +/* 0x5e0b */ { false, 0x5e0b, 0x5e0b }, +/* 0x5e0c */ { false, 0x5e0c, 0x5e0c }, +/* 0x5e0d */ { false, 0x5e0d, 0x5e0d }, +/* 0x5e0e */ { false, 0x5e0e, 0x5e0e }, +/* 0x5e0f */ { false, 0x5e0f, 0x5e0f }, +/* 0x5e10 */ { false, 0x5e10, 0x5e10 }, +/* 0x5e11 */ { false, 0x5e11, 0x5e11 }, +/* 0x5e12 */ { false, 0x5e12, 0x5e12 }, +/* 0x5e13 */ { false, 0x5e13, 0x5e13 }, +/* 0x5e14 */ { false, 0x5e14, 0x5e14 }, +/* 0x5e15 */ { false, 0x5e15, 0x5e15 }, +/* 0x5e16 */ { false, 0x5e16, 0x5e16 }, +/* 0x5e17 */ { false, 0x5e17, 0x5e17 }, +/* 0x5e18 */ { false, 0x5e18, 0x5e18 }, +/* 0x5e19 */ { false, 0x5e19, 0x5e19 }, +/* 0x5e1a */ { false, 0x5e1a, 0x5e1a }, +/* 0x5e1b */ { false, 0x5e1b, 0x5e1b }, +/* 0x5e1c */ { false, 0x5e1c, 0x5e1c }, +/* 0x5e1d */ { false, 0x5e1d, 0x5e1d }, +/* 0x5e1e */ { false, 0x5e1e, 0x5e1e }, +/* 0x5e1f */ { false, 0x5e1f, 0x5e1f }, +/* 0x5e20 */ { false, 0x5e20, 0x5e20 }, +/* 0x5e21 */ { false, 0x5e21, 0x5e21 }, +/* 0x5e22 */ { false, 0x5e22, 0x5e22 }, +/* 0x5e23 */ { false, 0x5e23, 0x5e23 }, +/* 0x5e24 */ { false, 0x5e24, 0x5e24 }, +/* 0x5e25 */ { false, 0x5e25, 0x5e25 }, +/* 0x5e26 */ { false, 0x5e26, 0x5e26 }, +/* 0x5e27 */ { false, 0x5e27, 0x5e27 }, +/* 0x5e28 */ { false, 0x5e28, 0x5e28 }, +/* 0x5e29 */ { false, 0x5e29, 0x5e29 }, +/* 0x5e2a */ { false, 0x5e2a, 0x5e2a }, +/* 0x5e2b */ { false, 0x5e2b, 0x5e2b }, +/* 0x5e2c */ { false, 0x5e2c, 0x5e2c }, +/* 0x5e2d */ { false, 0x5e2d, 0x5e2d }, +/* 0x5e2e */ { false, 0x5e2e, 0x5e2e }, +/* 0x5e2f */ { false, 0x5e2f, 0x5e2f }, +/* 0x5e30 */ { false, 0x5e30, 0x5e30 }, +/* 0x5e31 */ { false, 0x5e31, 0x5e31 }, +/* 0x5e32 */ { false, 0x5e32, 0x5e32 }, +/* 0x5e33 */ { false, 0x5e33, 0x5e33 }, +/* 0x5e34 */ { false, 0x5e34, 0x5e34 }, +/* 0x5e35 */ { false, 0x5e35, 0x5e35 }, +/* 0x5e36 */ { false, 0x5e36, 0x5e36 }, +/* 0x5e37 */ { false, 0x5e37, 0x5e37 }, +/* 0x5e38 */ { false, 0x5e38, 0x5e38 }, +/* 0x5e39 */ { false, 0x5e39, 0x5e39 }, +/* 0x5e3a */ { false, 0x5e3a, 0x5e3a }, +/* 0x5e3b */ { false, 0x5e3b, 0x5e3b }, +/* 0x5e3c */ { false, 0x5e3c, 0x5e3c }, +/* 0x5e3d */ { false, 0x5e3d, 0x5e3d }, +/* 0x5e3e */ { false, 0x5e3e, 0x5e3e }, +/* 0x5e3f */ { false, 0x5e3f, 0x5e3f }, +/* 0x5e40 */ { false, 0x5e40, 0x5e40 }, +/* 0x5e41 */ { false, 0x5e41, 0x5e41 }, +/* 0x5e42 */ { false, 0x5e42, 0x5e42 }, +/* 0x5e43 */ { false, 0x5e43, 0x5e43 }, +/* 0x5e44 */ { false, 0x5e44, 0x5e44 }, +/* 0x5e45 */ { false, 0x5e45, 0x5e45 }, +/* 0x5e46 */ { false, 0x5e46, 0x5e46 }, +/* 0x5e47 */ { false, 0x5e47, 0x5e47 }, +/* 0x5e48 */ { false, 0x5e48, 0x5e48 }, +/* 0x5e49 */ { false, 0x5e49, 0x5e49 }, +/* 0x5e4a */ { false, 0x5e4a, 0x5e4a }, +/* 0x5e4b */ { false, 0x5e4b, 0x5e4b }, +/* 0x5e4c */ { false, 0x5e4c, 0x5e4c }, +/* 0x5e4d */ { false, 0x5e4d, 0x5e4d }, +/* 0x5e4e */ { false, 0x5e4e, 0x5e4e }, +/* 0x5e4f */ { false, 0x5e4f, 0x5e4f }, +/* 0x5e50 */ { false, 0x5e50, 0x5e50 }, +/* 0x5e51 */ { false, 0x5e51, 0x5e51 }, +/* 0x5e52 */ { false, 0x5e52, 0x5e52 }, +/* 0x5e53 */ { false, 0x5e53, 0x5e53 }, +/* 0x5e54 */ { false, 0x5e54, 0x5e54 }, +/* 0x5e55 */ { false, 0x5e55, 0x5e55 }, +/* 0x5e56 */ { false, 0x5e56, 0x5e56 }, +/* 0x5e57 */ { false, 0x5e57, 0x5e57 }, +/* 0x5e58 */ { false, 0x5e58, 0x5e58 }, +/* 0x5e59 */ { false, 0x5e59, 0x5e59 }, +/* 0x5e5a */ { false, 0x5e5a, 0x5e5a }, +/* 0x5e5b */ { false, 0x5e5b, 0x5e5b }, +/* 0x5e5c */ { false, 0x5e5c, 0x5e5c }, +/* 0x5e5d */ { false, 0x5e5d, 0x5e5d }, +/* 0x5e5e */ { false, 0x5e5e, 0x5e5e }, +/* 0x5e5f */ { false, 0x5e5f, 0x5e5f }, +/* 0x5e60 */ { false, 0x5e60, 0x5e60 }, +/* 0x5e61 */ { false, 0x5e61, 0x5e61 }, +/* 0x5e62 */ { false, 0x5e62, 0x5e62 }, +/* 0x5e63 */ { false, 0x5e63, 0x5e63 }, +/* 0x5e64 */ { false, 0x5e64, 0x5e64 }, +/* 0x5e65 */ { false, 0x5e65, 0x5e65 }, +/* 0x5e66 */ { false, 0x5e66, 0x5e66 }, +/* 0x5e67 */ { false, 0x5e67, 0x5e67 }, +/* 0x5e68 */ { false, 0x5e68, 0x5e68 }, +/* 0x5e69 */ { false, 0x5e69, 0x5e69 }, +/* 0x5e6a */ { false, 0x5e6a, 0x5e6a }, +/* 0x5e6b */ { false, 0x5e6b, 0x5e6b }, +/* 0x5e6c */ { false, 0x5e6c, 0x5e6c }, +/* 0x5e6d */ { false, 0x5e6d, 0x5e6d }, +/* 0x5e6e */ { false, 0x5e6e, 0x5e6e }, +/* 0x5e6f */ { false, 0x5e6f, 0x5e6f }, +/* 0x5e70 */ { false, 0x5e70, 0x5e70 }, +/* 0x5e71 */ { false, 0x5e71, 0x5e71 }, +/* 0x5e72 */ { false, 0x5e72, 0x5e72 }, +/* 0x5e73 */ { false, 0x5e73, 0x5e73 }, +/* 0x5e74 */ { false, 0x5e74, 0x5e74 }, +/* 0x5e75 */ { false, 0x5e75, 0x5e75 }, +/* 0x5e76 */ { false, 0x5e76, 0x5e76 }, +/* 0x5e77 */ { false, 0x5e77, 0x5e77 }, +/* 0x5e78 */ { false, 0x5e78, 0x5e78 }, +/* 0x5e79 */ { false, 0x5e79, 0x5e79 }, +/* 0x5e7a */ { false, 0x5e7a, 0x5e7a }, +/* 0x5e7b */ { false, 0x5e7b, 0x5e7b }, +/* 0x5e7c */ { false, 0x5e7c, 0x5e7c }, +/* 0x5e7d */ { false, 0x5e7d, 0x5e7d }, +/* 0x5e7e */ { false, 0x5e7e, 0x5e7e }, +/* 0x5e7f */ { false, 0x5e7f, 0x5e7f }, +/* 0x5e80 */ { false, 0x5e80, 0x5e80 }, +/* 0x5e81 */ { false, 0x5e81, 0x5e81 }, +/* 0x5e82 */ { false, 0x5e82, 0x5e82 }, +/* 0x5e83 */ { false, 0x5e83, 0x5e83 }, +/* 0x5e84 */ { false, 0x5e84, 0x5e84 }, +/* 0x5e85 */ { false, 0x5e85, 0x5e85 }, +/* 0x5e86 */ { false, 0x5e86, 0x5e86 }, +/* 0x5e87 */ { false, 0x5e87, 0x5e87 }, +/* 0x5e88 */ { false, 0x5e88, 0x5e88 }, +/* 0x5e89 */ { false, 0x5e89, 0x5e89 }, +/* 0x5e8a */ { false, 0x5e8a, 0x5e8a }, +/* 0x5e8b */ { false, 0x5e8b, 0x5e8b }, +/* 0x5e8c */ { false, 0x5e8c, 0x5e8c }, +/* 0x5e8d */ { false, 0x5e8d, 0x5e8d }, +/* 0x5e8e */ { false, 0x5e8e, 0x5e8e }, +/* 0x5e8f */ { false, 0x5e8f, 0x5e8f }, +/* 0x5e90 */ { false, 0x5e90, 0x5e90 }, +/* 0x5e91 */ { false, 0x5e91, 0x5e91 }, +/* 0x5e92 */ { false, 0x5e92, 0x5e92 }, +/* 0x5e93 */ { false, 0x5e93, 0x5e93 }, +/* 0x5e94 */ { false, 0x5e94, 0x5e94 }, +/* 0x5e95 */ { false, 0x5e95, 0x5e95 }, +/* 0x5e96 */ { false, 0x5e96, 0x5e96 }, +/* 0x5e97 */ { false, 0x5e97, 0x5e97 }, +/* 0x5e98 */ { false, 0x5e98, 0x5e98 }, +/* 0x5e99 */ { false, 0x5e99, 0x5e99 }, +/* 0x5e9a */ { false, 0x5e9a, 0x5e9a }, +/* 0x5e9b */ { false, 0x5e9b, 0x5e9b }, +/* 0x5e9c */ { false, 0x5e9c, 0x5e9c }, +/* 0x5e9d */ { false, 0x5e9d, 0x5e9d }, +/* 0x5e9e */ { false, 0x5e9e, 0x5e9e }, +/* 0x5e9f */ { false, 0x5e9f, 0x5e9f }, +/* 0x5ea0 */ { false, 0x5ea0, 0x5ea0 }, +/* 0x5ea1 */ { false, 0x5ea1, 0x5ea1 }, +/* 0x5ea2 */ { false, 0x5ea2, 0x5ea2 }, +/* 0x5ea3 */ { false, 0x5ea3, 0x5ea3 }, +/* 0x5ea4 */ { false, 0x5ea4, 0x5ea4 }, +/* 0x5ea5 */ { false, 0x5ea5, 0x5ea5 }, +/* 0x5ea6 */ { false, 0x5ea6, 0x5ea6 }, +/* 0x5ea7 */ { false, 0x5ea7, 0x5ea7 }, +/* 0x5ea8 */ { false, 0x5ea8, 0x5ea8 }, +/* 0x5ea9 */ { false, 0x5ea9, 0x5ea9 }, +/* 0x5eaa */ { false, 0x5eaa, 0x5eaa }, +/* 0x5eab */ { false, 0x5eab, 0x5eab }, +/* 0x5eac */ { false, 0x5eac, 0x5eac }, +/* 0x5ead */ { false, 0x5ead, 0x5ead }, +/* 0x5eae */ { false, 0x5eae, 0x5eae }, +/* 0x5eaf */ { false, 0x5eaf, 0x5eaf }, +/* 0x5eb0 */ { false, 0x5eb0, 0x5eb0 }, +/* 0x5eb1 */ { false, 0x5eb1, 0x5eb1 }, +/* 0x5eb2 */ { false, 0x5eb2, 0x5eb2 }, +/* 0x5eb3 */ { false, 0x5eb3, 0x5eb3 }, +/* 0x5eb4 */ { false, 0x5eb4, 0x5eb4 }, +/* 0x5eb5 */ { false, 0x5eb5, 0x5eb5 }, +/* 0x5eb6 */ { false, 0x5eb6, 0x5eb6 }, +/* 0x5eb7 */ { false, 0x5eb7, 0x5eb7 }, +/* 0x5eb8 */ { false, 0x5eb8, 0x5eb8 }, +/* 0x5eb9 */ { false, 0x5eb9, 0x5eb9 }, +/* 0x5eba */ { false, 0x5eba, 0x5eba }, +/* 0x5ebb */ { false, 0x5ebb, 0x5ebb }, +/* 0x5ebc */ { false, 0x5ebc, 0x5ebc }, +/* 0x5ebd */ { false, 0x5ebd, 0x5ebd }, +/* 0x5ebe */ { false, 0x5ebe, 0x5ebe }, +/* 0x5ebf */ { false, 0x5ebf, 0x5ebf }, +/* 0x5ec0 */ { false, 0x5ec0, 0x5ec0 }, +/* 0x5ec1 */ { false, 0x5ec1, 0x5ec1 }, +/* 0x5ec2 */ { false, 0x5ec2, 0x5ec2 }, +/* 0x5ec3 */ { false, 0x5ec3, 0x5ec3 }, +/* 0x5ec4 */ { false, 0x5ec4, 0x5ec4 }, +/* 0x5ec5 */ { false, 0x5ec5, 0x5ec5 }, +/* 0x5ec6 */ { false, 0x5ec6, 0x5ec6 }, +/* 0x5ec7 */ { false, 0x5ec7, 0x5ec7 }, +/* 0x5ec8 */ { false, 0x5ec8, 0x5ec8 }, +/* 0x5ec9 */ { false, 0x5ec9, 0x5ec9 }, +/* 0x5eca */ { false, 0x5eca, 0x5eca }, +/* 0x5ecb */ { false, 0x5ecb, 0x5ecb }, +/* 0x5ecc */ { false, 0x5ecc, 0x5ecc }, +/* 0x5ecd */ { false, 0x5ecd, 0x5ecd }, +/* 0x5ece */ { false, 0x5ece, 0x5ece }, +/* 0x5ecf */ { false, 0x5ecf, 0x5ecf }, +/* 0x5ed0 */ { false, 0x5ed0, 0x5ed0 }, +/* 0x5ed1 */ { false, 0x5ed1, 0x5ed1 }, +/* 0x5ed2 */ { false, 0x5ed2, 0x5ed2 }, +/* 0x5ed3 */ { false, 0x5ed3, 0x5ed3 }, +/* 0x5ed4 */ { false, 0x5ed4, 0x5ed4 }, +/* 0x5ed5 */ { false, 0x5ed5, 0x5ed5 }, +/* 0x5ed6 */ { false, 0x5ed6, 0x5ed6 }, +/* 0x5ed7 */ { false, 0x5ed7, 0x5ed7 }, +/* 0x5ed8 */ { false, 0x5ed8, 0x5ed8 }, +/* 0x5ed9 */ { false, 0x5ed9, 0x5ed9 }, +/* 0x5eda */ { false, 0x5eda, 0x5eda }, +/* 0x5edb */ { false, 0x5edb, 0x5edb }, +/* 0x5edc */ { false, 0x5edc, 0x5edc }, +/* 0x5edd */ { false, 0x5edd, 0x5edd }, +/* 0x5ede */ { false, 0x5ede, 0x5ede }, +/* 0x5edf */ { false, 0x5edf, 0x5edf }, +/* 0x5ee0 */ { false, 0x5ee0, 0x5ee0 }, +/* 0x5ee1 */ { false, 0x5ee1, 0x5ee1 }, +/* 0x5ee2 */ { false, 0x5ee2, 0x5ee2 }, +/* 0x5ee3 */ { false, 0x5ee3, 0x5ee3 }, +/* 0x5ee4 */ { false, 0x5ee4, 0x5ee4 }, +/* 0x5ee5 */ { false, 0x5ee5, 0x5ee5 }, +/* 0x5ee6 */ { false, 0x5ee6, 0x5ee6 }, +/* 0x5ee7 */ { false, 0x5ee7, 0x5ee7 }, +/* 0x5ee8 */ { false, 0x5ee8, 0x5ee8 }, +/* 0x5ee9 */ { false, 0x5ee9, 0x5ee9 }, +/* 0x5eea */ { false, 0x5eea, 0x5eea }, +/* 0x5eeb */ { false, 0x5eeb, 0x5eeb }, +/* 0x5eec */ { false, 0x5eec, 0x5eec }, +/* 0x5eed */ { false, 0x5eed, 0x5eed }, +/* 0x5eee */ { false, 0x5eee, 0x5eee }, +/* 0x5eef */ { false, 0x5eef, 0x5eef }, +/* 0x5ef0 */ { false, 0x5ef0, 0x5ef0 }, +/* 0x5ef1 */ { false, 0x5ef1, 0x5ef1 }, +/* 0x5ef2 */ { false, 0x5ef2, 0x5ef2 }, +/* 0x5ef3 */ { false, 0x5ef3, 0x5ef3 }, +/* 0x5ef4 */ { false, 0x5ef4, 0x5ef4 }, +/* 0x5ef5 */ { false, 0x5ef5, 0x5ef5 }, +/* 0x5ef6 */ { false, 0x5ef6, 0x5ef6 }, +/* 0x5ef7 */ { false, 0x5ef7, 0x5ef7 }, +/* 0x5ef8 */ { false, 0x5ef8, 0x5ef8 }, +/* 0x5ef9 */ { false, 0x5ef9, 0x5ef9 }, +/* 0x5efa */ { false, 0x5efa, 0x5efa }, +/* 0x5efb */ { false, 0x5efb, 0x5efb }, +/* 0x5efc */ { false, 0x5efc, 0x5efc }, +/* 0x5efd */ { false, 0x5efd, 0x5efd }, +/* 0x5efe */ { false, 0x5efe, 0x5efe }, +/* 0x5eff */ { false, 0x5eff, 0x5eff }, +/* 0x5f00 */ { false, 0x5f00, 0x5f00 }, +/* 0x5f01 */ { false, 0x5f01, 0x5f01 }, +/* 0x5f02 */ { false, 0x5f02, 0x5f02 }, +/* 0x5f03 */ { false, 0x5f03, 0x5f03 }, +/* 0x5f04 */ { false, 0x5f04, 0x5f04 }, +/* 0x5f05 */ { false, 0x5f05, 0x5f05 }, +/* 0x5f06 */ { false, 0x5f06, 0x5f06 }, +/* 0x5f07 */ { false, 0x5f07, 0x5f07 }, +/* 0x5f08 */ { false, 0x5f08, 0x5f08 }, +/* 0x5f09 */ { false, 0x5f09, 0x5f09 }, +/* 0x5f0a */ { false, 0x5f0a, 0x5f0a }, +/* 0x5f0b */ { false, 0x5f0b, 0x5f0b }, +/* 0x5f0c */ { false, 0x5f0c, 0x5f0c }, +/* 0x5f0d */ { false, 0x5f0d, 0x5f0d }, +/* 0x5f0e */ { false, 0x5f0e, 0x5f0e }, +/* 0x5f0f */ { false, 0x5f0f, 0x5f0f }, +/* 0x5f10 */ { false, 0x5f10, 0x5f10 }, +/* 0x5f11 */ { false, 0x5f11, 0x5f11 }, +/* 0x5f12 */ { false, 0x5f12, 0x5f12 }, +/* 0x5f13 */ { false, 0x5f13, 0x5f13 }, +/* 0x5f14 */ { false, 0x5f14, 0x5f14 }, +/* 0x5f15 */ { false, 0x5f15, 0x5f15 }, +/* 0x5f16 */ { false, 0x5f16, 0x5f16 }, +/* 0x5f17 */ { false, 0x5f17, 0x5f17 }, +/* 0x5f18 */ { false, 0x5f18, 0x5f18 }, +/* 0x5f19 */ { false, 0x5f19, 0x5f19 }, +/* 0x5f1a */ { false, 0x5f1a, 0x5f1a }, +/* 0x5f1b */ { false, 0x5f1b, 0x5f1b }, +/* 0x5f1c */ { false, 0x5f1c, 0x5f1c }, +/* 0x5f1d */ { false, 0x5f1d, 0x5f1d }, +/* 0x5f1e */ { false, 0x5f1e, 0x5f1e }, +/* 0x5f1f */ { false, 0x5f1f, 0x5f1f }, +/* 0x5f20 */ { false, 0x5f20, 0x5f20 }, +/* 0x5f21 */ { false, 0x5f21, 0x5f21 }, +/* 0x5f22 */ { false, 0x5f22, 0x5f22 }, +/* 0x5f23 */ { false, 0x5f23, 0x5f23 }, +/* 0x5f24 */ { false, 0x5f24, 0x5f24 }, +/* 0x5f25 */ { false, 0x5f25, 0x5f25 }, +/* 0x5f26 */ { false, 0x5f26, 0x5f26 }, +/* 0x5f27 */ { false, 0x5f27, 0x5f27 }, +/* 0x5f28 */ { false, 0x5f28, 0x5f28 }, +/* 0x5f29 */ { false, 0x5f29, 0x5f29 }, +/* 0x5f2a */ { false, 0x5f2a, 0x5f2a }, +/* 0x5f2b */ { false, 0x5f2b, 0x5f2b }, +/* 0x5f2c */ { false, 0x5f2c, 0x5f2c }, +/* 0x5f2d */ { false, 0x5f2d, 0x5f2d }, +/* 0x5f2e */ { false, 0x5f2e, 0x5f2e }, +/* 0x5f2f */ { false, 0x5f2f, 0x5f2f }, +/* 0x5f30 */ { false, 0x5f30, 0x5f30 }, +/* 0x5f31 */ { false, 0x5f31, 0x5f31 }, +/* 0x5f32 */ { false, 0x5f32, 0x5f32 }, +/* 0x5f33 */ { false, 0x5f33, 0x5f33 }, +/* 0x5f34 */ { false, 0x5f34, 0x5f34 }, +/* 0x5f35 */ { false, 0x5f35, 0x5f35 }, +/* 0x5f36 */ { false, 0x5f36, 0x5f36 }, +/* 0x5f37 */ { false, 0x5f37, 0x5f37 }, +/* 0x5f38 */ { false, 0x5f38, 0x5f38 }, +/* 0x5f39 */ { false, 0x5f39, 0x5f39 }, +/* 0x5f3a */ { false, 0x5f3a, 0x5f3a }, +/* 0x5f3b */ { false, 0x5f3b, 0x5f3b }, +/* 0x5f3c */ { false, 0x5f3c, 0x5f3c }, +/* 0x5f3d */ { false, 0x5f3d, 0x5f3d }, +/* 0x5f3e */ { false, 0x5f3e, 0x5f3e }, +/* 0x5f3f */ { false, 0x5f3f, 0x5f3f }, +/* 0x5f40 */ { false, 0x5f40, 0x5f40 }, +/* 0x5f41 */ { false, 0x5f41, 0x5f41 }, +/* 0x5f42 */ { false, 0x5f42, 0x5f42 }, +/* 0x5f43 */ { false, 0x5f43, 0x5f43 }, +/* 0x5f44 */ { false, 0x5f44, 0x5f44 }, +/* 0x5f45 */ { false, 0x5f45, 0x5f45 }, +/* 0x5f46 */ { false, 0x5f46, 0x5f46 }, +/* 0x5f47 */ { false, 0x5f47, 0x5f47 }, +/* 0x5f48 */ { false, 0x5f48, 0x5f48 }, +/* 0x5f49 */ { false, 0x5f49, 0x5f49 }, +/* 0x5f4a */ { false, 0x5f4a, 0x5f4a }, +/* 0x5f4b */ { false, 0x5f4b, 0x5f4b }, +/* 0x5f4c */ { false, 0x5f4c, 0x5f4c }, +/* 0x5f4d */ { false, 0x5f4d, 0x5f4d }, +/* 0x5f4e */ { false, 0x5f4e, 0x5f4e }, +/* 0x5f4f */ { false, 0x5f4f, 0x5f4f }, +/* 0x5f50 */ { false, 0x5f50, 0x5f50 }, +/* 0x5f51 */ { false, 0x5f51, 0x5f51 }, +/* 0x5f52 */ { false, 0x5f52, 0x5f52 }, +/* 0x5f53 */ { false, 0x5f53, 0x5f53 }, +/* 0x5f54 */ { false, 0x5f54, 0x5f54 }, +/* 0x5f55 */ { false, 0x5f55, 0x5f55 }, +/* 0x5f56 */ { false, 0x5f56, 0x5f56 }, +/* 0x5f57 */ { false, 0x5f57, 0x5f57 }, +/* 0x5f58 */ { false, 0x5f58, 0x5f58 }, +/* 0x5f59 */ { false, 0x5f59, 0x5f59 }, +/* 0x5f5a */ { false, 0x5f5a, 0x5f5a }, +/* 0x5f5b */ { false, 0x5f5b, 0x5f5b }, +/* 0x5f5c */ { false, 0x5f5c, 0x5f5c }, +/* 0x5f5d */ { false, 0x5f5d, 0x5f5d }, +/* 0x5f5e */ { false, 0x5f5e, 0x5f5e }, +/* 0x5f5f */ { false, 0x5f5f, 0x5f5f }, +/* 0x5f60 */ { false, 0x5f60, 0x5f60 }, +/* 0x5f61 */ { false, 0x5f61, 0x5f61 }, +/* 0x5f62 */ { false, 0x5f62, 0x5f62 }, +/* 0x5f63 */ { false, 0x5f63, 0x5f63 }, +/* 0x5f64 */ { false, 0x5f64, 0x5f64 }, +/* 0x5f65 */ { false, 0x5f65, 0x5f65 }, +/* 0x5f66 */ { false, 0x5f66, 0x5f66 }, +/* 0x5f67 */ { false, 0x5f67, 0x5f67 }, +/* 0x5f68 */ { false, 0x5f68, 0x5f68 }, +/* 0x5f69 */ { false, 0x5f69, 0x5f69 }, +/* 0x5f6a */ { false, 0x5f6a, 0x5f6a }, +/* 0x5f6b */ { false, 0x5f6b, 0x5f6b }, +/* 0x5f6c */ { false, 0x5f6c, 0x5f6c }, +/* 0x5f6d */ { false, 0x5f6d, 0x5f6d }, +/* 0x5f6e */ { false, 0x5f6e, 0x5f6e }, +/* 0x5f6f */ { false, 0x5f6f, 0x5f6f }, +/* 0x5f70 */ { false, 0x5f70, 0x5f70 }, +/* 0x5f71 */ { false, 0x5f71, 0x5f71 }, +/* 0x5f72 */ { false, 0x5f72, 0x5f72 }, +/* 0x5f73 */ { false, 0x5f73, 0x5f73 }, +/* 0x5f74 */ { false, 0x5f74, 0x5f74 }, +/* 0x5f75 */ { false, 0x5f75, 0x5f75 }, +/* 0x5f76 */ { false, 0x5f76, 0x5f76 }, +/* 0x5f77 */ { false, 0x5f77, 0x5f77 }, +/* 0x5f78 */ { false, 0x5f78, 0x5f78 }, +/* 0x5f79 */ { false, 0x5f79, 0x5f79 }, +/* 0x5f7a */ { false, 0x5f7a, 0x5f7a }, +/* 0x5f7b */ { false, 0x5f7b, 0x5f7b }, +/* 0x5f7c */ { false, 0x5f7c, 0x5f7c }, +/* 0x5f7d */ { false, 0x5f7d, 0x5f7d }, +/* 0x5f7e */ { false, 0x5f7e, 0x5f7e }, +/* 0x5f7f */ { false, 0x5f7f, 0x5f7f }, +/* 0x5f80 */ { false, 0x5f80, 0x5f80 }, +/* 0x5f81 */ { false, 0x5f81, 0x5f81 }, +/* 0x5f82 */ { false, 0x5f82, 0x5f82 }, +/* 0x5f83 */ { false, 0x5f83, 0x5f83 }, +/* 0x5f84 */ { false, 0x5f84, 0x5f84 }, +/* 0x5f85 */ { false, 0x5f85, 0x5f85 }, +/* 0x5f86 */ { false, 0x5f86, 0x5f86 }, +/* 0x5f87 */ { false, 0x5f87, 0x5f87 }, +/* 0x5f88 */ { false, 0x5f88, 0x5f88 }, +/* 0x5f89 */ { false, 0x5f89, 0x5f89 }, +/* 0x5f8a */ { false, 0x5f8a, 0x5f8a }, +/* 0x5f8b */ { false, 0x5f8b, 0x5f8b }, +/* 0x5f8c */ { false, 0x5f8c, 0x5f8c }, +/* 0x5f8d */ { false, 0x5f8d, 0x5f8d }, +/* 0x5f8e */ { false, 0x5f8e, 0x5f8e }, +/* 0x5f8f */ { false, 0x5f8f, 0x5f8f }, +/* 0x5f90 */ { false, 0x5f90, 0x5f90 }, +/* 0x5f91 */ { false, 0x5f91, 0x5f91 }, +/* 0x5f92 */ { false, 0x5f92, 0x5f92 }, +/* 0x5f93 */ { false, 0x5f93, 0x5f93 }, +/* 0x5f94 */ { false, 0x5f94, 0x5f94 }, +/* 0x5f95 */ { false, 0x5f95, 0x5f95 }, +/* 0x5f96 */ { false, 0x5f96, 0x5f96 }, +/* 0x5f97 */ { false, 0x5f97, 0x5f97 }, +/* 0x5f98 */ { false, 0x5f98, 0x5f98 }, +/* 0x5f99 */ { false, 0x5f99, 0x5f99 }, +/* 0x5f9a */ { false, 0x5f9a, 0x5f9a }, +/* 0x5f9b */ { false, 0x5f9b, 0x5f9b }, +/* 0x5f9c */ { false, 0x5f9c, 0x5f9c }, +/* 0x5f9d */ { false, 0x5f9d, 0x5f9d }, +/* 0x5f9e */ { false, 0x5f9e, 0x5f9e }, +/* 0x5f9f */ { false, 0x5f9f, 0x5f9f }, +/* 0x5fa0 */ { false, 0x5fa0, 0x5fa0 }, +/* 0x5fa1 */ { false, 0x5fa1, 0x5fa1 }, +/* 0x5fa2 */ { false, 0x5fa2, 0x5fa2 }, +/* 0x5fa3 */ { false, 0x5fa3, 0x5fa3 }, +/* 0x5fa4 */ { false, 0x5fa4, 0x5fa4 }, +/* 0x5fa5 */ { false, 0x5fa5, 0x5fa5 }, +/* 0x5fa6 */ { false, 0x5fa6, 0x5fa6 }, +/* 0x5fa7 */ { false, 0x5fa7, 0x5fa7 }, +/* 0x5fa8 */ { false, 0x5fa8, 0x5fa8 }, +/* 0x5fa9 */ { false, 0x5fa9, 0x5fa9 }, +/* 0x5faa */ { false, 0x5faa, 0x5faa }, +/* 0x5fab */ { false, 0x5fab, 0x5fab }, +/* 0x5fac */ { false, 0x5fac, 0x5fac }, +/* 0x5fad */ { false, 0x5fad, 0x5fad }, +/* 0x5fae */ { false, 0x5fae, 0x5fae }, +/* 0x5faf */ { false, 0x5faf, 0x5faf }, +/* 0x5fb0 */ { false, 0x5fb0, 0x5fb0 }, +/* 0x5fb1 */ { false, 0x5fb1, 0x5fb1 }, +/* 0x5fb2 */ { false, 0x5fb2, 0x5fb2 }, +/* 0x5fb3 */ { false, 0x5fb3, 0x5fb3 }, +/* 0x5fb4 */ { false, 0x5fb4, 0x5fb4 }, +/* 0x5fb5 */ { false, 0x5fb5, 0x5fb5 }, +/* 0x5fb6 */ { false, 0x5fb6, 0x5fb6 }, +/* 0x5fb7 */ { false, 0x5fb7, 0x5fb7 }, +/* 0x5fb8 */ { false, 0x5fb8, 0x5fb8 }, +/* 0x5fb9 */ { false, 0x5fb9, 0x5fb9 }, +/* 0x5fba */ { false, 0x5fba, 0x5fba }, +/* 0x5fbb */ { false, 0x5fbb, 0x5fbb }, +/* 0x5fbc */ { false, 0x5fbc, 0x5fbc }, +/* 0x5fbd */ { false, 0x5fbd, 0x5fbd }, +/* 0x5fbe */ { false, 0x5fbe, 0x5fbe }, +/* 0x5fbf */ { false, 0x5fbf, 0x5fbf }, +/* 0x5fc0 */ { false, 0x5fc0, 0x5fc0 }, +/* 0x5fc1 */ { false, 0x5fc1, 0x5fc1 }, +/* 0x5fc2 */ { false, 0x5fc2, 0x5fc2 }, +/* 0x5fc3 */ { false, 0x5fc3, 0x5fc3 }, +/* 0x5fc4 */ { false, 0x5fc4, 0x5fc4 }, +/* 0x5fc5 */ { false, 0x5fc5, 0x5fc5 }, +/* 0x5fc6 */ { false, 0x5fc6, 0x5fc6 }, +/* 0x5fc7 */ { false, 0x5fc7, 0x5fc7 }, +/* 0x5fc8 */ { false, 0x5fc8, 0x5fc8 }, +/* 0x5fc9 */ { false, 0x5fc9, 0x5fc9 }, +/* 0x5fca */ { false, 0x5fca, 0x5fca }, +/* 0x5fcb */ { false, 0x5fcb, 0x5fcb }, +/* 0x5fcc */ { false, 0x5fcc, 0x5fcc }, +/* 0x5fcd */ { false, 0x5fcd, 0x5fcd }, +/* 0x5fce */ { false, 0x5fce, 0x5fce }, +/* 0x5fcf */ { false, 0x5fcf, 0x5fcf }, +/* 0x5fd0 */ { false, 0x5fd0, 0x5fd0 }, +/* 0x5fd1 */ { false, 0x5fd1, 0x5fd1 }, +/* 0x5fd2 */ { false, 0x5fd2, 0x5fd2 }, +/* 0x5fd3 */ { false, 0x5fd3, 0x5fd3 }, +/* 0x5fd4 */ { false, 0x5fd4, 0x5fd4 }, +/* 0x5fd5 */ { false, 0x5fd5, 0x5fd5 }, +/* 0x5fd6 */ { false, 0x5fd6, 0x5fd6 }, +/* 0x5fd7 */ { false, 0x5fd7, 0x5fd7 }, +/* 0x5fd8 */ { false, 0x5fd8, 0x5fd8 }, +/* 0x5fd9 */ { false, 0x5fd9, 0x5fd9 }, +/* 0x5fda */ { false, 0x5fda, 0x5fda }, +/* 0x5fdb */ { false, 0x5fdb, 0x5fdb }, +/* 0x5fdc */ { false, 0x5fdc, 0x5fdc }, +/* 0x5fdd */ { false, 0x5fdd, 0x5fdd }, +/* 0x5fde */ { false, 0x5fde, 0x5fde }, +/* 0x5fdf */ { false, 0x5fdf, 0x5fdf }, +/* 0x5fe0 */ { false, 0x5fe0, 0x5fe0 }, +/* 0x5fe1 */ { false, 0x5fe1, 0x5fe1 }, +/* 0x5fe2 */ { false, 0x5fe2, 0x5fe2 }, +/* 0x5fe3 */ { false, 0x5fe3, 0x5fe3 }, +/* 0x5fe4 */ { false, 0x5fe4, 0x5fe4 }, +/* 0x5fe5 */ { false, 0x5fe5, 0x5fe5 }, +/* 0x5fe6 */ { false, 0x5fe6, 0x5fe6 }, +/* 0x5fe7 */ { false, 0x5fe7, 0x5fe7 }, +/* 0x5fe8 */ { false, 0x5fe8, 0x5fe8 }, +/* 0x5fe9 */ { false, 0x5fe9, 0x5fe9 }, +/* 0x5fea */ { false, 0x5fea, 0x5fea }, +/* 0x5feb */ { false, 0x5feb, 0x5feb }, +/* 0x5fec */ { false, 0x5fec, 0x5fec }, +/* 0x5fed */ { false, 0x5fed, 0x5fed }, +/* 0x5fee */ { false, 0x5fee, 0x5fee }, +/* 0x5fef */ { false, 0x5fef, 0x5fef }, +/* 0x5ff0 */ { false, 0x5ff0, 0x5ff0 }, +/* 0x5ff1 */ { false, 0x5ff1, 0x5ff1 }, +/* 0x5ff2 */ { false, 0x5ff2, 0x5ff2 }, +/* 0x5ff3 */ { false, 0x5ff3, 0x5ff3 }, +/* 0x5ff4 */ { false, 0x5ff4, 0x5ff4 }, +/* 0x5ff5 */ { false, 0x5ff5, 0x5ff5 }, +/* 0x5ff6 */ { false, 0x5ff6, 0x5ff6 }, +/* 0x5ff7 */ { false, 0x5ff7, 0x5ff7 }, +/* 0x5ff8 */ { false, 0x5ff8, 0x5ff8 }, +/* 0x5ff9 */ { false, 0x5ff9, 0x5ff9 }, +/* 0x5ffa */ { false, 0x5ffa, 0x5ffa }, +/* 0x5ffb */ { false, 0x5ffb, 0x5ffb }, +/* 0x5ffc */ { false, 0x5ffc, 0x5ffc }, +/* 0x5ffd */ { false, 0x5ffd, 0x5ffd }, +/* 0x5ffe */ { false, 0x5ffe, 0x5ffe }, +/* 0x5fff */ { false, 0x5fff, 0x5fff }, +/* 0x6000 */ { false, 0x6000, 0x6000 }, +/* 0x6001 */ { false, 0x6001, 0x6001 }, +/* 0x6002 */ { false, 0x6002, 0x6002 }, +/* 0x6003 */ { false, 0x6003, 0x6003 }, +/* 0x6004 */ { false, 0x6004, 0x6004 }, +/* 0x6005 */ { false, 0x6005, 0x6005 }, +/* 0x6006 */ { false, 0x6006, 0x6006 }, +/* 0x6007 */ { false, 0x6007, 0x6007 }, +/* 0x6008 */ { false, 0x6008, 0x6008 }, +/* 0x6009 */ { false, 0x6009, 0x6009 }, +/* 0x600a */ { false, 0x600a, 0x600a }, +/* 0x600b */ { false, 0x600b, 0x600b }, +/* 0x600c */ { false, 0x600c, 0x600c }, +/* 0x600d */ { false, 0x600d, 0x600d }, +/* 0x600e */ { false, 0x600e, 0x600e }, +/* 0x600f */ { false, 0x600f, 0x600f }, +/* 0x6010 */ { false, 0x6010, 0x6010 }, +/* 0x6011 */ { false, 0x6011, 0x6011 }, +/* 0x6012 */ { false, 0x6012, 0x6012 }, +/* 0x6013 */ { false, 0x6013, 0x6013 }, +/* 0x6014 */ { false, 0x6014, 0x6014 }, +/* 0x6015 */ { false, 0x6015, 0x6015 }, +/* 0x6016 */ { false, 0x6016, 0x6016 }, +/* 0x6017 */ { false, 0x6017, 0x6017 }, +/* 0x6018 */ { false, 0x6018, 0x6018 }, +/* 0x6019 */ { false, 0x6019, 0x6019 }, +/* 0x601a */ { false, 0x601a, 0x601a }, +/* 0x601b */ { false, 0x601b, 0x601b }, +/* 0x601c */ { false, 0x601c, 0x601c }, +/* 0x601d */ { false, 0x601d, 0x601d }, +/* 0x601e */ { false, 0x601e, 0x601e }, +/* 0x601f */ { false, 0x601f, 0x601f }, +/* 0x6020 */ { false, 0x6020, 0x6020 }, +/* 0x6021 */ { false, 0x6021, 0x6021 }, +/* 0x6022 */ { false, 0x6022, 0x6022 }, +/* 0x6023 */ { false, 0x6023, 0x6023 }, +/* 0x6024 */ { false, 0x6024, 0x6024 }, +/* 0x6025 */ { false, 0x6025, 0x6025 }, +/* 0x6026 */ { false, 0x6026, 0x6026 }, +/* 0x6027 */ { false, 0x6027, 0x6027 }, +/* 0x6028 */ { false, 0x6028, 0x6028 }, +/* 0x6029 */ { false, 0x6029, 0x6029 }, +/* 0x602a */ { false, 0x602a, 0x602a }, +/* 0x602b */ { false, 0x602b, 0x602b }, +/* 0x602c */ { false, 0x602c, 0x602c }, +/* 0x602d */ { false, 0x602d, 0x602d }, +/* 0x602e */ { false, 0x602e, 0x602e }, +/* 0x602f */ { false, 0x602f, 0x602f }, +/* 0x6030 */ { false, 0x6030, 0x6030 }, +/* 0x6031 */ { false, 0x6031, 0x6031 }, +/* 0x6032 */ { false, 0x6032, 0x6032 }, +/* 0x6033 */ { false, 0x6033, 0x6033 }, +/* 0x6034 */ { false, 0x6034, 0x6034 }, +/* 0x6035 */ { false, 0x6035, 0x6035 }, +/* 0x6036 */ { false, 0x6036, 0x6036 }, +/* 0x6037 */ { false, 0x6037, 0x6037 }, +/* 0x6038 */ { false, 0x6038, 0x6038 }, +/* 0x6039 */ { false, 0x6039, 0x6039 }, +/* 0x603a */ { false, 0x603a, 0x603a }, +/* 0x603b */ { false, 0x603b, 0x603b }, +/* 0x603c */ { false, 0x603c, 0x603c }, +/* 0x603d */ { false, 0x603d, 0x603d }, +/* 0x603e */ { false, 0x603e, 0x603e }, +/* 0x603f */ { false, 0x603f, 0x603f }, +/* 0x6040 */ { false, 0x6040, 0x6040 }, +/* 0x6041 */ { false, 0x6041, 0x6041 }, +/* 0x6042 */ { false, 0x6042, 0x6042 }, +/* 0x6043 */ { false, 0x6043, 0x6043 }, +/* 0x6044 */ { false, 0x6044, 0x6044 }, +/* 0x6045 */ { false, 0x6045, 0x6045 }, +/* 0x6046 */ { false, 0x6046, 0x6046 }, +/* 0x6047 */ { false, 0x6047, 0x6047 }, +/* 0x6048 */ { false, 0x6048, 0x6048 }, +/* 0x6049 */ { false, 0x6049, 0x6049 }, +/* 0x604a */ { false, 0x604a, 0x604a }, +/* 0x604b */ { false, 0x604b, 0x604b }, +/* 0x604c */ { false, 0x604c, 0x604c }, +/* 0x604d */ { false, 0x604d, 0x604d }, +/* 0x604e */ { false, 0x604e, 0x604e }, +/* 0x604f */ { false, 0x604f, 0x604f }, +/* 0x6050 */ { false, 0x6050, 0x6050 }, +/* 0x6051 */ { false, 0x6051, 0x6051 }, +/* 0x6052 */ { false, 0x6052, 0x6052 }, +/* 0x6053 */ { false, 0x6053, 0x6053 }, +/* 0x6054 */ { false, 0x6054, 0x6054 }, +/* 0x6055 */ { false, 0x6055, 0x6055 }, +/* 0x6056 */ { false, 0x6056, 0x6056 }, +/* 0x6057 */ { false, 0x6057, 0x6057 }, +/* 0x6058 */ { false, 0x6058, 0x6058 }, +/* 0x6059 */ { false, 0x6059, 0x6059 }, +/* 0x605a */ { false, 0x605a, 0x605a }, +/* 0x605b */ { false, 0x605b, 0x605b }, +/* 0x605c */ { false, 0x605c, 0x605c }, +/* 0x605d */ { false, 0x605d, 0x605d }, +/* 0x605e */ { false, 0x605e, 0x605e }, +/* 0x605f */ { false, 0x605f, 0x605f }, +/* 0x6060 */ { false, 0x6060, 0x6060 }, +/* 0x6061 */ { false, 0x6061, 0x6061 }, +/* 0x6062 */ { false, 0x6062, 0x6062 }, +/* 0x6063 */ { false, 0x6063, 0x6063 }, +/* 0x6064 */ { false, 0x6064, 0x6064 }, +/* 0x6065 */ { false, 0x6065, 0x6065 }, +/* 0x6066 */ { false, 0x6066, 0x6066 }, +/* 0x6067 */ { false, 0x6067, 0x6067 }, +/* 0x6068 */ { false, 0x6068, 0x6068 }, +/* 0x6069 */ { false, 0x6069, 0x6069 }, +/* 0x606a */ { false, 0x606a, 0x606a }, +/* 0x606b */ { false, 0x606b, 0x606b }, +/* 0x606c */ { false, 0x606c, 0x606c }, +/* 0x606d */ { false, 0x606d, 0x606d }, +/* 0x606e */ { false, 0x606e, 0x606e }, +/* 0x606f */ { false, 0x606f, 0x606f }, +/* 0x6070 */ { false, 0x6070, 0x6070 }, +/* 0x6071 */ { false, 0x6071, 0x6071 }, +/* 0x6072 */ { false, 0x6072, 0x6072 }, +/* 0x6073 */ { false, 0x6073, 0x6073 }, +/* 0x6074 */ { false, 0x6074, 0x6074 }, +/* 0x6075 */ { false, 0x6075, 0x6075 }, +/* 0x6076 */ { false, 0x6076, 0x6076 }, +/* 0x6077 */ { false, 0x6077, 0x6077 }, +/* 0x6078 */ { false, 0x6078, 0x6078 }, +/* 0x6079 */ { false, 0x6079, 0x6079 }, +/* 0x607a */ { false, 0x607a, 0x607a }, +/* 0x607b */ { false, 0x607b, 0x607b }, +/* 0x607c */ { false, 0x607c, 0x607c }, +/* 0x607d */ { false, 0x607d, 0x607d }, +/* 0x607e */ { false, 0x607e, 0x607e }, +/* 0x607f */ { false, 0x607f, 0x607f }, +/* 0x6080 */ { false, 0x6080, 0x6080 }, +/* 0x6081 */ { false, 0x6081, 0x6081 }, +/* 0x6082 */ { false, 0x6082, 0x6082 }, +/* 0x6083 */ { false, 0x6083, 0x6083 }, +/* 0x6084 */ { false, 0x6084, 0x6084 }, +/* 0x6085 */ { false, 0x6085, 0x6085 }, +/* 0x6086 */ { false, 0x6086, 0x6086 }, +/* 0x6087 */ { false, 0x6087, 0x6087 }, +/* 0x6088 */ { false, 0x6088, 0x6088 }, +/* 0x6089 */ { false, 0x6089, 0x6089 }, +/* 0x608a */ { false, 0x608a, 0x608a }, +/* 0x608b */ { false, 0x608b, 0x608b }, +/* 0x608c */ { false, 0x608c, 0x608c }, +/* 0x608d */ { false, 0x608d, 0x608d }, +/* 0x608e */ { false, 0x608e, 0x608e }, +/* 0x608f */ { false, 0x608f, 0x608f }, +/* 0x6090 */ { false, 0x6090, 0x6090 }, +/* 0x6091 */ { false, 0x6091, 0x6091 }, +/* 0x6092 */ { false, 0x6092, 0x6092 }, +/* 0x6093 */ { false, 0x6093, 0x6093 }, +/* 0x6094 */ { false, 0x6094, 0x6094 }, +/* 0x6095 */ { false, 0x6095, 0x6095 }, +/* 0x6096 */ { false, 0x6096, 0x6096 }, +/* 0x6097 */ { false, 0x6097, 0x6097 }, +/* 0x6098 */ { false, 0x6098, 0x6098 }, +/* 0x6099 */ { false, 0x6099, 0x6099 }, +/* 0x609a */ { false, 0x609a, 0x609a }, +/* 0x609b */ { false, 0x609b, 0x609b }, +/* 0x609c */ { false, 0x609c, 0x609c }, +/* 0x609d */ { false, 0x609d, 0x609d }, +/* 0x609e */ { false, 0x609e, 0x609e }, +/* 0x609f */ { false, 0x609f, 0x609f }, +/* 0x60a0 */ { false, 0x60a0, 0x60a0 }, +/* 0x60a1 */ { false, 0x60a1, 0x60a1 }, +/* 0x60a2 */ { false, 0x60a2, 0x60a2 }, +/* 0x60a3 */ { false, 0x60a3, 0x60a3 }, +/* 0x60a4 */ { false, 0x60a4, 0x60a4 }, +/* 0x60a5 */ { false, 0x60a5, 0x60a5 }, +/* 0x60a6 */ { false, 0x60a6, 0x60a6 }, +/* 0x60a7 */ { false, 0x60a7, 0x60a7 }, +/* 0x60a8 */ { false, 0x60a8, 0x60a8 }, +/* 0x60a9 */ { false, 0x60a9, 0x60a9 }, +/* 0x60aa */ { false, 0x60aa, 0x60aa }, +/* 0x60ab */ { false, 0x60ab, 0x60ab }, +/* 0x60ac */ { false, 0x60ac, 0x60ac }, +/* 0x60ad */ { false, 0x60ad, 0x60ad }, +/* 0x60ae */ { false, 0x60ae, 0x60ae }, +/* 0x60af */ { false, 0x60af, 0x60af }, +/* 0x60b0 */ { false, 0x60b0, 0x60b0 }, +/* 0x60b1 */ { false, 0x60b1, 0x60b1 }, +/* 0x60b2 */ { false, 0x60b2, 0x60b2 }, +/* 0x60b3 */ { false, 0x60b3, 0x60b3 }, +/* 0x60b4 */ { false, 0x60b4, 0x60b4 }, +/* 0x60b5 */ { false, 0x60b5, 0x60b5 }, +/* 0x60b6 */ { false, 0x60b6, 0x60b6 }, +/* 0x60b7 */ { false, 0x60b7, 0x60b7 }, +/* 0x60b8 */ { false, 0x60b8, 0x60b8 }, +/* 0x60b9 */ { false, 0x60b9, 0x60b9 }, +/* 0x60ba */ { false, 0x60ba, 0x60ba }, +/* 0x60bb */ { false, 0x60bb, 0x60bb }, +/* 0x60bc */ { false, 0x60bc, 0x60bc }, +/* 0x60bd */ { false, 0x60bd, 0x60bd }, +/* 0x60be */ { false, 0x60be, 0x60be }, +/* 0x60bf */ { false, 0x60bf, 0x60bf }, +/* 0x60c0 */ { false, 0x60c0, 0x60c0 }, +/* 0x60c1 */ { false, 0x60c1, 0x60c1 }, +/* 0x60c2 */ { false, 0x60c2, 0x60c2 }, +/* 0x60c3 */ { false, 0x60c3, 0x60c3 }, +/* 0x60c4 */ { false, 0x60c4, 0x60c4 }, +/* 0x60c5 */ { false, 0x60c5, 0x60c5 }, +/* 0x60c6 */ { false, 0x60c6, 0x60c6 }, +/* 0x60c7 */ { false, 0x60c7, 0x60c7 }, +/* 0x60c8 */ { false, 0x60c8, 0x60c8 }, +/* 0x60c9 */ { false, 0x60c9, 0x60c9 }, +/* 0x60ca */ { false, 0x60ca, 0x60ca }, +/* 0x60cb */ { false, 0x60cb, 0x60cb }, +/* 0x60cc */ { false, 0x60cc, 0x60cc }, +/* 0x60cd */ { false, 0x60cd, 0x60cd }, +/* 0x60ce */ { false, 0x60ce, 0x60ce }, +/* 0x60cf */ { false, 0x60cf, 0x60cf }, +/* 0x60d0 */ { false, 0x60d0, 0x60d0 }, +/* 0x60d1 */ { false, 0x60d1, 0x60d1 }, +/* 0x60d2 */ { false, 0x60d2, 0x60d2 }, +/* 0x60d3 */ { false, 0x60d3, 0x60d3 }, +/* 0x60d4 */ { false, 0x60d4, 0x60d4 }, +/* 0x60d5 */ { false, 0x60d5, 0x60d5 }, +/* 0x60d6 */ { false, 0x60d6, 0x60d6 }, +/* 0x60d7 */ { false, 0x60d7, 0x60d7 }, +/* 0x60d8 */ { false, 0x60d8, 0x60d8 }, +/* 0x60d9 */ { false, 0x60d9, 0x60d9 }, +/* 0x60da */ { false, 0x60da, 0x60da }, +/* 0x60db */ { false, 0x60db, 0x60db }, +/* 0x60dc */ { false, 0x60dc, 0x60dc }, +/* 0x60dd */ { false, 0x60dd, 0x60dd }, +/* 0x60de */ { false, 0x60de, 0x60de }, +/* 0x60df */ { false, 0x60df, 0x60df }, +/* 0x60e0 */ { false, 0x60e0, 0x60e0 }, +/* 0x60e1 */ { false, 0x60e1, 0x60e1 }, +/* 0x60e2 */ { false, 0x60e2, 0x60e2 }, +/* 0x60e3 */ { false, 0x60e3, 0x60e3 }, +/* 0x60e4 */ { false, 0x60e4, 0x60e4 }, +/* 0x60e5 */ { false, 0x60e5, 0x60e5 }, +/* 0x60e6 */ { false, 0x60e6, 0x60e6 }, +/* 0x60e7 */ { false, 0x60e7, 0x60e7 }, +/* 0x60e8 */ { false, 0x60e8, 0x60e8 }, +/* 0x60e9 */ { false, 0x60e9, 0x60e9 }, +/* 0x60ea */ { false, 0x60ea, 0x60ea }, +/* 0x60eb */ { false, 0x60eb, 0x60eb }, +/* 0x60ec */ { false, 0x60ec, 0x60ec }, +/* 0x60ed */ { false, 0x60ed, 0x60ed }, +/* 0x60ee */ { false, 0x60ee, 0x60ee }, +/* 0x60ef */ { false, 0x60ef, 0x60ef }, +/* 0x60f0 */ { false, 0x60f0, 0x60f0 }, +/* 0x60f1 */ { false, 0x60f1, 0x60f1 }, +/* 0x60f2 */ { false, 0x60f2, 0x60f2 }, +/* 0x60f3 */ { false, 0x60f3, 0x60f3 }, +/* 0x60f4 */ { false, 0x60f4, 0x60f4 }, +/* 0x60f5 */ { false, 0x60f5, 0x60f5 }, +/* 0x60f6 */ { false, 0x60f6, 0x60f6 }, +/* 0x60f7 */ { false, 0x60f7, 0x60f7 }, +/* 0x60f8 */ { false, 0x60f8, 0x60f8 }, +/* 0x60f9 */ { false, 0x60f9, 0x60f9 }, +/* 0x60fa */ { false, 0x60fa, 0x60fa }, +/* 0x60fb */ { false, 0x60fb, 0x60fb }, +/* 0x60fc */ { false, 0x60fc, 0x60fc }, +/* 0x60fd */ { false, 0x60fd, 0x60fd }, +/* 0x60fe */ { false, 0x60fe, 0x60fe }, +/* 0x60ff */ { false, 0x60ff, 0x60ff }, +/* 0x6100 */ { false, 0x6100, 0x6100 }, +/* 0x6101 */ { false, 0x6101, 0x6101 }, +/* 0x6102 */ { false, 0x6102, 0x6102 }, +/* 0x6103 */ { false, 0x6103, 0x6103 }, +/* 0x6104 */ { false, 0x6104, 0x6104 }, +/* 0x6105 */ { false, 0x6105, 0x6105 }, +/* 0x6106 */ { false, 0x6106, 0x6106 }, +/* 0x6107 */ { false, 0x6107, 0x6107 }, +/* 0x6108 */ { false, 0x6108, 0x6108 }, +/* 0x6109 */ { false, 0x6109, 0x6109 }, +/* 0x610a */ { false, 0x610a, 0x610a }, +/* 0x610b */ { false, 0x610b, 0x610b }, +/* 0x610c */ { false, 0x610c, 0x610c }, +/* 0x610d */ { false, 0x610d, 0x610d }, +/* 0x610e */ { false, 0x610e, 0x610e }, +/* 0x610f */ { false, 0x610f, 0x610f }, +/* 0x6110 */ { false, 0x6110, 0x6110 }, +/* 0x6111 */ { false, 0x6111, 0x6111 }, +/* 0x6112 */ { false, 0x6112, 0x6112 }, +/* 0x6113 */ { false, 0x6113, 0x6113 }, +/* 0x6114 */ { false, 0x6114, 0x6114 }, +/* 0x6115 */ { false, 0x6115, 0x6115 }, +/* 0x6116 */ { false, 0x6116, 0x6116 }, +/* 0x6117 */ { false, 0x6117, 0x6117 }, +/* 0x6118 */ { false, 0x6118, 0x6118 }, +/* 0x6119 */ { false, 0x6119, 0x6119 }, +/* 0x611a */ { false, 0x611a, 0x611a }, +/* 0x611b */ { false, 0x611b, 0x611b }, +/* 0x611c */ { false, 0x611c, 0x611c }, +/* 0x611d */ { false, 0x611d, 0x611d }, +/* 0x611e */ { false, 0x611e, 0x611e }, +/* 0x611f */ { false, 0x611f, 0x611f }, +/* 0x6120 */ { false, 0x6120, 0x6120 }, +/* 0x6121 */ { false, 0x6121, 0x6121 }, +/* 0x6122 */ { false, 0x6122, 0x6122 }, +/* 0x6123 */ { false, 0x6123, 0x6123 }, +/* 0x6124 */ { false, 0x6124, 0x6124 }, +/* 0x6125 */ { false, 0x6125, 0x6125 }, +/* 0x6126 */ { false, 0x6126, 0x6126 }, +/* 0x6127 */ { false, 0x6127, 0x6127 }, +/* 0x6128 */ { false, 0x6128, 0x6128 }, +/* 0x6129 */ { false, 0x6129, 0x6129 }, +/* 0x612a */ { false, 0x612a, 0x612a }, +/* 0x612b */ { false, 0x612b, 0x612b }, +/* 0x612c */ { false, 0x612c, 0x612c }, +/* 0x612d */ { false, 0x612d, 0x612d }, +/* 0x612e */ { false, 0x612e, 0x612e }, +/* 0x612f */ { false, 0x612f, 0x612f }, +/* 0x6130 */ { false, 0x6130, 0x6130 }, +/* 0x6131 */ { false, 0x6131, 0x6131 }, +/* 0x6132 */ { false, 0x6132, 0x6132 }, +/* 0x6133 */ { false, 0x6133, 0x6133 }, +/* 0x6134 */ { false, 0x6134, 0x6134 }, +/* 0x6135 */ { false, 0x6135, 0x6135 }, +/* 0x6136 */ { false, 0x6136, 0x6136 }, +/* 0x6137 */ { false, 0x6137, 0x6137 }, +/* 0x6138 */ { false, 0x6138, 0x6138 }, +/* 0x6139 */ { false, 0x6139, 0x6139 }, +/* 0x613a */ { false, 0x613a, 0x613a }, +/* 0x613b */ { false, 0x613b, 0x613b }, +/* 0x613c */ { false, 0x613c, 0x613c }, +/* 0x613d */ { false, 0x613d, 0x613d }, +/* 0x613e */ { false, 0x613e, 0x613e }, +/* 0x613f */ { false, 0x613f, 0x613f }, +/* 0x6140 */ { false, 0x6140, 0x6140 }, +/* 0x6141 */ { false, 0x6141, 0x6141 }, +/* 0x6142 */ { false, 0x6142, 0x6142 }, +/* 0x6143 */ { false, 0x6143, 0x6143 }, +/* 0x6144 */ { false, 0x6144, 0x6144 }, +/* 0x6145 */ { false, 0x6145, 0x6145 }, +/* 0x6146 */ { false, 0x6146, 0x6146 }, +/* 0x6147 */ { false, 0x6147, 0x6147 }, +/* 0x6148 */ { false, 0x6148, 0x6148 }, +/* 0x6149 */ { false, 0x6149, 0x6149 }, +/* 0x614a */ { false, 0x614a, 0x614a }, +/* 0x614b */ { false, 0x614b, 0x614b }, +/* 0x614c */ { false, 0x614c, 0x614c }, +/* 0x614d */ { false, 0x614d, 0x614d }, +/* 0x614e */ { false, 0x614e, 0x614e }, +/* 0x614f */ { false, 0x614f, 0x614f }, +/* 0x6150 */ { false, 0x6150, 0x6150 }, +/* 0x6151 */ { false, 0x6151, 0x6151 }, +/* 0x6152 */ { false, 0x6152, 0x6152 }, +/* 0x6153 */ { false, 0x6153, 0x6153 }, +/* 0x6154 */ { false, 0x6154, 0x6154 }, +/* 0x6155 */ { false, 0x6155, 0x6155 }, +/* 0x6156 */ { false, 0x6156, 0x6156 }, +/* 0x6157 */ { false, 0x6157, 0x6157 }, +/* 0x6158 */ { false, 0x6158, 0x6158 }, +/* 0x6159 */ { false, 0x6159, 0x6159 }, +/* 0x615a */ { false, 0x615a, 0x615a }, +/* 0x615b */ { false, 0x615b, 0x615b }, +/* 0x615c */ { false, 0x615c, 0x615c }, +/* 0x615d */ { false, 0x615d, 0x615d }, +/* 0x615e */ { false, 0x615e, 0x615e }, +/* 0x615f */ { false, 0x615f, 0x615f }, +/* 0x6160 */ { false, 0x6160, 0x6160 }, +/* 0x6161 */ { false, 0x6161, 0x6161 }, +/* 0x6162 */ { false, 0x6162, 0x6162 }, +/* 0x6163 */ { false, 0x6163, 0x6163 }, +/* 0x6164 */ { false, 0x6164, 0x6164 }, +/* 0x6165 */ { false, 0x6165, 0x6165 }, +/* 0x6166 */ { false, 0x6166, 0x6166 }, +/* 0x6167 */ { false, 0x6167, 0x6167 }, +/* 0x6168 */ { false, 0x6168, 0x6168 }, +/* 0x6169 */ { false, 0x6169, 0x6169 }, +/* 0x616a */ { false, 0x616a, 0x616a }, +/* 0x616b */ { false, 0x616b, 0x616b }, +/* 0x616c */ { false, 0x616c, 0x616c }, +/* 0x616d */ { false, 0x616d, 0x616d }, +/* 0x616e */ { false, 0x616e, 0x616e }, +/* 0x616f */ { false, 0x616f, 0x616f }, +/* 0x6170 */ { false, 0x6170, 0x6170 }, +/* 0x6171 */ { false, 0x6171, 0x6171 }, +/* 0x6172 */ { false, 0x6172, 0x6172 }, +/* 0x6173 */ { false, 0x6173, 0x6173 }, +/* 0x6174 */ { false, 0x6174, 0x6174 }, +/* 0x6175 */ { false, 0x6175, 0x6175 }, +/* 0x6176 */ { false, 0x6176, 0x6176 }, +/* 0x6177 */ { false, 0x6177, 0x6177 }, +/* 0x6178 */ { false, 0x6178, 0x6178 }, +/* 0x6179 */ { false, 0x6179, 0x6179 }, +/* 0x617a */ { false, 0x617a, 0x617a }, +/* 0x617b */ { false, 0x617b, 0x617b }, +/* 0x617c */ { false, 0x617c, 0x617c }, +/* 0x617d */ { false, 0x617d, 0x617d }, +/* 0x617e */ { false, 0x617e, 0x617e }, +/* 0x617f */ { false, 0x617f, 0x617f }, +/* 0x6180 */ { false, 0x6180, 0x6180 }, +/* 0x6181 */ { false, 0x6181, 0x6181 }, +/* 0x6182 */ { false, 0x6182, 0x6182 }, +/* 0x6183 */ { false, 0x6183, 0x6183 }, +/* 0x6184 */ { false, 0x6184, 0x6184 }, +/* 0x6185 */ { false, 0x6185, 0x6185 }, +/* 0x6186 */ { false, 0x6186, 0x6186 }, +/* 0x6187 */ { false, 0x6187, 0x6187 }, +/* 0x6188 */ { false, 0x6188, 0x6188 }, +/* 0x6189 */ { false, 0x6189, 0x6189 }, +/* 0x618a */ { false, 0x618a, 0x618a }, +/* 0x618b */ { false, 0x618b, 0x618b }, +/* 0x618c */ { false, 0x618c, 0x618c }, +/* 0x618d */ { false, 0x618d, 0x618d }, +/* 0x618e */ { false, 0x618e, 0x618e }, +/* 0x618f */ { false, 0x618f, 0x618f }, +/* 0x6190 */ { false, 0x6190, 0x6190 }, +/* 0x6191 */ { false, 0x6191, 0x6191 }, +/* 0x6192 */ { false, 0x6192, 0x6192 }, +/* 0x6193 */ { false, 0x6193, 0x6193 }, +/* 0x6194 */ { false, 0x6194, 0x6194 }, +/* 0x6195 */ { false, 0x6195, 0x6195 }, +/* 0x6196 */ { false, 0x6196, 0x6196 }, +/* 0x6197 */ { false, 0x6197, 0x6197 }, +/* 0x6198 */ { false, 0x6198, 0x6198 }, +/* 0x6199 */ { false, 0x6199, 0x6199 }, +/* 0x619a */ { false, 0x619a, 0x619a }, +/* 0x619b */ { false, 0x619b, 0x619b }, +/* 0x619c */ { false, 0x619c, 0x619c }, +/* 0x619d */ { false, 0x619d, 0x619d }, +/* 0x619e */ { false, 0x619e, 0x619e }, +/* 0x619f */ { false, 0x619f, 0x619f }, +/* 0x61a0 */ { false, 0x61a0, 0x61a0 }, +/* 0x61a1 */ { false, 0x61a1, 0x61a1 }, +/* 0x61a2 */ { false, 0x61a2, 0x61a2 }, +/* 0x61a3 */ { false, 0x61a3, 0x61a3 }, +/* 0x61a4 */ { false, 0x61a4, 0x61a4 }, +/* 0x61a5 */ { false, 0x61a5, 0x61a5 }, +/* 0x61a6 */ { false, 0x61a6, 0x61a6 }, +/* 0x61a7 */ { false, 0x61a7, 0x61a7 }, +/* 0x61a8 */ { false, 0x61a8, 0x61a8 }, +/* 0x61a9 */ { false, 0x61a9, 0x61a9 }, +/* 0x61aa */ { false, 0x61aa, 0x61aa }, +/* 0x61ab */ { false, 0x61ab, 0x61ab }, +/* 0x61ac */ { false, 0x61ac, 0x61ac }, +/* 0x61ad */ { false, 0x61ad, 0x61ad }, +/* 0x61ae */ { false, 0x61ae, 0x61ae }, +/* 0x61af */ { false, 0x61af, 0x61af }, +/* 0x61b0 */ { false, 0x61b0, 0x61b0 }, +/* 0x61b1 */ { false, 0x61b1, 0x61b1 }, +/* 0x61b2 */ { false, 0x61b2, 0x61b2 }, +/* 0x61b3 */ { false, 0x61b3, 0x61b3 }, +/* 0x61b4 */ { false, 0x61b4, 0x61b4 }, +/* 0x61b5 */ { false, 0x61b5, 0x61b5 }, +/* 0x61b6 */ { false, 0x61b6, 0x61b6 }, +/* 0x61b7 */ { false, 0x61b7, 0x61b7 }, +/* 0x61b8 */ { false, 0x61b8, 0x61b8 }, +/* 0x61b9 */ { false, 0x61b9, 0x61b9 }, +/* 0x61ba */ { false, 0x61ba, 0x61ba }, +/* 0x61bb */ { false, 0x61bb, 0x61bb }, +/* 0x61bc */ { false, 0x61bc, 0x61bc }, +/* 0x61bd */ { false, 0x61bd, 0x61bd }, +/* 0x61be */ { false, 0x61be, 0x61be }, +/* 0x61bf */ { false, 0x61bf, 0x61bf }, +/* 0x61c0 */ { false, 0x61c0, 0x61c0 }, +/* 0x61c1 */ { false, 0x61c1, 0x61c1 }, +/* 0x61c2 */ { false, 0x61c2, 0x61c2 }, +/* 0x61c3 */ { false, 0x61c3, 0x61c3 }, +/* 0x61c4 */ { false, 0x61c4, 0x61c4 }, +/* 0x61c5 */ { false, 0x61c5, 0x61c5 }, +/* 0x61c6 */ { false, 0x61c6, 0x61c6 }, +/* 0x61c7 */ { false, 0x61c7, 0x61c7 }, +/* 0x61c8 */ { false, 0x61c8, 0x61c8 }, +/* 0x61c9 */ { false, 0x61c9, 0x61c9 }, +/* 0x61ca */ { false, 0x61ca, 0x61ca }, +/* 0x61cb */ { false, 0x61cb, 0x61cb }, +/* 0x61cc */ { false, 0x61cc, 0x61cc }, +/* 0x61cd */ { false, 0x61cd, 0x61cd }, +/* 0x61ce */ { false, 0x61ce, 0x61ce }, +/* 0x61cf */ { false, 0x61cf, 0x61cf }, +/* 0x61d0 */ { false, 0x61d0, 0x61d0 }, +/* 0x61d1 */ { false, 0x61d1, 0x61d1 }, +/* 0x61d2 */ { false, 0x61d2, 0x61d2 }, +/* 0x61d3 */ { false, 0x61d3, 0x61d3 }, +/* 0x61d4 */ { false, 0x61d4, 0x61d4 }, +/* 0x61d5 */ { false, 0x61d5, 0x61d5 }, +/* 0x61d6 */ { false, 0x61d6, 0x61d6 }, +/* 0x61d7 */ { false, 0x61d7, 0x61d7 }, +/* 0x61d8 */ { false, 0x61d8, 0x61d8 }, +/* 0x61d9 */ { false, 0x61d9, 0x61d9 }, +/* 0x61da */ { false, 0x61da, 0x61da }, +/* 0x61db */ { false, 0x61db, 0x61db }, +/* 0x61dc */ { false, 0x61dc, 0x61dc }, +/* 0x61dd */ { false, 0x61dd, 0x61dd }, +/* 0x61de */ { false, 0x61de, 0x61de }, +/* 0x61df */ { false, 0x61df, 0x61df }, +/* 0x61e0 */ { false, 0x61e0, 0x61e0 }, +/* 0x61e1 */ { false, 0x61e1, 0x61e1 }, +/* 0x61e2 */ { false, 0x61e2, 0x61e2 }, +/* 0x61e3 */ { false, 0x61e3, 0x61e3 }, +/* 0x61e4 */ { false, 0x61e4, 0x61e4 }, +/* 0x61e5 */ { false, 0x61e5, 0x61e5 }, +/* 0x61e6 */ { false, 0x61e6, 0x61e6 }, +/* 0x61e7 */ { false, 0x61e7, 0x61e7 }, +/* 0x61e8 */ { false, 0x61e8, 0x61e8 }, +/* 0x61e9 */ { false, 0x61e9, 0x61e9 }, +/* 0x61ea */ { false, 0x61ea, 0x61ea }, +/* 0x61eb */ { false, 0x61eb, 0x61eb }, +/* 0x61ec */ { false, 0x61ec, 0x61ec }, +/* 0x61ed */ { false, 0x61ed, 0x61ed }, +/* 0x61ee */ { false, 0x61ee, 0x61ee }, +/* 0x61ef */ { false, 0x61ef, 0x61ef }, +/* 0x61f0 */ { false, 0x61f0, 0x61f0 }, +/* 0x61f1 */ { false, 0x61f1, 0x61f1 }, +/* 0x61f2 */ { false, 0x61f2, 0x61f2 }, +/* 0x61f3 */ { false, 0x61f3, 0x61f3 }, +/* 0x61f4 */ { false, 0x61f4, 0x61f4 }, +/* 0x61f5 */ { false, 0x61f5, 0x61f5 }, +/* 0x61f6 */ { false, 0x61f6, 0x61f6 }, +/* 0x61f7 */ { false, 0x61f7, 0x61f7 }, +/* 0x61f8 */ { false, 0x61f8, 0x61f8 }, +/* 0x61f9 */ { false, 0x61f9, 0x61f9 }, +/* 0x61fa */ { false, 0x61fa, 0x61fa }, +/* 0x61fb */ { false, 0x61fb, 0x61fb }, +/* 0x61fc */ { false, 0x61fc, 0x61fc }, +/* 0x61fd */ { false, 0x61fd, 0x61fd }, +/* 0x61fe */ { false, 0x61fe, 0x61fe }, +/* 0x61ff */ { false, 0x61ff, 0x61ff }, +/* 0x6200 */ { false, 0x6200, 0x6200 }, +/* 0x6201 */ { false, 0x6201, 0x6201 }, +/* 0x6202 */ { false, 0x6202, 0x6202 }, +/* 0x6203 */ { false, 0x6203, 0x6203 }, +/* 0x6204 */ { false, 0x6204, 0x6204 }, +/* 0x6205 */ { false, 0x6205, 0x6205 }, +/* 0x6206 */ { false, 0x6206, 0x6206 }, +/* 0x6207 */ { false, 0x6207, 0x6207 }, +/* 0x6208 */ { false, 0x6208, 0x6208 }, +/* 0x6209 */ { false, 0x6209, 0x6209 }, +/* 0x620a */ { false, 0x620a, 0x620a }, +/* 0x620b */ { false, 0x620b, 0x620b }, +/* 0x620c */ { false, 0x620c, 0x620c }, +/* 0x620d */ { false, 0x620d, 0x620d }, +/* 0x620e */ { false, 0x620e, 0x620e }, +/* 0x620f */ { false, 0x620f, 0x620f }, +/* 0x6210 */ { false, 0x6210, 0x6210 }, +/* 0x6211 */ { false, 0x6211, 0x6211 }, +/* 0x6212 */ { false, 0x6212, 0x6212 }, +/* 0x6213 */ { false, 0x6213, 0x6213 }, +/* 0x6214 */ { false, 0x6214, 0x6214 }, +/* 0x6215 */ { false, 0x6215, 0x6215 }, +/* 0x6216 */ { false, 0x6216, 0x6216 }, +/* 0x6217 */ { false, 0x6217, 0x6217 }, +/* 0x6218 */ { false, 0x6218, 0x6218 }, +/* 0x6219 */ { false, 0x6219, 0x6219 }, +/* 0x621a */ { false, 0x621a, 0x621a }, +/* 0x621b */ { false, 0x621b, 0x621b }, +/* 0x621c */ { false, 0x621c, 0x621c }, +/* 0x621d */ { false, 0x621d, 0x621d }, +/* 0x621e */ { false, 0x621e, 0x621e }, +/* 0x621f */ { false, 0x621f, 0x621f }, +/* 0x6220 */ { false, 0x6220, 0x6220 }, +/* 0x6221 */ { false, 0x6221, 0x6221 }, +/* 0x6222 */ { false, 0x6222, 0x6222 }, +/* 0x6223 */ { false, 0x6223, 0x6223 }, +/* 0x6224 */ { false, 0x6224, 0x6224 }, +/* 0x6225 */ { false, 0x6225, 0x6225 }, +/* 0x6226 */ { false, 0x6226, 0x6226 }, +/* 0x6227 */ { false, 0x6227, 0x6227 }, +/* 0x6228 */ { false, 0x6228, 0x6228 }, +/* 0x6229 */ { false, 0x6229, 0x6229 }, +/* 0x622a */ { false, 0x622a, 0x622a }, +/* 0x622b */ { false, 0x622b, 0x622b }, +/* 0x622c */ { false, 0x622c, 0x622c }, +/* 0x622d */ { false, 0x622d, 0x622d }, +/* 0x622e */ { false, 0x622e, 0x622e }, +/* 0x622f */ { false, 0x622f, 0x622f }, +/* 0x6230 */ { false, 0x6230, 0x6230 }, +/* 0x6231 */ { false, 0x6231, 0x6231 }, +/* 0x6232 */ { false, 0x6232, 0x6232 }, +/* 0x6233 */ { false, 0x6233, 0x6233 }, +/* 0x6234 */ { false, 0x6234, 0x6234 }, +/* 0x6235 */ { false, 0x6235, 0x6235 }, +/* 0x6236 */ { false, 0x6236, 0x6236 }, +/* 0x6237 */ { false, 0x6237, 0x6237 }, +/* 0x6238 */ { false, 0x6238, 0x6238 }, +/* 0x6239 */ { false, 0x6239, 0x6239 }, +/* 0x623a */ { false, 0x623a, 0x623a }, +/* 0x623b */ { false, 0x623b, 0x623b }, +/* 0x623c */ { false, 0x623c, 0x623c }, +/* 0x623d */ { false, 0x623d, 0x623d }, +/* 0x623e */ { false, 0x623e, 0x623e }, +/* 0x623f */ { false, 0x623f, 0x623f }, +/* 0x6240 */ { false, 0x6240, 0x6240 }, +/* 0x6241 */ { false, 0x6241, 0x6241 }, +/* 0x6242 */ { false, 0x6242, 0x6242 }, +/* 0x6243 */ { false, 0x6243, 0x6243 }, +/* 0x6244 */ { false, 0x6244, 0x6244 }, +/* 0x6245 */ { false, 0x6245, 0x6245 }, +/* 0x6246 */ { false, 0x6246, 0x6246 }, +/* 0x6247 */ { false, 0x6247, 0x6247 }, +/* 0x6248 */ { false, 0x6248, 0x6248 }, +/* 0x6249 */ { false, 0x6249, 0x6249 }, +/* 0x624a */ { false, 0x624a, 0x624a }, +/* 0x624b */ { false, 0x624b, 0x624b }, +/* 0x624c */ { false, 0x624c, 0x624c }, +/* 0x624d */ { false, 0x624d, 0x624d }, +/* 0x624e */ { false, 0x624e, 0x624e }, +/* 0x624f */ { false, 0x624f, 0x624f }, +/* 0x6250 */ { false, 0x6250, 0x6250 }, +/* 0x6251 */ { false, 0x6251, 0x6251 }, +/* 0x6252 */ { false, 0x6252, 0x6252 }, +/* 0x6253 */ { false, 0x6253, 0x6253 }, +/* 0x6254 */ { false, 0x6254, 0x6254 }, +/* 0x6255 */ { false, 0x6255, 0x6255 }, +/* 0x6256 */ { false, 0x6256, 0x6256 }, +/* 0x6257 */ { false, 0x6257, 0x6257 }, +/* 0x6258 */ { false, 0x6258, 0x6258 }, +/* 0x6259 */ { false, 0x6259, 0x6259 }, +/* 0x625a */ { false, 0x625a, 0x625a }, +/* 0x625b */ { false, 0x625b, 0x625b }, +/* 0x625c */ { false, 0x625c, 0x625c }, +/* 0x625d */ { false, 0x625d, 0x625d }, +/* 0x625e */ { false, 0x625e, 0x625e }, +/* 0x625f */ { false, 0x625f, 0x625f }, +/* 0x6260 */ { false, 0x6260, 0x6260 }, +/* 0x6261 */ { false, 0x6261, 0x6261 }, +/* 0x6262 */ { false, 0x6262, 0x6262 }, +/* 0x6263 */ { false, 0x6263, 0x6263 }, +/* 0x6264 */ { false, 0x6264, 0x6264 }, +/* 0x6265 */ { false, 0x6265, 0x6265 }, +/* 0x6266 */ { false, 0x6266, 0x6266 }, +/* 0x6267 */ { false, 0x6267, 0x6267 }, +/* 0x6268 */ { false, 0x6268, 0x6268 }, +/* 0x6269 */ { false, 0x6269, 0x6269 }, +/* 0x626a */ { false, 0x626a, 0x626a }, +/* 0x626b */ { false, 0x626b, 0x626b }, +/* 0x626c */ { false, 0x626c, 0x626c }, +/* 0x626d */ { false, 0x626d, 0x626d }, +/* 0x626e */ { false, 0x626e, 0x626e }, +/* 0x626f */ { false, 0x626f, 0x626f }, +/* 0x6270 */ { false, 0x6270, 0x6270 }, +/* 0x6271 */ { false, 0x6271, 0x6271 }, +/* 0x6272 */ { false, 0x6272, 0x6272 }, +/* 0x6273 */ { false, 0x6273, 0x6273 }, +/* 0x6274 */ { false, 0x6274, 0x6274 }, +/* 0x6275 */ { false, 0x6275, 0x6275 }, +/* 0x6276 */ { false, 0x6276, 0x6276 }, +/* 0x6277 */ { false, 0x6277, 0x6277 }, +/* 0x6278 */ { false, 0x6278, 0x6278 }, +/* 0x6279 */ { false, 0x6279, 0x6279 }, +/* 0x627a */ { false, 0x627a, 0x627a }, +/* 0x627b */ { false, 0x627b, 0x627b }, +/* 0x627c */ { false, 0x627c, 0x627c }, +/* 0x627d */ { false, 0x627d, 0x627d }, +/* 0x627e */ { false, 0x627e, 0x627e }, +/* 0x627f */ { false, 0x627f, 0x627f }, +/* 0x6280 */ { false, 0x6280, 0x6280 }, +/* 0x6281 */ { false, 0x6281, 0x6281 }, +/* 0x6282 */ { false, 0x6282, 0x6282 }, +/* 0x6283 */ { false, 0x6283, 0x6283 }, +/* 0x6284 */ { false, 0x6284, 0x6284 }, +/* 0x6285 */ { false, 0x6285, 0x6285 }, +/* 0x6286 */ { false, 0x6286, 0x6286 }, +/* 0x6287 */ { false, 0x6287, 0x6287 }, +/* 0x6288 */ { false, 0x6288, 0x6288 }, +/* 0x6289 */ { false, 0x6289, 0x6289 }, +/* 0x628a */ { false, 0x628a, 0x628a }, +/* 0x628b */ { false, 0x628b, 0x628b }, +/* 0x628c */ { false, 0x628c, 0x628c }, +/* 0x628d */ { false, 0x628d, 0x628d }, +/* 0x628e */ { false, 0x628e, 0x628e }, +/* 0x628f */ { false, 0x628f, 0x628f }, +/* 0x6290 */ { false, 0x6290, 0x6290 }, +/* 0x6291 */ { false, 0x6291, 0x6291 }, +/* 0x6292 */ { false, 0x6292, 0x6292 }, +/* 0x6293 */ { false, 0x6293, 0x6293 }, +/* 0x6294 */ { false, 0x6294, 0x6294 }, +/* 0x6295 */ { false, 0x6295, 0x6295 }, +/* 0x6296 */ { false, 0x6296, 0x6296 }, +/* 0x6297 */ { false, 0x6297, 0x6297 }, +/* 0x6298 */ { false, 0x6298, 0x6298 }, +/* 0x6299 */ { false, 0x6299, 0x6299 }, +/* 0x629a */ { false, 0x629a, 0x629a }, +/* 0x629b */ { false, 0x629b, 0x629b }, +/* 0x629c */ { false, 0x629c, 0x629c }, +/* 0x629d */ { false, 0x629d, 0x629d }, +/* 0x629e */ { false, 0x629e, 0x629e }, +/* 0x629f */ { false, 0x629f, 0x629f }, +/* 0x62a0 */ { false, 0x62a0, 0x62a0 }, +/* 0x62a1 */ { false, 0x62a1, 0x62a1 }, +/* 0x62a2 */ { false, 0x62a2, 0x62a2 }, +/* 0x62a3 */ { false, 0x62a3, 0x62a3 }, +/* 0x62a4 */ { false, 0x62a4, 0x62a4 }, +/* 0x62a5 */ { false, 0x62a5, 0x62a5 }, +/* 0x62a6 */ { false, 0x62a6, 0x62a6 }, +/* 0x62a7 */ { false, 0x62a7, 0x62a7 }, +/* 0x62a8 */ { false, 0x62a8, 0x62a8 }, +/* 0x62a9 */ { false, 0x62a9, 0x62a9 }, +/* 0x62aa */ { false, 0x62aa, 0x62aa }, +/* 0x62ab */ { false, 0x62ab, 0x62ab }, +/* 0x62ac */ { false, 0x62ac, 0x62ac }, +/* 0x62ad */ { false, 0x62ad, 0x62ad }, +/* 0x62ae */ { false, 0x62ae, 0x62ae }, +/* 0x62af */ { false, 0x62af, 0x62af }, +/* 0x62b0 */ { false, 0x62b0, 0x62b0 }, +/* 0x62b1 */ { false, 0x62b1, 0x62b1 }, +/* 0x62b2 */ { false, 0x62b2, 0x62b2 }, +/* 0x62b3 */ { false, 0x62b3, 0x62b3 }, +/* 0x62b4 */ { false, 0x62b4, 0x62b4 }, +/* 0x62b5 */ { false, 0x62b5, 0x62b5 }, +/* 0x62b6 */ { false, 0x62b6, 0x62b6 }, +/* 0x62b7 */ { false, 0x62b7, 0x62b7 }, +/* 0x62b8 */ { false, 0x62b8, 0x62b8 }, +/* 0x62b9 */ { false, 0x62b9, 0x62b9 }, +/* 0x62ba */ { false, 0x62ba, 0x62ba }, +/* 0x62bb */ { false, 0x62bb, 0x62bb }, +/* 0x62bc */ { false, 0x62bc, 0x62bc }, +/* 0x62bd */ { false, 0x62bd, 0x62bd }, +/* 0x62be */ { false, 0x62be, 0x62be }, +/* 0x62bf */ { false, 0x62bf, 0x62bf }, +/* 0x62c0 */ { false, 0x62c0, 0x62c0 }, +/* 0x62c1 */ { false, 0x62c1, 0x62c1 }, +/* 0x62c2 */ { false, 0x62c2, 0x62c2 }, +/* 0x62c3 */ { false, 0x62c3, 0x62c3 }, +/* 0x62c4 */ { false, 0x62c4, 0x62c4 }, +/* 0x62c5 */ { false, 0x62c5, 0x62c5 }, +/* 0x62c6 */ { false, 0x62c6, 0x62c6 }, +/* 0x62c7 */ { false, 0x62c7, 0x62c7 }, +/* 0x62c8 */ { false, 0x62c8, 0x62c8 }, +/* 0x62c9 */ { false, 0x62c9, 0x62c9 }, +/* 0x62ca */ { false, 0x62ca, 0x62ca }, +/* 0x62cb */ { false, 0x62cb, 0x62cb }, +/* 0x62cc */ { false, 0x62cc, 0x62cc }, +/* 0x62cd */ { false, 0x62cd, 0x62cd }, +/* 0x62ce */ { false, 0x62ce, 0x62ce }, +/* 0x62cf */ { false, 0x62cf, 0x62cf }, +/* 0x62d0 */ { false, 0x62d0, 0x62d0 }, +/* 0x62d1 */ { false, 0x62d1, 0x62d1 }, +/* 0x62d2 */ { false, 0x62d2, 0x62d2 }, +/* 0x62d3 */ { false, 0x62d3, 0x62d3 }, +/* 0x62d4 */ { false, 0x62d4, 0x62d4 }, +/* 0x62d5 */ { false, 0x62d5, 0x62d5 }, +/* 0x62d6 */ { false, 0x62d6, 0x62d6 }, +/* 0x62d7 */ { false, 0x62d7, 0x62d7 }, +/* 0x62d8 */ { false, 0x62d8, 0x62d8 }, +/* 0x62d9 */ { false, 0x62d9, 0x62d9 }, +/* 0x62da */ { false, 0x62da, 0x62da }, +/* 0x62db */ { false, 0x62db, 0x62db }, +/* 0x62dc */ { false, 0x62dc, 0x62dc }, +/* 0x62dd */ { false, 0x62dd, 0x62dd }, +/* 0x62de */ { false, 0x62de, 0x62de }, +/* 0x62df */ { false, 0x62df, 0x62df }, +/* 0x62e0 */ { false, 0x62e0, 0x62e0 }, +/* 0x62e1 */ { false, 0x62e1, 0x62e1 }, +/* 0x62e2 */ { false, 0x62e2, 0x62e2 }, +/* 0x62e3 */ { false, 0x62e3, 0x62e3 }, +/* 0x62e4 */ { false, 0x62e4, 0x62e4 }, +/* 0x62e5 */ { false, 0x62e5, 0x62e5 }, +/* 0x62e6 */ { false, 0x62e6, 0x62e6 }, +/* 0x62e7 */ { false, 0x62e7, 0x62e7 }, +/* 0x62e8 */ { false, 0x62e8, 0x62e8 }, +/* 0x62e9 */ { false, 0x62e9, 0x62e9 }, +/* 0x62ea */ { false, 0x62ea, 0x62ea }, +/* 0x62eb */ { false, 0x62eb, 0x62eb }, +/* 0x62ec */ { false, 0x62ec, 0x62ec }, +/* 0x62ed */ { false, 0x62ed, 0x62ed }, +/* 0x62ee */ { false, 0x62ee, 0x62ee }, +/* 0x62ef */ { false, 0x62ef, 0x62ef }, +/* 0x62f0 */ { false, 0x62f0, 0x62f0 }, +/* 0x62f1 */ { false, 0x62f1, 0x62f1 }, +/* 0x62f2 */ { false, 0x62f2, 0x62f2 }, +/* 0x62f3 */ { false, 0x62f3, 0x62f3 }, +/* 0x62f4 */ { false, 0x62f4, 0x62f4 }, +/* 0x62f5 */ { false, 0x62f5, 0x62f5 }, +/* 0x62f6 */ { false, 0x62f6, 0x62f6 }, +/* 0x62f7 */ { false, 0x62f7, 0x62f7 }, +/* 0x62f8 */ { false, 0x62f8, 0x62f8 }, +/* 0x62f9 */ { false, 0x62f9, 0x62f9 }, +/* 0x62fa */ { false, 0x62fa, 0x62fa }, +/* 0x62fb */ { false, 0x62fb, 0x62fb }, +/* 0x62fc */ { false, 0x62fc, 0x62fc }, +/* 0x62fd */ { false, 0x62fd, 0x62fd }, +/* 0x62fe */ { false, 0x62fe, 0x62fe }, +/* 0x62ff */ { false, 0x62ff, 0x62ff }, +/* 0x6300 */ { false, 0x6300, 0x6300 }, +/* 0x6301 */ { false, 0x6301, 0x6301 }, +/* 0x6302 */ { false, 0x6302, 0x6302 }, +/* 0x6303 */ { false, 0x6303, 0x6303 }, +/* 0x6304 */ { false, 0x6304, 0x6304 }, +/* 0x6305 */ { false, 0x6305, 0x6305 }, +/* 0x6306 */ { false, 0x6306, 0x6306 }, +/* 0x6307 */ { false, 0x6307, 0x6307 }, +/* 0x6308 */ { false, 0x6308, 0x6308 }, +/* 0x6309 */ { false, 0x6309, 0x6309 }, +/* 0x630a */ { false, 0x630a, 0x630a }, +/* 0x630b */ { false, 0x630b, 0x630b }, +/* 0x630c */ { false, 0x630c, 0x630c }, +/* 0x630d */ { false, 0x630d, 0x630d }, +/* 0x630e */ { false, 0x630e, 0x630e }, +/* 0x630f */ { false, 0x630f, 0x630f }, +/* 0x6310 */ { false, 0x6310, 0x6310 }, +/* 0x6311 */ { false, 0x6311, 0x6311 }, +/* 0x6312 */ { false, 0x6312, 0x6312 }, +/* 0x6313 */ { false, 0x6313, 0x6313 }, +/* 0x6314 */ { false, 0x6314, 0x6314 }, +/* 0x6315 */ { false, 0x6315, 0x6315 }, +/* 0x6316 */ { false, 0x6316, 0x6316 }, +/* 0x6317 */ { false, 0x6317, 0x6317 }, +/* 0x6318 */ { false, 0x6318, 0x6318 }, +/* 0x6319 */ { false, 0x6319, 0x6319 }, +/* 0x631a */ { false, 0x631a, 0x631a }, +/* 0x631b */ { false, 0x631b, 0x631b }, +/* 0x631c */ { false, 0x631c, 0x631c }, +/* 0x631d */ { false, 0x631d, 0x631d }, +/* 0x631e */ { false, 0x631e, 0x631e }, +/* 0x631f */ { false, 0x631f, 0x631f }, +/* 0x6320 */ { false, 0x6320, 0x6320 }, +/* 0x6321 */ { false, 0x6321, 0x6321 }, +/* 0x6322 */ { false, 0x6322, 0x6322 }, +/* 0x6323 */ { false, 0x6323, 0x6323 }, +/* 0x6324 */ { false, 0x6324, 0x6324 }, +/* 0x6325 */ { false, 0x6325, 0x6325 }, +/* 0x6326 */ { false, 0x6326, 0x6326 }, +/* 0x6327 */ { false, 0x6327, 0x6327 }, +/* 0x6328 */ { false, 0x6328, 0x6328 }, +/* 0x6329 */ { false, 0x6329, 0x6329 }, +/* 0x632a */ { false, 0x632a, 0x632a }, +/* 0x632b */ { false, 0x632b, 0x632b }, +/* 0x632c */ { false, 0x632c, 0x632c }, +/* 0x632d */ { false, 0x632d, 0x632d }, +/* 0x632e */ { false, 0x632e, 0x632e }, +/* 0x632f */ { false, 0x632f, 0x632f }, +/* 0x6330 */ { false, 0x6330, 0x6330 }, +/* 0x6331 */ { false, 0x6331, 0x6331 }, +/* 0x6332 */ { false, 0x6332, 0x6332 }, +/* 0x6333 */ { false, 0x6333, 0x6333 }, +/* 0x6334 */ { false, 0x6334, 0x6334 }, +/* 0x6335 */ { false, 0x6335, 0x6335 }, +/* 0x6336 */ { false, 0x6336, 0x6336 }, +/* 0x6337 */ { false, 0x6337, 0x6337 }, +/* 0x6338 */ { false, 0x6338, 0x6338 }, +/* 0x6339 */ { false, 0x6339, 0x6339 }, +/* 0x633a */ { false, 0x633a, 0x633a }, +/* 0x633b */ { false, 0x633b, 0x633b }, +/* 0x633c */ { false, 0x633c, 0x633c }, +/* 0x633d */ { false, 0x633d, 0x633d }, +/* 0x633e */ { false, 0x633e, 0x633e }, +/* 0x633f */ { false, 0x633f, 0x633f }, +/* 0x6340 */ { false, 0x6340, 0x6340 }, +/* 0x6341 */ { false, 0x6341, 0x6341 }, +/* 0x6342 */ { false, 0x6342, 0x6342 }, +/* 0x6343 */ { false, 0x6343, 0x6343 }, +/* 0x6344 */ { false, 0x6344, 0x6344 }, +/* 0x6345 */ { false, 0x6345, 0x6345 }, +/* 0x6346 */ { false, 0x6346, 0x6346 }, +/* 0x6347 */ { false, 0x6347, 0x6347 }, +/* 0x6348 */ { false, 0x6348, 0x6348 }, +/* 0x6349 */ { false, 0x6349, 0x6349 }, +/* 0x634a */ { false, 0x634a, 0x634a }, +/* 0x634b */ { false, 0x634b, 0x634b }, +/* 0x634c */ { false, 0x634c, 0x634c }, +/* 0x634d */ { false, 0x634d, 0x634d }, +/* 0x634e */ { false, 0x634e, 0x634e }, +/* 0x634f */ { false, 0x634f, 0x634f }, +/* 0x6350 */ { false, 0x6350, 0x6350 }, +/* 0x6351 */ { false, 0x6351, 0x6351 }, +/* 0x6352 */ { false, 0x6352, 0x6352 }, +/* 0x6353 */ { false, 0x6353, 0x6353 }, +/* 0x6354 */ { false, 0x6354, 0x6354 }, +/* 0x6355 */ { false, 0x6355, 0x6355 }, +/* 0x6356 */ { false, 0x6356, 0x6356 }, +/* 0x6357 */ { false, 0x6357, 0x6357 }, +/* 0x6358 */ { false, 0x6358, 0x6358 }, +/* 0x6359 */ { false, 0x6359, 0x6359 }, +/* 0x635a */ { false, 0x635a, 0x635a }, +/* 0x635b */ { false, 0x635b, 0x635b }, +/* 0x635c */ { false, 0x635c, 0x635c }, +/* 0x635d */ { false, 0x635d, 0x635d }, +/* 0x635e */ { false, 0x635e, 0x635e }, +/* 0x635f */ { false, 0x635f, 0x635f }, +/* 0x6360 */ { false, 0x6360, 0x6360 }, +/* 0x6361 */ { false, 0x6361, 0x6361 }, +/* 0x6362 */ { false, 0x6362, 0x6362 }, +/* 0x6363 */ { false, 0x6363, 0x6363 }, +/* 0x6364 */ { false, 0x6364, 0x6364 }, +/* 0x6365 */ { false, 0x6365, 0x6365 }, +/* 0x6366 */ { false, 0x6366, 0x6366 }, +/* 0x6367 */ { false, 0x6367, 0x6367 }, +/* 0x6368 */ { false, 0x6368, 0x6368 }, +/* 0x6369 */ { false, 0x6369, 0x6369 }, +/* 0x636a */ { false, 0x636a, 0x636a }, +/* 0x636b */ { false, 0x636b, 0x636b }, +/* 0x636c */ { false, 0x636c, 0x636c }, +/* 0x636d */ { false, 0x636d, 0x636d }, +/* 0x636e */ { false, 0x636e, 0x636e }, +/* 0x636f */ { false, 0x636f, 0x636f }, +/* 0x6370 */ { false, 0x6370, 0x6370 }, +/* 0x6371 */ { false, 0x6371, 0x6371 }, +/* 0x6372 */ { false, 0x6372, 0x6372 }, +/* 0x6373 */ { false, 0x6373, 0x6373 }, +/* 0x6374 */ { false, 0x6374, 0x6374 }, +/* 0x6375 */ { false, 0x6375, 0x6375 }, +/* 0x6376 */ { false, 0x6376, 0x6376 }, +/* 0x6377 */ { false, 0x6377, 0x6377 }, +/* 0x6378 */ { false, 0x6378, 0x6378 }, +/* 0x6379 */ { false, 0x6379, 0x6379 }, +/* 0x637a */ { false, 0x637a, 0x637a }, +/* 0x637b */ { false, 0x637b, 0x637b }, +/* 0x637c */ { false, 0x637c, 0x637c }, +/* 0x637d */ { false, 0x637d, 0x637d }, +/* 0x637e */ { false, 0x637e, 0x637e }, +/* 0x637f */ { false, 0x637f, 0x637f }, +/* 0x6380 */ { false, 0x6380, 0x6380 }, +/* 0x6381 */ { false, 0x6381, 0x6381 }, +/* 0x6382 */ { false, 0x6382, 0x6382 }, +/* 0x6383 */ { false, 0x6383, 0x6383 }, +/* 0x6384 */ { false, 0x6384, 0x6384 }, +/* 0x6385 */ { false, 0x6385, 0x6385 }, +/* 0x6386 */ { false, 0x6386, 0x6386 }, +/* 0x6387 */ { false, 0x6387, 0x6387 }, +/* 0x6388 */ { false, 0x6388, 0x6388 }, +/* 0x6389 */ { false, 0x6389, 0x6389 }, +/* 0x638a */ { false, 0x638a, 0x638a }, +/* 0x638b */ { false, 0x638b, 0x638b }, +/* 0x638c */ { false, 0x638c, 0x638c }, +/* 0x638d */ { false, 0x638d, 0x638d }, +/* 0x638e */ { false, 0x638e, 0x638e }, +/* 0x638f */ { false, 0x638f, 0x638f }, +/* 0x6390 */ { false, 0x6390, 0x6390 }, +/* 0x6391 */ { false, 0x6391, 0x6391 }, +/* 0x6392 */ { false, 0x6392, 0x6392 }, +/* 0x6393 */ { false, 0x6393, 0x6393 }, +/* 0x6394 */ { false, 0x6394, 0x6394 }, +/* 0x6395 */ { false, 0x6395, 0x6395 }, +/* 0x6396 */ { false, 0x6396, 0x6396 }, +/* 0x6397 */ { false, 0x6397, 0x6397 }, +/* 0x6398 */ { false, 0x6398, 0x6398 }, +/* 0x6399 */ { false, 0x6399, 0x6399 }, +/* 0x639a */ { false, 0x639a, 0x639a }, +/* 0x639b */ { false, 0x639b, 0x639b }, +/* 0x639c */ { false, 0x639c, 0x639c }, +/* 0x639d */ { false, 0x639d, 0x639d }, +/* 0x639e */ { false, 0x639e, 0x639e }, +/* 0x639f */ { false, 0x639f, 0x639f }, +/* 0x63a0 */ { false, 0x63a0, 0x63a0 }, +/* 0x63a1 */ { false, 0x63a1, 0x63a1 }, +/* 0x63a2 */ { false, 0x63a2, 0x63a2 }, +/* 0x63a3 */ { false, 0x63a3, 0x63a3 }, +/* 0x63a4 */ { false, 0x63a4, 0x63a4 }, +/* 0x63a5 */ { false, 0x63a5, 0x63a5 }, +/* 0x63a6 */ { false, 0x63a6, 0x63a6 }, +/* 0x63a7 */ { false, 0x63a7, 0x63a7 }, +/* 0x63a8 */ { false, 0x63a8, 0x63a8 }, +/* 0x63a9 */ { false, 0x63a9, 0x63a9 }, +/* 0x63aa */ { false, 0x63aa, 0x63aa }, +/* 0x63ab */ { false, 0x63ab, 0x63ab }, +/* 0x63ac */ { false, 0x63ac, 0x63ac }, +/* 0x63ad */ { false, 0x63ad, 0x63ad }, +/* 0x63ae */ { false, 0x63ae, 0x63ae }, +/* 0x63af */ { false, 0x63af, 0x63af }, +/* 0x63b0 */ { false, 0x63b0, 0x63b0 }, +/* 0x63b1 */ { false, 0x63b1, 0x63b1 }, +/* 0x63b2 */ { false, 0x63b2, 0x63b2 }, +/* 0x63b3 */ { false, 0x63b3, 0x63b3 }, +/* 0x63b4 */ { false, 0x63b4, 0x63b4 }, +/* 0x63b5 */ { false, 0x63b5, 0x63b5 }, +/* 0x63b6 */ { false, 0x63b6, 0x63b6 }, +/* 0x63b7 */ { false, 0x63b7, 0x63b7 }, +/* 0x63b8 */ { false, 0x63b8, 0x63b8 }, +/* 0x63b9 */ { false, 0x63b9, 0x63b9 }, +/* 0x63ba */ { false, 0x63ba, 0x63ba }, +/* 0x63bb */ { false, 0x63bb, 0x63bb }, +/* 0x63bc */ { false, 0x63bc, 0x63bc }, +/* 0x63bd */ { false, 0x63bd, 0x63bd }, +/* 0x63be */ { false, 0x63be, 0x63be }, +/* 0x63bf */ { false, 0x63bf, 0x63bf }, +/* 0x63c0 */ { false, 0x63c0, 0x63c0 }, +/* 0x63c1 */ { false, 0x63c1, 0x63c1 }, +/* 0x63c2 */ { false, 0x63c2, 0x63c2 }, +/* 0x63c3 */ { false, 0x63c3, 0x63c3 }, +/* 0x63c4 */ { false, 0x63c4, 0x63c4 }, +/* 0x63c5 */ { false, 0x63c5, 0x63c5 }, +/* 0x63c6 */ { false, 0x63c6, 0x63c6 }, +/* 0x63c7 */ { false, 0x63c7, 0x63c7 }, +/* 0x63c8 */ { false, 0x63c8, 0x63c8 }, +/* 0x63c9 */ { false, 0x63c9, 0x63c9 }, +/* 0x63ca */ { false, 0x63ca, 0x63ca }, +/* 0x63cb */ { false, 0x63cb, 0x63cb }, +/* 0x63cc */ { false, 0x63cc, 0x63cc }, +/* 0x63cd */ { false, 0x63cd, 0x63cd }, +/* 0x63ce */ { false, 0x63ce, 0x63ce }, +/* 0x63cf */ { false, 0x63cf, 0x63cf }, +/* 0x63d0 */ { false, 0x63d0, 0x63d0 }, +/* 0x63d1 */ { false, 0x63d1, 0x63d1 }, +/* 0x63d2 */ { false, 0x63d2, 0x63d2 }, +/* 0x63d3 */ { false, 0x63d3, 0x63d3 }, +/* 0x63d4 */ { false, 0x63d4, 0x63d4 }, +/* 0x63d5 */ { false, 0x63d5, 0x63d5 }, +/* 0x63d6 */ { false, 0x63d6, 0x63d6 }, +/* 0x63d7 */ { false, 0x63d7, 0x63d7 }, +/* 0x63d8 */ { false, 0x63d8, 0x63d8 }, +/* 0x63d9 */ { false, 0x63d9, 0x63d9 }, +/* 0x63da */ { false, 0x63da, 0x63da }, +/* 0x63db */ { false, 0x63db, 0x63db }, +/* 0x63dc */ { false, 0x63dc, 0x63dc }, +/* 0x63dd */ { false, 0x63dd, 0x63dd }, +/* 0x63de */ { false, 0x63de, 0x63de }, +/* 0x63df */ { false, 0x63df, 0x63df }, +/* 0x63e0 */ { false, 0x63e0, 0x63e0 }, +/* 0x63e1 */ { false, 0x63e1, 0x63e1 }, +/* 0x63e2 */ { false, 0x63e2, 0x63e2 }, +/* 0x63e3 */ { false, 0x63e3, 0x63e3 }, +/* 0x63e4 */ { false, 0x63e4, 0x63e4 }, +/* 0x63e5 */ { false, 0x63e5, 0x63e5 }, +/* 0x63e6 */ { false, 0x63e6, 0x63e6 }, +/* 0x63e7 */ { false, 0x63e7, 0x63e7 }, +/* 0x63e8 */ { false, 0x63e8, 0x63e8 }, +/* 0x63e9 */ { false, 0x63e9, 0x63e9 }, +/* 0x63ea */ { false, 0x63ea, 0x63ea }, +/* 0x63eb */ { false, 0x63eb, 0x63eb }, +/* 0x63ec */ { false, 0x63ec, 0x63ec }, +/* 0x63ed */ { false, 0x63ed, 0x63ed }, +/* 0x63ee */ { false, 0x63ee, 0x63ee }, +/* 0x63ef */ { false, 0x63ef, 0x63ef }, +/* 0x63f0 */ { false, 0x63f0, 0x63f0 }, +/* 0x63f1 */ { false, 0x63f1, 0x63f1 }, +/* 0x63f2 */ { false, 0x63f2, 0x63f2 }, +/* 0x63f3 */ { false, 0x63f3, 0x63f3 }, +/* 0x63f4 */ { false, 0x63f4, 0x63f4 }, +/* 0x63f5 */ { false, 0x63f5, 0x63f5 }, +/* 0x63f6 */ { false, 0x63f6, 0x63f6 }, +/* 0x63f7 */ { false, 0x63f7, 0x63f7 }, +/* 0x63f8 */ { false, 0x63f8, 0x63f8 }, +/* 0x63f9 */ { false, 0x63f9, 0x63f9 }, +/* 0x63fa */ { false, 0x63fa, 0x63fa }, +/* 0x63fb */ { false, 0x63fb, 0x63fb }, +/* 0x63fc */ { false, 0x63fc, 0x63fc }, +/* 0x63fd */ { false, 0x63fd, 0x63fd }, +/* 0x63fe */ { false, 0x63fe, 0x63fe }, +/* 0x63ff */ { false, 0x63ff, 0x63ff }, +/* 0x6400 */ { false, 0x6400, 0x6400 }, +/* 0x6401 */ { false, 0x6401, 0x6401 }, +/* 0x6402 */ { false, 0x6402, 0x6402 }, +/* 0x6403 */ { false, 0x6403, 0x6403 }, +/* 0x6404 */ { false, 0x6404, 0x6404 }, +/* 0x6405 */ { false, 0x6405, 0x6405 }, +/* 0x6406 */ { false, 0x6406, 0x6406 }, +/* 0x6407 */ { false, 0x6407, 0x6407 }, +/* 0x6408 */ { false, 0x6408, 0x6408 }, +/* 0x6409 */ { false, 0x6409, 0x6409 }, +/* 0x640a */ { false, 0x640a, 0x640a }, +/* 0x640b */ { false, 0x640b, 0x640b }, +/* 0x640c */ { false, 0x640c, 0x640c }, +/* 0x640d */ { false, 0x640d, 0x640d }, +/* 0x640e */ { false, 0x640e, 0x640e }, +/* 0x640f */ { false, 0x640f, 0x640f }, +/* 0x6410 */ { false, 0x6410, 0x6410 }, +/* 0x6411 */ { false, 0x6411, 0x6411 }, +/* 0x6412 */ { false, 0x6412, 0x6412 }, +/* 0x6413 */ { false, 0x6413, 0x6413 }, +/* 0x6414 */ { false, 0x6414, 0x6414 }, +/* 0x6415 */ { false, 0x6415, 0x6415 }, +/* 0x6416 */ { false, 0x6416, 0x6416 }, +/* 0x6417 */ { false, 0x6417, 0x6417 }, +/* 0x6418 */ { false, 0x6418, 0x6418 }, +/* 0x6419 */ { false, 0x6419, 0x6419 }, +/* 0x641a */ { false, 0x641a, 0x641a }, +/* 0x641b */ { false, 0x641b, 0x641b }, +/* 0x641c */ { false, 0x641c, 0x641c }, +/* 0x641d */ { false, 0x641d, 0x641d }, +/* 0x641e */ { false, 0x641e, 0x641e }, +/* 0x641f */ { false, 0x641f, 0x641f }, +/* 0x6420 */ { false, 0x6420, 0x6420 }, +/* 0x6421 */ { false, 0x6421, 0x6421 }, +/* 0x6422 */ { false, 0x6422, 0x6422 }, +/* 0x6423 */ { false, 0x6423, 0x6423 }, +/* 0x6424 */ { false, 0x6424, 0x6424 }, +/* 0x6425 */ { false, 0x6425, 0x6425 }, +/* 0x6426 */ { false, 0x6426, 0x6426 }, +/* 0x6427 */ { false, 0x6427, 0x6427 }, +/* 0x6428 */ { false, 0x6428, 0x6428 }, +/* 0x6429 */ { false, 0x6429, 0x6429 }, +/* 0x642a */ { false, 0x642a, 0x642a }, +/* 0x642b */ { false, 0x642b, 0x642b }, +/* 0x642c */ { false, 0x642c, 0x642c }, +/* 0x642d */ { false, 0x642d, 0x642d }, +/* 0x642e */ { false, 0x642e, 0x642e }, +/* 0x642f */ { false, 0x642f, 0x642f }, +/* 0x6430 */ { false, 0x6430, 0x6430 }, +/* 0x6431 */ { false, 0x6431, 0x6431 }, +/* 0x6432 */ { false, 0x6432, 0x6432 }, +/* 0x6433 */ { false, 0x6433, 0x6433 }, +/* 0x6434 */ { false, 0x6434, 0x6434 }, +/* 0x6435 */ { false, 0x6435, 0x6435 }, +/* 0x6436 */ { false, 0x6436, 0x6436 }, +/* 0x6437 */ { false, 0x6437, 0x6437 }, +/* 0x6438 */ { false, 0x6438, 0x6438 }, +/* 0x6439 */ { false, 0x6439, 0x6439 }, +/* 0x643a */ { false, 0x643a, 0x643a }, +/* 0x643b */ { false, 0x643b, 0x643b }, +/* 0x643c */ { false, 0x643c, 0x643c }, +/* 0x643d */ { false, 0x643d, 0x643d }, +/* 0x643e */ { false, 0x643e, 0x643e }, +/* 0x643f */ { false, 0x643f, 0x643f }, +/* 0x6440 */ { false, 0x6440, 0x6440 }, +/* 0x6441 */ { false, 0x6441, 0x6441 }, +/* 0x6442 */ { false, 0x6442, 0x6442 }, +/* 0x6443 */ { false, 0x6443, 0x6443 }, +/* 0x6444 */ { false, 0x6444, 0x6444 }, +/* 0x6445 */ { false, 0x6445, 0x6445 }, +/* 0x6446 */ { false, 0x6446, 0x6446 }, +/* 0x6447 */ { false, 0x6447, 0x6447 }, +/* 0x6448 */ { false, 0x6448, 0x6448 }, +/* 0x6449 */ { false, 0x6449, 0x6449 }, +/* 0x644a */ { false, 0x644a, 0x644a }, +/* 0x644b */ { false, 0x644b, 0x644b }, +/* 0x644c */ { false, 0x644c, 0x644c }, +/* 0x644d */ { false, 0x644d, 0x644d }, +/* 0x644e */ { false, 0x644e, 0x644e }, +/* 0x644f */ { false, 0x644f, 0x644f }, +/* 0x6450 */ { false, 0x6450, 0x6450 }, +/* 0x6451 */ { false, 0x6451, 0x6451 }, +/* 0x6452 */ { false, 0x6452, 0x6452 }, +/* 0x6453 */ { false, 0x6453, 0x6453 }, +/* 0x6454 */ { false, 0x6454, 0x6454 }, +/* 0x6455 */ { false, 0x6455, 0x6455 }, +/* 0x6456 */ { false, 0x6456, 0x6456 }, +/* 0x6457 */ { false, 0x6457, 0x6457 }, +/* 0x6458 */ { false, 0x6458, 0x6458 }, +/* 0x6459 */ { false, 0x6459, 0x6459 }, +/* 0x645a */ { false, 0x645a, 0x645a }, +/* 0x645b */ { false, 0x645b, 0x645b }, +/* 0x645c */ { false, 0x645c, 0x645c }, +/* 0x645d */ { false, 0x645d, 0x645d }, +/* 0x645e */ { false, 0x645e, 0x645e }, +/* 0x645f */ { false, 0x645f, 0x645f }, +/* 0x6460 */ { false, 0x6460, 0x6460 }, +/* 0x6461 */ { false, 0x6461, 0x6461 }, +/* 0x6462 */ { false, 0x6462, 0x6462 }, +/* 0x6463 */ { false, 0x6463, 0x6463 }, +/* 0x6464 */ { false, 0x6464, 0x6464 }, +/* 0x6465 */ { false, 0x6465, 0x6465 }, +/* 0x6466 */ { false, 0x6466, 0x6466 }, +/* 0x6467 */ { false, 0x6467, 0x6467 }, +/* 0x6468 */ { false, 0x6468, 0x6468 }, +/* 0x6469 */ { false, 0x6469, 0x6469 }, +/* 0x646a */ { false, 0x646a, 0x646a }, +/* 0x646b */ { false, 0x646b, 0x646b }, +/* 0x646c */ { false, 0x646c, 0x646c }, +/* 0x646d */ { false, 0x646d, 0x646d }, +/* 0x646e */ { false, 0x646e, 0x646e }, +/* 0x646f */ { false, 0x646f, 0x646f }, +/* 0x6470 */ { false, 0x6470, 0x6470 }, +/* 0x6471 */ { false, 0x6471, 0x6471 }, +/* 0x6472 */ { false, 0x6472, 0x6472 }, +/* 0x6473 */ { false, 0x6473, 0x6473 }, +/* 0x6474 */ { false, 0x6474, 0x6474 }, +/* 0x6475 */ { false, 0x6475, 0x6475 }, +/* 0x6476 */ { false, 0x6476, 0x6476 }, +/* 0x6477 */ { false, 0x6477, 0x6477 }, +/* 0x6478 */ { false, 0x6478, 0x6478 }, +/* 0x6479 */ { false, 0x6479, 0x6479 }, +/* 0x647a */ { false, 0x647a, 0x647a }, +/* 0x647b */ { false, 0x647b, 0x647b }, +/* 0x647c */ { false, 0x647c, 0x647c }, +/* 0x647d */ { false, 0x647d, 0x647d }, +/* 0x647e */ { false, 0x647e, 0x647e }, +/* 0x647f */ { false, 0x647f, 0x647f }, +/* 0x6480 */ { false, 0x6480, 0x6480 }, +/* 0x6481 */ { false, 0x6481, 0x6481 }, +/* 0x6482 */ { false, 0x6482, 0x6482 }, +/* 0x6483 */ { false, 0x6483, 0x6483 }, +/* 0x6484 */ { false, 0x6484, 0x6484 }, +/* 0x6485 */ { false, 0x6485, 0x6485 }, +/* 0x6486 */ { false, 0x6486, 0x6486 }, +/* 0x6487 */ { false, 0x6487, 0x6487 }, +/* 0x6488 */ { false, 0x6488, 0x6488 }, +/* 0x6489 */ { false, 0x6489, 0x6489 }, +/* 0x648a */ { false, 0x648a, 0x648a }, +/* 0x648b */ { false, 0x648b, 0x648b }, +/* 0x648c */ { false, 0x648c, 0x648c }, +/* 0x648d */ { false, 0x648d, 0x648d }, +/* 0x648e */ { false, 0x648e, 0x648e }, +/* 0x648f */ { false, 0x648f, 0x648f }, +/* 0x6490 */ { false, 0x6490, 0x6490 }, +/* 0x6491 */ { false, 0x6491, 0x6491 }, +/* 0x6492 */ { false, 0x6492, 0x6492 }, +/* 0x6493 */ { false, 0x6493, 0x6493 }, +/* 0x6494 */ { false, 0x6494, 0x6494 }, +/* 0x6495 */ { false, 0x6495, 0x6495 }, +/* 0x6496 */ { false, 0x6496, 0x6496 }, +/* 0x6497 */ { false, 0x6497, 0x6497 }, +/* 0x6498 */ { false, 0x6498, 0x6498 }, +/* 0x6499 */ { false, 0x6499, 0x6499 }, +/* 0x649a */ { false, 0x649a, 0x649a }, +/* 0x649b */ { false, 0x649b, 0x649b }, +/* 0x649c */ { false, 0x649c, 0x649c }, +/* 0x649d */ { false, 0x649d, 0x649d }, +/* 0x649e */ { false, 0x649e, 0x649e }, +/* 0x649f */ { false, 0x649f, 0x649f }, +/* 0x64a0 */ { false, 0x64a0, 0x64a0 }, +/* 0x64a1 */ { false, 0x64a1, 0x64a1 }, +/* 0x64a2 */ { false, 0x64a2, 0x64a2 }, +/* 0x64a3 */ { false, 0x64a3, 0x64a3 }, +/* 0x64a4 */ { false, 0x64a4, 0x64a4 }, +/* 0x64a5 */ { false, 0x64a5, 0x64a5 }, +/* 0x64a6 */ { false, 0x64a6, 0x64a6 }, +/* 0x64a7 */ { false, 0x64a7, 0x64a7 }, +/* 0x64a8 */ { false, 0x64a8, 0x64a8 }, +/* 0x64a9 */ { false, 0x64a9, 0x64a9 }, +/* 0x64aa */ { false, 0x64aa, 0x64aa }, +/* 0x64ab */ { false, 0x64ab, 0x64ab }, +/* 0x64ac */ { false, 0x64ac, 0x64ac }, +/* 0x64ad */ { false, 0x64ad, 0x64ad }, +/* 0x64ae */ { false, 0x64ae, 0x64ae }, +/* 0x64af */ { false, 0x64af, 0x64af }, +/* 0x64b0 */ { false, 0x64b0, 0x64b0 }, +/* 0x64b1 */ { false, 0x64b1, 0x64b1 }, +/* 0x64b2 */ { false, 0x64b2, 0x64b2 }, +/* 0x64b3 */ { false, 0x64b3, 0x64b3 }, +/* 0x64b4 */ { false, 0x64b4, 0x64b4 }, +/* 0x64b5 */ { false, 0x64b5, 0x64b5 }, +/* 0x64b6 */ { false, 0x64b6, 0x64b6 }, +/* 0x64b7 */ { false, 0x64b7, 0x64b7 }, +/* 0x64b8 */ { false, 0x64b8, 0x64b8 }, +/* 0x64b9 */ { false, 0x64b9, 0x64b9 }, +/* 0x64ba */ { false, 0x64ba, 0x64ba }, +/* 0x64bb */ { false, 0x64bb, 0x64bb }, +/* 0x64bc */ { false, 0x64bc, 0x64bc }, +/* 0x64bd */ { false, 0x64bd, 0x64bd }, +/* 0x64be */ { false, 0x64be, 0x64be }, +/* 0x64bf */ { false, 0x64bf, 0x64bf }, +/* 0x64c0 */ { false, 0x64c0, 0x64c0 }, +/* 0x64c1 */ { false, 0x64c1, 0x64c1 }, +/* 0x64c2 */ { false, 0x64c2, 0x64c2 }, +/* 0x64c3 */ { false, 0x64c3, 0x64c3 }, +/* 0x64c4 */ { false, 0x64c4, 0x64c4 }, +/* 0x64c5 */ { false, 0x64c5, 0x64c5 }, +/* 0x64c6 */ { false, 0x64c6, 0x64c6 }, +/* 0x64c7 */ { false, 0x64c7, 0x64c7 }, +/* 0x64c8 */ { false, 0x64c8, 0x64c8 }, +/* 0x64c9 */ { false, 0x64c9, 0x64c9 }, +/* 0x64ca */ { false, 0x64ca, 0x64ca }, +/* 0x64cb */ { false, 0x64cb, 0x64cb }, +/* 0x64cc */ { false, 0x64cc, 0x64cc }, +/* 0x64cd */ { false, 0x64cd, 0x64cd }, +/* 0x64ce */ { false, 0x64ce, 0x64ce }, +/* 0x64cf */ { false, 0x64cf, 0x64cf }, +/* 0x64d0 */ { false, 0x64d0, 0x64d0 }, +/* 0x64d1 */ { false, 0x64d1, 0x64d1 }, +/* 0x64d2 */ { false, 0x64d2, 0x64d2 }, +/* 0x64d3 */ { false, 0x64d3, 0x64d3 }, +/* 0x64d4 */ { false, 0x64d4, 0x64d4 }, +/* 0x64d5 */ { false, 0x64d5, 0x64d5 }, +/* 0x64d6 */ { false, 0x64d6, 0x64d6 }, +/* 0x64d7 */ { false, 0x64d7, 0x64d7 }, +/* 0x64d8 */ { false, 0x64d8, 0x64d8 }, +/* 0x64d9 */ { false, 0x64d9, 0x64d9 }, +/* 0x64da */ { false, 0x64da, 0x64da }, +/* 0x64db */ { false, 0x64db, 0x64db }, +/* 0x64dc */ { false, 0x64dc, 0x64dc }, +/* 0x64dd */ { false, 0x64dd, 0x64dd }, +/* 0x64de */ { false, 0x64de, 0x64de }, +/* 0x64df */ { false, 0x64df, 0x64df }, +/* 0x64e0 */ { false, 0x64e0, 0x64e0 }, +/* 0x64e1 */ { false, 0x64e1, 0x64e1 }, +/* 0x64e2 */ { false, 0x64e2, 0x64e2 }, +/* 0x64e3 */ { false, 0x64e3, 0x64e3 }, +/* 0x64e4 */ { false, 0x64e4, 0x64e4 }, +/* 0x64e5 */ { false, 0x64e5, 0x64e5 }, +/* 0x64e6 */ { false, 0x64e6, 0x64e6 }, +/* 0x64e7 */ { false, 0x64e7, 0x64e7 }, +/* 0x64e8 */ { false, 0x64e8, 0x64e8 }, +/* 0x64e9 */ { false, 0x64e9, 0x64e9 }, +/* 0x64ea */ { false, 0x64ea, 0x64ea }, +/* 0x64eb */ { false, 0x64eb, 0x64eb }, +/* 0x64ec */ { false, 0x64ec, 0x64ec }, +/* 0x64ed */ { false, 0x64ed, 0x64ed }, +/* 0x64ee */ { false, 0x64ee, 0x64ee }, +/* 0x64ef */ { false, 0x64ef, 0x64ef }, +/* 0x64f0 */ { false, 0x64f0, 0x64f0 }, +/* 0x64f1 */ { false, 0x64f1, 0x64f1 }, +/* 0x64f2 */ { false, 0x64f2, 0x64f2 }, +/* 0x64f3 */ { false, 0x64f3, 0x64f3 }, +/* 0x64f4 */ { false, 0x64f4, 0x64f4 }, +/* 0x64f5 */ { false, 0x64f5, 0x64f5 }, +/* 0x64f6 */ { false, 0x64f6, 0x64f6 }, +/* 0x64f7 */ { false, 0x64f7, 0x64f7 }, +/* 0x64f8 */ { false, 0x64f8, 0x64f8 }, +/* 0x64f9 */ { false, 0x64f9, 0x64f9 }, +/* 0x64fa */ { false, 0x64fa, 0x64fa }, +/* 0x64fb */ { false, 0x64fb, 0x64fb }, +/* 0x64fc */ { false, 0x64fc, 0x64fc }, +/* 0x64fd */ { false, 0x64fd, 0x64fd }, +/* 0x64fe */ { false, 0x64fe, 0x64fe }, +/* 0x64ff */ { false, 0x64ff, 0x64ff }, +/* 0x6500 */ { false, 0x6500, 0x6500 }, +/* 0x6501 */ { false, 0x6501, 0x6501 }, +/* 0x6502 */ { false, 0x6502, 0x6502 }, +/* 0x6503 */ { false, 0x6503, 0x6503 }, +/* 0x6504 */ { false, 0x6504, 0x6504 }, +/* 0x6505 */ { false, 0x6505, 0x6505 }, +/* 0x6506 */ { false, 0x6506, 0x6506 }, +/* 0x6507 */ { false, 0x6507, 0x6507 }, +/* 0x6508 */ { false, 0x6508, 0x6508 }, +/* 0x6509 */ { false, 0x6509, 0x6509 }, +/* 0x650a */ { false, 0x650a, 0x650a }, +/* 0x650b */ { false, 0x650b, 0x650b }, +/* 0x650c */ { false, 0x650c, 0x650c }, +/* 0x650d */ { false, 0x650d, 0x650d }, +/* 0x650e */ { false, 0x650e, 0x650e }, +/* 0x650f */ { false, 0x650f, 0x650f }, +/* 0x6510 */ { false, 0x6510, 0x6510 }, +/* 0x6511 */ { false, 0x6511, 0x6511 }, +/* 0x6512 */ { false, 0x6512, 0x6512 }, +/* 0x6513 */ { false, 0x6513, 0x6513 }, +/* 0x6514 */ { false, 0x6514, 0x6514 }, +/* 0x6515 */ { false, 0x6515, 0x6515 }, +/* 0x6516 */ { false, 0x6516, 0x6516 }, +/* 0x6517 */ { false, 0x6517, 0x6517 }, +/* 0x6518 */ { false, 0x6518, 0x6518 }, +/* 0x6519 */ { false, 0x6519, 0x6519 }, +/* 0x651a */ { false, 0x651a, 0x651a }, +/* 0x651b */ { false, 0x651b, 0x651b }, +/* 0x651c */ { false, 0x651c, 0x651c }, +/* 0x651d */ { false, 0x651d, 0x651d }, +/* 0x651e */ { false, 0x651e, 0x651e }, +/* 0x651f */ { false, 0x651f, 0x651f }, +/* 0x6520 */ { false, 0x6520, 0x6520 }, +/* 0x6521 */ { false, 0x6521, 0x6521 }, +/* 0x6522 */ { false, 0x6522, 0x6522 }, +/* 0x6523 */ { false, 0x6523, 0x6523 }, +/* 0x6524 */ { false, 0x6524, 0x6524 }, +/* 0x6525 */ { false, 0x6525, 0x6525 }, +/* 0x6526 */ { false, 0x6526, 0x6526 }, +/* 0x6527 */ { false, 0x6527, 0x6527 }, +/* 0x6528 */ { false, 0x6528, 0x6528 }, +/* 0x6529 */ { false, 0x6529, 0x6529 }, +/* 0x652a */ { false, 0x652a, 0x652a }, +/* 0x652b */ { false, 0x652b, 0x652b }, +/* 0x652c */ { false, 0x652c, 0x652c }, +/* 0x652d */ { false, 0x652d, 0x652d }, +/* 0x652e */ { false, 0x652e, 0x652e }, +/* 0x652f */ { false, 0x652f, 0x652f }, +/* 0x6530 */ { false, 0x6530, 0x6530 }, +/* 0x6531 */ { false, 0x6531, 0x6531 }, +/* 0x6532 */ { false, 0x6532, 0x6532 }, +/* 0x6533 */ { false, 0x6533, 0x6533 }, +/* 0x6534 */ { false, 0x6534, 0x6534 }, +/* 0x6535 */ { false, 0x6535, 0x6535 }, +/* 0x6536 */ { false, 0x6536, 0x6536 }, +/* 0x6537 */ { false, 0x6537, 0x6537 }, +/* 0x6538 */ { false, 0x6538, 0x6538 }, +/* 0x6539 */ { false, 0x6539, 0x6539 }, +/* 0x653a */ { false, 0x653a, 0x653a }, +/* 0x653b */ { false, 0x653b, 0x653b }, +/* 0x653c */ { false, 0x653c, 0x653c }, +/* 0x653d */ { false, 0x653d, 0x653d }, +/* 0x653e */ { false, 0x653e, 0x653e }, +/* 0x653f */ { false, 0x653f, 0x653f }, +/* 0x6540 */ { false, 0x6540, 0x6540 }, +/* 0x6541 */ { false, 0x6541, 0x6541 }, +/* 0x6542 */ { false, 0x6542, 0x6542 }, +/* 0x6543 */ { false, 0x6543, 0x6543 }, +/* 0x6544 */ { false, 0x6544, 0x6544 }, +/* 0x6545 */ { false, 0x6545, 0x6545 }, +/* 0x6546 */ { false, 0x6546, 0x6546 }, +/* 0x6547 */ { false, 0x6547, 0x6547 }, +/* 0x6548 */ { false, 0x6548, 0x6548 }, +/* 0x6549 */ { false, 0x6549, 0x6549 }, +/* 0x654a */ { false, 0x654a, 0x654a }, +/* 0x654b */ { false, 0x654b, 0x654b }, +/* 0x654c */ { false, 0x654c, 0x654c }, +/* 0x654d */ { false, 0x654d, 0x654d }, +/* 0x654e */ { false, 0x654e, 0x654e }, +/* 0x654f */ { false, 0x654f, 0x654f }, +/* 0x6550 */ { false, 0x6550, 0x6550 }, +/* 0x6551 */ { false, 0x6551, 0x6551 }, +/* 0x6552 */ { false, 0x6552, 0x6552 }, +/* 0x6553 */ { false, 0x6553, 0x6553 }, +/* 0x6554 */ { false, 0x6554, 0x6554 }, +/* 0x6555 */ { false, 0x6555, 0x6555 }, +/* 0x6556 */ { false, 0x6556, 0x6556 }, +/* 0x6557 */ { false, 0x6557, 0x6557 }, +/* 0x6558 */ { false, 0x6558, 0x6558 }, +/* 0x6559 */ { false, 0x6559, 0x6559 }, +/* 0x655a */ { false, 0x655a, 0x655a }, +/* 0x655b */ { false, 0x655b, 0x655b }, +/* 0x655c */ { false, 0x655c, 0x655c }, +/* 0x655d */ { false, 0x655d, 0x655d }, +/* 0x655e */ { false, 0x655e, 0x655e }, +/* 0x655f */ { false, 0x655f, 0x655f }, +/* 0x6560 */ { false, 0x6560, 0x6560 }, +/* 0x6561 */ { false, 0x6561, 0x6561 }, +/* 0x6562 */ { false, 0x6562, 0x6562 }, +/* 0x6563 */ { false, 0x6563, 0x6563 }, +/* 0x6564 */ { false, 0x6564, 0x6564 }, +/* 0x6565 */ { false, 0x6565, 0x6565 }, +/* 0x6566 */ { false, 0x6566, 0x6566 }, +/* 0x6567 */ { false, 0x6567, 0x6567 }, +/* 0x6568 */ { false, 0x6568, 0x6568 }, +/* 0x6569 */ { false, 0x6569, 0x6569 }, +/* 0x656a */ { false, 0x656a, 0x656a }, +/* 0x656b */ { false, 0x656b, 0x656b }, +/* 0x656c */ { false, 0x656c, 0x656c }, +/* 0x656d */ { false, 0x656d, 0x656d }, +/* 0x656e */ { false, 0x656e, 0x656e }, +/* 0x656f */ { false, 0x656f, 0x656f }, +/* 0x6570 */ { false, 0x6570, 0x6570 }, +/* 0x6571 */ { false, 0x6571, 0x6571 }, +/* 0x6572 */ { false, 0x6572, 0x6572 }, +/* 0x6573 */ { false, 0x6573, 0x6573 }, +/* 0x6574 */ { false, 0x6574, 0x6574 }, +/* 0x6575 */ { false, 0x6575, 0x6575 }, +/* 0x6576 */ { false, 0x6576, 0x6576 }, +/* 0x6577 */ { false, 0x6577, 0x6577 }, +/* 0x6578 */ { false, 0x6578, 0x6578 }, +/* 0x6579 */ { false, 0x6579, 0x6579 }, +/* 0x657a */ { false, 0x657a, 0x657a }, +/* 0x657b */ { false, 0x657b, 0x657b }, +/* 0x657c */ { false, 0x657c, 0x657c }, +/* 0x657d */ { false, 0x657d, 0x657d }, +/* 0x657e */ { false, 0x657e, 0x657e }, +/* 0x657f */ { false, 0x657f, 0x657f }, +/* 0x6580 */ { false, 0x6580, 0x6580 }, +/* 0x6581 */ { false, 0x6581, 0x6581 }, +/* 0x6582 */ { false, 0x6582, 0x6582 }, +/* 0x6583 */ { false, 0x6583, 0x6583 }, +/* 0x6584 */ { false, 0x6584, 0x6584 }, +/* 0x6585 */ { false, 0x6585, 0x6585 }, +/* 0x6586 */ { false, 0x6586, 0x6586 }, +/* 0x6587 */ { false, 0x6587, 0x6587 }, +/* 0x6588 */ { false, 0x6588, 0x6588 }, +/* 0x6589 */ { false, 0x6589, 0x6589 }, +/* 0x658a */ { false, 0x658a, 0x658a }, +/* 0x658b */ { false, 0x658b, 0x658b }, +/* 0x658c */ { false, 0x658c, 0x658c }, +/* 0x658d */ { false, 0x658d, 0x658d }, +/* 0x658e */ { false, 0x658e, 0x658e }, +/* 0x658f */ { false, 0x658f, 0x658f }, +/* 0x6590 */ { false, 0x6590, 0x6590 }, +/* 0x6591 */ { false, 0x6591, 0x6591 }, +/* 0x6592 */ { false, 0x6592, 0x6592 }, +/* 0x6593 */ { false, 0x6593, 0x6593 }, +/* 0x6594 */ { false, 0x6594, 0x6594 }, +/* 0x6595 */ { false, 0x6595, 0x6595 }, +/* 0x6596 */ { false, 0x6596, 0x6596 }, +/* 0x6597 */ { false, 0x6597, 0x6597 }, +/* 0x6598 */ { false, 0x6598, 0x6598 }, +/* 0x6599 */ { false, 0x6599, 0x6599 }, +/* 0x659a */ { false, 0x659a, 0x659a }, +/* 0x659b */ { false, 0x659b, 0x659b }, +/* 0x659c */ { false, 0x659c, 0x659c }, +/* 0x659d */ { false, 0x659d, 0x659d }, +/* 0x659e */ { false, 0x659e, 0x659e }, +/* 0x659f */ { false, 0x659f, 0x659f }, +/* 0x65a0 */ { false, 0x65a0, 0x65a0 }, +/* 0x65a1 */ { false, 0x65a1, 0x65a1 }, +/* 0x65a2 */ { false, 0x65a2, 0x65a2 }, +/* 0x65a3 */ { false, 0x65a3, 0x65a3 }, +/* 0x65a4 */ { false, 0x65a4, 0x65a4 }, +/* 0x65a5 */ { false, 0x65a5, 0x65a5 }, +/* 0x65a6 */ { false, 0x65a6, 0x65a6 }, +/* 0x65a7 */ { false, 0x65a7, 0x65a7 }, +/* 0x65a8 */ { false, 0x65a8, 0x65a8 }, +/* 0x65a9 */ { false, 0x65a9, 0x65a9 }, +/* 0x65aa */ { false, 0x65aa, 0x65aa }, +/* 0x65ab */ { false, 0x65ab, 0x65ab }, +/* 0x65ac */ { false, 0x65ac, 0x65ac }, +/* 0x65ad */ { false, 0x65ad, 0x65ad }, +/* 0x65ae */ { false, 0x65ae, 0x65ae }, +/* 0x65af */ { false, 0x65af, 0x65af }, +/* 0x65b0 */ { false, 0x65b0, 0x65b0 }, +/* 0x65b1 */ { false, 0x65b1, 0x65b1 }, +/* 0x65b2 */ { false, 0x65b2, 0x65b2 }, +/* 0x65b3 */ { false, 0x65b3, 0x65b3 }, +/* 0x65b4 */ { false, 0x65b4, 0x65b4 }, +/* 0x65b5 */ { false, 0x65b5, 0x65b5 }, +/* 0x65b6 */ { false, 0x65b6, 0x65b6 }, +/* 0x65b7 */ { false, 0x65b7, 0x65b7 }, +/* 0x65b8 */ { false, 0x65b8, 0x65b8 }, +/* 0x65b9 */ { false, 0x65b9, 0x65b9 }, +/* 0x65ba */ { false, 0x65ba, 0x65ba }, +/* 0x65bb */ { false, 0x65bb, 0x65bb }, +/* 0x65bc */ { false, 0x65bc, 0x65bc }, +/* 0x65bd */ { false, 0x65bd, 0x65bd }, +/* 0x65be */ { false, 0x65be, 0x65be }, +/* 0x65bf */ { false, 0x65bf, 0x65bf }, +/* 0x65c0 */ { false, 0x65c0, 0x65c0 }, +/* 0x65c1 */ { false, 0x65c1, 0x65c1 }, +/* 0x65c2 */ { false, 0x65c2, 0x65c2 }, +/* 0x65c3 */ { false, 0x65c3, 0x65c3 }, +/* 0x65c4 */ { false, 0x65c4, 0x65c4 }, +/* 0x65c5 */ { false, 0x65c5, 0x65c5 }, +/* 0x65c6 */ { false, 0x65c6, 0x65c6 }, +/* 0x65c7 */ { false, 0x65c7, 0x65c7 }, +/* 0x65c8 */ { false, 0x65c8, 0x65c8 }, +/* 0x65c9 */ { false, 0x65c9, 0x65c9 }, +/* 0x65ca */ { false, 0x65ca, 0x65ca }, +/* 0x65cb */ { false, 0x65cb, 0x65cb }, +/* 0x65cc */ { false, 0x65cc, 0x65cc }, +/* 0x65cd */ { false, 0x65cd, 0x65cd }, +/* 0x65ce */ { false, 0x65ce, 0x65ce }, +/* 0x65cf */ { false, 0x65cf, 0x65cf }, +/* 0x65d0 */ { false, 0x65d0, 0x65d0 }, +/* 0x65d1 */ { false, 0x65d1, 0x65d1 }, +/* 0x65d2 */ { false, 0x65d2, 0x65d2 }, +/* 0x65d3 */ { false, 0x65d3, 0x65d3 }, +/* 0x65d4 */ { false, 0x65d4, 0x65d4 }, +/* 0x65d5 */ { false, 0x65d5, 0x65d5 }, +/* 0x65d6 */ { false, 0x65d6, 0x65d6 }, +/* 0x65d7 */ { false, 0x65d7, 0x65d7 }, +/* 0x65d8 */ { false, 0x65d8, 0x65d8 }, +/* 0x65d9 */ { false, 0x65d9, 0x65d9 }, +/* 0x65da */ { false, 0x65da, 0x65da }, +/* 0x65db */ { false, 0x65db, 0x65db }, +/* 0x65dc */ { false, 0x65dc, 0x65dc }, +/* 0x65dd */ { false, 0x65dd, 0x65dd }, +/* 0x65de */ { false, 0x65de, 0x65de }, +/* 0x65df */ { false, 0x65df, 0x65df }, +/* 0x65e0 */ { false, 0x65e0, 0x65e0 }, +/* 0x65e1 */ { false, 0x65e1, 0x65e1 }, +/* 0x65e2 */ { false, 0x65e2, 0x65e2 }, +/* 0x65e3 */ { false, 0x65e3, 0x65e3 }, +/* 0x65e4 */ { false, 0x65e4, 0x65e4 }, +/* 0x65e5 */ { false, 0x65e5, 0x65e5 }, +/* 0x65e6 */ { false, 0x65e6, 0x65e6 }, +/* 0x65e7 */ { false, 0x65e7, 0x65e7 }, +/* 0x65e8 */ { false, 0x65e8, 0x65e8 }, +/* 0x65e9 */ { false, 0x65e9, 0x65e9 }, +/* 0x65ea */ { false, 0x65ea, 0x65ea }, +/* 0x65eb */ { false, 0x65eb, 0x65eb }, +/* 0x65ec */ { false, 0x65ec, 0x65ec }, +/* 0x65ed */ { false, 0x65ed, 0x65ed }, +/* 0x65ee */ { false, 0x65ee, 0x65ee }, +/* 0x65ef */ { false, 0x65ef, 0x65ef }, +/* 0x65f0 */ { false, 0x65f0, 0x65f0 }, +/* 0x65f1 */ { false, 0x65f1, 0x65f1 }, +/* 0x65f2 */ { false, 0x65f2, 0x65f2 }, +/* 0x65f3 */ { false, 0x65f3, 0x65f3 }, +/* 0x65f4 */ { false, 0x65f4, 0x65f4 }, +/* 0x65f5 */ { false, 0x65f5, 0x65f5 }, +/* 0x65f6 */ { false, 0x65f6, 0x65f6 }, +/* 0x65f7 */ { false, 0x65f7, 0x65f7 }, +/* 0x65f8 */ { false, 0x65f8, 0x65f8 }, +/* 0x65f9 */ { false, 0x65f9, 0x65f9 }, +/* 0x65fa */ { false, 0x65fa, 0x65fa }, +/* 0x65fb */ { false, 0x65fb, 0x65fb }, +/* 0x65fc */ { false, 0x65fc, 0x65fc }, +/* 0x65fd */ { false, 0x65fd, 0x65fd }, +/* 0x65fe */ { false, 0x65fe, 0x65fe }, +/* 0x65ff */ { false, 0x65ff, 0x65ff }, +/* 0x6600 */ { false, 0x6600, 0x6600 }, +/* 0x6601 */ { false, 0x6601, 0x6601 }, +/* 0x6602 */ { false, 0x6602, 0x6602 }, +/* 0x6603 */ { false, 0x6603, 0x6603 }, +/* 0x6604 */ { false, 0x6604, 0x6604 }, +/* 0x6605 */ { false, 0x6605, 0x6605 }, +/* 0x6606 */ { false, 0x6606, 0x6606 }, +/* 0x6607 */ { false, 0x6607, 0x6607 }, +/* 0x6608 */ { false, 0x6608, 0x6608 }, +/* 0x6609 */ { false, 0x6609, 0x6609 }, +/* 0x660a */ { false, 0x660a, 0x660a }, +/* 0x660b */ { false, 0x660b, 0x660b }, +/* 0x660c */ { false, 0x660c, 0x660c }, +/* 0x660d */ { false, 0x660d, 0x660d }, +/* 0x660e */ { false, 0x660e, 0x660e }, +/* 0x660f */ { false, 0x660f, 0x660f }, +/* 0x6610 */ { false, 0x6610, 0x6610 }, +/* 0x6611 */ { false, 0x6611, 0x6611 }, +/* 0x6612 */ { false, 0x6612, 0x6612 }, +/* 0x6613 */ { false, 0x6613, 0x6613 }, +/* 0x6614 */ { false, 0x6614, 0x6614 }, +/* 0x6615 */ { false, 0x6615, 0x6615 }, +/* 0x6616 */ { false, 0x6616, 0x6616 }, +/* 0x6617 */ { false, 0x6617, 0x6617 }, +/* 0x6618 */ { false, 0x6618, 0x6618 }, +/* 0x6619 */ { false, 0x6619, 0x6619 }, +/* 0x661a */ { false, 0x661a, 0x661a }, +/* 0x661b */ { false, 0x661b, 0x661b }, +/* 0x661c */ { false, 0x661c, 0x661c }, +/* 0x661d */ { false, 0x661d, 0x661d }, +/* 0x661e */ { false, 0x661e, 0x661e }, +/* 0x661f */ { false, 0x661f, 0x661f }, +/* 0x6620 */ { false, 0x6620, 0x6620 }, +/* 0x6621 */ { false, 0x6621, 0x6621 }, +/* 0x6622 */ { false, 0x6622, 0x6622 }, +/* 0x6623 */ { false, 0x6623, 0x6623 }, +/* 0x6624 */ { false, 0x6624, 0x6624 }, +/* 0x6625 */ { false, 0x6625, 0x6625 }, +/* 0x6626 */ { false, 0x6626, 0x6626 }, +/* 0x6627 */ { false, 0x6627, 0x6627 }, +/* 0x6628 */ { false, 0x6628, 0x6628 }, +/* 0x6629 */ { false, 0x6629, 0x6629 }, +/* 0x662a */ { false, 0x662a, 0x662a }, +/* 0x662b */ { false, 0x662b, 0x662b }, +/* 0x662c */ { false, 0x662c, 0x662c }, +/* 0x662d */ { false, 0x662d, 0x662d }, +/* 0x662e */ { false, 0x662e, 0x662e }, +/* 0x662f */ { false, 0x662f, 0x662f }, +/* 0x6630 */ { false, 0x6630, 0x6630 }, +/* 0x6631 */ { false, 0x6631, 0x6631 }, +/* 0x6632 */ { false, 0x6632, 0x6632 }, +/* 0x6633 */ { false, 0x6633, 0x6633 }, +/* 0x6634 */ { false, 0x6634, 0x6634 }, +/* 0x6635 */ { false, 0x6635, 0x6635 }, +/* 0x6636 */ { false, 0x6636, 0x6636 }, +/* 0x6637 */ { false, 0x6637, 0x6637 }, +/* 0x6638 */ { false, 0x6638, 0x6638 }, +/* 0x6639 */ { false, 0x6639, 0x6639 }, +/* 0x663a */ { false, 0x663a, 0x663a }, +/* 0x663b */ { false, 0x663b, 0x663b }, +/* 0x663c */ { false, 0x663c, 0x663c }, +/* 0x663d */ { false, 0x663d, 0x663d }, +/* 0x663e */ { false, 0x663e, 0x663e }, +/* 0x663f */ { false, 0x663f, 0x663f }, +/* 0x6640 */ { false, 0x6640, 0x6640 }, +/* 0x6641 */ { false, 0x6641, 0x6641 }, +/* 0x6642 */ { false, 0x6642, 0x6642 }, +/* 0x6643 */ { false, 0x6643, 0x6643 }, +/* 0x6644 */ { false, 0x6644, 0x6644 }, +/* 0x6645 */ { false, 0x6645, 0x6645 }, +/* 0x6646 */ { false, 0x6646, 0x6646 }, +/* 0x6647 */ { false, 0x6647, 0x6647 }, +/* 0x6648 */ { false, 0x6648, 0x6648 }, +/* 0x6649 */ { false, 0x6649, 0x6649 }, +/* 0x664a */ { false, 0x664a, 0x664a }, +/* 0x664b */ { false, 0x664b, 0x664b }, +/* 0x664c */ { false, 0x664c, 0x664c }, +/* 0x664d */ { false, 0x664d, 0x664d }, +/* 0x664e */ { false, 0x664e, 0x664e }, +/* 0x664f */ { false, 0x664f, 0x664f }, +/* 0x6650 */ { false, 0x6650, 0x6650 }, +/* 0x6651 */ { false, 0x6651, 0x6651 }, +/* 0x6652 */ { false, 0x6652, 0x6652 }, +/* 0x6653 */ { false, 0x6653, 0x6653 }, +/* 0x6654 */ { false, 0x6654, 0x6654 }, +/* 0x6655 */ { false, 0x6655, 0x6655 }, +/* 0x6656 */ { false, 0x6656, 0x6656 }, +/* 0x6657 */ { false, 0x6657, 0x6657 }, +/* 0x6658 */ { false, 0x6658, 0x6658 }, +/* 0x6659 */ { false, 0x6659, 0x6659 }, +/* 0x665a */ { false, 0x665a, 0x665a }, +/* 0x665b */ { false, 0x665b, 0x665b }, +/* 0x665c */ { false, 0x665c, 0x665c }, +/* 0x665d */ { false, 0x665d, 0x665d }, +/* 0x665e */ { false, 0x665e, 0x665e }, +/* 0x665f */ { false, 0x665f, 0x665f }, +/* 0x6660 */ { false, 0x6660, 0x6660 }, +/* 0x6661 */ { false, 0x6661, 0x6661 }, +/* 0x6662 */ { false, 0x6662, 0x6662 }, +/* 0x6663 */ { false, 0x6663, 0x6663 }, +/* 0x6664 */ { false, 0x6664, 0x6664 }, +/* 0x6665 */ { false, 0x6665, 0x6665 }, +/* 0x6666 */ { false, 0x6666, 0x6666 }, +/* 0x6667 */ { false, 0x6667, 0x6667 }, +/* 0x6668 */ { false, 0x6668, 0x6668 }, +/* 0x6669 */ { false, 0x6669, 0x6669 }, +/* 0x666a */ { false, 0x666a, 0x666a }, +/* 0x666b */ { false, 0x666b, 0x666b }, +/* 0x666c */ { false, 0x666c, 0x666c }, +/* 0x666d */ { false, 0x666d, 0x666d }, +/* 0x666e */ { false, 0x666e, 0x666e }, +/* 0x666f */ { false, 0x666f, 0x666f }, +/* 0x6670 */ { false, 0x6670, 0x6670 }, +/* 0x6671 */ { false, 0x6671, 0x6671 }, +/* 0x6672 */ { false, 0x6672, 0x6672 }, +/* 0x6673 */ { false, 0x6673, 0x6673 }, +/* 0x6674 */ { false, 0x6674, 0x6674 }, +/* 0x6675 */ { false, 0x6675, 0x6675 }, +/* 0x6676 */ { false, 0x6676, 0x6676 }, +/* 0x6677 */ { false, 0x6677, 0x6677 }, +/* 0x6678 */ { false, 0x6678, 0x6678 }, +/* 0x6679 */ { false, 0x6679, 0x6679 }, +/* 0x667a */ { false, 0x667a, 0x667a }, +/* 0x667b */ { false, 0x667b, 0x667b }, +/* 0x667c */ { false, 0x667c, 0x667c }, +/* 0x667d */ { false, 0x667d, 0x667d }, +/* 0x667e */ { false, 0x667e, 0x667e }, +/* 0x667f */ { false, 0x667f, 0x667f }, +/* 0x6680 */ { false, 0x6680, 0x6680 }, +/* 0x6681 */ { false, 0x6681, 0x6681 }, +/* 0x6682 */ { false, 0x6682, 0x6682 }, +/* 0x6683 */ { false, 0x6683, 0x6683 }, +/* 0x6684 */ { false, 0x6684, 0x6684 }, +/* 0x6685 */ { false, 0x6685, 0x6685 }, +/* 0x6686 */ { false, 0x6686, 0x6686 }, +/* 0x6687 */ { false, 0x6687, 0x6687 }, +/* 0x6688 */ { false, 0x6688, 0x6688 }, +/* 0x6689 */ { false, 0x6689, 0x6689 }, +/* 0x668a */ { false, 0x668a, 0x668a }, +/* 0x668b */ { false, 0x668b, 0x668b }, +/* 0x668c */ { false, 0x668c, 0x668c }, +/* 0x668d */ { false, 0x668d, 0x668d }, +/* 0x668e */ { false, 0x668e, 0x668e }, +/* 0x668f */ { false, 0x668f, 0x668f }, +/* 0x6690 */ { false, 0x6690, 0x6690 }, +/* 0x6691 */ { false, 0x6691, 0x6691 }, +/* 0x6692 */ { false, 0x6692, 0x6692 }, +/* 0x6693 */ { false, 0x6693, 0x6693 }, +/* 0x6694 */ { false, 0x6694, 0x6694 }, +/* 0x6695 */ { false, 0x6695, 0x6695 }, +/* 0x6696 */ { false, 0x6696, 0x6696 }, +/* 0x6697 */ { false, 0x6697, 0x6697 }, +/* 0x6698 */ { false, 0x6698, 0x6698 }, +/* 0x6699 */ { false, 0x6699, 0x6699 }, +/* 0x669a */ { false, 0x669a, 0x669a }, +/* 0x669b */ { false, 0x669b, 0x669b }, +/* 0x669c */ { false, 0x669c, 0x669c }, +/* 0x669d */ { false, 0x669d, 0x669d }, +/* 0x669e */ { false, 0x669e, 0x669e }, +/* 0x669f */ { false, 0x669f, 0x669f }, +/* 0x66a0 */ { false, 0x66a0, 0x66a0 }, +/* 0x66a1 */ { false, 0x66a1, 0x66a1 }, +/* 0x66a2 */ { false, 0x66a2, 0x66a2 }, +/* 0x66a3 */ { false, 0x66a3, 0x66a3 }, +/* 0x66a4 */ { false, 0x66a4, 0x66a4 }, +/* 0x66a5 */ { false, 0x66a5, 0x66a5 }, +/* 0x66a6 */ { false, 0x66a6, 0x66a6 }, +/* 0x66a7 */ { false, 0x66a7, 0x66a7 }, +/* 0x66a8 */ { false, 0x66a8, 0x66a8 }, +/* 0x66a9 */ { false, 0x66a9, 0x66a9 }, +/* 0x66aa */ { false, 0x66aa, 0x66aa }, +/* 0x66ab */ { false, 0x66ab, 0x66ab }, +/* 0x66ac */ { false, 0x66ac, 0x66ac }, +/* 0x66ad */ { false, 0x66ad, 0x66ad }, +/* 0x66ae */ { false, 0x66ae, 0x66ae }, +/* 0x66af */ { false, 0x66af, 0x66af }, +/* 0x66b0 */ { false, 0x66b0, 0x66b0 }, +/* 0x66b1 */ { false, 0x66b1, 0x66b1 }, +/* 0x66b2 */ { false, 0x66b2, 0x66b2 }, +/* 0x66b3 */ { false, 0x66b3, 0x66b3 }, +/* 0x66b4 */ { false, 0x66b4, 0x66b4 }, +/* 0x66b5 */ { false, 0x66b5, 0x66b5 }, +/* 0x66b6 */ { false, 0x66b6, 0x66b6 }, +/* 0x66b7 */ { false, 0x66b7, 0x66b7 }, +/* 0x66b8 */ { false, 0x66b8, 0x66b8 }, +/* 0x66b9 */ { false, 0x66b9, 0x66b9 }, +/* 0x66ba */ { false, 0x66ba, 0x66ba }, +/* 0x66bb */ { false, 0x66bb, 0x66bb }, +/* 0x66bc */ { false, 0x66bc, 0x66bc }, +/* 0x66bd */ { false, 0x66bd, 0x66bd }, +/* 0x66be */ { false, 0x66be, 0x66be }, +/* 0x66bf */ { false, 0x66bf, 0x66bf }, +/* 0x66c0 */ { false, 0x66c0, 0x66c0 }, +/* 0x66c1 */ { false, 0x66c1, 0x66c1 }, +/* 0x66c2 */ { false, 0x66c2, 0x66c2 }, +/* 0x66c3 */ { false, 0x66c3, 0x66c3 }, +/* 0x66c4 */ { false, 0x66c4, 0x66c4 }, +/* 0x66c5 */ { false, 0x66c5, 0x66c5 }, +/* 0x66c6 */ { false, 0x66c6, 0x66c6 }, +/* 0x66c7 */ { false, 0x66c7, 0x66c7 }, +/* 0x66c8 */ { false, 0x66c8, 0x66c8 }, +/* 0x66c9 */ { false, 0x66c9, 0x66c9 }, +/* 0x66ca */ { false, 0x66ca, 0x66ca }, +/* 0x66cb */ { false, 0x66cb, 0x66cb }, +/* 0x66cc */ { false, 0x66cc, 0x66cc }, +/* 0x66cd */ { false, 0x66cd, 0x66cd }, +/* 0x66ce */ { false, 0x66ce, 0x66ce }, +/* 0x66cf */ { false, 0x66cf, 0x66cf }, +/* 0x66d0 */ { false, 0x66d0, 0x66d0 }, +/* 0x66d1 */ { false, 0x66d1, 0x66d1 }, +/* 0x66d2 */ { false, 0x66d2, 0x66d2 }, +/* 0x66d3 */ { false, 0x66d3, 0x66d3 }, +/* 0x66d4 */ { false, 0x66d4, 0x66d4 }, +/* 0x66d5 */ { false, 0x66d5, 0x66d5 }, +/* 0x66d6 */ { false, 0x66d6, 0x66d6 }, +/* 0x66d7 */ { false, 0x66d7, 0x66d7 }, +/* 0x66d8 */ { false, 0x66d8, 0x66d8 }, +/* 0x66d9 */ { false, 0x66d9, 0x66d9 }, +/* 0x66da */ { false, 0x66da, 0x66da }, +/* 0x66db */ { false, 0x66db, 0x66db }, +/* 0x66dc */ { false, 0x66dc, 0x66dc }, +/* 0x66dd */ { false, 0x66dd, 0x66dd }, +/* 0x66de */ { false, 0x66de, 0x66de }, +/* 0x66df */ { false, 0x66df, 0x66df }, +/* 0x66e0 */ { false, 0x66e0, 0x66e0 }, +/* 0x66e1 */ { false, 0x66e1, 0x66e1 }, +/* 0x66e2 */ { false, 0x66e2, 0x66e2 }, +/* 0x66e3 */ { false, 0x66e3, 0x66e3 }, +/* 0x66e4 */ { false, 0x66e4, 0x66e4 }, +/* 0x66e5 */ { false, 0x66e5, 0x66e5 }, +/* 0x66e6 */ { false, 0x66e6, 0x66e6 }, +/* 0x66e7 */ { false, 0x66e7, 0x66e7 }, +/* 0x66e8 */ { false, 0x66e8, 0x66e8 }, +/* 0x66e9 */ { false, 0x66e9, 0x66e9 }, +/* 0x66ea */ { false, 0x66ea, 0x66ea }, +/* 0x66eb */ { false, 0x66eb, 0x66eb }, +/* 0x66ec */ { false, 0x66ec, 0x66ec }, +/* 0x66ed */ { false, 0x66ed, 0x66ed }, +/* 0x66ee */ { false, 0x66ee, 0x66ee }, +/* 0x66ef */ { false, 0x66ef, 0x66ef }, +/* 0x66f0 */ { false, 0x66f0, 0x66f0 }, +/* 0x66f1 */ { false, 0x66f1, 0x66f1 }, +/* 0x66f2 */ { false, 0x66f2, 0x66f2 }, +/* 0x66f3 */ { false, 0x66f3, 0x66f3 }, +/* 0x66f4 */ { false, 0x66f4, 0x66f4 }, +/* 0x66f5 */ { false, 0x66f5, 0x66f5 }, +/* 0x66f6 */ { false, 0x66f6, 0x66f6 }, +/* 0x66f7 */ { false, 0x66f7, 0x66f7 }, +/* 0x66f8 */ { false, 0x66f8, 0x66f8 }, +/* 0x66f9 */ { false, 0x66f9, 0x66f9 }, +/* 0x66fa */ { false, 0x66fa, 0x66fa }, +/* 0x66fb */ { false, 0x66fb, 0x66fb }, +/* 0x66fc */ { false, 0x66fc, 0x66fc }, +/* 0x66fd */ { false, 0x66fd, 0x66fd }, +/* 0x66fe */ { false, 0x66fe, 0x66fe }, +/* 0x66ff */ { false, 0x66ff, 0x66ff }, +/* 0x6700 */ { false, 0x6700, 0x6700 }, +/* 0x6701 */ { false, 0x6701, 0x6701 }, +/* 0x6702 */ { false, 0x6702, 0x6702 }, +/* 0x6703 */ { false, 0x6703, 0x6703 }, +/* 0x6704 */ { false, 0x6704, 0x6704 }, +/* 0x6705 */ { false, 0x6705, 0x6705 }, +/* 0x6706 */ { false, 0x6706, 0x6706 }, +/* 0x6707 */ { false, 0x6707, 0x6707 }, +/* 0x6708 */ { false, 0x6708, 0x6708 }, +/* 0x6709 */ { false, 0x6709, 0x6709 }, +/* 0x670a */ { false, 0x670a, 0x670a }, +/* 0x670b */ { false, 0x670b, 0x670b }, +/* 0x670c */ { false, 0x670c, 0x670c }, +/* 0x670d */ { false, 0x670d, 0x670d }, +/* 0x670e */ { false, 0x670e, 0x670e }, +/* 0x670f */ { false, 0x670f, 0x670f }, +/* 0x6710 */ { false, 0x6710, 0x6710 }, +/* 0x6711 */ { false, 0x6711, 0x6711 }, +/* 0x6712 */ { false, 0x6712, 0x6712 }, +/* 0x6713 */ { false, 0x6713, 0x6713 }, +/* 0x6714 */ { false, 0x6714, 0x6714 }, +/* 0x6715 */ { false, 0x6715, 0x6715 }, +/* 0x6716 */ { false, 0x6716, 0x6716 }, +/* 0x6717 */ { false, 0x6717, 0x6717 }, +/* 0x6718 */ { false, 0x6718, 0x6718 }, +/* 0x6719 */ { false, 0x6719, 0x6719 }, +/* 0x671a */ { false, 0x671a, 0x671a }, +/* 0x671b */ { false, 0x671b, 0x671b }, +/* 0x671c */ { false, 0x671c, 0x671c }, +/* 0x671d */ { false, 0x671d, 0x671d }, +/* 0x671e */ { false, 0x671e, 0x671e }, +/* 0x671f */ { false, 0x671f, 0x671f }, +/* 0x6720 */ { false, 0x6720, 0x6720 }, +/* 0x6721 */ { false, 0x6721, 0x6721 }, +/* 0x6722 */ { false, 0x6722, 0x6722 }, +/* 0x6723 */ { false, 0x6723, 0x6723 }, +/* 0x6724 */ { false, 0x6724, 0x6724 }, +/* 0x6725 */ { false, 0x6725, 0x6725 }, +/* 0x6726 */ { false, 0x6726, 0x6726 }, +/* 0x6727 */ { false, 0x6727, 0x6727 }, +/* 0x6728 */ { false, 0x6728, 0x6728 }, +/* 0x6729 */ { false, 0x6729, 0x6729 }, +/* 0x672a */ { false, 0x672a, 0x672a }, +/* 0x672b */ { false, 0x672b, 0x672b }, +/* 0x672c */ { false, 0x672c, 0x672c }, +/* 0x672d */ { false, 0x672d, 0x672d }, +/* 0x672e */ { false, 0x672e, 0x672e }, +/* 0x672f */ { false, 0x672f, 0x672f }, +/* 0x6730 */ { false, 0x6730, 0x6730 }, +/* 0x6731 */ { false, 0x6731, 0x6731 }, +/* 0x6732 */ { false, 0x6732, 0x6732 }, +/* 0x6733 */ { false, 0x6733, 0x6733 }, +/* 0x6734 */ { false, 0x6734, 0x6734 }, +/* 0x6735 */ { false, 0x6735, 0x6735 }, +/* 0x6736 */ { false, 0x6736, 0x6736 }, +/* 0x6737 */ { false, 0x6737, 0x6737 }, +/* 0x6738 */ { false, 0x6738, 0x6738 }, +/* 0x6739 */ { false, 0x6739, 0x6739 }, +/* 0x673a */ { false, 0x673a, 0x673a }, +/* 0x673b */ { false, 0x673b, 0x673b }, +/* 0x673c */ { false, 0x673c, 0x673c }, +/* 0x673d */ { false, 0x673d, 0x673d }, +/* 0x673e */ { false, 0x673e, 0x673e }, +/* 0x673f */ { false, 0x673f, 0x673f }, +/* 0x6740 */ { false, 0x6740, 0x6740 }, +/* 0x6741 */ { false, 0x6741, 0x6741 }, +/* 0x6742 */ { false, 0x6742, 0x6742 }, +/* 0x6743 */ { false, 0x6743, 0x6743 }, +/* 0x6744 */ { false, 0x6744, 0x6744 }, +/* 0x6745 */ { false, 0x6745, 0x6745 }, +/* 0x6746 */ { false, 0x6746, 0x6746 }, +/* 0x6747 */ { false, 0x6747, 0x6747 }, +/* 0x6748 */ { false, 0x6748, 0x6748 }, +/* 0x6749 */ { false, 0x6749, 0x6749 }, +/* 0x674a */ { false, 0x674a, 0x674a }, +/* 0x674b */ { false, 0x674b, 0x674b }, +/* 0x674c */ { false, 0x674c, 0x674c }, +/* 0x674d */ { false, 0x674d, 0x674d }, +/* 0x674e */ { false, 0x674e, 0x674e }, +/* 0x674f */ { false, 0x674f, 0x674f }, +/* 0x6750 */ { false, 0x6750, 0x6750 }, +/* 0x6751 */ { false, 0x6751, 0x6751 }, +/* 0x6752 */ { false, 0x6752, 0x6752 }, +/* 0x6753 */ { false, 0x6753, 0x6753 }, +/* 0x6754 */ { false, 0x6754, 0x6754 }, +/* 0x6755 */ { false, 0x6755, 0x6755 }, +/* 0x6756 */ { false, 0x6756, 0x6756 }, +/* 0x6757 */ { false, 0x6757, 0x6757 }, +/* 0x6758 */ { false, 0x6758, 0x6758 }, +/* 0x6759 */ { false, 0x6759, 0x6759 }, +/* 0x675a */ { false, 0x675a, 0x675a }, +/* 0x675b */ { false, 0x675b, 0x675b }, +/* 0x675c */ { false, 0x675c, 0x675c }, +/* 0x675d */ { false, 0x675d, 0x675d }, +/* 0x675e */ { false, 0x675e, 0x675e }, +/* 0x675f */ { false, 0x675f, 0x675f }, +/* 0x6760 */ { false, 0x6760, 0x6760 }, +/* 0x6761 */ { false, 0x6761, 0x6761 }, +/* 0x6762 */ { false, 0x6762, 0x6762 }, +/* 0x6763 */ { false, 0x6763, 0x6763 }, +/* 0x6764 */ { false, 0x6764, 0x6764 }, +/* 0x6765 */ { false, 0x6765, 0x6765 }, +/* 0x6766 */ { false, 0x6766, 0x6766 }, +/* 0x6767 */ { false, 0x6767, 0x6767 }, +/* 0x6768 */ { false, 0x6768, 0x6768 }, +/* 0x6769 */ { false, 0x6769, 0x6769 }, +/* 0x676a */ { false, 0x676a, 0x676a }, +/* 0x676b */ { false, 0x676b, 0x676b }, +/* 0x676c */ { false, 0x676c, 0x676c }, +/* 0x676d */ { false, 0x676d, 0x676d }, +/* 0x676e */ { false, 0x676e, 0x676e }, +/* 0x676f */ { false, 0x676f, 0x676f }, +/* 0x6770 */ { false, 0x6770, 0x6770 }, +/* 0x6771 */ { false, 0x6771, 0x6771 }, +/* 0x6772 */ { false, 0x6772, 0x6772 }, +/* 0x6773 */ { false, 0x6773, 0x6773 }, +/* 0x6774 */ { false, 0x6774, 0x6774 }, +/* 0x6775 */ { false, 0x6775, 0x6775 }, +/* 0x6776 */ { false, 0x6776, 0x6776 }, +/* 0x6777 */ { false, 0x6777, 0x6777 }, +/* 0x6778 */ { false, 0x6778, 0x6778 }, +/* 0x6779 */ { false, 0x6779, 0x6779 }, +/* 0x677a */ { false, 0x677a, 0x677a }, +/* 0x677b */ { false, 0x677b, 0x677b }, +/* 0x677c */ { false, 0x677c, 0x677c }, +/* 0x677d */ { false, 0x677d, 0x677d }, +/* 0x677e */ { false, 0x677e, 0x677e }, +/* 0x677f */ { false, 0x677f, 0x677f }, +/* 0x6780 */ { false, 0x6780, 0x6780 }, +/* 0x6781 */ { false, 0x6781, 0x6781 }, +/* 0x6782 */ { false, 0x6782, 0x6782 }, +/* 0x6783 */ { false, 0x6783, 0x6783 }, +/* 0x6784 */ { false, 0x6784, 0x6784 }, +/* 0x6785 */ { false, 0x6785, 0x6785 }, +/* 0x6786 */ { false, 0x6786, 0x6786 }, +/* 0x6787 */ { false, 0x6787, 0x6787 }, +/* 0x6788 */ { false, 0x6788, 0x6788 }, +/* 0x6789 */ { false, 0x6789, 0x6789 }, +/* 0x678a */ { false, 0x678a, 0x678a }, +/* 0x678b */ { false, 0x678b, 0x678b }, +/* 0x678c */ { false, 0x678c, 0x678c }, +/* 0x678d */ { false, 0x678d, 0x678d }, +/* 0x678e */ { false, 0x678e, 0x678e }, +/* 0x678f */ { false, 0x678f, 0x678f }, +/* 0x6790 */ { false, 0x6790, 0x6790 }, +/* 0x6791 */ { false, 0x6791, 0x6791 }, +/* 0x6792 */ { false, 0x6792, 0x6792 }, +/* 0x6793 */ { false, 0x6793, 0x6793 }, +/* 0x6794 */ { false, 0x6794, 0x6794 }, +/* 0x6795 */ { false, 0x6795, 0x6795 }, +/* 0x6796 */ { false, 0x6796, 0x6796 }, +/* 0x6797 */ { false, 0x6797, 0x6797 }, +/* 0x6798 */ { false, 0x6798, 0x6798 }, +/* 0x6799 */ { false, 0x6799, 0x6799 }, +/* 0x679a */ { false, 0x679a, 0x679a }, +/* 0x679b */ { false, 0x679b, 0x679b }, +/* 0x679c */ { false, 0x679c, 0x679c }, +/* 0x679d */ { false, 0x679d, 0x679d }, +/* 0x679e */ { false, 0x679e, 0x679e }, +/* 0x679f */ { false, 0x679f, 0x679f }, +/* 0x67a0 */ { false, 0x67a0, 0x67a0 }, +/* 0x67a1 */ { false, 0x67a1, 0x67a1 }, +/* 0x67a2 */ { false, 0x67a2, 0x67a2 }, +/* 0x67a3 */ { false, 0x67a3, 0x67a3 }, +/* 0x67a4 */ { false, 0x67a4, 0x67a4 }, +/* 0x67a5 */ { false, 0x67a5, 0x67a5 }, +/* 0x67a6 */ { false, 0x67a6, 0x67a6 }, +/* 0x67a7 */ { false, 0x67a7, 0x67a7 }, +/* 0x67a8 */ { false, 0x67a8, 0x67a8 }, +/* 0x67a9 */ { false, 0x67a9, 0x67a9 }, +/* 0x67aa */ { false, 0x67aa, 0x67aa }, +/* 0x67ab */ { false, 0x67ab, 0x67ab }, +/* 0x67ac */ { false, 0x67ac, 0x67ac }, +/* 0x67ad */ { false, 0x67ad, 0x67ad }, +/* 0x67ae */ { false, 0x67ae, 0x67ae }, +/* 0x67af */ { false, 0x67af, 0x67af }, +/* 0x67b0 */ { false, 0x67b0, 0x67b0 }, +/* 0x67b1 */ { false, 0x67b1, 0x67b1 }, +/* 0x67b2 */ { false, 0x67b2, 0x67b2 }, +/* 0x67b3 */ { false, 0x67b3, 0x67b3 }, +/* 0x67b4 */ { false, 0x67b4, 0x67b4 }, +/* 0x67b5 */ { false, 0x67b5, 0x67b5 }, +/* 0x67b6 */ { false, 0x67b6, 0x67b6 }, +/* 0x67b7 */ { false, 0x67b7, 0x67b7 }, +/* 0x67b8 */ { false, 0x67b8, 0x67b8 }, +/* 0x67b9 */ { false, 0x67b9, 0x67b9 }, +/* 0x67ba */ { false, 0x67ba, 0x67ba }, +/* 0x67bb */ { false, 0x67bb, 0x67bb }, +/* 0x67bc */ { false, 0x67bc, 0x67bc }, +/* 0x67bd */ { false, 0x67bd, 0x67bd }, +/* 0x67be */ { false, 0x67be, 0x67be }, +/* 0x67bf */ { false, 0x67bf, 0x67bf }, +/* 0x67c0 */ { false, 0x67c0, 0x67c0 }, +/* 0x67c1 */ { false, 0x67c1, 0x67c1 }, +/* 0x67c2 */ { false, 0x67c2, 0x67c2 }, +/* 0x67c3 */ { false, 0x67c3, 0x67c3 }, +/* 0x67c4 */ { false, 0x67c4, 0x67c4 }, +/* 0x67c5 */ { false, 0x67c5, 0x67c5 }, +/* 0x67c6 */ { false, 0x67c6, 0x67c6 }, +/* 0x67c7 */ { false, 0x67c7, 0x67c7 }, +/* 0x67c8 */ { false, 0x67c8, 0x67c8 }, +/* 0x67c9 */ { false, 0x67c9, 0x67c9 }, +/* 0x67ca */ { false, 0x67ca, 0x67ca }, +/* 0x67cb */ { false, 0x67cb, 0x67cb }, +/* 0x67cc */ { false, 0x67cc, 0x67cc }, +/* 0x67cd */ { false, 0x67cd, 0x67cd }, +/* 0x67ce */ { false, 0x67ce, 0x67ce }, +/* 0x67cf */ { false, 0x67cf, 0x67cf }, +/* 0x67d0 */ { false, 0x67d0, 0x67d0 }, +/* 0x67d1 */ { false, 0x67d1, 0x67d1 }, +/* 0x67d2 */ { false, 0x67d2, 0x67d2 }, +/* 0x67d3 */ { false, 0x67d3, 0x67d3 }, +/* 0x67d4 */ { false, 0x67d4, 0x67d4 }, +/* 0x67d5 */ { false, 0x67d5, 0x67d5 }, +/* 0x67d6 */ { false, 0x67d6, 0x67d6 }, +/* 0x67d7 */ { false, 0x67d7, 0x67d7 }, +/* 0x67d8 */ { false, 0x67d8, 0x67d8 }, +/* 0x67d9 */ { false, 0x67d9, 0x67d9 }, +/* 0x67da */ { false, 0x67da, 0x67da }, +/* 0x67db */ { false, 0x67db, 0x67db }, +/* 0x67dc */ { false, 0x67dc, 0x67dc }, +/* 0x67dd */ { false, 0x67dd, 0x67dd }, +/* 0x67de */ { false, 0x67de, 0x67de }, +/* 0x67df */ { false, 0x67df, 0x67df }, +/* 0x67e0 */ { false, 0x67e0, 0x67e0 }, +/* 0x67e1 */ { false, 0x67e1, 0x67e1 }, +/* 0x67e2 */ { false, 0x67e2, 0x67e2 }, +/* 0x67e3 */ { false, 0x67e3, 0x67e3 }, +/* 0x67e4 */ { false, 0x67e4, 0x67e4 }, +/* 0x67e5 */ { false, 0x67e5, 0x67e5 }, +/* 0x67e6 */ { false, 0x67e6, 0x67e6 }, +/* 0x67e7 */ { false, 0x67e7, 0x67e7 }, +/* 0x67e8 */ { false, 0x67e8, 0x67e8 }, +/* 0x67e9 */ { false, 0x67e9, 0x67e9 }, +/* 0x67ea */ { false, 0x67ea, 0x67ea }, +/* 0x67eb */ { false, 0x67eb, 0x67eb }, +/* 0x67ec */ { false, 0x67ec, 0x67ec }, +/* 0x67ed */ { false, 0x67ed, 0x67ed }, +/* 0x67ee */ { false, 0x67ee, 0x67ee }, +/* 0x67ef */ { false, 0x67ef, 0x67ef }, +/* 0x67f0 */ { false, 0x67f0, 0x67f0 }, +/* 0x67f1 */ { false, 0x67f1, 0x67f1 }, +/* 0x67f2 */ { false, 0x67f2, 0x67f2 }, +/* 0x67f3 */ { false, 0x67f3, 0x67f3 }, +/* 0x67f4 */ { false, 0x67f4, 0x67f4 }, +/* 0x67f5 */ { false, 0x67f5, 0x67f5 }, +/* 0x67f6 */ { false, 0x67f6, 0x67f6 }, +/* 0x67f7 */ { false, 0x67f7, 0x67f7 }, +/* 0x67f8 */ { false, 0x67f8, 0x67f8 }, +/* 0x67f9 */ { false, 0x67f9, 0x67f9 }, +/* 0x67fa */ { false, 0x67fa, 0x67fa }, +/* 0x67fb */ { false, 0x67fb, 0x67fb }, +/* 0x67fc */ { false, 0x67fc, 0x67fc }, +/* 0x67fd */ { false, 0x67fd, 0x67fd }, +/* 0x67fe */ { false, 0x67fe, 0x67fe }, +/* 0x67ff */ { false, 0x67ff, 0x67ff }, +/* 0x6800 */ { false, 0x6800, 0x6800 }, +/* 0x6801 */ { false, 0x6801, 0x6801 }, +/* 0x6802 */ { false, 0x6802, 0x6802 }, +/* 0x6803 */ { false, 0x6803, 0x6803 }, +/* 0x6804 */ { false, 0x6804, 0x6804 }, +/* 0x6805 */ { false, 0x6805, 0x6805 }, +/* 0x6806 */ { false, 0x6806, 0x6806 }, +/* 0x6807 */ { false, 0x6807, 0x6807 }, +/* 0x6808 */ { false, 0x6808, 0x6808 }, +/* 0x6809 */ { false, 0x6809, 0x6809 }, +/* 0x680a */ { false, 0x680a, 0x680a }, +/* 0x680b */ { false, 0x680b, 0x680b }, +/* 0x680c */ { false, 0x680c, 0x680c }, +/* 0x680d */ { false, 0x680d, 0x680d }, +/* 0x680e */ { false, 0x680e, 0x680e }, +/* 0x680f */ { false, 0x680f, 0x680f }, +/* 0x6810 */ { false, 0x6810, 0x6810 }, +/* 0x6811 */ { false, 0x6811, 0x6811 }, +/* 0x6812 */ { false, 0x6812, 0x6812 }, +/* 0x6813 */ { false, 0x6813, 0x6813 }, +/* 0x6814 */ { false, 0x6814, 0x6814 }, +/* 0x6815 */ { false, 0x6815, 0x6815 }, +/* 0x6816 */ { false, 0x6816, 0x6816 }, +/* 0x6817 */ { false, 0x6817, 0x6817 }, +/* 0x6818 */ { false, 0x6818, 0x6818 }, +/* 0x6819 */ { false, 0x6819, 0x6819 }, +/* 0x681a */ { false, 0x681a, 0x681a }, +/* 0x681b */ { false, 0x681b, 0x681b }, +/* 0x681c */ { false, 0x681c, 0x681c }, +/* 0x681d */ { false, 0x681d, 0x681d }, +/* 0x681e */ { false, 0x681e, 0x681e }, +/* 0x681f */ { false, 0x681f, 0x681f }, +/* 0x6820 */ { false, 0x6820, 0x6820 }, +/* 0x6821 */ { false, 0x6821, 0x6821 }, +/* 0x6822 */ { false, 0x6822, 0x6822 }, +/* 0x6823 */ { false, 0x6823, 0x6823 }, +/* 0x6824 */ { false, 0x6824, 0x6824 }, +/* 0x6825 */ { false, 0x6825, 0x6825 }, +/* 0x6826 */ { false, 0x6826, 0x6826 }, +/* 0x6827 */ { false, 0x6827, 0x6827 }, +/* 0x6828 */ { false, 0x6828, 0x6828 }, +/* 0x6829 */ { false, 0x6829, 0x6829 }, +/* 0x682a */ { false, 0x682a, 0x682a }, +/* 0x682b */ { false, 0x682b, 0x682b }, +/* 0x682c */ { false, 0x682c, 0x682c }, +/* 0x682d */ { false, 0x682d, 0x682d }, +/* 0x682e */ { false, 0x682e, 0x682e }, +/* 0x682f */ { false, 0x682f, 0x682f }, +/* 0x6830 */ { false, 0x6830, 0x6830 }, +/* 0x6831 */ { false, 0x6831, 0x6831 }, +/* 0x6832 */ { false, 0x6832, 0x6832 }, +/* 0x6833 */ { false, 0x6833, 0x6833 }, +/* 0x6834 */ { false, 0x6834, 0x6834 }, +/* 0x6835 */ { false, 0x6835, 0x6835 }, +/* 0x6836 */ { false, 0x6836, 0x6836 }, +/* 0x6837 */ { false, 0x6837, 0x6837 }, +/* 0x6838 */ { false, 0x6838, 0x6838 }, +/* 0x6839 */ { false, 0x6839, 0x6839 }, +/* 0x683a */ { false, 0x683a, 0x683a }, +/* 0x683b */ { false, 0x683b, 0x683b }, +/* 0x683c */ { false, 0x683c, 0x683c }, +/* 0x683d */ { false, 0x683d, 0x683d }, +/* 0x683e */ { false, 0x683e, 0x683e }, +/* 0x683f */ { false, 0x683f, 0x683f }, +/* 0x6840 */ { false, 0x6840, 0x6840 }, +/* 0x6841 */ { false, 0x6841, 0x6841 }, +/* 0x6842 */ { false, 0x6842, 0x6842 }, +/* 0x6843 */ { false, 0x6843, 0x6843 }, +/* 0x6844 */ { false, 0x6844, 0x6844 }, +/* 0x6845 */ { false, 0x6845, 0x6845 }, +/* 0x6846 */ { false, 0x6846, 0x6846 }, +/* 0x6847 */ { false, 0x6847, 0x6847 }, +/* 0x6848 */ { false, 0x6848, 0x6848 }, +/* 0x6849 */ { false, 0x6849, 0x6849 }, +/* 0x684a */ { false, 0x684a, 0x684a }, +/* 0x684b */ { false, 0x684b, 0x684b }, +/* 0x684c */ { false, 0x684c, 0x684c }, +/* 0x684d */ { false, 0x684d, 0x684d }, +/* 0x684e */ { false, 0x684e, 0x684e }, +/* 0x684f */ { false, 0x684f, 0x684f }, +/* 0x6850 */ { false, 0x6850, 0x6850 }, +/* 0x6851 */ { false, 0x6851, 0x6851 }, +/* 0x6852 */ { false, 0x6852, 0x6852 }, +/* 0x6853 */ { false, 0x6853, 0x6853 }, +/* 0x6854 */ { false, 0x6854, 0x6854 }, +/* 0x6855 */ { false, 0x6855, 0x6855 }, +/* 0x6856 */ { false, 0x6856, 0x6856 }, +/* 0x6857 */ { false, 0x6857, 0x6857 }, +/* 0x6858 */ { false, 0x6858, 0x6858 }, +/* 0x6859 */ { false, 0x6859, 0x6859 }, +/* 0x685a */ { false, 0x685a, 0x685a }, +/* 0x685b */ { false, 0x685b, 0x685b }, +/* 0x685c */ { false, 0x685c, 0x685c }, +/* 0x685d */ { false, 0x685d, 0x685d }, +/* 0x685e */ { false, 0x685e, 0x685e }, +/* 0x685f */ { false, 0x685f, 0x685f }, +/* 0x6860 */ { false, 0x6860, 0x6860 }, +/* 0x6861 */ { false, 0x6861, 0x6861 }, +/* 0x6862 */ { false, 0x6862, 0x6862 }, +/* 0x6863 */ { false, 0x6863, 0x6863 }, +/* 0x6864 */ { false, 0x6864, 0x6864 }, +/* 0x6865 */ { false, 0x6865, 0x6865 }, +/* 0x6866 */ { false, 0x6866, 0x6866 }, +/* 0x6867 */ { false, 0x6867, 0x6867 }, +/* 0x6868 */ { false, 0x6868, 0x6868 }, +/* 0x6869 */ { false, 0x6869, 0x6869 }, +/* 0x686a */ { false, 0x686a, 0x686a }, +/* 0x686b */ { false, 0x686b, 0x686b }, +/* 0x686c */ { false, 0x686c, 0x686c }, +/* 0x686d */ { false, 0x686d, 0x686d }, +/* 0x686e */ { false, 0x686e, 0x686e }, +/* 0x686f */ { false, 0x686f, 0x686f }, +/* 0x6870 */ { false, 0x6870, 0x6870 }, +/* 0x6871 */ { false, 0x6871, 0x6871 }, +/* 0x6872 */ { false, 0x6872, 0x6872 }, +/* 0x6873 */ { false, 0x6873, 0x6873 }, +/* 0x6874 */ { false, 0x6874, 0x6874 }, +/* 0x6875 */ { false, 0x6875, 0x6875 }, +/* 0x6876 */ { false, 0x6876, 0x6876 }, +/* 0x6877 */ { false, 0x6877, 0x6877 }, +/* 0x6878 */ { false, 0x6878, 0x6878 }, +/* 0x6879 */ { false, 0x6879, 0x6879 }, +/* 0x687a */ { false, 0x687a, 0x687a }, +/* 0x687b */ { false, 0x687b, 0x687b }, +/* 0x687c */ { false, 0x687c, 0x687c }, +/* 0x687d */ { false, 0x687d, 0x687d }, +/* 0x687e */ { false, 0x687e, 0x687e }, +/* 0x687f */ { false, 0x687f, 0x687f }, +/* 0x6880 */ { false, 0x6880, 0x6880 }, +/* 0x6881 */ { false, 0x6881, 0x6881 }, +/* 0x6882 */ { false, 0x6882, 0x6882 }, +/* 0x6883 */ { false, 0x6883, 0x6883 }, +/* 0x6884 */ { false, 0x6884, 0x6884 }, +/* 0x6885 */ { false, 0x6885, 0x6885 }, +/* 0x6886 */ { false, 0x6886, 0x6886 }, +/* 0x6887 */ { false, 0x6887, 0x6887 }, +/* 0x6888 */ { false, 0x6888, 0x6888 }, +/* 0x6889 */ { false, 0x6889, 0x6889 }, +/* 0x688a */ { false, 0x688a, 0x688a }, +/* 0x688b */ { false, 0x688b, 0x688b }, +/* 0x688c */ { false, 0x688c, 0x688c }, +/* 0x688d */ { false, 0x688d, 0x688d }, +/* 0x688e */ { false, 0x688e, 0x688e }, +/* 0x688f */ { false, 0x688f, 0x688f }, +/* 0x6890 */ { false, 0x6890, 0x6890 }, +/* 0x6891 */ { false, 0x6891, 0x6891 }, +/* 0x6892 */ { false, 0x6892, 0x6892 }, +/* 0x6893 */ { false, 0x6893, 0x6893 }, +/* 0x6894 */ { false, 0x6894, 0x6894 }, +/* 0x6895 */ { false, 0x6895, 0x6895 }, +/* 0x6896 */ { false, 0x6896, 0x6896 }, +/* 0x6897 */ { false, 0x6897, 0x6897 }, +/* 0x6898 */ { false, 0x6898, 0x6898 }, +/* 0x6899 */ { false, 0x6899, 0x6899 }, +/* 0x689a */ { false, 0x689a, 0x689a }, +/* 0x689b */ { false, 0x689b, 0x689b }, +/* 0x689c */ { false, 0x689c, 0x689c }, +/* 0x689d */ { false, 0x689d, 0x689d }, +/* 0x689e */ { false, 0x689e, 0x689e }, +/* 0x689f */ { false, 0x689f, 0x689f }, +/* 0x68a0 */ { false, 0x68a0, 0x68a0 }, +/* 0x68a1 */ { false, 0x68a1, 0x68a1 }, +/* 0x68a2 */ { false, 0x68a2, 0x68a2 }, +/* 0x68a3 */ { false, 0x68a3, 0x68a3 }, +/* 0x68a4 */ { false, 0x68a4, 0x68a4 }, +/* 0x68a5 */ { false, 0x68a5, 0x68a5 }, +/* 0x68a6 */ { false, 0x68a6, 0x68a6 }, +/* 0x68a7 */ { false, 0x68a7, 0x68a7 }, +/* 0x68a8 */ { false, 0x68a8, 0x68a8 }, +/* 0x68a9 */ { false, 0x68a9, 0x68a9 }, +/* 0x68aa */ { false, 0x68aa, 0x68aa }, +/* 0x68ab */ { false, 0x68ab, 0x68ab }, +/* 0x68ac */ { false, 0x68ac, 0x68ac }, +/* 0x68ad */ { false, 0x68ad, 0x68ad }, +/* 0x68ae */ { false, 0x68ae, 0x68ae }, +/* 0x68af */ { false, 0x68af, 0x68af }, +/* 0x68b0 */ { false, 0x68b0, 0x68b0 }, +/* 0x68b1 */ { false, 0x68b1, 0x68b1 }, +/* 0x68b2 */ { false, 0x68b2, 0x68b2 }, +/* 0x68b3 */ { false, 0x68b3, 0x68b3 }, +/* 0x68b4 */ { false, 0x68b4, 0x68b4 }, +/* 0x68b5 */ { false, 0x68b5, 0x68b5 }, +/* 0x68b6 */ { false, 0x68b6, 0x68b6 }, +/* 0x68b7 */ { false, 0x68b7, 0x68b7 }, +/* 0x68b8 */ { false, 0x68b8, 0x68b8 }, +/* 0x68b9 */ { false, 0x68b9, 0x68b9 }, +/* 0x68ba */ { false, 0x68ba, 0x68ba }, +/* 0x68bb */ { false, 0x68bb, 0x68bb }, +/* 0x68bc */ { false, 0x68bc, 0x68bc }, +/* 0x68bd */ { false, 0x68bd, 0x68bd }, +/* 0x68be */ { false, 0x68be, 0x68be }, +/* 0x68bf */ { false, 0x68bf, 0x68bf }, +/* 0x68c0 */ { false, 0x68c0, 0x68c0 }, +/* 0x68c1 */ { false, 0x68c1, 0x68c1 }, +/* 0x68c2 */ { false, 0x68c2, 0x68c2 }, +/* 0x68c3 */ { false, 0x68c3, 0x68c3 }, +/* 0x68c4 */ { false, 0x68c4, 0x68c4 }, +/* 0x68c5 */ { false, 0x68c5, 0x68c5 }, +/* 0x68c6 */ { false, 0x68c6, 0x68c6 }, +/* 0x68c7 */ { false, 0x68c7, 0x68c7 }, +/* 0x68c8 */ { false, 0x68c8, 0x68c8 }, +/* 0x68c9 */ { false, 0x68c9, 0x68c9 }, +/* 0x68ca */ { false, 0x68ca, 0x68ca }, +/* 0x68cb */ { false, 0x68cb, 0x68cb }, +/* 0x68cc */ { false, 0x68cc, 0x68cc }, +/* 0x68cd */ { false, 0x68cd, 0x68cd }, +/* 0x68ce */ { false, 0x68ce, 0x68ce }, +/* 0x68cf */ { false, 0x68cf, 0x68cf }, +/* 0x68d0 */ { false, 0x68d0, 0x68d0 }, +/* 0x68d1 */ { false, 0x68d1, 0x68d1 }, +/* 0x68d2 */ { false, 0x68d2, 0x68d2 }, +/* 0x68d3 */ { false, 0x68d3, 0x68d3 }, +/* 0x68d4 */ { false, 0x68d4, 0x68d4 }, +/* 0x68d5 */ { false, 0x68d5, 0x68d5 }, +/* 0x68d6 */ { false, 0x68d6, 0x68d6 }, +/* 0x68d7 */ { false, 0x68d7, 0x68d7 }, +/* 0x68d8 */ { false, 0x68d8, 0x68d8 }, +/* 0x68d9 */ { false, 0x68d9, 0x68d9 }, +/* 0x68da */ { false, 0x68da, 0x68da }, +/* 0x68db */ { false, 0x68db, 0x68db }, +/* 0x68dc */ { false, 0x68dc, 0x68dc }, +/* 0x68dd */ { false, 0x68dd, 0x68dd }, +/* 0x68de */ { false, 0x68de, 0x68de }, +/* 0x68df */ { false, 0x68df, 0x68df }, +/* 0x68e0 */ { false, 0x68e0, 0x68e0 }, +/* 0x68e1 */ { false, 0x68e1, 0x68e1 }, +/* 0x68e2 */ { false, 0x68e2, 0x68e2 }, +/* 0x68e3 */ { false, 0x68e3, 0x68e3 }, +/* 0x68e4 */ { false, 0x68e4, 0x68e4 }, +/* 0x68e5 */ { false, 0x68e5, 0x68e5 }, +/* 0x68e6 */ { false, 0x68e6, 0x68e6 }, +/* 0x68e7 */ { false, 0x68e7, 0x68e7 }, +/* 0x68e8 */ { false, 0x68e8, 0x68e8 }, +/* 0x68e9 */ { false, 0x68e9, 0x68e9 }, +/* 0x68ea */ { false, 0x68ea, 0x68ea }, +/* 0x68eb */ { false, 0x68eb, 0x68eb }, +/* 0x68ec */ { false, 0x68ec, 0x68ec }, +/* 0x68ed */ { false, 0x68ed, 0x68ed }, +/* 0x68ee */ { false, 0x68ee, 0x68ee }, +/* 0x68ef */ { false, 0x68ef, 0x68ef }, +/* 0x68f0 */ { false, 0x68f0, 0x68f0 }, +/* 0x68f1 */ { false, 0x68f1, 0x68f1 }, +/* 0x68f2 */ { false, 0x68f2, 0x68f2 }, +/* 0x68f3 */ { false, 0x68f3, 0x68f3 }, +/* 0x68f4 */ { false, 0x68f4, 0x68f4 }, +/* 0x68f5 */ { false, 0x68f5, 0x68f5 }, +/* 0x68f6 */ { false, 0x68f6, 0x68f6 }, +/* 0x68f7 */ { false, 0x68f7, 0x68f7 }, +/* 0x68f8 */ { false, 0x68f8, 0x68f8 }, +/* 0x68f9 */ { false, 0x68f9, 0x68f9 }, +/* 0x68fa */ { false, 0x68fa, 0x68fa }, +/* 0x68fb */ { false, 0x68fb, 0x68fb }, +/* 0x68fc */ { false, 0x68fc, 0x68fc }, +/* 0x68fd */ { false, 0x68fd, 0x68fd }, +/* 0x68fe */ { false, 0x68fe, 0x68fe }, +/* 0x68ff */ { false, 0x68ff, 0x68ff }, +/* 0x6900 */ { false, 0x6900, 0x6900 }, +/* 0x6901 */ { false, 0x6901, 0x6901 }, +/* 0x6902 */ { false, 0x6902, 0x6902 }, +/* 0x6903 */ { false, 0x6903, 0x6903 }, +/* 0x6904 */ { false, 0x6904, 0x6904 }, +/* 0x6905 */ { false, 0x6905, 0x6905 }, +/* 0x6906 */ { false, 0x6906, 0x6906 }, +/* 0x6907 */ { false, 0x6907, 0x6907 }, +/* 0x6908 */ { false, 0x6908, 0x6908 }, +/* 0x6909 */ { false, 0x6909, 0x6909 }, +/* 0x690a */ { false, 0x690a, 0x690a }, +/* 0x690b */ { false, 0x690b, 0x690b }, +/* 0x690c */ { false, 0x690c, 0x690c }, +/* 0x690d */ { false, 0x690d, 0x690d }, +/* 0x690e */ { false, 0x690e, 0x690e }, +/* 0x690f */ { false, 0x690f, 0x690f }, +/* 0x6910 */ { false, 0x6910, 0x6910 }, +/* 0x6911 */ { false, 0x6911, 0x6911 }, +/* 0x6912 */ { false, 0x6912, 0x6912 }, +/* 0x6913 */ { false, 0x6913, 0x6913 }, +/* 0x6914 */ { false, 0x6914, 0x6914 }, +/* 0x6915 */ { false, 0x6915, 0x6915 }, +/* 0x6916 */ { false, 0x6916, 0x6916 }, +/* 0x6917 */ { false, 0x6917, 0x6917 }, +/* 0x6918 */ { false, 0x6918, 0x6918 }, +/* 0x6919 */ { false, 0x6919, 0x6919 }, +/* 0x691a */ { false, 0x691a, 0x691a }, +/* 0x691b */ { false, 0x691b, 0x691b }, +/* 0x691c */ { false, 0x691c, 0x691c }, +/* 0x691d */ { false, 0x691d, 0x691d }, +/* 0x691e */ { false, 0x691e, 0x691e }, +/* 0x691f */ { false, 0x691f, 0x691f }, +/* 0x6920 */ { false, 0x6920, 0x6920 }, +/* 0x6921 */ { false, 0x6921, 0x6921 }, +/* 0x6922 */ { false, 0x6922, 0x6922 }, +/* 0x6923 */ { false, 0x6923, 0x6923 }, +/* 0x6924 */ { false, 0x6924, 0x6924 }, +/* 0x6925 */ { false, 0x6925, 0x6925 }, +/* 0x6926 */ { false, 0x6926, 0x6926 }, +/* 0x6927 */ { false, 0x6927, 0x6927 }, +/* 0x6928 */ { false, 0x6928, 0x6928 }, +/* 0x6929 */ { false, 0x6929, 0x6929 }, +/* 0x692a */ { false, 0x692a, 0x692a }, +/* 0x692b */ { false, 0x692b, 0x692b }, +/* 0x692c */ { false, 0x692c, 0x692c }, +/* 0x692d */ { false, 0x692d, 0x692d }, +/* 0x692e */ { false, 0x692e, 0x692e }, +/* 0x692f */ { false, 0x692f, 0x692f }, +/* 0x6930 */ { false, 0x6930, 0x6930 }, +/* 0x6931 */ { false, 0x6931, 0x6931 }, +/* 0x6932 */ { false, 0x6932, 0x6932 }, +/* 0x6933 */ { false, 0x6933, 0x6933 }, +/* 0x6934 */ { false, 0x6934, 0x6934 }, +/* 0x6935 */ { false, 0x6935, 0x6935 }, +/* 0x6936 */ { false, 0x6936, 0x6936 }, +/* 0x6937 */ { false, 0x6937, 0x6937 }, +/* 0x6938 */ { false, 0x6938, 0x6938 }, +/* 0x6939 */ { false, 0x6939, 0x6939 }, +/* 0x693a */ { false, 0x693a, 0x693a }, +/* 0x693b */ { false, 0x693b, 0x693b }, +/* 0x693c */ { false, 0x693c, 0x693c }, +/* 0x693d */ { false, 0x693d, 0x693d }, +/* 0x693e */ { false, 0x693e, 0x693e }, +/* 0x693f */ { false, 0x693f, 0x693f }, +/* 0x6940 */ { false, 0x6940, 0x6940 }, +/* 0x6941 */ { false, 0x6941, 0x6941 }, +/* 0x6942 */ { false, 0x6942, 0x6942 }, +/* 0x6943 */ { false, 0x6943, 0x6943 }, +/* 0x6944 */ { false, 0x6944, 0x6944 }, +/* 0x6945 */ { false, 0x6945, 0x6945 }, +/* 0x6946 */ { false, 0x6946, 0x6946 }, +/* 0x6947 */ { false, 0x6947, 0x6947 }, +/* 0x6948 */ { false, 0x6948, 0x6948 }, +/* 0x6949 */ { false, 0x6949, 0x6949 }, +/* 0x694a */ { false, 0x694a, 0x694a }, +/* 0x694b */ { false, 0x694b, 0x694b }, +/* 0x694c */ { false, 0x694c, 0x694c }, +/* 0x694d */ { false, 0x694d, 0x694d }, +/* 0x694e */ { false, 0x694e, 0x694e }, +/* 0x694f */ { false, 0x694f, 0x694f }, +/* 0x6950 */ { false, 0x6950, 0x6950 }, +/* 0x6951 */ { false, 0x6951, 0x6951 }, +/* 0x6952 */ { false, 0x6952, 0x6952 }, +/* 0x6953 */ { false, 0x6953, 0x6953 }, +/* 0x6954 */ { false, 0x6954, 0x6954 }, +/* 0x6955 */ { false, 0x6955, 0x6955 }, +/* 0x6956 */ { false, 0x6956, 0x6956 }, +/* 0x6957 */ { false, 0x6957, 0x6957 }, +/* 0x6958 */ { false, 0x6958, 0x6958 }, +/* 0x6959 */ { false, 0x6959, 0x6959 }, +/* 0x695a */ { false, 0x695a, 0x695a }, +/* 0x695b */ { false, 0x695b, 0x695b }, +/* 0x695c */ { false, 0x695c, 0x695c }, +/* 0x695d */ { false, 0x695d, 0x695d }, +/* 0x695e */ { false, 0x695e, 0x695e }, +/* 0x695f */ { false, 0x695f, 0x695f }, +/* 0x6960 */ { false, 0x6960, 0x6960 }, +/* 0x6961 */ { false, 0x6961, 0x6961 }, +/* 0x6962 */ { false, 0x6962, 0x6962 }, +/* 0x6963 */ { false, 0x6963, 0x6963 }, +/* 0x6964 */ { false, 0x6964, 0x6964 }, +/* 0x6965 */ { false, 0x6965, 0x6965 }, +/* 0x6966 */ { false, 0x6966, 0x6966 }, +/* 0x6967 */ { false, 0x6967, 0x6967 }, +/* 0x6968 */ { false, 0x6968, 0x6968 }, +/* 0x6969 */ { false, 0x6969, 0x6969 }, +/* 0x696a */ { false, 0x696a, 0x696a }, +/* 0x696b */ { false, 0x696b, 0x696b }, +/* 0x696c */ { false, 0x696c, 0x696c }, +/* 0x696d */ { false, 0x696d, 0x696d }, +/* 0x696e */ { false, 0x696e, 0x696e }, +/* 0x696f */ { false, 0x696f, 0x696f }, +/* 0x6970 */ { false, 0x6970, 0x6970 }, +/* 0x6971 */ { false, 0x6971, 0x6971 }, +/* 0x6972 */ { false, 0x6972, 0x6972 }, +/* 0x6973 */ { false, 0x6973, 0x6973 }, +/* 0x6974 */ { false, 0x6974, 0x6974 }, +/* 0x6975 */ { false, 0x6975, 0x6975 }, +/* 0x6976 */ { false, 0x6976, 0x6976 }, +/* 0x6977 */ { false, 0x6977, 0x6977 }, +/* 0x6978 */ { false, 0x6978, 0x6978 }, +/* 0x6979 */ { false, 0x6979, 0x6979 }, +/* 0x697a */ { false, 0x697a, 0x697a }, +/* 0x697b */ { false, 0x697b, 0x697b }, +/* 0x697c */ { false, 0x697c, 0x697c }, +/* 0x697d */ { false, 0x697d, 0x697d }, +/* 0x697e */ { false, 0x697e, 0x697e }, +/* 0x697f */ { false, 0x697f, 0x697f }, +/* 0x6980 */ { false, 0x6980, 0x6980 }, +/* 0x6981 */ { false, 0x6981, 0x6981 }, +/* 0x6982 */ { false, 0x6982, 0x6982 }, +/* 0x6983 */ { false, 0x6983, 0x6983 }, +/* 0x6984 */ { false, 0x6984, 0x6984 }, +/* 0x6985 */ { false, 0x6985, 0x6985 }, +/* 0x6986 */ { false, 0x6986, 0x6986 }, +/* 0x6987 */ { false, 0x6987, 0x6987 }, +/* 0x6988 */ { false, 0x6988, 0x6988 }, +/* 0x6989 */ { false, 0x6989, 0x6989 }, +/* 0x698a */ { false, 0x698a, 0x698a }, +/* 0x698b */ { false, 0x698b, 0x698b }, +/* 0x698c */ { false, 0x698c, 0x698c }, +/* 0x698d */ { false, 0x698d, 0x698d }, +/* 0x698e */ { false, 0x698e, 0x698e }, +/* 0x698f */ { false, 0x698f, 0x698f }, +/* 0x6990 */ { false, 0x6990, 0x6990 }, +/* 0x6991 */ { false, 0x6991, 0x6991 }, +/* 0x6992 */ { false, 0x6992, 0x6992 }, +/* 0x6993 */ { false, 0x6993, 0x6993 }, +/* 0x6994 */ { false, 0x6994, 0x6994 }, +/* 0x6995 */ { false, 0x6995, 0x6995 }, +/* 0x6996 */ { false, 0x6996, 0x6996 }, +/* 0x6997 */ { false, 0x6997, 0x6997 }, +/* 0x6998 */ { false, 0x6998, 0x6998 }, +/* 0x6999 */ { false, 0x6999, 0x6999 }, +/* 0x699a */ { false, 0x699a, 0x699a }, +/* 0x699b */ { false, 0x699b, 0x699b }, +/* 0x699c */ { false, 0x699c, 0x699c }, +/* 0x699d */ { false, 0x699d, 0x699d }, +/* 0x699e */ { false, 0x699e, 0x699e }, +/* 0x699f */ { false, 0x699f, 0x699f }, +/* 0x69a0 */ { false, 0x69a0, 0x69a0 }, +/* 0x69a1 */ { false, 0x69a1, 0x69a1 }, +/* 0x69a2 */ { false, 0x69a2, 0x69a2 }, +/* 0x69a3 */ { false, 0x69a3, 0x69a3 }, +/* 0x69a4 */ { false, 0x69a4, 0x69a4 }, +/* 0x69a5 */ { false, 0x69a5, 0x69a5 }, +/* 0x69a6 */ { false, 0x69a6, 0x69a6 }, +/* 0x69a7 */ { false, 0x69a7, 0x69a7 }, +/* 0x69a8 */ { false, 0x69a8, 0x69a8 }, +/* 0x69a9 */ { false, 0x69a9, 0x69a9 }, +/* 0x69aa */ { false, 0x69aa, 0x69aa }, +/* 0x69ab */ { false, 0x69ab, 0x69ab }, +/* 0x69ac */ { false, 0x69ac, 0x69ac }, +/* 0x69ad */ { false, 0x69ad, 0x69ad }, +/* 0x69ae */ { false, 0x69ae, 0x69ae }, +/* 0x69af */ { false, 0x69af, 0x69af }, +/* 0x69b0 */ { false, 0x69b0, 0x69b0 }, +/* 0x69b1 */ { false, 0x69b1, 0x69b1 }, +/* 0x69b2 */ { false, 0x69b2, 0x69b2 }, +/* 0x69b3 */ { false, 0x69b3, 0x69b3 }, +/* 0x69b4 */ { false, 0x69b4, 0x69b4 }, +/* 0x69b5 */ { false, 0x69b5, 0x69b5 }, +/* 0x69b6 */ { false, 0x69b6, 0x69b6 }, +/* 0x69b7 */ { false, 0x69b7, 0x69b7 }, +/* 0x69b8 */ { false, 0x69b8, 0x69b8 }, +/* 0x69b9 */ { false, 0x69b9, 0x69b9 }, +/* 0x69ba */ { false, 0x69ba, 0x69ba }, +/* 0x69bb */ { false, 0x69bb, 0x69bb }, +/* 0x69bc */ { false, 0x69bc, 0x69bc }, +/* 0x69bd */ { false, 0x69bd, 0x69bd }, +/* 0x69be */ { false, 0x69be, 0x69be }, +/* 0x69bf */ { false, 0x69bf, 0x69bf }, +/* 0x69c0 */ { false, 0x69c0, 0x69c0 }, +/* 0x69c1 */ { false, 0x69c1, 0x69c1 }, +/* 0x69c2 */ { false, 0x69c2, 0x69c2 }, +/* 0x69c3 */ { false, 0x69c3, 0x69c3 }, +/* 0x69c4 */ { false, 0x69c4, 0x69c4 }, +/* 0x69c5 */ { false, 0x69c5, 0x69c5 }, +/* 0x69c6 */ { false, 0x69c6, 0x69c6 }, +/* 0x69c7 */ { false, 0x69c7, 0x69c7 }, +/* 0x69c8 */ { false, 0x69c8, 0x69c8 }, +/* 0x69c9 */ { false, 0x69c9, 0x69c9 }, +/* 0x69ca */ { false, 0x69ca, 0x69ca }, +/* 0x69cb */ { false, 0x69cb, 0x69cb }, +/* 0x69cc */ { false, 0x69cc, 0x69cc }, +/* 0x69cd */ { false, 0x69cd, 0x69cd }, +/* 0x69ce */ { false, 0x69ce, 0x69ce }, +/* 0x69cf */ { false, 0x69cf, 0x69cf }, +/* 0x69d0 */ { false, 0x69d0, 0x69d0 }, +/* 0x69d1 */ { false, 0x69d1, 0x69d1 }, +/* 0x69d2 */ { false, 0x69d2, 0x69d2 }, +/* 0x69d3 */ { false, 0x69d3, 0x69d3 }, +/* 0x69d4 */ { false, 0x69d4, 0x69d4 }, +/* 0x69d5 */ { false, 0x69d5, 0x69d5 }, +/* 0x69d6 */ { false, 0x69d6, 0x69d6 }, +/* 0x69d7 */ { false, 0x69d7, 0x69d7 }, +/* 0x69d8 */ { false, 0x69d8, 0x69d8 }, +/* 0x69d9 */ { false, 0x69d9, 0x69d9 }, +/* 0x69da */ { false, 0x69da, 0x69da }, +/* 0x69db */ { false, 0x69db, 0x69db }, +/* 0x69dc */ { false, 0x69dc, 0x69dc }, +/* 0x69dd */ { false, 0x69dd, 0x69dd }, +/* 0x69de */ { false, 0x69de, 0x69de }, +/* 0x69df */ { false, 0x69df, 0x69df }, +/* 0x69e0 */ { false, 0x69e0, 0x69e0 }, +/* 0x69e1 */ { false, 0x69e1, 0x69e1 }, +/* 0x69e2 */ { false, 0x69e2, 0x69e2 }, +/* 0x69e3 */ { false, 0x69e3, 0x69e3 }, +/* 0x69e4 */ { false, 0x69e4, 0x69e4 }, +/* 0x69e5 */ { false, 0x69e5, 0x69e5 }, +/* 0x69e6 */ { false, 0x69e6, 0x69e6 }, +/* 0x69e7 */ { false, 0x69e7, 0x69e7 }, +/* 0x69e8 */ { false, 0x69e8, 0x69e8 }, +/* 0x69e9 */ { false, 0x69e9, 0x69e9 }, +/* 0x69ea */ { false, 0x69ea, 0x69ea }, +/* 0x69eb */ { false, 0x69eb, 0x69eb }, +/* 0x69ec */ { false, 0x69ec, 0x69ec }, +/* 0x69ed */ { false, 0x69ed, 0x69ed }, +/* 0x69ee */ { false, 0x69ee, 0x69ee }, +/* 0x69ef */ { false, 0x69ef, 0x69ef }, +/* 0x69f0 */ { false, 0x69f0, 0x69f0 }, +/* 0x69f1 */ { false, 0x69f1, 0x69f1 }, +/* 0x69f2 */ { false, 0x69f2, 0x69f2 }, +/* 0x69f3 */ { false, 0x69f3, 0x69f3 }, +/* 0x69f4 */ { false, 0x69f4, 0x69f4 }, +/* 0x69f5 */ { false, 0x69f5, 0x69f5 }, +/* 0x69f6 */ { false, 0x69f6, 0x69f6 }, +/* 0x69f7 */ { false, 0x69f7, 0x69f7 }, +/* 0x69f8 */ { false, 0x69f8, 0x69f8 }, +/* 0x69f9 */ { false, 0x69f9, 0x69f9 }, +/* 0x69fa */ { false, 0x69fa, 0x69fa }, +/* 0x69fb */ { false, 0x69fb, 0x69fb }, +/* 0x69fc */ { false, 0x69fc, 0x69fc }, +/* 0x69fd */ { false, 0x69fd, 0x69fd }, +/* 0x69fe */ { false, 0x69fe, 0x69fe }, +/* 0x69ff */ { false, 0x69ff, 0x69ff }, +/* 0x6a00 */ { false, 0x6a00, 0x6a00 }, +/* 0x6a01 */ { false, 0x6a01, 0x6a01 }, +/* 0x6a02 */ { false, 0x6a02, 0x6a02 }, +/* 0x6a03 */ { false, 0x6a03, 0x6a03 }, +/* 0x6a04 */ { false, 0x6a04, 0x6a04 }, +/* 0x6a05 */ { false, 0x6a05, 0x6a05 }, +/* 0x6a06 */ { false, 0x6a06, 0x6a06 }, +/* 0x6a07 */ { false, 0x6a07, 0x6a07 }, +/* 0x6a08 */ { false, 0x6a08, 0x6a08 }, +/* 0x6a09 */ { false, 0x6a09, 0x6a09 }, +/* 0x6a0a */ { false, 0x6a0a, 0x6a0a }, +/* 0x6a0b */ { false, 0x6a0b, 0x6a0b }, +/* 0x6a0c */ { false, 0x6a0c, 0x6a0c }, +/* 0x6a0d */ { false, 0x6a0d, 0x6a0d }, +/* 0x6a0e */ { false, 0x6a0e, 0x6a0e }, +/* 0x6a0f */ { false, 0x6a0f, 0x6a0f }, +/* 0x6a10 */ { false, 0x6a10, 0x6a10 }, +/* 0x6a11 */ { false, 0x6a11, 0x6a11 }, +/* 0x6a12 */ { false, 0x6a12, 0x6a12 }, +/* 0x6a13 */ { false, 0x6a13, 0x6a13 }, +/* 0x6a14 */ { false, 0x6a14, 0x6a14 }, +/* 0x6a15 */ { false, 0x6a15, 0x6a15 }, +/* 0x6a16 */ { false, 0x6a16, 0x6a16 }, +/* 0x6a17 */ { false, 0x6a17, 0x6a17 }, +/* 0x6a18 */ { false, 0x6a18, 0x6a18 }, +/* 0x6a19 */ { false, 0x6a19, 0x6a19 }, +/* 0x6a1a */ { false, 0x6a1a, 0x6a1a }, +/* 0x6a1b */ { false, 0x6a1b, 0x6a1b }, +/* 0x6a1c */ { false, 0x6a1c, 0x6a1c }, +/* 0x6a1d */ { false, 0x6a1d, 0x6a1d }, +/* 0x6a1e */ { false, 0x6a1e, 0x6a1e }, +/* 0x6a1f */ { false, 0x6a1f, 0x6a1f }, +/* 0x6a20 */ { false, 0x6a20, 0x6a20 }, +/* 0x6a21 */ { false, 0x6a21, 0x6a21 }, +/* 0x6a22 */ { false, 0x6a22, 0x6a22 }, +/* 0x6a23 */ { false, 0x6a23, 0x6a23 }, +/* 0x6a24 */ { false, 0x6a24, 0x6a24 }, +/* 0x6a25 */ { false, 0x6a25, 0x6a25 }, +/* 0x6a26 */ { false, 0x6a26, 0x6a26 }, +/* 0x6a27 */ { false, 0x6a27, 0x6a27 }, +/* 0x6a28 */ { false, 0x6a28, 0x6a28 }, +/* 0x6a29 */ { false, 0x6a29, 0x6a29 }, +/* 0x6a2a */ { false, 0x6a2a, 0x6a2a }, +/* 0x6a2b */ { false, 0x6a2b, 0x6a2b }, +/* 0x6a2c */ { false, 0x6a2c, 0x6a2c }, +/* 0x6a2d */ { false, 0x6a2d, 0x6a2d }, +/* 0x6a2e */ { false, 0x6a2e, 0x6a2e }, +/* 0x6a2f */ { false, 0x6a2f, 0x6a2f }, +/* 0x6a30 */ { false, 0x6a30, 0x6a30 }, +/* 0x6a31 */ { false, 0x6a31, 0x6a31 }, +/* 0x6a32 */ { false, 0x6a32, 0x6a32 }, +/* 0x6a33 */ { false, 0x6a33, 0x6a33 }, +/* 0x6a34 */ { false, 0x6a34, 0x6a34 }, +/* 0x6a35 */ { false, 0x6a35, 0x6a35 }, +/* 0x6a36 */ { false, 0x6a36, 0x6a36 }, +/* 0x6a37 */ { false, 0x6a37, 0x6a37 }, +/* 0x6a38 */ { false, 0x6a38, 0x6a38 }, +/* 0x6a39 */ { false, 0x6a39, 0x6a39 }, +/* 0x6a3a */ { false, 0x6a3a, 0x6a3a }, +/* 0x6a3b */ { false, 0x6a3b, 0x6a3b }, +/* 0x6a3c */ { false, 0x6a3c, 0x6a3c }, +/* 0x6a3d */ { false, 0x6a3d, 0x6a3d }, +/* 0x6a3e */ { false, 0x6a3e, 0x6a3e }, +/* 0x6a3f */ { false, 0x6a3f, 0x6a3f }, +/* 0x6a40 */ { false, 0x6a40, 0x6a40 }, +/* 0x6a41 */ { false, 0x6a41, 0x6a41 }, +/* 0x6a42 */ { false, 0x6a42, 0x6a42 }, +/* 0x6a43 */ { false, 0x6a43, 0x6a43 }, +/* 0x6a44 */ { false, 0x6a44, 0x6a44 }, +/* 0x6a45 */ { false, 0x6a45, 0x6a45 }, +/* 0x6a46 */ { false, 0x6a46, 0x6a46 }, +/* 0x6a47 */ { false, 0x6a47, 0x6a47 }, +/* 0x6a48 */ { false, 0x6a48, 0x6a48 }, +/* 0x6a49 */ { false, 0x6a49, 0x6a49 }, +/* 0x6a4a */ { false, 0x6a4a, 0x6a4a }, +/* 0x6a4b */ { false, 0x6a4b, 0x6a4b }, +/* 0x6a4c */ { false, 0x6a4c, 0x6a4c }, +/* 0x6a4d */ { false, 0x6a4d, 0x6a4d }, +/* 0x6a4e */ { false, 0x6a4e, 0x6a4e }, +/* 0x6a4f */ { false, 0x6a4f, 0x6a4f }, +/* 0x6a50 */ { false, 0x6a50, 0x6a50 }, +/* 0x6a51 */ { false, 0x6a51, 0x6a51 }, +/* 0x6a52 */ { false, 0x6a52, 0x6a52 }, +/* 0x6a53 */ { false, 0x6a53, 0x6a53 }, +/* 0x6a54 */ { false, 0x6a54, 0x6a54 }, +/* 0x6a55 */ { false, 0x6a55, 0x6a55 }, +/* 0x6a56 */ { false, 0x6a56, 0x6a56 }, +/* 0x6a57 */ { false, 0x6a57, 0x6a57 }, +/* 0x6a58 */ { false, 0x6a58, 0x6a58 }, +/* 0x6a59 */ { false, 0x6a59, 0x6a59 }, +/* 0x6a5a */ { false, 0x6a5a, 0x6a5a }, +/* 0x6a5b */ { false, 0x6a5b, 0x6a5b }, +/* 0x6a5c */ { false, 0x6a5c, 0x6a5c }, +/* 0x6a5d */ { false, 0x6a5d, 0x6a5d }, +/* 0x6a5e */ { false, 0x6a5e, 0x6a5e }, +/* 0x6a5f */ { false, 0x6a5f, 0x6a5f }, +/* 0x6a60 */ { false, 0x6a60, 0x6a60 }, +/* 0x6a61 */ { false, 0x6a61, 0x6a61 }, +/* 0x6a62 */ { false, 0x6a62, 0x6a62 }, +/* 0x6a63 */ { false, 0x6a63, 0x6a63 }, +/* 0x6a64 */ { false, 0x6a64, 0x6a64 }, +/* 0x6a65 */ { false, 0x6a65, 0x6a65 }, +/* 0x6a66 */ { false, 0x6a66, 0x6a66 }, +/* 0x6a67 */ { false, 0x6a67, 0x6a67 }, +/* 0x6a68 */ { false, 0x6a68, 0x6a68 }, +/* 0x6a69 */ { false, 0x6a69, 0x6a69 }, +/* 0x6a6a */ { false, 0x6a6a, 0x6a6a }, +/* 0x6a6b */ { false, 0x6a6b, 0x6a6b }, +/* 0x6a6c */ { false, 0x6a6c, 0x6a6c }, +/* 0x6a6d */ { false, 0x6a6d, 0x6a6d }, +/* 0x6a6e */ { false, 0x6a6e, 0x6a6e }, +/* 0x6a6f */ { false, 0x6a6f, 0x6a6f }, +/* 0x6a70 */ { false, 0x6a70, 0x6a70 }, +/* 0x6a71 */ { false, 0x6a71, 0x6a71 }, +/* 0x6a72 */ { false, 0x6a72, 0x6a72 }, +/* 0x6a73 */ { false, 0x6a73, 0x6a73 }, +/* 0x6a74 */ { false, 0x6a74, 0x6a74 }, +/* 0x6a75 */ { false, 0x6a75, 0x6a75 }, +/* 0x6a76 */ { false, 0x6a76, 0x6a76 }, +/* 0x6a77 */ { false, 0x6a77, 0x6a77 }, +/* 0x6a78 */ { false, 0x6a78, 0x6a78 }, +/* 0x6a79 */ { false, 0x6a79, 0x6a79 }, +/* 0x6a7a */ { false, 0x6a7a, 0x6a7a }, +/* 0x6a7b */ { false, 0x6a7b, 0x6a7b }, +/* 0x6a7c */ { false, 0x6a7c, 0x6a7c }, +/* 0x6a7d */ { false, 0x6a7d, 0x6a7d }, +/* 0x6a7e */ { false, 0x6a7e, 0x6a7e }, +/* 0x6a7f */ { false, 0x6a7f, 0x6a7f }, +/* 0x6a80 */ { false, 0x6a80, 0x6a80 }, +/* 0x6a81 */ { false, 0x6a81, 0x6a81 }, +/* 0x6a82 */ { false, 0x6a82, 0x6a82 }, +/* 0x6a83 */ { false, 0x6a83, 0x6a83 }, +/* 0x6a84 */ { false, 0x6a84, 0x6a84 }, +/* 0x6a85 */ { false, 0x6a85, 0x6a85 }, +/* 0x6a86 */ { false, 0x6a86, 0x6a86 }, +/* 0x6a87 */ { false, 0x6a87, 0x6a87 }, +/* 0x6a88 */ { false, 0x6a88, 0x6a88 }, +/* 0x6a89 */ { false, 0x6a89, 0x6a89 }, +/* 0x6a8a */ { false, 0x6a8a, 0x6a8a }, +/* 0x6a8b */ { false, 0x6a8b, 0x6a8b }, +/* 0x6a8c */ { false, 0x6a8c, 0x6a8c }, +/* 0x6a8d */ { false, 0x6a8d, 0x6a8d }, +/* 0x6a8e */ { false, 0x6a8e, 0x6a8e }, +/* 0x6a8f */ { false, 0x6a8f, 0x6a8f }, +/* 0x6a90 */ { false, 0x6a90, 0x6a90 }, +/* 0x6a91 */ { false, 0x6a91, 0x6a91 }, +/* 0x6a92 */ { false, 0x6a92, 0x6a92 }, +/* 0x6a93 */ { false, 0x6a93, 0x6a93 }, +/* 0x6a94 */ { false, 0x6a94, 0x6a94 }, +/* 0x6a95 */ { false, 0x6a95, 0x6a95 }, +/* 0x6a96 */ { false, 0x6a96, 0x6a96 }, +/* 0x6a97 */ { false, 0x6a97, 0x6a97 }, +/* 0x6a98 */ { false, 0x6a98, 0x6a98 }, +/* 0x6a99 */ { false, 0x6a99, 0x6a99 }, +/* 0x6a9a */ { false, 0x6a9a, 0x6a9a }, +/* 0x6a9b */ { false, 0x6a9b, 0x6a9b }, +/* 0x6a9c */ { false, 0x6a9c, 0x6a9c }, +/* 0x6a9d */ { false, 0x6a9d, 0x6a9d }, +/* 0x6a9e */ { false, 0x6a9e, 0x6a9e }, +/* 0x6a9f */ { false, 0x6a9f, 0x6a9f }, +/* 0x6aa0 */ { false, 0x6aa0, 0x6aa0 }, +/* 0x6aa1 */ { false, 0x6aa1, 0x6aa1 }, +/* 0x6aa2 */ { false, 0x6aa2, 0x6aa2 }, +/* 0x6aa3 */ { false, 0x6aa3, 0x6aa3 }, +/* 0x6aa4 */ { false, 0x6aa4, 0x6aa4 }, +/* 0x6aa5 */ { false, 0x6aa5, 0x6aa5 }, +/* 0x6aa6 */ { false, 0x6aa6, 0x6aa6 }, +/* 0x6aa7 */ { false, 0x6aa7, 0x6aa7 }, +/* 0x6aa8 */ { false, 0x6aa8, 0x6aa8 }, +/* 0x6aa9 */ { false, 0x6aa9, 0x6aa9 }, +/* 0x6aaa */ { false, 0x6aaa, 0x6aaa }, +/* 0x6aab */ { false, 0x6aab, 0x6aab }, +/* 0x6aac */ { false, 0x6aac, 0x6aac }, +/* 0x6aad */ { false, 0x6aad, 0x6aad }, +/* 0x6aae */ { false, 0x6aae, 0x6aae }, +/* 0x6aaf */ { false, 0x6aaf, 0x6aaf }, +/* 0x6ab0 */ { false, 0x6ab0, 0x6ab0 }, +/* 0x6ab1 */ { false, 0x6ab1, 0x6ab1 }, +/* 0x6ab2 */ { false, 0x6ab2, 0x6ab2 }, +/* 0x6ab3 */ { false, 0x6ab3, 0x6ab3 }, +/* 0x6ab4 */ { false, 0x6ab4, 0x6ab4 }, +/* 0x6ab5 */ { false, 0x6ab5, 0x6ab5 }, +/* 0x6ab6 */ { false, 0x6ab6, 0x6ab6 }, +/* 0x6ab7 */ { false, 0x6ab7, 0x6ab7 }, +/* 0x6ab8 */ { false, 0x6ab8, 0x6ab8 }, +/* 0x6ab9 */ { false, 0x6ab9, 0x6ab9 }, +/* 0x6aba */ { false, 0x6aba, 0x6aba }, +/* 0x6abb */ { false, 0x6abb, 0x6abb }, +/* 0x6abc */ { false, 0x6abc, 0x6abc }, +/* 0x6abd */ { false, 0x6abd, 0x6abd }, +/* 0x6abe */ { false, 0x6abe, 0x6abe }, +/* 0x6abf */ { false, 0x6abf, 0x6abf }, +/* 0x6ac0 */ { false, 0x6ac0, 0x6ac0 }, +/* 0x6ac1 */ { false, 0x6ac1, 0x6ac1 }, +/* 0x6ac2 */ { false, 0x6ac2, 0x6ac2 }, +/* 0x6ac3 */ { false, 0x6ac3, 0x6ac3 }, +/* 0x6ac4 */ { false, 0x6ac4, 0x6ac4 }, +/* 0x6ac5 */ { false, 0x6ac5, 0x6ac5 }, +/* 0x6ac6 */ { false, 0x6ac6, 0x6ac6 }, +/* 0x6ac7 */ { false, 0x6ac7, 0x6ac7 }, +/* 0x6ac8 */ { false, 0x6ac8, 0x6ac8 }, +/* 0x6ac9 */ { false, 0x6ac9, 0x6ac9 }, +/* 0x6aca */ { false, 0x6aca, 0x6aca }, +/* 0x6acb */ { false, 0x6acb, 0x6acb }, +/* 0x6acc */ { false, 0x6acc, 0x6acc }, +/* 0x6acd */ { false, 0x6acd, 0x6acd }, +/* 0x6ace */ { false, 0x6ace, 0x6ace }, +/* 0x6acf */ { false, 0x6acf, 0x6acf }, +/* 0x6ad0 */ { false, 0x6ad0, 0x6ad0 }, +/* 0x6ad1 */ { false, 0x6ad1, 0x6ad1 }, +/* 0x6ad2 */ { false, 0x6ad2, 0x6ad2 }, +/* 0x6ad3 */ { false, 0x6ad3, 0x6ad3 }, +/* 0x6ad4 */ { false, 0x6ad4, 0x6ad4 }, +/* 0x6ad5 */ { false, 0x6ad5, 0x6ad5 }, +/* 0x6ad6 */ { false, 0x6ad6, 0x6ad6 }, +/* 0x6ad7 */ { false, 0x6ad7, 0x6ad7 }, +/* 0x6ad8 */ { false, 0x6ad8, 0x6ad8 }, +/* 0x6ad9 */ { false, 0x6ad9, 0x6ad9 }, +/* 0x6ada */ { false, 0x6ada, 0x6ada }, +/* 0x6adb */ { false, 0x6adb, 0x6adb }, +/* 0x6adc */ { false, 0x6adc, 0x6adc }, +/* 0x6add */ { false, 0x6add, 0x6add }, +/* 0x6ade */ { false, 0x6ade, 0x6ade }, +/* 0x6adf */ { false, 0x6adf, 0x6adf }, +/* 0x6ae0 */ { false, 0x6ae0, 0x6ae0 }, +/* 0x6ae1 */ { false, 0x6ae1, 0x6ae1 }, +/* 0x6ae2 */ { false, 0x6ae2, 0x6ae2 }, +/* 0x6ae3 */ { false, 0x6ae3, 0x6ae3 }, +/* 0x6ae4 */ { false, 0x6ae4, 0x6ae4 }, +/* 0x6ae5 */ { false, 0x6ae5, 0x6ae5 }, +/* 0x6ae6 */ { false, 0x6ae6, 0x6ae6 }, +/* 0x6ae7 */ { false, 0x6ae7, 0x6ae7 }, +/* 0x6ae8 */ { false, 0x6ae8, 0x6ae8 }, +/* 0x6ae9 */ { false, 0x6ae9, 0x6ae9 }, +/* 0x6aea */ { false, 0x6aea, 0x6aea }, +/* 0x6aeb */ { false, 0x6aeb, 0x6aeb }, +/* 0x6aec */ { false, 0x6aec, 0x6aec }, +/* 0x6aed */ { false, 0x6aed, 0x6aed }, +/* 0x6aee */ { false, 0x6aee, 0x6aee }, +/* 0x6aef */ { false, 0x6aef, 0x6aef }, +/* 0x6af0 */ { false, 0x6af0, 0x6af0 }, +/* 0x6af1 */ { false, 0x6af1, 0x6af1 }, +/* 0x6af2 */ { false, 0x6af2, 0x6af2 }, +/* 0x6af3 */ { false, 0x6af3, 0x6af3 }, +/* 0x6af4 */ { false, 0x6af4, 0x6af4 }, +/* 0x6af5 */ { false, 0x6af5, 0x6af5 }, +/* 0x6af6 */ { false, 0x6af6, 0x6af6 }, +/* 0x6af7 */ { false, 0x6af7, 0x6af7 }, +/* 0x6af8 */ { false, 0x6af8, 0x6af8 }, +/* 0x6af9 */ { false, 0x6af9, 0x6af9 }, +/* 0x6afa */ { false, 0x6afa, 0x6afa }, +/* 0x6afb */ { false, 0x6afb, 0x6afb }, +/* 0x6afc */ { false, 0x6afc, 0x6afc }, +/* 0x6afd */ { false, 0x6afd, 0x6afd }, +/* 0x6afe */ { false, 0x6afe, 0x6afe }, +/* 0x6aff */ { false, 0x6aff, 0x6aff }, +/* 0x6b00 */ { false, 0x6b00, 0x6b00 }, +/* 0x6b01 */ { false, 0x6b01, 0x6b01 }, +/* 0x6b02 */ { false, 0x6b02, 0x6b02 }, +/* 0x6b03 */ { false, 0x6b03, 0x6b03 }, +/* 0x6b04 */ { false, 0x6b04, 0x6b04 }, +/* 0x6b05 */ { false, 0x6b05, 0x6b05 }, +/* 0x6b06 */ { false, 0x6b06, 0x6b06 }, +/* 0x6b07 */ { false, 0x6b07, 0x6b07 }, +/* 0x6b08 */ { false, 0x6b08, 0x6b08 }, +/* 0x6b09 */ { false, 0x6b09, 0x6b09 }, +/* 0x6b0a */ { false, 0x6b0a, 0x6b0a }, +/* 0x6b0b */ { false, 0x6b0b, 0x6b0b }, +/* 0x6b0c */ { false, 0x6b0c, 0x6b0c }, +/* 0x6b0d */ { false, 0x6b0d, 0x6b0d }, +/* 0x6b0e */ { false, 0x6b0e, 0x6b0e }, +/* 0x6b0f */ { false, 0x6b0f, 0x6b0f }, +/* 0x6b10 */ { false, 0x6b10, 0x6b10 }, +/* 0x6b11 */ { false, 0x6b11, 0x6b11 }, +/* 0x6b12 */ { false, 0x6b12, 0x6b12 }, +/* 0x6b13 */ { false, 0x6b13, 0x6b13 }, +/* 0x6b14 */ { false, 0x6b14, 0x6b14 }, +/* 0x6b15 */ { false, 0x6b15, 0x6b15 }, +/* 0x6b16 */ { false, 0x6b16, 0x6b16 }, +/* 0x6b17 */ { false, 0x6b17, 0x6b17 }, +/* 0x6b18 */ { false, 0x6b18, 0x6b18 }, +/* 0x6b19 */ { false, 0x6b19, 0x6b19 }, +/* 0x6b1a */ { false, 0x6b1a, 0x6b1a }, +/* 0x6b1b */ { false, 0x6b1b, 0x6b1b }, +/* 0x6b1c */ { false, 0x6b1c, 0x6b1c }, +/* 0x6b1d */ { false, 0x6b1d, 0x6b1d }, +/* 0x6b1e */ { false, 0x6b1e, 0x6b1e }, +/* 0x6b1f */ { false, 0x6b1f, 0x6b1f }, +/* 0x6b20 */ { false, 0x6b20, 0x6b20 }, +/* 0x6b21 */ { false, 0x6b21, 0x6b21 }, +/* 0x6b22 */ { false, 0x6b22, 0x6b22 }, +/* 0x6b23 */ { false, 0x6b23, 0x6b23 }, +/* 0x6b24 */ { false, 0x6b24, 0x6b24 }, +/* 0x6b25 */ { false, 0x6b25, 0x6b25 }, +/* 0x6b26 */ { false, 0x6b26, 0x6b26 }, +/* 0x6b27 */ { false, 0x6b27, 0x6b27 }, +/* 0x6b28 */ { false, 0x6b28, 0x6b28 }, +/* 0x6b29 */ { false, 0x6b29, 0x6b29 }, +/* 0x6b2a */ { false, 0x6b2a, 0x6b2a }, +/* 0x6b2b */ { false, 0x6b2b, 0x6b2b }, +/* 0x6b2c */ { false, 0x6b2c, 0x6b2c }, +/* 0x6b2d */ { false, 0x6b2d, 0x6b2d }, +/* 0x6b2e */ { false, 0x6b2e, 0x6b2e }, +/* 0x6b2f */ { false, 0x6b2f, 0x6b2f }, +/* 0x6b30 */ { false, 0x6b30, 0x6b30 }, +/* 0x6b31 */ { false, 0x6b31, 0x6b31 }, +/* 0x6b32 */ { false, 0x6b32, 0x6b32 }, +/* 0x6b33 */ { false, 0x6b33, 0x6b33 }, +/* 0x6b34 */ { false, 0x6b34, 0x6b34 }, +/* 0x6b35 */ { false, 0x6b35, 0x6b35 }, +/* 0x6b36 */ { false, 0x6b36, 0x6b36 }, +/* 0x6b37 */ { false, 0x6b37, 0x6b37 }, +/* 0x6b38 */ { false, 0x6b38, 0x6b38 }, +/* 0x6b39 */ { false, 0x6b39, 0x6b39 }, +/* 0x6b3a */ { false, 0x6b3a, 0x6b3a }, +/* 0x6b3b */ { false, 0x6b3b, 0x6b3b }, +/* 0x6b3c */ { false, 0x6b3c, 0x6b3c }, +/* 0x6b3d */ { false, 0x6b3d, 0x6b3d }, +/* 0x6b3e */ { false, 0x6b3e, 0x6b3e }, +/* 0x6b3f */ { false, 0x6b3f, 0x6b3f }, +/* 0x6b40 */ { false, 0x6b40, 0x6b40 }, +/* 0x6b41 */ { false, 0x6b41, 0x6b41 }, +/* 0x6b42 */ { false, 0x6b42, 0x6b42 }, +/* 0x6b43 */ { false, 0x6b43, 0x6b43 }, +/* 0x6b44 */ { false, 0x6b44, 0x6b44 }, +/* 0x6b45 */ { false, 0x6b45, 0x6b45 }, +/* 0x6b46 */ { false, 0x6b46, 0x6b46 }, +/* 0x6b47 */ { false, 0x6b47, 0x6b47 }, +/* 0x6b48 */ { false, 0x6b48, 0x6b48 }, +/* 0x6b49 */ { false, 0x6b49, 0x6b49 }, +/* 0x6b4a */ { false, 0x6b4a, 0x6b4a }, +/* 0x6b4b */ { false, 0x6b4b, 0x6b4b }, +/* 0x6b4c */ { false, 0x6b4c, 0x6b4c }, +/* 0x6b4d */ { false, 0x6b4d, 0x6b4d }, +/* 0x6b4e */ { false, 0x6b4e, 0x6b4e }, +/* 0x6b4f */ { false, 0x6b4f, 0x6b4f }, +/* 0x6b50 */ { false, 0x6b50, 0x6b50 }, +/* 0x6b51 */ { false, 0x6b51, 0x6b51 }, +/* 0x6b52 */ { false, 0x6b52, 0x6b52 }, +/* 0x6b53 */ { false, 0x6b53, 0x6b53 }, +/* 0x6b54 */ { false, 0x6b54, 0x6b54 }, +/* 0x6b55 */ { false, 0x6b55, 0x6b55 }, +/* 0x6b56 */ { false, 0x6b56, 0x6b56 }, +/* 0x6b57 */ { false, 0x6b57, 0x6b57 }, +/* 0x6b58 */ { false, 0x6b58, 0x6b58 }, +/* 0x6b59 */ { false, 0x6b59, 0x6b59 }, +/* 0x6b5a */ { false, 0x6b5a, 0x6b5a }, +/* 0x6b5b */ { false, 0x6b5b, 0x6b5b }, +/* 0x6b5c */ { false, 0x6b5c, 0x6b5c }, +/* 0x6b5d */ { false, 0x6b5d, 0x6b5d }, +/* 0x6b5e */ { false, 0x6b5e, 0x6b5e }, +/* 0x6b5f */ { false, 0x6b5f, 0x6b5f }, +/* 0x6b60 */ { false, 0x6b60, 0x6b60 }, +/* 0x6b61 */ { false, 0x6b61, 0x6b61 }, +/* 0x6b62 */ { false, 0x6b62, 0x6b62 }, +/* 0x6b63 */ { false, 0x6b63, 0x6b63 }, +/* 0x6b64 */ { false, 0x6b64, 0x6b64 }, +/* 0x6b65 */ { false, 0x6b65, 0x6b65 }, +/* 0x6b66 */ { false, 0x6b66, 0x6b66 }, +/* 0x6b67 */ { false, 0x6b67, 0x6b67 }, +/* 0x6b68 */ { false, 0x6b68, 0x6b68 }, +/* 0x6b69 */ { false, 0x6b69, 0x6b69 }, +/* 0x6b6a */ { false, 0x6b6a, 0x6b6a }, +/* 0x6b6b */ { false, 0x6b6b, 0x6b6b }, +/* 0x6b6c */ { false, 0x6b6c, 0x6b6c }, +/* 0x6b6d */ { false, 0x6b6d, 0x6b6d }, +/* 0x6b6e */ { false, 0x6b6e, 0x6b6e }, +/* 0x6b6f */ { false, 0x6b6f, 0x6b6f }, +/* 0x6b70 */ { false, 0x6b70, 0x6b70 }, +/* 0x6b71 */ { false, 0x6b71, 0x6b71 }, +/* 0x6b72 */ { false, 0x6b72, 0x6b72 }, +/* 0x6b73 */ { false, 0x6b73, 0x6b73 }, +/* 0x6b74 */ { false, 0x6b74, 0x6b74 }, +/* 0x6b75 */ { false, 0x6b75, 0x6b75 }, +/* 0x6b76 */ { false, 0x6b76, 0x6b76 }, +/* 0x6b77 */ { false, 0x6b77, 0x6b77 }, +/* 0x6b78 */ { false, 0x6b78, 0x6b78 }, +/* 0x6b79 */ { false, 0x6b79, 0x6b79 }, +/* 0x6b7a */ { false, 0x6b7a, 0x6b7a }, +/* 0x6b7b */ { false, 0x6b7b, 0x6b7b }, +/* 0x6b7c */ { false, 0x6b7c, 0x6b7c }, +/* 0x6b7d */ { false, 0x6b7d, 0x6b7d }, +/* 0x6b7e */ { false, 0x6b7e, 0x6b7e }, +/* 0x6b7f */ { false, 0x6b7f, 0x6b7f }, +/* 0x6b80 */ { false, 0x6b80, 0x6b80 }, +/* 0x6b81 */ { false, 0x6b81, 0x6b81 }, +/* 0x6b82 */ { false, 0x6b82, 0x6b82 }, +/* 0x6b83 */ { false, 0x6b83, 0x6b83 }, +/* 0x6b84 */ { false, 0x6b84, 0x6b84 }, +/* 0x6b85 */ { false, 0x6b85, 0x6b85 }, +/* 0x6b86 */ { false, 0x6b86, 0x6b86 }, +/* 0x6b87 */ { false, 0x6b87, 0x6b87 }, +/* 0x6b88 */ { false, 0x6b88, 0x6b88 }, +/* 0x6b89 */ { false, 0x6b89, 0x6b89 }, +/* 0x6b8a */ { false, 0x6b8a, 0x6b8a }, +/* 0x6b8b */ { false, 0x6b8b, 0x6b8b }, +/* 0x6b8c */ { false, 0x6b8c, 0x6b8c }, +/* 0x6b8d */ { false, 0x6b8d, 0x6b8d }, +/* 0x6b8e */ { false, 0x6b8e, 0x6b8e }, +/* 0x6b8f */ { false, 0x6b8f, 0x6b8f }, +/* 0x6b90 */ { false, 0x6b90, 0x6b90 }, +/* 0x6b91 */ { false, 0x6b91, 0x6b91 }, +/* 0x6b92 */ { false, 0x6b92, 0x6b92 }, +/* 0x6b93 */ { false, 0x6b93, 0x6b93 }, +/* 0x6b94 */ { false, 0x6b94, 0x6b94 }, +/* 0x6b95 */ { false, 0x6b95, 0x6b95 }, +/* 0x6b96 */ { false, 0x6b96, 0x6b96 }, +/* 0x6b97 */ { false, 0x6b97, 0x6b97 }, +/* 0x6b98 */ { false, 0x6b98, 0x6b98 }, +/* 0x6b99 */ { false, 0x6b99, 0x6b99 }, +/* 0x6b9a */ { false, 0x6b9a, 0x6b9a }, +/* 0x6b9b */ { false, 0x6b9b, 0x6b9b }, +/* 0x6b9c */ { false, 0x6b9c, 0x6b9c }, +/* 0x6b9d */ { false, 0x6b9d, 0x6b9d }, +/* 0x6b9e */ { false, 0x6b9e, 0x6b9e }, +/* 0x6b9f */ { false, 0x6b9f, 0x6b9f }, +/* 0x6ba0 */ { false, 0x6ba0, 0x6ba0 }, +/* 0x6ba1 */ { false, 0x6ba1, 0x6ba1 }, +/* 0x6ba2 */ { false, 0x6ba2, 0x6ba2 }, +/* 0x6ba3 */ { false, 0x6ba3, 0x6ba3 }, +/* 0x6ba4 */ { false, 0x6ba4, 0x6ba4 }, +/* 0x6ba5 */ { false, 0x6ba5, 0x6ba5 }, +/* 0x6ba6 */ { false, 0x6ba6, 0x6ba6 }, +/* 0x6ba7 */ { false, 0x6ba7, 0x6ba7 }, +/* 0x6ba8 */ { false, 0x6ba8, 0x6ba8 }, +/* 0x6ba9 */ { false, 0x6ba9, 0x6ba9 }, +/* 0x6baa */ { false, 0x6baa, 0x6baa }, +/* 0x6bab */ { false, 0x6bab, 0x6bab }, +/* 0x6bac */ { false, 0x6bac, 0x6bac }, +/* 0x6bad */ { false, 0x6bad, 0x6bad }, +/* 0x6bae */ { false, 0x6bae, 0x6bae }, +/* 0x6baf */ { false, 0x6baf, 0x6baf }, +/* 0x6bb0 */ { false, 0x6bb0, 0x6bb0 }, +/* 0x6bb1 */ { false, 0x6bb1, 0x6bb1 }, +/* 0x6bb2 */ { false, 0x6bb2, 0x6bb2 }, +/* 0x6bb3 */ { false, 0x6bb3, 0x6bb3 }, +/* 0x6bb4 */ { false, 0x6bb4, 0x6bb4 }, +/* 0x6bb5 */ { false, 0x6bb5, 0x6bb5 }, +/* 0x6bb6 */ { false, 0x6bb6, 0x6bb6 }, +/* 0x6bb7 */ { false, 0x6bb7, 0x6bb7 }, +/* 0x6bb8 */ { false, 0x6bb8, 0x6bb8 }, +/* 0x6bb9 */ { false, 0x6bb9, 0x6bb9 }, +/* 0x6bba */ { false, 0x6bba, 0x6bba }, +/* 0x6bbb */ { false, 0x6bbb, 0x6bbb }, +/* 0x6bbc */ { false, 0x6bbc, 0x6bbc }, +/* 0x6bbd */ { false, 0x6bbd, 0x6bbd }, +/* 0x6bbe */ { false, 0x6bbe, 0x6bbe }, +/* 0x6bbf */ { false, 0x6bbf, 0x6bbf }, +/* 0x6bc0 */ { false, 0x6bc0, 0x6bc0 }, +/* 0x6bc1 */ { false, 0x6bc1, 0x6bc1 }, +/* 0x6bc2 */ { false, 0x6bc2, 0x6bc2 }, +/* 0x6bc3 */ { false, 0x6bc3, 0x6bc3 }, +/* 0x6bc4 */ { false, 0x6bc4, 0x6bc4 }, +/* 0x6bc5 */ { false, 0x6bc5, 0x6bc5 }, +/* 0x6bc6 */ { false, 0x6bc6, 0x6bc6 }, +/* 0x6bc7 */ { false, 0x6bc7, 0x6bc7 }, +/* 0x6bc8 */ { false, 0x6bc8, 0x6bc8 }, +/* 0x6bc9 */ { false, 0x6bc9, 0x6bc9 }, +/* 0x6bca */ { false, 0x6bca, 0x6bca }, +/* 0x6bcb */ { false, 0x6bcb, 0x6bcb }, +/* 0x6bcc */ { false, 0x6bcc, 0x6bcc }, +/* 0x6bcd */ { false, 0x6bcd, 0x6bcd }, +/* 0x6bce */ { false, 0x6bce, 0x6bce }, +/* 0x6bcf */ { false, 0x6bcf, 0x6bcf }, +/* 0x6bd0 */ { false, 0x6bd0, 0x6bd0 }, +/* 0x6bd1 */ { false, 0x6bd1, 0x6bd1 }, +/* 0x6bd2 */ { false, 0x6bd2, 0x6bd2 }, +/* 0x6bd3 */ { false, 0x6bd3, 0x6bd3 }, +/* 0x6bd4 */ { false, 0x6bd4, 0x6bd4 }, +/* 0x6bd5 */ { false, 0x6bd5, 0x6bd5 }, +/* 0x6bd6 */ { false, 0x6bd6, 0x6bd6 }, +/* 0x6bd7 */ { false, 0x6bd7, 0x6bd7 }, +/* 0x6bd8 */ { false, 0x6bd8, 0x6bd8 }, +/* 0x6bd9 */ { false, 0x6bd9, 0x6bd9 }, +/* 0x6bda */ { false, 0x6bda, 0x6bda }, +/* 0x6bdb */ { false, 0x6bdb, 0x6bdb }, +/* 0x6bdc */ { false, 0x6bdc, 0x6bdc }, +/* 0x6bdd */ { false, 0x6bdd, 0x6bdd }, +/* 0x6bde */ { false, 0x6bde, 0x6bde }, +/* 0x6bdf */ { false, 0x6bdf, 0x6bdf }, +/* 0x6be0 */ { false, 0x6be0, 0x6be0 }, +/* 0x6be1 */ { false, 0x6be1, 0x6be1 }, +/* 0x6be2 */ { false, 0x6be2, 0x6be2 }, +/* 0x6be3 */ { false, 0x6be3, 0x6be3 }, +/* 0x6be4 */ { false, 0x6be4, 0x6be4 }, +/* 0x6be5 */ { false, 0x6be5, 0x6be5 }, +/* 0x6be6 */ { false, 0x6be6, 0x6be6 }, +/* 0x6be7 */ { false, 0x6be7, 0x6be7 }, +/* 0x6be8 */ { false, 0x6be8, 0x6be8 }, +/* 0x6be9 */ { false, 0x6be9, 0x6be9 }, +/* 0x6bea */ { false, 0x6bea, 0x6bea }, +/* 0x6beb */ { false, 0x6beb, 0x6beb }, +/* 0x6bec */ { false, 0x6bec, 0x6bec }, +/* 0x6bed */ { false, 0x6bed, 0x6bed }, +/* 0x6bee */ { false, 0x6bee, 0x6bee }, +/* 0x6bef */ { false, 0x6bef, 0x6bef }, +/* 0x6bf0 */ { false, 0x6bf0, 0x6bf0 }, +/* 0x6bf1 */ { false, 0x6bf1, 0x6bf1 }, +/* 0x6bf2 */ { false, 0x6bf2, 0x6bf2 }, +/* 0x6bf3 */ { false, 0x6bf3, 0x6bf3 }, +/* 0x6bf4 */ { false, 0x6bf4, 0x6bf4 }, +/* 0x6bf5 */ { false, 0x6bf5, 0x6bf5 }, +/* 0x6bf6 */ { false, 0x6bf6, 0x6bf6 }, +/* 0x6bf7 */ { false, 0x6bf7, 0x6bf7 }, +/* 0x6bf8 */ { false, 0x6bf8, 0x6bf8 }, +/* 0x6bf9 */ { false, 0x6bf9, 0x6bf9 }, +/* 0x6bfa */ { false, 0x6bfa, 0x6bfa }, +/* 0x6bfb */ { false, 0x6bfb, 0x6bfb }, +/* 0x6bfc */ { false, 0x6bfc, 0x6bfc }, +/* 0x6bfd */ { false, 0x6bfd, 0x6bfd }, +/* 0x6bfe */ { false, 0x6bfe, 0x6bfe }, +/* 0x6bff */ { false, 0x6bff, 0x6bff }, +/* 0x6c00 */ { false, 0x6c00, 0x6c00 }, +/* 0x6c01 */ { false, 0x6c01, 0x6c01 }, +/* 0x6c02 */ { false, 0x6c02, 0x6c02 }, +/* 0x6c03 */ { false, 0x6c03, 0x6c03 }, +/* 0x6c04 */ { false, 0x6c04, 0x6c04 }, +/* 0x6c05 */ { false, 0x6c05, 0x6c05 }, +/* 0x6c06 */ { false, 0x6c06, 0x6c06 }, +/* 0x6c07 */ { false, 0x6c07, 0x6c07 }, +/* 0x6c08 */ { false, 0x6c08, 0x6c08 }, +/* 0x6c09 */ { false, 0x6c09, 0x6c09 }, +/* 0x6c0a */ { false, 0x6c0a, 0x6c0a }, +/* 0x6c0b */ { false, 0x6c0b, 0x6c0b }, +/* 0x6c0c */ { false, 0x6c0c, 0x6c0c }, +/* 0x6c0d */ { false, 0x6c0d, 0x6c0d }, +/* 0x6c0e */ { false, 0x6c0e, 0x6c0e }, +/* 0x6c0f */ { false, 0x6c0f, 0x6c0f }, +/* 0x6c10 */ { false, 0x6c10, 0x6c10 }, +/* 0x6c11 */ { false, 0x6c11, 0x6c11 }, +/* 0x6c12 */ { false, 0x6c12, 0x6c12 }, +/* 0x6c13 */ { false, 0x6c13, 0x6c13 }, +/* 0x6c14 */ { false, 0x6c14, 0x6c14 }, +/* 0x6c15 */ { false, 0x6c15, 0x6c15 }, +/* 0x6c16 */ { false, 0x6c16, 0x6c16 }, +/* 0x6c17 */ { false, 0x6c17, 0x6c17 }, +/* 0x6c18 */ { false, 0x6c18, 0x6c18 }, +/* 0x6c19 */ { false, 0x6c19, 0x6c19 }, +/* 0x6c1a */ { false, 0x6c1a, 0x6c1a }, +/* 0x6c1b */ { false, 0x6c1b, 0x6c1b }, +/* 0x6c1c */ { false, 0x6c1c, 0x6c1c }, +/* 0x6c1d */ { false, 0x6c1d, 0x6c1d }, +/* 0x6c1e */ { false, 0x6c1e, 0x6c1e }, +/* 0x6c1f */ { false, 0x6c1f, 0x6c1f }, +/* 0x6c20 */ { false, 0x6c20, 0x6c20 }, +/* 0x6c21 */ { false, 0x6c21, 0x6c21 }, +/* 0x6c22 */ { false, 0x6c22, 0x6c22 }, +/* 0x6c23 */ { false, 0x6c23, 0x6c23 }, +/* 0x6c24 */ { false, 0x6c24, 0x6c24 }, +/* 0x6c25 */ { false, 0x6c25, 0x6c25 }, +/* 0x6c26 */ { false, 0x6c26, 0x6c26 }, +/* 0x6c27 */ { false, 0x6c27, 0x6c27 }, +/* 0x6c28 */ { false, 0x6c28, 0x6c28 }, +/* 0x6c29 */ { false, 0x6c29, 0x6c29 }, +/* 0x6c2a */ { false, 0x6c2a, 0x6c2a }, +/* 0x6c2b */ { false, 0x6c2b, 0x6c2b }, +/* 0x6c2c */ { false, 0x6c2c, 0x6c2c }, +/* 0x6c2d */ { false, 0x6c2d, 0x6c2d }, +/* 0x6c2e */ { false, 0x6c2e, 0x6c2e }, +/* 0x6c2f */ { false, 0x6c2f, 0x6c2f }, +/* 0x6c30 */ { false, 0x6c30, 0x6c30 }, +/* 0x6c31 */ { false, 0x6c31, 0x6c31 }, +/* 0x6c32 */ { false, 0x6c32, 0x6c32 }, +/* 0x6c33 */ { false, 0x6c33, 0x6c33 }, +/* 0x6c34 */ { false, 0x6c34, 0x6c34 }, +/* 0x6c35 */ { false, 0x6c35, 0x6c35 }, +/* 0x6c36 */ { false, 0x6c36, 0x6c36 }, +/* 0x6c37 */ { false, 0x6c37, 0x6c37 }, +/* 0x6c38 */ { false, 0x6c38, 0x6c38 }, +/* 0x6c39 */ { false, 0x6c39, 0x6c39 }, +/* 0x6c3a */ { false, 0x6c3a, 0x6c3a }, +/* 0x6c3b */ { false, 0x6c3b, 0x6c3b }, +/* 0x6c3c */ { false, 0x6c3c, 0x6c3c }, +/* 0x6c3d */ { false, 0x6c3d, 0x6c3d }, +/* 0x6c3e */ { false, 0x6c3e, 0x6c3e }, +/* 0x6c3f */ { false, 0x6c3f, 0x6c3f }, +/* 0x6c40 */ { false, 0x6c40, 0x6c40 }, +/* 0x6c41 */ { false, 0x6c41, 0x6c41 }, +/* 0x6c42 */ { false, 0x6c42, 0x6c42 }, +/* 0x6c43 */ { false, 0x6c43, 0x6c43 }, +/* 0x6c44 */ { false, 0x6c44, 0x6c44 }, +/* 0x6c45 */ { false, 0x6c45, 0x6c45 }, +/* 0x6c46 */ { false, 0x6c46, 0x6c46 }, +/* 0x6c47 */ { false, 0x6c47, 0x6c47 }, +/* 0x6c48 */ { false, 0x6c48, 0x6c48 }, +/* 0x6c49 */ { false, 0x6c49, 0x6c49 }, +/* 0x6c4a */ { false, 0x6c4a, 0x6c4a }, +/* 0x6c4b */ { false, 0x6c4b, 0x6c4b }, +/* 0x6c4c */ { false, 0x6c4c, 0x6c4c }, +/* 0x6c4d */ { false, 0x6c4d, 0x6c4d }, +/* 0x6c4e */ { false, 0x6c4e, 0x6c4e }, +/* 0x6c4f */ { false, 0x6c4f, 0x6c4f }, +/* 0x6c50 */ { false, 0x6c50, 0x6c50 }, +/* 0x6c51 */ { false, 0x6c51, 0x6c51 }, +/* 0x6c52 */ { false, 0x6c52, 0x6c52 }, +/* 0x6c53 */ { false, 0x6c53, 0x6c53 }, +/* 0x6c54 */ { false, 0x6c54, 0x6c54 }, +/* 0x6c55 */ { false, 0x6c55, 0x6c55 }, +/* 0x6c56 */ { false, 0x6c56, 0x6c56 }, +/* 0x6c57 */ { false, 0x6c57, 0x6c57 }, +/* 0x6c58 */ { false, 0x6c58, 0x6c58 }, +/* 0x6c59 */ { false, 0x6c59, 0x6c59 }, +/* 0x6c5a */ { false, 0x6c5a, 0x6c5a }, +/* 0x6c5b */ { false, 0x6c5b, 0x6c5b }, +/* 0x6c5c */ { false, 0x6c5c, 0x6c5c }, +/* 0x6c5d */ { false, 0x6c5d, 0x6c5d }, +/* 0x6c5e */ { false, 0x6c5e, 0x6c5e }, +/* 0x6c5f */ { false, 0x6c5f, 0x6c5f }, +/* 0x6c60 */ { false, 0x6c60, 0x6c60 }, +/* 0x6c61 */ { false, 0x6c61, 0x6c61 }, +/* 0x6c62 */ { false, 0x6c62, 0x6c62 }, +/* 0x6c63 */ { false, 0x6c63, 0x6c63 }, +/* 0x6c64 */ { false, 0x6c64, 0x6c64 }, +/* 0x6c65 */ { false, 0x6c65, 0x6c65 }, +/* 0x6c66 */ { false, 0x6c66, 0x6c66 }, +/* 0x6c67 */ { false, 0x6c67, 0x6c67 }, +/* 0x6c68 */ { false, 0x6c68, 0x6c68 }, +/* 0x6c69 */ { false, 0x6c69, 0x6c69 }, +/* 0x6c6a */ { false, 0x6c6a, 0x6c6a }, +/* 0x6c6b */ { false, 0x6c6b, 0x6c6b }, +/* 0x6c6c */ { false, 0x6c6c, 0x6c6c }, +/* 0x6c6d */ { false, 0x6c6d, 0x6c6d }, +/* 0x6c6e */ { false, 0x6c6e, 0x6c6e }, +/* 0x6c6f */ { false, 0x6c6f, 0x6c6f }, +/* 0x6c70 */ { false, 0x6c70, 0x6c70 }, +/* 0x6c71 */ { false, 0x6c71, 0x6c71 }, +/* 0x6c72 */ { false, 0x6c72, 0x6c72 }, +/* 0x6c73 */ { false, 0x6c73, 0x6c73 }, +/* 0x6c74 */ { false, 0x6c74, 0x6c74 }, +/* 0x6c75 */ { false, 0x6c75, 0x6c75 }, +/* 0x6c76 */ { false, 0x6c76, 0x6c76 }, +/* 0x6c77 */ { false, 0x6c77, 0x6c77 }, +/* 0x6c78 */ { false, 0x6c78, 0x6c78 }, +/* 0x6c79 */ { false, 0x6c79, 0x6c79 }, +/* 0x6c7a */ { false, 0x6c7a, 0x6c7a }, +/* 0x6c7b */ { false, 0x6c7b, 0x6c7b }, +/* 0x6c7c */ { false, 0x6c7c, 0x6c7c }, +/* 0x6c7d */ { false, 0x6c7d, 0x6c7d }, +/* 0x6c7e */ { false, 0x6c7e, 0x6c7e }, +/* 0x6c7f */ { false, 0x6c7f, 0x6c7f }, +/* 0x6c80 */ { false, 0x6c80, 0x6c80 }, +/* 0x6c81 */ { false, 0x6c81, 0x6c81 }, +/* 0x6c82 */ { false, 0x6c82, 0x6c82 }, +/* 0x6c83 */ { false, 0x6c83, 0x6c83 }, +/* 0x6c84 */ { false, 0x6c84, 0x6c84 }, +/* 0x6c85 */ { false, 0x6c85, 0x6c85 }, +/* 0x6c86 */ { false, 0x6c86, 0x6c86 }, +/* 0x6c87 */ { false, 0x6c87, 0x6c87 }, +/* 0x6c88 */ { false, 0x6c88, 0x6c88 }, +/* 0x6c89 */ { false, 0x6c89, 0x6c89 }, +/* 0x6c8a */ { false, 0x6c8a, 0x6c8a }, +/* 0x6c8b */ { false, 0x6c8b, 0x6c8b }, +/* 0x6c8c */ { false, 0x6c8c, 0x6c8c }, +/* 0x6c8d */ { false, 0x6c8d, 0x6c8d }, +/* 0x6c8e */ { false, 0x6c8e, 0x6c8e }, +/* 0x6c8f */ { false, 0x6c8f, 0x6c8f }, +/* 0x6c90 */ { false, 0x6c90, 0x6c90 }, +/* 0x6c91 */ { false, 0x6c91, 0x6c91 }, +/* 0x6c92 */ { false, 0x6c92, 0x6c92 }, +/* 0x6c93 */ { false, 0x6c93, 0x6c93 }, +/* 0x6c94 */ { false, 0x6c94, 0x6c94 }, +/* 0x6c95 */ { false, 0x6c95, 0x6c95 }, +/* 0x6c96 */ { false, 0x6c96, 0x6c96 }, +/* 0x6c97 */ { false, 0x6c97, 0x6c97 }, +/* 0x6c98 */ { false, 0x6c98, 0x6c98 }, +/* 0x6c99 */ { false, 0x6c99, 0x6c99 }, +/* 0x6c9a */ { false, 0x6c9a, 0x6c9a }, +/* 0x6c9b */ { false, 0x6c9b, 0x6c9b }, +/* 0x6c9c */ { false, 0x6c9c, 0x6c9c }, +/* 0x6c9d */ { false, 0x6c9d, 0x6c9d }, +/* 0x6c9e */ { false, 0x6c9e, 0x6c9e }, +/* 0x6c9f */ { false, 0x6c9f, 0x6c9f }, +/* 0x6ca0 */ { false, 0x6ca0, 0x6ca0 }, +/* 0x6ca1 */ { false, 0x6ca1, 0x6ca1 }, +/* 0x6ca2 */ { false, 0x6ca2, 0x6ca2 }, +/* 0x6ca3 */ { false, 0x6ca3, 0x6ca3 }, +/* 0x6ca4 */ { false, 0x6ca4, 0x6ca4 }, +/* 0x6ca5 */ { false, 0x6ca5, 0x6ca5 }, +/* 0x6ca6 */ { false, 0x6ca6, 0x6ca6 }, +/* 0x6ca7 */ { false, 0x6ca7, 0x6ca7 }, +/* 0x6ca8 */ { false, 0x6ca8, 0x6ca8 }, +/* 0x6ca9 */ { false, 0x6ca9, 0x6ca9 }, +/* 0x6caa */ { false, 0x6caa, 0x6caa }, +/* 0x6cab */ { false, 0x6cab, 0x6cab }, +/* 0x6cac */ { false, 0x6cac, 0x6cac }, +/* 0x6cad */ { false, 0x6cad, 0x6cad }, +/* 0x6cae */ { false, 0x6cae, 0x6cae }, +/* 0x6caf */ { false, 0x6caf, 0x6caf }, +/* 0x6cb0 */ { false, 0x6cb0, 0x6cb0 }, +/* 0x6cb1 */ { false, 0x6cb1, 0x6cb1 }, +/* 0x6cb2 */ { false, 0x6cb2, 0x6cb2 }, +/* 0x6cb3 */ { false, 0x6cb3, 0x6cb3 }, +/* 0x6cb4 */ { false, 0x6cb4, 0x6cb4 }, +/* 0x6cb5 */ { false, 0x6cb5, 0x6cb5 }, +/* 0x6cb6 */ { false, 0x6cb6, 0x6cb6 }, +/* 0x6cb7 */ { false, 0x6cb7, 0x6cb7 }, +/* 0x6cb8 */ { false, 0x6cb8, 0x6cb8 }, +/* 0x6cb9 */ { false, 0x6cb9, 0x6cb9 }, +/* 0x6cba */ { false, 0x6cba, 0x6cba }, +/* 0x6cbb */ { false, 0x6cbb, 0x6cbb }, +/* 0x6cbc */ { false, 0x6cbc, 0x6cbc }, +/* 0x6cbd */ { false, 0x6cbd, 0x6cbd }, +/* 0x6cbe */ { false, 0x6cbe, 0x6cbe }, +/* 0x6cbf */ { false, 0x6cbf, 0x6cbf }, +/* 0x6cc0 */ { false, 0x6cc0, 0x6cc0 }, +/* 0x6cc1 */ { false, 0x6cc1, 0x6cc1 }, +/* 0x6cc2 */ { false, 0x6cc2, 0x6cc2 }, +/* 0x6cc3 */ { false, 0x6cc3, 0x6cc3 }, +/* 0x6cc4 */ { false, 0x6cc4, 0x6cc4 }, +/* 0x6cc5 */ { false, 0x6cc5, 0x6cc5 }, +/* 0x6cc6 */ { false, 0x6cc6, 0x6cc6 }, +/* 0x6cc7 */ { false, 0x6cc7, 0x6cc7 }, +/* 0x6cc8 */ { false, 0x6cc8, 0x6cc8 }, +/* 0x6cc9 */ { false, 0x6cc9, 0x6cc9 }, +/* 0x6cca */ { false, 0x6cca, 0x6cca }, +/* 0x6ccb */ { false, 0x6ccb, 0x6ccb }, +/* 0x6ccc */ { false, 0x6ccc, 0x6ccc }, +/* 0x6ccd */ { false, 0x6ccd, 0x6ccd }, +/* 0x6cce */ { false, 0x6cce, 0x6cce }, +/* 0x6ccf */ { false, 0x6ccf, 0x6ccf }, +/* 0x6cd0 */ { false, 0x6cd0, 0x6cd0 }, +/* 0x6cd1 */ { false, 0x6cd1, 0x6cd1 }, +/* 0x6cd2 */ { false, 0x6cd2, 0x6cd2 }, +/* 0x6cd3 */ { false, 0x6cd3, 0x6cd3 }, +/* 0x6cd4 */ { false, 0x6cd4, 0x6cd4 }, +/* 0x6cd5 */ { false, 0x6cd5, 0x6cd5 }, +/* 0x6cd6 */ { false, 0x6cd6, 0x6cd6 }, +/* 0x6cd7 */ { false, 0x6cd7, 0x6cd7 }, +/* 0x6cd8 */ { false, 0x6cd8, 0x6cd8 }, +/* 0x6cd9 */ { false, 0x6cd9, 0x6cd9 }, +/* 0x6cda */ { false, 0x6cda, 0x6cda }, +/* 0x6cdb */ { false, 0x6cdb, 0x6cdb }, +/* 0x6cdc */ { false, 0x6cdc, 0x6cdc }, +/* 0x6cdd */ { false, 0x6cdd, 0x6cdd }, +/* 0x6cde */ { false, 0x6cde, 0x6cde }, +/* 0x6cdf */ { false, 0x6cdf, 0x6cdf }, +/* 0x6ce0 */ { false, 0x6ce0, 0x6ce0 }, +/* 0x6ce1 */ { false, 0x6ce1, 0x6ce1 }, +/* 0x6ce2 */ { false, 0x6ce2, 0x6ce2 }, +/* 0x6ce3 */ { false, 0x6ce3, 0x6ce3 }, +/* 0x6ce4 */ { false, 0x6ce4, 0x6ce4 }, +/* 0x6ce5 */ { false, 0x6ce5, 0x6ce5 }, +/* 0x6ce6 */ { false, 0x6ce6, 0x6ce6 }, +/* 0x6ce7 */ { false, 0x6ce7, 0x6ce7 }, +/* 0x6ce8 */ { false, 0x6ce8, 0x6ce8 }, +/* 0x6ce9 */ { false, 0x6ce9, 0x6ce9 }, +/* 0x6cea */ { false, 0x6cea, 0x6cea }, +/* 0x6ceb */ { false, 0x6ceb, 0x6ceb }, +/* 0x6cec */ { false, 0x6cec, 0x6cec }, +/* 0x6ced */ { false, 0x6ced, 0x6ced }, +/* 0x6cee */ { false, 0x6cee, 0x6cee }, +/* 0x6cef */ { false, 0x6cef, 0x6cef }, +/* 0x6cf0 */ { false, 0x6cf0, 0x6cf0 }, +/* 0x6cf1 */ { false, 0x6cf1, 0x6cf1 }, +/* 0x6cf2 */ { false, 0x6cf2, 0x6cf2 }, +/* 0x6cf3 */ { false, 0x6cf3, 0x6cf3 }, +/* 0x6cf4 */ { false, 0x6cf4, 0x6cf4 }, +/* 0x6cf5 */ { false, 0x6cf5, 0x6cf5 }, +/* 0x6cf6 */ { false, 0x6cf6, 0x6cf6 }, +/* 0x6cf7 */ { false, 0x6cf7, 0x6cf7 }, +/* 0x6cf8 */ { false, 0x6cf8, 0x6cf8 }, +/* 0x6cf9 */ { false, 0x6cf9, 0x6cf9 }, +/* 0x6cfa */ { false, 0x6cfa, 0x6cfa }, +/* 0x6cfb */ { false, 0x6cfb, 0x6cfb }, +/* 0x6cfc */ { false, 0x6cfc, 0x6cfc }, +/* 0x6cfd */ { false, 0x6cfd, 0x6cfd }, +/* 0x6cfe */ { false, 0x6cfe, 0x6cfe }, +/* 0x6cff */ { false, 0x6cff, 0x6cff }, +/* 0x6d00 */ { false, 0x6d00, 0x6d00 }, +/* 0x6d01 */ { false, 0x6d01, 0x6d01 }, +/* 0x6d02 */ { false, 0x6d02, 0x6d02 }, +/* 0x6d03 */ { false, 0x6d03, 0x6d03 }, +/* 0x6d04 */ { false, 0x6d04, 0x6d04 }, +/* 0x6d05 */ { false, 0x6d05, 0x6d05 }, +/* 0x6d06 */ { false, 0x6d06, 0x6d06 }, +/* 0x6d07 */ { false, 0x6d07, 0x6d07 }, +/* 0x6d08 */ { false, 0x6d08, 0x6d08 }, +/* 0x6d09 */ { false, 0x6d09, 0x6d09 }, +/* 0x6d0a */ { false, 0x6d0a, 0x6d0a }, +/* 0x6d0b */ { false, 0x6d0b, 0x6d0b }, +/* 0x6d0c */ { false, 0x6d0c, 0x6d0c }, +/* 0x6d0d */ { false, 0x6d0d, 0x6d0d }, +/* 0x6d0e */ { false, 0x6d0e, 0x6d0e }, +/* 0x6d0f */ { false, 0x6d0f, 0x6d0f }, +/* 0x6d10 */ { false, 0x6d10, 0x6d10 }, +/* 0x6d11 */ { false, 0x6d11, 0x6d11 }, +/* 0x6d12 */ { false, 0x6d12, 0x6d12 }, +/* 0x6d13 */ { false, 0x6d13, 0x6d13 }, +/* 0x6d14 */ { false, 0x6d14, 0x6d14 }, +/* 0x6d15 */ { false, 0x6d15, 0x6d15 }, +/* 0x6d16 */ { false, 0x6d16, 0x6d16 }, +/* 0x6d17 */ { false, 0x6d17, 0x6d17 }, +/* 0x6d18 */ { false, 0x6d18, 0x6d18 }, +/* 0x6d19 */ { false, 0x6d19, 0x6d19 }, +/* 0x6d1a */ { false, 0x6d1a, 0x6d1a }, +/* 0x6d1b */ { false, 0x6d1b, 0x6d1b }, +/* 0x6d1c */ { false, 0x6d1c, 0x6d1c }, +/* 0x6d1d */ { false, 0x6d1d, 0x6d1d }, +/* 0x6d1e */ { false, 0x6d1e, 0x6d1e }, +/* 0x6d1f */ { false, 0x6d1f, 0x6d1f }, +/* 0x6d20 */ { false, 0x6d20, 0x6d20 }, +/* 0x6d21 */ { false, 0x6d21, 0x6d21 }, +/* 0x6d22 */ { false, 0x6d22, 0x6d22 }, +/* 0x6d23 */ { false, 0x6d23, 0x6d23 }, +/* 0x6d24 */ { false, 0x6d24, 0x6d24 }, +/* 0x6d25 */ { false, 0x6d25, 0x6d25 }, +/* 0x6d26 */ { false, 0x6d26, 0x6d26 }, +/* 0x6d27 */ { false, 0x6d27, 0x6d27 }, +/* 0x6d28 */ { false, 0x6d28, 0x6d28 }, +/* 0x6d29 */ { false, 0x6d29, 0x6d29 }, +/* 0x6d2a */ { false, 0x6d2a, 0x6d2a }, +/* 0x6d2b */ { false, 0x6d2b, 0x6d2b }, +/* 0x6d2c */ { false, 0x6d2c, 0x6d2c }, +/* 0x6d2d */ { false, 0x6d2d, 0x6d2d }, +/* 0x6d2e */ { false, 0x6d2e, 0x6d2e }, +/* 0x6d2f */ { false, 0x6d2f, 0x6d2f }, +/* 0x6d30 */ { false, 0x6d30, 0x6d30 }, +/* 0x6d31 */ { false, 0x6d31, 0x6d31 }, +/* 0x6d32 */ { false, 0x6d32, 0x6d32 }, +/* 0x6d33 */ { false, 0x6d33, 0x6d33 }, +/* 0x6d34 */ { false, 0x6d34, 0x6d34 }, +/* 0x6d35 */ { false, 0x6d35, 0x6d35 }, +/* 0x6d36 */ { false, 0x6d36, 0x6d36 }, +/* 0x6d37 */ { false, 0x6d37, 0x6d37 }, +/* 0x6d38 */ { false, 0x6d38, 0x6d38 }, +/* 0x6d39 */ { false, 0x6d39, 0x6d39 }, +/* 0x6d3a */ { false, 0x6d3a, 0x6d3a }, +/* 0x6d3b */ { false, 0x6d3b, 0x6d3b }, +/* 0x6d3c */ { false, 0x6d3c, 0x6d3c }, +/* 0x6d3d */ { false, 0x6d3d, 0x6d3d }, +/* 0x6d3e */ { false, 0x6d3e, 0x6d3e }, +/* 0x6d3f */ { false, 0x6d3f, 0x6d3f }, +/* 0x6d40 */ { false, 0x6d40, 0x6d40 }, +/* 0x6d41 */ { false, 0x6d41, 0x6d41 }, +/* 0x6d42 */ { false, 0x6d42, 0x6d42 }, +/* 0x6d43 */ { false, 0x6d43, 0x6d43 }, +/* 0x6d44 */ { false, 0x6d44, 0x6d44 }, +/* 0x6d45 */ { false, 0x6d45, 0x6d45 }, +/* 0x6d46 */ { false, 0x6d46, 0x6d46 }, +/* 0x6d47 */ { false, 0x6d47, 0x6d47 }, +/* 0x6d48 */ { false, 0x6d48, 0x6d48 }, +/* 0x6d49 */ { false, 0x6d49, 0x6d49 }, +/* 0x6d4a */ { false, 0x6d4a, 0x6d4a }, +/* 0x6d4b */ { false, 0x6d4b, 0x6d4b }, +/* 0x6d4c */ { false, 0x6d4c, 0x6d4c }, +/* 0x6d4d */ { false, 0x6d4d, 0x6d4d }, +/* 0x6d4e */ { false, 0x6d4e, 0x6d4e }, +/* 0x6d4f */ { false, 0x6d4f, 0x6d4f }, +/* 0x6d50 */ { false, 0x6d50, 0x6d50 }, +/* 0x6d51 */ { false, 0x6d51, 0x6d51 }, +/* 0x6d52 */ { false, 0x6d52, 0x6d52 }, +/* 0x6d53 */ { false, 0x6d53, 0x6d53 }, +/* 0x6d54 */ { false, 0x6d54, 0x6d54 }, +/* 0x6d55 */ { false, 0x6d55, 0x6d55 }, +/* 0x6d56 */ { false, 0x6d56, 0x6d56 }, +/* 0x6d57 */ { false, 0x6d57, 0x6d57 }, +/* 0x6d58 */ { false, 0x6d58, 0x6d58 }, +/* 0x6d59 */ { false, 0x6d59, 0x6d59 }, +/* 0x6d5a */ { false, 0x6d5a, 0x6d5a }, +/* 0x6d5b */ { false, 0x6d5b, 0x6d5b }, +/* 0x6d5c */ { false, 0x6d5c, 0x6d5c }, +/* 0x6d5d */ { false, 0x6d5d, 0x6d5d }, +/* 0x6d5e */ { false, 0x6d5e, 0x6d5e }, +/* 0x6d5f */ { false, 0x6d5f, 0x6d5f }, +/* 0x6d60 */ { false, 0x6d60, 0x6d60 }, +/* 0x6d61 */ { false, 0x6d61, 0x6d61 }, +/* 0x6d62 */ { false, 0x6d62, 0x6d62 }, +/* 0x6d63 */ { false, 0x6d63, 0x6d63 }, +/* 0x6d64 */ { false, 0x6d64, 0x6d64 }, +/* 0x6d65 */ { false, 0x6d65, 0x6d65 }, +/* 0x6d66 */ { false, 0x6d66, 0x6d66 }, +/* 0x6d67 */ { false, 0x6d67, 0x6d67 }, +/* 0x6d68 */ { false, 0x6d68, 0x6d68 }, +/* 0x6d69 */ { false, 0x6d69, 0x6d69 }, +/* 0x6d6a */ { false, 0x6d6a, 0x6d6a }, +/* 0x6d6b */ { false, 0x6d6b, 0x6d6b }, +/* 0x6d6c */ { false, 0x6d6c, 0x6d6c }, +/* 0x6d6d */ { false, 0x6d6d, 0x6d6d }, +/* 0x6d6e */ { false, 0x6d6e, 0x6d6e }, +/* 0x6d6f */ { false, 0x6d6f, 0x6d6f }, +/* 0x6d70 */ { false, 0x6d70, 0x6d70 }, +/* 0x6d71 */ { false, 0x6d71, 0x6d71 }, +/* 0x6d72 */ { false, 0x6d72, 0x6d72 }, +/* 0x6d73 */ { false, 0x6d73, 0x6d73 }, +/* 0x6d74 */ { false, 0x6d74, 0x6d74 }, +/* 0x6d75 */ { false, 0x6d75, 0x6d75 }, +/* 0x6d76 */ { false, 0x6d76, 0x6d76 }, +/* 0x6d77 */ { false, 0x6d77, 0x6d77 }, +/* 0x6d78 */ { false, 0x6d78, 0x6d78 }, +/* 0x6d79 */ { false, 0x6d79, 0x6d79 }, +/* 0x6d7a */ { false, 0x6d7a, 0x6d7a }, +/* 0x6d7b */ { false, 0x6d7b, 0x6d7b }, +/* 0x6d7c */ { false, 0x6d7c, 0x6d7c }, +/* 0x6d7d */ { false, 0x6d7d, 0x6d7d }, +/* 0x6d7e */ { false, 0x6d7e, 0x6d7e }, +/* 0x6d7f */ { false, 0x6d7f, 0x6d7f }, +/* 0x6d80 */ { false, 0x6d80, 0x6d80 }, +/* 0x6d81 */ { false, 0x6d81, 0x6d81 }, +/* 0x6d82 */ { false, 0x6d82, 0x6d82 }, +/* 0x6d83 */ { false, 0x6d83, 0x6d83 }, +/* 0x6d84 */ { false, 0x6d84, 0x6d84 }, +/* 0x6d85 */ { false, 0x6d85, 0x6d85 }, +/* 0x6d86 */ { false, 0x6d86, 0x6d86 }, +/* 0x6d87 */ { false, 0x6d87, 0x6d87 }, +/* 0x6d88 */ { false, 0x6d88, 0x6d88 }, +/* 0x6d89 */ { false, 0x6d89, 0x6d89 }, +/* 0x6d8a */ { false, 0x6d8a, 0x6d8a }, +/* 0x6d8b */ { false, 0x6d8b, 0x6d8b }, +/* 0x6d8c */ { false, 0x6d8c, 0x6d8c }, +/* 0x6d8d */ { false, 0x6d8d, 0x6d8d }, +/* 0x6d8e */ { false, 0x6d8e, 0x6d8e }, +/* 0x6d8f */ { false, 0x6d8f, 0x6d8f }, +/* 0x6d90 */ { false, 0x6d90, 0x6d90 }, +/* 0x6d91 */ { false, 0x6d91, 0x6d91 }, +/* 0x6d92 */ { false, 0x6d92, 0x6d92 }, +/* 0x6d93 */ { false, 0x6d93, 0x6d93 }, +/* 0x6d94 */ { false, 0x6d94, 0x6d94 }, +/* 0x6d95 */ { false, 0x6d95, 0x6d95 }, +/* 0x6d96 */ { false, 0x6d96, 0x6d96 }, +/* 0x6d97 */ { false, 0x6d97, 0x6d97 }, +/* 0x6d98 */ { false, 0x6d98, 0x6d98 }, +/* 0x6d99 */ { false, 0x6d99, 0x6d99 }, +/* 0x6d9a */ { false, 0x6d9a, 0x6d9a }, +/* 0x6d9b */ { false, 0x6d9b, 0x6d9b }, +/* 0x6d9c */ { false, 0x6d9c, 0x6d9c }, +/* 0x6d9d */ { false, 0x6d9d, 0x6d9d }, +/* 0x6d9e */ { false, 0x6d9e, 0x6d9e }, +/* 0x6d9f */ { false, 0x6d9f, 0x6d9f }, +/* 0x6da0 */ { false, 0x6da0, 0x6da0 }, +/* 0x6da1 */ { false, 0x6da1, 0x6da1 }, +/* 0x6da2 */ { false, 0x6da2, 0x6da2 }, +/* 0x6da3 */ { false, 0x6da3, 0x6da3 }, +/* 0x6da4 */ { false, 0x6da4, 0x6da4 }, +/* 0x6da5 */ { false, 0x6da5, 0x6da5 }, +/* 0x6da6 */ { false, 0x6da6, 0x6da6 }, +/* 0x6da7 */ { false, 0x6da7, 0x6da7 }, +/* 0x6da8 */ { false, 0x6da8, 0x6da8 }, +/* 0x6da9 */ { false, 0x6da9, 0x6da9 }, +/* 0x6daa */ { false, 0x6daa, 0x6daa }, +/* 0x6dab */ { false, 0x6dab, 0x6dab }, +/* 0x6dac */ { false, 0x6dac, 0x6dac }, +/* 0x6dad */ { false, 0x6dad, 0x6dad }, +/* 0x6dae */ { false, 0x6dae, 0x6dae }, +/* 0x6daf */ { false, 0x6daf, 0x6daf }, +/* 0x6db0 */ { false, 0x6db0, 0x6db0 }, +/* 0x6db1 */ { false, 0x6db1, 0x6db1 }, +/* 0x6db2 */ { false, 0x6db2, 0x6db2 }, +/* 0x6db3 */ { false, 0x6db3, 0x6db3 }, +/* 0x6db4 */ { false, 0x6db4, 0x6db4 }, +/* 0x6db5 */ { false, 0x6db5, 0x6db5 }, +/* 0x6db6 */ { false, 0x6db6, 0x6db6 }, +/* 0x6db7 */ { false, 0x6db7, 0x6db7 }, +/* 0x6db8 */ { false, 0x6db8, 0x6db8 }, +/* 0x6db9 */ { false, 0x6db9, 0x6db9 }, +/* 0x6dba */ { false, 0x6dba, 0x6dba }, +/* 0x6dbb */ { false, 0x6dbb, 0x6dbb }, +/* 0x6dbc */ { false, 0x6dbc, 0x6dbc }, +/* 0x6dbd */ { false, 0x6dbd, 0x6dbd }, +/* 0x6dbe */ { false, 0x6dbe, 0x6dbe }, +/* 0x6dbf */ { false, 0x6dbf, 0x6dbf }, +/* 0x6dc0 */ { false, 0x6dc0, 0x6dc0 }, +/* 0x6dc1 */ { false, 0x6dc1, 0x6dc1 }, +/* 0x6dc2 */ { false, 0x6dc2, 0x6dc2 }, +/* 0x6dc3 */ { false, 0x6dc3, 0x6dc3 }, +/* 0x6dc4 */ { false, 0x6dc4, 0x6dc4 }, +/* 0x6dc5 */ { false, 0x6dc5, 0x6dc5 }, +/* 0x6dc6 */ { false, 0x6dc6, 0x6dc6 }, +/* 0x6dc7 */ { false, 0x6dc7, 0x6dc7 }, +/* 0x6dc8 */ { false, 0x6dc8, 0x6dc8 }, +/* 0x6dc9 */ { false, 0x6dc9, 0x6dc9 }, +/* 0x6dca */ { false, 0x6dca, 0x6dca }, +/* 0x6dcb */ { false, 0x6dcb, 0x6dcb }, +/* 0x6dcc */ { false, 0x6dcc, 0x6dcc }, +/* 0x6dcd */ { false, 0x6dcd, 0x6dcd }, +/* 0x6dce */ { false, 0x6dce, 0x6dce }, +/* 0x6dcf */ { false, 0x6dcf, 0x6dcf }, +/* 0x6dd0 */ { false, 0x6dd0, 0x6dd0 }, +/* 0x6dd1 */ { false, 0x6dd1, 0x6dd1 }, +/* 0x6dd2 */ { false, 0x6dd2, 0x6dd2 }, +/* 0x6dd3 */ { false, 0x6dd3, 0x6dd3 }, +/* 0x6dd4 */ { false, 0x6dd4, 0x6dd4 }, +/* 0x6dd5 */ { false, 0x6dd5, 0x6dd5 }, +/* 0x6dd6 */ { false, 0x6dd6, 0x6dd6 }, +/* 0x6dd7 */ { false, 0x6dd7, 0x6dd7 }, +/* 0x6dd8 */ { false, 0x6dd8, 0x6dd8 }, +/* 0x6dd9 */ { false, 0x6dd9, 0x6dd9 }, +/* 0x6dda */ { false, 0x6dda, 0x6dda }, +/* 0x6ddb */ { false, 0x6ddb, 0x6ddb }, +/* 0x6ddc */ { false, 0x6ddc, 0x6ddc }, +/* 0x6ddd */ { false, 0x6ddd, 0x6ddd }, +/* 0x6dde */ { false, 0x6dde, 0x6dde }, +/* 0x6ddf */ { false, 0x6ddf, 0x6ddf }, +/* 0x6de0 */ { false, 0x6de0, 0x6de0 }, +/* 0x6de1 */ { false, 0x6de1, 0x6de1 }, +/* 0x6de2 */ { false, 0x6de2, 0x6de2 }, +/* 0x6de3 */ { false, 0x6de3, 0x6de3 }, +/* 0x6de4 */ { false, 0x6de4, 0x6de4 }, +/* 0x6de5 */ { false, 0x6de5, 0x6de5 }, +/* 0x6de6 */ { false, 0x6de6, 0x6de6 }, +/* 0x6de7 */ { false, 0x6de7, 0x6de7 }, +/* 0x6de8 */ { false, 0x6de8, 0x6de8 }, +/* 0x6de9 */ { false, 0x6de9, 0x6de9 }, +/* 0x6dea */ { false, 0x6dea, 0x6dea }, +/* 0x6deb */ { false, 0x6deb, 0x6deb }, +/* 0x6dec */ { false, 0x6dec, 0x6dec }, +/* 0x6ded */ { false, 0x6ded, 0x6ded }, +/* 0x6dee */ { false, 0x6dee, 0x6dee }, +/* 0x6def */ { false, 0x6def, 0x6def }, +/* 0x6df0 */ { false, 0x6df0, 0x6df0 }, +/* 0x6df1 */ { false, 0x6df1, 0x6df1 }, +/* 0x6df2 */ { false, 0x6df2, 0x6df2 }, +/* 0x6df3 */ { false, 0x6df3, 0x6df3 }, +/* 0x6df4 */ { false, 0x6df4, 0x6df4 }, +/* 0x6df5 */ { false, 0x6df5, 0x6df5 }, +/* 0x6df6 */ { false, 0x6df6, 0x6df6 }, +/* 0x6df7 */ { false, 0x6df7, 0x6df7 }, +/* 0x6df8 */ { false, 0x6df8, 0x6df8 }, +/* 0x6df9 */ { false, 0x6df9, 0x6df9 }, +/* 0x6dfa */ { false, 0x6dfa, 0x6dfa }, +/* 0x6dfb */ { false, 0x6dfb, 0x6dfb }, +/* 0x6dfc */ { false, 0x6dfc, 0x6dfc }, +/* 0x6dfd */ { false, 0x6dfd, 0x6dfd }, +/* 0x6dfe */ { false, 0x6dfe, 0x6dfe }, +/* 0x6dff */ { false, 0x6dff, 0x6dff }, +/* 0x6e00 */ { false, 0x6e00, 0x6e00 }, +/* 0x6e01 */ { false, 0x6e01, 0x6e01 }, +/* 0x6e02 */ { false, 0x6e02, 0x6e02 }, +/* 0x6e03 */ { false, 0x6e03, 0x6e03 }, +/* 0x6e04 */ { false, 0x6e04, 0x6e04 }, +/* 0x6e05 */ { false, 0x6e05, 0x6e05 }, +/* 0x6e06 */ { false, 0x6e06, 0x6e06 }, +/* 0x6e07 */ { false, 0x6e07, 0x6e07 }, +/* 0x6e08 */ { false, 0x6e08, 0x6e08 }, +/* 0x6e09 */ { false, 0x6e09, 0x6e09 }, +/* 0x6e0a */ { false, 0x6e0a, 0x6e0a }, +/* 0x6e0b */ { false, 0x6e0b, 0x6e0b }, +/* 0x6e0c */ { false, 0x6e0c, 0x6e0c }, +/* 0x6e0d */ { false, 0x6e0d, 0x6e0d }, +/* 0x6e0e */ { false, 0x6e0e, 0x6e0e }, +/* 0x6e0f */ { false, 0x6e0f, 0x6e0f }, +/* 0x6e10 */ { false, 0x6e10, 0x6e10 }, +/* 0x6e11 */ { false, 0x6e11, 0x6e11 }, +/* 0x6e12 */ { false, 0x6e12, 0x6e12 }, +/* 0x6e13 */ { false, 0x6e13, 0x6e13 }, +/* 0x6e14 */ { false, 0x6e14, 0x6e14 }, +/* 0x6e15 */ { false, 0x6e15, 0x6e15 }, +/* 0x6e16 */ { false, 0x6e16, 0x6e16 }, +/* 0x6e17 */ { false, 0x6e17, 0x6e17 }, +/* 0x6e18 */ { false, 0x6e18, 0x6e18 }, +/* 0x6e19 */ { false, 0x6e19, 0x6e19 }, +/* 0x6e1a */ { false, 0x6e1a, 0x6e1a }, +/* 0x6e1b */ { false, 0x6e1b, 0x6e1b }, +/* 0x6e1c */ { false, 0x6e1c, 0x6e1c }, +/* 0x6e1d */ { false, 0x6e1d, 0x6e1d }, +/* 0x6e1e */ { false, 0x6e1e, 0x6e1e }, +/* 0x6e1f */ { false, 0x6e1f, 0x6e1f }, +/* 0x6e20 */ { false, 0x6e20, 0x6e20 }, +/* 0x6e21 */ { false, 0x6e21, 0x6e21 }, +/* 0x6e22 */ { false, 0x6e22, 0x6e22 }, +/* 0x6e23 */ { false, 0x6e23, 0x6e23 }, +/* 0x6e24 */ { false, 0x6e24, 0x6e24 }, +/* 0x6e25 */ { false, 0x6e25, 0x6e25 }, +/* 0x6e26 */ { false, 0x6e26, 0x6e26 }, +/* 0x6e27 */ { false, 0x6e27, 0x6e27 }, +/* 0x6e28 */ { false, 0x6e28, 0x6e28 }, +/* 0x6e29 */ { false, 0x6e29, 0x6e29 }, +/* 0x6e2a */ { false, 0x6e2a, 0x6e2a }, +/* 0x6e2b */ { false, 0x6e2b, 0x6e2b }, +/* 0x6e2c */ { false, 0x6e2c, 0x6e2c }, +/* 0x6e2d */ { false, 0x6e2d, 0x6e2d }, +/* 0x6e2e */ { false, 0x6e2e, 0x6e2e }, +/* 0x6e2f */ { false, 0x6e2f, 0x6e2f }, +/* 0x6e30 */ { false, 0x6e30, 0x6e30 }, +/* 0x6e31 */ { false, 0x6e31, 0x6e31 }, +/* 0x6e32 */ { false, 0x6e32, 0x6e32 }, +/* 0x6e33 */ { false, 0x6e33, 0x6e33 }, +/* 0x6e34 */ { false, 0x6e34, 0x6e34 }, +/* 0x6e35 */ { false, 0x6e35, 0x6e35 }, +/* 0x6e36 */ { false, 0x6e36, 0x6e36 }, +/* 0x6e37 */ { false, 0x6e37, 0x6e37 }, +/* 0x6e38 */ { false, 0x6e38, 0x6e38 }, +/* 0x6e39 */ { false, 0x6e39, 0x6e39 }, +/* 0x6e3a */ { false, 0x6e3a, 0x6e3a }, +/* 0x6e3b */ { false, 0x6e3b, 0x6e3b }, +/* 0x6e3c */ { false, 0x6e3c, 0x6e3c }, +/* 0x6e3d */ { false, 0x6e3d, 0x6e3d }, +/* 0x6e3e */ { false, 0x6e3e, 0x6e3e }, +/* 0x6e3f */ { false, 0x6e3f, 0x6e3f }, +/* 0x6e40 */ { false, 0x6e40, 0x6e40 }, +/* 0x6e41 */ { false, 0x6e41, 0x6e41 }, +/* 0x6e42 */ { false, 0x6e42, 0x6e42 }, +/* 0x6e43 */ { false, 0x6e43, 0x6e43 }, +/* 0x6e44 */ { false, 0x6e44, 0x6e44 }, +/* 0x6e45 */ { false, 0x6e45, 0x6e45 }, +/* 0x6e46 */ { false, 0x6e46, 0x6e46 }, +/* 0x6e47 */ { false, 0x6e47, 0x6e47 }, +/* 0x6e48 */ { false, 0x6e48, 0x6e48 }, +/* 0x6e49 */ { false, 0x6e49, 0x6e49 }, +/* 0x6e4a */ { false, 0x6e4a, 0x6e4a }, +/* 0x6e4b */ { false, 0x6e4b, 0x6e4b }, +/* 0x6e4c */ { false, 0x6e4c, 0x6e4c }, +/* 0x6e4d */ { false, 0x6e4d, 0x6e4d }, +/* 0x6e4e */ { false, 0x6e4e, 0x6e4e }, +/* 0x6e4f */ { false, 0x6e4f, 0x6e4f }, +/* 0x6e50 */ { false, 0x6e50, 0x6e50 }, +/* 0x6e51 */ { false, 0x6e51, 0x6e51 }, +/* 0x6e52 */ { false, 0x6e52, 0x6e52 }, +/* 0x6e53 */ { false, 0x6e53, 0x6e53 }, +/* 0x6e54 */ { false, 0x6e54, 0x6e54 }, +/* 0x6e55 */ { false, 0x6e55, 0x6e55 }, +/* 0x6e56 */ { false, 0x6e56, 0x6e56 }, +/* 0x6e57 */ { false, 0x6e57, 0x6e57 }, +/* 0x6e58 */ { false, 0x6e58, 0x6e58 }, +/* 0x6e59 */ { false, 0x6e59, 0x6e59 }, +/* 0x6e5a */ { false, 0x6e5a, 0x6e5a }, +/* 0x6e5b */ { false, 0x6e5b, 0x6e5b }, +/* 0x6e5c */ { false, 0x6e5c, 0x6e5c }, +/* 0x6e5d */ { false, 0x6e5d, 0x6e5d }, +/* 0x6e5e */ { false, 0x6e5e, 0x6e5e }, +/* 0x6e5f */ { false, 0x6e5f, 0x6e5f }, +/* 0x6e60 */ { false, 0x6e60, 0x6e60 }, +/* 0x6e61 */ { false, 0x6e61, 0x6e61 }, +/* 0x6e62 */ { false, 0x6e62, 0x6e62 }, +/* 0x6e63 */ { false, 0x6e63, 0x6e63 }, +/* 0x6e64 */ { false, 0x6e64, 0x6e64 }, +/* 0x6e65 */ { false, 0x6e65, 0x6e65 }, +/* 0x6e66 */ { false, 0x6e66, 0x6e66 }, +/* 0x6e67 */ { false, 0x6e67, 0x6e67 }, +/* 0x6e68 */ { false, 0x6e68, 0x6e68 }, +/* 0x6e69 */ { false, 0x6e69, 0x6e69 }, +/* 0x6e6a */ { false, 0x6e6a, 0x6e6a }, +/* 0x6e6b */ { false, 0x6e6b, 0x6e6b }, +/* 0x6e6c */ { false, 0x6e6c, 0x6e6c }, +/* 0x6e6d */ { false, 0x6e6d, 0x6e6d }, +/* 0x6e6e */ { false, 0x6e6e, 0x6e6e }, +/* 0x6e6f */ { false, 0x6e6f, 0x6e6f }, +/* 0x6e70 */ { false, 0x6e70, 0x6e70 }, +/* 0x6e71 */ { false, 0x6e71, 0x6e71 }, +/* 0x6e72 */ { false, 0x6e72, 0x6e72 }, +/* 0x6e73 */ { false, 0x6e73, 0x6e73 }, +/* 0x6e74 */ { false, 0x6e74, 0x6e74 }, +/* 0x6e75 */ { false, 0x6e75, 0x6e75 }, +/* 0x6e76 */ { false, 0x6e76, 0x6e76 }, +/* 0x6e77 */ { false, 0x6e77, 0x6e77 }, +/* 0x6e78 */ { false, 0x6e78, 0x6e78 }, +/* 0x6e79 */ { false, 0x6e79, 0x6e79 }, +/* 0x6e7a */ { false, 0x6e7a, 0x6e7a }, +/* 0x6e7b */ { false, 0x6e7b, 0x6e7b }, +/* 0x6e7c */ { false, 0x6e7c, 0x6e7c }, +/* 0x6e7d */ { false, 0x6e7d, 0x6e7d }, +/* 0x6e7e */ { false, 0x6e7e, 0x6e7e }, +/* 0x6e7f */ { false, 0x6e7f, 0x6e7f }, +/* 0x6e80 */ { false, 0x6e80, 0x6e80 }, +/* 0x6e81 */ { false, 0x6e81, 0x6e81 }, +/* 0x6e82 */ { false, 0x6e82, 0x6e82 }, +/* 0x6e83 */ { false, 0x6e83, 0x6e83 }, +/* 0x6e84 */ { false, 0x6e84, 0x6e84 }, +/* 0x6e85 */ { false, 0x6e85, 0x6e85 }, +/* 0x6e86 */ { false, 0x6e86, 0x6e86 }, +/* 0x6e87 */ { false, 0x6e87, 0x6e87 }, +/* 0x6e88 */ { false, 0x6e88, 0x6e88 }, +/* 0x6e89 */ { false, 0x6e89, 0x6e89 }, +/* 0x6e8a */ { false, 0x6e8a, 0x6e8a }, +/* 0x6e8b */ { false, 0x6e8b, 0x6e8b }, +/* 0x6e8c */ { false, 0x6e8c, 0x6e8c }, +/* 0x6e8d */ { false, 0x6e8d, 0x6e8d }, +/* 0x6e8e */ { false, 0x6e8e, 0x6e8e }, +/* 0x6e8f */ { false, 0x6e8f, 0x6e8f }, +/* 0x6e90 */ { false, 0x6e90, 0x6e90 }, +/* 0x6e91 */ { false, 0x6e91, 0x6e91 }, +/* 0x6e92 */ { false, 0x6e92, 0x6e92 }, +/* 0x6e93 */ { false, 0x6e93, 0x6e93 }, +/* 0x6e94 */ { false, 0x6e94, 0x6e94 }, +/* 0x6e95 */ { false, 0x6e95, 0x6e95 }, +/* 0x6e96 */ { false, 0x6e96, 0x6e96 }, +/* 0x6e97 */ { false, 0x6e97, 0x6e97 }, +/* 0x6e98 */ { false, 0x6e98, 0x6e98 }, +/* 0x6e99 */ { false, 0x6e99, 0x6e99 }, +/* 0x6e9a */ { false, 0x6e9a, 0x6e9a }, +/* 0x6e9b */ { false, 0x6e9b, 0x6e9b }, +/* 0x6e9c */ { false, 0x6e9c, 0x6e9c }, +/* 0x6e9d */ { false, 0x6e9d, 0x6e9d }, +/* 0x6e9e */ { false, 0x6e9e, 0x6e9e }, +/* 0x6e9f */ { false, 0x6e9f, 0x6e9f }, +/* 0x6ea0 */ { false, 0x6ea0, 0x6ea0 }, +/* 0x6ea1 */ { false, 0x6ea1, 0x6ea1 }, +/* 0x6ea2 */ { false, 0x6ea2, 0x6ea2 }, +/* 0x6ea3 */ { false, 0x6ea3, 0x6ea3 }, +/* 0x6ea4 */ { false, 0x6ea4, 0x6ea4 }, +/* 0x6ea5 */ { false, 0x6ea5, 0x6ea5 }, +/* 0x6ea6 */ { false, 0x6ea6, 0x6ea6 }, +/* 0x6ea7 */ { false, 0x6ea7, 0x6ea7 }, +/* 0x6ea8 */ { false, 0x6ea8, 0x6ea8 }, +/* 0x6ea9 */ { false, 0x6ea9, 0x6ea9 }, +/* 0x6eaa */ { false, 0x6eaa, 0x6eaa }, +/* 0x6eab */ { false, 0x6eab, 0x6eab }, +/* 0x6eac */ { false, 0x6eac, 0x6eac }, +/* 0x6ead */ { false, 0x6ead, 0x6ead }, +/* 0x6eae */ { false, 0x6eae, 0x6eae }, +/* 0x6eaf */ { false, 0x6eaf, 0x6eaf }, +/* 0x6eb0 */ { false, 0x6eb0, 0x6eb0 }, +/* 0x6eb1 */ { false, 0x6eb1, 0x6eb1 }, +/* 0x6eb2 */ { false, 0x6eb2, 0x6eb2 }, +/* 0x6eb3 */ { false, 0x6eb3, 0x6eb3 }, +/* 0x6eb4 */ { false, 0x6eb4, 0x6eb4 }, +/* 0x6eb5 */ { false, 0x6eb5, 0x6eb5 }, +/* 0x6eb6 */ { false, 0x6eb6, 0x6eb6 }, +/* 0x6eb7 */ { false, 0x6eb7, 0x6eb7 }, +/* 0x6eb8 */ { false, 0x6eb8, 0x6eb8 }, +/* 0x6eb9 */ { false, 0x6eb9, 0x6eb9 }, +/* 0x6eba */ { false, 0x6eba, 0x6eba }, +/* 0x6ebb */ { false, 0x6ebb, 0x6ebb }, +/* 0x6ebc */ { false, 0x6ebc, 0x6ebc }, +/* 0x6ebd */ { false, 0x6ebd, 0x6ebd }, +/* 0x6ebe */ { false, 0x6ebe, 0x6ebe }, +/* 0x6ebf */ { false, 0x6ebf, 0x6ebf }, +/* 0x6ec0 */ { false, 0x6ec0, 0x6ec0 }, +/* 0x6ec1 */ { false, 0x6ec1, 0x6ec1 }, +/* 0x6ec2 */ { false, 0x6ec2, 0x6ec2 }, +/* 0x6ec3 */ { false, 0x6ec3, 0x6ec3 }, +/* 0x6ec4 */ { false, 0x6ec4, 0x6ec4 }, +/* 0x6ec5 */ { false, 0x6ec5, 0x6ec5 }, +/* 0x6ec6 */ { false, 0x6ec6, 0x6ec6 }, +/* 0x6ec7 */ { false, 0x6ec7, 0x6ec7 }, +/* 0x6ec8 */ { false, 0x6ec8, 0x6ec8 }, +/* 0x6ec9 */ { false, 0x6ec9, 0x6ec9 }, +/* 0x6eca */ { false, 0x6eca, 0x6eca }, +/* 0x6ecb */ { false, 0x6ecb, 0x6ecb }, +/* 0x6ecc */ { false, 0x6ecc, 0x6ecc }, +/* 0x6ecd */ { false, 0x6ecd, 0x6ecd }, +/* 0x6ece */ { false, 0x6ece, 0x6ece }, +/* 0x6ecf */ { false, 0x6ecf, 0x6ecf }, +/* 0x6ed0 */ { false, 0x6ed0, 0x6ed0 }, +/* 0x6ed1 */ { false, 0x6ed1, 0x6ed1 }, +/* 0x6ed2 */ { false, 0x6ed2, 0x6ed2 }, +/* 0x6ed3 */ { false, 0x6ed3, 0x6ed3 }, +/* 0x6ed4 */ { false, 0x6ed4, 0x6ed4 }, +/* 0x6ed5 */ { false, 0x6ed5, 0x6ed5 }, +/* 0x6ed6 */ { false, 0x6ed6, 0x6ed6 }, +/* 0x6ed7 */ { false, 0x6ed7, 0x6ed7 }, +/* 0x6ed8 */ { false, 0x6ed8, 0x6ed8 }, +/* 0x6ed9 */ { false, 0x6ed9, 0x6ed9 }, +/* 0x6eda */ { false, 0x6eda, 0x6eda }, +/* 0x6edb */ { false, 0x6edb, 0x6edb }, +/* 0x6edc */ { false, 0x6edc, 0x6edc }, +/* 0x6edd */ { false, 0x6edd, 0x6edd }, +/* 0x6ede */ { false, 0x6ede, 0x6ede }, +/* 0x6edf */ { false, 0x6edf, 0x6edf }, +/* 0x6ee0 */ { false, 0x6ee0, 0x6ee0 }, +/* 0x6ee1 */ { false, 0x6ee1, 0x6ee1 }, +/* 0x6ee2 */ { false, 0x6ee2, 0x6ee2 }, +/* 0x6ee3 */ { false, 0x6ee3, 0x6ee3 }, +/* 0x6ee4 */ { false, 0x6ee4, 0x6ee4 }, +/* 0x6ee5 */ { false, 0x6ee5, 0x6ee5 }, +/* 0x6ee6 */ { false, 0x6ee6, 0x6ee6 }, +/* 0x6ee7 */ { false, 0x6ee7, 0x6ee7 }, +/* 0x6ee8 */ { false, 0x6ee8, 0x6ee8 }, +/* 0x6ee9 */ { false, 0x6ee9, 0x6ee9 }, +/* 0x6eea */ { false, 0x6eea, 0x6eea }, +/* 0x6eeb */ { false, 0x6eeb, 0x6eeb }, +/* 0x6eec */ { false, 0x6eec, 0x6eec }, +/* 0x6eed */ { false, 0x6eed, 0x6eed }, +/* 0x6eee */ { false, 0x6eee, 0x6eee }, +/* 0x6eef */ { false, 0x6eef, 0x6eef }, +/* 0x6ef0 */ { false, 0x6ef0, 0x6ef0 }, +/* 0x6ef1 */ { false, 0x6ef1, 0x6ef1 }, +/* 0x6ef2 */ { false, 0x6ef2, 0x6ef2 }, +/* 0x6ef3 */ { false, 0x6ef3, 0x6ef3 }, +/* 0x6ef4 */ { false, 0x6ef4, 0x6ef4 }, +/* 0x6ef5 */ { false, 0x6ef5, 0x6ef5 }, +/* 0x6ef6 */ { false, 0x6ef6, 0x6ef6 }, +/* 0x6ef7 */ { false, 0x6ef7, 0x6ef7 }, +/* 0x6ef8 */ { false, 0x6ef8, 0x6ef8 }, +/* 0x6ef9 */ { false, 0x6ef9, 0x6ef9 }, +/* 0x6efa */ { false, 0x6efa, 0x6efa }, +/* 0x6efb */ { false, 0x6efb, 0x6efb }, +/* 0x6efc */ { false, 0x6efc, 0x6efc }, +/* 0x6efd */ { false, 0x6efd, 0x6efd }, +/* 0x6efe */ { false, 0x6efe, 0x6efe }, +/* 0x6eff */ { false, 0x6eff, 0x6eff }, +/* 0x6f00 */ { false, 0x6f00, 0x6f00 }, +/* 0x6f01 */ { false, 0x6f01, 0x6f01 }, +/* 0x6f02 */ { false, 0x6f02, 0x6f02 }, +/* 0x6f03 */ { false, 0x6f03, 0x6f03 }, +/* 0x6f04 */ { false, 0x6f04, 0x6f04 }, +/* 0x6f05 */ { false, 0x6f05, 0x6f05 }, +/* 0x6f06 */ { false, 0x6f06, 0x6f06 }, +/* 0x6f07 */ { false, 0x6f07, 0x6f07 }, +/* 0x6f08 */ { false, 0x6f08, 0x6f08 }, +/* 0x6f09 */ { false, 0x6f09, 0x6f09 }, +/* 0x6f0a */ { false, 0x6f0a, 0x6f0a }, +/* 0x6f0b */ { false, 0x6f0b, 0x6f0b }, +/* 0x6f0c */ { false, 0x6f0c, 0x6f0c }, +/* 0x6f0d */ { false, 0x6f0d, 0x6f0d }, +/* 0x6f0e */ { false, 0x6f0e, 0x6f0e }, +/* 0x6f0f */ { false, 0x6f0f, 0x6f0f }, +/* 0x6f10 */ { false, 0x6f10, 0x6f10 }, +/* 0x6f11 */ { false, 0x6f11, 0x6f11 }, +/* 0x6f12 */ { false, 0x6f12, 0x6f12 }, +/* 0x6f13 */ { false, 0x6f13, 0x6f13 }, +/* 0x6f14 */ { false, 0x6f14, 0x6f14 }, +/* 0x6f15 */ { false, 0x6f15, 0x6f15 }, +/* 0x6f16 */ { false, 0x6f16, 0x6f16 }, +/* 0x6f17 */ { false, 0x6f17, 0x6f17 }, +/* 0x6f18 */ { false, 0x6f18, 0x6f18 }, +/* 0x6f19 */ { false, 0x6f19, 0x6f19 }, +/* 0x6f1a */ { false, 0x6f1a, 0x6f1a }, +/* 0x6f1b */ { false, 0x6f1b, 0x6f1b }, +/* 0x6f1c */ { false, 0x6f1c, 0x6f1c }, +/* 0x6f1d */ { false, 0x6f1d, 0x6f1d }, +/* 0x6f1e */ { false, 0x6f1e, 0x6f1e }, +/* 0x6f1f */ { false, 0x6f1f, 0x6f1f }, +/* 0x6f20 */ { false, 0x6f20, 0x6f20 }, +/* 0x6f21 */ { false, 0x6f21, 0x6f21 }, +/* 0x6f22 */ { false, 0x6f22, 0x6f22 }, +/* 0x6f23 */ { false, 0x6f23, 0x6f23 }, +/* 0x6f24 */ { false, 0x6f24, 0x6f24 }, +/* 0x6f25 */ { false, 0x6f25, 0x6f25 }, +/* 0x6f26 */ { false, 0x6f26, 0x6f26 }, +/* 0x6f27 */ { false, 0x6f27, 0x6f27 }, +/* 0x6f28 */ { false, 0x6f28, 0x6f28 }, +/* 0x6f29 */ { false, 0x6f29, 0x6f29 }, +/* 0x6f2a */ { false, 0x6f2a, 0x6f2a }, +/* 0x6f2b */ { false, 0x6f2b, 0x6f2b }, +/* 0x6f2c */ { false, 0x6f2c, 0x6f2c }, +/* 0x6f2d */ { false, 0x6f2d, 0x6f2d }, +/* 0x6f2e */ { false, 0x6f2e, 0x6f2e }, +/* 0x6f2f */ { false, 0x6f2f, 0x6f2f }, +/* 0x6f30 */ { false, 0x6f30, 0x6f30 }, +/* 0x6f31 */ { false, 0x6f31, 0x6f31 }, +/* 0x6f32 */ { false, 0x6f32, 0x6f32 }, +/* 0x6f33 */ { false, 0x6f33, 0x6f33 }, +/* 0x6f34 */ { false, 0x6f34, 0x6f34 }, +/* 0x6f35 */ { false, 0x6f35, 0x6f35 }, +/* 0x6f36 */ { false, 0x6f36, 0x6f36 }, +/* 0x6f37 */ { false, 0x6f37, 0x6f37 }, +/* 0x6f38 */ { false, 0x6f38, 0x6f38 }, +/* 0x6f39 */ { false, 0x6f39, 0x6f39 }, +/* 0x6f3a */ { false, 0x6f3a, 0x6f3a }, +/* 0x6f3b */ { false, 0x6f3b, 0x6f3b }, +/* 0x6f3c */ { false, 0x6f3c, 0x6f3c }, +/* 0x6f3d */ { false, 0x6f3d, 0x6f3d }, +/* 0x6f3e */ { false, 0x6f3e, 0x6f3e }, +/* 0x6f3f */ { false, 0x6f3f, 0x6f3f }, +/* 0x6f40 */ { false, 0x6f40, 0x6f40 }, +/* 0x6f41 */ { false, 0x6f41, 0x6f41 }, +/* 0x6f42 */ { false, 0x6f42, 0x6f42 }, +/* 0x6f43 */ { false, 0x6f43, 0x6f43 }, +/* 0x6f44 */ { false, 0x6f44, 0x6f44 }, +/* 0x6f45 */ { false, 0x6f45, 0x6f45 }, +/* 0x6f46 */ { false, 0x6f46, 0x6f46 }, +/* 0x6f47 */ { false, 0x6f47, 0x6f47 }, +/* 0x6f48 */ { false, 0x6f48, 0x6f48 }, +/* 0x6f49 */ { false, 0x6f49, 0x6f49 }, +/* 0x6f4a */ { false, 0x6f4a, 0x6f4a }, +/* 0x6f4b */ { false, 0x6f4b, 0x6f4b }, +/* 0x6f4c */ { false, 0x6f4c, 0x6f4c }, +/* 0x6f4d */ { false, 0x6f4d, 0x6f4d }, +/* 0x6f4e */ { false, 0x6f4e, 0x6f4e }, +/* 0x6f4f */ { false, 0x6f4f, 0x6f4f }, +/* 0x6f50 */ { false, 0x6f50, 0x6f50 }, +/* 0x6f51 */ { false, 0x6f51, 0x6f51 }, +/* 0x6f52 */ { false, 0x6f52, 0x6f52 }, +/* 0x6f53 */ { false, 0x6f53, 0x6f53 }, +/* 0x6f54 */ { false, 0x6f54, 0x6f54 }, +/* 0x6f55 */ { false, 0x6f55, 0x6f55 }, +/* 0x6f56 */ { false, 0x6f56, 0x6f56 }, +/* 0x6f57 */ { false, 0x6f57, 0x6f57 }, +/* 0x6f58 */ { false, 0x6f58, 0x6f58 }, +/* 0x6f59 */ { false, 0x6f59, 0x6f59 }, +/* 0x6f5a */ { false, 0x6f5a, 0x6f5a }, +/* 0x6f5b */ { false, 0x6f5b, 0x6f5b }, +/* 0x6f5c */ { false, 0x6f5c, 0x6f5c }, +/* 0x6f5d */ { false, 0x6f5d, 0x6f5d }, +/* 0x6f5e */ { false, 0x6f5e, 0x6f5e }, +/* 0x6f5f */ { false, 0x6f5f, 0x6f5f }, +/* 0x6f60 */ { false, 0x6f60, 0x6f60 }, +/* 0x6f61 */ { false, 0x6f61, 0x6f61 }, +/* 0x6f62 */ { false, 0x6f62, 0x6f62 }, +/* 0x6f63 */ { false, 0x6f63, 0x6f63 }, +/* 0x6f64 */ { false, 0x6f64, 0x6f64 }, +/* 0x6f65 */ { false, 0x6f65, 0x6f65 }, +/* 0x6f66 */ { false, 0x6f66, 0x6f66 }, +/* 0x6f67 */ { false, 0x6f67, 0x6f67 }, +/* 0x6f68 */ { false, 0x6f68, 0x6f68 }, +/* 0x6f69 */ { false, 0x6f69, 0x6f69 }, +/* 0x6f6a */ { false, 0x6f6a, 0x6f6a }, +/* 0x6f6b */ { false, 0x6f6b, 0x6f6b }, +/* 0x6f6c */ { false, 0x6f6c, 0x6f6c }, +/* 0x6f6d */ { false, 0x6f6d, 0x6f6d }, +/* 0x6f6e */ { false, 0x6f6e, 0x6f6e }, +/* 0x6f6f */ { false, 0x6f6f, 0x6f6f }, +/* 0x6f70 */ { false, 0x6f70, 0x6f70 }, +/* 0x6f71 */ { false, 0x6f71, 0x6f71 }, +/* 0x6f72 */ { false, 0x6f72, 0x6f72 }, +/* 0x6f73 */ { false, 0x6f73, 0x6f73 }, +/* 0x6f74 */ { false, 0x6f74, 0x6f74 }, +/* 0x6f75 */ { false, 0x6f75, 0x6f75 }, +/* 0x6f76 */ { false, 0x6f76, 0x6f76 }, +/* 0x6f77 */ { false, 0x6f77, 0x6f77 }, +/* 0x6f78 */ { false, 0x6f78, 0x6f78 }, +/* 0x6f79 */ { false, 0x6f79, 0x6f79 }, +/* 0x6f7a */ { false, 0x6f7a, 0x6f7a }, +/* 0x6f7b */ { false, 0x6f7b, 0x6f7b }, +/* 0x6f7c */ { false, 0x6f7c, 0x6f7c }, +/* 0x6f7d */ { false, 0x6f7d, 0x6f7d }, +/* 0x6f7e */ { false, 0x6f7e, 0x6f7e }, +/* 0x6f7f */ { false, 0x6f7f, 0x6f7f }, +/* 0x6f80 */ { false, 0x6f80, 0x6f80 }, +/* 0x6f81 */ { false, 0x6f81, 0x6f81 }, +/* 0x6f82 */ { false, 0x6f82, 0x6f82 }, +/* 0x6f83 */ { false, 0x6f83, 0x6f83 }, +/* 0x6f84 */ { false, 0x6f84, 0x6f84 }, +/* 0x6f85 */ { false, 0x6f85, 0x6f85 }, +/* 0x6f86 */ { false, 0x6f86, 0x6f86 }, +/* 0x6f87 */ { false, 0x6f87, 0x6f87 }, +/* 0x6f88 */ { false, 0x6f88, 0x6f88 }, +/* 0x6f89 */ { false, 0x6f89, 0x6f89 }, +/* 0x6f8a */ { false, 0x6f8a, 0x6f8a }, +/* 0x6f8b */ { false, 0x6f8b, 0x6f8b }, +/* 0x6f8c */ { false, 0x6f8c, 0x6f8c }, +/* 0x6f8d */ { false, 0x6f8d, 0x6f8d }, +/* 0x6f8e */ { false, 0x6f8e, 0x6f8e }, +/* 0x6f8f */ { false, 0x6f8f, 0x6f8f }, +/* 0x6f90 */ { false, 0x6f90, 0x6f90 }, +/* 0x6f91 */ { false, 0x6f91, 0x6f91 }, +/* 0x6f92 */ { false, 0x6f92, 0x6f92 }, +/* 0x6f93 */ { false, 0x6f93, 0x6f93 }, +/* 0x6f94 */ { false, 0x6f94, 0x6f94 }, +/* 0x6f95 */ { false, 0x6f95, 0x6f95 }, +/* 0x6f96 */ { false, 0x6f96, 0x6f96 }, +/* 0x6f97 */ { false, 0x6f97, 0x6f97 }, +/* 0x6f98 */ { false, 0x6f98, 0x6f98 }, +/* 0x6f99 */ { false, 0x6f99, 0x6f99 }, +/* 0x6f9a */ { false, 0x6f9a, 0x6f9a }, +/* 0x6f9b */ { false, 0x6f9b, 0x6f9b }, +/* 0x6f9c */ { false, 0x6f9c, 0x6f9c }, +/* 0x6f9d */ { false, 0x6f9d, 0x6f9d }, +/* 0x6f9e */ { false, 0x6f9e, 0x6f9e }, +/* 0x6f9f */ { false, 0x6f9f, 0x6f9f }, +/* 0x6fa0 */ { false, 0x6fa0, 0x6fa0 }, +/* 0x6fa1 */ { false, 0x6fa1, 0x6fa1 }, +/* 0x6fa2 */ { false, 0x6fa2, 0x6fa2 }, +/* 0x6fa3 */ { false, 0x6fa3, 0x6fa3 }, +/* 0x6fa4 */ { false, 0x6fa4, 0x6fa4 }, +/* 0x6fa5 */ { false, 0x6fa5, 0x6fa5 }, +/* 0x6fa6 */ { false, 0x6fa6, 0x6fa6 }, +/* 0x6fa7 */ { false, 0x6fa7, 0x6fa7 }, +/* 0x6fa8 */ { false, 0x6fa8, 0x6fa8 }, +/* 0x6fa9 */ { false, 0x6fa9, 0x6fa9 }, +/* 0x6faa */ { false, 0x6faa, 0x6faa }, +/* 0x6fab */ { false, 0x6fab, 0x6fab }, +/* 0x6fac */ { false, 0x6fac, 0x6fac }, +/* 0x6fad */ { false, 0x6fad, 0x6fad }, +/* 0x6fae */ { false, 0x6fae, 0x6fae }, +/* 0x6faf */ { false, 0x6faf, 0x6faf }, +/* 0x6fb0 */ { false, 0x6fb0, 0x6fb0 }, +/* 0x6fb1 */ { false, 0x6fb1, 0x6fb1 }, +/* 0x6fb2 */ { false, 0x6fb2, 0x6fb2 }, +/* 0x6fb3 */ { false, 0x6fb3, 0x6fb3 }, +/* 0x6fb4 */ { false, 0x6fb4, 0x6fb4 }, +/* 0x6fb5 */ { false, 0x6fb5, 0x6fb5 }, +/* 0x6fb6 */ { false, 0x6fb6, 0x6fb6 }, +/* 0x6fb7 */ { false, 0x6fb7, 0x6fb7 }, +/* 0x6fb8 */ { false, 0x6fb8, 0x6fb8 }, +/* 0x6fb9 */ { false, 0x6fb9, 0x6fb9 }, +/* 0x6fba */ { false, 0x6fba, 0x6fba }, +/* 0x6fbb */ { false, 0x6fbb, 0x6fbb }, +/* 0x6fbc */ { false, 0x6fbc, 0x6fbc }, +/* 0x6fbd */ { false, 0x6fbd, 0x6fbd }, +/* 0x6fbe */ { false, 0x6fbe, 0x6fbe }, +/* 0x6fbf */ { false, 0x6fbf, 0x6fbf }, +/* 0x6fc0 */ { false, 0x6fc0, 0x6fc0 }, +/* 0x6fc1 */ { false, 0x6fc1, 0x6fc1 }, +/* 0x6fc2 */ { false, 0x6fc2, 0x6fc2 }, +/* 0x6fc3 */ { false, 0x6fc3, 0x6fc3 }, +/* 0x6fc4 */ { false, 0x6fc4, 0x6fc4 }, +/* 0x6fc5 */ { false, 0x6fc5, 0x6fc5 }, +/* 0x6fc6 */ { false, 0x6fc6, 0x6fc6 }, +/* 0x6fc7 */ { false, 0x6fc7, 0x6fc7 }, +/* 0x6fc8 */ { false, 0x6fc8, 0x6fc8 }, +/* 0x6fc9 */ { false, 0x6fc9, 0x6fc9 }, +/* 0x6fca */ { false, 0x6fca, 0x6fca }, +/* 0x6fcb */ { false, 0x6fcb, 0x6fcb }, +/* 0x6fcc */ { false, 0x6fcc, 0x6fcc }, +/* 0x6fcd */ { false, 0x6fcd, 0x6fcd }, +/* 0x6fce */ { false, 0x6fce, 0x6fce }, +/* 0x6fcf */ { false, 0x6fcf, 0x6fcf }, +/* 0x6fd0 */ { false, 0x6fd0, 0x6fd0 }, +/* 0x6fd1 */ { false, 0x6fd1, 0x6fd1 }, +/* 0x6fd2 */ { false, 0x6fd2, 0x6fd2 }, +/* 0x6fd3 */ { false, 0x6fd3, 0x6fd3 }, +/* 0x6fd4 */ { false, 0x6fd4, 0x6fd4 }, +/* 0x6fd5 */ { false, 0x6fd5, 0x6fd5 }, +/* 0x6fd6 */ { false, 0x6fd6, 0x6fd6 }, +/* 0x6fd7 */ { false, 0x6fd7, 0x6fd7 }, +/* 0x6fd8 */ { false, 0x6fd8, 0x6fd8 }, +/* 0x6fd9 */ { false, 0x6fd9, 0x6fd9 }, +/* 0x6fda */ { false, 0x6fda, 0x6fda }, +/* 0x6fdb */ { false, 0x6fdb, 0x6fdb }, +/* 0x6fdc */ { false, 0x6fdc, 0x6fdc }, +/* 0x6fdd */ { false, 0x6fdd, 0x6fdd }, +/* 0x6fde */ { false, 0x6fde, 0x6fde }, +/* 0x6fdf */ { false, 0x6fdf, 0x6fdf }, +/* 0x6fe0 */ { false, 0x6fe0, 0x6fe0 }, +/* 0x6fe1 */ { false, 0x6fe1, 0x6fe1 }, +/* 0x6fe2 */ { false, 0x6fe2, 0x6fe2 }, +/* 0x6fe3 */ { false, 0x6fe3, 0x6fe3 }, +/* 0x6fe4 */ { false, 0x6fe4, 0x6fe4 }, +/* 0x6fe5 */ { false, 0x6fe5, 0x6fe5 }, +/* 0x6fe6 */ { false, 0x6fe6, 0x6fe6 }, +/* 0x6fe7 */ { false, 0x6fe7, 0x6fe7 }, +/* 0x6fe8 */ { false, 0x6fe8, 0x6fe8 }, +/* 0x6fe9 */ { false, 0x6fe9, 0x6fe9 }, +/* 0x6fea */ { false, 0x6fea, 0x6fea }, +/* 0x6feb */ { false, 0x6feb, 0x6feb }, +/* 0x6fec */ { false, 0x6fec, 0x6fec }, +/* 0x6fed */ { false, 0x6fed, 0x6fed }, +/* 0x6fee */ { false, 0x6fee, 0x6fee }, +/* 0x6fef */ { false, 0x6fef, 0x6fef }, +/* 0x6ff0 */ { false, 0x6ff0, 0x6ff0 }, +/* 0x6ff1 */ { false, 0x6ff1, 0x6ff1 }, +/* 0x6ff2 */ { false, 0x6ff2, 0x6ff2 }, +/* 0x6ff3 */ { false, 0x6ff3, 0x6ff3 }, +/* 0x6ff4 */ { false, 0x6ff4, 0x6ff4 }, +/* 0x6ff5 */ { false, 0x6ff5, 0x6ff5 }, +/* 0x6ff6 */ { false, 0x6ff6, 0x6ff6 }, +/* 0x6ff7 */ { false, 0x6ff7, 0x6ff7 }, +/* 0x6ff8 */ { false, 0x6ff8, 0x6ff8 }, +/* 0x6ff9 */ { false, 0x6ff9, 0x6ff9 }, +/* 0x6ffa */ { false, 0x6ffa, 0x6ffa }, +/* 0x6ffb */ { false, 0x6ffb, 0x6ffb }, +/* 0x6ffc */ { false, 0x6ffc, 0x6ffc }, +/* 0x6ffd */ { false, 0x6ffd, 0x6ffd }, +/* 0x6ffe */ { false, 0x6ffe, 0x6ffe }, +/* 0x6fff */ { false, 0x6fff, 0x6fff }, +/* 0x7000 */ { false, 0x7000, 0x7000 }, +/* 0x7001 */ { false, 0x7001, 0x7001 }, +/* 0x7002 */ { false, 0x7002, 0x7002 }, +/* 0x7003 */ { false, 0x7003, 0x7003 }, +/* 0x7004 */ { false, 0x7004, 0x7004 }, +/* 0x7005 */ { false, 0x7005, 0x7005 }, +/* 0x7006 */ { false, 0x7006, 0x7006 }, +/* 0x7007 */ { false, 0x7007, 0x7007 }, +/* 0x7008 */ { false, 0x7008, 0x7008 }, +/* 0x7009 */ { false, 0x7009, 0x7009 }, +/* 0x700a */ { false, 0x700a, 0x700a }, +/* 0x700b */ { false, 0x700b, 0x700b }, +/* 0x700c */ { false, 0x700c, 0x700c }, +/* 0x700d */ { false, 0x700d, 0x700d }, +/* 0x700e */ { false, 0x700e, 0x700e }, +/* 0x700f */ { false, 0x700f, 0x700f }, +/* 0x7010 */ { false, 0x7010, 0x7010 }, +/* 0x7011 */ { false, 0x7011, 0x7011 }, +/* 0x7012 */ { false, 0x7012, 0x7012 }, +/* 0x7013 */ { false, 0x7013, 0x7013 }, +/* 0x7014 */ { false, 0x7014, 0x7014 }, +/* 0x7015 */ { false, 0x7015, 0x7015 }, +/* 0x7016 */ { false, 0x7016, 0x7016 }, +/* 0x7017 */ { false, 0x7017, 0x7017 }, +/* 0x7018 */ { false, 0x7018, 0x7018 }, +/* 0x7019 */ { false, 0x7019, 0x7019 }, +/* 0x701a */ { false, 0x701a, 0x701a }, +/* 0x701b */ { false, 0x701b, 0x701b }, +/* 0x701c */ { false, 0x701c, 0x701c }, +/* 0x701d */ { false, 0x701d, 0x701d }, +/* 0x701e */ { false, 0x701e, 0x701e }, +/* 0x701f */ { false, 0x701f, 0x701f }, +/* 0x7020 */ { false, 0x7020, 0x7020 }, +/* 0x7021 */ { false, 0x7021, 0x7021 }, +/* 0x7022 */ { false, 0x7022, 0x7022 }, +/* 0x7023 */ { false, 0x7023, 0x7023 }, +/* 0x7024 */ { false, 0x7024, 0x7024 }, +/* 0x7025 */ { false, 0x7025, 0x7025 }, +/* 0x7026 */ { false, 0x7026, 0x7026 }, +/* 0x7027 */ { false, 0x7027, 0x7027 }, +/* 0x7028 */ { false, 0x7028, 0x7028 }, +/* 0x7029 */ { false, 0x7029, 0x7029 }, +/* 0x702a */ { false, 0x702a, 0x702a }, +/* 0x702b */ { false, 0x702b, 0x702b }, +/* 0x702c */ { false, 0x702c, 0x702c }, +/* 0x702d */ { false, 0x702d, 0x702d }, +/* 0x702e */ { false, 0x702e, 0x702e }, +/* 0x702f */ { false, 0x702f, 0x702f }, +/* 0x7030 */ { false, 0x7030, 0x7030 }, +/* 0x7031 */ { false, 0x7031, 0x7031 }, +/* 0x7032 */ { false, 0x7032, 0x7032 }, +/* 0x7033 */ { false, 0x7033, 0x7033 }, +/* 0x7034 */ { false, 0x7034, 0x7034 }, +/* 0x7035 */ { false, 0x7035, 0x7035 }, +/* 0x7036 */ { false, 0x7036, 0x7036 }, +/* 0x7037 */ { false, 0x7037, 0x7037 }, +/* 0x7038 */ { false, 0x7038, 0x7038 }, +/* 0x7039 */ { false, 0x7039, 0x7039 }, +/* 0x703a */ { false, 0x703a, 0x703a }, +/* 0x703b */ { false, 0x703b, 0x703b }, +/* 0x703c */ { false, 0x703c, 0x703c }, +/* 0x703d */ { false, 0x703d, 0x703d }, +/* 0x703e */ { false, 0x703e, 0x703e }, +/* 0x703f */ { false, 0x703f, 0x703f }, +/* 0x7040 */ { false, 0x7040, 0x7040 }, +/* 0x7041 */ { false, 0x7041, 0x7041 }, +/* 0x7042 */ { false, 0x7042, 0x7042 }, +/* 0x7043 */ { false, 0x7043, 0x7043 }, +/* 0x7044 */ { false, 0x7044, 0x7044 }, +/* 0x7045 */ { false, 0x7045, 0x7045 }, +/* 0x7046 */ { false, 0x7046, 0x7046 }, +/* 0x7047 */ { false, 0x7047, 0x7047 }, +/* 0x7048 */ { false, 0x7048, 0x7048 }, +/* 0x7049 */ { false, 0x7049, 0x7049 }, +/* 0x704a */ { false, 0x704a, 0x704a }, +/* 0x704b */ { false, 0x704b, 0x704b }, +/* 0x704c */ { false, 0x704c, 0x704c }, +/* 0x704d */ { false, 0x704d, 0x704d }, +/* 0x704e */ { false, 0x704e, 0x704e }, +/* 0x704f */ { false, 0x704f, 0x704f }, +/* 0x7050 */ { false, 0x7050, 0x7050 }, +/* 0x7051 */ { false, 0x7051, 0x7051 }, +/* 0x7052 */ { false, 0x7052, 0x7052 }, +/* 0x7053 */ { false, 0x7053, 0x7053 }, +/* 0x7054 */ { false, 0x7054, 0x7054 }, +/* 0x7055 */ { false, 0x7055, 0x7055 }, +/* 0x7056 */ { false, 0x7056, 0x7056 }, +/* 0x7057 */ { false, 0x7057, 0x7057 }, +/* 0x7058 */ { false, 0x7058, 0x7058 }, +/* 0x7059 */ { false, 0x7059, 0x7059 }, +/* 0x705a */ { false, 0x705a, 0x705a }, +/* 0x705b */ { false, 0x705b, 0x705b }, +/* 0x705c */ { false, 0x705c, 0x705c }, +/* 0x705d */ { false, 0x705d, 0x705d }, +/* 0x705e */ { false, 0x705e, 0x705e }, +/* 0x705f */ { false, 0x705f, 0x705f }, +/* 0x7060 */ { false, 0x7060, 0x7060 }, +/* 0x7061 */ { false, 0x7061, 0x7061 }, +/* 0x7062 */ { false, 0x7062, 0x7062 }, +/* 0x7063 */ { false, 0x7063, 0x7063 }, +/* 0x7064 */ { false, 0x7064, 0x7064 }, +/* 0x7065 */ { false, 0x7065, 0x7065 }, +/* 0x7066 */ { false, 0x7066, 0x7066 }, +/* 0x7067 */ { false, 0x7067, 0x7067 }, +/* 0x7068 */ { false, 0x7068, 0x7068 }, +/* 0x7069 */ { false, 0x7069, 0x7069 }, +/* 0x706a */ { false, 0x706a, 0x706a }, +/* 0x706b */ { false, 0x706b, 0x706b }, +/* 0x706c */ { false, 0x706c, 0x706c }, +/* 0x706d */ { false, 0x706d, 0x706d }, +/* 0x706e */ { false, 0x706e, 0x706e }, +/* 0x706f */ { false, 0x706f, 0x706f }, +/* 0x7070 */ { false, 0x7070, 0x7070 }, +/* 0x7071 */ { false, 0x7071, 0x7071 }, +/* 0x7072 */ { false, 0x7072, 0x7072 }, +/* 0x7073 */ { false, 0x7073, 0x7073 }, +/* 0x7074 */ { false, 0x7074, 0x7074 }, +/* 0x7075 */ { false, 0x7075, 0x7075 }, +/* 0x7076 */ { false, 0x7076, 0x7076 }, +/* 0x7077 */ { false, 0x7077, 0x7077 }, +/* 0x7078 */ { false, 0x7078, 0x7078 }, +/* 0x7079 */ { false, 0x7079, 0x7079 }, +/* 0x707a */ { false, 0x707a, 0x707a }, +/* 0x707b */ { false, 0x707b, 0x707b }, +/* 0x707c */ { false, 0x707c, 0x707c }, +/* 0x707d */ { false, 0x707d, 0x707d }, +/* 0x707e */ { false, 0x707e, 0x707e }, +/* 0x707f */ { false, 0x707f, 0x707f }, +/* 0x7080 */ { false, 0x7080, 0x7080 }, +/* 0x7081 */ { false, 0x7081, 0x7081 }, +/* 0x7082 */ { false, 0x7082, 0x7082 }, +/* 0x7083 */ { false, 0x7083, 0x7083 }, +/* 0x7084 */ { false, 0x7084, 0x7084 }, +/* 0x7085 */ { false, 0x7085, 0x7085 }, +/* 0x7086 */ { false, 0x7086, 0x7086 }, +/* 0x7087 */ { false, 0x7087, 0x7087 }, +/* 0x7088 */ { false, 0x7088, 0x7088 }, +/* 0x7089 */ { false, 0x7089, 0x7089 }, +/* 0x708a */ { false, 0x708a, 0x708a }, +/* 0x708b */ { false, 0x708b, 0x708b }, +/* 0x708c */ { false, 0x708c, 0x708c }, +/* 0x708d */ { false, 0x708d, 0x708d }, +/* 0x708e */ { false, 0x708e, 0x708e }, +/* 0x708f */ { false, 0x708f, 0x708f }, +/* 0x7090 */ { false, 0x7090, 0x7090 }, +/* 0x7091 */ { false, 0x7091, 0x7091 }, +/* 0x7092 */ { false, 0x7092, 0x7092 }, +/* 0x7093 */ { false, 0x7093, 0x7093 }, +/* 0x7094 */ { false, 0x7094, 0x7094 }, +/* 0x7095 */ { false, 0x7095, 0x7095 }, +/* 0x7096 */ { false, 0x7096, 0x7096 }, +/* 0x7097 */ { false, 0x7097, 0x7097 }, +/* 0x7098 */ { false, 0x7098, 0x7098 }, +/* 0x7099 */ { false, 0x7099, 0x7099 }, +/* 0x709a */ { false, 0x709a, 0x709a }, +/* 0x709b */ { false, 0x709b, 0x709b }, +/* 0x709c */ { false, 0x709c, 0x709c }, +/* 0x709d */ { false, 0x709d, 0x709d }, +/* 0x709e */ { false, 0x709e, 0x709e }, +/* 0x709f */ { false, 0x709f, 0x709f }, +/* 0x70a0 */ { false, 0x70a0, 0x70a0 }, +/* 0x70a1 */ { false, 0x70a1, 0x70a1 }, +/* 0x70a2 */ { false, 0x70a2, 0x70a2 }, +/* 0x70a3 */ { false, 0x70a3, 0x70a3 }, +/* 0x70a4 */ { false, 0x70a4, 0x70a4 }, +/* 0x70a5 */ { false, 0x70a5, 0x70a5 }, +/* 0x70a6 */ { false, 0x70a6, 0x70a6 }, +/* 0x70a7 */ { false, 0x70a7, 0x70a7 }, +/* 0x70a8 */ { false, 0x70a8, 0x70a8 }, +/* 0x70a9 */ { false, 0x70a9, 0x70a9 }, +/* 0x70aa */ { false, 0x70aa, 0x70aa }, +/* 0x70ab */ { false, 0x70ab, 0x70ab }, +/* 0x70ac */ { false, 0x70ac, 0x70ac }, +/* 0x70ad */ { false, 0x70ad, 0x70ad }, +/* 0x70ae */ { false, 0x70ae, 0x70ae }, +/* 0x70af */ { false, 0x70af, 0x70af }, +/* 0x70b0 */ { false, 0x70b0, 0x70b0 }, +/* 0x70b1 */ { false, 0x70b1, 0x70b1 }, +/* 0x70b2 */ { false, 0x70b2, 0x70b2 }, +/* 0x70b3 */ { false, 0x70b3, 0x70b3 }, +/* 0x70b4 */ { false, 0x70b4, 0x70b4 }, +/* 0x70b5 */ { false, 0x70b5, 0x70b5 }, +/* 0x70b6 */ { false, 0x70b6, 0x70b6 }, +/* 0x70b7 */ { false, 0x70b7, 0x70b7 }, +/* 0x70b8 */ { false, 0x70b8, 0x70b8 }, +/* 0x70b9 */ { false, 0x70b9, 0x70b9 }, +/* 0x70ba */ { false, 0x70ba, 0x70ba }, +/* 0x70bb */ { false, 0x70bb, 0x70bb }, +/* 0x70bc */ { false, 0x70bc, 0x70bc }, +/* 0x70bd */ { false, 0x70bd, 0x70bd }, +/* 0x70be */ { false, 0x70be, 0x70be }, +/* 0x70bf */ { false, 0x70bf, 0x70bf }, +/* 0x70c0 */ { false, 0x70c0, 0x70c0 }, +/* 0x70c1 */ { false, 0x70c1, 0x70c1 }, +/* 0x70c2 */ { false, 0x70c2, 0x70c2 }, +/* 0x70c3 */ { false, 0x70c3, 0x70c3 }, +/* 0x70c4 */ { false, 0x70c4, 0x70c4 }, +/* 0x70c5 */ { false, 0x70c5, 0x70c5 }, +/* 0x70c6 */ { false, 0x70c6, 0x70c6 }, +/* 0x70c7 */ { false, 0x70c7, 0x70c7 }, +/* 0x70c8 */ { false, 0x70c8, 0x70c8 }, +/* 0x70c9 */ { false, 0x70c9, 0x70c9 }, +/* 0x70ca */ { false, 0x70ca, 0x70ca }, +/* 0x70cb */ { false, 0x70cb, 0x70cb }, +/* 0x70cc */ { false, 0x70cc, 0x70cc }, +/* 0x70cd */ { false, 0x70cd, 0x70cd }, +/* 0x70ce */ { false, 0x70ce, 0x70ce }, +/* 0x70cf */ { false, 0x70cf, 0x70cf }, +/* 0x70d0 */ { false, 0x70d0, 0x70d0 }, +/* 0x70d1 */ { false, 0x70d1, 0x70d1 }, +/* 0x70d2 */ { false, 0x70d2, 0x70d2 }, +/* 0x70d3 */ { false, 0x70d3, 0x70d3 }, +/* 0x70d4 */ { false, 0x70d4, 0x70d4 }, +/* 0x70d5 */ { false, 0x70d5, 0x70d5 }, +/* 0x70d6 */ { false, 0x70d6, 0x70d6 }, +/* 0x70d7 */ { false, 0x70d7, 0x70d7 }, +/* 0x70d8 */ { false, 0x70d8, 0x70d8 }, +/* 0x70d9 */ { false, 0x70d9, 0x70d9 }, +/* 0x70da */ { false, 0x70da, 0x70da }, +/* 0x70db */ { false, 0x70db, 0x70db }, +/* 0x70dc */ { false, 0x70dc, 0x70dc }, +/* 0x70dd */ { false, 0x70dd, 0x70dd }, +/* 0x70de */ { false, 0x70de, 0x70de }, +/* 0x70df */ { false, 0x70df, 0x70df }, +/* 0x70e0 */ { false, 0x70e0, 0x70e0 }, +/* 0x70e1 */ { false, 0x70e1, 0x70e1 }, +/* 0x70e2 */ { false, 0x70e2, 0x70e2 }, +/* 0x70e3 */ { false, 0x70e3, 0x70e3 }, +/* 0x70e4 */ { false, 0x70e4, 0x70e4 }, +/* 0x70e5 */ { false, 0x70e5, 0x70e5 }, +/* 0x70e6 */ { false, 0x70e6, 0x70e6 }, +/* 0x70e7 */ { false, 0x70e7, 0x70e7 }, +/* 0x70e8 */ { false, 0x70e8, 0x70e8 }, +/* 0x70e9 */ { false, 0x70e9, 0x70e9 }, +/* 0x70ea */ { false, 0x70ea, 0x70ea }, +/* 0x70eb */ { false, 0x70eb, 0x70eb }, +/* 0x70ec */ { false, 0x70ec, 0x70ec }, +/* 0x70ed */ { false, 0x70ed, 0x70ed }, +/* 0x70ee */ { false, 0x70ee, 0x70ee }, +/* 0x70ef */ { false, 0x70ef, 0x70ef }, +/* 0x70f0 */ { false, 0x70f0, 0x70f0 }, +/* 0x70f1 */ { false, 0x70f1, 0x70f1 }, +/* 0x70f2 */ { false, 0x70f2, 0x70f2 }, +/* 0x70f3 */ { false, 0x70f3, 0x70f3 }, +/* 0x70f4 */ { false, 0x70f4, 0x70f4 }, +/* 0x70f5 */ { false, 0x70f5, 0x70f5 }, +/* 0x70f6 */ { false, 0x70f6, 0x70f6 }, +/* 0x70f7 */ { false, 0x70f7, 0x70f7 }, +/* 0x70f8 */ { false, 0x70f8, 0x70f8 }, +/* 0x70f9 */ { false, 0x70f9, 0x70f9 }, +/* 0x70fa */ { false, 0x70fa, 0x70fa }, +/* 0x70fb */ { false, 0x70fb, 0x70fb }, +/* 0x70fc */ { false, 0x70fc, 0x70fc }, +/* 0x70fd */ { false, 0x70fd, 0x70fd }, +/* 0x70fe */ { false, 0x70fe, 0x70fe }, +/* 0x70ff */ { false, 0x70ff, 0x70ff }, +/* 0x7100 */ { false, 0x7100, 0x7100 }, +/* 0x7101 */ { false, 0x7101, 0x7101 }, +/* 0x7102 */ { false, 0x7102, 0x7102 }, +/* 0x7103 */ { false, 0x7103, 0x7103 }, +/* 0x7104 */ { false, 0x7104, 0x7104 }, +/* 0x7105 */ { false, 0x7105, 0x7105 }, +/* 0x7106 */ { false, 0x7106, 0x7106 }, +/* 0x7107 */ { false, 0x7107, 0x7107 }, +/* 0x7108 */ { false, 0x7108, 0x7108 }, +/* 0x7109 */ { false, 0x7109, 0x7109 }, +/* 0x710a */ { false, 0x710a, 0x710a }, +/* 0x710b */ { false, 0x710b, 0x710b }, +/* 0x710c */ { false, 0x710c, 0x710c }, +/* 0x710d */ { false, 0x710d, 0x710d }, +/* 0x710e */ { false, 0x710e, 0x710e }, +/* 0x710f */ { false, 0x710f, 0x710f }, +/* 0x7110 */ { false, 0x7110, 0x7110 }, +/* 0x7111 */ { false, 0x7111, 0x7111 }, +/* 0x7112 */ { false, 0x7112, 0x7112 }, +/* 0x7113 */ { false, 0x7113, 0x7113 }, +/* 0x7114 */ { false, 0x7114, 0x7114 }, +/* 0x7115 */ { false, 0x7115, 0x7115 }, +/* 0x7116 */ { false, 0x7116, 0x7116 }, +/* 0x7117 */ { false, 0x7117, 0x7117 }, +/* 0x7118 */ { false, 0x7118, 0x7118 }, +/* 0x7119 */ { false, 0x7119, 0x7119 }, +/* 0x711a */ { false, 0x711a, 0x711a }, +/* 0x711b */ { false, 0x711b, 0x711b }, +/* 0x711c */ { false, 0x711c, 0x711c }, +/* 0x711d */ { false, 0x711d, 0x711d }, +/* 0x711e */ { false, 0x711e, 0x711e }, +/* 0x711f */ { false, 0x711f, 0x711f }, +/* 0x7120 */ { false, 0x7120, 0x7120 }, +/* 0x7121 */ { false, 0x7121, 0x7121 }, +/* 0x7122 */ { false, 0x7122, 0x7122 }, +/* 0x7123 */ { false, 0x7123, 0x7123 }, +/* 0x7124 */ { false, 0x7124, 0x7124 }, +/* 0x7125 */ { false, 0x7125, 0x7125 }, +/* 0x7126 */ { false, 0x7126, 0x7126 }, +/* 0x7127 */ { false, 0x7127, 0x7127 }, +/* 0x7128 */ { false, 0x7128, 0x7128 }, +/* 0x7129 */ { false, 0x7129, 0x7129 }, +/* 0x712a */ { false, 0x712a, 0x712a }, +/* 0x712b */ { false, 0x712b, 0x712b }, +/* 0x712c */ { false, 0x712c, 0x712c }, +/* 0x712d */ { false, 0x712d, 0x712d }, +/* 0x712e */ { false, 0x712e, 0x712e }, +/* 0x712f */ { false, 0x712f, 0x712f }, +/* 0x7130 */ { false, 0x7130, 0x7130 }, +/* 0x7131 */ { false, 0x7131, 0x7131 }, +/* 0x7132 */ { false, 0x7132, 0x7132 }, +/* 0x7133 */ { false, 0x7133, 0x7133 }, +/* 0x7134 */ { false, 0x7134, 0x7134 }, +/* 0x7135 */ { false, 0x7135, 0x7135 }, +/* 0x7136 */ { false, 0x7136, 0x7136 }, +/* 0x7137 */ { false, 0x7137, 0x7137 }, +/* 0x7138 */ { false, 0x7138, 0x7138 }, +/* 0x7139 */ { false, 0x7139, 0x7139 }, +/* 0x713a */ { false, 0x713a, 0x713a }, +/* 0x713b */ { false, 0x713b, 0x713b }, +/* 0x713c */ { false, 0x713c, 0x713c }, +/* 0x713d */ { false, 0x713d, 0x713d }, +/* 0x713e */ { false, 0x713e, 0x713e }, +/* 0x713f */ { false, 0x713f, 0x713f }, +/* 0x7140 */ { false, 0x7140, 0x7140 }, +/* 0x7141 */ { false, 0x7141, 0x7141 }, +/* 0x7142 */ { false, 0x7142, 0x7142 }, +/* 0x7143 */ { false, 0x7143, 0x7143 }, +/* 0x7144 */ { false, 0x7144, 0x7144 }, +/* 0x7145 */ { false, 0x7145, 0x7145 }, +/* 0x7146 */ { false, 0x7146, 0x7146 }, +/* 0x7147 */ { false, 0x7147, 0x7147 }, +/* 0x7148 */ { false, 0x7148, 0x7148 }, +/* 0x7149 */ { false, 0x7149, 0x7149 }, +/* 0x714a */ { false, 0x714a, 0x714a }, +/* 0x714b */ { false, 0x714b, 0x714b }, +/* 0x714c */ { false, 0x714c, 0x714c }, +/* 0x714d */ { false, 0x714d, 0x714d }, +/* 0x714e */ { false, 0x714e, 0x714e }, +/* 0x714f */ { false, 0x714f, 0x714f }, +/* 0x7150 */ { false, 0x7150, 0x7150 }, +/* 0x7151 */ { false, 0x7151, 0x7151 }, +/* 0x7152 */ { false, 0x7152, 0x7152 }, +/* 0x7153 */ { false, 0x7153, 0x7153 }, +/* 0x7154 */ { false, 0x7154, 0x7154 }, +/* 0x7155 */ { false, 0x7155, 0x7155 }, +/* 0x7156 */ { false, 0x7156, 0x7156 }, +/* 0x7157 */ { false, 0x7157, 0x7157 }, +/* 0x7158 */ { false, 0x7158, 0x7158 }, +/* 0x7159 */ { false, 0x7159, 0x7159 }, +/* 0x715a */ { false, 0x715a, 0x715a }, +/* 0x715b */ { false, 0x715b, 0x715b }, +/* 0x715c */ { false, 0x715c, 0x715c }, +/* 0x715d */ { false, 0x715d, 0x715d }, +/* 0x715e */ { false, 0x715e, 0x715e }, +/* 0x715f */ { false, 0x715f, 0x715f }, +/* 0x7160 */ { false, 0x7160, 0x7160 }, +/* 0x7161 */ { false, 0x7161, 0x7161 }, +/* 0x7162 */ { false, 0x7162, 0x7162 }, +/* 0x7163 */ { false, 0x7163, 0x7163 }, +/* 0x7164 */ { false, 0x7164, 0x7164 }, +/* 0x7165 */ { false, 0x7165, 0x7165 }, +/* 0x7166 */ { false, 0x7166, 0x7166 }, +/* 0x7167 */ { false, 0x7167, 0x7167 }, +/* 0x7168 */ { false, 0x7168, 0x7168 }, +/* 0x7169 */ { false, 0x7169, 0x7169 }, +/* 0x716a */ { false, 0x716a, 0x716a }, +/* 0x716b */ { false, 0x716b, 0x716b }, +/* 0x716c */ { false, 0x716c, 0x716c }, +/* 0x716d */ { false, 0x716d, 0x716d }, +/* 0x716e */ { false, 0x716e, 0x716e }, +/* 0x716f */ { false, 0x716f, 0x716f }, +/* 0x7170 */ { false, 0x7170, 0x7170 }, +/* 0x7171 */ { false, 0x7171, 0x7171 }, +/* 0x7172 */ { false, 0x7172, 0x7172 }, +/* 0x7173 */ { false, 0x7173, 0x7173 }, +/* 0x7174 */ { false, 0x7174, 0x7174 }, +/* 0x7175 */ { false, 0x7175, 0x7175 }, +/* 0x7176 */ { false, 0x7176, 0x7176 }, +/* 0x7177 */ { false, 0x7177, 0x7177 }, +/* 0x7178 */ { false, 0x7178, 0x7178 }, +/* 0x7179 */ { false, 0x7179, 0x7179 }, +/* 0x717a */ { false, 0x717a, 0x717a }, +/* 0x717b */ { false, 0x717b, 0x717b }, +/* 0x717c */ { false, 0x717c, 0x717c }, +/* 0x717d */ { false, 0x717d, 0x717d }, +/* 0x717e */ { false, 0x717e, 0x717e }, +/* 0x717f */ { false, 0x717f, 0x717f }, +/* 0x7180 */ { false, 0x7180, 0x7180 }, +/* 0x7181 */ { false, 0x7181, 0x7181 }, +/* 0x7182 */ { false, 0x7182, 0x7182 }, +/* 0x7183 */ { false, 0x7183, 0x7183 }, +/* 0x7184 */ { false, 0x7184, 0x7184 }, +/* 0x7185 */ { false, 0x7185, 0x7185 }, +/* 0x7186 */ { false, 0x7186, 0x7186 }, +/* 0x7187 */ { false, 0x7187, 0x7187 }, +/* 0x7188 */ { false, 0x7188, 0x7188 }, +/* 0x7189 */ { false, 0x7189, 0x7189 }, +/* 0x718a */ { false, 0x718a, 0x718a }, +/* 0x718b */ { false, 0x718b, 0x718b }, +/* 0x718c */ { false, 0x718c, 0x718c }, +/* 0x718d */ { false, 0x718d, 0x718d }, +/* 0x718e */ { false, 0x718e, 0x718e }, +/* 0x718f */ { false, 0x718f, 0x718f }, +/* 0x7190 */ { false, 0x7190, 0x7190 }, +/* 0x7191 */ { false, 0x7191, 0x7191 }, +/* 0x7192 */ { false, 0x7192, 0x7192 }, +/* 0x7193 */ { false, 0x7193, 0x7193 }, +/* 0x7194 */ { false, 0x7194, 0x7194 }, +/* 0x7195 */ { false, 0x7195, 0x7195 }, +/* 0x7196 */ { false, 0x7196, 0x7196 }, +/* 0x7197 */ { false, 0x7197, 0x7197 }, +/* 0x7198 */ { false, 0x7198, 0x7198 }, +/* 0x7199 */ { false, 0x7199, 0x7199 }, +/* 0x719a */ { false, 0x719a, 0x719a }, +/* 0x719b */ { false, 0x719b, 0x719b }, +/* 0x719c */ { false, 0x719c, 0x719c }, +/* 0x719d */ { false, 0x719d, 0x719d }, +/* 0x719e */ { false, 0x719e, 0x719e }, +/* 0x719f */ { false, 0x719f, 0x719f }, +/* 0x71a0 */ { false, 0x71a0, 0x71a0 }, +/* 0x71a1 */ { false, 0x71a1, 0x71a1 }, +/* 0x71a2 */ { false, 0x71a2, 0x71a2 }, +/* 0x71a3 */ { false, 0x71a3, 0x71a3 }, +/* 0x71a4 */ { false, 0x71a4, 0x71a4 }, +/* 0x71a5 */ { false, 0x71a5, 0x71a5 }, +/* 0x71a6 */ { false, 0x71a6, 0x71a6 }, +/* 0x71a7 */ { false, 0x71a7, 0x71a7 }, +/* 0x71a8 */ { false, 0x71a8, 0x71a8 }, +/* 0x71a9 */ { false, 0x71a9, 0x71a9 }, +/* 0x71aa */ { false, 0x71aa, 0x71aa }, +/* 0x71ab */ { false, 0x71ab, 0x71ab }, +/* 0x71ac */ { false, 0x71ac, 0x71ac }, +/* 0x71ad */ { false, 0x71ad, 0x71ad }, +/* 0x71ae */ { false, 0x71ae, 0x71ae }, +/* 0x71af */ { false, 0x71af, 0x71af }, +/* 0x71b0 */ { false, 0x71b0, 0x71b0 }, +/* 0x71b1 */ { false, 0x71b1, 0x71b1 }, +/* 0x71b2 */ { false, 0x71b2, 0x71b2 }, +/* 0x71b3 */ { false, 0x71b3, 0x71b3 }, +/* 0x71b4 */ { false, 0x71b4, 0x71b4 }, +/* 0x71b5 */ { false, 0x71b5, 0x71b5 }, +/* 0x71b6 */ { false, 0x71b6, 0x71b6 }, +/* 0x71b7 */ { false, 0x71b7, 0x71b7 }, +/* 0x71b8 */ { false, 0x71b8, 0x71b8 }, +/* 0x71b9 */ { false, 0x71b9, 0x71b9 }, +/* 0x71ba */ { false, 0x71ba, 0x71ba }, +/* 0x71bb */ { false, 0x71bb, 0x71bb }, +/* 0x71bc */ { false, 0x71bc, 0x71bc }, +/* 0x71bd */ { false, 0x71bd, 0x71bd }, +/* 0x71be */ { false, 0x71be, 0x71be }, +/* 0x71bf */ { false, 0x71bf, 0x71bf }, +/* 0x71c0 */ { false, 0x71c0, 0x71c0 }, +/* 0x71c1 */ { false, 0x71c1, 0x71c1 }, +/* 0x71c2 */ { false, 0x71c2, 0x71c2 }, +/* 0x71c3 */ { false, 0x71c3, 0x71c3 }, +/* 0x71c4 */ { false, 0x71c4, 0x71c4 }, +/* 0x71c5 */ { false, 0x71c5, 0x71c5 }, +/* 0x71c6 */ { false, 0x71c6, 0x71c6 }, +/* 0x71c7 */ { false, 0x71c7, 0x71c7 }, +/* 0x71c8 */ { false, 0x71c8, 0x71c8 }, +/* 0x71c9 */ { false, 0x71c9, 0x71c9 }, +/* 0x71ca */ { false, 0x71ca, 0x71ca }, +/* 0x71cb */ { false, 0x71cb, 0x71cb }, +/* 0x71cc */ { false, 0x71cc, 0x71cc }, +/* 0x71cd */ { false, 0x71cd, 0x71cd }, +/* 0x71ce */ { false, 0x71ce, 0x71ce }, +/* 0x71cf */ { false, 0x71cf, 0x71cf }, +/* 0x71d0 */ { false, 0x71d0, 0x71d0 }, +/* 0x71d1 */ { false, 0x71d1, 0x71d1 }, +/* 0x71d2 */ { false, 0x71d2, 0x71d2 }, +/* 0x71d3 */ { false, 0x71d3, 0x71d3 }, +/* 0x71d4 */ { false, 0x71d4, 0x71d4 }, +/* 0x71d5 */ { false, 0x71d5, 0x71d5 }, +/* 0x71d6 */ { false, 0x71d6, 0x71d6 }, +/* 0x71d7 */ { false, 0x71d7, 0x71d7 }, +/* 0x71d8 */ { false, 0x71d8, 0x71d8 }, +/* 0x71d9 */ { false, 0x71d9, 0x71d9 }, +/* 0x71da */ { false, 0x71da, 0x71da }, +/* 0x71db */ { false, 0x71db, 0x71db }, +/* 0x71dc */ { false, 0x71dc, 0x71dc }, +/* 0x71dd */ { false, 0x71dd, 0x71dd }, +/* 0x71de */ { false, 0x71de, 0x71de }, +/* 0x71df */ { false, 0x71df, 0x71df }, +/* 0x71e0 */ { false, 0x71e0, 0x71e0 }, +/* 0x71e1 */ { false, 0x71e1, 0x71e1 }, +/* 0x71e2 */ { false, 0x71e2, 0x71e2 }, +/* 0x71e3 */ { false, 0x71e3, 0x71e3 }, +/* 0x71e4 */ { false, 0x71e4, 0x71e4 }, +/* 0x71e5 */ { false, 0x71e5, 0x71e5 }, +/* 0x71e6 */ { false, 0x71e6, 0x71e6 }, +/* 0x71e7 */ { false, 0x71e7, 0x71e7 }, +/* 0x71e8 */ { false, 0x71e8, 0x71e8 }, +/* 0x71e9 */ { false, 0x71e9, 0x71e9 }, +/* 0x71ea */ { false, 0x71ea, 0x71ea }, +/* 0x71eb */ { false, 0x71eb, 0x71eb }, +/* 0x71ec */ { false, 0x71ec, 0x71ec }, +/* 0x71ed */ { false, 0x71ed, 0x71ed }, +/* 0x71ee */ { false, 0x71ee, 0x71ee }, +/* 0x71ef */ { false, 0x71ef, 0x71ef }, +/* 0x71f0 */ { false, 0x71f0, 0x71f0 }, +/* 0x71f1 */ { false, 0x71f1, 0x71f1 }, +/* 0x71f2 */ { false, 0x71f2, 0x71f2 }, +/* 0x71f3 */ { false, 0x71f3, 0x71f3 }, +/* 0x71f4 */ { false, 0x71f4, 0x71f4 }, +/* 0x71f5 */ { false, 0x71f5, 0x71f5 }, +/* 0x71f6 */ { false, 0x71f6, 0x71f6 }, +/* 0x71f7 */ { false, 0x71f7, 0x71f7 }, +/* 0x71f8 */ { false, 0x71f8, 0x71f8 }, +/* 0x71f9 */ { false, 0x71f9, 0x71f9 }, +/* 0x71fa */ { false, 0x71fa, 0x71fa }, +/* 0x71fb */ { false, 0x71fb, 0x71fb }, +/* 0x71fc */ { false, 0x71fc, 0x71fc }, +/* 0x71fd */ { false, 0x71fd, 0x71fd }, +/* 0x71fe */ { false, 0x71fe, 0x71fe }, +/* 0x71ff */ { false, 0x71ff, 0x71ff }, +/* 0x7200 */ { false, 0x7200, 0x7200 }, +/* 0x7201 */ { false, 0x7201, 0x7201 }, +/* 0x7202 */ { false, 0x7202, 0x7202 }, +/* 0x7203 */ { false, 0x7203, 0x7203 }, +/* 0x7204 */ { false, 0x7204, 0x7204 }, +/* 0x7205 */ { false, 0x7205, 0x7205 }, +/* 0x7206 */ { false, 0x7206, 0x7206 }, +/* 0x7207 */ { false, 0x7207, 0x7207 }, +/* 0x7208 */ { false, 0x7208, 0x7208 }, +/* 0x7209 */ { false, 0x7209, 0x7209 }, +/* 0x720a */ { false, 0x720a, 0x720a }, +/* 0x720b */ { false, 0x720b, 0x720b }, +/* 0x720c */ { false, 0x720c, 0x720c }, +/* 0x720d */ { false, 0x720d, 0x720d }, +/* 0x720e */ { false, 0x720e, 0x720e }, +/* 0x720f */ { false, 0x720f, 0x720f }, +/* 0x7210 */ { false, 0x7210, 0x7210 }, +/* 0x7211 */ { false, 0x7211, 0x7211 }, +/* 0x7212 */ { false, 0x7212, 0x7212 }, +/* 0x7213 */ { false, 0x7213, 0x7213 }, +/* 0x7214 */ { false, 0x7214, 0x7214 }, +/* 0x7215 */ { false, 0x7215, 0x7215 }, +/* 0x7216 */ { false, 0x7216, 0x7216 }, +/* 0x7217 */ { false, 0x7217, 0x7217 }, +/* 0x7218 */ { false, 0x7218, 0x7218 }, +/* 0x7219 */ { false, 0x7219, 0x7219 }, +/* 0x721a */ { false, 0x721a, 0x721a }, +/* 0x721b */ { false, 0x721b, 0x721b }, +/* 0x721c */ { false, 0x721c, 0x721c }, +/* 0x721d */ { false, 0x721d, 0x721d }, +/* 0x721e */ { false, 0x721e, 0x721e }, +/* 0x721f */ { false, 0x721f, 0x721f }, +/* 0x7220 */ { false, 0x7220, 0x7220 }, +/* 0x7221 */ { false, 0x7221, 0x7221 }, +/* 0x7222 */ { false, 0x7222, 0x7222 }, +/* 0x7223 */ { false, 0x7223, 0x7223 }, +/* 0x7224 */ { false, 0x7224, 0x7224 }, +/* 0x7225 */ { false, 0x7225, 0x7225 }, +/* 0x7226 */ { false, 0x7226, 0x7226 }, +/* 0x7227 */ { false, 0x7227, 0x7227 }, +/* 0x7228 */ { false, 0x7228, 0x7228 }, +/* 0x7229 */ { false, 0x7229, 0x7229 }, +/* 0x722a */ { false, 0x722a, 0x722a }, +/* 0x722b */ { false, 0x722b, 0x722b }, +/* 0x722c */ { false, 0x722c, 0x722c }, +/* 0x722d */ { false, 0x722d, 0x722d }, +/* 0x722e */ { false, 0x722e, 0x722e }, +/* 0x722f */ { false, 0x722f, 0x722f }, +/* 0x7230 */ { false, 0x7230, 0x7230 }, +/* 0x7231 */ { false, 0x7231, 0x7231 }, +/* 0x7232 */ { false, 0x7232, 0x7232 }, +/* 0x7233 */ { false, 0x7233, 0x7233 }, +/* 0x7234 */ { false, 0x7234, 0x7234 }, +/* 0x7235 */ { false, 0x7235, 0x7235 }, +/* 0x7236 */ { false, 0x7236, 0x7236 }, +/* 0x7237 */ { false, 0x7237, 0x7237 }, +/* 0x7238 */ { false, 0x7238, 0x7238 }, +/* 0x7239 */ { false, 0x7239, 0x7239 }, +/* 0x723a */ { false, 0x723a, 0x723a }, +/* 0x723b */ { false, 0x723b, 0x723b }, +/* 0x723c */ { false, 0x723c, 0x723c }, +/* 0x723d */ { false, 0x723d, 0x723d }, +/* 0x723e */ { false, 0x723e, 0x723e }, +/* 0x723f */ { false, 0x723f, 0x723f }, +/* 0x7240 */ { false, 0x7240, 0x7240 }, +/* 0x7241 */ { false, 0x7241, 0x7241 }, +/* 0x7242 */ { false, 0x7242, 0x7242 }, +/* 0x7243 */ { false, 0x7243, 0x7243 }, +/* 0x7244 */ { false, 0x7244, 0x7244 }, +/* 0x7245 */ { false, 0x7245, 0x7245 }, +/* 0x7246 */ { false, 0x7246, 0x7246 }, +/* 0x7247 */ { false, 0x7247, 0x7247 }, +/* 0x7248 */ { false, 0x7248, 0x7248 }, +/* 0x7249 */ { false, 0x7249, 0x7249 }, +/* 0x724a */ { false, 0x724a, 0x724a }, +/* 0x724b */ { false, 0x724b, 0x724b }, +/* 0x724c */ { false, 0x724c, 0x724c }, +/* 0x724d */ { false, 0x724d, 0x724d }, +/* 0x724e */ { false, 0x724e, 0x724e }, +/* 0x724f */ { false, 0x724f, 0x724f }, +/* 0x7250 */ { false, 0x7250, 0x7250 }, +/* 0x7251 */ { false, 0x7251, 0x7251 }, +/* 0x7252 */ { false, 0x7252, 0x7252 }, +/* 0x7253 */ { false, 0x7253, 0x7253 }, +/* 0x7254 */ { false, 0x7254, 0x7254 }, +/* 0x7255 */ { false, 0x7255, 0x7255 }, +/* 0x7256 */ { false, 0x7256, 0x7256 }, +/* 0x7257 */ { false, 0x7257, 0x7257 }, +/* 0x7258 */ { false, 0x7258, 0x7258 }, +/* 0x7259 */ { false, 0x7259, 0x7259 }, +/* 0x725a */ { false, 0x725a, 0x725a }, +/* 0x725b */ { false, 0x725b, 0x725b }, +/* 0x725c */ { false, 0x725c, 0x725c }, +/* 0x725d */ { false, 0x725d, 0x725d }, +/* 0x725e */ { false, 0x725e, 0x725e }, +/* 0x725f */ { false, 0x725f, 0x725f }, +/* 0x7260 */ { false, 0x7260, 0x7260 }, +/* 0x7261 */ { false, 0x7261, 0x7261 }, +/* 0x7262 */ { false, 0x7262, 0x7262 }, +/* 0x7263 */ { false, 0x7263, 0x7263 }, +/* 0x7264 */ { false, 0x7264, 0x7264 }, +/* 0x7265 */ { false, 0x7265, 0x7265 }, +/* 0x7266 */ { false, 0x7266, 0x7266 }, +/* 0x7267 */ { false, 0x7267, 0x7267 }, +/* 0x7268 */ { false, 0x7268, 0x7268 }, +/* 0x7269 */ { false, 0x7269, 0x7269 }, +/* 0x726a */ { false, 0x726a, 0x726a }, +/* 0x726b */ { false, 0x726b, 0x726b }, +/* 0x726c */ { false, 0x726c, 0x726c }, +/* 0x726d */ { false, 0x726d, 0x726d }, +/* 0x726e */ { false, 0x726e, 0x726e }, +/* 0x726f */ { false, 0x726f, 0x726f }, +/* 0x7270 */ { false, 0x7270, 0x7270 }, +/* 0x7271 */ { false, 0x7271, 0x7271 }, +/* 0x7272 */ { false, 0x7272, 0x7272 }, +/* 0x7273 */ { false, 0x7273, 0x7273 }, +/* 0x7274 */ { false, 0x7274, 0x7274 }, +/* 0x7275 */ { false, 0x7275, 0x7275 }, +/* 0x7276 */ { false, 0x7276, 0x7276 }, +/* 0x7277 */ { false, 0x7277, 0x7277 }, +/* 0x7278 */ { false, 0x7278, 0x7278 }, +/* 0x7279 */ { false, 0x7279, 0x7279 }, +/* 0x727a */ { false, 0x727a, 0x727a }, +/* 0x727b */ { false, 0x727b, 0x727b }, +/* 0x727c */ { false, 0x727c, 0x727c }, +/* 0x727d */ { false, 0x727d, 0x727d }, +/* 0x727e */ { false, 0x727e, 0x727e }, +/* 0x727f */ { false, 0x727f, 0x727f }, +/* 0x7280 */ { false, 0x7280, 0x7280 }, +/* 0x7281 */ { false, 0x7281, 0x7281 }, +/* 0x7282 */ { false, 0x7282, 0x7282 }, +/* 0x7283 */ { false, 0x7283, 0x7283 }, +/* 0x7284 */ { false, 0x7284, 0x7284 }, +/* 0x7285 */ { false, 0x7285, 0x7285 }, +/* 0x7286 */ { false, 0x7286, 0x7286 }, +/* 0x7287 */ { false, 0x7287, 0x7287 }, +/* 0x7288 */ { false, 0x7288, 0x7288 }, +/* 0x7289 */ { false, 0x7289, 0x7289 }, +/* 0x728a */ { false, 0x728a, 0x728a }, +/* 0x728b */ { false, 0x728b, 0x728b }, +/* 0x728c */ { false, 0x728c, 0x728c }, +/* 0x728d */ { false, 0x728d, 0x728d }, +/* 0x728e */ { false, 0x728e, 0x728e }, +/* 0x728f */ { false, 0x728f, 0x728f }, +/* 0x7290 */ { false, 0x7290, 0x7290 }, +/* 0x7291 */ { false, 0x7291, 0x7291 }, +/* 0x7292 */ { false, 0x7292, 0x7292 }, +/* 0x7293 */ { false, 0x7293, 0x7293 }, +/* 0x7294 */ { false, 0x7294, 0x7294 }, +/* 0x7295 */ { false, 0x7295, 0x7295 }, +/* 0x7296 */ { false, 0x7296, 0x7296 }, +/* 0x7297 */ { false, 0x7297, 0x7297 }, +/* 0x7298 */ { false, 0x7298, 0x7298 }, +/* 0x7299 */ { false, 0x7299, 0x7299 }, +/* 0x729a */ { false, 0x729a, 0x729a }, +/* 0x729b */ { false, 0x729b, 0x729b }, +/* 0x729c */ { false, 0x729c, 0x729c }, +/* 0x729d */ { false, 0x729d, 0x729d }, +/* 0x729e */ { false, 0x729e, 0x729e }, +/* 0x729f */ { false, 0x729f, 0x729f }, +/* 0x72a0 */ { false, 0x72a0, 0x72a0 }, +/* 0x72a1 */ { false, 0x72a1, 0x72a1 }, +/* 0x72a2 */ { false, 0x72a2, 0x72a2 }, +/* 0x72a3 */ { false, 0x72a3, 0x72a3 }, +/* 0x72a4 */ { false, 0x72a4, 0x72a4 }, +/* 0x72a5 */ { false, 0x72a5, 0x72a5 }, +/* 0x72a6 */ { false, 0x72a6, 0x72a6 }, +/* 0x72a7 */ { false, 0x72a7, 0x72a7 }, +/* 0x72a8 */ { false, 0x72a8, 0x72a8 }, +/* 0x72a9 */ { false, 0x72a9, 0x72a9 }, +/* 0x72aa */ { false, 0x72aa, 0x72aa }, +/* 0x72ab */ { false, 0x72ab, 0x72ab }, +/* 0x72ac */ { false, 0x72ac, 0x72ac }, +/* 0x72ad */ { false, 0x72ad, 0x72ad }, +/* 0x72ae */ { false, 0x72ae, 0x72ae }, +/* 0x72af */ { false, 0x72af, 0x72af }, +/* 0x72b0 */ { false, 0x72b0, 0x72b0 }, +/* 0x72b1 */ { false, 0x72b1, 0x72b1 }, +/* 0x72b2 */ { false, 0x72b2, 0x72b2 }, +/* 0x72b3 */ { false, 0x72b3, 0x72b3 }, +/* 0x72b4 */ { false, 0x72b4, 0x72b4 }, +/* 0x72b5 */ { false, 0x72b5, 0x72b5 }, +/* 0x72b6 */ { false, 0x72b6, 0x72b6 }, +/* 0x72b7 */ { false, 0x72b7, 0x72b7 }, +/* 0x72b8 */ { false, 0x72b8, 0x72b8 }, +/* 0x72b9 */ { false, 0x72b9, 0x72b9 }, +/* 0x72ba */ { false, 0x72ba, 0x72ba }, +/* 0x72bb */ { false, 0x72bb, 0x72bb }, +/* 0x72bc */ { false, 0x72bc, 0x72bc }, +/* 0x72bd */ { false, 0x72bd, 0x72bd }, +/* 0x72be */ { false, 0x72be, 0x72be }, +/* 0x72bf */ { false, 0x72bf, 0x72bf }, +/* 0x72c0 */ { false, 0x72c0, 0x72c0 }, +/* 0x72c1 */ { false, 0x72c1, 0x72c1 }, +/* 0x72c2 */ { false, 0x72c2, 0x72c2 }, +/* 0x72c3 */ { false, 0x72c3, 0x72c3 }, +/* 0x72c4 */ { false, 0x72c4, 0x72c4 }, +/* 0x72c5 */ { false, 0x72c5, 0x72c5 }, +/* 0x72c6 */ { false, 0x72c6, 0x72c6 }, +/* 0x72c7 */ { false, 0x72c7, 0x72c7 }, +/* 0x72c8 */ { false, 0x72c8, 0x72c8 }, +/* 0x72c9 */ { false, 0x72c9, 0x72c9 }, +/* 0x72ca */ { false, 0x72ca, 0x72ca }, +/* 0x72cb */ { false, 0x72cb, 0x72cb }, +/* 0x72cc */ { false, 0x72cc, 0x72cc }, +/* 0x72cd */ { false, 0x72cd, 0x72cd }, +/* 0x72ce */ { false, 0x72ce, 0x72ce }, +/* 0x72cf */ { false, 0x72cf, 0x72cf }, +/* 0x72d0 */ { false, 0x72d0, 0x72d0 }, +/* 0x72d1 */ { false, 0x72d1, 0x72d1 }, +/* 0x72d2 */ { false, 0x72d2, 0x72d2 }, +/* 0x72d3 */ { false, 0x72d3, 0x72d3 }, +/* 0x72d4 */ { false, 0x72d4, 0x72d4 }, +/* 0x72d5 */ { false, 0x72d5, 0x72d5 }, +/* 0x72d6 */ { false, 0x72d6, 0x72d6 }, +/* 0x72d7 */ { false, 0x72d7, 0x72d7 }, +/* 0x72d8 */ { false, 0x72d8, 0x72d8 }, +/* 0x72d9 */ { false, 0x72d9, 0x72d9 }, +/* 0x72da */ { false, 0x72da, 0x72da }, +/* 0x72db */ { false, 0x72db, 0x72db }, +/* 0x72dc */ { false, 0x72dc, 0x72dc }, +/* 0x72dd */ { false, 0x72dd, 0x72dd }, +/* 0x72de */ { false, 0x72de, 0x72de }, +/* 0x72df */ { false, 0x72df, 0x72df }, +/* 0x72e0 */ { false, 0x72e0, 0x72e0 }, +/* 0x72e1 */ { false, 0x72e1, 0x72e1 }, +/* 0x72e2 */ { false, 0x72e2, 0x72e2 }, +/* 0x72e3 */ { false, 0x72e3, 0x72e3 }, +/* 0x72e4 */ { false, 0x72e4, 0x72e4 }, +/* 0x72e5 */ { false, 0x72e5, 0x72e5 }, +/* 0x72e6 */ { false, 0x72e6, 0x72e6 }, +/* 0x72e7 */ { false, 0x72e7, 0x72e7 }, +/* 0x72e8 */ { false, 0x72e8, 0x72e8 }, +/* 0x72e9 */ { false, 0x72e9, 0x72e9 }, +/* 0x72ea */ { false, 0x72ea, 0x72ea }, +/* 0x72eb */ { false, 0x72eb, 0x72eb }, +/* 0x72ec */ { false, 0x72ec, 0x72ec }, +/* 0x72ed */ { false, 0x72ed, 0x72ed }, +/* 0x72ee */ { false, 0x72ee, 0x72ee }, +/* 0x72ef */ { false, 0x72ef, 0x72ef }, +/* 0x72f0 */ { false, 0x72f0, 0x72f0 }, +/* 0x72f1 */ { false, 0x72f1, 0x72f1 }, +/* 0x72f2 */ { false, 0x72f2, 0x72f2 }, +/* 0x72f3 */ { false, 0x72f3, 0x72f3 }, +/* 0x72f4 */ { false, 0x72f4, 0x72f4 }, +/* 0x72f5 */ { false, 0x72f5, 0x72f5 }, +/* 0x72f6 */ { false, 0x72f6, 0x72f6 }, +/* 0x72f7 */ { false, 0x72f7, 0x72f7 }, +/* 0x72f8 */ { false, 0x72f8, 0x72f8 }, +/* 0x72f9 */ { false, 0x72f9, 0x72f9 }, +/* 0x72fa */ { false, 0x72fa, 0x72fa }, +/* 0x72fb */ { false, 0x72fb, 0x72fb }, +/* 0x72fc */ { false, 0x72fc, 0x72fc }, +/* 0x72fd */ { false, 0x72fd, 0x72fd }, +/* 0x72fe */ { false, 0x72fe, 0x72fe }, +/* 0x72ff */ { false, 0x72ff, 0x72ff }, +/* 0x7300 */ { false, 0x7300, 0x7300 }, +/* 0x7301 */ { false, 0x7301, 0x7301 }, +/* 0x7302 */ { false, 0x7302, 0x7302 }, +/* 0x7303 */ { false, 0x7303, 0x7303 }, +/* 0x7304 */ { false, 0x7304, 0x7304 }, +/* 0x7305 */ { false, 0x7305, 0x7305 }, +/* 0x7306 */ { false, 0x7306, 0x7306 }, +/* 0x7307 */ { false, 0x7307, 0x7307 }, +/* 0x7308 */ { false, 0x7308, 0x7308 }, +/* 0x7309 */ { false, 0x7309, 0x7309 }, +/* 0x730a */ { false, 0x730a, 0x730a }, +/* 0x730b */ { false, 0x730b, 0x730b }, +/* 0x730c */ { false, 0x730c, 0x730c }, +/* 0x730d */ { false, 0x730d, 0x730d }, +/* 0x730e */ { false, 0x730e, 0x730e }, +/* 0x730f */ { false, 0x730f, 0x730f }, +/* 0x7310 */ { false, 0x7310, 0x7310 }, +/* 0x7311 */ { false, 0x7311, 0x7311 }, +/* 0x7312 */ { false, 0x7312, 0x7312 }, +/* 0x7313 */ { false, 0x7313, 0x7313 }, +/* 0x7314 */ { false, 0x7314, 0x7314 }, +/* 0x7315 */ { false, 0x7315, 0x7315 }, +/* 0x7316 */ { false, 0x7316, 0x7316 }, +/* 0x7317 */ { false, 0x7317, 0x7317 }, +/* 0x7318 */ { false, 0x7318, 0x7318 }, +/* 0x7319 */ { false, 0x7319, 0x7319 }, +/* 0x731a */ { false, 0x731a, 0x731a }, +/* 0x731b */ { false, 0x731b, 0x731b }, +/* 0x731c */ { false, 0x731c, 0x731c }, +/* 0x731d */ { false, 0x731d, 0x731d }, +/* 0x731e */ { false, 0x731e, 0x731e }, +/* 0x731f */ { false, 0x731f, 0x731f }, +/* 0x7320 */ { false, 0x7320, 0x7320 }, +/* 0x7321 */ { false, 0x7321, 0x7321 }, +/* 0x7322 */ { false, 0x7322, 0x7322 }, +/* 0x7323 */ { false, 0x7323, 0x7323 }, +/* 0x7324 */ { false, 0x7324, 0x7324 }, +/* 0x7325 */ { false, 0x7325, 0x7325 }, +/* 0x7326 */ { false, 0x7326, 0x7326 }, +/* 0x7327 */ { false, 0x7327, 0x7327 }, +/* 0x7328 */ { false, 0x7328, 0x7328 }, +/* 0x7329 */ { false, 0x7329, 0x7329 }, +/* 0x732a */ { false, 0x732a, 0x732a }, +/* 0x732b */ { false, 0x732b, 0x732b }, +/* 0x732c */ { false, 0x732c, 0x732c }, +/* 0x732d */ { false, 0x732d, 0x732d }, +/* 0x732e */ { false, 0x732e, 0x732e }, +/* 0x732f */ { false, 0x732f, 0x732f }, +/* 0x7330 */ { false, 0x7330, 0x7330 }, +/* 0x7331 */ { false, 0x7331, 0x7331 }, +/* 0x7332 */ { false, 0x7332, 0x7332 }, +/* 0x7333 */ { false, 0x7333, 0x7333 }, +/* 0x7334 */ { false, 0x7334, 0x7334 }, +/* 0x7335 */ { false, 0x7335, 0x7335 }, +/* 0x7336 */ { false, 0x7336, 0x7336 }, +/* 0x7337 */ { false, 0x7337, 0x7337 }, +/* 0x7338 */ { false, 0x7338, 0x7338 }, +/* 0x7339 */ { false, 0x7339, 0x7339 }, +/* 0x733a */ { false, 0x733a, 0x733a }, +/* 0x733b */ { false, 0x733b, 0x733b }, +/* 0x733c */ { false, 0x733c, 0x733c }, +/* 0x733d */ { false, 0x733d, 0x733d }, +/* 0x733e */ { false, 0x733e, 0x733e }, +/* 0x733f */ { false, 0x733f, 0x733f }, +/* 0x7340 */ { false, 0x7340, 0x7340 }, +/* 0x7341 */ { false, 0x7341, 0x7341 }, +/* 0x7342 */ { false, 0x7342, 0x7342 }, +/* 0x7343 */ { false, 0x7343, 0x7343 }, +/* 0x7344 */ { false, 0x7344, 0x7344 }, +/* 0x7345 */ { false, 0x7345, 0x7345 }, +/* 0x7346 */ { false, 0x7346, 0x7346 }, +/* 0x7347 */ { false, 0x7347, 0x7347 }, +/* 0x7348 */ { false, 0x7348, 0x7348 }, +/* 0x7349 */ { false, 0x7349, 0x7349 }, +/* 0x734a */ { false, 0x734a, 0x734a }, +/* 0x734b */ { false, 0x734b, 0x734b }, +/* 0x734c */ { false, 0x734c, 0x734c }, +/* 0x734d */ { false, 0x734d, 0x734d }, +/* 0x734e */ { false, 0x734e, 0x734e }, +/* 0x734f */ { false, 0x734f, 0x734f }, +/* 0x7350 */ { false, 0x7350, 0x7350 }, +/* 0x7351 */ { false, 0x7351, 0x7351 }, +/* 0x7352 */ { false, 0x7352, 0x7352 }, +/* 0x7353 */ { false, 0x7353, 0x7353 }, +/* 0x7354 */ { false, 0x7354, 0x7354 }, +/* 0x7355 */ { false, 0x7355, 0x7355 }, +/* 0x7356 */ { false, 0x7356, 0x7356 }, +/* 0x7357 */ { false, 0x7357, 0x7357 }, +/* 0x7358 */ { false, 0x7358, 0x7358 }, +/* 0x7359 */ { false, 0x7359, 0x7359 }, +/* 0x735a */ { false, 0x735a, 0x735a }, +/* 0x735b */ { false, 0x735b, 0x735b }, +/* 0x735c */ { false, 0x735c, 0x735c }, +/* 0x735d */ { false, 0x735d, 0x735d }, +/* 0x735e */ { false, 0x735e, 0x735e }, +/* 0x735f */ { false, 0x735f, 0x735f }, +/* 0x7360 */ { false, 0x7360, 0x7360 }, +/* 0x7361 */ { false, 0x7361, 0x7361 }, +/* 0x7362 */ { false, 0x7362, 0x7362 }, +/* 0x7363 */ { false, 0x7363, 0x7363 }, +/* 0x7364 */ { false, 0x7364, 0x7364 }, +/* 0x7365 */ { false, 0x7365, 0x7365 }, +/* 0x7366 */ { false, 0x7366, 0x7366 }, +/* 0x7367 */ { false, 0x7367, 0x7367 }, +/* 0x7368 */ { false, 0x7368, 0x7368 }, +/* 0x7369 */ { false, 0x7369, 0x7369 }, +/* 0x736a */ { false, 0x736a, 0x736a }, +/* 0x736b */ { false, 0x736b, 0x736b }, +/* 0x736c */ { false, 0x736c, 0x736c }, +/* 0x736d */ { false, 0x736d, 0x736d }, +/* 0x736e */ { false, 0x736e, 0x736e }, +/* 0x736f */ { false, 0x736f, 0x736f }, +/* 0x7370 */ { false, 0x7370, 0x7370 }, +/* 0x7371 */ { false, 0x7371, 0x7371 }, +/* 0x7372 */ { false, 0x7372, 0x7372 }, +/* 0x7373 */ { false, 0x7373, 0x7373 }, +/* 0x7374 */ { false, 0x7374, 0x7374 }, +/* 0x7375 */ { false, 0x7375, 0x7375 }, +/* 0x7376 */ { false, 0x7376, 0x7376 }, +/* 0x7377 */ { false, 0x7377, 0x7377 }, +/* 0x7378 */ { false, 0x7378, 0x7378 }, +/* 0x7379 */ { false, 0x7379, 0x7379 }, +/* 0x737a */ { false, 0x737a, 0x737a }, +/* 0x737b */ { false, 0x737b, 0x737b }, +/* 0x737c */ { false, 0x737c, 0x737c }, +/* 0x737d */ { false, 0x737d, 0x737d }, +/* 0x737e */ { false, 0x737e, 0x737e }, +/* 0x737f */ { false, 0x737f, 0x737f }, +/* 0x7380 */ { false, 0x7380, 0x7380 }, +/* 0x7381 */ { false, 0x7381, 0x7381 }, +/* 0x7382 */ { false, 0x7382, 0x7382 }, +/* 0x7383 */ { false, 0x7383, 0x7383 }, +/* 0x7384 */ { false, 0x7384, 0x7384 }, +/* 0x7385 */ { false, 0x7385, 0x7385 }, +/* 0x7386 */ { false, 0x7386, 0x7386 }, +/* 0x7387 */ { false, 0x7387, 0x7387 }, +/* 0x7388 */ { false, 0x7388, 0x7388 }, +/* 0x7389 */ { false, 0x7389, 0x7389 }, +/* 0x738a */ { false, 0x738a, 0x738a }, +/* 0x738b */ { false, 0x738b, 0x738b }, +/* 0x738c */ { false, 0x738c, 0x738c }, +/* 0x738d */ { false, 0x738d, 0x738d }, +/* 0x738e */ { false, 0x738e, 0x738e }, +/* 0x738f */ { false, 0x738f, 0x738f }, +/* 0x7390 */ { false, 0x7390, 0x7390 }, +/* 0x7391 */ { false, 0x7391, 0x7391 }, +/* 0x7392 */ { false, 0x7392, 0x7392 }, +/* 0x7393 */ { false, 0x7393, 0x7393 }, +/* 0x7394 */ { false, 0x7394, 0x7394 }, +/* 0x7395 */ { false, 0x7395, 0x7395 }, +/* 0x7396 */ { false, 0x7396, 0x7396 }, +/* 0x7397 */ { false, 0x7397, 0x7397 }, +/* 0x7398 */ { false, 0x7398, 0x7398 }, +/* 0x7399 */ { false, 0x7399, 0x7399 }, +/* 0x739a */ { false, 0x739a, 0x739a }, +/* 0x739b */ { false, 0x739b, 0x739b }, +/* 0x739c */ { false, 0x739c, 0x739c }, +/* 0x739d */ { false, 0x739d, 0x739d }, +/* 0x739e */ { false, 0x739e, 0x739e }, +/* 0x739f */ { false, 0x739f, 0x739f }, +/* 0x73a0 */ { false, 0x73a0, 0x73a0 }, +/* 0x73a1 */ { false, 0x73a1, 0x73a1 }, +/* 0x73a2 */ { false, 0x73a2, 0x73a2 }, +/* 0x73a3 */ { false, 0x73a3, 0x73a3 }, +/* 0x73a4 */ { false, 0x73a4, 0x73a4 }, +/* 0x73a5 */ { false, 0x73a5, 0x73a5 }, +/* 0x73a6 */ { false, 0x73a6, 0x73a6 }, +/* 0x73a7 */ { false, 0x73a7, 0x73a7 }, +/* 0x73a8 */ { false, 0x73a8, 0x73a8 }, +/* 0x73a9 */ { false, 0x73a9, 0x73a9 }, +/* 0x73aa */ { false, 0x73aa, 0x73aa }, +/* 0x73ab */ { false, 0x73ab, 0x73ab }, +/* 0x73ac */ { false, 0x73ac, 0x73ac }, +/* 0x73ad */ { false, 0x73ad, 0x73ad }, +/* 0x73ae */ { false, 0x73ae, 0x73ae }, +/* 0x73af */ { false, 0x73af, 0x73af }, +/* 0x73b0 */ { false, 0x73b0, 0x73b0 }, +/* 0x73b1 */ { false, 0x73b1, 0x73b1 }, +/* 0x73b2 */ { false, 0x73b2, 0x73b2 }, +/* 0x73b3 */ { false, 0x73b3, 0x73b3 }, +/* 0x73b4 */ { false, 0x73b4, 0x73b4 }, +/* 0x73b5 */ { false, 0x73b5, 0x73b5 }, +/* 0x73b6 */ { false, 0x73b6, 0x73b6 }, +/* 0x73b7 */ { false, 0x73b7, 0x73b7 }, +/* 0x73b8 */ { false, 0x73b8, 0x73b8 }, +/* 0x73b9 */ { false, 0x73b9, 0x73b9 }, +/* 0x73ba */ { false, 0x73ba, 0x73ba }, +/* 0x73bb */ { false, 0x73bb, 0x73bb }, +/* 0x73bc */ { false, 0x73bc, 0x73bc }, +/* 0x73bd */ { false, 0x73bd, 0x73bd }, +/* 0x73be */ { false, 0x73be, 0x73be }, +/* 0x73bf */ { false, 0x73bf, 0x73bf }, +/* 0x73c0 */ { false, 0x73c0, 0x73c0 }, +/* 0x73c1 */ { false, 0x73c1, 0x73c1 }, +/* 0x73c2 */ { false, 0x73c2, 0x73c2 }, +/* 0x73c3 */ { false, 0x73c3, 0x73c3 }, +/* 0x73c4 */ { false, 0x73c4, 0x73c4 }, +/* 0x73c5 */ { false, 0x73c5, 0x73c5 }, +/* 0x73c6 */ { false, 0x73c6, 0x73c6 }, +/* 0x73c7 */ { false, 0x73c7, 0x73c7 }, +/* 0x73c8 */ { false, 0x73c8, 0x73c8 }, +/* 0x73c9 */ { false, 0x73c9, 0x73c9 }, +/* 0x73ca */ { false, 0x73ca, 0x73ca }, +/* 0x73cb */ { false, 0x73cb, 0x73cb }, +/* 0x73cc */ { false, 0x73cc, 0x73cc }, +/* 0x73cd */ { false, 0x73cd, 0x73cd }, +/* 0x73ce */ { false, 0x73ce, 0x73ce }, +/* 0x73cf */ { false, 0x73cf, 0x73cf }, +/* 0x73d0 */ { false, 0x73d0, 0x73d0 }, +/* 0x73d1 */ { false, 0x73d1, 0x73d1 }, +/* 0x73d2 */ { false, 0x73d2, 0x73d2 }, +/* 0x73d3 */ { false, 0x73d3, 0x73d3 }, +/* 0x73d4 */ { false, 0x73d4, 0x73d4 }, +/* 0x73d5 */ { false, 0x73d5, 0x73d5 }, +/* 0x73d6 */ { false, 0x73d6, 0x73d6 }, +/* 0x73d7 */ { false, 0x73d7, 0x73d7 }, +/* 0x73d8 */ { false, 0x73d8, 0x73d8 }, +/* 0x73d9 */ { false, 0x73d9, 0x73d9 }, +/* 0x73da */ { false, 0x73da, 0x73da }, +/* 0x73db */ { false, 0x73db, 0x73db }, +/* 0x73dc */ { false, 0x73dc, 0x73dc }, +/* 0x73dd */ { false, 0x73dd, 0x73dd }, +/* 0x73de */ { false, 0x73de, 0x73de }, +/* 0x73df */ { false, 0x73df, 0x73df }, +/* 0x73e0 */ { false, 0x73e0, 0x73e0 }, +/* 0x73e1 */ { false, 0x73e1, 0x73e1 }, +/* 0x73e2 */ { false, 0x73e2, 0x73e2 }, +/* 0x73e3 */ { false, 0x73e3, 0x73e3 }, +/* 0x73e4 */ { false, 0x73e4, 0x73e4 }, +/* 0x73e5 */ { false, 0x73e5, 0x73e5 }, +/* 0x73e6 */ { false, 0x73e6, 0x73e6 }, +/* 0x73e7 */ { false, 0x73e7, 0x73e7 }, +/* 0x73e8 */ { false, 0x73e8, 0x73e8 }, +/* 0x73e9 */ { false, 0x73e9, 0x73e9 }, +/* 0x73ea */ { false, 0x73ea, 0x73ea }, +/* 0x73eb */ { false, 0x73eb, 0x73eb }, +/* 0x73ec */ { false, 0x73ec, 0x73ec }, +/* 0x73ed */ { false, 0x73ed, 0x73ed }, +/* 0x73ee */ { false, 0x73ee, 0x73ee }, +/* 0x73ef */ { false, 0x73ef, 0x73ef }, +/* 0x73f0 */ { false, 0x73f0, 0x73f0 }, +/* 0x73f1 */ { false, 0x73f1, 0x73f1 }, +/* 0x73f2 */ { false, 0x73f2, 0x73f2 }, +/* 0x73f3 */ { false, 0x73f3, 0x73f3 }, +/* 0x73f4 */ { false, 0x73f4, 0x73f4 }, +/* 0x73f5 */ { false, 0x73f5, 0x73f5 }, +/* 0x73f6 */ { false, 0x73f6, 0x73f6 }, +/* 0x73f7 */ { false, 0x73f7, 0x73f7 }, +/* 0x73f8 */ { false, 0x73f8, 0x73f8 }, +/* 0x73f9 */ { false, 0x73f9, 0x73f9 }, +/* 0x73fa */ { false, 0x73fa, 0x73fa }, +/* 0x73fb */ { false, 0x73fb, 0x73fb }, +/* 0x73fc */ { false, 0x73fc, 0x73fc }, +/* 0x73fd */ { false, 0x73fd, 0x73fd }, +/* 0x73fe */ { false, 0x73fe, 0x73fe }, +/* 0x73ff */ { false, 0x73ff, 0x73ff }, +/* 0x7400 */ { false, 0x7400, 0x7400 }, +/* 0x7401 */ { false, 0x7401, 0x7401 }, +/* 0x7402 */ { false, 0x7402, 0x7402 }, +/* 0x7403 */ { false, 0x7403, 0x7403 }, +/* 0x7404 */ { false, 0x7404, 0x7404 }, +/* 0x7405 */ { false, 0x7405, 0x7405 }, +/* 0x7406 */ { false, 0x7406, 0x7406 }, +/* 0x7407 */ { false, 0x7407, 0x7407 }, +/* 0x7408 */ { false, 0x7408, 0x7408 }, +/* 0x7409 */ { false, 0x7409, 0x7409 }, +/* 0x740a */ { false, 0x740a, 0x740a }, +/* 0x740b */ { false, 0x740b, 0x740b }, +/* 0x740c */ { false, 0x740c, 0x740c }, +/* 0x740d */ { false, 0x740d, 0x740d }, +/* 0x740e */ { false, 0x740e, 0x740e }, +/* 0x740f */ { false, 0x740f, 0x740f }, +/* 0x7410 */ { false, 0x7410, 0x7410 }, +/* 0x7411 */ { false, 0x7411, 0x7411 }, +/* 0x7412 */ { false, 0x7412, 0x7412 }, +/* 0x7413 */ { false, 0x7413, 0x7413 }, +/* 0x7414 */ { false, 0x7414, 0x7414 }, +/* 0x7415 */ { false, 0x7415, 0x7415 }, +/* 0x7416 */ { false, 0x7416, 0x7416 }, +/* 0x7417 */ { false, 0x7417, 0x7417 }, +/* 0x7418 */ { false, 0x7418, 0x7418 }, +/* 0x7419 */ { false, 0x7419, 0x7419 }, +/* 0x741a */ { false, 0x741a, 0x741a }, +/* 0x741b */ { false, 0x741b, 0x741b }, +/* 0x741c */ { false, 0x741c, 0x741c }, +/* 0x741d */ { false, 0x741d, 0x741d }, +/* 0x741e */ { false, 0x741e, 0x741e }, +/* 0x741f */ { false, 0x741f, 0x741f }, +/* 0x7420 */ { false, 0x7420, 0x7420 }, +/* 0x7421 */ { false, 0x7421, 0x7421 }, +/* 0x7422 */ { false, 0x7422, 0x7422 }, +/* 0x7423 */ { false, 0x7423, 0x7423 }, +/* 0x7424 */ { false, 0x7424, 0x7424 }, +/* 0x7425 */ { false, 0x7425, 0x7425 }, +/* 0x7426 */ { false, 0x7426, 0x7426 }, +/* 0x7427 */ { false, 0x7427, 0x7427 }, +/* 0x7428 */ { false, 0x7428, 0x7428 }, +/* 0x7429 */ { false, 0x7429, 0x7429 }, +/* 0x742a */ { false, 0x742a, 0x742a }, +/* 0x742b */ { false, 0x742b, 0x742b }, +/* 0x742c */ { false, 0x742c, 0x742c }, +/* 0x742d */ { false, 0x742d, 0x742d }, +/* 0x742e */ { false, 0x742e, 0x742e }, +/* 0x742f */ { false, 0x742f, 0x742f }, +/* 0x7430 */ { false, 0x7430, 0x7430 }, +/* 0x7431 */ { false, 0x7431, 0x7431 }, +/* 0x7432 */ { false, 0x7432, 0x7432 }, +/* 0x7433 */ { false, 0x7433, 0x7433 }, +/* 0x7434 */ { false, 0x7434, 0x7434 }, +/* 0x7435 */ { false, 0x7435, 0x7435 }, +/* 0x7436 */ { false, 0x7436, 0x7436 }, +/* 0x7437 */ { false, 0x7437, 0x7437 }, +/* 0x7438 */ { false, 0x7438, 0x7438 }, +/* 0x7439 */ { false, 0x7439, 0x7439 }, +/* 0x743a */ { false, 0x743a, 0x743a }, +/* 0x743b */ { false, 0x743b, 0x743b }, +/* 0x743c */ { false, 0x743c, 0x743c }, +/* 0x743d */ { false, 0x743d, 0x743d }, +/* 0x743e */ { false, 0x743e, 0x743e }, +/* 0x743f */ { false, 0x743f, 0x743f }, +/* 0x7440 */ { false, 0x7440, 0x7440 }, +/* 0x7441 */ { false, 0x7441, 0x7441 }, +/* 0x7442 */ { false, 0x7442, 0x7442 }, +/* 0x7443 */ { false, 0x7443, 0x7443 }, +/* 0x7444 */ { false, 0x7444, 0x7444 }, +/* 0x7445 */ { false, 0x7445, 0x7445 }, +/* 0x7446 */ { false, 0x7446, 0x7446 }, +/* 0x7447 */ { false, 0x7447, 0x7447 }, +/* 0x7448 */ { false, 0x7448, 0x7448 }, +/* 0x7449 */ { false, 0x7449, 0x7449 }, +/* 0x744a */ { false, 0x744a, 0x744a }, +/* 0x744b */ { false, 0x744b, 0x744b }, +/* 0x744c */ { false, 0x744c, 0x744c }, +/* 0x744d */ { false, 0x744d, 0x744d }, +/* 0x744e */ { false, 0x744e, 0x744e }, +/* 0x744f */ { false, 0x744f, 0x744f }, +/* 0x7450 */ { false, 0x7450, 0x7450 }, +/* 0x7451 */ { false, 0x7451, 0x7451 }, +/* 0x7452 */ { false, 0x7452, 0x7452 }, +/* 0x7453 */ { false, 0x7453, 0x7453 }, +/* 0x7454 */ { false, 0x7454, 0x7454 }, +/* 0x7455 */ { false, 0x7455, 0x7455 }, +/* 0x7456 */ { false, 0x7456, 0x7456 }, +/* 0x7457 */ { false, 0x7457, 0x7457 }, +/* 0x7458 */ { false, 0x7458, 0x7458 }, +/* 0x7459 */ { false, 0x7459, 0x7459 }, +/* 0x745a */ { false, 0x745a, 0x745a }, +/* 0x745b */ { false, 0x745b, 0x745b }, +/* 0x745c */ { false, 0x745c, 0x745c }, +/* 0x745d */ { false, 0x745d, 0x745d }, +/* 0x745e */ { false, 0x745e, 0x745e }, +/* 0x745f */ { false, 0x745f, 0x745f }, +/* 0x7460 */ { false, 0x7460, 0x7460 }, +/* 0x7461 */ { false, 0x7461, 0x7461 }, +/* 0x7462 */ { false, 0x7462, 0x7462 }, +/* 0x7463 */ { false, 0x7463, 0x7463 }, +/* 0x7464 */ { false, 0x7464, 0x7464 }, +/* 0x7465 */ { false, 0x7465, 0x7465 }, +/* 0x7466 */ { false, 0x7466, 0x7466 }, +/* 0x7467 */ { false, 0x7467, 0x7467 }, +/* 0x7468 */ { false, 0x7468, 0x7468 }, +/* 0x7469 */ { false, 0x7469, 0x7469 }, +/* 0x746a */ { false, 0x746a, 0x746a }, +/* 0x746b */ { false, 0x746b, 0x746b }, +/* 0x746c */ { false, 0x746c, 0x746c }, +/* 0x746d */ { false, 0x746d, 0x746d }, +/* 0x746e */ { false, 0x746e, 0x746e }, +/* 0x746f */ { false, 0x746f, 0x746f }, +/* 0x7470 */ { false, 0x7470, 0x7470 }, +/* 0x7471 */ { false, 0x7471, 0x7471 }, +/* 0x7472 */ { false, 0x7472, 0x7472 }, +/* 0x7473 */ { false, 0x7473, 0x7473 }, +/* 0x7474 */ { false, 0x7474, 0x7474 }, +/* 0x7475 */ { false, 0x7475, 0x7475 }, +/* 0x7476 */ { false, 0x7476, 0x7476 }, +/* 0x7477 */ { false, 0x7477, 0x7477 }, +/* 0x7478 */ { false, 0x7478, 0x7478 }, +/* 0x7479 */ { false, 0x7479, 0x7479 }, +/* 0x747a */ { false, 0x747a, 0x747a }, +/* 0x747b */ { false, 0x747b, 0x747b }, +/* 0x747c */ { false, 0x747c, 0x747c }, +/* 0x747d */ { false, 0x747d, 0x747d }, +/* 0x747e */ { false, 0x747e, 0x747e }, +/* 0x747f */ { false, 0x747f, 0x747f }, +/* 0x7480 */ { false, 0x7480, 0x7480 }, +/* 0x7481 */ { false, 0x7481, 0x7481 }, +/* 0x7482 */ { false, 0x7482, 0x7482 }, +/* 0x7483 */ { false, 0x7483, 0x7483 }, +/* 0x7484 */ { false, 0x7484, 0x7484 }, +/* 0x7485 */ { false, 0x7485, 0x7485 }, +/* 0x7486 */ { false, 0x7486, 0x7486 }, +/* 0x7487 */ { false, 0x7487, 0x7487 }, +/* 0x7488 */ { false, 0x7488, 0x7488 }, +/* 0x7489 */ { false, 0x7489, 0x7489 }, +/* 0x748a */ { false, 0x748a, 0x748a }, +/* 0x748b */ { false, 0x748b, 0x748b }, +/* 0x748c */ { false, 0x748c, 0x748c }, +/* 0x748d */ { false, 0x748d, 0x748d }, +/* 0x748e */ { false, 0x748e, 0x748e }, +/* 0x748f */ { false, 0x748f, 0x748f }, +/* 0x7490 */ { false, 0x7490, 0x7490 }, +/* 0x7491 */ { false, 0x7491, 0x7491 }, +/* 0x7492 */ { false, 0x7492, 0x7492 }, +/* 0x7493 */ { false, 0x7493, 0x7493 }, +/* 0x7494 */ { false, 0x7494, 0x7494 }, +/* 0x7495 */ { false, 0x7495, 0x7495 }, +/* 0x7496 */ { false, 0x7496, 0x7496 }, +/* 0x7497 */ { false, 0x7497, 0x7497 }, +/* 0x7498 */ { false, 0x7498, 0x7498 }, +/* 0x7499 */ { false, 0x7499, 0x7499 }, +/* 0x749a */ { false, 0x749a, 0x749a }, +/* 0x749b */ { false, 0x749b, 0x749b }, +/* 0x749c */ { false, 0x749c, 0x749c }, +/* 0x749d */ { false, 0x749d, 0x749d }, +/* 0x749e */ { false, 0x749e, 0x749e }, +/* 0x749f */ { false, 0x749f, 0x749f }, +/* 0x74a0 */ { false, 0x74a0, 0x74a0 }, +/* 0x74a1 */ { false, 0x74a1, 0x74a1 }, +/* 0x74a2 */ { false, 0x74a2, 0x74a2 }, +/* 0x74a3 */ { false, 0x74a3, 0x74a3 }, +/* 0x74a4 */ { false, 0x74a4, 0x74a4 }, +/* 0x74a5 */ { false, 0x74a5, 0x74a5 }, +/* 0x74a6 */ { false, 0x74a6, 0x74a6 }, +/* 0x74a7 */ { false, 0x74a7, 0x74a7 }, +/* 0x74a8 */ { false, 0x74a8, 0x74a8 }, +/* 0x74a9 */ { false, 0x74a9, 0x74a9 }, +/* 0x74aa */ { false, 0x74aa, 0x74aa }, +/* 0x74ab */ { false, 0x74ab, 0x74ab }, +/* 0x74ac */ { false, 0x74ac, 0x74ac }, +/* 0x74ad */ { false, 0x74ad, 0x74ad }, +/* 0x74ae */ { false, 0x74ae, 0x74ae }, +/* 0x74af */ { false, 0x74af, 0x74af }, +/* 0x74b0 */ { false, 0x74b0, 0x74b0 }, +/* 0x74b1 */ { false, 0x74b1, 0x74b1 }, +/* 0x74b2 */ { false, 0x74b2, 0x74b2 }, +/* 0x74b3 */ { false, 0x74b3, 0x74b3 }, +/* 0x74b4 */ { false, 0x74b4, 0x74b4 }, +/* 0x74b5 */ { false, 0x74b5, 0x74b5 }, +/* 0x74b6 */ { false, 0x74b6, 0x74b6 }, +/* 0x74b7 */ { false, 0x74b7, 0x74b7 }, +/* 0x74b8 */ { false, 0x74b8, 0x74b8 }, +/* 0x74b9 */ { false, 0x74b9, 0x74b9 }, +/* 0x74ba */ { false, 0x74ba, 0x74ba }, +/* 0x74bb */ { false, 0x74bb, 0x74bb }, +/* 0x74bc */ { false, 0x74bc, 0x74bc }, +/* 0x74bd */ { false, 0x74bd, 0x74bd }, +/* 0x74be */ { false, 0x74be, 0x74be }, +/* 0x74bf */ { false, 0x74bf, 0x74bf }, +/* 0x74c0 */ { false, 0x74c0, 0x74c0 }, +/* 0x74c1 */ { false, 0x74c1, 0x74c1 }, +/* 0x74c2 */ { false, 0x74c2, 0x74c2 }, +/* 0x74c3 */ { false, 0x74c3, 0x74c3 }, +/* 0x74c4 */ { false, 0x74c4, 0x74c4 }, +/* 0x74c5 */ { false, 0x74c5, 0x74c5 }, +/* 0x74c6 */ { false, 0x74c6, 0x74c6 }, +/* 0x74c7 */ { false, 0x74c7, 0x74c7 }, +/* 0x74c8 */ { false, 0x74c8, 0x74c8 }, +/* 0x74c9 */ { false, 0x74c9, 0x74c9 }, +/* 0x74ca */ { false, 0x74ca, 0x74ca }, +/* 0x74cb */ { false, 0x74cb, 0x74cb }, +/* 0x74cc */ { false, 0x74cc, 0x74cc }, +/* 0x74cd */ { false, 0x74cd, 0x74cd }, +/* 0x74ce */ { false, 0x74ce, 0x74ce }, +/* 0x74cf */ { false, 0x74cf, 0x74cf }, +/* 0x74d0 */ { false, 0x74d0, 0x74d0 }, +/* 0x74d1 */ { false, 0x74d1, 0x74d1 }, +/* 0x74d2 */ { false, 0x74d2, 0x74d2 }, +/* 0x74d3 */ { false, 0x74d3, 0x74d3 }, +/* 0x74d4 */ { false, 0x74d4, 0x74d4 }, +/* 0x74d5 */ { false, 0x74d5, 0x74d5 }, +/* 0x74d6 */ { false, 0x74d6, 0x74d6 }, +/* 0x74d7 */ { false, 0x74d7, 0x74d7 }, +/* 0x74d8 */ { false, 0x74d8, 0x74d8 }, +/* 0x74d9 */ { false, 0x74d9, 0x74d9 }, +/* 0x74da */ { false, 0x74da, 0x74da }, +/* 0x74db */ { false, 0x74db, 0x74db }, +/* 0x74dc */ { false, 0x74dc, 0x74dc }, +/* 0x74dd */ { false, 0x74dd, 0x74dd }, +/* 0x74de */ { false, 0x74de, 0x74de }, +/* 0x74df */ { false, 0x74df, 0x74df }, +/* 0x74e0 */ { false, 0x74e0, 0x74e0 }, +/* 0x74e1 */ { false, 0x74e1, 0x74e1 }, +/* 0x74e2 */ { false, 0x74e2, 0x74e2 }, +/* 0x74e3 */ { false, 0x74e3, 0x74e3 }, +/* 0x74e4 */ { false, 0x74e4, 0x74e4 }, +/* 0x74e5 */ { false, 0x74e5, 0x74e5 }, +/* 0x74e6 */ { false, 0x74e6, 0x74e6 }, +/* 0x74e7 */ { false, 0x74e7, 0x74e7 }, +/* 0x74e8 */ { false, 0x74e8, 0x74e8 }, +/* 0x74e9 */ { false, 0x74e9, 0x74e9 }, +/* 0x74ea */ { false, 0x74ea, 0x74ea }, +/* 0x74eb */ { false, 0x74eb, 0x74eb }, +/* 0x74ec */ { false, 0x74ec, 0x74ec }, +/* 0x74ed */ { false, 0x74ed, 0x74ed }, +/* 0x74ee */ { false, 0x74ee, 0x74ee }, +/* 0x74ef */ { false, 0x74ef, 0x74ef }, +/* 0x74f0 */ { false, 0x74f0, 0x74f0 }, +/* 0x74f1 */ { false, 0x74f1, 0x74f1 }, +/* 0x74f2 */ { false, 0x74f2, 0x74f2 }, +/* 0x74f3 */ { false, 0x74f3, 0x74f3 }, +/* 0x74f4 */ { false, 0x74f4, 0x74f4 }, +/* 0x74f5 */ { false, 0x74f5, 0x74f5 }, +/* 0x74f6 */ { false, 0x74f6, 0x74f6 }, +/* 0x74f7 */ { false, 0x74f7, 0x74f7 }, +/* 0x74f8 */ { false, 0x74f8, 0x74f8 }, +/* 0x74f9 */ { false, 0x74f9, 0x74f9 }, +/* 0x74fa */ { false, 0x74fa, 0x74fa }, +/* 0x74fb */ { false, 0x74fb, 0x74fb }, +/* 0x74fc */ { false, 0x74fc, 0x74fc }, +/* 0x74fd */ { false, 0x74fd, 0x74fd }, +/* 0x74fe */ { false, 0x74fe, 0x74fe }, +/* 0x74ff */ { false, 0x74ff, 0x74ff }, +/* 0x7500 */ { false, 0x7500, 0x7500 }, +/* 0x7501 */ { false, 0x7501, 0x7501 }, +/* 0x7502 */ { false, 0x7502, 0x7502 }, +/* 0x7503 */ { false, 0x7503, 0x7503 }, +/* 0x7504 */ { false, 0x7504, 0x7504 }, +/* 0x7505 */ { false, 0x7505, 0x7505 }, +/* 0x7506 */ { false, 0x7506, 0x7506 }, +/* 0x7507 */ { false, 0x7507, 0x7507 }, +/* 0x7508 */ { false, 0x7508, 0x7508 }, +/* 0x7509 */ { false, 0x7509, 0x7509 }, +/* 0x750a */ { false, 0x750a, 0x750a }, +/* 0x750b */ { false, 0x750b, 0x750b }, +/* 0x750c */ { false, 0x750c, 0x750c }, +/* 0x750d */ { false, 0x750d, 0x750d }, +/* 0x750e */ { false, 0x750e, 0x750e }, +/* 0x750f */ { false, 0x750f, 0x750f }, +/* 0x7510 */ { false, 0x7510, 0x7510 }, +/* 0x7511 */ { false, 0x7511, 0x7511 }, +/* 0x7512 */ { false, 0x7512, 0x7512 }, +/* 0x7513 */ { false, 0x7513, 0x7513 }, +/* 0x7514 */ { false, 0x7514, 0x7514 }, +/* 0x7515 */ { false, 0x7515, 0x7515 }, +/* 0x7516 */ { false, 0x7516, 0x7516 }, +/* 0x7517 */ { false, 0x7517, 0x7517 }, +/* 0x7518 */ { false, 0x7518, 0x7518 }, +/* 0x7519 */ { false, 0x7519, 0x7519 }, +/* 0x751a */ { false, 0x751a, 0x751a }, +/* 0x751b */ { false, 0x751b, 0x751b }, +/* 0x751c */ { false, 0x751c, 0x751c }, +/* 0x751d */ { false, 0x751d, 0x751d }, +/* 0x751e */ { false, 0x751e, 0x751e }, +/* 0x751f */ { false, 0x751f, 0x751f }, +/* 0x7520 */ { false, 0x7520, 0x7520 }, +/* 0x7521 */ { false, 0x7521, 0x7521 }, +/* 0x7522 */ { false, 0x7522, 0x7522 }, +/* 0x7523 */ { false, 0x7523, 0x7523 }, +/* 0x7524 */ { false, 0x7524, 0x7524 }, +/* 0x7525 */ { false, 0x7525, 0x7525 }, +/* 0x7526 */ { false, 0x7526, 0x7526 }, +/* 0x7527 */ { false, 0x7527, 0x7527 }, +/* 0x7528 */ { false, 0x7528, 0x7528 }, +/* 0x7529 */ { false, 0x7529, 0x7529 }, +/* 0x752a */ { false, 0x752a, 0x752a }, +/* 0x752b */ { false, 0x752b, 0x752b }, +/* 0x752c */ { false, 0x752c, 0x752c }, +/* 0x752d */ { false, 0x752d, 0x752d }, +/* 0x752e */ { false, 0x752e, 0x752e }, +/* 0x752f */ { false, 0x752f, 0x752f }, +/* 0x7530 */ { false, 0x7530, 0x7530 }, +/* 0x7531 */ { false, 0x7531, 0x7531 }, +/* 0x7532 */ { false, 0x7532, 0x7532 }, +/* 0x7533 */ { false, 0x7533, 0x7533 }, +/* 0x7534 */ { false, 0x7534, 0x7534 }, +/* 0x7535 */ { false, 0x7535, 0x7535 }, +/* 0x7536 */ { false, 0x7536, 0x7536 }, +/* 0x7537 */ { false, 0x7537, 0x7537 }, +/* 0x7538 */ { false, 0x7538, 0x7538 }, +/* 0x7539 */ { false, 0x7539, 0x7539 }, +/* 0x753a */ { false, 0x753a, 0x753a }, +/* 0x753b */ { false, 0x753b, 0x753b }, +/* 0x753c */ { false, 0x753c, 0x753c }, +/* 0x753d */ { false, 0x753d, 0x753d }, +/* 0x753e */ { false, 0x753e, 0x753e }, +/* 0x753f */ { false, 0x753f, 0x753f }, +/* 0x7540 */ { false, 0x7540, 0x7540 }, +/* 0x7541 */ { false, 0x7541, 0x7541 }, +/* 0x7542 */ { false, 0x7542, 0x7542 }, +/* 0x7543 */ { false, 0x7543, 0x7543 }, +/* 0x7544 */ { false, 0x7544, 0x7544 }, +/* 0x7545 */ { false, 0x7545, 0x7545 }, +/* 0x7546 */ { false, 0x7546, 0x7546 }, +/* 0x7547 */ { false, 0x7547, 0x7547 }, +/* 0x7548 */ { false, 0x7548, 0x7548 }, +/* 0x7549 */ { false, 0x7549, 0x7549 }, +/* 0x754a */ { false, 0x754a, 0x754a }, +/* 0x754b */ { false, 0x754b, 0x754b }, +/* 0x754c */ { false, 0x754c, 0x754c }, +/* 0x754d */ { false, 0x754d, 0x754d }, +/* 0x754e */ { false, 0x754e, 0x754e }, +/* 0x754f */ { false, 0x754f, 0x754f }, +/* 0x7550 */ { false, 0x7550, 0x7550 }, +/* 0x7551 */ { false, 0x7551, 0x7551 }, +/* 0x7552 */ { false, 0x7552, 0x7552 }, +/* 0x7553 */ { false, 0x7553, 0x7553 }, +/* 0x7554 */ { false, 0x7554, 0x7554 }, +/* 0x7555 */ { false, 0x7555, 0x7555 }, +/* 0x7556 */ { false, 0x7556, 0x7556 }, +/* 0x7557 */ { false, 0x7557, 0x7557 }, +/* 0x7558 */ { false, 0x7558, 0x7558 }, +/* 0x7559 */ { false, 0x7559, 0x7559 }, +/* 0x755a */ { false, 0x755a, 0x755a }, +/* 0x755b */ { false, 0x755b, 0x755b }, +/* 0x755c */ { false, 0x755c, 0x755c }, +/* 0x755d */ { false, 0x755d, 0x755d }, +/* 0x755e */ { false, 0x755e, 0x755e }, +/* 0x755f */ { false, 0x755f, 0x755f }, +/* 0x7560 */ { false, 0x7560, 0x7560 }, +/* 0x7561 */ { false, 0x7561, 0x7561 }, +/* 0x7562 */ { false, 0x7562, 0x7562 }, +/* 0x7563 */ { false, 0x7563, 0x7563 }, +/* 0x7564 */ { false, 0x7564, 0x7564 }, +/* 0x7565 */ { false, 0x7565, 0x7565 }, +/* 0x7566 */ { false, 0x7566, 0x7566 }, +/* 0x7567 */ { false, 0x7567, 0x7567 }, +/* 0x7568 */ { false, 0x7568, 0x7568 }, +/* 0x7569 */ { false, 0x7569, 0x7569 }, +/* 0x756a */ { false, 0x756a, 0x756a }, +/* 0x756b */ { false, 0x756b, 0x756b }, +/* 0x756c */ { false, 0x756c, 0x756c }, +/* 0x756d */ { false, 0x756d, 0x756d }, +/* 0x756e */ { false, 0x756e, 0x756e }, +/* 0x756f */ { false, 0x756f, 0x756f }, +/* 0x7570 */ { false, 0x7570, 0x7570 }, +/* 0x7571 */ { false, 0x7571, 0x7571 }, +/* 0x7572 */ { false, 0x7572, 0x7572 }, +/* 0x7573 */ { false, 0x7573, 0x7573 }, +/* 0x7574 */ { false, 0x7574, 0x7574 }, +/* 0x7575 */ { false, 0x7575, 0x7575 }, +/* 0x7576 */ { false, 0x7576, 0x7576 }, +/* 0x7577 */ { false, 0x7577, 0x7577 }, +/* 0x7578 */ { false, 0x7578, 0x7578 }, +/* 0x7579 */ { false, 0x7579, 0x7579 }, +/* 0x757a */ { false, 0x757a, 0x757a }, +/* 0x757b */ { false, 0x757b, 0x757b }, +/* 0x757c */ { false, 0x757c, 0x757c }, +/* 0x757d */ { false, 0x757d, 0x757d }, +/* 0x757e */ { false, 0x757e, 0x757e }, +/* 0x757f */ { false, 0x757f, 0x757f }, +/* 0x7580 */ { false, 0x7580, 0x7580 }, +/* 0x7581 */ { false, 0x7581, 0x7581 }, +/* 0x7582 */ { false, 0x7582, 0x7582 }, +/* 0x7583 */ { false, 0x7583, 0x7583 }, +/* 0x7584 */ { false, 0x7584, 0x7584 }, +/* 0x7585 */ { false, 0x7585, 0x7585 }, +/* 0x7586 */ { false, 0x7586, 0x7586 }, +/* 0x7587 */ { false, 0x7587, 0x7587 }, +/* 0x7588 */ { false, 0x7588, 0x7588 }, +/* 0x7589 */ { false, 0x7589, 0x7589 }, +/* 0x758a */ { false, 0x758a, 0x758a }, +/* 0x758b */ { false, 0x758b, 0x758b }, +/* 0x758c */ { false, 0x758c, 0x758c }, +/* 0x758d */ { false, 0x758d, 0x758d }, +/* 0x758e */ { false, 0x758e, 0x758e }, +/* 0x758f */ { false, 0x758f, 0x758f }, +/* 0x7590 */ { false, 0x7590, 0x7590 }, +/* 0x7591 */ { false, 0x7591, 0x7591 }, +/* 0x7592 */ { false, 0x7592, 0x7592 }, +/* 0x7593 */ { false, 0x7593, 0x7593 }, +/* 0x7594 */ { false, 0x7594, 0x7594 }, +/* 0x7595 */ { false, 0x7595, 0x7595 }, +/* 0x7596 */ { false, 0x7596, 0x7596 }, +/* 0x7597 */ { false, 0x7597, 0x7597 }, +/* 0x7598 */ { false, 0x7598, 0x7598 }, +/* 0x7599 */ { false, 0x7599, 0x7599 }, +/* 0x759a */ { false, 0x759a, 0x759a }, +/* 0x759b */ { false, 0x759b, 0x759b }, +/* 0x759c */ { false, 0x759c, 0x759c }, +/* 0x759d */ { false, 0x759d, 0x759d }, +/* 0x759e */ { false, 0x759e, 0x759e }, +/* 0x759f */ { false, 0x759f, 0x759f }, +/* 0x75a0 */ { false, 0x75a0, 0x75a0 }, +/* 0x75a1 */ { false, 0x75a1, 0x75a1 }, +/* 0x75a2 */ { false, 0x75a2, 0x75a2 }, +/* 0x75a3 */ { false, 0x75a3, 0x75a3 }, +/* 0x75a4 */ { false, 0x75a4, 0x75a4 }, +/* 0x75a5 */ { false, 0x75a5, 0x75a5 }, +/* 0x75a6 */ { false, 0x75a6, 0x75a6 }, +/* 0x75a7 */ { false, 0x75a7, 0x75a7 }, +/* 0x75a8 */ { false, 0x75a8, 0x75a8 }, +/* 0x75a9 */ { false, 0x75a9, 0x75a9 }, +/* 0x75aa */ { false, 0x75aa, 0x75aa }, +/* 0x75ab */ { false, 0x75ab, 0x75ab }, +/* 0x75ac */ { false, 0x75ac, 0x75ac }, +/* 0x75ad */ { false, 0x75ad, 0x75ad }, +/* 0x75ae */ { false, 0x75ae, 0x75ae }, +/* 0x75af */ { false, 0x75af, 0x75af }, +/* 0x75b0 */ { false, 0x75b0, 0x75b0 }, +/* 0x75b1 */ { false, 0x75b1, 0x75b1 }, +/* 0x75b2 */ { false, 0x75b2, 0x75b2 }, +/* 0x75b3 */ { false, 0x75b3, 0x75b3 }, +/* 0x75b4 */ { false, 0x75b4, 0x75b4 }, +/* 0x75b5 */ { false, 0x75b5, 0x75b5 }, +/* 0x75b6 */ { false, 0x75b6, 0x75b6 }, +/* 0x75b7 */ { false, 0x75b7, 0x75b7 }, +/* 0x75b8 */ { false, 0x75b8, 0x75b8 }, +/* 0x75b9 */ { false, 0x75b9, 0x75b9 }, +/* 0x75ba */ { false, 0x75ba, 0x75ba }, +/* 0x75bb */ { false, 0x75bb, 0x75bb }, +/* 0x75bc */ { false, 0x75bc, 0x75bc }, +/* 0x75bd */ { false, 0x75bd, 0x75bd }, +/* 0x75be */ { false, 0x75be, 0x75be }, +/* 0x75bf */ { false, 0x75bf, 0x75bf }, +/* 0x75c0 */ { false, 0x75c0, 0x75c0 }, +/* 0x75c1 */ { false, 0x75c1, 0x75c1 }, +/* 0x75c2 */ { false, 0x75c2, 0x75c2 }, +/* 0x75c3 */ { false, 0x75c3, 0x75c3 }, +/* 0x75c4 */ { false, 0x75c4, 0x75c4 }, +/* 0x75c5 */ { false, 0x75c5, 0x75c5 }, +/* 0x75c6 */ { false, 0x75c6, 0x75c6 }, +/* 0x75c7 */ { false, 0x75c7, 0x75c7 }, +/* 0x75c8 */ { false, 0x75c8, 0x75c8 }, +/* 0x75c9 */ { false, 0x75c9, 0x75c9 }, +/* 0x75ca */ { false, 0x75ca, 0x75ca }, +/* 0x75cb */ { false, 0x75cb, 0x75cb }, +/* 0x75cc */ { false, 0x75cc, 0x75cc }, +/* 0x75cd */ { false, 0x75cd, 0x75cd }, +/* 0x75ce */ { false, 0x75ce, 0x75ce }, +/* 0x75cf */ { false, 0x75cf, 0x75cf }, +/* 0x75d0 */ { false, 0x75d0, 0x75d0 }, +/* 0x75d1 */ { false, 0x75d1, 0x75d1 }, +/* 0x75d2 */ { false, 0x75d2, 0x75d2 }, +/* 0x75d3 */ { false, 0x75d3, 0x75d3 }, +/* 0x75d4 */ { false, 0x75d4, 0x75d4 }, +/* 0x75d5 */ { false, 0x75d5, 0x75d5 }, +/* 0x75d6 */ { false, 0x75d6, 0x75d6 }, +/* 0x75d7 */ { false, 0x75d7, 0x75d7 }, +/* 0x75d8 */ { false, 0x75d8, 0x75d8 }, +/* 0x75d9 */ { false, 0x75d9, 0x75d9 }, +/* 0x75da */ { false, 0x75da, 0x75da }, +/* 0x75db */ { false, 0x75db, 0x75db }, +/* 0x75dc */ { false, 0x75dc, 0x75dc }, +/* 0x75dd */ { false, 0x75dd, 0x75dd }, +/* 0x75de */ { false, 0x75de, 0x75de }, +/* 0x75df */ { false, 0x75df, 0x75df }, +/* 0x75e0 */ { false, 0x75e0, 0x75e0 }, +/* 0x75e1 */ { false, 0x75e1, 0x75e1 }, +/* 0x75e2 */ { false, 0x75e2, 0x75e2 }, +/* 0x75e3 */ { false, 0x75e3, 0x75e3 }, +/* 0x75e4 */ { false, 0x75e4, 0x75e4 }, +/* 0x75e5 */ { false, 0x75e5, 0x75e5 }, +/* 0x75e6 */ { false, 0x75e6, 0x75e6 }, +/* 0x75e7 */ { false, 0x75e7, 0x75e7 }, +/* 0x75e8 */ { false, 0x75e8, 0x75e8 }, +/* 0x75e9 */ { false, 0x75e9, 0x75e9 }, +/* 0x75ea */ { false, 0x75ea, 0x75ea }, +/* 0x75eb */ { false, 0x75eb, 0x75eb }, +/* 0x75ec */ { false, 0x75ec, 0x75ec }, +/* 0x75ed */ { false, 0x75ed, 0x75ed }, +/* 0x75ee */ { false, 0x75ee, 0x75ee }, +/* 0x75ef */ { false, 0x75ef, 0x75ef }, +/* 0x75f0 */ { false, 0x75f0, 0x75f0 }, +/* 0x75f1 */ { false, 0x75f1, 0x75f1 }, +/* 0x75f2 */ { false, 0x75f2, 0x75f2 }, +/* 0x75f3 */ { false, 0x75f3, 0x75f3 }, +/* 0x75f4 */ { false, 0x75f4, 0x75f4 }, +/* 0x75f5 */ { false, 0x75f5, 0x75f5 }, +/* 0x75f6 */ { false, 0x75f6, 0x75f6 }, +/* 0x75f7 */ { false, 0x75f7, 0x75f7 }, +/* 0x75f8 */ { false, 0x75f8, 0x75f8 }, +/* 0x75f9 */ { false, 0x75f9, 0x75f9 }, +/* 0x75fa */ { false, 0x75fa, 0x75fa }, +/* 0x75fb */ { false, 0x75fb, 0x75fb }, +/* 0x75fc */ { false, 0x75fc, 0x75fc }, +/* 0x75fd */ { false, 0x75fd, 0x75fd }, +/* 0x75fe */ { false, 0x75fe, 0x75fe }, +/* 0x75ff */ { false, 0x75ff, 0x75ff }, +/* 0x7600 */ { false, 0x7600, 0x7600 }, +/* 0x7601 */ { false, 0x7601, 0x7601 }, +/* 0x7602 */ { false, 0x7602, 0x7602 }, +/* 0x7603 */ { false, 0x7603, 0x7603 }, +/* 0x7604 */ { false, 0x7604, 0x7604 }, +/* 0x7605 */ { false, 0x7605, 0x7605 }, +/* 0x7606 */ { false, 0x7606, 0x7606 }, +/* 0x7607 */ { false, 0x7607, 0x7607 }, +/* 0x7608 */ { false, 0x7608, 0x7608 }, +/* 0x7609 */ { false, 0x7609, 0x7609 }, +/* 0x760a */ { false, 0x760a, 0x760a }, +/* 0x760b */ { false, 0x760b, 0x760b }, +/* 0x760c */ { false, 0x760c, 0x760c }, +/* 0x760d */ { false, 0x760d, 0x760d }, +/* 0x760e */ { false, 0x760e, 0x760e }, +/* 0x760f */ { false, 0x760f, 0x760f }, +/* 0x7610 */ { false, 0x7610, 0x7610 }, +/* 0x7611 */ { false, 0x7611, 0x7611 }, +/* 0x7612 */ { false, 0x7612, 0x7612 }, +/* 0x7613 */ { false, 0x7613, 0x7613 }, +/* 0x7614 */ { false, 0x7614, 0x7614 }, +/* 0x7615 */ { false, 0x7615, 0x7615 }, +/* 0x7616 */ { false, 0x7616, 0x7616 }, +/* 0x7617 */ { false, 0x7617, 0x7617 }, +/* 0x7618 */ { false, 0x7618, 0x7618 }, +/* 0x7619 */ { false, 0x7619, 0x7619 }, +/* 0x761a */ { false, 0x761a, 0x761a }, +/* 0x761b */ { false, 0x761b, 0x761b }, +/* 0x761c */ { false, 0x761c, 0x761c }, +/* 0x761d */ { false, 0x761d, 0x761d }, +/* 0x761e */ { false, 0x761e, 0x761e }, +/* 0x761f */ { false, 0x761f, 0x761f }, +/* 0x7620 */ { false, 0x7620, 0x7620 }, +/* 0x7621 */ { false, 0x7621, 0x7621 }, +/* 0x7622 */ { false, 0x7622, 0x7622 }, +/* 0x7623 */ { false, 0x7623, 0x7623 }, +/* 0x7624 */ { false, 0x7624, 0x7624 }, +/* 0x7625 */ { false, 0x7625, 0x7625 }, +/* 0x7626 */ { false, 0x7626, 0x7626 }, +/* 0x7627 */ { false, 0x7627, 0x7627 }, +/* 0x7628 */ { false, 0x7628, 0x7628 }, +/* 0x7629 */ { false, 0x7629, 0x7629 }, +/* 0x762a */ { false, 0x762a, 0x762a }, +/* 0x762b */ { false, 0x762b, 0x762b }, +/* 0x762c */ { false, 0x762c, 0x762c }, +/* 0x762d */ { false, 0x762d, 0x762d }, +/* 0x762e */ { false, 0x762e, 0x762e }, +/* 0x762f */ { false, 0x762f, 0x762f }, +/* 0x7630 */ { false, 0x7630, 0x7630 }, +/* 0x7631 */ { false, 0x7631, 0x7631 }, +/* 0x7632 */ { false, 0x7632, 0x7632 }, +/* 0x7633 */ { false, 0x7633, 0x7633 }, +/* 0x7634 */ { false, 0x7634, 0x7634 }, +/* 0x7635 */ { false, 0x7635, 0x7635 }, +/* 0x7636 */ { false, 0x7636, 0x7636 }, +/* 0x7637 */ { false, 0x7637, 0x7637 }, +/* 0x7638 */ { false, 0x7638, 0x7638 }, +/* 0x7639 */ { false, 0x7639, 0x7639 }, +/* 0x763a */ { false, 0x763a, 0x763a }, +/* 0x763b */ { false, 0x763b, 0x763b }, +/* 0x763c */ { false, 0x763c, 0x763c }, +/* 0x763d */ { false, 0x763d, 0x763d }, +/* 0x763e */ { false, 0x763e, 0x763e }, +/* 0x763f */ { false, 0x763f, 0x763f }, +/* 0x7640 */ { false, 0x7640, 0x7640 }, +/* 0x7641 */ { false, 0x7641, 0x7641 }, +/* 0x7642 */ { false, 0x7642, 0x7642 }, +/* 0x7643 */ { false, 0x7643, 0x7643 }, +/* 0x7644 */ { false, 0x7644, 0x7644 }, +/* 0x7645 */ { false, 0x7645, 0x7645 }, +/* 0x7646 */ { false, 0x7646, 0x7646 }, +/* 0x7647 */ { false, 0x7647, 0x7647 }, +/* 0x7648 */ { false, 0x7648, 0x7648 }, +/* 0x7649 */ { false, 0x7649, 0x7649 }, +/* 0x764a */ { false, 0x764a, 0x764a }, +/* 0x764b */ { false, 0x764b, 0x764b }, +/* 0x764c */ { false, 0x764c, 0x764c }, +/* 0x764d */ { false, 0x764d, 0x764d }, +/* 0x764e */ { false, 0x764e, 0x764e }, +/* 0x764f */ { false, 0x764f, 0x764f }, +/* 0x7650 */ { false, 0x7650, 0x7650 }, +/* 0x7651 */ { false, 0x7651, 0x7651 }, +/* 0x7652 */ { false, 0x7652, 0x7652 }, +/* 0x7653 */ { false, 0x7653, 0x7653 }, +/* 0x7654 */ { false, 0x7654, 0x7654 }, +/* 0x7655 */ { false, 0x7655, 0x7655 }, +/* 0x7656 */ { false, 0x7656, 0x7656 }, +/* 0x7657 */ { false, 0x7657, 0x7657 }, +/* 0x7658 */ { false, 0x7658, 0x7658 }, +/* 0x7659 */ { false, 0x7659, 0x7659 }, +/* 0x765a */ { false, 0x765a, 0x765a }, +/* 0x765b */ { false, 0x765b, 0x765b }, +/* 0x765c */ { false, 0x765c, 0x765c }, +/* 0x765d */ { false, 0x765d, 0x765d }, +/* 0x765e */ { false, 0x765e, 0x765e }, +/* 0x765f */ { false, 0x765f, 0x765f }, +/* 0x7660 */ { false, 0x7660, 0x7660 }, +/* 0x7661 */ { false, 0x7661, 0x7661 }, +/* 0x7662 */ { false, 0x7662, 0x7662 }, +/* 0x7663 */ { false, 0x7663, 0x7663 }, +/* 0x7664 */ { false, 0x7664, 0x7664 }, +/* 0x7665 */ { false, 0x7665, 0x7665 }, +/* 0x7666 */ { false, 0x7666, 0x7666 }, +/* 0x7667 */ { false, 0x7667, 0x7667 }, +/* 0x7668 */ { false, 0x7668, 0x7668 }, +/* 0x7669 */ { false, 0x7669, 0x7669 }, +/* 0x766a */ { false, 0x766a, 0x766a }, +/* 0x766b */ { false, 0x766b, 0x766b }, +/* 0x766c */ { false, 0x766c, 0x766c }, +/* 0x766d */ { false, 0x766d, 0x766d }, +/* 0x766e */ { false, 0x766e, 0x766e }, +/* 0x766f */ { false, 0x766f, 0x766f }, +/* 0x7670 */ { false, 0x7670, 0x7670 }, +/* 0x7671 */ { false, 0x7671, 0x7671 }, +/* 0x7672 */ { false, 0x7672, 0x7672 }, +/* 0x7673 */ { false, 0x7673, 0x7673 }, +/* 0x7674 */ { false, 0x7674, 0x7674 }, +/* 0x7675 */ { false, 0x7675, 0x7675 }, +/* 0x7676 */ { false, 0x7676, 0x7676 }, +/* 0x7677 */ { false, 0x7677, 0x7677 }, +/* 0x7678 */ { false, 0x7678, 0x7678 }, +/* 0x7679 */ { false, 0x7679, 0x7679 }, +/* 0x767a */ { false, 0x767a, 0x767a }, +/* 0x767b */ { false, 0x767b, 0x767b }, +/* 0x767c */ { false, 0x767c, 0x767c }, +/* 0x767d */ { false, 0x767d, 0x767d }, +/* 0x767e */ { false, 0x767e, 0x767e }, +/* 0x767f */ { false, 0x767f, 0x767f }, +/* 0x7680 */ { false, 0x7680, 0x7680 }, +/* 0x7681 */ { false, 0x7681, 0x7681 }, +/* 0x7682 */ { false, 0x7682, 0x7682 }, +/* 0x7683 */ { false, 0x7683, 0x7683 }, +/* 0x7684 */ { false, 0x7684, 0x7684 }, +/* 0x7685 */ { false, 0x7685, 0x7685 }, +/* 0x7686 */ { false, 0x7686, 0x7686 }, +/* 0x7687 */ { false, 0x7687, 0x7687 }, +/* 0x7688 */ { false, 0x7688, 0x7688 }, +/* 0x7689 */ { false, 0x7689, 0x7689 }, +/* 0x768a */ { false, 0x768a, 0x768a }, +/* 0x768b */ { false, 0x768b, 0x768b }, +/* 0x768c */ { false, 0x768c, 0x768c }, +/* 0x768d */ { false, 0x768d, 0x768d }, +/* 0x768e */ { false, 0x768e, 0x768e }, +/* 0x768f */ { false, 0x768f, 0x768f }, +/* 0x7690 */ { false, 0x7690, 0x7690 }, +/* 0x7691 */ { false, 0x7691, 0x7691 }, +/* 0x7692 */ { false, 0x7692, 0x7692 }, +/* 0x7693 */ { false, 0x7693, 0x7693 }, +/* 0x7694 */ { false, 0x7694, 0x7694 }, +/* 0x7695 */ { false, 0x7695, 0x7695 }, +/* 0x7696 */ { false, 0x7696, 0x7696 }, +/* 0x7697 */ { false, 0x7697, 0x7697 }, +/* 0x7698 */ { false, 0x7698, 0x7698 }, +/* 0x7699 */ { false, 0x7699, 0x7699 }, +/* 0x769a */ { false, 0x769a, 0x769a }, +/* 0x769b */ { false, 0x769b, 0x769b }, +/* 0x769c */ { false, 0x769c, 0x769c }, +/* 0x769d */ { false, 0x769d, 0x769d }, +/* 0x769e */ { false, 0x769e, 0x769e }, +/* 0x769f */ { false, 0x769f, 0x769f }, +/* 0x76a0 */ { false, 0x76a0, 0x76a0 }, +/* 0x76a1 */ { false, 0x76a1, 0x76a1 }, +/* 0x76a2 */ { false, 0x76a2, 0x76a2 }, +/* 0x76a3 */ { false, 0x76a3, 0x76a3 }, +/* 0x76a4 */ { false, 0x76a4, 0x76a4 }, +/* 0x76a5 */ { false, 0x76a5, 0x76a5 }, +/* 0x76a6 */ { false, 0x76a6, 0x76a6 }, +/* 0x76a7 */ { false, 0x76a7, 0x76a7 }, +/* 0x76a8 */ { false, 0x76a8, 0x76a8 }, +/* 0x76a9 */ { false, 0x76a9, 0x76a9 }, +/* 0x76aa */ { false, 0x76aa, 0x76aa }, +/* 0x76ab */ { false, 0x76ab, 0x76ab }, +/* 0x76ac */ { false, 0x76ac, 0x76ac }, +/* 0x76ad */ { false, 0x76ad, 0x76ad }, +/* 0x76ae */ { false, 0x76ae, 0x76ae }, +/* 0x76af */ { false, 0x76af, 0x76af }, +/* 0x76b0 */ { false, 0x76b0, 0x76b0 }, +/* 0x76b1 */ { false, 0x76b1, 0x76b1 }, +/* 0x76b2 */ { false, 0x76b2, 0x76b2 }, +/* 0x76b3 */ { false, 0x76b3, 0x76b3 }, +/* 0x76b4 */ { false, 0x76b4, 0x76b4 }, +/* 0x76b5 */ { false, 0x76b5, 0x76b5 }, +/* 0x76b6 */ { false, 0x76b6, 0x76b6 }, +/* 0x76b7 */ { false, 0x76b7, 0x76b7 }, +/* 0x76b8 */ { false, 0x76b8, 0x76b8 }, +/* 0x76b9 */ { false, 0x76b9, 0x76b9 }, +/* 0x76ba */ { false, 0x76ba, 0x76ba }, +/* 0x76bb */ { false, 0x76bb, 0x76bb }, +/* 0x76bc */ { false, 0x76bc, 0x76bc }, +/* 0x76bd */ { false, 0x76bd, 0x76bd }, +/* 0x76be */ { false, 0x76be, 0x76be }, +/* 0x76bf */ { false, 0x76bf, 0x76bf }, +/* 0x76c0 */ { false, 0x76c0, 0x76c0 }, +/* 0x76c1 */ { false, 0x76c1, 0x76c1 }, +/* 0x76c2 */ { false, 0x76c2, 0x76c2 }, +/* 0x76c3 */ { false, 0x76c3, 0x76c3 }, +/* 0x76c4 */ { false, 0x76c4, 0x76c4 }, +/* 0x76c5 */ { false, 0x76c5, 0x76c5 }, +/* 0x76c6 */ { false, 0x76c6, 0x76c6 }, +/* 0x76c7 */ { false, 0x76c7, 0x76c7 }, +/* 0x76c8 */ { false, 0x76c8, 0x76c8 }, +/* 0x76c9 */ { false, 0x76c9, 0x76c9 }, +/* 0x76ca */ { false, 0x76ca, 0x76ca }, +/* 0x76cb */ { false, 0x76cb, 0x76cb }, +/* 0x76cc */ { false, 0x76cc, 0x76cc }, +/* 0x76cd */ { false, 0x76cd, 0x76cd }, +/* 0x76ce */ { false, 0x76ce, 0x76ce }, +/* 0x76cf */ { false, 0x76cf, 0x76cf }, +/* 0x76d0 */ { false, 0x76d0, 0x76d0 }, +/* 0x76d1 */ { false, 0x76d1, 0x76d1 }, +/* 0x76d2 */ { false, 0x76d2, 0x76d2 }, +/* 0x76d3 */ { false, 0x76d3, 0x76d3 }, +/* 0x76d4 */ { false, 0x76d4, 0x76d4 }, +/* 0x76d5 */ { false, 0x76d5, 0x76d5 }, +/* 0x76d6 */ { false, 0x76d6, 0x76d6 }, +/* 0x76d7 */ { false, 0x76d7, 0x76d7 }, +/* 0x76d8 */ { false, 0x76d8, 0x76d8 }, +/* 0x76d9 */ { false, 0x76d9, 0x76d9 }, +/* 0x76da */ { false, 0x76da, 0x76da }, +/* 0x76db */ { false, 0x76db, 0x76db }, +/* 0x76dc */ { false, 0x76dc, 0x76dc }, +/* 0x76dd */ { false, 0x76dd, 0x76dd }, +/* 0x76de */ { false, 0x76de, 0x76de }, +/* 0x76df */ { false, 0x76df, 0x76df }, +/* 0x76e0 */ { false, 0x76e0, 0x76e0 }, +/* 0x76e1 */ { false, 0x76e1, 0x76e1 }, +/* 0x76e2 */ { false, 0x76e2, 0x76e2 }, +/* 0x76e3 */ { false, 0x76e3, 0x76e3 }, +/* 0x76e4 */ { false, 0x76e4, 0x76e4 }, +/* 0x76e5 */ { false, 0x76e5, 0x76e5 }, +/* 0x76e6 */ { false, 0x76e6, 0x76e6 }, +/* 0x76e7 */ { false, 0x76e7, 0x76e7 }, +/* 0x76e8 */ { false, 0x76e8, 0x76e8 }, +/* 0x76e9 */ { false, 0x76e9, 0x76e9 }, +/* 0x76ea */ { false, 0x76ea, 0x76ea }, +/* 0x76eb */ { false, 0x76eb, 0x76eb }, +/* 0x76ec */ { false, 0x76ec, 0x76ec }, +/* 0x76ed */ { false, 0x76ed, 0x76ed }, +/* 0x76ee */ { false, 0x76ee, 0x76ee }, +/* 0x76ef */ { false, 0x76ef, 0x76ef }, +/* 0x76f0 */ { false, 0x76f0, 0x76f0 }, +/* 0x76f1 */ { false, 0x76f1, 0x76f1 }, +/* 0x76f2 */ { false, 0x76f2, 0x76f2 }, +/* 0x76f3 */ { false, 0x76f3, 0x76f3 }, +/* 0x76f4 */ { false, 0x76f4, 0x76f4 }, +/* 0x76f5 */ { false, 0x76f5, 0x76f5 }, +/* 0x76f6 */ { false, 0x76f6, 0x76f6 }, +/* 0x76f7 */ { false, 0x76f7, 0x76f7 }, +/* 0x76f8 */ { false, 0x76f8, 0x76f8 }, +/* 0x76f9 */ { false, 0x76f9, 0x76f9 }, +/* 0x76fa */ { false, 0x76fa, 0x76fa }, +/* 0x76fb */ { false, 0x76fb, 0x76fb }, +/* 0x76fc */ { false, 0x76fc, 0x76fc }, +/* 0x76fd */ { false, 0x76fd, 0x76fd }, +/* 0x76fe */ { false, 0x76fe, 0x76fe }, +/* 0x76ff */ { false, 0x76ff, 0x76ff }, +/* 0x7700 */ { false, 0x7700, 0x7700 }, +/* 0x7701 */ { false, 0x7701, 0x7701 }, +/* 0x7702 */ { false, 0x7702, 0x7702 }, +/* 0x7703 */ { false, 0x7703, 0x7703 }, +/* 0x7704 */ { false, 0x7704, 0x7704 }, +/* 0x7705 */ { false, 0x7705, 0x7705 }, +/* 0x7706 */ { false, 0x7706, 0x7706 }, +/* 0x7707 */ { false, 0x7707, 0x7707 }, +/* 0x7708 */ { false, 0x7708, 0x7708 }, +/* 0x7709 */ { false, 0x7709, 0x7709 }, +/* 0x770a */ { false, 0x770a, 0x770a }, +/* 0x770b */ { false, 0x770b, 0x770b }, +/* 0x770c */ { false, 0x770c, 0x770c }, +/* 0x770d */ { false, 0x770d, 0x770d }, +/* 0x770e */ { false, 0x770e, 0x770e }, +/* 0x770f */ { false, 0x770f, 0x770f }, +/* 0x7710 */ { false, 0x7710, 0x7710 }, +/* 0x7711 */ { false, 0x7711, 0x7711 }, +/* 0x7712 */ { false, 0x7712, 0x7712 }, +/* 0x7713 */ { false, 0x7713, 0x7713 }, +/* 0x7714 */ { false, 0x7714, 0x7714 }, +/* 0x7715 */ { false, 0x7715, 0x7715 }, +/* 0x7716 */ { false, 0x7716, 0x7716 }, +/* 0x7717 */ { false, 0x7717, 0x7717 }, +/* 0x7718 */ { false, 0x7718, 0x7718 }, +/* 0x7719 */ { false, 0x7719, 0x7719 }, +/* 0x771a */ { false, 0x771a, 0x771a }, +/* 0x771b */ { false, 0x771b, 0x771b }, +/* 0x771c */ { false, 0x771c, 0x771c }, +/* 0x771d */ { false, 0x771d, 0x771d }, +/* 0x771e */ { false, 0x771e, 0x771e }, +/* 0x771f */ { false, 0x771f, 0x771f }, +/* 0x7720 */ { false, 0x7720, 0x7720 }, +/* 0x7721 */ { false, 0x7721, 0x7721 }, +/* 0x7722 */ { false, 0x7722, 0x7722 }, +/* 0x7723 */ { false, 0x7723, 0x7723 }, +/* 0x7724 */ { false, 0x7724, 0x7724 }, +/* 0x7725 */ { false, 0x7725, 0x7725 }, +/* 0x7726 */ { false, 0x7726, 0x7726 }, +/* 0x7727 */ { false, 0x7727, 0x7727 }, +/* 0x7728 */ { false, 0x7728, 0x7728 }, +/* 0x7729 */ { false, 0x7729, 0x7729 }, +/* 0x772a */ { false, 0x772a, 0x772a }, +/* 0x772b */ { false, 0x772b, 0x772b }, +/* 0x772c */ { false, 0x772c, 0x772c }, +/* 0x772d */ { false, 0x772d, 0x772d }, +/* 0x772e */ { false, 0x772e, 0x772e }, +/* 0x772f */ { false, 0x772f, 0x772f }, +/* 0x7730 */ { false, 0x7730, 0x7730 }, +/* 0x7731 */ { false, 0x7731, 0x7731 }, +/* 0x7732 */ { false, 0x7732, 0x7732 }, +/* 0x7733 */ { false, 0x7733, 0x7733 }, +/* 0x7734 */ { false, 0x7734, 0x7734 }, +/* 0x7735 */ { false, 0x7735, 0x7735 }, +/* 0x7736 */ { false, 0x7736, 0x7736 }, +/* 0x7737 */ { false, 0x7737, 0x7737 }, +/* 0x7738 */ { false, 0x7738, 0x7738 }, +/* 0x7739 */ { false, 0x7739, 0x7739 }, +/* 0x773a */ { false, 0x773a, 0x773a }, +/* 0x773b */ { false, 0x773b, 0x773b }, +/* 0x773c */ { false, 0x773c, 0x773c }, +/* 0x773d */ { false, 0x773d, 0x773d }, +/* 0x773e */ { false, 0x773e, 0x773e }, +/* 0x773f */ { false, 0x773f, 0x773f }, +/* 0x7740 */ { false, 0x7740, 0x7740 }, +/* 0x7741 */ { false, 0x7741, 0x7741 }, +/* 0x7742 */ { false, 0x7742, 0x7742 }, +/* 0x7743 */ { false, 0x7743, 0x7743 }, +/* 0x7744 */ { false, 0x7744, 0x7744 }, +/* 0x7745 */ { false, 0x7745, 0x7745 }, +/* 0x7746 */ { false, 0x7746, 0x7746 }, +/* 0x7747 */ { false, 0x7747, 0x7747 }, +/* 0x7748 */ { false, 0x7748, 0x7748 }, +/* 0x7749 */ { false, 0x7749, 0x7749 }, +/* 0x774a */ { false, 0x774a, 0x774a }, +/* 0x774b */ { false, 0x774b, 0x774b }, +/* 0x774c */ { false, 0x774c, 0x774c }, +/* 0x774d */ { false, 0x774d, 0x774d }, +/* 0x774e */ { false, 0x774e, 0x774e }, +/* 0x774f */ { false, 0x774f, 0x774f }, +/* 0x7750 */ { false, 0x7750, 0x7750 }, +/* 0x7751 */ { false, 0x7751, 0x7751 }, +/* 0x7752 */ { false, 0x7752, 0x7752 }, +/* 0x7753 */ { false, 0x7753, 0x7753 }, +/* 0x7754 */ { false, 0x7754, 0x7754 }, +/* 0x7755 */ { false, 0x7755, 0x7755 }, +/* 0x7756 */ { false, 0x7756, 0x7756 }, +/* 0x7757 */ { false, 0x7757, 0x7757 }, +/* 0x7758 */ { false, 0x7758, 0x7758 }, +/* 0x7759 */ { false, 0x7759, 0x7759 }, +/* 0x775a */ { false, 0x775a, 0x775a }, +/* 0x775b */ { false, 0x775b, 0x775b }, +/* 0x775c */ { false, 0x775c, 0x775c }, +/* 0x775d */ { false, 0x775d, 0x775d }, +/* 0x775e */ { false, 0x775e, 0x775e }, +/* 0x775f */ { false, 0x775f, 0x775f }, +/* 0x7760 */ { false, 0x7760, 0x7760 }, +/* 0x7761 */ { false, 0x7761, 0x7761 }, +/* 0x7762 */ { false, 0x7762, 0x7762 }, +/* 0x7763 */ { false, 0x7763, 0x7763 }, +/* 0x7764 */ { false, 0x7764, 0x7764 }, +/* 0x7765 */ { false, 0x7765, 0x7765 }, +/* 0x7766 */ { false, 0x7766, 0x7766 }, +/* 0x7767 */ { false, 0x7767, 0x7767 }, +/* 0x7768 */ { false, 0x7768, 0x7768 }, +/* 0x7769 */ { false, 0x7769, 0x7769 }, +/* 0x776a */ { false, 0x776a, 0x776a }, +/* 0x776b */ { false, 0x776b, 0x776b }, +/* 0x776c */ { false, 0x776c, 0x776c }, +/* 0x776d */ { false, 0x776d, 0x776d }, +/* 0x776e */ { false, 0x776e, 0x776e }, +/* 0x776f */ { false, 0x776f, 0x776f }, +/* 0x7770 */ { false, 0x7770, 0x7770 }, +/* 0x7771 */ { false, 0x7771, 0x7771 }, +/* 0x7772 */ { false, 0x7772, 0x7772 }, +/* 0x7773 */ { false, 0x7773, 0x7773 }, +/* 0x7774 */ { false, 0x7774, 0x7774 }, +/* 0x7775 */ { false, 0x7775, 0x7775 }, +/* 0x7776 */ { false, 0x7776, 0x7776 }, +/* 0x7777 */ { false, 0x7777, 0x7777 }, +/* 0x7778 */ { false, 0x7778, 0x7778 }, +/* 0x7779 */ { false, 0x7779, 0x7779 }, +/* 0x777a */ { false, 0x777a, 0x777a }, +/* 0x777b */ { false, 0x777b, 0x777b }, +/* 0x777c */ { false, 0x777c, 0x777c }, +/* 0x777d */ { false, 0x777d, 0x777d }, +/* 0x777e */ { false, 0x777e, 0x777e }, +/* 0x777f */ { false, 0x777f, 0x777f }, +/* 0x7780 */ { false, 0x7780, 0x7780 }, +/* 0x7781 */ { false, 0x7781, 0x7781 }, +/* 0x7782 */ { false, 0x7782, 0x7782 }, +/* 0x7783 */ { false, 0x7783, 0x7783 }, +/* 0x7784 */ { false, 0x7784, 0x7784 }, +/* 0x7785 */ { false, 0x7785, 0x7785 }, +/* 0x7786 */ { false, 0x7786, 0x7786 }, +/* 0x7787 */ { false, 0x7787, 0x7787 }, +/* 0x7788 */ { false, 0x7788, 0x7788 }, +/* 0x7789 */ { false, 0x7789, 0x7789 }, +/* 0x778a */ { false, 0x778a, 0x778a }, +/* 0x778b */ { false, 0x778b, 0x778b }, +/* 0x778c */ { false, 0x778c, 0x778c }, +/* 0x778d */ { false, 0x778d, 0x778d }, +/* 0x778e */ { false, 0x778e, 0x778e }, +/* 0x778f */ { false, 0x778f, 0x778f }, +/* 0x7790 */ { false, 0x7790, 0x7790 }, +/* 0x7791 */ { false, 0x7791, 0x7791 }, +/* 0x7792 */ { false, 0x7792, 0x7792 }, +/* 0x7793 */ { false, 0x7793, 0x7793 }, +/* 0x7794 */ { false, 0x7794, 0x7794 }, +/* 0x7795 */ { false, 0x7795, 0x7795 }, +/* 0x7796 */ { false, 0x7796, 0x7796 }, +/* 0x7797 */ { false, 0x7797, 0x7797 }, +/* 0x7798 */ { false, 0x7798, 0x7798 }, +/* 0x7799 */ { false, 0x7799, 0x7799 }, +/* 0x779a */ { false, 0x779a, 0x779a }, +/* 0x779b */ { false, 0x779b, 0x779b }, +/* 0x779c */ { false, 0x779c, 0x779c }, +/* 0x779d */ { false, 0x779d, 0x779d }, +/* 0x779e */ { false, 0x779e, 0x779e }, +/* 0x779f */ { false, 0x779f, 0x779f }, +/* 0x77a0 */ { false, 0x77a0, 0x77a0 }, +/* 0x77a1 */ { false, 0x77a1, 0x77a1 }, +/* 0x77a2 */ { false, 0x77a2, 0x77a2 }, +/* 0x77a3 */ { false, 0x77a3, 0x77a3 }, +/* 0x77a4 */ { false, 0x77a4, 0x77a4 }, +/* 0x77a5 */ { false, 0x77a5, 0x77a5 }, +/* 0x77a6 */ { false, 0x77a6, 0x77a6 }, +/* 0x77a7 */ { false, 0x77a7, 0x77a7 }, +/* 0x77a8 */ { false, 0x77a8, 0x77a8 }, +/* 0x77a9 */ { false, 0x77a9, 0x77a9 }, +/* 0x77aa */ { false, 0x77aa, 0x77aa }, +/* 0x77ab */ { false, 0x77ab, 0x77ab }, +/* 0x77ac */ { false, 0x77ac, 0x77ac }, +/* 0x77ad */ { false, 0x77ad, 0x77ad }, +/* 0x77ae */ { false, 0x77ae, 0x77ae }, +/* 0x77af */ { false, 0x77af, 0x77af }, +/* 0x77b0 */ { false, 0x77b0, 0x77b0 }, +/* 0x77b1 */ { false, 0x77b1, 0x77b1 }, +/* 0x77b2 */ { false, 0x77b2, 0x77b2 }, +/* 0x77b3 */ { false, 0x77b3, 0x77b3 }, +/* 0x77b4 */ { false, 0x77b4, 0x77b4 }, +/* 0x77b5 */ { false, 0x77b5, 0x77b5 }, +/* 0x77b6 */ { false, 0x77b6, 0x77b6 }, +/* 0x77b7 */ { false, 0x77b7, 0x77b7 }, +/* 0x77b8 */ { false, 0x77b8, 0x77b8 }, +/* 0x77b9 */ { false, 0x77b9, 0x77b9 }, +/* 0x77ba */ { false, 0x77ba, 0x77ba }, +/* 0x77bb */ { false, 0x77bb, 0x77bb }, +/* 0x77bc */ { false, 0x77bc, 0x77bc }, +/* 0x77bd */ { false, 0x77bd, 0x77bd }, +/* 0x77be */ { false, 0x77be, 0x77be }, +/* 0x77bf */ { false, 0x77bf, 0x77bf }, +/* 0x77c0 */ { false, 0x77c0, 0x77c0 }, +/* 0x77c1 */ { false, 0x77c1, 0x77c1 }, +/* 0x77c2 */ { false, 0x77c2, 0x77c2 }, +/* 0x77c3 */ { false, 0x77c3, 0x77c3 }, +/* 0x77c4 */ { false, 0x77c4, 0x77c4 }, +/* 0x77c5 */ { false, 0x77c5, 0x77c5 }, +/* 0x77c6 */ { false, 0x77c6, 0x77c6 }, +/* 0x77c7 */ { false, 0x77c7, 0x77c7 }, +/* 0x77c8 */ { false, 0x77c8, 0x77c8 }, +/* 0x77c9 */ { false, 0x77c9, 0x77c9 }, +/* 0x77ca */ { false, 0x77ca, 0x77ca }, +/* 0x77cb */ { false, 0x77cb, 0x77cb }, +/* 0x77cc */ { false, 0x77cc, 0x77cc }, +/* 0x77cd */ { false, 0x77cd, 0x77cd }, +/* 0x77ce */ { false, 0x77ce, 0x77ce }, +/* 0x77cf */ { false, 0x77cf, 0x77cf }, +/* 0x77d0 */ { false, 0x77d0, 0x77d0 }, +/* 0x77d1 */ { false, 0x77d1, 0x77d1 }, +/* 0x77d2 */ { false, 0x77d2, 0x77d2 }, +/* 0x77d3 */ { false, 0x77d3, 0x77d3 }, +/* 0x77d4 */ { false, 0x77d4, 0x77d4 }, +/* 0x77d5 */ { false, 0x77d5, 0x77d5 }, +/* 0x77d6 */ { false, 0x77d6, 0x77d6 }, +/* 0x77d7 */ { false, 0x77d7, 0x77d7 }, +/* 0x77d8 */ { false, 0x77d8, 0x77d8 }, +/* 0x77d9 */ { false, 0x77d9, 0x77d9 }, +/* 0x77da */ { false, 0x77da, 0x77da }, +/* 0x77db */ { false, 0x77db, 0x77db }, +/* 0x77dc */ { false, 0x77dc, 0x77dc }, +/* 0x77dd */ { false, 0x77dd, 0x77dd }, +/* 0x77de */ { false, 0x77de, 0x77de }, +/* 0x77df */ { false, 0x77df, 0x77df }, +/* 0x77e0 */ { false, 0x77e0, 0x77e0 }, +/* 0x77e1 */ { false, 0x77e1, 0x77e1 }, +/* 0x77e2 */ { false, 0x77e2, 0x77e2 }, +/* 0x77e3 */ { false, 0x77e3, 0x77e3 }, +/* 0x77e4 */ { false, 0x77e4, 0x77e4 }, +/* 0x77e5 */ { false, 0x77e5, 0x77e5 }, +/* 0x77e6 */ { false, 0x77e6, 0x77e6 }, +/* 0x77e7 */ { false, 0x77e7, 0x77e7 }, +/* 0x77e8 */ { false, 0x77e8, 0x77e8 }, +/* 0x77e9 */ { false, 0x77e9, 0x77e9 }, +/* 0x77ea */ { false, 0x77ea, 0x77ea }, +/* 0x77eb */ { false, 0x77eb, 0x77eb }, +/* 0x77ec */ { false, 0x77ec, 0x77ec }, +/* 0x77ed */ { false, 0x77ed, 0x77ed }, +/* 0x77ee */ { false, 0x77ee, 0x77ee }, +/* 0x77ef */ { false, 0x77ef, 0x77ef }, +/* 0x77f0 */ { false, 0x77f0, 0x77f0 }, +/* 0x77f1 */ { false, 0x77f1, 0x77f1 }, +/* 0x77f2 */ { false, 0x77f2, 0x77f2 }, +/* 0x77f3 */ { false, 0x77f3, 0x77f3 }, +/* 0x77f4 */ { false, 0x77f4, 0x77f4 }, +/* 0x77f5 */ { false, 0x77f5, 0x77f5 }, +/* 0x77f6 */ { false, 0x77f6, 0x77f6 }, +/* 0x77f7 */ { false, 0x77f7, 0x77f7 }, +/* 0x77f8 */ { false, 0x77f8, 0x77f8 }, +/* 0x77f9 */ { false, 0x77f9, 0x77f9 }, +/* 0x77fa */ { false, 0x77fa, 0x77fa }, +/* 0x77fb */ { false, 0x77fb, 0x77fb }, +/* 0x77fc */ { false, 0x77fc, 0x77fc }, +/* 0x77fd */ { false, 0x77fd, 0x77fd }, +/* 0x77fe */ { false, 0x77fe, 0x77fe }, +/* 0x77ff */ { false, 0x77ff, 0x77ff }, +/* 0x7800 */ { false, 0x7800, 0x7800 }, +/* 0x7801 */ { false, 0x7801, 0x7801 }, +/* 0x7802 */ { false, 0x7802, 0x7802 }, +/* 0x7803 */ { false, 0x7803, 0x7803 }, +/* 0x7804 */ { false, 0x7804, 0x7804 }, +/* 0x7805 */ { false, 0x7805, 0x7805 }, +/* 0x7806 */ { false, 0x7806, 0x7806 }, +/* 0x7807 */ { false, 0x7807, 0x7807 }, +/* 0x7808 */ { false, 0x7808, 0x7808 }, +/* 0x7809 */ { false, 0x7809, 0x7809 }, +/* 0x780a */ { false, 0x780a, 0x780a }, +/* 0x780b */ { false, 0x780b, 0x780b }, +/* 0x780c */ { false, 0x780c, 0x780c }, +/* 0x780d */ { false, 0x780d, 0x780d }, +/* 0x780e */ { false, 0x780e, 0x780e }, +/* 0x780f */ { false, 0x780f, 0x780f }, +/* 0x7810 */ { false, 0x7810, 0x7810 }, +/* 0x7811 */ { false, 0x7811, 0x7811 }, +/* 0x7812 */ { false, 0x7812, 0x7812 }, +/* 0x7813 */ { false, 0x7813, 0x7813 }, +/* 0x7814 */ { false, 0x7814, 0x7814 }, +/* 0x7815 */ { false, 0x7815, 0x7815 }, +/* 0x7816 */ { false, 0x7816, 0x7816 }, +/* 0x7817 */ { false, 0x7817, 0x7817 }, +/* 0x7818 */ { false, 0x7818, 0x7818 }, +/* 0x7819 */ { false, 0x7819, 0x7819 }, +/* 0x781a */ { false, 0x781a, 0x781a }, +/* 0x781b */ { false, 0x781b, 0x781b }, +/* 0x781c */ { false, 0x781c, 0x781c }, +/* 0x781d */ { false, 0x781d, 0x781d }, +/* 0x781e */ { false, 0x781e, 0x781e }, +/* 0x781f */ { false, 0x781f, 0x781f }, +/* 0x7820 */ { false, 0x7820, 0x7820 }, +/* 0x7821 */ { false, 0x7821, 0x7821 }, +/* 0x7822 */ { false, 0x7822, 0x7822 }, +/* 0x7823 */ { false, 0x7823, 0x7823 }, +/* 0x7824 */ { false, 0x7824, 0x7824 }, +/* 0x7825 */ { false, 0x7825, 0x7825 }, +/* 0x7826 */ { false, 0x7826, 0x7826 }, +/* 0x7827 */ { false, 0x7827, 0x7827 }, +/* 0x7828 */ { false, 0x7828, 0x7828 }, +/* 0x7829 */ { false, 0x7829, 0x7829 }, +/* 0x782a */ { false, 0x782a, 0x782a }, +/* 0x782b */ { false, 0x782b, 0x782b }, +/* 0x782c */ { false, 0x782c, 0x782c }, +/* 0x782d */ { false, 0x782d, 0x782d }, +/* 0x782e */ { false, 0x782e, 0x782e }, +/* 0x782f */ { false, 0x782f, 0x782f }, +/* 0x7830 */ { false, 0x7830, 0x7830 }, +/* 0x7831 */ { false, 0x7831, 0x7831 }, +/* 0x7832 */ { false, 0x7832, 0x7832 }, +/* 0x7833 */ { false, 0x7833, 0x7833 }, +/* 0x7834 */ { false, 0x7834, 0x7834 }, +/* 0x7835 */ { false, 0x7835, 0x7835 }, +/* 0x7836 */ { false, 0x7836, 0x7836 }, +/* 0x7837 */ { false, 0x7837, 0x7837 }, +/* 0x7838 */ { false, 0x7838, 0x7838 }, +/* 0x7839 */ { false, 0x7839, 0x7839 }, +/* 0x783a */ { false, 0x783a, 0x783a }, +/* 0x783b */ { false, 0x783b, 0x783b }, +/* 0x783c */ { false, 0x783c, 0x783c }, +/* 0x783d */ { false, 0x783d, 0x783d }, +/* 0x783e */ { false, 0x783e, 0x783e }, +/* 0x783f */ { false, 0x783f, 0x783f }, +/* 0x7840 */ { false, 0x7840, 0x7840 }, +/* 0x7841 */ { false, 0x7841, 0x7841 }, +/* 0x7842 */ { false, 0x7842, 0x7842 }, +/* 0x7843 */ { false, 0x7843, 0x7843 }, +/* 0x7844 */ { false, 0x7844, 0x7844 }, +/* 0x7845 */ { false, 0x7845, 0x7845 }, +/* 0x7846 */ { false, 0x7846, 0x7846 }, +/* 0x7847 */ { false, 0x7847, 0x7847 }, +/* 0x7848 */ { false, 0x7848, 0x7848 }, +/* 0x7849 */ { false, 0x7849, 0x7849 }, +/* 0x784a */ { false, 0x784a, 0x784a }, +/* 0x784b */ { false, 0x784b, 0x784b }, +/* 0x784c */ { false, 0x784c, 0x784c }, +/* 0x784d */ { false, 0x784d, 0x784d }, +/* 0x784e */ { false, 0x784e, 0x784e }, +/* 0x784f */ { false, 0x784f, 0x784f }, +/* 0x7850 */ { false, 0x7850, 0x7850 }, +/* 0x7851 */ { false, 0x7851, 0x7851 }, +/* 0x7852 */ { false, 0x7852, 0x7852 }, +/* 0x7853 */ { false, 0x7853, 0x7853 }, +/* 0x7854 */ { false, 0x7854, 0x7854 }, +/* 0x7855 */ { false, 0x7855, 0x7855 }, +/* 0x7856 */ { false, 0x7856, 0x7856 }, +/* 0x7857 */ { false, 0x7857, 0x7857 }, +/* 0x7858 */ { false, 0x7858, 0x7858 }, +/* 0x7859 */ { false, 0x7859, 0x7859 }, +/* 0x785a */ { false, 0x785a, 0x785a }, +/* 0x785b */ { false, 0x785b, 0x785b }, +/* 0x785c */ { false, 0x785c, 0x785c }, +/* 0x785d */ { false, 0x785d, 0x785d }, +/* 0x785e */ { false, 0x785e, 0x785e }, +/* 0x785f */ { false, 0x785f, 0x785f }, +/* 0x7860 */ { false, 0x7860, 0x7860 }, +/* 0x7861 */ { false, 0x7861, 0x7861 }, +/* 0x7862 */ { false, 0x7862, 0x7862 }, +/* 0x7863 */ { false, 0x7863, 0x7863 }, +/* 0x7864 */ { false, 0x7864, 0x7864 }, +/* 0x7865 */ { false, 0x7865, 0x7865 }, +/* 0x7866 */ { false, 0x7866, 0x7866 }, +/* 0x7867 */ { false, 0x7867, 0x7867 }, +/* 0x7868 */ { false, 0x7868, 0x7868 }, +/* 0x7869 */ { false, 0x7869, 0x7869 }, +/* 0x786a */ { false, 0x786a, 0x786a }, +/* 0x786b */ { false, 0x786b, 0x786b }, +/* 0x786c */ { false, 0x786c, 0x786c }, +/* 0x786d */ { false, 0x786d, 0x786d }, +/* 0x786e */ { false, 0x786e, 0x786e }, +/* 0x786f */ { false, 0x786f, 0x786f }, +/* 0x7870 */ { false, 0x7870, 0x7870 }, +/* 0x7871 */ { false, 0x7871, 0x7871 }, +/* 0x7872 */ { false, 0x7872, 0x7872 }, +/* 0x7873 */ { false, 0x7873, 0x7873 }, +/* 0x7874 */ { false, 0x7874, 0x7874 }, +/* 0x7875 */ { false, 0x7875, 0x7875 }, +/* 0x7876 */ { false, 0x7876, 0x7876 }, +/* 0x7877 */ { false, 0x7877, 0x7877 }, +/* 0x7878 */ { false, 0x7878, 0x7878 }, +/* 0x7879 */ { false, 0x7879, 0x7879 }, +/* 0x787a */ { false, 0x787a, 0x787a }, +/* 0x787b */ { false, 0x787b, 0x787b }, +/* 0x787c */ { false, 0x787c, 0x787c }, +/* 0x787d */ { false, 0x787d, 0x787d }, +/* 0x787e */ { false, 0x787e, 0x787e }, +/* 0x787f */ { false, 0x787f, 0x787f }, +/* 0x7880 */ { false, 0x7880, 0x7880 }, +/* 0x7881 */ { false, 0x7881, 0x7881 }, +/* 0x7882 */ { false, 0x7882, 0x7882 }, +/* 0x7883 */ { false, 0x7883, 0x7883 }, +/* 0x7884 */ { false, 0x7884, 0x7884 }, +/* 0x7885 */ { false, 0x7885, 0x7885 }, +/* 0x7886 */ { false, 0x7886, 0x7886 }, +/* 0x7887 */ { false, 0x7887, 0x7887 }, +/* 0x7888 */ { false, 0x7888, 0x7888 }, +/* 0x7889 */ { false, 0x7889, 0x7889 }, +/* 0x788a */ { false, 0x788a, 0x788a }, +/* 0x788b */ { false, 0x788b, 0x788b }, +/* 0x788c */ { false, 0x788c, 0x788c }, +/* 0x788d */ { false, 0x788d, 0x788d }, +/* 0x788e */ { false, 0x788e, 0x788e }, +/* 0x788f */ { false, 0x788f, 0x788f }, +/* 0x7890 */ { false, 0x7890, 0x7890 }, +/* 0x7891 */ { false, 0x7891, 0x7891 }, +/* 0x7892 */ { false, 0x7892, 0x7892 }, +/* 0x7893 */ { false, 0x7893, 0x7893 }, +/* 0x7894 */ { false, 0x7894, 0x7894 }, +/* 0x7895 */ { false, 0x7895, 0x7895 }, +/* 0x7896 */ { false, 0x7896, 0x7896 }, +/* 0x7897 */ { false, 0x7897, 0x7897 }, +/* 0x7898 */ { false, 0x7898, 0x7898 }, +/* 0x7899 */ { false, 0x7899, 0x7899 }, +/* 0x789a */ { false, 0x789a, 0x789a }, +/* 0x789b */ { false, 0x789b, 0x789b }, +/* 0x789c */ { false, 0x789c, 0x789c }, +/* 0x789d */ { false, 0x789d, 0x789d }, +/* 0x789e */ { false, 0x789e, 0x789e }, +/* 0x789f */ { false, 0x789f, 0x789f }, +/* 0x78a0 */ { false, 0x78a0, 0x78a0 }, +/* 0x78a1 */ { false, 0x78a1, 0x78a1 }, +/* 0x78a2 */ { false, 0x78a2, 0x78a2 }, +/* 0x78a3 */ { false, 0x78a3, 0x78a3 }, +/* 0x78a4 */ { false, 0x78a4, 0x78a4 }, +/* 0x78a5 */ { false, 0x78a5, 0x78a5 }, +/* 0x78a6 */ { false, 0x78a6, 0x78a6 }, +/* 0x78a7 */ { false, 0x78a7, 0x78a7 }, +/* 0x78a8 */ { false, 0x78a8, 0x78a8 }, +/* 0x78a9 */ { false, 0x78a9, 0x78a9 }, +/* 0x78aa */ { false, 0x78aa, 0x78aa }, +/* 0x78ab */ { false, 0x78ab, 0x78ab }, +/* 0x78ac */ { false, 0x78ac, 0x78ac }, +/* 0x78ad */ { false, 0x78ad, 0x78ad }, +/* 0x78ae */ { false, 0x78ae, 0x78ae }, +/* 0x78af */ { false, 0x78af, 0x78af }, +/* 0x78b0 */ { false, 0x78b0, 0x78b0 }, +/* 0x78b1 */ { false, 0x78b1, 0x78b1 }, +/* 0x78b2 */ { false, 0x78b2, 0x78b2 }, +/* 0x78b3 */ { false, 0x78b3, 0x78b3 }, +/* 0x78b4 */ { false, 0x78b4, 0x78b4 }, +/* 0x78b5 */ { false, 0x78b5, 0x78b5 }, +/* 0x78b6 */ { false, 0x78b6, 0x78b6 }, +/* 0x78b7 */ { false, 0x78b7, 0x78b7 }, +/* 0x78b8 */ { false, 0x78b8, 0x78b8 }, +/* 0x78b9 */ { false, 0x78b9, 0x78b9 }, +/* 0x78ba */ { false, 0x78ba, 0x78ba }, +/* 0x78bb */ { false, 0x78bb, 0x78bb }, +/* 0x78bc */ { false, 0x78bc, 0x78bc }, +/* 0x78bd */ { false, 0x78bd, 0x78bd }, +/* 0x78be */ { false, 0x78be, 0x78be }, +/* 0x78bf */ { false, 0x78bf, 0x78bf }, +/* 0x78c0 */ { false, 0x78c0, 0x78c0 }, +/* 0x78c1 */ { false, 0x78c1, 0x78c1 }, +/* 0x78c2 */ { false, 0x78c2, 0x78c2 }, +/* 0x78c3 */ { false, 0x78c3, 0x78c3 }, +/* 0x78c4 */ { false, 0x78c4, 0x78c4 }, +/* 0x78c5 */ { false, 0x78c5, 0x78c5 }, +/* 0x78c6 */ { false, 0x78c6, 0x78c6 }, +/* 0x78c7 */ { false, 0x78c7, 0x78c7 }, +/* 0x78c8 */ { false, 0x78c8, 0x78c8 }, +/* 0x78c9 */ { false, 0x78c9, 0x78c9 }, +/* 0x78ca */ { false, 0x78ca, 0x78ca }, +/* 0x78cb */ { false, 0x78cb, 0x78cb }, +/* 0x78cc */ { false, 0x78cc, 0x78cc }, +/* 0x78cd */ { false, 0x78cd, 0x78cd }, +/* 0x78ce */ { false, 0x78ce, 0x78ce }, +/* 0x78cf */ { false, 0x78cf, 0x78cf }, +/* 0x78d0 */ { false, 0x78d0, 0x78d0 }, +/* 0x78d1 */ { false, 0x78d1, 0x78d1 }, +/* 0x78d2 */ { false, 0x78d2, 0x78d2 }, +/* 0x78d3 */ { false, 0x78d3, 0x78d3 }, +/* 0x78d4 */ { false, 0x78d4, 0x78d4 }, +/* 0x78d5 */ { false, 0x78d5, 0x78d5 }, +/* 0x78d6 */ { false, 0x78d6, 0x78d6 }, +/* 0x78d7 */ { false, 0x78d7, 0x78d7 }, +/* 0x78d8 */ { false, 0x78d8, 0x78d8 }, +/* 0x78d9 */ { false, 0x78d9, 0x78d9 }, +/* 0x78da */ { false, 0x78da, 0x78da }, +/* 0x78db */ { false, 0x78db, 0x78db }, +/* 0x78dc */ { false, 0x78dc, 0x78dc }, +/* 0x78dd */ { false, 0x78dd, 0x78dd }, +/* 0x78de */ { false, 0x78de, 0x78de }, +/* 0x78df */ { false, 0x78df, 0x78df }, +/* 0x78e0 */ { false, 0x78e0, 0x78e0 }, +/* 0x78e1 */ { false, 0x78e1, 0x78e1 }, +/* 0x78e2 */ { false, 0x78e2, 0x78e2 }, +/* 0x78e3 */ { false, 0x78e3, 0x78e3 }, +/* 0x78e4 */ { false, 0x78e4, 0x78e4 }, +/* 0x78e5 */ { false, 0x78e5, 0x78e5 }, +/* 0x78e6 */ { false, 0x78e6, 0x78e6 }, +/* 0x78e7 */ { false, 0x78e7, 0x78e7 }, +/* 0x78e8 */ { false, 0x78e8, 0x78e8 }, +/* 0x78e9 */ { false, 0x78e9, 0x78e9 }, +/* 0x78ea */ { false, 0x78ea, 0x78ea }, +/* 0x78eb */ { false, 0x78eb, 0x78eb }, +/* 0x78ec */ { false, 0x78ec, 0x78ec }, +/* 0x78ed */ { false, 0x78ed, 0x78ed }, +/* 0x78ee */ { false, 0x78ee, 0x78ee }, +/* 0x78ef */ { false, 0x78ef, 0x78ef }, +/* 0x78f0 */ { false, 0x78f0, 0x78f0 }, +/* 0x78f1 */ { false, 0x78f1, 0x78f1 }, +/* 0x78f2 */ { false, 0x78f2, 0x78f2 }, +/* 0x78f3 */ { false, 0x78f3, 0x78f3 }, +/* 0x78f4 */ { false, 0x78f4, 0x78f4 }, +/* 0x78f5 */ { false, 0x78f5, 0x78f5 }, +/* 0x78f6 */ { false, 0x78f6, 0x78f6 }, +/* 0x78f7 */ { false, 0x78f7, 0x78f7 }, +/* 0x78f8 */ { false, 0x78f8, 0x78f8 }, +/* 0x78f9 */ { false, 0x78f9, 0x78f9 }, +/* 0x78fa */ { false, 0x78fa, 0x78fa }, +/* 0x78fb */ { false, 0x78fb, 0x78fb }, +/* 0x78fc */ { false, 0x78fc, 0x78fc }, +/* 0x78fd */ { false, 0x78fd, 0x78fd }, +/* 0x78fe */ { false, 0x78fe, 0x78fe }, +/* 0x78ff */ { false, 0x78ff, 0x78ff }, +/* 0x7900 */ { false, 0x7900, 0x7900 }, +/* 0x7901 */ { false, 0x7901, 0x7901 }, +/* 0x7902 */ { false, 0x7902, 0x7902 }, +/* 0x7903 */ { false, 0x7903, 0x7903 }, +/* 0x7904 */ { false, 0x7904, 0x7904 }, +/* 0x7905 */ { false, 0x7905, 0x7905 }, +/* 0x7906 */ { false, 0x7906, 0x7906 }, +/* 0x7907 */ { false, 0x7907, 0x7907 }, +/* 0x7908 */ { false, 0x7908, 0x7908 }, +/* 0x7909 */ { false, 0x7909, 0x7909 }, +/* 0x790a */ { false, 0x790a, 0x790a }, +/* 0x790b */ { false, 0x790b, 0x790b }, +/* 0x790c */ { false, 0x790c, 0x790c }, +/* 0x790d */ { false, 0x790d, 0x790d }, +/* 0x790e */ { false, 0x790e, 0x790e }, +/* 0x790f */ { false, 0x790f, 0x790f }, +/* 0x7910 */ { false, 0x7910, 0x7910 }, +/* 0x7911 */ { false, 0x7911, 0x7911 }, +/* 0x7912 */ { false, 0x7912, 0x7912 }, +/* 0x7913 */ { false, 0x7913, 0x7913 }, +/* 0x7914 */ { false, 0x7914, 0x7914 }, +/* 0x7915 */ { false, 0x7915, 0x7915 }, +/* 0x7916 */ { false, 0x7916, 0x7916 }, +/* 0x7917 */ { false, 0x7917, 0x7917 }, +/* 0x7918 */ { false, 0x7918, 0x7918 }, +/* 0x7919 */ { false, 0x7919, 0x7919 }, +/* 0x791a */ { false, 0x791a, 0x791a }, +/* 0x791b */ { false, 0x791b, 0x791b }, +/* 0x791c */ { false, 0x791c, 0x791c }, +/* 0x791d */ { false, 0x791d, 0x791d }, +/* 0x791e */ { false, 0x791e, 0x791e }, +/* 0x791f */ { false, 0x791f, 0x791f }, +/* 0x7920 */ { false, 0x7920, 0x7920 }, +/* 0x7921 */ { false, 0x7921, 0x7921 }, +/* 0x7922 */ { false, 0x7922, 0x7922 }, +/* 0x7923 */ { false, 0x7923, 0x7923 }, +/* 0x7924 */ { false, 0x7924, 0x7924 }, +/* 0x7925 */ { false, 0x7925, 0x7925 }, +/* 0x7926 */ { false, 0x7926, 0x7926 }, +/* 0x7927 */ { false, 0x7927, 0x7927 }, +/* 0x7928 */ { false, 0x7928, 0x7928 }, +/* 0x7929 */ { false, 0x7929, 0x7929 }, +/* 0x792a */ { false, 0x792a, 0x792a }, +/* 0x792b */ { false, 0x792b, 0x792b }, +/* 0x792c */ { false, 0x792c, 0x792c }, +/* 0x792d */ { false, 0x792d, 0x792d }, +/* 0x792e */ { false, 0x792e, 0x792e }, +/* 0x792f */ { false, 0x792f, 0x792f }, +/* 0x7930 */ { false, 0x7930, 0x7930 }, +/* 0x7931 */ { false, 0x7931, 0x7931 }, +/* 0x7932 */ { false, 0x7932, 0x7932 }, +/* 0x7933 */ { false, 0x7933, 0x7933 }, +/* 0x7934 */ { false, 0x7934, 0x7934 }, +/* 0x7935 */ { false, 0x7935, 0x7935 }, +/* 0x7936 */ { false, 0x7936, 0x7936 }, +/* 0x7937 */ { false, 0x7937, 0x7937 }, +/* 0x7938 */ { false, 0x7938, 0x7938 }, +/* 0x7939 */ { false, 0x7939, 0x7939 }, +/* 0x793a */ { false, 0x793a, 0x793a }, +/* 0x793b */ { false, 0x793b, 0x793b }, +/* 0x793c */ { false, 0x793c, 0x793c }, +/* 0x793d */ { false, 0x793d, 0x793d }, +/* 0x793e */ { false, 0x793e, 0x793e }, +/* 0x793f */ { false, 0x793f, 0x793f }, +/* 0x7940 */ { false, 0x7940, 0x7940 }, +/* 0x7941 */ { false, 0x7941, 0x7941 }, +/* 0x7942 */ { false, 0x7942, 0x7942 }, +/* 0x7943 */ { false, 0x7943, 0x7943 }, +/* 0x7944 */ { false, 0x7944, 0x7944 }, +/* 0x7945 */ { false, 0x7945, 0x7945 }, +/* 0x7946 */ { false, 0x7946, 0x7946 }, +/* 0x7947 */ { false, 0x7947, 0x7947 }, +/* 0x7948 */ { false, 0x7948, 0x7948 }, +/* 0x7949 */ { false, 0x7949, 0x7949 }, +/* 0x794a */ { false, 0x794a, 0x794a }, +/* 0x794b */ { false, 0x794b, 0x794b }, +/* 0x794c */ { false, 0x794c, 0x794c }, +/* 0x794d */ { false, 0x794d, 0x794d }, +/* 0x794e */ { false, 0x794e, 0x794e }, +/* 0x794f */ { false, 0x794f, 0x794f }, +/* 0x7950 */ { false, 0x7950, 0x7950 }, +/* 0x7951 */ { false, 0x7951, 0x7951 }, +/* 0x7952 */ { false, 0x7952, 0x7952 }, +/* 0x7953 */ { false, 0x7953, 0x7953 }, +/* 0x7954 */ { false, 0x7954, 0x7954 }, +/* 0x7955 */ { false, 0x7955, 0x7955 }, +/* 0x7956 */ { false, 0x7956, 0x7956 }, +/* 0x7957 */ { false, 0x7957, 0x7957 }, +/* 0x7958 */ { false, 0x7958, 0x7958 }, +/* 0x7959 */ { false, 0x7959, 0x7959 }, +/* 0x795a */ { false, 0x795a, 0x795a }, +/* 0x795b */ { false, 0x795b, 0x795b }, +/* 0x795c */ { false, 0x795c, 0x795c }, +/* 0x795d */ { false, 0x795d, 0x795d }, +/* 0x795e */ { false, 0x795e, 0x795e }, +/* 0x795f */ { false, 0x795f, 0x795f }, +/* 0x7960 */ { false, 0x7960, 0x7960 }, +/* 0x7961 */ { false, 0x7961, 0x7961 }, +/* 0x7962 */ { false, 0x7962, 0x7962 }, +/* 0x7963 */ { false, 0x7963, 0x7963 }, +/* 0x7964 */ { false, 0x7964, 0x7964 }, +/* 0x7965 */ { false, 0x7965, 0x7965 }, +/* 0x7966 */ { false, 0x7966, 0x7966 }, +/* 0x7967 */ { false, 0x7967, 0x7967 }, +/* 0x7968 */ { false, 0x7968, 0x7968 }, +/* 0x7969 */ { false, 0x7969, 0x7969 }, +/* 0x796a */ { false, 0x796a, 0x796a }, +/* 0x796b */ { false, 0x796b, 0x796b }, +/* 0x796c */ { false, 0x796c, 0x796c }, +/* 0x796d */ { false, 0x796d, 0x796d }, +/* 0x796e */ { false, 0x796e, 0x796e }, +/* 0x796f */ { false, 0x796f, 0x796f }, +/* 0x7970 */ { false, 0x7970, 0x7970 }, +/* 0x7971 */ { false, 0x7971, 0x7971 }, +/* 0x7972 */ { false, 0x7972, 0x7972 }, +/* 0x7973 */ { false, 0x7973, 0x7973 }, +/* 0x7974 */ { false, 0x7974, 0x7974 }, +/* 0x7975 */ { false, 0x7975, 0x7975 }, +/* 0x7976 */ { false, 0x7976, 0x7976 }, +/* 0x7977 */ { false, 0x7977, 0x7977 }, +/* 0x7978 */ { false, 0x7978, 0x7978 }, +/* 0x7979 */ { false, 0x7979, 0x7979 }, +/* 0x797a */ { false, 0x797a, 0x797a }, +/* 0x797b */ { false, 0x797b, 0x797b }, +/* 0x797c */ { false, 0x797c, 0x797c }, +/* 0x797d */ { false, 0x797d, 0x797d }, +/* 0x797e */ { false, 0x797e, 0x797e }, +/* 0x797f */ { false, 0x797f, 0x797f }, +/* 0x7980 */ { false, 0x7980, 0x7980 }, +/* 0x7981 */ { false, 0x7981, 0x7981 }, +/* 0x7982 */ { false, 0x7982, 0x7982 }, +/* 0x7983 */ { false, 0x7983, 0x7983 }, +/* 0x7984 */ { false, 0x7984, 0x7984 }, +/* 0x7985 */ { false, 0x7985, 0x7985 }, +/* 0x7986 */ { false, 0x7986, 0x7986 }, +/* 0x7987 */ { false, 0x7987, 0x7987 }, +/* 0x7988 */ { false, 0x7988, 0x7988 }, +/* 0x7989 */ { false, 0x7989, 0x7989 }, +/* 0x798a */ { false, 0x798a, 0x798a }, +/* 0x798b */ { false, 0x798b, 0x798b }, +/* 0x798c */ { false, 0x798c, 0x798c }, +/* 0x798d */ { false, 0x798d, 0x798d }, +/* 0x798e */ { false, 0x798e, 0x798e }, +/* 0x798f */ { false, 0x798f, 0x798f }, +/* 0x7990 */ { false, 0x7990, 0x7990 }, +/* 0x7991 */ { false, 0x7991, 0x7991 }, +/* 0x7992 */ { false, 0x7992, 0x7992 }, +/* 0x7993 */ { false, 0x7993, 0x7993 }, +/* 0x7994 */ { false, 0x7994, 0x7994 }, +/* 0x7995 */ { false, 0x7995, 0x7995 }, +/* 0x7996 */ { false, 0x7996, 0x7996 }, +/* 0x7997 */ { false, 0x7997, 0x7997 }, +/* 0x7998 */ { false, 0x7998, 0x7998 }, +/* 0x7999 */ { false, 0x7999, 0x7999 }, +/* 0x799a */ { false, 0x799a, 0x799a }, +/* 0x799b */ { false, 0x799b, 0x799b }, +/* 0x799c */ { false, 0x799c, 0x799c }, +/* 0x799d */ { false, 0x799d, 0x799d }, +/* 0x799e */ { false, 0x799e, 0x799e }, +/* 0x799f */ { false, 0x799f, 0x799f }, +/* 0x79a0 */ { false, 0x79a0, 0x79a0 }, +/* 0x79a1 */ { false, 0x79a1, 0x79a1 }, +/* 0x79a2 */ { false, 0x79a2, 0x79a2 }, +/* 0x79a3 */ { false, 0x79a3, 0x79a3 }, +/* 0x79a4 */ { false, 0x79a4, 0x79a4 }, +/* 0x79a5 */ { false, 0x79a5, 0x79a5 }, +/* 0x79a6 */ { false, 0x79a6, 0x79a6 }, +/* 0x79a7 */ { false, 0x79a7, 0x79a7 }, +/* 0x79a8 */ { false, 0x79a8, 0x79a8 }, +/* 0x79a9 */ { false, 0x79a9, 0x79a9 }, +/* 0x79aa */ { false, 0x79aa, 0x79aa }, +/* 0x79ab */ { false, 0x79ab, 0x79ab }, +/* 0x79ac */ { false, 0x79ac, 0x79ac }, +/* 0x79ad */ { false, 0x79ad, 0x79ad }, +/* 0x79ae */ { false, 0x79ae, 0x79ae }, +/* 0x79af */ { false, 0x79af, 0x79af }, +/* 0x79b0 */ { false, 0x79b0, 0x79b0 }, +/* 0x79b1 */ { false, 0x79b1, 0x79b1 }, +/* 0x79b2 */ { false, 0x79b2, 0x79b2 }, +/* 0x79b3 */ { false, 0x79b3, 0x79b3 }, +/* 0x79b4 */ { false, 0x79b4, 0x79b4 }, +/* 0x79b5 */ { false, 0x79b5, 0x79b5 }, +/* 0x79b6 */ { false, 0x79b6, 0x79b6 }, +/* 0x79b7 */ { false, 0x79b7, 0x79b7 }, +/* 0x79b8 */ { false, 0x79b8, 0x79b8 }, +/* 0x79b9 */ { false, 0x79b9, 0x79b9 }, +/* 0x79ba */ { false, 0x79ba, 0x79ba }, +/* 0x79bb */ { false, 0x79bb, 0x79bb }, +/* 0x79bc */ { false, 0x79bc, 0x79bc }, +/* 0x79bd */ { false, 0x79bd, 0x79bd }, +/* 0x79be */ { false, 0x79be, 0x79be }, +/* 0x79bf */ { false, 0x79bf, 0x79bf }, +/* 0x79c0 */ { false, 0x79c0, 0x79c0 }, +/* 0x79c1 */ { false, 0x79c1, 0x79c1 }, +/* 0x79c2 */ { false, 0x79c2, 0x79c2 }, +/* 0x79c3 */ { false, 0x79c3, 0x79c3 }, +/* 0x79c4 */ { false, 0x79c4, 0x79c4 }, +/* 0x79c5 */ { false, 0x79c5, 0x79c5 }, +/* 0x79c6 */ { false, 0x79c6, 0x79c6 }, +/* 0x79c7 */ { false, 0x79c7, 0x79c7 }, +/* 0x79c8 */ { false, 0x79c8, 0x79c8 }, +/* 0x79c9 */ { false, 0x79c9, 0x79c9 }, +/* 0x79ca */ { false, 0x79ca, 0x79ca }, +/* 0x79cb */ { false, 0x79cb, 0x79cb }, +/* 0x79cc */ { false, 0x79cc, 0x79cc }, +/* 0x79cd */ { false, 0x79cd, 0x79cd }, +/* 0x79ce */ { false, 0x79ce, 0x79ce }, +/* 0x79cf */ { false, 0x79cf, 0x79cf }, +/* 0x79d0 */ { false, 0x79d0, 0x79d0 }, +/* 0x79d1 */ { false, 0x79d1, 0x79d1 }, +/* 0x79d2 */ { false, 0x79d2, 0x79d2 }, +/* 0x79d3 */ { false, 0x79d3, 0x79d3 }, +/* 0x79d4 */ { false, 0x79d4, 0x79d4 }, +/* 0x79d5 */ { false, 0x79d5, 0x79d5 }, +/* 0x79d6 */ { false, 0x79d6, 0x79d6 }, +/* 0x79d7 */ { false, 0x79d7, 0x79d7 }, +/* 0x79d8 */ { false, 0x79d8, 0x79d8 }, +/* 0x79d9 */ { false, 0x79d9, 0x79d9 }, +/* 0x79da */ { false, 0x79da, 0x79da }, +/* 0x79db */ { false, 0x79db, 0x79db }, +/* 0x79dc */ { false, 0x79dc, 0x79dc }, +/* 0x79dd */ { false, 0x79dd, 0x79dd }, +/* 0x79de */ { false, 0x79de, 0x79de }, +/* 0x79df */ { false, 0x79df, 0x79df }, +/* 0x79e0 */ { false, 0x79e0, 0x79e0 }, +/* 0x79e1 */ { false, 0x79e1, 0x79e1 }, +/* 0x79e2 */ { false, 0x79e2, 0x79e2 }, +/* 0x79e3 */ { false, 0x79e3, 0x79e3 }, +/* 0x79e4 */ { false, 0x79e4, 0x79e4 }, +/* 0x79e5 */ { false, 0x79e5, 0x79e5 }, +/* 0x79e6 */ { false, 0x79e6, 0x79e6 }, +/* 0x79e7 */ { false, 0x79e7, 0x79e7 }, +/* 0x79e8 */ { false, 0x79e8, 0x79e8 }, +/* 0x79e9 */ { false, 0x79e9, 0x79e9 }, +/* 0x79ea */ { false, 0x79ea, 0x79ea }, +/* 0x79eb */ { false, 0x79eb, 0x79eb }, +/* 0x79ec */ { false, 0x79ec, 0x79ec }, +/* 0x79ed */ { false, 0x79ed, 0x79ed }, +/* 0x79ee */ { false, 0x79ee, 0x79ee }, +/* 0x79ef */ { false, 0x79ef, 0x79ef }, +/* 0x79f0 */ { false, 0x79f0, 0x79f0 }, +/* 0x79f1 */ { false, 0x79f1, 0x79f1 }, +/* 0x79f2 */ { false, 0x79f2, 0x79f2 }, +/* 0x79f3 */ { false, 0x79f3, 0x79f3 }, +/* 0x79f4 */ { false, 0x79f4, 0x79f4 }, +/* 0x79f5 */ { false, 0x79f5, 0x79f5 }, +/* 0x79f6 */ { false, 0x79f6, 0x79f6 }, +/* 0x79f7 */ { false, 0x79f7, 0x79f7 }, +/* 0x79f8 */ { false, 0x79f8, 0x79f8 }, +/* 0x79f9 */ { false, 0x79f9, 0x79f9 }, +/* 0x79fa */ { false, 0x79fa, 0x79fa }, +/* 0x79fb */ { false, 0x79fb, 0x79fb }, +/* 0x79fc */ { false, 0x79fc, 0x79fc }, +/* 0x79fd */ { false, 0x79fd, 0x79fd }, +/* 0x79fe */ { false, 0x79fe, 0x79fe }, +/* 0x79ff */ { false, 0x79ff, 0x79ff }, +/* 0x7a00 */ { false, 0x7a00, 0x7a00 }, +/* 0x7a01 */ { false, 0x7a01, 0x7a01 }, +/* 0x7a02 */ { false, 0x7a02, 0x7a02 }, +/* 0x7a03 */ { false, 0x7a03, 0x7a03 }, +/* 0x7a04 */ { false, 0x7a04, 0x7a04 }, +/* 0x7a05 */ { false, 0x7a05, 0x7a05 }, +/* 0x7a06 */ { false, 0x7a06, 0x7a06 }, +/* 0x7a07 */ { false, 0x7a07, 0x7a07 }, +/* 0x7a08 */ { false, 0x7a08, 0x7a08 }, +/* 0x7a09 */ { false, 0x7a09, 0x7a09 }, +/* 0x7a0a */ { false, 0x7a0a, 0x7a0a }, +/* 0x7a0b */ { false, 0x7a0b, 0x7a0b }, +/* 0x7a0c */ { false, 0x7a0c, 0x7a0c }, +/* 0x7a0d */ { false, 0x7a0d, 0x7a0d }, +/* 0x7a0e */ { false, 0x7a0e, 0x7a0e }, +/* 0x7a0f */ { false, 0x7a0f, 0x7a0f }, +/* 0x7a10 */ { false, 0x7a10, 0x7a10 }, +/* 0x7a11 */ { false, 0x7a11, 0x7a11 }, +/* 0x7a12 */ { false, 0x7a12, 0x7a12 }, +/* 0x7a13 */ { false, 0x7a13, 0x7a13 }, +/* 0x7a14 */ { false, 0x7a14, 0x7a14 }, +/* 0x7a15 */ { false, 0x7a15, 0x7a15 }, +/* 0x7a16 */ { false, 0x7a16, 0x7a16 }, +/* 0x7a17 */ { false, 0x7a17, 0x7a17 }, +/* 0x7a18 */ { false, 0x7a18, 0x7a18 }, +/* 0x7a19 */ { false, 0x7a19, 0x7a19 }, +/* 0x7a1a */ { false, 0x7a1a, 0x7a1a }, +/* 0x7a1b */ { false, 0x7a1b, 0x7a1b }, +/* 0x7a1c */ { false, 0x7a1c, 0x7a1c }, +/* 0x7a1d */ { false, 0x7a1d, 0x7a1d }, +/* 0x7a1e */ { false, 0x7a1e, 0x7a1e }, +/* 0x7a1f */ { false, 0x7a1f, 0x7a1f }, +/* 0x7a20 */ { false, 0x7a20, 0x7a20 }, +/* 0x7a21 */ { false, 0x7a21, 0x7a21 }, +/* 0x7a22 */ { false, 0x7a22, 0x7a22 }, +/* 0x7a23 */ { false, 0x7a23, 0x7a23 }, +/* 0x7a24 */ { false, 0x7a24, 0x7a24 }, +/* 0x7a25 */ { false, 0x7a25, 0x7a25 }, +/* 0x7a26 */ { false, 0x7a26, 0x7a26 }, +/* 0x7a27 */ { false, 0x7a27, 0x7a27 }, +/* 0x7a28 */ { false, 0x7a28, 0x7a28 }, +/* 0x7a29 */ { false, 0x7a29, 0x7a29 }, +/* 0x7a2a */ { false, 0x7a2a, 0x7a2a }, +/* 0x7a2b */ { false, 0x7a2b, 0x7a2b }, +/* 0x7a2c */ { false, 0x7a2c, 0x7a2c }, +/* 0x7a2d */ { false, 0x7a2d, 0x7a2d }, +/* 0x7a2e */ { false, 0x7a2e, 0x7a2e }, +/* 0x7a2f */ { false, 0x7a2f, 0x7a2f }, +/* 0x7a30 */ { false, 0x7a30, 0x7a30 }, +/* 0x7a31 */ { false, 0x7a31, 0x7a31 }, +/* 0x7a32 */ { false, 0x7a32, 0x7a32 }, +/* 0x7a33 */ { false, 0x7a33, 0x7a33 }, +/* 0x7a34 */ { false, 0x7a34, 0x7a34 }, +/* 0x7a35 */ { false, 0x7a35, 0x7a35 }, +/* 0x7a36 */ { false, 0x7a36, 0x7a36 }, +/* 0x7a37 */ { false, 0x7a37, 0x7a37 }, +/* 0x7a38 */ { false, 0x7a38, 0x7a38 }, +/* 0x7a39 */ { false, 0x7a39, 0x7a39 }, +/* 0x7a3a */ { false, 0x7a3a, 0x7a3a }, +/* 0x7a3b */ { false, 0x7a3b, 0x7a3b }, +/* 0x7a3c */ { false, 0x7a3c, 0x7a3c }, +/* 0x7a3d */ { false, 0x7a3d, 0x7a3d }, +/* 0x7a3e */ { false, 0x7a3e, 0x7a3e }, +/* 0x7a3f */ { false, 0x7a3f, 0x7a3f }, +/* 0x7a40 */ { false, 0x7a40, 0x7a40 }, +/* 0x7a41 */ { false, 0x7a41, 0x7a41 }, +/* 0x7a42 */ { false, 0x7a42, 0x7a42 }, +/* 0x7a43 */ { false, 0x7a43, 0x7a43 }, +/* 0x7a44 */ { false, 0x7a44, 0x7a44 }, +/* 0x7a45 */ { false, 0x7a45, 0x7a45 }, +/* 0x7a46 */ { false, 0x7a46, 0x7a46 }, +/* 0x7a47 */ { false, 0x7a47, 0x7a47 }, +/* 0x7a48 */ { false, 0x7a48, 0x7a48 }, +/* 0x7a49 */ { false, 0x7a49, 0x7a49 }, +/* 0x7a4a */ { false, 0x7a4a, 0x7a4a }, +/* 0x7a4b */ { false, 0x7a4b, 0x7a4b }, +/* 0x7a4c */ { false, 0x7a4c, 0x7a4c }, +/* 0x7a4d */ { false, 0x7a4d, 0x7a4d }, +/* 0x7a4e */ { false, 0x7a4e, 0x7a4e }, +/* 0x7a4f */ { false, 0x7a4f, 0x7a4f }, +/* 0x7a50 */ { false, 0x7a50, 0x7a50 }, +/* 0x7a51 */ { false, 0x7a51, 0x7a51 }, +/* 0x7a52 */ { false, 0x7a52, 0x7a52 }, +/* 0x7a53 */ { false, 0x7a53, 0x7a53 }, +/* 0x7a54 */ { false, 0x7a54, 0x7a54 }, +/* 0x7a55 */ { false, 0x7a55, 0x7a55 }, +/* 0x7a56 */ { false, 0x7a56, 0x7a56 }, +/* 0x7a57 */ { false, 0x7a57, 0x7a57 }, +/* 0x7a58 */ { false, 0x7a58, 0x7a58 }, +/* 0x7a59 */ { false, 0x7a59, 0x7a59 }, +/* 0x7a5a */ { false, 0x7a5a, 0x7a5a }, +/* 0x7a5b */ { false, 0x7a5b, 0x7a5b }, +/* 0x7a5c */ { false, 0x7a5c, 0x7a5c }, +/* 0x7a5d */ { false, 0x7a5d, 0x7a5d }, +/* 0x7a5e */ { false, 0x7a5e, 0x7a5e }, +/* 0x7a5f */ { false, 0x7a5f, 0x7a5f }, +/* 0x7a60 */ { false, 0x7a60, 0x7a60 }, +/* 0x7a61 */ { false, 0x7a61, 0x7a61 }, +/* 0x7a62 */ { false, 0x7a62, 0x7a62 }, +/* 0x7a63 */ { false, 0x7a63, 0x7a63 }, +/* 0x7a64 */ { false, 0x7a64, 0x7a64 }, +/* 0x7a65 */ { false, 0x7a65, 0x7a65 }, +/* 0x7a66 */ { false, 0x7a66, 0x7a66 }, +/* 0x7a67 */ { false, 0x7a67, 0x7a67 }, +/* 0x7a68 */ { false, 0x7a68, 0x7a68 }, +/* 0x7a69 */ { false, 0x7a69, 0x7a69 }, +/* 0x7a6a */ { false, 0x7a6a, 0x7a6a }, +/* 0x7a6b */ { false, 0x7a6b, 0x7a6b }, +/* 0x7a6c */ { false, 0x7a6c, 0x7a6c }, +/* 0x7a6d */ { false, 0x7a6d, 0x7a6d }, +/* 0x7a6e */ { false, 0x7a6e, 0x7a6e }, +/* 0x7a6f */ { false, 0x7a6f, 0x7a6f }, +/* 0x7a70 */ { false, 0x7a70, 0x7a70 }, +/* 0x7a71 */ { false, 0x7a71, 0x7a71 }, +/* 0x7a72 */ { false, 0x7a72, 0x7a72 }, +/* 0x7a73 */ { false, 0x7a73, 0x7a73 }, +/* 0x7a74 */ { false, 0x7a74, 0x7a74 }, +/* 0x7a75 */ { false, 0x7a75, 0x7a75 }, +/* 0x7a76 */ { false, 0x7a76, 0x7a76 }, +/* 0x7a77 */ { false, 0x7a77, 0x7a77 }, +/* 0x7a78 */ { false, 0x7a78, 0x7a78 }, +/* 0x7a79 */ { false, 0x7a79, 0x7a79 }, +/* 0x7a7a */ { false, 0x7a7a, 0x7a7a }, +/* 0x7a7b */ { false, 0x7a7b, 0x7a7b }, +/* 0x7a7c */ { false, 0x7a7c, 0x7a7c }, +/* 0x7a7d */ { false, 0x7a7d, 0x7a7d }, +/* 0x7a7e */ { false, 0x7a7e, 0x7a7e }, +/* 0x7a7f */ { false, 0x7a7f, 0x7a7f }, +/* 0x7a80 */ { false, 0x7a80, 0x7a80 }, +/* 0x7a81 */ { false, 0x7a81, 0x7a81 }, +/* 0x7a82 */ { false, 0x7a82, 0x7a82 }, +/* 0x7a83 */ { false, 0x7a83, 0x7a83 }, +/* 0x7a84 */ { false, 0x7a84, 0x7a84 }, +/* 0x7a85 */ { false, 0x7a85, 0x7a85 }, +/* 0x7a86 */ { false, 0x7a86, 0x7a86 }, +/* 0x7a87 */ { false, 0x7a87, 0x7a87 }, +/* 0x7a88 */ { false, 0x7a88, 0x7a88 }, +/* 0x7a89 */ { false, 0x7a89, 0x7a89 }, +/* 0x7a8a */ { false, 0x7a8a, 0x7a8a }, +/* 0x7a8b */ { false, 0x7a8b, 0x7a8b }, +/* 0x7a8c */ { false, 0x7a8c, 0x7a8c }, +/* 0x7a8d */ { false, 0x7a8d, 0x7a8d }, +/* 0x7a8e */ { false, 0x7a8e, 0x7a8e }, +/* 0x7a8f */ { false, 0x7a8f, 0x7a8f }, +/* 0x7a90 */ { false, 0x7a90, 0x7a90 }, +/* 0x7a91 */ { false, 0x7a91, 0x7a91 }, +/* 0x7a92 */ { false, 0x7a92, 0x7a92 }, +/* 0x7a93 */ { false, 0x7a93, 0x7a93 }, +/* 0x7a94 */ { false, 0x7a94, 0x7a94 }, +/* 0x7a95 */ { false, 0x7a95, 0x7a95 }, +/* 0x7a96 */ { false, 0x7a96, 0x7a96 }, +/* 0x7a97 */ { false, 0x7a97, 0x7a97 }, +/* 0x7a98 */ { false, 0x7a98, 0x7a98 }, +/* 0x7a99 */ { false, 0x7a99, 0x7a99 }, +/* 0x7a9a */ { false, 0x7a9a, 0x7a9a }, +/* 0x7a9b */ { false, 0x7a9b, 0x7a9b }, +/* 0x7a9c */ { false, 0x7a9c, 0x7a9c }, +/* 0x7a9d */ { false, 0x7a9d, 0x7a9d }, +/* 0x7a9e */ { false, 0x7a9e, 0x7a9e }, +/* 0x7a9f */ { false, 0x7a9f, 0x7a9f }, +/* 0x7aa0 */ { false, 0x7aa0, 0x7aa0 }, +/* 0x7aa1 */ { false, 0x7aa1, 0x7aa1 }, +/* 0x7aa2 */ { false, 0x7aa2, 0x7aa2 }, +/* 0x7aa3 */ { false, 0x7aa3, 0x7aa3 }, +/* 0x7aa4 */ { false, 0x7aa4, 0x7aa4 }, +/* 0x7aa5 */ { false, 0x7aa5, 0x7aa5 }, +/* 0x7aa6 */ { false, 0x7aa6, 0x7aa6 }, +/* 0x7aa7 */ { false, 0x7aa7, 0x7aa7 }, +/* 0x7aa8 */ { false, 0x7aa8, 0x7aa8 }, +/* 0x7aa9 */ { false, 0x7aa9, 0x7aa9 }, +/* 0x7aaa */ { false, 0x7aaa, 0x7aaa }, +/* 0x7aab */ { false, 0x7aab, 0x7aab }, +/* 0x7aac */ { false, 0x7aac, 0x7aac }, +/* 0x7aad */ { false, 0x7aad, 0x7aad }, +/* 0x7aae */ { false, 0x7aae, 0x7aae }, +/* 0x7aaf */ { false, 0x7aaf, 0x7aaf }, +/* 0x7ab0 */ { false, 0x7ab0, 0x7ab0 }, +/* 0x7ab1 */ { false, 0x7ab1, 0x7ab1 }, +/* 0x7ab2 */ { false, 0x7ab2, 0x7ab2 }, +/* 0x7ab3 */ { false, 0x7ab3, 0x7ab3 }, +/* 0x7ab4 */ { false, 0x7ab4, 0x7ab4 }, +/* 0x7ab5 */ { false, 0x7ab5, 0x7ab5 }, +/* 0x7ab6 */ { false, 0x7ab6, 0x7ab6 }, +/* 0x7ab7 */ { false, 0x7ab7, 0x7ab7 }, +/* 0x7ab8 */ { false, 0x7ab8, 0x7ab8 }, +/* 0x7ab9 */ { false, 0x7ab9, 0x7ab9 }, +/* 0x7aba */ { false, 0x7aba, 0x7aba }, +/* 0x7abb */ { false, 0x7abb, 0x7abb }, +/* 0x7abc */ { false, 0x7abc, 0x7abc }, +/* 0x7abd */ { false, 0x7abd, 0x7abd }, +/* 0x7abe */ { false, 0x7abe, 0x7abe }, +/* 0x7abf */ { false, 0x7abf, 0x7abf }, +/* 0x7ac0 */ { false, 0x7ac0, 0x7ac0 }, +/* 0x7ac1 */ { false, 0x7ac1, 0x7ac1 }, +/* 0x7ac2 */ { false, 0x7ac2, 0x7ac2 }, +/* 0x7ac3 */ { false, 0x7ac3, 0x7ac3 }, +/* 0x7ac4 */ { false, 0x7ac4, 0x7ac4 }, +/* 0x7ac5 */ { false, 0x7ac5, 0x7ac5 }, +/* 0x7ac6 */ { false, 0x7ac6, 0x7ac6 }, +/* 0x7ac7 */ { false, 0x7ac7, 0x7ac7 }, +/* 0x7ac8 */ { false, 0x7ac8, 0x7ac8 }, +/* 0x7ac9 */ { false, 0x7ac9, 0x7ac9 }, +/* 0x7aca */ { false, 0x7aca, 0x7aca }, +/* 0x7acb */ { false, 0x7acb, 0x7acb }, +/* 0x7acc */ { false, 0x7acc, 0x7acc }, +/* 0x7acd */ { false, 0x7acd, 0x7acd }, +/* 0x7ace */ { false, 0x7ace, 0x7ace }, +/* 0x7acf */ { false, 0x7acf, 0x7acf }, +/* 0x7ad0 */ { false, 0x7ad0, 0x7ad0 }, +/* 0x7ad1 */ { false, 0x7ad1, 0x7ad1 }, +/* 0x7ad2 */ { false, 0x7ad2, 0x7ad2 }, +/* 0x7ad3 */ { false, 0x7ad3, 0x7ad3 }, +/* 0x7ad4 */ { false, 0x7ad4, 0x7ad4 }, +/* 0x7ad5 */ { false, 0x7ad5, 0x7ad5 }, +/* 0x7ad6 */ { false, 0x7ad6, 0x7ad6 }, +/* 0x7ad7 */ { false, 0x7ad7, 0x7ad7 }, +/* 0x7ad8 */ { false, 0x7ad8, 0x7ad8 }, +/* 0x7ad9 */ { false, 0x7ad9, 0x7ad9 }, +/* 0x7ada */ { false, 0x7ada, 0x7ada }, +/* 0x7adb */ { false, 0x7adb, 0x7adb }, +/* 0x7adc */ { false, 0x7adc, 0x7adc }, +/* 0x7add */ { false, 0x7add, 0x7add }, +/* 0x7ade */ { false, 0x7ade, 0x7ade }, +/* 0x7adf */ { false, 0x7adf, 0x7adf }, +/* 0x7ae0 */ { false, 0x7ae0, 0x7ae0 }, +/* 0x7ae1 */ { false, 0x7ae1, 0x7ae1 }, +/* 0x7ae2 */ { false, 0x7ae2, 0x7ae2 }, +/* 0x7ae3 */ { false, 0x7ae3, 0x7ae3 }, +/* 0x7ae4 */ { false, 0x7ae4, 0x7ae4 }, +/* 0x7ae5 */ { false, 0x7ae5, 0x7ae5 }, +/* 0x7ae6 */ { false, 0x7ae6, 0x7ae6 }, +/* 0x7ae7 */ { false, 0x7ae7, 0x7ae7 }, +/* 0x7ae8 */ { false, 0x7ae8, 0x7ae8 }, +/* 0x7ae9 */ { false, 0x7ae9, 0x7ae9 }, +/* 0x7aea */ { false, 0x7aea, 0x7aea }, +/* 0x7aeb */ { false, 0x7aeb, 0x7aeb }, +/* 0x7aec */ { false, 0x7aec, 0x7aec }, +/* 0x7aed */ { false, 0x7aed, 0x7aed }, +/* 0x7aee */ { false, 0x7aee, 0x7aee }, +/* 0x7aef */ { false, 0x7aef, 0x7aef }, +/* 0x7af0 */ { false, 0x7af0, 0x7af0 }, +/* 0x7af1 */ { false, 0x7af1, 0x7af1 }, +/* 0x7af2 */ { false, 0x7af2, 0x7af2 }, +/* 0x7af3 */ { false, 0x7af3, 0x7af3 }, +/* 0x7af4 */ { false, 0x7af4, 0x7af4 }, +/* 0x7af5 */ { false, 0x7af5, 0x7af5 }, +/* 0x7af6 */ { false, 0x7af6, 0x7af6 }, +/* 0x7af7 */ { false, 0x7af7, 0x7af7 }, +/* 0x7af8 */ { false, 0x7af8, 0x7af8 }, +/* 0x7af9 */ { false, 0x7af9, 0x7af9 }, +/* 0x7afa */ { false, 0x7afa, 0x7afa }, +/* 0x7afb */ { false, 0x7afb, 0x7afb }, +/* 0x7afc */ { false, 0x7afc, 0x7afc }, +/* 0x7afd */ { false, 0x7afd, 0x7afd }, +/* 0x7afe */ { false, 0x7afe, 0x7afe }, +/* 0x7aff */ { false, 0x7aff, 0x7aff }, +/* 0x7b00 */ { false, 0x7b00, 0x7b00 }, +/* 0x7b01 */ { false, 0x7b01, 0x7b01 }, +/* 0x7b02 */ { false, 0x7b02, 0x7b02 }, +/* 0x7b03 */ { false, 0x7b03, 0x7b03 }, +/* 0x7b04 */ { false, 0x7b04, 0x7b04 }, +/* 0x7b05 */ { false, 0x7b05, 0x7b05 }, +/* 0x7b06 */ { false, 0x7b06, 0x7b06 }, +/* 0x7b07 */ { false, 0x7b07, 0x7b07 }, +/* 0x7b08 */ { false, 0x7b08, 0x7b08 }, +/* 0x7b09 */ { false, 0x7b09, 0x7b09 }, +/* 0x7b0a */ { false, 0x7b0a, 0x7b0a }, +/* 0x7b0b */ { false, 0x7b0b, 0x7b0b }, +/* 0x7b0c */ { false, 0x7b0c, 0x7b0c }, +/* 0x7b0d */ { false, 0x7b0d, 0x7b0d }, +/* 0x7b0e */ { false, 0x7b0e, 0x7b0e }, +/* 0x7b0f */ { false, 0x7b0f, 0x7b0f }, +/* 0x7b10 */ { false, 0x7b10, 0x7b10 }, +/* 0x7b11 */ { false, 0x7b11, 0x7b11 }, +/* 0x7b12 */ { false, 0x7b12, 0x7b12 }, +/* 0x7b13 */ { false, 0x7b13, 0x7b13 }, +/* 0x7b14 */ { false, 0x7b14, 0x7b14 }, +/* 0x7b15 */ { false, 0x7b15, 0x7b15 }, +/* 0x7b16 */ { false, 0x7b16, 0x7b16 }, +/* 0x7b17 */ { false, 0x7b17, 0x7b17 }, +/* 0x7b18 */ { false, 0x7b18, 0x7b18 }, +/* 0x7b19 */ { false, 0x7b19, 0x7b19 }, +/* 0x7b1a */ { false, 0x7b1a, 0x7b1a }, +/* 0x7b1b */ { false, 0x7b1b, 0x7b1b }, +/* 0x7b1c */ { false, 0x7b1c, 0x7b1c }, +/* 0x7b1d */ { false, 0x7b1d, 0x7b1d }, +/* 0x7b1e */ { false, 0x7b1e, 0x7b1e }, +/* 0x7b1f */ { false, 0x7b1f, 0x7b1f }, +/* 0x7b20 */ { false, 0x7b20, 0x7b20 }, +/* 0x7b21 */ { false, 0x7b21, 0x7b21 }, +/* 0x7b22 */ { false, 0x7b22, 0x7b22 }, +/* 0x7b23 */ { false, 0x7b23, 0x7b23 }, +/* 0x7b24 */ { false, 0x7b24, 0x7b24 }, +/* 0x7b25 */ { false, 0x7b25, 0x7b25 }, +/* 0x7b26 */ { false, 0x7b26, 0x7b26 }, +/* 0x7b27 */ { false, 0x7b27, 0x7b27 }, +/* 0x7b28 */ { false, 0x7b28, 0x7b28 }, +/* 0x7b29 */ { false, 0x7b29, 0x7b29 }, +/* 0x7b2a */ { false, 0x7b2a, 0x7b2a }, +/* 0x7b2b */ { false, 0x7b2b, 0x7b2b }, +/* 0x7b2c */ { false, 0x7b2c, 0x7b2c }, +/* 0x7b2d */ { false, 0x7b2d, 0x7b2d }, +/* 0x7b2e */ { false, 0x7b2e, 0x7b2e }, +/* 0x7b2f */ { false, 0x7b2f, 0x7b2f }, +/* 0x7b30 */ { false, 0x7b30, 0x7b30 }, +/* 0x7b31 */ { false, 0x7b31, 0x7b31 }, +/* 0x7b32 */ { false, 0x7b32, 0x7b32 }, +/* 0x7b33 */ { false, 0x7b33, 0x7b33 }, +/* 0x7b34 */ { false, 0x7b34, 0x7b34 }, +/* 0x7b35 */ { false, 0x7b35, 0x7b35 }, +/* 0x7b36 */ { false, 0x7b36, 0x7b36 }, +/* 0x7b37 */ { false, 0x7b37, 0x7b37 }, +/* 0x7b38 */ { false, 0x7b38, 0x7b38 }, +/* 0x7b39 */ { false, 0x7b39, 0x7b39 }, +/* 0x7b3a */ { false, 0x7b3a, 0x7b3a }, +/* 0x7b3b */ { false, 0x7b3b, 0x7b3b }, +/* 0x7b3c */ { false, 0x7b3c, 0x7b3c }, +/* 0x7b3d */ { false, 0x7b3d, 0x7b3d }, +/* 0x7b3e */ { false, 0x7b3e, 0x7b3e }, +/* 0x7b3f */ { false, 0x7b3f, 0x7b3f }, +/* 0x7b40 */ { false, 0x7b40, 0x7b40 }, +/* 0x7b41 */ { false, 0x7b41, 0x7b41 }, +/* 0x7b42 */ { false, 0x7b42, 0x7b42 }, +/* 0x7b43 */ { false, 0x7b43, 0x7b43 }, +/* 0x7b44 */ { false, 0x7b44, 0x7b44 }, +/* 0x7b45 */ { false, 0x7b45, 0x7b45 }, +/* 0x7b46 */ { false, 0x7b46, 0x7b46 }, +/* 0x7b47 */ { false, 0x7b47, 0x7b47 }, +/* 0x7b48 */ { false, 0x7b48, 0x7b48 }, +/* 0x7b49 */ { false, 0x7b49, 0x7b49 }, +/* 0x7b4a */ { false, 0x7b4a, 0x7b4a }, +/* 0x7b4b */ { false, 0x7b4b, 0x7b4b }, +/* 0x7b4c */ { false, 0x7b4c, 0x7b4c }, +/* 0x7b4d */ { false, 0x7b4d, 0x7b4d }, +/* 0x7b4e */ { false, 0x7b4e, 0x7b4e }, +/* 0x7b4f */ { false, 0x7b4f, 0x7b4f }, +/* 0x7b50 */ { false, 0x7b50, 0x7b50 }, +/* 0x7b51 */ { false, 0x7b51, 0x7b51 }, +/* 0x7b52 */ { false, 0x7b52, 0x7b52 }, +/* 0x7b53 */ { false, 0x7b53, 0x7b53 }, +/* 0x7b54 */ { false, 0x7b54, 0x7b54 }, +/* 0x7b55 */ { false, 0x7b55, 0x7b55 }, +/* 0x7b56 */ { false, 0x7b56, 0x7b56 }, +/* 0x7b57 */ { false, 0x7b57, 0x7b57 }, +/* 0x7b58 */ { false, 0x7b58, 0x7b58 }, +/* 0x7b59 */ { false, 0x7b59, 0x7b59 }, +/* 0x7b5a */ { false, 0x7b5a, 0x7b5a }, +/* 0x7b5b */ { false, 0x7b5b, 0x7b5b }, +/* 0x7b5c */ { false, 0x7b5c, 0x7b5c }, +/* 0x7b5d */ { false, 0x7b5d, 0x7b5d }, +/* 0x7b5e */ { false, 0x7b5e, 0x7b5e }, +/* 0x7b5f */ { false, 0x7b5f, 0x7b5f }, +/* 0x7b60 */ { false, 0x7b60, 0x7b60 }, +/* 0x7b61 */ { false, 0x7b61, 0x7b61 }, +/* 0x7b62 */ { false, 0x7b62, 0x7b62 }, +/* 0x7b63 */ { false, 0x7b63, 0x7b63 }, +/* 0x7b64 */ { false, 0x7b64, 0x7b64 }, +/* 0x7b65 */ { false, 0x7b65, 0x7b65 }, +/* 0x7b66 */ { false, 0x7b66, 0x7b66 }, +/* 0x7b67 */ { false, 0x7b67, 0x7b67 }, +/* 0x7b68 */ { false, 0x7b68, 0x7b68 }, +/* 0x7b69 */ { false, 0x7b69, 0x7b69 }, +/* 0x7b6a */ { false, 0x7b6a, 0x7b6a }, +/* 0x7b6b */ { false, 0x7b6b, 0x7b6b }, +/* 0x7b6c */ { false, 0x7b6c, 0x7b6c }, +/* 0x7b6d */ { false, 0x7b6d, 0x7b6d }, +/* 0x7b6e */ { false, 0x7b6e, 0x7b6e }, +/* 0x7b6f */ { false, 0x7b6f, 0x7b6f }, +/* 0x7b70 */ { false, 0x7b70, 0x7b70 }, +/* 0x7b71 */ { false, 0x7b71, 0x7b71 }, +/* 0x7b72 */ { false, 0x7b72, 0x7b72 }, +/* 0x7b73 */ { false, 0x7b73, 0x7b73 }, +/* 0x7b74 */ { false, 0x7b74, 0x7b74 }, +/* 0x7b75 */ { false, 0x7b75, 0x7b75 }, +/* 0x7b76 */ { false, 0x7b76, 0x7b76 }, +/* 0x7b77 */ { false, 0x7b77, 0x7b77 }, +/* 0x7b78 */ { false, 0x7b78, 0x7b78 }, +/* 0x7b79 */ { false, 0x7b79, 0x7b79 }, +/* 0x7b7a */ { false, 0x7b7a, 0x7b7a }, +/* 0x7b7b */ { false, 0x7b7b, 0x7b7b }, +/* 0x7b7c */ { false, 0x7b7c, 0x7b7c }, +/* 0x7b7d */ { false, 0x7b7d, 0x7b7d }, +/* 0x7b7e */ { false, 0x7b7e, 0x7b7e }, +/* 0x7b7f */ { false, 0x7b7f, 0x7b7f }, +/* 0x7b80 */ { false, 0x7b80, 0x7b80 }, +/* 0x7b81 */ { false, 0x7b81, 0x7b81 }, +/* 0x7b82 */ { false, 0x7b82, 0x7b82 }, +/* 0x7b83 */ { false, 0x7b83, 0x7b83 }, +/* 0x7b84 */ { false, 0x7b84, 0x7b84 }, +/* 0x7b85 */ { false, 0x7b85, 0x7b85 }, +/* 0x7b86 */ { false, 0x7b86, 0x7b86 }, +/* 0x7b87 */ { false, 0x7b87, 0x7b87 }, +/* 0x7b88 */ { false, 0x7b88, 0x7b88 }, +/* 0x7b89 */ { false, 0x7b89, 0x7b89 }, +/* 0x7b8a */ { false, 0x7b8a, 0x7b8a }, +/* 0x7b8b */ { false, 0x7b8b, 0x7b8b }, +/* 0x7b8c */ { false, 0x7b8c, 0x7b8c }, +/* 0x7b8d */ { false, 0x7b8d, 0x7b8d }, +/* 0x7b8e */ { false, 0x7b8e, 0x7b8e }, +/* 0x7b8f */ { false, 0x7b8f, 0x7b8f }, +/* 0x7b90 */ { false, 0x7b90, 0x7b90 }, +/* 0x7b91 */ { false, 0x7b91, 0x7b91 }, +/* 0x7b92 */ { false, 0x7b92, 0x7b92 }, +/* 0x7b93 */ { false, 0x7b93, 0x7b93 }, +/* 0x7b94 */ { false, 0x7b94, 0x7b94 }, +/* 0x7b95 */ { false, 0x7b95, 0x7b95 }, +/* 0x7b96 */ { false, 0x7b96, 0x7b96 }, +/* 0x7b97 */ { false, 0x7b97, 0x7b97 }, +/* 0x7b98 */ { false, 0x7b98, 0x7b98 }, +/* 0x7b99 */ { false, 0x7b99, 0x7b99 }, +/* 0x7b9a */ { false, 0x7b9a, 0x7b9a }, +/* 0x7b9b */ { false, 0x7b9b, 0x7b9b }, +/* 0x7b9c */ { false, 0x7b9c, 0x7b9c }, +/* 0x7b9d */ { false, 0x7b9d, 0x7b9d }, +/* 0x7b9e */ { false, 0x7b9e, 0x7b9e }, +/* 0x7b9f */ { false, 0x7b9f, 0x7b9f }, +/* 0x7ba0 */ { false, 0x7ba0, 0x7ba0 }, +/* 0x7ba1 */ { false, 0x7ba1, 0x7ba1 }, +/* 0x7ba2 */ { false, 0x7ba2, 0x7ba2 }, +/* 0x7ba3 */ { false, 0x7ba3, 0x7ba3 }, +/* 0x7ba4 */ { false, 0x7ba4, 0x7ba4 }, +/* 0x7ba5 */ { false, 0x7ba5, 0x7ba5 }, +/* 0x7ba6 */ { false, 0x7ba6, 0x7ba6 }, +/* 0x7ba7 */ { false, 0x7ba7, 0x7ba7 }, +/* 0x7ba8 */ { false, 0x7ba8, 0x7ba8 }, +/* 0x7ba9 */ { false, 0x7ba9, 0x7ba9 }, +/* 0x7baa */ { false, 0x7baa, 0x7baa }, +/* 0x7bab */ { false, 0x7bab, 0x7bab }, +/* 0x7bac */ { false, 0x7bac, 0x7bac }, +/* 0x7bad */ { false, 0x7bad, 0x7bad }, +/* 0x7bae */ { false, 0x7bae, 0x7bae }, +/* 0x7baf */ { false, 0x7baf, 0x7baf }, +/* 0x7bb0 */ { false, 0x7bb0, 0x7bb0 }, +/* 0x7bb1 */ { false, 0x7bb1, 0x7bb1 }, +/* 0x7bb2 */ { false, 0x7bb2, 0x7bb2 }, +/* 0x7bb3 */ { false, 0x7bb3, 0x7bb3 }, +/* 0x7bb4 */ { false, 0x7bb4, 0x7bb4 }, +/* 0x7bb5 */ { false, 0x7bb5, 0x7bb5 }, +/* 0x7bb6 */ { false, 0x7bb6, 0x7bb6 }, +/* 0x7bb7 */ { false, 0x7bb7, 0x7bb7 }, +/* 0x7bb8 */ { false, 0x7bb8, 0x7bb8 }, +/* 0x7bb9 */ { false, 0x7bb9, 0x7bb9 }, +/* 0x7bba */ { false, 0x7bba, 0x7bba }, +/* 0x7bbb */ { false, 0x7bbb, 0x7bbb }, +/* 0x7bbc */ { false, 0x7bbc, 0x7bbc }, +/* 0x7bbd */ { false, 0x7bbd, 0x7bbd }, +/* 0x7bbe */ { false, 0x7bbe, 0x7bbe }, +/* 0x7bbf */ { false, 0x7bbf, 0x7bbf }, +/* 0x7bc0 */ { false, 0x7bc0, 0x7bc0 }, +/* 0x7bc1 */ { false, 0x7bc1, 0x7bc1 }, +/* 0x7bc2 */ { false, 0x7bc2, 0x7bc2 }, +/* 0x7bc3 */ { false, 0x7bc3, 0x7bc3 }, +/* 0x7bc4 */ { false, 0x7bc4, 0x7bc4 }, +/* 0x7bc5 */ { false, 0x7bc5, 0x7bc5 }, +/* 0x7bc6 */ { false, 0x7bc6, 0x7bc6 }, +/* 0x7bc7 */ { false, 0x7bc7, 0x7bc7 }, +/* 0x7bc8 */ { false, 0x7bc8, 0x7bc8 }, +/* 0x7bc9 */ { false, 0x7bc9, 0x7bc9 }, +/* 0x7bca */ { false, 0x7bca, 0x7bca }, +/* 0x7bcb */ { false, 0x7bcb, 0x7bcb }, +/* 0x7bcc */ { false, 0x7bcc, 0x7bcc }, +/* 0x7bcd */ { false, 0x7bcd, 0x7bcd }, +/* 0x7bce */ { false, 0x7bce, 0x7bce }, +/* 0x7bcf */ { false, 0x7bcf, 0x7bcf }, +/* 0x7bd0 */ { false, 0x7bd0, 0x7bd0 }, +/* 0x7bd1 */ { false, 0x7bd1, 0x7bd1 }, +/* 0x7bd2 */ { false, 0x7bd2, 0x7bd2 }, +/* 0x7bd3 */ { false, 0x7bd3, 0x7bd3 }, +/* 0x7bd4 */ { false, 0x7bd4, 0x7bd4 }, +/* 0x7bd5 */ { false, 0x7bd5, 0x7bd5 }, +/* 0x7bd6 */ { false, 0x7bd6, 0x7bd6 }, +/* 0x7bd7 */ { false, 0x7bd7, 0x7bd7 }, +/* 0x7bd8 */ { false, 0x7bd8, 0x7bd8 }, +/* 0x7bd9 */ { false, 0x7bd9, 0x7bd9 }, +/* 0x7bda */ { false, 0x7bda, 0x7bda }, +/* 0x7bdb */ { false, 0x7bdb, 0x7bdb }, +/* 0x7bdc */ { false, 0x7bdc, 0x7bdc }, +/* 0x7bdd */ { false, 0x7bdd, 0x7bdd }, +/* 0x7bde */ { false, 0x7bde, 0x7bde }, +/* 0x7bdf */ { false, 0x7bdf, 0x7bdf }, +/* 0x7be0 */ { false, 0x7be0, 0x7be0 }, +/* 0x7be1 */ { false, 0x7be1, 0x7be1 }, +/* 0x7be2 */ { false, 0x7be2, 0x7be2 }, +/* 0x7be3 */ { false, 0x7be3, 0x7be3 }, +/* 0x7be4 */ { false, 0x7be4, 0x7be4 }, +/* 0x7be5 */ { false, 0x7be5, 0x7be5 }, +/* 0x7be6 */ { false, 0x7be6, 0x7be6 }, +/* 0x7be7 */ { false, 0x7be7, 0x7be7 }, +/* 0x7be8 */ { false, 0x7be8, 0x7be8 }, +/* 0x7be9 */ { false, 0x7be9, 0x7be9 }, +/* 0x7bea */ { false, 0x7bea, 0x7bea }, +/* 0x7beb */ { false, 0x7beb, 0x7beb }, +/* 0x7bec */ { false, 0x7bec, 0x7bec }, +/* 0x7bed */ { false, 0x7bed, 0x7bed }, +/* 0x7bee */ { false, 0x7bee, 0x7bee }, +/* 0x7bef */ { false, 0x7bef, 0x7bef }, +/* 0x7bf0 */ { false, 0x7bf0, 0x7bf0 }, +/* 0x7bf1 */ { false, 0x7bf1, 0x7bf1 }, +/* 0x7bf2 */ { false, 0x7bf2, 0x7bf2 }, +/* 0x7bf3 */ { false, 0x7bf3, 0x7bf3 }, +/* 0x7bf4 */ { false, 0x7bf4, 0x7bf4 }, +/* 0x7bf5 */ { false, 0x7bf5, 0x7bf5 }, +/* 0x7bf6 */ { false, 0x7bf6, 0x7bf6 }, +/* 0x7bf7 */ { false, 0x7bf7, 0x7bf7 }, +/* 0x7bf8 */ { false, 0x7bf8, 0x7bf8 }, +/* 0x7bf9 */ { false, 0x7bf9, 0x7bf9 }, +/* 0x7bfa */ { false, 0x7bfa, 0x7bfa }, +/* 0x7bfb */ { false, 0x7bfb, 0x7bfb }, +/* 0x7bfc */ { false, 0x7bfc, 0x7bfc }, +/* 0x7bfd */ { false, 0x7bfd, 0x7bfd }, +/* 0x7bfe */ { false, 0x7bfe, 0x7bfe }, +/* 0x7bff */ { false, 0x7bff, 0x7bff }, +/* 0x7c00 */ { false, 0x7c00, 0x7c00 }, +/* 0x7c01 */ { false, 0x7c01, 0x7c01 }, +/* 0x7c02 */ { false, 0x7c02, 0x7c02 }, +/* 0x7c03 */ { false, 0x7c03, 0x7c03 }, +/* 0x7c04 */ { false, 0x7c04, 0x7c04 }, +/* 0x7c05 */ { false, 0x7c05, 0x7c05 }, +/* 0x7c06 */ { false, 0x7c06, 0x7c06 }, +/* 0x7c07 */ { false, 0x7c07, 0x7c07 }, +/* 0x7c08 */ { false, 0x7c08, 0x7c08 }, +/* 0x7c09 */ { false, 0x7c09, 0x7c09 }, +/* 0x7c0a */ { false, 0x7c0a, 0x7c0a }, +/* 0x7c0b */ { false, 0x7c0b, 0x7c0b }, +/* 0x7c0c */ { false, 0x7c0c, 0x7c0c }, +/* 0x7c0d */ { false, 0x7c0d, 0x7c0d }, +/* 0x7c0e */ { false, 0x7c0e, 0x7c0e }, +/* 0x7c0f */ { false, 0x7c0f, 0x7c0f }, +/* 0x7c10 */ { false, 0x7c10, 0x7c10 }, +/* 0x7c11 */ { false, 0x7c11, 0x7c11 }, +/* 0x7c12 */ { false, 0x7c12, 0x7c12 }, +/* 0x7c13 */ { false, 0x7c13, 0x7c13 }, +/* 0x7c14 */ { false, 0x7c14, 0x7c14 }, +/* 0x7c15 */ { false, 0x7c15, 0x7c15 }, +/* 0x7c16 */ { false, 0x7c16, 0x7c16 }, +/* 0x7c17 */ { false, 0x7c17, 0x7c17 }, +/* 0x7c18 */ { false, 0x7c18, 0x7c18 }, +/* 0x7c19 */ { false, 0x7c19, 0x7c19 }, +/* 0x7c1a */ { false, 0x7c1a, 0x7c1a }, +/* 0x7c1b */ { false, 0x7c1b, 0x7c1b }, +/* 0x7c1c */ { false, 0x7c1c, 0x7c1c }, +/* 0x7c1d */ { false, 0x7c1d, 0x7c1d }, +/* 0x7c1e */ { false, 0x7c1e, 0x7c1e }, +/* 0x7c1f */ { false, 0x7c1f, 0x7c1f }, +/* 0x7c20 */ { false, 0x7c20, 0x7c20 }, +/* 0x7c21 */ { false, 0x7c21, 0x7c21 }, +/* 0x7c22 */ { false, 0x7c22, 0x7c22 }, +/* 0x7c23 */ { false, 0x7c23, 0x7c23 }, +/* 0x7c24 */ { false, 0x7c24, 0x7c24 }, +/* 0x7c25 */ { false, 0x7c25, 0x7c25 }, +/* 0x7c26 */ { false, 0x7c26, 0x7c26 }, +/* 0x7c27 */ { false, 0x7c27, 0x7c27 }, +/* 0x7c28 */ { false, 0x7c28, 0x7c28 }, +/* 0x7c29 */ { false, 0x7c29, 0x7c29 }, +/* 0x7c2a */ { false, 0x7c2a, 0x7c2a }, +/* 0x7c2b */ { false, 0x7c2b, 0x7c2b }, +/* 0x7c2c */ { false, 0x7c2c, 0x7c2c }, +/* 0x7c2d */ { false, 0x7c2d, 0x7c2d }, +/* 0x7c2e */ { false, 0x7c2e, 0x7c2e }, +/* 0x7c2f */ { false, 0x7c2f, 0x7c2f }, +/* 0x7c30 */ { false, 0x7c30, 0x7c30 }, +/* 0x7c31 */ { false, 0x7c31, 0x7c31 }, +/* 0x7c32 */ { false, 0x7c32, 0x7c32 }, +/* 0x7c33 */ { false, 0x7c33, 0x7c33 }, +/* 0x7c34 */ { false, 0x7c34, 0x7c34 }, +/* 0x7c35 */ { false, 0x7c35, 0x7c35 }, +/* 0x7c36 */ { false, 0x7c36, 0x7c36 }, +/* 0x7c37 */ { false, 0x7c37, 0x7c37 }, +/* 0x7c38 */ { false, 0x7c38, 0x7c38 }, +/* 0x7c39 */ { false, 0x7c39, 0x7c39 }, +/* 0x7c3a */ { false, 0x7c3a, 0x7c3a }, +/* 0x7c3b */ { false, 0x7c3b, 0x7c3b }, +/* 0x7c3c */ { false, 0x7c3c, 0x7c3c }, +/* 0x7c3d */ { false, 0x7c3d, 0x7c3d }, +/* 0x7c3e */ { false, 0x7c3e, 0x7c3e }, +/* 0x7c3f */ { false, 0x7c3f, 0x7c3f }, +/* 0x7c40 */ { false, 0x7c40, 0x7c40 }, +/* 0x7c41 */ { false, 0x7c41, 0x7c41 }, +/* 0x7c42 */ { false, 0x7c42, 0x7c42 }, +/* 0x7c43 */ { false, 0x7c43, 0x7c43 }, +/* 0x7c44 */ { false, 0x7c44, 0x7c44 }, +/* 0x7c45 */ { false, 0x7c45, 0x7c45 }, +/* 0x7c46 */ { false, 0x7c46, 0x7c46 }, +/* 0x7c47 */ { false, 0x7c47, 0x7c47 }, +/* 0x7c48 */ { false, 0x7c48, 0x7c48 }, +/* 0x7c49 */ { false, 0x7c49, 0x7c49 }, +/* 0x7c4a */ { false, 0x7c4a, 0x7c4a }, +/* 0x7c4b */ { false, 0x7c4b, 0x7c4b }, +/* 0x7c4c */ { false, 0x7c4c, 0x7c4c }, +/* 0x7c4d */ { false, 0x7c4d, 0x7c4d }, +/* 0x7c4e */ { false, 0x7c4e, 0x7c4e }, +/* 0x7c4f */ { false, 0x7c4f, 0x7c4f }, +/* 0x7c50 */ { false, 0x7c50, 0x7c50 }, +/* 0x7c51 */ { false, 0x7c51, 0x7c51 }, +/* 0x7c52 */ { false, 0x7c52, 0x7c52 }, +/* 0x7c53 */ { false, 0x7c53, 0x7c53 }, +/* 0x7c54 */ { false, 0x7c54, 0x7c54 }, +/* 0x7c55 */ { false, 0x7c55, 0x7c55 }, +/* 0x7c56 */ { false, 0x7c56, 0x7c56 }, +/* 0x7c57 */ { false, 0x7c57, 0x7c57 }, +/* 0x7c58 */ { false, 0x7c58, 0x7c58 }, +/* 0x7c59 */ { false, 0x7c59, 0x7c59 }, +/* 0x7c5a */ { false, 0x7c5a, 0x7c5a }, +/* 0x7c5b */ { false, 0x7c5b, 0x7c5b }, +/* 0x7c5c */ { false, 0x7c5c, 0x7c5c }, +/* 0x7c5d */ { false, 0x7c5d, 0x7c5d }, +/* 0x7c5e */ { false, 0x7c5e, 0x7c5e }, +/* 0x7c5f */ { false, 0x7c5f, 0x7c5f }, +/* 0x7c60 */ { false, 0x7c60, 0x7c60 }, +/* 0x7c61 */ { false, 0x7c61, 0x7c61 }, +/* 0x7c62 */ { false, 0x7c62, 0x7c62 }, +/* 0x7c63 */ { false, 0x7c63, 0x7c63 }, +/* 0x7c64 */ { false, 0x7c64, 0x7c64 }, +/* 0x7c65 */ { false, 0x7c65, 0x7c65 }, +/* 0x7c66 */ { false, 0x7c66, 0x7c66 }, +/* 0x7c67 */ { false, 0x7c67, 0x7c67 }, +/* 0x7c68 */ { false, 0x7c68, 0x7c68 }, +/* 0x7c69 */ { false, 0x7c69, 0x7c69 }, +/* 0x7c6a */ { false, 0x7c6a, 0x7c6a }, +/* 0x7c6b */ { false, 0x7c6b, 0x7c6b }, +/* 0x7c6c */ { false, 0x7c6c, 0x7c6c }, +/* 0x7c6d */ { false, 0x7c6d, 0x7c6d }, +/* 0x7c6e */ { false, 0x7c6e, 0x7c6e }, +/* 0x7c6f */ { false, 0x7c6f, 0x7c6f }, +/* 0x7c70 */ { false, 0x7c70, 0x7c70 }, +/* 0x7c71 */ { false, 0x7c71, 0x7c71 }, +/* 0x7c72 */ { false, 0x7c72, 0x7c72 }, +/* 0x7c73 */ { false, 0x7c73, 0x7c73 }, +/* 0x7c74 */ { false, 0x7c74, 0x7c74 }, +/* 0x7c75 */ { false, 0x7c75, 0x7c75 }, +/* 0x7c76 */ { false, 0x7c76, 0x7c76 }, +/* 0x7c77 */ { false, 0x7c77, 0x7c77 }, +/* 0x7c78 */ { false, 0x7c78, 0x7c78 }, +/* 0x7c79 */ { false, 0x7c79, 0x7c79 }, +/* 0x7c7a */ { false, 0x7c7a, 0x7c7a }, +/* 0x7c7b */ { false, 0x7c7b, 0x7c7b }, +/* 0x7c7c */ { false, 0x7c7c, 0x7c7c }, +/* 0x7c7d */ { false, 0x7c7d, 0x7c7d }, +/* 0x7c7e */ { false, 0x7c7e, 0x7c7e }, +/* 0x7c7f */ { false, 0x7c7f, 0x7c7f }, +/* 0x7c80 */ { false, 0x7c80, 0x7c80 }, +/* 0x7c81 */ { false, 0x7c81, 0x7c81 }, +/* 0x7c82 */ { false, 0x7c82, 0x7c82 }, +/* 0x7c83 */ { false, 0x7c83, 0x7c83 }, +/* 0x7c84 */ { false, 0x7c84, 0x7c84 }, +/* 0x7c85 */ { false, 0x7c85, 0x7c85 }, +/* 0x7c86 */ { false, 0x7c86, 0x7c86 }, +/* 0x7c87 */ { false, 0x7c87, 0x7c87 }, +/* 0x7c88 */ { false, 0x7c88, 0x7c88 }, +/* 0x7c89 */ { false, 0x7c89, 0x7c89 }, +/* 0x7c8a */ { false, 0x7c8a, 0x7c8a }, +/* 0x7c8b */ { false, 0x7c8b, 0x7c8b }, +/* 0x7c8c */ { false, 0x7c8c, 0x7c8c }, +/* 0x7c8d */ { false, 0x7c8d, 0x7c8d }, +/* 0x7c8e */ { false, 0x7c8e, 0x7c8e }, +/* 0x7c8f */ { false, 0x7c8f, 0x7c8f }, +/* 0x7c90 */ { false, 0x7c90, 0x7c90 }, +/* 0x7c91 */ { false, 0x7c91, 0x7c91 }, +/* 0x7c92 */ { false, 0x7c92, 0x7c92 }, +/* 0x7c93 */ { false, 0x7c93, 0x7c93 }, +/* 0x7c94 */ { false, 0x7c94, 0x7c94 }, +/* 0x7c95 */ { false, 0x7c95, 0x7c95 }, +/* 0x7c96 */ { false, 0x7c96, 0x7c96 }, +/* 0x7c97 */ { false, 0x7c97, 0x7c97 }, +/* 0x7c98 */ { false, 0x7c98, 0x7c98 }, +/* 0x7c99 */ { false, 0x7c99, 0x7c99 }, +/* 0x7c9a */ { false, 0x7c9a, 0x7c9a }, +/* 0x7c9b */ { false, 0x7c9b, 0x7c9b }, +/* 0x7c9c */ { false, 0x7c9c, 0x7c9c }, +/* 0x7c9d */ { false, 0x7c9d, 0x7c9d }, +/* 0x7c9e */ { false, 0x7c9e, 0x7c9e }, +/* 0x7c9f */ { false, 0x7c9f, 0x7c9f }, +/* 0x7ca0 */ { false, 0x7ca0, 0x7ca0 }, +/* 0x7ca1 */ { false, 0x7ca1, 0x7ca1 }, +/* 0x7ca2 */ { false, 0x7ca2, 0x7ca2 }, +/* 0x7ca3 */ { false, 0x7ca3, 0x7ca3 }, +/* 0x7ca4 */ { false, 0x7ca4, 0x7ca4 }, +/* 0x7ca5 */ { false, 0x7ca5, 0x7ca5 }, +/* 0x7ca6 */ { false, 0x7ca6, 0x7ca6 }, +/* 0x7ca7 */ { false, 0x7ca7, 0x7ca7 }, +/* 0x7ca8 */ { false, 0x7ca8, 0x7ca8 }, +/* 0x7ca9 */ { false, 0x7ca9, 0x7ca9 }, +/* 0x7caa */ { false, 0x7caa, 0x7caa }, +/* 0x7cab */ { false, 0x7cab, 0x7cab }, +/* 0x7cac */ { false, 0x7cac, 0x7cac }, +/* 0x7cad */ { false, 0x7cad, 0x7cad }, +/* 0x7cae */ { false, 0x7cae, 0x7cae }, +/* 0x7caf */ { false, 0x7caf, 0x7caf }, +/* 0x7cb0 */ { false, 0x7cb0, 0x7cb0 }, +/* 0x7cb1 */ { false, 0x7cb1, 0x7cb1 }, +/* 0x7cb2 */ { false, 0x7cb2, 0x7cb2 }, +/* 0x7cb3 */ { false, 0x7cb3, 0x7cb3 }, +/* 0x7cb4 */ { false, 0x7cb4, 0x7cb4 }, +/* 0x7cb5 */ { false, 0x7cb5, 0x7cb5 }, +/* 0x7cb6 */ { false, 0x7cb6, 0x7cb6 }, +/* 0x7cb7 */ { false, 0x7cb7, 0x7cb7 }, +/* 0x7cb8 */ { false, 0x7cb8, 0x7cb8 }, +/* 0x7cb9 */ { false, 0x7cb9, 0x7cb9 }, +/* 0x7cba */ { false, 0x7cba, 0x7cba }, +/* 0x7cbb */ { false, 0x7cbb, 0x7cbb }, +/* 0x7cbc */ { false, 0x7cbc, 0x7cbc }, +/* 0x7cbd */ { false, 0x7cbd, 0x7cbd }, +/* 0x7cbe */ { false, 0x7cbe, 0x7cbe }, +/* 0x7cbf */ { false, 0x7cbf, 0x7cbf }, +/* 0x7cc0 */ { false, 0x7cc0, 0x7cc0 }, +/* 0x7cc1 */ { false, 0x7cc1, 0x7cc1 }, +/* 0x7cc2 */ { false, 0x7cc2, 0x7cc2 }, +/* 0x7cc3 */ { false, 0x7cc3, 0x7cc3 }, +/* 0x7cc4 */ { false, 0x7cc4, 0x7cc4 }, +/* 0x7cc5 */ { false, 0x7cc5, 0x7cc5 }, +/* 0x7cc6 */ { false, 0x7cc6, 0x7cc6 }, +/* 0x7cc7 */ { false, 0x7cc7, 0x7cc7 }, +/* 0x7cc8 */ { false, 0x7cc8, 0x7cc8 }, +/* 0x7cc9 */ { false, 0x7cc9, 0x7cc9 }, +/* 0x7cca */ { false, 0x7cca, 0x7cca }, +/* 0x7ccb */ { false, 0x7ccb, 0x7ccb }, +/* 0x7ccc */ { false, 0x7ccc, 0x7ccc }, +/* 0x7ccd */ { false, 0x7ccd, 0x7ccd }, +/* 0x7cce */ { false, 0x7cce, 0x7cce }, +/* 0x7ccf */ { false, 0x7ccf, 0x7ccf }, +/* 0x7cd0 */ { false, 0x7cd0, 0x7cd0 }, +/* 0x7cd1 */ { false, 0x7cd1, 0x7cd1 }, +/* 0x7cd2 */ { false, 0x7cd2, 0x7cd2 }, +/* 0x7cd3 */ { false, 0x7cd3, 0x7cd3 }, +/* 0x7cd4 */ { false, 0x7cd4, 0x7cd4 }, +/* 0x7cd5 */ { false, 0x7cd5, 0x7cd5 }, +/* 0x7cd6 */ { false, 0x7cd6, 0x7cd6 }, +/* 0x7cd7 */ { false, 0x7cd7, 0x7cd7 }, +/* 0x7cd8 */ { false, 0x7cd8, 0x7cd8 }, +/* 0x7cd9 */ { false, 0x7cd9, 0x7cd9 }, +/* 0x7cda */ { false, 0x7cda, 0x7cda }, +/* 0x7cdb */ { false, 0x7cdb, 0x7cdb }, +/* 0x7cdc */ { false, 0x7cdc, 0x7cdc }, +/* 0x7cdd */ { false, 0x7cdd, 0x7cdd }, +/* 0x7cde */ { false, 0x7cde, 0x7cde }, +/* 0x7cdf */ { false, 0x7cdf, 0x7cdf }, +/* 0x7ce0 */ { false, 0x7ce0, 0x7ce0 }, +/* 0x7ce1 */ { false, 0x7ce1, 0x7ce1 }, +/* 0x7ce2 */ { false, 0x7ce2, 0x7ce2 }, +/* 0x7ce3 */ { false, 0x7ce3, 0x7ce3 }, +/* 0x7ce4 */ { false, 0x7ce4, 0x7ce4 }, +/* 0x7ce5 */ { false, 0x7ce5, 0x7ce5 }, +/* 0x7ce6 */ { false, 0x7ce6, 0x7ce6 }, +/* 0x7ce7 */ { false, 0x7ce7, 0x7ce7 }, +/* 0x7ce8 */ { false, 0x7ce8, 0x7ce8 }, +/* 0x7ce9 */ { false, 0x7ce9, 0x7ce9 }, +/* 0x7cea */ { false, 0x7cea, 0x7cea }, +/* 0x7ceb */ { false, 0x7ceb, 0x7ceb }, +/* 0x7cec */ { false, 0x7cec, 0x7cec }, +/* 0x7ced */ { false, 0x7ced, 0x7ced }, +/* 0x7cee */ { false, 0x7cee, 0x7cee }, +/* 0x7cef */ { false, 0x7cef, 0x7cef }, +/* 0x7cf0 */ { false, 0x7cf0, 0x7cf0 }, +/* 0x7cf1 */ { false, 0x7cf1, 0x7cf1 }, +/* 0x7cf2 */ { false, 0x7cf2, 0x7cf2 }, +/* 0x7cf3 */ { false, 0x7cf3, 0x7cf3 }, +/* 0x7cf4 */ { false, 0x7cf4, 0x7cf4 }, +/* 0x7cf5 */ { false, 0x7cf5, 0x7cf5 }, +/* 0x7cf6 */ { false, 0x7cf6, 0x7cf6 }, +/* 0x7cf7 */ { false, 0x7cf7, 0x7cf7 }, +/* 0x7cf8 */ { false, 0x7cf8, 0x7cf8 }, +/* 0x7cf9 */ { false, 0x7cf9, 0x7cf9 }, +/* 0x7cfa */ { false, 0x7cfa, 0x7cfa }, +/* 0x7cfb */ { false, 0x7cfb, 0x7cfb }, +/* 0x7cfc */ { false, 0x7cfc, 0x7cfc }, +/* 0x7cfd */ { false, 0x7cfd, 0x7cfd }, +/* 0x7cfe */ { false, 0x7cfe, 0x7cfe }, +/* 0x7cff */ { false, 0x7cff, 0x7cff }, +/* 0x7d00 */ { false, 0x7d00, 0x7d00 }, +/* 0x7d01 */ { false, 0x7d01, 0x7d01 }, +/* 0x7d02 */ { false, 0x7d02, 0x7d02 }, +/* 0x7d03 */ { false, 0x7d03, 0x7d03 }, +/* 0x7d04 */ { false, 0x7d04, 0x7d04 }, +/* 0x7d05 */ { false, 0x7d05, 0x7d05 }, +/* 0x7d06 */ { false, 0x7d06, 0x7d06 }, +/* 0x7d07 */ { false, 0x7d07, 0x7d07 }, +/* 0x7d08 */ { false, 0x7d08, 0x7d08 }, +/* 0x7d09 */ { false, 0x7d09, 0x7d09 }, +/* 0x7d0a */ { false, 0x7d0a, 0x7d0a }, +/* 0x7d0b */ { false, 0x7d0b, 0x7d0b }, +/* 0x7d0c */ { false, 0x7d0c, 0x7d0c }, +/* 0x7d0d */ { false, 0x7d0d, 0x7d0d }, +/* 0x7d0e */ { false, 0x7d0e, 0x7d0e }, +/* 0x7d0f */ { false, 0x7d0f, 0x7d0f }, +/* 0x7d10 */ { false, 0x7d10, 0x7d10 }, +/* 0x7d11 */ { false, 0x7d11, 0x7d11 }, +/* 0x7d12 */ { false, 0x7d12, 0x7d12 }, +/* 0x7d13 */ { false, 0x7d13, 0x7d13 }, +/* 0x7d14 */ { false, 0x7d14, 0x7d14 }, +/* 0x7d15 */ { false, 0x7d15, 0x7d15 }, +/* 0x7d16 */ { false, 0x7d16, 0x7d16 }, +/* 0x7d17 */ { false, 0x7d17, 0x7d17 }, +/* 0x7d18 */ { false, 0x7d18, 0x7d18 }, +/* 0x7d19 */ { false, 0x7d19, 0x7d19 }, +/* 0x7d1a */ { false, 0x7d1a, 0x7d1a }, +/* 0x7d1b */ { false, 0x7d1b, 0x7d1b }, +/* 0x7d1c */ { false, 0x7d1c, 0x7d1c }, +/* 0x7d1d */ { false, 0x7d1d, 0x7d1d }, +/* 0x7d1e */ { false, 0x7d1e, 0x7d1e }, +/* 0x7d1f */ { false, 0x7d1f, 0x7d1f }, +/* 0x7d20 */ { false, 0x7d20, 0x7d20 }, +/* 0x7d21 */ { false, 0x7d21, 0x7d21 }, +/* 0x7d22 */ { false, 0x7d22, 0x7d22 }, +/* 0x7d23 */ { false, 0x7d23, 0x7d23 }, +/* 0x7d24 */ { false, 0x7d24, 0x7d24 }, +/* 0x7d25 */ { false, 0x7d25, 0x7d25 }, +/* 0x7d26 */ { false, 0x7d26, 0x7d26 }, +/* 0x7d27 */ { false, 0x7d27, 0x7d27 }, +/* 0x7d28 */ { false, 0x7d28, 0x7d28 }, +/* 0x7d29 */ { false, 0x7d29, 0x7d29 }, +/* 0x7d2a */ { false, 0x7d2a, 0x7d2a }, +/* 0x7d2b */ { false, 0x7d2b, 0x7d2b }, +/* 0x7d2c */ { false, 0x7d2c, 0x7d2c }, +/* 0x7d2d */ { false, 0x7d2d, 0x7d2d }, +/* 0x7d2e */ { false, 0x7d2e, 0x7d2e }, +/* 0x7d2f */ { false, 0x7d2f, 0x7d2f }, +/* 0x7d30 */ { false, 0x7d30, 0x7d30 }, +/* 0x7d31 */ { false, 0x7d31, 0x7d31 }, +/* 0x7d32 */ { false, 0x7d32, 0x7d32 }, +/* 0x7d33 */ { false, 0x7d33, 0x7d33 }, +/* 0x7d34 */ { false, 0x7d34, 0x7d34 }, +/* 0x7d35 */ { false, 0x7d35, 0x7d35 }, +/* 0x7d36 */ { false, 0x7d36, 0x7d36 }, +/* 0x7d37 */ { false, 0x7d37, 0x7d37 }, +/* 0x7d38 */ { false, 0x7d38, 0x7d38 }, +/* 0x7d39 */ { false, 0x7d39, 0x7d39 }, +/* 0x7d3a */ { false, 0x7d3a, 0x7d3a }, +/* 0x7d3b */ { false, 0x7d3b, 0x7d3b }, +/* 0x7d3c */ { false, 0x7d3c, 0x7d3c }, +/* 0x7d3d */ { false, 0x7d3d, 0x7d3d }, +/* 0x7d3e */ { false, 0x7d3e, 0x7d3e }, +/* 0x7d3f */ { false, 0x7d3f, 0x7d3f }, +/* 0x7d40 */ { false, 0x7d40, 0x7d40 }, +/* 0x7d41 */ { false, 0x7d41, 0x7d41 }, +/* 0x7d42 */ { false, 0x7d42, 0x7d42 }, +/* 0x7d43 */ { false, 0x7d43, 0x7d43 }, +/* 0x7d44 */ { false, 0x7d44, 0x7d44 }, +/* 0x7d45 */ { false, 0x7d45, 0x7d45 }, +/* 0x7d46 */ { false, 0x7d46, 0x7d46 }, +/* 0x7d47 */ { false, 0x7d47, 0x7d47 }, +/* 0x7d48 */ { false, 0x7d48, 0x7d48 }, +/* 0x7d49 */ { false, 0x7d49, 0x7d49 }, +/* 0x7d4a */ { false, 0x7d4a, 0x7d4a }, +/* 0x7d4b */ { false, 0x7d4b, 0x7d4b }, +/* 0x7d4c */ { false, 0x7d4c, 0x7d4c }, +/* 0x7d4d */ { false, 0x7d4d, 0x7d4d }, +/* 0x7d4e */ { false, 0x7d4e, 0x7d4e }, +/* 0x7d4f */ { false, 0x7d4f, 0x7d4f }, +/* 0x7d50 */ { false, 0x7d50, 0x7d50 }, +/* 0x7d51 */ { false, 0x7d51, 0x7d51 }, +/* 0x7d52 */ { false, 0x7d52, 0x7d52 }, +/* 0x7d53 */ { false, 0x7d53, 0x7d53 }, +/* 0x7d54 */ { false, 0x7d54, 0x7d54 }, +/* 0x7d55 */ { false, 0x7d55, 0x7d55 }, +/* 0x7d56 */ { false, 0x7d56, 0x7d56 }, +/* 0x7d57 */ { false, 0x7d57, 0x7d57 }, +/* 0x7d58 */ { false, 0x7d58, 0x7d58 }, +/* 0x7d59 */ { false, 0x7d59, 0x7d59 }, +/* 0x7d5a */ { false, 0x7d5a, 0x7d5a }, +/* 0x7d5b */ { false, 0x7d5b, 0x7d5b }, +/* 0x7d5c */ { false, 0x7d5c, 0x7d5c }, +/* 0x7d5d */ { false, 0x7d5d, 0x7d5d }, +/* 0x7d5e */ { false, 0x7d5e, 0x7d5e }, +/* 0x7d5f */ { false, 0x7d5f, 0x7d5f }, +/* 0x7d60 */ { false, 0x7d60, 0x7d60 }, +/* 0x7d61 */ { false, 0x7d61, 0x7d61 }, +/* 0x7d62 */ { false, 0x7d62, 0x7d62 }, +/* 0x7d63 */ { false, 0x7d63, 0x7d63 }, +/* 0x7d64 */ { false, 0x7d64, 0x7d64 }, +/* 0x7d65 */ { false, 0x7d65, 0x7d65 }, +/* 0x7d66 */ { false, 0x7d66, 0x7d66 }, +/* 0x7d67 */ { false, 0x7d67, 0x7d67 }, +/* 0x7d68 */ { false, 0x7d68, 0x7d68 }, +/* 0x7d69 */ { false, 0x7d69, 0x7d69 }, +/* 0x7d6a */ { false, 0x7d6a, 0x7d6a }, +/* 0x7d6b */ { false, 0x7d6b, 0x7d6b }, +/* 0x7d6c */ { false, 0x7d6c, 0x7d6c }, +/* 0x7d6d */ { false, 0x7d6d, 0x7d6d }, +/* 0x7d6e */ { false, 0x7d6e, 0x7d6e }, +/* 0x7d6f */ { false, 0x7d6f, 0x7d6f }, +/* 0x7d70 */ { false, 0x7d70, 0x7d70 }, +/* 0x7d71 */ { false, 0x7d71, 0x7d71 }, +/* 0x7d72 */ { false, 0x7d72, 0x7d72 }, +/* 0x7d73 */ { false, 0x7d73, 0x7d73 }, +/* 0x7d74 */ { false, 0x7d74, 0x7d74 }, +/* 0x7d75 */ { false, 0x7d75, 0x7d75 }, +/* 0x7d76 */ { false, 0x7d76, 0x7d76 }, +/* 0x7d77 */ { false, 0x7d77, 0x7d77 }, +/* 0x7d78 */ { false, 0x7d78, 0x7d78 }, +/* 0x7d79 */ { false, 0x7d79, 0x7d79 }, +/* 0x7d7a */ { false, 0x7d7a, 0x7d7a }, +/* 0x7d7b */ { false, 0x7d7b, 0x7d7b }, +/* 0x7d7c */ { false, 0x7d7c, 0x7d7c }, +/* 0x7d7d */ { false, 0x7d7d, 0x7d7d }, +/* 0x7d7e */ { false, 0x7d7e, 0x7d7e }, +/* 0x7d7f */ { false, 0x7d7f, 0x7d7f }, +/* 0x7d80 */ { false, 0x7d80, 0x7d80 }, +/* 0x7d81 */ { false, 0x7d81, 0x7d81 }, +/* 0x7d82 */ { false, 0x7d82, 0x7d82 }, +/* 0x7d83 */ { false, 0x7d83, 0x7d83 }, +/* 0x7d84 */ { false, 0x7d84, 0x7d84 }, +/* 0x7d85 */ { false, 0x7d85, 0x7d85 }, +/* 0x7d86 */ { false, 0x7d86, 0x7d86 }, +/* 0x7d87 */ { false, 0x7d87, 0x7d87 }, +/* 0x7d88 */ { false, 0x7d88, 0x7d88 }, +/* 0x7d89 */ { false, 0x7d89, 0x7d89 }, +/* 0x7d8a */ { false, 0x7d8a, 0x7d8a }, +/* 0x7d8b */ { false, 0x7d8b, 0x7d8b }, +/* 0x7d8c */ { false, 0x7d8c, 0x7d8c }, +/* 0x7d8d */ { false, 0x7d8d, 0x7d8d }, +/* 0x7d8e */ { false, 0x7d8e, 0x7d8e }, +/* 0x7d8f */ { false, 0x7d8f, 0x7d8f }, +/* 0x7d90 */ { false, 0x7d90, 0x7d90 }, +/* 0x7d91 */ { false, 0x7d91, 0x7d91 }, +/* 0x7d92 */ { false, 0x7d92, 0x7d92 }, +/* 0x7d93 */ { false, 0x7d93, 0x7d93 }, +/* 0x7d94 */ { false, 0x7d94, 0x7d94 }, +/* 0x7d95 */ { false, 0x7d95, 0x7d95 }, +/* 0x7d96 */ { false, 0x7d96, 0x7d96 }, +/* 0x7d97 */ { false, 0x7d97, 0x7d97 }, +/* 0x7d98 */ { false, 0x7d98, 0x7d98 }, +/* 0x7d99 */ { false, 0x7d99, 0x7d99 }, +/* 0x7d9a */ { false, 0x7d9a, 0x7d9a }, +/* 0x7d9b */ { false, 0x7d9b, 0x7d9b }, +/* 0x7d9c */ { false, 0x7d9c, 0x7d9c }, +/* 0x7d9d */ { false, 0x7d9d, 0x7d9d }, +/* 0x7d9e */ { false, 0x7d9e, 0x7d9e }, +/* 0x7d9f */ { false, 0x7d9f, 0x7d9f }, +/* 0x7da0 */ { false, 0x7da0, 0x7da0 }, +/* 0x7da1 */ { false, 0x7da1, 0x7da1 }, +/* 0x7da2 */ { false, 0x7da2, 0x7da2 }, +/* 0x7da3 */ { false, 0x7da3, 0x7da3 }, +/* 0x7da4 */ { false, 0x7da4, 0x7da4 }, +/* 0x7da5 */ { false, 0x7da5, 0x7da5 }, +/* 0x7da6 */ { false, 0x7da6, 0x7da6 }, +/* 0x7da7 */ { false, 0x7da7, 0x7da7 }, +/* 0x7da8 */ { false, 0x7da8, 0x7da8 }, +/* 0x7da9 */ { false, 0x7da9, 0x7da9 }, +/* 0x7daa */ { false, 0x7daa, 0x7daa }, +/* 0x7dab */ { false, 0x7dab, 0x7dab }, +/* 0x7dac */ { false, 0x7dac, 0x7dac }, +/* 0x7dad */ { false, 0x7dad, 0x7dad }, +/* 0x7dae */ { false, 0x7dae, 0x7dae }, +/* 0x7daf */ { false, 0x7daf, 0x7daf }, +/* 0x7db0 */ { false, 0x7db0, 0x7db0 }, +/* 0x7db1 */ { false, 0x7db1, 0x7db1 }, +/* 0x7db2 */ { false, 0x7db2, 0x7db2 }, +/* 0x7db3 */ { false, 0x7db3, 0x7db3 }, +/* 0x7db4 */ { false, 0x7db4, 0x7db4 }, +/* 0x7db5 */ { false, 0x7db5, 0x7db5 }, +/* 0x7db6 */ { false, 0x7db6, 0x7db6 }, +/* 0x7db7 */ { false, 0x7db7, 0x7db7 }, +/* 0x7db8 */ { false, 0x7db8, 0x7db8 }, +/* 0x7db9 */ { false, 0x7db9, 0x7db9 }, +/* 0x7dba */ { false, 0x7dba, 0x7dba }, +/* 0x7dbb */ { false, 0x7dbb, 0x7dbb }, +/* 0x7dbc */ { false, 0x7dbc, 0x7dbc }, +/* 0x7dbd */ { false, 0x7dbd, 0x7dbd }, +/* 0x7dbe */ { false, 0x7dbe, 0x7dbe }, +/* 0x7dbf */ { false, 0x7dbf, 0x7dbf }, +/* 0x7dc0 */ { false, 0x7dc0, 0x7dc0 }, +/* 0x7dc1 */ { false, 0x7dc1, 0x7dc1 }, +/* 0x7dc2 */ { false, 0x7dc2, 0x7dc2 }, +/* 0x7dc3 */ { false, 0x7dc3, 0x7dc3 }, +/* 0x7dc4 */ { false, 0x7dc4, 0x7dc4 }, +/* 0x7dc5 */ { false, 0x7dc5, 0x7dc5 }, +/* 0x7dc6 */ { false, 0x7dc6, 0x7dc6 }, +/* 0x7dc7 */ { false, 0x7dc7, 0x7dc7 }, +/* 0x7dc8 */ { false, 0x7dc8, 0x7dc8 }, +/* 0x7dc9 */ { false, 0x7dc9, 0x7dc9 }, +/* 0x7dca */ { false, 0x7dca, 0x7dca }, +/* 0x7dcb */ { false, 0x7dcb, 0x7dcb }, +/* 0x7dcc */ { false, 0x7dcc, 0x7dcc }, +/* 0x7dcd */ { false, 0x7dcd, 0x7dcd }, +/* 0x7dce */ { false, 0x7dce, 0x7dce }, +/* 0x7dcf */ { false, 0x7dcf, 0x7dcf }, +/* 0x7dd0 */ { false, 0x7dd0, 0x7dd0 }, +/* 0x7dd1 */ { false, 0x7dd1, 0x7dd1 }, +/* 0x7dd2 */ { false, 0x7dd2, 0x7dd2 }, +/* 0x7dd3 */ { false, 0x7dd3, 0x7dd3 }, +/* 0x7dd4 */ { false, 0x7dd4, 0x7dd4 }, +/* 0x7dd5 */ { false, 0x7dd5, 0x7dd5 }, +/* 0x7dd6 */ { false, 0x7dd6, 0x7dd6 }, +/* 0x7dd7 */ { false, 0x7dd7, 0x7dd7 }, +/* 0x7dd8 */ { false, 0x7dd8, 0x7dd8 }, +/* 0x7dd9 */ { false, 0x7dd9, 0x7dd9 }, +/* 0x7dda */ { false, 0x7dda, 0x7dda }, +/* 0x7ddb */ { false, 0x7ddb, 0x7ddb }, +/* 0x7ddc */ { false, 0x7ddc, 0x7ddc }, +/* 0x7ddd */ { false, 0x7ddd, 0x7ddd }, +/* 0x7dde */ { false, 0x7dde, 0x7dde }, +/* 0x7ddf */ { false, 0x7ddf, 0x7ddf }, +/* 0x7de0 */ { false, 0x7de0, 0x7de0 }, +/* 0x7de1 */ { false, 0x7de1, 0x7de1 }, +/* 0x7de2 */ { false, 0x7de2, 0x7de2 }, +/* 0x7de3 */ { false, 0x7de3, 0x7de3 }, +/* 0x7de4 */ { false, 0x7de4, 0x7de4 }, +/* 0x7de5 */ { false, 0x7de5, 0x7de5 }, +/* 0x7de6 */ { false, 0x7de6, 0x7de6 }, +/* 0x7de7 */ { false, 0x7de7, 0x7de7 }, +/* 0x7de8 */ { false, 0x7de8, 0x7de8 }, +/* 0x7de9 */ { false, 0x7de9, 0x7de9 }, +/* 0x7dea */ { false, 0x7dea, 0x7dea }, +/* 0x7deb */ { false, 0x7deb, 0x7deb }, +/* 0x7dec */ { false, 0x7dec, 0x7dec }, +/* 0x7ded */ { false, 0x7ded, 0x7ded }, +/* 0x7dee */ { false, 0x7dee, 0x7dee }, +/* 0x7def */ { false, 0x7def, 0x7def }, +/* 0x7df0 */ { false, 0x7df0, 0x7df0 }, +/* 0x7df1 */ { false, 0x7df1, 0x7df1 }, +/* 0x7df2 */ { false, 0x7df2, 0x7df2 }, +/* 0x7df3 */ { false, 0x7df3, 0x7df3 }, +/* 0x7df4 */ { false, 0x7df4, 0x7df4 }, +/* 0x7df5 */ { false, 0x7df5, 0x7df5 }, +/* 0x7df6 */ { false, 0x7df6, 0x7df6 }, +/* 0x7df7 */ { false, 0x7df7, 0x7df7 }, +/* 0x7df8 */ { false, 0x7df8, 0x7df8 }, +/* 0x7df9 */ { false, 0x7df9, 0x7df9 }, +/* 0x7dfa */ { false, 0x7dfa, 0x7dfa }, +/* 0x7dfb */ { false, 0x7dfb, 0x7dfb }, +/* 0x7dfc */ { false, 0x7dfc, 0x7dfc }, +/* 0x7dfd */ { false, 0x7dfd, 0x7dfd }, +/* 0x7dfe */ { false, 0x7dfe, 0x7dfe }, +/* 0x7dff */ { false, 0x7dff, 0x7dff }, +/* 0x7e00 */ { false, 0x7e00, 0x7e00 }, +/* 0x7e01 */ { false, 0x7e01, 0x7e01 }, +/* 0x7e02 */ { false, 0x7e02, 0x7e02 }, +/* 0x7e03 */ { false, 0x7e03, 0x7e03 }, +/* 0x7e04 */ { false, 0x7e04, 0x7e04 }, +/* 0x7e05 */ { false, 0x7e05, 0x7e05 }, +/* 0x7e06 */ { false, 0x7e06, 0x7e06 }, +/* 0x7e07 */ { false, 0x7e07, 0x7e07 }, +/* 0x7e08 */ { false, 0x7e08, 0x7e08 }, +/* 0x7e09 */ { false, 0x7e09, 0x7e09 }, +/* 0x7e0a */ { false, 0x7e0a, 0x7e0a }, +/* 0x7e0b */ { false, 0x7e0b, 0x7e0b }, +/* 0x7e0c */ { false, 0x7e0c, 0x7e0c }, +/* 0x7e0d */ { false, 0x7e0d, 0x7e0d }, +/* 0x7e0e */ { false, 0x7e0e, 0x7e0e }, +/* 0x7e0f */ { false, 0x7e0f, 0x7e0f }, +/* 0x7e10 */ { false, 0x7e10, 0x7e10 }, +/* 0x7e11 */ { false, 0x7e11, 0x7e11 }, +/* 0x7e12 */ { false, 0x7e12, 0x7e12 }, +/* 0x7e13 */ { false, 0x7e13, 0x7e13 }, +/* 0x7e14 */ { false, 0x7e14, 0x7e14 }, +/* 0x7e15 */ { false, 0x7e15, 0x7e15 }, +/* 0x7e16 */ { false, 0x7e16, 0x7e16 }, +/* 0x7e17 */ { false, 0x7e17, 0x7e17 }, +/* 0x7e18 */ { false, 0x7e18, 0x7e18 }, +/* 0x7e19 */ { false, 0x7e19, 0x7e19 }, +/* 0x7e1a */ { false, 0x7e1a, 0x7e1a }, +/* 0x7e1b */ { false, 0x7e1b, 0x7e1b }, +/* 0x7e1c */ { false, 0x7e1c, 0x7e1c }, +/* 0x7e1d */ { false, 0x7e1d, 0x7e1d }, +/* 0x7e1e */ { false, 0x7e1e, 0x7e1e }, +/* 0x7e1f */ { false, 0x7e1f, 0x7e1f }, +/* 0x7e20 */ { false, 0x7e20, 0x7e20 }, +/* 0x7e21 */ { false, 0x7e21, 0x7e21 }, +/* 0x7e22 */ { false, 0x7e22, 0x7e22 }, +/* 0x7e23 */ { false, 0x7e23, 0x7e23 }, +/* 0x7e24 */ { false, 0x7e24, 0x7e24 }, +/* 0x7e25 */ { false, 0x7e25, 0x7e25 }, +/* 0x7e26 */ { false, 0x7e26, 0x7e26 }, +/* 0x7e27 */ { false, 0x7e27, 0x7e27 }, +/* 0x7e28 */ { false, 0x7e28, 0x7e28 }, +/* 0x7e29 */ { false, 0x7e29, 0x7e29 }, +/* 0x7e2a */ { false, 0x7e2a, 0x7e2a }, +/* 0x7e2b */ { false, 0x7e2b, 0x7e2b }, +/* 0x7e2c */ { false, 0x7e2c, 0x7e2c }, +/* 0x7e2d */ { false, 0x7e2d, 0x7e2d }, +/* 0x7e2e */ { false, 0x7e2e, 0x7e2e }, +/* 0x7e2f */ { false, 0x7e2f, 0x7e2f }, +/* 0x7e30 */ { false, 0x7e30, 0x7e30 }, +/* 0x7e31 */ { false, 0x7e31, 0x7e31 }, +/* 0x7e32 */ { false, 0x7e32, 0x7e32 }, +/* 0x7e33 */ { false, 0x7e33, 0x7e33 }, +/* 0x7e34 */ { false, 0x7e34, 0x7e34 }, +/* 0x7e35 */ { false, 0x7e35, 0x7e35 }, +/* 0x7e36 */ { false, 0x7e36, 0x7e36 }, +/* 0x7e37 */ { false, 0x7e37, 0x7e37 }, +/* 0x7e38 */ { false, 0x7e38, 0x7e38 }, +/* 0x7e39 */ { false, 0x7e39, 0x7e39 }, +/* 0x7e3a */ { false, 0x7e3a, 0x7e3a }, +/* 0x7e3b */ { false, 0x7e3b, 0x7e3b }, +/* 0x7e3c */ { false, 0x7e3c, 0x7e3c }, +/* 0x7e3d */ { false, 0x7e3d, 0x7e3d }, +/* 0x7e3e */ { false, 0x7e3e, 0x7e3e }, +/* 0x7e3f */ { false, 0x7e3f, 0x7e3f }, +/* 0x7e40 */ { false, 0x7e40, 0x7e40 }, +/* 0x7e41 */ { false, 0x7e41, 0x7e41 }, +/* 0x7e42 */ { false, 0x7e42, 0x7e42 }, +/* 0x7e43 */ { false, 0x7e43, 0x7e43 }, +/* 0x7e44 */ { false, 0x7e44, 0x7e44 }, +/* 0x7e45 */ { false, 0x7e45, 0x7e45 }, +/* 0x7e46 */ { false, 0x7e46, 0x7e46 }, +/* 0x7e47 */ { false, 0x7e47, 0x7e47 }, +/* 0x7e48 */ { false, 0x7e48, 0x7e48 }, +/* 0x7e49 */ { false, 0x7e49, 0x7e49 }, +/* 0x7e4a */ { false, 0x7e4a, 0x7e4a }, +/* 0x7e4b */ { false, 0x7e4b, 0x7e4b }, +/* 0x7e4c */ { false, 0x7e4c, 0x7e4c }, +/* 0x7e4d */ { false, 0x7e4d, 0x7e4d }, +/* 0x7e4e */ { false, 0x7e4e, 0x7e4e }, +/* 0x7e4f */ { false, 0x7e4f, 0x7e4f }, +/* 0x7e50 */ { false, 0x7e50, 0x7e50 }, +/* 0x7e51 */ { false, 0x7e51, 0x7e51 }, +/* 0x7e52 */ { false, 0x7e52, 0x7e52 }, +/* 0x7e53 */ { false, 0x7e53, 0x7e53 }, +/* 0x7e54 */ { false, 0x7e54, 0x7e54 }, +/* 0x7e55 */ { false, 0x7e55, 0x7e55 }, +/* 0x7e56 */ { false, 0x7e56, 0x7e56 }, +/* 0x7e57 */ { false, 0x7e57, 0x7e57 }, +/* 0x7e58 */ { false, 0x7e58, 0x7e58 }, +/* 0x7e59 */ { false, 0x7e59, 0x7e59 }, +/* 0x7e5a */ { false, 0x7e5a, 0x7e5a }, +/* 0x7e5b */ { false, 0x7e5b, 0x7e5b }, +/* 0x7e5c */ { false, 0x7e5c, 0x7e5c }, +/* 0x7e5d */ { false, 0x7e5d, 0x7e5d }, +/* 0x7e5e */ { false, 0x7e5e, 0x7e5e }, +/* 0x7e5f */ { false, 0x7e5f, 0x7e5f }, +/* 0x7e60 */ { false, 0x7e60, 0x7e60 }, +/* 0x7e61 */ { false, 0x7e61, 0x7e61 }, +/* 0x7e62 */ { false, 0x7e62, 0x7e62 }, +/* 0x7e63 */ { false, 0x7e63, 0x7e63 }, +/* 0x7e64 */ { false, 0x7e64, 0x7e64 }, +/* 0x7e65 */ { false, 0x7e65, 0x7e65 }, +/* 0x7e66 */ { false, 0x7e66, 0x7e66 }, +/* 0x7e67 */ { false, 0x7e67, 0x7e67 }, +/* 0x7e68 */ { false, 0x7e68, 0x7e68 }, +/* 0x7e69 */ { false, 0x7e69, 0x7e69 }, +/* 0x7e6a */ { false, 0x7e6a, 0x7e6a }, +/* 0x7e6b */ { false, 0x7e6b, 0x7e6b }, +/* 0x7e6c */ { false, 0x7e6c, 0x7e6c }, +/* 0x7e6d */ { false, 0x7e6d, 0x7e6d }, +/* 0x7e6e */ { false, 0x7e6e, 0x7e6e }, +/* 0x7e6f */ { false, 0x7e6f, 0x7e6f }, +/* 0x7e70 */ { false, 0x7e70, 0x7e70 }, +/* 0x7e71 */ { false, 0x7e71, 0x7e71 }, +/* 0x7e72 */ { false, 0x7e72, 0x7e72 }, +/* 0x7e73 */ { false, 0x7e73, 0x7e73 }, +/* 0x7e74 */ { false, 0x7e74, 0x7e74 }, +/* 0x7e75 */ { false, 0x7e75, 0x7e75 }, +/* 0x7e76 */ { false, 0x7e76, 0x7e76 }, +/* 0x7e77 */ { false, 0x7e77, 0x7e77 }, +/* 0x7e78 */ { false, 0x7e78, 0x7e78 }, +/* 0x7e79 */ { false, 0x7e79, 0x7e79 }, +/* 0x7e7a */ { false, 0x7e7a, 0x7e7a }, +/* 0x7e7b */ { false, 0x7e7b, 0x7e7b }, +/* 0x7e7c */ { false, 0x7e7c, 0x7e7c }, +/* 0x7e7d */ { false, 0x7e7d, 0x7e7d }, +/* 0x7e7e */ { false, 0x7e7e, 0x7e7e }, +/* 0x7e7f */ { false, 0x7e7f, 0x7e7f }, +/* 0x7e80 */ { false, 0x7e80, 0x7e80 }, +/* 0x7e81 */ { false, 0x7e81, 0x7e81 }, +/* 0x7e82 */ { false, 0x7e82, 0x7e82 }, +/* 0x7e83 */ { false, 0x7e83, 0x7e83 }, +/* 0x7e84 */ { false, 0x7e84, 0x7e84 }, +/* 0x7e85 */ { false, 0x7e85, 0x7e85 }, +/* 0x7e86 */ { false, 0x7e86, 0x7e86 }, +/* 0x7e87 */ { false, 0x7e87, 0x7e87 }, +/* 0x7e88 */ { false, 0x7e88, 0x7e88 }, +/* 0x7e89 */ { false, 0x7e89, 0x7e89 }, +/* 0x7e8a */ { false, 0x7e8a, 0x7e8a }, +/* 0x7e8b */ { false, 0x7e8b, 0x7e8b }, +/* 0x7e8c */ { false, 0x7e8c, 0x7e8c }, +/* 0x7e8d */ { false, 0x7e8d, 0x7e8d }, +/* 0x7e8e */ { false, 0x7e8e, 0x7e8e }, +/* 0x7e8f */ { false, 0x7e8f, 0x7e8f }, +/* 0x7e90 */ { false, 0x7e90, 0x7e90 }, +/* 0x7e91 */ { false, 0x7e91, 0x7e91 }, +/* 0x7e92 */ { false, 0x7e92, 0x7e92 }, +/* 0x7e93 */ { false, 0x7e93, 0x7e93 }, +/* 0x7e94 */ { false, 0x7e94, 0x7e94 }, +/* 0x7e95 */ { false, 0x7e95, 0x7e95 }, +/* 0x7e96 */ { false, 0x7e96, 0x7e96 }, +/* 0x7e97 */ { false, 0x7e97, 0x7e97 }, +/* 0x7e98 */ { false, 0x7e98, 0x7e98 }, +/* 0x7e99 */ { false, 0x7e99, 0x7e99 }, +/* 0x7e9a */ { false, 0x7e9a, 0x7e9a }, +/* 0x7e9b */ { false, 0x7e9b, 0x7e9b }, +/* 0x7e9c */ { false, 0x7e9c, 0x7e9c }, +/* 0x7e9d */ { false, 0x7e9d, 0x7e9d }, +/* 0x7e9e */ { false, 0x7e9e, 0x7e9e }, +/* 0x7e9f */ { false, 0x7e9f, 0x7e9f }, +/* 0x7ea0 */ { false, 0x7ea0, 0x7ea0 }, +/* 0x7ea1 */ { false, 0x7ea1, 0x7ea1 }, +/* 0x7ea2 */ { false, 0x7ea2, 0x7ea2 }, +/* 0x7ea3 */ { false, 0x7ea3, 0x7ea3 }, +/* 0x7ea4 */ { false, 0x7ea4, 0x7ea4 }, +/* 0x7ea5 */ { false, 0x7ea5, 0x7ea5 }, +/* 0x7ea6 */ { false, 0x7ea6, 0x7ea6 }, +/* 0x7ea7 */ { false, 0x7ea7, 0x7ea7 }, +/* 0x7ea8 */ { false, 0x7ea8, 0x7ea8 }, +/* 0x7ea9 */ { false, 0x7ea9, 0x7ea9 }, +/* 0x7eaa */ { false, 0x7eaa, 0x7eaa }, +/* 0x7eab */ { false, 0x7eab, 0x7eab }, +/* 0x7eac */ { false, 0x7eac, 0x7eac }, +/* 0x7ead */ { false, 0x7ead, 0x7ead }, +/* 0x7eae */ { false, 0x7eae, 0x7eae }, +/* 0x7eaf */ { false, 0x7eaf, 0x7eaf }, +/* 0x7eb0 */ { false, 0x7eb0, 0x7eb0 }, +/* 0x7eb1 */ { false, 0x7eb1, 0x7eb1 }, +/* 0x7eb2 */ { false, 0x7eb2, 0x7eb2 }, +/* 0x7eb3 */ { false, 0x7eb3, 0x7eb3 }, +/* 0x7eb4 */ { false, 0x7eb4, 0x7eb4 }, +/* 0x7eb5 */ { false, 0x7eb5, 0x7eb5 }, +/* 0x7eb6 */ { false, 0x7eb6, 0x7eb6 }, +/* 0x7eb7 */ { false, 0x7eb7, 0x7eb7 }, +/* 0x7eb8 */ { false, 0x7eb8, 0x7eb8 }, +/* 0x7eb9 */ { false, 0x7eb9, 0x7eb9 }, +/* 0x7eba */ { false, 0x7eba, 0x7eba }, +/* 0x7ebb */ { false, 0x7ebb, 0x7ebb }, +/* 0x7ebc */ { false, 0x7ebc, 0x7ebc }, +/* 0x7ebd */ { false, 0x7ebd, 0x7ebd }, +/* 0x7ebe */ { false, 0x7ebe, 0x7ebe }, +/* 0x7ebf */ { false, 0x7ebf, 0x7ebf }, +/* 0x7ec0 */ { false, 0x7ec0, 0x7ec0 }, +/* 0x7ec1 */ { false, 0x7ec1, 0x7ec1 }, +/* 0x7ec2 */ { false, 0x7ec2, 0x7ec2 }, +/* 0x7ec3 */ { false, 0x7ec3, 0x7ec3 }, +/* 0x7ec4 */ { false, 0x7ec4, 0x7ec4 }, +/* 0x7ec5 */ { false, 0x7ec5, 0x7ec5 }, +/* 0x7ec6 */ { false, 0x7ec6, 0x7ec6 }, +/* 0x7ec7 */ { false, 0x7ec7, 0x7ec7 }, +/* 0x7ec8 */ { false, 0x7ec8, 0x7ec8 }, +/* 0x7ec9 */ { false, 0x7ec9, 0x7ec9 }, +/* 0x7eca */ { false, 0x7eca, 0x7eca }, +/* 0x7ecb */ { false, 0x7ecb, 0x7ecb }, +/* 0x7ecc */ { false, 0x7ecc, 0x7ecc }, +/* 0x7ecd */ { false, 0x7ecd, 0x7ecd }, +/* 0x7ece */ { false, 0x7ece, 0x7ece }, +/* 0x7ecf */ { false, 0x7ecf, 0x7ecf }, +/* 0x7ed0 */ { false, 0x7ed0, 0x7ed0 }, +/* 0x7ed1 */ { false, 0x7ed1, 0x7ed1 }, +/* 0x7ed2 */ { false, 0x7ed2, 0x7ed2 }, +/* 0x7ed3 */ { false, 0x7ed3, 0x7ed3 }, +/* 0x7ed4 */ { false, 0x7ed4, 0x7ed4 }, +/* 0x7ed5 */ { false, 0x7ed5, 0x7ed5 }, +/* 0x7ed6 */ { false, 0x7ed6, 0x7ed6 }, +/* 0x7ed7 */ { false, 0x7ed7, 0x7ed7 }, +/* 0x7ed8 */ { false, 0x7ed8, 0x7ed8 }, +/* 0x7ed9 */ { false, 0x7ed9, 0x7ed9 }, +/* 0x7eda */ { false, 0x7eda, 0x7eda }, +/* 0x7edb */ { false, 0x7edb, 0x7edb }, +/* 0x7edc */ { false, 0x7edc, 0x7edc }, +/* 0x7edd */ { false, 0x7edd, 0x7edd }, +/* 0x7ede */ { false, 0x7ede, 0x7ede }, +/* 0x7edf */ { false, 0x7edf, 0x7edf }, +/* 0x7ee0 */ { false, 0x7ee0, 0x7ee0 }, +/* 0x7ee1 */ { false, 0x7ee1, 0x7ee1 }, +/* 0x7ee2 */ { false, 0x7ee2, 0x7ee2 }, +/* 0x7ee3 */ { false, 0x7ee3, 0x7ee3 }, +/* 0x7ee4 */ { false, 0x7ee4, 0x7ee4 }, +/* 0x7ee5 */ { false, 0x7ee5, 0x7ee5 }, +/* 0x7ee6 */ { false, 0x7ee6, 0x7ee6 }, +/* 0x7ee7 */ { false, 0x7ee7, 0x7ee7 }, +/* 0x7ee8 */ { false, 0x7ee8, 0x7ee8 }, +/* 0x7ee9 */ { false, 0x7ee9, 0x7ee9 }, +/* 0x7eea */ { false, 0x7eea, 0x7eea }, +/* 0x7eeb */ { false, 0x7eeb, 0x7eeb }, +/* 0x7eec */ { false, 0x7eec, 0x7eec }, +/* 0x7eed */ { false, 0x7eed, 0x7eed }, +/* 0x7eee */ { false, 0x7eee, 0x7eee }, +/* 0x7eef */ { false, 0x7eef, 0x7eef }, +/* 0x7ef0 */ { false, 0x7ef0, 0x7ef0 }, +/* 0x7ef1 */ { false, 0x7ef1, 0x7ef1 }, +/* 0x7ef2 */ { false, 0x7ef2, 0x7ef2 }, +/* 0x7ef3 */ { false, 0x7ef3, 0x7ef3 }, +/* 0x7ef4 */ { false, 0x7ef4, 0x7ef4 }, +/* 0x7ef5 */ { false, 0x7ef5, 0x7ef5 }, +/* 0x7ef6 */ { false, 0x7ef6, 0x7ef6 }, +/* 0x7ef7 */ { false, 0x7ef7, 0x7ef7 }, +/* 0x7ef8 */ { false, 0x7ef8, 0x7ef8 }, +/* 0x7ef9 */ { false, 0x7ef9, 0x7ef9 }, +/* 0x7efa */ { false, 0x7efa, 0x7efa }, +/* 0x7efb */ { false, 0x7efb, 0x7efb }, +/* 0x7efc */ { false, 0x7efc, 0x7efc }, +/* 0x7efd */ { false, 0x7efd, 0x7efd }, +/* 0x7efe */ { false, 0x7efe, 0x7efe }, +/* 0x7eff */ { false, 0x7eff, 0x7eff }, +/* 0x7f00 */ { false, 0x7f00, 0x7f00 }, +/* 0x7f01 */ { false, 0x7f01, 0x7f01 }, +/* 0x7f02 */ { false, 0x7f02, 0x7f02 }, +/* 0x7f03 */ { false, 0x7f03, 0x7f03 }, +/* 0x7f04 */ { false, 0x7f04, 0x7f04 }, +/* 0x7f05 */ { false, 0x7f05, 0x7f05 }, +/* 0x7f06 */ { false, 0x7f06, 0x7f06 }, +/* 0x7f07 */ { false, 0x7f07, 0x7f07 }, +/* 0x7f08 */ { false, 0x7f08, 0x7f08 }, +/* 0x7f09 */ { false, 0x7f09, 0x7f09 }, +/* 0x7f0a */ { false, 0x7f0a, 0x7f0a }, +/* 0x7f0b */ { false, 0x7f0b, 0x7f0b }, +/* 0x7f0c */ { false, 0x7f0c, 0x7f0c }, +/* 0x7f0d */ { false, 0x7f0d, 0x7f0d }, +/* 0x7f0e */ { false, 0x7f0e, 0x7f0e }, +/* 0x7f0f */ { false, 0x7f0f, 0x7f0f }, +/* 0x7f10 */ { false, 0x7f10, 0x7f10 }, +/* 0x7f11 */ { false, 0x7f11, 0x7f11 }, +/* 0x7f12 */ { false, 0x7f12, 0x7f12 }, +/* 0x7f13 */ { false, 0x7f13, 0x7f13 }, +/* 0x7f14 */ { false, 0x7f14, 0x7f14 }, +/* 0x7f15 */ { false, 0x7f15, 0x7f15 }, +/* 0x7f16 */ { false, 0x7f16, 0x7f16 }, +/* 0x7f17 */ { false, 0x7f17, 0x7f17 }, +/* 0x7f18 */ { false, 0x7f18, 0x7f18 }, +/* 0x7f19 */ { false, 0x7f19, 0x7f19 }, +/* 0x7f1a */ { false, 0x7f1a, 0x7f1a }, +/* 0x7f1b */ { false, 0x7f1b, 0x7f1b }, +/* 0x7f1c */ { false, 0x7f1c, 0x7f1c }, +/* 0x7f1d */ { false, 0x7f1d, 0x7f1d }, +/* 0x7f1e */ { false, 0x7f1e, 0x7f1e }, +/* 0x7f1f */ { false, 0x7f1f, 0x7f1f }, +/* 0x7f20 */ { false, 0x7f20, 0x7f20 }, +/* 0x7f21 */ { false, 0x7f21, 0x7f21 }, +/* 0x7f22 */ { false, 0x7f22, 0x7f22 }, +/* 0x7f23 */ { false, 0x7f23, 0x7f23 }, +/* 0x7f24 */ { false, 0x7f24, 0x7f24 }, +/* 0x7f25 */ { false, 0x7f25, 0x7f25 }, +/* 0x7f26 */ { false, 0x7f26, 0x7f26 }, +/* 0x7f27 */ { false, 0x7f27, 0x7f27 }, +/* 0x7f28 */ { false, 0x7f28, 0x7f28 }, +/* 0x7f29 */ { false, 0x7f29, 0x7f29 }, +/* 0x7f2a */ { false, 0x7f2a, 0x7f2a }, +/* 0x7f2b */ { false, 0x7f2b, 0x7f2b }, +/* 0x7f2c */ { false, 0x7f2c, 0x7f2c }, +/* 0x7f2d */ { false, 0x7f2d, 0x7f2d }, +/* 0x7f2e */ { false, 0x7f2e, 0x7f2e }, +/* 0x7f2f */ { false, 0x7f2f, 0x7f2f }, +/* 0x7f30 */ { false, 0x7f30, 0x7f30 }, +/* 0x7f31 */ { false, 0x7f31, 0x7f31 }, +/* 0x7f32 */ { false, 0x7f32, 0x7f32 }, +/* 0x7f33 */ { false, 0x7f33, 0x7f33 }, +/* 0x7f34 */ { false, 0x7f34, 0x7f34 }, +/* 0x7f35 */ { false, 0x7f35, 0x7f35 }, +/* 0x7f36 */ { false, 0x7f36, 0x7f36 }, +/* 0x7f37 */ { false, 0x7f37, 0x7f37 }, +/* 0x7f38 */ { false, 0x7f38, 0x7f38 }, +/* 0x7f39 */ { false, 0x7f39, 0x7f39 }, +/* 0x7f3a */ { false, 0x7f3a, 0x7f3a }, +/* 0x7f3b */ { false, 0x7f3b, 0x7f3b }, +/* 0x7f3c */ { false, 0x7f3c, 0x7f3c }, +/* 0x7f3d */ { false, 0x7f3d, 0x7f3d }, +/* 0x7f3e */ { false, 0x7f3e, 0x7f3e }, +/* 0x7f3f */ { false, 0x7f3f, 0x7f3f }, +/* 0x7f40 */ { false, 0x7f40, 0x7f40 }, +/* 0x7f41 */ { false, 0x7f41, 0x7f41 }, +/* 0x7f42 */ { false, 0x7f42, 0x7f42 }, +/* 0x7f43 */ { false, 0x7f43, 0x7f43 }, +/* 0x7f44 */ { false, 0x7f44, 0x7f44 }, +/* 0x7f45 */ { false, 0x7f45, 0x7f45 }, +/* 0x7f46 */ { false, 0x7f46, 0x7f46 }, +/* 0x7f47 */ { false, 0x7f47, 0x7f47 }, +/* 0x7f48 */ { false, 0x7f48, 0x7f48 }, +/* 0x7f49 */ { false, 0x7f49, 0x7f49 }, +/* 0x7f4a */ { false, 0x7f4a, 0x7f4a }, +/* 0x7f4b */ { false, 0x7f4b, 0x7f4b }, +/* 0x7f4c */ { false, 0x7f4c, 0x7f4c }, +/* 0x7f4d */ { false, 0x7f4d, 0x7f4d }, +/* 0x7f4e */ { false, 0x7f4e, 0x7f4e }, +/* 0x7f4f */ { false, 0x7f4f, 0x7f4f }, +/* 0x7f50 */ { false, 0x7f50, 0x7f50 }, +/* 0x7f51 */ { false, 0x7f51, 0x7f51 }, +/* 0x7f52 */ { false, 0x7f52, 0x7f52 }, +/* 0x7f53 */ { false, 0x7f53, 0x7f53 }, +/* 0x7f54 */ { false, 0x7f54, 0x7f54 }, +/* 0x7f55 */ { false, 0x7f55, 0x7f55 }, +/* 0x7f56 */ { false, 0x7f56, 0x7f56 }, +/* 0x7f57 */ { false, 0x7f57, 0x7f57 }, +/* 0x7f58 */ { false, 0x7f58, 0x7f58 }, +/* 0x7f59 */ { false, 0x7f59, 0x7f59 }, +/* 0x7f5a */ { false, 0x7f5a, 0x7f5a }, +/* 0x7f5b */ { false, 0x7f5b, 0x7f5b }, +/* 0x7f5c */ { false, 0x7f5c, 0x7f5c }, +/* 0x7f5d */ { false, 0x7f5d, 0x7f5d }, +/* 0x7f5e */ { false, 0x7f5e, 0x7f5e }, +/* 0x7f5f */ { false, 0x7f5f, 0x7f5f }, +/* 0x7f60 */ { false, 0x7f60, 0x7f60 }, +/* 0x7f61 */ { false, 0x7f61, 0x7f61 }, +/* 0x7f62 */ { false, 0x7f62, 0x7f62 }, +/* 0x7f63 */ { false, 0x7f63, 0x7f63 }, +/* 0x7f64 */ { false, 0x7f64, 0x7f64 }, +/* 0x7f65 */ { false, 0x7f65, 0x7f65 }, +/* 0x7f66 */ { false, 0x7f66, 0x7f66 }, +/* 0x7f67 */ { false, 0x7f67, 0x7f67 }, +/* 0x7f68 */ { false, 0x7f68, 0x7f68 }, +/* 0x7f69 */ { false, 0x7f69, 0x7f69 }, +/* 0x7f6a */ { false, 0x7f6a, 0x7f6a }, +/* 0x7f6b */ { false, 0x7f6b, 0x7f6b }, +/* 0x7f6c */ { false, 0x7f6c, 0x7f6c }, +/* 0x7f6d */ { false, 0x7f6d, 0x7f6d }, +/* 0x7f6e */ { false, 0x7f6e, 0x7f6e }, +/* 0x7f6f */ { false, 0x7f6f, 0x7f6f }, +/* 0x7f70 */ { false, 0x7f70, 0x7f70 }, +/* 0x7f71 */ { false, 0x7f71, 0x7f71 }, +/* 0x7f72 */ { false, 0x7f72, 0x7f72 }, +/* 0x7f73 */ { false, 0x7f73, 0x7f73 }, +/* 0x7f74 */ { false, 0x7f74, 0x7f74 }, +/* 0x7f75 */ { false, 0x7f75, 0x7f75 }, +/* 0x7f76 */ { false, 0x7f76, 0x7f76 }, +/* 0x7f77 */ { false, 0x7f77, 0x7f77 }, +/* 0x7f78 */ { false, 0x7f78, 0x7f78 }, +/* 0x7f79 */ { false, 0x7f79, 0x7f79 }, +/* 0x7f7a */ { false, 0x7f7a, 0x7f7a }, +/* 0x7f7b */ { false, 0x7f7b, 0x7f7b }, +/* 0x7f7c */ { false, 0x7f7c, 0x7f7c }, +/* 0x7f7d */ { false, 0x7f7d, 0x7f7d }, +/* 0x7f7e */ { false, 0x7f7e, 0x7f7e }, +/* 0x7f7f */ { false, 0x7f7f, 0x7f7f }, +/* 0x7f80 */ { false, 0x7f80, 0x7f80 }, +/* 0x7f81 */ { false, 0x7f81, 0x7f81 }, +/* 0x7f82 */ { false, 0x7f82, 0x7f82 }, +/* 0x7f83 */ { false, 0x7f83, 0x7f83 }, +/* 0x7f84 */ { false, 0x7f84, 0x7f84 }, +/* 0x7f85 */ { false, 0x7f85, 0x7f85 }, +/* 0x7f86 */ { false, 0x7f86, 0x7f86 }, +/* 0x7f87 */ { false, 0x7f87, 0x7f87 }, +/* 0x7f88 */ { false, 0x7f88, 0x7f88 }, +/* 0x7f89 */ { false, 0x7f89, 0x7f89 }, +/* 0x7f8a */ { false, 0x7f8a, 0x7f8a }, +/* 0x7f8b */ { false, 0x7f8b, 0x7f8b }, +/* 0x7f8c */ { false, 0x7f8c, 0x7f8c }, +/* 0x7f8d */ { false, 0x7f8d, 0x7f8d }, +/* 0x7f8e */ { false, 0x7f8e, 0x7f8e }, +/* 0x7f8f */ { false, 0x7f8f, 0x7f8f }, +/* 0x7f90 */ { false, 0x7f90, 0x7f90 }, +/* 0x7f91 */ { false, 0x7f91, 0x7f91 }, +/* 0x7f92 */ { false, 0x7f92, 0x7f92 }, +/* 0x7f93 */ { false, 0x7f93, 0x7f93 }, +/* 0x7f94 */ { false, 0x7f94, 0x7f94 }, +/* 0x7f95 */ { false, 0x7f95, 0x7f95 }, +/* 0x7f96 */ { false, 0x7f96, 0x7f96 }, +/* 0x7f97 */ { false, 0x7f97, 0x7f97 }, +/* 0x7f98 */ { false, 0x7f98, 0x7f98 }, +/* 0x7f99 */ { false, 0x7f99, 0x7f99 }, +/* 0x7f9a */ { false, 0x7f9a, 0x7f9a }, +/* 0x7f9b */ { false, 0x7f9b, 0x7f9b }, +/* 0x7f9c */ { false, 0x7f9c, 0x7f9c }, +/* 0x7f9d */ { false, 0x7f9d, 0x7f9d }, +/* 0x7f9e */ { false, 0x7f9e, 0x7f9e }, +/* 0x7f9f */ { false, 0x7f9f, 0x7f9f }, +/* 0x7fa0 */ { false, 0x7fa0, 0x7fa0 }, +/* 0x7fa1 */ { false, 0x7fa1, 0x7fa1 }, +/* 0x7fa2 */ { false, 0x7fa2, 0x7fa2 }, +/* 0x7fa3 */ { false, 0x7fa3, 0x7fa3 }, +/* 0x7fa4 */ { false, 0x7fa4, 0x7fa4 }, +/* 0x7fa5 */ { false, 0x7fa5, 0x7fa5 }, +/* 0x7fa6 */ { false, 0x7fa6, 0x7fa6 }, +/* 0x7fa7 */ { false, 0x7fa7, 0x7fa7 }, +/* 0x7fa8 */ { false, 0x7fa8, 0x7fa8 }, +/* 0x7fa9 */ { false, 0x7fa9, 0x7fa9 }, +/* 0x7faa */ { false, 0x7faa, 0x7faa }, +/* 0x7fab */ { false, 0x7fab, 0x7fab }, +/* 0x7fac */ { false, 0x7fac, 0x7fac }, +/* 0x7fad */ { false, 0x7fad, 0x7fad }, +/* 0x7fae */ { false, 0x7fae, 0x7fae }, +/* 0x7faf */ { false, 0x7faf, 0x7faf }, +/* 0x7fb0 */ { false, 0x7fb0, 0x7fb0 }, +/* 0x7fb1 */ { false, 0x7fb1, 0x7fb1 }, +/* 0x7fb2 */ { false, 0x7fb2, 0x7fb2 }, +/* 0x7fb3 */ { false, 0x7fb3, 0x7fb3 }, +/* 0x7fb4 */ { false, 0x7fb4, 0x7fb4 }, +/* 0x7fb5 */ { false, 0x7fb5, 0x7fb5 }, +/* 0x7fb6 */ { false, 0x7fb6, 0x7fb6 }, +/* 0x7fb7 */ { false, 0x7fb7, 0x7fb7 }, +/* 0x7fb8 */ { false, 0x7fb8, 0x7fb8 }, +/* 0x7fb9 */ { false, 0x7fb9, 0x7fb9 }, +/* 0x7fba */ { false, 0x7fba, 0x7fba }, +/* 0x7fbb */ { false, 0x7fbb, 0x7fbb }, +/* 0x7fbc */ { false, 0x7fbc, 0x7fbc }, +/* 0x7fbd */ { false, 0x7fbd, 0x7fbd }, +/* 0x7fbe */ { false, 0x7fbe, 0x7fbe }, +/* 0x7fbf */ { false, 0x7fbf, 0x7fbf }, +/* 0x7fc0 */ { false, 0x7fc0, 0x7fc0 }, +/* 0x7fc1 */ { false, 0x7fc1, 0x7fc1 }, +/* 0x7fc2 */ { false, 0x7fc2, 0x7fc2 }, +/* 0x7fc3 */ { false, 0x7fc3, 0x7fc3 }, +/* 0x7fc4 */ { false, 0x7fc4, 0x7fc4 }, +/* 0x7fc5 */ { false, 0x7fc5, 0x7fc5 }, +/* 0x7fc6 */ { false, 0x7fc6, 0x7fc6 }, +/* 0x7fc7 */ { false, 0x7fc7, 0x7fc7 }, +/* 0x7fc8 */ { false, 0x7fc8, 0x7fc8 }, +/* 0x7fc9 */ { false, 0x7fc9, 0x7fc9 }, +/* 0x7fca */ { false, 0x7fca, 0x7fca }, +/* 0x7fcb */ { false, 0x7fcb, 0x7fcb }, +/* 0x7fcc */ { false, 0x7fcc, 0x7fcc }, +/* 0x7fcd */ { false, 0x7fcd, 0x7fcd }, +/* 0x7fce */ { false, 0x7fce, 0x7fce }, +/* 0x7fcf */ { false, 0x7fcf, 0x7fcf }, +/* 0x7fd0 */ { false, 0x7fd0, 0x7fd0 }, +/* 0x7fd1 */ { false, 0x7fd1, 0x7fd1 }, +/* 0x7fd2 */ { false, 0x7fd2, 0x7fd2 }, +/* 0x7fd3 */ { false, 0x7fd3, 0x7fd3 }, +/* 0x7fd4 */ { false, 0x7fd4, 0x7fd4 }, +/* 0x7fd5 */ { false, 0x7fd5, 0x7fd5 }, +/* 0x7fd6 */ { false, 0x7fd6, 0x7fd6 }, +/* 0x7fd7 */ { false, 0x7fd7, 0x7fd7 }, +/* 0x7fd8 */ { false, 0x7fd8, 0x7fd8 }, +/* 0x7fd9 */ { false, 0x7fd9, 0x7fd9 }, +/* 0x7fda */ { false, 0x7fda, 0x7fda }, +/* 0x7fdb */ { false, 0x7fdb, 0x7fdb }, +/* 0x7fdc */ { false, 0x7fdc, 0x7fdc }, +/* 0x7fdd */ { false, 0x7fdd, 0x7fdd }, +/* 0x7fde */ { false, 0x7fde, 0x7fde }, +/* 0x7fdf */ { false, 0x7fdf, 0x7fdf }, +/* 0x7fe0 */ { false, 0x7fe0, 0x7fe0 }, +/* 0x7fe1 */ { false, 0x7fe1, 0x7fe1 }, +/* 0x7fe2 */ { false, 0x7fe2, 0x7fe2 }, +/* 0x7fe3 */ { false, 0x7fe3, 0x7fe3 }, +/* 0x7fe4 */ { false, 0x7fe4, 0x7fe4 }, +/* 0x7fe5 */ { false, 0x7fe5, 0x7fe5 }, +/* 0x7fe6 */ { false, 0x7fe6, 0x7fe6 }, +/* 0x7fe7 */ { false, 0x7fe7, 0x7fe7 }, +/* 0x7fe8 */ { false, 0x7fe8, 0x7fe8 }, +/* 0x7fe9 */ { false, 0x7fe9, 0x7fe9 }, +/* 0x7fea */ { false, 0x7fea, 0x7fea }, +/* 0x7feb */ { false, 0x7feb, 0x7feb }, +/* 0x7fec */ { false, 0x7fec, 0x7fec }, +/* 0x7fed */ { false, 0x7fed, 0x7fed }, +/* 0x7fee */ { false, 0x7fee, 0x7fee }, +/* 0x7fef */ { false, 0x7fef, 0x7fef }, +/* 0x7ff0 */ { false, 0x7ff0, 0x7ff0 }, +/* 0x7ff1 */ { false, 0x7ff1, 0x7ff1 }, +/* 0x7ff2 */ { false, 0x7ff2, 0x7ff2 }, +/* 0x7ff3 */ { false, 0x7ff3, 0x7ff3 }, +/* 0x7ff4 */ { false, 0x7ff4, 0x7ff4 }, +/* 0x7ff5 */ { false, 0x7ff5, 0x7ff5 }, +/* 0x7ff6 */ { false, 0x7ff6, 0x7ff6 }, +/* 0x7ff7 */ { false, 0x7ff7, 0x7ff7 }, +/* 0x7ff8 */ { false, 0x7ff8, 0x7ff8 }, +/* 0x7ff9 */ { false, 0x7ff9, 0x7ff9 }, +/* 0x7ffa */ { false, 0x7ffa, 0x7ffa }, +/* 0x7ffb */ { false, 0x7ffb, 0x7ffb }, +/* 0x7ffc */ { false, 0x7ffc, 0x7ffc }, +/* 0x7ffd */ { false, 0x7ffd, 0x7ffd }, +/* 0x7ffe */ { false, 0x7ffe, 0x7ffe }, +/* 0x7fff */ { false, 0x7fff, 0x7fff }, +/* 0x8000 */ { false, 0x8000, 0x8000 }, +/* 0x8001 */ { false, 0x8001, 0x8001 }, +/* 0x8002 */ { false, 0x8002, 0x8002 }, +/* 0x8003 */ { false, 0x8003, 0x8003 }, +/* 0x8004 */ { false, 0x8004, 0x8004 }, +/* 0x8005 */ { false, 0x8005, 0x8005 }, +/* 0x8006 */ { false, 0x8006, 0x8006 }, +/* 0x8007 */ { false, 0x8007, 0x8007 }, +/* 0x8008 */ { false, 0x8008, 0x8008 }, +/* 0x8009 */ { false, 0x8009, 0x8009 }, +/* 0x800a */ { false, 0x800a, 0x800a }, +/* 0x800b */ { false, 0x800b, 0x800b }, +/* 0x800c */ { false, 0x800c, 0x800c }, +/* 0x800d */ { false, 0x800d, 0x800d }, +/* 0x800e */ { false, 0x800e, 0x800e }, +/* 0x800f */ { false, 0x800f, 0x800f }, +/* 0x8010 */ { false, 0x8010, 0x8010 }, +/* 0x8011 */ { false, 0x8011, 0x8011 }, +/* 0x8012 */ { false, 0x8012, 0x8012 }, +/* 0x8013 */ { false, 0x8013, 0x8013 }, +/* 0x8014 */ { false, 0x8014, 0x8014 }, +/* 0x8015 */ { false, 0x8015, 0x8015 }, +/* 0x8016 */ { false, 0x8016, 0x8016 }, +/* 0x8017 */ { false, 0x8017, 0x8017 }, +/* 0x8018 */ { false, 0x8018, 0x8018 }, +/* 0x8019 */ { false, 0x8019, 0x8019 }, +/* 0x801a */ { false, 0x801a, 0x801a }, +/* 0x801b */ { false, 0x801b, 0x801b }, +/* 0x801c */ { false, 0x801c, 0x801c }, +/* 0x801d */ { false, 0x801d, 0x801d }, +/* 0x801e */ { false, 0x801e, 0x801e }, +/* 0x801f */ { false, 0x801f, 0x801f }, +/* 0x8020 */ { false, 0x8020, 0x8020 }, +/* 0x8021 */ { false, 0x8021, 0x8021 }, +/* 0x8022 */ { false, 0x8022, 0x8022 }, +/* 0x8023 */ { false, 0x8023, 0x8023 }, +/* 0x8024 */ { false, 0x8024, 0x8024 }, +/* 0x8025 */ { false, 0x8025, 0x8025 }, +/* 0x8026 */ { false, 0x8026, 0x8026 }, +/* 0x8027 */ { false, 0x8027, 0x8027 }, +/* 0x8028 */ { false, 0x8028, 0x8028 }, +/* 0x8029 */ { false, 0x8029, 0x8029 }, +/* 0x802a */ { false, 0x802a, 0x802a }, +/* 0x802b */ { false, 0x802b, 0x802b }, +/* 0x802c */ { false, 0x802c, 0x802c }, +/* 0x802d */ { false, 0x802d, 0x802d }, +/* 0x802e */ { false, 0x802e, 0x802e }, +/* 0x802f */ { false, 0x802f, 0x802f }, +/* 0x8030 */ { false, 0x8030, 0x8030 }, +/* 0x8031 */ { false, 0x8031, 0x8031 }, +/* 0x8032 */ { false, 0x8032, 0x8032 }, +/* 0x8033 */ { false, 0x8033, 0x8033 }, +/* 0x8034 */ { false, 0x8034, 0x8034 }, +/* 0x8035 */ { false, 0x8035, 0x8035 }, +/* 0x8036 */ { false, 0x8036, 0x8036 }, +/* 0x8037 */ { false, 0x8037, 0x8037 }, +/* 0x8038 */ { false, 0x8038, 0x8038 }, +/* 0x8039 */ { false, 0x8039, 0x8039 }, +/* 0x803a */ { false, 0x803a, 0x803a }, +/* 0x803b */ { false, 0x803b, 0x803b }, +/* 0x803c */ { false, 0x803c, 0x803c }, +/* 0x803d */ { false, 0x803d, 0x803d }, +/* 0x803e */ { false, 0x803e, 0x803e }, +/* 0x803f */ { false, 0x803f, 0x803f }, +/* 0x8040 */ { false, 0x8040, 0x8040 }, +/* 0x8041 */ { false, 0x8041, 0x8041 }, +/* 0x8042 */ { false, 0x8042, 0x8042 }, +/* 0x8043 */ { false, 0x8043, 0x8043 }, +/* 0x8044 */ { false, 0x8044, 0x8044 }, +/* 0x8045 */ { false, 0x8045, 0x8045 }, +/* 0x8046 */ { false, 0x8046, 0x8046 }, +/* 0x8047 */ { false, 0x8047, 0x8047 }, +/* 0x8048 */ { false, 0x8048, 0x8048 }, +/* 0x8049 */ { false, 0x8049, 0x8049 }, +/* 0x804a */ { false, 0x804a, 0x804a }, +/* 0x804b */ { false, 0x804b, 0x804b }, +/* 0x804c */ { false, 0x804c, 0x804c }, +/* 0x804d */ { false, 0x804d, 0x804d }, +/* 0x804e */ { false, 0x804e, 0x804e }, +/* 0x804f */ { false, 0x804f, 0x804f }, +/* 0x8050 */ { false, 0x8050, 0x8050 }, +/* 0x8051 */ { false, 0x8051, 0x8051 }, +/* 0x8052 */ { false, 0x8052, 0x8052 }, +/* 0x8053 */ { false, 0x8053, 0x8053 }, +/* 0x8054 */ { false, 0x8054, 0x8054 }, +/* 0x8055 */ { false, 0x8055, 0x8055 }, +/* 0x8056 */ { false, 0x8056, 0x8056 }, +/* 0x8057 */ { false, 0x8057, 0x8057 }, +/* 0x8058 */ { false, 0x8058, 0x8058 }, +/* 0x8059 */ { false, 0x8059, 0x8059 }, +/* 0x805a */ { false, 0x805a, 0x805a }, +/* 0x805b */ { false, 0x805b, 0x805b }, +/* 0x805c */ { false, 0x805c, 0x805c }, +/* 0x805d */ { false, 0x805d, 0x805d }, +/* 0x805e */ { false, 0x805e, 0x805e }, +/* 0x805f */ { false, 0x805f, 0x805f }, +/* 0x8060 */ { false, 0x8060, 0x8060 }, +/* 0x8061 */ { false, 0x8061, 0x8061 }, +/* 0x8062 */ { false, 0x8062, 0x8062 }, +/* 0x8063 */ { false, 0x8063, 0x8063 }, +/* 0x8064 */ { false, 0x8064, 0x8064 }, +/* 0x8065 */ { false, 0x8065, 0x8065 }, +/* 0x8066 */ { false, 0x8066, 0x8066 }, +/* 0x8067 */ { false, 0x8067, 0x8067 }, +/* 0x8068 */ { false, 0x8068, 0x8068 }, +/* 0x8069 */ { false, 0x8069, 0x8069 }, +/* 0x806a */ { false, 0x806a, 0x806a }, +/* 0x806b */ { false, 0x806b, 0x806b }, +/* 0x806c */ { false, 0x806c, 0x806c }, +/* 0x806d */ { false, 0x806d, 0x806d }, +/* 0x806e */ { false, 0x806e, 0x806e }, +/* 0x806f */ { false, 0x806f, 0x806f }, +/* 0x8070 */ { false, 0x8070, 0x8070 }, +/* 0x8071 */ { false, 0x8071, 0x8071 }, +/* 0x8072 */ { false, 0x8072, 0x8072 }, +/* 0x8073 */ { false, 0x8073, 0x8073 }, +/* 0x8074 */ { false, 0x8074, 0x8074 }, +/* 0x8075 */ { false, 0x8075, 0x8075 }, +/* 0x8076 */ { false, 0x8076, 0x8076 }, +/* 0x8077 */ { false, 0x8077, 0x8077 }, +/* 0x8078 */ { false, 0x8078, 0x8078 }, +/* 0x8079 */ { false, 0x8079, 0x8079 }, +/* 0x807a */ { false, 0x807a, 0x807a }, +/* 0x807b */ { false, 0x807b, 0x807b }, +/* 0x807c */ { false, 0x807c, 0x807c }, +/* 0x807d */ { false, 0x807d, 0x807d }, +/* 0x807e */ { false, 0x807e, 0x807e }, +/* 0x807f */ { false, 0x807f, 0x807f }, +/* 0x8080 */ { false, 0x8080, 0x8080 }, +/* 0x8081 */ { false, 0x8081, 0x8081 }, +/* 0x8082 */ { false, 0x8082, 0x8082 }, +/* 0x8083 */ { false, 0x8083, 0x8083 }, +/* 0x8084 */ { false, 0x8084, 0x8084 }, +/* 0x8085 */ { false, 0x8085, 0x8085 }, +/* 0x8086 */ { false, 0x8086, 0x8086 }, +/* 0x8087 */ { false, 0x8087, 0x8087 }, +/* 0x8088 */ { false, 0x8088, 0x8088 }, +/* 0x8089 */ { false, 0x8089, 0x8089 }, +/* 0x808a */ { false, 0x808a, 0x808a }, +/* 0x808b */ { false, 0x808b, 0x808b }, +/* 0x808c */ { false, 0x808c, 0x808c }, +/* 0x808d */ { false, 0x808d, 0x808d }, +/* 0x808e */ { false, 0x808e, 0x808e }, +/* 0x808f */ { false, 0x808f, 0x808f }, +/* 0x8090 */ { false, 0x8090, 0x8090 }, +/* 0x8091 */ { false, 0x8091, 0x8091 }, +/* 0x8092 */ { false, 0x8092, 0x8092 }, +/* 0x8093 */ { false, 0x8093, 0x8093 }, +/* 0x8094 */ { false, 0x8094, 0x8094 }, +/* 0x8095 */ { false, 0x8095, 0x8095 }, +/* 0x8096 */ { false, 0x8096, 0x8096 }, +/* 0x8097 */ { false, 0x8097, 0x8097 }, +/* 0x8098 */ { false, 0x8098, 0x8098 }, +/* 0x8099 */ { false, 0x8099, 0x8099 }, +/* 0x809a */ { false, 0x809a, 0x809a }, +/* 0x809b */ { false, 0x809b, 0x809b }, +/* 0x809c */ { false, 0x809c, 0x809c }, +/* 0x809d */ { false, 0x809d, 0x809d }, +/* 0x809e */ { false, 0x809e, 0x809e }, +/* 0x809f */ { false, 0x809f, 0x809f }, +/* 0x80a0 */ { false, 0x80a0, 0x80a0 }, +/* 0x80a1 */ { false, 0x80a1, 0x80a1 }, +/* 0x80a2 */ { false, 0x80a2, 0x80a2 }, +/* 0x80a3 */ { false, 0x80a3, 0x80a3 }, +/* 0x80a4 */ { false, 0x80a4, 0x80a4 }, +/* 0x80a5 */ { false, 0x80a5, 0x80a5 }, +/* 0x80a6 */ { false, 0x80a6, 0x80a6 }, +/* 0x80a7 */ { false, 0x80a7, 0x80a7 }, +/* 0x80a8 */ { false, 0x80a8, 0x80a8 }, +/* 0x80a9 */ { false, 0x80a9, 0x80a9 }, +/* 0x80aa */ { false, 0x80aa, 0x80aa }, +/* 0x80ab */ { false, 0x80ab, 0x80ab }, +/* 0x80ac */ { false, 0x80ac, 0x80ac }, +/* 0x80ad */ { false, 0x80ad, 0x80ad }, +/* 0x80ae */ { false, 0x80ae, 0x80ae }, +/* 0x80af */ { false, 0x80af, 0x80af }, +/* 0x80b0 */ { false, 0x80b0, 0x80b0 }, +/* 0x80b1 */ { false, 0x80b1, 0x80b1 }, +/* 0x80b2 */ { false, 0x80b2, 0x80b2 }, +/* 0x80b3 */ { false, 0x80b3, 0x80b3 }, +/* 0x80b4 */ { false, 0x80b4, 0x80b4 }, +/* 0x80b5 */ { false, 0x80b5, 0x80b5 }, +/* 0x80b6 */ { false, 0x80b6, 0x80b6 }, +/* 0x80b7 */ { false, 0x80b7, 0x80b7 }, +/* 0x80b8 */ { false, 0x80b8, 0x80b8 }, +/* 0x80b9 */ { false, 0x80b9, 0x80b9 }, +/* 0x80ba */ { false, 0x80ba, 0x80ba }, +/* 0x80bb */ { false, 0x80bb, 0x80bb }, +/* 0x80bc */ { false, 0x80bc, 0x80bc }, +/* 0x80bd */ { false, 0x80bd, 0x80bd }, +/* 0x80be */ { false, 0x80be, 0x80be }, +/* 0x80bf */ { false, 0x80bf, 0x80bf }, +/* 0x80c0 */ { false, 0x80c0, 0x80c0 }, +/* 0x80c1 */ { false, 0x80c1, 0x80c1 }, +/* 0x80c2 */ { false, 0x80c2, 0x80c2 }, +/* 0x80c3 */ { false, 0x80c3, 0x80c3 }, +/* 0x80c4 */ { false, 0x80c4, 0x80c4 }, +/* 0x80c5 */ { false, 0x80c5, 0x80c5 }, +/* 0x80c6 */ { false, 0x80c6, 0x80c6 }, +/* 0x80c7 */ { false, 0x80c7, 0x80c7 }, +/* 0x80c8 */ { false, 0x80c8, 0x80c8 }, +/* 0x80c9 */ { false, 0x80c9, 0x80c9 }, +/* 0x80ca */ { false, 0x80ca, 0x80ca }, +/* 0x80cb */ { false, 0x80cb, 0x80cb }, +/* 0x80cc */ { false, 0x80cc, 0x80cc }, +/* 0x80cd */ { false, 0x80cd, 0x80cd }, +/* 0x80ce */ { false, 0x80ce, 0x80ce }, +/* 0x80cf */ { false, 0x80cf, 0x80cf }, +/* 0x80d0 */ { false, 0x80d0, 0x80d0 }, +/* 0x80d1 */ { false, 0x80d1, 0x80d1 }, +/* 0x80d2 */ { false, 0x80d2, 0x80d2 }, +/* 0x80d3 */ { false, 0x80d3, 0x80d3 }, +/* 0x80d4 */ { false, 0x80d4, 0x80d4 }, +/* 0x80d5 */ { false, 0x80d5, 0x80d5 }, +/* 0x80d6 */ { false, 0x80d6, 0x80d6 }, +/* 0x80d7 */ { false, 0x80d7, 0x80d7 }, +/* 0x80d8 */ { false, 0x80d8, 0x80d8 }, +/* 0x80d9 */ { false, 0x80d9, 0x80d9 }, +/* 0x80da */ { false, 0x80da, 0x80da }, +/* 0x80db */ { false, 0x80db, 0x80db }, +/* 0x80dc */ { false, 0x80dc, 0x80dc }, +/* 0x80dd */ { false, 0x80dd, 0x80dd }, +/* 0x80de */ { false, 0x80de, 0x80de }, +/* 0x80df */ { false, 0x80df, 0x80df }, +/* 0x80e0 */ { false, 0x80e0, 0x80e0 }, +/* 0x80e1 */ { false, 0x80e1, 0x80e1 }, +/* 0x80e2 */ { false, 0x80e2, 0x80e2 }, +/* 0x80e3 */ { false, 0x80e3, 0x80e3 }, +/* 0x80e4 */ { false, 0x80e4, 0x80e4 }, +/* 0x80e5 */ { false, 0x80e5, 0x80e5 }, +/* 0x80e6 */ { false, 0x80e6, 0x80e6 }, +/* 0x80e7 */ { false, 0x80e7, 0x80e7 }, +/* 0x80e8 */ { false, 0x80e8, 0x80e8 }, +/* 0x80e9 */ { false, 0x80e9, 0x80e9 }, +/* 0x80ea */ { false, 0x80ea, 0x80ea }, +/* 0x80eb */ { false, 0x80eb, 0x80eb }, +/* 0x80ec */ { false, 0x80ec, 0x80ec }, +/* 0x80ed */ { false, 0x80ed, 0x80ed }, +/* 0x80ee */ { false, 0x80ee, 0x80ee }, +/* 0x80ef */ { false, 0x80ef, 0x80ef }, +/* 0x80f0 */ { false, 0x80f0, 0x80f0 }, +/* 0x80f1 */ { false, 0x80f1, 0x80f1 }, +/* 0x80f2 */ { false, 0x80f2, 0x80f2 }, +/* 0x80f3 */ { false, 0x80f3, 0x80f3 }, +/* 0x80f4 */ { false, 0x80f4, 0x80f4 }, +/* 0x80f5 */ { false, 0x80f5, 0x80f5 }, +/* 0x80f6 */ { false, 0x80f6, 0x80f6 }, +/* 0x80f7 */ { false, 0x80f7, 0x80f7 }, +/* 0x80f8 */ { false, 0x80f8, 0x80f8 }, +/* 0x80f9 */ { false, 0x80f9, 0x80f9 }, +/* 0x80fa */ { false, 0x80fa, 0x80fa }, +/* 0x80fb */ { false, 0x80fb, 0x80fb }, +/* 0x80fc */ { false, 0x80fc, 0x80fc }, +/* 0x80fd */ { false, 0x80fd, 0x80fd }, +/* 0x80fe */ { false, 0x80fe, 0x80fe }, +/* 0x80ff */ { false, 0x80ff, 0x80ff }, +/* 0x8100 */ { false, 0x8100, 0x8100 }, +/* 0x8101 */ { false, 0x8101, 0x8101 }, +/* 0x8102 */ { false, 0x8102, 0x8102 }, +/* 0x8103 */ { false, 0x8103, 0x8103 }, +/* 0x8104 */ { false, 0x8104, 0x8104 }, +/* 0x8105 */ { false, 0x8105, 0x8105 }, +/* 0x8106 */ { false, 0x8106, 0x8106 }, +/* 0x8107 */ { false, 0x8107, 0x8107 }, +/* 0x8108 */ { false, 0x8108, 0x8108 }, +/* 0x8109 */ { false, 0x8109, 0x8109 }, +/* 0x810a */ { false, 0x810a, 0x810a }, +/* 0x810b */ { false, 0x810b, 0x810b }, +/* 0x810c */ { false, 0x810c, 0x810c }, +/* 0x810d */ { false, 0x810d, 0x810d }, +/* 0x810e */ { false, 0x810e, 0x810e }, +/* 0x810f */ { false, 0x810f, 0x810f }, +/* 0x8110 */ { false, 0x8110, 0x8110 }, +/* 0x8111 */ { false, 0x8111, 0x8111 }, +/* 0x8112 */ { false, 0x8112, 0x8112 }, +/* 0x8113 */ { false, 0x8113, 0x8113 }, +/* 0x8114 */ { false, 0x8114, 0x8114 }, +/* 0x8115 */ { false, 0x8115, 0x8115 }, +/* 0x8116 */ { false, 0x8116, 0x8116 }, +/* 0x8117 */ { false, 0x8117, 0x8117 }, +/* 0x8118 */ { false, 0x8118, 0x8118 }, +/* 0x8119 */ { false, 0x8119, 0x8119 }, +/* 0x811a */ { false, 0x811a, 0x811a }, +/* 0x811b */ { false, 0x811b, 0x811b }, +/* 0x811c */ { false, 0x811c, 0x811c }, +/* 0x811d */ { false, 0x811d, 0x811d }, +/* 0x811e */ { false, 0x811e, 0x811e }, +/* 0x811f */ { false, 0x811f, 0x811f }, +/* 0x8120 */ { false, 0x8120, 0x8120 }, +/* 0x8121 */ { false, 0x8121, 0x8121 }, +/* 0x8122 */ { false, 0x8122, 0x8122 }, +/* 0x8123 */ { false, 0x8123, 0x8123 }, +/* 0x8124 */ { false, 0x8124, 0x8124 }, +/* 0x8125 */ { false, 0x8125, 0x8125 }, +/* 0x8126 */ { false, 0x8126, 0x8126 }, +/* 0x8127 */ { false, 0x8127, 0x8127 }, +/* 0x8128 */ { false, 0x8128, 0x8128 }, +/* 0x8129 */ { false, 0x8129, 0x8129 }, +/* 0x812a */ { false, 0x812a, 0x812a }, +/* 0x812b */ { false, 0x812b, 0x812b }, +/* 0x812c */ { false, 0x812c, 0x812c }, +/* 0x812d */ { false, 0x812d, 0x812d }, +/* 0x812e */ { false, 0x812e, 0x812e }, +/* 0x812f */ { false, 0x812f, 0x812f }, +/* 0x8130 */ { false, 0x8130, 0x8130 }, +/* 0x8131 */ { false, 0x8131, 0x8131 }, +/* 0x8132 */ { false, 0x8132, 0x8132 }, +/* 0x8133 */ { false, 0x8133, 0x8133 }, +/* 0x8134 */ { false, 0x8134, 0x8134 }, +/* 0x8135 */ { false, 0x8135, 0x8135 }, +/* 0x8136 */ { false, 0x8136, 0x8136 }, +/* 0x8137 */ { false, 0x8137, 0x8137 }, +/* 0x8138 */ { false, 0x8138, 0x8138 }, +/* 0x8139 */ { false, 0x8139, 0x8139 }, +/* 0x813a */ { false, 0x813a, 0x813a }, +/* 0x813b */ { false, 0x813b, 0x813b }, +/* 0x813c */ { false, 0x813c, 0x813c }, +/* 0x813d */ { false, 0x813d, 0x813d }, +/* 0x813e */ { false, 0x813e, 0x813e }, +/* 0x813f */ { false, 0x813f, 0x813f }, +/* 0x8140 */ { false, 0x8140, 0x8140 }, +/* 0x8141 */ { false, 0x8141, 0x8141 }, +/* 0x8142 */ { false, 0x8142, 0x8142 }, +/* 0x8143 */ { false, 0x8143, 0x8143 }, +/* 0x8144 */ { false, 0x8144, 0x8144 }, +/* 0x8145 */ { false, 0x8145, 0x8145 }, +/* 0x8146 */ { false, 0x8146, 0x8146 }, +/* 0x8147 */ { false, 0x8147, 0x8147 }, +/* 0x8148 */ { false, 0x8148, 0x8148 }, +/* 0x8149 */ { false, 0x8149, 0x8149 }, +/* 0x814a */ { false, 0x814a, 0x814a }, +/* 0x814b */ { false, 0x814b, 0x814b }, +/* 0x814c */ { false, 0x814c, 0x814c }, +/* 0x814d */ { false, 0x814d, 0x814d }, +/* 0x814e */ { false, 0x814e, 0x814e }, +/* 0x814f */ { false, 0x814f, 0x814f }, +/* 0x8150 */ { false, 0x8150, 0x8150 }, +/* 0x8151 */ { false, 0x8151, 0x8151 }, +/* 0x8152 */ { false, 0x8152, 0x8152 }, +/* 0x8153 */ { false, 0x8153, 0x8153 }, +/* 0x8154 */ { false, 0x8154, 0x8154 }, +/* 0x8155 */ { false, 0x8155, 0x8155 }, +/* 0x8156 */ { false, 0x8156, 0x8156 }, +/* 0x8157 */ { false, 0x8157, 0x8157 }, +/* 0x8158 */ { false, 0x8158, 0x8158 }, +/* 0x8159 */ { false, 0x8159, 0x8159 }, +/* 0x815a */ { false, 0x815a, 0x815a }, +/* 0x815b */ { false, 0x815b, 0x815b }, +/* 0x815c */ { false, 0x815c, 0x815c }, +/* 0x815d */ { false, 0x815d, 0x815d }, +/* 0x815e */ { false, 0x815e, 0x815e }, +/* 0x815f */ { false, 0x815f, 0x815f }, +/* 0x8160 */ { false, 0x8160, 0x8160 }, +/* 0x8161 */ { false, 0x8161, 0x8161 }, +/* 0x8162 */ { false, 0x8162, 0x8162 }, +/* 0x8163 */ { false, 0x8163, 0x8163 }, +/* 0x8164 */ { false, 0x8164, 0x8164 }, +/* 0x8165 */ { false, 0x8165, 0x8165 }, +/* 0x8166 */ { false, 0x8166, 0x8166 }, +/* 0x8167 */ { false, 0x8167, 0x8167 }, +/* 0x8168 */ { false, 0x8168, 0x8168 }, +/* 0x8169 */ { false, 0x8169, 0x8169 }, +/* 0x816a */ { false, 0x816a, 0x816a }, +/* 0x816b */ { false, 0x816b, 0x816b }, +/* 0x816c */ { false, 0x816c, 0x816c }, +/* 0x816d */ { false, 0x816d, 0x816d }, +/* 0x816e */ { false, 0x816e, 0x816e }, +/* 0x816f */ { false, 0x816f, 0x816f }, +/* 0x8170 */ { false, 0x8170, 0x8170 }, +/* 0x8171 */ { false, 0x8171, 0x8171 }, +/* 0x8172 */ { false, 0x8172, 0x8172 }, +/* 0x8173 */ { false, 0x8173, 0x8173 }, +/* 0x8174 */ { false, 0x8174, 0x8174 }, +/* 0x8175 */ { false, 0x8175, 0x8175 }, +/* 0x8176 */ { false, 0x8176, 0x8176 }, +/* 0x8177 */ { false, 0x8177, 0x8177 }, +/* 0x8178 */ { false, 0x8178, 0x8178 }, +/* 0x8179 */ { false, 0x8179, 0x8179 }, +/* 0x817a */ { false, 0x817a, 0x817a }, +/* 0x817b */ { false, 0x817b, 0x817b }, +/* 0x817c */ { false, 0x817c, 0x817c }, +/* 0x817d */ { false, 0x817d, 0x817d }, +/* 0x817e */ { false, 0x817e, 0x817e }, +/* 0x817f */ { false, 0x817f, 0x817f }, +/* 0x8180 */ { false, 0x8180, 0x8180 }, +/* 0x8181 */ { false, 0x8181, 0x8181 }, +/* 0x8182 */ { false, 0x8182, 0x8182 }, +/* 0x8183 */ { false, 0x8183, 0x8183 }, +/* 0x8184 */ { false, 0x8184, 0x8184 }, +/* 0x8185 */ { false, 0x8185, 0x8185 }, +/* 0x8186 */ { false, 0x8186, 0x8186 }, +/* 0x8187 */ { false, 0x8187, 0x8187 }, +/* 0x8188 */ { false, 0x8188, 0x8188 }, +/* 0x8189 */ { false, 0x8189, 0x8189 }, +/* 0x818a */ { false, 0x818a, 0x818a }, +/* 0x818b */ { false, 0x818b, 0x818b }, +/* 0x818c */ { false, 0x818c, 0x818c }, +/* 0x818d */ { false, 0x818d, 0x818d }, +/* 0x818e */ { false, 0x818e, 0x818e }, +/* 0x818f */ { false, 0x818f, 0x818f }, +/* 0x8190 */ { false, 0x8190, 0x8190 }, +/* 0x8191 */ { false, 0x8191, 0x8191 }, +/* 0x8192 */ { false, 0x8192, 0x8192 }, +/* 0x8193 */ { false, 0x8193, 0x8193 }, +/* 0x8194 */ { false, 0x8194, 0x8194 }, +/* 0x8195 */ { false, 0x8195, 0x8195 }, +/* 0x8196 */ { false, 0x8196, 0x8196 }, +/* 0x8197 */ { false, 0x8197, 0x8197 }, +/* 0x8198 */ { false, 0x8198, 0x8198 }, +/* 0x8199 */ { false, 0x8199, 0x8199 }, +/* 0x819a */ { false, 0x819a, 0x819a }, +/* 0x819b */ { false, 0x819b, 0x819b }, +/* 0x819c */ { false, 0x819c, 0x819c }, +/* 0x819d */ { false, 0x819d, 0x819d }, +/* 0x819e */ { false, 0x819e, 0x819e }, +/* 0x819f */ { false, 0x819f, 0x819f }, +/* 0x81a0 */ { false, 0x81a0, 0x81a0 }, +/* 0x81a1 */ { false, 0x81a1, 0x81a1 }, +/* 0x81a2 */ { false, 0x81a2, 0x81a2 }, +/* 0x81a3 */ { false, 0x81a3, 0x81a3 }, +/* 0x81a4 */ { false, 0x81a4, 0x81a4 }, +/* 0x81a5 */ { false, 0x81a5, 0x81a5 }, +/* 0x81a6 */ { false, 0x81a6, 0x81a6 }, +/* 0x81a7 */ { false, 0x81a7, 0x81a7 }, +/* 0x81a8 */ { false, 0x81a8, 0x81a8 }, +/* 0x81a9 */ { false, 0x81a9, 0x81a9 }, +/* 0x81aa */ { false, 0x81aa, 0x81aa }, +/* 0x81ab */ { false, 0x81ab, 0x81ab }, +/* 0x81ac */ { false, 0x81ac, 0x81ac }, +/* 0x81ad */ { false, 0x81ad, 0x81ad }, +/* 0x81ae */ { false, 0x81ae, 0x81ae }, +/* 0x81af */ { false, 0x81af, 0x81af }, +/* 0x81b0 */ { false, 0x81b0, 0x81b0 }, +/* 0x81b1 */ { false, 0x81b1, 0x81b1 }, +/* 0x81b2 */ { false, 0x81b2, 0x81b2 }, +/* 0x81b3 */ { false, 0x81b3, 0x81b3 }, +/* 0x81b4 */ { false, 0x81b4, 0x81b4 }, +/* 0x81b5 */ { false, 0x81b5, 0x81b5 }, +/* 0x81b6 */ { false, 0x81b6, 0x81b6 }, +/* 0x81b7 */ { false, 0x81b7, 0x81b7 }, +/* 0x81b8 */ { false, 0x81b8, 0x81b8 }, +/* 0x81b9 */ { false, 0x81b9, 0x81b9 }, +/* 0x81ba */ { false, 0x81ba, 0x81ba }, +/* 0x81bb */ { false, 0x81bb, 0x81bb }, +/* 0x81bc */ { false, 0x81bc, 0x81bc }, +/* 0x81bd */ { false, 0x81bd, 0x81bd }, +/* 0x81be */ { false, 0x81be, 0x81be }, +/* 0x81bf */ { false, 0x81bf, 0x81bf }, +/* 0x81c0 */ { false, 0x81c0, 0x81c0 }, +/* 0x81c1 */ { false, 0x81c1, 0x81c1 }, +/* 0x81c2 */ { false, 0x81c2, 0x81c2 }, +/* 0x81c3 */ { false, 0x81c3, 0x81c3 }, +/* 0x81c4 */ { false, 0x81c4, 0x81c4 }, +/* 0x81c5 */ { false, 0x81c5, 0x81c5 }, +/* 0x81c6 */ { false, 0x81c6, 0x81c6 }, +/* 0x81c7 */ { false, 0x81c7, 0x81c7 }, +/* 0x81c8 */ { false, 0x81c8, 0x81c8 }, +/* 0x81c9 */ { false, 0x81c9, 0x81c9 }, +/* 0x81ca */ { false, 0x81ca, 0x81ca }, +/* 0x81cb */ { false, 0x81cb, 0x81cb }, +/* 0x81cc */ { false, 0x81cc, 0x81cc }, +/* 0x81cd */ { false, 0x81cd, 0x81cd }, +/* 0x81ce */ { false, 0x81ce, 0x81ce }, +/* 0x81cf */ { false, 0x81cf, 0x81cf }, +/* 0x81d0 */ { false, 0x81d0, 0x81d0 }, +/* 0x81d1 */ { false, 0x81d1, 0x81d1 }, +/* 0x81d2 */ { false, 0x81d2, 0x81d2 }, +/* 0x81d3 */ { false, 0x81d3, 0x81d3 }, +/* 0x81d4 */ { false, 0x81d4, 0x81d4 }, +/* 0x81d5 */ { false, 0x81d5, 0x81d5 }, +/* 0x81d6 */ { false, 0x81d6, 0x81d6 }, +/* 0x81d7 */ { false, 0x81d7, 0x81d7 }, +/* 0x81d8 */ { false, 0x81d8, 0x81d8 }, +/* 0x81d9 */ { false, 0x81d9, 0x81d9 }, +/* 0x81da */ { false, 0x81da, 0x81da }, +/* 0x81db */ { false, 0x81db, 0x81db }, +/* 0x81dc */ { false, 0x81dc, 0x81dc }, +/* 0x81dd */ { false, 0x81dd, 0x81dd }, +/* 0x81de */ { false, 0x81de, 0x81de }, +/* 0x81df */ { false, 0x81df, 0x81df }, +/* 0x81e0 */ { false, 0x81e0, 0x81e0 }, +/* 0x81e1 */ { false, 0x81e1, 0x81e1 }, +/* 0x81e2 */ { false, 0x81e2, 0x81e2 }, +/* 0x81e3 */ { false, 0x81e3, 0x81e3 }, +/* 0x81e4 */ { false, 0x81e4, 0x81e4 }, +/* 0x81e5 */ { false, 0x81e5, 0x81e5 }, +/* 0x81e6 */ { false, 0x81e6, 0x81e6 }, +/* 0x81e7 */ { false, 0x81e7, 0x81e7 }, +/* 0x81e8 */ { false, 0x81e8, 0x81e8 }, +/* 0x81e9 */ { false, 0x81e9, 0x81e9 }, +/* 0x81ea */ { false, 0x81ea, 0x81ea }, +/* 0x81eb */ { false, 0x81eb, 0x81eb }, +/* 0x81ec */ { false, 0x81ec, 0x81ec }, +/* 0x81ed */ { false, 0x81ed, 0x81ed }, +/* 0x81ee */ { false, 0x81ee, 0x81ee }, +/* 0x81ef */ { false, 0x81ef, 0x81ef }, +/* 0x81f0 */ { false, 0x81f0, 0x81f0 }, +/* 0x81f1 */ { false, 0x81f1, 0x81f1 }, +/* 0x81f2 */ { false, 0x81f2, 0x81f2 }, +/* 0x81f3 */ { false, 0x81f3, 0x81f3 }, +/* 0x81f4 */ { false, 0x81f4, 0x81f4 }, +/* 0x81f5 */ { false, 0x81f5, 0x81f5 }, +/* 0x81f6 */ { false, 0x81f6, 0x81f6 }, +/* 0x81f7 */ { false, 0x81f7, 0x81f7 }, +/* 0x81f8 */ { false, 0x81f8, 0x81f8 }, +/* 0x81f9 */ { false, 0x81f9, 0x81f9 }, +/* 0x81fa */ { false, 0x81fa, 0x81fa }, +/* 0x81fb */ { false, 0x81fb, 0x81fb }, +/* 0x81fc */ { false, 0x81fc, 0x81fc }, +/* 0x81fd */ { false, 0x81fd, 0x81fd }, +/* 0x81fe */ { false, 0x81fe, 0x81fe }, +/* 0x81ff */ { false, 0x81ff, 0x81ff }, +/* 0x8200 */ { false, 0x8200, 0x8200 }, +/* 0x8201 */ { false, 0x8201, 0x8201 }, +/* 0x8202 */ { false, 0x8202, 0x8202 }, +/* 0x8203 */ { false, 0x8203, 0x8203 }, +/* 0x8204 */ { false, 0x8204, 0x8204 }, +/* 0x8205 */ { false, 0x8205, 0x8205 }, +/* 0x8206 */ { false, 0x8206, 0x8206 }, +/* 0x8207 */ { false, 0x8207, 0x8207 }, +/* 0x8208 */ { false, 0x8208, 0x8208 }, +/* 0x8209 */ { false, 0x8209, 0x8209 }, +/* 0x820a */ { false, 0x820a, 0x820a }, +/* 0x820b */ { false, 0x820b, 0x820b }, +/* 0x820c */ { false, 0x820c, 0x820c }, +/* 0x820d */ { false, 0x820d, 0x820d }, +/* 0x820e */ { false, 0x820e, 0x820e }, +/* 0x820f */ { false, 0x820f, 0x820f }, +/* 0x8210 */ { false, 0x8210, 0x8210 }, +/* 0x8211 */ { false, 0x8211, 0x8211 }, +/* 0x8212 */ { false, 0x8212, 0x8212 }, +/* 0x8213 */ { false, 0x8213, 0x8213 }, +/* 0x8214 */ { false, 0x8214, 0x8214 }, +/* 0x8215 */ { false, 0x8215, 0x8215 }, +/* 0x8216 */ { false, 0x8216, 0x8216 }, +/* 0x8217 */ { false, 0x8217, 0x8217 }, +/* 0x8218 */ { false, 0x8218, 0x8218 }, +/* 0x8219 */ { false, 0x8219, 0x8219 }, +/* 0x821a */ { false, 0x821a, 0x821a }, +/* 0x821b */ { false, 0x821b, 0x821b }, +/* 0x821c */ { false, 0x821c, 0x821c }, +/* 0x821d */ { false, 0x821d, 0x821d }, +/* 0x821e */ { false, 0x821e, 0x821e }, +/* 0x821f */ { false, 0x821f, 0x821f }, +/* 0x8220 */ { false, 0x8220, 0x8220 }, +/* 0x8221 */ { false, 0x8221, 0x8221 }, +/* 0x8222 */ { false, 0x8222, 0x8222 }, +/* 0x8223 */ { false, 0x8223, 0x8223 }, +/* 0x8224 */ { false, 0x8224, 0x8224 }, +/* 0x8225 */ { false, 0x8225, 0x8225 }, +/* 0x8226 */ { false, 0x8226, 0x8226 }, +/* 0x8227 */ { false, 0x8227, 0x8227 }, +/* 0x8228 */ { false, 0x8228, 0x8228 }, +/* 0x8229 */ { false, 0x8229, 0x8229 }, +/* 0x822a */ { false, 0x822a, 0x822a }, +/* 0x822b */ { false, 0x822b, 0x822b }, +/* 0x822c */ { false, 0x822c, 0x822c }, +/* 0x822d */ { false, 0x822d, 0x822d }, +/* 0x822e */ { false, 0x822e, 0x822e }, +/* 0x822f */ { false, 0x822f, 0x822f }, +/* 0x8230 */ { false, 0x8230, 0x8230 }, +/* 0x8231 */ { false, 0x8231, 0x8231 }, +/* 0x8232 */ { false, 0x8232, 0x8232 }, +/* 0x8233 */ { false, 0x8233, 0x8233 }, +/* 0x8234 */ { false, 0x8234, 0x8234 }, +/* 0x8235 */ { false, 0x8235, 0x8235 }, +/* 0x8236 */ { false, 0x8236, 0x8236 }, +/* 0x8237 */ { false, 0x8237, 0x8237 }, +/* 0x8238 */ { false, 0x8238, 0x8238 }, +/* 0x8239 */ { false, 0x8239, 0x8239 }, +/* 0x823a */ { false, 0x823a, 0x823a }, +/* 0x823b */ { false, 0x823b, 0x823b }, +/* 0x823c */ { false, 0x823c, 0x823c }, +/* 0x823d */ { false, 0x823d, 0x823d }, +/* 0x823e */ { false, 0x823e, 0x823e }, +/* 0x823f */ { false, 0x823f, 0x823f }, +/* 0x8240 */ { false, 0x8240, 0x8240 }, +/* 0x8241 */ { false, 0x8241, 0x8241 }, +/* 0x8242 */ { false, 0x8242, 0x8242 }, +/* 0x8243 */ { false, 0x8243, 0x8243 }, +/* 0x8244 */ { false, 0x8244, 0x8244 }, +/* 0x8245 */ { false, 0x8245, 0x8245 }, +/* 0x8246 */ { false, 0x8246, 0x8246 }, +/* 0x8247 */ { false, 0x8247, 0x8247 }, +/* 0x8248 */ { false, 0x8248, 0x8248 }, +/* 0x8249 */ { false, 0x8249, 0x8249 }, +/* 0x824a */ { false, 0x824a, 0x824a }, +/* 0x824b */ { false, 0x824b, 0x824b }, +/* 0x824c */ { false, 0x824c, 0x824c }, +/* 0x824d */ { false, 0x824d, 0x824d }, +/* 0x824e */ { false, 0x824e, 0x824e }, +/* 0x824f */ { false, 0x824f, 0x824f }, +/* 0x8250 */ { false, 0x8250, 0x8250 }, +/* 0x8251 */ { false, 0x8251, 0x8251 }, +/* 0x8252 */ { false, 0x8252, 0x8252 }, +/* 0x8253 */ { false, 0x8253, 0x8253 }, +/* 0x8254 */ { false, 0x8254, 0x8254 }, +/* 0x8255 */ { false, 0x8255, 0x8255 }, +/* 0x8256 */ { false, 0x8256, 0x8256 }, +/* 0x8257 */ { false, 0x8257, 0x8257 }, +/* 0x8258 */ { false, 0x8258, 0x8258 }, +/* 0x8259 */ { false, 0x8259, 0x8259 }, +/* 0x825a */ { false, 0x825a, 0x825a }, +/* 0x825b */ { false, 0x825b, 0x825b }, +/* 0x825c */ { false, 0x825c, 0x825c }, +/* 0x825d */ { false, 0x825d, 0x825d }, +/* 0x825e */ { false, 0x825e, 0x825e }, +/* 0x825f */ { false, 0x825f, 0x825f }, +/* 0x8260 */ { false, 0x8260, 0x8260 }, +/* 0x8261 */ { false, 0x8261, 0x8261 }, +/* 0x8262 */ { false, 0x8262, 0x8262 }, +/* 0x8263 */ { false, 0x8263, 0x8263 }, +/* 0x8264 */ { false, 0x8264, 0x8264 }, +/* 0x8265 */ { false, 0x8265, 0x8265 }, +/* 0x8266 */ { false, 0x8266, 0x8266 }, +/* 0x8267 */ { false, 0x8267, 0x8267 }, +/* 0x8268 */ { false, 0x8268, 0x8268 }, +/* 0x8269 */ { false, 0x8269, 0x8269 }, +/* 0x826a */ { false, 0x826a, 0x826a }, +/* 0x826b */ { false, 0x826b, 0x826b }, +/* 0x826c */ { false, 0x826c, 0x826c }, +/* 0x826d */ { false, 0x826d, 0x826d }, +/* 0x826e */ { false, 0x826e, 0x826e }, +/* 0x826f */ { false, 0x826f, 0x826f }, +/* 0x8270 */ { false, 0x8270, 0x8270 }, +/* 0x8271 */ { false, 0x8271, 0x8271 }, +/* 0x8272 */ { false, 0x8272, 0x8272 }, +/* 0x8273 */ { false, 0x8273, 0x8273 }, +/* 0x8274 */ { false, 0x8274, 0x8274 }, +/* 0x8275 */ { false, 0x8275, 0x8275 }, +/* 0x8276 */ { false, 0x8276, 0x8276 }, +/* 0x8277 */ { false, 0x8277, 0x8277 }, +/* 0x8278 */ { false, 0x8278, 0x8278 }, +/* 0x8279 */ { false, 0x8279, 0x8279 }, +/* 0x827a */ { false, 0x827a, 0x827a }, +/* 0x827b */ { false, 0x827b, 0x827b }, +/* 0x827c */ { false, 0x827c, 0x827c }, +/* 0x827d */ { false, 0x827d, 0x827d }, +/* 0x827e */ { false, 0x827e, 0x827e }, +/* 0x827f */ { false, 0x827f, 0x827f }, +/* 0x8280 */ { false, 0x8280, 0x8280 }, +/* 0x8281 */ { false, 0x8281, 0x8281 }, +/* 0x8282 */ { false, 0x8282, 0x8282 }, +/* 0x8283 */ { false, 0x8283, 0x8283 }, +/* 0x8284 */ { false, 0x8284, 0x8284 }, +/* 0x8285 */ { false, 0x8285, 0x8285 }, +/* 0x8286 */ { false, 0x8286, 0x8286 }, +/* 0x8287 */ { false, 0x8287, 0x8287 }, +/* 0x8288 */ { false, 0x8288, 0x8288 }, +/* 0x8289 */ { false, 0x8289, 0x8289 }, +/* 0x828a */ { false, 0x828a, 0x828a }, +/* 0x828b */ { false, 0x828b, 0x828b }, +/* 0x828c */ { false, 0x828c, 0x828c }, +/* 0x828d */ { false, 0x828d, 0x828d }, +/* 0x828e */ { false, 0x828e, 0x828e }, +/* 0x828f */ { false, 0x828f, 0x828f }, +/* 0x8290 */ { false, 0x8290, 0x8290 }, +/* 0x8291 */ { false, 0x8291, 0x8291 }, +/* 0x8292 */ { false, 0x8292, 0x8292 }, +/* 0x8293 */ { false, 0x8293, 0x8293 }, +/* 0x8294 */ { false, 0x8294, 0x8294 }, +/* 0x8295 */ { false, 0x8295, 0x8295 }, +/* 0x8296 */ { false, 0x8296, 0x8296 }, +/* 0x8297 */ { false, 0x8297, 0x8297 }, +/* 0x8298 */ { false, 0x8298, 0x8298 }, +/* 0x8299 */ { false, 0x8299, 0x8299 }, +/* 0x829a */ { false, 0x829a, 0x829a }, +/* 0x829b */ { false, 0x829b, 0x829b }, +/* 0x829c */ { false, 0x829c, 0x829c }, +/* 0x829d */ { false, 0x829d, 0x829d }, +/* 0x829e */ { false, 0x829e, 0x829e }, +/* 0x829f */ { false, 0x829f, 0x829f }, +/* 0x82a0 */ { false, 0x82a0, 0x82a0 }, +/* 0x82a1 */ { false, 0x82a1, 0x82a1 }, +/* 0x82a2 */ { false, 0x82a2, 0x82a2 }, +/* 0x82a3 */ { false, 0x82a3, 0x82a3 }, +/* 0x82a4 */ { false, 0x82a4, 0x82a4 }, +/* 0x82a5 */ { false, 0x82a5, 0x82a5 }, +/* 0x82a6 */ { false, 0x82a6, 0x82a6 }, +/* 0x82a7 */ { false, 0x82a7, 0x82a7 }, +/* 0x82a8 */ { false, 0x82a8, 0x82a8 }, +/* 0x82a9 */ { false, 0x82a9, 0x82a9 }, +/* 0x82aa */ { false, 0x82aa, 0x82aa }, +/* 0x82ab */ { false, 0x82ab, 0x82ab }, +/* 0x82ac */ { false, 0x82ac, 0x82ac }, +/* 0x82ad */ { false, 0x82ad, 0x82ad }, +/* 0x82ae */ { false, 0x82ae, 0x82ae }, +/* 0x82af */ { false, 0x82af, 0x82af }, +/* 0x82b0 */ { false, 0x82b0, 0x82b0 }, +/* 0x82b1 */ { false, 0x82b1, 0x82b1 }, +/* 0x82b2 */ { false, 0x82b2, 0x82b2 }, +/* 0x82b3 */ { false, 0x82b3, 0x82b3 }, +/* 0x82b4 */ { false, 0x82b4, 0x82b4 }, +/* 0x82b5 */ { false, 0x82b5, 0x82b5 }, +/* 0x82b6 */ { false, 0x82b6, 0x82b6 }, +/* 0x82b7 */ { false, 0x82b7, 0x82b7 }, +/* 0x82b8 */ { false, 0x82b8, 0x82b8 }, +/* 0x82b9 */ { false, 0x82b9, 0x82b9 }, +/* 0x82ba */ { false, 0x82ba, 0x82ba }, +/* 0x82bb */ { false, 0x82bb, 0x82bb }, +/* 0x82bc */ { false, 0x82bc, 0x82bc }, +/* 0x82bd */ { false, 0x82bd, 0x82bd }, +/* 0x82be */ { false, 0x82be, 0x82be }, +/* 0x82bf */ { false, 0x82bf, 0x82bf }, +/* 0x82c0 */ { false, 0x82c0, 0x82c0 }, +/* 0x82c1 */ { false, 0x82c1, 0x82c1 }, +/* 0x82c2 */ { false, 0x82c2, 0x82c2 }, +/* 0x82c3 */ { false, 0x82c3, 0x82c3 }, +/* 0x82c4 */ { false, 0x82c4, 0x82c4 }, +/* 0x82c5 */ { false, 0x82c5, 0x82c5 }, +/* 0x82c6 */ { false, 0x82c6, 0x82c6 }, +/* 0x82c7 */ { false, 0x82c7, 0x82c7 }, +/* 0x82c8 */ { false, 0x82c8, 0x82c8 }, +/* 0x82c9 */ { false, 0x82c9, 0x82c9 }, +/* 0x82ca */ { false, 0x82ca, 0x82ca }, +/* 0x82cb */ { false, 0x82cb, 0x82cb }, +/* 0x82cc */ { false, 0x82cc, 0x82cc }, +/* 0x82cd */ { false, 0x82cd, 0x82cd }, +/* 0x82ce */ { false, 0x82ce, 0x82ce }, +/* 0x82cf */ { false, 0x82cf, 0x82cf }, +/* 0x82d0 */ { false, 0x82d0, 0x82d0 }, +/* 0x82d1 */ { false, 0x82d1, 0x82d1 }, +/* 0x82d2 */ { false, 0x82d2, 0x82d2 }, +/* 0x82d3 */ { false, 0x82d3, 0x82d3 }, +/* 0x82d4 */ { false, 0x82d4, 0x82d4 }, +/* 0x82d5 */ { false, 0x82d5, 0x82d5 }, +/* 0x82d6 */ { false, 0x82d6, 0x82d6 }, +/* 0x82d7 */ { false, 0x82d7, 0x82d7 }, +/* 0x82d8 */ { false, 0x82d8, 0x82d8 }, +/* 0x82d9 */ { false, 0x82d9, 0x82d9 }, +/* 0x82da */ { false, 0x82da, 0x82da }, +/* 0x82db */ { false, 0x82db, 0x82db }, +/* 0x82dc */ { false, 0x82dc, 0x82dc }, +/* 0x82dd */ { false, 0x82dd, 0x82dd }, +/* 0x82de */ { false, 0x82de, 0x82de }, +/* 0x82df */ { false, 0x82df, 0x82df }, +/* 0x82e0 */ { false, 0x82e0, 0x82e0 }, +/* 0x82e1 */ { false, 0x82e1, 0x82e1 }, +/* 0x82e2 */ { false, 0x82e2, 0x82e2 }, +/* 0x82e3 */ { false, 0x82e3, 0x82e3 }, +/* 0x82e4 */ { false, 0x82e4, 0x82e4 }, +/* 0x82e5 */ { false, 0x82e5, 0x82e5 }, +/* 0x82e6 */ { false, 0x82e6, 0x82e6 }, +/* 0x82e7 */ { false, 0x82e7, 0x82e7 }, +/* 0x82e8 */ { false, 0x82e8, 0x82e8 }, +/* 0x82e9 */ { false, 0x82e9, 0x82e9 }, +/* 0x82ea */ { false, 0x82ea, 0x82ea }, +/* 0x82eb */ { false, 0x82eb, 0x82eb }, +/* 0x82ec */ { false, 0x82ec, 0x82ec }, +/* 0x82ed */ { false, 0x82ed, 0x82ed }, +/* 0x82ee */ { false, 0x82ee, 0x82ee }, +/* 0x82ef */ { false, 0x82ef, 0x82ef }, +/* 0x82f0 */ { false, 0x82f0, 0x82f0 }, +/* 0x82f1 */ { false, 0x82f1, 0x82f1 }, +/* 0x82f2 */ { false, 0x82f2, 0x82f2 }, +/* 0x82f3 */ { false, 0x82f3, 0x82f3 }, +/* 0x82f4 */ { false, 0x82f4, 0x82f4 }, +/* 0x82f5 */ { false, 0x82f5, 0x82f5 }, +/* 0x82f6 */ { false, 0x82f6, 0x82f6 }, +/* 0x82f7 */ { false, 0x82f7, 0x82f7 }, +/* 0x82f8 */ { false, 0x82f8, 0x82f8 }, +/* 0x82f9 */ { false, 0x82f9, 0x82f9 }, +/* 0x82fa */ { false, 0x82fa, 0x82fa }, +/* 0x82fb */ { false, 0x82fb, 0x82fb }, +/* 0x82fc */ { false, 0x82fc, 0x82fc }, +/* 0x82fd */ { false, 0x82fd, 0x82fd }, +/* 0x82fe */ { false, 0x82fe, 0x82fe }, +/* 0x82ff */ { false, 0x82ff, 0x82ff }, +/* 0x8300 */ { false, 0x8300, 0x8300 }, +/* 0x8301 */ { false, 0x8301, 0x8301 }, +/* 0x8302 */ { false, 0x8302, 0x8302 }, +/* 0x8303 */ { false, 0x8303, 0x8303 }, +/* 0x8304 */ { false, 0x8304, 0x8304 }, +/* 0x8305 */ { false, 0x8305, 0x8305 }, +/* 0x8306 */ { false, 0x8306, 0x8306 }, +/* 0x8307 */ { false, 0x8307, 0x8307 }, +/* 0x8308 */ { false, 0x8308, 0x8308 }, +/* 0x8309 */ { false, 0x8309, 0x8309 }, +/* 0x830a */ { false, 0x830a, 0x830a }, +/* 0x830b */ { false, 0x830b, 0x830b }, +/* 0x830c */ { false, 0x830c, 0x830c }, +/* 0x830d */ { false, 0x830d, 0x830d }, +/* 0x830e */ { false, 0x830e, 0x830e }, +/* 0x830f */ { false, 0x830f, 0x830f }, +/* 0x8310 */ { false, 0x8310, 0x8310 }, +/* 0x8311 */ { false, 0x8311, 0x8311 }, +/* 0x8312 */ { false, 0x8312, 0x8312 }, +/* 0x8313 */ { false, 0x8313, 0x8313 }, +/* 0x8314 */ { false, 0x8314, 0x8314 }, +/* 0x8315 */ { false, 0x8315, 0x8315 }, +/* 0x8316 */ { false, 0x8316, 0x8316 }, +/* 0x8317 */ { false, 0x8317, 0x8317 }, +/* 0x8318 */ { false, 0x8318, 0x8318 }, +/* 0x8319 */ { false, 0x8319, 0x8319 }, +/* 0x831a */ { false, 0x831a, 0x831a }, +/* 0x831b */ { false, 0x831b, 0x831b }, +/* 0x831c */ { false, 0x831c, 0x831c }, +/* 0x831d */ { false, 0x831d, 0x831d }, +/* 0x831e */ { false, 0x831e, 0x831e }, +/* 0x831f */ { false, 0x831f, 0x831f }, +/* 0x8320 */ { false, 0x8320, 0x8320 }, +/* 0x8321 */ { false, 0x8321, 0x8321 }, +/* 0x8322 */ { false, 0x8322, 0x8322 }, +/* 0x8323 */ { false, 0x8323, 0x8323 }, +/* 0x8324 */ { false, 0x8324, 0x8324 }, +/* 0x8325 */ { false, 0x8325, 0x8325 }, +/* 0x8326 */ { false, 0x8326, 0x8326 }, +/* 0x8327 */ { false, 0x8327, 0x8327 }, +/* 0x8328 */ { false, 0x8328, 0x8328 }, +/* 0x8329 */ { false, 0x8329, 0x8329 }, +/* 0x832a */ { false, 0x832a, 0x832a }, +/* 0x832b */ { false, 0x832b, 0x832b }, +/* 0x832c */ { false, 0x832c, 0x832c }, +/* 0x832d */ { false, 0x832d, 0x832d }, +/* 0x832e */ { false, 0x832e, 0x832e }, +/* 0x832f */ { false, 0x832f, 0x832f }, +/* 0x8330 */ { false, 0x8330, 0x8330 }, +/* 0x8331 */ { false, 0x8331, 0x8331 }, +/* 0x8332 */ { false, 0x8332, 0x8332 }, +/* 0x8333 */ { false, 0x8333, 0x8333 }, +/* 0x8334 */ { false, 0x8334, 0x8334 }, +/* 0x8335 */ { false, 0x8335, 0x8335 }, +/* 0x8336 */ { false, 0x8336, 0x8336 }, +/* 0x8337 */ { false, 0x8337, 0x8337 }, +/* 0x8338 */ { false, 0x8338, 0x8338 }, +/* 0x8339 */ { false, 0x8339, 0x8339 }, +/* 0x833a */ { false, 0x833a, 0x833a }, +/* 0x833b */ { false, 0x833b, 0x833b }, +/* 0x833c */ { false, 0x833c, 0x833c }, +/* 0x833d */ { false, 0x833d, 0x833d }, +/* 0x833e */ { false, 0x833e, 0x833e }, +/* 0x833f */ { false, 0x833f, 0x833f }, +/* 0x8340 */ { false, 0x8340, 0x8340 }, +/* 0x8341 */ { false, 0x8341, 0x8341 }, +/* 0x8342 */ { false, 0x8342, 0x8342 }, +/* 0x8343 */ { false, 0x8343, 0x8343 }, +/* 0x8344 */ { false, 0x8344, 0x8344 }, +/* 0x8345 */ { false, 0x8345, 0x8345 }, +/* 0x8346 */ { false, 0x8346, 0x8346 }, +/* 0x8347 */ { false, 0x8347, 0x8347 }, +/* 0x8348 */ { false, 0x8348, 0x8348 }, +/* 0x8349 */ { false, 0x8349, 0x8349 }, +/* 0x834a */ { false, 0x834a, 0x834a }, +/* 0x834b */ { false, 0x834b, 0x834b }, +/* 0x834c */ { false, 0x834c, 0x834c }, +/* 0x834d */ { false, 0x834d, 0x834d }, +/* 0x834e */ { false, 0x834e, 0x834e }, +/* 0x834f */ { false, 0x834f, 0x834f }, +/* 0x8350 */ { false, 0x8350, 0x8350 }, +/* 0x8351 */ { false, 0x8351, 0x8351 }, +/* 0x8352 */ { false, 0x8352, 0x8352 }, +/* 0x8353 */ { false, 0x8353, 0x8353 }, +/* 0x8354 */ { false, 0x8354, 0x8354 }, +/* 0x8355 */ { false, 0x8355, 0x8355 }, +/* 0x8356 */ { false, 0x8356, 0x8356 }, +/* 0x8357 */ { false, 0x8357, 0x8357 }, +/* 0x8358 */ { false, 0x8358, 0x8358 }, +/* 0x8359 */ { false, 0x8359, 0x8359 }, +/* 0x835a */ { false, 0x835a, 0x835a }, +/* 0x835b */ { false, 0x835b, 0x835b }, +/* 0x835c */ { false, 0x835c, 0x835c }, +/* 0x835d */ { false, 0x835d, 0x835d }, +/* 0x835e */ { false, 0x835e, 0x835e }, +/* 0x835f */ { false, 0x835f, 0x835f }, +/* 0x8360 */ { false, 0x8360, 0x8360 }, +/* 0x8361 */ { false, 0x8361, 0x8361 }, +/* 0x8362 */ { false, 0x8362, 0x8362 }, +/* 0x8363 */ { false, 0x8363, 0x8363 }, +/* 0x8364 */ { false, 0x8364, 0x8364 }, +/* 0x8365 */ { false, 0x8365, 0x8365 }, +/* 0x8366 */ { false, 0x8366, 0x8366 }, +/* 0x8367 */ { false, 0x8367, 0x8367 }, +/* 0x8368 */ { false, 0x8368, 0x8368 }, +/* 0x8369 */ { false, 0x8369, 0x8369 }, +/* 0x836a */ { false, 0x836a, 0x836a }, +/* 0x836b */ { false, 0x836b, 0x836b }, +/* 0x836c */ { false, 0x836c, 0x836c }, +/* 0x836d */ { false, 0x836d, 0x836d }, +/* 0x836e */ { false, 0x836e, 0x836e }, +/* 0x836f */ { false, 0x836f, 0x836f }, +/* 0x8370 */ { false, 0x8370, 0x8370 }, +/* 0x8371 */ { false, 0x8371, 0x8371 }, +/* 0x8372 */ { false, 0x8372, 0x8372 }, +/* 0x8373 */ { false, 0x8373, 0x8373 }, +/* 0x8374 */ { false, 0x8374, 0x8374 }, +/* 0x8375 */ { false, 0x8375, 0x8375 }, +/* 0x8376 */ { false, 0x8376, 0x8376 }, +/* 0x8377 */ { false, 0x8377, 0x8377 }, +/* 0x8378 */ { false, 0x8378, 0x8378 }, +/* 0x8379 */ { false, 0x8379, 0x8379 }, +/* 0x837a */ { false, 0x837a, 0x837a }, +/* 0x837b */ { false, 0x837b, 0x837b }, +/* 0x837c */ { false, 0x837c, 0x837c }, +/* 0x837d */ { false, 0x837d, 0x837d }, +/* 0x837e */ { false, 0x837e, 0x837e }, +/* 0x837f */ { false, 0x837f, 0x837f }, +/* 0x8380 */ { false, 0x8380, 0x8380 }, +/* 0x8381 */ { false, 0x8381, 0x8381 }, +/* 0x8382 */ { false, 0x8382, 0x8382 }, +/* 0x8383 */ { false, 0x8383, 0x8383 }, +/* 0x8384 */ { false, 0x8384, 0x8384 }, +/* 0x8385 */ { false, 0x8385, 0x8385 }, +/* 0x8386 */ { false, 0x8386, 0x8386 }, +/* 0x8387 */ { false, 0x8387, 0x8387 }, +/* 0x8388 */ { false, 0x8388, 0x8388 }, +/* 0x8389 */ { false, 0x8389, 0x8389 }, +/* 0x838a */ { false, 0x838a, 0x838a }, +/* 0x838b */ { false, 0x838b, 0x838b }, +/* 0x838c */ { false, 0x838c, 0x838c }, +/* 0x838d */ { false, 0x838d, 0x838d }, +/* 0x838e */ { false, 0x838e, 0x838e }, +/* 0x838f */ { false, 0x838f, 0x838f }, +/* 0x8390 */ { false, 0x8390, 0x8390 }, +/* 0x8391 */ { false, 0x8391, 0x8391 }, +/* 0x8392 */ { false, 0x8392, 0x8392 }, +/* 0x8393 */ { false, 0x8393, 0x8393 }, +/* 0x8394 */ { false, 0x8394, 0x8394 }, +/* 0x8395 */ { false, 0x8395, 0x8395 }, +/* 0x8396 */ { false, 0x8396, 0x8396 }, +/* 0x8397 */ { false, 0x8397, 0x8397 }, +/* 0x8398 */ { false, 0x8398, 0x8398 }, +/* 0x8399 */ { false, 0x8399, 0x8399 }, +/* 0x839a */ { false, 0x839a, 0x839a }, +/* 0x839b */ { false, 0x839b, 0x839b }, +/* 0x839c */ { false, 0x839c, 0x839c }, +/* 0x839d */ { false, 0x839d, 0x839d }, +/* 0x839e */ { false, 0x839e, 0x839e }, +/* 0x839f */ { false, 0x839f, 0x839f }, +/* 0x83a0 */ { false, 0x83a0, 0x83a0 }, +/* 0x83a1 */ { false, 0x83a1, 0x83a1 }, +/* 0x83a2 */ { false, 0x83a2, 0x83a2 }, +/* 0x83a3 */ { false, 0x83a3, 0x83a3 }, +/* 0x83a4 */ { false, 0x83a4, 0x83a4 }, +/* 0x83a5 */ { false, 0x83a5, 0x83a5 }, +/* 0x83a6 */ { false, 0x83a6, 0x83a6 }, +/* 0x83a7 */ { false, 0x83a7, 0x83a7 }, +/* 0x83a8 */ { false, 0x83a8, 0x83a8 }, +/* 0x83a9 */ { false, 0x83a9, 0x83a9 }, +/* 0x83aa */ { false, 0x83aa, 0x83aa }, +/* 0x83ab */ { false, 0x83ab, 0x83ab }, +/* 0x83ac */ { false, 0x83ac, 0x83ac }, +/* 0x83ad */ { false, 0x83ad, 0x83ad }, +/* 0x83ae */ { false, 0x83ae, 0x83ae }, +/* 0x83af */ { false, 0x83af, 0x83af }, +/* 0x83b0 */ { false, 0x83b0, 0x83b0 }, +/* 0x83b1 */ { false, 0x83b1, 0x83b1 }, +/* 0x83b2 */ { false, 0x83b2, 0x83b2 }, +/* 0x83b3 */ { false, 0x83b3, 0x83b3 }, +/* 0x83b4 */ { false, 0x83b4, 0x83b4 }, +/* 0x83b5 */ { false, 0x83b5, 0x83b5 }, +/* 0x83b6 */ { false, 0x83b6, 0x83b6 }, +/* 0x83b7 */ { false, 0x83b7, 0x83b7 }, +/* 0x83b8 */ { false, 0x83b8, 0x83b8 }, +/* 0x83b9 */ { false, 0x83b9, 0x83b9 }, +/* 0x83ba */ { false, 0x83ba, 0x83ba }, +/* 0x83bb */ { false, 0x83bb, 0x83bb }, +/* 0x83bc */ { false, 0x83bc, 0x83bc }, +/* 0x83bd */ { false, 0x83bd, 0x83bd }, +/* 0x83be */ { false, 0x83be, 0x83be }, +/* 0x83bf */ { false, 0x83bf, 0x83bf }, +/* 0x83c0 */ { false, 0x83c0, 0x83c0 }, +/* 0x83c1 */ { false, 0x83c1, 0x83c1 }, +/* 0x83c2 */ { false, 0x83c2, 0x83c2 }, +/* 0x83c3 */ { false, 0x83c3, 0x83c3 }, +/* 0x83c4 */ { false, 0x83c4, 0x83c4 }, +/* 0x83c5 */ { false, 0x83c5, 0x83c5 }, +/* 0x83c6 */ { false, 0x83c6, 0x83c6 }, +/* 0x83c7 */ { false, 0x83c7, 0x83c7 }, +/* 0x83c8 */ { false, 0x83c8, 0x83c8 }, +/* 0x83c9 */ { false, 0x83c9, 0x83c9 }, +/* 0x83ca */ { false, 0x83ca, 0x83ca }, +/* 0x83cb */ { false, 0x83cb, 0x83cb }, +/* 0x83cc */ { false, 0x83cc, 0x83cc }, +/* 0x83cd */ { false, 0x83cd, 0x83cd }, +/* 0x83ce */ { false, 0x83ce, 0x83ce }, +/* 0x83cf */ { false, 0x83cf, 0x83cf }, +/* 0x83d0 */ { false, 0x83d0, 0x83d0 }, +/* 0x83d1 */ { false, 0x83d1, 0x83d1 }, +/* 0x83d2 */ { false, 0x83d2, 0x83d2 }, +/* 0x83d3 */ { false, 0x83d3, 0x83d3 }, +/* 0x83d4 */ { false, 0x83d4, 0x83d4 }, +/* 0x83d5 */ { false, 0x83d5, 0x83d5 }, +/* 0x83d6 */ { false, 0x83d6, 0x83d6 }, +/* 0x83d7 */ { false, 0x83d7, 0x83d7 }, +/* 0x83d8 */ { false, 0x83d8, 0x83d8 }, +/* 0x83d9 */ { false, 0x83d9, 0x83d9 }, +/* 0x83da */ { false, 0x83da, 0x83da }, +/* 0x83db */ { false, 0x83db, 0x83db }, +/* 0x83dc */ { false, 0x83dc, 0x83dc }, +/* 0x83dd */ { false, 0x83dd, 0x83dd }, +/* 0x83de */ { false, 0x83de, 0x83de }, +/* 0x83df */ { false, 0x83df, 0x83df }, +/* 0x83e0 */ { false, 0x83e0, 0x83e0 }, +/* 0x83e1 */ { false, 0x83e1, 0x83e1 }, +/* 0x83e2 */ { false, 0x83e2, 0x83e2 }, +/* 0x83e3 */ { false, 0x83e3, 0x83e3 }, +/* 0x83e4 */ { false, 0x83e4, 0x83e4 }, +/* 0x83e5 */ { false, 0x83e5, 0x83e5 }, +/* 0x83e6 */ { false, 0x83e6, 0x83e6 }, +/* 0x83e7 */ { false, 0x83e7, 0x83e7 }, +/* 0x83e8 */ { false, 0x83e8, 0x83e8 }, +/* 0x83e9 */ { false, 0x83e9, 0x83e9 }, +/* 0x83ea */ { false, 0x83ea, 0x83ea }, +/* 0x83eb */ { false, 0x83eb, 0x83eb }, +/* 0x83ec */ { false, 0x83ec, 0x83ec }, +/* 0x83ed */ { false, 0x83ed, 0x83ed }, +/* 0x83ee */ { false, 0x83ee, 0x83ee }, +/* 0x83ef */ { false, 0x83ef, 0x83ef }, +/* 0x83f0 */ { false, 0x83f0, 0x83f0 }, +/* 0x83f1 */ { false, 0x83f1, 0x83f1 }, +/* 0x83f2 */ { false, 0x83f2, 0x83f2 }, +/* 0x83f3 */ { false, 0x83f3, 0x83f3 }, +/* 0x83f4 */ { false, 0x83f4, 0x83f4 }, +/* 0x83f5 */ { false, 0x83f5, 0x83f5 }, +/* 0x83f6 */ { false, 0x83f6, 0x83f6 }, +/* 0x83f7 */ { false, 0x83f7, 0x83f7 }, +/* 0x83f8 */ { false, 0x83f8, 0x83f8 }, +/* 0x83f9 */ { false, 0x83f9, 0x83f9 }, +/* 0x83fa */ { false, 0x83fa, 0x83fa }, +/* 0x83fb */ { false, 0x83fb, 0x83fb }, +/* 0x83fc */ { false, 0x83fc, 0x83fc }, +/* 0x83fd */ { false, 0x83fd, 0x83fd }, +/* 0x83fe */ { false, 0x83fe, 0x83fe }, +/* 0x83ff */ { false, 0x83ff, 0x83ff }, +/* 0x8400 */ { false, 0x8400, 0x8400 }, +/* 0x8401 */ { false, 0x8401, 0x8401 }, +/* 0x8402 */ { false, 0x8402, 0x8402 }, +/* 0x8403 */ { false, 0x8403, 0x8403 }, +/* 0x8404 */ { false, 0x8404, 0x8404 }, +/* 0x8405 */ { false, 0x8405, 0x8405 }, +/* 0x8406 */ { false, 0x8406, 0x8406 }, +/* 0x8407 */ { false, 0x8407, 0x8407 }, +/* 0x8408 */ { false, 0x8408, 0x8408 }, +/* 0x8409 */ { false, 0x8409, 0x8409 }, +/* 0x840a */ { false, 0x840a, 0x840a }, +/* 0x840b */ { false, 0x840b, 0x840b }, +/* 0x840c */ { false, 0x840c, 0x840c }, +/* 0x840d */ { false, 0x840d, 0x840d }, +/* 0x840e */ { false, 0x840e, 0x840e }, +/* 0x840f */ { false, 0x840f, 0x840f }, +/* 0x8410 */ { false, 0x8410, 0x8410 }, +/* 0x8411 */ { false, 0x8411, 0x8411 }, +/* 0x8412 */ { false, 0x8412, 0x8412 }, +/* 0x8413 */ { false, 0x8413, 0x8413 }, +/* 0x8414 */ { false, 0x8414, 0x8414 }, +/* 0x8415 */ { false, 0x8415, 0x8415 }, +/* 0x8416 */ { false, 0x8416, 0x8416 }, +/* 0x8417 */ { false, 0x8417, 0x8417 }, +/* 0x8418 */ { false, 0x8418, 0x8418 }, +/* 0x8419 */ { false, 0x8419, 0x8419 }, +/* 0x841a */ { false, 0x841a, 0x841a }, +/* 0x841b */ { false, 0x841b, 0x841b }, +/* 0x841c */ { false, 0x841c, 0x841c }, +/* 0x841d */ { false, 0x841d, 0x841d }, +/* 0x841e */ { false, 0x841e, 0x841e }, +/* 0x841f */ { false, 0x841f, 0x841f }, +/* 0x8420 */ { false, 0x8420, 0x8420 }, +/* 0x8421 */ { false, 0x8421, 0x8421 }, +/* 0x8422 */ { false, 0x8422, 0x8422 }, +/* 0x8423 */ { false, 0x8423, 0x8423 }, +/* 0x8424 */ { false, 0x8424, 0x8424 }, +/* 0x8425 */ { false, 0x8425, 0x8425 }, +/* 0x8426 */ { false, 0x8426, 0x8426 }, +/* 0x8427 */ { false, 0x8427, 0x8427 }, +/* 0x8428 */ { false, 0x8428, 0x8428 }, +/* 0x8429 */ { false, 0x8429, 0x8429 }, +/* 0x842a */ { false, 0x842a, 0x842a }, +/* 0x842b */ { false, 0x842b, 0x842b }, +/* 0x842c */ { false, 0x842c, 0x842c }, +/* 0x842d */ { false, 0x842d, 0x842d }, +/* 0x842e */ { false, 0x842e, 0x842e }, +/* 0x842f */ { false, 0x842f, 0x842f }, +/* 0x8430 */ { false, 0x8430, 0x8430 }, +/* 0x8431 */ { false, 0x8431, 0x8431 }, +/* 0x8432 */ { false, 0x8432, 0x8432 }, +/* 0x8433 */ { false, 0x8433, 0x8433 }, +/* 0x8434 */ { false, 0x8434, 0x8434 }, +/* 0x8435 */ { false, 0x8435, 0x8435 }, +/* 0x8436 */ { false, 0x8436, 0x8436 }, +/* 0x8437 */ { false, 0x8437, 0x8437 }, +/* 0x8438 */ { false, 0x8438, 0x8438 }, +/* 0x8439 */ { false, 0x8439, 0x8439 }, +/* 0x843a */ { false, 0x843a, 0x843a }, +/* 0x843b */ { false, 0x843b, 0x843b }, +/* 0x843c */ { false, 0x843c, 0x843c }, +/* 0x843d */ { false, 0x843d, 0x843d }, +/* 0x843e */ { false, 0x843e, 0x843e }, +/* 0x843f */ { false, 0x843f, 0x843f }, +/* 0x8440 */ { false, 0x8440, 0x8440 }, +/* 0x8441 */ { false, 0x8441, 0x8441 }, +/* 0x8442 */ { false, 0x8442, 0x8442 }, +/* 0x8443 */ { false, 0x8443, 0x8443 }, +/* 0x8444 */ { false, 0x8444, 0x8444 }, +/* 0x8445 */ { false, 0x8445, 0x8445 }, +/* 0x8446 */ { false, 0x8446, 0x8446 }, +/* 0x8447 */ { false, 0x8447, 0x8447 }, +/* 0x8448 */ { false, 0x8448, 0x8448 }, +/* 0x8449 */ { false, 0x8449, 0x8449 }, +/* 0x844a */ { false, 0x844a, 0x844a }, +/* 0x844b */ { false, 0x844b, 0x844b }, +/* 0x844c */ { false, 0x844c, 0x844c }, +/* 0x844d */ { false, 0x844d, 0x844d }, +/* 0x844e */ { false, 0x844e, 0x844e }, +/* 0x844f */ { false, 0x844f, 0x844f }, +/* 0x8450 */ { false, 0x8450, 0x8450 }, +/* 0x8451 */ { false, 0x8451, 0x8451 }, +/* 0x8452 */ { false, 0x8452, 0x8452 }, +/* 0x8453 */ { false, 0x8453, 0x8453 }, +/* 0x8454 */ { false, 0x8454, 0x8454 }, +/* 0x8455 */ { false, 0x8455, 0x8455 }, +/* 0x8456 */ { false, 0x8456, 0x8456 }, +/* 0x8457 */ { false, 0x8457, 0x8457 }, +/* 0x8458 */ { false, 0x8458, 0x8458 }, +/* 0x8459 */ { false, 0x8459, 0x8459 }, +/* 0x845a */ { false, 0x845a, 0x845a }, +/* 0x845b */ { false, 0x845b, 0x845b }, +/* 0x845c */ { false, 0x845c, 0x845c }, +/* 0x845d */ { false, 0x845d, 0x845d }, +/* 0x845e */ { false, 0x845e, 0x845e }, +/* 0x845f */ { false, 0x845f, 0x845f }, +/* 0x8460 */ { false, 0x8460, 0x8460 }, +/* 0x8461 */ { false, 0x8461, 0x8461 }, +/* 0x8462 */ { false, 0x8462, 0x8462 }, +/* 0x8463 */ { false, 0x8463, 0x8463 }, +/* 0x8464 */ { false, 0x8464, 0x8464 }, +/* 0x8465 */ { false, 0x8465, 0x8465 }, +/* 0x8466 */ { false, 0x8466, 0x8466 }, +/* 0x8467 */ { false, 0x8467, 0x8467 }, +/* 0x8468 */ { false, 0x8468, 0x8468 }, +/* 0x8469 */ { false, 0x8469, 0x8469 }, +/* 0x846a */ { false, 0x846a, 0x846a }, +/* 0x846b */ { false, 0x846b, 0x846b }, +/* 0x846c */ { false, 0x846c, 0x846c }, +/* 0x846d */ { false, 0x846d, 0x846d }, +/* 0x846e */ { false, 0x846e, 0x846e }, +/* 0x846f */ { false, 0x846f, 0x846f }, +/* 0x8470 */ { false, 0x8470, 0x8470 }, +/* 0x8471 */ { false, 0x8471, 0x8471 }, +/* 0x8472 */ { false, 0x8472, 0x8472 }, +/* 0x8473 */ { false, 0x8473, 0x8473 }, +/* 0x8474 */ { false, 0x8474, 0x8474 }, +/* 0x8475 */ { false, 0x8475, 0x8475 }, +/* 0x8476 */ { false, 0x8476, 0x8476 }, +/* 0x8477 */ { false, 0x8477, 0x8477 }, +/* 0x8478 */ { false, 0x8478, 0x8478 }, +/* 0x8479 */ { false, 0x8479, 0x8479 }, +/* 0x847a */ { false, 0x847a, 0x847a }, +/* 0x847b */ { false, 0x847b, 0x847b }, +/* 0x847c */ { false, 0x847c, 0x847c }, +/* 0x847d */ { false, 0x847d, 0x847d }, +/* 0x847e */ { false, 0x847e, 0x847e }, +/* 0x847f */ { false, 0x847f, 0x847f }, +/* 0x8480 */ { false, 0x8480, 0x8480 }, +/* 0x8481 */ { false, 0x8481, 0x8481 }, +/* 0x8482 */ { false, 0x8482, 0x8482 }, +/* 0x8483 */ { false, 0x8483, 0x8483 }, +/* 0x8484 */ { false, 0x8484, 0x8484 }, +/* 0x8485 */ { false, 0x8485, 0x8485 }, +/* 0x8486 */ { false, 0x8486, 0x8486 }, +/* 0x8487 */ { false, 0x8487, 0x8487 }, +/* 0x8488 */ { false, 0x8488, 0x8488 }, +/* 0x8489 */ { false, 0x8489, 0x8489 }, +/* 0x848a */ { false, 0x848a, 0x848a }, +/* 0x848b */ { false, 0x848b, 0x848b }, +/* 0x848c */ { false, 0x848c, 0x848c }, +/* 0x848d */ { false, 0x848d, 0x848d }, +/* 0x848e */ { false, 0x848e, 0x848e }, +/* 0x848f */ { false, 0x848f, 0x848f }, +/* 0x8490 */ { false, 0x8490, 0x8490 }, +/* 0x8491 */ { false, 0x8491, 0x8491 }, +/* 0x8492 */ { false, 0x8492, 0x8492 }, +/* 0x8493 */ { false, 0x8493, 0x8493 }, +/* 0x8494 */ { false, 0x8494, 0x8494 }, +/* 0x8495 */ { false, 0x8495, 0x8495 }, +/* 0x8496 */ { false, 0x8496, 0x8496 }, +/* 0x8497 */ { false, 0x8497, 0x8497 }, +/* 0x8498 */ { false, 0x8498, 0x8498 }, +/* 0x8499 */ { false, 0x8499, 0x8499 }, +/* 0x849a */ { false, 0x849a, 0x849a }, +/* 0x849b */ { false, 0x849b, 0x849b }, +/* 0x849c */ { false, 0x849c, 0x849c }, +/* 0x849d */ { false, 0x849d, 0x849d }, +/* 0x849e */ { false, 0x849e, 0x849e }, +/* 0x849f */ { false, 0x849f, 0x849f }, +/* 0x84a0 */ { false, 0x84a0, 0x84a0 }, +/* 0x84a1 */ { false, 0x84a1, 0x84a1 }, +/* 0x84a2 */ { false, 0x84a2, 0x84a2 }, +/* 0x84a3 */ { false, 0x84a3, 0x84a3 }, +/* 0x84a4 */ { false, 0x84a4, 0x84a4 }, +/* 0x84a5 */ { false, 0x84a5, 0x84a5 }, +/* 0x84a6 */ { false, 0x84a6, 0x84a6 }, +/* 0x84a7 */ { false, 0x84a7, 0x84a7 }, +/* 0x84a8 */ { false, 0x84a8, 0x84a8 }, +/* 0x84a9 */ { false, 0x84a9, 0x84a9 }, +/* 0x84aa */ { false, 0x84aa, 0x84aa }, +/* 0x84ab */ { false, 0x84ab, 0x84ab }, +/* 0x84ac */ { false, 0x84ac, 0x84ac }, +/* 0x84ad */ { false, 0x84ad, 0x84ad }, +/* 0x84ae */ { false, 0x84ae, 0x84ae }, +/* 0x84af */ { false, 0x84af, 0x84af }, +/* 0x84b0 */ { false, 0x84b0, 0x84b0 }, +/* 0x84b1 */ { false, 0x84b1, 0x84b1 }, +/* 0x84b2 */ { false, 0x84b2, 0x84b2 }, +/* 0x84b3 */ { false, 0x84b3, 0x84b3 }, +/* 0x84b4 */ { false, 0x84b4, 0x84b4 }, +/* 0x84b5 */ { false, 0x84b5, 0x84b5 }, +/* 0x84b6 */ { false, 0x84b6, 0x84b6 }, +/* 0x84b7 */ { false, 0x84b7, 0x84b7 }, +/* 0x84b8 */ { false, 0x84b8, 0x84b8 }, +/* 0x84b9 */ { false, 0x84b9, 0x84b9 }, +/* 0x84ba */ { false, 0x84ba, 0x84ba }, +/* 0x84bb */ { false, 0x84bb, 0x84bb }, +/* 0x84bc */ { false, 0x84bc, 0x84bc }, +/* 0x84bd */ { false, 0x84bd, 0x84bd }, +/* 0x84be */ { false, 0x84be, 0x84be }, +/* 0x84bf */ { false, 0x84bf, 0x84bf }, +/* 0x84c0 */ { false, 0x84c0, 0x84c0 }, +/* 0x84c1 */ { false, 0x84c1, 0x84c1 }, +/* 0x84c2 */ { false, 0x84c2, 0x84c2 }, +/* 0x84c3 */ { false, 0x84c3, 0x84c3 }, +/* 0x84c4 */ { false, 0x84c4, 0x84c4 }, +/* 0x84c5 */ { false, 0x84c5, 0x84c5 }, +/* 0x84c6 */ { false, 0x84c6, 0x84c6 }, +/* 0x84c7 */ { false, 0x84c7, 0x84c7 }, +/* 0x84c8 */ { false, 0x84c8, 0x84c8 }, +/* 0x84c9 */ { false, 0x84c9, 0x84c9 }, +/* 0x84ca */ { false, 0x84ca, 0x84ca }, +/* 0x84cb */ { false, 0x84cb, 0x84cb }, +/* 0x84cc */ { false, 0x84cc, 0x84cc }, +/* 0x84cd */ { false, 0x84cd, 0x84cd }, +/* 0x84ce */ { false, 0x84ce, 0x84ce }, +/* 0x84cf */ { false, 0x84cf, 0x84cf }, +/* 0x84d0 */ { false, 0x84d0, 0x84d0 }, +/* 0x84d1 */ { false, 0x84d1, 0x84d1 }, +/* 0x84d2 */ { false, 0x84d2, 0x84d2 }, +/* 0x84d3 */ { false, 0x84d3, 0x84d3 }, +/* 0x84d4 */ { false, 0x84d4, 0x84d4 }, +/* 0x84d5 */ { false, 0x84d5, 0x84d5 }, +/* 0x84d6 */ { false, 0x84d6, 0x84d6 }, +/* 0x84d7 */ { false, 0x84d7, 0x84d7 }, +/* 0x84d8 */ { false, 0x84d8, 0x84d8 }, +/* 0x84d9 */ { false, 0x84d9, 0x84d9 }, +/* 0x84da */ { false, 0x84da, 0x84da }, +/* 0x84db */ { false, 0x84db, 0x84db }, +/* 0x84dc */ { false, 0x84dc, 0x84dc }, +/* 0x84dd */ { false, 0x84dd, 0x84dd }, +/* 0x84de */ { false, 0x84de, 0x84de }, +/* 0x84df */ { false, 0x84df, 0x84df }, +/* 0x84e0 */ { false, 0x84e0, 0x84e0 }, +/* 0x84e1 */ { false, 0x84e1, 0x84e1 }, +/* 0x84e2 */ { false, 0x84e2, 0x84e2 }, +/* 0x84e3 */ { false, 0x84e3, 0x84e3 }, +/* 0x84e4 */ { false, 0x84e4, 0x84e4 }, +/* 0x84e5 */ { false, 0x84e5, 0x84e5 }, +/* 0x84e6 */ { false, 0x84e6, 0x84e6 }, +/* 0x84e7 */ { false, 0x84e7, 0x84e7 }, +/* 0x84e8 */ { false, 0x84e8, 0x84e8 }, +/* 0x84e9 */ { false, 0x84e9, 0x84e9 }, +/* 0x84ea */ { false, 0x84ea, 0x84ea }, +/* 0x84eb */ { false, 0x84eb, 0x84eb }, +/* 0x84ec */ { false, 0x84ec, 0x84ec }, +/* 0x84ed */ { false, 0x84ed, 0x84ed }, +/* 0x84ee */ { false, 0x84ee, 0x84ee }, +/* 0x84ef */ { false, 0x84ef, 0x84ef }, +/* 0x84f0 */ { false, 0x84f0, 0x84f0 }, +/* 0x84f1 */ { false, 0x84f1, 0x84f1 }, +/* 0x84f2 */ { false, 0x84f2, 0x84f2 }, +/* 0x84f3 */ { false, 0x84f3, 0x84f3 }, +/* 0x84f4 */ { false, 0x84f4, 0x84f4 }, +/* 0x84f5 */ { false, 0x84f5, 0x84f5 }, +/* 0x84f6 */ { false, 0x84f6, 0x84f6 }, +/* 0x84f7 */ { false, 0x84f7, 0x84f7 }, +/* 0x84f8 */ { false, 0x84f8, 0x84f8 }, +/* 0x84f9 */ { false, 0x84f9, 0x84f9 }, +/* 0x84fa */ { false, 0x84fa, 0x84fa }, +/* 0x84fb */ { false, 0x84fb, 0x84fb }, +/* 0x84fc */ { false, 0x84fc, 0x84fc }, +/* 0x84fd */ { false, 0x84fd, 0x84fd }, +/* 0x84fe */ { false, 0x84fe, 0x84fe }, +/* 0x84ff */ { false, 0x84ff, 0x84ff }, +/* 0x8500 */ { false, 0x8500, 0x8500 }, +/* 0x8501 */ { false, 0x8501, 0x8501 }, +/* 0x8502 */ { false, 0x8502, 0x8502 }, +/* 0x8503 */ { false, 0x8503, 0x8503 }, +/* 0x8504 */ { false, 0x8504, 0x8504 }, +/* 0x8505 */ { false, 0x8505, 0x8505 }, +/* 0x8506 */ { false, 0x8506, 0x8506 }, +/* 0x8507 */ { false, 0x8507, 0x8507 }, +/* 0x8508 */ { false, 0x8508, 0x8508 }, +/* 0x8509 */ { false, 0x8509, 0x8509 }, +/* 0x850a */ { false, 0x850a, 0x850a }, +/* 0x850b */ { false, 0x850b, 0x850b }, +/* 0x850c */ { false, 0x850c, 0x850c }, +/* 0x850d */ { false, 0x850d, 0x850d }, +/* 0x850e */ { false, 0x850e, 0x850e }, +/* 0x850f */ { false, 0x850f, 0x850f }, +/* 0x8510 */ { false, 0x8510, 0x8510 }, +/* 0x8511 */ { false, 0x8511, 0x8511 }, +/* 0x8512 */ { false, 0x8512, 0x8512 }, +/* 0x8513 */ { false, 0x8513, 0x8513 }, +/* 0x8514 */ { false, 0x8514, 0x8514 }, +/* 0x8515 */ { false, 0x8515, 0x8515 }, +/* 0x8516 */ { false, 0x8516, 0x8516 }, +/* 0x8517 */ { false, 0x8517, 0x8517 }, +/* 0x8518 */ { false, 0x8518, 0x8518 }, +/* 0x8519 */ { false, 0x8519, 0x8519 }, +/* 0x851a */ { false, 0x851a, 0x851a }, +/* 0x851b */ { false, 0x851b, 0x851b }, +/* 0x851c */ { false, 0x851c, 0x851c }, +/* 0x851d */ { false, 0x851d, 0x851d }, +/* 0x851e */ { false, 0x851e, 0x851e }, +/* 0x851f */ { false, 0x851f, 0x851f }, +/* 0x8520 */ { false, 0x8520, 0x8520 }, +/* 0x8521 */ { false, 0x8521, 0x8521 }, +/* 0x8522 */ { false, 0x8522, 0x8522 }, +/* 0x8523 */ { false, 0x8523, 0x8523 }, +/* 0x8524 */ { false, 0x8524, 0x8524 }, +/* 0x8525 */ { false, 0x8525, 0x8525 }, +/* 0x8526 */ { false, 0x8526, 0x8526 }, +/* 0x8527 */ { false, 0x8527, 0x8527 }, +/* 0x8528 */ { false, 0x8528, 0x8528 }, +/* 0x8529 */ { false, 0x8529, 0x8529 }, +/* 0x852a */ { false, 0x852a, 0x852a }, +/* 0x852b */ { false, 0x852b, 0x852b }, +/* 0x852c */ { false, 0x852c, 0x852c }, +/* 0x852d */ { false, 0x852d, 0x852d }, +/* 0x852e */ { false, 0x852e, 0x852e }, +/* 0x852f */ { false, 0x852f, 0x852f }, +/* 0x8530 */ { false, 0x8530, 0x8530 }, +/* 0x8531 */ { false, 0x8531, 0x8531 }, +/* 0x8532 */ { false, 0x8532, 0x8532 }, +/* 0x8533 */ { false, 0x8533, 0x8533 }, +/* 0x8534 */ { false, 0x8534, 0x8534 }, +/* 0x8535 */ { false, 0x8535, 0x8535 }, +/* 0x8536 */ { false, 0x8536, 0x8536 }, +/* 0x8537 */ { false, 0x8537, 0x8537 }, +/* 0x8538 */ { false, 0x8538, 0x8538 }, +/* 0x8539 */ { false, 0x8539, 0x8539 }, +/* 0x853a */ { false, 0x853a, 0x853a }, +/* 0x853b */ { false, 0x853b, 0x853b }, +/* 0x853c */ { false, 0x853c, 0x853c }, +/* 0x853d */ { false, 0x853d, 0x853d }, +/* 0x853e */ { false, 0x853e, 0x853e }, +/* 0x853f */ { false, 0x853f, 0x853f }, +/* 0x8540 */ { false, 0x8540, 0x8540 }, +/* 0x8541 */ { false, 0x8541, 0x8541 }, +/* 0x8542 */ { false, 0x8542, 0x8542 }, +/* 0x8543 */ { false, 0x8543, 0x8543 }, +/* 0x8544 */ { false, 0x8544, 0x8544 }, +/* 0x8545 */ { false, 0x8545, 0x8545 }, +/* 0x8546 */ { false, 0x8546, 0x8546 }, +/* 0x8547 */ { false, 0x8547, 0x8547 }, +/* 0x8548 */ { false, 0x8548, 0x8548 }, +/* 0x8549 */ { false, 0x8549, 0x8549 }, +/* 0x854a */ { false, 0x854a, 0x854a }, +/* 0x854b */ { false, 0x854b, 0x854b }, +/* 0x854c */ { false, 0x854c, 0x854c }, +/* 0x854d */ { false, 0x854d, 0x854d }, +/* 0x854e */ { false, 0x854e, 0x854e }, +/* 0x854f */ { false, 0x854f, 0x854f }, +/* 0x8550 */ { false, 0x8550, 0x8550 }, +/* 0x8551 */ { false, 0x8551, 0x8551 }, +/* 0x8552 */ { false, 0x8552, 0x8552 }, +/* 0x8553 */ { false, 0x8553, 0x8553 }, +/* 0x8554 */ { false, 0x8554, 0x8554 }, +/* 0x8555 */ { false, 0x8555, 0x8555 }, +/* 0x8556 */ { false, 0x8556, 0x8556 }, +/* 0x8557 */ { false, 0x8557, 0x8557 }, +/* 0x8558 */ { false, 0x8558, 0x8558 }, +/* 0x8559 */ { false, 0x8559, 0x8559 }, +/* 0x855a */ { false, 0x855a, 0x855a }, +/* 0x855b */ { false, 0x855b, 0x855b }, +/* 0x855c */ { false, 0x855c, 0x855c }, +/* 0x855d */ { false, 0x855d, 0x855d }, +/* 0x855e */ { false, 0x855e, 0x855e }, +/* 0x855f */ { false, 0x855f, 0x855f }, +/* 0x8560 */ { false, 0x8560, 0x8560 }, +/* 0x8561 */ { false, 0x8561, 0x8561 }, +/* 0x8562 */ { false, 0x8562, 0x8562 }, +/* 0x8563 */ { false, 0x8563, 0x8563 }, +/* 0x8564 */ { false, 0x8564, 0x8564 }, +/* 0x8565 */ { false, 0x8565, 0x8565 }, +/* 0x8566 */ { false, 0x8566, 0x8566 }, +/* 0x8567 */ { false, 0x8567, 0x8567 }, +/* 0x8568 */ { false, 0x8568, 0x8568 }, +/* 0x8569 */ { false, 0x8569, 0x8569 }, +/* 0x856a */ { false, 0x856a, 0x856a }, +/* 0x856b */ { false, 0x856b, 0x856b }, +/* 0x856c */ { false, 0x856c, 0x856c }, +/* 0x856d */ { false, 0x856d, 0x856d }, +/* 0x856e */ { false, 0x856e, 0x856e }, +/* 0x856f */ { false, 0x856f, 0x856f }, +/* 0x8570 */ { false, 0x8570, 0x8570 }, +/* 0x8571 */ { false, 0x8571, 0x8571 }, +/* 0x8572 */ { false, 0x8572, 0x8572 }, +/* 0x8573 */ { false, 0x8573, 0x8573 }, +/* 0x8574 */ { false, 0x8574, 0x8574 }, +/* 0x8575 */ { false, 0x8575, 0x8575 }, +/* 0x8576 */ { false, 0x8576, 0x8576 }, +/* 0x8577 */ { false, 0x8577, 0x8577 }, +/* 0x8578 */ { false, 0x8578, 0x8578 }, +/* 0x8579 */ { false, 0x8579, 0x8579 }, +/* 0x857a */ { false, 0x857a, 0x857a }, +/* 0x857b */ { false, 0x857b, 0x857b }, +/* 0x857c */ { false, 0x857c, 0x857c }, +/* 0x857d */ { false, 0x857d, 0x857d }, +/* 0x857e */ { false, 0x857e, 0x857e }, +/* 0x857f */ { false, 0x857f, 0x857f }, +/* 0x8580 */ { false, 0x8580, 0x8580 }, +/* 0x8581 */ { false, 0x8581, 0x8581 }, +/* 0x8582 */ { false, 0x8582, 0x8582 }, +/* 0x8583 */ { false, 0x8583, 0x8583 }, +/* 0x8584 */ { false, 0x8584, 0x8584 }, +/* 0x8585 */ { false, 0x8585, 0x8585 }, +/* 0x8586 */ { false, 0x8586, 0x8586 }, +/* 0x8587 */ { false, 0x8587, 0x8587 }, +/* 0x8588 */ { false, 0x8588, 0x8588 }, +/* 0x8589 */ { false, 0x8589, 0x8589 }, +/* 0x858a */ { false, 0x858a, 0x858a }, +/* 0x858b */ { false, 0x858b, 0x858b }, +/* 0x858c */ { false, 0x858c, 0x858c }, +/* 0x858d */ { false, 0x858d, 0x858d }, +/* 0x858e */ { false, 0x858e, 0x858e }, +/* 0x858f */ { false, 0x858f, 0x858f }, +/* 0x8590 */ { false, 0x8590, 0x8590 }, +/* 0x8591 */ { false, 0x8591, 0x8591 }, +/* 0x8592 */ { false, 0x8592, 0x8592 }, +/* 0x8593 */ { false, 0x8593, 0x8593 }, +/* 0x8594 */ { false, 0x8594, 0x8594 }, +/* 0x8595 */ { false, 0x8595, 0x8595 }, +/* 0x8596 */ { false, 0x8596, 0x8596 }, +/* 0x8597 */ { false, 0x8597, 0x8597 }, +/* 0x8598 */ { false, 0x8598, 0x8598 }, +/* 0x8599 */ { false, 0x8599, 0x8599 }, +/* 0x859a */ { false, 0x859a, 0x859a }, +/* 0x859b */ { false, 0x859b, 0x859b }, +/* 0x859c */ { false, 0x859c, 0x859c }, +/* 0x859d */ { false, 0x859d, 0x859d }, +/* 0x859e */ { false, 0x859e, 0x859e }, +/* 0x859f */ { false, 0x859f, 0x859f }, +/* 0x85a0 */ { false, 0x85a0, 0x85a0 }, +/* 0x85a1 */ { false, 0x85a1, 0x85a1 }, +/* 0x85a2 */ { false, 0x85a2, 0x85a2 }, +/* 0x85a3 */ { false, 0x85a3, 0x85a3 }, +/* 0x85a4 */ { false, 0x85a4, 0x85a4 }, +/* 0x85a5 */ { false, 0x85a5, 0x85a5 }, +/* 0x85a6 */ { false, 0x85a6, 0x85a6 }, +/* 0x85a7 */ { false, 0x85a7, 0x85a7 }, +/* 0x85a8 */ { false, 0x85a8, 0x85a8 }, +/* 0x85a9 */ { false, 0x85a9, 0x85a9 }, +/* 0x85aa */ { false, 0x85aa, 0x85aa }, +/* 0x85ab */ { false, 0x85ab, 0x85ab }, +/* 0x85ac */ { false, 0x85ac, 0x85ac }, +/* 0x85ad */ { false, 0x85ad, 0x85ad }, +/* 0x85ae */ { false, 0x85ae, 0x85ae }, +/* 0x85af */ { false, 0x85af, 0x85af }, +/* 0x85b0 */ { false, 0x85b0, 0x85b0 }, +/* 0x85b1 */ { false, 0x85b1, 0x85b1 }, +/* 0x85b2 */ { false, 0x85b2, 0x85b2 }, +/* 0x85b3 */ { false, 0x85b3, 0x85b3 }, +/* 0x85b4 */ { false, 0x85b4, 0x85b4 }, +/* 0x85b5 */ { false, 0x85b5, 0x85b5 }, +/* 0x85b6 */ { false, 0x85b6, 0x85b6 }, +/* 0x85b7 */ { false, 0x85b7, 0x85b7 }, +/* 0x85b8 */ { false, 0x85b8, 0x85b8 }, +/* 0x85b9 */ { false, 0x85b9, 0x85b9 }, +/* 0x85ba */ { false, 0x85ba, 0x85ba }, +/* 0x85bb */ { false, 0x85bb, 0x85bb }, +/* 0x85bc */ { false, 0x85bc, 0x85bc }, +/* 0x85bd */ { false, 0x85bd, 0x85bd }, +/* 0x85be */ { false, 0x85be, 0x85be }, +/* 0x85bf */ { false, 0x85bf, 0x85bf }, +/* 0x85c0 */ { false, 0x85c0, 0x85c0 }, +/* 0x85c1 */ { false, 0x85c1, 0x85c1 }, +/* 0x85c2 */ { false, 0x85c2, 0x85c2 }, +/* 0x85c3 */ { false, 0x85c3, 0x85c3 }, +/* 0x85c4 */ { false, 0x85c4, 0x85c4 }, +/* 0x85c5 */ { false, 0x85c5, 0x85c5 }, +/* 0x85c6 */ { false, 0x85c6, 0x85c6 }, +/* 0x85c7 */ { false, 0x85c7, 0x85c7 }, +/* 0x85c8 */ { false, 0x85c8, 0x85c8 }, +/* 0x85c9 */ { false, 0x85c9, 0x85c9 }, +/* 0x85ca */ { false, 0x85ca, 0x85ca }, +/* 0x85cb */ { false, 0x85cb, 0x85cb }, +/* 0x85cc */ { false, 0x85cc, 0x85cc }, +/* 0x85cd */ { false, 0x85cd, 0x85cd }, +/* 0x85ce */ { false, 0x85ce, 0x85ce }, +/* 0x85cf */ { false, 0x85cf, 0x85cf }, +/* 0x85d0 */ { false, 0x85d0, 0x85d0 }, +/* 0x85d1 */ { false, 0x85d1, 0x85d1 }, +/* 0x85d2 */ { false, 0x85d2, 0x85d2 }, +/* 0x85d3 */ { false, 0x85d3, 0x85d3 }, +/* 0x85d4 */ { false, 0x85d4, 0x85d4 }, +/* 0x85d5 */ { false, 0x85d5, 0x85d5 }, +/* 0x85d6 */ { false, 0x85d6, 0x85d6 }, +/* 0x85d7 */ { false, 0x85d7, 0x85d7 }, +/* 0x85d8 */ { false, 0x85d8, 0x85d8 }, +/* 0x85d9 */ { false, 0x85d9, 0x85d9 }, +/* 0x85da */ { false, 0x85da, 0x85da }, +/* 0x85db */ { false, 0x85db, 0x85db }, +/* 0x85dc */ { false, 0x85dc, 0x85dc }, +/* 0x85dd */ { false, 0x85dd, 0x85dd }, +/* 0x85de */ { false, 0x85de, 0x85de }, +/* 0x85df */ { false, 0x85df, 0x85df }, +/* 0x85e0 */ { false, 0x85e0, 0x85e0 }, +/* 0x85e1 */ { false, 0x85e1, 0x85e1 }, +/* 0x85e2 */ { false, 0x85e2, 0x85e2 }, +/* 0x85e3 */ { false, 0x85e3, 0x85e3 }, +/* 0x85e4 */ { false, 0x85e4, 0x85e4 }, +/* 0x85e5 */ { false, 0x85e5, 0x85e5 }, +/* 0x85e6 */ { false, 0x85e6, 0x85e6 }, +/* 0x85e7 */ { false, 0x85e7, 0x85e7 }, +/* 0x85e8 */ { false, 0x85e8, 0x85e8 }, +/* 0x85e9 */ { false, 0x85e9, 0x85e9 }, +/* 0x85ea */ { false, 0x85ea, 0x85ea }, +/* 0x85eb */ { false, 0x85eb, 0x85eb }, +/* 0x85ec */ { false, 0x85ec, 0x85ec }, +/* 0x85ed */ { false, 0x85ed, 0x85ed }, +/* 0x85ee */ { false, 0x85ee, 0x85ee }, +/* 0x85ef */ { false, 0x85ef, 0x85ef }, +/* 0x85f0 */ { false, 0x85f0, 0x85f0 }, +/* 0x85f1 */ { false, 0x85f1, 0x85f1 }, +/* 0x85f2 */ { false, 0x85f2, 0x85f2 }, +/* 0x85f3 */ { false, 0x85f3, 0x85f3 }, +/* 0x85f4 */ { false, 0x85f4, 0x85f4 }, +/* 0x85f5 */ { false, 0x85f5, 0x85f5 }, +/* 0x85f6 */ { false, 0x85f6, 0x85f6 }, +/* 0x85f7 */ { false, 0x85f7, 0x85f7 }, +/* 0x85f8 */ { false, 0x85f8, 0x85f8 }, +/* 0x85f9 */ { false, 0x85f9, 0x85f9 }, +/* 0x85fa */ { false, 0x85fa, 0x85fa }, +/* 0x85fb */ { false, 0x85fb, 0x85fb }, +/* 0x85fc */ { false, 0x85fc, 0x85fc }, +/* 0x85fd */ { false, 0x85fd, 0x85fd }, +/* 0x85fe */ { false, 0x85fe, 0x85fe }, +/* 0x85ff */ { false, 0x85ff, 0x85ff }, +/* 0x8600 */ { false, 0x8600, 0x8600 }, +/* 0x8601 */ { false, 0x8601, 0x8601 }, +/* 0x8602 */ { false, 0x8602, 0x8602 }, +/* 0x8603 */ { false, 0x8603, 0x8603 }, +/* 0x8604 */ { false, 0x8604, 0x8604 }, +/* 0x8605 */ { false, 0x8605, 0x8605 }, +/* 0x8606 */ { false, 0x8606, 0x8606 }, +/* 0x8607 */ { false, 0x8607, 0x8607 }, +/* 0x8608 */ { false, 0x8608, 0x8608 }, +/* 0x8609 */ { false, 0x8609, 0x8609 }, +/* 0x860a */ { false, 0x860a, 0x860a }, +/* 0x860b */ { false, 0x860b, 0x860b }, +/* 0x860c */ { false, 0x860c, 0x860c }, +/* 0x860d */ { false, 0x860d, 0x860d }, +/* 0x860e */ { false, 0x860e, 0x860e }, +/* 0x860f */ { false, 0x860f, 0x860f }, +/* 0x8610 */ { false, 0x8610, 0x8610 }, +/* 0x8611 */ { false, 0x8611, 0x8611 }, +/* 0x8612 */ { false, 0x8612, 0x8612 }, +/* 0x8613 */ { false, 0x8613, 0x8613 }, +/* 0x8614 */ { false, 0x8614, 0x8614 }, +/* 0x8615 */ { false, 0x8615, 0x8615 }, +/* 0x8616 */ { false, 0x8616, 0x8616 }, +/* 0x8617 */ { false, 0x8617, 0x8617 }, +/* 0x8618 */ { false, 0x8618, 0x8618 }, +/* 0x8619 */ { false, 0x8619, 0x8619 }, +/* 0x861a */ { false, 0x861a, 0x861a }, +/* 0x861b */ { false, 0x861b, 0x861b }, +/* 0x861c */ { false, 0x861c, 0x861c }, +/* 0x861d */ { false, 0x861d, 0x861d }, +/* 0x861e */ { false, 0x861e, 0x861e }, +/* 0x861f */ { false, 0x861f, 0x861f }, +/* 0x8620 */ { false, 0x8620, 0x8620 }, +/* 0x8621 */ { false, 0x8621, 0x8621 }, +/* 0x8622 */ { false, 0x8622, 0x8622 }, +/* 0x8623 */ { false, 0x8623, 0x8623 }, +/* 0x8624 */ { false, 0x8624, 0x8624 }, +/* 0x8625 */ { false, 0x8625, 0x8625 }, +/* 0x8626 */ { false, 0x8626, 0x8626 }, +/* 0x8627 */ { false, 0x8627, 0x8627 }, +/* 0x8628 */ { false, 0x8628, 0x8628 }, +/* 0x8629 */ { false, 0x8629, 0x8629 }, +/* 0x862a */ { false, 0x862a, 0x862a }, +/* 0x862b */ { false, 0x862b, 0x862b }, +/* 0x862c */ { false, 0x862c, 0x862c }, +/* 0x862d */ { false, 0x862d, 0x862d }, +/* 0x862e */ { false, 0x862e, 0x862e }, +/* 0x862f */ { false, 0x862f, 0x862f }, +/* 0x8630 */ { false, 0x8630, 0x8630 }, +/* 0x8631 */ { false, 0x8631, 0x8631 }, +/* 0x8632 */ { false, 0x8632, 0x8632 }, +/* 0x8633 */ { false, 0x8633, 0x8633 }, +/* 0x8634 */ { false, 0x8634, 0x8634 }, +/* 0x8635 */ { false, 0x8635, 0x8635 }, +/* 0x8636 */ { false, 0x8636, 0x8636 }, +/* 0x8637 */ { false, 0x8637, 0x8637 }, +/* 0x8638 */ { false, 0x8638, 0x8638 }, +/* 0x8639 */ { false, 0x8639, 0x8639 }, +/* 0x863a */ { false, 0x863a, 0x863a }, +/* 0x863b */ { false, 0x863b, 0x863b }, +/* 0x863c */ { false, 0x863c, 0x863c }, +/* 0x863d */ { false, 0x863d, 0x863d }, +/* 0x863e */ { false, 0x863e, 0x863e }, +/* 0x863f */ { false, 0x863f, 0x863f }, +/* 0x8640 */ { false, 0x8640, 0x8640 }, +/* 0x8641 */ { false, 0x8641, 0x8641 }, +/* 0x8642 */ { false, 0x8642, 0x8642 }, +/* 0x8643 */ { false, 0x8643, 0x8643 }, +/* 0x8644 */ { false, 0x8644, 0x8644 }, +/* 0x8645 */ { false, 0x8645, 0x8645 }, +/* 0x8646 */ { false, 0x8646, 0x8646 }, +/* 0x8647 */ { false, 0x8647, 0x8647 }, +/* 0x8648 */ { false, 0x8648, 0x8648 }, +/* 0x8649 */ { false, 0x8649, 0x8649 }, +/* 0x864a */ { false, 0x864a, 0x864a }, +/* 0x864b */ { false, 0x864b, 0x864b }, +/* 0x864c */ { false, 0x864c, 0x864c }, +/* 0x864d */ { false, 0x864d, 0x864d }, +/* 0x864e */ { false, 0x864e, 0x864e }, +/* 0x864f */ { false, 0x864f, 0x864f }, +/* 0x8650 */ { false, 0x8650, 0x8650 }, +/* 0x8651 */ { false, 0x8651, 0x8651 }, +/* 0x8652 */ { false, 0x8652, 0x8652 }, +/* 0x8653 */ { false, 0x8653, 0x8653 }, +/* 0x8654 */ { false, 0x8654, 0x8654 }, +/* 0x8655 */ { false, 0x8655, 0x8655 }, +/* 0x8656 */ { false, 0x8656, 0x8656 }, +/* 0x8657 */ { false, 0x8657, 0x8657 }, +/* 0x8658 */ { false, 0x8658, 0x8658 }, +/* 0x8659 */ { false, 0x8659, 0x8659 }, +/* 0x865a */ { false, 0x865a, 0x865a }, +/* 0x865b */ { false, 0x865b, 0x865b }, +/* 0x865c */ { false, 0x865c, 0x865c }, +/* 0x865d */ { false, 0x865d, 0x865d }, +/* 0x865e */ { false, 0x865e, 0x865e }, +/* 0x865f */ { false, 0x865f, 0x865f }, +/* 0x8660 */ { false, 0x8660, 0x8660 }, +/* 0x8661 */ { false, 0x8661, 0x8661 }, +/* 0x8662 */ { false, 0x8662, 0x8662 }, +/* 0x8663 */ { false, 0x8663, 0x8663 }, +/* 0x8664 */ { false, 0x8664, 0x8664 }, +/* 0x8665 */ { false, 0x8665, 0x8665 }, +/* 0x8666 */ { false, 0x8666, 0x8666 }, +/* 0x8667 */ { false, 0x8667, 0x8667 }, +/* 0x8668 */ { false, 0x8668, 0x8668 }, +/* 0x8669 */ { false, 0x8669, 0x8669 }, +/* 0x866a */ { false, 0x866a, 0x866a }, +/* 0x866b */ { false, 0x866b, 0x866b }, +/* 0x866c */ { false, 0x866c, 0x866c }, +/* 0x866d */ { false, 0x866d, 0x866d }, +/* 0x866e */ { false, 0x866e, 0x866e }, +/* 0x866f */ { false, 0x866f, 0x866f }, +/* 0x8670 */ { false, 0x8670, 0x8670 }, +/* 0x8671 */ { false, 0x8671, 0x8671 }, +/* 0x8672 */ { false, 0x8672, 0x8672 }, +/* 0x8673 */ { false, 0x8673, 0x8673 }, +/* 0x8674 */ { false, 0x8674, 0x8674 }, +/* 0x8675 */ { false, 0x8675, 0x8675 }, +/* 0x8676 */ { false, 0x8676, 0x8676 }, +/* 0x8677 */ { false, 0x8677, 0x8677 }, +/* 0x8678 */ { false, 0x8678, 0x8678 }, +/* 0x8679 */ { false, 0x8679, 0x8679 }, +/* 0x867a */ { false, 0x867a, 0x867a }, +/* 0x867b */ { false, 0x867b, 0x867b }, +/* 0x867c */ { false, 0x867c, 0x867c }, +/* 0x867d */ { false, 0x867d, 0x867d }, +/* 0x867e */ { false, 0x867e, 0x867e }, +/* 0x867f */ { false, 0x867f, 0x867f }, +/* 0x8680 */ { false, 0x8680, 0x8680 }, +/* 0x8681 */ { false, 0x8681, 0x8681 }, +/* 0x8682 */ { false, 0x8682, 0x8682 }, +/* 0x8683 */ { false, 0x8683, 0x8683 }, +/* 0x8684 */ { false, 0x8684, 0x8684 }, +/* 0x8685 */ { false, 0x8685, 0x8685 }, +/* 0x8686 */ { false, 0x8686, 0x8686 }, +/* 0x8687 */ { false, 0x8687, 0x8687 }, +/* 0x8688 */ { false, 0x8688, 0x8688 }, +/* 0x8689 */ { false, 0x8689, 0x8689 }, +/* 0x868a */ { false, 0x868a, 0x868a }, +/* 0x868b */ { false, 0x868b, 0x868b }, +/* 0x868c */ { false, 0x868c, 0x868c }, +/* 0x868d */ { false, 0x868d, 0x868d }, +/* 0x868e */ { false, 0x868e, 0x868e }, +/* 0x868f */ { false, 0x868f, 0x868f }, +/* 0x8690 */ { false, 0x8690, 0x8690 }, +/* 0x8691 */ { false, 0x8691, 0x8691 }, +/* 0x8692 */ { false, 0x8692, 0x8692 }, +/* 0x8693 */ { false, 0x8693, 0x8693 }, +/* 0x8694 */ { false, 0x8694, 0x8694 }, +/* 0x8695 */ { false, 0x8695, 0x8695 }, +/* 0x8696 */ { false, 0x8696, 0x8696 }, +/* 0x8697 */ { false, 0x8697, 0x8697 }, +/* 0x8698 */ { false, 0x8698, 0x8698 }, +/* 0x8699 */ { false, 0x8699, 0x8699 }, +/* 0x869a */ { false, 0x869a, 0x869a }, +/* 0x869b */ { false, 0x869b, 0x869b }, +/* 0x869c */ { false, 0x869c, 0x869c }, +/* 0x869d */ { false, 0x869d, 0x869d }, +/* 0x869e */ { false, 0x869e, 0x869e }, +/* 0x869f */ { false, 0x869f, 0x869f }, +/* 0x86a0 */ { false, 0x86a0, 0x86a0 }, +/* 0x86a1 */ { false, 0x86a1, 0x86a1 }, +/* 0x86a2 */ { false, 0x86a2, 0x86a2 }, +/* 0x86a3 */ { false, 0x86a3, 0x86a3 }, +/* 0x86a4 */ { false, 0x86a4, 0x86a4 }, +/* 0x86a5 */ { false, 0x86a5, 0x86a5 }, +/* 0x86a6 */ { false, 0x86a6, 0x86a6 }, +/* 0x86a7 */ { false, 0x86a7, 0x86a7 }, +/* 0x86a8 */ { false, 0x86a8, 0x86a8 }, +/* 0x86a9 */ { false, 0x86a9, 0x86a9 }, +/* 0x86aa */ { false, 0x86aa, 0x86aa }, +/* 0x86ab */ { false, 0x86ab, 0x86ab }, +/* 0x86ac */ { false, 0x86ac, 0x86ac }, +/* 0x86ad */ { false, 0x86ad, 0x86ad }, +/* 0x86ae */ { false, 0x86ae, 0x86ae }, +/* 0x86af */ { false, 0x86af, 0x86af }, +/* 0x86b0 */ { false, 0x86b0, 0x86b0 }, +/* 0x86b1 */ { false, 0x86b1, 0x86b1 }, +/* 0x86b2 */ { false, 0x86b2, 0x86b2 }, +/* 0x86b3 */ { false, 0x86b3, 0x86b3 }, +/* 0x86b4 */ { false, 0x86b4, 0x86b4 }, +/* 0x86b5 */ { false, 0x86b5, 0x86b5 }, +/* 0x86b6 */ { false, 0x86b6, 0x86b6 }, +/* 0x86b7 */ { false, 0x86b7, 0x86b7 }, +/* 0x86b8 */ { false, 0x86b8, 0x86b8 }, +/* 0x86b9 */ { false, 0x86b9, 0x86b9 }, +/* 0x86ba */ { false, 0x86ba, 0x86ba }, +/* 0x86bb */ { false, 0x86bb, 0x86bb }, +/* 0x86bc */ { false, 0x86bc, 0x86bc }, +/* 0x86bd */ { false, 0x86bd, 0x86bd }, +/* 0x86be */ { false, 0x86be, 0x86be }, +/* 0x86bf */ { false, 0x86bf, 0x86bf }, +/* 0x86c0 */ { false, 0x86c0, 0x86c0 }, +/* 0x86c1 */ { false, 0x86c1, 0x86c1 }, +/* 0x86c2 */ { false, 0x86c2, 0x86c2 }, +/* 0x86c3 */ { false, 0x86c3, 0x86c3 }, +/* 0x86c4 */ { false, 0x86c4, 0x86c4 }, +/* 0x86c5 */ { false, 0x86c5, 0x86c5 }, +/* 0x86c6 */ { false, 0x86c6, 0x86c6 }, +/* 0x86c7 */ { false, 0x86c7, 0x86c7 }, +/* 0x86c8 */ { false, 0x86c8, 0x86c8 }, +/* 0x86c9 */ { false, 0x86c9, 0x86c9 }, +/* 0x86ca */ { false, 0x86ca, 0x86ca }, +/* 0x86cb */ { false, 0x86cb, 0x86cb }, +/* 0x86cc */ { false, 0x86cc, 0x86cc }, +/* 0x86cd */ { false, 0x86cd, 0x86cd }, +/* 0x86ce */ { false, 0x86ce, 0x86ce }, +/* 0x86cf */ { false, 0x86cf, 0x86cf }, +/* 0x86d0 */ { false, 0x86d0, 0x86d0 }, +/* 0x86d1 */ { false, 0x86d1, 0x86d1 }, +/* 0x86d2 */ { false, 0x86d2, 0x86d2 }, +/* 0x86d3 */ { false, 0x86d3, 0x86d3 }, +/* 0x86d4 */ { false, 0x86d4, 0x86d4 }, +/* 0x86d5 */ { false, 0x86d5, 0x86d5 }, +/* 0x86d6 */ { false, 0x86d6, 0x86d6 }, +/* 0x86d7 */ { false, 0x86d7, 0x86d7 }, +/* 0x86d8 */ { false, 0x86d8, 0x86d8 }, +/* 0x86d9 */ { false, 0x86d9, 0x86d9 }, +/* 0x86da */ { false, 0x86da, 0x86da }, +/* 0x86db */ { false, 0x86db, 0x86db }, +/* 0x86dc */ { false, 0x86dc, 0x86dc }, +/* 0x86dd */ { false, 0x86dd, 0x86dd }, +/* 0x86de */ { false, 0x86de, 0x86de }, +/* 0x86df */ { false, 0x86df, 0x86df }, +/* 0x86e0 */ { false, 0x86e0, 0x86e0 }, +/* 0x86e1 */ { false, 0x86e1, 0x86e1 }, +/* 0x86e2 */ { false, 0x86e2, 0x86e2 }, +/* 0x86e3 */ { false, 0x86e3, 0x86e3 }, +/* 0x86e4 */ { false, 0x86e4, 0x86e4 }, +/* 0x86e5 */ { false, 0x86e5, 0x86e5 }, +/* 0x86e6 */ { false, 0x86e6, 0x86e6 }, +/* 0x86e7 */ { false, 0x86e7, 0x86e7 }, +/* 0x86e8 */ { false, 0x86e8, 0x86e8 }, +/* 0x86e9 */ { false, 0x86e9, 0x86e9 }, +/* 0x86ea */ { false, 0x86ea, 0x86ea }, +/* 0x86eb */ { false, 0x86eb, 0x86eb }, +/* 0x86ec */ { false, 0x86ec, 0x86ec }, +/* 0x86ed */ { false, 0x86ed, 0x86ed }, +/* 0x86ee */ { false, 0x86ee, 0x86ee }, +/* 0x86ef */ { false, 0x86ef, 0x86ef }, +/* 0x86f0 */ { false, 0x86f0, 0x86f0 }, +/* 0x86f1 */ { false, 0x86f1, 0x86f1 }, +/* 0x86f2 */ { false, 0x86f2, 0x86f2 }, +/* 0x86f3 */ { false, 0x86f3, 0x86f3 }, +/* 0x86f4 */ { false, 0x86f4, 0x86f4 }, +/* 0x86f5 */ { false, 0x86f5, 0x86f5 }, +/* 0x86f6 */ { false, 0x86f6, 0x86f6 }, +/* 0x86f7 */ { false, 0x86f7, 0x86f7 }, +/* 0x86f8 */ { false, 0x86f8, 0x86f8 }, +/* 0x86f9 */ { false, 0x86f9, 0x86f9 }, +/* 0x86fa */ { false, 0x86fa, 0x86fa }, +/* 0x86fb */ { false, 0x86fb, 0x86fb }, +/* 0x86fc */ { false, 0x86fc, 0x86fc }, +/* 0x86fd */ { false, 0x86fd, 0x86fd }, +/* 0x86fe */ { false, 0x86fe, 0x86fe }, +/* 0x86ff */ { false, 0x86ff, 0x86ff }, +/* 0x8700 */ { false, 0x8700, 0x8700 }, +/* 0x8701 */ { false, 0x8701, 0x8701 }, +/* 0x8702 */ { false, 0x8702, 0x8702 }, +/* 0x8703 */ { false, 0x8703, 0x8703 }, +/* 0x8704 */ { false, 0x8704, 0x8704 }, +/* 0x8705 */ { false, 0x8705, 0x8705 }, +/* 0x8706 */ { false, 0x8706, 0x8706 }, +/* 0x8707 */ { false, 0x8707, 0x8707 }, +/* 0x8708 */ { false, 0x8708, 0x8708 }, +/* 0x8709 */ { false, 0x8709, 0x8709 }, +/* 0x870a */ { false, 0x870a, 0x870a }, +/* 0x870b */ { false, 0x870b, 0x870b }, +/* 0x870c */ { false, 0x870c, 0x870c }, +/* 0x870d */ { false, 0x870d, 0x870d }, +/* 0x870e */ { false, 0x870e, 0x870e }, +/* 0x870f */ { false, 0x870f, 0x870f }, +/* 0x8710 */ { false, 0x8710, 0x8710 }, +/* 0x8711 */ { false, 0x8711, 0x8711 }, +/* 0x8712 */ { false, 0x8712, 0x8712 }, +/* 0x8713 */ { false, 0x8713, 0x8713 }, +/* 0x8714 */ { false, 0x8714, 0x8714 }, +/* 0x8715 */ { false, 0x8715, 0x8715 }, +/* 0x8716 */ { false, 0x8716, 0x8716 }, +/* 0x8717 */ { false, 0x8717, 0x8717 }, +/* 0x8718 */ { false, 0x8718, 0x8718 }, +/* 0x8719 */ { false, 0x8719, 0x8719 }, +/* 0x871a */ { false, 0x871a, 0x871a }, +/* 0x871b */ { false, 0x871b, 0x871b }, +/* 0x871c */ { false, 0x871c, 0x871c }, +/* 0x871d */ { false, 0x871d, 0x871d }, +/* 0x871e */ { false, 0x871e, 0x871e }, +/* 0x871f */ { false, 0x871f, 0x871f }, +/* 0x8720 */ { false, 0x8720, 0x8720 }, +/* 0x8721 */ { false, 0x8721, 0x8721 }, +/* 0x8722 */ { false, 0x8722, 0x8722 }, +/* 0x8723 */ { false, 0x8723, 0x8723 }, +/* 0x8724 */ { false, 0x8724, 0x8724 }, +/* 0x8725 */ { false, 0x8725, 0x8725 }, +/* 0x8726 */ { false, 0x8726, 0x8726 }, +/* 0x8727 */ { false, 0x8727, 0x8727 }, +/* 0x8728 */ { false, 0x8728, 0x8728 }, +/* 0x8729 */ { false, 0x8729, 0x8729 }, +/* 0x872a */ { false, 0x872a, 0x872a }, +/* 0x872b */ { false, 0x872b, 0x872b }, +/* 0x872c */ { false, 0x872c, 0x872c }, +/* 0x872d */ { false, 0x872d, 0x872d }, +/* 0x872e */ { false, 0x872e, 0x872e }, +/* 0x872f */ { false, 0x872f, 0x872f }, +/* 0x8730 */ { false, 0x8730, 0x8730 }, +/* 0x8731 */ { false, 0x8731, 0x8731 }, +/* 0x8732 */ { false, 0x8732, 0x8732 }, +/* 0x8733 */ { false, 0x8733, 0x8733 }, +/* 0x8734 */ { false, 0x8734, 0x8734 }, +/* 0x8735 */ { false, 0x8735, 0x8735 }, +/* 0x8736 */ { false, 0x8736, 0x8736 }, +/* 0x8737 */ { false, 0x8737, 0x8737 }, +/* 0x8738 */ { false, 0x8738, 0x8738 }, +/* 0x8739 */ { false, 0x8739, 0x8739 }, +/* 0x873a */ { false, 0x873a, 0x873a }, +/* 0x873b */ { false, 0x873b, 0x873b }, +/* 0x873c */ { false, 0x873c, 0x873c }, +/* 0x873d */ { false, 0x873d, 0x873d }, +/* 0x873e */ { false, 0x873e, 0x873e }, +/* 0x873f */ { false, 0x873f, 0x873f }, +/* 0x8740 */ { false, 0x8740, 0x8740 }, +/* 0x8741 */ { false, 0x8741, 0x8741 }, +/* 0x8742 */ { false, 0x8742, 0x8742 }, +/* 0x8743 */ { false, 0x8743, 0x8743 }, +/* 0x8744 */ { false, 0x8744, 0x8744 }, +/* 0x8745 */ { false, 0x8745, 0x8745 }, +/* 0x8746 */ { false, 0x8746, 0x8746 }, +/* 0x8747 */ { false, 0x8747, 0x8747 }, +/* 0x8748 */ { false, 0x8748, 0x8748 }, +/* 0x8749 */ { false, 0x8749, 0x8749 }, +/* 0x874a */ { false, 0x874a, 0x874a }, +/* 0x874b */ { false, 0x874b, 0x874b }, +/* 0x874c */ { false, 0x874c, 0x874c }, +/* 0x874d */ { false, 0x874d, 0x874d }, +/* 0x874e */ { false, 0x874e, 0x874e }, +/* 0x874f */ { false, 0x874f, 0x874f }, +/* 0x8750 */ { false, 0x8750, 0x8750 }, +/* 0x8751 */ { false, 0x8751, 0x8751 }, +/* 0x8752 */ { false, 0x8752, 0x8752 }, +/* 0x8753 */ { false, 0x8753, 0x8753 }, +/* 0x8754 */ { false, 0x8754, 0x8754 }, +/* 0x8755 */ { false, 0x8755, 0x8755 }, +/* 0x8756 */ { false, 0x8756, 0x8756 }, +/* 0x8757 */ { false, 0x8757, 0x8757 }, +/* 0x8758 */ { false, 0x8758, 0x8758 }, +/* 0x8759 */ { false, 0x8759, 0x8759 }, +/* 0x875a */ { false, 0x875a, 0x875a }, +/* 0x875b */ { false, 0x875b, 0x875b }, +/* 0x875c */ { false, 0x875c, 0x875c }, +/* 0x875d */ { false, 0x875d, 0x875d }, +/* 0x875e */ { false, 0x875e, 0x875e }, +/* 0x875f */ { false, 0x875f, 0x875f }, +/* 0x8760 */ { false, 0x8760, 0x8760 }, +/* 0x8761 */ { false, 0x8761, 0x8761 }, +/* 0x8762 */ { false, 0x8762, 0x8762 }, +/* 0x8763 */ { false, 0x8763, 0x8763 }, +/* 0x8764 */ { false, 0x8764, 0x8764 }, +/* 0x8765 */ { false, 0x8765, 0x8765 }, +/* 0x8766 */ { false, 0x8766, 0x8766 }, +/* 0x8767 */ { false, 0x8767, 0x8767 }, +/* 0x8768 */ { false, 0x8768, 0x8768 }, +/* 0x8769 */ { false, 0x8769, 0x8769 }, +/* 0x876a */ { false, 0x876a, 0x876a }, +/* 0x876b */ { false, 0x876b, 0x876b }, +/* 0x876c */ { false, 0x876c, 0x876c }, +/* 0x876d */ { false, 0x876d, 0x876d }, +/* 0x876e */ { false, 0x876e, 0x876e }, +/* 0x876f */ { false, 0x876f, 0x876f }, +/* 0x8770 */ { false, 0x8770, 0x8770 }, +/* 0x8771 */ { false, 0x8771, 0x8771 }, +/* 0x8772 */ { false, 0x8772, 0x8772 }, +/* 0x8773 */ { false, 0x8773, 0x8773 }, +/* 0x8774 */ { false, 0x8774, 0x8774 }, +/* 0x8775 */ { false, 0x8775, 0x8775 }, +/* 0x8776 */ { false, 0x8776, 0x8776 }, +/* 0x8777 */ { false, 0x8777, 0x8777 }, +/* 0x8778 */ { false, 0x8778, 0x8778 }, +/* 0x8779 */ { false, 0x8779, 0x8779 }, +/* 0x877a */ { false, 0x877a, 0x877a }, +/* 0x877b */ { false, 0x877b, 0x877b }, +/* 0x877c */ { false, 0x877c, 0x877c }, +/* 0x877d */ { false, 0x877d, 0x877d }, +/* 0x877e */ { false, 0x877e, 0x877e }, +/* 0x877f */ { false, 0x877f, 0x877f }, +/* 0x8780 */ { false, 0x8780, 0x8780 }, +/* 0x8781 */ { false, 0x8781, 0x8781 }, +/* 0x8782 */ { false, 0x8782, 0x8782 }, +/* 0x8783 */ { false, 0x8783, 0x8783 }, +/* 0x8784 */ { false, 0x8784, 0x8784 }, +/* 0x8785 */ { false, 0x8785, 0x8785 }, +/* 0x8786 */ { false, 0x8786, 0x8786 }, +/* 0x8787 */ { false, 0x8787, 0x8787 }, +/* 0x8788 */ { false, 0x8788, 0x8788 }, +/* 0x8789 */ { false, 0x8789, 0x8789 }, +/* 0x878a */ { false, 0x878a, 0x878a }, +/* 0x878b */ { false, 0x878b, 0x878b }, +/* 0x878c */ { false, 0x878c, 0x878c }, +/* 0x878d */ { false, 0x878d, 0x878d }, +/* 0x878e */ { false, 0x878e, 0x878e }, +/* 0x878f */ { false, 0x878f, 0x878f }, +/* 0x8790 */ { false, 0x8790, 0x8790 }, +/* 0x8791 */ { false, 0x8791, 0x8791 }, +/* 0x8792 */ { false, 0x8792, 0x8792 }, +/* 0x8793 */ { false, 0x8793, 0x8793 }, +/* 0x8794 */ { false, 0x8794, 0x8794 }, +/* 0x8795 */ { false, 0x8795, 0x8795 }, +/* 0x8796 */ { false, 0x8796, 0x8796 }, +/* 0x8797 */ { false, 0x8797, 0x8797 }, +/* 0x8798 */ { false, 0x8798, 0x8798 }, +/* 0x8799 */ { false, 0x8799, 0x8799 }, +/* 0x879a */ { false, 0x879a, 0x879a }, +/* 0x879b */ { false, 0x879b, 0x879b }, +/* 0x879c */ { false, 0x879c, 0x879c }, +/* 0x879d */ { false, 0x879d, 0x879d }, +/* 0x879e */ { false, 0x879e, 0x879e }, +/* 0x879f */ { false, 0x879f, 0x879f }, +/* 0x87a0 */ { false, 0x87a0, 0x87a0 }, +/* 0x87a1 */ { false, 0x87a1, 0x87a1 }, +/* 0x87a2 */ { false, 0x87a2, 0x87a2 }, +/* 0x87a3 */ { false, 0x87a3, 0x87a3 }, +/* 0x87a4 */ { false, 0x87a4, 0x87a4 }, +/* 0x87a5 */ { false, 0x87a5, 0x87a5 }, +/* 0x87a6 */ { false, 0x87a6, 0x87a6 }, +/* 0x87a7 */ { false, 0x87a7, 0x87a7 }, +/* 0x87a8 */ { false, 0x87a8, 0x87a8 }, +/* 0x87a9 */ { false, 0x87a9, 0x87a9 }, +/* 0x87aa */ { false, 0x87aa, 0x87aa }, +/* 0x87ab */ { false, 0x87ab, 0x87ab }, +/* 0x87ac */ { false, 0x87ac, 0x87ac }, +/* 0x87ad */ { false, 0x87ad, 0x87ad }, +/* 0x87ae */ { false, 0x87ae, 0x87ae }, +/* 0x87af */ { false, 0x87af, 0x87af }, +/* 0x87b0 */ { false, 0x87b0, 0x87b0 }, +/* 0x87b1 */ { false, 0x87b1, 0x87b1 }, +/* 0x87b2 */ { false, 0x87b2, 0x87b2 }, +/* 0x87b3 */ { false, 0x87b3, 0x87b3 }, +/* 0x87b4 */ { false, 0x87b4, 0x87b4 }, +/* 0x87b5 */ { false, 0x87b5, 0x87b5 }, +/* 0x87b6 */ { false, 0x87b6, 0x87b6 }, +/* 0x87b7 */ { false, 0x87b7, 0x87b7 }, +/* 0x87b8 */ { false, 0x87b8, 0x87b8 }, +/* 0x87b9 */ { false, 0x87b9, 0x87b9 }, +/* 0x87ba */ { false, 0x87ba, 0x87ba }, +/* 0x87bb */ { false, 0x87bb, 0x87bb }, +/* 0x87bc */ { false, 0x87bc, 0x87bc }, +/* 0x87bd */ { false, 0x87bd, 0x87bd }, +/* 0x87be */ { false, 0x87be, 0x87be }, +/* 0x87bf */ { false, 0x87bf, 0x87bf }, +/* 0x87c0 */ { false, 0x87c0, 0x87c0 }, +/* 0x87c1 */ { false, 0x87c1, 0x87c1 }, +/* 0x87c2 */ { false, 0x87c2, 0x87c2 }, +/* 0x87c3 */ { false, 0x87c3, 0x87c3 }, +/* 0x87c4 */ { false, 0x87c4, 0x87c4 }, +/* 0x87c5 */ { false, 0x87c5, 0x87c5 }, +/* 0x87c6 */ { false, 0x87c6, 0x87c6 }, +/* 0x87c7 */ { false, 0x87c7, 0x87c7 }, +/* 0x87c8 */ { false, 0x87c8, 0x87c8 }, +/* 0x87c9 */ { false, 0x87c9, 0x87c9 }, +/* 0x87ca */ { false, 0x87ca, 0x87ca }, +/* 0x87cb */ { false, 0x87cb, 0x87cb }, +/* 0x87cc */ { false, 0x87cc, 0x87cc }, +/* 0x87cd */ { false, 0x87cd, 0x87cd }, +/* 0x87ce */ { false, 0x87ce, 0x87ce }, +/* 0x87cf */ { false, 0x87cf, 0x87cf }, +/* 0x87d0 */ { false, 0x87d0, 0x87d0 }, +/* 0x87d1 */ { false, 0x87d1, 0x87d1 }, +/* 0x87d2 */ { false, 0x87d2, 0x87d2 }, +/* 0x87d3 */ { false, 0x87d3, 0x87d3 }, +/* 0x87d4 */ { false, 0x87d4, 0x87d4 }, +/* 0x87d5 */ { false, 0x87d5, 0x87d5 }, +/* 0x87d6 */ { false, 0x87d6, 0x87d6 }, +/* 0x87d7 */ { false, 0x87d7, 0x87d7 }, +/* 0x87d8 */ { false, 0x87d8, 0x87d8 }, +/* 0x87d9 */ { false, 0x87d9, 0x87d9 }, +/* 0x87da */ { false, 0x87da, 0x87da }, +/* 0x87db */ { false, 0x87db, 0x87db }, +/* 0x87dc */ { false, 0x87dc, 0x87dc }, +/* 0x87dd */ { false, 0x87dd, 0x87dd }, +/* 0x87de */ { false, 0x87de, 0x87de }, +/* 0x87df */ { false, 0x87df, 0x87df }, +/* 0x87e0 */ { false, 0x87e0, 0x87e0 }, +/* 0x87e1 */ { false, 0x87e1, 0x87e1 }, +/* 0x87e2 */ { false, 0x87e2, 0x87e2 }, +/* 0x87e3 */ { false, 0x87e3, 0x87e3 }, +/* 0x87e4 */ { false, 0x87e4, 0x87e4 }, +/* 0x87e5 */ { false, 0x87e5, 0x87e5 }, +/* 0x87e6 */ { false, 0x87e6, 0x87e6 }, +/* 0x87e7 */ { false, 0x87e7, 0x87e7 }, +/* 0x87e8 */ { false, 0x87e8, 0x87e8 }, +/* 0x87e9 */ { false, 0x87e9, 0x87e9 }, +/* 0x87ea */ { false, 0x87ea, 0x87ea }, +/* 0x87eb */ { false, 0x87eb, 0x87eb }, +/* 0x87ec */ { false, 0x87ec, 0x87ec }, +/* 0x87ed */ { false, 0x87ed, 0x87ed }, +/* 0x87ee */ { false, 0x87ee, 0x87ee }, +/* 0x87ef */ { false, 0x87ef, 0x87ef }, +/* 0x87f0 */ { false, 0x87f0, 0x87f0 }, +/* 0x87f1 */ { false, 0x87f1, 0x87f1 }, +/* 0x87f2 */ { false, 0x87f2, 0x87f2 }, +/* 0x87f3 */ { false, 0x87f3, 0x87f3 }, +/* 0x87f4 */ { false, 0x87f4, 0x87f4 }, +/* 0x87f5 */ { false, 0x87f5, 0x87f5 }, +/* 0x87f6 */ { false, 0x87f6, 0x87f6 }, +/* 0x87f7 */ { false, 0x87f7, 0x87f7 }, +/* 0x87f8 */ { false, 0x87f8, 0x87f8 }, +/* 0x87f9 */ { false, 0x87f9, 0x87f9 }, +/* 0x87fa */ { false, 0x87fa, 0x87fa }, +/* 0x87fb */ { false, 0x87fb, 0x87fb }, +/* 0x87fc */ { false, 0x87fc, 0x87fc }, +/* 0x87fd */ { false, 0x87fd, 0x87fd }, +/* 0x87fe */ { false, 0x87fe, 0x87fe }, +/* 0x87ff */ { false, 0x87ff, 0x87ff }, +/* 0x8800 */ { false, 0x8800, 0x8800 }, +/* 0x8801 */ { false, 0x8801, 0x8801 }, +/* 0x8802 */ { false, 0x8802, 0x8802 }, +/* 0x8803 */ { false, 0x8803, 0x8803 }, +/* 0x8804 */ { false, 0x8804, 0x8804 }, +/* 0x8805 */ { false, 0x8805, 0x8805 }, +/* 0x8806 */ { false, 0x8806, 0x8806 }, +/* 0x8807 */ { false, 0x8807, 0x8807 }, +/* 0x8808 */ { false, 0x8808, 0x8808 }, +/* 0x8809 */ { false, 0x8809, 0x8809 }, +/* 0x880a */ { false, 0x880a, 0x880a }, +/* 0x880b */ { false, 0x880b, 0x880b }, +/* 0x880c */ { false, 0x880c, 0x880c }, +/* 0x880d */ { false, 0x880d, 0x880d }, +/* 0x880e */ { false, 0x880e, 0x880e }, +/* 0x880f */ { false, 0x880f, 0x880f }, +/* 0x8810 */ { false, 0x8810, 0x8810 }, +/* 0x8811 */ { false, 0x8811, 0x8811 }, +/* 0x8812 */ { false, 0x8812, 0x8812 }, +/* 0x8813 */ { false, 0x8813, 0x8813 }, +/* 0x8814 */ { false, 0x8814, 0x8814 }, +/* 0x8815 */ { false, 0x8815, 0x8815 }, +/* 0x8816 */ { false, 0x8816, 0x8816 }, +/* 0x8817 */ { false, 0x8817, 0x8817 }, +/* 0x8818 */ { false, 0x8818, 0x8818 }, +/* 0x8819 */ { false, 0x8819, 0x8819 }, +/* 0x881a */ { false, 0x881a, 0x881a }, +/* 0x881b */ { false, 0x881b, 0x881b }, +/* 0x881c */ { false, 0x881c, 0x881c }, +/* 0x881d */ { false, 0x881d, 0x881d }, +/* 0x881e */ { false, 0x881e, 0x881e }, +/* 0x881f */ { false, 0x881f, 0x881f }, +/* 0x8820 */ { false, 0x8820, 0x8820 }, +/* 0x8821 */ { false, 0x8821, 0x8821 }, +/* 0x8822 */ { false, 0x8822, 0x8822 }, +/* 0x8823 */ { false, 0x8823, 0x8823 }, +/* 0x8824 */ { false, 0x8824, 0x8824 }, +/* 0x8825 */ { false, 0x8825, 0x8825 }, +/* 0x8826 */ { false, 0x8826, 0x8826 }, +/* 0x8827 */ { false, 0x8827, 0x8827 }, +/* 0x8828 */ { false, 0x8828, 0x8828 }, +/* 0x8829 */ { false, 0x8829, 0x8829 }, +/* 0x882a */ { false, 0x882a, 0x882a }, +/* 0x882b */ { false, 0x882b, 0x882b }, +/* 0x882c */ { false, 0x882c, 0x882c }, +/* 0x882d */ { false, 0x882d, 0x882d }, +/* 0x882e */ { false, 0x882e, 0x882e }, +/* 0x882f */ { false, 0x882f, 0x882f }, +/* 0x8830 */ { false, 0x8830, 0x8830 }, +/* 0x8831 */ { false, 0x8831, 0x8831 }, +/* 0x8832 */ { false, 0x8832, 0x8832 }, +/* 0x8833 */ { false, 0x8833, 0x8833 }, +/* 0x8834 */ { false, 0x8834, 0x8834 }, +/* 0x8835 */ { false, 0x8835, 0x8835 }, +/* 0x8836 */ { false, 0x8836, 0x8836 }, +/* 0x8837 */ { false, 0x8837, 0x8837 }, +/* 0x8838 */ { false, 0x8838, 0x8838 }, +/* 0x8839 */ { false, 0x8839, 0x8839 }, +/* 0x883a */ { false, 0x883a, 0x883a }, +/* 0x883b */ { false, 0x883b, 0x883b }, +/* 0x883c */ { false, 0x883c, 0x883c }, +/* 0x883d */ { false, 0x883d, 0x883d }, +/* 0x883e */ { false, 0x883e, 0x883e }, +/* 0x883f */ { false, 0x883f, 0x883f }, +/* 0x8840 */ { false, 0x8840, 0x8840 }, +/* 0x8841 */ { false, 0x8841, 0x8841 }, +/* 0x8842 */ { false, 0x8842, 0x8842 }, +/* 0x8843 */ { false, 0x8843, 0x8843 }, +/* 0x8844 */ { false, 0x8844, 0x8844 }, +/* 0x8845 */ { false, 0x8845, 0x8845 }, +/* 0x8846 */ { false, 0x8846, 0x8846 }, +/* 0x8847 */ { false, 0x8847, 0x8847 }, +/* 0x8848 */ { false, 0x8848, 0x8848 }, +/* 0x8849 */ { false, 0x8849, 0x8849 }, +/* 0x884a */ { false, 0x884a, 0x884a }, +/* 0x884b */ { false, 0x884b, 0x884b }, +/* 0x884c */ { false, 0x884c, 0x884c }, +/* 0x884d */ { false, 0x884d, 0x884d }, +/* 0x884e */ { false, 0x884e, 0x884e }, +/* 0x884f */ { false, 0x884f, 0x884f }, +/* 0x8850 */ { false, 0x8850, 0x8850 }, +/* 0x8851 */ { false, 0x8851, 0x8851 }, +/* 0x8852 */ { false, 0x8852, 0x8852 }, +/* 0x8853 */ { false, 0x8853, 0x8853 }, +/* 0x8854 */ { false, 0x8854, 0x8854 }, +/* 0x8855 */ { false, 0x8855, 0x8855 }, +/* 0x8856 */ { false, 0x8856, 0x8856 }, +/* 0x8857 */ { false, 0x8857, 0x8857 }, +/* 0x8858 */ { false, 0x8858, 0x8858 }, +/* 0x8859 */ { false, 0x8859, 0x8859 }, +/* 0x885a */ { false, 0x885a, 0x885a }, +/* 0x885b */ { false, 0x885b, 0x885b }, +/* 0x885c */ { false, 0x885c, 0x885c }, +/* 0x885d */ { false, 0x885d, 0x885d }, +/* 0x885e */ { false, 0x885e, 0x885e }, +/* 0x885f */ { false, 0x885f, 0x885f }, +/* 0x8860 */ { false, 0x8860, 0x8860 }, +/* 0x8861 */ { false, 0x8861, 0x8861 }, +/* 0x8862 */ { false, 0x8862, 0x8862 }, +/* 0x8863 */ { false, 0x8863, 0x8863 }, +/* 0x8864 */ { false, 0x8864, 0x8864 }, +/* 0x8865 */ { false, 0x8865, 0x8865 }, +/* 0x8866 */ { false, 0x8866, 0x8866 }, +/* 0x8867 */ { false, 0x8867, 0x8867 }, +/* 0x8868 */ { false, 0x8868, 0x8868 }, +/* 0x8869 */ { false, 0x8869, 0x8869 }, +/* 0x886a */ { false, 0x886a, 0x886a }, +/* 0x886b */ { false, 0x886b, 0x886b }, +/* 0x886c */ { false, 0x886c, 0x886c }, +/* 0x886d */ { false, 0x886d, 0x886d }, +/* 0x886e */ { false, 0x886e, 0x886e }, +/* 0x886f */ { false, 0x886f, 0x886f }, +/* 0x8870 */ { false, 0x8870, 0x8870 }, +/* 0x8871 */ { false, 0x8871, 0x8871 }, +/* 0x8872 */ { false, 0x8872, 0x8872 }, +/* 0x8873 */ { false, 0x8873, 0x8873 }, +/* 0x8874 */ { false, 0x8874, 0x8874 }, +/* 0x8875 */ { false, 0x8875, 0x8875 }, +/* 0x8876 */ { false, 0x8876, 0x8876 }, +/* 0x8877 */ { false, 0x8877, 0x8877 }, +/* 0x8878 */ { false, 0x8878, 0x8878 }, +/* 0x8879 */ { false, 0x8879, 0x8879 }, +/* 0x887a */ { false, 0x887a, 0x887a }, +/* 0x887b */ { false, 0x887b, 0x887b }, +/* 0x887c */ { false, 0x887c, 0x887c }, +/* 0x887d */ { false, 0x887d, 0x887d }, +/* 0x887e */ { false, 0x887e, 0x887e }, +/* 0x887f */ { false, 0x887f, 0x887f }, +/* 0x8880 */ { false, 0x8880, 0x8880 }, +/* 0x8881 */ { false, 0x8881, 0x8881 }, +/* 0x8882 */ { false, 0x8882, 0x8882 }, +/* 0x8883 */ { false, 0x8883, 0x8883 }, +/* 0x8884 */ { false, 0x8884, 0x8884 }, +/* 0x8885 */ { false, 0x8885, 0x8885 }, +/* 0x8886 */ { false, 0x8886, 0x8886 }, +/* 0x8887 */ { false, 0x8887, 0x8887 }, +/* 0x8888 */ { false, 0x8888, 0x8888 }, +/* 0x8889 */ { false, 0x8889, 0x8889 }, +/* 0x888a */ { false, 0x888a, 0x888a }, +/* 0x888b */ { false, 0x888b, 0x888b }, +/* 0x888c */ { false, 0x888c, 0x888c }, +/* 0x888d */ { false, 0x888d, 0x888d }, +/* 0x888e */ { false, 0x888e, 0x888e }, +/* 0x888f */ { false, 0x888f, 0x888f }, +/* 0x8890 */ { false, 0x8890, 0x8890 }, +/* 0x8891 */ { false, 0x8891, 0x8891 }, +/* 0x8892 */ { false, 0x8892, 0x8892 }, +/* 0x8893 */ { false, 0x8893, 0x8893 }, +/* 0x8894 */ { false, 0x8894, 0x8894 }, +/* 0x8895 */ { false, 0x8895, 0x8895 }, +/* 0x8896 */ { false, 0x8896, 0x8896 }, +/* 0x8897 */ { false, 0x8897, 0x8897 }, +/* 0x8898 */ { false, 0x8898, 0x8898 }, +/* 0x8899 */ { false, 0x8899, 0x8899 }, +/* 0x889a */ { false, 0x889a, 0x889a }, +/* 0x889b */ { false, 0x889b, 0x889b }, +/* 0x889c */ { false, 0x889c, 0x889c }, +/* 0x889d */ { false, 0x889d, 0x889d }, +/* 0x889e */ { false, 0x889e, 0x889e }, +/* 0x889f */ { false, 0x889f, 0x889f }, +/* 0x88a0 */ { false, 0x88a0, 0x88a0 }, +/* 0x88a1 */ { false, 0x88a1, 0x88a1 }, +/* 0x88a2 */ { false, 0x88a2, 0x88a2 }, +/* 0x88a3 */ { false, 0x88a3, 0x88a3 }, +/* 0x88a4 */ { false, 0x88a4, 0x88a4 }, +/* 0x88a5 */ { false, 0x88a5, 0x88a5 }, +/* 0x88a6 */ { false, 0x88a6, 0x88a6 }, +/* 0x88a7 */ { false, 0x88a7, 0x88a7 }, +/* 0x88a8 */ { false, 0x88a8, 0x88a8 }, +/* 0x88a9 */ { false, 0x88a9, 0x88a9 }, +/* 0x88aa */ { false, 0x88aa, 0x88aa }, +/* 0x88ab */ { false, 0x88ab, 0x88ab }, +/* 0x88ac */ { false, 0x88ac, 0x88ac }, +/* 0x88ad */ { false, 0x88ad, 0x88ad }, +/* 0x88ae */ { false, 0x88ae, 0x88ae }, +/* 0x88af */ { false, 0x88af, 0x88af }, +/* 0x88b0 */ { false, 0x88b0, 0x88b0 }, +/* 0x88b1 */ { false, 0x88b1, 0x88b1 }, +/* 0x88b2 */ { false, 0x88b2, 0x88b2 }, +/* 0x88b3 */ { false, 0x88b3, 0x88b3 }, +/* 0x88b4 */ { false, 0x88b4, 0x88b4 }, +/* 0x88b5 */ { false, 0x88b5, 0x88b5 }, +/* 0x88b6 */ { false, 0x88b6, 0x88b6 }, +/* 0x88b7 */ { false, 0x88b7, 0x88b7 }, +/* 0x88b8 */ { false, 0x88b8, 0x88b8 }, +/* 0x88b9 */ { false, 0x88b9, 0x88b9 }, +/* 0x88ba */ { false, 0x88ba, 0x88ba }, +/* 0x88bb */ { false, 0x88bb, 0x88bb }, +/* 0x88bc */ { false, 0x88bc, 0x88bc }, +/* 0x88bd */ { false, 0x88bd, 0x88bd }, +/* 0x88be */ { false, 0x88be, 0x88be }, +/* 0x88bf */ { false, 0x88bf, 0x88bf }, +/* 0x88c0 */ { false, 0x88c0, 0x88c0 }, +/* 0x88c1 */ { false, 0x88c1, 0x88c1 }, +/* 0x88c2 */ { false, 0x88c2, 0x88c2 }, +/* 0x88c3 */ { false, 0x88c3, 0x88c3 }, +/* 0x88c4 */ { false, 0x88c4, 0x88c4 }, +/* 0x88c5 */ { false, 0x88c5, 0x88c5 }, +/* 0x88c6 */ { false, 0x88c6, 0x88c6 }, +/* 0x88c7 */ { false, 0x88c7, 0x88c7 }, +/* 0x88c8 */ { false, 0x88c8, 0x88c8 }, +/* 0x88c9 */ { false, 0x88c9, 0x88c9 }, +/* 0x88ca */ { false, 0x88ca, 0x88ca }, +/* 0x88cb */ { false, 0x88cb, 0x88cb }, +/* 0x88cc */ { false, 0x88cc, 0x88cc }, +/* 0x88cd */ { false, 0x88cd, 0x88cd }, +/* 0x88ce */ { false, 0x88ce, 0x88ce }, +/* 0x88cf */ { false, 0x88cf, 0x88cf }, +/* 0x88d0 */ { false, 0x88d0, 0x88d0 }, +/* 0x88d1 */ { false, 0x88d1, 0x88d1 }, +/* 0x88d2 */ { false, 0x88d2, 0x88d2 }, +/* 0x88d3 */ { false, 0x88d3, 0x88d3 }, +/* 0x88d4 */ { false, 0x88d4, 0x88d4 }, +/* 0x88d5 */ { false, 0x88d5, 0x88d5 }, +/* 0x88d6 */ { false, 0x88d6, 0x88d6 }, +/* 0x88d7 */ { false, 0x88d7, 0x88d7 }, +/* 0x88d8 */ { false, 0x88d8, 0x88d8 }, +/* 0x88d9 */ { false, 0x88d9, 0x88d9 }, +/* 0x88da */ { false, 0x88da, 0x88da }, +/* 0x88db */ { false, 0x88db, 0x88db }, +/* 0x88dc */ { false, 0x88dc, 0x88dc }, +/* 0x88dd */ { false, 0x88dd, 0x88dd }, +/* 0x88de */ { false, 0x88de, 0x88de }, +/* 0x88df */ { false, 0x88df, 0x88df }, +/* 0x88e0 */ { false, 0x88e0, 0x88e0 }, +/* 0x88e1 */ { false, 0x88e1, 0x88e1 }, +/* 0x88e2 */ { false, 0x88e2, 0x88e2 }, +/* 0x88e3 */ { false, 0x88e3, 0x88e3 }, +/* 0x88e4 */ { false, 0x88e4, 0x88e4 }, +/* 0x88e5 */ { false, 0x88e5, 0x88e5 }, +/* 0x88e6 */ { false, 0x88e6, 0x88e6 }, +/* 0x88e7 */ { false, 0x88e7, 0x88e7 }, +/* 0x88e8 */ { false, 0x88e8, 0x88e8 }, +/* 0x88e9 */ { false, 0x88e9, 0x88e9 }, +/* 0x88ea */ { false, 0x88ea, 0x88ea }, +/* 0x88eb */ { false, 0x88eb, 0x88eb }, +/* 0x88ec */ { false, 0x88ec, 0x88ec }, +/* 0x88ed */ { false, 0x88ed, 0x88ed }, +/* 0x88ee */ { false, 0x88ee, 0x88ee }, +/* 0x88ef */ { false, 0x88ef, 0x88ef }, +/* 0x88f0 */ { false, 0x88f0, 0x88f0 }, +/* 0x88f1 */ { false, 0x88f1, 0x88f1 }, +/* 0x88f2 */ { false, 0x88f2, 0x88f2 }, +/* 0x88f3 */ { false, 0x88f3, 0x88f3 }, +/* 0x88f4 */ { false, 0x88f4, 0x88f4 }, +/* 0x88f5 */ { false, 0x88f5, 0x88f5 }, +/* 0x88f6 */ { false, 0x88f6, 0x88f6 }, +/* 0x88f7 */ { false, 0x88f7, 0x88f7 }, +/* 0x88f8 */ { false, 0x88f8, 0x88f8 }, +/* 0x88f9 */ { false, 0x88f9, 0x88f9 }, +/* 0x88fa */ { false, 0x88fa, 0x88fa }, +/* 0x88fb */ { false, 0x88fb, 0x88fb }, +/* 0x88fc */ { false, 0x88fc, 0x88fc }, +/* 0x88fd */ { false, 0x88fd, 0x88fd }, +/* 0x88fe */ { false, 0x88fe, 0x88fe }, +/* 0x88ff */ { false, 0x88ff, 0x88ff }, +/* 0x8900 */ { false, 0x8900, 0x8900 }, +/* 0x8901 */ { false, 0x8901, 0x8901 }, +/* 0x8902 */ { false, 0x8902, 0x8902 }, +/* 0x8903 */ { false, 0x8903, 0x8903 }, +/* 0x8904 */ { false, 0x8904, 0x8904 }, +/* 0x8905 */ { false, 0x8905, 0x8905 }, +/* 0x8906 */ { false, 0x8906, 0x8906 }, +/* 0x8907 */ { false, 0x8907, 0x8907 }, +/* 0x8908 */ { false, 0x8908, 0x8908 }, +/* 0x8909 */ { false, 0x8909, 0x8909 }, +/* 0x890a */ { false, 0x890a, 0x890a }, +/* 0x890b */ { false, 0x890b, 0x890b }, +/* 0x890c */ { false, 0x890c, 0x890c }, +/* 0x890d */ { false, 0x890d, 0x890d }, +/* 0x890e */ { false, 0x890e, 0x890e }, +/* 0x890f */ { false, 0x890f, 0x890f }, +/* 0x8910 */ { false, 0x8910, 0x8910 }, +/* 0x8911 */ { false, 0x8911, 0x8911 }, +/* 0x8912 */ { false, 0x8912, 0x8912 }, +/* 0x8913 */ { false, 0x8913, 0x8913 }, +/* 0x8914 */ { false, 0x8914, 0x8914 }, +/* 0x8915 */ { false, 0x8915, 0x8915 }, +/* 0x8916 */ { false, 0x8916, 0x8916 }, +/* 0x8917 */ { false, 0x8917, 0x8917 }, +/* 0x8918 */ { false, 0x8918, 0x8918 }, +/* 0x8919 */ { false, 0x8919, 0x8919 }, +/* 0x891a */ { false, 0x891a, 0x891a }, +/* 0x891b */ { false, 0x891b, 0x891b }, +/* 0x891c */ { false, 0x891c, 0x891c }, +/* 0x891d */ { false, 0x891d, 0x891d }, +/* 0x891e */ { false, 0x891e, 0x891e }, +/* 0x891f */ { false, 0x891f, 0x891f }, +/* 0x8920 */ { false, 0x8920, 0x8920 }, +/* 0x8921 */ { false, 0x8921, 0x8921 }, +/* 0x8922 */ { false, 0x8922, 0x8922 }, +/* 0x8923 */ { false, 0x8923, 0x8923 }, +/* 0x8924 */ { false, 0x8924, 0x8924 }, +/* 0x8925 */ { false, 0x8925, 0x8925 }, +/* 0x8926 */ { false, 0x8926, 0x8926 }, +/* 0x8927 */ { false, 0x8927, 0x8927 }, +/* 0x8928 */ { false, 0x8928, 0x8928 }, +/* 0x8929 */ { false, 0x8929, 0x8929 }, +/* 0x892a */ { false, 0x892a, 0x892a }, +/* 0x892b */ { false, 0x892b, 0x892b }, +/* 0x892c */ { false, 0x892c, 0x892c }, +/* 0x892d */ { false, 0x892d, 0x892d }, +/* 0x892e */ { false, 0x892e, 0x892e }, +/* 0x892f */ { false, 0x892f, 0x892f }, +/* 0x8930 */ { false, 0x8930, 0x8930 }, +/* 0x8931 */ { false, 0x8931, 0x8931 }, +/* 0x8932 */ { false, 0x8932, 0x8932 }, +/* 0x8933 */ { false, 0x8933, 0x8933 }, +/* 0x8934 */ { false, 0x8934, 0x8934 }, +/* 0x8935 */ { false, 0x8935, 0x8935 }, +/* 0x8936 */ { false, 0x8936, 0x8936 }, +/* 0x8937 */ { false, 0x8937, 0x8937 }, +/* 0x8938 */ { false, 0x8938, 0x8938 }, +/* 0x8939 */ { false, 0x8939, 0x8939 }, +/* 0x893a */ { false, 0x893a, 0x893a }, +/* 0x893b */ { false, 0x893b, 0x893b }, +/* 0x893c */ { false, 0x893c, 0x893c }, +/* 0x893d */ { false, 0x893d, 0x893d }, +/* 0x893e */ { false, 0x893e, 0x893e }, +/* 0x893f */ { false, 0x893f, 0x893f }, +/* 0x8940 */ { false, 0x8940, 0x8940 }, +/* 0x8941 */ { false, 0x8941, 0x8941 }, +/* 0x8942 */ { false, 0x8942, 0x8942 }, +/* 0x8943 */ { false, 0x8943, 0x8943 }, +/* 0x8944 */ { false, 0x8944, 0x8944 }, +/* 0x8945 */ { false, 0x8945, 0x8945 }, +/* 0x8946 */ { false, 0x8946, 0x8946 }, +/* 0x8947 */ { false, 0x8947, 0x8947 }, +/* 0x8948 */ { false, 0x8948, 0x8948 }, +/* 0x8949 */ { false, 0x8949, 0x8949 }, +/* 0x894a */ { false, 0x894a, 0x894a }, +/* 0x894b */ { false, 0x894b, 0x894b }, +/* 0x894c */ { false, 0x894c, 0x894c }, +/* 0x894d */ { false, 0x894d, 0x894d }, +/* 0x894e */ { false, 0x894e, 0x894e }, +/* 0x894f */ { false, 0x894f, 0x894f }, +/* 0x8950 */ { false, 0x8950, 0x8950 }, +/* 0x8951 */ { false, 0x8951, 0x8951 }, +/* 0x8952 */ { false, 0x8952, 0x8952 }, +/* 0x8953 */ { false, 0x8953, 0x8953 }, +/* 0x8954 */ { false, 0x8954, 0x8954 }, +/* 0x8955 */ { false, 0x8955, 0x8955 }, +/* 0x8956 */ { false, 0x8956, 0x8956 }, +/* 0x8957 */ { false, 0x8957, 0x8957 }, +/* 0x8958 */ { false, 0x8958, 0x8958 }, +/* 0x8959 */ { false, 0x8959, 0x8959 }, +/* 0x895a */ { false, 0x895a, 0x895a }, +/* 0x895b */ { false, 0x895b, 0x895b }, +/* 0x895c */ { false, 0x895c, 0x895c }, +/* 0x895d */ { false, 0x895d, 0x895d }, +/* 0x895e */ { false, 0x895e, 0x895e }, +/* 0x895f */ { false, 0x895f, 0x895f }, +/* 0x8960 */ { false, 0x8960, 0x8960 }, +/* 0x8961 */ { false, 0x8961, 0x8961 }, +/* 0x8962 */ { false, 0x8962, 0x8962 }, +/* 0x8963 */ { false, 0x8963, 0x8963 }, +/* 0x8964 */ { false, 0x8964, 0x8964 }, +/* 0x8965 */ { false, 0x8965, 0x8965 }, +/* 0x8966 */ { false, 0x8966, 0x8966 }, +/* 0x8967 */ { false, 0x8967, 0x8967 }, +/* 0x8968 */ { false, 0x8968, 0x8968 }, +/* 0x8969 */ { false, 0x8969, 0x8969 }, +/* 0x896a */ { false, 0x896a, 0x896a }, +/* 0x896b */ { false, 0x896b, 0x896b }, +/* 0x896c */ { false, 0x896c, 0x896c }, +/* 0x896d */ { false, 0x896d, 0x896d }, +/* 0x896e */ { false, 0x896e, 0x896e }, +/* 0x896f */ { false, 0x896f, 0x896f }, +/* 0x8970 */ { false, 0x8970, 0x8970 }, +/* 0x8971 */ { false, 0x8971, 0x8971 }, +/* 0x8972 */ { false, 0x8972, 0x8972 }, +/* 0x8973 */ { false, 0x8973, 0x8973 }, +/* 0x8974 */ { false, 0x8974, 0x8974 }, +/* 0x8975 */ { false, 0x8975, 0x8975 }, +/* 0x8976 */ { false, 0x8976, 0x8976 }, +/* 0x8977 */ { false, 0x8977, 0x8977 }, +/* 0x8978 */ { false, 0x8978, 0x8978 }, +/* 0x8979 */ { false, 0x8979, 0x8979 }, +/* 0x897a */ { false, 0x897a, 0x897a }, +/* 0x897b */ { false, 0x897b, 0x897b }, +/* 0x897c */ { false, 0x897c, 0x897c }, +/* 0x897d */ { false, 0x897d, 0x897d }, +/* 0x897e */ { false, 0x897e, 0x897e }, +/* 0x897f */ { false, 0x897f, 0x897f }, +/* 0x8980 */ { false, 0x8980, 0x8980 }, +/* 0x8981 */ { false, 0x8981, 0x8981 }, +/* 0x8982 */ { false, 0x8982, 0x8982 }, +/* 0x8983 */ { false, 0x8983, 0x8983 }, +/* 0x8984 */ { false, 0x8984, 0x8984 }, +/* 0x8985 */ { false, 0x8985, 0x8985 }, +/* 0x8986 */ { false, 0x8986, 0x8986 }, +/* 0x8987 */ { false, 0x8987, 0x8987 }, +/* 0x8988 */ { false, 0x8988, 0x8988 }, +/* 0x8989 */ { false, 0x8989, 0x8989 }, +/* 0x898a */ { false, 0x898a, 0x898a }, +/* 0x898b */ { false, 0x898b, 0x898b }, +/* 0x898c */ { false, 0x898c, 0x898c }, +/* 0x898d */ { false, 0x898d, 0x898d }, +/* 0x898e */ { false, 0x898e, 0x898e }, +/* 0x898f */ { false, 0x898f, 0x898f }, +/* 0x8990 */ { false, 0x8990, 0x8990 }, +/* 0x8991 */ { false, 0x8991, 0x8991 }, +/* 0x8992 */ { false, 0x8992, 0x8992 }, +/* 0x8993 */ { false, 0x8993, 0x8993 }, +/* 0x8994 */ { false, 0x8994, 0x8994 }, +/* 0x8995 */ { false, 0x8995, 0x8995 }, +/* 0x8996 */ { false, 0x8996, 0x8996 }, +/* 0x8997 */ { false, 0x8997, 0x8997 }, +/* 0x8998 */ { false, 0x8998, 0x8998 }, +/* 0x8999 */ { false, 0x8999, 0x8999 }, +/* 0x899a */ { false, 0x899a, 0x899a }, +/* 0x899b */ { false, 0x899b, 0x899b }, +/* 0x899c */ { false, 0x899c, 0x899c }, +/* 0x899d */ { false, 0x899d, 0x899d }, +/* 0x899e */ { false, 0x899e, 0x899e }, +/* 0x899f */ { false, 0x899f, 0x899f }, +/* 0x89a0 */ { false, 0x89a0, 0x89a0 }, +/* 0x89a1 */ { false, 0x89a1, 0x89a1 }, +/* 0x89a2 */ { false, 0x89a2, 0x89a2 }, +/* 0x89a3 */ { false, 0x89a3, 0x89a3 }, +/* 0x89a4 */ { false, 0x89a4, 0x89a4 }, +/* 0x89a5 */ { false, 0x89a5, 0x89a5 }, +/* 0x89a6 */ { false, 0x89a6, 0x89a6 }, +/* 0x89a7 */ { false, 0x89a7, 0x89a7 }, +/* 0x89a8 */ { false, 0x89a8, 0x89a8 }, +/* 0x89a9 */ { false, 0x89a9, 0x89a9 }, +/* 0x89aa */ { false, 0x89aa, 0x89aa }, +/* 0x89ab */ { false, 0x89ab, 0x89ab }, +/* 0x89ac */ { false, 0x89ac, 0x89ac }, +/* 0x89ad */ { false, 0x89ad, 0x89ad }, +/* 0x89ae */ { false, 0x89ae, 0x89ae }, +/* 0x89af */ { false, 0x89af, 0x89af }, +/* 0x89b0 */ { false, 0x89b0, 0x89b0 }, +/* 0x89b1 */ { false, 0x89b1, 0x89b1 }, +/* 0x89b2 */ { false, 0x89b2, 0x89b2 }, +/* 0x89b3 */ { false, 0x89b3, 0x89b3 }, +/* 0x89b4 */ { false, 0x89b4, 0x89b4 }, +/* 0x89b5 */ { false, 0x89b5, 0x89b5 }, +/* 0x89b6 */ { false, 0x89b6, 0x89b6 }, +/* 0x89b7 */ { false, 0x89b7, 0x89b7 }, +/* 0x89b8 */ { false, 0x89b8, 0x89b8 }, +/* 0x89b9 */ { false, 0x89b9, 0x89b9 }, +/* 0x89ba */ { false, 0x89ba, 0x89ba }, +/* 0x89bb */ { false, 0x89bb, 0x89bb }, +/* 0x89bc */ { false, 0x89bc, 0x89bc }, +/* 0x89bd */ { false, 0x89bd, 0x89bd }, +/* 0x89be */ { false, 0x89be, 0x89be }, +/* 0x89bf */ { false, 0x89bf, 0x89bf }, +/* 0x89c0 */ { false, 0x89c0, 0x89c0 }, +/* 0x89c1 */ { false, 0x89c1, 0x89c1 }, +/* 0x89c2 */ { false, 0x89c2, 0x89c2 }, +/* 0x89c3 */ { false, 0x89c3, 0x89c3 }, +/* 0x89c4 */ { false, 0x89c4, 0x89c4 }, +/* 0x89c5 */ { false, 0x89c5, 0x89c5 }, +/* 0x89c6 */ { false, 0x89c6, 0x89c6 }, +/* 0x89c7 */ { false, 0x89c7, 0x89c7 }, +/* 0x89c8 */ { false, 0x89c8, 0x89c8 }, +/* 0x89c9 */ { false, 0x89c9, 0x89c9 }, +/* 0x89ca */ { false, 0x89ca, 0x89ca }, +/* 0x89cb */ { false, 0x89cb, 0x89cb }, +/* 0x89cc */ { false, 0x89cc, 0x89cc }, +/* 0x89cd */ { false, 0x89cd, 0x89cd }, +/* 0x89ce */ { false, 0x89ce, 0x89ce }, +/* 0x89cf */ { false, 0x89cf, 0x89cf }, +/* 0x89d0 */ { false, 0x89d0, 0x89d0 }, +/* 0x89d1 */ { false, 0x89d1, 0x89d1 }, +/* 0x89d2 */ { false, 0x89d2, 0x89d2 }, +/* 0x89d3 */ { false, 0x89d3, 0x89d3 }, +/* 0x89d4 */ { false, 0x89d4, 0x89d4 }, +/* 0x89d5 */ { false, 0x89d5, 0x89d5 }, +/* 0x89d6 */ { false, 0x89d6, 0x89d6 }, +/* 0x89d7 */ { false, 0x89d7, 0x89d7 }, +/* 0x89d8 */ { false, 0x89d8, 0x89d8 }, +/* 0x89d9 */ { false, 0x89d9, 0x89d9 }, +/* 0x89da */ { false, 0x89da, 0x89da }, +/* 0x89db */ { false, 0x89db, 0x89db }, +/* 0x89dc */ { false, 0x89dc, 0x89dc }, +/* 0x89dd */ { false, 0x89dd, 0x89dd }, +/* 0x89de */ { false, 0x89de, 0x89de }, +/* 0x89df */ { false, 0x89df, 0x89df }, +/* 0x89e0 */ { false, 0x89e0, 0x89e0 }, +/* 0x89e1 */ { false, 0x89e1, 0x89e1 }, +/* 0x89e2 */ { false, 0x89e2, 0x89e2 }, +/* 0x89e3 */ { false, 0x89e3, 0x89e3 }, +/* 0x89e4 */ { false, 0x89e4, 0x89e4 }, +/* 0x89e5 */ { false, 0x89e5, 0x89e5 }, +/* 0x89e6 */ { false, 0x89e6, 0x89e6 }, +/* 0x89e7 */ { false, 0x89e7, 0x89e7 }, +/* 0x89e8 */ { false, 0x89e8, 0x89e8 }, +/* 0x89e9 */ { false, 0x89e9, 0x89e9 }, +/* 0x89ea */ { false, 0x89ea, 0x89ea }, +/* 0x89eb */ { false, 0x89eb, 0x89eb }, +/* 0x89ec */ { false, 0x89ec, 0x89ec }, +/* 0x89ed */ { false, 0x89ed, 0x89ed }, +/* 0x89ee */ { false, 0x89ee, 0x89ee }, +/* 0x89ef */ { false, 0x89ef, 0x89ef }, +/* 0x89f0 */ { false, 0x89f0, 0x89f0 }, +/* 0x89f1 */ { false, 0x89f1, 0x89f1 }, +/* 0x89f2 */ { false, 0x89f2, 0x89f2 }, +/* 0x89f3 */ { false, 0x89f3, 0x89f3 }, +/* 0x89f4 */ { false, 0x89f4, 0x89f4 }, +/* 0x89f5 */ { false, 0x89f5, 0x89f5 }, +/* 0x89f6 */ { false, 0x89f6, 0x89f6 }, +/* 0x89f7 */ { false, 0x89f7, 0x89f7 }, +/* 0x89f8 */ { false, 0x89f8, 0x89f8 }, +/* 0x89f9 */ { false, 0x89f9, 0x89f9 }, +/* 0x89fa */ { false, 0x89fa, 0x89fa }, +/* 0x89fb */ { false, 0x89fb, 0x89fb }, +/* 0x89fc */ { false, 0x89fc, 0x89fc }, +/* 0x89fd */ { false, 0x89fd, 0x89fd }, +/* 0x89fe */ { false, 0x89fe, 0x89fe }, +/* 0x89ff */ { false, 0x89ff, 0x89ff }, +/* 0x8a00 */ { false, 0x8a00, 0x8a00 }, +/* 0x8a01 */ { false, 0x8a01, 0x8a01 }, +/* 0x8a02 */ { false, 0x8a02, 0x8a02 }, +/* 0x8a03 */ { false, 0x8a03, 0x8a03 }, +/* 0x8a04 */ { false, 0x8a04, 0x8a04 }, +/* 0x8a05 */ { false, 0x8a05, 0x8a05 }, +/* 0x8a06 */ { false, 0x8a06, 0x8a06 }, +/* 0x8a07 */ { false, 0x8a07, 0x8a07 }, +/* 0x8a08 */ { false, 0x8a08, 0x8a08 }, +/* 0x8a09 */ { false, 0x8a09, 0x8a09 }, +/* 0x8a0a */ { false, 0x8a0a, 0x8a0a }, +/* 0x8a0b */ { false, 0x8a0b, 0x8a0b }, +/* 0x8a0c */ { false, 0x8a0c, 0x8a0c }, +/* 0x8a0d */ { false, 0x8a0d, 0x8a0d }, +/* 0x8a0e */ { false, 0x8a0e, 0x8a0e }, +/* 0x8a0f */ { false, 0x8a0f, 0x8a0f }, +/* 0x8a10 */ { false, 0x8a10, 0x8a10 }, +/* 0x8a11 */ { false, 0x8a11, 0x8a11 }, +/* 0x8a12 */ { false, 0x8a12, 0x8a12 }, +/* 0x8a13 */ { false, 0x8a13, 0x8a13 }, +/* 0x8a14 */ { false, 0x8a14, 0x8a14 }, +/* 0x8a15 */ { false, 0x8a15, 0x8a15 }, +/* 0x8a16 */ { false, 0x8a16, 0x8a16 }, +/* 0x8a17 */ { false, 0x8a17, 0x8a17 }, +/* 0x8a18 */ { false, 0x8a18, 0x8a18 }, +/* 0x8a19 */ { false, 0x8a19, 0x8a19 }, +/* 0x8a1a */ { false, 0x8a1a, 0x8a1a }, +/* 0x8a1b */ { false, 0x8a1b, 0x8a1b }, +/* 0x8a1c */ { false, 0x8a1c, 0x8a1c }, +/* 0x8a1d */ { false, 0x8a1d, 0x8a1d }, +/* 0x8a1e */ { false, 0x8a1e, 0x8a1e }, +/* 0x8a1f */ { false, 0x8a1f, 0x8a1f }, +/* 0x8a20 */ { false, 0x8a20, 0x8a20 }, +/* 0x8a21 */ { false, 0x8a21, 0x8a21 }, +/* 0x8a22 */ { false, 0x8a22, 0x8a22 }, +/* 0x8a23 */ { false, 0x8a23, 0x8a23 }, +/* 0x8a24 */ { false, 0x8a24, 0x8a24 }, +/* 0x8a25 */ { false, 0x8a25, 0x8a25 }, +/* 0x8a26 */ { false, 0x8a26, 0x8a26 }, +/* 0x8a27 */ { false, 0x8a27, 0x8a27 }, +/* 0x8a28 */ { false, 0x8a28, 0x8a28 }, +/* 0x8a29 */ { false, 0x8a29, 0x8a29 }, +/* 0x8a2a */ { false, 0x8a2a, 0x8a2a }, +/* 0x8a2b */ { false, 0x8a2b, 0x8a2b }, +/* 0x8a2c */ { false, 0x8a2c, 0x8a2c }, +/* 0x8a2d */ { false, 0x8a2d, 0x8a2d }, +/* 0x8a2e */ { false, 0x8a2e, 0x8a2e }, +/* 0x8a2f */ { false, 0x8a2f, 0x8a2f }, +/* 0x8a30 */ { false, 0x8a30, 0x8a30 }, +/* 0x8a31 */ { false, 0x8a31, 0x8a31 }, +/* 0x8a32 */ { false, 0x8a32, 0x8a32 }, +/* 0x8a33 */ { false, 0x8a33, 0x8a33 }, +/* 0x8a34 */ { false, 0x8a34, 0x8a34 }, +/* 0x8a35 */ { false, 0x8a35, 0x8a35 }, +/* 0x8a36 */ { false, 0x8a36, 0x8a36 }, +/* 0x8a37 */ { false, 0x8a37, 0x8a37 }, +/* 0x8a38 */ { false, 0x8a38, 0x8a38 }, +/* 0x8a39 */ { false, 0x8a39, 0x8a39 }, +/* 0x8a3a */ { false, 0x8a3a, 0x8a3a }, +/* 0x8a3b */ { false, 0x8a3b, 0x8a3b }, +/* 0x8a3c */ { false, 0x8a3c, 0x8a3c }, +/* 0x8a3d */ { false, 0x8a3d, 0x8a3d }, +/* 0x8a3e */ { false, 0x8a3e, 0x8a3e }, +/* 0x8a3f */ { false, 0x8a3f, 0x8a3f }, +/* 0x8a40 */ { false, 0x8a40, 0x8a40 }, +/* 0x8a41 */ { false, 0x8a41, 0x8a41 }, +/* 0x8a42 */ { false, 0x8a42, 0x8a42 }, +/* 0x8a43 */ { false, 0x8a43, 0x8a43 }, +/* 0x8a44 */ { false, 0x8a44, 0x8a44 }, +/* 0x8a45 */ { false, 0x8a45, 0x8a45 }, +/* 0x8a46 */ { false, 0x8a46, 0x8a46 }, +/* 0x8a47 */ { false, 0x8a47, 0x8a47 }, +/* 0x8a48 */ { false, 0x8a48, 0x8a48 }, +/* 0x8a49 */ { false, 0x8a49, 0x8a49 }, +/* 0x8a4a */ { false, 0x8a4a, 0x8a4a }, +/* 0x8a4b */ { false, 0x8a4b, 0x8a4b }, +/* 0x8a4c */ { false, 0x8a4c, 0x8a4c }, +/* 0x8a4d */ { false, 0x8a4d, 0x8a4d }, +/* 0x8a4e */ { false, 0x8a4e, 0x8a4e }, +/* 0x8a4f */ { false, 0x8a4f, 0x8a4f }, +/* 0x8a50 */ { false, 0x8a50, 0x8a50 }, +/* 0x8a51 */ { false, 0x8a51, 0x8a51 }, +/* 0x8a52 */ { false, 0x8a52, 0x8a52 }, +/* 0x8a53 */ { false, 0x8a53, 0x8a53 }, +/* 0x8a54 */ { false, 0x8a54, 0x8a54 }, +/* 0x8a55 */ { false, 0x8a55, 0x8a55 }, +/* 0x8a56 */ { false, 0x8a56, 0x8a56 }, +/* 0x8a57 */ { false, 0x8a57, 0x8a57 }, +/* 0x8a58 */ { false, 0x8a58, 0x8a58 }, +/* 0x8a59 */ { false, 0x8a59, 0x8a59 }, +/* 0x8a5a */ { false, 0x8a5a, 0x8a5a }, +/* 0x8a5b */ { false, 0x8a5b, 0x8a5b }, +/* 0x8a5c */ { false, 0x8a5c, 0x8a5c }, +/* 0x8a5d */ { false, 0x8a5d, 0x8a5d }, +/* 0x8a5e */ { false, 0x8a5e, 0x8a5e }, +/* 0x8a5f */ { false, 0x8a5f, 0x8a5f }, +/* 0x8a60 */ { false, 0x8a60, 0x8a60 }, +/* 0x8a61 */ { false, 0x8a61, 0x8a61 }, +/* 0x8a62 */ { false, 0x8a62, 0x8a62 }, +/* 0x8a63 */ { false, 0x8a63, 0x8a63 }, +/* 0x8a64 */ { false, 0x8a64, 0x8a64 }, +/* 0x8a65 */ { false, 0x8a65, 0x8a65 }, +/* 0x8a66 */ { false, 0x8a66, 0x8a66 }, +/* 0x8a67 */ { false, 0x8a67, 0x8a67 }, +/* 0x8a68 */ { false, 0x8a68, 0x8a68 }, +/* 0x8a69 */ { false, 0x8a69, 0x8a69 }, +/* 0x8a6a */ { false, 0x8a6a, 0x8a6a }, +/* 0x8a6b */ { false, 0x8a6b, 0x8a6b }, +/* 0x8a6c */ { false, 0x8a6c, 0x8a6c }, +/* 0x8a6d */ { false, 0x8a6d, 0x8a6d }, +/* 0x8a6e */ { false, 0x8a6e, 0x8a6e }, +/* 0x8a6f */ { false, 0x8a6f, 0x8a6f }, +/* 0x8a70 */ { false, 0x8a70, 0x8a70 }, +/* 0x8a71 */ { false, 0x8a71, 0x8a71 }, +/* 0x8a72 */ { false, 0x8a72, 0x8a72 }, +/* 0x8a73 */ { false, 0x8a73, 0x8a73 }, +/* 0x8a74 */ { false, 0x8a74, 0x8a74 }, +/* 0x8a75 */ { false, 0x8a75, 0x8a75 }, +/* 0x8a76 */ { false, 0x8a76, 0x8a76 }, +/* 0x8a77 */ { false, 0x8a77, 0x8a77 }, +/* 0x8a78 */ { false, 0x8a78, 0x8a78 }, +/* 0x8a79 */ { false, 0x8a79, 0x8a79 }, +/* 0x8a7a */ { false, 0x8a7a, 0x8a7a }, +/* 0x8a7b */ { false, 0x8a7b, 0x8a7b }, +/* 0x8a7c */ { false, 0x8a7c, 0x8a7c }, +/* 0x8a7d */ { false, 0x8a7d, 0x8a7d }, +/* 0x8a7e */ { false, 0x8a7e, 0x8a7e }, +/* 0x8a7f */ { false, 0x8a7f, 0x8a7f }, +/* 0x8a80 */ { false, 0x8a80, 0x8a80 }, +/* 0x8a81 */ { false, 0x8a81, 0x8a81 }, +/* 0x8a82 */ { false, 0x8a82, 0x8a82 }, +/* 0x8a83 */ { false, 0x8a83, 0x8a83 }, +/* 0x8a84 */ { false, 0x8a84, 0x8a84 }, +/* 0x8a85 */ { false, 0x8a85, 0x8a85 }, +/* 0x8a86 */ { false, 0x8a86, 0x8a86 }, +/* 0x8a87 */ { false, 0x8a87, 0x8a87 }, +/* 0x8a88 */ { false, 0x8a88, 0x8a88 }, +/* 0x8a89 */ { false, 0x8a89, 0x8a89 }, +/* 0x8a8a */ { false, 0x8a8a, 0x8a8a }, +/* 0x8a8b */ { false, 0x8a8b, 0x8a8b }, +/* 0x8a8c */ { false, 0x8a8c, 0x8a8c }, +/* 0x8a8d */ { false, 0x8a8d, 0x8a8d }, +/* 0x8a8e */ { false, 0x8a8e, 0x8a8e }, +/* 0x8a8f */ { false, 0x8a8f, 0x8a8f }, +/* 0x8a90 */ { false, 0x8a90, 0x8a90 }, +/* 0x8a91 */ { false, 0x8a91, 0x8a91 }, +/* 0x8a92 */ { false, 0x8a92, 0x8a92 }, +/* 0x8a93 */ { false, 0x8a93, 0x8a93 }, +/* 0x8a94 */ { false, 0x8a94, 0x8a94 }, +/* 0x8a95 */ { false, 0x8a95, 0x8a95 }, +/* 0x8a96 */ { false, 0x8a96, 0x8a96 }, +/* 0x8a97 */ { false, 0x8a97, 0x8a97 }, +/* 0x8a98 */ { false, 0x8a98, 0x8a98 }, +/* 0x8a99 */ { false, 0x8a99, 0x8a99 }, +/* 0x8a9a */ { false, 0x8a9a, 0x8a9a }, +/* 0x8a9b */ { false, 0x8a9b, 0x8a9b }, +/* 0x8a9c */ { false, 0x8a9c, 0x8a9c }, +/* 0x8a9d */ { false, 0x8a9d, 0x8a9d }, +/* 0x8a9e */ { false, 0x8a9e, 0x8a9e }, +/* 0x8a9f */ { false, 0x8a9f, 0x8a9f }, +/* 0x8aa0 */ { false, 0x8aa0, 0x8aa0 }, +/* 0x8aa1 */ { false, 0x8aa1, 0x8aa1 }, +/* 0x8aa2 */ { false, 0x8aa2, 0x8aa2 }, +/* 0x8aa3 */ { false, 0x8aa3, 0x8aa3 }, +/* 0x8aa4 */ { false, 0x8aa4, 0x8aa4 }, +/* 0x8aa5 */ { false, 0x8aa5, 0x8aa5 }, +/* 0x8aa6 */ { false, 0x8aa6, 0x8aa6 }, +/* 0x8aa7 */ { false, 0x8aa7, 0x8aa7 }, +/* 0x8aa8 */ { false, 0x8aa8, 0x8aa8 }, +/* 0x8aa9 */ { false, 0x8aa9, 0x8aa9 }, +/* 0x8aaa */ { false, 0x8aaa, 0x8aaa }, +/* 0x8aab */ { false, 0x8aab, 0x8aab }, +/* 0x8aac */ { false, 0x8aac, 0x8aac }, +/* 0x8aad */ { false, 0x8aad, 0x8aad }, +/* 0x8aae */ { false, 0x8aae, 0x8aae }, +/* 0x8aaf */ { false, 0x8aaf, 0x8aaf }, +/* 0x8ab0 */ { false, 0x8ab0, 0x8ab0 }, +/* 0x8ab1 */ { false, 0x8ab1, 0x8ab1 }, +/* 0x8ab2 */ { false, 0x8ab2, 0x8ab2 }, +/* 0x8ab3 */ { false, 0x8ab3, 0x8ab3 }, +/* 0x8ab4 */ { false, 0x8ab4, 0x8ab4 }, +/* 0x8ab5 */ { false, 0x8ab5, 0x8ab5 }, +/* 0x8ab6 */ { false, 0x8ab6, 0x8ab6 }, +/* 0x8ab7 */ { false, 0x8ab7, 0x8ab7 }, +/* 0x8ab8 */ { false, 0x8ab8, 0x8ab8 }, +/* 0x8ab9 */ { false, 0x8ab9, 0x8ab9 }, +/* 0x8aba */ { false, 0x8aba, 0x8aba }, +/* 0x8abb */ { false, 0x8abb, 0x8abb }, +/* 0x8abc */ { false, 0x8abc, 0x8abc }, +/* 0x8abd */ { false, 0x8abd, 0x8abd }, +/* 0x8abe */ { false, 0x8abe, 0x8abe }, +/* 0x8abf */ { false, 0x8abf, 0x8abf }, +/* 0x8ac0 */ { false, 0x8ac0, 0x8ac0 }, +/* 0x8ac1 */ { false, 0x8ac1, 0x8ac1 }, +/* 0x8ac2 */ { false, 0x8ac2, 0x8ac2 }, +/* 0x8ac3 */ { false, 0x8ac3, 0x8ac3 }, +/* 0x8ac4 */ { false, 0x8ac4, 0x8ac4 }, +/* 0x8ac5 */ { false, 0x8ac5, 0x8ac5 }, +/* 0x8ac6 */ { false, 0x8ac6, 0x8ac6 }, +/* 0x8ac7 */ { false, 0x8ac7, 0x8ac7 }, +/* 0x8ac8 */ { false, 0x8ac8, 0x8ac8 }, +/* 0x8ac9 */ { false, 0x8ac9, 0x8ac9 }, +/* 0x8aca */ { false, 0x8aca, 0x8aca }, +/* 0x8acb */ { false, 0x8acb, 0x8acb }, +/* 0x8acc */ { false, 0x8acc, 0x8acc }, +/* 0x8acd */ { false, 0x8acd, 0x8acd }, +/* 0x8ace */ { false, 0x8ace, 0x8ace }, +/* 0x8acf */ { false, 0x8acf, 0x8acf }, +/* 0x8ad0 */ { false, 0x8ad0, 0x8ad0 }, +/* 0x8ad1 */ { false, 0x8ad1, 0x8ad1 }, +/* 0x8ad2 */ { false, 0x8ad2, 0x8ad2 }, +/* 0x8ad3 */ { false, 0x8ad3, 0x8ad3 }, +/* 0x8ad4 */ { false, 0x8ad4, 0x8ad4 }, +/* 0x8ad5 */ { false, 0x8ad5, 0x8ad5 }, +/* 0x8ad6 */ { false, 0x8ad6, 0x8ad6 }, +/* 0x8ad7 */ { false, 0x8ad7, 0x8ad7 }, +/* 0x8ad8 */ { false, 0x8ad8, 0x8ad8 }, +/* 0x8ad9 */ { false, 0x8ad9, 0x8ad9 }, +/* 0x8ada */ { false, 0x8ada, 0x8ada }, +/* 0x8adb */ { false, 0x8adb, 0x8adb }, +/* 0x8adc */ { false, 0x8adc, 0x8adc }, +/* 0x8add */ { false, 0x8add, 0x8add }, +/* 0x8ade */ { false, 0x8ade, 0x8ade }, +/* 0x8adf */ { false, 0x8adf, 0x8adf }, +/* 0x8ae0 */ { false, 0x8ae0, 0x8ae0 }, +/* 0x8ae1 */ { false, 0x8ae1, 0x8ae1 }, +/* 0x8ae2 */ { false, 0x8ae2, 0x8ae2 }, +/* 0x8ae3 */ { false, 0x8ae3, 0x8ae3 }, +/* 0x8ae4 */ { false, 0x8ae4, 0x8ae4 }, +/* 0x8ae5 */ { false, 0x8ae5, 0x8ae5 }, +/* 0x8ae6 */ { false, 0x8ae6, 0x8ae6 }, +/* 0x8ae7 */ { false, 0x8ae7, 0x8ae7 }, +/* 0x8ae8 */ { false, 0x8ae8, 0x8ae8 }, +/* 0x8ae9 */ { false, 0x8ae9, 0x8ae9 }, +/* 0x8aea */ { false, 0x8aea, 0x8aea }, +/* 0x8aeb */ { false, 0x8aeb, 0x8aeb }, +/* 0x8aec */ { false, 0x8aec, 0x8aec }, +/* 0x8aed */ { false, 0x8aed, 0x8aed }, +/* 0x8aee */ { false, 0x8aee, 0x8aee }, +/* 0x8aef */ { false, 0x8aef, 0x8aef }, +/* 0x8af0 */ { false, 0x8af0, 0x8af0 }, +/* 0x8af1 */ { false, 0x8af1, 0x8af1 }, +/* 0x8af2 */ { false, 0x8af2, 0x8af2 }, +/* 0x8af3 */ { false, 0x8af3, 0x8af3 }, +/* 0x8af4 */ { false, 0x8af4, 0x8af4 }, +/* 0x8af5 */ { false, 0x8af5, 0x8af5 }, +/* 0x8af6 */ { false, 0x8af6, 0x8af6 }, +/* 0x8af7 */ { false, 0x8af7, 0x8af7 }, +/* 0x8af8 */ { false, 0x8af8, 0x8af8 }, +/* 0x8af9 */ { false, 0x8af9, 0x8af9 }, +/* 0x8afa */ { false, 0x8afa, 0x8afa }, +/* 0x8afb */ { false, 0x8afb, 0x8afb }, +/* 0x8afc */ { false, 0x8afc, 0x8afc }, +/* 0x8afd */ { false, 0x8afd, 0x8afd }, +/* 0x8afe */ { false, 0x8afe, 0x8afe }, +/* 0x8aff */ { false, 0x8aff, 0x8aff }, +/* 0x8b00 */ { false, 0x8b00, 0x8b00 }, +/* 0x8b01 */ { false, 0x8b01, 0x8b01 }, +/* 0x8b02 */ { false, 0x8b02, 0x8b02 }, +/* 0x8b03 */ { false, 0x8b03, 0x8b03 }, +/* 0x8b04 */ { false, 0x8b04, 0x8b04 }, +/* 0x8b05 */ { false, 0x8b05, 0x8b05 }, +/* 0x8b06 */ { false, 0x8b06, 0x8b06 }, +/* 0x8b07 */ { false, 0x8b07, 0x8b07 }, +/* 0x8b08 */ { false, 0x8b08, 0x8b08 }, +/* 0x8b09 */ { false, 0x8b09, 0x8b09 }, +/* 0x8b0a */ { false, 0x8b0a, 0x8b0a }, +/* 0x8b0b */ { false, 0x8b0b, 0x8b0b }, +/* 0x8b0c */ { false, 0x8b0c, 0x8b0c }, +/* 0x8b0d */ { false, 0x8b0d, 0x8b0d }, +/* 0x8b0e */ { false, 0x8b0e, 0x8b0e }, +/* 0x8b0f */ { false, 0x8b0f, 0x8b0f }, +/* 0x8b10 */ { false, 0x8b10, 0x8b10 }, +/* 0x8b11 */ { false, 0x8b11, 0x8b11 }, +/* 0x8b12 */ { false, 0x8b12, 0x8b12 }, +/* 0x8b13 */ { false, 0x8b13, 0x8b13 }, +/* 0x8b14 */ { false, 0x8b14, 0x8b14 }, +/* 0x8b15 */ { false, 0x8b15, 0x8b15 }, +/* 0x8b16 */ { false, 0x8b16, 0x8b16 }, +/* 0x8b17 */ { false, 0x8b17, 0x8b17 }, +/* 0x8b18 */ { false, 0x8b18, 0x8b18 }, +/* 0x8b19 */ { false, 0x8b19, 0x8b19 }, +/* 0x8b1a */ { false, 0x8b1a, 0x8b1a }, +/* 0x8b1b */ { false, 0x8b1b, 0x8b1b }, +/* 0x8b1c */ { false, 0x8b1c, 0x8b1c }, +/* 0x8b1d */ { false, 0x8b1d, 0x8b1d }, +/* 0x8b1e */ { false, 0x8b1e, 0x8b1e }, +/* 0x8b1f */ { false, 0x8b1f, 0x8b1f }, +/* 0x8b20 */ { false, 0x8b20, 0x8b20 }, +/* 0x8b21 */ { false, 0x8b21, 0x8b21 }, +/* 0x8b22 */ { false, 0x8b22, 0x8b22 }, +/* 0x8b23 */ { false, 0x8b23, 0x8b23 }, +/* 0x8b24 */ { false, 0x8b24, 0x8b24 }, +/* 0x8b25 */ { false, 0x8b25, 0x8b25 }, +/* 0x8b26 */ { false, 0x8b26, 0x8b26 }, +/* 0x8b27 */ { false, 0x8b27, 0x8b27 }, +/* 0x8b28 */ { false, 0x8b28, 0x8b28 }, +/* 0x8b29 */ { false, 0x8b29, 0x8b29 }, +/* 0x8b2a */ { false, 0x8b2a, 0x8b2a }, +/* 0x8b2b */ { false, 0x8b2b, 0x8b2b }, +/* 0x8b2c */ { false, 0x8b2c, 0x8b2c }, +/* 0x8b2d */ { false, 0x8b2d, 0x8b2d }, +/* 0x8b2e */ { false, 0x8b2e, 0x8b2e }, +/* 0x8b2f */ { false, 0x8b2f, 0x8b2f }, +/* 0x8b30 */ { false, 0x8b30, 0x8b30 }, +/* 0x8b31 */ { false, 0x8b31, 0x8b31 }, +/* 0x8b32 */ { false, 0x8b32, 0x8b32 }, +/* 0x8b33 */ { false, 0x8b33, 0x8b33 }, +/* 0x8b34 */ { false, 0x8b34, 0x8b34 }, +/* 0x8b35 */ { false, 0x8b35, 0x8b35 }, +/* 0x8b36 */ { false, 0x8b36, 0x8b36 }, +/* 0x8b37 */ { false, 0x8b37, 0x8b37 }, +/* 0x8b38 */ { false, 0x8b38, 0x8b38 }, +/* 0x8b39 */ { false, 0x8b39, 0x8b39 }, +/* 0x8b3a */ { false, 0x8b3a, 0x8b3a }, +/* 0x8b3b */ { false, 0x8b3b, 0x8b3b }, +/* 0x8b3c */ { false, 0x8b3c, 0x8b3c }, +/* 0x8b3d */ { false, 0x8b3d, 0x8b3d }, +/* 0x8b3e */ { false, 0x8b3e, 0x8b3e }, +/* 0x8b3f */ { false, 0x8b3f, 0x8b3f }, +/* 0x8b40 */ { false, 0x8b40, 0x8b40 }, +/* 0x8b41 */ { false, 0x8b41, 0x8b41 }, +/* 0x8b42 */ { false, 0x8b42, 0x8b42 }, +/* 0x8b43 */ { false, 0x8b43, 0x8b43 }, +/* 0x8b44 */ { false, 0x8b44, 0x8b44 }, +/* 0x8b45 */ { false, 0x8b45, 0x8b45 }, +/* 0x8b46 */ { false, 0x8b46, 0x8b46 }, +/* 0x8b47 */ { false, 0x8b47, 0x8b47 }, +/* 0x8b48 */ { false, 0x8b48, 0x8b48 }, +/* 0x8b49 */ { false, 0x8b49, 0x8b49 }, +/* 0x8b4a */ { false, 0x8b4a, 0x8b4a }, +/* 0x8b4b */ { false, 0x8b4b, 0x8b4b }, +/* 0x8b4c */ { false, 0x8b4c, 0x8b4c }, +/* 0x8b4d */ { false, 0x8b4d, 0x8b4d }, +/* 0x8b4e */ { false, 0x8b4e, 0x8b4e }, +/* 0x8b4f */ { false, 0x8b4f, 0x8b4f }, +/* 0x8b50 */ { false, 0x8b50, 0x8b50 }, +/* 0x8b51 */ { false, 0x8b51, 0x8b51 }, +/* 0x8b52 */ { false, 0x8b52, 0x8b52 }, +/* 0x8b53 */ { false, 0x8b53, 0x8b53 }, +/* 0x8b54 */ { false, 0x8b54, 0x8b54 }, +/* 0x8b55 */ { false, 0x8b55, 0x8b55 }, +/* 0x8b56 */ { false, 0x8b56, 0x8b56 }, +/* 0x8b57 */ { false, 0x8b57, 0x8b57 }, +/* 0x8b58 */ { false, 0x8b58, 0x8b58 }, +/* 0x8b59 */ { false, 0x8b59, 0x8b59 }, +/* 0x8b5a */ { false, 0x8b5a, 0x8b5a }, +/* 0x8b5b */ { false, 0x8b5b, 0x8b5b }, +/* 0x8b5c */ { false, 0x8b5c, 0x8b5c }, +/* 0x8b5d */ { false, 0x8b5d, 0x8b5d }, +/* 0x8b5e */ { false, 0x8b5e, 0x8b5e }, +/* 0x8b5f */ { false, 0x8b5f, 0x8b5f }, +/* 0x8b60 */ { false, 0x8b60, 0x8b60 }, +/* 0x8b61 */ { false, 0x8b61, 0x8b61 }, +/* 0x8b62 */ { false, 0x8b62, 0x8b62 }, +/* 0x8b63 */ { false, 0x8b63, 0x8b63 }, +/* 0x8b64 */ { false, 0x8b64, 0x8b64 }, +/* 0x8b65 */ { false, 0x8b65, 0x8b65 }, +/* 0x8b66 */ { false, 0x8b66, 0x8b66 }, +/* 0x8b67 */ { false, 0x8b67, 0x8b67 }, +/* 0x8b68 */ { false, 0x8b68, 0x8b68 }, +/* 0x8b69 */ { false, 0x8b69, 0x8b69 }, +/* 0x8b6a */ { false, 0x8b6a, 0x8b6a }, +/* 0x8b6b */ { false, 0x8b6b, 0x8b6b }, +/* 0x8b6c */ { false, 0x8b6c, 0x8b6c }, +/* 0x8b6d */ { false, 0x8b6d, 0x8b6d }, +/* 0x8b6e */ { false, 0x8b6e, 0x8b6e }, +/* 0x8b6f */ { false, 0x8b6f, 0x8b6f }, +/* 0x8b70 */ { false, 0x8b70, 0x8b70 }, +/* 0x8b71 */ { false, 0x8b71, 0x8b71 }, +/* 0x8b72 */ { false, 0x8b72, 0x8b72 }, +/* 0x8b73 */ { false, 0x8b73, 0x8b73 }, +/* 0x8b74 */ { false, 0x8b74, 0x8b74 }, +/* 0x8b75 */ { false, 0x8b75, 0x8b75 }, +/* 0x8b76 */ { false, 0x8b76, 0x8b76 }, +/* 0x8b77 */ { false, 0x8b77, 0x8b77 }, +/* 0x8b78 */ { false, 0x8b78, 0x8b78 }, +/* 0x8b79 */ { false, 0x8b79, 0x8b79 }, +/* 0x8b7a */ { false, 0x8b7a, 0x8b7a }, +/* 0x8b7b */ { false, 0x8b7b, 0x8b7b }, +/* 0x8b7c */ { false, 0x8b7c, 0x8b7c }, +/* 0x8b7d */ { false, 0x8b7d, 0x8b7d }, +/* 0x8b7e */ { false, 0x8b7e, 0x8b7e }, +/* 0x8b7f */ { false, 0x8b7f, 0x8b7f }, +/* 0x8b80 */ { false, 0x8b80, 0x8b80 }, +/* 0x8b81 */ { false, 0x8b81, 0x8b81 }, +/* 0x8b82 */ { false, 0x8b82, 0x8b82 }, +/* 0x8b83 */ { false, 0x8b83, 0x8b83 }, +/* 0x8b84 */ { false, 0x8b84, 0x8b84 }, +/* 0x8b85 */ { false, 0x8b85, 0x8b85 }, +/* 0x8b86 */ { false, 0x8b86, 0x8b86 }, +/* 0x8b87 */ { false, 0x8b87, 0x8b87 }, +/* 0x8b88 */ { false, 0x8b88, 0x8b88 }, +/* 0x8b89 */ { false, 0x8b89, 0x8b89 }, +/* 0x8b8a */ { false, 0x8b8a, 0x8b8a }, +/* 0x8b8b */ { false, 0x8b8b, 0x8b8b }, +/* 0x8b8c */ { false, 0x8b8c, 0x8b8c }, +/* 0x8b8d */ { false, 0x8b8d, 0x8b8d }, +/* 0x8b8e */ { false, 0x8b8e, 0x8b8e }, +/* 0x8b8f */ { false, 0x8b8f, 0x8b8f }, +/* 0x8b90 */ { false, 0x8b90, 0x8b90 }, +/* 0x8b91 */ { false, 0x8b91, 0x8b91 }, +/* 0x8b92 */ { false, 0x8b92, 0x8b92 }, +/* 0x8b93 */ { false, 0x8b93, 0x8b93 }, +/* 0x8b94 */ { false, 0x8b94, 0x8b94 }, +/* 0x8b95 */ { false, 0x8b95, 0x8b95 }, +/* 0x8b96 */ { false, 0x8b96, 0x8b96 }, +/* 0x8b97 */ { false, 0x8b97, 0x8b97 }, +/* 0x8b98 */ { false, 0x8b98, 0x8b98 }, +/* 0x8b99 */ { false, 0x8b99, 0x8b99 }, +/* 0x8b9a */ { false, 0x8b9a, 0x8b9a }, +/* 0x8b9b */ { false, 0x8b9b, 0x8b9b }, +/* 0x8b9c */ { false, 0x8b9c, 0x8b9c }, +/* 0x8b9d */ { false, 0x8b9d, 0x8b9d }, +/* 0x8b9e */ { false, 0x8b9e, 0x8b9e }, +/* 0x8b9f */ { false, 0x8b9f, 0x8b9f }, +/* 0x8ba0 */ { false, 0x8ba0, 0x8ba0 }, +/* 0x8ba1 */ { false, 0x8ba1, 0x8ba1 }, +/* 0x8ba2 */ { false, 0x8ba2, 0x8ba2 }, +/* 0x8ba3 */ { false, 0x8ba3, 0x8ba3 }, +/* 0x8ba4 */ { false, 0x8ba4, 0x8ba4 }, +/* 0x8ba5 */ { false, 0x8ba5, 0x8ba5 }, +/* 0x8ba6 */ { false, 0x8ba6, 0x8ba6 }, +/* 0x8ba7 */ { false, 0x8ba7, 0x8ba7 }, +/* 0x8ba8 */ { false, 0x8ba8, 0x8ba8 }, +/* 0x8ba9 */ { false, 0x8ba9, 0x8ba9 }, +/* 0x8baa */ { false, 0x8baa, 0x8baa }, +/* 0x8bab */ { false, 0x8bab, 0x8bab }, +/* 0x8bac */ { false, 0x8bac, 0x8bac }, +/* 0x8bad */ { false, 0x8bad, 0x8bad }, +/* 0x8bae */ { false, 0x8bae, 0x8bae }, +/* 0x8baf */ { false, 0x8baf, 0x8baf }, +/* 0x8bb0 */ { false, 0x8bb0, 0x8bb0 }, +/* 0x8bb1 */ { false, 0x8bb1, 0x8bb1 }, +/* 0x8bb2 */ { false, 0x8bb2, 0x8bb2 }, +/* 0x8bb3 */ { false, 0x8bb3, 0x8bb3 }, +/* 0x8bb4 */ { false, 0x8bb4, 0x8bb4 }, +/* 0x8bb5 */ { false, 0x8bb5, 0x8bb5 }, +/* 0x8bb6 */ { false, 0x8bb6, 0x8bb6 }, +/* 0x8bb7 */ { false, 0x8bb7, 0x8bb7 }, +/* 0x8bb8 */ { false, 0x8bb8, 0x8bb8 }, +/* 0x8bb9 */ { false, 0x8bb9, 0x8bb9 }, +/* 0x8bba */ { false, 0x8bba, 0x8bba }, +/* 0x8bbb */ { false, 0x8bbb, 0x8bbb }, +/* 0x8bbc */ { false, 0x8bbc, 0x8bbc }, +/* 0x8bbd */ { false, 0x8bbd, 0x8bbd }, +/* 0x8bbe */ { false, 0x8bbe, 0x8bbe }, +/* 0x8bbf */ { false, 0x8bbf, 0x8bbf }, +/* 0x8bc0 */ { false, 0x8bc0, 0x8bc0 }, +/* 0x8bc1 */ { false, 0x8bc1, 0x8bc1 }, +/* 0x8bc2 */ { false, 0x8bc2, 0x8bc2 }, +/* 0x8bc3 */ { false, 0x8bc3, 0x8bc3 }, +/* 0x8bc4 */ { false, 0x8bc4, 0x8bc4 }, +/* 0x8bc5 */ { false, 0x8bc5, 0x8bc5 }, +/* 0x8bc6 */ { false, 0x8bc6, 0x8bc6 }, +/* 0x8bc7 */ { false, 0x8bc7, 0x8bc7 }, +/* 0x8bc8 */ { false, 0x8bc8, 0x8bc8 }, +/* 0x8bc9 */ { false, 0x8bc9, 0x8bc9 }, +/* 0x8bca */ { false, 0x8bca, 0x8bca }, +/* 0x8bcb */ { false, 0x8bcb, 0x8bcb }, +/* 0x8bcc */ { false, 0x8bcc, 0x8bcc }, +/* 0x8bcd */ { false, 0x8bcd, 0x8bcd }, +/* 0x8bce */ { false, 0x8bce, 0x8bce }, +/* 0x8bcf */ { false, 0x8bcf, 0x8bcf }, +/* 0x8bd0 */ { false, 0x8bd0, 0x8bd0 }, +/* 0x8bd1 */ { false, 0x8bd1, 0x8bd1 }, +/* 0x8bd2 */ { false, 0x8bd2, 0x8bd2 }, +/* 0x8bd3 */ { false, 0x8bd3, 0x8bd3 }, +/* 0x8bd4 */ { false, 0x8bd4, 0x8bd4 }, +/* 0x8bd5 */ { false, 0x8bd5, 0x8bd5 }, +/* 0x8bd6 */ { false, 0x8bd6, 0x8bd6 }, +/* 0x8bd7 */ { false, 0x8bd7, 0x8bd7 }, +/* 0x8bd8 */ { false, 0x8bd8, 0x8bd8 }, +/* 0x8bd9 */ { false, 0x8bd9, 0x8bd9 }, +/* 0x8bda */ { false, 0x8bda, 0x8bda }, +/* 0x8bdb */ { false, 0x8bdb, 0x8bdb }, +/* 0x8bdc */ { false, 0x8bdc, 0x8bdc }, +/* 0x8bdd */ { false, 0x8bdd, 0x8bdd }, +/* 0x8bde */ { false, 0x8bde, 0x8bde }, +/* 0x8bdf */ { false, 0x8bdf, 0x8bdf }, +/* 0x8be0 */ { false, 0x8be0, 0x8be0 }, +/* 0x8be1 */ { false, 0x8be1, 0x8be1 }, +/* 0x8be2 */ { false, 0x8be2, 0x8be2 }, +/* 0x8be3 */ { false, 0x8be3, 0x8be3 }, +/* 0x8be4 */ { false, 0x8be4, 0x8be4 }, +/* 0x8be5 */ { false, 0x8be5, 0x8be5 }, +/* 0x8be6 */ { false, 0x8be6, 0x8be6 }, +/* 0x8be7 */ { false, 0x8be7, 0x8be7 }, +/* 0x8be8 */ { false, 0x8be8, 0x8be8 }, +/* 0x8be9 */ { false, 0x8be9, 0x8be9 }, +/* 0x8bea */ { false, 0x8bea, 0x8bea }, +/* 0x8beb */ { false, 0x8beb, 0x8beb }, +/* 0x8bec */ { false, 0x8bec, 0x8bec }, +/* 0x8bed */ { false, 0x8bed, 0x8bed }, +/* 0x8bee */ { false, 0x8bee, 0x8bee }, +/* 0x8bef */ { false, 0x8bef, 0x8bef }, +/* 0x8bf0 */ { false, 0x8bf0, 0x8bf0 }, +/* 0x8bf1 */ { false, 0x8bf1, 0x8bf1 }, +/* 0x8bf2 */ { false, 0x8bf2, 0x8bf2 }, +/* 0x8bf3 */ { false, 0x8bf3, 0x8bf3 }, +/* 0x8bf4 */ { false, 0x8bf4, 0x8bf4 }, +/* 0x8bf5 */ { false, 0x8bf5, 0x8bf5 }, +/* 0x8bf6 */ { false, 0x8bf6, 0x8bf6 }, +/* 0x8bf7 */ { false, 0x8bf7, 0x8bf7 }, +/* 0x8bf8 */ { false, 0x8bf8, 0x8bf8 }, +/* 0x8bf9 */ { false, 0x8bf9, 0x8bf9 }, +/* 0x8bfa */ { false, 0x8bfa, 0x8bfa }, +/* 0x8bfb */ { false, 0x8bfb, 0x8bfb }, +/* 0x8bfc */ { false, 0x8bfc, 0x8bfc }, +/* 0x8bfd */ { false, 0x8bfd, 0x8bfd }, +/* 0x8bfe */ { false, 0x8bfe, 0x8bfe }, +/* 0x8bff */ { false, 0x8bff, 0x8bff }, +/* 0x8c00 */ { false, 0x8c00, 0x8c00 }, +/* 0x8c01 */ { false, 0x8c01, 0x8c01 }, +/* 0x8c02 */ { false, 0x8c02, 0x8c02 }, +/* 0x8c03 */ { false, 0x8c03, 0x8c03 }, +/* 0x8c04 */ { false, 0x8c04, 0x8c04 }, +/* 0x8c05 */ { false, 0x8c05, 0x8c05 }, +/* 0x8c06 */ { false, 0x8c06, 0x8c06 }, +/* 0x8c07 */ { false, 0x8c07, 0x8c07 }, +/* 0x8c08 */ { false, 0x8c08, 0x8c08 }, +/* 0x8c09 */ { false, 0x8c09, 0x8c09 }, +/* 0x8c0a */ { false, 0x8c0a, 0x8c0a }, +/* 0x8c0b */ { false, 0x8c0b, 0x8c0b }, +/* 0x8c0c */ { false, 0x8c0c, 0x8c0c }, +/* 0x8c0d */ { false, 0x8c0d, 0x8c0d }, +/* 0x8c0e */ { false, 0x8c0e, 0x8c0e }, +/* 0x8c0f */ { false, 0x8c0f, 0x8c0f }, +/* 0x8c10 */ { false, 0x8c10, 0x8c10 }, +/* 0x8c11 */ { false, 0x8c11, 0x8c11 }, +/* 0x8c12 */ { false, 0x8c12, 0x8c12 }, +/* 0x8c13 */ { false, 0x8c13, 0x8c13 }, +/* 0x8c14 */ { false, 0x8c14, 0x8c14 }, +/* 0x8c15 */ { false, 0x8c15, 0x8c15 }, +/* 0x8c16 */ { false, 0x8c16, 0x8c16 }, +/* 0x8c17 */ { false, 0x8c17, 0x8c17 }, +/* 0x8c18 */ { false, 0x8c18, 0x8c18 }, +/* 0x8c19 */ { false, 0x8c19, 0x8c19 }, +/* 0x8c1a */ { false, 0x8c1a, 0x8c1a }, +/* 0x8c1b */ { false, 0x8c1b, 0x8c1b }, +/* 0x8c1c */ { false, 0x8c1c, 0x8c1c }, +/* 0x8c1d */ { false, 0x8c1d, 0x8c1d }, +/* 0x8c1e */ { false, 0x8c1e, 0x8c1e }, +/* 0x8c1f */ { false, 0x8c1f, 0x8c1f }, +/* 0x8c20 */ { false, 0x8c20, 0x8c20 }, +/* 0x8c21 */ { false, 0x8c21, 0x8c21 }, +/* 0x8c22 */ { false, 0x8c22, 0x8c22 }, +/* 0x8c23 */ { false, 0x8c23, 0x8c23 }, +/* 0x8c24 */ { false, 0x8c24, 0x8c24 }, +/* 0x8c25 */ { false, 0x8c25, 0x8c25 }, +/* 0x8c26 */ { false, 0x8c26, 0x8c26 }, +/* 0x8c27 */ { false, 0x8c27, 0x8c27 }, +/* 0x8c28 */ { false, 0x8c28, 0x8c28 }, +/* 0x8c29 */ { false, 0x8c29, 0x8c29 }, +/* 0x8c2a */ { false, 0x8c2a, 0x8c2a }, +/* 0x8c2b */ { false, 0x8c2b, 0x8c2b }, +/* 0x8c2c */ { false, 0x8c2c, 0x8c2c }, +/* 0x8c2d */ { false, 0x8c2d, 0x8c2d }, +/* 0x8c2e */ { false, 0x8c2e, 0x8c2e }, +/* 0x8c2f */ { false, 0x8c2f, 0x8c2f }, +/* 0x8c30 */ { false, 0x8c30, 0x8c30 }, +/* 0x8c31 */ { false, 0x8c31, 0x8c31 }, +/* 0x8c32 */ { false, 0x8c32, 0x8c32 }, +/* 0x8c33 */ { false, 0x8c33, 0x8c33 }, +/* 0x8c34 */ { false, 0x8c34, 0x8c34 }, +/* 0x8c35 */ { false, 0x8c35, 0x8c35 }, +/* 0x8c36 */ { false, 0x8c36, 0x8c36 }, +/* 0x8c37 */ { false, 0x8c37, 0x8c37 }, +/* 0x8c38 */ { false, 0x8c38, 0x8c38 }, +/* 0x8c39 */ { false, 0x8c39, 0x8c39 }, +/* 0x8c3a */ { false, 0x8c3a, 0x8c3a }, +/* 0x8c3b */ { false, 0x8c3b, 0x8c3b }, +/* 0x8c3c */ { false, 0x8c3c, 0x8c3c }, +/* 0x8c3d */ { false, 0x8c3d, 0x8c3d }, +/* 0x8c3e */ { false, 0x8c3e, 0x8c3e }, +/* 0x8c3f */ { false, 0x8c3f, 0x8c3f }, +/* 0x8c40 */ { false, 0x8c40, 0x8c40 }, +/* 0x8c41 */ { false, 0x8c41, 0x8c41 }, +/* 0x8c42 */ { false, 0x8c42, 0x8c42 }, +/* 0x8c43 */ { false, 0x8c43, 0x8c43 }, +/* 0x8c44 */ { false, 0x8c44, 0x8c44 }, +/* 0x8c45 */ { false, 0x8c45, 0x8c45 }, +/* 0x8c46 */ { false, 0x8c46, 0x8c46 }, +/* 0x8c47 */ { false, 0x8c47, 0x8c47 }, +/* 0x8c48 */ { false, 0x8c48, 0x8c48 }, +/* 0x8c49 */ { false, 0x8c49, 0x8c49 }, +/* 0x8c4a */ { false, 0x8c4a, 0x8c4a }, +/* 0x8c4b */ { false, 0x8c4b, 0x8c4b }, +/* 0x8c4c */ { false, 0x8c4c, 0x8c4c }, +/* 0x8c4d */ { false, 0x8c4d, 0x8c4d }, +/* 0x8c4e */ { false, 0x8c4e, 0x8c4e }, +/* 0x8c4f */ { false, 0x8c4f, 0x8c4f }, +/* 0x8c50 */ { false, 0x8c50, 0x8c50 }, +/* 0x8c51 */ { false, 0x8c51, 0x8c51 }, +/* 0x8c52 */ { false, 0x8c52, 0x8c52 }, +/* 0x8c53 */ { false, 0x8c53, 0x8c53 }, +/* 0x8c54 */ { false, 0x8c54, 0x8c54 }, +/* 0x8c55 */ { false, 0x8c55, 0x8c55 }, +/* 0x8c56 */ { false, 0x8c56, 0x8c56 }, +/* 0x8c57 */ { false, 0x8c57, 0x8c57 }, +/* 0x8c58 */ { false, 0x8c58, 0x8c58 }, +/* 0x8c59 */ { false, 0x8c59, 0x8c59 }, +/* 0x8c5a */ { false, 0x8c5a, 0x8c5a }, +/* 0x8c5b */ { false, 0x8c5b, 0x8c5b }, +/* 0x8c5c */ { false, 0x8c5c, 0x8c5c }, +/* 0x8c5d */ { false, 0x8c5d, 0x8c5d }, +/* 0x8c5e */ { false, 0x8c5e, 0x8c5e }, +/* 0x8c5f */ { false, 0x8c5f, 0x8c5f }, +/* 0x8c60 */ { false, 0x8c60, 0x8c60 }, +/* 0x8c61 */ { false, 0x8c61, 0x8c61 }, +/* 0x8c62 */ { false, 0x8c62, 0x8c62 }, +/* 0x8c63 */ { false, 0x8c63, 0x8c63 }, +/* 0x8c64 */ { false, 0x8c64, 0x8c64 }, +/* 0x8c65 */ { false, 0x8c65, 0x8c65 }, +/* 0x8c66 */ { false, 0x8c66, 0x8c66 }, +/* 0x8c67 */ { false, 0x8c67, 0x8c67 }, +/* 0x8c68 */ { false, 0x8c68, 0x8c68 }, +/* 0x8c69 */ { false, 0x8c69, 0x8c69 }, +/* 0x8c6a */ { false, 0x8c6a, 0x8c6a }, +/* 0x8c6b */ { false, 0x8c6b, 0x8c6b }, +/* 0x8c6c */ { false, 0x8c6c, 0x8c6c }, +/* 0x8c6d */ { false, 0x8c6d, 0x8c6d }, +/* 0x8c6e */ { false, 0x8c6e, 0x8c6e }, +/* 0x8c6f */ { false, 0x8c6f, 0x8c6f }, +/* 0x8c70 */ { false, 0x8c70, 0x8c70 }, +/* 0x8c71 */ { false, 0x8c71, 0x8c71 }, +/* 0x8c72 */ { false, 0x8c72, 0x8c72 }, +/* 0x8c73 */ { false, 0x8c73, 0x8c73 }, +/* 0x8c74 */ { false, 0x8c74, 0x8c74 }, +/* 0x8c75 */ { false, 0x8c75, 0x8c75 }, +/* 0x8c76 */ { false, 0x8c76, 0x8c76 }, +/* 0x8c77 */ { false, 0x8c77, 0x8c77 }, +/* 0x8c78 */ { false, 0x8c78, 0x8c78 }, +/* 0x8c79 */ { false, 0x8c79, 0x8c79 }, +/* 0x8c7a */ { false, 0x8c7a, 0x8c7a }, +/* 0x8c7b */ { false, 0x8c7b, 0x8c7b }, +/* 0x8c7c */ { false, 0x8c7c, 0x8c7c }, +/* 0x8c7d */ { false, 0x8c7d, 0x8c7d }, +/* 0x8c7e */ { false, 0x8c7e, 0x8c7e }, +/* 0x8c7f */ { false, 0x8c7f, 0x8c7f }, +/* 0x8c80 */ { false, 0x8c80, 0x8c80 }, +/* 0x8c81 */ { false, 0x8c81, 0x8c81 }, +/* 0x8c82 */ { false, 0x8c82, 0x8c82 }, +/* 0x8c83 */ { false, 0x8c83, 0x8c83 }, +/* 0x8c84 */ { false, 0x8c84, 0x8c84 }, +/* 0x8c85 */ { false, 0x8c85, 0x8c85 }, +/* 0x8c86 */ { false, 0x8c86, 0x8c86 }, +/* 0x8c87 */ { false, 0x8c87, 0x8c87 }, +/* 0x8c88 */ { false, 0x8c88, 0x8c88 }, +/* 0x8c89 */ { false, 0x8c89, 0x8c89 }, +/* 0x8c8a */ { false, 0x8c8a, 0x8c8a }, +/* 0x8c8b */ { false, 0x8c8b, 0x8c8b }, +/* 0x8c8c */ { false, 0x8c8c, 0x8c8c }, +/* 0x8c8d */ { false, 0x8c8d, 0x8c8d }, +/* 0x8c8e */ { false, 0x8c8e, 0x8c8e }, +/* 0x8c8f */ { false, 0x8c8f, 0x8c8f }, +/* 0x8c90 */ { false, 0x8c90, 0x8c90 }, +/* 0x8c91 */ { false, 0x8c91, 0x8c91 }, +/* 0x8c92 */ { false, 0x8c92, 0x8c92 }, +/* 0x8c93 */ { false, 0x8c93, 0x8c93 }, +/* 0x8c94 */ { false, 0x8c94, 0x8c94 }, +/* 0x8c95 */ { false, 0x8c95, 0x8c95 }, +/* 0x8c96 */ { false, 0x8c96, 0x8c96 }, +/* 0x8c97 */ { false, 0x8c97, 0x8c97 }, +/* 0x8c98 */ { false, 0x8c98, 0x8c98 }, +/* 0x8c99 */ { false, 0x8c99, 0x8c99 }, +/* 0x8c9a */ { false, 0x8c9a, 0x8c9a }, +/* 0x8c9b */ { false, 0x8c9b, 0x8c9b }, +/* 0x8c9c */ { false, 0x8c9c, 0x8c9c }, +/* 0x8c9d */ { false, 0x8c9d, 0x8c9d }, +/* 0x8c9e */ { false, 0x8c9e, 0x8c9e }, +/* 0x8c9f */ { false, 0x8c9f, 0x8c9f }, +/* 0x8ca0 */ { false, 0x8ca0, 0x8ca0 }, +/* 0x8ca1 */ { false, 0x8ca1, 0x8ca1 }, +/* 0x8ca2 */ { false, 0x8ca2, 0x8ca2 }, +/* 0x8ca3 */ { false, 0x8ca3, 0x8ca3 }, +/* 0x8ca4 */ { false, 0x8ca4, 0x8ca4 }, +/* 0x8ca5 */ { false, 0x8ca5, 0x8ca5 }, +/* 0x8ca6 */ { false, 0x8ca6, 0x8ca6 }, +/* 0x8ca7 */ { false, 0x8ca7, 0x8ca7 }, +/* 0x8ca8 */ { false, 0x8ca8, 0x8ca8 }, +/* 0x8ca9 */ { false, 0x8ca9, 0x8ca9 }, +/* 0x8caa */ { false, 0x8caa, 0x8caa }, +/* 0x8cab */ { false, 0x8cab, 0x8cab }, +/* 0x8cac */ { false, 0x8cac, 0x8cac }, +/* 0x8cad */ { false, 0x8cad, 0x8cad }, +/* 0x8cae */ { false, 0x8cae, 0x8cae }, +/* 0x8caf */ { false, 0x8caf, 0x8caf }, +/* 0x8cb0 */ { false, 0x8cb0, 0x8cb0 }, +/* 0x8cb1 */ { false, 0x8cb1, 0x8cb1 }, +/* 0x8cb2 */ { false, 0x8cb2, 0x8cb2 }, +/* 0x8cb3 */ { false, 0x8cb3, 0x8cb3 }, +/* 0x8cb4 */ { false, 0x8cb4, 0x8cb4 }, +/* 0x8cb5 */ { false, 0x8cb5, 0x8cb5 }, +/* 0x8cb6 */ { false, 0x8cb6, 0x8cb6 }, +/* 0x8cb7 */ { false, 0x8cb7, 0x8cb7 }, +/* 0x8cb8 */ { false, 0x8cb8, 0x8cb8 }, +/* 0x8cb9 */ { false, 0x8cb9, 0x8cb9 }, +/* 0x8cba */ { false, 0x8cba, 0x8cba }, +/* 0x8cbb */ { false, 0x8cbb, 0x8cbb }, +/* 0x8cbc */ { false, 0x8cbc, 0x8cbc }, +/* 0x8cbd */ { false, 0x8cbd, 0x8cbd }, +/* 0x8cbe */ { false, 0x8cbe, 0x8cbe }, +/* 0x8cbf */ { false, 0x8cbf, 0x8cbf }, +/* 0x8cc0 */ { false, 0x8cc0, 0x8cc0 }, +/* 0x8cc1 */ { false, 0x8cc1, 0x8cc1 }, +/* 0x8cc2 */ { false, 0x8cc2, 0x8cc2 }, +/* 0x8cc3 */ { false, 0x8cc3, 0x8cc3 }, +/* 0x8cc4 */ { false, 0x8cc4, 0x8cc4 }, +/* 0x8cc5 */ { false, 0x8cc5, 0x8cc5 }, +/* 0x8cc6 */ { false, 0x8cc6, 0x8cc6 }, +/* 0x8cc7 */ { false, 0x8cc7, 0x8cc7 }, +/* 0x8cc8 */ { false, 0x8cc8, 0x8cc8 }, +/* 0x8cc9 */ { false, 0x8cc9, 0x8cc9 }, +/* 0x8cca */ { false, 0x8cca, 0x8cca }, +/* 0x8ccb */ { false, 0x8ccb, 0x8ccb }, +/* 0x8ccc */ { false, 0x8ccc, 0x8ccc }, +/* 0x8ccd */ { false, 0x8ccd, 0x8ccd }, +/* 0x8cce */ { false, 0x8cce, 0x8cce }, +/* 0x8ccf */ { false, 0x8ccf, 0x8ccf }, +/* 0x8cd0 */ { false, 0x8cd0, 0x8cd0 }, +/* 0x8cd1 */ { false, 0x8cd1, 0x8cd1 }, +/* 0x8cd2 */ { false, 0x8cd2, 0x8cd2 }, +/* 0x8cd3 */ { false, 0x8cd3, 0x8cd3 }, +/* 0x8cd4 */ { false, 0x8cd4, 0x8cd4 }, +/* 0x8cd5 */ { false, 0x8cd5, 0x8cd5 }, +/* 0x8cd6 */ { false, 0x8cd6, 0x8cd6 }, +/* 0x8cd7 */ { false, 0x8cd7, 0x8cd7 }, +/* 0x8cd8 */ { false, 0x8cd8, 0x8cd8 }, +/* 0x8cd9 */ { false, 0x8cd9, 0x8cd9 }, +/* 0x8cda */ { false, 0x8cda, 0x8cda }, +/* 0x8cdb */ { false, 0x8cdb, 0x8cdb }, +/* 0x8cdc */ { false, 0x8cdc, 0x8cdc }, +/* 0x8cdd */ { false, 0x8cdd, 0x8cdd }, +/* 0x8cde */ { false, 0x8cde, 0x8cde }, +/* 0x8cdf */ { false, 0x8cdf, 0x8cdf }, +/* 0x8ce0 */ { false, 0x8ce0, 0x8ce0 }, +/* 0x8ce1 */ { false, 0x8ce1, 0x8ce1 }, +/* 0x8ce2 */ { false, 0x8ce2, 0x8ce2 }, +/* 0x8ce3 */ { false, 0x8ce3, 0x8ce3 }, +/* 0x8ce4 */ { false, 0x8ce4, 0x8ce4 }, +/* 0x8ce5 */ { false, 0x8ce5, 0x8ce5 }, +/* 0x8ce6 */ { false, 0x8ce6, 0x8ce6 }, +/* 0x8ce7 */ { false, 0x8ce7, 0x8ce7 }, +/* 0x8ce8 */ { false, 0x8ce8, 0x8ce8 }, +/* 0x8ce9 */ { false, 0x8ce9, 0x8ce9 }, +/* 0x8cea */ { false, 0x8cea, 0x8cea }, +/* 0x8ceb */ { false, 0x8ceb, 0x8ceb }, +/* 0x8cec */ { false, 0x8cec, 0x8cec }, +/* 0x8ced */ { false, 0x8ced, 0x8ced }, +/* 0x8cee */ { false, 0x8cee, 0x8cee }, +/* 0x8cef */ { false, 0x8cef, 0x8cef }, +/* 0x8cf0 */ { false, 0x8cf0, 0x8cf0 }, +/* 0x8cf1 */ { false, 0x8cf1, 0x8cf1 }, +/* 0x8cf2 */ { false, 0x8cf2, 0x8cf2 }, +/* 0x8cf3 */ { false, 0x8cf3, 0x8cf3 }, +/* 0x8cf4 */ { false, 0x8cf4, 0x8cf4 }, +/* 0x8cf5 */ { false, 0x8cf5, 0x8cf5 }, +/* 0x8cf6 */ { false, 0x8cf6, 0x8cf6 }, +/* 0x8cf7 */ { false, 0x8cf7, 0x8cf7 }, +/* 0x8cf8 */ { false, 0x8cf8, 0x8cf8 }, +/* 0x8cf9 */ { false, 0x8cf9, 0x8cf9 }, +/* 0x8cfa */ { false, 0x8cfa, 0x8cfa }, +/* 0x8cfb */ { false, 0x8cfb, 0x8cfb }, +/* 0x8cfc */ { false, 0x8cfc, 0x8cfc }, +/* 0x8cfd */ { false, 0x8cfd, 0x8cfd }, +/* 0x8cfe */ { false, 0x8cfe, 0x8cfe }, +/* 0x8cff */ { false, 0x8cff, 0x8cff }, +/* 0x8d00 */ { false, 0x8d00, 0x8d00 }, +/* 0x8d01 */ { false, 0x8d01, 0x8d01 }, +/* 0x8d02 */ { false, 0x8d02, 0x8d02 }, +/* 0x8d03 */ { false, 0x8d03, 0x8d03 }, +/* 0x8d04 */ { false, 0x8d04, 0x8d04 }, +/* 0x8d05 */ { false, 0x8d05, 0x8d05 }, +/* 0x8d06 */ { false, 0x8d06, 0x8d06 }, +/* 0x8d07 */ { false, 0x8d07, 0x8d07 }, +/* 0x8d08 */ { false, 0x8d08, 0x8d08 }, +/* 0x8d09 */ { false, 0x8d09, 0x8d09 }, +/* 0x8d0a */ { false, 0x8d0a, 0x8d0a }, +/* 0x8d0b */ { false, 0x8d0b, 0x8d0b }, +/* 0x8d0c */ { false, 0x8d0c, 0x8d0c }, +/* 0x8d0d */ { false, 0x8d0d, 0x8d0d }, +/* 0x8d0e */ { false, 0x8d0e, 0x8d0e }, +/* 0x8d0f */ { false, 0x8d0f, 0x8d0f }, +/* 0x8d10 */ { false, 0x8d10, 0x8d10 }, +/* 0x8d11 */ { false, 0x8d11, 0x8d11 }, +/* 0x8d12 */ { false, 0x8d12, 0x8d12 }, +/* 0x8d13 */ { false, 0x8d13, 0x8d13 }, +/* 0x8d14 */ { false, 0x8d14, 0x8d14 }, +/* 0x8d15 */ { false, 0x8d15, 0x8d15 }, +/* 0x8d16 */ { false, 0x8d16, 0x8d16 }, +/* 0x8d17 */ { false, 0x8d17, 0x8d17 }, +/* 0x8d18 */ { false, 0x8d18, 0x8d18 }, +/* 0x8d19 */ { false, 0x8d19, 0x8d19 }, +/* 0x8d1a */ { false, 0x8d1a, 0x8d1a }, +/* 0x8d1b */ { false, 0x8d1b, 0x8d1b }, +/* 0x8d1c */ { false, 0x8d1c, 0x8d1c }, +/* 0x8d1d */ { false, 0x8d1d, 0x8d1d }, +/* 0x8d1e */ { false, 0x8d1e, 0x8d1e }, +/* 0x8d1f */ { false, 0x8d1f, 0x8d1f }, +/* 0x8d20 */ { false, 0x8d20, 0x8d20 }, +/* 0x8d21 */ { false, 0x8d21, 0x8d21 }, +/* 0x8d22 */ { false, 0x8d22, 0x8d22 }, +/* 0x8d23 */ { false, 0x8d23, 0x8d23 }, +/* 0x8d24 */ { false, 0x8d24, 0x8d24 }, +/* 0x8d25 */ { false, 0x8d25, 0x8d25 }, +/* 0x8d26 */ { false, 0x8d26, 0x8d26 }, +/* 0x8d27 */ { false, 0x8d27, 0x8d27 }, +/* 0x8d28 */ { false, 0x8d28, 0x8d28 }, +/* 0x8d29 */ { false, 0x8d29, 0x8d29 }, +/* 0x8d2a */ { false, 0x8d2a, 0x8d2a }, +/* 0x8d2b */ { false, 0x8d2b, 0x8d2b }, +/* 0x8d2c */ { false, 0x8d2c, 0x8d2c }, +/* 0x8d2d */ { false, 0x8d2d, 0x8d2d }, +/* 0x8d2e */ { false, 0x8d2e, 0x8d2e }, +/* 0x8d2f */ { false, 0x8d2f, 0x8d2f }, +/* 0x8d30 */ { false, 0x8d30, 0x8d30 }, +/* 0x8d31 */ { false, 0x8d31, 0x8d31 }, +/* 0x8d32 */ { false, 0x8d32, 0x8d32 }, +/* 0x8d33 */ { false, 0x8d33, 0x8d33 }, +/* 0x8d34 */ { false, 0x8d34, 0x8d34 }, +/* 0x8d35 */ { false, 0x8d35, 0x8d35 }, +/* 0x8d36 */ { false, 0x8d36, 0x8d36 }, +/* 0x8d37 */ { false, 0x8d37, 0x8d37 }, +/* 0x8d38 */ { false, 0x8d38, 0x8d38 }, +/* 0x8d39 */ { false, 0x8d39, 0x8d39 }, +/* 0x8d3a */ { false, 0x8d3a, 0x8d3a }, +/* 0x8d3b */ { false, 0x8d3b, 0x8d3b }, +/* 0x8d3c */ { false, 0x8d3c, 0x8d3c }, +/* 0x8d3d */ { false, 0x8d3d, 0x8d3d }, +/* 0x8d3e */ { false, 0x8d3e, 0x8d3e }, +/* 0x8d3f */ { false, 0x8d3f, 0x8d3f }, +/* 0x8d40 */ { false, 0x8d40, 0x8d40 }, +/* 0x8d41 */ { false, 0x8d41, 0x8d41 }, +/* 0x8d42 */ { false, 0x8d42, 0x8d42 }, +/* 0x8d43 */ { false, 0x8d43, 0x8d43 }, +/* 0x8d44 */ { false, 0x8d44, 0x8d44 }, +/* 0x8d45 */ { false, 0x8d45, 0x8d45 }, +/* 0x8d46 */ { false, 0x8d46, 0x8d46 }, +/* 0x8d47 */ { false, 0x8d47, 0x8d47 }, +/* 0x8d48 */ { false, 0x8d48, 0x8d48 }, +/* 0x8d49 */ { false, 0x8d49, 0x8d49 }, +/* 0x8d4a */ { false, 0x8d4a, 0x8d4a }, +/* 0x8d4b */ { false, 0x8d4b, 0x8d4b }, +/* 0x8d4c */ { false, 0x8d4c, 0x8d4c }, +/* 0x8d4d */ { false, 0x8d4d, 0x8d4d }, +/* 0x8d4e */ { false, 0x8d4e, 0x8d4e }, +/* 0x8d4f */ { false, 0x8d4f, 0x8d4f }, +/* 0x8d50 */ { false, 0x8d50, 0x8d50 }, +/* 0x8d51 */ { false, 0x8d51, 0x8d51 }, +/* 0x8d52 */ { false, 0x8d52, 0x8d52 }, +/* 0x8d53 */ { false, 0x8d53, 0x8d53 }, +/* 0x8d54 */ { false, 0x8d54, 0x8d54 }, +/* 0x8d55 */ { false, 0x8d55, 0x8d55 }, +/* 0x8d56 */ { false, 0x8d56, 0x8d56 }, +/* 0x8d57 */ { false, 0x8d57, 0x8d57 }, +/* 0x8d58 */ { false, 0x8d58, 0x8d58 }, +/* 0x8d59 */ { false, 0x8d59, 0x8d59 }, +/* 0x8d5a */ { false, 0x8d5a, 0x8d5a }, +/* 0x8d5b */ { false, 0x8d5b, 0x8d5b }, +/* 0x8d5c */ { false, 0x8d5c, 0x8d5c }, +/* 0x8d5d */ { false, 0x8d5d, 0x8d5d }, +/* 0x8d5e */ { false, 0x8d5e, 0x8d5e }, +/* 0x8d5f */ { false, 0x8d5f, 0x8d5f }, +/* 0x8d60 */ { false, 0x8d60, 0x8d60 }, +/* 0x8d61 */ { false, 0x8d61, 0x8d61 }, +/* 0x8d62 */ { false, 0x8d62, 0x8d62 }, +/* 0x8d63 */ { false, 0x8d63, 0x8d63 }, +/* 0x8d64 */ { false, 0x8d64, 0x8d64 }, +/* 0x8d65 */ { false, 0x8d65, 0x8d65 }, +/* 0x8d66 */ { false, 0x8d66, 0x8d66 }, +/* 0x8d67 */ { false, 0x8d67, 0x8d67 }, +/* 0x8d68 */ { false, 0x8d68, 0x8d68 }, +/* 0x8d69 */ { false, 0x8d69, 0x8d69 }, +/* 0x8d6a */ { false, 0x8d6a, 0x8d6a }, +/* 0x8d6b */ { false, 0x8d6b, 0x8d6b }, +/* 0x8d6c */ { false, 0x8d6c, 0x8d6c }, +/* 0x8d6d */ { false, 0x8d6d, 0x8d6d }, +/* 0x8d6e */ { false, 0x8d6e, 0x8d6e }, +/* 0x8d6f */ { false, 0x8d6f, 0x8d6f }, +/* 0x8d70 */ { false, 0x8d70, 0x8d70 }, +/* 0x8d71 */ { false, 0x8d71, 0x8d71 }, +/* 0x8d72 */ { false, 0x8d72, 0x8d72 }, +/* 0x8d73 */ { false, 0x8d73, 0x8d73 }, +/* 0x8d74 */ { false, 0x8d74, 0x8d74 }, +/* 0x8d75 */ { false, 0x8d75, 0x8d75 }, +/* 0x8d76 */ { false, 0x8d76, 0x8d76 }, +/* 0x8d77 */ { false, 0x8d77, 0x8d77 }, +/* 0x8d78 */ { false, 0x8d78, 0x8d78 }, +/* 0x8d79 */ { false, 0x8d79, 0x8d79 }, +/* 0x8d7a */ { false, 0x8d7a, 0x8d7a }, +/* 0x8d7b */ { false, 0x8d7b, 0x8d7b }, +/* 0x8d7c */ { false, 0x8d7c, 0x8d7c }, +/* 0x8d7d */ { false, 0x8d7d, 0x8d7d }, +/* 0x8d7e */ { false, 0x8d7e, 0x8d7e }, +/* 0x8d7f */ { false, 0x8d7f, 0x8d7f }, +/* 0x8d80 */ { false, 0x8d80, 0x8d80 }, +/* 0x8d81 */ { false, 0x8d81, 0x8d81 }, +/* 0x8d82 */ { false, 0x8d82, 0x8d82 }, +/* 0x8d83 */ { false, 0x8d83, 0x8d83 }, +/* 0x8d84 */ { false, 0x8d84, 0x8d84 }, +/* 0x8d85 */ { false, 0x8d85, 0x8d85 }, +/* 0x8d86 */ { false, 0x8d86, 0x8d86 }, +/* 0x8d87 */ { false, 0x8d87, 0x8d87 }, +/* 0x8d88 */ { false, 0x8d88, 0x8d88 }, +/* 0x8d89 */ { false, 0x8d89, 0x8d89 }, +/* 0x8d8a */ { false, 0x8d8a, 0x8d8a }, +/* 0x8d8b */ { false, 0x8d8b, 0x8d8b }, +/* 0x8d8c */ { false, 0x8d8c, 0x8d8c }, +/* 0x8d8d */ { false, 0x8d8d, 0x8d8d }, +/* 0x8d8e */ { false, 0x8d8e, 0x8d8e }, +/* 0x8d8f */ { false, 0x8d8f, 0x8d8f }, +/* 0x8d90 */ { false, 0x8d90, 0x8d90 }, +/* 0x8d91 */ { false, 0x8d91, 0x8d91 }, +/* 0x8d92 */ { false, 0x8d92, 0x8d92 }, +/* 0x8d93 */ { false, 0x8d93, 0x8d93 }, +/* 0x8d94 */ { false, 0x8d94, 0x8d94 }, +/* 0x8d95 */ { false, 0x8d95, 0x8d95 }, +/* 0x8d96 */ { false, 0x8d96, 0x8d96 }, +/* 0x8d97 */ { false, 0x8d97, 0x8d97 }, +/* 0x8d98 */ { false, 0x8d98, 0x8d98 }, +/* 0x8d99 */ { false, 0x8d99, 0x8d99 }, +/* 0x8d9a */ { false, 0x8d9a, 0x8d9a }, +/* 0x8d9b */ { false, 0x8d9b, 0x8d9b }, +/* 0x8d9c */ { false, 0x8d9c, 0x8d9c }, +/* 0x8d9d */ { false, 0x8d9d, 0x8d9d }, +/* 0x8d9e */ { false, 0x8d9e, 0x8d9e }, +/* 0x8d9f */ { false, 0x8d9f, 0x8d9f }, +/* 0x8da0 */ { false, 0x8da0, 0x8da0 }, +/* 0x8da1 */ { false, 0x8da1, 0x8da1 }, +/* 0x8da2 */ { false, 0x8da2, 0x8da2 }, +/* 0x8da3 */ { false, 0x8da3, 0x8da3 }, +/* 0x8da4 */ { false, 0x8da4, 0x8da4 }, +/* 0x8da5 */ { false, 0x8da5, 0x8da5 }, +/* 0x8da6 */ { false, 0x8da6, 0x8da6 }, +/* 0x8da7 */ { false, 0x8da7, 0x8da7 }, +/* 0x8da8 */ { false, 0x8da8, 0x8da8 }, +/* 0x8da9 */ { false, 0x8da9, 0x8da9 }, +/* 0x8daa */ { false, 0x8daa, 0x8daa }, +/* 0x8dab */ { false, 0x8dab, 0x8dab }, +/* 0x8dac */ { false, 0x8dac, 0x8dac }, +/* 0x8dad */ { false, 0x8dad, 0x8dad }, +/* 0x8dae */ { false, 0x8dae, 0x8dae }, +/* 0x8daf */ { false, 0x8daf, 0x8daf }, +/* 0x8db0 */ { false, 0x8db0, 0x8db0 }, +/* 0x8db1 */ { false, 0x8db1, 0x8db1 }, +/* 0x8db2 */ { false, 0x8db2, 0x8db2 }, +/* 0x8db3 */ { false, 0x8db3, 0x8db3 }, +/* 0x8db4 */ { false, 0x8db4, 0x8db4 }, +/* 0x8db5 */ { false, 0x8db5, 0x8db5 }, +/* 0x8db6 */ { false, 0x8db6, 0x8db6 }, +/* 0x8db7 */ { false, 0x8db7, 0x8db7 }, +/* 0x8db8 */ { false, 0x8db8, 0x8db8 }, +/* 0x8db9 */ { false, 0x8db9, 0x8db9 }, +/* 0x8dba */ { false, 0x8dba, 0x8dba }, +/* 0x8dbb */ { false, 0x8dbb, 0x8dbb }, +/* 0x8dbc */ { false, 0x8dbc, 0x8dbc }, +/* 0x8dbd */ { false, 0x8dbd, 0x8dbd }, +/* 0x8dbe */ { false, 0x8dbe, 0x8dbe }, +/* 0x8dbf */ { false, 0x8dbf, 0x8dbf }, +/* 0x8dc0 */ { false, 0x8dc0, 0x8dc0 }, +/* 0x8dc1 */ { false, 0x8dc1, 0x8dc1 }, +/* 0x8dc2 */ { false, 0x8dc2, 0x8dc2 }, +/* 0x8dc3 */ { false, 0x8dc3, 0x8dc3 }, +/* 0x8dc4 */ { false, 0x8dc4, 0x8dc4 }, +/* 0x8dc5 */ { false, 0x8dc5, 0x8dc5 }, +/* 0x8dc6 */ { false, 0x8dc6, 0x8dc6 }, +/* 0x8dc7 */ { false, 0x8dc7, 0x8dc7 }, +/* 0x8dc8 */ { false, 0x8dc8, 0x8dc8 }, +/* 0x8dc9 */ { false, 0x8dc9, 0x8dc9 }, +/* 0x8dca */ { false, 0x8dca, 0x8dca }, +/* 0x8dcb */ { false, 0x8dcb, 0x8dcb }, +/* 0x8dcc */ { false, 0x8dcc, 0x8dcc }, +/* 0x8dcd */ { false, 0x8dcd, 0x8dcd }, +/* 0x8dce */ { false, 0x8dce, 0x8dce }, +/* 0x8dcf */ { false, 0x8dcf, 0x8dcf }, +/* 0x8dd0 */ { false, 0x8dd0, 0x8dd0 }, +/* 0x8dd1 */ { false, 0x8dd1, 0x8dd1 }, +/* 0x8dd2 */ { false, 0x8dd2, 0x8dd2 }, +/* 0x8dd3 */ { false, 0x8dd3, 0x8dd3 }, +/* 0x8dd4 */ { false, 0x8dd4, 0x8dd4 }, +/* 0x8dd5 */ { false, 0x8dd5, 0x8dd5 }, +/* 0x8dd6 */ { false, 0x8dd6, 0x8dd6 }, +/* 0x8dd7 */ { false, 0x8dd7, 0x8dd7 }, +/* 0x8dd8 */ { false, 0x8dd8, 0x8dd8 }, +/* 0x8dd9 */ { false, 0x8dd9, 0x8dd9 }, +/* 0x8dda */ { false, 0x8dda, 0x8dda }, +/* 0x8ddb */ { false, 0x8ddb, 0x8ddb }, +/* 0x8ddc */ { false, 0x8ddc, 0x8ddc }, +/* 0x8ddd */ { false, 0x8ddd, 0x8ddd }, +/* 0x8dde */ { false, 0x8dde, 0x8dde }, +/* 0x8ddf */ { false, 0x8ddf, 0x8ddf }, +/* 0x8de0 */ { false, 0x8de0, 0x8de0 }, +/* 0x8de1 */ { false, 0x8de1, 0x8de1 }, +/* 0x8de2 */ { false, 0x8de2, 0x8de2 }, +/* 0x8de3 */ { false, 0x8de3, 0x8de3 }, +/* 0x8de4 */ { false, 0x8de4, 0x8de4 }, +/* 0x8de5 */ { false, 0x8de5, 0x8de5 }, +/* 0x8de6 */ { false, 0x8de6, 0x8de6 }, +/* 0x8de7 */ { false, 0x8de7, 0x8de7 }, +/* 0x8de8 */ { false, 0x8de8, 0x8de8 }, +/* 0x8de9 */ { false, 0x8de9, 0x8de9 }, +/* 0x8dea */ { false, 0x8dea, 0x8dea }, +/* 0x8deb */ { false, 0x8deb, 0x8deb }, +/* 0x8dec */ { false, 0x8dec, 0x8dec }, +/* 0x8ded */ { false, 0x8ded, 0x8ded }, +/* 0x8dee */ { false, 0x8dee, 0x8dee }, +/* 0x8def */ { false, 0x8def, 0x8def }, +/* 0x8df0 */ { false, 0x8df0, 0x8df0 }, +/* 0x8df1 */ { false, 0x8df1, 0x8df1 }, +/* 0x8df2 */ { false, 0x8df2, 0x8df2 }, +/* 0x8df3 */ { false, 0x8df3, 0x8df3 }, +/* 0x8df4 */ { false, 0x8df4, 0x8df4 }, +/* 0x8df5 */ { false, 0x8df5, 0x8df5 }, +/* 0x8df6 */ { false, 0x8df6, 0x8df6 }, +/* 0x8df7 */ { false, 0x8df7, 0x8df7 }, +/* 0x8df8 */ { false, 0x8df8, 0x8df8 }, +/* 0x8df9 */ { false, 0x8df9, 0x8df9 }, +/* 0x8dfa */ { false, 0x8dfa, 0x8dfa }, +/* 0x8dfb */ { false, 0x8dfb, 0x8dfb }, +/* 0x8dfc */ { false, 0x8dfc, 0x8dfc }, +/* 0x8dfd */ { false, 0x8dfd, 0x8dfd }, +/* 0x8dfe */ { false, 0x8dfe, 0x8dfe }, +/* 0x8dff */ { false, 0x8dff, 0x8dff }, +/* 0x8e00 */ { false, 0x8e00, 0x8e00 }, +/* 0x8e01 */ { false, 0x8e01, 0x8e01 }, +/* 0x8e02 */ { false, 0x8e02, 0x8e02 }, +/* 0x8e03 */ { false, 0x8e03, 0x8e03 }, +/* 0x8e04 */ { false, 0x8e04, 0x8e04 }, +/* 0x8e05 */ { false, 0x8e05, 0x8e05 }, +/* 0x8e06 */ { false, 0x8e06, 0x8e06 }, +/* 0x8e07 */ { false, 0x8e07, 0x8e07 }, +/* 0x8e08 */ { false, 0x8e08, 0x8e08 }, +/* 0x8e09 */ { false, 0x8e09, 0x8e09 }, +/* 0x8e0a */ { false, 0x8e0a, 0x8e0a }, +/* 0x8e0b */ { false, 0x8e0b, 0x8e0b }, +/* 0x8e0c */ { false, 0x8e0c, 0x8e0c }, +/* 0x8e0d */ { false, 0x8e0d, 0x8e0d }, +/* 0x8e0e */ { false, 0x8e0e, 0x8e0e }, +/* 0x8e0f */ { false, 0x8e0f, 0x8e0f }, +/* 0x8e10 */ { false, 0x8e10, 0x8e10 }, +/* 0x8e11 */ { false, 0x8e11, 0x8e11 }, +/* 0x8e12 */ { false, 0x8e12, 0x8e12 }, +/* 0x8e13 */ { false, 0x8e13, 0x8e13 }, +/* 0x8e14 */ { false, 0x8e14, 0x8e14 }, +/* 0x8e15 */ { false, 0x8e15, 0x8e15 }, +/* 0x8e16 */ { false, 0x8e16, 0x8e16 }, +/* 0x8e17 */ { false, 0x8e17, 0x8e17 }, +/* 0x8e18 */ { false, 0x8e18, 0x8e18 }, +/* 0x8e19 */ { false, 0x8e19, 0x8e19 }, +/* 0x8e1a */ { false, 0x8e1a, 0x8e1a }, +/* 0x8e1b */ { false, 0x8e1b, 0x8e1b }, +/* 0x8e1c */ { false, 0x8e1c, 0x8e1c }, +/* 0x8e1d */ { false, 0x8e1d, 0x8e1d }, +/* 0x8e1e */ { false, 0x8e1e, 0x8e1e }, +/* 0x8e1f */ { false, 0x8e1f, 0x8e1f }, +/* 0x8e20 */ { false, 0x8e20, 0x8e20 }, +/* 0x8e21 */ { false, 0x8e21, 0x8e21 }, +/* 0x8e22 */ { false, 0x8e22, 0x8e22 }, +/* 0x8e23 */ { false, 0x8e23, 0x8e23 }, +/* 0x8e24 */ { false, 0x8e24, 0x8e24 }, +/* 0x8e25 */ { false, 0x8e25, 0x8e25 }, +/* 0x8e26 */ { false, 0x8e26, 0x8e26 }, +/* 0x8e27 */ { false, 0x8e27, 0x8e27 }, +/* 0x8e28 */ { false, 0x8e28, 0x8e28 }, +/* 0x8e29 */ { false, 0x8e29, 0x8e29 }, +/* 0x8e2a */ { false, 0x8e2a, 0x8e2a }, +/* 0x8e2b */ { false, 0x8e2b, 0x8e2b }, +/* 0x8e2c */ { false, 0x8e2c, 0x8e2c }, +/* 0x8e2d */ { false, 0x8e2d, 0x8e2d }, +/* 0x8e2e */ { false, 0x8e2e, 0x8e2e }, +/* 0x8e2f */ { false, 0x8e2f, 0x8e2f }, +/* 0x8e30 */ { false, 0x8e30, 0x8e30 }, +/* 0x8e31 */ { false, 0x8e31, 0x8e31 }, +/* 0x8e32 */ { false, 0x8e32, 0x8e32 }, +/* 0x8e33 */ { false, 0x8e33, 0x8e33 }, +/* 0x8e34 */ { false, 0x8e34, 0x8e34 }, +/* 0x8e35 */ { false, 0x8e35, 0x8e35 }, +/* 0x8e36 */ { false, 0x8e36, 0x8e36 }, +/* 0x8e37 */ { false, 0x8e37, 0x8e37 }, +/* 0x8e38 */ { false, 0x8e38, 0x8e38 }, +/* 0x8e39 */ { false, 0x8e39, 0x8e39 }, +/* 0x8e3a */ { false, 0x8e3a, 0x8e3a }, +/* 0x8e3b */ { false, 0x8e3b, 0x8e3b }, +/* 0x8e3c */ { false, 0x8e3c, 0x8e3c }, +/* 0x8e3d */ { false, 0x8e3d, 0x8e3d }, +/* 0x8e3e */ { false, 0x8e3e, 0x8e3e }, +/* 0x8e3f */ { false, 0x8e3f, 0x8e3f }, +/* 0x8e40 */ { false, 0x8e40, 0x8e40 }, +/* 0x8e41 */ { false, 0x8e41, 0x8e41 }, +/* 0x8e42 */ { false, 0x8e42, 0x8e42 }, +/* 0x8e43 */ { false, 0x8e43, 0x8e43 }, +/* 0x8e44 */ { false, 0x8e44, 0x8e44 }, +/* 0x8e45 */ { false, 0x8e45, 0x8e45 }, +/* 0x8e46 */ { false, 0x8e46, 0x8e46 }, +/* 0x8e47 */ { false, 0x8e47, 0x8e47 }, +/* 0x8e48 */ { false, 0x8e48, 0x8e48 }, +/* 0x8e49 */ { false, 0x8e49, 0x8e49 }, +/* 0x8e4a */ { false, 0x8e4a, 0x8e4a }, +/* 0x8e4b */ { false, 0x8e4b, 0x8e4b }, +/* 0x8e4c */ { false, 0x8e4c, 0x8e4c }, +/* 0x8e4d */ { false, 0x8e4d, 0x8e4d }, +/* 0x8e4e */ { false, 0x8e4e, 0x8e4e }, +/* 0x8e4f */ { false, 0x8e4f, 0x8e4f }, +/* 0x8e50 */ { false, 0x8e50, 0x8e50 }, +/* 0x8e51 */ { false, 0x8e51, 0x8e51 }, +/* 0x8e52 */ { false, 0x8e52, 0x8e52 }, +/* 0x8e53 */ { false, 0x8e53, 0x8e53 }, +/* 0x8e54 */ { false, 0x8e54, 0x8e54 }, +/* 0x8e55 */ { false, 0x8e55, 0x8e55 }, +/* 0x8e56 */ { false, 0x8e56, 0x8e56 }, +/* 0x8e57 */ { false, 0x8e57, 0x8e57 }, +/* 0x8e58 */ { false, 0x8e58, 0x8e58 }, +/* 0x8e59 */ { false, 0x8e59, 0x8e59 }, +/* 0x8e5a */ { false, 0x8e5a, 0x8e5a }, +/* 0x8e5b */ { false, 0x8e5b, 0x8e5b }, +/* 0x8e5c */ { false, 0x8e5c, 0x8e5c }, +/* 0x8e5d */ { false, 0x8e5d, 0x8e5d }, +/* 0x8e5e */ { false, 0x8e5e, 0x8e5e }, +/* 0x8e5f */ { false, 0x8e5f, 0x8e5f }, +/* 0x8e60 */ { false, 0x8e60, 0x8e60 }, +/* 0x8e61 */ { false, 0x8e61, 0x8e61 }, +/* 0x8e62 */ { false, 0x8e62, 0x8e62 }, +/* 0x8e63 */ { false, 0x8e63, 0x8e63 }, +/* 0x8e64 */ { false, 0x8e64, 0x8e64 }, +/* 0x8e65 */ { false, 0x8e65, 0x8e65 }, +/* 0x8e66 */ { false, 0x8e66, 0x8e66 }, +/* 0x8e67 */ { false, 0x8e67, 0x8e67 }, +/* 0x8e68 */ { false, 0x8e68, 0x8e68 }, +/* 0x8e69 */ { false, 0x8e69, 0x8e69 }, +/* 0x8e6a */ { false, 0x8e6a, 0x8e6a }, +/* 0x8e6b */ { false, 0x8e6b, 0x8e6b }, +/* 0x8e6c */ { false, 0x8e6c, 0x8e6c }, +/* 0x8e6d */ { false, 0x8e6d, 0x8e6d }, +/* 0x8e6e */ { false, 0x8e6e, 0x8e6e }, +/* 0x8e6f */ { false, 0x8e6f, 0x8e6f }, +/* 0x8e70 */ { false, 0x8e70, 0x8e70 }, +/* 0x8e71 */ { false, 0x8e71, 0x8e71 }, +/* 0x8e72 */ { false, 0x8e72, 0x8e72 }, +/* 0x8e73 */ { false, 0x8e73, 0x8e73 }, +/* 0x8e74 */ { false, 0x8e74, 0x8e74 }, +/* 0x8e75 */ { false, 0x8e75, 0x8e75 }, +/* 0x8e76 */ { false, 0x8e76, 0x8e76 }, +/* 0x8e77 */ { false, 0x8e77, 0x8e77 }, +/* 0x8e78 */ { false, 0x8e78, 0x8e78 }, +/* 0x8e79 */ { false, 0x8e79, 0x8e79 }, +/* 0x8e7a */ { false, 0x8e7a, 0x8e7a }, +/* 0x8e7b */ { false, 0x8e7b, 0x8e7b }, +/* 0x8e7c */ { false, 0x8e7c, 0x8e7c }, +/* 0x8e7d */ { false, 0x8e7d, 0x8e7d }, +/* 0x8e7e */ { false, 0x8e7e, 0x8e7e }, +/* 0x8e7f */ { false, 0x8e7f, 0x8e7f }, +/* 0x8e80 */ { false, 0x8e80, 0x8e80 }, +/* 0x8e81 */ { false, 0x8e81, 0x8e81 }, +/* 0x8e82 */ { false, 0x8e82, 0x8e82 }, +/* 0x8e83 */ { false, 0x8e83, 0x8e83 }, +/* 0x8e84 */ { false, 0x8e84, 0x8e84 }, +/* 0x8e85 */ { false, 0x8e85, 0x8e85 }, +/* 0x8e86 */ { false, 0x8e86, 0x8e86 }, +/* 0x8e87 */ { false, 0x8e87, 0x8e87 }, +/* 0x8e88 */ { false, 0x8e88, 0x8e88 }, +/* 0x8e89 */ { false, 0x8e89, 0x8e89 }, +/* 0x8e8a */ { false, 0x8e8a, 0x8e8a }, +/* 0x8e8b */ { false, 0x8e8b, 0x8e8b }, +/* 0x8e8c */ { false, 0x8e8c, 0x8e8c }, +/* 0x8e8d */ { false, 0x8e8d, 0x8e8d }, +/* 0x8e8e */ { false, 0x8e8e, 0x8e8e }, +/* 0x8e8f */ { false, 0x8e8f, 0x8e8f }, +/* 0x8e90 */ { false, 0x8e90, 0x8e90 }, +/* 0x8e91 */ { false, 0x8e91, 0x8e91 }, +/* 0x8e92 */ { false, 0x8e92, 0x8e92 }, +/* 0x8e93 */ { false, 0x8e93, 0x8e93 }, +/* 0x8e94 */ { false, 0x8e94, 0x8e94 }, +/* 0x8e95 */ { false, 0x8e95, 0x8e95 }, +/* 0x8e96 */ { false, 0x8e96, 0x8e96 }, +/* 0x8e97 */ { false, 0x8e97, 0x8e97 }, +/* 0x8e98 */ { false, 0x8e98, 0x8e98 }, +/* 0x8e99 */ { false, 0x8e99, 0x8e99 }, +/* 0x8e9a */ { false, 0x8e9a, 0x8e9a }, +/* 0x8e9b */ { false, 0x8e9b, 0x8e9b }, +/* 0x8e9c */ { false, 0x8e9c, 0x8e9c }, +/* 0x8e9d */ { false, 0x8e9d, 0x8e9d }, +/* 0x8e9e */ { false, 0x8e9e, 0x8e9e }, +/* 0x8e9f */ { false, 0x8e9f, 0x8e9f }, +/* 0x8ea0 */ { false, 0x8ea0, 0x8ea0 }, +/* 0x8ea1 */ { false, 0x8ea1, 0x8ea1 }, +/* 0x8ea2 */ { false, 0x8ea2, 0x8ea2 }, +/* 0x8ea3 */ { false, 0x8ea3, 0x8ea3 }, +/* 0x8ea4 */ { false, 0x8ea4, 0x8ea4 }, +/* 0x8ea5 */ { false, 0x8ea5, 0x8ea5 }, +/* 0x8ea6 */ { false, 0x8ea6, 0x8ea6 }, +/* 0x8ea7 */ { false, 0x8ea7, 0x8ea7 }, +/* 0x8ea8 */ { false, 0x8ea8, 0x8ea8 }, +/* 0x8ea9 */ { false, 0x8ea9, 0x8ea9 }, +/* 0x8eaa */ { false, 0x8eaa, 0x8eaa }, +/* 0x8eab */ { false, 0x8eab, 0x8eab }, +/* 0x8eac */ { false, 0x8eac, 0x8eac }, +/* 0x8ead */ { false, 0x8ead, 0x8ead }, +/* 0x8eae */ { false, 0x8eae, 0x8eae }, +/* 0x8eaf */ { false, 0x8eaf, 0x8eaf }, +/* 0x8eb0 */ { false, 0x8eb0, 0x8eb0 }, +/* 0x8eb1 */ { false, 0x8eb1, 0x8eb1 }, +/* 0x8eb2 */ { false, 0x8eb2, 0x8eb2 }, +/* 0x8eb3 */ { false, 0x8eb3, 0x8eb3 }, +/* 0x8eb4 */ { false, 0x8eb4, 0x8eb4 }, +/* 0x8eb5 */ { false, 0x8eb5, 0x8eb5 }, +/* 0x8eb6 */ { false, 0x8eb6, 0x8eb6 }, +/* 0x8eb7 */ { false, 0x8eb7, 0x8eb7 }, +/* 0x8eb8 */ { false, 0x8eb8, 0x8eb8 }, +/* 0x8eb9 */ { false, 0x8eb9, 0x8eb9 }, +/* 0x8eba */ { false, 0x8eba, 0x8eba }, +/* 0x8ebb */ { false, 0x8ebb, 0x8ebb }, +/* 0x8ebc */ { false, 0x8ebc, 0x8ebc }, +/* 0x8ebd */ { false, 0x8ebd, 0x8ebd }, +/* 0x8ebe */ { false, 0x8ebe, 0x8ebe }, +/* 0x8ebf */ { false, 0x8ebf, 0x8ebf }, +/* 0x8ec0 */ { false, 0x8ec0, 0x8ec0 }, +/* 0x8ec1 */ { false, 0x8ec1, 0x8ec1 }, +/* 0x8ec2 */ { false, 0x8ec2, 0x8ec2 }, +/* 0x8ec3 */ { false, 0x8ec3, 0x8ec3 }, +/* 0x8ec4 */ { false, 0x8ec4, 0x8ec4 }, +/* 0x8ec5 */ { false, 0x8ec5, 0x8ec5 }, +/* 0x8ec6 */ { false, 0x8ec6, 0x8ec6 }, +/* 0x8ec7 */ { false, 0x8ec7, 0x8ec7 }, +/* 0x8ec8 */ { false, 0x8ec8, 0x8ec8 }, +/* 0x8ec9 */ { false, 0x8ec9, 0x8ec9 }, +/* 0x8eca */ { false, 0x8eca, 0x8eca }, +/* 0x8ecb */ { false, 0x8ecb, 0x8ecb }, +/* 0x8ecc */ { false, 0x8ecc, 0x8ecc }, +/* 0x8ecd */ { false, 0x8ecd, 0x8ecd }, +/* 0x8ece */ { false, 0x8ece, 0x8ece }, +/* 0x8ecf */ { false, 0x8ecf, 0x8ecf }, +/* 0x8ed0 */ { false, 0x8ed0, 0x8ed0 }, +/* 0x8ed1 */ { false, 0x8ed1, 0x8ed1 }, +/* 0x8ed2 */ { false, 0x8ed2, 0x8ed2 }, +/* 0x8ed3 */ { false, 0x8ed3, 0x8ed3 }, +/* 0x8ed4 */ { false, 0x8ed4, 0x8ed4 }, +/* 0x8ed5 */ { false, 0x8ed5, 0x8ed5 }, +/* 0x8ed6 */ { false, 0x8ed6, 0x8ed6 }, +/* 0x8ed7 */ { false, 0x8ed7, 0x8ed7 }, +/* 0x8ed8 */ { false, 0x8ed8, 0x8ed8 }, +/* 0x8ed9 */ { false, 0x8ed9, 0x8ed9 }, +/* 0x8eda */ { false, 0x8eda, 0x8eda }, +/* 0x8edb */ { false, 0x8edb, 0x8edb }, +/* 0x8edc */ { false, 0x8edc, 0x8edc }, +/* 0x8edd */ { false, 0x8edd, 0x8edd }, +/* 0x8ede */ { false, 0x8ede, 0x8ede }, +/* 0x8edf */ { false, 0x8edf, 0x8edf }, +/* 0x8ee0 */ { false, 0x8ee0, 0x8ee0 }, +/* 0x8ee1 */ { false, 0x8ee1, 0x8ee1 }, +/* 0x8ee2 */ { false, 0x8ee2, 0x8ee2 }, +/* 0x8ee3 */ { false, 0x8ee3, 0x8ee3 }, +/* 0x8ee4 */ { false, 0x8ee4, 0x8ee4 }, +/* 0x8ee5 */ { false, 0x8ee5, 0x8ee5 }, +/* 0x8ee6 */ { false, 0x8ee6, 0x8ee6 }, +/* 0x8ee7 */ { false, 0x8ee7, 0x8ee7 }, +/* 0x8ee8 */ { false, 0x8ee8, 0x8ee8 }, +/* 0x8ee9 */ { false, 0x8ee9, 0x8ee9 }, +/* 0x8eea */ { false, 0x8eea, 0x8eea }, +/* 0x8eeb */ { false, 0x8eeb, 0x8eeb }, +/* 0x8eec */ { false, 0x8eec, 0x8eec }, +/* 0x8eed */ { false, 0x8eed, 0x8eed }, +/* 0x8eee */ { false, 0x8eee, 0x8eee }, +/* 0x8eef */ { false, 0x8eef, 0x8eef }, +/* 0x8ef0 */ { false, 0x8ef0, 0x8ef0 }, +/* 0x8ef1 */ { false, 0x8ef1, 0x8ef1 }, +/* 0x8ef2 */ { false, 0x8ef2, 0x8ef2 }, +/* 0x8ef3 */ { false, 0x8ef3, 0x8ef3 }, +/* 0x8ef4 */ { false, 0x8ef4, 0x8ef4 }, +/* 0x8ef5 */ { false, 0x8ef5, 0x8ef5 }, +/* 0x8ef6 */ { false, 0x8ef6, 0x8ef6 }, +/* 0x8ef7 */ { false, 0x8ef7, 0x8ef7 }, +/* 0x8ef8 */ { false, 0x8ef8, 0x8ef8 }, +/* 0x8ef9 */ { false, 0x8ef9, 0x8ef9 }, +/* 0x8efa */ { false, 0x8efa, 0x8efa }, +/* 0x8efb */ { false, 0x8efb, 0x8efb }, +/* 0x8efc */ { false, 0x8efc, 0x8efc }, +/* 0x8efd */ { false, 0x8efd, 0x8efd }, +/* 0x8efe */ { false, 0x8efe, 0x8efe }, +/* 0x8eff */ { false, 0x8eff, 0x8eff }, +/* 0x8f00 */ { false, 0x8f00, 0x8f00 }, +/* 0x8f01 */ { false, 0x8f01, 0x8f01 }, +/* 0x8f02 */ { false, 0x8f02, 0x8f02 }, +/* 0x8f03 */ { false, 0x8f03, 0x8f03 }, +/* 0x8f04 */ { false, 0x8f04, 0x8f04 }, +/* 0x8f05 */ { false, 0x8f05, 0x8f05 }, +/* 0x8f06 */ { false, 0x8f06, 0x8f06 }, +/* 0x8f07 */ { false, 0x8f07, 0x8f07 }, +/* 0x8f08 */ { false, 0x8f08, 0x8f08 }, +/* 0x8f09 */ { false, 0x8f09, 0x8f09 }, +/* 0x8f0a */ { false, 0x8f0a, 0x8f0a }, +/* 0x8f0b */ { false, 0x8f0b, 0x8f0b }, +/* 0x8f0c */ { false, 0x8f0c, 0x8f0c }, +/* 0x8f0d */ { false, 0x8f0d, 0x8f0d }, +/* 0x8f0e */ { false, 0x8f0e, 0x8f0e }, +/* 0x8f0f */ { false, 0x8f0f, 0x8f0f }, +/* 0x8f10 */ { false, 0x8f10, 0x8f10 }, +/* 0x8f11 */ { false, 0x8f11, 0x8f11 }, +/* 0x8f12 */ { false, 0x8f12, 0x8f12 }, +/* 0x8f13 */ { false, 0x8f13, 0x8f13 }, +/* 0x8f14 */ { false, 0x8f14, 0x8f14 }, +/* 0x8f15 */ { false, 0x8f15, 0x8f15 }, +/* 0x8f16 */ { false, 0x8f16, 0x8f16 }, +/* 0x8f17 */ { false, 0x8f17, 0x8f17 }, +/* 0x8f18 */ { false, 0x8f18, 0x8f18 }, +/* 0x8f19 */ { false, 0x8f19, 0x8f19 }, +/* 0x8f1a */ { false, 0x8f1a, 0x8f1a }, +/* 0x8f1b */ { false, 0x8f1b, 0x8f1b }, +/* 0x8f1c */ { false, 0x8f1c, 0x8f1c }, +/* 0x8f1d */ { false, 0x8f1d, 0x8f1d }, +/* 0x8f1e */ { false, 0x8f1e, 0x8f1e }, +/* 0x8f1f */ { false, 0x8f1f, 0x8f1f }, +/* 0x8f20 */ { false, 0x8f20, 0x8f20 }, +/* 0x8f21 */ { false, 0x8f21, 0x8f21 }, +/* 0x8f22 */ { false, 0x8f22, 0x8f22 }, +/* 0x8f23 */ { false, 0x8f23, 0x8f23 }, +/* 0x8f24 */ { false, 0x8f24, 0x8f24 }, +/* 0x8f25 */ { false, 0x8f25, 0x8f25 }, +/* 0x8f26 */ { false, 0x8f26, 0x8f26 }, +/* 0x8f27 */ { false, 0x8f27, 0x8f27 }, +/* 0x8f28 */ { false, 0x8f28, 0x8f28 }, +/* 0x8f29 */ { false, 0x8f29, 0x8f29 }, +/* 0x8f2a */ { false, 0x8f2a, 0x8f2a }, +/* 0x8f2b */ { false, 0x8f2b, 0x8f2b }, +/* 0x8f2c */ { false, 0x8f2c, 0x8f2c }, +/* 0x8f2d */ { false, 0x8f2d, 0x8f2d }, +/* 0x8f2e */ { false, 0x8f2e, 0x8f2e }, +/* 0x8f2f */ { false, 0x8f2f, 0x8f2f }, +/* 0x8f30 */ { false, 0x8f30, 0x8f30 }, +/* 0x8f31 */ { false, 0x8f31, 0x8f31 }, +/* 0x8f32 */ { false, 0x8f32, 0x8f32 }, +/* 0x8f33 */ { false, 0x8f33, 0x8f33 }, +/* 0x8f34 */ { false, 0x8f34, 0x8f34 }, +/* 0x8f35 */ { false, 0x8f35, 0x8f35 }, +/* 0x8f36 */ { false, 0x8f36, 0x8f36 }, +/* 0x8f37 */ { false, 0x8f37, 0x8f37 }, +/* 0x8f38 */ { false, 0x8f38, 0x8f38 }, +/* 0x8f39 */ { false, 0x8f39, 0x8f39 }, +/* 0x8f3a */ { false, 0x8f3a, 0x8f3a }, +/* 0x8f3b */ { false, 0x8f3b, 0x8f3b }, +/* 0x8f3c */ { false, 0x8f3c, 0x8f3c }, +/* 0x8f3d */ { false, 0x8f3d, 0x8f3d }, +/* 0x8f3e */ { false, 0x8f3e, 0x8f3e }, +/* 0x8f3f */ { false, 0x8f3f, 0x8f3f }, +/* 0x8f40 */ { false, 0x8f40, 0x8f40 }, +/* 0x8f41 */ { false, 0x8f41, 0x8f41 }, +/* 0x8f42 */ { false, 0x8f42, 0x8f42 }, +/* 0x8f43 */ { false, 0x8f43, 0x8f43 }, +/* 0x8f44 */ { false, 0x8f44, 0x8f44 }, +/* 0x8f45 */ { false, 0x8f45, 0x8f45 }, +/* 0x8f46 */ { false, 0x8f46, 0x8f46 }, +/* 0x8f47 */ { false, 0x8f47, 0x8f47 }, +/* 0x8f48 */ { false, 0x8f48, 0x8f48 }, +/* 0x8f49 */ { false, 0x8f49, 0x8f49 }, +/* 0x8f4a */ { false, 0x8f4a, 0x8f4a }, +/* 0x8f4b */ { false, 0x8f4b, 0x8f4b }, +/* 0x8f4c */ { false, 0x8f4c, 0x8f4c }, +/* 0x8f4d */ { false, 0x8f4d, 0x8f4d }, +/* 0x8f4e */ { false, 0x8f4e, 0x8f4e }, +/* 0x8f4f */ { false, 0x8f4f, 0x8f4f }, +/* 0x8f50 */ { false, 0x8f50, 0x8f50 }, +/* 0x8f51 */ { false, 0x8f51, 0x8f51 }, +/* 0x8f52 */ { false, 0x8f52, 0x8f52 }, +/* 0x8f53 */ { false, 0x8f53, 0x8f53 }, +/* 0x8f54 */ { false, 0x8f54, 0x8f54 }, +/* 0x8f55 */ { false, 0x8f55, 0x8f55 }, +/* 0x8f56 */ { false, 0x8f56, 0x8f56 }, +/* 0x8f57 */ { false, 0x8f57, 0x8f57 }, +/* 0x8f58 */ { false, 0x8f58, 0x8f58 }, +/* 0x8f59 */ { false, 0x8f59, 0x8f59 }, +/* 0x8f5a */ { false, 0x8f5a, 0x8f5a }, +/* 0x8f5b */ { false, 0x8f5b, 0x8f5b }, +/* 0x8f5c */ { false, 0x8f5c, 0x8f5c }, +/* 0x8f5d */ { false, 0x8f5d, 0x8f5d }, +/* 0x8f5e */ { false, 0x8f5e, 0x8f5e }, +/* 0x8f5f */ { false, 0x8f5f, 0x8f5f }, +/* 0x8f60 */ { false, 0x8f60, 0x8f60 }, +/* 0x8f61 */ { false, 0x8f61, 0x8f61 }, +/* 0x8f62 */ { false, 0x8f62, 0x8f62 }, +/* 0x8f63 */ { false, 0x8f63, 0x8f63 }, +/* 0x8f64 */ { false, 0x8f64, 0x8f64 }, +/* 0x8f65 */ { false, 0x8f65, 0x8f65 }, +/* 0x8f66 */ { false, 0x8f66, 0x8f66 }, +/* 0x8f67 */ { false, 0x8f67, 0x8f67 }, +/* 0x8f68 */ { false, 0x8f68, 0x8f68 }, +/* 0x8f69 */ { false, 0x8f69, 0x8f69 }, +/* 0x8f6a */ { false, 0x8f6a, 0x8f6a }, +/* 0x8f6b */ { false, 0x8f6b, 0x8f6b }, +/* 0x8f6c */ { false, 0x8f6c, 0x8f6c }, +/* 0x8f6d */ { false, 0x8f6d, 0x8f6d }, +/* 0x8f6e */ { false, 0x8f6e, 0x8f6e }, +/* 0x8f6f */ { false, 0x8f6f, 0x8f6f }, +/* 0x8f70 */ { false, 0x8f70, 0x8f70 }, +/* 0x8f71 */ { false, 0x8f71, 0x8f71 }, +/* 0x8f72 */ { false, 0x8f72, 0x8f72 }, +/* 0x8f73 */ { false, 0x8f73, 0x8f73 }, +/* 0x8f74 */ { false, 0x8f74, 0x8f74 }, +/* 0x8f75 */ { false, 0x8f75, 0x8f75 }, +/* 0x8f76 */ { false, 0x8f76, 0x8f76 }, +/* 0x8f77 */ { false, 0x8f77, 0x8f77 }, +/* 0x8f78 */ { false, 0x8f78, 0x8f78 }, +/* 0x8f79 */ { false, 0x8f79, 0x8f79 }, +/* 0x8f7a */ { false, 0x8f7a, 0x8f7a }, +/* 0x8f7b */ { false, 0x8f7b, 0x8f7b }, +/* 0x8f7c */ { false, 0x8f7c, 0x8f7c }, +/* 0x8f7d */ { false, 0x8f7d, 0x8f7d }, +/* 0x8f7e */ { false, 0x8f7e, 0x8f7e }, +/* 0x8f7f */ { false, 0x8f7f, 0x8f7f }, +/* 0x8f80 */ { false, 0x8f80, 0x8f80 }, +/* 0x8f81 */ { false, 0x8f81, 0x8f81 }, +/* 0x8f82 */ { false, 0x8f82, 0x8f82 }, +/* 0x8f83 */ { false, 0x8f83, 0x8f83 }, +/* 0x8f84 */ { false, 0x8f84, 0x8f84 }, +/* 0x8f85 */ { false, 0x8f85, 0x8f85 }, +/* 0x8f86 */ { false, 0x8f86, 0x8f86 }, +/* 0x8f87 */ { false, 0x8f87, 0x8f87 }, +/* 0x8f88 */ { false, 0x8f88, 0x8f88 }, +/* 0x8f89 */ { false, 0x8f89, 0x8f89 }, +/* 0x8f8a */ { false, 0x8f8a, 0x8f8a }, +/* 0x8f8b */ { false, 0x8f8b, 0x8f8b }, +/* 0x8f8c */ { false, 0x8f8c, 0x8f8c }, +/* 0x8f8d */ { false, 0x8f8d, 0x8f8d }, +/* 0x8f8e */ { false, 0x8f8e, 0x8f8e }, +/* 0x8f8f */ { false, 0x8f8f, 0x8f8f }, +/* 0x8f90 */ { false, 0x8f90, 0x8f90 }, +/* 0x8f91 */ { false, 0x8f91, 0x8f91 }, +/* 0x8f92 */ { false, 0x8f92, 0x8f92 }, +/* 0x8f93 */ { false, 0x8f93, 0x8f93 }, +/* 0x8f94 */ { false, 0x8f94, 0x8f94 }, +/* 0x8f95 */ { false, 0x8f95, 0x8f95 }, +/* 0x8f96 */ { false, 0x8f96, 0x8f96 }, +/* 0x8f97 */ { false, 0x8f97, 0x8f97 }, +/* 0x8f98 */ { false, 0x8f98, 0x8f98 }, +/* 0x8f99 */ { false, 0x8f99, 0x8f99 }, +/* 0x8f9a */ { false, 0x8f9a, 0x8f9a }, +/* 0x8f9b */ { false, 0x8f9b, 0x8f9b }, +/* 0x8f9c */ { false, 0x8f9c, 0x8f9c }, +/* 0x8f9d */ { false, 0x8f9d, 0x8f9d }, +/* 0x8f9e */ { false, 0x8f9e, 0x8f9e }, +/* 0x8f9f */ { false, 0x8f9f, 0x8f9f }, +/* 0x8fa0 */ { false, 0x8fa0, 0x8fa0 }, +/* 0x8fa1 */ { false, 0x8fa1, 0x8fa1 }, +/* 0x8fa2 */ { false, 0x8fa2, 0x8fa2 }, +/* 0x8fa3 */ { false, 0x8fa3, 0x8fa3 }, +/* 0x8fa4 */ { false, 0x8fa4, 0x8fa4 }, +/* 0x8fa5 */ { false, 0x8fa5, 0x8fa5 }, +/* 0x8fa6 */ { false, 0x8fa6, 0x8fa6 }, +/* 0x8fa7 */ { false, 0x8fa7, 0x8fa7 }, +/* 0x8fa8 */ { false, 0x8fa8, 0x8fa8 }, +/* 0x8fa9 */ { false, 0x8fa9, 0x8fa9 }, +/* 0x8faa */ { false, 0x8faa, 0x8faa }, +/* 0x8fab */ { false, 0x8fab, 0x8fab }, +/* 0x8fac */ { false, 0x8fac, 0x8fac }, +/* 0x8fad */ { false, 0x8fad, 0x8fad }, +/* 0x8fae */ { false, 0x8fae, 0x8fae }, +/* 0x8faf */ { false, 0x8faf, 0x8faf }, +/* 0x8fb0 */ { false, 0x8fb0, 0x8fb0 }, +/* 0x8fb1 */ { false, 0x8fb1, 0x8fb1 }, +/* 0x8fb2 */ { false, 0x8fb2, 0x8fb2 }, +/* 0x8fb3 */ { false, 0x8fb3, 0x8fb3 }, +/* 0x8fb4 */ { false, 0x8fb4, 0x8fb4 }, +/* 0x8fb5 */ { false, 0x8fb5, 0x8fb5 }, +/* 0x8fb6 */ { false, 0x8fb6, 0x8fb6 }, +/* 0x8fb7 */ { false, 0x8fb7, 0x8fb7 }, +/* 0x8fb8 */ { false, 0x8fb8, 0x8fb8 }, +/* 0x8fb9 */ { false, 0x8fb9, 0x8fb9 }, +/* 0x8fba */ { false, 0x8fba, 0x8fba }, +/* 0x8fbb */ { false, 0x8fbb, 0x8fbb }, +/* 0x8fbc */ { false, 0x8fbc, 0x8fbc }, +/* 0x8fbd */ { false, 0x8fbd, 0x8fbd }, +/* 0x8fbe */ { false, 0x8fbe, 0x8fbe }, +/* 0x8fbf */ { false, 0x8fbf, 0x8fbf }, +/* 0x8fc0 */ { false, 0x8fc0, 0x8fc0 }, +/* 0x8fc1 */ { false, 0x8fc1, 0x8fc1 }, +/* 0x8fc2 */ { false, 0x8fc2, 0x8fc2 }, +/* 0x8fc3 */ { false, 0x8fc3, 0x8fc3 }, +/* 0x8fc4 */ { false, 0x8fc4, 0x8fc4 }, +/* 0x8fc5 */ { false, 0x8fc5, 0x8fc5 }, +/* 0x8fc6 */ { false, 0x8fc6, 0x8fc6 }, +/* 0x8fc7 */ { false, 0x8fc7, 0x8fc7 }, +/* 0x8fc8 */ { false, 0x8fc8, 0x8fc8 }, +/* 0x8fc9 */ { false, 0x8fc9, 0x8fc9 }, +/* 0x8fca */ { false, 0x8fca, 0x8fca }, +/* 0x8fcb */ { false, 0x8fcb, 0x8fcb }, +/* 0x8fcc */ { false, 0x8fcc, 0x8fcc }, +/* 0x8fcd */ { false, 0x8fcd, 0x8fcd }, +/* 0x8fce */ { false, 0x8fce, 0x8fce }, +/* 0x8fcf */ { false, 0x8fcf, 0x8fcf }, +/* 0x8fd0 */ { false, 0x8fd0, 0x8fd0 }, +/* 0x8fd1 */ { false, 0x8fd1, 0x8fd1 }, +/* 0x8fd2 */ { false, 0x8fd2, 0x8fd2 }, +/* 0x8fd3 */ { false, 0x8fd3, 0x8fd3 }, +/* 0x8fd4 */ { false, 0x8fd4, 0x8fd4 }, +/* 0x8fd5 */ { false, 0x8fd5, 0x8fd5 }, +/* 0x8fd6 */ { false, 0x8fd6, 0x8fd6 }, +/* 0x8fd7 */ { false, 0x8fd7, 0x8fd7 }, +/* 0x8fd8 */ { false, 0x8fd8, 0x8fd8 }, +/* 0x8fd9 */ { false, 0x8fd9, 0x8fd9 }, +/* 0x8fda */ { false, 0x8fda, 0x8fda }, +/* 0x8fdb */ { false, 0x8fdb, 0x8fdb }, +/* 0x8fdc */ { false, 0x8fdc, 0x8fdc }, +/* 0x8fdd */ { false, 0x8fdd, 0x8fdd }, +/* 0x8fde */ { false, 0x8fde, 0x8fde }, +/* 0x8fdf */ { false, 0x8fdf, 0x8fdf }, +/* 0x8fe0 */ { false, 0x8fe0, 0x8fe0 }, +/* 0x8fe1 */ { false, 0x8fe1, 0x8fe1 }, +/* 0x8fe2 */ { false, 0x8fe2, 0x8fe2 }, +/* 0x8fe3 */ { false, 0x8fe3, 0x8fe3 }, +/* 0x8fe4 */ { false, 0x8fe4, 0x8fe4 }, +/* 0x8fe5 */ { false, 0x8fe5, 0x8fe5 }, +/* 0x8fe6 */ { false, 0x8fe6, 0x8fe6 }, +/* 0x8fe7 */ { false, 0x8fe7, 0x8fe7 }, +/* 0x8fe8 */ { false, 0x8fe8, 0x8fe8 }, +/* 0x8fe9 */ { false, 0x8fe9, 0x8fe9 }, +/* 0x8fea */ { false, 0x8fea, 0x8fea }, +/* 0x8feb */ { false, 0x8feb, 0x8feb }, +/* 0x8fec */ { false, 0x8fec, 0x8fec }, +/* 0x8fed */ { false, 0x8fed, 0x8fed }, +/* 0x8fee */ { false, 0x8fee, 0x8fee }, +/* 0x8fef */ { false, 0x8fef, 0x8fef }, +/* 0x8ff0 */ { false, 0x8ff0, 0x8ff0 }, +/* 0x8ff1 */ { false, 0x8ff1, 0x8ff1 }, +/* 0x8ff2 */ { false, 0x8ff2, 0x8ff2 }, +/* 0x8ff3 */ { false, 0x8ff3, 0x8ff3 }, +/* 0x8ff4 */ { false, 0x8ff4, 0x8ff4 }, +/* 0x8ff5 */ { false, 0x8ff5, 0x8ff5 }, +/* 0x8ff6 */ { false, 0x8ff6, 0x8ff6 }, +/* 0x8ff7 */ { false, 0x8ff7, 0x8ff7 }, +/* 0x8ff8 */ { false, 0x8ff8, 0x8ff8 }, +/* 0x8ff9 */ { false, 0x8ff9, 0x8ff9 }, +/* 0x8ffa */ { false, 0x8ffa, 0x8ffa }, +/* 0x8ffb */ { false, 0x8ffb, 0x8ffb }, +/* 0x8ffc */ { false, 0x8ffc, 0x8ffc }, +/* 0x8ffd */ { false, 0x8ffd, 0x8ffd }, +/* 0x8ffe */ { false, 0x8ffe, 0x8ffe }, +/* 0x8fff */ { false, 0x8fff, 0x8fff }, +/* 0x9000 */ { false, 0x9000, 0x9000 }, +/* 0x9001 */ { false, 0x9001, 0x9001 }, +/* 0x9002 */ { false, 0x9002, 0x9002 }, +/* 0x9003 */ { false, 0x9003, 0x9003 }, +/* 0x9004 */ { false, 0x9004, 0x9004 }, +/* 0x9005 */ { false, 0x9005, 0x9005 }, +/* 0x9006 */ { false, 0x9006, 0x9006 }, +/* 0x9007 */ { false, 0x9007, 0x9007 }, +/* 0x9008 */ { false, 0x9008, 0x9008 }, +/* 0x9009 */ { false, 0x9009, 0x9009 }, +/* 0x900a */ { false, 0x900a, 0x900a }, +/* 0x900b */ { false, 0x900b, 0x900b }, +/* 0x900c */ { false, 0x900c, 0x900c }, +/* 0x900d */ { false, 0x900d, 0x900d }, +/* 0x900e */ { false, 0x900e, 0x900e }, +/* 0x900f */ { false, 0x900f, 0x900f }, +/* 0x9010 */ { false, 0x9010, 0x9010 }, +/* 0x9011 */ { false, 0x9011, 0x9011 }, +/* 0x9012 */ { false, 0x9012, 0x9012 }, +/* 0x9013 */ { false, 0x9013, 0x9013 }, +/* 0x9014 */ { false, 0x9014, 0x9014 }, +/* 0x9015 */ { false, 0x9015, 0x9015 }, +/* 0x9016 */ { false, 0x9016, 0x9016 }, +/* 0x9017 */ { false, 0x9017, 0x9017 }, +/* 0x9018 */ { false, 0x9018, 0x9018 }, +/* 0x9019 */ { false, 0x9019, 0x9019 }, +/* 0x901a */ { false, 0x901a, 0x901a }, +/* 0x901b */ { false, 0x901b, 0x901b }, +/* 0x901c */ { false, 0x901c, 0x901c }, +/* 0x901d */ { false, 0x901d, 0x901d }, +/* 0x901e */ { false, 0x901e, 0x901e }, +/* 0x901f */ { false, 0x901f, 0x901f }, +/* 0x9020 */ { false, 0x9020, 0x9020 }, +/* 0x9021 */ { false, 0x9021, 0x9021 }, +/* 0x9022 */ { false, 0x9022, 0x9022 }, +/* 0x9023 */ { false, 0x9023, 0x9023 }, +/* 0x9024 */ { false, 0x9024, 0x9024 }, +/* 0x9025 */ { false, 0x9025, 0x9025 }, +/* 0x9026 */ { false, 0x9026, 0x9026 }, +/* 0x9027 */ { false, 0x9027, 0x9027 }, +/* 0x9028 */ { false, 0x9028, 0x9028 }, +/* 0x9029 */ { false, 0x9029, 0x9029 }, +/* 0x902a */ { false, 0x902a, 0x902a }, +/* 0x902b */ { false, 0x902b, 0x902b }, +/* 0x902c */ { false, 0x902c, 0x902c }, +/* 0x902d */ { false, 0x902d, 0x902d }, +/* 0x902e */ { false, 0x902e, 0x902e }, +/* 0x902f */ { false, 0x902f, 0x902f }, +/* 0x9030 */ { false, 0x9030, 0x9030 }, +/* 0x9031 */ { false, 0x9031, 0x9031 }, +/* 0x9032 */ { false, 0x9032, 0x9032 }, +/* 0x9033 */ { false, 0x9033, 0x9033 }, +/* 0x9034 */ { false, 0x9034, 0x9034 }, +/* 0x9035 */ { false, 0x9035, 0x9035 }, +/* 0x9036 */ { false, 0x9036, 0x9036 }, +/* 0x9037 */ { false, 0x9037, 0x9037 }, +/* 0x9038 */ { false, 0x9038, 0x9038 }, +/* 0x9039 */ { false, 0x9039, 0x9039 }, +/* 0x903a */ { false, 0x903a, 0x903a }, +/* 0x903b */ { false, 0x903b, 0x903b }, +/* 0x903c */ { false, 0x903c, 0x903c }, +/* 0x903d */ { false, 0x903d, 0x903d }, +/* 0x903e */ { false, 0x903e, 0x903e }, +/* 0x903f */ { false, 0x903f, 0x903f }, +/* 0x9040 */ { false, 0x9040, 0x9040 }, +/* 0x9041 */ { false, 0x9041, 0x9041 }, +/* 0x9042 */ { false, 0x9042, 0x9042 }, +/* 0x9043 */ { false, 0x9043, 0x9043 }, +/* 0x9044 */ { false, 0x9044, 0x9044 }, +/* 0x9045 */ { false, 0x9045, 0x9045 }, +/* 0x9046 */ { false, 0x9046, 0x9046 }, +/* 0x9047 */ { false, 0x9047, 0x9047 }, +/* 0x9048 */ { false, 0x9048, 0x9048 }, +/* 0x9049 */ { false, 0x9049, 0x9049 }, +/* 0x904a */ { false, 0x904a, 0x904a }, +/* 0x904b */ { false, 0x904b, 0x904b }, +/* 0x904c */ { false, 0x904c, 0x904c }, +/* 0x904d */ { false, 0x904d, 0x904d }, +/* 0x904e */ { false, 0x904e, 0x904e }, +/* 0x904f */ { false, 0x904f, 0x904f }, +/* 0x9050 */ { false, 0x9050, 0x9050 }, +/* 0x9051 */ { false, 0x9051, 0x9051 }, +/* 0x9052 */ { false, 0x9052, 0x9052 }, +/* 0x9053 */ { false, 0x9053, 0x9053 }, +/* 0x9054 */ { false, 0x9054, 0x9054 }, +/* 0x9055 */ { false, 0x9055, 0x9055 }, +/* 0x9056 */ { false, 0x9056, 0x9056 }, +/* 0x9057 */ { false, 0x9057, 0x9057 }, +/* 0x9058 */ { false, 0x9058, 0x9058 }, +/* 0x9059 */ { false, 0x9059, 0x9059 }, +/* 0x905a */ { false, 0x905a, 0x905a }, +/* 0x905b */ { false, 0x905b, 0x905b }, +/* 0x905c */ { false, 0x905c, 0x905c }, +/* 0x905d */ { false, 0x905d, 0x905d }, +/* 0x905e */ { false, 0x905e, 0x905e }, +/* 0x905f */ { false, 0x905f, 0x905f }, +/* 0x9060 */ { false, 0x9060, 0x9060 }, +/* 0x9061 */ { false, 0x9061, 0x9061 }, +/* 0x9062 */ { false, 0x9062, 0x9062 }, +/* 0x9063 */ { false, 0x9063, 0x9063 }, +/* 0x9064 */ { false, 0x9064, 0x9064 }, +/* 0x9065 */ { false, 0x9065, 0x9065 }, +/* 0x9066 */ { false, 0x9066, 0x9066 }, +/* 0x9067 */ { false, 0x9067, 0x9067 }, +/* 0x9068 */ { false, 0x9068, 0x9068 }, +/* 0x9069 */ { false, 0x9069, 0x9069 }, +/* 0x906a */ { false, 0x906a, 0x906a }, +/* 0x906b */ { false, 0x906b, 0x906b }, +/* 0x906c */ { false, 0x906c, 0x906c }, +/* 0x906d */ { false, 0x906d, 0x906d }, +/* 0x906e */ { false, 0x906e, 0x906e }, +/* 0x906f */ { false, 0x906f, 0x906f }, +/* 0x9070 */ { false, 0x9070, 0x9070 }, +/* 0x9071 */ { false, 0x9071, 0x9071 }, +/* 0x9072 */ { false, 0x9072, 0x9072 }, +/* 0x9073 */ { false, 0x9073, 0x9073 }, +/* 0x9074 */ { false, 0x9074, 0x9074 }, +/* 0x9075 */ { false, 0x9075, 0x9075 }, +/* 0x9076 */ { false, 0x9076, 0x9076 }, +/* 0x9077 */ { false, 0x9077, 0x9077 }, +/* 0x9078 */ { false, 0x9078, 0x9078 }, +/* 0x9079 */ { false, 0x9079, 0x9079 }, +/* 0x907a */ { false, 0x907a, 0x907a }, +/* 0x907b */ { false, 0x907b, 0x907b }, +/* 0x907c */ { false, 0x907c, 0x907c }, +/* 0x907d */ { false, 0x907d, 0x907d }, +/* 0x907e */ { false, 0x907e, 0x907e }, +/* 0x907f */ { false, 0x907f, 0x907f }, +/* 0x9080 */ { false, 0x9080, 0x9080 }, +/* 0x9081 */ { false, 0x9081, 0x9081 }, +/* 0x9082 */ { false, 0x9082, 0x9082 }, +/* 0x9083 */ { false, 0x9083, 0x9083 }, +/* 0x9084 */ { false, 0x9084, 0x9084 }, +/* 0x9085 */ { false, 0x9085, 0x9085 }, +/* 0x9086 */ { false, 0x9086, 0x9086 }, +/* 0x9087 */ { false, 0x9087, 0x9087 }, +/* 0x9088 */ { false, 0x9088, 0x9088 }, +/* 0x9089 */ { false, 0x9089, 0x9089 }, +/* 0x908a */ { false, 0x908a, 0x908a }, +/* 0x908b */ { false, 0x908b, 0x908b }, +/* 0x908c */ { false, 0x908c, 0x908c }, +/* 0x908d */ { false, 0x908d, 0x908d }, +/* 0x908e */ { false, 0x908e, 0x908e }, +/* 0x908f */ { false, 0x908f, 0x908f }, +/* 0x9090 */ { false, 0x9090, 0x9090 }, +/* 0x9091 */ { false, 0x9091, 0x9091 }, +/* 0x9092 */ { false, 0x9092, 0x9092 }, +/* 0x9093 */ { false, 0x9093, 0x9093 }, +/* 0x9094 */ { false, 0x9094, 0x9094 }, +/* 0x9095 */ { false, 0x9095, 0x9095 }, +/* 0x9096 */ { false, 0x9096, 0x9096 }, +/* 0x9097 */ { false, 0x9097, 0x9097 }, +/* 0x9098 */ { false, 0x9098, 0x9098 }, +/* 0x9099 */ { false, 0x9099, 0x9099 }, +/* 0x909a */ { false, 0x909a, 0x909a }, +/* 0x909b */ { false, 0x909b, 0x909b }, +/* 0x909c */ { false, 0x909c, 0x909c }, +/* 0x909d */ { false, 0x909d, 0x909d }, +/* 0x909e */ { false, 0x909e, 0x909e }, +/* 0x909f */ { false, 0x909f, 0x909f }, +/* 0x90a0 */ { false, 0x90a0, 0x90a0 }, +/* 0x90a1 */ { false, 0x90a1, 0x90a1 }, +/* 0x90a2 */ { false, 0x90a2, 0x90a2 }, +/* 0x90a3 */ { false, 0x90a3, 0x90a3 }, +/* 0x90a4 */ { false, 0x90a4, 0x90a4 }, +/* 0x90a5 */ { false, 0x90a5, 0x90a5 }, +/* 0x90a6 */ { false, 0x90a6, 0x90a6 }, +/* 0x90a7 */ { false, 0x90a7, 0x90a7 }, +/* 0x90a8 */ { false, 0x90a8, 0x90a8 }, +/* 0x90a9 */ { false, 0x90a9, 0x90a9 }, +/* 0x90aa */ { false, 0x90aa, 0x90aa }, +/* 0x90ab */ { false, 0x90ab, 0x90ab }, +/* 0x90ac */ { false, 0x90ac, 0x90ac }, +/* 0x90ad */ { false, 0x90ad, 0x90ad }, +/* 0x90ae */ { false, 0x90ae, 0x90ae }, +/* 0x90af */ { false, 0x90af, 0x90af }, +/* 0x90b0 */ { false, 0x90b0, 0x90b0 }, +/* 0x90b1 */ { false, 0x90b1, 0x90b1 }, +/* 0x90b2 */ { false, 0x90b2, 0x90b2 }, +/* 0x90b3 */ { false, 0x90b3, 0x90b3 }, +/* 0x90b4 */ { false, 0x90b4, 0x90b4 }, +/* 0x90b5 */ { false, 0x90b5, 0x90b5 }, +/* 0x90b6 */ { false, 0x90b6, 0x90b6 }, +/* 0x90b7 */ { false, 0x90b7, 0x90b7 }, +/* 0x90b8 */ { false, 0x90b8, 0x90b8 }, +/* 0x90b9 */ { false, 0x90b9, 0x90b9 }, +/* 0x90ba */ { false, 0x90ba, 0x90ba }, +/* 0x90bb */ { false, 0x90bb, 0x90bb }, +/* 0x90bc */ { false, 0x90bc, 0x90bc }, +/* 0x90bd */ { false, 0x90bd, 0x90bd }, +/* 0x90be */ { false, 0x90be, 0x90be }, +/* 0x90bf */ { false, 0x90bf, 0x90bf }, +/* 0x90c0 */ { false, 0x90c0, 0x90c0 }, +/* 0x90c1 */ { false, 0x90c1, 0x90c1 }, +/* 0x90c2 */ { false, 0x90c2, 0x90c2 }, +/* 0x90c3 */ { false, 0x90c3, 0x90c3 }, +/* 0x90c4 */ { false, 0x90c4, 0x90c4 }, +/* 0x90c5 */ { false, 0x90c5, 0x90c5 }, +/* 0x90c6 */ { false, 0x90c6, 0x90c6 }, +/* 0x90c7 */ { false, 0x90c7, 0x90c7 }, +/* 0x90c8 */ { false, 0x90c8, 0x90c8 }, +/* 0x90c9 */ { false, 0x90c9, 0x90c9 }, +/* 0x90ca */ { false, 0x90ca, 0x90ca }, +/* 0x90cb */ { false, 0x90cb, 0x90cb }, +/* 0x90cc */ { false, 0x90cc, 0x90cc }, +/* 0x90cd */ { false, 0x90cd, 0x90cd }, +/* 0x90ce */ { false, 0x90ce, 0x90ce }, +/* 0x90cf */ { false, 0x90cf, 0x90cf }, +/* 0x90d0 */ { false, 0x90d0, 0x90d0 }, +/* 0x90d1 */ { false, 0x90d1, 0x90d1 }, +/* 0x90d2 */ { false, 0x90d2, 0x90d2 }, +/* 0x90d3 */ { false, 0x90d3, 0x90d3 }, +/* 0x90d4 */ { false, 0x90d4, 0x90d4 }, +/* 0x90d5 */ { false, 0x90d5, 0x90d5 }, +/* 0x90d6 */ { false, 0x90d6, 0x90d6 }, +/* 0x90d7 */ { false, 0x90d7, 0x90d7 }, +/* 0x90d8 */ { false, 0x90d8, 0x90d8 }, +/* 0x90d9 */ { false, 0x90d9, 0x90d9 }, +/* 0x90da */ { false, 0x90da, 0x90da }, +/* 0x90db */ { false, 0x90db, 0x90db }, +/* 0x90dc */ { false, 0x90dc, 0x90dc }, +/* 0x90dd */ { false, 0x90dd, 0x90dd }, +/* 0x90de */ { false, 0x90de, 0x90de }, +/* 0x90df */ { false, 0x90df, 0x90df }, +/* 0x90e0 */ { false, 0x90e0, 0x90e0 }, +/* 0x90e1 */ { false, 0x90e1, 0x90e1 }, +/* 0x90e2 */ { false, 0x90e2, 0x90e2 }, +/* 0x90e3 */ { false, 0x90e3, 0x90e3 }, +/* 0x90e4 */ { false, 0x90e4, 0x90e4 }, +/* 0x90e5 */ { false, 0x90e5, 0x90e5 }, +/* 0x90e6 */ { false, 0x90e6, 0x90e6 }, +/* 0x90e7 */ { false, 0x90e7, 0x90e7 }, +/* 0x90e8 */ { false, 0x90e8, 0x90e8 }, +/* 0x90e9 */ { false, 0x90e9, 0x90e9 }, +/* 0x90ea */ { false, 0x90ea, 0x90ea }, +/* 0x90eb */ { false, 0x90eb, 0x90eb }, +/* 0x90ec */ { false, 0x90ec, 0x90ec }, +/* 0x90ed */ { false, 0x90ed, 0x90ed }, +/* 0x90ee */ { false, 0x90ee, 0x90ee }, +/* 0x90ef */ { false, 0x90ef, 0x90ef }, +/* 0x90f0 */ { false, 0x90f0, 0x90f0 }, +/* 0x90f1 */ { false, 0x90f1, 0x90f1 }, +/* 0x90f2 */ { false, 0x90f2, 0x90f2 }, +/* 0x90f3 */ { false, 0x90f3, 0x90f3 }, +/* 0x90f4 */ { false, 0x90f4, 0x90f4 }, +/* 0x90f5 */ { false, 0x90f5, 0x90f5 }, +/* 0x90f6 */ { false, 0x90f6, 0x90f6 }, +/* 0x90f7 */ { false, 0x90f7, 0x90f7 }, +/* 0x90f8 */ { false, 0x90f8, 0x90f8 }, +/* 0x90f9 */ { false, 0x90f9, 0x90f9 }, +/* 0x90fa */ { false, 0x90fa, 0x90fa }, +/* 0x90fb */ { false, 0x90fb, 0x90fb }, +/* 0x90fc */ { false, 0x90fc, 0x90fc }, +/* 0x90fd */ { false, 0x90fd, 0x90fd }, +/* 0x90fe */ { false, 0x90fe, 0x90fe }, +/* 0x90ff */ { false, 0x90ff, 0x90ff }, +/* 0x9100 */ { false, 0x9100, 0x9100 }, +/* 0x9101 */ { false, 0x9101, 0x9101 }, +/* 0x9102 */ { false, 0x9102, 0x9102 }, +/* 0x9103 */ { false, 0x9103, 0x9103 }, +/* 0x9104 */ { false, 0x9104, 0x9104 }, +/* 0x9105 */ { false, 0x9105, 0x9105 }, +/* 0x9106 */ { false, 0x9106, 0x9106 }, +/* 0x9107 */ { false, 0x9107, 0x9107 }, +/* 0x9108 */ { false, 0x9108, 0x9108 }, +/* 0x9109 */ { false, 0x9109, 0x9109 }, +/* 0x910a */ { false, 0x910a, 0x910a }, +/* 0x910b */ { false, 0x910b, 0x910b }, +/* 0x910c */ { false, 0x910c, 0x910c }, +/* 0x910d */ { false, 0x910d, 0x910d }, +/* 0x910e */ { false, 0x910e, 0x910e }, +/* 0x910f */ { false, 0x910f, 0x910f }, +/* 0x9110 */ { false, 0x9110, 0x9110 }, +/* 0x9111 */ { false, 0x9111, 0x9111 }, +/* 0x9112 */ { false, 0x9112, 0x9112 }, +/* 0x9113 */ { false, 0x9113, 0x9113 }, +/* 0x9114 */ { false, 0x9114, 0x9114 }, +/* 0x9115 */ { false, 0x9115, 0x9115 }, +/* 0x9116 */ { false, 0x9116, 0x9116 }, +/* 0x9117 */ { false, 0x9117, 0x9117 }, +/* 0x9118 */ { false, 0x9118, 0x9118 }, +/* 0x9119 */ { false, 0x9119, 0x9119 }, +/* 0x911a */ { false, 0x911a, 0x911a }, +/* 0x911b */ { false, 0x911b, 0x911b }, +/* 0x911c */ { false, 0x911c, 0x911c }, +/* 0x911d */ { false, 0x911d, 0x911d }, +/* 0x911e */ { false, 0x911e, 0x911e }, +/* 0x911f */ { false, 0x911f, 0x911f }, +/* 0x9120 */ { false, 0x9120, 0x9120 }, +/* 0x9121 */ { false, 0x9121, 0x9121 }, +/* 0x9122 */ { false, 0x9122, 0x9122 }, +/* 0x9123 */ { false, 0x9123, 0x9123 }, +/* 0x9124 */ { false, 0x9124, 0x9124 }, +/* 0x9125 */ { false, 0x9125, 0x9125 }, +/* 0x9126 */ { false, 0x9126, 0x9126 }, +/* 0x9127 */ { false, 0x9127, 0x9127 }, +/* 0x9128 */ { false, 0x9128, 0x9128 }, +/* 0x9129 */ { false, 0x9129, 0x9129 }, +/* 0x912a */ { false, 0x912a, 0x912a }, +/* 0x912b */ { false, 0x912b, 0x912b }, +/* 0x912c */ { false, 0x912c, 0x912c }, +/* 0x912d */ { false, 0x912d, 0x912d }, +/* 0x912e */ { false, 0x912e, 0x912e }, +/* 0x912f */ { false, 0x912f, 0x912f }, +/* 0x9130 */ { false, 0x9130, 0x9130 }, +/* 0x9131 */ { false, 0x9131, 0x9131 }, +/* 0x9132 */ { false, 0x9132, 0x9132 }, +/* 0x9133 */ { false, 0x9133, 0x9133 }, +/* 0x9134 */ { false, 0x9134, 0x9134 }, +/* 0x9135 */ { false, 0x9135, 0x9135 }, +/* 0x9136 */ { false, 0x9136, 0x9136 }, +/* 0x9137 */ { false, 0x9137, 0x9137 }, +/* 0x9138 */ { false, 0x9138, 0x9138 }, +/* 0x9139 */ { false, 0x9139, 0x9139 }, +/* 0x913a */ { false, 0x913a, 0x913a }, +/* 0x913b */ { false, 0x913b, 0x913b }, +/* 0x913c */ { false, 0x913c, 0x913c }, +/* 0x913d */ { false, 0x913d, 0x913d }, +/* 0x913e */ { false, 0x913e, 0x913e }, +/* 0x913f */ { false, 0x913f, 0x913f }, +/* 0x9140 */ { false, 0x9140, 0x9140 }, +/* 0x9141 */ { false, 0x9141, 0x9141 }, +/* 0x9142 */ { false, 0x9142, 0x9142 }, +/* 0x9143 */ { false, 0x9143, 0x9143 }, +/* 0x9144 */ { false, 0x9144, 0x9144 }, +/* 0x9145 */ { false, 0x9145, 0x9145 }, +/* 0x9146 */ { false, 0x9146, 0x9146 }, +/* 0x9147 */ { false, 0x9147, 0x9147 }, +/* 0x9148 */ { false, 0x9148, 0x9148 }, +/* 0x9149 */ { false, 0x9149, 0x9149 }, +/* 0x914a */ { false, 0x914a, 0x914a }, +/* 0x914b */ { false, 0x914b, 0x914b }, +/* 0x914c */ { false, 0x914c, 0x914c }, +/* 0x914d */ { false, 0x914d, 0x914d }, +/* 0x914e */ { false, 0x914e, 0x914e }, +/* 0x914f */ { false, 0x914f, 0x914f }, +/* 0x9150 */ { false, 0x9150, 0x9150 }, +/* 0x9151 */ { false, 0x9151, 0x9151 }, +/* 0x9152 */ { false, 0x9152, 0x9152 }, +/* 0x9153 */ { false, 0x9153, 0x9153 }, +/* 0x9154 */ { false, 0x9154, 0x9154 }, +/* 0x9155 */ { false, 0x9155, 0x9155 }, +/* 0x9156 */ { false, 0x9156, 0x9156 }, +/* 0x9157 */ { false, 0x9157, 0x9157 }, +/* 0x9158 */ { false, 0x9158, 0x9158 }, +/* 0x9159 */ { false, 0x9159, 0x9159 }, +/* 0x915a */ { false, 0x915a, 0x915a }, +/* 0x915b */ { false, 0x915b, 0x915b }, +/* 0x915c */ { false, 0x915c, 0x915c }, +/* 0x915d */ { false, 0x915d, 0x915d }, +/* 0x915e */ { false, 0x915e, 0x915e }, +/* 0x915f */ { false, 0x915f, 0x915f }, +/* 0x9160 */ { false, 0x9160, 0x9160 }, +/* 0x9161 */ { false, 0x9161, 0x9161 }, +/* 0x9162 */ { false, 0x9162, 0x9162 }, +/* 0x9163 */ { false, 0x9163, 0x9163 }, +/* 0x9164 */ { false, 0x9164, 0x9164 }, +/* 0x9165 */ { false, 0x9165, 0x9165 }, +/* 0x9166 */ { false, 0x9166, 0x9166 }, +/* 0x9167 */ { false, 0x9167, 0x9167 }, +/* 0x9168 */ { false, 0x9168, 0x9168 }, +/* 0x9169 */ { false, 0x9169, 0x9169 }, +/* 0x916a */ { false, 0x916a, 0x916a }, +/* 0x916b */ { false, 0x916b, 0x916b }, +/* 0x916c */ { false, 0x916c, 0x916c }, +/* 0x916d */ { false, 0x916d, 0x916d }, +/* 0x916e */ { false, 0x916e, 0x916e }, +/* 0x916f */ { false, 0x916f, 0x916f }, +/* 0x9170 */ { false, 0x9170, 0x9170 }, +/* 0x9171 */ { false, 0x9171, 0x9171 }, +/* 0x9172 */ { false, 0x9172, 0x9172 }, +/* 0x9173 */ { false, 0x9173, 0x9173 }, +/* 0x9174 */ { false, 0x9174, 0x9174 }, +/* 0x9175 */ { false, 0x9175, 0x9175 }, +/* 0x9176 */ { false, 0x9176, 0x9176 }, +/* 0x9177 */ { false, 0x9177, 0x9177 }, +/* 0x9178 */ { false, 0x9178, 0x9178 }, +/* 0x9179 */ { false, 0x9179, 0x9179 }, +/* 0x917a */ { false, 0x917a, 0x917a }, +/* 0x917b */ { false, 0x917b, 0x917b }, +/* 0x917c */ { false, 0x917c, 0x917c }, +/* 0x917d */ { false, 0x917d, 0x917d }, +/* 0x917e */ { false, 0x917e, 0x917e }, +/* 0x917f */ { false, 0x917f, 0x917f }, +/* 0x9180 */ { false, 0x9180, 0x9180 }, +/* 0x9181 */ { false, 0x9181, 0x9181 }, +/* 0x9182 */ { false, 0x9182, 0x9182 }, +/* 0x9183 */ { false, 0x9183, 0x9183 }, +/* 0x9184 */ { false, 0x9184, 0x9184 }, +/* 0x9185 */ { false, 0x9185, 0x9185 }, +/* 0x9186 */ { false, 0x9186, 0x9186 }, +/* 0x9187 */ { false, 0x9187, 0x9187 }, +/* 0x9188 */ { false, 0x9188, 0x9188 }, +/* 0x9189 */ { false, 0x9189, 0x9189 }, +/* 0x918a */ { false, 0x918a, 0x918a }, +/* 0x918b */ { false, 0x918b, 0x918b }, +/* 0x918c */ { false, 0x918c, 0x918c }, +/* 0x918d */ { false, 0x918d, 0x918d }, +/* 0x918e */ { false, 0x918e, 0x918e }, +/* 0x918f */ { false, 0x918f, 0x918f }, +/* 0x9190 */ { false, 0x9190, 0x9190 }, +/* 0x9191 */ { false, 0x9191, 0x9191 }, +/* 0x9192 */ { false, 0x9192, 0x9192 }, +/* 0x9193 */ { false, 0x9193, 0x9193 }, +/* 0x9194 */ { false, 0x9194, 0x9194 }, +/* 0x9195 */ { false, 0x9195, 0x9195 }, +/* 0x9196 */ { false, 0x9196, 0x9196 }, +/* 0x9197 */ { false, 0x9197, 0x9197 }, +/* 0x9198 */ { false, 0x9198, 0x9198 }, +/* 0x9199 */ { false, 0x9199, 0x9199 }, +/* 0x919a */ { false, 0x919a, 0x919a }, +/* 0x919b */ { false, 0x919b, 0x919b }, +/* 0x919c */ { false, 0x919c, 0x919c }, +/* 0x919d */ { false, 0x919d, 0x919d }, +/* 0x919e */ { false, 0x919e, 0x919e }, +/* 0x919f */ { false, 0x919f, 0x919f }, +/* 0x91a0 */ { false, 0x91a0, 0x91a0 }, +/* 0x91a1 */ { false, 0x91a1, 0x91a1 }, +/* 0x91a2 */ { false, 0x91a2, 0x91a2 }, +/* 0x91a3 */ { false, 0x91a3, 0x91a3 }, +/* 0x91a4 */ { false, 0x91a4, 0x91a4 }, +/* 0x91a5 */ { false, 0x91a5, 0x91a5 }, +/* 0x91a6 */ { false, 0x91a6, 0x91a6 }, +/* 0x91a7 */ { false, 0x91a7, 0x91a7 }, +/* 0x91a8 */ { false, 0x91a8, 0x91a8 }, +/* 0x91a9 */ { false, 0x91a9, 0x91a9 }, +/* 0x91aa */ { false, 0x91aa, 0x91aa }, +/* 0x91ab */ { false, 0x91ab, 0x91ab }, +/* 0x91ac */ { false, 0x91ac, 0x91ac }, +/* 0x91ad */ { false, 0x91ad, 0x91ad }, +/* 0x91ae */ { false, 0x91ae, 0x91ae }, +/* 0x91af */ { false, 0x91af, 0x91af }, +/* 0x91b0 */ { false, 0x91b0, 0x91b0 }, +/* 0x91b1 */ { false, 0x91b1, 0x91b1 }, +/* 0x91b2 */ { false, 0x91b2, 0x91b2 }, +/* 0x91b3 */ { false, 0x91b3, 0x91b3 }, +/* 0x91b4 */ { false, 0x91b4, 0x91b4 }, +/* 0x91b5 */ { false, 0x91b5, 0x91b5 }, +/* 0x91b6 */ { false, 0x91b6, 0x91b6 }, +/* 0x91b7 */ { false, 0x91b7, 0x91b7 }, +/* 0x91b8 */ { false, 0x91b8, 0x91b8 }, +/* 0x91b9 */ { false, 0x91b9, 0x91b9 }, +/* 0x91ba */ { false, 0x91ba, 0x91ba }, +/* 0x91bb */ { false, 0x91bb, 0x91bb }, +/* 0x91bc */ { false, 0x91bc, 0x91bc }, +/* 0x91bd */ { false, 0x91bd, 0x91bd }, +/* 0x91be */ { false, 0x91be, 0x91be }, +/* 0x91bf */ { false, 0x91bf, 0x91bf }, +/* 0x91c0 */ { false, 0x91c0, 0x91c0 }, +/* 0x91c1 */ { false, 0x91c1, 0x91c1 }, +/* 0x91c2 */ { false, 0x91c2, 0x91c2 }, +/* 0x91c3 */ { false, 0x91c3, 0x91c3 }, +/* 0x91c4 */ { false, 0x91c4, 0x91c4 }, +/* 0x91c5 */ { false, 0x91c5, 0x91c5 }, +/* 0x91c6 */ { false, 0x91c6, 0x91c6 }, +/* 0x91c7 */ { false, 0x91c7, 0x91c7 }, +/* 0x91c8 */ { false, 0x91c8, 0x91c8 }, +/* 0x91c9 */ { false, 0x91c9, 0x91c9 }, +/* 0x91ca */ { false, 0x91ca, 0x91ca }, +/* 0x91cb */ { false, 0x91cb, 0x91cb }, +/* 0x91cc */ { false, 0x91cc, 0x91cc }, +/* 0x91cd */ { false, 0x91cd, 0x91cd }, +/* 0x91ce */ { false, 0x91ce, 0x91ce }, +/* 0x91cf */ { false, 0x91cf, 0x91cf }, +/* 0x91d0 */ { false, 0x91d0, 0x91d0 }, +/* 0x91d1 */ { false, 0x91d1, 0x91d1 }, +/* 0x91d2 */ { false, 0x91d2, 0x91d2 }, +/* 0x91d3 */ { false, 0x91d3, 0x91d3 }, +/* 0x91d4 */ { false, 0x91d4, 0x91d4 }, +/* 0x91d5 */ { false, 0x91d5, 0x91d5 }, +/* 0x91d6 */ { false, 0x91d6, 0x91d6 }, +/* 0x91d7 */ { false, 0x91d7, 0x91d7 }, +/* 0x91d8 */ { false, 0x91d8, 0x91d8 }, +/* 0x91d9 */ { false, 0x91d9, 0x91d9 }, +/* 0x91da */ { false, 0x91da, 0x91da }, +/* 0x91db */ { false, 0x91db, 0x91db }, +/* 0x91dc */ { false, 0x91dc, 0x91dc }, +/* 0x91dd */ { false, 0x91dd, 0x91dd }, +/* 0x91de */ { false, 0x91de, 0x91de }, +/* 0x91df */ { false, 0x91df, 0x91df }, +/* 0x91e0 */ { false, 0x91e0, 0x91e0 }, +/* 0x91e1 */ { false, 0x91e1, 0x91e1 }, +/* 0x91e2 */ { false, 0x91e2, 0x91e2 }, +/* 0x91e3 */ { false, 0x91e3, 0x91e3 }, +/* 0x91e4 */ { false, 0x91e4, 0x91e4 }, +/* 0x91e5 */ { false, 0x91e5, 0x91e5 }, +/* 0x91e6 */ { false, 0x91e6, 0x91e6 }, +/* 0x91e7 */ { false, 0x91e7, 0x91e7 }, +/* 0x91e8 */ { false, 0x91e8, 0x91e8 }, +/* 0x91e9 */ { false, 0x91e9, 0x91e9 }, +/* 0x91ea */ { false, 0x91ea, 0x91ea }, +/* 0x91eb */ { false, 0x91eb, 0x91eb }, +/* 0x91ec */ { false, 0x91ec, 0x91ec }, +/* 0x91ed */ { false, 0x91ed, 0x91ed }, +/* 0x91ee */ { false, 0x91ee, 0x91ee }, +/* 0x91ef */ { false, 0x91ef, 0x91ef }, +/* 0x91f0 */ { false, 0x91f0, 0x91f0 }, +/* 0x91f1 */ { false, 0x91f1, 0x91f1 }, +/* 0x91f2 */ { false, 0x91f2, 0x91f2 }, +/* 0x91f3 */ { false, 0x91f3, 0x91f3 }, +/* 0x91f4 */ { false, 0x91f4, 0x91f4 }, +/* 0x91f5 */ { false, 0x91f5, 0x91f5 }, +/* 0x91f6 */ { false, 0x91f6, 0x91f6 }, +/* 0x91f7 */ { false, 0x91f7, 0x91f7 }, +/* 0x91f8 */ { false, 0x91f8, 0x91f8 }, +/* 0x91f9 */ { false, 0x91f9, 0x91f9 }, +/* 0x91fa */ { false, 0x91fa, 0x91fa }, +/* 0x91fb */ { false, 0x91fb, 0x91fb }, +/* 0x91fc */ { false, 0x91fc, 0x91fc }, +/* 0x91fd */ { false, 0x91fd, 0x91fd }, +/* 0x91fe */ { false, 0x91fe, 0x91fe }, +/* 0x91ff */ { false, 0x91ff, 0x91ff }, +/* 0x9200 */ { false, 0x9200, 0x9200 }, +/* 0x9201 */ { false, 0x9201, 0x9201 }, +/* 0x9202 */ { false, 0x9202, 0x9202 }, +/* 0x9203 */ { false, 0x9203, 0x9203 }, +/* 0x9204 */ { false, 0x9204, 0x9204 }, +/* 0x9205 */ { false, 0x9205, 0x9205 }, +/* 0x9206 */ { false, 0x9206, 0x9206 }, +/* 0x9207 */ { false, 0x9207, 0x9207 }, +/* 0x9208 */ { false, 0x9208, 0x9208 }, +/* 0x9209 */ { false, 0x9209, 0x9209 }, +/* 0x920a */ { false, 0x920a, 0x920a }, +/* 0x920b */ { false, 0x920b, 0x920b }, +/* 0x920c */ { false, 0x920c, 0x920c }, +/* 0x920d */ { false, 0x920d, 0x920d }, +/* 0x920e */ { false, 0x920e, 0x920e }, +/* 0x920f */ { false, 0x920f, 0x920f }, +/* 0x9210 */ { false, 0x9210, 0x9210 }, +/* 0x9211 */ { false, 0x9211, 0x9211 }, +/* 0x9212 */ { false, 0x9212, 0x9212 }, +/* 0x9213 */ { false, 0x9213, 0x9213 }, +/* 0x9214 */ { false, 0x9214, 0x9214 }, +/* 0x9215 */ { false, 0x9215, 0x9215 }, +/* 0x9216 */ { false, 0x9216, 0x9216 }, +/* 0x9217 */ { false, 0x9217, 0x9217 }, +/* 0x9218 */ { false, 0x9218, 0x9218 }, +/* 0x9219 */ { false, 0x9219, 0x9219 }, +/* 0x921a */ { false, 0x921a, 0x921a }, +/* 0x921b */ { false, 0x921b, 0x921b }, +/* 0x921c */ { false, 0x921c, 0x921c }, +/* 0x921d */ { false, 0x921d, 0x921d }, +/* 0x921e */ { false, 0x921e, 0x921e }, +/* 0x921f */ { false, 0x921f, 0x921f }, +/* 0x9220 */ { false, 0x9220, 0x9220 }, +/* 0x9221 */ { false, 0x9221, 0x9221 }, +/* 0x9222 */ { false, 0x9222, 0x9222 }, +/* 0x9223 */ { false, 0x9223, 0x9223 }, +/* 0x9224 */ { false, 0x9224, 0x9224 }, +/* 0x9225 */ { false, 0x9225, 0x9225 }, +/* 0x9226 */ { false, 0x9226, 0x9226 }, +/* 0x9227 */ { false, 0x9227, 0x9227 }, +/* 0x9228 */ { false, 0x9228, 0x9228 }, +/* 0x9229 */ { false, 0x9229, 0x9229 }, +/* 0x922a */ { false, 0x922a, 0x922a }, +/* 0x922b */ { false, 0x922b, 0x922b }, +/* 0x922c */ { false, 0x922c, 0x922c }, +/* 0x922d */ { false, 0x922d, 0x922d }, +/* 0x922e */ { false, 0x922e, 0x922e }, +/* 0x922f */ { false, 0x922f, 0x922f }, +/* 0x9230 */ { false, 0x9230, 0x9230 }, +/* 0x9231 */ { false, 0x9231, 0x9231 }, +/* 0x9232 */ { false, 0x9232, 0x9232 }, +/* 0x9233 */ { false, 0x9233, 0x9233 }, +/* 0x9234 */ { false, 0x9234, 0x9234 }, +/* 0x9235 */ { false, 0x9235, 0x9235 }, +/* 0x9236 */ { false, 0x9236, 0x9236 }, +/* 0x9237 */ { false, 0x9237, 0x9237 }, +/* 0x9238 */ { false, 0x9238, 0x9238 }, +/* 0x9239 */ { false, 0x9239, 0x9239 }, +/* 0x923a */ { false, 0x923a, 0x923a }, +/* 0x923b */ { false, 0x923b, 0x923b }, +/* 0x923c */ { false, 0x923c, 0x923c }, +/* 0x923d */ { false, 0x923d, 0x923d }, +/* 0x923e */ { false, 0x923e, 0x923e }, +/* 0x923f */ { false, 0x923f, 0x923f }, +/* 0x9240 */ { false, 0x9240, 0x9240 }, +/* 0x9241 */ { false, 0x9241, 0x9241 }, +/* 0x9242 */ { false, 0x9242, 0x9242 }, +/* 0x9243 */ { false, 0x9243, 0x9243 }, +/* 0x9244 */ { false, 0x9244, 0x9244 }, +/* 0x9245 */ { false, 0x9245, 0x9245 }, +/* 0x9246 */ { false, 0x9246, 0x9246 }, +/* 0x9247 */ { false, 0x9247, 0x9247 }, +/* 0x9248 */ { false, 0x9248, 0x9248 }, +/* 0x9249 */ { false, 0x9249, 0x9249 }, +/* 0x924a */ { false, 0x924a, 0x924a }, +/* 0x924b */ { false, 0x924b, 0x924b }, +/* 0x924c */ { false, 0x924c, 0x924c }, +/* 0x924d */ { false, 0x924d, 0x924d }, +/* 0x924e */ { false, 0x924e, 0x924e }, +/* 0x924f */ { false, 0x924f, 0x924f }, +/* 0x9250 */ { false, 0x9250, 0x9250 }, +/* 0x9251 */ { false, 0x9251, 0x9251 }, +/* 0x9252 */ { false, 0x9252, 0x9252 }, +/* 0x9253 */ { false, 0x9253, 0x9253 }, +/* 0x9254 */ { false, 0x9254, 0x9254 }, +/* 0x9255 */ { false, 0x9255, 0x9255 }, +/* 0x9256 */ { false, 0x9256, 0x9256 }, +/* 0x9257 */ { false, 0x9257, 0x9257 }, +/* 0x9258 */ { false, 0x9258, 0x9258 }, +/* 0x9259 */ { false, 0x9259, 0x9259 }, +/* 0x925a */ { false, 0x925a, 0x925a }, +/* 0x925b */ { false, 0x925b, 0x925b }, +/* 0x925c */ { false, 0x925c, 0x925c }, +/* 0x925d */ { false, 0x925d, 0x925d }, +/* 0x925e */ { false, 0x925e, 0x925e }, +/* 0x925f */ { false, 0x925f, 0x925f }, +/* 0x9260 */ { false, 0x9260, 0x9260 }, +/* 0x9261 */ { false, 0x9261, 0x9261 }, +/* 0x9262 */ { false, 0x9262, 0x9262 }, +/* 0x9263 */ { false, 0x9263, 0x9263 }, +/* 0x9264 */ { false, 0x9264, 0x9264 }, +/* 0x9265 */ { false, 0x9265, 0x9265 }, +/* 0x9266 */ { false, 0x9266, 0x9266 }, +/* 0x9267 */ { false, 0x9267, 0x9267 }, +/* 0x9268 */ { false, 0x9268, 0x9268 }, +/* 0x9269 */ { false, 0x9269, 0x9269 }, +/* 0x926a */ { false, 0x926a, 0x926a }, +/* 0x926b */ { false, 0x926b, 0x926b }, +/* 0x926c */ { false, 0x926c, 0x926c }, +/* 0x926d */ { false, 0x926d, 0x926d }, +/* 0x926e */ { false, 0x926e, 0x926e }, +/* 0x926f */ { false, 0x926f, 0x926f }, +/* 0x9270 */ { false, 0x9270, 0x9270 }, +/* 0x9271 */ { false, 0x9271, 0x9271 }, +/* 0x9272 */ { false, 0x9272, 0x9272 }, +/* 0x9273 */ { false, 0x9273, 0x9273 }, +/* 0x9274 */ { false, 0x9274, 0x9274 }, +/* 0x9275 */ { false, 0x9275, 0x9275 }, +/* 0x9276 */ { false, 0x9276, 0x9276 }, +/* 0x9277 */ { false, 0x9277, 0x9277 }, +/* 0x9278 */ { false, 0x9278, 0x9278 }, +/* 0x9279 */ { false, 0x9279, 0x9279 }, +/* 0x927a */ { false, 0x927a, 0x927a }, +/* 0x927b */ { false, 0x927b, 0x927b }, +/* 0x927c */ { false, 0x927c, 0x927c }, +/* 0x927d */ { false, 0x927d, 0x927d }, +/* 0x927e */ { false, 0x927e, 0x927e }, +/* 0x927f */ { false, 0x927f, 0x927f }, +/* 0x9280 */ { false, 0x9280, 0x9280 }, +/* 0x9281 */ { false, 0x9281, 0x9281 }, +/* 0x9282 */ { false, 0x9282, 0x9282 }, +/* 0x9283 */ { false, 0x9283, 0x9283 }, +/* 0x9284 */ { false, 0x9284, 0x9284 }, +/* 0x9285 */ { false, 0x9285, 0x9285 }, +/* 0x9286 */ { false, 0x9286, 0x9286 }, +/* 0x9287 */ { false, 0x9287, 0x9287 }, +/* 0x9288 */ { false, 0x9288, 0x9288 }, +/* 0x9289 */ { false, 0x9289, 0x9289 }, +/* 0x928a */ { false, 0x928a, 0x928a }, +/* 0x928b */ { false, 0x928b, 0x928b }, +/* 0x928c */ { false, 0x928c, 0x928c }, +/* 0x928d */ { false, 0x928d, 0x928d }, +/* 0x928e */ { false, 0x928e, 0x928e }, +/* 0x928f */ { false, 0x928f, 0x928f }, +/* 0x9290 */ { false, 0x9290, 0x9290 }, +/* 0x9291 */ { false, 0x9291, 0x9291 }, +/* 0x9292 */ { false, 0x9292, 0x9292 }, +/* 0x9293 */ { false, 0x9293, 0x9293 }, +/* 0x9294 */ { false, 0x9294, 0x9294 }, +/* 0x9295 */ { false, 0x9295, 0x9295 }, +/* 0x9296 */ { false, 0x9296, 0x9296 }, +/* 0x9297 */ { false, 0x9297, 0x9297 }, +/* 0x9298 */ { false, 0x9298, 0x9298 }, +/* 0x9299 */ { false, 0x9299, 0x9299 }, +/* 0x929a */ { false, 0x929a, 0x929a }, +/* 0x929b */ { false, 0x929b, 0x929b }, +/* 0x929c */ { false, 0x929c, 0x929c }, +/* 0x929d */ { false, 0x929d, 0x929d }, +/* 0x929e */ { false, 0x929e, 0x929e }, +/* 0x929f */ { false, 0x929f, 0x929f }, +/* 0x92a0 */ { false, 0x92a0, 0x92a0 }, +/* 0x92a1 */ { false, 0x92a1, 0x92a1 }, +/* 0x92a2 */ { false, 0x92a2, 0x92a2 }, +/* 0x92a3 */ { false, 0x92a3, 0x92a3 }, +/* 0x92a4 */ { false, 0x92a4, 0x92a4 }, +/* 0x92a5 */ { false, 0x92a5, 0x92a5 }, +/* 0x92a6 */ { false, 0x92a6, 0x92a6 }, +/* 0x92a7 */ { false, 0x92a7, 0x92a7 }, +/* 0x92a8 */ { false, 0x92a8, 0x92a8 }, +/* 0x92a9 */ { false, 0x92a9, 0x92a9 }, +/* 0x92aa */ { false, 0x92aa, 0x92aa }, +/* 0x92ab */ { false, 0x92ab, 0x92ab }, +/* 0x92ac */ { false, 0x92ac, 0x92ac }, +/* 0x92ad */ { false, 0x92ad, 0x92ad }, +/* 0x92ae */ { false, 0x92ae, 0x92ae }, +/* 0x92af */ { false, 0x92af, 0x92af }, +/* 0x92b0 */ { false, 0x92b0, 0x92b0 }, +/* 0x92b1 */ { false, 0x92b1, 0x92b1 }, +/* 0x92b2 */ { false, 0x92b2, 0x92b2 }, +/* 0x92b3 */ { false, 0x92b3, 0x92b3 }, +/* 0x92b4 */ { false, 0x92b4, 0x92b4 }, +/* 0x92b5 */ { false, 0x92b5, 0x92b5 }, +/* 0x92b6 */ { false, 0x92b6, 0x92b6 }, +/* 0x92b7 */ { false, 0x92b7, 0x92b7 }, +/* 0x92b8 */ { false, 0x92b8, 0x92b8 }, +/* 0x92b9 */ { false, 0x92b9, 0x92b9 }, +/* 0x92ba */ { false, 0x92ba, 0x92ba }, +/* 0x92bb */ { false, 0x92bb, 0x92bb }, +/* 0x92bc */ { false, 0x92bc, 0x92bc }, +/* 0x92bd */ { false, 0x92bd, 0x92bd }, +/* 0x92be */ { false, 0x92be, 0x92be }, +/* 0x92bf */ { false, 0x92bf, 0x92bf }, +/* 0x92c0 */ { false, 0x92c0, 0x92c0 }, +/* 0x92c1 */ { false, 0x92c1, 0x92c1 }, +/* 0x92c2 */ { false, 0x92c2, 0x92c2 }, +/* 0x92c3 */ { false, 0x92c3, 0x92c3 }, +/* 0x92c4 */ { false, 0x92c4, 0x92c4 }, +/* 0x92c5 */ { false, 0x92c5, 0x92c5 }, +/* 0x92c6 */ { false, 0x92c6, 0x92c6 }, +/* 0x92c7 */ { false, 0x92c7, 0x92c7 }, +/* 0x92c8 */ { false, 0x92c8, 0x92c8 }, +/* 0x92c9 */ { false, 0x92c9, 0x92c9 }, +/* 0x92ca */ { false, 0x92ca, 0x92ca }, +/* 0x92cb */ { false, 0x92cb, 0x92cb }, +/* 0x92cc */ { false, 0x92cc, 0x92cc }, +/* 0x92cd */ { false, 0x92cd, 0x92cd }, +/* 0x92ce */ { false, 0x92ce, 0x92ce }, +/* 0x92cf */ { false, 0x92cf, 0x92cf }, +/* 0x92d0 */ { false, 0x92d0, 0x92d0 }, +/* 0x92d1 */ { false, 0x92d1, 0x92d1 }, +/* 0x92d2 */ { false, 0x92d2, 0x92d2 }, +/* 0x92d3 */ { false, 0x92d3, 0x92d3 }, +/* 0x92d4 */ { false, 0x92d4, 0x92d4 }, +/* 0x92d5 */ { false, 0x92d5, 0x92d5 }, +/* 0x92d6 */ { false, 0x92d6, 0x92d6 }, +/* 0x92d7 */ { false, 0x92d7, 0x92d7 }, +/* 0x92d8 */ { false, 0x92d8, 0x92d8 }, +/* 0x92d9 */ { false, 0x92d9, 0x92d9 }, +/* 0x92da */ { false, 0x92da, 0x92da }, +/* 0x92db */ { false, 0x92db, 0x92db }, +/* 0x92dc */ { false, 0x92dc, 0x92dc }, +/* 0x92dd */ { false, 0x92dd, 0x92dd }, +/* 0x92de */ { false, 0x92de, 0x92de }, +/* 0x92df */ { false, 0x92df, 0x92df }, +/* 0x92e0 */ { false, 0x92e0, 0x92e0 }, +/* 0x92e1 */ { false, 0x92e1, 0x92e1 }, +/* 0x92e2 */ { false, 0x92e2, 0x92e2 }, +/* 0x92e3 */ { false, 0x92e3, 0x92e3 }, +/* 0x92e4 */ { false, 0x92e4, 0x92e4 }, +/* 0x92e5 */ { false, 0x92e5, 0x92e5 }, +/* 0x92e6 */ { false, 0x92e6, 0x92e6 }, +/* 0x92e7 */ { false, 0x92e7, 0x92e7 }, +/* 0x92e8 */ { false, 0x92e8, 0x92e8 }, +/* 0x92e9 */ { false, 0x92e9, 0x92e9 }, +/* 0x92ea */ { false, 0x92ea, 0x92ea }, +/* 0x92eb */ { false, 0x92eb, 0x92eb }, +/* 0x92ec */ { false, 0x92ec, 0x92ec }, +/* 0x92ed */ { false, 0x92ed, 0x92ed }, +/* 0x92ee */ { false, 0x92ee, 0x92ee }, +/* 0x92ef */ { false, 0x92ef, 0x92ef }, +/* 0x92f0 */ { false, 0x92f0, 0x92f0 }, +/* 0x92f1 */ { false, 0x92f1, 0x92f1 }, +/* 0x92f2 */ { false, 0x92f2, 0x92f2 }, +/* 0x92f3 */ { false, 0x92f3, 0x92f3 }, +/* 0x92f4 */ { false, 0x92f4, 0x92f4 }, +/* 0x92f5 */ { false, 0x92f5, 0x92f5 }, +/* 0x92f6 */ { false, 0x92f6, 0x92f6 }, +/* 0x92f7 */ { false, 0x92f7, 0x92f7 }, +/* 0x92f8 */ { false, 0x92f8, 0x92f8 }, +/* 0x92f9 */ { false, 0x92f9, 0x92f9 }, +/* 0x92fa */ { false, 0x92fa, 0x92fa }, +/* 0x92fb */ { false, 0x92fb, 0x92fb }, +/* 0x92fc */ { false, 0x92fc, 0x92fc }, +/* 0x92fd */ { false, 0x92fd, 0x92fd }, +/* 0x92fe */ { false, 0x92fe, 0x92fe }, +/* 0x92ff */ { false, 0x92ff, 0x92ff }, +/* 0x9300 */ { false, 0x9300, 0x9300 }, +/* 0x9301 */ { false, 0x9301, 0x9301 }, +/* 0x9302 */ { false, 0x9302, 0x9302 }, +/* 0x9303 */ { false, 0x9303, 0x9303 }, +/* 0x9304 */ { false, 0x9304, 0x9304 }, +/* 0x9305 */ { false, 0x9305, 0x9305 }, +/* 0x9306 */ { false, 0x9306, 0x9306 }, +/* 0x9307 */ { false, 0x9307, 0x9307 }, +/* 0x9308 */ { false, 0x9308, 0x9308 }, +/* 0x9309 */ { false, 0x9309, 0x9309 }, +/* 0x930a */ { false, 0x930a, 0x930a }, +/* 0x930b */ { false, 0x930b, 0x930b }, +/* 0x930c */ { false, 0x930c, 0x930c }, +/* 0x930d */ { false, 0x930d, 0x930d }, +/* 0x930e */ { false, 0x930e, 0x930e }, +/* 0x930f */ { false, 0x930f, 0x930f }, +/* 0x9310 */ { false, 0x9310, 0x9310 }, +/* 0x9311 */ { false, 0x9311, 0x9311 }, +/* 0x9312 */ { false, 0x9312, 0x9312 }, +/* 0x9313 */ { false, 0x9313, 0x9313 }, +/* 0x9314 */ { false, 0x9314, 0x9314 }, +/* 0x9315 */ { false, 0x9315, 0x9315 }, +/* 0x9316 */ { false, 0x9316, 0x9316 }, +/* 0x9317 */ { false, 0x9317, 0x9317 }, +/* 0x9318 */ { false, 0x9318, 0x9318 }, +/* 0x9319 */ { false, 0x9319, 0x9319 }, +/* 0x931a */ { false, 0x931a, 0x931a }, +/* 0x931b */ { false, 0x931b, 0x931b }, +/* 0x931c */ { false, 0x931c, 0x931c }, +/* 0x931d */ { false, 0x931d, 0x931d }, +/* 0x931e */ { false, 0x931e, 0x931e }, +/* 0x931f */ { false, 0x931f, 0x931f }, +/* 0x9320 */ { false, 0x9320, 0x9320 }, +/* 0x9321 */ { false, 0x9321, 0x9321 }, +/* 0x9322 */ { false, 0x9322, 0x9322 }, +/* 0x9323 */ { false, 0x9323, 0x9323 }, +/* 0x9324 */ { false, 0x9324, 0x9324 }, +/* 0x9325 */ { false, 0x9325, 0x9325 }, +/* 0x9326 */ { false, 0x9326, 0x9326 }, +/* 0x9327 */ { false, 0x9327, 0x9327 }, +/* 0x9328 */ { false, 0x9328, 0x9328 }, +/* 0x9329 */ { false, 0x9329, 0x9329 }, +/* 0x932a */ { false, 0x932a, 0x932a }, +/* 0x932b */ { false, 0x932b, 0x932b }, +/* 0x932c */ { false, 0x932c, 0x932c }, +/* 0x932d */ { false, 0x932d, 0x932d }, +/* 0x932e */ { false, 0x932e, 0x932e }, +/* 0x932f */ { false, 0x932f, 0x932f }, +/* 0x9330 */ { false, 0x9330, 0x9330 }, +/* 0x9331 */ { false, 0x9331, 0x9331 }, +/* 0x9332 */ { false, 0x9332, 0x9332 }, +/* 0x9333 */ { false, 0x9333, 0x9333 }, +/* 0x9334 */ { false, 0x9334, 0x9334 }, +/* 0x9335 */ { false, 0x9335, 0x9335 }, +/* 0x9336 */ { false, 0x9336, 0x9336 }, +/* 0x9337 */ { false, 0x9337, 0x9337 }, +/* 0x9338 */ { false, 0x9338, 0x9338 }, +/* 0x9339 */ { false, 0x9339, 0x9339 }, +/* 0x933a */ { false, 0x933a, 0x933a }, +/* 0x933b */ { false, 0x933b, 0x933b }, +/* 0x933c */ { false, 0x933c, 0x933c }, +/* 0x933d */ { false, 0x933d, 0x933d }, +/* 0x933e */ { false, 0x933e, 0x933e }, +/* 0x933f */ { false, 0x933f, 0x933f }, +/* 0x9340 */ { false, 0x9340, 0x9340 }, +/* 0x9341 */ { false, 0x9341, 0x9341 }, +/* 0x9342 */ { false, 0x9342, 0x9342 }, +/* 0x9343 */ { false, 0x9343, 0x9343 }, +/* 0x9344 */ { false, 0x9344, 0x9344 }, +/* 0x9345 */ { false, 0x9345, 0x9345 }, +/* 0x9346 */ { false, 0x9346, 0x9346 }, +/* 0x9347 */ { false, 0x9347, 0x9347 }, +/* 0x9348 */ { false, 0x9348, 0x9348 }, +/* 0x9349 */ { false, 0x9349, 0x9349 }, +/* 0x934a */ { false, 0x934a, 0x934a }, +/* 0x934b */ { false, 0x934b, 0x934b }, +/* 0x934c */ { false, 0x934c, 0x934c }, +/* 0x934d */ { false, 0x934d, 0x934d }, +/* 0x934e */ { false, 0x934e, 0x934e }, +/* 0x934f */ { false, 0x934f, 0x934f }, +/* 0x9350 */ { false, 0x9350, 0x9350 }, +/* 0x9351 */ { false, 0x9351, 0x9351 }, +/* 0x9352 */ { false, 0x9352, 0x9352 }, +/* 0x9353 */ { false, 0x9353, 0x9353 }, +/* 0x9354 */ { false, 0x9354, 0x9354 }, +/* 0x9355 */ { false, 0x9355, 0x9355 }, +/* 0x9356 */ { false, 0x9356, 0x9356 }, +/* 0x9357 */ { false, 0x9357, 0x9357 }, +/* 0x9358 */ { false, 0x9358, 0x9358 }, +/* 0x9359 */ { false, 0x9359, 0x9359 }, +/* 0x935a */ { false, 0x935a, 0x935a }, +/* 0x935b */ { false, 0x935b, 0x935b }, +/* 0x935c */ { false, 0x935c, 0x935c }, +/* 0x935d */ { false, 0x935d, 0x935d }, +/* 0x935e */ { false, 0x935e, 0x935e }, +/* 0x935f */ { false, 0x935f, 0x935f }, +/* 0x9360 */ { false, 0x9360, 0x9360 }, +/* 0x9361 */ { false, 0x9361, 0x9361 }, +/* 0x9362 */ { false, 0x9362, 0x9362 }, +/* 0x9363 */ { false, 0x9363, 0x9363 }, +/* 0x9364 */ { false, 0x9364, 0x9364 }, +/* 0x9365 */ { false, 0x9365, 0x9365 }, +/* 0x9366 */ { false, 0x9366, 0x9366 }, +/* 0x9367 */ { false, 0x9367, 0x9367 }, +/* 0x9368 */ { false, 0x9368, 0x9368 }, +/* 0x9369 */ { false, 0x9369, 0x9369 }, +/* 0x936a */ { false, 0x936a, 0x936a }, +/* 0x936b */ { false, 0x936b, 0x936b }, +/* 0x936c */ { false, 0x936c, 0x936c }, +/* 0x936d */ { false, 0x936d, 0x936d }, +/* 0x936e */ { false, 0x936e, 0x936e }, +/* 0x936f */ { false, 0x936f, 0x936f }, +/* 0x9370 */ { false, 0x9370, 0x9370 }, +/* 0x9371 */ { false, 0x9371, 0x9371 }, +/* 0x9372 */ { false, 0x9372, 0x9372 }, +/* 0x9373 */ { false, 0x9373, 0x9373 }, +/* 0x9374 */ { false, 0x9374, 0x9374 }, +/* 0x9375 */ { false, 0x9375, 0x9375 }, +/* 0x9376 */ { false, 0x9376, 0x9376 }, +/* 0x9377 */ { false, 0x9377, 0x9377 }, +/* 0x9378 */ { false, 0x9378, 0x9378 }, +/* 0x9379 */ { false, 0x9379, 0x9379 }, +/* 0x937a */ { false, 0x937a, 0x937a }, +/* 0x937b */ { false, 0x937b, 0x937b }, +/* 0x937c */ { false, 0x937c, 0x937c }, +/* 0x937d */ { false, 0x937d, 0x937d }, +/* 0x937e */ { false, 0x937e, 0x937e }, +/* 0x937f */ { false, 0x937f, 0x937f }, +/* 0x9380 */ { false, 0x9380, 0x9380 }, +/* 0x9381 */ { false, 0x9381, 0x9381 }, +/* 0x9382 */ { false, 0x9382, 0x9382 }, +/* 0x9383 */ { false, 0x9383, 0x9383 }, +/* 0x9384 */ { false, 0x9384, 0x9384 }, +/* 0x9385 */ { false, 0x9385, 0x9385 }, +/* 0x9386 */ { false, 0x9386, 0x9386 }, +/* 0x9387 */ { false, 0x9387, 0x9387 }, +/* 0x9388 */ { false, 0x9388, 0x9388 }, +/* 0x9389 */ { false, 0x9389, 0x9389 }, +/* 0x938a */ { false, 0x938a, 0x938a }, +/* 0x938b */ { false, 0x938b, 0x938b }, +/* 0x938c */ { false, 0x938c, 0x938c }, +/* 0x938d */ { false, 0x938d, 0x938d }, +/* 0x938e */ { false, 0x938e, 0x938e }, +/* 0x938f */ { false, 0x938f, 0x938f }, +/* 0x9390 */ { false, 0x9390, 0x9390 }, +/* 0x9391 */ { false, 0x9391, 0x9391 }, +/* 0x9392 */ { false, 0x9392, 0x9392 }, +/* 0x9393 */ { false, 0x9393, 0x9393 }, +/* 0x9394 */ { false, 0x9394, 0x9394 }, +/* 0x9395 */ { false, 0x9395, 0x9395 }, +/* 0x9396 */ { false, 0x9396, 0x9396 }, +/* 0x9397 */ { false, 0x9397, 0x9397 }, +/* 0x9398 */ { false, 0x9398, 0x9398 }, +/* 0x9399 */ { false, 0x9399, 0x9399 }, +/* 0x939a */ { false, 0x939a, 0x939a }, +/* 0x939b */ { false, 0x939b, 0x939b }, +/* 0x939c */ { false, 0x939c, 0x939c }, +/* 0x939d */ { false, 0x939d, 0x939d }, +/* 0x939e */ { false, 0x939e, 0x939e }, +/* 0x939f */ { false, 0x939f, 0x939f }, +/* 0x93a0 */ { false, 0x93a0, 0x93a0 }, +/* 0x93a1 */ { false, 0x93a1, 0x93a1 }, +/* 0x93a2 */ { false, 0x93a2, 0x93a2 }, +/* 0x93a3 */ { false, 0x93a3, 0x93a3 }, +/* 0x93a4 */ { false, 0x93a4, 0x93a4 }, +/* 0x93a5 */ { false, 0x93a5, 0x93a5 }, +/* 0x93a6 */ { false, 0x93a6, 0x93a6 }, +/* 0x93a7 */ { false, 0x93a7, 0x93a7 }, +/* 0x93a8 */ { false, 0x93a8, 0x93a8 }, +/* 0x93a9 */ { false, 0x93a9, 0x93a9 }, +/* 0x93aa */ { false, 0x93aa, 0x93aa }, +/* 0x93ab */ { false, 0x93ab, 0x93ab }, +/* 0x93ac */ { false, 0x93ac, 0x93ac }, +/* 0x93ad */ { false, 0x93ad, 0x93ad }, +/* 0x93ae */ { false, 0x93ae, 0x93ae }, +/* 0x93af */ { false, 0x93af, 0x93af }, +/* 0x93b0 */ { false, 0x93b0, 0x93b0 }, +/* 0x93b1 */ { false, 0x93b1, 0x93b1 }, +/* 0x93b2 */ { false, 0x93b2, 0x93b2 }, +/* 0x93b3 */ { false, 0x93b3, 0x93b3 }, +/* 0x93b4 */ { false, 0x93b4, 0x93b4 }, +/* 0x93b5 */ { false, 0x93b5, 0x93b5 }, +/* 0x93b6 */ { false, 0x93b6, 0x93b6 }, +/* 0x93b7 */ { false, 0x93b7, 0x93b7 }, +/* 0x93b8 */ { false, 0x93b8, 0x93b8 }, +/* 0x93b9 */ { false, 0x93b9, 0x93b9 }, +/* 0x93ba */ { false, 0x93ba, 0x93ba }, +/* 0x93bb */ { false, 0x93bb, 0x93bb }, +/* 0x93bc */ { false, 0x93bc, 0x93bc }, +/* 0x93bd */ { false, 0x93bd, 0x93bd }, +/* 0x93be */ { false, 0x93be, 0x93be }, +/* 0x93bf */ { false, 0x93bf, 0x93bf }, +/* 0x93c0 */ { false, 0x93c0, 0x93c0 }, +/* 0x93c1 */ { false, 0x93c1, 0x93c1 }, +/* 0x93c2 */ { false, 0x93c2, 0x93c2 }, +/* 0x93c3 */ { false, 0x93c3, 0x93c3 }, +/* 0x93c4 */ { false, 0x93c4, 0x93c4 }, +/* 0x93c5 */ { false, 0x93c5, 0x93c5 }, +/* 0x93c6 */ { false, 0x93c6, 0x93c6 }, +/* 0x93c7 */ { false, 0x93c7, 0x93c7 }, +/* 0x93c8 */ { false, 0x93c8, 0x93c8 }, +/* 0x93c9 */ { false, 0x93c9, 0x93c9 }, +/* 0x93ca */ { false, 0x93ca, 0x93ca }, +/* 0x93cb */ { false, 0x93cb, 0x93cb }, +/* 0x93cc */ { false, 0x93cc, 0x93cc }, +/* 0x93cd */ { false, 0x93cd, 0x93cd }, +/* 0x93ce */ { false, 0x93ce, 0x93ce }, +/* 0x93cf */ { false, 0x93cf, 0x93cf }, +/* 0x93d0 */ { false, 0x93d0, 0x93d0 }, +/* 0x93d1 */ { false, 0x93d1, 0x93d1 }, +/* 0x93d2 */ { false, 0x93d2, 0x93d2 }, +/* 0x93d3 */ { false, 0x93d3, 0x93d3 }, +/* 0x93d4 */ { false, 0x93d4, 0x93d4 }, +/* 0x93d5 */ { false, 0x93d5, 0x93d5 }, +/* 0x93d6 */ { false, 0x93d6, 0x93d6 }, +/* 0x93d7 */ { false, 0x93d7, 0x93d7 }, +/* 0x93d8 */ { false, 0x93d8, 0x93d8 }, +/* 0x93d9 */ { false, 0x93d9, 0x93d9 }, +/* 0x93da */ { false, 0x93da, 0x93da }, +/* 0x93db */ { false, 0x93db, 0x93db }, +/* 0x93dc */ { false, 0x93dc, 0x93dc }, +/* 0x93dd */ { false, 0x93dd, 0x93dd }, +/* 0x93de */ { false, 0x93de, 0x93de }, +/* 0x93df */ { false, 0x93df, 0x93df }, +/* 0x93e0 */ { false, 0x93e0, 0x93e0 }, +/* 0x93e1 */ { false, 0x93e1, 0x93e1 }, +/* 0x93e2 */ { false, 0x93e2, 0x93e2 }, +/* 0x93e3 */ { false, 0x93e3, 0x93e3 }, +/* 0x93e4 */ { false, 0x93e4, 0x93e4 }, +/* 0x93e5 */ { false, 0x93e5, 0x93e5 }, +/* 0x93e6 */ { false, 0x93e6, 0x93e6 }, +/* 0x93e7 */ { false, 0x93e7, 0x93e7 }, +/* 0x93e8 */ { false, 0x93e8, 0x93e8 }, +/* 0x93e9 */ { false, 0x93e9, 0x93e9 }, +/* 0x93ea */ { false, 0x93ea, 0x93ea }, +/* 0x93eb */ { false, 0x93eb, 0x93eb }, +/* 0x93ec */ { false, 0x93ec, 0x93ec }, +/* 0x93ed */ { false, 0x93ed, 0x93ed }, +/* 0x93ee */ { false, 0x93ee, 0x93ee }, +/* 0x93ef */ { false, 0x93ef, 0x93ef }, +/* 0x93f0 */ { false, 0x93f0, 0x93f0 }, +/* 0x93f1 */ { false, 0x93f1, 0x93f1 }, +/* 0x93f2 */ { false, 0x93f2, 0x93f2 }, +/* 0x93f3 */ { false, 0x93f3, 0x93f3 }, +/* 0x93f4 */ { false, 0x93f4, 0x93f4 }, +/* 0x93f5 */ { false, 0x93f5, 0x93f5 }, +/* 0x93f6 */ { false, 0x93f6, 0x93f6 }, +/* 0x93f7 */ { false, 0x93f7, 0x93f7 }, +/* 0x93f8 */ { false, 0x93f8, 0x93f8 }, +/* 0x93f9 */ { false, 0x93f9, 0x93f9 }, +/* 0x93fa */ { false, 0x93fa, 0x93fa }, +/* 0x93fb */ { false, 0x93fb, 0x93fb }, +/* 0x93fc */ { false, 0x93fc, 0x93fc }, +/* 0x93fd */ { false, 0x93fd, 0x93fd }, +/* 0x93fe */ { false, 0x93fe, 0x93fe }, +/* 0x93ff */ { false, 0x93ff, 0x93ff }, +/* 0x9400 */ { false, 0x9400, 0x9400 }, +/* 0x9401 */ { false, 0x9401, 0x9401 }, +/* 0x9402 */ { false, 0x9402, 0x9402 }, +/* 0x9403 */ { false, 0x9403, 0x9403 }, +/* 0x9404 */ { false, 0x9404, 0x9404 }, +/* 0x9405 */ { false, 0x9405, 0x9405 }, +/* 0x9406 */ { false, 0x9406, 0x9406 }, +/* 0x9407 */ { false, 0x9407, 0x9407 }, +/* 0x9408 */ { false, 0x9408, 0x9408 }, +/* 0x9409 */ { false, 0x9409, 0x9409 }, +/* 0x940a */ { false, 0x940a, 0x940a }, +/* 0x940b */ { false, 0x940b, 0x940b }, +/* 0x940c */ { false, 0x940c, 0x940c }, +/* 0x940d */ { false, 0x940d, 0x940d }, +/* 0x940e */ { false, 0x940e, 0x940e }, +/* 0x940f */ { false, 0x940f, 0x940f }, +/* 0x9410 */ { false, 0x9410, 0x9410 }, +/* 0x9411 */ { false, 0x9411, 0x9411 }, +/* 0x9412 */ { false, 0x9412, 0x9412 }, +/* 0x9413 */ { false, 0x9413, 0x9413 }, +/* 0x9414 */ { false, 0x9414, 0x9414 }, +/* 0x9415 */ { false, 0x9415, 0x9415 }, +/* 0x9416 */ { false, 0x9416, 0x9416 }, +/* 0x9417 */ { false, 0x9417, 0x9417 }, +/* 0x9418 */ { false, 0x9418, 0x9418 }, +/* 0x9419 */ { false, 0x9419, 0x9419 }, +/* 0x941a */ { false, 0x941a, 0x941a }, +/* 0x941b */ { false, 0x941b, 0x941b }, +/* 0x941c */ { false, 0x941c, 0x941c }, +/* 0x941d */ { false, 0x941d, 0x941d }, +/* 0x941e */ { false, 0x941e, 0x941e }, +/* 0x941f */ { false, 0x941f, 0x941f }, +/* 0x9420 */ { false, 0x9420, 0x9420 }, +/* 0x9421 */ { false, 0x9421, 0x9421 }, +/* 0x9422 */ { false, 0x9422, 0x9422 }, +/* 0x9423 */ { false, 0x9423, 0x9423 }, +/* 0x9424 */ { false, 0x9424, 0x9424 }, +/* 0x9425 */ { false, 0x9425, 0x9425 }, +/* 0x9426 */ { false, 0x9426, 0x9426 }, +/* 0x9427 */ { false, 0x9427, 0x9427 }, +/* 0x9428 */ { false, 0x9428, 0x9428 }, +/* 0x9429 */ { false, 0x9429, 0x9429 }, +/* 0x942a */ { false, 0x942a, 0x942a }, +/* 0x942b */ { false, 0x942b, 0x942b }, +/* 0x942c */ { false, 0x942c, 0x942c }, +/* 0x942d */ { false, 0x942d, 0x942d }, +/* 0x942e */ { false, 0x942e, 0x942e }, +/* 0x942f */ { false, 0x942f, 0x942f }, +/* 0x9430 */ { false, 0x9430, 0x9430 }, +/* 0x9431 */ { false, 0x9431, 0x9431 }, +/* 0x9432 */ { false, 0x9432, 0x9432 }, +/* 0x9433 */ { false, 0x9433, 0x9433 }, +/* 0x9434 */ { false, 0x9434, 0x9434 }, +/* 0x9435 */ { false, 0x9435, 0x9435 }, +/* 0x9436 */ { false, 0x9436, 0x9436 }, +/* 0x9437 */ { false, 0x9437, 0x9437 }, +/* 0x9438 */ { false, 0x9438, 0x9438 }, +/* 0x9439 */ { false, 0x9439, 0x9439 }, +/* 0x943a */ { false, 0x943a, 0x943a }, +/* 0x943b */ { false, 0x943b, 0x943b }, +/* 0x943c */ { false, 0x943c, 0x943c }, +/* 0x943d */ { false, 0x943d, 0x943d }, +/* 0x943e */ { false, 0x943e, 0x943e }, +/* 0x943f */ { false, 0x943f, 0x943f }, +/* 0x9440 */ { false, 0x9440, 0x9440 }, +/* 0x9441 */ { false, 0x9441, 0x9441 }, +/* 0x9442 */ { false, 0x9442, 0x9442 }, +/* 0x9443 */ { false, 0x9443, 0x9443 }, +/* 0x9444 */ { false, 0x9444, 0x9444 }, +/* 0x9445 */ { false, 0x9445, 0x9445 }, +/* 0x9446 */ { false, 0x9446, 0x9446 }, +/* 0x9447 */ { false, 0x9447, 0x9447 }, +/* 0x9448 */ { false, 0x9448, 0x9448 }, +/* 0x9449 */ { false, 0x9449, 0x9449 }, +/* 0x944a */ { false, 0x944a, 0x944a }, +/* 0x944b */ { false, 0x944b, 0x944b }, +/* 0x944c */ { false, 0x944c, 0x944c }, +/* 0x944d */ { false, 0x944d, 0x944d }, +/* 0x944e */ { false, 0x944e, 0x944e }, +/* 0x944f */ { false, 0x944f, 0x944f }, +/* 0x9450 */ { false, 0x9450, 0x9450 }, +/* 0x9451 */ { false, 0x9451, 0x9451 }, +/* 0x9452 */ { false, 0x9452, 0x9452 }, +/* 0x9453 */ { false, 0x9453, 0x9453 }, +/* 0x9454 */ { false, 0x9454, 0x9454 }, +/* 0x9455 */ { false, 0x9455, 0x9455 }, +/* 0x9456 */ { false, 0x9456, 0x9456 }, +/* 0x9457 */ { false, 0x9457, 0x9457 }, +/* 0x9458 */ { false, 0x9458, 0x9458 }, +/* 0x9459 */ { false, 0x9459, 0x9459 }, +/* 0x945a */ { false, 0x945a, 0x945a }, +/* 0x945b */ { false, 0x945b, 0x945b }, +/* 0x945c */ { false, 0x945c, 0x945c }, +/* 0x945d */ { false, 0x945d, 0x945d }, +/* 0x945e */ { false, 0x945e, 0x945e }, +/* 0x945f */ { false, 0x945f, 0x945f }, +/* 0x9460 */ { false, 0x9460, 0x9460 }, +/* 0x9461 */ { false, 0x9461, 0x9461 }, +/* 0x9462 */ { false, 0x9462, 0x9462 }, +/* 0x9463 */ { false, 0x9463, 0x9463 }, +/* 0x9464 */ { false, 0x9464, 0x9464 }, +/* 0x9465 */ { false, 0x9465, 0x9465 }, +/* 0x9466 */ { false, 0x9466, 0x9466 }, +/* 0x9467 */ { false, 0x9467, 0x9467 }, +/* 0x9468 */ { false, 0x9468, 0x9468 }, +/* 0x9469 */ { false, 0x9469, 0x9469 }, +/* 0x946a */ { false, 0x946a, 0x946a }, +/* 0x946b */ { false, 0x946b, 0x946b }, +/* 0x946c */ { false, 0x946c, 0x946c }, +/* 0x946d */ { false, 0x946d, 0x946d }, +/* 0x946e */ { false, 0x946e, 0x946e }, +/* 0x946f */ { false, 0x946f, 0x946f }, +/* 0x9470 */ { false, 0x9470, 0x9470 }, +/* 0x9471 */ { false, 0x9471, 0x9471 }, +/* 0x9472 */ { false, 0x9472, 0x9472 }, +/* 0x9473 */ { false, 0x9473, 0x9473 }, +/* 0x9474 */ { false, 0x9474, 0x9474 }, +/* 0x9475 */ { false, 0x9475, 0x9475 }, +/* 0x9476 */ { false, 0x9476, 0x9476 }, +/* 0x9477 */ { false, 0x9477, 0x9477 }, +/* 0x9478 */ { false, 0x9478, 0x9478 }, +/* 0x9479 */ { false, 0x9479, 0x9479 }, +/* 0x947a */ { false, 0x947a, 0x947a }, +/* 0x947b */ { false, 0x947b, 0x947b }, +/* 0x947c */ { false, 0x947c, 0x947c }, +/* 0x947d */ { false, 0x947d, 0x947d }, +/* 0x947e */ { false, 0x947e, 0x947e }, +/* 0x947f */ { false, 0x947f, 0x947f }, +/* 0x9480 */ { false, 0x9480, 0x9480 }, +/* 0x9481 */ { false, 0x9481, 0x9481 }, +/* 0x9482 */ { false, 0x9482, 0x9482 }, +/* 0x9483 */ { false, 0x9483, 0x9483 }, +/* 0x9484 */ { false, 0x9484, 0x9484 }, +/* 0x9485 */ { false, 0x9485, 0x9485 }, +/* 0x9486 */ { false, 0x9486, 0x9486 }, +/* 0x9487 */ { false, 0x9487, 0x9487 }, +/* 0x9488 */ { false, 0x9488, 0x9488 }, +/* 0x9489 */ { false, 0x9489, 0x9489 }, +/* 0x948a */ { false, 0x948a, 0x948a }, +/* 0x948b */ { false, 0x948b, 0x948b }, +/* 0x948c */ { false, 0x948c, 0x948c }, +/* 0x948d */ { false, 0x948d, 0x948d }, +/* 0x948e */ { false, 0x948e, 0x948e }, +/* 0x948f */ { false, 0x948f, 0x948f }, +/* 0x9490 */ { false, 0x9490, 0x9490 }, +/* 0x9491 */ { false, 0x9491, 0x9491 }, +/* 0x9492 */ { false, 0x9492, 0x9492 }, +/* 0x9493 */ { false, 0x9493, 0x9493 }, +/* 0x9494 */ { false, 0x9494, 0x9494 }, +/* 0x9495 */ { false, 0x9495, 0x9495 }, +/* 0x9496 */ { false, 0x9496, 0x9496 }, +/* 0x9497 */ { false, 0x9497, 0x9497 }, +/* 0x9498 */ { false, 0x9498, 0x9498 }, +/* 0x9499 */ { false, 0x9499, 0x9499 }, +/* 0x949a */ { false, 0x949a, 0x949a }, +/* 0x949b */ { false, 0x949b, 0x949b }, +/* 0x949c */ { false, 0x949c, 0x949c }, +/* 0x949d */ { false, 0x949d, 0x949d }, +/* 0x949e */ { false, 0x949e, 0x949e }, +/* 0x949f */ { false, 0x949f, 0x949f }, +/* 0x94a0 */ { false, 0x94a0, 0x94a0 }, +/* 0x94a1 */ { false, 0x94a1, 0x94a1 }, +/* 0x94a2 */ { false, 0x94a2, 0x94a2 }, +/* 0x94a3 */ { false, 0x94a3, 0x94a3 }, +/* 0x94a4 */ { false, 0x94a4, 0x94a4 }, +/* 0x94a5 */ { false, 0x94a5, 0x94a5 }, +/* 0x94a6 */ { false, 0x94a6, 0x94a6 }, +/* 0x94a7 */ { false, 0x94a7, 0x94a7 }, +/* 0x94a8 */ { false, 0x94a8, 0x94a8 }, +/* 0x94a9 */ { false, 0x94a9, 0x94a9 }, +/* 0x94aa */ { false, 0x94aa, 0x94aa }, +/* 0x94ab */ { false, 0x94ab, 0x94ab }, +/* 0x94ac */ { false, 0x94ac, 0x94ac }, +/* 0x94ad */ { false, 0x94ad, 0x94ad }, +/* 0x94ae */ { false, 0x94ae, 0x94ae }, +/* 0x94af */ { false, 0x94af, 0x94af }, +/* 0x94b0 */ { false, 0x94b0, 0x94b0 }, +/* 0x94b1 */ { false, 0x94b1, 0x94b1 }, +/* 0x94b2 */ { false, 0x94b2, 0x94b2 }, +/* 0x94b3 */ { false, 0x94b3, 0x94b3 }, +/* 0x94b4 */ { false, 0x94b4, 0x94b4 }, +/* 0x94b5 */ { false, 0x94b5, 0x94b5 }, +/* 0x94b6 */ { false, 0x94b6, 0x94b6 }, +/* 0x94b7 */ { false, 0x94b7, 0x94b7 }, +/* 0x94b8 */ { false, 0x94b8, 0x94b8 }, +/* 0x94b9 */ { false, 0x94b9, 0x94b9 }, +/* 0x94ba */ { false, 0x94ba, 0x94ba }, +/* 0x94bb */ { false, 0x94bb, 0x94bb }, +/* 0x94bc */ { false, 0x94bc, 0x94bc }, +/* 0x94bd */ { false, 0x94bd, 0x94bd }, +/* 0x94be */ { false, 0x94be, 0x94be }, +/* 0x94bf */ { false, 0x94bf, 0x94bf }, +/* 0x94c0 */ { false, 0x94c0, 0x94c0 }, +/* 0x94c1 */ { false, 0x94c1, 0x94c1 }, +/* 0x94c2 */ { false, 0x94c2, 0x94c2 }, +/* 0x94c3 */ { false, 0x94c3, 0x94c3 }, +/* 0x94c4 */ { false, 0x94c4, 0x94c4 }, +/* 0x94c5 */ { false, 0x94c5, 0x94c5 }, +/* 0x94c6 */ { false, 0x94c6, 0x94c6 }, +/* 0x94c7 */ { false, 0x94c7, 0x94c7 }, +/* 0x94c8 */ { false, 0x94c8, 0x94c8 }, +/* 0x94c9 */ { false, 0x94c9, 0x94c9 }, +/* 0x94ca */ { false, 0x94ca, 0x94ca }, +/* 0x94cb */ { false, 0x94cb, 0x94cb }, +/* 0x94cc */ { false, 0x94cc, 0x94cc }, +/* 0x94cd */ { false, 0x94cd, 0x94cd }, +/* 0x94ce */ { false, 0x94ce, 0x94ce }, +/* 0x94cf */ { false, 0x94cf, 0x94cf }, +/* 0x94d0 */ { false, 0x94d0, 0x94d0 }, +/* 0x94d1 */ { false, 0x94d1, 0x94d1 }, +/* 0x94d2 */ { false, 0x94d2, 0x94d2 }, +/* 0x94d3 */ { false, 0x94d3, 0x94d3 }, +/* 0x94d4 */ { false, 0x94d4, 0x94d4 }, +/* 0x94d5 */ { false, 0x94d5, 0x94d5 }, +/* 0x94d6 */ { false, 0x94d6, 0x94d6 }, +/* 0x94d7 */ { false, 0x94d7, 0x94d7 }, +/* 0x94d8 */ { false, 0x94d8, 0x94d8 }, +/* 0x94d9 */ { false, 0x94d9, 0x94d9 }, +/* 0x94da */ { false, 0x94da, 0x94da }, +/* 0x94db */ { false, 0x94db, 0x94db }, +/* 0x94dc */ { false, 0x94dc, 0x94dc }, +/* 0x94dd */ { false, 0x94dd, 0x94dd }, +/* 0x94de */ { false, 0x94de, 0x94de }, +/* 0x94df */ { false, 0x94df, 0x94df }, +/* 0x94e0 */ { false, 0x94e0, 0x94e0 }, +/* 0x94e1 */ { false, 0x94e1, 0x94e1 }, +/* 0x94e2 */ { false, 0x94e2, 0x94e2 }, +/* 0x94e3 */ { false, 0x94e3, 0x94e3 }, +/* 0x94e4 */ { false, 0x94e4, 0x94e4 }, +/* 0x94e5 */ { false, 0x94e5, 0x94e5 }, +/* 0x94e6 */ { false, 0x94e6, 0x94e6 }, +/* 0x94e7 */ { false, 0x94e7, 0x94e7 }, +/* 0x94e8 */ { false, 0x94e8, 0x94e8 }, +/* 0x94e9 */ { false, 0x94e9, 0x94e9 }, +/* 0x94ea */ { false, 0x94ea, 0x94ea }, +/* 0x94eb */ { false, 0x94eb, 0x94eb }, +/* 0x94ec */ { false, 0x94ec, 0x94ec }, +/* 0x94ed */ { false, 0x94ed, 0x94ed }, +/* 0x94ee */ { false, 0x94ee, 0x94ee }, +/* 0x94ef */ { false, 0x94ef, 0x94ef }, +/* 0x94f0 */ { false, 0x94f0, 0x94f0 }, +/* 0x94f1 */ { false, 0x94f1, 0x94f1 }, +/* 0x94f2 */ { false, 0x94f2, 0x94f2 }, +/* 0x94f3 */ { false, 0x94f3, 0x94f3 }, +/* 0x94f4 */ { false, 0x94f4, 0x94f4 }, +/* 0x94f5 */ { false, 0x94f5, 0x94f5 }, +/* 0x94f6 */ { false, 0x94f6, 0x94f6 }, +/* 0x94f7 */ { false, 0x94f7, 0x94f7 }, +/* 0x94f8 */ { false, 0x94f8, 0x94f8 }, +/* 0x94f9 */ { false, 0x94f9, 0x94f9 }, +/* 0x94fa */ { false, 0x94fa, 0x94fa }, +/* 0x94fb */ { false, 0x94fb, 0x94fb }, +/* 0x94fc */ { false, 0x94fc, 0x94fc }, +/* 0x94fd */ { false, 0x94fd, 0x94fd }, +/* 0x94fe */ { false, 0x94fe, 0x94fe }, +/* 0x94ff */ { false, 0x94ff, 0x94ff }, +/* 0x9500 */ { false, 0x9500, 0x9500 }, +/* 0x9501 */ { false, 0x9501, 0x9501 }, +/* 0x9502 */ { false, 0x9502, 0x9502 }, +/* 0x9503 */ { false, 0x9503, 0x9503 }, +/* 0x9504 */ { false, 0x9504, 0x9504 }, +/* 0x9505 */ { false, 0x9505, 0x9505 }, +/* 0x9506 */ { false, 0x9506, 0x9506 }, +/* 0x9507 */ { false, 0x9507, 0x9507 }, +/* 0x9508 */ { false, 0x9508, 0x9508 }, +/* 0x9509 */ { false, 0x9509, 0x9509 }, +/* 0x950a */ { false, 0x950a, 0x950a }, +/* 0x950b */ { false, 0x950b, 0x950b }, +/* 0x950c */ { false, 0x950c, 0x950c }, +/* 0x950d */ { false, 0x950d, 0x950d }, +/* 0x950e */ { false, 0x950e, 0x950e }, +/* 0x950f */ { false, 0x950f, 0x950f }, +/* 0x9510 */ { false, 0x9510, 0x9510 }, +/* 0x9511 */ { false, 0x9511, 0x9511 }, +/* 0x9512 */ { false, 0x9512, 0x9512 }, +/* 0x9513 */ { false, 0x9513, 0x9513 }, +/* 0x9514 */ { false, 0x9514, 0x9514 }, +/* 0x9515 */ { false, 0x9515, 0x9515 }, +/* 0x9516 */ { false, 0x9516, 0x9516 }, +/* 0x9517 */ { false, 0x9517, 0x9517 }, +/* 0x9518 */ { false, 0x9518, 0x9518 }, +/* 0x9519 */ { false, 0x9519, 0x9519 }, +/* 0x951a */ { false, 0x951a, 0x951a }, +/* 0x951b */ { false, 0x951b, 0x951b }, +/* 0x951c */ { false, 0x951c, 0x951c }, +/* 0x951d */ { false, 0x951d, 0x951d }, +/* 0x951e */ { false, 0x951e, 0x951e }, +/* 0x951f */ { false, 0x951f, 0x951f }, +/* 0x9520 */ { false, 0x9520, 0x9520 }, +/* 0x9521 */ { false, 0x9521, 0x9521 }, +/* 0x9522 */ { false, 0x9522, 0x9522 }, +/* 0x9523 */ { false, 0x9523, 0x9523 }, +/* 0x9524 */ { false, 0x9524, 0x9524 }, +/* 0x9525 */ { false, 0x9525, 0x9525 }, +/* 0x9526 */ { false, 0x9526, 0x9526 }, +/* 0x9527 */ { false, 0x9527, 0x9527 }, +/* 0x9528 */ { false, 0x9528, 0x9528 }, +/* 0x9529 */ { false, 0x9529, 0x9529 }, +/* 0x952a */ { false, 0x952a, 0x952a }, +/* 0x952b */ { false, 0x952b, 0x952b }, +/* 0x952c */ { false, 0x952c, 0x952c }, +/* 0x952d */ { false, 0x952d, 0x952d }, +/* 0x952e */ { false, 0x952e, 0x952e }, +/* 0x952f */ { false, 0x952f, 0x952f }, +/* 0x9530 */ { false, 0x9530, 0x9530 }, +/* 0x9531 */ { false, 0x9531, 0x9531 }, +/* 0x9532 */ { false, 0x9532, 0x9532 }, +/* 0x9533 */ { false, 0x9533, 0x9533 }, +/* 0x9534 */ { false, 0x9534, 0x9534 }, +/* 0x9535 */ { false, 0x9535, 0x9535 }, +/* 0x9536 */ { false, 0x9536, 0x9536 }, +/* 0x9537 */ { false, 0x9537, 0x9537 }, +/* 0x9538 */ { false, 0x9538, 0x9538 }, +/* 0x9539 */ { false, 0x9539, 0x9539 }, +/* 0x953a */ { false, 0x953a, 0x953a }, +/* 0x953b */ { false, 0x953b, 0x953b }, +/* 0x953c */ { false, 0x953c, 0x953c }, +/* 0x953d */ { false, 0x953d, 0x953d }, +/* 0x953e */ { false, 0x953e, 0x953e }, +/* 0x953f */ { false, 0x953f, 0x953f }, +/* 0x9540 */ { false, 0x9540, 0x9540 }, +/* 0x9541 */ { false, 0x9541, 0x9541 }, +/* 0x9542 */ { false, 0x9542, 0x9542 }, +/* 0x9543 */ { false, 0x9543, 0x9543 }, +/* 0x9544 */ { false, 0x9544, 0x9544 }, +/* 0x9545 */ { false, 0x9545, 0x9545 }, +/* 0x9546 */ { false, 0x9546, 0x9546 }, +/* 0x9547 */ { false, 0x9547, 0x9547 }, +/* 0x9548 */ { false, 0x9548, 0x9548 }, +/* 0x9549 */ { false, 0x9549, 0x9549 }, +/* 0x954a */ { false, 0x954a, 0x954a }, +/* 0x954b */ { false, 0x954b, 0x954b }, +/* 0x954c */ { false, 0x954c, 0x954c }, +/* 0x954d */ { false, 0x954d, 0x954d }, +/* 0x954e */ { false, 0x954e, 0x954e }, +/* 0x954f */ { false, 0x954f, 0x954f }, +/* 0x9550 */ { false, 0x9550, 0x9550 }, +/* 0x9551 */ { false, 0x9551, 0x9551 }, +/* 0x9552 */ { false, 0x9552, 0x9552 }, +/* 0x9553 */ { false, 0x9553, 0x9553 }, +/* 0x9554 */ { false, 0x9554, 0x9554 }, +/* 0x9555 */ { false, 0x9555, 0x9555 }, +/* 0x9556 */ { false, 0x9556, 0x9556 }, +/* 0x9557 */ { false, 0x9557, 0x9557 }, +/* 0x9558 */ { false, 0x9558, 0x9558 }, +/* 0x9559 */ { false, 0x9559, 0x9559 }, +/* 0x955a */ { false, 0x955a, 0x955a }, +/* 0x955b */ { false, 0x955b, 0x955b }, +/* 0x955c */ { false, 0x955c, 0x955c }, +/* 0x955d */ { false, 0x955d, 0x955d }, +/* 0x955e */ { false, 0x955e, 0x955e }, +/* 0x955f */ { false, 0x955f, 0x955f }, +/* 0x9560 */ { false, 0x9560, 0x9560 }, +/* 0x9561 */ { false, 0x9561, 0x9561 }, +/* 0x9562 */ { false, 0x9562, 0x9562 }, +/* 0x9563 */ { false, 0x9563, 0x9563 }, +/* 0x9564 */ { false, 0x9564, 0x9564 }, +/* 0x9565 */ { false, 0x9565, 0x9565 }, +/* 0x9566 */ { false, 0x9566, 0x9566 }, +/* 0x9567 */ { false, 0x9567, 0x9567 }, +/* 0x9568 */ { false, 0x9568, 0x9568 }, +/* 0x9569 */ { false, 0x9569, 0x9569 }, +/* 0x956a */ { false, 0x956a, 0x956a }, +/* 0x956b */ { false, 0x956b, 0x956b }, +/* 0x956c */ { false, 0x956c, 0x956c }, +/* 0x956d */ { false, 0x956d, 0x956d }, +/* 0x956e */ { false, 0x956e, 0x956e }, +/* 0x956f */ { false, 0x956f, 0x956f }, +/* 0x9570 */ { false, 0x9570, 0x9570 }, +/* 0x9571 */ { false, 0x9571, 0x9571 }, +/* 0x9572 */ { false, 0x9572, 0x9572 }, +/* 0x9573 */ { false, 0x9573, 0x9573 }, +/* 0x9574 */ { false, 0x9574, 0x9574 }, +/* 0x9575 */ { false, 0x9575, 0x9575 }, +/* 0x9576 */ { false, 0x9576, 0x9576 }, +/* 0x9577 */ { false, 0x9577, 0x9577 }, +/* 0x9578 */ { false, 0x9578, 0x9578 }, +/* 0x9579 */ { false, 0x9579, 0x9579 }, +/* 0x957a */ { false, 0x957a, 0x957a }, +/* 0x957b */ { false, 0x957b, 0x957b }, +/* 0x957c */ { false, 0x957c, 0x957c }, +/* 0x957d */ { false, 0x957d, 0x957d }, +/* 0x957e */ { false, 0x957e, 0x957e }, +/* 0x957f */ { false, 0x957f, 0x957f }, +/* 0x9580 */ { false, 0x9580, 0x9580 }, +/* 0x9581 */ { false, 0x9581, 0x9581 }, +/* 0x9582 */ { false, 0x9582, 0x9582 }, +/* 0x9583 */ { false, 0x9583, 0x9583 }, +/* 0x9584 */ { false, 0x9584, 0x9584 }, +/* 0x9585 */ { false, 0x9585, 0x9585 }, +/* 0x9586 */ { false, 0x9586, 0x9586 }, +/* 0x9587 */ { false, 0x9587, 0x9587 }, +/* 0x9588 */ { false, 0x9588, 0x9588 }, +/* 0x9589 */ { false, 0x9589, 0x9589 }, +/* 0x958a */ { false, 0x958a, 0x958a }, +/* 0x958b */ { false, 0x958b, 0x958b }, +/* 0x958c */ { false, 0x958c, 0x958c }, +/* 0x958d */ { false, 0x958d, 0x958d }, +/* 0x958e */ { false, 0x958e, 0x958e }, +/* 0x958f */ { false, 0x958f, 0x958f }, +/* 0x9590 */ { false, 0x9590, 0x9590 }, +/* 0x9591 */ { false, 0x9591, 0x9591 }, +/* 0x9592 */ { false, 0x9592, 0x9592 }, +/* 0x9593 */ { false, 0x9593, 0x9593 }, +/* 0x9594 */ { false, 0x9594, 0x9594 }, +/* 0x9595 */ { false, 0x9595, 0x9595 }, +/* 0x9596 */ { false, 0x9596, 0x9596 }, +/* 0x9597 */ { false, 0x9597, 0x9597 }, +/* 0x9598 */ { false, 0x9598, 0x9598 }, +/* 0x9599 */ { false, 0x9599, 0x9599 }, +/* 0x959a */ { false, 0x959a, 0x959a }, +/* 0x959b */ { false, 0x959b, 0x959b }, +/* 0x959c */ { false, 0x959c, 0x959c }, +/* 0x959d */ { false, 0x959d, 0x959d }, +/* 0x959e */ { false, 0x959e, 0x959e }, +/* 0x959f */ { false, 0x959f, 0x959f }, +/* 0x95a0 */ { false, 0x95a0, 0x95a0 }, +/* 0x95a1 */ { false, 0x95a1, 0x95a1 }, +/* 0x95a2 */ { false, 0x95a2, 0x95a2 }, +/* 0x95a3 */ { false, 0x95a3, 0x95a3 }, +/* 0x95a4 */ { false, 0x95a4, 0x95a4 }, +/* 0x95a5 */ { false, 0x95a5, 0x95a5 }, +/* 0x95a6 */ { false, 0x95a6, 0x95a6 }, +/* 0x95a7 */ { false, 0x95a7, 0x95a7 }, +/* 0x95a8 */ { false, 0x95a8, 0x95a8 }, +/* 0x95a9 */ { false, 0x95a9, 0x95a9 }, +/* 0x95aa */ { false, 0x95aa, 0x95aa }, +/* 0x95ab */ { false, 0x95ab, 0x95ab }, +/* 0x95ac */ { false, 0x95ac, 0x95ac }, +/* 0x95ad */ { false, 0x95ad, 0x95ad }, +/* 0x95ae */ { false, 0x95ae, 0x95ae }, +/* 0x95af */ { false, 0x95af, 0x95af }, +/* 0x95b0 */ { false, 0x95b0, 0x95b0 }, +/* 0x95b1 */ { false, 0x95b1, 0x95b1 }, +/* 0x95b2 */ { false, 0x95b2, 0x95b2 }, +/* 0x95b3 */ { false, 0x95b3, 0x95b3 }, +/* 0x95b4 */ { false, 0x95b4, 0x95b4 }, +/* 0x95b5 */ { false, 0x95b5, 0x95b5 }, +/* 0x95b6 */ { false, 0x95b6, 0x95b6 }, +/* 0x95b7 */ { false, 0x95b7, 0x95b7 }, +/* 0x95b8 */ { false, 0x95b8, 0x95b8 }, +/* 0x95b9 */ { false, 0x95b9, 0x95b9 }, +/* 0x95ba */ { false, 0x95ba, 0x95ba }, +/* 0x95bb */ { false, 0x95bb, 0x95bb }, +/* 0x95bc */ { false, 0x95bc, 0x95bc }, +/* 0x95bd */ { false, 0x95bd, 0x95bd }, +/* 0x95be */ { false, 0x95be, 0x95be }, +/* 0x95bf */ { false, 0x95bf, 0x95bf }, +/* 0x95c0 */ { false, 0x95c0, 0x95c0 }, +/* 0x95c1 */ { false, 0x95c1, 0x95c1 }, +/* 0x95c2 */ { false, 0x95c2, 0x95c2 }, +/* 0x95c3 */ { false, 0x95c3, 0x95c3 }, +/* 0x95c4 */ { false, 0x95c4, 0x95c4 }, +/* 0x95c5 */ { false, 0x95c5, 0x95c5 }, +/* 0x95c6 */ { false, 0x95c6, 0x95c6 }, +/* 0x95c7 */ { false, 0x95c7, 0x95c7 }, +/* 0x95c8 */ { false, 0x95c8, 0x95c8 }, +/* 0x95c9 */ { false, 0x95c9, 0x95c9 }, +/* 0x95ca */ { false, 0x95ca, 0x95ca }, +/* 0x95cb */ { false, 0x95cb, 0x95cb }, +/* 0x95cc */ { false, 0x95cc, 0x95cc }, +/* 0x95cd */ { false, 0x95cd, 0x95cd }, +/* 0x95ce */ { false, 0x95ce, 0x95ce }, +/* 0x95cf */ { false, 0x95cf, 0x95cf }, +/* 0x95d0 */ { false, 0x95d0, 0x95d0 }, +/* 0x95d1 */ { false, 0x95d1, 0x95d1 }, +/* 0x95d2 */ { false, 0x95d2, 0x95d2 }, +/* 0x95d3 */ { false, 0x95d3, 0x95d3 }, +/* 0x95d4 */ { false, 0x95d4, 0x95d4 }, +/* 0x95d5 */ { false, 0x95d5, 0x95d5 }, +/* 0x95d6 */ { false, 0x95d6, 0x95d6 }, +/* 0x95d7 */ { false, 0x95d7, 0x95d7 }, +/* 0x95d8 */ { false, 0x95d8, 0x95d8 }, +/* 0x95d9 */ { false, 0x95d9, 0x95d9 }, +/* 0x95da */ { false, 0x95da, 0x95da }, +/* 0x95db */ { false, 0x95db, 0x95db }, +/* 0x95dc */ { false, 0x95dc, 0x95dc }, +/* 0x95dd */ { false, 0x95dd, 0x95dd }, +/* 0x95de */ { false, 0x95de, 0x95de }, +/* 0x95df */ { false, 0x95df, 0x95df }, +/* 0x95e0 */ { false, 0x95e0, 0x95e0 }, +/* 0x95e1 */ { false, 0x95e1, 0x95e1 }, +/* 0x95e2 */ { false, 0x95e2, 0x95e2 }, +/* 0x95e3 */ { false, 0x95e3, 0x95e3 }, +/* 0x95e4 */ { false, 0x95e4, 0x95e4 }, +/* 0x95e5 */ { false, 0x95e5, 0x95e5 }, +/* 0x95e6 */ { false, 0x95e6, 0x95e6 }, +/* 0x95e7 */ { false, 0x95e7, 0x95e7 }, +/* 0x95e8 */ { false, 0x95e8, 0x95e8 }, +/* 0x95e9 */ { false, 0x95e9, 0x95e9 }, +/* 0x95ea */ { false, 0x95ea, 0x95ea }, +/* 0x95eb */ { false, 0x95eb, 0x95eb }, +/* 0x95ec */ { false, 0x95ec, 0x95ec }, +/* 0x95ed */ { false, 0x95ed, 0x95ed }, +/* 0x95ee */ { false, 0x95ee, 0x95ee }, +/* 0x95ef */ { false, 0x95ef, 0x95ef }, +/* 0x95f0 */ { false, 0x95f0, 0x95f0 }, +/* 0x95f1 */ { false, 0x95f1, 0x95f1 }, +/* 0x95f2 */ { false, 0x95f2, 0x95f2 }, +/* 0x95f3 */ { false, 0x95f3, 0x95f3 }, +/* 0x95f4 */ { false, 0x95f4, 0x95f4 }, +/* 0x95f5 */ { false, 0x95f5, 0x95f5 }, +/* 0x95f6 */ { false, 0x95f6, 0x95f6 }, +/* 0x95f7 */ { false, 0x95f7, 0x95f7 }, +/* 0x95f8 */ { false, 0x95f8, 0x95f8 }, +/* 0x95f9 */ { false, 0x95f9, 0x95f9 }, +/* 0x95fa */ { false, 0x95fa, 0x95fa }, +/* 0x95fb */ { false, 0x95fb, 0x95fb }, +/* 0x95fc */ { false, 0x95fc, 0x95fc }, +/* 0x95fd */ { false, 0x95fd, 0x95fd }, +/* 0x95fe */ { false, 0x95fe, 0x95fe }, +/* 0x95ff */ { false, 0x95ff, 0x95ff }, +/* 0x9600 */ { false, 0x9600, 0x9600 }, +/* 0x9601 */ { false, 0x9601, 0x9601 }, +/* 0x9602 */ { false, 0x9602, 0x9602 }, +/* 0x9603 */ { false, 0x9603, 0x9603 }, +/* 0x9604 */ { false, 0x9604, 0x9604 }, +/* 0x9605 */ { false, 0x9605, 0x9605 }, +/* 0x9606 */ { false, 0x9606, 0x9606 }, +/* 0x9607 */ { false, 0x9607, 0x9607 }, +/* 0x9608 */ { false, 0x9608, 0x9608 }, +/* 0x9609 */ { false, 0x9609, 0x9609 }, +/* 0x960a */ { false, 0x960a, 0x960a }, +/* 0x960b */ { false, 0x960b, 0x960b }, +/* 0x960c */ { false, 0x960c, 0x960c }, +/* 0x960d */ { false, 0x960d, 0x960d }, +/* 0x960e */ { false, 0x960e, 0x960e }, +/* 0x960f */ { false, 0x960f, 0x960f }, +/* 0x9610 */ { false, 0x9610, 0x9610 }, +/* 0x9611 */ { false, 0x9611, 0x9611 }, +/* 0x9612 */ { false, 0x9612, 0x9612 }, +/* 0x9613 */ { false, 0x9613, 0x9613 }, +/* 0x9614 */ { false, 0x9614, 0x9614 }, +/* 0x9615 */ { false, 0x9615, 0x9615 }, +/* 0x9616 */ { false, 0x9616, 0x9616 }, +/* 0x9617 */ { false, 0x9617, 0x9617 }, +/* 0x9618 */ { false, 0x9618, 0x9618 }, +/* 0x9619 */ { false, 0x9619, 0x9619 }, +/* 0x961a */ { false, 0x961a, 0x961a }, +/* 0x961b */ { false, 0x961b, 0x961b }, +/* 0x961c */ { false, 0x961c, 0x961c }, +/* 0x961d */ { false, 0x961d, 0x961d }, +/* 0x961e */ { false, 0x961e, 0x961e }, +/* 0x961f */ { false, 0x961f, 0x961f }, +/* 0x9620 */ { false, 0x9620, 0x9620 }, +/* 0x9621 */ { false, 0x9621, 0x9621 }, +/* 0x9622 */ { false, 0x9622, 0x9622 }, +/* 0x9623 */ { false, 0x9623, 0x9623 }, +/* 0x9624 */ { false, 0x9624, 0x9624 }, +/* 0x9625 */ { false, 0x9625, 0x9625 }, +/* 0x9626 */ { false, 0x9626, 0x9626 }, +/* 0x9627 */ { false, 0x9627, 0x9627 }, +/* 0x9628 */ { false, 0x9628, 0x9628 }, +/* 0x9629 */ { false, 0x9629, 0x9629 }, +/* 0x962a */ { false, 0x962a, 0x962a }, +/* 0x962b */ { false, 0x962b, 0x962b }, +/* 0x962c */ { false, 0x962c, 0x962c }, +/* 0x962d */ { false, 0x962d, 0x962d }, +/* 0x962e */ { false, 0x962e, 0x962e }, +/* 0x962f */ { false, 0x962f, 0x962f }, +/* 0x9630 */ { false, 0x9630, 0x9630 }, +/* 0x9631 */ { false, 0x9631, 0x9631 }, +/* 0x9632 */ { false, 0x9632, 0x9632 }, +/* 0x9633 */ { false, 0x9633, 0x9633 }, +/* 0x9634 */ { false, 0x9634, 0x9634 }, +/* 0x9635 */ { false, 0x9635, 0x9635 }, +/* 0x9636 */ { false, 0x9636, 0x9636 }, +/* 0x9637 */ { false, 0x9637, 0x9637 }, +/* 0x9638 */ { false, 0x9638, 0x9638 }, +/* 0x9639 */ { false, 0x9639, 0x9639 }, +/* 0x963a */ { false, 0x963a, 0x963a }, +/* 0x963b */ { false, 0x963b, 0x963b }, +/* 0x963c */ { false, 0x963c, 0x963c }, +/* 0x963d */ { false, 0x963d, 0x963d }, +/* 0x963e */ { false, 0x963e, 0x963e }, +/* 0x963f */ { false, 0x963f, 0x963f }, +/* 0x9640 */ { false, 0x9640, 0x9640 }, +/* 0x9641 */ { false, 0x9641, 0x9641 }, +/* 0x9642 */ { false, 0x9642, 0x9642 }, +/* 0x9643 */ { false, 0x9643, 0x9643 }, +/* 0x9644 */ { false, 0x9644, 0x9644 }, +/* 0x9645 */ { false, 0x9645, 0x9645 }, +/* 0x9646 */ { false, 0x9646, 0x9646 }, +/* 0x9647 */ { false, 0x9647, 0x9647 }, +/* 0x9648 */ { false, 0x9648, 0x9648 }, +/* 0x9649 */ { false, 0x9649, 0x9649 }, +/* 0x964a */ { false, 0x964a, 0x964a }, +/* 0x964b */ { false, 0x964b, 0x964b }, +/* 0x964c */ { false, 0x964c, 0x964c }, +/* 0x964d */ { false, 0x964d, 0x964d }, +/* 0x964e */ { false, 0x964e, 0x964e }, +/* 0x964f */ { false, 0x964f, 0x964f }, +/* 0x9650 */ { false, 0x9650, 0x9650 }, +/* 0x9651 */ { false, 0x9651, 0x9651 }, +/* 0x9652 */ { false, 0x9652, 0x9652 }, +/* 0x9653 */ { false, 0x9653, 0x9653 }, +/* 0x9654 */ { false, 0x9654, 0x9654 }, +/* 0x9655 */ { false, 0x9655, 0x9655 }, +/* 0x9656 */ { false, 0x9656, 0x9656 }, +/* 0x9657 */ { false, 0x9657, 0x9657 }, +/* 0x9658 */ { false, 0x9658, 0x9658 }, +/* 0x9659 */ { false, 0x9659, 0x9659 }, +/* 0x965a */ { false, 0x965a, 0x965a }, +/* 0x965b */ { false, 0x965b, 0x965b }, +/* 0x965c */ { false, 0x965c, 0x965c }, +/* 0x965d */ { false, 0x965d, 0x965d }, +/* 0x965e */ { false, 0x965e, 0x965e }, +/* 0x965f */ { false, 0x965f, 0x965f }, +/* 0x9660 */ { false, 0x9660, 0x9660 }, +/* 0x9661 */ { false, 0x9661, 0x9661 }, +/* 0x9662 */ { false, 0x9662, 0x9662 }, +/* 0x9663 */ { false, 0x9663, 0x9663 }, +/* 0x9664 */ { false, 0x9664, 0x9664 }, +/* 0x9665 */ { false, 0x9665, 0x9665 }, +/* 0x9666 */ { false, 0x9666, 0x9666 }, +/* 0x9667 */ { false, 0x9667, 0x9667 }, +/* 0x9668 */ { false, 0x9668, 0x9668 }, +/* 0x9669 */ { false, 0x9669, 0x9669 }, +/* 0x966a */ { false, 0x966a, 0x966a }, +/* 0x966b */ { false, 0x966b, 0x966b }, +/* 0x966c */ { false, 0x966c, 0x966c }, +/* 0x966d */ { false, 0x966d, 0x966d }, +/* 0x966e */ { false, 0x966e, 0x966e }, +/* 0x966f */ { false, 0x966f, 0x966f }, +/* 0x9670 */ { false, 0x9670, 0x9670 }, +/* 0x9671 */ { false, 0x9671, 0x9671 }, +/* 0x9672 */ { false, 0x9672, 0x9672 }, +/* 0x9673 */ { false, 0x9673, 0x9673 }, +/* 0x9674 */ { false, 0x9674, 0x9674 }, +/* 0x9675 */ { false, 0x9675, 0x9675 }, +/* 0x9676 */ { false, 0x9676, 0x9676 }, +/* 0x9677 */ { false, 0x9677, 0x9677 }, +/* 0x9678 */ { false, 0x9678, 0x9678 }, +/* 0x9679 */ { false, 0x9679, 0x9679 }, +/* 0x967a */ { false, 0x967a, 0x967a }, +/* 0x967b */ { false, 0x967b, 0x967b }, +/* 0x967c */ { false, 0x967c, 0x967c }, +/* 0x967d */ { false, 0x967d, 0x967d }, +/* 0x967e */ { false, 0x967e, 0x967e }, +/* 0x967f */ { false, 0x967f, 0x967f }, +/* 0x9680 */ { false, 0x9680, 0x9680 }, +/* 0x9681 */ { false, 0x9681, 0x9681 }, +/* 0x9682 */ { false, 0x9682, 0x9682 }, +/* 0x9683 */ { false, 0x9683, 0x9683 }, +/* 0x9684 */ { false, 0x9684, 0x9684 }, +/* 0x9685 */ { false, 0x9685, 0x9685 }, +/* 0x9686 */ { false, 0x9686, 0x9686 }, +/* 0x9687 */ { false, 0x9687, 0x9687 }, +/* 0x9688 */ { false, 0x9688, 0x9688 }, +/* 0x9689 */ { false, 0x9689, 0x9689 }, +/* 0x968a */ { false, 0x968a, 0x968a }, +/* 0x968b */ { false, 0x968b, 0x968b }, +/* 0x968c */ { false, 0x968c, 0x968c }, +/* 0x968d */ { false, 0x968d, 0x968d }, +/* 0x968e */ { false, 0x968e, 0x968e }, +/* 0x968f */ { false, 0x968f, 0x968f }, +/* 0x9690 */ { false, 0x9690, 0x9690 }, +/* 0x9691 */ { false, 0x9691, 0x9691 }, +/* 0x9692 */ { false, 0x9692, 0x9692 }, +/* 0x9693 */ { false, 0x9693, 0x9693 }, +/* 0x9694 */ { false, 0x9694, 0x9694 }, +/* 0x9695 */ { false, 0x9695, 0x9695 }, +/* 0x9696 */ { false, 0x9696, 0x9696 }, +/* 0x9697 */ { false, 0x9697, 0x9697 }, +/* 0x9698 */ { false, 0x9698, 0x9698 }, +/* 0x9699 */ { false, 0x9699, 0x9699 }, +/* 0x969a */ { false, 0x969a, 0x969a }, +/* 0x969b */ { false, 0x969b, 0x969b }, +/* 0x969c */ { false, 0x969c, 0x969c }, +/* 0x969d */ { false, 0x969d, 0x969d }, +/* 0x969e */ { false, 0x969e, 0x969e }, +/* 0x969f */ { false, 0x969f, 0x969f }, +/* 0x96a0 */ { false, 0x96a0, 0x96a0 }, +/* 0x96a1 */ { false, 0x96a1, 0x96a1 }, +/* 0x96a2 */ { false, 0x96a2, 0x96a2 }, +/* 0x96a3 */ { false, 0x96a3, 0x96a3 }, +/* 0x96a4 */ { false, 0x96a4, 0x96a4 }, +/* 0x96a5 */ { false, 0x96a5, 0x96a5 }, +/* 0x96a6 */ { false, 0x96a6, 0x96a6 }, +/* 0x96a7 */ { false, 0x96a7, 0x96a7 }, +/* 0x96a8 */ { false, 0x96a8, 0x96a8 }, +/* 0x96a9 */ { false, 0x96a9, 0x96a9 }, +/* 0x96aa */ { false, 0x96aa, 0x96aa }, +/* 0x96ab */ { false, 0x96ab, 0x96ab }, +/* 0x96ac */ { false, 0x96ac, 0x96ac }, +/* 0x96ad */ { false, 0x96ad, 0x96ad }, +/* 0x96ae */ { false, 0x96ae, 0x96ae }, +/* 0x96af */ { false, 0x96af, 0x96af }, +/* 0x96b0 */ { false, 0x96b0, 0x96b0 }, +/* 0x96b1 */ { false, 0x96b1, 0x96b1 }, +/* 0x96b2 */ { false, 0x96b2, 0x96b2 }, +/* 0x96b3 */ { false, 0x96b3, 0x96b3 }, +/* 0x96b4 */ { false, 0x96b4, 0x96b4 }, +/* 0x96b5 */ { false, 0x96b5, 0x96b5 }, +/* 0x96b6 */ { false, 0x96b6, 0x96b6 }, +/* 0x96b7 */ { false, 0x96b7, 0x96b7 }, +/* 0x96b8 */ { false, 0x96b8, 0x96b8 }, +/* 0x96b9 */ { false, 0x96b9, 0x96b9 }, +/* 0x96ba */ { false, 0x96ba, 0x96ba }, +/* 0x96bb */ { false, 0x96bb, 0x96bb }, +/* 0x96bc */ { false, 0x96bc, 0x96bc }, +/* 0x96bd */ { false, 0x96bd, 0x96bd }, +/* 0x96be */ { false, 0x96be, 0x96be }, +/* 0x96bf */ { false, 0x96bf, 0x96bf }, +/* 0x96c0 */ { false, 0x96c0, 0x96c0 }, +/* 0x96c1 */ { false, 0x96c1, 0x96c1 }, +/* 0x96c2 */ { false, 0x96c2, 0x96c2 }, +/* 0x96c3 */ { false, 0x96c3, 0x96c3 }, +/* 0x96c4 */ { false, 0x96c4, 0x96c4 }, +/* 0x96c5 */ { false, 0x96c5, 0x96c5 }, +/* 0x96c6 */ { false, 0x96c6, 0x96c6 }, +/* 0x96c7 */ { false, 0x96c7, 0x96c7 }, +/* 0x96c8 */ { false, 0x96c8, 0x96c8 }, +/* 0x96c9 */ { false, 0x96c9, 0x96c9 }, +/* 0x96ca */ { false, 0x96ca, 0x96ca }, +/* 0x96cb */ { false, 0x96cb, 0x96cb }, +/* 0x96cc */ { false, 0x96cc, 0x96cc }, +/* 0x96cd */ { false, 0x96cd, 0x96cd }, +/* 0x96ce */ { false, 0x96ce, 0x96ce }, +/* 0x96cf */ { false, 0x96cf, 0x96cf }, +/* 0x96d0 */ { false, 0x96d0, 0x96d0 }, +/* 0x96d1 */ { false, 0x96d1, 0x96d1 }, +/* 0x96d2 */ { false, 0x96d2, 0x96d2 }, +/* 0x96d3 */ { false, 0x96d3, 0x96d3 }, +/* 0x96d4 */ { false, 0x96d4, 0x96d4 }, +/* 0x96d5 */ { false, 0x96d5, 0x96d5 }, +/* 0x96d6 */ { false, 0x96d6, 0x96d6 }, +/* 0x96d7 */ { false, 0x96d7, 0x96d7 }, +/* 0x96d8 */ { false, 0x96d8, 0x96d8 }, +/* 0x96d9 */ { false, 0x96d9, 0x96d9 }, +/* 0x96da */ { false, 0x96da, 0x96da }, +/* 0x96db */ { false, 0x96db, 0x96db }, +/* 0x96dc */ { false, 0x96dc, 0x96dc }, +/* 0x96dd */ { false, 0x96dd, 0x96dd }, +/* 0x96de */ { false, 0x96de, 0x96de }, +/* 0x96df */ { false, 0x96df, 0x96df }, +/* 0x96e0 */ { false, 0x96e0, 0x96e0 }, +/* 0x96e1 */ { false, 0x96e1, 0x96e1 }, +/* 0x96e2 */ { false, 0x96e2, 0x96e2 }, +/* 0x96e3 */ { false, 0x96e3, 0x96e3 }, +/* 0x96e4 */ { false, 0x96e4, 0x96e4 }, +/* 0x96e5 */ { false, 0x96e5, 0x96e5 }, +/* 0x96e6 */ { false, 0x96e6, 0x96e6 }, +/* 0x96e7 */ { false, 0x96e7, 0x96e7 }, +/* 0x96e8 */ { false, 0x96e8, 0x96e8 }, +/* 0x96e9 */ { false, 0x96e9, 0x96e9 }, +/* 0x96ea */ { false, 0x96ea, 0x96ea }, +/* 0x96eb */ { false, 0x96eb, 0x96eb }, +/* 0x96ec */ { false, 0x96ec, 0x96ec }, +/* 0x96ed */ { false, 0x96ed, 0x96ed }, +/* 0x96ee */ { false, 0x96ee, 0x96ee }, +/* 0x96ef */ { false, 0x96ef, 0x96ef }, +/* 0x96f0 */ { false, 0x96f0, 0x96f0 }, +/* 0x96f1 */ { false, 0x96f1, 0x96f1 }, +/* 0x96f2 */ { false, 0x96f2, 0x96f2 }, +/* 0x96f3 */ { false, 0x96f3, 0x96f3 }, +/* 0x96f4 */ { false, 0x96f4, 0x96f4 }, +/* 0x96f5 */ { false, 0x96f5, 0x96f5 }, +/* 0x96f6 */ { false, 0x96f6, 0x96f6 }, +/* 0x96f7 */ { false, 0x96f7, 0x96f7 }, +/* 0x96f8 */ { false, 0x96f8, 0x96f8 }, +/* 0x96f9 */ { false, 0x96f9, 0x96f9 }, +/* 0x96fa */ { false, 0x96fa, 0x96fa }, +/* 0x96fb */ { false, 0x96fb, 0x96fb }, +/* 0x96fc */ { false, 0x96fc, 0x96fc }, +/* 0x96fd */ { false, 0x96fd, 0x96fd }, +/* 0x96fe */ { false, 0x96fe, 0x96fe }, +/* 0x96ff */ { false, 0x96ff, 0x96ff }, +/* 0x9700 */ { false, 0x9700, 0x9700 }, +/* 0x9701 */ { false, 0x9701, 0x9701 }, +/* 0x9702 */ { false, 0x9702, 0x9702 }, +/* 0x9703 */ { false, 0x9703, 0x9703 }, +/* 0x9704 */ { false, 0x9704, 0x9704 }, +/* 0x9705 */ { false, 0x9705, 0x9705 }, +/* 0x9706 */ { false, 0x9706, 0x9706 }, +/* 0x9707 */ { false, 0x9707, 0x9707 }, +/* 0x9708 */ { false, 0x9708, 0x9708 }, +/* 0x9709 */ { false, 0x9709, 0x9709 }, +/* 0x970a */ { false, 0x970a, 0x970a }, +/* 0x970b */ { false, 0x970b, 0x970b }, +/* 0x970c */ { false, 0x970c, 0x970c }, +/* 0x970d */ { false, 0x970d, 0x970d }, +/* 0x970e */ { false, 0x970e, 0x970e }, +/* 0x970f */ { false, 0x970f, 0x970f }, +/* 0x9710 */ { false, 0x9710, 0x9710 }, +/* 0x9711 */ { false, 0x9711, 0x9711 }, +/* 0x9712 */ { false, 0x9712, 0x9712 }, +/* 0x9713 */ { false, 0x9713, 0x9713 }, +/* 0x9714 */ { false, 0x9714, 0x9714 }, +/* 0x9715 */ { false, 0x9715, 0x9715 }, +/* 0x9716 */ { false, 0x9716, 0x9716 }, +/* 0x9717 */ { false, 0x9717, 0x9717 }, +/* 0x9718 */ { false, 0x9718, 0x9718 }, +/* 0x9719 */ { false, 0x9719, 0x9719 }, +/* 0x971a */ { false, 0x971a, 0x971a }, +/* 0x971b */ { false, 0x971b, 0x971b }, +/* 0x971c */ { false, 0x971c, 0x971c }, +/* 0x971d */ { false, 0x971d, 0x971d }, +/* 0x971e */ { false, 0x971e, 0x971e }, +/* 0x971f */ { false, 0x971f, 0x971f }, +/* 0x9720 */ { false, 0x9720, 0x9720 }, +/* 0x9721 */ { false, 0x9721, 0x9721 }, +/* 0x9722 */ { false, 0x9722, 0x9722 }, +/* 0x9723 */ { false, 0x9723, 0x9723 }, +/* 0x9724 */ { false, 0x9724, 0x9724 }, +/* 0x9725 */ { false, 0x9725, 0x9725 }, +/* 0x9726 */ { false, 0x9726, 0x9726 }, +/* 0x9727 */ { false, 0x9727, 0x9727 }, +/* 0x9728 */ { false, 0x9728, 0x9728 }, +/* 0x9729 */ { false, 0x9729, 0x9729 }, +/* 0x972a */ { false, 0x972a, 0x972a }, +/* 0x972b */ { false, 0x972b, 0x972b }, +/* 0x972c */ { false, 0x972c, 0x972c }, +/* 0x972d */ { false, 0x972d, 0x972d }, +/* 0x972e */ { false, 0x972e, 0x972e }, +/* 0x972f */ { false, 0x972f, 0x972f }, +/* 0x9730 */ { false, 0x9730, 0x9730 }, +/* 0x9731 */ { false, 0x9731, 0x9731 }, +/* 0x9732 */ { false, 0x9732, 0x9732 }, +/* 0x9733 */ { false, 0x9733, 0x9733 }, +/* 0x9734 */ { false, 0x9734, 0x9734 }, +/* 0x9735 */ { false, 0x9735, 0x9735 }, +/* 0x9736 */ { false, 0x9736, 0x9736 }, +/* 0x9737 */ { false, 0x9737, 0x9737 }, +/* 0x9738 */ { false, 0x9738, 0x9738 }, +/* 0x9739 */ { false, 0x9739, 0x9739 }, +/* 0x973a */ { false, 0x973a, 0x973a }, +/* 0x973b */ { false, 0x973b, 0x973b }, +/* 0x973c */ { false, 0x973c, 0x973c }, +/* 0x973d */ { false, 0x973d, 0x973d }, +/* 0x973e */ { false, 0x973e, 0x973e }, +/* 0x973f */ { false, 0x973f, 0x973f }, +/* 0x9740 */ { false, 0x9740, 0x9740 }, +/* 0x9741 */ { false, 0x9741, 0x9741 }, +/* 0x9742 */ { false, 0x9742, 0x9742 }, +/* 0x9743 */ { false, 0x9743, 0x9743 }, +/* 0x9744 */ { false, 0x9744, 0x9744 }, +/* 0x9745 */ { false, 0x9745, 0x9745 }, +/* 0x9746 */ { false, 0x9746, 0x9746 }, +/* 0x9747 */ { false, 0x9747, 0x9747 }, +/* 0x9748 */ { false, 0x9748, 0x9748 }, +/* 0x9749 */ { false, 0x9749, 0x9749 }, +/* 0x974a */ { false, 0x974a, 0x974a }, +/* 0x974b */ { false, 0x974b, 0x974b }, +/* 0x974c */ { false, 0x974c, 0x974c }, +/* 0x974d */ { false, 0x974d, 0x974d }, +/* 0x974e */ { false, 0x974e, 0x974e }, +/* 0x974f */ { false, 0x974f, 0x974f }, +/* 0x9750 */ { false, 0x9750, 0x9750 }, +/* 0x9751 */ { false, 0x9751, 0x9751 }, +/* 0x9752 */ { false, 0x9752, 0x9752 }, +/* 0x9753 */ { false, 0x9753, 0x9753 }, +/* 0x9754 */ { false, 0x9754, 0x9754 }, +/* 0x9755 */ { false, 0x9755, 0x9755 }, +/* 0x9756 */ { false, 0x9756, 0x9756 }, +/* 0x9757 */ { false, 0x9757, 0x9757 }, +/* 0x9758 */ { false, 0x9758, 0x9758 }, +/* 0x9759 */ { false, 0x9759, 0x9759 }, +/* 0x975a */ { false, 0x975a, 0x975a }, +/* 0x975b */ { false, 0x975b, 0x975b }, +/* 0x975c */ { false, 0x975c, 0x975c }, +/* 0x975d */ { false, 0x975d, 0x975d }, +/* 0x975e */ { false, 0x975e, 0x975e }, +/* 0x975f */ { false, 0x975f, 0x975f }, +/* 0x9760 */ { false, 0x9760, 0x9760 }, +/* 0x9761 */ { false, 0x9761, 0x9761 }, +/* 0x9762 */ { false, 0x9762, 0x9762 }, +/* 0x9763 */ { false, 0x9763, 0x9763 }, +/* 0x9764 */ { false, 0x9764, 0x9764 }, +/* 0x9765 */ { false, 0x9765, 0x9765 }, +/* 0x9766 */ { false, 0x9766, 0x9766 }, +/* 0x9767 */ { false, 0x9767, 0x9767 }, +/* 0x9768 */ { false, 0x9768, 0x9768 }, +/* 0x9769 */ { false, 0x9769, 0x9769 }, +/* 0x976a */ { false, 0x976a, 0x976a }, +/* 0x976b */ { false, 0x976b, 0x976b }, +/* 0x976c */ { false, 0x976c, 0x976c }, +/* 0x976d */ { false, 0x976d, 0x976d }, +/* 0x976e */ { false, 0x976e, 0x976e }, +/* 0x976f */ { false, 0x976f, 0x976f }, +/* 0x9770 */ { false, 0x9770, 0x9770 }, +/* 0x9771 */ { false, 0x9771, 0x9771 }, +/* 0x9772 */ { false, 0x9772, 0x9772 }, +/* 0x9773 */ { false, 0x9773, 0x9773 }, +/* 0x9774 */ { false, 0x9774, 0x9774 }, +/* 0x9775 */ { false, 0x9775, 0x9775 }, +/* 0x9776 */ { false, 0x9776, 0x9776 }, +/* 0x9777 */ { false, 0x9777, 0x9777 }, +/* 0x9778 */ { false, 0x9778, 0x9778 }, +/* 0x9779 */ { false, 0x9779, 0x9779 }, +/* 0x977a */ { false, 0x977a, 0x977a }, +/* 0x977b */ { false, 0x977b, 0x977b }, +/* 0x977c */ { false, 0x977c, 0x977c }, +/* 0x977d */ { false, 0x977d, 0x977d }, +/* 0x977e */ { false, 0x977e, 0x977e }, +/* 0x977f */ { false, 0x977f, 0x977f }, +/* 0x9780 */ { false, 0x9780, 0x9780 }, +/* 0x9781 */ { false, 0x9781, 0x9781 }, +/* 0x9782 */ { false, 0x9782, 0x9782 }, +/* 0x9783 */ { false, 0x9783, 0x9783 }, +/* 0x9784 */ { false, 0x9784, 0x9784 }, +/* 0x9785 */ { false, 0x9785, 0x9785 }, +/* 0x9786 */ { false, 0x9786, 0x9786 }, +/* 0x9787 */ { false, 0x9787, 0x9787 }, +/* 0x9788 */ { false, 0x9788, 0x9788 }, +/* 0x9789 */ { false, 0x9789, 0x9789 }, +/* 0x978a */ { false, 0x978a, 0x978a }, +/* 0x978b */ { false, 0x978b, 0x978b }, +/* 0x978c */ { false, 0x978c, 0x978c }, +/* 0x978d */ { false, 0x978d, 0x978d }, +/* 0x978e */ { false, 0x978e, 0x978e }, +/* 0x978f */ { false, 0x978f, 0x978f }, +/* 0x9790 */ { false, 0x9790, 0x9790 }, +/* 0x9791 */ { false, 0x9791, 0x9791 }, +/* 0x9792 */ { false, 0x9792, 0x9792 }, +/* 0x9793 */ { false, 0x9793, 0x9793 }, +/* 0x9794 */ { false, 0x9794, 0x9794 }, +/* 0x9795 */ { false, 0x9795, 0x9795 }, +/* 0x9796 */ { false, 0x9796, 0x9796 }, +/* 0x9797 */ { false, 0x9797, 0x9797 }, +/* 0x9798 */ { false, 0x9798, 0x9798 }, +/* 0x9799 */ { false, 0x9799, 0x9799 }, +/* 0x979a */ { false, 0x979a, 0x979a }, +/* 0x979b */ { false, 0x979b, 0x979b }, +/* 0x979c */ { false, 0x979c, 0x979c }, +/* 0x979d */ { false, 0x979d, 0x979d }, +/* 0x979e */ { false, 0x979e, 0x979e }, +/* 0x979f */ { false, 0x979f, 0x979f }, +/* 0x97a0 */ { false, 0x97a0, 0x97a0 }, +/* 0x97a1 */ { false, 0x97a1, 0x97a1 }, +/* 0x97a2 */ { false, 0x97a2, 0x97a2 }, +/* 0x97a3 */ { false, 0x97a3, 0x97a3 }, +/* 0x97a4 */ { false, 0x97a4, 0x97a4 }, +/* 0x97a5 */ { false, 0x97a5, 0x97a5 }, +/* 0x97a6 */ { false, 0x97a6, 0x97a6 }, +/* 0x97a7 */ { false, 0x97a7, 0x97a7 }, +/* 0x97a8 */ { false, 0x97a8, 0x97a8 }, +/* 0x97a9 */ { false, 0x97a9, 0x97a9 }, +/* 0x97aa */ { false, 0x97aa, 0x97aa }, +/* 0x97ab */ { false, 0x97ab, 0x97ab }, +/* 0x97ac */ { false, 0x97ac, 0x97ac }, +/* 0x97ad */ { false, 0x97ad, 0x97ad }, +/* 0x97ae */ { false, 0x97ae, 0x97ae }, +/* 0x97af */ { false, 0x97af, 0x97af }, +/* 0x97b0 */ { false, 0x97b0, 0x97b0 }, +/* 0x97b1 */ { false, 0x97b1, 0x97b1 }, +/* 0x97b2 */ { false, 0x97b2, 0x97b2 }, +/* 0x97b3 */ { false, 0x97b3, 0x97b3 }, +/* 0x97b4 */ { false, 0x97b4, 0x97b4 }, +/* 0x97b5 */ { false, 0x97b5, 0x97b5 }, +/* 0x97b6 */ { false, 0x97b6, 0x97b6 }, +/* 0x97b7 */ { false, 0x97b7, 0x97b7 }, +/* 0x97b8 */ { false, 0x97b8, 0x97b8 }, +/* 0x97b9 */ { false, 0x97b9, 0x97b9 }, +/* 0x97ba */ { false, 0x97ba, 0x97ba }, +/* 0x97bb */ { false, 0x97bb, 0x97bb }, +/* 0x97bc */ { false, 0x97bc, 0x97bc }, +/* 0x97bd */ { false, 0x97bd, 0x97bd }, +/* 0x97be */ { false, 0x97be, 0x97be }, +/* 0x97bf */ { false, 0x97bf, 0x97bf }, +/* 0x97c0 */ { false, 0x97c0, 0x97c0 }, +/* 0x97c1 */ { false, 0x97c1, 0x97c1 }, +/* 0x97c2 */ { false, 0x97c2, 0x97c2 }, +/* 0x97c3 */ { false, 0x97c3, 0x97c3 }, +/* 0x97c4 */ { false, 0x97c4, 0x97c4 }, +/* 0x97c5 */ { false, 0x97c5, 0x97c5 }, +/* 0x97c6 */ { false, 0x97c6, 0x97c6 }, +/* 0x97c7 */ { false, 0x97c7, 0x97c7 }, +/* 0x97c8 */ { false, 0x97c8, 0x97c8 }, +/* 0x97c9 */ { false, 0x97c9, 0x97c9 }, +/* 0x97ca */ { false, 0x97ca, 0x97ca }, +/* 0x97cb */ { false, 0x97cb, 0x97cb }, +/* 0x97cc */ { false, 0x97cc, 0x97cc }, +/* 0x97cd */ { false, 0x97cd, 0x97cd }, +/* 0x97ce */ { false, 0x97ce, 0x97ce }, +/* 0x97cf */ { false, 0x97cf, 0x97cf }, +/* 0x97d0 */ { false, 0x97d0, 0x97d0 }, +/* 0x97d1 */ { false, 0x97d1, 0x97d1 }, +/* 0x97d2 */ { false, 0x97d2, 0x97d2 }, +/* 0x97d3 */ { false, 0x97d3, 0x97d3 }, +/* 0x97d4 */ { false, 0x97d4, 0x97d4 }, +/* 0x97d5 */ { false, 0x97d5, 0x97d5 }, +/* 0x97d6 */ { false, 0x97d6, 0x97d6 }, +/* 0x97d7 */ { false, 0x97d7, 0x97d7 }, +/* 0x97d8 */ { false, 0x97d8, 0x97d8 }, +/* 0x97d9 */ { false, 0x97d9, 0x97d9 }, +/* 0x97da */ { false, 0x97da, 0x97da }, +/* 0x97db */ { false, 0x97db, 0x97db }, +/* 0x97dc */ { false, 0x97dc, 0x97dc }, +/* 0x97dd */ { false, 0x97dd, 0x97dd }, +/* 0x97de */ { false, 0x97de, 0x97de }, +/* 0x97df */ { false, 0x97df, 0x97df }, +/* 0x97e0 */ { false, 0x97e0, 0x97e0 }, +/* 0x97e1 */ { false, 0x97e1, 0x97e1 }, +/* 0x97e2 */ { false, 0x97e2, 0x97e2 }, +/* 0x97e3 */ { false, 0x97e3, 0x97e3 }, +/* 0x97e4 */ { false, 0x97e4, 0x97e4 }, +/* 0x97e5 */ { false, 0x97e5, 0x97e5 }, +/* 0x97e6 */ { false, 0x97e6, 0x97e6 }, +/* 0x97e7 */ { false, 0x97e7, 0x97e7 }, +/* 0x97e8 */ { false, 0x97e8, 0x97e8 }, +/* 0x97e9 */ { false, 0x97e9, 0x97e9 }, +/* 0x97ea */ { false, 0x97ea, 0x97ea }, +/* 0x97eb */ { false, 0x97eb, 0x97eb }, +/* 0x97ec */ { false, 0x97ec, 0x97ec }, +/* 0x97ed */ { false, 0x97ed, 0x97ed }, +/* 0x97ee */ { false, 0x97ee, 0x97ee }, +/* 0x97ef */ { false, 0x97ef, 0x97ef }, +/* 0x97f0 */ { false, 0x97f0, 0x97f0 }, +/* 0x97f1 */ { false, 0x97f1, 0x97f1 }, +/* 0x97f2 */ { false, 0x97f2, 0x97f2 }, +/* 0x97f3 */ { false, 0x97f3, 0x97f3 }, +/* 0x97f4 */ { false, 0x97f4, 0x97f4 }, +/* 0x97f5 */ { false, 0x97f5, 0x97f5 }, +/* 0x97f6 */ { false, 0x97f6, 0x97f6 }, +/* 0x97f7 */ { false, 0x97f7, 0x97f7 }, +/* 0x97f8 */ { false, 0x97f8, 0x97f8 }, +/* 0x97f9 */ { false, 0x97f9, 0x97f9 }, +/* 0x97fa */ { false, 0x97fa, 0x97fa }, +/* 0x97fb */ { false, 0x97fb, 0x97fb }, +/* 0x97fc */ { false, 0x97fc, 0x97fc }, +/* 0x97fd */ { false, 0x97fd, 0x97fd }, +/* 0x97fe */ { false, 0x97fe, 0x97fe }, +/* 0x97ff */ { false, 0x97ff, 0x97ff }, +/* 0x9800 */ { false, 0x9800, 0x9800 }, +/* 0x9801 */ { false, 0x9801, 0x9801 }, +/* 0x9802 */ { false, 0x9802, 0x9802 }, +/* 0x9803 */ { false, 0x9803, 0x9803 }, +/* 0x9804 */ { false, 0x9804, 0x9804 }, +/* 0x9805 */ { false, 0x9805, 0x9805 }, +/* 0x9806 */ { false, 0x9806, 0x9806 }, +/* 0x9807 */ { false, 0x9807, 0x9807 }, +/* 0x9808 */ { false, 0x9808, 0x9808 }, +/* 0x9809 */ { false, 0x9809, 0x9809 }, +/* 0x980a */ { false, 0x980a, 0x980a }, +/* 0x980b */ { false, 0x980b, 0x980b }, +/* 0x980c */ { false, 0x980c, 0x980c }, +/* 0x980d */ { false, 0x980d, 0x980d }, +/* 0x980e */ { false, 0x980e, 0x980e }, +/* 0x980f */ { false, 0x980f, 0x980f }, +/* 0x9810 */ { false, 0x9810, 0x9810 }, +/* 0x9811 */ { false, 0x9811, 0x9811 }, +/* 0x9812 */ { false, 0x9812, 0x9812 }, +/* 0x9813 */ { false, 0x9813, 0x9813 }, +/* 0x9814 */ { false, 0x9814, 0x9814 }, +/* 0x9815 */ { false, 0x9815, 0x9815 }, +/* 0x9816 */ { false, 0x9816, 0x9816 }, +/* 0x9817 */ { false, 0x9817, 0x9817 }, +/* 0x9818 */ { false, 0x9818, 0x9818 }, +/* 0x9819 */ { false, 0x9819, 0x9819 }, +/* 0x981a */ { false, 0x981a, 0x981a }, +/* 0x981b */ { false, 0x981b, 0x981b }, +/* 0x981c */ { false, 0x981c, 0x981c }, +/* 0x981d */ { false, 0x981d, 0x981d }, +/* 0x981e */ { false, 0x981e, 0x981e }, +/* 0x981f */ { false, 0x981f, 0x981f }, +/* 0x9820 */ { false, 0x9820, 0x9820 }, +/* 0x9821 */ { false, 0x9821, 0x9821 }, +/* 0x9822 */ { false, 0x9822, 0x9822 }, +/* 0x9823 */ { false, 0x9823, 0x9823 }, +/* 0x9824 */ { false, 0x9824, 0x9824 }, +/* 0x9825 */ { false, 0x9825, 0x9825 }, +/* 0x9826 */ { false, 0x9826, 0x9826 }, +/* 0x9827 */ { false, 0x9827, 0x9827 }, +/* 0x9828 */ { false, 0x9828, 0x9828 }, +/* 0x9829 */ { false, 0x9829, 0x9829 }, +/* 0x982a */ { false, 0x982a, 0x982a }, +/* 0x982b */ { false, 0x982b, 0x982b }, +/* 0x982c */ { false, 0x982c, 0x982c }, +/* 0x982d */ { false, 0x982d, 0x982d }, +/* 0x982e */ { false, 0x982e, 0x982e }, +/* 0x982f */ { false, 0x982f, 0x982f }, +/* 0x9830 */ { false, 0x9830, 0x9830 }, +/* 0x9831 */ { false, 0x9831, 0x9831 }, +/* 0x9832 */ { false, 0x9832, 0x9832 }, +/* 0x9833 */ { false, 0x9833, 0x9833 }, +/* 0x9834 */ { false, 0x9834, 0x9834 }, +/* 0x9835 */ { false, 0x9835, 0x9835 }, +/* 0x9836 */ { false, 0x9836, 0x9836 }, +/* 0x9837 */ { false, 0x9837, 0x9837 }, +/* 0x9838 */ { false, 0x9838, 0x9838 }, +/* 0x9839 */ { false, 0x9839, 0x9839 }, +/* 0x983a */ { false, 0x983a, 0x983a }, +/* 0x983b */ { false, 0x983b, 0x983b }, +/* 0x983c */ { false, 0x983c, 0x983c }, +/* 0x983d */ { false, 0x983d, 0x983d }, +/* 0x983e */ { false, 0x983e, 0x983e }, +/* 0x983f */ { false, 0x983f, 0x983f }, +/* 0x9840 */ { false, 0x9840, 0x9840 }, +/* 0x9841 */ { false, 0x9841, 0x9841 }, +/* 0x9842 */ { false, 0x9842, 0x9842 }, +/* 0x9843 */ { false, 0x9843, 0x9843 }, +/* 0x9844 */ { false, 0x9844, 0x9844 }, +/* 0x9845 */ { false, 0x9845, 0x9845 }, +/* 0x9846 */ { false, 0x9846, 0x9846 }, +/* 0x9847 */ { false, 0x9847, 0x9847 }, +/* 0x9848 */ { false, 0x9848, 0x9848 }, +/* 0x9849 */ { false, 0x9849, 0x9849 }, +/* 0x984a */ { false, 0x984a, 0x984a }, +/* 0x984b */ { false, 0x984b, 0x984b }, +/* 0x984c */ { false, 0x984c, 0x984c }, +/* 0x984d */ { false, 0x984d, 0x984d }, +/* 0x984e */ { false, 0x984e, 0x984e }, +/* 0x984f */ { false, 0x984f, 0x984f }, +/* 0x9850 */ { false, 0x9850, 0x9850 }, +/* 0x9851 */ { false, 0x9851, 0x9851 }, +/* 0x9852 */ { false, 0x9852, 0x9852 }, +/* 0x9853 */ { false, 0x9853, 0x9853 }, +/* 0x9854 */ { false, 0x9854, 0x9854 }, +/* 0x9855 */ { false, 0x9855, 0x9855 }, +/* 0x9856 */ { false, 0x9856, 0x9856 }, +/* 0x9857 */ { false, 0x9857, 0x9857 }, +/* 0x9858 */ { false, 0x9858, 0x9858 }, +/* 0x9859 */ { false, 0x9859, 0x9859 }, +/* 0x985a */ { false, 0x985a, 0x985a }, +/* 0x985b */ { false, 0x985b, 0x985b }, +/* 0x985c */ { false, 0x985c, 0x985c }, +/* 0x985d */ { false, 0x985d, 0x985d }, +/* 0x985e */ { false, 0x985e, 0x985e }, +/* 0x985f */ { false, 0x985f, 0x985f }, +/* 0x9860 */ { false, 0x9860, 0x9860 }, +/* 0x9861 */ { false, 0x9861, 0x9861 }, +/* 0x9862 */ { false, 0x9862, 0x9862 }, +/* 0x9863 */ { false, 0x9863, 0x9863 }, +/* 0x9864 */ { false, 0x9864, 0x9864 }, +/* 0x9865 */ { false, 0x9865, 0x9865 }, +/* 0x9866 */ { false, 0x9866, 0x9866 }, +/* 0x9867 */ { false, 0x9867, 0x9867 }, +/* 0x9868 */ { false, 0x9868, 0x9868 }, +/* 0x9869 */ { false, 0x9869, 0x9869 }, +/* 0x986a */ { false, 0x986a, 0x986a }, +/* 0x986b */ { false, 0x986b, 0x986b }, +/* 0x986c */ { false, 0x986c, 0x986c }, +/* 0x986d */ { false, 0x986d, 0x986d }, +/* 0x986e */ { false, 0x986e, 0x986e }, +/* 0x986f */ { false, 0x986f, 0x986f }, +/* 0x9870 */ { false, 0x9870, 0x9870 }, +/* 0x9871 */ { false, 0x9871, 0x9871 }, +/* 0x9872 */ { false, 0x9872, 0x9872 }, +/* 0x9873 */ { false, 0x9873, 0x9873 }, +/* 0x9874 */ { false, 0x9874, 0x9874 }, +/* 0x9875 */ { false, 0x9875, 0x9875 }, +/* 0x9876 */ { false, 0x9876, 0x9876 }, +/* 0x9877 */ { false, 0x9877, 0x9877 }, +/* 0x9878 */ { false, 0x9878, 0x9878 }, +/* 0x9879 */ { false, 0x9879, 0x9879 }, +/* 0x987a */ { false, 0x987a, 0x987a }, +/* 0x987b */ { false, 0x987b, 0x987b }, +/* 0x987c */ { false, 0x987c, 0x987c }, +/* 0x987d */ { false, 0x987d, 0x987d }, +/* 0x987e */ { false, 0x987e, 0x987e }, +/* 0x987f */ { false, 0x987f, 0x987f }, +/* 0x9880 */ { false, 0x9880, 0x9880 }, +/* 0x9881 */ { false, 0x9881, 0x9881 }, +/* 0x9882 */ { false, 0x9882, 0x9882 }, +/* 0x9883 */ { false, 0x9883, 0x9883 }, +/* 0x9884 */ { false, 0x9884, 0x9884 }, +/* 0x9885 */ { false, 0x9885, 0x9885 }, +/* 0x9886 */ { false, 0x9886, 0x9886 }, +/* 0x9887 */ { false, 0x9887, 0x9887 }, +/* 0x9888 */ { false, 0x9888, 0x9888 }, +/* 0x9889 */ { false, 0x9889, 0x9889 }, +/* 0x988a */ { false, 0x988a, 0x988a }, +/* 0x988b */ { false, 0x988b, 0x988b }, +/* 0x988c */ { false, 0x988c, 0x988c }, +/* 0x988d */ { false, 0x988d, 0x988d }, +/* 0x988e */ { false, 0x988e, 0x988e }, +/* 0x988f */ { false, 0x988f, 0x988f }, +/* 0x9890 */ { false, 0x9890, 0x9890 }, +/* 0x9891 */ { false, 0x9891, 0x9891 }, +/* 0x9892 */ { false, 0x9892, 0x9892 }, +/* 0x9893 */ { false, 0x9893, 0x9893 }, +/* 0x9894 */ { false, 0x9894, 0x9894 }, +/* 0x9895 */ { false, 0x9895, 0x9895 }, +/* 0x9896 */ { false, 0x9896, 0x9896 }, +/* 0x9897 */ { false, 0x9897, 0x9897 }, +/* 0x9898 */ { false, 0x9898, 0x9898 }, +/* 0x9899 */ { false, 0x9899, 0x9899 }, +/* 0x989a */ { false, 0x989a, 0x989a }, +/* 0x989b */ { false, 0x989b, 0x989b }, +/* 0x989c */ { false, 0x989c, 0x989c }, +/* 0x989d */ { false, 0x989d, 0x989d }, +/* 0x989e */ { false, 0x989e, 0x989e }, +/* 0x989f */ { false, 0x989f, 0x989f }, +/* 0x98a0 */ { false, 0x98a0, 0x98a0 }, +/* 0x98a1 */ { false, 0x98a1, 0x98a1 }, +/* 0x98a2 */ { false, 0x98a2, 0x98a2 }, +/* 0x98a3 */ { false, 0x98a3, 0x98a3 }, +/* 0x98a4 */ { false, 0x98a4, 0x98a4 }, +/* 0x98a5 */ { false, 0x98a5, 0x98a5 }, +/* 0x98a6 */ { false, 0x98a6, 0x98a6 }, +/* 0x98a7 */ { false, 0x98a7, 0x98a7 }, +/* 0x98a8 */ { false, 0x98a8, 0x98a8 }, +/* 0x98a9 */ { false, 0x98a9, 0x98a9 }, +/* 0x98aa */ { false, 0x98aa, 0x98aa }, +/* 0x98ab */ { false, 0x98ab, 0x98ab }, +/* 0x98ac */ { false, 0x98ac, 0x98ac }, +/* 0x98ad */ { false, 0x98ad, 0x98ad }, +/* 0x98ae */ { false, 0x98ae, 0x98ae }, +/* 0x98af */ { false, 0x98af, 0x98af }, +/* 0x98b0 */ { false, 0x98b0, 0x98b0 }, +/* 0x98b1 */ { false, 0x98b1, 0x98b1 }, +/* 0x98b2 */ { false, 0x98b2, 0x98b2 }, +/* 0x98b3 */ { false, 0x98b3, 0x98b3 }, +/* 0x98b4 */ { false, 0x98b4, 0x98b4 }, +/* 0x98b5 */ { false, 0x98b5, 0x98b5 }, +/* 0x98b6 */ { false, 0x98b6, 0x98b6 }, +/* 0x98b7 */ { false, 0x98b7, 0x98b7 }, +/* 0x98b8 */ { false, 0x98b8, 0x98b8 }, +/* 0x98b9 */ { false, 0x98b9, 0x98b9 }, +/* 0x98ba */ { false, 0x98ba, 0x98ba }, +/* 0x98bb */ { false, 0x98bb, 0x98bb }, +/* 0x98bc */ { false, 0x98bc, 0x98bc }, +/* 0x98bd */ { false, 0x98bd, 0x98bd }, +/* 0x98be */ { false, 0x98be, 0x98be }, +/* 0x98bf */ { false, 0x98bf, 0x98bf }, +/* 0x98c0 */ { false, 0x98c0, 0x98c0 }, +/* 0x98c1 */ { false, 0x98c1, 0x98c1 }, +/* 0x98c2 */ { false, 0x98c2, 0x98c2 }, +/* 0x98c3 */ { false, 0x98c3, 0x98c3 }, +/* 0x98c4 */ { false, 0x98c4, 0x98c4 }, +/* 0x98c5 */ { false, 0x98c5, 0x98c5 }, +/* 0x98c6 */ { false, 0x98c6, 0x98c6 }, +/* 0x98c7 */ { false, 0x98c7, 0x98c7 }, +/* 0x98c8 */ { false, 0x98c8, 0x98c8 }, +/* 0x98c9 */ { false, 0x98c9, 0x98c9 }, +/* 0x98ca */ { false, 0x98ca, 0x98ca }, +/* 0x98cb */ { false, 0x98cb, 0x98cb }, +/* 0x98cc */ { false, 0x98cc, 0x98cc }, +/* 0x98cd */ { false, 0x98cd, 0x98cd }, +/* 0x98ce */ { false, 0x98ce, 0x98ce }, +/* 0x98cf */ { false, 0x98cf, 0x98cf }, +/* 0x98d0 */ { false, 0x98d0, 0x98d0 }, +/* 0x98d1 */ { false, 0x98d1, 0x98d1 }, +/* 0x98d2 */ { false, 0x98d2, 0x98d2 }, +/* 0x98d3 */ { false, 0x98d3, 0x98d3 }, +/* 0x98d4 */ { false, 0x98d4, 0x98d4 }, +/* 0x98d5 */ { false, 0x98d5, 0x98d5 }, +/* 0x98d6 */ { false, 0x98d6, 0x98d6 }, +/* 0x98d7 */ { false, 0x98d7, 0x98d7 }, +/* 0x98d8 */ { false, 0x98d8, 0x98d8 }, +/* 0x98d9 */ { false, 0x98d9, 0x98d9 }, +/* 0x98da */ { false, 0x98da, 0x98da }, +/* 0x98db */ { false, 0x98db, 0x98db }, +/* 0x98dc */ { false, 0x98dc, 0x98dc }, +/* 0x98dd */ { false, 0x98dd, 0x98dd }, +/* 0x98de */ { false, 0x98de, 0x98de }, +/* 0x98df */ { false, 0x98df, 0x98df }, +/* 0x98e0 */ { false, 0x98e0, 0x98e0 }, +/* 0x98e1 */ { false, 0x98e1, 0x98e1 }, +/* 0x98e2 */ { false, 0x98e2, 0x98e2 }, +/* 0x98e3 */ { false, 0x98e3, 0x98e3 }, +/* 0x98e4 */ { false, 0x98e4, 0x98e4 }, +/* 0x98e5 */ { false, 0x98e5, 0x98e5 }, +/* 0x98e6 */ { false, 0x98e6, 0x98e6 }, +/* 0x98e7 */ { false, 0x98e7, 0x98e7 }, +/* 0x98e8 */ { false, 0x98e8, 0x98e8 }, +/* 0x98e9 */ { false, 0x98e9, 0x98e9 }, +/* 0x98ea */ { false, 0x98ea, 0x98ea }, +/* 0x98eb */ { false, 0x98eb, 0x98eb }, +/* 0x98ec */ { false, 0x98ec, 0x98ec }, +/* 0x98ed */ { false, 0x98ed, 0x98ed }, +/* 0x98ee */ { false, 0x98ee, 0x98ee }, +/* 0x98ef */ { false, 0x98ef, 0x98ef }, +/* 0x98f0 */ { false, 0x98f0, 0x98f0 }, +/* 0x98f1 */ { false, 0x98f1, 0x98f1 }, +/* 0x98f2 */ { false, 0x98f2, 0x98f2 }, +/* 0x98f3 */ { false, 0x98f3, 0x98f3 }, +/* 0x98f4 */ { false, 0x98f4, 0x98f4 }, +/* 0x98f5 */ { false, 0x98f5, 0x98f5 }, +/* 0x98f6 */ { false, 0x98f6, 0x98f6 }, +/* 0x98f7 */ { false, 0x98f7, 0x98f7 }, +/* 0x98f8 */ { false, 0x98f8, 0x98f8 }, +/* 0x98f9 */ { false, 0x98f9, 0x98f9 }, +/* 0x98fa */ { false, 0x98fa, 0x98fa }, +/* 0x98fb */ { false, 0x98fb, 0x98fb }, +/* 0x98fc */ { false, 0x98fc, 0x98fc }, +/* 0x98fd */ { false, 0x98fd, 0x98fd }, +/* 0x98fe */ { false, 0x98fe, 0x98fe }, +/* 0x98ff */ { false, 0x98ff, 0x98ff }, +/* 0x9900 */ { false, 0x9900, 0x9900 }, +/* 0x9901 */ { false, 0x9901, 0x9901 }, +/* 0x9902 */ { false, 0x9902, 0x9902 }, +/* 0x9903 */ { false, 0x9903, 0x9903 }, +/* 0x9904 */ { false, 0x9904, 0x9904 }, +/* 0x9905 */ { false, 0x9905, 0x9905 }, +/* 0x9906 */ { false, 0x9906, 0x9906 }, +/* 0x9907 */ { false, 0x9907, 0x9907 }, +/* 0x9908 */ { false, 0x9908, 0x9908 }, +/* 0x9909 */ { false, 0x9909, 0x9909 }, +/* 0x990a */ { false, 0x990a, 0x990a }, +/* 0x990b */ { false, 0x990b, 0x990b }, +/* 0x990c */ { false, 0x990c, 0x990c }, +/* 0x990d */ { false, 0x990d, 0x990d }, +/* 0x990e */ { false, 0x990e, 0x990e }, +/* 0x990f */ { false, 0x990f, 0x990f }, +/* 0x9910 */ { false, 0x9910, 0x9910 }, +/* 0x9911 */ { false, 0x9911, 0x9911 }, +/* 0x9912 */ { false, 0x9912, 0x9912 }, +/* 0x9913 */ { false, 0x9913, 0x9913 }, +/* 0x9914 */ { false, 0x9914, 0x9914 }, +/* 0x9915 */ { false, 0x9915, 0x9915 }, +/* 0x9916 */ { false, 0x9916, 0x9916 }, +/* 0x9917 */ { false, 0x9917, 0x9917 }, +/* 0x9918 */ { false, 0x9918, 0x9918 }, +/* 0x9919 */ { false, 0x9919, 0x9919 }, +/* 0x991a */ { false, 0x991a, 0x991a }, +/* 0x991b */ { false, 0x991b, 0x991b }, +/* 0x991c */ { false, 0x991c, 0x991c }, +/* 0x991d */ { false, 0x991d, 0x991d }, +/* 0x991e */ { false, 0x991e, 0x991e }, +/* 0x991f */ { false, 0x991f, 0x991f }, +/* 0x9920 */ { false, 0x9920, 0x9920 }, +/* 0x9921 */ { false, 0x9921, 0x9921 }, +/* 0x9922 */ { false, 0x9922, 0x9922 }, +/* 0x9923 */ { false, 0x9923, 0x9923 }, +/* 0x9924 */ { false, 0x9924, 0x9924 }, +/* 0x9925 */ { false, 0x9925, 0x9925 }, +/* 0x9926 */ { false, 0x9926, 0x9926 }, +/* 0x9927 */ { false, 0x9927, 0x9927 }, +/* 0x9928 */ { false, 0x9928, 0x9928 }, +/* 0x9929 */ { false, 0x9929, 0x9929 }, +/* 0x992a */ { false, 0x992a, 0x992a }, +/* 0x992b */ { false, 0x992b, 0x992b }, +/* 0x992c */ { false, 0x992c, 0x992c }, +/* 0x992d */ { false, 0x992d, 0x992d }, +/* 0x992e */ { false, 0x992e, 0x992e }, +/* 0x992f */ { false, 0x992f, 0x992f }, +/* 0x9930 */ { false, 0x9930, 0x9930 }, +/* 0x9931 */ { false, 0x9931, 0x9931 }, +/* 0x9932 */ { false, 0x9932, 0x9932 }, +/* 0x9933 */ { false, 0x9933, 0x9933 }, +/* 0x9934 */ { false, 0x9934, 0x9934 }, +/* 0x9935 */ { false, 0x9935, 0x9935 }, +/* 0x9936 */ { false, 0x9936, 0x9936 }, +/* 0x9937 */ { false, 0x9937, 0x9937 }, +/* 0x9938 */ { false, 0x9938, 0x9938 }, +/* 0x9939 */ { false, 0x9939, 0x9939 }, +/* 0x993a */ { false, 0x993a, 0x993a }, +/* 0x993b */ { false, 0x993b, 0x993b }, +/* 0x993c */ { false, 0x993c, 0x993c }, +/* 0x993d */ { false, 0x993d, 0x993d }, +/* 0x993e */ { false, 0x993e, 0x993e }, +/* 0x993f */ { false, 0x993f, 0x993f }, +/* 0x9940 */ { false, 0x9940, 0x9940 }, +/* 0x9941 */ { false, 0x9941, 0x9941 }, +/* 0x9942 */ { false, 0x9942, 0x9942 }, +/* 0x9943 */ { false, 0x9943, 0x9943 }, +/* 0x9944 */ { false, 0x9944, 0x9944 }, +/* 0x9945 */ { false, 0x9945, 0x9945 }, +/* 0x9946 */ { false, 0x9946, 0x9946 }, +/* 0x9947 */ { false, 0x9947, 0x9947 }, +/* 0x9948 */ { false, 0x9948, 0x9948 }, +/* 0x9949 */ { false, 0x9949, 0x9949 }, +/* 0x994a */ { false, 0x994a, 0x994a }, +/* 0x994b */ { false, 0x994b, 0x994b }, +/* 0x994c */ { false, 0x994c, 0x994c }, +/* 0x994d */ { false, 0x994d, 0x994d }, +/* 0x994e */ { false, 0x994e, 0x994e }, +/* 0x994f */ { false, 0x994f, 0x994f }, +/* 0x9950 */ { false, 0x9950, 0x9950 }, +/* 0x9951 */ { false, 0x9951, 0x9951 }, +/* 0x9952 */ { false, 0x9952, 0x9952 }, +/* 0x9953 */ { false, 0x9953, 0x9953 }, +/* 0x9954 */ { false, 0x9954, 0x9954 }, +/* 0x9955 */ { false, 0x9955, 0x9955 }, +/* 0x9956 */ { false, 0x9956, 0x9956 }, +/* 0x9957 */ { false, 0x9957, 0x9957 }, +/* 0x9958 */ { false, 0x9958, 0x9958 }, +/* 0x9959 */ { false, 0x9959, 0x9959 }, +/* 0x995a */ { false, 0x995a, 0x995a }, +/* 0x995b */ { false, 0x995b, 0x995b }, +/* 0x995c */ { false, 0x995c, 0x995c }, +/* 0x995d */ { false, 0x995d, 0x995d }, +/* 0x995e */ { false, 0x995e, 0x995e }, +/* 0x995f */ { false, 0x995f, 0x995f }, +/* 0x9960 */ { false, 0x9960, 0x9960 }, +/* 0x9961 */ { false, 0x9961, 0x9961 }, +/* 0x9962 */ { false, 0x9962, 0x9962 }, +/* 0x9963 */ { false, 0x9963, 0x9963 }, +/* 0x9964 */ { false, 0x9964, 0x9964 }, +/* 0x9965 */ { false, 0x9965, 0x9965 }, +/* 0x9966 */ { false, 0x9966, 0x9966 }, +/* 0x9967 */ { false, 0x9967, 0x9967 }, +/* 0x9968 */ { false, 0x9968, 0x9968 }, +/* 0x9969 */ { false, 0x9969, 0x9969 }, +/* 0x996a */ { false, 0x996a, 0x996a }, +/* 0x996b */ { false, 0x996b, 0x996b }, +/* 0x996c */ { false, 0x996c, 0x996c }, +/* 0x996d */ { false, 0x996d, 0x996d }, +/* 0x996e */ { false, 0x996e, 0x996e }, +/* 0x996f */ { false, 0x996f, 0x996f }, +/* 0x9970 */ { false, 0x9970, 0x9970 }, +/* 0x9971 */ { false, 0x9971, 0x9971 }, +/* 0x9972 */ { false, 0x9972, 0x9972 }, +/* 0x9973 */ { false, 0x9973, 0x9973 }, +/* 0x9974 */ { false, 0x9974, 0x9974 }, +/* 0x9975 */ { false, 0x9975, 0x9975 }, +/* 0x9976 */ { false, 0x9976, 0x9976 }, +/* 0x9977 */ { false, 0x9977, 0x9977 }, +/* 0x9978 */ { false, 0x9978, 0x9978 }, +/* 0x9979 */ { false, 0x9979, 0x9979 }, +/* 0x997a */ { false, 0x997a, 0x997a }, +/* 0x997b */ { false, 0x997b, 0x997b }, +/* 0x997c */ { false, 0x997c, 0x997c }, +/* 0x997d */ { false, 0x997d, 0x997d }, +/* 0x997e */ { false, 0x997e, 0x997e }, +/* 0x997f */ { false, 0x997f, 0x997f }, +/* 0x9980 */ { false, 0x9980, 0x9980 }, +/* 0x9981 */ { false, 0x9981, 0x9981 }, +/* 0x9982 */ { false, 0x9982, 0x9982 }, +/* 0x9983 */ { false, 0x9983, 0x9983 }, +/* 0x9984 */ { false, 0x9984, 0x9984 }, +/* 0x9985 */ { false, 0x9985, 0x9985 }, +/* 0x9986 */ { false, 0x9986, 0x9986 }, +/* 0x9987 */ { false, 0x9987, 0x9987 }, +/* 0x9988 */ { false, 0x9988, 0x9988 }, +/* 0x9989 */ { false, 0x9989, 0x9989 }, +/* 0x998a */ { false, 0x998a, 0x998a }, +/* 0x998b */ { false, 0x998b, 0x998b }, +/* 0x998c */ { false, 0x998c, 0x998c }, +/* 0x998d */ { false, 0x998d, 0x998d }, +/* 0x998e */ { false, 0x998e, 0x998e }, +/* 0x998f */ { false, 0x998f, 0x998f }, +/* 0x9990 */ { false, 0x9990, 0x9990 }, +/* 0x9991 */ { false, 0x9991, 0x9991 }, +/* 0x9992 */ { false, 0x9992, 0x9992 }, +/* 0x9993 */ { false, 0x9993, 0x9993 }, +/* 0x9994 */ { false, 0x9994, 0x9994 }, +/* 0x9995 */ { false, 0x9995, 0x9995 }, +/* 0x9996 */ { false, 0x9996, 0x9996 }, +/* 0x9997 */ { false, 0x9997, 0x9997 }, +/* 0x9998 */ { false, 0x9998, 0x9998 }, +/* 0x9999 */ { false, 0x9999, 0x9999 }, +/* 0x999a */ { false, 0x999a, 0x999a }, +/* 0x999b */ { false, 0x999b, 0x999b }, +/* 0x999c */ { false, 0x999c, 0x999c }, +/* 0x999d */ { false, 0x999d, 0x999d }, +/* 0x999e */ { false, 0x999e, 0x999e }, +/* 0x999f */ { false, 0x999f, 0x999f }, +/* 0x99a0 */ { false, 0x99a0, 0x99a0 }, +/* 0x99a1 */ { false, 0x99a1, 0x99a1 }, +/* 0x99a2 */ { false, 0x99a2, 0x99a2 }, +/* 0x99a3 */ { false, 0x99a3, 0x99a3 }, +/* 0x99a4 */ { false, 0x99a4, 0x99a4 }, +/* 0x99a5 */ { false, 0x99a5, 0x99a5 }, +/* 0x99a6 */ { false, 0x99a6, 0x99a6 }, +/* 0x99a7 */ { false, 0x99a7, 0x99a7 }, +/* 0x99a8 */ { false, 0x99a8, 0x99a8 }, +/* 0x99a9 */ { false, 0x99a9, 0x99a9 }, +/* 0x99aa */ { false, 0x99aa, 0x99aa }, +/* 0x99ab */ { false, 0x99ab, 0x99ab }, +/* 0x99ac */ { false, 0x99ac, 0x99ac }, +/* 0x99ad */ { false, 0x99ad, 0x99ad }, +/* 0x99ae */ { false, 0x99ae, 0x99ae }, +/* 0x99af */ { false, 0x99af, 0x99af }, +/* 0x99b0 */ { false, 0x99b0, 0x99b0 }, +/* 0x99b1 */ { false, 0x99b1, 0x99b1 }, +/* 0x99b2 */ { false, 0x99b2, 0x99b2 }, +/* 0x99b3 */ { false, 0x99b3, 0x99b3 }, +/* 0x99b4 */ { false, 0x99b4, 0x99b4 }, +/* 0x99b5 */ { false, 0x99b5, 0x99b5 }, +/* 0x99b6 */ { false, 0x99b6, 0x99b6 }, +/* 0x99b7 */ { false, 0x99b7, 0x99b7 }, +/* 0x99b8 */ { false, 0x99b8, 0x99b8 }, +/* 0x99b9 */ { false, 0x99b9, 0x99b9 }, +/* 0x99ba */ { false, 0x99ba, 0x99ba }, +/* 0x99bb */ { false, 0x99bb, 0x99bb }, +/* 0x99bc */ { false, 0x99bc, 0x99bc }, +/* 0x99bd */ { false, 0x99bd, 0x99bd }, +/* 0x99be */ { false, 0x99be, 0x99be }, +/* 0x99bf */ { false, 0x99bf, 0x99bf }, +/* 0x99c0 */ { false, 0x99c0, 0x99c0 }, +/* 0x99c1 */ { false, 0x99c1, 0x99c1 }, +/* 0x99c2 */ { false, 0x99c2, 0x99c2 }, +/* 0x99c3 */ { false, 0x99c3, 0x99c3 }, +/* 0x99c4 */ { false, 0x99c4, 0x99c4 }, +/* 0x99c5 */ { false, 0x99c5, 0x99c5 }, +/* 0x99c6 */ { false, 0x99c6, 0x99c6 }, +/* 0x99c7 */ { false, 0x99c7, 0x99c7 }, +/* 0x99c8 */ { false, 0x99c8, 0x99c8 }, +/* 0x99c9 */ { false, 0x99c9, 0x99c9 }, +/* 0x99ca */ { false, 0x99ca, 0x99ca }, +/* 0x99cb */ { false, 0x99cb, 0x99cb }, +/* 0x99cc */ { false, 0x99cc, 0x99cc }, +/* 0x99cd */ { false, 0x99cd, 0x99cd }, +/* 0x99ce */ { false, 0x99ce, 0x99ce }, +/* 0x99cf */ { false, 0x99cf, 0x99cf }, +/* 0x99d0 */ { false, 0x99d0, 0x99d0 }, +/* 0x99d1 */ { false, 0x99d1, 0x99d1 }, +/* 0x99d2 */ { false, 0x99d2, 0x99d2 }, +/* 0x99d3 */ { false, 0x99d3, 0x99d3 }, +/* 0x99d4 */ { false, 0x99d4, 0x99d4 }, +/* 0x99d5 */ { false, 0x99d5, 0x99d5 }, +/* 0x99d6 */ { false, 0x99d6, 0x99d6 }, +/* 0x99d7 */ { false, 0x99d7, 0x99d7 }, +/* 0x99d8 */ { false, 0x99d8, 0x99d8 }, +/* 0x99d9 */ { false, 0x99d9, 0x99d9 }, +/* 0x99da */ { false, 0x99da, 0x99da }, +/* 0x99db */ { false, 0x99db, 0x99db }, +/* 0x99dc */ { false, 0x99dc, 0x99dc }, +/* 0x99dd */ { false, 0x99dd, 0x99dd }, +/* 0x99de */ { false, 0x99de, 0x99de }, +/* 0x99df */ { false, 0x99df, 0x99df }, +/* 0x99e0 */ { false, 0x99e0, 0x99e0 }, +/* 0x99e1 */ { false, 0x99e1, 0x99e1 }, +/* 0x99e2 */ { false, 0x99e2, 0x99e2 }, +/* 0x99e3 */ { false, 0x99e3, 0x99e3 }, +/* 0x99e4 */ { false, 0x99e4, 0x99e4 }, +/* 0x99e5 */ { false, 0x99e5, 0x99e5 }, +/* 0x99e6 */ { false, 0x99e6, 0x99e6 }, +/* 0x99e7 */ { false, 0x99e7, 0x99e7 }, +/* 0x99e8 */ { false, 0x99e8, 0x99e8 }, +/* 0x99e9 */ { false, 0x99e9, 0x99e9 }, +/* 0x99ea */ { false, 0x99ea, 0x99ea }, +/* 0x99eb */ { false, 0x99eb, 0x99eb }, +/* 0x99ec */ { false, 0x99ec, 0x99ec }, +/* 0x99ed */ { false, 0x99ed, 0x99ed }, +/* 0x99ee */ { false, 0x99ee, 0x99ee }, +/* 0x99ef */ { false, 0x99ef, 0x99ef }, +/* 0x99f0 */ { false, 0x99f0, 0x99f0 }, +/* 0x99f1 */ { false, 0x99f1, 0x99f1 }, +/* 0x99f2 */ { false, 0x99f2, 0x99f2 }, +/* 0x99f3 */ { false, 0x99f3, 0x99f3 }, +/* 0x99f4 */ { false, 0x99f4, 0x99f4 }, +/* 0x99f5 */ { false, 0x99f5, 0x99f5 }, +/* 0x99f6 */ { false, 0x99f6, 0x99f6 }, +/* 0x99f7 */ { false, 0x99f7, 0x99f7 }, +/* 0x99f8 */ { false, 0x99f8, 0x99f8 }, +/* 0x99f9 */ { false, 0x99f9, 0x99f9 }, +/* 0x99fa */ { false, 0x99fa, 0x99fa }, +/* 0x99fb */ { false, 0x99fb, 0x99fb }, +/* 0x99fc */ { false, 0x99fc, 0x99fc }, +/* 0x99fd */ { false, 0x99fd, 0x99fd }, +/* 0x99fe */ { false, 0x99fe, 0x99fe }, +/* 0x99ff */ { false, 0x99ff, 0x99ff }, +/* 0x9a00 */ { false, 0x9a00, 0x9a00 }, +/* 0x9a01 */ { false, 0x9a01, 0x9a01 }, +/* 0x9a02 */ { false, 0x9a02, 0x9a02 }, +/* 0x9a03 */ { false, 0x9a03, 0x9a03 }, +/* 0x9a04 */ { false, 0x9a04, 0x9a04 }, +/* 0x9a05 */ { false, 0x9a05, 0x9a05 }, +/* 0x9a06 */ { false, 0x9a06, 0x9a06 }, +/* 0x9a07 */ { false, 0x9a07, 0x9a07 }, +/* 0x9a08 */ { false, 0x9a08, 0x9a08 }, +/* 0x9a09 */ { false, 0x9a09, 0x9a09 }, +/* 0x9a0a */ { false, 0x9a0a, 0x9a0a }, +/* 0x9a0b */ { false, 0x9a0b, 0x9a0b }, +/* 0x9a0c */ { false, 0x9a0c, 0x9a0c }, +/* 0x9a0d */ { false, 0x9a0d, 0x9a0d }, +/* 0x9a0e */ { false, 0x9a0e, 0x9a0e }, +/* 0x9a0f */ { false, 0x9a0f, 0x9a0f }, +/* 0x9a10 */ { false, 0x9a10, 0x9a10 }, +/* 0x9a11 */ { false, 0x9a11, 0x9a11 }, +/* 0x9a12 */ { false, 0x9a12, 0x9a12 }, +/* 0x9a13 */ { false, 0x9a13, 0x9a13 }, +/* 0x9a14 */ { false, 0x9a14, 0x9a14 }, +/* 0x9a15 */ { false, 0x9a15, 0x9a15 }, +/* 0x9a16 */ { false, 0x9a16, 0x9a16 }, +/* 0x9a17 */ { false, 0x9a17, 0x9a17 }, +/* 0x9a18 */ { false, 0x9a18, 0x9a18 }, +/* 0x9a19 */ { false, 0x9a19, 0x9a19 }, +/* 0x9a1a */ { false, 0x9a1a, 0x9a1a }, +/* 0x9a1b */ { false, 0x9a1b, 0x9a1b }, +/* 0x9a1c */ { false, 0x9a1c, 0x9a1c }, +/* 0x9a1d */ { false, 0x9a1d, 0x9a1d }, +/* 0x9a1e */ { false, 0x9a1e, 0x9a1e }, +/* 0x9a1f */ { false, 0x9a1f, 0x9a1f }, +/* 0x9a20 */ { false, 0x9a20, 0x9a20 }, +/* 0x9a21 */ { false, 0x9a21, 0x9a21 }, +/* 0x9a22 */ { false, 0x9a22, 0x9a22 }, +/* 0x9a23 */ { false, 0x9a23, 0x9a23 }, +/* 0x9a24 */ { false, 0x9a24, 0x9a24 }, +/* 0x9a25 */ { false, 0x9a25, 0x9a25 }, +/* 0x9a26 */ { false, 0x9a26, 0x9a26 }, +/* 0x9a27 */ { false, 0x9a27, 0x9a27 }, +/* 0x9a28 */ { false, 0x9a28, 0x9a28 }, +/* 0x9a29 */ { false, 0x9a29, 0x9a29 }, +/* 0x9a2a */ { false, 0x9a2a, 0x9a2a }, +/* 0x9a2b */ { false, 0x9a2b, 0x9a2b }, +/* 0x9a2c */ { false, 0x9a2c, 0x9a2c }, +/* 0x9a2d */ { false, 0x9a2d, 0x9a2d }, +/* 0x9a2e */ { false, 0x9a2e, 0x9a2e }, +/* 0x9a2f */ { false, 0x9a2f, 0x9a2f }, +/* 0x9a30 */ { false, 0x9a30, 0x9a30 }, +/* 0x9a31 */ { false, 0x9a31, 0x9a31 }, +/* 0x9a32 */ { false, 0x9a32, 0x9a32 }, +/* 0x9a33 */ { false, 0x9a33, 0x9a33 }, +/* 0x9a34 */ { false, 0x9a34, 0x9a34 }, +/* 0x9a35 */ { false, 0x9a35, 0x9a35 }, +/* 0x9a36 */ { false, 0x9a36, 0x9a36 }, +/* 0x9a37 */ { false, 0x9a37, 0x9a37 }, +/* 0x9a38 */ { false, 0x9a38, 0x9a38 }, +/* 0x9a39 */ { false, 0x9a39, 0x9a39 }, +/* 0x9a3a */ { false, 0x9a3a, 0x9a3a }, +/* 0x9a3b */ { false, 0x9a3b, 0x9a3b }, +/* 0x9a3c */ { false, 0x9a3c, 0x9a3c }, +/* 0x9a3d */ { false, 0x9a3d, 0x9a3d }, +/* 0x9a3e */ { false, 0x9a3e, 0x9a3e }, +/* 0x9a3f */ { false, 0x9a3f, 0x9a3f }, +/* 0x9a40 */ { false, 0x9a40, 0x9a40 }, +/* 0x9a41 */ { false, 0x9a41, 0x9a41 }, +/* 0x9a42 */ { false, 0x9a42, 0x9a42 }, +/* 0x9a43 */ { false, 0x9a43, 0x9a43 }, +/* 0x9a44 */ { false, 0x9a44, 0x9a44 }, +/* 0x9a45 */ { false, 0x9a45, 0x9a45 }, +/* 0x9a46 */ { false, 0x9a46, 0x9a46 }, +/* 0x9a47 */ { false, 0x9a47, 0x9a47 }, +/* 0x9a48 */ { false, 0x9a48, 0x9a48 }, +/* 0x9a49 */ { false, 0x9a49, 0x9a49 }, +/* 0x9a4a */ { false, 0x9a4a, 0x9a4a }, +/* 0x9a4b */ { false, 0x9a4b, 0x9a4b }, +/* 0x9a4c */ { false, 0x9a4c, 0x9a4c }, +/* 0x9a4d */ { false, 0x9a4d, 0x9a4d }, +/* 0x9a4e */ { false, 0x9a4e, 0x9a4e }, +/* 0x9a4f */ { false, 0x9a4f, 0x9a4f }, +/* 0x9a50 */ { false, 0x9a50, 0x9a50 }, +/* 0x9a51 */ { false, 0x9a51, 0x9a51 }, +/* 0x9a52 */ { false, 0x9a52, 0x9a52 }, +/* 0x9a53 */ { false, 0x9a53, 0x9a53 }, +/* 0x9a54 */ { false, 0x9a54, 0x9a54 }, +/* 0x9a55 */ { false, 0x9a55, 0x9a55 }, +/* 0x9a56 */ { false, 0x9a56, 0x9a56 }, +/* 0x9a57 */ { false, 0x9a57, 0x9a57 }, +/* 0x9a58 */ { false, 0x9a58, 0x9a58 }, +/* 0x9a59 */ { false, 0x9a59, 0x9a59 }, +/* 0x9a5a */ { false, 0x9a5a, 0x9a5a }, +/* 0x9a5b */ { false, 0x9a5b, 0x9a5b }, +/* 0x9a5c */ { false, 0x9a5c, 0x9a5c }, +/* 0x9a5d */ { false, 0x9a5d, 0x9a5d }, +/* 0x9a5e */ { false, 0x9a5e, 0x9a5e }, +/* 0x9a5f */ { false, 0x9a5f, 0x9a5f }, +/* 0x9a60 */ { false, 0x9a60, 0x9a60 }, +/* 0x9a61 */ { false, 0x9a61, 0x9a61 }, +/* 0x9a62 */ { false, 0x9a62, 0x9a62 }, +/* 0x9a63 */ { false, 0x9a63, 0x9a63 }, +/* 0x9a64 */ { false, 0x9a64, 0x9a64 }, +/* 0x9a65 */ { false, 0x9a65, 0x9a65 }, +/* 0x9a66 */ { false, 0x9a66, 0x9a66 }, +/* 0x9a67 */ { false, 0x9a67, 0x9a67 }, +/* 0x9a68 */ { false, 0x9a68, 0x9a68 }, +/* 0x9a69 */ { false, 0x9a69, 0x9a69 }, +/* 0x9a6a */ { false, 0x9a6a, 0x9a6a }, +/* 0x9a6b */ { false, 0x9a6b, 0x9a6b }, +/* 0x9a6c */ { false, 0x9a6c, 0x9a6c }, +/* 0x9a6d */ { false, 0x9a6d, 0x9a6d }, +/* 0x9a6e */ { false, 0x9a6e, 0x9a6e }, +/* 0x9a6f */ { false, 0x9a6f, 0x9a6f }, +/* 0x9a70 */ { false, 0x9a70, 0x9a70 }, +/* 0x9a71 */ { false, 0x9a71, 0x9a71 }, +/* 0x9a72 */ { false, 0x9a72, 0x9a72 }, +/* 0x9a73 */ { false, 0x9a73, 0x9a73 }, +/* 0x9a74 */ { false, 0x9a74, 0x9a74 }, +/* 0x9a75 */ { false, 0x9a75, 0x9a75 }, +/* 0x9a76 */ { false, 0x9a76, 0x9a76 }, +/* 0x9a77 */ { false, 0x9a77, 0x9a77 }, +/* 0x9a78 */ { false, 0x9a78, 0x9a78 }, +/* 0x9a79 */ { false, 0x9a79, 0x9a79 }, +/* 0x9a7a */ { false, 0x9a7a, 0x9a7a }, +/* 0x9a7b */ { false, 0x9a7b, 0x9a7b }, +/* 0x9a7c */ { false, 0x9a7c, 0x9a7c }, +/* 0x9a7d */ { false, 0x9a7d, 0x9a7d }, +/* 0x9a7e */ { false, 0x9a7e, 0x9a7e }, +/* 0x9a7f */ { false, 0x9a7f, 0x9a7f }, +/* 0x9a80 */ { false, 0x9a80, 0x9a80 }, +/* 0x9a81 */ { false, 0x9a81, 0x9a81 }, +/* 0x9a82 */ { false, 0x9a82, 0x9a82 }, +/* 0x9a83 */ { false, 0x9a83, 0x9a83 }, +/* 0x9a84 */ { false, 0x9a84, 0x9a84 }, +/* 0x9a85 */ { false, 0x9a85, 0x9a85 }, +/* 0x9a86 */ { false, 0x9a86, 0x9a86 }, +/* 0x9a87 */ { false, 0x9a87, 0x9a87 }, +/* 0x9a88 */ { false, 0x9a88, 0x9a88 }, +/* 0x9a89 */ { false, 0x9a89, 0x9a89 }, +/* 0x9a8a */ { false, 0x9a8a, 0x9a8a }, +/* 0x9a8b */ { false, 0x9a8b, 0x9a8b }, +/* 0x9a8c */ { false, 0x9a8c, 0x9a8c }, +/* 0x9a8d */ { false, 0x9a8d, 0x9a8d }, +/* 0x9a8e */ { false, 0x9a8e, 0x9a8e }, +/* 0x9a8f */ { false, 0x9a8f, 0x9a8f }, +/* 0x9a90 */ { false, 0x9a90, 0x9a90 }, +/* 0x9a91 */ { false, 0x9a91, 0x9a91 }, +/* 0x9a92 */ { false, 0x9a92, 0x9a92 }, +/* 0x9a93 */ { false, 0x9a93, 0x9a93 }, +/* 0x9a94 */ { false, 0x9a94, 0x9a94 }, +/* 0x9a95 */ { false, 0x9a95, 0x9a95 }, +/* 0x9a96 */ { false, 0x9a96, 0x9a96 }, +/* 0x9a97 */ { false, 0x9a97, 0x9a97 }, +/* 0x9a98 */ { false, 0x9a98, 0x9a98 }, +/* 0x9a99 */ { false, 0x9a99, 0x9a99 }, +/* 0x9a9a */ { false, 0x9a9a, 0x9a9a }, +/* 0x9a9b */ { false, 0x9a9b, 0x9a9b }, +/* 0x9a9c */ { false, 0x9a9c, 0x9a9c }, +/* 0x9a9d */ { false, 0x9a9d, 0x9a9d }, +/* 0x9a9e */ { false, 0x9a9e, 0x9a9e }, +/* 0x9a9f */ { false, 0x9a9f, 0x9a9f }, +/* 0x9aa0 */ { false, 0x9aa0, 0x9aa0 }, +/* 0x9aa1 */ { false, 0x9aa1, 0x9aa1 }, +/* 0x9aa2 */ { false, 0x9aa2, 0x9aa2 }, +/* 0x9aa3 */ { false, 0x9aa3, 0x9aa3 }, +/* 0x9aa4 */ { false, 0x9aa4, 0x9aa4 }, +/* 0x9aa5 */ { false, 0x9aa5, 0x9aa5 }, +/* 0x9aa6 */ { false, 0x9aa6, 0x9aa6 }, +/* 0x9aa7 */ { false, 0x9aa7, 0x9aa7 }, +/* 0x9aa8 */ { false, 0x9aa8, 0x9aa8 }, +/* 0x9aa9 */ { false, 0x9aa9, 0x9aa9 }, +/* 0x9aaa */ { false, 0x9aaa, 0x9aaa }, +/* 0x9aab */ { false, 0x9aab, 0x9aab }, +/* 0x9aac */ { false, 0x9aac, 0x9aac }, +/* 0x9aad */ { false, 0x9aad, 0x9aad }, +/* 0x9aae */ { false, 0x9aae, 0x9aae }, +/* 0x9aaf */ { false, 0x9aaf, 0x9aaf }, +/* 0x9ab0 */ { false, 0x9ab0, 0x9ab0 }, +/* 0x9ab1 */ { false, 0x9ab1, 0x9ab1 }, +/* 0x9ab2 */ { false, 0x9ab2, 0x9ab2 }, +/* 0x9ab3 */ { false, 0x9ab3, 0x9ab3 }, +/* 0x9ab4 */ { false, 0x9ab4, 0x9ab4 }, +/* 0x9ab5 */ { false, 0x9ab5, 0x9ab5 }, +/* 0x9ab6 */ { false, 0x9ab6, 0x9ab6 }, +/* 0x9ab7 */ { false, 0x9ab7, 0x9ab7 }, +/* 0x9ab8 */ { false, 0x9ab8, 0x9ab8 }, +/* 0x9ab9 */ { false, 0x9ab9, 0x9ab9 }, +/* 0x9aba */ { false, 0x9aba, 0x9aba }, +/* 0x9abb */ { false, 0x9abb, 0x9abb }, +/* 0x9abc */ { false, 0x9abc, 0x9abc }, +/* 0x9abd */ { false, 0x9abd, 0x9abd }, +/* 0x9abe */ { false, 0x9abe, 0x9abe }, +/* 0x9abf */ { false, 0x9abf, 0x9abf }, +/* 0x9ac0 */ { false, 0x9ac0, 0x9ac0 }, +/* 0x9ac1 */ { false, 0x9ac1, 0x9ac1 }, +/* 0x9ac2 */ { false, 0x9ac2, 0x9ac2 }, +/* 0x9ac3 */ { false, 0x9ac3, 0x9ac3 }, +/* 0x9ac4 */ { false, 0x9ac4, 0x9ac4 }, +/* 0x9ac5 */ { false, 0x9ac5, 0x9ac5 }, +/* 0x9ac6 */ { false, 0x9ac6, 0x9ac6 }, +/* 0x9ac7 */ { false, 0x9ac7, 0x9ac7 }, +/* 0x9ac8 */ { false, 0x9ac8, 0x9ac8 }, +/* 0x9ac9 */ { false, 0x9ac9, 0x9ac9 }, +/* 0x9aca */ { false, 0x9aca, 0x9aca }, +/* 0x9acb */ { false, 0x9acb, 0x9acb }, +/* 0x9acc */ { false, 0x9acc, 0x9acc }, +/* 0x9acd */ { false, 0x9acd, 0x9acd }, +/* 0x9ace */ { false, 0x9ace, 0x9ace }, +/* 0x9acf */ { false, 0x9acf, 0x9acf }, +/* 0x9ad0 */ { false, 0x9ad0, 0x9ad0 }, +/* 0x9ad1 */ { false, 0x9ad1, 0x9ad1 }, +/* 0x9ad2 */ { false, 0x9ad2, 0x9ad2 }, +/* 0x9ad3 */ { false, 0x9ad3, 0x9ad3 }, +/* 0x9ad4 */ { false, 0x9ad4, 0x9ad4 }, +/* 0x9ad5 */ { false, 0x9ad5, 0x9ad5 }, +/* 0x9ad6 */ { false, 0x9ad6, 0x9ad6 }, +/* 0x9ad7 */ { false, 0x9ad7, 0x9ad7 }, +/* 0x9ad8 */ { false, 0x9ad8, 0x9ad8 }, +/* 0x9ad9 */ { false, 0x9ad9, 0x9ad9 }, +/* 0x9ada */ { false, 0x9ada, 0x9ada }, +/* 0x9adb */ { false, 0x9adb, 0x9adb }, +/* 0x9adc */ { false, 0x9adc, 0x9adc }, +/* 0x9add */ { false, 0x9add, 0x9add }, +/* 0x9ade */ { false, 0x9ade, 0x9ade }, +/* 0x9adf */ { false, 0x9adf, 0x9adf }, +/* 0x9ae0 */ { false, 0x9ae0, 0x9ae0 }, +/* 0x9ae1 */ { false, 0x9ae1, 0x9ae1 }, +/* 0x9ae2 */ { false, 0x9ae2, 0x9ae2 }, +/* 0x9ae3 */ { false, 0x9ae3, 0x9ae3 }, +/* 0x9ae4 */ { false, 0x9ae4, 0x9ae4 }, +/* 0x9ae5 */ { false, 0x9ae5, 0x9ae5 }, +/* 0x9ae6 */ { false, 0x9ae6, 0x9ae6 }, +/* 0x9ae7 */ { false, 0x9ae7, 0x9ae7 }, +/* 0x9ae8 */ { false, 0x9ae8, 0x9ae8 }, +/* 0x9ae9 */ { false, 0x9ae9, 0x9ae9 }, +/* 0x9aea */ { false, 0x9aea, 0x9aea }, +/* 0x9aeb */ { false, 0x9aeb, 0x9aeb }, +/* 0x9aec */ { false, 0x9aec, 0x9aec }, +/* 0x9aed */ { false, 0x9aed, 0x9aed }, +/* 0x9aee */ { false, 0x9aee, 0x9aee }, +/* 0x9aef */ { false, 0x9aef, 0x9aef }, +/* 0x9af0 */ { false, 0x9af0, 0x9af0 }, +/* 0x9af1 */ { false, 0x9af1, 0x9af1 }, +/* 0x9af2 */ { false, 0x9af2, 0x9af2 }, +/* 0x9af3 */ { false, 0x9af3, 0x9af3 }, +/* 0x9af4 */ { false, 0x9af4, 0x9af4 }, +/* 0x9af5 */ { false, 0x9af5, 0x9af5 }, +/* 0x9af6 */ { false, 0x9af6, 0x9af6 }, +/* 0x9af7 */ { false, 0x9af7, 0x9af7 }, +/* 0x9af8 */ { false, 0x9af8, 0x9af8 }, +/* 0x9af9 */ { false, 0x9af9, 0x9af9 }, +/* 0x9afa */ { false, 0x9afa, 0x9afa }, +/* 0x9afb */ { false, 0x9afb, 0x9afb }, +/* 0x9afc */ { false, 0x9afc, 0x9afc }, +/* 0x9afd */ { false, 0x9afd, 0x9afd }, +/* 0x9afe */ { false, 0x9afe, 0x9afe }, +/* 0x9aff */ { false, 0x9aff, 0x9aff }, +/* 0x9b00 */ { false, 0x9b00, 0x9b00 }, +/* 0x9b01 */ { false, 0x9b01, 0x9b01 }, +/* 0x9b02 */ { false, 0x9b02, 0x9b02 }, +/* 0x9b03 */ { false, 0x9b03, 0x9b03 }, +/* 0x9b04 */ { false, 0x9b04, 0x9b04 }, +/* 0x9b05 */ { false, 0x9b05, 0x9b05 }, +/* 0x9b06 */ { false, 0x9b06, 0x9b06 }, +/* 0x9b07 */ { false, 0x9b07, 0x9b07 }, +/* 0x9b08 */ { false, 0x9b08, 0x9b08 }, +/* 0x9b09 */ { false, 0x9b09, 0x9b09 }, +/* 0x9b0a */ { false, 0x9b0a, 0x9b0a }, +/* 0x9b0b */ { false, 0x9b0b, 0x9b0b }, +/* 0x9b0c */ { false, 0x9b0c, 0x9b0c }, +/* 0x9b0d */ { false, 0x9b0d, 0x9b0d }, +/* 0x9b0e */ { false, 0x9b0e, 0x9b0e }, +/* 0x9b0f */ { false, 0x9b0f, 0x9b0f }, +/* 0x9b10 */ { false, 0x9b10, 0x9b10 }, +/* 0x9b11 */ { false, 0x9b11, 0x9b11 }, +/* 0x9b12 */ { false, 0x9b12, 0x9b12 }, +/* 0x9b13 */ { false, 0x9b13, 0x9b13 }, +/* 0x9b14 */ { false, 0x9b14, 0x9b14 }, +/* 0x9b15 */ { false, 0x9b15, 0x9b15 }, +/* 0x9b16 */ { false, 0x9b16, 0x9b16 }, +/* 0x9b17 */ { false, 0x9b17, 0x9b17 }, +/* 0x9b18 */ { false, 0x9b18, 0x9b18 }, +/* 0x9b19 */ { false, 0x9b19, 0x9b19 }, +/* 0x9b1a */ { false, 0x9b1a, 0x9b1a }, +/* 0x9b1b */ { false, 0x9b1b, 0x9b1b }, +/* 0x9b1c */ { false, 0x9b1c, 0x9b1c }, +/* 0x9b1d */ { false, 0x9b1d, 0x9b1d }, +/* 0x9b1e */ { false, 0x9b1e, 0x9b1e }, +/* 0x9b1f */ { false, 0x9b1f, 0x9b1f }, +/* 0x9b20 */ { false, 0x9b20, 0x9b20 }, +/* 0x9b21 */ { false, 0x9b21, 0x9b21 }, +/* 0x9b22 */ { false, 0x9b22, 0x9b22 }, +/* 0x9b23 */ { false, 0x9b23, 0x9b23 }, +/* 0x9b24 */ { false, 0x9b24, 0x9b24 }, +/* 0x9b25 */ { false, 0x9b25, 0x9b25 }, +/* 0x9b26 */ { false, 0x9b26, 0x9b26 }, +/* 0x9b27 */ { false, 0x9b27, 0x9b27 }, +/* 0x9b28 */ { false, 0x9b28, 0x9b28 }, +/* 0x9b29 */ { false, 0x9b29, 0x9b29 }, +/* 0x9b2a */ { false, 0x9b2a, 0x9b2a }, +/* 0x9b2b */ { false, 0x9b2b, 0x9b2b }, +/* 0x9b2c */ { false, 0x9b2c, 0x9b2c }, +/* 0x9b2d */ { false, 0x9b2d, 0x9b2d }, +/* 0x9b2e */ { false, 0x9b2e, 0x9b2e }, +/* 0x9b2f */ { false, 0x9b2f, 0x9b2f }, +/* 0x9b30 */ { false, 0x9b30, 0x9b30 }, +/* 0x9b31 */ { false, 0x9b31, 0x9b31 }, +/* 0x9b32 */ { false, 0x9b32, 0x9b32 }, +/* 0x9b33 */ { false, 0x9b33, 0x9b33 }, +/* 0x9b34 */ { false, 0x9b34, 0x9b34 }, +/* 0x9b35 */ { false, 0x9b35, 0x9b35 }, +/* 0x9b36 */ { false, 0x9b36, 0x9b36 }, +/* 0x9b37 */ { false, 0x9b37, 0x9b37 }, +/* 0x9b38 */ { false, 0x9b38, 0x9b38 }, +/* 0x9b39 */ { false, 0x9b39, 0x9b39 }, +/* 0x9b3a */ { false, 0x9b3a, 0x9b3a }, +/* 0x9b3b */ { false, 0x9b3b, 0x9b3b }, +/* 0x9b3c */ { false, 0x9b3c, 0x9b3c }, +/* 0x9b3d */ { false, 0x9b3d, 0x9b3d }, +/* 0x9b3e */ { false, 0x9b3e, 0x9b3e }, +/* 0x9b3f */ { false, 0x9b3f, 0x9b3f }, +/* 0x9b40 */ { false, 0x9b40, 0x9b40 }, +/* 0x9b41 */ { false, 0x9b41, 0x9b41 }, +/* 0x9b42 */ { false, 0x9b42, 0x9b42 }, +/* 0x9b43 */ { false, 0x9b43, 0x9b43 }, +/* 0x9b44 */ { false, 0x9b44, 0x9b44 }, +/* 0x9b45 */ { false, 0x9b45, 0x9b45 }, +/* 0x9b46 */ { false, 0x9b46, 0x9b46 }, +/* 0x9b47 */ { false, 0x9b47, 0x9b47 }, +/* 0x9b48 */ { false, 0x9b48, 0x9b48 }, +/* 0x9b49 */ { false, 0x9b49, 0x9b49 }, +/* 0x9b4a */ { false, 0x9b4a, 0x9b4a }, +/* 0x9b4b */ { false, 0x9b4b, 0x9b4b }, +/* 0x9b4c */ { false, 0x9b4c, 0x9b4c }, +/* 0x9b4d */ { false, 0x9b4d, 0x9b4d }, +/* 0x9b4e */ { false, 0x9b4e, 0x9b4e }, +/* 0x9b4f */ { false, 0x9b4f, 0x9b4f }, +/* 0x9b50 */ { false, 0x9b50, 0x9b50 }, +/* 0x9b51 */ { false, 0x9b51, 0x9b51 }, +/* 0x9b52 */ { false, 0x9b52, 0x9b52 }, +/* 0x9b53 */ { false, 0x9b53, 0x9b53 }, +/* 0x9b54 */ { false, 0x9b54, 0x9b54 }, +/* 0x9b55 */ { false, 0x9b55, 0x9b55 }, +/* 0x9b56 */ { false, 0x9b56, 0x9b56 }, +/* 0x9b57 */ { false, 0x9b57, 0x9b57 }, +/* 0x9b58 */ { false, 0x9b58, 0x9b58 }, +/* 0x9b59 */ { false, 0x9b59, 0x9b59 }, +/* 0x9b5a */ { false, 0x9b5a, 0x9b5a }, +/* 0x9b5b */ { false, 0x9b5b, 0x9b5b }, +/* 0x9b5c */ { false, 0x9b5c, 0x9b5c }, +/* 0x9b5d */ { false, 0x9b5d, 0x9b5d }, +/* 0x9b5e */ { false, 0x9b5e, 0x9b5e }, +/* 0x9b5f */ { false, 0x9b5f, 0x9b5f }, +/* 0x9b60 */ { false, 0x9b60, 0x9b60 }, +/* 0x9b61 */ { false, 0x9b61, 0x9b61 }, +/* 0x9b62 */ { false, 0x9b62, 0x9b62 }, +/* 0x9b63 */ { false, 0x9b63, 0x9b63 }, +/* 0x9b64 */ { false, 0x9b64, 0x9b64 }, +/* 0x9b65 */ { false, 0x9b65, 0x9b65 }, +/* 0x9b66 */ { false, 0x9b66, 0x9b66 }, +/* 0x9b67 */ { false, 0x9b67, 0x9b67 }, +/* 0x9b68 */ { false, 0x9b68, 0x9b68 }, +/* 0x9b69 */ { false, 0x9b69, 0x9b69 }, +/* 0x9b6a */ { false, 0x9b6a, 0x9b6a }, +/* 0x9b6b */ { false, 0x9b6b, 0x9b6b }, +/* 0x9b6c */ { false, 0x9b6c, 0x9b6c }, +/* 0x9b6d */ { false, 0x9b6d, 0x9b6d }, +/* 0x9b6e */ { false, 0x9b6e, 0x9b6e }, +/* 0x9b6f */ { false, 0x9b6f, 0x9b6f }, +/* 0x9b70 */ { false, 0x9b70, 0x9b70 }, +/* 0x9b71 */ { false, 0x9b71, 0x9b71 }, +/* 0x9b72 */ { false, 0x9b72, 0x9b72 }, +/* 0x9b73 */ { false, 0x9b73, 0x9b73 }, +/* 0x9b74 */ { false, 0x9b74, 0x9b74 }, +/* 0x9b75 */ { false, 0x9b75, 0x9b75 }, +/* 0x9b76 */ { false, 0x9b76, 0x9b76 }, +/* 0x9b77 */ { false, 0x9b77, 0x9b77 }, +/* 0x9b78 */ { false, 0x9b78, 0x9b78 }, +/* 0x9b79 */ { false, 0x9b79, 0x9b79 }, +/* 0x9b7a */ { false, 0x9b7a, 0x9b7a }, +/* 0x9b7b */ { false, 0x9b7b, 0x9b7b }, +/* 0x9b7c */ { false, 0x9b7c, 0x9b7c }, +/* 0x9b7d */ { false, 0x9b7d, 0x9b7d }, +/* 0x9b7e */ { false, 0x9b7e, 0x9b7e }, +/* 0x9b7f */ { false, 0x9b7f, 0x9b7f }, +/* 0x9b80 */ { false, 0x9b80, 0x9b80 }, +/* 0x9b81 */ { false, 0x9b81, 0x9b81 }, +/* 0x9b82 */ { false, 0x9b82, 0x9b82 }, +/* 0x9b83 */ { false, 0x9b83, 0x9b83 }, +/* 0x9b84 */ { false, 0x9b84, 0x9b84 }, +/* 0x9b85 */ { false, 0x9b85, 0x9b85 }, +/* 0x9b86 */ { false, 0x9b86, 0x9b86 }, +/* 0x9b87 */ { false, 0x9b87, 0x9b87 }, +/* 0x9b88 */ { false, 0x9b88, 0x9b88 }, +/* 0x9b89 */ { false, 0x9b89, 0x9b89 }, +/* 0x9b8a */ { false, 0x9b8a, 0x9b8a }, +/* 0x9b8b */ { false, 0x9b8b, 0x9b8b }, +/* 0x9b8c */ { false, 0x9b8c, 0x9b8c }, +/* 0x9b8d */ { false, 0x9b8d, 0x9b8d }, +/* 0x9b8e */ { false, 0x9b8e, 0x9b8e }, +/* 0x9b8f */ { false, 0x9b8f, 0x9b8f }, +/* 0x9b90 */ { false, 0x9b90, 0x9b90 }, +/* 0x9b91 */ { false, 0x9b91, 0x9b91 }, +/* 0x9b92 */ { false, 0x9b92, 0x9b92 }, +/* 0x9b93 */ { false, 0x9b93, 0x9b93 }, +/* 0x9b94 */ { false, 0x9b94, 0x9b94 }, +/* 0x9b95 */ { false, 0x9b95, 0x9b95 }, +/* 0x9b96 */ { false, 0x9b96, 0x9b96 }, +/* 0x9b97 */ { false, 0x9b97, 0x9b97 }, +/* 0x9b98 */ { false, 0x9b98, 0x9b98 }, +/* 0x9b99 */ { false, 0x9b99, 0x9b99 }, +/* 0x9b9a */ { false, 0x9b9a, 0x9b9a }, +/* 0x9b9b */ { false, 0x9b9b, 0x9b9b }, +/* 0x9b9c */ { false, 0x9b9c, 0x9b9c }, +/* 0x9b9d */ { false, 0x9b9d, 0x9b9d }, +/* 0x9b9e */ { false, 0x9b9e, 0x9b9e }, +/* 0x9b9f */ { false, 0x9b9f, 0x9b9f }, +/* 0x9ba0 */ { false, 0x9ba0, 0x9ba0 }, +/* 0x9ba1 */ { false, 0x9ba1, 0x9ba1 }, +/* 0x9ba2 */ { false, 0x9ba2, 0x9ba2 }, +/* 0x9ba3 */ { false, 0x9ba3, 0x9ba3 }, +/* 0x9ba4 */ { false, 0x9ba4, 0x9ba4 }, +/* 0x9ba5 */ { false, 0x9ba5, 0x9ba5 }, +/* 0x9ba6 */ { false, 0x9ba6, 0x9ba6 }, +/* 0x9ba7 */ { false, 0x9ba7, 0x9ba7 }, +/* 0x9ba8 */ { false, 0x9ba8, 0x9ba8 }, +/* 0x9ba9 */ { false, 0x9ba9, 0x9ba9 }, +/* 0x9baa */ { false, 0x9baa, 0x9baa }, +/* 0x9bab */ { false, 0x9bab, 0x9bab }, +/* 0x9bac */ { false, 0x9bac, 0x9bac }, +/* 0x9bad */ { false, 0x9bad, 0x9bad }, +/* 0x9bae */ { false, 0x9bae, 0x9bae }, +/* 0x9baf */ { false, 0x9baf, 0x9baf }, +/* 0x9bb0 */ { false, 0x9bb0, 0x9bb0 }, +/* 0x9bb1 */ { false, 0x9bb1, 0x9bb1 }, +/* 0x9bb2 */ { false, 0x9bb2, 0x9bb2 }, +/* 0x9bb3 */ { false, 0x9bb3, 0x9bb3 }, +/* 0x9bb4 */ { false, 0x9bb4, 0x9bb4 }, +/* 0x9bb5 */ { false, 0x9bb5, 0x9bb5 }, +/* 0x9bb6 */ { false, 0x9bb6, 0x9bb6 }, +/* 0x9bb7 */ { false, 0x9bb7, 0x9bb7 }, +/* 0x9bb8 */ { false, 0x9bb8, 0x9bb8 }, +/* 0x9bb9 */ { false, 0x9bb9, 0x9bb9 }, +/* 0x9bba */ { false, 0x9bba, 0x9bba }, +/* 0x9bbb */ { false, 0x9bbb, 0x9bbb }, +/* 0x9bbc */ { false, 0x9bbc, 0x9bbc }, +/* 0x9bbd */ { false, 0x9bbd, 0x9bbd }, +/* 0x9bbe */ { false, 0x9bbe, 0x9bbe }, +/* 0x9bbf */ { false, 0x9bbf, 0x9bbf }, +/* 0x9bc0 */ { false, 0x9bc0, 0x9bc0 }, +/* 0x9bc1 */ { false, 0x9bc1, 0x9bc1 }, +/* 0x9bc2 */ { false, 0x9bc2, 0x9bc2 }, +/* 0x9bc3 */ { false, 0x9bc3, 0x9bc3 }, +/* 0x9bc4 */ { false, 0x9bc4, 0x9bc4 }, +/* 0x9bc5 */ { false, 0x9bc5, 0x9bc5 }, +/* 0x9bc6 */ { false, 0x9bc6, 0x9bc6 }, +/* 0x9bc7 */ { false, 0x9bc7, 0x9bc7 }, +/* 0x9bc8 */ { false, 0x9bc8, 0x9bc8 }, +/* 0x9bc9 */ { false, 0x9bc9, 0x9bc9 }, +/* 0x9bca */ { false, 0x9bca, 0x9bca }, +/* 0x9bcb */ { false, 0x9bcb, 0x9bcb }, +/* 0x9bcc */ { false, 0x9bcc, 0x9bcc }, +/* 0x9bcd */ { false, 0x9bcd, 0x9bcd }, +/* 0x9bce */ { false, 0x9bce, 0x9bce }, +/* 0x9bcf */ { false, 0x9bcf, 0x9bcf }, +/* 0x9bd0 */ { false, 0x9bd0, 0x9bd0 }, +/* 0x9bd1 */ { false, 0x9bd1, 0x9bd1 }, +/* 0x9bd2 */ { false, 0x9bd2, 0x9bd2 }, +/* 0x9bd3 */ { false, 0x9bd3, 0x9bd3 }, +/* 0x9bd4 */ { false, 0x9bd4, 0x9bd4 }, +/* 0x9bd5 */ { false, 0x9bd5, 0x9bd5 }, +/* 0x9bd6 */ { false, 0x9bd6, 0x9bd6 }, +/* 0x9bd7 */ { false, 0x9bd7, 0x9bd7 }, +/* 0x9bd8 */ { false, 0x9bd8, 0x9bd8 }, +/* 0x9bd9 */ { false, 0x9bd9, 0x9bd9 }, +/* 0x9bda */ { false, 0x9bda, 0x9bda }, +/* 0x9bdb */ { false, 0x9bdb, 0x9bdb }, +/* 0x9bdc */ { false, 0x9bdc, 0x9bdc }, +/* 0x9bdd */ { false, 0x9bdd, 0x9bdd }, +/* 0x9bde */ { false, 0x9bde, 0x9bde }, +/* 0x9bdf */ { false, 0x9bdf, 0x9bdf }, +/* 0x9be0 */ { false, 0x9be0, 0x9be0 }, +/* 0x9be1 */ { false, 0x9be1, 0x9be1 }, +/* 0x9be2 */ { false, 0x9be2, 0x9be2 }, +/* 0x9be3 */ { false, 0x9be3, 0x9be3 }, +/* 0x9be4 */ { false, 0x9be4, 0x9be4 }, +/* 0x9be5 */ { false, 0x9be5, 0x9be5 }, +/* 0x9be6 */ { false, 0x9be6, 0x9be6 }, +/* 0x9be7 */ { false, 0x9be7, 0x9be7 }, +/* 0x9be8 */ { false, 0x9be8, 0x9be8 }, +/* 0x9be9 */ { false, 0x9be9, 0x9be9 }, +/* 0x9bea */ { false, 0x9bea, 0x9bea }, +/* 0x9beb */ { false, 0x9beb, 0x9beb }, +/* 0x9bec */ { false, 0x9bec, 0x9bec }, +/* 0x9bed */ { false, 0x9bed, 0x9bed }, +/* 0x9bee */ { false, 0x9bee, 0x9bee }, +/* 0x9bef */ { false, 0x9bef, 0x9bef }, +/* 0x9bf0 */ { false, 0x9bf0, 0x9bf0 }, +/* 0x9bf1 */ { false, 0x9bf1, 0x9bf1 }, +/* 0x9bf2 */ { false, 0x9bf2, 0x9bf2 }, +/* 0x9bf3 */ { false, 0x9bf3, 0x9bf3 }, +/* 0x9bf4 */ { false, 0x9bf4, 0x9bf4 }, +/* 0x9bf5 */ { false, 0x9bf5, 0x9bf5 }, +/* 0x9bf6 */ { false, 0x9bf6, 0x9bf6 }, +/* 0x9bf7 */ { false, 0x9bf7, 0x9bf7 }, +/* 0x9bf8 */ { false, 0x9bf8, 0x9bf8 }, +/* 0x9bf9 */ { false, 0x9bf9, 0x9bf9 }, +/* 0x9bfa */ { false, 0x9bfa, 0x9bfa }, +/* 0x9bfb */ { false, 0x9bfb, 0x9bfb }, +/* 0x9bfc */ { false, 0x9bfc, 0x9bfc }, +/* 0x9bfd */ { false, 0x9bfd, 0x9bfd }, +/* 0x9bfe */ { false, 0x9bfe, 0x9bfe }, +/* 0x9bff */ { false, 0x9bff, 0x9bff }, +/* 0x9c00 */ { false, 0x9c00, 0x9c00 }, +/* 0x9c01 */ { false, 0x9c01, 0x9c01 }, +/* 0x9c02 */ { false, 0x9c02, 0x9c02 }, +/* 0x9c03 */ { false, 0x9c03, 0x9c03 }, +/* 0x9c04 */ { false, 0x9c04, 0x9c04 }, +/* 0x9c05 */ { false, 0x9c05, 0x9c05 }, +/* 0x9c06 */ { false, 0x9c06, 0x9c06 }, +/* 0x9c07 */ { false, 0x9c07, 0x9c07 }, +/* 0x9c08 */ { false, 0x9c08, 0x9c08 }, +/* 0x9c09 */ { false, 0x9c09, 0x9c09 }, +/* 0x9c0a */ { false, 0x9c0a, 0x9c0a }, +/* 0x9c0b */ { false, 0x9c0b, 0x9c0b }, +/* 0x9c0c */ { false, 0x9c0c, 0x9c0c }, +/* 0x9c0d */ { false, 0x9c0d, 0x9c0d }, +/* 0x9c0e */ { false, 0x9c0e, 0x9c0e }, +/* 0x9c0f */ { false, 0x9c0f, 0x9c0f }, +/* 0x9c10 */ { false, 0x9c10, 0x9c10 }, +/* 0x9c11 */ { false, 0x9c11, 0x9c11 }, +/* 0x9c12 */ { false, 0x9c12, 0x9c12 }, +/* 0x9c13 */ { false, 0x9c13, 0x9c13 }, +/* 0x9c14 */ { false, 0x9c14, 0x9c14 }, +/* 0x9c15 */ { false, 0x9c15, 0x9c15 }, +/* 0x9c16 */ { false, 0x9c16, 0x9c16 }, +/* 0x9c17 */ { false, 0x9c17, 0x9c17 }, +/* 0x9c18 */ { false, 0x9c18, 0x9c18 }, +/* 0x9c19 */ { false, 0x9c19, 0x9c19 }, +/* 0x9c1a */ { false, 0x9c1a, 0x9c1a }, +/* 0x9c1b */ { false, 0x9c1b, 0x9c1b }, +/* 0x9c1c */ { false, 0x9c1c, 0x9c1c }, +/* 0x9c1d */ { false, 0x9c1d, 0x9c1d }, +/* 0x9c1e */ { false, 0x9c1e, 0x9c1e }, +/* 0x9c1f */ { false, 0x9c1f, 0x9c1f }, +/* 0x9c20 */ { false, 0x9c20, 0x9c20 }, +/* 0x9c21 */ { false, 0x9c21, 0x9c21 }, +/* 0x9c22 */ { false, 0x9c22, 0x9c22 }, +/* 0x9c23 */ { false, 0x9c23, 0x9c23 }, +/* 0x9c24 */ { false, 0x9c24, 0x9c24 }, +/* 0x9c25 */ { false, 0x9c25, 0x9c25 }, +/* 0x9c26 */ { false, 0x9c26, 0x9c26 }, +/* 0x9c27 */ { false, 0x9c27, 0x9c27 }, +/* 0x9c28 */ { false, 0x9c28, 0x9c28 }, +/* 0x9c29 */ { false, 0x9c29, 0x9c29 }, +/* 0x9c2a */ { false, 0x9c2a, 0x9c2a }, +/* 0x9c2b */ { false, 0x9c2b, 0x9c2b }, +/* 0x9c2c */ { false, 0x9c2c, 0x9c2c }, +/* 0x9c2d */ { false, 0x9c2d, 0x9c2d }, +/* 0x9c2e */ { false, 0x9c2e, 0x9c2e }, +/* 0x9c2f */ { false, 0x9c2f, 0x9c2f }, +/* 0x9c30 */ { false, 0x9c30, 0x9c30 }, +/* 0x9c31 */ { false, 0x9c31, 0x9c31 }, +/* 0x9c32 */ { false, 0x9c32, 0x9c32 }, +/* 0x9c33 */ { false, 0x9c33, 0x9c33 }, +/* 0x9c34 */ { false, 0x9c34, 0x9c34 }, +/* 0x9c35 */ { false, 0x9c35, 0x9c35 }, +/* 0x9c36 */ { false, 0x9c36, 0x9c36 }, +/* 0x9c37 */ { false, 0x9c37, 0x9c37 }, +/* 0x9c38 */ { false, 0x9c38, 0x9c38 }, +/* 0x9c39 */ { false, 0x9c39, 0x9c39 }, +/* 0x9c3a */ { false, 0x9c3a, 0x9c3a }, +/* 0x9c3b */ { false, 0x9c3b, 0x9c3b }, +/* 0x9c3c */ { false, 0x9c3c, 0x9c3c }, +/* 0x9c3d */ { false, 0x9c3d, 0x9c3d }, +/* 0x9c3e */ { false, 0x9c3e, 0x9c3e }, +/* 0x9c3f */ { false, 0x9c3f, 0x9c3f }, +/* 0x9c40 */ { false, 0x9c40, 0x9c40 }, +/* 0x9c41 */ { false, 0x9c41, 0x9c41 }, +/* 0x9c42 */ { false, 0x9c42, 0x9c42 }, +/* 0x9c43 */ { false, 0x9c43, 0x9c43 }, +/* 0x9c44 */ { false, 0x9c44, 0x9c44 }, +/* 0x9c45 */ { false, 0x9c45, 0x9c45 }, +/* 0x9c46 */ { false, 0x9c46, 0x9c46 }, +/* 0x9c47 */ { false, 0x9c47, 0x9c47 }, +/* 0x9c48 */ { false, 0x9c48, 0x9c48 }, +/* 0x9c49 */ { false, 0x9c49, 0x9c49 }, +/* 0x9c4a */ { false, 0x9c4a, 0x9c4a }, +/* 0x9c4b */ { false, 0x9c4b, 0x9c4b }, +/* 0x9c4c */ { false, 0x9c4c, 0x9c4c }, +/* 0x9c4d */ { false, 0x9c4d, 0x9c4d }, +/* 0x9c4e */ { false, 0x9c4e, 0x9c4e }, +/* 0x9c4f */ { false, 0x9c4f, 0x9c4f }, +/* 0x9c50 */ { false, 0x9c50, 0x9c50 }, +/* 0x9c51 */ { false, 0x9c51, 0x9c51 }, +/* 0x9c52 */ { false, 0x9c52, 0x9c52 }, +/* 0x9c53 */ { false, 0x9c53, 0x9c53 }, +/* 0x9c54 */ { false, 0x9c54, 0x9c54 }, +/* 0x9c55 */ { false, 0x9c55, 0x9c55 }, +/* 0x9c56 */ { false, 0x9c56, 0x9c56 }, +/* 0x9c57 */ { false, 0x9c57, 0x9c57 }, +/* 0x9c58 */ { false, 0x9c58, 0x9c58 }, +/* 0x9c59 */ { false, 0x9c59, 0x9c59 }, +/* 0x9c5a */ { false, 0x9c5a, 0x9c5a }, +/* 0x9c5b */ { false, 0x9c5b, 0x9c5b }, +/* 0x9c5c */ { false, 0x9c5c, 0x9c5c }, +/* 0x9c5d */ { false, 0x9c5d, 0x9c5d }, +/* 0x9c5e */ { false, 0x9c5e, 0x9c5e }, +/* 0x9c5f */ { false, 0x9c5f, 0x9c5f }, +/* 0x9c60 */ { false, 0x9c60, 0x9c60 }, +/* 0x9c61 */ { false, 0x9c61, 0x9c61 }, +/* 0x9c62 */ { false, 0x9c62, 0x9c62 }, +/* 0x9c63 */ { false, 0x9c63, 0x9c63 }, +/* 0x9c64 */ { false, 0x9c64, 0x9c64 }, +/* 0x9c65 */ { false, 0x9c65, 0x9c65 }, +/* 0x9c66 */ { false, 0x9c66, 0x9c66 }, +/* 0x9c67 */ { false, 0x9c67, 0x9c67 }, +/* 0x9c68 */ { false, 0x9c68, 0x9c68 }, +/* 0x9c69 */ { false, 0x9c69, 0x9c69 }, +/* 0x9c6a */ { false, 0x9c6a, 0x9c6a }, +/* 0x9c6b */ { false, 0x9c6b, 0x9c6b }, +/* 0x9c6c */ { false, 0x9c6c, 0x9c6c }, +/* 0x9c6d */ { false, 0x9c6d, 0x9c6d }, +/* 0x9c6e */ { false, 0x9c6e, 0x9c6e }, +/* 0x9c6f */ { false, 0x9c6f, 0x9c6f }, +/* 0x9c70 */ { false, 0x9c70, 0x9c70 }, +/* 0x9c71 */ { false, 0x9c71, 0x9c71 }, +/* 0x9c72 */ { false, 0x9c72, 0x9c72 }, +/* 0x9c73 */ { false, 0x9c73, 0x9c73 }, +/* 0x9c74 */ { false, 0x9c74, 0x9c74 }, +/* 0x9c75 */ { false, 0x9c75, 0x9c75 }, +/* 0x9c76 */ { false, 0x9c76, 0x9c76 }, +/* 0x9c77 */ { false, 0x9c77, 0x9c77 }, +/* 0x9c78 */ { false, 0x9c78, 0x9c78 }, +/* 0x9c79 */ { false, 0x9c79, 0x9c79 }, +/* 0x9c7a */ { false, 0x9c7a, 0x9c7a }, +/* 0x9c7b */ { false, 0x9c7b, 0x9c7b }, +/* 0x9c7c */ { false, 0x9c7c, 0x9c7c }, +/* 0x9c7d */ { false, 0x9c7d, 0x9c7d }, +/* 0x9c7e */ { false, 0x9c7e, 0x9c7e }, +/* 0x9c7f */ { false, 0x9c7f, 0x9c7f }, +/* 0x9c80 */ { false, 0x9c80, 0x9c80 }, +/* 0x9c81 */ { false, 0x9c81, 0x9c81 }, +/* 0x9c82 */ { false, 0x9c82, 0x9c82 }, +/* 0x9c83 */ { false, 0x9c83, 0x9c83 }, +/* 0x9c84 */ { false, 0x9c84, 0x9c84 }, +/* 0x9c85 */ { false, 0x9c85, 0x9c85 }, +/* 0x9c86 */ { false, 0x9c86, 0x9c86 }, +/* 0x9c87 */ { false, 0x9c87, 0x9c87 }, +/* 0x9c88 */ { false, 0x9c88, 0x9c88 }, +/* 0x9c89 */ { false, 0x9c89, 0x9c89 }, +/* 0x9c8a */ { false, 0x9c8a, 0x9c8a }, +/* 0x9c8b */ { false, 0x9c8b, 0x9c8b }, +/* 0x9c8c */ { false, 0x9c8c, 0x9c8c }, +/* 0x9c8d */ { false, 0x9c8d, 0x9c8d }, +/* 0x9c8e */ { false, 0x9c8e, 0x9c8e }, +/* 0x9c8f */ { false, 0x9c8f, 0x9c8f }, +/* 0x9c90 */ { false, 0x9c90, 0x9c90 }, +/* 0x9c91 */ { false, 0x9c91, 0x9c91 }, +/* 0x9c92 */ { false, 0x9c92, 0x9c92 }, +/* 0x9c93 */ { false, 0x9c93, 0x9c93 }, +/* 0x9c94 */ { false, 0x9c94, 0x9c94 }, +/* 0x9c95 */ { false, 0x9c95, 0x9c95 }, +/* 0x9c96 */ { false, 0x9c96, 0x9c96 }, +/* 0x9c97 */ { false, 0x9c97, 0x9c97 }, +/* 0x9c98 */ { false, 0x9c98, 0x9c98 }, +/* 0x9c99 */ { false, 0x9c99, 0x9c99 }, +/* 0x9c9a */ { false, 0x9c9a, 0x9c9a }, +/* 0x9c9b */ { false, 0x9c9b, 0x9c9b }, +/* 0x9c9c */ { false, 0x9c9c, 0x9c9c }, +/* 0x9c9d */ { false, 0x9c9d, 0x9c9d }, +/* 0x9c9e */ { false, 0x9c9e, 0x9c9e }, +/* 0x9c9f */ { false, 0x9c9f, 0x9c9f }, +/* 0x9ca0 */ { false, 0x9ca0, 0x9ca0 }, +/* 0x9ca1 */ { false, 0x9ca1, 0x9ca1 }, +/* 0x9ca2 */ { false, 0x9ca2, 0x9ca2 }, +/* 0x9ca3 */ { false, 0x9ca3, 0x9ca3 }, +/* 0x9ca4 */ { false, 0x9ca4, 0x9ca4 }, +/* 0x9ca5 */ { false, 0x9ca5, 0x9ca5 }, +/* 0x9ca6 */ { false, 0x9ca6, 0x9ca6 }, +/* 0x9ca7 */ { false, 0x9ca7, 0x9ca7 }, +/* 0x9ca8 */ { false, 0x9ca8, 0x9ca8 }, +/* 0x9ca9 */ { false, 0x9ca9, 0x9ca9 }, +/* 0x9caa */ { false, 0x9caa, 0x9caa }, +/* 0x9cab */ { false, 0x9cab, 0x9cab }, +/* 0x9cac */ { false, 0x9cac, 0x9cac }, +/* 0x9cad */ { false, 0x9cad, 0x9cad }, +/* 0x9cae */ { false, 0x9cae, 0x9cae }, +/* 0x9caf */ { false, 0x9caf, 0x9caf }, +/* 0x9cb0 */ { false, 0x9cb0, 0x9cb0 }, +/* 0x9cb1 */ { false, 0x9cb1, 0x9cb1 }, +/* 0x9cb2 */ { false, 0x9cb2, 0x9cb2 }, +/* 0x9cb3 */ { false, 0x9cb3, 0x9cb3 }, +/* 0x9cb4 */ { false, 0x9cb4, 0x9cb4 }, +/* 0x9cb5 */ { false, 0x9cb5, 0x9cb5 }, +/* 0x9cb6 */ { false, 0x9cb6, 0x9cb6 }, +/* 0x9cb7 */ { false, 0x9cb7, 0x9cb7 }, +/* 0x9cb8 */ { false, 0x9cb8, 0x9cb8 }, +/* 0x9cb9 */ { false, 0x9cb9, 0x9cb9 }, +/* 0x9cba */ { false, 0x9cba, 0x9cba }, +/* 0x9cbb */ { false, 0x9cbb, 0x9cbb }, +/* 0x9cbc */ { false, 0x9cbc, 0x9cbc }, +/* 0x9cbd */ { false, 0x9cbd, 0x9cbd }, +/* 0x9cbe */ { false, 0x9cbe, 0x9cbe }, +/* 0x9cbf */ { false, 0x9cbf, 0x9cbf }, +/* 0x9cc0 */ { false, 0x9cc0, 0x9cc0 }, +/* 0x9cc1 */ { false, 0x9cc1, 0x9cc1 }, +/* 0x9cc2 */ { false, 0x9cc2, 0x9cc2 }, +/* 0x9cc3 */ { false, 0x9cc3, 0x9cc3 }, +/* 0x9cc4 */ { false, 0x9cc4, 0x9cc4 }, +/* 0x9cc5 */ { false, 0x9cc5, 0x9cc5 }, +/* 0x9cc6 */ { false, 0x9cc6, 0x9cc6 }, +/* 0x9cc7 */ { false, 0x9cc7, 0x9cc7 }, +/* 0x9cc8 */ { false, 0x9cc8, 0x9cc8 }, +/* 0x9cc9 */ { false, 0x9cc9, 0x9cc9 }, +/* 0x9cca */ { false, 0x9cca, 0x9cca }, +/* 0x9ccb */ { false, 0x9ccb, 0x9ccb }, +/* 0x9ccc */ { false, 0x9ccc, 0x9ccc }, +/* 0x9ccd */ { false, 0x9ccd, 0x9ccd }, +/* 0x9cce */ { false, 0x9cce, 0x9cce }, +/* 0x9ccf */ { false, 0x9ccf, 0x9ccf }, +/* 0x9cd0 */ { false, 0x9cd0, 0x9cd0 }, +/* 0x9cd1 */ { false, 0x9cd1, 0x9cd1 }, +/* 0x9cd2 */ { false, 0x9cd2, 0x9cd2 }, +/* 0x9cd3 */ { false, 0x9cd3, 0x9cd3 }, +/* 0x9cd4 */ { false, 0x9cd4, 0x9cd4 }, +/* 0x9cd5 */ { false, 0x9cd5, 0x9cd5 }, +/* 0x9cd6 */ { false, 0x9cd6, 0x9cd6 }, +/* 0x9cd7 */ { false, 0x9cd7, 0x9cd7 }, +/* 0x9cd8 */ { false, 0x9cd8, 0x9cd8 }, +/* 0x9cd9 */ { false, 0x9cd9, 0x9cd9 }, +/* 0x9cda */ { false, 0x9cda, 0x9cda }, +/* 0x9cdb */ { false, 0x9cdb, 0x9cdb }, +/* 0x9cdc */ { false, 0x9cdc, 0x9cdc }, +/* 0x9cdd */ { false, 0x9cdd, 0x9cdd }, +/* 0x9cde */ { false, 0x9cde, 0x9cde }, +/* 0x9cdf */ { false, 0x9cdf, 0x9cdf }, +/* 0x9ce0 */ { false, 0x9ce0, 0x9ce0 }, +/* 0x9ce1 */ { false, 0x9ce1, 0x9ce1 }, +/* 0x9ce2 */ { false, 0x9ce2, 0x9ce2 }, +/* 0x9ce3 */ { false, 0x9ce3, 0x9ce3 }, +/* 0x9ce4 */ { false, 0x9ce4, 0x9ce4 }, +/* 0x9ce5 */ { false, 0x9ce5, 0x9ce5 }, +/* 0x9ce6 */ { false, 0x9ce6, 0x9ce6 }, +/* 0x9ce7 */ { false, 0x9ce7, 0x9ce7 }, +/* 0x9ce8 */ { false, 0x9ce8, 0x9ce8 }, +/* 0x9ce9 */ { false, 0x9ce9, 0x9ce9 }, +/* 0x9cea */ { false, 0x9cea, 0x9cea }, +/* 0x9ceb */ { false, 0x9ceb, 0x9ceb }, +/* 0x9cec */ { false, 0x9cec, 0x9cec }, +/* 0x9ced */ { false, 0x9ced, 0x9ced }, +/* 0x9cee */ { false, 0x9cee, 0x9cee }, +/* 0x9cef */ { false, 0x9cef, 0x9cef }, +/* 0x9cf0 */ { false, 0x9cf0, 0x9cf0 }, +/* 0x9cf1 */ { false, 0x9cf1, 0x9cf1 }, +/* 0x9cf2 */ { false, 0x9cf2, 0x9cf2 }, +/* 0x9cf3 */ { false, 0x9cf3, 0x9cf3 }, +/* 0x9cf4 */ { false, 0x9cf4, 0x9cf4 }, +/* 0x9cf5 */ { false, 0x9cf5, 0x9cf5 }, +/* 0x9cf6 */ { false, 0x9cf6, 0x9cf6 }, +/* 0x9cf7 */ { false, 0x9cf7, 0x9cf7 }, +/* 0x9cf8 */ { false, 0x9cf8, 0x9cf8 }, +/* 0x9cf9 */ { false, 0x9cf9, 0x9cf9 }, +/* 0x9cfa */ { false, 0x9cfa, 0x9cfa }, +/* 0x9cfb */ { false, 0x9cfb, 0x9cfb }, +/* 0x9cfc */ { false, 0x9cfc, 0x9cfc }, +/* 0x9cfd */ { false, 0x9cfd, 0x9cfd }, +/* 0x9cfe */ { false, 0x9cfe, 0x9cfe }, +/* 0x9cff */ { false, 0x9cff, 0x9cff }, +/* 0x9d00 */ { false, 0x9d00, 0x9d00 }, +/* 0x9d01 */ { false, 0x9d01, 0x9d01 }, +/* 0x9d02 */ { false, 0x9d02, 0x9d02 }, +/* 0x9d03 */ { false, 0x9d03, 0x9d03 }, +/* 0x9d04 */ { false, 0x9d04, 0x9d04 }, +/* 0x9d05 */ { false, 0x9d05, 0x9d05 }, +/* 0x9d06 */ { false, 0x9d06, 0x9d06 }, +/* 0x9d07 */ { false, 0x9d07, 0x9d07 }, +/* 0x9d08 */ { false, 0x9d08, 0x9d08 }, +/* 0x9d09 */ { false, 0x9d09, 0x9d09 }, +/* 0x9d0a */ { false, 0x9d0a, 0x9d0a }, +/* 0x9d0b */ { false, 0x9d0b, 0x9d0b }, +/* 0x9d0c */ { false, 0x9d0c, 0x9d0c }, +/* 0x9d0d */ { false, 0x9d0d, 0x9d0d }, +/* 0x9d0e */ { false, 0x9d0e, 0x9d0e }, +/* 0x9d0f */ { false, 0x9d0f, 0x9d0f }, +/* 0x9d10 */ { false, 0x9d10, 0x9d10 }, +/* 0x9d11 */ { false, 0x9d11, 0x9d11 }, +/* 0x9d12 */ { false, 0x9d12, 0x9d12 }, +/* 0x9d13 */ { false, 0x9d13, 0x9d13 }, +/* 0x9d14 */ { false, 0x9d14, 0x9d14 }, +/* 0x9d15 */ { false, 0x9d15, 0x9d15 }, +/* 0x9d16 */ { false, 0x9d16, 0x9d16 }, +/* 0x9d17 */ { false, 0x9d17, 0x9d17 }, +/* 0x9d18 */ { false, 0x9d18, 0x9d18 }, +/* 0x9d19 */ { false, 0x9d19, 0x9d19 }, +/* 0x9d1a */ { false, 0x9d1a, 0x9d1a }, +/* 0x9d1b */ { false, 0x9d1b, 0x9d1b }, +/* 0x9d1c */ { false, 0x9d1c, 0x9d1c }, +/* 0x9d1d */ { false, 0x9d1d, 0x9d1d }, +/* 0x9d1e */ { false, 0x9d1e, 0x9d1e }, +/* 0x9d1f */ { false, 0x9d1f, 0x9d1f }, +/* 0x9d20 */ { false, 0x9d20, 0x9d20 }, +/* 0x9d21 */ { false, 0x9d21, 0x9d21 }, +/* 0x9d22 */ { false, 0x9d22, 0x9d22 }, +/* 0x9d23 */ { false, 0x9d23, 0x9d23 }, +/* 0x9d24 */ { false, 0x9d24, 0x9d24 }, +/* 0x9d25 */ { false, 0x9d25, 0x9d25 }, +/* 0x9d26 */ { false, 0x9d26, 0x9d26 }, +/* 0x9d27 */ { false, 0x9d27, 0x9d27 }, +/* 0x9d28 */ { false, 0x9d28, 0x9d28 }, +/* 0x9d29 */ { false, 0x9d29, 0x9d29 }, +/* 0x9d2a */ { false, 0x9d2a, 0x9d2a }, +/* 0x9d2b */ { false, 0x9d2b, 0x9d2b }, +/* 0x9d2c */ { false, 0x9d2c, 0x9d2c }, +/* 0x9d2d */ { false, 0x9d2d, 0x9d2d }, +/* 0x9d2e */ { false, 0x9d2e, 0x9d2e }, +/* 0x9d2f */ { false, 0x9d2f, 0x9d2f }, +/* 0x9d30 */ { false, 0x9d30, 0x9d30 }, +/* 0x9d31 */ { false, 0x9d31, 0x9d31 }, +/* 0x9d32 */ { false, 0x9d32, 0x9d32 }, +/* 0x9d33 */ { false, 0x9d33, 0x9d33 }, +/* 0x9d34 */ { false, 0x9d34, 0x9d34 }, +/* 0x9d35 */ { false, 0x9d35, 0x9d35 }, +/* 0x9d36 */ { false, 0x9d36, 0x9d36 }, +/* 0x9d37 */ { false, 0x9d37, 0x9d37 }, +/* 0x9d38 */ { false, 0x9d38, 0x9d38 }, +/* 0x9d39 */ { false, 0x9d39, 0x9d39 }, +/* 0x9d3a */ { false, 0x9d3a, 0x9d3a }, +/* 0x9d3b */ { false, 0x9d3b, 0x9d3b }, +/* 0x9d3c */ { false, 0x9d3c, 0x9d3c }, +/* 0x9d3d */ { false, 0x9d3d, 0x9d3d }, +/* 0x9d3e */ { false, 0x9d3e, 0x9d3e }, +/* 0x9d3f */ { false, 0x9d3f, 0x9d3f }, +/* 0x9d40 */ { false, 0x9d40, 0x9d40 }, +/* 0x9d41 */ { false, 0x9d41, 0x9d41 }, +/* 0x9d42 */ { false, 0x9d42, 0x9d42 }, +/* 0x9d43 */ { false, 0x9d43, 0x9d43 }, +/* 0x9d44 */ { false, 0x9d44, 0x9d44 }, +/* 0x9d45 */ { false, 0x9d45, 0x9d45 }, +/* 0x9d46 */ { false, 0x9d46, 0x9d46 }, +/* 0x9d47 */ { false, 0x9d47, 0x9d47 }, +/* 0x9d48 */ { false, 0x9d48, 0x9d48 }, +/* 0x9d49 */ { false, 0x9d49, 0x9d49 }, +/* 0x9d4a */ { false, 0x9d4a, 0x9d4a }, +/* 0x9d4b */ { false, 0x9d4b, 0x9d4b }, +/* 0x9d4c */ { false, 0x9d4c, 0x9d4c }, +/* 0x9d4d */ { false, 0x9d4d, 0x9d4d }, +/* 0x9d4e */ { false, 0x9d4e, 0x9d4e }, +/* 0x9d4f */ { false, 0x9d4f, 0x9d4f }, +/* 0x9d50 */ { false, 0x9d50, 0x9d50 }, +/* 0x9d51 */ { false, 0x9d51, 0x9d51 }, +/* 0x9d52 */ { false, 0x9d52, 0x9d52 }, +/* 0x9d53 */ { false, 0x9d53, 0x9d53 }, +/* 0x9d54 */ { false, 0x9d54, 0x9d54 }, +/* 0x9d55 */ { false, 0x9d55, 0x9d55 }, +/* 0x9d56 */ { false, 0x9d56, 0x9d56 }, +/* 0x9d57 */ { false, 0x9d57, 0x9d57 }, +/* 0x9d58 */ { false, 0x9d58, 0x9d58 }, +/* 0x9d59 */ { false, 0x9d59, 0x9d59 }, +/* 0x9d5a */ { false, 0x9d5a, 0x9d5a }, +/* 0x9d5b */ { false, 0x9d5b, 0x9d5b }, +/* 0x9d5c */ { false, 0x9d5c, 0x9d5c }, +/* 0x9d5d */ { false, 0x9d5d, 0x9d5d }, +/* 0x9d5e */ { false, 0x9d5e, 0x9d5e }, +/* 0x9d5f */ { false, 0x9d5f, 0x9d5f }, +/* 0x9d60 */ { false, 0x9d60, 0x9d60 }, +/* 0x9d61 */ { false, 0x9d61, 0x9d61 }, +/* 0x9d62 */ { false, 0x9d62, 0x9d62 }, +/* 0x9d63 */ { false, 0x9d63, 0x9d63 }, +/* 0x9d64 */ { false, 0x9d64, 0x9d64 }, +/* 0x9d65 */ { false, 0x9d65, 0x9d65 }, +/* 0x9d66 */ { false, 0x9d66, 0x9d66 }, +/* 0x9d67 */ { false, 0x9d67, 0x9d67 }, +/* 0x9d68 */ { false, 0x9d68, 0x9d68 }, +/* 0x9d69 */ { false, 0x9d69, 0x9d69 }, +/* 0x9d6a */ { false, 0x9d6a, 0x9d6a }, +/* 0x9d6b */ { false, 0x9d6b, 0x9d6b }, +/* 0x9d6c */ { false, 0x9d6c, 0x9d6c }, +/* 0x9d6d */ { false, 0x9d6d, 0x9d6d }, +/* 0x9d6e */ { false, 0x9d6e, 0x9d6e }, +/* 0x9d6f */ { false, 0x9d6f, 0x9d6f }, +/* 0x9d70 */ { false, 0x9d70, 0x9d70 }, +/* 0x9d71 */ { false, 0x9d71, 0x9d71 }, +/* 0x9d72 */ { false, 0x9d72, 0x9d72 }, +/* 0x9d73 */ { false, 0x9d73, 0x9d73 }, +/* 0x9d74 */ { false, 0x9d74, 0x9d74 }, +/* 0x9d75 */ { false, 0x9d75, 0x9d75 }, +/* 0x9d76 */ { false, 0x9d76, 0x9d76 }, +/* 0x9d77 */ { false, 0x9d77, 0x9d77 }, +/* 0x9d78 */ { false, 0x9d78, 0x9d78 }, +/* 0x9d79 */ { false, 0x9d79, 0x9d79 }, +/* 0x9d7a */ { false, 0x9d7a, 0x9d7a }, +/* 0x9d7b */ { false, 0x9d7b, 0x9d7b }, +/* 0x9d7c */ { false, 0x9d7c, 0x9d7c }, +/* 0x9d7d */ { false, 0x9d7d, 0x9d7d }, +/* 0x9d7e */ { false, 0x9d7e, 0x9d7e }, +/* 0x9d7f */ { false, 0x9d7f, 0x9d7f }, +/* 0x9d80 */ { false, 0x9d80, 0x9d80 }, +/* 0x9d81 */ { false, 0x9d81, 0x9d81 }, +/* 0x9d82 */ { false, 0x9d82, 0x9d82 }, +/* 0x9d83 */ { false, 0x9d83, 0x9d83 }, +/* 0x9d84 */ { false, 0x9d84, 0x9d84 }, +/* 0x9d85 */ { false, 0x9d85, 0x9d85 }, +/* 0x9d86 */ { false, 0x9d86, 0x9d86 }, +/* 0x9d87 */ { false, 0x9d87, 0x9d87 }, +/* 0x9d88 */ { false, 0x9d88, 0x9d88 }, +/* 0x9d89 */ { false, 0x9d89, 0x9d89 }, +/* 0x9d8a */ { false, 0x9d8a, 0x9d8a }, +/* 0x9d8b */ { false, 0x9d8b, 0x9d8b }, +/* 0x9d8c */ { false, 0x9d8c, 0x9d8c }, +/* 0x9d8d */ { false, 0x9d8d, 0x9d8d }, +/* 0x9d8e */ { false, 0x9d8e, 0x9d8e }, +/* 0x9d8f */ { false, 0x9d8f, 0x9d8f }, +/* 0x9d90 */ { false, 0x9d90, 0x9d90 }, +/* 0x9d91 */ { false, 0x9d91, 0x9d91 }, +/* 0x9d92 */ { false, 0x9d92, 0x9d92 }, +/* 0x9d93 */ { false, 0x9d93, 0x9d93 }, +/* 0x9d94 */ { false, 0x9d94, 0x9d94 }, +/* 0x9d95 */ { false, 0x9d95, 0x9d95 }, +/* 0x9d96 */ { false, 0x9d96, 0x9d96 }, +/* 0x9d97 */ { false, 0x9d97, 0x9d97 }, +/* 0x9d98 */ { false, 0x9d98, 0x9d98 }, +/* 0x9d99 */ { false, 0x9d99, 0x9d99 }, +/* 0x9d9a */ { false, 0x9d9a, 0x9d9a }, +/* 0x9d9b */ { false, 0x9d9b, 0x9d9b }, +/* 0x9d9c */ { false, 0x9d9c, 0x9d9c }, +/* 0x9d9d */ { false, 0x9d9d, 0x9d9d }, +/* 0x9d9e */ { false, 0x9d9e, 0x9d9e }, +/* 0x9d9f */ { false, 0x9d9f, 0x9d9f }, +/* 0x9da0 */ { false, 0x9da0, 0x9da0 }, +/* 0x9da1 */ { false, 0x9da1, 0x9da1 }, +/* 0x9da2 */ { false, 0x9da2, 0x9da2 }, +/* 0x9da3 */ { false, 0x9da3, 0x9da3 }, +/* 0x9da4 */ { false, 0x9da4, 0x9da4 }, +/* 0x9da5 */ { false, 0x9da5, 0x9da5 }, +/* 0x9da6 */ { false, 0x9da6, 0x9da6 }, +/* 0x9da7 */ { false, 0x9da7, 0x9da7 }, +/* 0x9da8 */ { false, 0x9da8, 0x9da8 }, +/* 0x9da9 */ { false, 0x9da9, 0x9da9 }, +/* 0x9daa */ { false, 0x9daa, 0x9daa }, +/* 0x9dab */ { false, 0x9dab, 0x9dab }, +/* 0x9dac */ { false, 0x9dac, 0x9dac }, +/* 0x9dad */ { false, 0x9dad, 0x9dad }, +/* 0x9dae */ { false, 0x9dae, 0x9dae }, +/* 0x9daf */ { false, 0x9daf, 0x9daf }, +/* 0x9db0 */ { false, 0x9db0, 0x9db0 }, +/* 0x9db1 */ { false, 0x9db1, 0x9db1 }, +/* 0x9db2 */ { false, 0x9db2, 0x9db2 }, +/* 0x9db3 */ { false, 0x9db3, 0x9db3 }, +/* 0x9db4 */ { false, 0x9db4, 0x9db4 }, +/* 0x9db5 */ { false, 0x9db5, 0x9db5 }, +/* 0x9db6 */ { false, 0x9db6, 0x9db6 }, +/* 0x9db7 */ { false, 0x9db7, 0x9db7 }, +/* 0x9db8 */ { false, 0x9db8, 0x9db8 }, +/* 0x9db9 */ { false, 0x9db9, 0x9db9 }, +/* 0x9dba */ { false, 0x9dba, 0x9dba }, +/* 0x9dbb */ { false, 0x9dbb, 0x9dbb }, +/* 0x9dbc */ { false, 0x9dbc, 0x9dbc }, +/* 0x9dbd */ { false, 0x9dbd, 0x9dbd }, +/* 0x9dbe */ { false, 0x9dbe, 0x9dbe }, +/* 0x9dbf */ { false, 0x9dbf, 0x9dbf }, +/* 0x9dc0 */ { false, 0x9dc0, 0x9dc0 }, +/* 0x9dc1 */ { false, 0x9dc1, 0x9dc1 }, +/* 0x9dc2 */ { false, 0x9dc2, 0x9dc2 }, +/* 0x9dc3 */ { false, 0x9dc3, 0x9dc3 }, +/* 0x9dc4 */ { false, 0x9dc4, 0x9dc4 }, +/* 0x9dc5 */ { false, 0x9dc5, 0x9dc5 }, +/* 0x9dc6 */ { false, 0x9dc6, 0x9dc6 }, +/* 0x9dc7 */ { false, 0x9dc7, 0x9dc7 }, +/* 0x9dc8 */ { false, 0x9dc8, 0x9dc8 }, +/* 0x9dc9 */ { false, 0x9dc9, 0x9dc9 }, +/* 0x9dca */ { false, 0x9dca, 0x9dca }, +/* 0x9dcb */ { false, 0x9dcb, 0x9dcb }, +/* 0x9dcc */ { false, 0x9dcc, 0x9dcc }, +/* 0x9dcd */ { false, 0x9dcd, 0x9dcd }, +/* 0x9dce */ { false, 0x9dce, 0x9dce }, +/* 0x9dcf */ { false, 0x9dcf, 0x9dcf }, +/* 0x9dd0 */ { false, 0x9dd0, 0x9dd0 }, +/* 0x9dd1 */ { false, 0x9dd1, 0x9dd1 }, +/* 0x9dd2 */ { false, 0x9dd2, 0x9dd2 }, +/* 0x9dd3 */ { false, 0x9dd3, 0x9dd3 }, +/* 0x9dd4 */ { false, 0x9dd4, 0x9dd4 }, +/* 0x9dd5 */ { false, 0x9dd5, 0x9dd5 }, +/* 0x9dd6 */ { false, 0x9dd6, 0x9dd6 }, +/* 0x9dd7 */ { false, 0x9dd7, 0x9dd7 }, +/* 0x9dd8 */ { false, 0x9dd8, 0x9dd8 }, +/* 0x9dd9 */ { false, 0x9dd9, 0x9dd9 }, +/* 0x9dda */ { false, 0x9dda, 0x9dda }, +/* 0x9ddb */ { false, 0x9ddb, 0x9ddb }, +/* 0x9ddc */ { false, 0x9ddc, 0x9ddc }, +/* 0x9ddd */ { false, 0x9ddd, 0x9ddd }, +/* 0x9dde */ { false, 0x9dde, 0x9dde }, +/* 0x9ddf */ { false, 0x9ddf, 0x9ddf }, +/* 0x9de0 */ { false, 0x9de0, 0x9de0 }, +/* 0x9de1 */ { false, 0x9de1, 0x9de1 }, +/* 0x9de2 */ { false, 0x9de2, 0x9de2 }, +/* 0x9de3 */ { false, 0x9de3, 0x9de3 }, +/* 0x9de4 */ { false, 0x9de4, 0x9de4 }, +/* 0x9de5 */ { false, 0x9de5, 0x9de5 }, +/* 0x9de6 */ { false, 0x9de6, 0x9de6 }, +/* 0x9de7 */ { false, 0x9de7, 0x9de7 }, +/* 0x9de8 */ { false, 0x9de8, 0x9de8 }, +/* 0x9de9 */ { false, 0x9de9, 0x9de9 }, +/* 0x9dea */ { false, 0x9dea, 0x9dea }, +/* 0x9deb */ { false, 0x9deb, 0x9deb }, +/* 0x9dec */ { false, 0x9dec, 0x9dec }, +/* 0x9ded */ { false, 0x9ded, 0x9ded }, +/* 0x9dee */ { false, 0x9dee, 0x9dee }, +/* 0x9def */ { false, 0x9def, 0x9def }, +/* 0x9df0 */ { false, 0x9df0, 0x9df0 }, +/* 0x9df1 */ { false, 0x9df1, 0x9df1 }, +/* 0x9df2 */ { false, 0x9df2, 0x9df2 }, +/* 0x9df3 */ { false, 0x9df3, 0x9df3 }, +/* 0x9df4 */ { false, 0x9df4, 0x9df4 }, +/* 0x9df5 */ { false, 0x9df5, 0x9df5 }, +/* 0x9df6 */ { false, 0x9df6, 0x9df6 }, +/* 0x9df7 */ { false, 0x9df7, 0x9df7 }, +/* 0x9df8 */ { false, 0x9df8, 0x9df8 }, +/* 0x9df9 */ { false, 0x9df9, 0x9df9 }, +/* 0x9dfa */ { false, 0x9dfa, 0x9dfa }, +/* 0x9dfb */ { false, 0x9dfb, 0x9dfb }, +/* 0x9dfc */ { false, 0x9dfc, 0x9dfc }, +/* 0x9dfd */ { false, 0x9dfd, 0x9dfd }, +/* 0x9dfe */ { false, 0x9dfe, 0x9dfe }, +/* 0x9dff */ { false, 0x9dff, 0x9dff }, +/* 0x9e00 */ { false, 0x9e00, 0x9e00 }, +/* 0x9e01 */ { false, 0x9e01, 0x9e01 }, +/* 0x9e02 */ { false, 0x9e02, 0x9e02 }, +/* 0x9e03 */ { false, 0x9e03, 0x9e03 }, +/* 0x9e04 */ { false, 0x9e04, 0x9e04 }, +/* 0x9e05 */ { false, 0x9e05, 0x9e05 }, +/* 0x9e06 */ { false, 0x9e06, 0x9e06 }, +/* 0x9e07 */ { false, 0x9e07, 0x9e07 }, +/* 0x9e08 */ { false, 0x9e08, 0x9e08 }, +/* 0x9e09 */ { false, 0x9e09, 0x9e09 }, +/* 0x9e0a */ { false, 0x9e0a, 0x9e0a }, +/* 0x9e0b */ { false, 0x9e0b, 0x9e0b }, +/* 0x9e0c */ { false, 0x9e0c, 0x9e0c }, +/* 0x9e0d */ { false, 0x9e0d, 0x9e0d }, +/* 0x9e0e */ { false, 0x9e0e, 0x9e0e }, +/* 0x9e0f */ { false, 0x9e0f, 0x9e0f }, +/* 0x9e10 */ { false, 0x9e10, 0x9e10 }, +/* 0x9e11 */ { false, 0x9e11, 0x9e11 }, +/* 0x9e12 */ { false, 0x9e12, 0x9e12 }, +/* 0x9e13 */ { false, 0x9e13, 0x9e13 }, +/* 0x9e14 */ { false, 0x9e14, 0x9e14 }, +/* 0x9e15 */ { false, 0x9e15, 0x9e15 }, +/* 0x9e16 */ { false, 0x9e16, 0x9e16 }, +/* 0x9e17 */ { false, 0x9e17, 0x9e17 }, +/* 0x9e18 */ { false, 0x9e18, 0x9e18 }, +/* 0x9e19 */ { false, 0x9e19, 0x9e19 }, +/* 0x9e1a */ { false, 0x9e1a, 0x9e1a }, +/* 0x9e1b */ { false, 0x9e1b, 0x9e1b }, +/* 0x9e1c */ { false, 0x9e1c, 0x9e1c }, +/* 0x9e1d */ { false, 0x9e1d, 0x9e1d }, +/* 0x9e1e */ { false, 0x9e1e, 0x9e1e }, +/* 0x9e1f */ { false, 0x9e1f, 0x9e1f }, +/* 0x9e20 */ { false, 0x9e20, 0x9e20 }, +/* 0x9e21 */ { false, 0x9e21, 0x9e21 }, +/* 0x9e22 */ { false, 0x9e22, 0x9e22 }, +/* 0x9e23 */ { false, 0x9e23, 0x9e23 }, +/* 0x9e24 */ { false, 0x9e24, 0x9e24 }, +/* 0x9e25 */ { false, 0x9e25, 0x9e25 }, +/* 0x9e26 */ { false, 0x9e26, 0x9e26 }, +/* 0x9e27 */ { false, 0x9e27, 0x9e27 }, +/* 0x9e28 */ { false, 0x9e28, 0x9e28 }, +/* 0x9e29 */ { false, 0x9e29, 0x9e29 }, +/* 0x9e2a */ { false, 0x9e2a, 0x9e2a }, +/* 0x9e2b */ { false, 0x9e2b, 0x9e2b }, +/* 0x9e2c */ { false, 0x9e2c, 0x9e2c }, +/* 0x9e2d */ { false, 0x9e2d, 0x9e2d }, +/* 0x9e2e */ { false, 0x9e2e, 0x9e2e }, +/* 0x9e2f */ { false, 0x9e2f, 0x9e2f }, +/* 0x9e30 */ { false, 0x9e30, 0x9e30 }, +/* 0x9e31 */ { false, 0x9e31, 0x9e31 }, +/* 0x9e32 */ { false, 0x9e32, 0x9e32 }, +/* 0x9e33 */ { false, 0x9e33, 0x9e33 }, +/* 0x9e34 */ { false, 0x9e34, 0x9e34 }, +/* 0x9e35 */ { false, 0x9e35, 0x9e35 }, +/* 0x9e36 */ { false, 0x9e36, 0x9e36 }, +/* 0x9e37 */ { false, 0x9e37, 0x9e37 }, +/* 0x9e38 */ { false, 0x9e38, 0x9e38 }, +/* 0x9e39 */ { false, 0x9e39, 0x9e39 }, +/* 0x9e3a */ { false, 0x9e3a, 0x9e3a }, +/* 0x9e3b */ { false, 0x9e3b, 0x9e3b }, +/* 0x9e3c */ { false, 0x9e3c, 0x9e3c }, +/* 0x9e3d */ { false, 0x9e3d, 0x9e3d }, +/* 0x9e3e */ { false, 0x9e3e, 0x9e3e }, +/* 0x9e3f */ { false, 0x9e3f, 0x9e3f }, +/* 0x9e40 */ { false, 0x9e40, 0x9e40 }, +/* 0x9e41 */ { false, 0x9e41, 0x9e41 }, +/* 0x9e42 */ { false, 0x9e42, 0x9e42 }, +/* 0x9e43 */ { false, 0x9e43, 0x9e43 }, +/* 0x9e44 */ { false, 0x9e44, 0x9e44 }, +/* 0x9e45 */ { false, 0x9e45, 0x9e45 }, +/* 0x9e46 */ { false, 0x9e46, 0x9e46 }, +/* 0x9e47 */ { false, 0x9e47, 0x9e47 }, +/* 0x9e48 */ { false, 0x9e48, 0x9e48 }, +/* 0x9e49 */ { false, 0x9e49, 0x9e49 }, +/* 0x9e4a */ { false, 0x9e4a, 0x9e4a }, +/* 0x9e4b */ { false, 0x9e4b, 0x9e4b }, +/* 0x9e4c */ { false, 0x9e4c, 0x9e4c }, +/* 0x9e4d */ { false, 0x9e4d, 0x9e4d }, +/* 0x9e4e */ { false, 0x9e4e, 0x9e4e }, +/* 0x9e4f */ { false, 0x9e4f, 0x9e4f }, +/* 0x9e50 */ { false, 0x9e50, 0x9e50 }, +/* 0x9e51 */ { false, 0x9e51, 0x9e51 }, +/* 0x9e52 */ { false, 0x9e52, 0x9e52 }, +/* 0x9e53 */ { false, 0x9e53, 0x9e53 }, +/* 0x9e54 */ { false, 0x9e54, 0x9e54 }, +/* 0x9e55 */ { false, 0x9e55, 0x9e55 }, +/* 0x9e56 */ { false, 0x9e56, 0x9e56 }, +/* 0x9e57 */ { false, 0x9e57, 0x9e57 }, +/* 0x9e58 */ { false, 0x9e58, 0x9e58 }, +/* 0x9e59 */ { false, 0x9e59, 0x9e59 }, +/* 0x9e5a */ { false, 0x9e5a, 0x9e5a }, +/* 0x9e5b */ { false, 0x9e5b, 0x9e5b }, +/* 0x9e5c */ { false, 0x9e5c, 0x9e5c }, +/* 0x9e5d */ { false, 0x9e5d, 0x9e5d }, +/* 0x9e5e */ { false, 0x9e5e, 0x9e5e }, +/* 0x9e5f */ { false, 0x9e5f, 0x9e5f }, +/* 0x9e60 */ { false, 0x9e60, 0x9e60 }, +/* 0x9e61 */ { false, 0x9e61, 0x9e61 }, +/* 0x9e62 */ { false, 0x9e62, 0x9e62 }, +/* 0x9e63 */ { false, 0x9e63, 0x9e63 }, +/* 0x9e64 */ { false, 0x9e64, 0x9e64 }, +/* 0x9e65 */ { false, 0x9e65, 0x9e65 }, +/* 0x9e66 */ { false, 0x9e66, 0x9e66 }, +/* 0x9e67 */ { false, 0x9e67, 0x9e67 }, +/* 0x9e68 */ { false, 0x9e68, 0x9e68 }, +/* 0x9e69 */ { false, 0x9e69, 0x9e69 }, +/* 0x9e6a */ { false, 0x9e6a, 0x9e6a }, +/* 0x9e6b */ { false, 0x9e6b, 0x9e6b }, +/* 0x9e6c */ { false, 0x9e6c, 0x9e6c }, +/* 0x9e6d */ { false, 0x9e6d, 0x9e6d }, +/* 0x9e6e */ { false, 0x9e6e, 0x9e6e }, +/* 0x9e6f */ { false, 0x9e6f, 0x9e6f }, +/* 0x9e70 */ { false, 0x9e70, 0x9e70 }, +/* 0x9e71 */ { false, 0x9e71, 0x9e71 }, +/* 0x9e72 */ { false, 0x9e72, 0x9e72 }, +/* 0x9e73 */ { false, 0x9e73, 0x9e73 }, +/* 0x9e74 */ { false, 0x9e74, 0x9e74 }, +/* 0x9e75 */ { false, 0x9e75, 0x9e75 }, +/* 0x9e76 */ { false, 0x9e76, 0x9e76 }, +/* 0x9e77 */ { false, 0x9e77, 0x9e77 }, +/* 0x9e78 */ { false, 0x9e78, 0x9e78 }, +/* 0x9e79 */ { false, 0x9e79, 0x9e79 }, +/* 0x9e7a */ { false, 0x9e7a, 0x9e7a }, +/* 0x9e7b */ { false, 0x9e7b, 0x9e7b }, +/* 0x9e7c */ { false, 0x9e7c, 0x9e7c }, +/* 0x9e7d */ { false, 0x9e7d, 0x9e7d }, +/* 0x9e7e */ { false, 0x9e7e, 0x9e7e }, +/* 0x9e7f */ { false, 0x9e7f, 0x9e7f }, +/* 0x9e80 */ { false, 0x9e80, 0x9e80 }, +/* 0x9e81 */ { false, 0x9e81, 0x9e81 }, +/* 0x9e82 */ { false, 0x9e82, 0x9e82 }, +/* 0x9e83 */ { false, 0x9e83, 0x9e83 }, +/* 0x9e84 */ { false, 0x9e84, 0x9e84 }, +/* 0x9e85 */ { false, 0x9e85, 0x9e85 }, +/* 0x9e86 */ { false, 0x9e86, 0x9e86 }, +/* 0x9e87 */ { false, 0x9e87, 0x9e87 }, +/* 0x9e88 */ { false, 0x9e88, 0x9e88 }, +/* 0x9e89 */ { false, 0x9e89, 0x9e89 }, +/* 0x9e8a */ { false, 0x9e8a, 0x9e8a }, +/* 0x9e8b */ { false, 0x9e8b, 0x9e8b }, +/* 0x9e8c */ { false, 0x9e8c, 0x9e8c }, +/* 0x9e8d */ { false, 0x9e8d, 0x9e8d }, +/* 0x9e8e */ { false, 0x9e8e, 0x9e8e }, +/* 0x9e8f */ { false, 0x9e8f, 0x9e8f }, +/* 0x9e90 */ { false, 0x9e90, 0x9e90 }, +/* 0x9e91 */ { false, 0x9e91, 0x9e91 }, +/* 0x9e92 */ { false, 0x9e92, 0x9e92 }, +/* 0x9e93 */ { false, 0x9e93, 0x9e93 }, +/* 0x9e94 */ { false, 0x9e94, 0x9e94 }, +/* 0x9e95 */ { false, 0x9e95, 0x9e95 }, +/* 0x9e96 */ { false, 0x9e96, 0x9e96 }, +/* 0x9e97 */ { false, 0x9e97, 0x9e97 }, +/* 0x9e98 */ { false, 0x9e98, 0x9e98 }, +/* 0x9e99 */ { false, 0x9e99, 0x9e99 }, +/* 0x9e9a */ { false, 0x9e9a, 0x9e9a }, +/* 0x9e9b */ { false, 0x9e9b, 0x9e9b }, +/* 0x9e9c */ { false, 0x9e9c, 0x9e9c }, +/* 0x9e9d */ { false, 0x9e9d, 0x9e9d }, +/* 0x9e9e */ { false, 0x9e9e, 0x9e9e }, +/* 0x9e9f */ { false, 0x9e9f, 0x9e9f }, +/* 0x9ea0 */ { false, 0x9ea0, 0x9ea0 }, +/* 0x9ea1 */ { false, 0x9ea1, 0x9ea1 }, +/* 0x9ea2 */ { false, 0x9ea2, 0x9ea2 }, +/* 0x9ea3 */ { false, 0x9ea3, 0x9ea3 }, +/* 0x9ea4 */ { false, 0x9ea4, 0x9ea4 }, +/* 0x9ea5 */ { false, 0x9ea5, 0x9ea5 }, +/* 0x9ea6 */ { false, 0x9ea6, 0x9ea6 }, +/* 0x9ea7 */ { false, 0x9ea7, 0x9ea7 }, +/* 0x9ea8 */ { false, 0x9ea8, 0x9ea8 }, +/* 0x9ea9 */ { false, 0x9ea9, 0x9ea9 }, +/* 0x9eaa */ { false, 0x9eaa, 0x9eaa }, +/* 0x9eab */ { false, 0x9eab, 0x9eab }, +/* 0x9eac */ { false, 0x9eac, 0x9eac }, +/* 0x9ead */ { false, 0x9ead, 0x9ead }, +/* 0x9eae */ { false, 0x9eae, 0x9eae }, +/* 0x9eaf */ { false, 0x9eaf, 0x9eaf }, +/* 0x9eb0 */ { false, 0x9eb0, 0x9eb0 }, +/* 0x9eb1 */ { false, 0x9eb1, 0x9eb1 }, +/* 0x9eb2 */ { false, 0x9eb2, 0x9eb2 }, +/* 0x9eb3 */ { false, 0x9eb3, 0x9eb3 }, +/* 0x9eb4 */ { false, 0x9eb4, 0x9eb4 }, +/* 0x9eb5 */ { false, 0x9eb5, 0x9eb5 }, +/* 0x9eb6 */ { false, 0x9eb6, 0x9eb6 }, +/* 0x9eb7 */ { false, 0x9eb7, 0x9eb7 }, +/* 0x9eb8 */ { false, 0x9eb8, 0x9eb8 }, +/* 0x9eb9 */ { false, 0x9eb9, 0x9eb9 }, +/* 0x9eba */ { false, 0x9eba, 0x9eba }, +/* 0x9ebb */ { false, 0x9ebb, 0x9ebb }, +/* 0x9ebc */ { false, 0x9ebc, 0x9ebc }, +/* 0x9ebd */ { false, 0x9ebd, 0x9ebd }, +/* 0x9ebe */ { false, 0x9ebe, 0x9ebe }, +/* 0x9ebf */ { false, 0x9ebf, 0x9ebf }, +/* 0x9ec0 */ { false, 0x9ec0, 0x9ec0 }, +/* 0x9ec1 */ { false, 0x9ec1, 0x9ec1 }, +/* 0x9ec2 */ { false, 0x9ec2, 0x9ec2 }, +/* 0x9ec3 */ { false, 0x9ec3, 0x9ec3 }, +/* 0x9ec4 */ { false, 0x9ec4, 0x9ec4 }, +/* 0x9ec5 */ { false, 0x9ec5, 0x9ec5 }, +/* 0x9ec6 */ { false, 0x9ec6, 0x9ec6 }, +/* 0x9ec7 */ { false, 0x9ec7, 0x9ec7 }, +/* 0x9ec8 */ { false, 0x9ec8, 0x9ec8 }, +/* 0x9ec9 */ { false, 0x9ec9, 0x9ec9 }, +/* 0x9eca */ { false, 0x9eca, 0x9eca }, +/* 0x9ecb */ { false, 0x9ecb, 0x9ecb }, +/* 0x9ecc */ { false, 0x9ecc, 0x9ecc }, +/* 0x9ecd */ { false, 0x9ecd, 0x9ecd }, +/* 0x9ece */ { false, 0x9ece, 0x9ece }, +/* 0x9ecf */ { false, 0x9ecf, 0x9ecf }, +/* 0x9ed0 */ { false, 0x9ed0, 0x9ed0 }, +/* 0x9ed1 */ { false, 0x9ed1, 0x9ed1 }, +/* 0x9ed2 */ { false, 0x9ed2, 0x9ed2 }, +/* 0x9ed3 */ { false, 0x9ed3, 0x9ed3 }, +/* 0x9ed4 */ { false, 0x9ed4, 0x9ed4 }, +/* 0x9ed5 */ { false, 0x9ed5, 0x9ed5 }, +/* 0x9ed6 */ { false, 0x9ed6, 0x9ed6 }, +/* 0x9ed7 */ { false, 0x9ed7, 0x9ed7 }, +/* 0x9ed8 */ { false, 0x9ed8, 0x9ed8 }, +/* 0x9ed9 */ { false, 0x9ed9, 0x9ed9 }, +/* 0x9eda */ { false, 0x9eda, 0x9eda }, +/* 0x9edb */ { false, 0x9edb, 0x9edb }, +/* 0x9edc */ { false, 0x9edc, 0x9edc }, +/* 0x9edd */ { false, 0x9edd, 0x9edd }, +/* 0x9ede */ { false, 0x9ede, 0x9ede }, +/* 0x9edf */ { false, 0x9edf, 0x9edf }, +/* 0x9ee0 */ { false, 0x9ee0, 0x9ee0 }, +/* 0x9ee1 */ { false, 0x9ee1, 0x9ee1 }, +/* 0x9ee2 */ { false, 0x9ee2, 0x9ee2 }, +/* 0x9ee3 */ { false, 0x9ee3, 0x9ee3 }, +/* 0x9ee4 */ { false, 0x9ee4, 0x9ee4 }, +/* 0x9ee5 */ { false, 0x9ee5, 0x9ee5 }, +/* 0x9ee6 */ { false, 0x9ee6, 0x9ee6 }, +/* 0x9ee7 */ { false, 0x9ee7, 0x9ee7 }, +/* 0x9ee8 */ { false, 0x9ee8, 0x9ee8 }, +/* 0x9ee9 */ { false, 0x9ee9, 0x9ee9 }, +/* 0x9eea */ { false, 0x9eea, 0x9eea }, +/* 0x9eeb */ { false, 0x9eeb, 0x9eeb }, +/* 0x9eec */ { false, 0x9eec, 0x9eec }, +/* 0x9eed */ { false, 0x9eed, 0x9eed }, +/* 0x9eee */ { false, 0x9eee, 0x9eee }, +/* 0x9eef */ { false, 0x9eef, 0x9eef }, +/* 0x9ef0 */ { false, 0x9ef0, 0x9ef0 }, +/* 0x9ef1 */ { false, 0x9ef1, 0x9ef1 }, +/* 0x9ef2 */ { false, 0x9ef2, 0x9ef2 }, +/* 0x9ef3 */ { false, 0x9ef3, 0x9ef3 }, +/* 0x9ef4 */ { false, 0x9ef4, 0x9ef4 }, +/* 0x9ef5 */ { false, 0x9ef5, 0x9ef5 }, +/* 0x9ef6 */ { false, 0x9ef6, 0x9ef6 }, +/* 0x9ef7 */ { false, 0x9ef7, 0x9ef7 }, +/* 0x9ef8 */ { false, 0x9ef8, 0x9ef8 }, +/* 0x9ef9 */ { false, 0x9ef9, 0x9ef9 }, +/* 0x9efa */ { false, 0x9efa, 0x9efa }, +/* 0x9efb */ { false, 0x9efb, 0x9efb }, +/* 0x9efc */ { false, 0x9efc, 0x9efc }, +/* 0x9efd */ { false, 0x9efd, 0x9efd }, +/* 0x9efe */ { false, 0x9efe, 0x9efe }, +/* 0x9eff */ { false, 0x9eff, 0x9eff }, +/* 0x9f00 */ { false, 0x9f00, 0x9f00 }, +/* 0x9f01 */ { false, 0x9f01, 0x9f01 }, +/* 0x9f02 */ { false, 0x9f02, 0x9f02 }, +/* 0x9f03 */ { false, 0x9f03, 0x9f03 }, +/* 0x9f04 */ { false, 0x9f04, 0x9f04 }, +/* 0x9f05 */ { false, 0x9f05, 0x9f05 }, +/* 0x9f06 */ { false, 0x9f06, 0x9f06 }, +/* 0x9f07 */ { false, 0x9f07, 0x9f07 }, +/* 0x9f08 */ { false, 0x9f08, 0x9f08 }, +/* 0x9f09 */ { false, 0x9f09, 0x9f09 }, +/* 0x9f0a */ { false, 0x9f0a, 0x9f0a }, +/* 0x9f0b */ { false, 0x9f0b, 0x9f0b }, +/* 0x9f0c */ { false, 0x9f0c, 0x9f0c }, +/* 0x9f0d */ { false, 0x9f0d, 0x9f0d }, +/* 0x9f0e */ { false, 0x9f0e, 0x9f0e }, +/* 0x9f0f */ { false, 0x9f0f, 0x9f0f }, +/* 0x9f10 */ { false, 0x9f10, 0x9f10 }, +/* 0x9f11 */ { false, 0x9f11, 0x9f11 }, +/* 0x9f12 */ { false, 0x9f12, 0x9f12 }, +/* 0x9f13 */ { false, 0x9f13, 0x9f13 }, +/* 0x9f14 */ { false, 0x9f14, 0x9f14 }, +/* 0x9f15 */ { false, 0x9f15, 0x9f15 }, +/* 0x9f16 */ { false, 0x9f16, 0x9f16 }, +/* 0x9f17 */ { false, 0x9f17, 0x9f17 }, +/* 0x9f18 */ { false, 0x9f18, 0x9f18 }, +/* 0x9f19 */ { false, 0x9f19, 0x9f19 }, +/* 0x9f1a */ { false, 0x9f1a, 0x9f1a }, +/* 0x9f1b */ { false, 0x9f1b, 0x9f1b }, +/* 0x9f1c */ { false, 0x9f1c, 0x9f1c }, +/* 0x9f1d */ { false, 0x9f1d, 0x9f1d }, +/* 0x9f1e */ { false, 0x9f1e, 0x9f1e }, +/* 0x9f1f */ { false, 0x9f1f, 0x9f1f }, +/* 0x9f20 */ { false, 0x9f20, 0x9f20 }, +/* 0x9f21 */ { false, 0x9f21, 0x9f21 }, +/* 0x9f22 */ { false, 0x9f22, 0x9f22 }, +/* 0x9f23 */ { false, 0x9f23, 0x9f23 }, +/* 0x9f24 */ { false, 0x9f24, 0x9f24 }, +/* 0x9f25 */ { false, 0x9f25, 0x9f25 }, +/* 0x9f26 */ { false, 0x9f26, 0x9f26 }, +/* 0x9f27 */ { false, 0x9f27, 0x9f27 }, +/* 0x9f28 */ { false, 0x9f28, 0x9f28 }, +/* 0x9f29 */ { false, 0x9f29, 0x9f29 }, +/* 0x9f2a */ { false, 0x9f2a, 0x9f2a }, +/* 0x9f2b */ { false, 0x9f2b, 0x9f2b }, +/* 0x9f2c */ { false, 0x9f2c, 0x9f2c }, +/* 0x9f2d */ { false, 0x9f2d, 0x9f2d }, +/* 0x9f2e */ { false, 0x9f2e, 0x9f2e }, +/* 0x9f2f */ { false, 0x9f2f, 0x9f2f }, +/* 0x9f30 */ { false, 0x9f30, 0x9f30 }, +/* 0x9f31 */ { false, 0x9f31, 0x9f31 }, +/* 0x9f32 */ { false, 0x9f32, 0x9f32 }, +/* 0x9f33 */ { false, 0x9f33, 0x9f33 }, +/* 0x9f34 */ { false, 0x9f34, 0x9f34 }, +/* 0x9f35 */ { false, 0x9f35, 0x9f35 }, +/* 0x9f36 */ { false, 0x9f36, 0x9f36 }, +/* 0x9f37 */ { false, 0x9f37, 0x9f37 }, +/* 0x9f38 */ { false, 0x9f38, 0x9f38 }, +/* 0x9f39 */ { false, 0x9f39, 0x9f39 }, +/* 0x9f3a */ { false, 0x9f3a, 0x9f3a }, +/* 0x9f3b */ { false, 0x9f3b, 0x9f3b }, +/* 0x9f3c */ { false, 0x9f3c, 0x9f3c }, +/* 0x9f3d */ { false, 0x9f3d, 0x9f3d }, +/* 0x9f3e */ { false, 0x9f3e, 0x9f3e }, +/* 0x9f3f */ { false, 0x9f3f, 0x9f3f }, +/* 0x9f40 */ { false, 0x9f40, 0x9f40 }, +/* 0x9f41 */ { false, 0x9f41, 0x9f41 }, +/* 0x9f42 */ { false, 0x9f42, 0x9f42 }, +/* 0x9f43 */ { false, 0x9f43, 0x9f43 }, +/* 0x9f44 */ { false, 0x9f44, 0x9f44 }, +/* 0x9f45 */ { false, 0x9f45, 0x9f45 }, +/* 0x9f46 */ { false, 0x9f46, 0x9f46 }, +/* 0x9f47 */ { false, 0x9f47, 0x9f47 }, +/* 0x9f48 */ { false, 0x9f48, 0x9f48 }, +/* 0x9f49 */ { false, 0x9f49, 0x9f49 }, +/* 0x9f4a */ { false, 0x9f4a, 0x9f4a }, +/* 0x9f4b */ { false, 0x9f4b, 0x9f4b }, +/* 0x9f4c */ { false, 0x9f4c, 0x9f4c }, +/* 0x9f4d */ { false, 0x9f4d, 0x9f4d }, +/* 0x9f4e */ { false, 0x9f4e, 0x9f4e }, +/* 0x9f4f */ { false, 0x9f4f, 0x9f4f }, +/* 0x9f50 */ { false, 0x9f50, 0x9f50 }, +/* 0x9f51 */ { false, 0x9f51, 0x9f51 }, +/* 0x9f52 */ { false, 0x9f52, 0x9f52 }, +/* 0x9f53 */ { false, 0x9f53, 0x9f53 }, +/* 0x9f54 */ { false, 0x9f54, 0x9f54 }, +/* 0x9f55 */ { false, 0x9f55, 0x9f55 }, +/* 0x9f56 */ { false, 0x9f56, 0x9f56 }, +/* 0x9f57 */ { false, 0x9f57, 0x9f57 }, +/* 0x9f58 */ { false, 0x9f58, 0x9f58 }, +/* 0x9f59 */ { false, 0x9f59, 0x9f59 }, +/* 0x9f5a */ { false, 0x9f5a, 0x9f5a }, +/* 0x9f5b */ { false, 0x9f5b, 0x9f5b }, +/* 0x9f5c */ { false, 0x9f5c, 0x9f5c }, +/* 0x9f5d */ { false, 0x9f5d, 0x9f5d }, +/* 0x9f5e */ { false, 0x9f5e, 0x9f5e }, +/* 0x9f5f */ { false, 0x9f5f, 0x9f5f }, +/* 0x9f60 */ { false, 0x9f60, 0x9f60 }, +/* 0x9f61 */ { false, 0x9f61, 0x9f61 }, +/* 0x9f62 */ { false, 0x9f62, 0x9f62 }, +/* 0x9f63 */ { false, 0x9f63, 0x9f63 }, +/* 0x9f64 */ { false, 0x9f64, 0x9f64 }, +/* 0x9f65 */ { false, 0x9f65, 0x9f65 }, +/* 0x9f66 */ { false, 0x9f66, 0x9f66 }, +/* 0x9f67 */ { false, 0x9f67, 0x9f67 }, +/* 0x9f68 */ { false, 0x9f68, 0x9f68 }, +/* 0x9f69 */ { false, 0x9f69, 0x9f69 }, +/* 0x9f6a */ { false, 0x9f6a, 0x9f6a }, +/* 0x9f6b */ { false, 0x9f6b, 0x9f6b }, +/* 0x9f6c */ { false, 0x9f6c, 0x9f6c }, +/* 0x9f6d */ { false, 0x9f6d, 0x9f6d }, +/* 0x9f6e */ { false, 0x9f6e, 0x9f6e }, +/* 0x9f6f */ { false, 0x9f6f, 0x9f6f }, +/* 0x9f70 */ { false, 0x9f70, 0x9f70 }, +/* 0x9f71 */ { false, 0x9f71, 0x9f71 }, +/* 0x9f72 */ { false, 0x9f72, 0x9f72 }, +/* 0x9f73 */ { false, 0x9f73, 0x9f73 }, +/* 0x9f74 */ { false, 0x9f74, 0x9f74 }, +/* 0x9f75 */ { false, 0x9f75, 0x9f75 }, +/* 0x9f76 */ { false, 0x9f76, 0x9f76 }, +/* 0x9f77 */ { false, 0x9f77, 0x9f77 }, +/* 0x9f78 */ { false, 0x9f78, 0x9f78 }, +/* 0x9f79 */ { false, 0x9f79, 0x9f79 }, +/* 0x9f7a */ { false, 0x9f7a, 0x9f7a }, +/* 0x9f7b */ { false, 0x9f7b, 0x9f7b }, +/* 0x9f7c */ { false, 0x9f7c, 0x9f7c }, +/* 0x9f7d */ { false, 0x9f7d, 0x9f7d }, +/* 0x9f7e */ { false, 0x9f7e, 0x9f7e }, +/* 0x9f7f */ { false, 0x9f7f, 0x9f7f }, +/* 0x9f80 */ { false, 0x9f80, 0x9f80 }, +/* 0x9f81 */ { false, 0x9f81, 0x9f81 }, +/* 0x9f82 */ { false, 0x9f82, 0x9f82 }, +/* 0x9f83 */ { false, 0x9f83, 0x9f83 }, +/* 0x9f84 */ { false, 0x9f84, 0x9f84 }, +/* 0x9f85 */ { false, 0x9f85, 0x9f85 }, +/* 0x9f86 */ { false, 0x9f86, 0x9f86 }, +/* 0x9f87 */ { false, 0x9f87, 0x9f87 }, +/* 0x9f88 */ { false, 0x9f88, 0x9f88 }, +/* 0x9f89 */ { false, 0x9f89, 0x9f89 }, +/* 0x9f8a */ { false, 0x9f8a, 0x9f8a }, +/* 0x9f8b */ { false, 0x9f8b, 0x9f8b }, +/* 0x9f8c */ { false, 0x9f8c, 0x9f8c }, +/* 0x9f8d */ { false, 0x9f8d, 0x9f8d }, +/* 0x9f8e */ { false, 0x9f8e, 0x9f8e }, +/* 0x9f8f */ { false, 0x9f8f, 0x9f8f }, +/* 0x9f90 */ { false, 0x9f90, 0x9f90 }, +/* 0x9f91 */ { false, 0x9f91, 0x9f91 }, +/* 0x9f92 */ { false, 0x9f92, 0x9f92 }, +/* 0x9f93 */ { false, 0x9f93, 0x9f93 }, +/* 0x9f94 */ { false, 0x9f94, 0x9f94 }, +/* 0x9f95 */ { false, 0x9f95, 0x9f95 }, +/* 0x9f96 */ { false, 0x9f96, 0x9f96 }, +/* 0x9f97 */ { false, 0x9f97, 0x9f97 }, +/* 0x9f98 */ { false, 0x9f98, 0x9f98 }, +/* 0x9f99 */ { false, 0x9f99, 0x9f99 }, +/* 0x9f9a */ { false, 0x9f9a, 0x9f9a }, +/* 0x9f9b */ { false, 0x9f9b, 0x9f9b }, +/* 0x9f9c */ { false, 0x9f9c, 0x9f9c }, +/* 0x9f9d */ { false, 0x9f9d, 0x9f9d }, +/* 0x9f9e */ { false, 0x9f9e, 0x9f9e }, +/* 0x9f9f */ { false, 0x9f9f, 0x9f9f }, +/* 0x9fa0 */ { false, 0x9fa0, 0x9fa0 }, +/* 0x9fa1 */ { false, 0x9fa1, 0x9fa1 }, +/* 0x9fa2 */ { false, 0x9fa2, 0x9fa2 }, +/* 0x9fa3 */ { false, 0x9fa3, 0x9fa3 }, +/* 0x9fa4 */ { false, 0x9fa4, 0x9fa4 }, +/* 0x9fa5 */ { false, 0x9fa5, 0x9fa5 }, +/* 0x9fa6 */ { false, 0x9fa6, 0x9fa6 }, +/* 0x9fa7 */ { false, 0x9fa7, 0x9fa7 }, +/* 0x9fa8 */ { false, 0x9fa8, 0x9fa8 }, +/* 0x9fa9 */ { false, 0x9fa9, 0x9fa9 }, +/* 0x9faa */ { false, 0x9faa, 0x9faa }, +/* 0x9fab */ { false, 0x9fab, 0x9fab }, +/* 0x9fac */ { false, 0x9fac, 0x9fac }, +/* 0x9fad */ { false, 0x9fad, 0x9fad }, +/* 0x9fae */ { false, 0x9fae, 0x9fae }, +/* 0x9faf */ { false, 0x9faf, 0x9faf }, +/* 0x9fb0 */ { false, 0x9fb0, 0x9fb0 }, +/* 0x9fb1 */ { false, 0x9fb1, 0x9fb1 }, +/* 0x9fb2 */ { false, 0x9fb2, 0x9fb2 }, +/* 0x9fb3 */ { false, 0x9fb3, 0x9fb3 }, +/* 0x9fb4 */ { false, 0x9fb4, 0x9fb4 }, +/* 0x9fb5 */ { false, 0x9fb5, 0x9fb5 }, +/* 0x9fb6 */ { false, 0x9fb6, 0x9fb6 }, +/* 0x9fb7 */ { false, 0x9fb7, 0x9fb7 }, +/* 0x9fb8 */ { false, 0x9fb8, 0x9fb8 }, +/* 0x9fb9 */ { false, 0x9fb9, 0x9fb9 }, +/* 0x9fba */ { false, 0x9fba, 0x9fba }, +/* 0x9fbb */ { true, 0x9fbb, 0x9fbb }, +/* 0x9fbc */ { false, 0x9fbc, 0x9fbc }, +/* 0x9fbd */ { false, 0x9fbd, 0x9fbd }, +/* 0x9fbe */ { false, 0x9fbe, 0x9fbe }, +/* 0x9fbf */ { false, 0x9fbf, 0x9fbf }, +/* 0x9fc0 */ { false, 0x9fc0, 0x9fc0 }, +/* 0x9fc1 */ { false, 0x9fc1, 0x9fc1 }, +/* 0x9fc2 */ { false, 0x9fc2, 0x9fc2 }, +/* 0x9fc3 */ { false, 0x9fc3, 0x9fc3 }, +/* 0x9fc4 */ { false, 0x9fc4, 0x9fc4 }, +/* 0x9fc5 */ { false, 0x9fc5, 0x9fc5 }, +/* 0x9fc6 */ { false, 0x9fc6, 0x9fc6 }, +/* 0x9fc7 */ { false, 0x9fc7, 0x9fc7 }, +/* 0x9fc8 */ { false, 0x9fc8, 0x9fc8 }, +/* 0x9fc9 */ { false, 0x9fc9, 0x9fc9 }, +/* 0x9fca */ { false, 0x9fca, 0x9fca }, +/* 0x9fcb */ { false, 0x9fcb, 0x9fcb }, +/* 0x9fcc */ { false, 0x9fcc, 0x9fcc }, +/* 0x9fcd */ { false, 0x9fcd, 0x9fcd }, +/* 0x9fce */ { false, 0x9fce, 0x9fce }, +/* 0x9fcf */ { false, 0x9fcf, 0x9fcf }, +/* 0x9fd0 */ { false, 0x9fd0, 0x9fd0 }, +/* 0x9fd1 */ { false, 0x9fd1, 0x9fd1 }, +/* 0x9fd2 */ { false, 0x9fd2, 0x9fd2 }, +/* 0x9fd3 */ { false, 0x9fd3, 0x9fd3 }, +/* 0x9fd4 */ { false, 0x9fd4, 0x9fd4 }, +/* 0x9fd5 */ { false, 0x9fd5, 0x9fd5 }, +/* 0x9fd6 */ { false, 0x9fd6, 0x9fd6 }, +/* 0x9fd7 */ { false, 0x9fd7, 0x9fd7 }, +/* 0x9fd8 */ { false, 0x9fd8, 0x9fd8 }, +/* 0x9fd9 */ { false, 0x9fd9, 0x9fd9 }, +/* 0x9fda */ { false, 0x9fda, 0x9fda }, +/* 0x9fdb */ { false, 0x9fdb, 0x9fdb }, +/* 0x9fdc */ { false, 0x9fdc, 0x9fdc }, +/* 0x9fdd */ { false, 0x9fdd, 0x9fdd }, +/* 0x9fde */ { false, 0x9fde, 0x9fde }, +/* 0x9fdf */ { false, 0x9fdf, 0x9fdf }, +/* 0x9fe0 */ { false, 0x9fe0, 0x9fe0 }, +/* 0x9fe1 */ { false, 0x9fe1, 0x9fe1 }, +/* 0x9fe2 */ { false, 0x9fe2, 0x9fe2 }, +/* 0x9fe3 */ { false, 0x9fe3, 0x9fe3 }, +/* 0x9fe4 */ { false, 0x9fe4, 0x9fe4 }, +/* 0x9fe5 */ { false, 0x9fe5, 0x9fe5 }, +/* 0x9fe6 */ { false, 0x9fe6, 0x9fe6 }, +/* 0x9fe7 */ { false, 0x9fe7, 0x9fe7 }, +/* 0x9fe8 */ { false, 0x9fe8, 0x9fe8 }, +/* 0x9fe9 */ { false, 0x9fe9, 0x9fe9 }, +/* 0x9fea */ { false, 0x9fea, 0x9fea }, +/* 0x9feb */ { false, 0x9feb, 0x9feb }, +/* 0x9fec */ { false, 0x9fec, 0x9fec }, +/* 0x9fed */ { false, 0x9fed, 0x9fed }, +/* 0x9fee */ { false, 0x9fee, 0x9fee }, +/* 0x9fef */ { false, 0x9fef, 0x9fef }, +/* 0x9ff0 */ { false, 0x9ff0, 0x9ff0 }, +/* 0x9ff1 */ { false, 0x9ff1, 0x9ff1 }, +/* 0x9ff2 */ { false, 0x9ff2, 0x9ff2 }, +/* 0x9ff3 */ { false, 0x9ff3, 0x9ff3 }, +/* 0x9ff4 */ { false, 0x9ff4, 0x9ff4 }, +/* 0x9ff5 */ { false, 0x9ff5, 0x9ff5 }, +/* 0x9ff6 */ { false, 0x9ff6, 0x9ff6 }, +/* 0x9ff7 */ { false, 0x9ff7, 0x9ff7 }, +/* 0x9ff8 */ { false, 0x9ff8, 0x9ff8 }, +/* 0x9ff9 */ { false, 0x9ff9, 0x9ff9 }, +/* 0x9ffa */ { false, 0x9ffa, 0x9ffa }, +/* 0x9ffb */ { false, 0x9ffb, 0x9ffb }, +/* 0x9ffc */ { false, 0x9ffc, 0x9ffc }, +/* 0x9ffd */ { false, 0x9ffd, 0x9ffd }, +/* 0x9ffe */ { false, 0x9ffe, 0x9ffe }, +/* 0x9fff */ { false, 0x9fff, 0x9fff }, +/* 0xa000 */ { true, 0xa000, 0xa000 }, +/* 0xa001 */ { true, 0xa001, 0xa001 }, +/* 0xa002 */ { true, 0xa002, 0xa002 }, +/* 0xa003 */ { true, 0xa003, 0xa003 }, +/* 0xa004 */ { true, 0xa004, 0xa004 }, +/* 0xa005 */ { true, 0xa005, 0xa005 }, +/* 0xa006 */ { true, 0xa006, 0xa006 }, +/* 0xa007 */ { true, 0xa007, 0xa007 }, +/* 0xa008 */ { true, 0xa008, 0xa008 }, +/* 0xa009 */ { true, 0xa009, 0xa009 }, +/* 0xa00a */ { true, 0xa00a, 0xa00a }, +/* 0xa00b */ { true, 0xa00b, 0xa00b }, +/* 0xa00c */ { true, 0xa00c, 0xa00c }, +/* 0xa00d */ { true, 0xa00d, 0xa00d }, +/* 0xa00e */ { true, 0xa00e, 0xa00e }, +/* 0xa00f */ { true, 0xa00f, 0xa00f }, +/* 0xa010 */ { true, 0xa010, 0xa010 }, +/* 0xa011 */ { true, 0xa011, 0xa011 }, +/* 0xa012 */ { true, 0xa012, 0xa012 }, +/* 0xa013 */ { true, 0xa013, 0xa013 }, +/* 0xa014 */ { true, 0xa014, 0xa014 }, +/* 0xa015 */ { true, 0xa015, 0xa015 }, +/* 0xa016 */ { true, 0xa016, 0xa016 }, +/* 0xa017 */ { true, 0xa017, 0xa017 }, +/* 0xa018 */ { true, 0xa018, 0xa018 }, +/* 0xa019 */ { true, 0xa019, 0xa019 }, +/* 0xa01a */ { true, 0xa01a, 0xa01a }, +/* 0xa01b */ { true, 0xa01b, 0xa01b }, +/* 0xa01c */ { true, 0xa01c, 0xa01c }, +/* 0xa01d */ { true, 0xa01d, 0xa01d }, +/* 0xa01e */ { true, 0xa01e, 0xa01e }, +/* 0xa01f */ { true, 0xa01f, 0xa01f }, +/* 0xa020 */ { true, 0xa020, 0xa020 }, +/* 0xa021 */ { true, 0xa021, 0xa021 }, +/* 0xa022 */ { true, 0xa022, 0xa022 }, +/* 0xa023 */ { true, 0xa023, 0xa023 }, +/* 0xa024 */ { true, 0xa024, 0xa024 }, +/* 0xa025 */ { true, 0xa025, 0xa025 }, +/* 0xa026 */ { true, 0xa026, 0xa026 }, +/* 0xa027 */ { true, 0xa027, 0xa027 }, +/* 0xa028 */ { true, 0xa028, 0xa028 }, +/* 0xa029 */ { true, 0xa029, 0xa029 }, +/* 0xa02a */ { true, 0xa02a, 0xa02a }, +/* 0xa02b */ { true, 0xa02b, 0xa02b }, +/* 0xa02c */ { true, 0xa02c, 0xa02c }, +/* 0xa02d */ { true, 0xa02d, 0xa02d }, +/* 0xa02e */ { true, 0xa02e, 0xa02e }, +/* 0xa02f */ { true, 0xa02f, 0xa02f }, +/* 0xa030 */ { true, 0xa030, 0xa030 }, +/* 0xa031 */ { true, 0xa031, 0xa031 }, +/* 0xa032 */ { true, 0xa032, 0xa032 }, +/* 0xa033 */ { true, 0xa033, 0xa033 }, +/* 0xa034 */ { true, 0xa034, 0xa034 }, +/* 0xa035 */ { true, 0xa035, 0xa035 }, +/* 0xa036 */ { true, 0xa036, 0xa036 }, +/* 0xa037 */ { true, 0xa037, 0xa037 }, +/* 0xa038 */ { true, 0xa038, 0xa038 }, +/* 0xa039 */ { true, 0xa039, 0xa039 }, +/* 0xa03a */ { true, 0xa03a, 0xa03a }, +/* 0xa03b */ { true, 0xa03b, 0xa03b }, +/* 0xa03c */ { true, 0xa03c, 0xa03c }, +/* 0xa03d */ { true, 0xa03d, 0xa03d }, +/* 0xa03e */ { true, 0xa03e, 0xa03e }, +/* 0xa03f */ { true, 0xa03f, 0xa03f }, +/* 0xa040 */ { true, 0xa040, 0xa040 }, +/* 0xa041 */ { true, 0xa041, 0xa041 }, +/* 0xa042 */ { true, 0xa042, 0xa042 }, +/* 0xa043 */ { true, 0xa043, 0xa043 }, +/* 0xa044 */ { true, 0xa044, 0xa044 }, +/* 0xa045 */ { true, 0xa045, 0xa045 }, +/* 0xa046 */ { true, 0xa046, 0xa046 }, +/* 0xa047 */ { true, 0xa047, 0xa047 }, +/* 0xa048 */ { true, 0xa048, 0xa048 }, +/* 0xa049 */ { true, 0xa049, 0xa049 }, +/* 0xa04a */ { true, 0xa04a, 0xa04a }, +/* 0xa04b */ { true, 0xa04b, 0xa04b }, +/* 0xa04c */ { true, 0xa04c, 0xa04c }, +/* 0xa04d */ { true, 0xa04d, 0xa04d }, +/* 0xa04e */ { true, 0xa04e, 0xa04e }, +/* 0xa04f */ { true, 0xa04f, 0xa04f }, +/* 0xa050 */ { true, 0xa050, 0xa050 }, +/* 0xa051 */ { true, 0xa051, 0xa051 }, +/* 0xa052 */ { true, 0xa052, 0xa052 }, +/* 0xa053 */ { true, 0xa053, 0xa053 }, +/* 0xa054 */ { true, 0xa054, 0xa054 }, +/* 0xa055 */ { true, 0xa055, 0xa055 }, +/* 0xa056 */ { true, 0xa056, 0xa056 }, +/* 0xa057 */ { true, 0xa057, 0xa057 }, +/* 0xa058 */ { true, 0xa058, 0xa058 }, +/* 0xa059 */ { true, 0xa059, 0xa059 }, +/* 0xa05a */ { true, 0xa05a, 0xa05a }, +/* 0xa05b */ { true, 0xa05b, 0xa05b }, +/* 0xa05c */ { true, 0xa05c, 0xa05c }, +/* 0xa05d */ { true, 0xa05d, 0xa05d }, +/* 0xa05e */ { true, 0xa05e, 0xa05e }, +/* 0xa05f */ { true, 0xa05f, 0xa05f }, +/* 0xa060 */ { true, 0xa060, 0xa060 }, +/* 0xa061 */ { true, 0xa061, 0xa061 }, +/* 0xa062 */ { true, 0xa062, 0xa062 }, +/* 0xa063 */ { true, 0xa063, 0xa063 }, +/* 0xa064 */ { true, 0xa064, 0xa064 }, +/* 0xa065 */ { true, 0xa065, 0xa065 }, +/* 0xa066 */ { true, 0xa066, 0xa066 }, +/* 0xa067 */ { true, 0xa067, 0xa067 }, +/* 0xa068 */ { true, 0xa068, 0xa068 }, +/* 0xa069 */ { true, 0xa069, 0xa069 }, +/* 0xa06a */ { true, 0xa06a, 0xa06a }, +/* 0xa06b */ { true, 0xa06b, 0xa06b }, +/* 0xa06c */ { true, 0xa06c, 0xa06c }, +/* 0xa06d */ { true, 0xa06d, 0xa06d }, +/* 0xa06e */ { true, 0xa06e, 0xa06e }, +/* 0xa06f */ { true, 0xa06f, 0xa06f }, +/* 0xa070 */ { true, 0xa070, 0xa070 }, +/* 0xa071 */ { true, 0xa071, 0xa071 }, +/* 0xa072 */ { true, 0xa072, 0xa072 }, +/* 0xa073 */ { true, 0xa073, 0xa073 }, +/* 0xa074 */ { true, 0xa074, 0xa074 }, +/* 0xa075 */ { true, 0xa075, 0xa075 }, +/* 0xa076 */ { true, 0xa076, 0xa076 }, +/* 0xa077 */ { true, 0xa077, 0xa077 }, +/* 0xa078 */ { true, 0xa078, 0xa078 }, +/* 0xa079 */ { true, 0xa079, 0xa079 }, +/* 0xa07a */ { true, 0xa07a, 0xa07a }, +/* 0xa07b */ { true, 0xa07b, 0xa07b }, +/* 0xa07c */ { true, 0xa07c, 0xa07c }, +/* 0xa07d */ { true, 0xa07d, 0xa07d }, +/* 0xa07e */ { true, 0xa07e, 0xa07e }, +/* 0xa07f */ { true, 0xa07f, 0xa07f }, +/* 0xa080 */ { true, 0xa080, 0xa080 }, +/* 0xa081 */ { true, 0xa081, 0xa081 }, +/* 0xa082 */ { true, 0xa082, 0xa082 }, +/* 0xa083 */ { true, 0xa083, 0xa083 }, +/* 0xa084 */ { true, 0xa084, 0xa084 }, +/* 0xa085 */ { true, 0xa085, 0xa085 }, +/* 0xa086 */ { true, 0xa086, 0xa086 }, +/* 0xa087 */ { true, 0xa087, 0xa087 }, +/* 0xa088 */ { true, 0xa088, 0xa088 }, +/* 0xa089 */ { true, 0xa089, 0xa089 }, +/* 0xa08a */ { true, 0xa08a, 0xa08a }, +/* 0xa08b */ { true, 0xa08b, 0xa08b }, +/* 0xa08c */ { true, 0xa08c, 0xa08c }, +/* 0xa08d */ { true, 0xa08d, 0xa08d }, +/* 0xa08e */ { true, 0xa08e, 0xa08e }, +/* 0xa08f */ { true, 0xa08f, 0xa08f }, +/* 0xa090 */ { true, 0xa090, 0xa090 }, +/* 0xa091 */ { true, 0xa091, 0xa091 }, +/* 0xa092 */ { true, 0xa092, 0xa092 }, +/* 0xa093 */ { true, 0xa093, 0xa093 }, +/* 0xa094 */ { true, 0xa094, 0xa094 }, +/* 0xa095 */ { true, 0xa095, 0xa095 }, +/* 0xa096 */ { true, 0xa096, 0xa096 }, +/* 0xa097 */ { true, 0xa097, 0xa097 }, +/* 0xa098 */ { true, 0xa098, 0xa098 }, +/* 0xa099 */ { true, 0xa099, 0xa099 }, +/* 0xa09a */ { true, 0xa09a, 0xa09a }, +/* 0xa09b */ { true, 0xa09b, 0xa09b }, +/* 0xa09c */ { true, 0xa09c, 0xa09c }, +/* 0xa09d */ { true, 0xa09d, 0xa09d }, +/* 0xa09e */ { true, 0xa09e, 0xa09e }, +/* 0xa09f */ { true, 0xa09f, 0xa09f }, +/* 0xa0a0 */ { true, 0xa0a0, 0xa0a0 }, +/* 0xa0a1 */ { true, 0xa0a1, 0xa0a1 }, +/* 0xa0a2 */ { true, 0xa0a2, 0xa0a2 }, +/* 0xa0a3 */ { true, 0xa0a3, 0xa0a3 }, +/* 0xa0a4 */ { true, 0xa0a4, 0xa0a4 }, +/* 0xa0a5 */ { true, 0xa0a5, 0xa0a5 }, +/* 0xa0a6 */ { true, 0xa0a6, 0xa0a6 }, +/* 0xa0a7 */ { true, 0xa0a7, 0xa0a7 }, +/* 0xa0a8 */ { true, 0xa0a8, 0xa0a8 }, +/* 0xa0a9 */ { true, 0xa0a9, 0xa0a9 }, +/* 0xa0aa */ { true, 0xa0aa, 0xa0aa }, +/* 0xa0ab */ { true, 0xa0ab, 0xa0ab }, +/* 0xa0ac */ { true, 0xa0ac, 0xa0ac }, +/* 0xa0ad */ { true, 0xa0ad, 0xa0ad }, +/* 0xa0ae */ { true, 0xa0ae, 0xa0ae }, +/* 0xa0af */ { true, 0xa0af, 0xa0af }, +/* 0xa0b0 */ { true, 0xa0b0, 0xa0b0 }, +/* 0xa0b1 */ { true, 0xa0b1, 0xa0b1 }, +/* 0xa0b2 */ { true, 0xa0b2, 0xa0b2 }, +/* 0xa0b3 */ { true, 0xa0b3, 0xa0b3 }, +/* 0xa0b4 */ { true, 0xa0b4, 0xa0b4 }, +/* 0xa0b5 */ { true, 0xa0b5, 0xa0b5 }, +/* 0xa0b6 */ { true, 0xa0b6, 0xa0b6 }, +/* 0xa0b7 */ { true, 0xa0b7, 0xa0b7 }, +/* 0xa0b8 */ { true, 0xa0b8, 0xa0b8 }, +/* 0xa0b9 */ { true, 0xa0b9, 0xa0b9 }, +/* 0xa0ba */ { true, 0xa0ba, 0xa0ba }, +/* 0xa0bb */ { true, 0xa0bb, 0xa0bb }, +/* 0xa0bc */ { true, 0xa0bc, 0xa0bc }, +/* 0xa0bd */ { true, 0xa0bd, 0xa0bd }, +/* 0xa0be */ { true, 0xa0be, 0xa0be }, +/* 0xa0bf */ { true, 0xa0bf, 0xa0bf }, +/* 0xa0c0 */ { true, 0xa0c0, 0xa0c0 }, +/* 0xa0c1 */ { true, 0xa0c1, 0xa0c1 }, +/* 0xa0c2 */ { true, 0xa0c2, 0xa0c2 }, +/* 0xa0c3 */ { true, 0xa0c3, 0xa0c3 }, +/* 0xa0c4 */ { true, 0xa0c4, 0xa0c4 }, +/* 0xa0c5 */ { true, 0xa0c5, 0xa0c5 }, +/* 0xa0c6 */ { true, 0xa0c6, 0xa0c6 }, +/* 0xa0c7 */ { true, 0xa0c7, 0xa0c7 }, +/* 0xa0c8 */ { true, 0xa0c8, 0xa0c8 }, +/* 0xa0c9 */ { true, 0xa0c9, 0xa0c9 }, +/* 0xa0ca */ { true, 0xa0ca, 0xa0ca }, +/* 0xa0cb */ { true, 0xa0cb, 0xa0cb }, +/* 0xa0cc */ { true, 0xa0cc, 0xa0cc }, +/* 0xa0cd */ { true, 0xa0cd, 0xa0cd }, +/* 0xa0ce */ { true, 0xa0ce, 0xa0ce }, +/* 0xa0cf */ { true, 0xa0cf, 0xa0cf }, +/* 0xa0d0 */ { true, 0xa0d0, 0xa0d0 }, +/* 0xa0d1 */ { true, 0xa0d1, 0xa0d1 }, +/* 0xa0d2 */ { true, 0xa0d2, 0xa0d2 }, +/* 0xa0d3 */ { true, 0xa0d3, 0xa0d3 }, +/* 0xa0d4 */ { true, 0xa0d4, 0xa0d4 }, +/* 0xa0d5 */ { true, 0xa0d5, 0xa0d5 }, +/* 0xa0d6 */ { true, 0xa0d6, 0xa0d6 }, +/* 0xa0d7 */ { true, 0xa0d7, 0xa0d7 }, +/* 0xa0d8 */ { true, 0xa0d8, 0xa0d8 }, +/* 0xa0d9 */ { true, 0xa0d9, 0xa0d9 }, +/* 0xa0da */ { true, 0xa0da, 0xa0da }, +/* 0xa0db */ { true, 0xa0db, 0xa0db }, +/* 0xa0dc */ { true, 0xa0dc, 0xa0dc }, +/* 0xa0dd */ { true, 0xa0dd, 0xa0dd }, +/* 0xa0de */ { true, 0xa0de, 0xa0de }, +/* 0xa0df */ { true, 0xa0df, 0xa0df }, +/* 0xa0e0 */ { true, 0xa0e0, 0xa0e0 }, +/* 0xa0e1 */ { true, 0xa0e1, 0xa0e1 }, +/* 0xa0e2 */ { true, 0xa0e2, 0xa0e2 }, +/* 0xa0e3 */ { true, 0xa0e3, 0xa0e3 }, +/* 0xa0e4 */ { true, 0xa0e4, 0xa0e4 }, +/* 0xa0e5 */ { true, 0xa0e5, 0xa0e5 }, +/* 0xa0e6 */ { true, 0xa0e6, 0xa0e6 }, +/* 0xa0e7 */ { true, 0xa0e7, 0xa0e7 }, +/* 0xa0e8 */ { true, 0xa0e8, 0xa0e8 }, +/* 0xa0e9 */ { true, 0xa0e9, 0xa0e9 }, +/* 0xa0ea */ { true, 0xa0ea, 0xa0ea }, +/* 0xa0eb */ { true, 0xa0eb, 0xa0eb }, +/* 0xa0ec */ { true, 0xa0ec, 0xa0ec }, +/* 0xa0ed */ { true, 0xa0ed, 0xa0ed }, +/* 0xa0ee */ { true, 0xa0ee, 0xa0ee }, +/* 0xa0ef */ { true, 0xa0ef, 0xa0ef }, +/* 0xa0f0 */ { true, 0xa0f0, 0xa0f0 }, +/* 0xa0f1 */ { true, 0xa0f1, 0xa0f1 }, +/* 0xa0f2 */ { true, 0xa0f2, 0xa0f2 }, +/* 0xa0f3 */ { true, 0xa0f3, 0xa0f3 }, +/* 0xa0f4 */ { true, 0xa0f4, 0xa0f4 }, +/* 0xa0f5 */ { true, 0xa0f5, 0xa0f5 }, +/* 0xa0f6 */ { true, 0xa0f6, 0xa0f6 }, +/* 0xa0f7 */ { true, 0xa0f7, 0xa0f7 }, +/* 0xa0f8 */ { true, 0xa0f8, 0xa0f8 }, +/* 0xa0f9 */ { true, 0xa0f9, 0xa0f9 }, +/* 0xa0fa */ { true, 0xa0fa, 0xa0fa }, +/* 0xa0fb */ { true, 0xa0fb, 0xa0fb }, +/* 0xa0fc */ { true, 0xa0fc, 0xa0fc }, +/* 0xa0fd */ { true, 0xa0fd, 0xa0fd }, +/* 0xa0fe */ { true, 0xa0fe, 0xa0fe }, +/* 0xa0ff */ { true, 0xa0ff, 0xa0ff }, +/* 0xa100 */ { true, 0xa100, 0xa100 }, +/* 0xa101 */ { true, 0xa101, 0xa101 }, +/* 0xa102 */ { true, 0xa102, 0xa102 }, +/* 0xa103 */ { true, 0xa103, 0xa103 }, +/* 0xa104 */ { true, 0xa104, 0xa104 }, +/* 0xa105 */ { true, 0xa105, 0xa105 }, +/* 0xa106 */ { true, 0xa106, 0xa106 }, +/* 0xa107 */ { true, 0xa107, 0xa107 }, +/* 0xa108 */ { true, 0xa108, 0xa108 }, +/* 0xa109 */ { true, 0xa109, 0xa109 }, +/* 0xa10a */ { true, 0xa10a, 0xa10a }, +/* 0xa10b */ { true, 0xa10b, 0xa10b }, +/* 0xa10c */ { true, 0xa10c, 0xa10c }, +/* 0xa10d */ { true, 0xa10d, 0xa10d }, +/* 0xa10e */ { true, 0xa10e, 0xa10e }, +/* 0xa10f */ { true, 0xa10f, 0xa10f }, +/* 0xa110 */ { true, 0xa110, 0xa110 }, +/* 0xa111 */ { true, 0xa111, 0xa111 }, +/* 0xa112 */ { true, 0xa112, 0xa112 }, +/* 0xa113 */ { true, 0xa113, 0xa113 }, +/* 0xa114 */ { true, 0xa114, 0xa114 }, +/* 0xa115 */ { true, 0xa115, 0xa115 }, +/* 0xa116 */ { true, 0xa116, 0xa116 }, +/* 0xa117 */ { true, 0xa117, 0xa117 }, +/* 0xa118 */ { true, 0xa118, 0xa118 }, +/* 0xa119 */ { true, 0xa119, 0xa119 }, +/* 0xa11a */ { true, 0xa11a, 0xa11a }, +/* 0xa11b */ { true, 0xa11b, 0xa11b }, +/* 0xa11c */ { true, 0xa11c, 0xa11c }, +/* 0xa11d */ { true, 0xa11d, 0xa11d }, +/* 0xa11e */ { true, 0xa11e, 0xa11e }, +/* 0xa11f */ { true, 0xa11f, 0xa11f }, +/* 0xa120 */ { true, 0xa120, 0xa120 }, +/* 0xa121 */ { true, 0xa121, 0xa121 }, +/* 0xa122 */ { true, 0xa122, 0xa122 }, +/* 0xa123 */ { true, 0xa123, 0xa123 }, +/* 0xa124 */ { true, 0xa124, 0xa124 }, +/* 0xa125 */ { true, 0xa125, 0xa125 }, +/* 0xa126 */ { true, 0xa126, 0xa126 }, +/* 0xa127 */ { true, 0xa127, 0xa127 }, +/* 0xa128 */ { true, 0xa128, 0xa128 }, +/* 0xa129 */ { true, 0xa129, 0xa129 }, +/* 0xa12a */ { true, 0xa12a, 0xa12a }, +/* 0xa12b */ { true, 0xa12b, 0xa12b }, +/* 0xa12c */ { true, 0xa12c, 0xa12c }, +/* 0xa12d */ { true, 0xa12d, 0xa12d }, +/* 0xa12e */ { true, 0xa12e, 0xa12e }, +/* 0xa12f */ { true, 0xa12f, 0xa12f }, +/* 0xa130 */ { true, 0xa130, 0xa130 }, +/* 0xa131 */ { true, 0xa131, 0xa131 }, +/* 0xa132 */ { true, 0xa132, 0xa132 }, +/* 0xa133 */ { true, 0xa133, 0xa133 }, +/* 0xa134 */ { true, 0xa134, 0xa134 }, +/* 0xa135 */ { true, 0xa135, 0xa135 }, +/* 0xa136 */ { true, 0xa136, 0xa136 }, +/* 0xa137 */ { true, 0xa137, 0xa137 }, +/* 0xa138 */ { true, 0xa138, 0xa138 }, +/* 0xa139 */ { true, 0xa139, 0xa139 }, +/* 0xa13a */ { true, 0xa13a, 0xa13a }, +/* 0xa13b */ { true, 0xa13b, 0xa13b }, +/* 0xa13c */ { true, 0xa13c, 0xa13c }, +/* 0xa13d */ { true, 0xa13d, 0xa13d }, +/* 0xa13e */ { true, 0xa13e, 0xa13e }, +/* 0xa13f */ { true, 0xa13f, 0xa13f }, +/* 0xa140 */ { true, 0xa140, 0xa140 }, +/* 0xa141 */ { true, 0xa141, 0xa141 }, +/* 0xa142 */ { true, 0xa142, 0xa142 }, +/* 0xa143 */ { true, 0xa143, 0xa143 }, +/* 0xa144 */ { true, 0xa144, 0xa144 }, +/* 0xa145 */ { true, 0xa145, 0xa145 }, +/* 0xa146 */ { true, 0xa146, 0xa146 }, +/* 0xa147 */ { true, 0xa147, 0xa147 }, +/* 0xa148 */ { true, 0xa148, 0xa148 }, +/* 0xa149 */ { true, 0xa149, 0xa149 }, +/* 0xa14a */ { true, 0xa14a, 0xa14a }, +/* 0xa14b */ { true, 0xa14b, 0xa14b }, +/* 0xa14c */ { true, 0xa14c, 0xa14c }, +/* 0xa14d */ { true, 0xa14d, 0xa14d }, +/* 0xa14e */ { true, 0xa14e, 0xa14e }, +/* 0xa14f */ { true, 0xa14f, 0xa14f }, +/* 0xa150 */ { true, 0xa150, 0xa150 }, +/* 0xa151 */ { true, 0xa151, 0xa151 }, +/* 0xa152 */ { true, 0xa152, 0xa152 }, +/* 0xa153 */ { true, 0xa153, 0xa153 }, +/* 0xa154 */ { true, 0xa154, 0xa154 }, +/* 0xa155 */ { true, 0xa155, 0xa155 }, +/* 0xa156 */ { true, 0xa156, 0xa156 }, +/* 0xa157 */ { true, 0xa157, 0xa157 }, +/* 0xa158 */ { true, 0xa158, 0xa158 }, +/* 0xa159 */ { true, 0xa159, 0xa159 }, +/* 0xa15a */ { true, 0xa15a, 0xa15a }, +/* 0xa15b */ { true, 0xa15b, 0xa15b }, +/* 0xa15c */ { true, 0xa15c, 0xa15c }, +/* 0xa15d */ { true, 0xa15d, 0xa15d }, +/* 0xa15e */ { true, 0xa15e, 0xa15e }, +/* 0xa15f */ { true, 0xa15f, 0xa15f }, +/* 0xa160 */ { true, 0xa160, 0xa160 }, +/* 0xa161 */ { true, 0xa161, 0xa161 }, +/* 0xa162 */ { true, 0xa162, 0xa162 }, +/* 0xa163 */ { true, 0xa163, 0xa163 }, +/* 0xa164 */ { true, 0xa164, 0xa164 }, +/* 0xa165 */ { true, 0xa165, 0xa165 }, +/* 0xa166 */ { true, 0xa166, 0xa166 }, +/* 0xa167 */ { true, 0xa167, 0xa167 }, +/* 0xa168 */ { true, 0xa168, 0xa168 }, +/* 0xa169 */ { true, 0xa169, 0xa169 }, +/* 0xa16a */ { true, 0xa16a, 0xa16a }, +/* 0xa16b */ { true, 0xa16b, 0xa16b }, +/* 0xa16c */ { true, 0xa16c, 0xa16c }, +/* 0xa16d */ { true, 0xa16d, 0xa16d }, +/* 0xa16e */ { true, 0xa16e, 0xa16e }, +/* 0xa16f */ { true, 0xa16f, 0xa16f }, +/* 0xa170 */ { true, 0xa170, 0xa170 }, +/* 0xa171 */ { true, 0xa171, 0xa171 }, +/* 0xa172 */ { true, 0xa172, 0xa172 }, +/* 0xa173 */ { true, 0xa173, 0xa173 }, +/* 0xa174 */ { true, 0xa174, 0xa174 }, +/* 0xa175 */ { true, 0xa175, 0xa175 }, +/* 0xa176 */ { true, 0xa176, 0xa176 }, +/* 0xa177 */ { true, 0xa177, 0xa177 }, +/* 0xa178 */ { true, 0xa178, 0xa178 }, +/* 0xa179 */ { true, 0xa179, 0xa179 }, +/* 0xa17a */ { true, 0xa17a, 0xa17a }, +/* 0xa17b */ { true, 0xa17b, 0xa17b }, +/* 0xa17c */ { true, 0xa17c, 0xa17c }, +/* 0xa17d */ { true, 0xa17d, 0xa17d }, +/* 0xa17e */ { true, 0xa17e, 0xa17e }, +/* 0xa17f */ { true, 0xa17f, 0xa17f }, +/* 0xa180 */ { true, 0xa180, 0xa180 }, +/* 0xa181 */ { true, 0xa181, 0xa181 }, +/* 0xa182 */ { true, 0xa182, 0xa182 }, +/* 0xa183 */ { true, 0xa183, 0xa183 }, +/* 0xa184 */ { true, 0xa184, 0xa184 }, +/* 0xa185 */ { true, 0xa185, 0xa185 }, +/* 0xa186 */ { true, 0xa186, 0xa186 }, +/* 0xa187 */ { true, 0xa187, 0xa187 }, +/* 0xa188 */ { true, 0xa188, 0xa188 }, +/* 0xa189 */ { true, 0xa189, 0xa189 }, +/* 0xa18a */ { true, 0xa18a, 0xa18a }, +/* 0xa18b */ { true, 0xa18b, 0xa18b }, +/* 0xa18c */ { true, 0xa18c, 0xa18c }, +/* 0xa18d */ { true, 0xa18d, 0xa18d }, +/* 0xa18e */ { true, 0xa18e, 0xa18e }, +/* 0xa18f */ { true, 0xa18f, 0xa18f }, +/* 0xa190 */ { true, 0xa190, 0xa190 }, +/* 0xa191 */ { true, 0xa191, 0xa191 }, +/* 0xa192 */ { true, 0xa192, 0xa192 }, +/* 0xa193 */ { true, 0xa193, 0xa193 }, +/* 0xa194 */ { true, 0xa194, 0xa194 }, +/* 0xa195 */ { true, 0xa195, 0xa195 }, +/* 0xa196 */ { true, 0xa196, 0xa196 }, +/* 0xa197 */ { true, 0xa197, 0xa197 }, +/* 0xa198 */ { true, 0xa198, 0xa198 }, +/* 0xa199 */ { true, 0xa199, 0xa199 }, +/* 0xa19a */ { true, 0xa19a, 0xa19a }, +/* 0xa19b */ { true, 0xa19b, 0xa19b }, +/* 0xa19c */ { true, 0xa19c, 0xa19c }, +/* 0xa19d */ { true, 0xa19d, 0xa19d }, +/* 0xa19e */ { true, 0xa19e, 0xa19e }, +/* 0xa19f */ { true, 0xa19f, 0xa19f }, +/* 0xa1a0 */ { true, 0xa1a0, 0xa1a0 }, +/* 0xa1a1 */ { true, 0xa1a1, 0xa1a1 }, +/* 0xa1a2 */ { true, 0xa1a2, 0xa1a2 }, +/* 0xa1a3 */ { true, 0xa1a3, 0xa1a3 }, +/* 0xa1a4 */ { true, 0xa1a4, 0xa1a4 }, +/* 0xa1a5 */ { true, 0xa1a5, 0xa1a5 }, +/* 0xa1a6 */ { true, 0xa1a6, 0xa1a6 }, +/* 0xa1a7 */ { true, 0xa1a7, 0xa1a7 }, +/* 0xa1a8 */ { true, 0xa1a8, 0xa1a8 }, +/* 0xa1a9 */ { true, 0xa1a9, 0xa1a9 }, +/* 0xa1aa */ { true, 0xa1aa, 0xa1aa }, +/* 0xa1ab */ { true, 0xa1ab, 0xa1ab }, +/* 0xa1ac */ { true, 0xa1ac, 0xa1ac }, +/* 0xa1ad */ { true, 0xa1ad, 0xa1ad }, +/* 0xa1ae */ { true, 0xa1ae, 0xa1ae }, +/* 0xa1af */ { true, 0xa1af, 0xa1af }, +/* 0xa1b0 */ { true, 0xa1b0, 0xa1b0 }, +/* 0xa1b1 */ { true, 0xa1b1, 0xa1b1 }, +/* 0xa1b2 */ { true, 0xa1b2, 0xa1b2 }, +/* 0xa1b3 */ { true, 0xa1b3, 0xa1b3 }, +/* 0xa1b4 */ { true, 0xa1b4, 0xa1b4 }, +/* 0xa1b5 */ { true, 0xa1b5, 0xa1b5 }, +/* 0xa1b6 */ { true, 0xa1b6, 0xa1b6 }, +/* 0xa1b7 */ { true, 0xa1b7, 0xa1b7 }, +/* 0xa1b8 */ { true, 0xa1b8, 0xa1b8 }, +/* 0xa1b9 */ { true, 0xa1b9, 0xa1b9 }, +/* 0xa1ba */ { true, 0xa1ba, 0xa1ba }, +/* 0xa1bb */ { true, 0xa1bb, 0xa1bb }, +/* 0xa1bc */ { true, 0xa1bc, 0xa1bc }, +/* 0xa1bd */ { true, 0xa1bd, 0xa1bd }, +/* 0xa1be */ { true, 0xa1be, 0xa1be }, +/* 0xa1bf */ { true, 0xa1bf, 0xa1bf }, +/* 0xa1c0 */ { true, 0xa1c0, 0xa1c0 }, +/* 0xa1c1 */ { true, 0xa1c1, 0xa1c1 }, +/* 0xa1c2 */ { true, 0xa1c2, 0xa1c2 }, +/* 0xa1c3 */ { true, 0xa1c3, 0xa1c3 }, +/* 0xa1c4 */ { true, 0xa1c4, 0xa1c4 }, +/* 0xa1c5 */ { true, 0xa1c5, 0xa1c5 }, +/* 0xa1c6 */ { true, 0xa1c6, 0xa1c6 }, +/* 0xa1c7 */ { true, 0xa1c7, 0xa1c7 }, +/* 0xa1c8 */ { true, 0xa1c8, 0xa1c8 }, +/* 0xa1c9 */ { true, 0xa1c9, 0xa1c9 }, +/* 0xa1ca */ { true, 0xa1ca, 0xa1ca }, +/* 0xa1cb */ { true, 0xa1cb, 0xa1cb }, +/* 0xa1cc */ { true, 0xa1cc, 0xa1cc }, +/* 0xa1cd */ { true, 0xa1cd, 0xa1cd }, +/* 0xa1ce */ { true, 0xa1ce, 0xa1ce }, +/* 0xa1cf */ { true, 0xa1cf, 0xa1cf }, +/* 0xa1d0 */ { true, 0xa1d0, 0xa1d0 }, +/* 0xa1d1 */ { true, 0xa1d1, 0xa1d1 }, +/* 0xa1d2 */ { true, 0xa1d2, 0xa1d2 }, +/* 0xa1d3 */ { true, 0xa1d3, 0xa1d3 }, +/* 0xa1d4 */ { true, 0xa1d4, 0xa1d4 }, +/* 0xa1d5 */ { true, 0xa1d5, 0xa1d5 }, +/* 0xa1d6 */ { true, 0xa1d6, 0xa1d6 }, +/* 0xa1d7 */ { true, 0xa1d7, 0xa1d7 }, +/* 0xa1d8 */ { true, 0xa1d8, 0xa1d8 }, +/* 0xa1d9 */ { true, 0xa1d9, 0xa1d9 }, +/* 0xa1da */ { true, 0xa1da, 0xa1da }, +/* 0xa1db */ { true, 0xa1db, 0xa1db }, +/* 0xa1dc */ { true, 0xa1dc, 0xa1dc }, +/* 0xa1dd */ { true, 0xa1dd, 0xa1dd }, +/* 0xa1de */ { true, 0xa1de, 0xa1de }, +/* 0xa1df */ { true, 0xa1df, 0xa1df }, +/* 0xa1e0 */ { true, 0xa1e0, 0xa1e0 }, +/* 0xa1e1 */ { true, 0xa1e1, 0xa1e1 }, +/* 0xa1e2 */ { true, 0xa1e2, 0xa1e2 }, +/* 0xa1e3 */ { true, 0xa1e3, 0xa1e3 }, +/* 0xa1e4 */ { true, 0xa1e4, 0xa1e4 }, +/* 0xa1e5 */ { true, 0xa1e5, 0xa1e5 }, +/* 0xa1e6 */ { true, 0xa1e6, 0xa1e6 }, +/* 0xa1e7 */ { true, 0xa1e7, 0xa1e7 }, +/* 0xa1e8 */ { true, 0xa1e8, 0xa1e8 }, +/* 0xa1e9 */ { true, 0xa1e9, 0xa1e9 }, +/* 0xa1ea */ { true, 0xa1ea, 0xa1ea }, +/* 0xa1eb */ { true, 0xa1eb, 0xa1eb }, +/* 0xa1ec */ { true, 0xa1ec, 0xa1ec }, +/* 0xa1ed */ { true, 0xa1ed, 0xa1ed }, +/* 0xa1ee */ { true, 0xa1ee, 0xa1ee }, +/* 0xa1ef */ { true, 0xa1ef, 0xa1ef }, +/* 0xa1f0 */ { true, 0xa1f0, 0xa1f0 }, +/* 0xa1f1 */ { true, 0xa1f1, 0xa1f1 }, +/* 0xa1f2 */ { true, 0xa1f2, 0xa1f2 }, +/* 0xa1f3 */ { true, 0xa1f3, 0xa1f3 }, +/* 0xa1f4 */ { true, 0xa1f4, 0xa1f4 }, +/* 0xa1f5 */ { true, 0xa1f5, 0xa1f5 }, +/* 0xa1f6 */ { true, 0xa1f6, 0xa1f6 }, +/* 0xa1f7 */ { true, 0xa1f7, 0xa1f7 }, +/* 0xa1f8 */ { true, 0xa1f8, 0xa1f8 }, +/* 0xa1f9 */ { true, 0xa1f9, 0xa1f9 }, +/* 0xa1fa */ { true, 0xa1fa, 0xa1fa }, +/* 0xa1fb */ { true, 0xa1fb, 0xa1fb }, +/* 0xa1fc */ { true, 0xa1fc, 0xa1fc }, +/* 0xa1fd */ { true, 0xa1fd, 0xa1fd }, +/* 0xa1fe */ { true, 0xa1fe, 0xa1fe }, +/* 0xa1ff */ { true, 0xa1ff, 0xa1ff }, +/* 0xa200 */ { true, 0xa200, 0xa200 }, +/* 0xa201 */ { true, 0xa201, 0xa201 }, +/* 0xa202 */ { true, 0xa202, 0xa202 }, +/* 0xa203 */ { true, 0xa203, 0xa203 }, +/* 0xa204 */ { true, 0xa204, 0xa204 }, +/* 0xa205 */ { true, 0xa205, 0xa205 }, +/* 0xa206 */ { true, 0xa206, 0xa206 }, +/* 0xa207 */ { true, 0xa207, 0xa207 }, +/* 0xa208 */ { true, 0xa208, 0xa208 }, +/* 0xa209 */ { true, 0xa209, 0xa209 }, +/* 0xa20a */ { true, 0xa20a, 0xa20a }, +/* 0xa20b */ { true, 0xa20b, 0xa20b }, +/* 0xa20c */ { true, 0xa20c, 0xa20c }, +/* 0xa20d */ { true, 0xa20d, 0xa20d }, +/* 0xa20e */ { true, 0xa20e, 0xa20e }, +/* 0xa20f */ { true, 0xa20f, 0xa20f }, +/* 0xa210 */ { true, 0xa210, 0xa210 }, +/* 0xa211 */ { true, 0xa211, 0xa211 }, +/* 0xa212 */ { true, 0xa212, 0xa212 }, +/* 0xa213 */ { true, 0xa213, 0xa213 }, +/* 0xa214 */ { true, 0xa214, 0xa214 }, +/* 0xa215 */ { true, 0xa215, 0xa215 }, +/* 0xa216 */ { true, 0xa216, 0xa216 }, +/* 0xa217 */ { true, 0xa217, 0xa217 }, +/* 0xa218 */ { true, 0xa218, 0xa218 }, +/* 0xa219 */ { true, 0xa219, 0xa219 }, +/* 0xa21a */ { true, 0xa21a, 0xa21a }, +/* 0xa21b */ { true, 0xa21b, 0xa21b }, +/* 0xa21c */ { true, 0xa21c, 0xa21c }, +/* 0xa21d */ { true, 0xa21d, 0xa21d }, +/* 0xa21e */ { true, 0xa21e, 0xa21e }, +/* 0xa21f */ { true, 0xa21f, 0xa21f }, +/* 0xa220 */ { true, 0xa220, 0xa220 }, +/* 0xa221 */ { true, 0xa221, 0xa221 }, +/* 0xa222 */ { true, 0xa222, 0xa222 }, +/* 0xa223 */ { true, 0xa223, 0xa223 }, +/* 0xa224 */ { true, 0xa224, 0xa224 }, +/* 0xa225 */ { true, 0xa225, 0xa225 }, +/* 0xa226 */ { true, 0xa226, 0xa226 }, +/* 0xa227 */ { true, 0xa227, 0xa227 }, +/* 0xa228 */ { true, 0xa228, 0xa228 }, +/* 0xa229 */ { true, 0xa229, 0xa229 }, +/* 0xa22a */ { true, 0xa22a, 0xa22a }, +/* 0xa22b */ { true, 0xa22b, 0xa22b }, +/* 0xa22c */ { true, 0xa22c, 0xa22c }, +/* 0xa22d */ { true, 0xa22d, 0xa22d }, +/* 0xa22e */ { true, 0xa22e, 0xa22e }, +/* 0xa22f */ { true, 0xa22f, 0xa22f }, +/* 0xa230 */ { true, 0xa230, 0xa230 }, +/* 0xa231 */ { true, 0xa231, 0xa231 }, +/* 0xa232 */ { true, 0xa232, 0xa232 }, +/* 0xa233 */ { true, 0xa233, 0xa233 }, +/* 0xa234 */ { true, 0xa234, 0xa234 }, +/* 0xa235 */ { true, 0xa235, 0xa235 }, +/* 0xa236 */ { true, 0xa236, 0xa236 }, +/* 0xa237 */ { true, 0xa237, 0xa237 }, +/* 0xa238 */ { true, 0xa238, 0xa238 }, +/* 0xa239 */ { true, 0xa239, 0xa239 }, +/* 0xa23a */ { true, 0xa23a, 0xa23a }, +/* 0xa23b */ { true, 0xa23b, 0xa23b }, +/* 0xa23c */ { true, 0xa23c, 0xa23c }, +/* 0xa23d */ { true, 0xa23d, 0xa23d }, +/* 0xa23e */ { true, 0xa23e, 0xa23e }, +/* 0xa23f */ { true, 0xa23f, 0xa23f }, +/* 0xa240 */ { true, 0xa240, 0xa240 }, +/* 0xa241 */ { true, 0xa241, 0xa241 }, +/* 0xa242 */ { true, 0xa242, 0xa242 }, +/* 0xa243 */ { true, 0xa243, 0xa243 }, +/* 0xa244 */ { true, 0xa244, 0xa244 }, +/* 0xa245 */ { true, 0xa245, 0xa245 }, +/* 0xa246 */ { true, 0xa246, 0xa246 }, +/* 0xa247 */ { true, 0xa247, 0xa247 }, +/* 0xa248 */ { true, 0xa248, 0xa248 }, +/* 0xa249 */ { true, 0xa249, 0xa249 }, +/* 0xa24a */ { true, 0xa24a, 0xa24a }, +/* 0xa24b */ { true, 0xa24b, 0xa24b }, +/* 0xa24c */ { true, 0xa24c, 0xa24c }, +/* 0xa24d */ { true, 0xa24d, 0xa24d }, +/* 0xa24e */ { true, 0xa24e, 0xa24e }, +/* 0xa24f */ { true, 0xa24f, 0xa24f }, +/* 0xa250 */ { true, 0xa250, 0xa250 }, +/* 0xa251 */ { true, 0xa251, 0xa251 }, +/* 0xa252 */ { true, 0xa252, 0xa252 }, +/* 0xa253 */ { true, 0xa253, 0xa253 }, +/* 0xa254 */ { true, 0xa254, 0xa254 }, +/* 0xa255 */ { true, 0xa255, 0xa255 }, +/* 0xa256 */ { true, 0xa256, 0xa256 }, +/* 0xa257 */ { true, 0xa257, 0xa257 }, +/* 0xa258 */ { true, 0xa258, 0xa258 }, +/* 0xa259 */ { true, 0xa259, 0xa259 }, +/* 0xa25a */ { true, 0xa25a, 0xa25a }, +/* 0xa25b */ { true, 0xa25b, 0xa25b }, +/* 0xa25c */ { true, 0xa25c, 0xa25c }, +/* 0xa25d */ { true, 0xa25d, 0xa25d }, +/* 0xa25e */ { true, 0xa25e, 0xa25e }, +/* 0xa25f */ { true, 0xa25f, 0xa25f }, +/* 0xa260 */ { true, 0xa260, 0xa260 }, +/* 0xa261 */ { true, 0xa261, 0xa261 }, +/* 0xa262 */ { true, 0xa262, 0xa262 }, +/* 0xa263 */ { true, 0xa263, 0xa263 }, +/* 0xa264 */ { true, 0xa264, 0xa264 }, +/* 0xa265 */ { true, 0xa265, 0xa265 }, +/* 0xa266 */ { true, 0xa266, 0xa266 }, +/* 0xa267 */ { true, 0xa267, 0xa267 }, +/* 0xa268 */ { true, 0xa268, 0xa268 }, +/* 0xa269 */ { true, 0xa269, 0xa269 }, +/* 0xa26a */ { true, 0xa26a, 0xa26a }, +/* 0xa26b */ { true, 0xa26b, 0xa26b }, +/* 0xa26c */ { true, 0xa26c, 0xa26c }, +/* 0xa26d */ { true, 0xa26d, 0xa26d }, +/* 0xa26e */ { true, 0xa26e, 0xa26e }, +/* 0xa26f */ { true, 0xa26f, 0xa26f }, +/* 0xa270 */ { true, 0xa270, 0xa270 }, +/* 0xa271 */ { true, 0xa271, 0xa271 }, +/* 0xa272 */ { true, 0xa272, 0xa272 }, +/* 0xa273 */ { true, 0xa273, 0xa273 }, +/* 0xa274 */ { true, 0xa274, 0xa274 }, +/* 0xa275 */ { true, 0xa275, 0xa275 }, +/* 0xa276 */ { true, 0xa276, 0xa276 }, +/* 0xa277 */ { true, 0xa277, 0xa277 }, +/* 0xa278 */ { true, 0xa278, 0xa278 }, +/* 0xa279 */ { true, 0xa279, 0xa279 }, +/* 0xa27a */ { true, 0xa27a, 0xa27a }, +/* 0xa27b */ { true, 0xa27b, 0xa27b }, +/* 0xa27c */ { true, 0xa27c, 0xa27c }, +/* 0xa27d */ { true, 0xa27d, 0xa27d }, +/* 0xa27e */ { true, 0xa27e, 0xa27e }, +/* 0xa27f */ { true, 0xa27f, 0xa27f }, +/* 0xa280 */ { true, 0xa280, 0xa280 }, +/* 0xa281 */ { true, 0xa281, 0xa281 }, +/* 0xa282 */ { true, 0xa282, 0xa282 }, +/* 0xa283 */ { true, 0xa283, 0xa283 }, +/* 0xa284 */ { true, 0xa284, 0xa284 }, +/* 0xa285 */ { true, 0xa285, 0xa285 }, +/* 0xa286 */ { true, 0xa286, 0xa286 }, +/* 0xa287 */ { true, 0xa287, 0xa287 }, +/* 0xa288 */ { true, 0xa288, 0xa288 }, +/* 0xa289 */ { true, 0xa289, 0xa289 }, +/* 0xa28a */ { true, 0xa28a, 0xa28a }, +/* 0xa28b */ { true, 0xa28b, 0xa28b }, +/* 0xa28c */ { true, 0xa28c, 0xa28c }, +/* 0xa28d */ { true, 0xa28d, 0xa28d }, +/* 0xa28e */ { true, 0xa28e, 0xa28e }, +/* 0xa28f */ { true, 0xa28f, 0xa28f }, +/* 0xa290 */ { true, 0xa290, 0xa290 }, +/* 0xa291 */ { true, 0xa291, 0xa291 }, +/* 0xa292 */ { true, 0xa292, 0xa292 }, +/* 0xa293 */ { true, 0xa293, 0xa293 }, +/* 0xa294 */ { true, 0xa294, 0xa294 }, +/* 0xa295 */ { true, 0xa295, 0xa295 }, +/* 0xa296 */ { true, 0xa296, 0xa296 }, +/* 0xa297 */ { true, 0xa297, 0xa297 }, +/* 0xa298 */ { true, 0xa298, 0xa298 }, +/* 0xa299 */ { true, 0xa299, 0xa299 }, +/* 0xa29a */ { true, 0xa29a, 0xa29a }, +/* 0xa29b */ { true, 0xa29b, 0xa29b }, +/* 0xa29c */ { true, 0xa29c, 0xa29c }, +/* 0xa29d */ { true, 0xa29d, 0xa29d }, +/* 0xa29e */ { true, 0xa29e, 0xa29e }, +/* 0xa29f */ { true, 0xa29f, 0xa29f }, +/* 0xa2a0 */ { true, 0xa2a0, 0xa2a0 }, +/* 0xa2a1 */ { true, 0xa2a1, 0xa2a1 }, +/* 0xa2a2 */ { true, 0xa2a2, 0xa2a2 }, +/* 0xa2a3 */ { true, 0xa2a3, 0xa2a3 }, +/* 0xa2a4 */ { true, 0xa2a4, 0xa2a4 }, +/* 0xa2a5 */ { true, 0xa2a5, 0xa2a5 }, +/* 0xa2a6 */ { true, 0xa2a6, 0xa2a6 }, +/* 0xa2a7 */ { true, 0xa2a7, 0xa2a7 }, +/* 0xa2a8 */ { true, 0xa2a8, 0xa2a8 }, +/* 0xa2a9 */ { true, 0xa2a9, 0xa2a9 }, +/* 0xa2aa */ { true, 0xa2aa, 0xa2aa }, +/* 0xa2ab */ { true, 0xa2ab, 0xa2ab }, +/* 0xa2ac */ { true, 0xa2ac, 0xa2ac }, +/* 0xa2ad */ { true, 0xa2ad, 0xa2ad }, +/* 0xa2ae */ { true, 0xa2ae, 0xa2ae }, +/* 0xa2af */ { true, 0xa2af, 0xa2af }, +/* 0xa2b0 */ { true, 0xa2b0, 0xa2b0 }, +/* 0xa2b1 */ { true, 0xa2b1, 0xa2b1 }, +/* 0xa2b2 */ { true, 0xa2b2, 0xa2b2 }, +/* 0xa2b3 */ { true, 0xa2b3, 0xa2b3 }, +/* 0xa2b4 */ { true, 0xa2b4, 0xa2b4 }, +/* 0xa2b5 */ { true, 0xa2b5, 0xa2b5 }, +/* 0xa2b6 */ { true, 0xa2b6, 0xa2b6 }, +/* 0xa2b7 */ { true, 0xa2b7, 0xa2b7 }, +/* 0xa2b8 */ { true, 0xa2b8, 0xa2b8 }, +/* 0xa2b9 */ { true, 0xa2b9, 0xa2b9 }, +/* 0xa2ba */ { true, 0xa2ba, 0xa2ba }, +/* 0xa2bb */ { true, 0xa2bb, 0xa2bb }, +/* 0xa2bc */ { true, 0xa2bc, 0xa2bc }, +/* 0xa2bd */ { true, 0xa2bd, 0xa2bd }, +/* 0xa2be */ { true, 0xa2be, 0xa2be }, +/* 0xa2bf */ { true, 0xa2bf, 0xa2bf }, +/* 0xa2c0 */ { true, 0xa2c0, 0xa2c0 }, +/* 0xa2c1 */ { true, 0xa2c1, 0xa2c1 }, +/* 0xa2c2 */ { true, 0xa2c2, 0xa2c2 }, +/* 0xa2c3 */ { true, 0xa2c3, 0xa2c3 }, +/* 0xa2c4 */ { true, 0xa2c4, 0xa2c4 }, +/* 0xa2c5 */ { true, 0xa2c5, 0xa2c5 }, +/* 0xa2c6 */ { true, 0xa2c6, 0xa2c6 }, +/* 0xa2c7 */ { true, 0xa2c7, 0xa2c7 }, +/* 0xa2c8 */ { true, 0xa2c8, 0xa2c8 }, +/* 0xa2c9 */ { true, 0xa2c9, 0xa2c9 }, +/* 0xa2ca */ { true, 0xa2ca, 0xa2ca }, +/* 0xa2cb */ { true, 0xa2cb, 0xa2cb }, +/* 0xa2cc */ { true, 0xa2cc, 0xa2cc }, +/* 0xa2cd */ { true, 0xa2cd, 0xa2cd }, +/* 0xa2ce */ { true, 0xa2ce, 0xa2ce }, +/* 0xa2cf */ { true, 0xa2cf, 0xa2cf }, +/* 0xa2d0 */ { true, 0xa2d0, 0xa2d0 }, +/* 0xa2d1 */ { true, 0xa2d1, 0xa2d1 }, +/* 0xa2d2 */ { true, 0xa2d2, 0xa2d2 }, +/* 0xa2d3 */ { true, 0xa2d3, 0xa2d3 }, +/* 0xa2d4 */ { true, 0xa2d4, 0xa2d4 }, +/* 0xa2d5 */ { true, 0xa2d5, 0xa2d5 }, +/* 0xa2d6 */ { true, 0xa2d6, 0xa2d6 }, +/* 0xa2d7 */ { true, 0xa2d7, 0xa2d7 }, +/* 0xa2d8 */ { true, 0xa2d8, 0xa2d8 }, +/* 0xa2d9 */ { true, 0xa2d9, 0xa2d9 }, +/* 0xa2da */ { true, 0xa2da, 0xa2da }, +/* 0xa2db */ { true, 0xa2db, 0xa2db }, +/* 0xa2dc */ { true, 0xa2dc, 0xa2dc }, +/* 0xa2dd */ { true, 0xa2dd, 0xa2dd }, +/* 0xa2de */ { true, 0xa2de, 0xa2de }, +/* 0xa2df */ { true, 0xa2df, 0xa2df }, +/* 0xa2e0 */ { true, 0xa2e0, 0xa2e0 }, +/* 0xa2e1 */ { true, 0xa2e1, 0xa2e1 }, +/* 0xa2e2 */ { true, 0xa2e2, 0xa2e2 }, +/* 0xa2e3 */ { true, 0xa2e3, 0xa2e3 }, +/* 0xa2e4 */ { true, 0xa2e4, 0xa2e4 }, +/* 0xa2e5 */ { true, 0xa2e5, 0xa2e5 }, +/* 0xa2e6 */ { true, 0xa2e6, 0xa2e6 }, +/* 0xa2e7 */ { true, 0xa2e7, 0xa2e7 }, +/* 0xa2e8 */ { true, 0xa2e8, 0xa2e8 }, +/* 0xa2e9 */ { true, 0xa2e9, 0xa2e9 }, +/* 0xa2ea */ { true, 0xa2ea, 0xa2ea }, +/* 0xa2eb */ { true, 0xa2eb, 0xa2eb }, +/* 0xa2ec */ { true, 0xa2ec, 0xa2ec }, +/* 0xa2ed */ { true, 0xa2ed, 0xa2ed }, +/* 0xa2ee */ { true, 0xa2ee, 0xa2ee }, +/* 0xa2ef */ { true, 0xa2ef, 0xa2ef }, +/* 0xa2f0 */ { true, 0xa2f0, 0xa2f0 }, +/* 0xa2f1 */ { true, 0xa2f1, 0xa2f1 }, +/* 0xa2f2 */ { true, 0xa2f2, 0xa2f2 }, +/* 0xa2f3 */ { true, 0xa2f3, 0xa2f3 }, +/* 0xa2f4 */ { true, 0xa2f4, 0xa2f4 }, +/* 0xa2f5 */ { true, 0xa2f5, 0xa2f5 }, +/* 0xa2f6 */ { true, 0xa2f6, 0xa2f6 }, +/* 0xa2f7 */ { true, 0xa2f7, 0xa2f7 }, +/* 0xa2f8 */ { true, 0xa2f8, 0xa2f8 }, +/* 0xa2f9 */ { true, 0xa2f9, 0xa2f9 }, +/* 0xa2fa */ { true, 0xa2fa, 0xa2fa }, +/* 0xa2fb */ { true, 0xa2fb, 0xa2fb }, +/* 0xa2fc */ { true, 0xa2fc, 0xa2fc }, +/* 0xa2fd */ { true, 0xa2fd, 0xa2fd }, +/* 0xa2fe */ { true, 0xa2fe, 0xa2fe }, +/* 0xa2ff */ { true, 0xa2ff, 0xa2ff }, +/* 0xa300 */ { true, 0xa300, 0xa300 }, +/* 0xa301 */ { true, 0xa301, 0xa301 }, +/* 0xa302 */ { true, 0xa302, 0xa302 }, +/* 0xa303 */ { true, 0xa303, 0xa303 }, +/* 0xa304 */ { true, 0xa304, 0xa304 }, +/* 0xa305 */ { true, 0xa305, 0xa305 }, +/* 0xa306 */ { true, 0xa306, 0xa306 }, +/* 0xa307 */ { true, 0xa307, 0xa307 }, +/* 0xa308 */ { true, 0xa308, 0xa308 }, +/* 0xa309 */ { true, 0xa309, 0xa309 }, +/* 0xa30a */ { true, 0xa30a, 0xa30a }, +/* 0xa30b */ { true, 0xa30b, 0xa30b }, +/* 0xa30c */ { true, 0xa30c, 0xa30c }, +/* 0xa30d */ { true, 0xa30d, 0xa30d }, +/* 0xa30e */ { true, 0xa30e, 0xa30e }, +/* 0xa30f */ { true, 0xa30f, 0xa30f }, +/* 0xa310 */ { true, 0xa310, 0xa310 }, +/* 0xa311 */ { true, 0xa311, 0xa311 }, +/* 0xa312 */ { true, 0xa312, 0xa312 }, +/* 0xa313 */ { true, 0xa313, 0xa313 }, +/* 0xa314 */ { true, 0xa314, 0xa314 }, +/* 0xa315 */ { true, 0xa315, 0xa315 }, +/* 0xa316 */ { true, 0xa316, 0xa316 }, +/* 0xa317 */ { true, 0xa317, 0xa317 }, +/* 0xa318 */ { true, 0xa318, 0xa318 }, +/* 0xa319 */ { true, 0xa319, 0xa319 }, +/* 0xa31a */ { true, 0xa31a, 0xa31a }, +/* 0xa31b */ { true, 0xa31b, 0xa31b }, +/* 0xa31c */ { true, 0xa31c, 0xa31c }, +/* 0xa31d */ { true, 0xa31d, 0xa31d }, +/* 0xa31e */ { true, 0xa31e, 0xa31e }, +/* 0xa31f */ { true, 0xa31f, 0xa31f }, +/* 0xa320 */ { true, 0xa320, 0xa320 }, +/* 0xa321 */ { true, 0xa321, 0xa321 }, +/* 0xa322 */ { true, 0xa322, 0xa322 }, +/* 0xa323 */ { true, 0xa323, 0xa323 }, +/* 0xa324 */ { true, 0xa324, 0xa324 }, +/* 0xa325 */ { true, 0xa325, 0xa325 }, +/* 0xa326 */ { true, 0xa326, 0xa326 }, +/* 0xa327 */ { true, 0xa327, 0xa327 }, +/* 0xa328 */ { true, 0xa328, 0xa328 }, +/* 0xa329 */ { true, 0xa329, 0xa329 }, +/* 0xa32a */ { true, 0xa32a, 0xa32a }, +/* 0xa32b */ { true, 0xa32b, 0xa32b }, +/* 0xa32c */ { true, 0xa32c, 0xa32c }, +/* 0xa32d */ { true, 0xa32d, 0xa32d }, +/* 0xa32e */ { true, 0xa32e, 0xa32e }, +/* 0xa32f */ { true, 0xa32f, 0xa32f }, +/* 0xa330 */ { true, 0xa330, 0xa330 }, +/* 0xa331 */ { true, 0xa331, 0xa331 }, +/* 0xa332 */ { true, 0xa332, 0xa332 }, +/* 0xa333 */ { true, 0xa333, 0xa333 }, +/* 0xa334 */ { true, 0xa334, 0xa334 }, +/* 0xa335 */ { true, 0xa335, 0xa335 }, +/* 0xa336 */ { true, 0xa336, 0xa336 }, +/* 0xa337 */ { true, 0xa337, 0xa337 }, +/* 0xa338 */ { true, 0xa338, 0xa338 }, +/* 0xa339 */ { true, 0xa339, 0xa339 }, +/* 0xa33a */ { true, 0xa33a, 0xa33a }, +/* 0xa33b */ { true, 0xa33b, 0xa33b }, +/* 0xa33c */ { true, 0xa33c, 0xa33c }, +/* 0xa33d */ { true, 0xa33d, 0xa33d }, +/* 0xa33e */ { true, 0xa33e, 0xa33e }, +/* 0xa33f */ { true, 0xa33f, 0xa33f }, +/* 0xa340 */ { true, 0xa340, 0xa340 }, +/* 0xa341 */ { true, 0xa341, 0xa341 }, +/* 0xa342 */ { true, 0xa342, 0xa342 }, +/* 0xa343 */ { true, 0xa343, 0xa343 }, +/* 0xa344 */ { true, 0xa344, 0xa344 }, +/* 0xa345 */ { true, 0xa345, 0xa345 }, +/* 0xa346 */ { true, 0xa346, 0xa346 }, +/* 0xa347 */ { true, 0xa347, 0xa347 }, +/* 0xa348 */ { true, 0xa348, 0xa348 }, +/* 0xa349 */ { true, 0xa349, 0xa349 }, +/* 0xa34a */ { true, 0xa34a, 0xa34a }, +/* 0xa34b */ { true, 0xa34b, 0xa34b }, +/* 0xa34c */ { true, 0xa34c, 0xa34c }, +/* 0xa34d */ { true, 0xa34d, 0xa34d }, +/* 0xa34e */ { true, 0xa34e, 0xa34e }, +/* 0xa34f */ { true, 0xa34f, 0xa34f }, +/* 0xa350 */ { true, 0xa350, 0xa350 }, +/* 0xa351 */ { true, 0xa351, 0xa351 }, +/* 0xa352 */ { true, 0xa352, 0xa352 }, +/* 0xa353 */ { true, 0xa353, 0xa353 }, +/* 0xa354 */ { true, 0xa354, 0xa354 }, +/* 0xa355 */ { true, 0xa355, 0xa355 }, +/* 0xa356 */ { true, 0xa356, 0xa356 }, +/* 0xa357 */ { true, 0xa357, 0xa357 }, +/* 0xa358 */ { true, 0xa358, 0xa358 }, +/* 0xa359 */ { true, 0xa359, 0xa359 }, +/* 0xa35a */ { true, 0xa35a, 0xa35a }, +/* 0xa35b */ { true, 0xa35b, 0xa35b }, +/* 0xa35c */ { true, 0xa35c, 0xa35c }, +/* 0xa35d */ { true, 0xa35d, 0xa35d }, +/* 0xa35e */ { true, 0xa35e, 0xa35e }, +/* 0xa35f */ { true, 0xa35f, 0xa35f }, +/* 0xa360 */ { true, 0xa360, 0xa360 }, +/* 0xa361 */ { true, 0xa361, 0xa361 }, +/* 0xa362 */ { true, 0xa362, 0xa362 }, +/* 0xa363 */ { true, 0xa363, 0xa363 }, +/* 0xa364 */ { true, 0xa364, 0xa364 }, +/* 0xa365 */ { true, 0xa365, 0xa365 }, +/* 0xa366 */ { true, 0xa366, 0xa366 }, +/* 0xa367 */ { true, 0xa367, 0xa367 }, +/* 0xa368 */ { true, 0xa368, 0xa368 }, +/* 0xa369 */ { true, 0xa369, 0xa369 }, +/* 0xa36a */ { true, 0xa36a, 0xa36a }, +/* 0xa36b */ { true, 0xa36b, 0xa36b }, +/* 0xa36c */ { true, 0xa36c, 0xa36c }, +/* 0xa36d */ { true, 0xa36d, 0xa36d }, +/* 0xa36e */ { true, 0xa36e, 0xa36e }, +/* 0xa36f */ { true, 0xa36f, 0xa36f }, +/* 0xa370 */ { true, 0xa370, 0xa370 }, +/* 0xa371 */ { true, 0xa371, 0xa371 }, +/* 0xa372 */ { true, 0xa372, 0xa372 }, +/* 0xa373 */ { true, 0xa373, 0xa373 }, +/* 0xa374 */ { true, 0xa374, 0xa374 }, +/* 0xa375 */ { true, 0xa375, 0xa375 }, +/* 0xa376 */ { true, 0xa376, 0xa376 }, +/* 0xa377 */ { true, 0xa377, 0xa377 }, +/* 0xa378 */ { true, 0xa378, 0xa378 }, +/* 0xa379 */ { true, 0xa379, 0xa379 }, +/* 0xa37a */ { true, 0xa37a, 0xa37a }, +/* 0xa37b */ { true, 0xa37b, 0xa37b }, +/* 0xa37c */ { true, 0xa37c, 0xa37c }, +/* 0xa37d */ { true, 0xa37d, 0xa37d }, +/* 0xa37e */ { true, 0xa37e, 0xa37e }, +/* 0xa37f */ { true, 0xa37f, 0xa37f }, +/* 0xa380 */ { true, 0xa380, 0xa380 }, +/* 0xa381 */ { true, 0xa381, 0xa381 }, +/* 0xa382 */ { true, 0xa382, 0xa382 }, +/* 0xa383 */ { true, 0xa383, 0xa383 }, +/* 0xa384 */ { true, 0xa384, 0xa384 }, +/* 0xa385 */ { true, 0xa385, 0xa385 }, +/* 0xa386 */ { true, 0xa386, 0xa386 }, +/* 0xa387 */ { true, 0xa387, 0xa387 }, +/* 0xa388 */ { true, 0xa388, 0xa388 }, +/* 0xa389 */ { true, 0xa389, 0xa389 }, +/* 0xa38a */ { true, 0xa38a, 0xa38a }, +/* 0xa38b */ { true, 0xa38b, 0xa38b }, +/* 0xa38c */ { true, 0xa38c, 0xa38c }, +/* 0xa38d */ { true, 0xa38d, 0xa38d }, +/* 0xa38e */ { true, 0xa38e, 0xa38e }, +/* 0xa38f */ { true, 0xa38f, 0xa38f }, +/* 0xa390 */ { true, 0xa390, 0xa390 }, +/* 0xa391 */ { true, 0xa391, 0xa391 }, +/* 0xa392 */ { true, 0xa392, 0xa392 }, +/* 0xa393 */ { true, 0xa393, 0xa393 }, +/* 0xa394 */ { true, 0xa394, 0xa394 }, +/* 0xa395 */ { true, 0xa395, 0xa395 }, +/* 0xa396 */ { true, 0xa396, 0xa396 }, +/* 0xa397 */ { true, 0xa397, 0xa397 }, +/* 0xa398 */ { true, 0xa398, 0xa398 }, +/* 0xa399 */ { true, 0xa399, 0xa399 }, +/* 0xa39a */ { true, 0xa39a, 0xa39a }, +/* 0xa39b */ { true, 0xa39b, 0xa39b }, +/* 0xa39c */ { true, 0xa39c, 0xa39c }, +/* 0xa39d */ { true, 0xa39d, 0xa39d }, +/* 0xa39e */ { true, 0xa39e, 0xa39e }, +/* 0xa39f */ { true, 0xa39f, 0xa39f }, +/* 0xa3a0 */ { true, 0xa3a0, 0xa3a0 }, +/* 0xa3a1 */ { true, 0xa3a1, 0xa3a1 }, +/* 0xa3a2 */ { true, 0xa3a2, 0xa3a2 }, +/* 0xa3a3 */ { true, 0xa3a3, 0xa3a3 }, +/* 0xa3a4 */ { true, 0xa3a4, 0xa3a4 }, +/* 0xa3a5 */ { true, 0xa3a5, 0xa3a5 }, +/* 0xa3a6 */ { true, 0xa3a6, 0xa3a6 }, +/* 0xa3a7 */ { true, 0xa3a7, 0xa3a7 }, +/* 0xa3a8 */ { true, 0xa3a8, 0xa3a8 }, +/* 0xa3a9 */ { true, 0xa3a9, 0xa3a9 }, +/* 0xa3aa */ { true, 0xa3aa, 0xa3aa }, +/* 0xa3ab */ { true, 0xa3ab, 0xa3ab }, +/* 0xa3ac */ { true, 0xa3ac, 0xa3ac }, +/* 0xa3ad */ { true, 0xa3ad, 0xa3ad }, +/* 0xa3ae */ { true, 0xa3ae, 0xa3ae }, +/* 0xa3af */ { true, 0xa3af, 0xa3af }, +/* 0xa3b0 */ { true, 0xa3b0, 0xa3b0 }, +/* 0xa3b1 */ { true, 0xa3b1, 0xa3b1 }, +/* 0xa3b2 */ { true, 0xa3b2, 0xa3b2 }, +/* 0xa3b3 */ { true, 0xa3b3, 0xa3b3 }, +/* 0xa3b4 */ { true, 0xa3b4, 0xa3b4 }, +/* 0xa3b5 */ { true, 0xa3b5, 0xa3b5 }, +/* 0xa3b6 */ { true, 0xa3b6, 0xa3b6 }, +/* 0xa3b7 */ { true, 0xa3b7, 0xa3b7 }, +/* 0xa3b8 */ { true, 0xa3b8, 0xa3b8 }, +/* 0xa3b9 */ { true, 0xa3b9, 0xa3b9 }, +/* 0xa3ba */ { true, 0xa3ba, 0xa3ba }, +/* 0xa3bb */ { true, 0xa3bb, 0xa3bb }, +/* 0xa3bc */ { true, 0xa3bc, 0xa3bc }, +/* 0xa3bd */ { true, 0xa3bd, 0xa3bd }, +/* 0xa3be */ { true, 0xa3be, 0xa3be }, +/* 0xa3bf */ { true, 0xa3bf, 0xa3bf }, +/* 0xa3c0 */ { true, 0xa3c0, 0xa3c0 }, +/* 0xa3c1 */ { true, 0xa3c1, 0xa3c1 }, +/* 0xa3c2 */ { true, 0xa3c2, 0xa3c2 }, +/* 0xa3c3 */ { true, 0xa3c3, 0xa3c3 }, +/* 0xa3c4 */ { true, 0xa3c4, 0xa3c4 }, +/* 0xa3c5 */ { true, 0xa3c5, 0xa3c5 }, +/* 0xa3c6 */ { true, 0xa3c6, 0xa3c6 }, +/* 0xa3c7 */ { true, 0xa3c7, 0xa3c7 }, +/* 0xa3c8 */ { true, 0xa3c8, 0xa3c8 }, +/* 0xa3c9 */ { true, 0xa3c9, 0xa3c9 }, +/* 0xa3ca */ { true, 0xa3ca, 0xa3ca }, +/* 0xa3cb */ { true, 0xa3cb, 0xa3cb }, +/* 0xa3cc */ { true, 0xa3cc, 0xa3cc }, +/* 0xa3cd */ { true, 0xa3cd, 0xa3cd }, +/* 0xa3ce */ { true, 0xa3ce, 0xa3ce }, +/* 0xa3cf */ { true, 0xa3cf, 0xa3cf }, +/* 0xa3d0 */ { true, 0xa3d0, 0xa3d0 }, +/* 0xa3d1 */ { true, 0xa3d1, 0xa3d1 }, +/* 0xa3d2 */ { true, 0xa3d2, 0xa3d2 }, +/* 0xa3d3 */ { true, 0xa3d3, 0xa3d3 }, +/* 0xa3d4 */ { true, 0xa3d4, 0xa3d4 }, +/* 0xa3d5 */ { true, 0xa3d5, 0xa3d5 }, +/* 0xa3d6 */ { true, 0xa3d6, 0xa3d6 }, +/* 0xa3d7 */ { true, 0xa3d7, 0xa3d7 }, +/* 0xa3d8 */ { true, 0xa3d8, 0xa3d8 }, +/* 0xa3d9 */ { true, 0xa3d9, 0xa3d9 }, +/* 0xa3da */ { true, 0xa3da, 0xa3da }, +/* 0xa3db */ { true, 0xa3db, 0xa3db }, +/* 0xa3dc */ { true, 0xa3dc, 0xa3dc }, +/* 0xa3dd */ { true, 0xa3dd, 0xa3dd }, +/* 0xa3de */ { true, 0xa3de, 0xa3de }, +/* 0xa3df */ { true, 0xa3df, 0xa3df }, +/* 0xa3e0 */ { true, 0xa3e0, 0xa3e0 }, +/* 0xa3e1 */ { true, 0xa3e1, 0xa3e1 }, +/* 0xa3e2 */ { true, 0xa3e2, 0xa3e2 }, +/* 0xa3e3 */ { true, 0xa3e3, 0xa3e3 }, +/* 0xa3e4 */ { true, 0xa3e4, 0xa3e4 }, +/* 0xa3e5 */ { true, 0xa3e5, 0xa3e5 }, +/* 0xa3e6 */ { true, 0xa3e6, 0xa3e6 }, +/* 0xa3e7 */ { true, 0xa3e7, 0xa3e7 }, +/* 0xa3e8 */ { true, 0xa3e8, 0xa3e8 }, +/* 0xa3e9 */ { true, 0xa3e9, 0xa3e9 }, +/* 0xa3ea */ { true, 0xa3ea, 0xa3ea }, +/* 0xa3eb */ { true, 0xa3eb, 0xa3eb }, +/* 0xa3ec */ { true, 0xa3ec, 0xa3ec }, +/* 0xa3ed */ { true, 0xa3ed, 0xa3ed }, +/* 0xa3ee */ { true, 0xa3ee, 0xa3ee }, +/* 0xa3ef */ { true, 0xa3ef, 0xa3ef }, +/* 0xa3f0 */ { true, 0xa3f0, 0xa3f0 }, +/* 0xa3f1 */ { true, 0xa3f1, 0xa3f1 }, +/* 0xa3f2 */ { true, 0xa3f2, 0xa3f2 }, +/* 0xa3f3 */ { true, 0xa3f3, 0xa3f3 }, +/* 0xa3f4 */ { true, 0xa3f4, 0xa3f4 }, +/* 0xa3f5 */ { true, 0xa3f5, 0xa3f5 }, +/* 0xa3f6 */ { true, 0xa3f6, 0xa3f6 }, +/* 0xa3f7 */ { true, 0xa3f7, 0xa3f7 }, +/* 0xa3f8 */ { true, 0xa3f8, 0xa3f8 }, +/* 0xa3f9 */ { true, 0xa3f9, 0xa3f9 }, +/* 0xa3fa */ { true, 0xa3fa, 0xa3fa }, +/* 0xa3fb */ { true, 0xa3fb, 0xa3fb }, +/* 0xa3fc */ { true, 0xa3fc, 0xa3fc }, +/* 0xa3fd */ { true, 0xa3fd, 0xa3fd }, +/* 0xa3fe */ { true, 0xa3fe, 0xa3fe }, +/* 0xa3ff */ { true, 0xa3ff, 0xa3ff }, +/* 0xa400 */ { true, 0xa400, 0xa400 }, +/* 0xa401 */ { true, 0xa401, 0xa401 }, +/* 0xa402 */ { true, 0xa402, 0xa402 }, +/* 0xa403 */ { true, 0xa403, 0xa403 }, +/* 0xa404 */ { true, 0xa404, 0xa404 }, +/* 0xa405 */ { true, 0xa405, 0xa405 }, +/* 0xa406 */ { true, 0xa406, 0xa406 }, +/* 0xa407 */ { true, 0xa407, 0xa407 }, +/* 0xa408 */ { true, 0xa408, 0xa408 }, +/* 0xa409 */ { true, 0xa409, 0xa409 }, +/* 0xa40a */ { true, 0xa40a, 0xa40a }, +/* 0xa40b */ { true, 0xa40b, 0xa40b }, +/* 0xa40c */ { true, 0xa40c, 0xa40c }, +/* 0xa40d */ { true, 0xa40d, 0xa40d }, +/* 0xa40e */ { true, 0xa40e, 0xa40e }, +/* 0xa40f */ { true, 0xa40f, 0xa40f }, +/* 0xa410 */ { true, 0xa410, 0xa410 }, +/* 0xa411 */ { true, 0xa411, 0xa411 }, +/* 0xa412 */ { true, 0xa412, 0xa412 }, +/* 0xa413 */ { true, 0xa413, 0xa413 }, +/* 0xa414 */ { true, 0xa414, 0xa414 }, +/* 0xa415 */ { true, 0xa415, 0xa415 }, +/* 0xa416 */ { true, 0xa416, 0xa416 }, +/* 0xa417 */ { true, 0xa417, 0xa417 }, +/* 0xa418 */ { true, 0xa418, 0xa418 }, +/* 0xa419 */ { true, 0xa419, 0xa419 }, +/* 0xa41a */ { true, 0xa41a, 0xa41a }, +/* 0xa41b */ { true, 0xa41b, 0xa41b }, +/* 0xa41c */ { true, 0xa41c, 0xa41c }, +/* 0xa41d */ { true, 0xa41d, 0xa41d }, +/* 0xa41e */ { true, 0xa41e, 0xa41e }, +/* 0xa41f */ { true, 0xa41f, 0xa41f }, +/* 0xa420 */ { true, 0xa420, 0xa420 }, +/* 0xa421 */ { true, 0xa421, 0xa421 }, +/* 0xa422 */ { true, 0xa422, 0xa422 }, +/* 0xa423 */ { true, 0xa423, 0xa423 }, +/* 0xa424 */ { true, 0xa424, 0xa424 }, +/* 0xa425 */ { true, 0xa425, 0xa425 }, +/* 0xa426 */ { true, 0xa426, 0xa426 }, +/* 0xa427 */ { true, 0xa427, 0xa427 }, +/* 0xa428 */ { true, 0xa428, 0xa428 }, +/* 0xa429 */ { true, 0xa429, 0xa429 }, +/* 0xa42a */ { true, 0xa42a, 0xa42a }, +/* 0xa42b */ { true, 0xa42b, 0xa42b }, +/* 0xa42c */ { true, 0xa42c, 0xa42c }, +/* 0xa42d */ { true, 0xa42d, 0xa42d }, +/* 0xa42e */ { true, 0xa42e, 0xa42e }, +/* 0xa42f */ { true, 0xa42f, 0xa42f }, +/* 0xa430 */ { true, 0xa430, 0xa430 }, +/* 0xa431 */ { true, 0xa431, 0xa431 }, +/* 0xa432 */ { true, 0xa432, 0xa432 }, +/* 0xa433 */ { true, 0xa433, 0xa433 }, +/* 0xa434 */ { true, 0xa434, 0xa434 }, +/* 0xa435 */ { true, 0xa435, 0xa435 }, +/* 0xa436 */ { true, 0xa436, 0xa436 }, +/* 0xa437 */ { true, 0xa437, 0xa437 }, +/* 0xa438 */ { true, 0xa438, 0xa438 }, +/* 0xa439 */ { true, 0xa439, 0xa439 }, +/* 0xa43a */ { true, 0xa43a, 0xa43a }, +/* 0xa43b */ { true, 0xa43b, 0xa43b }, +/* 0xa43c */ { true, 0xa43c, 0xa43c }, +/* 0xa43d */ { true, 0xa43d, 0xa43d }, +/* 0xa43e */ { true, 0xa43e, 0xa43e }, +/* 0xa43f */ { true, 0xa43f, 0xa43f }, +/* 0xa440 */ { true, 0xa440, 0xa440 }, +/* 0xa441 */ { true, 0xa441, 0xa441 }, +/* 0xa442 */ { true, 0xa442, 0xa442 }, +/* 0xa443 */ { true, 0xa443, 0xa443 }, +/* 0xa444 */ { true, 0xa444, 0xa444 }, +/* 0xa445 */ { true, 0xa445, 0xa445 }, +/* 0xa446 */ { true, 0xa446, 0xa446 }, +/* 0xa447 */ { true, 0xa447, 0xa447 }, +/* 0xa448 */ { true, 0xa448, 0xa448 }, +/* 0xa449 */ { true, 0xa449, 0xa449 }, +/* 0xa44a */ { true, 0xa44a, 0xa44a }, +/* 0xa44b */ { true, 0xa44b, 0xa44b }, +/* 0xa44c */ { true, 0xa44c, 0xa44c }, +/* 0xa44d */ { true, 0xa44d, 0xa44d }, +/* 0xa44e */ { true, 0xa44e, 0xa44e }, +/* 0xa44f */ { true, 0xa44f, 0xa44f }, +/* 0xa450 */ { true, 0xa450, 0xa450 }, +/* 0xa451 */ { true, 0xa451, 0xa451 }, +/* 0xa452 */ { true, 0xa452, 0xa452 }, +/* 0xa453 */ { true, 0xa453, 0xa453 }, +/* 0xa454 */ { true, 0xa454, 0xa454 }, +/* 0xa455 */ { true, 0xa455, 0xa455 }, +/* 0xa456 */ { true, 0xa456, 0xa456 }, +/* 0xa457 */ { true, 0xa457, 0xa457 }, +/* 0xa458 */ { true, 0xa458, 0xa458 }, +/* 0xa459 */ { true, 0xa459, 0xa459 }, +/* 0xa45a */ { true, 0xa45a, 0xa45a }, +/* 0xa45b */ { true, 0xa45b, 0xa45b }, +/* 0xa45c */ { true, 0xa45c, 0xa45c }, +/* 0xa45d */ { true, 0xa45d, 0xa45d }, +/* 0xa45e */ { true, 0xa45e, 0xa45e }, +/* 0xa45f */ { true, 0xa45f, 0xa45f }, +/* 0xa460 */ { true, 0xa460, 0xa460 }, +/* 0xa461 */ { true, 0xa461, 0xa461 }, +/* 0xa462 */ { true, 0xa462, 0xa462 }, +/* 0xa463 */ { true, 0xa463, 0xa463 }, +/* 0xa464 */ { true, 0xa464, 0xa464 }, +/* 0xa465 */ { true, 0xa465, 0xa465 }, +/* 0xa466 */ { true, 0xa466, 0xa466 }, +/* 0xa467 */ { true, 0xa467, 0xa467 }, +/* 0xa468 */ { true, 0xa468, 0xa468 }, +/* 0xa469 */ { true, 0xa469, 0xa469 }, +/* 0xa46a */ { true, 0xa46a, 0xa46a }, +/* 0xa46b */ { true, 0xa46b, 0xa46b }, +/* 0xa46c */ { true, 0xa46c, 0xa46c }, +/* 0xa46d */ { true, 0xa46d, 0xa46d }, +/* 0xa46e */ { true, 0xa46e, 0xa46e }, +/* 0xa46f */ { true, 0xa46f, 0xa46f }, +/* 0xa470 */ { true, 0xa470, 0xa470 }, +/* 0xa471 */ { true, 0xa471, 0xa471 }, +/* 0xa472 */ { true, 0xa472, 0xa472 }, +/* 0xa473 */ { true, 0xa473, 0xa473 }, +/* 0xa474 */ { true, 0xa474, 0xa474 }, +/* 0xa475 */ { true, 0xa475, 0xa475 }, +/* 0xa476 */ { true, 0xa476, 0xa476 }, +/* 0xa477 */ { true, 0xa477, 0xa477 }, +/* 0xa478 */ { true, 0xa478, 0xa478 }, +/* 0xa479 */ { true, 0xa479, 0xa479 }, +/* 0xa47a */ { true, 0xa47a, 0xa47a }, +/* 0xa47b */ { true, 0xa47b, 0xa47b }, +/* 0xa47c */ { true, 0xa47c, 0xa47c }, +/* 0xa47d */ { true, 0xa47d, 0xa47d }, +/* 0xa47e */ { true, 0xa47e, 0xa47e }, +/* 0xa47f */ { true, 0xa47f, 0xa47f }, +/* 0xa480 */ { true, 0xa480, 0xa480 }, +/* 0xa481 */ { true, 0xa481, 0xa481 }, +/* 0xa482 */ { true, 0xa482, 0xa482 }, +/* 0xa483 */ { true, 0xa483, 0xa483 }, +/* 0xa484 */ { true, 0xa484, 0xa484 }, +/* 0xa485 */ { true, 0xa485, 0xa485 }, +/* 0xa486 */ { true, 0xa486, 0xa486 }, +/* 0xa487 */ { true, 0xa487, 0xa487 }, +/* 0xa488 */ { true, 0xa488, 0xa488 }, +/* 0xa489 */ { true, 0xa489, 0xa489 }, +/* 0xa48a */ { true, 0xa48a, 0xa48a }, +/* 0xa48b */ { true, 0xa48b, 0xa48b }, +/* 0xa48c */ { true, 0xa48c, 0xa48c }, +/* 0xa48d */ { false, 0xa48d, 0xa48d }, +/* 0xa48e */ { false, 0xa48e, 0xa48e }, +/* 0xa48f */ { false, 0xa48f, 0xa48f }, +/* 0xa490 */ { false, 0xa490, 0xa490 }, +/* 0xa491 */ { false, 0xa491, 0xa491 }, +/* 0xa492 */ { false, 0xa492, 0xa492 }, +/* 0xa493 */ { false, 0xa493, 0xa493 }, +/* 0xa494 */ { false, 0xa494, 0xa494 }, +/* 0xa495 */ { false, 0xa495, 0xa495 }, +/* 0xa496 */ { false, 0xa496, 0xa496 }, +/* 0xa497 */ { false, 0xa497, 0xa497 }, +/* 0xa498 */ { false, 0xa498, 0xa498 }, +/* 0xa499 */ { false, 0xa499, 0xa499 }, +/* 0xa49a */ { false, 0xa49a, 0xa49a }, +/* 0xa49b */ { false, 0xa49b, 0xa49b }, +/* 0xa49c */ { false, 0xa49c, 0xa49c }, +/* 0xa49d */ { false, 0xa49d, 0xa49d }, +/* 0xa49e */ { false, 0xa49e, 0xa49e }, +/* 0xa49f */ { false, 0xa49f, 0xa49f }, +/* 0xa4a0 */ { false, 0xa4a0, 0xa4a0 }, +/* 0xa4a1 */ { false, 0xa4a1, 0xa4a1 }, +/* 0xa4a2 */ { false, 0xa4a2, 0xa4a2 }, +/* 0xa4a3 */ { false, 0xa4a3, 0xa4a3 }, +/* 0xa4a4 */ { false, 0xa4a4, 0xa4a4 }, +/* 0xa4a5 */ { false, 0xa4a5, 0xa4a5 }, +/* 0xa4a6 */ { false, 0xa4a6, 0xa4a6 }, +/* 0xa4a7 */ { false, 0xa4a7, 0xa4a7 }, +/* 0xa4a8 */ { false, 0xa4a8, 0xa4a8 }, +/* 0xa4a9 */ { false, 0xa4a9, 0xa4a9 }, +/* 0xa4aa */ { false, 0xa4aa, 0xa4aa }, +/* 0xa4ab */ { false, 0xa4ab, 0xa4ab }, +/* 0xa4ac */ { false, 0xa4ac, 0xa4ac }, +/* 0xa4ad */ { false, 0xa4ad, 0xa4ad }, +/* 0xa4ae */ { false, 0xa4ae, 0xa4ae }, +/* 0xa4af */ { false, 0xa4af, 0xa4af }, +/* 0xa4b0 */ { false, 0xa4b0, 0xa4b0 }, +/* 0xa4b1 */ { false, 0xa4b1, 0xa4b1 }, +/* 0xa4b2 */ { false, 0xa4b2, 0xa4b2 }, +/* 0xa4b3 */ { false, 0xa4b3, 0xa4b3 }, +/* 0xa4b4 */ { false, 0xa4b4, 0xa4b4 }, +/* 0xa4b5 */ { false, 0xa4b5, 0xa4b5 }, +/* 0xa4b6 */ { false, 0xa4b6, 0xa4b6 }, +/* 0xa4b7 */ { false, 0xa4b7, 0xa4b7 }, +/* 0xa4b8 */ { false, 0xa4b8, 0xa4b8 }, +/* 0xa4b9 */ { false, 0xa4b9, 0xa4b9 }, +/* 0xa4ba */ { false, 0xa4ba, 0xa4ba }, +/* 0xa4bb */ { false, 0xa4bb, 0xa4bb }, +/* 0xa4bc */ { false, 0xa4bc, 0xa4bc }, +/* 0xa4bd */ { false, 0xa4bd, 0xa4bd }, +/* 0xa4be */ { false, 0xa4be, 0xa4be }, +/* 0xa4bf */ { false, 0xa4bf, 0xa4bf }, +/* 0xa4c0 */ { false, 0xa4c0, 0xa4c0 }, +/* 0xa4c1 */ { false, 0xa4c1, 0xa4c1 }, +/* 0xa4c2 */ { false, 0xa4c2, 0xa4c2 }, +/* 0xa4c3 */ { false, 0xa4c3, 0xa4c3 }, +/* 0xa4c4 */ { false, 0xa4c4, 0xa4c4 }, +/* 0xa4c5 */ { false, 0xa4c5, 0xa4c5 }, +/* 0xa4c6 */ { false, 0xa4c6, 0xa4c6 }, +/* 0xa4c7 */ { false, 0xa4c7, 0xa4c7 }, +/* 0xa4c8 */ { false, 0xa4c8, 0xa4c8 }, +/* 0xa4c9 */ { false, 0xa4c9, 0xa4c9 }, +/* 0xa4ca */ { false, 0xa4ca, 0xa4ca }, +/* 0xa4cb */ { false, 0xa4cb, 0xa4cb }, +/* 0xa4cc */ { false, 0xa4cc, 0xa4cc }, +/* 0xa4cd */ { false, 0xa4cd, 0xa4cd }, +/* 0xa4ce */ { false, 0xa4ce, 0xa4ce }, +/* 0xa4cf */ { false, 0xa4cf, 0xa4cf }, +/* 0xa4d0 */ { false, 0xa4d0, 0xa4d0 }, +/* 0xa4d1 */ { false, 0xa4d1, 0xa4d1 }, +/* 0xa4d2 */ { false, 0xa4d2, 0xa4d2 }, +/* 0xa4d3 */ { false, 0xa4d3, 0xa4d3 }, +/* 0xa4d4 */ { false, 0xa4d4, 0xa4d4 }, +/* 0xa4d5 */ { false, 0xa4d5, 0xa4d5 }, +/* 0xa4d6 */ { false, 0xa4d6, 0xa4d6 }, +/* 0xa4d7 */ { false, 0xa4d7, 0xa4d7 }, +/* 0xa4d8 */ { false, 0xa4d8, 0xa4d8 }, +/* 0xa4d9 */ { false, 0xa4d9, 0xa4d9 }, +/* 0xa4da */ { false, 0xa4da, 0xa4da }, +/* 0xa4db */ { false, 0xa4db, 0xa4db }, +/* 0xa4dc */ { false, 0xa4dc, 0xa4dc }, +/* 0xa4dd */ { false, 0xa4dd, 0xa4dd }, +/* 0xa4de */ { false, 0xa4de, 0xa4de }, +/* 0xa4df */ { false, 0xa4df, 0xa4df }, +/* 0xa4e0 */ { false, 0xa4e0, 0xa4e0 }, +/* 0xa4e1 */ { false, 0xa4e1, 0xa4e1 }, +/* 0xa4e2 */ { false, 0xa4e2, 0xa4e2 }, +/* 0xa4e3 */ { false, 0xa4e3, 0xa4e3 }, +/* 0xa4e4 */ { false, 0xa4e4, 0xa4e4 }, +/* 0xa4e5 */ { false, 0xa4e5, 0xa4e5 }, +/* 0xa4e6 */ { false, 0xa4e6, 0xa4e6 }, +/* 0xa4e7 */ { false, 0xa4e7, 0xa4e7 }, +/* 0xa4e8 */ { false, 0xa4e8, 0xa4e8 }, +/* 0xa4e9 */ { false, 0xa4e9, 0xa4e9 }, +/* 0xa4ea */ { false, 0xa4ea, 0xa4ea }, +/* 0xa4eb */ { false, 0xa4eb, 0xa4eb }, +/* 0xa4ec */ { false, 0xa4ec, 0xa4ec }, +/* 0xa4ed */ { false, 0xa4ed, 0xa4ed }, +/* 0xa4ee */ { false, 0xa4ee, 0xa4ee }, +/* 0xa4ef */ { false, 0xa4ef, 0xa4ef }, +/* 0xa4f0 */ { false, 0xa4f0, 0xa4f0 }, +/* 0xa4f1 */ { false, 0xa4f1, 0xa4f1 }, +/* 0xa4f2 */ { false, 0xa4f2, 0xa4f2 }, +/* 0xa4f3 */ { false, 0xa4f3, 0xa4f3 }, +/* 0xa4f4 */ { false, 0xa4f4, 0xa4f4 }, +/* 0xa4f5 */ { false, 0xa4f5, 0xa4f5 }, +/* 0xa4f6 */ { false, 0xa4f6, 0xa4f6 }, +/* 0xa4f7 */ { false, 0xa4f7, 0xa4f7 }, +/* 0xa4f8 */ { false, 0xa4f8, 0xa4f8 }, +/* 0xa4f9 */ { false, 0xa4f9, 0xa4f9 }, +/* 0xa4fa */ { false, 0xa4fa, 0xa4fa }, +/* 0xa4fb */ { false, 0xa4fb, 0xa4fb }, +/* 0xa4fc */ { false, 0xa4fc, 0xa4fc }, +/* 0xa4fd */ { false, 0xa4fd, 0xa4fd }, +/* 0xa4fe */ { false, 0xa4fe, 0xa4fe }, +/* 0xa4ff */ { false, 0xa4ff, 0xa4ff }, +/* 0xa500 */ { false, 0xa500, 0xa500 }, +/* 0xa501 */ { false, 0xa501, 0xa501 }, +/* 0xa502 */ { false, 0xa502, 0xa502 }, +/* 0xa503 */ { false, 0xa503, 0xa503 }, +/* 0xa504 */ { false, 0xa504, 0xa504 }, +/* 0xa505 */ { false, 0xa505, 0xa505 }, +/* 0xa506 */ { false, 0xa506, 0xa506 }, +/* 0xa507 */ { false, 0xa507, 0xa507 }, +/* 0xa508 */ { false, 0xa508, 0xa508 }, +/* 0xa509 */ { false, 0xa509, 0xa509 }, +/* 0xa50a */ { false, 0xa50a, 0xa50a }, +/* 0xa50b */ { false, 0xa50b, 0xa50b }, +/* 0xa50c */ { false, 0xa50c, 0xa50c }, +/* 0xa50d */ { false, 0xa50d, 0xa50d }, +/* 0xa50e */ { false, 0xa50e, 0xa50e }, +/* 0xa50f */ { false, 0xa50f, 0xa50f }, +/* 0xa510 */ { false, 0xa510, 0xa510 }, +/* 0xa511 */ { false, 0xa511, 0xa511 }, +/* 0xa512 */ { false, 0xa512, 0xa512 }, +/* 0xa513 */ { false, 0xa513, 0xa513 }, +/* 0xa514 */ { false, 0xa514, 0xa514 }, +/* 0xa515 */ { false, 0xa515, 0xa515 }, +/* 0xa516 */ { false, 0xa516, 0xa516 }, +/* 0xa517 */ { false, 0xa517, 0xa517 }, +/* 0xa518 */ { false, 0xa518, 0xa518 }, +/* 0xa519 */ { false, 0xa519, 0xa519 }, +/* 0xa51a */ { false, 0xa51a, 0xa51a }, +/* 0xa51b */ { false, 0xa51b, 0xa51b }, +/* 0xa51c */ { false, 0xa51c, 0xa51c }, +/* 0xa51d */ { false, 0xa51d, 0xa51d }, +/* 0xa51e */ { false, 0xa51e, 0xa51e }, +/* 0xa51f */ { false, 0xa51f, 0xa51f }, +/* 0xa520 */ { false, 0xa520, 0xa520 }, +/* 0xa521 */ { false, 0xa521, 0xa521 }, +/* 0xa522 */ { false, 0xa522, 0xa522 }, +/* 0xa523 */ { false, 0xa523, 0xa523 }, +/* 0xa524 */ { false, 0xa524, 0xa524 }, +/* 0xa525 */ { false, 0xa525, 0xa525 }, +/* 0xa526 */ { false, 0xa526, 0xa526 }, +/* 0xa527 */ { false, 0xa527, 0xa527 }, +/* 0xa528 */ { false, 0xa528, 0xa528 }, +/* 0xa529 */ { false, 0xa529, 0xa529 }, +/* 0xa52a */ { false, 0xa52a, 0xa52a }, +/* 0xa52b */ { false, 0xa52b, 0xa52b }, +/* 0xa52c */ { false, 0xa52c, 0xa52c }, +/* 0xa52d */ { false, 0xa52d, 0xa52d }, +/* 0xa52e */ { false, 0xa52e, 0xa52e }, +/* 0xa52f */ { false, 0xa52f, 0xa52f }, +/* 0xa530 */ { false, 0xa530, 0xa530 }, +/* 0xa531 */ { false, 0xa531, 0xa531 }, +/* 0xa532 */ { false, 0xa532, 0xa532 }, +/* 0xa533 */ { false, 0xa533, 0xa533 }, +/* 0xa534 */ { false, 0xa534, 0xa534 }, +/* 0xa535 */ { false, 0xa535, 0xa535 }, +/* 0xa536 */ { false, 0xa536, 0xa536 }, +/* 0xa537 */ { false, 0xa537, 0xa537 }, +/* 0xa538 */ { false, 0xa538, 0xa538 }, +/* 0xa539 */ { false, 0xa539, 0xa539 }, +/* 0xa53a */ { false, 0xa53a, 0xa53a }, +/* 0xa53b */ { false, 0xa53b, 0xa53b }, +/* 0xa53c */ { false, 0xa53c, 0xa53c }, +/* 0xa53d */ { false, 0xa53d, 0xa53d }, +/* 0xa53e */ { false, 0xa53e, 0xa53e }, +/* 0xa53f */ { false, 0xa53f, 0xa53f }, +/* 0xa540 */ { false, 0xa540, 0xa540 }, +/* 0xa541 */ { false, 0xa541, 0xa541 }, +/* 0xa542 */ { false, 0xa542, 0xa542 }, +/* 0xa543 */ { false, 0xa543, 0xa543 }, +/* 0xa544 */ { false, 0xa544, 0xa544 }, +/* 0xa545 */ { false, 0xa545, 0xa545 }, +/* 0xa546 */ { false, 0xa546, 0xa546 }, +/* 0xa547 */ { false, 0xa547, 0xa547 }, +/* 0xa548 */ { false, 0xa548, 0xa548 }, +/* 0xa549 */ { false, 0xa549, 0xa549 }, +/* 0xa54a */ { false, 0xa54a, 0xa54a }, +/* 0xa54b */ { false, 0xa54b, 0xa54b }, +/* 0xa54c */ { false, 0xa54c, 0xa54c }, +/* 0xa54d */ { false, 0xa54d, 0xa54d }, +/* 0xa54e */ { false, 0xa54e, 0xa54e }, +/* 0xa54f */ { false, 0xa54f, 0xa54f }, +/* 0xa550 */ { false, 0xa550, 0xa550 }, +/* 0xa551 */ { false, 0xa551, 0xa551 }, +/* 0xa552 */ { false, 0xa552, 0xa552 }, +/* 0xa553 */ { false, 0xa553, 0xa553 }, +/* 0xa554 */ { false, 0xa554, 0xa554 }, +/* 0xa555 */ { false, 0xa555, 0xa555 }, +/* 0xa556 */ { false, 0xa556, 0xa556 }, +/* 0xa557 */ { false, 0xa557, 0xa557 }, +/* 0xa558 */ { false, 0xa558, 0xa558 }, +/* 0xa559 */ { false, 0xa559, 0xa559 }, +/* 0xa55a */ { false, 0xa55a, 0xa55a }, +/* 0xa55b */ { false, 0xa55b, 0xa55b }, +/* 0xa55c */ { false, 0xa55c, 0xa55c }, +/* 0xa55d */ { false, 0xa55d, 0xa55d }, +/* 0xa55e */ { false, 0xa55e, 0xa55e }, +/* 0xa55f */ { false, 0xa55f, 0xa55f }, +/* 0xa560 */ { false, 0xa560, 0xa560 }, +/* 0xa561 */ { false, 0xa561, 0xa561 }, +/* 0xa562 */ { false, 0xa562, 0xa562 }, +/* 0xa563 */ { false, 0xa563, 0xa563 }, +/* 0xa564 */ { false, 0xa564, 0xa564 }, +/* 0xa565 */ { false, 0xa565, 0xa565 }, +/* 0xa566 */ { false, 0xa566, 0xa566 }, +/* 0xa567 */ { false, 0xa567, 0xa567 }, +/* 0xa568 */ { false, 0xa568, 0xa568 }, +/* 0xa569 */ { false, 0xa569, 0xa569 }, +/* 0xa56a */ { false, 0xa56a, 0xa56a }, +/* 0xa56b */ { false, 0xa56b, 0xa56b }, +/* 0xa56c */ { false, 0xa56c, 0xa56c }, +/* 0xa56d */ { false, 0xa56d, 0xa56d }, +/* 0xa56e */ { false, 0xa56e, 0xa56e }, +/* 0xa56f */ { false, 0xa56f, 0xa56f }, +/* 0xa570 */ { false, 0xa570, 0xa570 }, +/* 0xa571 */ { false, 0xa571, 0xa571 }, +/* 0xa572 */ { false, 0xa572, 0xa572 }, +/* 0xa573 */ { false, 0xa573, 0xa573 }, +/* 0xa574 */ { false, 0xa574, 0xa574 }, +/* 0xa575 */ { false, 0xa575, 0xa575 }, +/* 0xa576 */ { false, 0xa576, 0xa576 }, +/* 0xa577 */ { false, 0xa577, 0xa577 }, +/* 0xa578 */ { false, 0xa578, 0xa578 }, +/* 0xa579 */ { false, 0xa579, 0xa579 }, +/* 0xa57a */ { false, 0xa57a, 0xa57a }, +/* 0xa57b */ { false, 0xa57b, 0xa57b }, +/* 0xa57c */ { false, 0xa57c, 0xa57c }, +/* 0xa57d */ { false, 0xa57d, 0xa57d }, +/* 0xa57e */ { false, 0xa57e, 0xa57e }, +/* 0xa57f */ { false, 0xa57f, 0xa57f }, +/* 0xa580 */ { false, 0xa580, 0xa580 }, +/* 0xa581 */ { false, 0xa581, 0xa581 }, +/* 0xa582 */ { false, 0xa582, 0xa582 }, +/* 0xa583 */ { false, 0xa583, 0xa583 }, +/* 0xa584 */ { false, 0xa584, 0xa584 }, +/* 0xa585 */ { false, 0xa585, 0xa585 }, +/* 0xa586 */ { false, 0xa586, 0xa586 }, +/* 0xa587 */ { false, 0xa587, 0xa587 }, +/* 0xa588 */ { false, 0xa588, 0xa588 }, +/* 0xa589 */ { false, 0xa589, 0xa589 }, +/* 0xa58a */ { false, 0xa58a, 0xa58a }, +/* 0xa58b */ { false, 0xa58b, 0xa58b }, +/* 0xa58c */ { false, 0xa58c, 0xa58c }, +/* 0xa58d */ { false, 0xa58d, 0xa58d }, +/* 0xa58e */ { false, 0xa58e, 0xa58e }, +/* 0xa58f */ { false, 0xa58f, 0xa58f }, +/* 0xa590 */ { false, 0xa590, 0xa590 }, +/* 0xa591 */ { false, 0xa591, 0xa591 }, +/* 0xa592 */ { false, 0xa592, 0xa592 }, +/* 0xa593 */ { false, 0xa593, 0xa593 }, +/* 0xa594 */ { false, 0xa594, 0xa594 }, +/* 0xa595 */ { false, 0xa595, 0xa595 }, +/* 0xa596 */ { false, 0xa596, 0xa596 }, +/* 0xa597 */ { false, 0xa597, 0xa597 }, +/* 0xa598 */ { false, 0xa598, 0xa598 }, +/* 0xa599 */ { false, 0xa599, 0xa599 }, +/* 0xa59a */ { false, 0xa59a, 0xa59a }, +/* 0xa59b */ { false, 0xa59b, 0xa59b }, +/* 0xa59c */ { false, 0xa59c, 0xa59c }, +/* 0xa59d */ { false, 0xa59d, 0xa59d }, +/* 0xa59e */ { false, 0xa59e, 0xa59e }, +/* 0xa59f */ { false, 0xa59f, 0xa59f }, +/* 0xa5a0 */ { false, 0xa5a0, 0xa5a0 }, +/* 0xa5a1 */ { false, 0xa5a1, 0xa5a1 }, +/* 0xa5a2 */ { false, 0xa5a2, 0xa5a2 }, +/* 0xa5a3 */ { false, 0xa5a3, 0xa5a3 }, +/* 0xa5a4 */ { false, 0xa5a4, 0xa5a4 }, +/* 0xa5a5 */ { false, 0xa5a5, 0xa5a5 }, +/* 0xa5a6 */ { false, 0xa5a6, 0xa5a6 }, +/* 0xa5a7 */ { false, 0xa5a7, 0xa5a7 }, +/* 0xa5a8 */ { false, 0xa5a8, 0xa5a8 }, +/* 0xa5a9 */ { false, 0xa5a9, 0xa5a9 }, +/* 0xa5aa */ { false, 0xa5aa, 0xa5aa }, +/* 0xa5ab */ { false, 0xa5ab, 0xa5ab }, +/* 0xa5ac */ { false, 0xa5ac, 0xa5ac }, +/* 0xa5ad */ { false, 0xa5ad, 0xa5ad }, +/* 0xa5ae */ { false, 0xa5ae, 0xa5ae }, +/* 0xa5af */ { false, 0xa5af, 0xa5af }, +/* 0xa5b0 */ { false, 0xa5b0, 0xa5b0 }, +/* 0xa5b1 */ { false, 0xa5b1, 0xa5b1 }, +/* 0xa5b2 */ { false, 0xa5b2, 0xa5b2 }, +/* 0xa5b3 */ { false, 0xa5b3, 0xa5b3 }, +/* 0xa5b4 */ { false, 0xa5b4, 0xa5b4 }, +/* 0xa5b5 */ { false, 0xa5b5, 0xa5b5 }, +/* 0xa5b6 */ { false, 0xa5b6, 0xa5b6 }, +/* 0xa5b7 */ { false, 0xa5b7, 0xa5b7 }, +/* 0xa5b8 */ { false, 0xa5b8, 0xa5b8 }, +/* 0xa5b9 */ { false, 0xa5b9, 0xa5b9 }, +/* 0xa5ba */ { false, 0xa5ba, 0xa5ba }, +/* 0xa5bb */ { false, 0xa5bb, 0xa5bb }, +/* 0xa5bc */ { false, 0xa5bc, 0xa5bc }, +/* 0xa5bd */ { false, 0xa5bd, 0xa5bd }, +/* 0xa5be */ { false, 0xa5be, 0xa5be }, +/* 0xa5bf */ { false, 0xa5bf, 0xa5bf }, +/* 0xa5c0 */ { false, 0xa5c0, 0xa5c0 }, +/* 0xa5c1 */ { false, 0xa5c1, 0xa5c1 }, +/* 0xa5c2 */ { false, 0xa5c2, 0xa5c2 }, +/* 0xa5c3 */ { false, 0xa5c3, 0xa5c3 }, +/* 0xa5c4 */ { false, 0xa5c4, 0xa5c4 }, +/* 0xa5c5 */ { false, 0xa5c5, 0xa5c5 }, +/* 0xa5c6 */ { false, 0xa5c6, 0xa5c6 }, +/* 0xa5c7 */ { false, 0xa5c7, 0xa5c7 }, +/* 0xa5c8 */ { false, 0xa5c8, 0xa5c8 }, +/* 0xa5c9 */ { false, 0xa5c9, 0xa5c9 }, +/* 0xa5ca */ { false, 0xa5ca, 0xa5ca }, +/* 0xa5cb */ { false, 0xa5cb, 0xa5cb }, +/* 0xa5cc */ { false, 0xa5cc, 0xa5cc }, +/* 0xa5cd */ { false, 0xa5cd, 0xa5cd }, +/* 0xa5ce */ { false, 0xa5ce, 0xa5ce }, +/* 0xa5cf */ { false, 0xa5cf, 0xa5cf }, +/* 0xa5d0 */ { false, 0xa5d0, 0xa5d0 }, +/* 0xa5d1 */ { false, 0xa5d1, 0xa5d1 }, +/* 0xa5d2 */ { false, 0xa5d2, 0xa5d2 }, +/* 0xa5d3 */ { false, 0xa5d3, 0xa5d3 }, +/* 0xa5d4 */ { false, 0xa5d4, 0xa5d4 }, +/* 0xa5d5 */ { false, 0xa5d5, 0xa5d5 }, +/* 0xa5d6 */ { false, 0xa5d6, 0xa5d6 }, +/* 0xa5d7 */ { false, 0xa5d7, 0xa5d7 }, +/* 0xa5d8 */ { false, 0xa5d8, 0xa5d8 }, +/* 0xa5d9 */ { false, 0xa5d9, 0xa5d9 }, +/* 0xa5da */ { false, 0xa5da, 0xa5da }, +/* 0xa5db */ { false, 0xa5db, 0xa5db }, +/* 0xa5dc */ { false, 0xa5dc, 0xa5dc }, +/* 0xa5dd */ { false, 0xa5dd, 0xa5dd }, +/* 0xa5de */ { false, 0xa5de, 0xa5de }, +/* 0xa5df */ { false, 0xa5df, 0xa5df }, +/* 0xa5e0 */ { false, 0xa5e0, 0xa5e0 }, +/* 0xa5e1 */ { false, 0xa5e1, 0xa5e1 }, +/* 0xa5e2 */ { false, 0xa5e2, 0xa5e2 }, +/* 0xa5e3 */ { false, 0xa5e3, 0xa5e3 }, +/* 0xa5e4 */ { false, 0xa5e4, 0xa5e4 }, +/* 0xa5e5 */ { false, 0xa5e5, 0xa5e5 }, +/* 0xa5e6 */ { false, 0xa5e6, 0xa5e6 }, +/* 0xa5e7 */ { false, 0xa5e7, 0xa5e7 }, +/* 0xa5e8 */ { false, 0xa5e8, 0xa5e8 }, +/* 0xa5e9 */ { false, 0xa5e9, 0xa5e9 }, +/* 0xa5ea */ { false, 0xa5ea, 0xa5ea }, +/* 0xa5eb */ { false, 0xa5eb, 0xa5eb }, +/* 0xa5ec */ { false, 0xa5ec, 0xa5ec }, +/* 0xa5ed */ { false, 0xa5ed, 0xa5ed }, +/* 0xa5ee */ { false, 0xa5ee, 0xa5ee }, +/* 0xa5ef */ { false, 0xa5ef, 0xa5ef }, +/* 0xa5f0 */ { false, 0xa5f0, 0xa5f0 }, +/* 0xa5f1 */ { false, 0xa5f1, 0xa5f1 }, +/* 0xa5f2 */ { false, 0xa5f2, 0xa5f2 }, +/* 0xa5f3 */ { false, 0xa5f3, 0xa5f3 }, +/* 0xa5f4 */ { false, 0xa5f4, 0xa5f4 }, +/* 0xa5f5 */ { false, 0xa5f5, 0xa5f5 }, +/* 0xa5f6 */ { false, 0xa5f6, 0xa5f6 }, +/* 0xa5f7 */ { false, 0xa5f7, 0xa5f7 }, +/* 0xa5f8 */ { false, 0xa5f8, 0xa5f8 }, +/* 0xa5f9 */ { false, 0xa5f9, 0xa5f9 }, +/* 0xa5fa */ { false, 0xa5fa, 0xa5fa }, +/* 0xa5fb */ { false, 0xa5fb, 0xa5fb }, +/* 0xa5fc */ { false, 0xa5fc, 0xa5fc }, +/* 0xa5fd */ { false, 0xa5fd, 0xa5fd }, +/* 0xa5fe */ { false, 0xa5fe, 0xa5fe }, +/* 0xa5ff */ { false, 0xa5ff, 0xa5ff }, +/* 0xa600 */ { false, 0xa600, 0xa600 }, +/* 0xa601 */ { false, 0xa601, 0xa601 }, +/* 0xa602 */ { false, 0xa602, 0xa602 }, +/* 0xa603 */ { false, 0xa603, 0xa603 }, +/* 0xa604 */ { false, 0xa604, 0xa604 }, +/* 0xa605 */ { false, 0xa605, 0xa605 }, +/* 0xa606 */ { false, 0xa606, 0xa606 }, +/* 0xa607 */ { false, 0xa607, 0xa607 }, +/* 0xa608 */ { false, 0xa608, 0xa608 }, +/* 0xa609 */ { false, 0xa609, 0xa609 }, +/* 0xa60a */ { false, 0xa60a, 0xa60a }, +/* 0xa60b */ { false, 0xa60b, 0xa60b }, +/* 0xa60c */ { false, 0xa60c, 0xa60c }, +/* 0xa60d */ { false, 0xa60d, 0xa60d }, +/* 0xa60e */ { false, 0xa60e, 0xa60e }, +/* 0xa60f */ { false, 0xa60f, 0xa60f }, +/* 0xa610 */ { false, 0xa610, 0xa610 }, +/* 0xa611 */ { false, 0xa611, 0xa611 }, +/* 0xa612 */ { false, 0xa612, 0xa612 }, +/* 0xa613 */ { false, 0xa613, 0xa613 }, +/* 0xa614 */ { false, 0xa614, 0xa614 }, +/* 0xa615 */ { false, 0xa615, 0xa615 }, +/* 0xa616 */ { false, 0xa616, 0xa616 }, +/* 0xa617 */ { false, 0xa617, 0xa617 }, +/* 0xa618 */ { false, 0xa618, 0xa618 }, +/* 0xa619 */ { false, 0xa619, 0xa619 }, +/* 0xa61a */ { false, 0xa61a, 0xa61a }, +/* 0xa61b */ { false, 0xa61b, 0xa61b }, +/* 0xa61c */ { false, 0xa61c, 0xa61c }, +/* 0xa61d */ { false, 0xa61d, 0xa61d }, +/* 0xa61e */ { false, 0xa61e, 0xa61e }, +/* 0xa61f */ { false, 0xa61f, 0xa61f }, +/* 0xa620 */ { false, 0xa620, 0xa620 }, +/* 0xa621 */ { false, 0xa621, 0xa621 }, +/* 0xa622 */ { false, 0xa622, 0xa622 }, +/* 0xa623 */ { false, 0xa623, 0xa623 }, +/* 0xa624 */ { false, 0xa624, 0xa624 }, +/* 0xa625 */ { false, 0xa625, 0xa625 }, +/* 0xa626 */ { false, 0xa626, 0xa626 }, +/* 0xa627 */ { false, 0xa627, 0xa627 }, +/* 0xa628 */ { false, 0xa628, 0xa628 }, +/* 0xa629 */ { false, 0xa629, 0xa629 }, +/* 0xa62a */ { false, 0xa62a, 0xa62a }, +/* 0xa62b */ { false, 0xa62b, 0xa62b }, +/* 0xa62c */ { false, 0xa62c, 0xa62c }, +/* 0xa62d */ { false, 0xa62d, 0xa62d }, +/* 0xa62e */ { false, 0xa62e, 0xa62e }, +/* 0xa62f */ { false, 0xa62f, 0xa62f }, +/* 0xa630 */ { false, 0xa630, 0xa630 }, +/* 0xa631 */ { false, 0xa631, 0xa631 }, +/* 0xa632 */ { false, 0xa632, 0xa632 }, +/* 0xa633 */ { false, 0xa633, 0xa633 }, +/* 0xa634 */ { false, 0xa634, 0xa634 }, +/* 0xa635 */ { false, 0xa635, 0xa635 }, +/* 0xa636 */ { false, 0xa636, 0xa636 }, +/* 0xa637 */ { false, 0xa637, 0xa637 }, +/* 0xa638 */ { false, 0xa638, 0xa638 }, +/* 0xa639 */ { false, 0xa639, 0xa639 }, +/* 0xa63a */ { false, 0xa63a, 0xa63a }, +/* 0xa63b */ { false, 0xa63b, 0xa63b }, +/* 0xa63c */ { false, 0xa63c, 0xa63c }, +/* 0xa63d */ { false, 0xa63d, 0xa63d }, +/* 0xa63e */ { false, 0xa63e, 0xa63e }, +/* 0xa63f */ { false, 0xa63f, 0xa63f }, +/* 0xa640 */ { false, 0xa640, 0xa640 }, +/* 0xa641 */ { false, 0xa641, 0xa641 }, +/* 0xa642 */ { false, 0xa642, 0xa642 }, +/* 0xa643 */ { false, 0xa643, 0xa643 }, +/* 0xa644 */ { false, 0xa644, 0xa644 }, +/* 0xa645 */ { false, 0xa645, 0xa645 }, +/* 0xa646 */ { false, 0xa646, 0xa646 }, +/* 0xa647 */ { false, 0xa647, 0xa647 }, +/* 0xa648 */ { false, 0xa648, 0xa648 }, +/* 0xa649 */ { false, 0xa649, 0xa649 }, +/* 0xa64a */ { false, 0xa64a, 0xa64a }, +/* 0xa64b */ { false, 0xa64b, 0xa64b }, +/* 0xa64c */ { false, 0xa64c, 0xa64c }, +/* 0xa64d */ { false, 0xa64d, 0xa64d }, +/* 0xa64e */ { false, 0xa64e, 0xa64e }, +/* 0xa64f */ { false, 0xa64f, 0xa64f }, +/* 0xa650 */ { false, 0xa650, 0xa650 }, +/* 0xa651 */ { false, 0xa651, 0xa651 }, +/* 0xa652 */ { false, 0xa652, 0xa652 }, +/* 0xa653 */ { false, 0xa653, 0xa653 }, +/* 0xa654 */ { false, 0xa654, 0xa654 }, +/* 0xa655 */ { false, 0xa655, 0xa655 }, +/* 0xa656 */ { false, 0xa656, 0xa656 }, +/* 0xa657 */ { false, 0xa657, 0xa657 }, +/* 0xa658 */ { false, 0xa658, 0xa658 }, +/* 0xa659 */ { false, 0xa659, 0xa659 }, +/* 0xa65a */ { false, 0xa65a, 0xa65a }, +/* 0xa65b */ { false, 0xa65b, 0xa65b }, +/* 0xa65c */ { false, 0xa65c, 0xa65c }, +/* 0xa65d */ { false, 0xa65d, 0xa65d }, +/* 0xa65e */ { false, 0xa65e, 0xa65e }, +/* 0xa65f */ { false, 0xa65f, 0xa65f }, +/* 0xa660 */ { false, 0xa660, 0xa660 }, +/* 0xa661 */ { false, 0xa661, 0xa661 }, +/* 0xa662 */ { false, 0xa662, 0xa662 }, +/* 0xa663 */ { false, 0xa663, 0xa663 }, +/* 0xa664 */ { false, 0xa664, 0xa664 }, +/* 0xa665 */ { false, 0xa665, 0xa665 }, +/* 0xa666 */ { false, 0xa666, 0xa666 }, +/* 0xa667 */ { false, 0xa667, 0xa667 }, +/* 0xa668 */ { false, 0xa668, 0xa668 }, +/* 0xa669 */ { false, 0xa669, 0xa669 }, +/* 0xa66a */ { false, 0xa66a, 0xa66a }, +/* 0xa66b */ { false, 0xa66b, 0xa66b }, +/* 0xa66c */ { false, 0xa66c, 0xa66c }, +/* 0xa66d */ { false, 0xa66d, 0xa66d }, +/* 0xa66e */ { false, 0xa66e, 0xa66e }, +/* 0xa66f */ { false, 0xa66f, 0xa66f }, +/* 0xa670 */ { false, 0xa670, 0xa670 }, +/* 0xa671 */ { false, 0xa671, 0xa671 }, +/* 0xa672 */ { false, 0xa672, 0xa672 }, +/* 0xa673 */ { false, 0xa673, 0xa673 }, +/* 0xa674 */ { false, 0xa674, 0xa674 }, +/* 0xa675 */ { false, 0xa675, 0xa675 }, +/* 0xa676 */ { false, 0xa676, 0xa676 }, +/* 0xa677 */ { false, 0xa677, 0xa677 }, +/* 0xa678 */ { false, 0xa678, 0xa678 }, +/* 0xa679 */ { false, 0xa679, 0xa679 }, +/* 0xa67a */ { false, 0xa67a, 0xa67a }, +/* 0xa67b */ { false, 0xa67b, 0xa67b }, +/* 0xa67c */ { false, 0xa67c, 0xa67c }, +/* 0xa67d */ { false, 0xa67d, 0xa67d }, +/* 0xa67e */ { false, 0xa67e, 0xa67e }, +/* 0xa67f */ { false, 0xa67f, 0xa67f }, +/* 0xa680 */ { false, 0xa680, 0xa680 }, +/* 0xa681 */ { false, 0xa681, 0xa681 }, +/* 0xa682 */ { false, 0xa682, 0xa682 }, +/* 0xa683 */ { false, 0xa683, 0xa683 }, +/* 0xa684 */ { false, 0xa684, 0xa684 }, +/* 0xa685 */ { false, 0xa685, 0xa685 }, +/* 0xa686 */ { false, 0xa686, 0xa686 }, +/* 0xa687 */ { false, 0xa687, 0xa687 }, +/* 0xa688 */ { false, 0xa688, 0xa688 }, +/* 0xa689 */ { false, 0xa689, 0xa689 }, +/* 0xa68a */ { false, 0xa68a, 0xa68a }, +/* 0xa68b */ { false, 0xa68b, 0xa68b }, +/* 0xa68c */ { false, 0xa68c, 0xa68c }, +/* 0xa68d */ { false, 0xa68d, 0xa68d }, +/* 0xa68e */ { false, 0xa68e, 0xa68e }, +/* 0xa68f */ { false, 0xa68f, 0xa68f }, +/* 0xa690 */ { false, 0xa690, 0xa690 }, +/* 0xa691 */ { false, 0xa691, 0xa691 }, +/* 0xa692 */ { false, 0xa692, 0xa692 }, +/* 0xa693 */ { false, 0xa693, 0xa693 }, +/* 0xa694 */ { false, 0xa694, 0xa694 }, +/* 0xa695 */ { false, 0xa695, 0xa695 }, +/* 0xa696 */ { false, 0xa696, 0xa696 }, +/* 0xa697 */ { false, 0xa697, 0xa697 }, +/* 0xa698 */ { false, 0xa698, 0xa698 }, +/* 0xa699 */ { false, 0xa699, 0xa699 }, +/* 0xa69a */ { false, 0xa69a, 0xa69a }, +/* 0xa69b */ { false, 0xa69b, 0xa69b }, +/* 0xa69c */ { false, 0xa69c, 0xa69c }, +/* 0xa69d */ { false, 0xa69d, 0xa69d }, +/* 0xa69e */ { false, 0xa69e, 0xa69e }, +/* 0xa69f */ { false, 0xa69f, 0xa69f }, +/* 0xa6a0 */ { false, 0xa6a0, 0xa6a0 }, +/* 0xa6a1 */ { false, 0xa6a1, 0xa6a1 }, +/* 0xa6a2 */ { false, 0xa6a2, 0xa6a2 }, +/* 0xa6a3 */ { false, 0xa6a3, 0xa6a3 }, +/* 0xa6a4 */ { false, 0xa6a4, 0xa6a4 }, +/* 0xa6a5 */ { false, 0xa6a5, 0xa6a5 }, +/* 0xa6a6 */ { false, 0xa6a6, 0xa6a6 }, +/* 0xa6a7 */ { false, 0xa6a7, 0xa6a7 }, +/* 0xa6a8 */ { false, 0xa6a8, 0xa6a8 }, +/* 0xa6a9 */ { false, 0xa6a9, 0xa6a9 }, +/* 0xa6aa */ { false, 0xa6aa, 0xa6aa }, +/* 0xa6ab */ { false, 0xa6ab, 0xa6ab }, +/* 0xa6ac */ { false, 0xa6ac, 0xa6ac }, +/* 0xa6ad */ { false, 0xa6ad, 0xa6ad }, +/* 0xa6ae */ { false, 0xa6ae, 0xa6ae }, +/* 0xa6af */ { false, 0xa6af, 0xa6af }, +/* 0xa6b0 */ { false, 0xa6b0, 0xa6b0 }, +/* 0xa6b1 */ { false, 0xa6b1, 0xa6b1 }, +/* 0xa6b2 */ { false, 0xa6b2, 0xa6b2 }, +/* 0xa6b3 */ { false, 0xa6b3, 0xa6b3 }, +/* 0xa6b4 */ { false, 0xa6b4, 0xa6b4 }, +/* 0xa6b5 */ { false, 0xa6b5, 0xa6b5 }, +/* 0xa6b6 */ { false, 0xa6b6, 0xa6b6 }, +/* 0xa6b7 */ { false, 0xa6b7, 0xa6b7 }, +/* 0xa6b8 */ { false, 0xa6b8, 0xa6b8 }, +/* 0xa6b9 */ { false, 0xa6b9, 0xa6b9 }, +/* 0xa6ba */ { false, 0xa6ba, 0xa6ba }, +/* 0xa6bb */ { false, 0xa6bb, 0xa6bb }, +/* 0xa6bc */ { false, 0xa6bc, 0xa6bc }, +/* 0xa6bd */ { false, 0xa6bd, 0xa6bd }, +/* 0xa6be */ { false, 0xa6be, 0xa6be }, +/* 0xa6bf */ { false, 0xa6bf, 0xa6bf }, +/* 0xa6c0 */ { false, 0xa6c0, 0xa6c0 }, +/* 0xa6c1 */ { false, 0xa6c1, 0xa6c1 }, +/* 0xa6c2 */ { false, 0xa6c2, 0xa6c2 }, +/* 0xa6c3 */ { false, 0xa6c3, 0xa6c3 }, +/* 0xa6c4 */ { false, 0xa6c4, 0xa6c4 }, +/* 0xa6c5 */ { false, 0xa6c5, 0xa6c5 }, +/* 0xa6c6 */ { false, 0xa6c6, 0xa6c6 }, +/* 0xa6c7 */ { false, 0xa6c7, 0xa6c7 }, +/* 0xa6c8 */ { false, 0xa6c8, 0xa6c8 }, +/* 0xa6c9 */ { false, 0xa6c9, 0xa6c9 }, +/* 0xa6ca */ { false, 0xa6ca, 0xa6ca }, +/* 0xa6cb */ { false, 0xa6cb, 0xa6cb }, +/* 0xa6cc */ { false, 0xa6cc, 0xa6cc }, +/* 0xa6cd */ { false, 0xa6cd, 0xa6cd }, +/* 0xa6ce */ { false, 0xa6ce, 0xa6ce }, +/* 0xa6cf */ { false, 0xa6cf, 0xa6cf }, +/* 0xa6d0 */ { false, 0xa6d0, 0xa6d0 }, +/* 0xa6d1 */ { false, 0xa6d1, 0xa6d1 }, +/* 0xa6d2 */ { false, 0xa6d2, 0xa6d2 }, +/* 0xa6d3 */ { false, 0xa6d3, 0xa6d3 }, +/* 0xa6d4 */ { false, 0xa6d4, 0xa6d4 }, +/* 0xa6d5 */ { false, 0xa6d5, 0xa6d5 }, +/* 0xa6d6 */ { false, 0xa6d6, 0xa6d6 }, +/* 0xa6d7 */ { false, 0xa6d7, 0xa6d7 }, +/* 0xa6d8 */ { false, 0xa6d8, 0xa6d8 }, +/* 0xa6d9 */ { false, 0xa6d9, 0xa6d9 }, +/* 0xa6da */ { false, 0xa6da, 0xa6da }, +/* 0xa6db */ { false, 0xa6db, 0xa6db }, +/* 0xa6dc */ { false, 0xa6dc, 0xa6dc }, +/* 0xa6dd */ { false, 0xa6dd, 0xa6dd }, +/* 0xa6de */ { false, 0xa6de, 0xa6de }, +/* 0xa6df */ { false, 0xa6df, 0xa6df }, +/* 0xa6e0 */ { false, 0xa6e0, 0xa6e0 }, +/* 0xa6e1 */ { false, 0xa6e1, 0xa6e1 }, +/* 0xa6e2 */ { false, 0xa6e2, 0xa6e2 }, +/* 0xa6e3 */ { false, 0xa6e3, 0xa6e3 }, +/* 0xa6e4 */ { false, 0xa6e4, 0xa6e4 }, +/* 0xa6e5 */ { false, 0xa6e5, 0xa6e5 }, +/* 0xa6e6 */ { false, 0xa6e6, 0xa6e6 }, +/* 0xa6e7 */ { false, 0xa6e7, 0xa6e7 }, +/* 0xa6e8 */ { false, 0xa6e8, 0xa6e8 }, +/* 0xa6e9 */ { false, 0xa6e9, 0xa6e9 }, +/* 0xa6ea */ { false, 0xa6ea, 0xa6ea }, +/* 0xa6eb */ { false, 0xa6eb, 0xa6eb }, +/* 0xa6ec */ { false, 0xa6ec, 0xa6ec }, +/* 0xa6ed */ { false, 0xa6ed, 0xa6ed }, +/* 0xa6ee */ { false, 0xa6ee, 0xa6ee }, +/* 0xa6ef */ { false, 0xa6ef, 0xa6ef }, +/* 0xa6f0 */ { false, 0xa6f0, 0xa6f0 }, +/* 0xa6f1 */ { false, 0xa6f1, 0xa6f1 }, +/* 0xa6f2 */ { false, 0xa6f2, 0xa6f2 }, +/* 0xa6f3 */ { false, 0xa6f3, 0xa6f3 }, +/* 0xa6f4 */ { false, 0xa6f4, 0xa6f4 }, +/* 0xa6f5 */ { false, 0xa6f5, 0xa6f5 }, +/* 0xa6f6 */ { false, 0xa6f6, 0xa6f6 }, +/* 0xa6f7 */ { false, 0xa6f7, 0xa6f7 }, +/* 0xa6f8 */ { false, 0xa6f8, 0xa6f8 }, +/* 0xa6f9 */ { false, 0xa6f9, 0xa6f9 }, +/* 0xa6fa */ { false, 0xa6fa, 0xa6fa }, +/* 0xa6fb */ { false, 0xa6fb, 0xa6fb }, +/* 0xa6fc */ { false, 0xa6fc, 0xa6fc }, +/* 0xa6fd */ { false, 0xa6fd, 0xa6fd }, +/* 0xa6fe */ { false, 0xa6fe, 0xa6fe }, +/* 0xa6ff */ { false, 0xa6ff, 0xa6ff }, +/* 0xa700 */ { false, 0xa700, 0xa700 }, +/* 0xa701 */ { false, 0xa701, 0xa701 }, +/* 0xa702 */ { false, 0xa702, 0xa702 }, +/* 0xa703 */ { false, 0xa703, 0xa703 }, +/* 0xa704 */ { false, 0xa704, 0xa704 }, +/* 0xa705 */ { false, 0xa705, 0xa705 }, +/* 0xa706 */ { false, 0xa706, 0xa706 }, +/* 0xa707 */ { false, 0xa707, 0xa707 }, +/* 0xa708 */ { false, 0xa708, 0xa708 }, +/* 0xa709 */ { false, 0xa709, 0xa709 }, +/* 0xa70a */ { false, 0xa70a, 0xa70a }, +/* 0xa70b */ { false, 0xa70b, 0xa70b }, +/* 0xa70c */ { false, 0xa70c, 0xa70c }, +/* 0xa70d */ { false, 0xa70d, 0xa70d }, +/* 0xa70e */ { false, 0xa70e, 0xa70e }, +/* 0xa70f */ { false, 0xa70f, 0xa70f }, +/* 0xa710 */ { false, 0xa710, 0xa710 }, +/* 0xa711 */ { false, 0xa711, 0xa711 }, +/* 0xa712 */ { false, 0xa712, 0xa712 }, +/* 0xa713 */ { false, 0xa713, 0xa713 }, +/* 0xa714 */ { false, 0xa714, 0xa714 }, +/* 0xa715 */ { false, 0xa715, 0xa715 }, +/* 0xa716 */ { false, 0xa716, 0xa716 }, +/* 0xa717 */ { false, 0xa717, 0xa717 }, +/* 0xa718 */ { false, 0xa718, 0xa718 }, +/* 0xa719 */ { false, 0xa719, 0xa719 }, +/* 0xa71a */ { false, 0xa71a, 0xa71a }, +/* 0xa71b */ { false, 0xa71b, 0xa71b }, +/* 0xa71c */ { false, 0xa71c, 0xa71c }, +/* 0xa71d */ { false, 0xa71d, 0xa71d }, +/* 0xa71e */ { false, 0xa71e, 0xa71e }, +/* 0xa71f */ { false, 0xa71f, 0xa71f }, +/* 0xa720 */ { false, 0xa720, 0xa720 }, +/* 0xa721 */ { false, 0xa721, 0xa721 }, +/* 0xa722 */ { false, 0xa722, 0xa722 }, +/* 0xa723 */ { false, 0xa723, 0xa723 }, +/* 0xa724 */ { false, 0xa724, 0xa724 }, +/* 0xa725 */ { false, 0xa725, 0xa725 }, +/* 0xa726 */ { false, 0xa726, 0xa726 }, +/* 0xa727 */ { false, 0xa727, 0xa727 }, +/* 0xa728 */ { false, 0xa728, 0xa728 }, +/* 0xa729 */ { false, 0xa729, 0xa729 }, +/* 0xa72a */ { false, 0xa72a, 0xa72a }, +/* 0xa72b */ { false, 0xa72b, 0xa72b }, +/* 0xa72c */ { false, 0xa72c, 0xa72c }, +/* 0xa72d */ { false, 0xa72d, 0xa72d }, +/* 0xa72e */ { false, 0xa72e, 0xa72e }, +/* 0xa72f */ { false, 0xa72f, 0xa72f }, +/* 0xa730 */ { false, 0xa730, 0xa730 }, +/* 0xa731 */ { false, 0xa731, 0xa731 }, +/* 0xa732 */ { false, 0xa732, 0xa732 }, +/* 0xa733 */ { false, 0xa733, 0xa733 }, +/* 0xa734 */ { false, 0xa734, 0xa734 }, +/* 0xa735 */ { false, 0xa735, 0xa735 }, +/* 0xa736 */ { false, 0xa736, 0xa736 }, +/* 0xa737 */ { false, 0xa737, 0xa737 }, +/* 0xa738 */ { false, 0xa738, 0xa738 }, +/* 0xa739 */ { false, 0xa739, 0xa739 }, +/* 0xa73a */ { false, 0xa73a, 0xa73a }, +/* 0xa73b */ { false, 0xa73b, 0xa73b }, +/* 0xa73c */ { false, 0xa73c, 0xa73c }, +/* 0xa73d */ { false, 0xa73d, 0xa73d }, +/* 0xa73e */ { false, 0xa73e, 0xa73e }, +/* 0xa73f */ { false, 0xa73f, 0xa73f }, +/* 0xa740 */ { false, 0xa740, 0xa740 }, +/* 0xa741 */ { false, 0xa741, 0xa741 }, +/* 0xa742 */ { false, 0xa742, 0xa742 }, +/* 0xa743 */ { false, 0xa743, 0xa743 }, +/* 0xa744 */ { false, 0xa744, 0xa744 }, +/* 0xa745 */ { false, 0xa745, 0xa745 }, +/* 0xa746 */ { false, 0xa746, 0xa746 }, +/* 0xa747 */ { false, 0xa747, 0xa747 }, +/* 0xa748 */ { false, 0xa748, 0xa748 }, +/* 0xa749 */ { false, 0xa749, 0xa749 }, +/* 0xa74a */ { false, 0xa74a, 0xa74a }, +/* 0xa74b */ { false, 0xa74b, 0xa74b }, +/* 0xa74c */ { false, 0xa74c, 0xa74c }, +/* 0xa74d */ { false, 0xa74d, 0xa74d }, +/* 0xa74e */ { false, 0xa74e, 0xa74e }, +/* 0xa74f */ { false, 0xa74f, 0xa74f }, +/* 0xa750 */ { false, 0xa750, 0xa750 }, +/* 0xa751 */ { false, 0xa751, 0xa751 }, +/* 0xa752 */ { false, 0xa752, 0xa752 }, +/* 0xa753 */ { false, 0xa753, 0xa753 }, +/* 0xa754 */ { false, 0xa754, 0xa754 }, +/* 0xa755 */ { false, 0xa755, 0xa755 }, +/* 0xa756 */ { false, 0xa756, 0xa756 }, +/* 0xa757 */ { false, 0xa757, 0xa757 }, +/* 0xa758 */ { false, 0xa758, 0xa758 }, +/* 0xa759 */ { false, 0xa759, 0xa759 }, +/* 0xa75a */ { false, 0xa75a, 0xa75a }, +/* 0xa75b */ { false, 0xa75b, 0xa75b }, +/* 0xa75c */ { false, 0xa75c, 0xa75c }, +/* 0xa75d */ { false, 0xa75d, 0xa75d }, +/* 0xa75e */ { false, 0xa75e, 0xa75e }, +/* 0xa75f */ { false, 0xa75f, 0xa75f }, +/* 0xa760 */ { false, 0xa760, 0xa760 }, +/* 0xa761 */ { false, 0xa761, 0xa761 }, +/* 0xa762 */ { false, 0xa762, 0xa762 }, +/* 0xa763 */ { false, 0xa763, 0xa763 }, +/* 0xa764 */ { false, 0xa764, 0xa764 }, +/* 0xa765 */ { false, 0xa765, 0xa765 }, +/* 0xa766 */ { false, 0xa766, 0xa766 }, +/* 0xa767 */ { false, 0xa767, 0xa767 }, +/* 0xa768 */ { false, 0xa768, 0xa768 }, +/* 0xa769 */ { false, 0xa769, 0xa769 }, +/* 0xa76a */ { false, 0xa76a, 0xa76a }, +/* 0xa76b */ { false, 0xa76b, 0xa76b }, +/* 0xa76c */ { false, 0xa76c, 0xa76c }, +/* 0xa76d */ { false, 0xa76d, 0xa76d }, +/* 0xa76e */ { false, 0xa76e, 0xa76e }, +/* 0xa76f */ { false, 0xa76f, 0xa76f }, +/* 0xa770 */ { false, 0xa770, 0xa770 }, +/* 0xa771 */ { false, 0xa771, 0xa771 }, +/* 0xa772 */ { false, 0xa772, 0xa772 }, +/* 0xa773 */ { false, 0xa773, 0xa773 }, +/* 0xa774 */ { false, 0xa774, 0xa774 }, +/* 0xa775 */ { false, 0xa775, 0xa775 }, +/* 0xa776 */ { false, 0xa776, 0xa776 }, +/* 0xa777 */ { false, 0xa777, 0xa777 }, +/* 0xa778 */ { false, 0xa778, 0xa778 }, +/* 0xa779 */ { false, 0xa779, 0xa779 }, +/* 0xa77a */ { false, 0xa77a, 0xa77a }, +/* 0xa77b */ { false, 0xa77b, 0xa77b }, +/* 0xa77c */ { false, 0xa77c, 0xa77c }, +/* 0xa77d */ { false, 0xa77d, 0xa77d }, +/* 0xa77e */ { false, 0xa77e, 0xa77e }, +/* 0xa77f */ { false, 0xa77f, 0xa77f }, +/* 0xa780 */ { false, 0xa780, 0xa780 }, +/* 0xa781 */ { false, 0xa781, 0xa781 }, +/* 0xa782 */ { false, 0xa782, 0xa782 }, +/* 0xa783 */ { false, 0xa783, 0xa783 }, +/* 0xa784 */ { false, 0xa784, 0xa784 }, +/* 0xa785 */ { false, 0xa785, 0xa785 }, +/* 0xa786 */ { false, 0xa786, 0xa786 }, +/* 0xa787 */ { false, 0xa787, 0xa787 }, +/* 0xa788 */ { false, 0xa788, 0xa788 }, +/* 0xa789 */ { false, 0xa789, 0xa789 }, +/* 0xa78a */ { false, 0xa78a, 0xa78a }, +/* 0xa78b */ { false, 0xa78b, 0xa78b }, +/* 0xa78c */ { false, 0xa78c, 0xa78c }, +/* 0xa78d */ { false, 0xa78d, 0xa78d }, +/* 0xa78e */ { false, 0xa78e, 0xa78e }, +/* 0xa78f */ { false, 0xa78f, 0xa78f }, +/* 0xa790 */ { false, 0xa790, 0xa790 }, +/* 0xa791 */ { false, 0xa791, 0xa791 }, +/* 0xa792 */ { false, 0xa792, 0xa792 }, +/* 0xa793 */ { false, 0xa793, 0xa793 }, +/* 0xa794 */ { false, 0xa794, 0xa794 }, +/* 0xa795 */ { false, 0xa795, 0xa795 }, +/* 0xa796 */ { false, 0xa796, 0xa796 }, +/* 0xa797 */ { false, 0xa797, 0xa797 }, +/* 0xa798 */ { false, 0xa798, 0xa798 }, +/* 0xa799 */ { false, 0xa799, 0xa799 }, +/* 0xa79a */ { false, 0xa79a, 0xa79a }, +/* 0xa79b */ { false, 0xa79b, 0xa79b }, +/* 0xa79c */ { false, 0xa79c, 0xa79c }, +/* 0xa79d */ { false, 0xa79d, 0xa79d }, +/* 0xa79e */ { false, 0xa79e, 0xa79e }, +/* 0xa79f */ { false, 0xa79f, 0xa79f }, +/* 0xa7a0 */ { false, 0xa7a0, 0xa7a0 }, +/* 0xa7a1 */ { false, 0xa7a1, 0xa7a1 }, +/* 0xa7a2 */ { false, 0xa7a2, 0xa7a2 }, +/* 0xa7a3 */ { false, 0xa7a3, 0xa7a3 }, +/* 0xa7a4 */ { false, 0xa7a4, 0xa7a4 }, +/* 0xa7a5 */ { false, 0xa7a5, 0xa7a5 }, +/* 0xa7a6 */ { false, 0xa7a6, 0xa7a6 }, +/* 0xa7a7 */ { false, 0xa7a7, 0xa7a7 }, +/* 0xa7a8 */ { false, 0xa7a8, 0xa7a8 }, +/* 0xa7a9 */ { false, 0xa7a9, 0xa7a9 }, +/* 0xa7aa */ { false, 0xa7aa, 0xa7aa }, +/* 0xa7ab */ { false, 0xa7ab, 0xa7ab }, +/* 0xa7ac */ { false, 0xa7ac, 0xa7ac }, +/* 0xa7ad */ { false, 0xa7ad, 0xa7ad }, +/* 0xa7ae */ { false, 0xa7ae, 0xa7ae }, +/* 0xa7af */ { false, 0xa7af, 0xa7af }, +/* 0xa7b0 */ { false, 0xa7b0, 0xa7b0 }, +/* 0xa7b1 */ { false, 0xa7b1, 0xa7b1 }, +/* 0xa7b2 */ { false, 0xa7b2, 0xa7b2 }, +/* 0xa7b3 */ { false, 0xa7b3, 0xa7b3 }, +/* 0xa7b4 */ { false, 0xa7b4, 0xa7b4 }, +/* 0xa7b5 */ { false, 0xa7b5, 0xa7b5 }, +/* 0xa7b6 */ { false, 0xa7b6, 0xa7b6 }, +/* 0xa7b7 */ { false, 0xa7b7, 0xa7b7 }, +/* 0xa7b8 */ { false, 0xa7b8, 0xa7b8 }, +/* 0xa7b9 */ { false, 0xa7b9, 0xa7b9 }, +/* 0xa7ba */ { false, 0xa7ba, 0xa7ba }, +/* 0xa7bb */ { false, 0xa7bb, 0xa7bb }, +/* 0xa7bc */ { false, 0xa7bc, 0xa7bc }, +/* 0xa7bd */ { false, 0xa7bd, 0xa7bd }, +/* 0xa7be */ { false, 0xa7be, 0xa7be }, +/* 0xa7bf */ { false, 0xa7bf, 0xa7bf }, +/* 0xa7c0 */ { false, 0xa7c0, 0xa7c0 }, +/* 0xa7c1 */ { false, 0xa7c1, 0xa7c1 }, +/* 0xa7c2 */ { false, 0xa7c2, 0xa7c2 }, +/* 0xa7c3 */ { false, 0xa7c3, 0xa7c3 }, +/* 0xa7c4 */ { false, 0xa7c4, 0xa7c4 }, +/* 0xa7c5 */ { false, 0xa7c5, 0xa7c5 }, +/* 0xa7c6 */ { false, 0xa7c6, 0xa7c6 }, +/* 0xa7c7 */ { false, 0xa7c7, 0xa7c7 }, +/* 0xa7c8 */ { false, 0xa7c8, 0xa7c8 }, +/* 0xa7c9 */ { false, 0xa7c9, 0xa7c9 }, +/* 0xa7ca */ { false, 0xa7ca, 0xa7ca }, +/* 0xa7cb */ { false, 0xa7cb, 0xa7cb }, +/* 0xa7cc */ { false, 0xa7cc, 0xa7cc }, +/* 0xa7cd */ { false, 0xa7cd, 0xa7cd }, +/* 0xa7ce */ { false, 0xa7ce, 0xa7ce }, +/* 0xa7cf */ { false, 0xa7cf, 0xa7cf }, +/* 0xa7d0 */ { false, 0xa7d0, 0xa7d0 }, +/* 0xa7d1 */ { false, 0xa7d1, 0xa7d1 }, +/* 0xa7d2 */ { false, 0xa7d2, 0xa7d2 }, +/* 0xa7d3 */ { false, 0xa7d3, 0xa7d3 }, +/* 0xa7d4 */ { false, 0xa7d4, 0xa7d4 }, +/* 0xa7d5 */ { false, 0xa7d5, 0xa7d5 }, +/* 0xa7d6 */ { false, 0xa7d6, 0xa7d6 }, +/* 0xa7d7 */ { false, 0xa7d7, 0xa7d7 }, +/* 0xa7d8 */ { false, 0xa7d8, 0xa7d8 }, +/* 0xa7d9 */ { false, 0xa7d9, 0xa7d9 }, +/* 0xa7da */ { false, 0xa7da, 0xa7da }, +/* 0xa7db */ { false, 0xa7db, 0xa7db }, +/* 0xa7dc */ { false, 0xa7dc, 0xa7dc }, +/* 0xa7dd */ { false, 0xa7dd, 0xa7dd }, +/* 0xa7de */ { false, 0xa7de, 0xa7de }, +/* 0xa7df */ { false, 0xa7df, 0xa7df }, +/* 0xa7e0 */ { false, 0xa7e0, 0xa7e0 }, +/* 0xa7e1 */ { false, 0xa7e1, 0xa7e1 }, +/* 0xa7e2 */ { false, 0xa7e2, 0xa7e2 }, +/* 0xa7e3 */ { false, 0xa7e3, 0xa7e3 }, +/* 0xa7e4 */ { false, 0xa7e4, 0xa7e4 }, +/* 0xa7e5 */ { false, 0xa7e5, 0xa7e5 }, +/* 0xa7e6 */ { false, 0xa7e6, 0xa7e6 }, +/* 0xa7e7 */ { false, 0xa7e7, 0xa7e7 }, +/* 0xa7e8 */ { false, 0xa7e8, 0xa7e8 }, +/* 0xa7e9 */ { false, 0xa7e9, 0xa7e9 }, +/* 0xa7ea */ { false, 0xa7ea, 0xa7ea }, +/* 0xa7eb */ { false, 0xa7eb, 0xa7eb }, +/* 0xa7ec */ { false, 0xa7ec, 0xa7ec }, +/* 0xa7ed */ { false, 0xa7ed, 0xa7ed }, +/* 0xa7ee */ { false, 0xa7ee, 0xa7ee }, +/* 0xa7ef */ { false, 0xa7ef, 0xa7ef }, +/* 0xa7f0 */ { false, 0xa7f0, 0xa7f0 }, +/* 0xa7f1 */ { false, 0xa7f1, 0xa7f1 }, +/* 0xa7f2 */ { false, 0xa7f2, 0xa7f2 }, +/* 0xa7f3 */ { false, 0xa7f3, 0xa7f3 }, +/* 0xa7f4 */ { false, 0xa7f4, 0xa7f4 }, +/* 0xa7f5 */ { false, 0xa7f5, 0xa7f5 }, +/* 0xa7f6 */ { false, 0xa7f6, 0xa7f6 }, +/* 0xa7f7 */ { false, 0xa7f7, 0xa7f7 }, +/* 0xa7f8 */ { false, 0xa7f8, 0xa7f8 }, +/* 0xa7f9 */ { false, 0xa7f9, 0xa7f9 }, +/* 0xa7fa */ { false, 0xa7fa, 0xa7fa }, +/* 0xa7fb */ { false, 0xa7fb, 0xa7fb }, +/* 0xa7fc */ { false, 0xa7fc, 0xa7fc }, +/* 0xa7fd */ { false, 0xa7fd, 0xa7fd }, +/* 0xa7fe */ { false, 0xa7fe, 0xa7fe }, +/* 0xa7ff */ { false, 0xa7ff, 0xa7ff }, +/* 0xa800 */ { true, 0xa800, 0xa800 }, +/* 0xa801 */ { true, 0xa801, 0xa801 }, +/* 0xa802 */ { false, 0xa802, 0xa802 }, +/* 0xa803 */ { true, 0xa803, 0xa803 }, +/* 0xa804 */ { true, 0xa804, 0xa804 }, +/* 0xa805 */ { true, 0xa805, 0xa805 }, +/* 0xa806 */ { true, 0xa806, 0xa806 }, +/* 0xa807 */ { true, 0xa807, 0xa807 }, +/* 0xa808 */ { true, 0xa808, 0xa808 }, +/* 0xa809 */ { true, 0xa809, 0xa809 }, +/* 0xa80a */ { true, 0xa80a, 0xa80a }, +/* 0xa80b */ { true, 0xa80b, 0xa80b }, +/* 0xa80c */ { true, 0xa80c, 0xa80c }, +/* 0xa80d */ { true, 0xa80d, 0xa80d }, +/* 0xa80e */ { true, 0xa80e, 0xa80e }, +/* 0xa80f */ { true, 0xa80f, 0xa80f }, +/* 0xa810 */ { true, 0xa810, 0xa810 }, +/* 0xa811 */ { true, 0xa811, 0xa811 }, +/* 0xa812 */ { true, 0xa812, 0xa812 }, +/* 0xa813 */ { true, 0xa813, 0xa813 }, +/* 0xa814 */ { true, 0xa814, 0xa814 }, +/* 0xa815 */ { true, 0xa815, 0xa815 }, +/* 0xa816 */ { true, 0xa816, 0xa816 }, +/* 0xa817 */ { true, 0xa817, 0xa817 }, +/* 0xa818 */ { true, 0xa818, 0xa818 }, +/* 0xa819 */ { true, 0xa819, 0xa819 }, +/* 0xa81a */ { true, 0xa81a, 0xa81a }, +/* 0xa81b */ { true, 0xa81b, 0xa81b }, +/* 0xa81c */ { true, 0xa81c, 0xa81c }, +/* 0xa81d */ { true, 0xa81d, 0xa81d }, +/* 0xa81e */ { true, 0xa81e, 0xa81e }, +/* 0xa81f */ { true, 0xa81f, 0xa81f }, +/* 0xa820 */ { true, 0xa820, 0xa820 }, +/* 0xa821 */ { true, 0xa821, 0xa821 }, +/* 0xa822 */ { true, 0xa822, 0xa822 }, +/* 0xa823 */ { true, 0xa823, 0xa823 }, +/* 0xa824 */ { true, 0xa824, 0xa824 }, +/* 0xa825 */ { true, 0xa825, 0xa825 }, +/* 0xa826 */ { true, 0xa826, 0xa826 }, +/* 0xa827 */ { true, 0xa827, 0xa827 }, +/* 0xa828 */ { false, 0xa828, 0xa828 }, +/* 0xa829 */ { false, 0xa829, 0xa829 }, +/* 0xa82a */ { false, 0xa82a, 0xa82a }, +/* 0xa82b */ { false, 0xa82b, 0xa82b }, +/* 0xa82c */ { false, 0xa82c, 0xa82c }, +/* 0xa82d */ { false, 0xa82d, 0xa82d }, +/* 0xa82e */ { false, 0xa82e, 0xa82e }, +/* 0xa82f */ { false, 0xa82f, 0xa82f }, +/* 0xa830 */ { false, 0xa830, 0xa830 }, +/* 0xa831 */ { false, 0xa831, 0xa831 }, +/* 0xa832 */ { false, 0xa832, 0xa832 }, +/* 0xa833 */ { false, 0xa833, 0xa833 }, +/* 0xa834 */ { false, 0xa834, 0xa834 }, +/* 0xa835 */ { false, 0xa835, 0xa835 }, +/* 0xa836 */ { false, 0xa836, 0xa836 }, +/* 0xa837 */ { false, 0xa837, 0xa837 }, +/* 0xa838 */ { false, 0xa838, 0xa838 }, +/* 0xa839 */ { false, 0xa839, 0xa839 }, +/* 0xa83a */ { false, 0xa83a, 0xa83a }, +/* 0xa83b */ { false, 0xa83b, 0xa83b }, +/* 0xa83c */ { false, 0xa83c, 0xa83c }, +/* 0xa83d */ { false, 0xa83d, 0xa83d }, +/* 0xa83e */ { false, 0xa83e, 0xa83e }, +/* 0xa83f */ { false, 0xa83f, 0xa83f }, +/* 0xa840 */ { false, 0xa840, 0xa840 }, +/* 0xa841 */ { false, 0xa841, 0xa841 }, +/* 0xa842 */ { false, 0xa842, 0xa842 }, +/* 0xa843 */ { false, 0xa843, 0xa843 }, +/* 0xa844 */ { false, 0xa844, 0xa844 }, +/* 0xa845 */ { false, 0xa845, 0xa845 }, +/* 0xa846 */ { false, 0xa846, 0xa846 }, +/* 0xa847 */ { false, 0xa847, 0xa847 }, +/* 0xa848 */ { false, 0xa848, 0xa848 }, +/* 0xa849 */ { false, 0xa849, 0xa849 }, +/* 0xa84a */ { false, 0xa84a, 0xa84a }, +/* 0xa84b */ { false, 0xa84b, 0xa84b }, +/* 0xa84c */ { false, 0xa84c, 0xa84c }, +/* 0xa84d */ { false, 0xa84d, 0xa84d }, +/* 0xa84e */ { false, 0xa84e, 0xa84e }, +/* 0xa84f */ { false, 0xa84f, 0xa84f }, +/* 0xa850 */ { false, 0xa850, 0xa850 }, +/* 0xa851 */ { false, 0xa851, 0xa851 }, +/* 0xa852 */ { false, 0xa852, 0xa852 }, +/* 0xa853 */ { false, 0xa853, 0xa853 }, +/* 0xa854 */ { false, 0xa854, 0xa854 }, +/* 0xa855 */ { false, 0xa855, 0xa855 }, +/* 0xa856 */ { false, 0xa856, 0xa856 }, +/* 0xa857 */ { false, 0xa857, 0xa857 }, +/* 0xa858 */ { false, 0xa858, 0xa858 }, +/* 0xa859 */ { false, 0xa859, 0xa859 }, +/* 0xa85a */ { false, 0xa85a, 0xa85a }, +/* 0xa85b */ { false, 0xa85b, 0xa85b }, +/* 0xa85c */ { false, 0xa85c, 0xa85c }, +/* 0xa85d */ { false, 0xa85d, 0xa85d }, +/* 0xa85e */ { false, 0xa85e, 0xa85e }, +/* 0xa85f */ { false, 0xa85f, 0xa85f }, +/* 0xa860 */ { false, 0xa860, 0xa860 }, +/* 0xa861 */ { false, 0xa861, 0xa861 }, +/* 0xa862 */ { false, 0xa862, 0xa862 }, +/* 0xa863 */ { false, 0xa863, 0xa863 }, +/* 0xa864 */ { false, 0xa864, 0xa864 }, +/* 0xa865 */ { false, 0xa865, 0xa865 }, +/* 0xa866 */ { false, 0xa866, 0xa866 }, +/* 0xa867 */ { false, 0xa867, 0xa867 }, +/* 0xa868 */ { false, 0xa868, 0xa868 }, +/* 0xa869 */ { false, 0xa869, 0xa869 }, +/* 0xa86a */ { false, 0xa86a, 0xa86a }, +/* 0xa86b */ { false, 0xa86b, 0xa86b }, +/* 0xa86c */ { false, 0xa86c, 0xa86c }, +/* 0xa86d */ { false, 0xa86d, 0xa86d }, +/* 0xa86e */ { false, 0xa86e, 0xa86e }, +/* 0xa86f */ { false, 0xa86f, 0xa86f }, +/* 0xa870 */ { false, 0xa870, 0xa870 }, +/* 0xa871 */ { false, 0xa871, 0xa871 }, +/* 0xa872 */ { false, 0xa872, 0xa872 }, +/* 0xa873 */ { false, 0xa873, 0xa873 }, +/* 0xa874 */ { false, 0xa874, 0xa874 }, +/* 0xa875 */ { false, 0xa875, 0xa875 }, +/* 0xa876 */ { false, 0xa876, 0xa876 }, +/* 0xa877 */ { false, 0xa877, 0xa877 }, +/* 0xa878 */ { false, 0xa878, 0xa878 }, +/* 0xa879 */ { false, 0xa879, 0xa879 }, +/* 0xa87a */ { false, 0xa87a, 0xa87a }, +/* 0xa87b */ { false, 0xa87b, 0xa87b }, +/* 0xa87c */ { false, 0xa87c, 0xa87c }, +/* 0xa87d */ { false, 0xa87d, 0xa87d }, +/* 0xa87e */ { false, 0xa87e, 0xa87e }, +/* 0xa87f */ { false, 0xa87f, 0xa87f }, +/* 0xa880 */ { true, 0xa880, 0xa880 }, +/* 0xa881 */ { true, 0xa881, 0xa881 }, +/* 0xa882 */ { false, 0xa882, 0xa882 }, +/* 0xa883 */ { false, 0xa883, 0xa883 }, +/* 0xa884 */ { false, 0xa884, 0xa884 }, +/* 0xa885 */ { false, 0xa885, 0xa885 }, +/* 0xa886 */ { false, 0xa886, 0xa886 }, +/* 0xa887 */ { false, 0xa887, 0xa887 }, +/* 0xa888 */ { false, 0xa888, 0xa888 }, +/* 0xa889 */ { false, 0xa889, 0xa889 }, +/* 0xa88a */ { false, 0xa88a, 0xa88a }, +/* 0xa88b */ { false, 0xa88b, 0xa88b }, +/* 0xa88c */ { false, 0xa88c, 0xa88c }, +/* 0xa88d */ { false, 0xa88d, 0xa88d }, +/* 0xa88e */ { false, 0xa88e, 0xa88e }, +/* 0xa88f */ { false, 0xa88f, 0xa88f }, +/* 0xa890 */ { false, 0xa890, 0xa890 }, +/* 0xa891 */ { false, 0xa891, 0xa891 }, +/* 0xa892 */ { false, 0xa892, 0xa892 }, +/* 0xa893 */ { false, 0xa893, 0xa893 }, +/* 0xa894 */ { false, 0xa894, 0xa894 }, +/* 0xa895 */ { false, 0xa895, 0xa895 }, +/* 0xa896 */ { false, 0xa896, 0xa896 }, +/* 0xa897 */ { false, 0xa897, 0xa897 }, +/* 0xa898 */ { false, 0xa898, 0xa898 }, +/* 0xa899 */ { false, 0xa899, 0xa899 }, +/* 0xa89a */ { false, 0xa89a, 0xa89a }, +/* 0xa89b */ { false, 0xa89b, 0xa89b }, +/* 0xa89c */ { false, 0xa89c, 0xa89c }, +/* 0xa89d */ { false, 0xa89d, 0xa89d }, +/* 0xa89e */ { false, 0xa89e, 0xa89e }, +/* 0xa89f */ { false, 0xa89f, 0xa89f }, +/* 0xa8a0 */ { false, 0xa8a0, 0xa8a0 }, +/* 0xa8a1 */ { false, 0xa8a1, 0xa8a1 }, +/* 0xa8a2 */ { false, 0xa8a2, 0xa8a2 }, +/* 0xa8a3 */ { false, 0xa8a3, 0xa8a3 }, +/* 0xa8a4 */ { false, 0xa8a4, 0xa8a4 }, +/* 0xa8a5 */ { false, 0xa8a5, 0xa8a5 }, +/* 0xa8a6 */ { false, 0xa8a6, 0xa8a6 }, +/* 0xa8a7 */ { false, 0xa8a7, 0xa8a7 }, +/* 0xa8a8 */ { false, 0xa8a8, 0xa8a8 }, +/* 0xa8a9 */ { false, 0xa8a9, 0xa8a9 }, +/* 0xa8aa */ { false, 0xa8aa, 0xa8aa }, +/* 0xa8ab */ { false, 0xa8ab, 0xa8ab }, +/* 0xa8ac */ { false, 0xa8ac, 0xa8ac }, +/* 0xa8ad */ { false, 0xa8ad, 0xa8ad }, +/* 0xa8ae */ { false, 0xa8ae, 0xa8ae }, +/* 0xa8af */ { false, 0xa8af, 0xa8af }, +/* 0xa8b0 */ { false, 0xa8b0, 0xa8b0 }, +/* 0xa8b1 */ { false, 0xa8b1, 0xa8b1 }, +/* 0xa8b2 */ { false, 0xa8b2, 0xa8b2 }, +/* 0xa8b3 */ { false, 0xa8b3, 0xa8b3 }, +/* 0xa8b4 */ { true, 0xa8b4, 0xa8b4 }, +/* 0xa8b5 */ { true, 0xa8b5, 0xa8b5 }, +/* 0xa8b6 */ { true, 0xa8b6, 0xa8b6 }, +/* 0xa8b7 */ { true, 0xa8b7, 0xa8b7 }, +/* 0xa8b8 */ { true, 0xa8b8, 0xa8b8 }, +/* 0xa8b9 */ { true, 0xa8b9, 0xa8b9 }, +/* 0xa8ba */ { true, 0xa8ba, 0xa8ba }, +/* 0xa8bb */ { true, 0xa8bb, 0xa8bb }, +/* 0xa8bc */ { true, 0xa8bc, 0xa8bc }, +/* 0xa8bd */ { true, 0xa8bd, 0xa8bd }, +/* 0xa8be */ { true, 0xa8be, 0xa8be }, +/* 0xa8bf */ { true, 0xa8bf, 0xa8bf }, +/* 0xa8c0 */ { true, 0xa8c0, 0xa8c0 }, +/* 0xa8c1 */ { true, 0xa8c1, 0xa8c1 }, +/* 0xa8c2 */ { true, 0xa8c2, 0xa8c2 }, +/* 0xa8c3 */ { true, 0xa8c3, 0xa8c3 }, +/* 0xa8c4 */ { false, 0xa8c4, 0xa8c4 }, +/* 0xa8c5 */ { false, 0xa8c5, 0xa8c5 }, +/* 0xa8c6 */ { false, 0xa8c6, 0xa8c6 }, +/* 0xa8c7 */ { false, 0xa8c7, 0xa8c7 }, +/* 0xa8c8 */ { false, 0xa8c8, 0xa8c8 }, +/* 0xa8c9 */ { false, 0xa8c9, 0xa8c9 }, +/* 0xa8ca */ { false, 0xa8ca, 0xa8ca }, +/* 0xa8cb */ { false, 0xa8cb, 0xa8cb }, +/* 0xa8cc */ { false, 0xa8cc, 0xa8cc }, +/* 0xa8cd */ { false, 0xa8cd, 0xa8cd }, +/* 0xa8ce */ { false, 0xa8ce, 0xa8ce }, +/* 0xa8cf */ { false, 0xa8cf, 0xa8cf }, +/* 0xa8d0 */ { false, 0xa8d0, 0xa8d0 }, +/* 0xa8d1 */ { false, 0xa8d1, 0xa8d1 }, +/* 0xa8d2 */ { false, 0xa8d2, 0xa8d2 }, +/* 0xa8d3 */ { false, 0xa8d3, 0xa8d3 }, +/* 0xa8d4 */ { false, 0xa8d4, 0xa8d4 }, +/* 0xa8d5 */ { false, 0xa8d5, 0xa8d5 }, +/* 0xa8d6 */ { false, 0xa8d6, 0xa8d6 }, +/* 0xa8d7 */ { false, 0xa8d7, 0xa8d7 }, +/* 0xa8d8 */ { false, 0xa8d8, 0xa8d8 }, +/* 0xa8d9 */ { false, 0xa8d9, 0xa8d9 }, +/* 0xa8da */ { false, 0xa8da, 0xa8da }, +/* 0xa8db */ { false, 0xa8db, 0xa8db }, +/* 0xa8dc */ { false, 0xa8dc, 0xa8dc }, +/* 0xa8dd */ { false, 0xa8dd, 0xa8dd }, +/* 0xa8de */ { false, 0xa8de, 0xa8de }, +/* 0xa8df */ { false, 0xa8df, 0xa8df }, +/* 0xa8e0 */ { false, 0xa8e0, 0xa8e0 }, +/* 0xa8e1 */ { false, 0xa8e1, 0xa8e1 }, +/* 0xa8e2 */ { false, 0xa8e2, 0xa8e2 }, +/* 0xa8e3 */ { false, 0xa8e3, 0xa8e3 }, +/* 0xa8e4 */ { false, 0xa8e4, 0xa8e4 }, +/* 0xa8e5 */ { false, 0xa8e5, 0xa8e5 }, +/* 0xa8e6 */ { false, 0xa8e6, 0xa8e6 }, +/* 0xa8e7 */ { false, 0xa8e7, 0xa8e7 }, +/* 0xa8e8 */ { false, 0xa8e8, 0xa8e8 }, +/* 0xa8e9 */ { false, 0xa8e9, 0xa8e9 }, +/* 0xa8ea */ { false, 0xa8ea, 0xa8ea }, +/* 0xa8eb */ { false, 0xa8eb, 0xa8eb }, +/* 0xa8ec */ { false, 0xa8ec, 0xa8ec }, +/* 0xa8ed */ { false, 0xa8ed, 0xa8ed }, +/* 0xa8ee */ { false, 0xa8ee, 0xa8ee }, +/* 0xa8ef */ { false, 0xa8ef, 0xa8ef }, +/* 0xa8f0 */ { false, 0xa8f0, 0xa8f0 }, +/* 0xa8f1 */ { false, 0xa8f1, 0xa8f1 }, +/* 0xa8f2 */ { false, 0xa8f2, 0xa8f2 }, +/* 0xa8f3 */ { false, 0xa8f3, 0xa8f3 }, +/* 0xa8f4 */ { false, 0xa8f4, 0xa8f4 }, +/* 0xa8f5 */ { false, 0xa8f5, 0xa8f5 }, +/* 0xa8f6 */ { false, 0xa8f6, 0xa8f6 }, +/* 0xa8f7 */ { false, 0xa8f7, 0xa8f7 }, +/* 0xa8f8 */ { false, 0xa8f8, 0xa8f8 }, +/* 0xa8f9 */ { false, 0xa8f9, 0xa8f9 }, +/* 0xa8fa */ { false, 0xa8fa, 0xa8fa }, +/* 0xa8fb */ { false, 0xa8fb, 0xa8fb }, +/* 0xa8fc */ { false, 0xa8fc, 0xa8fc }, +/* 0xa8fd */ { false, 0xa8fd, 0xa8fd }, +/* 0xa8fe */ { false, 0xa8fe, 0xa8fe }, +/* 0xa8ff */ { false, 0xa8ff, 0xa8ff }, +/* 0xa900 */ { false, 0xa900, 0xa900 }, +/* 0xa901 */ { false, 0xa901, 0xa901 }, +/* 0xa902 */ { false, 0xa902, 0xa902 }, +/* 0xa903 */ { false, 0xa903, 0xa903 }, +/* 0xa904 */ { false, 0xa904, 0xa904 }, +/* 0xa905 */ { false, 0xa905, 0xa905 }, +/* 0xa906 */ { false, 0xa906, 0xa906 }, +/* 0xa907 */ { false, 0xa907, 0xa907 }, +/* 0xa908 */ { false, 0xa908, 0xa908 }, +/* 0xa909 */ { false, 0xa909, 0xa909 }, +/* 0xa90a */ { false, 0xa90a, 0xa90a }, +/* 0xa90b */ { false, 0xa90b, 0xa90b }, +/* 0xa90c */ { false, 0xa90c, 0xa90c }, +/* 0xa90d */ { false, 0xa90d, 0xa90d }, +/* 0xa90e */ { false, 0xa90e, 0xa90e }, +/* 0xa90f */ { false, 0xa90f, 0xa90f }, +/* 0xa910 */ { false, 0xa910, 0xa910 }, +/* 0xa911 */ { false, 0xa911, 0xa911 }, +/* 0xa912 */ { false, 0xa912, 0xa912 }, +/* 0xa913 */ { false, 0xa913, 0xa913 }, +/* 0xa914 */ { false, 0xa914, 0xa914 }, +/* 0xa915 */ { false, 0xa915, 0xa915 }, +/* 0xa916 */ { false, 0xa916, 0xa916 }, +/* 0xa917 */ { false, 0xa917, 0xa917 }, +/* 0xa918 */ { false, 0xa918, 0xa918 }, +/* 0xa919 */ { false, 0xa919, 0xa919 }, +/* 0xa91a */ { false, 0xa91a, 0xa91a }, +/* 0xa91b */ { false, 0xa91b, 0xa91b }, +/* 0xa91c */ { false, 0xa91c, 0xa91c }, +/* 0xa91d */ { false, 0xa91d, 0xa91d }, +/* 0xa91e */ { false, 0xa91e, 0xa91e }, +/* 0xa91f */ { false, 0xa91f, 0xa91f }, +/* 0xa920 */ { false, 0xa920, 0xa920 }, +/* 0xa921 */ { false, 0xa921, 0xa921 }, +/* 0xa922 */ { false, 0xa922, 0xa922 }, +/* 0xa923 */ { false, 0xa923, 0xa923 }, +/* 0xa924 */ { false, 0xa924, 0xa924 }, +/* 0xa925 */ { false, 0xa925, 0xa925 }, +/* 0xa926 */ { false, 0xa926, 0xa926 }, +/* 0xa927 */ { false, 0xa927, 0xa927 }, +/* 0xa928 */ { false, 0xa928, 0xa928 }, +/* 0xa929 */ { false, 0xa929, 0xa929 }, +/* 0xa92a */ { false, 0xa92a, 0xa92a }, +/* 0xa92b */ { false, 0xa92b, 0xa92b }, +/* 0xa92c */ { false, 0xa92c, 0xa92c }, +/* 0xa92d */ { false, 0xa92d, 0xa92d }, +/* 0xa92e */ { false, 0xa92e, 0xa92e }, +/* 0xa92f */ { false, 0xa92f, 0xa92f }, +/* 0xa930 */ { false, 0xa930, 0xa930 }, +/* 0xa931 */ { false, 0xa931, 0xa931 }, +/* 0xa932 */ { false, 0xa932, 0xa932 }, +/* 0xa933 */ { false, 0xa933, 0xa933 }, +/* 0xa934 */ { false, 0xa934, 0xa934 }, +/* 0xa935 */ { false, 0xa935, 0xa935 }, +/* 0xa936 */ { false, 0xa936, 0xa936 }, +/* 0xa937 */ { false, 0xa937, 0xa937 }, +/* 0xa938 */ { false, 0xa938, 0xa938 }, +/* 0xa939 */ { false, 0xa939, 0xa939 }, +/* 0xa93a */ { false, 0xa93a, 0xa93a }, +/* 0xa93b */ { false, 0xa93b, 0xa93b }, +/* 0xa93c */ { false, 0xa93c, 0xa93c }, +/* 0xa93d */ { false, 0xa93d, 0xa93d }, +/* 0xa93e */ { false, 0xa93e, 0xa93e }, +/* 0xa93f */ { false, 0xa93f, 0xa93f }, +/* 0xa940 */ { false, 0xa940, 0xa940 }, +/* 0xa941 */ { false, 0xa941, 0xa941 }, +/* 0xa942 */ { false, 0xa942, 0xa942 }, +/* 0xa943 */ { false, 0xa943, 0xa943 }, +/* 0xa944 */ { false, 0xa944, 0xa944 }, +/* 0xa945 */ { false, 0xa945, 0xa945 }, +/* 0xa946 */ { false, 0xa946, 0xa946 }, +/* 0xa947 */ { false, 0xa947, 0xa947 }, +/* 0xa948 */ { false, 0xa948, 0xa948 }, +/* 0xa949 */ { false, 0xa949, 0xa949 }, +/* 0xa94a */ { false, 0xa94a, 0xa94a }, +/* 0xa94b */ { false, 0xa94b, 0xa94b }, +/* 0xa94c */ { false, 0xa94c, 0xa94c }, +/* 0xa94d */ { false, 0xa94d, 0xa94d }, +/* 0xa94e */ { false, 0xa94e, 0xa94e }, +/* 0xa94f */ { false, 0xa94f, 0xa94f }, +/* 0xa950 */ { false, 0xa950, 0xa950 }, +/* 0xa951 */ { false, 0xa951, 0xa951 }, +/* 0xa952 */ { true, 0xa952, 0xa952 }, +/* 0xa953 */ { true, 0xa953, 0xa953 }, +/* 0xa954 */ { false, 0xa954, 0xa954 }, +/* 0xa955 */ { false, 0xa955, 0xa955 }, +/* 0xa956 */ { false, 0xa956, 0xa956 }, +/* 0xa957 */ { false, 0xa957, 0xa957 }, +/* 0xa958 */ { false, 0xa958, 0xa958 }, +/* 0xa959 */ { false, 0xa959, 0xa959 }, +/* 0xa95a */ { false, 0xa95a, 0xa95a }, +/* 0xa95b */ { false, 0xa95b, 0xa95b }, +/* 0xa95c */ { false, 0xa95c, 0xa95c }, +/* 0xa95d */ { false, 0xa95d, 0xa95d }, +/* 0xa95e */ { false, 0xa95e, 0xa95e }, +/* 0xa95f */ { false, 0xa95f, 0xa95f }, +/* 0xa960 */ { false, 0xa960, 0xa960 }, +/* 0xa961 */ { false, 0xa961, 0xa961 }, +/* 0xa962 */ { false, 0xa962, 0xa962 }, +/* 0xa963 */ { false, 0xa963, 0xa963 }, +/* 0xa964 */ { false, 0xa964, 0xa964 }, +/* 0xa965 */ { false, 0xa965, 0xa965 }, +/* 0xa966 */ { false, 0xa966, 0xa966 }, +/* 0xa967 */ { false, 0xa967, 0xa967 }, +/* 0xa968 */ { false, 0xa968, 0xa968 }, +/* 0xa969 */ { false, 0xa969, 0xa969 }, +/* 0xa96a */ { false, 0xa96a, 0xa96a }, +/* 0xa96b */ { false, 0xa96b, 0xa96b }, +/* 0xa96c */ { false, 0xa96c, 0xa96c }, +/* 0xa96d */ { false, 0xa96d, 0xa96d }, +/* 0xa96e */ { false, 0xa96e, 0xa96e }, +/* 0xa96f */ { false, 0xa96f, 0xa96f }, +/* 0xa970 */ { false, 0xa970, 0xa970 }, +/* 0xa971 */ { false, 0xa971, 0xa971 }, +/* 0xa972 */ { false, 0xa972, 0xa972 }, +/* 0xa973 */ { false, 0xa973, 0xa973 }, +/* 0xa974 */ { false, 0xa974, 0xa974 }, +/* 0xa975 */ { false, 0xa975, 0xa975 }, +/* 0xa976 */ { false, 0xa976, 0xa976 }, +/* 0xa977 */ { false, 0xa977, 0xa977 }, +/* 0xa978 */ { false, 0xa978, 0xa978 }, +/* 0xa979 */ { false, 0xa979, 0xa979 }, +/* 0xa97a */ { false, 0xa97a, 0xa97a }, +/* 0xa97b */ { false, 0xa97b, 0xa97b }, +/* 0xa97c */ { false, 0xa97c, 0xa97c }, +/* 0xa97d */ { false, 0xa97d, 0xa97d }, +/* 0xa97e */ { false, 0xa97e, 0xa97e }, +/* 0xa97f */ { false, 0xa97f, 0xa97f }, +/* 0xa980 */ { false, 0xa980, 0xa980 }, +/* 0xa981 */ { false, 0xa981, 0xa981 }, +/* 0xa982 */ { false, 0xa982, 0xa982 }, +/* 0xa983 */ { true, 0xa983, 0xa983 }, +/* 0xa984 */ { false, 0xa984, 0xa984 }, +/* 0xa985 */ { false, 0xa985, 0xa985 }, +/* 0xa986 */ { false, 0xa986, 0xa986 }, +/* 0xa987 */ { false, 0xa987, 0xa987 }, +/* 0xa988 */ { false, 0xa988, 0xa988 }, +/* 0xa989 */ { false, 0xa989, 0xa989 }, +/* 0xa98a */ { false, 0xa98a, 0xa98a }, +/* 0xa98b */ { false, 0xa98b, 0xa98b }, +/* 0xa98c */ { false, 0xa98c, 0xa98c }, +/* 0xa98d */ { false, 0xa98d, 0xa98d }, +/* 0xa98e */ { false, 0xa98e, 0xa98e }, +/* 0xa98f */ { false, 0xa98f, 0xa98f }, +/* 0xa990 */ { false, 0xa990, 0xa990 }, +/* 0xa991 */ { false, 0xa991, 0xa991 }, +/* 0xa992 */ { false, 0xa992, 0xa992 }, +/* 0xa993 */ { false, 0xa993, 0xa993 }, +/* 0xa994 */ { false, 0xa994, 0xa994 }, +/* 0xa995 */ { false, 0xa995, 0xa995 }, +/* 0xa996 */ { false, 0xa996, 0xa996 }, +/* 0xa997 */ { false, 0xa997, 0xa997 }, +/* 0xa998 */ { false, 0xa998, 0xa998 }, +/* 0xa999 */ { false, 0xa999, 0xa999 }, +/* 0xa99a */ { false, 0xa99a, 0xa99a }, +/* 0xa99b */ { false, 0xa99b, 0xa99b }, +/* 0xa99c */ { false, 0xa99c, 0xa99c }, +/* 0xa99d */ { false, 0xa99d, 0xa99d }, +/* 0xa99e */ { false, 0xa99e, 0xa99e }, +/* 0xa99f */ { false, 0xa99f, 0xa99f }, +/* 0xa9a0 */ { false, 0xa9a0, 0xa9a0 }, +/* 0xa9a1 */ { false, 0xa9a1, 0xa9a1 }, +/* 0xa9a2 */ { false, 0xa9a2, 0xa9a2 }, +/* 0xa9a3 */ { false, 0xa9a3, 0xa9a3 }, +/* 0xa9a4 */ { false, 0xa9a4, 0xa9a4 }, +/* 0xa9a5 */ { false, 0xa9a5, 0xa9a5 }, +/* 0xa9a6 */ { false, 0xa9a6, 0xa9a6 }, +/* 0xa9a7 */ { false, 0xa9a7, 0xa9a7 }, +/* 0xa9a8 */ { false, 0xa9a8, 0xa9a8 }, +/* 0xa9a9 */ { false, 0xa9a9, 0xa9a9 }, +/* 0xa9aa */ { false, 0xa9aa, 0xa9aa }, +/* 0xa9ab */ { false, 0xa9ab, 0xa9ab }, +/* 0xa9ac */ { false, 0xa9ac, 0xa9ac }, +/* 0xa9ad */ { false, 0xa9ad, 0xa9ad }, +/* 0xa9ae */ { false, 0xa9ae, 0xa9ae }, +/* 0xa9af */ { false, 0xa9af, 0xa9af }, +/* 0xa9b0 */ { false, 0xa9b0, 0xa9b0 }, +/* 0xa9b1 */ { false, 0xa9b1, 0xa9b1 }, +/* 0xa9b2 */ { false, 0xa9b2, 0xa9b2 }, +/* 0xa9b3 */ { false, 0xa9b3, 0xa9b3 }, +/* 0xa9b4 */ { true, 0xa9b4, 0xa9b4 }, +/* 0xa9b5 */ { true, 0xa9b5, 0xa9b5 }, +/* 0xa9b6 */ { false, 0xa9b6, 0xa9b6 }, +/* 0xa9b7 */ { false, 0xa9b7, 0xa9b7 }, +/* 0xa9b8 */ { false, 0xa9b8, 0xa9b8 }, +/* 0xa9b9 */ { false, 0xa9b9, 0xa9b9 }, +/* 0xa9ba */ { true, 0xa9ba, 0xa9ba }, +/* 0xa9bb */ { true, 0xa9bb, 0xa9bb }, +/* 0xa9bc */ { false, 0xa9bc, 0xa9bc }, +/* 0xa9bd */ { false, 0xa9bd, 0xa9bd }, +/* 0xa9be */ { true, 0xa9be, 0xa9be }, +/* 0xa9bf */ { true, 0xa9bf, 0xa9bf }, +/* 0xa9c0 */ { true, 0xa9c0, 0xa9c0 }, +/* 0xa9c1 */ { false, 0xa9c1, 0xa9c1 }, +/* 0xa9c2 */ { false, 0xa9c2, 0xa9c2 }, +/* 0xa9c3 */ { false, 0xa9c3, 0xa9c3 }, +/* 0xa9c4 */ { false, 0xa9c4, 0xa9c4 }, +/* 0xa9c5 */ { false, 0xa9c5, 0xa9c5 }, +/* 0xa9c6 */ { false, 0xa9c6, 0xa9c6 }, +/* 0xa9c7 */ { false, 0xa9c7, 0xa9c7 }, +/* 0xa9c8 */ { false, 0xa9c8, 0xa9c8 }, +/* 0xa9c9 */ { false, 0xa9c9, 0xa9c9 }, +/* 0xa9ca */ { false, 0xa9ca, 0xa9ca }, +/* 0xa9cb */ { false, 0xa9cb, 0xa9cb }, +/* 0xa9cc */ { false, 0xa9cc, 0xa9cc }, +/* 0xa9cd */ { false, 0xa9cd, 0xa9cd }, +/* 0xa9ce */ { false, 0xa9ce, 0xa9ce }, +/* 0xa9cf */ { false, 0xa9cf, 0xa9cf }, +/* 0xa9d0 */ { false, 0xa9d0, 0xa9d0 }, +/* 0xa9d1 */ { false, 0xa9d1, 0xa9d1 }, +/* 0xa9d2 */ { false, 0xa9d2, 0xa9d2 }, +/* 0xa9d3 */ { false, 0xa9d3, 0xa9d3 }, +/* 0xa9d4 */ { false, 0xa9d4, 0xa9d4 }, +/* 0xa9d5 */ { false, 0xa9d5, 0xa9d5 }, +/* 0xa9d6 */ { false, 0xa9d6, 0xa9d6 }, +/* 0xa9d7 */ { false, 0xa9d7, 0xa9d7 }, +/* 0xa9d8 */ { false, 0xa9d8, 0xa9d8 }, +/* 0xa9d9 */ { false, 0xa9d9, 0xa9d9 }, +/* 0xa9da */ { false, 0xa9da, 0xa9da }, +/* 0xa9db */ { false, 0xa9db, 0xa9db }, +/* 0xa9dc */ { false, 0xa9dc, 0xa9dc }, +/* 0xa9dd */ { false, 0xa9dd, 0xa9dd }, +/* 0xa9de */ { false, 0xa9de, 0xa9de }, +/* 0xa9df */ { false, 0xa9df, 0xa9df }, +/* 0xa9e0 */ { false, 0xa9e0, 0xa9e0 }, +/* 0xa9e1 */ { false, 0xa9e1, 0xa9e1 }, +/* 0xa9e2 */ { false, 0xa9e2, 0xa9e2 }, +/* 0xa9e3 */ { false, 0xa9e3, 0xa9e3 }, +/* 0xa9e4 */ { false, 0xa9e4, 0xa9e4 }, +/* 0xa9e5 */ { false, 0xa9e5, 0xa9e5 }, +/* 0xa9e6 */ { false, 0xa9e6, 0xa9e6 }, +/* 0xa9e7 */ { false, 0xa9e7, 0xa9e7 }, +/* 0xa9e8 */ { false, 0xa9e8, 0xa9e8 }, +/* 0xa9e9 */ { false, 0xa9e9, 0xa9e9 }, +/* 0xa9ea */ { false, 0xa9ea, 0xa9ea }, +/* 0xa9eb */ { false, 0xa9eb, 0xa9eb }, +/* 0xa9ec */ { false, 0xa9ec, 0xa9ec }, +/* 0xa9ed */ { false, 0xa9ed, 0xa9ed }, +/* 0xa9ee */ { false, 0xa9ee, 0xa9ee }, +/* 0xa9ef */ { false, 0xa9ef, 0xa9ef }, +/* 0xa9f0 */ { false, 0xa9f0, 0xa9f0 }, +/* 0xa9f1 */ { false, 0xa9f1, 0xa9f1 }, +/* 0xa9f2 */ { false, 0xa9f2, 0xa9f2 }, +/* 0xa9f3 */ { false, 0xa9f3, 0xa9f3 }, +/* 0xa9f4 */ { false, 0xa9f4, 0xa9f4 }, +/* 0xa9f5 */ { false, 0xa9f5, 0xa9f5 }, +/* 0xa9f6 */ { false, 0xa9f6, 0xa9f6 }, +/* 0xa9f7 */ { false, 0xa9f7, 0xa9f7 }, +/* 0xa9f8 */ { false, 0xa9f8, 0xa9f8 }, +/* 0xa9f9 */ { false, 0xa9f9, 0xa9f9 }, +/* 0xa9fa */ { false, 0xa9fa, 0xa9fa }, +/* 0xa9fb */ { false, 0xa9fb, 0xa9fb }, +/* 0xa9fc */ { false, 0xa9fc, 0xa9fc }, +/* 0xa9fd */ { false, 0xa9fd, 0xa9fd }, +/* 0xa9fe */ { false, 0xa9fe, 0xa9fe }, +/* 0xa9ff */ { false, 0xa9ff, 0xa9ff }, +/* 0xaa00 */ { false, 0xaa00, 0xaa00 }, +/* 0xaa01 */ { false, 0xaa01, 0xaa01 }, +/* 0xaa02 */ { false, 0xaa02, 0xaa02 }, +/* 0xaa03 */ { false, 0xaa03, 0xaa03 }, +/* 0xaa04 */ { false, 0xaa04, 0xaa04 }, +/* 0xaa05 */ { false, 0xaa05, 0xaa05 }, +/* 0xaa06 */ { false, 0xaa06, 0xaa06 }, +/* 0xaa07 */ { false, 0xaa07, 0xaa07 }, +/* 0xaa08 */ { false, 0xaa08, 0xaa08 }, +/* 0xaa09 */ { false, 0xaa09, 0xaa09 }, +/* 0xaa0a */ { false, 0xaa0a, 0xaa0a }, +/* 0xaa0b */ { false, 0xaa0b, 0xaa0b }, +/* 0xaa0c */ { false, 0xaa0c, 0xaa0c }, +/* 0xaa0d */ { false, 0xaa0d, 0xaa0d }, +/* 0xaa0e */ { false, 0xaa0e, 0xaa0e }, +/* 0xaa0f */ { false, 0xaa0f, 0xaa0f }, +/* 0xaa10 */ { false, 0xaa10, 0xaa10 }, +/* 0xaa11 */ { false, 0xaa11, 0xaa11 }, +/* 0xaa12 */ { false, 0xaa12, 0xaa12 }, +/* 0xaa13 */ { false, 0xaa13, 0xaa13 }, +/* 0xaa14 */ { false, 0xaa14, 0xaa14 }, +/* 0xaa15 */ { false, 0xaa15, 0xaa15 }, +/* 0xaa16 */ { false, 0xaa16, 0xaa16 }, +/* 0xaa17 */ { false, 0xaa17, 0xaa17 }, +/* 0xaa18 */ { false, 0xaa18, 0xaa18 }, +/* 0xaa19 */ { false, 0xaa19, 0xaa19 }, +/* 0xaa1a */ { false, 0xaa1a, 0xaa1a }, +/* 0xaa1b */ { false, 0xaa1b, 0xaa1b }, +/* 0xaa1c */ { false, 0xaa1c, 0xaa1c }, +/* 0xaa1d */ { false, 0xaa1d, 0xaa1d }, +/* 0xaa1e */ { false, 0xaa1e, 0xaa1e }, +/* 0xaa1f */ { false, 0xaa1f, 0xaa1f }, +/* 0xaa20 */ { false, 0xaa20, 0xaa20 }, +/* 0xaa21 */ { false, 0xaa21, 0xaa21 }, +/* 0xaa22 */ { false, 0xaa22, 0xaa22 }, +/* 0xaa23 */ { false, 0xaa23, 0xaa23 }, +/* 0xaa24 */ { false, 0xaa24, 0xaa24 }, +/* 0xaa25 */ { false, 0xaa25, 0xaa25 }, +/* 0xaa26 */ { false, 0xaa26, 0xaa26 }, +/* 0xaa27 */ { false, 0xaa27, 0xaa27 }, +/* 0xaa28 */ { false, 0xaa28, 0xaa28 }, +/* 0xaa29 */ { false, 0xaa29, 0xaa29 }, +/* 0xaa2a */ { false, 0xaa2a, 0xaa2a }, +/* 0xaa2b */ { false, 0xaa2b, 0xaa2b }, +/* 0xaa2c */ { false, 0xaa2c, 0xaa2c }, +/* 0xaa2d */ { false, 0xaa2d, 0xaa2d }, +/* 0xaa2e */ { false, 0xaa2e, 0xaa2e }, +/* 0xaa2f */ { true, 0xaa2f, 0xaa2f }, +/* 0xaa30 */ { true, 0xaa30, 0xaa30 }, +/* 0xaa31 */ { false, 0xaa31, 0xaa31 }, +/* 0xaa32 */ { false, 0xaa32, 0xaa32 }, +/* 0xaa33 */ { true, 0xaa33, 0xaa33 }, +/* 0xaa34 */ { true, 0xaa34, 0xaa34 }, +/* 0xaa35 */ { false, 0xaa35, 0xaa35 }, +/* 0xaa36 */ { false, 0xaa36, 0xaa36 }, +/* 0xaa37 */ { false, 0xaa37, 0xaa37 }, +/* 0xaa38 */ { false, 0xaa38, 0xaa38 }, +/* 0xaa39 */ { false, 0xaa39, 0xaa39 }, +/* 0xaa3a */ { false, 0xaa3a, 0xaa3a }, +/* 0xaa3b */ { false, 0xaa3b, 0xaa3b }, +/* 0xaa3c */ { false, 0xaa3c, 0xaa3c }, +/* 0xaa3d */ { false, 0xaa3d, 0xaa3d }, +/* 0xaa3e */ { false, 0xaa3e, 0xaa3e }, +/* 0xaa3f */ { false, 0xaa3f, 0xaa3f }, +/* 0xaa40 */ { false, 0xaa40, 0xaa40 }, +/* 0xaa41 */ { false, 0xaa41, 0xaa41 }, +/* 0xaa42 */ { false, 0xaa42, 0xaa42 }, +/* 0xaa43 */ { false, 0xaa43, 0xaa43 }, +/* 0xaa44 */ { false, 0xaa44, 0xaa44 }, +/* 0xaa45 */ { false, 0xaa45, 0xaa45 }, +/* 0xaa46 */ { false, 0xaa46, 0xaa46 }, +/* 0xaa47 */ { false, 0xaa47, 0xaa47 }, +/* 0xaa48 */ { false, 0xaa48, 0xaa48 }, +/* 0xaa49 */ { false, 0xaa49, 0xaa49 }, +/* 0xaa4a */ { false, 0xaa4a, 0xaa4a }, +/* 0xaa4b */ { false, 0xaa4b, 0xaa4b }, +/* 0xaa4c */ { false, 0xaa4c, 0xaa4c }, +/* 0xaa4d */ { true, 0xaa4d, 0xaa4d }, +/* 0xaa4e */ { false, 0xaa4e, 0xaa4e }, +/* 0xaa4f */ { false, 0xaa4f, 0xaa4f }, +/* 0xaa50 */ { false, 0xaa50, 0xaa50 }, +/* 0xaa51 */ { false, 0xaa51, 0xaa51 }, +/* 0xaa52 */ { false, 0xaa52, 0xaa52 }, +/* 0xaa53 */ { false, 0xaa53, 0xaa53 }, +/* 0xaa54 */ { false, 0xaa54, 0xaa54 }, +/* 0xaa55 */ { false, 0xaa55, 0xaa55 }, +/* 0xaa56 */ { false, 0xaa56, 0xaa56 }, +/* 0xaa57 */ { false, 0xaa57, 0xaa57 }, +/* 0xaa58 */ { false, 0xaa58, 0xaa58 }, +/* 0xaa59 */ { false, 0xaa59, 0xaa59 }, +/* 0xaa5a */ { false, 0xaa5a, 0xaa5a }, +/* 0xaa5b */ { false, 0xaa5b, 0xaa5b }, +/* 0xaa5c */ { false, 0xaa5c, 0xaa5c }, +/* 0xaa5d */ { false, 0xaa5d, 0xaa5d }, +/* 0xaa5e */ { false, 0xaa5e, 0xaa5e }, +/* 0xaa5f */ { false, 0xaa5f, 0xaa5f }, +/* 0xaa60 */ { false, 0xaa60, 0xaa60 }, +/* 0xaa61 */ { false, 0xaa61, 0xaa61 }, +/* 0xaa62 */ { false, 0xaa62, 0xaa62 }, +/* 0xaa63 */ { false, 0xaa63, 0xaa63 }, +/* 0xaa64 */ { false, 0xaa64, 0xaa64 }, +/* 0xaa65 */ { false, 0xaa65, 0xaa65 }, +/* 0xaa66 */ { false, 0xaa66, 0xaa66 }, +/* 0xaa67 */ { false, 0xaa67, 0xaa67 }, +/* 0xaa68 */ { false, 0xaa68, 0xaa68 }, +/* 0xaa69 */ { false, 0xaa69, 0xaa69 }, +/* 0xaa6a */ { false, 0xaa6a, 0xaa6a }, +/* 0xaa6b */ { false, 0xaa6b, 0xaa6b }, +/* 0xaa6c */ { false, 0xaa6c, 0xaa6c }, +/* 0xaa6d */ { false, 0xaa6d, 0xaa6d }, +/* 0xaa6e */ { false, 0xaa6e, 0xaa6e }, +/* 0xaa6f */ { false, 0xaa6f, 0xaa6f }, +/* 0xaa70 */ { false, 0xaa70, 0xaa70 }, +/* 0xaa71 */ { false, 0xaa71, 0xaa71 }, +/* 0xaa72 */ { false, 0xaa72, 0xaa72 }, +/* 0xaa73 */ { false, 0xaa73, 0xaa73 }, +/* 0xaa74 */ { false, 0xaa74, 0xaa74 }, +/* 0xaa75 */ { false, 0xaa75, 0xaa75 }, +/* 0xaa76 */ { false, 0xaa76, 0xaa76 }, +/* 0xaa77 */ { false, 0xaa77, 0xaa77 }, +/* 0xaa78 */ { false, 0xaa78, 0xaa78 }, +/* 0xaa79 */ { false, 0xaa79, 0xaa79 }, +/* 0xaa7a */ { false, 0xaa7a, 0xaa7a }, +/* 0xaa7b */ { true, 0xaa7b, 0xaa7b }, +/* 0xaa7c */ { false, 0xaa7c, 0xaa7c }, +/* 0xaa7d */ { true, 0xaa7d, 0xaa7d }, +/* 0xaa7e */ { false, 0xaa7e, 0xaa7e }, +/* 0xaa7f */ { false, 0xaa7f, 0xaa7f }, +/* 0xaa80 */ { false, 0xaa80, 0xaa80 }, +/* 0xaa81 */ { false, 0xaa81, 0xaa81 }, +/* 0xaa82 */ { false, 0xaa82, 0xaa82 }, +/* 0xaa83 */ { false, 0xaa83, 0xaa83 }, +/* 0xaa84 */ { false, 0xaa84, 0xaa84 }, +/* 0xaa85 */ { false, 0xaa85, 0xaa85 }, +/* 0xaa86 */ { false, 0xaa86, 0xaa86 }, +/* 0xaa87 */ { false, 0xaa87, 0xaa87 }, +/* 0xaa88 */ { false, 0xaa88, 0xaa88 }, +/* 0xaa89 */ { false, 0xaa89, 0xaa89 }, +/* 0xaa8a */ { false, 0xaa8a, 0xaa8a }, +/* 0xaa8b */ { false, 0xaa8b, 0xaa8b }, +/* 0xaa8c */ { false, 0xaa8c, 0xaa8c }, +/* 0xaa8d */ { false, 0xaa8d, 0xaa8d }, +/* 0xaa8e */ { false, 0xaa8e, 0xaa8e }, +/* 0xaa8f */ { false, 0xaa8f, 0xaa8f }, +/* 0xaa90 */ { false, 0xaa90, 0xaa90 }, +/* 0xaa91 */ { false, 0xaa91, 0xaa91 }, +/* 0xaa92 */ { false, 0xaa92, 0xaa92 }, +/* 0xaa93 */ { false, 0xaa93, 0xaa93 }, +/* 0xaa94 */ { false, 0xaa94, 0xaa94 }, +/* 0xaa95 */ { false, 0xaa95, 0xaa95 }, +/* 0xaa96 */ { false, 0xaa96, 0xaa96 }, +/* 0xaa97 */ { false, 0xaa97, 0xaa97 }, +/* 0xaa98 */ { false, 0xaa98, 0xaa98 }, +/* 0xaa99 */ { false, 0xaa99, 0xaa99 }, +/* 0xaa9a */ { false, 0xaa9a, 0xaa9a }, +/* 0xaa9b */ { false, 0xaa9b, 0xaa9b }, +/* 0xaa9c */ { false, 0xaa9c, 0xaa9c }, +/* 0xaa9d */ { false, 0xaa9d, 0xaa9d }, +/* 0xaa9e */ { false, 0xaa9e, 0xaa9e }, +/* 0xaa9f */ { false, 0xaa9f, 0xaa9f }, +/* 0xaaa0 */ { false, 0xaaa0, 0xaaa0 }, +/* 0xaaa1 */ { false, 0xaaa1, 0xaaa1 }, +/* 0xaaa2 */ { false, 0xaaa2, 0xaaa2 }, +/* 0xaaa3 */ { false, 0xaaa3, 0xaaa3 }, +/* 0xaaa4 */ { false, 0xaaa4, 0xaaa4 }, +/* 0xaaa5 */ { false, 0xaaa5, 0xaaa5 }, +/* 0xaaa6 */ { false, 0xaaa6, 0xaaa6 }, +/* 0xaaa7 */ { false, 0xaaa7, 0xaaa7 }, +/* 0xaaa8 */ { false, 0xaaa8, 0xaaa8 }, +/* 0xaaa9 */ { false, 0xaaa9, 0xaaa9 }, +/* 0xaaaa */ { false, 0xaaaa, 0xaaaa }, +/* 0xaaab */ { false, 0xaaab, 0xaaab }, +/* 0xaaac */ { false, 0xaaac, 0xaaac }, +/* 0xaaad */ { false, 0xaaad, 0xaaad }, +/* 0xaaae */ { false, 0xaaae, 0xaaae }, +/* 0xaaaf */ { false, 0xaaaf, 0xaaaf }, +/* 0xaab0 */ { false, 0xaab0, 0xaab0 }, +/* 0xaab1 */ { false, 0xaab1, 0xaab1 }, +/* 0xaab2 */ { false, 0xaab2, 0xaab2 }, +/* 0xaab3 */ { false, 0xaab3, 0xaab3 }, +/* 0xaab4 */ { false, 0xaab4, 0xaab4 }, +/* 0xaab5 */ { false, 0xaab5, 0xaab5 }, +/* 0xaab6 */ { false, 0xaab6, 0xaab6 }, +/* 0xaab7 */ { false, 0xaab7, 0xaab7 }, +/* 0xaab8 */ { false, 0xaab8, 0xaab8 }, +/* 0xaab9 */ { false, 0xaab9, 0xaab9 }, +/* 0xaaba */ { false, 0xaaba, 0xaaba }, +/* 0xaabb */ { false, 0xaabb, 0xaabb }, +/* 0xaabc */ { false, 0xaabc, 0xaabc }, +/* 0xaabd */ { false, 0xaabd, 0xaabd }, +/* 0xaabe */ { false, 0xaabe, 0xaabe }, +/* 0xaabf */ { false, 0xaabf, 0xaabf }, +/* 0xaac0 */ { false, 0xaac0, 0xaac0 }, +/* 0xaac1 */ { false, 0xaac1, 0xaac1 }, +/* 0xaac2 */ { false, 0xaac2, 0xaac2 }, +/* 0xaac3 */ { false, 0xaac3, 0xaac3 }, +/* 0xaac4 */ { false, 0xaac4, 0xaac4 }, +/* 0xaac5 */ { false, 0xaac5, 0xaac5 }, +/* 0xaac6 */ { false, 0xaac6, 0xaac6 }, +/* 0xaac7 */ { false, 0xaac7, 0xaac7 }, +/* 0xaac8 */ { false, 0xaac8, 0xaac8 }, +/* 0xaac9 */ { false, 0xaac9, 0xaac9 }, +/* 0xaaca */ { false, 0xaaca, 0xaaca }, +/* 0xaacb */ { false, 0xaacb, 0xaacb }, +/* 0xaacc */ { false, 0xaacc, 0xaacc }, +/* 0xaacd */ { false, 0xaacd, 0xaacd }, +/* 0xaace */ { false, 0xaace, 0xaace }, +/* 0xaacf */ { false, 0xaacf, 0xaacf }, +/* 0xaad0 */ { false, 0xaad0, 0xaad0 }, +/* 0xaad1 */ { false, 0xaad1, 0xaad1 }, +/* 0xaad2 */ { false, 0xaad2, 0xaad2 }, +/* 0xaad3 */ { false, 0xaad3, 0xaad3 }, +/* 0xaad4 */ { false, 0xaad4, 0xaad4 }, +/* 0xaad5 */ { false, 0xaad5, 0xaad5 }, +/* 0xaad6 */ { false, 0xaad6, 0xaad6 }, +/* 0xaad7 */ { false, 0xaad7, 0xaad7 }, +/* 0xaad8 */ { false, 0xaad8, 0xaad8 }, +/* 0xaad9 */ { false, 0xaad9, 0xaad9 }, +/* 0xaada */ { false, 0xaada, 0xaada }, +/* 0xaadb */ { false, 0xaadb, 0xaadb }, +/* 0xaadc */ { false, 0xaadc, 0xaadc }, +/* 0xaadd */ { false, 0xaadd, 0xaadd }, +/* 0xaade */ { false, 0xaade, 0xaade }, +/* 0xaadf */ { false, 0xaadf, 0xaadf }, +/* 0xaae0 */ { false, 0xaae0, 0xaae0 }, +/* 0xaae1 */ { false, 0xaae1, 0xaae1 }, +/* 0xaae2 */ { false, 0xaae2, 0xaae2 }, +/* 0xaae3 */ { false, 0xaae3, 0xaae3 }, +/* 0xaae4 */ { false, 0xaae4, 0xaae4 }, +/* 0xaae5 */ { false, 0xaae5, 0xaae5 }, +/* 0xaae6 */ { false, 0xaae6, 0xaae6 }, +/* 0xaae7 */ { false, 0xaae7, 0xaae7 }, +/* 0xaae8 */ { false, 0xaae8, 0xaae8 }, +/* 0xaae9 */ { false, 0xaae9, 0xaae9 }, +/* 0xaaea */ { false, 0xaaea, 0xaaea }, +/* 0xaaeb */ { true, 0xaaeb, 0xaaeb }, +/* 0xaaec */ { false, 0xaaec, 0xaaec }, +/* 0xaaed */ { false, 0xaaed, 0xaaed }, +/* 0xaaee */ { true, 0xaaee, 0xaaee }, +/* 0xaaef */ { true, 0xaaef, 0xaaef }, +/* 0xaaf0 */ { false, 0xaaf0, 0xaaf0 }, +/* 0xaaf1 */ { false, 0xaaf1, 0xaaf1 }, +/* 0xaaf2 */ { false, 0xaaf2, 0xaaf2 }, +/* 0xaaf3 */ { false, 0xaaf3, 0xaaf3 }, +/* 0xaaf4 */ { false, 0xaaf4, 0xaaf4 }, +/* 0xaaf5 */ { true, 0xaaf5, 0xaaf5 }, +/* 0xaaf6 */ { false, 0xaaf6, 0xaaf6 }, +/* 0xaaf7 */ { false, 0xaaf7, 0xaaf7 }, +/* 0xaaf8 */ { false, 0xaaf8, 0xaaf8 }, +/* 0xaaf9 */ { false, 0xaaf9, 0xaaf9 }, +/* 0xaafa */ { false, 0xaafa, 0xaafa }, +/* 0xaafb */ { false, 0xaafb, 0xaafb }, +/* 0xaafc */ { false, 0xaafc, 0xaafc }, +/* 0xaafd */ { false, 0xaafd, 0xaafd }, +/* 0xaafe */ { false, 0xaafe, 0xaafe }, +/* 0xaaff */ { false, 0xaaff, 0xaaff }, +/* 0xab00 */ { false, 0xab00, 0xab00 }, +/* 0xab01 */ { false, 0xab01, 0xab01 }, +/* 0xab02 */ { false, 0xab02, 0xab02 }, +/* 0xab03 */ { false, 0xab03, 0xab03 }, +/* 0xab04 */ { false, 0xab04, 0xab04 }, +/* 0xab05 */ { false, 0xab05, 0xab05 }, +/* 0xab06 */ { false, 0xab06, 0xab06 }, +/* 0xab07 */ { false, 0xab07, 0xab07 }, +/* 0xab08 */ { false, 0xab08, 0xab08 }, +/* 0xab09 */ { false, 0xab09, 0xab09 }, +/* 0xab0a */ { false, 0xab0a, 0xab0a }, +/* 0xab0b */ { false, 0xab0b, 0xab0b }, +/* 0xab0c */ { false, 0xab0c, 0xab0c }, +/* 0xab0d */ { false, 0xab0d, 0xab0d }, +/* 0xab0e */ { false, 0xab0e, 0xab0e }, +/* 0xab0f */ { false, 0xab0f, 0xab0f }, +/* 0xab10 */ { false, 0xab10, 0xab10 }, +/* 0xab11 */ { false, 0xab11, 0xab11 }, +/* 0xab12 */ { false, 0xab12, 0xab12 }, +/* 0xab13 */ { false, 0xab13, 0xab13 }, +/* 0xab14 */ { false, 0xab14, 0xab14 }, +/* 0xab15 */ { false, 0xab15, 0xab15 }, +/* 0xab16 */ { false, 0xab16, 0xab16 }, +/* 0xab17 */ { false, 0xab17, 0xab17 }, +/* 0xab18 */ { false, 0xab18, 0xab18 }, +/* 0xab19 */ { false, 0xab19, 0xab19 }, +/* 0xab1a */ { false, 0xab1a, 0xab1a }, +/* 0xab1b */ { false, 0xab1b, 0xab1b }, +/* 0xab1c */ { false, 0xab1c, 0xab1c }, +/* 0xab1d */ { false, 0xab1d, 0xab1d }, +/* 0xab1e */ { false, 0xab1e, 0xab1e }, +/* 0xab1f */ { false, 0xab1f, 0xab1f }, +/* 0xab20 */ { false, 0xab20, 0xab20 }, +/* 0xab21 */ { false, 0xab21, 0xab21 }, +/* 0xab22 */ { false, 0xab22, 0xab22 }, +/* 0xab23 */ { false, 0xab23, 0xab23 }, +/* 0xab24 */ { false, 0xab24, 0xab24 }, +/* 0xab25 */ { false, 0xab25, 0xab25 }, +/* 0xab26 */ { false, 0xab26, 0xab26 }, +/* 0xab27 */ { false, 0xab27, 0xab27 }, +/* 0xab28 */ { false, 0xab28, 0xab28 }, +/* 0xab29 */ { false, 0xab29, 0xab29 }, +/* 0xab2a */ { false, 0xab2a, 0xab2a }, +/* 0xab2b */ { false, 0xab2b, 0xab2b }, +/* 0xab2c */ { false, 0xab2c, 0xab2c }, +/* 0xab2d */ { false, 0xab2d, 0xab2d }, +/* 0xab2e */ { false, 0xab2e, 0xab2e }, +/* 0xab2f */ { false, 0xab2f, 0xab2f }, +/* 0xab30 */ { false, 0xab30, 0xab30 }, +/* 0xab31 */ { false, 0xab31, 0xab31 }, +/* 0xab32 */ { false, 0xab32, 0xab32 }, +/* 0xab33 */ { false, 0xab33, 0xab33 }, +/* 0xab34 */ { false, 0xab34, 0xab34 }, +/* 0xab35 */ { false, 0xab35, 0xab35 }, +/* 0xab36 */ { false, 0xab36, 0xab36 }, +/* 0xab37 */ { false, 0xab37, 0xab37 }, +/* 0xab38 */ { false, 0xab38, 0xab38 }, +/* 0xab39 */ { false, 0xab39, 0xab39 }, +/* 0xab3a */ { false, 0xab3a, 0xab3a }, +/* 0xab3b */ { false, 0xab3b, 0xab3b }, +/* 0xab3c */ { false, 0xab3c, 0xab3c }, +/* 0xab3d */ { false, 0xab3d, 0xab3d }, +/* 0xab3e */ { false, 0xab3e, 0xab3e }, +/* 0xab3f */ { false, 0xab3f, 0xab3f }, +/* 0xab40 */ { false, 0xab40, 0xab40 }, +/* 0xab41 */ { false, 0xab41, 0xab41 }, +/* 0xab42 */ { false, 0xab42, 0xab42 }, +/* 0xab43 */ { false, 0xab43, 0xab43 }, +/* 0xab44 */ { false, 0xab44, 0xab44 }, +/* 0xab45 */ { false, 0xab45, 0xab45 }, +/* 0xab46 */ { false, 0xab46, 0xab46 }, +/* 0xab47 */ { false, 0xab47, 0xab47 }, +/* 0xab48 */ { false, 0xab48, 0xab48 }, +/* 0xab49 */ { false, 0xab49, 0xab49 }, +/* 0xab4a */ { false, 0xab4a, 0xab4a }, +/* 0xab4b */ { false, 0xab4b, 0xab4b }, +/* 0xab4c */ { false, 0xab4c, 0xab4c }, +/* 0xab4d */ { false, 0xab4d, 0xab4d }, +/* 0xab4e */ { false, 0xab4e, 0xab4e }, +/* 0xab4f */ { false, 0xab4f, 0xab4f }, +/* 0xab50 */ { false, 0xab50, 0xab50 }, +/* 0xab51 */ { false, 0xab51, 0xab51 }, +/* 0xab52 */ { false, 0xab52, 0xab52 }, +/* 0xab53 */ { false, 0xab53, 0xab53 }, +/* 0xab54 */ { false, 0xab54, 0xab54 }, +/* 0xab55 */ { false, 0xab55, 0xab55 }, +/* 0xab56 */ { false, 0xab56, 0xab56 }, +/* 0xab57 */ { false, 0xab57, 0xab57 }, +/* 0xab58 */ { false, 0xab58, 0xab58 }, +/* 0xab59 */ { false, 0xab59, 0xab59 }, +/* 0xab5a */ { false, 0xab5a, 0xab5a }, +/* 0xab5b */ { false, 0xab5b, 0xab5b }, +/* 0xab5c */ { false, 0xab5c, 0xab5c }, +/* 0xab5d */ { false, 0xab5d, 0xab5d }, +/* 0xab5e */ { false, 0xab5e, 0xab5e }, +/* 0xab5f */ { false, 0xab5f, 0xab5f }, +/* 0xab60 */ { false, 0xab60, 0xab60 }, +/* 0xab61 */ { false, 0xab61, 0xab61 }, +/* 0xab62 */ { false, 0xab62, 0xab62 }, +/* 0xab63 */ { false, 0xab63, 0xab63 }, +/* 0xab64 */ { false, 0xab64, 0xab64 }, +/* 0xab65 */ { false, 0xab65, 0xab65 }, +/* 0xab66 */ { false, 0xab66, 0xab66 }, +/* 0xab67 */ { false, 0xab67, 0xab67 }, +/* 0xab68 */ { false, 0xab68, 0xab68 }, +/* 0xab69 */ { false, 0xab69, 0xab69 }, +/* 0xab6a */ { false, 0xab6a, 0xab6a }, +/* 0xab6b */ { false, 0xab6b, 0xab6b }, +/* 0xab6c */ { false, 0xab6c, 0xab6c }, +/* 0xab6d */ { false, 0xab6d, 0xab6d }, +/* 0xab6e */ { false, 0xab6e, 0xab6e }, +/* 0xab6f */ { false, 0xab6f, 0xab6f }, +/* 0xab70 */ { false, 0xab70, 0xab70 }, +/* 0xab71 */ { false, 0xab71, 0xab71 }, +/* 0xab72 */ { false, 0xab72, 0xab72 }, +/* 0xab73 */ { false, 0xab73, 0xab73 }, +/* 0xab74 */ { false, 0xab74, 0xab74 }, +/* 0xab75 */ { false, 0xab75, 0xab75 }, +/* 0xab76 */ { false, 0xab76, 0xab76 }, +/* 0xab77 */ { false, 0xab77, 0xab77 }, +/* 0xab78 */ { false, 0xab78, 0xab78 }, +/* 0xab79 */ { false, 0xab79, 0xab79 }, +/* 0xab7a */ { false, 0xab7a, 0xab7a }, +/* 0xab7b */ { false, 0xab7b, 0xab7b }, +/* 0xab7c */ { false, 0xab7c, 0xab7c }, +/* 0xab7d */ { false, 0xab7d, 0xab7d }, +/* 0xab7e */ { false, 0xab7e, 0xab7e }, +/* 0xab7f */ { false, 0xab7f, 0xab7f }, +/* 0xab80 */ { false, 0xab80, 0xab80 }, +/* 0xab81 */ { false, 0xab81, 0xab81 }, +/* 0xab82 */ { false, 0xab82, 0xab82 }, +/* 0xab83 */ { false, 0xab83, 0xab83 }, +/* 0xab84 */ { false, 0xab84, 0xab84 }, +/* 0xab85 */ { false, 0xab85, 0xab85 }, +/* 0xab86 */ { false, 0xab86, 0xab86 }, +/* 0xab87 */ { false, 0xab87, 0xab87 }, +/* 0xab88 */ { false, 0xab88, 0xab88 }, +/* 0xab89 */ { false, 0xab89, 0xab89 }, +/* 0xab8a */ { false, 0xab8a, 0xab8a }, +/* 0xab8b */ { false, 0xab8b, 0xab8b }, +/* 0xab8c */ { false, 0xab8c, 0xab8c }, +/* 0xab8d */ { false, 0xab8d, 0xab8d }, +/* 0xab8e */ { false, 0xab8e, 0xab8e }, +/* 0xab8f */ { false, 0xab8f, 0xab8f }, +/* 0xab90 */ { false, 0xab90, 0xab90 }, +/* 0xab91 */ { false, 0xab91, 0xab91 }, +/* 0xab92 */ { false, 0xab92, 0xab92 }, +/* 0xab93 */ { false, 0xab93, 0xab93 }, +/* 0xab94 */ { false, 0xab94, 0xab94 }, +/* 0xab95 */ { false, 0xab95, 0xab95 }, +/* 0xab96 */ { false, 0xab96, 0xab96 }, +/* 0xab97 */ { false, 0xab97, 0xab97 }, +/* 0xab98 */ { false, 0xab98, 0xab98 }, +/* 0xab99 */ { false, 0xab99, 0xab99 }, +/* 0xab9a */ { false, 0xab9a, 0xab9a }, +/* 0xab9b */ { false, 0xab9b, 0xab9b }, +/* 0xab9c */ { false, 0xab9c, 0xab9c }, +/* 0xab9d */ { false, 0xab9d, 0xab9d }, +/* 0xab9e */ { false, 0xab9e, 0xab9e }, +/* 0xab9f */ { false, 0xab9f, 0xab9f }, +/* 0xaba0 */ { false, 0xaba0, 0xaba0 }, +/* 0xaba1 */ { false, 0xaba1, 0xaba1 }, +/* 0xaba2 */ { false, 0xaba2, 0xaba2 }, +/* 0xaba3 */ { false, 0xaba3, 0xaba3 }, +/* 0xaba4 */ { false, 0xaba4, 0xaba4 }, +/* 0xaba5 */ { false, 0xaba5, 0xaba5 }, +/* 0xaba6 */ { false, 0xaba6, 0xaba6 }, +/* 0xaba7 */ { false, 0xaba7, 0xaba7 }, +/* 0xaba8 */ { false, 0xaba8, 0xaba8 }, +/* 0xaba9 */ { false, 0xaba9, 0xaba9 }, +/* 0xabaa */ { false, 0xabaa, 0xabaa }, +/* 0xabab */ { false, 0xabab, 0xabab }, +/* 0xabac */ { false, 0xabac, 0xabac }, +/* 0xabad */ { false, 0xabad, 0xabad }, +/* 0xabae */ { false, 0xabae, 0xabae }, +/* 0xabaf */ { false, 0xabaf, 0xabaf }, +/* 0xabb0 */ { false, 0xabb0, 0xabb0 }, +/* 0xabb1 */ { false, 0xabb1, 0xabb1 }, +/* 0xabb2 */ { false, 0xabb2, 0xabb2 }, +/* 0xabb3 */ { false, 0xabb3, 0xabb3 }, +/* 0xabb4 */ { false, 0xabb4, 0xabb4 }, +/* 0xabb5 */ { false, 0xabb5, 0xabb5 }, +/* 0xabb6 */ { false, 0xabb6, 0xabb6 }, +/* 0xabb7 */ { false, 0xabb7, 0xabb7 }, +/* 0xabb8 */ { false, 0xabb8, 0xabb8 }, +/* 0xabb9 */ { false, 0xabb9, 0xabb9 }, +/* 0xabba */ { false, 0xabba, 0xabba }, +/* 0xabbb */ { false, 0xabbb, 0xabbb }, +/* 0xabbc */ { false, 0xabbc, 0xabbc }, +/* 0xabbd */ { false, 0xabbd, 0xabbd }, +/* 0xabbe */ { false, 0xabbe, 0xabbe }, +/* 0xabbf */ { false, 0xabbf, 0xabbf }, +/* 0xabc0 */ { false, 0xabc0, 0xabc0 }, +/* 0xabc1 */ { false, 0xabc1, 0xabc1 }, +/* 0xabc2 */ { false, 0xabc2, 0xabc2 }, +/* 0xabc3 */ { false, 0xabc3, 0xabc3 }, +/* 0xabc4 */ { false, 0xabc4, 0xabc4 }, +/* 0xabc5 */ { false, 0xabc5, 0xabc5 }, +/* 0xabc6 */ { false, 0xabc6, 0xabc6 }, +/* 0xabc7 */ { false, 0xabc7, 0xabc7 }, +/* 0xabc8 */ { false, 0xabc8, 0xabc8 }, +/* 0xabc9 */ { false, 0xabc9, 0xabc9 }, +/* 0xabca */ { false, 0xabca, 0xabca }, +/* 0xabcb */ { false, 0xabcb, 0xabcb }, +/* 0xabcc */ { false, 0xabcc, 0xabcc }, +/* 0xabcd */ { false, 0xabcd, 0xabcd }, +/* 0xabce */ { false, 0xabce, 0xabce }, +/* 0xabcf */ { false, 0xabcf, 0xabcf }, +/* 0xabd0 */ { false, 0xabd0, 0xabd0 }, +/* 0xabd1 */ { false, 0xabd1, 0xabd1 }, +/* 0xabd2 */ { false, 0xabd2, 0xabd2 }, +/* 0xabd3 */ { false, 0xabd3, 0xabd3 }, +/* 0xabd4 */ { false, 0xabd4, 0xabd4 }, +/* 0xabd5 */ { false, 0xabd5, 0xabd5 }, +/* 0xabd6 */ { false, 0xabd6, 0xabd6 }, +/* 0xabd7 */ { false, 0xabd7, 0xabd7 }, +/* 0xabd8 */ { false, 0xabd8, 0xabd8 }, +/* 0xabd9 */ { false, 0xabd9, 0xabd9 }, +/* 0xabda */ { false, 0xabda, 0xabda }, +/* 0xabdb */ { false, 0xabdb, 0xabdb }, +/* 0xabdc */ { false, 0xabdc, 0xabdc }, +/* 0xabdd */ { false, 0xabdd, 0xabdd }, +/* 0xabde */ { false, 0xabde, 0xabde }, +/* 0xabdf */ { false, 0xabdf, 0xabdf }, +/* 0xabe0 */ { false, 0xabe0, 0xabe0 }, +/* 0xabe1 */ { false, 0xabe1, 0xabe1 }, +/* 0xabe2 */ { false, 0xabe2, 0xabe2 }, +/* 0xabe3 */ { true, 0xabe3, 0xabe3 }, +/* 0xabe4 */ { true, 0xabe4, 0xabe4 }, +/* 0xabe5 */ { false, 0xabe5, 0xabe5 }, +/* 0xabe6 */ { true, 0xabe6, 0xabe6 }, +/* 0xabe7 */ { true, 0xabe7, 0xabe7 }, +/* 0xabe8 */ { false, 0xabe8, 0xabe8 }, +/* 0xabe9 */ { true, 0xabe9, 0xabe9 }, +/* 0xabea */ { true, 0xabea, 0xabea }, +/* 0xabeb */ { false, 0xabeb, 0xabeb }, +/* 0xabec */ { true, 0xabec, 0xabec }, +/* 0xabed */ { false, 0xabed, 0xabed }, +/* 0xabee */ { false, 0xabee, 0xabee }, +/* 0xabef */ { false, 0xabef, 0xabef }, +/* 0xabf0 */ { false, 0xabf0, 0xabf0 }, +/* 0xabf1 */ { false, 0xabf1, 0xabf1 }, +/* 0xabf2 */ { false, 0xabf2, 0xabf2 }, +/* 0xabf3 */ { false, 0xabf3, 0xabf3 }, +/* 0xabf4 */ { false, 0xabf4, 0xabf4 }, +/* 0xabf5 */ { false, 0xabf5, 0xabf5 }, +/* 0xabf6 */ { false, 0xabf6, 0xabf6 }, +/* 0xabf7 */ { false, 0xabf7, 0xabf7 }, +/* 0xabf8 */ { false, 0xabf8, 0xabf8 }, +/* 0xabf9 */ { false, 0xabf9, 0xabf9 }, +/* 0xabfa */ { false, 0xabfa, 0xabfa }, +/* 0xabfb */ { false, 0xabfb, 0xabfb }, +/* 0xabfc */ { false, 0xabfc, 0xabfc }, +/* 0xabfd */ { false, 0xabfd, 0xabfd }, +/* 0xabfe */ { false, 0xabfe, 0xabfe }, +/* 0xabff */ { false, 0xabff, 0xabff }, +/* 0xac00 */ { true, 0xac00, 0xac00 }, +/* 0xac01 */ { true, 0xac01, 0xac01 }, +/* 0xac02 */ { true, 0xac02, 0xac02 }, +/* 0xac03 */ { true, 0xac03, 0xac03 }, +/* 0xac04 */ { true, 0xac04, 0xac04 }, +/* 0xac05 */ { true, 0xac05, 0xac05 }, +/* 0xac06 */ { true, 0xac06, 0xac06 }, +/* 0xac07 */ { true, 0xac07, 0xac07 }, +/* 0xac08 */ { true, 0xac08, 0xac08 }, +/* 0xac09 */ { true, 0xac09, 0xac09 }, +/* 0xac0a */ { true, 0xac0a, 0xac0a }, +/* 0xac0b */ { true, 0xac0b, 0xac0b }, +/* 0xac0c */ { true, 0xac0c, 0xac0c }, +/* 0xac0d */ { true, 0xac0d, 0xac0d }, +/* 0xac0e */ { true, 0xac0e, 0xac0e }, +/* 0xac0f */ { true, 0xac0f, 0xac0f }, +/* 0xac10 */ { true, 0xac10, 0xac10 }, +/* 0xac11 */ { true, 0xac11, 0xac11 }, +/* 0xac12 */ { true, 0xac12, 0xac12 }, +/* 0xac13 */ { true, 0xac13, 0xac13 }, +/* 0xac14 */ { true, 0xac14, 0xac14 }, +/* 0xac15 */ { true, 0xac15, 0xac15 }, +/* 0xac16 */ { true, 0xac16, 0xac16 }, +/* 0xac17 */ { true, 0xac17, 0xac17 }, +/* 0xac18 */ { true, 0xac18, 0xac18 }, +/* 0xac19 */ { true, 0xac19, 0xac19 }, +/* 0xac1a */ { true, 0xac1a, 0xac1a }, +/* 0xac1b */ { true, 0xac1b, 0xac1b }, +/* 0xac1c */ { true, 0xac1c, 0xac1c }, +/* 0xac1d */ { true, 0xac1d, 0xac1d }, +/* 0xac1e */ { true, 0xac1e, 0xac1e }, +/* 0xac1f */ { true, 0xac1f, 0xac1f }, +/* 0xac20 */ { true, 0xac20, 0xac20 }, +/* 0xac21 */ { true, 0xac21, 0xac21 }, +/* 0xac22 */ { true, 0xac22, 0xac22 }, +/* 0xac23 */ { true, 0xac23, 0xac23 }, +/* 0xac24 */ { true, 0xac24, 0xac24 }, +/* 0xac25 */ { true, 0xac25, 0xac25 }, +/* 0xac26 */ { true, 0xac26, 0xac26 }, +/* 0xac27 */ { true, 0xac27, 0xac27 }, +/* 0xac28 */ { true, 0xac28, 0xac28 }, +/* 0xac29 */ { true, 0xac29, 0xac29 }, +/* 0xac2a */ { true, 0xac2a, 0xac2a }, +/* 0xac2b */ { true, 0xac2b, 0xac2b }, +/* 0xac2c */ { true, 0xac2c, 0xac2c }, +/* 0xac2d */ { true, 0xac2d, 0xac2d }, +/* 0xac2e */ { true, 0xac2e, 0xac2e }, +/* 0xac2f */ { true, 0xac2f, 0xac2f }, +/* 0xac30 */ { true, 0xac30, 0xac30 }, +/* 0xac31 */ { true, 0xac31, 0xac31 }, +/* 0xac32 */ { true, 0xac32, 0xac32 }, +/* 0xac33 */ { true, 0xac33, 0xac33 }, +/* 0xac34 */ { true, 0xac34, 0xac34 }, +/* 0xac35 */ { true, 0xac35, 0xac35 }, +/* 0xac36 */ { true, 0xac36, 0xac36 }, +/* 0xac37 */ { true, 0xac37, 0xac37 }, +/* 0xac38 */ { true, 0xac38, 0xac38 }, +/* 0xac39 */ { true, 0xac39, 0xac39 }, +/* 0xac3a */ { true, 0xac3a, 0xac3a }, +/* 0xac3b */ { true, 0xac3b, 0xac3b }, +/* 0xac3c */ { true, 0xac3c, 0xac3c }, +/* 0xac3d */ { true, 0xac3d, 0xac3d }, +/* 0xac3e */ { true, 0xac3e, 0xac3e }, +/* 0xac3f */ { true, 0xac3f, 0xac3f }, +/* 0xac40 */ { true, 0xac40, 0xac40 }, +/* 0xac41 */ { true, 0xac41, 0xac41 }, +/* 0xac42 */ { true, 0xac42, 0xac42 }, +/* 0xac43 */ { true, 0xac43, 0xac43 }, +/* 0xac44 */ { true, 0xac44, 0xac44 }, +/* 0xac45 */ { true, 0xac45, 0xac45 }, +/* 0xac46 */ { true, 0xac46, 0xac46 }, +/* 0xac47 */ { true, 0xac47, 0xac47 }, +/* 0xac48 */ { true, 0xac48, 0xac48 }, +/* 0xac49 */ { true, 0xac49, 0xac49 }, +/* 0xac4a */ { true, 0xac4a, 0xac4a }, +/* 0xac4b */ { true, 0xac4b, 0xac4b }, +/* 0xac4c */ { true, 0xac4c, 0xac4c }, +/* 0xac4d */ { true, 0xac4d, 0xac4d }, +/* 0xac4e */ { true, 0xac4e, 0xac4e }, +/* 0xac4f */ { true, 0xac4f, 0xac4f }, +/* 0xac50 */ { true, 0xac50, 0xac50 }, +/* 0xac51 */ { true, 0xac51, 0xac51 }, +/* 0xac52 */ { true, 0xac52, 0xac52 }, +/* 0xac53 */ { true, 0xac53, 0xac53 }, +/* 0xac54 */ { true, 0xac54, 0xac54 }, +/* 0xac55 */ { true, 0xac55, 0xac55 }, +/* 0xac56 */ { true, 0xac56, 0xac56 }, +/* 0xac57 */ { true, 0xac57, 0xac57 }, +/* 0xac58 */ { true, 0xac58, 0xac58 }, +/* 0xac59 */ { true, 0xac59, 0xac59 }, +/* 0xac5a */ { true, 0xac5a, 0xac5a }, +/* 0xac5b */ { true, 0xac5b, 0xac5b }, +/* 0xac5c */ { true, 0xac5c, 0xac5c }, +/* 0xac5d */ { true, 0xac5d, 0xac5d }, +/* 0xac5e */ { true, 0xac5e, 0xac5e }, +/* 0xac5f */ { true, 0xac5f, 0xac5f }, +/* 0xac60 */ { true, 0xac60, 0xac60 }, +/* 0xac61 */ { true, 0xac61, 0xac61 }, +/* 0xac62 */ { true, 0xac62, 0xac62 }, +/* 0xac63 */ { true, 0xac63, 0xac63 }, +/* 0xac64 */ { true, 0xac64, 0xac64 }, +/* 0xac65 */ { true, 0xac65, 0xac65 }, +/* 0xac66 */ { true, 0xac66, 0xac66 }, +/* 0xac67 */ { true, 0xac67, 0xac67 }, +/* 0xac68 */ { true, 0xac68, 0xac68 }, +/* 0xac69 */ { true, 0xac69, 0xac69 }, +/* 0xac6a */ { true, 0xac6a, 0xac6a }, +/* 0xac6b */ { true, 0xac6b, 0xac6b }, +/* 0xac6c */ { true, 0xac6c, 0xac6c }, +/* 0xac6d */ { true, 0xac6d, 0xac6d }, +/* 0xac6e */ { true, 0xac6e, 0xac6e }, +/* 0xac6f */ { true, 0xac6f, 0xac6f }, +/* 0xac70 */ { true, 0xac70, 0xac70 }, +/* 0xac71 */ { true, 0xac71, 0xac71 }, +/* 0xac72 */ { true, 0xac72, 0xac72 }, +/* 0xac73 */ { true, 0xac73, 0xac73 }, +/* 0xac74 */ { true, 0xac74, 0xac74 }, +/* 0xac75 */ { true, 0xac75, 0xac75 }, +/* 0xac76 */ { true, 0xac76, 0xac76 }, +/* 0xac77 */ { true, 0xac77, 0xac77 }, +/* 0xac78 */ { true, 0xac78, 0xac78 }, +/* 0xac79 */ { true, 0xac79, 0xac79 }, +/* 0xac7a */ { true, 0xac7a, 0xac7a }, +/* 0xac7b */ { true, 0xac7b, 0xac7b }, +/* 0xac7c */ { true, 0xac7c, 0xac7c }, +/* 0xac7d */ { true, 0xac7d, 0xac7d }, +/* 0xac7e */ { true, 0xac7e, 0xac7e }, +/* 0xac7f */ { true, 0xac7f, 0xac7f }, +/* 0xac80 */ { true, 0xac80, 0xac80 }, +/* 0xac81 */ { true, 0xac81, 0xac81 }, +/* 0xac82 */ { true, 0xac82, 0xac82 }, +/* 0xac83 */ { true, 0xac83, 0xac83 }, +/* 0xac84 */ { true, 0xac84, 0xac84 }, +/* 0xac85 */ { true, 0xac85, 0xac85 }, +/* 0xac86 */ { true, 0xac86, 0xac86 }, +/* 0xac87 */ { true, 0xac87, 0xac87 }, +/* 0xac88 */ { true, 0xac88, 0xac88 }, +/* 0xac89 */ { true, 0xac89, 0xac89 }, +/* 0xac8a */ { true, 0xac8a, 0xac8a }, +/* 0xac8b */ { true, 0xac8b, 0xac8b }, +/* 0xac8c */ { true, 0xac8c, 0xac8c }, +/* 0xac8d */ { true, 0xac8d, 0xac8d }, +/* 0xac8e */ { true, 0xac8e, 0xac8e }, +/* 0xac8f */ { true, 0xac8f, 0xac8f }, +/* 0xac90 */ { true, 0xac90, 0xac90 }, +/* 0xac91 */ { true, 0xac91, 0xac91 }, +/* 0xac92 */ { true, 0xac92, 0xac92 }, +/* 0xac93 */ { true, 0xac93, 0xac93 }, +/* 0xac94 */ { true, 0xac94, 0xac94 }, +/* 0xac95 */ { true, 0xac95, 0xac95 }, +/* 0xac96 */ { true, 0xac96, 0xac96 }, +/* 0xac97 */ { true, 0xac97, 0xac97 }, +/* 0xac98 */ { true, 0xac98, 0xac98 }, +/* 0xac99 */ { true, 0xac99, 0xac99 }, +/* 0xac9a */ { true, 0xac9a, 0xac9a }, +/* 0xac9b */ { true, 0xac9b, 0xac9b }, +/* 0xac9c */ { true, 0xac9c, 0xac9c }, +/* 0xac9d */ { true, 0xac9d, 0xac9d }, +/* 0xac9e */ { true, 0xac9e, 0xac9e }, +/* 0xac9f */ { true, 0xac9f, 0xac9f }, +/* 0xaca0 */ { true, 0xaca0, 0xaca0 }, +/* 0xaca1 */ { true, 0xaca1, 0xaca1 }, +/* 0xaca2 */ { true, 0xaca2, 0xaca2 }, +/* 0xaca3 */ { true, 0xaca3, 0xaca3 }, +/* 0xaca4 */ { true, 0xaca4, 0xaca4 }, +/* 0xaca5 */ { true, 0xaca5, 0xaca5 }, +/* 0xaca6 */ { true, 0xaca6, 0xaca6 }, +/* 0xaca7 */ { true, 0xaca7, 0xaca7 }, +/* 0xaca8 */ { true, 0xaca8, 0xaca8 }, +/* 0xaca9 */ { true, 0xaca9, 0xaca9 }, +/* 0xacaa */ { true, 0xacaa, 0xacaa }, +/* 0xacab */ { true, 0xacab, 0xacab }, +/* 0xacac */ { true, 0xacac, 0xacac }, +/* 0xacad */ { true, 0xacad, 0xacad }, +/* 0xacae */ { true, 0xacae, 0xacae }, +/* 0xacaf */ { true, 0xacaf, 0xacaf }, +/* 0xacb0 */ { true, 0xacb0, 0xacb0 }, +/* 0xacb1 */ { true, 0xacb1, 0xacb1 }, +/* 0xacb2 */ { true, 0xacb2, 0xacb2 }, +/* 0xacb3 */ { true, 0xacb3, 0xacb3 }, +/* 0xacb4 */ { true, 0xacb4, 0xacb4 }, +/* 0xacb5 */ { true, 0xacb5, 0xacb5 }, +/* 0xacb6 */ { true, 0xacb6, 0xacb6 }, +/* 0xacb7 */ { true, 0xacb7, 0xacb7 }, +/* 0xacb8 */ { true, 0xacb8, 0xacb8 }, +/* 0xacb9 */ { true, 0xacb9, 0xacb9 }, +/* 0xacba */ { true, 0xacba, 0xacba }, +/* 0xacbb */ { true, 0xacbb, 0xacbb }, +/* 0xacbc */ { true, 0xacbc, 0xacbc }, +/* 0xacbd */ { true, 0xacbd, 0xacbd }, +/* 0xacbe */ { true, 0xacbe, 0xacbe }, +/* 0xacbf */ { true, 0xacbf, 0xacbf }, +/* 0xacc0 */ { true, 0xacc0, 0xacc0 }, +/* 0xacc1 */ { true, 0xacc1, 0xacc1 }, +/* 0xacc2 */ { true, 0xacc2, 0xacc2 }, +/* 0xacc3 */ { true, 0xacc3, 0xacc3 }, +/* 0xacc4 */ { true, 0xacc4, 0xacc4 }, +/* 0xacc5 */ { true, 0xacc5, 0xacc5 }, +/* 0xacc6 */ { true, 0xacc6, 0xacc6 }, +/* 0xacc7 */ { true, 0xacc7, 0xacc7 }, +/* 0xacc8 */ { true, 0xacc8, 0xacc8 }, +/* 0xacc9 */ { true, 0xacc9, 0xacc9 }, +/* 0xacca */ { true, 0xacca, 0xacca }, +/* 0xaccb */ { true, 0xaccb, 0xaccb }, +/* 0xaccc */ { true, 0xaccc, 0xaccc }, +/* 0xaccd */ { true, 0xaccd, 0xaccd }, +/* 0xacce */ { true, 0xacce, 0xacce }, +/* 0xaccf */ { true, 0xaccf, 0xaccf }, +/* 0xacd0 */ { true, 0xacd0, 0xacd0 }, +/* 0xacd1 */ { true, 0xacd1, 0xacd1 }, +/* 0xacd2 */ { true, 0xacd2, 0xacd2 }, +/* 0xacd3 */ { true, 0xacd3, 0xacd3 }, +/* 0xacd4 */ { true, 0xacd4, 0xacd4 }, +/* 0xacd5 */ { true, 0xacd5, 0xacd5 }, +/* 0xacd6 */ { true, 0xacd6, 0xacd6 }, +/* 0xacd7 */ { true, 0xacd7, 0xacd7 }, +/* 0xacd8 */ { true, 0xacd8, 0xacd8 }, +/* 0xacd9 */ { true, 0xacd9, 0xacd9 }, +/* 0xacda */ { true, 0xacda, 0xacda }, +/* 0xacdb */ { true, 0xacdb, 0xacdb }, +/* 0xacdc */ { true, 0xacdc, 0xacdc }, +/* 0xacdd */ { true, 0xacdd, 0xacdd }, +/* 0xacde */ { true, 0xacde, 0xacde }, +/* 0xacdf */ { true, 0xacdf, 0xacdf }, +/* 0xace0 */ { true, 0xace0, 0xace0 }, +/* 0xace1 */ { true, 0xace1, 0xace1 }, +/* 0xace2 */ { true, 0xace2, 0xace2 }, +/* 0xace3 */ { true, 0xace3, 0xace3 }, +/* 0xace4 */ { true, 0xace4, 0xace4 }, +/* 0xace5 */ { true, 0xace5, 0xace5 }, +/* 0xace6 */ { true, 0xace6, 0xace6 }, +/* 0xace7 */ { true, 0xace7, 0xace7 }, +/* 0xace8 */ { true, 0xace8, 0xace8 }, +/* 0xace9 */ { true, 0xace9, 0xace9 }, +/* 0xacea */ { true, 0xacea, 0xacea }, +/* 0xaceb */ { true, 0xaceb, 0xaceb }, +/* 0xacec */ { true, 0xacec, 0xacec }, +/* 0xaced */ { true, 0xaced, 0xaced }, +/* 0xacee */ { true, 0xacee, 0xacee }, +/* 0xacef */ { true, 0xacef, 0xacef }, +/* 0xacf0 */ { true, 0xacf0, 0xacf0 }, +/* 0xacf1 */ { true, 0xacf1, 0xacf1 }, +/* 0xacf2 */ { true, 0xacf2, 0xacf2 }, +/* 0xacf3 */ { true, 0xacf3, 0xacf3 }, +/* 0xacf4 */ { true, 0xacf4, 0xacf4 }, +/* 0xacf5 */ { true, 0xacf5, 0xacf5 }, +/* 0xacf6 */ { true, 0xacf6, 0xacf6 }, +/* 0xacf7 */ { true, 0xacf7, 0xacf7 }, +/* 0xacf8 */ { true, 0xacf8, 0xacf8 }, +/* 0xacf9 */ { true, 0xacf9, 0xacf9 }, +/* 0xacfa */ { true, 0xacfa, 0xacfa }, +/* 0xacfb */ { true, 0xacfb, 0xacfb }, +/* 0xacfc */ { true, 0xacfc, 0xacfc }, +/* 0xacfd */ { true, 0xacfd, 0xacfd }, +/* 0xacfe */ { true, 0xacfe, 0xacfe }, +/* 0xacff */ { true, 0xacff, 0xacff }, +/* 0xad00 */ { true, 0xad00, 0xad00 }, +/* 0xad01 */ { true, 0xad01, 0xad01 }, +/* 0xad02 */ { true, 0xad02, 0xad02 }, +/* 0xad03 */ { true, 0xad03, 0xad03 }, +/* 0xad04 */ { true, 0xad04, 0xad04 }, +/* 0xad05 */ { true, 0xad05, 0xad05 }, +/* 0xad06 */ { true, 0xad06, 0xad06 }, +/* 0xad07 */ { true, 0xad07, 0xad07 }, +/* 0xad08 */ { true, 0xad08, 0xad08 }, +/* 0xad09 */ { true, 0xad09, 0xad09 }, +/* 0xad0a */ { true, 0xad0a, 0xad0a }, +/* 0xad0b */ { true, 0xad0b, 0xad0b }, +/* 0xad0c */ { true, 0xad0c, 0xad0c }, +/* 0xad0d */ { true, 0xad0d, 0xad0d }, +/* 0xad0e */ { true, 0xad0e, 0xad0e }, +/* 0xad0f */ { true, 0xad0f, 0xad0f }, +/* 0xad10 */ { true, 0xad10, 0xad10 }, +/* 0xad11 */ { true, 0xad11, 0xad11 }, +/* 0xad12 */ { true, 0xad12, 0xad12 }, +/* 0xad13 */ { true, 0xad13, 0xad13 }, +/* 0xad14 */ { true, 0xad14, 0xad14 }, +/* 0xad15 */ { true, 0xad15, 0xad15 }, +/* 0xad16 */ { true, 0xad16, 0xad16 }, +/* 0xad17 */ { true, 0xad17, 0xad17 }, +/* 0xad18 */ { true, 0xad18, 0xad18 }, +/* 0xad19 */ { true, 0xad19, 0xad19 }, +/* 0xad1a */ { true, 0xad1a, 0xad1a }, +/* 0xad1b */ { true, 0xad1b, 0xad1b }, +/* 0xad1c */ { true, 0xad1c, 0xad1c }, +/* 0xad1d */ { true, 0xad1d, 0xad1d }, +/* 0xad1e */ { true, 0xad1e, 0xad1e }, +/* 0xad1f */ { true, 0xad1f, 0xad1f }, +/* 0xad20 */ { true, 0xad20, 0xad20 }, +/* 0xad21 */ { true, 0xad21, 0xad21 }, +/* 0xad22 */ { true, 0xad22, 0xad22 }, +/* 0xad23 */ { true, 0xad23, 0xad23 }, +/* 0xad24 */ { true, 0xad24, 0xad24 }, +/* 0xad25 */ { true, 0xad25, 0xad25 }, +/* 0xad26 */ { true, 0xad26, 0xad26 }, +/* 0xad27 */ { true, 0xad27, 0xad27 }, +/* 0xad28 */ { true, 0xad28, 0xad28 }, +/* 0xad29 */ { true, 0xad29, 0xad29 }, +/* 0xad2a */ { true, 0xad2a, 0xad2a }, +/* 0xad2b */ { true, 0xad2b, 0xad2b }, +/* 0xad2c */ { true, 0xad2c, 0xad2c }, +/* 0xad2d */ { true, 0xad2d, 0xad2d }, +/* 0xad2e */ { true, 0xad2e, 0xad2e }, +/* 0xad2f */ { true, 0xad2f, 0xad2f }, +/* 0xad30 */ { true, 0xad30, 0xad30 }, +/* 0xad31 */ { true, 0xad31, 0xad31 }, +/* 0xad32 */ { true, 0xad32, 0xad32 }, +/* 0xad33 */ { true, 0xad33, 0xad33 }, +/* 0xad34 */ { true, 0xad34, 0xad34 }, +/* 0xad35 */ { true, 0xad35, 0xad35 }, +/* 0xad36 */ { true, 0xad36, 0xad36 }, +/* 0xad37 */ { true, 0xad37, 0xad37 }, +/* 0xad38 */ { true, 0xad38, 0xad38 }, +/* 0xad39 */ { true, 0xad39, 0xad39 }, +/* 0xad3a */ { true, 0xad3a, 0xad3a }, +/* 0xad3b */ { true, 0xad3b, 0xad3b }, +/* 0xad3c */ { true, 0xad3c, 0xad3c }, +/* 0xad3d */ { true, 0xad3d, 0xad3d }, +/* 0xad3e */ { true, 0xad3e, 0xad3e }, +/* 0xad3f */ { true, 0xad3f, 0xad3f }, +/* 0xad40 */ { true, 0xad40, 0xad40 }, +/* 0xad41 */ { true, 0xad41, 0xad41 }, +/* 0xad42 */ { true, 0xad42, 0xad42 }, +/* 0xad43 */ { true, 0xad43, 0xad43 }, +/* 0xad44 */ { true, 0xad44, 0xad44 }, +/* 0xad45 */ { true, 0xad45, 0xad45 }, +/* 0xad46 */ { true, 0xad46, 0xad46 }, +/* 0xad47 */ { true, 0xad47, 0xad47 }, +/* 0xad48 */ { true, 0xad48, 0xad48 }, +/* 0xad49 */ { true, 0xad49, 0xad49 }, +/* 0xad4a */ { true, 0xad4a, 0xad4a }, +/* 0xad4b */ { true, 0xad4b, 0xad4b }, +/* 0xad4c */ { true, 0xad4c, 0xad4c }, +/* 0xad4d */ { true, 0xad4d, 0xad4d }, +/* 0xad4e */ { true, 0xad4e, 0xad4e }, +/* 0xad4f */ { true, 0xad4f, 0xad4f }, +/* 0xad50 */ { true, 0xad50, 0xad50 }, +/* 0xad51 */ { true, 0xad51, 0xad51 }, +/* 0xad52 */ { true, 0xad52, 0xad52 }, +/* 0xad53 */ { true, 0xad53, 0xad53 }, +/* 0xad54 */ { true, 0xad54, 0xad54 }, +/* 0xad55 */ { true, 0xad55, 0xad55 }, +/* 0xad56 */ { true, 0xad56, 0xad56 }, +/* 0xad57 */ { true, 0xad57, 0xad57 }, +/* 0xad58 */ { true, 0xad58, 0xad58 }, +/* 0xad59 */ { true, 0xad59, 0xad59 }, +/* 0xad5a */ { true, 0xad5a, 0xad5a }, +/* 0xad5b */ { true, 0xad5b, 0xad5b }, +/* 0xad5c */ { true, 0xad5c, 0xad5c }, +/* 0xad5d */ { true, 0xad5d, 0xad5d }, +/* 0xad5e */ { true, 0xad5e, 0xad5e }, +/* 0xad5f */ { true, 0xad5f, 0xad5f }, +/* 0xad60 */ { true, 0xad60, 0xad60 }, +/* 0xad61 */ { true, 0xad61, 0xad61 }, +/* 0xad62 */ { true, 0xad62, 0xad62 }, +/* 0xad63 */ { true, 0xad63, 0xad63 }, +/* 0xad64 */ { true, 0xad64, 0xad64 }, +/* 0xad65 */ { true, 0xad65, 0xad65 }, +/* 0xad66 */ { true, 0xad66, 0xad66 }, +/* 0xad67 */ { true, 0xad67, 0xad67 }, +/* 0xad68 */ { true, 0xad68, 0xad68 }, +/* 0xad69 */ { true, 0xad69, 0xad69 }, +/* 0xad6a */ { true, 0xad6a, 0xad6a }, +/* 0xad6b */ { true, 0xad6b, 0xad6b }, +/* 0xad6c */ { true, 0xad6c, 0xad6c }, +/* 0xad6d */ { true, 0xad6d, 0xad6d }, +/* 0xad6e */ { true, 0xad6e, 0xad6e }, +/* 0xad6f */ { true, 0xad6f, 0xad6f }, +/* 0xad70 */ { true, 0xad70, 0xad70 }, +/* 0xad71 */ { true, 0xad71, 0xad71 }, +/* 0xad72 */ { true, 0xad72, 0xad72 }, +/* 0xad73 */ { true, 0xad73, 0xad73 }, +/* 0xad74 */ { true, 0xad74, 0xad74 }, +/* 0xad75 */ { true, 0xad75, 0xad75 }, +/* 0xad76 */ { true, 0xad76, 0xad76 }, +/* 0xad77 */ { true, 0xad77, 0xad77 }, +/* 0xad78 */ { true, 0xad78, 0xad78 }, +/* 0xad79 */ { true, 0xad79, 0xad79 }, +/* 0xad7a */ { true, 0xad7a, 0xad7a }, +/* 0xad7b */ { true, 0xad7b, 0xad7b }, +/* 0xad7c */ { true, 0xad7c, 0xad7c }, +/* 0xad7d */ { true, 0xad7d, 0xad7d }, +/* 0xad7e */ { true, 0xad7e, 0xad7e }, +/* 0xad7f */ { true, 0xad7f, 0xad7f }, +/* 0xad80 */ { true, 0xad80, 0xad80 }, +/* 0xad81 */ { true, 0xad81, 0xad81 }, +/* 0xad82 */ { true, 0xad82, 0xad82 }, +/* 0xad83 */ { true, 0xad83, 0xad83 }, +/* 0xad84 */ { true, 0xad84, 0xad84 }, +/* 0xad85 */ { true, 0xad85, 0xad85 }, +/* 0xad86 */ { true, 0xad86, 0xad86 }, +/* 0xad87 */ { true, 0xad87, 0xad87 }, +/* 0xad88 */ { true, 0xad88, 0xad88 }, +/* 0xad89 */ { true, 0xad89, 0xad89 }, +/* 0xad8a */ { true, 0xad8a, 0xad8a }, +/* 0xad8b */ { true, 0xad8b, 0xad8b }, +/* 0xad8c */ { true, 0xad8c, 0xad8c }, +/* 0xad8d */ { true, 0xad8d, 0xad8d }, +/* 0xad8e */ { true, 0xad8e, 0xad8e }, +/* 0xad8f */ { true, 0xad8f, 0xad8f }, +/* 0xad90 */ { true, 0xad90, 0xad90 }, +/* 0xad91 */ { true, 0xad91, 0xad91 }, +/* 0xad92 */ { true, 0xad92, 0xad92 }, +/* 0xad93 */ { true, 0xad93, 0xad93 }, +/* 0xad94 */ { true, 0xad94, 0xad94 }, +/* 0xad95 */ { true, 0xad95, 0xad95 }, +/* 0xad96 */ { true, 0xad96, 0xad96 }, +/* 0xad97 */ { true, 0xad97, 0xad97 }, +/* 0xad98 */ { true, 0xad98, 0xad98 }, +/* 0xad99 */ { true, 0xad99, 0xad99 }, +/* 0xad9a */ { true, 0xad9a, 0xad9a }, +/* 0xad9b */ { true, 0xad9b, 0xad9b }, +/* 0xad9c */ { true, 0xad9c, 0xad9c }, +/* 0xad9d */ { true, 0xad9d, 0xad9d }, +/* 0xad9e */ { true, 0xad9e, 0xad9e }, +/* 0xad9f */ { true, 0xad9f, 0xad9f }, +/* 0xada0 */ { true, 0xada0, 0xada0 }, +/* 0xada1 */ { true, 0xada1, 0xada1 }, +/* 0xada2 */ { true, 0xada2, 0xada2 }, +/* 0xada3 */ { true, 0xada3, 0xada3 }, +/* 0xada4 */ { true, 0xada4, 0xada4 }, +/* 0xada5 */ { true, 0xada5, 0xada5 }, +/* 0xada6 */ { true, 0xada6, 0xada6 }, +/* 0xada7 */ { true, 0xada7, 0xada7 }, +/* 0xada8 */ { true, 0xada8, 0xada8 }, +/* 0xada9 */ { true, 0xada9, 0xada9 }, +/* 0xadaa */ { true, 0xadaa, 0xadaa }, +/* 0xadab */ { true, 0xadab, 0xadab }, +/* 0xadac */ { true, 0xadac, 0xadac }, +/* 0xadad */ { true, 0xadad, 0xadad }, +/* 0xadae */ { true, 0xadae, 0xadae }, +/* 0xadaf */ { true, 0xadaf, 0xadaf }, +/* 0xadb0 */ { true, 0xadb0, 0xadb0 }, +/* 0xadb1 */ { true, 0xadb1, 0xadb1 }, +/* 0xadb2 */ { true, 0xadb2, 0xadb2 }, +/* 0xadb3 */ { true, 0xadb3, 0xadb3 }, +/* 0xadb4 */ { true, 0xadb4, 0xadb4 }, +/* 0xadb5 */ { true, 0xadb5, 0xadb5 }, +/* 0xadb6 */ { true, 0xadb6, 0xadb6 }, +/* 0xadb7 */ { true, 0xadb7, 0xadb7 }, +/* 0xadb8 */ { true, 0xadb8, 0xadb8 }, +/* 0xadb9 */ { true, 0xadb9, 0xadb9 }, +/* 0xadba */ { true, 0xadba, 0xadba }, +/* 0xadbb */ { true, 0xadbb, 0xadbb }, +/* 0xadbc */ { true, 0xadbc, 0xadbc }, +/* 0xadbd */ { true, 0xadbd, 0xadbd }, +/* 0xadbe */ { true, 0xadbe, 0xadbe }, +/* 0xadbf */ { true, 0xadbf, 0xadbf }, +/* 0xadc0 */ { true, 0xadc0, 0xadc0 }, +/* 0xadc1 */ { true, 0xadc1, 0xadc1 }, +/* 0xadc2 */ { true, 0xadc2, 0xadc2 }, +/* 0xadc3 */ { true, 0xadc3, 0xadc3 }, +/* 0xadc4 */ { true, 0xadc4, 0xadc4 }, +/* 0xadc5 */ { true, 0xadc5, 0xadc5 }, +/* 0xadc6 */ { true, 0xadc6, 0xadc6 }, +/* 0xadc7 */ { true, 0xadc7, 0xadc7 }, +/* 0xadc8 */ { true, 0xadc8, 0xadc8 }, +/* 0xadc9 */ { true, 0xadc9, 0xadc9 }, +/* 0xadca */ { true, 0xadca, 0xadca }, +/* 0xadcb */ { true, 0xadcb, 0xadcb }, +/* 0xadcc */ { true, 0xadcc, 0xadcc }, +/* 0xadcd */ { true, 0xadcd, 0xadcd }, +/* 0xadce */ { true, 0xadce, 0xadce }, +/* 0xadcf */ { true, 0xadcf, 0xadcf }, +/* 0xadd0 */ { true, 0xadd0, 0xadd0 }, +/* 0xadd1 */ { true, 0xadd1, 0xadd1 }, +/* 0xadd2 */ { true, 0xadd2, 0xadd2 }, +/* 0xadd3 */ { true, 0xadd3, 0xadd3 }, +/* 0xadd4 */ { true, 0xadd4, 0xadd4 }, +/* 0xadd5 */ { true, 0xadd5, 0xadd5 }, +/* 0xadd6 */ { true, 0xadd6, 0xadd6 }, +/* 0xadd7 */ { true, 0xadd7, 0xadd7 }, +/* 0xadd8 */ { true, 0xadd8, 0xadd8 }, +/* 0xadd9 */ { true, 0xadd9, 0xadd9 }, +/* 0xadda */ { true, 0xadda, 0xadda }, +/* 0xaddb */ { true, 0xaddb, 0xaddb }, +/* 0xaddc */ { true, 0xaddc, 0xaddc }, +/* 0xaddd */ { true, 0xaddd, 0xaddd }, +/* 0xadde */ { true, 0xadde, 0xadde }, +/* 0xaddf */ { true, 0xaddf, 0xaddf }, +/* 0xade0 */ { true, 0xade0, 0xade0 }, +/* 0xade1 */ { true, 0xade1, 0xade1 }, +/* 0xade2 */ { true, 0xade2, 0xade2 }, +/* 0xade3 */ { true, 0xade3, 0xade3 }, +/* 0xade4 */ { true, 0xade4, 0xade4 }, +/* 0xade5 */ { true, 0xade5, 0xade5 }, +/* 0xade6 */ { true, 0xade6, 0xade6 }, +/* 0xade7 */ { true, 0xade7, 0xade7 }, +/* 0xade8 */ { true, 0xade8, 0xade8 }, +/* 0xade9 */ { true, 0xade9, 0xade9 }, +/* 0xadea */ { true, 0xadea, 0xadea }, +/* 0xadeb */ { true, 0xadeb, 0xadeb }, +/* 0xadec */ { true, 0xadec, 0xadec }, +/* 0xaded */ { true, 0xaded, 0xaded }, +/* 0xadee */ { true, 0xadee, 0xadee }, +/* 0xadef */ { true, 0xadef, 0xadef }, +/* 0xadf0 */ { true, 0xadf0, 0xadf0 }, +/* 0xadf1 */ { true, 0xadf1, 0xadf1 }, +/* 0xadf2 */ { true, 0xadf2, 0xadf2 }, +/* 0xadf3 */ { true, 0xadf3, 0xadf3 }, +/* 0xadf4 */ { true, 0xadf4, 0xadf4 }, +/* 0xadf5 */ { true, 0xadf5, 0xadf5 }, +/* 0xadf6 */ { true, 0xadf6, 0xadf6 }, +/* 0xadf7 */ { true, 0xadf7, 0xadf7 }, +/* 0xadf8 */ { true, 0xadf8, 0xadf8 }, +/* 0xadf9 */ { true, 0xadf9, 0xadf9 }, +/* 0xadfa */ { true, 0xadfa, 0xadfa }, +/* 0xadfb */ { true, 0xadfb, 0xadfb }, +/* 0xadfc */ { true, 0xadfc, 0xadfc }, +/* 0xadfd */ { true, 0xadfd, 0xadfd }, +/* 0xadfe */ { true, 0xadfe, 0xadfe }, +/* 0xadff */ { true, 0xadff, 0xadff }, +/* 0xae00 */ { true, 0xae00, 0xae00 }, +/* 0xae01 */ { true, 0xae01, 0xae01 }, +/* 0xae02 */ { true, 0xae02, 0xae02 }, +/* 0xae03 */ { true, 0xae03, 0xae03 }, +/* 0xae04 */ { true, 0xae04, 0xae04 }, +/* 0xae05 */ { true, 0xae05, 0xae05 }, +/* 0xae06 */ { true, 0xae06, 0xae06 }, +/* 0xae07 */ { true, 0xae07, 0xae07 }, +/* 0xae08 */ { true, 0xae08, 0xae08 }, +/* 0xae09 */ { true, 0xae09, 0xae09 }, +/* 0xae0a */ { true, 0xae0a, 0xae0a }, +/* 0xae0b */ { true, 0xae0b, 0xae0b }, +/* 0xae0c */ { true, 0xae0c, 0xae0c }, +/* 0xae0d */ { true, 0xae0d, 0xae0d }, +/* 0xae0e */ { true, 0xae0e, 0xae0e }, +/* 0xae0f */ { true, 0xae0f, 0xae0f }, +/* 0xae10 */ { true, 0xae10, 0xae10 }, +/* 0xae11 */ { true, 0xae11, 0xae11 }, +/* 0xae12 */ { true, 0xae12, 0xae12 }, +/* 0xae13 */ { true, 0xae13, 0xae13 }, +/* 0xae14 */ { true, 0xae14, 0xae14 }, +/* 0xae15 */ { true, 0xae15, 0xae15 }, +/* 0xae16 */ { true, 0xae16, 0xae16 }, +/* 0xae17 */ { true, 0xae17, 0xae17 }, +/* 0xae18 */ { true, 0xae18, 0xae18 }, +/* 0xae19 */ { true, 0xae19, 0xae19 }, +/* 0xae1a */ { true, 0xae1a, 0xae1a }, +/* 0xae1b */ { true, 0xae1b, 0xae1b }, +/* 0xae1c */ { true, 0xae1c, 0xae1c }, +/* 0xae1d */ { true, 0xae1d, 0xae1d }, +/* 0xae1e */ { true, 0xae1e, 0xae1e }, +/* 0xae1f */ { true, 0xae1f, 0xae1f }, +/* 0xae20 */ { true, 0xae20, 0xae20 }, +/* 0xae21 */ { true, 0xae21, 0xae21 }, +/* 0xae22 */ { true, 0xae22, 0xae22 }, +/* 0xae23 */ { true, 0xae23, 0xae23 }, +/* 0xae24 */ { true, 0xae24, 0xae24 }, +/* 0xae25 */ { true, 0xae25, 0xae25 }, +/* 0xae26 */ { true, 0xae26, 0xae26 }, +/* 0xae27 */ { true, 0xae27, 0xae27 }, +/* 0xae28 */ { true, 0xae28, 0xae28 }, +/* 0xae29 */ { true, 0xae29, 0xae29 }, +/* 0xae2a */ { true, 0xae2a, 0xae2a }, +/* 0xae2b */ { true, 0xae2b, 0xae2b }, +/* 0xae2c */ { true, 0xae2c, 0xae2c }, +/* 0xae2d */ { true, 0xae2d, 0xae2d }, +/* 0xae2e */ { true, 0xae2e, 0xae2e }, +/* 0xae2f */ { true, 0xae2f, 0xae2f }, +/* 0xae30 */ { true, 0xae30, 0xae30 }, +/* 0xae31 */ { true, 0xae31, 0xae31 }, +/* 0xae32 */ { true, 0xae32, 0xae32 }, +/* 0xae33 */ { true, 0xae33, 0xae33 }, +/* 0xae34 */ { true, 0xae34, 0xae34 }, +/* 0xae35 */ { true, 0xae35, 0xae35 }, +/* 0xae36 */ { true, 0xae36, 0xae36 }, +/* 0xae37 */ { true, 0xae37, 0xae37 }, +/* 0xae38 */ { true, 0xae38, 0xae38 }, +/* 0xae39 */ { true, 0xae39, 0xae39 }, +/* 0xae3a */ { true, 0xae3a, 0xae3a }, +/* 0xae3b */ { true, 0xae3b, 0xae3b }, +/* 0xae3c */ { true, 0xae3c, 0xae3c }, +/* 0xae3d */ { true, 0xae3d, 0xae3d }, +/* 0xae3e */ { true, 0xae3e, 0xae3e }, +/* 0xae3f */ { true, 0xae3f, 0xae3f }, +/* 0xae40 */ { true, 0xae40, 0xae40 }, +/* 0xae41 */ { true, 0xae41, 0xae41 }, +/* 0xae42 */ { true, 0xae42, 0xae42 }, +/* 0xae43 */ { true, 0xae43, 0xae43 }, +/* 0xae44 */ { true, 0xae44, 0xae44 }, +/* 0xae45 */ { true, 0xae45, 0xae45 }, +/* 0xae46 */ { true, 0xae46, 0xae46 }, +/* 0xae47 */ { true, 0xae47, 0xae47 }, +/* 0xae48 */ { true, 0xae48, 0xae48 }, +/* 0xae49 */ { true, 0xae49, 0xae49 }, +/* 0xae4a */ { true, 0xae4a, 0xae4a }, +/* 0xae4b */ { true, 0xae4b, 0xae4b }, +/* 0xae4c */ { true, 0xae4c, 0xae4c }, +/* 0xae4d */ { true, 0xae4d, 0xae4d }, +/* 0xae4e */ { true, 0xae4e, 0xae4e }, +/* 0xae4f */ { true, 0xae4f, 0xae4f }, +/* 0xae50 */ { true, 0xae50, 0xae50 }, +/* 0xae51 */ { true, 0xae51, 0xae51 }, +/* 0xae52 */ { true, 0xae52, 0xae52 }, +/* 0xae53 */ { true, 0xae53, 0xae53 }, +/* 0xae54 */ { true, 0xae54, 0xae54 }, +/* 0xae55 */ { true, 0xae55, 0xae55 }, +/* 0xae56 */ { true, 0xae56, 0xae56 }, +/* 0xae57 */ { true, 0xae57, 0xae57 }, +/* 0xae58 */ { true, 0xae58, 0xae58 }, +/* 0xae59 */ { true, 0xae59, 0xae59 }, +/* 0xae5a */ { true, 0xae5a, 0xae5a }, +/* 0xae5b */ { true, 0xae5b, 0xae5b }, +/* 0xae5c */ { true, 0xae5c, 0xae5c }, +/* 0xae5d */ { true, 0xae5d, 0xae5d }, +/* 0xae5e */ { true, 0xae5e, 0xae5e }, +/* 0xae5f */ { true, 0xae5f, 0xae5f }, +/* 0xae60 */ { true, 0xae60, 0xae60 }, +/* 0xae61 */ { true, 0xae61, 0xae61 }, +/* 0xae62 */ { true, 0xae62, 0xae62 }, +/* 0xae63 */ { true, 0xae63, 0xae63 }, +/* 0xae64 */ { true, 0xae64, 0xae64 }, +/* 0xae65 */ { true, 0xae65, 0xae65 }, +/* 0xae66 */ { true, 0xae66, 0xae66 }, +/* 0xae67 */ { true, 0xae67, 0xae67 }, +/* 0xae68 */ { true, 0xae68, 0xae68 }, +/* 0xae69 */ { true, 0xae69, 0xae69 }, +/* 0xae6a */ { true, 0xae6a, 0xae6a }, +/* 0xae6b */ { true, 0xae6b, 0xae6b }, +/* 0xae6c */ { true, 0xae6c, 0xae6c }, +/* 0xae6d */ { true, 0xae6d, 0xae6d }, +/* 0xae6e */ { true, 0xae6e, 0xae6e }, +/* 0xae6f */ { true, 0xae6f, 0xae6f }, +/* 0xae70 */ { true, 0xae70, 0xae70 }, +/* 0xae71 */ { true, 0xae71, 0xae71 }, +/* 0xae72 */ { true, 0xae72, 0xae72 }, +/* 0xae73 */ { true, 0xae73, 0xae73 }, +/* 0xae74 */ { true, 0xae74, 0xae74 }, +/* 0xae75 */ { true, 0xae75, 0xae75 }, +/* 0xae76 */ { true, 0xae76, 0xae76 }, +/* 0xae77 */ { true, 0xae77, 0xae77 }, +/* 0xae78 */ { true, 0xae78, 0xae78 }, +/* 0xae79 */ { true, 0xae79, 0xae79 }, +/* 0xae7a */ { true, 0xae7a, 0xae7a }, +/* 0xae7b */ { true, 0xae7b, 0xae7b }, +/* 0xae7c */ { true, 0xae7c, 0xae7c }, +/* 0xae7d */ { true, 0xae7d, 0xae7d }, +/* 0xae7e */ { true, 0xae7e, 0xae7e }, +/* 0xae7f */ { true, 0xae7f, 0xae7f }, +/* 0xae80 */ { true, 0xae80, 0xae80 }, +/* 0xae81 */ { true, 0xae81, 0xae81 }, +/* 0xae82 */ { true, 0xae82, 0xae82 }, +/* 0xae83 */ { true, 0xae83, 0xae83 }, +/* 0xae84 */ { true, 0xae84, 0xae84 }, +/* 0xae85 */ { true, 0xae85, 0xae85 }, +/* 0xae86 */ { true, 0xae86, 0xae86 }, +/* 0xae87 */ { true, 0xae87, 0xae87 }, +/* 0xae88 */ { true, 0xae88, 0xae88 }, +/* 0xae89 */ { true, 0xae89, 0xae89 }, +/* 0xae8a */ { true, 0xae8a, 0xae8a }, +/* 0xae8b */ { true, 0xae8b, 0xae8b }, +/* 0xae8c */ { true, 0xae8c, 0xae8c }, +/* 0xae8d */ { true, 0xae8d, 0xae8d }, +/* 0xae8e */ { true, 0xae8e, 0xae8e }, +/* 0xae8f */ { true, 0xae8f, 0xae8f }, +/* 0xae90 */ { true, 0xae90, 0xae90 }, +/* 0xae91 */ { true, 0xae91, 0xae91 }, +/* 0xae92 */ { true, 0xae92, 0xae92 }, +/* 0xae93 */ { true, 0xae93, 0xae93 }, +/* 0xae94 */ { true, 0xae94, 0xae94 }, +/* 0xae95 */ { true, 0xae95, 0xae95 }, +/* 0xae96 */ { true, 0xae96, 0xae96 }, +/* 0xae97 */ { true, 0xae97, 0xae97 }, +/* 0xae98 */ { true, 0xae98, 0xae98 }, +/* 0xae99 */ { true, 0xae99, 0xae99 }, +/* 0xae9a */ { true, 0xae9a, 0xae9a }, +/* 0xae9b */ { true, 0xae9b, 0xae9b }, +/* 0xae9c */ { true, 0xae9c, 0xae9c }, +/* 0xae9d */ { true, 0xae9d, 0xae9d }, +/* 0xae9e */ { true, 0xae9e, 0xae9e }, +/* 0xae9f */ { true, 0xae9f, 0xae9f }, +/* 0xaea0 */ { true, 0xaea0, 0xaea0 }, +/* 0xaea1 */ { true, 0xaea1, 0xaea1 }, +/* 0xaea2 */ { true, 0xaea2, 0xaea2 }, +/* 0xaea3 */ { true, 0xaea3, 0xaea3 }, +/* 0xaea4 */ { true, 0xaea4, 0xaea4 }, +/* 0xaea5 */ { true, 0xaea5, 0xaea5 }, +/* 0xaea6 */ { true, 0xaea6, 0xaea6 }, +/* 0xaea7 */ { true, 0xaea7, 0xaea7 }, +/* 0xaea8 */ { true, 0xaea8, 0xaea8 }, +/* 0xaea9 */ { true, 0xaea9, 0xaea9 }, +/* 0xaeaa */ { true, 0xaeaa, 0xaeaa }, +/* 0xaeab */ { true, 0xaeab, 0xaeab }, +/* 0xaeac */ { true, 0xaeac, 0xaeac }, +/* 0xaead */ { true, 0xaead, 0xaead }, +/* 0xaeae */ { true, 0xaeae, 0xaeae }, +/* 0xaeaf */ { true, 0xaeaf, 0xaeaf }, +/* 0xaeb0 */ { true, 0xaeb0, 0xaeb0 }, +/* 0xaeb1 */ { true, 0xaeb1, 0xaeb1 }, +/* 0xaeb2 */ { true, 0xaeb2, 0xaeb2 }, +/* 0xaeb3 */ { true, 0xaeb3, 0xaeb3 }, +/* 0xaeb4 */ { true, 0xaeb4, 0xaeb4 }, +/* 0xaeb5 */ { true, 0xaeb5, 0xaeb5 }, +/* 0xaeb6 */ { true, 0xaeb6, 0xaeb6 }, +/* 0xaeb7 */ { true, 0xaeb7, 0xaeb7 }, +/* 0xaeb8 */ { true, 0xaeb8, 0xaeb8 }, +/* 0xaeb9 */ { true, 0xaeb9, 0xaeb9 }, +/* 0xaeba */ { true, 0xaeba, 0xaeba }, +/* 0xaebb */ { true, 0xaebb, 0xaebb }, +/* 0xaebc */ { true, 0xaebc, 0xaebc }, +/* 0xaebd */ { true, 0xaebd, 0xaebd }, +/* 0xaebe */ { true, 0xaebe, 0xaebe }, +/* 0xaebf */ { true, 0xaebf, 0xaebf }, +/* 0xaec0 */ { true, 0xaec0, 0xaec0 }, +/* 0xaec1 */ { true, 0xaec1, 0xaec1 }, +/* 0xaec2 */ { true, 0xaec2, 0xaec2 }, +/* 0xaec3 */ { true, 0xaec3, 0xaec3 }, +/* 0xaec4 */ { true, 0xaec4, 0xaec4 }, +/* 0xaec5 */ { true, 0xaec5, 0xaec5 }, +/* 0xaec6 */ { true, 0xaec6, 0xaec6 }, +/* 0xaec7 */ { true, 0xaec7, 0xaec7 }, +/* 0xaec8 */ { true, 0xaec8, 0xaec8 }, +/* 0xaec9 */ { true, 0xaec9, 0xaec9 }, +/* 0xaeca */ { true, 0xaeca, 0xaeca }, +/* 0xaecb */ { true, 0xaecb, 0xaecb }, +/* 0xaecc */ { true, 0xaecc, 0xaecc }, +/* 0xaecd */ { true, 0xaecd, 0xaecd }, +/* 0xaece */ { true, 0xaece, 0xaece }, +/* 0xaecf */ { true, 0xaecf, 0xaecf }, +/* 0xaed0 */ { true, 0xaed0, 0xaed0 }, +/* 0xaed1 */ { true, 0xaed1, 0xaed1 }, +/* 0xaed2 */ { true, 0xaed2, 0xaed2 }, +/* 0xaed3 */ { true, 0xaed3, 0xaed3 }, +/* 0xaed4 */ { true, 0xaed4, 0xaed4 }, +/* 0xaed5 */ { true, 0xaed5, 0xaed5 }, +/* 0xaed6 */ { true, 0xaed6, 0xaed6 }, +/* 0xaed7 */ { true, 0xaed7, 0xaed7 }, +/* 0xaed8 */ { true, 0xaed8, 0xaed8 }, +/* 0xaed9 */ { true, 0xaed9, 0xaed9 }, +/* 0xaeda */ { true, 0xaeda, 0xaeda }, +/* 0xaedb */ { true, 0xaedb, 0xaedb }, +/* 0xaedc */ { true, 0xaedc, 0xaedc }, +/* 0xaedd */ { true, 0xaedd, 0xaedd }, +/* 0xaede */ { true, 0xaede, 0xaede }, +/* 0xaedf */ { true, 0xaedf, 0xaedf }, +/* 0xaee0 */ { true, 0xaee0, 0xaee0 }, +/* 0xaee1 */ { true, 0xaee1, 0xaee1 }, +/* 0xaee2 */ { true, 0xaee2, 0xaee2 }, +/* 0xaee3 */ { true, 0xaee3, 0xaee3 }, +/* 0xaee4 */ { true, 0xaee4, 0xaee4 }, +/* 0xaee5 */ { true, 0xaee5, 0xaee5 }, +/* 0xaee6 */ { true, 0xaee6, 0xaee6 }, +/* 0xaee7 */ { true, 0xaee7, 0xaee7 }, +/* 0xaee8 */ { true, 0xaee8, 0xaee8 }, +/* 0xaee9 */ { true, 0xaee9, 0xaee9 }, +/* 0xaeea */ { true, 0xaeea, 0xaeea }, +/* 0xaeeb */ { true, 0xaeeb, 0xaeeb }, +/* 0xaeec */ { true, 0xaeec, 0xaeec }, +/* 0xaeed */ { true, 0xaeed, 0xaeed }, +/* 0xaeee */ { true, 0xaeee, 0xaeee }, +/* 0xaeef */ { true, 0xaeef, 0xaeef }, +/* 0xaef0 */ { true, 0xaef0, 0xaef0 }, +/* 0xaef1 */ { true, 0xaef1, 0xaef1 }, +/* 0xaef2 */ { true, 0xaef2, 0xaef2 }, +/* 0xaef3 */ { true, 0xaef3, 0xaef3 }, +/* 0xaef4 */ { true, 0xaef4, 0xaef4 }, +/* 0xaef5 */ { true, 0xaef5, 0xaef5 }, +/* 0xaef6 */ { true, 0xaef6, 0xaef6 }, +/* 0xaef7 */ { true, 0xaef7, 0xaef7 }, +/* 0xaef8 */ { true, 0xaef8, 0xaef8 }, +/* 0xaef9 */ { true, 0xaef9, 0xaef9 }, +/* 0xaefa */ { true, 0xaefa, 0xaefa }, +/* 0xaefb */ { true, 0xaefb, 0xaefb }, +/* 0xaefc */ { true, 0xaefc, 0xaefc }, +/* 0xaefd */ { true, 0xaefd, 0xaefd }, +/* 0xaefe */ { true, 0xaefe, 0xaefe }, +/* 0xaeff */ { true, 0xaeff, 0xaeff }, +/* 0xaf00 */ { true, 0xaf00, 0xaf00 }, +/* 0xaf01 */ { true, 0xaf01, 0xaf01 }, +/* 0xaf02 */ { true, 0xaf02, 0xaf02 }, +/* 0xaf03 */ { true, 0xaf03, 0xaf03 }, +/* 0xaf04 */ { true, 0xaf04, 0xaf04 }, +/* 0xaf05 */ { true, 0xaf05, 0xaf05 }, +/* 0xaf06 */ { true, 0xaf06, 0xaf06 }, +/* 0xaf07 */ { true, 0xaf07, 0xaf07 }, +/* 0xaf08 */ { true, 0xaf08, 0xaf08 }, +/* 0xaf09 */ { true, 0xaf09, 0xaf09 }, +/* 0xaf0a */ { true, 0xaf0a, 0xaf0a }, +/* 0xaf0b */ { true, 0xaf0b, 0xaf0b }, +/* 0xaf0c */ { true, 0xaf0c, 0xaf0c }, +/* 0xaf0d */ { true, 0xaf0d, 0xaf0d }, +/* 0xaf0e */ { true, 0xaf0e, 0xaf0e }, +/* 0xaf0f */ { true, 0xaf0f, 0xaf0f }, +/* 0xaf10 */ { true, 0xaf10, 0xaf10 }, +/* 0xaf11 */ { true, 0xaf11, 0xaf11 }, +/* 0xaf12 */ { true, 0xaf12, 0xaf12 }, +/* 0xaf13 */ { true, 0xaf13, 0xaf13 }, +/* 0xaf14 */ { true, 0xaf14, 0xaf14 }, +/* 0xaf15 */ { true, 0xaf15, 0xaf15 }, +/* 0xaf16 */ { true, 0xaf16, 0xaf16 }, +/* 0xaf17 */ { true, 0xaf17, 0xaf17 }, +/* 0xaf18 */ { true, 0xaf18, 0xaf18 }, +/* 0xaf19 */ { true, 0xaf19, 0xaf19 }, +/* 0xaf1a */ { true, 0xaf1a, 0xaf1a }, +/* 0xaf1b */ { true, 0xaf1b, 0xaf1b }, +/* 0xaf1c */ { true, 0xaf1c, 0xaf1c }, +/* 0xaf1d */ { true, 0xaf1d, 0xaf1d }, +/* 0xaf1e */ { true, 0xaf1e, 0xaf1e }, +/* 0xaf1f */ { true, 0xaf1f, 0xaf1f }, +/* 0xaf20 */ { true, 0xaf20, 0xaf20 }, +/* 0xaf21 */ { true, 0xaf21, 0xaf21 }, +/* 0xaf22 */ { true, 0xaf22, 0xaf22 }, +/* 0xaf23 */ { true, 0xaf23, 0xaf23 }, +/* 0xaf24 */ { true, 0xaf24, 0xaf24 }, +/* 0xaf25 */ { true, 0xaf25, 0xaf25 }, +/* 0xaf26 */ { true, 0xaf26, 0xaf26 }, +/* 0xaf27 */ { true, 0xaf27, 0xaf27 }, +/* 0xaf28 */ { true, 0xaf28, 0xaf28 }, +/* 0xaf29 */ { true, 0xaf29, 0xaf29 }, +/* 0xaf2a */ { true, 0xaf2a, 0xaf2a }, +/* 0xaf2b */ { true, 0xaf2b, 0xaf2b }, +/* 0xaf2c */ { true, 0xaf2c, 0xaf2c }, +/* 0xaf2d */ { true, 0xaf2d, 0xaf2d }, +/* 0xaf2e */ { true, 0xaf2e, 0xaf2e }, +/* 0xaf2f */ { true, 0xaf2f, 0xaf2f }, +/* 0xaf30 */ { true, 0xaf30, 0xaf30 }, +/* 0xaf31 */ { true, 0xaf31, 0xaf31 }, +/* 0xaf32 */ { true, 0xaf32, 0xaf32 }, +/* 0xaf33 */ { true, 0xaf33, 0xaf33 }, +/* 0xaf34 */ { true, 0xaf34, 0xaf34 }, +/* 0xaf35 */ { true, 0xaf35, 0xaf35 }, +/* 0xaf36 */ { true, 0xaf36, 0xaf36 }, +/* 0xaf37 */ { true, 0xaf37, 0xaf37 }, +/* 0xaf38 */ { true, 0xaf38, 0xaf38 }, +/* 0xaf39 */ { true, 0xaf39, 0xaf39 }, +/* 0xaf3a */ { true, 0xaf3a, 0xaf3a }, +/* 0xaf3b */ { true, 0xaf3b, 0xaf3b }, +/* 0xaf3c */ { true, 0xaf3c, 0xaf3c }, +/* 0xaf3d */ { true, 0xaf3d, 0xaf3d }, +/* 0xaf3e */ { true, 0xaf3e, 0xaf3e }, +/* 0xaf3f */ { true, 0xaf3f, 0xaf3f }, +/* 0xaf40 */ { true, 0xaf40, 0xaf40 }, +/* 0xaf41 */ { true, 0xaf41, 0xaf41 }, +/* 0xaf42 */ { true, 0xaf42, 0xaf42 }, +/* 0xaf43 */ { true, 0xaf43, 0xaf43 }, +/* 0xaf44 */ { true, 0xaf44, 0xaf44 }, +/* 0xaf45 */ { true, 0xaf45, 0xaf45 }, +/* 0xaf46 */ { true, 0xaf46, 0xaf46 }, +/* 0xaf47 */ { true, 0xaf47, 0xaf47 }, +/* 0xaf48 */ { true, 0xaf48, 0xaf48 }, +/* 0xaf49 */ { true, 0xaf49, 0xaf49 }, +/* 0xaf4a */ { true, 0xaf4a, 0xaf4a }, +/* 0xaf4b */ { true, 0xaf4b, 0xaf4b }, +/* 0xaf4c */ { true, 0xaf4c, 0xaf4c }, +/* 0xaf4d */ { true, 0xaf4d, 0xaf4d }, +/* 0xaf4e */ { true, 0xaf4e, 0xaf4e }, +/* 0xaf4f */ { true, 0xaf4f, 0xaf4f }, +/* 0xaf50 */ { true, 0xaf50, 0xaf50 }, +/* 0xaf51 */ { true, 0xaf51, 0xaf51 }, +/* 0xaf52 */ { true, 0xaf52, 0xaf52 }, +/* 0xaf53 */ { true, 0xaf53, 0xaf53 }, +/* 0xaf54 */ { true, 0xaf54, 0xaf54 }, +/* 0xaf55 */ { true, 0xaf55, 0xaf55 }, +/* 0xaf56 */ { true, 0xaf56, 0xaf56 }, +/* 0xaf57 */ { true, 0xaf57, 0xaf57 }, +/* 0xaf58 */ { true, 0xaf58, 0xaf58 }, +/* 0xaf59 */ { true, 0xaf59, 0xaf59 }, +/* 0xaf5a */ { true, 0xaf5a, 0xaf5a }, +/* 0xaf5b */ { true, 0xaf5b, 0xaf5b }, +/* 0xaf5c */ { true, 0xaf5c, 0xaf5c }, +/* 0xaf5d */ { true, 0xaf5d, 0xaf5d }, +/* 0xaf5e */ { true, 0xaf5e, 0xaf5e }, +/* 0xaf5f */ { true, 0xaf5f, 0xaf5f }, +/* 0xaf60 */ { true, 0xaf60, 0xaf60 }, +/* 0xaf61 */ { true, 0xaf61, 0xaf61 }, +/* 0xaf62 */ { true, 0xaf62, 0xaf62 }, +/* 0xaf63 */ { true, 0xaf63, 0xaf63 }, +/* 0xaf64 */ { true, 0xaf64, 0xaf64 }, +/* 0xaf65 */ { true, 0xaf65, 0xaf65 }, +/* 0xaf66 */ { true, 0xaf66, 0xaf66 }, +/* 0xaf67 */ { true, 0xaf67, 0xaf67 }, +/* 0xaf68 */ { true, 0xaf68, 0xaf68 }, +/* 0xaf69 */ { true, 0xaf69, 0xaf69 }, +/* 0xaf6a */ { true, 0xaf6a, 0xaf6a }, +/* 0xaf6b */ { true, 0xaf6b, 0xaf6b }, +/* 0xaf6c */ { true, 0xaf6c, 0xaf6c }, +/* 0xaf6d */ { true, 0xaf6d, 0xaf6d }, +/* 0xaf6e */ { true, 0xaf6e, 0xaf6e }, +/* 0xaf6f */ { true, 0xaf6f, 0xaf6f }, +/* 0xaf70 */ { true, 0xaf70, 0xaf70 }, +/* 0xaf71 */ { true, 0xaf71, 0xaf71 }, +/* 0xaf72 */ { true, 0xaf72, 0xaf72 }, +/* 0xaf73 */ { true, 0xaf73, 0xaf73 }, +/* 0xaf74 */ { true, 0xaf74, 0xaf74 }, +/* 0xaf75 */ { true, 0xaf75, 0xaf75 }, +/* 0xaf76 */ { true, 0xaf76, 0xaf76 }, +/* 0xaf77 */ { true, 0xaf77, 0xaf77 }, +/* 0xaf78 */ { true, 0xaf78, 0xaf78 }, +/* 0xaf79 */ { true, 0xaf79, 0xaf79 }, +/* 0xaf7a */ { true, 0xaf7a, 0xaf7a }, +/* 0xaf7b */ { true, 0xaf7b, 0xaf7b }, +/* 0xaf7c */ { true, 0xaf7c, 0xaf7c }, +/* 0xaf7d */ { true, 0xaf7d, 0xaf7d }, +/* 0xaf7e */ { true, 0xaf7e, 0xaf7e }, +/* 0xaf7f */ { true, 0xaf7f, 0xaf7f }, +/* 0xaf80 */ { true, 0xaf80, 0xaf80 }, +/* 0xaf81 */ { true, 0xaf81, 0xaf81 }, +/* 0xaf82 */ { true, 0xaf82, 0xaf82 }, +/* 0xaf83 */ { true, 0xaf83, 0xaf83 }, +/* 0xaf84 */ { true, 0xaf84, 0xaf84 }, +/* 0xaf85 */ { true, 0xaf85, 0xaf85 }, +/* 0xaf86 */ { true, 0xaf86, 0xaf86 }, +/* 0xaf87 */ { true, 0xaf87, 0xaf87 }, +/* 0xaf88 */ { true, 0xaf88, 0xaf88 }, +/* 0xaf89 */ { true, 0xaf89, 0xaf89 }, +/* 0xaf8a */ { true, 0xaf8a, 0xaf8a }, +/* 0xaf8b */ { true, 0xaf8b, 0xaf8b }, +/* 0xaf8c */ { true, 0xaf8c, 0xaf8c }, +/* 0xaf8d */ { true, 0xaf8d, 0xaf8d }, +/* 0xaf8e */ { true, 0xaf8e, 0xaf8e }, +/* 0xaf8f */ { true, 0xaf8f, 0xaf8f }, +/* 0xaf90 */ { true, 0xaf90, 0xaf90 }, +/* 0xaf91 */ { true, 0xaf91, 0xaf91 }, +/* 0xaf92 */ { true, 0xaf92, 0xaf92 }, +/* 0xaf93 */ { true, 0xaf93, 0xaf93 }, +/* 0xaf94 */ { true, 0xaf94, 0xaf94 }, +/* 0xaf95 */ { true, 0xaf95, 0xaf95 }, +/* 0xaf96 */ { true, 0xaf96, 0xaf96 }, +/* 0xaf97 */ { true, 0xaf97, 0xaf97 }, +/* 0xaf98 */ { true, 0xaf98, 0xaf98 }, +/* 0xaf99 */ { true, 0xaf99, 0xaf99 }, +/* 0xaf9a */ { true, 0xaf9a, 0xaf9a }, +/* 0xaf9b */ { true, 0xaf9b, 0xaf9b }, +/* 0xaf9c */ { true, 0xaf9c, 0xaf9c }, +/* 0xaf9d */ { true, 0xaf9d, 0xaf9d }, +/* 0xaf9e */ { true, 0xaf9e, 0xaf9e }, +/* 0xaf9f */ { true, 0xaf9f, 0xaf9f }, +/* 0xafa0 */ { true, 0xafa0, 0xafa0 }, +/* 0xafa1 */ { true, 0xafa1, 0xafa1 }, +/* 0xafa2 */ { true, 0xafa2, 0xafa2 }, +/* 0xafa3 */ { true, 0xafa3, 0xafa3 }, +/* 0xafa4 */ { true, 0xafa4, 0xafa4 }, +/* 0xafa5 */ { true, 0xafa5, 0xafa5 }, +/* 0xafa6 */ { true, 0xafa6, 0xafa6 }, +/* 0xafa7 */ { true, 0xafa7, 0xafa7 }, +/* 0xafa8 */ { true, 0xafa8, 0xafa8 }, +/* 0xafa9 */ { true, 0xafa9, 0xafa9 }, +/* 0xafaa */ { true, 0xafaa, 0xafaa }, +/* 0xafab */ { true, 0xafab, 0xafab }, +/* 0xafac */ { true, 0xafac, 0xafac }, +/* 0xafad */ { true, 0xafad, 0xafad }, +/* 0xafae */ { true, 0xafae, 0xafae }, +/* 0xafaf */ { true, 0xafaf, 0xafaf }, +/* 0xafb0 */ { true, 0xafb0, 0xafb0 }, +/* 0xafb1 */ { true, 0xafb1, 0xafb1 }, +/* 0xafb2 */ { true, 0xafb2, 0xafb2 }, +/* 0xafb3 */ { true, 0xafb3, 0xafb3 }, +/* 0xafb4 */ { true, 0xafb4, 0xafb4 }, +/* 0xafb5 */ { true, 0xafb5, 0xafb5 }, +/* 0xafb6 */ { true, 0xafb6, 0xafb6 }, +/* 0xafb7 */ { true, 0xafb7, 0xafb7 }, +/* 0xafb8 */ { true, 0xafb8, 0xafb8 }, +/* 0xafb9 */ { true, 0xafb9, 0xafb9 }, +/* 0xafba */ { true, 0xafba, 0xafba }, +/* 0xafbb */ { true, 0xafbb, 0xafbb }, +/* 0xafbc */ { true, 0xafbc, 0xafbc }, +/* 0xafbd */ { true, 0xafbd, 0xafbd }, +/* 0xafbe */ { true, 0xafbe, 0xafbe }, +/* 0xafbf */ { true, 0xafbf, 0xafbf }, +/* 0xafc0 */ { true, 0xafc0, 0xafc0 }, +/* 0xafc1 */ { true, 0xafc1, 0xafc1 }, +/* 0xafc2 */ { true, 0xafc2, 0xafc2 }, +/* 0xafc3 */ { true, 0xafc3, 0xafc3 }, +/* 0xafc4 */ { true, 0xafc4, 0xafc4 }, +/* 0xafc5 */ { true, 0xafc5, 0xafc5 }, +/* 0xafc6 */ { true, 0xafc6, 0xafc6 }, +/* 0xafc7 */ { true, 0xafc7, 0xafc7 }, +/* 0xafc8 */ { true, 0xafc8, 0xafc8 }, +/* 0xafc9 */ { true, 0xafc9, 0xafc9 }, +/* 0xafca */ { true, 0xafca, 0xafca }, +/* 0xafcb */ { true, 0xafcb, 0xafcb }, +/* 0xafcc */ { true, 0xafcc, 0xafcc }, +/* 0xafcd */ { true, 0xafcd, 0xafcd }, +/* 0xafce */ { true, 0xafce, 0xafce }, +/* 0xafcf */ { true, 0xafcf, 0xafcf }, +/* 0xafd0 */ { true, 0xafd0, 0xafd0 }, +/* 0xafd1 */ { true, 0xafd1, 0xafd1 }, +/* 0xafd2 */ { true, 0xafd2, 0xafd2 }, +/* 0xafd3 */ { true, 0xafd3, 0xafd3 }, +/* 0xafd4 */ { true, 0xafd4, 0xafd4 }, +/* 0xafd5 */ { true, 0xafd5, 0xafd5 }, +/* 0xafd6 */ { true, 0xafd6, 0xafd6 }, +/* 0xafd7 */ { true, 0xafd7, 0xafd7 }, +/* 0xafd8 */ { true, 0xafd8, 0xafd8 }, +/* 0xafd9 */ { true, 0xafd9, 0xafd9 }, +/* 0xafda */ { true, 0xafda, 0xafda }, +/* 0xafdb */ { true, 0xafdb, 0xafdb }, +/* 0xafdc */ { true, 0xafdc, 0xafdc }, +/* 0xafdd */ { true, 0xafdd, 0xafdd }, +/* 0xafde */ { true, 0xafde, 0xafde }, +/* 0xafdf */ { true, 0xafdf, 0xafdf }, +/* 0xafe0 */ { true, 0xafe0, 0xafe0 }, +/* 0xafe1 */ { true, 0xafe1, 0xafe1 }, +/* 0xafe2 */ { true, 0xafe2, 0xafe2 }, +/* 0xafe3 */ { true, 0xafe3, 0xafe3 }, +/* 0xafe4 */ { true, 0xafe4, 0xafe4 }, +/* 0xafe5 */ { true, 0xafe5, 0xafe5 }, +/* 0xafe6 */ { true, 0xafe6, 0xafe6 }, +/* 0xafe7 */ { true, 0xafe7, 0xafe7 }, +/* 0xafe8 */ { true, 0xafe8, 0xafe8 }, +/* 0xafe9 */ { true, 0xafe9, 0xafe9 }, +/* 0xafea */ { true, 0xafea, 0xafea }, +/* 0xafeb */ { true, 0xafeb, 0xafeb }, +/* 0xafec */ { true, 0xafec, 0xafec }, +/* 0xafed */ { true, 0xafed, 0xafed }, +/* 0xafee */ { true, 0xafee, 0xafee }, +/* 0xafef */ { true, 0xafef, 0xafef }, +/* 0xaff0 */ { true, 0xaff0, 0xaff0 }, +/* 0xaff1 */ { true, 0xaff1, 0xaff1 }, +/* 0xaff2 */ { true, 0xaff2, 0xaff2 }, +/* 0xaff3 */ { true, 0xaff3, 0xaff3 }, +/* 0xaff4 */ { true, 0xaff4, 0xaff4 }, +/* 0xaff5 */ { true, 0xaff5, 0xaff5 }, +/* 0xaff6 */ { true, 0xaff6, 0xaff6 }, +/* 0xaff7 */ { true, 0xaff7, 0xaff7 }, +/* 0xaff8 */ { true, 0xaff8, 0xaff8 }, +/* 0xaff9 */ { true, 0xaff9, 0xaff9 }, +/* 0xaffa */ { true, 0xaffa, 0xaffa }, +/* 0xaffb */ { true, 0xaffb, 0xaffb }, +/* 0xaffc */ { true, 0xaffc, 0xaffc }, +/* 0xaffd */ { true, 0xaffd, 0xaffd }, +/* 0xaffe */ { true, 0xaffe, 0xaffe }, +/* 0xafff */ { true, 0xafff, 0xafff }, +/* 0xb000 */ { true, 0xb000, 0xb000 }, +/* 0xb001 */ { true, 0xb001, 0xb001 }, +/* 0xb002 */ { true, 0xb002, 0xb002 }, +/* 0xb003 */ { true, 0xb003, 0xb003 }, +/* 0xb004 */ { true, 0xb004, 0xb004 }, +/* 0xb005 */ { true, 0xb005, 0xb005 }, +/* 0xb006 */ { true, 0xb006, 0xb006 }, +/* 0xb007 */ { true, 0xb007, 0xb007 }, +/* 0xb008 */ { true, 0xb008, 0xb008 }, +/* 0xb009 */ { true, 0xb009, 0xb009 }, +/* 0xb00a */ { true, 0xb00a, 0xb00a }, +/* 0xb00b */ { true, 0xb00b, 0xb00b }, +/* 0xb00c */ { true, 0xb00c, 0xb00c }, +/* 0xb00d */ { true, 0xb00d, 0xb00d }, +/* 0xb00e */ { true, 0xb00e, 0xb00e }, +/* 0xb00f */ { true, 0xb00f, 0xb00f }, +/* 0xb010 */ { true, 0xb010, 0xb010 }, +/* 0xb011 */ { true, 0xb011, 0xb011 }, +/* 0xb012 */ { true, 0xb012, 0xb012 }, +/* 0xb013 */ { true, 0xb013, 0xb013 }, +/* 0xb014 */ { true, 0xb014, 0xb014 }, +/* 0xb015 */ { true, 0xb015, 0xb015 }, +/* 0xb016 */ { true, 0xb016, 0xb016 }, +/* 0xb017 */ { true, 0xb017, 0xb017 }, +/* 0xb018 */ { true, 0xb018, 0xb018 }, +/* 0xb019 */ { true, 0xb019, 0xb019 }, +/* 0xb01a */ { true, 0xb01a, 0xb01a }, +/* 0xb01b */ { true, 0xb01b, 0xb01b }, +/* 0xb01c */ { true, 0xb01c, 0xb01c }, +/* 0xb01d */ { true, 0xb01d, 0xb01d }, +/* 0xb01e */ { true, 0xb01e, 0xb01e }, +/* 0xb01f */ { true, 0xb01f, 0xb01f }, +/* 0xb020 */ { true, 0xb020, 0xb020 }, +/* 0xb021 */ { true, 0xb021, 0xb021 }, +/* 0xb022 */ { true, 0xb022, 0xb022 }, +/* 0xb023 */ { true, 0xb023, 0xb023 }, +/* 0xb024 */ { true, 0xb024, 0xb024 }, +/* 0xb025 */ { true, 0xb025, 0xb025 }, +/* 0xb026 */ { true, 0xb026, 0xb026 }, +/* 0xb027 */ { true, 0xb027, 0xb027 }, +/* 0xb028 */ { true, 0xb028, 0xb028 }, +/* 0xb029 */ { true, 0xb029, 0xb029 }, +/* 0xb02a */ { true, 0xb02a, 0xb02a }, +/* 0xb02b */ { true, 0xb02b, 0xb02b }, +/* 0xb02c */ { true, 0xb02c, 0xb02c }, +/* 0xb02d */ { true, 0xb02d, 0xb02d }, +/* 0xb02e */ { true, 0xb02e, 0xb02e }, +/* 0xb02f */ { true, 0xb02f, 0xb02f }, +/* 0xb030 */ { true, 0xb030, 0xb030 }, +/* 0xb031 */ { true, 0xb031, 0xb031 }, +/* 0xb032 */ { true, 0xb032, 0xb032 }, +/* 0xb033 */ { true, 0xb033, 0xb033 }, +/* 0xb034 */ { true, 0xb034, 0xb034 }, +/* 0xb035 */ { true, 0xb035, 0xb035 }, +/* 0xb036 */ { true, 0xb036, 0xb036 }, +/* 0xb037 */ { true, 0xb037, 0xb037 }, +/* 0xb038 */ { true, 0xb038, 0xb038 }, +/* 0xb039 */ { true, 0xb039, 0xb039 }, +/* 0xb03a */ { true, 0xb03a, 0xb03a }, +/* 0xb03b */ { true, 0xb03b, 0xb03b }, +/* 0xb03c */ { true, 0xb03c, 0xb03c }, +/* 0xb03d */ { true, 0xb03d, 0xb03d }, +/* 0xb03e */ { true, 0xb03e, 0xb03e }, +/* 0xb03f */ { true, 0xb03f, 0xb03f }, +/* 0xb040 */ { true, 0xb040, 0xb040 }, +/* 0xb041 */ { true, 0xb041, 0xb041 }, +/* 0xb042 */ { true, 0xb042, 0xb042 }, +/* 0xb043 */ { true, 0xb043, 0xb043 }, +/* 0xb044 */ { true, 0xb044, 0xb044 }, +/* 0xb045 */ { true, 0xb045, 0xb045 }, +/* 0xb046 */ { true, 0xb046, 0xb046 }, +/* 0xb047 */ { true, 0xb047, 0xb047 }, +/* 0xb048 */ { true, 0xb048, 0xb048 }, +/* 0xb049 */ { true, 0xb049, 0xb049 }, +/* 0xb04a */ { true, 0xb04a, 0xb04a }, +/* 0xb04b */ { true, 0xb04b, 0xb04b }, +/* 0xb04c */ { true, 0xb04c, 0xb04c }, +/* 0xb04d */ { true, 0xb04d, 0xb04d }, +/* 0xb04e */ { true, 0xb04e, 0xb04e }, +/* 0xb04f */ { true, 0xb04f, 0xb04f }, +/* 0xb050 */ { true, 0xb050, 0xb050 }, +/* 0xb051 */ { true, 0xb051, 0xb051 }, +/* 0xb052 */ { true, 0xb052, 0xb052 }, +/* 0xb053 */ { true, 0xb053, 0xb053 }, +/* 0xb054 */ { true, 0xb054, 0xb054 }, +/* 0xb055 */ { true, 0xb055, 0xb055 }, +/* 0xb056 */ { true, 0xb056, 0xb056 }, +/* 0xb057 */ { true, 0xb057, 0xb057 }, +/* 0xb058 */ { true, 0xb058, 0xb058 }, +/* 0xb059 */ { true, 0xb059, 0xb059 }, +/* 0xb05a */ { true, 0xb05a, 0xb05a }, +/* 0xb05b */ { true, 0xb05b, 0xb05b }, +/* 0xb05c */ { true, 0xb05c, 0xb05c }, +/* 0xb05d */ { true, 0xb05d, 0xb05d }, +/* 0xb05e */ { true, 0xb05e, 0xb05e }, +/* 0xb05f */ { true, 0xb05f, 0xb05f }, +/* 0xb060 */ { true, 0xb060, 0xb060 }, +/* 0xb061 */ { true, 0xb061, 0xb061 }, +/* 0xb062 */ { true, 0xb062, 0xb062 }, +/* 0xb063 */ { true, 0xb063, 0xb063 }, +/* 0xb064 */ { true, 0xb064, 0xb064 }, +/* 0xb065 */ { true, 0xb065, 0xb065 }, +/* 0xb066 */ { true, 0xb066, 0xb066 }, +/* 0xb067 */ { true, 0xb067, 0xb067 }, +/* 0xb068 */ { true, 0xb068, 0xb068 }, +/* 0xb069 */ { true, 0xb069, 0xb069 }, +/* 0xb06a */ { true, 0xb06a, 0xb06a }, +/* 0xb06b */ { true, 0xb06b, 0xb06b }, +/* 0xb06c */ { true, 0xb06c, 0xb06c }, +/* 0xb06d */ { true, 0xb06d, 0xb06d }, +/* 0xb06e */ { true, 0xb06e, 0xb06e }, +/* 0xb06f */ { true, 0xb06f, 0xb06f }, +/* 0xb070 */ { true, 0xb070, 0xb070 }, +/* 0xb071 */ { true, 0xb071, 0xb071 }, +/* 0xb072 */ { true, 0xb072, 0xb072 }, +/* 0xb073 */ { true, 0xb073, 0xb073 }, +/* 0xb074 */ { true, 0xb074, 0xb074 }, +/* 0xb075 */ { true, 0xb075, 0xb075 }, +/* 0xb076 */ { true, 0xb076, 0xb076 }, +/* 0xb077 */ { true, 0xb077, 0xb077 }, +/* 0xb078 */ { true, 0xb078, 0xb078 }, +/* 0xb079 */ { true, 0xb079, 0xb079 }, +/* 0xb07a */ { true, 0xb07a, 0xb07a }, +/* 0xb07b */ { true, 0xb07b, 0xb07b }, +/* 0xb07c */ { true, 0xb07c, 0xb07c }, +/* 0xb07d */ { true, 0xb07d, 0xb07d }, +/* 0xb07e */ { true, 0xb07e, 0xb07e }, +/* 0xb07f */ { true, 0xb07f, 0xb07f }, +/* 0xb080 */ { true, 0xb080, 0xb080 }, +/* 0xb081 */ { true, 0xb081, 0xb081 }, +/* 0xb082 */ { true, 0xb082, 0xb082 }, +/* 0xb083 */ { true, 0xb083, 0xb083 }, +/* 0xb084 */ { true, 0xb084, 0xb084 }, +/* 0xb085 */ { true, 0xb085, 0xb085 }, +/* 0xb086 */ { true, 0xb086, 0xb086 }, +/* 0xb087 */ { true, 0xb087, 0xb087 }, +/* 0xb088 */ { true, 0xb088, 0xb088 }, +/* 0xb089 */ { true, 0xb089, 0xb089 }, +/* 0xb08a */ { true, 0xb08a, 0xb08a }, +/* 0xb08b */ { true, 0xb08b, 0xb08b }, +/* 0xb08c */ { true, 0xb08c, 0xb08c }, +/* 0xb08d */ { true, 0xb08d, 0xb08d }, +/* 0xb08e */ { true, 0xb08e, 0xb08e }, +/* 0xb08f */ { true, 0xb08f, 0xb08f }, +/* 0xb090 */ { true, 0xb090, 0xb090 }, +/* 0xb091 */ { true, 0xb091, 0xb091 }, +/* 0xb092 */ { true, 0xb092, 0xb092 }, +/* 0xb093 */ { true, 0xb093, 0xb093 }, +/* 0xb094 */ { true, 0xb094, 0xb094 }, +/* 0xb095 */ { true, 0xb095, 0xb095 }, +/* 0xb096 */ { true, 0xb096, 0xb096 }, +/* 0xb097 */ { true, 0xb097, 0xb097 }, +/* 0xb098 */ { true, 0xb098, 0xb098 }, +/* 0xb099 */ { true, 0xb099, 0xb099 }, +/* 0xb09a */ { true, 0xb09a, 0xb09a }, +/* 0xb09b */ { true, 0xb09b, 0xb09b }, +/* 0xb09c */ { true, 0xb09c, 0xb09c }, +/* 0xb09d */ { true, 0xb09d, 0xb09d }, +/* 0xb09e */ { true, 0xb09e, 0xb09e }, +/* 0xb09f */ { true, 0xb09f, 0xb09f }, +/* 0xb0a0 */ { true, 0xb0a0, 0xb0a0 }, +/* 0xb0a1 */ { true, 0xb0a1, 0xb0a1 }, +/* 0xb0a2 */ { true, 0xb0a2, 0xb0a2 }, +/* 0xb0a3 */ { true, 0xb0a3, 0xb0a3 }, +/* 0xb0a4 */ { true, 0xb0a4, 0xb0a4 }, +/* 0xb0a5 */ { true, 0xb0a5, 0xb0a5 }, +/* 0xb0a6 */ { true, 0xb0a6, 0xb0a6 }, +/* 0xb0a7 */ { true, 0xb0a7, 0xb0a7 }, +/* 0xb0a8 */ { true, 0xb0a8, 0xb0a8 }, +/* 0xb0a9 */ { true, 0xb0a9, 0xb0a9 }, +/* 0xb0aa */ { true, 0xb0aa, 0xb0aa }, +/* 0xb0ab */ { true, 0xb0ab, 0xb0ab }, +/* 0xb0ac */ { true, 0xb0ac, 0xb0ac }, +/* 0xb0ad */ { true, 0xb0ad, 0xb0ad }, +/* 0xb0ae */ { true, 0xb0ae, 0xb0ae }, +/* 0xb0af */ { true, 0xb0af, 0xb0af }, +/* 0xb0b0 */ { true, 0xb0b0, 0xb0b0 }, +/* 0xb0b1 */ { true, 0xb0b1, 0xb0b1 }, +/* 0xb0b2 */ { true, 0xb0b2, 0xb0b2 }, +/* 0xb0b3 */ { true, 0xb0b3, 0xb0b3 }, +/* 0xb0b4 */ { true, 0xb0b4, 0xb0b4 }, +/* 0xb0b5 */ { true, 0xb0b5, 0xb0b5 }, +/* 0xb0b6 */ { true, 0xb0b6, 0xb0b6 }, +/* 0xb0b7 */ { true, 0xb0b7, 0xb0b7 }, +/* 0xb0b8 */ { true, 0xb0b8, 0xb0b8 }, +/* 0xb0b9 */ { true, 0xb0b9, 0xb0b9 }, +/* 0xb0ba */ { true, 0xb0ba, 0xb0ba }, +/* 0xb0bb */ { true, 0xb0bb, 0xb0bb }, +/* 0xb0bc */ { true, 0xb0bc, 0xb0bc }, +/* 0xb0bd */ { true, 0xb0bd, 0xb0bd }, +/* 0xb0be */ { true, 0xb0be, 0xb0be }, +/* 0xb0bf */ { true, 0xb0bf, 0xb0bf }, +/* 0xb0c0 */ { true, 0xb0c0, 0xb0c0 }, +/* 0xb0c1 */ { true, 0xb0c1, 0xb0c1 }, +/* 0xb0c2 */ { true, 0xb0c2, 0xb0c2 }, +/* 0xb0c3 */ { true, 0xb0c3, 0xb0c3 }, +/* 0xb0c4 */ { true, 0xb0c4, 0xb0c4 }, +/* 0xb0c5 */ { true, 0xb0c5, 0xb0c5 }, +/* 0xb0c6 */ { true, 0xb0c6, 0xb0c6 }, +/* 0xb0c7 */ { true, 0xb0c7, 0xb0c7 }, +/* 0xb0c8 */ { true, 0xb0c8, 0xb0c8 }, +/* 0xb0c9 */ { true, 0xb0c9, 0xb0c9 }, +/* 0xb0ca */ { true, 0xb0ca, 0xb0ca }, +/* 0xb0cb */ { true, 0xb0cb, 0xb0cb }, +/* 0xb0cc */ { true, 0xb0cc, 0xb0cc }, +/* 0xb0cd */ { true, 0xb0cd, 0xb0cd }, +/* 0xb0ce */ { true, 0xb0ce, 0xb0ce }, +/* 0xb0cf */ { true, 0xb0cf, 0xb0cf }, +/* 0xb0d0 */ { true, 0xb0d0, 0xb0d0 }, +/* 0xb0d1 */ { true, 0xb0d1, 0xb0d1 }, +/* 0xb0d2 */ { true, 0xb0d2, 0xb0d2 }, +/* 0xb0d3 */ { true, 0xb0d3, 0xb0d3 }, +/* 0xb0d4 */ { true, 0xb0d4, 0xb0d4 }, +/* 0xb0d5 */ { true, 0xb0d5, 0xb0d5 }, +/* 0xb0d6 */ { true, 0xb0d6, 0xb0d6 }, +/* 0xb0d7 */ { true, 0xb0d7, 0xb0d7 }, +/* 0xb0d8 */ { true, 0xb0d8, 0xb0d8 }, +/* 0xb0d9 */ { true, 0xb0d9, 0xb0d9 }, +/* 0xb0da */ { true, 0xb0da, 0xb0da }, +/* 0xb0db */ { true, 0xb0db, 0xb0db }, +/* 0xb0dc */ { true, 0xb0dc, 0xb0dc }, +/* 0xb0dd */ { true, 0xb0dd, 0xb0dd }, +/* 0xb0de */ { true, 0xb0de, 0xb0de }, +/* 0xb0df */ { true, 0xb0df, 0xb0df }, +/* 0xb0e0 */ { true, 0xb0e0, 0xb0e0 }, +/* 0xb0e1 */ { true, 0xb0e1, 0xb0e1 }, +/* 0xb0e2 */ { true, 0xb0e2, 0xb0e2 }, +/* 0xb0e3 */ { true, 0xb0e3, 0xb0e3 }, +/* 0xb0e4 */ { true, 0xb0e4, 0xb0e4 }, +/* 0xb0e5 */ { true, 0xb0e5, 0xb0e5 }, +/* 0xb0e6 */ { true, 0xb0e6, 0xb0e6 }, +/* 0xb0e7 */ { true, 0xb0e7, 0xb0e7 }, +/* 0xb0e8 */ { true, 0xb0e8, 0xb0e8 }, +/* 0xb0e9 */ { true, 0xb0e9, 0xb0e9 }, +/* 0xb0ea */ { true, 0xb0ea, 0xb0ea }, +/* 0xb0eb */ { true, 0xb0eb, 0xb0eb }, +/* 0xb0ec */ { true, 0xb0ec, 0xb0ec }, +/* 0xb0ed */ { true, 0xb0ed, 0xb0ed }, +/* 0xb0ee */ { true, 0xb0ee, 0xb0ee }, +/* 0xb0ef */ { true, 0xb0ef, 0xb0ef }, +/* 0xb0f0 */ { true, 0xb0f0, 0xb0f0 }, +/* 0xb0f1 */ { true, 0xb0f1, 0xb0f1 }, +/* 0xb0f2 */ { true, 0xb0f2, 0xb0f2 }, +/* 0xb0f3 */ { true, 0xb0f3, 0xb0f3 }, +/* 0xb0f4 */ { true, 0xb0f4, 0xb0f4 }, +/* 0xb0f5 */ { true, 0xb0f5, 0xb0f5 }, +/* 0xb0f6 */ { true, 0xb0f6, 0xb0f6 }, +/* 0xb0f7 */ { true, 0xb0f7, 0xb0f7 }, +/* 0xb0f8 */ { true, 0xb0f8, 0xb0f8 }, +/* 0xb0f9 */ { true, 0xb0f9, 0xb0f9 }, +/* 0xb0fa */ { true, 0xb0fa, 0xb0fa }, +/* 0xb0fb */ { true, 0xb0fb, 0xb0fb }, +/* 0xb0fc */ { true, 0xb0fc, 0xb0fc }, +/* 0xb0fd */ { true, 0xb0fd, 0xb0fd }, +/* 0xb0fe */ { true, 0xb0fe, 0xb0fe }, +/* 0xb0ff */ { true, 0xb0ff, 0xb0ff }, +/* 0xb100 */ { true, 0xb100, 0xb100 }, +/* 0xb101 */ { true, 0xb101, 0xb101 }, +/* 0xb102 */ { true, 0xb102, 0xb102 }, +/* 0xb103 */ { true, 0xb103, 0xb103 }, +/* 0xb104 */ { true, 0xb104, 0xb104 }, +/* 0xb105 */ { true, 0xb105, 0xb105 }, +/* 0xb106 */ { true, 0xb106, 0xb106 }, +/* 0xb107 */ { true, 0xb107, 0xb107 }, +/* 0xb108 */ { true, 0xb108, 0xb108 }, +/* 0xb109 */ { true, 0xb109, 0xb109 }, +/* 0xb10a */ { true, 0xb10a, 0xb10a }, +/* 0xb10b */ { true, 0xb10b, 0xb10b }, +/* 0xb10c */ { true, 0xb10c, 0xb10c }, +/* 0xb10d */ { true, 0xb10d, 0xb10d }, +/* 0xb10e */ { true, 0xb10e, 0xb10e }, +/* 0xb10f */ { true, 0xb10f, 0xb10f }, +/* 0xb110 */ { true, 0xb110, 0xb110 }, +/* 0xb111 */ { true, 0xb111, 0xb111 }, +/* 0xb112 */ { true, 0xb112, 0xb112 }, +/* 0xb113 */ { true, 0xb113, 0xb113 }, +/* 0xb114 */ { true, 0xb114, 0xb114 }, +/* 0xb115 */ { true, 0xb115, 0xb115 }, +/* 0xb116 */ { true, 0xb116, 0xb116 }, +/* 0xb117 */ { true, 0xb117, 0xb117 }, +/* 0xb118 */ { true, 0xb118, 0xb118 }, +/* 0xb119 */ { true, 0xb119, 0xb119 }, +/* 0xb11a */ { true, 0xb11a, 0xb11a }, +/* 0xb11b */ { true, 0xb11b, 0xb11b }, +/* 0xb11c */ { true, 0xb11c, 0xb11c }, +/* 0xb11d */ { true, 0xb11d, 0xb11d }, +/* 0xb11e */ { true, 0xb11e, 0xb11e }, +/* 0xb11f */ { true, 0xb11f, 0xb11f }, +/* 0xb120 */ { true, 0xb120, 0xb120 }, +/* 0xb121 */ { true, 0xb121, 0xb121 }, +/* 0xb122 */ { true, 0xb122, 0xb122 }, +/* 0xb123 */ { true, 0xb123, 0xb123 }, +/* 0xb124 */ { true, 0xb124, 0xb124 }, +/* 0xb125 */ { true, 0xb125, 0xb125 }, +/* 0xb126 */ { true, 0xb126, 0xb126 }, +/* 0xb127 */ { true, 0xb127, 0xb127 }, +/* 0xb128 */ { true, 0xb128, 0xb128 }, +/* 0xb129 */ { true, 0xb129, 0xb129 }, +/* 0xb12a */ { true, 0xb12a, 0xb12a }, +/* 0xb12b */ { true, 0xb12b, 0xb12b }, +/* 0xb12c */ { true, 0xb12c, 0xb12c }, +/* 0xb12d */ { true, 0xb12d, 0xb12d }, +/* 0xb12e */ { true, 0xb12e, 0xb12e }, +/* 0xb12f */ { true, 0xb12f, 0xb12f }, +/* 0xb130 */ { true, 0xb130, 0xb130 }, +/* 0xb131 */ { true, 0xb131, 0xb131 }, +/* 0xb132 */ { true, 0xb132, 0xb132 }, +/* 0xb133 */ { true, 0xb133, 0xb133 }, +/* 0xb134 */ { true, 0xb134, 0xb134 }, +/* 0xb135 */ { true, 0xb135, 0xb135 }, +/* 0xb136 */ { true, 0xb136, 0xb136 }, +/* 0xb137 */ { true, 0xb137, 0xb137 }, +/* 0xb138 */ { true, 0xb138, 0xb138 }, +/* 0xb139 */ { true, 0xb139, 0xb139 }, +/* 0xb13a */ { true, 0xb13a, 0xb13a }, +/* 0xb13b */ { true, 0xb13b, 0xb13b }, +/* 0xb13c */ { true, 0xb13c, 0xb13c }, +/* 0xb13d */ { true, 0xb13d, 0xb13d }, +/* 0xb13e */ { true, 0xb13e, 0xb13e }, +/* 0xb13f */ { true, 0xb13f, 0xb13f }, +/* 0xb140 */ { true, 0xb140, 0xb140 }, +/* 0xb141 */ { true, 0xb141, 0xb141 }, +/* 0xb142 */ { true, 0xb142, 0xb142 }, +/* 0xb143 */ { true, 0xb143, 0xb143 }, +/* 0xb144 */ { true, 0xb144, 0xb144 }, +/* 0xb145 */ { true, 0xb145, 0xb145 }, +/* 0xb146 */ { true, 0xb146, 0xb146 }, +/* 0xb147 */ { true, 0xb147, 0xb147 }, +/* 0xb148 */ { true, 0xb148, 0xb148 }, +/* 0xb149 */ { true, 0xb149, 0xb149 }, +/* 0xb14a */ { true, 0xb14a, 0xb14a }, +/* 0xb14b */ { true, 0xb14b, 0xb14b }, +/* 0xb14c */ { true, 0xb14c, 0xb14c }, +/* 0xb14d */ { true, 0xb14d, 0xb14d }, +/* 0xb14e */ { true, 0xb14e, 0xb14e }, +/* 0xb14f */ { true, 0xb14f, 0xb14f }, +/* 0xb150 */ { true, 0xb150, 0xb150 }, +/* 0xb151 */ { true, 0xb151, 0xb151 }, +/* 0xb152 */ { true, 0xb152, 0xb152 }, +/* 0xb153 */ { true, 0xb153, 0xb153 }, +/* 0xb154 */ { true, 0xb154, 0xb154 }, +/* 0xb155 */ { true, 0xb155, 0xb155 }, +/* 0xb156 */ { true, 0xb156, 0xb156 }, +/* 0xb157 */ { true, 0xb157, 0xb157 }, +/* 0xb158 */ { true, 0xb158, 0xb158 }, +/* 0xb159 */ { true, 0xb159, 0xb159 }, +/* 0xb15a */ { true, 0xb15a, 0xb15a }, +/* 0xb15b */ { true, 0xb15b, 0xb15b }, +/* 0xb15c */ { true, 0xb15c, 0xb15c }, +/* 0xb15d */ { true, 0xb15d, 0xb15d }, +/* 0xb15e */ { true, 0xb15e, 0xb15e }, +/* 0xb15f */ { true, 0xb15f, 0xb15f }, +/* 0xb160 */ { true, 0xb160, 0xb160 }, +/* 0xb161 */ { true, 0xb161, 0xb161 }, +/* 0xb162 */ { true, 0xb162, 0xb162 }, +/* 0xb163 */ { true, 0xb163, 0xb163 }, +/* 0xb164 */ { true, 0xb164, 0xb164 }, +/* 0xb165 */ { true, 0xb165, 0xb165 }, +/* 0xb166 */ { true, 0xb166, 0xb166 }, +/* 0xb167 */ { true, 0xb167, 0xb167 }, +/* 0xb168 */ { true, 0xb168, 0xb168 }, +/* 0xb169 */ { true, 0xb169, 0xb169 }, +/* 0xb16a */ { true, 0xb16a, 0xb16a }, +/* 0xb16b */ { true, 0xb16b, 0xb16b }, +/* 0xb16c */ { true, 0xb16c, 0xb16c }, +/* 0xb16d */ { true, 0xb16d, 0xb16d }, +/* 0xb16e */ { true, 0xb16e, 0xb16e }, +/* 0xb16f */ { true, 0xb16f, 0xb16f }, +/* 0xb170 */ { true, 0xb170, 0xb170 }, +/* 0xb171 */ { true, 0xb171, 0xb171 }, +/* 0xb172 */ { true, 0xb172, 0xb172 }, +/* 0xb173 */ { true, 0xb173, 0xb173 }, +/* 0xb174 */ { true, 0xb174, 0xb174 }, +/* 0xb175 */ { true, 0xb175, 0xb175 }, +/* 0xb176 */ { true, 0xb176, 0xb176 }, +/* 0xb177 */ { true, 0xb177, 0xb177 }, +/* 0xb178 */ { true, 0xb178, 0xb178 }, +/* 0xb179 */ { true, 0xb179, 0xb179 }, +/* 0xb17a */ { true, 0xb17a, 0xb17a }, +/* 0xb17b */ { true, 0xb17b, 0xb17b }, +/* 0xb17c */ { true, 0xb17c, 0xb17c }, +/* 0xb17d */ { true, 0xb17d, 0xb17d }, +/* 0xb17e */ { true, 0xb17e, 0xb17e }, +/* 0xb17f */ { true, 0xb17f, 0xb17f }, +/* 0xb180 */ { true, 0xb180, 0xb180 }, +/* 0xb181 */ { true, 0xb181, 0xb181 }, +/* 0xb182 */ { true, 0xb182, 0xb182 }, +/* 0xb183 */ { true, 0xb183, 0xb183 }, +/* 0xb184 */ { true, 0xb184, 0xb184 }, +/* 0xb185 */ { true, 0xb185, 0xb185 }, +/* 0xb186 */ { true, 0xb186, 0xb186 }, +/* 0xb187 */ { true, 0xb187, 0xb187 }, +/* 0xb188 */ { true, 0xb188, 0xb188 }, +/* 0xb189 */ { true, 0xb189, 0xb189 }, +/* 0xb18a */ { true, 0xb18a, 0xb18a }, +/* 0xb18b */ { true, 0xb18b, 0xb18b }, +/* 0xb18c */ { true, 0xb18c, 0xb18c }, +/* 0xb18d */ { true, 0xb18d, 0xb18d }, +/* 0xb18e */ { true, 0xb18e, 0xb18e }, +/* 0xb18f */ { true, 0xb18f, 0xb18f }, +/* 0xb190 */ { true, 0xb190, 0xb190 }, +/* 0xb191 */ { true, 0xb191, 0xb191 }, +/* 0xb192 */ { true, 0xb192, 0xb192 }, +/* 0xb193 */ { true, 0xb193, 0xb193 }, +/* 0xb194 */ { true, 0xb194, 0xb194 }, +/* 0xb195 */ { true, 0xb195, 0xb195 }, +/* 0xb196 */ { true, 0xb196, 0xb196 }, +/* 0xb197 */ { true, 0xb197, 0xb197 }, +/* 0xb198 */ { true, 0xb198, 0xb198 }, +/* 0xb199 */ { true, 0xb199, 0xb199 }, +/* 0xb19a */ { true, 0xb19a, 0xb19a }, +/* 0xb19b */ { true, 0xb19b, 0xb19b }, +/* 0xb19c */ { true, 0xb19c, 0xb19c }, +/* 0xb19d */ { true, 0xb19d, 0xb19d }, +/* 0xb19e */ { true, 0xb19e, 0xb19e }, +/* 0xb19f */ { true, 0xb19f, 0xb19f }, +/* 0xb1a0 */ { true, 0xb1a0, 0xb1a0 }, +/* 0xb1a1 */ { true, 0xb1a1, 0xb1a1 }, +/* 0xb1a2 */ { true, 0xb1a2, 0xb1a2 }, +/* 0xb1a3 */ { true, 0xb1a3, 0xb1a3 }, +/* 0xb1a4 */ { true, 0xb1a4, 0xb1a4 }, +/* 0xb1a5 */ { true, 0xb1a5, 0xb1a5 }, +/* 0xb1a6 */ { true, 0xb1a6, 0xb1a6 }, +/* 0xb1a7 */ { true, 0xb1a7, 0xb1a7 }, +/* 0xb1a8 */ { true, 0xb1a8, 0xb1a8 }, +/* 0xb1a9 */ { true, 0xb1a9, 0xb1a9 }, +/* 0xb1aa */ { true, 0xb1aa, 0xb1aa }, +/* 0xb1ab */ { true, 0xb1ab, 0xb1ab }, +/* 0xb1ac */ { true, 0xb1ac, 0xb1ac }, +/* 0xb1ad */ { true, 0xb1ad, 0xb1ad }, +/* 0xb1ae */ { true, 0xb1ae, 0xb1ae }, +/* 0xb1af */ { true, 0xb1af, 0xb1af }, +/* 0xb1b0 */ { true, 0xb1b0, 0xb1b0 }, +/* 0xb1b1 */ { true, 0xb1b1, 0xb1b1 }, +/* 0xb1b2 */ { true, 0xb1b2, 0xb1b2 }, +/* 0xb1b3 */ { true, 0xb1b3, 0xb1b3 }, +/* 0xb1b4 */ { true, 0xb1b4, 0xb1b4 }, +/* 0xb1b5 */ { true, 0xb1b5, 0xb1b5 }, +/* 0xb1b6 */ { true, 0xb1b6, 0xb1b6 }, +/* 0xb1b7 */ { true, 0xb1b7, 0xb1b7 }, +/* 0xb1b8 */ { true, 0xb1b8, 0xb1b8 }, +/* 0xb1b9 */ { true, 0xb1b9, 0xb1b9 }, +/* 0xb1ba */ { true, 0xb1ba, 0xb1ba }, +/* 0xb1bb */ { true, 0xb1bb, 0xb1bb }, +/* 0xb1bc */ { true, 0xb1bc, 0xb1bc }, +/* 0xb1bd */ { true, 0xb1bd, 0xb1bd }, +/* 0xb1be */ { true, 0xb1be, 0xb1be }, +/* 0xb1bf */ { true, 0xb1bf, 0xb1bf }, +/* 0xb1c0 */ { true, 0xb1c0, 0xb1c0 }, +/* 0xb1c1 */ { true, 0xb1c1, 0xb1c1 }, +/* 0xb1c2 */ { true, 0xb1c2, 0xb1c2 }, +/* 0xb1c3 */ { true, 0xb1c3, 0xb1c3 }, +/* 0xb1c4 */ { true, 0xb1c4, 0xb1c4 }, +/* 0xb1c5 */ { true, 0xb1c5, 0xb1c5 }, +/* 0xb1c6 */ { true, 0xb1c6, 0xb1c6 }, +/* 0xb1c7 */ { true, 0xb1c7, 0xb1c7 }, +/* 0xb1c8 */ { true, 0xb1c8, 0xb1c8 }, +/* 0xb1c9 */ { true, 0xb1c9, 0xb1c9 }, +/* 0xb1ca */ { true, 0xb1ca, 0xb1ca }, +/* 0xb1cb */ { true, 0xb1cb, 0xb1cb }, +/* 0xb1cc */ { true, 0xb1cc, 0xb1cc }, +/* 0xb1cd */ { true, 0xb1cd, 0xb1cd }, +/* 0xb1ce */ { true, 0xb1ce, 0xb1ce }, +/* 0xb1cf */ { true, 0xb1cf, 0xb1cf }, +/* 0xb1d0 */ { true, 0xb1d0, 0xb1d0 }, +/* 0xb1d1 */ { true, 0xb1d1, 0xb1d1 }, +/* 0xb1d2 */ { true, 0xb1d2, 0xb1d2 }, +/* 0xb1d3 */ { true, 0xb1d3, 0xb1d3 }, +/* 0xb1d4 */ { true, 0xb1d4, 0xb1d4 }, +/* 0xb1d5 */ { true, 0xb1d5, 0xb1d5 }, +/* 0xb1d6 */ { true, 0xb1d6, 0xb1d6 }, +/* 0xb1d7 */ { true, 0xb1d7, 0xb1d7 }, +/* 0xb1d8 */ { true, 0xb1d8, 0xb1d8 }, +/* 0xb1d9 */ { true, 0xb1d9, 0xb1d9 }, +/* 0xb1da */ { true, 0xb1da, 0xb1da }, +/* 0xb1db */ { true, 0xb1db, 0xb1db }, +/* 0xb1dc */ { true, 0xb1dc, 0xb1dc }, +/* 0xb1dd */ { true, 0xb1dd, 0xb1dd }, +/* 0xb1de */ { true, 0xb1de, 0xb1de }, +/* 0xb1df */ { true, 0xb1df, 0xb1df }, +/* 0xb1e0 */ { true, 0xb1e0, 0xb1e0 }, +/* 0xb1e1 */ { true, 0xb1e1, 0xb1e1 }, +/* 0xb1e2 */ { true, 0xb1e2, 0xb1e2 }, +/* 0xb1e3 */ { true, 0xb1e3, 0xb1e3 }, +/* 0xb1e4 */ { true, 0xb1e4, 0xb1e4 }, +/* 0xb1e5 */ { true, 0xb1e5, 0xb1e5 }, +/* 0xb1e6 */ { true, 0xb1e6, 0xb1e6 }, +/* 0xb1e7 */ { true, 0xb1e7, 0xb1e7 }, +/* 0xb1e8 */ { true, 0xb1e8, 0xb1e8 }, +/* 0xb1e9 */ { true, 0xb1e9, 0xb1e9 }, +/* 0xb1ea */ { true, 0xb1ea, 0xb1ea }, +/* 0xb1eb */ { true, 0xb1eb, 0xb1eb }, +/* 0xb1ec */ { true, 0xb1ec, 0xb1ec }, +/* 0xb1ed */ { true, 0xb1ed, 0xb1ed }, +/* 0xb1ee */ { true, 0xb1ee, 0xb1ee }, +/* 0xb1ef */ { true, 0xb1ef, 0xb1ef }, +/* 0xb1f0 */ { true, 0xb1f0, 0xb1f0 }, +/* 0xb1f1 */ { true, 0xb1f1, 0xb1f1 }, +/* 0xb1f2 */ { true, 0xb1f2, 0xb1f2 }, +/* 0xb1f3 */ { true, 0xb1f3, 0xb1f3 }, +/* 0xb1f4 */ { true, 0xb1f4, 0xb1f4 }, +/* 0xb1f5 */ { true, 0xb1f5, 0xb1f5 }, +/* 0xb1f6 */ { true, 0xb1f6, 0xb1f6 }, +/* 0xb1f7 */ { true, 0xb1f7, 0xb1f7 }, +/* 0xb1f8 */ { true, 0xb1f8, 0xb1f8 }, +/* 0xb1f9 */ { true, 0xb1f9, 0xb1f9 }, +/* 0xb1fa */ { true, 0xb1fa, 0xb1fa }, +/* 0xb1fb */ { true, 0xb1fb, 0xb1fb }, +/* 0xb1fc */ { true, 0xb1fc, 0xb1fc }, +/* 0xb1fd */ { true, 0xb1fd, 0xb1fd }, +/* 0xb1fe */ { true, 0xb1fe, 0xb1fe }, +/* 0xb1ff */ { true, 0xb1ff, 0xb1ff }, +/* 0xb200 */ { true, 0xb200, 0xb200 }, +/* 0xb201 */ { true, 0xb201, 0xb201 }, +/* 0xb202 */ { true, 0xb202, 0xb202 }, +/* 0xb203 */ { true, 0xb203, 0xb203 }, +/* 0xb204 */ { true, 0xb204, 0xb204 }, +/* 0xb205 */ { true, 0xb205, 0xb205 }, +/* 0xb206 */ { true, 0xb206, 0xb206 }, +/* 0xb207 */ { true, 0xb207, 0xb207 }, +/* 0xb208 */ { true, 0xb208, 0xb208 }, +/* 0xb209 */ { true, 0xb209, 0xb209 }, +/* 0xb20a */ { true, 0xb20a, 0xb20a }, +/* 0xb20b */ { true, 0xb20b, 0xb20b }, +/* 0xb20c */ { true, 0xb20c, 0xb20c }, +/* 0xb20d */ { true, 0xb20d, 0xb20d }, +/* 0xb20e */ { true, 0xb20e, 0xb20e }, +/* 0xb20f */ { true, 0xb20f, 0xb20f }, +/* 0xb210 */ { true, 0xb210, 0xb210 }, +/* 0xb211 */ { true, 0xb211, 0xb211 }, +/* 0xb212 */ { true, 0xb212, 0xb212 }, +/* 0xb213 */ { true, 0xb213, 0xb213 }, +/* 0xb214 */ { true, 0xb214, 0xb214 }, +/* 0xb215 */ { true, 0xb215, 0xb215 }, +/* 0xb216 */ { true, 0xb216, 0xb216 }, +/* 0xb217 */ { true, 0xb217, 0xb217 }, +/* 0xb218 */ { true, 0xb218, 0xb218 }, +/* 0xb219 */ { true, 0xb219, 0xb219 }, +/* 0xb21a */ { true, 0xb21a, 0xb21a }, +/* 0xb21b */ { true, 0xb21b, 0xb21b }, +/* 0xb21c */ { true, 0xb21c, 0xb21c }, +/* 0xb21d */ { true, 0xb21d, 0xb21d }, +/* 0xb21e */ { true, 0xb21e, 0xb21e }, +/* 0xb21f */ { true, 0xb21f, 0xb21f }, +/* 0xb220 */ { true, 0xb220, 0xb220 }, +/* 0xb221 */ { true, 0xb221, 0xb221 }, +/* 0xb222 */ { true, 0xb222, 0xb222 }, +/* 0xb223 */ { true, 0xb223, 0xb223 }, +/* 0xb224 */ { true, 0xb224, 0xb224 }, +/* 0xb225 */ { true, 0xb225, 0xb225 }, +/* 0xb226 */ { true, 0xb226, 0xb226 }, +/* 0xb227 */ { true, 0xb227, 0xb227 }, +/* 0xb228 */ { true, 0xb228, 0xb228 }, +/* 0xb229 */ { true, 0xb229, 0xb229 }, +/* 0xb22a */ { true, 0xb22a, 0xb22a }, +/* 0xb22b */ { true, 0xb22b, 0xb22b }, +/* 0xb22c */ { true, 0xb22c, 0xb22c }, +/* 0xb22d */ { true, 0xb22d, 0xb22d }, +/* 0xb22e */ { true, 0xb22e, 0xb22e }, +/* 0xb22f */ { true, 0xb22f, 0xb22f }, +/* 0xb230 */ { true, 0xb230, 0xb230 }, +/* 0xb231 */ { true, 0xb231, 0xb231 }, +/* 0xb232 */ { true, 0xb232, 0xb232 }, +/* 0xb233 */ { true, 0xb233, 0xb233 }, +/* 0xb234 */ { true, 0xb234, 0xb234 }, +/* 0xb235 */ { true, 0xb235, 0xb235 }, +/* 0xb236 */ { true, 0xb236, 0xb236 }, +/* 0xb237 */ { true, 0xb237, 0xb237 }, +/* 0xb238 */ { true, 0xb238, 0xb238 }, +/* 0xb239 */ { true, 0xb239, 0xb239 }, +/* 0xb23a */ { true, 0xb23a, 0xb23a }, +/* 0xb23b */ { true, 0xb23b, 0xb23b }, +/* 0xb23c */ { true, 0xb23c, 0xb23c }, +/* 0xb23d */ { true, 0xb23d, 0xb23d }, +/* 0xb23e */ { true, 0xb23e, 0xb23e }, +/* 0xb23f */ { true, 0xb23f, 0xb23f }, +/* 0xb240 */ { true, 0xb240, 0xb240 }, +/* 0xb241 */ { true, 0xb241, 0xb241 }, +/* 0xb242 */ { true, 0xb242, 0xb242 }, +/* 0xb243 */ { true, 0xb243, 0xb243 }, +/* 0xb244 */ { true, 0xb244, 0xb244 }, +/* 0xb245 */ { true, 0xb245, 0xb245 }, +/* 0xb246 */ { true, 0xb246, 0xb246 }, +/* 0xb247 */ { true, 0xb247, 0xb247 }, +/* 0xb248 */ { true, 0xb248, 0xb248 }, +/* 0xb249 */ { true, 0xb249, 0xb249 }, +/* 0xb24a */ { true, 0xb24a, 0xb24a }, +/* 0xb24b */ { true, 0xb24b, 0xb24b }, +/* 0xb24c */ { true, 0xb24c, 0xb24c }, +/* 0xb24d */ { true, 0xb24d, 0xb24d }, +/* 0xb24e */ { true, 0xb24e, 0xb24e }, +/* 0xb24f */ { true, 0xb24f, 0xb24f }, +/* 0xb250 */ { true, 0xb250, 0xb250 }, +/* 0xb251 */ { true, 0xb251, 0xb251 }, +/* 0xb252 */ { true, 0xb252, 0xb252 }, +/* 0xb253 */ { true, 0xb253, 0xb253 }, +/* 0xb254 */ { true, 0xb254, 0xb254 }, +/* 0xb255 */ { true, 0xb255, 0xb255 }, +/* 0xb256 */ { true, 0xb256, 0xb256 }, +/* 0xb257 */ { true, 0xb257, 0xb257 }, +/* 0xb258 */ { true, 0xb258, 0xb258 }, +/* 0xb259 */ { true, 0xb259, 0xb259 }, +/* 0xb25a */ { true, 0xb25a, 0xb25a }, +/* 0xb25b */ { true, 0xb25b, 0xb25b }, +/* 0xb25c */ { true, 0xb25c, 0xb25c }, +/* 0xb25d */ { true, 0xb25d, 0xb25d }, +/* 0xb25e */ { true, 0xb25e, 0xb25e }, +/* 0xb25f */ { true, 0xb25f, 0xb25f }, +/* 0xb260 */ { true, 0xb260, 0xb260 }, +/* 0xb261 */ { true, 0xb261, 0xb261 }, +/* 0xb262 */ { true, 0xb262, 0xb262 }, +/* 0xb263 */ { true, 0xb263, 0xb263 }, +/* 0xb264 */ { true, 0xb264, 0xb264 }, +/* 0xb265 */ { true, 0xb265, 0xb265 }, +/* 0xb266 */ { true, 0xb266, 0xb266 }, +/* 0xb267 */ { true, 0xb267, 0xb267 }, +/* 0xb268 */ { true, 0xb268, 0xb268 }, +/* 0xb269 */ { true, 0xb269, 0xb269 }, +/* 0xb26a */ { true, 0xb26a, 0xb26a }, +/* 0xb26b */ { true, 0xb26b, 0xb26b }, +/* 0xb26c */ { true, 0xb26c, 0xb26c }, +/* 0xb26d */ { true, 0xb26d, 0xb26d }, +/* 0xb26e */ { true, 0xb26e, 0xb26e }, +/* 0xb26f */ { true, 0xb26f, 0xb26f }, +/* 0xb270 */ { true, 0xb270, 0xb270 }, +/* 0xb271 */ { true, 0xb271, 0xb271 }, +/* 0xb272 */ { true, 0xb272, 0xb272 }, +/* 0xb273 */ { true, 0xb273, 0xb273 }, +/* 0xb274 */ { true, 0xb274, 0xb274 }, +/* 0xb275 */ { true, 0xb275, 0xb275 }, +/* 0xb276 */ { true, 0xb276, 0xb276 }, +/* 0xb277 */ { true, 0xb277, 0xb277 }, +/* 0xb278 */ { true, 0xb278, 0xb278 }, +/* 0xb279 */ { true, 0xb279, 0xb279 }, +/* 0xb27a */ { true, 0xb27a, 0xb27a }, +/* 0xb27b */ { true, 0xb27b, 0xb27b }, +/* 0xb27c */ { true, 0xb27c, 0xb27c }, +/* 0xb27d */ { true, 0xb27d, 0xb27d }, +/* 0xb27e */ { true, 0xb27e, 0xb27e }, +/* 0xb27f */ { true, 0xb27f, 0xb27f }, +/* 0xb280 */ { true, 0xb280, 0xb280 }, +/* 0xb281 */ { true, 0xb281, 0xb281 }, +/* 0xb282 */ { true, 0xb282, 0xb282 }, +/* 0xb283 */ { true, 0xb283, 0xb283 }, +/* 0xb284 */ { true, 0xb284, 0xb284 }, +/* 0xb285 */ { true, 0xb285, 0xb285 }, +/* 0xb286 */ { true, 0xb286, 0xb286 }, +/* 0xb287 */ { true, 0xb287, 0xb287 }, +/* 0xb288 */ { true, 0xb288, 0xb288 }, +/* 0xb289 */ { true, 0xb289, 0xb289 }, +/* 0xb28a */ { true, 0xb28a, 0xb28a }, +/* 0xb28b */ { true, 0xb28b, 0xb28b }, +/* 0xb28c */ { true, 0xb28c, 0xb28c }, +/* 0xb28d */ { true, 0xb28d, 0xb28d }, +/* 0xb28e */ { true, 0xb28e, 0xb28e }, +/* 0xb28f */ { true, 0xb28f, 0xb28f }, +/* 0xb290 */ { true, 0xb290, 0xb290 }, +/* 0xb291 */ { true, 0xb291, 0xb291 }, +/* 0xb292 */ { true, 0xb292, 0xb292 }, +/* 0xb293 */ { true, 0xb293, 0xb293 }, +/* 0xb294 */ { true, 0xb294, 0xb294 }, +/* 0xb295 */ { true, 0xb295, 0xb295 }, +/* 0xb296 */ { true, 0xb296, 0xb296 }, +/* 0xb297 */ { true, 0xb297, 0xb297 }, +/* 0xb298 */ { true, 0xb298, 0xb298 }, +/* 0xb299 */ { true, 0xb299, 0xb299 }, +/* 0xb29a */ { true, 0xb29a, 0xb29a }, +/* 0xb29b */ { true, 0xb29b, 0xb29b }, +/* 0xb29c */ { true, 0xb29c, 0xb29c }, +/* 0xb29d */ { true, 0xb29d, 0xb29d }, +/* 0xb29e */ { true, 0xb29e, 0xb29e }, +/* 0xb29f */ { true, 0xb29f, 0xb29f }, +/* 0xb2a0 */ { true, 0xb2a0, 0xb2a0 }, +/* 0xb2a1 */ { true, 0xb2a1, 0xb2a1 }, +/* 0xb2a2 */ { true, 0xb2a2, 0xb2a2 }, +/* 0xb2a3 */ { true, 0xb2a3, 0xb2a3 }, +/* 0xb2a4 */ { true, 0xb2a4, 0xb2a4 }, +/* 0xb2a5 */ { true, 0xb2a5, 0xb2a5 }, +/* 0xb2a6 */ { true, 0xb2a6, 0xb2a6 }, +/* 0xb2a7 */ { true, 0xb2a7, 0xb2a7 }, +/* 0xb2a8 */ { true, 0xb2a8, 0xb2a8 }, +/* 0xb2a9 */ { true, 0xb2a9, 0xb2a9 }, +/* 0xb2aa */ { true, 0xb2aa, 0xb2aa }, +/* 0xb2ab */ { true, 0xb2ab, 0xb2ab }, +/* 0xb2ac */ { true, 0xb2ac, 0xb2ac }, +/* 0xb2ad */ { true, 0xb2ad, 0xb2ad }, +/* 0xb2ae */ { true, 0xb2ae, 0xb2ae }, +/* 0xb2af */ { true, 0xb2af, 0xb2af }, +/* 0xb2b0 */ { true, 0xb2b0, 0xb2b0 }, +/* 0xb2b1 */ { true, 0xb2b1, 0xb2b1 }, +/* 0xb2b2 */ { true, 0xb2b2, 0xb2b2 }, +/* 0xb2b3 */ { true, 0xb2b3, 0xb2b3 }, +/* 0xb2b4 */ { true, 0xb2b4, 0xb2b4 }, +/* 0xb2b5 */ { true, 0xb2b5, 0xb2b5 }, +/* 0xb2b6 */ { true, 0xb2b6, 0xb2b6 }, +/* 0xb2b7 */ { true, 0xb2b7, 0xb2b7 }, +/* 0xb2b8 */ { true, 0xb2b8, 0xb2b8 }, +/* 0xb2b9 */ { true, 0xb2b9, 0xb2b9 }, +/* 0xb2ba */ { true, 0xb2ba, 0xb2ba }, +/* 0xb2bb */ { true, 0xb2bb, 0xb2bb }, +/* 0xb2bc */ { true, 0xb2bc, 0xb2bc }, +/* 0xb2bd */ { true, 0xb2bd, 0xb2bd }, +/* 0xb2be */ { true, 0xb2be, 0xb2be }, +/* 0xb2bf */ { true, 0xb2bf, 0xb2bf }, +/* 0xb2c0 */ { true, 0xb2c0, 0xb2c0 }, +/* 0xb2c1 */ { true, 0xb2c1, 0xb2c1 }, +/* 0xb2c2 */ { true, 0xb2c2, 0xb2c2 }, +/* 0xb2c3 */ { true, 0xb2c3, 0xb2c3 }, +/* 0xb2c4 */ { true, 0xb2c4, 0xb2c4 }, +/* 0xb2c5 */ { true, 0xb2c5, 0xb2c5 }, +/* 0xb2c6 */ { true, 0xb2c6, 0xb2c6 }, +/* 0xb2c7 */ { true, 0xb2c7, 0xb2c7 }, +/* 0xb2c8 */ { true, 0xb2c8, 0xb2c8 }, +/* 0xb2c9 */ { true, 0xb2c9, 0xb2c9 }, +/* 0xb2ca */ { true, 0xb2ca, 0xb2ca }, +/* 0xb2cb */ { true, 0xb2cb, 0xb2cb }, +/* 0xb2cc */ { true, 0xb2cc, 0xb2cc }, +/* 0xb2cd */ { true, 0xb2cd, 0xb2cd }, +/* 0xb2ce */ { true, 0xb2ce, 0xb2ce }, +/* 0xb2cf */ { true, 0xb2cf, 0xb2cf }, +/* 0xb2d0 */ { true, 0xb2d0, 0xb2d0 }, +/* 0xb2d1 */ { true, 0xb2d1, 0xb2d1 }, +/* 0xb2d2 */ { true, 0xb2d2, 0xb2d2 }, +/* 0xb2d3 */ { true, 0xb2d3, 0xb2d3 }, +/* 0xb2d4 */ { true, 0xb2d4, 0xb2d4 }, +/* 0xb2d5 */ { true, 0xb2d5, 0xb2d5 }, +/* 0xb2d6 */ { true, 0xb2d6, 0xb2d6 }, +/* 0xb2d7 */ { true, 0xb2d7, 0xb2d7 }, +/* 0xb2d8 */ { true, 0xb2d8, 0xb2d8 }, +/* 0xb2d9 */ { true, 0xb2d9, 0xb2d9 }, +/* 0xb2da */ { true, 0xb2da, 0xb2da }, +/* 0xb2db */ { true, 0xb2db, 0xb2db }, +/* 0xb2dc */ { true, 0xb2dc, 0xb2dc }, +/* 0xb2dd */ { true, 0xb2dd, 0xb2dd }, +/* 0xb2de */ { true, 0xb2de, 0xb2de }, +/* 0xb2df */ { true, 0xb2df, 0xb2df }, +/* 0xb2e0 */ { true, 0xb2e0, 0xb2e0 }, +/* 0xb2e1 */ { true, 0xb2e1, 0xb2e1 }, +/* 0xb2e2 */ { true, 0xb2e2, 0xb2e2 }, +/* 0xb2e3 */ { true, 0xb2e3, 0xb2e3 }, +/* 0xb2e4 */ { true, 0xb2e4, 0xb2e4 }, +/* 0xb2e5 */ { true, 0xb2e5, 0xb2e5 }, +/* 0xb2e6 */ { true, 0xb2e6, 0xb2e6 }, +/* 0xb2e7 */ { true, 0xb2e7, 0xb2e7 }, +/* 0xb2e8 */ { true, 0xb2e8, 0xb2e8 }, +/* 0xb2e9 */ { true, 0xb2e9, 0xb2e9 }, +/* 0xb2ea */ { true, 0xb2ea, 0xb2ea }, +/* 0xb2eb */ { true, 0xb2eb, 0xb2eb }, +/* 0xb2ec */ { true, 0xb2ec, 0xb2ec }, +/* 0xb2ed */ { true, 0xb2ed, 0xb2ed }, +/* 0xb2ee */ { true, 0xb2ee, 0xb2ee }, +/* 0xb2ef */ { true, 0xb2ef, 0xb2ef }, +/* 0xb2f0 */ { true, 0xb2f0, 0xb2f0 }, +/* 0xb2f1 */ { true, 0xb2f1, 0xb2f1 }, +/* 0xb2f2 */ { true, 0xb2f2, 0xb2f2 }, +/* 0xb2f3 */ { true, 0xb2f3, 0xb2f3 }, +/* 0xb2f4 */ { true, 0xb2f4, 0xb2f4 }, +/* 0xb2f5 */ { true, 0xb2f5, 0xb2f5 }, +/* 0xb2f6 */ { true, 0xb2f6, 0xb2f6 }, +/* 0xb2f7 */ { true, 0xb2f7, 0xb2f7 }, +/* 0xb2f8 */ { true, 0xb2f8, 0xb2f8 }, +/* 0xb2f9 */ { true, 0xb2f9, 0xb2f9 }, +/* 0xb2fa */ { true, 0xb2fa, 0xb2fa }, +/* 0xb2fb */ { true, 0xb2fb, 0xb2fb }, +/* 0xb2fc */ { true, 0xb2fc, 0xb2fc }, +/* 0xb2fd */ { true, 0xb2fd, 0xb2fd }, +/* 0xb2fe */ { true, 0xb2fe, 0xb2fe }, +/* 0xb2ff */ { true, 0xb2ff, 0xb2ff }, +/* 0xb300 */ { true, 0xb300, 0xb300 }, +/* 0xb301 */ { true, 0xb301, 0xb301 }, +/* 0xb302 */ { true, 0xb302, 0xb302 }, +/* 0xb303 */ { true, 0xb303, 0xb303 }, +/* 0xb304 */ { true, 0xb304, 0xb304 }, +/* 0xb305 */ { true, 0xb305, 0xb305 }, +/* 0xb306 */ { true, 0xb306, 0xb306 }, +/* 0xb307 */ { true, 0xb307, 0xb307 }, +/* 0xb308 */ { true, 0xb308, 0xb308 }, +/* 0xb309 */ { true, 0xb309, 0xb309 }, +/* 0xb30a */ { true, 0xb30a, 0xb30a }, +/* 0xb30b */ { true, 0xb30b, 0xb30b }, +/* 0xb30c */ { true, 0xb30c, 0xb30c }, +/* 0xb30d */ { true, 0xb30d, 0xb30d }, +/* 0xb30e */ { true, 0xb30e, 0xb30e }, +/* 0xb30f */ { true, 0xb30f, 0xb30f }, +/* 0xb310 */ { true, 0xb310, 0xb310 }, +/* 0xb311 */ { true, 0xb311, 0xb311 }, +/* 0xb312 */ { true, 0xb312, 0xb312 }, +/* 0xb313 */ { true, 0xb313, 0xb313 }, +/* 0xb314 */ { true, 0xb314, 0xb314 }, +/* 0xb315 */ { true, 0xb315, 0xb315 }, +/* 0xb316 */ { true, 0xb316, 0xb316 }, +/* 0xb317 */ { true, 0xb317, 0xb317 }, +/* 0xb318 */ { true, 0xb318, 0xb318 }, +/* 0xb319 */ { true, 0xb319, 0xb319 }, +/* 0xb31a */ { true, 0xb31a, 0xb31a }, +/* 0xb31b */ { true, 0xb31b, 0xb31b }, +/* 0xb31c */ { true, 0xb31c, 0xb31c }, +/* 0xb31d */ { true, 0xb31d, 0xb31d }, +/* 0xb31e */ { true, 0xb31e, 0xb31e }, +/* 0xb31f */ { true, 0xb31f, 0xb31f }, +/* 0xb320 */ { true, 0xb320, 0xb320 }, +/* 0xb321 */ { true, 0xb321, 0xb321 }, +/* 0xb322 */ { true, 0xb322, 0xb322 }, +/* 0xb323 */ { true, 0xb323, 0xb323 }, +/* 0xb324 */ { true, 0xb324, 0xb324 }, +/* 0xb325 */ { true, 0xb325, 0xb325 }, +/* 0xb326 */ { true, 0xb326, 0xb326 }, +/* 0xb327 */ { true, 0xb327, 0xb327 }, +/* 0xb328 */ { true, 0xb328, 0xb328 }, +/* 0xb329 */ { true, 0xb329, 0xb329 }, +/* 0xb32a */ { true, 0xb32a, 0xb32a }, +/* 0xb32b */ { true, 0xb32b, 0xb32b }, +/* 0xb32c */ { true, 0xb32c, 0xb32c }, +/* 0xb32d */ { true, 0xb32d, 0xb32d }, +/* 0xb32e */ { true, 0xb32e, 0xb32e }, +/* 0xb32f */ { true, 0xb32f, 0xb32f }, +/* 0xb330 */ { true, 0xb330, 0xb330 }, +/* 0xb331 */ { true, 0xb331, 0xb331 }, +/* 0xb332 */ { true, 0xb332, 0xb332 }, +/* 0xb333 */ { true, 0xb333, 0xb333 }, +/* 0xb334 */ { true, 0xb334, 0xb334 }, +/* 0xb335 */ { true, 0xb335, 0xb335 }, +/* 0xb336 */ { true, 0xb336, 0xb336 }, +/* 0xb337 */ { true, 0xb337, 0xb337 }, +/* 0xb338 */ { true, 0xb338, 0xb338 }, +/* 0xb339 */ { true, 0xb339, 0xb339 }, +/* 0xb33a */ { true, 0xb33a, 0xb33a }, +/* 0xb33b */ { true, 0xb33b, 0xb33b }, +/* 0xb33c */ { true, 0xb33c, 0xb33c }, +/* 0xb33d */ { true, 0xb33d, 0xb33d }, +/* 0xb33e */ { true, 0xb33e, 0xb33e }, +/* 0xb33f */ { true, 0xb33f, 0xb33f }, +/* 0xb340 */ { true, 0xb340, 0xb340 }, +/* 0xb341 */ { true, 0xb341, 0xb341 }, +/* 0xb342 */ { true, 0xb342, 0xb342 }, +/* 0xb343 */ { true, 0xb343, 0xb343 }, +/* 0xb344 */ { true, 0xb344, 0xb344 }, +/* 0xb345 */ { true, 0xb345, 0xb345 }, +/* 0xb346 */ { true, 0xb346, 0xb346 }, +/* 0xb347 */ { true, 0xb347, 0xb347 }, +/* 0xb348 */ { true, 0xb348, 0xb348 }, +/* 0xb349 */ { true, 0xb349, 0xb349 }, +/* 0xb34a */ { true, 0xb34a, 0xb34a }, +/* 0xb34b */ { true, 0xb34b, 0xb34b }, +/* 0xb34c */ { true, 0xb34c, 0xb34c }, +/* 0xb34d */ { true, 0xb34d, 0xb34d }, +/* 0xb34e */ { true, 0xb34e, 0xb34e }, +/* 0xb34f */ { true, 0xb34f, 0xb34f }, +/* 0xb350 */ { true, 0xb350, 0xb350 }, +/* 0xb351 */ { true, 0xb351, 0xb351 }, +/* 0xb352 */ { true, 0xb352, 0xb352 }, +/* 0xb353 */ { true, 0xb353, 0xb353 }, +/* 0xb354 */ { true, 0xb354, 0xb354 }, +/* 0xb355 */ { true, 0xb355, 0xb355 }, +/* 0xb356 */ { true, 0xb356, 0xb356 }, +/* 0xb357 */ { true, 0xb357, 0xb357 }, +/* 0xb358 */ { true, 0xb358, 0xb358 }, +/* 0xb359 */ { true, 0xb359, 0xb359 }, +/* 0xb35a */ { true, 0xb35a, 0xb35a }, +/* 0xb35b */ { true, 0xb35b, 0xb35b }, +/* 0xb35c */ { true, 0xb35c, 0xb35c }, +/* 0xb35d */ { true, 0xb35d, 0xb35d }, +/* 0xb35e */ { true, 0xb35e, 0xb35e }, +/* 0xb35f */ { true, 0xb35f, 0xb35f }, +/* 0xb360 */ { true, 0xb360, 0xb360 }, +/* 0xb361 */ { true, 0xb361, 0xb361 }, +/* 0xb362 */ { true, 0xb362, 0xb362 }, +/* 0xb363 */ { true, 0xb363, 0xb363 }, +/* 0xb364 */ { true, 0xb364, 0xb364 }, +/* 0xb365 */ { true, 0xb365, 0xb365 }, +/* 0xb366 */ { true, 0xb366, 0xb366 }, +/* 0xb367 */ { true, 0xb367, 0xb367 }, +/* 0xb368 */ { true, 0xb368, 0xb368 }, +/* 0xb369 */ { true, 0xb369, 0xb369 }, +/* 0xb36a */ { true, 0xb36a, 0xb36a }, +/* 0xb36b */ { true, 0xb36b, 0xb36b }, +/* 0xb36c */ { true, 0xb36c, 0xb36c }, +/* 0xb36d */ { true, 0xb36d, 0xb36d }, +/* 0xb36e */ { true, 0xb36e, 0xb36e }, +/* 0xb36f */ { true, 0xb36f, 0xb36f }, +/* 0xb370 */ { true, 0xb370, 0xb370 }, +/* 0xb371 */ { true, 0xb371, 0xb371 }, +/* 0xb372 */ { true, 0xb372, 0xb372 }, +/* 0xb373 */ { true, 0xb373, 0xb373 }, +/* 0xb374 */ { true, 0xb374, 0xb374 }, +/* 0xb375 */ { true, 0xb375, 0xb375 }, +/* 0xb376 */ { true, 0xb376, 0xb376 }, +/* 0xb377 */ { true, 0xb377, 0xb377 }, +/* 0xb378 */ { true, 0xb378, 0xb378 }, +/* 0xb379 */ { true, 0xb379, 0xb379 }, +/* 0xb37a */ { true, 0xb37a, 0xb37a }, +/* 0xb37b */ { true, 0xb37b, 0xb37b }, +/* 0xb37c */ { true, 0xb37c, 0xb37c }, +/* 0xb37d */ { true, 0xb37d, 0xb37d }, +/* 0xb37e */ { true, 0xb37e, 0xb37e }, +/* 0xb37f */ { true, 0xb37f, 0xb37f }, +/* 0xb380 */ { true, 0xb380, 0xb380 }, +/* 0xb381 */ { true, 0xb381, 0xb381 }, +/* 0xb382 */ { true, 0xb382, 0xb382 }, +/* 0xb383 */ { true, 0xb383, 0xb383 }, +/* 0xb384 */ { true, 0xb384, 0xb384 }, +/* 0xb385 */ { true, 0xb385, 0xb385 }, +/* 0xb386 */ { true, 0xb386, 0xb386 }, +/* 0xb387 */ { true, 0xb387, 0xb387 }, +/* 0xb388 */ { true, 0xb388, 0xb388 }, +/* 0xb389 */ { true, 0xb389, 0xb389 }, +/* 0xb38a */ { true, 0xb38a, 0xb38a }, +/* 0xb38b */ { true, 0xb38b, 0xb38b }, +/* 0xb38c */ { true, 0xb38c, 0xb38c }, +/* 0xb38d */ { true, 0xb38d, 0xb38d }, +/* 0xb38e */ { true, 0xb38e, 0xb38e }, +/* 0xb38f */ { true, 0xb38f, 0xb38f }, +/* 0xb390 */ { true, 0xb390, 0xb390 }, +/* 0xb391 */ { true, 0xb391, 0xb391 }, +/* 0xb392 */ { true, 0xb392, 0xb392 }, +/* 0xb393 */ { true, 0xb393, 0xb393 }, +/* 0xb394 */ { true, 0xb394, 0xb394 }, +/* 0xb395 */ { true, 0xb395, 0xb395 }, +/* 0xb396 */ { true, 0xb396, 0xb396 }, +/* 0xb397 */ { true, 0xb397, 0xb397 }, +/* 0xb398 */ { true, 0xb398, 0xb398 }, +/* 0xb399 */ { true, 0xb399, 0xb399 }, +/* 0xb39a */ { true, 0xb39a, 0xb39a }, +/* 0xb39b */ { true, 0xb39b, 0xb39b }, +/* 0xb39c */ { true, 0xb39c, 0xb39c }, +/* 0xb39d */ { true, 0xb39d, 0xb39d }, +/* 0xb39e */ { true, 0xb39e, 0xb39e }, +/* 0xb39f */ { true, 0xb39f, 0xb39f }, +/* 0xb3a0 */ { true, 0xb3a0, 0xb3a0 }, +/* 0xb3a1 */ { true, 0xb3a1, 0xb3a1 }, +/* 0xb3a2 */ { true, 0xb3a2, 0xb3a2 }, +/* 0xb3a3 */ { true, 0xb3a3, 0xb3a3 }, +/* 0xb3a4 */ { true, 0xb3a4, 0xb3a4 }, +/* 0xb3a5 */ { true, 0xb3a5, 0xb3a5 }, +/* 0xb3a6 */ { true, 0xb3a6, 0xb3a6 }, +/* 0xb3a7 */ { true, 0xb3a7, 0xb3a7 }, +/* 0xb3a8 */ { true, 0xb3a8, 0xb3a8 }, +/* 0xb3a9 */ { true, 0xb3a9, 0xb3a9 }, +/* 0xb3aa */ { true, 0xb3aa, 0xb3aa }, +/* 0xb3ab */ { true, 0xb3ab, 0xb3ab }, +/* 0xb3ac */ { true, 0xb3ac, 0xb3ac }, +/* 0xb3ad */ { true, 0xb3ad, 0xb3ad }, +/* 0xb3ae */ { true, 0xb3ae, 0xb3ae }, +/* 0xb3af */ { true, 0xb3af, 0xb3af }, +/* 0xb3b0 */ { true, 0xb3b0, 0xb3b0 }, +/* 0xb3b1 */ { true, 0xb3b1, 0xb3b1 }, +/* 0xb3b2 */ { true, 0xb3b2, 0xb3b2 }, +/* 0xb3b3 */ { true, 0xb3b3, 0xb3b3 }, +/* 0xb3b4 */ { true, 0xb3b4, 0xb3b4 }, +/* 0xb3b5 */ { true, 0xb3b5, 0xb3b5 }, +/* 0xb3b6 */ { true, 0xb3b6, 0xb3b6 }, +/* 0xb3b7 */ { true, 0xb3b7, 0xb3b7 }, +/* 0xb3b8 */ { true, 0xb3b8, 0xb3b8 }, +/* 0xb3b9 */ { true, 0xb3b9, 0xb3b9 }, +/* 0xb3ba */ { true, 0xb3ba, 0xb3ba }, +/* 0xb3bb */ { true, 0xb3bb, 0xb3bb }, +/* 0xb3bc */ { true, 0xb3bc, 0xb3bc }, +/* 0xb3bd */ { true, 0xb3bd, 0xb3bd }, +/* 0xb3be */ { true, 0xb3be, 0xb3be }, +/* 0xb3bf */ { true, 0xb3bf, 0xb3bf }, +/* 0xb3c0 */ { true, 0xb3c0, 0xb3c0 }, +/* 0xb3c1 */ { true, 0xb3c1, 0xb3c1 }, +/* 0xb3c2 */ { true, 0xb3c2, 0xb3c2 }, +/* 0xb3c3 */ { true, 0xb3c3, 0xb3c3 }, +/* 0xb3c4 */ { true, 0xb3c4, 0xb3c4 }, +/* 0xb3c5 */ { true, 0xb3c5, 0xb3c5 }, +/* 0xb3c6 */ { true, 0xb3c6, 0xb3c6 }, +/* 0xb3c7 */ { true, 0xb3c7, 0xb3c7 }, +/* 0xb3c8 */ { true, 0xb3c8, 0xb3c8 }, +/* 0xb3c9 */ { true, 0xb3c9, 0xb3c9 }, +/* 0xb3ca */ { true, 0xb3ca, 0xb3ca }, +/* 0xb3cb */ { true, 0xb3cb, 0xb3cb }, +/* 0xb3cc */ { true, 0xb3cc, 0xb3cc }, +/* 0xb3cd */ { true, 0xb3cd, 0xb3cd }, +/* 0xb3ce */ { true, 0xb3ce, 0xb3ce }, +/* 0xb3cf */ { true, 0xb3cf, 0xb3cf }, +/* 0xb3d0 */ { true, 0xb3d0, 0xb3d0 }, +/* 0xb3d1 */ { true, 0xb3d1, 0xb3d1 }, +/* 0xb3d2 */ { true, 0xb3d2, 0xb3d2 }, +/* 0xb3d3 */ { true, 0xb3d3, 0xb3d3 }, +/* 0xb3d4 */ { true, 0xb3d4, 0xb3d4 }, +/* 0xb3d5 */ { true, 0xb3d5, 0xb3d5 }, +/* 0xb3d6 */ { true, 0xb3d6, 0xb3d6 }, +/* 0xb3d7 */ { true, 0xb3d7, 0xb3d7 }, +/* 0xb3d8 */ { true, 0xb3d8, 0xb3d8 }, +/* 0xb3d9 */ { true, 0xb3d9, 0xb3d9 }, +/* 0xb3da */ { true, 0xb3da, 0xb3da }, +/* 0xb3db */ { true, 0xb3db, 0xb3db }, +/* 0xb3dc */ { true, 0xb3dc, 0xb3dc }, +/* 0xb3dd */ { true, 0xb3dd, 0xb3dd }, +/* 0xb3de */ { true, 0xb3de, 0xb3de }, +/* 0xb3df */ { true, 0xb3df, 0xb3df }, +/* 0xb3e0 */ { true, 0xb3e0, 0xb3e0 }, +/* 0xb3e1 */ { true, 0xb3e1, 0xb3e1 }, +/* 0xb3e2 */ { true, 0xb3e2, 0xb3e2 }, +/* 0xb3e3 */ { true, 0xb3e3, 0xb3e3 }, +/* 0xb3e4 */ { true, 0xb3e4, 0xb3e4 }, +/* 0xb3e5 */ { true, 0xb3e5, 0xb3e5 }, +/* 0xb3e6 */ { true, 0xb3e6, 0xb3e6 }, +/* 0xb3e7 */ { true, 0xb3e7, 0xb3e7 }, +/* 0xb3e8 */ { true, 0xb3e8, 0xb3e8 }, +/* 0xb3e9 */ { true, 0xb3e9, 0xb3e9 }, +/* 0xb3ea */ { true, 0xb3ea, 0xb3ea }, +/* 0xb3eb */ { true, 0xb3eb, 0xb3eb }, +/* 0xb3ec */ { true, 0xb3ec, 0xb3ec }, +/* 0xb3ed */ { true, 0xb3ed, 0xb3ed }, +/* 0xb3ee */ { true, 0xb3ee, 0xb3ee }, +/* 0xb3ef */ { true, 0xb3ef, 0xb3ef }, +/* 0xb3f0 */ { true, 0xb3f0, 0xb3f0 }, +/* 0xb3f1 */ { true, 0xb3f1, 0xb3f1 }, +/* 0xb3f2 */ { true, 0xb3f2, 0xb3f2 }, +/* 0xb3f3 */ { true, 0xb3f3, 0xb3f3 }, +/* 0xb3f4 */ { true, 0xb3f4, 0xb3f4 }, +/* 0xb3f5 */ { true, 0xb3f5, 0xb3f5 }, +/* 0xb3f6 */ { true, 0xb3f6, 0xb3f6 }, +/* 0xb3f7 */ { true, 0xb3f7, 0xb3f7 }, +/* 0xb3f8 */ { true, 0xb3f8, 0xb3f8 }, +/* 0xb3f9 */ { true, 0xb3f9, 0xb3f9 }, +/* 0xb3fa */ { true, 0xb3fa, 0xb3fa }, +/* 0xb3fb */ { true, 0xb3fb, 0xb3fb }, +/* 0xb3fc */ { true, 0xb3fc, 0xb3fc }, +/* 0xb3fd */ { true, 0xb3fd, 0xb3fd }, +/* 0xb3fe */ { true, 0xb3fe, 0xb3fe }, +/* 0xb3ff */ { true, 0xb3ff, 0xb3ff }, +/* 0xb400 */ { true, 0xb400, 0xb400 }, +/* 0xb401 */ { true, 0xb401, 0xb401 }, +/* 0xb402 */ { true, 0xb402, 0xb402 }, +/* 0xb403 */ { true, 0xb403, 0xb403 }, +/* 0xb404 */ { true, 0xb404, 0xb404 }, +/* 0xb405 */ { true, 0xb405, 0xb405 }, +/* 0xb406 */ { true, 0xb406, 0xb406 }, +/* 0xb407 */ { true, 0xb407, 0xb407 }, +/* 0xb408 */ { true, 0xb408, 0xb408 }, +/* 0xb409 */ { true, 0xb409, 0xb409 }, +/* 0xb40a */ { true, 0xb40a, 0xb40a }, +/* 0xb40b */ { true, 0xb40b, 0xb40b }, +/* 0xb40c */ { true, 0xb40c, 0xb40c }, +/* 0xb40d */ { true, 0xb40d, 0xb40d }, +/* 0xb40e */ { true, 0xb40e, 0xb40e }, +/* 0xb40f */ { true, 0xb40f, 0xb40f }, +/* 0xb410 */ { true, 0xb410, 0xb410 }, +/* 0xb411 */ { true, 0xb411, 0xb411 }, +/* 0xb412 */ { true, 0xb412, 0xb412 }, +/* 0xb413 */ { true, 0xb413, 0xb413 }, +/* 0xb414 */ { true, 0xb414, 0xb414 }, +/* 0xb415 */ { true, 0xb415, 0xb415 }, +/* 0xb416 */ { true, 0xb416, 0xb416 }, +/* 0xb417 */ { true, 0xb417, 0xb417 }, +/* 0xb418 */ { true, 0xb418, 0xb418 }, +/* 0xb419 */ { true, 0xb419, 0xb419 }, +/* 0xb41a */ { true, 0xb41a, 0xb41a }, +/* 0xb41b */ { true, 0xb41b, 0xb41b }, +/* 0xb41c */ { true, 0xb41c, 0xb41c }, +/* 0xb41d */ { true, 0xb41d, 0xb41d }, +/* 0xb41e */ { true, 0xb41e, 0xb41e }, +/* 0xb41f */ { true, 0xb41f, 0xb41f }, +/* 0xb420 */ { true, 0xb420, 0xb420 }, +/* 0xb421 */ { true, 0xb421, 0xb421 }, +/* 0xb422 */ { true, 0xb422, 0xb422 }, +/* 0xb423 */ { true, 0xb423, 0xb423 }, +/* 0xb424 */ { true, 0xb424, 0xb424 }, +/* 0xb425 */ { true, 0xb425, 0xb425 }, +/* 0xb426 */ { true, 0xb426, 0xb426 }, +/* 0xb427 */ { true, 0xb427, 0xb427 }, +/* 0xb428 */ { true, 0xb428, 0xb428 }, +/* 0xb429 */ { true, 0xb429, 0xb429 }, +/* 0xb42a */ { true, 0xb42a, 0xb42a }, +/* 0xb42b */ { true, 0xb42b, 0xb42b }, +/* 0xb42c */ { true, 0xb42c, 0xb42c }, +/* 0xb42d */ { true, 0xb42d, 0xb42d }, +/* 0xb42e */ { true, 0xb42e, 0xb42e }, +/* 0xb42f */ { true, 0xb42f, 0xb42f }, +/* 0xb430 */ { true, 0xb430, 0xb430 }, +/* 0xb431 */ { true, 0xb431, 0xb431 }, +/* 0xb432 */ { true, 0xb432, 0xb432 }, +/* 0xb433 */ { true, 0xb433, 0xb433 }, +/* 0xb434 */ { true, 0xb434, 0xb434 }, +/* 0xb435 */ { true, 0xb435, 0xb435 }, +/* 0xb436 */ { true, 0xb436, 0xb436 }, +/* 0xb437 */ { true, 0xb437, 0xb437 }, +/* 0xb438 */ { true, 0xb438, 0xb438 }, +/* 0xb439 */ { true, 0xb439, 0xb439 }, +/* 0xb43a */ { true, 0xb43a, 0xb43a }, +/* 0xb43b */ { true, 0xb43b, 0xb43b }, +/* 0xb43c */ { true, 0xb43c, 0xb43c }, +/* 0xb43d */ { true, 0xb43d, 0xb43d }, +/* 0xb43e */ { true, 0xb43e, 0xb43e }, +/* 0xb43f */ { true, 0xb43f, 0xb43f }, +/* 0xb440 */ { true, 0xb440, 0xb440 }, +/* 0xb441 */ { true, 0xb441, 0xb441 }, +/* 0xb442 */ { true, 0xb442, 0xb442 }, +/* 0xb443 */ { true, 0xb443, 0xb443 }, +/* 0xb444 */ { true, 0xb444, 0xb444 }, +/* 0xb445 */ { true, 0xb445, 0xb445 }, +/* 0xb446 */ { true, 0xb446, 0xb446 }, +/* 0xb447 */ { true, 0xb447, 0xb447 }, +/* 0xb448 */ { true, 0xb448, 0xb448 }, +/* 0xb449 */ { true, 0xb449, 0xb449 }, +/* 0xb44a */ { true, 0xb44a, 0xb44a }, +/* 0xb44b */ { true, 0xb44b, 0xb44b }, +/* 0xb44c */ { true, 0xb44c, 0xb44c }, +/* 0xb44d */ { true, 0xb44d, 0xb44d }, +/* 0xb44e */ { true, 0xb44e, 0xb44e }, +/* 0xb44f */ { true, 0xb44f, 0xb44f }, +/* 0xb450 */ { true, 0xb450, 0xb450 }, +/* 0xb451 */ { true, 0xb451, 0xb451 }, +/* 0xb452 */ { true, 0xb452, 0xb452 }, +/* 0xb453 */ { true, 0xb453, 0xb453 }, +/* 0xb454 */ { true, 0xb454, 0xb454 }, +/* 0xb455 */ { true, 0xb455, 0xb455 }, +/* 0xb456 */ { true, 0xb456, 0xb456 }, +/* 0xb457 */ { true, 0xb457, 0xb457 }, +/* 0xb458 */ { true, 0xb458, 0xb458 }, +/* 0xb459 */ { true, 0xb459, 0xb459 }, +/* 0xb45a */ { true, 0xb45a, 0xb45a }, +/* 0xb45b */ { true, 0xb45b, 0xb45b }, +/* 0xb45c */ { true, 0xb45c, 0xb45c }, +/* 0xb45d */ { true, 0xb45d, 0xb45d }, +/* 0xb45e */ { true, 0xb45e, 0xb45e }, +/* 0xb45f */ { true, 0xb45f, 0xb45f }, +/* 0xb460 */ { true, 0xb460, 0xb460 }, +/* 0xb461 */ { true, 0xb461, 0xb461 }, +/* 0xb462 */ { true, 0xb462, 0xb462 }, +/* 0xb463 */ { true, 0xb463, 0xb463 }, +/* 0xb464 */ { true, 0xb464, 0xb464 }, +/* 0xb465 */ { true, 0xb465, 0xb465 }, +/* 0xb466 */ { true, 0xb466, 0xb466 }, +/* 0xb467 */ { true, 0xb467, 0xb467 }, +/* 0xb468 */ { true, 0xb468, 0xb468 }, +/* 0xb469 */ { true, 0xb469, 0xb469 }, +/* 0xb46a */ { true, 0xb46a, 0xb46a }, +/* 0xb46b */ { true, 0xb46b, 0xb46b }, +/* 0xb46c */ { true, 0xb46c, 0xb46c }, +/* 0xb46d */ { true, 0xb46d, 0xb46d }, +/* 0xb46e */ { true, 0xb46e, 0xb46e }, +/* 0xb46f */ { true, 0xb46f, 0xb46f }, +/* 0xb470 */ { true, 0xb470, 0xb470 }, +/* 0xb471 */ { true, 0xb471, 0xb471 }, +/* 0xb472 */ { true, 0xb472, 0xb472 }, +/* 0xb473 */ { true, 0xb473, 0xb473 }, +/* 0xb474 */ { true, 0xb474, 0xb474 }, +/* 0xb475 */ { true, 0xb475, 0xb475 }, +/* 0xb476 */ { true, 0xb476, 0xb476 }, +/* 0xb477 */ { true, 0xb477, 0xb477 }, +/* 0xb478 */ { true, 0xb478, 0xb478 }, +/* 0xb479 */ { true, 0xb479, 0xb479 }, +/* 0xb47a */ { true, 0xb47a, 0xb47a }, +/* 0xb47b */ { true, 0xb47b, 0xb47b }, +/* 0xb47c */ { true, 0xb47c, 0xb47c }, +/* 0xb47d */ { true, 0xb47d, 0xb47d }, +/* 0xb47e */ { true, 0xb47e, 0xb47e }, +/* 0xb47f */ { true, 0xb47f, 0xb47f }, +/* 0xb480 */ { true, 0xb480, 0xb480 }, +/* 0xb481 */ { true, 0xb481, 0xb481 }, +/* 0xb482 */ { true, 0xb482, 0xb482 }, +/* 0xb483 */ { true, 0xb483, 0xb483 }, +/* 0xb484 */ { true, 0xb484, 0xb484 }, +/* 0xb485 */ { true, 0xb485, 0xb485 }, +/* 0xb486 */ { true, 0xb486, 0xb486 }, +/* 0xb487 */ { true, 0xb487, 0xb487 }, +/* 0xb488 */ { true, 0xb488, 0xb488 }, +/* 0xb489 */ { true, 0xb489, 0xb489 }, +/* 0xb48a */ { true, 0xb48a, 0xb48a }, +/* 0xb48b */ { true, 0xb48b, 0xb48b }, +/* 0xb48c */ { true, 0xb48c, 0xb48c }, +/* 0xb48d */ { true, 0xb48d, 0xb48d }, +/* 0xb48e */ { true, 0xb48e, 0xb48e }, +/* 0xb48f */ { true, 0xb48f, 0xb48f }, +/* 0xb490 */ { true, 0xb490, 0xb490 }, +/* 0xb491 */ { true, 0xb491, 0xb491 }, +/* 0xb492 */ { true, 0xb492, 0xb492 }, +/* 0xb493 */ { true, 0xb493, 0xb493 }, +/* 0xb494 */ { true, 0xb494, 0xb494 }, +/* 0xb495 */ { true, 0xb495, 0xb495 }, +/* 0xb496 */ { true, 0xb496, 0xb496 }, +/* 0xb497 */ { true, 0xb497, 0xb497 }, +/* 0xb498 */ { true, 0xb498, 0xb498 }, +/* 0xb499 */ { true, 0xb499, 0xb499 }, +/* 0xb49a */ { true, 0xb49a, 0xb49a }, +/* 0xb49b */ { true, 0xb49b, 0xb49b }, +/* 0xb49c */ { true, 0xb49c, 0xb49c }, +/* 0xb49d */ { true, 0xb49d, 0xb49d }, +/* 0xb49e */ { true, 0xb49e, 0xb49e }, +/* 0xb49f */ { true, 0xb49f, 0xb49f }, +/* 0xb4a0 */ { true, 0xb4a0, 0xb4a0 }, +/* 0xb4a1 */ { true, 0xb4a1, 0xb4a1 }, +/* 0xb4a2 */ { true, 0xb4a2, 0xb4a2 }, +/* 0xb4a3 */ { true, 0xb4a3, 0xb4a3 }, +/* 0xb4a4 */ { true, 0xb4a4, 0xb4a4 }, +/* 0xb4a5 */ { true, 0xb4a5, 0xb4a5 }, +/* 0xb4a6 */ { true, 0xb4a6, 0xb4a6 }, +/* 0xb4a7 */ { true, 0xb4a7, 0xb4a7 }, +/* 0xb4a8 */ { true, 0xb4a8, 0xb4a8 }, +/* 0xb4a9 */ { true, 0xb4a9, 0xb4a9 }, +/* 0xb4aa */ { true, 0xb4aa, 0xb4aa }, +/* 0xb4ab */ { true, 0xb4ab, 0xb4ab }, +/* 0xb4ac */ { true, 0xb4ac, 0xb4ac }, +/* 0xb4ad */ { true, 0xb4ad, 0xb4ad }, +/* 0xb4ae */ { true, 0xb4ae, 0xb4ae }, +/* 0xb4af */ { true, 0xb4af, 0xb4af }, +/* 0xb4b0 */ { true, 0xb4b0, 0xb4b0 }, +/* 0xb4b1 */ { true, 0xb4b1, 0xb4b1 }, +/* 0xb4b2 */ { true, 0xb4b2, 0xb4b2 }, +/* 0xb4b3 */ { true, 0xb4b3, 0xb4b3 }, +/* 0xb4b4 */ { true, 0xb4b4, 0xb4b4 }, +/* 0xb4b5 */ { true, 0xb4b5, 0xb4b5 }, +/* 0xb4b6 */ { true, 0xb4b6, 0xb4b6 }, +/* 0xb4b7 */ { true, 0xb4b7, 0xb4b7 }, +/* 0xb4b8 */ { true, 0xb4b8, 0xb4b8 }, +/* 0xb4b9 */ { true, 0xb4b9, 0xb4b9 }, +/* 0xb4ba */ { true, 0xb4ba, 0xb4ba }, +/* 0xb4bb */ { true, 0xb4bb, 0xb4bb }, +/* 0xb4bc */ { true, 0xb4bc, 0xb4bc }, +/* 0xb4bd */ { true, 0xb4bd, 0xb4bd }, +/* 0xb4be */ { true, 0xb4be, 0xb4be }, +/* 0xb4bf */ { true, 0xb4bf, 0xb4bf }, +/* 0xb4c0 */ { true, 0xb4c0, 0xb4c0 }, +/* 0xb4c1 */ { true, 0xb4c1, 0xb4c1 }, +/* 0xb4c2 */ { true, 0xb4c2, 0xb4c2 }, +/* 0xb4c3 */ { true, 0xb4c3, 0xb4c3 }, +/* 0xb4c4 */ { true, 0xb4c4, 0xb4c4 }, +/* 0xb4c5 */ { true, 0xb4c5, 0xb4c5 }, +/* 0xb4c6 */ { true, 0xb4c6, 0xb4c6 }, +/* 0xb4c7 */ { true, 0xb4c7, 0xb4c7 }, +/* 0xb4c8 */ { true, 0xb4c8, 0xb4c8 }, +/* 0xb4c9 */ { true, 0xb4c9, 0xb4c9 }, +/* 0xb4ca */ { true, 0xb4ca, 0xb4ca }, +/* 0xb4cb */ { true, 0xb4cb, 0xb4cb }, +/* 0xb4cc */ { true, 0xb4cc, 0xb4cc }, +/* 0xb4cd */ { true, 0xb4cd, 0xb4cd }, +/* 0xb4ce */ { true, 0xb4ce, 0xb4ce }, +/* 0xb4cf */ { true, 0xb4cf, 0xb4cf }, +/* 0xb4d0 */ { true, 0xb4d0, 0xb4d0 }, +/* 0xb4d1 */ { true, 0xb4d1, 0xb4d1 }, +/* 0xb4d2 */ { true, 0xb4d2, 0xb4d2 }, +/* 0xb4d3 */ { true, 0xb4d3, 0xb4d3 }, +/* 0xb4d4 */ { true, 0xb4d4, 0xb4d4 }, +/* 0xb4d5 */ { true, 0xb4d5, 0xb4d5 }, +/* 0xb4d6 */ { true, 0xb4d6, 0xb4d6 }, +/* 0xb4d7 */ { true, 0xb4d7, 0xb4d7 }, +/* 0xb4d8 */ { true, 0xb4d8, 0xb4d8 }, +/* 0xb4d9 */ { true, 0xb4d9, 0xb4d9 }, +/* 0xb4da */ { true, 0xb4da, 0xb4da }, +/* 0xb4db */ { true, 0xb4db, 0xb4db }, +/* 0xb4dc */ { true, 0xb4dc, 0xb4dc }, +/* 0xb4dd */ { true, 0xb4dd, 0xb4dd }, +/* 0xb4de */ { true, 0xb4de, 0xb4de }, +/* 0xb4df */ { true, 0xb4df, 0xb4df }, +/* 0xb4e0 */ { true, 0xb4e0, 0xb4e0 }, +/* 0xb4e1 */ { true, 0xb4e1, 0xb4e1 }, +/* 0xb4e2 */ { true, 0xb4e2, 0xb4e2 }, +/* 0xb4e3 */ { true, 0xb4e3, 0xb4e3 }, +/* 0xb4e4 */ { true, 0xb4e4, 0xb4e4 }, +/* 0xb4e5 */ { true, 0xb4e5, 0xb4e5 }, +/* 0xb4e6 */ { true, 0xb4e6, 0xb4e6 }, +/* 0xb4e7 */ { true, 0xb4e7, 0xb4e7 }, +/* 0xb4e8 */ { true, 0xb4e8, 0xb4e8 }, +/* 0xb4e9 */ { true, 0xb4e9, 0xb4e9 }, +/* 0xb4ea */ { true, 0xb4ea, 0xb4ea }, +/* 0xb4eb */ { true, 0xb4eb, 0xb4eb }, +/* 0xb4ec */ { true, 0xb4ec, 0xb4ec }, +/* 0xb4ed */ { true, 0xb4ed, 0xb4ed }, +/* 0xb4ee */ { true, 0xb4ee, 0xb4ee }, +/* 0xb4ef */ { true, 0xb4ef, 0xb4ef }, +/* 0xb4f0 */ { true, 0xb4f0, 0xb4f0 }, +/* 0xb4f1 */ { true, 0xb4f1, 0xb4f1 }, +/* 0xb4f2 */ { true, 0xb4f2, 0xb4f2 }, +/* 0xb4f3 */ { true, 0xb4f3, 0xb4f3 }, +/* 0xb4f4 */ { true, 0xb4f4, 0xb4f4 }, +/* 0xb4f5 */ { true, 0xb4f5, 0xb4f5 }, +/* 0xb4f6 */ { true, 0xb4f6, 0xb4f6 }, +/* 0xb4f7 */ { true, 0xb4f7, 0xb4f7 }, +/* 0xb4f8 */ { true, 0xb4f8, 0xb4f8 }, +/* 0xb4f9 */ { true, 0xb4f9, 0xb4f9 }, +/* 0xb4fa */ { true, 0xb4fa, 0xb4fa }, +/* 0xb4fb */ { true, 0xb4fb, 0xb4fb }, +/* 0xb4fc */ { true, 0xb4fc, 0xb4fc }, +/* 0xb4fd */ { true, 0xb4fd, 0xb4fd }, +/* 0xb4fe */ { true, 0xb4fe, 0xb4fe }, +/* 0xb4ff */ { true, 0xb4ff, 0xb4ff }, +/* 0xb500 */ { true, 0xb500, 0xb500 }, +/* 0xb501 */ { true, 0xb501, 0xb501 }, +/* 0xb502 */ { true, 0xb502, 0xb502 }, +/* 0xb503 */ { true, 0xb503, 0xb503 }, +/* 0xb504 */ { true, 0xb504, 0xb504 }, +/* 0xb505 */ { true, 0xb505, 0xb505 }, +/* 0xb506 */ { true, 0xb506, 0xb506 }, +/* 0xb507 */ { true, 0xb507, 0xb507 }, +/* 0xb508 */ { true, 0xb508, 0xb508 }, +/* 0xb509 */ { true, 0xb509, 0xb509 }, +/* 0xb50a */ { true, 0xb50a, 0xb50a }, +/* 0xb50b */ { true, 0xb50b, 0xb50b }, +/* 0xb50c */ { true, 0xb50c, 0xb50c }, +/* 0xb50d */ { true, 0xb50d, 0xb50d }, +/* 0xb50e */ { true, 0xb50e, 0xb50e }, +/* 0xb50f */ { true, 0xb50f, 0xb50f }, +/* 0xb510 */ { true, 0xb510, 0xb510 }, +/* 0xb511 */ { true, 0xb511, 0xb511 }, +/* 0xb512 */ { true, 0xb512, 0xb512 }, +/* 0xb513 */ { true, 0xb513, 0xb513 }, +/* 0xb514 */ { true, 0xb514, 0xb514 }, +/* 0xb515 */ { true, 0xb515, 0xb515 }, +/* 0xb516 */ { true, 0xb516, 0xb516 }, +/* 0xb517 */ { true, 0xb517, 0xb517 }, +/* 0xb518 */ { true, 0xb518, 0xb518 }, +/* 0xb519 */ { true, 0xb519, 0xb519 }, +/* 0xb51a */ { true, 0xb51a, 0xb51a }, +/* 0xb51b */ { true, 0xb51b, 0xb51b }, +/* 0xb51c */ { true, 0xb51c, 0xb51c }, +/* 0xb51d */ { true, 0xb51d, 0xb51d }, +/* 0xb51e */ { true, 0xb51e, 0xb51e }, +/* 0xb51f */ { true, 0xb51f, 0xb51f }, +/* 0xb520 */ { true, 0xb520, 0xb520 }, +/* 0xb521 */ { true, 0xb521, 0xb521 }, +/* 0xb522 */ { true, 0xb522, 0xb522 }, +/* 0xb523 */ { true, 0xb523, 0xb523 }, +/* 0xb524 */ { true, 0xb524, 0xb524 }, +/* 0xb525 */ { true, 0xb525, 0xb525 }, +/* 0xb526 */ { true, 0xb526, 0xb526 }, +/* 0xb527 */ { true, 0xb527, 0xb527 }, +/* 0xb528 */ { true, 0xb528, 0xb528 }, +/* 0xb529 */ { true, 0xb529, 0xb529 }, +/* 0xb52a */ { true, 0xb52a, 0xb52a }, +/* 0xb52b */ { true, 0xb52b, 0xb52b }, +/* 0xb52c */ { true, 0xb52c, 0xb52c }, +/* 0xb52d */ { true, 0xb52d, 0xb52d }, +/* 0xb52e */ { true, 0xb52e, 0xb52e }, +/* 0xb52f */ { true, 0xb52f, 0xb52f }, +/* 0xb530 */ { true, 0xb530, 0xb530 }, +/* 0xb531 */ { true, 0xb531, 0xb531 }, +/* 0xb532 */ { true, 0xb532, 0xb532 }, +/* 0xb533 */ { true, 0xb533, 0xb533 }, +/* 0xb534 */ { true, 0xb534, 0xb534 }, +/* 0xb535 */ { true, 0xb535, 0xb535 }, +/* 0xb536 */ { true, 0xb536, 0xb536 }, +/* 0xb537 */ { true, 0xb537, 0xb537 }, +/* 0xb538 */ { true, 0xb538, 0xb538 }, +/* 0xb539 */ { true, 0xb539, 0xb539 }, +/* 0xb53a */ { true, 0xb53a, 0xb53a }, +/* 0xb53b */ { true, 0xb53b, 0xb53b }, +/* 0xb53c */ { true, 0xb53c, 0xb53c }, +/* 0xb53d */ { true, 0xb53d, 0xb53d }, +/* 0xb53e */ { true, 0xb53e, 0xb53e }, +/* 0xb53f */ { true, 0xb53f, 0xb53f }, +/* 0xb540 */ { true, 0xb540, 0xb540 }, +/* 0xb541 */ { true, 0xb541, 0xb541 }, +/* 0xb542 */ { true, 0xb542, 0xb542 }, +/* 0xb543 */ { true, 0xb543, 0xb543 }, +/* 0xb544 */ { true, 0xb544, 0xb544 }, +/* 0xb545 */ { true, 0xb545, 0xb545 }, +/* 0xb546 */ { true, 0xb546, 0xb546 }, +/* 0xb547 */ { true, 0xb547, 0xb547 }, +/* 0xb548 */ { true, 0xb548, 0xb548 }, +/* 0xb549 */ { true, 0xb549, 0xb549 }, +/* 0xb54a */ { true, 0xb54a, 0xb54a }, +/* 0xb54b */ { true, 0xb54b, 0xb54b }, +/* 0xb54c */ { true, 0xb54c, 0xb54c }, +/* 0xb54d */ { true, 0xb54d, 0xb54d }, +/* 0xb54e */ { true, 0xb54e, 0xb54e }, +/* 0xb54f */ { true, 0xb54f, 0xb54f }, +/* 0xb550 */ { true, 0xb550, 0xb550 }, +/* 0xb551 */ { true, 0xb551, 0xb551 }, +/* 0xb552 */ { true, 0xb552, 0xb552 }, +/* 0xb553 */ { true, 0xb553, 0xb553 }, +/* 0xb554 */ { true, 0xb554, 0xb554 }, +/* 0xb555 */ { true, 0xb555, 0xb555 }, +/* 0xb556 */ { true, 0xb556, 0xb556 }, +/* 0xb557 */ { true, 0xb557, 0xb557 }, +/* 0xb558 */ { true, 0xb558, 0xb558 }, +/* 0xb559 */ { true, 0xb559, 0xb559 }, +/* 0xb55a */ { true, 0xb55a, 0xb55a }, +/* 0xb55b */ { true, 0xb55b, 0xb55b }, +/* 0xb55c */ { true, 0xb55c, 0xb55c }, +/* 0xb55d */ { true, 0xb55d, 0xb55d }, +/* 0xb55e */ { true, 0xb55e, 0xb55e }, +/* 0xb55f */ { true, 0xb55f, 0xb55f }, +/* 0xb560 */ { true, 0xb560, 0xb560 }, +/* 0xb561 */ { true, 0xb561, 0xb561 }, +/* 0xb562 */ { true, 0xb562, 0xb562 }, +/* 0xb563 */ { true, 0xb563, 0xb563 }, +/* 0xb564 */ { true, 0xb564, 0xb564 }, +/* 0xb565 */ { true, 0xb565, 0xb565 }, +/* 0xb566 */ { true, 0xb566, 0xb566 }, +/* 0xb567 */ { true, 0xb567, 0xb567 }, +/* 0xb568 */ { true, 0xb568, 0xb568 }, +/* 0xb569 */ { true, 0xb569, 0xb569 }, +/* 0xb56a */ { true, 0xb56a, 0xb56a }, +/* 0xb56b */ { true, 0xb56b, 0xb56b }, +/* 0xb56c */ { true, 0xb56c, 0xb56c }, +/* 0xb56d */ { true, 0xb56d, 0xb56d }, +/* 0xb56e */ { true, 0xb56e, 0xb56e }, +/* 0xb56f */ { true, 0xb56f, 0xb56f }, +/* 0xb570 */ { true, 0xb570, 0xb570 }, +/* 0xb571 */ { true, 0xb571, 0xb571 }, +/* 0xb572 */ { true, 0xb572, 0xb572 }, +/* 0xb573 */ { true, 0xb573, 0xb573 }, +/* 0xb574 */ { true, 0xb574, 0xb574 }, +/* 0xb575 */ { true, 0xb575, 0xb575 }, +/* 0xb576 */ { true, 0xb576, 0xb576 }, +/* 0xb577 */ { true, 0xb577, 0xb577 }, +/* 0xb578 */ { true, 0xb578, 0xb578 }, +/* 0xb579 */ { true, 0xb579, 0xb579 }, +/* 0xb57a */ { true, 0xb57a, 0xb57a }, +/* 0xb57b */ { true, 0xb57b, 0xb57b }, +/* 0xb57c */ { true, 0xb57c, 0xb57c }, +/* 0xb57d */ { true, 0xb57d, 0xb57d }, +/* 0xb57e */ { true, 0xb57e, 0xb57e }, +/* 0xb57f */ { true, 0xb57f, 0xb57f }, +/* 0xb580 */ { true, 0xb580, 0xb580 }, +/* 0xb581 */ { true, 0xb581, 0xb581 }, +/* 0xb582 */ { true, 0xb582, 0xb582 }, +/* 0xb583 */ { true, 0xb583, 0xb583 }, +/* 0xb584 */ { true, 0xb584, 0xb584 }, +/* 0xb585 */ { true, 0xb585, 0xb585 }, +/* 0xb586 */ { true, 0xb586, 0xb586 }, +/* 0xb587 */ { true, 0xb587, 0xb587 }, +/* 0xb588 */ { true, 0xb588, 0xb588 }, +/* 0xb589 */ { true, 0xb589, 0xb589 }, +/* 0xb58a */ { true, 0xb58a, 0xb58a }, +/* 0xb58b */ { true, 0xb58b, 0xb58b }, +/* 0xb58c */ { true, 0xb58c, 0xb58c }, +/* 0xb58d */ { true, 0xb58d, 0xb58d }, +/* 0xb58e */ { true, 0xb58e, 0xb58e }, +/* 0xb58f */ { true, 0xb58f, 0xb58f }, +/* 0xb590 */ { true, 0xb590, 0xb590 }, +/* 0xb591 */ { true, 0xb591, 0xb591 }, +/* 0xb592 */ { true, 0xb592, 0xb592 }, +/* 0xb593 */ { true, 0xb593, 0xb593 }, +/* 0xb594 */ { true, 0xb594, 0xb594 }, +/* 0xb595 */ { true, 0xb595, 0xb595 }, +/* 0xb596 */ { true, 0xb596, 0xb596 }, +/* 0xb597 */ { true, 0xb597, 0xb597 }, +/* 0xb598 */ { true, 0xb598, 0xb598 }, +/* 0xb599 */ { true, 0xb599, 0xb599 }, +/* 0xb59a */ { true, 0xb59a, 0xb59a }, +/* 0xb59b */ { true, 0xb59b, 0xb59b }, +/* 0xb59c */ { true, 0xb59c, 0xb59c }, +/* 0xb59d */ { true, 0xb59d, 0xb59d }, +/* 0xb59e */ { true, 0xb59e, 0xb59e }, +/* 0xb59f */ { true, 0xb59f, 0xb59f }, +/* 0xb5a0 */ { true, 0xb5a0, 0xb5a0 }, +/* 0xb5a1 */ { true, 0xb5a1, 0xb5a1 }, +/* 0xb5a2 */ { true, 0xb5a2, 0xb5a2 }, +/* 0xb5a3 */ { true, 0xb5a3, 0xb5a3 }, +/* 0xb5a4 */ { true, 0xb5a4, 0xb5a4 }, +/* 0xb5a5 */ { true, 0xb5a5, 0xb5a5 }, +/* 0xb5a6 */ { true, 0xb5a6, 0xb5a6 }, +/* 0xb5a7 */ { true, 0xb5a7, 0xb5a7 }, +/* 0xb5a8 */ { true, 0xb5a8, 0xb5a8 }, +/* 0xb5a9 */ { true, 0xb5a9, 0xb5a9 }, +/* 0xb5aa */ { true, 0xb5aa, 0xb5aa }, +/* 0xb5ab */ { true, 0xb5ab, 0xb5ab }, +/* 0xb5ac */ { true, 0xb5ac, 0xb5ac }, +/* 0xb5ad */ { true, 0xb5ad, 0xb5ad }, +/* 0xb5ae */ { true, 0xb5ae, 0xb5ae }, +/* 0xb5af */ { true, 0xb5af, 0xb5af }, +/* 0xb5b0 */ { true, 0xb5b0, 0xb5b0 }, +/* 0xb5b1 */ { true, 0xb5b1, 0xb5b1 }, +/* 0xb5b2 */ { true, 0xb5b2, 0xb5b2 }, +/* 0xb5b3 */ { true, 0xb5b3, 0xb5b3 }, +/* 0xb5b4 */ { true, 0xb5b4, 0xb5b4 }, +/* 0xb5b5 */ { true, 0xb5b5, 0xb5b5 }, +/* 0xb5b6 */ { true, 0xb5b6, 0xb5b6 }, +/* 0xb5b7 */ { true, 0xb5b7, 0xb5b7 }, +/* 0xb5b8 */ { true, 0xb5b8, 0xb5b8 }, +/* 0xb5b9 */ { true, 0xb5b9, 0xb5b9 }, +/* 0xb5ba */ { true, 0xb5ba, 0xb5ba }, +/* 0xb5bb */ { true, 0xb5bb, 0xb5bb }, +/* 0xb5bc */ { true, 0xb5bc, 0xb5bc }, +/* 0xb5bd */ { true, 0xb5bd, 0xb5bd }, +/* 0xb5be */ { true, 0xb5be, 0xb5be }, +/* 0xb5bf */ { true, 0xb5bf, 0xb5bf }, +/* 0xb5c0 */ { true, 0xb5c0, 0xb5c0 }, +/* 0xb5c1 */ { true, 0xb5c1, 0xb5c1 }, +/* 0xb5c2 */ { true, 0xb5c2, 0xb5c2 }, +/* 0xb5c3 */ { true, 0xb5c3, 0xb5c3 }, +/* 0xb5c4 */ { true, 0xb5c4, 0xb5c4 }, +/* 0xb5c5 */ { true, 0xb5c5, 0xb5c5 }, +/* 0xb5c6 */ { true, 0xb5c6, 0xb5c6 }, +/* 0xb5c7 */ { true, 0xb5c7, 0xb5c7 }, +/* 0xb5c8 */ { true, 0xb5c8, 0xb5c8 }, +/* 0xb5c9 */ { true, 0xb5c9, 0xb5c9 }, +/* 0xb5ca */ { true, 0xb5ca, 0xb5ca }, +/* 0xb5cb */ { true, 0xb5cb, 0xb5cb }, +/* 0xb5cc */ { true, 0xb5cc, 0xb5cc }, +/* 0xb5cd */ { true, 0xb5cd, 0xb5cd }, +/* 0xb5ce */ { true, 0xb5ce, 0xb5ce }, +/* 0xb5cf */ { true, 0xb5cf, 0xb5cf }, +/* 0xb5d0 */ { true, 0xb5d0, 0xb5d0 }, +/* 0xb5d1 */ { true, 0xb5d1, 0xb5d1 }, +/* 0xb5d2 */ { true, 0xb5d2, 0xb5d2 }, +/* 0xb5d3 */ { true, 0xb5d3, 0xb5d3 }, +/* 0xb5d4 */ { true, 0xb5d4, 0xb5d4 }, +/* 0xb5d5 */ { true, 0xb5d5, 0xb5d5 }, +/* 0xb5d6 */ { true, 0xb5d6, 0xb5d6 }, +/* 0xb5d7 */ { true, 0xb5d7, 0xb5d7 }, +/* 0xb5d8 */ { true, 0xb5d8, 0xb5d8 }, +/* 0xb5d9 */ { true, 0xb5d9, 0xb5d9 }, +/* 0xb5da */ { true, 0xb5da, 0xb5da }, +/* 0xb5db */ { true, 0xb5db, 0xb5db }, +/* 0xb5dc */ { true, 0xb5dc, 0xb5dc }, +/* 0xb5dd */ { true, 0xb5dd, 0xb5dd }, +/* 0xb5de */ { true, 0xb5de, 0xb5de }, +/* 0xb5df */ { true, 0xb5df, 0xb5df }, +/* 0xb5e0 */ { true, 0xb5e0, 0xb5e0 }, +/* 0xb5e1 */ { true, 0xb5e1, 0xb5e1 }, +/* 0xb5e2 */ { true, 0xb5e2, 0xb5e2 }, +/* 0xb5e3 */ { true, 0xb5e3, 0xb5e3 }, +/* 0xb5e4 */ { true, 0xb5e4, 0xb5e4 }, +/* 0xb5e5 */ { true, 0xb5e5, 0xb5e5 }, +/* 0xb5e6 */ { true, 0xb5e6, 0xb5e6 }, +/* 0xb5e7 */ { true, 0xb5e7, 0xb5e7 }, +/* 0xb5e8 */ { true, 0xb5e8, 0xb5e8 }, +/* 0xb5e9 */ { true, 0xb5e9, 0xb5e9 }, +/* 0xb5ea */ { true, 0xb5ea, 0xb5ea }, +/* 0xb5eb */ { true, 0xb5eb, 0xb5eb }, +/* 0xb5ec */ { true, 0xb5ec, 0xb5ec }, +/* 0xb5ed */ { true, 0xb5ed, 0xb5ed }, +/* 0xb5ee */ { true, 0xb5ee, 0xb5ee }, +/* 0xb5ef */ { true, 0xb5ef, 0xb5ef }, +/* 0xb5f0 */ { true, 0xb5f0, 0xb5f0 }, +/* 0xb5f1 */ { true, 0xb5f1, 0xb5f1 }, +/* 0xb5f2 */ { true, 0xb5f2, 0xb5f2 }, +/* 0xb5f3 */ { true, 0xb5f3, 0xb5f3 }, +/* 0xb5f4 */ { true, 0xb5f4, 0xb5f4 }, +/* 0xb5f5 */ { true, 0xb5f5, 0xb5f5 }, +/* 0xb5f6 */ { true, 0xb5f6, 0xb5f6 }, +/* 0xb5f7 */ { true, 0xb5f7, 0xb5f7 }, +/* 0xb5f8 */ { true, 0xb5f8, 0xb5f8 }, +/* 0xb5f9 */ { true, 0xb5f9, 0xb5f9 }, +/* 0xb5fa */ { true, 0xb5fa, 0xb5fa }, +/* 0xb5fb */ { true, 0xb5fb, 0xb5fb }, +/* 0xb5fc */ { true, 0xb5fc, 0xb5fc }, +/* 0xb5fd */ { true, 0xb5fd, 0xb5fd }, +/* 0xb5fe */ { true, 0xb5fe, 0xb5fe }, +/* 0xb5ff */ { true, 0xb5ff, 0xb5ff }, +/* 0xb600 */ { true, 0xb600, 0xb600 }, +/* 0xb601 */ { true, 0xb601, 0xb601 }, +/* 0xb602 */ { true, 0xb602, 0xb602 }, +/* 0xb603 */ { true, 0xb603, 0xb603 }, +/* 0xb604 */ { true, 0xb604, 0xb604 }, +/* 0xb605 */ { true, 0xb605, 0xb605 }, +/* 0xb606 */ { true, 0xb606, 0xb606 }, +/* 0xb607 */ { true, 0xb607, 0xb607 }, +/* 0xb608 */ { true, 0xb608, 0xb608 }, +/* 0xb609 */ { true, 0xb609, 0xb609 }, +/* 0xb60a */ { true, 0xb60a, 0xb60a }, +/* 0xb60b */ { true, 0xb60b, 0xb60b }, +/* 0xb60c */ { true, 0xb60c, 0xb60c }, +/* 0xb60d */ { true, 0xb60d, 0xb60d }, +/* 0xb60e */ { true, 0xb60e, 0xb60e }, +/* 0xb60f */ { true, 0xb60f, 0xb60f }, +/* 0xb610 */ { true, 0xb610, 0xb610 }, +/* 0xb611 */ { true, 0xb611, 0xb611 }, +/* 0xb612 */ { true, 0xb612, 0xb612 }, +/* 0xb613 */ { true, 0xb613, 0xb613 }, +/* 0xb614 */ { true, 0xb614, 0xb614 }, +/* 0xb615 */ { true, 0xb615, 0xb615 }, +/* 0xb616 */ { true, 0xb616, 0xb616 }, +/* 0xb617 */ { true, 0xb617, 0xb617 }, +/* 0xb618 */ { true, 0xb618, 0xb618 }, +/* 0xb619 */ { true, 0xb619, 0xb619 }, +/* 0xb61a */ { true, 0xb61a, 0xb61a }, +/* 0xb61b */ { true, 0xb61b, 0xb61b }, +/* 0xb61c */ { true, 0xb61c, 0xb61c }, +/* 0xb61d */ { true, 0xb61d, 0xb61d }, +/* 0xb61e */ { true, 0xb61e, 0xb61e }, +/* 0xb61f */ { true, 0xb61f, 0xb61f }, +/* 0xb620 */ { true, 0xb620, 0xb620 }, +/* 0xb621 */ { true, 0xb621, 0xb621 }, +/* 0xb622 */ { true, 0xb622, 0xb622 }, +/* 0xb623 */ { true, 0xb623, 0xb623 }, +/* 0xb624 */ { true, 0xb624, 0xb624 }, +/* 0xb625 */ { true, 0xb625, 0xb625 }, +/* 0xb626 */ { true, 0xb626, 0xb626 }, +/* 0xb627 */ { true, 0xb627, 0xb627 }, +/* 0xb628 */ { true, 0xb628, 0xb628 }, +/* 0xb629 */ { true, 0xb629, 0xb629 }, +/* 0xb62a */ { true, 0xb62a, 0xb62a }, +/* 0xb62b */ { true, 0xb62b, 0xb62b }, +/* 0xb62c */ { true, 0xb62c, 0xb62c }, +/* 0xb62d */ { true, 0xb62d, 0xb62d }, +/* 0xb62e */ { true, 0xb62e, 0xb62e }, +/* 0xb62f */ { true, 0xb62f, 0xb62f }, +/* 0xb630 */ { true, 0xb630, 0xb630 }, +/* 0xb631 */ { true, 0xb631, 0xb631 }, +/* 0xb632 */ { true, 0xb632, 0xb632 }, +/* 0xb633 */ { true, 0xb633, 0xb633 }, +/* 0xb634 */ { true, 0xb634, 0xb634 }, +/* 0xb635 */ { true, 0xb635, 0xb635 }, +/* 0xb636 */ { true, 0xb636, 0xb636 }, +/* 0xb637 */ { true, 0xb637, 0xb637 }, +/* 0xb638 */ { true, 0xb638, 0xb638 }, +/* 0xb639 */ { true, 0xb639, 0xb639 }, +/* 0xb63a */ { true, 0xb63a, 0xb63a }, +/* 0xb63b */ { true, 0xb63b, 0xb63b }, +/* 0xb63c */ { true, 0xb63c, 0xb63c }, +/* 0xb63d */ { true, 0xb63d, 0xb63d }, +/* 0xb63e */ { true, 0xb63e, 0xb63e }, +/* 0xb63f */ { true, 0xb63f, 0xb63f }, +/* 0xb640 */ { true, 0xb640, 0xb640 }, +/* 0xb641 */ { true, 0xb641, 0xb641 }, +/* 0xb642 */ { true, 0xb642, 0xb642 }, +/* 0xb643 */ { true, 0xb643, 0xb643 }, +/* 0xb644 */ { true, 0xb644, 0xb644 }, +/* 0xb645 */ { true, 0xb645, 0xb645 }, +/* 0xb646 */ { true, 0xb646, 0xb646 }, +/* 0xb647 */ { true, 0xb647, 0xb647 }, +/* 0xb648 */ { true, 0xb648, 0xb648 }, +/* 0xb649 */ { true, 0xb649, 0xb649 }, +/* 0xb64a */ { true, 0xb64a, 0xb64a }, +/* 0xb64b */ { true, 0xb64b, 0xb64b }, +/* 0xb64c */ { true, 0xb64c, 0xb64c }, +/* 0xb64d */ { true, 0xb64d, 0xb64d }, +/* 0xb64e */ { true, 0xb64e, 0xb64e }, +/* 0xb64f */ { true, 0xb64f, 0xb64f }, +/* 0xb650 */ { true, 0xb650, 0xb650 }, +/* 0xb651 */ { true, 0xb651, 0xb651 }, +/* 0xb652 */ { true, 0xb652, 0xb652 }, +/* 0xb653 */ { true, 0xb653, 0xb653 }, +/* 0xb654 */ { true, 0xb654, 0xb654 }, +/* 0xb655 */ { true, 0xb655, 0xb655 }, +/* 0xb656 */ { true, 0xb656, 0xb656 }, +/* 0xb657 */ { true, 0xb657, 0xb657 }, +/* 0xb658 */ { true, 0xb658, 0xb658 }, +/* 0xb659 */ { true, 0xb659, 0xb659 }, +/* 0xb65a */ { true, 0xb65a, 0xb65a }, +/* 0xb65b */ { true, 0xb65b, 0xb65b }, +/* 0xb65c */ { true, 0xb65c, 0xb65c }, +/* 0xb65d */ { true, 0xb65d, 0xb65d }, +/* 0xb65e */ { true, 0xb65e, 0xb65e }, +/* 0xb65f */ { true, 0xb65f, 0xb65f }, +/* 0xb660 */ { true, 0xb660, 0xb660 }, +/* 0xb661 */ { true, 0xb661, 0xb661 }, +/* 0xb662 */ { true, 0xb662, 0xb662 }, +/* 0xb663 */ { true, 0xb663, 0xb663 }, +/* 0xb664 */ { true, 0xb664, 0xb664 }, +/* 0xb665 */ { true, 0xb665, 0xb665 }, +/* 0xb666 */ { true, 0xb666, 0xb666 }, +/* 0xb667 */ { true, 0xb667, 0xb667 }, +/* 0xb668 */ { true, 0xb668, 0xb668 }, +/* 0xb669 */ { true, 0xb669, 0xb669 }, +/* 0xb66a */ { true, 0xb66a, 0xb66a }, +/* 0xb66b */ { true, 0xb66b, 0xb66b }, +/* 0xb66c */ { true, 0xb66c, 0xb66c }, +/* 0xb66d */ { true, 0xb66d, 0xb66d }, +/* 0xb66e */ { true, 0xb66e, 0xb66e }, +/* 0xb66f */ { true, 0xb66f, 0xb66f }, +/* 0xb670 */ { true, 0xb670, 0xb670 }, +/* 0xb671 */ { true, 0xb671, 0xb671 }, +/* 0xb672 */ { true, 0xb672, 0xb672 }, +/* 0xb673 */ { true, 0xb673, 0xb673 }, +/* 0xb674 */ { true, 0xb674, 0xb674 }, +/* 0xb675 */ { true, 0xb675, 0xb675 }, +/* 0xb676 */ { true, 0xb676, 0xb676 }, +/* 0xb677 */ { true, 0xb677, 0xb677 }, +/* 0xb678 */ { true, 0xb678, 0xb678 }, +/* 0xb679 */ { true, 0xb679, 0xb679 }, +/* 0xb67a */ { true, 0xb67a, 0xb67a }, +/* 0xb67b */ { true, 0xb67b, 0xb67b }, +/* 0xb67c */ { true, 0xb67c, 0xb67c }, +/* 0xb67d */ { true, 0xb67d, 0xb67d }, +/* 0xb67e */ { true, 0xb67e, 0xb67e }, +/* 0xb67f */ { true, 0xb67f, 0xb67f }, +/* 0xb680 */ { true, 0xb680, 0xb680 }, +/* 0xb681 */ { true, 0xb681, 0xb681 }, +/* 0xb682 */ { true, 0xb682, 0xb682 }, +/* 0xb683 */ { true, 0xb683, 0xb683 }, +/* 0xb684 */ { true, 0xb684, 0xb684 }, +/* 0xb685 */ { true, 0xb685, 0xb685 }, +/* 0xb686 */ { true, 0xb686, 0xb686 }, +/* 0xb687 */ { true, 0xb687, 0xb687 }, +/* 0xb688 */ { true, 0xb688, 0xb688 }, +/* 0xb689 */ { true, 0xb689, 0xb689 }, +/* 0xb68a */ { true, 0xb68a, 0xb68a }, +/* 0xb68b */ { true, 0xb68b, 0xb68b }, +/* 0xb68c */ { true, 0xb68c, 0xb68c }, +/* 0xb68d */ { true, 0xb68d, 0xb68d }, +/* 0xb68e */ { true, 0xb68e, 0xb68e }, +/* 0xb68f */ { true, 0xb68f, 0xb68f }, +/* 0xb690 */ { true, 0xb690, 0xb690 }, +/* 0xb691 */ { true, 0xb691, 0xb691 }, +/* 0xb692 */ { true, 0xb692, 0xb692 }, +/* 0xb693 */ { true, 0xb693, 0xb693 }, +/* 0xb694 */ { true, 0xb694, 0xb694 }, +/* 0xb695 */ { true, 0xb695, 0xb695 }, +/* 0xb696 */ { true, 0xb696, 0xb696 }, +/* 0xb697 */ { true, 0xb697, 0xb697 }, +/* 0xb698 */ { true, 0xb698, 0xb698 }, +/* 0xb699 */ { true, 0xb699, 0xb699 }, +/* 0xb69a */ { true, 0xb69a, 0xb69a }, +/* 0xb69b */ { true, 0xb69b, 0xb69b }, +/* 0xb69c */ { true, 0xb69c, 0xb69c }, +/* 0xb69d */ { true, 0xb69d, 0xb69d }, +/* 0xb69e */ { true, 0xb69e, 0xb69e }, +/* 0xb69f */ { true, 0xb69f, 0xb69f }, +/* 0xb6a0 */ { true, 0xb6a0, 0xb6a0 }, +/* 0xb6a1 */ { true, 0xb6a1, 0xb6a1 }, +/* 0xb6a2 */ { true, 0xb6a2, 0xb6a2 }, +/* 0xb6a3 */ { true, 0xb6a3, 0xb6a3 }, +/* 0xb6a4 */ { true, 0xb6a4, 0xb6a4 }, +/* 0xb6a5 */ { true, 0xb6a5, 0xb6a5 }, +/* 0xb6a6 */ { true, 0xb6a6, 0xb6a6 }, +/* 0xb6a7 */ { true, 0xb6a7, 0xb6a7 }, +/* 0xb6a8 */ { true, 0xb6a8, 0xb6a8 }, +/* 0xb6a9 */ { true, 0xb6a9, 0xb6a9 }, +/* 0xb6aa */ { true, 0xb6aa, 0xb6aa }, +/* 0xb6ab */ { true, 0xb6ab, 0xb6ab }, +/* 0xb6ac */ { true, 0xb6ac, 0xb6ac }, +/* 0xb6ad */ { true, 0xb6ad, 0xb6ad }, +/* 0xb6ae */ { true, 0xb6ae, 0xb6ae }, +/* 0xb6af */ { true, 0xb6af, 0xb6af }, +/* 0xb6b0 */ { true, 0xb6b0, 0xb6b0 }, +/* 0xb6b1 */ { true, 0xb6b1, 0xb6b1 }, +/* 0xb6b2 */ { true, 0xb6b2, 0xb6b2 }, +/* 0xb6b3 */ { true, 0xb6b3, 0xb6b3 }, +/* 0xb6b4 */ { true, 0xb6b4, 0xb6b4 }, +/* 0xb6b5 */ { true, 0xb6b5, 0xb6b5 }, +/* 0xb6b6 */ { true, 0xb6b6, 0xb6b6 }, +/* 0xb6b7 */ { true, 0xb6b7, 0xb6b7 }, +/* 0xb6b8 */ { true, 0xb6b8, 0xb6b8 }, +/* 0xb6b9 */ { true, 0xb6b9, 0xb6b9 }, +/* 0xb6ba */ { true, 0xb6ba, 0xb6ba }, +/* 0xb6bb */ { true, 0xb6bb, 0xb6bb }, +/* 0xb6bc */ { true, 0xb6bc, 0xb6bc }, +/* 0xb6bd */ { true, 0xb6bd, 0xb6bd }, +/* 0xb6be */ { true, 0xb6be, 0xb6be }, +/* 0xb6bf */ { true, 0xb6bf, 0xb6bf }, +/* 0xb6c0 */ { true, 0xb6c0, 0xb6c0 }, +/* 0xb6c1 */ { true, 0xb6c1, 0xb6c1 }, +/* 0xb6c2 */ { true, 0xb6c2, 0xb6c2 }, +/* 0xb6c3 */ { true, 0xb6c3, 0xb6c3 }, +/* 0xb6c4 */ { true, 0xb6c4, 0xb6c4 }, +/* 0xb6c5 */ { true, 0xb6c5, 0xb6c5 }, +/* 0xb6c6 */ { true, 0xb6c6, 0xb6c6 }, +/* 0xb6c7 */ { true, 0xb6c7, 0xb6c7 }, +/* 0xb6c8 */ { true, 0xb6c8, 0xb6c8 }, +/* 0xb6c9 */ { true, 0xb6c9, 0xb6c9 }, +/* 0xb6ca */ { true, 0xb6ca, 0xb6ca }, +/* 0xb6cb */ { true, 0xb6cb, 0xb6cb }, +/* 0xb6cc */ { true, 0xb6cc, 0xb6cc }, +/* 0xb6cd */ { true, 0xb6cd, 0xb6cd }, +/* 0xb6ce */ { true, 0xb6ce, 0xb6ce }, +/* 0xb6cf */ { true, 0xb6cf, 0xb6cf }, +/* 0xb6d0 */ { true, 0xb6d0, 0xb6d0 }, +/* 0xb6d1 */ { true, 0xb6d1, 0xb6d1 }, +/* 0xb6d2 */ { true, 0xb6d2, 0xb6d2 }, +/* 0xb6d3 */ { true, 0xb6d3, 0xb6d3 }, +/* 0xb6d4 */ { true, 0xb6d4, 0xb6d4 }, +/* 0xb6d5 */ { true, 0xb6d5, 0xb6d5 }, +/* 0xb6d6 */ { true, 0xb6d6, 0xb6d6 }, +/* 0xb6d7 */ { true, 0xb6d7, 0xb6d7 }, +/* 0xb6d8 */ { true, 0xb6d8, 0xb6d8 }, +/* 0xb6d9 */ { true, 0xb6d9, 0xb6d9 }, +/* 0xb6da */ { true, 0xb6da, 0xb6da }, +/* 0xb6db */ { true, 0xb6db, 0xb6db }, +/* 0xb6dc */ { true, 0xb6dc, 0xb6dc }, +/* 0xb6dd */ { true, 0xb6dd, 0xb6dd }, +/* 0xb6de */ { true, 0xb6de, 0xb6de }, +/* 0xb6df */ { true, 0xb6df, 0xb6df }, +/* 0xb6e0 */ { true, 0xb6e0, 0xb6e0 }, +/* 0xb6e1 */ { true, 0xb6e1, 0xb6e1 }, +/* 0xb6e2 */ { true, 0xb6e2, 0xb6e2 }, +/* 0xb6e3 */ { true, 0xb6e3, 0xb6e3 }, +/* 0xb6e4 */ { true, 0xb6e4, 0xb6e4 }, +/* 0xb6e5 */ { true, 0xb6e5, 0xb6e5 }, +/* 0xb6e6 */ { true, 0xb6e6, 0xb6e6 }, +/* 0xb6e7 */ { true, 0xb6e7, 0xb6e7 }, +/* 0xb6e8 */ { true, 0xb6e8, 0xb6e8 }, +/* 0xb6e9 */ { true, 0xb6e9, 0xb6e9 }, +/* 0xb6ea */ { true, 0xb6ea, 0xb6ea }, +/* 0xb6eb */ { true, 0xb6eb, 0xb6eb }, +/* 0xb6ec */ { true, 0xb6ec, 0xb6ec }, +/* 0xb6ed */ { true, 0xb6ed, 0xb6ed }, +/* 0xb6ee */ { true, 0xb6ee, 0xb6ee }, +/* 0xb6ef */ { true, 0xb6ef, 0xb6ef }, +/* 0xb6f0 */ { true, 0xb6f0, 0xb6f0 }, +/* 0xb6f1 */ { true, 0xb6f1, 0xb6f1 }, +/* 0xb6f2 */ { true, 0xb6f2, 0xb6f2 }, +/* 0xb6f3 */ { true, 0xb6f3, 0xb6f3 }, +/* 0xb6f4 */ { true, 0xb6f4, 0xb6f4 }, +/* 0xb6f5 */ { true, 0xb6f5, 0xb6f5 }, +/* 0xb6f6 */ { true, 0xb6f6, 0xb6f6 }, +/* 0xb6f7 */ { true, 0xb6f7, 0xb6f7 }, +/* 0xb6f8 */ { true, 0xb6f8, 0xb6f8 }, +/* 0xb6f9 */ { true, 0xb6f9, 0xb6f9 }, +/* 0xb6fa */ { true, 0xb6fa, 0xb6fa }, +/* 0xb6fb */ { true, 0xb6fb, 0xb6fb }, +/* 0xb6fc */ { true, 0xb6fc, 0xb6fc }, +/* 0xb6fd */ { true, 0xb6fd, 0xb6fd }, +/* 0xb6fe */ { true, 0xb6fe, 0xb6fe }, +/* 0xb6ff */ { true, 0xb6ff, 0xb6ff }, +/* 0xb700 */ { true, 0xb700, 0xb700 }, +/* 0xb701 */ { true, 0xb701, 0xb701 }, +/* 0xb702 */ { true, 0xb702, 0xb702 }, +/* 0xb703 */ { true, 0xb703, 0xb703 }, +/* 0xb704 */ { true, 0xb704, 0xb704 }, +/* 0xb705 */ { true, 0xb705, 0xb705 }, +/* 0xb706 */ { true, 0xb706, 0xb706 }, +/* 0xb707 */ { true, 0xb707, 0xb707 }, +/* 0xb708 */ { true, 0xb708, 0xb708 }, +/* 0xb709 */ { true, 0xb709, 0xb709 }, +/* 0xb70a */ { true, 0xb70a, 0xb70a }, +/* 0xb70b */ { true, 0xb70b, 0xb70b }, +/* 0xb70c */ { true, 0xb70c, 0xb70c }, +/* 0xb70d */ { true, 0xb70d, 0xb70d }, +/* 0xb70e */ { true, 0xb70e, 0xb70e }, +/* 0xb70f */ { true, 0xb70f, 0xb70f }, +/* 0xb710 */ { true, 0xb710, 0xb710 }, +/* 0xb711 */ { true, 0xb711, 0xb711 }, +/* 0xb712 */ { true, 0xb712, 0xb712 }, +/* 0xb713 */ { true, 0xb713, 0xb713 }, +/* 0xb714 */ { true, 0xb714, 0xb714 }, +/* 0xb715 */ { true, 0xb715, 0xb715 }, +/* 0xb716 */ { true, 0xb716, 0xb716 }, +/* 0xb717 */ { true, 0xb717, 0xb717 }, +/* 0xb718 */ { true, 0xb718, 0xb718 }, +/* 0xb719 */ { true, 0xb719, 0xb719 }, +/* 0xb71a */ { true, 0xb71a, 0xb71a }, +/* 0xb71b */ { true, 0xb71b, 0xb71b }, +/* 0xb71c */ { true, 0xb71c, 0xb71c }, +/* 0xb71d */ { true, 0xb71d, 0xb71d }, +/* 0xb71e */ { true, 0xb71e, 0xb71e }, +/* 0xb71f */ { true, 0xb71f, 0xb71f }, +/* 0xb720 */ { true, 0xb720, 0xb720 }, +/* 0xb721 */ { true, 0xb721, 0xb721 }, +/* 0xb722 */ { true, 0xb722, 0xb722 }, +/* 0xb723 */ { true, 0xb723, 0xb723 }, +/* 0xb724 */ { true, 0xb724, 0xb724 }, +/* 0xb725 */ { true, 0xb725, 0xb725 }, +/* 0xb726 */ { true, 0xb726, 0xb726 }, +/* 0xb727 */ { true, 0xb727, 0xb727 }, +/* 0xb728 */ { true, 0xb728, 0xb728 }, +/* 0xb729 */ { true, 0xb729, 0xb729 }, +/* 0xb72a */ { true, 0xb72a, 0xb72a }, +/* 0xb72b */ { true, 0xb72b, 0xb72b }, +/* 0xb72c */ { true, 0xb72c, 0xb72c }, +/* 0xb72d */ { true, 0xb72d, 0xb72d }, +/* 0xb72e */ { true, 0xb72e, 0xb72e }, +/* 0xb72f */ { true, 0xb72f, 0xb72f }, +/* 0xb730 */ { true, 0xb730, 0xb730 }, +/* 0xb731 */ { true, 0xb731, 0xb731 }, +/* 0xb732 */ { true, 0xb732, 0xb732 }, +/* 0xb733 */ { true, 0xb733, 0xb733 }, +/* 0xb734 */ { true, 0xb734, 0xb734 }, +/* 0xb735 */ { true, 0xb735, 0xb735 }, +/* 0xb736 */ { true, 0xb736, 0xb736 }, +/* 0xb737 */ { true, 0xb737, 0xb737 }, +/* 0xb738 */ { true, 0xb738, 0xb738 }, +/* 0xb739 */ { true, 0xb739, 0xb739 }, +/* 0xb73a */ { true, 0xb73a, 0xb73a }, +/* 0xb73b */ { true, 0xb73b, 0xb73b }, +/* 0xb73c */ { true, 0xb73c, 0xb73c }, +/* 0xb73d */ { true, 0xb73d, 0xb73d }, +/* 0xb73e */ { true, 0xb73e, 0xb73e }, +/* 0xb73f */ { true, 0xb73f, 0xb73f }, +/* 0xb740 */ { true, 0xb740, 0xb740 }, +/* 0xb741 */ { true, 0xb741, 0xb741 }, +/* 0xb742 */ { true, 0xb742, 0xb742 }, +/* 0xb743 */ { true, 0xb743, 0xb743 }, +/* 0xb744 */ { true, 0xb744, 0xb744 }, +/* 0xb745 */ { true, 0xb745, 0xb745 }, +/* 0xb746 */ { true, 0xb746, 0xb746 }, +/* 0xb747 */ { true, 0xb747, 0xb747 }, +/* 0xb748 */ { true, 0xb748, 0xb748 }, +/* 0xb749 */ { true, 0xb749, 0xb749 }, +/* 0xb74a */ { true, 0xb74a, 0xb74a }, +/* 0xb74b */ { true, 0xb74b, 0xb74b }, +/* 0xb74c */ { true, 0xb74c, 0xb74c }, +/* 0xb74d */ { true, 0xb74d, 0xb74d }, +/* 0xb74e */ { true, 0xb74e, 0xb74e }, +/* 0xb74f */ { true, 0xb74f, 0xb74f }, +/* 0xb750 */ { true, 0xb750, 0xb750 }, +/* 0xb751 */ { true, 0xb751, 0xb751 }, +/* 0xb752 */ { true, 0xb752, 0xb752 }, +/* 0xb753 */ { true, 0xb753, 0xb753 }, +/* 0xb754 */ { true, 0xb754, 0xb754 }, +/* 0xb755 */ { true, 0xb755, 0xb755 }, +/* 0xb756 */ { true, 0xb756, 0xb756 }, +/* 0xb757 */ { true, 0xb757, 0xb757 }, +/* 0xb758 */ { true, 0xb758, 0xb758 }, +/* 0xb759 */ { true, 0xb759, 0xb759 }, +/* 0xb75a */ { true, 0xb75a, 0xb75a }, +/* 0xb75b */ { true, 0xb75b, 0xb75b }, +/* 0xb75c */ { true, 0xb75c, 0xb75c }, +/* 0xb75d */ { true, 0xb75d, 0xb75d }, +/* 0xb75e */ { true, 0xb75e, 0xb75e }, +/* 0xb75f */ { true, 0xb75f, 0xb75f }, +/* 0xb760 */ { true, 0xb760, 0xb760 }, +/* 0xb761 */ { true, 0xb761, 0xb761 }, +/* 0xb762 */ { true, 0xb762, 0xb762 }, +/* 0xb763 */ { true, 0xb763, 0xb763 }, +/* 0xb764 */ { true, 0xb764, 0xb764 }, +/* 0xb765 */ { true, 0xb765, 0xb765 }, +/* 0xb766 */ { true, 0xb766, 0xb766 }, +/* 0xb767 */ { true, 0xb767, 0xb767 }, +/* 0xb768 */ { true, 0xb768, 0xb768 }, +/* 0xb769 */ { true, 0xb769, 0xb769 }, +/* 0xb76a */ { true, 0xb76a, 0xb76a }, +/* 0xb76b */ { true, 0xb76b, 0xb76b }, +/* 0xb76c */ { true, 0xb76c, 0xb76c }, +/* 0xb76d */ { true, 0xb76d, 0xb76d }, +/* 0xb76e */ { true, 0xb76e, 0xb76e }, +/* 0xb76f */ { true, 0xb76f, 0xb76f }, +/* 0xb770 */ { true, 0xb770, 0xb770 }, +/* 0xb771 */ { true, 0xb771, 0xb771 }, +/* 0xb772 */ { true, 0xb772, 0xb772 }, +/* 0xb773 */ { true, 0xb773, 0xb773 }, +/* 0xb774 */ { true, 0xb774, 0xb774 }, +/* 0xb775 */ { true, 0xb775, 0xb775 }, +/* 0xb776 */ { true, 0xb776, 0xb776 }, +/* 0xb777 */ { true, 0xb777, 0xb777 }, +/* 0xb778 */ { true, 0xb778, 0xb778 }, +/* 0xb779 */ { true, 0xb779, 0xb779 }, +/* 0xb77a */ { true, 0xb77a, 0xb77a }, +/* 0xb77b */ { true, 0xb77b, 0xb77b }, +/* 0xb77c */ { true, 0xb77c, 0xb77c }, +/* 0xb77d */ { true, 0xb77d, 0xb77d }, +/* 0xb77e */ { true, 0xb77e, 0xb77e }, +/* 0xb77f */ { true, 0xb77f, 0xb77f }, +/* 0xb780 */ { true, 0xb780, 0xb780 }, +/* 0xb781 */ { true, 0xb781, 0xb781 }, +/* 0xb782 */ { true, 0xb782, 0xb782 }, +/* 0xb783 */ { true, 0xb783, 0xb783 }, +/* 0xb784 */ { true, 0xb784, 0xb784 }, +/* 0xb785 */ { true, 0xb785, 0xb785 }, +/* 0xb786 */ { true, 0xb786, 0xb786 }, +/* 0xb787 */ { true, 0xb787, 0xb787 }, +/* 0xb788 */ { true, 0xb788, 0xb788 }, +/* 0xb789 */ { true, 0xb789, 0xb789 }, +/* 0xb78a */ { true, 0xb78a, 0xb78a }, +/* 0xb78b */ { true, 0xb78b, 0xb78b }, +/* 0xb78c */ { true, 0xb78c, 0xb78c }, +/* 0xb78d */ { true, 0xb78d, 0xb78d }, +/* 0xb78e */ { true, 0xb78e, 0xb78e }, +/* 0xb78f */ { true, 0xb78f, 0xb78f }, +/* 0xb790 */ { true, 0xb790, 0xb790 }, +/* 0xb791 */ { true, 0xb791, 0xb791 }, +/* 0xb792 */ { true, 0xb792, 0xb792 }, +/* 0xb793 */ { true, 0xb793, 0xb793 }, +/* 0xb794 */ { true, 0xb794, 0xb794 }, +/* 0xb795 */ { true, 0xb795, 0xb795 }, +/* 0xb796 */ { true, 0xb796, 0xb796 }, +/* 0xb797 */ { true, 0xb797, 0xb797 }, +/* 0xb798 */ { true, 0xb798, 0xb798 }, +/* 0xb799 */ { true, 0xb799, 0xb799 }, +/* 0xb79a */ { true, 0xb79a, 0xb79a }, +/* 0xb79b */ { true, 0xb79b, 0xb79b }, +/* 0xb79c */ { true, 0xb79c, 0xb79c }, +/* 0xb79d */ { true, 0xb79d, 0xb79d }, +/* 0xb79e */ { true, 0xb79e, 0xb79e }, +/* 0xb79f */ { true, 0xb79f, 0xb79f }, +/* 0xb7a0 */ { true, 0xb7a0, 0xb7a0 }, +/* 0xb7a1 */ { true, 0xb7a1, 0xb7a1 }, +/* 0xb7a2 */ { true, 0xb7a2, 0xb7a2 }, +/* 0xb7a3 */ { true, 0xb7a3, 0xb7a3 }, +/* 0xb7a4 */ { true, 0xb7a4, 0xb7a4 }, +/* 0xb7a5 */ { true, 0xb7a5, 0xb7a5 }, +/* 0xb7a6 */ { true, 0xb7a6, 0xb7a6 }, +/* 0xb7a7 */ { true, 0xb7a7, 0xb7a7 }, +/* 0xb7a8 */ { true, 0xb7a8, 0xb7a8 }, +/* 0xb7a9 */ { true, 0xb7a9, 0xb7a9 }, +/* 0xb7aa */ { true, 0xb7aa, 0xb7aa }, +/* 0xb7ab */ { true, 0xb7ab, 0xb7ab }, +/* 0xb7ac */ { true, 0xb7ac, 0xb7ac }, +/* 0xb7ad */ { true, 0xb7ad, 0xb7ad }, +/* 0xb7ae */ { true, 0xb7ae, 0xb7ae }, +/* 0xb7af */ { true, 0xb7af, 0xb7af }, +/* 0xb7b0 */ { true, 0xb7b0, 0xb7b0 }, +/* 0xb7b1 */ { true, 0xb7b1, 0xb7b1 }, +/* 0xb7b2 */ { true, 0xb7b2, 0xb7b2 }, +/* 0xb7b3 */ { true, 0xb7b3, 0xb7b3 }, +/* 0xb7b4 */ { true, 0xb7b4, 0xb7b4 }, +/* 0xb7b5 */ { true, 0xb7b5, 0xb7b5 }, +/* 0xb7b6 */ { true, 0xb7b6, 0xb7b6 }, +/* 0xb7b7 */ { true, 0xb7b7, 0xb7b7 }, +/* 0xb7b8 */ { true, 0xb7b8, 0xb7b8 }, +/* 0xb7b9 */ { true, 0xb7b9, 0xb7b9 }, +/* 0xb7ba */ { true, 0xb7ba, 0xb7ba }, +/* 0xb7bb */ { true, 0xb7bb, 0xb7bb }, +/* 0xb7bc */ { true, 0xb7bc, 0xb7bc }, +/* 0xb7bd */ { true, 0xb7bd, 0xb7bd }, +/* 0xb7be */ { true, 0xb7be, 0xb7be }, +/* 0xb7bf */ { true, 0xb7bf, 0xb7bf }, +/* 0xb7c0 */ { true, 0xb7c0, 0xb7c0 }, +/* 0xb7c1 */ { true, 0xb7c1, 0xb7c1 }, +/* 0xb7c2 */ { true, 0xb7c2, 0xb7c2 }, +/* 0xb7c3 */ { true, 0xb7c3, 0xb7c3 }, +/* 0xb7c4 */ { true, 0xb7c4, 0xb7c4 }, +/* 0xb7c5 */ { true, 0xb7c5, 0xb7c5 }, +/* 0xb7c6 */ { true, 0xb7c6, 0xb7c6 }, +/* 0xb7c7 */ { true, 0xb7c7, 0xb7c7 }, +/* 0xb7c8 */ { true, 0xb7c8, 0xb7c8 }, +/* 0xb7c9 */ { true, 0xb7c9, 0xb7c9 }, +/* 0xb7ca */ { true, 0xb7ca, 0xb7ca }, +/* 0xb7cb */ { true, 0xb7cb, 0xb7cb }, +/* 0xb7cc */ { true, 0xb7cc, 0xb7cc }, +/* 0xb7cd */ { true, 0xb7cd, 0xb7cd }, +/* 0xb7ce */ { true, 0xb7ce, 0xb7ce }, +/* 0xb7cf */ { true, 0xb7cf, 0xb7cf }, +/* 0xb7d0 */ { true, 0xb7d0, 0xb7d0 }, +/* 0xb7d1 */ { true, 0xb7d1, 0xb7d1 }, +/* 0xb7d2 */ { true, 0xb7d2, 0xb7d2 }, +/* 0xb7d3 */ { true, 0xb7d3, 0xb7d3 }, +/* 0xb7d4 */ { true, 0xb7d4, 0xb7d4 }, +/* 0xb7d5 */ { true, 0xb7d5, 0xb7d5 }, +/* 0xb7d6 */ { true, 0xb7d6, 0xb7d6 }, +/* 0xb7d7 */ { true, 0xb7d7, 0xb7d7 }, +/* 0xb7d8 */ { true, 0xb7d8, 0xb7d8 }, +/* 0xb7d9 */ { true, 0xb7d9, 0xb7d9 }, +/* 0xb7da */ { true, 0xb7da, 0xb7da }, +/* 0xb7db */ { true, 0xb7db, 0xb7db }, +/* 0xb7dc */ { true, 0xb7dc, 0xb7dc }, +/* 0xb7dd */ { true, 0xb7dd, 0xb7dd }, +/* 0xb7de */ { true, 0xb7de, 0xb7de }, +/* 0xb7df */ { true, 0xb7df, 0xb7df }, +/* 0xb7e0 */ { true, 0xb7e0, 0xb7e0 }, +/* 0xb7e1 */ { true, 0xb7e1, 0xb7e1 }, +/* 0xb7e2 */ { true, 0xb7e2, 0xb7e2 }, +/* 0xb7e3 */ { true, 0xb7e3, 0xb7e3 }, +/* 0xb7e4 */ { true, 0xb7e4, 0xb7e4 }, +/* 0xb7e5 */ { true, 0xb7e5, 0xb7e5 }, +/* 0xb7e6 */ { true, 0xb7e6, 0xb7e6 }, +/* 0xb7e7 */ { true, 0xb7e7, 0xb7e7 }, +/* 0xb7e8 */ { true, 0xb7e8, 0xb7e8 }, +/* 0xb7e9 */ { true, 0xb7e9, 0xb7e9 }, +/* 0xb7ea */ { true, 0xb7ea, 0xb7ea }, +/* 0xb7eb */ { true, 0xb7eb, 0xb7eb }, +/* 0xb7ec */ { true, 0xb7ec, 0xb7ec }, +/* 0xb7ed */ { true, 0xb7ed, 0xb7ed }, +/* 0xb7ee */ { true, 0xb7ee, 0xb7ee }, +/* 0xb7ef */ { true, 0xb7ef, 0xb7ef }, +/* 0xb7f0 */ { true, 0xb7f0, 0xb7f0 }, +/* 0xb7f1 */ { true, 0xb7f1, 0xb7f1 }, +/* 0xb7f2 */ { true, 0xb7f2, 0xb7f2 }, +/* 0xb7f3 */ { true, 0xb7f3, 0xb7f3 }, +/* 0xb7f4 */ { true, 0xb7f4, 0xb7f4 }, +/* 0xb7f5 */ { true, 0xb7f5, 0xb7f5 }, +/* 0xb7f6 */ { true, 0xb7f6, 0xb7f6 }, +/* 0xb7f7 */ { true, 0xb7f7, 0xb7f7 }, +/* 0xb7f8 */ { true, 0xb7f8, 0xb7f8 }, +/* 0xb7f9 */ { true, 0xb7f9, 0xb7f9 }, +/* 0xb7fa */ { true, 0xb7fa, 0xb7fa }, +/* 0xb7fb */ { true, 0xb7fb, 0xb7fb }, +/* 0xb7fc */ { true, 0xb7fc, 0xb7fc }, +/* 0xb7fd */ { true, 0xb7fd, 0xb7fd }, +/* 0xb7fe */ { true, 0xb7fe, 0xb7fe }, +/* 0xb7ff */ { true, 0xb7ff, 0xb7ff }, +/* 0xb800 */ { true, 0xb800, 0xb800 }, +/* 0xb801 */ { true, 0xb801, 0xb801 }, +/* 0xb802 */ { true, 0xb802, 0xb802 }, +/* 0xb803 */ { true, 0xb803, 0xb803 }, +/* 0xb804 */ { true, 0xb804, 0xb804 }, +/* 0xb805 */ { true, 0xb805, 0xb805 }, +/* 0xb806 */ { true, 0xb806, 0xb806 }, +/* 0xb807 */ { true, 0xb807, 0xb807 }, +/* 0xb808 */ { true, 0xb808, 0xb808 }, +/* 0xb809 */ { true, 0xb809, 0xb809 }, +/* 0xb80a */ { true, 0xb80a, 0xb80a }, +/* 0xb80b */ { true, 0xb80b, 0xb80b }, +/* 0xb80c */ { true, 0xb80c, 0xb80c }, +/* 0xb80d */ { true, 0xb80d, 0xb80d }, +/* 0xb80e */ { true, 0xb80e, 0xb80e }, +/* 0xb80f */ { true, 0xb80f, 0xb80f }, +/* 0xb810 */ { true, 0xb810, 0xb810 }, +/* 0xb811 */ { true, 0xb811, 0xb811 }, +/* 0xb812 */ { true, 0xb812, 0xb812 }, +/* 0xb813 */ { true, 0xb813, 0xb813 }, +/* 0xb814 */ { true, 0xb814, 0xb814 }, +/* 0xb815 */ { true, 0xb815, 0xb815 }, +/* 0xb816 */ { true, 0xb816, 0xb816 }, +/* 0xb817 */ { true, 0xb817, 0xb817 }, +/* 0xb818 */ { true, 0xb818, 0xb818 }, +/* 0xb819 */ { true, 0xb819, 0xb819 }, +/* 0xb81a */ { true, 0xb81a, 0xb81a }, +/* 0xb81b */ { true, 0xb81b, 0xb81b }, +/* 0xb81c */ { true, 0xb81c, 0xb81c }, +/* 0xb81d */ { true, 0xb81d, 0xb81d }, +/* 0xb81e */ { true, 0xb81e, 0xb81e }, +/* 0xb81f */ { true, 0xb81f, 0xb81f }, +/* 0xb820 */ { true, 0xb820, 0xb820 }, +/* 0xb821 */ { true, 0xb821, 0xb821 }, +/* 0xb822 */ { true, 0xb822, 0xb822 }, +/* 0xb823 */ { true, 0xb823, 0xb823 }, +/* 0xb824 */ { true, 0xb824, 0xb824 }, +/* 0xb825 */ { true, 0xb825, 0xb825 }, +/* 0xb826 */ { true, 0xb826, 0xb826 }, +/* 0xb827 */ { true, 0xb827, 0xb827 }, +/* 0xb828 */ { true, 0xb828, 0xb828 }, +/* 0xb829 */ { true, 0xb829, 0xb829 }, +/* 0xb82a */ { true, 0xb82a, 0xb82a }, +/* 0xb82b */ { true, 0xb82b, 0xb82b }, +/* 0xb82c */ { true, 0xb82c, 0xb82c }, +/* 0xb82d */ { true, 0xb82d, 0xb82d }, +/* 0xb82e */ { true, 0xb82e, 0xb82e }, +/* 0xb82f */ { true, 0xb82f, 0xb82f }, +/* 0xb830 */ { true, 0xb830, 0xb830 }, +/* 0xb831 */ { true, 0xb831, 0xb831 }, +/* 0xb832 */ { true, 0xb832, 0xb832 }, +/* 0xb833 */ { true, 0xb833, 0xb833 }, +/* 0xb834 */ { true, 0xb834, 0xb834 }, +/* 0xb835 */ { true, 0xb835, 0xb835 }, +/* 0xb836 */ { true, 0xb836, 0xb836 }, +/* 0xb837 */ { true, 0xb837, 0xb837 }, +/* 0xb838 */ { true, 0xb838, 0xb838 }, +/* 0xb839 */ { true, 0xb839, 0xb839 }, +/* 0xb83a */ { true, 0xb83a, 0xb83a }, +/* 0xb83b */ { true, 0xb83b, 0xb83b }, +/* 0xb83c */ { true, 0xb83c, 0xb83c }, +/* 0xb83d */ { true, 0xb83d, 0xb83d }, +/* 0xb83e */ { true, 0xb83e, 0xb83e }, +/* 0xb83f */ { true, 0xb83f, 0xb83f }, +/* 0xb840 */ { true, 0xb840, 0xb840 }, +/* 0xb841 */ { true, 0xb841, 0xb841 }, +/* 0xb842 */ { true, 0xb842, 0xb842 }, +/* 0xb843 */ { true, 0xb843, 0xb843 }, +/* 0xb844 */ { true, 0xb844, 0xb844 }, +/* 0xb845 */ { true, 0xb845, 0xb845 }, +/* 0xb846 */ { true, 0xb846, 0xb846 }, +/* 0xb847 */ { true, 0xb847, 0xb847 }, +/* 0xb848 */ { true, 0xb848, 0xb848 }, +/* 0xb849 */ { true, 0xb849, 0xb849 }, +/* 0xb84a */ { true, 0xb84a, 0xb84a }, +/* 0xb84b */ { true, 0xb84b, 0xb84b }, +/* 0xb84c */ { true, 0xb84c, 0xb84c }, +/* 0xb84d */ { true, 0xb84d, 0xb84d }, +/* 0xb84e */ { true, 0xb84e, 0xb84e }, +/* 0xb84f */ { true, 0xb84f, 0xb84f }, +/* 0xb850 */ { true, 0xb850, 0xb850 }, +/* 0xb851 */ { true, 0xb851, 0xb851 }, +/* 0xb852 */ { true, 0xb852, 0xb852 }, +/* 0xb853 */ { true, 0xb853, 0xb853 }, +/* 0xb854 */ { true, 0xb854, 0xb854 }, +/* 0xb855 */ { true, 0xb855, 0xb855 }, +/* 0xb856 */ { true, 0xb856, 0xb856 }, +/* 0xb857 */ { true, 0xb857, 0xb857 }, +/* 0xb858 */ { true, 0xb858, 0xb858 }, +/* 0xb859 */ { true, 0xb859, 0xb859 }, +/* 0xb85a */ { true, 0xb85a, 0xb85a }, +/* 0xb85b */ { true, 0xb85b, 0xb85b }, +/* 0xb85c */ { true, 0xb85c, 0xb85c }, +/* 0xb85d */ { true, 0xb85d, 0xb85d }, +/* 0xb85e */ { true, 0xb85e, 0xb85e }, +/* 0xb85f */ { true, 0xb85f, 0xb85f }, +/* 0xb860 */ { true, 0xb860, 0xb860 }, +/* 0xb861 */ { true, 0xb861, 0xb861 }, +/* 0xb862 */ { true, 0xb862, 0xb862 }, +/* 0xb863 */ { true, 0xb863, 0xb863 }, +/* 0xb864 */ { true, 0xb864, 0xb864 }, +/* 0xb865 */ { true, 0xb865, 0xb865 }, +/* 0xb866 */ { true, 0xb866, 0xb866 }, +/* 0xb867 */ { true, 0xb867, 0xb867 }, +/* 0xb868 */ { true, 0xb868, 0xb868 }, +/* 0xb869 */ { true, 0xb869, 0xb869 }, +/* 0xb86a */ { true, 0xb86a, 0xb86a }, +/* 0xb86b */ { true, 0xb86b, 0xb86b }, +/* 0xb86c */ { true, 0xb86c, 0xb86c }, +/* 0xb86d */ { true, 0xb86d, 0xb86d }, +/* 0xb86e */ { true, 0xb86e, 0xb86e }, +/* 0xb86f */ { true, 0xb86f, 0xb86f }, +/* 0xb870 */ { true, 0xb870, 0xb870 }, +/* 0xb871 */ { true, 0xb871, 0xb871 }, +/* 0xb872 */ { true, 0xb872, 0xb872 }, +/* 0xb873 */ { true, 0xb873, 0xb873 }, +/* 0xb874 */ { true, 0xb874, 0xb874 }, +/* 0xb875 */ { true, 0xb875, 0xb875 }, +/* 0xb876 */ { true, 0xb876, 0xb876 }, +/* 0xb877 */ { true, 0xb877, 0xb877 }, +/* 0xb878 */ { true, 0xb878, 0xb878 }, +/* 0xb879 */ { true, 0xb879, 0xb879 }, +/* 0xb87a */ { true, 0xb87a, 0xb87a }, +/* 0xb87b */ { true, 0xb87b, 0xb87b }, +/* 0xb87c */ { true, 0xb87c, 0xb87c }, +/* 0xb87d */ { true, 0xb87d, 0xb87d }, +/* 0xb87e */ { true, 0xb87e, 0xb87e }, +/* 0xb87f */ { true, 0xb87f, 0xb87f }, +/* 0xb880 */ { true, 0xb880, 0xb880 }, +/* 0xb881 */ { true, 0xb881, 0xb881 }, +/* 0xb882 */ { true, 0xb882, 0xb882 }, +/* 0xb883 */ { true, 0xb883, 0xb883 }, +/* 0xb884 */ { true, 0xb884, 0xb884 }, +/* 0xb885 */ { true, 0xb885, 0xb885 }, +/* 0xb886 */ { true, 0xb886, 0xb886 }, +/* 0xb887 */ { true, 0xb887, 0xb887 }, +/* 0xb888 */ { true, 0xb888, 0xb888 }, +/* 0xb889 */ { true, 0xb889, 0xb889 }, +/* 0xb88a */ { true, 0xb88a, 0xb88a }, +/* 0xb88b */ { true, 0xb88b, 0xb88b }, +/* 0xb88c */ { true, 0xb88c, 0xb88c }, +/* 0xb88d */ { true, 0xb88d, 0xb88d }, +/* 0xb88e */ { true, 0xb88e, 0xb88e }, +/* 0xb88f */ { true, 0xb88f, 0xb88f }, +/* 0xb890 */ { true, 0xb890, 0xb890 }, +/* 0xb891 */ { true, 0xb891, 0xb891 }, +/* 0xb892 */ { true, 0xb892, 0xb892 }, +/* 0xb893 */ { true, 0xb893, 0xb893 }, +/* 0xb894 */ { true, 0xb894, 0xb894 }, +/* 0xb895 */ { true, 0xb895, 0xb895 }, +/* 0xb896 */ { true, 0xb896, 0xb896 }, +/* 0xb897 */ { true, 0xb897, 0xb897 }, +/* 0xb898 */ { true, 0xb898, 0xb898 }, +/* 0xb899 */ { true, 0xb899, 0xb899 }, +/* 0xb89a */ { true, 0xb89a, 0xb89a }, +/* 0xb89b */ { true, 0xb89b, 0xb89b }, +/* 0xb89c */ { true, 0xb89c, 0xb89c }, +/* 0xb89d */ { true, 0xb89d, 0xb89d }, +/* 0xb89e */ { true, 0xb89e, 0xb89e }, +/* 0xb89f */ { true, 0xb89f, 0xb89f }, +/* 0xb8a0 */ { true, 0xb8a0, 0xb8a0 }, +/* 0xb8a1 */ { true, 0xb8a1, 0xb8a1 }, +/* 0xb8a2 */ { true, 0xb8a2, 0xb8a2 }, +/* 0xb8a3 */ { true, 0xb8a3, 0xb8a3 }, +/* 0xb8a4 */ { true, 0xb8a4, 0xb8a4 }, +/* 0xb8a5 */ { true, 0xb8a5, 0xb8a5 }, +/* 0xb8a6 */ { true, 0xb8a6, 0xb8a6 }, +/* 0xb8a7 */ { true, 0xb8a7, 0xb8a7 }, +/* 0xb8a8 */ { true, 0xb8a8, 0xb8a8 }, +/* 0xb8a9 */ { true, 0xb8a9, 0xb8a9 }, +/* 0xb8aa */ { true, 0xb8aa, 0xb8aa }, +/* 0xb8ab */ { true, 0xb8ab, 0xb8ab }, +/* 0xb8ac */ { true, 0xb8ac, 0xb8ac }, +/* 0xb8ad */ { true, 0xb8ad, 0xb8ad }, +/* 0xb8ae */ { true, 0xb8ae, 0xb8ae }, +/* 0xb8af */ { true, 0xb8af, 0xb8af }, +/* 0xb8b0 */ { true, 0xb8b0, 0xb8b0 }, +/* 0xb8b1 */ { true, 0xb8b1, 0xb8b1 }, +/* 0xb8b2 */ { true, 0xb8b2, 0xb8b2 }, +/* 0xb8b3 */ { true, 0xb8b3, 0xb8b3 }, +/* 0xb8b4 */ { true, 0xb8b4, 0xb8b4 }, +/* 0xb8b5 */ { true, 0xb8b5, 0xb8b5 }, +/* 0xb8b6 */ { true, 0xb8b6, 0xb8b6 }, +/* 0xb8b7 */ { true, 0xb8b7, 0xb8b7 }, +/* 0xb8b8 */ { true, 0xb8b8, 0xb8b8 }, +/* 0xb8b9 */ { true, 0xb8b9, 0xb8b9 }, +/* 0xb8ba */ { true, 0xb8ba, 0xb8ba }, +/* 0xb8bb */ { true, 0xb8bb, 0xb8bb }, +/* 0xb8bc */ { true, 0xb8bc, 0xb8bc }, +/* 0xb8bd */ { true, 0xb8bd, 0xb8bd }, +/* 0xb8be */ { true, 0xb8be, 0xb8be }, +/* 0xb8bf */ { true, 0xb8bf, 0xb8bf }, +/* 0xb8c0 */ { true, 0xb8c0, 0xb8c0 }, +/* 0xb8c1 */ { true, 0xb8c1, 0xb8c1 }, +/* 0xb8c2 */ { true, 0xb8c2, 0xb8c2 }, +/* 0xb8c3 */ { true, 0xb8c3, 0xb8c3 }, +/* 0xb8c4 */ { true, 0xb8c4, 0xb8c4 }, +/* 0xb8c5 */ { true, 0xb8c5, 0xb8c5 }, +/* 0xb8c6 */ { true, 0xb8c6, 0xb8c6 }, +/* 0xb8c7 */ { true, 0xb8c7, 0xb8c7 }, +/* 0xb8c8 */ { true, 0xb8c8, 0xb8c8 }, +/* 0xb8c9 */ { true, 0xb8c9, 0xb8c9 }, +/* 0xb8ca */ { true, 0xb8ca, 0xb8ca }, +/* 0xb8cb */ { true, 0xb8cb, 0xb8cb }, +/* 0xb8cc */ { true, 0xb8cc, 0xb8cc }, +/* 0xb8cd */ { true, 0xb8cd, 0xb8cd }, +/* 0xb8ce */ { true, 0xb8ce, 0xb8ce }, +/* 0xb8cf */ { true, 0xb8cf, 0xb8cf }, +/* 0xb8d0 */ { true, 0xb8d0, 0xb8d0 }, +/* 0xb8d1 */ { true, 0xb8d1, 0xb8d1 }, +/* 0xb8d2 */ { true, 0xb8d2, 0xb8d2 }, +/* 0xb8d3 */ { true, 0xb8d3, 0xb8d3 }, +/* 0xb8d4 */ { true, 0xb8d4, 0xb8d4 }, +/* 0xb8d5 */ { true, 0xb8d5, 0xb8d5 }, +/* 0xb8d6 */ { true, 0xb8d6, 0xb8d6 }, +/* 0xb8d7 */ { true, 0xb8d7, 0xb8d7 }, +/* 0xb8d8 */ { true, 0xb8d8, 0xb8d8 }, +/* 0xb8d9 */ { true, 0xb8d9, 0xb8d9 }, +/* 0xb8da */ { true, 0xb8da, 0xb8da }, +/* 0xb8db */ { true, 0xb8db, 0xb8db }, +/* 0xb8dc */ { true, 0xb8dc, 0xb8dc }, +/* 0xb8dd */ { true, 0xb8dd, 0xb8dd }, +/* 0xb8de */ { true, 0xb8de, 0xb8de }, +/* 0xb8df */ { true, 0xb8df, 0xb8df }, +/* 0xb8e0 */ { true, 0xb8e0, 0xb8e0 }, +/* 0xb8e1 */ { true, 0xb8e1, 0xb8e1 }, +/* 0xb8e2 */ { true, 0xb8e2, 0xb8e2 }, +/* 0xb8e3 */ { true, 0xb8e3, 0xb8e3 }, +/* 0xb8e4 */ { true, 0xb8e4, 0xb8e4 }, +/* 0xb8e5 */ { true, 0xb8e5, 0xb8e5 }, +/* 0xb8e6 */ { true, 0xb8e6, 0xb8e6 }, +/* 0xb8e7 */ { true, 0xb8e7, 0xb8e7 }, +/* 0xb8e8 */ { true, 0xb8e8, 0xb8e8 }, +/* 0xb8e9 */ { true, 0xb8e9, 0xb8e9 }, +/* 0xb8ea */ { true, 0xb8ea, 0xb8ea }, +/* 0xb8eb */ { true, 0xb8eb, 0xb8eb }, +/* 0xb8ec */ { true, 0xb8ec, 0xb8ec }, +/* 0xb8ed */ { true, 0xb8ed, 0xb8ed }, +/* 0xb8ee */ { true, 0xb8ee, 0xb8ee }, +/* 0xb8ef */ { true, 0xb8ef, 0xb8ef }, +/* 0xb8f0 */ { true, 0xb8f0, 0xb8f0 }, +/* 0xb8f1 */ { true, 0xb8f1, 0xb8f1 }, +/* 0xb8f2 */ { true, 0xb8f2, 0xb8f2 }, +/* 0xb8f3 */ { true, 0xb8f3, 0xb8f3 }, +/* 0xb8f4 */ { true, 0xb8f4, 0xb8f4 }, +/* 0xb8f5 */ { true, 0xb8f5, 0xb8f5 }, +/* 0xb8f6 */ { true, 0xb8f6, 0xb8f6 }, +/* 0xb8f7 */ { true, 0xb8f7, 0xb8f7 }, +/* 0xb8f8 */ { true, 0xb8f8, 0xb8f8 }, +/* 0xb8f9 */ { true, 0xb8f9, 0xb8f9 }, +/* 0xb8fa */ { true, 0xb8fa, 0xb8fa }, +/* 0xb8fb */ { true, 0xb8fb, 0xb8fb }, +/* 0xb8fc */ { true, 0xb8fc, 0xb8fc }, +/* 0xb8fd */ { true, 0xb8fd, 0xb8fd }, +/* 0xb8fe */ { true, 0xb8fe, 0xb8fe }, +/* 0xb8ff */ { true, 0xb8ff, 0xb8ff }, +/* 0xb900 */ { true, 0xb900, 0xb900 }, +/* 0xb901 */ { true, 0xb901, 0xb901 }, +/* 0xb902 */ { true, 0xb902, 0xb902 }, +/* 0xb903 */ { true, 0xb903, 0xb903 }, +/* 0xb904 */ { true, 0xb904, 0xb904 }, +/* 0xb905 */ { true, 0xb905, 0xb905 }, +/* 0xb906 */ { true, 0xb906, 0xb906 }, +/* 0xb907 */ { true, 0xb907, 0xb907 }, +/* 0xb908 */ { true, 0xb908, 0xb908 }, +/* 0xb909 */ { true, 0xb909, 0xb909 }, +/* 0xb90a */ { true, 0xb90a, 0xb90a }, +/* 0xb90b */ { true, 0xb90b, 0xb90b }, +/* 0xb90c */ { true, 0xb90c, 0xb90c }, +/* 0xb90d */ { true, 0xb90d, 0xb90d }, +/* 0xb90e */ { true, 0xb90e, 0xb90e }, +/* 0xb90f */ { true, 0xb90f, 0xb90f }, +/* 0xb910 */ { true, 0xb910, 0xb910 }, +/* 0xb911 */ { true, 0xb911, 0xb911 }, +/* 0xb912 */ { true, 0xb912, 0xb912 }, +/* 0xb913 */ { true, 0xb913, 0xb913 }, +/* 0xb914 */ { true, 0xb914, 0xb914 }, +/* 0xb915 */ { true, 0xb915, 0xb915 }, +/* 0xb916 */ { true, 0xb916, 0xb916 }, +/* 0xb917 */ { true, 0xb917, 0xb917 }, +/* 0xb918 */ { true, 0xb918, 0xb918 }, +/* 0xb919 */ { true, 0xb919, 0xb919 }, +/* 0xb91a */ { true, 0xb91a, 0xb91a }, +/* 0xb91b */ { true, 0xb91b, 0xb91b }, +/* 0xb91c */ { true, 0xb91c, 0xb91c }, +/* 0xb91d */ { true, 0xb91d, 0xb91d }, +/* 0xb91e */ { true, 0xb91e, 0xb91e }, +/* 0xb91f */ { true, 0xb91f, 0xb91f }, +/* 0xb920 */ { true, 0xb920, 0xb920 }, +/* 0xb921 */ { true, 0xb921, 0xb921 }, +/* 0xb922 */ { true, 0xb922, 0xb922 }, +/* 0xb923 */ { true, 0xb923, 0xb923 }, +/* 0xb924 */ { true, 0xb924, 0xb924 }, +/* 0xb925 */ { true, 0xb925, 0xb925 }, +/* 0xb926 */ { true, 0xb926, 0xb926 }, +/* 0xb927 */ { true, 0xb927, 0xb927 }, +/* 0xb928 */ { true, 0xb928, 0xb928 }, +/* 0xb929 */ { true, 0xb929, 0xb929 }, +/* 0xb92a */ { true, 0xb92a, 0xb92a }, +/* 0xb92b */ { true, 0xb92b, 0xb92b }, +/* 0xb92c */ { true, 0xb92c, 0xb92c }, +/* 0xb92d */ { true, 0xb92d, 0xb92d }, +/* 0xb92e */ { true, 0xb92e, 0xb92e }, +/* 0xb92f */ { true, 0xb92f, 0xb92f }, +/* 0xb930 */ { true, 0xb930, 0xb930 }, +/* 0xb931 */ { true, 0xb931, 0xb931 }, +/* 0xb932 */ { true, 0xb932, 0xb932 }, +/* 0xb933 */ { true, 0xb933, 0xb933 }, +/* 0xb934 */ { true, 0xb934, 0xb934 }, +/* 0xb935 */ { true, 0xb935, 0xb935 }, +/* 0xb936 */ { true, 0xb936, 0xb936 }, +/* 0xb937 */ { true, 0xb937, 0xb937 }, +/* 0xb938 */ { true, 0xb938, 0xb938 }, +/* 0xb939 */ { true, 0xb939, 0xb939 }, +/* 0xb93a */ { true, 0xb93a, 0xb93a }, +/* 0xb93b */ { true, 0xb93b, 0xb93b }, +/* 0xb93c */ { true, 0xb93c, 0xb93c }, +/* 0xb93d */ { true, 0xb93d, 0xb93d }, +/* 0xb93e */ { true, 0xb93e, 0xb93e }, +/* 0xb93f */ { true, 0xb93f, 0xb93f }, +/* 0xb940 */ { true, 0xb940, 0xb940 }, +/* 0xb941 */ { true, 0xb941, 0xb941 }, +/* 0xb942 */ { true, 0xb942, 0xb942 }, +/* 0xb943 */ { true, 0xb943, 0xb943 }, +/* 0xb944 */ { true, 0xb944, 0xb944 }, +/* 0xb945 */ { true, 0xb945, 0xb945 }, +/* 0xb946 */ { true, 0xb946, 0xb946 }, +/* 0xb947 */ { true, 0xb947, 0xb947 }, +/* 0xb948 */ { true, 0xb948, 0xb948 }, +/* 0xb949 */ { true, 0xb949, 0xb949 }, +/* 0xb94a */ { true, 0xb94a, 0xb94a }, +/* 0xb94b */ { true, 0xb94b, 0xb94b }, +/* 0xb94c */ { true, 0xb94c, 0xb94c }, +/* 0xb94d */ { true, 0xb94d, 0xb94d }, +/* 0xb94e */ { true, 0xb94e, 0xb94e }, +/* 0xb94f */ { true, 0xb94f, 0xb94f }, +/* 0xb950 */ { true, 0xb950, 0xb950 }, +/* 0xb951 */ { true, 0xb951, 0xb951 }, +/* 0xb952 */ { true, 0xb952, 0xb952 }, +/* 0xb953 */ { true, 0xb953, 0xb953 }, +/* 0xb954 */ { true, 0xb954, 0xb954 }, +/* 0xb955 */ { true, 0xb955, 0xb955 }, +/* 0xb956 */ { true, 0xb956, 0xb956 }, +/* 0xb957 */ { true, 0xb957, 0xb957 }, +/* 0xb958 */ { true, 0xb958, 0xb958 }, +/* 0xb959 */ { true, 0xb959, 0xb959 }, +/* 0xb95a */ { true, 0xb95a, 0xb95a }, +/* 0xb95b */ { true, 0xb95b, 0xb95b }, +/* 0xb95c */ { true, 0xb95c, 0xb95c }, +/* 0xb95d */ { true, 0xb95d, 0xb95d }, +/* 0xb95e */ { true, 0xb95e, 0xb95e }, +/* 0xb95f */ { true, 0xb95f, 0xb95f }, +/* 0xb960 */ { true, 0xb960, 0xb960 }, +/* 0xb961 */ { true, 0xb961, 0xb961 }, +/* 0xb962 */ { true, 0xb962, 0xb962 }, +/* 0xb963 */ { true, 0xb963, 0xb963 }, +/* 0xb964 */ { true, 0xb964, 0xb964 }, +/* 0xb965 */ { true, 0xb965, 0xb965 }, +/* 0xb966 */ { true, 0xb966, 0xb966 }, +/* 0xb967 */ { true, 0xb967, 0xb967 }, +/* 0xb968 */ { true, 0xb968, 0xb968 }, +/* 0xb969 */ { true, 0xb969, 0xb969 }, +/* 0xb96a */ { true, 0xb96a, 0xb96a }, +/* 0xb96b */ { true, 0xb96b, 0xb96b }, +/* 0xb96c */ { true, 0xb96c, 0xb96c }, +/* 0xb96d */ { true, 0xb96d, 0xb96d }, +/* 0xb96e */ { true, 0xb96e, 0xb96e }, +/* 0xb96f */ { true, 0xb96f, 0xb96f }, +/* 0xb970 */ { true, 0xb970, 0xb970 }, +/* 0xb971 */ { true, 0xb971, 0xb971 }, +/* 0xb972 */ { true, 0xb972, 0xb972 }, +/* 0xb973 */ { true, 0xb973, 0xb973 }, +/* 0xb974 */ { true, 0xb974, 0xb974 }, +/* 0xb975 */ { true, 0xb975, 0xb975 }, +/* 0xb976 */ { true, 0xb976, 0xb976 }, +/* 0xb977 */ { true, 0xb977, 0xb977 }, +/* 0xb978 */ { true, 0xb978, 0xb978 }, +/* 0xb979 */ { true, 0xb979, 0xb979 }, +/* 0xb97a */ { true, 0xb97a, 0xb97a }, +/* 0xb97b */ { true, 0xb97b, 0xb97b }, +/* 0xb97c */ { true, 0xb97c, 0xb97c }, +/* 0xb97d */ { true, 0xb97d, 0xb97d }, +/* 0xb97e */ { true, 0xb97e, 0xb97e }, +/* 0xb97f */ { true, 0xb97f, 0xb97f }, +/* 0xb980 */ { true, 0xb980, 0xb980 }, +/* 0xb981 */ { true, 0xb981, 0xb981 }, +/* 0xb982 */ { true, 0xb982, 0xb982 }, +/* 0xb983 */ { true, 0xb983, 0xb983 }, +/* 0xb984 */ { true, 0xb984, 0xb984 }, +/* 0xb985 */ { true, 0xb985, 0xb985 }, +/* 0xb986 */ { true, 0xb986, 0xb986 }, +/* 0xb987 */ { true, 0xb987, 0xb987 }, +/* 0xb988 */ { true, 0xb988, 0xb988 }, +/* 0xb989 */ { true, 0xb989, 0xb989 }, +/* 0xb98a */ { true, 0xb98a, 0xb98a }, +/* 0xb98b */ { true, 0xb98b, 0xb98b }, +/* 0xb98c */ { true, 0xb98c, 0xb98c }, +/* 0xb98d */ { true, 0xb98d, 0xb98d }, +/* 0xb98e */ { true, 0xb98e, 0xb98e }, +/* 0xb98f */ { true, 0xb98f, 0xb98f }, +/* 0xb990 */ { true, 0xb990, 0xb990 }, +/* 0xb991 */ { true, 0xb991, 0xb991 }, +/* 0xb992 */ { true, 0xb992, 0xb992 }, +/* 0xb993 */ { true, 0xb993, 0xb993 }, +/* 0xb994 */ { true, 0xb994, 0xb994 }, +/* 0xb995 */ { true, 0xb995, 0xb995 }, +/* 0xb996 */ { true, 0xb996, 0xb996 }, +/* 0xb997 */ { true, 0xb997, 0xb997 }, +/* 0xb998 */ { true, 0xb998, 0xb998 }, +/* 0xb999 */ { true, 0xb999, 0xb999 }, +/* 0xb99a */ { true, 0xb99a, 0xb99a }, +/* 0xb99b */ { true, 0xb99b, 0xb99b }, +/* 0xb99c */ { true, 0xb99c, 0xb99c }, +/* 0xb99d */ { true, 0xb99d, 0xb99d }, +/* 0xb99e */ { true, 0xb99e, 0xb99e }, +/* 0xb99f */ { true, 0xb99f, 0xb99f }, +/* 0xb9a0 */ { true, 0xb9a0, 0xb9a0 }, +/* 0xb9a1 */ { true, 0xb9a1, 0xb9a1 }, +/* 0xb9a2 */ { true, 0xb9a2, 0xb9a2 }, +/* 0xb9a3 */ { true, 0xb9a3, 0xb9a3 }, +/* 0xb9a4 */ { true, 0xb9a4, 0xb9a4 }, +/* 0xb9a5 */ { true, 0xb9a5, 0xb9a5 }, +/* 0xb9a6 */ { true, 0xb9a6, 0xb9a6 }, +/* 0xb9a7 */ { true, 0xb9a7, 0xb9a7 }, +/* 0xb9a8 */ { true, 0xb9a8, 0xb9a8 }, +/* 0xb9a9 */ { true, 0xb9a9, 0xb9a9 }, +/* 0xb9aa */ { true, 0xb9aa, 0xb9aa }, +/* 0xb9ab */ { true, 0xb9ab, 0xb9ab }, +/* 0xb9ac */ { true, 0xb9ac, 0xb9ac }, +/* 0xb9ad */ { true, 0xb9ad, 0xb9ad }, +/* 0xb9ae */ { true, 0xb9ae, 0xb9ae }, +/* 0xb9af */ { true, 0xb9af, 0xb9af }, +/* 0xb9b0 */ { true, 0xb9b0, 0xb9b0 }, +/* 0xb9b1 */ { true, 0xb9b1, 0xb9b1 }, +/* 0xb9b2 */ { true, 0xb9b2, 0xb9b2 }, +/* 0xb9b3 */ { true, 0xb9b3, 0xb9b3 }, +/* 0xb9b4 */ { true, 0xb9b4, 0xb9b4 }, +/* 0xb9b5 */ { true, 0xb9b5, 0xb9b5 }, +/* 0xb9b6 */ { true, 0xb9b6, 0xb9b6 }, +/* 0xb9b7 */ { true, 0xb9b7, 0xb9b7 }, +/* 0xb9b8 */ { true, 0xb9b8, 0xb9b8 }, +/* 0xb9b9 */ { true, 0xb9b9, 0xb9b9 }, +/* 0xb9ba */ { true, 0xb9ba, 0xb9ba }, +/* 0xb9bb */ { true, 0xb9bb, 0xb9bb }, +/* 0xb9bc */ { true, 0xb9bc, 0xb9bc }, +/* 0xb9bd */ { true, 0xb9bd, 0xb9bd }, +/* 0xb9be */ { true, 0xb9be, 0xb9be }, +/* 0xb9bf */ { true, 0xb9bf, 0xb9bf }, +/* 0xb9c0 */ { true, 0xb9c0, 0xb9c0 }, +/* 0xb9c1 */ { true, 0xb9c1, 0xb9c1 }, +/* 0xb9c2 */ { true, 0xb9c2, 0xb9c2 }, +/* 0xb9c3 */ { true, 0xb9c3, 0xb9c3 }, +/* 0xb9c4 */ { true, 0xb9c4, 0xb9c4 }, +/* 0xb9c5 */ { true, 0xb9c5, 0xb9c5 }, +/* 0xb9c6 */ { true, 0xb9c6, 0xb9c6 }, +/* 0xb9c7 */ { true, 0xb9c7, 0xb9c7 }, +/* 0xb9c8 */ { true, 0xb9c8, 0xb9c8 }, +/* 0xb9c9 */ { true, 0xb9c9, 0xb9c9 }, +/* 0xb9ca */ { true, 0xb9ca, 0xb9ca }, +/* 0xb9cb */ { true, 0xb9cb, 0xb9cb }, +/* 0xb9cc */ { true, 0xb9cc, 0xb9cc }, +/* 0xb9cd */ { true, 0xb9cd, 0xb9cd }, +/* 0xb9ce */ { true, 0xb9ce, 0xb9ce }, +/* 0xb9cf */ { true, 0xb9cf, 0xb9cf }, +/* 0xb9d0 */ { true, 0xb9d0, 0xb9d0 }, +/* 0xb9d1 */ { true, 0xb9d1, 0xb9d1 }, +/* 0xb9d2 */ { true, 0xb9d2, 0xb9d2 }, +/* 0xb9d3 */ { true, 0xb9d3, 0xb9d3 }, +/* 0xb9d4 */ { true, 0xb9d4, 0xb9d4 }, +/* 0xb9d5 */ { true, 0xb9d5, 0xb9d5 }, +/* 0xb9d6 */ { true, 0xb9d6, 0xb9d6 }, +/* 0xb9d7 */ { true, 0xb9d7, 0xb9d7 }, +/* 0xb9d8 */ { true, 0xb9d8, 0xb9d8 }, +/* 0xb9d9 */ { true, 0xb9d9, 0xb9d9 }, +/* 0xb9da */ { true, 0xb9da, 0xb9da }, +/* 0xb9db */ { true, 0xb9db, 0xb9db }, +/* 0xb9dc */ { true, 0xb9dc, 0xb9dc }, +/* 0xb9dd */ { true, 0xb9dd, 0xb9dd }, +/* 0xb9de */ { true, 0xb9de, 0xb9de }, +/* 0xb9df */ { true, 0xb9df, 0xb9df }, +/* 0xb9e0 */ { true, 0xb9e0, 0xb9e0 }, +/* 0xb9e1 */ { true, 0xb9e1, 0xb9e1 }, +/* 0xb9e2 */ { true, 0xb9e2, 0xb9e2 }, +/* 0xb9e3 */ { true, 0xb9e3, 0xb9e3 }, +/* 0xb9e4 */ { true, 0xb9e4, 0xb9e4 }, +/* 0xb9e5 */ { true, 0xb9e5, 0xb9e5 }, +/* 0xb9e6 */ { true, 0xb9e6, 0xb9e6 }, +/* 0xb9e7 */ { true, 0xb9e7, 0xb9e7 }, +/* 0xb9e8 */ { true, 0xb9e8, 0xb9e8 }, +/* 0xb9e9 */ { true, 0xb9e9, 0xb9e9 }, +/* 0xb9ea */ { true, 0xb9ea, 0xb9ea }, +/* 0xb9eb */ { true, 0xb9eb, 0xb9eb }, +/* 0xb9ec */ { true, 0xb9ec, 0xb9ec }, +/* 0xb9ed */ { true, 0xb9ed, 0xb9ed }, +/* 0xb9ee */ { true, 0xb9ee, 0xb9ee }, +/* 0xb9ef */ { true, 0xb9ef, 0xb9ef }, +/* 0xb9f0 */ { true, 0xb9f0, 0xb9f0 }, +/* 0xb9f1 */ { true, 0xb9f1, 0xb9f1 }, +/* 0xb9f2 */ { true, 0xb9f2, 0xb9f2 }, +/* 0xb9f3 */ { true, 0xb9f3, 0xb9f3 }, +/* 0xb9f4 */ { true, 0xb9f4, 0xb9f4 }, +/* 0xb9f5 */ { true, 0xb9f5, 0xb9f5 }, +/* 0xb9f6 */ { true, 0xb9f6, 0xb9f6 }, +/* 0xb9f7 */ { true, 0xb9f7, 0xb9f7 }, +/* 0xb9f8 */ { true, 0xb9f8, 0xb9f8 }, +/* 0xb9f9 */ { true, 0xb9f9, 0xb9f9 }, +/* 0xb9fa */ { true, 0xb9fa, 0xb9fa }, +/* 0xb9fb */ { true, 0xb9fb, 0xb9fb }, +/* 0xb9fc */ { true, 0xb9fc, 0xb9fc }, +/* 0xb9fd */ { true, 0xb9fd, 0xb9fd }, +/* 0xb9fe */ { true, 0xb9fe, 0xb9fe }, +/* 0xb9ff */ { true, 0xb9ff, 0xb9ff }, +/* 0xba00 */ { true, 0xba00, 0xba00 }, +/* 0xba01 */ { true, 0xba01, 0xba01 }, +/* 0xba02 */ { true, 0xba02, 0xba02 }, +/* 0xba03 */ { true, 0xba03, 0xba03 }, +/* 0xba04 */ { true, 0xba04, 0xba04 }, +/* 0xba05 */ { true, 0xba05, 0xba05 }, +/* 0xba06 */ { true, 0xba06, 0xba06 }, +/* 0xba07 */ { true, 0xba07, 0xba07 }, +/* 0xba08 */ { true, 0xba08, 0xba08 }, +/* 0xba09 */ { true, 0xba09, 0xba09 }, +/* 0xba0a */ { true, 0xba0a, 0xba0a }, +/* 0xba0b */ { true, 0xba0b, 0xba0b }, +/* 0xba0c */ { true, 0xba0c, 0xba0c }, +/* 0xba0d */ { true, 0xba0d, 0xba0d }, +/* 0xba0e */ { true, 0xba0e, 0xba0e }, +/* 0xba0f */ { true, 0xba0f, 0xba0f }, +/* 0xba10 */ { true, 0xba10, 0xba10 }, +/* 0xba11 */ { true, 0xba11, 0xba11 }, +/* 0xba12 */ { true, 0xba12, 0xba12 }, +/* 0xba13 */ { true, 0xba13, 0xba13 }, +/* 0xba14 */ { true, 0xba14, 0xba14 }, +/* 0xba15 */ { true, 0xba15, 0xba15 }, +/* 0xba16 */ { true, 0xba16, 0xba16 }, +/* 0xba17 */ { true, 0xba17, 0xba17 }, +/* 0xba18 */ { true, 0xba18, 0xba18 }, +/* 0xba19 */ { true, 0xba19, 0xba19 }, +/* 0xba1a */ { true, 0xba1a, 0xba1a }, +/* 0xba1b */ { true, 0xba1b, 0xba1b }, +/* 0xba1c */ { true, 0xba1c, 0xba1c }, +/* 0xba1d */ { true, 0xba1d, 0xba1d }, +/* 0xba1e */ { true, 0xba1e, 0xba1e }, +/* 0xba1f */ { true, 0xba1f, 0xba1f }, +/* 0xba20 */ { true, 0xba20, 0xba20 }, +/* 0xba21 */ { true, 0xba21, 0xba21 }, +/* 0xba22 */ { true, 0xba22, 0xba22 }, +/* 0xba23 */ { true, 0xba23, 0xba23 }, +/* 0xba24 */ { true, 0xba24, 0xba24 }, +/* 0xba25 */ { true, 0xba25, 0xba25 }, +/* 0xba26 */ { true, 0xba26, 0xba26 }, +/* 0xba27 */ { true, 0xba27, 0xba27 }, +/* 0xba28 */ { true, 0xba28, 0xba28 }, +/* 0xba29 */ { true, 0xba29, 0xba29 }, +/* 0xba2a */ { true, 0xba2a, 0xba2a }, +/* 0xba2b */ { true, 0xba2b, 0xba2b }, +/* 0xba2c */ { true, 0xba2c, 0xba2c }, +/* 0xba2d */ { true, 0xba2d, 0xba2d }, +/* 0xba2e */ { true, 0xba2e, 0xba2e }, +/* 0xba2f */ { true, 0xba2f, 0xba2f }, +/* 0xba30 */ { true, 0xba30, 0xba30 }, +/* 0xba31 */ { true, 0xba31, 0xba31 }, +/* 0xba32 */ { true, 0xba32, 0xba32 }, +/* 0xba33 */ { true, 0xba33, 0xba33 }, +/* 0xba34 */ { true, 0xba34, 0xba34 }, +/* 0xba35 */ { true, 0xba35, 0xba35 }, +/* 0xba36 */ { true, 0xba36, 0xba36 }, +/* 0xba37 */ { true, 0xba37, 0xba37 }, +/* 0xba38 */ { true, 0xba38, 0xba38 }, +/* 0xba39 */ { true, 0xba39, 0xba39 }, +/* 0xba3a */ { true, 0xba3a, 0xba3a }, +/* 0xba3b */ { true, 0xba3b, 0xba3b }, +/* 0xba3c */ { true, 0xba3c, 0xba3c }, +/* 0xba3d */ { true, 0xba3d, 0xba3d }, +/* 0xba3e */ { true, 0xba3e, 0xba3e }, +/* 0xba3f */ { true, 0xba3f, 0xba3f }, +/* 0xba40 */ { true, 0xba40, 0xba40 }, +/* 0xba41 */ { true, 0xba41, 0xba41 }, +/* 0xba42 */ { true, 0xba42, 0xba42 }, +/* 0xba43 */ { true, 0xba43, 0xba43 }, +/* 0xba44 */ { true, 0xba44, 0xba44 }, +/* 0xba45 */ { true, 0xba45, 0xba45 }, +/* 0xba46 */ { true, 0xba46, 0xba46 }, +/* 0xba47 */ { true, 0xba47, 0xba47 }, +/* 0xba48 */ { true, 0xba48, 0xba48 }, +/* 0xba49 */ { true, 0xba49, 0xba49 }, +/* 0xba4a */ { true, 0xba4a, 0xba4a }, +/* 0xba4b */ { true, 0xba4b, 0xba4b }, +/* 0xba4c */ { true, 0xba4c, 0xba4c }, +/* 0xba4d */ { true, 0xba4d, 0xba4d }, +/* 0xba4e */ { true, 0xba4e, 0xba4e }, +/* 0xba4f */ { true, 0xba4f, 0xba4f }, +/* 0xba50 */ { true, 0xba50, 0xba50 }, +/* 0xba51 */ { true, 0xba51, 0xba51 }, +/* 0xba52 */ { true, 0xba52, 0xba52 }, +/* 0xba53 */ { true, 0xba53, 0xba53 }, +/* 0xba54 */ { true, 0xba54, 0xba54 }, +/* 0xba55 */ { true, 0xba55, 0xba55 }, +/* 0xba56 */ { true, 0xba56, 0xba56 }, +/* 0xba57 */ { true, 0xba57, 0xba57 }, +/* 0xba58 */ { true, 0xba58, 0xba58 }, +/* 0xba59 */ { true, 0xba59, 0xba59 }, +/* 0xba5a */ { true, 0xba5a, 0xba5a }, +/* 0xba5b */ { true, 0xba5b, 0xba5b }, +/* 0xba5c */ { true, 0xba5c, 0xba5c }, +/* 0xba5d */ { true, 0xba5d, 0xba5d }, +/* 0xba5e */ { true, 0xba5e, 0xba5e }, +/* 0xba5f */ { true, 0xba5f, 0xba5f }, +/* 0xba60 */ { true, 0xba60, 0xba60 }, +/* 0xba61 */ { true, 0xba61, 0xba61 }, +/* 0xba62 */ { true, 0xba62, 0xba62 }, +/* 0xba63 */ { true, 0xba63, 0xba63 }, +/* 0xba64 */ { true, 0xba64, 0xba64 }, +/* 0xba65 */ { true, 0xba65, 0xba65 }, +/* 0xba66 */ { true, 0xba66, 0xba66 }, +/* 0xba67 */ { true, 0xba67, 0xba67 }, +/* 0xba68 */ { true, 0xba68, 0xba68 }, +/* 0xba69 */ { true, 0xba69, 0xba69 }, +/* 0xba6a */ { true, 0xba6a, 0xba6a }, +/* 0xba6b */ { true, 0xba6b, 0xba6b }, +/* 0xba6c */ { true, 0xba6c, 0xba6c }, +/* 0xba6d */ { true, 0xba6d, 0xba6d }, +/* 0xba6e */ { true, 0xba6e, 0xba6e }, +/* 0xba6f */ { true, 0xba6f, 0xba6f }, +/* 0xba70 */ { true, 0xba70, 0xba70 }, +/* 0xba71 */ { true, 0xba71, 0xba71 }, +/* 0xba72 */ { true, 0xba72, 0xba72 }, +/* 0xba73 */ { true, 0xba73, 0xba73 }, +/* 0xba74 */ { true, 0xba74, 0xba74 }, +/* 0xba75 */ { true, 0xba75, 0xba75 }, +/* 0xba76 */ { true, 0xba76, 0xba76 }, +/* 0xba77 */ { true, 0xba77, 0xba77 }, +/* 0xba78 */ { true, 0xba78, 0xba78 }, +/* 0xba79 */ { true, 0xba79, 0xba79 }, +/* 0xba7a */ { true, 0xba7a, 0xba7a }, +/* 0xba7b */ { true, 0xba7b, 0xba7b }, +/* 0xba7c */ { true, 0xba7c, 0xba7c }, +/* 0xba7d */ { true, 0xba7d, 0xba7d }, +/* 0xba7e */ { true, 0xba7e, 0xba7e }, +/* 0xba7f */ { true, 0xba7f, 0xba7f }, +/* 0xba80 */ { true, 0xba80, 0xba80 }, +/* 0xba81 */ { true, 0xba81, 0xba81 }, +/* 0xba82 */ { true, 0xba82, 0xba82 }, +/* 0xba83 */ { true, 0xba83, 0xba83 }, +/* 0xba84 */ { true, 0xba84, 0xba84 }, +/* 0xba85 */ { true, 0xba85, 0xba85 }, +/* 0xba86 */ { true, 0xba86, 0xba86 }, +/* 0xba87 */ { true, 0xba87, 0xba87 }, +/* 0xba88 */ { true, 0xba88, 0xba88 }, +/* 0xba89 */ { true, 0xba89, 0xba89 }, +/* 0xba8a */ { true, 0xba8a, 0xba8a }, +/* 0xba8b */ { true, 0xba8b, 0xba8b }, +/* 0xba8c */ { true, 0xba8c, 0xba8c }, +/* 0xba8d */ { true, 0xba8d, 0xba8d }, +/* 0xba8e */ { true, 0xba8e, 0xba8e }, +/* 0xba8f */ { true, 0xba8f, 0xba8f }, +/* 0xba90 */ { true, 0xba90, 0xba90 }, +/* 0xba91 */ { true, 0xba91, 0xba91 }, +/* 0xba92 */ { true, 0xba92, 0xba92 }, +/* 0xba93 */ { true, 0xba93, 0xba93 }, +/* 0xba94 */ { true, 0xba94, 0xba94 }, +/* 0xba95 */ { true, 0xba95, 0xba95 }, +/* 0xba96 */ { true, 0xba96, 0xba96 }, +/* 0xba97 */ { true, 0xba97, 0xba97 }, +/* 0xba98 */ { true, 0xba98, 0xba98 }, +/* 0xba99 */ { true, 0xba99, 0xba99 }, +/* 0xba9a */ { true, 0xba9a, 0xba9a }, +/* 0xba9b */ { true, 0xba9b, 0xba9b }, +/* 0xba9c */ { true, 0xba9c, 0xba9c }, +/* 0xba9d */ { true, 0xba9d, 0xba9d }, +/* 0xba9e */ { true, 0xba9e, 0xba9e }, +/* 0xba9f */ { true, 0xba9f, 0xba9f }, +/* 0xbaa0 */ { true, 0xbaa0, 0xbaa0 }, +/* 0xbaa1 */ { true, 0xbaa1, 0xbaa1 }, +/* 0xbaa2 */ { true, 0xbaa2, 0xbaa2 }, +/* 0xbaa3 */ { true, 0xbaa3, 0xbaa3 }, +/* 0xbaa4 */ { true, 0xbaa4, 0xbaa4 }, +/* 0xbaa5 */ { true, 0xbaa5, 0xbaa5 }, +/* 0xbaa6 */ { true, 0xbaa6, 0xbaa6 }, +/* 0xbaa7 */ { true, 0xbaa7, 0xbaa7 }, +/* 0xbaa8 */ { true, 0xbaa8, 0xbaa8 }, +/* 0xbaa9 */ { true, 0xbaa9, 0xbaa9 }, +/* 0xbaaa */ { true, 0xbaaa, 0xbaaa }, +/* 0xbaab */ { true, 0xbaab, 0xbaab }, +/* 0xbaac */ { true, 0xbaac, 0xbaac }, +/* 0xbaad */ { true, 0xbaad, 0xbaad }, +/* 0xbaae */ { true, 0xbaae, 0xbaae }, +/* 0xbaaf */ { true, 0xbaaf, 0xbaaf }, +/* 0xbab0 */ { true, 0xbab0, 0xbab0 }, +/* 0xbab1 */ { true, 0xbab1, 0xbab1 }, +/* 0xbab2 */ { true, 0xbab2, 0xbab2 }, +/* 0xbab3 */ { true, 0xbab3, 0xbab3 }, +/* 0xbab4 */ { true, 0xbab4, 0xbab4 }, +/* 0xbab5 */ { true, 0xbab5, 0xbab5 }, +/* 0xbab6 */ { true, 0xbab6, 0xbab6 }, +/* 0xbab7 */ { true, 0xbab7, 0xbab7 }, +/* 0xbab8 */ { true, 0xbab8, 0xbab8 }, +/* 0xbab9 */ { true, 0xbab9, 0xbab9 }, +/* 0xbaba */ { true, 0xbaba, 0xbaba }, +/* 0xbabb */ { true, 0xbabb, 0xbabb }, +/* 0xbabc */ { true, 0xbabc, 0xbabc }, +/* 0xbabd */ { true, 0xbabd, 0xbabd }, +/* 0xbabe */ { true, 0xbabe, 0xbabe }, +/* 0xbabf */ { true, 0xbabf, 0xbabf }, +/* 0xbac0 */ { true, 0xbac0, 0xbac0 }, +/* 0xbac1 */ { true, 0xbac1, 0xbac1 }, +/* 0xbac2 */ { true, 0xbac2, 0xbac2 }, +/* 0xbac3 */ { true, 0xbac3, 0xbac3 }, +/* 0xbac4 */ { true, 0xbac4, 0xbac4 }, +/* 0xbac5 */ { true, 0xbac5, 0xbac5 }, +/* 0xbac6 */ { true, 0xbac6, 0xbac6 }, +/* 0xbac7 */ { true, 0xbac7, 0xbac7 }, +/* 0xbac8 */ { true, 0xbac8, 0xbac8 }, +/* 0xbac9 */ { true, 0xbac9, 0xbac9 }, +/* 0xbaca */ { true, 0xbaca, 0xbaca }, +/* 0xbacb */ { true, 0xbacb, 0xbacb }, +/* 0xbacc */ { true, 0xbacc, 0xbacc }, +/* 0xbacd */ { true, 0xbacd, 0xbacd }, +/* 0xbace */ { true, 0xbace, 0xbace }, +/* 0xbacf */ { true, 0xbacf, 0xbacf }, +/* 0xbad0 */ { true, 0xbad0, 0xbad0 }, +/* 0xbad1 */ { true, 0xbad1, 0xbad1 }, +/* 0xbad2 */ { true, 0xbad2, 0xbad2 }, +/* 0xbad3 */ { true, 0xbad3, 0xbad3 }, +/* 0xbad4 */ { true, 0xbad4, 0xbad4 }, +/* 0xbad5 */ { true, 0xbad5, 0xbad5 }, +/* 0xbad6 */ { true, 0xbad6, 0xbad6 }, +/* 0xbad7 */ { true, 0xbad7, 0xbad7 }, +/* 0xbad8 */ { true, 0xbad8, 0xbad8 }, +/* 0xbad9 */ { true, 0xbad9, 0xbad9 }, +/* 0xbada */ { true, 0xbada, 0xbada }, +/* 0xbadb */ { true, 0xbadb, 0xbadb }, +/* 0xbadc */ { true, 0xbadc, 0xbadc }, +/* 0xbadd */ { true, 0xbadd, 0xbadd }, +/* 0xbade */ { true, 0xbade, 0xbade }, +/* 0xbadf */ { true, 0xbadf, 0xbadf }, +/* 0xbae0 */ { true, 0xbae0, 0xbae0 }, +/* 0xbae1 */ { true, 0xbae1, 0xbae1 }, +/* 0xbae2 */ { true, 0xbae2, 0xbae2 }, +/* 0xbae3 */ { true, 0xbae3, 0xbae3 }, +/* 0xbae4 */ { true, 0xbae4, 0xbae4 }, +/* 0xbae5 */ { true, 0xbae5, 0xbae5 }, +/* 0xbae6 */ { true, 0xbae6, 0xbae6 }, +/* 0xbae7 */ { true, 0xbae7, 0xbae7 }, +/* 0xbae8 */ { true, 0xbae8, 0xbae8 }, +/* 0xbae9 */ { true, 0xbae9, 0xbae9 }, +/* 0xbaea */ { true, 0xbaea, 0xbaea }, +/* 0xbaeb */ { true, 0xbaeb, 0xbaeb }, +/* 0xbaec */ { true, 0xbaec, 0xbaec }, +/* 0xbaed */ { true, 0xbaed, 0xbaed }, +/* 0xbaee */ { true, 0xbaee, 0xbaee }, +/* 0xbaef */ { true, 0xbaef, 0xbaef }, +/* 0xbaf0 */ { true, 0xbaf0, 0xbaf0 }, +/* 0xbaf1 */ { true, 0xbaf1, 0xbaf1 }, +/* 0xbaf2 */ { true, 0xbaf2, 0xbaf2 }, +/* 0xbaf3 */ { true, 0xbaf3, 0xbaf3 }, +/* 0xbaf4 */ { true, 0xbaf4, 0xbaf4 }, +/* 0xbaf5 */ { true, 0xbaf5, 0xbaf5 }, +/* 0xbaf6 */ { true, 0xbaf6, 0xbaf6 }, +/* 0xbaf7 */ { true, 0xbaf7, 0xbaf7 }, +/* 0xbaf8 */ { true, 0xbaf8, 0xbaf8 }, +/* 0xbaf9 */ { true, 0xbaf9, 0xbaf9 }, +/* 0xbafa */ { true, 0xbafa, 0xbafa }, +/* 0xbafb */ { true, 0xbafb, 0xbafb }, +/* 0xbafc */ { true, 0xbafc, 0xbafc }, +/* 0xbafd */ { true, 0xbafd, 0xbafd }, +/* 0xbafe */ { true, 0xbafe, 0xbafe }, +/* 0xbaff */ { true, 0xbaff, 0xbaff }, +/* 0xbb00 */ { true, 0xbb00, 0xbb00 }, +/* 0xbb01 */ { true, 0xbb01, 0xbb01 }, +/* 0xbb02 */ { true, 0xbb02, 0xbb02 }, +/* 0xbb03 */ { true, 0xbb03, 0xbb03 }, +/* 0xbb04 */ { true, 0xbb04, 0xbb04 }, +/* 0xbb05 */ { true, 0xbb05, 0xbb05 }, +/* 0xbb06 */ { true, 0xbb06, 0xbb06 }, +/* 0xbb07 */ { true, 0xbb07, 0xbb07 }, +/* 0xbb08 */ { true, 0xbb08, 0xbb08 }, +/* 0xbb09 */ { true, 0xbb09, 0xbb09 }, +/* 0xbb0a */ { true, 0xbb0a, 0xbb0a }, +/* 0xbb0b */ { true, 0xbb0b, 0xbb0b }, +/* 0xbb0c */ { true, 0xbb0c, 0xbb0c }, +/* 0xbb0d */ { true, 0xbb0d, 0xbb0d }, +/* 0xbb0e */ { true, 0xbb0e, 0xbb0e }, +/* 0xbb0f */ { true, 0xbb0f, 0xbb0f }, +/* 0xbb10 */ { true, 0xbb10, 0xbb10 }, +/* 0xbb11 */ { true, 0xbb11, 0xbb11 }, +/* 0xbb12 */ { true, 0xbb12, 0xbb12 }, +/* 0xbb13 */ { true, 0xbb13, 0xbb13 }, +/* 0xbb14 */ { true, 0xbb14, 0xbb14 }, +/* 0xbb15 */ { true, 0xbb15, 0xbb15 }, +/* 0xbb16 */ { true, 0xbb16, 0xbb16 }, +/* 0xbb17 */ { true, 0xbb17, 0xbb17 }, +/* 0xbb18 */ { true, 0xbb18, 0xbb18 }, +/* 0xbb19 */ { true, 0xbb19, 0xbb19 }, +/* 0xbb1a */ { true, 0xbb1a, 0xbb1a }, +/* 0xbb1b */ { true, 0xbb1b, 0xbb1b }, +/* 0xbb1c */ { true, 0xbb1c, 0xbb1c }, +/* 0xbb1d */ { true, 0xbb1d, 0xbb1d }, +/* 0xbb1e */ { true, 0xbb1e, 0xbb1e }, +/* 0xbb1f */ { true, 0xbb1f, 0xbb1f }, +/* 0xbb20 */ { true, 0xbb20, 0xbb20 }, +/* 0xbb21 */ { true, 0xbb21, 0xbb21 }, +/* 0xbb22 */ { true, 0xbb22, 0xbb22 }, +/* 0xbb23 */ { true, 0xbb23, 0xbb23 }, +/* 0xbb24 */ { true, 0xbb24, 0xbb24 }, +/* 0xbb25 */ { true, 0xbb25, 0xbb25 }, +/* 0xbb26 */ { true, 0xbb26, 0xbb26 }, +/* 0xbb27 */ { true, 0xbb27, 0xbb27 }, +/* 0xbb28 */ { true, 0xbb28, 0xbb28 }, +/* 0xbb29 */ { true, 0xbb29, 0xbb29 }, +/* 0xbb2a */ { true, 0xbb2a, 0xbb2a }, +/* 0xbb2b */ { true, 0xbb2b, 0xbb2b }, +/* 0xbb2c */ { true, 0xbb2c, 0xbb2c }, +/* 0xbb2d */ { true, 0xbb2d, 0xbb2d }, +/* 0xbb2e */ { true, 0xbb2e, 0xbb2e }, +/* 0xbb2f */ { true, 0xbb2f, 0xbb2f }, +/* 0xbb30 */ { true, 0xbb30, 0xbb30 }, +/* 0xbb31 */ { true, 0xbb31, 0xbb31 }, +/* 0xbb32 */ { true, 0xbb32, 0xbb32 }, +/* 0xbb33 */ { true, 0xbb33, 0xbb33 }, +/* 0xbb34 */ { true, 0xbb34, 0xbb34 }, +/* 0xbb35 */ { true, 0xbb35, 0xbb35 }, +/* 0xbb36 */ { true, 0xbb36, 0xbb36 }, +/* 0xbb37 */ { true, 0xbb37, 0xbb37 }, +/* 0xbb38 */ { true, 0xbb38, 0xbb38 }, +/* 0xbb39 */ { true, 0xbb39, 0xbb39 }, +/* 0xbb3a */ { true, 0xbb3a, 0xbb3a }, +/* 0xbb3b */ { true, 0xbb3b, 0xbb3b }, +/* 0xbb3c */ { true, 0xbb3c, 0xbb3c }, +/* 0xbb3d */ { true, 0xbb3d, 0xbb3d }, +/* 0xbb3e */ { true, 0xbb3e, 0xbb3e }, +/* 0xbb3f */ { true, 0xbb3f, 0xbb3f }, +/* 0xbb40 */ { true, 0xbb40, 0xbb40 }, +/* 0xbb41 */ { true, 0xbb41, 0xbb41 }, +/* 0xbb42 */ { true, 0xbb42, 0xbb42 }, +/* 0xbb43 */ { true, 0xbb43, 0xbb43 }, +/* 0xbb44 */ { true, 0xbb44, 0xbb44 }, +/* 0xbb45 */ { true, 0xbb45, 0xbb45 }, +/* 0xbb46 */ { true, 0xbb46, 0xbb46 }, +/* 0xbb47 */ { true, 0xbb47, 0xbb47 }, +/* 0xbb48 */ { true, 0xbb48, 0xbb48 }, +/* 0xbb49 */ { true, 0xbb49, 0xbb49 }, +/* 0xbb4a */ { true, 0xbb4a, 0xbb4a }, +/* 0xbb4b */ { true, 0xbb4b, 0xbb4b }, +/* 0xbb4c */ { true, 0xbb4c, 0xbb4c }, +/* 0xbb4d */ { true, 0xbb4d, 0xbb4d }, +/* 0xbb4e */ { true, 0xbb4e, 0xbb4e }, +/* 0xbb4f */ { true, 0xbb4f, 0xbb4f }, +/* 0xbb50 */ { true, 0xbb50, 0xbb50 }, +/* 0xbb51 */ { true, 0xbb51, 0xbb51 }, +/* 0xbb52 */ { true, 0xbb52, 0xbb52 }, +/* 0xbb53 */ { true, 0xbb53, 0xbb53 }, +/* 0xbb54 */ { true, 0xbb54, 0xbb54 }, +/* 0xbb55 */ { true, 0xbb55, 0xbb55 }, +/* 0xbb56 */ { true, 0xbb56, 0xbb56 }, +/* 0xbb57 */ { true, 0xbb57, 0xbb57 }, +/* 0xbb58 */ { true, 0xbb58, 0xbb58 }, +/* 0xbb59 */ { true, 0xbb59, 0xbb59 }, +/* 0xbb5a */ { true, 0xbb5a, 0xbb5a }, +/* 0xbb5b */ { true, 0xbb5b, 0xbb5b }, +/* 0xbb5c */ { true, 0xbb5c, 0xbb5c }, +/* 0xbb5d */ { true, 0xbb5d, 0xbb5d }, +/* 0xbb5e */ { true, 0xbb5e, 0xbb5e }, +/* 0xbb5f */ { true, 0xbb5f, 0xbb5f }, +/* 0xbb60 */ { true, 0xbb60, 0xbb60 }, +/* 0xbb61 */ { true, 0xbb61, 0xbb61 }, +/* 0xbb62 */ { true, 0xbb62, 0xbb62 }, +/* 0xbb63 */ { true, 0xbb63, 0xbb63 }, +/* 0xbb64 */ { true, 0xbb64, 0xbb64 }, +/* 0xbb65 */ { true, 0xbb65, 0xbb65 }, +/* 0xbb66 */ { true, 0xbb66, 0xbb66 }, +/* 0xbb67 */ { true, 0xbb67, 0xbb67 }, +/* 0xbb68 */ { true, 0xbb68, 0xbb68 }, +/* 0xbb69 */ { true, 0xbb69, 0xbb69 }, +/* 0xbb6a */ { true, 0xbb6a, 0xbb6a }, +/* 0xbb6b */ { true, 0xbb6b, 0xbb6b }, +/* 0xbb6c */ { true, 0xbb6c, 0xbb6c }, +/* 0xbb6d */ { true, 0xbb6d, 0xbb6d }, +/* 0xbb6e */ { true, 0xbb6e, 0xbb6e }, +/* 0xbb6f */ { true, 0xbb6f, 0xbb6f }, +/* 0xbb70 */ { true, 0xbb70, 0xbb70 }, +/* 0xbb71 */ { true, 0xbb71, 0xbb71 }, +/* 0xbb72 */ { true, 0xbb72, 0xbb72 }, +/* 0xbb73 */ { true, 0xbb73, 0xbb73 }, +/* 0xbb74 */ { true, 0xbb74, 0xbb74 }, +/* 0xbb75 */ { true, 0xbb75, 0xbb75 }, +/* 0xbb76 */ { true, 0xbb76, 0xbb76 }, +/* 0xbb77 */ { true, 0xbb77, 0xbb77 }, +/* 0xbb78 */ { true, 0xbb78, 0xbb78 }, +/* 0xbb79 */ { true, 0xbb79, 0xbb79 }, +/* 0xbb7a */ { true, 0xbb7a, 0xbb7a }, +/* 0xbb7b */ { true, 0xbb7b, 0xbb7b }, +/* 0xbb7c */ { true, 0xbb7c, 0xbb7c }, +/* 0xbb7d */ { true, 0xbb7d, 0xbb7d }, +/* 0xbb7e */ { true, 0xbb7e, 0xbb7e }, +/* 0xbb7f */ { true, 0xbb7f, 0xbb7f }, +/* 0xbb80 */ { true, 0xbb80, 0xbb80 }, +/* 0xbb81 */ { true, 0xbb81, 0xbb81 }, +/* 0xbb82 */ { true, 0xbb82, 0xbb82 }, +/* 0xbb83 */ { true, 0xbb83, 0xbb83 }, +/* 0xbb84 */ { true, 0xbb84, 0xbb84 }, +/* 0xbb85 */ { true, 0xbb85, 0xbb85 }, +/* 0xbb86 */ { true, 0xbb86, 0xbb86 }, +/* 0xbb87 */ { true, 0xbb87, 0xbb87 }, +/* 0xbb88 */ { true, 0xbb88, 0xbb88 }, +/* 0xbb89 */ { true, 0xbb89, 0xbb89 }, +/* 0xbb8a */ { true, 0xbb8a, 0xbb8a }, +/* 0xbb8b */ { true, 0xbb8b, 0xbb8b }, +/* 0xbb8c */ { true, 0xbb8c, 0xbb8c }, +/* 0xbb8d */ { true, 0xbb8d, 0xbb8d }, +/* 0xbb8e */ { true, 0xbb8e, 0xbb8e }, +/* 0xbb8f */ { true, 0xbb8f, 0xbb8f }, +/* 0xbb90 */ { true, 0xbb90, 0xbb90 }, +/* 0xbb91 */ { true, 0xbb91, 0xbb91 }, +/* 0xbb92 */ { true, 0xbb92, 0xbb92 }, +/* 0xbb93 */ { true, 0xbb93, 0xbb93 }, +/* 0xbb94 */ { true, 0xbb94, 0xbb94 }, +/* 0xbb95 */ { true, 0xbb95, 0xbb95 }, +/* 0xbb96 */ { true, 0xbb96, 0xbb96 }, +/* 0xbb97 */ { true, 0xbb97, 0xbb97 }, +/* 0xbb98 */ { true, 0xbb98, 0xbb98 }, +/* 0xbb99 */ { true, 0xbb99, 0xbb99 }, +/* 0xbb9a */ { true, 0xbb9a, 0xbb9a }, +/* 0xbb9b */ { true, 0xbb9b, 0xbb9b }, +/* 0xbb9c */ { true, 0xbb9c, 0xbb9c }, +/* 0xbb9d */ { true, 0xbb9d, 0xbb9d }, +/* 0xbb9e */ { true, 0xbb9e, 0xbb9e }, +/* 0xbb9f */ { true, 0xbb9f, 0xbb9f }, +/* 0xbba0 */ { true, 0xbba0, 0xbba0 }, +/* 0xbba1 */ { true, 0xbba1, 0xbba1 }, +/* 0xbba2 */ { true, 0xbba2, 0xbba2 }, +/* 0xbba3 */ { true, 0xbba3, 0xbba3 }, +/* 0xbba4 */ { true, 0xbba4, 0xbba4 }, +/* 0xbba5 */ { true, 0xbba5, 0xbba5 }, +/* 0xbba6 */ { true, 0xbba6, 0xbba6 }, +/* 0xbba7 */ { true, 0xbba7, 0xbba7 }, +/* 0xbba8 */ { true, 0xbba8, 0xbba8 }, +/* 0xbba9 */ { true, 0xbba9, 0xbba9 }, +/* 0xbbaa */ { true, 0xbbaa, 0xbbaa }, +/* 0xbbab */ { true, 0xbbab, 0xbbab }, +/* 0xbbac */ { true, 0xbbac, 0xbbac }, +/* 0xbbad */ { true, 0xbbad, 0xbbad }, +/* 0xbbae */ { true, 0xbbae, 0xbbae }, +/* 0xbbaf */ { true, 0xbbaf, 0xbbaf }, +/* 0xbbb0 */ { true, 0xbbb0, 0xbbb0 }, +/* 0xbbb1 */ { true, 0xbbb1, 0xbbb1 }, +/* 0xbbb2 */ { true, 0xbbb2, 0xbbb2 }, +/* 0xbbb3 */ { true, 0xbbb3, 0xbbb3 }, +/* 0xbbb4 */ { true, 0xbbb4, 0xbbb4 }, +/* 0xbbb5 */ { true, 0xbbb5, 0xbbb5 }, +/* 0xbbb6 */ { true, 0xbbb6, 0xbbb6 }, +/* 0xbbb7 */ { true, 0xbbb7, 0xbbb7 }, +/* 0xbbb8 */ { true, 0xbbb8, 0xbbb8 }, +/* 0xbbb9 */ { true, 0xbbb9, 0xbbb9 }, +/* 0xbbba */ { true, 0xbbba, 0xbbba }, +/* 0xbbbb */ { true, 0xbbbb, 0xbbbb }, +/* 0xbbbc */ { true, 0xbbbc, 0xbbbc }, +/* 0xbbbd */ { true, 0xbbbd, 0xbbbd }, +/* 0xbbbe */ { true, 0xbbbe, 0xbbbe }, +/* 0xbbbf */ { true, 0xbbbf, 0xbbbf }, +/* 0xbbc0 */ { true, 0xbbc0, 0xbbc0 }, +/* 0xbbc1 */ { true, 0xbbc1, 0xbbc1 }, +/* 0xbbc2 */ { true, 0xbbc2, 0xbbc2 }, +/* 0xbbc3 */ { true, 0xbbc3, 0xbbc3 }, +/* 0xbbc4 */ { true, 0xbbc4, 0xbbc4 }, +/* 0xbbc5 */ { true, 0xbbc5, 0xbbc5 }, +/* 0xbbc6 */ { true, 0xbbc6, 0xbbc6 }, +/* 0xbbc7 */ { true, 0xbbc7, 0xbbc7 }, +/* 0xbbc8 */ { true, 0xbbc8, 0xbbc8 }, +/* 0xbbc9 */ { true, 0xbbc9, 0xbbc9 }, +/* 0xbbca */ { true, 0xbbca, 0xbbca }, +/* 0xbbcb */ { true, 0xbbcb, 0xbbcb }, +/* 0xbbcc */ { true, 0xbbcc, 0xbbcc }, +/* 0xbbcd */ { true, 0xbbcd, 0xbbcd }, +/* 0xbbce */ { true, 0xbbce, 0xbbce }, +/* 0xbbcf */ { true, 0xbbcf, 0xbbcf }, +/* 0xbbd0 */ { true, 0xbbd0, 0xbbd0 }, +/* 0xbbd1 */ { true, 0xbbd1, 0xbbd1 }, +/* 0xbbd2 */ { true, 0xbbd2, 0xbbd2 }, +/* 0xbbd3 */ { true, 0xbbd3, 0xbbd3 }, +/* 0xbbd4 */ { true, 0xbbd4, 0xbbd4 }, +/* 0xbbd5 */ { true, 0xbbd5, 0xbbd5 }, +/* 0xbbd6 */ { true, 0xbbd6, 0xbbd6 }, +/* 0xbbd7 */ { true, 0xbbd7, 0xbbd7 }, +/* 0xbbd8 */ { true, 0xbbd8, 0xbbd8 }, +/* 0xbbd9 */ { true, 0xbbd9, 0xbbd9 }, +/* 0xbbda */ { true, 0xbbda, 0xbbda }, +/* 0xbbdb */ { true, 0xbbdb, 0xbbdb }, +/* 0xbbdc */ { true, 0xbbdc, 0xbbdc }, +/* 0xbbdd */ { true, 0xbbdd, 0xbbdd }, +/* 0xbbde */ { true, 0xbbde, 0xbbde }, +/* 0xbbdf */ { true, 0xbbdf, 0xbbdf }, +/* 0xbbe0 */ { true, 0xbbe0, 0xbbe0 }, +/* 0xbbe1 */ { true, 0xbbe1, 0xbbe1 }, +/* 0xbbe2 */ { true, 0xbbe2, 0xbbe2 }, +/* 0xbbe3 */ { true, 0xbbe3, 0xbbe3 }, +/* 0xbbe4 */ { true, 0xbbe4, 0xbbe4 }, +/* 0xbbe5 */ { true, 0xbbe5, 0xbbe5 }, +/* 0xbbe6 */ { true, 0xbbe6, 0xbbe6 }, +/* 0xbbe7 */ { true, 0xbbe7, 0xbbe7 }, +/* 0xbbe8 */ { true, 0xbbe8, 0xbbe8 }, +/* 0xbbe9 */ { true, 0xbbe9, 0xbbe9 }, +/* 0xbbea */ { true, 0xbbea, 0xbbea }, +/* 0xbbeb */ { true, 0xbbeb, 0xbbeb }, +/* 0xbbec */ { true, 0xbbec, 0xbbec }, +/* 0xbbed */ { true, 0xbbed, 0xbbed }, +/* 0xbbee */ { true, 0xbbee, 0xbbee }, +/* 0xbbef */ { true, 0xbbef, 0xbbef }, +/* 0xbbf0 */ { true, 0xbbf0, 0xbbf0 }, +/* 0xbbf1 */ { true, 0xbbf1, 0xbbf1 }, +/* 0xbbf2 */ { true, 0xbbf2, 0xbbf2 }, +/* 0xbbf3 */ { true, 0xbbf3, 0xbbf3 }, +/* 0xbbf4 */ { true, 0xbbf4, 0xbbf4 }, +/* 0xbbf5 */ { true, 0xbbf5, 0xbbf5 }, +/* 0xbbf6 */ { true, 0xbbf6, 0xbbf6 }, +/* 0xbbf7 */ { true, 0xbbf7, 0xbbf7 }, +/* 0xbbf8 */ { true, 0xbbf8, 0xbbf8 }, +/* 0xbbf9 */ { true, 0xbbf9, 0xbbf9 }, +/* 0xbbfa */ { true, 0xbbfa, 0xbbfa }, +/* 0xbbfb */ { true, 0xbbfb, 0xbbfb }, +/* 0xbbfc */ { true, 0xbbfc, 0xbbfc }, +/* 0xbbfd */ { true, 0xbbfd, 0xbbfd }, +/* 0xbbfe */ { true, 0xbbfe, 0xbbfe }, +/* 0xbbff */ { true, 0xbbff, 0xbbff }, +/* 0xbc00 */ { true, 0xbc00, 0xbc00 }, +/* 0xbc01 */ { true, 0xbc01, 0xbc01 }, +/* 0xbc02 */ { true, 0xbc02, 0xbc02 }, +/* 0xbc03 */ { true, 0xbc03, 0xbc03 }, +/* 0xbc04 */ { true, 0xbc04, 0xbc04 }, +/* 0xbc05 */ { true, 0xbc05, 0xbc05 }, +/* 0xbc06 */ { true, 0xbc06, 0xbc06 }, +/* 0xbc07 */ { true, 0xbc07, 0xbc07 }, +/* 0xbc08 */ { true, 0xbc08, 0xbc08 }, +/* 0xbc09 */ { true, 0xbc09, 0xbc09 }, +/* 0xbc0a */ { true, 0xbc0a, 0xbc0a }, +/* 0xbc0b */ { true, 0xbc0b, 0xbc0b }, +/* 0xbc0c */ { true, 0xbc0c, 0xbc0c }, +/* 0xbc0d */ { true, 0xbc0d, 0xbc0d }, +/* 0xbc0e */ { true, 0xbc0e, 0xbc0e }, +/* 0xbc0f */ { true, 0xbc0f, 0xbc0f }, +/* 0xbc10 */ { true, 0xbc10, 0xbc10 }, +/* 0xbc11 */ { true, 0xbc11, 0xbc11 }, +/* 0xbc12 */ { true, 0xbc12, 0xbc12 }, +/* 0xbc13 */ { true, 0xbc13, 0xbc13 }, +/* 0xbc14 */ { true, 0xbc14, 0xbc14 }, +/* 0xbc15 */ { true, 0xbc15, 0xbc15 }, +/* 0xbc16 */ { true, 0xbc16, 0xbc16 }, +/* 0xbc17 */ { true, 0xbc17, 0xbc17 }, +/* 0xbc18 */ { true, 0xbc18, 0xbc18 }, +/* 0xbc19 */ { true, 0xbc19, 0xbc19 }, +/* 0xbc1a */ { true, 0xbc1a, 0xbc1a }, +/* 0xbc1b */ { true, 0xbc1b, 0xbc1b }, +/* 0xbc1c */ { true, 0xbc1c, 0xbc1c }, +/* 0xbc1d */ { true, 0xbc1d, 0xbc1d }, +/* 0xbc1e */ { true, 0xbc1e, 0xbc1e }, +/* 0xbc1f */ { true, 0xbc1f, 0xbc1f }, +/* 0xbc20 */ { true, 0xbc20, 0xbc20 }, +/* 0xbc21 */ { true, 0xbc21, 0xbc21 }, +/* 0xbc22 */ { true, 0xbc22, 0xbc22 }, +/* 0xbc23 */ { true, 0xbc23, 0xbc23 }, +/* 0xbc24 */ { true, 0xbc24, 0xbc24 }, +/* 0xbc25 */ { true, 0xbc25, 0xbc25 }, +/* 0xbc26 */ { true, 0xbc26, 0xbc26 }, +/* 0xbc27 */ { true, 0xbc27, 0xbc27 }, +/* 0xbc28 */ { true, 0xbc28, 0xbc28 }, +/* 0xbc29 */ { true, 0xbc29, 0xbc29 }, +/* 0xbc2a */ { true, 0xbc2a, 0xbc2a }, +/* 0xbc2b */ { true, 0xbc2b, 0xbc2b }, +/* 0xbc2c */ { true, 0xbc2c, 0xbc2c }, +/* 0xbc2d */ { true, 0xbc2d, 0xbc2d }, +/* 0xbc2e */ { true, 0xbc2e, 0xbc2e }, +/* 0xbc2f */ { true, 0xbc2f, 0xbc2f }, +/* 0xbc30 */ { true, 0xbc30, 0xbc30 }, +/* 0xbc31 */ { true, 0xbc31, 0xbc31 }, +/* 0xbc32 */ { true, 0xbc32, 0xbc32 }, +/* 0xbc33 */ { true, 0xbc33, 0xbc33 }, +/* 0xbc34 */ { true, 0xbc34, 0xbc34 }, +/* 0xbc35 */ { true, 0xbc35, 0xbc35 }, +/* 0xbc36 */ { true, 0xbc36, 0xbc36 }, +/* 0xbc37 */ { true, 0xbc37, 0xbc37 }, +/* 0xbc38 */ { true, 0xbc38, 0xbc38 }, +/* 0xbc39 */ { true, 0xbc39, 0xbc39 }, +/* 0xbc3a */ { true, 0xbc3a, 0xbc3a }, +/* 0xbc3b */ { true, 0xbc3b, 0xbc3b }, +/* 0xbc3c */ { true, 0xbc3c, 0xbc3c }, +/* 0xbc3d */ { true, 0xbc3d, 0xbc3d }, +/* 0xbc3e */ { true, 0xbc3e, 0xbc3e }, +/* 0xbc3f */ { true, 0xbc3f, 0xbc3f }, +/* 0xbc40 */ { true, 0xbc40, 0xbc40 }, +/* 0xbc41 */ { true, 0xbc41, 0xbc41 }, +/* 0xbc42 */ { true, 0xbc42, 0xbc42 }, +/* 0xbc43 */ { true, 0xbc43, 0xbc43 }, +/* 0xbc44 */ { true, 0xbc44, 0xbc44 }, +/* 0xbc45 */ { true, 0xbc45, 0xbc45 }, +/* 0xbc46 */ { true, 0xbc46, 0xbc46 }, +/* 0xbc47 */ { true, 0xbc47, 0xbc47 }, +/* 0xbc48 */ { true, 0xbc48, 0xbc48 }, +/* 0xbc49 */ { true, 0xbc49, 0xbc49 }, +/* 0xbc4a */ { true, 0xbc4a, 0xbc4a }, +/* 0xbc4b */ { true, 0xbc4b, 0xbc4b }, +/* 0xbc4c */ { true, 0xbc4c, 0xbc4c }, +/* 0xbc4d */ { true, 0xbc4d, 0xbc4d }, +/* 0xbc4e */ { true, 0xbc4e, 0xbc4e }, +/* 0xbc4f */ { true, 0xbc4f, 0xbc4f }, +/* 0xbc50 */ { true, 0xbc50, 0xbc50 }, +/* 0xbc51 */ { true, 0xbc51, 0xbc51 }, +/* 0xbc52 */ { true, 0xbc52, 0xbc52 }, +/* 0xbc53 */ { true, 0xbc53, 0xbc53 }, +/* 0xbc54 */ { true, 0xbc54, 0xbc54 }, +/* 0xbc55 */ { true, 0xbc55, 0xbc55 }, +/* 0xbc56 */ { true, 0xbc56, 0xbc56 }, +/* 0xbc57 */ { true, 0xbc57, 0xbc57 }, +/* 0xbc58 */ { true, 0xbc58, 0xbc58 }, +/* 0xbc59 */ { true, 0xbc59, 0xbc59 }, +/* 0xbc5a */ { true, 0xbc5a, 0xbc5a }, +/* 0xbc5b */ { true, 0xbc5b, 0xbc5b }, +/* 0xbc5c */ { true, 0xbc5c, 0xbc5c }, +/* 0xbc5d */ { true, 0xbc5d, 0xbc5d }, +/* 0xbc5e */ { true, 0xbc5e, 0xbc5e }, +/* 0xbc5f */ { true, 0xbc5f, 0xbc5f }, +/* 0xbc60 */ { true, 0xbc60, 0xbc60 }, +/* 0xbc61 */ { true, 0xbc61, 0xbc61 }, +/* 0xbc62 */ { true, 0xbc62, 0xbc62 }, +/* 0xbc63 */ { true, 0xbc63, 0xbc63 }, +/* 0xbc64 */ { true, 0xbc64, 0xbc64 }, +/* 0xbc65 */ { true, 0xbc65, 0xbc65 }, +/* 0xbc66 */ { true, 0xbc66, 0xbc66 }, +/* 0xbc67 */ { true, 0xbc67, 0xbc67 }, +/* 0xbc68 */ { true, 0xbc68, 0xbc68 }, +/* 0xbc69 */ { true, 0xbc69, 0xbc69 }, +/* 0xbc6a */ { true, 0xbc6a, 0xbc6a }, +/* 0xbc6b */ { true, 0xbc6b, 0xbc6b }, +/* 0xbc6c */ { true, 0xbc6c, 0xbc6c }, +/* 0xbc6d */ { true, 0xbc6d, 0xbc6d }, +/* 0xbc6e */ { true, 0xbc6e, 0xbc6e }, +/* 0xbc6f */ { true, 0xbc6f, 0xbc6f }, +/* 0xbc70 */ { true, 0xbc70, 0xbc70 }, +/* 0xbc71 */ { true, 0xbc71, 0xbc71 }, +/* 0xbc72 */ { true, 0xbc72, 0xbc72 }, +/* 0xbc73 */ { true, 0xbc73, 0xbc73 }, +/* 0xbc74 */ { true, 0xbc74, 0xbc74 }, +/* 0xbc75 */ { true, 0xbc75, 0xbc75 }, +/* 0xbc76 */ { true, 0xbc76, 0xbc76 }, +/* 0xbc77 */ { true, 0xbc77, 0xbc77 }, +/* 0xbc78 */ { true, 0xbc78, 0xbc78 }, +/* 0xbc79 */ { true, 0xbc79, 0xbc79 }, +/* 0xbc7a */ { true, 0xbc7a, 0xbc7a }, +/* 0xbc7b */ { true, 0xbc7b, 0xbc7b }, +/* 0xbc7c */ { true, 0xbc7c, 0xbc7c }, +/* 0xbc7d */ { true, 0xbc7d, 0xbc7d }, +/* 0xbc7e */ { true, 0xbc7e, 0xbc7e }, +/* 0xbc7f */ { true, 0xbc7f, 0xbc7f }, +/* 0xbc80 */ { true, 0xbc80, 0xbc80 }, +/* 0xbc81 */ { true, 0xbc81, 0xbc81 }, +/* 0xbc82 */ { true, 0xbc82, 0xbc82 }, +/* 0xbc83 */ { true, 0xbc83, 0xbc83 }, +/* 0xbc84 */ { true, 0xbc84, 0xbc84 }, +/* 0xbc85 */ { true, 0xbc85, 0xbc85 }, +/* 0xbc86 */ { true, 0xbc86, 0xbc86 }, +/* 0xbc87 */ { true, 0xbc87, 0xbc87 }, +/* 0xbc88 */ { true, 0xbc88, 0xbc88 }, +/* 0xbc89 */ { true, 0xbc89, 0xbc89 }, +/* 0xbc8a */ { true, 0xbc8a, 0xbc8a }, +/* 0xbc8b */ { true, 0xbc8b, 0xbc8b }, +/* 0xbc8c */ { true, 0xbc8c, 0xbc8c }, +/* 0xbc8d */ { true, 0xbc8d, 0xbc8d }, +/* 0xbc8e */ { true, 0xbc8e, 0xbc8e }, +/* 0xbc8f */ { true, 0xbc8f, 0xbc8f }, +/* 0xbc90 */ { true, 0xbc90, 0xbc90 }, +/* 0xbc91 */ { true, 0xbc91, 0xbc91 }, +/* 0xbc92 */ { true, 0xbc92, 0xbc92 }, +/* 0xbc93 */ { true, 0xbc93, 0xbc93 }, +/* 0xbc94 */ { true, 0xbc94, 0xbc94 }, +/* 0xbc95 */ { true, 0xbc95, 0xbc95 }, +/* 0xbc96 */ { true, 0xbc96, 0xbc96 }, +/* 0xbc97 */ { true, 0xbc97, 0xbc97 }, +/* 0xbc98 */ { true, 0xbc98, 0xbc98 }, +/* 0xbc99 */ { true, 0xbc99, 0xbc99 }, +/* 0xbc9a */ { true, 0xbc9a, 0xbc9a }, +/* 0xbc9b */ { true, 0xbc9b, 0xbc9b }, +/* 0xbc9c */ { true, 0xbc9c, 0xbc9c }, +/* 0xbc9d */ { true, 0xbc9d, 0xbc9d }, +/* 0xbc9e */ { true, 0xbc9e, 0xbc9e }, +/* 0xbc9f */ { true, 0xbc9f, 0xbc9f }, +/* 0xbca0 */ { true, 0xbca0, 0xbca0 }, +/* 0xbca1 */ { true, 0xbca1, 0xbca1 }, +/* 0xbca2 */ { true, 0xbca2, 0xbca2 }, +/* 0xbca3 */ { true, 0xbca3, 0xbca3 }, +/* 0xbca4 */ { true, 0xbca4, 0xbca4 }, +/* 0xbca5 */ { true, 0xbca5, 0xbca5 }, +/* 0xbca6 */ { true, 0xbca6, 0xbca6 }, +/* 0xbca7 */ { true, 0xbca7, 0xbca7 }, +/* 0xbca8 */ { true, 0xbca8, 0xbca8 }, +/* 0xbca9 */ { true, 0xbca9, 0xbca9 }, +/* 0xbcaa */ { true, 0xbcaa, 0xbcaa }, +/* 0xbcab */ { true, 0xbcab, 0xbcab }, +/* 0xbcac */ { true, 0xbcac, 0xbcac }, +/* 0xbcad */ { true, 0xbcad, 0xbcad }, +/* 0xbcae */ { true, 0xbcae, 0xbcae }, +/* 0xbcaf */ { true, 0xbcaf, 0xbcaf }, +/* 0xbcb0 */ { true, 0xbcb0, 0xbcb0 }, +/* 0xbcb1 */ { true, 0xbcb1, 0xbcb1 }, +/* 0xbcb2 */ { true, 0xbcb2, 0xbcb2 }, +/* 0xbcb3 */ { true, 0xbcb3, 0xbcb3 }, +/* 0xbcb4 */ { true, 0xbcb4, 0xbcb4 }, +/* 0xbcb5 */ { true, 0xbcb5, 0xbcb5 }, +/* 0xbcb6 */ { true, 0xbcb6, 0xbcb6 }, +/* 0xbcb7 */ { true, 0xbcb7, 0xbcb7 }, +/* 0xbcb8 */ { true, 0xbcb8, 0xbcb8 }, +/* 0xbcb9 */ { true, 0xbcb9, 0xbcb9 }, +/* 0xbcba */ { true, 0xbcba, 0xbcba }, +/* 0xbcbb */ { true, 0xbcbb, 0xbcbb }, +/* 0xbcbc */ { true, 0xbcbc, 0xbcbc }, +/* 0xbcbd */ { true, 0xbcbd, 0xbcbd }, +/* 0xbcbe */ { true, 0xbcbe, 0xbcbe }, +/* 0xbcbf */ { true, 0xbcbf, 0xbcbf }, +/* 0xbcc0 */ { true, 0xbcc0, 0xbcc0 }, +/* 0xbcc1 */ { true, 0xbcc1, 0xbcc1 }, +/* 0xbcc2 */ { true, 0xbcc2, 0xbcc2 }, +/* 0xbcc3 */ { true, 0xbcc3, 0xbcc3 }, +/* 0xbcc4 */ { true, 0xbcc4, 0xbcc4 }, +/* 0xbcc5 */ { true, 0xbcc5, 0xbcc5 }, +/* 0xbcc6 */ { true, 0xbcc6, 0xbcc6 }, +/* 0xbcc7 */ { true, 0xbcc7, 0xbcc7 }, +/* 0xbcc8 */ { true, 0xbcc8, 0xbcc8 }, +/* 0xbcc9 */ { true, 0xbcc9, 0xbcc9 }, +/* 0xbcca */ { true, 0xbcca, 0xbcca }, +/* 0xbccb */ { true, 0xbccb, 0xbccb }, +/* 0xbccc */ { true, 0xbccc, 0xbccc }, +/* 0xbccd */ { true, 0xbccd, 0xbccd }, +/* 0xbcce */ { true, 0xbcce, 0xbcce }, +/* 0xbccf */ { true, 0xbccf, 0xbccf }, +/* 0xbcd0 */ { true, 0xbcd0, 0xbcd0 }, +/* 0xbcd1 */ { true, 0xbcd1, 0xbcd1 }, +/* 0xbcd2 */ { true, 0xbcd2, 0xbcd2 }, +/* 0xbcd3 */ { true, 0xbcd3, 0xbcd3 }, +/* 0xbcd4 */ { true, 0xbcd4, 0xbcd4 }, +/* 0xbcd5 */ { true, 0xbcd5, 0xbcd5 }, +/* 0xbcd6 */ { true, 0xbcd6, 0xbcd6 }, +/* 0xbcd7 */ { true, 0xbcd7, 0xbcd7 }, +/* 0xbcd8 */ { true, 0xbcd8, 0xbcd8 }, +/* 0xbcd9 */ { true, 0xbcd9, 0xbcd9 }, +/* 0xbcda */ { true, 0xbcda, 0xbcda }, +/* 0xbcdb */ { true, 0xbcdb, 0xbcdb }, +/* 0xbcdc */ { true, 0xbcdc, 0xbcdc }, +/* 0xbcdd */ { true, 0xbcdd, 0xbcdd }, +/* 0xbcde */ { true, 0xbcde, 0xbcde }, +/* 0xbcdf */ { true, 0xbcdf, 0xbcdf }, +/* 0xbce0 */ { true, 0xbce0, 0xbce0 }, +/* 0xbce1 */ { true, 0xbce1, 0xbce1 }, +/* 0xbce2 */ { true, 0xbce2, 0xbce2 }, +/* 0xbce3 */ { true, 0xbce3, 0xbce3 }, +/* 0xbce4 */ { true, 0xbce4, 0xbce4 }, +/* 0xbce5 */ { true, 0xbce5, 0xbce5 }, +/* 0xbce6 */ { true, 0xbce6, 0xbce6 }, +/* 0xbce7 */ { true, 0xbce7, 0xbce7 }, +/* 0xbce8 */ { true, 0xbce8, 0xbce8 }, +/* 0xbce9 */ { true, 0xbce9, 0xbce9 }, +/* 0xbcea */ { true, 0xbcea, 0xbcea }, +/* 0xbceb */ { true, 0xbceb, 0xbceb }, +/* 0xbcec */ { true, 0xbcec, 0xbcec }, +/* 0xbced */ { true, 0xbced, 0xbced }, +/* 0xbcee */ { true, 0xbcee, 0xbcee }, +/* 0xbcef */ { true, 0xbcef, 0xbcef }, +/* 0xbcf0 */ { true, 0xbcf0, 0xbcf0 }, +/* 0xbcf1 */ { true, 0xbcf1, 0xbcf1 }, +/* 0xbcf2 */ { true, 0xbcf2, 0xbcf2 }, +/* 0xbcf3 */ { true, 0xbcf3, 0xbcf3 }, +/* 0xbcf4 */ { true, 0xbcf4, 0xbcf4 }, +/* 0xbcf5 */ { true, 0xbcf5, 0xbcf5 }, +/* 0xbcf6 */ { true, 0xbcf6, 0xbcf6 }, +/* 0xbcf7 */ { true, 0xbcf7, 0xbcf7 }, +/* 0xbcf8 */ { true, 0xbcf8, 0xbcf8 }, +/* 0xbcf9 */ { true, 0xbcf9, 0xbcf9 }, +/* 0xbcfa */ { true, 0xbcfa, 0xbcfa }, +/* 0xbcfb */ { true, 0xbcfb, 0xbcfb }, +/* 0xbcfc */ { true, 0xbcfc, 0xbcfc }, +/* 0xbcfd */ { true, 0xbcfd, 0xbcfd }, +/* 0xbcfe */ { true, 0xbcfe, 0xbcfe }, +/* 0xbcff */ { true, 0xbcff, 0xbcff }, +/* 0xbd00 */ { true, 0xbd00, 0xbd00 }, +/* 0xbd01 */ { true, 0xbd01, 0xbd01 }, +/* 0xbd02 */ { true, 0xbd02, 0xbd02 }, +/* 0xbd03 */ { true, 0xbd03, 0xbd03 }, +/* 0xbd04 */ { true, 0xbd04, 0xbd04 }, +/* 0xbd05 */ { true, 0xbd05, 0xbd05 }, +/* 0xbd06 */ { true, 0xbd06, 0xbd06 }, +/* 0xbd07 */ { true, 0xbd07, 0xbd07 }, +/* 0xbd08 */ { true, 0xbd08, 0xbd08 }, +/* 0xbd09 */ { true, 0xbd09, 0xbd09 }, +/* 0xbd0a */ { true, 0xbd0a, 0xbd0a }, +/* 0xbd0b */ { true, 0xbd0b, 0xbd0b }, +/* 0xbd0c */ { true, 0xbd0c, 0xbd0c }, +/* 0xbd0d */ { true, 0xbd0d, 0xbd0d }, +/* 0xbd0e */ { true, 0xbd0e, 0xbd0e }, +/* 0xbd0f */ { true, 0xbd0f, 0xbd0f }, +/* 0xbd10 */ { true, 0xbd10, 0xbd10 }, +/* 0xbd11 */ { true, 0xbd11, 0xbd11 }, +/* 0xbd12 */ { true, 0xbd12, 0xbd12 }, +/* 0xbd13 */ { true, 0xbd13, 0xbd13 }, +/* 0xbd14 */ { true, 0xbd14, 0xbd14 }, +/* 0xbd15 */ { true, 0xbd15, 0xbd15 }, +/* 0xbd16 */ { true, 0xbd16, 0xbd16 }, +/* 0xbd17 */ { true, 0xbd17, 0xbd17 }, +/* 0xbd18 */ { true, 0xbd18, 0xbd18 }, +/* 0xbd19 */ { true, 0xbd19, 0xbd19 }, +/* 0xbd1a */ { true, 0xbd1a, 0xbd1a }, +/* 0xbd1b */ { true, 0xbd1b, 0xbd1b }, +/* 0xbd1c */ { true, 0xbd1c, 0xbd1c }, +/* 0xbd1d */ { true, 0xbd1d, 0xbd1d }, +/* 0xbd1e */ { true, 0xbd1e, 0xbd1e }, +/* 0xbd1f */ { true, 0xbd1f, 0xbd1f }, +/* 0xbd20 */ { true, 0xbd20, 0xbd20 }, +/* 0xbd21 */ { true, 0xbd21, 0xbd21 }, +/* 0xbd22 */ { true, 0xbd22, 0xbd22 }, +/* 0xbd23 */ { true, 0xbd23, 0xbd23 }, +/* 0xbd24 */ { true, 0xbd24, 0xbd24 }, +/* 0xbd25 */ { true, 0xbd25, 0xbd25 }, +/* 0xbd26 */ { true, 0xbd26, 0xbd26 }, +/* 0xbd27 */ { true, 0xbd27, 0xbd27 }, +/* 0xbd28 */ { true, 0xbd28, 0xbd28 }, +/* 0xbd29 */ { true, 0xbd29, 0xbd29 }, +/* 0xbd2a */ { true, 0xbd2a, 0xbd2a }, +/* 0xbd2b */ { true, 0xbd2b, 0xbd2b }, +/* 0xbd2c */ { true, 0xbd2c, 0xbd2c }, +/* 0xbd2d */ { true, 0xbd2d, 0xbd2d }, +/* 0xbd2e */ { true, 0xbd2e, 0xbd2e }, +/* 0xbd2f */ { true, 0xbd2f, 0xbd2f }, +/* 0xbd30 */ { true, 0xbd30, 0xbd30 }, +/* 0xbd31 */ { true, 0xbd31, 0xbd31 }, +/* 0xbd32 */ { true, 0xbd32, 0xbd32 }, +/* 0xbd33 */ { true, 0xbd33, 0xbd33 }, +/* 0xbd34 */ { true, 0xbd34, 0xbd34 }, +/* 0xbd35 */ { true, 0xbd35, 0xbd35 }, +/* 0xbd36 */ { true, 0xbd36, 0xbd36 }, +/* 0xbd37 */ { true, 0xbd37, 0xbd37 }, +/* 0xbd38 */ { true, 0xbd38, 0xbd38 }, +/* 0xbd39 */ { true, 0xbd39, 0xbd39 }, +/* 0xbd3a */ { true, 0xbd3a, 0xbd3a }, +/* 0xbd3b */ { true, 0xbd3b, 0xbd3b }, +/* 0xbd3c */ { true, 0xbd3c, 0xbd3c }, +/* 0xbd3d */ { true, 0xbd3d, 0xbd3d }, +/* 0xbd3e */ { true, 0xbd3e, 0xbd3e }, +/* 0xbd3f */ { true, 0xbd3f, 0xbd3f }, +/* 0xbd40 */ { true, 0xbd40, 0xbd40 }, +/* 0xbd41 */ { true, 0xbd41, 0xbd41 }, +/* 0xbd42 */ { true, 0xbd42, 0xbd42 }, +/* 0xbd43 */ { true, 0xbd43, 0xbd43 }, +/* 0xbd44 */ { true, 0xbd44, 0xbd44 }, +/* 0xbd45 */ { true, 0xbd45, 0xbd45 }, +/* 0xbd46 */ { true, 0xbd46, 0xbd46 }, +/* 0xbd47 */ { true, 0xbd47, 0xbd47 }, +/* 0xbd48 */ { true, 0xbd48, 0xbd48 }, +/* 0xbd49 */ { true, 0xbd49, 0xbd49 }, +/* 0xbd4a */ { true, 0xbd4a, 0xbd4a }, +/* 0xbd4b */ { true, 0xbd4b, 0xbd4b }, +/* 0xbd4c */ { true, 0xbd4c, 0xbd4c }, +/* 0xbd4d */ { true, 0xbd4d, 0xbd4d }, +/* 0xbd4e */ { true, 0xbd4e, 0xbd4e }, +/* 0xbd4f */ { true, 0xbd4f, 0xbd4f }, +/* 0xbd50 */ { true, 0xbd50, 0xbd50 }, +/* 0xbd51 */ { true, 0xbd51, 0xbd51 }, +/* 0xbd52 */ { true, 0xbd52, 0xbd52 }, +/* 0xbd53 */ { true, 0xbd53, 0xbd53 }, +/* 0xbd54 */ { true, 0xbd54, 0xbd54 }, +/* 0xbd55 */ { true, 0xbd55, 0xbd55 }, +/* 0xbd56 */ { true, 0xbd56, 0xbd56 }, +/* 0xbd57 */ { true, 0xbd57, 0xbd57 }, +/* 0xbd58 */ { true, 0xbd58, 0xbd58 }, +/* 0xbd59 */ { true, 0xbd59, 0xbd59 }, +/* 0xbd5a */ { true, 0xbd5a, 0xbd5a }, +/* 0xbd5b */ { true, 0xbd5b, 0xbd5b }, +/* 0xbd5c */ { true, 0xbd5c, 0xbd5c }, +/* 0xbd5d */ { true, 0xbd5d, 0xbd5d }, +/* 0xbd5e */ { true, 0xbd5e, 0xbd5e }, +/* 0xbd5f */ { true, 0xbd5f, 0xbd5f }, +/* 0xbd60 */ { true, 0xbd60, 0xbd60 }, +/* 0xbd61 */ { true, 0xbd61, 0xbd61 }, +/* 0xbd62 */ { true, 0xbd62, 0xbd62 }, +/* 0xbd63 */ { true, 0xbd63, 0xbd63 }, +/* 0xbd64 */ { true, 0xbd64, 0xbd64 }, +/* 0xbd65 */ { true, 0xbd65, 0xbd65 }, +/* 0xbd66 */ { true, 0xbd66, 0xbd66 }, +/* 0xbd67 */ { true, 0xbd67, 0xbd67 }, +/* 0xbd68 */ { true, 0xbd68, 0xbd68 }, +/* 0xbd69 */ { true, 0xbd69, 0xbd69 }, +/* 0xbd6a */ { true, 0xbd6a, 0xbd6a }, +/* 0xbd6b */ { true, 0xbd6b, 0xbd6b }, +/* 0xbd6c */ { true, 0xbd6c, 0xbd6c }, +/* 0xbd6d */ { true, 0xbd6d, 0xbd6d }, +/* 0xbd6e */ { true, 0xbd6e, 0xbd6e }, +/* 0xbd6f */ { true, 0xbd6f, 0xbd6f }, +/* 0xbd70 */ { true, 0xbd70, 0xbd70 }, +/* 0xbd71 */ { true, 0xbd71, 0xbd71 }, +/* 0xbd72 */ { true, 0xbd72, 0xbd72 }, +/* 0xbd73 */ { true, 0xbd73, 0xbd73 }, +/* 0xbd74 */ { true, 0xbd74, 0xbd74 }, +/* 0xbd75 */ { true, 0xbd75, 0xbd75 }, +/* 0xbd76 */ { true, 0xbd76, 0xbd76 }, +/* 0xbd77 */ { true, 0xbd77, 0xbd77 }, +/* 0xbd78 */ { true, 0xbd78, 0xbd78 }, +/* 0xbd79 */ { true, 0xbd79, 0xbd79 }, +/* 0xbd7a */ { true, 0xbd7a, 0xbd7a }, +/* 0xbd7b */ { true, 0xbd7b, 0xbd7b }, +/* 0xbd7c */ { true, 0xbd7c, 0xbd7c }, +/* 0xbd7d */ { true, 0xbd7d, 0xbd7d }, +/* 0xbd7e */ { true, 0xbd7e, 0xbd7e }, +/* 0xbd7f */ { true, 0xbd7f, 0xbd7f }, +/* 0xbd80 */ { true, 0xbd80, 0xbd80 }, +/* 0xbd81 */ { true, 0xbd81, 0xbd81 }, +/* 0xbd82 */ { true, 0xbd82, 0xbd82 }, +/* 0xbd83 */ { true, 0xbd83, 0xbd83 }, +/* 0xbd84 */ { true, 0xbd84, 0xbd84 }, +/* 0xbd85 */ { true, 0xbd85, 0xbd85 }, +/* 0xbd86 */ { true, 0xbd86, 0xbd86 }, +/* 0xbd87 */ { true, 0xbd87, 0xbd87 }, +/* 0xbd88 */ { true, 0xbd88, 0xbd88 }, +/* 0xbd89 */ { true, 0xbd89, 0xbd89 }, +/* 0xbd8a */ { true, 0xbd8a, 0xbd8a }, +/* 0xbd8b */ { true, 0xbd8b, 0xbd8b }, +/* 0xbd8c */ { true, 0xbd8c, 0xbd8c }, +/* 0xbd8d */ { true, 0xbd8d, 0xbd8d }, +/* 0xbd8e */ { true, 0xbd8e, 0xbd8e }, +/* 0xbd8f */ { true, 0xbd8f, 0xbd8f }, +/* 0xbd90 */ { true, 0xbd90, 0xbd90 }, +/* 0xbd91 */ { true, 0xbd91, 0xbd91 }, +/* 0xbd92 */ { true, 0xbd92, 0xbd92 }, +/* 0xbd93 */ { true, 0xbd93, 0xbd93 }, +/* 0xbd94 */ { true, 0xbd94, 0xbd94 }, +/* 0xbd95 */ { true, 0xbd95, 0xbd95 }, +/* 0xbd96 */ { true, 0xbd96, 0xbd96 }, +/* 0xbd97 */ { true, 0xbd97, 0xbd97 }, +/* 0xbd98 */ { true, 0xbd98, 0xbd98 }, +/* 0xbd99 */ { true, 0xbd99, 0xbd99 }, +/* 0xbd9a */ { true, 0xbd9a, 0xbd9a }, +/* 0xbd9b */ { true, 0xbd9b, 0xbd9b }, +/* 0xbd9c */ { true, 0xbd9c, 0xbd9c }, +/* 0xbd9d */ { true, 0xbd9d, 0xbd9d }, +/* 0xbd9e */ { true, 0xbd9e, 0xbd9e }, +/* 0xbd9f */ { true, 0xbd9f, 0xbd9f }, +/* 0xbda0 */ { true, 0xbda0, 0xbda0 }, +/* 0xbda1 */ { true, 0xbda1, 0xbda1 }, +/* 0xbda2 */ { true, 0xbda2, 0xbda2 }, +/* 0xbda3 */ { true, 0xbda3, 0xbda3 }, +/* 0xbda4 */ { true, 0xbda4, 0xbda4 }, +/* 0xbda5 */ { true, 0xbda5, 0xbda5 }, +/* 0xbda6 */ { true, 0xbda6, 0xbda6 }, +/* 0xbda7 */ { true, 0xbda7, 0xbda7 }, +/* 0xbda8 */ { true, 0xbda8, 0xbda8 }, +/* 0xbda9 */ { true, 0xbda9, 0xbda9 }, +/* 0xbdaa */ { true, 0xbdaa, 0xbdaa }, +/* 0xbdab */ { true, 0xbdab, 0xbdab }, +/* 0xbdac */ { true, 0xbdac, 0xbdac }, +/* 0xbdad */ { true, 0xbdad, 0xbdad }, +/* 0xbdae */ { true, 0xbdae, 0xbdae }, +/* 0xbdaf */ { true, 0xbdaf, 0xbdaf }, +/* 0xbdb0 */ { true, 0xbdb0, 0xbdb0 }, +/* 0xbdb1 */ { true, 0xbdb1, 0xbdb1 }, +/* 0xbdb2 */ { true, 0xbdb2, 0xbdb2 }, +/* 0xbdb3 */ { true, 0xbdb3, 0xbdb3 }, +/* 0xbdb4 */ { true, 0xbdb4, 0xbdb4 }, +/* 0xbdb5 */ { true, 0xbdb5, 0xbdb5 }, +/* 0xbdb6 */ { true, 0xbdb6, 0xbdb6 }, +/* 0xbdb7 */ { true, 0xbdb7, 0xbdb7 }, +/* 0xbdb8 */ { true, 0xbdb8, 0xbdb8 }, +/* 0xbdb9 */ { true, 0xbdb9, 0xbdb9 }, +/* 0xbdba */ { true, 0xbdba, 0xbdba }, +/* 0xbdbb */ { true, 0xbdbb, 0xbdbb }, +/* 0xbdbc */ { true, 0xbdbc, 0xbdbc }, +/* 0xbdbd */ { true, 0xbdbd, 0xbdbd }, +/* 0xbdbe */ { true, 0xbdbe, 0xbdbe }, +/* 0xbdbf */ { true, 0xbdbf, 0xbdbf }, +/* 0xbdc0 */ { true, 0xbdc0, 0xbdc0 }, +/* 0xbdc1 */ { true, 0xbdc1, 0xbdc1 }, +/* 0xbdc2 */ { true, 0xbdc2, 0xbdc2 }, +/* 0xbdc3 */ { true, 0xbdc3, 0xbdc3 }, +/* 0xbdc4 */ { true, 0xbdc4, 0xbdc4 }, +/* 0xbdc5 */ { true, 0xbdc5, 0xbdc5 }, +/* 0xbdc6 */ { true, 0xbdc6, 0xbdc6 }, +/* 0xbdc7 */ { true, 0xbdc7, 0xbdc7 }, +/* 0xbdc8 */ { true, 0xbdc8, 0xbdc8 }, +/* 0xbdc9 */ { true, 0xbdc9, 0xbdc9 }, +/* 0xbdca */ { true, 0xbdca, 0xbdca }, +/* 0xbdcb */ { true, 0xbdcb, 0xbdcb }, +/* 0xbdcc */ { true, 0xbdcc, 0xbdcc }, +/* 0xbdcd */ { true, 0xbdcd, 0xbdcd }, +/* 0xbdce */ { true, 0xbdce, 0xbdce }, +/* 0xbdcf */ { true, 0xbdcf, 0xbdcf }, +/* 0xbdd0 */ { true, 0xbdd0, 0xbdd0 }, +/* 0xbdd1 */ { true, 0xbdd1, 0xbdd1 }, +/* 0xbdd2 */ { true, 0xbdd2, 0xbdd2 }, +/* 0xbdd3 */ { true, 0xbdd3, 0xbdd3 }, +/* 0xbdd4 */ { true, 0xbdd4, 0xbdd4 }, +/* 0xbdd5 */ { true, 0xbdd5, 0xbdd5 }, +/* 0xbdd6 */ { true, 0xbdd6, 0xbdd6 }, +/* 0xbdd7 */ { true, 0xbdd7, 0xbdd7 }, +/* 0xbdd8 */ { true, 0xbdd8, 0xbdd8 }, +/* 0xbdd9 */ { true, 0xbdd9, 0xbdd9 }, +/* 0xbdda */ { true, 0xbdda, 0xbdda }, +/* 0xbddb */ { true, 0xbddb, 0xbddb }, +/* 0xbddc */ { true, 0xbddc, 0xbddc }, +/* 0xbddd */ { true, 0xbddd, 0xbddd }, +/* 0xbdde */ { true, 0xbdde, 0xbdde }, +/* 0xbddf */ { true, 0xbddf, 0xbddf }, +/* 0xbde0 */ { true, 0xbde0, 0xbde0 }, +/* 0xbde1 */ { true, 0xbde1, 0xbde1 }, +/* 0xbde2 */ { true, 0xbde2, 0xbde2 }, +/* 0xbde3 */ { true, 0xbde3, 0xbde3 }, +/* 0xbde4 */ { true, 0xbde4, 0xbde4 }, +/* 0xbde5 */ { true, 0xbde5, 0xbde5 }, +/* 0xbde6 */ { true, 0xbde6, 0xbde6 }, +/* 0xbde7 */ { true, 0xbde7, 0xbde7 }, +/* 0xbde8 */ { true, 0xbde8, 0xbde8 }, +/* 0xbde9 */ { true, 0xbde9, 0xbde9 }, +/* 0xbdea */ { true, 0xbdea, 0xbdea }, +/* 0xbdeb */ { true, 0xbdeb, 0xbdeb }, +/* 0xbdec */ { true, 0xbdec, 0xbdec }, +/* 0xbded */ { true, 0xbded, 0xbded }, +/* 0xbdee */ { true, 0xbdee, 0xbdee }, +/* 0xbdef */ { true, 0xbdef, 0xbdef }, +/* 0xbdf0 */ { true, 0xbdf0, 0xbdf0 }, +/* 0xbdf1 */ { true, 0xbdf1, 0xbdf1 }, +/* 0xbdf2 */ { true, 0xbdf2, 0xbdf2 }, +/* 0xbdf3 */ { true, 0xbdf3, 0xbdf3 }, +/* 0xbdf4 */ { true, 0xbdf4, 0xbdf4 }, +/* 0xbdf5 */ { true, 0xbdf5, 0xbdf5 }, +/* 0xbdf6 */ { true, 0xbdf6, 0xbdf6 }, +/* 0xbdf7 */ { true, 0xbdf7, 0xbdf7 }, +/* 0xbdf8 */ { true, 0xbdf8, 0xbdf8 }, +/* 0xbdf9 */ { true, 0xbdf9, 0xbdf9 }, +/* 0xbdfa */ { true, 0xbdfa, 0xbdfa }, +/* 0xbdfb */ { true, 0xbdfb, 0xbdfb }, +/* 0xbdfc */ { true, 0xbdfc, 0xbdfc }, +/* 0xbdfd */ { true, 0xbdfd, 0xbdfd }, +/* 0xbdfe */ { true, 0xbdfe, 0xbdfe }, +/* 0xbdff */ { true, 0xbdff, 0xbdff }, +/* 0xbe00 */ { true, 0xbe00, 0xbe00 }, +/* 0xbe01 */ { true, 0xbe01, 0xbe01 }, +/* 0xbe02 */ { true, 0xbe02, 0xbe02 }, +/* 0xbe03 */ { true, 0xbe03, 0xbe03 }, +/* 0xbe04 */ { true, 0xbe04, 0xbe04 }, +/* 0xbe05 */ { true, 0xbe05, 0xbe05 }, +/* 0xbe06 */ { true, 0xbe06, 0xbe06 }, +/* 0xbe07 */ { true, 0xbe07, 0xbe07 }, +/* 0xbe08 */ { true, 0xbe08, 0xbe08 }, +/* 0xbe09 */ { true, 0xbe09, 0xbe09 }, +/* 0xbe0a */ { true, 0xbe0a, 0xbe0a }, +/* 0xbe0b */ { true, 0xbe0b, 0xbe0b }, +/* 0xbe0c */ { true, 0xbe0c, 0xbe0c }, +/* 0xbe0d */ { true, 0xbe0d, 0xbe0d }, +/* 0xbe0e */ { true, 0xbe0e, 0xbe0e }, +/* 0xbe0f */ { true, 0xbe0f, 0xbe0f }, +/* 0xbe10 */ { true, 0xbe10, 0xbe10 }, +/* 0xbe11 */ { true, 0xbe11, 0xbe11 }, +/* 0xbe12 */ { true, 0xbe12, 0xbe12 }, +/* 0xbe13 */ { true, 0xbe13, 0xbe13 }, +/* 0xbe14 */ { true, 0xbe14, 0xbe14 }, +/* 0xbe15 */ { true, 0xbe15, 0xbe15 }, +/* 0xbe16 */ { true, 0xbe16, 0xbe16 }, +/* 0xbe17 */ { true, 0xbe17, 0xbe17 }, +/* 0xbe18 */ { true, 0xbe18, 0xbe18 }, +/* 0xbe19 */ { true, 0xbe19, 0xbe19 }, +/* 0xbe1a */ { true, 0xbe1a, 0xbe1a }, +/* 0xbe1b */ { true, 0xbe1b, 0xbe1b }, +/* 0xbe1c */ { true, 0xbe1c, 0xbe1c }, +/* 0xbe1d */ { true, 0xbe1d, 0xbe1d }, +/* 0xbe1e */ { true, 0xbe1e, 0xbe1e }, +/* 0xbe1f */ { true, 0xbe1f, 0xbe1f }, +/* 0xbe20 */ { true, 0xbe20, 0xbe20 }, +/* 0xbe21 */ { true, 0xbe21, 0xbe21 }, +/* 0xbe22 */ { true, 0xbe22, 0xbe22 }, +/* 0xbe23 */ { true, 0xbe23, 0xbe23 }, +/* 0xbe24 */ { true, 0xbe24, 0xbe24 }, +/* 0xbe25 */ { true, 0xbe25, 0xbe25 }, +/* 0xbe26 */ { true, 0xbe26, 0xbe26 }, +/* 0xbe27 */ { true, 0xbe27, 0xbe27 }, +/* 0xbe28 */ { true, 0xbe28, 0xbe28 }, +/* 0xbe29 */ { true, 0xbe29, 0xbe29 }, +/* 0xbe2a */ { true, 0xbe2a, 0xbe2a }, +/* 0xbe2b */ { true, 0xbe2b, 0xbe2b }, +/* 0xbe2c */ { true, 0xbe2c, 0xbe2c }, +/* 0xbe2d */ { true, 0xbe2d, 0xbe2d }, +/* 0xbe2e */ { true, 0xbe2e, 0xbe2e }, +/* 0xbe2f */ { true, 0xbe2f, 0xbe2f }, +/* 0xbe30 */ { true, 0xbe30, 0xbe30 }, +/* 0xbe31 */ { true, 0xbe31, 0xbe31 }, +/* 0xbe32 */ { true, 0xbe32, 0xbe32 }, +/* 0xbe33 */ { true, 0xbe33, 0xbe33 }, +/* 0xbe34 */ { true, 0xbe34, 0xbe34 }, +/* 0xbe35 */ { true, 0xbe35, 0xbe35 }, +/* 0xbe36 */ { true, 0xbe36, 0xbe36 }, +/* 0xbe37 */ { true, 0xbe37, 0xbe37 }, +/* 0xbe38 */ { true, 0xbe38, 0xbe38 }, +/* 0xbe39 */ { true, 0xbe39, 0xbe39 }, +/* 0xbe3a */ { true, 0xbe3a, 0xbe3a }, +/* 0xbe3b */ { true, 0xbe3b, 0xbe3b }, +/* 0xbe3c */ { true, 0xbe3c, 0xbe3c }, +/* 0xbe3d */ { true, 0xbe3d, 0xbe3d }, +/* 0xbe3e */ { true, 0xbe3e, 0xbe3e }, +/* 0xbe3f */ { true, 0xbe3f, 0xbe3f }, +/* 0xbe40 */ { true, 0xbe40, 0xbe40 }, +/* 0xbe41 */ { true, 0xbe41, 0xbe41 }, +/* 0xbe42 */ { true, 0xbe42, 0xbe42 }, +/* 0xbe43 */ { true, 0xbe43, 0xbe43 }, +/* 0xbe44 */ { true, 0xbe44, 0xbe44 }, +/* 0xbe45 */ { true, 0xbe45, 0xbe45 }, +/* 0xbe46 */ { true, 0xbe46, 0xbe46 }, +/* 0xbe47 */ { true, 0xbe47, 0xbe47 }, +/* 0xbe48 */ { true, 0xbe48, 0xbe48 }, +/* 0xbe49 */ { true, 0xbe49, 0xbe49 }, +/* 0xbe4a */ { true, 0xbe4a, 0xbe4a }, +/* 0xbe4b */ { true, 0xbe4b, 0xbe4b }, +/* 0xbe4c */ { true, 0xbe4c, 0xbe4c }, +/* 0xbe4d */ { true, 0xbe4d, 0xbe4d }, +/* 0xbe4e */ { true, 0xbe4e, 0xbe4e }, +/* 0xbe4f */ { true, 0xbe4f, 0xbe4f }, +/* 0xbe50 */ { true, 0xbe50, 0xbe50 }, +/* 0xbe51 */ { true, 0xbe51, 0xbe51 }, +/* 0xbe52 */ { true, 0xbe52, 0xbe52 }, +/* 0xbe53 */ { true, 0xbe53, 0xbe53 }, +/* 0xbe54 */ { true, 0xbe54, 0xbe54 }, +/* 0xbe55 */ { true, 0xbe55, 0xbe55 }, +/* 0xbe56 */ { true, 0xbe56, 0xbe56 }, +/* 0xbe57 */ { true, 0xbe57, 0xbe57 }, +/* 0xbe58 */ { true, 0xbe58, 0xbe58 }, +/* 0xbe59 */ { true, 0xbe59, 0xbe59 }, +/* 0xbe5a */ { true, 0xbe5a, 0xbe5a }, +/* 0xbe5b */ { true, 0xbe5b, 0xbe5b }, +/* 0xbe5c */ { true, 0xbe5c, 0xbe5c }, +/* 0xbe5d */ { true, 0xbe5d, 0xbe5d }, +/* 0xbe5e */ { true, 0xbe5e, 0xbe5e }, +/* 0xbe5f */ { true, 0xbe5f, 0xbe5f }, +/* 0xbe60 */ { true, 0xbe60, 0xbe60 }, +/* 0xbe61 */ { true, 0xbe61, 0xbe61 }, +/* 0xbe62 */ { true, 0xbe62, 0xbe62 }, +/* 0xbe63 */ { true, 0xbe63, 0xbe63 }, +/* 0xbe64 */ { true, 0xbe64, 0xbe64 }, +/* 0xbe65 */ { true, 0xbe65, 0xbe65 }, +/* 0xbe66 */ { true, 0xbe66, 0xbe66 }, +/* 0xbe67 */ { true, 0xbe67, 0xbe67 }, +/* 0xbe68 */ { true, 0xbe68, 0xbe68 }, +/* 0xbe69 */ { true, 0xbe69, 0xbe69 }, +/* 0xbe6a */ { true, 0xbe6a, 0xbe6a }, +/* 0xbe6b */ { true, 0xbe6b, 0xbe6b }, +/* 0xbe6c */ { true, 0xbe6c, 0xbe6c }, +/* 0xbe6d */ { true, 0xbe6d, 0xbe6d }, +/* 0xbe6e */ { true, 0xbe6e, 0xbe6e }, +/* 0xbe6f */ { true, 0xbe6f, 0xbe6f }, +/* 0xbe70 */ { true, 0xbe70, 0xbe70 }, +/* 0xbe71 */ { true, 0xbe71, 0xbe71 }, +/* 0xbe72 */ { true, 0xbe72, 0xbe72 }, +/* 0xbe73 */ { true, 0xbe73, 0xbe73 }, +/* 0xbe74 */ { true, 0xbe74, 0xbe74 }, +/* 0xbe75 */ { true, 0xbe75, 0xbe75 }, +/* 0xbe76 */ { true, 0xbe76, 0xbe76 }, +/* 0xbe77 */ { true, 0xbe77, 0xbe77 }, +/* 0xbe78 */ { true, 0xbe78, 0xbe78 }, +/* 0xbe79 */ { true, 0xbe79, 0xbe79 }, +/* 0xbe7a */ { true, 0xbe7a, 0xbe7a }, +/* 0xbe7b */ { true, 0xbe7b, 0xbe7b }, +/* 0xbe7c */ { true, 0xbe7c, 0xbe7c }, +/* 0xbe7d */ { true, 0xbe7d, 0xbe7d }, +/* 0xbe7e */ { true, 0xbe7e, 0xbe7e }, +/* 0xbe7f */ { true, 0xbe7f, 0xbe7f }, +/* 0xbe80 */ { true, 0xbe80, 0xbe80 }, +/* 0xbe81 */ { true, 0xbe81, 0xbe81 }, +/* 0xbe82 */ { true, 0xbe82, 0xbe82 }, +/* 0xbe83 */ { true, 0xbe83, 0xbe83 }, +/* 0xbe84 */ { true, 0xbe84, 0xbe84 }, +/* 0xbe85 */ { true, 0xbe85, 0xbe85 }, +/* 0xbe86 */ { true, 0xbe86, 0xbe86 }, +/* 0xbe87 */ { true, 0xbe87, 0xbe87 }, +/* 0xbe88 */ { true, 0xbe88, 0xbe88 }, +/* 0xbe89 */ { true, 0xbe89, 0xbe89 }, +/* 0xbe8a */ { true, 0xbe8a, 0xbe8a }, +/* 0xbe8b */ { true, 0xbe8b, 0xbe8b }, +/* 0xbe8c */ { true, 0xbe8c, 0xbe8c }, +/* 0xbe8d */ { true, 0xbe8d, 0xbe8d }, +/* 0xbe8e */ { true, 0xbe8e, 0xbe8e }, +/* 0xbe8f */ { true, 0xbe8f, 0xbe8f }, +/* 0xbe90 */ { true, 0xbe90, 0xbe90 }, +/* 0xbe91 */ { true, 0xbe91, 0xbe91 }, +/* 0xbe92 */ { true, 0xbe92, 0xbe92 }, +/* 0xbe93 */ { true, 0xbe93, 0xbe93 }, +/* 0xbe94 */ { true, 0xbe94, 0xbe94 }, +/* 0xbe95 */ { true, 0xbe95, 0xbe95 }, +/* 0xbe96 */ { true, 0xbe96, 0xbe96 }, +/* 0xbe97 */ { true, 0xbe97, 0xbe97 }, +/* 0xbe98 */ { true, 0xbe98, 0xbe98 }, +/* 0xbe99 */ { true, 0xbe99, 0xbe99 }, +/* 0xbe9a */ { true, 0xbe9a, 0xbe9a }, +/* 0xbe9b */ { true, 0xbe9b, 0xbe9b }, +/* 0xbe9c */ { true, 0xbe9c, 0xbe9c }, +/* 0xbe9d */ { true, 0xbe9d, 0xbe9d }, +/* 0xbe9e */ { true, 0xbe9e, 0xbe9e }, +/* 0xbe9f */ { true, 0xbe9f, 0xbe9f }, +/* 0xbea0 */ { true, 0xbea0, 0xbea0 }, +/* 0xbea1 */ { true, 0xbea1, 0xbea1 }, +/* 0xbea2 */ { true, 0xbea2, 0xbea2 }, +/* 0xbea3 */ { true, 0xbea3, 0xbea3 }, +/* 0xbea4 */ { true, 0xbea4, 0xbea4 }, +/* 0xbea5 */ { true, 0xbea5, 0xbea5 }, +/* 0xbea6 */ { true, 0xbea6, 0xbea6 }, +/* 0xbea7 */ { true, 0xbea7, 0xbea7 }, +/* 0xbea8 */ { true, 0xbea8, 0xbea8 }, +/* 0xbea9 */ { true, 0xbea9, 0xbea9 }, +/* 0xbeaa */ { true, 0xbeaa, 0xbeaa }, +/* 0xbeab */ { true, 0xbeab, 0xbeab }, +/* 0xbeac */ { true, 0xbeac, 0xbeac }, +/* 0xbead */ { true, 0xbead, 0xbead }, +/* 0xbeae */ { true, 0xbeae, 0xbeae }, +/* 0xbeaf */ { true, 0xbeaf, 0xbeaf }, +/* 0xbeb0 */ { true, 0xbeb0, 0xbeb0 }, +/* 0xbeb1 */ { true, 0xbeb1, 0xbeb1 }, +/* 0xbeb2 */ { true, 0xbeb2, 0xbeb2 }, +/* 0xbeb3 */ { true, 0xbeb3, 0xbeb3 }, +/* 0xbeb4 */ { true, 0xbeb4, 0xbeb4 }, +/* 0xbeb5 */ { true, 0xbeb5, 0xbeb5 }, +/* 0xbeb6 */ { true, 0xbeb6, 0xbeb6 }, +/* 0xbeb7 */ { true, 0xbeb7, 0xbeb7 }, +/* 0xbeb8 */ { true, 0xbeb8, 0xbeb8 }, +/* 0xbeb9 */ { true, 0xbeb9, 0xbeb9 }, +/* 0xbeba */ { true, 0xbeba, 0xbeba }, +/* 0xbebb */ { true, 0xbebb, 0xbebb }, +/* 0xbebc */ { true, 0xbebc, 0xbebc }, +/* 0xbebd */ { true, 0xbebd, 0xbebd }, +/* 0xbebe */ { true, 0xbebe, 0xbebe }, +/* 0xbebf */ { true, 0xbebf, 0xbebf }, +/* 0xbec0 */ { true, 0xbec0, 0xbec0 }, +/* 0xbec1 */ { true, 0xbec1, 0xbec1 }, +/* 0xbec2 */ { true, 0xbec2, 0xbec2 }, +/* 0xbec3 */ { true, 0xbec3, 0xbec3 }, +/* 0xbec4 */ { true, 0xbec4, 0xbec4 }, +/* 0xbec5 */ { true, 0xbec5, 0xbec5 }, +/* 0xbec6 */ { true, 0xbec6, 0xbec6 }, +/* 0xbec7 */ { true, 0xbec7, 0xbec7 }, +/* 0xbec8 */ { true, 0xbec8, 0xbec8 }, +/* 0xbec9 */ { true, 0xbec9, 0xbec9 }, +/* 0xbeca */ { true, 0xbeca, 0xbeca }, +/* 0xbecb */ { true, 0xbecb, 0xbecb }, +/* 0xbecc */ { true, 0xbecc, 0xbecc }, +/* 0xbecd */ { true, 0xbecd, 0xbecd }, +/* 0xbece */ { true, 0xbece, 0xbece }, +/* 0xbecf */ { true, 0xbecf, 0xbecf }, +/* 0xbed0 */ { true, 0xbed0, 0xbed0 }, +/* 0xbed1 */ { true, 0xbed1, 0xbed1 }, +/* 0xbed2 */ { true, 0xbed2, 0xbed2 }, +/* 0xbed3 */ { true, 0xbed3, 0xbed3 }, +/* 0xbed4 */ { true, 0xbed4, 0xbed4 }, +/* 0xbed5 */ { true, 0xbed5, 0xbed5 }, +/* 0xbed6 */ { true, 0xbed6, 0xbed6 }, +/* 0xbed7 */ { true, 0xbed7, 0xbed7 }, +/* 0xbed8 */ { true, 0xbed8, 0xbed8 }, +/* 0xbed9 */ { true, 0xbed9, 0xbed9 }, +/* 0xbeda */ { true, 0xbeda, 0xbeda }, +/* 0xbedb */ { true, 0xbedb, 0xbedb }, +/* 0xbedc */ { true, 0xbedc, 0xbedc }, +/* 0xbedd */ { true, 0xbedd, 0xbedd }, +/* 0xbede */ { true, 0xbede, 0xbede }, +/* 0xbedf */ { true, 0xbedf, 0xbedf }, +/* 0xbee0 */ { true, 0xbee0, 0xbee0 }, +/* 0xbee1 */ { true, 0xbee1, 0xbee1 }, +/* 0xbee2 */ { true, 0xbee2, 0xbee2 }, +/* 0xbee3 */ { true, 0xbee3, 0xbee3 }, +/* 0xbee4 */ { true, 0xbee4, 0xbee4 }, +/* 0xbee5 */ { true, 0xbee5, 0xbee5 }, +/* 0xbee6 */ { true, 0xbee6, 0xbee6 }, +/* 0xbee7 */ { true, 0xbee7, 0xbee7 }, +/* 0xbee8 */ { true, 0xbee8, 0xbee8 }, +/* 0xbee9 */ { true, 0xbee9, 0xbee9 }, +/* 0xbeea */ { true, 0xbeea, 0xbeea }, +/* 0xbeeb */ { true, 0xbeeb, 0xbeeb }, +/* 0xbeec */ { true, 0xbeec, 0xbeec }, +/* 0xbeed */ { true, 0xbeed, 0xbeed }, +/* 0xbeee */ { true, 0xbeee, 0xbeee }, +/* 0xbeef */ { true, 0xbeef, 0xbeef }, +/* 0xbef0 */ { true, 0xbef0, 0xbef0 }, +/* 0xbef1 */ { true, 0xbef1, 0xbef1 }, +/* 0xbef2 */ { true, 0xbef2, 0xbef2 }, +/* 0xbef3 */ { true, 0xbef3, 0xbef3 }, +/* 0xbef4 */ { true, 0xbef4, 0xbef4 }, +/* 0xbef5 */ { true, 0xbef5, 0xbef5 }, +/* 0xbef6 */ { true, 0xbef6, 0xbef6 }, +/* 0xbef7 */ { true, 0xbef7, 0xbef7 }, +/* 0xbef8 */ { true, 0xbef8, 0xbef8 }, +/* 0xbef9 */ { true, 0xbef9, 0xbef9 }, +/* 0xbefa */ { true, 0xbefa, 0xbefa }, +/* 0xbefb */ { true, 0xbefb, 0xbefb }, +/* 0xbefc */ { true, 0xbefc, 0xbefc }, +/* 0xbefd */ { true, 0xbefd, 0xbefd }, +/* 0xbefe */ { true, 0xbefe, 0xbefe }, +/* 0xbeff */ { true, 0xbeff, 0xbeff }, +/* 0xbf00 */ { true, 0xbf00, 0xbf00 }, +/* 0xbf01 */ { true, 0xbf01, 0xbf01 }, +/* 0xbf02 */ { true, 0xbf02, 0xbf02 }, +/* 0xbf03 */ { true, 0xbf03, 0xbf03 }, +/* 0xbf04 */ { true, 0xbf04, 0xbf04 }, +/* 0xbf05 */ { true, 0xbf05, 0xbf05 }, +/* 0xbf06 */ { true, 0xbf06, 0xbf06 }, +/* 0xbf07 */ { true, 0xbf07, 0xbf07 }, +/* 0xbf08 */ { true, 0xbf08, 0xbf08 }, +/* 0xbf09 */ { true, 0xbf09, 0xbf09 }, +/* 0xbf0a */ { true, 0xbf0a, 0xbf0a }, +/* 0xbf0b */ { true, 0xbf0b, 0xbf0b }, +/* 0xbf0c */ { true, 0xbf0c, 0xbf0c }, +/* 0xbf0d */ { true, 0xbf0d, 0xbf0d }, +/* 0xbf0e */ { true, 0xbf0e, 0xbf0e }, +/* 0xbf0f */ { true, 0xbf0f, 0xbf0f }, +/* 0xbf10 */ { true, 0xbf10, 0xbf10 }, +/* 0xbf11 */ { true, 0xbf11, 0xbf11 }, +/* 0xbf12 */ { true, 0xbf12, 0xbf12 }, +/* 0xbf13 */ { true, 0xbf13, 0xbf13 }, +/* 0xbf14 */ { true, 0xbf14, 0xbf14 }, +/* 0xbf15 */ { true, 0xbf15, 0xbf15 }, +/* 0xbf16 */ { true, 0xbf16, 0xbf16 }, +/* 0xbf17 */ { true, 0xbf17, 0xbf17 }, +/* 0xbf18 */ { true, 0xbf18, 0xbf18 }, +/* 0xbf19 */ { true, 0xbf19, 0xbf19 }, +/* 0xbf1a */ { true, 0xbf1a, 0xbf1a }, +/* 0xbf1b */ { true, 0xbf1b, 0xbf1b }, +/* 0xbf1c */ { true, 0xbf1c, 0xbf1c }, +/* 0xbf1d */ { true, 0xbf1d, 0xbf1d }, +/* 0xbf1e */ { true, 0xbf1e, 0xbf1e }, +/* 0xbf1f */ { true, 0xbf1f, 0xbf1f }, +/* 0xbf20 */ { true, 0xbf20, 0xbf20 }, +/* 0xbf21 */ { true, 0xbf21, 0xbf21 }, +/* 0xbf22 */ { true, 0xbf22, 0xbf22 }, +/* 0xbf23 */ { true, 0xbf23, 0xbf23 }, +/* 0xbf24 */ { true, 0xbf24, 0xbf24 }, +/* 0xbf25 */ { true, 0xbf25, 0xbf25 }, +/* 0xbf26 */ { true, 0xbf26, 0xbf26 }, +/* 0xbf27 */ { true, 0xbf27, 0xbf27 }, +/* 0xbf28 */ { true, 0xbf28, 0xbf28 }, +/* 0xbf29 */ { true, 0xbf29, 0xbf29 }, +/* 0xbf2a */ { true, 0xbf2a, 0xbf2a }, +/* 0xbf2b */ { true, 0xbf2b, 0xbf2b }, +/* 0xbf2c */ { true, 0xbf2c, 0xbf2c }, +/* 0xbf2d */ { true, 0xbf2d, 0xbf2d }, +/* 0xbf2e */ { true, 0xbf2e, 0xbf2e }, +/* 0xbf2f */ { true, 0xbf2f, 0xbf2f }, +/* 0xbf30 */ { true, 0xbf30, 0xbf30 }, +/* 0xbf31 */ { true, 0xbf31, 0xbf31 }, +/* 0xbf32 */ { true, 0xbf32, 0xbf32 }, +/* 0xbf33 */ { true, 0xbf33, 0xbf33 }, +/* 0xbf34 */ { true, 0xbf34, 0xbf34 }, +/* 0xbf35 */ { true, 0xbf35, 0xbf35 }, +/* 0xbf36 */ { true, 0xbf36, 0xbf36 }, +/* 0xbf37 */ { true, 0xbf37, 0xbf37 }, +/* 0xbf38 */ { true, 0xbf38, 0xbf38 }, +/* 0xbf39 */ { true, 0xbf39, 0xbf39 }, +/* 0xbf3a */ { true, 0xbf3a, 0xbf3a }, +/* 0xbf3b */ { true, 0xbf3b, 0xbf3b }, +/* 0xbf3c */ { true, 0xbf3c, 0xbf3c }, +/* 0xbf3d */ { true, 0xbf3d, 0xbf3d }, +/* 0xbf3e */ { true, 0xbf3e, 0xbf3e }, +/* 0xbf3f */ { true, 0xbf3f, 0xbf3f }, +/* 0xbf40 */ { true, 0xbf40, 0xbf40 }, +/* 0xbf41 */ { true, 0xbf41, 0xbf41 }, +/* 0xbf42 */ { true, 0xbf42, 0xbf42 }, +/* 0xbf43 */ { true, 0xbf43, 0xbf43 }, +/* 0xbf44 */ { true, 0xbf44, 0xbf44 }, +/* 0xbf45 */ { true, 0xbf45, 0xbf45 }, +/* 0xbf46 */ { true, 0xbf46, 0xbf46 }, +/* 0xbf47 */ { true, 0xbf47, 0xbf47 }, +/* 0xbf48 */ { true, 0xbf48, 0xbf48 }, +/* 0xbf49 */ { true, 0xbf49, 0xbf49 }, +/* 0xbf4a */ { true, 0xbf4a, 0xbf4a }, +/* 0xbf4b */ { true, 0xbf4b, 0xbf4b }, +/* 0xbf4c */ { true, 0xbf4c, 0xbf4c }, +/* 0xbf4d */ { true, 0xbf4d, 0xbf4d }, +/* 0xbf4e */ { true, 0xbf4e, 0xbf4e }, +/* 0xbf4f */ { true, 0xbf4f, 0xbf4f }, +/* 0xbf50 */ { true, 0xbf50, 0xbf50 }, +/* 0xbf51 */ { true, 0xbf51, 0xbf51 }, +/* 0xbf52 */ { true, 0xbf52, 0xbf52 }, +/* 0xbf53 */ { true, 0xbf53, 0xbf53 }, +/* 0xbf54 */ { true, 0xbf54, 0xbf54 }, +/* 0xbf55 */ { true, 0xbf55, 0xbf55 }, +/* 0xbf56 */ { true, 0xbf56, 0xbf56 }, +/* 0xbf57 */ { true, 0xbf57, 0xbf57 }, +/* 0xbf58 */ { true, 0xbf58, 0xbf58 }, +/* 0xbf59 */ { true, 0xbf59, 0xbf59 }, +/* 0xbf5a */ { true, 0xbf5a, 0xbf5a }, +/* 0xbf5b */ { true, 0xbf5b, 0xbf5b }, +/* 0xbf5c */ { true, 0xbf5c, 0xbf5c }, +/* 0xbf5d */ { true, 0xbf5d, 0xbf5d }, +/* 0xbf5e */ { true, 0xbf5e, 0xbf5e }, +/* 0xbf5f */ { true, 0xbf5f, 0xbf5f }, +/* 0xbf60 */ { true, 0xbf60, 0xbf60 }, +/* 0xbf61 */ { true, 0xbf61, 0xbf61 }, +/* 0xbf62 */ { true, 0xbf62, 0xbf62 }, +/* 0xbf63 */ { true, 0xbf63, 0xbf63 }, +/* 0xbf64 */ { true, 0xbf64, 0xbf64 }, +/* 0xbf65 */ { true, 0xbf65, 0xbf65 }, +/* 0xbf66 */ { true, 0xbf66, 0xbf66 }, +/* 0xbf67 */ { true, 0xbf67, 0xbf67 }, +/* 0xbf68 */ { true, 0xbf68, 0xbf68 }, +/* 0xbf69 */ { true, 0xbf69, 0xbf69 }, +/* 0xbf6a */ { true, 0xbf6a, 0xbf6a }, +/* 0xbf6b */ { true, 0xbf6b, 0xbf6b }, +/* 0xbf6c */ { true, 0xbf6c, 0xbf6c }, +/* 0xbf6d */ { true, 0xbf6d, 0xbf6d }, +/* 0xbf6e */ { true, 0xbf6e, 0xbf6e }, +/* 0xbf6f */ { true, 0xbf6f, 0xbf6f }, +/* 0xbf70 */ { true, 0xbf70, 0xbf70 }, +/* 0xbf71 */ { true, 0xbf71, 0xbf71 }, +/* 0xbf72 */ { true, 0xbf72, 0xbf72 }, +/* 0xbf73 */ { true, 0xbf73, 0xbf73 }, +/* 0xbf74 */ { true, 0xbf74, 0xbf74 }, +/* 0xbf75 */ { true, 0xbf75, 0xbf75 }, +/* 0xbf76 */ { true, 0xbf76, 0xbf76 }, +/* 0xbf77 */ { true, 0xbf77, 0xbf77 }, +/* 0xbf78 */ { true, 0xbf78, 0xbf78 }, +/* 0xbf79 */ { true, 0xbf79, 0xbf79 }, +/* 0xbf7a */ { true, 0xbf7a, 0xbf7a }, +/* 0xbf7b */ { true, 0xbf7b, 0xbf7b }, +/* 0xbf7c */ { true, 0xbf7c, 0xbf7c }, +/* 0xbf7d */ { true, 0xbf7d, 0xbf7d }, +/* 0xbf7e */ { true, 0xbf7e, 0xbf7e }, +/* 0xbf7f */ { true, 0xbf7f, 0xbf7f }, +/* 0xbf80 */ { true, 0xbf80, 0xbf80 }, +/* 0xbf81 */ { true, 0xbf81, 0xbf81 }, +/* 0xbf82 */ { true, 0xbf82, 0xbf82 }, +/* 0xbf83 */ { true, 0xbf83, 0xbf83 }, +/* 0xbf84 */ { true, 0xbf84, 0xbf84 }, +/* 0xbf85 */ { true, 0xbf85, 0xbf85 }, +/* 0xbf86 */ { true, 0xbf86, 0xbf86 }, +/* 0xbf87 */ { true, 0xbf87, 0xbf87 }, +/* 0xbf88 */ { true, 0xbf88, 0xbf88 }, +/* 0xbf89 */ { true, 0xbf89, 0xbf89 }, +/* 0xbf8a */ { true, 0xbf8a, 0xbf8a }, +/* 0xbf8b */ { true, 0xbf8b, 0xbf8b }, +/* 0xbf8c */ { true, 0xbf8c, 0xbf8c }, +/* 0xbf8d */ { true, 0xbf8d, 0xbf8d }, +/* 0xbf8e */ { true, 0xbf8e, 0xbf8e }, +/* 0xbf8f */ { true, 0xbf8f, 0xbf8f }, +/* 0xbf90 */ { true, 0xbf90, 0xbf90 }, +/* 0xbf91 */ { true, 0xbf91, 0xbf91 }, +/* 0xbf92 */ { true, 0xbf92, 0xbf92 }, +/* 0xbf93 */ { true, 0xbf93, 0xbf93 }, +/* 0xbf94 */ { true, 0xbf94, 0xbf94 }, +/* 0xbf95 */ { true, 0xbf95, 0xbf95 }, +/* 0xbf96 */ { true, 0xbf96, 0xbf96 }, +/* 0xbf97 */ { true, 0xbf97, 0xbf97 }, +/* 0xbf98 */ { true, 0xbf98, 0xbf98 }, +/* 0xbf99 */ { true, 0xbf99, 0xbf99 }, +/* 0xbf9a */ { true, 0xbf9a, 0xbf9a }, +/* 0xbf9b */ { true, 0xbf9b, 0xbf9b }, +/* 0xbf9c */ { true, 0xbf9c, 0xbf9c }, +/* 0xbf9d */ { true, 0xbf9d, 0xbf9d }, +/* 0xbf9e */ { true, 0xbf9e, 0xbf9e }, +/* 0xbf9f */ { true, 0xbf9f, 0xbf9f }, +/* 0xbfa0 */ { true, 0xbfa0, 0xbfa0 }, +/* 0xbfa1 */ { true, 0xbfa1, 0xbfa1 }, +/* 0xbfa2 */ { true, 0xbfa2, 0xbfa2 }, +/* 0xbfa3 */ { true, 0xbfa3, 0xbfa3 }, +/* 0xbfa4 */ { true, 0xbfa4, 0xbfa4 }, +/* 0xbfa5 */ { true, 0xbfa5, 0xbfa5 }, +/* 0xbfa6 */ { true, 0xbfa6, 0xbfa6 }, +/* 0xbfa7 */ { true, 0xbfa7, 0xbfa7 }, +/* 0xbfa8 */ { true, 0xbfa8, 0xbfa8 }, +/* 0xbfa9 */ { true, 0xbfa9, 0xbfa9 }, +/* 0xbfaa */ { true, 0xbfaa, 0xbfaa }, +/* 0xbfab */ { true, 0xbfab, 0xbfab }, +/* 0xbfac */ { true, 0xbfac, 0xbfac }, +/* 0xbfad */ { true, 0xbfad, 0xbfad }, +/* 0xbfae */ { true, 0xbfae, 0xbfae }, +/* 0xbfaf */ { true, 0xbfaf, 0xbfaf }, +/* 0xbfb0 */ { true, 0xbfb0, 0xbfb0 }, +/* 0xbfb1 */ { true, 0xbfb1, 0xbfb1 }, +/* 0xbfb2 */ { true, 0xbfb2, 0xbfb2 }, +/* 0xbfb3 */ { true, 0xbfb3, 0xbfb3 }, +/* 0xbfb4 */ { true, 0xbfb4, 0xbfb4 }, +/* 0xbfb5 */ { true, 0xbfb5, 0xbfb5 }, +/* 0xbfb6 */ { true, 0xbfb6, 0xbfb6 }, +/* 0xbfb7 */ { true, 0xbfb7, 0xbfb7 }, +/* 0xbfb8 */ { true, 0xbfb8, 0xbfb8 }, +/* 0xbfb9 */ { true, 0xbfb9, 0xbfb9 }, +/* 0xbfba */ { true, 0xbfba, 0xbfba }, +/* 0xbfbb */ { true, 0xbfbb, 0xbfbb }, +/* 0xbfbc */ { true, 0xbfbc, 0xbfbc }, +/* 0xbfbd */ { true, 0xbfbd, 0xbfbd }, +/* 0xbfbe */ { true, 0xbfbe, 0xbfbe }, +/* 0xbfbf */ { true, 0xbfbf, 0xbfbf }, +/* 0xbfc0 */ { true, 0xbfc0, 0xbfc0 }, +/* 0xbfc1 */ { true, 0xbfc1, 0xbfc1 }, +/* 0xbfc2 */ { true, 0xbfc2, 0xbfc2 }, +/* 0xbfc3 */ { true, 0xbfc3, 0xbfc3 }, +/* 0xbfc4 */ { true, 0xbfc4, 0xbfc4 }, +/* 0xbfc5 */ { true, 0xbfc5, 0xbfc5 }, +/* 0xbfc6 */ { true, 0xbfc6, 0xbfc6 }, +/* 0xbfc7 */ { true, 0xbfc7, 0xbfc7 }, +/* 0xbfc8 */ { true, 0xbfc8, 0xbfc8 }, +/* 0xbfc9 */ { true, 0xbfc9, 0xbfc9 }, +/* 0xbfca */ { true, 0xbfca, 0xbfca }, +/* 0xbfcb */ { true, 0xbfcb, 0xbfcb }, +/* 0xbfcc */ { true, 0xbfcc, 0xbfcc }, +/* 0xbfcd */ { true, 0xbfcd, 0xbfcd }, +/* 0xbfce */ { true, 0xbfce, 0xbfce }, +/* 0xbfcf */ { true, 0xbfcf, 0xbfcf }, +/* 0xbfd0 */ { true, 0xbfd0, 0xbfd0 }, +/* 0xbfd1 */ { true, 0xbfd1, 0xbfd1 }, +/* 0xbfd2 */ { true, 0xbfd2, 0xbfd2 }, +/* 0xbfd3 */ { true, 0xbfd3, 0xbfd3 }, +/* 0xbfd4 */ { true, 0xbfd4, 0xbfd4 }, +/* 0xbfd5 */ { true, 0xbfd5, 0xbfd5 }, +/* 0xbfd6 */ { true, 0xbfd6, 0xbfd6 }, +/* 0xbfd7 */ { true, 0xbfd7, 0xbfd7 }, +/* 0xbfd8 */ { true, 0xbfd8, 0xbfd8 }, +/* 0xbfd9 */ { true, 0xbfd9, 0xbfd9 }, +/* 0xbfda */ { true, 0xbfda, 0xbfda }, +/* 0xbfdb */ { true, 0xbfdb, 0xbfdb }, +/* 0xbfdc */ { true, 0xbfdc, 0xbfdc }, +/* 0xbfdd */ { true, 0xbfdd, 0xbfdd }, +/* 0xbfde */ { true, 0xbfde, 0xbfde }, +/* 0xbfdf */ { true, 0xbfdf, 0xbfdf }, +/* 0xbfe0 */ { true, 0xbfe0, 0xbfe0 }, +/* 0xbfe1 */ { true, 0xbfe1, 0xbfe1 }, +/* 0xbfe2 */ { true, 0xbfe2, 0xbfe2 }, +/* 0xbfe3 */ { true, 0xbfe3, 0xbfe3 }, +/* 0xbfe4 */ { true, 0xbfe4, 0xbfe4 }, +/* 0xbfe5 */ { true, 0xbfe5, 0xbfe5 }, +/* 0xbfe6 */ { true, 0xbfe6, 0xbfe6 }, +/* 0xbfe7 */ { true, 0xbfe7, 0xbfe7 }, +/* 0xbfe8 */ { true, 0xbfe8, 0xbfe8 }, +/* 0xbfe9 */ { true, 0xbfe9, 0xbfe9 }, +/* 0xbfea */ { true, 0xbfea, 0xbfea }, +/* 0xbfeb */ { true, 0xbfeb, 0xbfeb }, +/* 0xbfec */ { true, 0xbfec, 0xbfec }, +/* 0xbfed */ { true, 0xbfed, 0xbfed }, +/* 0xbfee */ { true, 0xbfee, 0xbfee }, +/* 0xbfef */ { true, 0xbfef, 0xbfef }, +/* 0xbff0 */ { true, 0xbff0, 0xbff0 }, +/* 0xbff1 */ { true, 0xbff1, 0xbff1 }, +/* 0xbff2 */ { true, 0xbff2, 0xbff2 }, +/* 0xbff3 */ { true, 0xbff3, 0xbff3 }, +/* 0xbff4 */ { true, 0xbff4, 0xbff4 }, +/* 0xbff5 */ { true, 0xbff5, 0xbff5 }, +/* 0xbff6 */ { true, 0xbff6, 0xbff6 }, +/* 0xbff7 */ { true, 0xbff7, 0xbff7 }, +/* 0xbff8 */ { true, 0xbff8, 0xbff8 }, +/* 0xbff9 */ { true, 0xbff9, 0xbff9 }, +/* 0xbffa */ { true, 0xbffa, 0xbffa }, +/* 0xbffb */ { true, 0xbffb, 0xbffb }, +/* 0xbffc */ { true, 0xbffc, 0xbffc }, +/* 0xbffd */ { true, 0xbffd, 0xbffd }, +/* 0xbffe */ { true, 0xbffe, 0xbffe }, +/* 0xbfff */ { true, 0xbfff, 0xbfff }, +/* 0xc000 */ { true, 0xc000, 0xc000 }, +/* 0xc001 */ { true, 0xc001, 0xc001 }, +/* 0xc002 */ { true, 0xc002, 0xc002 }, +/* 0xc003 */ { true, 0xc003, 0xc003 }, +/* 0xc004 */ { true, 0xc004, 0xc004 }, +/* 0xc005 */ { true, 0xc005, 0xc005 }, +/* 0xc006 */ { true, 0xc006, 0xc006 }, +/* 0xc007 */ { true, 0xc007, 0xc007 }, +/* 0xc008 */ { true, 0xc008, 0xc008 }, +/* 0xc009 */ { true, 0xc009, 0xc009 }, +/* 0xc00a */ { true, 0xc00a, 0xc00a }, +/* 0xc00b */ { true, 0xc00b, 0xc00b }, +/* 0xc00c */ { true, 0xc00c, 0xc00c }, +/* 0xc00d */ { true, 0xc00d, 0xc00d }, +/* 0xc00e */ { true, 0xc00e, 0xc00e }, +/* 0xc00f */ { true, 0xc00f, 0xc00f }, +/* 0xc010 */ { true, 0xc010, 0xc010 }, +/* 0xc011 */ { true, 0xc011, 0xc011 }, +/* 0xc012 */ { true, 0xc012, 0xc012 }, +/* 0xc013 */ { true, 0xc013, 0xc013 }, +/* 0xc014 */ { true, 0xc014, 0xc014 }, +/* 0xc015 */ { true, 0xc015, 0xc015 }, +/* 0xc016 */ { true, 0xc016, 0xc016 }, +/* 0xc017 */ { true, 0xc017, 0xc017 }, +/* 0xc018 */ { true, 0xc018, 0xc018 }, +/* 0xc019 */ { true, 0xc019, 0xc019 }, +/* 0xc01a */ { true, 0xc01a, 0xc01a }, +/* 0xc01b */ { true, 0xc01b, 0xc01b }, +/* 0xc01c */ { true, 0xc01c, 0xc01c }, +/* 0xc01d */ { true, 0xc01d, 0xc01d }, +/* 0xc01e */ { true, 0xc01e, 0xc01e }, +/* 0xc01f */ { true, 0xc01f, 0xc01f }, +/* 0xc020 */ { true, 0xc020, 0xc020 }, +/* 0xc021 */ { true, 0xc021, 0xc021 }, +/* 0xc022 */ { true, 0xc022, 0xc022 }, +/* 0xc023 */ { true, 0xc023, 0xc023 }, +/* 0xc024 */ { true, 0xc024, 0xc024 }, +/* 0xc025 */ { true, 0xc025, 0xc025 }, +/* 0xc026 */ { true, 0xc026, 0xc026 }, +/* 0xc027 */ { true, 0xc027, 0xc027 }, +/* 0xc028 */ { true, 0xc028, 0xc028 }, +/* 0xc029 */ { true, 0xc029, 0xc029 }, +/* 0xc02a */ { true, 0xc02a, 0xc02a }, +/* 0xc02b */ { true, 0xc02b, 0xc02b }, +/* 0xc02c */ { true, 0xc02c, 0xc02c }, +/* 0xc02d */ { true, 0xc02d, 0xc02d }, +/* 0xc02e */ { true, 0xc02e, 0xc02e }, +/* 0xc02f */ { true, 0xc02f, 0xc02f }, +/* 0xc030 */ { true, 0xc030, 0xc030 }, +/* 0xc031 */ { true, 0xc031, 0xc031 }, +/* 0xc032 */ { true, 0xc032, 0xc032 }, +/* 0xc033 */ { true, 0xc033, 0xc033 }, +/* 0xc034 */ { true, 0xc034, 0xc034 }, +/* 0xc035 */ { true, 0xc035, 0xc035 }, +/* 0xc036 */ { true, 0xc036, 0xc036 }, +/* 0xc037 */ { true, 0xc037, 0xc037 }, +/* 0xc038 */ { true, 0xc038, 0xc038 }, +/* 0xc039 */ { true, 0xc039, 0xc039 }, +/* 0xc03a */ { true, 0xc03a, 0xc03a }, +/* 0xc03b */ { true, 0xc03b, 0xc03b }, +/* 0xc03c */ { true, 0xc03c, 0xc03c }, +/* 0xc03d */ { true, 0xc03d, 0xc03d }, +/* 0xc03e */ { true, 0xc03e, 0xc03e }, +/* 0xc03f */ { true, 0xc03f, 0xc03f }, +/* 0xc040 */ { true, 0xc040, 0xc040 }, +/* 0xc041 */ { true, 0xc041, 0xc041 }, +/* 0xc042 */ { true, 0xc042, 0xc042 }, +/* 0xc043 */ { true, 0xc043, 0xc043 }, +/* 0xc044 */ { true, 0xc044, 0xc044 }, +/* 0xc045 */ { true, 0xc045, 0xc045 }, +/* 0xc046 */ { true, 0xc046, 0xc046 }, +/* 0xc047 */ { true, 0xc047, 0xc047 }, +/* 0xc048 */ { true, 0xc048, 0xc048 }, +/* 0xc049 */ { true, 0xc049, 0xc049 }, +/* 0xc04a */ { true, 0xc04a, 0xc04a }, +/* 0xc04b */ { true, 0xc04b, 0xc04b }, +/* 0xc04c */ { true, 0xc04c, 0xc04c }, +/* 0xc04d */ { true, 0xc04d, 0xc04d }, +/* 0xc04e */ { true, 0xc04e, 0xc04e }, +/* 0xc04f */ { true, 0xc04f, 0xc04f }, +/* 0xc050 */ { true, 0xc050, 0xc050 }, +/* 0xc051 */ { true, 0xc051, 0xc051 }, +/* 0xc052 */ { true, 0xc052, 0xc052 }, +/* 0xc053 */ { true, 0xc053, 0xc053 }, +/* 0xc054 */ { true, 0xc054, 0xc054 }, +/* 0xc055 */ { true, 0xc055, 0xc055 }, +/* 0xc056 */ { true, 0xc056, 0xc056 }, +/* 0xc057 */ { true, 0xc057, 0xc057 }, +/* 0xc058 */ { true, 0xc058, 0xc058 }, +/* 0xc059 */ { true, 0xc059, 0xc059 }, +/* 0xc05a */ { true, 0xc05a, 0xc05a }, +/* 0xc05b */ { true, 0xc05b, 0xc05b }, +/* 0xc05c */ { true, 0xc05c, 0xc05c }, +/* 0xc05d */ { true, 0xc05d, 0xc05d }, +/* 0xc05e */ { true, 0xc05e, 0xc05e }, +/* 0xc05f */ { true, 0xc05f, 0xc05f }, +/* 0xc060 */ { true, 0xc060, 0xc060 }, +/* 0xc061 */ { true, 0xc061, 0xc061 }, +/* 0xc062 */ { true, 0xc062, 0xc062 }, +/* 0xc063 */ { true, 0xc063, 0xc063 }, +/* 0xc064 */ { true, 0xc064, 0xc064 }, +/* 0xc065 */ { true, 0xc065, 0xc065 }, +/* 0xc066 */ { true, 0xc066, 0xc066 }, +/* 0xc067 */ { true, 0xc067, 0xc067 }, +/* 0xc068 */ { true, 0xc068, 0xc068 }, +/* 0xc069 */ { true, 0xc069, 0xc069 }, +/* 0xc06a */ { true, 0xc06a, 0xc06a }, +/* 0xc06b */ { true, 0xc06b, 0xc06b }, +/* 0xc06c */ { true, 0xc06c, 0xc06c }, +/* 0xc06d */ { true, 0xc06d, 0xc06d }, +/* 0xc06e */ { true, 0xc06e, 0xc06e }, +/* 0xc06f */ { true, 0xc06f, 0xc06f }, +/* 0xc070 */ { true, 0xc070, 0xc070 }, +/* 0xc071 */ { true, 0xc071, 0xc071 }, +/* 0xc072 */ { true, 0xc072, 0xc072 }, +/* 0xc073 */ { true, 0xc073, 0xc073 }, +/* 0xc074 */ { true, 0xc074, 0xc074 }, +/* 0xc075 */ { true, 0xc075, 0xc075 }, +/* 0xc076 */ { true, 0xc076, 0xc076 }, +/* 0xc077 */ { true, 0xc077, 0xc077 }, +/* 0xc078 */ { true, 0xc078, 0xc078 }, +/* 0xc079 */ { true, 0xc079, 0xc079 }, +/* 0xc07a */ { true, 0xc07a, 0xc07a }, +/* 0xc07b */ { true, 0xc07b, 0xc07b }, +/* 0xc07c */ { true, 0xc07c, 0xc07c }, +/* 0xc07d */ { true, 0xc07d, 0xc07d }, +/* 0xc07e */ { true, 0xc07e, 0xc07e }, +/* 0xc07f */ { true, 0xc07f, 0xc07f }, +/* 0xc080 */ { true, 0xc080, 0xc080 }, +/* 0xc081 */ { true, 0xc081, 0xc081 }, +/* 0xc082 */ { true, 0xc082, 0xc082 }, +/* 0xc083 */ { true, 0xc083, 0xc083 }, +/* 0xc084 */ { true, 0xc084, 0xc084 }, +/* 0xc085 */ { true, 0xc085, 0xc085 }, +/* 0xc086 */ { true, 0xc086, 0xc086 }, +/* 0xc087 */ { true, 0xc087, 0xc087 }, +/* 0xc088 */ { true, 0xc088, 0xc088 }, +/* 0xc089 */ { true, 0xc089, 0xc089 }, +/* 0xc08a */ { true, 0xc08a, 0xc08a }, +/* 0xc08b */ { true, 0xc08b, 0xc08b }, +/* 0xc08c */ { true, 0xc08c, 0xc08c }, +/* 0xc08d */ { true, 0xc08d, 0xc08d }, +/* 0xc08e */ { true, 0xc08e, 0xc08e }, +/* 0xc08f */ { true, 0xc08f, 0xc08f }, +/* 0xc090 */ { true, 0xc090, 0xc090 }, +/* 0xc091 */ { true, 0xc091, 0xc091 }, +/* 0xc092 */ { true, 0xc092, 0xc092 }, +/* 0xc093 */ { true, 0xc093, 0xc093 }, +/* 0xc094 */ { true, 0xc094, 0xc094 }, +/* 0xc095 */ { true, 0xc095, 0xc095 }, +/* 0xc096 */ { true, 0xc096, 0xc096 }, +/* 0xc097 */ { true, 0xc097, 0xc097 }, +/* 0xc098 */ { true, 0xc098, 0xc098 }, +/* 0xc099 */ { true, 0xc099, 0xc099 }, +/* 0xc09a */ { true, 0xc09a, 0xc09a }, +/* 0xc09b */ { true, 0xc09b, 0xc09b }, +/* 0xc09c */ { true, 0xc09c, 0xc09c }, +/* 0xc09d */ { true, 0xc09d, 0xc09d }, +/* 0xc09e */ { true, 0xc09e, 0xc09e }, +/* 0xc09f */ { true, 0xc09f, 0xc09f }, +/* 0xc0a0 */ { true, 0xc0a0, 0xc0a0 }, +/* 0xc0a1 */ { true, 0xc0a1, 0xc0a1 }, +/* 0xc0a2 */ { true, 0xc0a2, 0xc0a2 }, +/* 0xc0a3 */ { true, 0xc0a3, 0xc0a3 }, +/* 0xc0a4 */ { true, 0xc0a4, 0xc0a4 }, +/* 0xc0a5 */ { true, 0xc0a5, 0xc0a5 }, +/* 0xc0a6 */ { true, 0xc0a6, 0xc0a6 }, +/* 0xc0a7 */ { true, 0xc0a7, 0xc0a7 }, +/* 0xc0a8 */ { true, 0xc0a8, 0xc0a8 }, +/* 0xc0a9 */ { true, 0xc0a9, 0xc0a9 }, +/* 0xc0aa */ { true, 0xc0aa, 0xc0aa }, +/* 0xc0ab */ { true, 0xc0ab, 0xc0ab }, +/* 0xc0ac */ { true, 0xc0ac, 0xc0ac }, +/* 0xc0ad */ { true, 0xc0ad, 0xc0ad }, +/* 0xc0ae */ { true, 0xc0ae, 0xc0ae }, +/* 0xc0af */ { true, 0xc0af, 0xc0af }, +/* 0xc0b0 */ { true, 0xc0b0, 0xc0b0 }, +/* 0xc0b1 */ { true, 0xc0b1, 0xc0b1 }, +/* 0xc0b2 */ { true, 0xc0b2, 0xc0b2 }, +/* 0xc0b3 */ { true, 0xc0b3, 0xc0b3 }, +/* 0xc0b4 */ { true, 0xc0b4, 0xc0b4 }, +/* 0xc0b5 */ { true, 0xc0b5, 0xc0b5 }, +/* 0xc0b6 */ { true, 0xc0b6, 0xc0b6 }, +/* 0xc0b7 */ { true, 0xc0b7, 0xc0b7 }, +/* 0xc0b8 */ { true, 0xc0b8, 0xc0b8 }, +/* 0xc0b9 */ { true, 0xc0b9, 0xc0b9 }, +/* 0xc0ba */ { true, 0xc0ba, 0xc0ba }, +/* 0xc0bb */ { true, 0xc0bb, 0xc0bb }, +/* 0xc0bc */ { true, 0xc0bc, 0xc0bc }, +/* 0xc0bd */ { true, 0xc0bd, 0xc0bd }, +/* 0xc0be */ { true, 0xc0be, 0xc0be }, +/* 0xc0bf */ { true, 0xc0bf, 0xc0bf }, +/* 0xc0c0 */ { true, 0xc0c0, 0xc0c0 }, +/* 0xc0c1 */ { true, 0xc0c1, 0xc0c1 }, +/* 0xc0c2 */ { true, 0xc0c2, 0xc0c2 }, +/* 0xc0c3 */ { true, 0xc0c3, 0xc0c3 }, +/* 0xc0c4 */ { true, 0xc0c4, 0xc0c4 }, +/* 0xc0c5 */ { true, 0xc0c5, 0xc0c5 }, +/* 0xc0c6 */ { true, 0xc0c6, 0xc0c6 }, +/* 0xc0c7 */ { true, 0xc0c7, 0xc0c7 }, +/* 0xc0c8 */ { true, 0xc0c8, 0xc0c8 }, +/* 0xc0c9 */ { true, 0xc0c9, 0xc0c9 }, +/* 0xc0ca */ { true, 0xc0ca, 0xc0ca }, +/* 0xc0cb */ { true, 0xc0cb, 0xc0cb }, +/* 0xc0cc */ { true, 0xc0cc, 0xc0cc }, +/* 0xc0cd */ { true, 0xc0cd, 0xc0cd }, +/* 0xc0ce */ { true, 0xc0ce, 0xc0ce }, +/* 0xc0cf */ { true, 0xc0cf, 0xc0cf }, +/* 0xc0d0 */ { true, 0xc0d0, 0xc0d0 }, +/* 0xc0d1 */ { true, 0xc0d1, 0xc0d1 }, +/* 0xc0d2 */ { true, 0xc0d2, 0xc0d2 }, +/* 0xc0d3 */ { true, 0xc0d3, 0xc0d3 }, +/* 0xc0d4 */ { true, 0xc0d4, 0xc0d4 }, +/* 0xc0d5 */ { true, 0xc0d5, 0xc0d5 }, +/* 0xc0d6 */ { true, 0xc0d6, 0xc0d6 }, +/* 0xc0d7 */ { true, 0xc0d7, 0xc0d7 }, +/* 0xc0d8 */ { true, 0xc0d8, 0xc0d8 }, +/* 0xc0d9 */ { true, 0xc0d9, 0xc0d9 }, +/* 0xc0da */ { true, 0xc0da, 0xc0da }, +/* 0xc0db */ { true, 0xc0db, 0xc0db }, +/* 0xc0dc */ { true, 0xc0dc, 0xc0dc }, +/* 0xc0dd */ { true, 0xc0dd, 0xc0dd }, +/* 0xc0de */ { true, 0xc0de, 0xc0de }, +/* 0xc0df */ { true, 0xc0df, 0xc0df }, +/* 0xc0e0 */ { true, 0xc0e0, 0xc0e0 }, +/* 0xc0e1 */ { true, 0xc0e1, 0xc0e1 }, +/* 0xc0e2 */ { true, 0xc0e2, 0xc0e2 }, +/* 0xc0e3 */ { true, 0xc0e3, 0xc0e3 }, +/* 0xc0e4 */ { true, 0xc0e4, 0xc0e4 }, +/* 0xc0e5 */ { true, 0xc0e5, 0xc0e5 }, +/* 0xc0e6 */ { true, 0xc0e6, 0xc0e6 }, +/* 0xc0e7 */ { true, 0xc0e7, 0xc0e7 }, +/* 0xc0e8 */ { true, 0xc0e8, 0xc0e8 }, +/* 0xc0e9 */ { true, 0xc0e9, 0xc0e9 }, +/* 0xc0ea */ { true, 0xc0ea, 0xc0ea }, +/* 0xc0eb */ { true, 0xc0eb, 0xc0eb }, +/* 0xc0ec */ { true, 0xc0ec, 0xc0ec }, +/* 0xc0ed */ { true, 0xc0ed, 0xc0ed }, +/* 0xc0ee */ { true, 0xc0ee, 0xc0ee }, +/* 0xc0ef */ { true, 0xc0ef, 0xc0ef }, +/* 0xc0f0 */ { true, 0xc0f0, 0xc0f0 }, +/* 0xc0f1 */ { true, 0xc0f1, 0xc0f1 }, +/* 0xc0f2 */ { true, 0xc0f2, 0xc0f2 }, +/* 0xc0f3 */ { true, 0xc0f3, 0xc0f3 }, +/* 0xc0f4 */ { true, 0xc0f4, 0xc0f4 }, +/* 0xc0f5 */ { true, 0xc0f5, 0xc0f5 }, +/* 0xc0f6 */ { true, 0xc0f6, 0xc0f6 }, +/* 0xc0f7 */ { true, 0xc0f7, 0xc0f7 }, +/* 0xc0f8 */ { true, 0xc0f8, 0xc0f8 }, +/* 0xc0f9 */ { true, 0xc0f9, 0xc0f9 }, +/* 0xc0fa */ { true, 0xc0fa, 0xc0fa }, +/* 0xc0fb */ { true, 0xc0fb, 0xc0fb }, +/* 0xc0fc */ { true, 0xc0fc, 0xc0fc }, +/* 0xc0fd */ { true, 0xc0fd, 0xc0fd }, +/* 0xc0fe */ { true, 0xc0fe, 0xc0fe }, +/* 0xc0ff */ { true, 0xc0ff, 0xc0ff }, +/* 0xc100 */ { true, 0xc100, 0xc100 }, +/* 0xc101 */ { true, 0xc101, 0xc101 }, +/* 0xc102 */ { true, 0xc102, 0xc102 }, +/* 0xc103 */ { true, 0xc103, 0xc103 }, +/* 0xc104 */ { true, 0xc104, 0xc104 }, +/* 0xc105 */ { true, 0xc105, 0xc105 }, +/* 0xc106 */ { true, 0xc106, 0xc106 }, +/* 0xc107 */ { true, 0xc107, 0xc107 }, +/* 0xc108 */ { true, 0xc108, 0xc108 }, +/* 0xc109 */ { true, 0xc109, 0xc109 }, +/* 0xc10a */ { true, 0xc10a, 0xc10a }, +/* 0xc10b */ { true, 0xc10b, 0xc10b }, +/* 0xc10c */ { true, 0xc10c, 0xc10c }, +/* 0xc10d */ { true, 0xc10d, 0xc10d }, +/* 0xc10e */ { true, 0xc10e, 0xc10e }, +/* 0xc10f */ { true, 0xc10f, 0xc10f }, +/* 0xc110 */ { true, 0xc110, 0xc110 }, +/* 0xc111 */ { true, 0xc111, 0xc111 }, +/* 0xc112 */ { true, 0xc112, 0xc112 }, +/* 0xc113 */ { true, 0xc113, 0xc113 }, +/* 0xc114 */ { true, 0xc114, 0xc114 }, +/* 0xc115 */ { true, 0xc115, 0xc115 }, +/* 0xc116 */ { true, 0xc116, 0xc116 }, +/* 0xc117 */ { true, 0xc117, 0xc117 }, +/* 0xc118 */ { true, 0xc118, 0xc118 }, +/* 0xc119 */ { true, 0xc119, 0xc119 }, +/* 0xc11a */ { true, 0xc11a, 0xc11a }, +/* 0xc11b */ { true, 0xc11b, 0xc11b }, +/* 0xc11c */ { true, 0xc11c, 0xc11c }, +/* 0xc11d */ { true, 0xc11d, 0xc11d }, +/* 0xc11e */ { true, 0xc11e, 0xc11e }, +/* 0xc11f */ { true, 0xc11f, 0xc11f }, +/* 0xc120 */ { true, 0xc120, 0xc120 }, +/* 0xc121 */ { true, 0xc121, 0xc121 }, +/* 0xc122 */ { true, 0xc122, 0xc122 }, +/* 0xc123 */ { true, 0xc123, 0xc123 }, +/* 0xc124 */ { true, 0xc124, 0xc124 }, +/* 0xc125 */ { true, 0xc125, 0xc125 }, +/* 0xc126 */ { true, 0xc126, 0xc126 }, +/* 0xc127 */ { true, 0xc127, 0xc127 }, +/* 0xc128 */ { true, 0xc128, 0xc128 }, +/* 0xc129 */ { true, 0xc129, 0xc129 }, +/* 0xc12a */ { true, 0xc12a, 0xc12a }, +/* 0xc12b */ { true, 0xc12b, 0xc12b }, +/* 0xc12c */ { true, 0xc12c, 0xc12c }, +/* 0xc12d */ { true, 0xc12d, 0xc12d }, +/* 0xc12e */ { true, 0xc12e, 0xc12e }, +/* 0xc12f */ { true, 0xc12f, 0xc12f }, +/* 0xc130 */ { true, 0xc130, 0xc130 }, +/* 0xc131 */ { true, 0xc131, 0xc131 }, +/* 0xc132 */ { true, 0xc132, 0xc132 }, +/* 0xc133 */ { true, 0xc133, 0xc133 }, +/* 0xc134 */ { true, 0xc134, 0xc134 }, +/* 0xc135 */ { true, 0xc135, 0xc135 }, +/* 0xc136 */ { true, 0xc136, 0xc136 }, +/* 0xc137 */ { true, 0xc137, 0xc137 }, +/* 0xc138 */ { true, 0xc138, 0xc138 }, +/* 0xc139 */ { true, 0xc139, 0xc139 }, +/* 0xc13a */ { true, 0xc13a, 0xc13a }, +/* 0xc13b */ { true, 0xc13b, 0xc13b }, +/* 0xc13c */ { true, 0xc13c, 0xc13c }, +/* 0xc13d */ { true, 0xc13d, 0xc13d }, +/* 0xc13e */ { true, 0xc13e, 0xc13e }, +/* 0xc13f */ { true, 0xc13f, 0xc13f }, +/* 0xc140 */ { true, 0xc140, 0xc140 }, +/* 0xc141 */ { true, 0xc141, 0xc141 }, +/* 0xc142 */ { true, 0xc142, 0xc142 }, +/* 0xc143 */ { true, 0xc143, 0xc143 }, +/* 0xc144 */ { true, 0xc144, 0xc144 }, +/* 0xc145 */ { true, 0xc145, 0xc145 }, +/* 0xc146 */ { true, 0xc146, 0xc146 }, +/* 0xc147 */ { true, 0xc147, 0xc147 }, +/* 0xc148 */ { true, 0xc148, 0xc148 }, +/* 0xc149 */ { true, 0xc149, 0xc149 }, +/* 0xc14a */ { true, 0xc14a, 0xc14a }, +/* 0xc14b */ { true, 0xc14b, 0xc14b }, +/* 0xc14c */ { true, 0xc14c, 0xc14c }, +/* 0xc14d */ { true, 0xc14d, 0xc14d }, +/* 0xc14e */ { true, 0xc14e, 0xc14e }, +/* 0xc14f */ { true, 0xc14f, 0xc14f }, +/* 0xc150 */ { true, 0xc150, 0xc150 }, +/* 0xc151 */ { true, 0xc151, 0xc151 }, +/* 0xc152 */ { true, 0xc152, 0xc152 }, +/* 0xc153 */ { true, 0xc153, 0xc153 }, +/* 0xc154 */ { true, 0xc154, 0xc154 }, +/* 0xc155 */ { true, 0xc155, 0xc155 }, +/* 0xc156 */ { true, 0xc156, 0xc156 }, +/* 0xc157 */ { true, 0xc157, 0xc157 }, +/* 0xc158 */ { true, 0xc158, 0xc158 }, +/* 0xc159 */ { true, 0xc159, 0xc159 }, +/* 0xc15a */ { true, 0xc15a, 0xc15a }, +/* 0xc15b */ { true, 0xc15b, 0xc15b }, +/* 0xc15c */ { true, 0xc15c, 0xc15c }, +/* 0xc15d */ { true, 0xc15d, 0xc15d }, +/* 0xc15e */ { true, 0xc15e, 0xc15e }, +/* 0xc15f */ { true, 0xc15f, 0xc15f }, +/* 0xc160 */ { true, 0xc160, 0xc160 }, +/* 0xc161 */ { true, 0xc161, 0xc161 }, +/* 0xc162 */ { true, 0xc162, 0xc162 }, +/* 0xc163 */ { true, 0xc163, 0xc163 }, +/* 0xc164 */ { true, 0xc164, 0xc164 }, +/* 0xc165 */ { true, 0xc165, 0xc165 }, +/* 0xc166 */ { true, 0xc166, 0xc166 }, +/* 0xc167 */ { true, 0xc167, 0xc167 }, +/* 0xc168 */ { true, 0xc168, 0xc168 }, +/* 0xc169 */ { true, 0xc169, 0xc169 }, +/* 0xc16a */ { true, 0xc16a, 0xc16a }, +/* 0xc16b */ { true, 0xc16b, 0xc16b }, +/* 0xc16c */ { true, 0xc16c, 0xc16c }, +/* 0xc16d */ { true, 0xc16d, 0xc16d }, +/* 0xc16e */ { true, 0xc16e, 0xc16e }, +/* 0xc16f */ { true, 0xc16f, 0xc16f }, +/* 0xc170 */ { true, 0xc170, 0xc170 }, +/* 0xc171 */ { true, 0xc171, 0xc171 }, +/* 0xc172 */ { true, 0xc172, 0xc172 }, +/* 0xc173 */ { true, 0xc173, 0xc173 }, +/* 0xc174 */ { true, 0xc174, 0xc174 }, +/* 0xc175 */ { true, 0xc175, 0xc175 }, +/* 0xc176 */ { true, 0xc176, 0xc176 }, +/* 0xc177 */ { true, 0xc177, 0xc177 }, +/* 0xc178 */ { true, 0xc178, 0xc178 }, +/* 0xc179 */ { true, 0xc179, 0xc179 }, +/* 0xc17a */ { true, 0xc17a, 0xc17a }, +/* 0xc17b */ { true, 0xc17b, 0xc17b }, +/* 0xc17c */ { true, 0xc17c, 0xc17c }, +/* 0xc17d */ { true, 0xc17d, 0xc17d }, +/* 0xc17e */ { true, 0xc17e, 0xc17e }, +/* 0xc17f */ { true, 0xc17f, 0xc17f }, +/* 0xc180 */ { true, 0xc180, 0xc180 }, +/* 0xc181 */ { true, 0xc181, 0xc181 }, +/* 0xc182 */ { true, 0xc182, 0xc182 }, +/* 0xc183 */ { true, 0xc183, 0xc183 }, +/* 0xc184 */ { true, 0xc184, 0xc184 }, +/* 0xc185 */ { true, 0xc185, 0xc185 }, +/* 0xc186 */ { true, 0xc186, 0xc186 }, +/* 0xc187 */ { true, 0xc187, 0xc187 }, +/* 0xc188 */ { true, 0xc188, 0xc188 }, +/* 0xc189 */ { true, 0xc189, 0xc189 }, +/* 0xc18a */ { true, 0xc18a, 0xc18a }, +/* 0xc18b */ { true, 0xc18b, 0xc18b }, +/* 0xc18c */ { true, 0xc18c, 0xc18c }, +/* 0xc18d */ { true, 0xc18d, 0xc18d }, +/* 0xc18e */ { true, 0xc18e, 0xc18e }, +/* 0xc18f */ { true, 0xc18f, 0xc18f }, +/* 0xc190 */ { true, 0xc190, 0xc190 }, +/* 0xc191 */ { true, 0xc191, 0xc191 }, +/* 0xc192 */ { true, 0xc192, 0xc192 }, +/* 0xc193 */ { true, 0xc193, 0xc193 }, +/* 0xc194 */ { true, 0xc194, 0xc194 }, +/* 0xc195 */ { true, 0xc195, 0xc195 }, +/* 0xc196 */ { true, 0xc196, 0xc196 }, +/* 0xc197 */ { true, 0xc197, 0xc197 }, +/* 0xc198 */ { true, 0xc198, 0xc198 }, +/* 0xc199 */ { true, 0xc199, 0xc199 }, +/* 0xc19a */ { true, 0xc19a, 0xc19a }, +/* 0xc19b */ { true, 0xc19b, 0xc19b }, +/* 0xc19c */ { true, 0xc19c, 0xc19c }, +/* 0xc19d */ { true, 0xc19d, 0xc19d }, +/* 0xc19e */ { true, 0xc19e, 0xc19e }, +/* 0xc19f */ { true, 0xc19f, 0xc19f }, +/* 0xc1a0 */ { true, 0xc1a0, 0xc1a0 }, +/* 0xc1a1 */ { true, 0xc1a1, 0xc1a1 }, +/* 0xc1a2 */ { true, 0xc1a2, 0xc1a2 }, +/* 0xc1a3 */ { true, 0xc1a3, 0xc1a3 }, +/* 0xc1a4 */ { true, 0xc1a4, 0xc1a4 }, +/* 0xc1a5 */ { true, 0xc1a5, 0xc1a5 }, +/* 0xc1a6 */ { true, 0xc1a6, 0xc1a6 }, +/* 0xc1a7 */ { true, 0xc1a7, 0xc1a7 }, +/* 0xc1a8 */ { true, 0xc1a8, 0xc1a8 }, +/* 0xc1a9 */ { true, 0xc1a9, 0xc1a9 }, +/* 0xc1aa */ { true, 0xc1aa, 0xc1aa }, +/* 0xc1ab */ { true, 0xc1ab, 0xc1ab }, +/* 0xc1ac */ { true, 0xc1ac, 0xc1ac }, +/* 0xc1ad */ { true, 0xc1ad, 0xc1ad }, +/* 0xc1ae */ { true, 0xc1ae, 0xc1ae }, +/* 0xc1af */ { true, 0xc1af, 0xc1af }, +/* 0xc1b0 */ { true, 0xc1b0, 0xc1b0 }, +/* 0xc1b1 */ { true, 0xc1b1, 0xc1b1 }, +/* 0xc1b2 */ { true, 0xc1b2, 0xc1b2 }, +/* 0xc1b3 */ { true, 0xc1b3, 0xc1b3 }, +/* 0xc1b4 */ { true, 0xc1b4, 0xc1b4 }, +/* 0xc1b5 */ { true, 0xc1b5, 0xc1b5 }, +/* 0xc1b6 */ { true, 0xc1b6, 0xc1b6 }, +/* 0xc1b7 */ { true, 0xc1b7, 0xc1b7 }, +/* 0xc1b8 */ { true, 0xc1b8, 0xc1b8 }, +/* 0xc1b9 */ { true, 0xc1b9, 0xc1b9 }, +/* 0xc1ba */ { true, 0xc1ba, 0xc1ba }, +/* 0xc1bb */ { true, 0xc1bb, 0xc1bb }, +/* 0xc1bc */ { true, 0xc1bc, 0xc1bc }, +/* 0xc1bd */ { true, 0xc1bd, 0xc1bd }, +/* 0xc1be */ { true, 0xc1be, 0xc1be }, +/* 0xc1bf */ { true, 0xc1bf, 0xc1bf }, +/* 0xc1c0 */ { true, 0xc1c0, 0xc1c0 }, +/* 0xc1c1 */ { true, 0xc1c1, 0xc1c1 }, +/* 0xc1c2 */ { true, 0xc1c2, 0xc1c2 }, +/* 0xc1c3 */ { true, 0xc1c3, 0xc1c3 }, +/* 0xc1c4 */ { true, 0xc1c4, 0xc1c4 }, +/* 0xc1c5 */ { true, 0xc1c5, 0xc1c5 }, +/* 0xc1c6 */ { true, 0xc1c6, 0xc1c6 }, +/* 0xc1c7 */ { true, 0xc1c7, 0xc1c7 }, +/* 0xc1c8 */ { true, 0xc1c8, 0xc1c8 }, +/* 0xc1c9 */ { true, 0xc1c9, 0xc1c9 }, +/* 0xc1ca */ { true, 0xc1ca, 0xc1ca }, +/* 0xc1cb */ { true, 0xc1cb, 0xc1cb }, +/* 0xc1cc */ { true, 0xc1cc, 0xc1cc }, +/* 0xc1cd */ { true, 0xc1cd, 0xc1cd }, +/* 0xc1ce */ { true, 0xc1ce, 0xc1ce }, +/* 0xc1cf */ { true, 0xc1cf, 0xc1cf }, +/* 0xc1d0 */ { true, 0xc1d0, 0xc1d0 }, +/* 0xc1d1 */ { true, 0xc1d1, 0xc1d1 }, +/* 0xc1d2 */ { true, 0xc1d2, 0xc1d2 }, +/* 0xc1d3 */ { true, 0xc1d3, 0xc1d3 }, +/* 0xc1d4 */ { true, 0xc1d4, 0xc1d4 }, +/* 0xc1d5 */ { true, 0xc1d5, 0xc1d5 }, +/* 0xc1d6 */ { true, 0xc1d6, 0xc1d6 }, +/* 0xc1d7 */ { true, 0xc1d7, 0xc1d7 }, +/* 0xc1d8 */ { true, 0xc1d8, 0xc1d8 }, +/* 0xc1d9 */ { true, 0xc1d9, 0xc1d9 }, +/* 0xc1da */ { true, 0xc1da, 0xc1da }, +/* 0xc1db */ { true, 0xc1db, 0xc1db }, +/* 0xc1dc */ { true, 0xc1dc, 0xc1dc }, +/* 0xc1dd */ { true, 0xc1dd, 0xc1dd }, +/* 0xc1de */ { true, 0xc1de, 0xc1de }, +/* 0xc1df */ { true, 0xc1df, 0xc1df }, +/* 0xc1e0 */ { true, 0xc1e0, 0xc1e0 }, +/* 0xc1e1 */ { true, 0xc1e1, 0xc1e1 }, +/* 0xc1e2 */ { true, 0xc1e2, 0xc1e2 }, +/* 0xc1e3 */ { true, 0xc1e3, 0xc1e3 }, +/* 0xc1e4 */ { true, 0xc1e4, 0xc1e4 }, +/* 0xc1e5 */ { true, 0xc1e5, 0xc1e5 }, +/* 0xc1e6 */ { true, 0xc1e6, 0xc1e6 }, +/* 0xc1e7 */ { true, 0xc1e7, 0xc1e7 }, +/* 0xc1e8 */ { true, 0xc1e8, 0xc1e8 }, +/* 0xc1e9 */ { true, 0xc1e9, 0xc1e9 }, +/* 0xc1ea */ { true, 0xc1ea, 0xc1ea }, +/* 0xc1eb */ { true, 0xc1eb, 0xc1eb }, +/* 0xc1ec */ { true, 0xc1ec, 0xc1ec }, +/* 0xc1ed */ { true, 0xc1ed, 0xc1ed }, +/* 0xc1ee */ { true, 0xc1ee, 0xc1ee }, +/* 0xc1ef */ { true, 0xc1ef, 0xc1ef }, +/* 0xc1f0 */ { true, 0xc1f0, 0xc1f0 }, +/* 0xc1f1 */ { true, 0xc1f1, 0xc1f1 }, +/* 0xc1f2 */ { true, 0xc1f2, 0xc1f2 }, +/* 0xc1f3 */ { true, 0xc1f3, 0xc1f3 }, +/* 0xc1f4 */ { true, 0xc1f4, 0xc1f4 }, +/* 0xc1f5 */ { true, 0xc1f5, 0xc1f5 }, +/* 0xc1f6 */ { true, 0xc1f6, 0xc1f6 }, +/* 0xc1f7 */ { true, 0xc1f7, 0xc1f7 }, +/* 0xc1f8 */ { true, 0xc1f8, 0xc1f8 }, +/* 0xc1f9 */ { true, 0xc1f9, 0xc1f9 }, +/* 0xc1fa */ { true, 0xc1fa, 0xc1fa }, +/* 0xc1fb */ { true, 0xc1fb, 0xc1fb }, +/* 0xc1fc */ { true, 0xc1fc, 0xc1fc }, +/* 0xc1fd */ { true, 0xc1fd, 0xc1fd }, +/* 0xc1fe */ { true, 0xc1fe, 0xc1fe }, +/* 0xc1ff */ { true, 0xc1ff, 0xc1ff }, +/* 0xc200 */ { true, 0xc200, 0xc200 }, +/* 0xc201 */ { true, 0xc201, 0xc201 }, +/* 0xc202 */ { true, 0xc202, 0xc202 }, +/* 0xc203 */ { true, 0xc203, 0xc203 }, +/* 0xc204 */ { true, 0xc204, 0xc204 }, +/* 0xc205 */ { true, 0xc205, 0xc205 }, +/* 0xc206 */ { true, 0xc206, 0xc206 }, +/* 0xc207 */ { true, 0xc207, 0xc207 }, +/* 0xc208 */ { true, 0xc208, 0xc208 }, +/* 0xc209 */ { true, 0xc209, 0xc209 }, +/* 0xc20a */ { true, 0xc20a, 0xc20a }, +/* 0xc20b */ { true, 0xc20b, 0xc20b }, +/* 0xc20c */ { true, 0xc20c, 0xc20c }, +/* 0xc20d */ { true, 0xc20d, 0xc20d }, +/* 0xc20e */ { true, 0xc20e, 0xc20e }, +/* 0xc20f */ { true, 0xc20f, 0xc20f }, +/* 0xc210 */ { true, 0xc210, 0xc210 }, +/* 0xc211 */ { true, 0xc211, 0xc211 }, +/* 0xc212 */ { true, 0xc212, 0xc212 }, +/* 0xc213 */ { true, 0xc213, 0xc213 }, +/* 0xc214 */ { true, 0xc214, 0xc214 }, +/* 0xc215 */ { true, 0xc215, 0xc215 }, +/* 0xc216 */ { true, 0xc216, 0xc216 }, +/* 0xc217 */ { true, 0xc217, 0xc217 }, +/* 0xc218 */ { true, 0xc218, 0xc218 }, +/* 0xc219 */ { true, 0xc219, 0xc219 }, +/* 0xc21a */ { true, 0xc21a, 0xc21a }, +/* 0xc21b */ { true, 0xc21b, 0xc21b }, +/* 0xc21c */ { true, 0xc21c, 0xc21c }, +/* 0xc21d */ { true, 0xc21d, 0xc21d }, +/* 0xc21e */ { true, 0xc21e, 0xc21e }, +/* 0xc21f */ { true, 0xc21f, 0xc21f }, +/* 0xc220 */ { true, 0xc220, 0xc220 }, +/* 0xc221 */ { true, 0xc221, 0xc221 }, +/* 0xc222 */ { true, 0xc222, 0xc222 }, +/* 0xc223 */ { true, 0xc223, 0xc223 }, +/* 0xc224 */ { true, 0xc224, 0xc224 }, +/* 0xc225 */ { true, 0xc225, 0xc225 }, +/* 0xc226 */ { true, 0xc226, 0xc226 }, +/* 0xc227 */ { true, 0xc227, 0xc227 }, +/* 0xc228 */ { true, 0xc228, 0xc228 }, +/* 0xc229 */ { true, 0xc229, 0xc229 }, +/* 0xc22a */ { true, 0xc22a, 0xc22a }, +/* 0xc22b */ { true, 0xc22b, 0xc22b }, +/* 0xc22c */ { true, 0xc22c, 0xc22c }, +/* 0xc22d */ { true, 0xc22d, 0xc22d }, +/* 0xc22e */ { true, 0xc22e, 0xc22e }, +/* 0xc22f */ { true, 0xc22f, 0xc22f }, +/* 0xc230 */ { true, 0xc230, 0xc230 }, +/* 0xc231 */ { true, 0xc231, 0xc231 }, +/* 0xc232 */ { true, 0xc232, 0xc232 }, +/* 0xc233 */ { true, 0xc233, 0xc233 }, +/* 0xc234 */ { true, 0xc234, 0xc234 }, +/* 0xc235 */ { true, 0xc235, 0xc235 }, +/* 0xc236 */ { true, 0xc236, 0xc236 }, +/* 0xc237 */ { true, 0xc237, 0xc237 }, +/* 0xc238 */ { true, 0xc238, 0xc238 }, +/* 0xc239 */ { true, 0xc239, 0xc239 }, +/* 0xc23a */ { true, 0xc23a, 0xc23a }, +/* 0xc23b */ { true, 0xc23b, 0xc23b }, +/* 0xc23c */ { true, 0xc23c, 0xc23c }, +/* 0xc23d */ { true, 0xc23d, 0xc23d }, +/* 0xc23e */ { true, 0xc23e, 0xc23e }, +/* 0xc23f */ { true, 0xc23f, 0xc23f }, +/* 0xc240 */ { true, 0xc240, 0xc240 }, +/* 0xc241 */ { true, 0xc241, 0xc241 }, +/* 0xc242 */ { true, 0xc242, 0xc242 }, +/* 0xc243 */ { true, 0xc243, 0xc243 }, +/* 0xc244 */ { true, 0xc244, 0xc244 }, +/* 0xc245 */ { true, 0xc245, 0xc245 }, +/* 0xc246 */ { true, 0xc246, 0xc246 }, +/* 0xc247 */ { true, 0xc247, 0xc247 }, +/* 0xc248 */ { true, 0xc248, 0xc248 }, +/* 0xc249 */ { true, 0xc249, 0xc249 }, +/* 0xc24a */ { true, 0xc24a, 0xc24a }, +/* 0xc24b */ { true, 0xc24b, 0xc24b }, +/* 0xc24c */ { true, 0xc24c, 0xc24c }, +/* 0xc24d */ { true, 0xc24d, 0xc24d }, +/* 0xc24e */ { true, 0xc24e, 0xc24e }, +/* 0xc24f */ { true, 0xc24f, 0xc24f }, +/* 0xc250 */ { true, 0xc250, 0xc250 }, +/* 0xc251 */ { true, 0xc251, 0xc251 }, +/* 0xc252 */ { true, 0xc252, 0xc252 }, +/* 0xc253 */ { true, 0xc253, 0xc253 }, +/* 0xc254 */ { true, 0xc254, 0xc254 }, +/* 0xc255 */ { true, 0xc255, 0xc255 }, +/* 0xc256 */ { true, 0xc256, 0xc256 }, +/* 0xc257 */ { true, 0xc257, 0xc257 }, +/* 0xc258 */ { true, 0xc258, 0xc258 }, +/* 0xc259 */ { true, 0xc259, 0xc259 }, +/* 0xc25a */ { true, 0xc25a, 0xc25a }, +/* 0xc25b */ { true, 0xc25b, 0xc25b }, +/* 0xc25c */ { true, 0xc25c, 0xc25c }, +/* 0xc25d */ { true, 0xc25d, 0xc25d }, +/* 0xc25e */ { true, 0xc25e, 0xc25e }, +/* 0xc25f */ { true, 0xc25f, 0xc25f }, +/* 0xc260 */ { true, 0xc260, 0xc260 }, +/* 0xc261 */ { true, 0xc261, 0xc261 }, +/* 0xc262 */ { true, 0xc262, 0xc262 }, +/* 0xc263 */ { true, 0xc263, 0xc263 }, +/* 0xc264 */ { true, 0xc264, 0xc264 }, +/* 0xc265 */ { true, 0xc265, 0xc265 }, +/* 0xc266 */ { true, 0xc266, 0xc266 }, +/* 0xc267 */ { true, 0xc267, 0xc267 }, +/* 0xc268 */ { true, 0xc268, 0xc268 }, +/* 0xc269 */ { true, 0xc269, 0xc269 }, +/* 0xc26a */ { true, 0xc26a, 0xc26a }, +/* 0xc26b */ { true, 0xc26b, 0xc26b }, +/* 0xc26c */ { true, 0xc26c, 0xc26c }, +/* 0xc26d */ { true, 0xc26d, 0xc26d }, +/* 0xc26e */ { true, 0xc26e, 0xc26e }, +/* 0xc26f */ { true, 0xc26f, 0xc26f }, +/* 0xc270 */ { true, 0xc270, 0xc270 }, +/* 0xc271 */ { true, 0xc271, 0xc271 }, +/* 0xc272 */ { true, 0xc272, 0xc272 }, +/* 0xc273 */ { true, 0xc273, 0xc273 }, +/* 0xc274 */ { true, 0xc274, 0xc274 }, +/* 0xc275 */ { true, 0xc275, 0xc275 }, +/* 0xc276 */ { true, 0xc276, 0xc276 }, +/* 0xc277 */ { true, 0xc277, 0xc277 }, +/* 0xc278 */ { true, 0xc278, 0xc278 }, +/* 0xc279 */ { true, 0xc279, 0xc279 }, +/* 0xc27a */ { true, 0xc27a, 0xc27a }, +/* 0xc27b */ { true, 0xc27b, 0xc27b }, +/* 0xc27c */ { true, 0xc27c, 0xc27c }, +/* 0xc27d */ { true, 0xc27d, 0xc27d }, +/* 0xc27e */ { true, 0xc27e, 0xc27e }, +/* 0xc27f */ { true, 0xc27f, 0xc27f }, +/* 0xc280 */ { true, 0xc280, 0xc280 }, +/* 0xc281 */ { true, 0xc281, 0xc281 }, +/* 0xc282 */ { true, 0xc282, 0xc282 }, +/* 0xc283 */ { true, 0xc283, 0xc283 }, +/* 0xc284 */ { true, 0xc284, 0xc284 }, +/* 0xc285 */ { true, 0xc285, 0xc285 }, +/* 0xc286 */ { true, 0xc286, 0xc286 }, +/* 0xc287 */ { true, 0xc287, 0xc287 }, +/* 0xc288 */ { true, 0xc288, 0xc288 }, +/* 0xc289 */ { true, 0xc289, 0xc289 }, +/* 0xc28a */ { true, 0xc28a, 0xc28a }, +/* 0xc28b */ { true, 0xc28b, 0xc28b }, +/* 0xc28c */ { true, 0xc28c, 0xc28c }, +/* 0xc28d */ { true, 0xc28d, 0xc28d }, +/* 0xc28e */ { true, 0xc28e, 0xc28e }, +/* 0xc28f */ { true, 0xc28f, 0xc28f }, +/* 0xc290 */ { true, 0xc290, 0xc290 }, +/* 0xc291 */ { true, 0xc291, 0xc291 }, +/* 0xc292 */ { true, 0xc292, 0xc292 }, +/* 0xc293 */ { true, 0xc293, 0xc293 }, +/* 0xc294 */ { true, 0xc294, 0xc294 }, +/* 0xc295 */ { true, 0xc295, 0xc295 }, +/* 0xc296 */ { true, 0xc296, 0xc296 }, +/* 0xc297 */ { true, 0xc297, 0xc297 }, +/* 0xc298 */ { true, 0xc298, 0xc298 }, +/* 0xc299 */ { true, 0xc299, 0xc299 }, +/* 0xc29a */ { true, 0xc29a, 0xc29a }, +/* 0xc29b */ { true, 0xc29b, 0xc29b }, +/* 0xc29c */ { true, 0xc29c, 0xc29c }, +/* 0xc29d */ { true, 0xc29d, 0xc29d }, +/* 0xc29e */ { true, 0xc29e, 0xc29e }, +/* 0xc29f */ { true, 0xc29f, 0xc29f }, +/* 0xc2a0 */ { true, 0xc2a0, 0xc2a0 }, +/* 0xc2a1 */ { true, 0xc2a1, 0xc2a1 }, +/* 0xc2a2 */ { true, 0xc2a2, 0xc2a2 }, +/* 0xc2a3 */ { true, 0xc2a3, 0xc2a3 }, +/* 0xc2a4 */ { true, 0xc2a4, 0xc2a4 }, +/* 0xc2a5 */ { true, 0xc2a5, 0xc2a5 }, +/* 0xc2a6 */ { true, 0xc2a6, 0xc2a6 }, +/* 0xc2a7 */ { true, 0xc2a7, 0xc2a7 }, +/* 0xc2a8 */ { true, 0xc2a8, 0xc2a8 }, +/* 0xc2a9 */ { true, 0xc2a9, 0xc2a9 }, +/* 0xc2aa */ { true, 0xc2aa, 0xc2aa }, +/* 0xc2ab */ { true, 0xc2ab, 0xc2ab }, +/* 0xc2ac */ { true, 0xc2ac, 0xc2ac }, +/* 0xc2ad */ { true, 0xc2ad, 0xc2ad }, +/* 0xc2ae */ { true, 0xc2ae, 0xc2ae }, +/* 0xc2af */ { true, 0xc2af, 0xc2af }, +/* 0xc2b0 */ { true, 0xc2b0, 0xc2b0 }, +/* 0xc2b1 */ { true, 0xc2b1, 0xc2b1 }, +/* 0xc2b2 */ { true, 0xc2b2, 0xc2b2 }, +/* 0xc2b3 */ { true, 0xc2b3, 0xc2b3 }, +/* 0xc2b4 */ { true, 0xc2b4, 0xc2b4 }, +/* 0xc2b5 */ { true, 0xc2b5, 0xc2b5 }, +/* 0xc2b6 */ { true, 0xc2b6, 0xc2b6 }, +/* 0xc2b7 */ { true, 0xc2b7, 0xc2b7 }, +/* 0xc2b8 */ { true, 0xc2b8, 0xc2b8 }, +/* 0xc2b9 */ { true, 0xc2b9, 0xc2b9 }, +/* 0xc2ba */ { true, 0xc2ba, 0xc2ba }, +/* 0xc2bb */ { true, 0xc2bb, 0xc2bb }, +/* 0xc2bc */ { true, 0xc2bc, 0xc2bc }, +/* 0xc2bd */ { true, 0xc2bd, 0xc2bd }, +/* 0xc2be */ { true, 0xc2be, 0xc2be }, +/* 0xc2bf */ { true, 0xc2bf, 0xc2bf }, +/* 0xc2c0 */ { true, 0xc2c0, 0xc2c0 }, +/* 0xc2c1 */ { true, 0xc2c1, 0xc2c1 }, +/* 0xc2c2 */ { true, 0xc2c2, 0xc2c2 }, +/* 0xc2c3 */ { true, 0xc2c3, 0xc2c3 }, +/* 0xc2c4 */ { true, 0xc2c4, 0xc2c4 }, +/* 0xc2c5 */ { true, 0xc2c5, 0xc2c5 }, +/* 0xc2c6 */ { true, 0xc2c6, 0xc2c6 }, +/* 0xc2c7 */ { true, 0xc2c7, 0xc2c7 }, +/* 0xc2c8 */ { true, 0xc2c8, 0xc2c8 }, +/* 0xc2c9 */ { true, 0xc2c9, 0xc2c9 }, +/* 0xc2ca */ { true, 0xc2ca, 0xc2ca }, +/* 0xc2cb */ { true, 0xc2cb, 0xc2cb }, +/* 0xc2cc */ { true, 0xc2cc, 0xc2cc }, +/* 0xc2cd */ { true, 0xc2cd, 0xc2cd }, +/* 0xc2ce */ { true, 0xc2ce, 0xc2ce }, +/* 0xc2cf */ { true, 0xc2cf, 0xc2cf }, +/* 0xc2d0 */ { true, 0xc2d0, 0xc2d0 }, +/* 0xc2d1 */ { true, 0xc2d1, 0xc2d1 }, +/* 0xc2d2 */ { true, 0xc2d2, 0xc2d2 }, +/* 0xc2d3 */ { true, 0xc2d3, 0xc2d3 }, +/* 0xc2d4 */ { true, 0xc2d4, 0xc2d4 }, +/* 0xc2d5 */ { true, 0xc2d5, 0xc2d5 }, +/* 0xc2d6 */ { true, 0xc2d6, 0xc2d6 }, +/* 0xc2d7 */ { true, 0xc2d7, 0xc2d7 }, +/* 0xc2d8 */ { true, 0xc2d8, 0xc2d8 }, +/* 0xc2d9 */ { true, 0xc2d9, 0xc2d9 }, +/* 0xc2da */ { true, 0xc2da, 0xc2da }, +/* 0xc2db */ { true, 0xc2db, 0xc2db }, +/* 0xc2dc */ { true, 0xc2dc, 0xc2dc }, +/* 0xc2dd */ { true, 0xc2dd, 0xc2dd }, +/* 0xc2de */ { true, 0xc2de, 0xc2de }, +/* 0xc2df */ { true, 0xc2df, 0xc2df }, +/* 0xc2e0 */ { true, 0xc2e0, 0xc2e0 }, +/* 0xc2e1 */ { true, 0xc2e1, 0xc2e1 }, +/* 0xc2e2 */ { true, 0xc2e2, 0xc2e2 }, +/* 0xc2e3 */ { true, 0xc2e3, 0xc2e3 }, +/* 0xc2e4 */ { true, 0xc2e4, 0xc2e4 }, +/* 0xc2e5 */ { true, 0xc2e5, 0xc2e5 }, +/* 0xc2e6 */ { true, 0xc2e6, 0xc2e6 }, +/* 0xc2e7 */ { true, 0xc2e7, 0xc2e7 }, +/* 0xc2e8 */ { true, 0xc2e8, 0xc2e8 }, +/* 0xc2e9 */ { true, 0xc2e9, 0xc2e9 }, +/* 0xc2ea */ { true, 0xc2ea, 0xc2ea }, +/* 0xc2eb */ { true, 0xc2eb, 0xc2eb }, +/* 0xc2ec */ { true, 0xc2ec, 0xc2ec }, +/* 0xc2ed */ { true, 0xc2ed, 0xc2ed }, +/* 0xc2ee */ { true, 0xc2ee, 0xc2ee }, +/* 0xc2ef */ { true, 0xc2ef, 0xc2ef }, +/* 0xc2f0 */ { true, 0xc2f0, 0xc2f0 }, +/* 0xc2f1 */ { true, 0xc2f1, 0xc2f1 }, +/* 0xc2f2 */ { true, 0xc2f2, 0xc2f2 }, +/* 0xc2f3 */ { true, 0xc2f3, 0xc2f3 }, +/* 0xc2f4 */ { true, 0xc2f4, 0xc2f4 }, +/* 0xc2f5 */ { true, 0xc2f5, 0xc2f5 }, +/* 0xc2f6 */ { true, 0xc2f6, 0xc2f6 }, +/* 0xc2f7 */ { true, 0xc2f7, 0xc2f7 }, +/* 0xc2f8 */ { true, 0xc2f8, 0xc2f8 }, +/* 0xc2f9 */ { true, 0xc2f9, 0xc2f9 }, +/* 0xc2fa */ { true, 0xc2fa, 0xc2fa }, +/* 0xc2fb */ { true, 0xc2fb, 0xc2fb }, +/* 0xc2fc */ { true, 0xc2fc, 0xc2fc }, +/* 0xc2fd */ { true, 0xc2fd, 0xc2fd }, +/* 0xc2fe */ { true, 0xc2fe, 0xc2fe }, +/* 0xc2ff */ { true, 0xc2ff, 0xc2ff }, +/* 0xc300 */ { true, 0xc300, 0xc300 }, +/* 0xc301 */ { true, 0xc301, 0xc301 }, +/* 0xc302 */ { true, 0xc302, 0xc302 }, +/* 0xc303 */ { true, 0xc303, 0xc303 }, +/* 0xc304 */ { true, 0xc304, 0xc304 }, +/* 0xc305 */ { true, 0xc305, 0xc305 }, +/* 0xc306 */ { true, 0xc306, 0xc306 }, +/* 0xc307 */ { true, 0xc307, 0xc307 }, +/* 0xc308 */ { true, 0xc308, 0xc308 }, +/* 0xc309 */ { true, 0xc309, 0xc309 }, +/* 0xc30a */ { true, 0xc30a, 0xc30a }, +/* 0xc30b */ { true, 0xc30b, 0xc30b }, +/* 0xc30c */ { true, 0xc30c, 0xc30c }, +/* 0xc30d */ { true, 0xc30d, 0xc30d }, +/* 0xc30e */ { true, 0xc30e, 0xc30e }, +/* 0xc30f */ { true, 0xc30f, 0xc30f }, +/* 0xc310 */ { true, 0xc310, 0xc310 }, +/* 0xc311 */ { true, 0xc311, 0xc311 }, +/* 0xc312 */ { true, 0xc312, 0xc312 }, +/* 0xc313 */ { true, 0xc313, 0xc313 }, +/* 0xc314 */ { true, 0xc314, 0xc314 }, +/* 0xc315 */ { true, 0xc315, 0xc315 }, +/* 0xc316 */ { true, 0xc316, 0xc316 }, +/* 0xc317 */ { true, 0xc317, 0xc317 }, +/* 0xc318 */ { true, 0xc318, 0xc318 }, +/* 0xc319 */ { true, 0xc319, 0xc319 }, +/* 0xc31a */ { true, 0xc31a, 0xc31a }, +/* 0xc31b */ { true, 0xc31b, 0xc31b }, +/* 0xc31c */ { true, 0xc31c, 0xc31c }, +/* 0xc31d */ { true, 0xc31d, 0xc31d }, +/* 0xc31e */ { true, 0xc31e, 0xc31e }, +/* 0xc31f */ { true, 0xc31f, 0xc31f }, +/* 0xc320 */ { true, 0xc320, 0xc320 }, +/* 0xc321 */ { true, 0xc321, 0xc321 }, +/* 0xc322 */ { true, 0xc322, 0xc322 }, +/* 0xc323 */ { true, 0xc323, 0xc323 }, +/* 0xc324 */ { true, 0xc324, 0xc324 }, +/* 0xc325 */ { true, 0xc325, 0xc325 }, +/* 0xc326 */ { true, 0xc326, 0xc326 }, +/* 0xc327 */ { true, 0xc327, 0xc327 }, +/* 0xc328 */ { true, 0xc328, 0xc328 }, +/* 0xc329 */ { true, 0xc329, 0xc329 }, +/* 0xc32a */ { true, 0xc32a, 0xc32a }, +/* 0xc32b */ { true, 0xc32b, 0xc32b }, +/* 0xc32c */ { true, 0xc32c, 0xc32c }, +/* 0xc32d */ { true, 0xc32d, 0xc32d }, +/* 0xc32e */ { true, 0xc32e, 0xc32e }, +/* 0xc32f */ { true, 0xc32f, 0xc32f }, +/* 0xc330 */ { true, 0xc330, 0xc330 }, +/* 0xc331 */ { true, 0xc331, 0xc331 }, +/* 0xc332 */ { true, 0xc332, 0xc332 }, +/* 0xc333 */ { true, 0xc333, 0xc333 }, +/* 0xc334 */ { true, 0xc334, 0xc334 }, +/* 0xc335 */ { true, 0xc335, 0xc335 }, +/* 0xc336 */ { true, 0xc336, 0xc336 }, +/* 0xc337 */ { true, 0xc337, 0xc337 }, +/* 0xc338 */ { true, 0xc338, 0xc338 }, +/* 0xc339 */ { true, 0xc339, 0xc339 }, +/* 0xc33a */ { true, 0xc33a, 0xc33a }, +/* 0xc33b */ { true, 0xc33b, 0xc33b }, +/* 0xc33c */ { true, 0xc33c, 0xc33c }, +/* 0xc33d */ { true, 0xc33d, 0xc33d }, +/* 0xc33e */ { true, 0xc33e, 0xc33e }, +/* 0xc33f */ { true, 0xc33f, 0xc33f }, +/* 0xc340 */ { true, 0xc340, 0xc340 }, +/* 0xc341 */ { true, 0xc341, 0xc341 }, +/* 0xc342 */ { true, 0xc342, 0xc342 }, +/* 0xc343 */ { true, 0xc343, 0xc343 }, +/* 0xc344 */ { true, 0xc344, 0xc344 }, +/* 0xc345 */ { true, 0xc345, 0xc345 }, +/* 0xc346 */ { true, 0xc346, 0xc346 }, +/* 0xc347 */ { true, 0xc347, 0xc347 }, +/* 0xc348 */ { true, 0xc348, 0xc348 }, +/* 0xc349 */ { true, 0xc349, 0xc349 }, +/* 0xc34a */ { true, 0xc34a, 0xc34a }, +/* 0xc34b */ { true, 0xc34b, 0xc34b }, +/* 0xc34c */ { true, 0xc34c, 0xc34c }, +/* 0xc34d */ { true, 0xc34d, 0xc34d }, +/* 0xc34e */ { true, 0xc34e, 0xc34e }, +/* 0xc34f */ { true, 0xc34f, 0xc34f }, +/* 0xc350 */ { true, 0xc350, 0xc350 }, +/* 0xc351 */ { true, 0xc351, 0xc351 }, +/* 0xc352 */ { true, 0xc352, 0xc352 }, +/* 0xc353 */ { true, 0xc353, 0xc353 }, +/* 0xc354 */ { true, 0xc354, 0xc354 }, +/* 0xc355 */ { true, 0xc355, 0xc355 }, +/* 0xc356 */ { true, 0xc356, 0xc356 }, +/* 0xc357 */ { true, 0xc357, 0xc357 }, +/* 0xc358 */ { true, 0xc358, 0xc358 }, +/* 0xc359 */ { true, 0xc359, 0xc359 }, +/* 0xc35a */ { true, 0xc35a, 0xc35a }, +/* 0xc35b */ { true, 0xc35b, 0xc35b }, +/* 0xc35c */ { true, 0xc35c, 0xc35c }, +/* 0xc35d */ { true, 0xc35d, 0xc35d }, +/* 0xc35e */ { true, 0xc35e, 0xc35e }, +/* 0xc35f */ { true, 0xc35f, 0xc35f }, +/* 0xc360 */ { true, 0xc360, 0xc360 }, +/* 0xc361 */ { true, 0xc361, 0xc361 }, +/* 0xc362 */ { true, 0xc362, 0xc362 }, +/* 0xc363 */ { true, 0xc363, 0xc363 }, +/* 0xc364 */ { true, 0xc364, 0xc364 }, +/* 0xc365 */ { true, 0xc365, 0xc365 }, +/* 0xc366 */ { true, 0xc366, 0xc366 }, +/* 0xc367 */ { true, 0xc367, 0xc367 }, +/* 0xc368 */ { true, 0xc368, 0xc368 }, +/* 0xc369 */ { true, 0xc369, 0xc369 }, +/* 0xc36a */ { true, 0xc36a, 0xc36a }, +/* 0xc36b */ { true, 0xc36b, 0xc36b }, +/* 0xc36c */ { true, 0xc36c, 0xc36c }, +/* 0xc36d */ { true, 0xc36d, 0xc36d }, +/* 0xc36e */ { true, 0xc36e, 0xc36e }, +/* 0xc36f */ { true, 0xc36f, 0xc36f }, +/* 0xc370 */ { true, 0xc370, 0xc370 }, +/* 0xc371 */ { true, 0xc371, 0xc371 }, +/* 0xc372 */ { true, 0xc372, 0xc372 }, +/* 0xc373 */ { true, 0xc373, 0xc373 }, +/* 0xc374 */ { true, 0xc374, 0xc374 }, +/* 0xc375 */ { true, 0xc375, 0xc375 }, +/* 0xc376 */ { true, 0xc376, 0xc376 }, +/* 0xc377 */ { true, 0xc377, 0xc377 }, +/* 0xc378 */ { true, 0xc378, 0xc378 }, +/* 0xc379 */ { true, 0xc379, 0xc379 }, +/* 0xc37a */ { true, 0xc37a, 0xc37a }, +/* 0xc37b */ { true, 0xc37b, 0xc37b }, +/* 0xc37c */ { true, 0xc37c, 0xc37c }, +/* 0xc37d */ { true, 0xc37d, 0xc37d }, +/* 0xc37e */ { true, 0xc37e, 0xc37e }, +/* 0xc37f */ { true, 0xc37f, 0xc37f }, +/* 0xc380 */ { true, 0xc380, 0xc380 }, +/* 0xc381 */ { true, 0xc381, 0xc381 }, +/* 0xc382 */ { true, 0xc382, 0xc382 }, +/* 0xc383 */ { true, 0xc383, 0xc383 }, +/* 0xc384 */ { true, 0xc384, 0xc384 }, +/* 0xc385 */ { true, 0xc385, 0xc385 }, +/* 0xc386 */ { true, 0xc386, 0xc386 }, +/* 0xc387 */ { true, 0xc387, 0xc387 }, +/* 0xc388 */ { true, 0xc388, 0xc388 }, +/* 0xc389 */ { true, 0xc389, 0xc389 }, +/* 0xc38a */ { true, 0xc38a, 0xc38a }, +/* 0xc38b */ { true, 0xc38b, 0xc38b }, +/* 0xc38c */ { true, 0xc38c, 0xc38c }, +/* 0xc38d */ { true, 0xc38d, 0xc38d }, +/* 0xc38e */ { true, 0xc38e, 0xc38e }, +/* 0xc38f */ { true, 0xc38f, 0xc38f }, +/* 0xc390 */ { true, 0xc390, 0xc390 }, +/* 0xc391 */ { true, 0xc391, 0xc391 }, +/* 0xc392 */ { true, 0xc392, 0xc392 }, +/* 0xc393 */ { true, 0xc393, 0xc393 }, +/* 0xc394 */ { true, 0xc394, 0xc394 }, +/* 0xc395 */ { true, 0xc395, 0xc395 }, +/* 0xc396 */ { true, 0xc396, 0xc396 }, +/* 0xc397 */ { true, 0xc397, 0xc397 }, +/* 0xc398 */ { true, 0xc398, 0xc398 }, +/* 0xc399 */ { true, 0xc399, 0xc399 }, +/* 0xc39a */ { true, 0xc39a, 0xc39a }, +/* 0xc39b */ { true, 0xc39b, 0xc39b }, +/* 0xc39c */ { true, 0xc39c, 0xc39c }, +/* 0xc39d */ { true, 0xc39d, 0xc39d }, +/* 0xc39e */ { true, 0xc39e, 0xc39e }, +/* 0xc39f */ { true, 0xc39f, 0xc39f }, +/* 0xc3a0 */ { true, 0xc3a0, 0xc3a0 }, +/* 0xc3a1 */ { true, 0xc3a1, 0xc3a1 }, +/* 0xc3a2 */ { true, 0xc3a2, 0xc3a2 }, +/* 0xc3a3 */ { true, 0xc3a3, 0xc3a3 }, +/* 0xc3a4 */ { true, 0xc3a4, 0xc3a4 }, +/* 0xc3a5 */ { true, 0xc3a5, 0xc3a5 }, +/* 0xc3a6 */ { true, 0xc3a6, 0xc3a6 }, +/* 0xc3a7 */ { true, 0xc3a7, 0xc3a7 }, +/* 0xc3a8 */ { true, 0xc3a8, 0xc3a8 }, +/* 0xc3a9 */ { true, 0xc3a9, 0xc3a9 }, +/* 0xc3aa */ { true, 0xc3aa, 0xc3aa }, +/* 0xc3ab */ { true, 0xc3ab, 0xc3ab }, +/* 0xc3ac */ { true, 0xc3ac, 0xc3ac }, +/* 0xc3ad */ { true, 0xc3ad, 0xc3ad }, +/* 0xc3ae */ { true, 0xc3ae, 0xc3ae }, +/* 0xc3af */ { true, 0xc3af, 0xc3af }, +/* 0xc3b0 */ { true, 0xc3b0, 0xc3b0 }, +/* 0xc3b1 */ { true, 0xc3b1, 0xc3b1 }, +/* 0xc3b2 */ { true, 0xc3b2, 0xc3b2 }, +/* 0xc3b3 */ { true, 0xc3b3, 0xc3b3 }, +/* 0xc3b4 */ { true, 0xc3b4, 0xc3b4 }, +/* 0xc3b5 */ { true, 0xc3b5, 0xc3b5 }, +/* 0xc3b6 */ { true, 0xc3b6, 0xc3b6 }, +/* 0xc3b7 */ { true, 0xc3b7, 0xc3b7 }, +/* 0xc3b8 */ { true, 0xc3b8, 0xc3b8 }, +/* 0xc3b9 */ { true, 0xc3b9, 0xc3b9 }, +/* 0xc3ba */ { true, 0xc3ba, 0xc3ba }, +/* 0xc3bb */ { true, 0xc3bb, 0xc3bb }, +/* 0xc3bc */ { true, 0xc3bc, 0xc3bc }, +/* 0xc3bd */ { true, 0xc3bd, 0xc3bd }, +/* 0xc3be */ { true, 0xc3be, 0xc3be }, +/* 0xc3bf */ { true, 0xc3bf, 0xc3bf }, +/* 0xc3c0 */ { true, 0xc3c0, 0xc3c0 }, +/* 0xc3c1 */ { true, 0xc3c1, 0xc3c1 }, +/* 0xc3c2 */ { true, 0xc3c2, 0xc3c2 }, +/* 0xc3c3 */ { true, 0xc3c3, 0xc3c3 }, +/* 0xc3c4 */ { true, 0xc3c4, 0xc3c4 }, +/* 0xc3c5 */ { true, 0xc3c5, 0xc3c5 }, +/* 0xc3c6 */ { true, 0xc3c6, 0xc3c6 }, +/* 0xc3c7 */ { true, 0xc3c7, 0xc3c7 }, +/* 0xc3c8 */ { true, 0xc3c8, 0xc3c8 }, +/* 0xc3c9 */ { true, 0xc3c9, 0xc3c9 }, +/* 0xc3ca */ { true, 0xc3ca, 0xc3ca }, +/* 0xc3cb */ { true, 0xc3cb, 0xc3cb }, +/* 0xc3cc */ { true, 0xc3cc, 0xc3cc }, +/* 0xc3cd */ { true, 0xc3cd, 0xc3cd }, +/* 0xc3ce */ { true, 0xc3ce, 0xc3ce }, +/* 0xc3cf */ { true, 0xc3cf, 0xc3cf }, +/* 0xc3d0 */ { true, 0xc3d0, 0xc3d0 }, +/* 0xc3d1 */ { true, 0xc3d1, 0xc3d1 }, +/* 0xc3d2 */ { true, 0xc3d2, 0xc3d2 }, +/* 0xc3d3 */ { true, 0xc3d3, 0xc3d3 }, +/* 0xc3d4 */ { true, 0xc3d4, 0xc3d4 }, +/* 0xc3d5 */ { true, 0xc3d5, 0xc3d5 }, +/* 0xc3d6 */ { true, 0xc3d6, 0xc3d6 }, +/* 0xc3d7 */ { true, 0xc3d7, 0xc3d7 }, +/* 0xc3d8 */ { true, 0xc3d8, 0xc3d8 }, +/* 0xc3d9 */ { true, 0xc3d9, 0xc3d9 }, +/* 0xc3da */ { true, 0xc3da, 0xc3da }, +/* 0xc3db */ { true, 0xc3db, 0xc3db }, +/* 0xc3dc */ { true, 0xc3dc, 0xc3dc }, +/* 0xc3dd */ { true, 0xc3dd, 0xc3dd }, +/* 0xc3de */ { true, 0xc3de, 0xc3de }, +/* 0xc3df */ { true, 0xc3df, 0xc3df }, +/* 0xc3e0 */ { true, 0xc3e0, 0xc3e0 }, +/* 0xc3e1 */ { true, 0xc3e1, 0xc3e1 }, +/* 0xc3e2 */ { true, 0xc3e2, 0xc3e2 }, +/* 0xc3e3 */ { true, 0xc3e3, 0xc3e3 }, +/* 0xc3e4 */ { true, 0xc3e4, 0xc3e4 }, +/* 0xc3e5 */ { true, 0xc3e5, 0xc3e5 }, +/* 0xc3e6 */ { true, 0xc3e6, 0xc3e6 }, +/* 0xc3e7 */ { true, 0xc3e7, 0xc3e7 }, +/* 0xc3e8 */ { true, 0xc3e8, 0xc3e8 }, +/* 0xc3e9 */ { true, 0xc3e9, 0xc3e9 }, +/* 0xc3ea */ { true, 0xc3ea, 0xc3ea }, +/* 0xc3eb */ { true, 0xc3eb, 0xc3eb }, +/* 0xc3ec */ { true, 0xc3ec, 0xc3ec }, +/* 0xc3ed */ { true, 0xc3ed, 0xc3ed }, +/* 0xc3ee */ { true, 0xc3ee, 0xc3ee }, +/* 0xc3ef */ { true, 0xc3ef, 0xc3ef }, +/* 0xc3f0 */ { true, 0xc3f0, 0xc3f0 }, +/* 0xc3f1 */ { true, 0xc3f1, 0xc3f1 }, +/* 0xc3f2 */ { true, 0xc3f2, 0xc3f2 }, +/* 0xc3f3 */ { true, 0xc3f3, 0xc3f3 }, +/* 0xc3f4 */ { true, 0xc3f4, 0xc3f4 }, +/* 0xc3f5 */ { true, 0xc3f5, 0xc3f5 }, +/* 0xc3f6 */ { true, 0xc3f6, 0xc3f6 }, +/* 0xc3f7 */ { true, 0xc3f7, 0xc3f7 }, +/* 0xc3f8 */ { true, 0xc3f8, 0xc3f8 }, +/* 0xc3f9 */ { true, 0xc3f9, 0xc3f9 }, +/* 0xc3fa */ { true, 0xc3fa, 0xc3fa }, +/* 0xc3fb */ { true, 0xc3fb, 0xc3fb }, +/* 0xc3fc */ { true, 0xc3fc, 0xc3fc }, +/* 0xc3fd */ { true, 0xc3fd, 0xc3fd }, +/* 0xc3fe */ { true, 0xc3fe, 0xc3fe }, +/* 0xc3ff */ { true, 0xc3ff, 0xc3ff }, +/* 0xc400 */ { true, 0xc400, 0xc400 }, +/* 0xc401 */ { true, 0xc401, 0xc401 }, +/* 0xc402 */ { true, 0xc402, 0xc402 }, +/* 0xc403 */ { true, 0xc403, 0xc403 }, +/* 0xc404 */ { true, 0xc404, 0xc404 }, +/* 0xc405 */ { true, 0xc405, 0xc405 }, +/* 0xc406 */ { true, 0xc406, 0xc406 }, +/* 0xc407 */ { true, 0xc407, 0xc407 }, +/* 0xc408 */ { true, 0xc408, 0xc408 }, +/* 0xc409 */ { true, 0xc409, 0xc409 }, +/* 0xc40a */ { true, 0xc40a, 0xc40a }, +/* 0xc40b */ { true, 0xc40b, 0xc40b }, +/* 0xc40c */ { true, 0xc40c, 0xc40c }, +/* 0xc40d */ { true, 0xc40d, 0xc40d }, +/* 0xc40e */ { true, 0xc40e, 0xc40e }, +/* 0xc40f */ { true, 0xc40f, 0xc40f }, +/* 0xc410 */ { true, 0xc410, 0xc410 }, +/* 0xc411 */ { true, 0xc411, 0xc411 }, +/* 0xc412 */ { true, 0xc412, 0xc412 }, +/* 0xc413 */ { true, 0xc413, 0xc413 }, +/* 0xc414 */ { true, 0xc414, 0xc414 }, +/* 0xc415 */ { true, 0xc415, 0xc415 }, +/* 0xc416 */ { true, 0xc416, 0xc416 }, +/* 0xc417 */ { true, 0xc417, 0xc417 }, +/* 0xc418 */ { true, 0xc418, 0xc418 }, +/* 0xc419 */ { true, 0xc419, 0xc419 }, +/* 0xc41a */ { true, 0xc41a, 0xc41a }, +/* 0xc41b */ { true, 0xc41b, 0xc41b }, +/* 0xc41c */ { true, 0xc41c, 0xc41c }, +/* 0xc41d */ { true, 0xc41d, 0xc41d }, +/* 0xc41e */ { true, 0xc41e, 0xc41e }, +/* 0xc41f */ { true, 0xc41f, 0xc41f }, +/* 0xc420 */ { true, 0xc420, 0xc420 }, +/* 0xc421 */ { true, 0xc421, 0xc421 }, +/* 0xc422 */ { true, 0xc422, 0xc422 }, +/* 0xc423 */ { true, 0xc423, 0xc423 }, +/* 0xc424 */ { true, 0xc424, 0xc424 }, +/* 0xc425 */ { true, 0xc425, 0xc425 }, +/* 0xc426 */ { true, 0xc426, 0xc426 }, +/* 0xc427 */ { true, 0xc427, 0xc427 }, +/* 0xc428 */ { true, 0xc428, 0xc428 }, +/* 0xc429 */ { true, 0xc429, 0xc429 }, +/* 0xc42a */ { true, 0xc42a, 0xc42a }, +/* 0xc42b */ { true, 0xc42b, 0xc42b }, +/* 0xc42c */ { true, 0xc42c, 0xc42c }, +/* 0xc42d */ { true, 0xc42d, 0xc42d }, +/* 0xc42e */ { true, 0xc42e, 0xc42e }, +/* 0xc42f */ { true, 0xc42f, 0xc42f }, +/* 0xc430 */ { true, 0xc430, 0xc430 }, +/* 0xc431 */ { true, 0xc431, 0xc431 }, +/* 0xc432 */ { true, 0xc432, 0xc432 }, +/* 0xc433 */ { true, 0xc433, 0xc433 }, +/* 0xc434 */ { true, 0xc434, 0xc434 }, +/* 0xc435 */ { true, 0xc435, 0xc435 }, +/* 0xc436 */ { true, 0xc436, 0xc436 }, +/* 0xc437 */ { true, 0xc437, 0xc437 }, +/* 0xc438 */ { true, 0xc438, 0xc438 }, +/* 0xc439 */ { true, 0xc439, 0xc439 }, +/* 0xc43a */ { true, 0xc43a, 0xc43a }, +/* 0xc43b */ { true, 0xc43b, 0xc43b }, +/* 0xc43c */ { true, 0xc43c, 0xc43c }, +/* 0xc43d */ { true, 0xc43d, 0xc43d }, +/* 0xc43e */ { true, 0xc43e, 0xc43e }, +/* 0xc43f */ { true, 0xc43f, 0xc43f }, +/* 0xc440 */ { true, 0xc440, 0xc440 }, +/* 0xc441 */ { true, 0xc441, 0xc441 }, +/* 0xc442 */ { true, 0xc442, 0xc442 }, +/* 0xc443 */ { true, 0xc443, 0xc443 }, +/* 0xc444 */ { true, 0xc444, 0xc444 }, +/* 0xc445 */ { true, 0xc445, 0xc445 }, +/* 0xc446 */ { true, 0xc446, 0xc446 }, +/* 0xc447 */ { true, 0xc447, 0xc447 }, +/* 0xc448 */ { true, 0xc448, 0xc448 }, +/* 0xc449 */ { true, 0xc449, 0xc449 }, +/* 0xc44a */ { true, 0xc44a, 0xc44a }, +/* 0xc44b */ { true, 0xc44b, 0xc44b }, +/* 0xc44c */ { true, 0xc44c, 0xc44c }, +/* 0xc44d */ { true, 0xc44d, 0xc44d }, +/* 0xc44e */ { true, 0xc44e, 0xc44e }, +/* 0xc44f */ { true, 0xc44f, 0xc44f }, +/* 0xc450 */ { true, 0xc450, 0xc450 }, +/* 0xc451 */ { true, 0xc451, 0xc451 }, +/* 0xc452 */ { true, 0xc452, 0xc452 }, +/* 0xc453 */ { true, 0xc453, 0xc453 }, +/* 0xc454 */ { true, 0xc454, 0xc454 }, +/* 0xc455 */ { true, 0xc455, 0xc455 }, +/* 0xc456 */ { true, 0xc456, 0xc456 }, +/* 0xc457 */ { true, 0xc457, 0xc457 }, +/* 0xc458 */ { true, 0xc458, 0xc458 }, +/* 0xc459 */ { true, 0xc459, 0xc459 }, +/* 0xc45a */ { true, 0xc45a, 0xc45a }, +/* 0xc45b */ { true, 0xc45b, 0xc45b }, +/* 0xc45c */ { true, 0xc45c, 0xc45c }, +/* 0xc45d */ { true, 0xc45d, 0xc45d }, +/* 0xc45e */ { true, 0xc45e, 0xc45e }, +/* 0xc45f */ { true, 0xc45f, 0xc45f }, +/* 0xc460 */ { true, 0xc460, 0xc460 }, +/* 0xc461 */ { true, 0xc461, 0xc461 }, +/* 0xc462 */ { true, 0xc462, 0xc462 }, +/* 0xc463 */ { true, 0xc463, 0xc463 }, +/* 0xc464 */ { true, 0xc464, 0xc464 }, +/* 0xc465 */ { true, 0xc465, 0xc465 }, +/* 0xc466 */ { true, 0xc466, 0xc466 }, +/* 0xc467 */ { true, 0xc467, 0xc467 }, +/* 0xc468 */ { true, 0xc468, 0xc468 }, +/* 0xc469 */ { true, 0xc469, 0xc469 }, +/* 0xc46a */ { true, 0xc46a, 0xc46a }, +/* 0xc46b */ { true, 0xc46b, 0xc46b }, +/* 0xc46c */ { true, 0xc46c, 0xc46c }, +/* 0xc46d */ { true, 0xc46d, 0xc46d }, +/* 0xc46e */ { true, 0xc46e, 0xc46e }, +/* 0xc46f */ { true, 0xc46f, 0xc46f }, +/* 0xc470 */ { true, 0xc470, 0xc470 }, +/* 0xc471 */ { true, 0xc471, 0xc471 }, +/* 0xc472 */ { true, 0xc472, 0xc472 }, +/* 0xc473 */ { true, 0xc473, 0xc473 }, +/* 0xc474 */ { true, 0xc474, 0xc474 }, +/* 0xc475 */ { true, 0xc475, 0xc475 }, +/* 0xc476 */ { true, 0xc476, 0xc476 }, +/* 0xc477 */ { true, 0xc477, 0xc477 }, +/* 0xc478 */ { true, 0xc478, 0xc478 }, +/* 0xc479 */ { true, 0xc479, 0xc479 }, +/* 0xc47a */ { true, 0xc47a, 0xc47a }, +/* 0xc47b */ { true, 0xc47b, 0xc47b }, +/* 0xc47c */ { true, 0xc47c, 0xc47c }, +/* 0xc47d */ { true, 0xc47d, 0xc47d }, +/* 0xc47e */ { true, 0xc47e, 0xc47e }, +/* 0xc47f */ { true, 0xc47f, 0xc47f }, +/* 0xc480 */ { true, 0xc480, 0xc480 }, +/* 0xc481 */ { true, 0xc481, 0xc481 }, +/* 0xc482 */ { true, 0xc482, 0xc482 }, +/* 0xc483 */ { true, 0xc483, 0xc483 }, +/* 0xc484 */ { true, 0xc484, 0xc484 }, +/* 0xc485 */ { true, 0xc485, 0xc485 }, +/* 0xc486 */ { true, 0xc486, 0xc486 }, +/* 0xc487 */ { true, 0xc487, 0xc487 }, +/* 0xc488 */ { true, 0xc488, 0xc488 }, +/* 0xc489 */ { true, 0xc489, 0xc489 }, +/* 0xc48a */ { true, 0xc48a, 0xc48a }, +/* 0xc48b */ { true, 0xc48b, 0xc48b }, +/* 0xc48c */ { true, 0xc48c, 0xc48c }, +/* 0xc48d */ { true, 0xc48d, 0xc48d }, +/* 0xc48e */ { true, 0xc48e, 0xc48e }, +/* 0xc48f */ { true, 0xc48f, 0xc48f }, +/* 0xc490 */ { true, 0xc490, 0xc490 }, +/* 0xc491 */ { true, 0xc491, 0xc491 }, +/* 0xc492 */ { true, 0xc492, 0xc492 }, +/* 0xc493 */ { true, 0xc493, 0xc493 }, +/* 0xc494 */ { true, 0xc494, 0xc494 }, +/* 0xc495 */ { true, 0xc495, 0xc495 }, +/* 0xc496 */ { true, 0xc496, 0xc496 }, +/* 0xc497 */ { true, 0xc497, 0xc497 }, +/* 0xc498 */ { true, 0xc498, 0xc498 }, +/* 0xc499 */ { true, 0xc499, 0xc499 }, +/* 0xc49a */ { true, 0xc49a, 0xc49a }, +/* 0xc49b */ { true, 0xc49b, 0xc49b }, +/* 0xc49c */ { true, 0xc49c, 0xc49c }, +/* 0xc49d */ { true, 0xc49d, 0xc49d }, +/* 0xc49e */ { true, 0xc49e, 0xc49e }, +/* 0xc49f */ { true, 0xc49f, 0xc49f }, +/* 0xc4a0 */ { true, 0xc4a0, 0xc4a0 }, +/* 0xc4a1 */ { true, 0xc4a1, 0xc4a1 }, +/* 0xc4a2 */ { true, 0xc4a2, 0xc4a2 }, +/* 0xc4a3 */ { true, 0xc4a3, 0xc4a3 }, +/* 0xc4a4 */ { true, 0xc4a4, 0xc4a4 }, +/* 0xc4a5 */ { true, 0xc4a5, 0xc4a5 }, +/* 0xc4a6 */ { true, 0xc4a6, 0xc4a6 }, +/* 0xc4a7 */ { true, 0xc4a7, 0xc4a7 }, +/* 0xc4a8 */ { true, 0xc4a8, 0xc4a8 }, +/* 0xc4a9 */ { true, 0xc4a9, 0xc4a9 }, +/* 0xc4aa */ { true, 0xc4aa, 0xc4aa }, +/* 0xc4ab */ { true, 0xc4ab, 0xc4ab }, +/* 0xc4ac */ { true, 0xc4ac, 0xc4ac }, +/* 0xc4ad */ { true, 0xc4ad, 0xc4ad }, +/* 0xc4ae */ { true, 0xc4ae, 0xc4ae }, +/* 0xc4af */ { true, 0xc4af, 0xc4af }, +/* 0xc4b0 */ { true, 0xc4b0, 0xc4b0 }, +/* 0xc4b1 */ { true, 0xc4b1, 0xc4b1 }, +/* 0xc4b2 */ { true, 0xc4b2, 0xc4b2 }, +/* 0xc4b3 */ { true, 0xc4b3, 0xc4b3 }, +/* 0xc4b4 */ { true, 0xc4b4, 0xc4b4 }, +/* 0xc4b5 */ { true, 0xc4b5, 0xc4b5 }, +/* 0xc4b6 */ { true, 0xc4b6, 0xc4b6 }, +/* 0xc4b7 */ { true, 0xc4b7, 0xc4b7 }, +/* 0xc4b8 */ { true, 0xc4b8, 0xc4b8 }, +/* 0xc4b9 */ { true, 0xc4b9, 0xc4b9 }, +/* 0xc4ba */ { true, 0xc4ba, 0xc4ba }, +/* 0xc4bb */ { true, 0xc4bb, 0xc4bb }, +/* 0xc4bc */ { true, 0xc4bc, 0xc4bc }, +/* 0xc4bd */ { true, 0xc4bd, 0xc4bd }, +/* 0xc4be */ { true, 0xc4be, 0xc4be }, +/* 0xc4bf */ { true, 0xc4bf, 0xc4bf }, +/* 0xc4c0 */ { true, 0xc4c0, 0xc4c0 }, +/* 0xc4c1 */ { true, 0xc4c1, 0xc4c1 }, +/* 0xc4c2 */ { true, 0xc4c2, 0xc4c2 }, +/* 0xc4c3 */ { true, 0xc4c3, 0xc4c3 }, +/* 0xc4c4 */ { true, 0xc4c4, 0xc4c4 }, +/* 0xc4c5 */ { true, 0xc4c5, 0xc4c5 }, +/* 0xc4c6 */ { true, 0xc4c6, 0xc4c6 }, +/* 0xc4c7 */ { true, 0xc4c7, 0xc4c7 }, +/* 0xc4c8 */ { true, 0xc4c8, 0xc4c8 }, +/* 0xc4c9 */ { true, 0xc4c9, 0xc4c9 }, +/* 0xc4ca */ { true, 0xc4ca, 0xc4ca }, +/* 0xc4cb */ { true, 0xc4cb, 0xc4cb }, +/* 0xc4cc */ { true, 0xc4cc, 0xc4cc }, +/* 0xc4cd */ { true, 0xc4cd, 0xc4cd }, +/* 0xc4ce */ { true, 0xc4ce, 0xc4ce }, +/* 0xc4cf */ { true, 0xc4cf, 0xc4cf }, +/* 0xc4d0 */ { true, 0xc4d0, 0xc4d0 }, +/* 0xc4d1 */ { true, 0xc4d1, 0xc4d1 }, +/* 0xc4d2 */ { true, 0xc4d2, 0xc4d2 }, +/* 0xc4d3 */ { true, 0xc4d3, 0xc4d3 }, +/* 0xc4d4 */ { true, 0xc4d4, 0xc4d4 }, +/* 0xc4d5 */ { true, 0xc4d5, 0xc4d5 }, +/* 0xc4d6 */ { true, 0xc4d6, 0xc4d6 }, +/* 0xc4d7 */ { true, 0xc4d7, 0xc4d7 }, +/* 0xc4d8 */ { true, 0xc4d8, 0xc4d8 }, +/* 0xc4d9 */ { true, 0xc4d9, 0xc4d9 }, +/* 0xc4da */ { true, 0xc4da, 0xc4da }, +/* 0xc4db */ { true, 0xc4db, 0xc4db }, +/* 0xc4dc */ { true, 0xc4dc, 0xc4dc }, +/* 0xc4dd */ { true, 0xc4dd, 0xc4dd }, +/* 0xc4de */ { true, 0xc4de, 0xc4de }, +/* 0xc4df */ { true, 0xc4df, 0xc4df }, +/* 0xc4e0 */ { true, 0xc4e0, 0xc4e0 }, +/* 0xc4e1 */ { true, 0xc4e1, 0xc4e1 }, +/* 0xc4e2 */ { true, 0xc4e2, 0xc4e2 }, +/* 0xc4e3 */ { true, 0xc4e3, 0xc4e3 }, +/* 0xc4e4 */ { true, 0xc4e4, 0xc4e4 }, +/* 0xc4e5 */ { true, 0xc4e5, 0xc4e5 }, +/* 0xc4e6 */ { true, 0xc4e6, 0xc4e6 }, +/* 0xc4e7 */ { true, 0xc4e7, 0xc4e7 }, +/* 0xc4e8 */ { true, 0xc4e8, 0xc4e8 }, +/* 0xc4e9 */ { true, 0xc4e9, 0xc4e9 }, +/* 0xc4ea */ { true, 0xc4ea, 0xc4ea }, +/* 0xc4eb */ { true, 0xc4eb, 0xc4eb }, +/* 0xc4ec */ { true, 0xc4ec, 0xc4ec }, +/* 0xc4ed */ { true, 0xc4ed, 0xc4ed }, +/* 0xc4ee */ { true, 0xc4ee, 0xc4ee }, +/* 0xc4ef */ { true, 0xc4ef, 0xc4ef }, +/* 0xc4f0 */ { true, 0xc4f0, 0xc4f0 }, +/* 0xc4f1 */ { true, 0xc4f1, 0xc4f1 }, +/* 0xc4f2 */ { true, 0xc4f2, 0xc4f2 }, +/* 0xc4f3 */ { true, 0xc4f3, 0xc4f3 }, +/* 0xc4f4 */ { true, 0xc4f4, 0xc4f4 }, +/* 0xc4f5 */ { true, 0xc4f5, 0xc4f5 }, +/* 0xc4f6 */ { true, 0xc4f6, 0xc4f6 }, +/* 0xc4f7 */ { true, 0xc4f7, 0xc4f7 }, +/* 0xc4f8 */ { true, 0xc4f8, 0xc4f8 }, +/* 0xc4f9 */ { true, 0xc4f9, 0xc4f9 }, +/* 0xc4fa */ { true, 0xc4fa, 0xc4fa }, +/* 0xc4fb */ { true, 0xc4fb, 0xc4fb }, +/* 0xc4fc */ { true, 0xc4fc, 0xc4fc }, +/* 0xc4fd */ { true, 0xc4fd, 0xc4fd }, +/* 0xc4fe */ { true, 0xc4fe, 0xc4fe }, +/* 0xc4ff */ { true, 0xc4ff, 0xc4ff }, +/* 0xc500 */ { true, 0xc500, 0xc500 }, +/* 0xc501 */ { true, 0xc501, 0xc501 }, +/* 0xc502 */ { true, 0xc502, 0xc502 }, +/* 0xc503 */ { true, 0xc503, 0xc503 }, +/* 0xc504 */ { true, 0xc504, 0xc504 }, +/* 0xc505 */ { true, 0xc505, 0xc505 }, +/* 0xc506 */ { true, 0xc506, 0xc506 }, +/* 0xc507 */ { true, 0xc507, 0xc507 }, +/* 0xc508 */ { true, 0xc508, 0xc508 }, +/* 0xc509 */ { true, 0xc509, 0xc509 }, +/* 0xc50a */ { true, 0xc50a, 0xc50a }, +/* 0xc50b */ { true, 0xc50b, 0xc50b }, +/* 0xc50c */ { true, 0xc50c, 0xc50c }, +/* 0xc50d */ { true, 0xc50d, 0xc50d }, +/* 0xc50e */ { true, 0xc50e, 0xc50e }, +/* 0xc50f */ { true, 0xc50f, 0xc50f }, +/* 0xc510 */ { true, 0xc510, 0xc510 }, +/* 0xc511 */ { true, 0xc511, 0xc511 }, +/* 0xc512 */ { true, 0xc512, 0xc512 }, +/* 0xc513 */ { true, 0xc513, 0xc513 }, +/* 0xc514 */ { true, 0xc514, 0xc514 }, +/* 0xc515 */ { true, 0xc515, 0xc515 }, +/* 0xc516 */ { true, 0xc516, 0xc516 }, +/* 0xc517 */ { true, 0xc517, 0xc517 }, +/* 0xc518 */ { true, 0xc518, 0xc518 }, +/* 0xc519 */ { true, 0xc519, 0xc519 }, +/* 0xc51a */ { true, 0xc51a, 0xc51a }, +/* 0xc51b */ { true, 0xc51b, 0xc51b }, +/* 0xc51c */ { true, 0xc51c, 0xc51c }, +/* 0xc51d */ { true, 0xc51d, 0xc51d }, +/* 0xc51e */ { true, 0xc51e, 0xc51e }, +/* 0xc51f */ { true, 0xc51f, 0xc51f }, +/* 0xc520 */ { true, 0xc520, 0xc520 }, +/* 0xc521 */ { true, 0xc521, 0xc521 }, +/* 0xc522 */ { true, 0xc522, 0xc522 }, +/* 0xc523 */ { true, 0xc523, 0xc523 }, +/* 0xc524 */ { true, 0xc524, 0xc524 }, +/* 0xc525 */ { true, 0xc525, 0xc525 }, +/* 0xc526 */ { true, 0xc526, 0xc526 }, +/* 0xc527 */ { true, 0xc527, 0xc527 }, +/* 0xc528 */ { true, 0xc528, 0xc528 }, +/* 0xc529 */ { true, 0xc529, 0xc529 }, +/* 0xc52a */ { true, 0xc52a, 0xc52a }, +/* 0xc52b */ { true, 0xc52b, 0xc52b }, +/* 0xc52c */ { true, 0xc52c, 0xc52c }, +/* 0xc52d */ { true, 0xc52d, 0xc52d }, +/* 0xc52e */ { true, 0xc52e, 0xc52e }, +/* 0xc52f */ { true, 0xc52f, 0xc52f }, +/* 0xc530 */ { true, 0xc530, 0xc530 }, +/* 0xc531 */ { true, 0xc531, 0xc531 }, +/* 0xc532 */ { true, 0xc532, 0xc532 }, +/* 0xc533 */ { true, 0xc533, 0xc533 }, +/* 0xc534 */ { true, 0xc534, 0xc534 }, +/* 0xc535 */ { true, 0xc535, 0xc535 }, +/* 0xc536 */ { true, 0xc536, 0xc536 }, +/* 0xc537 */ { true, 0xc537, 0xc537 }, +/* 0xc538 */ { true, 0xc538, 0xc538 }, +/* 0xc539 */ { true, 0xc539, 0xc539 }, +/* 0xc53a */ { true, 0xc53a, 0xc53a }, +/* 0xc53b */ { true, 0xc53b, 0xc53b }, +/* 0xc53c */ { true, 0xc53c, 0xc53c }, +/* 0xc53d */ { true, 0xc53d, 0xc53d }, +/* 0xc53e */ { true, 0xc53e, 0xc53e }, +/* 0xc53f */ { true, 0xc53f, 0xc53f }, +/* 0xc540 */ { true, 0xc540, 0xc540 }, +/* 0xc541 */ { true, 0xc541, 0xc541 }, +/* 0xc542 */ { true, 0xc542, 0xc542 }, +/* 0xc543 */ { true, 0xc543, 0xc543 }, +/* 0xc544 */ { true, 0xc544, 0xc544 }, +/* 0xc545 */ { true, 0xc545, 0xc545 }, +/* 0xc546 */ { true, 0xc546, 0xc546 }, +/* 0xc547 */ { true, 0xc547, 0xc547 }, +/* 0xc548 */ { true, 0xc548, 0xc548 }, +/* 0xc549 */ { true, 0xc549, 0xc549 }, +/* 0xc54a */ { true, 0xc54a, 0xc54a }, +/* 0xc54b */ { true, 0xc54b, 0xc54b }, +/* 0xc54c */ { true, 0xc54c, 0xc54c }, +/* 0xc54d */ { true, 0xc54d, 0xc54d }, +/* 0xc54e */ { true, 0xc54e, 0xc54e }, +/* 0xc54f */ { true, 0xc54f, 0xc54f }, +/* 0xc550 */ { true, 0xc550, 0xc550 }, +/* 0xc551 */ { true, 0xc551, 0xc551 }, +/* 0xc552 */ { true, 0xc552, 0xc552 }, +/* 0xc553 */ { true, 0xc553, 0xc553 }, +/* 0xc554 */ { true, 0xc554, 0xc554 }, +/* 0xc555 */ { true, 0xc555, 0xc555 }, +/* 0xc556 */ { true, 0xc556, 0xc556 }, +/* 0xc557 */ { true, 0xc557, 0xc557 }, +/* 0xc558 */ { true, 0xc558, 0xc558 }, +/* 0xc559 */ { true, 0xc559, 0xc559 }, +/* 0xc55a */ { true, 0xc55a, 0xc55a }, +/* 0xc55b */ { true, 0xc55b, 0xc55b }, +/* 0xc55c */ { true, 0xc55c, 0xc55c }, +/* 0xc55d */ { true, 0xc55d, 0xc55d }, +/* 0xc55e */ { true, 0xc55e, 0xc55e }, +/* 0xc55f */ { true, 0xc55f, 0xc55f }, +/* 0xc560 */ { true, 0xc560, 0xc560 }, +/* 0xc561 */ { true, 0xc561, 0xc561 }, +/* 0xc562 */ { true, 0xc562, 0xc562 }, +/* 0xc563 */ { true, 0xc563, 0xc563 }, +/* 0xc564 */ { true, 0xc564, 0xc564 }, +/* 0xc565 */ { true, 0xc565, 0xc565 }, +/* 0xc566 */ { true, 0xc566, 0xc566 }, +/* 0xc567 */ { true, 0xc567, 0xc567 }, +/* 0xc568 */ { true, 0xc568, 0xc568 }, +/* 0xc569 */ { true, 0xc569, 0xc569 }, +/* 0xc56a */ { true, 0xc56a, 0xc56a }, +/* 0xc56b */ { true, 0xc56b, 0xc56b }, +/* 0xc56c */ { true, 0xc56c, 0xc56c }, +/* 0xc56d */ { true, 0xc56d, 0xc56d }, +/* 0xc56e */ { true, 0xc56e, 0xc56e }, +/* 0xc56f */ { true, 0xc56f, 0xc56f }, +/* 0xc570 */ { true, 0xc570, 0xc570 }, +/* 0xc571 */ { true, 0xc571, 0xc571 }, +/* 0xc572 */ { true, 0xc572, 0xc572 }, +/* 0xc573 */ { true, 0xc573, 0xc573 }, +/* 0xc574 */ { true, 0xc574, 0xc574 }, +/* 0xc575 */ { true, 0xc575, 0xc575 }, +/* 0xc576 */ { true, 0xc576, 0xc576 }, +/* 0xc577 */ { true, 0xc577, 0xc577 }, +/* 0xc578 */ { true, 0xc578, 0xc578 }, +/* 0xc579 */ { true, 0xc579, 0xc579 }, +/* 0xc57a */ { true, 0xc57a, 0xc57a }, +/* 0xc57b */ { true, 0xc57b, 0xc57b }, +/* 0xc57c */ { true, 0xc57c, 0xc57c }, +/* 0xc57d */ { true, 0xc57d, 0xc57d }, +/* 0xc57e */ { true, 0xc57e, 0xc57e }, +/* 0xc57f */ { true, 0xc57f, 0xc57f }, +/* 0xc580 */ { true, 0xc580, 0xc580 }, +/* 0xc581 */ { true, 0xc581, 0xc581 }, +/* 0xc582 */ { true, 0xc582, 0xc582 }, +/* 0xc583 */ { true, 0xc583, 0xc583 }, +/* 0xc584 */ { true, 0xc584, 0xc584 }, +/* 0xc585 */ { true, 0xc585, 0xc585 }, +/* 0xc586 */ { true, 0xc586, 0xc586 }, +/* 0xc587 */ { true, 0xc587, 0xc587 }, +/* 0xc588 */ { true, 0xc588, 0xc588 }, +/* 0xc589 */ { true, 0xc589, 0xc589 }, +/* 0xc58a */ { true, 0xc58a, 0xc58a }, +/* 0xc58b */ { true, 0xc58b, 0xc58b }, +/* 0xc58c */ { true, 0xc58c, 0xc58c }, +/* 0xc58d */ { true, 0xc58d, 0xc58d }, +/* 0xc58e */ { true, 0xc58e, 0xc58e }, +/* 0xc58f */ { true, 0xc58f, 0xc58f }, +/* 0xc590 */ { true, 0xc590, 0xc590 }, +/* 0xc591 */ { true, 0xc591, 0xc591 }, +/* 0xc592 */ { true, 0xc592, 0xc592 }, +/* 0xc593 */ { true, 0xc593, 0xc593 }, +/* 0xc594 */ { true, 0xc594, 0xc594 }, +/* 0xc595 */ { true, 0xc595, 0xc595 }, +/* 0xc596 */ { true, 0xc596, 0xc596 }, +/* 0xc597 */ { true, 0xc597, 0xc597 }, +/* 0xc598 */ { true, 0xc598, 0xc598 }, +/* 0xc599 */ { true, 0xc599, 0xc599 }, +/* 0xc59a */ { true, 0xc59a, 0xc59a }, +/* 0xc59b */ { true, 0xc59b, 0xc59b }, +/* 0xc59c */ { true, 0xc59c, 0xc59c }, +/* 0xc59d */ { true, 0xc59d, 0xc59d }, +/* 0xc59e */ { true, 0xc59e, 0xc59e }, +/* 0xc59f */ { true, 0xc59f, 0xc59f }, +/* 0xc5a0 */ { true, 0xc5a0, 0xc5a0 }, +/* 0xc5a1 */ { true, 0xc5a1, 0xc5a1 }, +/* 0xc5a2 */ { true, 0xc5a2, 0xc5a2 }, +/* 0xc5a3 */ { true, 0xc5a3, 0xc5a3 }, +/* 0xc5a4 */ { true, 0xc5a4, 0xc5a4 }, +/* 0xc5a5 */ { true, 0xc5a5, 0xc5a5 }, +/* 0xc5a6 */ { true, 0xc5a6, 0xc5a6 }, +/* 0xc5a7 */ { true, 0xc5a7, 0xc5a7 }, +/* 0xc5a8 */ { true, 0xc5a8, 0xc5a8 }, +/* 0xc5a9 */ { true, 0xc5a9, 0xc5a9 }, +/* 0xc5aa */ { true, 0xc5aa, 0xc5aa }, +/* 0xc5ab */ { true, 0xc5ab, 0xc5ab }, +/* 0xc5ac */ { true, 0xc5ac, 0xc5ac }, +/* 0xc5ad */ { true, 0xc5ad, 0xc5ad }, +/* 0xc5ae */ { true, 0xc5ae, 0xc5ae }, +/* 0xc5af */ { true, 0xc5af, 0xc5af }, +/* 0xc5b0 */ { true, 0xc5b0, 0xc5b0 }, +/* 0xc5b1 */ { true, 0xc5b1, 0xc5b1 }, +/* 0xc5b2 */ { true, 0xc5b2, 0xc5b2 }, +/* 0xc5b3 */ { true, 0xc5b3, 0xc5b3 }, +/* 0xc5b4 */ { true, 0xc5b4, 0xc5b4 }, +/* 0xc5b5 */ { true, 0xc5b5, 0xc5b5 }, +/* 0xc5b6 */ { true, 0xc5b6, 0xc5b6 }, +/* 0xc5b7 */ { true, 0xc5b7, 0xc5b7 }, +/* 0xc5b8 */ { true, 0xc5b8, 0xc5b8 }, +/* 0xc5b9 */ { true, 0xc5b9, 0xc5b9 }, +/* 0xc5ba */ { true, 0xc5ba, 0xc5ba }, +/* 0xc5bb */ { true, 0xc5bb, 0xc5bb }, +/* 0xc5bc */ { true, 0xc5bc, 0xc5bc }, +/* 0xc5bd */ { true, 0xc5bd, 0xc5bd }, +/* 0xc5be */ { true, 0xc5be, 0xc5be }, +/* 0xc5bf */ { true, 0xc5bf, 0xc5bf }, +/* 0xc5c0 */ { true, 0xc5c0, 0xc5c0 }, +/* 0xc5c1 */ { true, 0xc5c1, 0xc5c1 }, +/* 0xc5c2 */ { true, 0xc5c2, 0xc5c2 }, +/* 0xc5c3 */ { true, 0xc5c3, 0xc5c3 }, +/* 0xc5c4 */ { true, 0xc5c4, 0xc5c4 }, +/* 0xc5c5 */ { true, 0xc5c5, 0xc5c5 }, +/* 0xc5c6 */ { true, 0xc5c6, 0xc5c6 }, +/* 0xc5c7 */ { true, 0xc5c7, 0xc5c7 }, +/* 0xc5c8 */ { true, 0xc5c8, 0xc5c8 }, +/* 0xc5c9 */ { true, 0xc5c9, 0xc5c9 }, +/* 0xc5ca */ { true, 0xc5ca, 0xc5ca }, +/* 0xc5cb */ { true, 0xc5cb, 0xc5cb }, +/* 0xc5cc */ { true, 0xc5cc, 0xc5cc }, +/* 0xc5cd */ { true, 0xc5cd, 0xc5cd }, +/* 0xc5ce */ { true, 0xc5ce, 0xc5ce }, +/* 0xc5cf */ { true, 0xc5cf, 0xc5cf }, +/* 0xc5d0 */ { true, 0xc5d0, 0xc5d0 }, +/* 0xc5d1 */ { true, 0xc5d1, 0xc5d1 }, +/* 0xc5d2 */ { true, 0xc5d2, 0xc5d2 }, +/* 0xc5d3 */ { true, 0xc5d3, 0xc5d3 }, +/* 0xc5d4 */ { true, 0xc5d4, 0xc5d4 }, +/* 0xc5d5 */ { true, 0xc5d5, 0xc5d5 }, +/* 0xc5d6 */ { true, 0xc5d6, 0xc5d6 }, +/* 0xc5d7 */ { true, 0xc5d7, 0xc5d7 }, +/* 0xc5d8 */ { true, 0xc5d8, 0xc5d8 }, +/* 0xc5d9 */ { true, 0xc5d9, 0xc5d9 }, +/* 0xc5da */ { true, 0xc5da, 0xc5da }, +/* 0xc5db */ { true, 0xc5db, 0xc5db }, +/* 0xc5dc */ { true, 0xc5dc, 0xc5dc }, +/* 0xc5dd */ { true, 0xc5dd, 0xc5dd }, +/* 0xc5de */ { true, 0xc5de, 0xc5de }, +/* 0xc5df */ { true, 0xc5df, 0xc5df }, +/* 0xc5e0 */ { true, 0xc5e0, 0xc5e0 }, +/* 0xc5e1 */ { true, 0xc5e1, 0xc5e1 }, +/* 0xc5e2 */ { true, 0xc5e2, 0xc5e2 }, +/* 0xc5e3 */ { true, 0xc5e3, 0xc5e3 }, +/* 0xc5e4 */ { true, 0xc5e4, 0xc5e4 }, +/* 0xc5e5 */ { true, 0xc5e5, 0xc5e5 }, +/* 0xc5e6 */ { true, 0xc5e6, 0xc5e6 }, +/* 0xc5e7 */ { true, 0xc5e7, 0xc5e7 }, +/* 0xc5e8 */ { true, 0xc5e8, 0xc5e8 }, +/* 0xc5e9 */ { true, 0xc5e9, 0xc5e9 }, +/* 0xc5ea */ { true, 0xc5ea, 0xc5ea }, +/* 0xc5eb */ { true, 0xc5eb, 0xc5eb }, +/* 0xc5ec */ { true, 0xc5ec, 0xc5ec }, +/* 0xc5ed */ { true, 0xc5ed, 0xc5ed }, +/* 0xc5ee */ { true, 0xc5ee, 0xc5ee }, +/* 0xc5ef */ { true, 0xc5ef, 0xc5ef }, +/* 0xc5f0 */ { true, 0xc5f0, 0xc5f0 }, +/* 0xc5f1 */ { true, 0xc5f1, 0xc5f1 }, +/* 0xc5f2 */ { true, 0xc5f2, 0xc5f2 }, +/* 0xc5f3 */ { true, 0xc5f3, 0xc5f3 }, +/* 0xc5f4 */ { true, 0xc5f4, 0xc5f4 }, +/* 0xc5f5 */ { true, 0xc5f5, 0xc5f5 }, +/* 0xc5f6 */ { true, 0xc5f6, 0xc5f6 }, +/* 0xc5f7 */ { true, 0xc5f7, 0xc5f7 }, +/* 0xc5f8 */ { true, 0xc5f8, 0xc5f8 }, +/* 0xc5f9 */ { true, 0xc5f9, 0xc5f9 }, +/* 0xc5fa */ { true, 0xc5fa, 0xc5fa }, +/* 0xc5fb */ { true, 0xc5fb, 0xc5fb }, +/* 0xc5fc */ { true, 0xc5fc, 0xc5fc }, +/* 0xc5fd */ { true, 0xc5fd, 0xc5fd }, +/* 0xc5fe */ { true, 0xc5fe, 0xc5fe }, +/* 0xc5ff */ { true, 0xc5ff, 0xc5ff }, +/* 0xc600 */ { true, 0xc600, 0xc600 }, +/* 0xc601 */ { true, 0xc601, 0xc601 }, +/* 0xc602 */ { true, 0xc602, 0xc602 }, +/* 0xc603 */ { true, 0xc603, 0xc603 }, +/* 0xc604 */ { true, 0xc604, 0xc604 }, +/* 0xc605 */ { true, 0xc605, 0xc605 }, +/* 0xc606 */ { true, 0xc606, 0xc606 }, +/* 0xc607 */ { true, 0xc607, 0xc607 }, +/* 0xc608 */ { true, 0xc608, 0xc608 }, +/* 0xc609 */ { true, 0xc609, 0xc609 }, +/* 0xc60a */ { true, 0xc60a, 0xc60a }, +/* 0xc60b */ { true, 0xc60b, 0xc60b }, +/* 0xc60c */ { true, 0xc60c, 0xc60c }, +/* 0xc60d */ { true, 0xc60d, 0xc60d }, +/* 0xc60e */ { true, 0xc60e, 0xc60e }, +/* 0xc60f */ { true, 0xc60f, 0xc60f }, +/* 0xc610 */ { true, 0xc610, 0xc610 }, +/* 0xc611 */ { true, 0xc611, 0xc611 }, +/* 0xc612 */ { true, 0xc612, 0xc612 }, +/* 0xc613 */ { true, 0xc613, 0xc613 }, +/* 0xc614 */ { true, 0xc614, 0xc614 }, +/* 0xc615 */ { true, 0xc615, 0xc615 }, +/* 0xc616 */ { true, 0xc616, 0xc616 }, +/* 0xc617 */ { true, 0xc617, 0xc617 }, +/* 0xc618 */ { true, 0xc618, 0xc618 }, +/* 0xc619 */ { true, 0xc619, 0xc619 }, +/* 0xc61a */ { true, 0xc61a, 0xc61a }, +/* 0xc61b */ { true, 0xc61b, 0xc61b }, +/* 0xc61c */ { true, 0xc61c, 0xc61c }, +/* 0xc61d */ { true, 0xc61d, 0xc61d }, +/* 0xc61e */ { true, 0xc61e, 0xc61e }, +/* 0xc61f */ { true, 0xc61f, 0xc61f }, +/* 0xc620 */ { true, 0xc620, 0xc620 }, +/* 0xc621 */ { true, 0xc621, 0xc621 }, +/* 0xc622 */ { true, 0xc622, 0xc622 }, +/* 0xc623 */ { true, 0xc623, 0xc623 }, +/* 0xc624 */ { true, 0xc624, 0xc624 }, +/* 0xc625 */ { true, 0xc625, 0xc625 }, +/* 0xc626 */ { true, 0xc626, 0xc626 }, +/* 0xc627 */ { true, 0xc627, 0xc627 }, +/* 0xc628 */ { true, 0xc628, 0xc628 }, +/* 0xc629 */ { true, 0xc629, 0xc629 }, +/* 0xc62a */ { true, 0xc62a, 0xc62a }, +/* 0xc62b */ { true, 0xc62b, 0xc62b }, +/* 0xc62c */ { true, 0xc62c, 0xc62c }, +/* 0xc62d */ { true, 0xc62d, 0xc62d }, +/* 0xc62e */ { true, 0xc62e, 0xc62e }, +/* 0xc62f */ { true, 0xc62f, 0xc62f }, +/* 0xc630 */ { true, 0xc630, 0xc630 }, +/* 0xc631 */ { true, 0xc631, 0xc631 }, +/* 0xc632 */ { true, 0xc632, 0xc632 }, +/* 0xc633 */ { true, 0xc633, 0xc633 }, +/* 0xc634 */ { true, 0xc634, 0xc634 }, +/* 0xc635 */ { true, 0xc635, 0xc635 }, +/* 0xc636 */ { true, 0xc636, 0xc636 }, +/* 0xc637 */ { true, 0xc637, 0xc637 }, +/* 0xc638 */ { true, 0xc638, 0xc638 }, +/* 0xc639 */ { true, 0xc639, 0xc639 }, +/* 0xc63a */ { true, 0xc63a, 0xc63a }, +/* 0xc63b */ { true, 0xc63b, 0xc63b }, +/* 0xc63c */ { true, 0xc63c, 0xc63c }, +/* 0xc63d */ { true, 0xc63d, 0xc63d }, +/* 0xc63e */ { true, 0xc63e, 0xc63e }, +/* 0xc63f */ { true, 0xc63f, 0xc63f }, +/* 0xc640 */ { true, 0xc640, 0xc640 }, +/* 0xc641 */ { true, 0xc641, 0xc641 }, +/* 0xc642 */ { true, 0xc642, 0xc642 }, +/* 0xc643 */ { true, 0xc643, 0xc643 }, +/* 0xc644 */ { true, 0xc644, 0xc644 }, +/* 0xc645 */ { true, 0xc645, 0xc645 }, +/* 0xc646 */ { true, 0xc646, 0xc646 }, +/* 0xc647 */ { true, 0xc647, 0xc647 }, +/* 0xc648 */ { true, 0xc648, 0xc648 }, +/* 0xc649 */ { true, 0xc649, 0xc649 }, +/* 0xc64a */ { true, 0xc64a, 0xc64a }, +/* 0xc64b */ { true, 0xc64b, 0xc64b }, +/* 0xc64c */ { true, 0xc64c, 0xc64c }, +/* 0xc64d */ { true, 0xc64d, 0xc64d }, +/* 0xc64e */ { true, 0xc64e, 0xc64e }, +/* 0xc64f */ { true, 0xc64f, 0xc64f }, +/* 0xc650 */ { true, 0xc650, 0xc650 }, +/* 0xc651 */ { true, 0xc651, 0xc651 }, +/* 0xc652 */ { true, 0xc652, 0xc652 }, +/* 0xc653 */ { true, 0xc653, 0xc653 }, +/* 0xc654 */ { true, 0xc654, 0xc654 }, +/* 0xc655 */ { true, 0xc655, 0xc655 }, +/* 0xc656 */ { true, 0xc656, 0xc656 }, +/* 0xc657 */ { true, 0xc657, 0xc657 }, +/* 0xc658 */ { true, 0xc658, 0xc658 }, +/* 0xc659 */ { true, 0xc659, 0xc659 }, +/* 0xc65a */ { true, 0xc65a, 0xc65a }, +/* 0xc65b */ { true, 0xc65b, 0xc65b }, +/* 0xc65c */ { true, 0xc65c, 0xc65c }, +/* 0xc65d */ { true, 0xc65d, 0xc65d }, +/* 0xc65e */ { true, 0xc65e, 0xc65e }, +/* 0xc65f */ { true, 0xc65f, 0xc65f }, +/* 0xc660 */ { true, 0xc660, 0xc660 }, +/* 0xc661 */ { true, 0xc661, 0xc661 }, +/* 0xc662 */ { true, 0xc662, 0xc662 }, +/* 0xc663 */ { true, 0xc663, 0xc663 }, +/* 0xc664 */ { true, 0xc664, 0xc664 }, +/* 0xc665 */ { true, 0xc665, 0xc665 }, +/* 0xc666 */ { true, 0xc666, 0xc666 }, +/* 0xc667 */ { true, 0xc667, 0xc667 }, +/* 0xc668 */ { true, 0xc668, 0xc668 }, +/* 0xc669 */ { true, 0xc669, 0xc669 }, +/* 0xc66a */ { true, 0xc66a, 0xc66a }, +/* 0xc66b */ { true, 0xc66b, 0xc66b }, +/* 0xc66c */ { true, 0xc66c, 0xc66c }, +/* 0xc66d */ { true, 0xc66d, 0xc66d }, +/* 0xc66e */ { true, 0xc66e, 0xc66e }, +/* 0xc66f */ { true, 0xc66f, 0xc66f }, +/* 0xc670 */ { true, 0xc670, 0xc670 }, +/* 0xc671 */ { true, 0xc671, 0xc671 }, +/* 0xc672 */ { true, 0xc672, 0xc672 }, +/* 0xc673 */ { true, 0xc673, 0xc673 }, +/* 0xc674 */ { true, 0xc674, 0xc674 }, +/* 0xc675 */ { true, 0xc675, 0xc675 }, +/* 0xc676 */ { true, 0xc676, 0xc676 }, +/* 0xc677 */ { true, 0xc677, 0xc677 }, +/* 0xc678 */ { true, 0xc678, 0xc678 }, +/* 0xc679 */ { true, 0xc679, 0xc679 }, +/* 0xc67a */ { true, 0xc67a, 0xc67a }, +/* 0xc67b */ { true, 0xc67b, 0xc67b }, +/* 0xc67c */ { true, 0xc67c, 0xc67c }, +/* 0xc67d */ { true, 0xc67d, 0xc67d }, +/* 0xc67e */ { true, 0xc67e, 0xc67e }, +/* 0xc67f */ { true, 0xc67f, 0xc67f }, +/* 0xc680 */ { true, 0xc680, 0xc680 }, +/* 0xc681 */ { true, 0xc681, 0xc681 }, +/* 0xc682 */ { true, 0xc682, 0xc682 }, +/* 0xc683 */ { true, 0xc683, 0xc683 }, +/* 0xc684 */ { true, 0xc684, 0xc684 }, +/* 0xc685 */ { true, 0xc685, 0xc685 }, +/* 0xc686 */ { true, 0xc686, 0xc686 }, +/* 0xc687 */ { true, 0xc687, 0xc687 }, +/* 0xc688 */ { true, 0xc688, 0xc688 }, +/* 0xc689 */ { true, 0xc689, 0xc689 }, +/* 0xc68a */ { true, 0xc68a, 0xc68a }, +/* 0xc68b */ { true, 0xc68b, 0xc68b }, +/* 0xc68c */ { true, 0xc68c, 0xc68c }, +/* 0xc68d */ { true, 0xc68d, 0xc68d }, +/* 0xc68e */ { true, 0xc68e, 0xc68e }, +/* 0xc68f */ { true, 0xc68f, 0xc68f }, +/* 0xc690 */ { true, 0xc690, 0xc690 }, +/* 0xc691 */ { true, 0xc691, 0xc691 }, +/* 0xc692 */ { true, 0xc692, 0xc692 }, +/* 0xc693 */ { true, 0xc693, 0xc693 }, +/* 0xc694 */ { true, 0xc694, 0xc694 }, +/* 0xc695 */ { true, 0xc695, 0xc695 }, +/* 0xc696 */ { true, 0xc696, 0xc696 }, +/* 0xc697 */ { true, 0xc697, 0xc697 }, +/* 0xc698 */ { true, 0xc698, 0xc698 }, +/* 0xc699 */ { true, 0xc699, 0xc699 }, +/* 0xc69a */ { true, 0xc69a, 0xc69a }, +/* 0xc69b */ { true, 0xc69b, 0xc69b }, +/* 0xc69c */ { true, 0xc69c, 0xc69c }, +/* 0xc69d */ { true, 0xc69d, 0xc69d }, +/* 0xc69e */ { true, 0xc69e, 0xc69e }, +/* 0xc69f */ { true, 0xc69f, 0xc69f }, +/* 0xc6a0 */ { true, 0xc6a0, 0xc6a0 }, +/* 0xc6a1 */ { true, 0xc6a1, 0xc6a1 }, +/* 0xc6a2 */ { true, 0xc6a2, 0xc6a2 }, +/* 0xc6a3 */ { true, 0xc6a3, 0xc6a3 }, +/* 0xc6a4 */ { true, 0xc6a4, 0xc6a4 }, +/* 0xc6a5 */ { true, 0xc6a5, 0xc6a5 }, +/* 0xc6a6 */ { true, 0xc6a6, 0xc6a6 }, +/* 0xc6a7 */ { true, 0xc6a7, 0xc6a7 }, +/* 0xc6a8 */ { true, 0xc6a8, 0xc6a8 }, +/* 0xc6a9 */ { true, 0xc6a9, 0xc6a9 }, +/* 0xc6aa */ { true, 0xc6aa, 0xc6aa }, +/* 0xc6ab */ { true, 0xc6ab, 0xc6ab }, +/* 0xc6ac */ { true, 0xc6ac, 0xc6ac }, +/* 0xc6ad */ { true, 0xc6ad, 0xc6ad }, +/* 0xc6ae */ { true, 0xc6ae, 0xc6ae }, +/* 0xc6af */ { true, 0xc6af, 0xc6af }, +/* 0xc6b0 */ { true, 0xc6b0, 0xc6b0 }, +/* 0xc6b1 */ { true, 0xc6b1, 0xc6b1 }, +/* 0xc6b2 */ { true, 0xc6b2, 0xc6b2 }, +/* 0xc6b3 */ { true, 0xc6b3, 0xc6b3 }, +/* 0xc6b4 */ { true, 0xc6b4, 0xc6b4 }, +/* 0xc6b5 */ { true, 0xc6b5, 0xc6b5 }, +/* 0xc6b6 */ { true, 0xc6b6, 0xc6b6 }, +/* 0xc6b7 */ { true, 0xc6b7, 0xc6b7 }, +/* 0xc6b8 */ { true, 0xc6b8, 0xc6b8 }, +/* 0xc6b9 */ { true, 0xc6b9, 0xc6b9 }, +/* 0xc6ba */ { true, 0xc6ba, 0xc6ba }, +/* 0xc6bb */ { true, 0xc6bb, 0xc6bb }, +/* 0xc6bc */ { true, 0xc6bc, 0xc6bc }, +/* 0xc6bd */ { true, 0xc6bd, 0xc6bd }, +/* 0xc6be */ { true, 0xc6be, 0xc6be }, +/* 0xc6bf */ { true, 0xc6bf, 0xc6bf }, +/* 0xc6c0 */ { true, 0xc6c0, 0xc6c0 }, +/* 0xc6c1 */ { true, 0xc6c1, 0xc6c1 }, +/* 0xc6c2 */ { true, 0xc6c2, 0xc6c2 }, +/* 0xc6c3 */ { true, 0xc6c3, 0xc6c3 }, +/* 0xc6c4 */ { true, 0xc6c4, 0xc6c4 }, +/* 0xc6c5 */ { true, 0xc6c5, 0xc6c5 }, +/* 0xc6c6 */ { true, 0xc6c6, 0xc6c6 }, +/* 0xc6c7 */ { true, 0xc6c7, 0xc6c7 }, +/* 0xc6c8 */ { true, 0xc6c8, 0xc6c8 }, +/* 0xc6c9 */ { true, 0xc6c9, 0xc6c9 }, +/* 0xc6ca */ { true, 0xc6ca, 0xc6ca }, +/* 0xc6cb */ { true, 0xc6cb, 0xc6cb }, +/* 0xc6cc */ { true, 0xc6cc, 0xc6cc }, +/* 0xc6cd */ { true, 0xc6cd, 0xc6cd }, +/* 0xc6ce */ { true, 0xc6ce, 0xc6ce }, +/* 0xc6cf */ { true, 0xc6cf, 0xc6cf }, +/* 0xc6d0 */ { true, 0xc6d0, 0xc6d0 }, +/* 0xc6d1 */ { true, 0xc6d1, 0xc6d1 }, +/* 0xc6d2 */ { true, 0xc6d2, 0xc6d2 }, +/* 0xc6d3 */ { true, 0xc6d3, 0xc6d3 }, +/* 0xc6d4 */ { true, 0xc6d4, 0xc6d4 }, +/* 0xc6d5 */ { true, 0xc6d5, 0xc6d5 }, +/* 0xc6d6 */ { true, 0xc6d6, 0xc6d6 }, +/* 0xc6d7 */ { true, 0xc6d7, 0xc6d7 }, +/* 0xc6d8 */ { true, 0xc6d8, 0xc6d8 }, +/* 0xc6d9 */ { true, 0xc6d9, 0xc6d9 }, +/* 0xc6da */ { true, 0xc6da, 0xc6da }, +/* 0xc6db */ { true, 0xc6db, 0xc6db }, +/* 0xc6dc */ { true, 0xc6dc, 0xc6dc }, +/* 0xc6dd */ { true, 0xc6dd, 0xc6dd }, +/* 0xc6de */ { true, 0xc6de, 0xc6de }, +/* 0xc6df */ { true, 0xc6df, 0xc6df }, +/* 0xc6e0 */ { true, 0xc6e0, 0xc6e0 }, +/* 0xc6e1 */ { true, 0xc6e1, 0xc6e1 }, +/* 0xc6e2 */ { true, 0xc6e2, 0xc6e2 }, +/* 0xc6e3 */ { true, 0xc6e3, 0xc6e3 }, +/* 0xc6e4 */ { true, 0xc6e4, 0xc6e4 }, +/* 0xc6e5 */ { true, 0xc6e5, 0xc6e5 }, +/* 0xc6e6 */ { true, 0xc6e6, 0xc6e6 }, +/* 0xc6e7 */ { true, 0xc6e7, 0xc6e7 }, +/* 0xc6e8 */ { true, 0xc6e8, 0xc6e8 }, +/* 0xc6e9 */ { true, 0xc6e9, 0xc6e9 }, +/* 0xc6ea */ { true, 0xc6ea, 0xc6ea }, +/* 0xc6eb */ { true, 0xc6eb, 0xc6eb }, +/* 0xc6ec */ { true, 0xc6ec, 0xc6ec }, +/* 0xc6ed */ { true, 0xc6ed, 0xc6ed }, +/* 0xc6ee */ { true, 0xc6ee, 0xc6ee }, +/* 0xc6ef */ { true, 0xc6ef, 0xc6ef }, +/* 0xc6f0 */ { true, 0xc6f0, 0xc6f0 }, +/* 0xc6f1 */ { true, 0xc6f1, 0xc6f1 }, +/* 0xc6f2 */ { true, 0xc6f2, 0xc6f2 }, +/* 0xc6f3 */ { true, 0xc6f3, 0xc6f3 }, +/* 0xc6f4 */ { true, 0xc6f4, 0xc6f4 }, +/* 0xc6f5 */ { true, 0xc6f5, 0xc6f5 }, +/* 0xc6f6 */ { true, 0xc6f6, 0xc6f6 }, +/* 0xc6f7 */ { true, 0xc6f7, 0xc6f7 }, +/* 0xc6f8 */ { true, 0xc6f8, 0xc6f8 }, +/* 0xc6f9 */ { true, 0xc6f9, 0xc6f9 }, +/* 0xc6fa */ { true, 0xc6fa, 0xc6fa }, +/* 0xc6fb */ { true, 0xc6fb, 0xc6fb }, +/* 0xc6fc */ { true, 0xc6fc, 0xc6fc }, +/* 0xc6fd */ { true, 0xc6fd, 0xc6fd }, +/* 0xc6fe */ { true, 0xc6fe, 0xc6fe }, +/* 0xc6ff */ { true, 0xc6ff, 0xc6ff }, +/* 0xc700 */ { true, 0xc700, 0xc700 }, +/* 0xc701 */ { true, 0xc701, 0xc701 }, +/* 0xc702 */ { true, 0xc702, 0xc702 }, +/* 0xc703 */ { true, 0xc703, 0xc703 }, +/* 0xc704 */ { true, 0xc704, 0xc704 }, +/* 0xc705 */ { true, 0xc705, 0xc705 }, +/* 0xc706 */ { true, 0xc706, 0xc706 }, +/* 0xc707 */ { true, 0xc707, 0xc707 }, +/* 0xc708 */ { true, 0xc708, 0xc708 }, +/* 0xc709 */ { true, 0xc709, 0xc709 }, +/* 0xc70a */ { true, 0xc70a, 0xc70a }, +/* 0xc70b */ { true, 0xc70b, 0xc70b }, +/* 0xc70c */ { true, 0xc70c, 0xc70c }, +/* 0xc70d */ { true, 0xc70d, 0xc70d }, +/* 0xc70e */ { true, 0xc70e, 0xc70e }, +/* 0xc70f */ { true, 0xc70f, 0xc70f }, +/* 0xc710 */ { true, 0xc710, 0xc710 }, +/* 0xc711 */ { true, 0xc711, 0xc711 }, +/* 0xc712 */ { true, 0xc712, 0xc712 }, +/* 0xc713 */ { true, 0xc713, 0xc713 }, +/* 0xc714 */ { true, 0xc714, 0xc714 }, +/* 0xc715 */ { true, 0xc715, 0xc715 }, +/* 0xc716 */ { true, 0xc716, 0xc716 }, +/* 0xc717 */ { true, 0xc717, 0xc717 }, +/* 0xc718 */ { true, 0xc718, 0xc718 }, +/* 0xc719 */ { true, 0xc719, 0xc719 }, +/* 0xc71a */ { true, 0xc71a, 0xc71a }, +/* 0xc71b */ { true, 0xc71b, 0xc71b }, +/* 0xc71c */ { true, 0xc71c, 0xc71c }, +/* 0xc71d */ { true, 0xc71d, 0xc71d }, +/* 0xc71e */ { true, 0xc71e, 0xc71e }, +/* 0xc71f */ { true, 0xc71f, 0xc71f }, +/* 0xc720 */ { true, 0xc720, 0xc720 }, +/* 0xc721 */ { true, 0xc721, 0xc721 }, +/* 0xc722 */ { true, 0xc722, 0xc722 }, +/* 0xc723 */ { true, 0xc723, 0xc723 }, +/* 0xc724 */ { true, 0xc724, 0xc724 }, +/* 0xc725 */ { true, 0xc725, 0xc725 }, +/* 0xc726 */ { true, 0xc726, 0xc726 }, +/* 0xc727 */ { true, 0xc727, 0xc727 }, +/* 0xc728 */ { true, 0xc728, 0xc728 }, +/* 0xc729 */ { true, 0xc729, 0xc729 }, +/* 0xc72a */ { true, 0xc72a, 0xc72a }, +/* 0xc72b */ { true, 0xc72b, 0xc72b }, +/* 0xc72c */ { true, 0xc72c, 0xc72c }, +/* 0xc72d */ { true, 0xc72d, 0xc72d }, +/* 0xc72e */ { true, 0xc72e, 0xc72e }, +/* 0xc72f */ { true, 0xc72f, 0xc72f }, +/* 0xc730 */ { true, 0xc730, 0xc730 }, +/* 0xc731 */ { true, 0xc731, 0xc731 }, +/* 0xc732 */ { true, 0xc732, 0xc732 }, +/* 0xc733 */ { true, 0xc733, 0xc733 }, +/* 0xc734 */ { true, 0xc734, 0xc734 }, +/* 0xc735 */ { true, 0xc735, 0xc735 }, +/* 0xc736 */ { true, 0xc736, 0xc736 }, +/* 0xc737 */ { true, 0xc737, 0xc737 }, +/* 0xc738 */ { true, 0xc738, 0xc738 }, +/* 0xc739 */ { true, 0xc739, 0xc739 }, +/* 0xc73a */ { true, 0xc73a, 0xc73a }, +/* 0xc73b */ { true, 0xc73b, 0xc73b }, +/* 0xc73c */ { true, 0xc73c, 0xc73c }, +/* 0xc73d */ { true, 0xc73d, 0xc73d }, +/* 0xc73e */ { true, 0xc73e, 0xc73e }, +/* 0xc73f */ { true, 0xc73f, 0xc73f }, +/* 0xc740 */ { true, 0xc740, 0xc740 }, +/* 0xc741 */ { true, 0xc741, 0xc741 }, +/* 0xc742 */ { true, 0xc742, 0xc742 }, +/* 0xc743 */ { true, 0xc743, 0xc743 }, +/* 0xc744 */ { true, 0xc744, 0xc744 }, +/* 0xc745 */ { true, 0xc745, 0xc745 }, +/* 0xc746 */ { true, 0xc746, 0xc746 }, +/* 0xc747 */ { true, 0xc747, 0xc747 }, +/* 0xc748 */ { true, 0xc748, 0xc748 }, +/* 0xc749 */ { true, 0xc749, 0xc749 }, +/* 0xc74a */ { true, 0xc74a, 0xc74a }, +/* 0xc74b */ { true, 0xc74b, 0xc74b }, +/* 0xc74c */ { true, 0xc74c, 0xc74c }, +/* 0xc74d */ { true, 0xc74d, 0xc74d }, +/* 0xc74e */ { true, 0xc74e, 0xc74e }, +/* 0xc74f */ { true, 0xc74f, 0xc74f }, +/* 0xc750 */ { true, 0xc750, 0xc750 }, +/* 0xc751 */ { true, 0xc751, 0xc751 }, +/* 0xc752 */ { true, 0xc752, 0xc752 }, +/* 0xc753 */ { true, 0xc753, 0xc753 }, +/* 0xc754 */ { true, 0xc754, 0xc754 }, +/* 0xc755 */ { true, 0xc755, 0xc755 }, +/* 0xc756 */ { true, 0xc756, 0xc756 }, +/* 0xc757 */ { true, 0xc757, 0xc757 }, +/* 0xc758 */ { true, 0xc758, 0xc758 }, +/* 0xc759 */ { true, 0xc759, 0xc759 }, +/* 0xc75a */ { true, 0xc75a, 0xc75a }, +/* 0xc75b */ { true, 0xc75b, 0xc75b }, +/* 0xc75c */ { true, 0xc75c, 0xc75c }, +/* 0xc75d */ { true, 0xc75d, 0xc75d }, +/* 0xc75e */ { true, 0xc75e, 0xc75e }, +/* 0xc75f */ { true, 0xc75f, 0xc75f }, +/* 0xc760 */ { true, 0xc760, 0xc760 }, +/* 0xc761 */ { true, 0xc761, 0xc761 }, +/* 0xc762 */ { true, 0xc762, 0xc762 }, +/* 0xc763 */ { true, 0xc763, 0xc763 }, +/* 0xc764 */ { true, 0xc764, 0xc764 }, +/* 0xc765 */ { true, 0xc765, 0xc765 }, +/* 0xc766 */ { true, 0xc766, 0xc766 }, +/* 0xc767 */ { true, 0xc767, 0xc767 }, +/* 0xc768 */ { true, 0xc768, 0xc768 }, +/* 0xc769 */ { true, 0xc769, 0xc769 }, +/* 0xc76a */ { true, 0xc76a, 0xc76a }, +/* 0xc76b */ { true, 0xc76b, 0xc76b }, +/* 0xc76c */ { true, 0xc76c, 0xc76c }, +/* 0xc76d */ { true, 0xc76d, 0xc76d }, +/* 0xc76e */ { true, 0xc76e, 0xc76e }, +/* 0xc76f */ { true, 0xc76f, 0xc76f }, +/* 0xc770 */ { true, 0xc770, 0xc770 }, +/* 0xc771 */ { true, 0xc771, 0xc771 }, +/* 0xc772 */ { true, 0xc772, 0xc772 }, +/* 0xc773 */ { true, 0xc773, 0xc773 }, +/* 0xc774 */ { true, 0xc774, 0xc774 }, +/* 0xc775 */ { true, 0xc775, 0xc775 }, +/* 0xc776 */ { true, 0xc776, 0xc776 }, +/* 0xc777 */ { true, 0xc777, 0xc777 }, +/* 0xc778 */ { true, 0xc778, 0xc778 }, +/* 0xc779 */ { true, 0xc779, 0xc779 }, +/* 0xc77a */ { true, 0xc77a, 0xc77a }, +/* 0xc77b */ { true, 0xc77b, 0xc77b }, +/* 0xc77c */ { true, 0xc77c, 0xc77c }, +/* 0xc77d */ { true, 0xc77d, 0xc77d }, +/* 0xc77e */ { true, 0xc77e, 0xc77e }, +/* 0xc77f */ { true, 0xc77f, 0xc77f }, +/* 0xc780 */ { true, 0xc780, 0xc780 }, +/* 0xc781 */ { true, 0xc781, 0xc781 }, +/* 0xc782 */ { true, 0xc782, 0xc782 }, +/* 0xc783 */ { true, 0xc783, 0xc783 }, +/* 0xc784 */ { true, 0xc784, 0xc784 }, +/* 0xc785 */ { true, 0xc785, 0xc785 }, +/* 0xc786 */ { true, 0xc786, 0xc786 }, +/* 0xc787 */ { true, 0xc787, 0xc787 }, +/* 0xc788 */ { true, 0xc788, 0xc788 }, +/* 0xc789 */ { true, 0xc789, 0xc789 }, +/* 0xc78a */ { true, 0xc78a, 0xc78a }, +/* 0xc78b */ { true, 0xc78b, 0xc78b }, +/* 0xc78c */ { true, 0xc78c, 0xc78c }, +/* 0xc78d */ { true, 0xc78d, 0xc78d }, +/* 0xc78e */ { true, 0xc78e, 0xc78e }, +/* 0xc78f */ { true, 0xc78f, 0xc78f }, +/* 0xc790 */ { true, 0xc790, 0xc790 }, +/* 0xc791 */ { true, 0xc791, 0xc791 }, +/* 0xc792 */ { true, 0xc792, 0xc792 }, +/* 0xc793 */ { true, 0xc793, 0xc793 }, +/* 0xc794 */ { true, 0xc794, 0xc794 }, +/* 0xc795 */ { true, 0xc795, 0xc795 }, +/* 0xc796 */ { true, 0xc796, 0xc796 }, +/* 0xc797 */ { true, 0xc797, 0xc797 }, +/* 0xc798 */ { true, 0xc798, 0xc798 }, +/* 0xc799 */ { true, 0xc799, 0xc799 }, +/* 0xc79a */ { true, 0xc79a, 0xc79a }, +/* 0xc79b */ { true, 0xc79b, 0xc79b }, +/* 0xc79c */ { true, 0xc79c, 0xc79c }, +/* 0xc79d */ { true, 0xc79d, 0xc79d }, +/* 0xc79e */ { true, 0xc79e, 0xc79e }, +/* 0xc79f */ { true, 0xc79f, 0xc79f }, +/* 0xc7a0 */ { true, 0xc7a0, 0xc7a0 }, +/* 0xc7a1 */ { true, 0xc7a1, 0xc7a1 }, +/* 0xc7a2 */ { true, 0xc7a2, 0xc7a2 }, +/* 0xc7a3 */ { true, 0xc7a3, 0xc7a3 }, +/* 0xc7a4 */ { true, 0xc7a4, 0xc7a4 }, +/* 0xc7a5 */ { true, 0xc7a5, 0xc7a5 }, +/* 0xc7a6 */ { true, 0xc7a6, 0xc7a6 }, +/* 0xc7a7 */ { true, 0xc7a7, 0xc7a7 }, +/* 0xc7a8 */ { true, 0xc7a8, 0xc7a8 }, +/* 0xc7a9 */ { true, 0xc7a9, 0xc7a9 }, +/* 0xc7aa */ { true, 0xc7aa, 0xc7aa }, +/* 0xc7ab */ { true, 0xc7ab, 0xc7ab }, +/* 0xc7ac */ { true, 0xc7ac, 0xc7ac }, +/* 0xc7ad */ { true, 0xc7ad, 0xc7ad }, +/* 0xc7ae */ { true, 0xc7ae, 0xc7ae }, +/* 0xc7af */ { true, 0xc7af, 0xc7af }, +/* 0xc7b0 */ { true, 0xc7b0, 0xc7b0 }, +/* 0xc7b1 */ { true, 0xc7b1, 0xc7b1 }, +/* 0xc7b2 */ { true, 0xc7b2, 0xc7b2 }, +/* 0xc7b3 */ { true, 0xc7b3, 0xc7b3 }, +/* 0xc7b4 */ { true, 0xc7b4, 0xc7b4 }, +/* 0xc7b5 */ { true, 0xc7b5, 0xc7b5 }, +/* 0xc7b6 */ { true, 0xc7b6, 0xc7b6 }, +/* 0xc7b7 */ { true, 0xc7b7, 0xc7b7 }, +/* 0xc7b8 */ { true, 0xc7b8, 0xc7b8 }, +/* 0xc7b9 */ { true, 0xc7b9, 0xc7b9 }, +/* 0xc7ba */ { true, 0xc7ba, 0xc7ba }, +/* 0xc7bb */ { true, 0xc7bb, 0xc7bb }, +/* 0xc7bc */ { true, 0xc7bc, 0xc7bc }, +/* 0xc7bd */ { true, 0xc7bd, 0xc7bd }, +/* 0xc7be */ { true, 0xc7be, 0xc7be }, +/* 0xc7bf */ { true, 0xc7bf, 0xc7bf }, +/* 0xc7c0 */ { true, 0xc7c0, 0xc7c0 }, +/* 0xc7c1 */ { true, 0xc7c1, 0xc7c1 }, +/* 0xc7c2 */ { true, 0xc7c2, 0xc7c2 }, +/* 0xc7c3 */ { true, 0xc7c3, 0xc7c3 }, +/* 0xc7c4 */ { true, 0xc7c4, 0xc7c4 }, +/* 0xc7c5 */ { true, 0xc7c5, 0xc7c5 }, +/* 0xc7c6 */ { true, 0xc7c6, 0xc7c6 }, +/* 0xc7c7 */ { true, 0xc7c7, 0xc7c7 }, +/* 0xc7c8 */ { true, 0xc7c8, 0xc7c8 }, +/* 0xc7c9 */ { true, 0xc7c9, 0xc7c9 }, +/* 0xc7ca */ { true, 0xc7ca, 0xc7ca }, +/* 0xc7cb */ { true, 0xc7cb, 0xc7cb }, +/* 0xc7cc */ { true, 0xc7cc, 0xc7cc }, +/* 0xc7cd */ { true, 0xc7cd, 0xc7cd }, +/* 0xc7ce */ { true, 0xc7ce, 0xc7ce }, +/* 0xc7cf */ { true, 0xc7cf, 0xc7cf }, +/* 0xc7d0 */ { true, 0xc7d0, 0xc7d0 }, +/* 0xc7d1 */ { true, 0xc7d1, 0xc7d1 }, +/* 0xc7d2 */ { true, 0xc7d2, 0xc7d2 }, +/* 0xc7d3 */ { true, 0xc7d3, 0xc7d3 }, +/* 0xc7d4 */ { true, 0xc7d4, 0xc7d4 }, +/* 0xc7d5 */ { true, 0xc7d5, 0xc7d5 }, +/* 0xc7d6 */ { true, 0xc7d6, 0xc7d6 }, +/* 0xc7d7 */ { true, 0xc7d7, 0xc7d7 }, +/* 0xc7d8 */ { true, 0xc7d8, 0xc7d8 }, +/* 0xc7d9 */ { true, 0xc7d9, 0xc7d9 }, +/* 0xc7da */ { true, 0xc7da, 0xc7da }, +/* 0xc7db */ { true, 0xc7db, 0xc7db }, +/* 0xc7dc */ { true, 0xc7dc, 0xc7dc }, +/* 0xc7dd */ { true, 0xc7dd, 0xc7dd }, +/* 0xc7de */ { true, 0xc7de, 0xc7de }, +/* 0xc7df */ { true, 0xc7df, 0xc7df }, +/* 0xc7e0 */ { true, 0xc7e0, 0xc7e0 }, +/* 0xc7e1 */ { true, 0xc7e1, 0xc7e1 }, +/* 0xc7e2 */ { true, 0xc7e2, 0xc7e2 }, +/* 0xc7e3 */ { true, 0xc7e3, 0xc7e3 }, +/* 0xc7e4 */ { true, 0xc7e4, 0xc7e4 }, +/* 0xc7e5 */ { true, 0xc7e5, 0xc7e5 }, +/* 0xc7e6 */ { true, 0xc7e6, 0xc7e6 }, +/* 0xc7e7 */ { true, 0xc7e7, 0xc7e7 }, +/* 0xc7e8 */ { true, 0xc7e8, 0xc7e8 }, +/* 0xc7e9 */ { true, 0xc7e9, 0xc7e9 }, +/* 0xc7ea */ { true, 0xc7ea, 0xc7ea }, +/* 0xc7eb */ { true, 0xc7eb, 0xc7eb }, +/* 0xc7ec */ { true, 0xc7ec, 0xc7ec }, +/* 0xc7ed */ { true, 0xc7ed, 0xc7ed }, +/* 0xc7ee */ { true, 0xc7ee, 0xc7ee }, +/* 0xc7ef */ { true, 0xc7ef, 0xc7ef }, +/* 0xc7f0 */ { true, 0xc7f0, 0xc7f0 }, +/* 0xc7f1 */ { true, 0xc7f1, 0xc7f1 }, +/* 0xc7f2 */ { true, 0xc7f2, 0xc7f2 }, +/* 0xc7f3 */ { true, 0xc7f3, 0xc7f3 }, +/* 0xc7f4 */ { true, 0xc7f4, 0xc7f4 }, +/* 0xc7f5 */ { true, 0xc7f5, 0xc7f5 }, +/* 0xc7f6 */ { true, 0xc7f6, 0xc7f6 }, +/* 0xc7f7 */ { true, 0xc7f7, 0xc7f7 }, +/* 0xc7f8 */ { true, 0xc7f8, 0xc7f8 }, +/* 0xc7f9 */ { true, 0xc7f9, 0xc7f9 }, +/* 0xc7fa */ { true, 0xc7fa, 0xc7fa }, +/* 0xc7fb */ { true, 0xc7fb, 0xc7fb }, +/* 0xc7fc */ { true, 0xc7fc, 0xc7fc }, +/* 0xc7fd */ { true, 0xc7fd, 0xc7fd }, +/* 0xc7fe */ { true, 0xc7fe, 0xc7fe }, +/* 0xc7ff */ { true, 0xc7ff, 0xc7ff }, +/* 0xc800 */ { true, 0xc800, 0xc800 }, +/* 0xc801 */ { true, 0xc801, 0xc801 }, +/* 0xc802 */ { true, 0xc802, 0xc802 }, +/* 0xc803 */ { true, 0xc803, 0xc803 }, +/* 0xc804 */ { true, 0xc804, 0xc804 }, +/* 0xc805 */ { true, 0xc805, 0xc805 }, +/* 0xc806 */ { true, 0xc806, 0xc806 }, +/* 0xc807 */ { true, 0xc807, 0xc807 }, +/* 0xc808 */ { true, 0xc808, 0xc808 }, +/* 0xc809 */ { true, 0xc809, 0xc809 }, +/* 0xc80a */ { true, 0xc80a, 0xc80a }, +/* 0xc80b */ { true, 0xc80b, 0xc80b }, +/* 0xc80c */ { true, 0xc80c, 0xc80c }, +/* 0xc80d */ { true, 0xc80d, 0xc80d }, +/* 0xc80e */ { true, 0xc80e, 0xc80e }, +/* 0xc80f */ { true, 0xc80f, 0xc80f }, +/* 0xc810 */ { true, 0xc810, 0xc810 }, +/* 0xc811 */ { true, 0xc811, 0xc811 }, +/* 0xc812 */ { true, 0xc812, 0xc812 }, +/* 0xc813 */ { true, 0xc813, 0xc813 }, +/* 0xc814 */ { true, 0xc814, 0xc814 }, +/* 0xc815 */ { true, 0xc815, 0xc815 }, +/* 0xc816 */ { true, 0xc816, 0xc816 }, +/* 0xc817 */ { true, 0xc817, 0xc817 }, +/* 0xc818 */ { true, 0xc818, 0xc818 }, +/* 0xc819 */ { true, 0xc819, 0xc819 }, +/* 0xc81a */ { true, 0xc81a, 0xc81a }, +/* 0xc81b */ { true, 0xc81b, 0xc81b }, +/* 0xc81c */ { true, 0xc81c, 0xc81c }, +/* 0xc81d */ { true, 0xc81d, 0xc81d }, +/* 0xc81e */ { true, 0xc81e, 0xc81e }, +/* 0xc81f */ { true, 0xc81f, 0xc81f }, +/* 0xc820 */ { true, 0xc820, 0xc820 }, +/* 0xc821 */ { true, 0xc821, 0xc821 }, +/* 0xc822 */ { true, 0xc822, 0xc822 }, +/* 0xc823 */ { true, 0xc823, 0xc823 }, +/* 0xc824 */ { true, 0xc824, 0xc824 }, +/* 0xc825 */ { true, 0xc825, 0xc825 }, +/* 0xc826 */ { true, 0xc826, 0xc826 }, +/* 0xc827 */ { true, 0xc827, 0xc827 }, +/* 0xc828 */ { true, 0xc828, 0xc828 }, +/* 0xc829 */ { true, 0xc829, 0xc829 }, +/* 0xc82a */ { true, 0xc82a, 0xc82a }, +/* 0xc82b */ { true, 0xc82b, 0xc82b }, +/* 0xc82c */ { true, 0xc82c, 0xc82c }, +/* 0xc82d */ { true, 0xc82d, 0xc82d }, +/* 0xc82e */ { true, 0xc82e, 0xc82e }, +/* 0xc82f */ { true, 0xc82f, 0xc82f }, +/* 0xc830 */ { true, 0xc830, 0xc830 }, +/* 0xc831 */ { true, 0xc831, 0xc831 }, +/* 0xc832 */ { true, 0xc832, 0xc832 }, +/* 0xc833 */ { true, 0xc833, 0xc833 }, +/* 0xc834 */ { true, 0xc834, 0xc834 }, +/* 0xc835 */ { true, 0xc835, 0xc835 }, +/* 0xc836 */ { true, 0xc836, 0xc836 }, +/* 0xc837 */ { true, 0xc837, 0xc837 }, +/* 0xc838 */ { true, 0xc838, 0xc838 }, +/* 0xc839 */ { true, 0xc839, 0xc839 }, +/* 0xc83a */ { true, 0xc83a, 0xc83a }, +/* 0xc83b */ { true, 0xc83b, 0xc83b }, +/* 0xc83c */ { true, 0xc83c, 0xc83c }, +/* 0xc83d */ { true, 0xc83d, 0xc83d }, +/* 0xc83e */ { true, 0xc83e, 0xc83e }, +/* 0xc83f */ { true, 0xc83f, 0xc83f }, +/* 0xc840 */ { true, 0xc840, 0xc840 }, +/* 0xc841 */ { true, 0xc841, 0xc841 }, +/* 0xc842 */ { true, 0xc842, 0xc842 }, +/* 0xc843 */ { true, 0xc843, 0xc843 }, +/* 0xc844 */ { true, 0xc844, 0xc844 }, +/* 0xc845 */ { true, 0xc845, 0xc845 }, +/* 0xc846 */ { true, 0xc846, 0xc846 }, +/* 0xc847 */ { true, 0xc847, 0xc847 }, +/* 0xc848 */ { true, 0xc848, 0xc848 }, +/* 0xc849 */ { true, 0xc849, 0xc849 }, +/* 0xc84a */ { true, 0xc84a, 0xc84a }, +/* 0xc84b */ { true, 0xc84b, 0xc84b }, +/* 0xc84c */ { true, 0xc84c, 0xc84c }, +/* 0xc84d */ { true, 0xc84d, 0xc84d }, +/* 0xc84e */ { true, 0xc84e, 0xc84e }, +/* 0xc84f */ { true, 0xc84f, 0xc84f }, +/* 0xc850 */ { true, 0xc850, 0xc850 }, +/* 0xc851 */ { true, 0xc851, 0xc851 }, +/* 0xc852 */ { true, 0xc852, 0xc852 }, +/* 0xc853 */ { true, 0xc853, 0xc853 }, +/* 0xc854 */ { true, 0xc854, 0xc854 }, +/* 0xc855 */ { true, 0xc855, 0xc855 }, +/* 0xc856 */ { true, 0xc856, 0xc856 }, +/* 0xc857 */ { true, 0xc857, 0xc857 }, +/* 0xc858 */ { true, 0xc858, 0xc858 }, +/* 0xc859 */ { true, 0xc859, 0xc859 }, +/* 0xc85a */ { true, 0xc85a, 0xc85a }, +/* 0xc85b */ { true, 0xc85b, 0xc85b }, +/* 0xc85c */ { true, 0xc85c, 0xc85c }, +/* 0xc85d */ { true, 0xc85d, 0xc85d }, +/* 0xc85e */ { true, 0xc85e, 0xc85e }, +/* 0xc85f */ { true, 0xc85f, 0xc85f }, +/* 0xc860 */ { true, 0xc860, 0xc860 }, +/* 0xc861 */ { true, 0xc861, 0xc861 }, +/* 0xc862 */ { true, 0xc862, 0xc862 }, +/* 0xc863 */ { true, 0xc863, 0xc863 }, +/* 0xc864 */ { true, 0xc864, 0xc864 }, +/* 0xc865 */ { true, 0xc865, 0xc865 }, +/* 0xc866 */ { true, 0xc866, 0xc866 }, +/* 0xc867 */ { true, 0xc867, 0xc867 }, +/* 0xc868 */ { true, 0xc868, 0xc868 }, +/* 0xc869 */ { true, 0xc869, 0xc869 }, +/* 0xc86a */ { true, 0xc86a, 0xc86a }, +/* 0xc86b */ { true, 0xc86b, 0xc86b }, +/* 0xc86c */ { true, 0xc86c, 0xc86c }, +/* 0xc86d */ { true, 0xc86d, 0xc86d }, +/* 0xc86e */ { true, 0xc86e, 0xc86e }, +/* 0xc86f */ { true, 0xc86f, 0xc86f }, +/* 0xc870 */ { true, 0xc870, 0xc870 }, +/* 0xc871 */ { true, 0xc871, 0xc871 }, +/* 0xc872 */ { true, 0xc872, 0xc872 }, +/* 0xc873 */ { true, 0xc873, 0xc873 }, +/* 0xc874 */ { true, 0xc874, 0xc874 }, +/* 0xc875 */ { true, 0xc875, 0xc875 }, +/* 0xc876 */ { true, 0xc876, 0xc876 }, +/* 0xc877 */ { true, 0xc877, 0xc877 }, +/* 0xc878 */ { true, 0xc878, 0xc878 }, +/* 0xc879 */ { true, 0xc879, 0xc879 }, +/* 0xc87a */ { true, 0xc87a, 0xc87a }, +/* 0xc87b */ { true, 0xc87b, 0xc87b }, +/* 0xc87c */ { true, 0xc87c, 0xc87c }, +/* 0xc87d */ { true, 0xc87d, 0xc87d }, +/* 0xc87e */ { true, 0xc87e, 0xc87e }, +/* 0xc87f */ { true, 0xc87f, 0xc87f }, +/* 0xc880 */ { true, 0xc880, 0xc880 }, +/* 0xc881 */ { true, 0xc881, 0xc881 }, +/* 0xc882 */ { true, 0xc882, 0xc882 }, +/* 0xc883 */ { true, 0xc883, 0xc883 }, +/* 0xc884 */ { true, 0xc884, 0xc884 }, +/* 0xc885 */ { true, 0xc885, 0xc885 }, +/* 0xc886 */ { true, 0xc886, 0xc886 }, +/* 0xc887 */ { true, 0xc887, 0xc887 }, +/* 0xc888 */ { true, 0xc888, 0xc888 }, +/* 0xc889 */ { true, 0xc889, 0xc889 }, +/* 0xc88a */ { true, 0xc88a, 0xc88a }, +/* 0xc88b */ { true, 0xc88b, 0xc88b }, +/* 0xc88c */ { true, 0xc88c, 0xc88c }, +/* 0xc88d */ { true, 0xc88d, 0xc88d }, +/* 0xc88e */ { true, 0xc88e, 0xc88e }, +/* 0xc88f */ { true, 0xc88f, 0xc88f }, +/* 0xc890 */ { true, 0xc890, 0xc890 }, +/* 0xc891 */ { true, 0xc891, 0xc891 }, +/* 0xc892 */ { true, 0xc892, 0xc892 }, +/* 0xc893 */ { true, 0xc893, 0xc893 }, +/* 0xc894 */ { true, 0xc894, 0xc894 }, +/* 0xc895 */ { true, 0xc895, 0xc895 }, +/* 0xc896 */ { true, 0xc896, 0xc896 }, +/* 0xc897 */ { true, 0xc897, 0xc897 }, +/* 0xc898 */ { true, 0xc898, 0xc898 }, +/* 0xc899 */ { true, 0xc899, 0xc899 }, +/* 0xc89a */ { true, 0xc89a, 0xc89a }, +/* 0xc89b */ { true, 0xc89b, 0xc89b }, +/* 0xc89c */ { true, 0xc89c, 0xc89c }, +/* 0xc89d */ { true, 0xc89d, 0xc89d }, +/* 0xc89e */ { true, 0xc89e, 0xc89e }, +/* 0xc89f */ { true, 0xc89f, 0xc89f }, +/* 0xc8a0 */ { true, 0xc8a0, 0xc8a0 }, +/* 0xc8a1 */ { true, 0xc8a1, 0xc8a1 }, +/* 0xc8a2 */ { true, 0xc8a2, 0xc8a2 }, +/* 0xc8a3 */ { true, 0xc8a3, 0xc8a3 }, +/* 0xc8a4 */ { true, 0xc8a4, 0xc8a4 }, +/* 0xc8a5 */ { true, 0xc8a5, 0xc8a5 }, +/* 0xc8a6 */ { true, 0xc8a6, 0xc8a6 }, +/* 0xc8a7 */ { true, 0xc8a7, 0xc8a7 }, +/* 0xc8a8 */ { true, 0xc8a8, 0xc8a8 }, +/* 0xc8a9 */ { true, 0xc8a9, 0xc8a9 }, +/* 0xc8aa */ { true, 0xc8aa, 0xc8aa }, +/* 0xc8ab */ { true, 0xc8ab, 0xc8ab }, +/* 0xc8ac */ { true, 0xc8ac, 0xc8ac }, +/* 0xc8ad */ { true, 0xc8ad, 0xc8ad }, +/* 0xc8ae */ { true, 0xc8ae, 0xc8ae }, +/* 0xc8af */ { true, 0xc8af, 0xc8af }, +/* 0xc8b0 */ { true, 0xc8b0, 0xc8b0 }, +/* 0xc8b1 */ { true, 0xc8b1, 0xc8b1 }, +/* 0xc8b2 */ { true, 0xc8b2, 0xc8b2 }, +/* 0xc8b3 */ { true, 0xc8b3, 0xc8b3 }, +/* 0xc8b4 */ { true, 0xc8b4, 0xc8b4 }, +/* 0xc8b5 */ { true, 0xc8b5, 0xc8b5 }, +/* 0xc8b6 */ { true, 0xc8b6, 0xc8b6 }, +/* 0xc8b7 */ { true, 0xc8b7, 0xc8b7 }, +/* 0xc8b8 */ { true, 0xc8b8, 0xc8b8 }, +/* 0xc8b9 */ { true, 0xc8b9, 0xc8b9 }, +/* 0xc8ba */ { true, 0xc8ba, 0xc8ba }, +/* 0xc8bb */ { true, 0xc8bb, 0xc8bb }, +/* 0xc8bc */ { true, 0xc8bc, 0xc8bc }, +/* 0xc8bd */ { true, 0xc8bd, 0xc8bd }, +/* 0xc8be */ { true, 0xc8be, 0xc8be }, +/* 0xc8bf */ { true, 0xc8bf, 0xc8bf }, +/* 0xc8c0 */ { true, 0xc8c0, 0xc8c0 }, +/* 0xc8c1 */ { true, 0xc8c1, 0xc8c1 }, +/* 0xc8c2 */ { true, 0xc8c2, 0xc8c2 }, +/* 0xc8c3 */ { true, 0xc8c3, 0xc8c3 }, +/* 0xc8c4 */ { true, 0xc8c4, 0xc8c4 }, +/* 0xc8c5 */ { true, 0xc8c5, 0xc8c5 }, +/* 0xc8c6 */ { true, 0xc8c6, 0xc8c6 }, +/* 0xc8c7 */ { true, 0xc8c7, 0xc8c7 }, +/* 0xc8c8 */ { true, 0xc8c8, 0xc8c8 }, +/* 0xc8c9 */ { true, 0xc8c9, 0xc8c9 }, +/* 0xc8ca */ { true, 0xc8ca, 0xc8ca }, +/* 0xc8cb */ { true, 0xc8cb, 0xc8cb }, +/* 0xc8cc */ { true, 0xc8cc, 0xc8cc }, +/* 0xc8cd */ { true, 0xc8cd, 0xc8cd }, +/* 0xc8ce */ { true, 0xc8ce, 0xc8ce }, +/* 0xc8cf */ { true, 0xc8cf, 0xc8cf }, +/* 0xc8d0 */ { true, 0xc8d0, 0xc8d0 }, +/* 0xc8d1 */ { true, 0xc8d1, 0xc8d1 }, +/* 0xc8d2 */ { true, 0xc8d2, 0xc8d2 }, +/* 0xc8d3 */ { true, 0xc8d3, 0xc8d3 }, +/* 0xc8d4 */ { true, 0xc8d4, 0xc8d4 }, +/* 0xc8d5 */ { true, 0xc8d5, 0xc8d5 }, +/* 0xc8d6 */ { true, 0xc8d6, 0xc8d6 }, +/* 0xc8d7 */ { true, 0xc8d7, 0xc8d7 }, +/* 0xc8d8 */ { true, 0xc8d8, 0xc8d8 }, +/* 0xc8d9 */ { true, 0xc8d9, 0xc8d9 }, +/* 0xc8da */ { true, 0xc8da, 0xc8da }, +/* 0xc8db */ { true, 0xc8db, 0xc8db }, +/* 0xc8dc */ { true, 0xc8dc, 0xc8dc }, +/* 0xc8dd */ { true, 0xc8dd, 0xc8dd }, +/* 0xc8de */ { true, 0xc8de, 0xc8de }, +/* 0xc8df */ { true, 0xc8df, 0xc8df }, +/* 0xc8e0 */ { true, 0xc8e0, 0xc8e0 }, +/* 0xc8e1 */ { true, 0xc8e1, 0xc8e1 }, +/* 0xc8e2 */ { true, 0xc8e2, 0xc8e2 }, +/* 0xc8e3 */ { true, 0xc8e3, 0xc8e3 }, +/* 0xc8e4 */ { true, 0xc8e4, 0xc8e4 }, +/* 0xc8e5 */ { true, 0xc8e5, 0xc8e5 }, +/* 0xc8e6 */ { true, 0xc8e6, 0xc8e6 }, +/* 0xc8e7 */ { true, 0xc8e7, 0xc8e7 }, +/* 0xc8e8 */ { true, 0xc8e8, 0xc8e8 }, +/* 0xc8e9 */ { true, 0xc8e9, 0xc8e9 }, +/* 0xc8ea */ { true, 0xc8ea, 0xc8ea }, +/* 0xc8eb */ { true, 0xc8eb, 0xc8eb }, +/* 0xc8ec */ { true, 0xc8ec, 0xc8ec }, +/* 0xc8ed */ { true, 0xc8ed, 0xc8ed }, +/* 0xc8ee */ { true, 0xc8ee, 0xc8ee }, +/* 0xc8ef */ { true, 0xc8ef, 0xc8ef }, +/* 0xc8f0 */ { true, 0xc8f0, 0xc8f0 }, +/* 0xc8f1 */ { true, 0xc8f1, 0xc8f1 }, +/* 0xc8f2 */ { true, 0xc8f2, 0xc8f2 }, +/* 0xc8f3 */ { true, 0xc8f3, 0xc8f3 }, +/* 0xc8f4 */ { true, 0xc8f4, 0xc8f4 }, +/* 0xc8f5 */ { true, 0xc8f5, 0xc8f5 }, +/* 0xc8f6 */ { true, 0xc8f6, 0xc8f6 }, +/* 0xc8f7 */ { true, 0xc8f7, 0xc8f7 }, +/* 0xc8f8 */ { true, 0xc8f8, 0xc8f8 }, +/* 0xc8f9 */ { true, 0xc8f9, 0xc8f9 }, +/* 0xc8fa */ { true, 0xc8fa, 0xc8fa }, +/* 0xc8fb */ { true, 0xc8fb, 0xc8fb }, +/* 0xc8fc */ { true, 0xc8fc, 0xc8fc }, +/* 0xc8fd */ { true, 0xc8fd, 0xc8fd }, +/* 0xc8fe */ { true, 0xc8fe, 0xc8fe }, +/* 0xc8ff */ { true, 0xc8ff, 0xc8ff }, +/* 0xc900 */ { true, 0xc900, 0xc900 }, +/* 0xc901 */ { true, 0xc901, 0xc901 }, +/* 0xc902 */ { true, 0xc902, 0xc902 }, +/* 0xc903 */ { true, 0xc903, 0xc903 }, +/* 0xc904 */ { true, 0xc904, 0xc904 }, +/* 0xc905 */ { true, 0xc905, 0xc905 }, +/* 0xc906 */ { true, 0xc906, 0xc906 }, +/* 0xc907 */ { true, 0xc907, 0xc907 }, +/* 0xc908 */ { true, 0xc908, 0xc908 }, +/* 0xc909 */ { true, 0xc909, 0xc909 }, +/* 0xc90a */ { true, 0xc90a, 0xc90a }, +/* 0xc90b */ { true, 0xc90b, 0xc90b }, +/* 0xc90c */ { true, 0xc90c, 0xc90c }, +/* 0xc90d */ { true, 0xc90d, 0xc90d }, +/* 0xc90e */ { true, 0xc90e, 0xc90e }, +/* 0xc90f */ { true, 0xc90f, 0xc90f }, +/* 0xc910 */ { true, 0xc910, 0xc910 }, +/* 0xc911 */ { true, 0xc911, 0xc911 }, +/* 0xc912 */ { true, 0xc912, 0xc912 }, +/* 0xc913 */ { true, 0xc913, 0xc913 }, +/* 0xc914 */ { true, 0xc914, 0xc914 }, +/* 0xc915 */ { true, 0xc915, 0xc915 }, +/* 0xc916 */ { true, 0xc916, 0xc916 }, +/* 0xc917 */ { true, 0xc917, 0xc917 }, +/* 0xc918 */ { true, 0xc918, 0xc918 }, +/* 0xc919 */ { true, 0xc919, 0xc919 }, +/* 0xc91a */ { true, 0xc91a, 0xc91a }, +/* 0xc91b */ { true, 0xc91b, 0xc91b }, +/* 0xc91c */ { true, 0xc91c, 0xc91c }, +/* 0xc91d */ { true, 0xc91d, 0xc91d }, +/* 0xc91e */ { true, 0xc91e, 0xc91e }, +/* 0xc91f */ { true, 0xc91f, 0xc91f }, +/* 0xc920 */ { true, 0xc920, 0xc920 }, +/* 0xc921 */ { true, 0xc921, 0xc921 }, +/* 0xc922 */ { true, 0xc922, 0xc922 }, +/* 0xc923 */ { true, 0xc923, 0xc923 }, +/* 0xc924 */ { true, 0xc924, 0xc924 }, +/* 0xc925 */ { true, 0xc925, 0xc925 }, +/* 0xc926 */ { true, 0xc926, 0xc926 }, +/* 0xc927 */ { true, 0xc927, 0xc927 }, +/* 0xc928 */ { true, 0xc928, 0xc928 }, +/* 0xc929 */ { true, 0xc929, 0xc929 }, +/* 0xc92a */ { true, 0xc92a, 0xc92a }, +/* 0xc92b */ { true, 0xc92b, 0xc92b }, +/* 0xc92c */ { true, 0xc92c, 0xc92c }, +/* 0xc92d */ { true, 0xc92d, 0xc92d }, +/* 0xc92e */ { true, 0xc92e, 0xc92e }, +/* 0xc92f */ { true, 0xc92f, 0xc92f }, +/* 0xc930 */ { true, 0xc930, 0xc930 }, +/* 0xc931 */ { true, 0xc931, 0xc931 }, +/* 0xc932 */ { true, 0xc932, 0xc932 }, +/* 0xc933 */ { true, 0xc933, 0xc933 }, +/* 0xc934 */ { true, 0xc934, 0xc934 }, +/* 0xc935 */ { true, 0xc935, 0xc935 }, +/* 0xc936 */ { true, 0xc936, 0xc936 }, +/* 0xc937 */ { true, 0xc937, 0xc937 }, +/* 0xc938 */ { true, 0xc938, 0xc938 }, +/* 0xc939 */ { true, 0xc939, 0xc939 }, +/* 0xc93a */ { true, 0xc93a, 0xc93a }, +/* 0xc93b */ { true, 0xc93b, 0xc93b }, +/* 0xc93c */ { true, 0xc93c, 0xc93c }, +/* 0xc93d */ { true, 0xc93d, 0xc93d }, +/* 0xc93e */ { true, 0xc93e, 0xc93e }, +/* 0xc93f */ { true, 0xc93f, 0xc93f }, +/* 0xc940 */ { true, 0xc940, 0xc940 }, +/* 0xc941 */ { true, 0xc941, 0xc941 }, +/* 0xc942 */ { true, 0xc942, 0xc942 }, +/* 0xc943 */ { true, 0xc943, 0xc943 }, +/* 0xc944 */ { true, 0xc944, 0xc944 }, +/* 0xc945 */ { true, 0xc945, 0xc945 }, +/* 0xc946 */ { true, 0xc946, 0xc946 }, +/* 0xc947 */ { true, 0xc947, 0xc947 }, +/* 0xc948 */ { true, 0xc948, 0xc948 }, +/* 0xc949 */ { true, 0xc949, 0xc949 }, +/* 0xc94a */ { true, 0xc94a, 0xc94a }, +/* 0xc94b */ { true, 0xc94b, 0xc94b }, +/* 0xc94c */ { true, 0xc94c, 0xc94c }, +/* 0xc94d */ { true, 0xc94d, 0xc94d }, +/* 0xc94e */ { true, 0xc94e, 0xc94e }, +/* 0xc94f */ { true, 0xc94f, 0xc94f }, +/* 0xc950 */ { true, 0xc950, 0xc950 }, +/* 0xc951 */ { true, 0xc951, 0xc951 }, +/* 0xc952 */ { true, 0xc952, 0xc952 }, +/* 0xc953 */ { true, 0xc953, 0xc953 }, +/* 0xc954 */ { true, 0xc954, 0xc954 }, +/* 0xc955 */ { true, 0xc955, 0xc955 }, +/* 0xc956 */ { true, 0xc956, 0xc956 }, +/* 0xc957 */ { true, 0xc957, 0xc957 }, +/* 0xc958 */ { true, 0xc958, 0xc958 }, +/* 0xc959 */ { true, 0xc959, 0xc959 }, +/* 0xc95a */ { true, 0xc95a, 0xc95a }, +/* 0xc95b */ { true, 0xc95b, 0xc95b }, +/* 0xc95c */ { true, 0xc95c, 0xc95c }, +/* 0xc95d */ { true, 0xc95d, 0xc95d }, +/* 0xc95e */ { true, 0xc95e, 0xc95e }, +/* 0xc95f */ { true, 0xc95f, 0xc95f }, +/* 0xc960 */ { true, 0xc960, 0xc960 }, +/* 0xc961 */ { true, 0xc961, 0xc961 }, +/* 0xc962 */ { true, 0xc962, 0xc962 }, +/* 0xc963 */ { true, 0xc963, 0xc963 }, +/* 0xc964 */ { true, 0xc964, 0xc964 }, +/* 0xc965 */ { true, 0xc965, 0xc965 }, +/* 0xc966 */ { true, 0xc966, 0xc966 }, +/* 0xc967 */ { true, 0xc967, 0xc967 }, +/* 0xc968 */ { true, 0xc968, 0xc968 }, +/* 0xc969 */ { true, 0xc969, 0xc969 }, +/* 0xc96a */ { true, 0xc96a, 0xc96a }, +/* 0xc96b */ { true, 0xc96b, 0xc96b }, +/* 0xc96c */ { true, 0xc96c, 0xc96c }, +/* 0xc96d */ { true, 0xc96d, 0xc96d }, +/* 0xc96e */ { true, 0xc96e, 0xc96e }, +/* 0xc96f */ { true, 0xc96f, 0xc96f }, +/* 0xc970 */ { true, 0xc970, 0xc970 }, +/* 0xc971 */ { true, 0xc971, 0xc971 }, +/* 0xc972 */ { true, 0xc972, 0xc972 }, +/* 0xc973 */ { true, 0xc973, 0xc973 }, +/* 0xc974 */ { true, 0xc974, 0xc974 }, +/* 0xc975 */ { true, 0xc975, 0xc975 }, +/* 0xc976 */ { true, 0xc976, 0xc976 }, +/* 0xc977 */ { true, 0xc977, 0xc977 }, +/* 0xc978 */ { true, 0xc978, 0xc978 }, +/* 0xc979 */ { true, 0xc979, 0xc979 }, +/* 0xc97a */ { true, 0xc97a, 0xc97a }, +/* 0xc97b */ { true, 0xc97b, 0xc97b }, +/* 0xc97c */ { true, 0xc97c, 0xc97c }, +/* 0xc97d */ { true, 0xc97d, 0xc97d }, +/* 0xc97e */ { true, 0xc97e, 0xc97e }, +/* 0xc97f */ { true, 0xc97f, 0xc97f }, +/* 0xc980 */ { true, 0xc980, 0xc980 }, +/* 0xc981 */ { true, 0xc981, 0xc981 }, +/* 0xc982 */ { true, 0xc982, 0xc982 }, +/* 0xc983 */ { true, 0xc983, 0xc983 }, +/* 0xc984 */ { true, 0xc984, 0xc984 }, +/* 0xc985 */ { true, 0xc985, 0xc985 }, +/* 0xc986 */ { true, 0xc986, 0xc986 }, +/* 0xc987 */ { true, 0xc987, 0xc987 }, +/* 0xc988 */ { true, 0xc988, 0xc988 }, +/* 0xc989 */ { true, 0xc989, 0xc989 }, +/* 0xc98a */ { true, 0xc98a, 0xc98a }, +/* 0xc98b */ { true, 0xc98b, 0xc98b }, +/* 0xc98c */ { true, 0xc98c, 0xc98c }, +/* 0xc98d */ { true, 0xc98d, 0xc98d }, +/* 0xc98e */ { true, 0xc98e, 0xc98e }, +/* 0xc98f */ { true, 0xc98f, 0xc98f }, +/* 0xc990 */ { true, 0xc990, 0xc990 }, +/* 0xc991 */ { true, 0xc991, 0xc991 }, +/* 0xc992 */ { true, 0xc992, 0xc992 }, +/* 0xc993 */ { true, 0xc993, 0xc993 }, +/* 0xc994 */ { true, 0xc994, 0xc994 }, +/* 0xc995 */ { true, 0xc995, 0xc995 }, +/* 0xc996 */ { true, 0xc996, 0xc996 }, +/* 0xc997 */ { true, 0xc997, 0xc997 }, +/* 0xc998 */ { true, 0xc998, 0xc998 }, +/* 0xc999 */ { true, 0xc999, 0xc999 }, +/* 0xc99a */ { true, 0xc99a, 0xc99a }, +/* 0xc99b */ { true, 0xc99b, 0xc99b }, +/* 0xc99c */ { true, 0xc99c, 0xc99c }, +/* 0xc99d */ { true, 0xc99d, 0xc99d }, +/* 0xc99e */ { true, 0xc99e, 0xc99e }, +/* 0xc99f */ { true, 0xc99f, 0xc99f }, +/* 0xc9a0 */ { true, 0xc9a0, 0xc9a0 }, +/* 0xc9a1 */ { true, 0xc9a1, 0xc9a1 }, +/* 0xc9a2 */ { true, 0xc9a2, 0xc9a2 }, +/* 0xc9a3 */ { true, 0xc9a3, 0xc9a3 }, +/* 0xc9a4 */ { true, 0xc9a4, 0xc9a4 }, +/* 0xc9a5 */ { true, 0xc9a5, 0xc9a5 }, +/* 0xc9a6 */ { true, 0xc9a6, 0xc9a6 }, +/* 0xc9a7 */ { true, 0xc9a7, 0xc9a7 }, +/* 0xc9a8 */ { true, 0xc9a8, 0xc9a8 }, +/* 0xc9a9 */ { true, 0xc9a9, 0xc9a9 }, +/* 0xc9aa */ { true, 0xc9aa, 0xc9aa }, +/* 0xc9ab */ { true, 0xc9ab, 0xc9ab }, +/* 0xc9ac */ { true, 0xc9ac, 0xc9ac }, +/* 0xc9ad */ { true, 0xc9ad, 0xc9ad }, +/* 0xc9ae */ { true, 0xc9ae, 0xc9ae }, +/* 0xc9af */ { true, 0xc9af, 0xc9af }, +/* 0xc9b0 */ { true, 0xc9b0, 0xc9b0 }, +/* 0xc9b1 */ { true, 0xc9b1, 0xc9b1 }, +/* 0xc9b2 */ { true, 0xc9b2, 0xc9b2 }, +/* 0xc9b3 */ { true, 0xc9b3, 0xc9b3 }, +/* 0xc9b4 */ { true, 0xc9b4, 0xc9b4 }, +/* 0xc9b5 */ { true, 0xc9b5, 0xc9b5 }, +/* 0xc9b6 */ { true, 0xc9b6, 0xc9b6 }, +/* 0xc9b7 */ { true, 0xc9b7, 0xc9b7 }, +/* 0xc9b8 */ { true, 0xc9b8, 0xc9b8 }, +/* 0xc9b9 */ { true, 0xc9b9, 0xc9b9 }, +/* 0xc9ba */ { true, 0xc9ba, 0xc9ba }, +/* 0xc9bb */ { true, 0xc9bb, 0xc9bb }, +/* 0xc9bc */ { true, 0xc9bc, 0xc9bc }, +/* 0xc9bd */ { true, 0xc9bd, 0xc9bd }, +/* 0xc9be */ { true, 0xc9be, 0xc9be }, +/* 0xc9bf */ { true, 0xc9bf, 0xc9bf }, +/* 0xc9c0 */ { true, 0xc9c0, 0xc9c0 }, +/* 0xc9c1 */ { true, 0xc9c1, 0xc9c1 }, +/* 0xc9c2 */ { true, 0xc9c2, 0xc9c2 }, +/* 0xc9c3 */ { true, 0xc9c3, 0xc9c3 }, +/* 0xc9c4 */ { true, 0xc9c4, 0xc9c4 }, +/* 0xc9c5 */ { true, 0xc9c5, 0xc9c5 }, +/* 0xc9c6 */ { true, 0xc9c6, 0xc9c6 }, +/* 0xc9c7 */ { true, 0xc9c7, 0xc9c7 }, +/* 0xc9c8 */ { true, 0xc9c8, 0xc9c8 }, +/* 0xc9c9 */ { true, 0xc9c9, 0xc9c9 }, +/* 0xc9ca */ { true, 0xc9ca, 0xc9ca }, +/* 0xc9cb */ { true, 0xc9cb, 0xc9cb }, +/* 0xc9cc */ { true, 0xc9cc, 0xc9cc }, +/* 0xc9cd */ { true, 0xc9cd, 0xc9cd }, +/* 0xc9ce */ { true, 0xc9ce, 0xc9ce }, +/* 0xc9cf */ { true, 0xc9cf, 0xc9cf }, +/* 0xc9d0 */ { true, 0xc9d0, 0xc9d0 }, +/* 0xc9d1 */ { true, 0xc9d1, 0xc9d1 }, +/* 0xc9d2 */ { true, 0xc9d2, 0xc9d2 }, +/* 0xc9d3 */ { true, 0xc9d3, 0xc9d3 }, +/* 0xc9d4 */ { true, 0xc9d4, 0xc9d4 }, +/* 0xc9d5 */ { true, 0xc9d5, 0xc9d5 }, +/* 0xc9d6 */ { true, 0xc9d6, 0xc9d6 }, +/* 0xc9d7 */ { true, 0xc9d7, 0xc9d7 }, +/* 0xc9d8 */ { true, 0xc9d8, 0xc9d8 }, +/* 0xc9d9 */ { true, 0xc9d9, 0xc9d9 }, +/* 0xc9da */ { true, 0xc9da, 0xc9da }, +/* 0xc9db */ { true, 0xc9db, 0xc9db }, +/* 0xc9dc */ { true, 0xc9dc, 0xc9dc }, +/* 0xc9dd */ { true, 0xc9dd, 0xc9dd }, +/* 0xc9de */ { true, 0xc9de, 0xc9de }, +/* 0xc9df */ { true, 0xc9df, 0xc9df }, +/* 0xc9e0 */ { true, 0xc9e0, 0xc9e0 }, +/* 0xc9e1 */ { true, 0xc9e1, 0xc9e1 }, +/* 0xc9e2 */ { true, 0xc9e2, 0xc9e2 }, +/* 0xc9e3 */ { true, 0xc9e3, 0xc9e3 }, +/* 0xc9e4 */ { true, 0xc9e4, 0xc9e4 }, +/* 0xc9e5 */ { true, 0xc9e5, 0xc9e5 }, +/* 0xc9e6 */ { true, 0xc9e6, 0xc9e6 }, +/* 0xc9e7 */ { true, 0xc9e7, 0xc9e7 }, +/* 0xc9e8 */ { true, 0xc9e8, 0xc9e8 }, +/* 0xc9e9 */ { true, 0xc9e9, 0xc9e9 }, +/* 0xc9ea */ { true, 0xc9ea, 0xc9ea }, +/* 0xc9eb */ { true, 0xc9eb, 0xc9eb }, +/* 0xc9ec */ { true, 0xc9ec, 0xc9ec }, +/* 0xc9ed */ { true, 0xc9ed, 0xc9ed }, +/* 0xc9ee */ { true, 0xc9ee, 0xc9ee }, +/* 0xc9ef */ { true, 0xc9ef, 0xc9ef }, +/* 0xc9f0 */ { true, 0xc9f0, 0xc9f0 }, +/* 0xc9f1 */ { true, 0xc9f1, 0xc9f1 }, +/* 0xc9f2 */ { true, 0xc9f2, 0xc9f2 }, +/* 0xc9f3 */ { true, 0xc9f3, 0xc9f3 }, +/* 0xc9f4 */ { true, 0xc9f4, 0xc9f4 }, +/* 0xc9f5 */ { true, 0xc9f5, 0xc9f5 }, +/* 0xc9f6 */ { true, 0xc9f6, 0xc9f6 }, +/* 0xc9f7 */ { true, 0xc9f7, 0xc9f7 }, +/* 0xc9f8 */ { true, 0xc9f8, 0xc9f8 }, +/* 0xc9f9 */ { true, 0xc9f9, 0xc9f9 }, +/* 0xc9fa */ { true, 0xc9fa, 0xc9fa }, +/* 0xc9fb */ { true, 0xc9fb, 0xc9fb }, +/* 0xc9fc */ { true, 0xc9fc, 0xc9fc }, +/* 0xc9fd */ { true, 0xc9fd, 0xc9fd }, +/* 0xc9fe */ { true, 0xc9fe, 0xc9fe }, +/* 0xc9ff */ { true, 0xc9ff, 0xc9ff }, +/* 0xca00 */ { true, 0xca00, 0xca00 }, +/* 0xca01 */ { true, 0xca01, 0xca01 }, +/* 0xca02 */ { true, 0xca02, 0xca02 }, +/* 0xca03 */ { true, 0xca03, 0xca03 }, +/* 0xca04 */ { true, 0xca04, 0xca04 }, +/* 0xca05 */ { true, 0xca05, 0xca05 }, +/* 0xca06 */ { true, 0xca06, 0xca06 }, +/* 0xca07 */ { true, 0xca07, 0xca07 }, +/* 0xca08 */ { true, 0xca08, 0xca08 }, +/* 0xca09 */ { true, 0xca09, 0xca09 }, +/* 0xca0a */ { true, 0xca0a, 0xca0a }, +/* 0xca0b */ { true, 0xca0b, 0xca0b }, +/* 0xca0c */ { true, 0xca0c, 0xca0c }, +/* 0xca0d */ { true, 0xca0d, 0xca0d }, +/* 0xca0e */ { true, 0xca0e, 0xca0e }, +/* 0xca0f */ { true, 0xca0f, 0xca0f }, +/* 0xca10 */ { true, 0xca10, 0xca10 }, +/* 0xca11 */ { true, 0xca11, 0xca11 }, +/* 0xca12 */ { true, 0xca12, 0xca12 }, +/* 0xca13 */ { true, 0xca13, 0xca13 }, +/* 0xca14 */ { true, 0xca14, 0xca14 }, +/* 0xca15 */ { true, 0xca15, 0xca15 }, +/* 0xca16 */ { true, 0xca16, 0xca16 }, +/* 0xca17 */ { true, 0xca17, 0xca17 }, +/* 0xca18 */ { true, 0xca18, 0xca18 }, +/* 0xca19 */ { true, 0xca19, 0xca19 }, +/* 0xca1a */ { true, 0xca1a, 0xca1a }, +/* 0xca1b */ { true, 0xca1b, 0xca1b }, +/* 0xca1c */ { true, 0xca1c, 0xca1c }, +/* 0xca1d */ { true, 0xca1d, 0xca1d }, +/* 0xca1e */ { true, 0xca1e, 0xca1e }, +/* 0xca1f */ { true, 0xca1f, 0xca1f }, +/* 0xca20 */ { true, 0xca20, 0xca20 }, +/* 0xca21 */ { true, 0xca21, 0xca21 }, +/* 0xca22 */ { true, 0xca22, 0xca22 }, +/* 0xca23 */ { true, 0xca23, 0xca23 }, +/* 0xca24 */ { true, 0xca24, 0xca24 }, +/* 0xca25 */ { true, 0xca25, 0xca25 }, +/* 0xca26 */ { true, 0xca26, 0xca26 }, +/* 0xca27 */ { true, 0xca27, 0xca27 }, +/* 0xca28 */ { true, 0xca28, 0xca28 }, +/* 0xca29 */ { true, 0xca29, 0xca29 }, +/* 0xca2a */ { true, 0xca2a, 0xca2a }, +/* 0xca2b */ { true, 0xca2b, 0xca2b }, +/* 0xca2c */ { true, 0xca2c, 0xca2c }, +/* 0xca2d */ { true, 0xca2d, 0xca2d }, +/* 0xca2e */ { true, 0xca2e, 0xca2e }, +/* 0xca2f */ { true, 0xca2f, 0xca2f }, +/* 0xca30 */ { true, 0xca30, 0xca30 }, +/* 0xca31 */ { true, 0xca31, 0xca31 }, +/* 0xca32 */ { true, 0xca32, 0xca32 }, +/* 0xca33 */ { true, 0xca33, 0xca33 }, +/* 0xca34 */ { true, 0xca34, 0xca34 }, +/* 0xca35 */ { true, 0xca35, 0xca35 }, +/* 0xca36 */ { true, 0xca36, 0xca36 }, +/* 0xca37 */ { true, 0xca37, 0xca37 }, +/* 0xca38 */ { true, 0xca38, 0xca38 }, +/* 0xca39 */ { true, 0xca39, 0xca39 }, +/* 0xca3a */ { true, 0xca3a, 0xca3a }, +/* 0xca3b */ { true, 0xca3b, 0xca3b }, +/* 0xca3c */ { true, 0xca3c, 0xca3c }, +/* 0xca3d */ { true, 0xca3d, 0xca3d }, +/* 0xca3e */ { true, 0xca3e, 0xca3e }, +/* 0xca3f */ { true, 0xca3f, 0xca3f }, +/* 0xca40 */ { true, 0xca40, 0xca40 }, +/* 0xca41 */ { true, 0xca41, 0xca41 }, +/* 0xca42 */ { true, 0xca42, 0xca42 }, +/* 0xca43 */ { true, 0xca43, 0xca43 }, +/* 0xca44 */ { true, 0xca44, 0xca44 }, +/* 0xca45 */ { true, 0xca45, 0xca45 }, +/* 0xca46 */ { true, 0xca46, 0xca46 }, +/* 0xca47 */ { true, 0xca47, 0xca47 }, +/* 0xca48 */ { true, 0xca48, 0xca48 }, +/* 0xca49 */ { true, 0xca49, 0xca49 }, +/* 0xca4a */ { true, 0xca4a, 0xca4a }, +/* 0xca4b */ { true, 0xca4b, 0xca4b }, +/* 0xca4c */ { true, 0xca4c, 0xca4c }, +/* 0xca4d */ { true, 0xca4d, 0xca4d }, +/* 0xca4e */ { true, 0xca4e, 0xca4e }, +/* 0xca4f */ { true, 0xca4f, 0xca4f }, +/* 0xca50 */ { true, 0xca50, 0xca50 }, +/* 0xca51 */ { true, 0xca51, 0xca51 }, +/* 0xca52 */ { true, 0xca52, 0xca52 }, +/* 0xca53 */ { true, 0xca53, 0xca53 }, +/* 0xca54 */ { true, 0xca54, 0xca54 }, +/* 0xca55 */ { true, 0xca55, 0xca55 }, +/* 0xca56 */ { true, 0xca56, 0xca56 }, +/* 0xca57 */ { true, 0xca57, 0xca57 }, +/* 0xca58 */ { true, 0xca58, 0xca58 }, +/* 0xca59 */ { true, 0xca59, 0xca59 }, +/* 0xca5a */ { true, 0xca5a, 0xca5a }, +/* 0xca5b */ { true, 0xca5b, 0xca5b }, +/* 0xca5c */ { true, 0xca5c, 0xca5c }, +/* 0xca5d */ { true, 0xca5d, 0xca5d }, +/* 0xca5e */ { true, 0xca5e, 0xca5e }, +/* 0xca5f */ { true, 0xca5f, 0xca5f }, +/* 0xca60 */ { true, 0xca60, 0xca60 }, +/* 0xca61 */ { true, 0xca61, 0xca61 }, +/* 0xca62 */ { true, 0xca62, 0xca62 }, +/* 0xca63 */ { true, 0xca63, 0xca63 }, +/* 0xca64 */ { true, 0xca64, 0xca64 }, +/* 0xca65 */ { true, 0xca65, 0xca65 }, +/* 0xca66 */ { true, 0xca66, 0xca66 }, +/* 0xca67 */ { true, 0xca67, 0xca67 }, +/* 0xca68 */ { true, 0xca68, 0xca68 }, +/* 0xca69 */ { true, 0xca69, 0xca69 }, +/* 0xca6a */ { true, 0xca6a, 0xca6a }, +/* 0xca6b */ { true, 0xca6b, 0xca6b }, +/* 0xca6c */ { true, 0xca6c, 0xca6c }, +/* 0xca6d */ { true, 0xca6d, 0xca6d }, +/* 0xca6e */ { true, 0xca6e, 0xca6e }, +/* 0xca6f */ { true, 0xca6f, 0xca6f }, +/* 0xca70 */ { true, 0xca70, 0xca70 }, +/* 0xca71 */ { true, 0xca71, 0xca71 }, +/* 0xca72 */ { true, 0xca72, 0xca72 }, +/* 0xca73 */ { true, 0xca73, 0xca73 }, +/* 0xca74 */ { true, 0xca74, 0xca74 }, +/* 0xca75 */ { true, 0xca75, 0xca75 }, +/* 0xca76 */ { true, 0xca76, 0xca76 }, +/* 0xca77 */ { true, 0xca77, 0xca77 }, +/* 0xca78 */ { true, 0xca78, 0xca78 }, +/* 0xca79 */ { true, 0xca79, 0xca79 }, +/* 0xca7a */ { true, 0xca7a, 0xca7a }, +/* 0xca7b */ { true, 0xca7b, 0xca7b }, +/* 0xca7c */ { true, 0xca7c, 0xca7c }, +/* 0xca7d */ { true, 0xca7d, 0xca7d }, +/* 0xca7e */ { true, 0xca7e, 0xca7e }, +/* 0xca7f */ { true, 0xca7f, 0xca7f }, +/* 0xca80 */ { true, 0xca80, 0xca80 }, +/* 0xca81 */ { true, 0xca81, 0xca81 }, +/* 0xca82 */ { true, 0xca82, 0xca82 }, +/* 0xca83 */ { true, 0xca83, 0xca83 }, +/* 0xca84 */ { true, 0xca84, 0xca84 }, +/* 0xca85 */ { true, 0xca85, 0xca85 }, +/* 0xca86 */ { true, 0xca86, 0xca86 }, +/* 0xca87 */ { true, 0xca87, 0xca87 }, +/* 0xca88 */ { true, 0xca88, 0xca88 }, +/* 0xca89 */ { true, 0xca89, 0xca89 }, +/* 0xca8a */ { true, 0xca8a, 0xca8a }, +/* 0xca8b */ { true, 0xca8b, 0xca8b }, +/* 0xca8c */ { true, 0xca8c, 0xca8c }, +/* 0xca8d */ { true, 0xca8d, 0xca8d }, +/* 0xca8e */ { true, 0xca8e, 0xca8e }, +/* 0xca8f */ { true, 0xca8f, 0xca8f }, +/* 0xca90 */ { true, 0xca90, 0xca90 }, +/* 0xca91 */ { true, 0xca91, 0xca91 }, +/* 0xca92 */ { true, 0xca92, 0xca92 }, +/* 0xca93 */ { true, 0xca93, 0xca93 }, +/* 0xca94 */ { true, 0xca94, 0xca94 }, +/* 0xca95 */ { true, 0xca95, 0xca95 }, +/* 0xca96 */ { true, 0xca96, 0xca96 }, +/* 0xca97 */ { true, 0xca97, 0xca97 }, +/* 0xca98 */ { true, 0xca98, 0xca98 }, +/* 0xca99 */ { true, 0xca99, 0xca99 }, +/* 0xca9a */ { true, 0xca9a, 0xca9a }, +/* 0xca9b */ { true, 0xca9b, 0xca9b }, +/* 0xca9c */ { true, 0xca9c, 0xca9c }, +/* 0xca9d */ { true, 0xca9d, 0xca9d }, +/* 0xca9e */ { true, 0xca9e, 0xca9e }, +/* 0xca9f */ { true, 0xca9f, 0xca9f }, +/* 0xcaa0 */ { true, 0xcaa0, 0xcaa0 }, +/* 0xcaa1 */ { true, 0xcaa1, 0xcaa1 }, +/* 0xcaa2 */ { true, 0xcaa2, 0xcaa2 }, +/* 0xcaa3 */ { true, 0xcaa3, 0xcaa3 }, +/* 0xcaa4 */ { true, 0xcaa4, 0xcaa4 }, +/* 0xcaa5 */ { true, 0xcaa5, 0xcaa5 }, +/* 0xcaa6 */ { true, 0xcaa6, 0xcaa6 }, +/* 0xcaa7 */ { true, 0xcaa7, 0xcaa7 }, +/* 0xcaa8 */ { true, 0xcaa8, 0xcaa8 }, +/* 0xcaa9 */ { true, 0xcaa9, 0xcaa9 }, +/* 0xcaaa */ { true, 0xcaaa, 0xcaaa }, +/* 0xcaab */ { true, 0xcaab, 0xcaab }, +/* 0xcaac */ { true, 0xcaac, 0xcaac }, +/* 0xcaad */ { true, 0xcaad, 0xcaad }, +/* 0xcaae */ { true, 0xcaae, 0xcaae }, +/* 0xcaaf */ { true, 0xcaaf, 0xcaaf }, +/* 0xcab0 */ { true, 0xcab0, 0xcab0 }, +/* 0xcab1 */ { true, 0xcab1, 0xcab1 }, +/* 0xcab2 */ { true, 0xcab2, 0xcab2 }, +/* 0xcab3 */ { true, 0xcab3, 0xcab3 }, +/* 0xcab4 */ { true, 0xcab4, 0xcab4 }, +/* 0xcab5 */ { true, 0xcab5, 0xcab5 }, +/* 0xcab6 */ { true, 0xcab6, 0xcab6 }, +/* 0xcab7 */ { true, 0xcab7, 0xcab7 }, +/* 0xcab8 */ { true, 0xcab8, 0xcab8 }, +/* 0xcab9 */ { true, 0xcab9, 0xcab9 }, +/* 0xcaba */ { true, 0xcaba, 0xcaba }, +/* 0xcabb */ { true, 0xcabb, 0xcabb }, +/* 0xcabc */ { true, 0xcabc, 0xcabc }, +/* 0xcabd */ { true, 0xcabd, 0xcabd }, +/* 0xcabe */ { true, 0xcabe, 0xcabe }, +/* 0xcabf */ { true, 0xcabf, 0xcabf }, +/* 0xcac0 */ { true, 0xcac0, 0xcac0 }, +/* 0xcac1 */ { true, 0xcac1, 0xcac1 }, +/* 0xcac2 */ { true, 0xcac2, 0xcac2 }, +/* 0xcac3 */ { true, 0xcac3, 0xcac3 }, +/* 0xcac4 */ { true, 0xcac4, 0xcac4 }, +/* 0xcac5 */ { true, 0xcac5, 0xcac5 }, +/* 0xcac6 */ { true, 0xcac6, 0xcac6 }, +/* 0xcac7 */ { true, 0xcac7, 0xcac7 }, +/* 0xcac8 */ { true, 0xcac8, 0xcac8 }, +/* 0xcac9 */ { true, 0xcac9, 0xcac9 }, +/* 0xcaca */ { true, 0xcaca, 0xcaca }, +/* 0xcacb */ { true, 0xcacb, 0xcacb }, +/* 0xcacc */ { true, 0xcacc, 0xcacc }, +/* 0xcacd */ { true, 0xcacd, 0xcacd }, +/* 0xcace */ { true, 0xcace, 0xcace }, +/* 0xcacf */ { true, 0xcacf, 0xcacf }, +/* 0xcad0 */ { true, 0xcad0, 0xcad0 }, +/* 0xcad1 */ { true, 0xcad1, 0xcad1 }, +/* 0xcad2 */ { true, 0xcad2, 0xcad2 }, +/* 0xcad3 */ { true, 0xcad3, 0xcad3 }, +/* 0xcad4 */ { true, 0xcad4, 0xcad4 }, +/* 0xcad5 */ { true, 0xcad5, 0xcad5 }, +/* 0xcad6 */ { true, 0xcad6, 0xcad6 }, +/* 0xcad7 */ { true, 0xcad7, 0xcad7 }, +/* 0xcad8 */ { true, 0xcad8, 0xcad8 }, +/* 0xcad9 */ { true, 0xcad9, 0xcad9 }, +/* 0xcada */ { true, 0xcada, 0xcada }, +/* 0xcadb */ { true, 0xcadb, 0xcadb }, +/* 0xcadc */ { true, 0xcadc, 0xcadc }, +/* 0xcadd */ { true, 0xcadd, 0xcadd }, +/* 0xcade */ { true, 0xcade, 0xcade }, +/* 0xcadf */ { true, 0xcadf, 0xcadf }, +/* 0xcae0 */ { true, 0xcae0, 0xcae0 }, +/* 0xcae1 */ { true, 0xcae1, 0xcae1 }, +/* 0xcae2 */ { true, 0xcae2, 0xcae2 }, +/* 0xcae3 */ { true, 0xcae3, 0xcae3 }, +/* 0xcae4 */ { true, 0xcae4, 0xcae4 }, +/* 0xcae5 */ { true, 0xcae5, 0xcae5 }, +/* 0xcae6 */ { true, 0xcae6, 0xcae6 }, +/* 0xcae7 */ { true, 0xcae7, 0xcae7 }, +/* 0xcae8 */ { true, 0xcae8, 0xcae8 }, +/* 0xcae9 */ { true, 0xcae9, 0xcae9 }, +/* 0xcaea */ { true, 0xcaea, 0xcaea }, +/* 0xcaeb */ { true, 0xcaeb, 0xcaeb }, +/* 0xcaec */ { true, 0xcaec, 0xcaec }, +/* 0xcaed */ { true, 0xcaed, 0xcaed }, +/* 0xcaee */ { true, 0xcaee, 0xcaee }, +/* 0xcaef */ { true, 0xcaef, 0xcaef }, +/* 0xcaf0 */ { true, 0xcaf0, 0xcaf0 }, +/* 0xcaf1 */ { true, 0xcaf1, 0xcaf1 }, +/* 0xcaf2 */ { true, 0xcaf2, 0xcaf2 }, +/* 0xcaf3 */ { true, 0xcaf3, 0xcaf3 }, +/* 0xcaf4 */ { true, 0xcaf4, 0xcaf4 }, +/* 0xcaf5 */ { true, 0xcaf5, 0xcaf5 }, +/* 0xcaf6 */ { true, 0xcaf6, 0xcaf6 }, +/* 0xcaf7 */ { true, 0xcaf7, 0xcaf7 }, +/* 0xcaf8 */ { true, 0xcaf8, 0xcaf8 }, +/* 0xcaf9 */ { true, 0xcaf9, 0xcaf9 }, +/* 0xcafa */ { true, 0xcafa, 0xcafa }, +/* 0xcafb */ { true, 0xcafb, 0xcafb }, +/* 0xcafc */ { true, 0xcafc, 0xcafc }, +/* 0xcafd */ { true, 0xcafd, 0xcafd }, +/* 0xcafe */ { true, 0xcafe, 0xcafe }, +/* 0xcaff */ { true, 0xcaff, 0xcaff }, +/* 0xcb00 */ { true, 0xcb00, 0xcb00 }, +/* 0xcb01 */ { true, 0xcb01, 0xcb01 }, +/* 0xcb02 */ { true, 0xcb02, 0xcb02 }, +/* 0xcb03 */ { true, 0xcb03, 0xcb03 }, +/* 0xcb04 */ { true, 0xcb04, 0xcb04 }, +/* 0xcb05 */ { true, 0xcb05, 0xcb05 }, +/* 0xcb06 */ { true, 0xcb06, 0xcb06 }, +/* 0xcb07 */ { true, 0xcb07, 0xcb07 }, +/* 0xcb08 */ { true, 0xcb08, 0xcb08 }, +/* 0xcb09 */ { true, 0xcb09, 0xcb09 }, +/* 0xcb0a */ { true, 0xcb0a, 0xcb0a }, +/* 0xcb0b */ { true, 0xcb0b, 0xcb0b }, +/* 0xcb0c */ { true, 0xcb0c, 0xcb0c }, +/* 0xcb0d */ { true, 0xcb0d, 0xcb0d }, +/* 0xcb0e */ { true, 0xcb0e, 0xcb0e }, +/* 0xcb0f */ { true, 0xcb0f, 0xcb0f }, +/* 0xcb10 */ { true, 0xcb10, 0xcb10 }, +/* 0xcb11 */ { true, 0xcb11, 0xcb11 }, +/* 0xcb12 */ { true, 0xcb12, 0xcb12 }, +/* 0xcb13 */ { true, 0xcb13, 0xcb13 }, +/* 0xcb14 */ { true, 0xcb14, 0xcb14 }, +/* 0xcb15 */ { true, 0xcb15, 0xcb15 }, +/* 0xcb16 */ { true, 0xcb16, 0xcb16 }, +/* 0xcb17 */ { true, 0xcb17, 0xcb17 }, +/* 0xcb18 */ { true, 0xcb18, 0xcb18 }, +/* 0xcb19 */ { true, 0xcb19, 0xcb19 }, +/* 0xcb1a */ { true, 0xcb1a, 0xcb1a }, +/* 0xcb1b */ { true, 0xcb1b, 0xcb1b }, +/* 0xcb1c */ { true, 0xcb1c, 0xcb1c }, +/* 0xcb1d */ { true, 0xcb1d, 0xcb1d }, +/* 0xcb1e */ { true, 0xcb1e, 0xcb1e }, +/* 0xcb1f */ { true, 0xcb1f, 0xcb1f }, +/* 0xcb20 */ { true, 0xcb20, 0xcb20 }, +/* 0xcb21 */ { true, 0xcb21, 0xcb21 }, +/* 0xcb22 */ { true, 0xcb22, 0xcb22 }, +/* 0xcb23 */ { true, 0xcb23, 0xcb23 }, +/* 0xcb24 */ { true, 0xcb24, 0xcb24 }, +/* 0xcb25 */ { true, 0xcb25, 0xcb25 }, +/* 0xcb26 */ { true, 0xcb26, 0xcb26 }, +/* 0xcb27 */ { true, 0xcb27, 0xcb27 }, +/* 0xcb28 */ { true, 0xcb28, 0xcb28 }, +/* 0xcb29 */ { true, 0xcb29, 0xcb29 }, +/* 0xcb2a */ { true, 0xcb2a, 0xcb2a }, +/* 0xcb2b */ { true, 0xcb2b, 0xcb2b }, +/* 0xcb2c */ { true, 0xcb2c, 0xcb2c }, +/* 0xcb2d */ { true, 0xcb2d, 0xcb2d }, +/* 0xcb2e */ { true, 0xcb2e, 0xcb2e }, +/* 0xcb2f */ { true, 0xcb2f, 0xcb2f }, +/* 0xcb30 */ { true, 0xcb30, 0xcb30 }, +/* 0xcb31 */ { true, 0xcb31, 0xcb31 }, +/* 0xcb32 */ { true, 0xcb32, 0xcb32 }, +/* 0xcb33 */ { true, 0xcb33, 0xcb33 }, +/* 0xcb34 */ { true, 0xcb34, 0xcb34 }, +/* 0xcb35 */ { true, 0xcb35, 0xcb35 }, +/* 0xcb36 */ { true, 0xcb36, 0xcb36 }, +/* 0xcb37 */ { true, 0xcb37, 0xcb37 }, +/* 0xcb38 */ { true, 0xcb38, 0xcb38 }, +/* 0xcb39 */ { true, 0xcb39, 0xcb39 }, +/* 0xcb3a */ { true, 0xcb3a, 0xcb3a }, +/* 0xcb3b */ { true, 0xcb3b, 0xcb3b }, +/* 0xcb3c */ { true, 0xcb3c, 0xcb3c }, +/* 0xcb3d */ { true, 0xcb3d, 0xcb3d }, +/* 0xcb3e */ { true, 0xcb3e, 0xcb3e }, +/* 0xcb3f */ { true, 0xcb3f, 0xcb3f }, +/* 0xcb40 */ { true, 0xcb40, 0xcb40 }, +/* 0xcb41 */ { true, 0xcb41, 0xcb41 }, +/* 0xcb42 */ { true, 0xcb42, 0xcb42 }, +/* 0xcb43 */ { true, 0xcb43, 0xcb43 }, +/* 0xcb44 */ { true, 0xcb44, 0xcb44 }, +/* 0xcb45 */ { true, 0xcb45, 0xcb45 }, +/* 0xcb46 */ { true, 0xcb46, 0xcb46 }, +/* 0xcb47 */ { true, 0xcb47, 0xcb47 }, +/* 0xcb48 */ { true, 0xcb48, 0xcb48 }, +/* 0xcb49 */ { true, 0xcb49, 0xcb49 }, +/* 0xcb4a */ { true, 0xcb4a, 0xcb4a }, +/* 0xcb4b */ { true, 0xcb4b, 0xcb4b }, +/* 0xcb4c */ { true, 0xcb4c, 0xcb4c }, +/* 0xcb4d */ { true, 0xcb4d, 0xcb4d }, +/* 0xcb4e */ { true, 0xcb4e, 0xcb4e }, +/* 0xcb4f */ { true, 0xcb4f, 0xcb4f }, +/* 0xcb50 */ { true, 0xcb50, 0xcb50 }, +/* 0xcb51 */ { true, 0xcb51, 0xcb51 }, +/* 0xcb52 */ { true, 0xcb52, 0xcb52 }, +/* 0xcb53 */ { true, 0xcb53, 0xcb53 }, +/* 0xcb54 */ { true, 0xcb54, 0xcb54 }, +/* 0xcb55 */ { true, 0xcb55, 0xcb55 }, +/* 0xcb56 */ { true, 0xcb56, 0xcb56 }, +/* 0xcb57 */ { true, 0xcb57, 0xcb57 }, +/* 0xcb58 */ { true, 0xcb58, 0xcb58 }, +/* 0xcb59 */ { true, 0xcb59, 0xcb59 }, +/* 0xcb5a */ { true, 0xcb5a, 0xcb5a }, +/* 0xcb5b */ { true, 0xcb5b, 0xcb5b }, +/* 0xcb5c */ { true, 0xcb5c, 0xcb5c }, +/* 0xcb5d */ { true, 0xcb5d, 0xcb5d }, +/* 0xcb5e */ { true, 0xcb5e, 0xcb5e }, +/* 0xcb5f */ { true, 0xcb5f, 0xcb5f }, +/* 0xcb60 */ { true, 0xcb60, 0xcb60 }, +/* 0xcb61 */ { true, 0xcb61, 0xcb61 }, +/* 0xcb62 */ { true, 0xcb62, 0xcb62 }, +/* 0xcb63 */ { true, 0xcb63, 0xcb63 }, +/* 0xcb64 */ { true, 0xcb64, 0xcb64 }, +/* 0xcb65 */ { true, 0xcb65, 0xcb65 }, +/* 0xcb66 */ { true, 0xcb66, 0xcb66 }, +/* 0xcb67 */ { true, 0xcb67, 0xcb67 }, +/* 0xcb68 */ { true, 0xcb68, 0xcb68 }, +/* 0xcb69 */ { true, 0xcb69, 0xcb69 }, +/* 0xcb6a */ { true, 0xcb6a, 0xcb6a }, +/* 0xcb6b */ { true, 0xcb6b, 0xcb6b }, +/* 0xcb6c */ { true, 0xcb6c, 0xcb6c }, +/* 0xcb6d */ { true, 0xcb6d, 0xcb6d }, +/* 0xcb6e */ { true, 0xcb6e, 0xcb6e }, +/* 0xcb6f */ { true, 0xcb6f, 0xcb6f }, +/* 0xcb70 */ { true, 0xcb70, 0xcb70 }, +/* 0xcb71 */ { true, 0xcb71, 0xcb71 }, +/* 0xcb72 */ { true, 0xcb72, 0xcb72 }, +/* 0xcb73 */ { true, 0xcb73, 0xcb73 }, +/* 0xcb74 */ { true, 0xcb74, 0xcb74 }, +/* 0xcb75 */ { true, 0xcb75, 0xcb75 }, +/* 0xcb76 */ { true, 0xcb76, 0xcb76 }, +/* 0xcb77 */ { true, 0xcb77, 0xcb77 }, +/* 0xcb78 */ { true, 0xcb78, 0xcb78 }, +/* 0xcb79 */ { true, 0xcb79, 0xcb79 }, +/* 0xcb7a */ { true, 0xcb7a, 0xcb7a }, +/* 0xcb7b */ { true, 0xcb7b, 0xcb7b }, +/* 0xcb7c */ { true, 0xcb7c, 0xcb7c }, +/* 0xcb7d */ { true, 0xcb7d, 0xcb7d }, +/* 0xcb7e */ { true, 0xcb7e, 0xcb7e }, +/* 0xcb7f */ { true, 0xcb7f, 0xcb7f }, +/* 0xcb80 */ { true, 0xcb80, 0xcb80 }, +/* 0xcb81 */ { true, 0xcb81, 0xcb81 }, +/* 0xcb82 */ { true, 0xcb82, 0xcb82 }, +/* 0xcb83 */ { true, 0xcb83, 0xcb83 }, +/* 0xcb84 */ { true, 0xcb84, 0xcb84 }, +/* 0xcb85 */ { true, 0xcb85, 0xcb85 }, +/* 0xcb86 */ { true, 0xcb86, 0xcb86 }, +/* 0xcb87 */ { true, 0xcb87, 0xcb87 }, +/* 0xcb88 */ { true, 0xcb88, 0xcb88 }, +/* 0xcb89 */ { true, 0xcb89, 0xcb89 }, +/* 0xcb8a */ { true, 0xcb8a, 0xcb8a }, +/* 0xcb8b */ { true, 0xcb8b, 0xcb8b }, +/* 0xcb8c */ { true, 0xcb8c, 0xcb8c }, +/* 0xcb8d */ { true, 0xcb8d, 0xcb8d }, +/* 0xcb8e */ { true, 0xcb8e, 0xcb8e }, +/* 0xcb8f */ { true, 0xcb8f, 0xcb8f }, +/* 0xcb90 */ { true, 0xcb90, 0xcb90 }, +/* 0xcb91 */ { true, 0xcb91, 0xcb91 }, +/* 0xcb92 */ { true, 0xcb92, 0xcb92 }, +/* 0xcb93 */ { true, 0xcb93, 0xcb93 }, +/* 0xcb94 */ { true, 0xcb94, 0xcb94 }, +/* 0xcb95 */ { true, 0xcb95, 0xcb95 }, +/* 0xcb96 */ { true, 0xcb96, 0xcb96 }, +/* 0xcb97 */ { true, 0xcb97, 0xcb97 }, +/* 0xcb98 */ { true, 0xcb98, 0xcb98 }, +/* 0xcb99 */ { true, 0xcb99, 0xcb99 }, +/* 0xcb9a */ { true, 0xcb9a, 0xcb9a }, +/* 0xcb9b */ { true, 0xcb9b, 0xcb9b }, +/* 0xcb9c */ { true, 0xcb9c, 0xcb9c }, +/* 0xcb9d */ { true, 0xcb9d, 0xcb9d }, +/* 0xcb9e */ { true, 0xcb9e, 0xcb9e }, +/* 0xcb9f */ { true, 0xcb9f, 0xcb9f }, +/* 0xcba0 */ { true, 0xcba0, 0xcba0 }, +/* 0xcba1 */ { true, 0xcba1, 0xcba1 }, +/* 0xcba2 */ { true, 0xcba2, 0xcba2 }, +/* 0xcba3 */ { true, 0xcba3, 0xcba3 }, +/* 0xcba4 */ { true, 0xcba4, 0xcba4 }, +/* 0xcba5 */ { true, 0xcba5, 0xcba5 }, +/* 0xcba6 */ { true, 0xcba6, 0xcba6 }, +/* 0xcba7 */ { true, 0xcba7, 0xcba7 }, +/* 0xcba8 */ { true, 0xcba8, 0xcba8 }, +/* 0xcba9 */ { true, 0xcba9, 0xcba9 }, +/* 0xcbaa */ { true, 0xcbaa, 0xcbaa }, +/* 0xcbab */ { true, 0xcbab, 0xcbab }, +/* 0xcbac */ { true, 0xcbac, 0xcbac }, +/* 0xcbad */ { true, 0xcbad, 0xcbad }, +/* 0xcbae */ { true, 0xcbae, 0xcbae }, +/* 0xcbaf */ { true, 0xcbaf, 0xcbaf }, +/* 0xcbb0 */ { true, 0xcbb0, 0xcbb0 }, +/* 0xcbb1 */ { true, 0xcbb1, 0xcbb1 }, +/* 0xcbb2 */ { true, 0xcbb2, 0xcbb2 }, +/* 0xcbb3 */ { true, 0xcbb3, 0xcbb3 }, +/* 0xcbb4 */ { true, 0xcbb4, 0xcbb4 }, +/* 0xcbb5 */ { true, 0xcbb5, 0xcbb5 }, +/* 0xcbb6 */ { true, 0xcbb6, 0xcbb6 }, +/* 0xcbb7 */ { true, 0xcbb7, 0xcbb7 }, +/* 0xcbb8 */ { true, 0xcbb8, 0xcbb8 }, +/* 0xcbb9 */ { true, 0xcbb9, 0xcbb9 }, +/* 0xcbba */ { true, 0xcbba, 0xcbba }, +/* 0xcbbb */ { true, 0xcbbb, 0xcbbb }, +/* 0xcbbc */ { true, 0xcbbc, 0xcbbc }, +/* 0xcbbd */ { true, 0xcbbd, 0xcbbd }, +/* 0xcbbe */ { true, 0xcbbe, 0xcbbe }, +/* 0xcbbf */ { true, 0xcbbf, 0xcbbf }, +/* 0xcbc0 */ { true, 0xcbc0, 0xcbc0 }, +/* 0xcbc1 */ { true, 0xcbc1, 0xcbc1 }, +/* 0xcbc2 */ { true, 0xcbc2, 0xcbc2 }, +/* 0xcbc3 */ { true, 0xcbc3, 0xcbc3 }, +/* 0xcbc4 */ { true, 0xcbc4, 0xcbc4 }, +/* 0xcbc5 */ { true, 0xcbc5, 0xcbc5 }, +/* 0xcbc6 */ { true, 0xcbc6, 0xcbc6 }, +/* 0xcbc7 */ { true, 0xcbc7, 0xcbc7 }, +/* 0xcbc8 */ { true, 0xcbc8, 0xcbc8 }, +/* 0xcbc9 */ { true, 0xcbc9, 0xcbc9 }, +/* 0xcbca */ { true, 0xcbca, 0xcbca }, +/* 0xcbcb */ { true, 0xcbcb, 0xcbcb }, +/* 0xcbcc */ { true, 0xcbcc, 0xcbcc }, +/* 0xcbcd */ { true, 0xcbcd, 0xcbcd }, +/* 0xcbce */ { true, 0xcbce, 0xcbce }, +/* 0xcbcf */ { true, 0xcbcf, 0xcbcf }, +/* 0xcbd0 */ { true, 0xcbd0, 0xcbd0 }, +/* 0xcbd1 */ { true, 0xcbd1, 0xcbd1 }, +/* 0xcbd2 */ { true, 0xcbd2, 0xcbd2 }, +/* 0xcbd3 */ { true, 0xcbd3, 0xcbd3 }, +/* 0xcbd4 */ { true, 0xcbd4, 0xcbd4 }, +/* 0xcbd5 */ { true, 0xcbd5, 0xcbd5 }, +/* 0xcbd6 */ { true, 0xcbd6, 0xcbd6 }, +/* 0xcbd7 */ { true, 0xcbd7, 0xcbd7 }, +/* 0xcbd8 */ { true, 0xcbd8, 0xcbd8 }, +/* 0xcbd9 */ { true, 0xcbd9, 0xcbd9 }, +/* 0xcbda */ { true, 0xcbda, 0xcbda }, +/* 0xcbdb */ { true, 0xcbdb, 0xcbdb }, +/* 0xcbdc */ { true, 0xcbdc, 0xcbdc }, +/* 0xcbdd */ { true, 0xcbdd, 0xcbdd }, +/* 0xcbde */ { true, 0xcbde, 0xcbde }, +/* 0xcbdf */ { true, 0xcbdf, 0xcbdf }, +/* 0xcbe0 */ { true, 0xcbe0, 0xcbe0 }, +/* 0xcbe1 */ { true, 0xcbe1, 0xcbe1 }, +/* 0xcbe2 */ { true, 0xcbe2, 0xcbe2 }, +/* 0xcbe3 */ { true, 0xcbe3, 0xcbe3 }, +/* 0xcbe4 */ { true, 0xcbe4, 0xcbe4 }, +/* 0xcbe5 */ { true, 0xcbe5, 0xcbe5 }, +/* 0xcbe6 */ { true, 0xcbe6, 0xcbe6 }, +/* 0xcbe7 */ { true, 0xcbe7, 0xcbe7 }, +/* 0xcbe8 */ { true, 0xcbe8, 0xcbe8 }, +/* 0xcbe9 */ { true, 0xcbe9, 0xcbe9 }, +/* 0xcbea */ { true, 0xcbea, 0xcbea }, +/* 0xcbeb */ { true, 0xcbeb, 0xcbeb }, +/* 0xcbec */ { true, 0xcbec, 0xcbec }, +/* 0xcbed */ { true, 0xcbed, 0xcbed }, +/* 0xcbee */ { true, 0xcbee, 0xcbee }, +/* 0xcbef */ { true, 0xcbef, 0xcbef }, +/* 0xcbf0 */ { true, 0xcbf0, 0xcbf0 }, +/* 0xcbf1 */ { true, 0xcbf1, 0xcbf1 }, +/* 0xcbf2 */ { true, 0xcbf2, 0xcbf2 }, +/* 0xcbf3 */ { true, 0xcbf3, 0xcbf3 }, +/* 0xcbf4 */ { true, 0xcbf4, 0xcbf4 }, +/* 0xcbf5 */ { true, 0xcbf5, 0xcbf5 }, +/* 0xcbf6 */ { true, 0xcbf6, 0xcbf6 }, +/* 0xcbf7 */ { true, 0xcbf7, 0xcbf7 }, +/* 0xcbf8 */ { true, 0xcbf8, 0xcbf8 }, +/* 0xcbf9 */ { true, 0xcbf9, 0xcbf9 }, +/* 0xcbfa */ { true, 0xcbfa, 0xcbfa }, +/* 0xcbfb */ { true, 0xcbfb, 0xcbfb }, +/* 0xcbfc */ { true, 0xcbfc, 0xcbfc }, +/* 0xcbfd */ { true, 0xcbfd, 0xcbfd }, +/* 0xcbfe */ { true, 0xcbfe, 0xcbfe }, +/* 0xcbff */ { true, 0xcbff, 0xcbff }, +/* 0xcc00 */ { true, 0xcc00, 0xcc00 }, +/* 0xcc01 */ { true, 0xcc01, 0xcc01 }, +/* 0xcc02 */ { true, 0xcc02, 0xcc02 }, +/* 0xcc03 */ { true, 0xcc03, 0xcc03 }, +/* 0xcc04 */ { true, 0xcc04, 0xcc04 }, +/* 0xcc05 */ { true, 0xcc05, 0xcc05 }, +/* 0xcc06 */ { true, 0xcc06, 0xcc06 }, +/* 0xcc07 */ { true, 0xcc07, 0xcc07 }, +/* 0xcc08 */ { true, 0xcc08, 0xcc08 }, +/* 0xcc09 */ { true, 0xcc09, 0xcc09 }, +/* 0xcc0a */ { true, 0xcc0a, 0xcc0a }, +/* 0xcc0b */ { true, 0xcc0b, 0xcc0b }, +/* 0xcc0c */ { true, 0xcc0c, 0xcc0c }, +/* 0xcc0d */ { true, 0xcc0d, 0xcc0d }, +/* 0xcc0e */ { true, 0xcc0e, 0xcc0e }, +/* 0xcc0f */ { true, 0xcc0f, 0xcc0f }, +/* 0xcc10 */ { true, 0xcc10, 0xcc10 }, +/* 0xcc11 */ { true, 0xcc11, 0xcc11 }, +/* 0xcc12 */ { true, 0xcc12, 0xcc12 }, +/* 0xcc13 */ { true, 0xcc13, 0xcc13 }, +/* 0xcc14 */ { true, 0xcc14, 0xcc14 }, +/* 0xcc15 */ { true, 0xcc15, 0xcc15 }, +/* 0xcc16 */ { true, 0xcc16, 0xcc16 }, +/* 0xcc17 */ { true, 0xcc17, 0xcc17 }, +/* 0xcc18 */ { true, 0xcc18, 0xcc18 }, +/* 0xcc19 */ { true, 0xcc19, 0xcc19 }, +/* 0xcc1a */ { true, 0xcc1a, 0xcc1a }, +/* 0xcc1b */ { true, 0xcc1b, 0xcc1b }, +/* 0xcc1c */ { true, 0xcc1c, 0xcc1c }, +/* 0xcc1d */ { true, 0xcc1d, 0xcc1d }, +/* 0xcc1e */ { true, 0xcc1e, 0xcc1e }, +/* 0xcc1f */ { true, 0xcc1f, 0xcc1f }, +/* 0xcc20 */ { true, 0xcc20, 0xcc20 }, +/* 0xcc21 */ { true, 0xcc21, 0xcc21 }, +/* 0xcc22 */ { true, 0xcc22, 0xcc22 }, +/* 0xcc23 */ { true, 0xcc23, 0xcc23 }, +/* 0xcc24 */ { true, 0xcc24, 0xcc24 }, +/* 0xcc25 */ { true, 0xcc25, 0xcc25 }, +/* 0xcc26 */ { true, 0xcc26, 0xcc26 }, +/* 0xcc27 */ { true, 0xcc27, 0xcc27 }, +/* 0xcc28 */ { true, 0xcc28, 0xcc28 }, +/* 0xcc29 */ { true, 0xcc29, 0xcc29 }, +/* 0xcc2a */ { true, 0xcc2a, 0xcc2a }, +/* 0xcc2b */ { true, 0xcc2b, 0xcc2b }, +/* 0xcc2c */ { true, 0xcc2c, 0xcc2c }, +/* 0xcc2d */ { true, 0xcc2d, 0xcc2d }, +/* 0xcc2e */ { true, 0xcc2e, 0xcc2e }, +/* 0xcc2f */ { true, 0xcc2f, 0xcc2f }, +/* 0xcc30 */ { true, 0xcc30, 0xcc30 }, +/* 0xcc31 */ { true, 0xcc31, 0xcc31 }, +/* 0xcc32 */ { true, 0xcc32, 0xcc32 }, +/* 0xcc33 */ { true, 0xcc33, 0xcc33 }, +/* 0xcc34 */ { true, 0xcc34, 0xcc34 }, +/* 0xcc35 */ { true, 0xcc35, 0xcc35 }, +/* 0xcc36 */ { true, 0xcc36, 0xcc36 }, +/* 0xcc37 */ { true, 0xcc37, 0xcc37 }, +/* 0xcc38 */ { true, 0xcc38, 0xcc38 }, +/* 0xcc39 */ { true, 0xcc39, 0xcc39 }, +/* 0xcc3a */ { true, 0xcc3a, 0xcc3a }, +/* 0xcc3b */ { true, 0xcc3b, 0xcc3b }, +/* 0xcc3c */ { true, 0xcc3c, 0xcc3c }, +/* 0xcc3d */ { true, 0xcc3d, 0xcc3d }, +/* 0xcc3e */ { true, 0xcc3e, 0xcc3e }, +/* 0xcc3f */ { true, 0xcc3f, 0xcc3f }, +/* 0xcc40 */ { true, 0xcc40, 0xcc40 }, +/* 0xcc41 */ { true, 0xcc41, 0xcc41 }, +/* 0xcc42 */ { true, 0xcc42, 0xcc42 }, +/* 0xcc43 */ { true, 0xcc43, 0xcc43 }, +/* 0xcc44 */ { true, 0xcc44, 0xcc44 }, +/* 0xcc45 */ { true, 0xcc45, 0xcc45 }, +/* 0xcc46 */ { true, 0xcc46, 0xcc46 }, +/* 0xcc47 */ { true, 0xcc47, 0xcc47 }, +/* 0xcc48 */ { true, 0xcc48, 0xcc48 }, +/* 0xcc49 */ { true, 0xcc49, 0xcc49 }, +/* 0xcc4a */ { true, 0xcc4a, 0xcc4a }, +/* 0xcc4b */ { true, 0xcc4b, 0xcc4b }, +/* 0xcc4c */ { true, 0xcc4c, 0xcc4c }, +/* 0xcc4d */ { true, 0xcc4d, 0xcc4d }, +/* 0xcc4e */ { true, 0xcc4e, 0xcc4e }, +/* 0xcc4f */ { true, 0xcc4f, 0xcc4f }, +/* 0xcc50 */ { true, 0xcc50, 0xcc50 }, +/* 0xcc51 */ { true, 0xcc51, 0xcc51 }, +/* 0xcc52 */ { true, 0xcc52, 0xcc52 }, +/* 0xcc53 */ { true, 0xcc53, 0xcc53 }, +/* 0xcc54 */ { true, 0xcc54, 0xcc54 }, +/* 0xcc55 */ { true, 0xcc55, 0xcc55 }, +/* 0xcc56 */ { true, 0xcc56, 0xcc56 }, +/* 0xcc57 */ { true, 0xcc57, 0xcc57 }, +/* 0xcc58 */ { true, 0xcc58, 0xcc58 }, +/* 0xcc59 */ { true, 0xcc59, 0xcc59 }, +/* 0xcc5a */ { true, 0xcc5a, 0xcc5a }, +/* 0xcc5b */ { true, 0xcc5b, 0xcc5b }, +/* 0xcc5c */ { true, 0xcc5c, 0xcc5c }, +/* 0xcc5d */ { true, 0xcc5d, 0xcc5d }, +/* 0xcc5e */ { true, 0xcc5e, 0xcc5e }, +/* 0xcc5f */ { true, 0xcc5f, 0xcc5f }, +/* 0xcc60 */ { true, 0xcc60, 0xcc60 }, +/* 0xcc61 */ { true, 0xcc61, 0xcc61 }, +/* 0xcc62 */ { true, 0xcc62, 0xcc62 }, +/* 0xcc63 */ { true, 0xcc63, 0xcc63 }, +/* 0xcc64 */ { true, 0xcc64, 0xcc64 }, +/* 0xcc65 */ { true, 0xcc65, 0xcc65 }, +/* 0xcc66 */ { true, 0xcc66, 0xcc66 }, +/* 0xcc67 */ { true, 0xcc67, 0xcc67 }, +/* 0xcc68 */ { true, 0xcc68, 0xcc68 }, +/* 0xcc69 */ { true, 0xcc69, 0xcc69 }, +/* 0xcc6a */ { true, 0xcc6a, 0xcc6a }, +/* 0xcc6b */ { true, 0xcc6b, 0xcc6b }, +/* 0xcc6c */ { true, 0xcc6c, 0xcc6c }, +/* 0xcc6d */ { true, 0xcc6d, 0xcc6d }, +/* 0xcc6e */ { true, 0xcc6e, 0xcc6e }, +/* 0xcc6f */ { true, 0xcc6f, 0xcc6f }, +/* 0xcc70 */ { true, 0xcc70, 0xcc70 }, +/* 0xcc71 */ { true, 0xcc71, 0xcc71 }, +/* 0xcc72 */ { true, 0xcc72, 0xcc72 }, +/* 0xcc73 */ { true, 0xcc73, 0xcc73 }, +/* 0xcc74 */ { true, 0xcc74, 0xcc74 }, +/* 0xcc75 */ { true, 0xcc75, 0xcc75 }, +/* 0xcc76 */ { true, 0xcc76, 0xcc76 }, +/* 0xcc77 */ { true, 0xcc77, 0xcc77 }, +/* 0xcc78 */ { true, 0xcc78, 0xcc78 }, +/* 0xcc79 */ { true, 0xcc79, 0xcc79 }, +/* 0xcc7a */ { true, 0xcc7a, 0xcc7a }, +/* 0xcc7b */ { true, 0xcc7b, 0xcc7b }, +/* 0xcc7c */ { true, 0xcc7c, 0xcc7c }, +/* 0xcc7d */ { true, 0xcc7d, 0xcc7d }, +/* 0xcc7e */ { true, 0xcc7e, 0xcc7e }, +/* 0xcc7f */ { true, 0xcc7f, 0xcc7f }, +/* 0xcc80 */ { true, 0xcc80, 0xcc80 }, +/* 0xcc81 */ { true, 0xcc81, 0xcc81 }, +/* 0xcc82 */ { true, 0xcc82, 0xcc82 }, +/* 0xcc83 */ { true, 0xcc83, 0xcc83 }, +/* 0xcc84 */ { true, 0xcc84, 0xcc84 }, +/* 0xcc85 */ { true, 0xcc85, 0xcc85 }, +/* 0xcc86 */ { true, 0xcc86, 0xcc86 }, +/* 0xcc87 */ { true, 0xcc87, 0xcc87 }, +/* 0xcc88 */ { true, 0xcc88, 0xcc88 }, +/* 0xcc89 */ { true, 0xcc89, 0xcc89 }, +/* 0xcc8a */ { true, 0xcc8a, 0xcc8a }, +/* 0xcc8b */ { true, 0xcc8b, 0xcc8b }, +/* 0xcc8c */ { true, 0xcc8c, 0xcc8c }, +/* 0xcc8d */ { true, 0xcc8d, 0xcc8d }, +/* 0xcc8e */ { true, 0xcc8e, 0xcc8e }, +/* 0xcc8f */ { true, 0xcc8f, 0xcc8f }, +/* 0xcc90 */ { true, 0xcc90, 0xcc90 }, +/* 0xcc91 */ { true, 0xcc91, 0xcc91 }, +/* 0xcc92 */ { true, 0xcc92, 0xcc92 }, +/* 0xcc93 */ { true, 0xcc93, 0xcc93 }, +/* 0xcc94 */ { true, 0xcc94, 0xcc94 }, +/* 0xcc95 */ { true, 0xcc95, 0xcc95 }, +/* 0xcc96 */ { true, 0xcc96, 0xcc96 }, +/* 0xcc97 */ { true, 0xcc97, 0xcc97 }, +/* 0xcc98 */ { true, 0xcc98, 0xcc98 }, +/* 0xcc99 */ { true, 0xcc99, 0xcc99 }, +/* 0xcc9a */ { true, 0xcc9a, 0xcc9a }, +/* 0xcc9b */ { true, 0xcc9b, 0xcc9b }, +/* 0xcc9c */ { true, 0xcc9c, 0xcc9c }, +/* 0xcc9d */ { true, 0xcc9d, 0xcc9d }, +/* 0xcc9e */ { true, 0xcc9e, 0xcc9e }, +/* 0xcc9f */ { true, 0xcc9f, 0xcc9f }, +/* 0xcca0 */ { true, 0xcca0, 0xcca0 }, +/* 0xcca1 */ { true, 0xcca1, 0xcca1 }, +/* 0xcca2 */ { true, 0xcca2, 0xcca2 }, +/* 0xcca3 */ { true, 0xcca3, 0xcca3 }, +/* 0xcca4 */ { true, 0xcca4, 0xcca4 }, +/* 0xcca5 */ { true, 0xcca5, 0xcca5 }, +/* 0xcca6 */ { true, 0xcca6, 0xcca6 }, +/* 0xcca7 */ { true, 0xcca7, 0xcca7 }, +/* 0xcca8 */ { true, 0xcca8, 0xcca8 }, +/* 0xcca9 */ { true, 0xcca9, 0xcca9 }, +/* 0xccaa */ { true, 0xccaa, 0xccaa }, +/* 0xccab */ { true, 0xccab, 0xccab }, +/* 0xccac */ { true, 0xccac, 0xccac }, +/* 0xccad */ { true, 0xccad, 0xccad }, +/* 0xccae */ { true, 0xccae, 0xccae }, +/* 0xccaf */ { true, 0xccaf, 0xccaf }, +/* 0xccb0 */ { true, 0xccb0, 0xccb0 }, +/* 0xccb1 */ { true, 0xccb1, 0xccb1 }, +/* 0xccb2 */ { true, 0xccb2, 0xccb2 }, +/* 0xccb3 */ { true, 0xccb3, 0xccb3 }, +/* 0xccb4 */ { true, 0xccb4, 0xccb4 }, +/* 0xccb5 */ { true, 0xccb5, 0xccb5 }, +/* 0xccb6 */ { true, 0xccb6, 0xccb6 }, +/* 0xccb7 */ { true, 0xccb7, 0xccb7 }, +/* 0xccb8 */ { true, 0xccb8, 0xccb8 }, +/* 0xccb9 */ { true, 0xccb9, 0xccb9 }, +/* 0xccba */ { true, 0xccba, 0xccba }, +/* 0xccbb */ { true, 0xccbb, 0xccbb }, +/* 0xccbc */ { true, 0xccbc, 0xccbc }, +/* 0xccbd */ { true, 0xccbd, 0xccbd }, +/* 0xccbe */ { true, 0xccbe, 0xccbe }, +/* 0xccbf */ { true, 0xccbf, 0xccbf }, +/* 0xccc0 */ { true, 0xccc0, 0xccc0 }, +/* 0xccc1 */ { true, 0xccc1, 0xccc1 }, +/* 0xccc2 */ { true, 0xccc2, 0xccc2 }, +/* 0xccc3 */ { true, 0xccc3, 0xccc3 }, +/* 0xccc4 */ { true, 0xccc4, 0xccc4 }, +/* 0xccc5 */ { true, 0xccc5, 0xccc5 }, +/* 0xccc6 */ { true, 0xccc6, 0xccc6 }, +/* 0xccc7 */ { true, 0xccc7, 0xccc7 }, +/* 0xccc8 */ { true, 0xccc8, 0xccc8 }, +/* 0xccc9 */ { true, 0xccc9, 0xccc9 }, +/* 0xccca */ { true, 0xccca, 0xccca }, +/* 0xcccb */ { true, 0xcccb, 0xcccb }, +/* 0xcccc */ { true, 0xcccc, 0xcccc }, +/* 0xcccd */ { true, 0xcccd, 0xcccd }, +/* 0xccce */ { true, 0xccce, 0xccce }, +/* 0xcccf */ { true, 0xcccf, 0xcccf }, +/* 0xccd0 */ { true, 0xccd0, 0xccd0 }, +/* 0xccd1 */ { true, 0xccd1, 0xccd1 }, +/* 0xccd2 */ { true, 0xccd2, 0xccd2 }, +/* 0xccd3 */ { true, 0xccd3, 0xccd3 }, +/* 0xccd4 */ { true, 0xccd4, 0xccd4 }, +/* 0xccd5 */ { true, 0xccd5, 0xccd5 }, +/* 0xccd6 */ { true, 0xccd6, 0xccd6 }, +/* 0xccd7 */ { true, 0xccd7, 0xccd7 }, +/* 0xccd8 */ { true, 0xccd8, 0xccd8 }, +/* 0xccd9 */ { true, 0xccd9, 0xccd9 }, +/* 0xccda */ { true, 0xccda, 0xccda }, +/* 0xccdb */ { true, 0xccdb, 0xccdb }, +/* 0xccdc */ { true, 0xccdc, 0xccdc }, +/* 0xccdd */ { true, 0xccdd, 0xccdd }, +/* 0xccde */ { true, 0xccde, 0xccde }, +/* 0xccdf */ { true, 0xccdf, 0xccdf }, +/* 0xcce0 */ { true, 0xcce0, 0xcce0 }, +/* 0xcce1 */ { true, 0xcce1, 0xcce1 }, +/* 0xcce2 */ { true, 0xcce2, 0xcce2 }, +/* 0xcce3 */ { true, 0xcce3, 0xcce3 }, +/* 0xcce4 */ { true, 0xcce4, 0xcce4 }, +/* 0xcce5 */ { true, 0xcce5, 0xcce5 }, +/* 0xcce6 */ { true, 0xcce6, 0xcce6 }, +/* 0xcce7 */ { true, 0xcce7, 0xcce7 }, +/* 0xcce8 */ { true, 0xcce8, 0xcce8 }, +/* 0xcce9 */ { true, 0xcce9, 0xcce9 }, +/* 0xccea */ { true, 0xccea, 0xccea }, +/* 0xcceb */ { true, 0xcceb, 0xcceb }, +/* 0xccec */ { true, 0xccec, 0xccec }, +/* 0xcced */ { true, 0xcced, 0xcced }, +/* 0xccee */ { true, 0xccee, 0xccee }, +/* 0xccef */ { true, 0xccef, 0xccef }, +/* 0xccf0 */ { true, 0xccf0, 0xccf0 }, +/* 0xccf1 */ { true, 0xccf1, 0xccf1 }, +/* 0xccf2 */ { true, 0xccf2, 0xccf2 }, +/* 0xccf3 */ { true, 0xccf3, 0xccf3 }, +/* 0xccf4 */ { true, 0xccf4, 0xccf4 }, +/* 0xccf5 */ { true, 0xccf5, 0xccf5 }, +/* 0xccf6 */ { true, 0xccf6, 0xccf6 }, +/* 0xccf7 */ { true, 0xccf7, 0xccf7 }, +/* 0xccf8 */ { true, 0xccf8, 0xccf8 }, +/* 0xccf9 */ { true, 0xccf9, 0xccf9 }, +/* 0xccfa */ { true, 0xccfa, 0xccfa }, +/* 0xccfb */ { true, 0xccfb, 0xccfb }, +/* 0xccfc */ { true, 0xccfc, 0xccfc }, +/* 0xccfd */ { true, 0xccfd, 0xccfd }, +/* 0xccfe */ { true, 0xccfe, 0xccfe }, +/* 0xccff */ { true, 0xccff, 0xccff }, +/* 0xcd00 */ { true, 0xcd00, 0xcd00 }, +/* 0xcd01 */ { true, 0xcd01, 0xcd01 }, +/* 0xcd02 */ { true, 0xcd02, 0xcd02 }, +/* 0xcd03 */ { true, 0xcd03, 0xcd03 }, +/* 0xcd04 */ { true, 0xcd04, 0xcd04 }, +/* 0xcd05 */ { true, 0xcd05, 0xcd05 }, +/* 0xcd06 */ { true, 0xcd06, 0xcd06 }, +/* 0xcd07 */ { true, 0xcd07, 0xcd07 }, +/* 0xcd08 */ { true, 0xcd08, 0xcd08 }, +/* 0xcd09 */ { true, 0xcd09, 0xcd09 }, +/* 0xcd0a */ { true, 0xcd0a, 0xcd0a }, +/* 0xcd0b */ { true, 0xcd0b, 0xcd0b }, +/* 0xcd0c */ { true, 0xcd0c, 0xcd0c }, +/* 0xcd0d */ { true, 0xcd0d, 0xcd0d }, +/* 0xcd0e */ { true, 0xcd0e, 0xcd0e }, +/* 0xcd0f */ { true, 0xcd0f, 0xcd0f }, +/* 0xcd10 */ { true, 0xcd10, 0xcd10 }, +/* 0xcd11 */ { true, 0xcd11, 0xcd11 }, +/* 0xcd12 */ { true, 0xcd12, 0xcd12 }, +/* 0xcd13 */ { true, 0xcd13, 0xcd13 }, +/* 0xcd14 */ { true, 0xcd14, 0xcd14 }, +/* 0xcd15 */ { true, 0xcd15, 0xcd15 }, +/* 0xcd16 */ { true, 0xcd16, 0xcd16 }, +/* 0xcd17 */ { true, 0xcd17, 0xcd17 }, +/* 0xcd18 */ { true, 0xcd18, 0xcd18 }, +/* 0xcd19 */ { true, 0xcd19, 0xcd19 }, +/* 0xcd1a */ { true, 0xcd1a, 0xcd1a }, +/* 0xcd1b */ { true, 0xcd1b, 0xcd1b }, +/* 0xcd1c */ { true, 0xcd1c, 0xcd1c }, +/* 0xcd1d */ { true, 0xcd1d, 0xcd1d }, +/* 0xcd1e */ { true, 0xcd1e, 0xcd1e }, +/* 0xcd1f */ { true, 0xcd1f, 0xcd1f }, +/* 0xcd20 */ { true, 0xcd20, 0xcd20 }, +/* 0xcd21 */ { true, 0xcd21, 0xcd21 }, +/* 0xcd22 */ { true, 0xcd22, 0xcd22 }, +/* 0xcd23 */ { true, 0xcd23, 0xcd23 }, +/* 0xcd24 */ { true, 0xcd24, 0xcd24 }, +/* 0xcd25 */ { true, 0xcd25, 0xcd25 }, +/* 0xcd26 */ { true, 0xcd26, 0xcd26 }, +/* 0xcd27 */ { true, 0xcd27, 0xcd27 }, +/* 0xcd28 */ { true, 0xcd28, 0xcd28 }, +/* 0xcd29 */ { true, 0xcd29, 0xcd29 }, +/* 0xcd2a */ { true, 0xcd2a, 0xcd2a }, +/* 0xcd2b */ { true, 0xcd2b, 0xcd2b }, +/* 0xcd2c */ { true, 0xcd2c, 0xcd2c }, +/* 0xcd2d */ { true, 0xcd2d, 0xcd2d }, +/* 0xcd2e */ { true, 0xcd2e, 0xcd2e }, +/* 0xcd2f */ { true, 0xcd2f, 0xcd2f }, +/* 0xcd30 */ { true, 0xcd30, 0xcd30 }, +/* 0xcd31 */ { true, 0xcd31, 0xcd31 }, +/* 0xcd32 */ { true, 0xcd32, 0xcd32 }, +/* 0xcd33 */ { true, 0xcd33, 0xcd33 }, +/* 0xcd34 */ { true, 0xcd34, 0xcd34 }, +/* 0xcd35 */ { true, 0xcd35, 0xcd35 }, +/* 0xcd36 */ { true, 0xcd36, 0xcd36 }, +/* 0xcd37 */ { true, 0xcd37, 0xcd37 }, +/* 0xcd38 */ { true, 0xcd38, 0xcd38 }, +/* 0xcd39 */ { true, 0xcd39, 0xcd39 }, +/* 0xcd3a */ { true, 0xcd3a, 0xcd3a }, +/* 0xcd3b */ { true, 0xcd3b, 0xcd3b }, +/* 0xcd3c */ { true, 0xcd3c, 0xcd3c }, +/* 0xcd3d */ { true, 0xcd3d, 0xcd3d }, +/* 0xcd3e */ { true, 0xcd3e, 0xcd3e }, +/* 0xcd3f */ { true, 0xcd3f, 0xcd3f }, +/* 0xcd40 */ { true, 0xcd40, 0xcd40 }, +/* 0xcd41 */ { true, 0xcd41, 0xcd41 }, +/* 0xcd42 */ { true, 0xcd42, 0xcd42 }, +/* 0xcd43 */ { true, 0xcd43, 0xcd43 }, +/* 0xcd44 */ { true, 0xcd44, 0xcd44 }, +/* 0xcd45 */ { true, 0xcd45, 0xcd45 }, +/* 0xcd46 */ { true, 0xcd46, 0xcd46 }, +/* 0xcd47 */ { true, 0xcd47, 0xcd47 }, +/* 0xcd48 */ { true, 0xcd48, 0xcd48 }, +/* 0xcd49 */ { true, 0xcd49, 0xcd49 }, +/* 0xcd4a */ { true, 0xcd4a, 0xcd4a }, +/* 0xcd4b */ { true, 0xcd4b, 0xcd4b }, +/* 0xcd4c */ { true, 0xcd4c, 0xcd4c }, +/* 0xcd4d */ { true, 0xcd4d, 0xcd4d }, +/* 0xcd4e */ { true, 0xcd4e, 0xcd4e }, +/* 0xcd4f */ { true, 0xcd4f, 0xcd4f }, +/* 0xcd50 */ { true, 0xcd50, 0xcd50 }, +/* 0xcd51 */ { true, 0xcd51, 0xcd51 }, +/* 0xcd52 */ { true, 0xcd52, 0xcd52 }, +/* 0xcd53 */ { true, 0xcd53, 0xcd53 }, +/* 0xcd54 */ { true, 0xcd54, 0xcd54 }, +/* 0xcd55 */ { true, 0xcd55, 0xcd55 }, +/* 0xcd56 */ { true, 0xcd56, 0xcd56 }, +/* 0xcd57 */ { true, 0xcd57, 0xcd57 }, +/* 0xcd58 */ { true, 0xcd58, 0xcd58 }, +/* 0xcd59 */ { true, 0xcd59, 0xcd59 }, +/* 0xcd5a */ { true, 0xcd5a, 0xcd5a }, +/* 0xcd5b */ { true, 0xcd5b, 0xcd5b }, +/* 0xcd5c */ { true, 0xcd5c, 0xcd5c }, +/* 0xcd5d */ { true, 0xcd5d, 0xcd5d }, +/* 0xcd5e */ { true, 0xcd5e, 0xcd5e }, +/* 0xcd5f */ { true, 0xcd5f, 0xcd5f }, +/* 0xcd60 */ { true, 0xcd60, 0xcd60 }, +/* 0xcd61 */ { true, 0xcd61, 0xcd61 }, +/* 0xcd62 */ { true, 0xcd62, 0xcd62 }, +/* 0xcd63 */ { true, 0xcd63, 0xcd63 }, +/* 0xcd64 */ { true, 0xcd64, 0xcd64 }, +/* 0xcd65 */ { true, 0xcd65, 0xcd65 }, +/* 0xcd66 */ { true, 0xcd66, 0xcd66 }, +/* 0xcd67 */ { true, 0xcd67, 0xcd67 }, +/* 0xcd68 */ { true, 0xcd68, 0xcd68 }, +/* 0xcd69 */ { true, 0xcd69, 0xcd69 }, +/* 0xcd6a */ { true, 0xcd6a, 0xcd6a }, +/* 0xcd6b */ { true, 0xcd6b, 0xcd6b }, +/* 0xcd6c */ { true, 0xcd6c, 0xcd6c }, +/* 0xcd6d */ { true, 0xcd6d, 0xcd6d }, +/* 0xcd6e */ { true, 0xcd6e, 0xcd6e }, +/* 0xcd6f */ { true, 0xcd6f, 0xcd6f }, +/* 0xcd70 */ { true, 0xcd70, 0xcd70 }, +/* 0xcd71 */ { true, 0xcd71, 0xcd71 }, +/* 0xcd72 */ { true, 0xcd72, 0xcd72 }, +/* 0xcd73 */ { true, 0xcd73, 0xcd73 }, +/* 0xcd74 */ { true, 0xcd74, 0xcd74 }, +/* 0xcd75 */ { true, 0xcd75, 0xcd75 }, +/* 0xcd76 */ { true, 0xcd76, 0xcd76 }, +/* 0xcd77 */ { true, 0xcd77, 0xcd77 }, +/* 0xcd78 */ { true, 0xcd78, 0xcd78 }, +/* 0xcd79 */ { true, 0xcd79, 0xcd79 }, +/* 0xcd7a */ { true, 0xcd7a, 0xcd7a }, +/* 0xcd7b */ { true, 0xcd7b, 0xcd7b }, +/* 0xcd7c */ { true, 0xcd7c, 0xcd7c }, +/* 0xcd7d */ { true, 0xcd7d, 0xcd7d }, +/* 0xcd7e */ { true, 0xcd7e, 0xcd7e }, +/* 0xcd7f */ { true, 0xcd7f, 0xcd7f }, +/* 0xcd80 */ { true, 0xcd80, 0xcd80 }, +/* 0xcd81 */ { true, 0xcd81, 0xcd81 }, +/* 0xcd82 */ { true, 0xcd82, 0xcd82 }, +/* 0xcd83 */ { true, 0xcd83, 0xcd83 }, +/* 0xcd84 */ { true, 0xcd84, 0xcd84 }, +/* 0xcd85 */ { true, 0xcd85, 0xcd85 }, +/* 0xcd86 */ { true, 0xcd86, 0xcd86 }, +/* 0xcd87 */ { true, 0xcd87, 0xcd87 }, +/* 0xcd88 */ { true, 0xcd88, 0xcd88 }, +/* 0xcd89 */ { true, 0xcd89, 0xcd89 }, +/* 0xcd8a */ { true, 0xcd8a, 0xcd8a }, +/* 0xcd8b */ { true, 0xcd8b, 0xcd8b }, +/* 0xcd8c */ { true, 0xcd8c, 0xcd8c }, +/* 0xcd8d */ { true, 0xcd8d, 0xcd8d }, +/* 0xcd8e */ { true, 0xcd8e, 0xcd8e }, +/* 0xcd8f */ { true, 0xcd8f, 0xcd8f }, +/* 0xcd90 */ { true, 0xcd90, 0xcd90 }, +/* 0xcd91 */ { true, 0xcd91, 0xcd91 }, +/* 0xcd92 */ { true, 0xcd92, 0xcd92 }, +/* 0xcd93 */ { true, 0xcd93, 0xcd93 }, +/* 0xcd94 */ { true, 0xcd94, 0xcd94 }, +/* 0xcd95 */ { true, 0xcd95, 0xcd95 }, +/* 0xcd96 */ { true, 0xcd96, 0xcd96 }, +/* 0xcd97 */ { true, 0xcd97, 0xcd97 }, +/* 0xcd98 */ { true, 0xcd98, 0xcd98 }, +/* 0xcd99 */ { true, 0xcd99, 0xcd99 }, +/* 0xcd9a */ { true, 0xcd9a, 0xcd9a }, +/* 0xcd9b */ { true, 0xcd9b, 0xcd9b }, +/* 0xcd9c */ { true, 0xcd9c, 0xcd9c }, +/* 0xcd9d */ { true, 0xcd9d, 0xcd9d }, +/* 0xcd9e */ { true, 0xcd9e, 0xcd9e }, +/* 0xcd9f */ { true, 0xcd9f, 0xcd9f }, +/* 0xcda0 */ { true, 0xcda0, 0xcda0 }, +/* 0xcda1 */ { true, 0xcda1, 0xcda1 }, +/* 0xcda2 */ { true, 0xcda2, 0xcda2 }, +/* 0xcda3 */ { true, 0xcda3, 0xcda3 }, +/* 0xcda4 */ { true, 0xcda4, 0xcda4 }, +/* 0xcda5 */ { true, 0xcda5, 0xcda5 }, +/* 0xcda6 */ { true, 0xcda6, 0xcda6 }, +/* 0xcda7 */ { true, 0xcda7, 0xcda7 }, +/* 0xcda8 */ { true, 0xcda8, 0xcda8 }, +/* 0xcda9 */ { true, 0xcda9, 0xcda9 }, +/* 0xcdaa */ { true, 0xcdaa, 0xcdaa }, +/* 0xcdab */ { true, 0xcdab, 0xcdab }, +/* 0xcdac */ { true, 0xcdac, 0xcdac }, +/* 0xcdad */ { true, 0xcdad, 0xcdad }, +/* 0xcdae */ { true, 0xcdae, 0xcdae }, +/* 0xcdaf */ { true, 0xcdaf, 0xcdaf }, +/* 0xcdb0 */ { true, 0xcdb0, 0xcdb0 }, +/* 0xcdb1 */ { true, 0xcdb1, 0xcdb1 }, +/* 0xcdb2 */ { true, 0xcdb2, 0xcdb2 }, +/* 0xcdb3 */ { true, 0xcdb3, 0xcdb3 }, +/* 0xcdb4 */ { true, 0xcdb4, 0xcdb4 }, +/* 0xcdb5 */ { true, 0xcdb5, 0xcdb5 }, +/* 0xcdb6 */ { true, 0xcdb6, 0xcdb6 }, +/* 0xcdb7 */ { true, 0xcdb7, 0xcdb7 }, +/* 0xcdb8 */ { true, 0xcdb8, 0xcdb8 }, +/* 0xcdb9 */ { true, 0xcdb9, 0xcdb9 }, +/* 0xcdba */ { true, 0xcdba, 0xcdba }, +/* 0xcdbb */ { true, 0xcdbb, 0xcdbb }, +/* 0xcdbc */ { true, 0xcdbc, 0xcdbc }, +/* 0xcdbd */ { true, 0xcdbd, 0xcdbd }, +/* 0xcdbe */ { true, 0xcdbe, 0xcdbe }, +/* 0xcdbf */ { true, 0xcdbf, 0xcdbf }, +/* 0xcdc0 */ { true, 0xcdc0, 0xcdc0 }, +/* 0xcdc1 */ { true, 0xcdc1, 0xcdc1 }, +/* 0xcdc2 */ { true, 0xcdc2, 0xcdc2 }, +/* 0xcdc3 */ { true, 0xcdc3, 0xcdc3 }, +/* 0xcdc4 */ { true, 0xcdc4, 0xcdc4 }, +/* 0xcdc5 */ { true, 0xcdc5, 0xcdc5 }, +/* 0xcdc6 */ { true, 0xcdc6, 0xcdc6 }, +/* 0xcdc7 */ { true, 0xcdc7, 0xcdc7 }, +/* 0xcdc8 */ { true, 0xcdc8, 0xcdc8 }, +/* 0xcdc9 */ { true, 0xcdc9, 0xcdc9 }, +/* 0xcdca */ { true, 0xcdca, 0xcdca }, +/* 0xcdcb */ { true, 0xcdcb, 0xcdcb }, +/* 0xcdcc */ { true, 0xcdcc, 0xcdcc }, +/* 0xcdcd */ { true, 0xcdcd, 0xcdcd }, +/* 0xcdce */ { true, 0xcdce, 0xcdce }, +/* 0xcdcf */ { true, 0xcdcf, 0xcdcf }, +/* 0xcdd0 */ { true, 0xcdd0, 0xcdd0 }, +/* 0xcdd1 */ { true, 0xcdd1, 0xcdd1 }, +/* 0xcdd2 */ { true, 0xcdd2, 0xcdd2 }, +/* 0xcdd3 */ { true, 0xcdd3, 0xcdd3 }, +/* 0xcdd4 */ { true, 0xcdd4, 0xcdd4 }, +/* 0xcdd5 */ { true, 0xcdd5, 0xcdd5 }, +/* 0xcdd6 */ { true, 0xcdd6, 0xcdd6 }, +/* 0xcdd7 */ { true, 0xcdd7, 0xcdd7 }, +/* 0xcdd8 */ { true, 0xcdd8, 0xcdd8 }, +/* 0xcdd9 */ { true, 0xcdd9, 0xcdd9 }, +/* 0xcdda */ { true, 0xcdda, 0xcdda }, +/* 0xcddb */ { true, 0xcddb, 0xcddb }, +/* 0xcddc */ { true, 0xcddc, 0xcddc }, +/* 0xcddd */ { true, 0xcddd, 0xcddd }, +/* 0xcdde */ { true, 0xcdde, 0xcdde }, +/* 0xcddf */ { true, 0xcddf, 0xcddf }, +/* 0xcde0 */ { true, 0xcde0, 0xcde0 }, +/* 0xcde1 */ { true, 0xcde1, 0xcde1 }, +/* 0xcde2 */ { true, 0xcde2, 0xcde2 }, +/* 0xcde3 */ { true, 0xcde3, 0xcde3 }, +/* 0xcde4 */ { true, 0xcde4, 0xcde4 }, +/* 0xcde5 */ { true, 0xcde5, 0xcde5 }, +/* 0xcde6 */ { true, 0xcde6, 0xcde6 }, +/* 0xcde7 */ { true, 0xcde7, 0xcde7 }, +/* 0xcde8 */ { true, 0xcde8, 0xcde8 }, +/* 0xcde9 */ { true, 0xcde9, 0xcde9 }, +/* 0xcdea */ { true, 0xcdea, 0xcdea }, +/* 0xcdeb */ { true, 0xcdeb, 0xcdeb }, +/* 0xcdec */ { true, 0xcdec, 0xcdec }, +/* 0xcded */ { true, 0xcded, 0xcded }, +/* 0xcdee */ { true, 0xcdee, 0xcdee }, +/* 0xcdef */ { true, 0xcdef, 0xcdef }, +/* 0xcdf0 */ { true, 0xcdf0, 0xcdf0 }, +/* 0xcdf1 */ { true, 0xcdf1, 0xcdf1 }, +/* 0xcdf2 */ { true, 0xcdf2, 0xcdf2 }, +/* 0xcdf3 */ { true, 0xcdf3, 0xcdf3 }, +/* 0xcdf4 */ { true, 0xcdf4, 0xcdf4 }, +/* 0xcdf5 */ { true, 0xcdf5, 0xcdf5 }, +/* 0xcdf6 */ { true, 0xcdf6, 0xcdf6 }, +/* 0xcdf7 */ { true, 0xcdf7, 0xcdf7 }, +/* 0xcdf8 */ { true, 0xcdf8, 0xcdf8 }, +/* 0xcdf9 */ { true, 0xcdf9, 0xcdf9 }, +/* 0xcdfa */ { true, 0xcdfa, 0xcdfa }, +/* 0xcdfb */ { true, 0xcdfb, 0xcdfb }, +/* 0xcdfc */ { true, 0xcdfc, 0xcdfc }, +/* 0xcdfd */ { true, 0xcdfd, 0xcdfd }, +/* 0xcdfe */ { true, 0xcdfe, 0xcdfe }, +/* 0xcdff */ { true, 0xcdff, 0xcdff }, +/* 0xce00 */ { true, 0xce00, 0xce00 }, +/* 0xce01 */ { true, 0xce01, 0xce01 }, +/* 0xce02 */ { true, 0xce02, 0xce02 }, +/* 0xce03 */ { true, 0xce03, 0xce03 }, +/* 0xce04 */ { true, 0xce04, 0xce04 }, +/* 0xce05 */ { true, 0xce05, 0xce05 }, +/* 0xce06 */ { true, 0xce06, 0xce06 }, +/* 0xce07 */ { true, 0xce07, 0xce07 }, +/* 0xce08 */ { true, 0xce08, 0xce08 }, +/* 0xce09 */ { true, 0xce09, 0xce09 }, +/* 0xce0a */ { true, 0xce0a, 0xce0a }, +/* 0xce0b */ { true, 0xce0b, 0xce0b }, +/* 0xce0c */ { true, 0xce0c, 0xce0c }, +/* 0xce0d */ { true, 0xce0d, 0xce0d }, +/* 0xce0e */ { true, 0xce0e, 0xce0e }, +/* 0xce0f */ { true, 0xce0f, 0xce0f }, +/* 0xce10 */ { true, 0xce10, 0xce10 }, +/* 0xce11 */ { true, 0xce11, 0xce11 }, +/* 0xce12 */ { true, 0xce12, 0xce12 }, +/* 0xce13 */ { true, 0xce13, 0xce13 }, +/* 0xce14 */ { true, 0xce14, 0xce14 }, +/* 0xce15 */ { true, 0xce15, 0xce15 }, +/* 0xce16 */ { true, 0xce16, 0xce16 }, +/* 0xce17 */ { true, 0xce17, 0xce17 }, +/* 0xce18 */ { true, 0xce18, 0xce18 }, +/* 0xce19 */ { true, 0xce19, 0xce19 }, +/* 0xce1a */ { true, 0xce1a, 0xce1a }, +/* 0xce1b */ { true, 0xce1b, 0xce1b }, +/* 0xce1c */ { true, 0xce1c, 0xce1c }, +/* 0xce1d */ { true, 0xce1d, 0xce1d }, +/* 0xce1e */ { true, 0xce1e, 0xce1e }, +/* 0xce1f */ { true, 0xce1f, 0xce1f }, +/* 0xce20 */ { true, 0xce20, 0xce20 }, +/* 0xce21 */ { true, 0xce21, 0xce21 }, +/* 0xce22 */ { true, 0xce22, 0xce22 }, +/* 0xce23 */ { true, 0xce23, 0xce23 }, +/* 0xce24 */ { true, 0xce24, 0xce24 }, +/* 0xce25 */ { true, 0xce25, 0xce25 }, +/* 0xce26 */ { true, 0xce26, 0xce26 }, +/* 0xce27 */ { true, 0xce27, 0xce27 }, +/* 0xce28 */ { true, 0xce28, 0xce28 }, +/* 0xce29 */ { true, 0xce29, 0xce29 }, +/* 0xce2a */ { true, 0xce2a, 0xce2a }, +/* 0xce2b */ { true, 0xce2b, 0xce2b }, +/* 0xce2c */ { true, 0xce2c, 0xce2c }, +/* 0xce2d */ { true, 0xce2d, 0xce2d }, +/* 0xce2e */ { true, 0xce2e, 0xce2e }, +/* 0xce2f */ { true, 0xce2f, 0xce2f }, +/* 0xce30 */ { true, 0xce30, 0xce30 }, +/* 0xce31 */ { true, 0xce31, 0xce31 }, +/* 0xce32 */ { true, 0xce32, 0xce32 }, +/* 0xce33 */ { true, 0xce33, 0xce33 }, +/* 0xce34 */ { true, 0xce34, 0xce34 }, +/* 0xce35 */ { true, 0xce35, 0xce35 }, +/* 0xce36 */ { true, 0xce36, 0xce36 }, +/* 0xce37 */ { true, 0xce37, 0xce37 }, +/* 0xce38 */ { true, 0xce38, 0xce38 }, +/* 0xce39 */ { true, 0xce39, 0xce39 }, +/* 0xce3a */ { true, 0xce3a, 0xce3a }, +/* 0xce3b */ { true, 0xce3b, 0xce3b }, +/* 0xce3c */ { true, 0xce3c, 0xce3c }, +/* 0xce3d */ { true, 0xce3d, 0xce3d }, +/* 0xce3e */ { true, 0xce3e, 0xce3e }, +/* 0xce3f */ { true, 0xce3f, 0xce3f }, +/* 0xce40 */ { true, 0xce40, 0xce40 }, +/* 0xce41 */ { true, 0xce41, 0xce41 }, +/* 0xce42 */ { true, 0xce42, 0xce42 }, +/* 0xce43 */ { true, 0xce43, 0xce43 }, +/* 0xce44 */ { true, 0xce44, 0xce44 }, +/* 0xce45 */ { true, 0xce45, 0xce45 }, +/* 0xce46 */ { true, 0xce46, 0xce46 }, +/* 0xce47 */ { true, 0xce47, 0xce47 }, +/* 0xce48 */ { true, 0xce48, 0xce48 }, +/* 0xce49 */ { true, 0xce49, 0xce49 }, +/* 0xce4a */ { true, 0xce4a, 0xce4a }, +/* 0xce4b */ { true, 0xce4b, 0xce4b }, +/* 0xce4c */ { true, 0xce4c, 0xce4c }, +/* 0xce4d */ { true, 0xce4d, 0xce4d }, +/* 0xce4e */ { true, 0xce4e, 0xce4e }, +/* 0xce4f */ { true, 0xce4f, 0xce4f }, +/* 0xce50 */ { true, 0xce50, 0xce50 }, +/* 0xce51 */ { true, 0xce51, 0xce51 }, +/* 0xce52 */ { true, 0xce52, 0xce52 }, +/* 0xce53 */ { true, 0xce53, 0xce53 }, +/* 0xce54 */ { true, 0xce54, 0xce54 }, +/* 0xce55 */ { true, 0xce55, 0xce55 }, +/* 0xce56 */ { true, 0xce56, 0xce56 }, +/* 0xce57 */ { true, 0xce57, 0xce57 }, +/* 0xce58 */ { true, 0xce58, 0xce58 }, +/* 0xce59 */ { true, 0xce59, 0xce59 }, +/* 0xce5a */ { true, 0xce5a, 0xce5a }, +/* 0xce5b */ { true, 0xce5b, 0xce5b }, +/* 0xce5c */ { true, 0xce5c, 0xce5c }, +/* 0xce5d */ { true, 0xce5d, 0xce5d }, +/* 0xce5e */ { true, 0xce5e, 0xce5e }, +/* 0xce5f */ { true, 0xce5f, 0xce5f }, +/* 0xce60 */ { true, 0xce60, 0xce60 }, +/* 0xce61 */ { true, 0xce61, 0xce61 }, +/* 0xce62 */ { true, 0xce62, 0xce62 }, +/* 0xce63 */ { true, 0xce63, 0xce63 }, +/* 0xce64 */ { true, 0xce64, 0xce64 }, +/* 0xce65 */ { true, 0xce65, 0xce65 }, +/* 0xce66 */ { true, 0xce66, 0xce66 }, +/* 0xce67 */ { true, 0xce67, 0xce67 }, +/* 0xce68 */ { true, 0xce68, 0xce68 }, +/* 0xce69 */ { true, 0xce69, 0xce69 }, +/* 0xce6a */ { true, 0xce6a, 0xce6a }, +/* 0xce6b */ { true, 0xce6b, 0xce6b }, +/* 0xce6c */ { true, 0xce6c, 0xce6c }, +/* 0xce6d */ { true, 0xce6d, 0xce6d }, +/* 0xce6e */ { true, 0xce6e, 0xce6e }, +/* 0xce6f */ { true, 0xce6f, 0xce6f }, +/* 0xce70 */ { true, 0xce70, 0xce70 }, +/* 0xce71 */ { true, 0xce71, 0xce71 }, +/* 0xce72 */ { true, 0xce72, 0xce72 }, +/* 0xce73 */ { true, 0xce73, 0xce73 }, +/* 0xce74 */ { true, 0xce74, 0xce74 }, +/* 0xce75 */ { true, 0xce75, 0xce75 }, +/* 0xce76 */ { true, 0xce76, 0xce76 }, +/* 0xce77 */ { true, 0xce77, 0xce77 }, +/* 0xce78 */ { true, 0xce78, 0xce78 }, +/* 0xce79 */ { true, 0xce79, 0xce79 }, +/* 0xce7a */ { true, 0xce7a, 0xce7a }, +/* 0xce7b */ { true, 0xce7b, 0xce7b }, +/* 0xce7c */ { true, 0xce7c, 0xce7c }, +/* 0xce7d */ { true, 0xce7d, 0xce7d }, +/* 0xce7e */ { true, 0xce7e, 0xce7e }, +/* 0xce7f */ { true, 0xce7f, 0xce7f }, +/* 0xce80 */ { true, 0xce80, 0xce80 }, +/* 0xce81 */ { true, 0xce81, 0xce81 }, +/* 0xce82 */ { true, 0xce82, 0xce82 }, +/* 0xce83 */ { true, 0xce83, 0xce83 }, +/* 0xce84 */ { true, 0xce84, 0xce84 }, +/* 0xce85 */ { true, 0xce85, 0xce85 }, +/* 0xce86 */ { true, 0xce86, 0xce86 }, +/* 0xce87 */ { true, 0xce87, 0xce87 }, +/* 0xce88 */ { true, 0xce88, 0xce88 }, +/* 0xce89 */ { true, 0xce89, 0xce89 }, +/* 0xce8a */ { true, 0xce8a, 0xce8a }, +/* 0xce8b */ { true, 0xce8b, 0xce8b }, +/* 0xce8c */ { true, 0xce8c, 0xce8c }, +/* 0xce8d */ { true, 0xce8d, 0xce8d }, +/* 0xce8e */ { true, 0xce8e, 0xce8e }, +/* 0xce8f */ { true, 0xce8f, 0xce8f }, +/* 0xce90 */ { true, 0xce90, 0xce90 }, +/* 0xce91 */ { true, 0xce91, 0xce91 }, +/* 0xce92 */ { true, 0xce92, 0xce92 }, +/* 0xce93 */ { true, 0xce93, 0xce93 }, +/* 0xce94 */ { true, 0xce94, 0xce94 }, +/* 0xce95 */ { true, 0xce95, 0xce95 }, +/* 0xce96 */ { true, 0xce96, 0xce96 }, +/* 0xce97 */ { true, 0xce97, 0xce97 }, +/* 0xce98 */ { true, 0xce98, 0xce98 }, +/* 0xce99 */ { true, 0xce99, 0xce99 }, +/* 0xce9a */ { true, 0xce9a, 0xce9a }, +/* 0xce9b */ { true, 0xce9b, 0xce9b }, +/* 0xce9c */ { true, 0xce9c, 0xce9c }, +/* 0xce9d */ { true, 0xce9d, 0xce9d }, +/* 0xce9e */ { true, 0xce9e, 0xce9e }, +/* 0xce9f */ { true, 0xce9f, 0xce9f }, +/* 0xcea0 */ { true, 0xcea0, 0xcea0 }, +/* 0xcea1 */ { true, 0xcea1, 0xcea1 }, +/* 0xcea2 */ { true, 0xcea2, 0xcea2 }, +/* 0xcea3 */ { true, 0xcea3, 0xcea3 }, +/* 0xcea4 */ { true, 0xcea4, 0xcea4 }, +/* 0xcea5 */ { true, 0xcea5, 0xcea5 }, +/* 0xcea6 */ { true, 0xcea6, 0xcea6 }, +/* 0xcea7 */ { true, 0xcea7, 0xcea7 }, +/* 0xcea8 */ { true, 0xcea8, 0xcea8 }, +/* 0xcea9 */ { true, 0xcea9, 0xcea9 }, +/* 0xceaa */ { true, 0xceaa, 0xceaa }, +/* 0xceab */ { true, 0xceab, 0xceab }, +/* 0xceac */ { true, 0xceac, 0xceac }, +/* 0xcead */ { true, 0xcead, 0xcead }, +/* 0xceae */ { true, 0xceae, 0xceae }, +/* 0xceaf */ { true, 0xceaf, 0xceaf }, +/* 0xceb0 */ { true, 0xceb0, 0xceb0 }, +/* 0xceb1 */ { true, 0xceb1, 0xceb1 }, +/* 0xceb2 */ { true, 0xceb2, 0xceb2 }, +/* 0xceb3 */ { true, 0xceb3, 0xceb3 }, +/* 0xceb4 */ { true, 0xceb4, 0xceb4 }, +/* 0xceb5 */ { true, 0xceb5, 0xceb5 }, +/* 0xceb6 */ { true, 0xceb6, 0xceb6 }, +/* 0xceb7 */ { true, 0xceb7, 0xceb7 }, +/* 0xceb8 */ { true, 0xceb8, 0xceb8 }, +/* 0xceb9 */ { true, 0xceb9, 0xceb9 }, +/* 0xceba */ { true, 0xceba, 0xceba }, +/* 0xcebb */ { true, 0xcebb, 0xcebb }, +/* 0xcebc */ { true, 0xcebc, 0xcebc }, +/* 0xcebd */ { true, 0xcebd, 0xcebd }, +/* 0xcebe */ { true, 0xcebe, 0xcebe }, +/* 0xcebf */ { true, 0xcebf, 0xcebf }, +/* 0xcec0 */ { true, 0xcec0, 0xcec0 }, +/* 0xcec1 */ { true, 0xcec1, 0xcec1 }, +/* 0xcec2 */ { true, 0xcec2, 0xcec2 }, +/* 0xcec3 */ { true, 0xcec3, 0xcec3 }, +/* 0xcec4 */ { true, 0xcec4, 0xcec4 }, +/* 0xcec5 */ { true, 0xcec5, 0xcec5 }, +/* 0xcec6 */ { true, 0xcec6, 0xcec6 }, +/* 0xcec7 */ { true, 0xcec7, 0xcec7 }, +/* 0xcec8 */ { true, 0xcec8, 0xcec8 }, +/* 0xcec9 */ { true, 0xcec9, 0xcec9 }, +/* 0xceca */ { true, 0xceca, 0xceca }, +/* 0xcecb */ { true, 0xcecb, 0xcecb }, +/* 0xcecc */ { true, 0xcecc, 0xcecc }, +/* 0xcecd */ { true, 0xcecd, 0xcecd }, +/* 0xcece */ { true, 0xcece, 0xcece }, +/* 0xcecf */ { true, 0xcecf, 0xcecf }, +/* 0xced0 */ { true, 0xced0, 0xced0 }, +/* 0xced1 */ { true, 0xced1, 0xced1 }, +/* 0xced2 */ { true, 0xced2, 0xced2 }, +/* 0xced3 */ { true, 0xced3, 0xced3 }, +/* 0xced4 */ { true, 0xced4, 0xced4 }, +/* 0xced5 */ { true, 0xced5, 0xced5 }, +/* 0xced6 */ { true, 0xced6, 0xced6 }, +/* 0xced7 */ { true, 0xced7, 0xced7 }, +/* 0xced8 */ { true, 0xced8, 0xced8 }, +/* 0xced9 */ { true, 0xced9, 0xced9 }, +/* 0xceda */ { true, 0xceda, 0xceda }, +/* 0xcedb */ { true, 0xcedb, 0xcedb }, +/* 0xcedc */ { true, 0xcedc, 0xcedc }, +/* 0xcedd */ { true, 0xcedd, 0xcedd }, +/* 0xcede */ { true, 0xcede, 0xcede }, +/* 0xcedf */ { true, 0xcedf, 0xcedf }, +/* 0xcee0 */ { true, 0xcee0, 0xcee0 }, +/* 0xcee1 */ { true, 0xcee1, 0xcee1 }, +/* 0xcee2 */ { true, 0xcee2, 0xcee2 }, +/* 0xcee3 */ { true, 0xcee3, 0xcee3 }, +/* 0xcee4 */ { true, 0xcee4, 0xcee4 }, +/* 0xcee5 */ { true, 0xcee5, 0xcee5 }, +/* 0xcee6 */ { true, 0xcee6, 0xcee6 }, +/* 0xcee7 */ { true, 0xcee7, 0xcee7 }, +/* 0xcee8 */ { true, 0xcee8, 0xcee8 }, +/* 0xcee9 */ { true, 0xcee9, 0xcee9 }, +/* 0xceea */ { true, 0xceea, 0xceea }, +/* 0xceeb */ { true, 0xceeb, 0xceeb }, +/* 0xceec */ { true, 0xceec, 0xceec }, +/* 0xceed */ { true, 0xceed, 0xceed }, +/* 0xceee */ { true, 0xceee, 0xceee }, +/* 0xceef */ { true, 0xceef, 0xceef }, +/* 0xcef0 */ { true, 0xcef0, 0xcef0 }, +/* 0xcef1 */ { true, 0xcef1, 0xcef1 }, +/* 0xcef2 */ { true, 0xcef2, 0xcef2 }, +/* 0xcef3 */ { true, 0xcef3, 0xcef3 }, +/* 0xcef4 */ { true, 0xcef4, 0xcef4 }, +/* 0xcef5 */ { true, 0xcef5, 0xcef5 }, +/* 0xcef6 */ { true, 0xcef6, 0xcef6 }, +/* 0xcef7 */ { true, 0xcef7, 0xcef7 }, +/* 0xcef8 */ { true, 0xcef8, 0xcef8 }, +/* 0xcef9 */ { true, 0xcef9, 0xcef9 }, +/* 0xcefa */ { true, 0xcefa, 0xcefa }, +/* 0xcefb */ { true, 0xcefb, 0xcefb }, +/* 0xcefc */ { true, 0xcefc, 0xcefc }, +/* 0xcefd */ { true, 0xcefd, 0xcefd }, +/* 0xcefe */ { true, 0xcefe, 0xcefe }, +/* 0xceff */ { true, 0xceff, 0xceff }, +/* 0xcf00 */ { true, 0xcf00, 0xcf00 }, +/* 0xcf01 */ { true, 0xcf01, 0xcf01 }, +/* 0xcf02 */ { true, 0xcf02, 0xcf02 }, +/* 0xcf03 */ { true, 0xcf03, 0xcf03 }, +/* 0xcf04 */ { true, 0xcf04, 0xcf04 }, +/* 0xcf05 */ { true, 0xcf05, 0xcf05 }, +/* 0xcf06 */ { true, 0xcf06, 0xcf06 }, +/* 0xcf07 */ { true, 0xcf07, 0xcf07 }, +/* 0xcf08 */ { true, 0xcf08, 0xcf08 }, +/* 0xcf09 */ { true, 0xcf09, 0xcf09 }, +/* 0xcf0a */ { true, 0xcf0a, 0xcf0a }, +/* 0xcf0b */ { true, 0xcf0b, 0xcf0b }, +/* 0xcf0c */ { true, 0xcf0c, 0xcf0c }, +/* 0xcf0d */ { true, 0xcf0d, 0xcf0d }, +/* 0xcf0e */ { true, 0xcf0e, 0xcf0e }, +/* 0xcf0f */ { true, 0xcf0f, 0xcf0f }, +/* 0xcf10 */ { true, 0xcf10, 0xcf10 }, +/* 0xcf11 */ { true, 0xcf11, 0xcf11 }, +/* 0xcf12 */ { true, 0xcf12, 0xcf12 }, +/* 0xcf13 */ { true, 0xcf13, 0xcf13 }, +/* 0xcf14 */ { true, 0xcf14, 0xcf14 }, +/* 0xcf15 */ { true, 0xcf15, 0xcf15 }, +/* 0xcf16 */ { true, 0xcf16, 0xcf16 }, +/* 0xcf17 */ { true, 0xcf17, 0xcf17 }, +/* 0xcf18 */ { true, 0xcf18, 0xcf18 }, +/* 0xcf19 */ { true, 0xcf19, 0xcf19 }, +/* 0xcf1a */ { true, 0xcf1a, 0xcf1a }, +/* 0xcf1b */ { true, 0xcf1b, 0xcf1b }, +/* 0xcf1c */ { true, 0xcf1c, 0xcf1c }, +/* 0xcf1d */ { true, 0xcf1d, 0xcf1d }, +/* 0xcf1e */ { true, 0xcf1e, 0xcf1e }, +/* 0xcf1f */ { true, 0xcf1f, 0xcf1f }, +/* 0xcf20 */ { true, 0xcf20, 0xcf20 }, +/* 0xcf21 */ { true, 0xcf21, 0xcf21 }, +/* 0xcf22 */ { true, 0xcf22, 0xcf22 }, +/* 0xcf23 */ { true, 0xcf23, 0xcf23 }, +/* 0xcf24 */ { true, 0xcf24, 0xcf24 }, +/* 0xcf25 */ { true, 0xcf25, 0xcf25 }, +/* 0xcf26 */ { true, 0xcf26, 0xcf26 }, +/* 0xcf27 */ { true, 0xcf27, 0xcf27 }, +/* 0xcf28 */ { true, 0xcf28, 0xcf28 }, +/* 0xcf29 */ { true, 0xcf29, 0xcf29 }, +/* 0xcf2a */ { true, 0xcf2a, 0xcf2a }, +/* 0xcf2b */ { true, 0xcf2b, 0xcf2b }, +/* 0xcf2c */ { true, 0xcf2c, 0xcf2c }, +/* 0xcf2d */ { true, 0xcf2d, 0xcf2d }, +/* 0xcf2e */ { true, 0xcf2e, 0xcf2e }, +/* 0xcf2f */ { true, 0xcf2f, 0xcf2f }, +/* 0xcf30 */ { true, 0xcf30, 0xcf30 }, +/* 0xcf31 */ { true, 0xcf31, 0xcf31 }, +/* 0xcf32 */ { true, 0xcf32, 0xcf32 }, +/* 0xcf33 */ { true, 0xcf33, 0xcf33 }, +/* 0xcf34 */ { true, 0xcf34, 0xcf34 }, +/* 0xcf35 */ { true, 0xcf35, 0xcf35 }, +/* 0xcf36 */ { true, 0xcf36, 0xcf36 }, +/* 0xcf37 */ { true, 0xcf37, 0xcf37 }, +/* 0xcf38 */ { true, 0xcf38, 0xcf38 }, +/* 0xcf39 */ { true, 0xcf39, 0xcf39 }, +/* 0xcf3a */ { true, 0xcf3a, 0xcf3a }, +/* 0xcf3b */ { true, 0xcf3b, 0xcf3b }, +/* 0xcf3c */ { true, 0xcf3c, 0xcf3c }, +/* 0xcf3d */ { true, 0xcf3d, 0xcf3d }, +/* 0xcf3e */ { true, 0xcf3e, 0xcf3e }, +/* 0xcf3f */ { true, 0xcf3f, 0xcf3f }, +/* 0xcf40 */ { true, 0xcf40, 0xcf40 }, +/* 0xcf41 */ { true, 0xcf41, 0xcf41 }, +/* 0xcf42 */ { true, 0xcf42, 0xcf42 }, +/* 0xcf43 */ { true, 0xcf43, 0xcf43 }, +/* 0xcf44 */ { true, 0xcf44, 0xcf44 }, +/* 0xcf45 */ { true, 0xcf45, 0xcf45 }, +/* 0xcf46 */ { true, 0xcf46, 0xcf46 }, +/* 0xcf47 */ { true, 0xcf47, 0xcf47 }, +/* 0xcf48 */ { true, 0xcf48, 0xcf48 }, +/* 0xcf49 */ { true, 0xcf49, 0xcf49 }, +/* 0xcf4a */ { true, 0xcf4a, 0xcf4a }, +/* 0xcf4b */ { true, 0xcf4b, 0xcf4b }, +/* 0xcf4c */ { true, 0xcf4c, 0xcf4c }, +/* 0xcf4d */ { true, 0xcf4d, 0xcf4d }, +/* 0xcf4e */ { true, 0xcf4e, 0xcf4e }, +/* 0xcf4f */ { true, 0xcf4f, 0xcf4f }, +/* 0xcf50 */ { true, 0xcf50, 0xcf50 }, +/* 0xcf51 */ { true, 0xcf51, 0xcf51 }, +/* 0xcf52 */ { true, 0xcf52, 0xcf52 }, +/* 0xcf53 */ { true, 0xcf53, 0xcf53 }, +/* 0xcf54 */ { true, 0xcf54, 0xcf54 }, +/* 0xcf55 */ { true, 0xcf55, 0xcf55 }, +/* 0xcf56 */ { true, 0xcf56, 0xcf56 }, +/* 0xcf57 */ { true, 0xcf57, 0xcf57 }, +/* 0xcf58 */ { true, 0xcf58, 0xcf58 }, +/* 0xcf59 */ { true, 0xcf59, 0xcf59 }, +/* 0xcf5a */ { true, 0xcf5a, 0xcf5a }, +/* 0xcf5b */ { true, 0xcf5b, 0xcf5b }, +/* 0xcf5c */ { true, 0xcf5c, 0xcf5c }, +/* 0xcf5d */ { true, 0xcf5d, 0xcf5d }, +/* 0xcf5e */ { true, 0xcf5e, 0xcf5e }, +/* 0xcf5f */ { true, 0xcf5f, 0xcf5f }, +/* 0xcf60 */ { true, 0xcf60, 0xcf60 }, +/* 0xcf61 */ { true, 0xcf61, 0xcf61 }, +/* 0xcf62 */ { true, 0xcf62, 0xcf62 }, +/* 0xcf63 */ { true, 0xcf63, 0xcf63 }, +/* 0xcf64 */ { true, 0xcf64, 0xcf64 }, +/* 0xcf65 */ { true, 0xcf65, 0xcf65 }, +/* 0xcf66 */ { true, 0xcf66, 0xcf66 }, +/* 0xcf67 */ { true, 0xcf67, 0xcf67 }, +/* 0xcf68 */ { true, 0xcf68, 0xcf68 }, +/* 0xcf69 */ { true, 0xcf69, 0xcf69 }, +/* 0xcf6a */ { true, 0xcf6a, 0xcf6a }, +/* 0xcf6b */ { true, 0xcf6b, 0xcf6b }, +/* 0xcf6c */ { true, 0xcf6c, 0xcf6c }, +/* 0xcf6d */ { true, 0xcf6d, 0xcf6d }, +/* 0xcf6e */ { true, 0xcf6e, 0xcf6e }, +/* 0xcf6f */ { true, 0xcf6f, 0xcf6f }, +/* 0xcf70 */ { true, 0xcf70, 0xcf70 }, +/* 0xcf71 */ { true, 0xcf71, 0xcf71 }, +/* 0xcf72 */ { true, 0xcf72, 0xcf72 }, +/* 0xcf73 */ { true, 0xcf73, 0xcf73 }, +/* 0xcf74 */ { true, 0xcf74, 0xcf74 }, +/* 0xcf75 */ { true, 0xcf75, 0xcf75 }, +/* 0xcf76 */ { true, 0xcf76, 0xcf76 }, +/* 0xcf77 */ { true, 0xcf77, 0xcf77 }, +/* 0xcf78 */ { true, 0xcf78, 0xcf78 }, +/* 0xcf79 */ { true, 0xcf79, 0xcf79 }, +/* 0xcf7a */ { true, 0xcf7a, 0xcf7a }, +/* 0xcf7b */ { true, 0xcf7b, 0xcf7b }, +/* 0xcf7c */ { true, 0xcf7c, 0xcf7c }, +/* 0xcf7d */ { true, 0xcf7d, 0xcf7d }, +/* 0xcf7e */ { true, 0xcf7e, 0xcf7e }, +/* 0xcf7f */ { true, 0xcf7f, 0xcf7f }, +/* 0xcf80 */ { true, 0xcf80, 0xcf80 }, +/* 0xcf81 */ { true, 0xcf81, 0xcf81 }, +/* 0xcf82 */ { true, 0xcf82, 0xcf82 }, +/* 0xcf83 */ { true, 0xcf83, 0xcf83 }, +/* 0xcf84 */ { true, 0xcf84, 0xcf84 }, +/* 0xcf85 */ { true, 0xcf85, 0xcf85 }, +/* 0xcf86 */ { true, 0xcf86, 0xcf86 }, +/* 0xcf87 */ { true, 0xcf87, 0xcf87 }, +/* 0xcf88 */ { true, 0xcf88, 0xcf88 }, +/* 0xcf89 */ { true, 0xcf89, 0xcf89 }, +/* 0xcf8a */ { true, 0xcf8a, 0xcf8a }, +/* 0xcf8b */ { true, 0xcf8b, 0xcf8b }, +/* 0xcf8c */ { true, 0xcf8c, 0xcf8c }, +/* 0xcf8d */ { true, 0xcf8d, 0xcf8d }, +/* 0xcf8e */ { true, 0xcf8e, 0xcf8e }, +/* 0xcf8f */ { true, 0xcf8f, 0xcf8f }, +/* 0xcf90 */ { true, 0xcf90, 0xcf90 }, +/* 0xcf91 */ { true, 0xcf91, 0xcf91 }, +/* 0xcf92 */ { true, 0xcf92, 0xcf92 }, +/* 0xcf93 */ { true, 0xcf93, 0xcf93 }, +/* 0xcf94 */ { true, 0xcf94, 0xcf94 }, +/* 0xcf95 */ { true, 0xcf95, 0xcf95 }, +/* 0xcf96 */ { true, 0xcf96, 0xcf96 }, +/* 0xcf97 */ { true, 0xcf97, 0xcf97 }, +/* 0xcf98 */ { true, 0xcf98, 0xcf98 }, +/* 0xcf99 */ { true, 0xcf99, 0xcf99 }, +/* 0xcf9a */ { true, 0xcf9a, 0xcf9a }, +/* 0xcf9b */ { true, 0xcf9b, 0xcf9b }, +/* 0xcf9c */ { true, 0xcf9c, 0xcf9c }, +/* 0xcf9d */ { true, 0xcf9d, 0xcf9d }, +/* 0xcf9e */ { true, 0xcf9e, 0xcf9e }, +/* 0xcf9f */ { true, 0xcf9f, 0xcf9f }, +/* 0xcfa0 */ { true, 0xcfa0, 0xcfa0 }, +/* 0xcfa1 */ { true, 0xcfa1, 0xcfa1 }, +/* 0xcfa2 */ { true, 0xcfa2, 0xcfa2 }, +/* 0xcfa3 */ { true, 0xcfa3, 0xcfa3 }, +/* 0xcfa4 */ { true, 0xcfa4, 0xcfa4 }, +/* 0xcfa5 */ { true, 0xcfa5, 0xcfa5 }, +/* 0xcfa6 */ { true, 0xcfa6, 0xcfa6 }, +/* 0xcfa7 */ { true, 0xcfa7, 0xcfa7 }, +/* 0xcfa8 */ { true, 0xcfa8, 0xcfa8 }, +/* 0xcfa9 */ { true, 0xcfa9, 0xcfa9 }, +/* 0xcfaa */ { true, 0xcfaa, 0xcfaa }, +/* 0xcfab */ { true, 0xcfab, 0xcfab }, +/* 0xcfac */ { true, 0xcfac, 0xcfac }, +/* 0xcfad */ { true, 0xcfad, 0xcfad }, +/* 0xcfae */ { true, 0xcfae, 0xcfae }, +/* 0xcfaf */ { true, 0xcfaf, 0xcfaf }, +/* 0xcfb0 */ { true, 0xcfb0, 0xcfb0 }, +/* 0xcfb1 */ { true, 0xcfb1, 0xcfb1 }, +/* 0xcfb2 */ { true, 0xcfb2, 0xcfb2 }, +/* 0xcfb3 */ { true, 0xcfb3, 0xcfb3 }, +/* 0xcfb4 */ { true, 0xcfb4, 0xcfb4 }, +/* 0xcfb5 */ { true, 0xcfb5, 0xcfb5 }, +/* 0xcfb6 */ { true, 0xcfb6, 0xcfb6 }, +/* 0xcfb7 */ { true, 0xcfb7, 0xcfb7 }, +/* 0xcfb8 */ { true, 0xcfb8, 0xcfb8 }, +/* 0xcfb9 */ { true, 0xcfb9, 0xcfb9 }, +/* 0xcfba */ { true, 0xcfba, 0xcfba }, +/* 0xcfbb */ { true, 0xcfbb, 0xcfbb }, +/* 0xcfbc */ { true, 0xcfbc, 0xcfbc }, +/* 0xcfbd */ { true, 0xcfbd, 0xcfbd }, +/* 0xcfbe */ { true, 0xcfbe, 0xcfbe }, +/* 0xcfbf */ { true, 0xcfbf, 0xcfbf }, +/* 0xcfc0 */ { true, 0xcfc0, 0xcfc0 }, +/* 0xcfc1 */ { true, 0xcfc1, 0xcfc1 }, +/* 0xcfc2 */ { true, 0xcfc2, 0xcfc2 }, +/* 0xcfc3 */ { true, 0xcfc3, 0xcfc3 }, +/* 0xcfc4 */ { true, 0xcfc4, 0xcfc4 }, +/* 0xcfc5 */ { true, 0xcfc5, 0xcfc5 }, +/* 0xcfc6 */ { true, 0xcfc6, 0xcfc6 }, +/* 0xcfc7 */ { true, 0xcfc7, 0xcfc7 }, +/* 0xcfc8 */ { true, 0xcfc8, 0xcfc8 }, +/* 0xcfc9 */ { true, 0xcfc9, 0xcfc9 }, +/* 0xcfca */ { true, 0xcfca, 0xcfca }, +/* 0xcfcb */ { true, 0xcfcb, 0xcfcb }, +/* 0xcfcc */ { true, 0xcfcc, 0xcfcc }, +/* 0xcfcd */ { true, 0xcfcd, 0xcfcd }, +/* 0xcfce */ { true, 0xcfce, 0xcfce }, +/* 0xcfcf */ { true, 0xcfcf, 0xcfcf }, +/* 0xcfd0 */ { true, 0xcfd0, 0xcfd0 }, +/* 0xcfd1 */ { true, 0xcfd1, 0xcfd1 }, +/* 0xcfd2 */ { true, 0xcfd2, 0xcfd2 }, +/* 0xcfd3 */ { true, 0xcfd3, 0xcfd3 }, +/* 0xcfd4 */ { true, 0xcfd4, 0xcfd4 }, +/* 0xcfd5 */ { true, 0xcfd5, 0xcfd5 }, +/* 0xcfd6 */ { true, 0xcfd6, 0xcfd6 }, +/* 0xcfd7 */ { true, 0xcfd7, 0xcfd7 }, +/* 0xcfd8 */ { true, 0xcfd8, 0xcfd8 }, +/* 0xcfd9 */ { true, 0xcfd9, 0xcfd9 }, +/* 0xcfda */ { true, 0xcfda, 0xcfda }, +/* 0xcfdb */ { true, 0xcfdb, 0xcfdb }, +/* 0xcfdc */ { true, 0xcfdc, 0xcfdc }, +/* 0xcfdd */ { true, 0xcfdd, 0xcfdd }, +/* 0xcfde */ { true, 0xcfde, 0xcfde }, +/* 0xcfdf */ { true, 0xcfdf, 0xcfdf }, +/* 0xcfe0 */ { true, 0xcfe0, 0xcfe0 }, +/* 0xcfe1 */ { true, 0xcfe1, 0xcfe1 }, +/* 0xcfe2 */ { true, 0xcfe2, 0xcfe2 }, +/* 0xcfe3 */ { true, 0xcfe3, 0xcfe3 }, +/* 0xcfe4 */ { true, 0xcfe4, 0xcfe4 }, +/* 0xcfe5 */ { true, 0xcfe5, 0xcfe5 }, +/* 0xcfe6 */ { true, 0xcfe6, 0xcfe6 }, +/* 0xcfe7 */ { true, 0xcfe7, 0xcfe7 }, +/* 0xcfe8 */ { true, 0xcfe8, 0xcfe8 }, +/* 0xcfe9 */ { true, 0xcfe9, 0xcfe9 }, +/* 0xcfea */ { true, 0xcfea, 0xcfea }, +/* 0xcfeb */ { true, 0xcfeb, 0xcfeb }, +/* 0xcfec */ { true, 0xcfec, 0xcfec }, +/* 0xcfed */ { true, 0xcfed, 0xcfed }, +/* 0xcfee */ { true, 0xcfee, 0xcfee }, +/* 0xcfef */ { true, 0xcfef, 0xcfef }, +/* 0xcff0 */ { true, 0xcff0, 0xcff0 }, +/* 0xcff1 */ { true, 0xcff1, 0xcff1 }, +/* 0xcff2 */ { true, 0xcff2, 0xcff2 }, +/* 0xcff3 */ { true, 0xcff3, 0xcff3 }, +/* 0xcff4 */ { true, 0xcff4, 0xcff4 }, +/* 0xcff5 */ { true, 0xcff5, 0xcff5 }, +/* 0xcff6 */ { true, 0xcff6, 0xcff6 }, +/* 0xcff7 */ { true, 0xcff7, 0xcff7 }, +/* 0xcff8 */ { true, 0xcff8, 0xcff8 }, +/* 0xcff9 */ { true, 0xcff9, 0xcff9 }, +/* 0xcffa */ { true, 0xcffa, 0xcffa }, +/* 0xcffb */ { true, 0xcffb, 0xcffb }, +/* 0xcffc */ { true, 0xcffc, 0xcffc }, +/* 0xcffd */ { true, 0xcffd, 0xcffd }, +/* 0xcffe */ { true, 0xcffe, 0xcffe }, +/* 0xcfff */ { true, 0xcfff, 0xcfff }, +/* 0xd000 */ { true, 0xd000, 0xd000 }, +/* 0xd001 */ { true, 0xd001, 0xd001 }, +/* 0xd002 */ { true, 0xd002, 0xd002 }, +/* 0xd003 */ { true, 0xd003, 0xd003 }, +/* 0xd004 */ { true, 0xd004, 0xd004 }, +/* 0xd005 */ { true, 0xd005, 0xd005 }, +/* 0xd006 */ { true, 0xd006, 0xd006 }, +/* 0xd007 */ { true, 0xd007, 0xd007 }, +/* 0xd008 */ { true, 0xd008, 0xd008 }, +/* 0xd009 */ { true, 0xd009, 0xd009 }, +/* 0xd00a */ { true, 0xd00a, 0xd00a }, +/* 0xd00b */ { true, 0xd00b, 0xd00b }, +/* 0xd00c */ { true, 0xd00c, 0xd00c }, +/* 0xd00d */ { true, 0xd00d, 0xd00d }, +/* 0xd00e */ { true, 0xd00e, 0xd00e }, +/* 0xd00f */ { true, 0xd00f, 0xd00f }, +/* 0xd010 */ { true, 0xd010, 0xd010 }, +/* 0xd011 */ { true, 0xd011, 0xd011 }, +/* 0xd012 */ { true, 0xd012, 0xd012 }, +/* 0xd013 */ { true, 0xd013, 0xd013 }, +/* 0xd014 */ { true, 0xd014, 0xd014 }, +/* 0xd015 */ { true, 0xd015, 0xd015 }, +/* 0xd016 */ { true, 0xd016, 0xd016 }, +/* 0xd017 */ { true, 0xd017, 0xd017 }, +/* 0xd018 */ { true, 0xd018, 0xd018 }, +/* 0xd019 */ { true, 0xd019, 0xd019 }, +/* 0xd01a */ { true, 0xd01a, 0xd01a }, +/* 0xd01b */ { true, 0xd01b, 0xd01b }, +/* 0xd01c */ { true, 0xd01c, 0xd01c }, +/* 0xd01d */ { true, 0xd01d, 0xd01d }, +/* 0xd01e */ { true, 0xd01e, 0xd01e }, +/* 0xd01f */ { true, 0xd01f, 0xd01f }, +/* 0xd020 */ { true, 0xd020, 0xd020 }, +/* 0xd021 */ { true, 0xd021, 0xd021 }, +/* 0xd022 */ { true, 0xd022, 0xd022 }, +/* 0xd023 */ { true, 0xd023, 0xd023 }, +/* 0xd024 */ { true, 0xd024, 0xd024 }, +/* 0xd025 */ { true, 0xd025, 0xd025 }, +/* 0xd026 */ { true, 0xd026, 0xd026 }, +/* 0xd027 */ { true, 0xd027, 0xd027 }, +/* 0xd028 */ { true, 0xd028, 0xd028 }, +/* 0xd029 */ { true, 0xd029, 0xd029 }, +/* 0xd02a */ { true, 0xd02a, 0xd02a }, +/* 0xd02b */ { true, 0xd02b, 0xd02b }, +/* 0xd02c */ { true, 0xd02c, 0xd02c }, +/* 0xd02d */ { true, 0xd02d, 0xd02d }, +/* 0xd02e */ { true, 0xd02e, 0xd02e }, +/* 0xd02f */ { true, 0xd02f, 0xd02f }, +/* 0xd030 */ { true, 0xd030, 0xd030 }, +/* 0xd031 */ { true, 0xd031, 0xd031 }, +/* 0xd032 */ { true, 0xd032, 0xd032 }, +/* 0xd033 */ { true, 0xd033, 0xd033 }, +/* 0xd034 */ { true, 0xd034, 0xd034 }, +/* 0xd035 */ { true, 0xd035, 0xd035 }, +/* 0xd036 */ { true, 0xd036, 0xd036 }, +/* 0xd037 */ { true, 0xd037, 0xd037 }, +/* 0xd038 */ { true, 0xd038, 0xd038 }, +/* 0xd039 */ { true, 0xd039, 0xd039 }, +/* 0xd03a */ { true, 0xd03a, 0xd03a }, +/* 0xd03b */ { true, 0xd03b, 0xd03b }, +/* 0xd03c */ { true, 0xd03c, 0xd03c }, +/* 0xd03d */ { true, 0xd03d, 0xd03d }, +/* 0xd03e */ { true, 0xd03e, 0xd03e }, +/* 0xd03f */ { true, 0xd03f, 0xd03f }, +/* 0xd040 */ { true, 0xd040, 0xd040 }, +/* 0xd041 */ { true, 0xd041, 0xd041 }, +/* 0xd042 */ { true, 0xd042, 0xd042 }, +/* 0xd043 */ { true, 0xd043, 0xd043 }, +/* 0xd044 */ { true, 0xd044, 0xd044 }, +/* 0xd045 */ { true, 0xd045, 0xd045 }, +/* 0xd046 */ { true, 0xd046, 0xd046 }, +/* 0xd047 */ { true, 0xd047, 0xd047 }, +/* 0xd048 */ { true, 0xd048, 0xd048 }, +/* 0xd049 */ { true, 0xd049, 0xd049 }, +/* 0xd04a */ { true, 0xd04a, 0xd04a }, +/* 0xd04b */ { true, 0xd04b, 0xd04b }, +/* 0xd04c */ { true, 0xd04c, 0xd04c }, +/* 0xd04d */ { true, 0xd04d, 0xd04d }, +/* 0xd04e */ { true, 0xd04e, 0xd04e }, +/* 0xd04f */ { true, 0xd04f, 0xd04f }, +/* 0xd050 */ { true, 0xd050, 0xd050 }, +/* 0xd051 */ { true, 0xd051, 0xd051 }, +/* 0xd052 */ { true, 0xd052, 0xd052 }, +/* 0xd053 */ { true, 0xd053, 0xd053 }, +/* 0xd054 */ { true, 0xd054, 0xd054 }, +/* 0xd055 */ { true, 0xd055, 0xd055 }, +/* 0xd056 */ { true, 0xd056, 0xd056 }, +/* 0xd057 */ { true, 0xd057, 0xd057 }, +/* 0xd058 */ { true, 0xd058, 0xd058 }, +/* 0xd059 */ { true, 0xd059, 0xd059 }, +/* 0xd05a */ { true, 0xd05a, 0xd05a }, +/* 0xd05b */ { true, 0xd05b, 0xd05b }, +/* 0xd05c */ { true, 0xd05c, 0xd05c }, +/* 0xd05d */ { true, 0xd05d, 0xd05d }, +/* 0xd05e */ { true, 0xd05e, 0xd05e }, +/* 0xd05f */ { true, 0xd05f, 0xd05f }, +/* 0xd060 */ { true, 0xd060, 0xd060 }, +/* 0xd061 */ { true, 0xd061, 0xd061 }, +/* 0xd062 */ { true, 0xd062, 0xd062 }, +/* 0xd063 */ { true, 0xd063, 0xd063 }, +/* 0xd064 */ { true, 0xd064, 0xd064 }, +/* 0xd065 */ { true, 0xd065, 0xd065 }, +/* 0xd066 */ { true, 0xd066, 0xd066 }, +/* 0xd067 */ { true, 0xd067, 0xd067 }, +/* 0xd068 */ { true, 0xd068, 0xd068 }, +/* 0xd069 */ { true, 0xd069, 0xd069 }, +/* 0xd06a */ { true, 0xd06a, 0xd06a }, +/* 0xd06b */ { true, 0xd06b, 0xd06b }, +/* 0xd06c */ { true, 0xd06c, 0xd06c }, +/* 0xd06d */ { true, 0xd06d, 0xd06d }, +/* 0xd06e */ { true, 0xd06e, 0xd06e }, +/* 0xd06f */ { true, 0xd06f, 0xd06f }, +/* 0xd070 */ { true, 0xd070, 0xd070 }, +/* 0xd071 */ { true, 0xd071, 0xd071 }, +/* 0xd072 */ { true, 0xd072, 0xd072 }, +/* 0xd073 */ { true, 0xd073, 0xd073 }, +/* 0xd074 */ { true, 0xd074, 0xd074 }, +/* 0xd075 */ { true, 0xd075, 0xd075 }, +/* 0xd076 */ { true, 0xd076, 0xd076 }, +/* 0xd077 */ { true, 0xd077, 0xd077 }, +/* 0xd078 */ { true, 0xd078, 0xd078 }, +/* 0xd079 */ { true, 0xd079, 0xd079 }, +/* 0xd07a */ { true, 0xd07a, 0xd07a }, +/* 0xd07b */ { true, 0xd07b, 0xd07b }, +/* 0xd07c */ { true, 0xd07c, 0xd07c }, +/* 0xd07d */ { true, 0xd07d, 0xd07d }, +/* 0xd07e */ { true, 0xd07e, 0xd07e }, +/* 0xd07f */ { true, 0xd07f, 0xd07f }, +/* 0xd080 */ { true, 0xd080, 0xd080 }, +/* 0xd081 */ { true, 0xd081, 0xd081 }, +/* 0xd082 */ { true, 0xd082, 0xd082 }, +/* 0xd083 */ { true, 0xd083, 0xd083 }, +/* 0xd084 */ { true, 0xd084, 0xd084 }, +/* 0xd085 */ { true, 0xd085, 0xd085 }, +/* 0xd086 */ { true, 0xd086, 0xd086 }, +/* 0xd087 */ { true, 0xd087, 0xd087 }, +/* 0xd088 */ { true, 0xd088, 0xd088 }, +/* 0xd089 */ { true, 0xd089, 0xd089 }, +/* 0xd08a */ { true, 0xd08a, 0xd08a }, +/* 0xd08b */ { true, 0xd08b, 0xd08b }, +/* 0xd08c */ { true, 0xd08c, 0xd08c }, +/* 0xd08d */ { true, 0xd08d, 0xd08d }, +/* 0xd08e */ { true, 0xd08e, 0xd08e }, +/* 0xd08f */ { true, 0xd08f, 0xd08f }, +/* 0xd090 */ { true, 0xd090, 0xd090 }, +/* 0xd091 */ { true, 0xd091, 0xd091 }, +/* 0xd092 */ { true, 0xd092, 0xd092 }, +/* 0xd093 */ { true, 0xd093, 0xd093 }, +/* 0xd094 */ { true, 0xd094, 0xd094 }, +/* 0xd095 */ { true, 0xd095, 0xd095 }, +/* 0xd096 */ { true, 0xd096, 0xd096 }, +/* 0xd097 */ { true, 0xd097, 0xd097 }, +/* 0xd098 */ { true, 0xd098, 0xd098 }, +/* 0xd099 */ { true, 0xd099, 0xd099 }, +/* 0xd09a */ { true, 0xd09a, 0xd09a }, +/* 0xd09b */ { true, 0xd09b, 0xd09b }, +/* 0xd09c */ { true, 0xd09c, 0xd09c }, +/* 0xd09d */ { true, 0xd09d, 0xd09d }, +/* 0xd09e */ { true, 0xd09e, 0xd09e }, +/* 0xd09f */ { true, 0xd09f, 0xd09f }, +/* 0xd0a0 */ { true, 0xd0a0, 0xd0a0 }, +/* 0xd0a1 */ { true, 0xd0a1, 0xd0a1 }, +/* 0xd0a2 */ { true, 0xd0a2, 0xd0a2 }, +/* 0xd0a3 */ { true, 0xd0a3, 0xd0a3 }, +/* 0xd0a4 */ { true, 0xd0a4, 0xd0a4 }, +/* 0xd0a5 */ { true, 0xd0a5, 0xd0a5 }, +/* 0xd0a6 */ { true, 0xd0a6, 0xd0a6 }, +/* 0xd0a7 */ { true, 0xd0a7, 0xd0a7 }, +/* 0xd0a8 */ { true, 0xd0a8, 0xd0a8 }, +/* 0xd0a9 */ { true, 0xd0a9, 0xd0a9 }, +/* 0xd0aa */ { true, 0xd0aa, 0xd0aa }, +/* 0xd0ab */ { true, 0xd0ab, 0xd0ab }, +/* 0xd0ac */ { true, 0xd0ac, 0xd0ac }, +/* 0xd0ad */ { true, 0xd0ad, 0xd0ad }, +/* 0xd0ae */ { true, 0xd0ae, 0xd0ae }, +/* 0xd0af */ { true, 0xd0af, 0xd0af }, +/* 0xd0b0 */ { true, 0xd0b0, 0xd0b0 }, +/* 0xd0b1 */ { true, 0xd0b1, 0xd0b1 }, +/* 0xd0b2 */ { true, 0xd0b2, 0xd0b2 }, +/* 0xd0b3 */ { true, 0xd0b3, 0xd0b3 }, +/* 0xd0b4 */ { true, 0xd0b4, 0xd0b4 }, +/* 0xd0b5 */ { true, 0xd0b5, 0xd0b5 }, +/* 0xd0b6 */ { true, 0xd0b6, 0xd0b6 }, +/* 0xd0b7 */ { true, 0xd0b7, 0xd0b7 }, +/* 0xd0b8 */ { true, 0xd0b8, 0xd0b8 }, +/* 0xd0b9 */ { true, 0xd0b9, 0xd0b9 }, +/* 0xd0ba */ { true, 0xd0ba, 0xd0ba }, +/* 0xd0bb */ { true, 0xd0bb, 0xd0bb }, +/* 0xd0bc */ { true, 0xd0bc, 0xd0bc }, +/* 0xd0bd */ { true, 0xd0bd, 0xd0bd }, +/* 0xd0be */ { true, 0xd0be, 0xd0be }, +/* 0xd0bf */ { true, 0xd0bf, 0xd0bf }, +/* 0xd0c0 */ { true, 0xd0c0, 0xd0c0 }, +/* 0xd0c1 */ { true, 0xd0c1, 0xd0c1 }, +/* 0xd0c2 */ { true, 0xd0c2, 0xd0c2 }, +/* 0xd0c3 */ { true, 0xd0c3, 0xd0c3 }, +/* 0xd0c4 */ { true, 0xd0c4, 0xd0c4 }, +/* 0xd0c5 */ { true, 0xd0c5, 0xd0c5 }, +/* 0xd0c6 */ { true, 0xd0c6, 0xd0c6 }, +/* 0xd0c7 */ { true, 0xd0c7, 0xd0c7 }, +/* 0xd0c8 */ { true, 0xd0c8, 0xd0c8 }, +/* 0xd0c9 */ { true, 0xd0c9, 0xd0c9 }, +/* 0xd0ca */ { true, 0xd0ca, 0xd0ca }, +/* 0xd0cb */ { true, 0xd0cb, 0xd0cb }, +/* 0xd0cc */ { true, 0xd0cc, 0xd0cc }, +/* 0xd0cd */ { true, 0xd0cd, 0xd0cd }, +/* 0xd0ce */ { true, 0xd0ce, 0xd0ce }, +/* 0xd0cf */ { true, 0xd0cf, 0xd0cf }, +/* 0xd0d0 */ { true, 0xd0d0, 0xd0d0 }, +/* 0xd0d1 */ { true, 0xd0d1, 0xd0d1 }, +/* 0xd0d2 */ { true, 0xd0d2, 0xd0d2 }, +/* 0xd0d3 */ { true, 0xd0d3, 0xd0d3 }, +/* 0xd0d4 */ { true, 0xd0d4, 0xd0d4 }, +/* 0xd0d5 */ { true, 0xd0d5, 0xd0d5 }, +/* 0xd0d6 */ { true, 0xd0d6, 0xd0d6 }, +/* 0xd0d7 */ { true, 0xd0d7, 0xd0d7 }, +/* 0xd0d8 */ { true, 0xd0d8, 0xd0d8 }, +/* 0xd0d9 */ { true, 0xd0d9, 0xd0d9 }, +/* 0xd0da */ { true, 0xd0da, 0xd0da }, +/* 0xd0db */ { true, 0xd0db, 0xd0db }, +/* 0xd0dc */ { true, 0xd0dc, 0xd0dc }, +/* 0xd0dd */ { true, 0xd0dd, 0xd0dd }, +/* 0xd0de */ { true, 0xd0de, 0xd0de }, +/* 0xd0df */ { true, 0xd0df, 0xd0df }, +/* 0xd0e0 */ { true, 0xd0e0, 0xd0e0 }, +/* 0xd0e1 */ { true, 0xd0e1, 0xd0e1 }, +/* 0xd0e2 */ { true, 0xd0e2, 0xd0e2 }, +/* 0xd0e3 */ { true, 0xd0e3, 0xd0e3 }, +/* 0xd0e4 */ { true, 0xd0e4, 0xd0e4 }, +/* 0xd0e5 */ { true, 0xd0e5, 0xd0e5 }, +/* 0xd0e6 */ { true, 0xd0e6, 0xd0e6 }, +/* 0xd0e7 */ { true, 0xd0e7, 0xd0e7 }, +/* 0xd0e8 */ { true, 0xd0e8, 0xd0e8 }, +/* 0xd0e9 */ { true, 0xd0e9, 0xd0e9 }, +/* 0xd0ea */ { true, 0xd0ea, 0xd0ea }, +/* 0xd0eb */ { true, 0xd0eb, 0xd0eb }, +/* 0xd0ec */ { true, 0xd0ec, 0xd0ec }, +/* 0xd0ed */ { true, 0xd0ed, 0xd0ed }, +/* 0xd0ee */ { true, 0xd0ee, 0xd0ee }, +/* 0xd0ef */ { true, 0xd0ef, 0xd0ef }, +/* 0xd0f0 */ { true, 0xd0f0, 0xd0f0 }, +/* 0xd0f1 */ { true, 0xd0f1, 0xd0f1 }, +/* 0xd0f2 */ { true, 0xd0f2, 0xd0f2 }, +/* 0xd0f3 */ { true, 0xd0f3, 0xd0f3 }, +/* 0xd0f4 */ { true, 0xd0f4, 0xd0f4 }, +/* 0xd0f5 */ { true, 0xd0f5, 0xd0f5 }, +/* 0xd0f6 */ { true, 0xd0f6, 0xd0f6 }, +/* 0xd0f7 */ { true, 0xd0f7, 0xd0f7 }, +/* 0xd0f8 */ { true, 0xd0f8, 0xd0f8 }, +/* 0xd0f9 */ { true, 0xd0f9, 0xd0f9 }, +/* 0xd0fa */ { true, 0xd0fa, 0xd0fa }, +/* 0xd0fb */ { true, 0xd0fb, 0xd0fb }, +/* 0xd0fc */ { true, 0xd0fc, 0xd0fc }, +/* 0xd0fd */ { true, 0xd0fd, 0xd0fd }, +/* 0xd0fe */ { true, 0xd0fe, 0xd0fe }, +/* 0xd0ff */ { true, 0xd0ff, 0xd0ff }, +/* 0xd100 */ { true, 0xd100, 0xd100 }, +/* 0xd101 */ { true, 0xd101, 0xd101 }, +/* 0xd102 */ { true, 0xd102, 0xd102 }, +/* 0xd103 */ { true, 0xd103, 0xd103 }, +/* 0xd104 */ { true, 0xd104, 0xd104 }, +/* 0xd105 */ { true, 0xd105, 0xd105 }, +/* 0xd106 */ { true, 0xd106, 0xd106 }, +/* 0xd107 */ { true, 0xd107, 0xd107 }, +/* 0xd108 */ { true, 0xd108, 0xd108 }, +/* 0xd109 */ { true, 0xd109, 0xd109 }, +/* 0xd10a */ { true, 0xd10a, 0xd10a }, +/* 0xd10b */ { true, 0xd10b, 0xd10b }, +/* 0xd10c */ { true, 0xd10c, 0xd10c }, +/* 0xd10d */ { true, 0xd10d, 0xd10d }, +/* 0xd10e */ { true, 0xd10e, 0xd10e }, +/* 0xd10f */ { true, 0xd10f, 0xd10f }, +/* 0xd110 */ { true, 0xd110, 0xd110 }, +/* 0xd111 */ { true, 0xd111, 0xd111 }, +/* 0xd112 */ { true, 0xd112, 0xd112 }, +/* 0xd113 */ { true, 0xd113, 0xd113 }, +/* 0xd114 */ { true, 0xd114, 0xd114 }, +/* 0xd115 */ { true, 0xd115, 0xd115 }, +/* 0xd116 */ { true, 0xd116, 0xd116 }, +/* 0xd117 */ { true, 0xd117, 0xd117 }, +/* 0xd118 */ { true, 0xd118, 0xd118 }, +/* 0xd119 */ { true, 0xd119, 0xd119 }, +/* 0xd11a */ { true, 0xd11a, 0xd11a }, +/* 0xd11b */ { true, 0xd11b, 0xd11b }, +/* 0xd11c */ { true, 0xd11c, 0xd11c }, +/* 0xd11d */ { true, 0xd11d, 0xd11d }, +/* 0xd11e */ { true, 0xd11e, 0xd11e }, +/* 0xd11f */ { true, 0xd11f, 0xd11f }, +/* 0xd120 */ { true, 0xd120, 0xd120 }, +/* 0xd121 */ { true, 0xd121, 0xd121 }, +/* 0xd122 */ { true, 0xd122, 0xd122 }, +/* 0xd123 */ { true, 0xd123, 0xd123 }, +/* 0xd124 */ { true, 0xd124, 0xd124 }, +/* 0xd125 */ { true, 0xd125, 0xd125 }, +/* 0xd126 */ { true, 0xd126, 0xd126 }, +/* 0xd127 */ { true, 0xd127, 0xd127 }, +/* 0xd128 */ { true, 0xd128, 0xd128 }, +/* 0xd129 */ { true, 0xd129, 0xd129 }, +/* 0xd12a */ { true, 0xd12a, 0xd12a }, +/* 0xd12b */ { true, 0xd12b, 0xd12b }, +/* 0xd12c */ { true, 0xd12c, 0xd12c }, +/* 0xd12d */ { true, 0xd12d, 0xd12d }, +/* 0xd12e */ { true, 0xd12e, 0xd12e }, +/* 0xd12f */ { true, 0xd12f, 0xd12f }, +/* 0xd130 */ { true, 0xd130, 0xd130 }, +/* 0xd131 */ { true, 0xd131, 0xd131 }, +/* 0xd132 */ { true, 0xd132, 0xd132 }, +/* 0xd133 */ { true, 0xd133, 0xd133 }, +/* 0xd134 */ { true, 0xd134, 0xd134 }, +/* 0xd135 */ { true, 0xd135, 0xd135 }, +/* 0xd136 */ { true, 0xd136, 0xd136 }, +/* 0xd137 */ { true, 0xd137, 0xd137 }, +/* 0xd138 */ { true, 0xd138, 0xd138 }, +/* 0xd139 */ { true, 0xd139, 0xd139 }, +/* 0xd13a */ { true, 0xd13a, 0xd13a }, +/* 0xd13b */ { true, 0xd13b, 0xd13b }, +/* 0xd13c */ { true, 0xd13c, 0xd13c }, +/* 0xd13d */ { true, 0xd13d, 0xd13d }, +/* 0xd13e */ { true, 0xd13e, 0xd13e }, +/* 0xd13f */ { true, 0xd13f, 0xd13f }, +/* 0xd140 */ { true, 0xd140, 0xd140 }, +/* 0xd141 */ { true, 0xd141, 0xd141 }, +/* 0xd142 */ { true, 0xd142, 0xd142 }, +/* 0xd143 */ { true, 0xd143, 0xd143 }, +/* 0xd144 */ { true, 0xd144, 0xd144 }, +/* 0xd145 */ { true, 0xd145, 0xd145 }, +/* 0xd146 */ { true, 0xd146, 0xd146 }, +/* 0xd147 */ { true, 0xd147, 0xd147 }, +/* 0xd148 */ { true, 0xd148, 0xd148 }, +/* 0xd149 */ { true, 0xd149, 0xd149 }, +/* 0xd14a */ { true, 0xd14a, 0xd14a }, +/* 0xd14b */ { true, 0xd14b, 0xd14b }, +/* 0xd14c */ { true, 0xd14c, 0xd14c }, +/* 0xd14d */ { true, 0xd14d, 0xd14d }, +/* 0xd14e */ { true, 0xd14e, 0xd14e }, +/* 0xd14f */ { true, 0xd14f, 0xd14f }, +/* 0xd150 */ { true, 0xd150, 0xd150 }, +/* 0xd151 */ { true, 0xd151, 0xd151 }, +/* 0xd152 */ { true, 0xd152, 0xd152 }, +/* 0xd153 */ { true, 0xd153, 0xd153 }, +/* 0xd154 */ { true, 0xd154, 0xd154 }, +/* 0xd155 */ { true, 0xd155, 0xd155 }, +/* 0xd156 */ { true, 0xd156, 0xd156 }, +/* 0xd157 */ { true, 0xd157, 0xd157 }, +/* 0xd158 */ { true, 0xd158, 0xd158 }, +/* 0xd159 */ { true, 0xd159, 0xd159 }, +/* 0xd15a */ { true, 0xd15a, 0xd15a }, +/* 0xd15b */ { true, 0xd15b, 0xd15b }, +/* 0xd15c */ { true, 0xd15c, 0xd15c }, +/* 0xd15d */ { true, 0xd15d, 0xd15d }, +/* 0xd15e */ { true, 0xd15e, 0xd15e }, +/* 0xd15f */ { true, 0xd15f, 0xd15f }, +/* 0xd160 */ { true, 0xd160, 0xd160 }, +/* 0xd161 */ { true, 0xd161, 0xd161 }, +/* 0xd162 */ { true, 0xd162, 0xd162 }, +/* 0xd163 */ { true, 0xd163, 0xd163 }, +/* 0xd164 */ { true, 0xd164, 0xd164 }, +/* 0xd165 */ { true, 0xd165, 0xd165 }, +/* 0xd166 */ { true, 0xd166, 0xd166 }, +/* 0xd167 */ { true, 0xd167, 0xd167 }, +/* 0xd168 */ { true, 0xd168, 0xd168 }, +/* 0xd169 */ { true, 0xd169, 0xd169 }, +/* 0xd16a */ { true, 0xd16a, 0xd16a }, +/* 0xd16b */ { true, 0xd16b, 0xd16b }, +/* 0xd16c */ { true, 0xd16c, 0xd16c }, +/* 0xd16d */ { true, 0xd16d, 0xd16d }, +/* 0xd16e */ { true, 0xd16e, 0xd16e }, +/* 0xd16f */ { true, 0xd16f, 0xd16f }, +/* 0xd170 */ { true, 0xd170, 0xd170 }, +/* 0xd171 */ { true, 0xd171, 0xd171 }, +/* 0xd172 */ { true, 0xd172, 0xd172 }, +/* 0xd173 */ { true, 0xd173, 0xd173 }, +/* 0xd174 */ { true, 0xd174, 0xd174 }, +/* 0xd175 */ { true, 0xd175, 0xd175 }, +/* 0xd176 */ { true, 0xd176, 0xd176 }, +/* 0xd177 */ { true, 0xd177, 0xd177 }, +/* 0xd178 */ { true, 0xd178, 0xd178 }, +/* 0xd179 */ { true, 0xd179, 0xd179 }, +/* 0xd17a */ { true, 0xd17a, 0xd17a }, +/* 0xd17b */ { true, 0xd17b, 0xd17b }, +/* 0xd17c */ { true, 0xd17c, 0xd17c }, +/* 0xd17d */ { true, 0xd17d, 0xd17d }, +/* 0xd17e */ { true, 0xd17e, 0xd17e }, +/* 0xd17f */ { true, 0xd17f, 0xd17f }, +/* 0xd180 */ { true, 0xd180, 0xd180 }, +/* 0xd181 */ { true, 0xd181, 0xd181 }, +/* 0xd182 */ { true, 0xd182, 0xd182 }, +/* 0xd183 */ { true, 0xd183, 0xd183 }, +/* 0xd184 */ { true, 0xd184, 0xd184 }, +/* 0xd185 */ { true, 0xd185, 0xd185 }, +/* 0xd186 */ { true, 0xd186, 0xd186 }, +/* 0xd187 */ { true, 0xd187, 0xd187 }, +/* 0xd188 */ { true, 0xd188, 0xd188 }, +/* 0xd189 */ { true, 0xd189, 0xd189 }, +/* 0xd18a */ { true, 0xd18a, 0xd18a }, +/* 0xd18b */ { true, 0xd18b, 0xd18b }, +/* 0xd18c */ { true, 0xd18c, 0xd18c }, +/* 0xd18d */ { true, 0xd18d, 0xd18d }, +/* 0xd18e */ { true, 0xd18e, 0xd18e }, +/* 0xd18f */ { true, 0xd18f, 0xd18f }, +/* 0xd190 */ { true, 0xd190, 0xd190 }, +/* 0xd191 */ { true, 0xd191, 0xd191 }, +/* 0xd192 */ { true, 0xd192, 0xd192 }, +/* 0xd193 */ { true, 0xd193, 0xd193 }, +/* 0xd194 */ { true, 0xd194, 0xd194 }, +/* 0xd195 */ { true, 0xd195, 0xd195 }, +/* 0xd196 */ { true, 0xd196, 0xd196 }, +/* 0xd197 */ { true, 0xd197, 0xd197 }, +/* 0xd198 */ { true, 0xd198, 0xd198 }, +/* 0xd199 */ { true, 0xd199, 0xd199 }, +/* 0xd19a */ { true, 0xd19a, 0xd19a }, +/* 0xd19b */ { true, 0xd19b, 0xd19b }, +/* 0xd19c */ { true, 0xd19c, 0xd19c }, +/* 0xd19d */ { true, 0xd19d, 0xd19d }, +/* 0xd19e */ { true, 0xd19e, 0xd19e }, +/* 0xd19f */ { true, 0xd19f, 0xd19f }, +/* 0xd1a0 */ { true, 0xd1a0, 0xd1a0 }, +/* 0xd1a1 */ { true, 0xd1a1, 0xd1a1 }, +/* 0xd1a2 */ { true, 0xd1a2, 0xd1a2 }, +/* 0xd1a3 */ { true, 0xd1a3, 0xd1a3 }, +/* 0xd1a4 */ { true, 0xd1a4, 0xd1a4 }, +/* 0xd1a5 */ { true, 0xd1a5, 0xd1a5 }, +/* 0xd1a6 */ { true, 0xd1a6, 0xd1a6 }, +/* 0xd1a7 */ { true, 0xd1a7, 0xd1a7 }, +/* 0xd1a8 */ { true, 0xd1a8, 0xd1a8 }, +/* 0xd1a9 */ { true, 0xd1a9, 0xd1a9 }, +/* 0xd1aa */ { true, 0xd1aa, 0xd1aa }, +/* 0xd1ab */ { true, 0xd1ab, 0xd1ab }, +/* 0xd1ac */ { true, 0xd1ac, 0xd1ac }, +/* 0xd1ad */ { true, 0xd1ad, 0xd1ad }, +/* 0xd1ae */ { true, 0xd1ae, 0xd1ae }, +/* 0xd1af */ { true, 0xd1af, 0xd1af }, +/* 0xd1b0 */ { true, 0xd1b0, 0xd1b0 }, +/* 0xd1b1 */ { true, 0xd1b1, 0xd1b1 }, +/* 0xd1b2 */ { true, 0xd1b2, 0xd1b2 }, +/* 0xd1b3 */ { true, 0xd1b3, 0xd1b3 }, +/* 0xd1b4 */ { true, 0xd1b4, 0xd1b4 }, +/* 0xd1b5 */ { true, 0xd1b5, 0xd1b5 }, +/* 0xd1b6 */ { true, 0xd1b6, 0xd1b6 }, +/* 0xd1b7 */ { true, 0xd1b7, 0xd1b7 }, +/* 0xd1b8 */ { true, 0xd1b8, 0xd1b8 }, +/* 0xd1b9 */ { true, 0xd1b9, 0xd1b9 }, +/* 0xd1ba */ { true, 0xd1ba, 0xd1ba }, +/* 0xd1bb */ { true, 0xd1bb, 0xd1bb }, +/* 0xd1bc */ { true, 0xd1bc, 0xd1bc }, +/* 0xd1bd */ { true, 0xd1bd, 0xd1bd }, +/* 0xd1be */ { true, 0xd1be, 0xd1be }, +/* 0xd1bf */ { true, 0xd1bf, 0xd1bf }, +/* 0xd1c0 */ { true, 0xd1c0, 0xd1c0 }, +/* 0xd1c1 */ { true, 0xd1c1, 0xd1c1 }, +/* 0xd1c2 */ { true, 0xd1c2, 0xd1c2 }, +/* 0xd1c3 */ { true, 0xd1c3, 0xd1c3 }, +/* 0xd1c4 */ { true, 0xd1c4, 0xd1c4 }, +/* 0xd1c5 */ { true, 0xd1c5, 0xd1c5 }, +/* 0xd1c6 */ { true, 0xd1c6, 0xd1c6 }, +/* 0xd1c7 */ { true, 0xd1c7, 0xd1c7 }, +/* 0xd1c8 */ { true, 0xd1c8, 0xd1c8 }, +/* 0xd1c9 */ { true, 0xd1c9, 0xd1c9 }, +/* 0xd1ca */ { true, 0xd1ca, 0xd1ca }, +/* 0xd1cb */ { true, 0xd1cb, 0xd1cb }, +/* 0xd1cc */ { true, 0xd1cc, 0xd1cc }, +/* 0xd1cd */ { true, 0xd1cd, 0xd1cd }, +/* 0xd1ce */ { true, 0xd1ce, 0xd1ce }, +/* 0xd1cf */ { true, 0xd1cf, 0xd1cf }, +/* 0xd1d0 */ { true, 0xd1d0, 0xd1d0 }, +/* 0xd1d1 */ { true, 0xd1d1, 0xd1d1 }, +/* 0xd1d2 */ { true, 0xd1d2, 0xd1d2 }, +/* 0xd1d3 */ { true, 0xd1d3, 0xd1d3 }, +/* 0xd1d4 */ { true, 0xd1d4, 0xd1d4 }, +/* 0xd1d5 */ { true, 0xd1d5, 0xd1d5 }, +/* 0xd1d6 */ { true, 0xd1d6, 0xd1d6 }, +/* 0xd1d7 */ { true, 0xd1d7, 0xd1d7 }, +/* 0xd1d8 */ { true, 0xd1d8, 0xd1d8 }, +/* 0xd1d9 */ { true, 0xd1d9, 0xd1d9 }, +/* 0xd1da */ { true, 0xd1da, 0xd1da }, +/* 0xd1db */ { true, 0xd1db, 0xd1db }, +/* 0xd1dc */ { true, 0xd1dc, 0xd1dc }, +/* 0xd1dd */ { true, 0xd1dd, 0xd1dd }, +/* 0xd1de */ { true, 0xd1de, 0xd1de }, +/* 0xd1df */ { true, 0xd1df, 0xd1df }, +/* 0xd1e0 */ { true, 0xd1e0, 0xd1e0 }, +/* 0xd1e1 */ { true, 0xd1e1, 0xd1e1 }, +/* 0xd1e2 */ { true, 0xd1e2, 0xd1e2 }, +/* 0xd1e3 */ { true, 0xd1e3, 0xd1e3 }, +/* 0xd1e4 */ { true, 0xd1e4, 0xd1e4 }, +/* 0xd1e5 */ { true, 0xd1e5, 0xd1e5 }, +/* 0xd1e6 */ { true, 0xd1e6, 0xd1e6 }, +/* 0xd1e7 */ { true, 0xd1e7, 0xd1e7 }, +/* 0xd1e8 */ { true, 0xd1e8, 0xd1e8 }, +/* 0xd1e9 */ { true, 0xd1e9, 0xd1e9 }, +/* 0xd1ea */ { true, 0xd1ea, 0xd1ea }, +/* 0xd1eb */ { true, 0xd1eb, 0xd1eb }, +/* 0xd1ec */ { true, 0xd1ec, 0xd1ec }, +/* 0xd1ed */ { true, 0xd1ed, 0xd1ed }, +/* 0xd1ee */ { true, 0xd1ee, 0xd1ee }, +/* 0xd1ef */ { true, 0xd1ef, 0xd1ef }, +/* 0xd1f0 */ { true, 0xd1f0, 0xd1f0 }, +/* 0xd1f1 */ { true, 0xd1f1, 0xd1f1 }, +/* 0xd1f2 */ { true, 0xd1f2, 0xd1f2 }, +/* 0xd1f3 */ { true, 0xd1f3, 0xd1f3 }, +/* 0xd1f4 */ { true, 0xd1f4, 0xd1f4 }, +/* 0xd1f5 */ { true, 0xd1f5, 0xd1f5 }, +/* 0xd1f6 */ { true, 0xd1f6, 0xd1f6 }, +/* 0xd1f7 */ { true, 0xd1f7, 0xd1f7 }, +/* 0xd1f8 */ { true, 0xd1f8, 0xd1f8 }, +/* 0xd1f9 */ { true, 0xd1f9, 0xd1f9 }, +/* 0xd1fa */ { true, 0xd1fa, 0xd1fa }, +/* 0xd1fb */ { true, 0xd1fb, 0xd1fb }, +/* 0xd1fc */ { true, 0xd1fc, 0xd1fc }, +/* 0xd1fd */ { true, 0xd1fd, 0xd1fd }, +/* 0xd1fe */ { true, 0xd1fe, 0xd1fe }, +/* 0xd1ff */ { true, 0xd1ff, 0xd1ff }, +/* 0xd200 */ { true, 0xd200, 0xd200 }, +/* 0xd201 */ { true, 0xd201, 0xd201 }, +/* 0xd202 */ { true, 0xd202, 0xd202 }, +/* 0xd203 */ { true, 0xd203, 0xd203 }, +/* 0xd204 */ { true, 0xd204, 0xd204 }, +/* 0xd205 */ { true, 0xd205, 0xd205 }, +/* 0xd206 */ { true, 0xd206, 0xd206 }, +/* 0xd207 */ { true, 0xd207, 0xd207 }, +/* 0xd208 */ { true, 0xd208, 0xd208 }, +/* 0xd209 */ { true, 0xd209, 0xd209 }, +/* 0xd20a */ { true, 0xd20a, 0xd20a }, +/* 0xd20b */ { true, 0xd20b, 0xd20b }, +/* 0xd20c */ { true, 0xd20c, 0xd20c }, +/* 0xd20d */ { true, 0xd20d, 0xd20d }, +/* 0xd20e */ { true, 0xd20e, 0xd20e }, +/* 0xd20f */ { true, 0xd20f, 0xd20f }, +/* 0xd210 */ { true, 0xd210, 0xd210 }, +/* 0xd211 */ { true, 0xd211, 0xd211 }, +/* 0xd212 */ { true, 0xd212, 0xd212 }, +/* 0xd213 */ { true, 0xd213, 0xd213 }, +/* 0xd214 */ { true, 0xd214, 0xd214 }, +/* 0xd215 */ { true, 0xd215, 0xd215 }, +/* 0xd216 */ { true, 0xd216, 0xd216 }, +/* 0xd217 */ { true, 0xd217, 0xd217 }, +/* 0xd218 */ { true, 0xd218, 0xd218 }, +/* 0xd219 */ { true, 0xd219, 0xd219 }, +/* 0xd21a */ { true, 0xd21a, 0xd21a }, +/* 0xd21b */ { true, 0xd21b, 0xd21b }, +/* 0xd21c */ { true, 0xd21c, 0xd21c }, +/* 0xd21d */ { true, 0xd21d, 0xd21d }, +/* 0xd21e */ { true, 0xd21e, 0xd21e }, +/* 0xd21f */ { true, 0xd21f, 0xd21f }, +/* 0xd220 */ { true, 0xd220, 0xd220 }, +/* 0xd221 */ { true, 0xd221, 0xd221 }, +/* 0xd222 */ { true, 0xd222, 0xd222 }, +/* 0xd223 */ { true, 0xd223, 0xd223 }, +/* 0xd224 */ { true, 0xd224, 0xd224 }, +/* 0xd225 */ { true, 0xd225, 0xd225 }, +/* 0xd226 */ { true, 0xd226, 0xd226 }, +/* 0xd227 */ { true, 0xd227, 0xd227 }, +/* 0xd228 */ { true, 0xd228, 0xd228 }, +/* 0xd229 */ { true, 0xd229, 0xd229 }, +/* 0xd22a */ { true, 0xd22a, 0xd22a }, +/* 0xd22b */ { true, 0xd22b, 0xd22b }, +/* 0xd22c */ { true, 0xd22c, 0xd22c }, +/* 0xd22d */ { true, 0xd22d, 0xd22d }, +/* 0xd22e */ { true, 0xd22e, 0xd22e }, +/* 0xd22f */ { true, 0xd22f, 0xd22f }, +/* 0xd230 */ { true, 0xd230, 0xd230 }, +/* 0xd231 */ { true, 0xd231, 0xd231 }, +/* 0xd232 */ { true, 0xd232, 0xd232 }, +/* 0xd233 */ { true, 0xd233, 0xd233 }, +/* 0xd234 */ { true, 0xd234, 0xd234 }, +/* 0xd235 */ { true, 0xd235, 0xd235 }, +/* 0xd236 */ { true, 0xd236, 0xd236 }, +/* 0xd237 */ { true, 0xd237, 0xd237 }, +/* 0xd238 */ { true, 0xd238, 0xd238 }, +/* 0xd239 */ { true, 0xd239, 0xd239 }, +/* 0xd23a */ { true, 0xd23a, 0xd23a }, +/* 0xd23b */ { true, 0xd23b, 0xd23b }, +/* 0xd23c */ { true, 0xd23c, 0xd23c }, +/* 0xd23d */ { true, 0xd23d, 0xd23d }, +/* 0xd23e */ { true, 0xd23e, 0xd23e }, +/* 0xd23f */ { true, 0xd23f, 0xd23f }, +/* 0xd240 */ { true, 0xd240, 0xd240 }, +/* 0xd241 */ { true, 0xd241, 0xd241 }, +/* 0xd242 */ { true, 0xd242, 0xd242 }, +/* 0xd243 */ { true, 0xd243, 0xd243 }, +/* 0xd244 */ { true, 0xd244, 0xd244 }, +/* 0xd245 */ { true, 0xd245, 0xd245 }, +/* 0xd246 */ { true, 0xd246, 0xd246 }, +/* 0xd247 */ { true, 0xd247, 0xd247 }, +/* 0xd248 */ { true, 0xd248, 0xd248 }, +/* 0xd249 */ { true, 0xd249, 0xd249 }, +/* 0xd24a */ { true, 0xd24a, 0xd24a }, +/* 0xd24b */ { true, 0xd24b, 0xd24b }, +/* 0xd24c */ { true, 0xd24c, 0xd24c }, +/* 0xd24d */ { true, 0xd24d, 0xd24d }, +/* 0xd24e */ { true, 0xd24e, 0xd24e }, +/* 0xd24f */ { true, 0xd24f, 0xd24f }, +/* 0xd250 */ { true, 0xd250, 0xd250 }, +/* 0xd251 */ { true, 0xd251, 0xd251 }, +/* 0xd252 */ { true, 0xd252, 0xd252 }, +/* 0xd253 */ { true, 0xd253, 0xd253 }, +/* 0xd254 */ { true, 0xd254, 0xd254 }, +/* 0xd255 */ { true, 0xd255, 0xd255 }, +/* 0xd256 */ { true, 0xd256, 0xd256 }, +/* 0xd257 */ { true, 0xd257, 0xd257 }, +/* 0xd258 */ { true, 0xd258, 0xd258 }, +/* 0xd259 */ { true, 0xd259, 0xd259 }, +/* 0xd25a */ { true, 0xd25a, 0xd25a }, +/* 0xd25b */ { true, 0xd25b, 0xd25b }, +/* 0xd25c */ { true, 0xd25c, 0xd25c }, +/* 0xd25d */ { true, 0xd25d, 0xd25d }, +/* 0xd25e */ { true, 0xd25e, 0xd25e }, +/* 0xd25f */ { true, 0xd25f, 0xd25f }, +/* 0xd260 */ { true, 0xd260, 0xd260 }, +/* 0xd261 */ { true, 0xd261, 0xd261 }, +/* 0xd262 */ { true, 0xd262, 0xd262 }, +/* 0xd263 */ { true, 0xd263, 0xd263 }, +/* 0xd264 */ { true, 0xd264, 0xd264 }, +/* 0xd265 */ { true, 0xd265, 0xd265 }, +/* 0xd266 */ { true, 0xd266, 0xd266 }, +/* 0xd267 */ { true, 0xd267, 0xd267 }, +/* 0xd268 */ { true, 0xd268, 0xd268 }, +/* 0xd269 */ { true, 0xd269, 0xd269 }, +/* 0xd26a */ { true, 0xd26a, 0xd26a }, +/* 0xd26b */ { true, 0xd26b, 0xd26b }, +/* 0xd26c */ { true, 0xd26c, 0xd26c }, +/* 0xd26d */ { true, 0xd26d, 0xd26d }, +/* 0xd26e */ { true, 0xd26e, 0xd26e }, +/* 0xd26f */ { true, 0xd26f, 0xd26f }, +/* 0xd270 */ { true, 0xd270, 0xd270 }, +/* 0xd271 */ { true, 0xd271, 0xd271 }, +/* 0xd272 */ { true, 0xd272, 0xd272 }, +/* 0xd273 */ { true, 0xd273, 0xd273 }, +/* 0xd274 */ { true, 0xd274, 0xd274 }, +/* 0xd275 */ { true, 0xd275, 0xd275 }, +/* 0xd276 */ { true, 0xd276, 0xd276 }, +/* 0xd277 */ { true, 0xd277, 0xd277 }, +/* 0xd278 */ { true, 0xd278, 0xd278 }, +/* 0xd279 */ { true, 0xd279, 0xd279 }, +/* 0xd27a */ { true, 0xd27a, 0xd27a }, +/* 0xd27b */ { true, 0xd27b, 0xd27b }, +/* 0xd27c */ { true, 0xd27c, 0xd27c }, +/* 0xd27d */ { true, 0xd27d, 0xd27d }, +/* 0xd27e */ { true, 0xd27e, 0xd27e }, +/* 0xd27f */ { true, 0xd27f, 0xd27f }, +/* 0xd280 */ { true, 0xd280, 0xd280 }, +/* 0xd281 */ { true, 0xd281, 0xd281 }, +/* 0xd282 */ { true, 0xd282, 0xd282 }, +/* 0xd283 */ { true, 0xd283, 0xd283 }, +/* 0xd284 */ { true, 0xd284, 0xd284 }, +/* 0xd285 */ { true, 0xd285, 0xd285 }, +/* 0xd286 */ { true, 0xd286, 0xd286 }, +/* 0xd287 */ { true, 0xd287, 0xd287 }, +/* 0xd288 */ { true, 0xd288, 0xd288 }, +/* 0xd289 */ { true, 0xd289, 0xd289 }, +/* 0xd28a */ { true, 0xd28a, 0xd28a }, +/* 0xd28b */ { true, 0xd28b, 0xd28b }, +/* 0xd28c */ { true, 0xd28c, 0xd28c }, +/* 0xd28d */ { true, 0xd28d, 0xd28d }, +/* 0xd28e */ { true, 0xd28e, 0xd28e }, +/* 0xd28f */ { true, 0xd28f, 0xd28f }, +/* 0xd290 */ { true, 0xd290, 0xd290 }, +/* 0xd291 */ { true, 0xd291, 0xd291 }, +/* 0xd292 */ { true, 0xd292, 0xd292 }, +/* 0xd293 */ { true, 0xd293, 0xd293 }, +/* 0xd294 */ { true, 0xd294, 0xd294 }, +/* 0xd295 */ { true, 0xd295, 0xd295 }, +/* 0xd296 */ { true, 0xd296, 0xd296 }, +/* 0xd297 */ { true, 0xd297, 0xd297 }, +/* 0xd298 */ { true, 0xd298, 0xd298 }, +/* 0xd299 */ { true, 0xd299, 0xd299 }, +/* 0xd29a */ { true, 0xd29a, 0xd29a }, +/* 0xd29b */ { true, 0xd29b, 0xd29b }, +/* 0xd29c */ { true, 0xd29c, 0xd29c }, +/* 0xd29d */ { true, 0xd29d, 0xd29d }, +/* 0xd29e */ { true, 0xd29e, 0xd29e }, +/* 0xd29f */ { true, 0xd29f, 0xd29f }, +/* 0xd2a0 */ { true, 0xd2a0, 0xd2a0 }, +/* 0xd2a1 */ { true, 0xd2a1, 0xd2a1 }, +/* 0xd2a2 */ { true, 0xd2a2, 0xd2a2 }, +/* 0xd2a3 */ { true, 0xd2a3, 0xd2a3 }, +/* 0xd2a4 */ { true, 0xd2a4, 0xd2a4 }, +/* 0xd2a5 */ { true, 0xd2a5, 0xd2a5 }, +/* 0xd2a6 */ { true, 0xd2a6, 0xd2a6 }, +/* 0xd2a7 */ { true, 0xd2a7, 0xd2a7 }, +/* 0xd2a8 */ { true, 0xd2a8, 0xd2a8 }, +/* 0xd2a9 */ { true, 0xd2a9, 0xd2a9 }, +/* 0xd2aa */ { true, 0xd2aa, 0xd2aa }, +/* 0xd2ab */ { true, 0xd2ab, 0xd2ab }, +/* 0xd2ac */ { true, 0xd2ac, 0xd2ac }, +/* 0xd2ad */ { true, 0xd2ad, 0xd2ad }, +/* 0xd2ae */ { true, 0xd2ae, 0xd2ae }, +/* 0xd2af */ { true, 0xd2af, 0xd2af }, +/* 0xd2b0 */ { true, 0xd2b0, 0xd2b0 }, +/* 0xd2b1 */ { true, 0xd2b1, 0xd2b1 }, +/* 0xd2b2 */ { true, 0xd2b2, 0xd2b2 }, +/* 0xd2b3 */ { true, 0xd2b3, 0xd2b3 }, +/* 0xd2b4 */ { true, 0xd2b4, 0xd2b4 }, +/* 0xd2b5 */ { true, 0xd2b5, 0xd2b5 }, +/* 0xd2b6 */ { true, 0xd2b6, 0xd2b6 }, +/* 0xd2b7 */ { true, 0xd2b7, 0xd2b7 }, +/* 0xd2b8 */ { true, 0xd2b8, 0xd2b8 }, +/* 0xd2b9 */ { true, 0xd2b9, 0xd2b9 }, +/* 0xd2ba */ { true, 0xd2ba, 0xd2ba }, +/* 0xd2bb */ { true, 0xd2bb, 0xd2bb }, +/* 0xd2bc */ { true, 0xd2bc, 0xd2bc }, +/* 0xd2bd */ { true, 0xd2bd, 0xd2bd }, +/* 0xd2be */ { true, 0xd2be, 0xd2be }, +/* 0xd2bf */ { true, 0xd2bf, 0xd2bf }, +/* 0xd2c0 */ { true, 0xd2c0, 0xd2c0 }, +/* 0xd2c1 */ { true, 0xd2c1, 0xd2c1 }, +/* 0xd2c2 */ { true, 0xd2c2, 0xd2c2 }, +/* 0xd2c3 */ { true, 0xd2c3, 0xd2c3 }, +/* 0xd2c4 */ { true, 0xd2c4, 0xd2c4 }, +/* 0xd2c5 */ { true, 0xd2c5, 0xd2c5 }, +/* 0xd2c6 */ { true, 0xd2c6, 0xd2c6 }, +/* 0xd2c7 */ { true, 0xd2c7, 0xd2c7 }, +/* 0xd2c8 */ { true, 0xd2c8, 0xd2c8 }, +/* 0xd2c9 */ { true, 0xd2c9, 0xd2c9 }, +/* 0xd2ca */ { true, 0xd2ca, 0xd2ca }, +/* 0xd2cb */ { true, 0xd2cb, 0xd2cb }, +/* 0xd2cc */ { true, 0xd2cc, 0xd2cc }, +/* 0xd2cd */ { true, 0xd2cd, 0xd2cd }, +/* 0xd2ce */ { true, 0xd2ce, 0xd2ce }, +/* 0xd2cf */ { true, 0xd2cf, 0xd2cf }, +/* 0xd2d0 */ { true, 0xd2d0, 0xd2d0 }, +/* 0xd2d1 */ { true, 0xd2d1, 0xd2d1 }, +/* 0xd2d2 */ { true, 0xd2d2, 0xd2d2 }, +/* 0xd2d3 */ { true, 0xd2d3, 0xd2d3 }, +/* 0xd2d4 */ { true, 0xd2d4, 0xd2d4 }, +/* 0xd2d5 */ { true, 0xd2d5, 0xd2d5 }, +/* 0xd2d6 */ { true, 0xd2d6, 0xd2d6 }, +/* 0xd2d7 */ { true, 0xd2d7, 0xd2d7 }, +/* 0xd2d8 */ { true, 0xd2d8, 0xd2d8 }, +/* 0xd2d9 */ { true, 0xd2d9, 0xd2d9 }, +/* 0xd2da */ { true, 0xd2da, 0xd2da }, +/* 0xd2db */ { true, 0xd2db, 0xd2db }, +/* 0xd2dc */ { true, 0xd2dc, 0xd2dc }, +/* 0xd2dd */ { true, 0xd2dd, 0xd2dd }, +/* 0xd2de */ { true, 0xd2de, 0xd2de }, +/* 0xd2df */ { true, 0xd2df, 0xd2df }, +/* 0xd2e0 */ { true, 0xd2e0, 0xd2e0 }, +/* 0xd2e1 */ { true, 0xd2e1, 0xd2e1 }, +/* 0xd2e2 */ { true, 0xd2e2, 0xd2e2 }, +/* 0xd2e3 */ { true, 0xd2e3, 0xd2e3 }, +/* 0xd2e4 */ { true, 0xd2e4, 0xd2e4 }, +/* 0xd2e5 */ { true, 0xd2e5, 0xd2e5 }, +/* 0xd2e6 */ { true, 0xd2e6, 0xd2e6 }, +/* 0xd2e7 */ { true, 0xd2e7, 0xd2e7 }, +/* 0xd2e8 */ { true, 0xd2e8, 0xd2e8 }, +/* 0xd2e9 */ { true, 0xd2e9, 0xd2e9 }, +/* 0xd2ea */ { true, 0xd2ea, 0xd2ea }, +/* 0xd2eb */ { true, 0xd2eb, 0xd2eb }, +/* 0xd2ec */ { true, 0xd2ec, 0xd2ec }, +/* 0xd2ed */ { true, 0xd2ed, 0xd2ed }, +/* 0xd2ee */ { true, 0xd2ee, 0xd2ee }, +/* 0xd2ef */ { true, 0xd2ef, 0xd2ef }, +/* 0xd2f0 */ { true, 0xd2f0, 0xd2f0 }, +/* 0xd2f1 */ { true, 0xd2f1, 0xd2f1 }, +/* 0xd2f2 */ { true, 0xd2f2, 0xd2f2 }, +/* 0xd2f3 */ { true, 0xd2f3, 0xd2f3 }, +/* 0xd2f4 */ { true, 0xd2f4, 0xd2f4 }, +/* 0xd2f5 */ { true, 0xd2f5, 0xd2f5 }, +/* 0xd2f6 */ { true, 0xd2f6, 0xd2f6 }, +/* 0xd2f7 */ { true, 0xd2f7, 0xd2f7 }, +/* 0xd2f8 */ { true, 0xd2f8, 0xd2f8 }, +/* 0xd2f9 */ { true, 0xd2f9, 0xd2f9 }, +/* 0xd2fa */ { true, 0xd2fa, 0xd2fa }, +/* 0xd2fb */ { true, 0xd2fb, 0xd2fb }, +/* 0xd2fc */ { true, 0xd2fc, 0xd2fc }, +/* 0xd2fd */ { true, 0xd2fd, 0xd2fd }, +/* 0xd2fe */ { true, 0xd2fe, 0xd2fe }, +/* 0xd2ff */ { true, 0xd2ff, 0xd2ff }, +/* 0xd300 */ { true, 0xd300, 0xd300 }, +/* 0xd301 */ { true, 0xd301, 0xd301 }, +/* 0xd302 */ { true, 0xd302, 0xd302 }, +/* 0xd303 */ { true, 0xd303, 0xd303 }, +/* 0xd304 */ { true, 0xd304, 0xd304 }, +/* 0xd305 */ { true, 0xd305, 0xd305 }, +/* 0xd306 */ { true, 0xd306, 0xd306 }, +/* 0xd307 */ { true, 0xd307, 0xd307 }, +/* 0xd308 */ { true, 0xd308, 0xd308 }, +/* 0xd309 */ { true, 0xd309, 0xd309 }, +/* 0xd30a */ { true, 0xd30a, 0xd30a }, +/* 0xd30b */ { true, 0xd30b, 0xd30b }, +/* 0xd30c */ { true, 0xd30c, 0xd30c }, +/* 0xd30d */ { true, 0xd30d, 0xd30d }, +/* 0xd30e */ { true, 0xd30e, 0xd30e }, +/* 0xd30f */ { true, 0xd30f, 0xd30f }, +/* 0xd310 */ { true, 0xd310, 0xd310 }, +/* 0xd311 */ { true, 0xd311, 0xd311 }, +/* 0xd312 */ { true, 0xd312, 0xd312 }, +/* 0xd313 */ { true, 0xd313, 0xd313 }, +/* 0xd314 */ { true, 0xd314, 0xd314 }, +/* 0xd315 */ { true, 0xd315, 0xd315 }, +/* 0xd316 */ { true, 0xd316, 0xd316 }, +/* 0xd317 */ { true, 0xd317, 0xd317 }, +/* 0xd318 */ { true, 0xd318, 0xd318 }, +/* 0xd319 */ { true, 0xd319, 0xd319 }, +/* 0xd31a */ { true, 0xd31a, 0xd31a }, +/* 0xd31b */ { true, 0xd31b, 0xd31b }, +/* 0xd31c */ { true, 0xd31c, 0xd31c }, +/* 0xd31d */ { true, 0xd31d, 0xd31d }, +/* 0xd31e */ { true, 0xd31e, 0xd31e }, +/* 0xd31f */ { true, 0xd31f, 0xd31f }, +/* 0xd320 */ { true, 0xd320, 0xd320 }, +/* 0xd321 */ { true, 0xd321, 0xd321 }, +/* 0xd322 */ { true, 0xd322, 0xd322 }, +/* 0xd323 */ { true, 0xd323, 0xd323 }, +/* 0xd324 */ { true, 0xd324, 0xd324 }, +/* 0xd325 */ { true, 0xd325, 0xd325 }, +/* 0xd326 */ { true, 0xd326, 0xd326 }, +/* 0xd327 */ { true, 0xd327, 0xd327 }, +/* 0xd328 */ { true, 0xd328, 0xd328 }, +/* 0xd329 */ { true, 0xd329, 0xd329 }, +/* 0xd32a */ { true, 0xd32a, 0xd32a }, +/* 0xd32b */ { true, 0xd32b, 0xd32b }, +/* 0xd32c */ { true, 0xd32c, 0xd32c }, +/* 0xd32d */ { true, 0xd32d, 0xd32d }, +/* 0xd32e */ { true, 0xd32e, 0xd32e }, +/* 0xd32f */ { true, 0xd32f, 0xd32f }, +/* 0xd330 */ { true, 0xd330, 0xd330 }, +/* 0xd331 */ { true, 0xd331, 0xd331 }, +/* 0xd332 */ { true, 0xd332, 0xd332 }, +/* 0xd333 */ { true, 0xd333, 0xd333 }, +/* 0xd334 */ { true, 0xd334, 0xd334 }, +/* 0xd335 */ { true, 0xd335, 0xd335 }, +/* 0xd336 */ { true, 0xd336, 0xd336 }, +/* 0xd337 */ { true, 0xd337, 0xd337 }, +/* 0xd338 */ { true, 0xd338, 0xd338 }, +/* 0xd339 */ { true, 0xd339, 0xd339 }, +/* 0xd33a */ { true, 0xd33a, 0xd33a }, +/* 0xd33b */ { true, 0xd33b, 0xd33b }, +/* 0xd33c */ { true, 0xd33c, 0xd33c }, +/* 0xd33d */ { true, 0xd33d, 0xd33d }, +/* 0xd33e */ { true, 0xd33e, 0xd33e }, +/* 0xd33f */ { true, 0xd33f, 0xd33f }, +/* 0xd340 */ { true, 0xd340, 0xd340 }, +/* 0xd341 */ { true, 0xd341, 0xd341 }, +/* 0xd342 */ { true, 0xd342, 0xd342 }, +/* 0xd343 */ { true, 0xd343, 0xd343 }, +/* 0xd344 */ { true, 0xd344, 0xd344 }, +/* 0xd345 */ { true, 0xd345, 0xd345 }, +/* 0xd346 */ { true, 0xd346, 0xd346 }, +/* 0xd347 */ { true, 0xd347, 0xd347 }, +/* 0xd348 */ { true, 0xd348, 0xd348 }, +/* 0xd349 */ { true, 0xd349, 0xd349 }, +/* 0xd34a */ { true, 0xd34a, 0xd34a }, +/* 0xd34b */ { true, 0xd34b, 0xd34b }, +/* 0xd34c */ { true, 0xd34c, 0xd34c }, +/* 0xd34d */ { true, 0xd34d, 0xd34d }, +/* 0xd34e */ { true, 0xd34e, 0xd34e }, +/* 0xd34f */ { true, 0xd34f, 0xd34f }, +/* 0xd350 */ { true, 0xd350, 0xd350 }, +/* 0xd351 */ { true, 0xd351, 0xd351 }, +/* 0xd352 */ { true, 0xd352, 0xd352 }, +/* 0xd353 */ { true, 0xd353, 0xd353 }, +/* 0xd354 */ { true, 0xd354, 0xd354 }, +/* 0xd355 */ { true, 0xd355, 0xd355 }, +/* 0xd356 */ { true, 0xd356, 0xd356 }, +/* 0xd357 */ { true, 0xd357, 0xd357 }, +/* 0xd358 */ { true, 0xd358, 0xd358 }, +/* 0xd359 */ { true, 0xd359, 0xd359 }, +/* 0xd35a */ { true, 0xd35a, 0xd35a }, +/* 0xd35b */ { true, 0xd35b, 0xd35b }, +/* 0xd35c */ { true, 0xd35c, 0xd35c }, +/* 0xd35d */ { true, 0xd35d, 0xd35d }, +/* 0xd35e */ { true, 0xd35e, 0xd35e }, +/* 0xd35f */ { true, 0xd35f, 0xd35f }, +/* 0xd360 */ { true, 0xd360, 0xd360 }, +/* 0xd361 */ { true, 0xd361, 0xd361 }, +/* 0xd362 */ { true, 0xd362, 0xd362 }, +/* 0xd363 */ { true, 0xd363, 0xd363 }, +/* 0xd364 */ { true, 0xd364, 0xd364 }, +/* 0xd365 */ { true, 0xd365, 0xd365 }, +/* 0xd366 */ { true, 0xd366, 0xd366 }, +/* 0xd367 */ { true, 0xd367, 0xd367 }, +/* 0xd368 */ { true, 0xd368, 0xd368 }, +/* 0xd369 */ { true, 0xd369, 0xd369 }, +/* 0xd36a */ { true, 0xd36a, 0xd36a }, +/* 0xd36b */ { true, 0xd36b, 0xd36b }, +/* 0xd36c */ { true, 0xd36c, 0xd36c }, +/* 0xd36d */ { true, 0xd36d, 0xd36d }, +/* 0xd36e */ { true, 0xd36e, 0xd36e }, +/* 0xd36f */ { true, 0xd36f, 0xd36f }, +/* 0xd370 */ { true, 0xd370, 0xd370 }, +/* 0xd371 */ { true, 0xd371, 0xd371 }, +/* 0xd372 */ { true, 0xd372, 0xd372 }, +/* 0xd373 */ { true, 0xd373, 0xd373 }, +/* 0xd374 */ { true, 0xd374, 0xd374 }, +/* 0xd375 */ { true, 0xd375, 0xd375 }, +/* 0xd376 */ { true, 0xd376, 0xd376 }, +/* 0xd377 */ { true, 0xd377, 0xd377 }, +/* 0xd378 */ { true, 0xd378, 0xd378 }, +/* 0xd379 */ { true, 0xd379, 0xd379 }, +/* 0xd37a */ { true, 0xd37a, 0xd37a }, +/* 0xd37b */ { true, 0xd37b, 0xd37b }, +/* 0xd37c */ { true, 0xd37c, 0xd37c }, +/* 0xd37d */ { true, 0xd37d, 0xd37d }, +/* 0xd37e */ { true, 0xd37e, 0xd37e }, +/* 0xd37f */ { true, 0xd37f, 0xd37f }, +/* 0xd380 */ { true, 0xd380, 0xd380 }, +/* 0xd381 */ { true, 0xd381, 0xd381 }, +/* 0xd382 */ { true, 0xd382, 0xd382 }, +/* 0xd383 */ { true, 0xd383, 0xd383 }, +/* 0xd384 */ { true, 0xd384, 0xd384 }, +/* 0xd385 */ { true, 0xd385, 0xd385 }, +/* 0xd386 */ { true, 0xd386, 0xd386 }, +/* 0xd387 */ { true, 0xd387, 0xd387 }, +/* 0xd388 */ { true, 0xd388, 0xd388 }, +/* 0xd389 */ { true, 0xd389, 0xd389 }, +/* 0xd38a */ { true, 0xd38a, 0xd38a }, +/* 0xd38b */ { true, 0xd38b, 0xd38b }, +/* 0xd38c */ { true, 0xd38c, 0xd38c }, +/* 0xd38d */ { true, 0xd38d, 0xd38d }, +/* 0xd38e */ { true, 0xd38e, 0xd38e }, +/* 0xd38f */ { true, 0xd38f, 0xd38f }, +/* 0xd390 */ { true, 0xd390, 0xd390 }, +/* 0xd391 */ { true, 0xd391, 0xd391 }, +/* 0xd392 */ { true, 0xd392, 0xd392 }, +/* 0xd393 */ { true, 0xd393, 0xd393 }, +/* 0xd394 */ { true, 0xd394, 0xd394 }, +/* 0xd395 */ { true, 0xd395, 0xd395 }, +/* 0xd396 */ { true, 0xd396, 0xd396 }, +/* 0xd397 */ { true, 0xd397, 0xd397 }, +/* 0xd398 */ { true, 0xd398, 0xd398 }, +/* 0xd399 */ { true, 0xd399, 0xd399 }, +/* 0xd39a */ { true, 0xd39a, 0xd39a }, +/* 0xd39b */ { true, 0xd39b, 0xd39b }, +/* 0xd39c */ { true, 0xd39c, 0xd39c }, +/* 0xd39d */ { true, 0xd39d, 0xd39d }, +/* 0xd39e */ { true, 0xd39e, 0xd39e }, +/* 0xd39f */ { true, 0xd39f, 0xd39f }, +/* 0xd3a0 */ { true, 0xd3a0, 0xd3a0 }, +/* 0xd3a1 */ { true, 0xd3a1, 0xd3a1 }, +/* 0xd3a2 */ { true, 0xd3a2, 0xd3a2 }, +/* 0xd3a3 */ { true, 0xd3a3, 0xd3a3 }, +/* 0xd3a4 */ { true, 0xd3a4, 0xd3a4 }, +/* 0xd3a5 */ { true, 0xd3a5, 0xd3a5 }, +/* 0xd3a6 */ { true, 0xd3a6, 0xd3a6 }, +/* 0xd3a7 */ { true, 0xd3a7, 0xd3a7 }, +/* 0xd3a8 */ { true, 0xd3a8, 0xd3a8 }, +/* 0xd3a9 */ { true, 0xd3a9, 0xd3a9 }, +/* 0xd3aa */ { true, 0xd3aa, 0xd3aa }, +/* 0xd3ab */ { true, 0xd3ab, 0xd3ab }, +/* 0xd3ac */ { true, 0xd3ac, 0xd3ac }, +/* 0xd3ad */ { true, 0xd3ad, 0xd3ad }, +/* 0xd3ae */ { true, 0xd3ae, 0xd3ae }, +/* 0xd3af */ { true, 0xd3af, 0xd3af }, +/* 0xd3b0 */ { true, 0xd3b0, 0xd3b0 }, +/* 0xd3b1 */ { true, 0xd3b1, 0xd3b1 }, +/* 0xd3b2 */ { true, 0xd3b2, 0xd3b2 }, +/* 0xd3b3 */ { true, 0xd3b3, 0xd3b3 }, +/* 0xd3b4 */ { true, 0xd3b4, 0xd3b4 }, +/* 0xd3b5 */ { true, 0xd3b5, 0xd3b5 }, +/* 0xd3b6 */ { true, 0xd3b6, 0xd3b6 }, +/* 0xd3b7 */ { true, 0xd3b7, 0xd3b7 }, +/* 0xd3b8 */ { true, 0xd3b8, 0xd3b8 }, +/* 0xd3b9 */ { true, 0xd3b9, 0xd3b9 }, +/* 0xd3ba */ { true, 0xd3ba, 0xd3ba }, +/* 0xd3bb */ { true, 0xd3bb, 0xd3bb }, +/* 0xd3bc */ { true, 0xd3bc, 0xd3bc }, +/* 0xd3bd */ { true, 0xd3bd, 0xd3bd }, +/* 0xd3be */ { true, 0xd3be, 0xd3be }, +/* 0xd3bf */ { true, 0xd3bf, 0xd3bf }, +/* 0xd3c0 */ { true, 0xd3c0, 0xd3c0 }, +/* 0xd3c1 */ { true, 0xd3c1, 0xd3c1 }, +/* 0xd3c2 */ { true, 0xd3c2, 0xd3c2 }, +/* 0xd3c3 */ { true, 0xd3c3, 0xd3c3 }, +/* 0xd3c4 */ { true, 0xd3c4, 0xd3c4 }, +/* 0xd3c5 */ { true, 0xd3c5, 0xd3c5 }, +/* 0xd3c6 */ { true, 0xd3c6, 0xd3c6 }, +/* 0xd3c7 */ { true, 0xd3c7, 0xd3c7 }, +/* 0xd3c8 */ { true, 0xd3c8, 0xd3c8 }, +/* 0xd3c9 */ { true, 0xd3c9, 0xd3c9 }, +/* 0xd3ca */ { true, 0xd3ca, 0xd3ca }, +/* 0xd3cb */ { true, 0xd3cb, 0xd3cb }, +/* 0xd3cc */ { true, 0xd3cc, 0xd3cc }, +/* 0xd3cd */ { true, 0xd3cd, 0xd3cd }, +/* 0xd3ce */ { true, 0xd3ce, 0xd3ce }, +/* 0xd3cf */ { true, 0xd3cf, 0xd3cf }, +/* 0xd3d0 */ { true, 0xd3d0, 0xd3d0 }, +/* 0xd3d1 */ { true, 0xd3d1, 0xd3d1 }, +/* 0xd3d2 */ { true, 0xd3d2, 0xd3d2 }, +/* 0xd3d3 */ { true, 0xd3d3, 0xd3d3 }, +/* 0xd3d4 */ { true, 0xd3d4, 0xd3d4 }, +/* 0xd3d5 */ { true, 0xd3d5, 0xd3d5 }, +/* 0xd3d6 */ { true, 0xd3d6, 0xd3d6 }, +/* 0xd3d7 */ { true, 0xd3d7, 0xd3d7 }, +/* 0xd3d8 */ { true, 0xd3d8, 0xd3d8 }, +/* 0xd3d9 */ { true, 0xd3d9, 0xd3d9 }, +/* 0xd3da */ { true, 0xd3da, 0xd3da }, +/* 0xd3db */ { true, 0xd3db, 0xd3db }, +/* 0xd3dc */ { true, 0xd3dc, 0xd3dc }, +/* 0xd3dd */ { true, 0xd3dd, 0xd3dd }, +/* 0xd3de */ { true, 0xd3de, 0xd3de }, +/* 0xd3df */ { true, 0xd3df, 0xd3df }, +/* 0xd3e0 */ { true, 0xd3e0, 0xd3e0 }, +/* 0xd3e1 */ { true, 0xd3e1, 0xd3e1 }, +/* 0xd3e2 */ { true, 0xd3e2, 0xd3e2 }, +/* 0xd3e3 */ { true, 0xd3e3, 0xd3e3 }, +/* 0xd3e4 */ { true, 0xd3e4, 0xd3e4 }, +/* 0xd3e5 */ { true, 0xd3e5, 0xd3e5 }, +/* 0xd3e6 */ { true, 0xd3e6, 0xd3e6 }, +/* 0xd3e7 */ { true, 0xd3e7, 0xd3e7 }, +/* 0xd3e8 */ { true, 0xd3e8, 0xd3e8 }, +/* 0xd3e9 */ { true, 0xd3e9, 0xd3e9 }, +/* 0xd3ea */ { true, 0xd3ea, 0xd3ea }, +/* 0xd3eb */ { true, 0xd3eb, 0xd3eb }, +/* 0xd3ec */ { true, 0xd3ec, 0xd3ec }, +/* 0xd3ed */ { true, 0xd3ed, 0xd3ed }, +/* 0xd3ee */ { true, 0xd3ee, 0xd3ee }, +/* 0xd3ef */ { true, 0xd3ef, 0xd3ef }, +/* 0xd3f0 */ { true, 0xd3f0, 0xd3f0 }, +/* 0xd3f1 */ { true, 0xd3f1, 0xd3f1 }, +/* 0xd3f2 */ { true, 0xd3f2, 0xd3f2 }, +/* 0xd3f3 */ { true, 0xd3f3, 0xd3f3 }, +/* 0xd3f4 */ { true, 0xd3f4, 0xd3f4 }, +/* 0xd3f5 */ { true, 0xd3f5, 0xd3f5 }, +/* 0xd3f6 */ { true, 0xd3f6, 0xd3f6 }, +/* 0xd3f7 */ { true, 0xd3f7, 0xd3f7 }, +/* 0xd3f8 */ { true, 0xd3f8, 0xd3f8 }, +/* 0xd3f9 */ { true, 0xd3f9, 0xd3f9 }, +/* 0xd3fa */ { true, 0xd3fa, 0xd3fa }, +/* 0xd3fb */ { true, 0xd3fb, 0xd3fb }, +/* 0xd3fc */ { true, 0xd3fc, 0xd3fc }, +/* 0xd3fd */ { true, 0xd3fd, 0xd3fd }, +/* 0xd3fe */ { true, 0xd3fe, 0xd3fe }, +/* 0xd3ff */ { true, 0xd3ff, 0xd3ff }, +/* 0xd400 */ { true, 0xd400, 0xd400 }, +/* 0xd401 */ { true, 0xd401, 0xd401 }, +/* 0xd402 */ { true, 0xd402, 0xd402 }, +/* 0xd403 */ { true, 0xd403, 0xd403 }, +/* 0xd404 */ { true, 0xd404, 0xd404 }, +/* 0xd405 */ { true, 0xd405, 0xd405 }, +/* 0xd406 */ { true, 0xd406, 0xd406 }, +/* 0xd407 */ { true, 0xd407, 0xd407 }, +/* 0xd408 */ { true, 0xd408, 0xd408 }, +/* 0xd409 */ { true, 0xd409, 0xd409 }, +/* 0xd40a */ { true, 0xd40a, 0xd40a }, +/* 0xd40b */ { true, 0xd40b, 0xd40b }, +/* 0xd40c */ { true, 0xd40c, 0xd40c }, +/* 0xd40d */ { true, 0xd40d, 0xd40d }, +/* 0xd40e */ { true, 0xd40e, 0xd40e }, +/* 0xd40f */ { true, 0xd40f, 0xd40f }, +/* 0xd410 */ { true, 0xd410, 0xd410 }, +/* 0xd411 */ { true, 0xd411, 0xd411 }, +/* 0xd412 */ { true, 0xd412, 0xd412 }, +/* 0xd413 */ { true, 0xd413, 0xd413 }, +/* 0xd414 */ { true, 0xd414, 0xd414 }, +/* 0xd415 */ { true, 0xd415, 0xd415 }, +/* 0xd416 */ { true, 0xd416, 0xd416 }, +/* 0xd417 */ { true, 0xd417, 0xd417 }, +/* 0xd418 */ { true, 0xd418, 0xd418 }, +/* 0xd419 */ { true, 0xd419, 0xd419 }, +/* 0xd41a */ { true, 0xd41a, 0xd41a }, +/* 0xd41b */ { true, 0xd41b, 0xd41b }, +/* 0xd41c */ { true, 0xd41c, 0xd41c }, +/* 0xd41d */ { true, 0xd41d, 0xd41d }, +/* 0xd41e */ { true, 0xd41e, 0xd41e }, +/* 0xd41f */ { true, 0xd41f, 0xd41f }, +/* 0xd420 */ { true, 0xd420, 0xd420 }, +/* 0xd421 */ { true, 0xd421, 0xd421 }, +/* 0xd422 */ { true, 0xd422, 0xd422 }, +/* 0xd423 */ { true, 0xd423, 0xd423 }, +/* 0xd424 */ { true, 0xd424, 0xd424 }, +/* 0xd425 */ { true, 0xd425, 0xd425 }, +/* 0xd426 */ { true, 0xd426, 0xd426 }, +/* 0xd427 */ { true, 0xd427, 0xd427 }, +/* 0xd428 */ { true, 0xd428, 0xd428 }, +/* 0xd429 */ { true, 0xd429, 0xd429 }, +/* 0xd42a */ { true, 0xd42a, 0xd42a }, +/* 0xd42b */ { true, 0xd42b, 0xd42b }, +/* 0xd42c */ { true, 0xd42c, 0xd42c }, +/* 0xd42d */ { true, 0xd42d, 0xd42d }, +/* 0xd42e */ { true, 0xd42e, 0xd42e }, +/* 0xd42f */ { true, 0xd42f, 0xd42f }, +/* 0xd430 */ { true, 0xd430, 0xd430 }, +/* 0xd431 */ { true, 0xd431, 0xd431 }, +/* 0xd432 */ { true, 0xd432, 0xd432 }, +/* 0xd433 */ { true, 0xd433, 0xd433 }, +/* 0xd434 */ { true, 0xd434, 0xd434 }, +/* 0xd435 */ { true, 0xd435, 0xd435 }, +/* 0xd436 */ { true, 0xd436, 0xd436 }, +/* 0xd437 */ { true, 0xd437, 0xd437 }, +/* 0xd438 */ { true, 0xd438, 0xd438 }, +/* 0xd439 */ { true, 0xd439, 0xd439 }, +/* 0xd43a */ { true, 0xd43a, 0xd43a }, +/* 0xd43b */ { true, 0xd43b, 0xd43b }, +/* 0xd43c */ { true, 0xd43c, 0xd43c }, +/* 0xd43d */ { true, 0xd43d, 0xd43d }, +/* 0xd43e */ { true, 0xd43e, 0xd43e }, +/* 0xd43f */ { true, 0xd43f, 0xd43f }, +/* 0xd440 */ { true, 0xd440, 0xd440 }, +/* 0xd441 */ { true, 0xd441, 0xd441 }, +/* 0xd442 */ { true, 0xd442, 0xd442 }, +/* 0xd443 */ { true, 0xd443, 0xd443 }, +/* 0xd444 */ { true, 0xd444, 0xd444 }, +/* 0xd445 */ { true, 0xd445, 0xd445 }, +/* 0xd446 */ { true, 0xd446, 0xd446 }, +/* 0xd447 */ { true, 0xd447, 0xd447 }, +/* 0xd448 */ { true, 0xd448, 0xd448 }, +/* 0xd449 */ { true, 0xd449, 0xd449 }, +/* 0xd44a */ { true, 0xd44a, 0xd44a }, +/* 0xd44b */ { true, 0xd44b, 0xd44b }, +/* 0xd44c */ { true, 0xd44c, 0xd44c }, +/* 0xd44d */ { true, 0xd44d, 0xd44d }, +/* 0xd44e */ { true, 0xd44e, 0xd44e }, +/* 0xd44f */ { true, 0xd44f, 0xd44f }, +/* 0xd450 */ { true, 0xd450, 0xd450 }, +/* 0xd451 */ { true, 0xd451, 0xd451 }, +/* 0xd452 */ { true, 0xd452, 0xd452 }, +/* 0xd453 */ { true, 0xd453, 0xd453 }, +/* 0xd454 */ { true, 0xd454, 0xd454 }, +/* 0xd455 */ { true, 0xd455, 0xd455 }, +/* 0xd456 */ { true, 0xd456, 0xd456 }, +/* 0xd457 */ { true, 0xd457, 0xd457 }, +/* 0xd458 */ { true, 0xd458, 0xd458 }, +/* 0xd459 */ { true, 0xd459, 0xd459 }, +/* 0xd45a */ { true, 0xd45a, 0xd45a }, +/* 0xd45b */ { true, 0xd45b, 0xd45b }, +/* 0xd45c */ { true, 0xd45c, 0xd45c }, +/* 0xd45d */ { true, 0xd45d, 0xd45d }, +/* 0xd45e */ { true, 0xd45e, 0xd45e }, +/* 0xd45f */ { true, 0xd45f, 0xd45f }, +/* 0xd460 */ { true, 0xd460, 0xd460 }, +/* 0xd461 */ { true, 0xd461, 0xd461 }, +/* 0xd462 */ { true, 0xd462, 0xd462 }, +/* 0xd463 */ { true, 0xd463, 0xd463 }, +/* 0xd464 */ { true, 0xd464, 0xd464 }, +/* 0xd465 */ { true, 0xd465, 0xd465 }, +/* 0xd466 */ { true, 0xd466, 0xd466 }, +/* 0xd467 */ { true, 0xd467, 0xd467 }, +/* 0xd468 */ { true, 0xd468, 0xd468 }, +/* 0xd469 */ { true, 0xd469, 0xd469 }, +/* 0xd46a */ { true, 0xd46a, 0xd46a }, +/* 0xd46b */ { true, 0xd46b, 0xd46b }, +/* 0xd46c */ { true, 0xd46c, 0xd46c }, +/* 0xd46d */ { true, 0xd46d, 0xd46d }, +/* 0xd46e */ { true, 0xd46e, 0xd46e }, +/* 0xd46f */ { true, 0xd46f, 0xd46f }, +/* 0xd470 */ { true, 0xd470, 0xd470 }, +/* 0xd471 */ { true, 0xd471, 0xd471 }, +/* 0xd472 */ { true, 0xd472, 0xd472 }, +/* 0xd473 */ { true, 0xd473, 0xd473 }, +/* 0xd474 */ { true, 0xd474, 0xd474 }, +/* 0xd475 */ { true, 0xd475, 0xd475 }, +/* 0xd476 */ { true, 0xd476, 0xd476 }, +/* 0xd477 */ { true, 0xd477, 0xd477 }, +/* 0xd478 */ { true, 0xd478, 0xd478 }, +/* 0xd479 */ { true, 0xd479, 0xd479 }, +/* 0xd47a */ { true, 0xd47a, 0xd47a }, +/* 0xd47b */ { true, 0xd47b, 0xd47b }, +/* 0xd47c */ { true, 0xd47c, 0xd47c }, +/* 0xd47d */ { true, 0xd47d, 0xd47d }, +/* 0xd47e */ { true, 0xd47e, 0xd47e }, +/* 0xd47f */ { true, 0xd47f, 0xd47f }, +/* 0xd480 */ { true, 0xd480, 0xd480 }, +/* 0xd481 */ { true, 0xd481, 0xd481 }, +/* 0xd482 */ { true, 0xd482, 0xd482 }, +/* 0xd483 */ { true, 0xd483, 0xd483 }, +/* 0xd484 */ { true, 0xd484, 0xd484 }, +/* 0xd485 */ { true, 0xd485, 0xd485 }, +/* 0xd486 */ { true, 0xd486, 0xd486 }, +/* 0xd487 */ { true, 0xd487, 0xd487 }, +/* 0xd488 */ { true, 0xd488, 0xd488 }, +/* 0xd489 */ { true, 0xd489, 0xd489 }, +/* 0xd48a */ { true, 0xd48a, 0xd48a }, +/* 0xd48b */ { true, 0xd48b, 0xd48b }, +/* 0xd48c */ { true, 0xd48c, 0xd48c }, +/* 0xd48d */ { true, 0xd48d, 0xd48d }, +/* 0xd48e */ { true, 0xd48e, 0xd48e }, +/* 0xd48f */ { true, 0xd48f, 0xd48f }, +/* 0xd490 */ { true, 0xd490, 0xd490 }, +/* 0xd491 */ { true, 0xd491, 0xd491 }, +/* 0xd492 */ { true, 0xd492, 0xd492 }, +/* 0xd493 */ { true, 0xd493, 0xd493 }, +/* 0xd494 */ { true, 0xd494, 0xd494 }, +/* 0xd495 */ { true, 0xd495, 0xd495 }, +/* 0xd496 */ { true, 0xd496, 0xd496 }, +/* 0xd497 */ { true, 0xd497, 0xd497 }, +/* 0xd498 */ { true, 0xd498, 0xd498 }, +/* 0xd499 */ { true, 0xd499, 0xd499 }, +/* 0xd49a */ { true, 0xd49a, 0xd49a }, +/* 0xd49b */ { true, 0xd49b, 0xd49b }, +/* 0xd49c */ { true, 0xd49c, 0xd49c }, +/* 0xd49d */ { true, 0xd49d, 0xd49d }, +/* 0xd49e */ { true, 0xd49e, 0xd49e }, +/* 0xd49f */ { true, 0xd49f, 0xd49f }, +/* 0xd4a0 */ { true, 0xd4a0, 0xd4a0 }, +/* 0xd4a1 */ { true, 0xd4a1, 0xd4a1 }, +/* 0xd4a2 */ { true, 0xd4a2, 0xd4a2 }, +/* 0xd4a3 */ { true, 0xd4a3, 0xd4a3 }, +/* 0xd4a4 */ { true, 0xd4a4, 0xd4a4 }, +/* 0xd4a5 */ { true, 0xd4a5, 0xd4a5 }, +/* 0xd4a6 */ { true, 0xd4a6, 0xd4a6 }, +/* 0xd4a7 */ { true, 0xd4a7, 0xd4a7 }, +/* 0xd4a8 */ { true, 0xd4a8, 0xd4a8 }, +/* 0xd4a9 */ { true, 0xd4a9, 0xd4a9 }, +/* 0xd4aa */ { true, 0xd4aa, 0xd4aa }, +/* 0xd4ab */ { true, 0xd4ab, 0xd4ab }, +/* 0xd4ac */ { true, 0xd4ac, 0xd4ac }, +/* 0xd4ad */ { true, 0xd4ad, 0xd4ad }, +/* 0xd4ae */ { true, 0xd4ae, 0xd4ae }, +/* 0xd4af */ { true, 0xd4af, 0xd4af }, +/* 0xd4b0 */ { true, 0xd4b0, 0xd4b0 }, +/* 0xd4b1 */ { true, 0xd4b1, 0xd4b1 }, +/* 0xd4b2 */ { true, 0xd4b2, 0xd4b2 }, +/* 0xd4b3 */ { true, 0xd4b3, 0xd4b3 }, +/* 0xd4b4 */ { true, 0xd4b4, 0xd4b4 }, +/* 0xd4b5 */ { true, 0xd4b5, 0xd4b5 }, +/* 0xd4b6 */ { true, 0xd4b6, 0xd4b6 }, +/* 0xd4b7 */ { true, 0xd4b7, 0xd4b7 }, +/* 0xd4b8 */ { true, 0xd4b8, 0xd4b8 }, +/* 0xd4b9 */ { true, 0xd4b9, 0xd4b9 }, +/* 0xd4ba */ { true, 0xd4ba, 0xd4ba }, +/* 0xd4bb */ { true, 0xd4bb, 0xd4bb }, +/* 0xd4bc */ { true, 0xd4bc, 0xd4bc }, +/* 0xd4bd */ { true, 0xd4bd, 0xd4bd }, +/* 0xd4be */ { true, 0xd4be, 0xd4be }, +/* 0xd4bf */ { true, 0xd4bf, 0xd4bf }, +/* 0xd4c0 */ { true, 0xd4c0, 0xd4c0 }, +/* 0xd4c1 */ { true, 0xd4c1, 0xd4c1 }, +/* 0xd4c2 */ { true, 0xd4c2, 0xd4c2 }, +/* 0xd4c3 */ { true, 0xd4c3, 0xd4c3 }, +/* 0xd4c4 */ { true, 0xd4c4, 0xd4c4 }, +/* 0xd4c5 */ { true, 0xd4c5, 0xd4c5 }, +/* 0xd4c6 */ { true, 0xd4c6, 0xd4c6 }, +/* 0xd4c7 */ { true, 0xd4c7, 0xd4c7 }, +/* 0xd4c8 */ { true, 0xd4c8, 0xd4c8 }, +/* 0xd4c9 */ { true, 0xd4c9, 0xd4c9 }, +/* 0xd4ca */ { true, 0xd4ca, 0xd4ca }, +/* 0xd4cb */ { true, 0xd4cb, 0xd4cb }, +/* 0xd4cc */ { true, 0xd4cc, 0xd4cc }, +/* 0xd4cd */ { true, 0xd4cd, 0xd4cd }, +/* 0xd4ce */ { true, 0xd4ce, 0xd4ce }, +/* 0xd4cf */ { true, 0xd4cf, 0xd4cf }, +/* 0xd4d0 */ { true, 0xd4d0, 0xd4d0 }, +/* 0xd4d1 */ { true, 0xd4d1, 0xd4d1 }, +/* 0xd4d2 */ { true, 0xd4d2, 0xd4d2 }, +/* 0xd4d3 */ { true, 0xd4d3, 0xd4d3 }, +/* 0xd4d4 */ { true, 0xd4d4, 0xd4d4 }, +/* 0xd4d5 */ { true, 0xd4d5, 0xd4d5 }, +/* 0xd4d6 */ { true, 0xd4d6, 0xd4d6 }, +/* 0xd4d7 */ { true, 0xd4d7, 0xd4d7 }, +/* 0xd4d8 */ { true, 0xd4d8, 0xd4d8 }, +/* 0xd4d9 */ { true, 0xd4d9, 0xd4d9 }, +/* 0xd4da */ { true, 0xd4da, 0xd4da }, +/* 0xd4db */ { true, 0xd4db, 0xd4db }, +/* 0xd4dc */ { true, 0xd4dc, 0xd4dc }, +/* 0xd4dd */ { true, 0xd4dd, 0xd4dd }, +/* 0xd4de */ { true, 0xd4de, 0xd4de }, +/* 0xd4df */ { true, 0xd4df, 0xd4df }, +/* 0xd4e0 */ { true, 0xd4e0, 0xd4e0 }, +/* 0xd4e1 */ { true, 0xd4e1, 0xd4e1 }, +/* 0xd4e2 */ { true, 0xd4e2, 0xd4e2 }, +/* 0xd4e3 */ { true, 0xd4e3, 0xd4e3 }, +/* 0xd4e4 */ { true, 0xd4e4, 0xd4e4 }, +/* 0xd4e5 */ { true, 0xd4e5, 0xd4e5 }, +/* 0xd4e6 */ { true, 0xd4e6, 0xd4e6 }, +/* 0xd4e7 */ { true, 0xd4e7, 0xd4e7 }, +/* 0xd4e8 */ { true, 0xd4e8, 0xd4e8 }, +/* 0xd4e9 */ { true, 0xd4e9, 0xd4e9 }, +/* 0xd4ea */ { true, 0xd4ea, 0xd4ea }, +/* 0xd4eb */ { true, 0xd4eb, 0xd4eb }, +/* 0xd4ec */ { true, 0xd4ec, 0xd4ec }, +/* 0xd4ed */ { true, 0xd4ed, 0xd4ed }, +/* 0xd4ee */ { true, 0xd4ee, 0xd4ee }, +/* 0xd4ef */ { true, 0xd4ef, 0xd4ef }, +/* 0xd4f0 */ { true, 0xd4f0, 0xd4f0 }, +/* 0xd4f1 */ { true, 0xd4f1, 0xd4f1 }, +/* 0xd4f2 */ { true, 0xd4f2, 0xd4f2 }, +/* 0xd4f3 */ { true, 0xd4f3, 0xd4f3 }, +/* 0xd4f4 */ { true, 0xd4f4, 0xd4f4 }, +/* 0xd4f5 */ { true, 0xd4f5, 0xd4f5 }, +/* 0xd4f6 */ { true, 0xd4f6, 0xd4f6 }, +/* 0xd4f7 */ { true, 0xd4f7, 0xd4f7 }, +/* 0xd4f8 */ { true, 0xd4f8, 0xd4f8 }, +/* 0xd4f9 */ { true, 0xd4f9, 0xd4f9 }, +/* 0xd4fa */ { true, 0xd4fa, 0xd4fa }, +/* 0xd4fb */ { true, 0xd4fb, 0xd4fb }, +/* 0xd4fc */ { true, 0xd4fc, 0xd4fc }, +/* 0xd4fd */ { true, 0xd4fd, 0xd4fd }, +/* 0xd4fe */ { true, 0xd4fe, 0xd4fe }, +/* 0xd4ff */ { true, 0xd4ff, 0xd4ff }, +/* 0xd500 */ { true, 0xd500, 0xd500 }, +/* 0xd501 */ { true, 0xd501, 0xd501 }, +/* 0xd502 */ { true, 0xd502, 0xd502 }, +/* 0xd503 */ { true, 0xd503, 0xd503 }, +/* 0xd504 */ { true, 0xd504, 0xd504 }, +/* 0xd505 */ { true, 0xd505, 0xd505 }, +/* 0xd506 */ { true, 0xd506, 0xd506 }, +/* 0xd507 */ { true, 0xd507, 0xd507 }, +/* 0xd508 */ { true, 0xd508, 0xd508 }, +/* 0xd509 */ { true, 0xd509, 0xd509 }, +/* 0xd50a */ { true, 0xd50a, 0xd50a }, +/* 0xd50b */ { true, 0xd50b, 0xd50b }, +/* 0xd50c */ { true, 0xd50c, 0xd50c }, +/* 0xd50d */ { true, 0xd50d, 0xd50d }, +/* 0xd50e */ { true, 0xd50e, 0xd50e }, +/* 0xd50f */ { true, 0xd50f, 0xd50f }, +/* 0xd510 */ { true, 0xd510, 0xd510 }, +/* 0xd511 */ { true, 0xd511, 0xd511 }, +/* 0xd512 */ { true, 0xd512, 0xd512 }, +/* 0xd513 */ { true, 0xd513, 0xd513 }, +/* 0xd514 */ { true, 0xd514, 0xd514 }, +/* 0xd515 */ { true, 0xd515, 0xd515 }, +/* 0xd516 */ { true, 0xd516, 0xd516 }, +/* 0xd517 */ { true, 0xd517, 0xd517 }, +/* 0xd518 */ { true, 0xd518, 0xd518 }, +/* 0xd519 */ { true, 0xd519, 0xd519 }, +/* 0xd51a */ { true, 0xd51a, 0xd51a }, +/* 0xd51b */ { true, 0xd51b, 0xd51b }, +/* 0xd51c */ { true, 0xd51c, 0xd51c }, +/* 0xd51d */ { true, 0xd51d, 0xd51d }, +/* 0xd51e */ { true, 0xd51e, 0xd51e }, +/* 0xd51f */ { true, 0xd51f, 0xd51f }, +/* 0xd520 */ { true, 0xd520, 0xd520 }, +/* 0xd521 */ { true, 0xd521, 0xd521 }, +/* 0xd522 */ { true, 0xd522, 0xd522 }, +/* 0xd523 */ { true, 0xd523, 0xd523 }, +/* 0xd524 */ { true, 0xd524, 0xd524 }, +/* 0xd525 */ { true, 0xd525, 0xd525 }, +/* 0xd526 */ { true, 0xd526, 0xd526 }, +/* 0xd527 */ { true, 0xd527, 0xd527 }, +/* 0xd528 */ { true, 0xd528, 0xd528 }, +/* 0xd529 */ { true, 0xd529, 0xd529 }, +/* 0xd52a */ { true, 0xd52a, 0xd52a }, +/* 0xd52b */ { true, 0xd52b, 0xd52b }, +/* 0xd52c */ { true, 0xd52c, 0xd52c }, +/* 0xd52d */ { true, 0xd52d, 0xd52d }, +/* 0xd52e */ { true, 0xd52e, 0xd52e }, +/* 0xd52f */ { true, 0xd52f, 0xd52f }, +/* 0xd530 */ { true, 0xd530, 0xd530 }, +/* 0xd531 */ { true, 0xd531, 0xd531 }, +/* 0xd532 */ { true, 0xd532, 0xd532 }, +/* 0xd533 */ { true, 0xd533, 0xd533 }, +/* 0xd534 */ { true, 0xd534, 0xd534 }, +/* 0xd535 */ { true, 0xd535, 0xd535 }, +/* 0xd536 */ { true, 0xd536, 0xd536 }, +/* 0xd537 */ { true, 0xd537, 0xd537 }, +/* 0xd538 */ { true, 0xd538, 0xd538 }, +/* 0xd539 */ { true, 0xd539, 0xd539 }, +/* 0xd53a */ { true, 0xd53a, 0xd53a }, +/* 0xd53b */ { true, 0xd53b, 0xd53b }, +/* 0xd53c */ { true, 0xd53c, 0xd53c }, +/* 0xd53d */ { true, 0xd53d, 0xd53d }, +/* 0xd53e */ { true, 0xd53e, 0xd53e }, +/* 0xd53f */ { true, 0xd53f, 0xd53f }, +/* 0xd540 */ { true, 0xd540, 0xd540 }, +/* 0xd541 */ { true, 0xd541, 0xd541 }, +/* 0xd542 */ { true, 0xd542, 0xd542 }, +/* 0xd543 */ { true, 0xd543, 0xd543 }, +/* 0xd544 */ { true, 0xd544, 0xd544 }, +/* 0xd545 */ { true, 0xd545, 0xd545 }, +/* 0xd546 */ { true, 0xd546, 0xd546 }, +/* 0xd547 */ { true, 0xd547, 0xd547 }, +/* 0xd548 */ { true, 0xd548, 0xd548 }, +/* 0xd549 */ { true, 0xd549, 0xd549 }, +/* 0xd54a */ { true, 0xd54a, 0xd54a }, +/* 0xd54b */ { true, 0xd54b, 0xd54b }, +/* 0xd54c */ { true, 0xd54c, 0xd54c }, +/* 0xd54d */ { true, 0xd54d, 0xd54d }, +/* 0xd54e */ { true, 0xd54e, 0xd54e }, +/* 0xd54f */ { true, 0xd54f, 0xd54f }, +/* 0xd550 */ { true, 0xd550, 0xd550 }, +/* 0xd551 */ { true, 0xd551, 0xd551 }, +/* 0xd552 */ { true, 0xd552, 0xd552 }, +/* 0xd553 */ { true, 0xd553, 0xd553 }, +/* 0xd554 */ { true, 0xd554, 0xd554 }, +/* 0xd555 */ { true, 0xd555, 0xd555 }, +/* 0xd556 */ { true, 0xd556, 0xd556 }, +/* 0xd557 */ { true, 0xd557, 0xd557 }, +/* 0xd558 */ { true, 0xd558, 0xd558 }, +/* 0xd559 */ { true, 0xd559, 0xd559 }, +/* 0xd55a */ { true, 0xd55a, 0xd55a }, +/* 0xd55b */ { true, 0xd55b, 0xd55b }, +/* 0xd55c */ { true, 0xd55c, 0xd55c }, +/* 0xd55d */ { true, 0xd55d, 0xd55d }, +/* 0xd55e */ { true, 0xd55e, 0xd55e }, +/* 0xd55f */ { true, 0xd55f, 0xd55f }, +/* 0xd560 */ { true, 0xd560, 0xd560 }, +/* 0xd561 */ { true, 0xd561, 0xd561 }, +/* 0xd562 */ { true, 0xd562, 0xd562 }, +/* 0xd563 */ { true, 0xd563, 0xd563 }, +/* 0xd564 */ { true, 0xd564, 0xd564 }, +/* 0xd565 */ { true, 0xd565, 0xd565 }, +/* 0xd566 */ { true, 0xd566, 0xd566 }, +/* 0xd567 */ { true, 0xd567, 0xd567 }, +/* 0xd568 */ { true, 0xd568, 0xd568 }, +/* 0xd569 */ { true, 0xd569, 0xd569 }, +/* 0xd56a */ { true, 0xd56a, 0xd56a }, +/* 0xd56b */ { true, 0xd56b, 0xd56b }, +/* 0xd56c */ { true, 0xd56c, 0xd56c }, +/* 0xd56d */ { true, 0xd56d, 0xd56d }, +/* 0xd56e */ { true, 0xd56e, 0xd56e }, +/* 0xd56f */ { true, 0xd56f, 0xd56f }, +/* 0xd570 */ { true, 0xd570, 0xd570 }, +/* 0xd571 */ { true, 0xd571, 0xd571 }, +/* 0xd572 */ { true, 0xd572, 0xd572 }, +/* 0xd573 */ { true, 0xd573, 0xd573 }, +/* 0xd574 */ { true, 0xd574, 0xd574 }, +/* 0xd575 */ { true, 0xd575, 0xd575 }, +/* 0xd576 */ { true, 0xd576, 0xd576 }, +/* 0xd577 */ { true, 0xd577, 0xd577 }, +/* 0xd578 */ { true, 0xd578, 0xd578 }, +/* 0xd579 */ { true, 0xd579, 0xd579 }, +/* 0xd57a */ { true, 0xd57a, 0xd57a }, +/* 0xd57b */ { true, 0xd57b, 0xd57b }, +/* 0xd57c */ { true, 0xd57c, 0xd57c }, +/* 0xd57d */ { true, 0xd57d, 0xd57d }, +/* 0xd57e */ { true, 0xd57e, 0xd57e }, +/* 0xd57f */ { true, 0xd57f, 0xd57f }, +/* 0xd580 */ { true, 0xd580, 0xd580 }, +/* 0xd581 */ { true, 0xd581, 0xd581 }, +/* 0xd582 */ { true, 0xd582, 0xd582 }, +/* 0xd583 */ { true, 0xd583, 0xd583 }, +/* 0xd584 */ { true, 0xd584, 0xd584 }, +/* 0xd585 */ { true, 0xd585, 0xd585 }, +/* 0xd586 */ { true, 0xd586, 0xd586 }, +/* 0xd587 */ { true, 0xd587, 0xd587 }, +/* 0xd588 */ { true, 0xd588, 0xd588 }, +/* 0xd589 */ { true, 0xd589, 0xd589 }, +/* 0xd58a */ { true, 0xd58a, 0xd58a }, +/* 0xd58b */ { true, 0xd58b, 0xd58b }, +/* 0xd58c */ { true, 0xd58c, 0xd58c }, +/* 0xd58d */ { true, 0xd58d, 0xd58d }, +/* 0xd58e */ { true, 0xd58e, 0xd58e }, +/* 0xd58f */ { true, 0xd58f, 0xd58f }, +/* 0xd590 */ { true, 0xd590, 0xd590 }, +/* 0xd591 */ { true, 0xd591, 0xd591 }, +/* 0xd592 */ { true, 0xd592, 0xd592 }, +/* 0xd593 */ { true, 0xd593, 0xd593 }, +/* 0xd594 */ { true, 0xd594, 0xd594 }, +/* 0xd595 */ { true, 0xd595, 0xd595 }, +/* 0xd596 */ { true, 0xd596, 0xd596 }, +/* 0xd597 */ { true, 0xd597, 0xd597 }, +/* 0xd598 */ { true, 0xd598, 0xd598 }, +/* 0xd599 */ { true, 0xd599, 0xd599 }, +/* 0xd59a */ { true, 0xd59a, 0xd59a }, +/* 0xd59b */ { true, 0xd59b, 0xd59b }, +/* 0xd59c */ { true, 0xd59c, 0xd59c }, +/* 0xd59d */ { true, 0xd59d, 0xd59d }, +/* 0xd59e */ { true, 0xd59e, 0xd59e }, +/* 0xd59f */ { true, 0xd59f, 0xd59f }, +/* 0xd5a0 */ { true, 0xd5a0, 0xd5a0 }, +/* 0xd5a1 */ { true, 0xd5a1, 0xd5a1 }, +/* 0xd5a2 */ { true, 0xd5a2, 0xd5a2 }, +/* 0xd5a3 */ { true, 0xd5a3, 0xd5a3 }, +/* 0xd5a4 */ { true, 0xd5a4, 0xd5a4 }, +/* 0xd5a5 */ { true, 0xd5a5, 0xd5a5 }, +/* 0xd5a6 */ { true, 0xd5a6, 0xd5a6 }, +/* 0xd5a7 */ { true, 0xd5a7, 0xd5a7 }, +/* 0xd5a8 */ { true, 0xd5a8, 0xd5a8 }, +/* 0xd5a9 */ { true, 0xd5a9, 0xd5a9 }, +/* 0xd5aa */ { true, 0xd5aa, 0xd5aa }, +/* 0xd5ab */ { true, 0xd5ab, 0xd5ab }, +/* 0xd5ac */ { true, 0xd5ac, 0xd5ac }, +/* 0xd5ad */ { true, 0xd5ad, 0xd5ad }, +/* 0xd5ae */ { true, 0xd5ae, 0xd5ae }, +/* 0xd5af */ { true, 0xd5af, 0xd5af }, +/* 0xd5b0 */ { true, 0xd5b0, 0xd5b0 }, +/* 0xd5b1 */ { true, 0xd5b1, 0xd5b1 }, +/* 0xd5b2 */ { true, 0xd5b2, 0xd5b2 }, +/* 0xd5b3 */ { true, 0xd5b3, 0xd5b3 }, +/* 0xd5b4 */ { true, 0xd5b4, 0xd5b4 }, +/* 0xd5b5 */ { true, 0xd5b5, 0xd5b5 }, +/* 0xd5b6 */ { true, 0xd5b6, 0xd5b6 }, +/* 0xd5b7 */ { true, 0xd5b7, 0xd5b7 }, +/* 0xd5b8 */ { true, 0xd5b8, 0xd5b8 }, +/* 0xd5b9 */ { true, 0xd5b9, 0xd5b9 }, +/* 0xd5ba */ { true, 0xd5ba, 0xd5ba }, +/* 0xd5bb */ { true, 0xd5bb, 0xd5bb }, +/* 0xd5bc */ { true, 0xd5bc, 0xd5bc }, +/* 0xd5bd */ { true, 0xd5bd, 0xd5bd }, +/* 0xd5be */ { true, 0xd5be, 0xd5be }, +/* 0xd5bf */ { true, 0xd5bf, 0xd5bf }, +/* 0xd5c0 */ { true, 0xd5c0, 0xd5c0 }, +/* 0xd5c1 */ { true, 0xd5c1, 0xd5c1 }, +/* 0xd5c2 */ { true, 0xd5c2, 0xd5c2 }, +/* 0xd5c3 */ { true, 0xd5c3, 0xd5c3 }, +/* 0xd5c4 */ { true, 0xd5c4, 0xd5c4 }, +/* 0xd5c5 */ { true, 0xd5c5, 0xd5c5 }, +/* 0xd5c6 */ { true, 0xd5c6, 0xd5c6 }, +/* 0xd5c7 */ { true, 0xd5c7, 0xd5c7 }, +/* 0xd5c8 */ { true, 0xd5c8, 0xd5c8 }, +/* 0xd5c9 */ { true, 0xd5c9, 0xd5c9 }, +/* 0xd5ca */ { true, 0xd5ca, 0xd5ca }, +/* 0xd5cb */ { true, 0xd5cb, 0xd5cb }, +/* 0xd5cc */ { true, 0xd5cc, 0xd5cc }, +/* 0xd5cd */ { true, 0xd5cd, 0xd5cd }, +/* 0xd5ce */ { true, 0xd5ce, 0xd5ce }, +/* 0xd5cf */ { true, 0xd5cf, 0xd5cf }, +/* 0xd5d0 */ { true, 0xd5d0, 0xd5d0 }, +/* 0xd5d1 */ { true, 0xd5d1, 0xd5d1 }, +/* 0xd5d2 */ { true, 0xd5d2, 0xd5d2 }, +/* 0xd5d3 */ { true, 0xd5d3, 0xd5d3 }, +/* 0xd5d4 */ { true, 0xd5d4, 0xd5d4 }, +/* 0xd5d5 */ { true, 0xd5d5, 0xd5d5 }, +/* 0xd5d6 */ { true, 0xd5d6, 0xd5d6 }, +/* 0xd5d7 */ { true, 0xd5d7, 0xd5d7 }, +/* 0xd5d8 */ { true, 0xd5d8, 0xd5d8 }, +/* 0xd5d9 */ { true, 0xd5d9, 0xd5d9 }, +/* 0xd5da */ { true, 0xd5da, 0xd5da }, +/* 0xd5db */ { true, 0xd5db, 0xd5db }, +/* 0xd5dc */ { true, 0xd5dc, 0xd5dc }, +/* 0xd5dd */ { true, 0xd5dd, 0xd5dd }, +/* 0xd5de */ { true, 0xd5de, 0xd5de }, +/* 0xd5df */ { true, 0xd5df, 0xd5df }, +/* 0xd5e0 */ { true, 0xd5e0, 0xd5e0 }, +/* 0xd5e1 */ { true, 0xd5e1, 0xd5e1 }, +/* 0xd5e2 */ { true, 0xd5e2, 0xd5e2 }, +/* 0xd5e3 */ { true, 0xd5e3, 0xd5e3 }, +/* 0xd5e4 */ { true, 0xd5e4, 0xd5e4 }, +/* 0xd5e5 */ { true, 0xd5e5, 0xd5e5 }, +/* 0xd5e6 */ { true, 0xd5e6, 0xd5e6 }, +/* 0xd5e7 */ { true, 0xd5e7, 0xd5e7 }, +/* 0xd5e8 */ { true, 0xd5e8, 0xd5e8 }, +/* 0xd5e9 */ { true, 0xd5e9, 0xd5e9 }, +/* 0xd5ea */ { true, 0xd5ea, 0xd5ea }, +/* 0xd5eb */ { true, 0xd5eb, 0xd5eb }, +/* 0xd5ec */ { true, 0xd5ec, 0xd5ec }, +/* 0xd5ed */ { true, 0xd5ed, 0xd5ed }, +/* 0xd5ee */ { true, 0xd5ee, 0xd5ee }, +/* 0xd5ef */ { true, 0xd5ef, 0xd5ef }, +/* 0xd5f0 */ { true, 0xd5f0, 0xd5f0 }, +/* 0xd5f1 */ { true, 0xd5f1, 0xd5f1 }, +/* 0xd5f2 */ { true, 0xd5f2, 0xd5f2 }, +/* 0xd5f3 */ { true, 0xd5f3, 0xd5f3 }, +/* 0xd5f4 */ { true, 0xd5f4, 0xd5f4 }, +/* 0xd5f5 */ { true, 0xd5f5, 0xd5f5 }, +/* 0xd5f6 */ { true, 0xd5f6, 0xd5f6 }, +/* 0xd5f7 */ { true, 0xd5f7, 0xd5f7 }, +/* 0xd5f8 */ { true, 0xd5f8, 0xd5f8 }, +/* 0xd5f9 */ { true, 0xd5f9, 0xd5f9 }, +/* 0xd5fa */ { true, 0xd5fa, 0xd5fa }, +/* 0xd5fb */ { true, 0xd5fb, 0xd5fb }, +/* 0xd5fc */ { true, 0xd5fc, 0xd5fc }, +/* 0xd5fd */ { true, 0xd5fd, 0xd5fd }, +/* 0xd5fe */ { true, 0xd5fe, 0xd5fe }, +/* 0xd5ff */ { true, 0xd5ff, 0xd5ff }, +/* 0xd600 */ { true, 0xd600, 0xd600 }, +/* 0xd601 */ { true, 0xd601, 0xd601 }, +/* 0xd602 */ { true, 0xd602, 0xd602 }, +/* 0xd603 */ { true, 0xd603, 0xd603 }, +/* 0xd604 */ { true, 0xd604, 0xd604 }, +/* 0xd605 */ { true, 0xd605, 0xd605 }, +/* 0xd606 */ { true, 0xd606, 0xd606 }, +/* 0xd607 */ { true, 0xd607, 0xd607 }, +/* 0xd608 */ { true, 0xd608, 0xd608 }, +/* 0xd609 */ { true, 0xd609, 0xd609 }, +/* 0xd60a */ { true, 0xd60a, 0xd60a }, +/* 0xd60b */ { true, 0xd60b, 0xd60b }, +/* 0xd60c */ { true, 0xd60c, 0xd60c }, +/* 0xd60d */ { true, 0xd60d, 0xd60d }, +/* 0xd60e */ { true, 0xd60e, 0xd60e }, +/* 0xd60f */ { true, 0xd60f, 0xd60f }, +/* 0xd610 */ { true, 0xd610, 0xd610 }, +/* 0xd611 */ { true, 0xd611, 0xd611 }, +/* 0xd612 */ { true, 0xd612, 0xd612 }, +/* 0xd613 */ { true, 0xd613, 0xd613 }, +/* 0xd614 */ { true, 0xd614, 0xd614 }, +/* 0xd615 */ { true, 0xd615, 0xd615 }, +/* 0xd616 */ { true, 0xd616, 0xd616 }, +/* 0xd617 */ { true, 0xd617, 0xd617 }, +/* 0xd618 */ { true, 0xd618, 0xd618 }, +/* 0xd619 */ { true, 0xd619, 0xd619 }, +/* 0xd61a */ { true, 0xd61a, 0xd61a }, +/* 0xd61b */ { true, 0xd61b, 0xd61b }, +/* 0xd61c */ { true, 0xd61c, 0xd61c }, +/* 0xd61d */ { true, 0xd61d, 0xd61d }, +/* 0xd61e */ { true, 0xd61e, 0xd61e }, +/* 0xd61f */ { true, 0xd61f, 0xd61f }, +/* 0xd620 */ { true, 0xd620, 0xd620 }, +/* 0xd621 */ { true, 0xd621, 0xd621 }, +/* 0xd622 */ { true, 0xd622, 0xd622 }, +/* 0xd623 */ { true, 0xd623, 0xd623 }, +/* 0xd624 */ { true, 0xd624, 0xd624 }, +/* 0xd625 */ { true, 0xd625, 0xd625 }, +/* 0xd626 */ { true, 0xd626, 0xd626 }, +/* 0xd627 */ { true, 0xd627, 0xd627 }, +/* 0xd628 */ { true, 0xd628, 0xd628 }, +/* 0xd629 */ { true, 0xd629, 0xd629 }, +/* 0xd62a */ { true, 0xd62a, 0xd62a }, +/* 0xd62b */ { true, 0xd62b, 0xd62b }, +/* 0xd62c */ { true, 0xd62c, 0xd62c }, +/* 0xd62d */ { true, 0xd62d, 0xd62d }, +/* 0xd62e */ { true, 0xd62e, 0xd62e }, +/* 0xd62f */ { true, 0xd62f, 0xd62f }, +/* 0xd630 */ { true, 0xd630, 0xd630 }, +/* 0xd631 */ { true, 0xd631, 0xd631 }, +/* 0xd632 */ { true, 0xd632, 0xd632 }, +/* 0xd633 */ { true, 0xd633, 0xd633 }, +/* 0xd634 */ { true, 0xd634, 0xd634 }, +/* 0xd635 */ { true, 0xd635, 0xd635 }, +/* 0xd636 */ { true, 0xd636, 0xd636 }, +/* 0xd637 */ { true, 0xd637, 0xd637 }, +/* 0xd638 */ { true, 0xd638, 0xd638 }, +/* 0xd639 */ { true, 0xd639, 0xd639 }, +/* 0xd63a */ { true, 0xd63a, 0xd63a }, +/* 0xd63b */ { true, 0xd63b, 0xd63b }, +/* 0xd63c */ { true, 0xd63c, 0xd63c }, +/* 0xd63d */ { true, 0xd63d, 0xd63d }, +/* 0xd63e */ { true, 0xd63e, 0xd63e }, +/* 0xd63f */ { true, 0xd63f, 0xd63f }, +/* 0xd640 */ { true, 0xd640, 0xd640 }, +/* 0xd641 */ { true, 0xd641, 0xd641 }, +/* 0xd642 */ { true, 0xd642, 0xd642 }, +/* 0xd643 */ { true, 0xd643, 0xd643 }, +/* 0xd644 */ { true, 0xd644, 0xd644 }, +/* 0xd645 */ { true, 0xd645, 0xd645 }, +/* 0xd646 */ { true, 0xd646, 0xd646 }, +/* 0xd647 */ { true, 0xd647, 0xd647 }, +/* 0xd648 */ { true, 0xd648, 0xd648 }, +/* 0xd649 */ { true, 0xd649, 0xd649 }, +/* 0xd64a */ { true, 0xd64a, 0xd64a }, +/* 0xd64b */ { true, 0xd64b, 0xd64b }, +/* 0xd64c */ { true, 0xd64c, 0xd64c }, +/* 0xd64d */ { true, 0xd64d, 0xd64d }, +/* 0xd64e */ { true, 0xd64e, 0xd64e }, +/* 0xd64f */ { true, 0xd64f, 0xd64f }, +/* 0xd650 */ { true, 0xd650, 0xd650 }, +/* 0xd651 */ { true, 0xd651, 0xd651 }, +/* 0xd652 */ { true, 0xd652, 0xd652 }, +/* 0xd653 */ { true, 0xd653, 0xd653 }, +/* 0xd654 */ { true, 0xd654, 0xd654 }, +/* 0xd655 */ { true, 0xd655, 0xd655 }, +/* 0xd656 */ { true, 0xd656, 0xd656 }, +/* 0xd657 */ { true, 0xd657, 0xd657 }, +/* 0xd658 */ { true, 0xd658, 0xd658 }, +/* 0xd659 */ { true, 0xd659, 0xd659 }, +/* 0xd65a */ { true, 0xd65a, 0xd65a }, +/* 0xd65b */ { true, 0xd65b, 0xd65b }, +/* 0xd65c */ { true, 0xd65c, 0xd65c }, +/* 0xd65d */ { true, 0xd65d, 0xd65d }, +/* 0xd65e */ { true, 0xd65e, 0xd65e }, +/* 0xd65f */ { true, 0xd65f, 0xd65f }, +/* 0xd660 */ { true, 0xd660, 0xd660 }, +/* 0xd661 */ { true, 0xd661, 0xd661 }, +/* 0xd662 */ { true, 0xd662, 0xd662 }, +/* 0xd663 */ { true, 0xd663, 0xd663 }, +/* 0xd664 */ { true, 0xd664, 0xd664 }, +/* 0xd665 */ { true, 0xd665, 0xd665 }, +/* 0xd666 */ { true, 0xd666, 0xd666 }, +/* 0xd667 */ { true, 0xd667, 0xd667 }, +/* 0xd668 */ { true, 0xd668, 0xd668 }, +/* 0xd669 */ { true, 0xd669, 0xd669 }, +/* 0xd66a */ { true, 0xd66a, 0xd66a }, +/* 0xd66b */ { true, 0xd66b, 0xd66b }, +/* 0xd66c */ { true, 0xd66c, 0xd66c }, +/* 0xd66d */ { true, 0xd66d, 0xd66d }, +/* 0xd66e */ { true, 0xd66e, 0xd66e }, +/* 0xd66f */ { true, 0xd66f, 0xd66f }, +/* 0xd670 */ { true, 0xd670, 0xd670 }, +/* 0xd671 */ { true, 0xd671, 0xd671 }, +/* 0xd672 */ { true, 0xd672, 0xd672 }, +/* 0xd673 */ { true, 0xd673, 0xd673 }, +/* 0xd674 */ { true, 0xd674, 0xd674 }, +/* 0xd675 */ { true, 0xd675, 0xd675 }, +/* 0xd676 */ { true, 0xd676, 0xd676 }, +/* 0xd677 */ { true, 0xd677, 0xd677 }, +/* 0xd678 */ { true, 0xd678, 0xd678 }, +/* 0xd679 */ { true, 0xd679, 0xd679 }, +/* 0xd67a */ { true, 0xd67a, 0xd67a }, +/* 0xd67b */ { true, 0xd67b, 0xd67b }, +/* 0xd67c */ { true, 0xd67c, 0xd67c }, +/* 0xd67d */ { true, 0xd67d, 0xd67d }, +/* 0xd67e */ { true, 0xd67e, 0xd67e }, +/* 0xd67f */ { true, 0xd67f, 0xd67f }, +/* 0xd680 */ { true, 0xd680, 0xd680 }, +/* 0xd681 */ { true, 0xd681, 0xd681 }, +/* 0xd682 */ { true, 0xd682, 0xd682 }, +/* 0xd683 */ { true, 0xd683, 0xd683 }, +/* 0xd684 */ { true, 0xd684, 0xd684 }, +/* 0xd685 */ { true, 0xd685, 0xd685 }, +/* 0xd686 */ { true, 0xd686, 0xd686 }, +/* 0xd687 */ { true, 0xd687, 0xd687 }, +/* 0xd688 */ { true, 0xd688, 0xd688 }, +/* 0xd689 */ { true, 0xd689, 0xd689 }, +/* 0xd68a */ { true, 0xd68a, 0xd68a }, +/* 0xd68b */ { true, 0xd68b, 0xd68b }, +/* 0xd68c */ { true, 0xd68c, 0xd68c }, +/* 0xd68d */ { true, 0xd68d, 0xd68d }, +/* 0xd68e */ { true, 0xd68e, 0xd68e }, +/* 0xd68f */ { true, 0xd68f, 0xd68f }, +/* 0xd690 */ { true, 0xd690, 0xd690 }, +/* 0xd691 */ { true, 0xd691, 0xd691 }, +/* 0xd692 */ { true, 0xd692, 0xd692 }, +/* 0xd693 */ { true, 0xd693, 0xd693 }, +/* 0xd694 */ { true, 0xd694, 0xd694 }, +/* 0xd695 */ { true, 0xd695, 0xd695 }, +/* 0xd696 */ { true, 0xd696, 0xd696 }, +/* 0xd697 */ { true, 0xd697, 0xd697 }, +/* 0xd698 */ { true, 0xd698, 0xd698 }, +/* 0xd699 */ { true, 0xd699, 0xd699 }, +/* 0xd69a */ { true, 0xd69a, 0xd69a }, +/* 0xd69b */ { true, 0xd69b, 0xd69b }, +/* 0xd69c */ { true, 0xd69c, 0xd69c }, +/* 0xd69d */ { true, 0xd69d, 0xd69d }, +/* 0xd69e */ { true, 0xd69e, 0xd69e }, +/* 0xd69f */ { true, 0xd69f, 0xd69f }, +/* 0xd6a0 */ { true, 0xd6a0, 0xd6a0 }, +/* 0xd6a1 */ { true, 0xd6a1, 0xd6a1 }, +/* 0xd6a2 */ { true, 0xd6a2, 0xd6a2 }, +/* 0xd6a3 */ { true, 0xd6a3, 0xd6a3 }, +/* 0xd6a4 */ { true, 0xd6a4, 0xd6a4 }, +/* 0xd6a5 */ { true, 0xd6a5, 0xd6a5 }, +/* 0xd6a6 */ { true, 0xd6a6, 0xd6a6 }, +/* 0xd6a7 */ { true, 0xd6a7, 0xd6a7 }, +/* 0xd6a8 */ { true, 0xd6a8, 0xd6a8 }, +/* 0xd6a9 */ { true, 0xd6a9, 0xd6a9 }, +/* 0xd6aa */ { true, 0xd6aa, 0xd6aa }, +/* 0xd6ab */ { true, 0xd6ab, 0xd6ab }, +/* 0xd6ac */ { true, 0xd6ac, 0xd6ac }, +/* 0xd6ad */ { true, 0xd6ad, 0xd6ad }, +/* 0xd6ae */ { true, 0xd6ae, 0xd6ae }, +/* 0xd6af */ { true, 0xd6af, 0xd6af }, +/* 0xd6b0 */ { true, 0xd6b0, 0xd6b0 }, +/* 0xd6b1 */ { true, 0xd6b1, 0xd6b1 }, +/* 0xd6b2 */ { true, 0xd6b2, 0xd6b2 }, +/* 0xd6b3 */ { true, 0xd6b3, 0xd6b3 }, +/* 0xd6b4 */ { true, 0xd6b4, 0xd6b4 }, +/* 0xd6b5 */ { true, 0xd6b5, 0xd6b5 }, +/* 0xd6b6 */ { true, 0xd6b6, 0xd6b6 }, +/* 0xd6b7 */ { true, 0xd6b7, 0xd6b7 }, +/* 0xd6b8 */ { true, 0xd6b8, 0xd6b8 }, +/* 0xd6b9 */ { true, 0xd6b9, 0xd6b9 }, +/* 0xd6ba */ { true, 0xd6ba, 0xd6ba }, +/* 0xd6bb */ { true, 0xd6bb, 0xd6bb }, +/* 0xd6bc */ { true, 0xd6bc, 0xd6bc }, +/* 0xd6bd */ { true, 0xd6bd, 0xd6bd }, +/* 0xd6be */ { true, 0xd6be, 0xd6be }, +/* 0xd6bf */ { true, 0xd6bf, 0xd6bf }, +/* 0xd6c0 */ { true, 0xd6c0, 0xd6c0 }, +/* 0xd6c1 */ { true, 0xd6c1, 0xd6c1 }, +/* 0xd6c2 */ { true, 0xd6c2, 0xd6c2 }, +/* 0xd6c3 */ { true, 0xd6c3, 0xd6c3 }, +/* 0xd6c4 */ { true, 0xd6c4, 0xd6c4 }, +/* 0xd6c5 */ { true, 0xd6c5, 0xd6c5 }, +/* 0xd6c6 */ { true, 0xd6c6, 0xd6c6 }, +/* 0xd6c7 */ { true, 0xd6c7, 0xd6c7 }, +/* 0xd6c8 */ { true, 0xd6c8, 0xd6c8 }, +/* 0xd6c9 */ { true, 0xd6c9, 0xd6c9 }, +/* 0xd6ca */ { true, 0xd6ca, 0xd6ca }, +/* 0xd6cb */ { true, 0xd6cb, 0xd6cb }, +/* 0xd6cc */ { true, 0xd6cc, 0xd6cc }, +/* 0xd6cd */ { true, 0xd6cd, 0xd6cd }, +/* 0xd6ce */ { true, 0xd6ce, 0xd6ce }, +/* 0xd6cf */ { true, 0xd6cf, 0xd6cf }, +/* 0xd6d0 */ { true, 0xd6d0, 0xd6d0 }, +/* 0xd6d1 */ { true, 0xd6d1, 0xd6d1 }, +/* 0xd6d2 */ { true, 0xd6d2, 0xd6d2 }, +/* 0xd6d3 */ { true, 0xd6d3, 0xd6d3 }, +/* 0xd6d4 */ { true, 0xd6d4, 0xd6d4 }, +/* 0xd6d5 */ { true, 0xd6d5, 0xd6d5 }, +/* 0xd6d6 */ { true, 0xd6d6, 0xd6d6 }, +/* 0xd6d7 */ { true, 0xd6d7, 0xd6d7 }, +/* 0xd6d8 */ { true, 0xd6d8, 0xd6d8 }, +/* 0xd6d9 */ { true, 0xd6d9, 0xd6d9 }, +/* 0xd6da */ { true, 0xd6da, 0xd6da }, +/* 0xd6db */ { true, 0xd6db, 0xd6db }, +/* 0xd6dc */ { true, 0xd6dc, 0xd6dc }, +/* 0xd6dd */ { true, 0xd6dd, 0xd6dd }, +/* 0xd6de */ { true, 0xd6de, 0xd6de }, +/* 0xd6df */ { true, 0xd6df, 0xd6df }, +/* 0xd6e0 */ { true, 0xd6e0, 0xd6e0 }, +/* 0xd6e1 */ { true, 0xd6e1, 0xd6e1 }, +/* 0xd6e2 */ { true, 0xd6e2, 0xd6e2 }, +/* 0xd6e3 */ { true, 0xd6e3, 0xd6e3 }, +/* 0xd6e4 */ { true, 0xd6e4, 0xd6e4 }, +/* 0xd6e5 */ { true, 0xd6e5, 0xd6e5 }, +/* 0xd6e6 */ { true, 0xd6e6, 0xd6e6 }, +/* 0xd6e7 */ { true, 0xd6e7, 0xd6e7 }, +/* 0xd6e8 */ { true, 0xd6e8, 0xd6e8 }, +/* 0xd6e9 */ { true, 0xd6e9, 0xd6e9 }, +/* 0xd6ea */ { true, 0xd6ea, 0xd6ea }, +/* 0xd6eb */ { true, 0xd6eb, 0xd6eb }, +/* 0xd6ec */ { true, 0xd6ec, 0xd6ec }, +/* 0xd6ed */ { true, 0xd6ed, 0xd6ed }, +/* 0xd6ee */ { true, 0xd6ee, 0xd6ee }, +/* 0xd6ef */ { true, 0xd6ef, 0xd6ef }, +/* 0xd6f0 */ { true, 0xd6f0, 0xd6f0 }, +/* 0xd6f1 */ { true, 0xd6f1, 0xd6f1 }, +/* 0xd6f2 */ { true, 0xd6f2, 0xd6f2 }, +/* 0xd6f3 */ { true, 0xd6f3, 0xd6f3 }, +/* 0xd6f4 */ { true, 0xd6f4, 0xd6f4 }, +/* 0xd6f5 */ { true, 0xd6f5, 0xd6f5 }, +/* 0xd6f6 */ { true, 0xd6f6, 0xd6f6 }, +/* 0xd6f7 */ { true, 0xd6f7, 0xd6f7 }, +/* 0xd6f8 */ { true, 0xd6f8, 0xd6f8 }, +/* 0xd6f9 */ { true, 0xd6f9, 0xd6f9 }, +/* 0xd6fa */ { true, 0xd6fa, 0xd6fa }, +/* 0xd6fb */ { true, 0xd6fb, 0xd6fb }, +/* 0xd6fc */ { true, 0xd6fc, 0xd6fc }, +/* 0xd6fd */ { true, 0xd6fd, 0xd6fd }, +/* 0xd6fe */ { true, 0xd6fe, 0xd6fe }, +/* 0xd6ff */ { true, 0xd6ff, 0xd6ff }, +/* 0xd700 */ { true, 0xd700, 0xd700 }, +/* 0xd701 */ { true, 0xd701, 0xd701 }, +/* 0xd702 */ { true, 0xd702, 0xd702 }, +/* 0xd703 */ { true, 0xd703, 0xd703 }, +/* 0xd704 */ { true, 0xd704, 0xd704 }, +/* 0xd705 */ { true, 0xd705, 0xd705 }, +/* 0xd706 */ { true, 0xd706, 0xd706 }, +/* 0xd707 */ { true, 0xd707, 0xd707 }, +/* 0xd708 */ { true, 0xd708, 0xd708 }, +/* 0xd709 */ { true, 0xd709, 0xd709 }, +/* 0xd70a */ { true, 0xd70a, 0xd70a }, +/* 0xd70b */ { true, 0xd70b, 0xd70b }, +/* 0xd70c */ { true, 0xd70c, 0xd70c }, +/* 0xd70d */ { true, 0xd70d, 0xd70d }, +/* 0xd70e */ { true, 0xd70e, 0xd70e }, +/* 0xd70f */ { true, 0xd70f, 0xd70f }, +/* 0xd710 */ { true, 0xd710, 0xd710 }, +/* 0xd711 */ { true, 0xd711, 0xd711 }, +/* 0xd712 */ { true, 0xd712, 0xd712 }, +/* 0xd713 */ { true, 0xd713, 0xd713 }, +/* 0xd714 */ { true, 0xd714, 0xd714 }, +/* 0xd715 */ { true, 0xd715, 0xd715 }, +/* 0xd716 */ { true, 0xd716, 0xd716 }, +/* 0xd717 */ { true, 0xd717, 0xd717 }, +/* 0xd718 */ { true, 0xd718, 0xd718 }, +/* 0xd719 */ { true, 0xd719, 0xd719 }, +/* 0xd71a */ { true, 0xd71a, 0xd71a }, +/* 0xd71b */ { true, 0xd71b, 0xd71b }, +/* 0xd71c */ { true, 0xd71c, 0xd71c }, +/* 0xd71d */ { true, 0xd71d, 0xd71d }, +/* 0xd71e */ { true, 0xd71e, 0xd71e }, +/* 0xd71f */ { true, 0xd71f, 0xd71f }, +/* 0xd720 */ { true, 0xd720, 0xd720 }, +/* 0xd721 */ { true, 0xd721, 0xd721 }, +/* 0xd722 */ { true, 0xd722, 0xd722 }, +/* 0xd723 */ { true, 0xd723, 0xd723 }, +/* 0xd724 */ { true, 0xd724, 0xd724 }, +/* 0xd725 */ { true, 0xd725, 0xd725 }, +/* 0xd726 */ { true, 0xd726, 0xd726 }, +/* 0xd727 */ { true, 0xd727, 0xd727 }, +/* 0xd728 */ { true, 0xd728, 0xd728 }, +/* 0xd729 */ { true, 0xd729, 0xd729 }, +/* 0xd72a */ { true, 0xd72a, 0xd72a }, +/* 0xd72b */ { true, 0xd72b, 0xd72b }, +/* 0xd72c */ { true, 0xd72c, 0xd72c }, +/* 0xd72d */ { true, 0xd72d, 0xd72d }, +/* 0xd72e */ { true, 0xd72e, 0xd72e }, +/* 0xd72f */ { true, 0xd72f, 0xd72f }, +/* 0xd730 */ { true, 0xd730, 0xd730 }, +/* 0xd731 */ { true, 0xd731, 0xd731 }, +/* 0xd732 */ { true, 0xd732, 0xd732 }, +/* 0xd733 */ { true, 0xd733, 0xd733 }, +/* 0xd734 */ { true, 0xd734, 0xd734 }, +/* 0xd735 */ { true, 0xd735, 0xd735 }, +/* 0xd736 */ { true, 0xd736, 0xd736 }, +/* 0xd737 */ { true, 0xd737, 0xd737 }, +/* 0xd738 */ { true, 0xd738, 0xd738 }, +/* 0xd739 */ { true, 0xd739, 0xd739 }, +/* 0xd73a */ { true, 0xd73a, 0xd73a }, +/* 0xd73b */ { true, 0xd73b, 0xd73b }, +/* 0xd73c */ { true, 0xd73c, 0xd73c }, +/* 0xd73d */ { true, 0xd73d, 0xd73d }, +/* 0xd73e */ { true, 0xd73e, 0xd73e }, +/* 0xd73f */ { true, 0xd73f, 0xd73f }, +/* 0xd740 */ { true, 0xd740, 0xd740 }, +/* 0xd741 */ { true, 0xd741, 0xd741 }, +/* 0xd742 */ { true, 0xd742, 0xd742 }, +/* 0xd743 */ { true, 0xd743, 0xd743 }, +/* 0xd744 */ { true, 0xd744, 0xd744 }, +/* 0xd745 */ { true, 0xd745, 0xd745 }, +/* 0xd746 */ { true, 0xd746, 0xd746 }, +/* 0xd747 */ { true, 0xd747, 0xd747 }, +/* 0xd748 */ { true, 0xd748, 0xd748 }, +/* 0xd749 */ { true, 0xd749, 0xd749 }, +/* 0xd74a */ { true, 0xd74a, 0xd74a }, +/* 0xd74b */ { true, 0xd74b, 0xd74b }, +/* 0xd74c */ { true, 0xd74c, 0xd74c }, +/* 0xd74d */ { true, 0xd74d, 0xd74d }, +/* 0xd74e */ { true, 0xd74e, 0xd74e }, +/* 0xd74f */ { true, 0xd74f, 0xd74f }, +/* 0xd750 */ { true, 0xd750, 0xd750 }, +/* 0xd751 */ { true, 0xd751, 0xd751 }, +/* 0xd752 */ { true, 0xd752, 0xd752 }, +/* 0xd753 */ { true, 0xd753, 0xd753 }, +/* 0xd754 */ { true, 0xd754, 0xd754 }, +/* 0xd755 */ { true, 0xd755, 0xd755 }, +/* 0xd756 */ { true, 0xd756, 0xd756 }, +/* 0xd757 */ { true, 0xd757, 0xd757 }, +/* 0xd758 */ { true, 0xd758, 0xd758 }, +/* 0xd759 */ { true, 0xd759, 0xd759 }, +/* 0xd75a */ { true, 0xd75a, 0xd75a }, +/* 0xd75b */ { true, 0xd75b, 0xd75b }, +/* 0xd75c */ { true, 0xd75c, 0xd75c }, +/* 0xd75d */ { true, 0xd75d, 0xd75d }, +/* 0xd75e */ { true, 0xd75e, 0xd75e }, +/* 0xd75f */ { true, 0xd75f, 0xd75f }, +/* 0xd760 */ { true, 0xd760, 0xd760 }, +/* 0xd761 */ { true, 0xd761, 0xd761 }, +/* 0xd762 */ { true, 0xd762, 0xd762 }, +/* 0xd763 */ { true, 0xd763, 0xd763 }, +/* 0xd764 */ { true, 0xd764, 0xd764 }, +/* 0xd765 */ { true, 0xd765, 0xd765 }, +/* 0xd766 */ { true, 0xd766, 0xd766 }, +/* 0xd767 */ { true, 0xd767, 0xd767 }, +/* 0xd768 */ { true, 0xd768, 0xd768 }, +/* 0xd769 */ { true, 0xd769, 0xd769 }, +/* 0xd76a */ { true, 0xd76a, 0xd76a }, +/* 0xd76b */ { true, 0xd76b, 0xd76b }, +/* 0xd76c */ { true, 0xd76c, 0xd76c }, +/* 0xd76d */ { true, 0xd76d, 0xd76d }, +/* 0xd76e */ { true, 0xd76e, 0xd76e }, +/* 0xd76f */ { true, 0xd76f, 0xd76f }, +/* 0xd770 */ { true, 0xd770, 0xd770 }, +/* 0xd771 */ { true, 0xd771, 0xd771 }, +/* 0xd772 */ { true, 0xd772, 0xd772 }, +/* 0xd773 */ { true, 0xd773, 0xd773 }, +/* 0xd774 */ { true, 0xd774, 0xd774 }, +/* 0xd775 */ { true, 0xd775, 0xd775 }, +/* 0xd776 */ { true, 0xd776, 0xd776 }, +/* 0xd777 */ { true, 0xd777, 0xd777 }, +/* 0xd778 */ { true, 0xd778, 0xd778 }, +/* 0xd779 */ { true, 0xd779, 0xd779 }, +/* 0xd77a */ { true, 0xd77a, 0xd77a }, +/* 0xd77b */ { true, 0xd77b, 0xd77b }, +/* 0xd77c */ { true, 0xd77c, 0xd77c }, +/* 0xd77d */ { true, 0xd77d, 0xd77d }, +/* 0xd77e */ { true, 0xd77e, 0xd77e }, +/* 0xd77f */ { true, 0xd77f, 0xd77f }, +/* 0xd780 */ { true, 0xd780, 0xd780 }, +/* 0xd781 */ { true, 0xd781, 0xd781 }, +/* 0xd782 */ { true, 0xd782, 0xd782 }, +/* 0xd783 */ { true, 0xd783, 0xd783 }, +/* 0xd784 */ { true, 0xd784, 0xd784 }, +/* 0xd785 */ { true, 0xd785, 0xd785 }, +/* 0xd786 */ { true, 0xd786, 0xd786 }, +/* 0xd787 */ { true, 0xd787, 0xd787 }, +/* 0xd788 */ { true, 0xd788, 0xd788 }, +/* 0xd789 */ { true, 0xd789, 0xd789 }, +/* 0xd78a */ { true, 0xd78a, 0xd78a }, +/* 0xd78b */ { true, 0xd78b, 0xd78b }, +/* 0xd78c */ { true, 0xd78c, 0xd78c }, +/* 0xd78d */ { true, 0xd78d, 0xd78d }, +/* 0xd78e */ { true, 0xd78e, 0xd78e }, +/* 0xd78f */ { true, 0xd78f, 0xd78f }, +/* 0xd790 */ { true, 0xd790, 0xd790 }, +/* 0xd791 */ { true, 0xd791, 0xd791 }, +/* 0xd792 */ { true, 0xd792, 0xd792 }, +/* 0xd793 */ { true, 0xd793, 0xd793 }, +/* 0xd794 */ { true, 0xd794, 0xd794 }, +/* 0xd795 */ { true, 0xd795, 0xd795 }, +/* 0xd796 */ { true, 0xd796, 0xd796 }, +/* 0xd797 */ { true, 0xd797, 0xd797 }, +/* 0xd798 */ { true, 0xd798, 0xd798 }, +/* 0xd799 */ { true, 0xd799, 0xd799 }, +/* 0xd79a */ { true, 0xd79a, 0xd79a }, +/* 0xd79b */ { true, 0xd79b, 0xd79b }, +/* 0xd79c */ { true, 0xd79c, 0xd79c }, +/* 0xd79d */ { true, 0xd79d, 0xd79d }, +/* 0xd79e */ { true, 0xd79e, 0xd79e }, +/* 0xd79f */ { true, 0xd79f, 0xd79f }, +/* 0xd7a0 */ { true, 0xd7a0, 0xd7a0 }, +/* 0xd7a1 */ { true, 0xd7a1, 0xd7a1 }, +/* 0xd7a2 */ { true, 0xd7a2, 0xd7a2 }, +/* 0xd7a3 */ { true, 0xd7a3, 0xd7a3 }, +/* 0xd7a4 */ { false, 0xd7a4, 0xd7a4 }, +/* 0xd7a5 */ { false, 0xd7a5, 0xd7a5 }, +/* 0xd7a6 */ { false, 0xd7a6, 0xd7a6 }, +/* 0xd7a7 */ { false, 0xd7a7, 0xd7a7 }, +/* 0xd7a8 */ { false, 0xd7a8, 0xd7a8 }, +/* 0xd7a9 */ { false, 0xd7a9, 0xd7a9 }, +/* 0xd7aa */ { false, 0xd7aa, 0xd7aa }, +/* 0xd7ab */ { false, 0xd7ab, 0xd7ab }, +/* 0xd7ac */ { false, 0xd7ac, 0xd7ac }, +/* 0xd7ad */ { false, 0xd7ad, 0xd7ad }, +/* 0xd7ae */ { false, 0xd7ae, 0xd7ae }, +/* 0xd7af */ { false, 0xd7af, 0xd7af }, +/* 0xd7b0 */ { false, 0xd7b0, 0xd7b0 }, +/* 0xd7b1 */ { false, 0xd7b1, 0xd7b1 }, +/* 0xd7b2 */ { false, 0xd7b2, 0xd7b2 }, +/* 0xd7b3 */ { false, 0xd7b3, 0xd7b3 }, +/* 0xd7b4 */ { false, 0xd7b4, 0xd7b4 }, +/* 0xd7b5 */ { false, 0xd7b5, 0xd7b5 }, +/* 0xd7b6 */ { false, 0xd7b6, 0xd7b6 }, +/* 0xd7b7 */ { false, 0xd7b7, 0xd7b7 }, +/* 0xd7b8 */ { false, 0xd7b8, 0xd7b8 }, +/* 0xd7b9 */ { false, 0xd7b9, 0xd7b9 }, +/* 0xd7ba */ { false, 0xd7ba, 0xd7ba }, +/* 0xd7bb */ { false, 0xd7bb, 0xd7bb }, +/* 0xd7bc */ { false, 0xd7bc, 0xd7bc }, +/* 0xd7bd */ { false, 0xd7bd, 0xd7bd }, +/* 0xd7be */ { false, 0xd7be, 0xd7be }, +/* 0xd7bf */ { false, 0xd7bf, 0xd7bf }, +/* 0xd7c0 */ { false, 0xd7c0, 0xd7c0 }, +/* 0xd7c1 */ { false, 0xd7c1, 0xd7c1 }, +/* 0xd7c2 */ { false, 0xd7c2, 0xd7c2 }, +/* 0xd7c3 */ { false, 0xd7c3, 0xd7c3 }, +/* 0xd7c4 */ { false, 0xd7c4, 0xd7c4 }, +/* 0xd7c5 */ { false, 0xd7c5, 0xd7c5 }, +/* 0xd7c6 */ { false, 0xd7c6, 0xd7c6 }, +/* 0xd7c7 */ { false, 0xd7c7, 0xd7c7 }, +/* 0xd7c8 */ { false, 0xd7c8, 0xd7c8 }, +/* 0xd7c9 */ { false, 0xd7c9, 0xd7c9 }, +/* 0xd7ca */ { false, 0xd7ca, 0xd7ca }, +/* 0xd7cb */ { false, 0xd7cb, 0xd7cb }, +/* 0xd7cc */ { false, 0xd7cc, 0xd7cc }, +/* 0xd7cd */ { false, 0xd7cd, 0xd7cd }, +/* 0xd7ce */ { false, 0xd7ce, 0xd7ce }, +/* 0xd7cf */ { false, 0xd7cf, 0xd7cf }, +/* 0xd7d0 */ { false, 0xd7d0, 0xd7d0 }, +/* 0xd7d1 */ { false, 0xd7d1, 0xd7d1 }, +/* 0xd7d2 */ { false, 0xd7d2, 0xd7d2 }, +/* 0xd7d3 */ { false, 0xd7d3, 0xd7d3 }, +/* 0xd7d4 */ { false, 0xd7d4, 0xd7d4 }, +/* 0xd7d5 */ { false, 0xd7d5, 0xd7d5 }, +/* 0xd7d6 */ { false, 0xd7d6, 0xd7d6 }, +/* 0xd7d7 */ { false, 0xd7d7, 0xd7d7 }, +/* 0xd7d8 */ { false, 0xd7d8, 0xd7d8 }, +/* 0xd7d9 */ { false, 0xd7d9, 0xd7d9 }, +/* 0xd7da */ { false, 0xd7da, 0xd7da }, +/* 0xd7db */ { false, 0xd7db, 0xd7db }, +/* 0xd7dc */ { false, 0xd7dc, 0xd7dc }, +/* 0xd7dd */ { false, 0xd7dd, 0xd7dd }, +/* 0xd7de */ { false, 0xd7de, 0xd7de }, +/* 0xd7df */ { false, 0xd7df, 0xd7df }, +/* 0xd7e0 */ { false, 0xd7e0, 0xd7e0 }, +/* 0xd7e1 */ { false, 0xd7e1, 0xd7e1 }, +/* 0xd7e2 */ { false, 0xd7e2, 0xd7e2 }, +/* 0xd7e3 */ { false, 0xd7e3, 0xd7e3 }, +/* 0xd7e4 */ { false, 0xd7e4, 0xd7e4 }, +/* 0xd7e5 */ { false, 0xd7e5, 0xd7e5 }, +/* 0xd7e6 */ { false, 0xd7e6, 0xd7e6 }, +/* 0xd7e7 */ { false, 0xd7e7, 0xd7e7 }, +/* 0xd7e8 */ { false, 0xd7e8, 0xd7e8 }, +/* 0xd7e9 */ { false, 0xd7e9, 0xd7e9 }, +/* 0xd7ea */ { false, 0xd7ea, 0xd7ea }, +/* 0xd7eb */ { false, 0xd7eb, 0xd7eb }, +/* 0xd7ec */ { false, 0xd7ec, 0xd7ec }, +/* 0xd7ed */ { false, 0xd7ed, 0xd7ed }, +/* 0xd7ee */ { false, 0xd7ee, 0xd7ee }, +/* 0xd7ef */ { false, 0xd7ef, 0xd7ef }, +/* 0xd7f0 */ { false, 0xd7f0, 0xd7f0 }, +/* 0xd7f1 */ { false, 0xd7f1, 0xd7f1 }, +/* 0xd7f2 */ { false, 0xd7f2, 0xd7f2 }, +/* 0xd7f3 */ { false, 0xd7f3, 0xd7f3 }, +/* 0xd7f4 */ { false, 0xd7f4, 0xd7f4 }, +/* 0xd7f5 */ { false, 0xd7f5, 0xd7f5 }, +/* 0xd7f6 */ { false, 0xd7f6, 0xd7f6 }, +/* 0xd7f7 */ { false, 0xd7f7, 0xd7f7 }, +/* 0xd7f8 */ { false, 0xd7f8, 0xd7f8 }, +/* 0xd7f9 */ { false, 0xd7f9, 0xd7f9 }, +/* 0xd7fa */ { false, 0xd7fa, 0xd7fa }, +/* 0xd7fb */ { false, 0xd7fb, 0xd7fb }, +/* 0xd7fc */ { false, 0xd7fc, 0xd7fc }, +/* 0xd7fd */ { false, 0xd7fd, 0xd7fd }, +/* 0xd7fe */ { false, 0xd7fe, 0xd7fe }, +/* 0xd7ff */ { false, 0xd7ff, 0xd7ff }, +/* 0xd800 */ { false, 0xd800, 0xd800 }, +/* 0xd801 */ { false, 0xd801, 0xd801 }, +/* 0xd802 */ { false, 0xd802, 0xd802 }, +/* 0xd803 */ { false, 0xd803, 0xd803 }, +/* 0xd804 */ { false, 0xd804, 0xd804 }, +/* 0xd805 */ { false, 0xd805, 0xd805 }, +/* 0xd806 */ { false, 0xd806, 0xd806 }, +/* 0xd807 */ { false, 0xd807, 0xd807 }, +/* 0xd808 */ { false, 0xd808, 0xd808 }, +/* 0xd809 */ { false, 0xd809, 0xd809 }, +/* 0xd80a */ { false, 0xd80a, 0xd80a }, +/* 0xd80b */ { false, 0xd80b, 0xd80b }, +/* 0xd80c */ { false, 0xd80c, 0xd80c }, +/* 0xd80d */ { false, 0xd80d, 0xd80d }, +/* 0xd80e */ { false, 0xd80e, 0xd80e }, +/* 0xd80f */ { false, 0xd80f, 0xd80f }, +/* 0xd810 */ { false, 0xd810, 0xd810 }, +/* 0xd811 */ { false, 0xd811, 0xd811 }, +/* 0xd812 */ { false, 0xd812, 0xd812 }, +/* 0xd813 */ { false, 0xd813, 0xd813 }, +/* 0xd814 */ { false, 0xd814, 0xd814 }, +/* 0xd815 */ { false, 0xd815, 0xd815 }, +/* 0xd816 */ { false, 0xd816, 0xd816 }, +/* 0xd817 */ { false, 0xd817, 0xd817 }, +/* 0xd818 */ { false, 0xd818, 0xd818 }, +/* 0xd819 */ { false, 0xd819, 0xd819 }, +/* 0xd81a */ { false, 0xd81a, 0xd81a }, +/* 0xd81b */ { false, 0xd81b, 0xd81b }, +/* 0xd81c */ { false, 0xd81c, 0xd81c }, +/* 0xd81d */ { false, 0xd81d, 0xd81d }, +/* 0xd81e */ { false, 0xd81e, 0xd81e }, +/* 0xd81f */ { false, 0xd81f, 0xd81f }, +/* 0xd820 */ { false, 0xd820, 0xd820 }, +/* 0xd821 */ { false, 0xd821, 0xd821 }, +/* 0xd822 */ { false, 0xd822, 0xd822 }, +/* 0xd823 */ { false, 0xd823, 0xd823 }, +/* 0xd824 */ { false, 0xd824, 0xd824 }, +/* 0xd825 */ { false, 0xd825, 0xd825 }, +/* 0xd826 */ { false, 0xd826, 0xd826 }, +/* 0xd827 */ { false, 0xd827, 0xd827 }, +/* 0xd828 */ { false, 0xd828, 0xd828 }, +/* 0xd829 */ { false, 0xd829, 0xd829 }, +/* 0xd82a */ { false, 0xd82a, 0xd82a }, +/* 0xd82b */ { false, 0xd82b, 0xd82b }, +/* 0xd82c */ { false, 0xd82c, 0xd82c }, +/* 0xd82d */ { false, 0xd82d, 0xd82d }, +/* 0xd82e */ { false, 0xd82e, 0xd82e }, +/* 0xd82f */ { false, 0xd82f, 0xd82f }, +/* 0xd830 */ { false, 0xd830, 0xd830 }, +/* 0xd831 */ { false, 0xd831, 0xd831 }, +/* 0xd832 */ { false, 0xd832, 0xd832 }, +/* 0xd833 */ { false, 0xd833, 0xd833 }, +/* 0xd834 */ { false, 0xd834, 0xd834 }, +/* 0xd835 */ { false, 0xd835, 0xd835 }, +/* 0xd836 */ { false, 0xd836, 0xd836 }, +/* 0xd837 */ { false, 0xd837, 0xd837 }, +/* 0xd838 */ { false, 0xd838, 0xd838 }, +/* 0xd839 */ { false, 0xd839, 0xd839 }, +/* 0xd83a */ { false, 0xd83a, 0xd83a }, +/* 0xd83b */ { false, 0xd83b, 0xd83b }, +/* 0xd83c */ { false, 0xd83c, 0xd83c }, +/* 0xd83d */ { false, 0xd83d, 0xd83d }, +/* 0xd83e */ { false, 0xd83e, 0xd83e }, +/* 0xd83f */ { false, 0xd83f, 0xd83f }, +/* 0xd840 */ { false, 0xd840, 0xd840 }, +/* 0xd841 */ { false, 0xd841, 0xd841 }, +/* 0xd842 */ { false, 0xd842, 0xd842 }, +/* 0xd843 */ { false, 0xd843, 0xd843 }, +/* 0xd844 */ { false, 0xd844, 0xd844 }, +/* 0xd845 */ { false, 0xd845, 0xd845 }, +/* 0xd846 */ { false, 0xd846, 0xd846 }, +/* 0xd847 */ { false, 0xd847, 0xd847 }, +/* 0xd848 */ { false, 0xd848, 0xd848 }, +/* 0xd849 */ { false, 0xd849, 0xd849 }, +/* 0xd84a */ { false, 0xd84a, 0xd84a }, +/* 0xd84b */ { false, 0xd84b, 0xd84b }, +/* 0xd84c */ { false, 0xd84c, 0xd84c }, +/* 0xd84d */ { false, 0xd84d, 0xd84d }, +/* 0xd84e */ { false, 0xd84e, 0xd84e }, +/* 0xd84f */ { false, 0xd84f, 0xd84f }, +/* 0xd850 */ { false, 0xd850, 0xd850 }, +/* 0xd851 */ { false, 0xd851, 0xd851 }, +/* 0xd852 */ { false, 0xd852, 0xd852 }, +/* 0xd853 */ { false, 0xd853, 0xd853 }, +/* 0xd854 */ { false, 0xd854, 0xd854 }, +/* 0xd855 */ { false, 0xd855, 0xd855 }, +/* 0xd856 */ { false, 0xd856, 0xd856 }, +/* 0xd857 */ { false, 0xd857, 0xd857 }, +/* 0xd858 */ { false, 0xd858, 0xd858 }, +/* 0xd859 */ { false, 0xd859, 0xd859 }, +/* 0xd85a */ { false, 0xd85a, 0xd85a }, +/* 0xd85b */ { false, 0xd85b, 0xd85b }, +/* 0xd85c */ { false, 0xd85c, 0xd85c }, +/* 0xd85d */ { false, 0xd85d, 0xd85d }, +/* 0xd85e */ { false, 0xd85e, 0xd85e }, +/* 0xd85f */ { false, 0xd85f, 0xd85f }, +/* 0xd860 */ { false, 0xd860, 0xd860 }, +/* 0xd861 */ { false, 0xd861, 0xd861 }, +/* 0xd862 */ { false, 0xd862, 0xd862 }, +/* 0xd863 */ { false, 0xd863, 0xd863 }, +/* 0xd864 */ { false, 0xd864, 0xd864 }, +/* 0xd865 */ { false, 0xd865, 0xd865 }, +/* 0xd866 */ { false, 0xd866, 0xd866 }, +/* 0xd867 */ { false, 0xd867, 0xd867 }, +/* 0xd868 */ { false, 0xd868, 0xd868 }, +/* 0xd869 */ { false, 0xd869, 0xd869 }, +/* 0xd86a */ { false, 0xd86a, 0xd86a }, +/* 0xd86b */ { false, 0xd86b, 0xd86b }, +/* 0xd86c */ { false, 0xd86c, 0xd86c }, +/* 0xd86d */ { false, 0xd86d, 0xd86d }, +/* 0xd86e */ { false, 0xd86e, 0xd86e }, +/* 0xd86f */ { false, 0xd86f, 0xd86f }, +/* 0xd870 */ { false, 0xd870, 0xd870 }, +/* 0xd871 */ { false, 0xd871, 0xd871 }, +/* 0xd872 */ { false, 0xd872, 0xd872 }, +/* 0xd873 */ { false, 0xd873, 0xd873 }, +/* 0xd874 */ { false, 0xd874, 0xd874 }, +/* 0xd875 */ { false, 0xd875, 0xd875 }, +/* 0xd876 */ { false, 0xd876, 0xd876 }, +/* 0xd877 */ { false, 0xd877, 0xd877 }, +/* 0xd878 */ { false, 0xd878, 0xd878 }, +/* 0xd879 */ { false, 0xd879, 0xd879 }, +/* 0xd87a */ { false, 0xd87a, 0xd87a }, +/* 0xd87b */ { false, 0xd87b, 0xd87b }, +/* 0xd87c */ { false, 0xd87c, 0xd87c }, +/* 0xd87d */ { false, 0xd87d, 0xd87d }, +/* 0xd87e */ { false, 0xd87e, 0xd87e }, +/* 0xd87f */ { false, 0xd87f, 0xd87f }, +/* 0xd880 */ { false, 0xd880, 0xd880 }, +/* 0xd881 */ { false, 0xd881, 0xd881 }, +/* 0xd882 */ { false, 0xd882, 0xd882 }, +/* 0xd883 */ { false, 0xd883, 0xd883 }, +/* 0xd884 */ { false, 0xd884, 0xd884 }, +/* 0xd885 */ { false, 0xd885, 0xd885 }, +/* 0xd886 */ { false, 0xd886, 0xd886 }, +/* 0xd887 */ { false, 0xd887, 0xd887 }, +/* 0xd888 */ { false, 0xd888, 0xd888 }, +/* 0xd889 */ { false, 0xd889, 0xd889 }, +/* 0xd88a */ { false, 0xd88a, 0xd88a }, +/* 0xd88b */ { false, 0xd88b, 0xd88b }, +/* 0xd88c */ { false, 0xd88c, 0xd88c }, +/* 0xd88d */ { false, 0xd88d, 0xd88d }, +/* 0xd88e */ { false, 0xd88e, 0xd88e }, +/* 0xd88f */ { false, 0xd88f, 0xd88f }, +/* 0xd890 */ { false, 0xd890, 0xd890 }, +/* 0xd891 */ { false, 0xd891, 0xd891 }, +/* 0xd892 */ { false, 0xd892, 0xd892 }, +/* 0xd893 */ { false, 0xd893, 0xd893 }, +/* 0xd894 */ { false, 0xd894, 0xd894 }, +/* 0xd895 */ { false, 0xd895, 0xd895 }, +/* 0xd896 */ { false, 0xd896, 0xd896 }, +/* 0xd897 */ { false, 0xd897, 0xd897 }, +/* 0xd898 */ { false, 0xd898, 0xd898 }, +/* 0xd899 */ { false, 0xd899, 0xd899 }, +/* 0xd89a */ { false, 0xd89a, 0xd89a }, +/* 0xd89b */ { false, 0xd89b, 0xd89b }, +/* 0xd89c */ { false, 0xd89c, 0xd89c }, +/* 0xd89d */ { false, 0xd89d, 0xd89d }, +/* 0xd89e */ { false, 0xd89e, 0xd89e }, +/* 0xd89f */ { false, 0xd89f, 0xd89f }, +/* 0xd8a0 */ { false, 0xd8a0, 0xd8a0 }, +/* 0xd8a1 */ { false, 0xd8a1, 0xd8a1 }, +/* 0xd8a2 */ { false, 0xd8a2, 0xd8a2 }, +/* 0xd8a3 */ { false, 0xd8a3, 0xd8a3 }, +/* 0xd8a4 */ { false, 0xd8a4, 0xd8a4 }, +/* 0xd8a5 */ { false, 0xd8a5, 0xd8a5 }, +/* 0xd8a6 */ { false, 0xd8a6, 0xd8a6 }, +/* 0xd8a7 */ { false, 0xd8a7, 0xd8a7 }, +/* 0xd8a8 */ { false, 0xd8a8, 0xd8a8 }, +/* 0xd8a9 */ { false, 0xd8a9, 0xd8a9 }, +/* 0xd8aa */ { false, 0xd8aa, 0xd8aa }, +/* 0xd8ab */ { false, 0xd8ab, 0xd8ab }, +/* 0xd8ac */ { false, 0xd8ac, 0xd8ac }, +/* 0xd8ad */ { false, 0xd8ad, 0xd8ad }, +/* 0xd8ae */ { false, 0xd8ae, 0xd8ae }, +/* 0xd8af */ { false, 0xd8af, 0xd8af }, +/* 0xd8b0 */ { false, 0xd8b0, 0xd8b0 }, +/* 0xd8b1 */ { false, 0xd8b1, 0xd8b1 }, +/* 0xd8b2 */ { false, 0xd8b2, 0xd8b2 }, +/* 0xd8b3 */ { false, 0xd8b3, 0xd8b3 }, +/* 0xd8b4 */ { false, 0xd8b4, 0xd8b4 }, +/* 0xd8b5 */ { false, 0xd8b5, 0xd8b5 }, +/* 0xd8b6 */ { false, 0xd8b6, 0xd8b6 }, +/* 0xd8b7 */ { false, 0xd8b7, 0xd8b7 }, +/* 0xd8b8 */ { false, 0xd8b8, 0xd8b8 }, +/* 0xd8b9 */ { false, 0xd8b9, 0xd8b9 }, +/* 0xd8ba */ { false, 0xd8ba, 0xd8ba }, +/* 0xd8bb */ { false, 0xd8bb, 0xd8bb }, +/* 0xd8bc */ { false, 0xd8bc, 0xd8bc }, +/* 0xd8bd */ { false, 0xd8bd, 0xd8bd }, +/* 0xd8be */ { false, 0xd8be, 0xd8be }, +/* 0xd8bf */ { false, 0xd8bf, 0xd8bf }, +/* 0xd8c0 */ { false, 0xd8c0, 0xd8c0 }, +/* 0xd8c1 */ { false, 0xd8c1, 0xd8c1 }, +/* 0xd8c2 */ { false, 0xd8c2, 0xd8c2 }, +/* 0xd8c3 */ { false, 0xd8c3, 0xd8c3 }, +/* 0xd8c4 */ { false, 0xd8c4, 0xd8c4 }, +/* 0xd8c5 */ { false, 0xd8c5, 0xd8c5 }, +/* 0xd8c6 */ { false, 0xd8c6, 0xd8c6 }, +/* 0xd8c7 */ { false, 0xd8c7, 0xd8c7 }, +/* 0xd8c8 */ { false, 0xd8c8, 0xd8c8 }, +/* 0xd8c9 */ { false, 0xd8c9, 0xd8c9 }, +/* 0xd8ca */ { false, 0xd8ca, 0xd8ca }, +/* 0xd8cb */ { false, 0xd8cb, 0xd8cb }, +/* 0xd8cc */ { false, 0xd8cc, 0xd8cc }, +/* 0xd8cd */ { false, 0xd8cd, 0xd8cd }, +/* 0xd8ce */ { false, 0xd8ce, 0xd8ce }, +/* 0xd8cf */ { false, 0xd8cf, 0xd8cf }, +/* 0xd8d0 */ { false, 0xd8d0, 0xd8d0 }, +/* 0xd8d1 */ { false, 0xd8d1, 0xd8d1 }, +/* 0xd8d2 */ { false, 0xd8d2, 0xd8d2 }, +/* 0xd8d3 */ { false, 0xd8d3, 0xd8d3 }, +/* 0xd8d4 */ { false, 0xd8d4, 0xd8d4 }, +/* 0xd8d5 */ { false, 0xd8d5, 0xd8d5 }, +/* 0xd8d6 */ { false, 0xd8d6, 0xd8d6 }, +/* 0xd8d7 */ { false, 0xd8d7, 0xd8d7 }, +/* 0xd8d8 */ { false, 0xd8d8, 0xd8d8 }, +/* 0xd8d9 */ { false, 0xd8d9, 0xd8d9 }, +/* 0xd8da */ { false, 0xd8da, 0xd8da }, +/* 0xd8db */ { false, 0xd8db, 0xd8db }, +/* 0xd8dc */ { false, 0xd8dc, 0xd8dc }, +/* 0xd8dd */ { false, 0xd8dd, 0xd8dd }, +/* 0xd8de */ { false, 0xd8de, 0xd8de }, +/* 0xd8df */ { false, 0xd8df, 0xd8df }, +/* 0xd8e0 */ { false, 0xd8e0, 0xd8e0 }, +/* 0xd8e1 */ { false, 0xd8e1, 0xd8e1 }, +/* 0xd8e2 */ { false, 0xd8e2, 0xd8e2 }, +/* 0xd8e3 */ { false, 0xd8e3, 0xd8e3 }, +/* 0xd8e4 */ { false, 0xd8e4, 0xd8e4 }, +/* 0xd8e5 */ { false, 0xd8e5, 0xd8e5 }, +/* 0xd8e6 */ { false, 0xd8e6, 0xd8e6 }, +/* 0xd8e7 */ { false, 0xd8e7, 0xd8e7 }, +/* 0xd8e8 */ { false, 0xd8e8, 0xd8e8 }, +/* 0xd8e9 */ { false, 0xd8e9, 0xd8e9 }, +/* 0xd8ea */ { false, 0xd8ea, 0xd8ea }, +/* 0xd8eb */ { false, 0xd8eb, 0xd8eb }, +/* 0xd8ec */ { false, 0xd8ec, 0xd8ec }, +/* 0xd8ed */ { false, 0xd8ed, 0xd8ed }, +/* 0xd8ee */ { false, 0xd8ee, 0xd8ee }, +/* 0xd8ef */ { false, 0xd8ef, 0xd8ef }, +/* 0xd8f0 */ { false, 0xd8f0, 0xd8f0 }, +/* 0xd8f1 */ { false, 0xd8f1, 0xd8f1 }, +/* 0xd8f2 */ { false, 0xd8f2, 0xd8f2 }, +/* 0xd8f3 */ { false, 0xd8f3, 0xd8f3 }, +/* 0xd8f4 */ { false, 0xd8f4, 0xd8f4 }, +/* 0xd8f5 */ { false, 0xd8f5, 0xd8f5 }, +/* 0xd8f6 */ { false, 0xd8f6, 0xd8f6 }, +/* 0xd8f7 */ { false, 0xd8f7, 0xd8f7 }, +/* 0xd8f8 */ { false, 0xd8f8, 0xd8f8 }, +/* 0xd8f9 */ { false, 0xd8f9, 0xd8f9 }, +/* 0xd8fa */ { false, 0xd8fa, 0xd8fa }, +/* 0xd8fb */ { false, 0xd8fb, 0xd8fb }, +/* 0xd8fc */ { false, 0xd8fc, 0xd8fc }, +/* 0xd8fd */ { false, 0xd8fd, 0xd8fd }, +/* 0xd8fe */ { false, 0xd8fe, 0xd8fe }, +/* 0xd8ff */ { false, 0xd8ff, 0xd8ff }, +/* 0xd900 */ { false, 0xd900, 0xd900 }, +/* 0xd901 */ { false, 0xd901, 0xd901 }, +/* 0xd902 */ { false, 0xd902, 0xd902 }, +/* 0xd903 */ { false, 0xd903, 0xd903 }, +/* 0xd904 */ { false, 0xd904, 0xd904 }, +/* 0xd905 */ { false, 0xd905, 0xd905 }, +/* 0xd906 */ { false, 0xd906, 0xd906 }, +/* 0xd907 */ { false, 0xd907, 0xd907 }, +/* 0xd908 */ { false, 0xd908, 0xd908 }, +/* 0xd909 */ { false, 0xd909, 0xd909 }, +/* 0xd90a */ { false, 0xd90a, 0xd90a }, +/* 0xd90b */ { false, 0xd90b, 0xd90b }, +/* 0xd90c */ { false, 0xd90c, 0xd90c }, +/* 0xd90d */ { false, 0xd90d, 0xd90d }, +/* 0xd90e */ { false, 0xd90e, 0xd90e }, +/* 0xd90f */ { false, 0xd90f, 0xd90f }, +/* 0xd910 */ { false, 0xd910, 0xd910 }, +/* 0xd911 */ { false, 0xd911, 0xd911 }, +/* 0xd912 */ { false, 0xd912, 0xd912 }, +/* 0xd913 */ { false, 0xd913, 0xd913 }, +/* 0xd914 */ { false, 0xd914, 0xd914 }, +/* 0xd915 */ { false, 0xd915, 0xd915 }, +/* 0xd916 */ { false, 0xd916, 0xd916 }, +/* 0xd917 */ { false, 0xd917, 0xd917 }, +/* 0xd918 */ { false, 0xd918, 0xd918 }, +/* 0xd919 */ { false, 0xd919, 0xd919 }, +/* 0xd91a */ { false, 0xd91a, 0xd91a }, +/* 0xd91b */ { false, 0xd91b, 0xd91b }, +/* 0xd91c */ { false, 0xd91c, 0xd91c }, +/* 0xd91d */ { false, 0xd91d, 0xd91d }, +/* 0xd91e */ { false, 0xd91e, 0xd91e }, +/* 0xd91f */ { false, 0xd91f, 0xd91f }, +/* 0xd920 */ { false, 0xd920, 0xd920 }, +/* 0xd921 */ { false, 0xd921, 0xd921 }, +/* 0xd922 */ { false, 0xd922, 0xd922 }, +/* 0xd923 */ { false, 0xd923, 0xd923 }, +/* 0xd924 */ { false, 0xd924, 0xd924 }, +/* 0xd925 */ { false, 0xd925, 0xd925 }, +/* 0xd926 */ { false, 0xd926, 0xd926 }, +/* 0xd927 */ { false, 0xd927, 0xd927 }, +/* 0xd928 */ { false, 0xd928, 0xd928 }, +/* 0xd929 */ { false, 0xd929, 0xd929 }, +/* 0xd92a */ { false, 0xd92a, 0xd92a }, +/* 0xd92b */ { false, 0xd92b, 0xd92b }, +/* 0xd92c */ { false, 0xd92c, 0xd92c }, +/* 0xd92d */ { false, 0xd92d, 0xd92d }, +/* 0xd92e */ { false, 0xd92e, 0xd92e }, +/* 0xd92f */ { false, 0xd92f, 0xd92f }, +/* 0xd930 */ { false, 0xd930, 0xd930 }, +/* 0xd931 */ { false, 0xd931, 0xd931 }, +/* 0xd932 */ { false, 0xd932, 0xd932 }, +/* 0xd933 */ { false, 0xd933, 0xd933 }, +/* 0xd934 */ { false, 0xd934, 0xd934 }, +/* 0xd935 */ { false, 0xd935, 0xd935 }, +/* 0xd936 */ { false, 0xd936, 0xd936 }, +/* 0xd937 */ { false, 0xd937, 0xd937 }, +/* 0xd938 */ { false, 0xd938, 0xd938 }, +/* 0xd939 */ { false, 0xd939, 0xd939 }, +/* 0xd93a */ { false, 0xd93a, 0xd93a }, +/* 0xd93b */ { false, 0xd93b, 0xd93b }, +/* 0xd93c */ { false, 0xd93c, 0xd93c }, +/* 0xd93d */ { false, 0xd93d, 0xd93d }, +/* 0xd93e */ { false, 0xd93e, 0xd93e }, +/* 0xd93f */ { false, 0xd93f, 0xd93f }, +/* 0xd940 */ { false, 0xd940, 0xd940 }, +/* 0xd941 */ { false, 0xd941, 0xd941 }, +/* 0xd942 */ { false, 0xd942, 0xd942 }, +/* 0xd943 */ { false, 0xd943, 0xd943 }, +/* 0xd944 */ { false, 0xd944, 0xd944 }, +/* 0xd945 */ { false, 0xd945, 0xd945 }, +/* 0xd946 */ { false, 0xd946, 0xd946 }, +/* 0xd947 */ { false, 0xd947, 0xd947 }, +/* 0xd948 */ { false, 0xd948, 0xd948 }, +/* 0xd949 */ { false, 0xd949, 0xd949 }, +/* 0xd94a */ { false, 0xd94a, 0xd94a }, +/* 0xd94b */ { false, 0xd94b, 0xd94b }, +/* 0xd94c */ { false, 0xd94c, 0xd94c }, +/* 0xd94d */ { false, 0xd94d, 0xd94d }, +/* 0xd94e */ { false, 0xd94e, 0xd94e }, +/* 0xd94f */ { false, 0xd94f, 0xd94f }, +/* 0xd950 */ { false, 0xd950, 0xd950 }, +/* 0xd951 */ { false, 0xd951, 0xd951 }, +/* 0xd952 */ { false, 0xd952, 0xd952 }, +/* 0xd953 */ { false, 0xd953, 0xd953 }, +/* 0xd954 */ { false, 0xd954, 0xd954 }, +/* 0xd955 */ { false, 0xd955, 0xd955 }, +/* 0xd956 */ { false, 0xd956, 0xd956 }, +/* 0xd957 */ { false, 0xd957, 0xd957 }, +/* 0xd958 */ { false, 0xd958, 0xd958 }, +/* 0xd959 */ { false, 0xd959, 0xd959 }, +/* 0xd95a */ { false, 0xd95a, 0xd95a }, +/* 0xd95b */ { false, 0xd95b, 0xd95b }, +/* 0xd95c */ { false, 0xd95c, 0xd95c }, +/* 0xd95d */ { false, 0xd95d, 0xd95d }, +/* 0xd95e */ { false, 0xd95e, 0xd95e }, +/* 0xd95f */ { false, 0xd95f, 0xd95f }, +/* 0xd960 */ { false, 0xd960, 0xd960 }, +/* 0xd961 */ { false, 0xd961, 0xd961 }, +/* 0xd962 */ { false, 0xd962, 0xd962 }, +/* 0xd963 */ { false, 0xd963, 0xd963 }, +/* 0xd964 */ { false, 0xd964, 0xd964 }, +/* 0xd965 */ { false, 0xd965, 0xd965 }, +/* 0xd966 */ { false, 0xd966, 0xd966 }, +/* 0xd967 */ { false, 0xd967, 0xd967 }, +/* 0xd968 */ { false, 0xd968, 0xd968 }, +/* 0xd969 */ { false, 0xd969, 0xd969 }, +/* 0xd96a */ { false, 0xd96a, 0xd96a }, +/* 0xd96b */ { false, 0xd96b, 0xd96b }, +/* 0xd96c */ { false, 0xd96c, 0xd96c }, +/* 0xd96d */ { false, 0xd96d, 0xd96d }, +/* 0xd96e */ { false, 0xd96e, 0xd96e }, +/* 0xd96f */ { false, 0xd96f, 0xd96f }, +/* 0xd970 */ { false, 0xd970, 0xd970 }, +/* 0xd971 */ { false, 0xd971, 0xd971 }, +/* 0xd972 */ { false, 0xd972, 0xd972 }, +/* 0xd973 */ { false, 0xd973, 0xd973 }, +/* 0xd974 */ { false, 0xd974, 0xd974 }, +/* 0xd975 */ { false, 0xd975, 0xd975 }, +/* 0xd976 */ { false, 0xd976, 0xd976 }, +/* 0xd977 */ { false, 0xd977, 0xd977 }, +/* 0xd978 */ { false, 0xd978, 0xd978 }, +/* 0xd979 */ { false, 0xd979, 0xd979 }, +/* 0xd97a */ { false, 0xd97a, 0xd97a }, +/* 0xd97b */ { false, 0xd97b, 0xd97b }, +/* 0xd97c */ { false, 0xd97c, 0xd97c }, +/* 0xd97d */ { false, 0xd97d, 0xd97d }, +/* 0xd97e */ { false, 0xd97e, 0xd97e }, +/* 0xd97f */ { false, 0xd97f, 0xd97f }, +/* 0xd980 */ { false, 0xd980, 0xd980 }, +/* 0xd981 */ { false, 0xd981, 0xd981 }, +/* 0xd982 */ { false, 0xd982, 0xd982 }, +/* 0xd983 */ { false, 0xd983, 0xd983 }, +/* 0xd984 */ { false, 0xd984, 0xd984 }, +/* 0xd985 */ { false, 0xd985, 0xd985 }, +/* 0xd986 */ { false, 0xd986, 0xd986 }, +/* 0xd987 */ { false, 0xd987, 0xd987 }, +/* 0xd988 */ { false, 0xd988, 0xd988 }, +/* 0xd989 */ { false, 0xd989, 0xd989 }, +/* 0xd98a */ { false, 0xd98a, 0xd98a }, +/* 0xd98b */ { false, 0xd98b, 0xd98b }, +/* 0xd98c */ { false, 0xd98c, 0xd98c }, +/* 0xd98d */ { false, 0xd98d, 0xd98d }, +/* 0xd98e */ { false, 0xd98e, 0xd98e }, +/* 0xd98f */ { false, 0xd98f, 0xd98f }, +/* 0xd990 */ { false, 0xd990, 0xd990 }, +/* 0xd991 */ { false, 0xd991, 0xd991 }, +/* 0xd992 */ { false, 0xd992, 0xd992 }, +/* 0xd993 */ { false, 0xd993, 0xd993 }, +/* 0xd994 */ { false, 0xd994, 0xd994 }, +/* 0xd995 */ { false, 0xd995, 0xd995 }, +/* 0xd996 */ { false, 0xd996, 0xd996 }, +/* 0xd997 */ { false, 0xd997, 0xd997 }, +/* 0xd998 */ { false, 0xd998, 0xd998 }, +/* 0xd999 */ { false, 0xd999, 0xd999 }, +/* 0xd99a */ { false, 0xd99a, 0xd99a }, +/* 0xd99b */ { false, 0xd99b, 0xd99b }, +/* 0xd99c */ { false, 0xd99c, 0xd99c }, +/* 0xd99d */ { false, 0xd99d, 0xd99d }, +/* 0xd99e */ { false, 0xd99e, 0xd99e }, +/* 0xd99f */ { false, 0xd99f, 0xd99f }, +/* 0xd9a0 */ { false, 0xd9a0, 0xd9a0 }, +/* 0xd9a1 */ { false, 0xd9a1, 0xd9a1 }, +/* 0xd9a2 */ { false, 0xd9a2, 0xd9a2 }, +/* 0xd9a3 */ { false, 0xd9a3, 0xd9a3 }, +/* 0xd9a4 */ { false, 0xd9a4, 0xd9a4 }, +/* 0xd9a5 */ { false, 0xd9a5, 0xd9a5 }, +/* 0xd9a6 */ { false, 0xd9a6, 0xd9a6 }, +/* 0xd9a7 */ { false, 0xd9a7, 0xd9a7 }, +/* 0xd9a8 */ { false, 0xd9a8, 0xd9a8 }, +/* 0xd9a9 */ { false, 0xd9a9, 0xd9a9 }, +/* 0xd9aa */ { false, 0xd9aa, 0xd9aa }, +/* 0xd9ab */ { false, 0xd9ab, 0xd9ab }, +/* 0xd9ac */ { false, 0xd9ac, 0xd9ac }, +/* 0xd9ad */ { false, 0xd9ad, 0xd9ad }, +/* 0xd9ae */ { false, 0xd9ae, 0xd9ae }, +/* 0xd9af */ { false, 0xd9af, 0xd9af }, +/* 0xd9b0 */ { false, 0xd9b0, 0xd9b0 }, +/* 0xd9b1 */ { false, 0xd9b1, 0xd9b1 }, +/* 0xd9b2 */ { false, 0xd9b2, 0xd9b2 }, +/* 0xd9b3 */ { false, 0xd9b3, 0xd9b3 }, +/* 0xd9b4 */ { false, 0xd9b4, 0xd9b4 }, +/* 0xd9b5 */ { false, 0xd9b5, 0xd9b5 }, +/* 0xd9b6 */ { false, 0xd9b6, 0xd9b6 }, +/* 0xd9b7 */ { false, 0xd9b7, 0xd9b7 }, +/* 0xd9b8 */ { false, 0xd9b8, 0xd9b8 }, +/* 0xd9b9 */ { false, 0xd9b9, 0xd9b9 }, +/* 0xd9ba */ { false, 0xd9ba, 0xd9ba }, +/* 0xd9bb */ { false, 0xd9bb, 0xd9bb }, +/* 0xd9bc */ { false, 0xd9bc, 0xd9bc }, +/* 0xd9bd */ { false, 0xd9bd, 0xd9bd }, +/* 0xd9be */ { false, 0xd9be, 0xd9be }, +/* 0xd9bf */ { false, 0xd9bf, 0xd9bf }, +/* 0xd9c0 */ { false, 0xd9c0, 0xd9c0 }, +/* 0xd9c1 */ { false, 0xd9c1, 0xd9c1 }, +/* 0xd9c2 */ { false, 0xd9c2, 0xd9c2 }, +/* 0xd9c3 */ { false, 0xd9c3, 0xd9c3 }, +/* 0xd9c4 */ { false, 0xd9c4, 0xd9c4 }, +/* 0xd9c5 */ { false, 0xd9c5, 0xd9c5 }, +/* 0xd9c6 */ { false, 0xd9c6, 0xd9c6 }, +/* 0xd9c7 */ { false, 0xd9c7, 0xd9c7 }, +/* 0xd9c8 */ { false, 0xd9c8, 0xd9c8 }, +/* 0xd9c9 */ { false, 0xd9c9, 0xd9c9 }, +/* 0xd9ca */ { false, 0xd9ca, 0xd9ca }, +/* 0xd9cb */ { false, 0xd9cb, 0xd9cb }, +/* 0xd9cc */ { false, 0xd9cc, 0xd9cc }, +/* 0xd9cd */ { false, 0xd9cd, 0xd9cd }, +/* 0xd9ce */ { false, 0xd9ce, 0xd9ce }, +/* 0xd9cf */ { false, 0xd9cf, 0xd9cf }, +/* 0xd9d0 */ { false, 0xd9d0, 0xd9d0 }, +/* 0xd9d1 */ { false, 0xd9d1, 0xd9d1 }, +/* 0xd9d2 */ { false, 0xd9d2, 0xd9d2 }, +/* 0xd9d3 */ { false, 0xd9d3, 0xd9d3 }, +/* 0xd9d4 */ { false, 0xd9d4, 0xd9d4 }, +/* 0xd9d5 */ { false, 0xd9d5, 0xd9d5 }, +/* 0xd9d6 */ { false, 0xd9d6, 0xd9d6 }, +/* 0xd9d7 */ { false, 0xd9d7, 0xd9d7 }, +/* 0xd9d8 */ { false, 0xd9d8, 0xd9d8 }, +/* 0xd9d9 */ { false, 0xd9d9, 0xd9d9 }, +/* 0xd9da */ { false, 0xd9da, 0xd9da }, +/* 0xd9db */ { false, 0xd9db, 0xd9db }, +/* 0xd9dc */ { false, 0xd9dc, 0xd9dc }, +/* 0xd9dd */ { false, 0xd9dd, 0xd9dd }, +/* 0xd9de */ { false, 0xd9de, 0xd9de }, +/* 0xd9df */ { false, 0xd9df, 0xd9df }, +/* 0xd9e0 */ { false, 0xd9e0, 0xd9e0 }, +/* 0xd9e1 */ { false, 0xd9e1, 0xd9e1 }, +/* 0xd9e2 */ { false, 0xd9e2, 0xd9e2 }, +/* 0xd9e3 */ { false, 0xd9e3, 0xd9e3 }, +/* 0xd9e4 */ { false, 0xd9e4, 0xd9e4 }, +/* 0xd9e5 */ { false, 0xd9e5, 0xd9e5 }, +/* 0xd9e6 */ { false, 0xd9e6, 0xd9e6 }, +/* 0xd9e7 */ { false, 0xd9e7, 0xd9e7 }, +/* 0xd9e8 */ { false, 0xd9e8, 0xd9e8 }, +/* 0xd9e9 */ { false, 0xd9e9, 0xd9e9 }, +/* 0xd9ea */ { false, 0xd9ea, 0xd9ea }, +/* 0xd9eb */ { false, 0xd9eb, 0xd9eb }, +/* 0xd9ec */ { false, 0xd9ec, 0xd9ec }, +/* 0xd9ed */ { false, 0xd9ed, 0xd9ed }, +/* 0xd9ee */ { false, 0xd9ee, 0xd9ee }, +/* 0xd9ef */ { false, 0xd9ef, 0xd9ef }, +/* 0xd9f0 */ { false, 0xd9f0, 0xd9f0 }, +/* 0xd9f1 */ { false, 0xd9f1, 0xd9f1 }, +/* 0xd9f2 */ { false, 0xd9f2, 0xd9f2 }, +/* 0xd9f3 */ { false, 0xd9f3, 0xd9f3 }, +/* 0xd9f4 */ { false, 0xd9f4, 0xd9f4 }, +/* 0xd9f5 */ { false, 0xd9f5, 0xd9f5 }, +/* 0xd9f6 */ { false, 0xd9f6, 0xd9f6 }, +/* 0xd9f7 */ { false, 0xd9f7, 0xd9f7 }, +/* 0xd9f8 */ { false, 0xd9f8, 0xd9f8 }, +/* 0xd9f9 */ { false, 0xd9f9, 0xd9f9 }, +/* 0xd9fa */ { false, 0xd9fa, 0xd9fa }, +/* 0xd9fb */ { false, 0xd9fb, 0xd9fb }, +/* 0xd9fc */ { false, 0xd9fc, 0xd9fc }, +/* 0xd9fd */ { false, 0xd9fd, 0xd9fd }, +/* 0xd9fe */ { false, 0xd9fe, 0xd9fe }, +/* 0xd9ff */ { false, 0xd9ff, 0xd9ff }, +/* 0xda00 */ { false, 0xda00, 0xda00 }, +/* 0xda01 */ { false, 0xda01, 0xda01 }, +/* 0xda02 */ { false, 0xda02, 0xda02 }, +/* 0xda03 */ { false, 0xda03, 0xda03 }, +/* 0xda04 */ { false, 0xda04, 0xda04 }, +/* 0xda05 */ { false, 0xda05, 0xda05 }, +/* 0xda06 */ { false, 0xda06, 0xda06 }, +/* 0xda07 */ { false, 0xda07, 0xda07 }, +/* 0xda08 */ { false, 0xda08, 0xda08 }, +/* 0xda09 */ { false, 0xda09, 0xda09 }, +/* 0xda0a */ { false, 0xda0a, 0xda0a }, +/* 0xda0b */ { false, 0xda0b, 0xda0b }, +/* 0xda0c */ { false, 0xda0c, 0xda0c }, +/* 0xda0d */ { false, 0xda0d, 0xda0d }, +/* 0xda0e */ { false, 0xda0e, 0xda0e }, +/* 0xda0f */ { false, 0xda0f, 0xda0f }, +/* 0xda10 */ { false, 0xda10, 0xda10 }, +/* 0xda11 */ { false, 0xda11, 0xda11 }, +/* 0xda12 */ { false, 0xda12, 0xda12 }, +/* 0xda13 */ { false, 0xda13, 0xda13 }, +/* 0xda14 */ { false, 0xda14, 0xda14 }, +/* 0xda15 */ { false, 0xda15, 0xda15 }, +/* 0xda16 */ { false, 0xda16, 0xda16 }, +/* 0xda17 */ { false, 0xda17, 0xda17 }, +/* 0xda18 */ { false, 0xda18, 0xda18 }, +/* 0xda19 */ { false, 0xda19, 0xda19 }, +/* 0xda1a */ { false, 0xda1a, 0xda1a }, +/* 0xda1b */ { false, 0xda1b, 0xda1b }, +/* 0xda1c */ { false, 0xda1c, 0xda1c }, +/* 0xda1d */ { false, 0xda1d, 0xda1d }, +/* 0xda1e */ { false, 0xda1e, 0xda1e }, +/* 0xda1f */ { false, 0xda1f, 0xda1f }, +/* 0xda20 */ { false, 0xda20, 0xda20 }, +/* 0xda21 */ { false, 0xda21, 0xda21 }, +/* 0xda22 */ { false, 0xda22, 0xda22 }, +/* 0xda23 */ { false, 0xda23, 0xda23 }, +/* 0xda24 */ { false, 0xda24, 0xda24 }, +/* 0xda25 */ { false, 0xda25, 0xda25 }, +/* 0xda26 */ { false, 0xda26, 0xda26 }, +/* 0xda27 */ { false, 0xda27, 0xda27 }, +/* 0xda28 */ { false, 0xda28, 0xda28 }, +/* 0xda29 */ { false, 0xda29, 0xda29 }, +/* 0xda2a */ { false, 0xda2a, 0xda2a }, +/* 0xda2b */ { false, 0xda2b, 0xda2b }, +/* 0xda2c */ { false, 0xda2c, 0xda2c }, +/* 0xda2d */ { false, 0xda2d, 0xda2d }, +/* 0xda2e */ { false, 0xda2e, 0xda2e }, +/* 0xda2f */ { false, 0xda2f, 0xda2f }, +/* 0xda30 */ { false, 0xda30, 0xda30 }, +/* 0xda31 */ { false, 0xda31, 0xda31 }, +/* 0xda32 */ { false, 0xda32, 0xda32 }, +/* 0xda33 */ { false, 0xda33, 0xda33 }, +/* 0xda34 */ { false, 0xda34, 0xda34 }, +/* 0xda35 */ { false, 0xda35, 0xda35 }, +/* 0xda36 */ { false, 0xda36, 0xda36 }, +/* 0xda37 */ { false, 0xda37, 0xda37 }, +/* 0xda38 */ { false, 0xda38, 0xda38 }, +/* 0xda39 */ { false, 0xda39, 0xda39 }, +/* 0xda3a */ { false, 0xda3a, 0xda3a }, +/* 0xda3b */ { false, 0xda3b, 0xda3b }, +/* 0xda3c */ { false, 0xda3c, 0xda3c }, +/* 0xda3d */ { false, 0xda3d, 0xda3d }, +/* 0xda3e */ { false, 0xda3e, 0xda3e }, +/* 0xda3f */ { false, 0xda3f, 0xda3f }, +/* 0xda40 */ { false, 0xda40, 0xda40 }, +/* 0xda41 */ { false, 0xda41, 0xda41 }, +/* 0xda42 */ { false, 0xda42, 0xda42 }, +/* 0xda43 */ { false, 0xda43, 0xda43 }, +/* 0xda44 */ { false, 0xda44, 0xda44 }, +/* 0xda45 */ { false, 0xda45, 0xda45 }, +/* 0xda46 */ { false, 0xda46, 0xda46 }, +/* 0xda47 */ { false, 0xda47, 0xda47 }, +/* 0xda48 */ { false, 0xda48, 0xda48 }, +/* 0xda49 */ { false, 0xda49, 0xda49 }, +/* 0xda4a */ { false, 0xda4a, 0xda4a }, +/* 0xda4b */ { false, 0xda4b, 0xda4b }, +/* 0xda4c */ { false, 0xda4c, 0xda4c }, +/* 0xda4d */ { false, 0xda4d, 0xda4d }, +/* 0xda4e */ { false, 0xda4e, 0xda4e }, +/* 0xda4f */ { false, 0xda4f, 0xda4f }, +/* 0xda50 */ { false, 0xda50, 0xda50 }, +/* 0xda51 */ { false, 0xda51, 0xda51 }, +/* 0xda52 */ { false, 0xda52, 0xda52 }, +/* 0xda53 */ { false, 0xda53, 0xda53 }, +/* 0xda54 */ { false, 0xda54, 0xda54 }, +/* 0xda55 */ { false, 0xda55, 0xda55 }, +/* 0xda56 */ { false, 0xda56, 0xda56 }, +/* 0xda57 */ { false, 0xda57, 0xda57 }, +/* 0xda58 */ { false, 0xda58, 0xda58 }, +/* 0xda59 */ { false, 0xda59, 0xda59 }, +/* 0xda5a */ { false, 0xda5a, 0xda5a }, +/* 0xda5b */ { false, 0xda5b, 0xda5b }, +/* 0xda5c */ { false, 0xda5c, 0xda5c }, +/* 0xda5d */ { false, 0xda5d, 0xda5d }, +/* 0xda5e */ { false, 0xda5e, 0xda5e }, +/* 0xda5f */ { false, 0xda5f, 0xda5f }, +/* 0xda60 */ { false, 0xda60, 0xda60 }, +/* 0xda61 */ { false, 0xda61, 0xda61 }, +/* 0xda62 */ { false, 0xda62, 0xda62 }, +/* 0xda63 */ { false, 0xda63, 0xda63 }, +/* 0xda64 */ { false, 0xda64, 0xda64 }, +/* 0xda65 */ { false, 0xda65, 0xda65 }, +/* 0xda66 */ { false, 0xda66, 0xda66 }, +/* 0xda67 */ { false, 0xda67, 0xda67 }, +/* 0xda68 */ { false, 0xda68, 0xda68 }, +/* 0xda69 */ { false, 0xda69, 0xda69 }, +/* 0xda6a */ { false, 0xda6a, 0xda6a }, +/* 0xda6b */ { false, 0xda6b, 0xda6b }, +/* 0xda6c */ { false, 0xda6c, 0xda6c }, +/* 0xda6d */ { false, 0xda6d, 0xda6d }, +/* 0xda6e */ { false, 0xda6e, 0xda6e }, +/* 0xda6f */ { false, 0xda6f, 0xda6f }, +/* 0xda70 */ { false, 0xda70, 0xda70 }, +/* 0xda71 */ { false, 0xda71, 0xda71 }, +/* 0xda72 */ { false, 0xda72, 0xda72 }, +/* 0xda73 */ { false, 0xda73, 0xda73 }, +/* 0xda74 */ { false, 0xda74, 0xda74 }, +/* 0xda75 */ { false, 0xda75, 0xda75 }, +/* 0xda76 */ { false, 0xda76, 0xda76 }, +/* 0xda77 */ { false, 0xda77, 0xda77 }, +/* 0xda78 */ { false, 0xda78, 0xda78 }, +/* 0xda79 */ { false, 0xda79, 0xda79 }, +/* 0xda7a */ { false, 0xda7a, 0xda7a }, +/* 0xda7b */ { false, 0xda7b, 0xda7b }, +/* 0xda7c */ { false, 0xda7c, 0xda7c }, +/* 0xda7d */ { false, 0xda7d, 0xda7d }, +/* 0xda7e */ { false, 0xda7e, 0xda7e }, +/* 0xda7f */ { false, 0xda7f, 0xda7f }, +/* 0xda80 */ { false, 0xda80, 0xda80 }, +/* 0xda81 */ { false, 0xda81, 0xda81 }, +/* 0xda82 */ { false, 0xda82, 0xda82 }, +/* 0xda83 */ { false, 0xda83, 0xda83 }, +/* 0xda84 */ { false, 0xda84, 0xda84 }, +/* 0xda85 */ { false, 0xda85, 0xda85 }, +/* 0xda86 */ { false, 0xda86, 0xda86 }, +/* 0xda87 */ { false, 0xda87, 0xda87 }, +/* 0xda88 */ { false, 0xda88, 0xda88 }, +/* 0xda89 */ { false, 0xda89, 0xda89 }, +/* 0xda8a */ { false, 0xda8a, 0xda8a }, +/* 0xda8b */ { false, 0xda8b, 0xda8b }, +/* 0xda8c */ { false, 0xda8c, 0xda8c }, +/* 0xda8d */ { false, 0xda8d, 0xda8d }, +/* 0xda8e */ { false, 0xda8e, 0xda8e }, +/* 0xda8f */ { false, 0xda8f, 0xda8f }, +/* 0xda90 */ { false, 0xda90, 0xda90 }, +/* 0xda91 */ { false, 0xda91, 0xda91 }, +/* 0xda92 */ { false, 0xda92, 0xda92 }, +/* 0xda93 */ { false, 0xda93, 0xda93 }, +/* 0xda94 */ { false, 0xda94, 0xda94 }, +/* 0xda95 */ { false, 0xda95, 0xda95 }, +/* 0xda96 */ { false, 0xda96, 0xda96 }, +/* 0xda97 */ { false, 0xda97, 0xda97 }, +/* 0xda98 */ { false, 0xda98, 0xda98 }, +/* 0xda99 */ { false, 0xda99, 0xda99 }, +/* 0xda9a */ { false, 0xda9a, 0xda9a }, +/* 0xda9b */ { false, 0xda9b, 0xda9b }, +/* 0xda9c */ { false, 0xda9c, 0xda9c }, +/* 0xda9d */ { false, 0xda9d, 0xda9d }, +/* 0xda9e */ { false, 0xda9e, 0xda9e }, +/* 0xda9f */ { false, 0xda9f, 0xda9f }, +/* 0xdaa0 */ { false, 0xdaa0, 0xdaa0 }, +/* 0xdaa1 */ { false, 0xdaa1, 0xdaa1 }, +/* 0xdaa2 */ { false, 0xdaa2, 0xdaa2 }, +/* 0xdaa3 */ { false, 0xdaa3, 0xdaa3 }, +/* 0xdaa4 */ { false, 0xdaa4, 0xdaa4 }, +/* 0xdaa5 */ { false, 0xdaa5, 0xdaa5 }, +/* 0xdaa6 */ { false, 0xdaa6, 0xdaa6 }, +/* 0xdaa7 */ { false, 0xdaa7, 0xdaa7 }, +/* 0xdaa8 */ { false, 0xdaa8, 0xdaa8 }, +/* 0xdaa9 */ { false, 0xdaa9, 0xdaa9 }, +/* 0xdaaa */ { false, 0xdaaa, 0xdaaa }, +/* 0xdaab */ { false, 0xdaab, 0xdaab }, +/* 0xdaac */ { false, 0xdaac, 0xdaac }, +/* 0xdaad */ { false, 0xdaad, 0xdaad }, +/* 0xdaae */ { false, 0xdaae, 0xdaae }, +/* 0xdaaf */ { false, 0xdaaf, 0xdaaf }, +/* 0xdab0 */ { false, 0xdab0, 0xdab0 }, +/* 0xdab1 */ { false, 0xdab1, 0xdab1 }, +/* 0xdab2 */ { false, 0xdab2, 0xdab2 }, +/* 0xdab3 */ { false, 0xdab3, 0xdab3 }, +/* 0xdab4 */ { false, 0xdab4, 0xdab4 }, +/* 0xdab5 */ { false, 0xdab5, 0xdab5 }, +/* 0xdab6 */ { false, 0xdab6, 0xdab6 }, +/* 0xdab7 */ { false, 0xdab7, 0xdab7 }, +/* 0xdab8 */ { false, 0xdab8, 0xdab8 }, +/* 0xdab9 */ { false, 0xdab9, 0xdab9 }, +/* 0xdaba */ { false, 0xdaba, 0xdaba }, +/* 0xdabb */ { false, 0xdabb, 0xdabb }, +/* 0xdabc */ { false, 0xdabc, 0xdabc }, +/* 0xdabd */ { false, 0xdabd, 0xdabd }, +/* 0xdabe */ { false, 0xdabe, 0xdabe }, +/* 0xdabf */ { false, 0xdabf, 0xdabf }, +/* 0xdac0 */ { false, 0xdac0, 0xdac0 }, +/* 0xdac1 */ { false, 0xdac1, 0xdac1 }, +/* 0xdac2 */ { false, 0xdac2, 0xdac2 }, +/* 0xdac3 */ { false, 0xdac3, 0xdac3 }, +/* 0xdac4 */ { false, 0xdac4, 0xdac4 }, +/* 0xdac5 */ { false, 0xdac5, 0xdac5 }, +/* 0xdac6 */ { false, 0xdac6, 0xdac6 }, +/* 0xdac7 */ { false, 0xdac7, 0xdac7 }, +/* 0xdac8 */ { false, 0xdac8, 0xdac8 }, +/* 0xdac9 */ { false, 0xdac9, 0xdac9 }, +/* 0xdaca */ { false, 0xdaca, 0xdaca }, +/* 0xdacb */ { false, 0xdacb, 0xdacb }, +/* 0xdacc */ { false, 0xdacc, 0xdacc }, +/* 0xdacd */ { false, 0xdacd, 0xdacd }, +/* 0xdace */ { false, 0xdace, 0xdace }, +/* 0xdacf */ { false, 0xdacf, 0xdacf }, +/* 0xdad0 */ { false, 0xdad0, 0xdad0 }, +/* 0xdad1 */ { false, 0xdad1, 0xdad1 }, +/* 0xdad2 */ { false, 0xdad2, 0xdad2 }, +/* 0xdad3 */ { false, 0xdad3, 0xdad3 }, +/* 0xdad4 */ { false, 0xdad4, 0xdad4 }, +/* 0xdad5 */ { false, 0xdad5, 0xdad5 }, +/* 0xdad6 */ { false, 0xdad6, 0xdad6 }, +/* 0xdad7 */ { false, 0xdad7, 0xdad7 }, +/* 0xdad8 */ { false, 0xdad8, 0xdad8 }, +/* 0xdad9 */ { false, 0xdad9, 0xdad9 }, +/* 0xdada */ { false, 0xdada, 0xdada }, +/* 0xdadb */ { false, 0xdadb, 0xdadb }, +/* 0xdadc */ { false, 0xdadc, 0xdadc }, +/* 0xdadd */ { false, 0xdadd, 0xdadd }, +/* 0xdade */ { false, 0xdade, 0xdade }, +/* 0xdadf */ { false, 0xdadf, 0xdadf }, +/* 0xdae0 */ { false, 0xdae0, 0xdae0 }, +/* 0xdae1 */ { false, 0xdae1, 0xdae1 }, +/* 0xdae2 */ { false, 0xdae2, 0xdae2 }, +/* 0xdae3 */ { false, 0xdae3, 0xdae3 }, +/* 0xdae4 */ { false, 0xdae4, 0xdae4 }, +/* 0xdae5 */ { false, 0xdae5, 0xdae5 }, +/* 0xdae6 */ { false, 0xdae6, 0xdae6 }, +/* 0xdae7 */ { false, 0xdae7, 0xdae7 }, +/* 0xdae8 */ { false, 0xdae8, 0xdae8 }, +/* 0xdae9 */ { false, 0xdae9, 0xdae9 }, +/* 0xdaea */ { false, 0xdaea, 0xdaea }, +/* 0xdaeb */ { false, 0xdaeb, 0xdaeb }, +/* 0xdaec */ { false, 0xdaec, 0xdaec }, +/* 0xdaed */ { false, 0xdaed, 0xdaed }, +/* 0xdaee */ { false, 0xdaee, 0xdaee }, +/* 0xdaef */ { false, 0xdaef, 0xdaef }, +/* 0xdaf0 */ { false, 0xdaf0, 0xdaf0 }, +/* 0xdaf1 */ { false, 0xdaf1, 0xdaf1 }, +/* 0xdaf2 */ { false, 0xdaf2, 0xdaf2 }, +/* 0xdaf3 */ { false, 0xdaf3, 0xdaf3 }, +/* 0xdaf4 */ { false, 0xdaf4, 0xdaf4 }, +/* 0xdaf5 */ { false, 0xdaf5, 0xdaf5 }, +/* 0xdaf6 */ { false, 0xdaf6, 0xdaf6 }, +/* 0xdaf7 */ { false, 0xdaf7, 0xdaf7 }, +/* 0xdaf8 */ { false, 0xdaf8, 0xdaf8 }, +/* 0xdaf9 */ { false, 0xdaf9, 0xdaf9 }, +/* 0xdafa */ { false, 0xdafa, 0xdafa }, +/* 0xdafb */ { false, 0xdafb, 0xdafb }, +/* 0xdafc */ { false, 0xdafc, 0xdafc }, +/* 0xdafd */ { false, 0xdafd, 0xdafd }, +/* 0xdafe */ { false, 0xdafe, 0xdafe }, +/* 0xdaff */ { false, 0xdaff, 0xdaff }, +/* 0xdb00 */ { false, 0xdb00, 0xdb00 }, +/* 0xdb01 */ { false, 0xdb01, 0xdb01 }, +/* 0xdb02 */ { false, 0xdb02, 0xdb02 }, +/* 0xdb03 */ { false, 0xdb03, 0xdb03 }, +/* 0xdb04 */ { false, 0xdb04, 0xdb04 }, +/* 0xdb05 */ { false, 0xdb05, 0xdb05 }, +/* 0xdb06 */ { false, 0xdb06, 0xdb06 }, +/* 0xdb07 */ { false, 0xdb07, 0xdb07 }, +/* 0xdb08 */ { false, 0xdb08, 0xdb08 }, +/* 0xdb09 */ { false, 0xdb09, 0xdb09 }, +/* 0xdb0a */ { false, 0xdb0a, 0xdb0a }, +/* 0xdb0b */ { false, 0xdb0b, 0xdb0b }, +/* 0xdb0c */ { false, 0xdb0c, 0xdb0c }, +/* 0xdb0d */ { false, 0xdb0d, 0xdb0d }, +/* 0xdb0e */ { false, 0xdb0e, 0xdb0e }, +/* 0xdb0f */ { false, 0xdb0f, 0xdb0f }, +/* 0xdb10 */ { false, 0xdb10, 0xdb10 }, +/* 0xdb11 */ { false, 0xdb11, 0xdb11 }, +/* 0xdb12 */ { false, 0xdb12, 0xdb12 }, +/* 0xdb13 */ { false, 0xdb13, 0xdb13 }, +/* 0xdb14 */ { false, 0xdb14, 0xdb14 }, +/* 0xdb15 */ { false, 0xdb15, 0xdb15 }, +/* 0xdb16 */ { false, 0xdb16, 0xdb16 }, +/* 0xdb17 */ { false, 0xdb17, 0xdb17 }, +/* 0xdb18 */ { false, 0xdb18, 0xdb18 }, +/* 0xdb19 */ { false, 0xdb19, 0xdb19 }, +/* 0xdb1a */ { false, 0xdb1a, 0xdb1a }, +/* 0xdb1b */ { false, 0xdb1b, 0xdb1b }, +/* 0xdb1c */ { false, 0xdb1c, 0xdb1c }, +/* 0xdb1d */ { false, 0xdb1d, 0xdb1d }, +/* 0xdb1e */ { false, 0xdb1e, 0xdb1e }, +/* 0xdb1f */ { false, 0xdb1f, 0xdb1f }, +/* 0xdb20 */ { false, 0xdb20, 0xdb20 }, +/* 0xdb21 */ { false, 0xdb21, 0xdb21 }, +/* 0xdb22 */ { false, 0xdb22, 0xdb22 }, +/* 0xdb23 */ { false, 0xdb23, 0xdb23 }, +/* 0xdb24 */ { false, 0xdb24, 0xdb24 }, +/* 0xdb25 */ { false, 0xdb25, 0xdb25 }, +/* 0xdb26 */ { false, 0xdb26, 0xdb26 }, +/* 0xdb27 */ { false, 0xdb27, 0xdb27 }, +/* 0xdb28 */ { false, 0xdb28, 0xdb28 }, +/* 0xdb29 */ { false, 0xdb29, 0xdb29 }, +/* 0xdb2a */ { false, 0xdb2a, 0xdb2a }, +/* 0xdb2b */ { false, 0xdb2b, 0xdb2b }, +/* 0xdb2c */ { false, 0xdb2c, 0xdb2c }, +/* 0xdb2d */ { false, 0xdb2d, 0xdb2d }, +/* 0xdb2e */ { false, 0xdb2e, 0xdb2e }, +/* 0xdb2f */ { false, 0xdb2f, 0xdb2f }, +/* 0xdb30 */ { false, 0xdb30, 0xdb30 }, +/* 0xdb31 */ { false, 0xdb31, 0xdb31 }, +/* 0xdb32 */ { false, 0xdb32, 0xdb32 }, +/* 0xdb33 */ { false, 0xdb33, 0xdb33 }, +/* 0xdb34 */ { false, 0xdb34, 0xdb34 }, +/* 0xdb35 */ { false, 0xdb35, 0xdb35 }, +/* 0xdb36 */ { false, 0xdb36, 0xdb36 }, +/* 0xdb37 */ { false, 0xdb37, 0xdb37 }, +/* 0xdb38 */ { false, 0xdb38, 0xdb38 }, +/* 0xdb39 */ { false, 0xdb39, 0xdb39 }, +/* 0xdb3a */ { false, 0xdb3a, 0xdb3a }, +/* 0xdb3b */ { false, 0xdb3b, 0xdb3b }, +/* 0xdb3c */ { false, 0xdb3c, 0xdb3c }, +/* 0xdb3d */ { false, 0xdb3d, 0xdb3d }, +/* 0xdb3e */ { false, 0xdb3e, 0xdb3e }, +/* 0xdb3f */ { false, 0xdb3f, 0xdb3f }, +/* 0xdb40 */ { false, 0xdb40, 0xdb40 }, +/* 0xdb41 */ { false, 0xdb41, 0xdb41 }, +/* 0xdb42 */ { false, 0xdb42, 0xdb42 }, +/* 0xdb43 */ { false, 0xdb43, 0xdb43 }, +/* 0xdb44 */ { false, 0xdb44, 0xdb44 }, +/* 0xdb45 */ { false, 0xdb45, 0xdb45 }, +/* 0xdb46 */ { false, 0xdb46, 0xdb46 }, +/* 0xdb47 */ { false, 0xdb47, 0xdb47 }, +/* 0xdb48 */ { false, 0xdb48, 0xdb48 }, +/* 0xdb49 */ { false, 0xdb49, 0xdb49 }, +/* 0xdb4a */ { false, 0xdb4a, 0xdb4a }, +/* 0xdb4b */ { false, 0xdb4b, 0xdb4b }, +/* 0xdb4c */ { false, 0xdb4c, 0xdb4c }, +/* 0xdb4d */ { false, 0xdb4d, 0xdb4d }, +/* 0xdb4e */ { false, 0xdb4e, 0xdb4e }, +/* 0xdb4f */ { false, 0xdb4f, 0xdb4f }, +/* 0xdb50 */ { false, 0xdb50, 0xdb50 }, +/* 0xdb51 */ { false, 0xdb51, 0xdb51 }, +/* 0xdb52 */ { false, 0xdb52, 0xdb52 }, +/* 0xdb53 */ { false, 0xdb53, 0xdb53 }, +/* 0xdb54 */ { false, 0xdb54, 0xdb54 }, +/* 0xdb55 */ { false, 0xdb55, 0xdb55 }, +/* 0xdb56 */ { false, 0xdb56, 0xdb56 }, +/* 0xdb57 */ { false, 0xdb57, 0xdb57 }, +/* 0xdb58 */ { false, 0xdb58, 0xdb58 }, +/* 0xdb59 */ { false, 0xdb59, 0xdb59 }, +/* 0xdb5a */ { false, 0xdb5a, 0xdb5a }, +/* 0xdb5b */ { false, 0xdb5b, 0xdb5b }, +/* 0xdb5c */ { false, 0xdb5c, 0xdb5c }, +/* 0xdb5d */ { false, 0xdb5d, 0xdb5d }, +/* 0xdb5e */ { false, 0xdb5e, 0xdb5e }, +/* 0xdb5f */ { false, 0xdb5f, 0xdb5f }, +/* 0xdb60 */ { false, 0xdb60, 0xdb60 }, +/* 0xdb61 */ { false, 0xdb61, 0xdb61 }, +/* 0xdb62 */ { false, 0xdb62, 0xdb62 }, +/* 0xdb63 */ { false, 0xdb63, 0xdb63 }, +/* 0xdb64 */ { false, 0xdb64, 0xdb64 }, +/* 0xdb65 */ { false, 0xdb65, 0xdb65 }, +/* 0xdb66 */ { false, 0xdb66, 0xdb66 }, +/* 0xdb67 */ { false, 0xdb67, 0xdb67 }, +/* 0xdb68 */ { false, 0xdb68, 0xdb68 }, +/* 0xdb69 */ { false, 0xdb69, 0xdb69 }, +/* 0xdb6a */ { false, 0xdb6a, 0xdb6a }, +/* 0xdb6b */ { false, 0xdb6b, 0xdb6b }, +/* 0xdb6c */ { false, 0xdb6c, 0xdb6c }, +/* 0xdb6d */ { false, 0xdb6d, 0xdb6d }, +/* 0xdb6e */ { false, 0xdb6e, 0xdb6e }, +/* 0xdb6f */ { false, 0xdb6f, 0xdb6f }, +/* 0xdb70 */ { false, 0xdb70, 0xdb70 }, +/* 0xdb71 */ { false, 0xdb71, 0xdb71 }, +/* 0xdb72 */ { false, 0xdb72, 0xdb72 }, +/* 0xdb73 */ { false, 0xdb73, 0xdb73 }, +/* 0xdb74 */ { false, 0xdb74, 0xdb74 }, +/* 0xdb75 */ { false, 0xdb75, 0xdb75 }, +/* 0xdb76 */ { false, 0xdb76, 0xdb76 }, +/* 0xdb77 */ { false, 0xdb77, 0xdb77 }, +/* 0xdb78 */ { false, 0xdb78, 0xdb78 }, +/* 0xdb79 */ { false, 0xdb79, 0xdb79 }, +/* 0xdb7a */ { false, 0xdb7a, 0xdb7a }, +/* 0xdb7b */ { false, 0xdb7b, 0xdb7b }, +/* 0xdb7c */ { false, 0xdb7c, 0xdb7c }, +/* 0xdb7d */ { false, 0xdb7d, 0xdb7d }, +/* 0xdb7e */ { false, 0xdb7e, 0xdb7e }, +/* 0xdb7f */ { false, 0xdb7f, 0xdb7f }, +/* 0xdb80 */ { false, 0xdb80, 0xdb80 }, +/* 0xdb81 */ { false, 0xdb81, 0xdb81 }, +/* 0xdb82 */ { false, 0xdb82, 0xdb82 }, +/* 0xdb83 */ { false, 0xdb83, 0xdb83 }, +/* 0xdb84 */ { false, 0xdb84, 0xdb84 }, +/* 0xdb85 */ { false, 0xdb85, 0xdb85 }, +/* 0xdb86 */ { false, 0xdb86, 0xdb86 }, +/* 0xdb87 */ { false, 0xdb87, 0xdb87 }, +/* 0xdb88 */ { false, 0xdb88, 0xdb88 }, +/* 0xdb89 */ { false, 0xdb89, 0xdb89 }, +/* 0xdb8a */ { false, 0xdb8a, 0xdb8a }, +/* 0xdb8b */ { false, 0xdb8b, 0xdb8b }, +/* 0xdb8c */ { false, 0xdb8c, 0xdb8c }, +/* 0xdb8d */ { false, 0xdb8d, 0xdb8d }, +/* 0xdb8e */ { false, 0xdb8e, 0xdb8e }, +/* 0xdb8f */ { false, 0xdb8f, 0xdb8f }, +/* 0xdb90 */ { false, 0xdb90, 0xdb90 }, +/* 0xdb91 */ { false, 0xdb91, 0xdb91 }, +/* 0xdb92 */ { false, 0xdb92, 0xdb92 }, +/* 0xdb93 */ { false, 0xdb93, 0xdb93 }, +/* 0xdb94 */ { false, 0xdb94, 0xdb94 }, +/* 0xdb95 */ { false, 0xdb95, 0xdb95 }, +/* 0xdb96 */ { false, 0xdb96, 0xdb96 }, +/* 0xdb97 */ { false, 0xdb97, 0xdb97 }, +/* 0xdb98 */ { false, 0xdb98, 0xdb98 }, +/* 0xdb99 */ { false, 0xdb99, 0xdb99 }, +/* 0xdb9a */ { false, 0xdb9a, 0xdb9a }, +/* 0xdb9b */ { false, 0xdb9b, 0xdb9b }, +/* 0xdb9c */ { false, 0xdb9c, 0xdb9c }, +/* 0xdb9d */ { false, 0xdb9d, 0xdb9d }, +/* 0xdb9e */ { false, 0xdb9e, 0xdb9e }, +/* 0xdb9f */ { false, 0xdb9f, 0xdb9f }, +/* 0xdba0 */ { false, 0xdba0, 0xdba0 }, +/* 0xdba1 */ { false, 0xdba1, 0xdba1 }, +/* 0xdba2 */ { false, 0xdba2, 0xdba2 }, +/* 0xdba3 */ { false, 0xdba3, 0xdba3 }, +/* 0xdba4 */ { false, 0xdba4, 0xdba4 }, +/* 0xdba5 */ { false, 0xdba5, 0xdba5 }, +/* 0xdba6 */ { false, 0xdba6, 0xdba6 }, +/* 0xdba7 */ { false, 0xdba7, 0xdba7 }, +/* 0xdba8 */ { false, 0xdba8, 0xdba8 }, +/* 0xdba9 */ { false, 0xdba9, 0xdba9 }, +/* 0xdbaa */ { false, 0xdbaa, 0xdbaa }, +/* 0xdbab */ { false, 0xdbab, 0xdbab }, +/* 0xdbac */ { false, 0xdbac, 0xdbac }, +/* 0xdbad */ { false, 0xdbad, 0xdbad }, +/* 0xdbae */ { false, 0xdbae, 0xdbae }, +/* 0xdbaf */ { false, 0xdbaf, 0xdbaf }, +/* 0xdbb0 */ { false, 0xdbb0, 0xdbb0 }, +/* 0xdbb1 */ { false, 0xdbb1, 0xdbb1 }, +/* 0xdbb2 */ { false, 0xdbb2, 0xdbb2 }, +/* 0xdbb3 */ { false, 0xdbb3, 0xdbb3 }, +/* 0xdbb4 */ { false, 0xdbb4, 0xdbb4 }, +/* 0xdbb5 */ { false, 0xdbb5, 0xdbb5 }, +/* 0xdbb6 */ { false, 0xdbb6, 0xdbb6 }, +/* 0xdbb7 */ { false, 0xdbb7, 0xdbb7 }, +/* 0xdbb8 */ { false, 0xdbb8, 0xdbb8 }, +/* 0xdbb9 */ { false, 0xdbb9, 0xdbb9 }, +/* 0xdbba */ { false, 0xdbba, 0xdbba }, +/* 0xdbbb */ { false, 0xdbbb, 0xdbbb }, +/* 0xdbbc */ { false, 0xdbbc, 0xdbbc }, +/* 0xdbbd */ { false, 0xdbbd, 0xdbbd }, +/* 0xdbbe */ { false, 0xdbbe, 0xdbbe }, +/* 0xdbbf */ { false, 0xdbbf, 0xdbbf }, +/* 0xdbc0 */ { false, 0xdbc0, 0xdbc0 }, +/* 0xdbc1 */ { false, 0xdbc1, 0xdbc1 }, +/* 0xdbc2 */ { false, 0xdbc2, 0xdbc2 }, +/* 0xdbc3 */ { false, 0xdbc3, 0xdbc3 }, +/* 0xdbc4 */ { false, 0xdbc4, 0xdbc4 }, +/* 0xdbc5 */ { false, 0xdbc5, 0xdbc5 }, +/* 0xdbc6 */ { false, 0xdbc6, 0xdbc6 }, +/* 0xdbc7 */ { false, 0xdbc7, 0xdbc7 }, +/* 0xdbc8 */ { false, 0xdbc8, 0xdbc8 }, +/* 0xdbc9 */ { false, 0xdbc9, 0xdbc9 }, +/* 0xdbca */ { false, 0xdbca, 0xdbca }, +/* 0xdbcb */ { false, 0xdbcb, 0xdbcb }, +/* 0xdbcc */ { false, 0xdbcc, 0xdbcc }, +/* 0xdbcd */ { false, 0xdbcd, 0xdbcd }, +/* 0xdbce */ { false, 0xdbce, 0xdbce }, +/* 0xdbcf */ { false, 0xdbcf, 0xdbcf }, +/* 0xdbd0 */ { false, 0xdbd0, 0xdbd0 }, +/* 0xdbd1 */ { false, 0xdbd1, 0xdbd1 }, +/* 0xdbd2 */ { false, 0xdbd2, 0xdbd2 }, +/* 0xdbd3 */ { false, 0xdbd3, 0xdbd3 }, +/* 0xdbd4 */ { false, 0xdbd4, 0xdbd4 }, +/* 0xdbd5 */ { false, 0xdbd5, 0xdbd5 }, +/* 0xdbd6 */ { false, 0xdbd6, 0xdbd6 }, +/* 0xdbd7 */ { false, 0xdbd7, 0xdbd7 }, +/* 0xdbd8 */ { false, 0xdbd8, 0xdbd8 }, +/* 0xdbd9 */ { false, 0xdbd9, 0xdbd9 }, +/* 0xdbda */ { false, 0xdbda, 0xdbda }, +/* 0xdbdb */ { false, 0xdbdb, 0xdbdb }, +/* 0xdbdc */ { false, 0xdbdc, 0xdbdc }, +/* 0xdbdd */ { false, 0xdbdd, 0xdbdd }, +/* 0xdbde */ { false, 0xdbde, 0xdbde }, +/* 0xdbdf */ { false, 0xdbdf, 0xdbdf }, +/* 0xdbe0 */ { false, 0xdbe0, 0xdbe0 }, +/* 0xdbe1 */ { false, 0xdbe1, 0xdbe1 }, +/* 0xdbe2 */ { false, 0xdbe2, 0xdbe2 }, +/* 0xdbe3 */ { false, 0xdbe3, 0xdbe3 }, +/* 0xdbe4 */ { false, 0xdbe4, 0xdbe4 }, +/* 0xdbe5 */ { false, 0xdbe5, 0xdbe5 }, +/* 0xdbe6 */ { false, 0xdbe6, 0xdbe6 }, +/* 0xdbe7 */ { false, 0xdbe7, 0xdbe7 }, +/* 0xdbe8 */ { false, 0xdbe8, 0xdbe8 }, +/* 0xdbe9 */ { false, 0xdbe9, 0xdbe9 }, +/* 0xdbea */ { false, 0xdbea, 0xdbea }, +/* 0xdbeb */ { false, 0xdbeb, 0xdbeb }, +/* 0xdbec */ { false, 0xdbec, 0xdbec }, +/* 0xdbed */ { false, 0xdbed, 0xdbed }, +/* 0xdbee */ { false, 0xdbee, 0xdbee }, +/* 0xdbef */ { false, 0xdbef, 0xdbef }, +/* 0xdbf0 */ { false, 0xdbf0, 0xdbf0 }, +/* 0xdbf1 */ { false, 0xdbf1, 0xdbf1 }, +/* 0xdbf2 */ { false, 0xdbf2, 0xdbf2 }, +/* 0xdbf3 */ { false, 0xdbf3, 0xdbf3 }, +/* 0xdbf4 */ { false, 0xdbf4, 0xdbf4 }, +/* 0xdbf5 */ { false, 0xdbf5, 0xdbf5 }, +/* 0xdbf6 */ { false, 0xdbf6, 0xdbf6 }, +/* 0xdbf7 */ { false, 0xdbf7, 0xdbf7 }, +/* 0xdbf8 */ { false, 0xdbf8, 0xdbf8 }, +/* 0xdbf9 */ { false, 0xdbf9, 0xdbf9 }, +/* 0xdbfa */ { false, 0xdbfa, 0xdbfa }, +/* 0xdbfb */ { false, 0xdbfb, 0xdbfb }, +/* 0xdbfc */ { false, 0xdbfc, 0xdbfc }, +/* 0xdbfd */ { false, 0xdbfd, 0xdbfd }, +/* 0xdbfe */ { false, 0xdbfe, 0xdbfe }, +/* 0xdbff */ { false, 0xdbff, 0xdbff }, +/* 0xdc00 */ { false, 0xdc00, 0xdc00 }, +/* 0xdc01 */ { false, 0xdc01, 0xdc01 }, +/* 0xdc02 */ { false, 0xdc02, 0xdc02 }, +/* 0xdc03 */ { false, 0xdc03, 0xdc03 }, +/* 0xdc04 */ { false, 0xdc04, 0xdc04 }, +/* 0xdc05 */ { false, 0xdc05, 0xdc05 }, +/* 0xdc06 */ { false, 0xdc06, 0xdc06 }, +/* 0xdc07 */ { false, 0xdc07, 0xdc07 }, +/* 0xdc08 */ { false, 0xdc08, 0xdc08 }, +/* 0xdc09 */ { false, 0xdc09, 0xdc09 }, +/* 0xdc0a */ { false, 0xdc0a, 0xdc0a }, +/* 0xdc0b */ { false, 0xdc0b, 0xdc0b }, +/* 0xdc0c */ { false, 0xdc0c, 0xdc0c }, +/* 0xdc0d */ { false, 0xdc0d, 0xdc0d }, +/* 0xdc0e */ { false, 0xdc0e, 0xdc0e }, +/* 0xdc0f */ { false, 0xdc0f, 0xdc0f }, +/* 0xdc10 */ { false, 0xdc10, 0xdc10 }, +/* 0xdc11 */ { false, 0xdc11, 0xdc11 }, +/* 0xdc12 */ { false, 0xdc12, 0xdc12 }, +/* 0xdc13 */ { false, 0xdc13, 0xdc13 }, +/* 0xdc14 */ { false, 0xdc14, 0xdc14 }, +/* 0xdc15 */ { false, 0xdc15, 0xdc15 }, +/* 0xdc16 */ { false, 0xdc16, 0xdc16 }, +/* 0xdc17 */ { false, 0xdc17, 0xdc17 }, +/* 0xdc18 */ { false, 0xdc18, 0xdc18 }, +/* 0xdc19 */ { false, 0xdc19, 0xdc19 }, +/* 0xdc1a */ { false, 0xdc1a, 0xdc1a }, +/* 0xdc1b */ { false, 0xdc1b, 0xdc1b }, +/* 0xdc1c */ { false, 0xdc1c, 0xdc1c }, +/* 0xdc1d */ { false, 0xdc1d, 0xdc1d }, +/* 0xdc1e */ { false, 0xdc1e, 0xdc1e }, +/* 0xdc1f */ { false, 0xdc1f, 0xdc1f }, +/* 0xdc20 */ { false, 0xdc20, 0xdc20 }, +/* 0xdc21 */ { false, 0xdc21, 0xdc21 }, +/* 0xdc22 */ { false, 0xdc22, 0xdc22 }, +/* 0xdc23 */ { false, 0xdc23, 0xdc23 }, +/* 0xdc24 */ { false, 0xdc24, 0xdc24 }, +/* 0xdc25 */ { false, 0xdc25, 0xdc25 }, +/* 0xdc26 */ { false, 0xdc26, 0xdc26 }, +/* 0xdc27 */ { false, 0xdc27, 0xdc27 }, +/* 0xdc28 */ { false, 0xdc28, 0xdc28 }, +/* 0xdc29 */ { false, 0xdc29, 0xdc29 }, +/* 0xdc2a */ { false, 0xdc2a, 0xdc2a }, +/* 0xdc2b */ { false, 0xdc2b, 0xdc2b }, +/* 0xdc2c */ { false, 0xdc2c, 0xdc2c }, +/* 0xdc2d */ { false, 0xdc2d, 0xdc2d }, +/* 0xdc2e */ { false, 0xdc2e, 0xdc2e }, +/* 0xdc2f */ { false, 0xdc2f, 0xdc2f }, +/* 0xdc30 */ { false, 0xdc30, 0xdc30 }, +/* 0xdc31 */ { false, 0xdc31, 0xdc31 }, +/* 0xdc32 */ { false, 0xdc32, 0xdc32 }, +/* 0xdc33 */ { false, 0xdc33, 0xdc33 }, +/* 0xdc34 */ { false, 0xdc34, 0xdc34 }, +/* 0xdc35 */ { false, 0xdc35, 0xdc35 }, +/* 0xdc36 */ { false, 0xdc36, 0xdc36 }, +/* 0xdc37 */ { false, 0xdc37, 0xdc37 }, +/* 0xdc38 */ { false, 0xdc38, 0xdc38 }, +/* 0xdc39 */ { false, 0xdc39, 0xdc39 }, +/* 0xdc3a */ { false, 0xdc3a, 0xdc3a }, +/* 0xdc3b */ { false, 0xdc3b, 0xdc3b }, +/* 0xdc3c */ { false, 0xdc3c, 0xdc3c }, +/* 0xdc3d */ { false, 0xdc3d, 0xdc3d }, +/* 0xdc3e */ { false, 0xdc3e, 0xdc3e }, +/* 0xdc3f */ { false, 0xdc3f, 0xdc3f }, +/* 0xdc40 */ { false, 0xdc40, 0xdc40 }, +/* 0xdc41 */ { false, 0xdc41, 0xdc41 }, +/* 0xdc42 */ { false, 0xdc42, 0xdc42 }, +/* 0xdc43 */ { false, 0xdc43, 0xdc43 }, +/* 0xdc44 */ { false, 0xdc44, 0xdc44 }, +/* 0xdc45 */ { false, 0xdc45, 0xdc45 }, +/* 0xdc46 */ { false, 0xdc46, 0xdc46 }, +/* 0xdc47 */ { false, 0xdc47, 0xdc47 }, +/* 0xdc48 */ { false, 0xdc48, 0xdc48 }, +/* 0xdc49 */ { false, 0xdc49, 0xdc49 }, +/* 0xdc4a */ { false, 0xdc4a, 0xdc4a }, +/* 0xdc4b */ { false, 0xdc4b, 0xdc4b }, +/* 0xdc4c */ { false, 0xdc4c, 0xdc4c }, +/* 0xdc4d */ { false, 0xdc4d, 0xdc4d }, +/* 0xdc4e */ { false, 0xdc4e, 0xdc4e }, +/* 0xdc4f */ { false, 0xdc4f, 0xdc4f }, +/* 0xdc50 */ { false, 0xdc50, 0xdc50 }, +/* 0xdc51 */ { false, 0xdc51, 0xdc51 }, +/* 0xdc52 */ { false, 0xdc52, 0xdc52 }, +/* 0xdc53 */ { false, 0xdc53, 0xdc53 }, +/* 0xdc54 */ { false, 0xdc54, 0xdc54 }, +/* 0xdc55 */ { false, 0xdc55, 0xdc55 }, +/* 0xdc56 */ { false, 0xdc56, 0xdc56 }, +/* 0xdc57 */ { false, 0xdc57, 0xdc57 }, +/* 0xdc58 */ { false, 0xdc58, 0xdc58 }, +/* 0xdc59 */ { false, 0xdc59, 0xdc59 }, +/* 0xdc5a */ { false, 0xdc5a, 0xdc5a }, +/* 0xdc5b */ { false, 0xdc5b, 0xdc5b }, +/* 0xdc5c */ { false, 0xdc5c, 0xdc5c }, +/* 0xdc5d */ { false, 0xdc5d, 0xdc5d }, +/* 0xdc5e */ { false, 0xdc5e, 0xdc5e }, +/* 0xdc5f */ { false, 0xdc5f, 0xdc5f }, +/* 0xdc60 */ { false, 0xdc60, 0xdc60 }, +/* 0xdc61 */ { false, 0xdc61, 0xdc61 }, +/* 0xdc62 */ { false, 0xdc62, 0xdc62 }, +/* 0xdc63 */ { false, 0xdc63, 0xdc63 }, +/* 0xdc64 */ { false, 0xdc64, 0xdc64 }, +/* 0xdc65 */ { false, 0xdc65, 0xdc65 }, +/* 0xdc66 */ { false, 0xdc66, 0xdc66 }, +/* 0xdc67 */ { false, 0xdc67, 0xdc67 }, +/* 0xdc68 */ { false, 0xdc68, 0xdc68 }, +/* 0xdc69 */ { false, 0xdc69, 0xdc69 }, +/* 0xdc6a */ { false, 0xdc6a, 0xdc6a }, +/* 0xdc6b */ { false, 0xdc6b, 0xdc6b }, +/* 0xdc6c */ { false, 0xdc6c, 0xdc6c }, +/* 0xdc6d */ { false, 0xdc6d, 0xdc6d }, +/* 0xdc6e */ { false, 0xdc6e, 0xdc6e }, +/* 0xdc6f */ { false, 0xdc6f, 0xdc6f }, +/* 0xdc70 */ { false, 0xdc70, 0xdc70 }, +/* 0xdc71 */ { false, 0xdc71, 0xdc71 }, +/* 0xdc72 */ { false, 0xdc72, 0xdc72 }, +/* 0xdc73 */ { false, 0xdc73, 0xdc73 }, +/* 0xdc74 */ { false, 0xdc74, 0xdc74 }, +/* 0xdc75 */ { false, 0xdc75, 0xdc75 }, +/* 0xdc76 */ { false, 0xdc76, 0xdc76 }, +/* 0xdc77 */ { false, 0xdc77, 0xdc77 }, +/* 0xdc78 */ { false, 0xdc78, 0xdc78 }, +/* 0xdc79 */ { false, 0xdc79, 0xdc79 }, +/* 0xdc7a */ { false, 0xdc7a, 0xdc7a }, +/* 0xdc7b */ { false, 0xdc7b, 0xdc7b }, +/* 0xdc7c */ { false, 0xdc7c, 0xdc7c }, +/* 0xdc7d */ { false, 0xdc7d, 0xdc7d }, +/* 0xdc7e */ { false, 0xdc7e, 0xdc7e }, +/* 0xdc7f */ { false, 0xdc7f, 0xdc7f }, +/* 0xdc80 */ { false, 0xdc80, 0xdc80 }, +/* 0xdc81 */ { false, 0xdc81, 0xdc81 }, +/* 0xdc82 */ { false, 0xdc82, 0xdc82 }, +/* 0xdc83 */ { false, 0xdc83, 0xdc83 }, +/* 0xdc84 */ { false, 0xdc84, 0xdc84 }, +/* 0xdc85 */ { false, 0xdc85, 0xdc85 }, +/* 0xdc86 */ { false, 0xdc86, 0xdc86 }, +/* 0xdc87 */ { false, 0xdc87, 0xdc87 }, +/* 0xdc88 */ { false, 0xdc88, 0xdc88 }, +/* 0xdc89 */ { false, 0xdc89, 0xdc89 }, +/* 0xdc8a */ { false, 0xdc8a, 0xdc8a }, +/* 0xdc8b */ { false, 0xdc8b, 0xdc8b }, +/* 0xdc8c */ { false, 0xdc8c, 0xdc8c }, +/* 0xdc8d */ { false, 0xdc8d, 0xdc8d }, +/* 0xdc8e */ { false, 0xdc8e, 0xdc8e }, +/* 0xdc8f */ { false, 0xdc8f, 0xdc8f }, +/* 0xdc90 */ { false, 0xdc90, 0xdc90 }, +/* 0xdc91 */ { false, 0xdc91, 0xdc91 }, +/* 0xdc92 */ { false, 0xdc92, 0xdc92 }, +/* 0xdc93 */ { false, 0xdc93, 0xdc93 }, +/* 0xdc94 */ { false, 0xdc94, 0xdc94 }, +/* 0xdc95 */ { false, 0xdc95, 0xdc95 }, +/* 0xdc96 */ { false, 0xdc96, 0xdc96 }, +/* 0xdc97 */ { false, 0xdc97, 0xdc97 }, +/* 0xdc98 */ { false, 0xdc98, 0xdc98 }, +/* 0xdc99 */ { false, 0xdc99, 0xdc99 }, +/* 0xdc9a */ { false, 0xdc9a, 0xdc9a }, +/* 0xdc9b */ { false, 0xdc9b, 0xdc9b }, +/* 0xdc9c */ { false, 0xdc9c, 0xdc9c }, +/* 0xdc9d */ { false, 0xdc9d, 0xdc9d }, +/* 0xdc9e */ { false, 0xdc9e, 0xdc9e }, +/* 0xdc9f */ { false, 0xdc9f, 0xdc9f }, +/* 0xdca0 */ { false, 0xdca0, 0xdca0 }, +/* 0xdca1 */ { false, 0xdca1, 0xdca1 }, +/* 0xdca2 */ { false, 0xdca2, 0xdca2 }, +/* 0xdca3 */ { false, 0xdca3, 0xdca3 }, +/* 0xdca4 */ { false, 0xdca4, 0xdca4 }, +/* 0xdca5 */ { false, 0xdca5, 0xdca5 }, +/* 0xdca6 */ { false, 0xdca6, 0xdca6 }, +/* 0xdca7 */ { false, 0xdca7, 0xdca7 }, +/* 0xdca8 */ { false, 0xdca8, 0xdca8 }, +/* 0xdca9 */ { false, 0xdca9, 0xdca9 }, +/* 0xdcaa */ { false, 0xdcaa, 0xdcaa }, +/* 0xdcab */ { false, 0xdcab, 0xdcab }, +/* 0xdcac */ { false, 0xdcac, 0xdcac }, +/* 0xdcad */ { false, 0xdcad, 0xdcad }, +/* 0xdcae */ { false, 0xdcae, 0xdcae }, +/* 0xdcaf */ { false, 0xdcaf, 0xdcaf }, +/* 0xdcb0 */ { false, 0xdcb0, 0xdcb0 }, +/* 0xdcb1 */ { false, 0xdcb1, 0xdcb1 }, +/* 0xdcb2 */ { false, 0xdcb2, 0xdcb2 }, +/* 0xdcb3 */ { false, 0xdcb3, 0xdcb3 }, +/* 0xdcb4 */ { false, 0xdcb4, 0xdcb4 }, +/* 0xdcb5 */ { false, 0xdcb5, 0xdcb5 }, +/* 0xdcb6 */ { false, 0xdcb6, 0xdcb6 }, +/* 0xdcb7 */ { false, 0xdcb7, 0xdcb7 }, +/* 0xdcb8 */ { false, 0xdcb8, 0xdcb8 }, +/* 0xdcb9 */ { false, 0xdcb9, 0xdcb9 }, +/* 0xdcba */ { false, 0xdcba, 0xdcba }, +/* 0xdcbb */ { false, 0xdcbb, 0xdcbb }, +/* 0xdcbc */ { false, 0xdcbc, 0xdcbc }, +/* 0xdcbd */ { false, 0xdcbd, 0xdcbd }, +/* 0xdcbe */ { false, 0xdcbe, 0xdcbe }, +/* 0xdcbf */ { false, 0xdcbf, 0xdcbf }, +/* 0xdcc0 */ { false, 0xdcc0, 0xdcc0 }, +/* 0xdcc1 */ { false, 0xdcc1, 0xdcc1 }, +/* 0xdcc2 */ { false, 0xdcc2, 0xdcc2 }, +/* 0xdcc3 */ { false, 0xdcc3, 0xdcc3 }, +/* 0xdcc4 */ { false, 0xdcc4, 0xdcc4 }, +/* 0xdcc5 */ { false, 0xdcc5, 0xdcc5 }, +/* 0xdcc6 */ { false, 0xdcc6, 0xdcc6 }, +/* 0xdcc7 */ { false, 0xdcc7, 0xdcc7 }, +/* 0xdcc8 */ { false, 0xdcc8, 0xdcc8 }, +/* 0xdcc9 */ { false, 0xdcc9, 0xdcc9 }, +/* 0xdcca */ { false, 0xdcca, 0xdcca }, +/* 0xdccb */ { false, 0xdccb, 0xdccb }, +/* 0xdccc */ { false, 0xdccc, 0xdccc }, +/* 0xdccd */ { false, 0xdccd, 0xdccd }, +/* 0xdcce */ { false, 0xdcce, 0xdcce }, +/* 0xdccf */ { false, 0xdccf, 0xdccf }, +/* 0xdcd0 */ { false, 0xdcd0, 0xdcd0 }, +/* 0xdcd1 */ { false, 0xdcd1, 0xdcd1 }, +/* 0xdcd2 */ { false, 0xdcd2, 0xdcd2 }, +/* 0xdcd3 */ { false, 0xdcd3, 0xdcd3 }, +/* 0xdcd4 */ { false, 0xdcd4, 0xdcd4 }, +/* 0xdcd5 */ { false, 0xdcd5, 0xdcd5 }, +/* 0xdcd6 */ { false, 0xdcd6, 0xdcd6 }, +/* 0xdcd7 */ { false, 0xdcd7, 0xdcd7 }, +/* 0xdcd8 */ { false, 0xdcd8, 0xdcd8 }, +/* 0xdcd9 */ { false, 0xdcd9, 0xdcd9 }, +/* 0xdcda */ { false, 0xdcda, 0xdcda }, +/* 0xdcdb */ { false, 0xdcdb, 0xdcdb }, +/* 0xdcdc */ { false, 0xdcdc, 0xdcdc }, +/* 0xdcdd */ { false, 0xdcdd, 0xdcdd }, +/* 0xdcde */ { false, 0xdcde, 0xdcde }, +/* 0xdcdf */ { false, 0xdcdf, 0xdcdf }, +/* 0xdce0 */ { false, 0xdce0, 0xdce0 }, +/* 0xdce1 */ { false, 0xdce1, 0xdce1 }, +/* 0xdce2 */ { false, 0xdce2, 0xdce2 }, +/* 0xdce3 */ { false, 0xdce3, 0xdce3 }, +/* 0xdce4 */ { false, 0xdce4, 0xdce4 }, +/* 0xdce5 */ { false, 0xdce5, 0xdce5 }, +/* 0xdce6 */ { false, 0xdce6, 0xdce6 }, +/* 0xdce7 */ { false, 0xdce7, 0xdce7 }, +/* 0xdce8 */ { false, 0xdce8, 0xdce8 }, +/* 0xdce9 */ { false, 0xdce9, 0xdce9 }, +/* 0xdcea */ { false, 0xdcea, 0xdcea }, +/* 0xdceb */ { false, 0xdceb, 0xdceb }, +/* 0xdcec */ { false, 0xdcec, 0xdcec }, +/* 0xdced */ { false, 0xdced, 0xdced }, +/* 0xdcee */ { false, 0xdcee, 0xdcee }, +/* 0xdcef */ { false, 0xdcef, 0xdcef }, +/* 0xdcf0 */ { false, 0xdcf0, 0xdcf0 }, +/* 0xdcf1 */ { false, 0xdcf1, 0xdcf1 }, +/* 0xdcf2 */ { false, 0xdcf2, 0xdcf2 }, +/* 0xdcf3 */ { false, 0xdcf3, 0xdcf3 }, +/* 0xdcf4 */ { false, 0xdcf4, 0xdcf4 }, +/* 0xdcf5 */ { false, 0xdcf5, 0xdcf5 }, +/* 0xdcf6 */ { false, 0xdcf6, 0xdcf6 }, +/* 0xdcf7 */ { false, 0xdcf7, 0xdcf7 }, +/* 0xdcf8 */ { false, 0xdcf8, 0xdcf8 }, +/* 0xdcf9 */ { false, 0xdcf9, 0xdcf9 }, +/* 0xdcfa */ { false, 0xdcfa, 0xdcfa }, +/* 0xdcfb */ { false, 0xdcfb, 0xdcfb }, +/* 0xdcfc */ { false, 0xdcfc, 0xdcfc }, +/* 0xdcfd */ { false, 0xdcfd, 0xdcfd }, +/* 0xdcfe */ { false, 0xdcfe, 0xdcfe }, +/* 0xdcff */ { false, 0xdcff, 0xdcff }, +/* 0xdd00 */ { false, 0xdd00, 0xdd00 }, +/* 0xdd01 */ { false, 0xdd01, 0xdd01 }, +/* 0xdd02 */ { false, 0xdd02, 0xdd02 }, +/* 0xdd03 */ { false, 0xdd03, 0xdd03 }, +/* 0xdd04 */ { false, 0xdd04, 0xdd04 }, +/* 0xdd05 */ { false, 0xdd05, 0xdd05 }, +/* 0xdd06 */ { false, 0xdd06, 0xdd06 }, +/* 0xdd07 */ { false, 0xdd07, 0xdd07 }, +/* 0xdd08 */ { false, 0xdd08, 0xdd08 }, +/* 0xdd09 */ { false, 0xdd09, 0xdd09 }, +/* 0xdd0a */ { false, 0xdd0a, 0xdd0a }, +/* 0xdd0b */ { false, 0xdd0b, 0xdd0b }, +/* 0xdd0c */ { false, 0xdd0c, 0xdd0c }, +/* 0xdd0d */ { false, 0xdd0d, 0xdd0d }, +/* 0xdd0e */ { false, 0xdd0e, 0xdd0e }, +/* 0xdd0f */ { false, 0xdd0f, 0xdd0f }, +/* 0xdd10 */ { false, 0xdd10, 0xdd10 }, +/* 0xdd11 */ { false, 0xdd11, 0xdd11 }, +/* 0xdd12 */ { false, 0xdd12, 0xdd12 }, +/* 0xdd13 */ { false, 0xdd13, 0xdd13 }, +/* 0xdd14 */ { false, 0xdd14, 0xdd14 }, +/* 0xdd15 */ { false, 0xdd15, 0xdd15 }, +/* 0xdd16 */ { false, 0xdd16, 0xdd16 }, +/* 0xdd17 */ { false, 0xdd17, 0xdd17 }, +/* 0xdd18 */ { false, 0xdd18, 0xdd18 }, +/* 0xdd19 */ { false, 0xdd19, 0xdd19 }, +/* 0xdd1a */ { false, 0xdd1a, 0xdd1a }, +/* 0xdd1b */ { false, 0xdd1b, 0xdd1b }, +/* 0xdd1c */ { false, 0xdd1c, 0xdd1c }, +/* 0xdd1d */ { false, 0xdd1d, 0xdd1d }, +/* 0xdd1e */ { false, 0xdd1e, 0xdd1e }, +/* 0xdd1f */ { false, 0xdd1f, 0xdd1f }, +/* 0xdd20 */ { false, 0xdd20, 0xdd20 }, +/* 0xdd21 */ { false, 0xdd21, 0xdd21 }, +/* 0xdd22 */ { false, 0xdd22, 0xdd22 }, +/* 0xdd23 */ { false, 0xdd23, 0xdd23 }, +/* 0xdd24 */ { false, 0xdd24, 0xdd24 }, +/* 0xdd25 */ { false, 0xdd25, 0xdd25 }, +/* 0xdd26 */ { false, 0xdd26, 0xdd26 }, +/* 0xdd27 */ { false, 0xdd27, 0xdd27 }, +/* 0xdd28 */ { false, 0xdd28, 0xdd28 }, +/* 0xdd29 */ { false, 0xdd29, 0xdd29 }, +/* 0xdd2a */ { false, 0xdd2a, 0xdd2a }, +/* 0xdd2b */ { false, 0xdd2b, 0xdd2b }, +/* 0xdd2c */ { false, 0xdd2c, 0xdd2c }, +/* 0xdd2d */ { false, 0xdd2d, 0xdd2d }, +/* 0xdd2e */ { false, 0xdd2e, 0xdd2e }, +/* 0xdd2f */ { false, 0xdd2f, 0xdd2f }, +/* 0xdd30 */ { false, 0xdd30, 0xdd30 }, +/* 0xdd31 */ { false, 0xdd31, 0xdd31 }, +/* 0xdd32 */ { false, 0xdd32, 0xdd32 }, +/* 0xdd33 */ { false, 0xdd33, 0xdd33 }, +/* 0xdd34 */ { false, 0xdd34, 0xdd34 }, +/* 0xdd35 */ { false, 0xdd35, 0xdd35 }, +/* 0xdd36 */ { false, 0xdd36, 0xdd36 }, +/* 0xdd37 */ { false, 0xdd37, 0xdd37 }, +/* 0xdd38 */ { false, 0xdd38, 0xdd38 }, +/* 0xdd39 */ { false, 0xdd39, 0xdd39 }, +/* 0xdd3a */ { false, 0xdd3a, 0xdd3a }, +/* 0xdd3b */ { false, 0xdd3b, 0xdd3b }, +/* 0xdd3c */ { false, 0xdd3c, 0xdd3c }, +/* 0xdd3d */ { false, 0xdd3d, 0xdd3d }, +/* 0xdd3e */ { false, 0xdd3e, 0xdd3e }, +/* 0xdd3f */ { false, 0xdd3f, 0xdd3f }, +/* 0xdd40 */ { false, 0xdd40, 0xdd40 }, +/* 0xdd41 */ { false, 0xdd41, 0xdd41 }, +/* 0xdd42 */ { false, 0xdd42, 0xdd42 }, +/* 0xdd43 */ { false, 0xdd43, 0xdd43 }, +/* 0xdd44 */ { false, 0xdd44, 0xdd44 }, +/* 0xdd45 */ { false, 0xdd45, 0xdd45 }, +/* 0xdd46 */ { false, 0xdd46, 0xdd46 }, +/* 0xdd47 */ { false, 0xdd47, 0xdd47 }, +/* 0xdd48 */ { false, 0xdd48, 0xdd48 }, +/* 0xdd49 */ { false, 0xdd49, 0xdd49 }, +/* 0xdd4a */ { false, 0xdd4a, 0xdd4a }, +/* 0xdd4b */ { false, 0xdd4b, 0xdd4b }, +/* 0xdd4c */ { false, 0xdd4c, 0xdd4c }, +/* 0xdd4d */ { false, 0xdd4d, 0xdd4d }, +/* 0xdd4e */ { false, 0xdd4e, 0xdd4e }, +/* 0xdd4f */ { false, 0xdd4f, 0xdd4f }, +/* 0xdd50 */ { false, 0xdd50, 0xdd50 }, +/* 0xdd51 */ { false, 0xdd51, 0xdd51 }, +/* 0xdd52 */ { false, 0xdd52, 0xdd52 }, +/* 0xdd53 */ { false, 0xdd53, 0xdd53 }, +/* 0xdd54 */ { false, 0xdd54, 0xdd54 }, +/* 0xdd55 */ { false, 0xdd55, 0xdd55 }, +/* 0xdd56 */ { false, 0xdd56, 0xdd56 }, +/* 0xdd57 */ { false, 0xdd57, 0xdd57 }, +/* 0xdd58 */ { false, 0xdd58, 0xdd58 }, +/* 0xdd59 */ { false, 0xdd59, 0xdd59 }, +/* 0xdd5a */ { false, 0xdd5a, 0xdd5a }, +/* 0xdd5b */ { false, 0xdd5b, 0xdd5b }, +/* 0xdd5c */ { false, 0xdd5c, 0xdd5c }, +/* 0xdd5d */ { false, 0xdd5d, 0xdd5d }, +/* 0xdd5e */ { false, 0xdd5e, 0xdd5e }, +/* 0xdd5f */ { false, 0xdd5f, 0xdd5f }, +/* 0xdd60 */ { false, 0xdd60, 0xdd60 }, +/* 0xdd61 */ { false, 0xdd61, 0xdd61 }, +/* 0xdd62 */ { false, 0xdd62, 0xdd62 }, +/* 0xdd63 */ { false, 0xdd63, 0xdd63 }, +/* 0xdd64 */ { false, 0xdd64, 0xdd64 }, +/* 0xdd65 */ { false, 0xdd65, 0xdd65 }, +/* 0xdd66 */ { false, 0xdd66, 0xdd66 }, +/* 0xdd67 */ { false, 0xdd67, 0xdd67 }, +/* 0xdd68 */ { false, 0xdd68, 0xdd68 }, +/* 0xdd69 */ { false, 0xdd69, 0xdd69 }, +/* 0xdd6a */ { false, 0xdd6a, 0xdd6a }, +/* 0xdd6b */ { false, 0xdd6b, 0xdd6b }, +/* 0xdd6c */ { false, 0xdd6c, 0xdd6c }, +/* 0xdd6d */ { false, 0xdd6d, 0xdd6d }, +/* 0xdd6e */ { false, 0xdd6e, 0xdd6e }, +/* 0xdd6f */ { false, 0xdd6f, 0xdd6f }, +/* 0xdd70 */ { false, 0xdd70, 0xdd70 }, +/* 0xdd71 */ { false, 0xdd71, 0xdd71 }, +/* 0xdd72 */ { false, 0xdd72, 0xdd72 }, +/* 0xdd73 */ { false, 0xdd73, 0xdd73 }, +/* 0xdd74 */ { false, 0xdd74, 0xdd74 }, +/* 0xdd75 */ { false, 0xdd75, 0xdd75 }, +/* 0xdd76 */ { false, 0xdd76, 0xdd76 }, +/* 0xdd77 */ { false, 0xdd77, 0xdd77 }, +/* 0xdd78 */ { false, 0xdd78, 0xdd78 }, +/* 0xdd79 */ { false, 0xdd79, 0xdd79 }, +/* 0xdd7a */ { false, 0xdd7a, 0xdd7a }, +/* 0xdd7b */ { false, 0xdd7b, 0xdd7b }, +/* 0xdd7c */ { false, 0xdd7c, 0xdd7c }, +/* 0xdd7d */ { false, 0xdd7d, 0xdd7d }, +/* 0xdd7e */ { false, 0xdd7e, 0xdd7e }, +/* 0xdd7f */ { false, 0xdd7f, 0xdd7f }, +/* 0xdd80 */ { false, 0xdd80, 0xdd80 }, +/* 0xdd81 */ { false, 0xdd81, 0xdd81 }, +/* 0xdd82 */ { false, 0xdd82, 0xdd82 }, +/* 0xdd83 */ { false, 0xdd83, 0xdd83 }, +/* 0xdd84 */ { false, 0xdd84, 0xdd84 }, +/* 0xdd85 */ { false, 0xdd85, 0xdd85 }, +/* 0xdd86 */ { false, 0xdd86, 0xdd86 }, +/* 0xdd87 */ { false, 0xdd87, 0xdd87 }, +/* 0xdd88 */ { false, 0xdd88, 0xdd88 }, +/* 0xdd89 */ { false, 0xdd89, 0xdd89 }, +/* 0xdd8a */ { false, 0xdd8a, 0xdd8a }, +/* 0xdd8b */ { false, 0xdd8b, 0xdd8b }, +/* 0xdd8c */ { false, 0xdd8c, 0xdd8c }, +/* 0xdd8d */ { false, 0xdd8d, 0xdd8d }, +/* 0xdd8e */ { false, 0xdd8e, 0xdd8e }, +/* 0xdd8f */ { false, 0xdd8f, 0xdd8f }, +/* 0xdd90 */ { false, 0xdd90, 0xdd90 }, +/* 0xdd91 */ { false, 0xdd91, 0xdd91 }, +/* 0xdd92 */ { false, 0xdd92, 0xdd92 }, +/* 0xdd93 */ { false, 0xdd93, 0xdd93 }, +/* 0xdd94 */ { false, 0xdd94, 0xdd94 }, +/* 0xdd95 */ { false, 0xdd95, 0xdd95 }, +/* 0xdd96 */ { false, 0xdd96, 0xdd96 }, +/* 0xdd97 */ { false, 0xdd97, 0xdd97 }, +/* 0xdd98 */ { false, 0xdd98, 0xdd98 }, +/* 0xdd99 */ { false, 0xdd99, 0xdd99 }, +/* 0xdd9a */ { false, 0xdd9a, 0xdd9a }, +/* 0xdd9b */ { false, 0xdd9b, 0xdd9b }, +/* 0xdd9c */ { false, 0xdd9c, 0xdd9c }, +/* 0xdd9d */ { false, 0xdd9d, 0xdd9d }, +/* 0xdd9e */ { false, 0xdd9e, 0xdd9e }, +/* 0xdd9f */ { false, 0xdd9f, 0xdd9f }, +/* 0xdda0 */ { false, 0xdda0, 0xdda0 }, +/* 0xdda1 */ { false, 0xdda1, 0xdda1 }, +/* 0xdda2 */ { false, 0xdda2, 0xdda2 }, +/* 0xdda3 */ { false, 0xdda3, 0xdda3 }, +/* 0xdda4 */ { false, 0xdda4, 0xdda4 }, +/* 0xdda5 */ { false, 0xdda5, 0xdda5 }, +/* 0xdda6 */ { false, 0xdda6, 0xdda6 }, +/* 0xdda7 */ { false, 0xdda7, 0xdda7 }, +/* 0xdda8 */ { false, 0xdda8, 0xdda8 }, +/* 0xdda9 */ { false, 0xdda9, 0xdda9 }, +/* 0xddaa */ { false, 0xddaa, 0xddaa }, +/* 0xddab */ { false, 0xddab, 0xddab }, +/* 0xddac */ { false, 0xddac, 0xddac }, +/* 0xddad */ { false, 0xddad, 0xddad }, +/* 0xddae */ { false, 0xddae, 0xddae }, +/* 0xddaf */ { false, 0xddaf, 0xddaf }, +/* 0xddb0 */ { false, 0xddb0, 0xddb0 }, +/* 0xddb1 */ { false, 0xddb1, 0xddb1 }, +/* 0xddb2 */ { false, 0xddb2, 0xddb2 }, +/* 0xddb3 */ { false, 0xddb3, 0xddb3 }, +/* 0xddb4 */ { false, 0xddb4, 0xddb4 }, +/* 0xddb5 */ { false, 0xddb5, 0xddb5 }, +/* 0xddb6 */ { false, 0xddb6, 0xddb6 }, +/* 0xddb7 */ { false, 0xddb7, 0xddb7 }, +/* 0xddb8 */ { false, 0xddb8, 0xddb8 }, +/* 0xddb9 */ { false, 0xddb9, 0xddb9 }, +/* 0xddba */ { false, 0xddba, 0xddba }, +/* 0xddbb */ { false, 0xddbb, 0xddbb }, +/* 0xddbc */ { false, 0xddbc, 0xddbc }, +/* 0xddbd */ { false, 0xddbd, 0xddbd }, +/* 0xddbe */ { false, 0xddbe, 0xddbe }, +/* 0xddbf */ { false, 0xddbf, 0xddbf }, +/* 0xddc0 */ { false, 0xddc0, 0xddc0 }, +/* 0xddc1 */ { false, 0xddc1, 0xddc1 }, +/* 0xddc2 */ { false, 0xddc2, 0xddc2 }, +/* 0xddc3 */ { false, 0xddc3, 0xddc3 }, +/* 0xddc4 */ { false, 0xddc4, 0xddc4 }, +/* 0xddc5 */ { false, 0xddc5, 0xddc5 }, +/* 0xddc6 */ { false, 0xddc6, 0xddc6 }, +/* 0xddc7 */ { false, 0xddc7, 0xddc7 }, +/* 0xddc8 */ { false, 0xddc8, 0xddc8 }, +/* 0xddc9 */ { false, 0xddc9, 0xddc9 }, +/* 0xddca */ { false, 0xddca, 0xddca }, +/* 0xddcb */ { false, 0xddcb, 0xddcb }, +/* 0xddcc */ { false, 0xddcc, 0xddcc }, +/* 0xddcd */ { false, 0xddcd, 0xddcd }, +/* 0xddce */ { false, 0xddce, 0xddce }, +/* 0xddcf */ { false, 0xddcf, 0xddcf }, +/* 0xddd0 */ { false, 0xddd0, 0xddd0 }, +/* 0xddd1 */ { false, 0xddd1, 0xddd1 }, +/* 0xddd2 */ { false, 0xddd2, 0xddd2 }, +/* 0xddd3 */ { false, 0xddd3, 0xddd3 }, +/* 0xddd4 */ { false, 0xddd4, 0xddd4 }, +/* 0xddd5 */ { false, 0xddd5, 0xddd5 }, +/* 0xddd6 */ { false, 0xddd6, 0xddd6 }, +/* 0xddd7 */ { false, 0xddd7, 0xddd7 }, +/* 0xddd8 */ { false, 0xddd8, 0xddd8 }, +/* 0xddd9 */ { false, 0xddd9, 0xddd9 }, +/* 0xddda */ { false, 0xddda, 0xddda }, +/* 0xdddb */ { false, 0xdddb, 0xdddb }, +/* 0xdddc */ { false, 0xdddc, 0xdddc }, +/* 0xdddd */ { false, 0xdddd, 0xdddd }, +/* 0xddde */ { false, 0xddde, 0xddde }, +/* 0xdddf */ { false, 0xdddf, 0xdddf }, +/* 0xdde0 */ { false, 0xdde0, 0xdde0 }, +/* 0xdde1 */ { false, 0xdde1, 0xdde1 }, +/* 0xdde2 */ { false, 0xdde2, 0xdde2 }, +/* 0xdde3 */ { false, 0xdde3, 0xdde3 }, +/* 0xdde4 */ { false, 0xdde4, 0xdde4 }, +/* 0xdde5 */ { false, 0xdde5, 0xdde5 }, +/* 0xdde6 */ { false, 0xdde6, 0xdde6 }, +/* 0xdde7 */ { false, 0xdde7, 0xdde7 }, +/* 0xdde8 */ { false, 0xdde8, 0xdde8 }, +/* 0xdde9 */ { false, 0xdde9, 0xdde9 }, +/* 0xddea */ { false, 0xddea, 0xddea }, +/* 0xddeb */ { false, 0xddeb, 0xddeb }, +/* 0xddec */ { false, 0xddec, 0xddec }, +/* 0xdded */ { false, 0xdded, 0xdded }, +/* 0xddee */ { false, 0xddee, 0xddee }, +/* 0xddef */ { false, 0xddef, 0xddef }, +/* 0xddf0 */ { false, 0xddf0, 0xddf0 }, +/* 0xddf1 */ { false, 0xddf1, 0xddf1 }, +/* 0xddf2 */ { false, 0xddf2, 0xddf2 }, +/* 0xddf3 */ { false, 0xddf3, 0xddf3 }, +/* 0xddf4 */ { false, 0xddf4, 0xddf4 }, +/* 0xddf5 */ { false, 0xddf5, 0xddf5 }, +/* 0xddf6 */ { false, 0xddf6, 0xddf6 }, +/* 0xddf7 */ { false, 0xddf7, 0xddf7 }, +/* 0xddf8 */ { false, 0xddf8, 0xddf8 }, +/* 0xddf9 */ { false, 0xddf9, 0xddf9 }, +/* 0xddfa */ { false, 0xddfa, 0xddfa }, +/* 0xddfb */ { false, 0xddfb, 0xddfb }, +/* 0xddfc */ { false, 0xddfc, 0xddfc }, +/* 0xddfd */ { false, 0xddfd, 0xddfd }, +/* 0xddfe */ { false, 0xddfe, 0xddfe }, +/* 0xddff */ { false, 0xddff, 0xddff }, +/* 0xde00 */ { false, 0xde00, 0xde00 }, +/* 0xde01 */ { false, 0xde01, 0xde01 }, +/* 0xde02 */ { false, 0xde02, 0xde02 }, +/* 0xde03 */ { false, 0xde03, 0xde03 }, +/* 0xde04 */ { false, 0xde04, 0xde04 }, +/* 0xde05 */ { false, 0xde05, 0xde05 }, +/* 0xde06 */ { false, 0xde06, 0xde06 }, +/* 0xde07 */ { false, 0xde07, 0xde07 }, +/* 0xde08 */ { false, 0xde08, 0xde08 }, +/* 0xde09 */ { false, 0xde09, 0xde09 }, +/* 0xde0a */ { false, 0xde0a, 0xde0a }, +/* 0xde0b */ { false, 0xde0b, 0xde0b }, +/* 0xde0c */ { false, 0xde0c, 0xde0c }, +/* 0xde0d */ { false, 0xde0d, 0xde0d }, +/* 0xde0e */ { false, 0xde0e, 0xde0e }, +/* 0xde0f */ { false, 0xde0f, 0xde0f }, +/* 0xde10 */ { false, 0xde10, 0xde10 }, +/* 0xde11 */ { false, 0xde11, 0xde11 }, +/* 0xde12 */ { false, 0xde12, 0xde12 }, +/* 0xde13 */ { false, 0xde13, 0xde13 }, +/* 0xde14 */ { false, 0xde14, 0xde14 }, +/* 0xde15 */ { false, 0xde15, 0xde15 }, +/* 0xde16 */ { false, 0xde16, 0xde16 }, +/* 0xde17 */ { false, 0xde17, 0xde17 }, +/* 0xde18 */ { false, 0xde18, 0xde18 }, +/* 0xde19 */ { false, 0xde19, 0xde19 }, +/* 0xde1a */ { false, 0xde1a, 0xde1a }, +/* 0xde1b */ { false, 0xde1b, 0xde1b }, +/* 0xde1c */ { false, 0xde1c, 0xde1c }, +/* 0xde1d */ { false, 0xde1d, 0xde1d }, +/* 0xde1e */ { false, 0xde1e, 0xde1e }, +/* 0xde1f */ { false, 0xde1f, 0xde1f }, +/* 0xde20 */ { false, 0xde20, 0xde20 }, +/* 0xde21 */ { false, 0xde21, 0xde21 }, +/* 0xde22 */ { false, 0xde22, 0xde22 }, +/* 0xde23 */ { false, 0xde23, 0xde23 }, +/* 0xde24 */ { false, 0xde24, 0xde24 }, +/* 0xde25 */ { false, 0xde25, 0xde25 }, +/* 0xde26 */ { false, 0xde26, 0xde26 }, +/* 0xde27 */ { false, 0xde27, 0xde27 }, +/* 0xde28 */ { false, 0xde28, 0xde28 }, +/* 0xde29 */ { false, 0xde29, 0xde29 }, +/* 0xde2a */ { false, 0xde2a, 0xde2a }, +/* 0xde2b */ { false, 0xde2b, 0xde2b }, +/* 0xde2c */ { false, 0xde2c, 0xde2c }, +/* 0xde2d */ { false, 0xde2d, 0xde2d }, +/* 0xde2e */ { false, 0xde2e, 0xde2e }, +/* 0xde2f */ { false, 0xde2f, 0xde2f }, +/* 0xde30 */ { false, 0xde30, 0xde30 }, +/* 0xde31 */ { false, 0xde31, 0xde31 }, +/* 0xde32 */ { false, 0xde32, 0xde32 }, +/* 0xde33 */ { false, 0xde33, 0xde33 }, +/* 0xde34 */ { false, 0xde34, 0xde34 }, +/* 0xde35 */ { false, 0xde35, 0xde35 }, +/* 0xde36 */ { false, 0xde36, 0xde36 }, +/* 0xde37 */ { false, 0xde37, 0xde37 }, +/* 0xde38 */ { false, 0xde38, 0xde38 }, +/* 0xde39 */ { false, 0xde39, 0xde39 }, +/* 0xde3a */ { false, 0xde3a, 0xde3a }, +/* 0xde3b */ { false, 0xde3b, 0xde3b }, +/* 0xde3c */ { false, 0xde3c, 0xde3c }, +/* 0xde3d */ { false, 0xde3d, 0xde3d }, +/* 0xde3e */ { false, 0xde3e, 0xde3e }, +/* 0xde3f */ { false, 0xde3f, 0xde3f }, +/* 0xde40 */ { false, 0xde40, 0xde40 }, +/* 0xde41 */ { false, 0xde41, 0xde41 }, +/* 0xde42 */ { false, 0xde42, 0xde42 }, +/* 0xde43 */ { false, 0xde43, 0xde43 }, +/* 0xde44 */ { false, 0xde44, 0xde44 }, +/* 0xde45 */ { false, 0xde45, 0xde45 }, +/* 0xde46 */ { false, 0xde46, 0xde46 }, +/* 0xde47 */ { false, 0xde47, 0xde47 }, +/* 0xde48 */ { false, 0xde48, 0xde48 }, +/* 0xde49 */ { false, 0xde49, 0xde49 }, +/* 0xde4a */ { false, 0xde4a, 0xde4a }, +/* 0xde4b */ { false, 0xde4b, 0xde4b }, +/* 0xde4c */ { false, 0xde4c, 0xde4c }, +/* 0xde4d */ { false, 0xde4d, 0xde4d }, +/* 0xde4e */ { false, 0xde4e, 0xde4e }, +/* 0xde4f */ { false, 0xde4f, 0xde4f }, +/* 0xde50 */ { false, 0xde50, 0xde50 }, +/* 0xde51 */ { false, 0xde51, 0xde51 }, +/* 0xde52 */ { false, 0xde52, 0xde52 }, +/* 0xde53 */ { false, 0xde53, 0xde53 }, +/* 0xde54 */ { false, 0xde54, 0xde54 }, +/* 0xde55 */ { false, 0xde55, 0xde55 }, +/* 0xde56 */ { false, 0xde56, 0xde56 }, +/* 0xde57 */ { false, 0xde57, 0xde57 }, +/* 0xde58 */ { false, 0xde58, 0xde58 }, +/* 0xde59 */ { false, 0xde59, 0xde59 }, +/* 0xde5a */ { false, 0xde5a, 0xde5a }, +/* 0xde5b */ { false, 0xde5b, 0xde5b }, +/* 0xde5c */ { false, 0xde5c, 0xde5c }, +/* 0xde5d */ { false, 0xde5d, 0xde5d }, +/* 0xde5e */ { false, 0xde5e, 0xde5e }, +/* 0xde5f */ { false, 0xde5f, 0xde5f }, +/* 0xde60 */ { false, 0xde60, 0xde60 }, +/* 0xde61 */ { false, 0xde61, 0xde61 }, +/* 0xde62 */ { false, 0xde62, 0xde62 }, +/* 0xde63 */ { false, 0xde63, 0xde63 }, +/* 0xde64 */ { false, 0xde64, 0xde64 }, +/* 0xde65 */ { false, 0xde65, 0xde65 }, +/* 0xde66 */ { false, 0xde66, 0xde66 }, +/* 0xde67 */ { false, 0xde67, 0xde67 }, +/* 0xde68 */ { false, 0xde68, 0xde68 }, +/* 0xde69 */ { false, 0xde69, 0xde69 }, +/* 0xde6a */ { false, 0xde6a, 0xde6a }, +/* 0xde6b */ { false, 0xde6b, 0xde6b }, +/* 0xde6c */ { false, 0xde6c, 0xde6c }, +/* 0xde6d */ { false, 0xde6d, 0xde6d }, +/* 0xde6e */ { false, 0xde6e, 0xde6e }, +/* 0xde6f */ { false, 0xde6f, 0xde6f }, +/* 0xde70 */ { false, 0xde70, 0xde70 }, +/* 0xde71 */ { false, 0xde71, 0xde71 }, +/* 0xde72 */ { false, 0xde72, 0xde72 }, +/* 0xde73 */ { false, 0xde73, 0xde73 }, +/* 0xde74 */ { false, 0xde74, 0xde74 }, +/* 0xde75 */ { false, 0xde75, 0xde75 }, +/* 0xde76 */ { false, 0xde76, 0xde76 }, +/* 0xde77 */ { false, 0xde77, 0xde77 }, +/* 0xde78 */ { false, 0xde78, 0xde78 }, +/* 0xde79 */ { false, 0xde79, 0xde79 }, +/* 0xde7a */ { false, 0xde7a, 0xde7a }, +/* 0xde7b */ { false, 0xde7b, 0xde7b }, +/* 0xde7c */ { false, 0xde7c, 0xde7c }, +/* 0xde7d */ { false, 0xde7d, 0xde7d }, +/* 0xde7e */ { false, 0xde7e, 0xde7e }, +/* 0xde7f */ { false, 0xde7f, 0xde7f }, +/* 0xde80 */ { false, 0xde80, 0xde80 }, +/* 0xde81 */ { false, 0xde81, 0xde81 }, +/* 0xde82 */ { false, 0xde82, 0xde82 }, +/* 0xde83 */ { false, 0xde83, 0xde83 }, +/* 0xde84 */ { false, 0xde84, 0xde84 }, +/* 0xde85 */ { false, 0xde85, 0xde85 }, +/* 0xde86 */ { false, 0xde86, 0xde86 }, +/* 0xde87 */ { false, 0xde87, 0xde87 }, +/* 0xde88 */ { false, 0xde88, 0xde88 }, +/* 0xde89 */ { false, 0xde89, 0xde89 }, +/* 0xde8a */ { false, 0xde8a, 0xde8a }, +/* 0xde8b */ { false, 0xde8b, 0xde8b }, +/* 0xde8c */ { false, 0xde8c, 0xde8c }, +/* 0xde8d */ { false, 0xde8d, 0xde8d }, +/* 0xde8e */ { false, 0xde8e, 0xde8e }, +/* 0xde8f */ { false, 0xde8f, 0xde8f }, +/* 0xde90 */ { false, 0xde90, 0xde90 }, +/* 0xde91 */ { false, 0xde91, 0xde91 }, +/* 0xde92 */ { false, 0xde92, 0xde92 }, +/* 0xde93 */ { false, 0xde93, 0xde93 }, +/* 0xde94 */ { false, 0xde94, 0xde94 }, +/* 0xde95 */ { false, 0xde95, 0xde95 }, +/* 0xde96 */ { false, 0xde96, 0xde96 }, +/* 0xde97 */ { false, 0xde97, 0xde97 }, +/* 0xde98 */ { false, 0xde98, 0xde98 }, +/* 0xde99 */ { false, 0xde99, 0xde99 }, +/* 0xde9a */ { false, 0xde9a, 0xde9a }, +/* 0xde9b */ { false, 0xde9b, 0xde9b }, +/* 0xde9c */ { false, 0xde9c, 0xde9c }, +/* 0xde9d */ { false, 0xde9d, 0xde9d }, +/* 0xde9e */ { false, 0xde9e, 0xde9e }, +/* 0xde9f */ { false, 0xde9f, 0xde9f }, +/* 0xdea0 */ { false, 0xdea0, 0xdea0 }, +/* 0xdea1 */ { false, 0xdea1, 0xdea1 }, +/* 0xdea2 */ { false, 0xdea2, 0xdea2 }, +/* 0xdea3 */ { false, 0xdea3, 0xdea3 }, +/* 0xdea4 */ { false, 0xdea4, 0xdea4 }, +/* 0xdea5 */ { false, 0xdea5, 0xdea5 }, +/* 0xdea6 */ { false, 0xdea6, 0xdea6 }, +/* 0xdea7 */ { false, 0xdea7, 0xdea7 }, +/* 0xdea8 */ { false, 0xdea8, 0xdea8 }, +/* 0xdea9 */ { false, 0xdea9, 0xdea9 }, +/* 0xdeaa */ { false, 0xdeaa, 0xdeaa }, +/* 0xdeab */ { false, 0xdeab, 0xdeab }, +/* 0xdeac */ { false, 0xdeac, 0xdeac }, +/* 0xdead */ { false, 0xdead, 0xdead }, +/* 0xdeae */ { false, 0xdeae, 0xdeae }, +/* 0xdeaf */ { false, 0xdeaf, 0xdeaf }, +/* 0xdeb0 */ { false, 0xdeb0, 0xdeb0 }, +/* 0xdeb1 */ { false, 0xdeb1, 0xdeb1 }, +/* 0xdeb2 */ { false, 0xdeb2, 0xdeb2 }, +/* 0xdeb3 */ { false, 0xdeb3, 0xdeb3 }, +/* 0xdeb4 */ { false, 0xdeb4, 0xdeb4 }, +/* 0xdeb5 */ { false, 0xdeb5, 0xdeb5 }, +/* 0xdeb6 */ { false, 0xdeb6, 0xdeb6 }, +/* 0xdeb7 */ { false, 0xdeb7, 0xdeb7 }, +/* 0xdeb8 */ { false, 0xdeb8, 0xdeb8 }, +/* 0xdeb9 */ { false, 0xdeb9, 0xdeb9 }, +/* 0xdeba */ { false, 0xdeba, 0xdeba }, +/* 0xdebb */ { false, 0xdebb, 0xdebb }, +/* 0xdebc */ { false, 0xdebc, 0xdebc }, +/* 0xdebd */ { false, 0xdebd, 0xdebd }, +/* 0xdebe */ { false, 0xdebe, 0xdebe }, +/* 0xdebf */ { false, 0xdebf, 0xdebf }, +/* 0xdec0 */ { false, 0xdec0, 0xdec0 }, +/* 0xdec1 */ { false, 0xdec1, 0xdec1 }, +/* 0xdec2 */ { false, 0xdec2, 0xdec2 }, +/* 0xdec3 */ { false, 0xdec3, 0xdec3 }, +/* 0xdec4 */ { false, 0xdec4, 0xdec4 }, +/* 0xdec5 */ { false, 0xdec5, 0xdec5 }, +/* 0xdec6 */ { false, 0xdec6, 0xdec6 }, +/* 0xdec7 */ { false, 0xdec7, 0xdec7 }, +/* 0xdec8 */ { false, 0xdec8, 0xdec8 }, +/* 0xdec9 */ { false, 0xdec9, 0xdec9 }, +/* 0xdeca */ { false, 0xdeca, 0xdeca }, +/* 0xdecb */ { false, 0xdecb, 0xdecb }, +/* 0xdecc */ { false, 0xdecc, 0xdecc }, +/* 0xdecd */ { false, 0xdecd, 0xdecd }, +/* 0xdece */ { false, 0xdece, 0xdece }, +/* 0xdecf */ { false, 0xdecf, 0xdecf }, +/* 0xded0 */ { false, 0xded0, 0xded0 }, +/* 0xded1 */ { false, 0xded1, 0xded1 }, +/* 0xded2 */ { false, 0xded2, 0xded2 }, +/* 0xded3 */ { false, 0xded3, 0xded3 }, +/* 0xded4 */ { false, 0xded4, 0xded4 }, +/* 0xded5 */ { false, 0xded5, 0xded5 }, +/* 0xded6 */ { false, 0xded6, 0xded6 }, +/* 0xded7 */ { false, 0xded7, 0xded7 }, +/* 0xded8 */ { false, 0xded8, 0xded8 }, +/* 0xded9 */ { false, 0xded9, 0xded9 }, +/* 0xdeda */ { false, 0xdeda, 0xdeda }, +/* 0xdedb */ { false, 0xdedb, 0xdedb }, +/* 0xdedc */ { false, 0xdedc, 0xdedc }, +/* 0xdedd */ { false, 0xdedd, 0xdedd }, +/* 0xdede */ { false, 0xdede, 0xdede }, +/* 0xdedf */ { false, 0xdedf, 0xdedf }, +/* 0xdee0 */ { false, 0xdee0, 0xdee0 }, +/* 0xdee1 */ { false, 0xdee1, 0xdee1 }, +/* 0xdee2 */ { false, 0xdee2, 0xdee2 }, +/* 0xdee3 */ { false, 0xdee3, 0xdee3 }, +/* 0xdee4 */ { false, 0xdee4, 0xdee4 }, +/* 0xdee5 */ { false, 0xdee5, 0xdee5 }, +/* 0xdee6 */ { false, 0xdee6, 0xdee6 }, +/* 0xdee7 */ { false, 0xdee7, 0xdee7 }, +/* 0xdee8 */ { false, 0xdee8, 0xdee8 }, +/* 0xdee9 */ { false, 0xdee9, 0xdee9 }, +/* 0xdeea */ { false, 0xdeea, 0xdeea }, +/* 0xdeeb */ { false, 0xdeeb, 0xdeeb }, +/* 0xdeec */ { false, 0xdeec, 0xdeec }, +/* 0xdeed */ { false, 0xdeed, 0xdeed }, +/* 0xdeee */ { false, 0xdeee, 0xdeee }, +/* 0xdeef */ { false, 0xdeef, 0xdeef }, +/* 0xdef0 */ { false, 0xdef0, 0xdef0 }, +/* 0xdef1 */ { false, 0xdef1, 0xdef1 }, +/* 0xdef2 */ { false, 0xdef2, 0xdef2 }, +/* 0xdef3 */ { false, 0xdef3, 0xdef3 }, +/* 0xdef4 */ { false, 0xdef4, 0xdef4 }, +/* 0xdef5 */ { false, 0xdef5, 0xdef5 }, +/* 0xdef6 */ { false, 0xdef6, 0xdef6 }, +/* 0xdef7 */ { false, 0xdef7, 0xdef7 }, +/* 0xdef8 */ { false, 0xdef8, 0xdef8 }, +/* 0xdef9 */ { false, 0xdef9, 0xdef9 }, +/* 0xdefa */ { false, 0xdefa, 0xdefa }, +/* 0xdefb */ { false, 0xdefb, 0xdefb }, +/* 0xdefc */ { false, 0xdefc, 0xdefc }, +/* 0xdefd */ { false, 0xdefd, 0xdefd }, +/* 0xdefe */ { false, 0xdefe, 0xdefe }, +/* 0xdeff */ { false, 0xdeff, 0xdeff }, +/* 0xdf00 */ { false, 0xdf00, 0xdf00 }, +/* 0xdf01 */ { false, 0xdf01, 0xdf01 }, +/* 0xdf02 */ { false, 0xdf02, 0xdf02 }, +/* 0xdf03 */ { false, 0xdf03, 0xdf03 }, +/* 0xdf04 */ { false, 0xdf04, 0xdf04 }, +/* 0xdf05 */ { false, 0xdf05, 0xdf05 }, +/* 0xdf06 */ { false, 0xdf06, 0xdf06 }, +/* 0xdf07 */ { false, 0xdf07, 0xdf07 }, +/* 0xdf08 */ { false, 0xdf08, 0xdf08 }, +/* 0xdf09 */ { false, 0xdf09, 0xdf09 }, +/* 0xdf0a */ { false, 0xdf0a, 0xdf0a }, +/* 0xdf0b */ { false, 0xdf0b, 0xdf0b }, +/* 0xdf0c */ { false, 0xdf0c, 0xdf0c }, +/* 0xdf0d */ { false, 0xdf0d, 0xdf0d }, +/* 0xdf0e */ { false, 0xdf0e, 0xdf0e }, +/* 0xdf0f */ { false, 0xdf0f, 0xdf0f }, +/* 0xdf10 */ { false, 0xdf10, 0xdf10 }, +/* 0xdf11 */ { false, 0xdf11, 0xdf11 }, +/* 0xdf12 */ { false, 0xdf12, 0xdf12 }, +/* 0xdf13 */ { false, 0xdf13, 0xdf13 }, +/* 0xdf14 */ { false, 0xdf14, 0xdf14 }, +/* 0xdf15 */ { false, 0xdf15, 0xdf15 }, +/* 0xdf16 */ { false, 0xdf16, 0xdf16 }, +/* 0xdf17 */ { false, 0xdf17, 0xdf17 }, +/* 0xdf18 */ { false, 0xdf18, 0xdf18 }, +/* 0xdf19 */ { false, 0xdf19, 0xdf19 }, +/* 0xdf1a */ { false, 0xdf1a, 0xdf1a }, +/* 0xdf1b */ { false, 0xdf1b, 0xdf1b }, +/* 0xdf1c */ { false, 0xdf1c, 0xdf1c }, +/* 0xdf1d */ { false, 0xdf1d, 0xdf1d }, +/* 0xdf1e */ { false, 0xdf1e, 0xdf1e }, +/* 0xdf1f */ { false, 0xdf1f, 0xdf1f }, +/* 0xdf20 */ { false, 0xdf20, 0xdf20 }, +/* 0xdf21 */ { false, 0xdf21, 0xdf21 }, +/* 0xdf22 */ { false, 0xdf22, 0xdf22 }, +/* 0xdf23 */ { false, 0xdf23, 0xdf23 }, +/* 0xdf24 */ { false, 0xdf24, 0xdf24 }, +/* 0xdf25 */ { false, 0xdf25, 0xdf25 }, +/* 0xdf26 */ { false, 0xdf26, 0xdf26 }, +/* 0xdf27 */ { false, 0xdf27, 0xdf27 }, +/* 0xdf28 */ { false, 0xdf28, 0xdf28 }, +/* 0xdf29 */ { false, 0xdf29, 0xdf29 }, +/* 0xdf2a */ { false, 0xdf2a, 0xdf2a }, +/* 0xdf2b */ { false, 0xdf2b, 0xdf2b }, +/* 0xdf2c */ { false, 0xdf2c, 0xdf2c }, +/* 0xdf2d */ { false, 0xdf2d, 0xdf2d }, +/* 0xdf2e */ { false, 0xdf2e, 0xdf2e }, +/* 0xdf2f */ { false, 0xdf2f, 0xdf2f }, +/* 0xdf30 */ { false, 0xdf30, 0xdf30 }, +/* 0xdf31 */ { false, 0xdf31, 0xdf31 }, +/* 0xdf32 */ { false, 0xdf32, 0xdf32 }, +/* 0xdf33 */ { false, 0xdf33, 0xdf33 }, +/* 0xdf34 */ { false, 0xdf34, 0xdf34 }, +/* 0xdf35 */ { false, 0xdf35, 0xdf35 }, +/* 0xdf36 */ { false, 0xdf36, 0xdf36 }, +/* 0xdf37 */ { false, 0xdf37, 0xdf37 }, +/* 0xdf38 */ { false, 0xdf38, 0xdf38 }, +/* 0xdf39 */ { false, 0xdf39, 0xdf39 }, +/* 0xdf3a */ { false, 0xdf3a, 0xdf3a }, +/* 0xdf3b */ { false, 0xdf3b, 0xdf3b }, +/* 0xdf3c */ { false, 0xdf3c, 0xdf3c }, +/* 0xdf3d */ { false, 0xdf3d, 0xdf3d }, +/* 0xdf3e */ { false, 0xdf3e, 0xdf3e }, +/* 0xdf3f */ { false, 0xdf3f, 0xdf3f }, +/* 0xdf40 */ { false, 0xdf40, 0xdf40 }, +/* 0xdf41 */ { false, 0xdf41, 0xdf41 }, +/* 0xdf42 */ { false, 0xdf42, 0xdf42 }, +/* 0xdf43 */ { false, 0xdf43, 0xdf43 }, +/* 0xdf44 */ { false, 0xdf44, 0xdf44 }, +/* 0xdf45 */ { false, 0xdf45, 0xdf45 }, +/* 0xdf46 */ { false, 0xdf46, 0xdf46 }, +/* 0xdf47 */ { false, 0xdf47, 0xdf47 }, +/* 0xdf48 */ { false, 0xdf48, 0xdf48 }, +/* 0xdf49 */ { false, 0xdf49, 0xdf49 }, +/* 0xdf4a */ { false, 0xdf4a, 0xdf4a }, +/* 0xdf4b */ { false, 0xdf4b, 0xdf4b }, +/* 0xdf4c */ { false, 0xdf4c, 0xdf4c }, +/* 0xdf4d */ { false, 0xdf4d, 0xdf4d }, +/* 0xdf4e */ { false, 0xdf4e, 0xdf4e }, +/* 0xdf4f */ { false, 0xdf4f, 0xdf4f }, +/* 0xdf50 */ { false, 0xdf50, 0xdf50 }, +/* 0xdf51 */ { false, 0xdf51, 0xdf51 }, +/* 0xdf52 */ { false, 0xdf52, 0xdf52 }, +/* 0xdf53 */ { false, 0xdf53, 0xdf53 }, +/* 0xdf54 */ { false, 0xdf54, 0xdf54 }, +/* 0xdf55 */ { false, 0xdf55, 0xdf55 }, +/* 0xdf56 */ { false, 0xdf56, 0xdf56 }, +/* 0xdf57 */ { false, 0xdf57, 0xdf57 }, +/* 0xdf58 */ { false, 0xdf58, 0xdf58 }, +/* 0xdf59 */ { false, 0xdf59, 0xdf59 }, +/* 0xdf5a */ { false, 0xdf5a, 0xdf5a }, +/* 0xdf5b */ { false, 0xdf5b, 0xdf5b }, +/* 0xdf5c */ { false, 0xdf5c, 0xdf5c }, +/* 0xdf5d */ { false, 0xdf5d, 0xdf5d }, +/* 0xdf5e */ { false, 0xdf5e, 0xdf5e }, +/* 0xdf5f */ { false, 0xdf5f, 0xdf5f }, +/* 0xdf60 */ { false, 0xdf60, 0xdf60 }, +/* 0xdf61 */ { false, 0xdf61, 0xdf61 }, +/* 0xdf62 */ { false, 0xdf62, 0xdf62 }, +/* 0xdf63 */ { false, 0xdf63, 0xdf63 }, +/* 0xdf64 */ { false, 0xdf64, 0xdf64 }, +/* 0xdf65 */ { false, 0xdf65, 0xdf65 }, +/* 0xdf66 */ { false, 0xdf66, 0xdf66 }, +/* 0xdf67 */ { false, 0xdf67, 0xdf67 }, +/* 0xdf68 */ { false, 0xdf68, 0xdf68 }, +/* 0xdf69 */ { false, 0xdf69, 0xdf69 }, +/* 0xdf6a */ { false, 0xdf6a, 0xdf6a }, +/* 0xdf6b */ { false, 0xdf6b, 0xdf6b }, +/* 0xdf6c */ { false, 0xdf6c, 0xdf6c }, +/* 0xdf6d */ { false, 0xdf6d, 0xdf6d }, +/* 0xdf6e */ { false, 0xdf6e, 0xdf6e }, +/* 0xdf6f */ { false, 0xdf6f, 0xdf6f }, +/* 0xdf70 */ { false, 0xdf70, 0xdf70 }, +/* 0xdf71 */ { false, 0xdf71, 0xdf71 }, +/* 0xdf72 */ { false, 0xdf72, 0xdf72 }, +/* 0xdf73 */ { false, 0xdf73, 0xdf73 }, +/* 0xdf74 */ { false, 0xdf74, 0xdf74 }, +/* 0xdf75 */ { false, 0xdf75, 0xdf75 }, +/* 0xdf76 */ { false, 0xdf76, 0xdf76 }, +/* 0xdf77 */ { false, 0xdf77, 0xdf77 }, +/* 0xdf78 */ { false, 0xdf78, 0xdf78 }, +/* 0xdf79 */ { false, 0xdf79, 0xdf79 }, +/* 0xdf7a */ { false, 0xdf7a, 0xdf7a }, +/* 0xdf7b */ { false, 0xdf7b, 0xdf7b }, +/* 0xdf7c */ { false, 0xdf7c, 0xdf7c }, +/* 0xdf7d */ { false, 0xdf7d, 0xdf7d }, +/* 0xdf7e */ { false, 0xdf7e, 0xdf7e }, +/* 0xdf7f */ { false, 0xdf7f, 0xdf7f }, +/* 0xdf80 */ { false, 0xdf80, 0xdf80 }, +/* 0xdf81 */ { false, 0xdf81, 0xdf81 }, +/* 0xdf82 */ { false, 0xdf82, 0xdf82 }, +/* 0xdf83 */ { false, 0xdf83, 0xdf83 }, +/* 0xdf84 */ { false, 0xdf84, 0xdf84 }, +/* 0xdf85 */ { false, 0xdf85, 0xdf85 }, +/* 0xdf86 */ { false, 0xdf86, 0xdf86 }, +/* 0xdf87 */ { false, 0xdf87, 0xdf87 }, +/* 0xdf88 */ { false, 0xdf88, 0xdf88 }, +/* 0xdf89 */ { false, 0xdf89, 0xdf89 }, +/* 0xdf8a */ { false, 0xdf8a, 0xdf8a }, +/* 0xdf8b */ { false, 0xdf8b, 0xdf8b }, +/* 0xdf8c */ { false, 0xdf8c, 0xdf8c }, +/* 0xdf8d */ { false, 0xdf8d, 0xdf8d }, +/* 0xdf8e */ { false, 0xdf8e, 0xdf8e }, +/* 0xdf8f */ { false, 0xdf8f, 0xdf8f }, +/* 0xdf90 */ { false, 0xdf90, 0xdf90 }, +/* 0xdf91 */ { false, 0xdf91, 0xdf91 }, +/* 0xdf92 */ { false, 0xdf92, 0xdf92 }, +/* 0xdf93 */ { false, 0xdf93, 0xdf93 }, +/* 0xdf94 */ { false, 0xdf94, 0xdf94 }, +/* 0xdf95 */ { false, 0xdf95, 0xdf95 }, +/* 0xdf96 */ { false, 0xdf96, 0xdf96 }, +/* 0xdf97 */ { false, 0xdf97, 0xdf97 }, +/* 0xdf98 */ { false, 0xdf98, 0xdf98 }, +/* 0xdf99 */ { false, 0xdf99, 0xdf99 }, +/* 0xdf9a */ { false, 0xdf9a, 0xdf9a }, +/* 0xdf9b */ { false, 0xdf9b, 0xdf9b }, +/* 0xdf9c */ { false, 0xdf9c, 0xdf9c }, +/* 0xdf9d */ { false, 0xdf9d, 0xdf9d }, +/* 0xdf9e */ { false, 0xdf9e, 0xdf9e }, +/* 0xdf9f */ { false, 0xdf9f, 0xdf9f }, +/* 0xdfa0 */ { false, 0xdfa0, 0xdfa0 }, +/* 0xdfa1 */ { false, 0xdfa1, 0xdfa1 }, +/* 0xdfa2 */ { false, 0xdfa2, 0xdfa2 }, +/* 0xdfa3 */ { false, 0xdfa3, 0xdfa3 }, +/* 0xdfa4 */ { false, 0xdfa4, 0xdfa4 }, +/* 0xdfa5 */ { false, 0xdfa5, 0xdfa5 }, +/* 0xdfa6 */ { false, 0xdfa6, 0xdfa6 }, +/* 0xdfa7 */ { false, 0xdfa7, 0xdfa7 }, +/* 0xdfa8 */ { false, 0xdfa8, 0xdfa8 }, +/* 0xdfa9 */ { false, 0xdfa9, 0xdfa9 }, +/* 0xdfaa */ { false, 0xdfaa, 0xdfaa }, +/* 0xdfab */ { false, 0xdfab, 0xdfab }, +/* 0xdfac */ { false, 0xdfac, 0xdfac }, +/* 0xdfad */ { false, 0xdfad, 0xdfad }, +/* 0xdfae */ { false, 0xdfae, 0xdfae }, +/* 0xdfaf */ { false, 0xdfaf, 0xdfaf }, +/* 0xdfb0 */ { false, 0xdfb0, 0xdfb0 }, +/* 0xdfb1 */ { false, 0xdfb1, 0xdfb1 }, +/* 0xdfb2 */ { false, 0xdfb2, 0xdfb2 }, +/* 0xdfb3 */ { false, 0xdfb3, 0xdfb3 }, +/* 0xdfb4 */ { false, 0xdfb4, 0xdfb4 }, +/* 0xdfb5 */ { false, 0xdfb5, 0xdfb5 }, +/* 0xdfb6 */ { false, 0xdfb6, 0xdfb6 }, +/* 0xdfb7 */ { false, 0xdfb7, 0xdfb7 }, +/* 0xdfb8 */ { false, 0xdfb8, 0xdfb8 }, +/* 0xdfb9 */ { false, 0xdfb9, 0xdfb9 }, +/* 0xdfba */ { false, 0xdfba, 0xdfba }, +/* 0xdfbb */ { false, 0xdfbb, 0xdfbb }, +/* 0xdfbc */ { false, 0xdfbc, 0xdfbc }, +/* 0xdfbd */ { false, 0xdfbd, 0xdfbd }, +/* 0xdfbe */ { false, 0xdfbe, 0xdfbe }, +/* 0xdfbf */ { false, 0xdfbf, 0xdfbf }, +/* 0xdfc0 */ { false, 0xdfc0, 0xdfc0 }, +/* 0xdfc1 */ { false, 0xdfc1, 0xdfc1 }, +/* 0xdfc2 */ { false, 0xdfc2, 0xdfc2 }, +/* 0xdfc3 */ { false, 0xdfc3, 0xdfc3 }, +/* 0xdfc4 */ { false, 0xdfc4, 0xdfc4 }, +/* 0xdfc5 */ { false, 0xdfc5, 0xdfc5 }, +/* 0xdfc6 */ { false, 0xdfc6, 0xdfc6 }, +/* 0xdfc7 */ { false, 0xdfc7, 0xdfc7 }, +/* 0xdfc8 */ { false, 0xdfc8, 0xdfc8 }, +/* 0xdfc9 */ { false, 0xdfc9, 0xdfc9 }, +/* 0xdfca */ { false, 0xdfca, 0xdfca }, +/* 0xdfcb */ { false, 0xdfcb, 0xdfcb }, +/* 0xdfcc */ { false, 0xdfcc, 0xdfcc }, +/* 0xdfcd */ { false, 0xdfcd, 0xdfcd }, +/* 0xdfce */ { false, 0xdfce, 0xdfce }, +/* 0xdfcf */ { false, 0xdfcf, 0xdfcf }, +/* 0xdfd0 */ { false, 0xdfd0, 0xdfd0 }, +/* 0xdfd1 */ { false, 0xdfd1, 0xdfd1 }, +/* 0xdfd2 */ { false, 0xdfd2, 0xdfd2 }, +/* 0xdfd3 */ { false, 0xdfd3, 0xdfd3 }, +/* 0xdfd4 */ { false, 0xdfd4, 0xdfd4 }, +/* 0xdfd5 */ { false, 0xdfd5, 0xdfd5 }, +/* 0xdfd6 */ { false, 0xdfd6, 0xdfd6 }, +/* 0xdfd7 */ { false, 0xdfd7, 0xdfd7 }, +/* 0xdfd8 */ { false, 0xdfd8, 0xdfd8 }, +/* 0xdfd9 */ { false, 0xdfd9, 0xdfd9 }, +/* 0xdfda */ { false, 0xdfda, 0xdfda }, +/* 0xdfdb */ { false, 0xdfdb, 0xdfdb }, +/* 0xdfdc */ { false, 0xdfdc, 0xdfdc }, +/* 0xdfdd */ { false, 0xdfdd, 0xdfdd }, +/* 0xdfde */ { false, 0xdfde, 0xdfde }, +/* 0xdfdf */ { false, 0xdfdf, 0xdfdf }, +/* 0xdfe0 */ { false, 0xdfe0, 0xdfe0 }, +/* 0xdfe1 */ { false, 0xdfe1, 0xdfe1 }, +/* 0xdfe2 */ { false, 0xdfe2, 0xdfe2 }, +/* 0xdfe3 */ { false, 0xdfe3, 0xdfe3 }, +/* 0xdfe4 */ { false, 0xdfe4, 0xdfe4 }, +/* 0xdfe5 */ { false, 0xdfe5, 0xdfe5 }, +/* 0xdfe6 */ { false, 0xdfe6, 0xdfe6 }, +/* 0xdfe7 */ { false, 0xdfe7, 0xdfe7 }, +/* 0xdfe8 */ { false, 0xdfe8, 0xdfe8 }, +/* 0xdfe9 */ { false, 0xdfe9, 0xdfe9 }, +/* 0xdfea */ { false, 0xdfea, 0xdfea }, +/* 0xdfeb */ { false, 0xdfeb, 0xdfeb }, +/* 0xdfec */ { false, 0xdfec, 0xdfec }, +/* 0xdfed */ { false, 0xdfed, 0xdfed }, +/* 0xdfee */ { false, 0xdfee, 0xdfee }, +/* 0xdfef */ { false, 0xdfef, 0xdfef }, +/* 0xdff0 */ { false, 0xdff0, 0xdff0 }, +/* 0xdff1 */ { false, 0xdff1, 0xdff1 }, +/* 0xdff2 */ { false, 0xdff2, 0xdff2 }, +/* 0xdff3 */ { false, 0xdff3, 0xdff3 }, +/* 0xdff4 */ { false, 0xdff4, 0xdff4 }, +/* 0xdff5 */ { false, 0xdff5, 0xdff5 }, +/* 0xdff6 */ { false, 0xdff6, 0xdff6 }, +/* 0xdff7 */ { false, 0xdff7, 0xdff7 }, +/* 0xdff8 */ { false, 0xdff8, 0xdff8 }, +/* 0xdff9 */ { false, 0xdff9, 0xdff9 }, +/* 0xdffa */ { false, 0xdffa, 0xdffa }, +/* 0xdffb */ { false, 0xdffb, 0xdffb }, +/* 0xdffc */ { false, 0xdffc, 0xdffc }, +/* 0xdffd */ { false, 0xdffd, 0xdffd }, +/* 0xdffe */ { false, 0xdffe, 0xdffe }, +/* 0xdfff */ { false, 0xdfff, 0xdfff }, +/* 0xe000 */ { false, 0xe000, 0xe000 }, +/* 0xe001 */ { false, 0xe001, 0xe001 }, +/* 0xe002 */ { false, 0xe002, 0xe002 }, +/* 0xe003 */ { false, 0xe003, 0xe003 }, +/* 0xe004 */ { false, 0xe004, 0xe004 }, +/* 0xe005 */ { false, 0xe005, 0xe005 }, +/* 0xe006 */ { false, 0xe006, 0xe006 }, +/* 0xe007 */ { false, 0xe007, 0xe007 }, +/* 0xe008 */ { false, 0xe008, 0xe008 }, +/* 0xe009 */ { false, 0xe009, 0xe009 }, +/* 0xe00a */ { false, 0xe00a, 0xe00a }, +/* 0xe00b */ { false, 0xe00b, 0xe00b }, +/* 0xe00c */ { false, 0xe00c, 0xe00c }, +/* 0xe00d */ { false, 0xe00d, 0xe00d }, +/* 0xe00e */ { false, 0xe00e, 0xe00e }, +/* 0xe00f */ { false, 0xe00f, 0xe00f }, +/* 0xe010 */ { false, 0xe010, 0xe010 }, +/* 0xe011 */ { false, 0xe011, 0xe011 }, +/* 0xe012 */ { false, 0xe012, 0xe012 }, +/* 0xe013 */ { false, 0xe013, 0xe013 }, +/* 0xe014 */ { false, 0xe014, 0xe014 }, +/* 0xe015 */ { false, 0xe015, 0xe015 }, +/* 0xe016 */ { false, 0xe016, 0xe016 }, +/* 0xe017 */ { false, 0xe017, 0xe017 }, +/* 0xe018 */ { false, 0xe018, 0xe018 }, +/* 0xe019 */ { false, 0xe019, 0xe019 }, +/* 0xe01a */ { false, 0xe01a, 0xe01a }, +/* 0xe01b */ { false, 0xe01b, 0xe01b }, +/* 0xe01c */ { false, 0xe01c, 0xe01c }, +/* 0xe01d */ { false, 0xe01d, 0xe01d }, +/* 0xe01e */ { false, 0xe01e, 0xe01e }, +/* 0xe01f */ { false, 0xe01f, 0xe01f }, +/* 0xe020 */ { false, 0xe020, 0xe020 }, +/* 0xe021 */ { false, 0xe021, 0xe021 }, +/* 0xe022 */ { false, 0xe022, 0xe022 }, +/* 0xe023 */ { false, 0xe023, 0xe023 }, +/* 0xe024 */ { false, 0xe024, 0xe024 }, +/* 0xe025 */ { false, 0xe025, 0xe025 }, +/* 0xe026 */ { false, 0xe026, 0xe026 }, +/* 0xe027 */ { false, 0xe027, 0xe027 }, +/* 0xe028 */ { false, 0xe028, 0xe028 }, +/* 0xe029 */ { false, 0xe029, 0xe029 }, +/* 0xe02a */ { false, 0xe02a, 0xe02a }, +/* 0xe02b */ { false, 0xe02b, 0xe02b }, +/* 0xe02c */ { false, 0xe02c, 0xe02c }, +/* 0xe02d */ { false, 0xe02d, 0xe02d }, +/* 0xe02e */ { false, 0xe02e, 0xe02e }, +/* 0xe02f */ { false, 0xe02f, 0xe02f }, +/* 0xe030 */ { false, 0xe030, 0xe030 }, +/* 0xe031 */ { false, 0xe031, 0xe031 }, +/* 0xe032 */ { false, 0xe032, 0xe032 }, +/* 0xe033 */ { false, 0xe033, 0xe033 }, +/* 0xe034 */ { false, 0xe034, 0xe034 }, +/* 0xe035 */ { false, 0xe035, 0xe035 }, +/* 0xe036 */ { false, 0xe036, 0xe036 }, +/* 0xe037 */ { false, 0xe037, 0xe037 }, +/* 0xe038 */ { false, 0xe038, 0xe038 }, +/* 0xe039 */ { false, 0xe039, 0xe039 }, +/* 0xe03a */ { false, 0xe03a, 0xe03a }, +/* 0xe03b */ { false, 0xe03b, 0xe03b }, +/* 0xe03c */ { false, 0xe03c, 0xe03c }, +/* 0xe03d */ { false, 0xe03d, 0xe03d }, +/* 0xe03e */ { false, 0xe03e, 0xe03e }, +/* 0xe03f */ { false, 0xe03f, 0xe03f }, +/* 0xe040 */ { false, 0xe040, 0xe040 }, +/* 0xe041 */ { false, 0xe041, 0xe041 }, +/* 0xe042 */ { false, 0xe042, 0xe042 }, +/* 0xe043 */ { false, 0xe043, 0xe043 }, +/* 0xe044 */ { false, 0xe044, 0xe044 }, +/* 0xe045 */ { false, 0xe045, 0xe045 }, +/* 0xe046 */ { false, 0xe046, 0xe046 }, +/* 0xe047 */ { false, 0xe047, 0xe047 }, +/* 0xe048 */ { false, 0xe048, 0xe048 }, +/* 0xe049 */ { false, 0xe049, 0xe049 }, +/* 0xe04a */ { false, 0xe04a, 0xe04a }, +/* 0xe04b */ { false, 0xe04b, 0xe04b }, +/* 0xe04c */ { false, 0xe04c, 0xe04c }, +/* 0xe04d */ { false, 0xe04d, 0xe04d }, +/* 0xe04e */ { false, 0xe04e, 0xe04e }, +/* 0xe04f */ { false, 0xe04f, 0xe04f }, +/* 0xe050 */ { false, 0xe050, 0xe050 }, +/* 0xe051 */ { false, 0xe051, 0xe051 }, +/* 0xe052 */ { false, 0xe052, 0xe052 }, +/* 0xe053 */ { false, 0xe053, 0xe053 }, +/* 0xe054 */ { false, 0xe054, 0xe054 }, +/* 0xe055 */ { false, 0xe055, 0xe055 }, +/* 0xe056 */ { false, 0xe056, 0xe056 }, +/* 0xe057 */ { false, 0xe057, 0xe057 }, +/* 0xe058 */ { false, 0xe058, 0xe058 }, +/* 0xe059 */ { false, 0xe059, 0xe059 }, +/* 0xe05a */ { false, 0xe05a, 0xe05a }, +/* 0xe05b */ { false, 0xe05b, 0xe05b }, +/* 0xe05c */ { false, 0xe05c, 0xe05c }, +/* 0xe05d */ { false, 0xe05d, 0xe05d }, +/* 0xe05e */ { false, 0xe05e, 0xe05e }, +/* 0xe05f */ { false, 0xe05f, 0xe05f }, +/* 0xe060 */ { false, 0xe060, 0xe060 }, +/* 0xe061 */ { false, 0xe061, 0xe061 }, +/* 0xe062 */ { false, 0xe062, 0xe062 }, +/* 0xe063 */ { false, 0xe063, 0xe063 }, +/* 0xe064 */ { false, 0xe064, 0xe064 }, +/* 0xe065 */ { false, 0xe065, 0xe065 }, +/* 0xe066 */ { false, 0xe066, 0xe066 }, +/* 0xe067 */ { false, 0xe067, 0xe067 }, +/* 0xe068 */ { false, 0xe068, 0xe068 }, +/* 0xe069 */ { false, 0xe069, 0xe069 }, +/* 0xe06a */ { false, 0xe06a, 0xe06a }, +/* 0xe06b */ { false, 0xe06b, 0xe06b }, +/* 0xe06c */ { false, 0xe06c, 0xe06c }, +/* 0xe06d */ { false, 0xe06d, 0xe06d }, +/* 0xe06e */ { false, 0xe06e, 0xe06e }, +/* 0xe06f */ { false, 0xe06f, 0xe06f }, +/* 0xe070 */ { false, 0xe070, 0xe070 }, +/* 0xe071 */ { false, 0xe071, 0xe071 }, +/* 0xe072 */ { false, 0xe072, 0xe072 }, +/* 0xe073 */ { false, 0xe073, 0xe073 }, +/* 0xe074 */ { false, 0xe074, 0xe074 }, +/* 0xe075 */ { false, 0xe075, 0xe075 }, +/* 0xe076 */ { false, 0xe076, 0xe076 }, +/* 0xe077 */ { false, 0xe077, 0xe077 }, +/* 0xe078 */ { false, 0xe078, 0xe078 }, +/* 0xe079 */ { false, 0xe079, 0xe079 }, +/* 0xe07a */ { false, 0xe07a, 0xe07a }, +/* 0xe07b */ { false, 0xe07b, 0xe07b }, +/* 0xe07c */ { false, 0xe07c, 0xe07c }, +/* 0xe07d */ { false, 0xe07d, 0xe07d }, +/* 0xe07e */ { false, 0xe07e, 0xe07e }, +/* 0xe07f */ { false, 0xe07f, 0xe07f }, +/* 0xe080 */ { false, 0xe080, 0xe080 }, +/* 0xe081 */ { false, 0xe081, 0xe081 }, +/* 0xe082 */ { false, 0xe082, 0xe082 }, +/* 0xe083 */ { false, 0xe083, 0xe083 }, +/* 0xe084 */ { false, 0xe084, 0xe084 }, +/* 0xe085 */ { false, 0xe085, 0xe085 }, +/* 0xe086 */ { false, 0xe086, 0xe086 }, +/* 0xe087 */ { false, 0xe087, 0xe087 }, +/* 0xe088 */ { false, 0xe088, 0xe088 }, +/* 0xe089 */ { false, 0xe089, 0xe089 }, +/* 0xe08a */ { false, 0xe08a, 0xe08a }, +/* 0xe08b */ { false, 0xe08b, 0xe08b }, +/* 0xe08c */ { false, 0xe08c, 0xe08c }, +/* 0xe08d */ { false, 0xe08d, 0xe08d }, +/* 0xe08e */ { false, 0xe08e, 0xe08e }, +/* 0xe08f */ { false, 0xe08f, 0xe08f }, +/* 0xe090 */ { false, 0xe090, 0xe090 }, +/* 0xe091 */ { false, 0xe091, 0xe091 }, +/* 0xe092 */ { false, 0xe092, 0xe092 }, +/* 0xe093 */ { false, 0xe093, 0xe093 }, +/* 0xe094 */ { false, 0xe094, 0xe094 }, +/* 0xe095 */ { false, 0xe095, 0xe095 }, +/* 0xe096 */ { false, 0xe096, 0xe096 }, +/* 0xe097 */ { false, 0xe097, 0xe097 }, +/* 0xe098 */ { false, 0xe098, 0xe098 }, +/* 0xe099 */ { false, 0xe099, 0xe099 }, +/* 0xe09a */ { false, 0xe09a, 0xe09a }, +/* 0xe09b */ { false, 0xe09b, 0xe09b }, +/* 0xe09c */ { false, 0xe09c, 0xe09c }, +/* 0xe09d */ { false, 0xe09d, 0xe09d }, +/* 0xe09e */ { false, 0xe09e, 0xe09e }, +/* 0xe09f */ { false, 0xe09f, 0xe09f }, +/* 0xe0a0 */ { false, 0xe0a0, 0xe0a0 }, +/* 0xe0a1 */ { false, 0xe0a1, 0xe0a1 }, +/* 0xe0a2 */ { false, 0xe0a2, 0xe0a2 }, +/* 0xe0a3 */ { false, 0xe0a3, 0xe0a3 }, +/* 0xe0a4 */ { false, 0xe0a4, 0xe0a4 }, +/* 0xe0a5 */ { false, 0xe0a5, 0xe0a5 }, +/* 0xe0a6 */ { false, 0xe0a6, 0xe0a6 }, +/* 0xe0a7 */ { false, 0xe0a7, 0xe0a7 }, +/* 0xe0a8 */ { false, 0xe0a8, 0xe0a8 }, +/* 0xe0a9 */ { false, 0xe0a9, 0xe0a9 }, +/* 0xe0aa */ { false, 0xe0aa, 0xe0aa }, +/* 0xe0ab */ { false, 0xe0ab, 0xe0ab }, +/* 0xe0ac */ { false, 0xe0ac, 0xe0ac }, +/* 0xe0ad */ { false, 0xe0ad, 0xe0ad }, +/* 0xe0ae */ { false, 0xe0ae, 0xe0ae }, +/* 0xe0af */ { false, 0xe0af, 0xe0af }, +/* 0xe0b0 */ { false, 0xe0b0, 0xe0b0 }, +/* 0xe0b1 */ { false, 0xe0b1, 0xe0b1 }, +/* 0xe0b2 */ { false, 0xe0b2, 0xe0b2 }, +/* 0xe0b3 */ { false, 0xe0b3, 0xe0b3 }, +/* 0xe0b4 */ { false, 0xe0b4, 0xe0b4 }, +/* 0xe0b5 */ { false, 0xe0b5, 0xe0b5 }, +/* 0xe0b6 */ { false, 0xe0b6, 0xe0b6 }, +/* 0xe0b7 */ { false, 0xe0b7, 0xe0b7 }, +/* 0xe0b8 */ { false, 0xe0b8, 0xe0b8 }, +/* 0xe0b9 */ { false, 0xe0b9, 0xe0b9 }, +/* 0xe0ba */ { false, 0xe0ba, 0xe0ba }, +/* 0xe0bb */ { false, 0xe0bb, 0xe0bb }, +/* 0xe0bc */ { false, 0xe0bc, 0xe0bc }, +/* 0xe0bd */ { false, 0xe0bd, 0xe0bd }, +/* 0xe0be */ { false, 0xe0be, 0xe0be }, +/* 0xe0bf */ { false, 0xe0bf, 0xe0bf }, +/* 0xe0c0 */ { false, 0xe0c0, 0xe0c0 }, +/* 0xe0c1 */ { false, 0xe0c1, 0xe0c1 }, +/* 0xe0c2 */ { false, 0xe0c2, 0xe0c2 }, +/* 0xe0c3 */ { false, 0xe0c3, 0xe0c3 }, +/* 0xe0c4 */ { false, 0xe0c4, 0xe0c4 }, +/* 0xe0c5 */ { false, 0xe0c5, 0xe0c5 }, +/* 0xe0c6 */ { false, 0xe0c6, 0xe0c6 }, +/* 0xe0c7 */ { false, 0xe0c7, 0xe0c7 }, +/* 0xe0c8 */ { false, 0xe0c8, 0xe0c8 }, +/* 0xe0c9 */ { false, 0xe0c9, 0xe0c9 }, +/* 0xe0ca */ { false, 0xe0ca, 0xe0ca }, +/* 0xe0cb */ { false, 0xe0cb, 0xe0cb }, +/* 0xe0cc */ { false, 0xe0cc, 0xe0cc }, +/* 0xe0cd */ { false, 0xe0cd, 0xe0cd }, +/* 0xe0ce */ { false, 0xe0ce, 0xe0ce }, +/* 0xe0cf */ { false, 0xe0cf, 0xe0cf }, +/* 0xe0d0 */ { false, 0xe0d0, 0xe0d0 }, +/* 0xe0d1 */ { false, 0xe0d1, 0xe0d1 }, +/* 0xe0d2 */ { false, 0xe0d2, 0xe0d2 }, +/* 0xe0d3 */ { false, 0xe0d3, 0xe0d3 }, +/* 0xe0d4 */ { false, 0xe0d4, 0xe0d4 }, +/* 0xe0d5 */ { false, 0xe0d5, 0xe0d5 }, +/* 0xe0d6 */ { false, 0xe0d6, 0xe0d6 }, +/* 0xe0d7 */ { false, 0xe0d7, 0xe0d7 }, +/* 0xe0d8 */ { false, 0xe0d8, 0xe0d8 }, +/* 0xe0d9 */ { false, 0xe0d9, 0xe0d9 }, +/* 0xe0da */ { false, 0xe0da, 0xe0da }, +/* 0xe0db */ { false, 0xe0db, 0xe0db }, +/* 0xe0dc */ { false, 0xe0dc, 0xe0dc }, +/* 0xe0dd */ { false, 0xe0dd, 0xe0dd }, +/* 0xe0de */ { false, 0xe0de, 0xe0de }, +/* 0xe0df */ { false, 0xe0df, 0xe0df }, +/* 0xe0e0 */ { false, 0xe0e0, 0xe0e0 }, +/* 0xe0e1 */ { false, 0xe0e1, 0xe0e1 }, +/* 0xe0e2 */ { false, 0xe0e2, 0xe0e2 }, +/* 0xe0e3 */ { false, 0xe0e3, 0xe0e3 }, +/* 0xe0e4 */ { false, 0xe0e4, 0xe0e4 }, +/* 0xe0e5 */ { false, 0xe0e5, 0xe0e5 }, +/* 0xe0e6 */ { false, 0xe0e6, 0xe0e6 }, +/* 0xe0e7 */ { false, 0xe0e7, 0xe0e7 }, +/* 0xe0e8 */ { false, 0xe0e8, 0xe0e8 }, +/* 0xe0e9 */ { false, 0xe0e9, 0xe0e9 }, +/* 0xe0ea */ { false, 0xe0ea, 0xe0ea }, +/* 0xe0eb */ { false, 0xe0eb, 0xe0eb }, +/* 0xe0ec */ { false, 0xe0ec, 0xe0ec }, +/* 0xe0ed */ { false, 0xe0ed, 0xe0ed }, +/* 0xe0ee */ { false, 0xe0ee, 0xe0ee }, +/* 0xe0ef */ { false, 0xe0ef, 0xe0ef }, +/* 0xe0f0 */ { false, 0xe0f0, 0xe0f0 }, +/* 0xe0f1 */ { false, 0xe0f1, 0xe0f1 }, +/* 0xe0f2 */ { false, 0xe0f2, 0xe0f2 }, +/* 0xe0f3 */ { false, 0xe0f3, 0xe0f3 }, +/* 0xe0f4 */ { false, 0xe0f4, 0xe0f4 }, +/* 0xe0f5 */ { false, 0xe0f5, 0xe0f5 }, +/* 0xe0f6 */ { false, 0xe0f6, 0xe0f6 }, +/* 0xe0f7 */ { false, 0xe0f7, 0xe0f7 }, +/* 0xe0f8 */ { false, 0xe0f8, 0xe0f8 }, +/* 0xe0f9 */ { false, 0xe0f9, 0xe0f9 }, +/* 0xe0fa */ { false, 0xe0fa, 0xe0fa }, +/* 0xe0fb */ { false, 0xe0fb, 0xe0fb }, +/* 0xe0fc */ { false, 0xe0fc, 0xe0fc }, +/* 0xe0fd */ { false, 0xe0fd, 0xe0fd }, +/* 0xe0fe */ { false, 0xe0fe, 0xe0fe }, +/* 0xe0ff */ { false, 0xe0ff, 0xe0ff }, +/* 0xe100 */ { false, 0xe100, 0xe100 }, +/* 0xe101 */ { false, 0xe101, 0xe101 }, +/* 0xe102 */ { false, 0xe102, 0xe102 }, +/* 0xe103 */ { false, 0xe103, 0xe103 }, +/* 0xe104 */ { false, 0xe104, 0xe104 }, +/* 0xe105 */ { false, 0xe105, 0xe105 }, +/* 0xe106 */ { false, 0xe106, 0xe106 }, +/* 0xe107 */ { false, 0xe107, 0xe107 }, +/* 0xe108 */ { false, 0xe108, 0xe108 }, +/* 0xe109 */ { false, 0xe109, 0xe109 }, +/* 0xe10a */ { false, 0xe10a, 0xe10a }, +/* 0xe10b */ { false, 0xe10b, 0xe10b }, +/* 0xe10c */ { false, 0xe10c, 0xe10c }, +/* 0xe10d */ { false, 0xe10d, 0xe10d }, +/* 0xe10e */ { false, 0xe10e, 0xe10e }, +/* 0xe10f */ { false, 0xe10f, 0xe10f }, +/* 0xe110 */ { false, 0xe110, 0xe110 }, +/* 0xe111 */ { false, 0xe111, 0xe111 }, +/* 0xe112 */ { false, 0xe112, 0xe112 }, +/* 0xe113 */ { false, 0xe113, 0xe113 }, +/* 0xe114 */ { false, 0xe114, 0xe114 }, +/* 0xe115 */ { false, 0xe115, 0xe115 }, +/* 0xe116 */ { false, 0xe116, 0xe116 }, +/* 0xe117 */ { false, 0xe117, 0xe117 }, +/* 0xe118 */ { false, 0xe118, 0xe118 }, +/* 0xe119 */ { false, 0xe119, 0xe119 }, +/* 0xe11a */ { false, 0xe11a, 0xe11a }, +/* 0xe11b */ { false, 0xe11b, 0xe11b }, +/* 0xe11c */ { false, 0xe11c, 0xe11c }, +/* 0xe11d */ { false, 0xe11d, 0xe11d }, +/* 0xe11e */ { false, 0xe11e, 0xe11e }, +/* 0xe11f */ { false, 0xe11f, 0xe11f }, +/* 0xe120 */ { false, 0xe120, 0xe120 }, +/* 0xe121 */ { false, 0xe121, 0xe121 }, +/* 0xe122 */ { false, 0xe122, 0xe122 }, +/* 0xe123 */ { false, 0xe123, 0xe123 }, +/* 0xe124 */ { false, 0xe124, 0xe124 }, +/* 0xe125 */ { false, 0xe125, 0xe125 }, +/* 0xe126 */ { false, 0xe126, 0xe126 }, +/* 0xe127 */ { false, 0xe127, 0xe127 }, +/* 0xe128 */ { false, 0xe128, 0xe128 }, +/* 0xe129 */ { false, 0xe129, 0xe129 }, +/* 0xe12a */ { false, 0xe12a, 0xe12a }, +/* 0xe12b */ { false, 0xe12b, 0xe12b }, +/* 0xe12c */ { false, 0xe12c, 0xe12c }, +/* 0xe12d */ { false, 0xe12d, 0xe12d }, +/* 0xe12e */ { false, 0xe12e, 0xe12e }, +/* 0xe12f */ { false, 0xe12f, 0xe12f }, +/* 0xe130 */ { false, 0xe130, 0xe130 }, +/* 0xe131 */ { false, 0xe131, 0xe131 }, +/* 0xe132 */ { false, 0xe132, 0xe132 }, +/* 0xe133 */ { false, 0xe133, 0xe133 }, +/* 0xe134 */ { false, 0xe134, 0xe134 }, +/* 0xe135 */ { false, 0xe135, 0xe135 }, +/* 0xe136 */ { false, 0xe136, 0xe136 }, +/* 0xe137 */ { false, 0xe137, 0xe137 }, +/* 0xe138 */ { false, 0xe138, 0xe138 }, +/* 0xe139 */ { false, 0xe139, 0xe139 }, +/* 0xe13a */ { false, 0xe13a, 0xe13a }, +/* 0xe13b */ { false, 0xe13b, 0xe13b }, +/* 0xe13c */ { false, 0xe13c, 0xe13c }, +/* 0xe13d */ { false, 0xe13d, 0xe13d }, +/* 0xe13e */ { false, 0xe13e, 0xe13e }, +/* 0xe13f */ { false, 0xe13f, 0xe13f }, +/* 0xe140 */ { false, 0xe140, 0xe140 }, +/* 0xe141 */ { false, 0xe141, 0xe141 }, +/* 0xe142 */ { false, 0xe142, 0xe142 }, +/* 0xe143 */ { false, 0xe143, 0xe143 }, +/* 0xe144 */ { false, 0xe144, 0xe144 }, +/* 0xe145 */ { false, 0xe145, 0xe145 }, +/* 0xe146 */ { false, 0xe146, 0xe146 }, +/* 0xe147 */ { false, 0xe147, 0xe147 }, +/* 0xe148 */ { false, 0xe148, 0xe148 }, +/* 0xe149 */ { false, 0xe149, 0xe149 }, +/* 0xe14a */ { false, 0xe14a, 0xe14a }, +/* 0xe14b */ { false, 0xe14b, 0xe14b }, +/* 0xe14c */ { false, 0xe14c, 0xe14c }, +/* 0xe14d */ { false, 0xe14d, 0xe14d }, +/* 0xe14e */ { false, 0xe14e, 0xe14e }, +/* 0xe14f */ { false, 0xe14f, 0xe14f }, +/* 0xe150 */ { false, 0xe150, 0xe150 }, +/* 0xe151 */ { false, 0xe151, 0xe151 }, +/* 0xe152 */ { false, 0xe152, 0xe152 }, +/* 0xe153 */ { false, 0xe153, 0xe153 }, +/* 0xe154 */ { false, 0xe154, 0xe154 }, +/* 0xe155 */ { false, 0xe155, 0xe155 }, +/* 0xe156 */ { false, 0xe156, 0xe156 }, +/* 0xe157 */ { false, 0xe157, 0xe157 }, +/* 0xe158 */ { false, 0xe158, 0xe158 }, +/* 0xe159 */ { false, 0xe159, 0xe159 }, +/* 0xe15a */ { false, 0xe15a, 0xe15a }, +/* 0xe15b */ { false, 0xe15b, 0xe15b }, +/* 0xe15c */ { false, 0xe15c, 0xe15c }, +/* 0xe15d */ { false, 0xe15d, 0xe15d }, +/* 0xe15e */ { false, 0xe15e, 0xe15e }, +/* 0xe15f */ { false, 0xe15f, 0xe15f }, +/* 0xe160 */ { false, 0xe160, 0xe160 }, +/* 0xe161 */ { false, 0xe161, 0xe161 }, +/* 0xe162 */ { false, 0xe162, 0xe162 }, +/* 0xe163 */ { false, 0xe163, 0xe163 }, +/* 0xe164 */ { false, 0xe164, 0xe164 }, +/* 0xe165 */ { false, 0xe165, 0xe165 }, +/* 0xe166 */ { false, 0xe166, 0xe166 }, +/* 0xe167 */ { false, 0xe167, 0xe167 }, +/* 0xe168 */ { false, 0xe168, 0xe168 }, +/* 0xe169 */ { false, 0xe169, 0xe169 }, +/* 0xe16a */ { false, 0xe16a, 0xe16a }, +/* 0xe16b */ { false, 0xe16b, 0xe16b }, +/* 0xe16c */ { false, 0xe16c, 0xe16c }, +/* 0xe16d */ { false, 0xe16d, 0xe16d }, +/* 0xe16e */ { false, 0xe16e, 0xe16e }, +/* 0xe16f */ { false, 0xe16f, 0xe16f }, +/* 0xe170 */ { false, 0xe170, 0xe170 }, +/* 0xe171 */ { false, 0xe171, 0xe171 }, +/* 0xe172 */ { false, 0xe172, 0xe172 }, +/* 0xe173 */ { false, 0xe173, 0xe173 }, +/* 0xe174 */ { false, 0xe174, 0xe174 }, +/* 0xe175 */ { false, 0xe175, 0xe175 }, +/* 0xe176 */ { false, 0xe176, 0xe176 }, +/* 0xe177 */ { false, 0xe177, 0xe177 }, +/* 0xe178 */ { false, 0xe178, 0xe178 }, +/* 0xe179 */ { false, 0xe179, 0xe179 }, +/* 0xe17a */ { false, 0xe17a, 0xe17a }, +/* 0xe17b */ { false, 0xe17b, 0xe17b }, +/* 0xe17c */ { false, 0xe17c, 0xe17c }, +/* 0xe17d */ { false, 0xe17d, 0xe17d }, +/* 0xe17e */ { false, 0xe17e, 0xe17e }, +/* 0xe17f */ { false, 0xe17f, 0xe17f }, +/* 0xe180 */ { false, 0xe180, 0xe180 }, +/* 0xe181 */ { false, 0xe181, 0xe181 }, +/* 0xe182 */ { false, 0xe182, 0xe182 }, +/* 0xe183 */ { false, 0xe183, 0xe183 }, +/* 0xe184 */ { false, 0xe184, 0xe184 }, +/* 0xe185 */ { false, 0xe185, 0xe185 }, +/* 0xe186 */ { false, 0xe186, 0xe186 }, +/* 0xe187 */ { false, 0xe187, 0xe187 }, +/* 0xe188 */ { false, 0xe188, 0xe188 }, +/* 0xe189 */ { false, 0xe189, 0xe189 }, +/* 0xe18a */ { false, 0xe18a, 0xe18a }, +/* 0xe18b */ { false, 0xe18b, 0xe18b }, +/* 0xe18c */ { false, 0xe18c, 0xe18c }, +/* 0xe18d */ { false, 0xe18d, 0xe18d }, +/* 0xe18e */ { false, 0xe18e, 0xe18e }, +/* 0xe18f */ { false, 0xe18f, 0xe18f }, +/* 0xe190 */ { false, 0xe190, 0xe190 }, +/* 0xe191 */ { false, 0xe191, 0xe191 }, +/* 0xe192 */ { false, 0xe192, 0xe192 }, +/* 0xe193 */ { false, 0xe193, 0xe193 }, +/* 0xe194 */ { false, 0xe194, 0xe194 }, +/* 0xe195 */ { false, 0xe195, 0xe195 }, +/* 0xe196 */ { false, 0xe196, 0xe196 }, +/* 0xe197 */ { false, 0xe197, 0xe197 }, +/* 0xe198 */ { false, 0xe198, 0xe198 }, +/* 0xe199 */ { false, 0xe199, 0xe199 }, +/* 0xe19a */ { false, 0xe19a, 0xe19a }, +/* 0xe19b */ { false, 0xe19b, 0xe19b }, +/* 0xe19c */ { false, 0xe19c, 0xe19c }, +/* 0xe19d */ { false, 0xe19d, 0xe19d }, +/* 0xe19e */ { false, 0xe19e, 0xe19e }, +/* 0xe19f */ { false, 0xe19f, 0xe19f }, +/* 0xe1a0 */ { false, 0xe1a0, 0xe1a0 }, +/* 0xe1a1 */ { false, 0xe1a1, 0xe1a1 }, +/* 0xe1a2 */ { false, 0xe1a2, 0xe1a2 }, +/* 0xe1a3 */ { false, 0xe1a3, 0xe1a3 }, +/* 0xe1a4 */ { false, 0xe1a4, 0xe1a4 }, +/* 0xe1a5 */ { false, 0xe1a5, 0xe1a5 }, +/* 0xe1a6 */ { false, 0xe1a6, 0xe1a6 }, +/* 0xe1a7 */ { false, 0xe1a7, 0xe1a7 }, +/* 0xe1a8 */ { false, 0xe1a8, 0xe1a8 }, +/* 0xe1a9 */ { false, 0xe1a9, 0xe1a9 }, +/* 0xe1aa */ { false, 0xe1aa, 0xe1aa }, +/* 0xe1ab */ { false, 0xe1ab, 0xe1ab }, +/* 0xe1ac */ { false, 0xe1ac, 0xe1ac }, +/* 0xe1ad */ { false, 0xe1ad, 0xe1ad }, +/* 0xe1ae */ { false, 0xe1ae, 0xe1ae }, +/* 0xe1af */ { false, 0xe1af, 0xe1af }, +/* 0xe1b0 */ { false, 0xe1b0, 0xe1b0 }, +/* 0xe1b1 */ { false, 0xe1b1, 0xe1b1 }, +/* 0xe1b2 */ { false, 0xe1b2, 0xe1b2 }, +/* 0xe1b3 */ { false, 0xe1b3, 0xe1b3 }, +/* 0xe1b4 */ { false, 0xe1b4, 0xe1b4 }, +/* 0xe1b5 */ { false, 0xe1b5, 0xe1b5 }, +/* 0xe1b6 */ { false, 0xe1b6, 0xe1b6 }, +/* 0xe1b7 */ { false, 0xe1b7, 0xe1b7 }, +/* 0xe1b8 */ { false, 0xe1b8, 0xe1b8 }, +/* 0xe1b9 */ { false, 0xe1b9, 0xe1b9 }, +/* 0xe1ba */ { false, 0xe1ba, 0xe1ba }, +/* 0xe1bb */ { false, 0xe1bb, 0xe1bb }, +/* 0xe1bc */ { false, 0xe1bc, 0xe1bc }, +/* 0xe1bd */ { false, 0xe1bd, 0xe1bd }, +/* 0xe1be */ { false, 0xe1be, 0xe1be }, +/* 0xe1bf */ { false, 0xe1bf, 0xe1bf }, +/* 0xe1c0 */ { false, 0xe1c0, 0xe1c0 }, +/* 0xe1c1 */ { false, 0xe1c1, 0xe1c1 }, +/* 0xe1c2 */ { false, 0xe1c2, 0xe1c2 }, +/* 0xe1c3 */ { false, 0xe1c3, 0xe1c3 }, +/* 0xe1c4 */ { false, 0xe1c4, 0xe1c4 }, +/* 0xe1c5 */ { false, 0xe1c5, 0xe1c5 }, +/* 0xe1c6 */ { false, 0xe1c6, 0xe1c6 }, +/* 0xe1c7 */ { false, 0xe1c7, 0xe1c7 }, +/* 0xe1c8 */ { false, 0xe1c8, 0xe1c8 }, +/* 0xe1c9 */ { false, 0xe1c9, 0xe1c9 }, +/* 0xe1ca */ { false, 0xe1ca, 0xe1ca }, +/* 0xe1cb */ { false, 0xe1cb, 0xe1cb }, +/* 0xe1cc */ { false, 0xe1cc, 0xe1cc }, +/* 0xe1cd */ { false, 0xe1cd, 0xe1cd }, +/* 0xe1ce */ { false, 0xe1ce, 0xe1ce }, +/* 0xe1cf */ { false, 0xe1cf, 0xe1cf }, +/* 0xe1d0 */ { false, 0xe1d0, 0xe1d0 }, +/* 0xe1d1 */ { false, 0xe1d1, 0xe1d1 }, +/* 0xe1d2 */ { false, 0xe1d2, 0xe1d2 }, +/* 0xe1d3 */ { false, 0xe1d3, 0xe1d3 }, +/* 0xe1d4 */ { false, 0xe1d4, 0xe1d4 }, +/* 0xe1d5 */ { false, 0xe1d5, 0xe1d5 }, +/* 0xe1d6 */ { false, 0xe1d6, 0xe1d6 }, +/* 0xe1d7 */ { false, 0xe1d7, 0xe1d7 }, +/* 0xe1d8 */ { false, 0xe1d8, 0xe1d8 }, +/* 0xe1d9 */ { false, 0xe1d9, 0xe1d9 }, +/* 0xe1da */ { false, 0xe1da, 0xe1da }, +/* 0xe1db */ { false, 0xe1db, 0xe1db }, +/* 0xe1dc */ { false, 0xe1dc, 0xe1dc }, +/* 0xe1dd */ { false, 0xe1dd, 0xe1dd }, +/* 0xe1de */ { false, 0xe1de, 0xe1de }, +/* 0xe1df */ { false, 0xe1df, 0xe1df }, +/* 0xe1e0 */ { false, 0xe1e0, 0xe1e0 }, +/* 0xe1e1 */ { false, 0xe1e1, 0xe1e1 }, +/* 0xe1e2 */ { false, 0xe1e2, 0xe1e2 }, +/* 0xe1e3 */ { false, 0xe1e3, 0xe1e3 }, +/* 0xe1e4 */ { false, 0xe1e4, 0xe1e4 }, +/* 0xe1e5 */ { false, 0xe1e5, 0xe1e5 }, +/* 0xe1e6 */ { false, 0xe1e6, 0xe1e6 }, +/* 0xe1e7 */ { false, 0xe1e7, 0xe1e7 }, +/* 0xe1e8 */ { false, 0xe1e8, 0xe1e8 }, +/* 0xe1e9 */ { false, 0xe1e9, 0xe1e9 }, +/* 0xe1ea */ { false, 0xe1ea, 0xe1ea }, +/* 0xe1eb */ { false, 0xe1eb, 0xe1eb }, +/* 0xe1ec */ { false, 0xe1ec, 0xe1ec }, +/* 0xe1ed */ { false, 0xe1ed, 0xe1ed }, +/* 0xe1ee */ { false, 0xe1ee, 0xe1ee }, +/* 0xe1ef */ { false, 0xe1ef, 0xe1ef }, +/* 0xe1f0 */ { false, 0xe1f0, 0xe1f0 }, +/* 0xe1f1 */ { false, 0xe1f1, 0xe1f1 }, +/* 0xe1f2 */ { false, 0xe1f2, 0xe1f2 }, +/* 0xe1f3 */ { false, 0xe1f3, 0xe1f3 }, +/* 0xe1f4 */ { false, 0xe1f4, 0xe1f4 }, +/* 0xe1f5 */ { false, 0xe1f5, 0xe1f5 }, +/* 0xe1f6 */ { false, 0xe1f6, 0xe1f6 }, +/* 0xe1f7 */ { false, 0xe1f7, 0xe1f7 }, +/* 0xe1f8 */ { false, 0xe1f8, 0xe1f8 }, +/* 0xe1f9 */ { false, 0xe1f9, 0xe1f9 }, +/* 0xe1fa */ { false, 0xe1fa, 0xe1fa }, +/* 0xe1fb */ { false, 0xe1fb, 0xe1fb }, +/* 0xe1fc */ { false, 0xe1fc, 0xe1fc }, +/* 0xe1fd */ { false, 0xe1fd, 0xe1fd }, +/* 0xe1fe */ { false, 0xe1fe, 0xe1fe }, +/* 0xe1ff */ { false, 0xe1ff, 0xe1ff }, +/* 0xe200 */ { false, 0xe200, 0xe200 }, +/* 0xe201 */ { false, 0xe201, 0xe201 }, +/* 0xe202 */ { false, 0xe202, 0xe202 }, +/* 0xe203 */ { false, 0xe203, 0xe203 }, +/* 0xe204 */ { false, 0xe204, 0xe204 }, +/* 0xe205 */ { false, 0xe205, 0xe205 }, +/* 0xe206 */ { false, 0xe206, 0xe206 }, +/* 0xe207 */ { false, 0xe207, 0xe207 }, +/* 0xe208 */ { false, 0xe208, 0xe208 }, +/* 0xe209 */ { false, 0xe209, 0xe209 }, +/* 0xe20a */ { false, 0xe20a, 0xe20a }, +/* 0xe20b */ { false, 0xe20b, 0xe20b }, +/* 0xe20c */ { false, 0xe20c, 0xe20c }, +/* 0xe20d */ { false, 0xe20d, 0xe20d }, +/* 0xe20e */ { false, 0xe20e, 0xe20e }, +/* 0xe20f */ { false, 0xe20f, 0xe20f }, +/* 0xe210 */ { false, 0xe210, 0xe210 }, +/* 0xe211 */ { false, 0xe211, 0xe211 }, +/* 0xe212 */ { false, 0xe212, 0xe212 }, +/* 0xe213 */ { false, 0xe213, 0xe213 }, +/* 0xe214 */ { false, 0xe214, 0xe214 }, +/* 0xe215 */ { false, 0xe215, 0xe215 }, +/* 0xe216 */ { false, 0xe216, 0xe216 }, +/* 0xe217 */ { false, 0xe217, 0xe217 }, +/* 0xe218 */ { false, 0xe218, 0xe218 }, +/* 0xe219 */ { false, 0xe219, 0xe219 }, +/* 0xe21a */ { false, 0xe21a, 0xe21a }, +/* 0xe21b */ { false, 0xe21b, 0xe21b }, +/* 0xe21c */ { false, 0xe21c, 0xe21c }, +/* 0xe21d */ { false, 0xe21d, 0xe21d }, +/* 0xe21e */ { false, 0xe21e, 0xe21e }, +/* 0xe21f */ { false, 0xe21f, 0xe21f }, +/* 0xe220 */ { false, 0xe220, 0xe220 }, +/* 0xe221 */ { false, 0xe221, 0xe221 }, +/* 0xe222 */ { false, 0xe222, 0xe222 }, +/* 0xe223 */ { false, 0xe223, 0xe223 }, +/* 0xe224 */ { false, 0xe224, 0xe224 }, +/* 0xe225 */ { false, 0xe225, 0xe225 }, +/* 0xe226 */ { false, 0xe226, 0xe226 }, +/* 0xe227 */ { false, 0xe227, 0xe227 }, +/* 0xe228 */ { false, 0xe228, 0xe228 }, +/* 0xe229 */ { false, 0xe229, 0xe229 }, +/* 0xe22a */ { false, 0xe22a, 0xe22a }, +/* 0xe22b */ { false, 0xe22b, 0xe22b }, +/* 0xe22c */ { false, 0xe22c, 0xe22c }, +/* 0xe22d */ { false, 0xe22d, 0xe22d }, +/* 0xe22e */ { false, 0xe22e, 0xe22e }, +/* 0xe22f */ { false, 0xe22f, 0xe22f }, +/* 0xe230 */ { false, 0xe230, 0xe230 }, +/* 0xe231 */ { false, 0xe231, 0xe231 }, +/* 0xe232 */ { false, 0xe232, 0xe232 }, +/* 0xe233 */ { false, 0xe233, 0xe233 }, +/* 0xe234 */ { false, 0xe234, 0xe234 }, +/* 0xe235 */ { false, 0xe235, 0xe235 }, +/* 0xe236 */ { false, 0xe236, 0xe236 }, +/* 0xe237 */ { false, 0xe237, 0xe237 }, +/* 0xe238 */ { false, 0xe238, 0xe238 }, +/* 0xe239 */ { false, 0xe239, 0xe239 }, +/* 0xe23a */ { false, 0xe23a, 0xe23a }, +/* 0xe23b */ { false, 0xe23b, 0xe23b }, +/* 0xe23c */ { false, 0xe23c, 0xe23c }, +/* 0xe23d */ { false, 0xe23d, 0xe23d }, +/* 0xe23e */ { false, 0xe23e, 0xe23e }, +/* 0xe23f */ { false, 0xe23f, 0xe23f }, +/* 0xe240 */ { false, 0xe240, 0xe240 }, +/* 0xe241 */ { false, 0xe241, 0xe241 }, +/* 0xe242 */ { false, 0xe242, 0xe242 }, +/* 0xe243 */ { false, 0xe243, 0xe243 }, +/* 0xe244 */ { false, 0xe244, 0xe244 }, +/* 0xe245 */ { false, 0xe245, 0xe245 }, +/* 0xe246 */ { false, 0xe246, 0xe246 }, +/* 0xe247 */ { false, 0xe247, 0xe247 }, +/* 0xe248 */ { false, 0xe248, 0xe248 }, +/* 0xe249 */ { false, 0xe249, 0xe249 }, +/* 0xe24a */ { false, 0xe24a, 0xe24a }, +/* 0xe24b */ { false, 0xe24b, 0xe24b }, +/* 0xe24c */ { false, 0xe24c, 0xe24c }, +/* 0xe24d */ { false, 0xe24d, 0xe24d }, +/* 0xe24e */ { false, 0xe24e, 0xe24e }, +/* 0xe24f */ { false, 0xe24f, 0xe24f }, +/* 0xe250 */ { false, 0xe250, 0xe250 }, +/* 0xe251 */ { false, 0xe251, 0xe251 }, +/* 0xe252 */ { false, 0xe252, 0xe252 }, +/* 0xe253 */ { false, 0xe253, 0xe253 }, +/* 0xe254 */ { false, 0xe254, 0xe254 }, +/* 0xe255 */ { false, 0xe255, 0xe255 }, +/* 0xe256 */ { false, 0xe256, 0xe256 }, +/* 0xe257 */ { false, 0xe257, 0xe257 }, +/* 0xe258 */ { false, 0xe258, 0xe258 }, +/* 0xe259 */ { false, 0xe259, 0xe259 }, +/* 0xe25a */ { false, 0xe25a, 0xe25a }, +/* 0xe25b */ { false, 0xe25b, 0xe25b }, +/* 0xe25c */ { false, 0xe25c, 0xe25c }, +/* 0xe25d */ { false, 0xe25d, 0xe25d }, +/* 0xe25e */ { false, 0xe25e, 0xe25e }, +/* 0xe25f */ { false, 0xe25f, 0xe25f }, +/* 0xe260 */ { false, 0xe260, 0xe260 }, +/* 0xe261 */ { false, 0xe261, 0xe261 }, +/* 0xe262 */ { false, 0xe262, 0xe262 }, +/* 0xe263 */ { false, 0xe263, 0xe263 }, +/* 0xe264 */ { false, 0xe264, 0xe264 }, +/* 0xe265 */ { false, 0xe265, 0xe265 }, +/* 0xe266 */ { false, 0xe266, 0xe266 }, +/* 0xe267 */ { false, 0xe267, 0xe267 }, +/* 0xe268 */ { false, 0xe268, 0xe268 }, +/* 0xe269 */ { false, 0xe269, 0xe269 }, +/* 0xe26a */ { false, 0xe26a, 0xe26a }, +/* 0xe26b */ { false, 0xe26b, 0xe26b }, +/* 0xe26c */ { false, 0xe26c, 0xe26c }, +/* 0xe26d */ { false, 0xe26d, 0xe26d }, +/* 0xe26e */ { false, 0xe26e, 0xe26e }, +/* 0xe26f */ { false, 0xe26f, 0xe26f }, +/* 0xe270 */ { false, 0xe270, 0xe270 }, +/* 0xe271 */ { false, 0xe271, 0xe271 }, +/* 0xe272 */ { false, 0xe272, 0xe272 }, +/* 0xe273 */ { false, 0xe273, 0xe273 }, +/* 0xe274 */ { false, 0xe274, 0xe274 }, +/* 0xe275 */ { false, 0xe275, 0xe275 }, +/* 0xe276 */ { false, 0xe276, 0xe276 }, +/* 0xe277 */ { false, 0xe277, 0xe277 }, +/* 0xe278 */ { false, 0xe278, 0xe278 }, +/* 0xe279 */ { false, 0xe279, 0xe279 }, +/* 0xe27a */ { false, 0xe27a, 0xe27a }, +/* 0xe27b */ { false, 0xe27b, 0xe27b }, +/* 0xe27c */ { false, 0xe27c, 0xe27c }, +/* 0xe27d */ { false, 0xe27d, 0xe27d }, +/* 0xe27e */ { false, 0xe27e, 0xe27e }, +/* 0xe27f */ { false, 0xe27f, 0xe27f }, +/* 0xe280 */ { false, 0xe280, 0xe280 }, +/* 0xe281 */ { false, 0xe281, 0xe281 }, +/* 0xe282 */ { false, 0xe282, 0xe282 }, +/* 0xe283 */ { false, 0xe283, 0xe283 }, +/* 0xe284 */ { false, 0xe284, 0xe284 }, +/* 0xe285 */ { false, 0xe285, 0xe285 }, +/* 0xe286 */ { false, 0xe286, 0xe286 }, +/* 0xe287 */ { false, 0xe287, 0xe287 }, +/* 0xe288 */ { false, 0xe288, 0xe288 }, +/* 0xe289 */ { false, 0xe289, 0xe289 }, +/* 0xe28a */ { false, 0xe28a, 0xe28a }, +/* 0xe28b */ { false, 0xe28b, 0xe28b }, +/* 0xe28c */ { false, 0xe28c, 0xe28c }, +/* 0xe28d */ { false, 0xe28d, 0xe28d }, +/* 0xe28e */ { false, 0xe28e, 0xe28e }, +/* 0xe28f */ { false, 0xe28f, 0xe28f }, +/* 0xe290 */ { false, 0xe290, 0xe290 }, +/* 0xe291 */ { false, 0xe291, 0xe291 }, +/* 0xe292 */ { false, 0xe292, 0xe292 }, +/* 0xe293 */ { false, 0xe293, 0xe293 }, +/* 0xe294 */ { false, 0xe294, 0xe294 }, +/* 0xe295 */ { false, 0xe295, 0xe295 }, +/* 0xe296 */ { false, 0xe296, 0xe296 }, +/* 0xe297 */ { false, 0xe297, 0xe297 }, +/* 0xe298 */ { false, 0xe298, 0xe298 }, +/* 0xe299 */ { false, 0xe299, 0xe299 }, +/* 0xe29a */ { false, 0xe29a, 0xe29a }, +/* 0xe29b */ { false, 0xe29b, 0xe29b }, +/* 0xe29c */ { false, 0xe29c, 0xe29c }, +/* 0xe29d */ { false, 0xe29d, 0xe29d }, +/* 0xe29e */ { false, 0xe29e, 0xe29e }, +/* 0xe29f */ { false, 0xe29f, 0xe29f }, +/* 0xe2a0 */ { false, 0xe2a0, 0xe2a0 }, +/* 0xe2a1 */ { false, 0xe2a1, 0xe2a1 }, +/* 0xe2a2 */ { false, 0xe2a2, 0xe2a2 }, +/* 0xe2a3 */ { false, 0xe2a3, 0xe2a3 }, +/* 0xe2a4 */ { false, 0xe2a4, 0xe2a4 }, +/* 0xe2a5 */ { false, 0xe2a5, 0xe2a5 }, +/* 0xe2a6 */ { false, 0xe2a6, 0xe2a6 }, +/* 0xe2a7 */ { false, 0xe2a7, 0xe2a7 }, +/* 0xe2a8 */ { false, 0xe2a8, 0xe2a8 }, +/* 0xe2a9 */ { false, 0xe2a9, 0xe2a9 }, +/* 0xe2aa */ { false, 0xe2aa, 0xe2aa }, +/* 0xe2ab */ { false, 0xe2ab, 0xe2ab }, +/* 0xe2ac */ { false, 0xe2ac, 0xe2ac }, +/* 0xe2ad */ { false, 0xe2ad, 0xe2ad }, +/* 0xe2ae */ { false, 0xe2ae, 0xe2ae }, +/* 0xe2af */ { false, 0xe2af, 0xe2af }, +/* 0xe2b0 */ { false, 0xe2b0, 0xe2b0 }, +/* 0xe2b1 */ { false, 0xe2b1, 0xe2b1 }, +/* 0xe2b2 */ { false, 0xe2b2, 0xe2b2 }, +/* 0xe2b3 */ { false, 0xe2b3, 0xe2b3 }, +/* 0xe2b4 */ { false, 0xe2b4, 0xe2b4 }, +/* 0xe2b5 */ { false, 0xe2b5, 0xe2b5 }, +/* 0xe2b6 */ { false, 0xe2b6, 0xe2b6 }, +/* 0xe2b7 */ { false, 0xe2b7, 0xe2b7 }, +/* 0xe2b8 */ { false, 0xe2b8, 0xe2b8 }, +/* 0xe2b9 */ { false, 0xe2b9, 0xe2b9 }, +/* 0xe2ba */ { false, 0xe2ba, 0xe2ba }, +/* 0xe2bb */ { false, 0xe2bb, 0xe2bb }, +/* 0xe2bc */ { false, 0xe2bc, 0xe2bc }, +/* 0xe2bd */ { false, 0xe2bd, 0xe2bd }, +/* 0xe2be */ { false, 0xe2be, 0xe2be }, +/* 0xe2bf */ { false, 0xe2bf, 0xe2bf }, +/* 0xe2c0 */ { false, 0xe2c0, 0xe2c0 }, +/* 0xe2c1 */ { false, 0xe2c1, 0xe2c1 }, +/* 0xe2c2 */ { false, 0xe2c2, 0xe2c2 }, +/* 0xe2c3 */ { false, 0xe2c3, 0xe2c3 }, +/* 0xe2c4 */ { false, 0xe2c4, 0xe2c4 }, +/* 0xe2c5 */ { false, 0xe2c5, 0xe2c5 }, +/* 0xe2c6 */ { false, 0xe2c6, 0xe2c6 }, +/* 0xe2c7 */ { false, 0xe2c7, 0xe2c7 }, +/* 0xe2c8 */ { false, 0xe2c8, 0xe2c8 }, +/* 0xe2c9 */ { false, 0xe2c9, 0xe2c9 }, +/* 0xe2ca */ { false, 0xe2ca, 0xe2ca }, +/* 0xe2cb */ { false, 0xe2cb, 0xe2cb }, +/* 0xe2cc */ { false, 0xe2cc, 0xe2cc }, +/* 0xe2cd */ { false, 0xe2cd, 0xe2cd }, +/* 0xe2ce */ { false, 0xe2ce, 0xe2ce }, +/* 0xe2cf */ { false, 0xe2cf, 0xe2cf }, +/* 0xe2d0 */ { false, 0xe2d0, 0xe2d0 }, +/* 0xe2d1 */ { false, 0xe2d1, 0xe2d1 }, +/* 0xe2d2 */ { false, 0xe2d2, 0xe2d2 }, +/* 0xe2d3 */ { false, 0xe2d3, 0xe2d3 }, +/* 0xe2d4 */ { false, 0xe2d4, 0xe2d4 }, +/* 0xe2d5 */ { false, 0xe2d5, 0xe2d5 }, +/* 0xe2d6 */ { false, 0xe2d6, 0xe2d6 }, +/* 0xe2d7 */ { false, 0xe2d7, 0xe2d7 }, +/* 0xe2d8 */ { false, 0xe2d8, 0xe2d8 }, +/* 0xe2d9 */ { false, 0xe2d9, 0xe2d9 }, +/* 0xe2da */ { false, 0xe2da, 0xe2da }, +/* 0xe2db */ { false, 0xe2db, 0xe2db }, +/* 0xe2dc */ { false, 0xe2dc, 0xe2dc }, +/* 0xe2dd */ { false, 0xe2dd, 0xe2dd }, +/* 0xe2de */ { false, 0xe2de, 0xe2de }, +/* 0xe2df */ { false, 0xe2df, 0xe2df }, +/* 0xe2e0 */ { false, 0xe2e0, 0xe2e0 }, +/* 0xe2e1 */ { false, 0xe2e1, 0xe2e1 }, +/* 0xe2e2 */ { false, 0xe2e2, 0xe2e2 }, +/* 0xe2e3 */ { false, 0xe2e3, 0xe2e3 }, +/* 0xe2e4 */ { false, 0xe2e4, 0xe2e4 }, +/* 0xe2e5 */ { false, 0xe2e5, 0xe2e5 }, +/* 0xe2e6 */ { false, 0xe2e6, 0xe2e6 }, +/* 0xe2e7 */ { false, 0xe2e7, 0xe2e7 }, +/* 0xe2e8 */ { false, 0xe2e8, 0xe2e8 }, +/* 0xe2e9 */ { false, 0xe2e9, 0xe2e9 }, +/* 0xe2ea */ { false, 0xe2ea, 0xe2ea }, +/* 0xe2eb */ { false, 0xe2eb, 0xe2eb }, +/* 0xe2ec */ { false, 0xe2ec, 0xe2ec }, +/* 0xe2ed */ { false, 0xe2ed, 0xe2ed }, +/* 0xe2ee */ { false, 0xe2ee, 0xe2ee }, +/* 0xe2ef */ { false, 0xe2ef, 0xe2ef }, +/* 0xe2f0 */ { false, 0xe2f0, 0xe2f0 }, +/* 0xe2f1 */ { false, 0xe2f1, 0xe2f1 }, +/* 0xe2f2 */ { false, 0xe2f2, 0xe2f2 }, +/* 0xe2f3 */ { false, 0xe2f3, 0xe2f3 }, +/* 0xe2f4 */ { false, 0xe2f4, 0xe2f4 }, +/* 0xe2f5 */ { false, 0xe2f5, 0xe2f5 }, +/* 0xe2f6 */ { false, 0xe2f6, 0xe2f6 }, +/* 0xe2f7 */ { false, 0xe2f7, 0xe2f7 }, +/* 0xe2f8 */ { false, 0xe2f8, 0xe2f8 }, +/* 0xe2f9 */ { false, 0xe2f9, 0xe2f9 }, +/* 0xe2fa */ { false, 0xe2fa, 0xe2fa }, +/* 0xe2fb */ { false, 0xe2fb, 0xe2fb }, +/* 0xe2fc */ { false, 0xe2fc, 0xe2fc }, +/* 0xe2fd */ { false, 0xe2fd, 0xe2fd }, +/* 0xe2fe */ { false, 0xe2fe, 0xe2fe }, +/* 0xe2ff */ { false, 0xe2ff, 0xe2ff }, +/* 0xe300 */ { false, 0xe300, 0xe300 }, +/* 0xe301 */ { false, 0xe301, 0xe301 }, +/* 0xe302 */ { false, 0xe302, 0xe302 }, +/* 0xe303 */ { false, 0xe303, 0xe303 }, +/* 0xe304 */ { false, 0xe304, 0xe304 }, +/* 0xe305 */ { false, 0xe305, 0xe305 }, +/* 0xe306 */ { false, 0xe306, 0xe306 }, +/* 0xe307 */ { false, 0xe307, 0xe307 }, +/* 0xe308 */ { false, 0xe308, 0xe308 }, +/* 0xe309 */ { false, 0xe309, 0xe309 }, +/* 0xe30a */ { false, 0xe30a, 0xe30a }, +/* 0xe30b */ { false, 0xe30b, 0xe30b }, +/* 0xe30c */ { false, 0xe30c, 0xe30c }, +/* 0xe30d */ { false, 0xe30d, 0xe30d }, +/* 0xe30e */ { false, 0xe30e, 0xe30e }, +/* 0xe30f */ { false, 0xe30f, 0xe30f }, +/* 0xe310 */ { false, 0xe310, 0xe310 }, +/* 0xe311 */ { false, 0xe311, 0xe311 }, +/* 0xe312 */ { false, 0xe312, 0xe312 }, +/* 0xe313 */ { false, 0xe313, 0xe313 }, +/* 0xe314 */ { false, 0xe314, 0xe314 }, +/* 0xe315 */ { false, 0xe315, 0xe315 }, +/* 0xe316 */ { false, 0xe316, 0xe316 }, +/* 0xe317 */ { false, 0xe317, 0xe317 }, +/* 0xe318 */ { false, 0xe318, 0xe318 }, +/* 0xe319 */ { false, 0xe319, 0xe319 }, +/* 0xe31a */ { false, 0xe31a, 0xe31a }, +/* 0xe31b */ { false, 0xe31b, 0xe31b }, +/* 0xe31c */ { false, 0xe31c, 0xe31c }, +/* 0xe31d */ { false, 0xe31d, 0xe31d }, +/* 0xe31e */ { false, 0xe31e, 0xe31e }, +/* 0xe31f */ { false, 0xe31f, 0xe31f }, +/* 0xe320 */ { false, 0xe320, 0xe320 }, +/* 0xe321 */ { false, 0xe321, 0xe321 }, +/* 0xe322 */ { false, 0xe322, 0xe322 }, +/* 0xe323 */ { false, 0xe323, 0xe323 }, +/* 0xe324 */ { false, 0xe324, 0xe324 }, +/* 0xe325 */ { false, 0xe325, 0xe325 }, +/* 0xe326 */ { false, 0xe326, 0xe326 }, +/* 0xe327 */ { false, 0xe327, 0xe327 }, +/* 0xe328 */ { false, 0xe328, 0xe328 }, +/* 0xe329 */ { false, 0xe329, 0xe329 }, +/* 0xe32a */ { false, 0xe32a, 0xe32a }, +/* 0xe32b */ { false, 0xe32b, 0xe32b }, +/* 0xe32c */ { false, 0xe32c, 0xe32c }, +/* 0xe32d */ { false, 0xe32d, 0xe32d }, +/* 0xe32e */ { false, 0xe32e, 0xe32e }, +/* 0xe32f */ { false, 0xe32f, 0xe32f }, +/* 0xe330 */ { false, 0xe330, 0xe330 }, +/* 0xe331 */ { false, 0xe331, 0xe331 }, +/* 0xe332 */ { false, 0xe332, 0xe332 }, +/* 0xe333 */ { false, 0xe333, 0xe333 }, +/* 0xe334 */ { false, 0xe334, 0xe334 }, +/* 0xe335 */ { false, 0xe335, 0xe335 }, +/* 0xe336 */ { false, 0xe336, 0xe336 }, +/* 0xe337 */ { false, 0xe337, 0xe337 }, +/* 0xe338 */ { false, 0xe338, 0xe338 }, +/* 0xe339 */ { false, 0xe339, 0xe339 }, +/* 0xe33a */ { false, 0xe33a, 0xe33a }, +/* 0xe33b */ { false, 0xe33b, 0xe33b }, +/* 0xe33c */ { false, 0xe33c, 0xe33c }, +/* 0xe33d */ { false, 0xe33d, 0xe33d }, +/* 0xe33e */ { false, 0xe33e, 0xe33e }, +/* 0xe33f */ { false, 0xe33f, 0xe33f }, +/* 0xe340 */ { false, 0xe340, 0xe340 }, +/* 0xe341 */ { false, 0xe341, 0xe341 }, +/* 0xe342 */ { false, 0xe342, 0xe342 }, +/* 0xe343 */ { false, 0xe343, 0xe343 }, +/* 0xe344 */ { false, 0xe344, 0xe344 }, +/* 0xe345 */ { false, 0xe345, 0xe345 }, +/* 0xe346 */ { false, 0xe346, 0xe346 }, +/* 0xe347 */ { false, 0xe347, 0xe347 }, +/* 0xe348 */ { false, 0xe348, 0xe348 }, +/* 0xe349 */ { false, 0xe349, 0xe349 }, +/* 0xe34a */ { false, 0xe34a, 0xe34a }, +/* 0xe34b */ { false, 0xe34b, 0xe34b }, +/* 0xe34c */ { false, 0xe34c, 0xe34c }, +/* 0xe34d */ { false, 0xe34d, 0xe34d }, +/* 0xe34e */ { false, 0xe34e, 0xe34e }, +/* 0xe34f */ { false, 0xe34f, 0xe34f }, +/* 0xe350 */ { false, 0xe350, 0xe350 }, +/* 0xe351 */ { false, 0xe351, 0xe351 }, +/* 0xe352 */ { false, 0xe352, 0xe352 }, +/* 0xe353 */ { false, 0xe353, 0xe353 }, +/* 0xe354 */ { false, 0xe354, 0xe354 }, +/* 0xe355 */ { false, 0xe355, 0xe355 }, +/* 0xe356 */ { false, 0xe356, 0xe356 }, +/* 0xe357 */ { false, 0xe357, 0xe357 }, +/* 0xe358 */ { false, 0xe358, 0xe358 }, +/* 0xe359 */ { false, 0xe359, 0xe359 }, +/* 0xe35a */ { false, 0xe35a, 0xe35a }, +/* 0xe35b */ { false, 0xe35b, 0xe35b }, +/* 0xe35c */ { false, 0xe35c, 0xe35c }, +/* 0xe35d */ { false, 0xe35d, 0xe35d }, +/* 0xe35e */ { false, 0xe35e, 0xe35e }, +/* 0xe35f */ { false, 0xe35f, 0xe35f }, +/* 0xe360 */ { false, 0xe360, 0xe360 }, +/* 0xe361 */ { false, 0xe361, 0xe361 }, +/* 0xe362 */ { false, 0xe362, 0xe362 }, +/* 0xe363 */ { false, 0xe363, 0xe363 }, +/* 0xe364 */ { false, 0xe364, 0xe364 }, +/* 0xe365 */ { false, 0xe365, 0xe365 }, +/* 0xe366 */ { false, 0xe366, 0xe366 }, +/* 0xe367 */ { false, 0xe367, 0xe367 }, +/* 0xe368 */ { false, 0xe368, 0xe368 }, +/* 0xe369 */ { false, 0xe369, 0xe369 }, +/* 0xe36a */ { false, 0xe36a, 0xe36a }, +/* 0xe36b */ { false, 0xe36b, 0xe36b }, +/* 0xe36c */ { false, 0xe36c, 0xe36c }, +/* 0xe36d */ { false, 0xe36d, 0xe36d }, +/* 0xe36e */ { false, 0xe36e, 0xe36e }, +/* 0xe36f */ { false, 0xe36f, 0xe36f }, +/* 0xe370 */ { false, 0xe370, 0xe370 }, +/* 0xe371 */ { false, 0xe371, 0xe371 }, +/* 0xe372 */ { false, 0xe372, 0xe372 }, +/* 0xe373 */ { false, 0xe373, 0xe373 }, +/* 0xe374 */ { false, 0xe374, 0xe374 }, +/* 0xe375 */ { false, 0xe375, 0xe375 }, +/* 0xe376 */ { false, 0xe376, 0xe376 }, +/* 0xe377 */ { false, 0xe377, 0xe377 }, +/* 0xe378 */ { false, 0xe378, 0xe378 }, +/* 0xe379 */ { false, 0xe379, 0xe379 }, +/* 0xe37a */ { false, 0xe37a, 0xe37a }, +/* 0xe37b */ { false, 0xe37b, 0xe37b }, +/* 0xe37c */ { false, 0xe37c, 0xe37c }, +/* 0xe37d */ { false, 0xe37d, 0xe37d }, +/* 0xe37e */ { false, 0xe37e, 0xe37e }, +/* 0xe37f */ { false, 0xe37f, 0xe37f }, +/* 0xe380 */ { false, 0xe380, 0xe380 }, +/* 0xe381 */ { false, 0xe381, 0xe381 }, +/* 0xe382 */ { false, 0xe382, 0xe382 }, +/* 0xe383 */ { false, 0xe383, 0xe383 }, +/* 0xe384 */ { false, 0xe384, 0xe384 }, +/* 0xe385 */ { false, 0xe385, 0xe385 }, +/* 0xe386 */ { false, 0xe386, 0xe386 }, +/* 0xe387 */ { false, 0xe387, 0xe387 }, +/* 0xe388 */ { false, 0xe388, 0xe388 }, +/* 0xe389 */ { false, 0xe389, 0xe389 }, +/* 0xe38a */ { false, 0xe38a, 0xe38a }, +/* 0xe38b */ { false, 0xe38b, 0xe38b }, +/* 0xe38c */ { false, 0xe38c, 0xe38c }, +/* 0xe38d */ { false, 0xe38d, 0xe38d }, +/* 0xe38e */ { false, 0xe38e, 0xe38e }, +/* 0xe38f */ { false, 0xe38f, 0xe38f }, +/* 0xe390 */ { false, 0xe390, 0xe390 }, +/* 0xe391 */ { false, 0xe391, 0xe391 }, +/* 0xe392 */ { false, 0xe392, 0xe392 }, +/* 0xe393 */ { false, 0xe393, 0xe393 }, +/* 0xe394 */ { false, 0xe394, 0xe394 }, +/* 0xe395 */ { false, 0xe395, 0xe395 }, +/* 0xe396 */ { false, 0xe396, 0xe396 }, +/* 0xe397 */ { false, 0xe397, 0xe397 }, +/* 0xe398 */ { false, 0xe398, 0xe398 }, +/* 0xe399 */ { false, 0xe399, 0xe399 }, +/* 0xe39a */ { false, 0xe39a, 0xe39a }, +/* 0xe39b */ { false, 0xe39b, 0xe39b }, +/* 0xe39c */ { false, 0xe39c, 0xe39c }, +/* 0xe39d */ { false, 0xe39d, 0xe39d }, +/* 0xe39e */ { false, 0xe39e, 0xe39e }, +/* 0xe39f */ { false, 0xe39f, 0xe39f }, +/* 0xe3a0 */ { false, 0xe3a0, 0xe3a0 }, +/* 0xe3a1 */ { false, 0xe3a1, 0xe3a1 }, +/* 0xe3a2 */ { false, 0xe3a2, 0xe3a2 }, +/* 0xe3a3 */ { false, 0xe3a3, 0xe3a3 }, +/* 0xe3a4 */ { false, 0xe3a4, 0xe3a4 }, +/* 0xe3a5 */ { false, 0xe3a5, 0xe3a5 }, +/* 0xe3a6 */ { false, 0xe3a6, 0xe3a6 }, +/* 0xe3a7 */ { false, 0xe3a7, 0xe3a7 }, +/* 0xe3a8 */ { false, 0xe3a8, 0xe3a8 }, +/* 0xe3a9 */ { false, 0xe3a9, 0xe3a9 }, +/* 0xe3aa */ { false, 0xe3aa, 0xe3aa }, +/* 0xe3ab */ { false, 0xe3ab, 0xe3ab }, +/* 0xe3ac */ { false, 0xe3ac, 0xe3ac }, +/* 0xe3ad */ { false, 0xe3ad, 0xe3ad }, +/* 0xe3ae */ { false, 0xe3ae, 0xe3ae }, +/* 0xe3af */ { false, 0xe3af, 0xe3af }, +/* 0xe3b0 */ { false, 0xe3b0, 0xe3b0 }, +/* 0xe3b1 */ { false, 0xe3b1, 0xe3b1 }, +/* 0xe3b2 */ { false, 0xe3b2, 0xe3b2 }, +/* 0xe3b3 */ { false, 0xe3b3, 0xe3b3 }, +/* 0xe3b4 */ { false, 0xe3b4, 0xe3b4 }, +/* 0xe3b5 */ { false, 0xe3b5, 0xe3b5 }, +/* 0xe3b6 */ { false, 0xe3b6, 0xe3b6 }, +/* 0xe3b7 */ { false, 0xe3b7, 0xe3b7 }, +/* 0xe3b8 */ { false, 0xe3b8, 0xe3b8 }, +/* 0xe3b9 */ { false, 0xe3b9, 0xe3b9 }, +/* 0xe3ba */ { false, 0xe3ba, 0xe3ba }, +/* 0xe3bb */ { false, 0xe3bb, 0xe3bb }, +/* 0xe3bc */ { false, 0xe3bc, 0xe3bc }, +/* 0xe3bd */ { false, 0xe3bd, 0xe3bd }, +/* 0xe3be */ { false, 0xe3be, 0xe3be }, +/* 0xe3bf */ { false, 0xe3bf, 0xe3bf }, +/* 0xe3c0 */ { false, 0xe3c0, 0xe3c0 }, +/* 0xe3c1 */ { false, 0xe3c1, 0xe3c1 }, +/* 0xe3c2 */ { false, 0xe3c2, 0xe3c2 }, +/* 0xe3c3 */ { false, 0xe3c3, 0xe3c3 }, +/* 0xe3c4 */ { false, 0xe3c4, 0xe3c4 }, +/* 0xe3c5 */ { false, 0xe3c5, 0xe3c5 }, +/* 0xe3c6 */ { false, 0xe3c6, 0xe3c6 }, +/* 0xe3c7 */ { false, 0xe3c7, 0xe3c7 }, +/* 0xe3c8 */ { false, 0xe3c8, 0xe3c8 }, +/* 0xe3c9 */ { false, 0xe3c9, 0xe3c9 }, +/* 0xe3ca */ { false, 0xe3ca, 0xe3ca }, +/* 0xe3cb */ { false, 0xe3cb, 0xe3cb }, +/* 0xe3cc */ { false, 0xe3cc, 0xe3cc }, +/* 0xe3cd */ { false, 0xe3cd, 0xe3cd }, +/* 0xe3ce */ { false, 0xe3ce, 0xe3ce }, +/* 0xe3cf */ { false, 0xe3cf, 0xe3cf }, +/* 0xe3d0 */ { false, 0xe3d0, 0xe3d0 }, +/* 0xe3d1 */ { false, 0xe3d1, 0xe3d1 }, +/* 0xe3d2 */ { false, 0xe3d2, 0xe3d2 }, +/* 0xe3d3 */ { false, 0xe3d3, 0xe3d3 }, +/* 0xe3d4 */ { false, 0xe3d4, 0xe3d4 }, +/* 0xe3d5 */ { false, 0xe3d5, 0xe3d5 }, +/* 0xe3d6 */ { false, 0xe3d6, 0xe3d6 }, +/* 0xe3d7 */ { false, 0xe3d7, 0xe3d7 }, +/* 0xe3d8 */ { false, 0xe3d8, 0xe3d8 }, +/* 0xe3d9 */ { false, 0xe3d9, 0xe3d9 }, +/* 0xe3da */ { false, 0xe3da, 0xe3da }, +/* 0xe3db */ { false, 0xe3db, 0xe3db }, +/* 0xe3dc */ { false, 0xe3dc, 0xe3dc }, +/* 0xe3dd */ { false, 0xe3dd, 0xe3dd }, +/* 0xe3de */ { false, 0xe3de, 0xe3de }, +/* 0xe3df */ { false, 0xe3df, 0xe3df }, +/* 0xe3e0 */ { false, 0xe3e0, 0xe3e0 }, +/* 0xe3e1 */ { false, 0xe3e1, 0xe3e1 }, +/* 0xe3e2 */ { false, 0xe3e2, 0xe3e2 }, +/* 0xe3e3 */ { false, 0xe3e3, 0xe3e3 }, +/* 0xe3e4 */ { false, 0xe3e4, 0xe3e4 }, +/* 0xe3e5 */ { false, 0xe3e5, 0xe3e5 }, +/* 0xe3e6 */ { false, 0xe3e6, 0xe3e6 }, +/* 0xe3e7 */ { false, 0xe3e7, 0xe3e7 }, +/* 0xe3e8 */ { false, 0xe3e8, 0xe3e8 }, +/* 0xe3e9 */ { false, 0xe3e9, 0xe3e9 }, +/* 0xe3ea */ { false, 0xe3ea, 0xe3ea }, +/* 0xe3eb */ { false, 0xe3eb, 0xe3eb }, +/* 0xe3ec */ { false, 0xe3ec, 0xe3ec }, +/* 0xe3ed */ { false, 0xe3ed, 0xe3ed }, +/* 0xe3ee */ { false, 0xe3ee, 0xe3ee }, +/* 0xe3ef */ { false, 0xe3ef, 0xe3ef }, +/* 0xe3f0 */ { false, 0xe3f0, 0xe3f0 }, +/* 0xe3f1 */ { false, 0xe3f1, 0xe3f1 }, +/* 0xe3f2 */ { false, 0xe3f2, 0xe3f2 }, +/* 0xe3f3 */ { false, 0xe3f3, 0xe3f3 }, +/* 0xe3f4 */ { false, 0xe3f4, 0xe3f4 }, +/* 0xe3f5 */ { false, 0xe3f5, 0xe3f5 }, +/* 0xe3f6 */ { false, 0xe3f6, 0xe3f6 }, +/* 0xe3f7 */ { false, 0xe3f7, 0xe3f7 }, +/* 0xe3f8 */ { false, 0xe3f8, 0xe3f8 }, +/* 0xe3f9 */ { false, 0xe3f9, 0xe3f9 }, +/* 0xe3fa */ { false, 0xe3fa, 0xe3fa }, +/* 0xe3fb */ { false, 0xe3fb, 0xe3fb }, +/* 0xe3fc */ { false, 0xe3fc, 0xe3fc }, +/* 0xe3fd */ { false, 0xe3fd, 0xe3fd }, +/* 0xe3fe */ { false, 0xe3fe, 0xe3fe }, +/* 0xe3ff */ { false, 0xe3ff, 0xe3ff }, +/* 0xe400 */ { false, 0xe400, 0xe400 }, +/* 0xe401 */ { false, 0xe401, 0xe401 }, +/* 0xe402 */ { false, 0xe402, 0xe402 }, +/* 0xe403 */ { false, 0xe403, 0xe403 }, +/* 0xe404 */ { false, 0xe404, 0xe404 }, +/* 0xe405 */ { false, 0xe405, 0xe405 }, +/* 0xe406 */ { false, 0xe406, 0xe406 }, +/* 0xe407 */ { false, 0xe407, 0xe407 }, +/* 0xe408 */ { false, 0xe408, 0xe408 }, +/* 0xe409 */ { false, 0xe409, 0xe409 }, +/* 0xe40a */ { false, 0xe40a, 0xe40a }, +/* 0xe40b */ { false, 0xe40b, 0xe40b }, +/* 0xe40c */ { false, 0xe40c, 0xe40c }, +/* 0xe40d */ { false, 0xe40d, 0xe40d }, +/* 0xe40e */ { false, 0xe40e, 0xe40e }, +/* 0xe40f */ { false, 0xe40f, 0xe40f }, +/* 0xe410 */ { false, 0xe410, 0xe410 }, +/* 0xe411 */ { false, 0xe411, 0xe411 }, +/* 0xe412 */ { false, 0xe412, 0xe412 }, +/* 0xe413 */ { false, 0xe413, 0xe413 }, +/* 0xe414 */ { false, 0xe414, 0xe414 }, +/* 0xe415 */ { false, 0xe415, 0xe415 }, +/* 0xe416 */ { false, 0xe416, 0xe416 }, +/* 0xe417 */ { false, 0xe417, 0xe417 }, +/* 0xe418 */ { false, 0xe418, 0xe418 }, +/* 0xe419 */ { false, 0xe419, 0xe419 }, +/* 0xe41a */ { false, 0xe41a, 0xe41a }, +/* 0xe41b */ { false, 0xe41b, 0xe41b }, +/* 0xe41c */ { false, 0xe41c, 0xe41c }, +/* 0xe41d */ { false, 0xe41d, 0xe41d }, +/* 0xe41e */ { false, 0xe41e, 0xe41e }, +/* 0xe41f */ { false, 0xe41f, 0xe41f }, +/* 0xe420 */ { false, 0xe420, 0xe420 }, +/* 0xe421 */ { false, 0xe421, 0xe421 }, +/* 0xe422 */ { false, 0xe422, 0xe422 }, +/* 0xe423 */ { false, 0xe423, 0xe423 }, +/* 0xe424 */ { false, 0xe424, 0xe424 }, +/* 0xe425 */ { false, 0xe425, 0xe425 }, +/* 0xe426 */ { false, 0xe426, 0xe426 }, +/* 0xe427 */ { false, 0xe427, 0xe427 }, +/* 0xe428 */ { false, 0xe428, 0xe428 }, +/* 0xe429 */ { false, 0xe429, 0xe429 }, +/* 0xe42a */ { false, 0xe42a, 0xe42a }, +/* 0xe42b */ { false, 0xe42b, 0xe42b }, +/* 0xe42c */ { false, 0xe42c, 0xe42c }, +/* 0xe42d */ { false, 0xe42d, 0xe42d }, +/* 0xe42e */ { false, 0xe42e, 0xe42e }, +/* 0xe42f */ { false, 0xe42f, 0xe42f }, +/* 0xe430 */ { false, 0xe430, 0xe430 }, +/* 0xe431 */ { false, 0xe431, 0xe431 }, +/* 0xe432 */ { false, 0xe432, 0xe432 }, +/* 0xe433 */ { false, 0xe433, 0xe433 }, +/* 0xe434 */ { false, 0xe434, 0xe434 }, +/* 0xe435 */ { false, 0xe435, 0xe435 }, +/* 0xe436 */ { false, 0xe436, 0xe436 }, +/* 0xe437 */ { false, 0xe437, 0xe437 }, +/* 0xe438 */ { false, 0xe438, 0xe438 }, +/* 0xe439 */ { false, 0xe439, 0xe439 }, +/* 0xe43a */ { false, 0xe43a, 0xe43a }, +/* 0xe43b */ { false, 0xe43b, 0xe43b }, +/* 0xe43c */ { false, 0xe43c, 0xe43c }, +/* 0xe43d */ { false, 0xe43d, 0xe43d }, +/* 0xe43e */ { false, 0xe43e, 0xe43e }, +/* 0xe43f */ { false, 0xe43f, 0xe43f }, +/* 0xe440 */ { false, 0xe440, 0xe440 }, +/* 0xe441 */ { false, 0xe441, 0xe441 }, +/* 0xe442 */ { false, 0xe442, 0xe442 }, +/* 0xe443 */ { false, 0xe443, 0xe443 }, +/* 0xe444 */ { false, 0xe444, 0xe444 }, +/* 0xe445 */ { false, 0xe445, 0xe445 }, +/* 0xe446 */ { false, 0xe446, 0xe446 }, +/* 0xe447 */ { false, 0xe447, 0xe447 }, +/* 0xe448 */ { false, 0xe448, 0xe448 }, +/* 0xe449 */ { false, 0xe449, 0xe449 }, +/* 0xe44a */ { false, 0xe44a, 0xe44a }, +/* 0xe44b */ { false, 0xe44b, 0xe44b }, +/* 0xe44c */ { false, 0xe44c, 0xe44c }, +/* 0xe44d */ { false, 0xe44d, 0xe44d }, +/* 0xe44e */ { false, 0xe44e, 0xe44e }, +/* 0xe44f */ { false, 0xe44f, 0xe44f }, +/* 0xe450 */ { false, 0xe450, 0xe450 }, +/* 0xe451 */ { false, 0xe451, 0xe451 }, +/* 0xe452 */ { false, 0xe452, 0xe452 }, +/* 0xe453 */ { false, 0xe453, 0xe453 }, +/* 0xe454 */ { false, 0xe454, 0xe454 }, +/* 0xe455 */ { false, 0xe455, 0xe455 }, +/* 0xe456 */ { false, 0xe456, 0xe456 }, +/* 0xe457 */ { false, 0xe457, 0xe457 }, +/* 0xe458 */ { false, 0xe458, 0xe458 }, +/* 0xe459 */ { false, 0xe459, 0xe459 }, +/* 0xe45a */ { false, 0xe45a, 0xe45a }, +/* 0xe45b */ { false, 0xe45b, 0xe45b }, +/* 0xe45c */ { false, 0xe45c, 0xe45c }, +/* 0xe45d */ { false, 0xe45d, 0xe45d }, +/* 0xe45e */ { false, 0xe45e, 0xe45e }, +/* 0xe45f */ { false, 0xe45f, 0xe45f }, +/* 0xe460 */ { false, 0xe460, 0xe460 }, +/* 0xe461 */ { false, 0xe461, 0xe461 }, +/* 0xe462 */ { false, 0xe462, 0xe462 }, +/* 0xe463 */ { false, 0xe463, 0xe463 }, +/* 0xe464 */ { false, 0xe464, 0xe464 }, +/* 0xe465 */ { false, 0xe465, 0xe465 }, +/* 0xe466 */ { false, 0xe466, 0xe466 }, +/* 0xe467 */ { false, 0xe467, 0xe467 }, +/* 0xe468 */ { false, 0xe468, 0xe468 }, +/* 0xe469 */ { false, 0xe469, 0xe469 }, +/* 0xe46a */ { false, 0xe46a, 0xe46a }, +/* 0xe46b */ { false, 0xe46b, 0xe46b }, +/* 0xe46c */ { false, 0xe46c, 0xe46c }, +/* 0xe46d */ { false, 0xe46d, 0xe46d }, +/* 0xe46e */ { false, 0xe46e, 0xe46e }, +/* 0xe46f */ { false, 0xe46f, 0xe46f }, +/* 0xe470 */ { false, 0xe470, 0xe470 }, +/* 0xe471 */ { false, 0xe471, 0xe471 }, +/* 0xe472 */ { false, 0xe472, 0xe472 }, +/* 0xe473 */ { false, 0xe473, 0xe473 }, +/* 0xe474 */ { false, 0xe474, 0xe474 }, +/* 0xe475 */ { false, 0xe475, 0xe475 }, +/* 0xe476 */ { false, 0xe476, 0xe476 }, +/* 0xe477 */ { false, 0xe477, 0xe477 }, +/* 0xe478 */ { false, 0xe478, 0xe478 }, +/* 0xe479 */ { false, 0xe479, 0xe479 }, +/* 0xe47a */ { false, 0xe47a, 0xe47a }, +/* 0xe47b */ { false, 0xe47b, 0xe47b }, +/* 0xe47c */ { false, 0xe47c, 0xe47c }, +/* 0xe47d */ { false, 0xe47d, 0xe47d }, +/* 0xe47e */ { false, 0xe47e, 0xe47e }, +/* 0xe47f */ { false, 0xe47f, 0xe47f }, +/* 0xe480 */ { false, 0xe480, 0xe480 }, +/* 0xe481 */ { false, 0xe481, 0xe481 }, +/* 0xe482 */ { false, 0xe482, 0xe482 }, +/* 0xe483 */ { false, 0xe483, 0xe483 }, +/* 0xe484 */ { false, 0xe484, 0xe484 }, +/* 0xe485 */ { false, 0xe485, 0xe485 }, +/* 0xe486 */ { false, 0xe486, 0xe486 }, +/* 0xe487 */ { false, 0xe487, 0xe487 }, +/* 0xe488 */ { false, 0xe488, 0xe488 }, +/* 0xe489 */ { false, 0xe489, 0xe489 }, +/* 0xe48a */ { false, 0xe48a, 0xe48a }, +/* 0xe48b */ { false, 0xe48b, 0xe48b }, +/* 0xe48c */ { false, 0xe48c, 0xe48c }, +/* 0xe48d */ { false, 0xe48d, 0xe48d }, +/* 0xe48e */ { false, 0xe48e, 0xe48e }, +/* 0xe48f */ { false, 0xe48f, 0xe48f }, +/* 0xe490 */ { false, 0xe490, 0xe490 }, +/* 0xe491 */ { false, 0xe491, 0xe491 }, +/* 0xe492 */ { false, 0xe492, 0xe492 }, +/* 0xe493 */ { false, 0xe493, 0xe493 }, +/* 0xe494 */ { false, 0xe494, 0xe494 }, +/* 0xe495 */ { false, 0xe495, 0xe495 }, +/* 0xe496 */ { false, 0xe496, 0xe496 }, +/* 0xe497 */ { false, 0xe497, 0xe497 }, +/* 0xe498 */ { false, 0xe498, 0xe498 }, +/* 0xe499 */ { false, 0xe499, 0xe499 }, +/* 0xe49a */ { false, 0xe49a, 0xe49a }, +/* 0xe49b */ { false, 0xe49b, 0xe49b }, +/* 0xe49c */ { false, 0xe49c, 0xe49c }, +/* 0xe49d */ { false, 0xe49d, 0xe49d }, +/* 0xe49e */ { false, 0xe49e, 0xe49e }, +/* 0xe49f */ { false, 0xe49f, 0xe49f }, +/* 0xe4a0 */ { false, 0xe4a0, 0xe4a0 }, +/* 0xe4a1 */ { false, 0xe4a1, 0xe4a1 }, +/* 0xe4a2 */ { false, 0xe4a2, 0xe4a2 }, +/* 0xe4a3 */ { false, 0xe4a3, 0xe4a3 }, +/* 0xe4a4 */ { false, 0xe4a4, 0xe4a4 }, +/* 0xe4a5 */ { false, 0xe4a5, 0xe4a5 }, +/* 0xe4a6 */ { false, 0xe4a6, 0xe4a6 }, +/* 0xe4a7 */ { false, 0xe4a7, 0xe4a7 }, +/* 0xe4a8 */ { false, 0xe4a8, 0xe4a8 }, +/* 0xe4a9 */ { false, 0xe4a9, 0xe4a9 }, +/* 0xe4aa */ { false, 0xe4aa, 0xe4aa }, +/* 0xe4ab */ { false, 0xe4ab, 0xe4ab }, +/* 0xe4ac */ { false, 0xe4ac, 0xe4ac }, +/* 0xe4ad */ { false, 0xe4ad, 0xe4ad }, +/* 0xe4ae */ { false, 0xe4ae, 0xe4ae }, +/* 0xe4af */ { false, 0xe4af, 0xe4af }, +/* 0xe4b0 */ { false, 0xe4b0, 0xe4b0 }, +/* 0xe4b1 */ { false, 0xe4b1, 0xe4b1 }, +/* 0xe4b2 */ { false, 0xe4b2, 0xe4b2 }, +/* 0xe4b3 */ { false, 0xe4b3, 0xe4b3 }, +/* 0xe4b4 */ { false, 0xe4b4, 0xe4b4 }, +/* 0xe4b5 */ { false, 0xe4b5, 0xe4b5 }, +/* 0xe4b6 */ { false, 0xe4b6, 0xe4b6 }, +/* 0xe4b7 */ { false, 0xe4b7, 0xe4b7 }, +/* 0xe4b8 */ { false, 0xe4b8, 0xe4b8 }, +/* 0xe4b9 */ { false, 0xe4b9, 0xe4b9 }, +/* 0xe4ba */ { false, 0xe4ba, 0xe4ba }, +/* 0xe4bb */ { false, 0xe4bb, 0xe4bb }, +/* 0xe4bc */ { false, 0xe4bc, 0xe4bc }, +/* 0xe4bd */ { false, 0xe4bd, 0xe4bd }, +/* 0xe4be */ { false, 0xe4be, 0xe4be }, +/* 0xe4bf */ { false, 0xe4bf, 0xe4bf }, +/* 0xe4c0 */ { false, 0xe4c0, 0xe4c0 }, +/* 0xe4c1 */ { false, 0xe4c1, 0xe4c1 }, +/* 0xe4c2 */ { false, 0xe4c2, 0xe4c2 }, +/* 0xe4c3 */ { false, 0xe4c3, 0xe4c3 }, +/* 0xe4c4 */ { false, 0xe4c4, 0xe4c4 }, +/* 0xe4c5 */ { false, 0xe4c5, 0xe4c5 }, +/* 0xe4c6 */ { false, 0xe4c6, 0xe4c6 }, +/* 0xe4c7 */ { false, 0xe4c7, 0xe4c7 }, +/* 0xe4c8 */ { false, 0xe4c8, 0xe4c8 }, +/* 0xe4c9 */ { false, 0xe4c9, 0xe4c9 }, +/* 0xe4ca */ { false, 0xe4ca, 0xe4ca }, +/* 0xe4cb */ { false, 0xe4cb, 0xe4cb }, +/* 0xe4cc */ { false, 0xe4cc, 0xe4cc }, +/* 0xe4cd */ { false, 0xe4cd, 0xe4cd }, +/* 0xe4ce */ { false, 0xe4ce, 0xe4ce }, +/* 0xe4cf */ { false, 0xe4cf, 0xe4cf }, +/* 0xe4d0 */ { false, 0xe4d0, 0xe4d0 }, +/* 0xe4d1 */ { false, 0xe4d1, 0xe4d1 }, +/* 0xe4d2 */ { false, 0xe4d2, 0xe4d2 }, +/* 0xe4d3 */ { false, 0xe4d3, 0xe4d3 }, +/* 0xe4d4 */ { false, 0xe4d4, 0xe4d4 }, +/* 0xe4d5 */ { false, 0xe4d5, 0xe4d5 }, +/* 0xe4d6 */ { false, 0xe4d6, 0xe4d6 }, +/* 0xe4d7 */ { false, 0xe4d7, 0xe4d7 }, +/* 0xe4d8 */ { false, 0xe4d8, 0xe4d8 }, +/* 0xe4d9 */ { false, 0xe4d9, 0xe4d9 }, +/* 0xe4da */ { false, 0xe4da, 0xe4da }, +/* 0xe4db */ { false, 0xe4db, 0xe4db }, +/* 0xe4dc */ { false, 0xe4dc, 0xe4dc }, +/* 0xe4dd */ { false, 0xe4dd, 0xe4dd }, +/* 0xe4de */ { false, 0xe4de, 0xe4de }, +/* 0xe4df */ { false, 0xe4df, 0xe4df }, +/* 0xe4e0 */ { false, 0xe4e0, 0xe4e0 }, +/* 0xe4e1 */ { false, 0xe4e1, 0xe4e1 }, +/* 0xe4e2 */ { false, 0xe4e2, 0xe4e2 }, +/* 0xe4e3 */ { false, 0xe4e3, 0xe4e3 }, +/* 0xe4e4 */ { false, 0xe4e4, 0xe4e4 }, +/* 0xe4e5 */ { false, 0xe4e5, 0xe4e5 }, +/* 0xe4e6 */ { false, 0xe4e6, 0xe4e6 }, +/* 0xe4e7 */ { false, 0xe4e7, 0xe4e7 }, +/* 0xe4e8 */ { false, 0xe4e8, 0xe4e8 }, +/* 0xe4e9 */ { false, 0xe4e9, 0xe4e9 }, +/* 0xe4ea */ { false, 0xe4ea, 0xe4ea }, +/* 0xe4eb */ { false, 0xe4eb, 0xe4eb }, +/* 0xe4ec */ { false, 0xe4ec, 0xe4ec }, +/* 0xe4ed */ { false, 0xe4ed, 0xe4ed }, +/* 0xe4ee */ { false, 0xe4ee, 0xe4ee }, +/* 0xe4ef */ { false, 0xe4ef, 0xe4ef }, +/* 0xe4f0 */ { false, 0xe4f0, 0xe4f0 }, +/* 0xe4f1 */ { false, 0xe4f1, 0xe4f1 }, +/* 0xe4f2 */ { false, 0xe4f2, 0xe4f2 }, +/* 0xe4f3 */ { false, 0xe4f3, 0xe4f3 }, +/* 0xe4f4 */ { false, 0xe4f4, 0xe4f4 }, +/* 0xe4f5 */ { false, 0xe4f5, 0xe4f5 }, +/* 0xe4f6 */ { false, 0xe4f6, 0xe4f6 }, +/* 0xe4f7 */ { false, 0xe4f7, 0xe4f7 }, +/* 0xe4f8 */ { false, 0xe4f8, 0xe4f8 }, +/* 0xe4f9 */ { false, 0xe4f9, 0xe4f9 }, +/* 0xe4fa */ { false, 0xe4fa, 0xe4fa }, +/* 0xe4fb */ { false, 0xe4fb, 0xe4fb }, +/* 0xe4fc */ { false, 0xe4fc, 0xe4fc }, +/* 0xe4fd */ { false, 0xe4fd, 0xe4fd }, +/* 0xe4fe */ { false, 0xe4fe, 0xe4fe }, +/* 0xe4ff */ { false, 0xe4ff, 0xe4ff }, +/* 0xe500 */ { false, 0xe500, 0xe500 }, +/* 0xe501 */ { false, 0xe501, 0xe501 }, +/* 0xe502 */ { false, 0xe502, 0xe502 }, +/* 0xe503 */ { false, 0xe503, 0xe503 }, +/* 0xe504 */ { false, 0xe504, 0xe504 }, +/* 0xe505 */ { false, 0xe505, 0xe505 }, +/* 0xe506 */ { false, 0xe506, 0xe506 }, +/* 0xe507 */ { false, 0xe507, 0xe507 }, +/* 0xe508 */ { false, 0xe508, 0xe508 }, +/* 0xe509 */ { false, 0xe509, 0xe509 }, +/* 0xe50a */ { false, 0xe50a, 0xe50a }, +/* 0xe50b */ { false, 0xe50b, 0xe50b }, +/* 0xe50c */ { false, 0xe50c, 0xe50c }, +/* 0xe50d */ { false, 0xe50d, 0xe50d }, +/* 0xe50e */ { false, 0xe50e, 0xe50e }, +/* 0xe50f */ { false, 0xe50f, 0xe50f }, +/* 0xe510 */ { false, 0xe510, 0xe510 }, +/* 0xe511 */ { false, 0xe511, 0xe511 }, +/* 0xe512 */ { false, 0xe512, 0xe512 }, +/* 0xe513 */ { false, 0xe513, 0xe513 }, +/* 0xe514 */ { false, 0xe514, 0xe514 }, +/* 0xe515 */ { false, 0xe515, 0xe515 }, +/* 0xe516 */ { false, 0xe516, 0xe516 }, +/* 0xe517 */ { false, 0xe517, 0xe517 }, +/* 0xe518 */ { false, 0xe518, 0xe518 }, +/* 0xe519 */ { false, 0xe519, 0xe519 }, +/* 0xe51a */ { false, 0xe51a, 0xe51a }, +/* 0xe51b */ { false, 0xe51b, 0xe51b }, +/* 0xe51c */ { false, 0xe51c, 0xe51c }, +/* 0xe51d */ { false, 0xe51d, 0xe51d }, +/* 0xe51e */ { false, 0xe51e, 0xe51e }, +/* 0xe51f */ { false, 0xe51f, 0xe51f }, +/* 0xe520 */ { false, 0xe520, 0xe520 }, +/* 0xe521 */ { false, 0xe521, 0xe521 }, +/* 0xe522 */ { false, 0xe522, 0xe522 }, +/* 0xe523 */ { false, 0xe523, 0xe523 }, +/* 0xe524 */ { false, 0xe524, 0xe524 }, +/* 0xe525 */ { false, 0xe525, 0xe525 }, +/* 0xe526 */ { false, 0xe526, 0xe526 }, +/* 0xe527 */ { false, 0xe527, 0xe527 }, +/* 0xe528 */ { false, 0xe528, 0xe528 }, +/* 0xe529 */ { false, 0xe529, 0xe529 }, +/* 0xe52a */ { false, 0xe52a, 0xe52a }, +/* 0xe52b */ { false, 0xe52b, 0xe52b }, +/* 0xe52c */ { false, 0xe52c, 0xe52c }, +/* 0xe52d */ { false, 0xe52d, 0xe52d }, +/* 0xe52e */ { false, 0xe52e, 0xe52e }, +/* 0xe52f */ { false, 0xe52f, 0xe52f }, +/* 0xe530 */ { false, 0xe530, 0xe530 }, +/* 0xe531 */ { false, 0xe531, 0xe531 }, +/* 0xe532 */ { false, 0xe532, 0xe532 }, +/* 0xe533 */ { false, 0xe533, 0xe533 }, +/* 0xe534 */ { false, 0xe534, 0xe534 }, +/* 0xe535 */ { false, 0xe535, 0xe535 }, +/* 0xe536 */ { false, 0xe536, 0xe536 }, +/* 0xe537 */ { false, 0xe537, 0xe537 }, +/* 0xe538 */ { false, 0xe538, 0xe538 }, +/* 0xe539 */ { false, 0xe539, 0xe539 }, +/* 0xe53a */ { false, 0xe53a, 0xe53a }, +/* 0xe53b */ { false, 0xe53b, 0xe53b }, +/* 0xe53c */ { false, 0xe53c, 0xe53c }, +/* 0xe53d */ { false, 0xe53d, 0xe53d }, +/* 0xe53e */ { false, 0xe53e, 0xe53e }, +/* 0xe53f */ { false, 0xe53f, 0xe53f }, +/* 0xe540 */ { false, 0xe540, 0xe540 }, +/* 0xe541 */ { false, 0xe541, 0xe541 }, +/* 0xe542 */ { false, 0xe542, 0xe542 }, +/* 0xe543 */ { false, 0xe543, 0xe543 }, +/* 0xe544 */ { false, 0xe544, 0xe544 }, +/* 0xe545 */ { false, 0xe545, 0xe545 }, +/* 0xe546 */ { false, 0xe546, 0xe546 }, +/* 0xe547 */ { false, 0xe547, 0xe547 }, +/* 0xe548 */ { false, 0xe548, 0xe548 }, +/* 0xe549 */ { false, 0xe549, 0xe549 }, +/* 0xe54a */ { false, 0xe54a, 0xe54a }, +/* 0xe54b */ { false, 0xe54b, 0xe54b }, +/* 0xe54c */ { false, 0xe54c, 0xe54c }, +/* 0xe54d */ { false, 0xe54d, 0xe54d }, +/* 0xe54e */ { false, 0xe54e, 0xe54e }, +/* 0xe54f */ { false, 0xe54f, 0xe54f }, +/* 0xe550 */ { false, 0xe550, 0xe550 }, +/* 0xe551 */ { false, 0xe551, 0xe551 }, +/* 0xe552 */ { false, 0xe552, 0xe552 }, +/* 0xe553 */ { false, 0xe553, 0xe553 }, +/* 0xe554 */ { false, 0xe554, 0xe554 }, +/* 0xe555 */ { false, 0xe555, 0xe555 }, +/* 0xe556 */ { false, 0xe556, 0xe556 }, +/* 0xe557 */ { false, 0xe557, 0xe557 }, +/* 0xe558 */ { false, 0xe558, 0xe558 }, +/* 0xe559 */ { false, 0xe559, 0xe559 }, +/* 0xe55a */ { false, 0xe55a, 0xe55a }, +/* 0xe55b */ { false, 0xe55b, 0xe55b }, +/* 0xe55c */ { false, 0xe55c, 0xe55c }, +/* 0xe55d */ { false, 0xe55d, 0xe55d }, +/* 0xe55e */ { false, 0xe55e, 0xe55e }, +/* 0xe55f */ { false, 0xe55f, 0xe55f }, +/* 0xe560 */ { false, 0xe560, 0xe560 }, +/* 0xe561 */ { false, 0xe561, 0xe561 }, +/* 0xe562 */ { false, 0xe562, 0xe562 }, +/* 0xe563 */ { false, 0xe563, 0xe563 }, +/* 0xe564 */ { false, 0xe564, 0xe564 }, +/* 0xe565 */ { false, 0xe565, 0xe565 }, +/* 0xe566 */ { false, 0xe566, 0xe566 }, +/* 0xe567 */ { false, 0xe567, 0xe567 }, +/* 0xe568 */ { false, 0xe568, 0xe568 }, +/* 0xe569 */ { false, 0xe569, 0xe569 }, +/* 0xe56a */ { false, 0xe56a, 0xe56a }, +/* 0xe56b */ { false, 0xe56b, 0xe56b }, +/* 0xe56c */ { false, 0xe56c, 0xe56c }, +/* 0xe56d */ { false, 0xe56d, 0xe56d }, +/* 0xe56e */ { false, 0xe56e, 0xe56e }, +/* 0xe56f */ { false, 0xe56f, 0xe56f }, +/* 0xe570 */ { false, 0xe570, 0xe570 }, +/* 0xe571 */ { false, 0xe571, 0xe571 }, +/* 0xe572 */ { false, 0xe572, 0xe572 }, +/* 0xe573 */ { false, 0xe573, 0xe573 }, +/* 0xe574 */ { false, 0xe574, 0xe574 }, +/* 0xe575 */ { false, 0xe575, 0xe575 }, +/* 0xe576 */ { false, 0xe576, 0xe576 }, +/* 0xe577 */ { false, 0xe577, 0xe577 }, +/* 0xe578 */ { false, 0xe578, 0xe578 }, +/* 0xe579 */ { false, 0xe579, 0xe579 }, +/* 0xe57a */ { false, 0xe57a, 0xe57a }, +/* 0xe57b */ { false, 0xe57b, 0xe57b }, +/* 0xe57c */ { false, 0xe57c, 0xe57c }, +/* 0xe57d */ { false, 0xe57d, 0xe57d }, +/* 0xe57e */ { false, 0xe57e, 0xe57e }, +/* 0xe57f */ { false, 0xe57f, 0xe57f }, +/* 0xe580 */ { false, 0xe580, 0xe580 }, +/* 0xe581 */ { false, 0xe581, 0xe581 }, +/* 0xe582 */ { false, 0xe582, 0xe582 }, +/* 0xe583 */ { false, 0xe583, 0xe583 }, +/* 0xe584 */ { false, 0xe584, 0xe584 }, +/* 0xe585 */ { false, 0xe585, 0xe585 }, +/* 0xe586 */ { false, 0xe586, 0xe586 }, +/* 0xe587 */ { false, 0xe587, 0xe587 }, +/* 0xe588 */ { false, 0xe588, 0xe588 }, +/* 0xe589 */ { false, 0xe589, 0xe589 }, +/* 0xe58a */ { false, 0xe58a, 0xe58a }, +/* 0xe58b */ { false, 0xe58b, 0xe58b }, +/* 0xe58c */ { false, 0xe58c, 0xe58c }, +/* 0xe58d */ { false, 0xe58d, 0xe58d }, +/* 0xe58e */ { false, 0xe58e, 0xe58e }, +/* 0xe58f */ { false, 0xe58f, 0xe58f }, +/* 0xe590 */ { false, 0xe590, 0xe590 }, +/* 0xe591 */ { false, 0xe591, 0xe591 }, +/* 0xe592 */ { false, 0xe592, 0xe592 }, +/* 0xe593 */ { false, 0xe593, 0xe593 }, +/* 0xe594 */ { false, 0xe594, 0xe594 }, +/* 0xe595 */ { false, 0xe595, 0xe595 }, +/* 0xe596 */ { false, 0xe596, 0xe596 }, +/* 0xe597 */ { false, 0xe597, 0xe597 }, +/* 0xe598 */ { false, 0xe598, 0xe598 }, +/* 0xe599 */ { false, 0xe599, 0xe599 }, +/* 0xe59a */ { false, 0xe59a, 0xe59a }, +/* 0xe59b */ { false, 0xe59b, 0xe59b }, +/* 0xe59c */ { false, 0xe59c, 0xe59c }, +/* 0xe59d */ { false, 0xe59d, 0xe59d }, +/* 0xe59e */ { false, 0xe59e, 0xe59e }, +/* 0xe59f */ { false, 0xe59f, 0xe59f }, +/* 0xe5a0 */ { false, 0xe5a0, 0xe5a0 }, +/* 0xe5a1 */ { false, 0xe5a1, 0xe5a1 }, +/* 0xe5a2 */ { false, 0xe5a2, 0xe5a2 }, +/* 0xe5a3 */ { false, 0xe5a3, 0xe5a3 }, +/* 0xe5a4 */ { false, 0xe5a4, 0xe5a4 }, +/* 0xe5a5 */ { false, 0xe5a5, 0xe5a5 }, +/* 0xe5a6 */ { false, 0xe5a6, 0xe5a6 }, +/* 0xe5a7 */ { false, 0xe5a7, 0xe5a7 }, +/* 0xe5a8 */ { false, 0xe5a8, 0xe5a8 }, +/* 0xe5a9 */ { false, 0xe5a9, 0xe5a9 }, +/* 0xe5aa */ { false, 0xe5aa, 0xe5aa }, +/* 0xe5ab */ { false, 0xe5ab, 0xe5ab }, +/* 0xe5ac */ { false, 0xe5ac, 0xe5ac }, +/* 0xe5ad */ { false, 0xe5ad, 0xe5ad }, +/* 0xe5ae */ { false, 0xe5ae, 0xe5ae }, +/* 0xe5af */ { false, 0xe5af, 0xe5af }, +/* 0xe5b0 */ { false, 0xe5b0, 0xe5b0 }, +/* 0xe5b1 */ { false, 0xe5b1, 0xe5b1 }, +/* 0xe5b2 */ { false, 0xe5b2, 0xe5b2 }, +/* 0xe5b3 */ { false, 0xe5b3, 0xe5b3 }, +/* 0xe5b4 */ { false, 0xe5b4, 0xe5b4 }, +/* 0xe5b5 */ { false, 0xe5b5, 0xe5b5 }, +/* 0xe5b6 */ { false, 0xe5b6, 0xe5b6 }, +/* 0xe5b7 */ { false, 0xe5b7, 0xe5b7 }, +/* 0xe5b8 */ { false, 0xe5b8, 0xe5b8 }, +/* 0xe5b9 */ { false, 0xe5b9, 0xe5b9 }, +/* 0xe5ba */ { false, 0xe5ba, 0xe5ba }, +/* 0xe5bb */ { false, 0xe5bb, 0xe5bb }, +/* 0xe5bc */ { false, 0xe5bc, 0xe5bc }, +/* 0xe5bd */ { false, 0xe5bd, 0xe5bd }, +/* 0xe5be */ { false, 0xe5be, 0xe5be }, +/* 0xe5bf */ { false, 0xe5bf, 0xe5bf }, +/* 0xe5c0 */ { false, 0xe5c0, 0xe5c0 }, +/* 0xe5c1 */ { false, 0xe5c1, 0xe5c1 }, +/* 0xe5c2 */ { false, 0xe5c2, 0xe5c2 }, +/* 0xe5c3 */ { false, 0xe5c3, 0xe5c3 }, +/* 0xe5c4 */ { false, 0xe5c4, 0xe5c4 }, +/* 0xe5c5 */ { false, 0xe5c5, 0xe5c5 }, +/* 0xe5c6 */ { false, 0xe5c6, 0xe5c6 }, +/* 0xe5c7 */ { false, 0xe5c7, 0xe5c7 }, +/* 0xe5c8 */ { false, 0xe5c8, 0xe5c8 }, +/* 0xe5c9 */ { false, 0xe5c9, 0xe5c9 }, +/* 0xe5ca */ { false, 0xe5ca, 0xe5ca }, +/* 0xe5cb */ { false, 0xe5cb, 0xe5cb }, +/* 0xe5cc */ { false, 0xe5cc, 0xe5cc }, +/* 0xe5cd */ { false, 0xe5cd, 0xe5cd }, +/* 0xe5ce */ { false, 0xe5ce, 0xe5ce }, +/* 0xe5cf */ { false, 0xe5cf, 0xe5cf }, +/* 0xe5d0 */ { false, 0xe5d0, 0xe5d0 }, +/* 0xe5d1 */ { false, 0xe5d1, 0xe5d1 }, +/* 0xe5d2 */ { false, 0xe5d2, 0xe5d2 }, +/* 0xe5d3 */ { false, 0xe5d3, 0xe5d3 }, +/* 0xe5d4 */ { false, 0xe5d4, 0xe5d4 }, +/* 0xe5d5 */ { false, 0xe5d5, 0xe5d5 }, +/* 0xe5d6 */ { false, 0xe5d6, 0xe5d6 }, +/* 0xe5d7 */ { false, 0xe5d7, 0xe5d7 }, +/* 0xe5d8 */ { false, 0xe5d8, 0xe5d8 }, +/* 0xe5d9 */ { false, 0xe5d9, 0xe5d9 }, +/* 0xe5da */ { false, 0xe5da, 0xe5da }, +/* 0xe5db */ { false, 0xe5db, 0xe5db }, +/* 0xe5dc */ { false, 0xe5dc, 0xe5dc }, +/* 0xe5dd */ { false, 0xe5dd, 0xe5dd }, +/* 0xe5de */ { false, 0xe5de, 0xe5de }, +/* 0xe5df */ { false, 0xe5df, 0xe5df }, +/* 0xe5e0 */ { false, 0xe5e0, 0xe5e0 }, +/* 0xe5e1 */ { false, 0xe5e1, 0xe5e1 }, +/* 0xe5e2 */ { false, 0xe5e2, 0xe5e2 }, +/* 0xe5e3 */ { false, 0xe5e3, 0xe5e3 }, +/* 0xe5e4 */ { false, 0xe5e4, 0xe5e4 }, +/* 0xe5e5 */ { false, 0xe5e5, 0xe5e5 }, +/* 0xe5e6 */ { false, 0xe5e6, 0xe5e6 }, +/* 0xe5e7 */ { false, 0xe5e7, 0xe5e7 }, +/* 0xe5e8 */ { false, 0xe5e8, 0xe5e8 }, +/* 0xe5e9 */ { false, 0xe5e9, 0xe5e9 }, +/* 0xe5ea */ { false, 0xe5ea, 0xe5ea }, +/* 0xe5eb */ { false, 0xe5eb, 0xe5eb }, +/* 0xe5ec */ { false, 0xe5ec, 0xe5ec }, +/* 0xe5ed */ { false, 0xe5ed, 0xe5ed }, +/* 0xe5ee */ { false, 0xe5ee, 0xe5ee }, +/* 0xe5ef */ { false, 0xe5ef, 0xe5ef }, +/* 0xe5f0 */ { false, 0xe5f0, 0xe5f0 }, +/* 0xe5f1 */ { false, 0xe5f1, 0xe5f1 }, +/* 0xe5f2 */ { false, 0xe5f2, 0xe5f2 }, +/* 0xe5f3 */ { false, 0xe5f3, 0xe5f3 }, +/* 0xe5f4 */ { false, 0xe5f4, 0xe5f4 }, +/* 0xe5f5 */ { false, 0xe5f5, 0xe5f5 }, +/* 0xe5f6 */ { false, 0xe5f6, 0xe5f6 }, +/* 0xe5f7 */ { false, 0xe5f7, 0xe5f7 }, +/* 0xe5f8 */ { false, 0xe5f8, 0xe5f8 }, +/* 0xe5f9 */ { false, 0xe5f9, 0xe5f9 }, +/* 0xe5fa */ { false, 0xe5fa, 0xe5fa }, +/* 0xe5fb */ { false, 0xe5fb, 0xe5fb }, +/* 0xe5fc */ { false, 0xe5fc, 0xe5fc }, +/* 0xe5fd */ { false, 0xe5fd, 0xe5fd }, +/* 0xe5fe */ { false, 0xe5fe, 0xe5fe }, +/* 0xe5ff */ { false, 0xe5ff, 0xe5ff }, +/* 0xe600 */ { false, 0xe600, 0xe600 }, +/* 0xe601 */ { false, 0xe601, 0xe601 }, +/* 0xe602 */ { false, 0xe602, 0xe602 }, +/* 0xe603 */ { false, 0xe603, 0xe603 }, +/* 0xe604 */ { false, 0xe604, 0xe604 }, +/* 0xe605 */ { false, 0xe605, 0xe605 }, +/* 0xe606 */ { false, 0xe606, 0xe606 }, +/* 0xe607 */ { false, 0xe607, 0xe607 }, +/* 0xe608 */ { false, 0xe608, 0xe608 }, +/* 0xe609 */ { false, 0xe609, 0xe609 }, +/* 0xe60a */ { false, 0xe60a, 0xe60a }, +/* 0xe60b */ { false, 0xe60b, 0xe60b }, +/* 0xe60c */ { false, 0xe60c, 0xe60c }, +/* 0xe60d */ { false, 0xe60d, 0xe60d }, +/* 0xe60e */ { false, 0xe60e, 0xe60e }, +/* 0xe60f */ { false, 0xe60f, 0xe60f }, +/* 0xe610 */ { false, 0xe610, 0xe610 }, +/* 0xe611 */ { false, 0xe611, 0xe611 }, +/* 0xe612 */ { false, 0xe612, 0xe612 }, +/* 0xe613 */ { false, 0xe613, 0xe613 }, +/* 0xe614 */ { false, 0xe614, 0xe614 }, +/* 0xe615 */ { false, 0xe615, 0xe615 }, +/* 0xe616 */ { false, 0xe616, 0xe616 }, +/* 0xe617 */ { false, 0xe617, 0xe617 }, +/* 0xe618 */ { false, 0xe618, 0xe618 }, +/* 0xe619 */ { false, 0xe619, 0xe619 }, +/* 0xe61a */ { false, 0xe61a, 0xe61a }, +/* 0xe61b */ { false, 0xe61b, 0xe61b }, +/* 0xe61c */ { false, 0xe61c, 0xe61c }, +/* 0xe61d */ { false, 0xe61d, 0xe61d }, +/* 0xe61e */ { false, 0xe61e, 0xe61e }, +/* 0xe61f */ { false, 0xe61f, 0xe61f }, +/* 0xe620 */ { false, 0xe620, 0xe620 }, +/* 0xe621 */ { false, 0xe621, 0xe621 }, +/* 0xe622 */ { false, 0xe622, 0xe622 }, +/* 0xe623 */ { false, 0xe623, 0xe623 }, +/* 0xe624 */ { false, 0xe624, 0xe624 }, +/* 0xe625 */ { false, 0xe625, 0xe625 }, +/* 0xe626 */ { false, 0xe626, 0xe626 }, +/* 0xe627 */ { false, 0xe627, 0xe627 }, +/* 0xe628 */ { false, 0xe628, 0xe628 }, +/* 0xe629 */ { false, 0xe629, 0xe629 }, +/* 0xe62a */ { false, 0xe62a, 0xe62a }, +/* 0xe62b */ { false, 0xe62b, 0xe62b }, +/* 0xe62c */ { false, 0xe62c, 0xe62c }, +/* 0xe62d */ { false, 0xe62d, 0xe62d }, +/* 0xe62e */ { false, 0xe62e, 0xe62e }, +/* 0xe62f */ { false, 0xe62f, 0xe62f }, +/* 0xe630 */ { false, 0xe630, 0xe630 }, +/* 0xe631 */ { false, 0xe631, 0xe631 }, +/* 0xe632 */ { false, 0xe632, 0xe632 }, +/* 0xe633 */ { false, 0xe633, 0xe633 }, +/* 0xe634 */ { false, 0xe634, 0xe634 }, +/* 0xe635 */ { false, 0xe635, 0xe635 }, +/* 0xe636 */ { false, 0xe636, 0xe636 }, +/* 0xe637 */ { false, 0xe637, 0xe637 }, +/* 0xe638 */ { false, 0xe638, 0xe638 }, +/* 0xe639 */ { false, 0xe639, 0xe639 }, +/* 0xe63a */ { false, 0xe63a, 0xe63a }, +/* 0xe63b */ { false, 0xe63b, 0xe63b }, +/* 0xe63c */ { false, 0xe63c, 0xe63c }, +/* 0xe63d */ { false, 0xe63d, 0xe63d }, +/* 0xe63e */ { false, 0xe63e, 0xe63e }, +/* 0xe63f */ { false, 0xe63f, 0xe63f }, +/* 0xe640 */ { false, 0xe640, 0xe640 }, +/* 0xe641 */ { false, 0xe641, 0xe641 }, +/* 0xe642 */ { false, 0xe642, 0xe642 }, +/* 0xe643 */ { false, 0xe643, 0xe643 }, +/* 0xe644 */ { false, 0xe644, 0xe644 }, +/* 0xe645 */ { false, 0xe645, 0xe645 }, +/* 0xe646 */ { false, 0xe646, 0xe646 }, +/* 0xe647 */ { false, 0xe647, 0xe647 }, +/* 0xe648 */ { false, 0xe648, 0xe648 }, +/* 0xe649 */ { false, 0xe649, 0xe649 }, +/* 0xe64a */ { false, 0xe64a, 0xe64a }, +/* 0xe64b */ { false, 0xe64b, 0xe64b }, +/* 0xe64c */ { false, 0xe64c, 0xe64c }, +/* 0xe64d */ { false, 0xe64d, 0xe64d }, +/* 0xe64e */ { false, 0xe64e, 0xe64e }, +/* 0xe64f */ { false, 0xe64f, 0xe64f }, +/* 0xe650 */ { false, 0xe650, 0xe650 }, +/* 0xe651 */ { false, 0xe651, 0xe651 }, +/* 0xe652 */ { false, 0xe652, 0xe652 }, +/* 0xe653 */ { false, 0xe653, 0xe653 }, +/* 0xe654 */ { false, 0xe654, 0xe654 }, +/* 0xe655 */ { false, 0xe655, 0xe655 }, +/* 0xe656 */ { false, 0xe656, 0xe656 }, +/* 0xe657 */ { false, 0xe657, 0xe657 }, +/* 0xe658 */ { false, 0xe658, 0xe658 }, +/* 0xe659 */ { false, 0xe659, 0xe659 }, +/* 0xe65a */ { false, 0xe65a, 0xe65a }, +/* 0xe65b */ { false, 0xe65b, 0xe65b }, +/* 0xe65c */ { false, 0xe65c, 0xe65c }, +/* 0xe65d */ { false, 0xe65d, 0xe65d }, +/* 0xe65e */ { false, 0xe65e, 0xe65e }, +/* 0xe65f */ { false, 0xe65f, 0xe65f }, +/* 0xe660 */ { false, 0xe660, 0xe660 }, +/* 0xe661 */ { false, 0xe661, 0xe661 }, +/* 0xe662 */ { false, 0xe662, 0xe662 }, +/* 0xe663 */ { false, 0xe663, 0xe663 }, +/* 0xe664 */ { false, 0xe664, 0xe664 }, +/* 0xe665 */ { false, 0xe665, 0xe665 }, +/* 0xe666 */ { false, 0xe666, 0xe666 }, +/* 0xe667 */ { false, 0xe667, 0xe667 }, +/* 0xe668 */ { false, 0xe668, 0xe668 }, +/* 0xe669 */ { false, 0xe669, 0xe669 }, +/* 0xe66a */ { false, 0xe66a, 0xe66a }, +/* 0xe66b */ { false, 0xe66b, 0xe66b }, +/* 0xe66c */ { false, 0xe66c, 0xe66c }, +/* 0xe66d */ { false, 0xe66d, 0xe66d }, +/* 0xe66e */ { false, 0xe66e, 0xe66e }, +/* 0xe66f */ { false, 0xe66f, 0xe66f }, +/* 0xe670 */ { false, 0xe670, 0xe670 }, +/* 0xe671 */ { false, 0xe671, 0xe671 }, +/* 0xe672 */ { false, 0xe672, 0xe672 }, +/* 0xe673 */ { false, 0xe673, 0xe673 }, +/* 0xe674 */ { false, 0xe674, 0xe674 }, +/* 0xe675 */ { false, 0xe675, 0xe675 }, +/* 0xe676 */ { false, 0xe676, 0xe676 }, +/* 0xe677 */ { false, 0xe677, 0xe677 }, +/* 0xe678 */ { false, 0xe678, 0xe678 }, +/* 0xe679 */ { false, 0xe679, 0xe679 }, +/* 0xe67a */ { false, 0xe67a, 0xe67a }, +/* 0xe67b */ { false, 0xe67b, 0xe67b }, +/* 0xe67c */ { false, 0xe67c, 0xe67c }, +/* 0xe67d */ { false, 0xe67d, 0xe67d }, +/* 0xe67e */ { false, 0xe67e, 0xe67e }, +/* 0xe67f */ { false, 0xe67f, 0xe67f }, +/* 0xe680 */ { false, 0xe680, 0xe680 }, +/* 0xe681 */ { false, 0xe681, 0xe681 }, +/* 0xe682 */ { false, 0xe682, 0xe682 }, +/* 0xe683 */ { false, 0xe683, 0xe683 }, +/* 0xe684 */ { false, 0xe684, 0xe684 }, +/* 0xe685 */ { false, 0xe685, 0xe685 }, +/* 0xe686 */ { false, 0xe686, 0xe686 }, +/* 0xe687 */ { false, 0xe687, 0xe687 }, +/* 0xe688 */ { false, 0xe688, 0xe688 }, +/* 0xe689 */ { false, 0xe689, 0xe689 }, +/* 0xe68a */ { false, 0xe68a, 0xe68a }, +/* 0xe68b */ { false, 0xe68b, 0xe68b }, +/* 0xe68c */ { false, 0xe68c, 0xe68c }, +/* 0xe68d */ { false, 0xe68d, 0xe68d }, +/* 0xe68e */ { false, 0xe68e, 0xe68e }, +/* 0xe68f */ { false, 0xe68f, 0xe68f }, +/* 0xe690 */ { false, 0xe690, 0xe690 }, +/* 0xe691 */ { false, 0xe691, 0xe691 }, +/* 0xe692 */ { false, 0xe692, 0xe692 }, +/* 0xe693 */ { false, 0xe693, 0xe693 }, +/* 0xe694 */ { false, 0xe694, 0xe694 }, +/* 0xe695 */ { false, 0xe695, 0xe695 }, +/* 0xe696 */ { false, 0xe696, 0xe696 }, +/* 0xe697 */ { false, 0xe697, 0xe697 }, +/* 0xe698 */ { false, 0xe698, 0xe698 }, +/* 0xe699 */ { false, 0xe699, 0xe699 }, +/* 0xe69a */ { false, 0xe69a, 0xe69a }, +/* 0xe69b */ { false, 0xe69b, 0xe69b }, +/* 0xe69c */ { false, 0xe69c, 0xe69c }, +/* 0xe69d */ { false, 0xe69d, 0xe69d }, +/* 0xe69e */ { false, 0xe69e, 0xe69e }, +/* 0xe69f */ { false, 0xe69f, 0xe69f }, +/* 0xe6a0 */ { false, 0xe6a0, 0xe6a0 }, +/* 0xe6a1 */ { false, 0xe6a1, 0xe6a1 }, +/* 0xe6a2 */ { false, 0xe6a2, 0xe6a2 }, +/* 0xe6a3 */ { false, 0xe6a3, 0xe6a3 }, +/* 0xe6a4 */ { false, 0xe6a4, 0xe6a4 }, +/* 0xe6a5 */ { false, 0xe6a5, 0xe6a5 }, +/* 0xe6a6 */ { false, 0xe6a6, 0xe6a6 }, +/* 0xe6a7 */ { false, 0xe6a7, 0xe6a7 }, +/* 0xe6a8 */ { false, 0xe6a8, 0xe6a8 }, +/* 0xe6a9 */ { false, 0xe6a9, 0xe6a9 }, +/* 0xe6aa */ { false, 0xe6aa, 0xe6aa }, +/* 0xe6ab */ { false, 0xe6ab, 0xe6ab }, +/* 0xe6ac */ { false, 0xe6ac, 0xe6ac }, +/* 0xe6ad */ { false, 0xe6ad, 0xe6ad }, +/* 0xe6ae */ { false, 0xe6ae, 0xe6ae }, +/* 0xe6af */ { false, 0xe6af, 0xe6af }, +/* 0xe6b0 */ { false, 0xe6b0, 0xe6b0 }, +/* 0xe6b1 */ { false, 0xe6b1, 0xe6b1 }, +/* 0xe6b2 */ { false, 0xe6b2, 0xe6b2 }, +/* 0xe6b3 */ { false, 0xe6b3, 0xe6b3 }, +/* 0xe6b4 */ { false, 0xe6b4, 0xe6b4 }, +/* 0xe6b5 */ { false, 0xe6b5, 0xe6b5 }, +/* 0xe6b6 */ { false, 0xe6b6, 0xe6b6 }, +/* 0xe6b7 */ { false, 0xe6b7, 0xe6b7 }, +/* 0xe6b8 */ { false, 0xe6b8, 0xe6b8 }, +/* 0xe6b9 */ { false, 0xe6b9, 0xe6b9 }, +/* 0xe6ba */ { false, 0xe6ba, 0xe6ba }, +/* 0xe6bb */ { false, 0xe6bb, 0xe6bb }, +/* 0xe6bc */ { false, 0xe6bc, 0xe6bc }, +/* 0xe6bd */ { false, 0xe6bd, 0xe6bd }, +/* 0xe6be */ { false, 0xe6be, 0xe6be }, +/* 0xe6bf */ { false, 0xe6bf, 0xe6bf }, +/* 0xe6c0 */ { false, 0xe6c0, 0xe6c0 }, +/* 0xe6c1 */ { false, 0xe6c1, 0xe6c1 }, +/* 0xe6c2 */ { false, 0xe6c2, 0xe6c2 }, +/* 0xe6c3 */ { false, 0xe6c3, 0xe6c3 }, +/* 0xe6c4 */ { false, 0xe6c4, 0xe6c4 }, +/* 0xe6c5 */ { false, 0xe6c5, 0xe6c5 }, +/* 0xe6c6 */ { false, 0xe6c6, 0xe6c6 }, +/* 0xe6c7 */ { false, 0xe6c7, 0xe6c7 }, +/* 0xe6c8 */ { false, 0xe6c8, 0xe6c8 }, +/* 0xe6c9 */ { false, 0xe6c9, 0xe6c9 }, +/* 0xe6ca */ { false, 0xe6ca, 0xe6ca }, +/* 0xe6cb */ { false, 0xe6cb, 0xe6cb }, +/* 0xe6cc */ { false, 0xe6cc, 0xe6cc }, +/* 0xe6cd */ { false, 0xe6cd, 0xe6cd }, +/* 0xe6ce */ { false, 0xe6ce, 0xe6ce }, +/* 0xe6cf */ { false, 0xe6cf, 0xe6cf }, +/* 0xe6d0 */ { false, 0xe6d0, 0xe6d0 }, +/* 0xe6d1 */ { false, 0xe6d1, 0xe6d1 }, +/* 0xe6d2 */ { false, 0xe6d2, 0xe6d2 }, +/* 0xe6d3 */ { false, 0xe6d3, 0xe6d3 }, +/* 0xe6d4 */ { false, 0xe6d4, 0xe6d4 }, +/* 0xe6d5 */ { false, 0xe6d5, 0xe6d5 }, +/* 0xe6d6 */ { false, 0xe6d6, 0xe6d6 }, +/* 0xe6d7 */ { false, 0xe6d7, 0xe6d7 }, +/* 0xe6d8 */ { false, 0xe6d8, 0xe6d8 }, +/* 0xe6d9 */ { false, 0xe6d9, 0xe6d9 }, +/* 0xe6da */ { false, 0xe6da, 0xe6da }, +/* 0xe6db */ { false, 0xe6db, 0xe6db }, +/* 0xe6dc */ { false, 0xe6dc, 0xe6dc }, +/* 0xe6dd */ { false, 0xe6dd, 0xe6dd }, +/* 0xe6de */ { false, 0xe6de, 0xe6de }, +/* 0xe6df */ { false, 0xe6df, 0xe6df }, +/* 0xe6e0 */ { false, 0xe6e0, 0xe6e0 }, +/* 0xe6e1 */ { false, 0xe6e1, 0xe6e1 }, +/* 0xe6e2 */ { false, 0xe6e2, 0xe6e2 }, +/* 0xe6e3 */ { false, 0xe6e3, 0xe6e3 }, +/* 0xe6e4 */ { false, 0xe6e4, 0xe6e4 }, +/* 0xe6e5 */ { false, 0xe6e5, 0xe6e5 }, +/* 0xe6e6 */ { false, 0xe6e6, 0xe6e6 }, +/* 0xe6e7 */ { false, 0xe6e7, 0xe6e7 }, +/* 0xe6e8 */ { false, 0xe6e8, 0xe6e8 }, +/* 0xe6e9 */ { false, 0xe6e9, 0xe6e9 }, +/* 0xe6ea */ { false, 0xe6ea, 0xe6ea }, +/* 0xe6eb */ { false, 0xe6eb, 0xe6eb }, +/* 0xe6ec */ { false, 0xe6ec, 0xe6ec }, +/* 0xe6ed */ { false, 0xe6ed, 0xe6ed }, +/* 0xe6ee */ { false, 0xe6ee, 0xe6ee }, +/* 0xe6ef */ { false, 0xe6ef, 0xe6ef }, +/* 0xe6f0 */ { false, 0xe6f0, 0xe6f0 }, +/* 0xe6f1 */ { false, 0xe6f1, 0xe6f1 }, +/* 0xe6f2 */ { false, 0xe6f2, 0xe6f2 }, +/* 0xe6f3 */ { false, 0xe6f3, 0xe6f3 }, +/* 0xe6f4 */ { false, 0xe6f4, 0xe6f4 }, +/* 0xe6f5 */ { false, 0xe6f5, 0xe6f5 }, +/* 0xe6f6 */ { false, 0xe6f6, 0xe6f6 }, +/* 0xe6f7 */ { false, 0xe6f7, 0xe6f7 }, +/* 0xe6f8 */ { false, 0xe6f8, 0xe6f8 }, +/* 0xe6f9 */ { false, 0xe6f9, 0xe6f9 }, +/* 0xe6fa */ { false, 0xe6fa, 0xe6fa }, +/* 0xe6fb */ { false, 0xe6fb, 0xe6fb }, +/* 0xe6fc */ { false, 0xe6fc, 0xe6fc }, +/* 0xe6fd */ { false, 0xe6fd, 0xe6fd }, +/* 0xe6fe */ { false, 0xe6fe, 0xe6fe }, +/* 0xe6ff */ { false, 0xe6ff, 0xe6ff }, +/* 0xe700 */ { false, 0xe700, 0xe700 }, +/* 0xe701 */ { false, 0xe701, 0xe701 }, +/* 0xe702 */ { false, 0xe702, 0xe702 }, +/* 0xe703 */ { false, 0xe703, 0xe703 }, +/* 0xe704 */ { false, 0xe704, 0xe704 }, +/* 0xe705 */ { false, 0xe705, 0xe705 }, +/* 0xe706 */ { false, 0xe706, 0xe706 }, +/* 0xe707 */ { false, 0xe707, 0xe707 }, +/* 0xe708 */ { false, 0xe708, 0xe708 }, +/* 0xe709 */ { false, 0xe709, 0xe709 }, +/* 0xe70a */ { false, 0xe70a, 0xe70a }, +/* 0xe70b */ { false, 0xe70b, 0xe70b }, +/* 0xe70c */ { false, 0xe70c, 0xe70c }, +/* 0xe70d */ { false, 0xe70d, 0xe70d }, +/* 0xe70e */ { false, 0xe70e, 0xe70e }, +/* 0xe70f */ { false, 0xe70f, 0xe70f }, +/* 0xe710 */ { false, 0xe710, 0xe710 }, +/* 0xe711 */ { false, 0xe711, 0xe711 }, +/* 0xe712 */ { false, 0xe712, 0xe712 }, +/* 0xe713 */ { false, 0xe713, 0xe713 }, +/* 0xe714 */ { false, 0xe714, 0xe714 }, +/* 0xe715 */ { false, 0xe715, 0xe715 }, +/* 0xe716 */ { false, 0xe716, 0xe716 }, +/* 0xe717 */ { false, 0xe717, 0xe717 }, +/* 0xe718 */ { false, 0xe718, 0xe718 }, +/* 0xe719 */ { false, 0xe719, 0xe719 }, +/* 0xe71a */ { false, 0xe71a, 0xe71a }, +/* 0xe71b */ { false, 0xe71b, 0xe71b }, +/* 0xe71c */ { false, 0xe71c, 0xe71c }, +/* 0xe71d */ { false, 0xe71d, 0xe71d }, +/* 0xe71e */ { false, 0xe71e, 0xe71e }, +/* 0xe71f */ { false, 0xe71f, 0xe71f }, +/* 0xe720 */ { false, 0xe720, 0xe720 }, +/* 0xe721 */ { false, 0xe721, 0xe721 }, +/* 0xe722 */ { false, 0xe722, 0xe722 }, +/* 0xe723 */ { false, 0xe723, 0xe723 }, +/* 0xe724 */ { false, 0xe724, 0xe724 }, +/* 0xe725 */ { false, 0xe725, 0xe725 }, +/* 0xe726 */ { false, 0xe726, 0xe726 }, +/* 0xe727 */ { false, 0xe727, 0xe727 }, +/* 0xe728 */ { false, 0xe728, 0xe728 }, +/* 0xe729 */ { false, 0xe729, 0xe729 }, +/* 0xe72a */ { false, 0xe72a, 0xe72a }, +/* 0xe72b */ { false, 0xe72b, 0xe72b }, +/* 0xe72c */ { false, 0xe72c, 0xe72c }, +/* 0xe72d */ { false, 0xe72d, 0xe72d }, +/* 0xe72e */ { false, 0xe72e, 0xe72e }, +/* 0xe72f */ { false, 0xe72f, 0xe72f }, +/* 0xe730 */ { false, 0xe730, 0xe730 }, +/* 0xe731 */ { false, 0xe731, 0xe731 }, +/* 0xe732 */ { false, 0xe732, 0xe732 }, +/* 0xe733 */ { false, 0xe733, 0xe733 }, +/* 0xe734 */ { false, 0xe734, 0xe734 }, +/* 0xe735 */ { false, 0xe735, 0xe735 }, +/* 0xe736 */ { false, 0xe736, 0xe736 }, +/* 0xe737 */ { false, 0xe737, 0xe737 }, +/* 0xe738 */ { false, 0xe738, 0xe738 }, +/* 0xe739 */ { false, 0xe739, 0xe739 }, +/* 0xe73a */ { false, 0xe73a, 0xe73a }, +/* 0xe73b */ { false, 0xe73b, 0xe73b }, +/* 0xe73c */ { false, 0xe73c, 0xe73c }, +/* 0xe73d */ { false, 0xe73d, 0xe73d }, +/* 0xe73e */ { false, 0xe73e, 0xe73e }, +/* 0xe73f */ { false, 0xe73f, 0xe73f }, +/* 0xe740 */ { false, 0xe740, 0xe740 }, +/* 0xe741 */ { false, 0xe741, 0xe741 }, +/* 0xe742 */ { false, 0xe742, 0xe742 }, +/* 0xe743 */ { false, 0xe743, 0xe743 }, +/* 0xe744 */ { false, 0xe744, 0xe744 }, +/* 0xe745 */ { false, 0xe745, 0xe745 }, +/* 0xe746 */ { false, 0xe746, 0xe746 }, +/* 0xe747 */ { false, 0xe747, 0xe747 }, +/* 0xe748 */ { false, 0xe748, 0xe748 }, +/* 0xe749 */ { false, 0xe749, 0xe749 }, +/* 0xe74a */ { false, 0xe74a, 0xe74a }, +/* 0xe74b */ { false, 0xe74b, 0xe74b }, +/* 0xe74c */ { false, 0xe74c, 0xe74c }, +/* 0xe74d */ { false, 0xe74d, 0xe74d }, +/* 0xe74e */ { false, 0xe74e, 0xe74e }, +/* 0xe74f */ { false, 0xe74f, 0xe74f }, +/* 0xe750 */ { false, 0xe750, 0xe750 }, +/* 0xe751 */ { false, 0xe751, 0xe751 }, +/* 0xe752 */ { false, 0xe752, 0xe752 }, +/* 0xe753 */ { false, 0xe753, 0xe753 }, +/* 0xe754 */ { false, 0xe754, 0xe754 }, +/* 0xe755 */ { false, 0xe755, 0xe755 }, +/* 0xe756 */ { false, 0xe756, 0xe756 }, +/* 0xe757 */ { false, 0xe757, 0xe757 }, +/* 0xe758 */ { false, 0xe758, 0xe758 }, +/* 0xe759 */ { false, 0xe759, 0xe759 }, +/* 0xe75a */ { false, 0xe75a, 0xe75a }, +/* 0xe75b */ { false, 0xe75b, 0xe75b }, +/* 0xe75c */ { false, 0xe75c, 0xe75c }, +/* 0xe75d */ { false, 0xe75d, 0xe75d }, +/* 0xe75e */ { false, 0xe75e, 0xe75e }, +/* 0xe75f */ { false, 0xe75f, 0xe75f }, +/* 0xe760 */ { false, 0xe760, 0xe760 }, +/* 0xe761 */ { false, 0xe761, 0xe761 }, +/* 0xe762 */ { false, 0xe762, 0xe762 }, +/* 0xe763 */ { false, 0xe763, 0xe763 }, +/* 0xe764 */ { false, 0xe764, 0xe764 }, +/* 0xe765 */ { false, 0xe765, 0xe765 }, +/* 0xe766 */ { false, 0xe766, 0xe766 }, +/* 0xe767 */ { false, 0xe767, 0xe767 }, +/* 0xe768 */ { false, 0xe768, 0xe768 }, +/* 0xe769 */ { false, 0xe769, 0xe769 }, +/* 0xe76a */ { false, 0xe76a, 0xe76a }, +/* 0xe76b */ { false, 0xe76b, 0xe76b }, +/* 0xe76c */ { false, 0xe76c, 0xe76c }, +/* 0xe76d */ { false, 0xe76d, 0xe76d }, +/* 0xe76e */ { false, 0xe76e, 0xe76e }, +/* 0xe76f */ { false, 0xe76f, 0xe76f }, +/* 0xe770 */ { false, 0xe770, 0xe770 }, +/* 0xe771 */ { false, 0xe771, 0xe771 }, +/* 0xe772 */ { false, 0xe772, 0xe772 }, +/* 0xe773 */ { false, 0xe773, 0xe773 }, +/* 0xe774 */ { false, 0xe774, 0xe774 }, +/* 0xe775 */ { false, 0xe775, 0xe775 }, +/* 0xe776 */ { false, 0xe776, 0xe776 }, +/* 0xe777 */ { false, 0xe777, 0xe777 }, +/* 0xe778 */ { false, 0xe778, 0xe778 }, +/* 0xe779 */ { false, 0xe779, 0xe779 }, +/* 0xe77a */ { false, 0xe77a, 0xe77a }, +/* 0xe77b */ { false, 0xe77b, 0xe77b }, +/* 0xe77c */ { false, 0xe77c, 0xe77c }, +/* 0xe77d */ { false, 0xe77d, 0xe77d }, +/* 0xe77e */ { false, 0xe77e, 0xe77e }, +/* 0xe77f */ { false, 0xe77f, 0xe77f }, +/* 0xe780 */ { false, 0xe780, 0xe780 }, +/* 0xe781 */ { false, 0xe781, 0xe781 }, +/* 0xe782 */ { false, 0xe782, 0xe782 }, +/* 0xe783 */ { false, 0xe783, 0xe783 }, +/* 0xe784 */ { false, 0xe784, 0xe784 }, +/* 0xe785 */ { false, 0xe785, 0xe785 }, +/* 0xe786 */ { false, 0xe786, 0xe786 }, +/* 0xe787 */ { false, 0xe787, 0xe787 }, +/* 0xe788 */ { false, 0xe788, 0xe788 }, +/* 0xe789 */ { false, 0xe789, 0xe789 }, +/* 0xe78a */ { false, 0xe78a, 0xe78a }, +/* 0xe78b */ { false, 0xe78b, 0xe78b }, +/* 0xe78c */ { false, 0xe78c, 0xe78c }, +/* 0xe78d */ { false, 0xe78d, 0xe78d }, +/* 0xe78e */ { false, 0xe78e, 0xe78e }, +/* 0xe78f */ { false, 0xe78f, 0xe78f }, +/* 0xe790 */ { false, 0xe790, 0xe790 }, +/* 0xe791 */ { false, 0xe791, 0xe791 }, +/* 0xe792 */ { false, 0xe792, 0xe792 }, +/* 0xe793 */ { false, 0xe793, 0xe793 }, +/* 0xe794 */ { false, 0xe794, 0xe794 }, +/* 0xe795 */ { false, 0xe795, 0xe795 }, +/* 0xe796 */ { false, 0xe796, 0xe796 }, +/* 0xe797 */ { false, 0xe797, 0xe797 }, +/* 0xe798 */ { false, 0xe798, 0xe798 }, +/* 0xe799 */ { false, 0xe799, 0xe799 }, +/* 0xe79a */ { false, 0xe79a, 0xe79a }, +/* 0xe79b */ { false, 0xe79b, 0xe79b }, +/* 0xe79c */ { false, 0xe79c, 0xe79c }, +/* 0xe79d */ { false, 0xe79d, 0xe79d }, +/* 0xe79e */ { false, 0xe79e, 0xe79e }, +/* 0xe79f */ { false, 0xe79f, 0xe79f }, +/* 0xe7a0 */ { false, 0xe7a0, 0xe7a0 }, +/* 0xe7a1 */ { false, 0xe7a1, 0xe7a1 }, +/* 0xe7a2 */ { false, 0xe7a2, 0xe7a2 }, +/* 0xe7a3 */ { false, 0xe7a3, 0xe7a3 }, +/* 0xe7a4 */ { false, 0xe7a4, 0xe7a4 }, +/* 0xe7a5 */ { false, 0xe7a5, 0xe7a5 }, +/* 0xe7a6 */ { false, 0xe7a6, 0xe7a6 }, +/* 0xe7a7 */ { false, 0xe7a7, 0xe7a7 }, +/* 0xe7a8 */ { false, 0xe7a8, 0xe7a8 }, +/* 0xe7a9 */ { false, 0xe7a9, 0xe7a9 }, +/* 0xe7aa */ { false, 0xe7aa, 0xe7aa }, +/* 0xe7ab */ { false, 0xe7ab, 0xe7ab }, +/* 0xe7ac */ { false, 0xe7ac, 0xe7ac }, +/* 0xe7ad */ { false, 0xe7ad, 0xe7ad }, +/* 0xe7ae */ { false, 0xe7ae, 0xe7ae }, +/* 0xe7af */ { false, 0xe7af, 0xe7af }, +/* 0xe7b0 */ { false, 0xe7b0, 0xe7b0 }, +/* 0xe7b1 */ { false, 0xe7b1, 0xe7b1 }, +/* 0xe7b2 */ { false, 0xe7b2, 0xe7b2 }, +/* 0xe7b3 */ { false, 0xe7b3, 0xe7b3 }, +/* 0xe7b4 */ { false, 0xe7b4, 0xe7b4 }, +/* 0xe7b5 */ { false, 0xe7b5, 0xe7b5 }, +/* 0xe7b6 */ { false, 0xe7b6, 0xe7b6 }, +/* 0xe7b7 */ { false, 0xe7b7, 0xe7b7 }, +/* 0xe7b8 */ { false, 0xe7b8, 0xe7b8 }, +/* 0xe7b9 */ { false, 0xe7b9, 0xe7b9 }, +/* 0xe7ba */ { false, 0xe7ba, 0xe7ba }, +/* 0xe7bb */ { false, 0xe7bb, 0xe7bb }, +/* 0xe7bc */ { false, 0xe7bc, 0xe7bc }, +/* 0xe7bd */ { false, 0xe7bd, 0xe7bd }, +/* 0xe7be */ { false, 0xe7be, 0xe7be }, +/* 0xe7bf */ { false, 0xe7bf, 0xe7bf }, +/* 0xe7c0 */ { false, 0xe7c0, 0xe7c0 }, +/* 0xe7c1 */ { false, 0xe7c1, 0xe7c1 }, +/* 0xe7c2 */ { false, 0xe7c2, 0xe7c2 }, +/* 0xe7c3 */ { false, 0xe7c3, 0xe7c3 }, +/* 0xe7c4 */ { false, 0xe7c4, 0xe7c4 }, +/* 0xe7c5 */ { false, 0xe7c5, 0xe7c5 }, +/* 0xe7c6 */ { false, 0xe7c6, 0xe7c6 }, +/* 0xe7c7 */ { false, 0xe7c7, 0xe7c7 }, +/* 0xe7c8 */ { false, 0xe7c8, 0xe7c8 }, +/* 0xe7c9 */ { false, 0xe7c9, 0xe7c9 }, +/* 0xe7ca */ { false, 0xe7ca, 0xe7ca }, +/* 0xe7cb */ { false, 0xe7cb, 0xe7cb }, +/* 0xe7cc */ { false, 0xe7cc, 0xe7cc }, +/* 0xe7cd */ { false, 0xe7cd, 0xe7cd }, +/* 0xe7ce */ { false, 0xe7ce, 0xe7ce }, +/* 0xe7cf */ { false, 0xe7cf, 0xe7cf }, +/* 0xe7d0 */ { false, 0xe7d0, 0xe7d0 }, +/* 0xe7d1 */ { false, 0xe7d1, 0xe7d1 }, +/* 0xe7d2 */ { false, 0xe7d2, 0xe7d2 }, +/* 0xe7d3 */ { false, 0xe7d3, 0xe7d3 }, +/* 0xe7d4 */ { false, 0xe7d4, 0xe7d4 }, +/* 0xe7d5 */ { false, 0xe7d5, 0xe7d5 }, +/* 0xe7d6 */ { false, 0xe7d6, 0xe7d6 }, +/* 0xe7d7 */ { false, 0xe7d7, 0xe7d7 }, +/* 0xe7d8 */ { false, 0xe7d8, 0xe7d8 }, +/* 0xe7d9 */ { false, 0xe7d9, 0xe7d9 }, +/* 0xe7da */ { false, 0xe7da, 0xe7da }, +/* 0xe7db */ { false, 0xe7db, 0xe7db }, +/* 0xe7dc */ { false, 0xe7dc, 0xe7dc }, +/* 0xe7dd */ { false, 0xe7dd, 0xe7dd }, +/* 0xe7de */ { false, 0xe7de, 0xe7de }, +/* 0xe7df */ { false, 0xe7df, 0xe7df }, +/* 0xe7e0 */ { false, 0xe7e0, 0xe7e0 }, +/* 0xe7e1 */ { false, 0xe7e1, 0xe7e1 }, +/* 0xe7e2 */ { false, 0xe7e2, 0xe7e2 }, +/* 0xe7e3 */ { false, 0xe7e3, 0xe7e3 }, +/* 0xe7e4 */ { false, 0xe7e4, 0xe7e4 }, +/* 0xe7e5 */ { false, 0xe7e5, 0xe7e5 }, +/* 0xe7e6 */ { false, 0xe7e6, 0xe7e6 }, +/* 0xe7e7 */ { false, 0xe7e7, 0xe7e7 }, +/* 0xe7e8 */ { false, 0xe7e8, 0xe7e8 }, +/* 0xe7e9 */ { false, 0xe7e9, 0xe7e9 }, +/* 0xe7ea */ { false, 0xe7ea, 0xe7ea }, +/* 0xe7eb */ { false, 0xe7eb, 0xe7eb }, +/* 0xe7ec */ { false, 0xe7ec, 0xe7ec }, +/* 0xe7ed */ { false, 0xe7ed, 0xe7ed }, +/* 0xe7ee */ { false, 0xe7ee, 0xe7ee }, +/* 0xe7ef */ { false, 0xe7ef, 0xe7ef }, +/* 0xe7f0 */ { false, 0xe7f0, 0xe7f0 }, +/* 0xe7f1 */ { false, 0xe7f1, 0xe7f1 }, +/* 0xe7f2 */ { false, 0xe7f2, 0xe7f2 }, +/* 0xe7f3 */ { false, 0xe7f3, 0xe7f3 }, +/* 0xe7f4 */ { false, 0xe7f4, 0xe7f4 }, +/* 0xe7f5 */ { false, 0xe7f5, 0xe7f5 }, +/* 0xe7f6 */ { false, 0xe7f6, 0xe7f6 }, +/* 0xe7f7 */ { false, 0xe7f7, 0xe7f7 }, +/* 0xe7f8 */ { false, 0xe7f8, 0xe7f8 }, +/* 0xe7f9 */ { false, 0xe7f9, 0xe7f9 }, +/* 0xe7fa */ { false, 0xe7fa, 0xe7fa }, +/* 0xe7fb */ { false, 0xe7fb, 0xe7fb }, +/* 0xe7fc */ { false, 0xe7fc, 0xe7fc }, +/* 0xe7fd */ { false, 0xe7fd, 0xe7fd }, +/* 0xe7fe */ { false, 0xe7fe, 0xe7fe }, +/* 0xe7ff */ { false, 0xe7ff, 0xe7ff }, +/* 0xe800 */ { false, 0xe800, 0xe800 }, +/* 0xe801 */ { false, 0xe801, 0xe801 }, +/* 0xe802 */ { false, 0xe802, 0xe802 }, +/* 0xe803 */ { false, 0xe803, 0xe803 }, +/* 0xe804 */ { false, 0xe804, 0xe804 }, +/* 0xe805 */ { false, 0xe805, 0xe805 }, +/* 0xe806 */ { false, 0xe806, 0xe806 }, +/* 0xe807 */ { false, 0xe807, 0xe807 }, +/* 0xe808 */ { false, 0xe808, 0xe808 }, +/* 0xe809 */ { false, 0xe809, 0xe809 }, +/* 0xe80a */ { false, 0xe80a, 0xe80a }, +/* 0xe80b */ { false, 0xe80b, 0xe80b }, +/* 0xe80c */ { false, 0xe80c, 0xe80c }, +/* 0xe80d */ { false, 0xe80d, 0xe80d }, +/* 0xe80e */ { false, 0xe80e, 0xe80e }, +/* 0xe80f */ { false, 0xe80f, 0xe80f }, +/* 0xe810 */ { false, 0xe810, 0xe810 }, +/* 0xe811 */ { false, 0xe811, 0xe811 }, +/* 0xe812 */ { false, 0xe812, 0xe812 }, +/* 0xe813 */ { false, 0xe813, 0xe813 }, +/* 0xe814 */ { false, 0xe814, 0xe814 }, +/* 0xe815 */ { false, 0xe815, 0xe815 }, +/* 0xe816 */ { false, 0xe816, 0xe816 }, +/* 0xe817 */ { false, 0xe817, 0xe817 }, +/* 0xe818 */ { false, 0xe818, 0xe818 }, +/* 0xe819 */ { false, 0xe819, 0xe819 }, +/* 0xe81a */ { false, 0xe81a, 0xe81a }, +/* 0xe81b */ { false, 0xe81b, 0xe81b }, +/* 0xe81c */ { false, 0xe81c, 0xe81c }, +/* 0xe81d */ { false, 0xe81d, 0xe81d }, +/* 0xe81e */ { false, 0xe81e, 0xe81e }, +/* 0xe81f */ { false, 0xe81f, 0xe81f }, +/* 0xe820 */ { false, 0xe820, 0xe820 }, +/* 0xe821 */ { false, 0xe821, 0xe821 }, +/* 0xe822 */ { false, 0xe822, 0xe822 }, +/* 0xe823 */ { false, 0xe823, 0xe823 }, +/* 0xe824 */ { false, 0xe824, 0xe824 }, +/* 0xe825 */ { false, 0xe825, 0xe825 }, +/* 0xe826 */ { false, 0xe826, 0xe826 }, +/* 0xe827 */ { false, 0xe827, 0xe827 }, +/* 0xe828 */ { false, 0xe828, 0xe828 }, +/* 0xe829 */ { false, 0xe829, 0xe829 }, +/* 0xe82a */ { false, 0xe82a, 0xe82a }, +/* 0xe82b */ { false, 0xe82b, 0xe82b }, +/* 0xe82c */ { false, 0xe82c, 0xe82c }, +/* 0xe82d */ { false, 0xe82d, 0xe82d }, +/* 0xe82e */ { false, 0xe82e, 0xe82e }, +/* 0xe82f */ { false, 0xe82f, 0xe82f }, +/* 0xe830 */ { false, 0xe830, 0xe830 }, +/* 0xe831 */ { false, 0xe831, 0xe831 }, +/* 0xe832 */ { false, 0xe832, 0xe832 }, +/* 0xe833 */ { false, 0xe833, 0xe833 }, +/* 0xe834 */ { false, 0xe834, 0xe834 }, +/* 0xe835 */ { false, 0xe835, 0xe835 }, +/* 0xe836 */ { false, 0xe836, 0xe836 }, +/* 0xe837 */ { false, 0xe837, 0xe837 }, +/* 0xe838 */ { false, 0xe838, 0xe838 }, +/* 0xe839 */ { false, 0xe839, 0xe839 }, +/* 0xe83a */ { false, 0xe83a, 0xe83a }, +/* 0xe83b */ { false, 0xe83b, 0xe83b }, +/* 0xe83c */ { false, 0xe83c, 0xe83c }, +/* 0xe83d */ { false, 0xe83d, 0xe83d }, +/* 0xe83e */ { false, 0xe83e, 0xe83e }, +/* 0xe83f */ { false, 0xe83f, 0xe83f }, +/* 0xe840 */ { false, 0xe840, 0xe840 }, +/* 0xe841 */ { false, 0xe841, 0xe841 }, +/* 0xe842 */ { false, 0xe842, 0xe842 }, +/* 0xe843 */ { false, 0xe843, 0xe843 }, +/* 0xe844 */ { false, 0xe844, 0xe844 }, +/* 0xe845 */ { false, 0xe845, 0xe845 }, +/* 0xe846 */ { false, 0xe846, 0xe846 }, +/* 0xe847 */ { false, 0xe847, 0xe847 }, +/* 0xe848 */ { false, 0xe848, 0xe848 }, +/* 0xe849 */ { false, 0xe849, 0xe849 }, +/* 0xe84a */ { false, 0xe84a, 0xe84a }, +/* 0xe84b */ { false, 0xe84b, 0xe84b }, +/* 0xe84c */ { false, 0xe84c, 0xe84c }, +/* 0xe84d */ { false, 0xe84d, 0xe84d }, +/* 0xe84e */ { false, 0xe84e, 0xe84e }, +/* 0xe84f */ { false, 0xe84f, 0xe84f }, +/* 0xe850 */ { false, 0xe850, 0xe850 }, +/* 0xe851 */ { false, 0xe851, 0xe851 }, +/* 0xe852 */ { false, 0xe852, 0xe852 }, +/* 0xe853 */ { false, 0xe853, 0xe853 }, +/* 0xe854 */ { false, 0xe854, 0xe854 }, +/* 0xe855 */ { false, 0xe855, 0xe855 }, +/* 0xe856 */ { false, 0xe856, 0xe856 }, +/* 0xe857 */ { false, 0xe857, 0xe857 }, +/* 0xe858 */ { false, 0xe858, 0xe858 }, +/* 0xe859 */ { false, 0xe859, 0xe859 }, +/* 0xe85a */ { false, 0xe85a, 0xe85a }, +/* 0xe85b */ { false, 0xe85b, 0xe85b }, +/* 0xe85c */ { false, 0xe85c, 0xe85c }, +/* 0xe85d */ { false, 0xe85d, 0xe85d }, +/* 0xe85e */ { false, 0xe85e, 0xe85e }, +/* 0xe85f */ { false, 0xe85f, 0xe85f }, +/* 0xe860 */ { false, 0xe860, 0xe860 }, +/* 0xe861 */ { false, 0xe861, 0xe861 }, +/* 0xe862 */ { false, 0xe862, 0xe862 }, +/* 0xe863 */ { false, 0xe863, 0xe863 }, +/* 0xe864 */ { false, 0xe864, 0xe864 }, +/* 0xe865 */ { false, 0xe865, 0xe865 }, +/* 0xe866 */ { false, 0xe866, 0xe866 }, +/* 0xe867 */ { false, 0xe867, 0xe867 }, +/* 0xe868 */ { false, 0xe868, 0xe868 }, +/* 0xe869 */ { false, 0xe869, 0xe869 }, +/* 0xe86a */ { false, 0xe86a, 0xe86a }, +/* 0xe86b */ { false, 0xe86b, 0xe86b }, +/* 0xe86c */ { false, 0xe86c, 0xe86c }, +/* 0xe86d */ { false, 0xe86d, 0xe86d }, +/* 0xe86e */ { false, 0xe86e, 0xe86e }, +/* 0xe86f */ { false, 0xe86f, 0xe86f }, +/* 0xe870 */ { false, 0xe870, 0xe870 }, +/* 0xe871 */ { false, 0xe871, 0xe871 }, +/* 0xe872 */ { false, 0xe872, 0xe872 }, +/* 0xe873 */ { false, 0xe873, 0xe873 }, +/* 0xe874 */ { false, 0xe874, 0xe874 }, +/* 0xe875 */ { false, 0xe875, 0xe875 }, +/* 0xe876 */ { false, 0xe876, 0xe876 }, +/* 0xe877 */ { false, 0xe877, 0xe877 }, +/* 0xe878 */ { false, 0xe878, 0xe878 }, +/* 0xe879 */ { false, 0xe879, 0xe879 }, +/* 0xe87a */ { false, 0xe87a, 0xe87a }, +/* 0xe87b */ { false, 0xe87b, 0xe87b }, +/* 0xe87c */ { false, 0xe87c, 0xe87c }, +/* 0xe87d */ { false, 0xe87d, 0xe87d }, +/* 0xe87e */ { false, 0xe87e, 0xe87e }, +/* 0xe87f */ { false, 0xe87f, 0xe87f }, +/* 0xe880 */ { false, 0xe880, 0xe880 }, +/* 0xe881 */ { false, 0xe881, 0xe881 }, +/* 0xe882 */ { false, 0xe882, 0xe882 }, +/* 0xe883 */ { false, 0xe883, 0xe883 }, +/* 0xe884 */ { false, 0xe884, 0xe884 }, +/* 0xe885 */ { false, 0xe885, 0xe885 }, +/* 0xe886 */ { false, 0xe886, 0xe886 }, +/* 0xe887 */ { false, 0xe887, 0xe887 }, +/* 0xe888 */ { false, 0xe888, 0xe888 }, +/* 0xe889 */ { false, 0xe889, 0xe889 }, +/* 0xe88a */ { false, 0xe88a, 0xe88a }, +/* 0xe88b */ { false, 0xe88b, 0xe88b }, +/* 0xe88c */ { false, 0xe88c, 0xe88c }, +/* 0xe88d */ { false, 0xe88d, 0xe88d }, +/* 0xe88e */ { false, 0xe88e, 0xe88e }, +/* 0xe88f */ { false, 0xe88f, 0xe88f }, +/* 0xe890 */ { false, 0xe890, 0xe890 }, +/* 0xe891 */ { false, 0xe891, 0xe891 }, +/* 0xe892 */ { false, 0xe892, 0xe892 }, +/* 0xe893 */ { false, 0xe893, 0xe893 }, +/* 0xe894 */ { false, 0xe894, 0xe894 }, +/* 0xe895 */ { false, 0xe895, 0xe895 }, +/* 0xe896 */ { false, 0xe896, 0xe896 }, +/* 0xe897 */ { false, 0xe897, 0xe897 }, +/* 0xe898 */ { false, 0xe898, 0xe898 }, +/* 0xe899 */ { false, 0xe899, 0xe899 }, +/* 0xe89a */ { false, 0xe89a, 0xe89a }, +/* 0xe89b */ { false, 0xe89b, 0xe89b }, +/* 0xe89c */ { false, 0xe89c, 0xe89c }, +/* 0xe89d */ { false, 0xe89d, 0xe89d }, +/* 0xe89e */ { false, 0xe89e, 0xe89e }, +/* 0xe89f */ { false, 0xe89f, 0xe89f }, +/* 0xe8a0 */ { false, 0xe8a0, 0xe8a0 }, +/* 0xe8a1 */ { false, 0xe8a1, 0xe8a1 }, +/* 0xe8a2 */ { false, 0xe8a2, 0xe8a2 }, +/* 0xe8a3 */ { false, 0xe8a3, 0xe8a3 }, +/* 0xe8a4 */ { false, 0xe8a4, 0xe8a4 }, +/* 0xe8a5 */ { false, 0xe8a5, 0xe8a5 }, +/* 0xe8a6 */ { false, 0xe8a6, 0xe8a6 }, +/* 0xe8a7 */ { false, 0xe8a7, 0xe8a7 }, +/* 0xe8a8 */ { false, 0xe8a8, 0xe8a8 }, +/* 0xe8a9 */ { false, 0xe8a9, 0xe8a9 }, +/* 0xe8aa */ { false, 0xe8aa, 0xe8aa }, +/* 0xe8ab */ { false, 0xe8ab, 0xe8ab }, +/* 0xe8ac */ { false, 0xe8ac, 0xe8ac }, +/* 0xe8ad */ { false, 0xe8ad, 0xe8ad }, +/* 0xe8ae */ { false, 0xe8ae, 0xe8ae }, +/* 0xe8af */ { false, 0xe8af, 0xe8af }, +/* 0xe8b0 */ { false, 0xe8b0, 0xe8b0 }, +/* 0xe8b1 */ { false, 0xe8b1, 0xe8b1 }, +/* 0xe8b2 */ { false, 0xe8b2, 0xe8b2 }, +/* 0xe8b3 */ { false, 0xe8b3, 0xe8b3 }, +/* 0xe8b4 */ { false, 0xe8b4, 0xe8b4 }, +/* 0xe8b5 */ { false, 0xe8b5, 0xe8b5 }, +/* 0xe8b6 */ { false, 0xe8b6, 0xe8b6 }, +/* 0xe8b7 */ { false, 0xe8b7, 0xe8b7 }, +/* 0xe8b8 */ { false, 0xe8b8, 0xe8b8 }, +/* 0xe8b9 */ { false, 0xe8b9, 0xe8b9 }, +/* 0xe8ba */ { false, 0xe8ba, 0xe8ba }, +/* 0xe8bb */ { false, 0xe8bb, 0xe8bb }, +/* 0xe8bc */ { false, 0xe8bc, 0xe8bc }, +/* 0xe8bd */ { false, 0xe8bd, 0xe8bd }, +/* 0xe8be */ { false, 0xe8be, 0xe8be }, +/* 0xe8bf */ { false, 0xe8bf, 0xe8bf }, +/* 0xe8c0 */ { false, 0xe8c0, 0xe8c0 }, +/* 0xe8c1 */ { false, 0xe8c1, 0xe8c1 }, +/* 0xe8c2 */ { false, 0xe8c2, 0xe8c2 }, +/* 0xe8c3 */ { false, 0xe8c3, 0xe8c3 }, +/* 0xe8c4 */ { false, 0xe8c4, 0xe8c4 }, +/* 0xe8c5 */ { false, 0xe8c5, 0xe8c5 }, +/* 0xe8c6 */ { false, 0xe8c6, 0xe8c6 }, +/* 0xe8c7 */ { false, 0xe8c7, 0xe8c7 }, +/* 0xe8c8 */ { false, 0xe8c8, 0xe8c8 }, +/* 0xe8c9 */ { false, 0xe8c9, 0xe8c9 }, +/* 0xe8ca */ { false, 0xe8ca, 0xe8ca }, +/* 0xe8cb */ { false, 0xe8cb, 0xe8cb }, +/* 0xe8cc */ { false, 0xe8cc, 0xe8cc }, +/* 0xe8cd */ { false, 0xe8cd, 0xe8cd }, +/* 0xe8ce */ { false, 0xe8ce, 0xe8ce }, +/* 0xe8cf */ { false, 0xe8cf, 0xe8cf }, +/* 0xe8d0 */ { false, 0xe8d0, 0xe8d0 }, +/* 0xe8d1 */ { false, 0xe8d1, 0xe8d1 }, +/* 0xe8d2 */ { false, 0xe8d2, 0xe8d2 }, +/* 0xe8d3 */ { false, 0xe8d3, 0xe8d3 }, +/* 0xe8d4 */ { false, 0xe8d4, 0xe8d4 }, +/* 0xe8d5 */ { false, 0xe8d5, 0xe8d5 }, +/* 0xe8d6 */ { false, 0xe8d6, 0xe8d6 }, +/* 0xe8d7 */ { false, 0xe8d7, 0xe8d7 }, +/* 0xe8d8 */ { false, 0xe8d8, 0xe8d8 }, +/* 0xe8d9 */ { false, 0xe8d9, 0xe8d9 }, +/* 0xe8da */ { false, 0xe8da, 0xe8da }, +/* 0xe8db */ { false, 0xe8db, 0xe8db }, +/* 0xe8dc */ { false, 0xe8dc, 0xe8dc }, +/* 0xe8dd */ { false, 0xe8dd, 0xe8dd }, +/* 0xe8de */ { false, 0xe8de, 0xe8de }, +/* 0xe8df */ { false, 0xe8df, 0xe8df }, +/* 0xe8e0 */ { false, 0xe8e0, 0xe8e0 }, +/* 0xe8e1 */ { false, 0xe8e1, 0xe8e1 }, +/* 0xe8e2 */ { false, 0xe8e2, 0xe8e2 }, +/* 0xe8e3 */ { false, 0xe8e3, 0xe8e3 }, +/* 0xe8e4 */ { false, 0xe8e4, 0xe8e4 }, +/* 0xe8e5 */ { false, 0xe8e5, 0xe8e5 }, +/* 0xe8e6 */ { false, 0xe8e6, 0xe8e6 }, +/* 0xe8e7 */ { false, 0xe8e7, 0xe8e7 }, +/* 0xe8e8 */ { false, 0xe8e8, 0xe8e8 }, +/* 0xe8e9 */ { false, 0xe8e9, 0xe8e9 }, +/* 0xe8ea */ { false, 0xe8ea, 0xe8ea }, +/* 0xe8eb */ { false, 0xe8eb, 0xe8eb }, +/* 0xe8ec */ { false, 0xe8ec, 0xe8ec }, +/* 0xe8ed */ { false, 0xe8ed, 0xe8ed }, +/* 0xe8ee */ { false, 0xe8ee, 0xe8ee }, +/* 0xe8ef */ { false, 0xe8ef, 0xe8ef }, +/* 0xe8f0 */ { false, 0xe8f0, 0xe8f0 }, +/* 0xe8f1 */ { false, 0xe8f1, 0xe8f1 }, +/* 0xe8f2 */ { false, 0xe8f2, 0xe8f2 }, +/* 0xe8f3 */ { false, 0xe8f3, 0xe8f3 }, +/* 0xe8f4 */ { false, 0xe8f4, 0xe8f4 }, +/* 0xe8f5 */ { false, 0xe8f5, 0xe8f5 }, +/* 0xe8f6 */ { false, 0xe8f6, 0xe8f6 }, +/* 0xe8f7 */ { false, 0xe8f7, 0xe8f7 }, +/* 0xe8f8 */ { false, 0xe8f8, 0xe8f8 }, +/* 0xe8f9 */ { false, 0xe8f9, 0xe8f9 }, +/* 0xe8fa */ { false, 0xe8fa, 0xe8fa }, +/* 0xe8fb */ { false, 0xe8fb, 0xe8fb }, +/* 0xe8fc */ { false, 0xe8fc, 0xe8fc }, +/* 0xe8fd */ { false, 0xe8fd, 0xe8fd }, +/* 0xe8fe */ { false, 0xe8fe, 0xe8fe }, +/* 0xe8ff */ { false, 0xe8ff, 0xe8ff }, +/* 0xe900 */ { false, 0xe900, 0xe900 }, +/* 0xe901 */ { false, 0xe901, 0xe901 }, +/* 0xe902 */ { false, 0xe902, 0xe902 }, +/* 0xe903 */ { false, 0xe903, 0xe903 }, +/* 0xe904 */ { false, 0xe904, 0xe904 }, +/* 0xe905 */ { false, 0xe905, 0xe905 }, +/* 0xe906 */ { false, 0xe906, 0xe906 }, +/* 0xe907 */ { false, 0xe907, 0xe907 }, +/* 0xe908 */ { false, 0xe908, 0xe908 }, +/* 0xe909 */ { false, 0xe909, 0xe909 }, +/* 0xe90a */ { false, 0xe90a, 0xe90a }, +/* 0xe90b */ { false, 0xe90b, 0xe90b }, +/* 0xe90c */ { false, 0xe90c, 0xe90c }, +/* 0xe90d */ { false, 0xe90d, 0xe90d }, +/* 0xe90e */ { false, 0xe90e, 0xe90e }, +/* 0xe90f */ { false, 0xe90f, 0xe90f }, +/* 0xe910 */ { false, 0xe910, 0xe910 }, +/* 0xe911 */ { false, 0xe911, 0xe911 }, +/* 0xe912 */ { false, 0xe912, 0xe912 }, +/* 0xe913 */ { false, 0xe913, 0xe913 }, +/* 0xe914 */ { false, 0xe914, 0xe914 }, +/* 0xe915 */ { false, 0xe915, 0xe915 }, +/* 0xe916 */ { false, 0xe916, 0xe916 }, +/* 0xe917 */ { false, 0xe917, 0xe917 }, +/* 0xe918 */ { false, 0xe918, 0xe918 }, +/* 0xe919 */ { false, 0xe919, 0xe919 }, +/* 0xe91a */ { false, 0xe91a, 0xe91a }, +/* 0xe91b */ { false, 0xe91b, 0xe91b }, +/* 0xe91c */ { false, 0xe91c, 0xe91c }, +/* 0xe91d */ { false, 0xe91d, 0xe91d }, +/* 0xe91e */ { false, 0xe91e, 0xe91e }, +/* 0xe91f */ { false, 0xe91f, 0xe91f }, +/* 0xe920 */ { false, 0xe920, 0xe920 }, +/* 0xe921 */ { false, 0xe921, 0xe921 }, +/* 0xe922 */ { false, 0xe922, 0xe922 }, +/* 0xe923 */ { false, 0xe923, 0xe923 }, +/* 0xe924 */ { false, 0xe924, 0xe924 }, +/* 0xe925 */ { false, 0xe925, 0xe925 }, +/* 0xe926 */ { false, 0xe926, 0xe926 }, +/* 0xe927 */ { false, 0xe927, 0xe927 }, +/* 0xe928 */ { false, 0xe928, 0xe928 }, +/* 0xe929 */ { false, 0xe929, 0xe929 }, +/* 0xe92a */ { false, 0xe92a, 0xe92a }, +/* 0xe92b */ { false, 0xe92b, 0xe92b }, +/* 0xe92c */ { false, 0xe92c, 0xe92c }, +/* 0xe92d */ { false, 0xe92d, 0xe92d }, +/* 0xe92e */ { false, 0xe92e, 0xe92e }, +/* 0xe92f */ { false, 0xe92f, 0xe92f }, +/* 0xe930 */ { false, 0xe930, 0xe930 }, +/* 0xe931 */ { false, 0xe931, 0xe931 }, +/* 0xe932 */ { false, 0xe932, 0xe932 }, +/* 0xe933 */ { false, 0xe933, 0xe933 }, +/* 0xe934 */ { false, 0xe934, 0xe934 }, +/* 0xe935 */ { false, 0xe935, 0xe935 }, +/* 0xe936 */ { false, 0xe936, 0xe936 }, +/* 0xe937 */ { false, 0xe937, 0xe937 }, +/* 0xe938 */ { false, 0xe938, 0xe938 }, +/* 0xe939 */ { false, 0xe939, 0xe939 }, +/* 0xe93a */ { false, 0xe93a, 0xe93a }, +/* 0xe93b */ { false, 0xe93b, 0xe93b }, +/* 0xe93c */ { false, 0xe93c, 0xe93c }, +/* 0xe93d */ { false, 0xe93d, 0xe93d }, +/* 0xe93e */ { false, 0xe93e, 0xe93e }, +/* 0xe93f */ { false, 0xe93f, 0xe93f }, +/* 0xe940 */ { false, 0xe940, 0xe940 }, +/* 0xe941 */ { false, 0xe941, 0xe941 }, +/* 0xe942 */ { false, 0xe942, 0xe942 }, +/* 0xe943 */ { false, 0xe943, 0xe943 }, +/* 0xe944 */ { false, 0xe944, 0xe944 }, +/* 0xe945 */ { false, 0xe945, 0xe945 }, +/* 0xe946 */ { false, 0xe946, 0xe946 }, +/* 0xe947 */ { false, 0xe947, 0xe947 }, +/* 0xe948 */ { false, 0xe948, 0xe948 }, +/* 0xe949 */ { false, 0xe949, 0xe949 }, +/* 0xe94a */ { false, 0xe94a, 0xe94a }, +/* 0xe94b */ { false, 0xe94b, 0xe94b }, +/* 0xe94c */ { false, 0xe94c, 0xe94c }, +/* 0xe94d */ { false, 0xe94d, 0xe94d }, +/* 0xe94e */ { false, 0xe94e, 0xe94e }, +/* 0xe94f */ { false, 0xe94f, 0xe94f }, +/* 0xe950 */ { false, 0xe950, 0xe950 }, +/* 0xe951 */ { false, 0xe951, 0xe951 }, +/* 0xe952 */ { false, 0xe952, 0xe952 }, +/* 0xe953 */ { false, 0xe953, 0xe953 }, +/* 0xe954 */ { false, 0xe954, 0xe954 }, +/* 0xe955 */ { false, 0xe955, 0xe955 }, +/* 0xe956 */ { false, 0xe956, 0xe956 }, +/* 0xe957 */ { false, 0xe957, 0xe957 }, +/* 0xe958 */ { false, 0xe958, 0xe958 }, +/* 0xe959 */ { false, 0xe959, 0xe959 }, +/* 0xe95a */ { false, 0xe95a, 0xe95a }, +/* 0xe95b */ { false, 0xe95b, 0xe95b }, +/* 0xe95c */ { false, 0xe95c, 0xe95c }, +/* 0xe95d */ { false, 0xe95d, 0xe95d }, +/* 0xe95e */ { false, 0xe95e, 0xe95e }, +/* 0xe95f */ { false, 0xe95f, 0xe95f }, +/* 0xe960 */ { false, 0xe960, 0xe960 }, +/* 0xe961 */ { false, 0xe961, 0xe961 }, +/* 0xe962 */ { false, 0xe962, 0xe962 }, +/* 0xe963 */ { false, 0xe963, 0xe963 }, +/* 0xe964 */ { false, 0xe964, 0xe964 }, +/* 0xe965 */ { false, 0xe965, 0xe965 }, +/* 0xe966 */ { false, 0xe966, 0xe966 }, +/* 0xe967 */ { false, 0xe967, 0xe967 }, +/* 0xe968 */ { false, 0xe968, 0xe968 }, +/* 0xe969 */ { false, 0xe969, 0xe969 }, +/* 0xe96a */ { false, 0xe96a, 0xe96a }, +/* 0xe96b */ { false, 0xe96b, 0xe96b }, +/* 0xe96c */ { false, 0xe96c, 0xe96c }, +/* 0xe96d */ { false, 0xe96d, 0xe96d }, +/* 0xe96e */ { false, 0xe96e, 0xe96e }, +/* 0xe96f */ { false, 0xe96f, 0xe96f }, +/* 0xe970 */ { false, 0xe970, 0xe970 }, +/* 0xe971 */ { false, 0xe971, 0xe971 }, +/* 0xe972 */ { false, 0xe972, 0xe972 }, +/* 0xe973 */ { false, 0xe973, 0xe973 }, +/* 0xe974 */ { false, 0xe974, 0xe974 }, +/* 0xe975 */ { false, 0xe975, 0xe975 }, +/* 0xe976 */ { false, 0xe976, 0xe976 }, +/* 0xe977 */ { false, 0xe977, 0xe977 }, +/* 0xe978 */ { false, 0xe978, 0xe978 }, +/* 0xe979 */ { false, 0xe979, 0xe979 }, +/* 0xe97a */ { false, 0xe97a, 0xe97a }, +/* 0xe97b */ { false, 0xe97b, 0xe97b }, +/* 0xe97c */ { false, 0xe97c, 0xe97c }, +/* 0xe97d */ { false, 0xe97d, 0xe97d }, +/* 0xe97e */ { false, 0xe97e, 0xe97e }, +/* 0xe97f */ { false, 0xe97f, 0xe97f }, +/* 0xe980 */ { false, 0xe980, 0xe980 }, +/* 0xe981 */ { false, 0xe981, 0xe981 }, +/* 0xe982 */ { false, 0xe982, 0xe982 }, +/* 0xe983 */ { false, 0xe983, 0xe983 }, +/* 0xe984 */ { false, 0xe984, 0xe984 }, +/* 0xe985 */ { false, 0xe985, 0xe985 }, +/* 0xe986 */ { false, 0xe986, 0xe986 }, +/* 0xe987 */ { false, 0xe987, 0xe987 }, +/* 0xe988 */ { false, 0xe988, 0xe988 }, +/* 0xe989 */ { false, 0xe989, 0xe989 }, +/* 0xe98a */ { false, 0xe98a, 0xe98a }, +/* 0xe98b */ { false, 0xe98b, 0xe98b }, +/* 0xe98c */ { false, 0xe98c, 0xe98c }, +/* 0xe98d */ { false, 0xe98d, 0xe98d }, +/* 0xe98e */ { false, 0xe98e, 0xe98e }, +/* 0xe98f */ { false, 0xe98f, 0xe98f }, +/* 0xe990 */ { false, 0xe990, 0xe990 }, +/* 0xe991 */ { false, 0xe991, 0xe991 }, +/* 0xe992 */ { false, 0xe992, 0xe992 }, +/* 0xe993 */ { false, 0xe993, 0xe993 }, +/* 0xe994 */ { false, 0xe994, 0xe994 }, +/* 0xe995 */ { false, 0xe995, 0xe995 }, +/* 0xe996 */ { false, 0xe996, 0xe996 }, +/* 0xe997 */ { false, 0xe997, 0xe997 }, +/* 0xe998 */ { false, 0xe998, 0xe998 }, +/* 0xe999 */ { false, 0xe999, 0xe999 }, +/* 0xe99a */ { false, 0xe99a, 0xe99a }, +/* 0xe99b */ { false, 0xe99b, 0xe99b }, +/* 0xe99c */ { false, 0xe99c, 0xe99c }, +/* 0xe99d */ { false, 0xe99d, 0xe99d }, +/* 0xe99e */ { false, 0xe99e, 0xe99e }, +/* 0xe99f */ { false, 0xe99f, 0xe99f }, +/* 0xe9a0 */ { false, 0xe9a0, 0xe9a0 }, +/* 0xe9a1 */ { false, 0xe9a1, 0xe9a1 }, +/* 0xe9a2 */ { false, 0xe9a2, 0xe9a2 }, +/* 0xe9a3 */ { false, 0xe9a3, 0xe9a3 }, +/* 0xe9a4 */ { false, 0xe9a4, 0xe9a4 }, +/* 0xe9a5 */ { false, 0xe9a5, 0xe9a5 }, +/* 0xe9a6 */ { false, 0xe9a6, 0xe9a6 }, +/* 0xe9a7 */ { false, 0xe9a7, 0xe9a7 }, +/* 0xe9a8 */ { false, 0xe9a8, 0xe9a8 }, +/* 0xe9a9 */ { false, 0xe9a9, 0xe9a9 }, +/* 0xe9aa */ { false, 0xe9aa, 0xe9aa }, +/* 0xe9ab */ { false, 0xe9ab, 0xe9ab }, +/* 0xe9ac */ { false, 0xe9ac, 0xe9ac }, +/* 0xe9ad */ { false, 0xe9ad, 0xe9ad }, +/* 0xe9ae */ { false, 0xe9ae, 0xe9ae }, +/* 0xe9af */ { false, 0xe9af, 0xe9af }, +/* 0xe9b0 */ { false, 0xe9b0, 0xe9b0 }, +/* 0xe9b1 */ { false, 0xe9b1, 0xe9b1 }, +/* 0xe9b2 */ { false, 0xe9b2, 0xe9b2 }, +/* 0xe9b3 */ { false, 0xe9b3, 0xe9b3 }, +/* 0xe9b4 */ { false, 0xe9b4, 0xe9b4 }, +/* 0xe9b5 */ { false, 0xe9b5, 0xe9b5 }, +/* 0xe9b6 */ { false, 0xe9b6, 0xe9b6 }, +/* 0xe9b7 */ { false, 0xe9b7, 0xe9b7 }, +/* 0xe9b8 */ { false, 0xe9b8, 0xe9b8 }, +/* 0xe9b9 */ { false, 0xe9b9, 0xe9b9 }, +/* 0xe9ba */ { false, 0xe9ba, 0xe9ba }, +/* 0xe9bb */ { false, 0xe9bb, 0xe9bb }, +/* 0xe9bc */ { false, 0xe9bc, 0xe9bc }, +/* 0xe9bd */ { false, 0xe9bd, 0xe9bd }, +/* 0xe9be */ { false, 0xe9be, 0xe9be }, +/* 0xe9bf */ { false, 0xe9bf, 0xe9bf }, +/* 0xe9c0 */ { false, 0xe9c0, 0xe9c0 }, +/* 0xe9c1 */ { false, 0xe9c1, 0xe9c1 }, +/* 0xe9c2 */ { false, 0xe9c2, 0xe9c2 }, +/* 0xe9c3 */ { false, 0xe9c3, 0xe9c3 }, +/* 0xe9c4 */ { false, 0xe9c4, 0xe9c4 }, +/* 0xe9c5 */ { false, 0xe9c5, 0xe9c5 }, +/* 0xe9c6 */ { false, 0xe9c6, 0xe9c6 }, +/* 0xe9c7 */ { false, 0xe9c7, 0xe9c7 }, +/* 0xe9c8 */ { false, 0xe9c8, 0xe9c8 }, +/* 0xe9c9 */ { false, 0xe9c9, 0xe9c9 }, +/* 0xe9ca */ { false, 0xe9ca, 0xe9ca }, +/* 0xe9cb */ { false, 0xe9cb, 0xe9cb }, +/* 0xe9cc */ { false, 0xe9cc, 0xe9cc }, +/* 0xe9cd */ { false, 0xe9cd, 0xe9cd }, +/* 0xe9ce */ { false, 0xe9ce, 0xe9ce }, +/* 0xe9cf */ { false, 0xe9cf, 0xe9cf }, +/* 0xe9d0 */ { false, 0xe9d0, 0xe9d0 }, +/* 0xe9d1 */ { false, 0xe9d1, 0xe9d1 }, +/* 0xe9d2 */ { false, 0xe9d2, 0xe9d2 }, +/* 0xe9d3 */ { false, 0xe9d3, 0xe9d3 }, +/* 0xe9d4 */ { false, 0xe9d4, 0xe9d4 }, +/* 0xe9d5 */ { false, 0xe9d5, 0xe9d5 }, +/* 0xe9d6 */ { false, 0xe9d6, 0xe9d6 }, +/* 0xe9d7 */ { false, 0xe9d7, 0xe9d7 }, +/* 0xe9d8 */ { false, 0xe9d8, 0xe9d8 }, +/* 0xe9d9 */ { false, 0xe9d9, 0xe9d9 }, +/* 0xe9da */ { false, 0xe9da, 0xe9da }, +/* 0xe9db */ { false, 0xe9db, 0xe9db }, +/* 0xe9dc */ { false, 0xe9dc, 0xe9dc }, +/* 0xe9dd */ { false, 0xe9dd, 0xe9dd }, +/* 0xe9de */ { false, 0xe9de, 0xe9de }, +/* 0xe9df */ { false, 0xe9df, 0xe9df }, +/* 0xe9e0 */ { false, 0xe9e0, 0xe9e0 }, +/* 0xe9e1 */ { false, 0xe9e1, 0xe9e1 }, +/* 0xe9e2 */ { false, 0xe9e2, 0xe9e2 }, +/* 0xe9e3 */ { false, 0xe9e3, 0xe9e3 }, +/* 0xe9e4 */ { false, 0xe9e4, 0xe9e4 }, +/* 0xe9e5 */ { false, 0xe9e5, 0xe9e5 }, +/* 0xe9e6 */ { false, 0xe9e6, 0xe9e6 }, +/* 0xe9e7 */ { false, 0xe9e7, 0xe9e7 }, +/* 0xe9e8 */ { false, 0xe9e8, 0xe9e8 }, +/* 0xe9e9 */ { false, 0xe9e9, 0xe9e9 }, +/* 0xe9ea */ { false, 0xe9ea, 0xe9ea }, +/* 0xe9eb */ { false, 0xe9eb, 0xe9eb }, +/* 0xe9ec */ { false, 0xe9ec, 0xe9ec }, +/* 0xe9ed */ { false, 0xe9ed, 0xe9ed }, +/* 0xe9ee */ { false, 0xe9ee, 0xe9ee }, +/* 0xe9ef */ { false, 0xe9ef, 0xe9ef }, +/* 0xe9f0 */ { false, 0xe9f0, 0xe9f0 }, +/* 0xe9f1 */ { false, 0xe9f1, 0xe9f1 }, +/* 0xe9f2 */ { false, 0xe9f2, 0xe9f2 }, +/* 0xe9f3 */ { false, 0xe9f3, 0xe9f3 }, +/* 0xe9f4 */ { false, 0xe9f4, 0xe9f4 }, +/* 0xe9f5 */ { false, 0xe9f5, 0xe9f5 }, +/* 0xe9f6 */ { false, 0xe9f6, 0xe9f6 }, +/* 0xe9f7 */ { false, 0xe9f7, 0xe9f7 }, +/* 0xe9f8 */ { false, 0xe9f8, 0xe9f8 }, +/* 0xe9f9 */ { false, 0xe9f9, 0xe9f9 }, +/* 0xe9fa */ { false, 0xe9fa, 0xe9fa }, +/* 0xe9fb */ { false, 0xe9fb, 0xe9fb }, +/* 0xe9fc */ { false, 0xe9fc, 0xe9fc }, +/* 0xe9fd */ { false, 0xe9fd, 0xe9fd }, +/* 0xe9fe */ { false, 0xe9fe, 0xe9fe }, +/* 0xe9ff */ { false, 0xe9ff, 0xe9ff }, +/* 0xea00 */ { false, 0xea00, 0xea00 }, +/* 0xea01 */ { false, 0xea01, 0xea01 }, +/* 0xea02 */ { false, 0xea02, 0xea02 }, +/* 0xea03 */ { false, 0xea03, 0xea03 }, +/* 0xea04 */ { false, 0xea04, 0xea04 }, +/* 0xea05 */ { false, 0xea05, 0xea05 }, +/* 0xea06 */ { false, 0xea06, 0xea06 }, +/* 0xea07 */ { false, 0xea07, 0xea07 }, +/* 0xea08 */ { false, 0xea08, 0xea08 }, +/* 0xea09 */ { false, 0xea09, 0xea09 }, +/* 0xea0a */ { false, 0xea0a, 0xea0a }, +/* 0xea0b */ { false, 0xea0b, 0xea0b }, +/* 0xea0c */ { false, 0xea0c, 0xea0c }, +/* 0xea0d */ { false, 0xea0d, 0xea0d }, +/* 0xea0e */ { false, 0xea0e, 0xea0e }, +/* 0xea0f */ { false, 0xea0f, 0xea0f }, +/* 0xea10 */ { false, 0xea10, 0xea10 }, +/* 0xea11 */ { false, 0xea11, 0xea11 }, +/* 0xea12 */ { false, 0xea12, 0xea12 }, +/* 0xea13 */ { false, 0xea13, 0xea13 }, +/* 0xea14 */ { false, 0xea14, 0xea14 }, +/* 0xea15 */ { false, 0xea15, 0xea15 }, +/* 0xea16 */ { false, 0xea16, 0xea16 }, +/* 0xea17 */ { false, 0xea17, 0xea17 }, +/* 0xea18 */ { false, 0xea18, 0xea18 }, +/* 0xea19 */ { false, 0xea19, 0xea19 }, +/* 0xea1a */ { false, 0xea1a, 0xea1a }, +/* 0xea1b */ { false, 0xea1b, 0xea1b }, +/* 0xea1c */ { false, 0xea1c, 0xea1c }, +/* 0xea1d */ { false, 0xea1d, 0xea1d }, +/* 0xea1e */ { false, 0xea1e, 0xea1e }, +/* 0xea1f */ { false, 0xea1f, 0xea1f }, +/* 0xea20 */ { false, 0xea20, 0xea20 }, +/* 0xea21 */ { false, 0xea21, 0xea21 }, +/* 0xea22 */ { false, 0xea22, 0xea22 }, +/* 0xea23 */ { false, 0xea23, 0xea23 }, +/* 0xea24 */ { false, 0xea24, 0xea24 }, +/* 0xea25 */ { false, 0xea25, 0xea25 }, +/* 0xea26 */ { false, 0xea26, 0xea26 }, +/* 0xea27 */ { false, 0xea27, 0xea27 }, +/* 0xea28 */ { false, 0xea28, 0xea28 }, +/* 0xea29 */ { false, 0xea29, 0xea29 }, +/* 0xea2a */ { false, 0xea2a, 0xea2a }, +/* 0xea2b */ { false, 0xea2b, 0xea2b }, +/* 0xea2c */ { false, 0xea2c, 0xea2c }, +/* 0xea2d */ { false, 0xea2d, 0xea2d }, +/* 0xea2e */ { false, 0xea2e, 0xea2e }, +/* 0xea2f */ { false, 0xea2f, 0xea2f }, +/* 0xea30 */ { false, 0xea30, 0xea30 }, +/* 0xea31 */ { false, 0xea31, 0xea31 }, +/* 0xea32 */ { false, 0xea32, 0xea32 }, +/* 0xea33 */ { false, 0xea33, 0xea33 }, +/* 0xea34 */ { false, 0xea34, 0xea34 }, +/* 0xea35 */ { false, 0xea35, 0xea35 }, +/* 0xea36 */ { false, 0xea36, 0xea36 }, +/* 0xea37 */ { false, 0xea37, 0xea37 }, +/* 0xea38 */ { false, 0xea38, 0xea38 }, +/* 0xea39 */ { false, 0xea39, 0xea39 }, +/* 0xea3a */ { false, 0xea3a, 0xea3a }, +/* 0xea3b */ { false, 0xea3b, 0xea3b }, +/* 0xea3c */ { false, 0xea3c, 0xea3c }, +/* 0xea3d */ { false, 0xea3d, 0xea3d }, +/* 0xea3e */ { false, 0xea3e, 0xea3e }, +/* 0xea3f */ { false, 0xea3f, 0xea3f }, +/* 0xea40 */ { false, 0xea40, 0xea40 }, +/* 0xea41 */ { false, 0xea41, 0xea41 }, +/* 0xea42 */ { false, 0xea42, 0xea42 }, +/* 0xea43 */ { false, 0xea43, 0xea43 }, +/* 0xea44 */ { false, 0xea44, 0xea44 }, +/* 0xea45 */ { false, 0xea45, 0xea45 }, +/* 0xea46 */ { false, 0xea46, 0xea46 }, +/* 0xea47 */ { false, 0xea47, 0xea47 }, +/* 0xea48 */ { false, 0xea48, 0xea48 }, +/* 0xea49 */ { false, 0xea49, 0xea49 }, +/* 0xea4a */ { false, 0xea4a, 0xea4a }, +/* 0xea4b */ { false, 0xea4b, 0xea4b }, +/* 0xea4c */ { false, 0xea4c, 0xea4c }, +/* 0xea4d */ { false, 0xea4d, 0xea4d }, +/* 0xea4e */ { false, 0xea4e, 0xea4e }, +/* 0xea4f */ { false, 0xea4f, 0xea4f }, +/* 0xea50 */ { false, 0xea50, 0xea50 }, +/* 0xea51 */ { false, 0xea51, 0xea51 }, +/* 0xea52 */ { false, 0xea52, 0xea52 }, +/* 0xea53 */ { false, 0xea53, 0xea53 }, +/* 0xea54 */ { false, 0xea54, 0xea54 }, +/* 0xea55 */ { false, 0xea55, 0xea55 }, +/* 0xea56 */ { false, 0xea56, 0xea56 }, +/* 0xea57 */ { false, 0xea57, 0xea57 }, +/* 0xea58 */ { false, 0xea58, 0xea58 }, +/* 0xea59 */ { false, 0xea59, 0xea59 }, +/* 0xea5a */ { false, 0xea5a, 0xea5a }, +/* 0xea5b */ { false, 0xea5b, 0xea5b }, +/* 0xea5c */ { false, 0xea5c, 0xea5c }, +/* 0xea5d */ { false, 0xea5d, 0xea5d }, +/* 0xea5e */ { false, 0xea5e, 0xea5e }, +/* 0xea5f */ { false, 0xea5f, 0xea5f }, +/* 0xea60 */ { false, 0xea60, 0xea60 }, +/* 0xea61 */ { false, 0xea61, 0xea61 }, +/* 0xea62 */ { false, 0xea62, 0xea62 }, +/* 0xea63 */ { false, 0xea63, 0xea63 }, +/* 0xea64 */ { false, 0xea64, 0xea64 }, +/* 0xea65 */ { false, 0xea65, 0xea65 }, +/* 0xea66 */ { false, 0xea66, 0xea66 }, +/* 0xea67 */ { false, 0xea67, 0xea67 }, +/* 0xea68 */ { false, 0xea68, 0xea68 }, +/* 0xea69 */ { false, 0xea69, 0xea69 }, +/* 0xea6a */ { false, 0xea6a, 0xea6a }, +/* 0xea6b */ { false, 0xea6b, 0xea6b }, +/* 0xea6c */ { false, 0xea6c, 0xea6c }, +/* 0xea6d */ { false, 0xea6d, 0xea6d }, +/* 0xea6e */ { false, 0xea6e, 0xea6e }, +/* 0xea6f */ { false, 0xea6f, 0xea6f }, +/* 0xea70 */ { false, 0xea70, 0xea70 }, +/* 0xea71 */ { false, 0xea71, 0xea71 }, +/* 0xea72 */ { false, 0xea72, 0xea72 }, +/* 0xea73 */ { false, 0xea73, 0xea73 }, +/* 0xea74 */ { false, 0xea74, 0xea74 }, +/* 0xea75 */ { false, 0xea75, 0xea75 }, +/* 0xea76 */ { false, 0xea76, 0xea76 }, +/* 0xea77 */ { false, 0xea77, 0xea77 }, +/* 0xea78 */ { false, 0xea78, 0xea78 }, +/* 0xea79 */ { false, 0xea79, 0xea79 }, +/* 0xea7a */ { false, 0xea7a, 0xea7a }, +/* 0xea7b */ { false, 0xea7b, 0xea7b }, +/* 0xea7c */ { false, 0xea7c, 0xea7c }, +/* 0xea7d */ { false, 0xea7d, 0xea7d }, +/* 0xea7e */ { false, 0xea7e, 0xea7e }, +/* 0xea7f */ { false, 0xea7f, 0xea7f }, +/* 0xea80 */ { false, 0xea80, 0xea80 }, +/* 0xea81 */ { false, 0xea81, 0xea81 }, +/* 0xea82 */ { false, 0xea82, 0xea82 }, +/* 0xea83 */ { false, 0xea83, 0xea83 }, +/* 0xea84 */ { false, 0xea84, 0xea84 }, +/* 0xea85 */ { false, 0xea85, 0xea85 }, +/* 0xea86 */ { false, 0xea86, 0xea86 }, +/* 0xea87 */ { false, 0xea87, 0xea87 }, +/* 0xea88 */ { false, 0xea88, 0xea88 }, +/* 0xea89 */ { false, 0xea89, 0xea89 }, +/* 0xea8a */ { false, 0xea8a, 0xea8a }, +/* 0xea8b */ { false, 0xea8b, 0xea8b }, +/* 0xea8c */ { false, 0xea8c, 0xea8c }, +/* 0xea8d */ { false, 0xea8d, 0xea8d }, +/* 0xea8e */ { false, 0xea8e, 0xea8e }, +/* 0xea8f */ { false, 0xea8f, 0xea8f }, +/* 0xea90 */ { false, 0xea90, 0xea90 }, +/* 0xea91 */ { false, 0xea91, 0xea91 }, +/* 0xea92 */ { false, 0xea92, 0xea92 }, +/* 0xea93 */ { false, 0xea93, 0xea93 }, +/* 0xea94 */ { false, 0xea94, 0xea94 }, +/* 0xea95 */ { false, 0xea95, 0xea95 }, +/* 0xea96 */ { false, 0xea96, 0xea96 }, +/* 0xea97 */ { false, 0xea97, 0xea97 }, +/* 0xea98 */ { false, 0xea98, 0xea98 }, +/* 0xea99 */ { false, 0xea99, 0xea99 }, +/* 0xea9a */ { false, 0xea9a, 0xea9a }, +/* 0xea9b */ { false, 0xea9b, 0xea9b }, +/* 0xea9c */ { false, 0xea9c, 0xea9c }, +/* 0xea9d */ { false, 0xea9d, 0xea9d }, +/* 0xea9e */ { false, 0xea9e, 0xea9e }, +/* 0xea9f */ { false, 0xea9f, 0xea9f }, +/* 0xeaa0 */ { false, 0xeaa0, 0xeaa0 }, +/* 0xeaa1 */ { false, 0xeaa1, 0xeaa1 }, +/* 0xeaa2 */ { false, 0xeaa2, 0xeaa2 }, +/* 0xeaa3 */ { false, 0xeaa3, 0xeaa3 }, +/* 0xeaa4 */ { false, 0xeaa4, 0xeaa4 }, +/* 0xeaa5 */ { false, 0xeaa5, 0xeaa5 }, +/* 0xeaa6 */ { false, 0xeaa6, 0xeaa6 }, +/* 0xeaa7 */ { false, 0xeaa7, 0xeaa7 }, +/* 0xeaa8 */ { false, 0xeaa8, 0xeaa8 }, +/* 0xeaa9 */ { false, 0xeaa9, 0xeaa9 }, +/* 0xeaaa */ { false, 0xeaaa, 0xeaaa }, +/* 0xeaab */ { false, 0xeaab, 0xeaab }, +/* 0xeaac */ { false, 0xeaac, 0xeaac }, +/* 0xeaad */ { false, 0xeaad, 0xeaad }, +/* 0xeaae */ { false, 0xeaae, 0xeaae }, +/* 0xeaaf */ { false, 0xeaaf, 0xeaaf }, +/* 0xeab0 */ { false, 0xeab0, 0xeab0 }, +/* 0xeab1 */ { false, 0xeab1, 0xeab1 }, +/* 0xeab2 */ { false, 0xeab2, 0xeab2 }, +/* 0xeab3 */ { false, 0xeab3, 0xeab3 }, +/* 0xeab4 */ { false, 0xeab4, 0xeab4 }, +/* 0xeab5 */ { false, 0xeab5, 0xeab5 }, +/* 0xeab6 */ { false, 0xeab6, 0xeab6 }, +/* 0xeab7 */ { false, 0xeab7, 0xeab7 }, +/* 0xeab8 */ { false, 0xeab8, 0xeab8 }, +/* 0xeab9 */ { false, 0xeab9, 0xeab9 }, +/* 0xeaba */ { false, 0xeaba, 0xeaba }, +/* 0xeabb */ { false, 0xeabb, 0xeabb }, +/* 0xeabc */ { false, 0xeabc, 0xeabc }, +/* 0xeabd */ { false, 0xeabd, 0xeabd }, +/* 0xeabe */ { false, 0xeabe, 0xeabe }, +/* 0xeabf */ { false, 0xeabf, 0xeabf }, +/* 0xeac0 */ { false, 0xeac0, 0xeac0 }, +/* 0xeac1 */ { false, 0xeac1, 0xeac1 }, +/* 0xeac2 */ { false, 0xeac2, 0xeac2 }, +/* 0xeac3 */ { false, 0xeac3, 0xeac3 }, +/* 0xeac4 */ { false, 0xeac4, 0xeac4 }, +/* 0xeac5 */ { false, 0xeac5, 0xeac5 }, +/* 0xeac6 */ { false, 0xeac6, 0xeac6 }, +/* 0xeac7 */ { false, 0xeac7, 0xeac7 }, +/* 0xeac8 */ { false, 0xeac8, 0xeac8 }, +/* 0xeac9 */ { false, 0xeac9, 0xeac9 }, +/* 0xeaca */ { false, 0xeaca, 0xeaca }, +/* 0xeacb */ { false, 0xeacb, 0xeacb }, +/* 0xeacc */ { false, 0xeacc, 0xeacc }, +/* 0xeacd */ { false, 0xeacd, 0xeacd }, +/* 0xeace */ { false, 0xeace, 0xeace }, +/* 0xeacf */ { false, 0xeacf, 0xeacf }, +/* 0xead0 */ { false, 0xead0, 0xead0 }, +/* 0xead1 */ { false, 0xead1, 0xead1 }, +/* 0xead2 */ { false, 0xead2, 0xead2 }, +/* 0xead3 */ { false, 0xead3, 0xead3 }, +/* 0xead4 */ { false, 0xead4, 0xead4 }, +/* 0xead5 */ { false, 0xead5, 0xead5 }, +/* 0xead6 */ { false, 0xead6, 0xead6 }, +/* 0xead7 */ { false, 0xead7, 0xead7 }, +/* 0xead8 */ { false, 0xead8, 0xead8 }, +/* 0xead9 */ { false, 0xead9, 0xead9 }, +/* 0xeada */ { false, 0xeada, 0xeada }, +/* 0xeadb */ { false, 0xeadb, 0xeadb }, +/* 0xeadc */ { false, 0xeadc, 0xeadc }, +/* 0xeadd */ { false, 0xeadd, 0xeadd }, +/* 0xeade */ { false, 0xeade, 0xeade }, +/* 0xeadf */ { false, 0xeadf, 0xeadf }, +/* 0xeae0 */ { false, 0xeae0, 0xeae0 }, +/* 0xeae1 */ { false, 0xeae1, 0xeae1 }, +/* 0xeae2 */ { false, 0xeae2, 0xeae2 }, +/* 0xeae3 */ { false, 0xeae3, 0xeae3 }, +/* 0xeae4 */ { false, 0xeae4, 0xeae4 }, +/* 0xeae5 */ { false, 0xeae5, 0xeae5 }, +/* 0xeae6 */ { false, 0xeae6, 0xeae6 }, +/* 0xeae7 */ { false, 0xeae7, 0xeae7 }, +/* 0xeae8 */ { false, 0xeae8, 0xeae8 }, +/* 0xeae9 */ { false, 0xeae9, 0xeae9 }, +/* 0xeaea */ { false, 0xeaea, 0xeaea }, +/* 0xeaeb */ { false, 0xeaeb, 0xeaeb }, +/* 0xeaec */ { false, 0xeaec, 0xeaec }, +/* 0xeaed */ { false, 0xeaed, 0xeaed }, +/* 0xeaee */ { false, 0xeaee, 0xeaee }, +/* 0xeaef */ { false, 0xeaef, 0xeaef }, +/* 0xeaf0 */ { false, 0xeaf0, 0xeaf0 }, +/* 0xeaf1 */ { false, 0xeaf1, 0xeaf1 }, +/* 0xeaf2 */ { false, 0xeaf2, 0xeaf2 }, +/* 0xeaf3 */ { false, 0xeaf3, 0xeaf3 }, +/* 0xeaf4 */ { false, 0xeaf4, 0xeaf4 }, +/* 0xeaf5 */ { false, 0xeaf5, 0xeaf5 }, +/* 0xeaf6 */ { false, 0xeaf6, 0xeaf6 }, +/* 0xeaf7 */ { false, 0xeaf7, 0xeaf7 }, +/* 0xeaf8 */ { false, 0xeaf8, 0xeaf8 }, +/* 0xeaf9 */ { false, 0xeaf9, 0xeaf9 }, +/* 0xeafa */ { false, 0xeafa, 0xeafa }, +/* 0xeafb */ { false, 0xeafb, 0xeafb }, +/* 0xeafc */ { false, 0xeafc, 0xeafc }, +/* 0xeafd */ { false, 0xeafd, 0xeafd }, +/* 0xeafe */ { false, 0xeafe, 0xeafe }, +/* 0xeaff */ { false, 0xeaff, 0xeaff }, +/* 0xeb00 */ { false, 0xeb00, 0xeb00 }, +/* 0xeb01 */ { false, 0xeb01, 0xeb01 }, +/* 0xeb02 */ { false, 0xeb02, 0xeb02 }, +/* 0xeb03 */ { false, 0xeb03, 0xeb03 }, +/* 0xeb04 */ { false, 0xeb04, 0xeb04 }, +/* 0xeb05 */ { false, 0xeb05, 0xeb05 }, +/* 0xeb06 */ { false, 0xeb06, 0xeb06 }, +/* 0xeb07 */ { false, 0xeb07, 0xeb07 }, +/* 0xeb08 */ { false, 0xeb08, 0xeb08 }, +/* 0xeb09 */ { false, 0xeb09, 0xeb09 }, +/* 0xeb0a */ { false, 0xeb0a, 0xeb0a }, +/* 0xeb0b */ { false, 0xeb0b, 0xeb0b }, +/* 0xeb0c */ { false, 0xeb0c, 0xeb0c }, +/* 0xeb0d */ { false, 0xeb0d, 0xeb0d }, +/* 0xeb0e */ { false, 0xeb0e, 0xeb0e }, +/* 0xeb0f */ { false, 0xeb0f, 0xeb0f }, +/* 0xeb10 */ { false, 0xeb10, 0xeb10 }, +/* 0xeb11 */ { false, 0xeb11, 0xeb11 }, +/* 0xeb12 */ { false, 0xeb12, 0xeb12 }, +/* 0xeb13 */ { false, 0xeb13, 0xeb13 }, +/* 0xeb14 */ { false, 0xeb14, 0xeb14 }, +/* 0xeb15 */ { false, 0xeb15, 0xeb15 }, +/* 0xeb16 */ { false, 0xeb16, 0xeb16 }, +/* 0xeb17 */ { false, 0xeb17, 0xeb17 }, +/* 0xeb18 */ { false, 0xeb18, 0xeb18 }, +/* 0xeb19 */ { false, 0xeb19, 0xeb19 }, +/* 0xeb1a */ { false, 0xeb1a, 0xeb1a }, +/* 0xeb1b */ { false, 0xeb1b, 0xeb1b }, +/* 0xeb1c */ { false, 0xeb1c, 0xeb1c }, +/* 0xeb1d */ { false, 0xeb1d, 0xeb1d }, +/* 0xeb1e */ { false, 0xeb1e, 0xeb1e }, +/* 0xeb1f */ { false, 0xeb1f, 0xeb1f }, +/* 0xeb20 */ { false, 0xeb20, 0xeb20 }, +/* 0xeb21 */ { false, 0xeb21, 0xeb21 }, +/* 0xeb22 */ { false, 0xeb22, 0xeb22 }, +/* 0xeb23 */ { false, 0xeb23, 0xeb23 }, +/* 0xeb24 */ { false, 0xeb24, 0xeb24 }, +/* 0xeb25 */ { false, 0xeb25, 0xeb25 }, +/* 0xeb26 */ { false, 0xeb26, 0xeb26 }, +/* 0xeb27 */ { false, 0xeb27, 0xeb27 }, +/* 0xeb28 */ { false, 0xeb28, 0xeb28 }, +/* 0xeb29 */ { false, 0xeb29, 0xeb29 }, +/* 0xeb2a */ { false, 0xeb2a, 0xeb2a }, +/* 0xeb2b */ { false, 0xeb2b, 0xeb2b }, +/* 0xeb2c */ { false, 0xeb2c, 0xeb2c }, +/* 0xeb2d */ { false, 0xeb2d, 0xeb2d }, +/* 0xeb2e */ { false, 0xeb2e, 0xeb2e }, +/* 0xeb2f */ { false, 0xeb2f, 0xeb2f }, +/* 0xeb30 */ { false, 0xeb30, 0xeb30 }, +/* 0xeb31 */ { false, 0xeb31, 0xeb31 }, +/* 0xeb32 */ { false, 0xeb32, 0xeb32 }, +/* 0xeb33 */ { false, 0xeb33, 0xeb33 }, +/* 0xeb34 */ { false, 0xeb34, 0xeb34 }, +/* 0xeb35 */ { false, 0xeb35, 0xeb35 }, +/* 0xeb36 */ { false, 0xeb36, 0xeb36 }, +/* 0xeb37 */ { false, 0xeb37, 0xeb37 }, +/* 0xeb38 */ { false, 0xeb38, 0xeb38 }, +/* 0xeb39 */ { false, 0xeb39, 0xeb39 }, +/* 0xeb3a */ { false, 0xeb3a, 0xeb3a }, +/* 0xeb3b */ { false, 0xeb3b, 0xeb3b }, +/* 0xeb3c */ { false, 0xeb3c, 0xeb3c }, +/* 0xeb3d */ { false, 0xeb3d, 0xeb3d }, +/* 0xeb3e */ { false, 0xeb3e, 0xeb3e }, +/* 0xeb3f */ { false, 0xeb3f, 0xeb3f }, +/* 0xeb40 */ { false, 0xeb40, 0xeb40 }, +/* 0xeb41 */ { false, 0xeb41, 0xeb41 }, +/* 0xeb42 */ { false, 0xeb42, 0xeb42 }, +/* 0xeb43 */ { false, 0xeb43, 0xeb43 }, +/* 0xeb44 */ { false, 0xeb44, 0xeb44 }, +/* 0xeb45 */ { false, 0xeb45, 0xeb45 }, +/* 0xeb46 */ { false, 0xeb46, 0xeb46 }, +/* 0xeb47 */ { false, 0xeb47, 0xeb47 }, +/* 0xeb48 */ { false, 0xeb48, 0xeb48 }, +/* 0xeb49 */ { false, 0xeb49, 0xeb49 }, +/* 0xeb4a */ { false, 0xeb4a, 0xeb4a }, +/* 0xeb4b */ { false, 0xeb4b, 0xeb4b }, +/* 0xeb4c */ { false, 0xeb4c, 0xeb4c }, +/* 0xeb4d */ { false, 0xeb4d, 0xeb4d }, +/* 0xeb4e */ { false, 0xeb4e, 0xeb4e }, +/* 0xeb4f */ { false, 0xeb4f, 0xeb4f }, +/* 0xeb50 */ { false, 0xeb50, 0xeb50 }, +/* 0xeb51 */ { false, 0xeb51, 0xeb51 }, +/* 0xeb52 */ { false, 0xeb52, 0xeb52 }, +/* 0xeb53 */ { false, 0xeb53, 0xeb53 }, +/* 0xeb54 */ { false, 0xeb54, 0xeb54 }, +/* 0xeb55 */ { false, 0xeb55, 0xeb55 }, +/* 0xeb56 */ { false, 0xeb56, 0xeb56 }, +/* 0xeb57 */ { false, 0xeb57, 0xeb57 }, +/* 0xeb58 */ { false, 0xeb58, 0xeb58 }, +/* 0xeb59 */ { false, 0xeb59, 0xeb59 }, +/* 0xeb5a */ { false, 0xeb5a, 0xeb5a }, +/* 0xeb5b */ { false, 0xeb5b, 0xeb5b }, +/* 0xeb5c */ { false, 0xeb5c, 0xeb5c }, +/* 0xeb5d */ { false, 0xeb5d, 0xeb5d }, +/* 0xeb5e */ { false, 0xeb5e, 0xeb5e }, +/* 0xeb5f */ { false, 0xeb5f, 0xeb5f }, +/* 0xeb60 */ { false, 0xeb60, 0xeb60 }, +/* 0xeb61 */ { false, 0xeb61, 0xeb61 }, +/* 0xeb62 */ { false, 0xeb62, 0xeb62 }, +/* 0xeb63 */ { false, 0xeb63, 0xeb63 }, +/* 0xeb64 */ { false, 0xeb64, 0xeb64 }, +/* 0xeb65 */ { false, 0xeb65, 0xeb65 }, +/* 0xeb66 */ { false, 0xeb66, 0xeb66 }, +/* 0xeb67 */ { false, 0xeb67, 0xeb67 }, +/* 0xeb68 */ { false, 0xeb68, 0xeb68 }, +/* 0xeb69 */ { false, 0xeb69, 0xeb69 }, +/* 0xeb6a */ { false, 0xeb6a, 0xeb6a }, +/* 0xeb6b */ { false, 0xeb6b, 0xeb6b }, +/* 0xeb6c */ { false, 0xeb6c, 0xeb6c }, +/* 0xeb6d */ { false, 0xeb6d, 0xeb6d }, +/* 0xeb6e */ { false, 0xeb6e, 0xeb6e }, +/* 0xeb6f */ { false, 0xeb6f, 0xeb6f }, +/* 0xeb70 */ { false, 0xeb70, 0xeb70 }, +/* 0xeb71 */ { false, 0xeb71, 0xeb71 }, +/* 0xeb72 */ { false, 0xeb72, 0xeb72 }, +/* 0xeb73 */ { false, 0xeb73, 0xeb73 }, +/* 0xeb74 */ { false, 0xeb74, 0xeb74 }, +/* 0xeb75 */ { false, 0xeb75, 0xeb75 }, +/* 0xeb76 */ { false, 0xeb76, 0xeb76 }, +/* 0xeb77 */ { false, 0xeb77, 0xeb77 }, +/* 0xeb78 */ { false, 0xeb78, 0xeb78 }, +/* 0xeb79 */ { false, 0xeb79, 0xeb79 }, +/* 0xeb7a */ { false, 0xeb7a, 0xeb7a }, +/* 0xeb7b */ { false, 0xeb7b, 0xeb7b }, +/* 0xeb7c */ { false, 0xeb7c, 0xeb7c }, +/* 0xeb7d */ { false, 0xeb7d, 0xeb7d }, +/* 0xeb7e */ { false, 0xeb7e, 0xeb7e }, +/* 0xeb7f */ { false, 0xeb7f, 0xeb7f }, +/* 0xeb80 */ { false, 0xeb80, 0xeb80 }, +/* 0xeb81 */ { false, 0xeb81, 0xeb81 }, +/* 0xeb82 */ { false, 0xeb82, 0xeb82 }, +/* 0xeb83 */ { false, 0xeb83, 0xeb83 }, +/* 0xeb84 */ { false, 0xeb84, 0xeb84 }, +/* 0xeb85 */ { false, 0xeb85, 0xeb85 }, +/* 0xeb86 */ { false, 0xeb86, 0xeb86 }, +/* 0xeb87 */ { false, 0xeb87, 0xeb87 }, +/* 0xeb88 */ { false, 0xeb88, 0xeb88 }, +/* 0xeb89 */ { false, 0xeb89, 0xeb89 }, +/* 0xeb8a */ { false, 0xeb8a, 0xeb8a }, +/* 0xeb8b */ { false, 0xeb8b, 0xeb8b }, +/* 0xeb8c */ { false, 0xeb8c, 0xeb8c }, +/* 0xeb8d */ { false, 0xeb8d, 0xeb8d }, +/* 0xeb8e */ { false, 0xeb8e, 0xeb8e }, +/* 0xeb8f */ { false, 0xeb8f, 0xeb8f }, +/* 0xeb90 */ { false, 0xeb90, 0xeb90 }, +/* 0xeb91 */ { false, 0xeb91, 0xeb91 }, +/* 0xeb92 */ { false, 0xeb92, 0xeb92 }, +/* 0xeb93 */ { false, 0xeb93, 0xeb93 }, +/* 0xeb94 */ { false, 0xeb94, 0xeb94 }, +/* 0xeb95 */ { false, 0xeb95, 0xeb95 }, +/* 0xeb96 */ { false, 0xeb96, 0xeb96 }, +/* 0xeb97 */ { false, 0xeb97, 0xeb97 }, +/* 0xeb98 */ { false, 0xeb98, 0xeb98 }, +/* 0xeb99 */ { false, 0xeb99, 0xeb99 }, +/* 0xeb9a */ { false, 0xeb9a, 0xeb9a }, +/* 0xeb9b */ { false, 0xeb9b, 0xeb9b }, +/* 0xeb9c */ { false, 0xeb9c, 0xeb9c }, +/* 0xeb9d */ { false, 0xeb9d, 0xeb9d }, +/* 0xeb9e */ { false, 0xeb9e, 0xeb9e }, +/* 0xeb9f */ { false, 0xeb9f, 0xeb9f }, +/* 0xeba0 */ { false, 0xeba0, 0xeba0 }, +/* 0xeba1 */ { false, 0xeba1, 0xeba1 }, +/* 0xeba2 */ { false, 0xeba2, 0xeba2 }, +/* 0xeba3 */ { false, 0xeba3, 0xeba3 }, +/* 0xeba4 */ { false, 0xeba4, 0xeba4 }, +/* 0xeba5 */ { false, 0xeba5, 0xeba5 }, +/* 0xeba6 */ { false, 0xeba6, 0xeba6 }, +/* 0xeba7 */ { false, 0xeba7, 0xeba7 }, +/* 0xeba8 */ { false, 0xeba8, 0xeba8 }, +/* 0xeba9 */ { false, 0xeba9, 0xeba9 }, +/* 0xebaa */ { false, 0xebaa, 0xebaa }, +/* 0xebab */ { false, 0xebab, 0xebab }, +/* 0xebac */ { false, 0xebac, 0xebac }, +/* 0xebad */ { false, 0xebad, 0xebad }, +/* 0xebae */ { false, 0xebae, 0xebae }, +/* 0xebaf */ { false, 0xebaf, 0xebaf }, +/* 0xebb0 */ { false, 0xebb0, 0xebb0 }, +/* 0xebb1 */ { false, 0xebb1, 0xebb1 }, +/* 0xebb2 */ { false, 0xebb2, 0xebb2 }, +/* 0xebb3 */ { false, 0xebb3, 0xebb3 }, +/* 0xebb4 */ { false, 0xebb4, 0xebb4 }, +/* 0xebb5 */ { false, 0xebb5, 0xebb5 }, +/* 0xebb6 */ { false, 0xebb6, 0xebb6 }, +/* 0xebb7 */ { false, 0xebb7, 0xebb7 }, +/* 0xebb8 */ { false, 0xebb8, 0xebb8 }, +/* 0xebb9 */ { false, 0xebb9, 0xebb9 }, +/* 0xebba */ { false, 0xebba, 0xebba }, +/* 0xebbb */ { false, 0xebbb, 0xebbb }, +/* 0xebbc */ { false, 0xebbc, 0xebbc }, +/* 0xebbd */ { false, 0xebbd, 0xebbd }, +/* 0xebbe */ { false, 0xebbe, 0xebbe }, +/* 0xebbf */ { false, 0xebbf, 0xebbf }, +/* 0xebc0 */ { false, 0xebc0, 0xebc0 }, +/* 0xebc1 */ { false, 0xebc1, 0xebc1 }, +/* 0xebc2 */ { false, 0xebc2, 0xebc2 }, +/* 0xebc3 */ { false, 0xebc3, 0xebc3 }, +/* 0xebc4 */ { false, 0xebc4, 0xebc4 }, +/* 0xebc5 */ { false, 0xebc5, 0xebc5 }, +/* 0xebc6 */ { false, 0xebc6, 0xebc6 }, +/* 0xebc7 */ { false, 0xebc7, 0xebc7 }, +/* 0xebc8 */ { false, 0xebc8, 0xebc8 }, +/* 0xebc9 */ { false, 0xebc9, 0xebc9 }, +/* 0xebca */ { false, 0xebca, 0xebca }, +/* 0xebcb */ { false, 0xebcb, 0xebcb }, +/* 0xebcc */ { false, 0xebcc, 0xebcc }, +/* 0xebcd */ { false, 0xebcd, 0xebcd }, +/* 0xebce */ { false, 0xebce, 0xebce }, +/* 0xebcf */ { false, 0xebcf, 0xebcf }, +/* 0xebd0 */ { false, 0xebd0, 0xebd0 }, +/* 0xebd1 */ { false, 0xebd1, 0xebd1 }, +/* 0xebd2 */ { false, 0xebd2, 0xebd2 }, +/* 0xebd3 */ { false, 0xebd3, 0xebd3 }, +/* 0xebd4 */ { false, 0xebd4, 0xebd4 }, +/* 0xebd5 */ { false, 0xebd5, 0xebd5 }, +/* 0xebd6 */ { false, 0xebd6, 0xebd6 }, +/* 0xebd7 */ { false, 0xebd7, 0xebd7 }, +/* 0xebd8 */ { false, 0xebd8, 0xebd8 }, +/* 0xebd9 */ { false, 0xebd9, 0xebd9 }, +/* 0xebda */ { false, 0xebda, 0xebda }, +/* 0xebdb */ { false, 0xebdb, 0xebdb }, +/* 0xebdc */ { false, 0xebdc, 0xebdc }, +/* 0xebdd */ { false, 0xebdd, 0xebdd }, +/* 0xebde */ { false, 0xebde, 0xebde }, +/* 0xebdf */ { false, 0xebdf, 0xebdf }, +/* 0xebe0 */ { false, 0xebe0, 0xebe0 }, +/* 0xebe1 */ { false, 0xebe1, 0xebe1 }, +/* 0xebe2 */ { false, 0xebe2, 0xebe2 }, +/* 0xebe3 */ { false, 0xebe3, 0xebe3 }, +/* 0xebe4 */ { false, 0xebe4, 0xebe4 }, +/* 0xebe5 */ { false, 0xebe5, 0xebe5 }, +/* 0xebe6 */ { false, 0xebe6, 0xebe6 }, +/* 0xebe7 */ { false, 0xebe7, 0xebe7 }, +/* 0xebe8 */ { false, 0xebe8, 0xebe8 }, +/* 0xebe9 */ { false, 0xebe9, 0xebe9 }, +/* 0xebea */ { false, 0xebea, 0xebea }, +/* 0xebeb */ { false, 0xebeb, 0xebeb }, +/* 0xebec */ { false, 0xebec, 0xebec }, +/* 0xebed */ { false, 0xebed, 0xebed }, +/* 0xebee */ { false, 0xebee, 0xebee }, +/* 0xebef */ { false, 0xebef, 0xebef }, +/* 0xebf0 */ { false, 0xebf0, 0xebf0 }, +/* 0xebf1 */ { false, 0xebf1, 0xebf1 }, +/* 0xebf2 */ { false, 0xebf2, 0xebf2 }, +/* 0xebf3 */ { false, 0xebf3, 0xebf3 }, +/* 0xebf4 */ { false, 0xebf4, 0xebf4 }, +/* 0xebf5 */ { false, 0xebf5, 0xebf5 }, +/* 0xebf6 */ { false, 0xebf6, 0xebf6 }, +/* 0xebf7 */ { false, 0xebf7, 0xebf7 }, +/* 0xebf8 */ { false, 0xebf8, 0xebf8 }, +/* 0xebf9 */ { false, 0xebf9, 0xebf9 }, +/* 0xebfa */ { false, 0xebfa, 0xebfa }, +/* 0xebfb */ { false, 0xebfb, 0xebfb }, +/* 0xebfc */ { false, 0xebfc, 0xebfc }, +/* 0xebfd */ { false, 0xebfd, 0xebfd }, +/* 0xebfe */ { false, 0xebfe, 0xebfe }, +/* 0xebff */ { false, 0xebff, 0xebff }, +/* 0xec00 */ { false, 0xec00, 0xec00 }, +/* 0xec01 */ { false, 0xec01, 0xec01 }, +/* 0xec02 */ { false, 0xec02, 0xec02 }, +/* 0xec03 */ { false, 0xec03, 0xec03 }, +/* 0xec04 */ { false, 0xec04, 0xec04 }, +/* 0xec05 */ { false, 0xec05, 0xec05 }, +/* 0xec06 */ { false, 0xec06, 0xec06 }, +/* 0xec07 */ { false, 0xec07, 0xec07 }, +/* 0xec08 */ { false, 0xec08, 0xec08 }, +/* 0xec09 */ { false, 0xec09, 0xec09 }, +/* 0xec0a */ { false, 0xec0a, 0xec0a }, +/* 0xec0b */ { false, 0xec0b, 0xec0b }, +/* 0xec0c */ { false, 0xec0c, 0xec0c }, +/* 0xec0d */ { false, 0xec0d, 0xec0d }, +/* 0xec0e */ { false, 0xec0e, 0xec0e }, +/* 0xec0f */ { false, 0xec0f, 0xec0f }, +/* 0xec10 */ { false, 0xec10, 0xec10 }, +/* 0xec11 */ { false, 0xec11, 0xec11 }, +/* 0xec12 */ { false, 0xec12, 0xec12 }, +/* 0xec13 */ { false, 0xec13, 0xec13 }, +/* 0xec14 */ { false, 0xec14, 0xec14 }, +/* 0xec15 */ { false, 0xec15, 0xec15 }, +/* 0xec16 */ { false, 0xec16, 0xec16 }, +/* 0xec17 */ { false, 0xec17, 0xec17 }, +/* 0xec18 */ { false, 0xec18, 0xec18 }, +/* 0xec19 */ { false, 0xec19, 0xec19 }, +/* 0xec1a */ { false, 0xec1a, 0xec1a }, +/* 0xec1b */ { false, 0xec1b, 0xec1b }, +/* 0xec1c */ { false, 0xec1c, 0xec1c }, +/* 0xec1d */ { false, 0xec1d, 0xec1d }, +/* 0xec1e */ { false, 0xec1e, 0xec1e }, +/* 0xec1f */ { false, 0xec1f, 0xec1f }, +/* 0xec20 */ { false, 0xec20, 0xec20 }, +/* 0xec21 */ { false, 0xec21, 0xec21 }, +/* 0xec22 */ { false, 0xec22, 0xec22 }, +/* 0xec23 */ { false, 0xec23, 0xec23 }, +/* 0xec24 */ { false, 0xec24, 0xec24 }, +/* 0xec25 */ { false, 0xec25, 0xec25 }, +/* 0xec26 */ { false, 0xec26, 0xec26 }, +/* 0xec27 */ { false, 0xec27, 0xec27 }, +/* 0xec28 */ { false, 0xec28, 0xec28 }, +/* 0xec29 */ { false, 0xec29, 0xec29 }, +/* 0xec2a */ { false, 0xec2a, 0xec2a }, +/* 0xec2b */ { false, 0xec2b, 0xec2b }, +/* 0xec2c */ { false, 0xec2c, 0xec2c }, +/* 0xec2d */ { false, 0xec2d, 0xec2d }, +/* 0xec2e */ { false, 0xec2e, 0xec2e }, +/* 0xec2f */ { false, 0xec2f, 0xec2f }, +/* 0xec30 */ { false, 0xec30, 0xec30 }, +/* 0xec31 */ { false, 0xec31, 0xec31 }, +/* 0xec32 */ { false, 0xec32, 0xec32 }, +/* 0xec33 */ { false, 0xec33, 0xec33 }, +/* 0xec34 */ { false, 0xec34, 0xec34 }, +/* 0xec35 */ { false, 0xec35, 0xec35 }, +/* 0xec36 */ { false, 0xec36, 0xec36 }, +/* 0xec37 */ { false, 0xec37, 0xec37 }, +/* 0xec38 */ { false, 0xec38, 0xec38 }, +/* 0xec39 */ { false, 0xec39, 0xec39 }, +/* 0xec3a */ { false, 0xec3a, 0xec3a }, +/* 0xec3b */ { false, 0xec3b, 0xec3b }, +/* 0xec3c */ { false, 0xec3c, 0xec3c }, +/* 0xec3d */ { false, 0xec3d, 0xec3d }, +/* 0xec3e */ { false, 0xec3e, 0xec3e }, +/* 0xec3f */ { false, 0xec3f, 0xec3f }, +/* 0xec40 */ { false, 0xec40, 0xec40 }, +/* 0xec41 */ { false, 0xec41, 0xec41 }, +/* 0xec42 */ { false, 0xec42, 0xec42 }, +/* 0xec43 */ { false, 0xec43, 0xec43 }, +/* 0xec44 */ { false, 0xec44, 0xec44 }, +/* 0xec45 */ { false, 0xec45, 0xec45 }, +/* 0xec46 */ { false, 0xec46, 0xec46 }, +/* 0xec47 */ { false, 0xec47, 0xec47 }, +/* 0xec48 */ { false, 0xec48, 0xec48 }, +/* 0xec49 */ { false, 0xec49, 0xec49 }, +/* 0xec4a */ { false, 0xec4a, 0xec4a }, +/* 0xec4b */ { false, 0xec4b, 0xec4b }, +/* 0xec4c */ { false, 0xec4c, 0xec4c }, +/* 0xec4d */ { false, 0xec4d, 0xec4d }, +/* 0xec4e */ { false, 0xec4e, 0xec4e }, +/* 0xec4f */ { false, 0xec4f, 0xec4f }, +/* 0xec50 */ { false, 0xec50, 0xec50 }, +/* 0xec51 */ { false, 0xec51, 0xec51 }, +/* 0xec52 */ { false, 0xec52, 0xec52 }, +/* 0xec53 */ { false, 0xec53, 0xec53 }, +/* 0xec54 */ { false, 0xec54, 0xec54 }, +/* 0xec55 */ { false, 0xec55, 0xec55 }, +/* 0xec56 */ { false, 0xec56, 0xec56 }, +/* 0xec57 */ { false, 0xec57, 0xec57 }, +/* 0xec58 */ { false, 0xec58, 0xec58 }, +/* 0xec59 */ { false, 0xec59, 0xec59 }, +/* 0xec5a */ { false, 0xec5a, 0xec5a }, +/* 0xec5b */ { false, 0xec5b, 0xec5b }, +/* 0xec5c */ { false, 0xec5c, 0xec5c }, +/* 0xec5d */ { false, 0xec5d, 0xec5d }, +/* 0xec5e */ { false, 0xec5e, 0xec5e }, +/* 0xec5f */ { false, 0xec5f, 0xec5f }, +/* 0xec60 */ { false, 0xec60, 0xec60 }, +/* 0xec61 */ { false, 0xec61, 0xec61 }, +/* 0xec62 */ { false, 0xec62, 0xec62 }, +/* 0xec63 */ { false, 0xec63, 0xec63 }, +/* 0xec64 */ { false, 0xec64, 0xec64 }, +/* 0xec65 */ { false, 0xec65, 0xec65 }, +/* 0xec66 */ { false, 0xec66, 0xec66 }, +/* 0xec67 */ { false, 0xec67, 0xec67 }, +/* 0xec68 */ { false, 0xec68, 0xec68 }, +/* 0xec69 */ { false, 0xec69, 0xec69 }, +/* 0xec6a */ { false, 0xec6a, 0xec6a }, +/* 0xec6b */ { false, 0xec6b, 0xec6b }, +/* 0xec6c */ { false, 0xec6c, 0xec6c }, +/* 0xec6d */ { false, 0xec6d, 0xec6d }, +/* 0xec6e */ { false, 0xec6e, 0xec6e }, +/* 0xec6f */ { false, 0xec6f, 0xec6f }, +/* 0xec70 */ { false, 0xec70, 0xec70 }, +/* 0xec71 */ { false, 0xec71, 0xec71 }, +/* 0xec72 */ { false, 0xec72, 0xec72 }, +/* 0xec73 */ { false, 0xec73, 0xec73 }, +/* 0xec74 */ { false, 0xec74, 0xec74 }, +/* 0xec75 */ { false, 0xec75, 0xec75 }, +/* 0xec76 */ { false, 0xec76, 0xec76 }, +/* 0xec77 */ { false, 0xec77, 0xec77 }, +/* 0xec78 */ { false, 0xec78, 0xec78 }, +/* 0xec79 */ { false, 0xec79, 0xec79 }, +/* 0xec7a */ { false, 0xec7a, 0xec7a }, +/* 0xec7b */ { false, 0xec7b, 0xec7b }, +/* 0xec7c */ { false, 0xec7c, 0xec7c }, +/* 0xec7d */ { false, 0xec7d, 0xec7d }, +/* 0xec7e */ { false, 0xec7e, 0xec7e }, +/* 0xec7f */ { false, 0xec7f, 0xec7f }, +/* 0xec80 */ { false, 0xec80, 0xec80 }, +/* 0xec81 */ { false, 0xec81, 0xec81 }, +/* 0xec82 */ { false, 0xec82, 0xec82 }, +/* 0xec83 */ { false, 0xec83, 0xec83 }, +/* 0xec84 */ { false, 0xec84, 0xec84 }, +/* 0xec85 */ { false, 0xec85, 0xec85 }, +/* 0xec86 */ { false, 0xec86, 0xec86 }, +/* 0xec87 */ { false, 0xec87, 0xec87 }, +/* 0xec88 */ { false, 0xec88, 0xec88 }, +/* 0xec89 */ { false, 0xec89, 0xec89 }, +/* 0xec8a */ { false, 0xec8a, 0xec8a }, +/* 0xec8b */ { false, 0xec8b, 0xec8b }, +/* 0xec8c */ { false, 0xec8c, 0xec8c }, +/* 0xec8d */ { false, 0xec8d, 0xec8d }, +/* 0xec8e */ { false, 0xec8e, 0xec8e }, +/* 0xec8f */ { false, 0xec8f, 0xec8f }, +/* 0xec90 */ { false, 0xec90, 0xec90 }, +/* 0xec91 */ { false, 0xec91, 0xec91 }, +/* 0xec92 */ { false, 0xec92, 0xec92 }, +/* 0xec93 */ { false, 0xec93, 0xec93 }, +/* 0xec94 */ { false, 0xec94, 0xec94 }, +/* 0xec95 */ { false, 0xec95, 0xec95 }, +/* 0xec96 */ { false, 0xec96, 0xec96 }, +/* 0xec97 */ { false, 0xec97, 0xec97 }, +/* 0xec98 */ { false, 0xec98, 0xec98 }, +/* 0xec99 */ { false, 0xec99, 0xec99 }, +/* 0xec9a */ { false, 0xec9a, 0xec9a }, +/* 0xec9b */ { false, 0xec9b, 0xec9b }, +/* 0xec9c */ { false, 0xec9c, 0xec9c }, +/* 0xec9d */ { false, 0xec9d, 0xec9d }, +/* 0xec9e */ { false, 0xec9e, 0xec9e }, +/* 0xec9f */ { false, 0xec9f, 0xec9f }, +/* 0xeca0 */ { false, 0xeca0, 0xeca0 }, +/* 0xeca1 */ { false, 0xeca1, 0xeca1 }, +/* 0xeca2 */ { false, 0xeca2, 0xeca2 }, +/* 0xeca3 */ { false, 0xeca3, 0xeca3 }, +/* 0xeca4 */ { false, 0xeca4, 0xeca4 }, +/* 0xeca5 */ { false, 0xeca5, 0xeca5 }, +/* 0xeca6 */ { false, 0xeca6, 0xeca6 }, +/* 0xeca7 */ { false, 0xeca7, 0xeca7 }, +/* 0xeca8 */ { false, 0xeca8, 0xeca8 }, +/* 0xeca9 */ { false, 0xeca9, 0xeca9 }, +/* 0xecaa */ { false, 0xecaa, 0xecaa }, +/* 0xecab */ { false, 0xecab, 0xecab }, +/* 0xecac */ { false, 0xecac, 0xecac }, +/* 0xecad */ { false, 0xecad, 0xecad }, +/* 0xecae */ { false, 0xecae, 0xecae }, +/* 0xecaf */ { false, 0xecaf, 0xecaf }, +/* 0xecb0 */ { false, 0xecb0, 0xecb0 }, +/* 0xecb1 */ { false, 0xecb1, 0xecb1 }, +/* 0xecb2 */ { false, 0xecb2, 0xecb2 }, +/* 0xecb3 */ { false, 0xecb3, 0xecb3 }, +/* 0xecb4 */ { false, 0xecb4, 0xecb4 }, +/* 0xecb5 */ { false, 0xecb5, 0xecb5 }, +/* 0xecb6 */ { false, 0xecb6, 0xecb6 }, +/* 0xecb7 */ { false, 0xecb7, 0xecb7 }, +/* 0xecb8 */ { false, 0xecb8, 0xecb8 }, +/* 0xecb9 */ { false, 0xecb9, 0xecb9 }, +/* 0xecba */ { false, 0xecba, 0xecba }, +/* 0xecbb */ { false, 0xecbb, 0xecbb }, +/* 0xecbc */ { false, 0xecbc, 0xecbc }, +/* 0xecbd */ { false, 0xecbd, 0xecbd }, +/* 0xecbe */ { false, 0xecbe, 0xecbe }, +/* 0xecbf */ { false, 0xecbf, 0xecbf }, +/* 0xecc0 */ { false, 0xecc0, 0xecc0 }, +/* 0xecc1 */ { false, 0xecc1, 0xecc1 }, +/* 0xecc2 */ { false, 0xecc2, 0xecc2 }, +/* 0xecc3 */ { false, 0xecc3, 0xecc3 }, +/* 0xecc4 */ { false, 0xecc4, 0xecc4 }, +/* 0xecc5 */ { false, 0xecc5, 0xecc5 }, +/* 0xecc6 */ { false, 0xecc6, 0xecc6 }, +/* 0xecc7 */ { false, 0xecc7, 0xecc7 }, +/* 0xecc8 */ { false, 0xecc8, 0xecc8 }, +/* 0xecc9 */ { false, 0xecc9, 0xecc9 }, +/* 0xecca */ { false, 0xecca, 0xecca }, +/* 0xeccb */ { false, 0xeccb, 0xeccb }, +/* 0xeccc */ { false, 0xeccc, 0xeccc }, +/* 0xeccd */ { false, 0xeccd, 0xeccd }, +/* 0xecce */ { false, 0xecce, 0xecce }, +/* 0xeccf */ { false, 0xeccf, 0xeccf }, +/* 0xecd0 */ { false, 0xecd0, 0xecd0 }, +/* 0xecd1 */ { false, 0xecd1, 0xecd1 }, +/* 0xecd2 */ { false, 0xecd2, 0xecd2 }, +/* 0xecd3 */ { false, 0xecd3, 0xecd3 }, +/* 0xecd4 */ { false, 0xecd4, 0xecd4 }, +/* 0xecd5 */ { false, 0xecd5, 0xecd5 }, +/* 0xecd6 */ { false, 0xecd6, 0xecd6 }, +/* 0xecd7 */ { false, 0xecd7, 0xecd7 }, +/* 0xecd8 */ { false, 0xecd8, 0xecd8 }, +/* 0xecd9 */ { false, 0xecd9, 0xecd9 }, +/* 0xecda */ { false, 0xecda, 0xecda }, +/* 0xecdb */ { false, 0xecdb, 0xecdb }, +/* 0xecdc */ { false, 0xecdc, 0xecdc }, +/* 0xecdd */ { false, 0xecdd, 0xecdd }, +/* 0xecde */ { false, 0xecde, 0xecde }, +/* 0xecdf */ { false, 0xecdf, 0xecdf }, +/* 0xece0 */ { false, 0xece0, 0xece0 }, +/* 0xece1 */ { false, 0xece1, 0xece1 }, +/* 0xece2 */ { false, 0xece2, 0xece2 }, +/* 0xece3 */ { false, 0xece3, 0xece3 }, +/* 0xece4 */ { false, 0xece4, 0xece4 }, +/* 0xece5 */ { false, 0xece5, 0xece5 }, +/* 0xece6 */ { false, 0xece6, 0xece6 }, +/* 0xece7 */ { false, 0xece7, 0xece7 }, +/* 0xece8 */ { false, 0xece8, 0xece8 }, +/* 0xece9 */ { false, 0xece9, 0xece9 }, +/* 0xecea */ { false, 0xecea, 0xecea }, +/* 0xeceb */ { false, 0xeceb, 0xeceb }, +/* 0xecec */ { false, 0xecec, 0xecec }, +/* 0xeced */ { false, 0xeced, 0xeced }, +/* 0xecee */ { false, 0xecee, 0xecee }, +/* 0xecef */ { false, 0xecef, 0xecef }, +/* 0xecf0 */ { false, 0xecf0, 0xecf0 }, +/* 0xecf1 */ { false, 0xecf1, 0xecf1 }, +/* 0xecf2 */ { false, 0xecf2, 0xecf2 }, +/* 0xecf3 */ { false, 0xecf3, 0xecf3 }, +/* 0xecf4 */ { false, 0xecf4, 0xecf4 }, +/* 0xecf5 */ { false, 0xecf5, 0xecf5 }, +/* 0xecf6 */ { false, 0xecf6, 0xecf6 }, +/* 0xecf7 */ { false, 0xecf7, 0xecf7 }, +/* 0xecf8 */ { false, 0xecf8, 0xecf8 }, +/* 0xecf9 */ { false, 0xecf9, 0xecf9 }, +/* 0xecfa */ { false, 0xecfa, 0xecfa }, +/* 0xecfb */ { false, 0xecfb, 0xecfb }, +/* 0xecfc */ { false, 0xecfc, 0xecfc }, +/* 0xecfd */ { false, 0xecfd, 0xecfd }, +/* 0xecfe */ { false, 0xecfe, 0xecfe }, +/* 0xecff */ { false, 0xecff, 0xecff }, +/* 0xed00 */ { false, 0xed00, 0xed00 }, +/* 0xed01 */ { false, 0xed01, 0xed01 }, +/* 0xed02 */ { false, 0xed02, 0xed02 }, +/* 0xed03 */ { false, 0xed03, 0xed03 }, +/* 0xed04 */ { false, 0xed04, 0xed04 }, +/* 0xed05 */ { false, 0xed05, 0xed05 }, +/* 0xed06 */ { false, 0xed06, 0xed06 }, +/* 0xed07 */ { false, 0xed07, 0xed07 }, +/* 0xed08 */ { false, 0xed08, 0xed08 }, +/* 0xed09 */ { false, 0xed09, 0xed09 }, +/* 0xed0a */ { false, 0xed0a, 0xed0a }, +/* 0xed0b */ { false, 0xed0b, 0xed0b }, +/* 0xed0c */ { false, 0xed0c, 0xed0c }, +/* 0xed0d */ { false, 0xed0d, 0xed0d }, +/* 0xed0e */ { false, 0xed0e, 0xed0e }, +/* 0xed0f */ { false, 0xed0f, 0xed0f }, +/* 0xed10 */ { false, 0xed10, 0xed10 }, +/* 0xed11 */ { false, 0xed11, 0xed11 }, +/* 0xed12 */ { false, 0xed12, 0xed12 }, +/* 0xed13 */ { false, 0xed13, 0xed13 }, +/* 0xed14 */ { false, 0xed14, 0xed14 }, +/* 0xed15 */ { false, 0xed15, 0xed15 }, +/* 0xed16 */ { false, 0xed16, 0xed16 }, +/* 0xed17 */ { false, 0xed17, 0xed17 }, +/* 0xed18 */ { false, 0xed18, 0xed18 }, +/* 0xed19 */ { false, 0xed19, 0xed19 }, +/* 0xed1a */ { false, 0xed1a, 0xed1a }, +/* 0xed1b */ { false, 0xed1b, 0xed1b }, +/* 0xed1c */ { false, 0xed1c, 0xed1c }, +/* 0xed1d */ { false, 0xed1d, 0xed1d }, +/* 0xed1e */ { false, 0xed1e, 0xed1e }, +/* 0xed1f */ { false, 0xed1f, 0xed1f }, +/* 0xed20 */ { false, 0xed20, 0xed20 }, +/* 0xed21 */ { false, 0xed21, 0xed21 }, +/* 0xed22 */ { false, 0xed22, 0xed22 }, +/* 0xed23 */ { false, 0xed23, 0xed23 }, +/* 0xed24 */ { false, 0xed24, 0xed24 }, +/* 0xed25 */ { false, 0xed25, 0xed25 }, +/* 0xed26 */ { false, 0xed26, 0xed26 }, +/* 0xed27 */ { false, 0xed27, 0xed27 }, +/* 0xed28 */ { false, 0xed28, 0xed28 }, +/* 0xed29 */ { false, 0xed29, 0xed29 }, +/* 0xed2a */ { false, 0xed2a, 0xed2a }, +/* 0xed2b */ { false, 0xed2b, 0xed2b }, +/* 0xed2c */ { false, 0xed2c, 0xed2c }, +/* 0xed2d */ { false, 0xed2d, 0xed2d }, +/* 0xed2e */ { false, 0xed2e, 0xed2e }, +/* 0xed2f */ { false, 0xed2f, 0xed2f }, +/* 0xed30 */ { false, 0xed30, 0xed30 }, +/* 0xed31 */ { false, 0xed31, 0xed31 }, +/* 0xed32 */ { false, 0xed32, 0xed32 }, +/* 0xed33 */ { false, 0xed33, 0xed33 }, +/* 0xed34 */ { false, 0xed34, 0xed34 }, +/* 0xed35 */ { false, 0xed35, 0xed35 }, +/* 0xed36 */ { false, 0xed36, 0xed36 }, +/* 0xed37 */ { false, 0xed37, 0xed37 }, +/* 0xed38 */ { false, 0xed38, 0xed38 }, +/* 0xed39 */ { false, 0xed39, 0xed39 }, +/* 0xed3a */ { false, 0xed3a, 0xed3a }, +/* 0xed3b */ { false, 0xed3b, 0xed3b }, +/* 0xed3c */ { false, 0xed3c, 0xed3c }, +/* 0xed3d */ { false, 0xed3d, 0xed3d }, +/* 0xed3e */ { false, 0xed3e, 0xed3e }, +/* 0xed3f */ { false, 0xed3f, 0xed3f }, +/* 0xed40 */ { false, 0xed40, 0xed40 }, +/* 0xed41 */ { false, 0xed41, 0xed41 }, +/* 0xed42 */ { false, 0xed42, 0xed42 }, +/* 0xed43 */ { false, 0xed43, 0xed43 }, +/* 0xed44 */ { false, 0xed44, 0xed44 }, +/* 0xed45 */ { false, 0xed45, 0xed45 }, +/* 0xed46 */ { false, 0xed46, 0xed46 }, +/* 0xed47 */ { false, 0xed47, 0xed47 }, +/* 0xed48 */ { false, 0xed48, 0xed48 }, +/* 0xed49 */ { false, 0xed49, 0xed49 }, +/* 0xed4a */ { false, 0xed4a, 0xed4a }, +/* 0xed4b */ { false, 0xed4b, 0xed4b }, +/* 0xed4c */ { false, 0xed4c, 0xed4c }, +/* 0xed4d */ { false, 0xed4d, 0xed4d }, +/* 0xed4e */ { false, 0xed4e, 0xed4e }, +/* 0xed4f */ { false, 0xed4f, 0xed4f }, +/* 0xed50 */ { false, 0xed50, 0xed50 }, +/* 0xed51 */ { false, 0xed51, 0xed51 }, +/* 0xed52 */ { false, 0xed52, 0xed52 }, +/* 0xed53 */ { false, 0xed53, 0xed53 }, +/* 0xed54 */ { false, 0xed54, 0xed54 }, +/* 0xed55 */ { false, 0xed55, 0xed55 }, +/* 0xed56 */ { false, 0xed56, 0xed56 }, +/* 0xed57 */ { false, 0xed57, 0xed57 }, +/* 0xed58 */ { false, 0xed58, 0xed58 }, +/* 0xed59 */ { false, 0xed59, 0xed59 }, +/* 0xed5a */ { false, 0xed5a, 0xed5a }, +/* 0xed5b */ { false, 0xed5b, 0xed5b }, +/* 0xed5c */ { false, 0xed5c, 0xed5c }, +/* 0xed5d */ { false, 0xed5d, 0xed5d }, +/* 0xed5e */ { false, 0xed5e, 0xed5e }, +/* 0xed5f */ { false, 0xed5f, 0xed5f }, +/* 0xed60 */ { false, 0xed60, 0xed60 }, +/* 0xed61 */ { false, 0xed61, 0xed61 }, +/* 0xed62 */ { false, 0xed62, 0xed62 }, +/* 0xed63 */ { false, 0xed63, 0xed63 }, +/* 0xed64 */ { false, 0xed64, 0xed64 }, +/* 0xed65 */ { false, 0xed65, 0xed65 }, +/* 0xed66 */ { false, 0xed66, 0xed66 }, +/* 0xed67 */ { false, 0xed67, 0xed67 }, +/* 0xed68 */ { false, 0xed68, 0xed68 }, +/* 0xed69 */ { false, 0xed69, 0xed69 }, +/* 0xed6a */ { false, 0xed6a, 0xed6a }, +/* 0xed6b */ { false, 0xed6b, 0xed6b }, +/* 0xed6c */ { false, 0xed6c, 0xed6c }, +/* 0xed6d */ { false, 0xed6d, 0xed6d }, +/* 0xed6e */ { false, 0xed6e, 0xed6e }, +/* 0xed6f */ { false, 0xed6f, 0xed6f }, +/* 0xed70 */ { false, 0xed70, 0xed70 }, +/* 0xed71 */ { false, 0xed71, 0xed71 }, +/* 0xed72 */ { false, 0xed72, 0xed72 }, +/* 0xed73 */ { false, 0xed73, 0xed73 }, +/* 0xed74 */ { false, 0xed74, 0xed74 }, +/* 0xed75 */ { false, 0xed75, 0xed75 }, +/* 0xed76 */ { false, 0xed76, 0xed76 }, +/* 0xed77 */ { false, 0xed77, 0xed77 }, +/* 0xed78 */ { false, 0xed78, 0xed78 }, +/* 0xed79 */ { false, 0xed79, 0xed79 }, +/* 0xed7a */ { false, 0xed7a, 0xed7a }, +/* 0xed7b */ { false, 0xed7b, 0xed7b }, +/* 0xed7c */ { false, 0xed7c, 0xed7c }, +/* 0xed7d */ { false, 0xed7d, 0xed7d }, +/* 0xed7e */ { false, 0xed7e, 0xed7e }, +/* 0xed7f */ { false, 0xed7f, 0xed7f }, +/* 0xed80 */ { false, 0xed80, 0xed80 }, +/* 0xed81 */ { false, 0xed81, 0xed81 }, +/* 0xed82 */ { false, 0xed82, 0xed82 }, +/* 0xed83 */ { false, 0xed83, 0xed83 }, +/* 0xed84 */ { false, 0xed84, 0xed84 }, +/* 0xed85 */ { false, 0xed85, 0xed85 }, +/* 0xed86 */ { false, 0xed86, 0xed86 }, +/* 0xed87 */ { false, 0xed87, 0xed87 }, +/* 0xed88 */ { false, 0xed88, 0xed88 }, +/* 0xed89 */ { false, 0xed89, 0xed89 }, +/* 0xed8a */ { false, 0xed8a, 0xed8a }, +/* 0xed8b */ { false, 0xed8b, 0xed8b }, +/* 0xed8c */ { false, 0xed8c, 0xed8c }, +/* 0xed8d */ { false, 0xed8d, 0xed8d }, +/* 0xed8e */ { false, 0xed8e, 0xed8e }, +/* 0xed8f */ { false, 0xed8f, 0xed8f }, +/* 0xed90 */ { false, 0xed90, 0xed90 }, +/* 0xed91 */ { false, 0xed91, 0xed91 }, +/* 0xed92 */ { false, 0xed92, 0xed92 }, +/* 0xed93 */ { false, 0xed93, 0xed93 }, +/* 0xed94 */ { false, 0xed94, 0xed94 }, +/* 0xed95 */ { false, 0xed95, 0xed95 }, +/* 0xed96 */ { false, 0xed96, 0xed96 }, +/* 0xed97 */ { false, 0xed97, 0xed97 }, +/* 0xed98 */ { false, 0xed98, 0xed98 }, +/* 0xed99 */ { false, 0xed99, 0xed99 }, +/* 0xed9a */ { false, 0xed9a, 0xed9a }, +/* 0xed9b */ { false, 0xed9b, 0xed9b }, +/* 0xed9c */ { false, 0xed9c, 0xed9c }, +/* 0xed9d */ { false, 0xed9d, 0xed9d }, +/* 0xed9e */ { false, 0xed9e, 0xed9e }, +/* 0xed9f */ { false, 0xed9f, 0xed9f }, +/* 0xeda0 */ { false, 0xeda0, 0xeda0 }, +/* 0xeda1 */ { false, 0xeda1, 0xeda1 }, +/* 0xeda2 */ { false, 0xeda2, 0xeda2 }, +/* 0xeda3 */ { false, 0xeda3, 0xeda3 }, +/* 0xeda4 */ { false, 0xeda4, 0xeda4 }, +/* 0xeda5 */ { false, 0xeda5, 0xeda5 }, +/* 0xeda6 */ { false, 0xeda6, 0xeda6 }, +/* 0xeda7 */ { false, 0xeda7, 0xeda7 }, +/* 0xeda8 */ { false, 0xeda8, 0xeda8 }, +/* 0xeda9 */ { false, 0xeda9, 0xeda9 }, +/* 0xedaa */ { false, 0xedaa, 0xedaa }, +/* 0xedab */ { false, 0xedab, 0xedab }, +/* 0xedac */ { false, 0xedac, 0xedac }, +/* 0xedad */ { false, 0xedad, 0xedad }, +/* 0xedae */ { false, 0xedae, 0xedae }, +/* 0xedaf */ { false, 0xedaf, 0xedaf }, +/* 0xedb0 */ { false, 0xedb0, 0xedb0 }, +/* 0xedb1 */ { false, 0xedb1, 0xedb1 }, +/* 0xedb2 */ { false, 0xedb2, 0xedb2 }, +/* 0xedb3 */ { false, 0xedb3, 0xedb3 }, +/* 0xedb4 */ { false, 0xedb4, 0xedb4 }, +/* 0xedb5 */ { false, 0xedb5, 0xedb5 }, +/* 0xedb6 */ { false, 0xedb6, 0xedb6 }, +/* 0xedb7 */ { false, 0xedb7, 0xedb7 }, +/* 0xedb8 */ { false, 0xedb8, 0xedb8 }, +/* 0xedb9 */ { false, 0xedb9, 0xedb9 }, +/* 0xedba */ { false, 0xedba, 0xedba }, +/* 0xedbb */ { false, 0xedbb, 0xedbb }, +/* 0xedbc */ { false, 0xedbc, 0xedbc }, +/* 0xedbd */ { false, 0xedbd, 0xedbd }, +/* 0xedbe */ { false, 0xedbe, 0xedbe }, +/* 0xedbf */ { false, 0xedbf, 0xedbf }, +/* 0xedc0 */ { false, 0xedc0, 0xedc0 }, +/* 0xedc1 */ { false, 0xedc1, 0xedc1 }, +/* 0xedc2 */ { false, 0xedc2, 0xedc2 }, +/* 0xedc3 */ { false, 0xedc3, 0xedc3 }, +/* 0xedc4 */ { false, 0xedc4, 0xedc4 }, +/* 0xedc5 */ { false, 0xedc5, 0xedc5 }, +/* 0xedc6 */ { false, 0xedc6, 0xedc6 }, +/* 0xedc7 */ { false, 0xedc7, 0xedc7 }, +/* 0xedc8 */ { false, 0xedc8, 0xedc8 }, +/* 0xedc9 */ { false, 0xedc9, 0xedc9 }, +/* 0xedca */ { false, 0xedca, 0xedca }, +/* 0xedcb */ { false, 0xedcb, 0xedcb }, +/* 0xedcc */ { false, 0xedcc, 0xedcc }, +/* 0xedcd */ { false, 0xedcd, 0xedcd }, +/* 0xedce */ { false, 0xedce, 0xedce }, +/* 0xedcf */ { false, 0xedcf, 0xedcf }, +/* 0xedd0 */ { false, 0xedd0, 0xedd0 }, +/* 0xedd1 */ { false, 0xedd1, 0xedd1 }, +/* 0xedd2 */ { false, 0xedd2, 0xedd2 }, +/* 0xedd3 */ { false, 0xedd3, 0xedd3 }, +/* 0xedd4 */ { false, 0xedd4, 0xedd4 }, +/* 0xedd5 */ { false, 0xedd5, 0xedd5 }, +/* 0xedd6 */ { false, 0xedd6, 0xedd6 }, +/* 0xedd7 */ { false, 0xedd7, 0xedd7 }, +/* 0xedd8 */ { false, 0xedd8, 0xedd8 }, +/* 0xedd9 */ { false, 0xedd9, 0xedd9 }, +/* 0xedda */ { false, 0xedda, 0xedda }, +/* 0xeddb */ { false, 0xeddb, 0xeddb }, +/* 0xeddc */ { false, 0xeddc, 0xeddc }, +/* 0xeddd */ { false, 0xeddd, 0xeddd }, +/* 0xedde */ { false, 0xedde, 0xedde }, +/* 0xeddf */ { false, 0xeddf, 0xeddf }, +/* 0xede0 */ { false, 0xede0, 0xede0 }, +/* 0xede1 */ { false, 0xede1, 0xede1 }, +/* 0xede2 */ { false, 0xede2, 0xede2 }, +/* 0xede3 */ { false, 0xede3, 0xede3 }, +/* 0xede4 */ { false, 0xede4, 0xede4 }, +/* 0xede5 */ { false, 0xede5, 0xede5 }, +/* 0xede6 */ { false, 0xede6, 0xede6 }, +/* 0xede7 */ { false, 0xede7, 0xede7 }, +/* 0xede8 */ { false, 0xede8, 0xede8 }, +/* 0xede9 */ { false, 0xede9, 0xede9 }, +/* 0xedea */ { false, 0xedea, 0xedea }, +/* 0xedeb */ { false, 0xedeb, 0xedeb }, +/* 0xedec */ { false, 0xedec, 0xedec }, +/* 0xeded */ { false, 0xeded, 0xeded }, +/* 0xedee */ { false, 0xedee, 0xedee }, +/* 0xedef */ { false, 0xedef, 0xedef }, +/* 0xedf0 */ { false, 0xedf0, 0xedf0 }, +/* 0xedf1 */ { false, 0xedf1, 0xedf1 }, +/* 0xedf2 */ { false, 0xedf2, 0xedf2 }, +/* 0xedf3 */ { false, 0xedf3, 0xedf3 }, +/* 0xedf4 */ { false, 0xedf4, 0xedf4 }, +/* 0xedf5 */ { false, 0xedf5, 0xedf5 }, +/* 0xedf6 */ { false, 0xedf6, 0xedf6 }, +/* 0xedf7 */ { false, 0xedf7, 0xedf7 }, +/* 0xedf8 */ { false, 0xedf8, 0xedf8 }, +/* 0xedf9 */ { false, 0xedf9, 0xedf9 }, +/* 0xedfa */ { false, 0xedfa, 0xedfa }, +/* 0xedfb */ { false, 0xedfb, 0xedfb }, +/* 0xedfc */ { false, 0xedfc, 0xedfc }, +/* 0xedfd */ { false, 0xedfd, 0xedfd }, +/* 0xedfe */ { false, 0xedfe, 0xedfe }, +/* 0xedff */ { false, 0xedff, 0xedff }, +/* 0xee00 */ { false, 0xee00, 0xee00 }, +/* 0xee01 */ { false, 0xee01, 0xee01 }, +/* 0xee02 */ { false, 0xee02, 0xee02 }, +/* 0xee03 */ { false, 0xee03, 0xee03 }, +/* 0xee04 */ { false, 0xee04, 0xee04 }, +/* 0xee05 */ { false, 0xee05, 0xee05 }, +/* 0xee06 */ { false, 0xee06, 0xee06 }, +/* 0xee07 */ { false, 0xee07, 0xee07 }, +/* 0xee08 */ { false, 0xee08, 0xee08 }, +/* 0xee09 */ { false, 0xee09, 0xee09 }, +/* 0xee0a */ { false, 0xee0a, 0xee0a }, +/* 0xee0b */ { false, 0xee0b, 0xee0b }, +/* 0xee0c */ { false, 0xee0c, 0xee0c }, +/* 0xee0d */ { false, 0xee0d, 0xee0d }, +/* 0xee0e */ { false, 0xee0e, 0xee0e }, +/* 0xee0f */ { false, 0xee0f, 0xee0f }, +/* 0xee10 */ { false, 0xee10, 0xee10 }, +/* 0xee11 */ { false, 0xee11, 0xee11 }, +/* 0xee12 */ { false, 0xee12, 0xee12 }, +/* 0xee13 */ { false, 0xee13, 0xee13 }, +/* 0xee14 */ { false, 0xee14, 0xee14 }, +/* 0xee15 */ { false, 0xee15, 0xee15 }, +/* 0xee16 */ { false, 0xee16, 0xee16 }, +/* 0xee17 */ { false, 0xee17, 0xee17 }, +/* 0xee18 */ { false, 0xee18, 0xee18 }, +/* 0xee19 */ { false, 0xee19, 0xee19 }, +/* 0xee1a */ { false, 0xee1a, 0xee1a }, +/* 0xee1b */ { false, 0xee1b, 0xee1b }, +/* 0xee1c */ { false, 0xee1c, 0xee1c }, +/* 0xee1d */ { false, 0xee1d, 0xee1d }, +/* 0xee1e */ { false, 0xee1e, 0xee1e }, +/* 0xee1f */ { false, 0xee1f, 0xee1f }, +/* 0xee20 */ { false, 0xee20, 0xee20 }, +/* 0xee21 */ { false, 0xee21, 0xee21 }, +/* 0xee22 */ { false, 0xee22, 0xee22 }, +/* 0xee23 */ { false, 0xee23, 0xee23 }, +/* 0xee24 */ { false, 0xee24, 0xee24 }, +/* 0xee25 */ { false, 0xee25, 0xee25 }, +/* 0xee26 */ { false, 0xee26, 0xee26 }, +/* 0xee27 */ { false, 0xee27, 0xee27 }, +/* 0xee28 */ { false, 0xee28, 0xee28 }, +/* 0xee29 */ { false, 0xee29, 0xee29 }, +/* 0xee2a */ { false, 0xee2a, 0xee2a }, +/* 0xee2b */ { false, 0xee2b, 0xee2b }, +/* 0xee2c */ { false, 0xee2c, 0xee2c }, +/* 0xee2d */ { false, 0xee2d, 0xee2d }, +/* 0xee2e */ { false, 0xee2e, 0xee2e }, +/* 0xee2f */ { false, 0xee2f, 0xee2f }, +/* 0xee30 */ { false, 0xee30, 0xee30 }, +/* 0xee31 */ { false, 0xee31, 0xee31 }, +/* 0xee32 */ { false, 0xee32, 0xee32 }, +/* 0xee33 */ { false, 0xee33, 0xee33 }, +/* 0xee34 */ { false, 0xee34, 0xee34 }, +/* 0xee35 */ { false, 0xee35, 0xee35 }, +/* 0xee36 */ { false, 0xee36, 0xee36 }, +/* 0xee37 */ { false, 0xee37, 0xee37 }, +/* 0xee38 */ { false, 0xee38, 0xee38 }, +/* 0xee39 */ { false, 0xee39, 0xee39 }, +/* 0xee3a */ { false, 0xee3a, 0xee3a }, +/* 0xee3b */ { false, 0xee3b, 0xee3b }, +/* 0xee3c */ { false, 0xee3c, 0xee3c }, +/* 0xee3d */ { false, 0xee3d, 0xee3d }, +/* 0xee3e */ { false, 0xee3e, 0xee3e }, +/* 0xee3f */ { false, 0xee3f, 0xee3f }, +/* 0xee40 */ { false, 0xee40, 0xee40 }, +/* 0xee41 */ { false, 0xee41, 0xee41 }, +/* 0xee42 */ { false, 0xee42, 0xee42 }, +/* 0xee43 */ { false, 0xee43, 0xee43 }, +/* 0xee44 */ { false, 0xee44, 0xee44 }, +/* 0xee45 */ { false, 0xee45, 0xee45 }, +/* 0xee46 */ { false, 0xee46, 0xee46 }, +/* 0xee47 */ { false, 0xee47, 0xee47 }, +/* 0xee48 */ { false, 0xee48, 0xee48 }, +/* 0xee49 */ { false, 0xee49, 0xee49 }, +/* 0xee4a */ { false, 0xee4a, 0xee4a }, +/* 0xee4b */ { false, 0xee4b, 0xee4b }, +/* 0xee4c */ { false, 0xee4c, 0xee4c }, +/* 0xee4d */ { false, 0xee4d, 0xee4d }, +/* 0xee4e */ { false, 0xee4e, 0xee4e }, +/* 0xee4f */ { false, 0xee4f, 0xee4f }, +/* 0xee50 */ { false, 0xee50, 0xee50 }, +/* 0xee51 */ { false, 0xee51, 0xee51 }, +/* 0xee52 */ { false, 0xee52, 0xee52 }, +/* 0xee53 */ { false, 0xee53, 0xee53 }, +/* 0xee54 */ { false, 0xee54, 0xee54 }, +/* 0xee55 */ { false, 0xee55, 0xee55 }, +/* 0xee56 */ { false, 0xee56, 0xee56 }, +/* 0xee57 */ { false, 0xee57, 0xee57 }, +/* 0xee58 */ { false, 0xee58, 0xee58 }, +/* 0xee59 */ { false, 0xee59, 0xee59 }, +/* 0xee5a */ { false, 0xee5a, 0xee5a }, +/* 0xee5b */ { false, 0xee5b, 0xee5b }, +/* 0xee5c */ { false, 0xee5c, 0xee5c }, +/* 0xee5d */ { false, 0xee5d, 0xee5d }, +/* 0xee5e */ { false, 0xee5e, 0xee5e }, +/* 0xee5f */ { false, 0xee5f, 0xee5f }, +/* 0xee60 */ { false, 0xee60, 0xee60 }, +/* 0xee61 */ { false, 0xee61, 0xee61 }, +/* 0xee62 */ { false, 0xee62, 0xee62 }, +/* 0xee63 */ { false, 0xee63, 0xee63 }, +/* 0xee64 */ { false, 0xee64, 0xee64 }, +/* 0xee65 */ { false, 0xee65, 0xee65 }, +/* 0xee66 */ { false, 0xee66, 0xee66 }, +/* 0xee67 */ { false, 0xee67, 0xee67 }, +/* 0xee68 */ { false, 0xee68, 0xee68 }, +/* 0xee69 */ { false, 0xee69, 0xee69 }, +/* 0xee6a */ { false, 0xee6a, 0xee6a }, +/* 0xee6b */ { false, 0xee6b, 0xee6b }, +/* 0xee6c */ { false, 0xee6c, 0xee6c }, +/* 0xee6d */ { false, 0xee6d, 0xee6d }, +/* 0xee6e */ { false, 0xee6e, 0xee6e }, +/* 0xee6f */ { false, 0xee6f, 0xee6f }, +/* 0xee70 */ { false, 0xee70, 0xee70 }, +/* 0xee71 */ { false, 0xee71, 0xee71 }, +/* 0xee72 */ { false, 0xee72, 0xee72 }, +/* 0xee73 */ { false, 0xee73, 0xee73 }, +/* 0xee74 */ { false, 0xee74, 0xee74 }, +/* 0xee75 */ { false, 0xee75, 0xee75 }, +/* 0xee76 */ { false, 0xee76, 0xee76 }, +/* 0xee77 */ { false, 0xee77, 0xee77 }, +/* 0xee78 */ { false, 0xee78, 0xee78 }, +/* 0xee79 */ { false, 0xee79, 0xee79 }, +/* 0xee7a */ { false, 0xee7a, 0xee7a }, +/* 0xee7b */ { false, 0xee7b, 0xee7b }, +/* 0xee7c */ { false, 0xee7c, 0xee7c }, +/* 0xee7d */ { false, 0xee7d, 0xee7d }, +/* 0xee7e */ { false, 0xee7e, 0xee7e }, +/* 0xee7f */ { false, 0xee7f, 0xee7f }, +/* 0xee80 */ { false, 0xee80, 0xee80 }, +/* 0xee81 */ { false, 0xee81, 0xee81 }, +/* 0xee82 */ { false, 0xee82, 0xee82 }, +/* 0xee83 */ { false, 0xee83, 0xee83 }, +/* 0xee84 */ { false, 0xee84, 0xee84 }, +/* 0xee85 */ { false, 0xee85, 0xee85 }, +/* 0xee86 */ { false, 0xee86, 0xee86 }, +/* 0xee87 */ { false, 0xee87, 0xee87 }, +/* 0xee88 */ { false, 0xee88, 0xee88 }, +/* 0xee89 */ { false, 0xee89, 0xee89 }, +/* 0xee8a */ { false, 0xee8a, 0xee8a }, +/* 0xee8b */ { false, 0xee8b, 0xee8b }, +/* 0xee8c */ { false, 0xee8c, 0xee8c }, +/* 0xee8d */ { false, 0xee8d, 0xee8d }, +/* 0xee8e */ { false, 0xee8e, 0xee8e }, +/* 0xee8f */ { false, 0xee8f, 0xee8f }, +/* 0xee90 */ { false, 0xee90, 0xee90 }, +/* 0xee91 */ { false, 0xee91, 0xee91 }, +/* 0xee92 */ { false, 0xee92, 0xee92 }, +/* 0xee93 */ { false, 0xee93, 0xee93 }, +/* 0xee94 */ { false, 0xee94, 0xee94 }, +/* 0xee95 */ { false, 0xee95, 0xee95 }, +/* 0xee96 */ { false, 0xee96, 0xee96 }, +/* 0xee97 */ { false, 0xee97, 0xee97 }, +/* 0xee98 */ { false, 0xee98, 0xee98 }, +/* 0xee99 */ { false, 0xee99, 0xee99 }, +/* 0xee9a */ { false, 0xee9a, 0xee9a }, +/* 0xee9b */ { false, 0xee9b, 0xee9b }, +/* 0xee9c */ { false, 0xee9c, 0xee9c }, +/* 0xee9d */ { false, 0xee9d, 0xee9d }, +/* 0xee9e */ { false, 0xee9e, 0xee9e }, +/* 0xee9f */ { false, 0xee9f, 0xee9f }, +/* 0xeea0 */ { false, 0xeea0, 0xeea0 }, +/* 0xeea1 */ { false, 0xeea1, 0xeea1 }, +/* 0xeea2 */ { false, 0xeea2, 0xeea2 }, +/* 0xeea3 */ { false, 0xeea3, 0xeea3 }, +/* 0xeea4 */ { false, 0xeea4, 0xeea4 }, +/* 0xeea5 */ { false, 0xeea5, 0xeea5 }, +/* 0xeea6 */ { false, 0xeea6, 0xeea6 }, +/* 0xeea7 */ { false, 0xeea7, 0xeea7 }, +/* 0xeea8 */ { false, 0xeea8, 0xeea8 }, +/* 0xeea9 */ { false, 0xeea9, 0xeea9 }, +/* 0xeeaa */ { false, 0xeeaa, 0xeeaa }, +/* 0xeeab */ { false, 0xeeab, 0xeeab }, +/* 0xeeac */ { false, 0xeeac, 0xeeac }, +/* 0xeead */ { false, 0xeead, 0xeead }, +/* 0xeeae */ { false, 0xeeae, 0xeeae }, +/* 0xeeaf */ { false, 0xeeaf, 0xeeaf }, +/* 0xeeb0 */ { false, 0xeeb0, 0xeeb0 }, +/* 0xeeb1 */ { false, 0xeeb1, 0xeeb1 }, +/* 0xeeb2 */ { false, 0xeeb2, 0xeeb2 }, +/* 0xeeb3 */ { false, 0xeeb3, 0xeeb3 }, +/* 0xeeb4 */ { false, 0xeeb4, 0xeeb4 }, +/* 0xeeb5 */ { false, 0xeeb5, 0xeeb5 }, +/* 0xeeb6 */ { false, 0xeeb6, 0xeeb6 }, +/* 0xeeb7 */ { false, 0xeeb7, 0xeeb7 }, +/* 0xeeb8 */ { false, 0xeeb8, 0xeeb8 }, +/* 0xeeb9 */ { false, 0xeeb9, 0xeeb9 }, +/* 0xeeba */ { false, 0xeeba, 0xeeba }, +/* 0xeebb */ { false, 0xeebb, 0xeebb }, +/* 0xeebc */ { false, 0xeebc, 0xeebc }, +/* 0xeebd */ { false, 0xeebd, 0xeebd }, +/* 0xeebe */ { false, 0xeebe, 0xeebe }, +/* 0xeebf */ { false, 0xeebf, 0xeebf }, +/* 0xeec0 */ { false, 0xeec0, 0xeec0 }, +/* 0xeec1 */ { false, 0xeec1, 0xeec1 }, +/* 0xeec2 */ { false, 0xeec2, 0xeec2 }, +/* 0xeec3 */ { false, 0xeec3, 0xeec3 }, +/* 0xeec4 */ { false, 0xeec4, 0xeec4 }, +/* 0xeec5 */ { false, 0xeec5, 0xeec5 }, +/* 0xeec6 */ { false, 0xeec6, 0xeec6 }, +/* 0xeec7 */ { false, 0xeec7, 0xeec7 }, +/* 0xeec8 */ { false, 0xeec8, 0xeec8 }, +/* 0xeec9 */ { false, 0xeec9, 0xeec9 }, +/* 0xeeca */ { false, 0xeeca, 0xeeca }, +/* 0xeecb */ { false, 0xeecb, 0xeecb }, +/* 0xeecc */ { false, 0xeecc, 0xeecc }, +/* 0xeecd */ { false, 0xeecd, 0xeecd }, +/* 0xeece */ { false, 0xeece, 0xeece }, +/* 0xeecf */ { false, 0xeecf, 0xeecf }, +/* 0xeed0 */ { false, 0xeed0, 0xeed0 }, +/* 0xeed1 */ { false, 0xeed1, 0xeed1 }, +/* 0xeed2 */ { false, 0xeed2, 0xeed2 }, +/* 0xeed3 */ { false, 0xeed3, 0xeed3 }, +/* 0xeed4 */ { false, 0xeed4, 0xeed4 }, +/* 0xeed5 */ { false, 0xeed5, 0xeed5 }, +/* 0xeed6 */ { false, 0xeed6, 0xeed6 }, +/* 0xeed7 */ { false, 0xeed7, 0xeed7 }, +/* 0xeed8 */ { false, 0xeed8, 0xeed8 }, +/* 0xeed9 */ { false, 0xeed9, 0xeed9 }, +/* 0xeeda */ { false, 0xeeda, 0xeeda }, +/* 0xeedb */ { false, 0xeedb, 0xeedb }, +/* 0xeedc */ { false, 0xeedc, 0xeedc }, +/* 0xeedd */ { false, 0xeedd, 0xeedd }, +/* 0xeede */ { false, 0xeede, 0xeede }, +/* 0xeedf */ { false, 0xeedf, 0xeedf }, +/* 0xeee0 */ { false, 0xeee0, 0xeee0 }, +/* 0xeee1 */ { false, 0xeee1, 0xeee1 }, +/* 0xeee2 */ { false, 0xeee2, 0xeee2 }, +/* 0xeee3 */ { false, 0xeee3, 0xeee3 }, +/* 0xeee4 */ { false, 0xeee4, 0xeee4 }, +/* 0xeee5 */ { false, 0xeee5, 0xeee5 }, +/* 0xeee6 */ { false, 0xeee6, 0xeee6 }, +/* 0xeee7 */ { false, 0xeee7, 0xeee7 }, +/* 0xeee8 */ { false, 0xeee8, 0xeee8 }, +/* 0xeee9 */ { false, 0xeee9, 0xeee9 }, +/* 0xeeea */ { false, 0xeeea, 0xeeea }, +/* 0xeeeb */ { false, 0xeeeb, 0xeeeb }, +/* 0xeeec */ { false, 0xeeec, 0xeeec }, +/* 0xeeed */ { false, 0xeeed, 0xeeed }, +/* 0xeeee */ { false, 0xeeee, 0xeeee }, +/* 0xeeef */ { false, 0xeeef, 0xeeef }, +/* 0xeef0 */ { false, 0xeef0, 0xeef0 }, +/* 0xeef1 */ { false, 0xeef1, 0xeef1 }, +/* 0xeef2 */ { false, 0xeef2, 0xeef2 }, +/* 0xeef3 */ { false, 0xeef3, 0xeef3 }, +/* 0xeef4 */ { false, 0xeef4, 0xeef4 }, +/* 0xeef5 */ { false, 0xeef5, 0xeef5 }, +/* 0xeef6 */ { false, 0xeef6, 0xeef6 }, +/* 0xeef7 */ { false, 0xeef7, 0xeef7 }, +/* 0xeef8 */ { false, 0xeef8, 0xeef8 }, +/* 0xeef9 */ { false, 0xeef9, 0xeef9 }, +/* 0xeefa */ { false, 0xeefa, 0xeefa }, +/* 0xeefb */ { false, 0xeefb, 0xeefb }, +/* 0xeefc */ { false, 0xeefc, 0xeefc }, +/* 0xeefd */ { false, 0xeefd, 0xeefd }, +/* 0xeefe */ { false, 0xeefe, 0xeefe }, +/* 0xeeff */ { false, 0xeeff, 0xeeff }, +/* 0xef00 */ { false, 0xef00, 0xef00 }, +/* 0xef01 */ { false, 0xef01, 0xef01 }, +/* 0xef02 */ { false, 0xef02, 0xef02 }, +/* 0xef03 */ { false, 0xef03, 0xef03 }, +/* 0xef04 */ { false, 0xef04, 0xef04 }, +/* 0xef05 */ { false, 0xef05, 0xef05 }, +/* 0xef06 */ { false, 0xef06, 0xef06 }, +/* 0xef07 */ { false, 0xef07, 0xef07 }, +/* 0xef08 */ { false, 0xef08, 0xef08 }, +/* 0xef09 */ { false, 0xef09, 0xef09 }, +/* 0xef0a */ { false, 0xef0a, 0xef0a }, +/* 0xef0b */ { false, 0xef0b, 0xef0b }, +/* 0xef0c */ { false, 0xef0c, 0xef0c }, +/* 0xef0d */ { false, 0xef0d, 0xef0d }, +/* 0xef0e */ { false, 0xef0e, 0xef0e }, +/* 0xef0f */ { false, 0xef0f, 0xef0f }, +/* 0xef10 */ { false, 0xef10, 0xef10 }, +/* 0xef11 */ { false, 0xef11, 0xef11 }, +/* 0xef12 */ { false, 0xef12, 0xef12 }, +/* 0xef13 */ { false, 0xef13, 0xef13 }, +/* 0xef14 */ { false, 0xef14, 0xef14 }, +/* 0xef15 */ { false, 0xef15, 0xef15 }, +/* 0xef16 */ { false, 0xef16, 0xef16 }, +/* 0xef17 */ { false, 0xef17, 0xef17 }, +/* 0xef18 */ { false, 0xef18, 0xef18 }, +/* 0xef19 */ { false, 0xef19, 0xef19 }, +/* 0xef1a */ { false, 0xef1a, 0xef1a }, +/* 0xef1b */ { false, 0xef1b, 0xef1b }, +/* 0xef1c */ { false, 0xef1c, 0xef1c }, +/* 0xef1d */ { false, 0xef1d, 0xef1d }, +/* 0xef1e */ { false, 0xef1e, 0xef1e }, +/* 0xef1f */ { false, 0xef1f, 0xef1f }, +/* 0xef20 */ { false, 0xef20, 0xef20 }, +/* 0xef21 */ { false, 0xef21, 0xef21 }, +/* 0xef22 */ { false, 0xef22, 0xef22 }, +/* 0xef23 */ { false, 0xef23, 0xef23 }, +/* 0xef24 */ { false, 0xef24, 0xef24 }, +/* 0xef25 */ { false, 0xef25, 0xef25 }, +/* 0xef26 */ { false, 0xef26, 0xef26 }, +/* 0xef27 */ { false, 0xef27, 0xef27 }, +/* 0xef28 */ { false, 0xef28, 0xef28 }, +/* 0xef29 */ { false, 0xef29, 0xef29 }, +/* 0xef2a */ { false, 0xef2a, 0xef2a }, +/* 0xef2b */ { false, 0xef2b, 0xef2b }, +/* 0xef2c */ { false, 0xef2c, 0xef2c }, +/* 0xef2d */ { false, 0xef2d, 0xef2d }, +/* 0xef2e */ { false, 0xef2e, 0xef2e }, +/* 0xef2f */ { false, 0xef2f, 0xef2f }, +/* 0xef30 */ { false, 0xef30, 0xef30 }, +/* 0xef31 */ { false, 0xef31, 0xef31 }, +/* 0xef32 */ { false, 0xef32, 0xef32 }, +/* 0xef33 */ { false, 0xef33, 0xef33 }, +/* 0xef34 */ { false, 0xef34, 0xef34 }, +/* 0xef35 */ { false, 0xef35, 0xef35 }, +/* 0xef36 */ { false, 0xef36, 0xef36 }, +/* 0xef37 */ { false, 0xef37, 0xef37 }, +/* 0xef38 */ { false, 0xef38, 0xef38 }, +/* 0xef39 */ { false, 0xef39, 0xef39 }, +/* 0xef3a */ { false, 0xef3a, 0xef3a }, +/* 0xef3b */ { false, 0xef3b, 0xef3b }, +/* 0xef3c */ { false, 0xef3c, 0xef3c }, +/* 0xef3d */ { false, 0xef3d, 0xef3d }, +/* 0xef3e */ { false, 0xef3e, 0xef3e }, +/* 0xef3f */ { false, 0xef3f, 0xef3f }, +/* 0xef40 */ { false, 0xef40, 0xef40 }, +/* 0xef41 */ { false, 0xef41, 0xef41 }, +/* 0xef42 */ { false, 0xef42, 0xef42 }, +/* 0xef43 */ { false, 0xef43, 0xef43 }, +/* 0xef44 */ { false, 0xef44, 0xef44 }, +/* 0xef45 */ { false, 0xef45, 0xef45 }, +/* 0xef46 */ { false, 0xef46, 0xef46 }, +/* 0xef47 */ { false, 0xef47, 0xef47 }, +/* 0xef48 */ { false, 0xef48, 0xef48 }, +/* 0xef49 */ { false, 0xef49, 0xef49 }, +/* 0xef4a */ { false, 0xef4a, 0xef4a }, +/* 0xef4b */ { false, 0xef4b, 0xef4b }, +/* 0xef4c */ { false, 0xef4c, 0xef4c }, +/* 0xef4d */ { false, 0xef4d, 0xef4d }, +/* 0xef4e */ { false, 0xef4e, 0xef4e }, +/* 0xef4f */ { false, 0xef4f, 0xef4f }, +/* 0xef50 */ { false, 0xef50, 0xef50 }, +/* 0xef51 */ { false, 0xef51, 0xef51 }, +/* 0xef52 */ { false, 0xef52, 0xef52 }, +/* 0xef53 */ { false, 0xef53, 0xef53 }, +/* 0xef54 */ { false, 0xef54, 0xef54 }, +/* 0xef55 */ { false, 0xef55, 0xef55 }, +/* 0xef56 */ { false, 0xef56, 0xef56 }, +/* 0xef57 */ { false, 0xef57, 0xef57 }, +/* 0xef58 */ { false, 0xef58, 0xef58 }, +/* 0xef59 */ { false, 0xef59, 0xef59 }, +/* 0xef5a */ { false, 0xef5a, 0xef5a }, +/* 0xef5b */ { false, 0xef5b, 0xef5b }, +/* 0xef5c */ { false, 0xef5c, 0xef5c }, +/* 0xef5d */ { false, 0xef5d, 0xef5d }, +/* 0xef5e */ { false, 0xef5e, 0xef5e }, +/* 0xef5f */ { false, 0xef5f, 0xef5f }, +/* 0xef60 */ { false, 0xef60, 0xef60 }, +/* 0xef61 */ { false, 0xef61, 0xef61 }, +/* 0xef62 */ { false, 0xef62, 0xef62 }, +/* 0xef63 */ { false, 0xef63, 0xef63 }, +/* 0xef64 */ { false, 0xef64, 0xef64 }, +/* 0xef65 */ { false, 0xef65, 0xef65 }, +/* 0xef66 */ { false, 0xef66, 0xef66 }, +/* 0xef67 */ { false, 0xef67, 0xef67 }, +/* 0xef68 */ { false, 0xef68, 0xef68 }, +/* 0xef69 */ { false, 0xef69, 0xef69 }, +/* 0xef6a */ { false, 0xef6a, 0xef6a }, +/* 0xef6b */ { false, 0xef6b, 0xef6b }, +/* 0xef6c */ { false, 0xef6c, 0xef6c }, +/* 0xef6d */ { false, 0xef6d, 0xef6d }, +/* 0xef6e */ { false, 0xef6e, 0xef6e }, +/* 0xef6f */ { false, 0xef6f, 0xef6f }, +/* 0xef70 */ { false, 0xef70, 0xef70 }, +/* 0xef71 */ { false, 0xef71, 0xef71 }, +/* 0xef72 */ { false, 0xef72, 0xef72 }, +/* 0xef73 */ { false, 0xef73, 0xef73 }, +/* 0xef74 */ { false, 0xef74, 0xef74 }, +/* 0xef75 */ { false, 0xef75, 0xef75 }, +/* 0xef76 */ { false, 0xef76, 0xef76 }, +/* 0xef77 */ { false, 0xef77, 0xef77 }, +/* 0xef78 */ { false, 0xef78, 0xef78 }, +/* 0xef79 */ { false, 0xef79, 0xef79 }, +/* 0xef7a */ { false, 0xef7a, 0xef7a }, +/* 0xef7b */ { false, 0xef7b, 0xef7b }, +/* 0xef7c */ { false, 0xef7c, 0xef7c }, +/* 0xef7d */ { false, 0xef7d, 0xef7d }, +/* 0xef7e */ { false, 0xef7e, 0xef7e }, +/* 0xef7f */ { false, 0xef7f, 0xef7f }, +/* 0xef80 */ { false, 0xef80, 0xef80 }, +/* 0xef81 */ { false, 0xef81, 0xef81 }, +/* 0xef82 */ { false, 0xef82, 0xef82 }, +/* 0xef83 */ { false, 0xef83, 0xef83 }, +/* 0xef84 */ { false, 0xef84, 0xef84 }, +/* 0xef85 */ { false, 0xef85, 0xef85 }, +/* 0xef86 */ { false, 0xef86, 0xef86 }, +/* 0xef87 */ { false, 0xef87, 0xef87 }, +/* 0xef88 */ { false, 0xef88, 0xef88 }, +/* 0xef89 */ { false, 0xef89, 0xef89 }, +/* 0xef8a */ { false, 0xef8a, 0xef8a }, +/* 0xef8b */ { false, 0xef8b, 0xef8b }, +/* 0xef8c */ { false, 0xef8c, 0xef8c }, +/* 0xef8d */ { false, 0xef8d, 0xef8d }, +/* 0xef8e */ { false, 0xef8e, 0xef8e }, +/* 0xef8f */ { false, 0xef8f, 0xef8f }, +/* 0xef90 */ { false, 0xef90, 0xef90 }, +/* 0xef91 */ { false, 0xef91, 0xef91 }, +/* 0xef92 */ { false, 0xef92, 0xef92 }, +/* 0xef93 */ { false, 0xef93, 0xef93 }, +/* 0xef94 */ { false, 0xef94, 0xef94 }, +/* 0xef95 */ { false, 0xef95, 0xef95 }, +/* 0xef96 */ { false, 0xef96, 0xef96 }, +/* 0xef97 */ { false, 0xef97, 0xef97 }, +/* 0xef98 */ { false, 0xef98, 0xef98 }, +/* 0xef99 */ { false, 0xef99, 0xef99 }, +/* 0xef9a */ { false, 0xef9a, 0xef9a }, +/* 0xef9b */ { false, 0xef9b, 0xef9b }, +/* 0xef9c */ { false, 0xef9c, 0xef9c }, +/* 0xef9d */ { false, 0xef9d, 0xef9d }, +/* 0xef9e */ { false, 0xef9e, 0xef9e }, +/* 0xef9f */ { false, 0xef9f, 0xef9f }, +/* 0xefa0 */ { false, 0xefa0, 0xefa0 }, +/* 0xefa1 */ { false, 0xefa1, 0xefa1 }, +/* 0xefa2 */ { false, 0xefa2, 0xefa2 }, +/* 0xefa3 */ { false, 0xefa3, 0xefa3 }, +/* 0xefa4 */ { false, 0xefa4, 0xefa4 }, +/* 0xefa5 */ { false, 0xefa5, 0xefa5 }, +/* 0xefa6 */ { false, 0xefa6, 0xefa6 }, +/* 0xefa7 */ { false, 0xefa7, 0xefa7 }, +/* 0xefa8 */ { false, 0xefa8, 0xefa8 }, +/* 0xefa9 */ { false, 0xefa9, 0xefa9 }, +/* 0xefaa */ { false, 0xefaa, 0xefaa }, +/* 0xefab */ { false, 0xefab, 0xefab }, +/* 0xefac */ { false, 0xefac, 0xefac }, +/* 0xefad */ { false, 0xefad, 0xefad }, +/* 0xefae */ { false, 0xefae, 0xefae }, +/* 0xefaf */ { false, 0xefaf, 0xefaf }, +/* 0xefb0 */ { false, 0xefb0, 0xefb0 }, +/* 0xefb1 */ { false, 0xefb1, 0xefb1 }, +/* 0xefb2 */ { false, 0xefb2, 0xefb2 }, +/* 0xefb3 */ { false, 0xefb3, 0xefb3 }, +/* 0xefb4 */ { false, 0xefb4, 0xefb4 }, +/* 0xefb5 */ { false, 0xefb5, 0xefb5 }, +/* 0xefb6 */ { false, 0xefb6, 0xefb6 }, +/* 0xefb7 */ { false, 0xefb7, 0xefb7 }, +/* 0xefb8 */ { false, 0xefb8, 0xefb8 }, +/* 0xefb9 */ { false, 0xefb9, 0xefb9 }, +/* 0xefba */ { false, 0xefba, 0xefba }, +/* 0xefbb */ { false, 0xefbb, 0xefbb }, +/* 0xefbc */ { false, 0xefbc, 0xefbc }, +/* 0xefbd */ { false, 0xefbd, 0xefbd }, +/* 0xefbe */ { false, 0xefbe, 0xefbe }, +/* 0xefbf */ { false, 0xefbf, 0xefbf }, +/* 0xefc0 */ { false, 0xefc0, 0xefc0 }, +/* 0xefc1 */ { false, 0xefc1, 0xefc1 }, +/* 0xefc2 */ { false, 0xefc2, 0xefc2 }, +/* 0xefc3 */ { false, 0xefc3, 0xefc3 }, +/* 0xefc4 */ { false, 0xefc4, 0xefc4 }, +/* 0xefc5 */ { false, 0xefc5, 0xefc5 }, +/* 0xefc6 */ { false, 0xefc6, 0xefc6 }, +/* 0xefc7 */ { false, 0xefc7, 0xefc7 }, +/* 0xefc8 */ { false, 0xefc8, 0xefc8 }, +/* 0xefc9 */ { false, 0xefc9, 0xefc9 }, +/* 0xefca */ { false, 0xefca, 0xefca }, +/* 0xefcb */ { false, 0xefcb, 0xefcb }, +/* 0xefcc */ { false, 0xefcc, 0xefcc }, +/* 0xefcd */ { false, 0xefcd, 0xefcd }, +/* 0xefce */ { false, 0xefce, 0xefce }, +/* 0xefcf */ { false, 0xefcf, 0xefcf }, +/* 0xefd0 */ { false, 0xefd0, 0xefd0 }, +/* 0xefd1 */ { false, 0xefd1, 0xefd1 }, +/* 0xefd2 */ { false, 0xefd2, 0xefd2 }, +/* 0xefd3 */ { false, 0xefd3, 0xefd3 }, +/* 0xefd4 */ { false, 0xefd4, 0xefd4 }, +/* 0xefd5 */ { false, 0xefd5, 0xefd5 }, +/* 0xefd6 */ { false, 0xefd6, 0xefd6 }, +/* 0xefd7 */ { false, 0xefd7, 0xefd7 }, +/* 0xefd8 */ { false, 0xefd8, 0xefd8 }, +/* 0xefd9 */ { false, 0xefd9, 0xefd9 }, +/* 0xefda */ { false, 0xefda, 0xefda }, +/* 0xefdb */ { false, 0xefdb, 0xefdb }, +/* 0xefdc */ { false, 0xefdc, 0xefdc }, +/* 0xefdd */ { false, 0xefdd, 0xefdd }, +/* 0xefde */ { false, 0xefde, 0xefde }, +/* 0xefdf */ { false, 0xefdf, 0xefdf }, +/* 0xefe0 */ { false, 0xefe0, 0xefe0 }, +/* 0xefe1 */ { false, 0xefe1, 0xefe1 }, +/* 0xefe2 */ { false, 0xefe2, 0xefe2 }, +/* 0xefe3 */ { false, 0xefe3, 0xefe3 }, +/* 0xefe4 */ { false, 0xefe4, 0xefe4 }, +/* 0xefe5 */ { false, 0xefe5, 0xefe5 }, +/* 0xefe6 */ { false, 0xefe6, 0xefe6 }, +/* 0xefe7 */ { false, 0xefe7, 0xefe7 }, +/* 0xefe8 */ { false, 0xefe8, 0xefe8 }, +/* 0xefe9 */ { false, 0xefe9, 0xefe9 }, +/* 0xefea */ { false, 0xefea, 0xefea }, +/* 0xefeb */ { false, 0xefeb, 0xefeb }, +/* 0xefec */ { false, 0xefec, 0xefec }, +/* 0xefed */ { false, 0xefed, 0xefed }, +/* 0xefee */ { false, 0xefee, 0xefee }, +/* 0xefef */ { false, 0xefef, 0xefef }, +/* 0xeff0 */ { false, 0xeff0, 0xeff0 }, +/* 0xeff1 */ { false, 0xeff1, 0xeff1 }, +/* 0xeff2 */ { false, 0xeff2, 0xeff2 }, +/* 0xeff3 */ { false, 0xeff3, 0xeff3 }, +/* 0xeff4 */ { false, 0xeff4, 0xeff4 }, +/* 0xeff5 */ { false, 0xeff5, 0xeff5 }, +/* 0xeff6 */ { false, 0xeff6, 0xeff6 }, +/* 0xeff7 */ { false, 0xeff7, 0xeff7 }, +/* 0xeff8 */ { false, 0xeff8, 0xeff8 }, +/* 0xeff9 */ { false, 0xeff9, 0xeff9 }, +/* 0xeffa */ { false, 0xeffa, 0xeffa }, +/* 0xeffb */ { false, 0xeffb, 0xeffb }, +/* 0xeffc */ { false, 0xeffc, 0xeffc }, +/* 0xeffd */ { false, 0xeffd, 0xeffd }, +/* 0xeffe */ { false, 0xeffe, 0xeffe }, +/* 0xefff */ { false, 0xefff, 0xefff }, +/* 0xf000 */ { false, 0xf000, 0xf000 }, +/* 0xf001 */ { false, 0xf001, 0xf001 }, +/* 0xf002 */ { false, 0xf002, 0xf002 }, +/* 0xf003 */ { false, 0xf003, 0xf003 }, +/* 0xf004 */ { false, 0xf004, 0xf004 }, +/* 0xf005 */ { false, 0xf005, 0xf005 }, +/* 0xf006 */ { false, 0xf006, 0xf006 }, +/* 0xf007 */ { false, 0xf007, 0xf007 }, +/* 0xf008 */ { false, 0xf008, 0xf008 }, +/* 0xf009 */ { false, 0xf009, 0xf009 }, +/* 0xf00a */ { false, 0xf00a, 0xf00a }, +/* 0xf00b */ { false, 0xf00b, 0xf00b }, +/* 0xf00c */ { false, 0xf00c, 0xf00c }, +/* 0xf00d */ { false, 0xf00d, 0xf00d }, +/* 0xf00e */ { false, 0xf00e, 0xf00e }, +/* 0xf00f */ { false, 0xf00f, 0xf00f }, +/* 0xf010 */ { false, 0xf010, 0xf010 }, +/* 0xf011 */ { false, 0xf011, 0xf011 }, +/* 0xf012 */ { false, 0xf012, 0xf012 }, +/* 0xf013 */ { false, 0xf013, 0xf013 }, +/* 0xf014 */ { false, 0xf014, 0xf014 }, +/* 0xf015 */ { false, 0xf015, 0xf015 }, +/* 0xf016 */ { false, 0xf016, 0xf016 }, +/* 0xf017 */ { false, 0xf017, 0xf017 }, +/* 0xf018 */ { false, 0xf018, 0xf018 }, +/* 0xf019 */ { false, 0xf019, 0xf019 }, +/* 0xf01a */ { false, 0xf01a, 0xf01a }, +/* 0xf01b */ { false, 0xf01b, 0xf01b }, +/* 0xf01c */ { false, 0xf01c, 0xf01c }, +/* 0xf01d */ { false, 0xf01d, 0xf01d }, +/* 0xf01e */ { false, 0xf01e, 0xf01e }, +/* 0xf01f */ { false, 0xf01f, 0xf01f }, +/* 0xf020 */ { false, 0xf020, 0xf020 }, +/* 0xf021 */ { false, 0xf021, 0xf021 }, +/* 0xf022 */ { false, 0xf022, 0xf022 }, +/* 0xf023 */ { false, 0xf023, 0xf023 }, +/* 0xf024 */ { false, 0xf024, 0xf024 }, +/* 0xf025 */ { false, 0xf025, 0xf025 }, +/* 0xf026 */ { false, 0xf026, 0xf026 }, +/* 0xf027 */ { false, 0xf027, 0xf027 }, +/* 0xf028 */ { false, 0xf028, 0xf028 }, +/* 0xf029 */ { false, 0xf029, 0xf029 }, +/* 0xf02a */ { false, 0xf02a, 0xf02a }, +/* 0xf02b */ { false, 0xf02b, 0xf02b }, +/* 0xf02c */ { false, 0xf02c, 0xf02c }, +/* 0xf02d */ { false, 0xf02d, 0xf02d }, +/* 0xf02e */ { false, 0xf02e, 0xf02e }, +/* 0xf02f */ { false, 0xf02f, 0xf02f }, +/* 0xf030 */ { false, 0xf030, 0xf030 }, +/* 0xf031 */ { false, 0xf031, 0xf031 }, +/* 0xf032 */ { false, 0xf032, 0xf032 }, +/* 0xf033 */ { false, 0xf033, 0xf033 }, +/* 0xf034 */ { false, 0xf034, 0xf034 }, +/* 0xf035 */ { false, 0xf035, 0xf035 }, +/* 0xf036 */ { false, 0xf036, 0xf036 }, +/* 0xf037 */ { false, 0xf037, 0xf037 }, +/* 0xf038 */ { false, 0xf038, 0xf038 }, +/* 0xf039 */ { false, 0xf039, 0xf039 }, +/* 0xf03a */ { false, 0xf03a, 0xf03a }, +/* 0xf03b */ { false, 0xf03b, 0xf03b }, +/* 0xf03c */ { false, 0xf03c, 0xf03c }, +/* 0xf03d */ { false, 0xf03d, 0xf03d }, +/* 0xf03e */ { false, 0xf03e, 0xf03e }, +/* 0xf03f */ { false, 0xf03f, 0xf03f }, +/* 0xf040 */ { false, 0xf040, 0xf040 }, +/* 0xf041 */ { false, 0xf041, 0xf041 }, +/* 0xf042 */ { false, 0xf042, 0xf042 }, +/* 0xf043 */ { false, 0xf043, 0xf043 }, +/* 0xf044 */ { false, 0xf044, 0xf044 }, +/* 0xf045 */ { false, 0xf045, 0xf045 }, +/* 0xf046 */ { false, 0xf046, 0xf046 }, +/* 0xf047 */ { false, 0xf047, 0xf047 }, +/* 0xf048 */ { false, 0xf048, 0xf048 }, +/* 0xf049 */ { false, 0xf049, 0xf049 }, +/* 0xf04a */ { false, 0xf04a, 0xf04a }, +/* 0xf04b */ { false, 0xf04b, 0xf04b }, +/* 0xf04c */ { false, 0xf04c, 0xf04c }, +/* 0xf04d */ { false, 0xf04d, 0xf04d }, +/* 0xf04e */ { false, 0xf04e, 0xf04e }, +/* 0xf04f */ { false, 0xf04f, 0xf04f }, +/* 0xf050 */ { false, 0xf050, 0xf050 }, +/* 0xf051 */ { false, 0xf051, 0xf051 }, +/* 0xf052 */ { false, 0xf052, 0xf052 }, +/* 0xf053 */ { false, 0xf053, 0xf053 }, +/* 0xf054 */ { false, 0xf054, 0xf054 }, +/* 0xf055 */ { false, 0xf055, 0xf055 }, +/* 0xf056 */ { false, 0xf056, 0xf056 }, +/* 0xf057 */ { false, 0xf057, 0xf057 }, +/* 0xf058 */ { false, 0xf058, 0xf058 }, +/* 0xf059 */ { false, 0xf059, 0xf059 }, +/* 0xf05a */ { false, 0xf05a, 0xf05a }, +/* 0xf05b */ { false, 0xf05b, 0xf05b }, +/* 0xf05c */ { false, 0xf05c, 0xf05c }, +/* 0xf05d */ { false, 0xf05d, 0xf05d }, +/* 0xf05e */ { false, 0xf05e, 0xf05e }, +/* 0xf05f */ { false, 0xf05f, 0xf05f }, +/* 0xf060 */ { false, 0xf060, 0xf060 }, +/* 0xf061 */ { false, 0xf061, 0xf061 }, +/* 0xf062 */ { false, 0xf062, 0xf062 }, +/* 0xf063 */ { false, 0xf063, 0xf063 }, +/* 0xf064 */ { false, 0xf064, 0xf064 }, +/* 0xf065 */ { false, 0xf065, 0xf065 }, +/* 0xf066 */ { false, 0xf066, 0xf066 }, +/* 0xf067 */ { false, 0xf067, 0xf067 }, +/* 0xf068 */ { false, 0xf068, 0xf068 }, +/* 0xf069 */ { false, 0xf069, 0xf069 }, +/* 0xf06a */ { false, 0xf06a, 0xf06a }, +/* 0xf06b */ { false, 0xf06b, 0xf06b }, +/* 0xf06c */ { false, 0xf06c, 0xf06c }, +/* 0xf06d */ { false, 0xf06d, 0xf06d }, +/* 0xf06e */ { false, 0xf06e, 0xf06e }, +/* 0xf06f */ { false, 0xf06f, 0xf06f }, +/* 0xf070 */ { false, 0xf070, 0xf070 }, +/* 0xf071 */ { false, 0xf071, 0xf071 }, +/* 0xf072 */ { false, 0xf072, 0xf072 }, +/* 0xf073 */ { false, 0xf073, 0xf073 }, +/* 0xf074 */ { false, 0xf074, 0xf074 }, +/* 0xf075 */ { false, 0xf075, 0xf075 }, +/* 0xf076 */ { false, 0xf076, 0xf076 }, +/* 0xf077 */ { false, 0xf077, 0xf077 }, +/* 0xf078 */ { false, 0xf078, 0xf078 }, +/* 0xf079 */ { false, 0xf079, 0xf079 }, +/* 0xf07a */ { false, 0xf07a, 0xf07a }, +/* 0xf07b */ { false, 0xf07b, 0xf07b }, +/* 0xf07c */ { false, 0xf07c, 0xf07c }, +/* 0xf07d */ { false, 0xf07d, 0xf07d }, +/* 0xf07e */ { false, 0xf07e, 0xf07e }, +/* 0xf07f */ { false, 0xf07f, 0xf07f }, +/* 0xf080 */ { false, 0xf080, 0xf080 }, +/* 0xf081 */ { false, 0xf081, 0xf081 }, +/* 0xf082 */ { false, 0xf082, 0xf082 }, +/* 0xf083 */ { false, 0xf083, 0xf083 }, +/* 0xf084 */ { false, 0xf084, 0xf084 }, +/* 0xf085 */ { false, 0xf085, 0xf085 }, +/* 0xf086 */ { false, 0xf086, 0xf086 }, +/* 0xf087 */ { false, 0xf087, 0xf087 }, +/* 0xf088 */ { false, 0xf088, 0xf088 }, +/* 0xf089 */ { false, 0xf089, 0xf089 }, +/* 0xf08a */ { false, 0xf08a, 0xf08a }, +/* 0xf08b */ { false, 0xf08b, 0xf08b }, +/* 0xf08c */ { false, 0xf08c, 0xf08c }, +/* 0xf08d */ { false, 0xf08d, 0xf08d }, +/* 0xf08e */ { false, 0xf08e, 0xf08e }, +/* 0xf08f */ { false, 0xf08f, 0xf08f }, +/* 0xf090 */ { false, 0xf090, 0xf090 }, +/* 0xf091 */ { false, 0xf091, 0xf091 }, +/* 0xf092 */ { false, 0xf092, 0xf092 }, +/* 0xf093 */ { false, 0xf093, 0xf093 }, +/* 0xf094 */ { false, 0xf094, 0xf094 }, +/* 0xf095 */ { false, 0xf095, 0xf095 }, +/* 0xf096 */ { false, 0xf096, 0xf096 }, +/* 0xf097 */ { false, 0xf097, 0xf097 }, +/* 0xf098 */ { false, 0xf098, 0xf098 }, +/* 0xf099 */ { false, 0xf099, 0xf099 }, +/* 0xf09a */ { false, 0xf09a, 0xf09a }, +/* 0xf09b */ { false, 0xf09b, 0xf09b }, +/* 0xf09c */ { false, 0xf09c, 0xf09c }, +/* 0xf09d */ { false, 0xf09d, 0xf09d }, +/* 0xf09e */ { false, 0xf09e, 0xf09e }, +/* 0xf09f */ { false, 0xf09f, 0xf09f }, +/* 0xf0a0 */ { false, 0xf0a0, 0xf0a0 }, +/* 0xf0a1 */ { false, 0xf0a1, 0xf0a1 }, +/* 0xf0a2 */ { false, 0xf0a2, 0xf0a2 }, +/* 0xf0a3 */ { false, 0xf0a3, 0xf0a3 }, +/* 0xf0a4 */ { false, 0xf0a4, 0xf0a4 }, +/* 0xf0a5 */ { false, 0xf0a5, 0xf0a5 }, +/* 0xf0a6 */ { false, 0xf0a6, 0xf0a6 }, +/* 0xf0a7 */ { false, 0xf0a7, 0xf0a7 }, +/* 0xf0a8 */ { false, 0xf0a8, 0xf0a8 }, +/* 0xf0a9 */ { false, 0xf0a9, 0xf0a9 }, +/* 0xf0aa */ { false, 0xf0aa, 0xf0aa }, +/* 0xf0ab */ { false, 0xf0ab, 0xf0ab }, +/* 0xf0ac */ { false, 0xf0ac, 0xf0ac }, +/* 0xf0ad */ { false, 0xf0ad, 0xf0ad }, +/* 0xf0ae */ { false, 0xf0ae, 0xf0ae }, +/* 0xf0af */ { false, 0xf0af, 0xf0af }, +/* 0xf0b0 */ { false, 0xf0b0, 0xf0b0 }, +/* 0xf0b1 */ { false, 0xf0b1, 0xf0b1 }, +/* 0xf0b2 */ { false, 0xf0b2, 0xf0b2 }, +/* 0xf0b3 */ { false, 0xf0b3, 0xf0b3 }, +/* 0xf0b4 */ { false, 0xf0b4, 0xf0b4 }, +/* 0xf0b5 */ { false, 0xf0b5, 0xf0b5 }, +/* 0xf0b6 */ { false, 0xf0b6, 0xf0b6 }, +/* 0xf0b7 */ { false, 0xf0b7, 0xf0b7 }, +/* 0xf0b8 */ { false, 0xf0b8, 0xf0b8 }, +/* 0xf0b9 */ { false, 0xf0b9, 0xf0b9 }, +/* 0xf0ba */ { false, 0xf0ba, 0xf0ba }, +/* 0xf0bb */ { false, 0xf0bb, 0xf0bb }, +/* 0xf0bc */ { false, 0xf0bc, 0xf0bc }, +/* 0xf0bd */ { false, 0xf0bd, 0xf0bd }, +/* 0xf0be */ { false, 0xf0be, 0xf0be }, +/* 0xf0bf */ { false, 0xf0bf, 0xf0bf }, +/* 0xf0c0 */ { false, 0xf0c0, 0xf0c0 }, +/* 0xf0c1 */ { false, 0xf0c1, 0xf0c1 }, +/* 0xf0c2 */ { false, 0xf0c2, 0xf0c2 }, +/* 0xf0c3 */ { false, 0xf0c3, 0xf0c3 }, +/* 0xf0c4 */ { false, 0xf0c4, 0xf0c4 }, +/* 0xf0c5 */ { false, 0xf0c5, 0xf0c5 }, +/* 0xf0c6 */ { false, 0xf0c6, 0xf0c6 }, +/* 0xf0c7 */ { false, 0xf0c7, 0xf0c7 }, +/* 0xf0c8 */ { false, 0xf0c8, 0xf0c8 }, +/* 0xf0c9 */ { false, 0xf0c9, 0xf0c9 }, +/* 0xf0ca */ { false, 0xf0ca, 0xf0ca }, +/* 0xf0cb */ { false, 0xf0cb, 0xf0cb }, +/* 0xf0cc */ { false, 0xf0cc, 0xf0cc }, +/* 0xf0cd */ { false, 0xf0cd, 0xf0cd }, +/* 0xf0ce */ { false, 0xf0ce, 0xf0ce }, +/* 0xf0cf */ { false, 0xf0cf, 0xf0cf }, +/* 0xf0d0 */ { false, 0xf0d0, 0xf0d0 }, +/* 0xf0d1 */ { false, 0xf0d1, 0xf0d1 }, +/* 0xf0d2 */ { false, 0xf0d2, 0xf0d2 }, +/* 0xf0d3 */ { false, 0xf0d3, 0xf0d3 }, +/* 0xf0d4 */ { false, 0xf0d4, 0xf0d4 }, +/* 0xf0d5 */ { false, 0xf0d5, 0xf0d5 }, +/* 0xf0d6 */ { false, 0xf0d6, 0xf0d6 }, +/* 0xf0d7 */ { false, 0xf0d7, 0xf0d7 }, +/* 0xf0d8 */ { false, 0xf0d8, 0xf0d8 }, +/* 0xf0d9 */ { false, 0xf0d9, 0xf0d9 }, +/* 0xf0da */ { false, 0xf0da, 0xf0da }, +/* 0xf0db */ { false, 0xf0db, 0xf0db }, +/* 0xf0dc */ { false, 0xf0dc, 0xf0dc }, +/* 0xf0dd */ { false, 0xf0dd, 0xf0dd }, +/* 0xf0de */ { false, 0xf0de, 0xf0de }, +/* 0xf0df */ { false, 0xf0df, 0xf0df }, +/* 0xf0e0 */ { false, 0xf0e0, 0xf0e0 }, +/* 0xf0e1 */ { false, 0xf0e1, 0xf0e1 }, +/* 0xf0e2 */ { false, 0xf0e2, 0xf0e2 }, +/* 0xf0e3 */ { false, 0xf0e3, 0xf0e3 }, +/* 0xf0e4 */ { false, 0xf0e4, 0xf0e4 }, +/* 0xf0e5 */ { false, 0xf0e5, 0xf0e5 }, +/* 0xf0e6 */ { false, 0xf0e6, 0xf0e6 }, +/* 0xf0e7 */ { false, 0xf0e7, 0xf0e7 }, +/* 0xf0e8 */ { false, 0xf0e8, 0xf0e8 }, +/* 0xf0e9 */ { false, 0xf0e9, 0xf0e9 }, +/* 0xf0ea */ { false, 0xf0ea, 0xf0ea }, +/* 0xf0eb */ { false, 0xf0eb, 0xf0eb }, +/* 0xf0ec */ { false, 0xf0ec, 0xf0ec }, +/* 0xf0ed */ { false, 0xf0ed, 0xf0ed }, +/* 0xf0ee */ { false, 0xf0ee, 0xf0ee }, +/* 0xf0ef */ { false, 0xf0ef, 0xf0ef }, +/* 0xf0f0 */ { false, 0xf0f0, 0xf0f0 }, +/* 0xf0f1 */ { false, 0xf0f1, 0xf0f1 }, +/* 0xf0f2 */ { false, 0xf0f2, 0xf0f2 }, +/* 0xf0f3 */ { false, 0xf0f3, 0xf0f3 }, +/* 0xf0f4 */ { false, 0xf0f4, 0xf0f4 }, +/* 0xf0f5 */ { false, 0xf0f5, 0xf0f5 }, +/* 0xf0f6 */ { false, 0xf0f6, 0xf0f6 }, +/* 0xf0f7 */ { false, 0xf0f7, 0xf0f7 }, +/* 0xf0f8 */ { false, 0xf0f8, 0xf0f8 }, +/* 0xf0f9 */ { false, 0xf0f9, 0xf0f9 }, +/* 0xf0fa */ { false, 0xf0fa, 0xf0fa }, +/* 0xf0fb */ { false, 0xf0fb, 0xf0fb }, +/* 0xf0fc */ { false, 0xf0fc, 0xf0fc }, +/* 0xf0fd */ { false, 0xf0fd, 0xf0fd }, +/* 0xf0fe */ { false, 0xf0fe, 0xf0fe }, +/* 0xf0ff */ { false, 0xf0ff, 0xf0ff }, +/* 0xf100 */ { false, 0xf100, 0xf100 }, +/* 0xf101 */ { false, 0xf101, 0xf101 }, +/* 0xf102 */ { false, 0xf102, 0xf102 }, +/* 0xf103 */ { false, 0xf103, 0xf103 }, +/* 0xf104 */ { false, 0xf104, 0xf104 }, +/* 0xf105 */ { false, 0xf105, 0xf105 }, +/* 0xf106 */ { false, 0xf106, 0xf106 }, +/* 0xf107 */ { false, 0xf107, 0xf107 }, +/* 0xf108 */ { false, 0xf108, 0xf108 }, +/* 0xf109 */ { false, 0xf109, 0xf109 }, +/* 0xf10a */ { false, 0xf10a, 0xf10a }, +/* 0xf10b */ { false, 0xf10b, 0xf10b }, +/* 0xf10c */ { false, 0xf10c, 0xf10c }, +/* 0xf10d */ { false, 0xf10d, 0xf10d }, +/* 0xf10e */ { false, 0xf10e, 0xf10e }, +/* 0xf10f */ { false, 0xf10f, 0xf10f }, +/* 0xf110 */ { false, 0xf110, 0xf110 }, +/* 0xf111 */ { false, 0xf111, 0xf111 }, +/* 0xf112 */ { false, 0xf112, 0xf112 }, +/* 0xf113 */ { false, 0xf113, 0xf113 }, +/* 0xf114 */ { false, 0xf114, 0xf114 }, +/* 0xf115 */ { false, 0xf115, 0xf115 }, +/* 0xf116 */ { false, 0xf116, 0xf116 }, +/* 0xf117 */ { false, 0xf117, 0xf117 }, +/* 0xf118 */ { false, 0xf118, 0xf118 }, +/* 0xf119 */ { false, 0xf119, 0xf119 }, +/* 0xf11a */ { false, 0xf11a, 0xf11a }, +/* 0xf11b */ { false, 0xf11b, 0xf11b }, +/* 0xf11c */ { false, 0xf11c, 0xf11c }, +/* 0xf11d */ { false, 0xf11d, 0xf11d }, +/* 0xf11e */ { false, 0xf11e, 0xf11e }, +/* 0xf11f */ { false, 0xf11f, 0xf11f }, +/* 0xf120 */ { false, 0xf120, 0xf120 }, +/* 0xf121 */ { false, 0xf121, 0xf121 }, +/* 0xf122 */ { false, 0xf122, 0xf122 }, +/* 0xf123 */ { false, 0xf123, 0xf123 }, +/* 0xf124 */ { false, 0xf124, 0xf124 }, +/* 0xf125 */ { false, 0xf125, 0xf125 }, +/* 0xf126 */ { false, 0xf126, 0xf126 }, +/* 0xf127 */ { false, 0xf127, 0xf127 }, +/* 0xf128 */ { false, 0xf128, 0xf128 }, +/* 0xf129 */ { false, 0xf129, 0xf129 }, +/* 0xf12a */ { false, 0xf12a, 0xf12a }, +/* 0xf12b */ { false, 0xf12b, 0xf12b }, +/* 0xf12c */ { false, 0xf12c, 0xf12c }, +/* 0xf12d */ { false, 0xf12d, 0xf12d }, +/* 0xf12e */ { false, 0xf12e, 0xf12e }, +/* 0xf12f */ { false, 0xf12f, 0xf12f }, +/* 0xf130 */ { false, 0xf130, 0xf130 }, +/* 0xf131 */ { false, 0xf131, 0xf131 }, +/* 0xf132 */ { false, 0xf132, 0xf132 }, +/* 0xf133 */ { false, 0xf133, 0xf133 }, +/* 0xf134 */ { false, 0xf134, 0xf134 }, +/* 0xf135 */ { false, 0xf135, 0xf135 }, +/* 0xf136 */ { false, 0xf136, 0xf136 }, +/* 0xf137 */ { false, 0xf137, 0xf137 }, +/* 0xf138 */ { false, 0xf138, 0xf138 }, +/* 0xf139 */ { false, 0xf139, 0xf139 }, +/* 0xf13a */ { false, 0xf13a, 0xf13a }, +/* 0xf13b */ { false, 0xf13b, 0xf13b }, +/* 0xf13c */ { false, 0xf13c, 0xf13c }, +/* 0xf13d */ { false, 0xf13d, 0xf13d }, +/* 0xf13e */ { false, 0xf13e, 0xf13e }, +/* 0xf13f */ { false, 0xf13f, 0xf13f }, +/* 0xf140 */ { false, 0xf140, 0xf140 }, +/* 0xf141 */ { false, 0xf141, 0xf141 }, +/* 0xf142 */ { false, 0xf142, 0xf142 }, +/* 0xf143 */ { false, 0xf143, 0xf143 }, +/* 0xf144 */ { false, 0xf144, 0xf144 }, +/* 0xf145 */ { false, 0xf145, 0xf145 }, +/* 0xf146 */ { false, 0xf146, 0xf146 }, +/* 0xf147 */ { false, 0xf147, 0xf147 }, +/* 0xf148 */ { false, 0xf148, 0xf148 }, +/* 0xf149 */ { false, 0xf149, 0xf149 }, +/* 0xf14a */ { false, 0xf14a, 0xf14a }, +/* 0xf14b */ { false, 0xf14b, 0xf14b }, +/* 0xf14c */ { false, 0xf14c, 0xf14c }, +/* 0xf14d */ { false, 0xf14d, 0xf14d }, +/* 0xf14e */ { false, 0xf14e, 0xf14e }, +/* 0xf14f */ { false, 0xf14f, 0xf14f }, +/* 0xf150 */ { false, 0xf150, 0xf150 }, +/* 0xf151 */ { false, 0xf151, 0xf151 }, +/* 0xf152 */ { false, 0xf152, 0xf152 }, +/* 0xf153 */ { false, 0xf153, 0xf153 }, +/* 0xf154 */ { false, 0xf154, 0xf154 }, +/* 0xf155 */ { false, 0xf155, 0xf155 }, +/* 0xf156 */ { false, 0xf156, 0xf156 }, +/* 0xf157 */ { false, 0xf157, 0xf157 }, +/* 0xf158 */ { false, 0xf158, 0xf158 }, +/* 0xf159 */ { false, 0xf159, 0xf159 }, +/* 0xf15a */ { false, 0xf15a, 0xf15a }, +/* 0xf15b */ { false, 0xf15b, 0xf15b }, +/* 0xf15c */ { false, 0xf15c, 0xf15c }, +/* 0xf15d */ { false, 0xf15d, 0xf15d }, +/* 0xf15e */ { false, 0xf15e, 0xf15e }, +/* 0xf15f */ { false, 0xf15f, 0xf15f }, +/* 0xf160 */ { false, 0xf160, 0xf160 }, +/* 0xf161 */ { false, 0xf161, 0xf161 }, +/* 0xf162 */ { false, 0xf162, 0xf162 }, +/* 0xf163 */ { false, 0xf163, 0xf163 }, +/* 0xf164 */ { false, 0xf164, 0xf164 }, +/* 0xf165 */ { false, 0xf165, 0xf165 }, +/* 0xf166 */ { false, 0xf166, 0xf166 }, +/* 0xf167 */ { false, 0xf167, 0xf167 }, +/* 0xf168 */ { false, 0xf168, 0xf168 }, +/* 0xf169 */ { false, 0xf169, 0xf169 }, +/* 0xf16a */ { false, 0xf16a, 0xf16a }, +/* 0xf16b */ { false, 0xf16b, 0xf16b }, +/* 0xf16c */ { false, 0xf16c, 0xf16c }, +/* 0xf16d */ { false, 0xf16d, 0xf16d }, +/* 0xf16e */ { false, 0xf16e, 0xf16e }, +/* 0xf16f */ { false, 0xf16f, 0xf16f }, +/* 0xf170 */ { false, 0xf170, 0xf170 }, +/* 0xf171 */ { false, 0xf171, 0xf171 }, +/* 0xf172 */ { false, 0xf172, 0xf172 }, +/* 0xf173 */ { false, 0xf173, 0xf173 }, +/* 0xf174 */ { false, 0xf174, 0xf174 }, +/* 0xf175 */ { false, 0xf175, 0xf175 }, +/* 0xf176 */ { false, 0xf176, 0xf176 }, +/* 0xf177 */ { false, 0xf177, 0xf177 }, +/* 0xf178 */ { false, 0xf178, 0xf178 }, +/* 0xf179 */ { false, 0xf179, 0xf179 }, +/* 0xf17a */ { false, 0xf17a, 0xf17a }, +/* 0xf17b */ { false, 0xf17b, 0xf17b }, +/* 0xf17c */ { false, 0xf17c, 0xf17c }, +/* 0xf17d */ { false, 0xf17d, 0xf17d }, +/* 0xf17e */ { false, 0xf17e, 0xf17e }, +/* 0xf17f */ { false, 0xf17f, 0xf17f }, +/* 0xf180 */ { false, 0xf180, 0xf180 }, +/* 0xf181 */ { false, 0xf181, 0xf181 }, +/* 0xf182 */ { false, 0xf182, 0xf182 }, +/* 0xf183 */ { false, 0xf183, 0xf183 }, +/* 0xf184 */ { false, 0xf184, 0xf184 }, +/* 0xf185 */ { false, 0xf185, 0xf185 }, +/* 0xf186 */ { false, 0xf186, 0xf186 }, +/* 0xf187 */ { false, 0xf187, 0xf187 }, +/* 0xf188 */ { false, 0xf188, 0xf188 }, +/* 0xf189 */ { false, 0xf189, 0xf189 }, +/* 0xf18a */ { false, 0xf18a, 0xf18a }, +/* 0xf18b */ { false, 0xf18b, 0xf18b }, +/* 0xf18c */ { false, 0xf18c, 0xf18c }, +/* 0xf18d */ { false, 0xf18d, 0xf18d }, +/* 0xf18e */ { false, 0xf18e, 0xf18e }, +/* 0xf18f */ { false, 0xf18f, 0xf18f }, +/* 0xf190 */ { false, 0xf190, 0xf190 }, +/* 0xf191 */ { false, 0xf191, 0xf191 }, +/* 0xf192 */ { false, 0xf192, 0xf192 }, +/* 0xf193 */ { false, 0xf193, 0xf193 }, +/* 0xf194 */ { false, 0xf194, 0xf194 }, +/* 0xf195 */ { false, 0xf195, 0xf195 }, +/* 0xf196 */ { false, 0xf196, 0xf196 }, +/* 0xf197 */ { false, 0xf197, 0xf197 }, +/* 0xf198 */ { false, 0xf198, 0xf198 }, +/* 0xf199 */ { false, 0xf199, 0xf199 }, +/* 0xf19a */ { false, 0xf19a, 0xf19a }, +/* 0xf19b */ { false, 0xf19b, 0xf19b }, +/* 0xf19c */ { false, 0xf19c, 0xf19c }, +/* 0xf19d */ { false, 0xf19d, 0xf19d }, +/* 0xf19e */ { false, 0xf19e, 0xf19e }, +/* 0xf19f */ { false, 0xf19f, 0xf19f }, +/* 0xf1a0 */ { false, 0xf1a0, 0xf1a0 }, +/* 0xf1a1 */ { false, 0xf1a1, 0xf1a1 }, +/* 0xf1a2 */ { false, 0xf1a2, 0xf1a2 }, +/* 0xf1a3 */ { false, 0xf1a3, 0xf1a3 }, +/* 0xf1a4 */ { false, 0xf1a4, 0xf1a4 }, +/* 0xf1a5 */ { false, 0xf1a5, 0xf1a5 }, +/* 0xf1a6 */ { false, 0xf1a6, 0xf1a6 }, +/* 0xf1a7 */ { false, 0xf1a7, 0xf1a7 }, +/* 0xf1a8 */ { false, 0xf1a8, 0xf1a8 }, +/* 0xf1a9 */ { false, 0xf1a9, 0xf1a9 }, +/* 0xf1aa */ { false, 0xf1aa, 0xf1aa }, +/* 0xf1ab */ { false, 0xf1ab, 0xf1ab }, +/* 0xf1ac */ { false, 0xf1ac, 0xf1ac }, +/* 0xf1ad */ { false, 0xf1ad, 0xf1ad }, +/* 0xf1ae */ { false, 0xf1ae, 0xf1ae }, +/* 0xf1af */ { false, 0xf1af, 0xf1af }, +/* 0xf1b0 */ { false, 0xf1b0, 0xf1b0 }, +/* 0xf1b1 */ { false, 0xf1b1, 0xf1b1 }, +/* 0xf1b2 */ { false, 0xf1b2, 0xf1b2 }, +/* 0xf1b3 */ { false, 0xf1b3, 0xf1b3 }, +/* 0xf1b4 */ { false, 0xf1b4, 0xf1b4 }, +/* 0xf1b5 */ { false, 0xf1b5, 0xf1b5 }, +/* 0xf1b6 */ { false, 0xf1b6, 0xf1b6 }, +/* 0xf1b7 */ { false, 0xf1b7, 0xf1b7 }, +/* 0xf1b8 */ { false, 0xf1b8, 0xf1b8 }, +/* 0xf1b9 */ { false, 0xf1b9, 0xf1b9 }, +/* 0xf1ba */ { false, 0xf1ba, 0xf1ba }, +/* 0xf1bb */ { false, 0xf1bb, 0xf1bb }, +/* 0xf1bc */ { false, 0xf1bc, 0xf1bc }, +/* 0xf1bd */ { false, 0xf1bd, 0xf1bd }, +/* 0xf1be */ { false, 0xf1be, 0xf1be }, +/* 0xf1bf */ { false, 0xf1bf, 0xf1bf }, +/* 0xf1c0 */ { false, 0xf1c0, 0xf1c0 }, +/* 0xf1c1 */ { false, 0xf1c1, 0xf1c1 }, +/* 0xf1c2 */ { false, 0xf1c2, 0xf1c2 }, +/* 0xf1c3 */ { false, 0xf1c3, 0xf1c3 }, +/* 0xf1c4 */ { false, 0xf1c4, 0xf1c4 }, +/* 0xf1c5 */ { false, 0xf1c5, 0xf1c5 }, +/* 0xf1c6 */ { false, 0xf1c6, 0xf1c6 }, +/* 0xf1c7 */ { false, 0xf1c7, 0xf1c7 }, +/* 0xf1c8 */ { false, 0xf1c8, 0xf1c8 }, +/* 0xf1c9 */ { false, 0xf1c9, 0xf1c9 }, +/* 0xf1ca */ { false, 0xf1ca, 0xf1ca }, +/* 0xf1cb */ { false, 0xf1cb, 0xf1cb }, +/* 0xf1cc */ { false, 0xf1cc, 0xf1cc }, +/* 0xf1cd */ { false, 0xf1cd, 0xf1cd }, +/* 0xf1ce */ { false, 0xf1ce, 0xf1ce }, +/* 0xf1cf */ { false, 0xf1cf, 0xf1cf }, +/* 0xf1d0 */ { false, 0xf1d0, 0xf1d0 }, +/* 0xf1d1 */ { false, 0xf1d1, 0xf1d1 }, +/* 0xf1d2 */ { false, 0xf1d2, 0xf1d2 }, +/* 0xf1d3 */ { false, 0xf1d3, 0xf1d3 }, +/* 0xf1d4 */ { false, 0xf1d4, 0xf1d4 }, +/* 0xf1d5 */ { false, 0xf1d5, 0xf1d5 }, +/* 0xf1d6 */ { false, 0xf1d6, 0xf1d6 }, +/* 0xf1d7 */ { false, 0xf1d7, 0xf1d7 }, +/* 0xf1d8 */ { false, 0xf1d8, 0xf1d8 }, +/* 0xf1d9 */ { false, 0xf1d9, 0xf1d9 }, +/* 0xf1da */ { false, 0xf1da, 0xf1da }, +/* 0xf1db */ { false, 0xf1db, 0xf1db }, +/* 0xf1dc */ { false, 0xf1dc, 0xf1dc }, +/* 0xf1dd */ { false, 0xf1dd, 0xf1dd }, +/* 0xf1de */ { false, 0xf1de, 0xf1de }, +/* 0xf1df */ { false, 0xf1df, 0xf1df }, +/* 0xf1e0 */ { false, 0xf1e0, 0xf1e0 }, +/* 0xf1e1 */ { false, 0xf1e1, 0xf1e1 }, +/* 0xf1e2 */ { false, 0xf1e2, 0xf1e2 }, +/* 0xf1e3 */ { false, 0xf1e3, 0xf1e3 }, +/* 0xf1e4 */ { false, 0xf1e4, 0xf1e4 }, +/* 0xf1e5 */ { false, 0xf1e5, 0xf1e5 }, +/* 0xf1e6 */ { false, 0xf1e6, 0xf1e6 }, +/* 0xf1e7 */ { false, 0xf1e7, 0xf1e7 }, +/* 0xf1e8 */ { false, 0xf1e8, 0xf1e8 }, +/* 0xf1e9 */ { false, 0xf1e9, 0xf1e9 }, +/* 0xf1ea */ { false, 0xf1ea, 0xf1ea }, +/* 0xf1eb */ { false, 0xf1eb, 0xf1eb }, +/* 0xf1ec */ { false, 0xf1ec, 0xf1ec }, +/* 0xf1ed */ { false, 0xf1ed, 0xf1ed }, +/* 0xf1ee */ { false, 0xf1ee, 0xf1ee }, +/* 0xf1ef */ { false, 0xf1ef, 0xf1ef }, +/* 0xf1f0 */ { false, 0xf1f0, 0xf1f0 }, +/* 0xf1f1 */ { false, 0xf1f1, 0xf1f1 }, +/* 0xf1f2 */ { false, 0xf1f2, 0xf1f2 }, +/* 0xf1f3 */ { false, 0xf1f3, 0xf1f3 }, +/* 0xf1f4 */ { false, 0xf1f4, 0xf1f4 }, +/* 0xf1f5 */ { false, 0xf1f5, 0xf1f5 }, +/* 0xf1f6 */ { false, 0xf1f6, 0xf1f6 }, +/* 0xf1f7 */ { false, 0xf1f7, 0xf1f7 }, +/* 0xf1f8 */ { false, 0xf1f8, 0xf1f8 }, +/* 0xf1f9 */ { false, 0xf1f9, 0xf1f9 }, +/* 0xf1fa */ { false, 0xf1fa, 0xf1fa }, +/* 0xf1fb */ { false, 0xf1fb, 0xf1fb }, +/* 0xf1fc */ { false, 0xf1fc, 0xf1fc }, +/* 0xf1fd */ { false, 0xf1fd, 0xf1fd }, +/* 0xf1fe */ { false, 0xf1fe, 0xf1fe }, +/* 0xf1ff */ { false, 0xf1ff, 0xf1ff }, +/* 0xf200 */ { false, 0xf200, 0xf200 }, +/* 0xf201 */ { false, 0xf201, 0xf201 }, +/* 0xf202 */ { false, 0xf202, 0xf202 }, +/* 0xf203 */ { false, 0xf203, 0xf203 }, +/* 0xf204 */ { false, 0xf204, 0xf204 }, +/* 0xf205 */ { false, 0xf205, 0xf205 }, +/* 0xf206 */ { false, 0xf206, 0xf206 }, +/* 0xf207 */ { false, 0xf207, 0xf207 }, +/* 0xf208 */ { false, 0xf208, 0xf208 }, +/* 0xf209 */ { false, 0xf209, 0xf209 }, +/* 0xf20a */ { false, 0xf20a, 0xf20a }, +/* 0xf20b */ { false, 0xf20b, 0xf20b }, +/* 0xf20c */ { false, 0xf20c, 0xf20c }, +/* 0xf20d */ { false, 0xf20d, 0xf20d }, +/* 0xf20e */ { false, 0xf20e, 0xf20e }, +/* 0xf20f */ { false, 0xf20f, 0xf20f }, +/* 0xf210 */ { false, 0xf210, 0xf210 }, +/* 0xf211 */ { false, 0xf211, 0xf211 }, +/* 0xf212 */ { false, 0xf212, 0xf212 }, +/* 0xf213 */ { false, 0xf213, 0xf213 }, +/* 0xf214 */ { false, 0xf214, 0xf214 }, +/* 0xf215 */ { false, 0xf215, 0xf215 }, +/* 0xf216 */ { false, 0xf216, 0xf216 }, +/* 0xf217 */ { false, 0xf217, 0xf217 }, +/* 0xf218 */ { false, 0xf218, 0xf218 }, +/* 0xf219 */ { false, 0xf219, 0xf219 }, +/* 0xf21a */ { false, 0xf21a, 0xf21a }, +/* 0xf21b */ { false, 0xf21b, 0xf21b }, +/* 0xf21c */ { false, 0xf21c, 0xf21c }, +/* 0xf21d */ { false, 0xf21d, 0xf21d }, +/* 0xf21e */ { false, 0xf21e, 0xf21e }, +/* 0xf21f */ { false, 0xf21f, 0xf21f }, +/* 0xf220 */ { false, 0xf220, 0xf220 }, +/* 0xf221 */ { false, 0xf221, 0xf221 }, +/* 0xf222 */ { false, 0xf222, 0xf222 }, +/* 0xf223 */ { false, 0xf223, 0xf223 }, +/* 0xf224 */ { false, 0xf224, 0xf224 }, +/* 0xf225 */ { false, 0xf225, 0xf225 }, +/* 0xf226 */ { false, 0xf226, 0xf226 }, +/* 0xf227 */ { false, 0xf227, 0xf227 }, +/* 0xf228 */ { false, 0xf228, 0xf228 }, +/* 0xf229 */ { false, 0xf229, 0xf229 }, +/* 0xf22a */ { false, 0xf22a, 0xf22a }, +/* 0xf22b */ { false, 0xf22b, 0xf22b }, +/* 0xf22c */ { false, 0xf22c, 0xf22c }, +/* 0xf22d */ { false, 0xf22d, 0xf22d }, +/* 0xf22e */ { false, 0xf22e, 0xf22e }, +/* 0xf22f */ { false, 0xf22f, 0xf22f }, +/* 0xf230 */ { false, 0xf230, 0xf230 }, +/* 0xf231 */ { false, 0xf231, 0xf231 }, +/* 0xf232 */ { false, 0xf232, 0xf232 }, +/* 0xf233 */ { false, 0xf233, 0xf233 }, +/* 0xf234 */ { false, 0xf234, 0xf234 }, +/* 0xf235 */ { false, 0xf235, 0xf235 }, +/* 0xf236 */ { false, 0xf236, 0xf236 }, +/* 0xf237 */ { false, 0xf237, 0xf237 }, +/* 0xf238 */ { false, 0xf238, 0xf238 }, +/* 0xf239 */ { false, 0xf239, 0xf239 }, +/* 0xf23a */ { false, 0xf23a, 0xf23a }, +/* 0xf23b */ { false, 0xf23b, 0xf23b }, +/* 0xf23c */ { false, 0xf23c, 0xf23c }, +/* 0xf23d */ { false, 0xf23d, 0xf23d }, +/* 0xf23e */ { false, 0xf23e, 0xf23e }, +/* 0xf23f */ { false, 0xf23f, 0xf23f }, +/* 0xf240 */ { false, 0xf240, 0xf240 }, +/* 0xf241 */ { false, 0xf241, 0xf241 }, +/* 0xf242 */ { false, 0xf242, 0xf242 }, +/* 0xf243 */ { false, 0xf243, 0xf243 }, +/* 0xf244 */ { false, 0xf244, 0xf244 }, +/* 0xf245 */ { false, 0xf245, 0xf245 }, +/* 0xf246 */ { false, 0xf246, 0xf246 }, +/* 0xf247 */ { false, 0xf247, 0xf247 }, +/* 0xf248 */ { false, 0xf248, 0xf248 }, +/* 0xf249 */ { false, 0xf249, 0xf249 }, +/* 0xf24a */ { false, 0xf24a, 0xf24a }, +/* 0xf24b */ { false, 0xf24b, 0xf24b }, +/* 0xf24c */ { false, 0xf24c, 0xf24c }, +/* 0xf24d */ { false, 0xf24d, 0xf24d }, +/* 0xf24e */ { false, 0xf24e, 0xf24e }, +/* 0xf24f */ { false, 0xf24f, 0xf24f }, +/* 0xf250 */ { false, 0xf250, 0xf250 }, +/* 0xf251 */ { false, 0xf251, 0xf251 }, +/* 0xf252 */ { false, 0xf252, 0xf252 }, +/* 0xf253 */ { false, 0xf253, 0xf253 }, +/* 0xf254 */ { false, 0xf254, 0xf254 }, +/* 0xf255 */ { false, 0xf255, 0xf255 }, +/* 0xf256 */ { false, 0xf256, 0xf256 }, +/* 0xf257 */ { false, 0xf257, 0xf257 }, +/* 0xf258 */ { false, 0xf258, 0xf258 }, +/* 0xf259 */ { false, 0xf259, 0xf259 }, +/* 0xf25a */ { false, 0xf25a, 0xf25a }, +/* 0xf25b */ { false, 0xf25b, 0xf25b }, +/* 0xf25c */ { false, 0xf25c, 0xf25c }, +/* 0xf25d */ { false, 0xf25d, 0xf25d }, +/* 0xf25e */ { false, 0xf25e, 0xf25e }, +/* 0xf25f */ { false, 0xf25f, 0xf25f }, +/* 0xf260 */ { false, 0xf260, 0xf260 }, +/* 0xf261 */ { false, 0xf261, 0xf261 }, +/* 0xf262 */ { false, 0xf262, 0xf262 }, +/* 0xf263 */ { false, 0xf263, 0xf263 }, +/* 0xf264 */ { false, 0xf264, 0xf264 }, +/* 0xf265 */ { false, 0xf265, 0xf265 }, +/* 0xf266 */ { false, 0xf266, 0xf266 }, +/* 0xf267 */ { false, 0xf267, 0xf267 }, +/* 0xf268 */ { false, 0xf268, 0xf268 }, +/* 0xf269 */ { false, 0xf269, 0xf269 }, +/* 0xf26a */ { false, 0xf26a, 0xf26a }, +/* 0xf26b */ { false, 0xf26b, 0xf26b }, +/* 0xf26c */ { false, 0xf26c, 0xf26c }, +/* 0xf26d */ { false, 0xf26d, 0xf26d }, +/* 0xf26e */ { false, 0xf26e, 0xf26e }, +/* 0xf26f */ { false, 0xf26f, 0xf26f }, +/* 0xf270 */ { false, 0xf270, 0xf270 }, +/* 0xf271 */ { false, 0xf271, 0xf271 }, +/* 0xf272 */ { false, 0xf272, 0xf272 }, +/* 0xf273 */ { false, 0xf273, 0xf273 }, +/* 0xf274 */ { false, 0xf274, 0xf274 }, +/* 0xf275 */ { false, 0xf275, 0xf275 }, +/* 0xf276 */ { false, 0xf276, 0xf276 }, +/* 0xf277 */ { false, 0xf277, 0xf277 }, +/* 0xf278 */ { false, 0xf278, 0xf278 }, +/* 0xf279 */ { false, 0xf279, 0xf279 }, +/* 0xf27a */ { false, 0xf27a, 0xf27a }, +/* 0xf27b */ { false, 0xf27b, 0xf27b }, +/* 0xf27c */ { false, 0xf27c, 0xf27c }, +/* 0xf27d */ { false, 0xf27d, 0xf27d }, +/* 0xf27e */ { false, 0xf27e, 0xf27e }, +/* 0xf27f */ { false, 0xf27f, 0xf27f }, +/* 0xf280 */ { false, 0xf280, 0xf280 }, +/* 0xf281 */ { false, 0xf281, 0xf281 }, +/* 0xf282 */ { false, 0xf282, 0xf282 }, +/* 0xf283 */ { false, 0xf283, 0xf283 }, +/* 0xf284 */ { false, 0xf284, 0xf284 }, +/* 0xf285 */ { false, 0xf285, 0xf285 }, +/* 0xf286 */ { false, 0xf286, 0xf286 }, +/* 0xf287 */ { false, 0xf287, 0xf287 }, +/* 0xf288 */ { false, 0xf288, 0xf288 }, +/* 0xf289 */ { false, 0xf289, 0xf289 }, +/* 0xf28a */ { false, 0xf28a, 0xf28a }, +/* 0xf28b */ { false, 0xf28b, 0xf28b }, +/* 0xf28c */ { false, 0xf28c, 0xf28c }, +/* 0xf28d */ { false, 0xf28d, 0xf28d }, +/* 0xf28e */ { false, 0xf28e, 0xf28e }, +/* 0xf28f */ { false, 0xf28f, 0xf28f }, +/* 0xf290 */ { false, 0xf290, 0xf290 }, +/* 0xf291 */ { false, 0xf291, 0xf291 }, +/* 0xf292 */ { false, 0xf292, 0xf292 }, +/* 0xf293 */ { false, 0xf293, 0xf293 }, +/* 0xf294 */ { false, 0xf294, 0xf294 }, +/* 0xf295 */ { false, 0xf295, 0xf295 }, +/* 0xf296 */ { false, 0xf296, 0xf296 }, +/* 0xf297 */ { false, 0xf297, 0xf297 }, +/* 0xf298 */ { false, 0xf298, 0xf298 }, +/* 0xf299 */ { false, 0xf299, 0xf299 }, +/* 0xf29a */ { false, 0xf29a, 0xf29a }, +/* 0xf29b */ { false, 0xf29b, 0xf29b }, +/* 0xf29c */ { false, 0xf29c, 0xf29c }, +/* 0xf29d */ { false, 0xf29d, 0xf29d }, +/* 0xf29e */ { false, 0xf29e, 0xf29e }, +/* 0xf29f */ { false, 0xf29f, 0xf29f }, +/* 0xf2a0 */ { false, 0xf2a0, 0xf2a0 }, +/* 0xf2a1 */ { false, 0xf2a1, 0xf2a1 }, +/* 0xf2a2 */ { false, 0xf2a2, 0xf2a2 }, +/* 0xf2a3 */ { false, 0xf2a3, 0xf2a3 }, +/* 0xf2a4 */ { false, 0xf2a4, 0xf2a4 }, +/* 0xf2a5 */ { false, 0xf2a5, 0xf2a5 }, +/* 0xf2a6 */ { false, 0xf2a6, 0xf2a6 }, +/* 0xf2a7 */ { false, 0xf2a7, 0xf2a7 }, +/* 0xf2a8 */ { false, 0xf2a8, 0xf2a8 }, +/* 0xf2a9 */ { false, 0xf2a9, 0xf2a9 }, +/* 0xf2aa */ { false, 0xf2aa, 0xf2aa }, +/* 0xf2ab */ { false, 0xf2ab, 0xf2ab }, +/* 0xf2ac */ { false, 0xf2ac, 0xf2ac }, +/* 0xf2ad */ { false, 0xf2ad, 0xf2ad }, +/* 0xf2ae */ { false, 0xf2ae, 0xf2ae }, +/* 0xf2af */ { false, 0xf2af, 0xf2af }, +/* 0xf2b0 */ { false, 0xf2b0, 0xf2b0 }, +/* 0xf2b1 */ { false, 0xf2b1, 0xf2b1 }, +/* 0xf2b2 */ { false, 0xf2b2, 0xf2b2 }, +/* 0xf2b3 */ { false, 0xf2b3, 0xf2b3 }, +/* 0xf2b4 */ { false, 0xf2b4, 0xf2b4 }, +/* 0xf2b5 */ { false, 0xf2b5, 0xf2b5 }, +/* 0xf2b6 */ { false, 0xf2b6, 0xf2b6 }, +/* 0xf2b7 */ { false, 0xf2b7, 0xf2b7 }, +/* 0xf2b8 */ { false, 0xf2b8, 0xf2b8 }, +/* 0xf2b9 */ { false, 0xf2b9, 0xf2b9 }, +/* 0xf2ba */ { false, 0xf2ba, 0xf2ba }, +/* 0xf2bb */ { false, 0xf2bb, 0xf2bb }, +/* 0xf2bc */ { false, 0xf2bc, 0xf2bc }, +/* 0xf2bd */ { false, 0xf2bd, 0xf2bd }, +/* 0xf2be */ { false, 0xf2be, 0xf2be }, +/* 0xf2bf */ { false, 0xf2bf, 0xf2bf }, +/* 0xf2c0 */ { false, 0xf2c0, 0xf2c0 }, +/* 0xf2c1 */ { false, 0xf2c1, 0xf2c1 }, +/* 0xf2c2 */ { false, 0xf2c2, 0xf2c2 }, +/* 0xf2c3 */ { false, 0xf2c3, 0xf2c3 }, +/* 0xf2c4 */ { false, 0xf2c4, 0xf2c4 }, +/* 0xf2c5 */ { false, 0xf2c5, 0xf2c5 }, +/* 0xf2c6 */ { false, 0xf2c6, 0xf2c6 }, +/* 0xf2c7 */ { false, 0xf2c7, 0xf2c7 }, +/* 0xf2c8 */ { false, 0xf2c8, 0xf2c8 }, +/* 0xf2c9 */ { false, 0xf2c9, 0xf2c9 }, +/* 0xf2ca */ { false, 0xf2ca, 0xf2ca }, +/* 0xf2cb */ { false, 0xf2cb, 0xf2cb }, +/* 0xf2cc */ { false, 0xf2cc, 0xf2cc }, +/* 0xf2cd */ { false, 0xf2cd, 0xf2cd }, +/* 0xf2ce */ { false, 0xf2ce, 0xf2ce }, +/* 0xf2cf */ { false, 0xf2cf, 0xf2cf }, +/* 0xf2d0 */ { false, 0xf2d0, 0xf2d0 }, +/* 0xf2d1 */ { false, 0xf2d1, 0xf2d1 }, +/* 0xf2d2 */ { false, 0xf2d2, 0xf2d2 }, +/* 0xf2d3 */ { false, 0xf2d3, 0xf2d3 }, +/* 0xf2d4 */ { false, 0xf2d4, 0xf2d4 }, +/* 0xf2d5 */ { false, 0xf2d5, 0xf2d5 }, +/* 0xf2d6 */ { false, 0xf2d6, 0xf2d6 }, +/* 0xf2d7 */ { false, 0xf2d7, 0xf2d7 }, +/* 0xf2d8 */ { false, 0xf2d8, 0xf2d8 }, +/* 0xf2d9 */ { false, 0xf2d9, 0xf2d9 }, +/* 0xf2da */ { false, 0xf2da, 0xf2da }, +/* 0xf2db */ { false, 0xf2db, 0xf2db }, +/* 0xf2dc */ { false, 0xf2dc, 0xf2dc }, +/* 0xf2dd */ { false, 0xf2dd, 0xf2dd }, +/* 0xf2de */ { false, 0xf2de, 0xf2de }, +/* 0xf2df */ { false, 0xf2df, 0xf2df }, +/* 0xf2e0 */ { false, 0xf2e0, 0xf2e0 }, +/* 0xf2e1 */ { false, 0xf2e1, 0xf2e1 }, +/* 0xf2e2 */ { false, 0xf2e2, 0xf2e2 }, +/* 0xf2e3 */ { false, 0xf2e3, 0xf2e3 }, +/* 0xf2e4 */ { false, 0xf2e4, 0xf2e4 }, +/* 0xf2e5 */ { false, 0xf2e5, 0xf2e5 }, +/* 0xf2e6 */ { false, 0xf2e6, 0xf2e6 }, +/* 0xf2e7 */ { false, 0xf2e7, 0xf2e7 }, +/* 0xf2e8 */ { false, 0xf2e8, 0xf2e8 }, +/* 0xf2e9 */ { false, 0xf2e9, 0xf2e9 }, +/* 0xf2ea */ { false, 0xf2ea, 0xf2ea }, +/* 0xf2eb */ { false, 0xf2eb, 0xf2eb }, +/* 0xf2ec */ { false, 0xf2ec, 0xf2ec }, +/* 0xf2ed */ { false, 0xf2ed, 0xf2ed }, +/* 0xf2ee */ { false, 0xf2ee, 0xf2ee }, +/* 0xf2ef */ { false, 0xf2ef, 0xf2ef }, +/* 0xf2f0 */ { false, 0xf2f0, 0xf2f0 }, +/* 0xf2f1 */ { false, 0xf2f1, 0xf2f1 }, +/* 0xf2f2 */ { false, 0xf2f2, 0xf2f2 }, +/* 0xf2f3 */ { false, 0xf2f3, 0xf2f3 }, +/* 0xf2f4 */ { false, 0xf2f4, 0xf2f4 }, +/* 0xf2f5 */ { false, 0xf2f5, 0xf2f5 }, +/* 0xf2f6 */ { false, 0xf2f6, 0xf2f6 }, +/* 0xf2f7 */ { false, 0xf2f7, 0xf2f7 }, +/* 0xf2f8 */ { false, 0xf2f8, 0xf2f8 }, +/* 0xf2f9 */ { false, 0xf2f9, 0xf2f9 }, +/* 0xf2fa */ { false, 0xf2fa, 0xf2fa }, +/* 0xf2fb */ { false, 0xf2fb, 0xf2fb }, +/* 0xf2fc */ { false, 0xf2fc, 0xf2fc }, +/* 0xf2fd */ { false, 0xf2fd, 0xf2fd }, +/* 0xf2fe */ { false, 0xf2fe, 0xf2fe }, +/* 0xf2ff */ { false, 0xf2ff, 0xf2ff }, +/* 0xf300 */ { false, 0xf300, 0xf300 }, +/* 0xf301 */ { false, 0xf301, 0xf301 }, +/* 0xf302 */ { false, 0xf302, 0xf302 }, +/* 0xf303 */ { false, 0xf303, 0xf303 }, +/* 0xf304 */ { false, 0xf304, 0xf304 }, +/* 0xf305 */ { false, 0xf305, 0xf305 }, +/* 0xf306 */ { false, 0xf306, 0xf306 }, +/* 0xf307 */ { false, 0xf307, 0xf307 }, +/* 0xf308 */ { false, 0xf308, 0xf308 }, +/* 0xf309 */ { false, 0xf309, 0xf309 }, +/* 0xf30a */ { false, 0xf30a, 0xf30a }, +/* 0xf30b */ { false, 0xf30b, 0xf30b }, +/* 0xf30c */ { false, 0xf30c, 0xf30c }, +/* 0xf30d */ { false, 0xf30d, 0xf30d }, +/* 0xf30e */ { false, 0xf30e, 0xf30e }, +/* 0xf30f */ { false, 0xf30f, 0xf30f }, +/* 0xf310 */ { false, 0xf310, 0xf310 }, +/* 0xf311 */ { false, 0xf311, 0xf311 }, +/* 0xf312 */ { false, 0xf312, 0xf312 }, +/* 0xf313 */ { false, 0xf313, 0xf313 }, +/* 0xf314 */ { false, 0xf314, 0xf314 }, +/* 0xf315 */ { false, 0xf315, 0xf315 }, +/* 0xf316 */ { false, 0xf316, 0xf316 }, +/* 0xf317 */ { false, 0xf317, 0xf317 }, +/* 0xf318 */ { false, 0xf318, 0xf318 }, +/* 0xf319 */ { false, 0xf319, 0xf319 }, +/* 0xf31a */ { false, 0xf31a, 0xf31a }, +/* 0xf31b */ { false, 0xf31b, 0xf31b }, +/* 0xf31c */ { false, 0xf31c, 0xf31c }, +/* 0xf31d */ { false, 0xf31d, 0xf31d }, +/* 0xf31e */ { false, 0xf31e, 0xf31e }, +/* 0xf31f */ { false, 0xf31f, 0xf31f }, +/* 0xf320 */ { false, 0xf320, 0xf320 }, +/* 0xf321 */ { false, 0xf321, 0xf321 }, +/* 0xf322 */ { false, 0xf322, 0xf322 }, +/* 0xf323 */ { false, 0xf323, 0xf323 }, +/* 0xf324 */ { false, 0xf324, 0xf324 }, +/* 0xf325 */ { false, 0xf325, 0xf325 }, +/* 0xf326 */ { false, 0xf326, 0xf326 }, +/* 0xf327 */ { false, 0xf327, 0xf327 }, +/* 0xf328 */ { false, 0xf328, 0xf328 }, +/* 0xf329 */ { false, 0xf329, 0xf329 }, +/* 0xf32a */ { false, 0xf32a, 0xf32a }, +/* 0xf32b */ { false, 0xf32b, 0xf32b }, +/* 0xf32c */ { false, 0xf32c, 0xf32c }, +/* 0xf32d */ { false, 0xf32d, 0xf32d }, +/* 0xf32e */ { false, 0xf32e, 0xf32e }, +/* 0xf32f */ { false, 0xf32f, 0xf32f }, +/* 0xf330 */ { false, 0xf330, 0xf330 }, +/* 0xf331 */ { false, 0xf331, 0xf331 }, +/* 0xf332 */ { false, 0xf332, 0xf332 }, +/* 0xf333 */ { false, 0xf333, 0xf333 }, +/* 0xf334 */ { false, 0xf334, 0xf334 }, +/* 0xf335 */ { false, 0xf335, 0xf335 }, +/* 0xf336 */ { false, 0xf336, 0xf336 }, +/* 0xf337 */ { false, 0xf337, 0xf337 }, +/* 0xf338 */ { false, 0xf338, 0xf338 }, +/* 0xf339 */ { false, 0xf339, 0xf339 }, +/* 0xf33a */ { false, 0xf33a, 0xf33a }, +/* 0xf33b */ { false, 0xf33b, 0xf33b }, +/* 0xf33c */ { false, 0xf33c, 0xf33c }, +/* 0xf33d */ { false, 0xf33d, 0xf33d }, +/* 0xf33e */ { false, 0xf33e, 0xf33e }, +/* 0xf33f */ { false, 0xf33f, 0xf33f }, +/* 0xf340 */ { false, 0xf340, 0xf340 }, +/* 0xf341 */ { false, 0xf341, 0xf341 }, +/* 0xf342 */ { false, 0xf342, 0xf342 }, +/* 0xf343 */ { false, 0xf343, 0xf343 }, +/* 0xf344 */ { false, 0xf344, 0xf344 }, +/* 0xf345 */ { false, 0xf345, 0xf345 }, +/* 0xf346 */ { false, 0xf346, 0xf346 }, +/* 0xf347 */ { false, 0xf347, 0xf347 }, +/* 0xf348 */ { false, 0xf348, 0xf348 }, +/* 0xf349 */ { false, 0xf349, 0xf349 }, +/* 0xf34a */ { false, 0xf34a, 0xf34a }, +/* 0xf34b */ { false, 0xf34b, 0xf34b }, +/* 0xf34c */ { false, 0xf34c, 0xf34c }, +/* 0xf34d */ { false, 0xf34d, 0xf34d }, +/* 0xf34e */ { false, 0xf34e, 0xf34e }, +/* 0xf34f */ { false, 0xf34f, 0xf34f }, +/* 0xf350 */ { false, 0xf350, 0xf350 }, +/* 0xf351 */ { false, 0xf351, 0xf351 }, +/* 0xf352 */ { false, 0xf352, 0xf352 }, +/* 0xf353 */ { false, 0xf353, 0xf353 }, +/* 0xf354 */ { false, 0xf354, 0xf354 }, +/* 0xf355 */ { false, 0xf355, 0xf355 }, +/* 0xf356 */ { false, 0xf356, 0xf356 }, +/* 0xf357 */ { false, 0xf357, 0xf357 }, +/* 0xf358 */ { false, 0xf358, 0xf358 }, +/* 0xf359 */ { false, 0xf359, 0xf359 }, +/* 0xf35a */ { false, 0xf35a, 0xf35a }, +/* 0xf35b */ { false, 0xf35b, 0xf35b }, +/* 0xf35c */ { false, 0xf35c, 0xf35c }, +/* 0xf35d */ { false, 0xf35d, 0xf35d }, +/* 0xf35e */ { false, 0xf35e, 0xf35e }, +/* 0xf35f */ { false, 0xf35f, 0xf35f }, +/* 0xf360 */ { false, 0xf360, 0xf360 }, +/* 0xf361 */ { false, 0xf361, 0xf361 }, +/* 0xf362 */ { false, 0xf362, 0xf362 }, +/* 0xf363 */ { false, 0xf363, 0xf363 }, +/* 0xf364 */ { false, 0xf364, 0xf364 }, +/* 0xf365 */ { false, 0xf365, 0xf365 }, +/* 0xf366 */ { false, 0xf366, 0xf366 }, +/* 0xf367 */ { false, 0xf367, 0xf367 }, +/* 0xf368 */ { false, 0xf368, 0xf368 }, +/* 0xf369 */ { false, 0xf369, 0xf369 }, +/* 0xf36a */ { false, 0xf36a, 0xf36a }, +/* 0xf36b */ { false, 0xf36b, 0xf36b }, +/* 0xf36c */ { false, 0xf36c, 0xf36c }, +/* 0xf36d */ { false, 0xf36d, 0xf36d }, +/* 0xf36e */ { false, 0xf36e, 0xf36e }, +/* 0xf36f */ { false, 0xf36f, 0xf36f }, +/* 0xf370 */ { false, 0xf370, 0xf370 }, +/* 0xf371 */ { false, 0xf371, 0xf371 }, +/* 0xf372 */ { false, 0xf372, 0xf372 }, +/* 0xf373 */ { false, 0xf373, 0xf373 }, +/* 0xf374 */ { false, 0xf374, 0xf374 }, +/* 0xf375 */ { false, 0xf375, 0xf375 }, +/* 0xf376 */ { false, 0xf376, 0xf376 }, +/* 0xf377 */ { false, 0xf377, 0xf377 }, +/* 0xf378 */ { false, 0xf378, 0xf378 }, +/* 0xf379 */ { false, 0xf379, 0xf379 }, +/* 0xf37a */ { false, 0xf37a, 0xf37a }, +/* 0xf37b */ { false, 0xf37b, 0xf37b }, +/* 0xf37c */ { false, 0xf37c, 0xf37c }, +/* 0xf37d */ { false, 0xf37d, 0xf37d }, +/* 0xf37e */ { false, 0xf37e, 0xf37e }, +/* 0xf37f */ { false, 0xf37f, 0xf37f }, +/* 0xf380 */ { false, 0xf380, 0xf380 }, +/* 0xf381 */ { false, 0xf381, 0xf381 }, +/* 0xf382 */ { false, 0xf382, 0xf382 }, +/* 0xf383 */ { false, 0xf383, 0xf383 }, +/* 0xf384 */ { false, 0xf384, 0xf384 }, +/* 0xf385 */ { false, 0xf385, 0xf385 }, +/* 0xf386 */ { false, 0xf386, 0xf386 }, +/* 0xf387 */ { false, 0xf387, 0xf387 }, +/* 0xf388 */ { false, 0xf388, 0xf388 }, +/* 0xf389 */ { false, 0xf389, 0xf389 }, +/* 0xf38a */ { false, 0xf38a, 0xf38a }, +/* 0xf38b */ { false, 0xf38b, 0xf38b }, +/* 0xf38c */ { false, 0xf38c, 0xf38c }, +/* 0xf38d */ { false, 0xf38d, 0xf38d }, +/* 0xf38e */ { false, 0xf38e, 0xf38e }, +/* 0xf38f */ { false, 0xf38f, 0xf38f }, +/* 0xf390 */ { false, 0xf390, 0xf390 }, +/* 0xf391 */ { false, 0xf391, 0xf391 }, +/* 0xf392 */ { false, 0xf392, 0xf392 }, +/* 0xf393 */ { false, 0xf393, 0xf393 }, +/* 0xf394 */ { false, 0xf394, 0xf394 }, +/* 0xf395 */ { false, 0xf395, 0xf395 }, +/* 0xf396 */ { false, 0xf396, 0xf396 }, +/* 0xf397 */ { false, 0xf397, 0xf397 }, +/* 0xf398 */ { false, 0xf398, 0xf398 }, +/* 0xf399 */ { false, 0xf399, 0xf399 }, +/* 0xf39a */ { false, 0xf39a, 0xf39a }, +/* 0xf39b */ { false, 0xf39b, 0xf39b }, +/* 0xf39c */ { false, 0xf39c, 0xf39c }, +/* 0xf39d */ { false, 0xf39d, 0xf39d }, +/* 0xf39e */ { false, 0xf39e, 0xf39e }, +/* 0xf39f */ { false, 0xf39f, 0xf39f }, +/* 0xf3a0 */ { false, 0xf3a0, 0xf3a0 }, +/* 0xf3a1 */ { false, 0xf3a1, 0xf3a1 }, +/* 0xf3a2 */ { false, 0xf3a2, 0xf3a2 }, +/* 0xf3a3 */ { false, 0xf3a3, 0xf3a3 }, +/* 0xf3a4 */ { false, 0xf3a4, 0xf3a4 }, +/* 0xf3a5 */ { false, 0xf3a5, 0xf3a5 }, +/* 0xf3a6 */ { false, 0xf3a6, 0xf3a6 }, +/* 0xf3a7 */ { false, 0xf3a7, 0xf3a7 }, +/* 0xf3a8 */ { false, 0xf3a8, 0xf3a8 }, +/* 0xf3a9 */ { false, 0xf3a9, 0xf3a9 }, +/* 0xf3aa */ { false, 0xf3aa, 0xf3aa }, +/* 0xf3ab */ { false, 0xf3ab, 0xf3ab }, +/* 0xf3ac */ { false, 0xf3ac, 0xf3ac }, +/* 0xf3ad */ { false, 0xf3ad, 0xf3ad }, +/* 0xf3ae */ { false, 0xf3ae, 0xf3ae }, +/* 0xf3af */ { false, 0xf3af, 0xf3af }, +/* 0xf3b0 */ { false, 0xf3b0, 0xf3b0 }, +/* 0xf3b1 */ { false, 0xf3b1, 0xf3b1 }, +/* 0xf3b2 */ { false, 0xf3b2, 0xf3b2 }, +/* 0xf3b3 */ { false, 0xf3b3, 0xf3b3 }, +/* 0xf3b4 */ { false, 0xf3b4, 0xf3b4 }, +/* 0xf3b5 */ { false, 0xf3b5, 0xf3b5 }, +/* 0xf3b6 */ { false, 0xf3b6, 0xf3b6 }, +/* 0xf3b7 */ { false, 0xf3b7, 0xf3b7 }, +/* 0xf3b8 */ { false, 0xf3b8, 0xf3b8 }, +/* 0xf3b9 */ { false, 0xf3b9, 0xf3b9 }, +/* 0xf3ba */ { false, 0xf3ba, 0xf3ba }, +/* 0xf3bb */ { false, 0xf3bb, 0xf3bb }, +/* 0xf3bc */ { false, 0xf3bc, 0xf3bc }, +/* 0xf3bd */ { false, 0xf3bd, 0xf3bd }, +/* 0xf3be */ { false, 0xf3be, 0xf3be }, +/* 0xf3bf */ { false, 0xf3bf, 0xf3bf }, +/* 0xf3c0 */ { false, 0xf3c0, 0xf3c0 }, +/* 0xf3c1 */ { false, 0xf3c1, 0xf3c1 }, +/* 0xf3c2 */ { false, 0xf3c2, 0xf3c2 }, +/* 0xf3c3 */ { false, 0xf3c3, 0xf3c3 }, +/* 0xf3c4 */ { false, 0xf3c4, 0xf3c4 }, +/* 0xf3c5 */ { false, 0xf3c5, 0xf3c5 }, +/* 0xf3c6 */ { false, 0xf3c6, 0xf3c6 }, +/* 0xf3c7 */ { false, 0xf3c7, 0xf3c7 }, +/* 0xf3c8 */ { false, 0xf3c8, 0xf3c8 }, +/* 0xf3c9 */ { false, 0xf3c9, 0xf3c9 }, +/* 0xf3ca */ { false, 0xf3ca, 0xf3ca }, +/* 0xf3cb */ { false, 0xf3cb, 0xf3cb }, +/* 0xf3cc */ { false, 0xf3cc, 0xf3cc }, +/* 0xf3cd */ { false, 0xf3cd, 0xf3cd }, +/* 0xf3ce */ { false, 0xf3ce, 0xf3ce }, +/* 0xf3cf */ { false, 0xf3cf, 0xf3cf }, +/* 0xf3d0 */ { false, 0xf3d0, 0xf3d0 }, +/* 0xf3d1 */ { false, 0xf3d1, 0xf3d1 }, +/* 0xf3d2 */ { false, 0xf3d2, 0xf3d2 }, +/* 0xf3d3 */ { false, 0xf3d3, 0xf3d3 }, +/* 0xf3d4 */ { false, 0xf3d4, 0xf3d4 }, +/* 0xf3d5 */ { false, 0xf3d5, 0xf3d5 }, +/* 0xf3d6 */ { false, 0xf3d6, 0xf3d6 }, +/* 0xf3d7 */ { false, 0xf3d7, 0xf3d7 }, +/* 0xf3d8 */ { false, 0xf3d8, 0xf3d8 }, +/* 0xf3d9 */ { false, 0xf3d9, 0xf3d9 }, +/* 0xf3da */ { false, 0xf3da, 0xf3da }, +/* 0xf3db */ { false, 0xf3db, 0xf3db }, +/* 0xf3dc */ { false, 0xf3dc, 0xf3dc }, +/* 0xf3dd */ { false, 0xf3dd, 0xf3dd }, +/* 0xf3de */ { false, 0xf3de, 0xf3de }, +/* 0xf3df */ { false, 0xf3df, 0xf3df }, +/* 0xf3e0 */ { false, 0xf3e0, 0xf3e0 }, +/* 0xf3e1 */ { false, 0xf3e1, 0xf3e1 }, +/* 0xf3e2 */ { false, 0xf3e2, 0xf3e2 }, +/* 0xf3e3 */ { false, 0xf3e3, 0xf3e3 }, +/* 0xf3e4 */ { false, 0xf3e4, 0xf3e4 }, +/* 0xf3e5 */ { false, 0xf3e5, 0xf3e5 }, +/* 0xf3e6 */ { false, 0xf3e6, 0xf3e6 }, +/* 0xf3e7 */ { false, 0xf3e7, 0xf3e7 }, +/* 0xf3e8 */ { false, 0xf3e8, 0xf3e8 }, +/* 0xf3e9 */ { false, 0xf3e9, 0xf3e9 }, +/* 0xf3ea */ { false, 0xf3ea, 0xf3ea }, +/* 0xf3eb */ { false, 0xf3eb, 0xf3eb }, +/* 0xf3ec */ { false, 0xf3ec, 0xf3ec }, +/* 0xf3ed */ { false, 0xf3ed, 0xf3ed }, +/* 0xf3ee */ { false, 0xf3ee, 0xf3ee }, +/* 0xf3ef */ { false, 0xf3ef, 0xf3ef }, +/* 0xf3f0 */ { false, 0xf3f0, 0xf3f0 }, +/* 0xf3f1 */ { false, 0xf3f1, 0xf3f1 }, +/* 0xf3f2 */ { false, 0xf3f2, 0xf3f2 }, +/* 0xf3f3 */ { false, 0xf3f3, 0xf3f3 }, +/* 0xf3f4 */ { false, 0xf3f4, 0xf3f4 }, +/* 0xf3f5 */ { false, 0xf3f5, 0xf3f5 }, +/* 0xf3f6 */ { false, 0xf3f6, 0xf3f6 }, +/* 0xf3f7 */ { false, 0xf3f7, 0xf3f7 }, +/* 0xf3f8 */ { false, 0xf3f8, 0xf3f8 }, +/* 0xf3f9 */ { false, 0xf3f9, 0xf3f9 }, +/* 0xf3fa */ { false, 0xf3fa, 0xf3fa }, +/* 0xf3fb */ { false, 0xf3fb, 0xf3fb }, +/* 0xf3fc */ { false, 0xf3fc, 0xf3fc }, +/* 0xf3fd */ { false, 0xf3fd, 0xf3fd }, +/* 0xf3fe */ { false, 0xf3fe, 0xf3fe }, +/* 0xf3ff */ { false, 0xf3ff, 0xf3ff }, +/* 0xf400 */ { false, 0xf400, 0xf400 }, +/* 0xf401 */ { false, 0xf401, 0xf401 }, +/* 0xf402 */ { false, 0xf402, 0xf402 }, +/* 0xf403 */ { false, 0xf403, 0xf403 }, +/* 0xf404 */ { false, 0xf404, 0xf404 }, +/* 0xf405 */ { false, 0xf405, 0xf405 }, +/* 0xf406 */ { false, 0xf406, 0xf406 }, +/* 0xf407 */ { false, 0xf407, 0xf407 }, +/* 0xf408 */ { false, 0xf408, 0xf408 }, +/* 0xf409 */ { false, 0xf409, 0xf409 }, +/* 0xf40a */ { false, 0xf40a, 0xf40a }, +/* 0xf40b */ { false, 0xf40b, 0xf40b }, +/* 0xf40c */ { false, 0xf40c, 0xf40c }, +/* 0xf40d */ { false, 0xf40d, 0xf40d }, +/* 0xf40e */ { false, 0xf40e, 0xf40e }, +/* 0xf40f */ { false, 0xf40f, 0xf40f }, +/* 0xf410 */ { false, 0xf410, 0xf410 }, +/* 0xf411 */ { false, 0xf411, 0xf411 }, +/* 0xf412 */ { false, 0xf412, 0xf412 }, +/* 0xf413 */ { false, 0xf413, 0xf413 }, +/* 0xf414 */ { false, 0xf414, 0xf414 }, +/* 0xf415 */ { false, 0xf415, 0xf415 }, +/* 0xf416 */ { false, 0xf416, 0xf416 }, +/* 0xf417 */ { false, 0xf417, 0xf417 }, +/* 0xf418 */ { false, 0xf418, 0xf418 }, +/* 0xf419 */ { false, 0xf419, 0xf419 }, +/* 0xf41a */ { false, 0xf41a, 0xf41a }, +/* 0xf41b */ { false, 0xf41b, 0xf41b }, +/* 0xf41c */ { false, 0xf41c, 0xf41c }, +/* 0xf41d */ { false, 0xf41d, 0xf41d }, +/* 0xf41e */ { false, 0xf41e, 0xf41e }, +/* 0xf41f */ { false, 0xf41f, 0xf41f }, +/* 0xf420 */ { false, 0xf420, 0xf420 }, +/* 0xf421 */ { false, 0xf421, 0xf421 }, +/* 0xf422 */ { false, 0xf422, 0xf422 }, +/* 0xf423 */ { false, 0xf423, 0xf423 }, +/* 0xf424 */ { false, 0xf424, 0xf424 }, +/* 0xf425 */ { false, 0xf425, 0xf425 }, +/* 0xf426 */ { false, 0xf426, 0xf426 }, +/* 0xf427 */ { false, 0xf427, 0xf427 }, +/* 0xf428 */ { false, 0xf428, 0xf428 }, +/* 0xf429 */ { false, 0xf429, 0xf429 }, +/* 0xf42a */ { false, 0xf42a, 0xf42a }, +/* 0xf42b */ { false, 0xf42b, 0xf42b }, +/* 0xf42c */ { false, 0xf42c, 0xf42c }, +/* 0xf42d */ { false, 0xf42d, 0xf42d }, +/* 0xf42e */ { false, 0xf42e, 0xf42e }, +/* 0xf42f */ { false, 0xf42f, 0xf42f }, +/* 0xf430 */ { false, 0xf430, 0xf430 }, +/* 0xf431 */ { false, 0xf431, 0xf431 }, +/* 0xf432 */ { false, 0xf432, 0xf432 }, +/* 0xf433 */ { false, 0xf433, 0xf433 }, +/* 0xf434 */ { false, 0xf434, 0xf434 }, +/* 0xf435 */ { false, 0xf435, 0xf435 }, +/* 0xf436 */ { false, 0xf436, 0xf436 }, +/* 0xf437 */ { false, 0xf437, 0xf437 }, +/* 0xf438 */ { false, 0xf438, 0xf438 }, +/* 0xf439 */ { false, 0xf439, 0xf439 }, +/* 0xf43a */ { false, 0xf43a, 0xf43a }, +/* 0xf43b */ { false, 0xf43b, 0xf43b }, +/* 0xf43c */ { false, 0xf43c, 0xf43c }, +/* 0xf43d */ { false, 0xf43d, 0xf43d }, +/* 0xf43e */ { false, 0xf43e, 0xf43e }, +/* 0xf43f */ { false, 0xf43f, 0xf43f }, +/* 0xf440 */ { false, 0xf440, 0xf440 }, +/* 0xf441 */ { false, 0xf441, 0xf441 }, +/* 0xf442 */ { false, 0xf442, 0xf442 }, +/* 0xf443 */ { false, 0xf443, 0xf443 }, +/* 0xf444 */ { false, 0xf444, 0xf444 }, +/* 0xf445 */ { false, 0xf445, 0xf445 }, +/* 0xf446 */ { false, 0xf446, 0xf446 }, +/* 0xf447 */ { false, 0xf447, 0xf447 }, +/* 0xf448 */ { false, 0xf448, 0xf448 }, +/* 0xf449 */ { false, 0xf449, 0xf449 }, +/* 0xf44a */ { false, 0xf44a, 0xf44a }, +/* 0xf44b */ { false, 0xf44b, 0xf44b }, +/* 0xf44c */ { false, 0xf44c, 0xf44c }, +/* 0xf44d */ { false, 0xf44d, 0xf44d }, +/* 0xf44e */ { false, 0xf44e, 0xf44e }, +/* 0xf44f */ { false, 0xf44f, 0xf44f }, +/* 0xf450 */ { false, 0xf450, 0xf450 }, +/* 0xf451 */ { false, 0xf451, 0xf451 }, +/* 0xf452 */ { false, 0xf452, 0xf452 }, +/* 0xf453 */ { false, 0xf453, 0xf453 }, +/* 0xf454 */ { false, 0xf454, 0xf454 }, +/* 0xf455 */ { false, 0xf455, 0xf455 }, +/* 0xf456 */ { false, 0xf456, 0xf456 }, +/* 0xf457 */ { false, 0xf457, 0xf457 }, +/* 0xf458 */ { false, 0xf458, 0xf458 }, +/* 0xf459 */ { false, 0xf459, 0xf459 }, +/* 0xf45a */ { false, 0xf45a, 0xf45a }, +/* 0xf45b */ { false, 0xf45b, 0xf45b }, +/* 0xf45c */ { false, 0xf45c, 0xf45c }, +/* 0xf45d */ { false, 0xf45d, 0xf45d }, +/* 0xf45e */ { false, 0xf45e, 0xf45e }, +/* 0xf45f */ { false, 0xf45f, 0xf45f }, +/* 0xf460 */ { false, 0xf460, 0xf460 }, +/* 0xf461 */ { false, 0xf461, 0xf461 }, +/* 0xf462 */ { false, 0xf462, 0xf462 }, +/* 0xf463 */ { false, 0xf463, 0xf463 }, +/* 0xf464 */ { false, 0xf464, 0xf464 }, +/* 0xf465 */ { false, 0xf465, 0xf465 }, +/* 0xf466 */ { false, 0xf466, 0xf466 }, +/* 0xf467 */ { false, 0xf467, 0xf467 }, +/* 0xf468 */ { false, 0xf468, 0xf468 }, +/* 0xf469 */ { false, 0xf469, 0xf469 }, +/* 0xf46a */ { false, 0xf46a, 0xf46a }, +/* 0xf46b */ { false, 0xf46b, 0xf46b }, +/* 0xf46c */ { false, 0xf46c, 0xf46c }, +/* 0xf46d */ { false, 0xf46d, 0xf46d }, +/* 0xf46e */ { false, 0xf46e, 0xf46e }, +/* 0xf46f */ { false, 0xf46f, 0xf46f }, +/* 0xf470 */ { false, 0xf470, 0xf470 }, +/* 0xf471 */ { false, 0xf471, 0xf471 }, +/* 0xf472 */ { false, 0xf472, 0xf472 }, +/* 0xf473 */ { false, 0xf473, 0xf473 }, +/* 0xf474 */ { false, 0xf474, 0xf474 }, +/* 0xf475 */ { false, 0xf475, 0xf475 }, +/* 0xf476 */ { false, 0xf476, 0xf476 }, +/* 0xf477 */ { false, 0xf477, 0xf477 }, +/* 0xf478 */ { false, 0xf478, 0xf478 }, +/* 0xf479 */ { false, 0xf479, 0xf479 }, +/* 0xf47a */ { false, 0xf47a, 0xf47a }, +/* 0xf47b */ { false, 0xf47b, 0xf47b }, +/* 0xf47c */ { false, 0xf47c, 0xf47c }, +/* 0xf47d */ { false, 0xf47d, 0xf47d }, +/* 0xf47e */ { false, 0xf47e, 0xf47e }, +/* 0xf47f */ { false, 0xf47f, 0xf47f }, +/* 0xf480 */ { false, 0xf480, 0xf480 }, +/* 0xf481 */ { false, 0xf481, 0xf481 }, +/* 0xf482 */ { false, 0xf482, 0xf482 }, +/* 0xf483 */ { false, 0xf483, 0xf483 }, +/* 0xf484 */ { false, 0xf484, 0xf484 }, +/* 0xf485 */ { false, 0xf485, 0xf485 }, +/* 0xf486 */ { false, 0xf486, 0xf486 }, +/* 0xf487 */ { false, 0xf487, 0xf487 }, +/* 0xf488 */ { false, 0xf488, 0xf488 }, +/* 0xf489 */ { false, 0xf489, 0xf489 }, +/* 0xf48a */ { false, 0xf48a, 0xf48a }, +/* 0xf48b */ { false, 0xf48b, 0xf48b }, +/* 0xf48c */ { false, 0xf48c, 0xf48c }, +/* 0xf48d */ { false, 0xf48d, 0xf48d }, +/* 0xf48e */ { false, 0xf48e, 0xf48e }, +/* 0xf48f */ { false, 0xf48f, 0xf48f }, +/* 0xf490 */ { false, 0xf490, 0xf490 }, +/* 0xf491 */ { false, 0xf491, 0xf491 }, +/* 0xf492 */ { false, 0xf492, 0xf492 }, +/* 0xf493 */ { false, 0xf493, 0xf493 }, +/* 0xf494 */ { false, 0xf494, 0xf494 }, +/* 0xf495 */ { false, 0xf495, 0xf495 }, +/* 0xf496 */ { false, 0xf496, 0xf496 }, +/* 0xf497 */ { false, 0xf497, 0xf497 }, +/* 0xf498 */ { false, 0xf498, 0xf498 }, +/* 0xf499 */ { false, 0xf499, 0xf499 }, +/* 0xf49a */ { false, 0xf49a, 0xf49a }, +/* 0xf49b */ { false, 0xf49b, 0xf49b }, +/* 0xf49c */ { false, 0xf49c, 0xf49c }, +/* 0xf49d */ { false, 0xf49d, 0xf49d }, +/* 0xf49e */ { false, 0xf49e, 0xf49e }, +/* 0xf49f */ { false, 0xf49f, 0xf49f }, +/* 0xf4a0 */ { false, 0xf4a0, 0xf4a0 }, +/* 0xf4a1 */ { false, 0xf4a1, 0xf4a1 }, +/* 0xf4a2 */ { false, 0xf4a2, 0xf4a2 }, +/* 0xf4a3 */ { false, 0xf4a3, 0xf4a3 }, +/* 0xf4a4 */ { false, 0xf4a4, 0xf4a4 }, +/* 0xf4a5 */ { false, 0xf4a5, 0xf4a5 }, +/* 0xf4a6 */ { false, 0xf4a6, 0xf4a6 }, +/* 0xf4a7 */ { false, 0xf4a7, 0xf4a7 }, +/* 0xf4a8 */ { false, 0xf4a8, 0xf4a8 }, +/* 0xf4a9 */ { false, 0xf4a9, 0xf4a9 }, +/* 0xf4aa */ { false, 0xf4aa, 0xf4aa }, +/* 0xf4ab */ { false, 0xf4ab, 0xf4ab }, +/* 0xf4ac */ { false, 0xf4ac, 0xf4ac }, +/* 0xf4ad */ { false, 0xf4ad, 0xf4ad }, +/* 0xf4ae */ { false, 0xf4ae, 0xf4ae }, +/* 0xf4af */ { false, 0xf4af, 0xf4af }, +/* 0xf4b0 */ { false, 0xf4b0, 0xf4b0 }, +/* 0xf4b1 */ { false, 0xf4b1, 0xf4b1 }, +/* 0xf4b2 */ { false, 0xf4b2, 0xf4b2 }, +/* 0xf4b3 */ { false, 0xf4b3, 0xf4b3 }, +/* 0xf4b4 */ { false, 0xf4b4, 0xf4b4 }, +/* 0xf4b5 */ { false, 0xf4b5, 0xf4b5 }, +/* 0xf4b6 */ { false, 0xf4b6, 0xf4b6 }, +/* 0xf4b7 */ { false, 0xf4b7, 0xf4b7 }, +/* 0xf4b8 */ { false, 0xf4b8, 0xf4b8 }, +/* 0xf4b9 */ { false, 0xf4b9, 0xf4b9 }, +/* 0xf4ba */ { false, 0xf4ba, 0xf4ba }, +/* 0xf4bb */ { false, 0xf4bb, 0xf4bb }, +/* 0xf4bc */ { false, 0xf4bc, 0xf4bc }, +/* 0xf4bd */ { false, 0xf4bd, 0xf4bd }, +/* 0xf4be */ { false, 0xf4be, 0xf4be }, +/* 0xf4bf */ { false, 0xf4bf, 0xf4bf }, +/* 0xf4c0 */ { false, 0xf4c0, 0xf4c0 }, +/* 0xf4c1 */ { false, 0xf4c1, 0xf4c1 }, +/* 0xf4c2 */ { false, 0xf4c2, 0xf4c2 }, +/* 0xf4c3 */ { false, 0xf4c3, 0xf4c3 }, +/* 0xf4c4 */ { false, 0xf4c4, 0xf4c4 }, +/* 0xf4c5 */ { false, 0xf4c5, 0xf4c5 }, +/* 0xf4c6 */ { false, 0xf4c6, 0xf4c6 }, +/* 0xf4c7 */ { false, 0xf4c7, 0xf4c7 }, +/* 0xf4c8 */ { false, 0xf4c8, 0xf4c8 }, +/* 0xf4c9 */ { false, 0xf4c9, 0xf4c9 }, +/* 0xf4ca */ { false, 0xf4ca, 0xf4ca }, +/* 0xf4cb */ { false, 0xf4cb, 0xf4cb }, +/* 0xf4cc */ { false, 0xf4cc, 0xf4cc }, +/* 0xf4cd */ { false, 0xf4cd, 0xf4cd }, +/* 0xf4ce */ { false, 0xf4ce, 0xf4ce }, +/* 0xf4cf */ { false, 0xf4cf, 0xf4cf }, +/* 0xf4d0 */ { false, 0xf4d0, 0xf4d0 }, +/* 0xf4d1 */ { false, 0xf4d1, 0xf4d1 }, +/* 0xf4d2 */ { false, 0xf4d2, 0xf4d2 }, +/* 0xf4d3 */ { false, 0xf4d3, 0xf4d3 }, +/* 0xf4d4 */ { false, 0xf4d4, 0xf4d4 }, +/* 0xf4d5 */ { false, 0xf4d5, 0xf4d5 }, +/* 0xf4d6 */ { false, 0xf4d6, 0xf4d6 }, +/* 0xf4d7 */ { false, 0xf4d7, 0xf4d7 }, +/* 0xf4d8 */ { false, 0xf4d8, 0xf4d8 }, +/* 0xf4d9 */ { false, 0xf4d9, 0xf4d9 }, +/* 0xf4da */ { false, 0xf4da, 0xf4da }, +/* 0xf4db */ { false, 0xf4db, 0xf4db }, +/* 0xf4dc */ { false, 0xf4dc, 0xf4dc }, +/* 0xf4dd */ { false, 0xf4dd, 0xf4dd }, +/* 0xf4de */ { false, 0xf4de, 0xf4de }, +/* 0xf4df */ { false, 0xf4df, 0xf4df }, +/* 0xf4e0 */ { false, 0xf4e0, 0xf4e0 }, +/* 0xf4e1 */ { false, 0xf4e1, 0xf4e1 }, +/* 0xf4e2 */ { false, 0xf4e2, 0xf4e2 }, +/* 0xf4e3 */ { false, 0xf4e3, 0xf4e3 }, +/* 0xf4e4 */ { false, 0xf4e4, 0xf4e4 }, +/* 0xf4e5 */ { false, 0xf4e5, 0xf4e5 }, +/* 0xf4e6 */ { false, 0xf4e6, 0xf4e6 }, +/* 0xf4e7 */ { false, 0xf4e7, 0xf4e7 }, +/* 0xf4e8 */ { false, 0xf4e8, 0xf4e8 }, +/* 0xf4e9 */ { false, 0xf4e9, 0xf4e9 }, +/* 0xf4ea */ { false, 0xf4ea, 0xf4ea }, +/* 0xf4eb */ { false, 0xf4eb, 0xf4eb }, +/* 0xf4ec */ { false, 0xf4ec, 0xf4ec }, +/* 0xf4ed */ { false, 0xf4ed, 0xf4ed }, +/* 0xf4ee */ { false, 0xf4ee, 0xf4ee }, +/* 0xf4ef */ { false, 0xf4ef, 0xf4ef }, +/* 0xf4f0 */ { false, 0xf4f0, 0xf4f0 }, +/* 0xf4f1 */ { false, 0xf4f1, 0xf4f1 }, +/* 0xf4f2 */ { false, 0xf4f2, 0xf4f2 }, +/* 0xf4f3 */ { false, 0xf4f3, 0xf4f3 }, +/* 0xf4f4 */ { false, 0xf4f4, 0xf4f4 }, +/* 0xf4f5 */ { false, 0xf4f5, 0xf4f5 }, +/* 0xf4f6 */ { false, 0xf4f6, 0xf4f6 }, +/* 0xf4f7 */ { false, 0xf4f7, 0xf4f7 }, +/* 0xf4f8 */ { false, 0xf4f8, 0xf4f8 }, +/* 0xf4f9 */ { false, 0xf4f9, 0xf4f9 }, +/* 0xf4fa */ { false, 0xf4fa, 0xf4fa }, +/* 0xf4fb */ { false, 0xf4fb, 0xf4fb }, +/* 0xf4fc */ { false, 0xf4fc, 0xf4fc }, +/* 0xf4fd */ { false, 0xf4fd, 0xf4fd }, +/* 0xf4fe */ { false, 0xf4fe, 0xf4fe }, +/* 0xf4ff */ { false, 0xf4ff, 0xf4ff }, +/* 0xf500 */ { false, 0xf500, 0xf500 }, +/* 0xf501 */ { false, 0xf501, 0xf501 }, +/* 0xf502 */ { false, 0xf502, 0xf502 }, +/* 0xf503 */ { false, 0xf503, 0xf503 }, +/* 0xf504 */ { false, 0xf504, 0xf504 }, +/* 0xf505 */ { false, 0xf505, 0xf505 }, +/* 0xf506 */ { false, 0xf506, 0xf506 }, +/* 0xf507 */ { false, 0xf507, 0xf507 }, +/* 0xf508 */ { false, 0xf508, 0xf508 }, +/* 0xf509 */ { false, 0xf509, 0xf509 }, +/* 0xf50a */ { false, 0xf50a, 0xf50a }, +/* 0xf50b */ { false, 0xf50b, 0xf50b }, +/* 0xf50c */ { false, 0xf50c, 0xf50c }, +/* 0xf50d */ { false, 0xf50d, 0xf50d }, +/* 0xf50e */ { false, 0xf50e, 0xf50e }, +/* 0xf50f */ { false, 0xf50f, 0xf50f }, +/* 0xf510 */ { false, 0xf510, 0xf510 }, +/* 0xf511 */ { false, 0xf511, 0xf511 }, +/* 0xf512 */ { false, 0xf512, 0xf512 }, +/* 0xf513 */ { false, 0xf513, 0xf513 }, +/* 0xf514 */ { false, 0xf514, 0xf514 }, +/* 0xf515 */ { false, 0xf515, 0xf515 }, +/* 0xf516 */ { false, 0xf516, 0xf516 }, +/* 0xf517 */ { false, 0xf517, 0xf517 }, +/* 0xf518 */ { false, 0xf518, 0xf518 }, +/* 0xf519 */ { false, 0xf519, 0xf519 }, +/* 0xf51a */ { false, 0xf51a, 0xf51a }, +/* 0xf51b */ { false, 0xf51b, 0xf51b }, +/* 0xf51c */ { false, 0xf51c, 0xf51c }, +/* 0xf51d */ { false, 0xf51d, 0xf51d }, +/* 0xf51e */ { false, 0xf51e, 0xf51e }, +/* 0xf51f */ { false, 0xf51f, 0xf51f }, +/* 0xf520 */ { false, 0xf520, 0xf520 }, +/* 0xf521 */ { false, 0xf521, 0xf521 }, +/* 0xf522 */ { false, 0xf522, 0xf522 }, +/* 0xf523 */ { false, 0xf523, 0xf523 }, +/* 0xf524 */ { false, 0xf524, 0xf524 }, +/* 0xf525 */ { false, 0xf525, 0xf525 }, +/* 0xf526 */ { false, 0xf526, 0xf526 }, +/* 0xf527 */ { false, 0xf527, 0xf527 }, +/* 0xf528 */ { false, 0xf528, 0xf528 }, +/* 0xf529 */ { false, 0xf529, 0xf529 }, +/* 0xf52a */ { false, 0xf52a, 0xf52a }, +/* 0xf52b */ { false, 0xf52b, 0xf52b }, +/* 0xf52c */ { false, 0xf52c, 0xf52c }, +/* 0xf52d */ { false, 0xf52d, 0xf52d }, +/* 0xf52e */ { false, 0xf52e, 0xf52e }, +/* 0xf52f */ { false, 0xf52f, 0xf52f }, +/* 0xf530 */ { false, 0xf530, 0xf530 }, +/* 0xf531 */ { false, 0xf531, 0xf531 }, +/* 0xf532 */ { false, 0xf532, 0xf532 }, +/* 0xf533 */ { false, 0xf533, 0xf533 }, +/* 0xf534 */ { false, 0xf534, 0xf534 }, +/* 0xf535 */ { false, 0xf535, 0xf535 }, +/* 0xf536 */ { false, 0xf536, 0xf536 }, +/* 0xf537 */ { false, 0xf537, 0xf537 }, +/* 0xf538 */ { false, 0xf538, 0xf538 }, +/* 0xf539 */ { false, 0xf539, 0xf539 }, +/* 0xf53a */ { false, 0xf53a, 0xf53a }, +/* 0xf53b */ { false, 0xf53b, 0xf53b }, +/* 0xf53c */ { false, 0xf53c, 0xf53c }, +/* 0xf53d */ { false, 0xf53d, 0xf53d }, +/* 0xf53e */ { false, 0xf53e, 0xf53e }, +/* 0xf53f */ { false, 0xf53f, 0xf53f }, +/* 0xf540 */ { false, 0xf540, 0xf540 }, +/* 0xf541 */ { false, 0xf541, 0xf541 }, +/* 0xf542 */ { false, 0xf542, 0xf542 }, +/* 0xf543 */ { false, 0xf543, 0xf543 }, +/* 0xf544 */ { false, 0xf544, 0xf544 }, +/* 0xf545 */ { false, 0xf545, 0xf545 }, +/* 0xf546 */ { false, 0xf546, 0xf546 }, +/* 0xf547 */ { false, 0xf547, 0xf547 }, +/* 0xf548 */ { false, 0xf548, 0xf548 }, +/* 0xf549 */ { false, 0xf549, 0xf549 }, +/* 0xf54a */ { false, 0xf54a, 0xf54a }, +/* 0xf54b */ { false, 0xf54b, 0xf54b }, +/* 0xf54c */ { false, 0xf54c, 0xf54c }, +/* 0xf54d */ { false, 0xf54d, 0xf54d }, +/* 0xf54e */ { false, 0xf54e, 0xf54e }, +/* 0xf54f */ { false, 0xf54f, 0xf54f }, +/* 0xf550 */ { false, 0xf550, 0xf550 }, +/* 0xf551 */ { false, 0xf551, 0xf551 }, +/* 0xf552 */ { false, 0xf552, 0xf552 }, +/* 0xf553 */ { false, 0xf553, 0xf553 }, +/* 0xf554 */ { false, 0xf554, 0xf554 }, +/* 0xf555 */ { false, 0xf555, 0xf555 }, +/* 0xf556 */ { false, 0xf556, 0xf556 }, +/* 0xf557 */ { false, 0xf557, 0xf557 }, +/* 0xf558 */ { false, 0xf558, 0xf558 }, +/* 0xf559 */ { false, 0xf559, 0xf559 }, +/* 0xf55a */ { false, 0xf55a, 0xf55a }, +/* 0xf55b */ { false, 0xf55b, 0xf55b }, +/* 0xf55c */ { false, 0xf55c, 0xf55c }, +/* 0xf55d */ { false, 0xf55d, 0xf55d }, +/* 0xf55e */ { false, 0xf55e, 0xf55e }, +/* 0xf55f */ { false, 0xf55f, 0xf55f }, +/* 0xf560 */ { false, 0xf560, 0xf560 }, +/* 0xf561 */ { false, 0xf561, 0xf561 }, +/* 0xf562 */ { false, 0xf562, 0xf562 }, +/* 0xf563 */ { false, 0xf563, 0xf563 }, +/* 0xf564 */ { false, 0xf564, 0xf564 }, +/* 0xf565 */ { false, 0xf565, 0xf565 }, +/* 0xf566 */ { false, 0xf566, 0xf566 }, +/* 0xf567 */ { false, 0xf567, 0xf567 }, +/* 0xf568 */ { false, 0xf568, 0xf568 }, +/* 0xf569 */ { false, 0xf569, 0xf569 }, +/* 0xf56a */ { false, 0xf56a, 0xf56a }, +/* 0xf56b */ { false, 0xf56b, 0xf56b }, +/* 0xf56c */ { false, 0xf56c, 0xf56c }, +/* 0xf56d */ { false, 0xf56d, 0xf56d }, +/* 0xf56e */ { false, 0xf56e, 0xf56e }, +/* 0xf56f */ { false, 0xf56f, 0xf56f }, +/* 0xf570 */ { false, 0xf570, 0xf570 }, +/* 0xf571 */ { false, 0xf571, 0xf571 }, +/* 0xf572 */ { false, 0xf572, 0xf572 }, +/* 0xf573 */ { false, 0xf573, 0xf573 }, +/* 0xf574 */ { false, 0xf574, 0xf574 }, +/* 0xf575 */ { false, 0xf575, 0xf575 }, +/* 0xf576 */ { false, 0xf576, 0xf576 }, +/* 0xf577 */ { false, 0xf577, 0xf577 }, +/* 0xf578 */ { false, 0xf578, 0xf578 }, +/* 0xf579 */ { false, 0xf579, 0xf579 }, +/* 0xf57a */ { false, 0xf57a, 0xf57a }, +/* 0xf57b */ { false, 0xf57b, 0xf57b }, +/* 0xf57c */ { false, 0xf57c, 0xf57c }, +/* 0xf57d */ { false, 0xf57d, 0xf57d }, +/* 0xf57e */ { false, 0xf57e, 0xf57e }, +/* 0xf57f */ { false, 0xf57f, 0xf57f }, +/* 0xf580 */ { false, 0xf580, 0xf580 }, +/* 0xf581 */ { false, 0xf581, 0xf581 }, +/* 0xf582 */ { false, 0xf582, 0xf582 }, +/* 0xf583 */ { false, 0xf583, 0xf583 }, +/* 0xf584 */ { false, 0xf584, 0xf584 }, +/* 0xf585 */ { false, 0xf585, 0xf585 }, +/* 0xf586 */ { false, 0xf586, 0xf586 }, +/* 0xf587 */ { false, 0xf587, 0xf587 }, +/* 0xf588 */ { false, 0xf588, 0xf588 }, +/* 0xf589 */ { false, 0xf589, 0xf589 }, +/* 0xf58a */ { false, 0xf58a, 0xf58a }, +/* 0xf58b */ { false, 0xf58b, 0xf58b }, +/* 0xf58c */ { false, 0xf58c, 0xf58c }, +/* 0xf58d */ { false, 0xf58d, 0xf58d }, +/* 0xf58e */ { false, 0xf58e, 0xf58e }, +/* 0xf58f */ { false, 0xf58f, 0xf58f }, +/* 0xf590 */ { false, 0xf590, 0xf590 }, +/* 0xf591 */ { false, 0xf591, 0xf591 }, +/* 0xf592 */ { false, 0xf592, 0xf592 }, +/* 0xf593 */ { false, 0xf593, 0xf593 }, +/* 0xf594 */ { false, 0xf594, 0xf594 }, +/* 0xf595 */ { false, 0xf595, 0xf595 }, +/* 0xf596 */ { false, 0xf596, 0xf596 }, +/* 0xf597 */ { false, 0xf597, 0xf597 }, +/* 0xf598 */ { false, 0xf598, 0xf598 }, +/* 0xf599 */ { false, 0xf599, 0xf599 }, +/* 0xf59a */ { false, 0xf59a, 0xf59a }, +/* 0xf59b */ { false, 0xf59b, 0xf59b }, +/* 0xf59c */ { false, 0xf59c, 0xf59c }, +/* 0xf59d */ { false, 0xf59d, 0xf59d }, +/* 0xf59e */ { false, 0xf59e, 0xf59e }, +/* 0xf59f */ { false, 0xf59f, 0xf59f }, +/* 0xf5a0 */ { false, 0xf5a0, 0xf5a0 }, +/* 0xf5a1 */ { false, 0xf5a1, 0xf5a1 }, +/* 0xf5a2 */ { false, 0xf5a2, 0xf5a2 }, +/* 0xf5a3 */ { false, 0xf5a3, 0xf5a3 }, +/* 0xf5a4 */ { false, 0xf5a4, 0xf5a4 }, +/* 0xf5a5 */ { false, 0xf5a5, 0xf5a5 }, +/* 0xf5a6 */ { false, 0xf5a6, 0xf5a6 }, +/* 0xf5a7 */ { false, 0xf5a7, 0xf5a7 }, +/* 0xf5a8 */ { false, 0xf5a8, 0xf5a8 }, +/* 0xf5a9 */ { false, 0xf5a9, 0xf5a9 }, +/* 0xf5aa */ { false, 0xf5aa, 0xf5aa }, +/* 0xf5ab */ { false, 0xf5ab, 0xf5ab }, +/* 0xf5ac */ { false, 0xf5ac, 0xf5ac }, +/* 0xf5ad */ { false, 0xf5ad, 0xf5ad }, +/* 0xf5ae */ { false, 0xf5ae, 0xf5ae }, +/* 0xf5af */ { false, 0xf5af, 0xf5af }, +/* 0xf5b0 */ { false, 0xf5b0, 0xf5b0 }, +/* 0xf5b1 */ { false, 0xf5b1, 0xf5b1 }, +/* 0xf5b2 */ { false, 0xf5b2, 0xf5b2 }, +/* 0xf5b3 */ { false, 0xf5b3, 0xf5b3 }, +/* 0xf5b4 */ { false, 0xf5b4, 0xf5b4 }, +/* 0xf5b5 */ { false, 0xf5b5, 0xf5b5 }, +/* 0xf5b6 */ { false, 0xf5b6, 0xf5b6 }, +/* 0xf5b7 */ { false, 0xf5b7, 0xf5b7 }, +/* 0xf5b8 */ { false, 0xf5b8, 0xf5b8 }, +/* 0xf5b9 */ { false, 0xf5b9, 0xf5b9 }, +/* 0xf5ba */ { false, 0xf5ba, 0xf5ba }, +/* 0xf5bb */ { false, 0xf5bb, 0xf5bb }, +/* 0xf5bc */ { false, 0xf5bc, 0xf5bc }, +/* 0xf5bd */ { false, 0xf5bd, 0xf5bd }, +/* 0xf5be */ { false, 0xf5be, 0xf5be }, +/* 0xf5bf */ { false, 0xf5bf, 0xf5bf }, +/* 0xf5c0 */ { false, 0xf5c0, 0xf5c0 }, +/* 0xf5c1 */ { false, 0xf5c1, 0xf5c1 }, +/* 0xf5c2 */ { false, 0xf5c2, 0xf5c2 }, +/* 0xf5c3 */ { false, 0xf5c3, 0xf5c3 }, +/* 0xf5c4 */ { false, 0xf5c4, 0xf5c4 }, +/* 0xf5c5 */ { false, 0xf5c5, 0xf5c5 }, +/* 0xf5c6 */ { false, 0xf5c6, 0xf5c6 }, +/* 0xf5c7 */ { false, 0xf5c7, 0xf5c7 }, +/* 0xf5c8 */ { false, 0xf5c8, 0xf5c8 }, +/* 0xf5c9 */ { false, 0xf5c9, 0xf5c9 }, +/* 0xf5ca */ { false, 0xf5ca, 0xf5ca }, +/* 0xf5cb */ { false, 0xf5cb, 0xf5cb }, +/* 0xf5cc */ { false, 0xf5cc, 0xf5cc }, +/* 0xf5cd */ { false, 0xf5cd, 0xf5cd }, +/* 0xf5ce */ { false, 0xf5ce, 0xf5ce }, +/* 0xf5cf */ { false, 0xf5cf, 0xf5cf }, +/* 0xf5d0 */ { false, 0xf5d0, 0xf5d0 }, +/* 0xf5d1 */ { false, 0xf5d1, 0xf5d1 }, +/* 0xf5d2 */ { false, 0xf5d2, 0xf5d2 }, +/* 0xf5d3 */ { false, 0xf5d3, 0xf5d3 }, +/* 0xf5d4 */ { false, 0xf5d4, 0xf5d4 }, +/* 0xf5d5 */ { false, 0xf5d5, 0xf5d5 }, +/* 0xf5d6 */ { false, 0xf5d6, 0xf5d6 }, +/* 0xf5d7 */ { false, 0xf5d7, 0xf5d7 }, +/* 0xf5d8 */ { false, 0xf5d8, 0xf5d8 }, +/* 0xf5d9 */ { false, 0xf5d9, 0xf5d9 }, +/* 0xf5da */ { false, 0xf5da, 0xf5da }, +/* 0xf5db */ { false, 0xf5db, 0xf5db }, +/* 0xf5dc */ { false, 0xf5dc, 0xf5dc }, +/* 0xf5dd */ { false, 0xf5dd, 0xf5dd }, +/* 0xf5de */ { false, 0xf5de, 0xf5de }, +/* 0xf5df */ { false, 0xf5df, 0xf5df }, +/* 0xf5e0 */ { false, 0xf5e0, 0xf5e0 }, +/* 0xf5e1 */ { false, 0xf5e1, 0xf5e1 }, +/* 0xf5e2 */ { false, 0xf5e2, 0xf5e2 }, +/* 0xf5e3 */ { false, 0xf5e3, 0xf5e3 }, +/* 0xf5e4 */ { false, 0xf5e4, 0xf5e4 }, +/* 0xf5e5 */ { false, 0xf5e5, 0xf5e5 }, +/* 0xf5e6 */ { false, 0xf5e6, 0xf5e6 }, +/* 0xf5e7 */ { false, 0xf5e7, 0xf5e7 }, +/* 0xf5e8 */ { false, 0xf5e8, 0xf5e8 }, +/* 0xf5e9 */ { false, 0xf5e9, 0xf5e9 }, +/* 0xf5ea */ { false, 0xf5ea, 0xf5ea }, +/* 0xf5eb */ { false, 0xf5eb, 0xf5eb }, +/* 0xf5ec */ { false, 0xf5ec, 0xf5ec }, +/* 0xf5ed */ { false, 0xf5ed, 0xf5ed }, +/* 0xf5ee */ { false, 0xf5ee, 0xf5ee }, +/* 0xf5ef */ { false, 0xf5ef, 0xf5ef }, +/* 0xf5f0 */ { false, 0xf5f0, 0xf5f0 }, +/* 0xf5f1 */ { false, 0xf5f1, 0xf5f1 }, +/* 0xf5f2 */ { false, 0xf5f2, 0xf5f2 }, +/* 0xf5f3 */ { false, 0xf5f3, 0xf5f3 }, +/* 0xf5f4 */ { false, 0xf5f4, 0xf5f4 }, +/* 0xf5f5 */ { false, 0xf5f5, 0xf5f5 }, +/* 0xf5f6 */ { false, 0xf5f6, 0xf5f6 }, +/* 0xf5f7 */ { false, 0xf5f7, 0xf5f7 }, +/* 0xf5f8 */ { false, 0xf5f8, 0xf5f8 }, +/* 0xf5f9 */ { false, 0xf5f9, 0xf5f9 }, +/* 0xf5fa */ { false, 0xf5fa, 0xf5fa }, +/* 0xf5fb */ { false, 0xf5fb, 0xf5fb }, +/* 0xf5fc */ { false, 0xf5fc, 0xf5fc }, +/* 0xf5fd */ { false, 0xf5fd, 0xf5fd }, +/* 0xf5fe */ { false, 0xf5fe, 0xf5fe }, +/* 0xf5ff */ { false, 0xf5ff, 0xf5ff }, +/* 0xf600 */ { false, 0xf600, 0xf600 }, +/* 0xf601 */ { false, 0xf601, 0xf601 }, +/* 0xf602 */ { false, 0xf602, 0xf602 }, +/* 0xf603 */ { false, 0xf603, 0xf603 }, +/* 0xf604 */ { false, 0xf604, 0xf604 }, +/* 0xf605 */ { false, 0xf605, 0xf605 }, +/* 0xf606 */ { false, 0xf606, 0xf606 }, +/* 0xf607 */ { false, 0xf607, 0xf607 }, +/* 0xf608 */ { false, 0xf608, 0xf608 }, +/* 0xf609 */ { false, 0xf609, 0xf609 }, +/* 0xf60a */ { false, 0xf60a, 0xf60a }, +/* 0xf60b */ { false, 0xf60b, 0xf60b }, +/* 0xf60c */ { false, 0xf60c, 0xf60c }, +/* 0xf60d */ { false, 0xf60d, 0xf60d }, +/* 0xf60e */ { false, 0xf60e, 0xf60e }, +/* 0xf60f */ { false, 0xf60f, 0xf60f }, +/* 0xf610 */ { false, 0xf610, 0xf610 }, +/* 0xf611 */ { false, 0xf611, 0xf611 }, +/* 0xf612 */ { false, 0xf612, 0xf612 }, +/* 0xf613 */ { false, 0xf613, 0xf613 }, +/* 0xf614 */ { false, 0xf614, 0xf614 }, +/* 0xf615 */ { false, 0xf615, 0xf615 }, +/* 0xf616 */ { false, 0xf616, 0xf616 }, +/* 0xf617 */ { false, 0xf617, 0xf617 }, +/* 0xf618 */ { false, 0xf618, 0xf618 }, +/* 0xf619 */ { false, 0xf619, 0xf619 }, +/* 0xf61a */ { false, 0xf61a, 0xf61a }, +/* 0xf61b */ { false, 0xf61b, 0xf61b }, +/* 0xf61c */ { false, 0xf61c, 0xf61c }, +/* 0xf61d */ { false, 0xf61d, 0xf61d }, +/* 0xf61e */ { false, 0xf61e, 0xf61e }, +/* 0xf61f */ { false, 0xf61f, 0xf61f }, +/* 0xf620 */ { false, 0xf620, 0xf620 }, +/* 0xf621 */ { false, 0xf621, 0xf621 }, +/* 0xf622 */ { false, 0xf622, 0xf622 }, +/* 0xf623 */ { false, 0xf623, 0xf623 }, +/* 0xf624 */ { false, 0xf624, 0xf624 }, +/* 0xf625 */ { false, 0xf625, 0xf625 }, +/* 0xf626 */ { false, 0xf626, 0xf626 }, +/* 0xf627 */ { false, 0xf627, 0xf627 }, +/* 0xf628 */ { false, 0xf628, 0xf628 }, +/* 0xf629 */ { false, 0xf629, 0xf629 }, +/* 0xf62a */ { false, 0xf62a, 0xf62a }, +/* 0xf62b */ { false, 0xf62b, 0xf62b }, +/* 0xf62c */ { false, 0xf62c, 0xf62c }, +/* 0xf62d */ { false, 0xf62d, 0xf62d }, +/* 0xf62e */ { false, 0xf62e, 0xf62e }, +/* 0xf62f */ { false, 0xf62f, 0xf62f }, +/* 0xf630 */ { false, 0xf630, 0xf630 }, +/* 0xf631 */ { false, 0xf631, 0xf631 }, +/* 0xf632 */ { false, 0xf632, 0xf632 }, +/* 0xf633 */ { false, 0xf633, 0xf633 }, +/* 0xf634 */ { false, 0xf634, 0xf634 }, +/* 0xf635 */ { false, 0xf635, 0xf635 }, +/* 0xf636 */ { false, 0xf636, 0xf636 }, +/* 0xf637 */ { false, 0xf637, 0xf637 }, +/* 0xf638 */ { false, 0xf638, 0xf638 }, +/* 0xf639 */ { false, 0xf639, 0xf639 }, +/* 0xf63a */ { false, 0xf63a, 0xf63a }, +/* 0xf63b */ { false, 0xf63b, 0xf63b }, +/* 0xf63c */ { false, 0xf63c, 0xf63c }, +/* 0xf63d */ { false, 0xf63d, 0xf63d }, +/* 0xf63e */ { false, 0xf63e, 0xf63e }, +/* 0xf63f */ { false, 0xf63f, 0xf63f }, +/* 0xf640 */ { false, 0xf640, 0xf640 }, +/* 0xf641 */ { false, 0xf641, 0xf641 }, +/* 0xf642 */ { false, 0xf642, 0xf642 }, +/* 0xf643 */ { false, 0xf643, 0xf643 }, +/* 0xf644 */ { false, 0xf644, 0xf644 }, +/* 0xf645 */ { false, 0xf645, 0xf645 }, +/* 0xf646 */ { false, 0xf646, 0xf646 }, +/* 0xf647 */ { false, 0xf647, 0xf647 }, +/* 0xf648 */ { false, 0xf648, 0xf648 }, +/* 0xf649 */ { false, 0xf649, 0xf649 }, +/* 0xf64a */ { false, 0xf64a, 0xf64a }, +/* 0xf64b */ { false, 0xf64b, 0xf64b }, +/* 0xf64c */ { false, 0xf64c, 0xf64c }, +/* 0xf64d */ { false, 0xf64d, 0xf64d }, +/* 0xf64e */ { false, 0xf64e, 0xf64e }, +/* 0xf64f */ { false, 0xf64f, 0xf64f }, +/* 0xf650 */ { false, 0xf650, 0xf650 }, +/* 0xf651 */ { false, 0xf651, 0xf651 }, +/* 0xf652 */ { false, 0xf652, 0xf652 }, +/* 0xf653 */ { false, 0xf653, 0xf653 }, +/* 0xf654 */ { false, 0xf654, 0xf654 }, +/* 0xf655 */ { false, 0xf655, 0xf655 }, +/* 0xf656 */ { false, 0xf656, 0xf656 }, +/* 0xf657 */ { false, 0xf657, 0xf657 }, +/* 0xf658 */ { false, 0xf658, 0xf658 }, +/* 0xf659 */ { false, 0xf659, 0xf659 }, +/* 0xf65a */ { false, 0xf65a, 0xf65a }, +/* 0xf65b */ { false, 0xf65b, 0xf65b }, +/* 0xf65c */ { false, 0xf65c, 0xf65c }, +/* 0xf65d */ { false, 0xf65d, 0xf65d }, +/* 0xf65e */ { false, 0xf65e, 0xf65e }, +/* 0xf65f */ { false, 0xf65f, 0xf65f }, +/* 0xf660 */ { false, 0xf660, 0xf660 }, +/* 0xf661 */ { false, 0xf661, 0xf661 }, +/* 0xf662 */ { false, 0xf662, 0xf662 }, +/* 0xf663 */ { false, 0xf663, 0xf663 }, +/* 0xf664 */ { false, 0xf664, 0xf664 }, +/* 0xf665 */ { false, 0xf665, 0xf665 }, +/* 0xf666 */ { false, 0xf666, 0xf666 }, +/* 0xf667 */ { false, 0xf667, 0xf667 }, +/* 0xf668 */ { false, 0xf668, 0xf668 }, +/* 0xf669 */ { false, 0xf669, 0xf669 }, +/* 0xf66a */ { false, 0xf66a, 0xf66a }, +/* 0xf66b */ { false, 0xf66b, 0xf66b }, +/* 0xf66c */ { false, 0xf66c, 0xf66c }, +/* 0xf66d */ { false, 0xf66d, 0xf66d }, +/* 0xf66e */ { false, 0xf66e, 0xf66e }, +/* 0xf66f */ { false, 0xf66f, 0xf66f }, +/* 0xf670 */ { false, 0xf670, 0xf670 }, +/* 0xf671 */ { false, 0xf671, 0xf671 }, +/* 0xf672 */ { false, 0xf672, 0xf672 }, +/* 0xf673 */ { false, 0xf673, 0xf673 }, +/* 0xf674 */ { false, 0xf674, 0xf674 }, +/* 0xf675 */ { false, 0xf675, 0xf675 }, +/* 0xf676 */ { false, 0xf676, 0xf676 }, +/* 0xf677 */ { false, 0xf677, 0xf677 }, +/* 0xf678 */ { false, 0xf678, 0xf678 }, +/* 0xf679 */ { false, 0xf679, 0xf679 }, +/* 0xf67a */ { false, 0xf67a, 0xf67a }, +/* 0xf67b */ { false, 0xf67b, 0xf67b }, +/* 0xf67c */ { false, 0xf67c, 0xf67c }, +/* 0xf67d */ { false, 0xf67d, 0xf67d }, +/* 0xf67e */ { false, 0xf67e, 0xf67e }, +/* 0xf67f */ { false, 0xf67f, 0xf67f }, +/* 0xf680 */ { false, 0xf680, 0xf680 }, +/* 0xf681 */ { false, 0xf681, 0xf681 }, +/* 0xf682 */ { false, 0xf682, 0xf682 }, +/* 0xf683 */ { false, 0xf683, 0xf683 }, +/* 0xf684 */ { false, 0xf684, 0xf684 }, +/* 0xf685 */ { false, 0xf685, 0xf685 }, +/* 0xf686 */ { false, 0xf686, 0xf686 }, +/* 0xf687 */ { false, 0xf687, 0xf687 }, +/* 0xf688 */ { false, 0xf688, 0xf688 }, +/* 0xf689 */ { false, 0xf689, 0xf689 }, +/* 0xf68a */ { false, 0xf68a, 0xf68a }, +/* 0xf68b */ { false, 0xf68b, 0xf68b }, +/* 0xf68c */ { false, 0xf68c, 0xf68c }, +/* 0xf68d */ { false, 0xf68d, 0xf68d }, +/* 0xf68e */ { false, 0xf68e, 0xf68e }, +/* 0xf68f */ { false, 0xf68f, 0xf68f }, +/* 0xf690 */ { false, 0xf690, 0xf690 }, +/* 0xf691 */ { false, 0xf691, 0xf691 }, +/* 0xf692 */ { false, 0xf692, 0xf692 }, +/* 0xf693 */ { false, 0xf693, 0xf693 }, +/* 0xf694 */ { false, 0xf694, 0xf694 }, +/* 0xf695 */ { false, 0xf695, 0xf695 }, +/* 0xf696 */ { false, 0xf696, 0xf696 }, +/* 0xf697 */ { false, 0xf697, 0xf697 }, +/* 0xf698 */ { false, 0xf698, 0xf698 }, +/* 0xf699 */ { false, 0xf699, 0xf699 }, +/* 0xf69a */ { false, 0xf69a, 0xf69a }, +/* 0xf69b */ { false, 0xf69b, 0xf69b }, +/* 0xf69c */ { false, 0xf69c, 0xf69c }, +/* 0xf69d */ { false, 0xf69d, 0xf69d }, +/* 0xf69e */ { false, 0xf69e, 0xf69e }, +/* 0xf69f */ { false, 0xf69f, 0xf69f }, +/* 0xf6a0 */ { false, 0xf6a0, 0xf6a0 }, +/* 0xf6a1 */ { false, 0xf6a1, 0xf6a1 }, +/* 0xf6a2 */ { false, 0xf6a2, 0xf6a2 }, +/* 0xf6a3 */ { false, 0xf6a3, 0xf6a3 }, +/* 0xf6a4 */ { false, 0xf6a4, 0xf6a4 }, +/* 0xf6a5 */ { false, 0xf6a5, 0xf6a5 }, +/* 0xf6a6 */ { false, 0xf6a6, 0xf6a6 }, +/* 0xf6a7 */ { false, 0xf6a7, 0xf6a7 }, +/* 0xf6a8 */ { false, 0xf6a8, 0xf6a8 }, +/* 0xf6a9 */ { false, 0xf6a9, 0xf6a9 }, +/* 0xf6aa */ { false, 0xf6aa, 0xf6aa }, +/* 0xf6ab */ { false, 0xf6ab, 0xf6ab }, +/* 0xf6ac */ { false, 0xf6ac, 0xf6ac }, +/* 0xf6ad */ { false, 0xf6ad, 0xf6ad }, +/* 0xf6ae */ { false, 0xf6ae, 0xf6ae }, +/* 0xf6af */ { false, 0xf6af, 0xf6af }, +/* 0xf6b0 */ { false, 0xf6b0, 0xf6b0 }, +/* 0xf6b1 */ { false, 0xf6b1, 0xf6b1 }, +/* 0xf6b2 */ { false, 0xf6b2, 0xf6b2 }, +/* 0xf6b3 */ { false, 0xf6b3, 0xf6b3 }, +/* 0xf6b4 */ { false, 0xf6b4, 0xf6b4 }, +/* 0xf6b5 */ { false, 0xf6b5, 0xf6b5 }, +/* 0xf6b6 */ { false, 0xf6b6, 0xf6b6 }, +/* 0xf6b7 */ { false, 0xf6b7, 0xf6b7 }, +/* 0xf6b8 */ { false, 0xf6b8, 0xf6b8 }, +/* 0xf6b9 */ { false, 0xf6b9, 0xf6b9 }, +/* 0xf6ba */ { false, 0xf6ba, 0xf6ba }, +/* 0xf6bb */ { false, 0xf6bb, 0xf6bb }, +/* 0xf6bc */ { false, 0xf6bc, 0xf6bc }, +/* 0xf6bd */ { false, 0xf6bd, 0xf6bd }, +/* 0xf6be */ { false, 0xf6be, 0xf6be }, +/* 0xf6bf */ { false, 0xf6bf, 0xf6bf }, +/* 0xf6c0 */ { false, 0xf6c0, 0xf6c0 }, +/* 0xf6c1 */ { false, 0xf6c1, 0xf6c1 }, +/* 0xf6c2 */ { false, 0xf6c2, 0xf6c2 }, +/* 0xf6c3 */ { false, 0xf6c3, 0xf6c3 }, +/* 0xf6c4 */ { false, 0xf6c4, 0xf6c4 }, +/* 0xf6c5 */ { false, 0xf6c5, 0xf6c5 }, +/* 0xf6c6 */ { false, 0xf6c6, 0xf6c6 }, +/* 0xf6c7 */ { false, 0xf6c7, 0xf6c7 }, +/* 0xf6c8 */ { false, 0xf6c8, 0xf6c8 }, +/* 0xf6c9 */ { false, 0xf6c9, 0xf6c9 }, +/* 0xf6ca */ { false, 0xf6ca, 0xf6ca }, +/* 0xf6cb */ { false, 0xf6cb, 0xf6cb }, +/* 0xf6cc */ { false, 0xf6cc, 0xf6cc }, +/* 0xf6cd */ { false, 0xf6cd, 0xf6cd }, +/* 0xf6ce */ { false, 0xf6ce, 0xf6ce }, +/* 0xf6cf */ { false, 0xf6cf, 0xf6cf }, +/* 0xf6d0 */ { false, 0xf6d0, 0xf6d0 }, +/* 0xf6d1 */ { false, 0xf6d1, 0xf6d1 }, +/* 0xf6d2 */ { false, 0xf6d2, 0xf6d2 }, +/* 0xf6d3 */ { false, 0xf6d3, 0xf6d3 }, +/* 0xf6d4 */ { false, 0xf6d4, 0xf6d4 }, +/* 0xf6d5 */ { false, 0xf6d5, 0xf6d5 }, +/* 0xf6d6 */ { false, 0xf6d6, 0xf6d6 }, +/* 0xf6d7 */ { false, 0xf6d7, 0xf6d7 }, +/* 0xf6d8 */ { false, 0xf6d8, 0xf6d8 }, +/* 0xf6d9 */ { false, 0xf6d9, 0xf6d9 }, +/* 0xf6da */ { false, 0xf6da, 0xf6da }, +/* 0xf6db */ { false, 0xf6db, 0xf6db }, +/* 0xf6dc */ { false, 0xf6dc, 0xf6dc }, +/* 0xf6dd */ { false, 0xf6dd, 0xf6dd }, +/* 0xf6de */ { false, 0xf6de, 0xf6de }, +/* 0xf6df */ { false, 0xf6df, 0xf6df }, +/* 0xf6e0 */ { false, 0xf6e0, 0xf6e0 }, +/* 0xf6e1 */ { false, 0xf6e1, 0xf6e1 }, +/* 0xf6e2 */ { false, 0xf6e2, 0xf6e2 }, +/* 0xf6e3 */ { false, 0xf6e3, 0xf6e3 }, +/* 0xf6e4 */ { false, 0xf6e4, 0xf6e4 }, +/* 0xf6e5 */ { false, 0xf6e5, 0xf6e5 }, +/* 0xf6e6 */ { false, 0xf6e6, 0xf6e6 }, +/* 0xf6e7 */ { false, 0xf6e7, 0xf6e7 }, +/* 0xf6e8 */ { false, 0xf6e8, 0xf6e8 }, +/* 0xf6e9 */ { false, 0xf6e9, 0xf6e9 }, +/* 0xf6ea */ { false, 0xf6ea, 0xf6ea }, +/* 0xf6eb */ { false, 0xf6eb, 0xf6eb }, +/* 0xf6ec */ { false, 0xf6ec, 0xf6ec }, +/* 0xf6ed */ { false, 0xf6ed, 0xf6ed }, +/* 0xf6ee */ { false, 0xf6ee, 0xf6ee }, +/* 0xf6ef */ { false, 0xf6ef, 0xf6ef }, +/* 0xf6f0 */ { false, 0xf6f0, 0xf6f0 }, +/* 0xf6f1 */ { false, 0xf6f1, 0xf6f1 }, +/* 0xf6f2 */ { false, 0xf6f2, 0xf6f2 }, +/* 0xf6f3 */ { false, 0xf6f3, 0xf6f3 }, +/* 0xf6f4 */ { false, 0xf6f4, 0xf6f4 }, +/* 0xf6f5 */ { false, 0xf6f5, 0xf6f5 }, +/* 0xf6f6 */ { false, 0xf6f6, 0xf6f6 }, +/* 0xf6f7 */ { false, 0xf6f7, 0xf6f7 }, +/* 0xf6f8 */ { false, 0xf6f8, 0xf6f8 }, +/* 0xf6f9 */ { false, 0xf6f9, 0xf6f9 }, +/* 0xf6fa */ { false, 0xf6fa, 0xf6fa }, +/* 0xf6fb */ { false, 0xf6fb, 0xf6fb }, +/* 0xf6fc */ { false, 0xf6fc, 0xf6fc }, +/* 0xf6fd */ { false, 0xf6fd, 0xf6fd }, +/* 0xf6fe */ { false, 0xf6fe, 0xf6fe }, +/* 0xf6ff */ { false, 0xf6ff, 0xf6ff }, +/* 0xf700 */ { false, 0xf700, 0xf700 }, +/* 0xf701 */ { false, 0xf701, 0xf701 }, +/* 0xf702 */ { false, 0xf702, 0xf702 }, +/* 0xf703 */ { false, 0xf703, 0xf703 }, +/* 0xf704 */ { false, 0xf704, 0xf704 }, +/* 0xf705 */ { false, 0xf705, 0xf705 }, +/* 0xf706 */ { false, 0xf706, 0xf706 }, +/* 0xf707 */ { false, 0xf707, 0xf707 }, +/* 0xf708 */ { false, 0xf708, 0xf708 }, +/* 0xf709 */ { false, 0xf709, 0xf709 }, +/* 0xf70a */ { false, 0xf70a, 0xf70a }, +/* 0xf70b */ { false, 0xf70b, 0xf70b }, +/* 0xf70c */ { false, 0xf70c, 0xf70c }, +/* 0xf70d */ { false, 0xf70d, 0xf70d }, +/* 0xf70e */ { false, 0xf70e, 0xf70e }, +/* 0xf70f */ { false, 0xf70f, 0xf70f }, +/* 0xf710 */ { false, 0xf710, 0xf710 }, +/* 0xf711 */ { false, 0xf711, 0xf711 }, +/* 0xf712 */ { false, 0xf712, 0xf712 }, +/* 0xf713 */ { false, 0xf713, 0xf713 }, +/* 0xf714 */ { false, 0xf714, 0xf714 }, +/* 0xf715 */ { false, 0xf715, 0xf715 }, +/* 0xf716 */ { false, 0xf716, 0xf716 }, +/* 0xf717 */ { false, 0xf717, 0xf717 }, +/* 0xf718 */ { false, 0xf718, 0xf718 }, +/* 0xf719 */ { false, 0xf719, 0xf719 }, +/* 0xf71a */ { false, 0xf71a, 0xf71a }, +/* 0xf71b */ { false, 0xf71b, 0xf71b }, +/* 0xf71c */ { false, 0xf71c, 0xf71c }, +/* 0xf71d */ { false, 0xf71d, 0xf71d }, +/* 0xf71e */ { false, 0xf71e, 0xf71e }, +/* 0xf71f */ { false, 0xf71f, 0xf71f }, +/* 0xf720 */ { false, 0xf720, 0xf720 }, +/* 0xf721 */ { false, 0xf721, 0xf721 }, +/* 0xf722 */ { false, 0xf722, 0xf722 }, +/* 0xf723 */ { false, 0xf723, 0xf723 }, +/* 0xf724 */ { false, 0xf724, 0xf724 }, +/* 0xf725 */ { false, 0xf725, 0xf725 }, +/* 0xf726 */ { false, 0xf726, 0xf726 }, +/* 0xf727 */ { false, 0xf727, 0xf727 }, +/* 0xf728 */ { false, 0xf728, 0xf728 }, +/* 0xf729 */ { false, 0xf729, 0xf729 }, +/* 0xf72a */ { false, 0xf72a, 0xf72a }, +/* 0xf72b */ { false, 0xf72b, 0xf72b }, +/* 0xf72c */ { false, 0xf72c, 0xf72c }, +/* 0xf72d */ { false, 0xf72d, 0xf72d }, +/* 0xf72e */ { false, 0xf72e, 0xf72e }, +/* 0xf72f */ { false, 0xf72f, 0xf72f }, +/* 0xf730 */ { false, 0xf730, 0xf730 }, +/* 0xf731 */ { false, 0xf731, 0xf731 }, +/* 0xf732 */ { false, 0xf732, 0xf732 }, +/* 0xf733 */ { false, 0xf733, 0xf733 }, +/* 0xf734 */ { false, 0xf734, 0xf734 }, +/* 0xf735 */ { false, 0xf735, 0xf735 }, +/* 0xf736 */ { false, 0xf736, 0xf736 }, +/* 0xf737 */ { false, 0xf737, 0xf737 }, +/* 0xf738 */ { false, 0xf738, 0xf738 }, +/* 0xf739 */ { false, 0xf739, 0xf739 }, +/* 0xf73a */ { false, 0xf73a, 0xf73a }, +/* 0xf73b */ { false, 0xf73b, 0xf73b }, +/* 0xf73c */ { false, 0xf73c, 0xf73c }, +/* 0xf73d */ { false, 0xf73d, 0xf73d }, +/* 0xf73e */ { false, 0xf73e, 0xf73e }, +/* 0xf73f */ { false, 0xf73f, 0xf73f }, +/* 0xf740 */ { false, 0xf740, 0xf740 }, +/* 0xf741 */ { false, 0xf741, 0xf741 }, +/* 0xf742 */ { false, 0xf742, 0xf742 }, +/* 0xf743 */ { false, 0xf743, 0xf743 }, +/* 0xf744 */ { false, 0xf744, 0xf744 }, +/* 0xf745 */ { false, 0xf745, 0xf745 }, +/* 0xf746 */ { false, 0xf746, 0xf746 }, +/* 0xf747 */ { false, 0xf747, 0xf747 }, +/* 0xf748 */ { false, 0xf748, 0xf748 }, +/* 0xf749 */ { false, 0xf749, 0xf749 }, +/* 0xf74a */ { false, 0xf74a, 0xf74a }, +/* 0xf74b */ { false, 0xf74b, 0xf74b }, +/* 0xf74c */ { false, 0xf74c, 0xf74c }, +/* 0xf74d */ { false, 0xf74d, 0xf74d }, +/* 0xf74e */ { false, 0xf74e, 0xf74e }, +/* 0xf74f */ { false, 0xf74f, 0xf74f }, +/* 0xf750 */ { false, 0xf750, 0xf750 }, +/* 0xf751 */ { false, 0xf751, 0xf751 }, +/* 0xf752 */ { false, 0xf752, 0xf752 }, +/* 0xf753 */ { false, 0xf753, 0xf753 }, +/* 0xf754 */ { false, 0xf754, 0xf754 }, +/* 0xf755 */ { false, 0xf755, 0xf755 }, +/* 0xf756 */ { false, 0xf756, 0xf756 }, +/* 0xf757 */ { false, 0xf757, 0xf757 }, +/* 0xf758 */ { false, 0xf758, 0xf758 }, +/* 0xf759 */ { false, 0xf759, 0xf759 }, +/* 0xf75a */ { false, 0xf75a, 0xf75a }, +/* 0xf75b */ { false, 0xf75b, 0xf75b }, +/* 0xf75c */ { false, 0xf75c, 0xf75c }, +/* 0xf75d */ { false, 0xf75d, 0xf75d }, +/* 0xf75e */ { false, 0xf75e, 0xf75e }, +/* 0xf75f */ { false, 0xf75f, 0xf75f }, +/* 0xf760 */ { false, 0xf760, 0xf760 }, +/* 0xf761 */ { false, 0xf761, 0xf761 }, +/* 0xf762 */ { false, 0xf762, 0xf762 }, +/* 0xf763 */ { false, 0xf763, 0xf763 }, +/* 0xf764 */ { false, 0xf764, 0xf764 }, +/* 0xf765 */ { false, 0xf765, 0xf765 }, +/* 0xf766 */ { false, 0xf766, 0xf766 }, +/* 0xf767 */ { false, 0xf767, 0xf767 }, +/* 0xf768 */ { false, 0xf768, 0xf768 }, +/* 0xf769 */ { false, 0xf769, 0xf769 }, +/* 0xf76a */ { false, 0xf76a, 0xf76a }, +/* 0xf76b */ { false, 0xf76b, 0xf76b }, +/* 0xf76c */ { false, 0xf76c, 0xf76c }, +/* 0xf76d */ { false, 0xf76d, 0xf76d }, +/* 0xf76e */ { false, 0xf76e, 0xf76e }, +/* 0xf76f */ { false, 0xf76f, 0xf76f }, +/* 0xf770 */ { false, 0xf770, 0xf770 }, +/* 0xf771 */ { false, 0xf771, 0xf771 }, +/* 0xf772 */ { false, 0xf772, 0xf772 }, +/* 0xf773 */ { false, 0xf773, 0xf773 }, +/* 0xf774 */ { false, 0xf774, 0xf774 }, +/* 0xf775 */ { false, 0xf775, 0xf775 }, +/* 0xf776 */ { false, 0xf776, 0xf776 }, +/* 0xf777 */ { false, 0xf777, 0xf777 }, +/* 0xf778 */ { false, 0xf778, 0xf778 }, +/* 0xf779 */ { false, 0xf779, 0xf779 }, +/* 0xf77a */ { false, 0xf77a, 0xf77a }, +/* 0xf77b */ { false, 0xf77b, 0xf77b }, +/* 0xf77c */ { false, 0xf77c, 0xf77c }, +/* 0xf77d */ { false, 0xf77d, 0xf77d }, +/* 0xf77e */ { false, 0xf77e, 0xf77e }, +/* 0xf77f */ { false, 0xf77f, 0xf77f }, +/* 0xf780 */ { false, 0xf780, 0xf780 }, +/* 0xf781 */ { false, 0xf781, 0xf781 }, +/* 0xf782 */ { false, 0xf782, 0xf782 }, +/* 0xf783 */ { false, 0xf783, 0xf783 }, +/* 0xf784 */ { false, 0xf784, 0xf784 }, +/* 0xf785 */ { false, 0xf785, 0xf785 }, +/* 0xf786 */ { false, 0xf786, 0xf786 }, +/* 0xf787 */ { false, 0xf787, 0xf787 }, +/* 0xf788 */ { false, 0xf788, 0xf788 }, +/* 0xf789 */ { false, 0xf789, 0xf789 }, +/* 0xf78a */ { false, 0xf78a, 0xf78a }, +/* 0xf78b */ { false, 0xf78b, 0xf78b }, +/* 0xf78c */ { false, 0xf78c, 0xf78c }, +/* 0xf78d */ { false, 0xf78d, 0xf78d }, +/* 0xf78e */ { false, 0xf78e, 0xf78e }, +/* 0xf78f */ { false, 0xf78f, 0xf78f }, +/* 0xf790 */ { false, 0xf790, 0xf790 }, +/* 0xf791 */ { false, 0xf791, 0xf791 }, +/* 0xf792 */ { false, 0xf792, 0xf792 }, +/* 0xf793 */ { false, 0xf793, 0xf793 }, +/* 0xf794 */ { false, 0xf794, 0xf794 }, +/* 0xf795 */ { false, 0xf795, 0xf795 }, +/* 0xf796 */ { false, 0xf796, 0xf796 }, +/* 0xf797 */ { false, 0xf797, 0xf797 }, +/* 0xf798 */ { false, 0xf798, 0xf798 }, +/* 0xf799 */ { false, 0xf799, 0xf799 }, +/* 0xf79a */ { false, 0xf79a, 0xf79a }, +/* 0xf79b */ { false, 0xf79b, 0xf79b }, +/* 0xf79c */ { false, 0xf79c, 0xf79c }, +/* 0xf79d */ { false, 0xf79d, 0xf79d }, +/* 0xf79e */ { false, 0xf79e, 0xf79e }, +/* 0xf79f */ { false, 0xf79f, 0xf79f }, +/* 0xf7a0 */ { false, 0xf7a0, 0xf7a0 }, +/* 0xf7a1 */ { false, 0xf7a1, 0xf7a1 }, +/* 0xf7a2 */ { false, 0xf7a2, 0xf7a2 }, +/* 0xf7a3 */ { false, 0xf7a3, 0xf7a3 }, +/* 0xf7a4 */ { false, 0xf7a4, 0xf7a4 }, +/* 0xf7a5 */ { false, 0xf7a5, 0xf7a5 }, +/* 0xf7a6 */ { false, 0xf7a6, 0xf7a6 }, +/* 0xf7a7 */ { false, 0xf7a7, 0xf7a7 }, +/* 0xf7a8 */ { false, 0xf7a8, 0xf7a8 }, +/* 0xf7a9 */ { false, 0xf7a9, 0xf7a9 }, +/* 0xf7aa */ { false, 0xf7aa, 0xf7aa }, +/* 0xf7ab */ { false, 0xf7ab, 0xf7ab }, +/* 0xf7ac */ { false, 0xf7ac, 0xf7ac }, +/* 0xf7ad */ { false, 0xf7ad, 0xf7ad }, +/* 0xf7ae */ { false, 0xf7ae, 0xf7ae }, +/* 0xf7af */ { false, 0xf7af, 0xf7af }, +/* 0xf7b0 */ { false, 0xf7b0, 0xf7b0 }, +/* 0xf7b1 */ { false, 0xf7b1, 0xf7b1 }, +/* 0xf7b2 */ { false, 0xf7b2, 0xf7b2 }, +/* 0xf7b3 */ { false, 0xf7b3, 0xf7b3 }, +/* 0xf7b4 */ { false, 0xf7b4, 0xf7b4 }, +/* 0xf7b5 */ { false, 0xf7b5, 0xf7b5 }, +/* 0xf7b6 */ { false, 0xf7b6, 0xf7b6 }, +/* 0xf7b7 */ { false, 0xf7b7, 0xf7b7 }, +/* 0xf7b8 */ { false, 0xf7b8, 0xf7b8 }, +/* 0xf7b9 */ { false, 0xf7b9, 0xf7b9 }, +/* 0xf7ba */ { false, 0xf7ba, 0xf7ba }, +/* 0xf7bb */ { false, 0xf7bb, 0xf7bb }, +/* 0xf7bc */ { false, 0xf7bc, 0xf7bc }, +/* 0xf7bd */ { false, 0xf7bd, 0xf7bd }, +/* 0xf7be */ { false, 0xf7be, 0xf7be }, +/* 0xf7bf */ { false, 0xf7bf, 0xf7bf }, +/* 0xf7c0 */ { false, 0xf7c0, 0xf7c0 }, +/* 0xf7c1 */ { false, 0xf7c1, 0xf7c1 }, +/* 0xf7c2 */ { false, 0xf7c2, 0xf7c2 }, +/* 0xf7c3 */ { false, 0xf7c3, 0xf7c3 }, +/* 0xf7c4 */ { false, 0xf7c4, 0xf7c4 }, +/* 0xf7c5 */ { false, 0xf7c5, 0xf7c5 }, +/* 0xf7c6 */ { false, 0xf7c6, 0xf7c6 }, +/* 0xf7c7 */ { false, 0xf7c7, 0xf7c7 }, +/* 0xf7c8 */ { false, 0xf7c8, 0xf7c8 }, +/* 0xf7c9 */ { false, 0xf7c9, 0xf7c9 }, +/* 0xf7ca */ { false, 0xf7ca, 0xf7ca }, +/* 0xf7cb */ { false, 0xf7cb, 0xf7cb }, +/* 0xf7cc */ { false, 0xf7cc, 0xf7cc }, +/* 0xf7cd */ { false, 0xf7cd, 0xf7cd }, +/* 0xf7ce */ { false, 0xf7ce, 0xf7ce }, +/* 0xf7cf */ { false, 0xf7cf, 0xf7cf }, +/* 0xf7d0 */ { false, 0xf7d0, 0xf7d0 }, +/* 0xf7d1 */ { false, 0xf7d1, 0xf7d1 }, +/* 0xf7d2 */ { false, 0xf7d2, 0xf7d2 }, +/* 0xf7d3 */ { false, 0xf7d3, 0xf7d3 }, +/* 0xf7d4 */ { false, 0xf7d4, 0xf7d4 }, +/* 0xf7d5 */ { false, 0xf7d5, 0xf7d5 }, +/* 0xf7d6 */ { false, 0xf7d6, 0xf7d6 }, +/* 0xf7d7 */ { false, 0xf7d7, 0xf7d7 }, +/* 0xf7d8 */ { false, 0xf7d8, 0xf7d8 }, +/* 0xf7d9 */ { false, 0xf7d9, 0xf7d9 }, +/* 0xf7da */ { false, 0xf7da, 0xf7da }, +/* 0xf7db */ { false, 0xf7db, 0xf7db }, +/* 0xf7dc */ { false, 0xf7dc, 0xf7dc }, +/* 0xf7dd */ { false, 0xf7dd, 0xf7dd }, +/* 0xf7de */ { false, 0xf7de, 0xf7de }, +/* 0xf7df */ { false, 0xf7df, 0xf7df }, +/* 0xf7e0 */ { false, 0xf7e0, 0xf7e0 }, +/* 0xf7e1 */ { false, 0xf7e1, 0xf7e1 }, +/* 0xf7e2 */ { false, 0xf7e2, 0xf7e2 }, +/* 0xf7e3 */ { false, 0xf7e3, 0xf7e3 }, +/* 0xf7e4 */ { false, 0xf7e4, 0xf7e4 }, +/* 0xf7e5 */ { false, 0xf7e5, 0xf7e5 }, +/* 0xf7e6 */ { false, 0xf7e6, 0xf7e6 }, +/* 0xf7e7 */ { false, 0xf7e7, 0xf7e7 }, +/* 0xf7e8 */ { false, 0xf7e8, 0xf7e8 }, +/* 0xf7e9 */ { false, 0xf7e9, 0xf7e9 }, +/* 0xf7ea */ { false, 0xf7ea, 0xf7ea }, +/* 0xf7eb */ { false, 0xf7eb, 0xf7eb }, +/* 0xf7ec */ { false, 0xf7ec, 0xf7ec }, +/* 0xf7ed */ { false, 0xf7ed, 0xf7ed }, +/* 0xf7ee */ { false, 0xf7ee, 0xf7ee }, +/* 0xf7ef */ { false, 0xf7ef, 0xf7ef }, +/* 0xf7f0 */ { false, 0xf7f0, 0xf7f0 }, +/* 0xf7f1 */ { false, 0xf7f1, 0xf7f1 }, +/* 0xf7f2 */ { false, 0xf7f2, 0xf7f2 }, +/* 0xf7f3 */ { false, 0xf7f3, 0xf7f3 }, +/* 0xf7f4 */ { false, 0xf7f4, 0xf7f4 }, +/* 0xf7f5 */ { false, 0xf7f5, 0xf7f5 }, +/* 0xf7f6 */ { false, 0xf7f6, 0xf7f6 }, +/* 0xf7f7 */ { false, 0xf7f7, 0xf7f7 }, +/* 0xf7f8 */ { false, 0xf7f8, 0xf7f8 }, +/* 0xf7f9 */ { false, 0xf7f9, 0xf7f9 }, +/* 0xf7fa */ { false, 0xf7fa, 0xf7fa }, +/* 0xf7fb */ { false, 0xf7fb, 0xf7fb }, +/* 0xf7fc */ { false, 0xf7fc, 0xf7fc }, +/* 0xf7fd */ { false, 0xf7fd, 0xf7fd }, +/* 0xf7fe */ { false, 0xf7fe, 0xf7fe }, +/* 0xf7ff */ { false, 0xf7ff, 0xf7ff }, +/* 0xf800 */ { false, 0xf800, 0xf800 }, +/* 0xf801 */ { false, 0xf801, 0xf801 }, +/* 0xf802 */ { false, 0xf802, 0xf802 }, +/* 0xf803 */ { false, 0xf803, 0xf803 }, +/* 0xf804 */ { false, 0xf804, 0xf804 }, +/* 0xf805 */ { false, 0xf805, 0xf805 }, +/* 0xf806 */ { false, 0xf806, 0xf806 }, +/* 0xf807 */ { false, 0xf807, 0xf807 }, +/* 0xf808 */ { false, 0xf808, 0xf808 }, +/* 0xf809 */ { false, 0xf809, 0xf809 }, +/* 0xf80a */ { false, 0xf80a, 0xf80a }, +/* 0xf80b */ { false, 0xf80b, 0xf80b }, +/* 0xf80c */ { false, 0xf80c, 0xf80c }, +/* 0xf80d */ { false, 0xf80d, 0xf80d }, +/* 0xf80e */ { false, 0xf80e, 0xf80e }, +/* 0xf80f */ { false, 0xf80f, 0xf80f }, +/* 0xf810 */ { false, 0xf810, 0xf810 }, +/* 0xf811 */ { false, 0xf811, 0xf811 }, +/* 0xf812 */ { false, 0xf812, 0xf812 }, +/* 0xf813 */ { false, 0xf813, 0xf813 }, +/* 0xf814 */ { false, 0xf814, 0xf814 }, +/* 0xf815 */ { false, 0xf815, 0xf815 }, +/* 0xf816 */ { false, 0xf816, 0xf816 }, +/* 0xf817 */ { false, 0xf817, 0xf817 }, +/* 0xf818 */ { false, 0xf818, 0xf818 }, +/* 0xf819 */ { false, 0xf819, 0xf819 }, +/* 0xf81a */ { false, 0xf81a, 0xf81a }, +/* 0xf81b */ { false, 0xf81b, 0xf81b }, +/* 0xf81c */ { false, 0xf81c, 0xf81c }, +/* 0xf81d */ { false, 0xf81d, 0xf81d }, +/* 0xf81e */ { false, 0xf81e, 0xf81e }, +/* 0xf81f */ { false, 0xf81f, 0xf81f }, +/* 0xf820 */ { false, 0xf820, 0xf820 }, +/* 0xf821 */ { false, 0xf821, 0xf821 }, +/* 0xf822 */ { false, 0xf822, 0xf822 }, +/* 0xf823 */ { false, 0xf823, 0xf823 }, +/* 0xf824 */ { false, 0xf824, 0xf824 }, +/* 0xf825 */ { false, 0xf825, 0xf825 }, +/* 0xf826 */ { false, 0xf826, 0xf826 }, +/* 0xf827 */ { false, 0xf827, 0xf827 }, +/* 0xf828 */ { false, 0xf828, 0xf828 }, +/* 0xf829 */ { false, 0xf829, 0xf829 }, +/* 0xf82a */ { false, 0xf82a, 0xf82a }, +/* 0xf82b */ { false, 0xf82b, 0xf82b }, +/* 0xf82c */ { false, 0xf82c, 0xf82c }, +/* 0xf82d */ { false, 0xf82d, 0xf82d }, +/* 0xf82e */ { false, 0xf82e, 0xf82e }, +/* 0xf82f */ { false, 0xf82f, 0xf82f }, +/* 0xf830 */ { false, 0xf830, 0xf830 }, +/* 0xf831 */ { false, 0xf831, 0xf831 }, +/* 0xf832 */ { false, 0xf832, 0xf832 }, +/* 0xf833 */ { false, 0xf833, 0xf833 }, +/* 0xf834 */ { false, 0xf834, 0xf834 }, +/* 0xf835 */ { false, 0xf835, 0xf835 }, +/* 0xf836 */ { false, 0xf836, 0xf836 }, +/* 0xf837 */ { false, 0xf837, 0xf837 }, +/* 0xf838 */ { false, 0xf838, 0xf838 }, +/* 0xf839 */ { false, 0xf839, 0xf839 }, +/* 0xf83a */ { false, 0xf83a, 0xf83a }, +/* 0xf83b */ { false, 0xf83b, 0xf83b }, +/* 0xf83c */ { false, 0xf83c, 0xf83c }, +/* 0xf83d */ { false, 0xf83d, 0xf83d }, +/* 0xf83e */ { false, 0xf83e, 0xf83e }, +/* 0xf83f */ { false, 0xf83f, 0xf83f }, +/* 0xf840 */ { false, 0xf840, 0xf840 }, +/* 0xf841 */ { false, 0xf841, 0xf841 }, +/* 0xf842 */ { false, 0xf842, 0xf842 }, +/* 0xf843 */ { false, 0xf843, 0xf843 }, +/* 0xf844 */ { false, 0xf844, 0xf844 }, +/* 0xf845 */ { false, 0xf845, 0xf845 }, +/* 0xf846 */ { false, 0xf846, 0xf846 }, +/* 0xf847 */ { false, 0xf847, 0xf847 }, +/* 0xf848 */ { false, 0xf848, 0xf848 }, +/* 0xf849 */ { false, 0xf849, 0xf849 }, +/* 0xf84a */ { false, 0xf84a, 0xf84a }, +/* 0xf84b */ { false, 0xf84b, 0xf84b }, +/* 0xf84c */ { false, 0xf84c, 0xf84c }, +/* 0xf84d */ { false, 0xf84d, 0xf84d }, +/* 0xf84e */ { false, 0xf84e, 0xf84e }, +/* 0xf84f */ { false, 0xf84f, 0xf84f }, +/* 0xf850 */ { false, 0xf850, 0xf850 }, +/* 0xf851 */ { false, 0xf851, 0xf851 }, +/* 0xf852 */ { false, 0xf852, 0xf852 }, +/* 0xf853 */ { false, 0xf853, 0xf853 }, +/* 0xf854 */ { false, 0xf854, 0xf854 }, +/* 0xf855 */ { false, 0xf855, 0xf855 }, +/* 0xf856 */ { false, 0xf856, 0xf856 }, +/* 0xf857 */ { false, 0xf857, 0xf857 }, +/* 0xf858 */ { false, 0xf858, 0xf858 }, +/* 0xf859 */ { false, 0xf859, 0xf859 }, +/* 0xf85a */ { false, 0xf85a, 0xf85a }, +/* 0xf85b */ { false, 0xf85b, 0xf85b }, +/* 0xf85c */ { false, 0xf85c, 0xf85c }, +/* 0xf85d */ { false, 0xf85d, 0xf85d }, +/* 0xf85e */ { false, 0xf85e, 0xf85e }, +/* 0xf85f */ { false, 0xf85f, 0xf85f }, +/* 0xf860 */ { false, 0xf860, 0xf860 }, +/* 0xf861 */ { false, 0xf861, 0xf861 }, +/* 0xf862 */ { false, 0xf862, 0xf862 }, +/* 0xf863 */ { false, 0xf863, 0xf863 }, +/* 0xf864 */ { false, 0xf864, 0xf864 }, +/* 0xf865 */ { false, 0xf865, 0xf865 }, +/* 0xf866 */ { false, 0xf866, 0xf866 }, +/* 0xf867 */ { false, 0xf867, 0xf867 }, +/* 0xf868 */ { false, 0xf868, 0xf868 }, +/* 0xf869 */ { false, 0xf869, 0xf869 }, +/* 0xf86a */ { false, 0xf86a, 0xf86a }, +/* 0xf86b */ { false, 0xf86b, 0xf86b }, +/* 0xf86c */ { false, 0xf86c, 0xf86c }, +/* 0xf86d */ { false, 0xf86d, 0xf86d }, +/* 0xf86e */ { false, 0xf86e, 0xf86e }, +/* 0xf86f */ { false, 0xf86f, 0xf86f }, +/* 0xf870 */ { false, 0xf870, 0xf870 }, +/* 0xf871 */ { false, 0xf871, 0xf871 }, +/* 0xf872 */ { false, 0xf872, 0xf872 }, +/* 0xf873 */ { false, 0xf873, 0xf873 }, +/* 0xf874 */ { false, 0xf874, 0xf874 }, +/* 0xf875 */ { false, 0xf875, 0xf875 }, +/* 0xf876 */ { false, 0xf876, 0xf876 }, +/* 0xf877 */ { false, 0xf877, 0xf877 }, +/* 0xf878 */ { false, 0xf878, 0xf878 }, +/* 0xf879 */ { false, 0xf879, 0xf879 }, +/* 0xf87a */ { false, 0xf87a, 0xf87a }, +/* 0xf87b */ { false, 0xf87b, 0xf87b }, +/* 0xf87c */ { false, 0xf87c, 0xf87c }, +/* 0xf87d */ { false, 0xf87d, 0xf87d }, +/* 0xf87e */ { false, 0xf87e, 0xf87e }, +/* 0xf87f */ { false, 0xf87f, 0xf87f }, +/* 0xf880 */ { false, 0xf880, 0xf880 }, +/* 0xf881 */ { false, 0xf881, 0xf881 }, +/* 0xf882 */ { false, 0xf882, 0xf882 }, +/* 0xf883 */ { false, 0xf883, 0xf883 }, +/* 0xf884 */ { false, 0xf884, 0xf884 }, +/* 0xf885 */ { false, 0xf885, 0xf885 }, +/* 0xf886 */ { false, 0xf886, 0xf886 }, +/* 0xf887 */ { false, 0xf887, 0xf887 }, +/* 0xf888 */ { false, 0xf888, 0xf888 }, +/* 0xf889 */ { false, 0xf889, 0xf889 }, +/* 0xf88a */ { false, 0xf88a, 0xf88a }, +/* 0xf88b */ { false, 0xf88b, 0xf88b }, +/* 0xf88c */ { false, 0xf88c, 0xf88c }, +/* 0xf88d */ { false, 0xf88d, 0xf88d }, +/* 0xf88e */ { false, 0xf88e, 0xf88e }, +/* 0xf88f */ { false, 0xf88f, 0xf88f }, +/* 0xf890 */ { false, 0xf890, 0xf890 }, +/* 0xf891 */ { false, 0xf891, 0xf891 }, +/* 0xf892 */ { false, 0xf892, 0xf892 }, +/* 0xf893 */ { false, 0xf893, 0xf893 }, +/* 0xf894 */ { false, 0xf894, 0xf894 }, +/* 0xf895 */ { false, 0xf895, 0xf895 }, +/* 0xf896 */ { false, 0xf896, 0xf896 }, +/* 0xf897 */ { false, 0xf897, 0xf897 }, +/* 0xf898 */ { false, 0xf898, 0xf898 }, +/* 0xf899 */ { false, 0xf899, 0xf899 }, +/* 0xf89a */ { false, 0xf89a, 0xf89a }, +/* 0xf89b */ { false, 0xf89b, 0xf89b }, +/* 0xf89c */ { false, 0xf89c, 0xf89c }, +/* 0xf89d */ { false, 0xf89d, 0xf89d }, +/* 0xf89e */ { false, 0xf89e, 0xf89e }, +/* 0xf89f */ { false, 0xf89f, 0xf89f }, +/* 0xf8a0 */ { false, 0xf8a0, 0xf8a0 }, +/* 0xf8a1 */ { false, 0xf8a1, 0xf8a1 }, +/* 0xf8a2 */ { false, 0xf8a2, 0xf8a2 }, +/* 0xf8a3 */ { false, 0xf8a3, 0xf8a3 }, +/* 0xf8a4 */ { false, 0xf8a4, 0xf8a4 }, +/* 0xf8a5 */ { false, 0xf8a5, 0xf8a5 }, +/* 0xf8a6 */ { false, 0xf8a6, 0xf8a6 }, +/* 0xf8a7 */ { false, 0xf8a7, 0xf8a7 }, +/* 0xf8a8 */ { false, 0xf8a8, 0xf8a8 }, +/* 0xf8a9 */ { false, 0xf8a9, 0xf8a9 }, +/* 0xf8aa */ { false, 0xf8aa, 0xf8aa }, +/* 0xf8ab */ { false, 0xf8ab, 0xf8ab }, +/* 0xf8ac */ { false, 0xf8ac, 0xf8ac }, +/* 0xf8ad */ { false, 0xf8ad, 0xf8ad }, +/* 0xf8ae */ { false, 0xf8ae, 0xf8ae }, +/* 0xf8af */ { false, 0xf8af, 0xf8af }, +/* 0xf8b0 */ { false, 0xf8b0, 0xf8b0 }, +/* 0xf8b1 */ { false, 0xf8b1, 0xf8b1 }, +/* 0xf8b2 */ { false, 0xf8b2, 0xf8b2 }, +/* 0xf8b3 */ { false, 0xf8b3, 0xf8b3 }, +/* 0xf8b4 */ { false, 0xf8b4, 0xf8b4 }, +/* 0xf8b5 */ { false, 0xf8b5, 0xf8b5 }, +/* 0xf8b6 */ { false, 0xf8b6, 0xf8b6 }, +/* 0xf8b7 */ { false, 0xf8b7, 0xf8b7 }, +/* 0xf8b8 */ { false, 0xf8b8, 0xf8b8 }, +/* 0xf8b9 */ { false, 0xf8b9, 0xf8b9 }, +/* 0xf8ba */ { false, 0xf8ba, 0xf8ba }, +/* 0xf8bb */ { false, 0xf8bb, 0xf8bb }, +/* 0xf8bc */ { false, 0xf8bc, 0xf8bc }, +/* 0xf8bd */ { false, 0xf8bd, 0xf8bd }, +/* 0xf8be */ { false, 0xf8be, 0xf8be }, +/* 0xf8bf */ { false, 0xf8bf, 0xf8bf }, +/* 0xf8c0 */ { false, 0xf8c0, 0xf8c0 }, +/* 0xf8c1 */ { false, 0xf8c1, 0xf8c1 }, +/* 0xf8c2 */ { false, 0xf8c2, 0xf8c2 }, +/* 0xf8c3 */ { false, 0xf8c3, 0xf8c3 }, +/* 0xf8c4 */ { false, 0xf8c4, 0xf8c4 }, +/* 0xf8c5 */ { false, 0xf8c5, 0xf8c5 }, +/* 0xf8c6 */ { false, 0xf8c6, 0xf8c6 }, +/* 0xf8c7 */ { false, 0xf8c7, 0xf8c7 }, +/* 0xf8c8 */ { false, 0xf8c8, 0xf8c8 }, +/* 0xf8c9 */ { false, 0xf8c9, 0xf8c9 }, +/* 0xf8ca */ { false, 0xf8ca, 0xf8ca }, +/* 0xf8cb */ { false, 0xf8cb, 0xf8cb }, +/* 0xf8cc */ { false, 0xf8cc, 0xf8cc }, +/* 0xf8cd */ { false, 0xf8cd, 0xf8cd }, +/* 0xf8ce */ { false, 0xf8ce, 0xf8ce }, +/* 0xf8cf */ { false, 0xf8cf, 0xf8cf }, +/* 0xf8d0 */ { false, 0xf8d0, 0xf8d0 }, +/* 0xf8d1 */ { false, 0xf8d1, 0xf8d1 }, +/* 0xf8d2 */ { false, 0xf8d2, 0xf8d2 }, +/* 0xf8d3 */ { false, 0xf8d3, 0xf8d3 }, +/* 0xf8d4 */ { false, 0xf8d4, 0xf8d4 }, +/* 0xf8d5 */ { false, 0xf8d5, 0xf8d5 }, +/* 0xf8d6 */ { false, 0xf8d6, 0xf8d6 }, +/* 0xf8d7 */ { false, 0xf8d7, 0xf8d7 }, +/* 0xf8d8 */ { false, 0xf8d8, 0xf8d8 }, +/* 0xf8d9 */ { false, 0xf8d9, 0xf8d9 }, +/* 0xf8da */ { false, 0xf8da, 0xf8da }, +/* 0xf8db */ { false, 0xf8db, 0xf8db }, +/* 0xf8dc */ { false, 0xf8dc, 0xf8dc }, +/* 0xf8dd */ { false, 0xf8dd, 0xf8dd }, +/* 0xf8de */ { false, 0xf8de, 0xf8de }, +/* 0xf8df */ { false, 0xf8df, 0xf8df }, +/* 0xf8e0 */ { false, 0xf8e0, 0xf8e0 }, +/* 0xf8e1 */ { false, 0xf8e1, 0xf8e1 }, +/* 0xf8e2 */ { false, 0xf8e2, 0xf8e2 }, +/* 0xf8e3 */ { false, 0xf8e3, 0xf8e3 }, +/* 0xf8e4 */ { false, 0xf8e4, 0xf8e4 }, +/* 0xf8e5 */ { false, 0xf8e5, 0xf8e5 }, +/* 0xf8e6 */ { false, 0xf8e6, 0xf8e6 }, +/* 0xf8e7 */ { false, 0xf8e7, 0xf8e7 }, +/* 0xf8e8 */ { false, 0xf8e8, 0xf8e8 }, +/* 0xf8e9 */ { false, 0xf8e9, 0xf8e9 }, +/* 0xf8ea */ { false, 0xf8ea, 0xf8ea }, +/* 0xf8eb */ { false, 0xf8eb, 0xf8eb }, +/* 0xf8ec */ { false, 0xf8ec, 0xf8ec }, +/* 0xf8ed */ { false, 0xf8ed, 0xf8ed }, +/* 0xf8ee */ { false, 0xf8ee, 0xf8ee }, +/* 0xf8ef */ { false, 0xf8ef, 0xf8ef }, +/* 0xf8f0 */ { false, 0xf8f0, 0xf8f0 }, +/* 0xf8f1 */ { false, 0xf8f1, 0xf8f1 }, +/* 0xf8f2 */ { false, 0xf8f2, 0xf8f2 }, +/* 0xf8f3 */ { false, 0xf8f3, 0xf8f3 }, +/* 0xf8f4 */ { false, 0xf8f4, 0xf8f4 }, +/* 0xf8f5 */ { false, 0xf8f5, 0xf8f5 }, +/* 0xf8f6 */ { false, 0xf8f6, 0xf8f6 }, +/* 0xf8f7 */ { false, 0xf8f7, 0xf8f7 }, +/* 0xf8f8 */ { false, 0xf8f8, 0xf8f8 }, +/* 0xf8f9 */ { false, 0xf8f9, 0xf8f9 }, +/* 0xf8fa */ { false, 0xf8fa, 0xf8fa }, +/* 0xf8fb */ { false, 0xf8fb, 0xf8fb }, +/* 0xf8fc */ { false, 0xf8fc, 0xf8fc }, +/* 0xf8fd */ { false, 0xf8fd, 0xf8fd }, +/* 0xf8fe */ { false, 0xf8fe, 0xf8fe }, +/* 0xf8ff */ { false, 0xf8ff, 0xf8ff }, +/* 0xf900 */ { true, 0xf900, 0xf900 }, +/* 0xf901 */ { true, 0xf901, 0xf901 }, +/* 0xf902 */ { true, 0xf902, 0xf902 }, +/* 0xf903 */ { true, 0xf903, 0xf903 }, +/* 0xf904 */ { true, 0xf904, 0xf904 }, +/* 0xf905 */ { true, 0xf905, 0xf905 }, +/* 0xf906 */ { true, 0xf906, 0xf906 }, +/* 0xf907 */ { true, 0xf907, 0xf907 }, +/* 0xf908 */ { true, 0xf908, 0xf908 }, +/* 0xf909 */ { true, 0xf909, 0xf909 }, +/* 0xf90a */ { true, 0xf90a, 0xf90a }, +/* 0xf90b */ { true, 0xf90b, 0xf90b }, +/* 0xf90c */ { true, 0xf90c, 0xf90c }, +/* 0xf90d */ { true, 0xf90d, 0xf90d }, +/* 0xf90e */ { true, 0xf90e, 0xf90e }, +/* 0xf90f */ { true, 0xf90f, 0xf90f }, +/* 0xf910 */ { true, 0xf910, 0xf910 }, +/* 0xf911 */ { true, 0xf911, 0xf911 }, +/* 0xf912 */ { true, 0xf912, 0xf912 }, +/* 0xf913 */ { true, 0xf913, 0xf913 }, +/* 0xf914 */ { true, 0xf914, 0xf914 }, +/* 0xf915 */ { true, 0xf915, 0xf915 }, +/* 0xf916 */ { true, 0xf916, 0xf916 }, +/* 0xf917 */ { true, 0xf917, 0xf917 }, +/* 0xf918 */ { true, 0xf918, 0xf918 }, +/* 0xf919 */ { true, 0xf919, 0xf919 }, +/* 0xf91a */ { true, 0xf91a, 0xf91a }, +/* 0xf91b */ { true, 0xf91b, 0xf91b }, +/* 0xf91c */ { true, 0xf91c, 0xf91c }, +/* 0xf91d */ { true, 0xf91d, 0xf91d }, +/* 0xf91e */ { true, 0xf91e, 0xf91e }, +/* 0xf91f */ { true, 0xf91f, 0xf91f }, +/* 0xf920 */ { true, 0xf920, 0xf920 }, +/* 0xf921 */ { true, 0xf921, 0xf921 }, +/* 0xf922 */ { true, 0xf922, 0xf922 }, +/* 0xf923 */ { true, 0xf923, 0xf923 }, +/* 0xf924 */ { true, 0xf924, 0xf924 }, +/* 0xf925 */ { true, 0xf925, 0xf925 }, +/* 0xf926 */ { true, 0xf926, 0xf926 }, +/* 0xf927 */ { true, 0xf927, 0xf927 }, +/* 0xf928 */ { true, 0xf928, 0xf928 }, +/* 0xf929 */ { true, 0xf929, 0xf929 }, +/* 0xf92a */ { true, 0xf92a, 0xf92a }, +/* 0xf92b */ { true, 0xf92b, 0xf92b }, +/* 0xf92c */ { true, 0xf92c, 0xf92c }, +/* 0xf92d */ { true, 0xf92d, 0xf92d }, +/* 0xf92e */ { true, 0xf92e, 0xf92e }, +/* 0xf92f */ { true, 0xf92f, 0xf92f }, +/* 0xf930 */ { true, 0xf930, 0xf930 }, +/* 0xf931 */ { true, 0xf931, 0xf931 }, +/* 0xf932 */ { true, 0xf932, 0xf932 }, +/* 0xf933 */ { true, 0xf933, 0xf933 }, +/* 0xf934 */ { true, 0xf934, 0xf934 }, +/* 0xf935 */ { true, 0xf935, 0xf935 }, +/* 0xf936 */ { true, 0xf936, 0xf936 }, +/* 0xf937 */ { true, 0xf937, 0xf937 }, +/* 0xf938 */ { true, 0xf938, 0xf938 }, +/* 0xf939 */ { true, 0xf939, 0xf939 }, +/* 0xf93a */ { true, 0xf93a, 0xf93a }, +/* 0xf93b */ { true, 0xf93b, 0xf93b }, +/* 0xf93c */ { true, 0xf93c, 0xf93c }, +/* 0xf93d */ { true, 0xf93d, 0xf93d }, +/* 0xf93e */ { true, 0xf93e, 0xf93e }, +/* 0xf93f */ { true, 0xf93f, 0xf93f }, +/* 0xf940 */ { true, 0xf940, 0xf940 }, +/* 0xf941 */ { true, 0xf941, 0xf941 }, +/* 0xf942 */ { true, 0xf942, 0xf942 }, +/* 0xf943 */ { true, 0xf943, 0xf943 }, +/* 0xf944 */ { true, 0xf944, 0xf944 }, +/* 0xf945 */ { true, 0xf945, 0xf945 }, +/* 0xf946 */ { true, 0xf946, 0xf946 }, +/* 0xf947 */ { true, 0xf947, 0xf947 }, +/* 0xf948 */ { true, 0xf948, 0xf948 }, +/* 0xf949 */ { true, 0xf949, 0xf949 }, +/* 0xf94a */ { true, 0xf94a, 0xf94a }, +/* 0xf94b */ { true, 0xf94b, 0xf94b }, +/* 0xf94c */ { true, 0xf94c, 0xf94c }, +/* 0xf94d */ { true, 0xf94d, 0xf94d }, +/* 0xf94e */ { true, 0xf94e, 0xf94e }, +/* 0xf94f */ { true, 0xf94f, 0xf94f }, +/* 0xf950 */ { true, 0xf950, 0xf950 }, +/* 0xf951 */ { true, 0xf951, 0xf951 }, +/* 0xf952 */ { true, 0xf952, 0xf952 }, +/* 0xf953 */ { true, 0xf953, 0xf953 }, +/* 0xf954 */ { true, 0xf954, 0xf954 }, +/* 0xf955 */ { true, 0xf955, 0xf955 }, +/* 0xf956 */ { true, 0xf956, 0xf956 }, +/* 0xf957 */ { true, 0xf957, 0xf957 }, +/* 0xf958 */ { true, 0xf958, 0xf958 }, +/* 0xf959 */ { true, 0xf959, 0xf959 }, +/* 0xf95a */ { true, 0xf95a, 0xf95a }, +/* 0xf95b */ { true, 0xf95b, 0xf95b }, +/* 0xf95c */ { true, 0xf95c, 0xf95c }, +/* 0xf95d */ { true, 0xf95d, 0xf95d }, +/* 0xf95e */ { true, 0xf95e, 0xf95e }, +/* 0xf95f */ { true, 0xf95f, 0xf95f }, +/* 0xf960 */ { true, 0xf960, 0xf960 }, +/* 0xf961 */ { true, 0xf961, 0xf961 }, +/* 0xf962 */ { true, 0xf962, 0xf962 }, +/* 0xf963 */ { true, 0xf963, 0xf963 }, +/* 0xf964 */ { true, 0xf964, 0xf964 }, +/* 0xf965 */ { true, 0xf965, 0xf965 }, +/* 0xf966 */ { true, 0xf966, 0xf966 }, +/* 0xf967 */ { true, 0xf967, 0xf967 }, +/* 0xf968 */ { true, 0xf968, 0xf968 }, +/* 0xf969 */ { true, 0xf969, 0xf969 }, +/* 0xf96a */ { true, 0xf96a, 0xf96a }, +/* 0xf96b */ { true, 0xf96b, 0xf96b }, +/* 0xf96c */ { true, 0xf96c, 0xf96c }, +/* 0xf96d */ { true, 0xf96d, 0xf96d }, +/* 0xf96e */ { true, 0xf96e, 0xf96e }, +/* 0xf96f */ { true, 0xf96f, 0xf96f }, +/* 0xf970 */ { true, 0xf970, 0xf970 }, +/* 0xf971 */ { true, 0xf971, 0xf971 }, +/* 0xf972 */ { true, 0xf972, 0xf972 }, +/* 0xf973 */ { true, 0xf973, 0xf973 }, +/* 0xf974 */ { true, 0xf974, 0xf974 }, +/* 0xf975 */ { true, 0xf975, 0xf975 }, +/* 0xf976 */ { true, 0xf976, 0xf976 }, +/* 0xf977 */ { true, 0xf977, 0xf977 }, +/* 0xf978 */ { true, 0xf978, 0xf978 }, +/* 0xf979 */ { true, 0xf979, 0xf979 }, +/* 0xf97a */ { true, 0xf97a, 0xf97a }, +/* 0xf97b */ { true, 0xf97b, 0xf97b }, +/* 0xf97c */ { true, 0xf97c, 0xf97c }, +/* 0xf97d */ { true, 0xf97d, 0xf97d }, +/* 0xf97e */ { true, 0xf97e, 0xf97e }, +/* 0xf97f */ { true, 0xf97f, 0xf97f }, +/* 0xf980 */ { true, 0xf980, 0xf980 }, +/* 0xf981 */ { true, 0xf981, 0xf981 }, +/* 0xf982 */ { true, 0xf982, 0xf982 }, +/* 0xf983 */ { true, 0xf983, 0xf983 }, +/* 0xf984 */ { true, 0xf984, 0xf984 }, +/* 0xf985 */ { true, 0xf985, 0xf985 }, +/* 0xf986 */ { true, 0xf986, 0xf986 }, +/* 0xf987 */ { true, 0xf987, 0xf987 }, +/* 0xf988 */ { true, 0xf988, 0xf988 }, +/* 0xf989 */ { true, 0xf989, 0xf989 }, +/* 0xf98a */ { true, 0xf98a, 0xf98a }, +/* 0xf98b */ { true, 0xf98b, 0xf98b }, +/* 0xf98c */ { true, 0xf98c, 0xf98c }, +/* 0xf98d */ { true, 0xf98d, 0xf98d }, +/* 0xf98e */ { true, 0xf98e, 0xf98e }, +/* 0xf98f */ { true, 0xf98f, 0xf98f }, +/* 0xf990 */ { true, 0xf990, 0xf990 }, +/* 0xf991 */ { true, 0xf991, 0xf991 }, +/* 0xf992 */ { true, 0xf992, 0xf992 }, +/* 0xf993 */ { true, 0xf993, 0xf993 }, +/* 0xf994 */ { true, 0xf994, 0xf994 }, +/* 0xf995 */ { true, 0xf995, 0xf995 }, +/* 0xf996 */ { true, 0xf996, 0xf996 }, +/* 0xf997 */ { true, 0xf997, 0xf997 }, +/* 0xf998 */ { true, 0xf998, 0xf998 }, +/* 0xf999 */ { true, 0xf999, 0xf999 }, +/* 0xf99a */ { true, 0xf99a, 0xf99a }, +/* 0xf99b */ { true, 0xf99b, 0xf99b }, +/* 0xf99c */ { true, 0xf99c, 0xf99c }, +/* 0xf99d */ { true, 0xf99d, 0xf99d }, +/* 0xf99e */ { true, 0xf99e, 0xf99e }, +/* 0xf99f */ { true, 0xf99f, 0xf99f }, +/* 0xf9a0 */ { true, 0xf9a0, 0xf9a0 }, +/* 0xf9a1 */ { true, 0xf9a1, 0xf9a1 }, +/* 0xf9a2 */ { true, 0xf9a2, 0xf9a2 }, +/* 0xf9a3 */ { true, 0xf9a3, 0xf9a3 }, +/* 0xf9a4 */ { true, 0xf9a4, 0xf9a4 }, +/* 0xf9a5 */ { true, 0xf9a5, 0xf9a5 }, +/* 0xf9a6 */ { true, 0xf9a6, 0xf9a6 }, +/* 0xf9a7 */ { true, 0xf9a7, 0xf9a7 }, +/* 0xf9a8 */ { true, 0xf9a8, 0xf9a8 }, +/* 0xf9a9 */ { true, 0xf9a9, 0xf9a9 }, +/* 0xf9aa */ { true, 0xf9aa, 0xf9aa }, +/* 0xf9ab */ { true, 0xf9ab, 0xf9ab }, +/* 0xf9ac */ { true, 0xf9ac, 0xf9ac }, +/* 0xf9ad */ { true, 0xf9ad, 0xf9ad }, +/* 0xf9ae */ { true, 0xf9ae, 0xf9ae }, +/* 0xf9af */ { true, 0xf9af, 0xf9af }, +/* 0xf9b0 */ { true, 0xf9b0, 0xf9b0 }, +/* 0xf9b1 */ { true, 0xf9b1, 0xf9b1 }, +/* 0xf9b2 */ { true, 0xf9b2, 0xf9b2 }, +/* 0xf9b3 */ { true, 0xf9b3, 0xf9b3 }, +/* 0xf9b4 */ { true, 0xf9b4, 0xf9b4 }, +/* 0xf9b5 */ { true, 0xf9b5, 0xf9b5 }, +/* 0xf9b6 */ { true, 0xf9b6, 0xf9b6 }, +/* 0xf9b7 */ { true, 0xf9b7, 0xf9b7 }, +/* 0xf9b8 */ { true, 0xf9b8, 0xf9b8 }, +/* 0xf9b9 */ { true, 0xf9b9, 0xf9b9 }, +/* 0xf9ba */ { true, 0xf9ba, 0xf9ba }, +/* 0xf9bb */ { true, 0xf9bb, 0xf9bb }, +/* 0xf9bc */ { true, 0xf9bc, 0xf9bc }, +/* 0xf9bd */ { true, 0xf9bd, 0xf9bd }, +/* 0xf9be */ { true, 0xf9be, 0xf9be }, +/* 0xf9bf */ { true, 0xf9bf, 0xf9bf }, +/* 0xf9c0 */ { true, 0xf9c0, 0xf9c0 }, +/* 0xf9c1 */ { true, 0xf9c1, 0xf9c1 }, +/* 0xf9c2 */ { true, 0xf9c2, 0xf9c2 }, +/* 0xf9c3 */ { true, 0xf9c3, 0xf9c3 }, +/* 0xf9c4 */ { true, 0xf9c4, 0xf9c4 }, +/* 0xf9c5 */ { true, 0xf9c5, 0xf9c5 }, +/* 0xf9c6 */ { true, 0xf9c6, 0xf9c6 }, +/* 0xf9c7 */ { true, 0xf9c7, 0xf9c7 }, +/* 0xf9c8 */ { true, 0xf9c8, 0xf9c8 }, +/* 0xf9c9 */ { true, 0xf9c9, 0xf9c9 }, +/* 0xf9ca */ { true, 0xf9ca, 0xf9ca }, +/* 0xf9cb */ { true, 0xf9cb, 0xf9cb }, +/* 0xf9cc */ { true, 0xf9cc, 0xf9cc }, +/* 0xf9cd */ { true, 0xf9cd, 0xf9cd }, +/* 0xf9ce */ { true, 0xf9ce, 0xf9ce }, +/* 0xf9cf */ { true, 0xf9cf, 0xf9cf }, +/* 0xf9d0 */ { true, 0xf9d0, 0xf9d0 }, +/* 0xf9d1 */ { true, 0xf9d1, 0xf9d1 }, +/* 0xf9d2 */ { true, 0xf9d2, 0xf9d2 }, +/* 0xf9d3 */ { true, 0xf9d3, 0xf9d3 }, +/* 0xf9d4 */ { true, 0xf9d4, 0xf9d4 }, +/* 0xf9d5 */ { true, 0xf9d5, 0xf9d5 }, +/* 0xf9d6 */ { true, 0xf9d6, 0xf9d6 }, +/* 0xf9d7 */ { true, 0xf9d7, 0xf9d7 }, +/* 0xf9d8 */ { true, 0xf9d8, 0xf9d8 }, +/* 0xf9d9 */ { true, 0xf9d9, 0xf9d9 }, +/* 0xf9da */ { true, 0xf9da, 0xf9da }, +/* 0xf9db */ { true, 0xf9db, 0xf9db }, +/* 0xf9dc */ { true, 0xf9dc, 0xf9dc }, +/* 0xf9dd */ { true, 0xf9dd, 0xf9dd }, +/* 0xf9de */ { true, 0xf9de, 0xf9de }, +/* 0xf9df */ { true, 0xf9df, 0xf9df }, +/* 0xf9e0 */ { true, 0xf9e0, 0xf9e0 }, +/* 0xf9e1 */ { true, 0xf9e1, 0xf9e1 }, +/* 0xf9e2 */ { true, 0xf9e2, 0xf9e2 }, +/* 0xf9e3 */ { true, 0xf9e3, 0xf9e3 }, +/* 0xf9e4 */ { true, 0xf9e4, 0xf9e4 }, +/* 0xf9e5 */ { true, 0xf9e5, 0xf9e5 }, +/* 0xf9e6 */ { true, 0xf9e6, 0xf9e6 }, +/* 0xf9e7 */ { true, 0xf9e7, 0xf9e7 }, +/* 0xf9e8 */ { true, 0xf9e8, 0xf9e8 }, +/* 0xf9e9 */ { true, 0xf9e9, 0xf9e9 }, +/* 0xf9ea */ { true, 0xf9ea, 0xf9ea }, +/* 0xf9eb */ { true, 0xf9eb, 0xf9eb }, +/* 0xf9ec */ { true, 0xf9ec, 0xf9ec }, +/* 0xf9ed */ { true, 0xf9ed, 0xf9ed }, +/* 0xf9ee */ { true, 0xf9ee, 0xf9ee }, +/* 0xf9ef */ { true, 0xf9ef, 0xf9ef }, +/* 0xf9f0 */ { true, 0xf9f0, 0xf9f0 }, +/* 0xf9f1 */ { true, 0xf9f1, 0xf9f1 }, +/* 0xf9f2 */ { true, 0xf9f2, 0xf9f2 }, +/* 0xf9f3 */ { true, 0xf9f3, 0xf9f3 }, +/* 0xf9f4 */ { true, 0xf9f4, 0xf9f4 }, +/* 0xf9f5 */ { true, 0xf9f5, 0xf9f5 }, +/* 0xf9f6 */ { true, 0xf9f6, 0xf9f6 }, +/* 0xf9f7 */ { true, 0xf9f7, 0xf9f7 }, +/* 0xf9f8 */ { true, 0xf9f8, 0xf9f8 }, +/* 0xf9f9 */ { true, 0xf9f9, 0xf9f9 }, +/* 0xf9fa */ { true, 0xf9fa, 0xf9fa }, +/* 0xf9fb */ { true, 0xf9fb, 0xf9fb }, +/* 0xf9fc */ { true, 0xf9fc, 0xf9fc }, +/* 0xf9fd */ { true, 0xf9fd, 0xf9fd }, +/* 0xf9fe */ { true, 0xf9fe, 0xf9fe }, +/* 0xf9ff */ { true, 0xf9ff, 0xf9ff }, +/* 0xfa00 */ { true, 0xfa00, 0xfa00 }, +/* 0xfa01 */ { true, 0xfa01, 0xfa01 }, +/* 0xfa02 */ { true, 0xfa02, 0xfa02 }, +/* 0xfa03 */ { true, 0xfa03, 0xfa03 }, +/* 0xfa04 */ { true, 0xfa04, 0xfa04 }, +/* 0xfa05 */ { true, 0xfa05, 0xfa05 }, +/* 0xfa06 */ { true, 0xfa06, 0xfa06 }, +/* 0xfa07 */ { true, 0xfa07, 0xfa07 }, +/* 0xfa08 */ { true, 0xfa08, 0xfa08 }, +/* 0xfa09 */ { true, 0xfa09, 0xfa09 }, +/* 0xfa0a */ { true, 0xfa0a, 0xfa0a }, +/* 0xfa0b */ { true, 0xfa0b, 0xfa0b }, +/* 0xfa0c */ { true, 0xfa0c, 0xfa0c }, +/* 0xfa0d */ { true, 0xfa0d, 0xfa0d }, +/* 0xfa0e */ { true, 0xfa0e, 0xfa0e }, +/* 0xfa0f */ { true, 0xfa0f, 0xfa0f }, +/* 0xfa10 */ { true, 0xfa10, 0xfa10 }, +/* 0xfa11 */ { true, 0xfa11, 0xfa11 }, +/* 0xfa12 */ { true, 0xfa12, 0xfa12 }, +/* 0xfa13 */ { true, 0xfa13, 0xfa13 }, +/* 0xfa14 */ { true, 0xfa14, 0xfa14 }, +/* 0xfa15 */ { true, 0xfa15, 0xfa15 }, +/* 0xfa16 */ { true, 0xfa16, 0xfa16 }, +/* 0xfa17 */ { true, 0xfa17, 0xfa17 }, +/* 0xfa18 */ { true, 0xfa18, 0xfa18 }, +/* 0xfa19 */ { true, 0xfa19, 0xfa19 }, +/* 0xfa1a */ { true, 0xfa1a, 0xfa1a }, +/* 0xfa1b */ { true, 0xfa1b, 0xfa1b }, +/* 0xfa1c */ { true, 0xfa1c, 0xfa1c }, +/* 0xfa1d */ { true, 0xfa1d, 0xfa1d }, +/* 0xfa1e */ { true, 0xfa1e, 0xfa1e }, +/* 0xfa1f */ { true, 0xfa1f, 0xfa1f }, +/* 0xfa20 */ { true, 0xfa20, 0xfa20 }, +/* 0xfa21 */ { true, 0xfa21, 0xfa21 }, +/* 0xfa22 */ { true, 0xfa22, 0xfa22 }, +/* 0xfa23 */ { true, 0xfa23, 0xfa23 }, +/* 0xfa24 */ { true, 0xfa24, 0xfa24 }, +/* 0xfa25 */ { true, 0xfa25, 0xfa25 }, +/* 0xfa26 */ { true, 0xfa26, 0xfa26 }, +/* 0xfa27 */ { true, 0xfa27, 0xfa27 }, +/* 0xfa28 */ { true, 0xfa28, 0xfa28 }, +/* 0xfa29 */ { true, 0xfa29, 0xfa29 }, +/* 0xfa2a */ { true, 0xfa2a, 0xfa2a }, +/* 0xfa2b */ { true, 0xfa2b, 0xfa2b }, +/* 0xfa2c */ { true, 0xfa2c, 0xfa2c }, +/* 0xfa2d */ { true, 0xfa2d, 0xfa2d }, +/* 0xfa2e */ { false, 0xfa2e, 0xfa2e }, +/* 0xfa2f */ { false, 0xfa2f, 0xfa2f }, +/* 0xfa30 */ { true, 0xfa30, 0xfa30 }, +/* 0xfa31 */ { true, 0xfa31, 0xfa31 }, +/* 0xfa32 */ { true, 0xfa32, 0xfa32 }, +/* 0xfa33 */ { true, 0xfa33, 0xfa33 }, +/* 0xfa34 */ { true, 0xfa34, 0xfa34 }, +/* 0xfa35 */ { true, 0xfa35, 0xfa35 }, +/* 0xfa36 */ { true, 0xfa36, 0xfa36 }, +/* 0xfa37 */ { true, 0xfa37, 0xfa37 }, +/* 0xfa38 */ { true, 0xfa38, 0xfa38 }, +/* 0xfa39 */ { true, 0xfa39, 0xfa39 }, +/* 0xfa3a */ { true, 0xfa3a, 0xfa3a }, +/* 0xfa3b */ { true, 0xfa3b, 0xfa3b }, +/* 0xfa3c */ { true, 0xfa3c, 0xfa3c }, +/* 0xfa3d */ { true, 0xfa3d, 0xfa3d }, +/* 0xfa3e */ { true, 0xfa3e, 0xfa3e }, +/* 0xfa3f */ { true, 0xfa3f, 0xfa3f }, +/* 0xfa40 */ { true, 0xfa40, 0xfa40 }, +/* 0xfa41 */ { true, 0xfa41, 0xfa41 }, +/* 0xfa42 */ { true, 0xfa42, 0xfa42 }, +/* 0xfa43 */ { true, 0xfa43, 0xfa43 }, +/* 0xfa44 */ { true, 0xfa44, 0xfa44 }, +/* 0xfa45 */ { true, 0xfa45, 0xfa45 }, +/* 0xfa46 */ { true, 0xfa46, 0xfa46 }, +/* 0xfa47 */ { true, 0xfa47, 0xfa47 }, +/* 0xfa48 */ { true, 0xfa48, 0xfa48 }, +/* 0xfa49 */ { true, 0xfa49, 0xfa49 }, +/* 0xfa4a */ { true, 0xfa4a, 0xfa4a }, +/* 0xfa4b */ { true, 0xfa4b, 0xfa4b }, +/* 0xfa4c */ { true, 0xfa4c, 0xfa4c }, +/* 0xfa4d */ { true, 0xfa4d, 0xfa4d }, +/* 0xfa4e */ { true, 0xfa4e, 0xfa4e }, +/* 0xfa4f */ { true, 0xfa4f, 0xfa4f }, +/* 0xfa50 */ { true, 0xfa50, 0xfa50 }, +/* 0xfa51 */ { true, 0xfa51, 0xfa51 }, +/* 0xfa52 */ { true, 0xfa52, 0xfa52 }, +/* 0xfa53 */ { true, 0xfa53, 0xfa53 }, +/* 0xfa54 */ { true, 0xfa54, 0xfa54 }, +/* 0xfa55 */ { true, 0xfa55, 0xfa55 }, +/* 0xfa56 */ { true, 0xfa56, 0xfa56 }, +/* 0xfa57 */ { true, 0xfa57, 0xfa57 }, +/* 0xfa58 */ { true, 0xfa58, 0xfa58 }, +/* 0xfa59 */ { true, 0xfa59, 0xfa59 }, +/* 0xfa5a */ { true, 0xfa5a, 0xfa5a }, +/* 0xfa5b */ { true, 0xfa5b, 0xfa5b }, +/* 0xfa5c */ { true, 0xfa5c, 0xfa5c }, +/* 0xfa5d */ { true, 0xfa5d, 0xfa5d }, +/* 0xfa5e */ { true, 0xfa5e, 0xfa5e }, +/* 0xfa5f */ { true, 0xfa5f, 0xfa5f }, +/* 0xfa60 */ { true, 0xfa60, 0xfa60 }, +/* 0xfa61 */ { true, 0xfa61, 0xfa61 }, +/* 0xfa62 */ { true, 0xfa62, 0xfa62 }, +/* 0xfa63 */ { true, 0xfa63, 0xfa63 }, +/* 0xfa64 */ { true, 0xfa64, 0xfa64 }, +/* 0xfa65 */ { true, 0xfa65, 0xfa65 }, +/* 0xfa66 */ { true, 0xfa66, 0xfa66 }, +/* 0xfa67 */ { true, 0xfa67, 0xfa67 }, +/* 0xfa68 */ { true, 0xfa68, 0xfa68 }, +/* 0xfa69 */ { true, 0xfa69, 0xfa69 }, +/* 0xfa6a */ { true, 0xfa6a, 0xfa6a }, +/* 0xfa6b */ { false, 0xfa6b, 0xfa6b }, +/* 0xfa6c */ { false, 0xfa6c, 0xfa6c }, +/* 0xfa6d */ { false, 0xfa6d, 0xfa6d }, +/* 0xfa6e */ { false, 0xfa6e, 0xfa6e }, +/* 0xfa6f */ { false, 0xfa6f, 0xfa6f }, +/* 0xfa70 */ { true, 0xfa70, 0xfa70 }, +/* 0xfa71 */ { true, 0xfa71, 0xfa71 }, +/* 0xfa72 */ { true, 0xfa72, 0xfa72 }, +/* 0xfa73 */ { true, 0xfa73, 0xfa73 }, +/* 0xfa74 */ { true, 0xfa74, 0xfa74 }, +/* 0xfa75 */ { true, 0xfa75, 0xfa75 }, +/* 0xfa76 */ { true, 0xfa76, 0xfa76 }, +/* 0xfa77 */ { true, 0xfa77, 0xfa77 }, +/* 0xfa78 */ { true, 0xfa78, 0xfa78 }, +/* 0xfa79 */ { true, 0xfa79, 0xfa79 }, +/* 0xfa7a */ { true, 0xfa7a, 0xfa7a }, +/* 0xfa7b */ { true, 0xfa7b, 0xfa7b }, +/* 0xfa7c */ { true, 0xfa7c, 0xfa7c }, +/* 0xfa7d */ { true, 0xfa7d, 0xfa7d }, +/* 0xfa7e */ { true, 0xfa7e, 0xfa7e }, +/* 0xfa7f */ { true, 0xfa7f, 0xfa7f }, +/* 0xfa80 */ { true, 0xfa80, 0xfa80 }, +/* 0xfa81 */ { true, 0xfa81, 0xfa81 }, +/* 0xfa82 */ { true, 0xfa82, 0xfa82 }, +/* 0xfa83 */ { true, 0xfa83, 0xfa83 }, +/* 0xfa84 */ { true, 0xfa84, 0xfa84 }, +/* 0xfa85 */ { true, 0xfa85, 0xfa85 }, +/* 0xfa86 */ { true, 0xfa86, 0xfa86 }, +/* 0xfa87 */ { true, 0xfa87, 0xfa87 }, +/* 0xfa88 */ { true, 0xfa88, 0xfa88 }, +/* 0xfa89 */ { true, 0xfa89, 0xfa89 }, +/* 0xfa8a */ { true, 0xfa8a, 0xfa8a }, +/* 0xfa8b */ { true, 0xfa8b, 0xfa8b }, +/* 0xfa8c */ { true, 0xfa8c, 0xfa8c }, +/* 0xfa8d */ { true, 0xfa8d, 0xfa8d }, +/* 0xfa8e */ { true, 0xfa8e, 0xfa8e }, +/* 0xfa8f */ { true, 0xfa8f, 0xfa8f }, +/* 0xfa90 */ { true, 0xfa90, 0xfa90 }, +/* 0xfa91 */ { true, 0xfa91, 0xfa91 }, +/* 0xfa92 */ { true, 0xfa92, 0xfa92 }, +/* 0xfa93 */ { true, 0xfa93, 0xfa93 }, +/* 0xfa94 */ { true, 0xfa94, 0xfa94 }, +/* 0xfa95 */ { true, 0xfa95, 0xfa95 }, +/* 0xfa96 */ { true, 0xfa96, 0xfa96 }, +/* 0xfa97 */ { true, 0xfa97, 0xfa97 }, +/* 0xfa98 */ { true, 0xfa98, 0xfa98 }, +/* 0xfa99 */ { true, 0xfa99, 0xfa99 }, +/* 0xfa9a */ { true, 0xfa9a, 0xfa9a }, +/* 0xfa9b */ { true, 0xfa9b, 0xfa9b }, +/* 0xfa9c */ { true, 0xfa9c, 0xfa9c }, +/* 0xfa9d */ { true, 0xfa9d, 0xfa9d }, +/* 0xfa9e */ { true, 0xfa9e, 0xfa9e }, +/* 0xfa9f */ { true, 0xfa9f, 0xfa9f }, +/* 0xfaa0 */ { true, 0xfaa0, 0xfaa0 }, +/* 0xfaa1 */ { true, 0xfaa1, 0xfaa1 }, +/* 0xfaa2 */ { true, 0xfaa2, 0xfaa2 }, +/* 0xfaa3 */ { true, 0xfaa3, 0xfaa3 }, +/* 0xfaa4 */ { true, 0xfaa4, 0xfaa4 }, +/* 0xfaa5 */ { true, 0xfaa5, 0xfaa5 }, +/* 0xfaa6 */ { true, 0xfaa6, 0xfaa6 }, +/* 0xfaa7 */ { true, 0xfaa7, 0xfaa7 }, +/* 0xfaa8 */ { true, 0xfaa8, 0xfaa8 }, +/* 0xfaa9 */ { true, 0xfaa9, 0xfaa9 }, +/* 0xfaaa */ { true, 0xfaaa, 0xfaaa }, +/* 0xfaab */ { true, 0xfaab, 0xfaab }, +/* 0xfaac */ { true, 0xfaac, 0xfaac }, +/* 0xfaad */ { true, 0xfaad, 0xfaad }, +/* 0xfaae */ { true, 0xfaae, 0xfaae }, +/* 0xfaaf */ { true, 0xfaaf, 0xfaaf }, +/* 0xfab0 */ { true, 0xfab0, 0xfab0 }, +/* 0xfab1 */ { true, 0xfab1, 0xfab1 }, +/* 0xfab2 */ { true, 0xfab2, 0xfab2 }, +/* 0xfab3 */ { true, 0xfab3, 0xfab3 }, +/* 0xfab4 */ { true, 0xfab4, 0xfab4 }, +/* 0xfab5 */ { true, 0xfab5, 0xfab5 }, +/* 0xfab6 */ { true, 0xfab6, 0xfab6 }, +/* 0xfab7 */ { true, 0xfab7, 0xfab7 }, +/* 0xfab8 */ { true, 0xfab8, 0xfab8 }, +/* 0xfab9 */ { true, 0xfab9, 0xfab9 }, +/* 0xfaba */ { true, 0xfaba, 0xfaba }, +/* 0xfabb */ { true, 0xfabb, 0xfabb }, +/* 0xfabc */ { true, 0xfabc, 0xfabc }, +/* 0xfabd */ { true, 0xfabd, 0xfabd }, +/* 0xfabe */ { true, 0xfabe, 0xfabe }, +/* 0xfabf */ { true, 0xfabf, 0xfabf }, +/* 0xfac0 */ { true, 0xfac0, 0xfac0 }, +/* 0xfac1 */ { true, 0xfac1, 0xfac1 }, +/* 0xfac2 */ { true, 0xfac2, 0xfac2 }, +/* 0xfac3 */ { true, 0xfac3, 0xfac3 }, +/* 0xfac4 */ { true, 0xfac4, 0xfac4 }, +/* 0xfac5 */ { true, 0xfac5, 0xfac5 }, +/* 0xfac6 */ { true, 0xfac6, 0xfac6 }, +/* 0xfac7 */ { true, 0xfac7, 0xfac7 }, +/* 0xfac8 */ { true, 0xfac8, 0xfac8 }, +/* 0xfac9 */ { true, 0xfac9, 0xfac9 }, +/* 0xfaca */ { true, 0xfaca, 0xfaca }, +/* 0xfacb */ { true, 0xfacb, 0xfacb }, +/* 0xfacc */ { true, 0xfacc, 0xfacc }, +/* 0xfacd */ { true, 0xfacd, 0xfacd }, +/* 0xface */ { true, 0xface, 0xface }, +/* 0xfacf */ { true, 0xfacf, 0xfacf }, +/* 0xfad0 */ { true, 0xfad0, 0xfad0 }, +/* 0xfad1 */ { true, 0xfad1, 0xfad1 }, +/* 0xfad2 */ { true, 0xfad2, 0xfad2 }, +/* 0xfad3 */ { true, 0xfad3, 0xfad3 }, +/* 0xfad4 */ { true, 0xfad4, 0xfad4 }, +/* 0xfad5 */ { true, 0xfad5, 0xfad5 }, +/* 0xfad6 */ { true, 0xfad6, 0xfad6 }, +/* 0xfad7 */ { true, 0xfad7, 0xfad7 }, +/* 0xfad8 */ { true, 0xfad8, 0xfad8 }, +/* 0xfad9 */ { true, 0xfad9, 0xfad9 }, +/* 0xfada */ { false, 0xfada, 0xfada }, +/* 0xfadb */ { false, 0xfadb, 0xfadb }, +/* 0xfadc */ { false, 0xfadc, 0xfadc }, +/* 0xfadd */ { false, 0xfadd, 0xfadd }, +/* 0xfade */ { false, 0xfade, 0xfade }, +/* 0xfadf */ { false, 0xfadf, 0xfadf }, +/* 0xfae0 */ { false, 0xfae0, 0xfae0 }, +/* 0xfae1 */ { false, 0xfae1, 0xfae1 }, +/* 0xfae2 */ { false, 0xfae2, 0xfae2 }, +/* 0xfae3 */ { false, 0xfae3, 0xfae3 }, +/* 0xfae4 */ { false, 0xfae4, 0xfae4 }, +/* 0xfae5 */ { false, 0xfae5, 0xfae5 }, +/* 0xfae6 */ { false, 0xfae6, 0xfae6 }, +/* 0xfae7 */ { false, 0xfae7, 0xfae7 }, +/* 0xfae8 */ { false, 0xfae8, 0xfae8 }, +/* 0xfae9 */ { false, 0xfae9, 0xfae9 }, +/* 0xfaea */ { false, 0xfaea, 0xfaea }, +/* 0xfaeb */ { false, 0xfaeb, 0xfaeb }, +/* 0xfaec */ { false, 0xfaec, 0xfaec }, +/* 0xfaed */ { false, 0xfaed, 0xfaed }, +/* 0xfaee */ { false, 0xfaee, 0xfaee }, +/* 0xfaef */ { false, 0xfaef, 0xfaef }, +/* 0xfaf0 */ { false, 0xfaf0, 0xfaf0 }, +/* 0xfaf1 */ { false, 0xfaf1, 0xfaf1 }, +/* 0xfaf2 */ { false, 0xfaf2, 0xfaf2 }, +/* 0xfaf3 */ { false, 0xfaf3, 0xfaf3 }, +/* 0xfaf4 */ { false, 0xfaf4, 0xfaf4 }, +/* 0xfaf5 */ { false, 0xfaf5, 0xfaf5 }, +/* 0xfaf6 */ { false, 0xfaf6, 0xfaf6 }, +/* 0xfaf7 */ { false, 0xfaf7, 0xfaf7 }, +/* 0xfaf8 */ { false, 0xfaf8, 0xfaf8 }, +/* 0xfaf9 */ { false, 0xfaf9, 0xfaf9 }, +/* 0xfafa */ { false, 0xfafa, 0xfafa }, +/* 0xfafb */ { false, 0xfafb, 0xfafb }, +/* 0xfafc */ { false, 0xfafc, 0xfafc }, +/* 0xfafd */ { false, 0xfafd, 0xfafd }, +/* 0xfafe */ { false, 0xfafe, 0xfafe }, +/* 0xfaff */ { false, 0xfaff, 0xfaff }, +/* 0xfb00 */ { true, 0xfb00, 0xfb00 }, +/* 0xfb01 */ { true, 0xfb01, 0xfb01 }, +/* 0xfb02 */ { true, 0xfb02, 0xfb02 }, +/* 0xfb03 */ { true, 0xfb03, 0xfb03 }, +/* 0xfb04 */ { true, 0xfb04, 0xfb04 }, +/* 0xfb05 */ { true, 0xfb05, 0xfb05 }, +/* 0xfb06 */ { true, 0xfb06, 0xfb06 }, +/* 0xfb07 */ { false, 0xfb07, 0xfb07 }, +/* 0xfb08 */ { false, 0xfb08, 0xfb08 }, +/* 0xfb09 */ { false, 0xfb09, 0xfb09 }, +/* 0xfb0a */ { false, 0xfb0a, 0xfb0a }, +/* 0xfb0b */ { false, 0xfb0b, 0xfb0b }, +/* 0xfb0c */ { false, 0xfb0c, 0xfb0c }, +/* 0xfb0d */ { false, 0xfb0d, 0xfb0d }, +/* 0xfb0e */ { false, 0xfb0e, 0xfb0e }, +/* 0xfb0f */ { false, 0xfb0f, 0xfb0f }, +/* 0xfb10 */ { false, 0xfb10, 0xfb10 }, +/* 0xfb11 */ { false, 0xfb11, 0xfb11 }, +/* 0xfb12 */ { false, 0xfb12, 0xfb12 }, +/* 0xfb13 */ { true, 0xfb13, 0xfb13 }, +/* 0xfb14 */ { true, 0xfb14, 0xfb14 }, +/* 0xfb15 */ { true, 0xfb15, 0xfb15 }, +/* 0xfb16 */ { true, 0xfb16, 0xfb16 }, +/* 0xfb17 */ { true, 0xfb17, 0xfb17 }, +/* 0xfb18 */ { false, 0xfb18, 0xfb18 }, +/* 0xfb19 */ { false, 0xfb19, 0xfb19 }, +/* 0xfb1a */ { false, 0xfb1a, 0xfb1a }, +/* 0xfb1b */ { false, 0xfb1b, 0xfb1b }, +/* 0xfb1c */ { false, 0xfb1c, 0xfb1c }, +/* 0xfb1d */ { true, 0xfb1d, 0xfb1d }, +/* 0xfb1e */ { true, 0xfb1e, 0xfb1e }, +/* 0xfb1f */ { true, 0xfb1f, 0xfb1f }, +/* 0xfb20 */ { true, 0xfb20, 0xfb20 }, +/* 0xfb21 */ { true, 0xfb21, 0xfb21 }, +/* 0xfb22 */ { true, 0xfb22, 0xfb22 }, +/* 0xfb23 */ { true, 0xfb23, 0xfb23 }, +/* 0xfb24 */ { true, 0xfb24, 0xfb24 }, +/* 0xfb25 */ { true, 0xfb25, 0xfb25 }, +/* 0xfb26 */ { true, 0xfb26, 0xfb26 }, +/* 0xfb27 */ { true, 0xfb27, 0xfb27 }, +/* 0xfb28 */ { true, 0xfb28, 0xfb28 }, +/* 0xfb29 */ { false, 0xfb29, 0xfb29 }, +/* 0xfb2a */ { true, 0xfb2a, 0xfb2a }, +/* 0xfb2b */ { true, 0xfb2b, 0xfb2b }, +/* 0xfb2c */ { true, 0xfb2c, 0xfb2c }, +/* 0xfb2d */ { true, 0xfb2d, 0xfb2d }, +/* 0xfb2e */ { true, 0xfb2e, 0xfb2e }, +/* 0xfb2f */ { true, 0xfb2f, 0xfb2f }, +/* 0xfb30 */ { true, 0xfb30, 0xfb30 }, +/* 0xfb31 */ { true, 0xfb31, 0xfb31 }, +/* 0xfb32 */ { true, 0xfb32, 0xfb32 }, +/* 0xfb33 */ { true, 0xfb33, 0xfb33 }, +/* 0xfb34 */ { true, 0xfb34, 0xfb34 }, +/* 0xfb35 */ { true, 0xfb35, 0xfb35 }, +/* 0xfb36 */ { true, 0xfb36, 0xfb36 }, +/* 0xfb37 */ { false, 0xfb37, 0xfb37 }, +/* 0xfb38 */ { true, 0xfb38, 0xfb38 }, +/* 0xfb39 */ { true, 0xfb39, 0xfb39 }, +/* 0xfb3a */ { true, 0xfb3a, 0xfb3a }, +/* 0xfb3b */ { true, 0xfb3b, 0xfb3b }, +/* 0xfb3c */ { true, 0xfb3c, 0xfb3c }, +/* 0xfb3d */ { false, 0xfb3d, 0xfb3d }, +/* 0xfb3e */ { true, 0xfb3e, 0xfb3e }, +/* 0xfb3f */ { false, 0xfb3f, 0xfb3f }, +/* 0xfb40 */ { true, 0xfb40, 0xfb40 }, +/* 0xfb41 */ { true, 0xfb41, 0xfb41 }, +/* 0xfb42 */ { false, 0xfb42, 0xfb42 }, +/* 0xfb43 */ { true, 0xfb43, 0xfb43 }, +/* 0xfb44 */ { true, 0xfb44, 0xfb44 }, +/* 0xfb45 */ { false, 0xfb45, 0xfb45 }, +/* 0xfb46 */ { true, 0xfb46, 0xfb46 }, +/* 0xfb47 */ { true, 0xfb47, 0xfb47 }, +/* 0xfb48 */ { true, 0xfb48, 0xfb48 }, +/* 0xfb49 */ { true, 0xfb49, 0xfb49 }, +/* 0xfb4a */ { true, 0xfb4a, 0xfb4a }, +/* 0xfb4b */ { true, 0xfb4b, 0xfb4b }, +/* 0xfb4c */ { true, 0xfb4c, 0xfb4c }, +/* 0xfb4d */ { true, 0xfb4d, 0xfb4d }, +/* 0xfb4e */ { true, 0xfb4e, 0xfb4e }, +/* 0xfb4f */ { true, 0xfb4f, 0xfb4f }, +/* 0xfb50 */ { true, 0xfb50, 0xfb50 }, +/* 0xfb51 */ { true, 0xfb51, 0xfb51 }, +/* 0xfb52 */ { true, 0xfb52, 0xfb52 }, +/* 0xfb53 */ { true, 0xfb53, 0xfb53 }, +/* 0xfb54 */ { true, 0xfb54, 0xfb54 }, +/* 0xfb55 */ { true, 0xfb55, 0xfb55 }, +/* 0xfb56 */ { true, 0xfb56, 0xfb56 }, +/* 0xfb57 */ { true, 0xfb57, 0xfb57 }, +/* 0xfb58 */ { true, 0xfb58, 0xfb58 }, +/* 0xfb59 */ { true, 0xfb59, 0xfb59 }, +/* 0xfb5a */ { true, 0xfb5a, 0xfb5a }, +/* 0xfb5b */ { true, 0xfb5b, 0xfb5b }, +/* 0xfb5c */ { true, 0xfb5c, 0xfb5c }, +/* 0xfb5d */ { true, 0xfb5d, 0xfb5d }, +/* 0xfb5e */ { true, 0xfb5e, 0xfb5e }, +/* 0xfb5f */ { true, 0xfb5f, 0xfb5f }, +/* 0xfb60 */ { true, 0xfb60, 0xfb60 }, +/* 0xfb61 */ { true, 0xfb61, 0xfb61 }, +/* 0xfb62 */ { true, 0xfb62, 0xfb62 }, +/* 0xfb63 */ { true, 0xfb63, 0xfb63 }, +/* 0xfb64 */ { true, 0xfb64, 0xfb64 }, +/* 0xfb65 */ { true, 0xfb65, 0xfb65 }, +/* 0xfb66 */ { true, 0xfb66, 0xfb66 }, +/* 0xfb67 */ { true, 0xfb67, 0xfb67 }, +/* 0xfb68 */ { true, 0xfb68, 0xfb68 }, +/* 0xfb69 */ { true, 0xfb69, 0xfb69 }, +/* 0xfb6a */ { true, 0xfb6a, 0xfb6a }, +/* 0xfb6b */ { true, 0xfb6b, 0xfb6b }, +/* 0xfb6c */ { true, 0xfb6c, 0xfb6c }, +/* 0xfb6d */ { true, 0xfb6d, 0xfb6d }, +/* 0xfb6e */ { true, 0xfb6e, 0xfb6e }, +/* 0xfb6f */ { true, 0xfb6f, 0xfb6f }, +/* 0xfb70 */ { true, 0xfb70, 0xfb70 }, +/* 0xfb71 */ { true, 0xfb71, 0xfb71 }, +/* 0xfb72 */ { true, 0xfb72, 0xfb72 }, +/* 0xfb73 */ { true, 0xfb73, 0xfb73 }, +/* 0xfb74 */ { true, 0xfb74, 0xfb74 }, +/* 0xfb75 */ { true, 0xfb75, 0xfb75 }, +/* 0xfb76 */ { true, 0xfb76, 0xfb76 }, +/* 0xfb77 */ { true, 0xfb77, 0xfb77 }, +/* 0xfb78 */ { true, 0xfb78, 0xfb78 }, +/* 0xfb79 */ { true, 0xfb79, 0xfb79 }, +/* 0xfb7a */ { true, 0xfb7a, 0xfb7a }, +/* 0xfb7b */ { true, 0xfb7b, 0xfb7b }, +/* 0xfb7c */ { true, 0xfb7c, 0xfb7c }, +/* 0xfb7d */ { true, 0xfb7d, 0xfb7d }, +/* 0xfb7e */ { true, 0xfb7e, 0xfb7e }, +/* 0xfb7f */ { true, 0xfb7f, 0xfb7f }, +/* 0xfb80 */ { true, 0xfb80, 0xfb80 }, +/* 0xfb81 */ { true, 0xfb81, 0xfb81 }, +/* 0xfb82 */ { true, 0xfb82, 0xfb82 }, +/* 0xfb83 */ { true, 0xfb83, 0xfb83 }, +/* 0xfb84 */ { true, 0xfb84, 0xfb84 }, +/* 0xfb85 */ { true, 0xfb85, 0xfb85 }, +/* 0xfb86 */ { true, 0xfb86, 0xfb86 }, +/* 0xfb87 */ { true, 0xfb87, 0xfb87 }, +/* 0xfb88 */ { true, 0xfb88, 0xfb88 }, +/* 0xfb89 */ { true, 0xfb89, 0xfb89 }, +/* 0xfb8a */ { true, 0xfb8a, 0xfb8a }, +/* 0xfb8b */ { true, 0xfb8b, 0xfb8b }, +/* 0xfb8c */ { true, 0xfb8c, 0xfb8c }, +/* 0xfb8d */ { true, 0xfb8d, 0xfb8d }, +/* 0xfb8e */ { true, 0xfb8e, 0xfb8e }, +/* 0xfb8f */ { true, 0xfb8f, 0xfb8f }, +/* 0xfb90 */ { true, 0xfb90, 0xfb90 }, +/* 0xfb91 */ { true, 0xfb91, 0xfb91 }, +/* 0xfb92 */ { true, 0xfb92, 0xfb92 }, +/* 0xfb93 */ { true, 0xfb93, 0xfb93 }, +/* 0xfb94 */ { true, 0xfb94, 0xfb94 }, +/* 0xfb95 */ { true, 0xfb95, 0xfb95 }, +/* 0xfb96 */ { true, 0xfb96, 0xfb96 }, +/* 0xfb97 */ { true, 0xfb97, 0xfb97 }, +/* 0xfb98 */ { true, 0xfb98, 0xfb98 }, +/* 0xfb99 */ { true, 0xfb99, 0xfb99 }, +/* 0xfb9a */ { true, 0xfb9a, 0xfb9a }, +/* 0xfb9b */ { true, 0xfb9b, 0xfb9b }, +/* 0xfb9c */ { true, 0xfb9c, 0xfb9c }, +/* 0xfb9d */ { true, 0xfb9d, 0xfb9d }, +/* 0xfb9e */ { true, 0xfb9e, 0xfb9e }, +/* 0xfb9f */ { true, 0xfb9f, 0xfb9f }, +/* 0xfba0 */ { true, 0xfba0, 0xfba0 }, +/* 0xfba1 */ { true, 0xfba1, 0xfba1 }, +/* 0xfba2 */ { true, 0xfba2, 0xfba2 }, +/* 0xfba3 */ { true, 0xfba3, 0xfba3 }, +/* 0xfba4 */ { true, 0xfba4, 0xfba4 }, +/* 0xfba5 */ { true, 0xfba5, 0xfba5 }, +/* 0xfba6 */ { true, 0xfba6, 0xfba6 }, +/* 0xfba7 */ { true, 0xfba7, 0xfba7 }, +/* 0xfba8 */ { true, 0xfba8, 0xfba8 }, +/* 0xfba9 */ { true, 0xfba9, 0xfba9 }, +/* 0xfbaa */ { true, 0xfbaa, 0xfbaa }, +/* 0xfbab */ { true, 0xfbab, 0xfbab }, +/* 0xfbac */ { true, 0xfbac, 0xfbac }, +/* 0xfbad */ { true, 0xfbad, 0xfbad }, +/* 0xfbae */ { true, 0xfbae, 0xfbae }, +/* 0xfbaf */ { true, 0xfbaf, 0xfbaf }, +/* 0xfbb0 */ { true, 0xfbb0, 0xfbb0 }, +/* 0xfbb1 */ { true, 0xfbb1, 0xfbb1 }, +/* 0xfbb2 */ { false, 0xfbb2, 0xfbb2 }, +/* 0xfbb3 */ { false, 0xfbb3, 0xfbb3 }, +/* 0xfbb4 */ { false, 0xfbb4, 0xfbb4 }, +/* 0xfbb5 */ { false, 0xfbb5, 0xfbb5 }, +/* 0xfbb6 */ { false, 0xfbb6, 0xfbb6 }, +/* 0xfbb7 */ { false, 0xfbb7, 0xfbb7 }, +/* 0xfbb8 */ { false, 0xfbb8, 0xfbb8 }, +/* 0xfbb9 */ { false, 0xfbb9, 0xfbb9 }, +/* 0xfbba */ { false, 0xfbba, 0xfbba }, +/* 0xfbbb */ { false, 0xfbbb, 0xfbbb }, +/* 0xfbbc */ { false, 0xfbbc, 0xfbbc }, +/* 0xfbbd */ { false, 0xfbbd, 0xfbbd }, +/* 0xfbbe */ { false, 0xfbbe, 0xfbbe }, +/* 0xfbbf */ { false, 0xfbbf, 0xfbbf }, +/* 0xfbc0 */ { false, 0xfbc0, 0xfbc0 }, +/* 0xfbc1 */ { false, 0xfbc1, 0xfbc1 }, +/* 0xfbc2 */ { false, 0xfbc2, 0xfbc2 }, +/* 0xfbc3 */ { false, 0xfbc3, 0xfbc3 }, +/* 0xfbc4 */ { false, 0xfbc4, 0xfbc4 }, +/* 0xfbc5 */ { false, 0xfbc5, 0xfbc5 }, +/* 0xfbc6 */ { false, 0xfbc6, 0xfbc6 }, +/* 0xfbc7 */ { false, 0xfbc7, 0xfbc7 }, +/* 0xfbc8 */ { false, 0xfbc8, 0xfbc8 }, +/* 0xfbc9 */ { false, 0xfbc9, 0xfbc9 }, +/* 0xfbca */ { false, 0xfbca, 0xfbca }, +/* 0xfbcb */ { false, 0xfbcb, 0xfbcb }, +/* 0xfbcc */ { false, 0xfbcc, 0xfbcc }, +/* 0xfbcd */ { false, 0xfbcd, 0xfbcd }, +/* 0xfbce */ { false, 0xfbce, 0xfbce }, +/* 0xfbcf */ { false, 0xfbcf, 0xfbcf }, +/* 0xfbd0 */ { false, 0xfbd0, 0xfbd0 }, +/* 0xfbd1 */ { false, 0xfbd1, 0xfbd1 }, +/* 0xfbd2 */ { false, 0xfbd2, 0xfbd2 }, +/* 0xfbd3 */ { true, 0xfbd3, 0xfbd3 }, +/* 0xfbd4 */ { true, 0xfbd4, 0xfbd4 }, +/* 0xfbd5 */ { true, 0xfbd5, 0xfbd5 }, +/* 0xfbd6 */ { true, 0xfbd6, 0xfbd6 }, +/* 0xfbd7 */ { true, 0xfbd7, 0xfbd7 }, +/* 0xfbd8 */ { true, 0xfbd8, 0xfbd8 }, +/* 0xfbd9 */ { true, 0xfbd9, 0xfbd9 }, +/* 0xfbda */ { true, 0xfbda, 0xfbda }, +/* 0xfbdb */ { true, 0xfbdb, 0xfbdb }, +/* 0xfbdc */ { true, 0xfbdc, 0xfbdc }, +/* 0xfbdd */ { true, 0xfbdd, 0xfbdd }, +/* 0xfbde */ { true, 0xfbde, 0xfbde }, +/* 0xfbdf */ { true, 0xfbdf, 0xfbdf }, +/* 0xfbe0 */ { true, 0xfbe0, 0xfbe0 }, +/* 0xfbe1 */ { true, 0xfbe1, 0xfbe1 }, +/* 0xfbe2 */ { true, 0xfbe2, 0xfbe2 }, +/* 0xfbe3 */ { true, 0xfbe3, 0xfbe3 }, +/* 0xfbe4 */ { true, 0xfbe4, 0xfbe4 }, +/* 0xfbe5 */ { true, 0xfbe5, 0xfbe5 }, +/* 0xfbe6 */ { true, 0xfbe6, 0xfbe6 }, +/* 0xfbe7 */ { true, 0xfbe7, 0xfbe7 }, +/* 0xfbe8 */ { true, 0xfbe8, 0xfbe8 }, +/* 0xfbe9 */ { true, 0xfbe9, 0xfbe9 }, +/* 0xfbea */ { true, 0xfbea, 0xfbea }, +/* 0xfbeb */ { true, 0xfbeb, 0xfbeb }, +/* 0xfbec */ { true, 0xfbec, 0xfbec }, +/* 0xfbed */ { true, 0xfbed, 0xfbed }, +/* 0xfbee */ { true, 0xfbee, 0xfbee }, +/* 0xfbef */ { true, 0xfbef, 0xfbef }, +/* 0xfbf0 */ { true, 0xfbf0, 0xfbf0 }, +/* 0xfbf1 */ { true, 0xfbf1, 0xfbf1 }, +/* 0xfbf2 */ { true, 0xfbf2, 0xfbf2 }, +/* 0xfbf3 */ { true, 0xfbf3, 0xfbf3 }, +/* 0xfbf4 */ { true, 0xfbf4, 0xfbf4 }, +/* 0xfbf5 */ { true, 0xfbf5, 0xfbf5 }, +/* 0xfbf6 */ { true, 0xfbf6, 0xfbf6 }, +/* 0xfbf7 */ { true, 0xfbf7, 0xfbf7 }, +/* 0xfbf8 */ { true, 0xfbf8, 0xfbf8 }, +/* 0xfbf9 */ { true, 0xfbf9, 0xfbf9 }, +/* 0xfbfa */ { true, 0xfbfa, 0xfbfa }, +/* 0xfbfb */ { true, 0xfbfb, 0xfbfb }, +/* 0xfbfc */ { true, 0xfbfc, 0xfbfc }, +/* 0xfbfd */ { true, 0xfbfd, 0xfbfd }, +/* 0xfbfe */ { true, 0xfbfe, 0xfbfe }, +/* 0xfbff */ { true, 0xfbff, 0xfbff }, +/* 0xfc00 */ { true, 0xfc00, 0xfc00 }, +/* 0xfc01 */ { true, 0xfc01, 0xfc01 }, +/* 0xfc02 */ { true, 0xfc02, 0xfc02 }, +/* 0xfc03 */ { true, 0xfc03, 0xfc03 }, +/* 0xfc04 */ { true, 0xfc04, 0xfc04 }, +/* 0xfc05 */ { true, 0xfc05, 0xfc05 }, +/* 0xfc06 */ { true, 0xfc06, 0xfc06 }, +/* 0xfc07 */ { true, 0xfc07, 0xfc07 }, +/* 0xfc08 */ { true, 0xfc08, 0xfc08 }, +/* 0xfc09 */ { true, 0xfc09, 0xfc09 }, +/* 0xfc0a */ { true, 0xfc0a, 0xfc0a }, +/* 0xfc0b */ { true, 0xfc0b, 0xfc0b }, +/* 0xfc0c */ { true, 0xfc0c, 0xfc0c }, +/* 0xfc0d */ { true, 0xfc0d, 0xfc0d }, +/* 0xfc0e */ { true, 0xfc0e, 0xfc0e }, +/* 0xfc0f */ { true, 0xfc0f, 0xfc0f }, +/* 0xfc10 */ { true, 0xfc10, 0xfc10 }, +/* 0xfc11 */ { true, 0xfc11, 0xfc11 }, +/* 0xfc12 */ { true, 0xfc12, 0xfc12 }, +/* 0xfc13 */ { true, 0xfc13, 0xfc13 }, +/* 0xfc14 */ { true, 0xfc14, 0xfc14 }, +/* 0xfc15 */ { true, 0xfc15, 0xfc15 }, +/* 0xfc16 */ { true, 0xfc16, 0xfc16 }, +/* 0xfc17 */ { true, 0xfc17, 0xfc17 }, +/* 0xfc18 */ { true, 0xfc18, 0xfc18 }, +/* 0xfc19 */ { true, 0xfc19, 0xfc19 }, +/* 0xfc1a */ { true, 0xfc1a, 0xfc1a }, +/* 0xfc1b */ { true, 0xfc1b, 0xfc1b }, +/* 0xfc1c */ { true, 0xfc1c, 0xfc1c }, +/* 0xfc1d */ { true, 0xfc1d, 0xfc1d }, +/* 0xfc1e */ { true, 0xfc1e, 0xfc1e }, +/* 0xfc1f */ { true, 0xfc1f, 0xfc1f }, +/* 0xfc20 */ { true, 0xfc20, 0xfc20 }, +/* 0xfc21 */ { true, 0xfc21, 0xfc21 }, +/* 0xfc22 */ { true, 0xfc22, 0xfc22 }, +/* 0xfc23 */ { true, 0xfc23, 0xfc23 }, +/* 0xfc24 */ { true, 0xfc24, 0xfc24 }, +/* 0xfc25 */ { true, 0xfc25, 0xfc25 }, +/* 0xfc26 */ { true, 0xfc26, 0xfc26 }, +/* 0xfc27 */ { true, 0xfc27, 0xfc27 }, +/* 0xfc28 */ { true, 0xfc28, 0xfc28 }, +/* 0xfc29 */ { true, 0xfc29, 0xfc29 }, +/* 0xfc2a */ { true, 0xfc2a, 0xfc2a }, +/* 0xfc2b */ { true, 0xfc2b, 0xfc2b }, +/* 0xfc2c */ { true, 0xfc2c, 0xfc2c }, +/* 0xfc2d */ { true, 0xfc2d, 0xfc2d }, +/* 0xfc2e */ { true, 0xfc2e, 0xfc2e }, +/* 0xfc2f */ { true, 0xfc2f, 0xfc2f }, +/* 0xfc30 */ { true, 0xfc30, 0xfc30 }, +/* 0xfc31 */ { true, 0xfc31, 0xfc31 }, +/* 0xfc32 */ { true, 0xfc32, 0xfc32 }, +/* 0xfc33 */ { true, 0xfc33, 0xfc33 }, +/* 0xfc34 */ { true, 0xfc34, 0xfc34 }, +/* 0xfc35 */ { true, 0xfc35, 0xfc35 }, +/* 0xfc36 */ { true, 0xfc36, 0xfc36 }, +/* 0xfc37 */ { true, 0xfc37, 0xfc37 }, +/* 0xfc38 */ { true, 0xfc38, 0xfc38 }, +/* 0xfc39 */ { true, 0xfc39, 0xfc39 }, +/* 0xfc3a */ { true, 0xfc3a, 0xfc3a }, +/* 0xfc3b */ { true, 0xfc3b, 0xfc3b }, +/* 0xfc3c */ { true, 0xfc3c, 0xfc3c }, +/* 0xfc3d */ { true, 0xfc3d, 0xfc3d }, +/* 0xfc3e */ { true, 0xfc3e, 0xfc3e }, +/* 0xfc3f */ { true, 0xfc3f, 0xfc3f }, +/* 0xfc40 */ { true, 0xfc40, 0xfc40 }, +/* 0xfc41 */ { true, 0xfc41, 0xfc41 }, +/* 0xfc42 */ { true, 0xfc42, 0xfc42 }, +/* 0xfc43 */ { true, 0xfc43, 0xfc43 }, +/* 0xfc44 */ { true, 0xfc44, 0xfc44 }, +/* 0xfc45 */ { true, 0xfc45, 0xfc45 }, +/* 0xfc46 */ { true, 0xfc46, 0xfc46 }, +/* 0xfc47 */ { true, 0xfc47, 0xfc47 }, +/* 0xfc48 */ { true, 0xfc48, 0xfc48 }, +/* 0xfc49 */ { true, 0xfc49, 0xfc49 }, +/* 0xfc4a */ { true, 0xfc4a, 0xfc4a }, +/* 0xfc4b */ { true, 0xfc4b, 0xfc4b }, +/* 0xfc4c */ { true, 0xfc4c, 0xfc4c }, +/* 0xfc4d */ { true, 0xfc4d, 0xfc4d }, +/* 0xfc4e */ { true, 0xfc4e, 0xfc4e }, +/* 0xfc4f */ { true, 0xfc4f, 0xfc4f }, +/* 0xfc50 */ { true, 0xfc50, 0xfc50 }, +/* 0xfc51 */ { true, 0xfc51, 0xfc51 }, +/* 0xfc52 */ { true, 0xfc52, 0xfc52 }, +/* 0xfc53 */ { true, 0xfc53, 0xfc53 }, +/* 0xfc54 */ { true, 0xfc54, 0xfc54 }, +/* 0xfc55 */ { true, 0xfc55, 0xfc55 }, +/* 0xfc56 */ { true, 0xfc56, 0xfc56 }, +/* 0xfc57 */ { true, 0xfc57, 0xfc57 }, +/* 0xfc58 */ { true, 0xfc58, 0xfc58 }, +/* 0xfc59 */ { true, 0xfc59, 0xfc59 }, +/* 0xfc5a */ { true, 0xfc5a, 0xfc5a }, +/* 0xfc5b */ { true, 0xfc5b, 0xfc5b }, +/* 0xfc5c */ { true, 0xfc5c, 0xfc5c }, +/* 0xfc5d */ { true, 0xfc5d, 0xfc5d }, +/* 0xfc5e */ { true, 0xfc5e, 0xfc5e }, +/* 0xfc5f */ { true, 0xfc5f, 0xfc5f }, +/* 0xfc60 */ { true, 0xfc60, 0xfc60 }, +/* 0xfc61 */ { true, 0xfc61, 0xfc61 }, +/* 0xfc62 */ { true, 0xfc62, 0xfc62 }, +/* 0xfc63 */ { true, 0xfc63, 0xfc63 }, +/* 0xfc64 */ { true, 0xfc64, 0xfc64 }, +/* 0xfc65 */ { true, 0xfc65, 0xfc65 }, +/* 0xfc66 */ { true, 0xfc66, 0xfc66 }, +/* 0xfc67 */ { true, 0xfc67, 0xfc67 }, +/* 0xfc68 */ { true, 0xfc68, 0xfc68 }, +/* 0xfc69 */ { true, 0xfc69, 0xfc69 }, +/* 0xfc6a */ { true, 0xfc6a, 0xfc6a }, +/* 0xfc6b */ { true, 0xfc6b, 0xfc6b }, +/* 0xfc6c */ { true, 0xfc6c, 0xfc6c }, +/* 0xfc6d */ { true, 0xfc6d, 0xfc6d }, +/* 0xfc6e */ { true, 0xfc6e, 0xfc6e }, +/* 0xfc6f */ { true, 0xfc6f, 0xfc6f }, +/* 0xfc70 */ { true, 0xfc70, 0xfc70 }, +/* 0xfc71 */ { true, 0xfc71, 0xfc71 }, +/* 0xfc72 */ { true, 0xfc72, 0xfc72 }, +/* 0xfc73 */ { true, 0xfc73, 0xfc73 }, +/* 0xfc74 */ { true, 0xfc74, 0xfc74 }, +/* 0xfc75 */ { true, 0xfc75, 0xfc75 }, +/* 0xfc76 */ { true, 0xfc76, 0xfc76 }, +/* 0xfc77 */ { true, 0xfc77, 0xfc77 }, +/* 0xfc78 */ { true, 0xfc78, 0xfc78 }, +/* 0xfc79 */ { true, 0xfc79, 0xfc79 }, +/* 0xfc7a */ { true, 0xfc7a, 0xfc7a }, +/* 0xfc7b */ { true, 0xfc7b, 0xfc7b }, +/* 0xfc7c */ { true, 0xfc7c, 0xfc7c }, +/* 0xfc7d */ { true, 0xfc7d, 0xfc7d }, +/* 0xfc7e */ { true, 0xfc7e, 0xfc7e }, +/* 0xfc7f */ { true, 0xfc7f, 0xfc7f }, +/* 0xfc80 */ { true, 0xfc80, 0xfc80 }, +/* 0xfc81 */ { true, 0xfc81, 0xfc81 }, +/* 0xfc82 */ { true, 0xfc82, 0xfc82 }, +/* 0xfc83 */ { true, 0xfc83, 0xfc83 }, +/* 0xfc84 */ { true, 0xfc84, 0xfc84 }, +/* 0xfc85 */ { true, 0xfc85, 0xfc85 }, +/* 0xfc86 */ { true, 0xfc86, 0xfc86 }, +/* 0xfc87 */ { true, 0xfc87, 0xfc87 }, +/* 0xfc88 */ { true, 0xfc88, 0xfc88 }, +/* 0xfc89 */ { true, 0xfc89, 0xfc89 }, +/* 0xfc8a */ { true, 0xfc8a, 0xfc8a }, +/* 0xfc8b */ { true, 0xfc8b, 0xfc8b }, +/* 0xfc8c */ { true, 0xfc8c, 0xfc8c }, +/* 0xfc8d */ { true, 0xfc8d, 0xfc8d }, +/* 0xfc8e */ { true, 0xfc8e, 0xfc8e }, +/* 0xfc8f */ { true, 0xfc8f, 0xfc8f }, +/* 0xfc90 */ { true, 0xfc90, 0xfc90 }, +/* 0xfc91 */ { true, 0xfc91, 0xfc91 }, +/* 0xfc92 */ { true, 0xfc92, 0xfc92 }, +/* 0xfc93 */ { true, 0xfc93, 0xfc93 }, +/* 0xfc94 */ { true, 0xfc94, 0xfc94 }, +/* 0xfc95 */ { true, 0xfc95, 0xfc95 }, +/* 0xfc96 */ { true, 0xfc96, 0xfc96 }, +/* 0xfc97 */ { true, 0xfc97, 0xfc97 }, +/* 0xfc98 */ { true, 0xfc98, 0xfc98 }, +/* 0xfc99 */ { true, 0xfc99, 0xfc99 }, +/* 0xfc9a */ { true, 0xfc9a, 0xfc9a }, +/* 0xfc9b */ { true, 0xfc9b, 0xfc9b }, +/* 0xfc9c */ { true, 0xfc9c, 0xfc9c }, +/* 0xfc9d */ { true, 0xfc9d, 0xfc9d }, +/* 0xfc9e */ { true, 0xfc9e, 0xfc9e }, +/* 0xfc9f */ { true, 0xfc9f, 0xfc9f }, +/* 0xfca0 */ { true, 0xfca0, 0xfca0 }, +/* 0xfca1 */ { true, 0xfca1, 0xfca1 }, +/* 0xfca2 */ { true, 0xfca2, 0xfca2 }, +/* 0xfca3 */ { true, 0xfca3, 0xfca3 }, +/* 0xfca4 */ { true, 0xfca4, 0xfca4 }, +/* 0xfca5 */ { true, 0xfca5, 0xfca5 }, +/* 0xfca6 */ { true, 0xfca6, 0xfca6 }, +/* 0xfca7 */ { true, 0xfca7, 0xfca7 }, +/* 0xfca8 */ { true, 0xfca8, 0xfca8 }, +/* 0xfca9 */ { true, 0xfca9, 0xfca9 }, +/* 0xfcaa */ { true, 0xfcaa, 0xfcaa }, +/* 0xfcab */ { true, 0xfcab, 0xfcab }, +/* 0xfcac */ { true, 0xfcac, 0xfcac }, +/* 0xfcad */ { true, 0xfcad, 0xfcad }, +/* 0xfcae */ { true, 0xfcae, 0xfcae }, +/* 0xfcaf */ { true, 0xfcaf, 0xfcaf }, +/* 0xfcb0 */ { true, 0xfcb0, 0xfcb0 }, +/* 0xfcb1 */ { true, 0xfcb1, 0xfcb1 }, +/* 0xfcb2 */ { true, 0xfcb2, 0xfcb2 }, +/* 0xfcb3 */ { true, 0xfcb3, 0xfcb3 }, +/* 0xfcb4 */ { true, 0xfcb4, 0xfcb4 }, +/* 0xfcb5 */ { true, 0xfcb5, 0xfcb5 }, +/* 0xfcb6 */ { true, 0xfcb6, 0xfcb6 }, +/* 0xfcb7 */ { true, 0xfcb7, 0xfcb7 }, +/* 0xfcb8 */ { true, 0xfcb8, 0xfcb8 }, +/* 0xfcb9 */ { true, 0xfcb9, 0xfcb9 }, +/* 0xfcba */ { true, 0xfcba, 0xfcba }, +/* 0xfcbb */ { true, 0xfcbb, 0xfcbb }, +/* 0xfcbc */ { true, 0xfcbc, 0xfcbc }, +/* 0xfcbd */ { true, 0xfcbd, 0xfcbd }, +/* 0xfcbe */ { true, 0xfcbe, 0xfcbe }, +/* 0xfcbf */ { true, 0xfcbf, 0xfcbf }, +/* 0xfcc0 */ { true, 0xfcc0, 0xfcc0 }, +/* 0xfcc1 */ { true, 0xfcc1, 0xfcc1 }, +/* 0xfcc2 */ { true, 0xfcc2, 0xfcc2 }, +/* 0xfcc3 */ { true, 0xfcc3, 0xfcc3 }, +/* 0xfcc4 */ { true, 0xfcc4, 0xfcc4 }, +/* 0xfcc5 */ { true, 0xfcc5, 0xfcc5 }, +/* 0xfcc6 */ { true, 0xfcc6, 0xfcc6 }, +/* 0xfcc7 */ { true, 0xfcc7, 0xfcc7 }, +/* 0xfcc8 */ { true, 0xfcc8, 0xfcc8 }, +/* 0xfcc9 */ { true, 0xfcc9, 0xfcc9 }, +/* 0xfcca */ { true, 0xfcca, 0xfcca }, +/* 0xfccb */ { true, 0xfccb, 0xfccb }, +/* 0xfccc */ { true, 0xfccc, 0xfccc }, +/* 0xfccd */ { true, 0xfccd, 0xfccd }, +/* 0xfcce */ { true, 0xfcce, 0xfcce }, +/* 0xfccf */ { true, 0xfccf, 0xfccf }, +/* 0xfcd0 */ { true, 0xfcd0, 0xfcd0 }, +/* 0xfcd1 */ { true, 0xfcd1, 0xfcd1 }, +/* 0xfcd2 */ { true, 0xfcd2, 0xfcd2 }, +/* 0xfcd3 */ { true, 0xfcd3, 0xfcd3 }, +/* 0xfcd4 */ { true, 0xfcd4, 0xfcd4 }, +/* 0xfcd5 */ { true, 0xfcd5, 0xfcd5 }, +/* 0xfcd6 */ { true, 0xfcd6, 0xfcd6 }, +/* 0xfcd7 */ { true, 0xfcd7, 0xfcd7 }, +/* 0xfcd8 */ { true, 0xfcd8, 0xfcd8 }, +/* 0xfcd9 */ { true, 0xfcd9, 0xfcd9 }, +/* 0xfcda */ { true, 0xfcda, 0xfcda }, +/* 0xfcdb */ { true, 0xfcdb, 0xfcdb }, +/* 0xfcdc */ { true, 0xfcdc, 0xfcdc }, +/* 0xfcdd */ { true, 0xfcdd, 0xfcdd }, +/* 0xfcde */ { true, 0xfcde, 0xfcde }, +/* 0xfcdf */ { true, 0xfcdf, 0xfcdf }, +/* 0xfce0 */ { true, 0xfce0, 0xfce0 }, +/* 0xfce1 */ { true, 0xfce1, 0xfce1 }, +/* 0xfce2 */ { true, 0xfce2, 0xfce2 }, +/* 0xfce3 */ { true, 0xfce3, 0xfce3 }, +/* 0xfce4 */ { true, 0xfce4, 0xfce4 }, +/* 0xfce5 */ { true, 0xfce5, 0xfce5 }, +/* 0xfce6 */ { true, 0xfce6, 0xfce6 }, +/* 0xfce7 */ { true, 0xfce7, 0xfce7 }, +/* 0xfce8 */ { true, 0xfce8, 0xfce8 }, +/* 0xfce9 */ { true, 0xfce9, 0xfce9 }, +/* 0xfcea */ { true, 0xfcea, 0xfcea }, +/* 0xfceb */ { true, 0xfceb, 0xfceb }, +/* 0xfcec */ { true, 0xfcec, 0xfcec }, +/* 0xfced */ { true, 0xfced, 0xfced }, +/* 0xfcee */ { true, 0xfcee, 0xfcee }, +/* 0xfcef */ { true, 0xfcef, 0xfcef }, +/* 0xfcf0 */ { true, 0xfcf0, 0xfcf0 }, +/* 0xfcf1 */ { true, 0xfcf1, 0xfcf1 }, +/* 0xfcf2 */ { true, 0xfcf2, 0xfcf2 }, +/* 0xfcf3 */ { true, 0xfcf3, 0xfcf3 }, +/* 0xfcf4 */ { true, 0xfcf4, 0xfcf4 }, +/* 0xfcf5 */ { true, 0xfcf5, 0xfcf5 }, +/* 0xfcf6 */ { true, 0xfcf6, 0xfcf6 }, +/* 0xfcf7 */ { true, 0xfcf7, 0xfcf7 }, +/* 0xfcf8 */ { true, 0xfcf8, 0xfcf8 }, +/* 0xfcf9 */ { true, 0xfcf9, 0xfcf9 }, +/* 0xfcfa */ { true, 0xfcfa, 0xfcfa }, +/* 0xfcfb */ { true, 0xfcfb, 0xfcfb }, +/* 0xfcfc */ { true, 0xfcfc, 0xfcfc }, +/* 0xfcfd */ { true, 0xfcfd, 0xfcfd }, +/* 0xfcfe */ { true, 0xfcfe, 0xfcfe }, +/* 0xfcff */ { true, 0xfcff, 0xfcff }, +/* 0xfd00 */ { true, 0xfd00, 0xfd00 }, +/* 0xfd01 */ { true, 0xfd01, 0xfd01 }, +/* 0xfd02 */ { true, 0xfd02, 0xfd02 }, +/* 0xfd03 */ { true, 0xfd03, 0xfd03 }, +/* 0xfd04 */ { true, 0xfd04, 0xfd04 }, +/* 0xfd05 */ { true, 0xfd05, 0xfd05 }, +/* 0xfd06 */ { true, 0xfd06, 0xfd06 }, +/* 0xfd07 */ { true, 0xfd07, 0xfd07 }, +/* 0xfd08 */ { true, 0xfd08, 0xfd08 }, +/* 0xfd09 */ { true, 0xfd09, 0xfd09 }, +/* 0xfd0a */ { true, 0xfd0a, 0xfd0a }, +/* 0xfd0b */ { true, 0xfd0b, 0xfd0b }, +/* 0xfd0c */ { true, 0xfd0c, 0xfd0c }, +/* 0xfd0d */ { true, 0xfd0d, 0xfd0d }, +/* 0xfd0e */ { true, 0xfd0e, 0xfd0e }, +/* 0xfd0f */ { true, 0xfd0f, 0xfd0f }, +/* 0xfd10 */ { true, 0xfd10, 0xfd10 }, +/* 0xfd11 */ { true, 0xfd11, 0xfd11 }, +/* 0xfd12 */ { true, 0xfd12, 0xfd12 }, +/* 0xfd13 */ { true, 0xfd13, 0xfd13 }, +/* 0xfd14 */ { true, 0xfd14, 0xfd14 }, +/* 0xfd15 */ { true, 0xfd15, 0xfd15 }, +/* 0xfd16 */ { true, 0xfd16, 0xfd16 }, +/* 0xfd17 */ { true, 0xfd17, 0xfd17 }, +/* 0xfd18 */ { true, 0xfd18, 0xfd18 }, +/* 0xfd19 */ { true, 0xfd19, 0xfd19 }, +/* 0xfd1a */ { true, 0xfd1a, 0xfd1a }, +/* 0xfd1b */ { true, 0xfd1b, 0xfd1b }, +/* 0xfd1c */ { true, 0xfd1c, 0xfd1c }, +/* 0xfd1d */ { true, 0xfd1d, 0xfd1d }, +/* 0xfd1e */ { true, 0xfd1e, 0xfd1e }, +/* 0xfd1f */ { true, 0xfd1f, 0xfd1f }, +/* 0xfd20 */ { true, 0xfd20, 0xfd20 }, +/* 0xfd21 */ { true, 0xfd21, 0xfd21 }, +/* 0xfd22 */ { true, 0xfd22, 0xfd22 }, +/* 0xfd23 */ { true, 0xfd23, 0xfd23 }, +/* 0xfd24 */ { true, 0xfd24, 0xfd24 }, +/* 0xfd25 */ { true, 0xfd25, 0xfd25 }, +/* 0xfd26 */ { true, 0xfd26, 0xfd26 }, +/* 0xfd27 */ { true, 0xfd27, 0xfd27 }, +/* 0xfd28 */ { true, 0xfd28, 0xfd28 }, +/* 0xfd29 */ { true, 0xfd29, 0xfd29 }, +/* 0xfd2a */ { true, 0xfd2a, 0xfd2a }, +/* 0xfd2b */ { true, 0xfd2b, 0xfd2b }, +/* 0xfd2c */ { true, 0xfd2c, 0xfd2c }, +/* 0xfd2d */ { true, 0xfd2d, 0xfd2d }, +/* 0xfd2e */ { true, 0xfd2e, 0xfd2e }, +/* 0xfd2f */ { true, 0xfd2f, 0xfd2f }, +/* 0xfd30 */ { true, 0xfd30, 0xfd30 }, +/* 0xfd31 */ { true, 0xfd31, 0xfd31 }, +/* 0xfd32 */ { true, 0xfd32, 0xfd32 }, +/* 0xfd33 */ { true, 0xfd33, 0xfd33 }, +/* 0xfd34 */ { true, 0xfd34, 0xfd34 }, +/* 0xfd35 */ { true, 0xfd35, 0xfd35 }, +/* 0xfd36 */ { true, 0xfd36, 0xfd36 }, +/* 0xfd37 */ { true, 0xfd37, 0xfd37 }, +/* 0xfd38 */ { true, 0xfd38, 0xfd38 }, +/* 0xfd39 */ { true, 0xfd39, 0xfd39 }, +/* 0xfd3a */ { true, 0xfd3a, 0xfd3a }, +/* 0xfd3b */ { true, 0xfd3b, 0xfd3b }, +/* 0xfd3c */ { true, 0xfd3c, 0xfd3c }, +/* 0xfd3d */ { true, 0xfd3d, 0xfd3d }, +/* 0xfd3e */ { false, 0xfd3e, 0xfd3e }, +/* 0xfd3f */ { false, 0xfd3f, 0xfd3f }, +/* 0xfd40 */ { false, 0xfd40, 0xfd40 }, +/* 0xfd41 */ { false, 0xfd41, 0xfd41 }, +/* 0xfd42 */ { false, 0xfd42, 0xfd42 }, +/* 0xfd43 */ { false, 0xfd43, 0xfd43 }, +/* 0xfd44 */ { false, 0xfd44, 0xfd44 }, +/* 0xfd45 */ { false, 0xfd45, 0xfd45 }, +/* 0xfd46 */ { false, 0xfd46, 0xfd46 }, +/* 0xfd47 */ { false, 0xfd47, 0xfd47 }, +/* 0xfd48 */ { false, 0xfd48, 0xfd48 }, +/* 0xfd49 */ { false, 0xfd49, 0xfd49 }, +/* 0xfd4a */ { false, 0xfd4a, 0xfd4a }, +/* 0xfd4b */ { false, 0xfd4b, 0xfd4b }, +/* 0xfd4c */ { false, 0xfd4c, 0xfd4c }, +/* 0xfd4d */ { false, 0xfd4d, 0xfd4d }, +/* 0xfd4e */ { false, 0xfd4e, 0xfd4e }, +/* 0xfd4f */ { false, 0xfd4f, 0xfd4f }, +/* 0xfd50 */ { true, 0xfd50, 0xfd50 }, +/* 0xfd51 */ { true, 0xfd51, 0xfd51 }, +/* 0xfd52 */ { true, 0xfd52, 0xfd52 }, +/* 0xfd53 */ { true, 0xfd53, 0xfd53 }, +/* 0xfd54 */ { true, 0xfd54, 0xfd54 }, +/* 0xfd55 */ { true, 0xfd55, 0xfd55 }, +/* 0xfd56 */ { true, 0xfd56, 0xfd56 }, +/* 0xfd57 */ { true, 0xfd57, 0xfd57 }, +/* 0xfd58 */ { true, 0xfd58, 0xfd58 }, +/* 0xfd59 */ { true, 0xfd59, 0xfd59 }, +/* 0xfd5a */ { true, 0xfd5a, 0xfd5a }, +/* 0xfd5b */ { true, 0xfd5b, 0xfd5b }, +/* 0xfd5c */ { true, 0xfd5c, 0xfd5c }, +/* 0xfd5d */ { true, 0xfd5d, 0xfd5d }, +/* 0xfd5e */ { true, 0xfd5e, 0xfd5e }, +/* 0xfd5f */ { true, 0xfd5f, 0xfd5f }, +/* 0xfd60 */ { true, 0xfd60, 0xfd60 }, +/* 0xfd61 */ { true, 0xfd61, 0xfd61 }, +/* 0xfd62 */ { true, 0xfd62, 0xfd62 }, +/* 0xfd63 */ { true, 0xfd63, 0xfd63 }, +/* 0xfd64 */ { true, 0xfd64, 0xfd64 }, +/* 0xfd65 */ { true, 0xfd65, 0xfd65 }, +/* 0xfd66 */ { true, 0xfd66, 0xfd66 }, +/* 0xfd67 */ { true, 0xfd67, 0xfd67 }, +/* 0xfd68 */ { true, 0xfd68, 0xfd68 }, +/* 0xfd69 */ { true, 0xfd69, 0xfd69 }, +/* 0xfd6a */ { true, 0xfd6a, 0xfd6a }, +/* 0xfd6b */ { true, 0xfd6b, 0xfd6b }, +/* 0xfd6c */ { true, 0xfd6c, 0xfd6c }, +/* 0xfd6d */ { true, 0xfd6d, 0xfd6d }, +/* 0xfd6e */ { true, 0xfd6e, 0xfd6e }, +/* 0xfd6f */ { true, 0xfd6f, 0xfd6f }, +/* 0xfd70 */ { true, 0xfd70, 0xfd70 }, +/* 0xfd71 */ { true, 0xfd71, 0xfd71 }, +/* 0xfd72 */ { true, 0xfd72, 0xfd72 }, +/* 0xfd73 */ { true, 0xfd73, 0xfd73 }, +/* 0xfd74 */ { true, 0xfd74, 0xfd74 }, +/* 0xfd75 */ { true, 0xfd75, 0xfd75 }, +/* 0xfd76 */ { true, 0xfd76, 0xfd76 }, +/* 0xfd77 */ { true, 0xfd77, 0xfd77 }, +/* 0xfd78 */ { true, 0xfd78, 0xfd78 }, +/* 0xfd79 */ { true, 0xfd79, 0xfd79 }, +/* 0xfd7a */ { true, 0xfd7a, 0xfd7a }, +/* 0xfd7b */ { true, 0xfd7b, 0xfd7b }, +/* 0xfd7c */ { true, 0xfd7c, 0xfd7c }, +/* 0xfd7d */ { true, 0xfd7d, 0xfd7d }, +/* 0xfd7e */ { true, 0xfd7e, 0xfd7e }, +/* 0xfd7f */ { true, 0xfd7f, 0xfd7f }, +/* 0xfd80 */ { true, 0xfd80, 0xfd80 }, +/* 0xfd81 */ { true, 0xfd81, 0xfd81 }, +/* 0xfd82 */ { true, 0xfd82, 0xfd82 }, +/* 0xfd83 */ { true, 0xfd83, 0xfd83 }, +/* 0xfd84 */ { true, 0xfd84, 0xfd84 }, +/* 0xfd85 */ { true, 0xfd85, 0xfd85 }, +/* 0xfd86 */ { true, 0xfd86, 0xfd86 }, +/* 0xfd87 */ { true, 0xfd87, 0xfd87 }, +/* 0xfd88 */ { true, 0xfd88, 0xfd88 }, +/* 0xfd89 */ { true, 0xfd89, 0xfd89 }, +/* 0xfd8a */ { true, 0xfd8a, 0xfd8a }, +/* 0xfd8b */ { true, 0xfd8b, 0xfd8b }, +/* 0xfd8c */ { true, 0xfd8c, 0xfd8c }, +/* 0xfd8d */ { true, 0xfd8d, 0xfd8d }, +/* 0xfd8e */ { true, 0xfd8e, 0xfd8e }, +/* 0xfd8f */ { true, 0xfd8f, 0xfd8f }, +/* 0xfd90 */ { false, 0xfd90, 0xfd90 }, +/* 0xfd91 */ { false, 0xfd91, 0xfd91 }, +/* 0xfd92 */ { true, 0xfd92, 0xfd92 }, +/* 0xfd93 */ { true, 0xfd93, 0xfd93 }, +/* 0xfd94 */ { true, 0xfd94, 0xfd94 }, +/* 0xfd95 */ { true, 0xfd95, 0xfd95 }, +/* 0xfd96 */ { true, 0xfd96, 0xfd96 }, +/* 0xfd97 */ { true, 0xfd97, 0xfd97 }, +/* 0xfd98 */ { true, 0xfd98, 0xfd98 }, +/* 0xfd99 */ { true, 0xfd99, 0xfd99 }, +/* 0xfd9a */ { true, 0xfd9a, 0xfd9a }, +/* 0xfd9b */ { true, 0xfd9b, 0xfd9b }, +/* 0xfd9c */ { true, 0xfd9c, 0xfd9c }, +/* 0xfd9d */ { true, 0xfd9d, 0xfd9d }, +/* 0xfd9e */ { true, 0xfd9e, 0xfd9e }, +/* 0xfd9f */ { true, 0xfd9f, 0xfd9f }, +/* 0xfda0 */ { true, 0xfda0, 0xfda0 }, +/* 0xfda1 */ { true, 0xfda1, 0xfda1 }, +/* 0xfda2 */ { true, 0xfda2, 0xfda2 }, +/* 0xfda3 */ { true, 0xfda3, 0xfda3 }, +/* 0xfda4 */ { true, 0xfda4, 0xfda4 }, +/* 0xfda5 */ { true, 0xfda5, 0xfda5 }, +/* 0xfda6 */ { true, 0xfda6, 0xfda6 }, +/* 0xfda7 */ { true, 0xfda7, 0xfda7 }, +/* 0xfda8 */ { true, 0xfda8, 0xfda8 }, +/* 0xfda9 */ { true, 0xfda9, 0xfda9 }, +/* 0xfdaa */ { true, 0xfdaa, 0xfdaa }, +/* 0xfdab */ { true, 0xfdab, 0xfdab }, +/* 0xfdac */ { true, 0xfdac, 0xfdac }, +/* 0xfdad */ { true, 0xfdad, 0xfdad }, +/* 0xfdae */ { true, 0xfdae, 0xfdae }, +/* 0xfdaf */ { true, 0xfdaf, 0xfdaf }, +/* 0xfdb0 */ { true, 0xfdb0, 0xfdb0 }, +/* 0xfdb1 */ { true, 0xfdb1, 0xfdb1 }, +/* 0xfdb2 */ { true, 0xfdb2, 0xfdb2 }, +/* 0xfdb3 */ { true, 0xfdb3, 0xfdb3 }, +/* 0xfdb4 */ { true, 0xfdb4, 0xfdb4 }, +/* 0xfdb5 */ { true, 0xfdb5, 0xfdb5 }, +/* 0xfdb6 */ { true, 0xfdb6, 0xfdb6 }, +/* 0xfdb7 */ { true, 0xfdb7, 0xfdb7 }, +/* 0xfdb8 */ { true, 0xfdb8, 0xfdb8 }, +/* 0xfdb9 */ { true, 0xfdb9, 0xfdb9 }, +/* 0xfdba */ { true, 0xfdba, 0xfdba }, +/* 0xfdbb */ { true, 0xfdbb, 0xfdbb }, +/* 0xfdbc */ { true, 0xfdbc, 0xfdbc }, +/* 0xfdbd */ { true, 0xfdbd, 0xfdbd }, +/* 0xfdbe */ { true, 0xfdbe, 0xfdbe }, +/* 0xfdbf */ { true, 0xfdbf, 0xfdbf }, +/* 0xfdc0 */ { true, 0xfdc0, 0xfdc0 }, +/* 0xfdc1 */ { true, 0xfdc1, 0xfdc1 }, +/* 0xfdc2 */ { true, 0xfdc2, 0xfdc2 }, +/* 0xfdc3 */ { true, 0xfdc3, 0xfdc3 }, +/* 0xfdc4 */ { true, 0xfdc4, 0xfdc4 }, +/* 0xfdc5 */ { true, 0xfdc5, 0xfdc5 }, +/* 0xfdc6 */ { true, 0xfdc6, 0xfdc6 }, +/* 0xfdc7 */ { true, 0xfdc7, 0xfdc7 }, +/* 0xfdc8 */ { false, 0xfdc8, 0xfdc8 }, +/* 0xfdc9 */ { false, 0xfdc9, 0xfdc9 }, +/* 0xfdca */ { false, 0xfdca, 0xfdca }, +/* 0xfdcb */ { false, 0xfdcb, 0xfdcb }, +/* 0xfdcc */ { false, 0xfdcc, 0xfdcc }, +/* 0xfdcd */ { false, 0xfdcd, 0xfdcd }, +/* 0xfdce */ { false, 0xfdce, 0xfdce }, +/* 0xfdcf */ { false, 0xfdcf, 0xfdcf }, +/* 0xfdd0 */ { false, 0xfdd0, 0xfdd0 }, +/* 0xfdd1 */ { false, 0xfdd1, 0xfdd1 }, +/* 0xfdd2 */ { false, 0xfdd2, 0xfdd2 }, +/* 0xfdd3 */ { false, 0xfdd3, 0xfdd3 }, +/* 0xfdd4 */ { false, 0xfdd4, 0xfdd4 }, +/* 0xfdd5 */ { false, 0xfdd5, 0xfdd5 }, +/* 0xfdd6 */ { false, 0xfdd6, 0xfdd6 }, +/* 0xfdd7 */ { false, 0xfdd7, 0xfdd7 }, +/* 0xfdd8 */ { false, 0xfdd8, 0xfdd8 }, +/* 0xfdd9 */ { false, 0xfdd9, 0xfdd9 }, +/* 0xfdda */ { false, 0xfdda, 0xfdda }, +/* 0xfddb */ { false, 0xfddb, 0xfddb }, +/* 0xfddc */ { false, 0xfddc, 0xfddc }, +/* 0xfddd */ { false, 0xfddd, 0xfddd }, +/* 0xfdde */ { false, 0xfdde, 0xfdde }, +/* 0xfddf */ { false, 0xfddf, 0xfddf }, +/* 0xfde0 */ { false, 0xfde0, 0xfde0 }, +/* 0xfde1 */ { false, 0xfde1, 0xfde1 }, +/* 0xfde2 */ { false, 0xfde2, 0xfde2 }, +/* 0xfde3 */ { false, 0xfde3, 0xfde3 }, +/* 0xfde4 */ { false, 0xfde4, 0xfde4 }, +/* 0xfde5 */ { false, 0xfde5, 0xfde5 }, +/* 0xfde6 */ { false, 0xfde6, 0xfde6 }, +/* 0xfde7 */ { false, 0xfde7, 0xfde7 }, +/* 0xfde8 */ { false, 0xfde8, 0xfde8 }, +/* 0xfde9 */ { false, 0xfde9, 0xfde9 }, +/* 0xfdea */ { false, 0xfdea, 0xfdea }, +/* 0xfdeb */ { false, 0xfdeb, 0xfdeb }, +/* 0xfdec */ { false, 0xfdec, 0xfdec }, +/* 0xfded */ { false, 0xfded, 0xfded }, +/* 0xfdee */ { false, 0xfdee, 0xfdee }, +/* 0xfdef */ { false, 0xfdef, 0xfdef }, +/* 0xfdf0 */ { true, 0xfdf0, 0xfdf0 }, +/* 0xfdf1 */ { true, 0xfdf1, 0xfdf1 }, +/* 0xfdf2 */ { true, 0xfdf2, 0xfdf2 }, +/* 0xfdf3 */ { true, 0xfdf3, 0xfdf3 }, +/* 0xfdf4 */ { true, 0xfdf4, 0xfdf4 }, +/* 0xfdf5 */ { true, 0xfdf5, 0xfdf5 }, +/* 0xfdf6 */ { true, 0xfdf6, 0xfdf6 }, +/* 0xfdf7 */ { true, 0xfdf7, 0xfdf7 }, +/* 0xfdf8 */ { true, 0xfdf8, 0xfdf8 }, +/* 0xfdf9 */ { true, 0xfdf9, 0xfdf9 }, +/* 0xfdfa */ { true, 0xfdfa, 0xfdfa }, +/* 0xfdfb */ { true, 0xfdfb, 0xfdfb }, +/* 0xfdfc */ { false, 0xfdfc, 0xfdfc }, +/* 0xfdfd */ { false, 0xfdfd, 0xfdfd }, +/* 0xfdfe */ { false, 0xfdfe, 0xfdfe }, +/* 0xfdff */ { false, 0xfdff, 0xfdff }, +/* 0xfe00 */ { true, 0xfe00, 0xfe00 }, +/* 0xfe01 */ { true, 0xfe01, 0xfe01 }, +/* 0xfe02 */ { true, 0xfe02, 0xfe02 }, +/* 0xfe03 */ { true, 0xfe03, 0xfe03 }, +/* 0xfe04 */ { true, 0xfe04, 0xfe04 }, +/* 0xfe05 */ { true, 0xfe05, 0xfe05 }, +/* 0xfe06 */ { true, 0xfe06, 0xfe06 }, +/* 0xfe07 */ { true, 0xfe07, 0xfe07 }, +/* 0xfe08 */ { true, 0xfe08, 0xfe08 }, +/* 0xfe09 */ { true, 0xfe09, 0xfe09 }, +/* 0xfe0a */ { true, 0xfe0a, 0xfe0a }, +/* 0xfe0b */ { true, 0xfe0b, 0xfe0b }, +/* 0xfe0c */ { true, 0xfe0c, 0xfe0c }, +/* 0xfe0d */ { true, 0xfe0d, 0xfe0d }, +/* 0xfe0e */ { true, 0xfe0e, 0xfe0e }, +/* 0xfe0f */ { true, 0xfe0f, 0xfe0f }, +/* 0xfe10 */ { false, 0xfe10, 0xfe10 }, +/* 0xfe11 */ { false, 0xfe11, 0xfe11 }, +/* 0xfe12 */ { false, 0xfe12, 0xfe12 }, +/* 0xfe13 */ { false, 0xfe13, 0xfe13 }, +/* 0xfe14 */ { false, 0xfe14, 0xfe14 }, +/* 0xfe15 */ { false, 0xfe15, 0xfe15 }, +/* 0xfe16 */ { false, 0xfe16, 0xfe16 }, +/* 0xfe17 */ { false, 0xfe17, 0xfe17 }, +/* 0xfe18 */ { false, 0xfe18, 0xfe18 }, +/* 0xfe19 */ { false, 0xfe19, 0xfe19 }, +/* 0xfe1a */ { false, 0xfe1a, 0xfe1a }, +/* 0xfe1b */ { false, 0xfe1b, 0xfe1b }, +/* 0xfe1c */ { false, 0xfe1c, 0xfe1c }, +/* 0xfe1d */ { false, 0xfe1d, 0xfe1d }, +/* 0xfe1e */ { false, 0xfe1e, 0xfe1e }, +/* 0xfe1f */ { false, 0xfe1f, 0xfe1f }, +/* 0xfe20 */ { true, 0xfe20, 0xfe20 }, +/* 0xfe21 */ { true, 0xfe21, 0xfe21 }, +/* 0xfe22 */ { true, 0xfe22, 0xfe22 }, +/* 0xfe23 */ { true, 0xfe23, 0xfe23 }, +/* 0xfe24 */ { false, 0xfe24, 0xfe24 }, +/* 0xfe25 */ { false, 0xfe25, 0xfe25 }, +/* 0xfe26 */ { false, 0xfe26, 0xfe26 }, +/* 0xfe27 */ { false, 0xfe27, 0xfe27 }, +/* 0xfe28 */ { false, 0xfe28, 0xfe28 }, +/* 0xfe29 */ { false, 0xfe29, 0xfe29 }, +/* 0xfe2a */ { false, 0xfe2a, 0xfe2a }, +/* 0xfe2b */ { false, 0xfe2b, 0xfe2b }, +/* 0xfe2c */ { false, 0xfe2c, 0xfe2c }, +/* 0xfe2d */ { false, 0xfe2d, 0xfe2d }, +/* 0xfe2e */ { false, 0xfe2e, 0xfe2e }, +/* 0xfe2f */ { false, 0xfe2f, 0xfe2f }, +/* 0xfe30 */ { false, 0xfe30, 0xfe30 }, +/* 0xfe31 */ { false, 0xfe31, 0xfe31 }, +/* 0xfe32 */ { false, 0xfe32, 0xfe32 }, +/* 0xfe33 */ { false, 0xfe33, 0xfe33 }, +/* 0xfe34 */ { false, 0xfe34, 0xfe34 }, +/* 0xfe35 */ { false, 0xfe35, 0xfe35 }, +/* 0xfe36 */ { false, 0xfe36, 0xfe36 }, +/* 0xfe37 */ { false, 0xfe37, 0xfe37 }, +/* 0xfe38 */ { false, 0xfe38, 0xfe38 }, +/* 0xfe39 */ { false, 0xfe39, 0xfe39 }, +/* 0xfe3a */ { false, 0xfe3a, 0xfe3a }, +/* 0xfe3b */ { false, 0xfe3b, 0xfe3b }, +/* 0xfe3c */ { false, 0xfe3c, 0xfe3c }, +/* 0xfe3d */ { false, 0xfe3d, 0xfe3d }, +/* 0xfe3e */ { false, 0xfe3e, 0xfe3e }, +/* 0xfe3f */ { false, 0xfe3f, 0xfe3f }, +/* 0xfe40 */ { false, 0xfe40, 0xfe40 }, +/* 0xfe41 */ { false, 0xfe41, 0xfe41 }, +/* 0xfe42 */ { false, 0xfe42, 0xfe42 }, +/* 0xfe43 */ { false, 0xfe43, 0xfe43 }, +/* 0xfe44 */ { false, 0xfe44, 0xfe44 }, +/* 0xfe45 */ { false, 0xfe45, 0xfe45 }, +/* 0xfe46 */ { false, 0xfe46, 0xfe46 }, +/* 0xfe47 */ { false, 0xfe47, 0xfe47 }, +/* 0xfe48 */ { false, 0xfe48, 0xfe48 }, +/* 0xfe49 */ { false, 0xfe49, 0xfe49 }, +/* 0xfe4a */ { false, 0xfe4a, 0xfe4a }, +/* 0xfe4b */ { false, 0xfe4b, 0xfe4b }, +/* 0xfe4c */ { false, 0xfe4c, 0xfe4c }, +/* 0xfe4d */ { false, 0xfe4d, 0xfe4d }, +/* 0xfe4e */ { false, 0xfe4e, 0xfe4e }, +/* 0xfe4f */ { false, 0xfe4f, 0xfe4f }, +/* 0xfe50 */ { false, 0xfe50, 0xfe50 }, +/* 0xfe51 */ { false, 0xfe51, 0xfe51 }, +/* 0xfe52 */ { false, 0xfe52, 0xfe52 }, +/* 0xfe53 */ { false, 0xfe53, 0xfe53 }, +/* 0xfe54 */ { false, 0xfe54, 0xfe54 }, +/* 0xfe55 */ { false, 0xfe55, 0xfe55 }, +/* 0xfe56 */ { false, 0xfe56, 0xfe56 }, +/* 0xfe57 */ { false, 0xfe57, 0xfe57 }, +/* 0xfe58 */ { false, 0xfe58, 0xfe58 }, +/* 0xfe59 */ { false, 0xfe59, 0xfe59 }, +/* 0xfe5a */ { false, 0xfe5a, 0xfe5a }, +/* 0xfe5b */ { false, 0xfe5b, 0xfe5b }, +/* 0xfe5c */ { false, 0xfe5c, 0xfe5c }, +/* 0xfe5d */ { false, 0xfe5d, 0xfe5d }, +/* 0xfe5e */ { false, 0xfe5e, 0xfe5e }, +/* 0xfe5f */ { false, 0xfe5f, 0xfe5f }, +/* 0xfe60 */ { false, 0xfe60, 0xfe60 }, +/* 0xfe61 */ { false, 0xfe61, 0xfe61 }, +/* 0xfe62 */ { false, 0xfe62, 0xfe62 }, +/* 0xfe63 */ { false, 0xfe63, 0xfe63 }, +/* 0xfe64 */ { false, 0xfe64, 0xfe64 }, +/* 0xfe65 */ { false, 0xfe65, 0xfe65 }, +/* 0xfe66 */ { false, 0xfe66, 0xfe66 }, +/* 0xfe67 */ { false, 0xfe67, 0xfe67 }, +/* 0xfe68 */ { false, 0xfe68, 0xfe68 }, +/* 0xfe69 */ { false, 0xfe69, 0xfe69 }, +/* 0xfe6a */ { false, 0xfe6a, 0xfe6a }, +/* 0xfe6b */ { false, 0xfe6b, 0xfe6b }, +/* 0xfe6c */ { false, 0xfe6c, 0xfe6c }, +/* 0xfe6d */ { false, 0xfe6d, 0xfe6d }, +/* 0xfe6e */ { false, 0xfe6e, 0xfe6e }, +/* 0xfe6f */ { false, 0xfe6f, 0xfe6f }, +/* 0xfe70 */ { true, 0xfe70, 0xfe70 }, +/* 0xfe71 */ { true, 0xfe71, 0xfe71 }, +/* 0xfe72 */ { true, 0xfe72, 0xfe72 }, +/* 0xfe73 */ { true, 0xfe73, 0xfe73 }, +/* 0xfe74 */ { true, 0xfe74, 0xfe74 }, +/* 0xfe75 */ { false, 0xfe75, 0xfe75 }, +/* 0xfe76 */ { true, 0xfe76, 0xfe76 }, +/* 0xfe77 */ { true, 0xfe77, 0xfe77 }, +/* 0xfe78 */ { true, 0xfe78, 0xfe78 }, +/* 0xfe79 */ { true, 0xfe79, 0xfe79 }, +/* 0xfe7a */ { true, 0xfe7a, 0xfe7a }, +/* 0xfe7b */ { true, 0xfe7b, 0xfe7b }, +/* 0xfe7c */ { true, 0xfe7c, 0xfe7c }, +/* 0xfe7d */ { true, 0xfe7d, 0xfe7d }, +/* 0xfe7e */ { true, 0xfe7e, 0xfe7e }, +/* 0xfe7f */ { true, 0xfe7f, 0xfe7f }, +/* 0xfe80 */ { true, 0xfe80, 0xfe80 }, +/* 0xfe81 */ { true, 0xfe81, 0xfe81 }, +/* 0xfe82 */ { true, 0xfe82, 0xfe82 }, +/* 0xfe83 */ { true, 0xfe83, 0xfe83 }, +/* 0xfe84 */ { true, 0xfe84, 0xfe84 }, +/* 0xfe85 */ { true, 0xfe85, 0xfe85 }, +/* 0xfe86 */ { true, 0xfe86, 0xfe86 }, +/* 0xfe87 */ { true, 0xfe87, 0xfe87 }, +/* 0xfe88 */ { true, 0xfe88, 0xfe88 }, +/* 0xfe89 */ { true, 0xfe89, 0xfe89 }, +/* 0xfe8a */ { true, 0xfe8a, 0xfe8a }, +/* 0xfe8b */ { true, 0xfe8b, 0xfe8b }, +/* 0xfe8c */ { true, 0xfe8c, 0xfe8c }, +/* 0xfe8d */ { true, 0xfe8d, 0xfe8d }, +/* 0xfe8e */ { true, 0xfe8e, 0xfe8e }, +/* 0xfe8f */ { true, 0xfe8f, 0xfe8f }, +/* 0xfe90 */ { true, 0xfe90, 0xfe90 }, +/* 0xfe91 */ { true, 0xfe91, 0xfe91 }, +/* 0xfe92 */ { true, 0xfe92, 0xfe92 }, +/* 0xfe93 */ { true, 0xfe93, 0xfe93 }, +/* 0xfe94 */ { true, 0xfe94, 0xfe94 }, +/* 0xfe95 */ { true, 0xfe95, 0xfe95 }, +/* 0xfe96 */ { true, 0xfe96, 0xfe96 }, +/* 0xfe97 */ { true, 0xfe97, 0xfe97 }, +/* 0xfe98 */ { true, 0xfe98, 0xfe98 }, +/* 0xfe99 */ { true, 0xfe99, 0xfe99 }, +/* 0xfe9a */ { true, 0xfe9a, 0xfe9a }, +/* 0xfe9b */ { true, 0xfe9b, 0xfe9b }, +/* 0xfe9c */ { true, 0xfe9c, 0xfe9c }, +/* 0xfe9d */ { true, 0xfe9d, 0xfe9d }, +/* 0xfe9e */ { true, 0xfe9e, 0xfe9e }, +/* 0xfe9f */ { true, 0xfe9f, 0xfe9f }, +/* 0xfea0 */ { true, 0xfea0, 0xfea0 }, +/* 0xfea1 */ { true, 0xfea1, 0xfea1 }, +/* 0xfea2 */ { true, 0xfea2, 0xfea2 }, +/* 0xfea3 */ { true, 0xfea3, 0xfea3 }, +/* 0xfea4 */ { true, 0xfea4, 0xfea4 }, +/* 0xfea5 */ { true, 0xfea5, 0xfea5 }, +/* 0xfea6 */ { true, 0xfea6, 0xfea6 }, +/* 0xfea7 */ { true, 0xfea7, 0xfea7 }, +/* 0xfea8 */ { true, 0xfea8, 0xfea8 }, +/* 0xfea9 */ { true, 0xfea9, 0xfea9 }, +/* 0xfeaa */ { true, 0xfeaa, 0xfeaa }, +/* 0xfeab */ { true, 0xfeab, 0xfeab }, +/* 0xfeac */ { true, 0xfeac, 0xfeac }, +/* 0xfead */ { true, 0xfead, 0xfead }, +/* 0xfeae */ { true, 0xfeae, 0xfeae }, +/* 0xfeaf */ { true, 0xfeaf, 0xfeaf }, +/* 0xfeb0 */ { true, 0xfeb0, 0xfeb0 }, +/* 0xfeb1 */ { true, 0xfeb1, 0xfeb1 }, +/* 0xfeb2 */ { true, 0xfeb2, 0xfeb2 }, +/* 0xfeb3 */ { true, 0xfeb3, 0xfeb3 }, +/* 0xfeb4 */ { true, 0xfeb4, 0xfeb4 }, +/* 0xfeb5 */ { true, 0xfeb5, 0xfeb5 }, +/* 0xfeb6 */ { true, 0xfeb6, 0xfeb6 }, +/* 0xfeb7 */ { true, 0xfeb7, 0xfeb7 }, +/* 0xfeb8 */ { true, 0xfeb8, 0xfeb8 }, +/* 0xfeb9 */ { true, 0xfeb9, 0xfeb9 }, +/* 0xfeba */ { true, 0xfeba, 0xfeba }, +/* 0xfebb */ { true, 0xfebb, 0xfebb }, +/* 0xfebc */ { true, 0xfebc, 0xfebc }, +/* 0xfebd */ { true, 0xfebd, 0xfebd }, +/* 0xfebe */ { true, 0xfebe, 0xfebe }, +/* 0xfebf */ { true, 0xfebf, 0xfebf }, +/* 0xfec0 */ { true, 0xfec0, 0xfec0 }, +/* 0xfec1 */ { true, 0xfec1, 0xfec1 }, +/* 0xfec2 */ { true, 0xfec2, 0xfec2 }, +/* 0xfec3 */ { true, 0xfec3, 0xfec3 }, +/* 0xfec4 */ { true, 0xfec4, 0xfec4 }, +/* 0xfec5 */ { true, 0xfec5, 0xfec5 }, +/* 0xfec6 */ { true, 0xfec6, 0xfec6 }, +/* 0xfec7 */ { true, 0xfec7, 0xfec7 }, +/* 0xfec8 */ { true, 0xfec8, 0xfec8 }, +/* 0xfec9 */ { true, 0xfec9, 0xfec9 }, +/* 0xfeca */ { true, 0xfeca, 0xfeca }, +/* 0xfecb */ { true, 0xfecb, 0xfecb }, +/* 0xfecc */ { true, 0xfecc, 0xfecc }, +/* 0xfecd */ { true, 0xfecd, 0xfecd }, +/* 0xfece */ { true, 0xfece, 0xfece }, +/* 0xfecf */ { true, 0xfecf, 0xfecf }, +/* 0xfed0 */ { true, 0xfed0, 0xfed0 }, +/* 0xfed1 */ { true, 0xfed1, 0xfed1 }, +/* 0xfed2 */ { true, 0xfed2, 0xfed2 }, +/* 0xfed3 */ { true, 0xfed3, 0xfed3 }, +/* 0xfed4 */ { true, 0xfed4, 0xfed4 }, +/* 0xfed5 */ { true, 0xfed5, 0xfed5 }, +/* 0xfed6 */ { true, 0xfed6, 0xfed6 }, +/* 0xfed7 */ { true, 0xfed7, 0xfed7 }, +/* 0xfed8 */ { true, 0xfed8, 0xfed8 }, +/* 0xfed9 */ { true, 0xfed9, 0xfed9 }, +/* 0xfeda */ { true, 0xfeda, 0xfeda }, +/* 0xfedb */ { true, 0xfedb, 0xfedb }, +/* 0xfedc */ { true, 0xfedc, 0xfedc }, +/* 0xfedd */ { true, 0xfedd, 0xfedd }, +/* 0xfede */ { true, 0xfede, 0xfede }, +/* 0xfedf */ { true, 0xfedf, 0xfedf }, +/* 0xfee0 */ { true, 0xfee0, 0xfee0 }, +/* 0xfee1 */ { true, 0xfee1, 0xfee1 }, +/* 0xfee2 */ { true, 0xfee2, 0xfee2 }, +/* 0xfee3 */ { true, 0xfee3, 0xfee3 }, +/* 0xfee4 */ { true, 0xfee4, 0xfee4 }, +/* 0xfee5 */ { true, 0xfee5, 0xfee5 }, +/* 0xfee6 */ { true, 0xfee6, 0xfee6 }, +/* 0xfee7 */ { true, 0xfee7, 0xfee7 }, +/* 0xfee8 */ { true, 0xfee8, 0xfee8 }, +/* 0xfee9 */ { true, 0xfee9, 0xfee9 }, +/* 0xfeea */ { true, 0xfeea, 0xfeea }, +/* 0xfeeb */ { true, 0xfeeb, 0xfeeb }, +/* 0xfeec */ { true, 0xfeec, 0xfeec }, +/* 0xfeed */ { true, 0xfeed, 0xfeed }, +/* 0xfeee */ { true, 0xfeee, 0xfeee }, +/* 0xfeef */ { true, 0xfeef, 0xfeef }, +/* 0xfef0 */ { true, 0xfef0, 0xfef0 }, +/* 0xfef1 */ { true, 0xfef1, 0xfef1 }, +/* 0xfef2 */ { true, 0xfef2, 0xfef2 }, +/* 0xfef3 */ { true, 0xfef3, 0xfef3 }, +/* 0xfef4 */ { true, 0xfef4, 0xfef4 }, +/* 0xfef5 */ { true, 0xfef5, 0xfef5 }, +/* 0xfef6 */ { true, 0xfef6, 0xfef6 }, +/* 0xfef7 */ { true, 0xfef7, 0xfef7 }, +/* 0xfef8 */ { true, 0xfef8, 0xfef8 }, +/* 0xfef9 */ { true, 0xfef9, 0xfef9 }, +/* 0xfefa */ { true, 0xfefa, 0xfefa }, +/* 0xfefb */ { true, 0xfefb, 0xfefb }, +/* 0xfefc */ { true, 0xfefc, 0xfefc }, +/* 0xfefd */ { false, 0xfefd, 0xfefd }, +/* 0xfefe */ { false, 0xfefe, 0xfefe }, +/* 0xfeff */ { false, 0xfeff, 0xfeff }, +/* 0xff00 */ { false, 0xff00, 0xff00 }, +/* 0xff01 */ { false, 0xff01, 0xff01 }, +/* 0xff02 */ { false, 0xff02, 0xff02 }, +/* 0xff03 */ { false, 0xff03, 0xff03 }, +/* 0xff04 */ { false, 0xff04, 0xff04 }, +/* 0xff05 */ { false, 0xff05, 0xff05 }, +/* 0xff06 */ { false, 0xff06, 0xff06 }, +/* 0xff07 */ { false, 0xff07, 0xff07 }, +/* 0xff08 */ { false, 0xff08, 0xff08 }, +/* 0xff09 */ { false, 0xff09, 0xff09 }, +/* 0xff0a */ { false, 0xff0a, 0xff0a }, +/* 0xff0b */ { false, 0xff0b, 0xff0b }, +/* 0xff0c */ { false, 0xff0c, 0xff0c }, +/* 0xff0d */ { false, 0xff0d, 0xff0d }, +/* 0xff0e */ { false, 0xff0e, 0xff0e }, +/* 0xff0f */ { false, 0xff0f, 0xff0f }, +/* 0xff10 */ { false, 0xff10, 0xff10 }, +/* 0xff11 */ { false, 0xff11, 0xff11 }, +/* 0xff12 */ { false, 0xff12, 0xff12 }, +/* 0xff13 */ { false, 0xff13, 0xff13 }, +/* 0xff14 */ { false, 0xff14, 0xff14 }, +/* 0xff15 */ { false, 0xff15, 0xff15 }, +/* 0xff16 */ { false, 0xff16, 0xff16 }, +/* 0xff17 */ { false, 0xff17, 0xff17 }, +/* 0xff18 */ { false, 0xff18, 0xff18 }, +/* 0xff19 */ { false, 0xff19, 0xff19 }, +/* 0xff1a */ { false, 0xff1a, 0xff1a }, +/* 0xff1b */ { false, 0xff1b, 0xff1b }, +/* 0xff1c */ { false, 0xff1c, 0xff1c }, +/* 0xff1d */ { false, 0xff1d, 0xff1d }, +/* 0xff1e */ { false, 0xff1e, 0xff1e }, +/* 0xff1f */ { false, 0xff1f, 0xff1f }, +/* 0xff20 */ { false, 0xff20, 0xff20 }, +/* 0xff21 */ { true, 0xff21, 0xff41 }, +/* 0xff22 */ { true, 0xff22, 0xff42 }, +/* 0xff23 */ { true, 0xff23, 0xff43 }, +/* 0xff24 */ { true, 0xff24, 0xff44 }, +/* 0xff25 */ { true, 0xff25, 0xff45 }, +/* 0xff26 */ { true, 0xff26, 0xff46 }, +/* 0xff27 */ { true, 0xff27, 0xff47 }, +/* 0xff28 */ { true, 0xff28, 0xff48 }, +/* 0xff29 */ { true, 0xff29, 0xff49 }, +/* 0xff2a */ { true, 0xff2a, 0xff4a }, +/* 0xff2b */ { true, 0xff2b, 0xff4b }, +/* 0xff2c */ { true, 0xff2c, 0xff4c }, +/* 0xff2d */ { true, 0xff2d, 0xff4d }, +/* 0xff2e */ { true, 0xff2e, 0xff4e }, +/* 0xff2f */ { true, 0xff2f, 0xff4f }, +/* 0xff30 */ { true, 0xff30, 0xff50 }, +/* 0xff31 */ { true, 0xff31, 0xff51 }, +/* 0xff32 */ { true, 0xff32, 0xff52 }, +/* 0xff33 */ { true, 0xff33, 0xff53 }, +/* 0xff34 */ { true, 0xff34, 0xff54 }, +/* 0xff35 */ { true, 0xff35, 0xff55 }, +/* 0xff36 */ { true, 0xff36, 0xff56 }, +/* 0xff37 */ { true, 0xff37, 0xff57 }, +/* 0xff38 */ { true, 0xff38, 0xff58 }, +/* 0xff39 */ { true, 0xff39, 0xff59 }, +/* 0xff3a */ { true, 0xff3a, 0xff5a }, +/* 0xff3b */ { false, 0xff3b, 0xff3b }, +/* 0xff3c */ { false, 0xff3c, 0xff3c }, +/* 0xff3d */ { false, 0xff3d, 0xff3d }, +/* 0xff3e */ { false, 0xff3e, 0xff3e }, +/* 0xff3f */ { false, 0xff3f, 0xff3f }, +/* 0xff40 */ { false, 0xff40, 0xff40 }, +/* 0xff41 */ { true, 0xff21, 0xff41 }, +/* 0xff42 */ { true, 0xff22, 0xff42 }, +/* 0xff43 */ { true, 0xff23, 0xff43 }, +/* 0xff44 */ { true, 0xff24, 0xff44 }, +/* 0xff45 */ { true, 0xff25, 0xff45 }, +/* 0xff46 */ { true, 0xff26, 0xff46 }, +/* 0xff47 */ { true, 0xff27, 0xff47 }, +/* 0xff48 */ { true, 0xff28, 0xff48 }, +/* 0xff49 */ { true, 0xff29, 0xff49 }, +/* 0xff4a */ { true, 0xff2a, 0xff4a }, +/* 0xff4b */ { true, 0xff2b, 0xff4b }, +/* 0xff4c */ { true, 0xff2c, 0xff4c }, +/* 0xff4d */ { true, 0xff2d, 0xff4d }, +/* 0xff4e */ { true, 0xff2e, 0xff4e }, +/* 0xff4f */ { true, 0xff2f, 0xff4f }, +/* 0xff50 */ { true, 0xff30, 0xff50 }, +/* 0xff51 */ { true, 0xff31, 0xff51 }, +/* 0xff52 */ { true, 0xff32, 0xff52 }, +/* 0xff53 */ { true, 0xff33, 0xff53 }, +/* 0xff54 */ { true, 0xff34, 0xff54 }, +/* 0xff55 */ { true, 0xff35, 0xff55 }, +/* 0xff56 */ { true, 0xff36, 0xff56 }, +/* 0xff57 */ { true, 0xff37, 0xff57 }, +/* 0xff58 */ { true, 0xff38, 0xff58 }, +/* 0xff59 */ { true, 0xff39, 0xff59 }, +/* 0xff5a */ { true, 0xff3a, 0xff5a }, +/* 0xff5b */ { false, 0xff5b, 0xff5b }, +/* 0xff5c */ { false, 0xff5c, 0xff5c }, +/* 0xff5d */ { false, 0xff5d, 0xff5d }, +/* 0xff5e */ { false, 0xff5e, 0xff5e }, +/* 0xff5f */ { false, 0xff5f, 0xff5f }, +/* 0xff60 */ { false, 0xff60, 0xff60 }, +/* 0xff61 */ { false, 0xff61, 0xff61 }, +/* 0xff62 */ { false, 0xff62, 0xff62 }, +/* 0xff63 */ { false, 0xff63, 0xff63 }, +/* 0xff64 */ { false, 0xff64, 0xff64 }, +/* 0xff65 */ { false, 0xff65, 0xff65 }, +/* 0xff66 */ { true, 0xff66, 0xff66 }, +/* 0xff67 */ { true, 0xff67, 0xff67 }, +/* 0xff68 */ { true, 0xff68, 0xff68 }, +/* 0xff69 */ { true, 0xff69, 0xff69 }, +/* 0xff6a */ { true, 0xff6a, 0xff6a }, +/* 0xff6b */ { true, 0xff6b, 0xff6b }, +/* 0xff6c */ { true, 0xff6c, 0xff6c }, +/* 0xff6d */ { true, 0xff6d, 0xff6d }, +/* 0xff6e */ { true, 0xff6e, 0xff6e }, +/* 0xff6f */ { true, 0xff6f, 0xff6f }, +/* 0xff70 */ { true, 0xff70, 0xff70 }, +/* 0xff71 */ { true, 0xff71, 0xff71 }, +/* 0xff72 */ { true, 0xff72, 0xff72 }, +/* 0xff73 */ { true, 0xff73, 0xff73 }, +/* 0xff74 */ { true, 0xff74, 0xff74 }, +/* 0xff75 */ { true, 0xff75, 0xff75 }, +/* 0xff76 */ { true, 0xff76, 0xff76 }, +/* 0xff77 */ { true, 0xff77, 0xff77 }, +/* 0xff78 */ { true, 0xff78, 0xff78 }, +/* 0xff79 */ { true, 0xff79, 0xff79 }, +/* 0xff7a */ { true, 0xff7a, 0xff7a }, +/* 0xff7b */ { true, 0xff7b, 0xff7b }, +/* 0xff7c */ { true, 0xff7c, 0xff7c }, +/* 0xff7d */ { true, 0xff7d, 0xff7d }, +/* 0xff7e */ { true, 0xff7e, 0xff7e }, +/* 0xff7f */ { true, 0xff7f, 0xff7f }, +/* 0xff80 */ { true, 0xff80, 0xff80 }, +/* 0xff81 */ { true, 0xff81, 0xff81 }, +/* 0xff82 */ { true, 0xff82, 0xff82 }, +/* 0xff83 */ { true, 0xff83, 0xff83 }, +/* 0xff84 */ { true, 0xff84, 0xff84 }, +/* 0xff85 */ { true, 0xff85, 0xff85 }, +/* 0xff86 */ { true, 0xff86, 0xff86 }, +/* 0xff87 */ { true, 0xff87, 0xff87 }, +/* 0xff88 */ { true, 0xff88, 0xff88 }, +/* 0xff89 */ { true, 0xff89, 0xff89 }, +/* 0xff8a */ { true, 0xff8a, 0xff8a }, +/* 0xff8b */ { true, 0xff8b, 0xff8b }, +/* 0xff8c */ { true, 0xff8c, 0xff8c }, +/* 0xff8d */ { true, 0xff8d, 0xff8d }, +/* 0xff8e */ { true, 0xff8e, 0xff8e }, +/* 0xff8f */ { true, 0xff8f, 0xff8f }, +/* 0xff90 */ { true, 0xff90, 0xff90 }, +/* 0xff91 */ { true, 0xff91, 0xff91 }, +/* 0xff92 */ { true, 0xff92, 0xff92 }, +/* 0xff93 */ { true, 0xff93, 0xff93 }, +/* 0xff94 */ { true, 0xff94, 0xff94 }, +/* 0xff95 */ { true, 0xff95, 0xff95 }, +/* 0xff96 */ { true, 0xff96, 0xff96 }, +/* 0xff97 */ { true, 0xff97, 0xff97 }, +/* 0xff98 */ { true, 0xff98, 0xff98 }, +/* 0xff99 */ { true, 0xff99, 0xff99 }, +/* 0xff9a */ { true, 0xff9a, 0xff9a }, +/* 0xff9b */ { true, 0xff9b, 0xff9b }, +/* 0xff9c */ { true, 0xff9c, 0xff9c }, +/* 0xff9d */ { true, 0xff9d, 0xff9d }, +/* 0xff9e */ { true, 0xff9e, 0xff9e }, +/* 0xff9f */ { true, 0xff9f, 0xff9f }, +/* 0xffa0 */ { true, 0xffa0, 0xffa0 }, +/* 0xffa1 */ { true, 0xffa1, 0xffa1 }, +/* 0xffa2 */ { true, 0xffa2, 0xffa2 }, +/* 0xffa3 */ { true, 0xffa3, 0xffa3 }, +/* 0xffa4 */ { true, 0xffa4, 0xffa4 }, +/* 0xffa5 */ { true, 0xffa5, 0xffa5 }, +/* 0xffa6 */ { true, 0xffa6, 0xffa6 }, +/* 0xffa7 */ { true, 0xffa7, 0xffa7 }, +/* 0xffa8 */ { true, 0xffa8, 0xffa8 }, +/* 0xffa9 */ { true, 0xffa9, 0xffa9 }, +/* 0xffaa */ { true, 0xffaa, 0xffaa }, +/* 0xffab */ { true, 0xffab, 0xffab }, +/* 0xffac */ { true, 0xffac, 0xffac }, +/* 0xffad */ { true, 0xffad, 0xffad }, +/* 0xffae */ { true, 0xffae, 0xffae }, +/* 0xffaf */ { true, 0xffaf, 0xffaf }, +/* 0xffb0 */ { true, 0xffb0, 0xffb0 }, +/* 0xffb1 */ { true, 0xffb1, 0xffb1 }, +/* 0xffb2 */ { true, 0xffb2, 0xffb2 }, +/* 0xffb3 */ { true, 0xffb3, 0xffb3 }, +/* 0xffb4 */ { true, 0xffb4, 0xffb4 }, +/* 0xffb5 */ { true, 0xffb5, 0xffb5 }, +/* 0xffb6 */ { true, 0xffb6, 0xffb6 }, +/* 0xffb7 */ { true, 0xffb7, 0xffb7 }, +/* 0xffb8 */ { true, 0xffb8, 0xffb8 }, +/* 0xffb9 */ { true, 0xffb9, 0xffb9 }, +/* 0xffba */ { true, 0xffba, 0xffba }, +/* 0xffbb */ { true, 0xffbb, 0xffbb }, +/* 0xffbc */ { true, 0xffbc, 0xffbc }, +/* 0xffbd */ { true, 0xffbd, 0xffbd }, +/* 0xffbe */ { true, 0xffbe, 0xffbe }, +/* 0xffbf */ { false, 0xffbf, 0xffbf }, +/* 0xffc0 */ { false, 0xffc0, 0xffc0 }, +/* 0xffc1 */ { false, 0xffc1, 0xffc1 }, +/* 0xffc2 */ { true, 0xffc2, 0xffc2 }, +/* 0xffc3 */ { true, 0xffc3, 0xffc3 }, +/* 0xffc4 */ { true, 0xffc4, 0xffc4 }, +/* 0xffc5 */ { true, 0xffc5, 0xffc5 }, +/* 0xffc6 */ { true, 0xffc6, 0xffc6 }, +/* 0xffc7 */ { true, 0xffc7, 0xffc7 }, +/* 0xffc8 */ { false, 0xffc8, 0xffc8 }, +/* 0xffc9 */ { false, 0xffc9, 0xffc9 }, +/* 0xffca */ { true, 0xffca, 0xffca }, +/* 0xffcb */ { true, 0xffcb, 0xffcb }, +/* 0xffcc */ { true, 0xffcc, 0xffcc }, +/* 0xffcd */ { true, 0xffcd, 0xffcd }, +/* 0xffce */ { true, 0xffce, 0xffce }, +/* 0xffcf */ { true, 0xffcf, 0xffcf }, +/* 0xffd0 */ { false, 0xffd0, 0xffd0 }, +/* 0xffd1 */ { false, 0xffd1, 0xffd1 }, +/* 0xffd2 */ { true, 0xffd2, 0xffd2 }, +/* 0xffd3 */ { true, 0xffd3, 0xffd3 }, +/* 0xffd4 */ { true, 0xffd4, 0xffd4 }, +/* 0xffd5 */ { true, 0xffd5, 0xffd5 }, +/* 0xffd6 */ { true, 0xffd6, 0xffd6 }, +/* 0xffd7 */ { true, 0xffd7, 0xffd7 }, +/* 0xffd8 */ { false, 0xffd8, 0xffd8 }, +/* 0xffd9 */ { false, 0xffd9, 0xffd9 }, +/* 0xffda */ { true, 0xffda, 0xffda }, +/* 0xffdb */ { true, 0xffdb, 0xffdb }, +/* 0xffdc */ { true, 0xffdc, 0xffdc }, +/* 0xffdd */ { false, 0xffdd, 0xffdd }, +/* 0xffde */ { false, 0xffde, 0xffde }, +/* 0xffdf */ { false, 0xffdf, 0xffdf }, +/* 0xffe0 */ { false, 0xffe0, 0xffe0 }, +/* 0xffe1 */ { false, 0xffe1, 0xffe1 }, +/* 0xffe2 */ { false, 0xffe2, 0xffe2 }, +/* 0xffe3 */ { false, 0xffe3, 0xffe3 }, +/* 0xffe4 */ { false, 0xffe4, 0xffe4 }, +/* 0xffe5 */ { false, 0xffe5, 0xffe5 }, +/* 0xffe6 */ { false, 0xffe6, 0xffe6 }, +/* 0xffe7 */ { false, 0xffe7, 0xffe7 }, +/* 0xffe8 */ { false, 0xffe8, 0xffe8 }, +/* 0xffe9 */ { false, 0xffe9, 0xffe9 }, +/* 0xffea */ { false, 0xffea, 0xffea }, +/* 0xffeb */ { false, 0xffeb, 0xffeb }, +/* 0xffec */ { false, 0xffec, 0xffec }, +/* 0xffed */ { false, 0xffed, 0xffed }, +/* 0xffee */ { false, 0xffee, 0xffee }, +/* 0xffef */ { false, 0xffef, 0xffef }, +/* 0xfff0 */ { false, 0xfff0, 0xfff0 }, +/* 0xfff1 */ { false, 0xfff1, 0xfff1 }, +/* 0xfff2 */ { false, 0xfff2, 0xfff2 }, +/* 0xfff3 */ { false, 0xfff3, 0xfff3 }, +/* 0xfff4 */ { false, 0xfff4, 0xfff4 }, +/* 0xfff5 */ { false, 0xfff5, 0xfff5 }, +/* 0xfff6 */ { false, 0xfff6, 0xfff6 }, +/* 0xfff7 */ { false, 0xfff7, 0xfff7 }, +/* 0xfff8 */ { false, 0xfff8, 0xfff8 }, +/* 0xfff9 */ { false, 0xfff9, 0xfff9 }, +/* 0xfffa */ { false, 0xfffa, 0xfffa }, +/* 0xfffb */ { false, 0xfffb, 0xfffb }, +/* 0xfffc */ { false, 0xfffc, 0xfffc }, +/* 0xfffd */ { false, 0xfffd, 0xfffd }, +/* 0xfffe */ { false, 0xfffe, 0xfffe }, +/* 0xffff */ { false, 0xffff, 0xffff }, +}; +// clang-format on diff --git a/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/w_char.hxx b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/w_char.hxx new file mode 100644 index 00000000..614b729c --- /dev/null +++ b/packages/busymark_spellcheck_native/third_party/hunspell/src/hunspell/w_char.hxx @@ -0,0 +1,92 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * Copyright (C) 2002-2022 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 + +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#include +#endif +#include + +#ifndef GCC +struct w_char { +#else +struct __attribute__((packed)) w_char { +#endif + unsigned char l; + unsigned char h; + + operator unsigned short() const + { +#if defined(_WIN32) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)) || defined(__LITTLE_ENDIAN__) + //use little-endian optimized version +#if (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) && defined __cpp_lib_bit_cast && __cpp_lib_bit_cast >= 201806L + return std::bit_cast(*this); +#else + unsigned short u; + memcpy(&u, this, sizeof(unsigned short)); + return u; +#endif + +#else + return ((unsigned short)h << 8) | (unsigned short)l; +#endif + } + + friend bool operator<(const w_char a, const w_char b) { + return (unsigned short)a < (unsigned short)b; + } + + friend bool operator==(const w_char a, const w_char b) { + return (unsigned short)a == (unsigned short)b; + } + + 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 diff --git a/packages/busymark_spellcheck_native/tool/fetch_hunspell.sh b/packages/busymark_spellcheck_native/tool/fetch_hunspell.sh new file mode 100755 index 00000000..2175d44f --- /dev/null +++ b/packages/busymark_spellcheck_native/tool/fetch_hunspell.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -euo pipefail + +HUNSPELL_VERSION="1.7.3" +HUNSPELL_REVISION="c5f98152a274e25b5107101104bef632b83a0cc9" +HUNSPELL_ARCHIVE_SHA256="933be3dac6fd55f6e752331a170efb7e33800e40fae1156d8434cc8c85379a1b" +HUNSPELL_URL="https://github.com/hunspell/hunspell/archive/refs/tags/v${HUNSPELL_VERSION}.tar.gz" + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +PACKAGE_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)" +DESTINATION="${PACKAGE_DIR}/third_party/hunspell" +TEMP_DIR="$(mktemp -d)" +trap 'rm -rf -- "${TEMP_DIR}"' EXIT + +ARCHIVE="${TEMP_DIR}/hunspell.tar.gz" +if [[ -n "${BUSYMARK_HUNSPELL_ARCHIVE:-}" ]]; then + cp -- "${BUSYMARK_HUNSPELL_ARCHIVE}" "${ARCHIVE}" +else + curl --fail --location --retry 3 --retry-delay 1 \ + --output "${ARCHIVE}" "${HUNSPELL_URL}" +fi +printf '%s %s\n' "${HUNSPELL_ARCHIVE_SHA256}" "${ARCHIVE}" | + sha256sum --check --status + +mkdir -p -- "${TEMP_DIR}/source" "${TEMP_DIR}/prepared/src" +tar --extract --gzip --file "${ARCHIVE}" --directory "${TEMP_DIR}/source" \ + --strip-components=1 +cp -R -- "${TEMP_DIR}/source/src/hunspell" "${TEMP_DIR}/prepared/src/" +mkdir -p -- "${TEMP_DIR}/prepared/licenses" +for license in COPYING COPYING.LESSER COPYING.MPL license.hunspell license.myspell; do + test -f "${TEMP_DIR}/source/${license}" + cp -- "${TEMP_DIR}/source/${license}" "${TEMP_DIR}/prepared/licenses/${license}" +done +printf '%s\n' "${HUNSPELL_REVISION}" > "${TEMP_DIR}/prepared/REVISION" +printf '%s\n' "${HUNSPELL_ARCHIVE_SHA256}" > "${TEMP_DIR}/prepared/ARCHIVE.sha256" + +rm -rf -- "${DESTINATION}" +mv -- "${TEMP_DIR}/prepared" "${DESTINATION}" diff --git a/pubspec.lock b/pubspec.lock index ee4391ac..8bcc1ff1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -73,8 +73,15 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + busymark_spellcheck_native: + dependency: "direct main" + description: + path: "packages/busymark_spellcheck_native" + relative: true + source: path + version: "0.1.0" characters: - dependency: transitive + dependency: "direct main" description: name: characters sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b @@ -533,6 +540,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: a1c26117c48cebe5677b0cf0e33a980a79a7c5577effc86f52e5a0d309cdcb60 + url: "https://pub.dev" + source: hosted + version: "0.19.3" node_preamble: dependency: transitive description: @@ -898,6 +913,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.2+3" + unorm_dart: + dependency: "direct main" + description: + name: unorm_dart + sha256: "0c69186b03ca6addab0774bcc0f4f17b88d4ce78d9d4d8f0619e30a99ead58e7" + url: "https://pub.dev" + source: hosted + version: "0.3.2" url_launcher: dependency: "direct main" description: @@ -1140,4 +1163,4 @@ packages: version: "0.0.4" sdks: dart: ">=3.12.1 <4.0.0" - flutter: "3.47.2" + flutter: "3.47.4" diff --git a/pubspec.yaml b/pubspec.yaml index 770406e2..2c6470c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,17 +1,20 @@ name: busymark description: Local-first Markdown and Writerside-compatible documentation editor. publish_to: 'none' -version: 0.4.2 +version: 0.5.0 environment: sdk: ">=3.12.1 <4.0.0" - flutter: 3.47.2 + flutter: 3.47.4 dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter + busymark_spellcheck_native: + path: packages/busymark_spellcheck_native + characters: ^1.4.1 crypto: ^3.0.6 csslib: ^1.0.2 dbus: ^0.7.13 @@ -31,6 +34,7 @@ dependencies: ubuntu_localizations: ^0.5.2+3 url_launcher: ^6.3.2 uuid: ^4.6.0 + unorm_dart: ^0.3.2 window_manager: ^0.5.1 xml: ^7.0.1 yaru: ^10.1.0 @@ -48,3 +52,4 @@ flutter: - assets/export/html.css - assets/export/markdown.typ - assets/writerside/templates.json + - assets/spelling/dictionaries.json diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 1767fd4d..e0cfc2c9 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: busymark title: BusyMark -version: "0.4.2" +version: "0.5.0" summary: Markdown and Writerside documentation editor # Snap Store listing translations are managed outside this Flutter package. # Update store metadata when approved translated listing text is supplied. @@ -54,6 +54,7 @@ apps: XDG_CACHE_HOME: $SNAP_USER_DATA/.cache XDG_CONFIG_HOME: $SNAP_USER_DATA/.config XDG_DATA_HOME: $SNAP_USER_DATA/.local/share + BUSYMARK_SPELLING_INSTALL_ROOT: $SNAP_USER_COMMON/spelling/dictionaries parts: busymark: @@ -64,7 +65,7 @@ parts: flutter-target: lib/main.dart flutter-channel: stable build-environment: - - BUSYMARK_FLUTTER_VERSION: "3.47.2" + - BUSYMARK_FLUTTER_VERSION: "3.47.4" build-snaps: - node/24/stable build-packages: @@ -72,6 +73,8 @@ parts: - fonts-noto-mono - curl - libhandy-1-dev + - libglib2.0-dev + - libpango1.0-dev - libsecret-1-dev - libwebkit2gtk-4.1-dev - xz-utils @@ -80,6 +83,8 @@ parts: - libsecret-1-0 - libwebkit2gtk-4.1-0 - libgtk-3-0t64 + - libglib2.0-0t64 + - libpango-1.0-0 - gstreamer1.0-libav - gstreamer1.0-plugins-bad - gstreamer1.0-plugins-base diff --git a/test/fixtures/clipboard/layout_table_job.html b/test/fixtures/clipboard/layout_table_job.html new file mode 100644 index 00000000..3071d152 --- /dev/null +++ b/test/fixtures/clipboard/layout_table_job.html @@ -0,0 +1,28 @@ + + + + + + + + + +

Example Developer

+ + + + + + +
ReferenceExample-42
LocationExample City
ScheduleFull time
+
Job Description
+

About the team

+

We build helpful tools for our community.

+
  • Design accessible interfaces.
  • Test changes carefully.
+

Work with colleagues across the organization.

+

Qualifications

+
  • Experience delivering reliable software.
+

Closing invitation with application details.

+

 

+

Send questions to team@example.test.

+
diff --git a/test/fixtures/spelling/pasted_job.html b/test/fixtures/spelling/pasted_job.html new file mode 100644 index 00000000..285dc588 --- /dev/null +++ b/test/fixtures/spelling/pasted_job.html @@ -0,0 +1,14 @@ + +
+

Example Developer

+ +
Reference #Example-42
LocationExample City
+


Team responsibilities

+

Build helpful tools and test changes carefully.

+
  • Design accessible interfaces.
  • Work with colleagues.
+

General team support

+

Inclusive workplace with respectful colleagues.

+

Apply at https://example.test/careers.

+

Send questions to team@example.test for assistance.

+

Final helo after all the formatted content.

+
diff --git a/test/fixtures/spelling/pasted_job.md b/test/fixtures/spelling/pasted_job.md new file mode 100644 index 00000000..1916fabc --- /dev/null +++ b/test/fixtures/spelling/pasted_job.md @@ -0,0 +1,22 @@ +## Example Developer + +| Reference # | Example-42 | +| --- | --- | +| Location | Example City | + +***Team responsibilities +
+
*** + +Build helpful tools and test changes carefully. +
+
+ +- Design accessible interfaces. +- Work with colleagues. + +Apply at [https://example.test/careers](https://example.test/careers). + +*Send questions to *[team@example.test](mailto:team@example.test "Email team@example.test")* for assistance.* + +Final helo after all the formatted content. diff --git a/test/src/app_router_test.dart b/test/src/app_router_test.dart index ac32951a..ec75c82e 100644 --- a/test/src/app_router_test.dart +++ b/test/src/app_router_test.dart @@ -70,11 +70,15 @@ void main() { test('settings page routes are explicit and validated', () { expect(settingsPageFromRouteValue(null), SettingsPage.appearance); expect(settingsPageFromRouteValue('editor'), SettingsPage.editor); + expect( + settingsPageFromRouteValue('spellingDictionaries'), + SettingsPage.spellingDictionaries, + ); expect(settingsPageFromRouteValue('validation'), SettingsPage.validation); expect(settingsPageFromRouteValue('ai'), SettingsPage.ai); - expect(settingsPageFromRouteValue('window'), SettingsPage.window); + expect(settingsPageFromRouteValue('window'), SettingsPage.history); expect(settingsPageFromRouteValue('privacy'), SettingsPage.privacy); - expect(settingsPageFromRouteValue('advanced'), SettingsPage.advanced); + expect(settingsPageFromRouteValue('advanced'), SettingsPage.history); expect(settingsPageFromRouteValue('unexpected'), SettingsPage.appearance); expect( SettingsPage.values.map(settingsPageRouteValue), diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index 5b0a0748..9e94ae2e 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -9,6 +9,7 @@ import 'package:busymark/l10n/generated/app_localizations_en.dart'; import 'package:busymark/l10n/generated/app_localizations_fa.dart'; import 'package:busymark/l10n/generated/app_localizations_fr.dart'; import 'package:busymark/src/app/app_metadata.dart'; +import 'package:busymark/src/app/app_router.dart'; import 'package:busymark/src/app/app_settings.dart'; import 'package:busymark/src/app/busymark_app.dart'; import 'package:busymark/src/app/busymark_dialogs.dart'; @@ -23,7 +24,10 @@ import 'package:busymark/src/core/busymark_exception.dart'; import 'package:busymark/src/core/diagnostic.dart'; import 'package:busymark/src/core/local_image_resolver.dart'; import 'package:busymark/src/core/source_span.dart'; +import 'package:busymark/src/clipboard/clipboard_history_controller.dart'; import 'package:busymark/src/clipboard/clipboard_history_panel.dart'; +import 'package:busymark/src/clipboard/clipboard_insertion.dart'; +import 'package:busymark/src/clipboard/clipboard_models.dart'; import 'package:busymark/src/editor/document_callout.dart'; import 'package:busymark/src/editor/document_code_block.dart'; import 'package:busymark/src/editor/document_layout.dart'; @@ -36,6 +40,7 @@ import 'package:busymark/src/editor/source/source_search.dart'; import 'package:busymark/src/editor/source_highlighter.dart' show BusyMarkSourceEditingController; import 'package:busymark/src/editor/source/source_read_only_view.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; import 'package:busymark/src/feedback/presentation/feedback_dialog.dart'; import 'package:busymark/src/export/export_options_editor.dart'; import 'package:busymark/src/git/application/git_controller.dart'; @@ -48,6 +53,9 @@ import 'package:busymark/src/markdown/preview_model.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/platform/linux_header_bar_service.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:busymark/src/spellcheck/spelling_dictionary_downloader.dart'; +import 'package:busymark/src/spellcheck/spelling_session_controller.dart'; import 'package:busymark/src/writerside/writerside_model.dart'; import 'package:busymark/src/writerside/writerside_project.dart'; import 'package:busymark/src/writerside/writerside_toc_editor.dart'; @@ -56,6 +64,8 @@ import 'package:busymark/src/writerside/writerside_topic_file_editor.dart'; import 'package:busymark/src/writerside/writerside_topic_removal_service.dart'; import 'package:busymark/src/workspace/presentation/settings_screen.dart'; import 'package:busymark/src/workspace/document_buffer.dart'; +import 'package:busymark/src/workspace/recovery_persistence.dart'; +import 'package:busymark/src/workspace/session_persistence.dart'; import 'package:busymark/src/workspace/workspace_controller.dart'; import 'package:busymark/src/workspace/workspace_file_monitor.dart'; import 'package:busymark/src/workspace/workspace_message.dart'; @@ -73,6 +83,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; import 'package:window_manager/window_manager.dart'; +import '../support/spelling_test_bundle.dart'; + void main() { late _FallbackHeaderBarService headerBarService; final l10n = AppLocalizationsEn(); @@ -80,6 +92,12 @@ void main() { setUp(() { final binding = TestWidgetsFlutterBinding.ensureInitialized(); binding.platformDispatcher.defaultRouteNameTestValue = '/'; + for (final channelName in ['yaru_window', 'yaru_window/events']) { + binding.defaultBinaryMessenger.setMockMethodCallHandler( + MethodChannel(channelName), + (call) async => call.method == 'state' ? {} : null, + ); + } headerBarService = _FallbackHeaderBarService(); }); @@ -117,11 +135,18 @@ void main() { BusyMarkEditorShortcutAction.hardLineBreak: 'Shift+Enter', }, ); + final pastePlainText = BusyMarkTextEditingShortcuts + .definitions[BusyMarkTextEditingShortcutAction.pastePlainText]!; + expect(pastePlainText.label, 'Ctrl+Shift+V'); + final activator = pastePlainText.activator as SingleActivator; + expect(activator.trigger, LogicalKeyboardKey.keyV); + expect(activator.control, isTrue); + expect(activator.shift, isTrue); expect( - BusyMarkTextEditingShortcuts.definitions.values.map( - (definition) => definition.label, + BusyMarkTextEditingShortcuts.definitions.values.where( + (definition) => definition.activator == activator, ), - isNot(contains('Ctrl+Shift+V')), + hasLength(1), ); }); @@ -161,6 +186,275 @@ void main() { } }); + testWidgets( + 'workspace routes paste shortcuts only to editable document views', + (tester) async { + var generation = 0; + var clipboardText = ''; + var readCount = 0; + const clipboardChannel = MethodChannel(richClipboardChannelName); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + clipboardChannel, + (call) async { + if (call.method != 'read') return null; + readCount += 1; + return { + 'text': clipboardText, + 'generation': generation, + }; + }, + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + clipboardChannel, + null, + ), + ); + + final settingsStore = _MemorySettingsStore() + ..value = AppSettings.defaults() + .copyWith( + autoSave: false, + documentViewMode: DocumentViewModePreference.editor, + ) + .toJson(); + const service = _SearchWorkspaceService('start'); + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue(settingsStore), + workspaceServiceProvider.overrideWithValue(service), + startupPathProvider.overrideWithValue('/tmp/workspace-paste.md'), + ], + ); + addTearDown(container.dispose); + + Future pressPaste(BusyMarkPasteMode mode) async { + final useShift = mode == BusyMarkPasteMode.plainText; + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + if (useShift) { + await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); + } + await tester.sendKeyEvent(LogicalKeyboardKey.keyV); + if (useShift) { + await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft); + } + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pump(const Duration(milliseconds: 100)); + } + + Future selectView(DocumentViewModePreference mode) async { + container + .read(workspaceControllerProvider.notifier) + .updateActiveEditorMode(mode); + await container + .read(appSettingsControllerProvider.notifier) + .setDocumentViewMode(mode); + for (var index = 0; index < 10; index += 1) { + await tester.pump(const Duration(milliseconds: 100)); + } + } + + Future focusLastEditableTextField() async { + final field = find.byType(TextField).last; + await tester.tap(field); + await tester.showKeyboard(field); + final controller = tester.widget(field).controller!; + controller.selection = TextSelection.collapsed( + offset: controller.text.length, + ); + await tester.pump(); + } + + Future typeSuffix(String suffix) async { + final field = find.byType(TextField).last; + final controller = tester.widget(field).controller!; + await tester.enterText(field, '${controller.text}$suffix'); + await tester.pump(const Duration(milliseconds: 100)); + } + + Future expectUndoRedoSequence({ + required BusyMarkPasteMode mode, + BusyMarkClipboardPayload? historyPayload, + String pasteText = 'b', + bool replaceTypedCharacter = false, + }) async { + final workspace = container.read(workspaceControllerProvider.notifier); + final original = container.read(workspaceControllerProvider).activeText; + await typeSuffix('a'); + final afterTyping = container + .read(workspaceControllerProvider) + .activeText; + if (replaceTypedCharacter) { + final field = find.byType(TextField).last; + final controller = tester.widget(field).controller!; + controller.selection = TextSelection( + baseOffset: controller.text.length - 1, + extentOffset: controller.text.length, + ); + await tester.pump(); + } + if (historyPayload == null) { + clipboardText = pasteText; + generation += 1; + await pressPaste(mode); + } else { + expect( + await container + .read(clipboardInsertionRegistryProvider) + .paste(historyPayload, mode: mode), + ClipboardPasteResult.inserted, + ); + await tester.pump(const Duration(milliseconds: 100)); + } + final afterPaste = container + .read(workspaceControllerProvider) + .activeText; + await typeSuffix('c'); + final afterFollowingTyping = container + .read(workspaceControllerProvider) + .activeText; + + workspace.undoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + afterPaste, + ); + workspace.undoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + afterTyping, + ); + workspace.undoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + original, + ); + + workspace.redoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + afterTyping, + ); + workspace.redoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + afterPaste, + ); + workspace.redoActiveBuffer(); + await tester.pump(const Duration(milliseconds: 100)); + expect( + container.read(workspaceControllerProvider).activeText, + afterFollowingTyping, + ); + } + + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const BusyMarkApp(), + ), + ); + for (var index = 0; index < 30; index += 1) { + await tester.pump(const Duration(milliseconds: 100)); + if (find + .byKey(const ValueKey('document-wysiwyg-pane')) + .evaluate() + .isNotEmpty) { + break; + } + } + + await focusLastEditableTextField(); + await expectUndoRedoSequence(mode: BusyMarkPasteMode.normal); + await focusLastEditableTextField(); + await expectUndoRedoSequence(mode: BusyMarkPasteMode.plainText); + await focusLastEditableTextField(); + await expectUndoRedoSequence( + mode: BusyMarkPasteMode.normal, + historyPayload: BusyMarkClipboardPayload( + id: 'workspace-history-paste', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + text: 'b', + external: true, + ), + ); + await focusLastEditableTextField(); + await expectUndoRedoSequence( + mode: BusyMarkPasteMode.normal, + replaceTypedCharacter: true, + ); + await focusLastEditableTextField(); + await expectUndoRedoSequence( + mode: BusyMarkPasteMode.normal, + pasteText: 'b\nline', + ); + await focusLastEditableTextField(); + clipboardText = ' editor-normal'; + generation += 1; + await pressPaste(BusyMarkPasteMode.normal); + clipboardText = ' editor-plain'; + generation += 1; + await pressPaste(BusyMarkPasteMode.plainText); + expect( + container.read(workspaceControllerProvider).activeText, + contains('editor-normal editor-plain'), + ); + + await selectView(DocumentViewModePreference.source); + expect(find.byType(BusyMarkSourceEditor), findsOneWidget); + await focusLastEditableTextField(); + await expectUndoRedoSequence(mode: BusyMarkPasteMode.normal); + await focusLastEditableTextField(); + await expectUndoRedoSequence(mode: BusyMarkPasteMode.plainText); + await focusLastEditableTextField(); + clipboardText = ' source-normal'; + generation += 1; + await pressPaste(BusyMarkPasteMode.normal); + clipboardText = ' source-plain'; + generation += 1; + await pressPaste(BusyMarkPasteMode.plainText); + expect( + container.read(workspaceControllerProvider).activeText, + contains('source-normal source-plain'), + ); + + await selectView(DocumentViewModePreference.split); + expect(find.byType(BusyMarkSourceEditor), findsOneWidget); + await focusLastEditableTextField(); + clipboardText = ' split-source'; + generation += 1; + await pressPaste(BusyMarkPasteMode.plainText); + expect( + container.read(workspaceControllerProvider).activeText, + endsWith(' split-source'), + ); + + await selectView(DocumentViewModePreference.preview); + expect(find.byType(BusyMarkSourceEditor), findsNothing); + expect(container.read(clipboardInsertionRegistryProvider).target, isNull); + final readingText = container + .read(workspaceControllerProvider) + .activeText; + final readingReadCount = readCount; + clipboardText = ' must-not-insert'; + generation += 1; + await pressPaste(BusyMarkPasteMode.normal); + await pressPaste(BusyMarkPasteMode.plainText); + expect( + container.read(workspaceControllerProvider).activeText, + readingText, + ); + expect(readCount, readingReadCount); + }, + ); + testWidgets('app wires generated localization delegates and locales', ( tester, ) async { @@ -256,6 +550,144 @@ void main() { ); }); + for (final readErrors in [0, 1]) { + testWidgets( + 'recovery shows one actionable notice and preserves damage warnings ($readErrors)', + (tester) async { + final recoveryStore = MemoryDocumentRecoveryStore() + ..value = RecoverySnapshot( + cleanShutdown: false, + readErrors: readErrors, + entries: [ + DocumentRecoveryEntry.fromBuffer( + DocumentBuffer.untitled( + id: 'recovered-draft', + name: 'Recovered draft', + text: '# Recovered draft\n', + ), + workspacePath: null, + ), + ], + ); + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue( + _MemorySettingsStore(), + ), + localHistoryStoreProvider.overrideWithValue( + MemoryLocalHistoryStore(), + ), + documentSessionStoreProvider.overrideWithValue( + MemoryDocumentSessionStore(), + ), + documentRecoveryStoreProvider.overrideWithValue(recoveryStore), + startupPathProvider.overrideWithValue(null), + ], + ); + addTearDown(container.dispose); + await tester.runAsync(() async { + await container + .read(appSettingsControllerProvider.notifier) + .waitUntilLoaded(); + expect( + await container + .read(workspaceControllerProvider.notifier) + .restorePreviousSession(), + isTrue, + ); + }); + container.read(appRouterProvider).go('/workspace'); + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const BusyMarkApp(), + ), + ); + await tester.pumpAndSettle(); + + final buffer = container + .read(workspaceControllerProvider) + .activeBuffer!; + expect(buffer.recovered, isTrue); + expect(buffer.text, '# Recovered draft\n'); + expect(find.text(l10n.workspaceRecoveryRestored(1)), findsNothing); + final review = find.text( + l10n.recoveredDocumentReview(buffer.displayName), + ); + expect(review, findsOneWidget); + final actions = find + .ancestor(of: review, matching: find.byType(Row)) + .first; + for (final label in [l10n.save, l10n.saveAs, l10n.discard]) { + final button = find.ancestor( + of: find.descendant(of: actions, matching: find.text(label)), + matching: find.byWidgetPredicate( + (widget) => widget is ButtonStyleButton, + ), + ); + expect(button, findsOneWidget); + expect(tester.widget(button).onPressed, isNotNull); + } + expect( + find.text(l10n.workspaceRecoveryDamaged(1)), + readErrors > 0 ? findsOneWidget : findsNothing, + ); + }, + ); + } + + for (final closeTabFirst in [false, true]) { + testWidgets( + 'Welcome creates a fresh Markdown workspace after leaving basic.md (close tab: $closeTabFirst)', + (tester) async { + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue( + _MemorySettingsStore(), + ), + startupPathProvider.overrideWithValue(null), + ], + ); + addTearDown(container.dispose); + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const BusyMarkApp(), + ), + ); + await tester.pumpAndSettle(); + final controller = container.read(workspaceControllerProvider.notifier); + await tester.runAsync( + () => controller.openPath('test/fixtures/markdown/basic.md'), + ); + container.read(appRouterProvider).go('/workspace'); + await tester.pumpAndSettle(); + final oldId = container + .read(workspaceControllerProvider) + .activeBufferId!; + if (closeTabFirst) { + await tester.runAsync(() => controller.closeDocumentBuffer(oldId)); + await tester.pumpAndSettle(); + } + await tester.tap( + find.byTooltip('${l10n.welcome} (${BusyMarkAppShortcutLabels.back})'), + ); + await tester.pumpAndSettle(); + expect(find.text(l10n.createMarkdownFile), findsOneWidget); + await tester.tap(find.text(l10n.createMarkdownFile)); + await tester.pumpAndSettle(); + final state = container.read(workspaceControllerProvider); + expect(state.documentBuffers, hasLength(1)); + expect(state.activeBuffer!.filePath, isNull); + expect(state.activeBufferId, isNot(oldId)); + expect(state.workspace!.kind, WorkspaceKind.untitledMarkdown); + expect(state.workspace!.openFilePaths, isEmpty); + }, + ); + } + testWidgets('main menu and F11 toggle full-screen mode', (tester) async { final nativeWindow = _FakeNativeWindowController(); await tester.pumpWidget( @@ -589,6 +1021,65 @@ void main() { await tester.tap(find.text(l10n.editor)); await tester.pumpAndSettle(); + Finder groupedSection(String title) => find.byWidgetPredicate( + (widget) => widget is BusyMarkGroupedList && widget.title == title, + ); + void expectControlInSection(String sectionTitle, String controlTitle) { + expect( + find.descendant( + of: groupedSection(sectionTitle), + matching: find.text(controlTitle), + ), + findsOneWidget, + ); + } + + expect( + tester + .widgetList(find.byType(BusyMarkGroupedList)) + .map((section) => section.title), + [ + l10n.editor, + l10n.settingsEditingButtonsSectionTitle, + l10n.spelling, + l10n.settingsDictionariesSectionTitle, + ], + ); + expectControlInSection(l10n.editor, l10n.autoSave); + expectControlInSection(l10n.editor, l10n.editorFontSize); + expectControlInSection( + l10n.settingsEditingButtonsSectionTitle, + l10n.editingButtonsPosition, + ); + expectControlInSection( + l10n.settingsEditingButtonsSectionTitle, + l10n.editingButtonsDirection, + ); + expectControlInSection(l10n.spelling, l10n.automaticSpelling); + expectControlInSection(l10n.spelling, l10n.defaultSpellingLanguage); + expectControlInSection(l10n.spelling, l10n.projectSpellingLanguage); + expectControlInSection( + l10n.settingsDictionariesSectionTitle, + l10n.spellingDictionaries, + ); + expectControlInSection( + l10n.settingsDictionariesSectionTitle, + l10n.personalSpellingDictionary, + ); + expectControlInSection( + l10n.settingsDictionariesSectionTitle, + l10n.projectSpellingDictionary, + ); + final dictionariesSection = tester.widget( + groupedSection(l10n.settingsDictionariesSectionTitle), + ); + expect(dictionariesSection.children, hasLength(3)); + expect(find.text(l10n.importSpellingDictionary), findsNothing); + expect( + tester.widget(find.byType(BusyMarkClamp)).scrollable, + isTrue, + ); + expect( find.byWidgetPredicate((widget) => widget is SegmentedButton), findsNothing, @@ -617,10 +1108,39 @@ void main() { expect(find.text(l10n.autoSave), findsOneWidget); expect(find.text(l10n.autoSaveDescription), findsOneWidget); + expect(find.text(l10n.wordWrapDescription), findsOneWidget); + final autoSaveRow = find.byWidgetPredicate( + (widget) => widget is BusyMarkSwitchRow && widget.title == l10n.autoSave, + ); + expect(autoSaveRow, findsOneWidget); + expect( + tester.widget(autoSaveRow).value, + AppSettings.defaults().autoSave, + ); + + await tester.tap( + find.descendant(of: autoSaveRow, matching: find.byType(BusyMarkSwitch)), + ); + await tester.pumpAndSettle(); + expect(settingsStore.value['autoSave'], isFalse); + expect(tester.widget(autoSaveRow).value, isFalse); + await tester.tap(find.text(l10n.autoSave)); await tester.pumpAndSettle(); + expect(settingsStore.value['autoSave'], isTrue); + expect(tester.widget(autoSaveRow).value, isTrue); - expect(settingsStore.value['autoSave'], isFalse); + final header = tester.widget( + find.byType(HeaderBarConfigurationPublisher), + ); + expect(header.configuration.title, l10n.editor); + expect(header.configuration.sidebarVisible, isFalse); + expect( + find.byKey(const ValueKey('settings-page-selector')), + findsOneWidget, + ); + expect(find.byType(BusyMarkGroupedList), findsNWidgets(4)); + expect(find.text(l10n.autoSave), findsOneWidget); await tester.tap(find.byKey(const ValueKey('settings-page-selector'))); await tester.pumpAndSettle(); @@ -631,52 +1151,182 @@ void main() { await tester.tap(find.byKey(const ValueKey('settings-page-selector'))); await tester.pumpAndSettle(); - await tester.tap(find.text(l10n.settingsWindowSectionTitle)); + await tester.tap(find.text(l10n.settingsHistory)); await tester.pumpAndSettle(); + final historySection = find.byWidgetPredicate( + (widget) => + widget is BusyMarkGroupedList && widget.title == l10n.settingsHistory, + ); + expect(historySection, findsOneWidget); expect( - find.text(l10n.settingsReopenWorkspaceOnStartupTitle), - findsOneWidget, + find.descendant( + of: historySection, + matching: find.byType(BusyMarkComboRow), + ), + findsNWidgets(3), ); expect( - find.text(l10n.settingsReopenWorkspaceOnStartupDescription), - findsOneWidget, + find.descendant( + of: historySection, + matching: find.byType(DropdownButton), + ), + findsNothing, ); - await tester.tap(find.text(l10n.settingsReopenWorkspaceOnStartupTitle)); - await tester.pumpAndSettle(); - - expect(settingsStore.value['reopenPreviousWorkspaceOnStartup'], isTrue); + BusyMarkComboRow historyRow(String title) => + tester.widget>( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkComboRow && widget.title == title, + ), + ); + expect(historyRow(l10n.settingsHistoryCheckpoint).values, [ + 30, + 60, + 120, + 300, + 600, + ]); + expect(historyRow(l10n.settingsHistoryCheckpoint).selected, 60); expect( - find.text(l10n.settingsConfirmCloseWithUnsavedChangesTitle), - findsOneWidget, + historyRow(l10n.settingsHistoryCheckpoint).labelFor(60), + l10n.settingsSecondsValue(60), ); + expect(historyRow(l10n.settingsHistoryRetention).values, [7, 30, 90, 365]); + expect(historyRow(l10n.settingsHistoryRetention).selected, 30); expect( - find.text(l10n.settingsConfirmCloseWithUnsavedChangesDescription), - findsOneWidget, + historyRow(l10n.settingsHistoryRetention).labelFor(30), + l10n.settingsDaysValue(30), ); - await tester.tap( - find.text(l10n.settingsConfirmCloseWithUnsavedChangesTitle), + expect(historyRow(l10n.settingsHistoryStorage).values, [ + 128, + 256, + 512, + 1024, + 2048, + 4096, + ]); + expect(historyRow(l10n.settingsHistoryStorage).selected, 512); + expect( + historyRow(l10n.settingsHistoryStorage).labelFor(512), + l10n.settingsMebibytesValue(512), ); + + await tester.tap(find.byTooltip(l10n.settingsHistoryCheckpoint)); + await tester.pumpAndSettle(); + for (final choice in [30, 60, 120, 300, 600]) { + expect(find.text(l10n.settingsSecondsValue(choice)), findsWidgets); + } + expect(find.byType(Radio), findsNothing); + expect(find.byType(RadioListTile), findsNothing); + await tester.tap(find.text(l10n.settingsSecondsValue(120)).last); await tester.pumpAndSettle(); + expect(settingsStore.value['localHistoryCheckpointSeconds'], 120); + expect(historyRow(l10n.settingsHistoryCheckpoint).selected, 120); - expect(settingsStore.value['confirmCloseWithUnsavedChanges'], isFalse); - }); + historyRow(l10n.settingsHistoryRetention).onSelected(90); + await tester.pumpAndSettle(); + expect(settingsStore.value['localHistoryRetentionDays'], 90); + expect(historyRow(l10n.settingsHistoryRetention).selected, 90); - testWidgets('settings uses the regular split sidebar at desktop width', ( - tester, - ) async { - tester.view.devicePixelRatio = 1; - tester.view.physicalSize = const Size(1200, 760); - addTearDown(tester.view.resetDevicePixelRatio); - addTearDown(tester.view.resetPhysicalSize); + historyRow(l10n.settingsHistoryStorage).onSelected(1024); + await tester.pumpAndSettle(); + expect(settingsStore.value['localHistoryMaximumStorageMiB'], 1024); + expect(historyRow(l10n.settingsHistoryStorage).selected, 1024); - await tester.pumpWidget( - ProviderScope( - overrides: [ - linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), - ], - child: const BusyMarkApp(), + await tester.tap(find.text(l10n.settingsLocalHistoryTitle)); + await tester.pumpAndSettle(); + expect(settingsStore.value['localHistoryRecordingEnabled'], isFalse); + expect( + tester + .widgetList>( + find.descendant( + of: historySection, + matching: find.byType(BusyMarkComboRow), + ), + ) + .every((row) => !row.enabled), + isTrue, + ); + + final clearRecentRow = tester.widget( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkActionRow && + widget.title == l10n.clearRecentWorkspaces, + ), + ); + expect(clearRecentRow.destructive, isTrue); + expect(clearRecentRow.onTap, isNotNull); + final clearRecentTitle = find.text(l10n.clearRecentWorkspaces); + final clearRecentContext = tester.element(clearRecentTitle); + expect( + tester.widget(clearRecentTitle).style?.color, + busyMarkDestructiveForeground(clearRecentContext), + ); + expect(Theme.of(clearRecentContext).brightness, Brightness.dark); + expect( + busyMarkDestructiveForeground(clearRecentContext), + isNot(Theme.of(clearRecentContext).colorScheme.error), + ); + + expect( + find.text(l10n.settingsReopenWorkspaceOnStartupTitle), + findsOneWidget, + ); + expect( + find.text(l10n.settingsReopenWorkspaceOnStartupDescription), + findsOneWidget, + ); + await tester.ensureVisible( + find.text(l10n.settingsReopenWorkspaceOnStartupTitle), + ); + await tester.tap(find.text(l10n.settingsReopenWorkspaceOnStartupTitle)); + await tester.pumpAndSettle(); + + expect(settingsStore.value['reopenPreviousWorkspaceOnStartup'], isTrue); + + expect( + find.text(l10n.settingsConfirmCloseWithUnsavedChangesTitle), + findsOneWidget, + ); + expect( + find.text(l10n.settingsConfirmCloseWithUnsavedChangesDescription), + findsOneWidget, + ); + await tester.ensureVisible( + find.text(l10n.settingsConfirmCloseWithUnsavedChangesTitle), + ); + await tester.tap( + find.text(l10n.settingsConfirmCloseWithUnsavedChangesTitle), + ); + await tester.pumpAndSettle(); + + expect(settingsStore.value['confirmCloseWithUnsavedChanges'], isFalse); + + await tester.tap( + find.byTooltip('${l10n.back} (${BusyMarkAppShortcutLabels.back})'), + ); + await tester.pumpAndSettle(); + + expect(find.text(l10n.createMarkdownFile), findsOneWidget); + }); + + testWidgets('settings uses the regular split sidebar at desktop width', ( + tester, + ) async { + tester.view.devicePixelRatio = 1; + tester.view.physicalSize = const Size(1200, 760); + addTearDown(tester.view.resetDevicePixelRatio); + addTearDown(tester.view.resetPhysicalSize); + + await tester.pumpWidget( + ProviderScope( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + ], + child: const BusyMarkApp(), ), ); await tester.pumpAndSettle(); @@ -690,7 +1340,7 @@ void main() { expect(find.byType(BusyMarkSidebarNavigation), findsOneWidget); expect( find.byType(BusyMarkSidebarNavigationTile), - findsNWidgets(SettingsPage.values.length), + findsNWidgets(SettingsPage.values.length - 1), ); expect( tester.getSize(find.byType(BusyMarkSidebarSurface)).width, @@ -725,14 +1375,647 @@ void main() { .selected, isTrue, ); + expect( + tester + .widgetList(find.byType(BusyMarkGroupedList)) + .map((section) => section.title), + [ + l10n.editor, + l10n.settingsEditingButtonsSectionTitle, + l10n.spelling, + l10n.settingsDictionariesSectionTitle, + ], + ); expect(find.text(l10n.autoSave), findsOneWidget); header = tester.widget( find.byType(HeaderBarConfigurationPublisher), ); expect(header.configuration.sidebarVisible, isTrue); expect(header.configuration.title, l10n.editor); + + expect(find.text(l10n.spellingDictionaries), findsOneWidget); + expect(find.byType(BusyMarkSidebarSurface), findsOneWidget); + expect(find.byKey(const ValueKey('settings-page-selector')), findsNothing); + expect(find.byType(Scrollable), findsWidgets); + expect( + tester.widget(find.byType(BusyMarkClamp)).scrollable, + isTrue, + ); + header = tester.widget( + find.byType(HeaderBarConfigurationPublisher), + ); + expect(header.configuration.sidebarVisible, isTrue); + expect(header.configuration.title, l10n.editor); + expect( + tester + .widget( + find.byKey(const ValueKey('settings-navigation-editor')), + ) + .selected, + isTrue, + ); + header = tester.widget( + find.byType(HeaderBarConfigurationPublisher), + ); + expect(header.configuration.sidebarVisible, isTrue); + expect(header.configuration.title, l10n.editor); + + final dictionariesNavigation = find.byKey( + const ValueKey('settings-spelling-dictionaries'), + ); + await tester.ensureVisible(dictionariesNavigation); + await tester.tap(dictionariesNavigation); + await tester.pumpAndSettle(); + + expect(find.byType(BusyMarkSidebarSurface), findsOneWidget); + expect(find.byKey(const ValueKey('settings-page-selector')), findsNothing); + expect( + tester + .widget( + find.byKey(const ValueKey('settings-navigation-editor')), + ) + .selected, + isTrue, + ); + header = tester.widget( + find.byType(HeaderBarConfigurationPublisher), + ); + expect(header.configuration.title, l10n.spellingDictionaries); + expect(find.text(l10n.importSpellingDictionary), findsOneWidget); + expect(find.text(l10n.spellingDictionaryProblems), findsNothing); + + await tester.tap( + find.byTooltip('${l10n.back} (${BusyMarkAppShortcutLabels.back})'), + ); + await tester.pumpAndSettle(); + header = tester.widget( + find.byType(HeaderBarConfigurationPublisher), + ); + expect(header.configuration.title, l10n.editor); + expect(find.text(l10n.autoSave), findsOneWidget); + }); + + testWidgets( + 'Spelling Dictionaries page groups downloadable and custom data', + (tester) async { + tester.view.devicePixelRatio = 1; + tester.view.physicalSize = const Size(800, 900); + addTearDown(tester.view.resetDevicePixelRatio); + addTearDown(tester.view.resetPhysicalSize); + + late Directory temporary; + late ({String bundle, String storage}) fixture; + late SpellingSessionController spelling; + await tester.runAsync(() async { + temporary = await Directory.systemTemp.createTemp( + 'busymark-settings-dictionaries-', + ); + fixture = await _createSettingsSpellingFixture(temporary); + spelling = SpellingSessionController( + bundledRoot: fixture.bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: fixture.storage, + verifyDictionaryChecksums: false, + ); + await spelling.prepareSettings(null); + }); + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue(_MemorySettingsStore()), + spellingSessionControllerProvider.overrideWith((ref) => spelling), + ], + ); + addTearDown(() async { + container.dispose(); + if (await temporary.exists()) { + await temporary.delete(recursive: true); + } + }); + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const BusyMarkApp(), + ), + ); + await tester.pumpAndSettle(); + + await tester.tap(find.byTooltip(l10n.mainMenu)); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.settings)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const ValueKey('settings-page-selector'))); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.editor)); + await tester.pumpAndSettle(); + await tester.tap( + find.byKey(const ValueKey('settings-spelling-dictionaries')), + ); + await tester.pumpAndSettle(); + + final availableGroup = find.byWidgetPredicate( + (widget) => + widget is BusyMarkGroupedList && + widget.title == l10n.availableSpellingDictionaries, + ); + final customGroup = find.byWidgetPredicate( + (widget) => + widget is BusyMarkGroupedList && + widget.title == l10n.customSpellingDictionaries, + ); + final problemsGroup = find.byWidgetPredicate( + (widget) => + widget is BusyMarkGroupedList && + widget.title == l10n.spellingDictionaryProblems, + ); + expect(availableGroup, findsOneWidget); + expect(customGroup, findsOneWidget); + expect(problemsGroup, findsOneWidget); + expect( + find.byKey(const ValueKey('settings-page-selector')), + findsOneWidget, + ); + expect( + find.descendant( + of: find.byKey(const ValueKey('settings-page-selector')), + matching: find.text(l10n.editor), + ), + findsOneWidget, + ); + expect( + container + .read(appRouterProvider) + .routerDelegate + .currentConfiguration + .uri + .queryParameters['page'], + 'spellingDictionaries', + ); + expect(find.byType(Scrollable), findsOneWidget); + expect( + tester.widget(find.byType(BusyMarkClamp)).scrollable, + isTrue, + ); + expect(find.text(l10n.importSpellingDictionary), findsOneWidget); + expect(find.text('Test English'), findsOneWidget); + expect(find.text('Test French'), findsOneWidget); + expect(find.text(l10n.spellingDictionaryInstalled), findsOneWidget); + expect(find.textContaining('Not installed ·'), findsAtLeastNWidgets(1)); + expect(find.text('Local Test English'), findsOneWidget); + expect(find.text('xx-Test'), findsOneWidget); + expect( + tester.getTopLeft(find.text('Test English')).dy, + lessThan(tester.getTopLeft(find.text('Test French')).dy), + ); + expect( + tester.getTopLeft(find.text('Test French')).dy, + lessThan( + tester.getTopLeft(find.text(l10n.importSpellingDictionary)).dy, + ), + ); + expect( + tester.getTopLeft(find.text(l10n.importSpellingDictionary)).dy, + lessThan(tester.getTopLeft(find.text('Local Test English')).dy), + ); + expect( + tester.getTopLeft(find.text('Local Test English')).dy, + lessThan(tester.getTopLeft(find.text('xx-Test')).dy), + ); + for (final resourceTitle in ['Test English', 'Test French']) { + final row = find.byWidgetPredicate( + (widget) => + widget is BusyMarkActionRow && widget.title == resourceTitle, + ); + expect( + find.descendant( + of: row, + matching: find.byType(BusyMarkCompactIconButton), + ), + findsOneWidget, + ); + final actionRow = tester.widget(row); + expect(actionRow.onTap, isNull); + expect(actionRow.destructive, isFalse); + } + + final importRow = tester.widget( + find.byKey(const ValueKey('import-spelling-dictionary')), + ); + expect(importRow.onTap, isNotNull); + final importedRow = tester.widget( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkActionRow && + widget.title == 'Local Test English', + ), + ); + expect(importedRow.destructive, isFalse); + expect(importedRow.onTap, isNull); + final importedRemove = importedRow.trailing! as BusyMarkCompactIconButton; + expect(importedRemove.onPressed, isNotNull); + expect( + importedRemove.foregroundColor, + Theme.of(tester.element(customGroup)).colorScheme.error, + ); + final invalidRow = tester.widget( + find.byWidgetPredicate( + (widget) => widget is BusyMarkActionRow && widget.title == 'xx-Test', + ), + ); + expect(invalidRow.destructive, isFalse); + expect(invalidRow.onTap, isNull); + final invalidRemove = invalidRow.trailing! as BusyMarkCompactIconButton; + expect(invalidRemove.onPressed, isNotNull); + expect( + invalidRemove.foregroundColor, + Theme.of(tester.element(problemsGroup)).colorScheme.error, + ); + + await tester.ensureVisible(find.text('Local Test English')); + await tester.tap(find.text('Local Test English')); + await tester.pumpAndSettle(); + expect( + spelling.catalog?.installations.any( + (entry) => entry.id == 'local-Test' && entry.imported, + ), + isTrue, + ); + }, + ); + + testWidgets( + 'import dictionary prompt uses native controls and submits a trimmed ID', + (tester) async { + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: _MemorySettingsStore(), + downloadFile: _copySettingsDictionaryDownload, + ); + addTearDown(harness.dispose); + const fileSelectorChannel = MethodChannel( + 'plugins.flutter.io/file_selector', + ); + final dictionaryFixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + fileSelectorChannel, + (call) async { + expect(call.method, 'openFile'); + expect((call.arguments as Map)['multiple'], isTrue); + return [ + p.join(dictionaryFixture, 'test.aff'), + p.join(dictionaryFixture, 'test.dic'), + ]; + }, + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + fileSelectorChannel, + null, + ), + ); + + await _openImportDictionaryPrompt(tester); + + final dialog = find.byType(BusyMarkDialogShell); + expect(dialog, findsOneWidget); + final shell = tester.widget(dialog); + expect(shell.title, l10n.importSpellingDictionary); + expect(shell.closable, isFalse); + final entryFinder = find.descendant( + of: dialog, + matching: find.byType(BusyMarkFloatingTextEntry), + ); + expect(entryFinder, findsOneWidget); + final entry = tester.widget(entryFinder); + expect(entry.label, l10n.language); + expect(entry.hintText, 'en-US'); + expect(entry.autofocus, isTrue); + expect(entry.textInputAction, TextInputAction.done); + expect(entry.minLines, 1); + expect(entry.maxLines, 1); + final actions = tester + .widgetList( + find.descendant( + of: dialog, + matching: find.byType(BusyMarkDialogButton), + ), + ) + .toList(growable: false); + expect(actions, hasLength(2)); + expect(actions.map((action) => action.label), [l10n.cancel, l10n.save]); + expect(actions.first.suggested, isFalse); + expect(actions.last.suggested, isTrue); + expect(find.byType(AlertDialog), findsNothing); + + await tester.enterText(find.byType(TextFormField), ' '); + await tester.testTextInput.receiveAction(TextInputAction.done); + await _pumpSettingsUi(tester); + expect(dialog, findsOneWidget); + + await tester.enterText(find.byType(TextFormField), ' en-GB '); + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pump(kThemeAnimationDuration); + await _pumpUntilCondition( + tester, + () => harness.spelling.catalog?.installedById('en-GB') != null, + ); + + expect(dialog, findsNothing); + expect(harness.spelling.catalog?.installedById('en-GB'), isNotNull); + }, + ); + + testWidgets('import dictionary prompt cancels and saves without redesign', ( + tester, + ) async { + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: _MemorySettingsStore(), + downloadFile: _copySettingsDictionaryDownload, + ); + addTearDown(harness.dispose); + const fileSelectorChannel = MethodChannel( + 'plugins.flutter.io/file_selector', + ); + final dictionaryFixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + fileSelectorChannel, + (call) async => [ + p.join(dictionaryFixture, 'test.aff'), + p.join(dictionaryFixture, 'test.dic'), + ], + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + fileSelectorChannel, + null, + ), + ); + + await _openImportDictionaryPrompt(tester); + await tester.tap( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkDialogButton && widget.label == l10n.cancel, + ), + ); + await _pumpSettingsUi(tester); + + expect(find.byType(BusyMarkDialogShell), findsNothing); + expect(harness.spelling.catalog?.installedById('en-GB'), isNull); + + await tester.tap(find.byKey(const ValueKey('import-spelling-dictionary'))); + await _pumpUntilFound(tester, find.byType(BusyMarkDialogShell)); + await tester.enterText(find.byType(TextFormField), ' en-GB '); + await tester.tap( + find.byWidgetPredicate( + (widget) => widget is BusyMarkDialogButton && widget.label == l10n.save, + ), + ); + await tester.pump(kThemeAnimationDuration); + await _pumpUntilCondition( + tester, + () => harness.spelling.catalog?.installedById('en-GB') != null, + ); + + expect(find.byType(BusyMarkDialogShell), findsNothing); + expect(harness.spelling.catalog?.installedById('en-GB'), isNotNull); + }); + + testWidgets( + 'cancelling a default-language install keeps the previous selection', + (tester) async { + var downloadCount = 0; + final settingsStore = _MemorySettingsStore() + ..value = AppSettings.defaults() + .copyWith(defaultSpellingLanguage: 'en-Test') + .toJson(); + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: settingsStore, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + await _copySettingsDictionaryDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ); + addTearDown(harness.dispose); + + await _selectSpellingLanguage( + tester, + selectorTooltip: l10n.defaultSpellingLanguage, + languageLabel: 'Test French', + ); + + expect(find.text(l10n.spellingDictionaryNotInstalled), findsOneWidget); + expect(find.byType(BusyMarkDialogShell), findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + expect(settingsStore.value['defaultSpellingLanguage'], 'en-Test'); + await tester.tap(find.text(l10n.cancel)); + await _pumpSettingsUi(tester); + + expect(settingsStore.value['defaultSpellingLanguage'], 'en-Test'); + expect( + _spellingLanguageSelector(tester, l10n.defaultSpellingLanguage).label, + 'Test English', + ); + expect(downloadCount, 0); + }, + ); + + testWidgets( + 'default language persists only after dictionary installation succeeds', + (tester) async { + var downloadCount = 0; + final allowDownload = Completer(); + final settingsStore = _MemorySettingsStore() + ..value = AppSettings.defaults() + .copyWith(defaultSpellingLanguage: 'en-Test') + .toJson(); + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: settingsStore, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + await allowDownload.future; + await _copySettingsDictionaryDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ); + addTearDown(harness.dispose); + + await _selectSpellingLanguage( + tester, + selectorTooltip: l10n.defaultSpellingLanguage, + languageLabel: 'Test French', + ); + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _pumpUntilCondition(tester, () => downloadCount > 0); + + expect(settingsStore.value['defaultSpellingLanguage'], 'en-Test'); + expect( + _spellingLanguageSelector(tester, l10n.defaultSpellingLanguage).label, + 'Test English', + ); + + allowDownload.complete(); + await _pumpUntilCondition( + tester, + () => settingsStore.value['defaultSpellingLanguage'] == 'fr-Test', + ); + + expect(harness.spelling.catalog?.installedById('fr-Test'), isNotNull); + expect(settingsStore.value['defaultSpellingLanguage'], 'fr-Test'); + expect( + _spellingLanguageSelector(tester, l10n.defaultSpellingLanguage).label, + 'Test French', + ); + expect(downloadCount, 2); + }, + ); + + testWidgets('failed dictionary install keeps the default language', ( + tester, + ) async { + var downloadCount = 0; + final settingsStore = _MemorySettingsStore() + ..value = AppSettings.defaults() + .copyWith(defaultSpellingLanguage: 'en-Test') + .toJson(); + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: settingsStore, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + throw const SocketException('test dictionary download failure'); + }, + ); + addTearDown(harness.dispose); + + await _selectSpellingLanguage( + tester, + selectorTooltip: l10n.defaultSpellingLanguage, + languageLabel: 'Test French', + ); + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _pumpUntilCondition( + tester, + () => + harness.spelling.dictionaryInstallStatus?.phase == + SpellingDictionaryInstallPhase.failed, + ); + + expect(downloadCount, 1); + expect(settingsStore.value['defaultSpellingLanguage'], 'en-Test'); + expect( + _spellingLanguageSelector(tester, l10n.defaultSpellingLanguage).label, + 'Test English', + ); + expect(find.text(l10n.commandUnavailableInContext), findsOneWidget); }); + testWidgets( + 'cancelling a project-language install keeps the previous selection', + (tester) async { + var downloadCount = 0; + final harness = await _pumpSettingsSpellingHarness( + tester, + headerBarService: headerBarService, + settingsStore: _MemorySettingsStore(), + projectLanguage: 'en-Test', + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + await _copySettingsDictionaryDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ); + addTearDown(harness.dispose); + + await _selectSpellingLanguage( + tester, + selectorTooltip: l10n.projectSpellingLanguage, + languageLabel: 'Test French', + ); + + expect(find.text(l10n.spellingDictionaryNotInstalled), findsOneWidget); + expect(harness.spelling.projectWords.projectLanguage, 'en-Test'); + await tester.tap(find.text(l10n.cancel)); + await _pumpSettingsUi(tester); + + expect(harness.spelling.projectWords.projectLanguage, 'en-Test'); + expect( + _spellingLanguageSelector(tester, l10n.projectSpellingLanguage).label, + 'Test English', + ); + expect(downloadCount, 0); + final persistedSource = await tester.runAsync( + () => File(harness.projectSpellingPath!).readAsString(), + ); + final persisted = jsonDecode(persistedSource!); + expect((persisted as Map)['projectLanguage'], 'en-Test'); + }, + ); + testWidgets('settings main surface matches the headerbar in light and dark', ( tester, ) async { @@ -1137,6 +2420,7 @@ void main() { ...BusyMarkTreeShortcuts.definitions.values.map( (definition) => definition.label, ), + 'F7', 'Ctrl+Shift+Home', 'Ctrl+Shift+End', }; @@ -1703,10 +2987,15 @@ void main() { tester, ) async { final service = _StartupWorkspaceService(); + final settingsStore = _MemorySettingsStore() + ..value = AppSettings.defaults() + .copyWith(defaultSpellingLanguage: null) + .toJson(); await tester.pumpWidget( ProviderScope( overrides: [ linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue(settingsStore), workspaceServiceProvider.overrideWithValue(service), ], child: const BusyMarkApp(), @@ -1754,6 +3043,17 @@ void main() { expect(service.untitledCount, 1); expect(find.text(l10n.createMarkdownFile), findsNothing); expect(find.text(l10n.workspaceKindUnsavedMarkdown), findsWidgets); + expect(find.byKey(const ValueKey('editor-tab-strip')), findsNothing); + expect(find.byKey(const ValueKey('document-status-bar')), findsOneWidget); + expect(find.text('LF'), findsOneWidget); + expect( + find.byKey(const ValueKey('document-spelling-language-status')), + findsOneWidget, + ); + expect(find.text(l10n.spellingLanguageUnsetStatus), findsOneWidget); + final spellingBanner = find.byKey(const ValueKey('spelling-banner')); + expect(spellingBanner, findsOneWidget); + expect(tester.widget(spellingBanner).revealed, isFalse); }); testWidgets('Ctrl+N keeps unsaved documents in independent tabs', ( @@ -1859,6 +3159,192 @@ void main() { await tester.pump(const Duration(milliseconds: 800)); }); + testWidgets('Ctrl+N creates real CommonMark inside a Writerside workspace', ( + tester, + ) async { + const yaruWindowChannel = MethodChannel('yaru_window'); + const yaruWindowEventsChannel = MethodChannel('yaru_window/events'); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(yaruWindowChannel, (call) async { + if (call.method == 'state') return {}; + return null; + }); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(yaruWindowEventsChannel, (_) async => null); + addTearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + ..setMockMethodCallHandler(yaruWindowChannel, null) + ..setMockMethodCallHandler(yaruWindowEventsChannel, null); + }); + final binding = TestWidgetsFlutterBinding.ensureInitialized(); + binding.platformDispatcher.defaultRouteNameTestValue = '/workspace'; + addTearDown(() { + binding.platformDispatcher.defaultRouteNameTestValue = '/'; + }); + final root = Directory('test/fixtures/writerside/basic_project').absolute; + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue( + _MemorySettingsStore() + ..value = AppSettings.defaults().copyWith(autoSave: false).toJson(), + ), + startupPathProvider.overrideWithValue(null), + ], + ); + addTearDown(container.dispose); + + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: const BusyMarkApp(), + ), + ); + await tester.runAsync( + () => container + .read(workspaceControllerProvider.notifier) + .openPath(root.path), + ); + for (var index = 0; index < 30; index += 1) { + await tester.pump(const Duration(milliseconds: 100)); + if (container.read(workspaceControllerProvider).workspace?.kind == + WorkspaceKind.writersideModule) { + break; + } + } + final before = container.read(workspaceControllerProvider); + expect(before.workspace?.kind, WorkspaceKind.writersideModule); + final topicId = before.activeBuffer!.id; + + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyDownEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + await tester.tap( + find.descendant( + of: find.byType(BusyMarkDialogShell), + matching: find.text(l10n.createMarkdownFile), + ), + ); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + final controller = container.read(workspaceControllerProvider.notifier); + const source = '''# Widget draft + +Paragraph with *emphasis*. + +- item + +```text +code + ``` +'''; + controller.updateActiveText(source); + await tester.runAsync(() => controller.validateActive()); + for (var index = 0; index < 30; index += 1) { + await tester.pump(const Duration(milliseconds: 100)); + if (container + .read(workspaceControllerProvider) + .preview + ?.blocks + .any((block) => block.text == 'Widget draft') ?? + false) { + break; + } + } + + var state = container.read(workspaceControllerProvider); + final untitledId = state.activeBuffer!.id; + final resolved = resolveWorkspaceDocumentContext( + state.workspace!, + state.activeBuffer!, + ); + expect(state.workspace?.kind, WorkspaceKind.writersideModule); + expect(state.workspace?.activeFilePath, isNull); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect( + state.preview?.blocks.map((block) => block.kind), + containsAll([ + PreviewBlockKind.heading, + PreviewBlockKind.paragraph, + PreviewBlockKind.list, + PreviewBlockKind.code, + ]), + ); + + controller.updateActiveEditorMode(DocumentViewModePreference.source); + await tester.pump(const Duration(milliseconds: 500)); + final sourceEditor = tester.widget( + find.byType(BusyMarkSourceEditor), + ); + expect(sourceEditor.documentId, untitledId); + expect(sourceEditor.language.name, 'markdown'); + expect(sourceEditor.documentFormat?.name, 'markdown'); + expect(sourceEditor.markdownMode, MarkdownMode.commonMark); + + controller.updateActiveEditorMode(DocumentViewModePreference.editor); + await tester.pump(const Duration(milliseconds: 500)); + expect(find.byKey(const ValueKey('document-wysiwyg-pane')), findsOneWidget); + expect(find.byKey(const ValueKey('document-source-pane')), findsNothing); + + expect( + await tester.runAsync(() => controller.activateDocumentBuffer(topicId)), + isTrue, + ); + expect( + await tester.runAsync( + () => controller.activateDocumentBuffer(untitledId), + ), + isTrue, + ); + await tester.pump(const Duration(milliseconds: 500)); + state = container.read(workspaceControllerProvider); + expect(state.activeBuffer?.id, untitledId); + expect( + resolveWorkspaceDocumentContext( + state.workspace!, + state.activeBuffer!, + ).markdownMode, + MarkdownMode.commonMark, + ); + expect(find.byKey(const ValueKey('document-wysiwyg-pane')), findsOneWidget); + expect( + state.preview?.blocks.any((block) => block.text == 'Widget draft'), + isTrue, + ); + + controller.updateActiveEditorMode(DocumentViewModePreference.source); + await tester.pump(const Duration(milliseconds: 300)); + final staleSourceCallback = tester + .widget(find.byType(BusyMarkSourceEditor)) + .onChanged; + controller.updateActiveEditorMode(DocumentViewModePreference.editor); + await tester.pump(const Duration(milliseconds: 300)); + final firstWysiwyg = tester.widget( + find.byType(BusyMarkWysiwygEditor), + ); + + await tester.runAsync(controller.createMarkdownFile); + controller.updateActiveText(source); + await tester.runAsync(() => controller.validateActive()); + await tester.pump(const Duration(milliseconds: 500)); + final secondState = container.read(workspaceControllerProvider); + final secondWysiwyg = tester.widget( + find.byType(BusyMarkWysiwygEditor), + ); + expect(secondState.activeBuffer?.id, isNot(untitledId)); + expect(secondWysiwyg.documentId, secondState.activeBuffer?.id); + expect(firstWysiwyg.documentId, untitledId); + expect(identical(firstWysiwyg.document, secondWysiwyg.document), isFalse); + + staleSourceCallback('# stale callback\n', ''); + expect(container.read(workspaceControllerProvider).activeText, source); + }); + testWidgets( 'Table of Contents creates from selection and exposes nested Writerside actions', (tester) async { @@ -3262,12 +4748,12 @@ void main() { temp.deleteSync(recursive: true); }); final first = File('${temp.path}/a.md')..writeAsStringSync('# A\n'); - final second = File('${temp.path}/b.md')..writeAsStringSync('# B\n'); + final second = File('${temp.path}/b.md')..writeAsStringSync('# B\r\n'); final third = File('${temp.path}/c.md')..writeAsStringSync('# C\n'); final service = _TabbedWorkspaceService( rootPath: temp.path, paths: [first.path, second.path, third.path], - ); + ).._sources[second.path] = '# B\r\n'; final container = ProviderContainer( overrides: [ linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), @@ -3332,6 +4818,18 @@ void main() { expect(find.text('LF'), findsOneWidget); expect(find.text('CRLF'), findsNothing); + final tabStrip = find.byKey(const ValueKey('editor-tab-strip')); + final statusBar = find.byKey(const ValueKey('document-status-bar')); + expect(tabStrip, findsOneWidget); + expect(statusBar, findsOneWidget); + expect( + find.descendant(of: statusBar, matching: find.text('LF')), + findsOneWidget, + ); + expect( + find.descendant(of: tabStrip, matching: find.text('LF')), + findsNothing, + ); expect( find.ancestor(of: find.text('LF'), matching: find.byType(InkWell)), findsNothing, @@ -3380,6 +4878,16 @@ void main() { container.read(workspaceControllerProvider).workspace?.openFilePaths, [first.path, second.path], ); + expect(find.text('LF'), findsNothing); + expect(find.text('CRLF'), findsOneWidget); + expect( + find.descendant(of: statusBar, matching: find.text('CRLF')), + findsOneWidget, + ); + expect( + find.descendant(of: tabStrip, matching: find.text('CRLF')), + findsNothing, + ); await pressControlShortcut(LogicalKeyboardKey.keyW, shift: true); expect( @@ -3487,6 +4995,7 @@ void main() { find.textContaining('Guide change', findRichText: true), findsWidgets, ); + expect(find.byKey(const ValueKey('document-status-bar')), findsNothing); await pressControlShortcut(LogicalKeyboardKey.tab); expect( @@ -3501,6 +5010,7 @@ void main() { find.textContaining('Guide change', findRichText: true), findsNothing, ); + expect(find.byKey(const ValueKey('document-status-bar')), findsOneWidget); await pressControlShortcut(LogicalKeyboardKey.tab); expect( @@ -3511,6 +5021,7 @@ void main() { find.textContaining('Readme change', findRichText: true), findsWidgets, ); + expect(find.byKey(const ValueKey('document-status-bar')), findsNothing); await pressControlShortcut(LogicalKeyboardKey.tab, shift: true); expect( @@ -4734,10 +6245,20 @@ void main() { final workspace = (await tester.runAsync( () => const WorkspaceService().openPath(root.path), ))!; + final source = workspace.markdown?.source ?? ''; + final activePath = workspace.activeFilePath!; + final activeBuffer = DocumentBuffer( + id: 'writerside-sidebar-active', + filePath: activePath, + text: source, + lastSavedText: source, + dirty: false, + ); final controller = _MutableWorkspaceController( WorkspaceState( workspace: workspace, - activeText: workspace.markdown?.source ?? '', + documentBuffers: [activeBuffer], + activeBufferId: activeBuffer.id, ), ); final container = ProviderContainer( @@ -4781,6 +6302,7 @@ void main() { Future setDocumentViewMode( DocumentViewModePreference expectedMode, ) async { + controller.updateActiveEditorMode(expectedMode); await container .read(appSettingsControllerProvider.notifier) .setDocumentViewMode(expectedMode); @@ -5253,8 +6775,18 @@ void main() { final workspace = const WorkspaceService() .createUntitledMarkdown(source: '# عنوان\n') .copyWith(diagnostics: const [diagnostic]); + final activeBuffer = DocumentBuffer.untitled( + id: 'arabic-untitled-active', + name: ar.untitledMarkdownFileName, + text: '# عنوان\n', + mode: DocumentViewModePreference.source, + ); final controller = _MutableWorkspaceController( - WorkspaceState(workspace: workspace, activeText: '# عنوان\n'), + WorkspaceState( + workspace: workspace, + documentBuffers: [activeBuffer], + activeBufferId: activeBuffer.id, + ), ); final settingsStore = _MemorySettingsStore() ..value = AppSettings.defaults() @@ -6014,6 +7546,7 @@ void main() { .copyWith( documentViewMode: DocumentViewModePreference.source, localeTag: 'de', + automaticSpelling: false, ) .toJson(); final container = ProviderContainer( @@ -6395,7 +7928,10 @@ void main() { final settingsStore = _MemorySettingsStore() ..value = AppSettings.defaults() - .copyWith(documentViewMode: DocumentViewModePreference.editor) + .copyWith( + documentViewMode: DocumentViewModePreference.editor, + automaticSpelling: false, + ) .toJson(); const service = _SearchWorkspaceService( '# Shared document frame\n\nParagraph line one\nParagraph line two\n', @@ -6929,7 +8465,10 @@ void main() { final settingsStore = _MemorySettingsStore() ..value = AppSettings.defaults() - .copyWith(documentViewMode: DocumentViewModePreference.editor) + .copyWith( + documentViewMode: DocumentViewModePreference.editor, + automaticSpelling: false, + ) .toJson(); const service = _SearchWorkspaceService('> Shared quote.\n'); final container = ProviderContainer( @@ -7033,6 +8572,7 @@ void main() { .copyWith( localeTag: 'ar', documentViewMode: DocumentViewModePreference.editor, + automaticSpelling: false, ) .toJson(); const service = _SearchWorkspaceService('```dart\n$code\n```\n\nمرحبا\n'); @@ -7150,7 +8690,10 @@ void main() { final settingsStore = _MemorySettingsStore() ..value = AppSettings.defaults() - .copyWith(documentViewMode: DocumentViewModePreference.editor) + .copyWith( + documentViewMode: DocumentViewModePreference.editor, + automaticSpelling: false, + ) .toJson(); const headings = ['First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth']; const service = _SearchWorkspaceService(''' @@ -7354,19 +8897,50 @@ After break. final settingsStore = _MemorySettingsStore() ..value = AppSettings.defaults() - .copyWith(documentViewMode: DocumentViewModePreference.editor) + .copyWith( + documentViewMode: DocumentViewModePreference.editor, + automaticSpelling: false, + ) .toJson(); - const service = _SearchWorkspaceService(''' + const source = ''' Shared warning. ![Shared image](missing.png){ width="320" } -''', writerside: true); +'''; + final root = Directory('test/fixtures/writerside/basic_project').absolute; + const service = WorkspaceService(); + final workspace = (await tester.runAsync( + () => service.openPath(root.path), + ))!; + final activeBuffer = DocumentBuffer( + id: 'writerside-rich-blocks-active', + filePath: workspace.activeFilePath, + text: source, + lastSavedText: source, + dirty: false, + editorState: const DocumentEditorState( + mode: DocumentViewModePreference.editor, + ), + ); + final preview = service.buildDocumentPreview(workspace, activeBuffer); + final controller = _MutableWorkspaceController( + WorkspaceState( + workspace: workspace, + preview: preview, + documentBuffers: [activeBuffer], + activeBufferId: activeBuffer.id, + ), + ); + final binding = TestWidgetsFlutterBinding.ensureInitialized(); + binding.platformDispatcher.defaultRouteNameTestValue = '/workspace'; + addTearDown(() { + binding.platformDispatcher.defaultRouteNameTestValue = '/'; + }); final container = ProviderContainer( overrides: [ linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), localSettingsStoreProvider.overrideWithValue(settingsStore), - workspaceServiceProvider.overrideWithValue(service), - startupPathProvider.overrideWithValue('/tmp/shared-rich-blocks.md'), + workspaceControllerProvider.overrideWith(() => controller), ], ); addTearDown(container.dispose); @@ -7384,6 +8958,10 @@ After break. break; } } + await tester.pump(BusyMarkMotion.bannerReveal); + final spellingBanner = find.byType(BusyMarkBanner); + expect(tester.widget(spellingBanner).revealed, isFalse); + expect(tester.getSize(spellingBanner).height, 0); final editorAdmonition = find.byType(BusyMarkDocumentAdmonition); final editorImage = find.byType(MarkdownImageView); @@ -11255,6 +12833,19 @@ class _MutableWorkspaceController extends WorkspaceController { @override void updateActiveEditorMode(DocumentViewModePreference mode) { requestedEditorMode = mode; + final activeId = state.activeBufferId; + if (activeId == null) return; + state = state.copyWith( + documentBuffers: [ + for (final buffer in state.documentBuffers) + if (buffer.id == activeId) + buffer.copyWith( + editorState: buffer.editorState.copyWith(mode: mode), + ) + else + buffer, + ], + ); } WritersideTocBatchMoveRequest? dragRequest; @@ -11760,8 +13351,10 @@ class _TabbedWorkspaceService extends WorkspaceService { @override Future loadTextWithSnapshot(String path) async { final text = _sources[path] ?? _sourceFor(path); + final decoded = decodeUtf8Document(utf8.encode(text)); return WorkspaceFileLoad( - text: text, + text: decoded.text, + format: decoded.format, snapshot: WorkspaceFileSnapshot( modifiedAt: DateTime(2026), size: text.length, @@ -11771,7 +13364,10 @@ class _TabbedWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { return workspace.copyWith(diagnostics: const []); } @@ -11995,19 +13591,16 @@ class _SearchRegressionService extends WorkspaceService { } class _SearchWorkspaceService extends WorkspaceService { - const _SearchWorkspaceService(this.source, {this.writerside = false}); + const _SearchWorkspaceService(this.source); final String source; - final bool writerside; @override Future openPath(String path) async { final markdown = markdownParser.parse( filePath: path, source: source, - mode: writerside - ? MarkdownMode.writersideMarkdown - : MarkdownMode.commonMark, + mode: MarkdownMode.commonMark, ); return Workspace( id: path, @@ -12020,9 +13613,7 @@ class _SearchWorkspaceService extends WorkspaceService { DocumentFile( absolutePath: path, relativePath: 'search-scroll.md', - kind: writerside - ? DocumentKind.writersideMarkdownTopic - : DocumentKind.markdown, + kind: DocumentKind.markdown, size: source.length, lastModified: DateTime(2026), ), @@ -12478,6 +14069,270 @@ GitDiffFile _gitDiffFile( ); } +Future<({String bundle, String storage})> _createSettingsSpellingFixture( + Directory temporary, +) async { + final bundle = await createSpellingTestBundle(temporary); + final storage = p.join(temporary.path, 'dictionary-storage'); + final catalogFile = File(p.join(bundle, 'dictionaries.json')); + final catalog = + jsonDecode(await catalogFile.readAsString()) as Map; + final dictionaries = catalog['dictionaries']! as List; + final english = Map.from( + dictionaries.single! as Map, + ); + dictionaries.add({ + ...english, + 'resourceId': 'fr-Test', + 'id': 'fr-Test', + 'locales': ['fr-Test'], + 'label': 'Test French', + }); + await catalogFile.writeAsString(jsonEncode(catalog)); + + final downloaded = Directory(p.join(storage, 'downloaded', 'en-Test')); + final installedManifest = + jsonDecode( + await File(p.join(downloaded.path, 'manifest.json')).readAsString(), + ) + as Map; + final imported = Directory(p.join(storage, 'imported', 'local-Test')); + await imported.create(recursive: true); + await File( + p.join(downloaded.path, 'dictionary.aff'), + ).copy(p.join(imported.path, 'dictionary.aff')); + await File( + p.join(downloaded.path, 'dictionary.dic'), + ).copy(p.join(imported.path, 'dictionary.dic')); + await File(p.join(imported.path, 'manifest.json')).writeAsString( + jsonEncode({ + ...installedManifest, + 'kind': 'imported', + 'resourceId': 'local-Test', + 'id': 'local-Test', + 'locales': ['local-Test'], + 'label': 'Local Test English', + 'sourceRevision': 'local-import', + }), + ); + + final invalid = Directory(p.join(storage, 'imported', 'xx-Test')); + await invalid.create(recursive: true); + await File(p.join(invalid.path, 'manifest.json')).writeAsString( + jsonEncode({ + ...installedManifest, + 'kind': 'imported', + 'resourceId': 'xx-Test', + 'id': 'xx-Test', + 'locales': ['xx-Test'], + 'label': 'Broken import', + 'sourceRevision': 'local-import', + }), + ); + return (bundle: bundle, storage: storage); +} + +class _SettingsSpellingHarness { + _SettingsSpellingHarness({ + required this.temporary, + required this.container, + required this.spelling, + this.projectSpellingPath, + }); + + final Directory temporary; + final ProviderContainer container; + final SpellingSessionController spelling; + final String? projectSpellingPath; + + Future dispose() async { + container.dispose(); + if (await temporary.exists()) { + await temporary.delete(recursive: true); + } + } +} + +Future<_SettingsSpellingHarness> _pumpSettingsSpellingHarness( + WidgetTester tester, { + required LinuxHeaderBarService headerBarService, + required _MemorySettingsStore settingsStore, + required SpellingDictionaryFileDownload downloadFile, + String? projectLanguage, +}) async { + tester.view.devicePixelRatio = 1; + tester.view.physicalSize = const Size(800, 900); + addTearDown(tester.view.resetDevicePixelRatio); + addTearDown(tester.view.resetPhysicalSize); + + late Directory temporary; + late SpellingSessionController spelling; + Workspace? workspace; + String? projectSpellingPath; + await tester.runAsync(() async { + temporary = await Directory.systemTemp.createTemp( + 'busymark-settings-language-transaction-', + ); + final fixture = await _createSettingsSpellingFixture(temporary); + if (projectLanguage != null) { + final projectRoot = Directory(p.join(temporary.path, 'project')); + await projectRoot.create(recursive: true); + await File( + p.join(projectRoot.path, 'document.md'), + ).writeAsString('# Project\n'); + projectSpellingPath = p.join( + projectRoot.path, + '.busymark', + 'spelling.json', + ); + final projectFile = File(projectSpellingPath!); + await projectFile.parent.create(recursive: true); + await projectFile.writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 1, + 'projectLanguage': projectLanguage, + 'words': {}, + }), + ); + workspace = await const WorkspaceService().openPath(projectRoot.path); + } + spelling = SpellingSessionController( + bundledRoot: fixture.bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: fixture.storage, + verifyDictionaryChecksums: false, + dictionaryDownloader: SpellingDictionaryDownloader( + downloadFile: downloadFile, + ), + ); + await spelling.prepareSettings(workspace); + }); + + final container = ProviderContainer( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue(settingsStore), + systemAccentColorProvider.overrideWith((ref) => const Stream.empty()), + spellingSessionControllerProvider.overrideWith((ref) => spelling), + if (workspace != null) + startupPathProvider.overrideWithValue(workspace!.rootPath), + ], + ); + await tester.pumpWidget( + UncontrolledProviderScope(container: container, child: const BusyMarkApp()), + ); + await tester.pump(); + for (var attempt = 0; attempt < 20; attempt += 1) { + await tester.pump(const Duration(milliseconds: 50)); + } + container.read(appRouterProvider).go('/settings?page=editor'); + await tester.pump(); + for (var attempt = 0; attempt < 10; attempt += 1) { + await tester.pump(const Duration(milliseconds: 50)); + } + final l10n = AppLocalizationsEn(); + await _pumpUntilFound(tester, find.byTooltip(l10n.defaultSpellingLanguage)); + + return _SettingsSpellingHarness( + temporary: temporary, + container: container, + spelling: spelling, + projectSpellingPath: projectSpellingPath, + ); +} + +Future _selectSpellingLanguage( + WidgetTester tester, { + required String selectorTooltip, + required String languageLabel, +}) async { + await tester.ensureVisible(find.byTooltip(selectorTooltip)); + await _pumpSettingsUi(tester); + final selector = _spellingLanguageSelector(tester, selectorTooltip); + final languageId = selector.options + .singleWhere((option) => option.label == languageLabel) + .value; + selector.onSelected(languageId); + await _pumpSettingsUi(tester); +} + +Future _openImportDictionaryPrompt(WidgetTester tester) async { + final import = find.byKey(const ValueKey('import-spelling-dictionary')); + if (import.evaluate().isEmpty) { + final dictionariesNavigation = find.byKey( + const ValueKey('settings-spelling-dictionaries'), + ); + await tester.ensureVisible(dictionariesNavigation); + await tester.tap(dictionariesNavigation); + await _pumpUntilFound(tester, import); + } + await tester.ensureVisible(import); + await _pumpSettingsUi(tester); + await tester.tap(import); + await _pumpUntilFound(tester, find.byType(BusyMarkDialogShell)); +} + +BusyMarkPopupSelector _spellingLanguageSelector( + WidgetTester tester, + String tooltip, +) { + return tester.widget>( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkPopupSelector && widget.tooltip == tooltip, + ), + ); +} + +Future _pumpUntilCondition( + WidgetTester tester, + bool Function() condition, +) async { + for (var attempt = 0; attempt < 200 && !condition(); attempt += 1) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 25)), + ); + await tester.pump(); + } + expect(condition(), isTrue); + await _pumpSettingsUi(tester); +} + +Future _pumpSettingsUi(WidgetTester tester) async { + await tester.pump(); + for (var attempt = 0; attempt < 6; attempt += 1) { + await tester.pump(const Duration(milliseconds: 50)); + } +} + +Future _copySettingsDictionaryDownload({ + required Uri source, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, +}) async { + cancellation.throwIfCancelled(); + final fileName = source.path.endsWith('.aff') ? 'test.aff' : 'test.dic'; + final sourceFile = File( + p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + fileName, + ), + ); + final bytes = await sourceFile.readAsBytes(); + if (bytes.length != expectedBytes) { + throw StateError('Test dictionary size does not match its catalog.'); + } + await destination.writeAsBytes(bytes, flush: true); + onProgress(bytes.length); +} + class _MemorySettingsStore implements LocalSettingsStore { Map value = {}; diff --git a/test/src/asset_ingestion_service_test.dart b/test/src/asset_ingestion_service_test.dart index 7807ff1b..cd2ff28a 100644 --- a/test/src/asset_ingestion_service_test.dart +++ b/test/src/asset_ingestion_service_test.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -59,6 +60,7 @@ void main() { request: request, origin: AssetIngestionOrigin.screenshotPaste, ); + await service.commit(first); final reused = await service.ingestBytes( bytes: png, suggestedFileName: 'different.png', @@ -78,6 +80,205 @@ void main() { expect(p.basename(collision.absolutePath), 'image-2.png'); }); + for (final identicalBytes in [true, false]) { + test( + 'overlapping ${identicalBytes ? 'identical' : 'different'} publications keep the committed owner', + () async { + final workspace = await Directory.systemTemp.createTemp( + 'busymark-asset-ownership-', + ); + addTearDown(() => workspace.delete(recursive: true)); + final firstDocument = File(p.join(workspace.path, 'first.md')) + ..writeAsStringSync(''); + final secondDocument = File(p.join(workspace.path, 'second.md')) + ..writeAsStringSync(''); + final firstPublished = Completer(); + final releaseFirst = Completer(); + final firstService = AssetIngestionService( + hooks: AssetIngestionHooks( + afterPublication: (asset) async { + firstPublished.complete(); + await releaseFirst.future; + }, + ), + ); + const secondService = AssetIngestionService(); + final firstRequest = AssetIngestionRequest( + documentFilePath: firstDocument.path, + workspaceKind: AssetWorkspaceKind.markdownWorkspace, + workspaceRoot: workspace.path, + ); + final secondRequest = AssetIngestionRequest( + documentFilePath: secondDocument.path, + workspaceKind: AssetWorkspaceKind.markdownWorkspace, + workspaceRoot: workspace.path, + ); + final otherBytes = Uint8List.fromList(png); + if (!identicalBytes) otherBytes[otherBytes.length - 1] ^= 1; + + final firstFuture = firstService.ingestBytes( + bytes: png, + suggestedFileName: 'image.png', + request: firstRequest, + origin: AssetIngestionOrigin.screenshotPaste, + ); + await firstPublished.future; + final committed = await secondService.ingestBytes( + bytes: otherBytes, + suggestedFileName: 'image.png', + request: secondRequest, + origin: AssetIngestionOrigin.clipboardImageFile, + ); + await secondService.commit(committed); + releaseFirst.complete(); + final stale = await firstFuture; + await firstService.rollback(stale); + + expect(committed.absolutePath, isNot(stale.absolutePath)); + expect(await File(committed.absolutePath).exists(), isTrue); + expect(await File(committed.absolutePath).readAsBytes(), otherBytes); + expect(await File(stale.absolutePath).exists(), isFalse); + }, + ); + } + + for (final identicalBytes in [true, false]) { + test( + 'separate processes protect ${identicalBytes ? 'identical' : 'different'} pending publications with equal filenames', + () async { + final workspace = await Directory.systemTemp.createTemp( + 'busymark-asset-process-ownership-', + ); + addTearDown(() => workspace.delete(recursive: true)); + final firstDocument = File(p.join(workspace.path, 'first.md')) + ..writeAsStringSync(''); + final secondDocument = File(p.join(workspace.path, 'second.md')) + ..writeAsStringSync(''); + final otherBytes = Uint8List.fromList(png); + if (!identicalBytes) otherBytes[otherBytes.length - 1] ^= 1; + + final first = await _startAssetProcess( + 'wait', + workspace.path, + firstDocument.path, + 'image.png', + png, + ); + addTearDown(() => first.process.kill()); + final second = await _runAssetProcess( + 'commit', + workspace.path, + secondDocument.path, + 'image.png', + otherBytes, + ); + first.process.stdin.writeln('rollback'); + await first.process.stdin.flush(); + expect(await first.process.exitCode, 0); + + expect(second['path'], isNot(first.message['path'])); + final committed = File(second['path']! as String); + expect(await committed.exists(), isTrue); + expect(await committed.readAsBytes(), otherBytes); + expect(await File(first.message['path']! as String).exists(), isFalse); + }, + ); + } + + test( + 'failed publication releases only its own filesystem reservation', + () async { + final workspace = await Directory.systemTemp.createTemp( + 'busymark-asset-process-failure-', + ); + addTearDown(() => workspace.delete(recursive: true)); + final document = File(p.join(workspace.path, 'note.md')) + ..writeAsStringSync(''); + + final failed = await _runAssetProcess( + 'fail-publication', + workspace.path, + document.path, + 'image.png', + png, + ); + expect(failed['error'], contains('injected publication failure')); + final committed = await _runAssetProcess( + 'commit', + workspace.path, + document.path, + 'image.png', + png, + ); + + expect(p.basename(committed['path']! as String), 'image.png'); + expect(await File(committed['path']! as String).readAsBytes(), png); + }, + ); + + test( + 'terminated provisional owner remains reserved across processes', + () async { + final workspace = await Directory.systemTemp.createTemp( + 'busymark-asset-process-termination-', + ); + addTearDown(() => workspace.delete(recursive: true)); + final firstDocument = File(p.join(workspace.path, 'first.md')) + ..writeAsStringSync(''); + final secondDocument = File(p.join(workspace.path, 'second.md')) + ..writeAsStringSync(''); + final first = await _startAssetProcess( + 'wait', + workspace.path, + firstDocument.path, + 'image.png', + png, + ); + first.process.kill(); + await first.process.exitCode; + + final second = await _runAssetProcess( + 'commit', + workspace.path, + secondDocument.path, + 'image.png', + png, + ); + + expect(second['path'], isNot(first.message['path'])); + expect(await File(first.message['path']! as String).readAsBytes(), png); + expect(await File(second['path']! as String).readAsBytes(), png); + }, + ); + + test( + 'rollback cannot delete an asset after its publication is committed', + () async { + final workspace = await Directory.systemTemp.createTemp( + 'busymark-asset-commit-', + ); + addTearDown(() => workspace.delete(recursive: true)); + final document = File(p.join(workspace.path, 'note.md')) + ..writeAsStringSync(''); + const service = AssetIngestionService(); + final asset = await service.ingestBytes( + bytes: png, + suggestedFileName: 'image.png', + request: AssetIngestionRequest( + documentFilePath: document.path, + workspaceKind: AssetWorkspaceKind.markdownWorkspace, + workspaceRoot: workspace.path, + ), + origin: AssetIngestionOrigin.screenshotPaste, + ); + + await service.commit(asset); + await service.rollback(asset); + + expect(await File(asset.absolutePath).readAsBytes(), png); + }, + ); + test('uses the configured Writerside images directory', () async { final project = await Directory.systemTemp.createTemp( 'busymark-ws-assets-', @@ -228,3 +429,56 @@ void main() { ); }); } + +Future<({Process process, Map message})> _startAssetProcess( + String action, + String workspace, + String document, + String filename, + List bytes, +) async { + final dart = p.join( + Platform.environment['FLUTTER_ROOT']!, + 'bin', + 'cache', + 'dart-sdk', + 'bin', + 'dart', + ); + final process = await Process.start(dart, [ + 'run', + 'test/support/asset_ingestion_process.dart', + action, + workspace, + document, + filename, + base64Encode(bytes), + ]); + final messages = process.stdout + .transform(utf8.decoder) + .transform(const LineSplitter()); + final message = jsonDecode(await messages.first) as Map; + return (process: process, message: message); +} + +Future> _runAssetProcess( + String action, + String workspace, + String document, + String filename, + List bytes, +) async { + final running = await _startAssetProcess( + action, + workspace, + document, + filename, + bytes, + ); + final stderrText = await running.process.stderr + .transform(utf8.decoder) + .join(); + final exitCode = await running.process.exitCode; + expect(exitCode, 0, reason: stderrText); + return running.message; +} diff --git a/test/src/busymark_design_test.dart b/test/src/busymark_design_test.dart index 189ab5cd..f2b14d2a 100644 --- a/test/src/busymark_design_test.dart +++ b/test/src/busymark_design_test.dart @@ -20,6 +20,430 @@ import 'package:yaru/yaru.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + testWidgets('switch suppresses state halos and preserves focus borders', ( + tester, + ) async { + final focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final theme = buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: const Color(0xFF3584E4), + ); + + final inheritedTheme = YaruSwitchThemeData( + color: const WidgetStatePropertyAll(Color(0xFF123456)), + borderColor: const WidgetStatePropertyAll(Color(0xFF234567)), + thumbColor: const WidgetStatePropertyAll(Color(0xFF345678)), + ); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: YaruTheme( + data: const YaruThemeData(focusBorders: true), + child: Theme( + data: theme, + child: YaruSwitchTheme( + data: inheritedTheme, + child: Scaffold( + body: BusyMarkSwitch( + value: true, + onChanged: (_) {}, + autofocus: true, + focusNode: focusNode, + ), + ), + ), + ), + ), + ), + ); + await tester.pump(); + + final switchFinder = find.byType(BusyMarkSwitch); + final localTheme = _busyMarkSwitchTheme(tester, switchFinder); + expect( + localTheme.indicatorColor?.resolve({WidgetState.hovered}), + Colors.transparent, + ); + expect( + localTheme.indicatorColor?.resolve({WidgetState.focused}), + Colors.transparent, + ); + expect(localTheme.color, same(inheritedTheme.color)); + expect(localTheme.borderColor, same(inheritedTheme.borderColor)); + expect(localTheme.thumbColor, same(inheritedTheme.thumbColor)); + expect(focusNode.hasFocus, isTrue); + expect( + find.descendant(of: switchFinder, matching: find.byType(YaruFocusBorder)), + findsOneWidget, + ); + }); + + const switchAccents = { + 'blue': Color(0xFF3584E4), + 'purple': Color(0xFFB34CB4), + }; + for (final brightness in Brightness.values) { + for (final accent in switchAccents.entries) { + testWidgets('checked switch follows ${accent.key} track states in ' + '${brightness.name}', (tester) async { + final theme = buildBusyMarkTheme( + brightness: brightness, + accentColor: accent.value, + ); + + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: BusyMarkSwitch( + key: const ValueKey('switch'), + value: true, + onChanged: (_) {}, + ), + ), + ), + ), + ); + + final switchFinder = find.byKey(const ValueKey('switch')); + Color selectedTrack() => tester + .widget( + find.descendant( + of: switchFinder, + matching: find.byType(YaruSwitch), + ), + ) + .selectedColor!; + final normal = selectedTrack(); + expect( + normal, + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: 0, + ), + ); + + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(mouse.removePointer); + await mouse.addPointer(location: Offset.zero); + await mouse.moveTo(tester.getCenter(switchFinder)); + await tester.pump(); + + final hovered = selectedTrack(); + expect( + hovered, + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: 0.07, + ), + ); + expect( + HSLColor.fromColor(hovered).lightness, + greaterThan(HSLColor.fromColor(normal).lightness), + ); + + await mouse.down(tester.getCenter(switchFinder)); + await tester.pump(); + final pressed = selectedTrack(); + expect( + pressed, + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: -0.07, + ), + ); + expect(pressed, isNot(normal)); + expect(pressed, isNot(hovered)); + + await mouse.up(); + await tester.pump(); + expect(selectedTrack(), hovered); + + await mouse.moveTo(Offset.zero); + await tester.pump(); + expect(selectedTrack(), normal); + }); + } + } + + testWidgets('disabled switch preserves inherited disabled styling', ( + tester, + ) async { + const disabledTrack = Color(0xFF595959); + const disabledThumb = Color(0xFF9A9A9A); + final inheritedTheme = YaruSwitchThemeData( + color: WidgetStateProperty.resolveWith( + (states) => + states.contains(WidgetState.disabled) ? disabledTrack : null, + ), + thumbColor: WidgetStateProperty.resolveWith( + (states) => + states.contains(WidgetState.disabled) ? disabledThumb : null, + ), + ); + + await tester.pumpWidget( + MaterialApp( + theme: buildBusyMarkTheme( + brightness: Brightness.dark, + accentColor: const Color(0xFFB34CB4), + ), + home: YaruSwitchTheme( + data: inheritedTheme, + child: const Scaffold( + body: Center( + child: BusyMarkSwitch( + key: ValueKey('switch'), + value: true, + onChanged: null, + ), + ), + ), + ), + ), + ); + + final switchFinder = find.byKey(const ValueKey('switch')); + Color? disabledSelectedTrack() => _busyMarkSwitchTheme( + tester, + switchFinder, + ).color!.resolve({WidgetState.disabled, WidgetState.selected}); + Color? disabledSelectedThumb() => _busyMarkSwitchTheme( + tester, + switchFinder, + ).thumbColor!.resolve({WidgetState.disabled, WidgetState.selected}); + + expect(disabledSelectedTrack(), disabledTrack); + expect(disabledSelectedThumb(), disabledThumb); + + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(mouse.removePointer); + await mouse.addPointer(location: Offset.zero); + await mouse.moveTo(tester.getCenter(switchFinder)); + await tester.pump(); + + expect(disabledSelectedTrack(), disabledTrack); + expect(disabledSelectedThumb(), disabledThumb); + expect( + tester.getSemantics(find.byType(YaruSwitch)).flagsCollection.isEnabled, + ui.Tristate.isFalse, + ); + }); + + testWidgets('switch row owns its control and activates exactly once', ( + tester, + ) async { + final changes = []; + + Widget buildRow() => MaterialApp( + home: Scaffold( + body: BusyMarkSwitchRow( + title: 'Automatic save', + value: false, + onChanged: changes.add, + ), + ), + ); + + await tester.pumpWidget(buildRow()); + + final row = find.byType(BusyMarkSwitchRow); + expect( + find.descendant(of: row, matching: find.byType(YaruSwitchListTile)), + findsOneWidget, + ); + expect( + find.descendant(of: row, matching: find.byType(BusyMarkSwitch)), + findsOneWidget, + ); + expect( + find.descendant(of: row, matching: find.byType(YaruSwitch)), + findsOneWidget, + ); + expect( + tester + .widget(find.byType(YaruSwitchListTile)) + .control, + isA(), + ); + + await tester.tap(find.byType(YaruSwitch)); + await tester.pump(); + expect(changes, [true]); + + changes.clear(); + await tester.pumpWidget(buildRow()); + await tester.tap(find.text('Automatic save')); + await tester.pump(); + expect(changes, [true]); + }); + + testWidgets('switch preserves Yaru drag activation', (tester) async { + final changes = []; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: BusyMarkSwitch(value: false, onChanged: changes.add), + ), + ), + ), + ); + + await tester.drag(find.byType(YaruSwitch), const Offset(40, 0)); + await tester.pump(); + + expect(changes, [true]); + }); + + testWidgets('radio suppresses state halos and preserves focus borders', ( + tester, + ) async { + final focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final theme = buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: const Color(0xFF3584E4), + ); + + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: YaruTheme( + data: const YaruThemeData(focusBorders: true), + child: Theme( + data: theme, + child: Scaffold( + body: BusyMarkRadioButton( + value: 'md', + groupValue: 'md', + onChanged: (_) {}, + title: const Text('Markdown'), + autofocus: true, + focusNode: focusNode, + ), + ), + ), + ), + ), + ); + await tester.pump(); + + final radio = find.byType(BusyMarkRadioButton); + final localTheme = tester.widget( + find.descendant(of: radio, matching: find.byType(YaruRadioTheme)), + ); + expect( + localTheme.data.indicatorColor?.resolve({WidgetState.hovered}), + Colors.transparent, + ); + expect( + localTheme.data.indicatorColor?.resolve({WidgetState.focused}), + Colors.transparent, + ); + expect(focusNode.hasFocus, isTrue); + expect( + tester + .widget( + find.descendant(of: radio, matching: find.byType(YaruToggleButton)), + ) + .hasFocusBorder, + isTrue, + ); + expect( + find.descendant(of: radio, matching: find.byType(YaruFocusBorder)), + findsOneWidget, + ); + }); + + const radioAccents = {'blue': Color(0xFF3584E4), 'purple': Color(0xFFB34CB4)}; + for (final brightness in Brightness.values) { + for (final accent in radioAccents.entries) { + testWidgets('selected radio follows ${accent.key} accent states in ' + '${brightness.name}', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: buildBusyMarkTheme( + brightness: brightness, + accentColor: accent.value, + ), + home: Scaffold( + body: Center( + child: BusyMarkRadioButton( + key: const ValueKey('radio'), + value: 'md', + groupValue: 'md', + onChanged: (_) {}, + title: const Text('Markdown'), + ), + ), + ), + ), + ); + await tester.pump(); + + final radio = find.byKey(const ValueKey('radio')); + Color selectedColor() { + final localTheme = tester.widget( + find.descendant(of: radio, matching: find.byType(YaruRadioTheme)), + ); + return localTheme.data.color!.resolve({WidgetState.selected})!; + } + + final normal = selectedColor(); + expect( + normal, + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: 0, + ), + ); + + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(mouse.removePointer); + await mouse.addPointer(location: Offset.zero); + await mouse.moveTo(tester.getCenter(radio)); + await tester.pump(); + + final hovered = selectedColor(); + expect(hovered, isNot(normal)); + expect( + hovered, + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: 0.07, + ), + ); + + await mouse.down(tester.getCenter(radio)); + await tester.pump(); + expect( + selectedColor(), + _expectedRadioColor( + accent.value, + brightness: brightness, + stateDelta: -0.07, + ), + ); + + await mouse.up(); + await tester.pump(); + expect(selectedColor(), hovered); + + await mouse.moveTo(Offset.zero); + await tester.pump(); + expect(selectedColor(), normal); + }); + } + } + testWidgets( 'informational dialog keeps the close control at the right edge', (tester) async { @@ -483,6 +907,8 @@ void main() { value: 'editor', label: 'Editor', shortcut: 'Ctrl+1', + checked: true, + trailingCheck: true, ), ], onSelected: (_) {}, @@ -506,6 +932,9 @@ void main() { ); expect(find.text('Editor'), findsOneWidget); expect(find.text('Ctrl+1'), findsOneWidget); + expect(find.byIcon(BusyMarkGlyphs.check), findsOneWidget); + expect(find.byType(Radio), findsNothing); + expect(find.byType(RadioListTile), findsNothing); expect(find.byTooltip('Editor (Ctrl+1)'), findsNothing); expect(find.byTooltip('Main menu'), findsOneWidget); expect( @@ -589,6 +1018,7 @@ void main() { 'enabled': true, 'checkable': false, 'selected': false, + 'mutuallyExclusive': true, 'separator': false, }, { @@ -596,6 +1026,7 @@ void main() { 'enabled': false, 'checkable': false, 'selected': false, + 'mutuallyExclusive': false, 'separator': true, }, { @@ -605,6 +1036,7 @@ void main() { 'enabled': true, 'checkable': true, 'selected': true, + 'mutuallyExclusive': true, 'separator': false, }, ]); @@ -1114,6 +1546,219 @@ void main() { ); }); + testWidgets('grouped list headings use the native semantic heading style', ( + tester, + ) async { + for (final brightness in Brightness.values) { + final theme = buildBusyMarkTheme( + brightness: brightness, + accentColor: const Color(0xFF3584E4), + ); + final colors = theme.extension()!; + + await tester.pumpWidget( + MaterialApp( + theme: theme, + darkTheme: theme, + themeMode: brightness == Brightness.dark + ? ThemeMode.dark + : ThemeMode.light, + themeAnimationDuration: Duration.zero, + home: const Scaffold( + body: BusyMarkGroupedList( + title: 'Native heading', + description: 'Secondary description', + children: [BusyMarkActionRow(title: 'Setting')], + ), + ), + ), + ); + + final heading = tester.widget(find.text('Native heading')); + expect(heading.style?.fontSize, theme.textTheme.bodyMedium?.fontSize); + expect(heading.style?.fontWeight, FontWeight.w700); + expect(heading.style?.color, colors.foreground); + expect(heading.style?.color, isNot(colors.mutedForeground)); + + final description = tester.widget( + find.text('Secondary description'), + ); + expect(description.style?.color, theme.colorScheme.onSurfaceVariant); + expect(description.style?.fontWeight, isNot(FontWeight.w700)); + } + }); + + testWidgets('contextual banner uses semantic surfaces in light and dark', ( + tester, + ) async { + for (final brightness in Brightness.values) { + final theme = buildBusyMarkTheme( + brightness: brightness, + accentColor: const Color(0xFF3584E4), + ); + final colors = theme.extension()!; + + await tester.pumpWidget( + MaterialApp( + theme: theme, + darkTheme: theme, + themeMode: brightness == Brightness.dark + ? ThemeMode.dark + : ThemeMode.light, + themeAnimationDuration: Duration.zero, + home: Scaffold( + body: SizedBox( + width: 360, + child: BusyMarkBanner( + title: 'Test English dictionary is not installed', + actionLabel: 'Install dictionary', + onAction: () {}, + ), + ), + ), + ), + ); + + final title = tester.widget( + find.text('Test English dictionary is not installed'), + ); + final surface = tester.widget( + find.descendant( + of: find.byType(BusyMarkBanner), + matching: find.byType(DecoratedBox), + ), + ); + final decoration = surface.decoration as BoxDecoration; + expect(title.style?.color, colors.foreground); + expect(title.style?.fontSize, theme.textTheme.bodySmall?.fontSize); + expect(title.style?.fontWeight, isNot(FontWeight.w700)); + expect(title.maxLines, 2); + expect(title.softWrap, isTrue); + expect(title.overflow, TextOverflow.ellipsis); + expect(title.textAlign, TextAlign.start); + expect(decoration.color, colors.panel); + expect(decoration.border?.bottom.color, colors.divider); + expect( + find.descendant( + of: find.byType(BusyMarkBanner), + matching: find.byType(FilledButton), + ), + findsOneWidget, + ); + expect( + find.descendant( + of: find.byType(BusyMarkBanner), + matching: find.byType(ElevatedButton), + ), + findsNothing, + ); + expect( + find.descendant( + of: find.byType(BusyMarkBanner), + matching: find.byWidgetPredicate( + (widget) => + widget is Padding && + widget.padding == + const EdgeInsets.symmetric( + horizontal: BusyMarkSpacing.md, + vertical: BusyMarkSpacing.xs, + ), + ), + ), + findsOneWidget, + ); + expect(tester.takeException(), isNull); + } + }); + + testWidgets('contextual banner animates its mounted layout height', ( + tester, + ) async { + const bannerKey = ValueKey('animated-banner'); + + Future pumpBanner(bool revealed) { + return tester.pumpWidget( + MaterialApp( + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: const Color(0xFF3584E4), + ), + home: Scaffold( + body: Align( + alignment: Alignment.topCenter, + child: BusyMarkBanner( + key: bannerKey, + title: 'Dictionary is not installed', + revealed: revealed, + ), + ), + ), + ), + ); + } + + await pumpBanner(false); + final banner = find.byKey(bannerKey); + expect(tester.getSize(banner).height, 0); + + await pumpBanner(true); + final immediateRevealHeight = tester.getSize(banner).height; + await tester.pump(const Duration(milliseconds: 125)); + final partialRevealHeight = tester.getSize(banner).height; + await tester.pumpAndSettle(); + final fullHeight = tester.getSize(banner).height; + + expect(immediateRevealHeight, lessThan(fullHeight)); + expect(partialRevealHeight, greaterThan(0)); + expect(partialRevealHeight, lessThan(fullHeight)); + + await pumpBanner(false); + await tester.pump(const Duration(milliseconds: 125)); + final partialConcealHeight = tester.getSize(banner).height; + expect(partialConcealHeight, greaterThan(0)); + expect(partialConcealHeight, lessThan(fullHeight)); + await tester.pumpAndSettle(); + expect(tester.getSize(banner).height, 0); + }); + + testWidgets('contextual banner reveal honors reduced motion', (tester) async { + const bannerKey = ValueKey('reduced-motion-banner'); + + Future pumpBanner(bool revealed) { + return tester.pumpWidget( + MaterialApp( + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: const Color(0xFF3584E4), + ), + home: MediaQuery( + data: const MediaQueryData(disableAnimations: true), + child: Scaffold( + body: Align( + alignment: Alignment.topCenter, + child: BusyMarkBanner( + key: bannerKey, + title: 'Dictionary is not installed', + revealed: revealed, + ), + ), + ), + ), + ), + ); + } + + await pumpBanner(false); + final banner = find.byKey(bannerKey); + expect(tester.getSize(banner).height, 0); + + await pumpBanner(true); + expect(tester.getSize(banner).height, greaterThan(0)); + + await pumpBanner(false); + expect(tester.getSize(banner).height, 0); + }); + testWidgets('dialog grouped cards resolve the contextual native layer', ( tester, ) async { @@ -1688,46 +2333,63 @@ void main() { expect(actionRows.length, greaterThan(1)); }); - testWidgets('disabled destructive rows use the disabled semantic color', ( - tester, - ) async { - final theme = buildBusyMarkTheme( - brightness: Brightness.dark, - accentColor: const Color(0xFFE95420), - ); - final colors = theme.extension()!; + testWidgets( + 'action rows use semantic destructive foreground in light and dark themes', + (tester) async { + for (final brightness in Brightness.values) { + final theme = buildBusyMarkTheme( + brightness: brightness, + accentColor: const Color(0xFFE95420), + ); + final colors = theme.extension()!; - await tester.pumpWidget( - MaterialApp( - theme: theme, - home: Scaffold( - body: Column( - children: [ - BusyMarkActionRow( - title: 'Enabled delete', - destructive: true, - onTap: () {}, - ), - const BusyMarkActionRow( - title: 'Disabled delete', - destructive: true, - enabled: false, + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + body: Column( + children: [ + BusyMarkActionRow( + title: 'Enabled delete', + destructive: true, + onTap: () {}, + ), + const BusyMarkActionRow(title: 'Ordinary action'), + const BusyMarkActionRow( + title: 'Disabled delete', + destructive: true, + enabled: false, + ), + ], ), - ], + ), ), - ), - ), - ); + ); + await tester.pumpAndSettle(); + + final enabled = find.text('Enabled delete'); + final enabledContext = tester.element(enabled); + final expected = brightness == Brightness.dark + ? BusyMarkLinuxPalette.destructiveForegroundDark + : BusyMarkLinuxPalette.destructiveForegroundLight; + expect(busyMarkDestructiveForeground(enabledContext), expected); + expect(tester.widget(enabled).style?.color, expected); + if (brightness == Brightness.dark) { + expect(expected, isNot(theme.colorScheme.error)); + } - expect( - tester.widget(find.text('Enabled delete')).style?.color, - theme.colorScheme.error, - ); - expect( - tester.widget(find.text('Disabled delete')).style?.color, - colors.disabledForeground, - ); - }); + final ordinary = find.text('Ordinary action'); + expect( + DefaultTextStyle.of(tester.element(ordinary)).style.color, + colors.foreground, + ); + expect( + tester.widget(find.text('Disabled delete')).style?.color, + colors.disabledForeground, + ); + } + }, + ); testWidgets('shared text-entry group delegates fields to the framework', ( tester, @@ -1939,6 +2601,18 @@ void main() { }); } +Color _expectedRadioColor( + Color accent, { + required Brightness brightness, + required double stateDelta, +}) { + final hsl = HSLColor.fromColor(accent); + final normalDelta = brightness == Brightness.light ? 0.05 : 0.0; + return hsl + .withLightness((hsl.lightness + normalDelta + stateDelta).clamp(0.0, 1.0)) + .toColor(); +} + double _contrastRatio(Color foreground, Color background) { final foregroundLuminance = foreground.computeLuminance(); final backgroundLuminance = background.computeLuminance(); @@ -2069,3 +2743,17 @@ class _CapturedPixels { final int width; final RenderRepaintBoundary boundary; } + +YaruSwitchThemeData _busyMarkSwitchTheme( + WidgetTester tester, + Finder switchFinder, +) { + return tester + .widget( + find.descendant( + of: switchFinder, + matching: find.byType(YaruSwitchTheme), + ), + ) + .data; +} diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index d296328c..a56336e6 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -4673,6 +4673,240 @@ void main() {} } }); + test('link title backslashes use standards-safe character references', () { + for (final value in const [ + (title: r'C:\Temp', encoded: 'C:\Temp'), + (title: r'C:\\Temp', encoded: 'C:\\Temp'), + (title: r'\* \[ \( \!', encoded: '\* \[ \( \!'), + (title: '\\"©\\', encoded: '\\\"&copy;\'), + ]) { + final link = BusyInline( + kind: BusyInlineKind.link, + text: 'X', + children: const [BusyInline(kind: BusyInlineKind.text, text: 'X')], + destination: 'https://example.test', + attributes: {'title': value.title}, + ); + final expected = '[X](https://example.test "${value.encoded}")'; + final serializer = const BusyMarkMarkdownSerializer(); + + expect(serializer.serializeInlineFragment([link]), expected); + final mapped = serializer.serializeInlineFragmentAtTextOffset([ + link, + ], textOffset: 1); + expect(mapped.source, expected); + expect(mapped.sourceOffset, expected.length); + + final reparsed = parser.parse( + filePath: 'topic.md', + source: '$expected\n', + validateLocalReferences: false, + ); + final reparsedLink = reparsed.busyDocument.blocks.single.inlines.single; + expect(reparsedLink.kind, BusyInlineKind.link); + expect(reparsedLink.attributes['title'], value.title, reason: expected); + } + }); + + test('inline serialization distinguishes every hard-break run boundary', () { + const hardBreak = BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'); + const serializer = BusyMarkMarkdownSerializer(); + + void expectOffsets( + List inlines, + String source, + Map offsets, + ) { + for (final entry in offsets.entries) { + final serialized = serializer.serializeInlineFragmentAtTextOffset( + inlines, + textOffset: entry.key, + ); + expect(serialized.source, source); + expect( + serialized.sourceOffset, + entry.value, + reason: 'logical offset ${entry.key} in $source', + ); + } + } + + expectOffsets( + const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + hardBreak, + hardBreak, + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + 'A\n
\n
\nB', + const {1: 1, 2: 6, 3: 11, 4: 13}, + ); + expectOffsets( + const [hardBreak, hardBreak], + '

', + const {0: 0, 1: 4, 2: 8}, + ); + expectOffsets( + const [hardBreak, hardBreak, hardBreak], + '

\n
', + const {0: 0, 1: 4, 2: 8, 3: 13}, + ); + + final nested = BusyInline( + kind: BusyInlineKind.link, + text: 'A\n\nB', + destination: 'https://destination.test', + children: const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + hardBreak, + hardBreak, + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + ); + expectOffsets( + [nested], + '[A\n
\n
\nB](https://destination.test)', + const {1: 2, 2: 7, 3: 12, 4: 41}, + ); + expectOffsets( + const [ + BusyInline( + kind: BusyInlineKind.strong, + text: 'A\n\n\nB', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + hardBreak, + hardBreak, + hardBreak, + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + ), + ], + '**A\n
\n
\n
\nB**', + const {1: 3, 2: 8, 3: 13, 4: 18, 5: 22}, + ); + + final markers = [ + const BusyMarkInlineLineBreakOffset(textOffset: 1), + const BusyMarkInlineLineBreakOffset(textOffset: 2), + ]; + final traversals = []; + debugBusyMarkInlineSerializationTraversal = traversals.add; + addTearDown(() => debugBusyMarkInlineSerializationTraversal = null); + final serialized = serializer.serializeInlineFragmentWithOffsets( + const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + hardBreak, + hardBreak, + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + textOffset: 2, + lineBreakOffsets: markers, + ); + expect(traversals, hasLength(1)); + expect(serialized.sourceOffset, 6); + expect(serialized.lineBreakSourceOffsets[markers.first], 6); + expect(serialized.lineBreakSourceOffsets[markers.last], 11); + }); + + test('link titles round-trip decoded punctuation and line endings', () { + for (final title in const [ + 'literal ©', + r'quote " and backslash \\', + 'first\nsecond', + 'first\r\nsecond', + ]) { + final source = const BusyMarkMarkdownSerializer().serializeInlineFragment( + [ + BusyInline( + kind: BusyInlineKind.link, + text: 'X', + children: [BusyInline(kind: BusyInlineKind.text, text: 'X')], + destination: 'https://example.test', + attributes: {'title': title}, + ), + ], + ); + final reparsed = parser.parse( + filePath: 'topic.md', + source: '$source\n', + validateLocalReferences: false, + ); + final link = reparsed.busyDocument.blocks.single.inlines.single; + expect(link.kind, BusyInlineKind.link, reason: source); + expect(link.destination, 'https://example.test', reason: source); + expect(link.attributes['title'], title, reason: source); + } + + const editorTitle = 'literal © "quoted" \\ first\nsecond'; + final controller = BusyMarkWysiwygDocumentController( + document: const BusyDocument( + filePath: 'editor.md', + mode: MarkdownMode.gfm, + blocks: [ + BusyBlock( + id: 'editor-link-title', + kind: BusyBlockKind.paragraph, + dirty: true, + inlines: [ + BusyInline( + kind: BusyInlineKind.link, + text: 'X', + destination: 'https://example.test', + children: [BusyInline(kind: BusyInlineKind.text, text: 'X')], + attributes: {'title': editorTitle}, + ), + ], + ), + ], + ), + ); + final editorMarkdown = controller.markdown; + controller.dispose(); + final editorLink = parser + .parse( + filePath: 'editor.md', + source: editorMarkdown, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines + .single; + expect(editorLink.attributes['title'], editorTitle); + }); + + test('table link titles retain multiline values without physical rows', () { + const title = 'first\nsecond ©'; + final link = BusyInline( + kind: BusyInlineKind.link, + text: 'X', + children: const [BusyInline(kind: BusyInlineKind.text, text: 'X')], + destination: 'https://example.test', + attributes: const {'title': title}, + ); + final cell = const BusyMarkMarkdownSerializer().serializeInlineFragment([ + link, + ], tableCell: true); + expect(cell, isNot(contains('\n'))); + final source = '| H |\n| --- |\n| $cell |\n'; + final reparsed = parser.parse( + filePath: 'topic.md', + source: source, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ); + final table = reparsed.busyDocument.blocks.single; + expect(table.kind, BusyBlockKind.table); + expect(table.children, hasLength(2)); + expect(table.children.last.children, hasLength(1)); + final reparsedLink = table.children.last.children.single.inlines.single; + expect(reparsedLink.kind, BusyInlineKind.link); + expect(reparsedLink.destination, 'https://example.test'); + expect(reparsedLink.attributes['title'], title); + }); + test( 'serializer preserves fenced code delimiters and trailing whitespace', () { diff --git a/test/src/clipboard_history_panel_test.dart b/test/src/clipboard_history_panel_test.dart index ea803e7c..4db49b6b 100644 --- a/test/src/clipboard_history_panel_test.dart +++ b/test/src/clipboard_history_panel_test.dart @@ -247,6 +247,7 @@ void main() { ), ); expect(disabledPaste, findsOneWidget); + expect(find.text('Paste as Plain Text'), findsNothing); }); testWidgets('double-clicking a shared history row pastes the item', ( @@ -313,6 +314,47 @@ void main() { }, ); + testWidgets('source-only payload has no plain-text action', (tester) async { + final container = _container(); + container + .read(clipboardHistoryControllerProvider.notifier) + .retain( + const BusyMarkClipboardCapture( + kind: BusyMarkClipboardContentKind.text, + sourceText: '**source only**', + ), + ); + container + .read(clipboardInsertionRegistryProvider) + .register(_PanelInsertionTarget()); + await _pumpPanel(tester, container); + + await _openEntryActions(tester); + expect(find.text('Paste as Plain Text'), findsNothing); + }); + + testWidgets('image exposes plain paste only with real text', (tester) async { + final container = _container(); + container + .read(clipboardHistoryControllerProvider.notifier) + .retain( + BusyMarkClipboardCapture( + kind: BusyMarkClipboardContentKind.image, + text: 'image alternative', + imageBytes: Uint8List.fromList([1, 2, 3]), + imageMimeType: 'image/png', + ), + ); + final target = _PanelInsertionTarget(); + container.read(clipboardInsertionRegistryProvider).register(target); + await _pumpPanel(tester, container); + + await _openEntryActions(tester); + await tester.tap(find.text('Paste as Plain Text')); + await tester.pump(); + expect(target.lastPlainText, isTrue); + }); + testWidgets('failed insertion reports visible feedback', (tester) async { final container = _container(); container @@ -325,7 +367,7 @@ void main() { ), ); final target = _PanelInsertionTarget( - result: ClipboardPasteResult.staleTarget, + result: ClipboardPasteResult.unsupported, ); container.read(clipboardInsertionRegistryProvider).register(target); await _pumpPanel(tester, container); @@ -340,6 +382,31 @@ void main() { ); }); + testWidgets('cancelled insertion is terminal without an error toast', ( + tester, + ) async { + final container = _container(); + container + .read(clipboardHistoryControllerProvider.notifier) + .retain( + const BusyMarkClipboardCapture( + kind: BusyMarkClipboardContentKind.text, + text: 'cancelled item', + ), + ); + final target = _PanelInsertionTarget( + result: ClipboardPasteResult.cancelled, + ); + container.read(clipboardInsertionRegistryProvider).register(target); + await _pumpPanel(tester, container); + + await _openEntryActions(tester); + await tester.tap(find.text('Paste')); + await tester.pump(const Duration(milliseconds: 200)); + expect(target.pasteCalls, 1); + expect(find.text(AppLocalizationsEn().clipboardUnavailable), findsNothing); + }); + testWidgets( 'current external HTML is transient until panel insertion and remains reusable', (tester) async { @@ -354,7 +421,12 @@ void main() { ), ); final container = _container(clipboard: clipboard); - final target = _PanelInsertionTarget(); + final history = container.read( + clipboardHistoryControllerProvider.notifier, + ); + final target = _PanelInsertionTarget( + onInserted: history.retainCurrentAfterPaste, + ); container.read(clipboardInsertionRegistryProvider).register(target); await _pumpPanel(tester, container); expect( @@ -371,6 +443,10 @@ void main() { container.read(clipboardHistoryControllerProvider).entries, hasLength(1), ); + expect( + container.read(clipboardHistoryControllerProvider).entries.single.html, + html, + ); clipboard.value = const RichClipboardData( text: 'Replacement clipboard', @@ -415,7 +491,11 @@ void main() { isEmpty, ); - final successful = _PanelInsertionTarget(); + final successful = _PanelInsertionTarget( + onInserted: container + .read(clipboardHistoryControllerProvider.notifier) + .retainCurrentAfterPaste, + ); container.read(clipboardInsertionRegistryProvider).register(successful); await tester.pump(); await _openEntryActions(tester); @@ -427,6 +507,10 @@ void main() { container.read(clipboardHistoryControllerProvider).entries, hasLength(1), ); + expect( + container.read(clipboardHistoryControllerProvider).entries.single.html, + '

Rich source

', + ); }, ); @@ -438,7 +522,12 @@ void main() { ); final container = _container(clipboard: clipboard); final result = Completer(); - final target = _PanelInsertionTarget(resultFuture: result.future); + final target = _PanelInsertionTarget( + resultFuture: result.future, + onInserted: container + .read(clipboardHistoryControllerProvider.notifier) + .retainCurrentAfterPaste, + ); container.read(clipboardInsertionRegistryProvider).register(target); await _pumpPanel(tester, container); @@ -582,6 +671,7 @@ class _PanelInsertionTarget this.plainTextPasteAvailable, this.result = ClipboardPasteResult.inserted, this.resultFuture, + this.onInserted, }); final bool supportImages; @@ -589,6 +679,7 @@ class _PanelInsertionTarget final bool? plainTextPasteAvailable; final ClipboardPasteResult result; final Future? resultFuture; + final ValueChanged? onInserted; int pasteCalls = 0; bool? lastPlainText; final payloads = []; @@ -606,23 +697,31 @@ class _PanelInsertionTarget bool get editable => true; @override - bool canPaste(BusyMarkClipboardPayload payload, {required bool plainText}) { - final configured = plainText + bool canPaste( + BusyMarkClipboardPayload payload, { + required BusyMarkPasteMode mode, + }) { + final configured = mode == BusyMarkPasteMode.plainText ? plainTextPasteAvailable : normalPasteAvailable; - return configured ?? - (supportImages || payload.kind != BusyMarkClipboardContentKind.image); + if (configured != null) return configured; + if (mode == BusyMarkPasteMode.plainText) { + return payload.hasPlainTextRepresentation; + } + return supportImages || payload.kind != BusyMarkClipboardContentKind.image; } @override Future paste( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }) async { pasteCalls++; - lastPlainText = plainText; + lastPlainText = mode == BusyMarkPasteMode.plainText; payloads.add(payload); - return resultFuture ?? result; + final outcome = await (resultFuture ?? Future.value(result)); + if (outcome == ClipboardPasteResult.inserted) onInserted?.call(payload); + return outcome; } @override diff --git a/test/src/clipboard_history_test.dart b/test/src/clipboard_history_test.dart index e4a6c55f..1e0f3b90 100644 --- a/test/src/clipboard_history_test.dart +++ b/test/src/clipboard_history_test.dart @@ -200,6 +200,28 @@ void main() { }, ); + test('current source-only clipboard does not invent plain text', () async { + final scope = container( + current: const RichClipboardData( + sourceText: '**authored source**', + generation: 13, + ), + ); + await Future.delayed(Duration.zero); + + await scope + .read(clipboardHistoryControllerProvider.notifier) + .refreshCurrentClipboard(); + final current = scope + .read(clipboardHistoryControllerProvider) + .currentClipboard!; + expect(current.kind, BusyMarkClipboardContentKind.text); + expect(current.text, isNull); + expect(current.sourceText, '**authored source**'); + expect(current.hasPlainTextRepresentation, isFalse); + expect(current.hasSourceOrTextRepresentation, isTrue); + }); + test('equal visible text with different structure stays distinct', () async { final scope = container(); await Future.delayed(Duration.zero); @@ -490,7 +512,7 @@ class _InsertionTarget implements BusyMarkClipboardInsertionTarget { @override Future paste( BusyMarkClipboardPayload payload, { - required bool plainText, + required BusyMarkPasteMode mode, }) async { pastes++; return ClipboardPasteResult.inserted; diff --git a/test/src/clipboard_layout_table_test.dart b/test/src/clipboard_layout_table_test.dart new file mode 100644 index 00000000..cb48bc14 --- /dev/null +++ b/test/src/clipboard_layout_table_test.dart @@ -0,0 +1,217 @@ +import 'dart:io'; + +import 'package:busymark/src/clipboard/clipboard_insertion.dart'; +import 'package:busymark/src/editor/clipboard_paste_resolver.dart'; +import 'package:busymark/src/editor/source/source_paste_engine.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final source = File( + 'test/fixtures/clipboard/layout_table_job.html', + ).readAsStringSync(); + const plainText = + 'Example Developer\nReference Example-42\nPlain description'; + final snapshot = BusyMarkClipboardSnapshot( + html: source, + text: plainText, + external: true, + sessionOwned: false, + fromSystemClipboard: true, + ); + const resolver = BusyMarkClipboardPasteResolver(); + const parser = MarkdownParser(); + + test('data tables remain tables, including borderless and single-column data', () { + for (final source in [ + '
NameValue
', + '
First
Second
', + '
Title

One

Two

', + '

Heading in a data cell

', + '

Heading in a bordered cell

', + '
Data title

One

Two

', + '

One

Two

Value
', + '

Spanning header

', + ]) { + final decoded = const WysiwygClipboardHtml().decode( + source, + mode: MarkdownMode.gfm, + )!; + expect( + decoded.documentBlocks.where( + (block) => block.kind == BusyBlockKind.table, + ), + hasLength(1), + reason: source, + ); + } + }); + + test('nested layout wrappers retain their inner data table and prose', () { + final wrapped = '
$source
'; + final decoded = const WysiwygClipboardHtml().decode( + wrapped, + mode: MarkdownMode.gfm, + )!; + expect(decoded.documentBlocks.first.kind, BusyBlockKind.heading); + expect( + decoded.documentBlocks.where( + (block) => block.kind == BusyBlockKind.table, + ), + hasLength(1), + ); + expect( + decoded.documentBlocks.last.plainText, + 'Send questions to team@example.test.', + ); + }); + + test( + 'explicit presentation table keeps caption, cell order and direction', + () { + final decoded = const WysiwygClipboardHtml().decode( + '' + '' + '
Caption

First

Second

', + mode: MarkdownMode.gfm, + )!; + expect(decoded.documentBlocks.map((block) => block.plainText), [ + 'Caption', + 'First', + 'Second', + ]); + expect(decoded.documentBlocks.map((block) => block.attributes['dir']), [ + 'rtl', + 'rtl', + 'ltr', + ]); + expect( + decoded.documentBlocks.every( + (block) => block.kind == BusyBlockKind.paragraph, + ), + isTrue, + ); + }, + ); + + for (final destination in [ + BusyMarkPasteDestination.editor, + BusyMarkPasteDestination.markdownSource, + ]) { + test('${destination.name} preserves content inside a layout table', () { + final plan = resolver.resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.normal, + destination: destination, + markdownMode: MarkdownMode.gfm, + ); + final candidate = + plan.candidates.first as BusyMarkStructuredPasteCandidate; + final blocks = candidate.fragment.documentBlocks; + expect(blocks.first.kind, BusyBlockKind.heading); + expect( + blocks.where((block) => block.kind == BusyBlockKind.table), + hasLength(1), + ); + expect( + blocks.where((block) => block.kind == BusyBlockKind.unorderedListItem), + hasLength(3), + ); + + final target = parser + .parse( + filePath: '/destination.md', + source: 'Target\n', + mode: MarkdownMode.gfm, + ) + .busyDocument; + late String output; + if (destination == BusyMarkPasteDestination.editor) { + final controller = BusyMarkWysiwygDocumentController(document: target); + addTearDown(controller.dispose); + expect( + controller.insertStyledBlocksAtSelection( + blockId: target.blocks.first.id, + selectionStart: 0, + selectionEnd: 6, + blocks: candidate.fragment.blocks, + ), + isNotNull, + ); + output = controller.markdown; + } else { + final prepared = const SourcePasteEngine().prepareStructured( + target: const SourcePasteDocumentSnapshot( + expectedSource: 'Target\n', + selection: TextSelection(baseOffset: 0, extentOffset: 6), + format: SourceDocumentFormat.markdown, + markdownMode: MarkdownMode.gfm, + filePath: '/destination.md', + ), + fragment: candidate.fragment, + ); + expect(prepared, isA()); + final edit = (prepared as SourcePasteReady).edit; + output = edit.expectedSource.replaceRange( + edit.start, + edit.end, + edit.replacement, + ); + } + var previous = -1; + for (final text in [ + '## Example Developer', + '| Reference | Example-42 |', + 'Job Description', + '**About the team**', + 'We build helpful tools for our community.', + '- Design accessible interfaces.', + '- Test changes carefully.', + 'Work with colleagues across the organization.', + '**Qualifications**', + '- Experience delivering reliable software.', + 'Closing invitation with [application details](https://example.test/careers).', + ]) { + final index = output.indexOf(text); + expect(index, greaterThan(previous), reason: '$text in:\n$output'); + previous = index; + } + final reparsed = parser + .parse( + filePath: '/destination.md', + source: output, + mode: MarkdownMode.gfm, + ) + .busyDocument; + expect(reparsed.blocks.first.kind, BusyBlockKind.heading); + expect( + reparsed.blocks.where((block) => block.kind == BusyBlockKind.table), + hasLength(1), + ); + expect( + reparsed.blocks.where( + (block) => block.kind == BusyBlockKind.unorderedListItem, + ), + hasLength(3), + ); + }); + + test('${destination.name} plain paste ignores layout and rich content', () { + final plan = resolver.resolve( + snapshot: snapshot, + mode: BusyMarkPasteMode.plainText, + destination: destination, + ); + expect(plan.candidates, hasLength(1)); + expect( + (plan.candidates.single as BusyMarkPlainTextPasteCandidate).text, + plainText, + ); + }); + } +} diff --git a/test/src/clipboard_paste_resolver_test.dart b/test/src/clipboard_paste_resolver_test.dart new file mode 100644 index 00000000..6d6c65b5 --- /dev/null +++ b/test/src/clipboard_paste_resolver_test.dart @@ -0,0 +1,444 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:busymark/src/clipboard/clipboard_insertion.dart'; +import 'package:busymark/src/clipboard/clipboard_models.dart'; +import 'package:busymark/src/editor/clipboard_paste_resolver.dart'; +import 'package:busymark/src/editor/clipboard_local_image_path.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + const resolver = BusyMarkClipboardPasteResolver(); + + WysiwygClipboardFragment fragment({ + MarkdownMode mode = MarkdownMode.commonMark, + String text = 'native', + }) => WysiwygClipboardFragment( + mode: mode, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: text, + ranges: const [], + ), + ], + ); + + BusyMarkClipboardSnapshot snapshot({ + String? text, + String? sourceText, + String? html, + String? richFragment, + }) => BusyMarkClipboardSnapshot( + text: text, + sourceText: sourceText, + html: html, + richFragment: richFragment, + external: true, + sessionOwned: false, + fromSystemClipboard: true, + ); + + BusyMarkPastePlan resolve( + BusyMarkClipboardSnapshot value, { + BusyMarkPasteMode mode = BusyMarkPasteMode.normal, + BusyMarkPasteDestination destination = BusyMarkPasteDestination.editor, + MarkdownMode markdownMode = MarkdownMode.commonMark, + }) => resolver.resolve( + snapshot: value, + mode: mode, + destination: destination, + markdownMode: markdownMode, + ); + + test('valid native fragment wins over HTML and text', () { + final plan = resolve( + snapshot( + richFragment: fragment().encode(), + html: '

HTML

', + text: 'plain', + ), + ); + final first = plan.candidates.first as BusyMarkStructuredPasteCandidate; + expect(first.source, BusyMarkStructuredClipboardSource.richFragment); + expect(first.fragment.blocks.single.text, 'native'); + }); + + test('malformed native fragment falls through to valid HTML', () { + final plan = resolve( + snapshot( + richFragment: '{bad', + html: '

HTML

', + text: 'plain', + ), + ); + final first = plan.candidates.first as BusyMarkStructuredPasteCandidate; + expect(first.source, BusyMarkStructuredClipboardSource.html); + expect(first.fragment.blocks.single.text, 'HTML'); + }); + + test('unusable HTML falls through to source and plain text', () { + final plan = resolve( + snapshot( + html: '', + sourceText: '**source**', + text: 'plain', + ), + destination: BusyMarkPasteDestination.markdownSource, + ); + expect(plan.candidates, [ + isA(), + isA(), + ]); + }); + + test('HTML-only blockquotes are usable through descendant content', () { + for (final html in [ + '

Quoted

', + '

Nested

', + '
  • Listed
', + ]) { + final richOnly = resolve(snapshot(html: html)); + expect(richOnly.candidates, hasLength(1), reason: html); + final rich = + richOnly.candidates.single as BusyMarkStructuredPasteCandidate; + expect(rich.source, BusyMarkStructuredClipboardSource.html); + expect( + rich.fragment.documentBlocks.single.kind, + BusyBlockKind.blockquote, + ); + expect(rich.fragment.markdown, startsWith('>')); + expect( + resolve( + snapshot(html: html), + mode: BusyMarkPasteMode.plainText, + ).isEmpty, + isTrue, + ); + + final withText = resolve(snapshot(html: html, text: 'plain')); + expect( + withText.candidates.first, + isA(), + ); + expect(withText.candidates.last, isA()); + final plain = resolve( + snapshot(html: html, text: 'plain'), + mode: BusyMarkPasteMode.plainText, + ); + expect(plain.candidates, hasLength(1)); + expect( + (plain.candidates.single as BusyMarkPlainTextPasteCandidate).text, + 'plain', + ); + } + }); + + test( + 'mixed external HTML preserves every block for Editor and Markdown Source', + () { + const mixedHtml = ''' +

Release notes

+

Opening paragraph.

+
  • First supported item
+

Text before the data.

+ + + +
NameValue
AlphaOne
+

Closing paragraph.

+'''; + const plainText = 'plain-text fallback only'; + const expectedKinds = [ + BusyBlockKind.heading, + BusyBlockKind.paragraph, + BusyBlockKind.unorderedListItem, + BusyBlockKind.paragraph, + BusyBlockKind.table, + BusyBlockKind.paragraph, + ]; + + for (final destination in [ + BusyMarkPasteDestination.editor, + BusyMarkPasteDestination.markdownSource, + ]) { + final plan = resolve( + snapshot(html: mixedHtml, text: plainText), + destination: destination, + markdownMode: MarkdownMode.gfm, + ); + final structured = + plan.candidates.first as BusyMarkStructuredPasteCandidate; + expect( + structured.source, + BusyMarkStructuredClipboardSource.html, + reason: destination.name, + ); + expect( + structured.fragment.documentBlocks.map((block) => block.kind), + expectedKinds, + reason: destination.name, + ); + final markdown = structured.fragment.serializeFor( + destinationMode: MarkdownMode.gfm, + destinationFilePath: '/workspace/mixed.md', + ); + expect( + markdown.indexOf('# Release notes'), + lessThan(markdown.indexOf('Opening paragraph.')), + ); + expect( + markdown.indexOf('Opening paragraph.'), + lessThan(markdown.indexOf('- First supported item')), + ); + expect( + markdown.indexOf('- First supported item'), + lessThan(markdown.indexOf('Text before the data.')), + ); + expect( + markdown.indexOf('Text before the data.'), + lessThan(markdown.indexOf('| Name | Value |')), + ); + expect( + markdown.indexOf('| Name | Value |'), + lessThan(markdown.indexOf('Closing paragraph.')), + ); + + final plain = resolve( + snapshot(html: mixedHtml, text: plainText), + mode: BusyMarkPasteMode.plainText, + destination: destination, + ); + expect(plain.candidates, hasLength(1)); + expect( + (plain.candidates.single as BusyMarkPlainTextPasteCandidate).text, + plainText, + reason: destination.name, + ); + } + }, + ); + + test('plain mode uses only interoperable text', () { + final plan = resolve( + snapshot( + text: 'plain', + sourceText: '**source**', + html: 'HTML', + richFragment: fragment().encode(), + ), + mode: BusyMarkPasteMode.plainText, + ); + expect(plan.candidates, hasLength(1)); + expect( + (plan.candidates.single as BusyMarkPlainTextPasteCandidate).text, + 'plain', + ); + }); + + test('plain mode rejects source-only and image-only payloads', () { + expect( + resolve( + snapshot(sourceText: '**source**'), + mode: BusyMarkPasteMode.plainText, + ).isEmpty, + isTrue, + ); + final image = BusyMarkClipboardSnapshot.fromPayload( + BusyMarkClipboardPayload( + id: 'image', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.image, + imageBytes: Uint8List.fromList([1]), + ), + ); + expect(resolve(image, mode: BusyMarkPasteMode.plainText).isEmpty, isTrue); + }); + + test('whitespace text is valid and empty text is unavailable', () { + expect( + (resolve( + snapshot(text: ' \n'), + mode: BusyMarkPasteMode.plainText, + ).candidates.single + as BusyMarkPlainTextPasteCandidate) + .text, + ' \n', + ); + expect( + resolve(snapshot(text: ''), mode: BusyMarkPasteMode.plainText).isEmpty, + isTrue, + ); + }); + + test('explicit image is first in normal mode', () { + final image = BusyMarkClipboardSnapshot.fromPayload( + BusyMarkClipboardPayload( + id: 'image', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.image, + text: 'alternative', + imageBytes: Uint8List.fromList([1, 2, 3]), + ), + ); + expect( + resolve(image).candidates.single, + isA(), + ); + }); + + test('Editor and Source use their required textual fallback order', () { + final value = snapshot(text: 'plain', sourceText: '**source**'); + expect( + resolve(value).candidates.map((candidate) => candidate.runtimeType), + [BusyMarkPlainTextPasteCandidate], + ); + expect( + resolve( + value, + destination: BusyMarkPasteDestination.markdownSource, + ).candidates.map((candidate) => candidate.runtimeType), + [BusyMarkSourceTextPasteCandidate, BusyMarkPlainTextPasteCandidate], + ); + }); + + test('structured source serialization accepts the destination mode', () { + final original = fragment( + mode: MarkdownMode.writersideMarkdown, + text: 'destination content', + ); + final candidate = + resolve( + snapshot(richFragment: original.encode()), + destination: BusyMarkPasteDestination.markdownSource, + markdownMode: MarkdownMode.gfm, + ).candidates.single + as BusyMarkStructuredPasteCandidate; + expect(candidate.fragment.mode, MarkdownMode.writersideMarkdown); + expect( + candidate.fragment.serializeFor( + destinationMode: MarkdownMode.gfm, + destinationFilePath: '/workspace/destination.md', + ), + 'destination content\n', + ); + expect( + candidate.fragment.serializeInlineFor( + destinationMode: MarkdownMode.gfm, + destinationFilePath: '/workspace/destination.md', + ), + 'destination content', + ); + }); + + test( + 'native inline serialization preserves whitespace without a newline', + () { + final value = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: ' X ', + ranges: const [ + BusyInlineStyleRange( + start: 1, + end: 2, + kind: BusyInlineKind.strong, + ), + ], + ), + ], + ); + expect( + value.serializeInlineFor( + destinationMode: MarkdownMode.commonMark, + destinationFilePath: '/workspace/target.md', + ), + ' **X** ', + ); + + final spaces = fragment(text: ' '); + expect( + spaces.serializeInlineFor( + destinationMode: MarkdownMode.commonMark, + destinationFilePath: '/workspace/target.md', + ), + ' ', + ); + }, + ); + + test( + 'table-cell fragment serialization escapes pipes and flattens lines', + () { + final value = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'A|B', + ranges: const [], + ), + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'C\nD', + ranges: const [], + ), + ], + ); + expect( + value.serializeTableCellFor( + destinationMode: MarkdownMode.gfm, + destinationFilePath: '/workspace/target.md', + ), + r'A\|B C D', + ); + }, + ); + + test( + 'local image path detection is safe and rejects altered URI meaning', + () async { + final directory = await Directory.systemTemp.createTemp( + 'busymark-local-clipboard-path-', + ); + addTearDown(() => directory.delete(recursive: true)); + final image = File('${directory.path}/image.png')..writeAsBytesSync([1]); + final text = File('${directory.path}/notes.txt') + ..writeAsStringSync('text'); + + expect(busyMarkLocalImagePathFromClipboardText(image.path), image.path); + expect( + busyMarkLocalImagePathFromClipboardText(image.uri.toString()), + image.path, + ); + expect( + busyMarkLocalImagePathFromClipboardText( + '${directory.path}/missing.png', + ), + isNull, + ); + expect(busyMarkLocalImagePathFromClipboardText(text.path), isNull); + expect( + busyMarkLocalImagePathFromClipboardText('${image.uri}?version=2'), + isNull, + ); + expect( + busyMarkLocalImagePathFromClipboardText('${image.uri}#preview'), + isNull, + ); + expect( + busyMarkLocalImagePathFromClipboardText( + 'file://remote-host${image.uri.path}', + ), + isNull, + ); + }, + ); +} diff --git a/test/src/command_registry_test.dart b/test/src/command_registry_test.dart index 3e149bc9..2b72078e 100644 --- a/test/src/command_registry_test.dart +++ b/test/src/command_registry_test.dart @@ -33,6 +33,12 @@ void main() { final registry = BusyMarkCommandCatalog.create(); expect(registry.commands, isNotEmpty); + expect(BusyMarkCommandIds.textPastePlainText, 'text.pastePlainText'); + final pastePlainText = registry[BusyMarkCommandIds.textPastePlainText]; + expect(pastePlainText, isNotNull); + expect(pastePlainText?.scope, BusyMarkCommandScope.textEditing); + expect(pastePlainText?.shortcut?.label, 'Ctrl+Shift+V'); + expect(pastePlainText?.execute, isNotNull); expect(registry[BusyMarkCommandIds.save]?.shortcut?.label, 'Ctrl+S'); expect( registry[BusyMarkCommandIds.commandPalette]?.shortcut?.label, diff --git a/test/src/document_status_bar_test.dart b/test/src/document_status_bar_test.dart new file mode 100644 index 00000000..a0433544 --- /dev/null +++ b/test/src/document_status_bar_test.dart @@ -0,0 +1,158 @@ +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/app/app_theme.dart'; +import 'package:busymark/src/app/busymark_design.dart'; +import 'package:busymark/src/workspace/presentation/document_status_bar.dart'; +import 'package:busymark/src/workspace/text_format_metadata.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const _lfFormat = TextFormatMetadata( + hasUtf8Bom: false, + lineEnding: DocumentLineEnding.lf, + hasFinalNewline: true, + lfCount: 1, +); + +void main() { + testWidgets('places interactive spelling at start and format at end', ( + tester, + ) async { + var presses = 0; + await _pumpStatusBar( + tester, + spellingLabel: 'English (Canada)', + onSpellingPressed: () => presses += 1, + ); + + final bar = find.byKey(const ValueKey('document-status-bar')); + final spelling = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + final format = find.text('LF'); + expect(find.text('English (Canada)'), findsOneWidget); + expect(format, findsOneWidget); + expect( + tester.getCenter(spelling).dx, + lessThan(tester.getCenter(format).dx), + ); + expect(tester.getSize(bar).height, BusyMarkSizes.documentStatusBarHeight); + + final context = tester.element(bar); + final colors = BusyMarkSurfaceColors.of(context); + final decoration = tester.widget(bar).decoration; + expect(decoration, isA()); + final box = decoration as BoxDecoration; + expect(box.color, colors.headerbarFlat); + expect(box.border?.top.color, colors.subtleBorder); + expect(find.byType(FilledButton), findsNothing); + expect(find.byType(ElevatedButton), findsNothing); + expect( + tester.widget(find.byType(Tooltip).first).message, + 'Choose spelling language', + ); + + await tester.tap(spelling); + expect(presses, 1); + }); + + testWidgets('keeps passive format when spelling is unsupported', ( + tester, + ) async { + await _pumpStatusBar(tester, spellingLabel: null); + + expect(find.byKey(const ValueKey('document-status-bar')), findsOneWidget); + expect( + find.byKey(const ValueKey('document-spelling-language-status')), + findsNothing, + ); + expect(find.text('LF'), findsOneWidget); + }); + + testWidgets('truncates a long one-line language without displacing format', ( + tester, + ) async { + await _pumpStatusBar( + tester, + width: 220, + spellingLabel: + 'An intentionally very long localized spelling language name', + onSpellingPressed: () {}, + ); + + final label = tester.widget( + find.text('An intentionally very long localized spelling language name'), + ); + final format = find.text('LF'); + expect(label.maxLines, 1); + expect(label.softWrap, isFalse); + expect(label.overflow, TextOverflow.ellipsis); + expect(format, findsOneWidget); + expect( + tester.getTopRight(format).dx, + lessThanOrEqualTo( + tester + .getTopRight(find.byKey(const ValueKey('document-status-bar'))) + .dx, + ), + ); + expect(tester.takeException(), isNull); + }); + + testWidgets('uses directional start and end placement in RTL', ( + tester, + ) async { + await _pumpStatusBar( + tester, + spellingLabel: 'العربية', + onSpellingPressed: () {}, + textDirection: TextDirection.rtl, + ); + + final spelling = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + final format = find.text('LF'); + expect( + tester.getCenter(spelling).dx, + greaterThan(tester.getCenter(format).dx), + ); + }); +} + +Future _pumpStatusBar( + WidgetTester tester, { + required String? spellingLabel, + VoidCallback? onSpellingPressed, + double width = 500, + TextDirection textDirection = TextDirection.ltr, +}) { + return tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.dark, + accentColor: BusyMarkLinuxPalette.blueAccent, + ), + home: Scaffold( + body: Directionality( + textDirection: textDirection, + child: Align( + alignment: Alignment.topCenter, + child: SizedBox( + width: width, + child: BusyMarkDocumentStatusBar( + format: _lfFormat, + spellingLabel: spellingLabel, + spellingTooltip: spellingLabel == null + ? null + : 'Choose spelling language', + onSpellingPressed: onSpellingPressed, + ), + ), + ), + ), + ), + ), + ); +} diff --git a/test/src/git/git_widget_test.dart b/test/src/git/git_widget_test.dart index efb304a8..c7fced62 100644 --- a/test/src/git/git_widget_test.dart +++ b/test/src/git/git_widget_test.dart @@ -1485,6 +1485,11 @@ void main() { ); expect(resetButton, findsOneWidget); expect(tester.widget(resetButton).onPressed, isNull); + expect( + find.byType(BusyMarkRadioButton), + findsNWidgets(GitResetMode.values.length), + ); + expect(find.byType(RadioListTile), findsNothing); await tester.tap(find.text(l10n.gitResetModeMixed)); await tester.pump(); diff --git a/test/src/html_publication_test.dart b/test/src/html_publication_test.dart index 0d4c333c..c0a14d71 100644 --- a/test/src/html_publication_test.dart +++ b/test/src/html_publication_test.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'dart:convert'; import 'package:busymark/src/core/atomic_file_writer.dart'; @@ -513,10 +514,18 @@ class _FailHtmlWrite extends AtomicFileWriter { String targetPath, List bytes, { required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, }) async { if (targetPath.endsWith('.html')) { throw const FileSystemException('Simulated permission failure'); } - return super.writeBytes(targetPath, bytes, overwrite: overwrite); + return super.writeBytes( + targetPath, + bytes, + overwrite: overwrite, + beforePublish: beforePublish, + acceptReplaced: acceptReplaced, + ); } } diff --git a/test/src/local_history_controller_test.dart b/test/src/local_history_controller_test.dart index f2d42265..17f63448 100644 --- a/test/src/local_history_controller_test.dart +++ b/test/src/local_history_controller_test.dart @@ -2022,11 +2022,13 @@ class _BlockingRevisionReadStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) => delegate.promoteUntitledDocument( documentId: documentId, destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); @override @@ -2077,11 +2079,13 @@ class _FailingSourceCaptureStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) => delegate.promoteUntitledDocument( documentId: documentId, destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); @override @@ -2155,11 +2159,13 @@ class _BlockingNextCaptureStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) => delegate.promoteUntitledDocument( documentId: documentId, destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); @override @@ -2180,6 +2186,7 @@ class _FailingFirstPromotionStore extends MemoryLocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) { if (_failNextPromotion) { _failNextPromotion = false; @@ -2190,6 +2197,7 @@ class _FailingFirstPromotionStore extends MemoryLocalHistoryStore { destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); } } @@ -2204,6 +2212,7 @@ class _ControllablePromotionStore extends MemoryLocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) { promotionAttempts++; if (failPromotions) { @@ -2216,6 +2225,7 @@ class _ControllablePromotionStore extends MemoryLocalHistoryStore { destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); } } @@ -2233,6 +2243,7 @@ class _FailingPromotionThenCaptureStore extends MemoryLocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) { if (_failPromotion) { _failPromotion = false; @@ -2243,6 +2254,7 @@ class _FailingPromotionThenCaptureStore extends MemoryLocalHistoryStore { destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); } diff --git a/test/src/local_history_store_test.dart b/test/src/local_history_store_test.dart index bfd3957e..17449704 100644 --- a/test/src/local_history_store_test.dart +++ b/test/src/local_history_store_test.dart @@ -48,6 +48,57 @@ void main() { maximumBytes: 16 * 1024 * 1024, ); + for (final inMemory in [false, true]) { + test( + 'promotion repair rechecks the stale owner atomically (memory=$inMemory)', + () async { + final LocalHistoryStore target = inMemory + ? MemoryLocalHistoryStore() + : store; + final time = DateTime.utc(2026, 1, 1); + final old = await target.capture(request('Old', time), policy); + final draft = await target.capture( + LocalHistoryCaptureRequest( + displayName: 'Draft', + source: 'New', + untitled: true, + format: TextFormatMetadata.utf8Lf, + capturedAt: time.add(const Duration(minutes: 1)), + reason: LocalHistoryCaptureReason.baseline, + ), + policy, + ); + await target.capture( + request('Another owner update', time.add(const Duration(minutes: 2))), + policy, + ); + expect( + await target.promoteUntitledDocument( + documentId: draft.document.id, + destinationPath: '/workspace/guide.md', + displayName: 'guide.md', + updatedAt: time.add(const Duration(minutes: 3)), + staleDestinationOwner: old.document, + ), + isNull, + ); + final snapshot = await target.load(); + expect( + snapshot.documents + .singleWhere((d) => d.id == old.document.id) + .deleted, + isFalse, + ); + expect( + snapshot.documents + .singleWhere((d) => d.id == draft.document.id) + .currentPath, + isNull, + ); + }, + ); + } + test( 'persists full revisions and stable document identity across restart', () async { @@ -170,6 +221,95 @@ void main() { }, ); + test('deleted paths never own promotion, lookup, or remap', () async { + for (final entry in <({String name, LocalHistoryStore store})>[ + (name: 'file', store: store), + (name: 'memory', store: MemoryLocalHistoryStore()), + ]) { + final path = '/workspace/${entry.name}-Note.md'; + final moved = '/archive/${entry.name}-Note.md'; + final time = DateTime.utc(2026, 1, 1); + final old = await entry.store.capture( + LocalHistoryCaptureRequest( + path: path, + displayName: 'Note.md', + source: 'old revision', + format: TextFormatMetadata.utf8Lf, + capturedAt: time, + reason: LocalHistoryCaptureReason.saved, + ), + policy, + ); + await entry.store.markDeleted(path, recursive: false); + final untitled = await entry.store.capture( + LocalHistoryCaptureRequest( + displayName: 'Draft.md', + source: 'new untitled revision', + format: TextFormatMetadata.utf8Lf, + capturedAt: time.add(const Duration(seconds: 1)), + reason: LocalHistoryCaptureReason.automaticCheckpoint, + untitled: true, + ), + policy, + ); + final promoted = await entry.store.promoteUntitledDocument( + documentId: untitled.document.id, + destinationPath: path, + displayName: 'Note.md', + updatedAt: time.add(const Duration(seconds: 2)), + ); + expect(promoted?.id, untitled.document.id, reason: entry.name); + + var snapshot = await entry.store.load(); + final oldDocument = snapshot.documents.singleWhere( + (document) => document.id == old.document.id, + ); + final active = snapshot.documents.singleWhere( + (document) => document.id == untitled.document.id, + ); + expect(oldDocument.deleted, isTrue, reason: entry.name); + expect(oldDocument.currentPath, path, reason: entry.name); + expect(active.deleted, isFalse, reason: entry.name); + expect(active.currentPath, path, reason: entry.name); + expect( + (await entry.store.readRevision(old.revision!.id))?.source, + 'old revision', + reason: entry.name, + ); + + await entry.store.remapPath(path, moved); + snapshot = await entry.store.load(); + expect( + snapshot.documents + .singleWhere((document) => document.id == old.document.id) + .currentPath, + path, + reason: entry.name, + ); + expect( + snapshot.documents + .singleWhere((document) => document.id == active.id) + .currentPath, + moved, + reason: entry.name, + ); + + await entry.store.markDeleted(moved, recursive: false); + final reused = await entry.store.capture( + LocalHistoryCaptureRequest( + path: moved, + displayName: 'Note.md', + source: 'fresh named revision', + format: TextFormatMetadata.utf8Lf, + capturedAt: time.add(const Duration(seconds: 3)), + reason: LocalHistoryCaptureReason.saved, + ), + policy, + ); + expect(reused.document.id, isNot(active.id), reason: entry.name); + } + }); + test( 'deduplicates only adjacent ordinary captures and preserves A-B-A', () async { diff --git a/test/src/local_history_workspace_test.dart b/test/src/local_history_workspace_test.dart index 0ff20440..f000fd72 100644 --- a/test/src/local_history_workspace_test.dart +++ b/test/src/local_history_workspace_test.dart @@ -35,6 +35,202 @@ void main() { if (await root.exists()) await root.delete(recursive: true); }); + for (final fileStore in [false, true]) { + for (final externalChange in [false, true]) { + test('restored promotion reconciles only the saved lineage ' + '(file=$fileStore external=$externalChange)', () async { + final LocalHistoryStore store = fileStore + ? FileLocalHistoryStore( + rootDirectory: () async => + Directory(p.join(root.path, 'history')), + ) + : MemoryLocalHistoryStore(); + final destination = p.join(root.path, 'Untitled.md'); + final old = await _capture( + store, + destination, + 'Old retained contents\n', + ); + final saved = await store.capture( + LocalHistoryCaptureRequest( + displayName: 'Untitled 1', + untitled: true, + source: 'Recovered lineage\n', + format: TextFormatMetadata.utf8Lf.copyWith(hasFinalNewline: true), + capturedAt: DateTime.utc(2026, 1, 1, 0, 0, 10), + reason: LocalHistoryCaptureReason.automaticCheckpoint, + ), + const LocalHistoryPolicy(), + ); + await File(destination).writeAsString( + externalChange ? 'External replacement\n' : 'Recovered lineage\n', + ); + final sessions = MemoryDocumentSessionStore() + ..value = WorkspaceSessionSnapshot( + workspacePath: null, + tabs: const [], + activeBufferId: null, + pendingLocalHistoryAssociations: [ + PendingLocalHistoryAssociation( + bufferId: 'old-closed-buffer', + documentId: saved.document.id, + destinationPath: destination, + displayName: 'Untitled.md', + ), + ], + ); + final harness = await _harness( + store, + sessionStore: sessions, + recoveryStore: MemoryDocumentRecoveryStore(), + ); + await harness.controller.restorePreviousSession(); + final history = harness.container.read( + localHistoryControllerProvider.notifier, + ); + var snapshot = await store.load(); + expect( + snapshot.documents + .singleWhere((d) => d.id == old.document.id) + .deleted, + !externalChange, + reason: + 'warning=${harness.container.read(localHistoryControllerProvider).warning?.detail}; pending=${history.pendingIdentityPromotions.length}; docs=${snapshot.documents.map((d) => '${d.id}:${d.untitled}:${d.updatedAt}').toList()}', + ); + expect( + snapshot.documents + .singleWhere((d) => d.id == saved.document.id) + .currentPath, + externalChange ? isNull : destination, + ); + expect( + (await store.readRevision(old.revision!.id))!.source, + 'Old retained contents\n', + ); + expect( + (await store.readRevision(saved.revision!.id))!.source, + 'Recovered lineage\n', + ); + expect( + history.pendingIdentityPromotions, + externalChange ? hasLength(1) : isEmpty, + ); + await harness.controller.createMarkdownFile(); + harness.controller.updateActiveText('New unrelated document\n'); + await history.flushBuffer(harness.state.activeBuffer!); + final warning = harness.container + .read(localHistoryControllerProvider) + .warning; + if (externalChange) { + expect(warning?.kind, LocalHistoryWarningKind.pathChange); + expect(warning?.detail, destination); + } else { + expect(warning, isNull); + await harness.controller.flushPersistence(); + expect(sessions.value!.pendingLocalHistoryAssociations, isEmpty); + } + snapshot = await store.load(); + expect(snapshot.documents, hasLength(3)); + expect( + await File(destination).readAsString(), + externalChange ? 'External replacement\n' : 'Recovered lineage\n', + ); + }); + } + } + + test('first save cannot adopt a deleted path lineage', () async { + final store = MemoryLocalHistoryStore(); + final destination = p.join(root.path, 'Note.md'); + final old = await _capture(store, destination, 'Old retained history\n'); + await store.markDeleted(destination, recursive: false); + final harness = await _harness(store); + + await harness.controller.createMarkdownFile(); + harness.controller.updateActiveText('New file contents\n'); + expect(await harness.controller.saveActiveAs(destination), isTrue); + + final snapshot = await store.load(); + final oldDocument = snapshot.documents.singleWhere( + (document) => document.id == old.document.id, + ); + final active = snapshot.documents.singleWhere( + (document) => !document.deleted && document.currentPath == destination, + ); + expect(active.id, isNot(oldDocument.id)); + expect(oldDocument.deleted, isTrue); + expect( + await _revisionSources(store, snapshot.revisionsFor(oldDocument.id)), + ['Old retained history\n'], + ); + expect(await File(destination).readAsString(), 'New file contents\n'); + expect(harness.state.activeBuffer!.isDirty, isFalse); + expect( + harness.container.read(localHistoryControllerProvider).warning?.kind, + isNot(LocalHistoryWarningKind.pathChange), + ); + }); + + test('vacant first save retires a stale active history owner', () async { + final store = MemoryLocalHistoryStore(); + final destination = p.join(root.path, 'Note.md'); + final stale = await _capture(store, destination, 'Stale owner\n'); + expect(await File(destination).exists(), isFalse); + final harness = await _harness(store); + + await harness.controller.createMarkdownFile(); + harness.controller.updateActiveText('Created after vacancy check\n'); + expect(await harness.controller.saveActiveAs(destination), isTrue); + + final snapshot = await store.load(); + final retired = snapshot.documents.singleWhere( + (document) => document.id == stale.document.id, + ); + final active = snapshot.documents.singleWhere( + (document) => !document.deleted && document.currentPath == destination, + ); + expect(retired.deleted, isTrue); + expect(active.id, isNot(retired.id)); + expect( + harness.container.read(localHistoryControllerProvider).warning?.kind, + isNot(LocalHistoryWarningKind.pathChange), + ); + }); + + test( + 'first save promotes an established untitled lineage over deleted history', + () async { + final store = MemoryLocalHistoryStore(); + final destination = p.join(root.path, 'Note.md'); + final old = await _capture(store, destination, 'Deleted revision\n'); + await store.markDeleted(destination, recursive: false); + final harness = await _harness(store); + await harness.controller.createMarkdownFile(); + harness.controller.updateActiveText('Established untitled revision\n'); + await Future.delayed(Duration.zero); + final history = harness.container.read( + localHistoryControllerProvider.notifier, + ); + expect(await history.flushBuffer(harness.state.activeBuffer!), isTrue); + final untitledId = history.documentIdForBuffer( + harness.state.activeBuffer!.id, + ); + + expect(await harness.controller.saveActiveAs(destination), isTrue); + final snapshot = await store.load(); + expect( + snapshot.documents.singleWhere((document) => !document.deleted).id, + untitledId, + ); + expect( + snapshot.documents + .singleWhere((document) => document.id == old.document.id) + .deleted, + isTrue, + ); + }, + ); + test( 'comparison uses unsaved editor source and whole restore is one undo step', () async { @@ -1789,11 +1985,13 @@ class _FailingProtectiveStore implements LocalHistoryStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) => delegate.promoteUntitledDocument( documentId: documentId, destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); @override @@ -1828,6 +2026,7 @@ class _FailingFirstPromotionStore extends _FailingProtectiveStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) { if (remainingPromotionFailures > 0) { remainingPromotionFailures--; @@ -1838,6 +2037,7 @@ class _FailingFirstPromotionStore extends _FailingProtectiveStore { destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); } } @@ -1919,8 +2119,11 @@ class _BlockingNextReparseWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { - final reparsed = await super.reparseActive(workspace, source); + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + final reparsed = await super.reparseDocument(workspace, buffer); if (!_pauseNext) return reparsed; _pauseNext = false; if (!started.isCompleted) started.complete(); @@ -2010,6 +2213,7 @@ class _BlockingPrePromotionCaptureStore extends _FailingProtectiveStore { required String destinationPath, required String displayName, required DateTime updatedAt, + LocalHistoryDocument? staleDestinationOwner, }) { promotionAttempts++; return super.promoteUntitledDocument( @@ -2017,6 +2221,7 @@ class _BlockingPrePromotionCaptureStore extends _FailingProtectiveStore { destinationPath: destinationPath, displayName: displayName, updatedAt: updatedAt, + staleDestinationOwner: staleDestinationOwner, ); } } diff --git a/test/src/markdown_parser_test.dart b/test/src/markdown_parser_test.dart index feffcfd0..96a8f62e 100644 --- a/test/src/markdown_parser_test.dart +++ b/test/src/markdown_parser_test.dart @@ -7,6 +7,7 @@ import 'package:busymark/src/markdown/busymark_document.dart'; import 'package:busymark/src/markdown/markdown_ast_adapter.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/markdown/markdown_source_map.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; @@ -15,6 +16,688 @@ void main() { String fixture(String name) => 'test/fixtures/markdown/$name'; + test('inline source mapping uses parsed formatting boundaries', () { + const marker = '\ue000'; + final codeSpans = List.filled(30, '`**`').join(' '); + final source = '**start $codeSpans left${marker}right $codeSpans end**'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: source.replaceAll(marker, ''), + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMapped(source); + + expect(context.parseInvocations, 1); + expect(mapped.inlines, hasLength(1)); + final strong = mapped.inlines.single; + expect(strong.kind, BusyInlineKind.strong); + final range = mapped.ranges[strong]; + expect(range?.start, 0); + expect(range?.end, source.length); + expect(range?.opening, '**'); + expect(range?.closing, '**'); + expect( + strong.children.where((inline) => inline.kind == BusyInlineKind.code), + hasLength(60), + ); + }); + + test('inline source mapping locates partially consumed delimiter runs', () { + BusyMarkMappedInlineRange mappedRange(String source, BusyInlineKind kind) { + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped(source); + BusyInline? result; + void visit(Iterable inlines) { + for (final inline in inlines) { + if (result == null && inline.kind == kind) result = inline; + visit(inline.children); + } + } + + visit(mapped.inlines); + expect(result, isNotNull, reason: source); + return mapped.ranges[result!]!; + } + + for (final delimiter in ['*', '_']) { + final partialOpening = + '$delimiter$delimiter${delimiter}leftright' + '$delimiter$delimiter'; + final openingRange = mappedRange(partialOpening, BusyInlineKind.strong); + expect(openingRange.start, 1, reason: partialOpening); + expect(openingRange.end, partialOpening.length, reason: partialOpening); + + final partialClosing = + '$delimiter${delimiter}leftright' + '$delimiter$delimiter$delimiter'; + final closingRange = mappedRange(partialClosing, BusyInlineKind.strong); + expect(closingRange.start, 0, reason: partialClosing); + expect( + closingRange.end, + partialClosing.length - 1, + reason: partialClosing, + ); + + final nested = + '$delimiter$delimiter${delimiter}leftright' + '$delimiter$delimiter$delimiter'; + final strongRange = mappedRange(nested, BusyInlineKind.strong); + final emphasisRange = mappedRange(nested, BusyInlineKind.emphasis); + expect(strongRange.start, 1, reason: nested); + expect(strongRange.end, nested.length - 1, reason: nested); + expect(emphasisRange.start, 0, reason: nested); + expect(emphasisRange.end, nested.length, reason: nested); + } + }); + + test('inline source mapping retains escaped collapsed references', () { + const marker = '\ue000'; + final marked = '${r'[prefix \[ left'}$marker${r'right][]'}'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: + '${r'[prefix \[ leftright][]'}\n\n' + '${r'[prefix \[ leftright]: https://destination.test'}\n', + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(context.parseInvocations, 4); + expect(mapped.inlines, hasLength(1)); + final link = mapped.inlines.single; + expect(link.kind, BusyInlineKind.link); + expect(link.destination, 'https://destination.test'); + final range = mapped.ranges[link]; + expect(range?.start, 0); + expect(range?.end, marked.length); + expect(range?.labelStart, 1); + expect(range?.labelEnd, marked.indexOf(']')); + expect(range?.isReference, isTrue); + }); + + test('inline source mapping keeps original autolink semantics', () { + const marker = '\ue000'; + const original = ''; + const marked = ''; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + + final link = mapped.inlines.single; + expect(link.kind, BusyInlineKind.link); + expect(link.plainText, 'https://example.test/left${marker}right'); + expect(link.destination, 'https://example.test/leftright'); + expect(link.attributes['href'], 'https://example.test/leftright'); + expect(mapped.ranges[link]?.isAutolink, isTrue); + expect(mapped.ranges[link]?.isReference, isFalse); + }); + + test('inline source mapping preserves supported autolink variants', () { + const cases = <({String original, String marked, String destination})>[ + ( + original: '', + marked: '', + destination: 'https://example.test/a%20b-right', + ), + ( + original: '', + marked: '', + destination: 'mailto:left@example.test', + ), + ( + original: '', + marked: '', + destination: 'https://example.test/%EE%80%80-%EE%80%80-right', + ), + ]; + for (final value in cases) { + final marker = value.marked.contains('\ue001') ? '\ue001' : '\ue000'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: value.original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMapped( + value.marked, + ignoredReferenceLabelMarkers: [marker], + ); + + final link = mapped.inlines.single; + expect(link.kind, BusyInlineKind.link, reason: value.original); + expect(link.destination, value.destination, reason: value.original); + expect( + link.attributes['href'], + value.destination, + reason: value.original, + ); + expect( + mapped.ranges[link]?.originalInline?.destination, + value.destination, + ); + expect(mapped.ranges[link]?.isAutolink, isTrue); + } + }); + + test('inline source mapping uses parser case folding for references', () { + const marker = '\ue000'; + const original = '[STRA\u1e9eE][]\n\n[STRASSE]: https://destination.test\n'; + final parsed = parser.parse( + filePath: 'case-folded.md', + source: original, + validateLocalReferences: false, + ); + expect( + parsed.busyDocument.blocks.first.inlines.single.destination, + 'https://destination.test', + ); + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMapped( + '[STRA$marker\u1e9eE][]', + ignoredReferenceLabelMarkers: const [marker], + ); + + final link = mapped.inlines.single; + expect(link.kind, BusyInlineKind.link); + expect(link.destination, 'https://destination.test'); + expect(link.attributes['href'], 'https://destination.test'); + }); + + test( + 'ordinary reference parsing retains pinned sharp-S folding behavior', + () { + for (final link in const ['[STRA\u1e9eE][]', '[STRA\u1e9eE]']) { + final parsed = parser.parse( + filePath: 'case-folded.md', + source: '$link\n\n[STRASSE]: https://destination.test\n', + validateLocalReferences: false, + ); + expect( + parsed.busyDocument.blocks.first.inlines.single.destination, + 'https://destination.test', + reason: link, + ); + } + + final unsupported = parser.parse( + filePath: 'case-folded.md', + source: '[stra\u00dfe][]\n\n[STRASSE]: https://destination.test\n', + validateLocalReferences: false, + ); + expect( + unsupported.busyDocument.blocks.first.inlines.single.kind, + BusyInlineKind.text, + ); + }, + ); + + test('invalid email-like text cannot orphan a later mapped link', () { + const marker = '\ue000'; + for (final original in const [ + 'Before and after', + 'Before and after', + 'Before and ' + ' after', + ]) { + final target = original.indexOf('leftright'); + final marked = original.replaceRange(target + 4, target + 4, marker); + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + final links = mapped.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + final selected = links.singleWhere( + (inline) => inline.plainText.contains(marker), + ); + expect( + mapped.ranges[selected]?.originalInline?.destination, + 'https://example.test/leftright', + reason: original, + ); + expect( + mapped.inlines.map((inline) => inline.plainText).join(), + marked.replaceAllMapped( + RegExp(r'<(https://example\.test/[^>]*)>'), + (match) => match[1]!, + ), + reason: original, + ); + } + }); + + test('block inline mapping projects logical content to container source', () { + const marker = '\ue000'; + const original = + '> [left\n' + '> right](https://destination.test)'; + const marked = + '> [left$marker\n' + '> right](https://destination.test)'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMappedBlock( + marked, + sourceStart: 0, + sourceEnd: marked.length, + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(mapped, isNotNull); + final link = mapped!.inlines.single; + expect(link.kind, BusyInlineKind.link); + expect(link.plainText, 'left$marker\nright'); + expect(link.plainText, isNot(contains('>'))); + final range = mapped.ranges[link]; + expect(range?.start, 2); + expect(range?.end, marked.length); + expect(range?.lineBreaks, hasLength(1)); + expect(range?.lineBreaks.single.lineEnding, '\n'); + expect(range?.lineBreaks.single.continuationPrefix, '> '); + expect(range?.lineBreaks.single.textOffset, 'left$marker'.length); + + final crlfMapped = context.parseMappedBlock( + marked.replaceAll('\n', '\r\n'), + sourceStart: 0, + sourceEnd: marked.length + 1, + ignoredReferenceLabelMarkers: const [marker], + ); + final crlfLink = crlfMapped!.inlines.single; + expect(crlfLink.plainText, 'left$marker\nright'); + expect(crlfMapped.ranges[crlfLink]?.lineBreaks.single.lineEnding, '\r\n'); + expect( + crlfMapped.ranges[crlfLink]?.lineBreaks.single.continuationPrefix, + '> ', + ); + }); + + test('positioned block mapping accepts a trailing empty logical line', () { + const source = '''> ```java +> record Document(String title, String content) {} +> ``` +'''; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parsePositionedBlocks(source); + + expect(mapped, isNotEmpty); + expect( + mapped.expand((parse) => parse.inlines).map((inline) => inline.plainText), + anyElement(contains('record Document')), + ); + }); + + test('block inline mapping ignores title and code-span source breaks', () { + const marker = '\ue000'; + const titleSource = + '> [left$marker\n' + '> middle\r\n' + '> right](https://destination.test "first\n' + '> second")'; + final titleContext = const MarkdownSourceMapper().createInlineParserContext( + documentSource: titleSource.replaceAll(marker, ''), + mode: MarkdownMode.commonMark, + ); + final titleMapped = titleContext.parseMappedBlock( + titleSource, + sourceStart: 0, + sourceEnd: titleSource.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final titleLink = titleMapped.inlines.single; + expect(titleLink.attributes['title'], 'first\nsecond'); + expect(titleMapped.ranges[titleLink]?.lineBreaks, hasLength(2)); + expect( + titleMapped.ranges[titleLink]?.lineBreaks.map( + (value) => value.lineEnding, + ), + ['\n', '\r\n'], + ); + expect( + titleMapped.ranges[titleLink]?.lineBreaks.map( + (value) => value.sourceOffset, + ), + [titleSource.indexOf('\n'), titleSource.indexOf('\r\n')], + ); + + const multipleTitleSource = + '> [left$marker\r\n' + '> right](https://destination.test "first\n' + '> second\r\n' + '> third")'; + final multipleTitleContext = const MarkdownSourceMapper() + .createInlineParserContext( + documentSource: multipleTitleSource.replaceAll(marker, ''), + mode: MarkdownMode.commonMark, + ); + final multipleTitleMapped = multipleTitleContext.parseMappedBlock( + multipleTitleSource, + sourceStart: 0, + sourceEnd: multipleTitleSource.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final multipleTitleLink = multipleTitleMapped.inlines.single; + expect(multipleTitleLink.attributes['title'], 'first\nsecond\nthird'); + expect( + multipleTitleMapped.ranges[multipleTitleLink]?.lineBreaks, + hasLength(1), + ); + expect( + multipleTitleMapped + .ranges[multipleTitleLink] + ?.lineBreaks + .single + .lineEnding, + '\r\n', + ); + + const codeSource = + '> [left `code\n' + '> span`$marker middle\r\n' + '> right](https://destination.test)'; + final codeContext = const MarkdownSourceMapper().createInlineParserContext( + documentSource: codeSource.replaceAll(marker, ''), + mode: MarkdownMode.commonMark, + ); + final codeMapped = codeContext.parseMappedBlock( + codeSource, + sourceStart: 0, + sourceEnd: codeSource.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final codeLink = codeMapped.inlines.single; + expect(codeLink.plainText, 'left code span$marker middle\nright'); + expect(codeMapped.ranges[codeLink]?.lineBreaks, hasLength(1)); + expect(codeMapped.ranges[codeLink]?.lineBreaks.single.lineEnding, '\r\n'); + }); + + test('block inline mapping keeps each hard-break occurrence range', () { + const marker = '\ue000'; + const source = + '> [left$marker \r\n' + '> middle \n' + '> right](https://destination.test)'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: source.replaceAll(marker, ''), + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMappedBlock( + source, + sourceStart: 0, + sourceEnd: source.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final link = mapped.inlines.single; + final hardBreaks = link.children + .where((inline) => inline.kind == BusyInlineKind.hardBreak) + .toList(growable: false); + final firstStart = source.indexOf(' \r\n'); + final secondStart = source.indexOf(' \n'); + + expect(hardBreaks, hasLength(2)); + expect(identical(hardBreaks.first, hardBreaks.last), isFalse); + expect(mapped.ranges[hardBreaks.first]?.start, firstStart); + expect(mapped.ranges[hardBreaks.first]?.end, firstStart + ' \r\n'.length); + expect(mapped.ranges[hardBreaks.last]?.start, secondStart); + expect(mapped.ranges[hardBreaks.last]?.end, secondStart + ' \n'.length); + expect( + mapped.ranges[link]?.lineBreaks.map( + (lineBreak) => ( + lineBreak.textOffset, + lineBreak.sourceOffset, + lineBreak.lineEnding, + lineBreak.continuationPrefix, + ), + ), + [ + ('left$marker'.length, source.indexOf('\r\n'), '\r\n', '> '), + ( + 'left$marker\nmiddle'.length, + source.indexOf('\n', source.indexOf('\r\n') + 2), + '\n', + '> ', + ), + ], + ); + }); + + test('block inline mapping matches standalone HTML break layout', () { + const marker = '\ue000'; + const original = + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + const marked = + '[A\n' + '
\n' + '
\n' + 'ri${marker}ght](https://destination.test) tail'; + final parsed = parser.parse( + filePath: 'generated-breaks.md', + source: original, + validateLocalReferences: false, + ); + final ordinaryLink = parsed.busyDocument.blocks.single.inlines.firstWhere( + (inline) => inline.kind == BusyInlineKind.link, + ); + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMappedBlock( + marked, + sourceStart: 0, + sourceEnd: marked.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final mappedLink = mapped.inlines.firstWhere( + (inline) => inline.kind == BusyInlineKind.link, + ); + final hardBreaks = mappedLink.children + .where((inline) => inline.kind == BusyInlineKind.hardBreak) + .toList(growable: false); + final firstBreak = marked.indexOf('
'); + final secondBreak = marked.indexOf('
', firstBreak + 1); + + expect(ordinaryLink.plainText, 'A\n\nright'); + expect(mappedLink.plainText.replaceAll(marker, ''), ordinaryLink.plainText); + expect(hardBreaks, hasLength(2)); + expect(mapped.ranges[hardBreaks.first]?.start, firstBreak); + expect(mapped.ranges[hardBreaks.first]?.end, firstBreak + '
'.length); + expect(mapped.ranges[hardBreaks.last]?.start, secondBreak); + expect(mapped.ranges[hardBreaks.last]?.end, secondBreak + '
'.length); + expect(mappedLink.destination, 'https://destination.test'); + expect( + mapped.ranges[mappedLink]?.originalInline?.destination, + 'https://destination.test', + ); + expect( + mapped.ranges[mappedLink]?.lineBreaks.map( + (lineBreak) => ( + lineBreak.lineEnding, + lineBreak.continuationPrefix, + lineBreak.sourceOffset, + ), + ), + [ + ('\n', '', original.indexOf('\n', firstBreak)), + ('\n', '', original.indexOf('\n', secondBreak)), + ], + ); + }); + + test( + 'block inline mapping projects HTML break layout through containers', + () { + const marker = '\ue000'; + const original = + '> [A\r\n' + '>
\r\n' + '>
\r\n' + '> right](https://destination.test) tail'; + const marked = + '> [A\r\n' + '>
\r\n' + '>
\r\n' + '> ri${marker}ght](https://destination.test) tail'; + final parsed = parser.parse( + filePath: 'generated-breaks.md', + source: original, + validateLocalReferences: false, + ); + final ordinaryLink = parsed + .busyDocument + .blocks + .single + .children + .single + .inlines + .firstWhere((inline) => inline.kind == BusyInlineKind.link); + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + + final mapped = context.parseMappedBlock( + marked, + sourceStart: 0, + sourceEnd: marked.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final mappedLink = mapped.inlines.firstWhere( + (inline) => inline.kind == BusyInlineKind.link, + ); + + expect(ordinaryLink.plainText, 'A\n\nright'); + expect( + mappedLink.plainText.replaceAll(marker, ''), + ordinaryLink.plainText, + ); + expect( + mappedLink.children.where( + (inline) => inline.kind == BusyInlineKind.hardBreak, + ), + hasLength(2), + ); + expect( + mapped.ranges[mappedLink]?.lineBreaks.map( + (lineBreak) => (lineBreak.lineEnding, lineBreak.continuationPrefix), + ), + const [('\r\n', '> '), ('\r\n', '> ')], + ); + expect( + mapped.ranges[mappedLink]?.originalInline?.destination, + 'https://destination.test', + ); + }, + ); + + test('HTML break layout mapping preserves soft breaks and literal code', () { + const marker = '\ue000'; + const original = + '> [left\n' + '> `
`\n' + '> right](https://destination.test)'; + const marked = + '> [left\n' + '> `
`\n' + '> ri${marker}ght](https://destination.test)'; + final context = const MarkdownSourceMapper().createInlineParserContext( + documentSource: original, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse('left\n`
`\nright'); + + final mapped = context.parseMappedBlock( + marked, + sourceStart: 0, + sourceEnd: marked.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final link = mapped.inlines.single; + + expect( + link.plainText.replaceAll(marker, ''), + ordinary.map((e) => e.plainText).join(), + ); + expect(link.plainText, 'left\n
\nri${marker}ght'); + expect( + link.children.where((inline) => inline.kind == BusyInlineKind.code), + hasLength(1), + ); + expect( + link.children.where((inline) => inline.kind == BusyInlineKind.hardBreak), + isEmpty, + ); + expect(mapped.ranges[link]?.lineBreaks, hasLength(2)); + expect(mapped.ranges[link]?.originalInline, isNotNull); + + const hardBreakOriginal = + '[left \n' + '
\n' + 'right](https://destination.test)'; + const hardBreakMarked = + '[left \n' + '
\n' + 'ri${marker}ght](https://destination.test)'; + final hardBreakContext = const MarkdownSourceMapper() + .createInlineParserContext( + documentSource: hardBreakOriginal, + mode: MarkdownMode.commonMark, + ); + final hardBreakMapped = hardBreakContext.parseMappedBlock( + hardBreakMarked, + sourceStart: 0, + sourceEnd: hardBreakMarked.length, + ignoredReferenceLabelMarkers: const [marker], + )!; + final hardBreakLink = hardBreakMapped.inlines.single; + expect( + hardBreakLink.children.where( + (inline) => inline.kind == BusyInlineKind.hardBreak, + ), + hasLength(2), + ); + expect( + hardBreakMapped.ranges[hardBreakLink]?.lineBreaks.map( + (lineBreak) => lineBreak.sourceOffset, + ), + [ + hardBreakOriginal.indexOf('\n'), + hardBreakOriginal.indexOf('\n', hardBreakOriginal.indexOf('
')), + ], + ); + }); + test('extracts title, outline, links, images, and code fences', () { final path = fixture('basic.md'); final parsed = parser.parse( diff --git a/test/src/markdown_serializer_metadata_test.dart b/test/src/markdown_serializer_metadata_test.dart new file mode 100644 index 00000000..b62b9aa7 --- /dev/null +++ b/test/src/markdown_serializer_metadata_test.dart @@ -0,0 +1,269 @@ +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/busymark_markdown_serializer.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + const serializer = BusyMarkMarkdownSerializer(); + + test('descendant whitespace preservation prevents ancestor trimming', () { + const preserved = {busyMarkPreserveTextWhitespaceAttribute: 'true'}; + const whitespace = BusyBlock( + id: 'whitespace', + kind: BusyBlockKind.paragraph, + inlines: [BusyInline(kind: BusyInlineKind.text, text: ' ')], + attributes: preserved, + dirty: true, + ); + const document = BusyDocument( + filePath: 'topic.md', + mode: MarkdownMode.commonMark, + blocks: [ + BusyBlock( + id: 'list', + kind: BusyBlockKind.unorderedListItem, + inlines: [BusyInline(kind: BusyInlineKind.text, text: 'Parent')], + children: [whitespace], + dirty: true, + ), + BusyBlock( + id: 'quote', + kind: BusyBlockKind.blockquote, + children: [ + BusyBlock( + id: 'quote-text', + kind: BusyBlockKind.paragraph, + inlines: [BusyInline(kind: BusyInlineKind.text, text: 'Quoted')], + dirty: true, + ), + whitespace, + ], + dirty: true, + ), + ], + ); + + final source = serializer.serialize(document); + + expect(source, contains('- Parent\n\n ')); + expect(source, contains('> Quoted\n>\n> ')); + expect(source, endsWith('> \n')); + expect(source, isNot(contains(busyMarkPreserveTextWhitespaceAttribute))); + }); + + test('ordinary and metadata inline emission are byte-identical', () { + final fixtures = + < + ({ + List inlines, + bool tableCell, + bool atBlockStart, + bool readableBreaks, + }) + >[ + ( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: 'plain'), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: '!'), + BusyInline( + kind: BusyInlineKind.link, + text: 'link', + destination: 'https://example.test', + attributes: {'title': 'A title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: 'link')], + ), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline( + kind: BusyInlineKind.strong, + text: 'bold and italic', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'bold '), + BusyInline( + kind: BusyInlineKind.emphasis, + text: 'and italic', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'and italic'), + ], + ), + ], + ), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: 'left'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'right'), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline( + kind: BusyInlineKind.underline, + text: 'left\nright', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'left'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'right'), + ], + ), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: 'a|b'), + BusyInline(kind: BusyInlineKind.code, text: 'c|d'), + ], + tableCell: true, + atBlockStart: false, + readableBreaks: false, + ), + ( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: '# literal heading'), + ], + tableCell: false, + atBlockStart: true, + readableBreaks: true, + ), + ( + inlines: const [ + BusyInline( + kind: BusyInlineKind.image, + text: 'alt', + destination: 'image.png', + ), + BusyInline(kind: BusyInlineKind.math, text: r'x + y'), + BusyInline(kind: BusyInlineKind.writersideVariable, text: 'name'), + ], + tableCell: false, + atBlockStart: false, + readableBreaks: true, + ), + ]; + + for (final fixture in fixtures) { + final ordinary = serializer.serializeInlineFragment( + fixture.inlines, + tableCell: fixture.tableCell, + atBlockStart: fixture.atBlockStart, + readableHardBreakRuns: fixture.readableBreaks, + ); + final textLength = fixture.inlines.fold( + 0, + (length, inline) => length + inline.plainText.length, + ); + final metadata = serializer.serializeInlineFragmentWithOffsets( + fixture.inlines, + textOffset: textLength ~/ 2, + tableCell: fixture.tableCell, + atBlockStart: fixture.atBlockStart, + readableHardBreakRuns: fixture.readableBreaks, + ); + + expect(metadata.source, ordinary, reason: fixture.toString()); + expect(metadata.sourceOffset, inInclusiveRange(0, ordinary.length)); + } + }); + + test('grouped breaks retain distinct source provenance in one traversal', () { + const first = BusyMarkInlineLineBreakOffset(textOffset: 1); + const second = BusyMarkInlineLineBreakOffset(textOffset: 2); + var traversals = 0; + var visitedNodes = 0; + debugBusyMarkInlineSerializationTraversal = (_) => traversals += 1; + debugBusyMarkInlineSerializationVisitedNodes = (value) { + visitedNodes = value; + }; + addTearDown(() { + debugBusyMarkInlineSerializationTraversal = null; + debugBusyMarkInlineSerializationVisitedNodes = null; + }); + + final result = serializer.serializeInlineFragmentWithOffsets( + const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + textOffset: 2, + lineBreakOffsets: const [first, second], + readableHardBreakRuns: true, + ); + + expect(traversals, 1); + expect(visitedNodes, 4); + expect(result.lineBreakSourceOffsets.keys, containsAll([first, second])); + expect( + result.lineBreakSourceOffsets[first], + isNot(result.lineBreakSourceOffsets[second]), + ); + expect(result.source, 'A\n
\n
\nB'); + }); + + test('text-leaf atoms use interior spans and exclude delimiters', () { + final result = serializer.serializeInlineFragmentWithOffsets(const [ + BusyInline( + kind: BusyInlineKind.strong, + text: 'mispel', + children: [BusyInline(kind: BusyInlineKind.text, text: 'mispel')], + ), + BusyInline(kind: BusyInlineKind.text, text: 'led'), + ], textOffset: 4); + + expect(result.source, '**mispel**led'); + expect(result.textAtoms.map((atom) => atom.text).join(), 'mispelled'); + expect( + [ + for (final atom in result.textAtoms) + result.source.substring(atom.sourceStart, atom.sourceEnd), + ].join(), + 'mispelled', + ); + expect(result.textAtoms.first.inlinePath, [0, 0]); + expect(result.textAtoms.last.inlinePath, [1]); + }); + + test('table escaping translates leaf spans without changing source', () { + const inlines = [BusyInline(kind: BusyInlineKind.text, text: 'a|b')]; + final ordinary = serializer.serializeInlineFragment( + inlines, + tableCell: true, + ); + final result = serializer.serializeInlineFragmentWithOffsets( + inlines, + textOffset: 2, + tableCell: true, + ); + + expect(result.source, ordinary); + expect(result.source, r'a\|b'); + final pipe = result.textAtoms.singleWhere((atom) => atom.text == '|'); + expect(result.source.substring(pipe.sourceStart, pipe.sourceEnd), r'\|'); + expect(pipe.escaped, isTrue); + }); +} diff --git a/test/src/markdown_source_map_test.dart b/test/src/markdown_source_map_test.dart new file mode 100644 index 00000000..c68adb52 --- /dev/null +++ b/test/src/markdown_source_map_test.dart @@ -0,0 +1,623 @@ +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_ast_adapter.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_source_map.dart'; +import 'package:busymark/src/markdown/raw_html_adapter.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:markdown/markdown.dart' as md; + +void main() { + const mapper = MarkdownSourceMapper(); + + test('annotated parsing has ordinary semantics across supported corpus', () { + const fixtures = [ + 'plain text and whitespace', + r'escaped \*literal\* and [balanced [label]](https://example.test)', + '***strong emphasis*** and ~~strike~~', + r'`**not strong**
` and ``a ` b``', + '![alt](image.png "title")', + '[full][ref] [collapsed][] [shortcut]\n\n' + '[ref]: https://one.test "One"\n' + '[collapsed]: https://two.test\n' + '[shortcut]: https://three.test', + ' ', + ' and ', + 'left
right
', + 'bold nested', + '
linked', + 'left
right
', + 'left
\nright
', + 'left\nright', + ' visible', + 'left \nright', + 'left\n
\n
\nright', + r'inline $x + y$ and %Writerside_Variable%', + 'Straße STRAẞE 😀 supplementary', + ]; + + for (final fixture in fixtures) { + final context = mapper.createInlineParserContext( + documentSource: fixture, + mode: MarkdownMode.writersideMarkdown, + ); + final ordinary = context.parse(fixture); + final mapped = context.parseMapped(fixture); + expect( + _semanticTree(mapped.inlines), + _semanticTree(ordinary), + reason: fixture, + ); + } + }); + + test('position records do not change HTML or link semantics', () { + const marker = '\ue001'; + const source = + '[left
right
]' + '(https://destination.test "Original title") tail'; + final positions = [ + source.indexOf('
'), + source.indexOf('
') + '
'.length, + source.indexOf(''), + source.indexOf('right') + 2, + ]; + final ordinaryContext = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final ordinary = ordinaryContext.parse(source); + + for (final position in positions) { + final marked = source.replaceRange(position, position, marker); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + expect( + mapped.positionRecordsComplete, + isTrue, + reason: 'supported HTML boundary $position in $marked', + ); + expect( + _leafMarkerOccurrences(mapped.inlines, marker), + 1, + reason: 'supported HTML boundary $position in $marked', + ); + expect( + _semanticTree(mapped.inlines, ignoredMarkers: const [marker]), + _semanticTree(ordinary), + reason: 'position $position in $marked', + ); + } + }); + + test('selection endpoints crossing HTML retain one semantic fragment', () { + const startMarker = '\ue001'; + const endMarker = '\ue002'; + const source = 'left
right
tail'; + final marked = source + .replaceRange( + source.indexOf('right') + 2, + source.indexOf('right') + 2, + endMarker, + ) + .replaceRange( + source.indexOf('left') + 2, + source.indexOf('left') + 2, + startMarker, + ); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse(source); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [startMarker, endMarker], + ); + + expect(mapped.positionRecordsComplete, isTrue); + expect(_leafMarkerOccurrences(mapped.inlines, startMarker), 1); + expect(_leafMarkerOccurrences(mapped.inlines, endMarker), 1); + expect( + _semanticTree( + mapped.inlines, + ignoredMarkers: const [startMarker, endMarker], + ), + _semanticTree(ordinary), + ); + final underline = mapped.inlines.singleWhere( + (inline) => inline.kind == BusyInlineKind.underline, + ); + expect( + underline.children.where( + (inline) => inline.kind == BusyInlineKind.hardBreak, + ), + hasLength(1), + ); + }); + + test( + 'supported HTML whitespace positions have complete position records', + () { + const marker = '\ue001'; + final fixtures = + <({String source, int position, String expectedMarkedText})>[ + ( + source: + '[left right]' + '(https://destination.test) tail', + position: '[left'.length, + expectedMarkedText: 'left$marker right', + ), + ( + source: + '[left right]' + '(https://destination.test) tail', + position: '[left '.length, + expectedMarkedText: + 'left $marker' + 'right', + ), + ( + source: + '[left right]' + '(https://destination.test) tail', + position: '[left '.length, + expectedMarkedText: + 'left $marker' + 'right', + ), + ( + source: + '[left \t right]' + '(https://destination.test) tail', + position: '[left \t'.length, + expectedMarkedText: + 'left $marker' + 'right', + ), + ( + source: + '[left \r\n\t right]' + '(https://destination.test) tail', + position: '[left \r\n'.length, + expectedMarkedText: + 'left $marker' + 'right', + ), + ]; + + for (final fixture in fixtures) { + final marked = fixture.source.replaceRange( + fixture.position, + fixture.position, + marker, + ); + final context = mapper.createInlineParserContext( + documentSource: fixture.source, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse(fixture.source); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(mapped.positionRecordsComplete, isTrue, reason: fixture.source); + expect( + _semanticTree(mapped.inlines, ignoredMarkers: const [marker]), + _semanticTree(ordinary), + reason: fixture.source, + ); + final underline = _allInlines( + mapped.inlines, + ).singleWhere((inline) => inline.kind == BusyInlineKind.underline); + expect(underline.plainText, fixture.expectedMarkedText); + expect( + _allInlines( + mapped.inlines, + ).where((inline) => inline.plainText.contains(marker)), + isNotEmpty, + ); + } + }, + ); + + test('only operation-local markers are ignored', () { + const authored = '\ue000'; + const marker = '\ue001'; + const source = 'authored $authored [label](https://example.test/%EE%80%80)'; + final position = source.indexOf('label') + 2; + final marked = source.replaceRange(position, position, marker); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(mapped.inlines.first.plainText, contains(authored)); + final link = mapped.inlines.singleWhere( + (inline) => inline.kind == BusyInlineKind.link, + ); + expect(link.destination, 'https://example.test/%EE%80%80'); + expect(mapped.positionRecordsComplete, isTrue); + }); + + test('delimiter-only positions are explicitly incomplete', () { + const marker = '\ue001'; + const source = '**left**'; + const position = 1; // Inside the opening delimiter, not text content. + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse(source); + final mapped = context.parseMapped( + source.replaceRange(position, position, marker), + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(mapped.positionRecordsComplete, isFalse); + expect(_semanticTree(mapped.inlines), _semanticTree(ordinary)); + }); + + test('syntax-boundary probes retain the ordinary semantic oracle', () { + // Completeness is deliberately not qualified here: this corpus includes + // both content boundaries and positions inside delimiters, destinations, + // and titles. Dedicated tests above classify those categories and require + // complete records for supported content. + const marker = '\ue001'; + final fixtures = <({String source, List positions})>[ + (source: '**left**', positions: const [0, 1, 2, 4, 6, 7, 8]), + (source: r'\*left\*', positions: const [0, 1, 2, 5, 6, 7, 8]), + (source: '`left`', positions: const [0, 1, 3, 5, 6, 7]), + ( + source: '[left](https://destination.test "Title")', + positions: const [0, 1, 5, 6, 7, 15, 33, 35, 40, 41], + ), + ( + source: '[left][ref]\n\n[ref]: https://destination.test "Title"', + positions: const [0, 1, 5, 6, 7, 10, 11], + ), + ( + source: '', + positions: const [0, 1, 10, 30, 31], + ), + ]; + var cases = 0; + for (final fixture in fixtures) { + final ordinaryContext = mapper.createInlineParserContext( + documentSource: fixture.source, + mode: MarkdownMode.commonMark, + ); + final ordinary = ordinaryContext.parse(fixture.source); + for (final position in fixture.positions) { + if (position > fixture.source.length) continue; + cases += 1; + final marked = fixture.source.replaceRange(position, position, marker); + final context = mapper.createInlineParserContext( + documentSource: fixture.source, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + expect( + _semanticTree(mapped.inlines, ignoredMarkers: const [marker]), + _semanticTree(ordinary), + reason: '${fixture.source} at $position', + ); + } + } + expect(cases, 40); + }); + + test('deterministic inline combinations preserve annotated semantics', () { + const marker = '\ue001'; + final contents = <({String value, int position})>[ + (value: 'plain', position: 2), + (value: 'white space', position: 5), + (value: 'white space', position: 'white '.length), + (value: 'Straße', position: 4), + (value: '😀 value', position: 5), + (value: r'escaped \* value', position: r'escaped \* val'.length), + (value: 'entity & value', position: 'entity & val'.length), + ]; + final wrappers = [ + (value) => value, + (value) => '**$value**', + (value) => '*$value*', + (value) => '~~$value~~', + (value) => '[$value](https://destination.test "Title")', + (value) => '$value', + (value) => '$value', + (value) => '$value', + (value) => '$value', + (value) => '$value
tail
', + ]; + var cases = 0; + for (final wrap in wrappers) { + for (final content in contents) { + cases += 1; + final source = wrap(content.value); + final contentStart = source.indexOf(content.value); + final position = contentStart + content.position; + final marked = source.replaceRange(position, position, marker); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.writersideMarkdown, + ); + final ordinary = context.parse(source); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + expect( + mapped.positionRecordsComplete, + isTrue, + reason: 'case $cases: $source at $position', + ); + expect( + _leafMarkerOccurrences(mapped.inlines, marker), + 1, + reason: 'case $cases: $source at $position', + ); + expect( + _semanticTree(mapped.inlines, ignoredMarkers: const [marker]), + _semanticTree(ordinary), + reason: 'case $cases: $source', + ); + } + } + expect(cases, 70); + }); + + test('standalone HTML break ownership uses one indexed lookup per break', () { + addTearDown(() => debugBusyMarkStandaloneBreakLayoutLookups = null); + for (final count in [10, 100, 1000]) { + var lookups = 0; + debugBusyMarkStandaloneBreakLayoutLookups = (value) => lookups += value; + final source = '${List.filled(count, 'x
\n').join()}z
'; + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final mapped = context.parseMapped(source); + + expect(context.parseInvocations, 1, reason: '$count breaks'); + expect(lookups, count, reason: '$count breaks'); + expect(_countKind(mapped.inlines, BusyInlineKind.hardBreak), count); + } + }); + + test('AST source boundary lookahead is linear and maps the final link', () { + addTearDown(() { + debugBusyMarkSourceMappingBoundaryInspections = null; + debugBusyMarkSourceMappingFallbackSearchCalls = null; + debugBusyMarkSourceMappingFallbackSearchRanges = null; + }); + const marker = '\ue001'; + const segment = r'**x** \[ '; + for (final count in [10, 100, 1000]) { + final prefix = List.filled(count, segment).join(); + final source = '$prefix[leftright](https://destination.test)'; + final position = source.indexOf('leftright') + 4; + final marked = source.replaceRange(position, position, marker); + var inspections = 0; + var fallbackCalls = 0; + final fallbackRanges = <({int start, int end})>[]; + debugBusyMarkSourceMappingBoundaryInspections = (value) => + inspections += value; + debugBusyMarkSourceMappingFallbackSearchCalls = () => fallbackCalls += 1; + debugBusyMarkSourceMappingFallbackSearchRanges = (start, end) => + fallbackRanges.add((start: start, end: end)); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse(source); + final mapped = context.parseMapped( + marked, + ignoredReferenceLabelMarkers: const [marker], + ); + + expect(mapped.positionRecordsComplete, isTrue, reason: '$count spans'); + expect( + _semanticTree(mapped.inlines, ignoredMarkers: const [marker]), + _semanticTree(ordinary), + ); + final link = _allInlines( + mapped.inlines, + ).singleWhere((inline) => inline.kind == BusyInlineKind.link); + expect(link.destination, 'https://destination.test'); + expect(link.plainText, 'left${marker}right'); + final range = mapped.ranges[link]; + expect(range, isNotNull); + expect(range!.start, source.indexOf('[leftright]')); + expect(range.end, marked.length); + expect(fallbackCalls, 0, reason: '$count spans'); + expect(fallbackRanges, isEmpty, reason: '$count spans'); + expect( + inspections, + lessThanOrEqualTo(count * 6 + 30), + reason: '$count spans inspected $inspections boundaries', + ); + } + }); + + test( + 'fallback mapping is bounded for entities repetitions and code spans', + () { + addTearDown(() { + debugBusyMarkSourceMappingBoundaryInspections = null; + debugBusyMarkSourceMappingFallbackSearchCalls = null; + debugBusyMarkSourceMappingFallbackSearchRanges = null; + }); + const source = 'A & B same same `same` tail'; + final nodes = [ + md.Text('A & B same same '), + md.Element.text('code', 'same'), + md.Text(' tail'), + ]; + var inspections = 0; + var fallbackCalls = 0; + final ranges = <({int start, int end})>[]; + debugBusyMarkSourceMappingBoundaryInspections = (value) => + inspections += value; + debugBusyMarkSourceMappingFallbackSearchCalls = () => fallbackCalls += 1; + debugBusyMarkSourceMappingFallbackSearchRanges = (start, end) => + ranges.add((start: start, end: end)); + final mappedRanges = {}; + + final inlines = const MarkdownAstAdapter().convertInlineNodes( + nodes, + sourceMappings: mappedRanges, + mappingSource: source, + mappingStart: 0, + mappingEnd: source.length, + ); + + expect( + inlines.map((inline) => inline.plainText).join(), + 'A & B same same same tail', + ); + expect( + _allInlines(inlines) + .where((inline) => inline.kind == BusyInlineKind.code) + .single + .plainText, + 'same', + ); + expect(inspections, 4, reason: 'three siblings plus the code child'); + expect(fallbackCalls, greaterThan(0)); + expect(ranges, hasLength(fallbackCalls)); + for (final range in ranges) { + expect(range.start, inInclusiveRange(0, source.length)); + expect(range.end, inInclusiveRange(range.start, source.length)); + } + }, + ); + + test('tag-looking attribute text does not claim break layout', () { + const source = 'left
\nright
'; + var lookups = 0; + debugBusyMarkStandaloneBreakLayoutLookups = (value) => lookups += value; + addTearDown(() => debugBusyMarkStandaloneBreakLayoutLookups = null); + final context = mapper.createInlineParserContext( + documentSource: source, + mode: MarkdownMode.commonMark, + ); + final ordinary = context.parse(source); + final mapped = context.parseMapped(source); + + expect(_semanticTree(mapped.inlines), _semanticTree(ordinary)); + expect(lookups, 1); + expect(_countKind(mapped.inlines, BusyInlineKind.hardBreak), 1); + }); +} + +Object _semanticTree( + List inlines, { + List ignoredMarkers = const [], +}) { + String clean(String value) { + var result = value; + for (final marker in ignoredMarkers) { + result = result.replaceAll(marker, ''); + } + return result; + } + + List siblings(List values) { + final result = []; + String? pendingText; + Map? pendingAttributes; + void flushText() { + if (pendingText == null) return; + result.add({ + 'kind': BusyInlineKind.text.name, + 'text': pendingText, + 'attributes': pendingAttributes, + 'children': const [], + }); + pendingText = null; + pendingAttributes = null; + } + + for (final inline in values) { + final attributes = Map.fromEntries( + inline.attributes.entries.toList() + ..sort((left, right) => left.key.compareTo(right.key)), + ); + if (inline.kind == BusyInlineKind.text && inline.children.isEmpty) { + final text = clean(inline.text); + if (text.isEmpty) continue; + if (pendingText != null && _mapEquals(pendingAttributes!, attributes)) { + pendingText = '$pendingText$text'; + } else { + flushText(); + pendingText = text; + pendingAttributes = attributes; + } + continue; + } + flushText(); + result.add({ + 'kind': inline.kind.name, + 'text': clean(inline.text), + 'destination': inline.destination, + 'attributes': attributes, + 'children': siblings(inline.children), + }); + } + flushText(); + return result; + } + + return siblings(inlines); +} + +bool _mapEquals(Map left, Map right) { + if (left.length != right.length) return false; + return left.entries.every((entry) => right[entry.key] == entry.value); +} + +int _countKind(List inlines, BusyInlineKind kind) { + var count = 0; + for (final inline in inlines) { + if (inline.kind == kind) count += 1; + count += _countKind(inline.children, kind); + } + return count; +} + +List _allInlines(List inlines) { + return [ + for (final inline in inlines) ...[inline, ..._allInlines(inline.children)], + ]; +} + +int _leafMarkerOccurrences(List inlines, String marker) { + var count = 0; + for (final inline in inlines) { + if (inline.children.isEmpty) { + var offset = 0; + while ((offset = inline.text.indexOf(marker, offset)) >= 0) { + count += 1; + offset += marker.length; + } + } else { + count += _leafMarkerOccurrences(inline.children, marker); + } + } + return count; +} diff --git a/test/src/markdown_source_structure_test.dart b/test/src/markdown_source_structure_test.dart new file mode 100644 index 00000000..1a2cb709 --- /dev/null +++ b/test/src/markdown_source_structure_test.dart @@ -0,0 +1,88 @@ +import 'package:busymark/src/markdown/markdown_source_structure.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('source line bounds treat offsets as insertion positions', () { + void expectBounds(String source, int offset, int start, int end) { + final bounds = busyMarkSourceLineBounds(source, offset); + expect( + (bounds.start, bounds.end), + (start, end), + reason: '$offset:$source', + ); + } + + expectBounds('', 0, 0, 0); + expectBounds('\nright', 0, 0, 0); + expectBounds('\nright', 1, 1, 6); + expectBounds('left\nright', 4, 0, 4); + expectBounds('left\nright', 5, 5, 10); + expectBounds('right', 5, 0, 5); + expectBounds('right\n', 6, 6, 6); + expectBounds('\r\nright', 0, 0, 1); + expectBounds('\r\nright', 2, 2, 7); + }); + + test('table cell spans respect meaningful outer pipes and escaping', () { + List cells(String row) => [ + for (final span in busyMarkMarkdownTableCellSpans(row)) + row.substring(span.start, span.end), + ]; + + expect(cells(' | cell |'), ['cell']); + expect(cells(' \t | cell | '), ['cell']); + expect(cells('| | value |'), ['', 'value']); + expect(cells('||'), ['']); + expect(cells(r'| left\|right | next |'), [r'left\|right', 'next']); + }); + + test('escaped terminal pipes remain in the final cell source span', () { + void expectSpans( + String row, + List<({int start, int end, String text})> expected, + ) { + final spans = busyMarkMarkdownTableCellSpans(row); + expect( + [ + for (final span in spans) + ( + start: span.start, + end: span.end, + text: row.substring(span.start, span.end), + ), + ], + expected, + reason: row, + ); + } + + expectSpans(r'A | B\|', [ + (start: 0, end: 1, text: 'A'), + (start: 4, end: 7, text: r'B\|'), + ]); + expectSpans(r'| B\|', [(start: 2, end: 5, text: r'B\|')]); + expectSpans(r'| B\| ', [(start: 2, end: 5, text: r'B\|')]); + expectSpans(r'| B\| |', [(start: 2, end: 5, text: r'B\|')]); + expectSpans(r' | B\|', [(start: 4, end: 7, text: r'B\|')]); + + // Odd backslash runs escape the pipe. Even runs leave it as a delimiter. + expectSpans(r'A | B\\\|', [ + (start: 0, end: 1, text: 'A'), + (start: 4, end: 9, text: r'B\\\|'), + ]); + expectSpans(r'A | B\\|', [ + (start: 0, end: 1, text: 'A'), + (start: 4, end: 7, text: r'B\\'), + ]); + + expectSpans('| A | B |', [ + (start: 2, end: 3, text: 'A'), + (start: 6, end: 7, text: 'B'), + ]); + expectSpans('A | B', [ + (start: 0, end: 1, text: 'A'), + (start: 4, end: 5, text: 'B'), + ]); + expectSpans('| |', [(start: 2, end: 2, text: '')]); + }); +} diff --git a/test/src/native_headerbar_audit_test.dart b/test/src/native_headerbar_audit_test.dart index bcbe1488..70170b9f 100644 --- a/test/src/native_headerbar_audit_test.dart +++ b/test/src/native_headerbar_audit_test.dart @@ -1557,6 +1557,7 @@ void main() { 'lib/src/platform/native_menu_service.dart', ).readAsStringSync(); final design = File('lib/src/app/busymark_design.dart').readAsStringSync(); + final probe = File('tools/linux_native_menu_probe.py').readAsStringSync(); final toolbar = File( 'lib/src/editor/wysiwyg/wysiwyg_toolbar.dart', ).readAsStringSync(); @@ -1582,7 +1583,14 @@ void main() { expect(nativeMenu, contains('GMenu* model;')); expect(nativeMenu, contains('GSimpleActionGroup* action_group;')); expect(nativeMenu, contains('g_simple_action_new_stateful(')); - expect(nativeMenu, contains('g_menu_item_set_action_and_target_value(')); + expect(nativeMenu, contains('g_variant_new_boolean(selected)')); + expect(nativeMenu, isNot(contains('G_VARIANT_TYPE_STRING'))); + expect(nativeMenu, isNot(contains('g_variant_new_string('))); + expect( + nativeMenu, + isNot(contains('g_menu_item_set_action_and_target_value(')), + ); + expect(nativeMenu, isNot(contains('select-group-'))); expect(nativeMenu, isNot(contains('GTK_IS_MODEL_BUTTON'))); expect(nativeMenu, isNot(contains('style_native_menu_item'))); expect(nativeMenu, isNot(contains('gtk_menu_button_'))); @@ -1606,7 +1614,8 @@ void main() { expect(nativeMenu, contains('set_menu_item_accelerator(')); expect(nativeMenu, contains('g_menu_item_set_icon(item, icon)')); expect(nativeMenu, contains('native_menu_action_activated_cb')); - expect(nativeMenu, contains('native_menu_selection_activated_cb')); + expect(nativeMenu, contains('native_menu_check_activated_cb')); + expect(nativeMenu, isNot(contains('native_menu_selection_activated_cb'))); expect(nativeMenu, contains('gtk_menu_new_from_model(')); expect(nativeMenu, contains('GTK_IS_MENU(session->menu)')); expect(nativeMenu, contains('gtk_menu_attach_to_widget(')); @@ -1640,6 +1649,8 @@ void main() { expect(service, contains("'iconColor': iconColorArgb!")); expect(service, contains("'shortcut': shortcut!")); expect(service, contains('this.checkable = false')); + expect(service, contains('this.mutuallyExclusive = false')); + expect(service, contains("'mutuallyExclusive': mutuallyExclusive")); expect(service, contains('separator = false')); expect(design, contains('NativeMenuEntry.separator()')); expect(design, contains('NativeMenuEntry.command(')); @@ -1654,6 +1665,11 @@ void main() { expect(nativeMenu, contains('gtk_icon_info_load_symbolic(')); expect(design, contains('shortcut: item.shortcut')); expect(design, contains('checkable: item.trailingCheck')); + expect(design, contains('mutuallyExclusive: item.mutuallyExclusive')); + expect(probe, contains('command == "assert-check"')); + expect(probe, contains('Atspi.Role.CHECK_MENU_ITEM')); + expect(probe, contains('Atspi.Role.RADIO_MENU_ITEM')); + expect(probe, contains('Atspi.StateType.CHECKED')); expect(design, contains('class BusyMarkMenuButton')); expect(design, isNot(contains('YaruPopupMenuButton('))); for (final shortcut in [ @@ -1852,7 +1868,6 @@ void main() { expect(welcome, contains('HeaderBarConfigurationPublisher(')); expect(welcome, contains('title: context.l10n.appTitle')); expect(settings, contains('HeaderBarConfigurationPublisher(')); - expect(settings, contains('final title = _settingsPageLabel(')); expect(settings, contains('title: title')); expect( workspace, diff --git a/test/src/native_menu_service_test.dart b/test/src/native_menu_service_test.dart index 932c9cb7..082cf21e 100644 --- a/test/src/native_menu_service_test.dart +++ b/test/src/native_menu_service_test.dart @@ -32,9 +32,15 @@ void main() { shortcut: 'Ctrl+O', checkable: true, selected: true, + mutuallyExclusive: true, ), NativeMenuEntry.separator(), NativeMenuEntry.command(label: 'Disabled', enabled: false), + NativeMenuEntry.command( + label: 'Full Screen', + checkable: true, + selected: true, + ), ], focusFirst: true, preferAbove: true, @@ -55,6 +61,7 @@ void main() { 'enabled': true, 'checkable': true, 'selected': true, + 'mutuallyExclusive': true, 'separator': false, }, { @@ -62,6 +69,7 @@ void main() { 'enabled': false, 'checkable': false, 'selected': false, + 'mutuallyExclusive': false, 'separator': true, }, { @@ -69,6 +77,15 @@ void main() { 'enabled': false, 'checkable': false, 'selected': false, + 'mutuallyExclusive': false, + 'separator': false, + }, + { + 'label': 'Full Screen', + 'enabled': true, + 'checkable': true, + 'selected': true, + 'mutuallyExclusive': false, 'separator': false, }, ], diff --git a/test/src/source_audit_test.dart b/test/src/source_audit_test.dart index 14b90fe2..f600db56 100644 --- a/test/src/source_audit_test.dart +++ b/test/src/source_audit_test.dart @@ -280,37 +280,6 @@ void main() { expect(createTopicDialog, contains('InputDecoration(')); }); - test('shared row hover delegates to Yaru interaction state', () { - final design = File('lib/src/app/busymark_design.dart').readAsStringSync(); - - final helper = RegExp( - r'Color busyMarkRowHoverColor\(BuildContext context\) \{(.*?)\n\}', - dotAll: true, - ).firstMatch(design)!.group(1)!; - expect(helper, contains('final hover = theme.hoverColor')); - expect(helper, contains('BusyMarkAlpha.groupedRowLightHoverStrength')); - expect(helper, isNot(contains('colors.foreground.withValues'))); - expect(design, isNot(contains('class _BusyMarkHoverBackground'))); - final actionRow = RegExp( - r'class BusyMarkActionRow[\s\S]*?class BusyMarkSwitchRow', - ).firstMatch(design)!.group(0)!; - expect(actionRow, contains('final row = YaruListTile.square(')); - expect(actionRow, isNot(contains('MouseRegion('))); - expect( - actionRow, - contains( - 'hoverColor: widget.hoverColor ?? busyMarkRowHoverColor(context)', - ), - ); - final switchRow = RegExp( - r'class BusyMarkSwitchRow[\s\S]*?class BusyMarkDialogShell', - ).firstMatch(design)!.group(0)!; - expect(switchRow, contains('return YaruSwitchListTile(')); - expect(switchRow, isNot(contains('MouseRegion('))); - expect(switchRow, contains('hoverColor: busyMarkRowHoverColor(context)')); - expect(switchRow, contains('shape: const RoundedRectangleBorder()')); - }); - test('shared grouped surfaces use native card shadow layers', () { final design = File('lib/src/app/busymark_design.dart').readAsStringSync(); final dialogs = File( diff --git a/test/src/source_editor_widget_test.dart b/test/src/source_editor_widget_test.dart index c70e96ab..257ec960 100644 --- a/test/src/source_editor_widget_test.dart +++ b/test/src/source_editor_widget_test.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:math' as math; import 'dart:ui' show BoxHeightStyle; import 'package:busymark/l10n/generated/app_localizations.dart'; @@ -10,11 +11,16 @@ import 'package:busymark/src/ai/ai_models.dart'; import 'package:busymark/src/app/app_theme.dart'; import 'package:busymark/src/app/busymark_design.dart'; import 'package:busymark/src/assets/asset_ingestion_service.dart'; +import 'package:busymark/src/assets/asset_input_service.dart'; import 'package:busymark/src/clipboard/clipboard_insertion.dart'; import 'package:busymark/src/clipboard/clipboard_models.dart'; import 'package:busymark/src/core/diagnostic.dart'; import 'package:busymark/src/core/source_span.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/busymark_markdown_serializer.dart'; +import 'package:busymark/src/markdown/markdown_ast_adapter.dart'; import 'package:busymark/src/editor/document_text_geometry.dart'; +import 'package:busymark/src/editor/editor_text_context_menu.dart'; import 'package:busymark/src/editor/source_highlighter.dart' show BusyMarkSourceEditingController; import 'package:busymark/src/editor/source/source_editor.dart'; @@ -31,15 +37,76 @@ import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/platform/native_menu_service.dart'; import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:busymark/src/spellcheck/spelling_coordinator.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/writerside/writerside_project.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:markdown/markdown.dart' as md; import 'package:yaru/yaru.dart'; void main() { + testWidgets('Source pastes a web layout table as a complete document', ( + tester, + ) async { + final clipboard = _SourceTestClipboard( + readData: RichClipboardData( + html: File( + 'test/fixtures/clipboard/layout_table_job.html', + ).readAsStringSync(), + text: 'Plain job description', + generation: 1, + ), + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'Target\n', + clipboard: clipboard, + markdownMode: MarkdownMode.gfm, + ); + controller.selection = const TextSelection(baseOffset: 0, extentOffset: 6); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pumpAndSettle(); + final document = const MarkdownParser() + .parse( + filePath: '/pasted.md', + source: controller.text, + mode: MarkdownMode.gfm, + ) + .busyDocument; + expect(document.blocks.first.kind, BusyBlockKind.heading); + expect( + document.blocks.where((block) => block.kind == BusyBlockKind.table), + hasLength(1), + ); + expect( + document.blocks.where( + (block) => block.kind == BusyBlockKind.unorderedListItem, + ), + hasLength(3), + ); + expect( + document.blocks.last.plainText, + 'Send questions to team@example.test.', + ); + expect( + controller.text, + contains('Closing invitation with [application details]'), + ); + controller.selection = TextSelection( + baseOffset: 0, + extentOffset: controller.text.length, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV, shift: true); + await tester.pumpAndSettle(); + expect(controller.text, 'Plain job description'); + }); + for (final lookupFinished in [false, true]) { for (final findNext in [false, true]) { testWidgets( @@ -288,6 +355,303 @@ void main() { await tester.pump(const Duration(seconds: 1)); }); + testWidgets('spelling review caret uses full offsets after an earlier fold', ( + tester, + ) async { + const source = '# First\nhidden text\n# Second\nmistakke\n'; + const path = '/project/folded-spelling.md'; + final firstRegion = sourceFoldRegions( + source, + SourceSyntaxLanguage.markdown, + ).first; + final target = source.indexOf('mistakke'); + final key = GlobalKey(); + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: BusyMarkSourceEditor( + key: key, + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: path, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + initialSelection: TextSelection.collapsed(offset: target), + initialFoldedRegionKeys: {firstRegion.key}, + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + ), + ), + ), + ); + await tester.pump(); + final controller = tester + .widgetList(find.byType(TextField)) + .map((field) => field.controller) + .whereType() + .single; + + expect(controller.selection.extentOffset, lessThan(target)); + expect(controller.fullSelection.extentOffset, target); + expect(key.currentState!.spellingCaretOffset, target); + }); + + testWidgets('spelling reveal unfolds and retains the word selection', ( + tester, + ) async { + const source = '# Fold\nhidden mistakke here\n# Next\nend\n'; + const path = '/project/folded-spelling.md'; + final region = sourceFoldRegions( + source, + SourceSyntaxLanguage.markdown, + ).first; + final start = source.indexOf('mistakke'); + final end = start + 'mistakke'.length; + final key = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: BusyMarkSourceEditor( + key: key, + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: path, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + initialFoldedRegionKeys: {region.key}, + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + ), + ), + ), + ); + await tester.pump(); + final controller = tester + .widgetList(find.byType(TextField)) + .map((field) => field.controller) + .whereType() + .single; + expect(controller.text, isNot(contains('hidden mistakke'))); + + key.currentState!.revealSpellingOccurrence( + _sourceSpellingOccurrence( + word: 'mistakke', + sourceStart: start, + sourceEnd: end, + filePath: path, + ), + ); + await tester.pump(); + + expect(controller.text, contains('hidden mistakke')); + expect( + controller.fullSelection, + TextSelection(baseOffset: start, extentOffset: end), + ); + expect(controller.fullSelection.isCollapsed, isFalse); + expect( + source.substring( + controller.fullSelection.start, + controller.fullSelection.end, + ), + 'mistakke', + ); + await tester.pump(const Duration(milliseconds: 100)); + await tester.pumpWidget(const SizedBox()); + await tester.pump(const Duration(seconds: 1)); + }); + + for (final mode + in < + ({ + String label, + String path, + SourceSyntaxLanguage language, + SourceDocumentFormat documentFormat, + MarkdownMode? markdownMode, + }) + >[ + ( + label: 'Markdown', + path: '/project/spelling.md', + language: SourceSyntaxLanguage.markdown, + documentFormat: SourceDocumentFormat.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ( + label: 'Writerside Markdown', + path: '/project/topics/spelling.md', + language: SourceSyntaxLanguage.markdown, + documentFormat: SourceDocumentFormat.markdown, + markdownMode: MarkdownMode.writersideMarkdown, + ), + ( + label: 'XML', + path: '/project/topics/spelling.topic', + language: SourceSyntaxLanguage.xml, + documentFormat: SourceDocumentFormat.genericXml, + markdownMode: null, + ), + ]) { + testWidgets( + 'Source ${mode.label} spelling painter ignores selection and tracks composition', + (tester) async { + final annotation = SpellingAnnotation( + occurrenceId: 'source-paint-helo', + start: 0, + end: 4, + target: SpellingSourceTarget(filePath: mode.path), + ); + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 600, + child: BusyMarkSourceEditor( + text: 'helo world', + language: mode.language, + documentFormat: mode.documentFormat, + markdownMode: mode.markdownMode, + filePath: mode.path, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + initialSelection: const TextSelection.collapsed(offset: 4), + spellingAnnotations: [annotation], + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + ), + ), + ), + ), + ); + await tester.pump(); + + final controller = tester + .widgetList(find.byType(TextField)) + .map((field) => field.controller) + .whereType() + .single; + const range = TextRange(start: 0, end: 4); + final painterFinder = find.byWidgetPredicate( + (widget) => + widget is CustomPaint && + widget.foregroundPainter.runtimeType.toString() == + '_SourceSpellingPainter', + ); + expect(painterFinder, findsOneWidget); + final render = tester.renderObject(painterFinder); + expect(render.debugNeedsPaint, isFalse); + expect(controller.fullSelection.extentOffset, 4); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.fullSelection = const TextSelection.collapsed(offset: 0); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.fullSelection = const TextSelection.collapsed(offset: 2); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.fullSelection = const TextSelection.collapsed(offset: 4); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.fullSelection = const TextSelection( + baseOffset: 0, + extentOffset: 4, + ); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.fullSelection = const TextSelection( + baseOffset: 5, + extentOffset: 10, + ); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + expect(render.debugNeedsPaint, isFalse); + controller.value = controller.value.copyWith( + composing: const TextRange(start: 0, end: 4), + ); + expect(render.debugNeedsPaint, isTrue); + await tester.pump(); + expect(controller.fullComposing, range); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isTrue, + ); + + controller.value = controller.value.copyWith( + composing: TextRange.empty, + ); + expect(render.debugNeedsPaint, isTrue); + await tester.pump(); + expect(painterFinder, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + + controller.value = controller.value.copyWith( + composing: const TextRange(start: 5, end: 10), + ); + expect(render.debugNeedsPaint, isTrue); + await tester.pump(); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + }, + ); + } + testWidgets('source AI action applies a selection through the editor path', ( tester, ) async { @@ -330,6 +694,9 @@ void main() { height: 600, child: BusyMarkSourceEditor( text: source, + clipboardService: _SourceTestClipboard( + readData: const RichClipboardData(text: 'Paste', generation: 7), + ), language: SourceSyntaxLanguage.markdown, filePath: '/project/topic.md', diagnostics: const [], @@ -396,8 +763,15 @@ void main() { await tester.tap(fieldFinder, buttons: kSecondaryMouseButton); await tester.pumpAndSettle(); + final expectedWithPlainPaste = []; + for (final label in expectedSelectionActions) { + expectedWithPlainPaste.add(label); + if (label == 'Paste') { + expectedWithPlainPaste.add('Paste as Plain Text'); + } + } expect(nativeEntries!.map((entry) => entry['label']), [ - ...expectedSelectionActions, + ...expectedWithPlainPaste, 'Refine with AI', '', 'Clipboard History', @@ -414,6 +788,10 @@ void main() { expect(_nativeShortcut(nativeEntries!, 'Cut'), 'Ctrl+X'); expect(_nativeShortcut(nativeEntries!, 'Copy'), 'Ctrl+C'); expect(_nativeShortcut(nativeEntries!, 'Paste'), 'Ctrl+V'); + expect( + _nativeShortcut(nativeEntries!, 'Paste as Plain Text'), + 'Ctrl+Shift+V', + ); expect(_nativeShortcut(nativeEntries!, 'Select all'), 'Ctrl+A'); expect(_nativeShortcut(nativeEntries!, 'Refine with AI'), 'Ctrl+G'); expect(_nativeIcon(nativeEntries!, 'Cut'), 'edit-cut-symbolic'); @@ -432,119 +810,392 @@ void main() { expect(changedText, 'Clear text.\n'); }); - testWidgets('source AI applies a user-selected insertion target', ( + testWidgets('source spelling menu targets the pointer occurrence exactly', ( tester, ) async { - const source = '# Plan\n\nNotes for draft.\n\nAfter.\n'; - AiEditorSnapshot? snapshot; - String? changedText; + const source = 'helo middle helo\n'; + final secondStart = source.lastIndexOf('helo'); + int? requestedOffset; + const nativeMenuChannel = MethodChannel(nativeMenuChannelName); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + (call) async { + if (call.method != 'show') return false; + return -1; + }, + ); + addTearDown(() { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + null, + ); + }); await tester.pumpWidget( MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, - theme: buildBusyMarkTheme( - brightness: Brightness.dark, - accentColor: BusyMarkLinuxPalette.blueAccent, - ), home: Scaffold( body: SizedBox( width: 900, height: 600, child: BusyMarkSourceEditor( text: source, + clipboardService: _SourceTestClipboard(), language: SourceSyntaxLanguage.markdown, - filePath: '/project/topic.md', + filePath: '/project/spelling.md', diagnostics: const [], editorFontSize: 14, wordWrap: true, searchActive: false, searchOptions: const SourceSearchOptions(), onSearchOptionsChanged: (_) {}, - onChanged: (text, _) => changedText = text, + onChanged: (_, _) {}, onOpenSearch: () {}, onCloseSearch: () {}, - editRevision: 10, - onAiEdit: (value) async { - snapshot = value; - final insertion = source.indexOf('After.'); - return AiEditApplication( - invocation: AiEditInvocation( - feature: AiFeature.editDocument, - scope: AiScope.markdownEdit, - input: source.substring( - value.selectionStart, - value.selectionEnd, - ), - replacementOriginal: '', - sourceRevision: value.sourceRevision, - targetId: value.targetId, - documentPath: value.documentPath, - instruction: 'Draft a section from these notes.', - editTarget: AiEditTargetKind.insertAfterBlock, - editContext: AiEditContextKind.selection, - documentSource: value.documentSource, - replacementStart: insertion, - replacementEnd: insertion, - replacementSuffix: '\n\n', + readSpellingMenuItems: (offset) async { + requestedOffset = offset; + return [ + BusyMarkEditorSpellingMenuItem( + label: 'hello', + onSelected: () {}, + suggestion: true, ), - output: 'Generated section.', - ); + ]; }, ), ), ), ), ); - final field = tester.widget(find.byType(TextField)); - await tester.tap(find.byType(TextField)); - final start = source.indexOf('Notes'); - field.controller!.selection = TextSelection( - baseOffset: start, - extentOffset: start + 'Notes for draft.'.length, + await tester.pump(); + final field = find.byType(TextField); + final render = _findRenderEditable(tester.renderObject(field))!; + final local = render.getLocalRectForCaret( + TextPosition(offset: secondStart + 1), + ); + await tester.tapAt( + render.localToGlobal(local.center), + buttons: kSecondaryMouseButton, ); - - await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); - await tester.sendKeyDownEvent(LogicalKeyboardKey.keyG); - await tester.sendKeyUpEvent(LogicalKeyboardKey.keyG); - await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); await tester.pumpAndSettle(); expect( - source.substring(snapshot!.selectionStart, snapshot!.selectionEnd), - 'Notes for draft.', + requestedOffset, + inInclusiveRange(secondStart, secondStart + 'helo'.length), ); - expect(changedText, contains('Notes for draft.')); - expect(changedText, contains('Generated section.\n\nAfter.')); }); - testWidgets('source editor remains LTR inside an Arabic interface', ( - tester, - ) async { - await tester.pumpWidget( - MaterialApp( - locale: const Locale('ar'), - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - theme: buildBusyMarkTheme( - brightness: Brightness.dark, - accentColor: BusyMarkLinuxPalette.blueAccent, - ), - home: Scaffold( - body: SizedBox( - width: 900, - height: 600, - child: BusyMarkSourceEditor( - text: '# مقدمة\npath: docs/مقدمة-v2.md\n', - language: SourceSyntaxLanguage.markdown, - filePath: '/project/topic.md', - diagnostics: const [], - editorFontSize: 14, - wordWrap: true, - searchActive: false, - searchOptions: const SourceSearchOptions(), - onSearchOptionsChanged: (_) {}, - onChanged: (_, _) {}, - onOpenSearch: () {}, + testWidgets( + 'source spelling language uses a checked native submenu without a dialog', + (tester) async { + const source = 'helo\n'; + const nativeMenuChannel = MethodChannel(nativeMenuChannelName); + List>? nativeEntries; + String? targetLabel; + String? selected; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + (call) async { + if (call.method != 'show') return false; + final arguments = call.arguments as Map; + nativeEntries = (arguments['entries'] as List) + .cast>(); + return targetLabel == null + ? -1 + : _nativeMenuIndexForLabel(nativeEntries!, targetLabel); + }, + ); + addTearDown(() { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + null, + ); + }); + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 600, + child: BusyMarkSourceEditor( + text: source, + clipboardService: _SourceTestClipboard(), + language: SourceSyntaxLanguage.markdown, + filePath: '/project/spelling-submenu.md', + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + readSpellingMenuItems: (_) async => [ + BusyMarkEditorSpellingMenuItem.submenu( + label: 'Choose spelling language', + children: [ + BusyMarkEditorSpellingMenuItem( + label: 'Inherit spelling language', + checked: true, + mutuallyExclusive: true, + onSelected: () => selected = 'inherit', + ), + BusyMarkEditorSpellingMenuItem( + label: 'Disable spelling', + mutuallyExclusive: true, + onSelected: () => selected = 'disabled', + ), + const BusyMarkEditorSpellingMenuItem.divider(), + BusyMarkEditorSpellingMenuItem( + label: 'Test English', + mutuallyExclusive: true, + onSelected: () => selected = 'en-Test', + ), + ], + ), + ], + ), + ), + ), + ), + ); + + Future openMenu() async { + nativeEntries = null; + await tester.tap( + find.byType(TextField), + buttons: kSecondaryMouseButton, + ); + await _pumpUntil(tester, () => nativeEntries != null); + } + + await openMenu(); + final languageMenu = nativeEntries!.singleWhere( + (entry) => entry['label'] == 'Choose spelling language', + ); + final children = (languageMenu['children'] as List) + .cast>(); + expect(children.map((entry) => entry['label']), [ + 'Inherit spelling language', + 'Disable spelling', + '', + 'Test English', + ]); + expect( + children.where((entry) => entry['selected'] == true), + hasLength(1), + ); + expect(children.first['selected'], isTrue); + expect(children.first['checkable'], isTrue); + expect(find.byType(SimpleDialog), findsNothing); + expect(find.byType(SimpleDialogOption), findsNothing); + + for (final choice in const { + 'Inherit spelling language': 'inherit', + 'Disable spelling': 'disabled', + 'Test English': 'en-Test', + }.entries) { + targetLabel = choice.key; + selected = null; + await openMenu(); + expect(selected, choice.value); + } + }, + ); + + testWidgets('source spelling menu converts folded offsets to full source', ( + tester, + ) async { + const source = '# First\nhelo hidden\n# Second\nhelo visible\n'; + const path = '/project/folded-menu.md'; + final region = sourceFoldRegions( + source, + SourceSyntaxLanguage.markdown, + ).first; + final expected = source.lastIndexOf('helo'); + int? requestedOffset; + const nativeMenuChannel = MethodChannel(nativeMenuChannelName); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + (call) async => call.method == 'show' ? -1 : false, + ); + addTearDown(() { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + null, + ); + }); + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 600, + child: BusyMarkSourceEditor( + text: source, + clipboardService: _SourceTestClipboard(), + language: SourceSyntaxLanguage.markdown, + filePath: path, + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + initialFoldedRegionKeys: {region.key}, + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, + onCloseSearch: () {}, + readSpellingMenuItems: (offset) async { + requestedOffset = offset; + return const []; + }, + ), + ), + ), + ), + ); + await tester.pump(); + final field = find.byType(TextField); + final controller = + tester.widget(field).controller! + as BusyMarkSourceEditingController; + final visibleTarget = controller.text.lastIndexOf('helo'); + expect(visibleTarget, lessThan(expected)); + final render = _findRenderEditable(tester.renderObject(field))!; + final local = render.getLocalRectForCaret( + TextPosition(offset: visibleTarget + 1), + ); + await tester.tapAt( + render.localToGlobal(local.center), + buttons: kSecondaryMouseButton, + ); + await tester.pumpAndSettle(); + + expect( + requestedOffset, + inInclusiveRange(expected, expected + 'helo'.length), + ); + }); + + testWidgets('source AI applies a user-selected insertion target', ( + tester, + ) async { + const source = '# Plan\n\nNotes for draft.\n\nAfter.\n'; + AiEditorSnapshot? snapshot; + String? changedText; + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.dark, + accentColor: BusyMarkLinuxPalette.blueAccent, + ), + home: Scaffold( + body: SizedBox( + width: 900, + height: 600, + child: BusyMarkSourceEditor( + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: '/project/topic.md', + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (text, _) => changedText = text, + onOpenSearch: () {}, + onCloseSearch: () {}, + editRevision: 10, + onAiEdit: (value) async { + snapshot = value; + final insertion = source.indexOf('After.'); + return AiEditApplication( + invocation: AiEditInvocation( + feature: AiFeature.editDocument, + scope: AiScope.markdownEdit, + input: source.substring( + value.selectionStart, + value.selectionEnd, + ), + replacementOriginal: '', + sourceRevision: value.sourceRevision, + targetId: value.targetId, + documentPath: value.documentPath, + instruction: 'Draft a section from these notes.', + editTarget: AiEditTargetKind.insertAfterBlock, + editContext: AiEditContextKind.selection, + documentSource: value.documentSource, + replacementStart: insertion, + replacementEnd: insertion, + replacementSuffix: '\n\n', + ), + output: 'Generated section.', + ); + }, + ), + ), + ), + ), + ); + final field = tester.widget(find.byType(TextField)); + await tester.tap(find.byType(TextField)); + final start = source.indexOf('Notes'); + field.controller!.selection = TextSelection( + baseOffset: start, + extentOffset: start + 'Notes for draft.'.length, + ); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyDownEvent(LogicalKeyboardKey.keyG); + await tester.sendKeyUpEvent(LogicalKeyboardKey.keyG); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pumpAndSettle(); + + expect( + source.substring(snapshot!.selectionStart, snapshot!.selectionEnd), + 'Notes for draft.', + ); + expect(changedText, contains('Notes for draft.')); + expect(changedText, contains('Generated section.\n\nAfter.')); + }); + + testWidgets('source editor remains LTR inside an Arabic interface', ( + tester, + ) async { + await tester.pumpWidget( + MaterialApp( + locale: const Locale('ar'), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.dark, + accentColor: BusyMarkLinuxPalette.blueAccent, + ), + home: Scaffold( + body: SizedBox( + width: 900, + height: 600, + child: BusyMarkSourceEditor( + text: '# مقدمة\npath: docs/مقدمة-v2.md\n', + language: SourceSyntaxLanguage.markdown, + filePath: '/project/topic.md', + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onOpenSearch: () {}, onCloseSearch: () {}, ), ), @@ -1660,82 +2311,6242 @@ void main() { ); }); - testWidgets('focused Source accepts authoritative parent text updates', ( + testWidgets('focused Source accepts authoritative parent text updates', ( + tester, + ) async { + var source = 'local'; + String? changedText; + late StateSetter updateHost; + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: StatefulBuilder( + builder: (context, setState) { + updateHost = setState; + return BusyMarkSourceEditor( + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: '/project/topic.md', + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (text, _) => changedText = text, + onOpenSearch: () {}, + onCloseSearch: () {}, + ); + }, + ), + ), + ), + ); + final fieldFinder = find.byType(TextField); + await tester.tap(fieldFinder); + expect(tester.widget(fieldFinder).focusNode!.hasFocus, isTrue); + + updateHost(() => source = 'authoritative'); + await tester.pump(); + + expect(tester.widget(fieldFinder).controller!.text, source); + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'authoritative!', + selection: TextSelection.collapsed(offset: 14), + ), + ); + await tester.pump(); + expect(changedText, 'authoritative!'); + }); + + testWidgets('source keyboard copy retains exact whitespace once', ( + tester, + ) async { + const source = 'before\n \n\t\nafter\n'; + final clipboard = _SourceTestClipboard(); + final captures = []; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: clipboard, + onCaptured: captures.add, + ); + controller.selection = TextSelection( + baseOffset: source.indexOf(' \n'), + extentOffset: source.indexOf('after'), + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyC); + await tester.pump(); + + expect(clipboard.writes, hasLength(1)); + expect(clipboard.writes.single.text, ' \n\t\n'); + expect(clipboard.writes.single.sourceText, ' \n\t\n'); + expect(captures, hasLength(1)); + expect(captures.single.sourceText, ' \n\t\n'); + }); + + testWidgets('Source normal HTML paste converts while plain paste uses text', ( + tester, + ) async { + final normalClipboard = _SourceTestClipboard( + readData: const RichClipboardData( + text: 'Plain HTML', + html: '

Heading

Bold

', + generation: 1, + ), + ); + final normal = await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: normalClipboard, + ); + normal.selection = const TextSelection(baseOffset: 0, extentOffset: 6); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(normal.text, contains('## Heading')); + expect(normal.text, contains('**Bold**')); + expect(normalClipboard.reads, 1); + + final plainClipboard = _SourceTestClipboard( + readData: const RichClipboardData( + text: ' Plain HTML\n', + html: '

Heading

Bold

', + generation: 2, + ), + ); + final plain = await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: plainClipboard, + ); + final readsBeforePlainPaste = plainClipboard.reads; + plain.selection = const TextSelection(baseOffset: 0, extentOffset: 6); + await _pressControlKey(tester, LogicalKeyboardKey.keyV, shift: true); + await tester.pump(); + expect(plain.text, ' Plain HTML\n'); + expect(plainClipboard.reads, readsBeforePlainPaste + 1); + await tester.pump(const Duration(milliseconds: 600)); + }); + + testWidgets('Source CRLF structured paste is one exact undo transaction', ( + tester, + ) async { + const source = 'leftright\r\n'; + final clipboard = _SourceTestClipboard( + readData: RichClipboardData( + text: '# Heading', + richFragment: _completeSourceFragment('# Heading\n').encode(), + ), + ); + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 'left'.length); + var history = const DocumentUndoState(); + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: clipboard, + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + transactions++; + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + ); + controller.selection = modelSelection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + final pasted = controller.text; + final pastedSelection = controller.selection; + expect(transactions, 1); + expect(pasted, contains('# Heading')); + expect(_sourceContainsLoneLf(pasted), isFalse, reason: pasted); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, pasted); + expect(controller.selection, pastedSelection); + }); + + testWidgets('Source plain paste keeps LF bytes in a CRLF document', ( + tester, + ) async { + const source = 'left\r\nright\r\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: const RichClipboardData(text: 'A\nB'), + ), + ); + controller.selection = const TextSelection.collapsed(offset: 'left'.length); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV, shift: true); + await tester.pump(); + + expect(controller.text, 'leftA\nB\r\nright\r\n'); + }); + + testWidgets('Source structured inline paste keeps surrounding text inline', ( + tester, + ) async { + final clipboard = _SourceTestClipboard( + readData: const RichClipboardData( + text: 'X', + html: 'X', + generation: 40, + ), + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: clipboard, + ); + controller.selection = const TextSelection.collapsed(offset: 4); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, 'left**X**right'); + expect(clipboard.reads, 1); + }); + + testWidgets('Source structured block paste adds Markdown boundaries', ( + tester, + ) async { + final clipboard = _SourceTestClipboard( + readData: const RichClipboardData( + text: 'Heading\nItem', + html: '

Heading

  • Item
', + generation: 41, + ), + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'existing', + clipboard: clipboard, + ); + controller.selection = const TextSelection.collapsed(offset: 8); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, 'existing\n\n## Heading\n\n- Item\n'); + expect(clipboard.reads, 1); + }); + + testWidgets('Source structured blocks keep boundaries at every position', ( + tester, + ) async { + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: const [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.heading, + text: 'Heading', + ranges: [], + attributes: {'level': '2'}, + ), + BusyWysiwygStyledBlock( + kind: BusyBlockKind.unorderedListItem, + text: 'Item', + ranges: [], + ), + ], + ); + for (final value in [ + ('existing', 0, '## Heading\n\n- Item\n\nexisting'), + ('existing', 8, 'existing\n\n## Heading\n\n- Item\n'), + ('leftright', 4, 'left\n\n## Heading\n\n- Item\n\nright'), + ]) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.$1, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading\nItem', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed(offset: value.$2); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(controller.text, value.$3); + } + }); + + testWidgets( + 'Source complete heading list and code blocks retain structure at every paragraph position', + (tester) async { + final cases = <({String source, BusyBlockKind kind, String text})>[ + (source: '## Heading\n', kind: BusyBlockKind.heading, text: 'Heading'), + ( + source: '- Item\n', + kind: BusyBlockKind.unorderedListItem, + text: 'Item', + ), + ( + source: '```text\ncode\n```\n', + kind: BusyBlockKind.codeBlock, + text: 'code', + ), + ]; + for (final blockCase in cases) { + final fragment = _completeSourceFragment(blockCase.source); + for (final position in [0, 4, 9]) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: blockCase.text, + richFragment: fragment.encode(), + generation: 700 + position, + ), + ), + ); + controller.selection = TextSelection.collapsed(offset: position); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.where((block) => block.kind == blockCase.kind), + hasLength(1), + ); + expect( + parsed.blocks + .singleWhere((block) => block.kind == blockCase.kind) + .plainText, + blockCase.text, + ); + expect( + parsed.blocks + .where((block) => block.kind == BusyBlockKind.paragraph) + .map((block) => block.plainText) + .join(), + 'leftright', + ); + } + } + }, + ); + + testWidgets( + 'Source complete-block split preserves styles caret and one-step Undo', + (tester) async { + const source = '**leftright**'; + final fragment = _completeSourceFragment('## Heading\n'); + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: fragment.encode(), + ), + ), + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + transactions += 1; + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + ); + const initialSelection = TextSelection.collapsed(offset: 6); + controller.selection = initialSelection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks, hasLength(3), reason: controller.text); + expect(parsed.blocks.map((block) => block.plainText), [ + 'left', + 'Heading', + 'right', + ]); + expect(parsed.blocks[1].kind, BusyBlockKind.heading); + for (final block in [parsed.blocks.first, parsed.blocks.last]) { + expect(block.inlines.single.kind, BusyInlineKind.strong); + } + const marker = '\ue005'; + final marked = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text.replaceRange( + controller.selection.baseOffset, + controller.selection.baseOffset, + marker, + ), + validateLocalReferences: false, + ) + .busyDocument; + expect(marked.blocks.last.plainText, '${marker}right'); + expect(marked.blocks.last.inlines.single.kind, BusyInlineKind.strong); + + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final editorResult = editor.insertStyledBlocksAtSelection( + blockId: editorDocument.blocks.single.id, + selectionStart: 4, + selectionEnd: 4, + blocks: fragment.blocks, + ); + expect(editorResult, isNotNull); + expect(editor.document.blocks.map((block) => block.plainText), [ + 'left', + 'Heading', + 'right', + ]); + for (final block in [ + editor.document.blocks.first, + editor.document.blocks.last, + ]) { + expect(block.inlines.single.kind, BusyInlineKind.strong); + } + + expect(transactions, 1); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + expect(controller.selection, initialSelection); + expect(transactions, 1); + }, + ); + + testWidgets( + 'Source boundary-crossing replacements restore text selection and caret', + (tester) async { + final cases = + < + ({ + String source, + TextSelection selection, + String fragmentSource, + String clipboardText, + String expected, + int expectedCaret, + }) + >[ + ( + source: '**leftSELECT**tail', + selection: TextSelection( + baseOffset: '**left'.length, + extentOffset: '**leftSELECT**'.length, + ), + fragmentSource: '## Heading\n', + clipboardText: 'Heading', + expected: '**left**\n\n## Heading\n\ntail', + expectedCaret: '**left**\n\n## Heading\n\n'.length, + ), + ( + source: 'alpha\n\nbeta', + selection: TextSelection(baseOffset: 2, extentOffset: 9), + fragmentSource: 'A\n\nB\n', + clipboardText: 'A\n\nB', + expected: 'alA\n\nBta', + expectedCaret: 'alA\n\nB'.length, + ), + ]; + + for (var index = 0; index < cases.length; index++) { + final value = cases[index]; + final fragment = _completeSourceFragment(value.fragmentSource); + var modelText = value.source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: value.clipboardText, + richFragment: fragment.encode(), + generation: 810 + index, + ), + ), + onTransactionalChanged: + (text, _, previousSelection, selection, undoGroup) { + transactions += 1; + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = text; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + ); + controller.selection = value.selection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final pastedSelection = TextSelection.collapsed( + offset: value.expectedCaret, + ); + expect(controller.text, value.expected); + expect(controller.selection, pastedSelection); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, value.source); + expect(controller.selection, value.selection); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, value.expected); + expect(controller.selection, pastedSelection); + expect(transactions, 1); + + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source rich inline paste composes with enclosing inline syntax', + (tester) async { + Future paste({ + required String source, + required int offset, + required String fragmentSource, + }) async { + final fragment = _completeSourceFragment(fragmentSource); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed(offset: offset); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + return controller; + } + + final bold = await paste( + source: 'Before\n\n**leftright**\n\nAfter\n', + offset: 'Before\n\n**left'.length, + fragmentSource: '**X**\n', + ); + expect(bold.text, 'Before\n\n**leftXright**\n\nAfter\n'); + final boldBlock = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: bold.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks[1]; + expect(boldBlock.inlines.single.kind, BusyInlineKind.strong); + expect(boldBlock.inlines.single.plainText, 'leftXright'); + + final emphasis = await paste( + source: '*leftright*', + offset: '*left'.length, + fragmentSource: '*X*\n', + ); + expect(emphasis.text, '*leftXright*'); + final emphasisInline = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: emphasis.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines + .single; + expect(emphasisInline.kind, BusyInlineKind.emphasis); + expect(emphasisInline.plainText, 'leftXright'); + + const linkedSource = '[leftright](https://example.test)'; + final linked = await paste( + source: linkedSource, + offset: '[left'.length, + fragmentSource: '**X**\n', + ); + final link = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: linked.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines + .single; + expect(link.kind, BusyInlineKind.link); + expect(link.destination, 'https://example.test'); + expect(link.plainText, 'leftXright'); + expect( + link.children.where((inline) => inline.kind == BusyInlineKind.strong), + hasLength(1), + ); + + final adjacent = await paste( + source: '**left****right**', + offset: '**left**'.length, + fragmentSource: '**X**\n', + ); + expect(adjacent.text, '**leftXright**'); + final adjacentBlock = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: adjacent.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(adjacentBlock.inlines.single.kind, BusyInlineKind.strong); + expect(adjacentBlock.inlines.single.plainText, 'leftXright'); + }, + ); + + testWidgets( + 'Source inline reconciliation ignores separate destination runs', + (tester) async { + const source = '**left** gap **right**'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + ); + final gap = source.indexOf('gap'); + controller.selection = TextSelection( + baseOffset: gap, + extentOffset: gap + 3, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '**left** **X** **right**'); + expect(controller.selection.baseOffset, '**left** **X**'.length); + final inlines = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines; + expect( + inlines + .where((inline) => inline.kind == BusyInlineKind.strong) + .map((inline) => inline.plainText), + ['left', 'X', 'right'], + ); + }, + ); + + testWidgets( + 'Source adjacent-style reconciliation preserves literal code delimiters', + (tester) async { + Future verify({ + required String source, + required MarkdownMode mode, + }) async { + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: mode, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '**X**\n', + mode: mode, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + final firstRunEnd = source.indexOf('**left**') + '**left**'.length; + controller.selection = TextSelection.collapsed(offset: firstRunEnd); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final expected = source.replaceRange(firstRunEnd, firstRunEnd, '**X**'); + expect(controller.text, expected); + expect(controller.selection.baseOffset, firstRunEnd + '**X**'.length); + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: mode, + validateLocalReferences: false, + ) + .busyDocument; + final inlines = document.blocks.single.kind == BusyBlockKind.table + ? document.blocks.single.children.last.children.single.inlines + : document.blocks.single.inlines; + expect(inlines, hasLength(1)); + expect(inlines.single.kind, BusyInlineKind.code); + expect(inlines.single.text, '**left****X****right**'); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + } + + await verify( + source: '`**left****right**`', + mode: MarkdownMode.commonMark, + ); + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + await verify( + source: + '| H |\n' + '| --- |\n' + '| `**left****right**` |\n', + mode: MarkdownMode.gfm, + ); + }, + ); + + testWidgets( + 'Source table reconciliation preserves a partially consumed delimiter', + (tester) async { + const source = '| H |\n| --- |\n| ***leftright** |\n'; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + 'X\n', + mode: MarkdownMode.gfm, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '| H |\n| --- |\n| ***left**X**right** |\n'); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final inlines = + parsed.blocks.single.children.last.children.single.inlines; + expect(inlines.map((inline) => inline.plainText).join(), '*leftXright'); + expect( + inlines + .where((inline) => inline.kind == BusyInlineKind.strong) + .map((inline) => inline.plainText), + ['left', 'right'], + ); + expect(controller.selection.baseOffset, controller.text.indexOf('X') + 1); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets( + 'Source table inline reconciliation is confined to the selected cell', + (tester) async { + const source = + '| A | B | C |\n' + '| --- | --- | --- |\n' + '| **left** | gap | **right** |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + ); + final gap = source.indexOf('gap'); + controller.selection = TextSelection( + baseOffset: gap, + extentOffset: gap + 3, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '| A | B | C |\n' + '| --- | --- | --- |\n' + '| **left** | **X** | **right** |\n', + ); + expect(controller.selection.baseOffset, controller.text.indexOf('X') + 3); + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + final cells = table.children.last.children; + expect(cells[0].inlines.single.kind, BusyInlineKind.strong); + expect(cells[1].inlines.single.kind, BusyInlineKind.strong); + expect(cells[1].inlines.single.plainText, 'X'); + expect(cells[2].inlines.single.kind, BusyInlineKind.strong); + }, + ); + + testWidgets('Source table keeps multiple independent incoming style runs', ( + tester, + ) async { + const source = '| H |\n| --- |\n| gap |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A and B', + richFragment: _completeSourceFragment('**A** and **B**\n').encode(), + ), + ), + ); + final gap = source.indexOf('gap'); + controller.selection = TextSelection( + baseOffset: gap, + extentOffset: gap + 3, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '| H |\n| --- |\n| **A** and **B** |\n'); + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect( + table.children.last.children.single.inlines + .where((inline) => inline.kind == BusyInlineKind.strong) + .map((inline) => inline.plainText), + ['A', 'B'], + ); + }); + + testWidgets( + 'Source does not treat multiple incoming bold runs as one wrapper', + (tester) async { + final fragment = _completeSourceFragment('**A** and **B**\n'); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A and B', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = const TextSelection.collapsed(offset: 4); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, 'left**A** and **B**right'); + final inlines = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines; + expect( + inlines + .where((inline) => inline.kind == BusyInlineKind.strong) + .map((inline) => inline.plainText), + ['A', 'B'], + ); + }, + ); + + testWidgets( + 'Source reconciles arbitrary inline sequences with paragraph context', + (tester) async { + final cases = [ + _completeSourceFragment('**A** and **B**\n'), + _completeSourceFragment('***A*** and [B](https://incoming.test)\n'), + ]; + for (final (index, fragment) in cases.indexed) { + const source = '**leftright**'; + final sourceController = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: fragment.documentBlocks.single.plainText, + richFragment: fragment.encode(), + ), + ), + ); + sourceController.selection = const TextSelection.collapsed(offset: 6); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final sourceDocument = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: sourceController.text, + validateLocalReferences: false, + ) + .busyDocument; + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + final editorController = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editorController.dispose); + final editorBlock = editorController.document.blocks.single; + expect( + editorController.insertStyledBlocksAtSelection( + blockId: editorBlock.id, + selectionStart: 4, + selectionEnd: 4, + blocks: fragment.blocks, + ), + isNotNull, + ); + + expect( + _inlineSemanticRuns(sourceDocument.blocks.single.inlines), + _inlineSemanticRuns(editorController.document.blocks.single.inlines), + reason: sourceController.text, + ); + expect( + sourceDocument.blocks.single.plainText, + 'left${fragment.documentBlocks.single.plainText}right', + ); + if (index == 0) { + expect(sourceController.text, '**leftA and Bright**'); + } else { + expect( + _inlineSemanticRuns( + sourceDocument.blocks.single.inlines, + ).any((run) => run.context.contains('link:https://incoming.test')), + isTrue, + ); + } + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source reconciles arbitrary inline sequences inside table cells', + (tester) async { + final fragment = _completeSourceFragment( + '**A** and **B**\n', + mode: MarkdownMode.gfm, + ); + const source = '| H |\n| --- |\n| **leftright** |\n'; + final sourceController = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A and B', + richFragment: fragment.encode(), + ), + ), + ); + sourceController.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final sourceTable = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: sourceController.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final editorController = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editorController.dispose); + final editorTable = editorController.document.blocks.single; + final editorCell = editorTable.children.last.children.single; + expect( + editorController.insertStyledInlinesInTableCell( + tableBlockId: editorTable.id, + cellId: editorCell.id, + selectionStart: 4, + selectionEnd: 4, + blocks: fragment.blocks, + ), + isNotNull, + ); + + final sourceCell = sourceTable.children.last.children.single; + final resultingEditorCell = editorController.blockById(editorCell.id)!; + expect( + _inlineSemanticRuns(sourceCell.inlines), + _inlineSemanticRuns(resultingEditorCell.inlines), + reason: sourceController.text, + ); + expect(sourceCell.plainText, 'leftA and Bright'); + expect(sourceTable.children, hasLength(2)); + }, + ); + + testWidgets( + 'Source table sequence reconciliation retains authored delimiters', + (tester) async { + final fragment = _completeSourceFragment( + '**A** and **B**\n', + mode: MarkdownMode.gfm, + ); + const source = '| H |\n| --- |\n| __leftright__ |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A and B', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '| H |\n| --- |\n| __leftA__ and __Bright__ |\n'); + expect(controller.selection.baseOffset, controller.text.indexOf('B') + 1); + }, + ); + + testWidgets('Source table reconciliation retains mixed nested styles', ( + tester, + ) async { + final fragment = _completeSourceFragment( + '***A*** and [B](https://incoming.test)\n', + mode: MarkdownMode.gfm, + ); + const source = '| H |\n| --- |\n| **leftright** |\n'; + final sourceController = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A and B', + richFragment: fragment.encode(), + ), + ), + ); + sourceController.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final sourceTable = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: sourceController.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + final sourceCell = sourceTable.children.last.children.single; + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final editorController = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editorController.dispose); + final editorTable = editorController.document.blocks.single; + final editorCell = editorTable.children.last.children.single; + expect( + editorController.insertStyledInlinesInTableCell( + tableBlockId: editorTable.id, + cellId: editorCell.id, + selectionStart: 4, + selectionEnd: 4, + blocks: fragment.blocks, + ), + isNotNull, + ); + expect( + _inlineSemanticRuns(sourceCell.inlines), + _inlineSemanticRuns(editorController.blockById(editorCell.id)!.inlines), + reason: sourceController.text, + ); + expect(sourceTable.children, hasLength(2)); + expect(sourceCell.plainText, 'leftA and Bright'); + expect( + _inlineSemanticRuns( + sourceCell.inlines, + ).any((run) => run.context.contains('link:https://incoming.test')), + isTrue, + ); + }); + + testWidgets('Source preserves hyperlink semantics in table cells', ( + tester, + ) async { + final cases = + < + ({ + String label, + int start, + int end, + String incoming, + List links, + }) + >[ + ( + label: 'leftright', + start: 4, + end: 4, + incoming: 'https://incoming.test', + links: const [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + ), + ( + label: 'leftright', + start: 4, + end: 4, + incoming: 'https://destination.test', + links: const ['https://destination.test'], + ), + ( + label: 'leftmiddleright', + start: 4, + end: 10, + incoming: 'https://incoming.test', + links: const [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + ), + ]; + for (final (index, value) in cases.indexed) { + final fragment = _completeSourceFragment( + '[X](${value.incoming})\n', + mode: MarkdownMode.gfm, + ); + final source = + '| H |\n' + '| --- |\n' + '| [${value.label}](https://destination.test) |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + final labelStart = source.indexOf(value.label); + controller.selection = TextSelection( + baseOffset: labelStart + value.start, + extentOffset: labelStart + value.end, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(table.children, hasLength(2), reason: controller.text); + final sourceCell = table.children.last.children.single; + expect( + sourceCell.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + value.links, + reason: controller.text, + ); + + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final editorController = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editorController.dispose); + final editorTable = editorController.document.blocks.single; + final editorCell = editorTable.children.last.children.single; + expect( + editorController.insertStyledInlinesInTableCell( + tableBlockId: editorTable.id, + cellId: editorCell.id, + selectionStart: value.start, + selectionEnd: value.end, + blocks: fragment.blocks, + ), + isNotNull, + ); + expect( + _inlineSemanticRuns(sourceCell.inlines), + _inlineSemanticRuns(editorController.blockById(editorCell.id)!.inlines), + reason: controller.text, + ); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source inline mapping handles links multiline styles and literal syntax', + (tester) async { + var pasteCount = 0; + Future paste({ + required String source, + required int start, + int? end, + required String fragmentSource, + }) async { + if (pasteCount++ > 0) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment(fragmentSource).encode(), + ), + ), + ); + controller.selection = TextSelection( + baseOffset: start, + extentOffset: end ?? start, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + return controller; + } + + const destinationLink = '[leftright](https://destination.test)'; + var controller = await paste( + source: destinationLink, + start: '[left'.length, + fragmentSource: '[X](https://incoming.test)\n', + ); + expect( + controller.text, + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[right](https://destination.test)', + ); + expect( + controller.selection.baseOffset, + '[left](https://destination.test)' + '[X](https://incoming.test)' + .length, + ); + var parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks.single.inlines.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + + controller = await paste( + source: destinationLink, + start: '[left'.length, + fragmentSource: '[X](https://destination.test)\n', + ); + expect(controller.text, '[leftXright](https://destination.test)'); + parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.single.inlines.single.destination, + 'https://destination.test', + ); + + const selectedLink = '[leftmiddleright](https://destination.test)'; + controller = await paste( + source: selectedLink, + start: selectedLink.indexOf('middle'), + end: selectedLink.indexOf('middle') + 'middle'.length, + fragmentSource: '[X](https://incoming.test)\n', + ); + expect( + controller.text, + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[right](https://destination.test)', + ); + + controller = await paste( + source: destinationLink, + start: 1, + end: 1 + 'leftright'.length, + fragmentSource: '[X](https://incoming.test)\n', + ); + expect(controller.text, '[X](https://incoming.test)'); + expect( + controller.selection.baseOffset, + '[X](https://incoming.test)'.length, + ); + + const titledDestination = + '[leftright](https://destination.test "Destination title")'; + controller = await paste( + source: titledDestination, + start: '[left'.length, + fragmentSource: '[X](https://incoming.test "Incoming title")\n', + ); + expect( + controller.text, + '[left](https://destination.test "Destination title")' + '[X](https://incoming.test "Incoming title")' + '[right](https://destination.test "Destination title")', + ); + parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.single.inlines.map( + (inline) => (inline.destination, inline.attributes['title']), + ), + [ + ('https://destination.test', 'Destination title'), + ('https://incoming.test', 'Incoming title'), + ('https://destination.test', 'Destination title'), + ], + ); + + controller = await paste( + source: 'leftright', + start: 4, + fragmentSource: '[X](https://incoming.test)\n', + ); + expect(controller.text, 'left[X](https://incoming.test)right'); + expect( + controller.selection.baseOffset, + 'left[X](https://incoming.test)'.length, + ); + + const multiline = '*left\nright*'; + controller = await paste( + source: multiline, + start: '*left'.length, + fragmentSource: '*X*\n', + ); + expect(controller.text, '*leftX\nright*'); + expect(controller.selection.baseOffset, '*leftX'.length); + parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks.single.inlines.single.kind, BusyInlineKind.emphasis); + + const escaped = r'\*\*left\*\* gap \*\*right\*\*'; + final escapedGap = escaped.indexOf('gap'); + controller = await paste( + source: escaped, + start: escapedGap, + end: escapedGap + 3, + fragmentSource: '**X**\n', + ); + expect(controller.text, r'\*\*left\*\* **X** \*\*right\*\*'); + parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.strong) + .map((inline) => inline.plainText), + ['X'], + ); + + const code = '`**left** gap **right**`'; + final codeGap = code.indexOf('gap'); + controller = await paste( + source: code, + start: codeGap, + end: codeGap + 3, + fragmentSource: '**X**\n', + ); + expect(controller.text, '`**left** **X** **right**`'); + parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks.single.inlines.single.kind, BusyInlineKind.code); + expect( + parsed.blocks.single.inlines.single.plainText, + '**left** **X** **right**', + ); + + const crossing = 'before **bold** and *em* after'; + final crossingStart = crossing.indexOf('**bold**'); + final crossingEnd = crossing.indexOf('*em*') + '*em*'.length; + controller = await paste( + source: crossing, + start: crossingStart, + end: crossingEnd, + fragmentSource: '**X**\n', + ); + expect(controller.text, 'before **X** after'); + expect(controller.selection.baseOffset, 'before **X**'.length); + + const replacement = '**leftDELETEright**'; + final replacementStart = replacement.indexOf('DELETE'); + controller = await paste( + source: replacement, + start: replacementStart, + end: replacementStart + 'DELETE'.length, + fragmentSource: '**X**\n', + ); + expect(controller.text, '**leftXright**'); + expect(controller.selection.baseOffset, '**leftX'.length); + + controller = await paste( + source: '**left**right', + start: '**left**'.length, + fragmentSource: '**X**\n', + ); + expect(controller.text, '**left****X**right'); + expect(controller.selection.baseOffset, '**left****X**'.length); + }, + ); + + testWidgets( + 'Source caret mapping preserves literal bang before a following link', + (tester) async { + Future verify({ + required String source, + required MarkdownMode mode, + }) async { + var transactions = 0; + TextEditingValue? undoValue; + final fragment = _completeSourceFragment( + '[X](https://incoming.test)!\n', + mode: mode, + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: mode, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X!', + richFragment: fragment.encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const replacement = + '[left](https://destination.test)' + '[X](https://incoming.test)\\!' + '[right](https://destination.test)'; + final expected = source.replaceFirst( + '[leftright](https://destination.test)', + replacement, + ); + expect(controller.text, expected); + expect(controller.selection.baseOffset, expected.indexOf(r'\!') + 2); + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: mode, + validateLocalReferences: false, + ) + .busyDocument; + final inlines = document.blocks.single.kind == BusyBlockKind.table + ? document.blocks.single.children.last.children.single.inlines + : document.blocks.single.inlines; + expect( + inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + reason: controller.text, + ); + expect( + inlines.where((inline) => inline.kind == BusyInlineKind.image), + isEmpty, + reason: controller.text, + ); + expect(inlines.map((inline) => inline.plainText).join(), 'leftX!right'); + expect(transactions, 1); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + } + + await verify( + source: '[leftright](https://destination.test)', + mode: MarkdownMode.commonMark, + ); + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + await verify( + source: + '| H |\n' + '| --- |\n' + '| [leftright](https://destination.test) |\n', + mode: MarkdownMode.gfm, + ); + }, + ); + + testWidgets( + 'Source splits resolved reference links without changing definitions', + (tester) async { + final cases = <({String link, String definition})>[ + ( + link: '[leftright][dest]', + definition: '[dest]: https://destination.test', + ), + ( + link: '[leftright][]', + definition: '[leftright]: https://destination.test', + ), + ( + link: '[leftright]', + definition: '[leftright]: https://destination.test', + ), + ]; + for (final (index, value) in cases.indexed) { + final source = '${value.link}\n\n${value.definition}\n'; + final fragment = _completeSourceFragment( + '[X](https://incoming.test)\n', + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[right](https://destination.test)\n\n' + '${value.definition}\n', + reason: value.link, + ); + expect( + controller.selection.baseOffset, + '[left](https://destination.test)' + '[X](https://incoming.test)' + .length, + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.first.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + ); + expect(controller.text, contains('${value.definition}\n')); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source splits multiline blockquote links without exposing prefixes', + (tester) async { + const source = + '> [left\n' + '> right](https://destination.test)'; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('left') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[\n' + '> right](https://destination.test)', + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks, hasLength(1), reason: controller.text); + expect(parsed.blocks.single.kind, BusyBlockKind.blockquote); + final paragraph = _sourceBlocksDepthFirst( + parsed.blocks.single.children, + ).firstWhere((block) => block.kind == BusyBlockKind.paragraph); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect(links[0].plainText, 'left'); + expect(links[1].plainText, 'X'); + expect(links[2].plainText, '\nright'); + expect(paragraph.plainText, 'leftX\nright'); + expect(paragraph.plainText, isNot(contains('>'))); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets('Source preserves occurrence-specific hard-break provenance', ( + tester, + ) async { + final cases = <({String source, String expected})>[ + ( + source: + '> [left \r\n' + '> middle \n' + '> right](https://destination.test)', + expected: + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[ \r\n' + '> middle \n' + '> right](https://destination.test)', + ), + ( + source: + '> [left \r\n' + ' > middle \n' + '> right](https://destination.test)', + expected: + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[ \r\n' + ' > middle \n' + '> right](https://destination.test)', + ), + ( + source: + '> [left \r\n' + '> right](https://destination.test) and ' + '[later \n' + '> end](https://later.test)', + expected: + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[ \r\n' + '> right](https://destination.test) and ' + '[later \n' + '> end](https://later.test)', + ), + ]; + for (final (index, value) in cases.indexed) { + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: value.source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf('left') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, value.expected, reason: value.source); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(controller.text, isNot(contains('\ue000'))); + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(document.blocks.single.kind, BusyBlockKind.blockquote); + final links = _sourceBlocksDepthFirst(document.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.take(3).map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, value.source); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets('Source caret remains between pasted and retained hard breaks', ( + tester, + ) async { + const source = '[left \nright](https://destination.test)'; + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'XA', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)' + '[A \n](https://destination.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('left') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const pasted = + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test)'; + expect(controller.text, pasted); + final intendedCaret = pasted.indexOf('
\n
') + '
'.length; + expect(controller.selection.baseOffset, intendedCaret); + + final typed = pasted.replaceRange(intendedCaret, intendedCaret, 'Z'); + tester.testTextInput.updateEditingValue( + TextEditingValue( + text: typed, + selection: TextSelection.collapsed(offset: intendedCaret + 1), + ), + ); + await tester.pump(); + expect(controller.text, typed); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + final lastChildren = links.last.children; + final hardBreakIndexes = [ + for (final (index, inline) in lastChildren.indexed) + if (inline.kind == BusyInlineKind.hardBreak) index, + ]; + final typedIndex = lastChildren.indexWhere( + (inline) => inline.plainText.contains('Z'), + ); + expect(hardBreakIndexes, hasLength(2)); + expect(hardBreakIndexes.first, lessThan(typedIndex)); + expect(typedIndex, lessThan(hardBreakIndexes.last)); + expect(controller.text, contains('
Z\n
')); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, pasted); + expect(controller.selection.baseOffset, intendedCaret); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, pasted); + expect(controller.selection.baseOffset, intendedCaret); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, typed); + expect(controller.selection.baseOffset, intendedCaret + 1); + }); + + testWidgets( + 'Source rich paste after an HTML break does not retain its layout newline', + (tester) async { + const source = + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Y', + richFragment: _completeSourceFragment( + '[Y](https://incoming.test)\n', + ).encode(), + ), + ), + ); + final secondBreak = source.indexOf('
', source.indexOf('
') + 1); + controller.selection = TextSelection.collapsed( + offset: secondBreak + '
'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = parsed.blocks.single; + expect(paragraph.plainText, 'A\n\nYright tail', reason: controller.text); + expect( + paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + reason: controller.text, + ); + }, + ); + + testWidgets('Source rich paste preserves enclosing inline HTML as one run', ( + tester, + ) async { + const source = '[left
right
](https://destination.test) tail'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Y', + richFragment: _completeSourceFragment( + '[Y](https://incoming.test)\n', + ).encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('right') + 'ri'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = parsed.blocks.single; + expect(paragraph.plainText, 'left\nriYght tail', reason: controller.text); + expect(controller.text, isNot(contains(' tail'))); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + final surviving = [links.first, links.last] + .expand((inline) => inline.children) + .where((inline) => inline.kind == BusyInlineKind.underline) + .toList(growable: false); + expect(surviving, hasLength(2), reason: controller.text); + expect( + surviving + .expand((inline) => inline.children) + .where((inline) => inline.kind == BusyInlineKind.hardBreak), + hasLength(1), + reason: controller.text, + ); + }); + + testWidgets( + 'Source system and history rich paste map normalized HTML whitespace', + (tester) async { + const source = + '[left right]' + '(https://destination.test) tail'; + const html = 'Y'; + for (final (index, fromHistory) in [false, true].indexed) { + final registry = BusyMarkClipboardInsertionRegistry(); + final clipboard = _SourceTestClipboard( + readData: const RichClipboardData( + text: 'Y', + html: html, + generation: 55, + ), + ); + TextEditingValue? undoValue; + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: clipboard, + registry: registry, + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = const TextSelection.collapsed( + offset: '[left '.length, + ); + + if (fromHistory) { + final payload = BusyMarkClipboardPayload( + id: 'html-whitespace-history', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'Y', + html: html, + ); + expect(registry.canPaste(payload), isTrue); + expect(await registry.paste(payload), ClipboardPasteResult.inserted); + } else { + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + } + + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = document.blocks.single; + expect(paragraph.plainText, 'left Yright tail'); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect( + _inlineSemanticRuns(paragraph.inlines) + .where((run) => run.context.contains('underline')) + .map((run) => run.text), + ['left', 'Y', 'right'], + reason: controller.text, + ); + final incomingEnd = + controller.text.indexOf('https://incoming.test') + + 'https://incoming.test'.length + + 1; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + registry.dispose(); + if (index == 0) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source syntax-only availability agrees with textual fallback execution', + (tester) async { + const source = '**left**'; + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard(), + ); + controller.selection = const TextSelection.collapsed(offset: 1); + final fragment = _completeSourceFragment('[Y](https://incoming.test)\n'); + final payload = BusyMarkClipboardPayload( + id: 'syntax-fallback', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'Y', + richFragment: fragment.encode(), + ); + + expect(registry.canPaste(payload), isTrue); + expect(await registry.paste(payload), ClipboardPasteResult.inserted); + expect(controller.text, '*Y*left**'); + expect(controller.selection, const TextSelection.collapsed(offset: 2)); + }, + ); + + testWidgets( + 'Source terminal structured failure blocks availability and text fallback', + (tester) async { + const source = 'left'; + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var transactions = 0; + final fragment = _completeSourceFragment('[Y](https://incoming.test)\n'); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Y', + richFragment: fragment.encode(), + ), + ), + onTransactionalChanged: (_, _, _, _, _) => transactions += 1, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('left') + 2, + ); + final payload = BusyMarkClipboardPayload( + id: 'terminal-structured', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'Y', + richFragment: fragment.encode(), + ); + + expect(registry.canPaste(payload), isFalse); + expect(await registry.paste(payload), ClipboardPasteResult.unavailable); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(controller.text, source); + expect(transactions, 0); + }, + ); + + testWidgets('Source rich paste remaps generated grouped hard breaks', ( + tester, + ) async { + const source = '[left \nright](https://destination.test) tail'; + final clipboard = _SourceTestClipboard( + readData: RichClipboardData( + text: 'XA', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)' + '[A \n](https://destination.test)\n', + ).encode(), + ), + ); + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: clipboard, + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + transactions += 1; + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue(text: target.text, selection: target.selection); + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('left') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const firstPaste = + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + expect(controller.text, firstPaste); + final firstCaret = firstPaste.indexOf('
\n
') + '
'.length; + expect(controller.selection.baseOffset, firstCaret); + + clipboard.readData = RichClipboardData( + text: 'Y', + richFragment: _completeSourceFragment( + '[Y](https://second.test)\n', + ).encode(), + ); + final secondInsertion = firstPaste.indexOf('right') + 'ri'.length; + controller.selection = TextSelection.collapsed(offset: secondInsertion); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const secondPaste = + '[left](https://destination.test)' + '[X](https://incoming.test)' + '[A\n' + '
\n' + '
\n' + 'ri](https://destination.test)' + '[Y](https://second.test)' + '[ght](https://destination.test) tail'; + expect(controller.text, secondPaste); + final secondCaret = + secondPaste.indexOf('[Y](https://second.test)') + + '[Y](https://second.test)'.length; + expect(controller.selection.baseOffset, secondCaret); + expect(transactions, 2); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + 'https://second.test', + 'https://destination.test', + ]); + expect( + links + .expand((link) => link.children) + .where((inline) => inline.kind == BusyInlineKind.hardBreak), + hasLength(2), + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, firstPaste); + expect(controller.selection.baseOffset, secondInsertion); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, firstPaste); + expect(controller.selection.baseOffset, secondInsertion); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, secondPaste); + expect(controller.selection.baseOffset, secondCaret); + }); + + testWidgets('Source remaps reopened grouped breaks in a CRLF container', ( + tester, + ) async { + const source = + '> [A\r\n' + '>
\r\n' + '>
\r\n' + '> right](https://destination.test) tail'; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Y', + richFragment: _completeSourceFragment( + '[Y](https://second.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('right') + 'ri'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const expected = + '> [A\r\n' + '>
\r\n' + '>
\r\n' + '> ri](https://destination.test)' + '[Y](https://second.test)' + '[ght](https://destination.test) tail'; + expect(controller.text, expected); + final caret = + expected.indexOf('[Y](https://second.test)') + + '[Y](https://second.test)'.length; + expect(controller.selection.baseOffset, caret); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = _sourceBlocksDepthFirst(parsed.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(growable: false); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://second.test', + 'https://destination.test', + ]); + expect( + links + .expand((link) => link.children) + .where((inline) => inline.kind == BusyInlineKind.hardBreak), + hasLength(2), + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }); + + testWidgets( + 'Source maps nested and reference links through container prefixes', + (tester) async { + final cases = + < + ({ + String source, + MarkdownMode mode, + List path, + String continuationPrefix, + String? definition, + }) + >[ + ( + source: + '> > [left\n' + '> > right](https://destination.test)', + mode: MarkdownMode.commonMark, + path: const [ + BusyBlockKind.blockquote, + BusyBlockKind.blockquote, + BusyBlockKind.paragraph, + ], + continuationPrefix: '> > ', + definition: null, + ), + ( + source: + '> [left\n' + 'right](https://destination.test)', + mode: MarkdownMode.commonMark, + path: const [BusyBlockKind.blockquote, BusyBlockKind.paragraph], + continuationPrefix: '', + definition: null, + ), + ( + source: + '- [left\n' + ' right][dest]\n' + '\n' + '[dest]: https://destination.test\n', + mode: MarkdownMode.commonMark, + path: const [BusyBlockKind.unorderedListItem], + continuationPrefix: ' ', + definition: '[dest]: https://destination.test\n', + ), + ]; + for (final (index, value) in cases.indexed) { + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + markdownMode: value.mode, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + mode: value.mode, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: value.source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf('left') + 'left'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: value.mode, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = _sourceBlocksDepthFirst(document.blocks).firstWhere( + (block) => + block.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .length == + 3, + ); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect(links[0].plainText, 'left'); + expect(links[1].plainText, 'X'); + expect(links[2].plainText, '\nright'); + expect(paragraph.plainText, isNot(contains('>'))); + expect( + controller.text.split('\n')[1], + startsWith('${value.continuationPrefix}right'), + reason: controller.text, + ); + final paths = _busyBlockKindPaths(document.blocks, paragraph.kind); + expect(paths, contains(equals(value.path)), reason: controller.text); + if (value.definition case final definition?) { + expect( + RegExp(RegExp.escape(definition)).allMatches(controller.text), + hasLength(1), + ); + } + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, value.source); + + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets('Source paste preserves autolink destination semantics', ( + tester, + ) async { + const originalDestination = 'https://example.test/leftright'; + const incomingDestination = 'https://incoming.test'; + for (final (index, value) + in <({String source, bool table, int length, String incoming})>[ + ( + source: 'Before <$originalDestination> after', + table: false, + length: 0, + incoming: incomingDestination, + ), + ( + source: 'Before <$originalDestination> after', + table: false, + length: 'left'.length, + incoming: incomingDestination, + ), + ( + source: '| H |\n| --- |\n| <$originalDestination> |\n', + table: true, + length: 0, + incoming: incomingDestination, + ), + ( + source: 'Before <$originalDestination> after', + table: false, + length: 0, + incoming: originalDestination, + ), + ].indexed) { + final source = value.source; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: value.table ? MarkdownMode.gfm : MarkdownMode.commonMark, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](${value.incoming})\n', + mode: value.table ? MarkdownMode.gfm : MarkdownMode.commonMark, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + final selectionStart = + source.indexOf('left') + (value.length == 0 ? 'left'.length : 0); + controller.selection = TextSelection( + baseOffset: selectionStart, + extentOffset: selectionStart + value.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: value.table ? MarkdownMode.gfm : MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final links = _sourceBlocksDepthFirst(document.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect( + links.map((inline) => inline.destination), + value.incoming == originalDestination + ? [originalDestination] + : [originalDestination, value.incoming, originalDestination], + reason: controller.text, + ); + expect( + links.map((inline) => inline.plainText).join(), + value.length == 0 + ? originalDestination.replaceFirst('right', 'Xright') + : originalDestination.replaceFirst('left', 'X'), + ); + expect( + links.every((link) => link.attributes['href'] == link.destination), + isTrue, + ); + expect(controller.text, isNot(contains('%EE%80%80'))); + expect(controller.text, isNot(contains('\ue000'))); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + if (index < 3) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'invalid email-like text does not invalidate another link target', + (tester) async { + const target = ''; + for (final (index, source) in const [ + 'Before and $target after', + 'Before $target and after', + '| H |\n| --- |\n| Before and $target after |\n', + 'Before $target and $target after', + ].indexed) { + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: index == 2 ? MarkdownMode.gfm : MarkdownMode.commonMark, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + mode: index == 2 ? MarkdownMode.gfm : MarkdownMode.commonMark, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + final selectedTarget = source.indexOf(target); + controller.selection = TextSelection.collapsed( + offset: selectedTarget + target.indexOf('leftright') + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + const replacement = + '[https://example.test/left](https://example.test/leftright)' + '[X](https://incoming.test)' + '[right](https://example.test/leftright)'; + final expected = source.replaceRange( + selectedTarget, + selectedTarget + target.length, + replacement, + ); + expect(controller.text, expected); + if (source.contains('')) { + expect(controller.text, contains(''), reason: source); + } + expect(controller.text, isNot(contains('\ue000'))); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: index == 2 ? MarkdownMode.gfm : MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final links = _sourceBlocksDepthFirst(parsed.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.take(3).map((inline) => inline.destination), [ + 'https://example.test/leftright', + 'https://incoming.test', + 'https://example.test/leftright', + ], reason: controller.text); + expect( + links + .take(3) + .every((link) => link.attributes['href'] == link.destination), + isTrue, + ); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + if (index + 1 < 4) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets('Source paste distinguishes authored and generated URL content', ( + tester, + ) async { + final cases = <({String source, String needle})>[ + ( + source: '', + needle: 'right', + ), + (source: '', needle: '@'), + ]; + for (final (index, value) in cases.indexed) { + final original = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: value.source, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single + .inlines + .single; + expect(original.kind, BusyInlineKind.link); + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf(value.needle), + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + original.destination, + 'https://incoming.test', + original.destination, + ], reason: controller.text); + if (value.source.contains('\ue000')) { + expect(controller.text, contains('\ue000')); + expect(controller.text, contains('%EE%80%80')); + expect(controller.text, isNot(contains('\ue001'))); + expect(controller.text, isNot(contains('%EE%81%81'))); + } + if (index == 0) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets('Source paste preserves parser-folded reference identity', ( + tester, + ) async { + const definition = '[STRASSE]: https://destination.test'; + for (final (index, value) in <({String link, String needle})>[ + (link: '[STRA\u1e9eE][]', needle: 'STRA'), + (link: '[STRA\u1e9eE]', needle: 'STRA'), + (link: '[leftright][STRA\u1e9eE]', needle: 'left'), + ].indexed) { + final source = '${value.link}\n\n$definition\n'; + final before = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + expect( + before.blocks.first.inlines.single.destination, + 'https://destination.test', + ); + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf(value.needle) + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final after = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = after.blocks.first.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect( + RegExp(RegExp.escape('$definition\n')).allMatches(controller.text), + hasLength(1), + ); + expect(controller.text, isNot(contains('\ue000'))); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + if (index < 2) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source same-destination paste preserves parser-folded reference identity', + (tester) async { + const definition = '[STRASSE]: https://destination.test'; + const source = '[STRA\u1e9eE][]\n\n$definition\n'; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://destination.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = const TextSelection.collapsed(offset: 5); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.first.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links, isNotEmpty, reason: controller.text); + expect( + links.map((inline) => inline.destination), + everyElement('https://destination.test'), + ); + expect(links.map((inline) => inline.plainText).join(), 'STRAX\u1e9eE'); + expect(controller.text, endsWith('\n\n$definition\n')); + expect(controller.text, isNot(contains('\ue000'))); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets('Source paste retains the provenance of surviving line breaks', ( + tester, + ) async { + const source = + '> [left\n' + '> middle\r\n' + '> right](https://destination.test)'; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection( + baseOffset: source.indexOf('left') + 'left'.length, + extentOffset: source.indexOf('middle') + 'middle'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[\r\n> right](https://destination.test)', + ); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }); + + testWidgets( + 'Source paste keeps label break provenance independent of link titles', + (tester) async { + const source = + '> [left\n' + '> middle\r\n' + '> right](https://destination.test "first\n' + '> second")'; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection( + baseOffset: source.indexOf('left') + 'left'.length, + extentOffset: source.indexOf('middle') + 'middle'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '> [left](https://destination.test "first second")' + '[X](https://incoming.test)' + '[\r\n> right](https://destination.test "first second")', + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = _sourceBlocksDepthFirst( + parsed.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.paragraph); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + expect(links.first.attributes['title'], 'first\nsecond'); + expect(links.last.attributes['title'], 'first\nsecond'); + expect(links.last.plainText, '\nright'); + expect(parsed.blocks.first.kind, BusyBlockKind.blockquote); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets( + 'normalized code-span breaks do not shift surviving link provenance', + (tester) async { + const source = + '> [left `code\n' + '> span` middle\r\n' + '> right](https://destination.test)'; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection( + baseOffset: source.indexOf('left') + 'left'.length, + extentOffset: source.indexOf('middle') + 'middle'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[\r\n> right](https://destination.test)', + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = _sourceBlocksDepthFirst( + parsed.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.paragraph); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + expect(links.last.plainText, '\nright'); + expect(parsed.blocks.first.kind, BusyBlockKind.blockquote); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets( + 'Source paste combines folded references with surviving break provenance', + (tester) async { + const source = + '> [STRA\n' + '> MIDDLE\r\n' + '> \u1e9eE][]\n' + '\n' + '[STRA MIDDLE SSE]: https://destination.test\n'; + final original = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + final originalLink = _sourceBlocksDepthFirst(original.blocks) + .expand((block) => block.inlines) + .singleWhere((inline) => inline.kind == BusyInlineKind.link); + expect(originalLink.destination, 'https://destination.test'); + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = TextSelection( + baseOffset: source.indexOf('STRA') + 'STRA'.length, + extentOffset: source.indexOf('MIDDLE') + 'MIDDLE'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '> [STRA](https://destination.test)' + '[X](https://incoming.test)' + '[\r\n> \u1e9eE](https://destination.test)\n' + '\n' + '[STRA MIDDLE SSE]: https://destination.test\n', + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = _sourceBlocksDepthFirst(parsed.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + expect(parsed.blocks.first.kind, BusyBlockKind.blockquote); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + }, + ); + + testWidgets('Source paste tracks old and new breaks independently', ( + tester, + ) async { + final cases = + <({String source, bool replace, String incoming, String expected})>[ + ( + source: + '> [left\r\n' + '> middle\n' + '> right](https://destination.test)', + replace: true, + incoming: '[X](https://incoming.test)\n', + expected: + '> [left](https://destination.test)' + '[X](https://incoming.test)' + '[\n> right](https://destination.test)', + ), + ( + source: + '> [left\n' + '> middle\r\n' + '> right](https://destination.test)', + replace: false, + incoming: '[X\nY](https://incoming.test)\n', + expected: + '> [left\n> middle](https://destination.test)' + '[X\n> Y](https://incoming.test)' + '[\r\n> right](https://destination.test)', + ), + ]; + for (final (index, value) in cases.indexed) { + final source = value.source; + final leftEnd = source.indexOf('left') + 'left'.length; + final middleEnd = source.indexOf('middle') + 'middle'.length; + final selection = value.replace + ? TextSelection(baseOffset: leftEnd, extentOffset: middleEnd) + : TextSelection.collapsed(offset: middleEnd); + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: value.incoming.startsWith('[X\n') ? 'X\nY' : 'X', + richFragment: _completeSourceFragment(value.incoming).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final result = undoValue; + undoValue = null; + return result; + }, + ); + controller.selection = selection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, value.expected); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = _sourceBlocksDepthFirst(parsed.blocks) + .expand((block) => block.inlines) + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.first.destination, 'https://destination.test'); + expect(links.last.destination, 'https://destination.test'); + expect(parsed.blocks.single.kind, BusyBlockKind.blockquote); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + if (index == 0) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets('Source reference-link label replacement retains definitions', ( + tester, + ) async { + final cases = <({String link, String definition})>[ + ( + link: '[leftright][dest]', + definition: '[dest]: https://destination.test', + ), + ( + link: '[leftright][]', + definition: '[leftright]: https://destination.test', + ), + ( + link: '[leftright]', + definition: '[leftright]: https://destination.test', + ), + ]; + for (final (index, value) in cases.indexed) { + final source = '${value.link}\n\n${value.definition}\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + ); + final labelStart = source.indexOf('leftright'); + controller.selection = TextSelection( + baseOffset: labelStart, + extentOffset: labelStart + 'leftright'.length, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '[X](https://incoming.test)\n\n${value.definition}\n', + reason: value.link, + ); + expect( + controller.selection.baseOffset, + '[X](https://incoming.test)'.length, + ); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source maps escaped brackets in collapsed and shortcut references', + (tester) async { + final cases = <({String link, String definition})>[ + ( + link: r'[prefix \[ leftright][]', + definition: r'[prefix \[ leftright]: https://destination.test', + ), + ( + link: r'[prefix \[ leftright]', + definition: r'[prefix \[ leftright]: https://destination.test', + ), + ]; + for (final (caseIndex, value) in cases.indexed) { + for (final selectionLength in [0, 'left'.length]) { + final source = '${value.link}\n\n${value.definition}\n'; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + final selectionStart = source.indexOf('left'); + controller.selection = TextSelection( + baseOffset: selectionStart, + extentOffset: selectionStart + selectionLength, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.first.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect( + links.map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + reason: + '${value.link}; selection $selectionLength; ' + '${controller.text}', + ); + expect(links[0].plainText, r'prefix [ '); + expect(links[1].plainText, 'X'); + expect( + links[2].plainText, + selectionLength == 0 ? 'leftright' : 'right', + ); + expect( + RegExp( + RegExp.escape('${value.definition}\n'), + ).allMatches(controller.text), + hasLength(1), + ); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + + if (caseIndex != cases.length - 1 || selectionLength != 4) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + } + }, + ); + + testWidgets('Source maps links around unmatched and code-span backticks', ( + tester, + ) async { + final cases = + < + ({ + String link, + String caretNeedle, + String expectedPlainText, + String expectedLeftLabel, + bool hasCode, + }) + >[ + ( + link: r'literal ` then [leftright](https://destination.test)', + caretNeedle: 'right', + expectedPlainText: r'literal ` then leftXright', + expectedLeftLabel: 'left', + hasCode: false, + ), + ( + link: r'[left`right](https://destination.test)', + caretNeedle: 'right', + expectedPlainText: r'left`Xright', + expectedLeftLabel: r'left`', + hasCode: false, + ), + ( + link: r'[left `code\` right](https://destination.test)', + caretNeedle: 'right', + expectedPlainText: r'left code\ Xright', + expectedLeftLabel: r'left code\ ', + hasCode: true, + ), + ]; + for (final (caseIndex, value) in cases.indexed) { + for (final inTable in [false, true]) { + final source = inTable + ? '| H |\n| --- |\n| ${value.link} |\n' + : value.link; + var transactions = 0; + TextEditingValue? undoValue; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: inTable ? MarkdownMode.gfm : MarkdownMode.commonMark, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment( + '[X](https://incoming.test)\n', + mode: inTable ? MarkdownMode.gfm : MarkdownMode.commonMark, + ).encode(), + ), + ), + onTransactionalChanged: (_, _, previousSelection, _, _) { + transactions += 1; + undoValue = TextEditingValue( + text: source, + selection: previousSelection, + ); + }, + onUndo: () { + final value = undoValue; + undoValue = null; + return value; + }, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf(value.caretNeedle), + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: inTable ? MarkdownMode.gfm : MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final inlines = inTable + ? parsed.blocks.single.children.last.children.single.inlines + : parsed.blocks.single.inlines; + final links = inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect( + inlines.map((inline) => inline.plainText).join(), + value.expectedPlainText, + ); + expect(links[0].plainText, value.expectedLeftLabel); + expect(links[1].plainText, 'X'); + expect(links[2].plainText, 'right'); + if (value.hasCode) { + expect( + links[0].children + .where((inline) => inline.kind == BusyInlineKind.code) + .single + .text, + r'code\', + ); + } + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(transactions, 1); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + + if (caseIndex != cases.length - 1 || !inTable) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + } + }); + + testWidgets('Source maps links with escaped and balanced label brackets', ( + tester, + ) async { + final measurements = []; + debugBusyMarkSourceInlineMappingParseCount = measurements.add; + addTearDown(() => debugBusyMarkSourceInlineMappingParseCount = null); + final escapedBrackets = List.filled(20, r'\[').join(); + final literalBrackets = List.filled(20, '[').join(); + final cases = [ + ( + source: + '[$escapedBrackets' + 'leftright](https://destination.test)', + startText: 'leftright', + selectionLength: 0, + expectedBefore: '${literalBrackets}left', + expectedAfter: 'right', + ), + ( + source: '[prefix [balanced] leftright](https://destination.test)', + startText: 'left', + selectionLength: 'left'.length, + expectedBefore: 'prefix [balanced] ', + expectedAfter: 'right', + ), + ]; + for (final (index, value) in cases.indexed) { + final registry = BusyMarkClipboardInsertionRegistry(); + final fragment = _completeSourceFragment('[X](https://incoming.test)\n'); + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + final selectionStart = + value.source.indexOf(value.startText) + + (value.selectionLength == 0 ? 4 : 0); + controller.selection = TextSelection( + baseOffset: selectionStart, + extentOffset: selectionStart + value.selectionLength, + ); + final payload = BusyMarkClipboardPayload( + id: 'bracket-link-$index', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + measurements.clear(); + expect(registry.canPaste(payload), isTrue); + expect(measurements, isNotEmpty); + + measurements.clear(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final links = parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: controller.text); + expect(links[0].plainText, value.expectedBefore); + expect(links[1].plainText, 'X'); + expect(links[2].plainText, value.expectedAfter); + final incomingEnd = + controller.text.indexOf('[X](https://incoming.test)') + + '[X](https://incoming.test)'.length; + expect(controller.selection.baseOffset, incomingEnd); + expect(measurements, isNotEmpty); + expect(measurements.reduce(math.max), lessThanOrEqualTo(4)); + registry.dispose(); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source inline wrapper mapping stays bounded for paste and availability', + (tester) async { + final measurements = []; + debugBusyMarkSourceInlineMappingParseCount = measurements.add; + addTearDown(() => debugBusyMarkSourceInlineMappingParseCount = null); + final fragment = _completeSourceFragment('**X**\n'); + for (final (index, spanCount) in [10, 60].indexed) { + final source = [ + for (var span = 0; span < spanCount; span++) '**value$span**', + ].join(' gap '); + final registry = BusyMarkClipboardInsertionRegistry(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('value${spanCount ~/ 2}') + 3, + ); + final payload = BusyMarkClipboardPayload( + id: 'mapping-$spanCount', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + measurements.clear(); + expect(registry.canPaste(payload), isTrue); + expect(measurements, isNotEmpty); + expect(measurements.reduce(math.max), lessThanOrEqualTo(4)); + + measurements.clear(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(measurements, isNotEmpty); + expect(measurements.reduce(math.max), lessThanOrEqualTo(4)); + expect(controller.text, contains('valXue${spanCount ~/ 2}')); + registry.dispose(); + if (index + 1 < 2) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + + final surroundingDocument = [ + for (var paragraph = 0; paragraph < 80; paragraph++) + 'Paragraph $paragraph has **bold text** and ' + '[a link](https://example.test/$paragraph).', + ].join('\n\n'); + final largeSource = + '$surroundingDocument\n\n' + 'Target **leftright** paragraph.\n\n' + '$surroundingDocument\n'; + final registry = BusyMarkClipboardInsertionRegistry(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: largeSource, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: largeSource.indexOf('leftright') + 4, + ); + final payload = BusyMarkClipboardPayload( + id: 'mapping-large-document', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + measurements.clear(); + expect(registry.canPaste(payload), isTrue); + expect(measurements, isNotEmpty); + expect(measurements.reduce(math.max), lessThanOrEqualTo(4)); + + measurements.clear(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(measurements, isNotEmpty); + expect(measurements.reduce(math.max), lessThanOrEqualTo(4)); + expect(controller.text, contains('Target **leftXright** paragraph.')); + registry.dispose(); + + for (final codeSpanCount in [10, 20, 30]) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + final codeSpans = List.filled(codeSpanCount, '`**`').join(' '); + final source = '**start $codeSpans leftright $codeSpans end**'; + final registry = BusyMarkClipboardInsertionRegistry(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + final payload = BusyMarkClipboardPayload( + id: 'mapping-code-spans-$codeSpanCount', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + measurements.clear(); + expect(registry.canPaste(payload), isTrue); + expect(measurements, isNotEmpty); + expect( + measurements.reduce(math.max), + lessThanOrEqualTo(4), + reason: 'availability with $codeSpanCount code spans per side', + ); + + measurements.clear(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(measurements, isNotEmpty); + expect( + measurements.reduce(math.max), + lessThanOrEqualTo(4), + reason: 'paste with $codeSpanCount code spans per side', + ); + expect(controller.text, source.replaceFirst('leftright', 'leftXright')); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks.single.inlines.single.kind, BusyInlineKind.strong); + expect( + parsed.blocks.single.inlines.single.children.where( + (inline) => inline.kind == BusyInlineKind.code, + ), + hasLength(codeSpanCount * 2), + ); + registry.dispose(); + } + }, + ); + + testWidgets( + 'Source maps all retained break offsets in one serialization traversal', + (tester) async { + final measurements = []; + final visitedNodes = []; + debugBusyMarkInlineSerializationTraversal = measurements.add; + debugBusyMarkInlineSerializationVisitedNodes = visitedNodes.add; + addTearDown(() { + debugBusyMarkInlineSerializationTraversal = null; + debugBusyMarkInlineSerializationVisitedNodes = null; + }); + for (final (caseIndex, breakCount) in [10, 100, 1000].indexed) { + const destination = 'https://destination.test'; + const incoming = '[X](https://incoming.test)'; + final label = StringBuffer('line0'); + final rawLabel = StringBuffer('line0'); + final surviving = StringBuffer(); + for (var line = 1; line <= breakCount; line++) { + final ending = line.isEven ? '\n' : '\r\n'; + label.write('$ending> line$line'); + rawLabel.write('\nline$line'); + surviving.write('$ending> line$line'); + } + final source = + '> [${label.toString()}]($destination "first\n> second")'; + final fragment = _completeSourceFragment('$incoming\n'); + final registry = BusyMarkClipboardInsertionRegistry(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('line0') + 'line0'.length, + ); + final payload = BusyMarkClipboardPayload( + id: 'break-offsets-$breakCount', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + measurements.clear(); + visitedNodes.clear(); + expect(registry.canPaste(payload), isTrue); + expect(measurements, hasLength(1)); + expect(visitedNodes, hasLength(1)); + expect(visitedNodes.single, lessThan(breakCount * 5 + 20)); + + measurements.clear(); + visitedNodes.clear(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(measurements, hasLength(1)); + expect(visitedNodes, hasLength(1)); + expect(visitedNodes.single, lessThan(breakCount * 5 + 20)); + expect(measurements.single, lessThan(source.length * 3)); + + final expected = + '> [line0]($destination "first second")' + '$incoming' + '[${surviving.toString()}]($destination "first second")'; + expect(controller.text, expected); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + final paragraph = _sourceBlocksDepthFirst( + parsed.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.paragraph); + final links = paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .toList(); + expect(links.map((inline) => inline.destination), [ + destination, + 'https://incoming.test', + destination, + ]); + expect(links.last.plainText, rawLabel.toString().substring(5)); + expect(links.first.attributes['title'], 'first\nsecond'); + expect(links.last.attributes['title'], 'first\nsecond'); + final incomingEnd = controller.text.indexOf(incoming) + incoming.length; + expect(controller.selection.baseOffset, incomingEnd); + registry.dispose(); + if (caseIndex + 1 < 3) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source AST boundary mapping stays linear for availability and paste', + (tester) async { + addTearDown(() => debugBusyMarkSourceMappingBoundaryInspections = null); + final fragment = _completeSourceFragment('[X](https://incoming.test)\n'); + for (final (caseIndex, codeSpanCount) in [10, 100, 1000].indexed) { + final prefix = [ + for (var index = 0; index < codeSpanCount; index++) '`code$index`', + ].join(' '); + final source = '$prefix [leftright](https://destination.test)'; + final registry = BusyMarkClipboardInsertionRegistry(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + registry: registry, + clipboard: _SourceTestClipboard(), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + final payload = BusyMarkClipboardPayload( + id: 'ast-boundaries-$codeSpanCount', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ); + + var inspections = 0; + debugBusyMarkSourceMappingBoundaryInspections = (value) => + inspections += value; + expect(registry.canPaste(payload), isTrue); + expect( + inspections, + lessThanOrEqualTo(codeSpanCount * 8 + 30), + reason: + 'availability with $codeSpanCount spans inspected ' + '$inspections boundaries', + ); + + inspections = 0; + expect(await registry.paste(payload), ClipboardPasteResult.inserted); + expect( + inspections, + lessThanOrEqualTo(codeSpanCount * 16 + 60), + reason: + 'paste with $codeSpanCount spans inspected ' + '$inspections boundaries', + ); + expect(controller.text, startsWith('$prefix ')); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.single.inlines.where( + (inline) => inline.kind == BusyInlineKind.code, + ), + hasLength(codeSpanCount), + ); + expect( + parsed.blocks.single.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + reason: controller.text, + ); + registry.dispose(); + if (caseIndex < 2) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets('Source table paste preserves multiline link titles', ( + tester, + ) async { + const title = 'first\nsecond ©'; + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.gfm, + blocks: const [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'X', + ranges: [], + completeBlock: BusyBlock( + id: 'title-fragment', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline( + kind: BusyInlineKind.link, + text: 'X', + destination: 'https://example.test', + children: [BusyInline(kind: BusyInlineKind.text, text: 'X')], + attributes: {'title': title}, + ), + ], + ), + ), + ], + ); + const source = '| H |\n| --- |\n| gap |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData(text: 'X', richFragment: fragment.encode()), + ), + ); + final gap = source.indexOf('gap'); + controller.selection = TextSelection( + baseOffset: gap, + extentOffset: gap + 3, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text.split('\n'), hasLength(4)); + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(table.children, hasLength(2)); + expect(table.children.last.children, hasLength(1)); + final link = table.children.last.children.single.inlines.single; + expect(link.kind, BusyInlineKind.link); + expect(link.destination, 'https://example.test'); + expect(link.attributes['title'], title); + }); + + testWidgets( + 'Source table boundary paste preserves styles caret and one-step history', + (tester) async { + const source = '| **leftSELECT**tail |\n| --- |\n'; + const expected = '| **leftX**tail |\n| --- |\n'; + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + transactions += 1; + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + ); + final selection = TextSelection( + baseOffset: source.indexOf('SELECT'), + extentOffset: source.indexOf('**tail') + 2, + ); + controller.selection = selection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, expected); + expect( + controller.selection, + TextSelection.collapsed(offset: expected.indexOf('**tail') + 2), + ); + expect(transactions, 1); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final cell = parsed.blocks.single.children.single.children.single; + expect(cell.plainText, 'leftXtail'); + expect(cell.inlines.first.kind, BusyInlineKind.strong); + expect(cell.inlines.first.plainText, 'leftX'); + expect(cell.inlines.last.kind, BusyInlineKind.text); + expect(cell.inlines.last.plainText, 'tail'); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + expect(controller.selection, selection); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, expected); + expect( + controller.selection, + TextSelection.collapsed(offset: expected.indexOf('**tail') + 2), + ); + expect(transactions, 1); + }, + ); + + testWidgets('Source structured inline paste handles every line boundary', ( + tester, + ) async { + final cases = <({String source, int offset, String expected})>[ + (source: '', offset: 0, expected: '**X**'), + (source: '\nright', offset: 0, expected: '**X**\nright'), + (source: '\n\nright', offset: 0, expected: '**X**\n\nright'), + (source: '\r\nright', offset: 0, expected: '**X**\r\nright'), + (source: 'left\nright', offset: 4, expected: 'left**X**\nright'), + (source: 'left\nright', offset: 5, expected: 'left\n**X**right'), + (source: 'right', offset: 5, expected: 'right**X**'), + (source: 'right\n', offset: 6, expected: 'right\n**X**'), + ]; + for (final (index, value) in cases.indexed) { + var transactions = 0; + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + onTransactionalChanged: (_, _, _, _, _) => transactions++, + ); + controller.selection = TextSelection.collapsed(offset: value.offset); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, value.expected, reason: value.source); + expect( + controller.selection.baseOffset, + value.offset + '**X**'.length, + reason: value.source, + ); + expect(transactions, 1, reason: value.source); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source inline paste preserves unrelated syntax whitespace and caret', + (tester) async { + Future paste( + String source, + int offset, + String? fragmentSource, + ) async { + final fragment = fragmentSource == null + ? WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: const [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'X ', + ranges: [], + ), + ], + ) + : _completeSourceFragment(fragmentSource); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed(offset: offset); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + return controller; + } + + var controller = await paste( + 'left __keep__ right', + 'left'.length, + '**X**\n', + ); + expect(controller.text, 'left**X** __keep__ right'); + expect(controller.selection.baseOffset, 'left**X**'.length); + + controller = await paste('**left**right', '**left**'.length, null); + expect(controller.text, '**left**X right'); + expect(controller.selection.baseOffset, '**left**X '.length); + + controller = await paste('__leftright__', '__left'.length, '**X**\n'); + expect(controller.text, '__leftXright__'); + expect(controller.selection.baseOffset, '__leftX'.length); + }, + ); + + testWidgets('Source table cells reconcile surrounding inline styles', ( + tester, + ) async { + const source = '| H |\n| --- |\n| **leftright** |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('left') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '| H |\n| --- |\n| **leftXright** |\n'); + expect(controller.selection.baseOffset, controller.text.indexOf('X') + 1); + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect( + table.children.last.children.single.inlines.single.kind, + BusyInlineKind.strong, + ); + + const indented = ' | H |\n | --- |\n | *leftright* |\n'; + final indentedController = await _pumpClipboardSourceEditor( + tester, + source: indented, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('*X*\n').encode(), + ), + ), + ); + indentedController.selection = TextSelection.collapsed( + offset: indented.indexOf('left') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(indentedController.text, ' | H |\n | --- |\n | *leftXright* |\n'); + }); + + testWidgets('Source reconciliation reuses table-normalized inline content', ( + tester, + ) async { + final cases = <({BusyInlineKind kind, List children})>[ + ( + kind: BusyInlineKind.strong, + children: const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ], + ), + ( + kind: BusyInlineKind.emphasis, + children: const [BusyInline(kind: BusyInlineKind.text, text: 'A\r\nB')], + ), + ]; + for (final (index, value) in cases.indexed) { + final delimiter = value.kind == BusyInlineKind.strong ? '**' : '*'; + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.gfm, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'A\nB', + ranges: const [], + completeBlock: BusyBlock( + id: 'normalized-inline-$index', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline( + kind: value.kind, + text: 'A\nB', + children: value.children, + ), + ], + ), + ), + ], + ); + final source = + '| H |\n' + '| --- |\n' + '| ${delimiter}leftright$delimiter |\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A B', + richFragment: fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '| H |\n' + '| --- |\n' + '| ${delimiter}leftA Bright$delimiter |\n', + ); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks, hasLength(1), reason: controller.text); + final table = parsed.blocks.single; + expect(table.kind, BusyBlockKind.table); + expect(table.children, hasLength(2)); + final cell = table.children.last.children.single; + expect(cell.plainText, 'leftA Bright'); + expect(cell.inlines.single.kind, value.kind); + expect(controller.text.split('\n'), hasLength(4)); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets( + 'Source whole-block replacement differs from surviving table and code contexts', + (tester) async { + final heading = _completeSourceFragment('## Replacement\n'); + const tableSource = '| A | B |\n| --- | --- |\n| one | two |\n'; + final wholeTable = await _pumpClipboardSourceEditor( + tester, + source: tableSource, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Replacement', + richFragment: heading.encode(), + ), + ), + ); + wholeTable.selection = TextSelection( + baseOffset: 0, + extentOffset: tableSource.length, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + var parsed = const MarkdownParser().parse( + filePath: '/project/source.md', + source: wholeTable.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ); + expect( + parsed.busyDocument.blocks.single.kind, + BusyBlockKind.heading, + reason: wholeTable.text, + ); + + final replacementTable = _completeSourceFragment( + '| C | D |\n| --- | --- |\n| three | four |\n', + mode: MarkdownMode.gfm, + ); + final tableWithTable = await _pumpClipboardSourceEditor( + tester, + source: tableSource, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'C D three four', + richFragment: replacementTable.encode(), + ), + ), + ); + tableWithTable.selection = TextSelection( + baseOffset: 0, + extentOffset: tableSource.length, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + parsed = const MarkdownParser().parse( + filePath: '/project/source.md', + source: tableWithTable.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ); + expect(parsed.busyDocument.blocks.single.kind, BusyBlockKind.table); + expect( + parsed.busyDocument.blocks.single.children.last.children.last.plainText, + 'four', + ); + + const codeSource = '```text\nold\n```\n'; + final wholeCode = await _pumpClipboardSourceEditor( + tester, + source: codeSource, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Replacement', + richFragment: heading.encode(), + ), + ), + ); + wholeCode.selection = TextSelection( + baseOffset: 0, + extentOffset: codeSource.length, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + parsed = const MarkdownParser().parse( + filePath: '/project/source.md', + source: wholeCode.text, + validateLocalReferences: false, + ); + expect(parsed.busyDocument.blocks.single.kind, BusyBlockKind.heading); + + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final crossCell = await _pumpClipboardSourceEditor( + tester, + source: tableSource, + markdownMode: MarkdownMode.gfm, + registry: registry, + clipboard: _SourceTestClipboard(), + ); + crossCell.selection = TextSelection( + baseOffset: tableSource.indexOf('one'), + extentOffset: tableSource.indexOf('two') + 3, + ); + await tester.pump(); + final richOnly = BusyMarkClipboardPayload( + id: 'cross-cell-rich-only', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + richFragment: heading.encode(), + ); + expect(registry.canPaste(richOnly), isFalse); + expect(await registry.paste(richOnly), ClipboardPasteResult.unavailable); + expect(crossCell.text, tableSource); + }, + ); + + testWidgets( + 'Source structured paragraph markers escape only at block starts', + (tester) async { + for (final marker in ['# Heading', '> quotation', '- item', '1. item']) { + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: marker, + ranges: const [], + completeBlock: BusyBlock( + id: 'literal-marker', + kind: BusyBlockKind.paragraph, + inlines: [BusyInline(kind: BusyInlineKind.text, text: marker)], + ), + ), + ], + ); + final empty = await _pumpClipboardSourceEditor( + tester, + source: '', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: marker, + richFragment: fragment.encode(), + ), + ), + ); + empty.selection = const TextSelection.collapsed(offset: 0); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + final parsed = const MarkdownParser().parse( + filePath: '/project/source.md', + source: empty.text, + validateLocalReferences: false, + ); + expect(parsed.busyDocument.blocks.single.kind, BusyBlockKind.paragraph); + expect(parsed.busyDocument.blocks.single.plainText, marker); + + final middle = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: marker, + richFragment: fragment.encode(), + ), + ), + ); + middle.selection = const TextSelection.collapsed(offset: 4); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(middle.text, 'left${marker}right'); + } + + final prefixedFragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: const [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: '# Heading', + ranges: [], + ), + ], + ); + for (final value in [ + (source: '> right', offset: 2, kind: BusyBlockKind.blockquote), + (source: '- right', offset: 2, kind: BusyBlockKind.unorderedListItem), + ]) { + final prefixed = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: '# Heading', + richFragment: prefixedFragment.encode(), + ), + ), + ); + prefixed.selection = TextSelection.collapsed(offset: value.offset); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + final parsed = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: prefixed.text, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks.single.kind, value.kind, reason: prefixed.text); + expect( + _sourceBlocksDepthFirst( + parsed.blocks, + ).any((block) => block.plainText == '# Headingright'), + isTrue, + reason: prefixed.text, + ); + expect(prefixed.text, contains(r'\# Heading')); + } + + final plain = await _pumpClipboardSourceEditor( + tester, + source: '', + clipboard: _SourceTestClipboard( + readData: const RichClipboardData(text: '# Heading'), + ), + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV, shift: true); + await tester.pump(); + expect(plain.text, '# Heading'); + }, + ); + + testWidgets('Source native inline paste preserves edge and only whitespace', ( + tester, + ) async { + WysiwygClipboardFragment native( + String text, { + List ranges = const [], + }) => WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: text, + ranges: ranges, + ), + ], + ); + + final trailing = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X ', + richFragment: native('X ').encode(), + generation: 42, + ), + ), + ); + trailing.selection = const TextSelection.collapsed(offset: 4); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(trailing.text, 'leftX right'); + + final styled = await _pumpClipboardSourceEditor( + tester, + source: 'leftright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: ' X ', + richFragment: native( + ' X ', + ranges: const [ + BusyInlineStyleRange( + start: 1, + end: 2, + kind: BusyInlineKind.strong, + ), + ], + ).encode(), + generation: 43, + ), + ), + ); + styled.selection = const TextSelection.collapsed(offset: 4); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(styled.text, 'left **X** right'); + + final whitespace = await _pumpClipboardSourceEditor( + tester, + source: 'leftDELETEright', + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: ' ', + richFragment: native(' ').encode(), + generation: 44, + ), + ), + ); + whitespace.selection = const TextSelection(baseOffset: 4, extentOffset: 10); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(whitespace.text, 'left right'); + }); + + testWidgets( + 'Source native rich edge whitespace repeats and restores real Undo state', + (tester) async { + const source = '[leftright](https://destination.test) tail'; + const fragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + sourcePath: '/clipboard/source.md', + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'Y ', + ranges: [ + BusyInlineStyleRange( + start: 0, + end: 2, + kind: BusyInlineKind.link, + destination: 'https://incoming.test', + ), + ], + completeBlock: BusyBlock( + id: 'native-rich-space', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline( + kind: BusyInlineKind.link, + text: 'Y ', + destination: 'https://incoming.test', + attributes: {'title': 'Incoming title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: 'Y ')], + ), + ], + ), + ), + ], + ); + final clipboard = _SourceTestClipboard( + readData: RichClipboardData( + text: 'PLAIN_FALLBACK', + sourceText: '**SOURCE_FALLBACK**', + html: '

HTML_FALLBACK

', + richFragment: fragment.encode(), + generation: 46, + ), + ); + var modelText = source; + var modelSelection = const TextSelection.collapsed(offset: 0); + var history = const DocumentUndoState(); + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: clipboard, + onTransactionalChanged: + (value, _, previousSelection, selection, undoGroup) { + history = history.push( + DocumentHistoryState( + text: modelText, + selection: previousSelection, + ), + group: undoGroup, + ); + modelText = value; + modelSelection = selection; + }, + onUndo: () { + if (history.undo.isEmpty) return null; + final target = history.undo.last; + history = history.afterUndo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + onRedo: () { + if (history.redo.isEmpty) return null; + final target = history.redo.last; + history = history.afterRedo( + DocumentHistoryState(text: modelText, selection: modelSelection), + ); + modelText = target.text; + modelSelection = target.selection; + return TextEditingValue( + text: target.text, + selection: target.selection, + ); + }, + ); + final initialSelection = TextSelection.collapsed( + offset: source.indexOf('right'), + ); + controller.selection = initialSelection; + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + final firstText = controller.text; + final firstSelection = controller.selection; + expect(firstSelection.isCollapsed, isTrue); + expect(firstText, isNot(contains('PLAIN_FALLBACK'))); + expect(firstText, isNot(contains('SOURCE_FALLBACK'))); + expect(firstText, isNot(contains('HTML_FALLBACK'))); + var paragraph = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: firstText, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(paragraph.plainText, 'leftY right tail', reason: firstText); + expect( + paragraph.inlines + .where((inline) => inline.kind == BusyInlineKind.link) + .map((inline) => inline.destination), + [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], + ); + final editorDocument = const MarkdownParser() + .parse( + filePath: '/project/editor.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + final editorController = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editorController.dispose); + final editorBlock = editorController.document.blocks.single; + expect( + editorController.insertStyledBlocksAtSelection( + blockId: editorBlock.id, + selectionStart: 4, + selectionEnd: 4, + blocks: fragment.blocks, + ), + isNotNull, + ); + final editorParagraph = editorController.document.blocks.single; + expect(editorParagraph.plainText, paragraph.plainText); + final sourceRuns = _inlineSemanticRuns( + paragraph.inlines, + ).where((run) => run.text.trim().isNotEmpty).toList(growable: false); + final editorRuns = _inlineSemanticRuns( + editorParagraph.inlines, + ).where((run) => run.text.trim().isNotEmpty).toList(growable: false); + expect( + sourceRuns.map((run) => run.text.trim()), + editorRuns.map((run) => run.text.trim()), + ); + for (final runs in [sourceRuns, editorRuns]) { + final incoming = runs.singleWhere((run) => run.text.trim() == 'Y'); + expect(incoming.context, contains('underline')); + expect(incoming.context, contains('link:https://incoming.test')); + expect(incoming.context, contains('Incoming title')); + } + expect( + editorRuns + .where( + (run) => run.context.contains('link:https://destination.test'), + ) + .map((run) => run.text.trim()), + ['left', 'right'], + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + final secondText = controller.text; + final secondSelection = controller.selection; + paragraph = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: secondText, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(paragraph.plainText, 'leftY Y right tail', reason: secondText); + expect( + secondSelection.baseOffset, + greaterThan(firstSelection.baseOffset), + ); + + final typedOffset = secondSelection.baseOffset; + final typedText = secondText.replaceRange(typedOffset, typedOffset, 'Z'); + tester.testTextInput.updateEditingValue( + TextEditingValue( + text: typedText, + selection: TextSelection.collapsed(offset: typedOffset + 1), + ), + ); + await tester.pump(); + expect(controller.text, typedText); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, secondText); + expect(controller.selection, secondSelection); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, firstText); + expect(controller.selection, firstSelection); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ); + await tester.pump(); + expect(controller.text, source); + expect(controller.selection, initialSelection); + + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, firstText); + expect(controller.selection, firstSelection); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, secondText); + expect(controller.selection, secondSelection); + await _pressControlKey(tester, LogicalKeyboardKey.keyZ, shift: true); + await tester.pump(); + expect(controller.text, typedText); + expect( + controller.selection, + TextSelection.collapsed(offset: typedOffset + 1), + ); + + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + final reopened = await _pumpClipboardSourceEditor( + tester, + source: secondText, + clipboard: clipboard, + ); + reopened.selection = secondSelection; + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + paragraph = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: reopened.text, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + expect(paragraph.plainText, 'leftY Y Y right tail'); + }, + ); + + testWidgets('Source structured paste respects table-cell semantics', ( + tester, + ) async { + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.gfm, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'A|B', + ranges: const [], + ), + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: 'C\nD', + ranges: const [], + ), + ], + ); + const source = 'before\n\n| H |\n| --- |\n| leftright |\n\nafter\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'A|B C D', + richFragment: fragment.encode(), + generation: 45, + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + 'before\n\n| H |\n| --- |\n| leftA\\|B C Dright |\n\nafter\n', + ); + final parsed = const MarkdownParser().parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ); + expect(parsed.busyDocument.blocks[1].kind, BusyBlockKind.table); + expect( + parsed.busyDocument.blocks[1].children.last.children.single.plainText, + 'leftA|B C Dright', + ); + }); + + testWidgets('Source maps a final table cell ending in an escaped pipe', ( + tester, + ) async { + const source = + '| A | B |\n' + '| --- | --- |\n' + '| left | B\\|'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'X', + richFragment: _completeSourceFragment('**X**\n').encode(), + ), + ), + ); + final selected = source.lastIndexOf('B'); + controller.selection = TextSelection( + baseOffset: selected, + extentOffset: selected + 1, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '| A | B |\n' + '| --- | --- |\n' + '| left | **X**\\|', + ); + expect(controller.selection.baseOffset, controller.text.indexOf('X') + 3); + final table = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument + .blocks + .single; + final cells = table.children.last.children; + expect(cells, hasLength(2)); + expect(cells.first.plainText, 'left'); + expect(cells.last.plainText, 'X|'); + expect(cells.last.inlines.first.kind, BusyInlineKind.strong); + }); + + testWidgets('Source structured blocks preserve list and quote containers', ( + tester, + ) async { + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.heading, + text: 'Heading', + ranges: const [], + attributes: const {'level': '2'}, + ), + ], + ); + for (final value in [ + ('- leftright\n', '- left\n\n ## Heading\n\n right\n'), + ('> leftright\n', '> left\n>\n> ## Heading\n>\n> right\n'), + ]) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.$1, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: fragment.encode(), + generation: 46, + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: value.$1.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(controller.text, value.$2); + } + }); + + testWidgets( + 'Source complete blocks remain in containers at every content boundary', + (tester) async { + final heading = _completeSourceFragment('## Heading\n'); + final cases = <({String source, int offset})>[]; + for (final source in ['> item', '> item\n', '- item', '- item\n']) { + final contentStart = source.indexOf('item'); + for (final relative in [0, 2, 4]) { + cases.add((source: source, offset: contentStart + relative)); + } + } + cases.addAll([ + (source: ' - item', offset: ' - item'.length), + (source: '> 3. item', offset: '> 3. item'.length), + ]); + for (final value in cases) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: heading.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed(offset: value.offset); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final headingPaths = _markdownElementPaths( + md.Document().parse(controller.text), + 'h2', + ); + expect(headingPaths, hasLength(1), reason: controller.text); + expect( + headingPaths.single.any( + (element) => element.tag == 'li' || element.tag == 'blockquote', + ), + isTrue, + reason: 'Heading escaped its container: ${controller.text}', + ); + } + }, + ); + + testWidgets('Source complete blocks retain continuation-line ancestors', ( + tester, + ) async { + final heading = _completeSourceFragment('## Heading\n'); + for (final source in [ + '- first\n leftright\n', + '- first\n\n leftright\n', + '> first\nleftright\n', + ]) { + final contentStart = source.indexOf('leftright'); + for (final relative in [0, 4, 9]) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: heading.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: contentStart + relative, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final headingPaths = _markdownElementPaths( + md.Document().parse(controller.text), + 'h2', + ); + expect(headingPaths, hasLength(1), reason: controller.text); + expect( + headingPaths.single.any( + (element) => element.tag == 'li' || element.tag == 'blockquote', + ), + isTrue, + reason: 'Heading escaped continuation: ${controller.text}', + ); + } + } + }); + + testWidgets( + 'Source container recovery is bound to the actual nested ancestors', + (tester) async { + final heading = _completeSourceFragment('## Heading\n'); + const subtree = + 'Paragraph.\n\n' + '- Outer\n' + ' - Inner\n' + ' leftright\n'; + final prefixes = ['12345. - unrelated\n\n', '', '9. - unrelated\n\n']; + for (final (index, prefix) in prefixes.indexed) { + final source = '$prefix$subtree'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: heading.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect( + controller.text, + '$prefix' + 'Paragraph.\n\n' + '- Outer\n' + ' - Inner\n' + ' left\n' + '\n' + ' ## Heading\n' + '\n' + ' right\n', + reason: prefix, + ); + final headingPaths = _markdownElementPaths( + md.Document().parse(controller.text), + 'h2', + ); + expect(headingPaths, hasLength(1), reason: controller.text); + expect( + headingPaths.single.where((element) => element.tag == 'li'), + hasLength(2), + reason: 'Heading does not belong to Inner under Outer', + ); + expect(RegExp(r'\bright\b').allMatches(controller.text), hasLength(1)); + if (index + 1 < prefixes.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets( + 'Source complete blocks use list markers rather than task prefixes', + (tester) async { + final heading = _completeSourceFragment('## Heading\n'); + final cases = <({String source, String expected, int listDepth})>[ + ( + source: '- [ ] leftright', + expected: + '- [ ] left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + listDepth: 1, + ), + ( + source: '- [x] leftright', + expected: + '- [x] left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + listDepth: 1, + ), + ( + source: '2. [X] leftright', + expected: + '2. [X] left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + listDepth: 1, + ), + ( + source: '- Outer\n - [ ] leftright', + expected: + '- Outer\n' + ' - [ ] left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + listDepth: 2, + ), + ( + source: '0. leftright', + expected: + '0. left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + listDepth: 1, + ), + ]; + for (final (index, value) in cases.indexed) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: heading.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf('leftright') + 4, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, value.expected, reason: value.source); + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final paths = _busyBlockKindPaths( + document.blocks, + BusyBlockKind.heading, + ); + expect(paths, hasLength(1), reason: controller.text); + expect( + paths.single + .where( + (kind) => + kind == BusyBlockKind.taskListItem || + kind == BusyBlockKind.orderedListItem || + kind == BusyBlockKind.unorderedListItem, + ) + .length, + value.listDepth, + reason: controller.text, + ); + if (value.source.contains('[ ]')) { + final task = _sourceBlocksDepthFirst( + document.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.taskListItem); + expect(task.attributes['task'], 'false'); + } + if (value.source.contains('[x]') || value.source.contains('[X]')) { + final task = _sourceBlocksDepthFirst( + document.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.taskListItem); + expect(task.attributes['task'], 'true'); + } + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets('Source task items keep block kinds at every content position', ( + tester, + ) async { + final fragments = [ + ( + fragment: _completeSourceFragment('## Heading\n'), + kind: BusyBlockKind.heading, + text: 'Heading', + ), + ( + fragment: _completeSourceFragment('```text\ncode\n```\n'), + kind: BusyBlockKind.codeBlock, + text: 'code', + ), + ]; + var caseIndex = 0; + for (final value in fragments) { + for (final relativeOffset in [0, 4, 'leftright'.length]) { + if (caseIndex++ > 0) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + const source = '- [ ] leftright'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: value.text, + richFragment: value.fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + relativeOffset, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final task = _sourceBlocksDepthFirst( + document.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.taskListItem); + expect(task.attributes['task'], 'false', reason: controller.text); + final paths = _busyBlockKindPaths(document.blocks, value.kind); + expect(paths, hasLength(1), reason: controller.text); + expect( + paths.single, + contains(BusyBlockKind.taskListItem), + reason: controller.text, + ); + } + } + }); + + testWidgets( + 'Source checked ordered nested and zero lists retain inserted block kinds', + (tester) async { + final heading = _completeSourceFragment('## Heading\n'); + final code = _completeSourceFragment('```text\ncode\n```\n'); + final cases = + < + ({ + String source, + int offset, + WysiwygClipboardFragment fragment, + BusyBlockKind kind, + int depth, + bool? checked, + }) + >[ + ( + source: '- [x] leftright', + offset: 0, + fragment: code, + kind: BusyBlockKind.codeBlock, + depth: 1, + checked: true, + ), + ( + source: '3. [ ] leftright', + offset: 'leftright'.length, + fragment: code, + kind: BusyBlockKind.codeBlock, + depth: 1, + checked: false, + ), + ( + source: '- Outer\n - [x] leftright', + offset: 4, + fragment: code, + kind: BusyBlockKind.codeBlock, + depth: 2, + checked: true, + ), + ( + source: '0. leftright', + offset: 0, + fragment: code, + kind: BusyBlockKind.codeBlock, + depth: 1, + checked: null, + ), + ( + source: '0. leftright', + offset: 'leftright'.length, + fragment: heading, + kind: BusyBlockKind.heading, + depth: 1, + checked: null, + ), + ]; + for (final (index, value) in cases.indexed) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + markdownMode: MarkdownMode.gfm, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: value.kind == BusyBlockKind.heading ? 'Heading' : 'code', + richFragment: value.fragment.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf('leftright') + value.offset, + ); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + final document = const MarkdownParser() + .parse( + filePath: '/project/source.md', + source: controller.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + final paths = _busyBlockKindPaths(document.blocks, value.kind); + expect(paths, hasLength(1), reason: controller.text); + expect( + paths.single + .where( + (kind) => + kind == BusyBlockKind.taskListItem || + kind == BusyBlockKind.orderedListItem || + kind == BusyBlockKind.unorderedListItem, + ) + .length, + value.depth, + reason: controller.text, + ); + if (value.checked != null) { + final task = _sourceBlocksDepthFirst( + document.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.taskListItem); + expect(task.attributes['task'], '${value.checked}'); + } + if (value.source.startsWith('0.')) { + final ordered = document.blocks.single; + expect(ordered.kind, BusyBlockKind.orderedListItem); + expect(ordered.attributes['marker'], '0.'); + } + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }, + ); + + testWidgets('Source composes mixed and continuation container ancestors', ( + tester, + ) async { + final heading = _completeSourceFragment('## Heading\n'); + final cases = <({String source, String expected, List ancestors})>[ + ( + source: '> Outer\n> - Inner\n> leftright', + expected: + '> Outer\n' + '> - Inner\n' + '> left\n' + '>\n' + '> ## Heading\n' + '>\n' + '> right', + ancestors: ['blockquote', 'li'], + ), + ( + source: '- Outer\n > Inner\n > leftright', + expected: + '- Outer\n' + ' > Inner\n' + ' > left\n' + ' >\n' + ' > ## Heading\n' + ' >\n' + ' > right', + ancestors: ['li', 'blockquote'], + ), + ( + source: '- Outer\n\n Later leftright', + expected: + '- Outer\n' + '\n' + ' Later left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + ancestors: ['li'], + ), + ( + source: '- Outer\n - Inner\n\tleftright', + expected: + '- Outer\n' + ' - Inner\n' + '\tleft\n' + '\n' + '\t## Heading\n' + '\n' + '\tright', + ancestors: ['li', 'li'], + ), + ( + source: '12345. Outer\n - Inner\n leftright', + expected: + '12345. Outer\n' + ' - Inner\n' + ' left\n' + '\n' + ' ## Heading\n' + '\n' + ' right', + ancestors: ['li', 'li'], + ), + ( + source: '> Outer\nleftright', + expected: + '> Outer\n' + 'left\n' + '>\n' + '> ## Heading\n' + '>\n' + '> right', + ancestors: ['blockquote'], + ), + ]; + for (final (index, value) in cases.indexed) { + final controller = await _pumpClipboardSourceEditor( + tester, + source: value.source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + richFragment: heading.encode(), + ), + ), + ); + controller.selection = TextSelection.collapsed( + offset: value.source.indexOf('leftright') + 4, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, value.expected, reason: value.source); + final paths = _markdownElementPaths( + md.Document().parse(controller.text), + 'h2', + ); + expect(paths, hasLength(1), reason: controller.text); + expect( + paths.single + .where( + (element) => element.tag == 'li' || element.tag == 'blockquote', + ) + .map((element) => element.tag), + value.ancestors, + reason: controller.text, + ); + expect(RegExp(r'\bright\b').allMatches(controller.text), hasLength(1)); + if (index + 1 < cases.length) { + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + } + }); + + testWidgets('Source protected contexts use the safe source fallback', ( + tester, + ) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + blocks: const [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.heading, + text: 'Heading', + ranges: [], + attributes: {'level': '2'}, + ), + ], + ); + const source = '```text\nleftright\n```\n'; + final controller = await _pumpClipboardSourceEditor( + tester, + source: source, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Heading', + sourceText: '## Heading', + richFragment: fragment.encode(), + ), + ), + registry: registry, + ); + controller.selection = TextSelection.collapsed( + offset: source.indexOf('leftright') + 4, + ); + await tester.pump(); + expect( + registry.canPaste( + BusyMarkClipboardPayload( + id: 'protected-rich-only', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + richFragment: fragment.encode(), + external: true, + ), + ), + isFalse, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + + expect(controller.text, '```text\nleft## Headingright\n```\n'); + }); + + testWidgets('Writerside Source preserves a structured procedure block', ( tester, ) async { - var source = 'local'; - String? changedText; - late StateSetter updateHost; - await tester.pumpWidget( - MaterialApp( - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - home: Scaffold( - body: StatefulBuilder( - builder: (context, setState) { - updateHost = setState; - return BusyMarkSourceEditor( - text: source, - language: SourceSyntaxLanguage.markdown, - filePath: '/project/topic.md', - diagnostics: const [], - editorFontSize: 14, - wordWrap: true, - searchActive: false, - searchOptions: const SourceSearchOptions(), - onSearchOptionsChanged: (_) {}, - onChanged: (text, _) => changedText = text, - onOpenSearch: () {}, - onCloseSearch: () {}, - ); - }, - ), + const procedure = + '

Run.

'; + final parsed = const MarkdownParser().parse( + filePath: '/project/topic.md', + source: '$procedure\n', + mode: MarkdownMode.writersideMarkdown, + validateLocalReferences: false, + ); + final block = parsed.busyDocument.blocks.single; + final fragment = WysiwygClipboardFragment( + mode: MarkdownMode.writersideMarkdown, + blocks: [ + BusyWysiwygStyledBlock( + kind: block.kind, + text: block.plainText, + ranges: busyInlineStyleRanges(block.inlines), + attributes: block.attributes, + completeBlock: busyMarkWysiwygImmutableBlockSnapshot(block), + ), + ], + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'Before', + markdownMode: MarkdownMode.writersideMarkdown, + clipboard: _SourceTestClipboard( + readData: RichClipboardData( + text: 'Deploy Run.', + sourceText: '$procedure\n', + richFragment: fragment.encode(), ), ), ); - final fieldFinder = find.byType(TextField); - await tester.tap(fieldFinder); - expect(tester.widget(fieldFinder).focusNode!.hasFocus, isTrue); + controller.selection = const TextSelection.collapsed(offset: 6); - updateHost(() => source = 'authoritative'); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); await tester.pump(); - expect(tester.widget(fieldFinder).controller!.text, source); - tester.testTextInput.updateEditingValue( - const TextEditingValue( - text: 'authoritative!', - selection: TextSelection.collapsed(offset: 14), - ), + expect(controller.text, 'Before\n\n$procedure\n'); + }); + + testWidgets('Source delayed paste rejects a changed selection', ( + tester, + ) async { + final clipboard = _SourceTestClipboard( + readData: const RichClipboardData(text: 'paste', generation: 3), + delayRead: true, + ); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'abcdef', + clipboard: clipboard, ); + controller.selection = const TextSelection.collapsed(offset: 1); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await clipboard.readStarted.future; + controller.selection = const TextSelection.collapsed(offset: 5); + clipboard.releaseRead(); await tester.pump(); - expect(changedText, 'authoritative!'); + expect(controller.text, 'abcdef'); + expect(clipboard.reads, 1); }); - testWidgets('source keyboard copy retains exact whitespace once', ( + testWidgets('Source paste preserves composition before and during a read', ( tester, ) async { - const source = 'before\n \n\t\nafter\n'; - final clipboard = _SourceTestClipboard(); + final clipboard = _SourceTestClipboard( + readData: const RichClipboardData(text: 'paste', generation: 47), + ); + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); final captures = []; final controller = await _pumpClipboardSourceEditor( tester, - source: source, + source: 'abcdef', clipboard: clipboard, + registry: registry, onCaptured: captures.add, ); - controller.selection = TextSelection( - baseOffset: source.indexOf(' \n'), - extentOffset: source.indexOf('after'), + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'abcdef', + selection: TextSelection.collapsed(offset: 2), + composing: TextRange(start: 1, end: 2), + ), ); - - await _pressControlKey(tester, LogicalKeyboardKey.keyC); await tester.pump(); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await tester.pump(); + expect(clipboard.reads, 0); + expect(controller.text, 'abcdef'); + expect(controller.value.composing, const TextRange(start: 1, end: 2)); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'source-composition-history', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + text: 'history', + external: true, + ), + ), + ClipboardPasteResult.unavailable, + ); - expect(clipboard.writes, hasLength(1)); - expect(clipboard.writes.single.text, ' \n\t\n'); - expect(clipboard.writes.single.sourceText, ' \n\t\n'); - expect(captures, hasLength(1)); - expect(captures.single.sourceText, ' \n\t\n'); + final delayed = _SourceTestClipboard( + readData: const RichClipboardData(text: 'paste', generation: 48), + delayRead: true, + ); + final delayedController = await _pumpClipboardSourceEditor( + tester, + source: 'abcdef', + clipboard: delayed, + onCaptured: captures.add, + ); + delayedController.selection = const TextSelection.collapsed(offset: 2); + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await delayed.readStarted.future; + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'abcdef', + selection: TextSelection.collapsed(offset: 2), + composing: TextRange(start: 1, end: 2), + ), + ); + await tester.pump(); + expect( + delayedController.value.composing, + const TextRange(start: 1, end: 2), + ); + delayed.releaseRead(); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 20)); + expect(delayedController.text, 'abcdef'); + expect(captures, isEmpty); }); testWidgets('source failed cut keeps text and does not record history', ( @@ -1813,8 +8624,26 @@ void main() { sourceText: '**rich**', ); + final sourceOnly = BusyMarkClipboardPayload( + id: 'source-only-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + sourceText: '**source only**', + ); + expect(registry.canPaste(sourceOnly), isTrue); + expect( + registry.canPaste(sourceOnly, mode: BusyMarkPasteMode.plainText), + isFalse, + ); + expect(await registry.paste(payload), ClipboardPasteResult.inserted); expect(changed, 'abc**rich**d'); + controller.selection = const TextSelection.collapsed(offset: 0); + expect( + await registry.paste(payload, mode: BusyMarkPasteMode.plainText), + ClipboardPasteResult.inserted, + ); + expect(changed, 'plainabc**rich**d'); }); testWidgets('structured history rebases retained media into Source', ( @@ -2015,6 +8844,171 @@ void main() { }, ); + testWidgets('Source local image path retains imported bytes once', ( + tester, + ) async { + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-source-path-image-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final original = Uint8List.fromList(const [ + 0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + ]); + final sourceFile = File('${root.path}/original.png'); + await tester.runAsync(() => sourceFile.writeAsBytes(original)); + final clipboard = _SourceTestClipboard( + readData: RichClipboardData(text: sourceFile.path, generation: 42), + ); + final captures = []; + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: clipboard, + onCaptured: captures.add, + filePath: '${root.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + controller.selection = const TextSelection.collapsed(offset: 6); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await _pumpUntil(tester, () => captures.isNotEmpty); + + expect(controller.text, contains('![Image](images/original.png)')); + expect(captures, hasLength(1)); + expect(captures.single.kind, BusyMarkClipboardContentKind.image); + expect(captures.single.text, sourceFile.path); + expect(captures.single.imageBytes, original); + + final capture = captures.single; + final retained = BusyMarkClipboardPayload( + id: 'source-retained-path-image', + acquiredAt: DateTime.utc(2026), + kind: capture.kind, + text: capture.text, + sourceText: capture.sourceText, + html: capture.html, + richFragment: capture.richFragment, + imageBytes: capture.imageBytes, + imageMimeType: capture.imageMimeType, + imageDisplayName: capture.imageDisplayName, + origin: capture.origin, + mediaBytes: capture.mediaBytes, + mediaComplete: capture.mediaComplete, + external: true, + ); + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final replacement = Uint8List.fromList(original); + replacement[replacement.length - 1] ^= 0xff; + await tester.runAsync(() => sourceFile.writeAsBytes(replacement)); + + Future expectNormalReplay(String directoryName) async { + final directory = Directory('${root.path}/$directoryName'); + await tester.runAsync(directory.create); + await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: _SourceTestClipboard(), + registry: registry, + filePath: '${directory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + expect( + await tester.runAsync(() => registry.paste(retained)), + ClipboardPasteResult.inserted, + ); + expect( + await tester.runAsync( + () => File('${directory.path}/images/original.png').readAsBytes(), + ), + original, + ); + } + + await expectNormalReplay('modified-replay'); + await tester.runAsync(sourceFile.delete); + await expectNormalReplay('deleted-replay'); + + final plainDirectory = Directory('${root.path}/plain-replay'); + await tester.runAsync(plainDirectory.create); + final plain = await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: _SourceTestClipboard(), + registry: registry, + filePath: '${plainDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + plain.selection = const TextSelection(baseOffset: 0, extentOffset: 6); + expect( + await registry.paste(retained, mode: BusyMarkPasteMode.plainText), + ClipboardPasteResult.inserted, + ); + expect(plain.text, sourceFile.path); + expect( + await tester.runAsync( + () => Directory('${plainDirectory.path}/images').exists(), + ), + isFalse, + ); + }); + + testWidgets('unsafe local image candidates paste their original text', ( + tester, + ) async { + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-source-path-fallback-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final image = File('${root.path}/image.png'); + final invalidImage = File('${root.path}/invalid.png'); + final textFile = File('${root.path}/notes.txt'); + await tester.runAsync(() async { + await image.writeAsBytes(const [0x89, 0x50, 0x4e, 0x47]); + await invalidImage.writeAsString('not an image'); + await textFile.writeAsString('notes'); + }); + final clipboard = _SourceTestClipboard(); + final values = [ + ' ${root.path}/missing.png ', + invalidImage.path, + textFile.path, + '${image.uri}?download=1', + '${image.uri}#preview', + 'file://remote-host${image.uri.path}', + ]; + for (final value in values) { + clipboard.readData = RichClipboardData(text: value); + final controller = await _pumpClipboardSourceEditor( + tester, + source: 'Target', + clipboard: clipboard, + filePath: '${root.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + controller.selection = const TextSelection( + baseOffset: 0, + extentOffset: 6, + ); + + await _pressControlKey(tester, LogicalKeyboardKey.keyV); + await _pumpUntil(tester, () => controller.text != 'Target'); + + expect(controller.text, value, reason: value); + } + }); + testWidgets('image history asks to save an untitled Source document', ( tester, ) async { @@ -2057,6 +9051,146 @@ void main() { expect(saveRequests, 1); expect(changes, 0); }); + + testWidgets('generic XML does not invent Writerside image syntax', ( + tester, + ) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final controller = await _pumpClipboardSourceEditor( + tester, + source: '', + clipboard: _SourceTestClipboard(), + registry: registry, + documentFormat: SourceDocumentFormat.genericXml, + ); + final payload = BusyMarkClipboardPayload( + id: 'generic-xml-image', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.image, + imageBytes: Uint8List.fromList(const [ + 0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + ]), + imageDisplayName: 'image.png', + ); + + expect(registry.canPaste(payload), isFalse); + expect(await registry.paste(payload), ClipboardPasteResult.unavailable); + expect(controller.text, ''); + }); +} + +WysiwygClipboardFragment _completeSourceFragment( + String source, { + MarkdownMode mode = MarkdownMode.commonMark, +}) { + final document = const MarkdownParser() + .parse( + filePath: '/clipboard/source.md', + source: source, + mode: mode, + validateLocalReferences: false, + ) + .busyDocument; + return WysiwygClipboardFragment( + sourcePath: document.filePath, + mode: document.mode, + blocks: [ + for (final block in document.blocks) + BusyWysiwygStyledBlock( + kind: block.kind, + text: block.plainText, + ranges: busyInlineStyleRanges(block.inlines), + attributes: block.attributes, + completeBlock: busyMarkWysiwygImmutableBlockSnapshot(block), + ), + ], + ); +} + +List> _markdownElementPaths( + Iterable nodes, + String targetTag, [ + List ancestors = const [], +]) { + final paths = >[]; + for (final node in nodes) { + if (node is! md.Element) continue; + final path = [...ancestors, node]; + if (node.tag == targetTag) paths.add(path); + paths.addAll( + _markdownElementPaths(node.children ?? const [], targetTag, path), + ); + } + return paths; +} + +List<({String text, String context})> _inlineSemanticRuns( + List inlines, +) { + final runs = <({String text, String context})>[]; + void append(String text, Iterable contexts) { + if (text.isEmpty) return; + final context = (contexts.toSet().toList()..sort()).join('|'); + if (runs.isNotEmpty && runs.last.context == context) { + final previous = runs.removeLast(); + runs.add((text: previous.text + text, context: context)); + } else { + runs.add((text: text, context: context)); + } + } + + void visit(BusyInline inline, List inherited) { + final own = switch (inline.kind) { + BusyInlineKind.strong => 'strong', + BusyInlineKind.emphasis => 'emphasis', + BusyInlineKind.underline => 'underline', + BusyInlineKind.strikethrough => 'strikethrough', + BusyInlineKind.link => 'link:${inline.destination}:${inline.attributes}', + _ => null, + }; + final contexts = own == null ? inherited : [...inherited, own]; + if (inline.children.isEmpty) { + append(inline.plainText, contexts); + return; + } + for (final child in inline.children) { + visit(child, contexts); + } + } + + for (final inline in inlines) { + visit(inline, const []); + } + return runs; +} + +List> _busyBlockKindPaths( + Iterable blocks, + BusyBlockKind target, [ + List ancestors = const [], +]) { + final paths = >[]; + for (final block in blocks) { + final path = [...ancestors, block.kind]; + if (block.kind == target) paths.add(path); + paths.addAll(_busyBlockKindPaths(block.children, target, path)); + } + return paths; +} + +Iterable _sourceBlocksDepthFirst(Iterable blocks) sync* { + for (final block in blocks) { + yield block; + yield* _sourceBlocksDepthFirst(block.children); + } } WysiwygClipboardFragment _structuredImageFragment(String sourcePath) { @@ -2191,9 +9325,13 @@ Future _pumpClipboardSourceEditor( BusyMarkSourceChanged? onChanged, BusyMarkSourceTransactionalChanged? onTransactionalChanged, TextEditingValue? Function()? onUndo, + TextEditingValue? Function()? onRedo, String? filePath = '/project/source.md', String? workspaceRoot, AssetWorkspaceKind? assetWorkspaceKind, + SourceDocumentFormat documentFormat = SourceDocumentFormat.markdown, + MarkdownMode markdownMode = MarkdownMode.commonMark, + AssetInputService? assetInputService, VoidCallback? onAssetSaveRequired, }) async { await tester.pumpWidget( @@ -2211,10 +9349,13 @@ Future _pumpClipboardSourceEditor( child: BusyMarkSourceEditor( text: source, language: SourceSyntaxLanguage.markdown, + documentFormat: documentFormat, + markdownMode: markdownMode, filePath: filePath, documentId: 'source-document', workspaceRoot: workspaceRoot, assetWorkspaceKind: assetWorkspaceKind, + assetInputService: assetInputService, diagnostics: const [], editorFontSize: 14, wordWrap: true, @@ -2224,6 +9365,7 @@ Future _pumpClipboardSourceEditor( onChanged: onChanged ?? (_, _) {}, onTransactionalChanged: onTransactionalChanged, onUndo: onUndo, + onRedo: onRedo, onOpenSearch: () {}, onCloseSearch: () {}, clipboardService: clipboard, @@ -2243,27 +9385,61 @@ Future _pumpClipboardSourceEditor( Future _pressControlKey( WidgetTester tester, - LogicalKeyboardKey key, -) async { + LogicalKeyboardKey key, { + bool shift = false, +}) async { await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + if (shift) await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); await tester.sendKeyEvent(key); + if (shift) await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft); await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); } +bool _sourceContainsLoneLf(String value) { + for (var index = 0; index < value.length; index++) { + if (value.codeUnitAt(index) == 0x0a && + (index == 0 || value.codeUnitAt(index - 1) != 0x0d)) { + return true; + } + } + return false; +} + class _SourceTestClipboard extends RichClipboardService { - _SourceTestClipboard({this.writeResult = true, this.delayWrite = false}) - : super(channel: const MethodChannel('busymark.test/source-clipboard')); + _SourceTestClipboard({ + this.writeResult = true, + this.delayWrite = false, + this.readData = const RichClipboardData(), + this.delayRead = false, + }) : super(channel: const MethodChannel('busymark.test/source-clipboard')); final bool writeResult; final bool delayWrite; + RichClipboardData readData; + final bool delayRead; final writes = []; + int reads = 0; final writeStarted = Completer(); final _writeRelease = Completer(); + final readStarted = Completer(); + final _readRelease = Completer(); void releaseWrite() { if (!_writeRelease.isCompleted) _writeRelease.complete(); } + void releaseRead() { + if (!_readRelease.isCompleted) _readRelease.complete(); + } + + @override + Future read() async { + reads++; + if (!readStarted.isCompleted) readStarted.complete(); + if (delayRead) await _readRelease.future; + return readData; + } + @override Future write(RichClipboardData data) async { writes.add(data); @@ -2283,6 +9459,27 @@ String? _nativeIcon(List> entries, String label) { as String?; } +int _nativeMenuIndexForLabel( + List> entries, + String label, +) { + var index = 0; + int? visit(List> items) { + for (final item in items) { + final current = index++; + if (item['label'] == label) return current; + final children = item['children']; + if (children is List) { + final found = visit(children.cast>()); + if (found != null) return found; + } + } + return null; + } + + return visit(entries) ?? -1; +} + RenderEditable? _findRenderEditable(RenderObject root) { if (root is RenderEditable) { return root; @@ -2306,3 +9503,42 @@ Future _pumpUntil(WidgetTester tester, bool Function() condition) async { } fail('Timed out waiting for asynchronous Source editor work.'); } + +SpellingOccurrence _sourceSpellingOccurrence({ + required String word, + required int sourceStart, + required int sourceEnd, + required String filePath, +}) { + final run = SpellingProseRun( + id: 'source-fold-$sourceStart', + text: word, + languageId: 'en-Test', + atoms: [ + SpellingSourceAtom( + logicalText: word, + logicalStart: 0, + logicalEnd: word.length, + sourceStart: sourceStart, + sourceEnd: sourceEnd, + transformation: SpellingTransformationKind.identity, + context: SpellingSourceContext.markdownProse, + ), + ], + target: SpellingSourceTarget(filePath: filePath), + snapshot: SpellingSnapshotIdentity( + bufferId: filePath, + contentRevision: 0, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ), + ); + return SpellingOccurrence( + id: 'source-fold-occurrence-$sourceStart', + run: run, + logicalStart: 0, + logicalEnd: word.length, + word: word, + outcome: SpellingCheckOutcome.rejected, + ); +} diff --git a/test/src/source_paste_engine_test.dart b/test/src/source_paste_engine_test.dart new file mode 100644 index 00000000..27daf5a5 --- /dev/null +++ b/test/src/source_paste_engine_test.dart @@ -0,0 +1,2016 @@ +import 'package:busymark/src/editor/source/source_paste_engine.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_ast_adapter.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + const engine = SourcePasteEngine(); + + test('single rich paragraph repairs independently surviving endpoints', () { + final cases = <({String source, int start, int end, String expected})>[ + ( + source: '**leftSELECT**tail', + start: 6, + end: 14, + expected: '**leftX**tail', + ), + ( + source: 'left**SELECTtail**', + start: 2, + end: 10, + expected: 'le**XCTtail**', + ), + ( + source: '**left** middle *right*', + start: 4, + end: 19, + expected: '**leX***ght*', + ), + (source: 'alpha\n\nbeta', start: 2, end: 9, expected: 'al**X**ta'), + ]; + for (final value in cases) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection(baseOffset: value.start, extentOffset: value.end), + ), + fragment: _fragment('**X**\n'), + ), + ); + expect(applied.source, value.expected, reason: value.source); + const caretMarker = '\ue007'; + final marked = _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + caretMarker, + ), + ); + final markedText = _blocksDepthFirst( + marked.blocks, + ).map((block) => block.plainText).join(); + expect(markedText.indexOf(caretMarker), markedText.indexOf('X') + 1); + } + }); + + test('table cells repair independently formatted selection endpoints', () { + final cases = <({String cell, int start, int end, String expected})>[ + ( + cell: '**leftSELECT**tail', + start: '**left'.length, + end: '**leftSELECT**'.length, + expected: '**leftX**tail', + ), + ( + cell: 'left**SELECTtail**', + start: 'left**'.length, + end: 'left**SELECT'.length, + expected: 'left**Xtail**', + ), + ( + cell: '**leftSELECT**middle*SELECTright*', + start: '**left'.length, + end: '**leftSELECT**middle*SELECT'.length, + expected: '**leftX***right*', + ), + ( + cell: '[leftSELECT](https://destination.test)tail', + start: '[left'.length, + end: '[leftSELECT](https://destination.test)'.length, + expected: '[left](https://destination.test)**X**tail', + ), + ]; + for (final value in cases) { + final source = '| ${value.cell} |\n| --- |\n'; + final cellStart = source.indexOf(value.cell); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection( + baseOffset: cellStart + value.start, + extentOffset: cellStart + value.end, + ), + ), + fragment: _fragment('**X**\n'), + ), + ); + expect( + applied.source.split('\n').first, + '| ${value.expected} |', + reason: value.cell, + ); + final cell = _parse( + applied.source, + ).blocks.single.children.first.children.single; + expect(cell.plainText, isNot(contains('SELECT')), reason: applied.source); + expect(_countKind(cell.inlines, BusyInlineKind.strong), greaterThan(0)); + const caretMarker = '\ue008'; + final marked = _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + caretMarker, + ), + ); + expect( + marked.blocks.single.children.first.children.single.plainText, + contains('X$caretMarker'), + reason: applied.source, + ); + } + }); + + test( + 'block insertion replaces only a heading own prefix at content start', + () { + for (final value in [ + (source: '## right', offset: 3, expected: '### New\n\nright'), + (source: '> ## right', offset: 5, expected: '> ### New\n>\n> right'), + (source: '- ## right', offset: 5, expected: '- ### New\n\n right'), + ]) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection.collapsed(offset: value.offset), + ), + fragment: _fragment('### New\n'), + ), + ); + expect(applied.source, value.expected, reason: value.source); + final headings = _blocksDepthFirst( + _parse(applied.source).blocks, + ).where((block) => block.kind == BusyBlockKind.heading).toList(); + expect(headings, hasLength(1), reason: applied.source); + expect(headings.single.attributes['level'], '3'); + expect(headings.single.plainText, 'New'); + } + }, + ); + + test('block insertion removes complete ATX and Setext heading syntax', () { + for (final value in [ + (source: '## right ##', offset: '## '.length), + (source: 'right\n---', offset: 0), + (source: '> ## right ##', offset: '> ## '.length), + (source: '- right\n ---', offset: '- '.length), + ]) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection.collapsed(offset: value.offset), + ), + fragment: _fragment('### New\n'), + ), + ); + final blocks = _blocksDepthFirst(_parse(applied.source).blocks).toList(); + expect( + blocks + .where((block) => block.kind == BusyBlockKind.heading) + .map((block) => (block.attributes['level'], block.plainText)), + [('3', 'New')], + reason: applied.source, + ); + expect( + blocks.where((block) => block.plainText.contains('right')).single.kind, + BusyBlockKind.paragraph, + reason: applied.source, + ); + expect(applied.source, isNot(contains('right ##'))); + expect(applied.source, isNot(contains('right\n---'))); + + final editorDocument = _parse(value.source); + final destination = _blocksDepthFirst( + editorDocument.blocks, + ).firstWhere((block) => block.kind == BusyBlockKind.heading); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final editorResult = editor.insertStyledBlocksAtSelection( + blockId: destination.id, + selectionStart: 0, + selectionEnd: 0, + blocks: _fragment('### New\n').blocks, + ); + expect(editorResult, isNotNull); + expect( + blocks.map( + (block) => (block.kind, block.attributes['level'], block.plainText), + ), + _blocksDepthFirst(editor.document.blocks).map( + (block) => (block.kind, block.attributes['level'], block.plainText), + ), + reason: 'Source: ${applied.source}\nEditor: ${editor.markdown}', + ); + } + }); + + test('block insertion retains literal paragraph hashes', () { + const source = 'right ##'; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target(source, const TextSelection.collapsed(offset: 0)), + fragment: _fragment('### New\n'), + ), + ); + final blocks = _parse(applied.source).blocks; + expect(blocks.map((block) => block.kind), [ + BusyBlockKind.heading, + BusyBlockKind.paragraph, + ]); + expect(blocks.last.plainText, 'right ##'); + }); + + test('whole heading replacement removes every authored marker', () { + final fragment = _fragment('New\n'); + for (final source in ['## Old ##', 'Old\n---']) { + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection(baseOffset: 0, extentOffset: source.length), + ), + fragment: fragment, + ), + ); + final parsed = _parse(applied.source); + expect(parsed.blocks, hasLength(1), reason: applied.source); + expect(parsed.blocks.single.kind, BusyBlockKind.paragraph); + expect(parsed.blocks.single.plainText, 'New'); + + final editorDocument = _parse(source); + final heading = editorDocument.blocks.single; + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final result = editor.replaceTextSelectionWithStyledBlocks( + firstBlockId: heading.id, + firstStartOffset: 0, + lastBlockId: heading.id, + lastEndOffset: heading.plainText.length, + removedBlockIds: [heading.id], + blocks: fragment.blocks, + replacementScope: BusyWysiwygReplacementScope.documentRange, + ); + expect(result, isNotNull); + expect(editor.document.blocks.single.kind, parsed.blocks.single.kind); + expect(editor.document.blocks.single.plainText, 'New'); + } + }); + + test( + 'heading insertion at middle and end preserves only the leading heading', + () { + for (final value in [ + (source: '## left right ##', offset: '## left'.length), + (source: 'left right\n===', offset: 'left right'.length), + ]) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection.collapsed(offset: value.offset), + ), + fragment: _fragment('A\n\nB\n'), + ), + ); + final parsed = _parse(applied.source); + expect( + _blocksDepthFirst( + parsed.blocks, + ).where((block) => block.kind == BusyBlockKind.heading), + hasLength(1), + reason: applied.source, + ); + expect(applied.source, isNot(contains('right ##'))); + expect(applied.source, isNot(contains('right\n==='))); + } + }, + ); + + test('paragraph sequence removes nested heading marker at content start', () { + const source = '> ## right'; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target(source, const TextSelection.collapsed(offset: 5)), + fragment: _fragment('A\n\nB\n'), + ), + ); + final blocks = _blocksDepthFirst(_parse(applied.source).blocks); + expect( + blocks.where((block) => block.kind == BusyBlockKind.heading), + isEmpty, + reason: applied.source, + ); + expect( + blocks + .where((block) => block.kind == BusyBlockKind.paragraph) + .map((block) => block.plainText), + ['A', 'Bright'], + reason: applied.source, + ); + }); + + test('external HTML blockquotes remain structured in Source', () { + for (final html in [ + '

Quoted

', + '

Nested

', + '
  • Listed
', + ]) { + final fragment = const WysiwygClipboardHtml().decode( + html, + mode: MarkdownMode.commonMark, + )!; + final applied = _applyReady( + '', + engine.prepareStructured( + target: _target('', const TextSelection.collapsed(offset: 0)), + fragment: fragment, + ), + ); + expect( + _parse(applied.source).blocks.single.kind, + BusyBlockKind.blockquote, + reason: applied.source, + ); + } + }); + + test('HTML break layout stays behind a caret after the semantic break', () { + const source = + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + final secondBreak = source.indexOf('
', source.indexOf('
') + 1); + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: secondBreak + '
'.length), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + + final applied = _applyReady(source, result); + expect(applied.edit.expectedSource, source); + expect( + applied.edit.caretOffset, + inInclusiveRange(0, applied.source.length), + ); + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'A\n\nYright tail', reason: applied.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + }); + + test( + 'caret immediately before an HTML break keeps the break after paste', + () { + const source = + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + final secondBreak = source.indexOf('
', source.indexOf('
') + 1); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target(source, TextSelection.collapsed(offset: secondBreak)), + fragment: _fragment('[Y](https://incoming.test)\n'), + ), + ); + + expect( + _parse(applied.source).blocks.single.plainText, + 'A\nY\nright tail', + reason: applied.source, + ); + }, + ); + + test('selection crossing an HTML break preserves both outside slices', () { + const source = + 'prefix [left
right
](https://destination.test) suffix'; + final start = source.indexOf('left') + 2; + final end = source.indexOf('right') + 2; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection(baseOffset: start, extentOffset: end), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ), + ); + + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'prefix leYght suffix', reason: applied.source); + expect(applied.source, startsWith('prefix ')); + expect(applied.source, endsWith(' suffix')); + expect(applied.source, isNot(contains('\ue000'))); + expect(applied.source, isNot(contains('\ue001'))); + }); + + test('complete inline HTML survives rich link insertion as one fragment', () { + const source = '[left
right
](https://destination.test) tail'; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed( + offset: source.indexOf('right') + 'ri'.length, + ), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ), + ); + + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'left\nriYght tail', reason: applied.source); + expect(applied.source, isNot(contains('
tail'))); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + expect(_countKind(paragraph.inlines, BusyInlineKind.underline), 3); + expect(_countKind(paragraph.inlines, BusyInlineKind.hardBreak), 1); + }); + + test('native rich trailing space survives inherited HTML insertion', () { + const source = '[leftright](https://destination.test) tail'; + const incomingDestination = 'https://incoming.test'; + const incomingText = 'Y '; + const native = WysiwygClipboardFragment( + mode: MarkdownMode.commonMark, + sourcePath: '/clipboard/source.md', + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: incomingText, + ranges: [ + BusyInlineStyleRange( + start: 0, + end: incomingText.length, + kind: BusyInlineKind.link, + destination: incomingDestination, + ), + ], + completeBlock: BusyBlock( + id: 'clipboard-paragraph', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline( + kind: BusyInlineKind.link, + text: incomingText, + destination: incomingDestination, + children: [ + BusyInline(kind: BusyInlineKind.text, text: incomingText), + ], + ), + ], + ), + ), + ], + ); + final decoded = WysiwygClipboardFragment.decode(native.encode()); + + expect(decoded, isNotNull); + expect(decoded!.blocks.single.text, incomingText); + final prepared = decoded.sourceInsertionInlinesFor(tableCell: false); + expect(prepared.single.kind, BusyInlineKind.link); + expect(prepared.single.plainText, incomingText); + expect(prepared.single.destination, incomingDestination); + + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('right')), + ), + fragment: decoded, + ); + final applied = _applyReady(source, result); + final paragraph = _parse(applied.source).blocks.single; + + expect(paragraph.plainText, 'leftY right tail', reason: applied.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + incomingDestination, + 'https://destination.test', + ], reason: applied.source); + expect( + _links(paragraph.inlines) + .singleWhere((inline) => inline.destination == incomingDestination) + .plainText, + 'Y', + reason: applied.source, + ); + const caretMarker = '\ue002'; + final marked = applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + caretMarker, + ); + expect( + _parse(marked).blocks.single.plainText, + 'leftY ${caretMarker}right tail', + reason: 'replacement: ${applied.edit.replacement}\nsource: $marked', + ); + }); + + test('native incoming edge whitespace survives inherited HTML styles', () { + const incomingDestination = 'https://incoming.test'; + const destination = 'https://destination.test'; + const destinationTitle = 'Destination title'; + const incomingTitle = 'Incoming title'; + final styles = <({String tag, BusyInlineKind kind})>[ + (tag: 'u', kind: BusyInlineKind.underline), + (tag: 'strong', kind: BusyInlineKind.strong), + (tag: 'em', kind: BusyInlineKind.emphasis), + (tag: 's', kind: BusyInlineKind.strikethrough), + ]; + const incomingValues = ['Y ', ' Y', ' Y ', ' ']; + var cases = 0; + + for (final style in styles) { + for (final incomingText in incomingValues) { + for (final tableCell in [false, true]) { + cases += 1; + final link = + '[<${style.tag}>leftright]' + '($destination "$destinationTitle") tail'; + final source = tableCell + ? '| H |\n| --- |\n| $link |\n' + : 'prefix $link suffix'; + final fragment = _nativeFragment([ + BusyInline( + kind: BusyInlineKind.link, + text: incomingText, + destination: incomingDestination, + attributes: const {'title': incomingTitle}, + children: [ + BusyInline(kind: BusyInlineKind.text, text: incomingText), + ], + ), + ]); + final decoded = WysiwygClipboardFragment.decode(fragment.encode()); + + expect(decoded, isNotNull, reason: 'case $cases'); + expect(decoded!.blocks.single.text, incomingText); + expect( + decoded + .sourceInsertionInlinesFor(tableCell: tableCell) + .map((inline) => inline.plainText) + .join(), + incomingText, + ); + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('right')), + ), + fragment: decoded, + ); + expect(result, isA(), reason: 'case $cases'); + final applied = _applyReady(source, result); + final paragraph = _contentParagraph(_parse(applied.source)); + final expectedText = tableCell + ? 'left${incomingText}right tail' + : 'prefix left${incomingText}right tail suffix'; + + expect( + paragraph.plainText, + expectedText, + reason: 'case $cases: ${applied.source}', + ); + expect( + applied.source.substring(0, applied.edit.start), + source.substring(0, applied.edit.start), + ); + expect( + applied.source.substring( + applied.edit.start + applied.edit.replacement.length, + ), + source.substring(applied.edit.end), + ); + final links = _links(paragraph.inlines); + expect( + links + .where((inline) => inline.destination == destination) + .map((inline) => inline.attributes['title']), + everyElement(destinationTitle), + reason: applied.source, + ); + final incomingLinks = links.where( + (inline) => inline.destination == incomingDestination, + ); + if (incomingText.trim().isEmpty) { + expect(incomingLinks.length, lessThanOrEqualTo(1)); + if (incomingLinks.isNotEmpty) { + expect(incomingLinks.single.plainText, incomingText); + expect(incomingLinks.single.attributes['title'], incomingTitle); + } + } else { + expect(incomingLinks, hasLength(1), reason: applied.source); + expect(incomingLinks.single.plainText.trim(), 'Y'); + expect(incomingLinks.single.attributes['title'], incomingTitle); + expect( + _leafContexts( + paragraph.inlines, + ).where((run) => run.text.trim() == 'Y').single.contexts, + containsAll([style.kind, BusyInlineKind.link]), + reason: applied.source, + ); + } + if (incomingText.trim().isEmpty || + style.kind != BusyInlineKind.underline) { + final localCaret = applied.edit.caretOffset - applied.edit.start; + expect( + localCaret, + inInclusiveRange(0, applied.edit.replacement.length), + reason: 'case $cases: ${applied.edit.replacement}', + ); + if (incomingText.trim().isEmpty && + style.kind == BusyInlineKind.underline) { + expect( + applied.edit.replacement.substring(0, localCaret), + endsWith(incomingText), + reason: 'case $cases: ${applied.edit.replacement}', + ); + } + } else { + final second = _applyReady( + applied.source, + engine.prepareStructured( + target: _target( + applied.source, + TextSelection.collapsed(offset: applied.edit.caretOffset), + ), + fragment: _nativeFragment(const [ + BusyInline( + kind: BusyInlineKind.link, + text: 'Z', + destination: 'https://second.test', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'Z'), + ], + ), + ]), + ), + ); + expect( + _contentParagraph(_parse(second.source)).plainText, + expectedText.replaceFirst( + '${incomingText}right', + '${incomingText}Zright', + ), + reason: 'case $cases: ${second.source}', + ); + expect( + _destinations(_contentParagraph(_parse(second.source)).inlines), + contains('https://second.test'), + ); + } + } + } + } + expect(cases, 32); + }); + + test('selection replacement retains native whitespace and link titles', () { + const source = + 'prefix [leftmiddleright]' + '(https://destination.test "Destination title") tail suffix'; + const incomingText = ' Y '; + final start = source.indexOf('middle'); + final end = start + 'middle'.length; + final fragment = _nativeFragment(const [ + BusyInline( + kind: BusyInlineKind.link, + text: incomingText, + destination: 'https://incoming.test', + attributes: {'title': 'Incoming title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: incomingText)], + ), + ]); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection(baseOffset: start, extentOffset: end), + ), + fragment: WysiwygClipboardFragment.decode(fragment.encode())!, + ), + ); + final paragraph = _parse(applied.source).blocks.single; + + expect(paragraph.plainText, 'prefix left Y right tail suffix'); + expect( + _links( + paragraph.inlines, + ).map((inline) => (inline.destination, inline.attributes['title'])), + [ + ('https://destination.test', 'Destination title'), + ('https://incoming.test', 'Incoming title'), + ('https://destination.test', 'Destination title'), + ], + reason: applied.source, + ); + const marker = '\ue002'; + expect( + _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + marker, + ), + ).blocks.single.plainText, + 'prefix left Y ${marker}right tail suffix', + ); + }); + + test('multiple native inline runs retain text styles links and spaces', () { + const source = + '[leftright]' + '(https://destination.test "Destination title") tail'; + final fragment = _nativeFragment(const [ + BusyInline( + kind: BusyInlineKind.link, + text: 'A ', + destination: 'https://first.test', + attributes: {'title': 'First title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: 'A ')], + ), + BusyInline( + kind: BusyInlineKind.strong, + text: 'B ', + children: [BusyInline(kind: BusyInlineKind.text, text: 'B ')], + ), + BusyInline( + kind: BusyInlineKind.link, + text: 'C', + destination: 'https://second.test', + attributes: {'title': 'Second title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: 'C')], + ), + ]); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('right')), + ), + fragment: WysiwygClipboardFragment.decode(fragment.encode())!, + ), + ); + final paragraph = _parse(applied.source).blocks.single; + + expect(paragraph.plainText, 'leftA B Cright tail', reason: applied.source); + expect( + _links( + paragraph.inlines, + ).map((inline) => (inline.destination, inline.attributes['title'])), + [ + ('https://destination.test', 'Destination title'), + ('https://first.test', 'First title'), + ('https://second.test', 'Second title'), + ('https://destination.test', 'Destination title'), + ], + reason: applied.source, + ); + final contexts = _leafContexts(paragraph.inlines); + expect( + contexts.singleWhere((run) => run.text.trim() == 'A').contexts, + containsAll([BusyInlineKind.underline, BusyInlineKind.link]), + ); + expect( + contexts.singleWhere((run) => run.text.trim() == 'B').contexts, + containsAll([BusyInlineKind.underline, BusyInlineKind.strong]), + ); + expect( + contexts.singleWhere((run) => run.text.trim() == 'C').contexts, + containsAll([BusyInlineKind.underline, BusyInlineKind.link]), + ); + const marker = '\ue002'; + expect( + _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + marker, + ), + ).blocks.single.plainText, + 'leftA B C${marker}right tail', + ); + }); + + test('rich insertion maps collapsed HTML whitespace as content', () { + final fixtures = <({String source, int caret})>[ + ( + source: + '[left right]' + '(https://destination.test) tail', + caret: '[left '.length, + ), + ( + source: + '[left \t right]' + '(https://destination.test) tail', + caret: '[left \t'.length, + ), + ( + source: + '[left \r\n\t right]' + '(https://destination.test) tail', + caret: '[left \r\n'.length, + ), + ]; + + for (final fixture in fixtures) { + final result = engine.prepareStructured( + target: _target( + fixture.source, + TextSelection.collapsed(offset: fixture.caret), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + expect(result, isA(), reason: fixture.source); + final applied = _applyReady(fixture.source, result); + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'left Yright tail', reason: applied.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: applied.source); + expect(_countKind(paragraph.inlines, BusyInlineKind.underline), 3); + expect( + applied.source, + contains( + '[left](https://destination.test) ' + '[Y](https://incoming.test)', + ), + ); + final incomingEnd = + applied.source.indexOf('https://incoming.test') + + 'https://incoming.test'.length + + 1; + expect(applied.edit.caretOffset, incomingEnd); + expect(applied.source, endsWith(' tail')); + } + }); + + test('collapsed whitespace maps through supported raw HTML styles', () { + final fixtures = <({String tag, BusyInlineKind kind})>[ + (tag: 'u', kind: BusyInlineKind.underline), + (tag: 'strong', kind: BusyInlineKind.strong), + (tag: 'em', kind: BusyInlineKind.emphasis), + (tag: 's', kind: BusyInlineKind.strikethrough), + ]; + for (final fixture in fixtures) { + final source = + '[<${fixture.tag}>left right]' + '(https://destination.test) tail'; + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('left') + 5), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + + final applied = _applyReady(source, result); + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'left Yright tail', reason: applied.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: applied.source); + expect(_countKind(paragraph.inlines, fixture.kind), 3); + } + }); + + test('collapsed whitespace maps through a supported raw HTML link', () { + const source = 'left right tail'; + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('left') + 5), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + + final applied = _applyReady(source, result); + final paragraph = _parse(applied.source).blocks.single; + expect(paragraph.plainText, 'left Yright tail', reason: applied.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ], reason: applied.source); + }); + + test('supported content corpus always plans a rich insertion', () { + const incomingDestination = 'https://incoming.test'; + final contents = <({String value, int position})>[ + (value: 'plain', position: 2), + (value: 'white space', position: 5), + (value: 'white space', position: 'white '.length), + (value: 'Straße', position: 4), + (value: '😀 value', position: 5), + (value: r'escaped \* value', position: r'escaped \* val'.length), + (value: 'entity & value', position: 'entity & val'.length), + ]; + final wrappers = [ + (value) => value, + (value) => '**$value**', + (value) => '*$value*', + (value) => '~~$value~~', + (value) => '[$value](https://destination.test "Title")', + (value) => '$value', + (value) => '$value', + (value) => '$value', + (value) => '$value', + (value) => '$value
tail
', + ]; + + var cases = 0; + for (final wrap in wrappers) { + for (final content in contents) { + cases += 1; + final source = 'prefix ${wrap(content.value)} suffix'; + final position = source.indexOf(content.value) + content.position; + final result = engine.prepareStructured( + target: _target(source, TextSelection.collapsed(offset: position)), + fragment: _fragment('[Y]($incomingDestination)\n'), + ); + + expect( + result, + isA(), + reason: 'case $cases: $source at $position', + ); + final applied = _applyReady(source, result); + final parsed = _parse(applied.source); + expect(applied.source, startsWith('prefix ')); + expect(applied.source, endsWith(' suffix')); + expect( + _destinations(parsed.blocks.single.inlines), + contains(incomingDestination), + reason: 'case $cases: ${applied.source}', + ); + if (source.contains('https://destination.test')) { + expect( + _destinations(parsed.blocks.single.inlines), + contains('https://destination.test'), + reason: 'case $cases: ${applied.source}', + ); + } + if (source.contains('"Title"')) { + expect( + _links(parsed.blocks.single.inlines) + .where( + (inline) => inline.destination == 'https://destination.test', + ) + .map((inline) => inline.attributes['title']), + everyElement('Title'), + reason: 'case $cases: ${applied.source}', + ); + } + final incomingEnd = + applied.source.indexOf(incomingDestination) + + incomingDestination.length + + 1; + expect( + applied.edit.caretOffset, + incomingEnd, + reason: 'case $cases: ${applied.source}', + ); + } + } + expect(cases, 70); + }); + + test('repeated mapped siblings avoid fallback and preserve final paste', () { + addTearDown(() { + debugBusyMarkSourceMappingBoundaryInspections = null; + debugBusyMarkSourceMappingFallbackSearchCalls = null; + debugBusyMarkSourceMappingFallbackSearchRanges = null; + }); + const segment = r'**x** \[ '; + for (final count in [10, 100, 1000]) { + final prefix = List.filled(count, segment).join(); + final source = '$prefix[leftright](https://destination.test)'; + var inspections = 0; + var fallbackCalls = 0; + final fallbackRanges = <({int start, int end})>[]; + debugBusyMarkSourceMappingBoundaryInspections = (value) => + inspections += value; + debugBusyMarkSourceMappingFallbackSearchCalls = () => fallbackCalls += 1; + debugBusyMarkSourceMappingFallbackSearchRanges = (start, end) => + fallbackRanges.add((start: start, end: end)); + final first = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('right')), + ), + fragment: _nativeFragment(const [ + BusyInline( + kind: BusyInlineKind.link, + text: 'Q', + destination: 'https://incoming.test', + attributes: {'title': 'Incoming title'}, + children: [BusyInline(kind: BusyInlineKind.text, text: 'Q')], + ), + ]), + ), + ); + + expect(first.source, startsWith(prefix), reason: '$count repetitions'); + final firstParagraph = _parse(first.source).blocks.single; + expect( + firstParagraph.plainText, + '${List.filled(count, 'x [ ').join()}leftQright', + ); + expect( + _links( + firstParagraph.inlines, + ).map((inline) => (inline.destination, inline.attributes['title'])), + [ + ('https://destination.test', null), + ('https://incoming.test', 'Incoming title'), + ('https://destination.test', null), + ], + ); + final second = _applyReady( + first.source, + engine.prepareStructured( + target: _target( + first.source, + TextSelection.collapsed(offset: first.edit.caretOffset), + ), + fragment: _nativeFragment(const [ + BusyInline( + kind: BusyInlineKind.link, + text: 'R', + destination: 'https://second.test', + children: [BusyInline(kind: BusyInlineKind.text, text: 'R')], + ), + ]), + ), + ); + expect(second.source, startsWith(prefix)); + expect( + _parse(second.source).blocks.single.plainText, + '${List.filled(count, 'x [ ').join()}leftQRright', + ); + expect(second.edit.caretOffset, greaterThan(first.edit.caretOffset)); + expect(fallbackCalls, 0, reason: '$count repetitions'); + expect(fallbackRanges, isEmpty, reason: '$count repetitions'); + expect(inspections, greaterThan(0)); + } + }); + + test('complete blocks split and preserve enclosing inline contexts', () { + final destinations = + < + ({String source, int caret, BusyInlineKind kind, String? destination}) + >[ + ( + source: 'prefix **leftright** suffix', + caret: 'prefix **left'.length, + kind: BusyInlineKind.strong, + destination: null, + ), + ( + source: 'prefix *leftright* suffix', + caret: 'prefix *left'.length, + kind: BusyInlineKind.emphasis, + destination: null, + ), + ( + source: + 'prefix [leftright](https://destination.test "Title") suffix', + caret: 'prefix [left'.length, + kind: BusyInlineKind.link, + destination: 'https://destination.test', + ), + ]; + final fragments = + < + ({WysiwygClipboardFragment fragment, BusyBlockKind kind, String text}) + >[ + ( + fragment: _fragment('## Heading\n'), + kind: BusyBlockKind.heading, + text: 'Heading', + ), + ( + fragment: _fragment('- Item\n'), + kind: BusyBlockKind.unorderedListItem, + text: 'Item', + ), + ( + fragment: _fragment('```text\ncode\n```\n'), + kind: BusyBlockKind.codeBlock, + text: 'code', + ), + ]; + + for (final destination in destinations) { + for (final inserted in fragments) { + final applied = _applyReady( + destination.source, + engine.prepareStructured( + target: _target( + destination.source, + TextSelection.collapsed(offset: destination.caret), + ), + fragment: inserted.fragment, + ), + ); + final document = _parse(applied.source); + final editorDocument = _parse(destination.source); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final editorResult = editor.insertStyledBlocksAtSelection( + blockId: editorDocument.blocks.single.id, + selectionStart: 'prefix left'.length, + selectionEnd: 'prefix left'.length, + blocks: inserted.fragment.blocks, + ); + expect(editorResult, isNotNull); + expect( + _documentSemanticSignature(document), + _documentSemanticSignature(editor.document), + reason: 'Source: ${applied.source}\nEditor: ${editor.markdown}', + ); + expect(document.blocks, hasLength(3), reason: applied.source); + expect(document.blocks[0].plainText, 'prefix left'); + expect(document.blocks[1].kind, inserted.kind); + expect(document.blocks[1].plainText, inserted.text); + expect(document.blocks[2].plainText, 'right suffix'); + for (final block in [document.blocks.first, document.blocks.last]) { + expect( + _countKind(block.inlines, destination.kind), + 1, + reason: applied.source, + ); + if (destination.destination case final value?) { + final link = _links(block.inlines).single; + expect(link.destination, value); + expect(link.attributes['title'], 'Title'); + } + } + expect(applied.source, startsWith('prefix ')); + expect(applied.source, endsWith(' suffix')); + + const marker = '\ue003'; + final marked = _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + marker, + ), + ); + expect(marked.blocks[2].plainText, '${marker}right suffix'); + expect( + _countKind(marked.blocks[2].inlines, destination.kind), + 1, + reason: applied.source, + ); + } + } + }); + + test('paragraph-only block sequences match Editor merge semantics', () { + final fragments = [ + _fragment('*A*\n\n[B](https://incoming.test "B title")\n'), + _fragment('*A*\n\n`C`\n\n[B](https://incoming.test "B title")\n'), + ]; + final selections = <({int start, int end})>[ + (start: 0, end: 0), + (start: 4, end: 4), + (start: 9, end: 9), + (start: 3, end: 6), + ]; + + for (final fragment in fragments) { + for (final selection in selections) { + const source = '**leftright**'; + final sourceSelection = TextSelection( + baseOffset: 2 + selection.start, + extentOffset: 2 + selection.end, + ); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target(source, sourceSelection), + fragment: fragment, + ), + ); + final sourceDocument = _parse(applied.source); + + final editorDocument = _parse(source); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final result = editor.insertStyledBlocksAtSelection( + blockId: editorDocument.blocks.single.id, + selectionStart: selection.start, + selectionEnd: selection.end, + blocks: fragment.blocks, + ); + expect(result, isNotNull); + final insertion = result!; + expect( + _documentSemanticSignature(sourceDocument), + _documentSemanticSignature(editor.document), + reason: + 'selection $selection\nSource: ${applied.source}\n' + 'Editor: ${editor.markdown}', + ); + + const marker = '\ue004'; + final marked = _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + marker, + ), + ); + final markedBlockIndex = marked.blocks.indexWhere( + (block) => block.plainText.contains(marker), + ); + final editorBlockIndex = editor.document.blocks.indexWhere( + (block) => block.id == insertion.blockId, + ); + expect(markedBlockIndex, editorBlockIndex, reason: applied.source); + expect( + marked.blocks[markedBlockIndex].plainText.indexOf(marker), + insertion.offset, + reason: applied.source, + ); + } + } + }); + + test('block paste preserves independent formatted selection boundaries', () { + final fragments = [ + _fragment('## Heading\n'), + _fragment('`A`\n\n[B](https://incoming.test "Incoming")\n'), + ]; + final cases = + < + ({ + String source, + int sourceStart, + int sourceEnd, + int editorStart, + int editorEnd, + }) + >[ + ( + source: '**leftSELECT**tail', + sourceStart: '**left'.length, + sourceEnd: '**leftSELECT**'.length, + editorStart: 'left'.length, + editorEnd: 'leftSELECT'.length, + ), + ( + source: '*leftSELECT*tail', + sourceStart: '*left'.length, + sourceEnd: '*leftSELECT*'.length, + editorStart: 'left'.length, + editorEnd: 'leftSELECT'.length, + ), + ( + source: '[leftSELECT](https://destination.test "Title")tail', + sourceStart: '[left'.length, + sourceEnd: '[leftSELECT](https://destination.test "Title")'.length, + editorStart: 'left'.length, + editorEnd: 'leftSELECT'.length, + ), + ( + source: 'headSELECT**RIGHTtail**', + sourceStart: 'head'.length, + sourceEnd: 'headSELECT**RIGHT'.length, + editorStart: 'head'.length, + editorEnd: 'headSELECTRIGHT'.length, + ), + ( + source: 'headSELECT*RIGHTtail*', + sourceStart: 'head'.length, + sourceEnd: 'headSELECT*RIGHT'.length, + editorStart: 'head'.length, + editorEnd: 'headSELECTRIGHT'.length, + ), + ( + source: 'headSELECT[RIGHTtail](https://destination.test "Title")', + sourceStart: 'head'.length, + sourceEnd: 'headSELECT[RIGHT'.length, + editorStart: 'head'.length, + editorEnd: 'headSELECTRIGHT'.length, + ), + ( + source: '**leftSELECT**middle*SELECTright*', + sourceStart: '**left'.length, + sourceEnd: '**leftSELECT**middle*SELECT'.length, + editorStart: 'left'.length, + editorEnd: 'leftSELECTmiddleSELECT'.length, + ), + ]; + + for (final value in cases) { + for (final fragment in fragments) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection( + baseOffset: value.sourceStart, + extentOffset: value.sourceEnd, + ), + ), + fragment: fragment, + ), + ); + if (value.source == '**leftSELECT**tail' && + fragment.blocks.length == 1 && + fragment.blocks.first.kind == BusyBlockKind.heading) { + expect(applied.source, '**left**\n\n## Heading\n\ntail'); + } + final editorDocument = _parse(value.source); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final result = editor.insertStyledBlocksAtSelection( + blockId: editorDocument.blocks.single.id, + selectionStart: value.editorStart, + selectionEnd: value.editorEnd, + blocks: fragment.blocks, + ); + expect(result, isNotNull); + _expectSourceEditorParity( + applied, + editor, + result!.blockId, + result.offset, + ); + } + } + }); + + test('structured paste spans partial first and last destination blocks', () { + final fragments = [ + _fragment('## Heading\n'), + _fragment('*A*\n\nM\n\n[B](https://incoming.test "Incoming")\n'), + ]; + final cases = + < + ({ + String source, + int sourceStart, + int sourceEnd, + int editorStart, + int editorEnd, + }) + >[ + ( + source: 'alpha\n\nbeta', + sourceStart: 2, + sourceEnd: 9, + editorStart: 2, + editorEnd: 2, + ), + ( + source: 'alpha\n\n## middle\n\nbeta', + sourceStart: 2, + sourceEnd: 'alpha\n\n## middle\n\nbe'.length, + editorStart: 2, + editorEnd: 2, + ), + ( + source: '**alpha**\n\nmid\n\n*beta*', + sourceStart: '**al'.length, + sourceEnd: '**alpha**\n\nmid\n\n*be'.length, + editorStart: 2, + editorEnd: 2, + ), + ]; + + for (final value in cases) { + for (final fragment in fragments) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection( + baseOffset: value.sourceStart, + extentOffset: value.sourceEnd, + ), + ), + fragment: fragment, + ), + ); + final editorDocument = _parse(value.source); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final result = editor.replaceTextSelectionWithStyledBlocks( + firstBlockId: editorDocument.blocks.first.id, + firstStartOffset: value.editorStart, + lastBlockId: editorDocument.blocks.last.id, + lastEndOffset: value.editorEnd, + removedBlockIds: [ + for (final block in editorDocument.blocks) block.id, + ], + blocks: fragment.blocks, + ); + expect(result, isNotNull); + _expectSourceEditorParity( + applied, + editor, + result!.blockId, + result.offset, + ); + } + } + }); + + test('paragraph sequences retain destination block and container paths', () { + final fragments = [ + _fragment('`A`\n\n[B](https://incoming.test "Incoming")\n'), + _fragment('`A`\n\nM\n\n[B](https://incoming.test "Incoming")\n'), + ]; + final cases = + < + ({ + String source, + int sourceOffset, + int editorOffset, + String targetText, + }) + >[ + ( + source: '> leftright', + sourceOffset: '> left'.length, + editorOffset: 'left'.length, + targetText: 'leftright', + ), + ( + source: '## leftright', + sourceOffset: '## '.length, + editorOffset: 0, + targetText: 'leftright', + ), + ( + source: '## leftright', + sourceOffset: '## left'.length, + editorOffset: 'left'.length, + targetText: 'leftright', + ), + ( + source: '## leftright', + sourceOffset: '## leftright'.length, + editorOffset: 'leftright'.length, + targetText: 'leftright', + ), + ( + source: '- leftright\n - child', + sourceOffset: '- '.length, + editorOffset: 0, + targetText: 'leftright', + ), + ( + source: '- leftright\n - child', + sourceOffset: '- left'.length, + editorOffset: 'left'.length, + targetText: 'leftright', + ), + ( + source: '- leftright\n - child', + sourceOffset: '- leftright'.length, + editorOffset: 'leftright'.length, + targetText: 'leftright', + ), + ( + source: '1. leftright\n - child', + sourceOffset: '1. left'.length, + editorOffset: 'left'.length, + targetText: 'leftright', + ), + ( + source: '- [ ] leftright\n - child', + sourceOffset: '- [ ] left'.length, + editorOffset: 'left'.length, + targetText: 'leftright', + ), + ]; + + for (final value in cases) { + for (final fragment in fragments) { + final applied = _applyReady( + value.source, + engine.prepareStructured( + target: _target( + value.source, + TextSelection.collapsed(offset: value.sourceOffset), + ), + fragment: fragment, + ), + ); + final editorDocument = _parse(value.source); + final targetBlock = _blocksDepthFirst( + editorDocument.blocks, + ).firstWhere((block) => block.plainText == value.targetText); + final editor = BusyMarkWysiwygDocumentController( + document: editorDocument, + ); + addTearDown(editor.dispose); + final result = editor.insertStyledBlocksAtSelection( + blockId: targetBlock.id, + selectionStart: value.editorOffset, + selectionEnd: value.editorOffset, + blocks: fragment.blocks, + ); + expect(result, isNotNull); + _expectSourceEditorParity( + applied, + editor, + result!.blockId, + result.offset, + ); + } + } + }); + + test('paste output is valid input for a second paste at returned caret', () { + const source = + '[A\n' + '
\n' + '
\n' + 'right](https://destination.test) tail'; + final secondBreak = source.indexOf('
', source.indexOf('
') + 1); + final first = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: secondBreak + '
'.length), + ), + fragment: _fragment('[Y](https://first.test)\n'), + ), + ); + final second = _applyReady( + first.source, + engine.prepareStructured( + target: _target( + first.source, + TextSelection.collapsed(offset: first.edit.caretOffset), + ), + fragment: _fragment('[Z](https://second.test)\n'), + ), + ); + + final paragraph = _parse(second.source).blocks.single; + expect(paragraph.plainText, 'A\n\nYZright tail', reason: second.source); + expect(_destinations(paragraph.inlines), [ + 'https://destination.test', + 'https://first.test', + 'https://second.test', + 'https://destination.test', + ]); + expect(second.edit.caretOffset, greaterThan(first.edit.caretOffset)); + }); + + test('CRLF blockquote projection retains its authored prefixes', () { + const source = + '> [A\r\n' + '>
\r\n' + '>
\r\n' + '> right](https://destination.test) tail'; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('right') + 2), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ), + ); + + expect(applied.source, contains('>
\r\n>
\r\n> ri]')); + final document = _parse(applied.source); + expect(document.blocks.single.kind, BusyBlockKind.blockquote); + expect(_destinations(_allInlines(document.blocks)), [ + 'https://destination.test', + 'https://incoming.test', + 'https://destination.test', + ]); + }); + + test('structured complete blocks generate only CRLF boundaries', () { + const source = 'leftright\r\n'; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + const TextSelection.collapsed(offset: 'left'.length), + ), + fragment: _fragment('# Heading\n'), + ), + ); + + expect(applied.source, contains('# Heading')); + expect(_containsLoneLf(applied.source), isFalse); + expect(applied.source, endsWith('right\r\n')); + expect(applied.edit.caretOffset, applied.source.indexOf('right')); + + for (final container in ['- leftright\r\n', '> leftright\r\n']) { + final containerApplied = _applyReady( + container, + engine.prepareStructured( + target: _target( + container, + TextSelection.collapsed(offset: container.indexOf('right')), + ), + fragment: _fragment('# Heading\n'), + ), + ); + expect( + _containsLoneLf(containerApplied.source), + isFalse, + reason: containerApplied.source, + ); + expect(containerApplied.source, contains('Heading')); + expect(containerApplied.source, contains('right')); + } + }); + + test('structured inline hard breaks use destination CRLF', () { + const source = 'leftright\r\n'; + final fragment = _nativeFragment(const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ]); + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target( + source, + const TextSelection.collapsed(offset: 'left'.length), + ), + fragment: fragment, + ), + ); + + expect(applied.source, 'leftA \r\nBright\r\n'); + expect(_containsLoneLf(applied.source), isFalse); + expect(applied.edit.caretOffset, 'leftA \r\nB'.length); + }); + + test( + 'mapped and generated structured breaks retain CRLF and caret width', + () { + const source = '[left \r\nright](https://destination.test) tail\r\n'; + final insertion = source.indexOf('left') + 'left'.length; + final applied = _applyReady( + source, + engine.prepareStructured( + target: _target(source, TextSelection.collapsed(offset: insertion)), + fragment: _nativeFragment(const [ + BusyInline(kind: BusyInlineKind.text, text: 'A'), + BusyInline(kind: BusyInlineKind.hardBreak, text: '\n'), + BusyInline(kind: BusyInlineKind.text, text: 'B'), + ]), + ), + ); + + expect(_containsLoneLf(applied.source), isFalse, reason: applied.source); + expect(RegExp(r' \r\n').allMatches(applied.source), hasLength(2)); + expect( + applied.source.substring(0, applied.edit.caretOffset), + endsWith('B'), + ); + expect(applied.source, contains('right')); + }, + ); + + test('protected Source context explicitly permits textual fallback', () { + const source = '```text\nprotected\n```'; + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('protected') + 3), + ), + fragment: _fragment('**rich**\n'), + ); + + expect(result, isA()); + }); + + test('syntax-only positions explicitly permit textual fallback', () { + const source = '**left**'; + final result = engine.prepareStructured( + target: _target(source, const TextSelection.collapsed(offset: 1)), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + + expect(result, isA()); + }); + + test('unmappable destination links stop rather than permit fallback', () { + const source = 'left'; + final result = engine.prepareStructured( + target: _target( + source, + TextSelection.collapsed(offset: source.indexOf('left') + 2), + ), + fragment: _fragment('[Y](https://incoming.test)\n'), + ); + + expect(result, isA()); + }); +} + +SourcePasteDocumentSnapshot _target(String source, TextSelection selection) { + return SourcePasteDocumentSnapshot( + expectedSource: source, + selection: selection, + format: SourceDocumentFormat.markdown, + markdownMode: MarkdownMode.commonMark, + filePath: '/project/source.md', + ); +} + +bool _containsLoneLf(String value) { + for (var index = 0; index < value.length; index++) { + if (value.codeUnitAt(index) == 0x0a && + (index == 0 || value.codeUnitAt(index - 1) != 0x0d)) { + return true; + } + } + return false; +} + +WysiwygClipboardFragment _fragment(String source) { + final document = _parse(source, filePath: '/clipboard/source.md'); + return WysiwygClipboardFragment( + sourcePath: document.filePath, + mode: document.mode, + blocks: [ + for (final block in document.blocks) + BusyWysiwygStyledBlock( + kind: block.kind, + text: block.plainText, + ranges: busyInlineStyleRanges(block.inlines), + attributes: block.attributes, + completeBlock: busyMarkWysiwygImmutableBlockSnapshot(block), + ), + ], + ); +} + +WysiwygClipboardFragment _nativeFragment(List inlines) { + final text = inlines.map((inline) => inline.plainText).join(); + final block = BusyBlock( + id: 'native-clipboard-paragraph', + kind: BusyBlockKind.paragraph, + inlines: inlines, + ); + return WysiwygClipboardFragment( + sourcePath: '/clipboard/source.md', + mode: MarkdownMode.commonMark, + blocks: [ + BusyWysiwygStyledBlock( + kind: BusyBlockKind.paragraph, + text: text, + ranges: busyInlineStyleRanges(inlines), + completeBlock: block, + ), + ], + ); +} + +BusyDocument _parse(String source, {String filePath = '/project/source.md'}) { + return const MarkdownParser() + .parse( + filePath: filePath, + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; +} + +BusyBlock _contentParagraph(BusyDocument document) { + final root = document.blocks.single; + if (root.kind != BusyBlockKind.table) return root; + return root.children.last.children.single; +} + +({String source, SourcePasteEdit edit}) _applyReady( + String source, + SourcePastePreparation result, +) { + expect(result, isA()); + final edit = (result as SourcePasteReady).edit; + expect(edit.expectedSource, source); + return ( + source: source.replaceRange(edit.start, edit.end, edit.replacement), + edit: edit, + ); +} + +List _destinations(List inlines) { + return [for (final inline in _links(inlines)) inline.destination]; +} + +List _links(List inlines) { + final result = []; + void visit(List values) { + for (final inline in values) { + if (inline.kind == BusyInlineKind.link) result.add(inline); + visit(inline.children); + } + } + + visit(inlines); + return result; +} + +List _documentSemanticSignature(BusyDocument document) { + final result = []; + + void addInline(BusyInline inline, int depth) { + result.add( + '${' ' * depth}inline:${inline.kind.name}:${inline.text}:' + '${inline.destination ?? ''}:${inline.attributes['title'] ?? ''}', + ); + for (final child in inline.children) { + addInline(child, depth + 1); + } + } + + void addBlock(BusyBlock block, int depth) { + result.add( + '${' ' * depth}block:${block.kind.name}:${block.attributes.entries.toList()}', + ); + for (final inline in block.inlines) { + addInline(inline, depth + 1); + } + for (final child in block.children) { + addBlock(child, depth + 1); + } + } + + for (final block in document.blocks) { + addBlock(block, 0); + } + return result; +} + +Iterable _blocksDepthFirst(Iterable blocks) sync* { + for (final block in blocks) { + yield block; + yield* _blocksDepthFirst(block.children); + } +} + +List? _blockPath( + List blocks, + bool Function(BusyBlock block) matches, +) { + for (var index = 0; index < blocks.length; index++) { + final block = blocks[index]; + if (matches(block)) return [index]; + final child = _blockPath(block.children, matches); + if (child != null) return [index, ...child]; + } + return null; +} + +void _expectSourceEditorParity( + ({String source, SourcePasteEdit edit}) applied, + BusyMarkWysiwygDocumentController editor, + String editorCaretBlockId, + int editorCaretOffset, +) { + final sourceDocument = _parse(applied.source); + expect( + _documentSemanticSignature(sourceDocument), + _documentSemanticSignature(_parse(editor.markdown)), + reason: 'Source: ${applied.source}\nEditor: ${editor.markdown}', + ); + + const marker = '\ue006'; + final marked = _parse( + applied.source.replaceRange( + applied.edit.caretOffset, + applied.edit.caretOffset, + marker, + ), + ); + final sourcePath = _blockPath( + marked.blocks, + (block) => block.plainText.contains(marker), + ); + final editorPath = _blockPath( + editor.document.blocks, + (block) => block.id == editorCaretBlockId, + ); + expect(sourcePath, editorPath, reason: applied.source); + final markedBlock = _blocksDepthFirst( + marked.blocks, + ).firstWhere((block) => block.plainText.contains(marker)); + expect( + markedBlock.plainText.indexOf(marker), + editorCaretOffset, + reason: applied.source, + ); +} + +int _countKind(List inlines, BusyInlineKind kind) { + var result = 0; + for (final inline in inlines) { + if (inline.kind == kind) result += 1; + result += _countKind(inline.children, kind); + } + return result; +} + +List<({String text, List contexts})> _leafContexts( + List inlines, +) { + final result = <({String text, List contexts})>[]; + + void visit(BusyInline inline, List inherited) { + final contexts = inline.kind == BusyInlineKind.text + ? inherited + : [...inherited, inline.kind]; + if (inline.children.isEmpty) { + if (inline.plainText.isNotEmpty) { + result.add((text: inline.plainText, contexts: contexts)); + } + return; + } + for (final child in inline.children) { + visit(child, contexts); + } + } + + for (final inline in inlines) { + visit(inline, const []); + } + return result; +} + +List _allInlines(List blocks) { + return [ + for (final block in blocks) ...[ + ...block.inlines, + ..._allInlines(block.children), + ], + ]; +} diff --git a/test/src/spellcheck_projection_test.dart b/test/src/spellcheck_projection_test.dart new file mode 100644 index 00000000..4cf6f840 --- /dev/null +++ b/test/src/spellcheck_projection_test.dart @@ -0,0 +1,1645 @@ +import 'dart:io'; + +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/spellcheck/markdown_spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_replacement.dart'; +import 'package:busymark/src/spellcheck/writerside_spelling_projection.dart'; +import 'package:busymark/src/spellcheck/wysiwyg_spelling_projection.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const _snapshot = SpellingSnapshotIdentity( + bufferId: 'buffer-1', + contentRevision: 7, + documentKind: DocumentKind.markdown, + contextGeneration: 2, +); + +SpellingOccurrence _rejected(SpellingProseRun run, String word) { + final start = run.text.indexOf(word); + expect(start, isNonNegative); + return SpellingOccurrence( + id: '${run.id}:$start', + run: run, + logicalStart: start, + logicalEnd: start + word.length, + word: word, + outcome: SpellingCheckOutcome.rejected, + ); +} + +void main() { + test( + 'different live prose still reports incomplete instead of guessed mapping', + () { + final parsed = const MarkdownParser() + .parse( + filePath: '/changed.md', + source: 'Original words\n', + mode: MarkdownMode.gfm, + ) + .busyDocument; + final changed = parsed.copyWith( + blocks: [ + parsed.blocks.single.copyWith( + inlines: const [ + BusyInline(kind: BusyInlineKind.text, text: 'Different words'), + ], + ), + ], + ); + final projection = const WysiwygSpellingProjector().project( + document: changed, + languageId: 'en-CA', + snapshot: _snapshot, + documentGeneration: 1, + ); + expect(projection.complete, isFalse); + }, + ); + + test( + 'general Markdown fixture has complete Source and rich spelling mappings', + () { + final source = File('test/fixtures/markdown/basic.md').readAsStringSync(); + final document = const MarkdownParser() + .parse(filePath: '/basic.md', source: source, mode: MarkdownMode.gfm) + .busyDocument; + final sourceProjection = const MarkdownSpellingProjector().project( + filePath: '/basic.md', + source: source, + mode: MarkdownMode.gfm, + languageId: 'en-CA', + snapshot: _snapshot, + ); + final rich = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-CA', + snapshot: _snapshot, + documentGeneration: 1, + ); + for (final projection in [sourceProjection, rich]) { + expect(projection.complete, isTrue, reason: projection.message); + final texts = projection.runs.map((run) => run.text); + expect(texts, contains('2. Paragraphs')); + expect(texts, contains('Less than: <')); + expect(texts, contains('Greater than: >')); + expect(texts.any((text) => text.contains(r'\frac')), isFalse); + expect(texts.any((text) => text.contains('^markdown')), isFalse); + expect(texts, contains('28. Document Conclusion')); + } + expect( + rich.runs.firstWhere((run) => run.text == 'Raw HTML block ').target, + isA(), + reason: 'Protected HTML still gets checked in Source.', + ); + expect( + rich.runs + .singleWhere((run) => run.text == '28. Document Conclusion') + .target, + isA(), + ); + }, + ); + + test('live HTML paste preserves prose and maps spelling before a reload', () { + final html = File( + 'test/fixtures/spelling/pasted_job.html', + ).readAsStringSync(); + final fragment = const WysiwygClipboardHtml().decode( + html, + mode: MarkdownMode.gfm, + )!; + final target = const MarkdownParser() + .parse( + filePath: '/pasted.md', + source: 'Target\n', + mode: MarkdownMode.gfm, + ) + .busyDocument; + final editor = BusyMarkWysiwygDocumentController(document: target); + addTearDown(editor.dispose); + editor.insertStyledBlocksAtSelection( + blockId: target.blocks.first.id, + selectionStart: 0, + selectionEnd: 6, + blocks: fragment.blocks, + ); + final source = editor.markdown; + final live = editor.document.copyWith(source: source); + final reloaded = const MarkdownParser() + .parse(filePath: '/pasted.md', source: source, mode: MarkdownMode.gfm) + .busyDocument; + List prose(BusyDocument document) => [ + for (final block in document.blocks) + if (block.plainText.trim().isNotEmpty) + block.plainText.trim().replaceAll(RegExp(r'\s+'), ' '), + ]; + expect( + prose(reloaded), + prose(live), + reason: 'Formatting must not reload as literal Markdown markers.', + ); + final projection = const WysiwygSpellingProjector().project( + document: live, + languageId: 'en-CA', + snapshot: _snapshot, + documentGeneration: 1, + ); + expect(projection.complete, isTrue, reason: projection.message); + final team = projection.runs.singleWhere( + (run) => run.text.contains('Team responsibilities'), + ); + final occurrence = _rejected(team, 'responsibilities'); + final block = live.blocks.singleWhere( + (block) => block.id == (team.target as SpellingRichBlockTarget).blockId, + ); + expect(occurrence.fieldStart, block.plainText.indexOf('responsibilities')); + final plan = const SpellingReplacementPlanner().build( + occurrence: occurrence, + suggestion: 'duties', + ); + expect( + plan.applyToSource(source), + source.replaceFirst('responsibilities', 'duties'), + ); + }); + + test('pasted job maps tables, trailing HTML breaks and address barriers', () { + final source = File( + 'test/fixtures/spelling/pasted_job.md', + ).readAsStringSync(); + final document = const MarkdownParser() + .parse(filePath: '/pasted.md', source: source, mode: MarkdownMode.gfm) + .busyDocument; + final sourceProjection = const MarkdownSpellingProjector().project( + filePath: '/pasted.md', + source: source, + mode: MarkdownMode.gfm, + languageId: 'en-CA', + snapshot: _snapshot, + ); + final rich = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-CA', + snapshot: _snapshot, + documentGeneration: 3, + ); + expect(sourceProjection.complete, isTrue, reason: sourceProjection.message); + expect(rich.complete, isTrue, reason: rich.message); + for (final projection in [sourceProjection, rich]) { + expect(projection.runs.every((run) => run.hasValidMapping), isTrue); + final reference = projection.runs.singleWhere( + (run) => run.text == 'Reference #', + ); + expect( + reference.atoms.first.context, + SpellingSourceContext.markdownTableCell, + ); + expect( + projection.runs.any((run) => run.text.contains('example.test')), + isFalse, + ); + final finalRun = projection.runs.singleWhere( + (run) => run.text.contains('helo'), + ); + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(finalRun, 'helo'), + suggestion: 'hello', + ); + expect(plan.applyToSource(source), source.replaceFirst('helo', 'hello')); + } + final reference = rich.runs.singleWhere((run) => run.text == 'Reference #'); + expect(reference.target, isA()); + final finalRun = rich.runs.singleWhere((run) => run.text.contains('helo')); + expect(finalRun.target, isA()); + final target = finalRun.target as SpellingRichBlockTarget; + expect(target.blockId, document.blocks.last.id); + expect(target.documentGeneration, 3); + final occurrence = _rejected(finalRun, 'helo'); + expect( + occurrence.fieldStart, + document.blocks.last.plainText.indexOf('helo'), + ); + expect( + occurrence.fieldEnd, + document.blocks.last.plainText.indexOf('helo') + 4, + ); + }); + + test('closing hashes are heading syntax only in an ATX heading', () { + final projection = const MarkdownSpellingProjector().project( + filePath: '/hash.md', + source: 'Reference #\n\n## Heading #\n', + mode: MarkdownMode.gfm, + languageId: 'en-US', + snapshot: _snapshot, + ); + expect(projection.complete, isTrue); + expect(projection.runs.map((run) => run.text), ['Reference #', 'Heading']); + }); + + group('Markdown spelling projection', () { + test('maps repeated and formatted prose without searching globally', () { + const source = 'mispelled\n\n**mispel**led and `hiddenbad` tail\n'; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/test.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + + expect(result.complete, isTrue); + expect(result.runs.map((run) => run.text), contains('mispelled')); + expect(result.runs.map((run) => run.text), contains('mispelled and ')); + expect(result.runs.map((run) => run.text), contains(' tail')); + expect( + result.runs.every((run) => !run.text.contains('hiddenbad')), + isTrue, + ); + + final formatted = result.runs.firstWhere( + (run) => run.text.startsWith('mispelled and'), + ); + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(formatted, 'mispelled'), + suggestion: 'misspelled', + ); + expect( + plan.applyToSource(source), + 'mispelled\n\n**misspel**led and `hiddenbad` tail\n', + ); + }); + + test('keeps entities, escapes, links, and table cells source exact', () { + const source = + '''A sm&ll [labell](https://example.invalid/badd) and \\word. + +| first | errored\\|cell | +| --- | --- | +| second | 😀 mistakke | +'''; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/test.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + + expect(result.complete, isTrue); + final allText = result.runs.map((run) => run.text).join('\n'); + expect(allText, contains('sm&ll')); + expect(allText, contains('labell')); + expect(allText, isNot(contains('example.invalid'))); + expect(allText, contains('errored|cell')); + expect(allText, contains('😀 mistakke')); + for (final run in result.runs) { + expect(run.hasValidMapping, isTrue); + for (final atom in run.atoms) { + expect(atom.sourceStart, greaterThanOrEqualTo(0)); + expect(atom.sourceEnd, lessThanOrEqualTo(source.length)); + } + } + }); + + test('keeps CRLF and repeated occurrence targets exact', () { + const source = '> First mistakke\r\n> second mistakke\r\n'; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/repeated.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = result.runs.single; + final start = run.text.lastIndexOf('mistakke'); + final occurrence = SpellingOccurrence( + id: 'second-mistakke', + run: run, + logicalStart: start, + logicalEnd: start + 'mistakke'.length, + word: 'mistakke', + outcome: SpellingCheckOutcome.rejected, + ); + final corrected = const SpellingReplacementPlanner() + .build(occurrence: occurrence, suggestion: 'mistake') + .applyToSource(source); + + expect(corrected, '> First mistakke\r\n> second mistake\r\n'); + }); + + test('uses barriers around excluded authored syntax', () { + const source = r'''--- +title: hiddenfront +--- + +Visiblee pre`hiddeninline`fix and $hiddenmath$ afterr. + + +Plainn https://example.invalid/hiddenplain thenn person@example.invalid afterwardd. +Beforecomment aftercomment. +Beforecode ``hidden +continuedcode`` aftercode. +Beforee %hiddenvariable% afterrr. +![Altternativ text](path/hidden.png "Readablee title") +'''; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/exclusions.md', + source: source, + mode: MarkdownMode.writersideMarkdown, + languageId: 'en-US', + snapshot: _snapshot, + ); + final texts = result.runs.map((run) => run.text).toList(); + final all = texts.join('\n'); + + expect(all, contains('Visiblee pre')); + expect(all, contains('fix and ')); + expect(all, contains(' afterr.')); + expect(all, contains('Beforee ')); + expect(all, contains(' afterrr.')); + expect(all, contains('Plainn ')); + expect(all, contains(' thenn ')); + expect(all, contains(' afterwardd.')); + expect(all, contains('Beforecomment ')); + expect(all, contains(' aftercomment.')); + expect(all, contains('Beforecode ')); + expect(all, contains(' aftercode.')); + expect(all, contains('Altternativ text')); + expect(all, contains('Readablee title')); + expect(all, isNot(contains('prefix'))); + expect(all, isNot(contains('hiddenfront'))); + expect(all, isNot(contains('hiddeninline'))); + expect(all, isNot(contains('hiddenmath'))); + expect(all, isNot(contains('hiddencomment'))); + expect(all, isNot(contains('hiddenurl'))); + expect(all, isNot(contains('hiddenplain'))); + expect(all, isNot(contains('example.invalid'))); + expect(all, isNot(contains('continuedcomment'))); + expect(all, isNot(contains('continuedcode'))); + expect(all, isNot(contains('hiddenvariable'))); + expect(all, isNot(contains('hidden.png'))); + }); + + test('excludes a fenced code block nested in a block quote', () { + const source = '''> ```java +> record Document(String title, String content) {} +> ``` + +Visiblee prose. +'''; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/quoted-code.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-CA', + snapshot: _snapshot, + ); + final all = result.runs.map((run) => run.text).join('\n'); + + expect(result.complete, isTrue, reason: result.message); + expect(all, contains('Visiblee prose.')); + expect(all, isNot(contains('record Document'))); + }); + + test('keeps unmatched delimiters and removes only parsed formatting', () { + const source = + 'Matched **mispel**led and literal foo_bar plus *unclosed.\n'; + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/delimiters.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + + expect(result.complete, isTrue); + expect( + result.runs.single.text, + 'Matched mispelled and literal foo_bar plus *unclosed.', + ); + expect( + result.runs.single.atoms.map((atom) => atom.logicalText).join(), + result.runs.single.text, + ); + }); + + test('maps quoted HTML attribute values from quote boundaries', () { + for (final fixture in <({String source, String expected})>[ + ( + source: 'A x.\n', + expected: 'A x.\n', + ), + ( + source: 'A x.\n', + expected: 'A x.\n', + ), + ( + source: "A x.\n", + expected: "A x.\n", + ), + ( + source: 'A x.\n', + expected: + 'A x.\n', + ), + ]) { + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/attributes.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = result.runs.firstWhere( + (candidate) => + candidate.text == 'titl' || candidate.text.startsWith('titl '), + ); + final corrected = const SpellingReplacementPlanner() + .build(occurrence: _rejected(run, 'titl'), suggestion: 'title') + .applyToSource(fixture.source); + + expect(corrected, fixture.expected); + expect(corrected, contains('

hello

world

+

before
after
again
last

+
lefthiddenwordright
+

abovebelow

+

visible

+'''; + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/html.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final texts = projected.runs.map((run) => run.text).toList(); + final all = texts.join('\n'); + + expect(projected.complete, isTrue, reason: projected.message); + expect(texts, containsAll(['hello', 'world'])); + expect(all, isNot(contains('helloworld'))); + expect(texts, containsAll(['before', 'after', 'again', 'last'])); + expect(all, isNot(contains('beforeafter'))); + expect(texts, contains('Readablee title')); + expect( + texts, + containsAll(['left', 'right', 'above', 'below', 'visible']), + ); + expect(all, isNot(contains('leftright'))); + expect(all, isNot(contains('hiddenword'))); + expect(all, isNot(contains('hidden script prose'))); + expect(all, isNot(contains('hidden style prose'))); + for (final run in projected.runs) { + expect(run.hasValidMapping, isTrue); + } + }); + + test('keeps comparison prose and scans multiline HTML tags exactly', () { + const source = '''Before 2 < 3, mispelled > 1 and x <= y. +
visiblee
+'''; + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/multiline-html.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final all = projected.runs.map((run) => run.text).join('\n'); + expect(projected.complete, isTrue, reason: projected.message); + expect(all, contains('mispelled')); + expect(all, contains('Readablee > prose')); + expect(all, contains('visiblee')); + expect(all, isNot(contains('technicall'))); + expect(all, isNot(contains('wrongg'))); + expect(all, isNot(contains('mistakke'))); + expect(all, isNot(contains('typpo'))); + + final run = projected.runs.singleWhere( + (candidate) => candidate.text.contains('mispelled'), + ); + final corrected = const SpellingReplacementPlanner() + .build( + occurrence: _rejected(run, 'mispelled'), + suggestion: 'misspelled', + ) + .applyToSource(source); + expect(corrected, source.replaceFirst('mispelled', 'misspelled')); + }); + + test('removes delimiters when a correction empties formatting', () { + for (final fixture in <({String source, MarkdownMode mode})>[ + (source: 'he**x**llo\n', mode: MarkdownMode.commonMark), + (source: 'he***x***llo\n', mode: MarkdownMode.commonMark), + (source: 'he~~x~~llo\n', mode: MarkdownMode.gfm), + ]) { + final result = const MarkdownSpellingProjector().project( + filePath: '/tmp/empty-format.md', + source: fixture.source, + mode: fixture.mode, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = result.runs.single; + final corrected = const SpellingReplacementPlanner() + .build(occurrence: _rejected(run, 'hexllo'), suggestion: 'hello') + .applyToSource(fixture.source); + final parsed = const MarkdownParser().parse( + filePath: '/tmp/empty-format.md', + source: corrected, + mode: fixture.mode, + validateLocalReferences: false, + ); + + expect(corrected, 'hello\n'); + expect(parsed.busyDocument.blocks.single.plainText, 'hello'); + expect( + parsed.busyDocument.blocks.single.inlines.where( + (inline) => inline.kind != BusyInlineKind.text, + ), + isEmpty, + ); + } + }); + + test('uses parser-compatible percentages escapes and code spans', () { + const source = + r'20% mispelled 30% \letter \*escaped* %real_variable% ' + 'before ``hidden ` tick`` after `unmatched\n'; + final commonMark = const MarkdownSpellingProjector().project( + filePath: '/tmp/common.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final writerside = const MarkdownSpellingProjector().project( + filePath: '/tmp/writerside.md', + source: source, + mode: MarkdownMode.writersideMarkdown, + languageId: 'en-US', + snapshot: _snapshot, + ); + final commonText = commonMark.runs.map((run) => run.text).join(' '); + final writersideText = writerside.runs.map((run) => run.text).join(' '); + + expect(commonText, contains(r'20% mispelled 30% \letter *escaped*')); + expect(commonText, contains('%real_variable%')); + expect(commonText, isNot(contains('hidden ` tick'))); + expect(commonText, contains('after `unmatched')); + expect(writersideText, contains('20% mispelled 30%')); + expect(writersideText, isNot(contains('real_variable'))); + final typoRun = writerside.runs.firstWhere( + (run) => run.text.contains('mispelled'), + ); + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(typoRun, 'mispelled'), + suggestion: 'misspelled', + ) + .applyToSource(source), + contains('20% misspelled 30%'), + ); + }); + + test('retains complete formatting ancestors across opaque children', () { + for (final fixture in <({String source, String expected})>[ + (source: 'hello**x`code`world**\n', expected: 'hello**`code`world**\n'), + ( + source: + r'hello**x$y$world**' + '\n', + expected: + r'hello**$y$world**' + '\n', + ), + ( + source: 'hello***x`code`world***\n', + expected: 'hello***`code`world***\n', + ), + ( + source: 'hello**x [good](target "title") world**\n', + expected: 'hello** [good](target "title") world**\n', + ), + ]) { + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/ancestor.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text.contains('hellox'), + ); + late final String corrected; + expect( + () => corrected = const SpellingReplacementPlanner() + .build(occurrence: _rejected(run, 'hellox'), suggestion: 'hello') + .applyToSource(fixture.source), + returnsNormally, + reason: fixture.source, + ); + + expect(corrected, fixture.expected); + } + }); + + test('validates formatting gaps in regional coordinates', () { + for (final source in ['he**llo**x\n', 'intro\n\nhe**llo**x\n']) { + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/regional.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text == 'hellox', + ); + + expect( + const SpellingReplacementPlanner() + .build(occurrence: _rejected(run, 'hellox'), suggestion: 'hello') + .applyToSource(source), + source.replaceFirst('he**llo**x', 'he**llo**'), + ); + } + }); + + test('accepts canonically equivalent mapped replacement text', () { + const source = 'prefix\n\ncafe\u0301x\n'; + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/unicode.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = projected.runs.singleWhere( + (candidate) => candidate.text.contains('cafe\u0301x'), + ); + + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(run, 'cafe\u0301x'), + suggestion: 'café', + ) + .applyToSource(source), + 'prefix\n\ncafe\u0301\n', + ); + }); + + test( + 'link titles use exact quote boundaries before trailing whitespace', + () { + for (final fixture in <({String source, String expected})>[ + ( + source: '[label](mispelled "mispelled" )\n', + expected: '[label](mispelled "misspelled" )\n', + ), + ( + source: "[label](target 'mispelled'\t )\n", + expected: "[label](target 'misspelled'\t )\n", + ), + ( + source: + r'''[label](target "mispelled \"quoted\"")''' + '\n', + expected: + r'''[label](target "misspelled \"quoted\"")''' + '\n', + ), + ]) { + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/title.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text.contains('mispelled'), + ); + final occurrence = _rejected(run, 'mispelled'); + expect( + fixture.source.substring( + occurrence.sourceStart!, + occurrence.sourceEnd!, + ), + 'mispelled', + ); + expect( + const SpellingReplacementPlanner() + .build(occurrence: occurrence, suggestion: 'misspelled') + .applyToSource(fixture.source), + fixture.expected, + ); + } + }, + ); + + test('semantic leaf blocks define independent complete prose runs', () { + const source = r''' hiddenindent + +- parentt + - nestedd + +> firstt +> +> secondd + +- visiblee + + hiddencontainercode + +before $$ mispelled $$ afterr + +before $hiddenmath$ aftermath +'''; + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/leaves.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final texts = projected.runs.map((run) => run.text).toList(); + + expect(projected.complete, isTrue, reason: projected.message); + expect(texts, contains('parentt')); + expect(texts, contains('nestedd')); + expect(texts, contains('firstt')); + expect(texts, contains('secondd')); + expect(texts, contains(r'before $$ mispelled $$ afterr')); + expect(texts.join(' '), isNot(contains('hiddenindent'))); + expect(texts.join(' '), isNot(contains('hiddencontainercode'))); + expect(texts.join(' '), isNot(contains('hiddenmath'))); + expect(texts.every((text) => text != 'parentt nestedd'), isTrue); + }); + + test('projects semantic HTML prose and trusts parser math nodes', () { + const source = + '''

mispelled

hiddenbad
+ +Price \$ 5, mispelled \$ 6 and actual \$hiddenmath\$ tail. +'''; + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/html.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final text = projected.runs.map((run) => run.text).join('\n'); + + expect(projected.complete, isTrue, reason: projected.message); + expect(text, contains('Readablee')); + expect(text, contains('mispelled')); + expect(text, contains(r'Price $ 5, mispelled $ 6')); + expect(text, isNot(contains('hiddenbad'))); + expect(text, isNot(contains('hiddenmath'))); + }); + + test('large formatting-heavy projection and correction stay bounded', () { + final source = List.generate( + 600, + (index) => + '**mispel**led paragraph $index with [hello](target) and `code` ' + r'$x$', + ).join('\n\n'); + final watch = Stopwatch()..start(); + final projected = const MarkdownSpellingProjector().project( + filePath: '/tmp/large-correction.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-US', + snapshot: _snapshot, + ); + final first = projected.runs.firstWhere( + (run) => run.text.contains('mispelled'), + ); + final corrected = const SpellingReplacementPlanner() + .build( + occurrence: _rejected(first, 'mispelled'), + suggestion: 'misspelled', + ) + .applyToSource(source); + watch.stop(); + + expect(projected.complete, isTrue, reason: projected.message); + expect(corrected, startsWith('**misspel**led paragraph 0')); + expect(corrected, contains('**mispel**led paragraph 599')); + expect(watch.elapsed, lessThan(const Duration(seconds: 5))); + }); + }); + + group('Writerside XML spelling projection', () { + test('maps text, entities, CDATA, and positive attributes', () { + const source = ''' +

Repeeted & formmatted.

+

+ hiddenbad + + Altternativ text +
'''; + final result = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/topic.topic', + source: source, + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + final text = result.runs.map((run) => run.text).join('\n'); + expect(result.complete, isTrue); + expect(text, contains('Titlle')); + expect(text, contains('Repeeted & formmatted')); + expect(text, contains('Cdataa prose')); + expect(text, contains('Altternativ text')); + expect(text, isNot(contains('hiddenbad'))); + expect(text, isNot(contains('other.topic'))); + expect(text, isNot(contains('path/teh.png'))); + }); + + test('reports malformed XML as incomplete without guessed targets', () { + final result = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/topic.topic', + source: '

broken', + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + expect(result.complete, isFalse); + expect(result.runs, isEmpty); + }); + + test( + 'clips CDATA occurrences while preserving repeated surrounding text', + () { + const source = + '

plain helo

'; + final projected = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/cdata.topic', + source: source, + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text.contains('hello helo helo world'), + ); + final first = _rejected(run, 'helo'); + + expect(source.substring(first.sourceStart!, first.sourceEnd!), 'helo'); + expect(first.sourceIntervals, hasLength(1)); + expect( + const SpellingReplacementPlanner() + .build(occurrence: first, suggestion: 'hello') + .applyToSource(source), + '

plain helo

', + ); + + final transformed = SpellingSourceAtom( + logicalText: 'xy', + logicalStart: 0, + logicalEnd: 2, + sourceStart: 10, + sourceEnd: 18, + transformation: SpellingTransformationKind.entity, + context: SpellingSourceContext.xmlText, + ); + expect(transformed.sourceIntervalFor(1, 2)?.start, 10); + expect(transformed.sourceIntervalFor(1, 2)?.end, 18); + }, + ); + + test('maps line breaks, excludes variables, and includes controls', () { + const source = r''' +

hello
world %projectname% prose %\escaped%

+

tail

+ Setttings +
'''; + final projected = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/variables.topic', + source: source, + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + final text = projected.runs.map((run) => run.text).join('\n'); + + expect(projected.complete, isTrue, reason: projected.message); + expect(text, contains('hello world')); + expect(text, isNot(contains('helloworld'))); + expect(text, isNot(contains('projectname'))); + expect(text, contains(r'%\escaped%')); + expect(text, contains('Titlle')); + expect(text, contains('Setttings')); + }); + + test('excludes entity-encoded variables after XML decoding', () { + const source = r''' +

before %projectname% after %other_name% literal %\escaped%

+

tail

+
'''; + final projected = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/encoded-variables.topic', + source: source, + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + final text = projected.runs.map((run) => run.text).join('\n'); + + expect(projected.complete, isTrue, reason: projected.message); + expect(text, contains('before ')); + expect(text, contains(' after ')); + expect(text, contains(r'literal %\escaped%')); + expect(text, isNot(contains('projectname'))); + expect(text, isNot(contains('other_name'))); + expect(text, isNot(contains('project'))); + }); + + test('keeps decomposed Unicode in XML and CDATA corrections', () { + for (final source in [ + '

cafe\u0301x

', + '

', + ]) { + final projected = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/unicode.topic', + source: source, + languageId: 'en-US', + snapshot: const SpellingSnapshotIdentity( + bufferId: 'xml', + contentRevision: 1, + documentKind: DocumentKind.writersideXmlTopic, + contextGeneration: 1, + ), + ); + final run = projected.runs.singleWhere( + (candidate) => candidate.text.contains('cafe\u0301x'), + ); + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(run, 'cafe\u0301x'), + suggestion: 'café', + ) + .applyToSource(source), + source.replaceFirst('cafe\u0301x', 'cafe\u0301'), + ); + } + }); + }); + + group('exact rich correction', () { + for (final source in [ + '# Introduction\n\n- [Overview](#overview)\n - [Motivation](#motivation)\n- [Discussion](#discussion)\n\n\n## Overview\n\nhelo **world**\n\nhelo world\n', + '- helo\n - helo\n\nhelo\n', + '\n\nhelo\n', + ]) { + test( + 'maps all rich fields without requiring parser block spans: $source', + () { + final document = const MarkdownParser() + .parse( + filePath: '/topic.md', + source: source, + mode: MarkdownMode.writersideMarkdown, + validateLocalReferences: false, + ) + .busyDocument; + final result = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 1, + ); + expect(result.complete, isTrue, reason: result.message); + expect( + result.runs.every((r) => r.target is SpellingRichBlockTarget), + isTrue, + ); + expect(result.runs.any((r) => r.text.contains(''; + final document = const MarkdownParser() + .parse( + filePath: '/literal.md', + source: source, + validateLocalReferences: false, + ) + .busyDocument; + final result = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 1, + ); + expect(result.complete, isTrue); + expect(result.runs.single.text, contains('helo')); + }); + + test('maps hard breaks by structural field identity', () { + const source = 'helo \nworld\n\nhelo world\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/hard-break.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 4, + ); + final richRuns = projection.runs + .where((run) => run.target is SpellingRichBlockTarget) + .toList(); + + expect(projection.complete, isTrue, reason: projection.message); + expect(richRuns, hasLength(2)); + expect(richRuns.map((run) => run.text), everyElement('helo world')); + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(richRuns.first, 'helo'), + suggestion: 'hello', + ) + .applyToSource(source), + 'hello \nworld\n\nhelo world\n', + ); + expect( + (richRuns.first.target as SpellingRichBlockTarget).blockId, + isNot((richRuns.last.target as SpellingRichBlockTarget).blockId), + ); + }); + + test('removes a rich formatting container emptied by deletion', () { + final document = BusyDocument( + filePath: '/tmp/empty-rich.md', + mode: MarkdownMode.commonMark, + blocks: const [ + BusyBlock( + id: 'p', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline(kind: BusyInlineKind.text, text: 'he'), + BusyInline( + kind: BusyInlineKind.strong, + text: 'x', + children: [BusyInline(kind: BusyInlineKind.text, text: 'x')], + ), + BusyInline(kind: BusyInlineKind.text, text: 'llo'), + ], + ), + ], + ); + final run = const WysiwygSpellingProjector() + .project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 1, + ) + .runs + .single; + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'hexllo'), + suggestion: 'hello', + ); + final controller = BusyMarkWysiwygDocumentController(document: document); + + expect( + controller.replaceSpellingInBlock( + blockId: 'p', + expectedFieldText: 'hexllo', + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, 'hello\n'); + expect( + controller + .blockById('p')! + .inlines + .where((inline) => inline.kind == BusyInlineKind.strong), + isEmpty, + ); + }); + + test('retains current source anchors and source-only title targets', () { + const source = + '![Altternativ](asset.png "Repeeted")\n\nRepeeted\n\n**mispel**led\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/current.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 9, + ); + + expect(projection.complete, isTrue); + final title = projection.runs.singleWhere( + (run) => run.text == 'Repeeted' && run.target is SpellingSourceTarget, + ); + final paragraph = projection.runs.singleWhere( + (run) => + run.text == 'Repeeted' && run.target is SpellingRichBlockTarget, + ); + final formatted = projection.runs.singleWhere( + (run) => run.text == 'mispelled', + ); + expect(paragraph.atoms.every((atom) => atom.sourceStart >= 0), isTrue); + expect(formatted.atoms.every((atom) => atom.sourceStart >= 0), isTrue); + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(formatted, 'mispelled'), + suggestion: 'misspelled', + ) + .applyToSource(source), + '![Altternativ](asset.png "Repeeted")\n\nRepeeted\n\n**misspel**led\n', + ); + expect( + const SpellingReplacementPlanner() + .build( + occurrence: _rejected(title, 'Repeeted'), + suggestion: 'Bob"s', + ) + .applyToSource(source), + '![Altternativ](asset.png "Bob\\"s")\n\nRepeeted\n\n**mispel**led\n', + ); + }); + + test('preserves formatting ownership across leaves', () { + final document = BusyDocument( + filePath: '/tmp/test.md', + mode: MarkdownMode.commonMark, + blocks: const [ + BusyBlock( + id: 'p', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline( + kind: BusyInlineKind.strong, + text: 'mispel', + children: [ + BusyInline(kind: BusyInlineKind.text, text: 'mispel'), + ], + ), + BusyInline(kind: BusyInlineKind.text, text: 'led'), + ], + ), + ], + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 4, + ); + final run = projection.runs.single; + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'mispelled'), + suggestion: 'misspelled', + ); + final controller = BusyMarkWysiwygDocumentController(document: document); + + expect( + controller.replaceSpellingInBlock( + blockId: 'p', + expectedFieldText: 'mispelled', + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, '**misspel**led\n'); + }); + + test('keeps trailing formatting on its original leaf', () { + final document = BusyDocument( + filePath: '/tmp/test.md', + mode: MarkdownMode.commonMark, + blocks: const [ + BusyBlock( + id: 'p', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline(kind: BusyInlineKind.text, text: 'mispel'), + BusyInline( + kind: BusyInlineKind.strong, + text: 'led', + children: [BusyInline(kind: BusyInlineKind.text, text: 'led')], + ), + ], + ), + ], + ); + final run = const WysiwygSpellingProjector() + .project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 4, + ) + .runs + .single; + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'mispelled'), + suggestion: 'misspelled', + ); + final controller = BusyMarkWysiwygDocumentController(document: document); + + expect( + controller.replaceSpellingInBlock( + blockId: 'p', + expectedFieldText: 'mispelled', + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, 'misspel**led**\n'); + }); + + test('preserves link destination and table structure', () { + final link = BusyInline( + kind: BusyInlineKind.link, + text: 'mispelled', + destination: 'target', + children: const [ + BusyInline(kind: BusyInlineKind.text, text: 'mispelled'), + ], + ); + final cell = BusyBlock( + id: 'cell', + kind: BusyBlockKind.paragraph, + inlines: [link], + ); + final document = BusyDocument( + filePath: '/tmp/test.md', + mode: MarkdownMode.commonMark, + blocks: [ + BusyBlock( + id: 'table', + kind: BusyBlockKind.table, + children: [ + BusyBlock( + id: 'row', + kind: BusyBlockKind.table, + attributes: const {'header': 'true'}, + children: [cell], + ), + ], + ), + ], + ); + final run = const WysiwygSpellingProjector() + .project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 1, + ) + .runs + .single; + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'mispelled'), + suggestion: 'misspelled', + ); + final controller = BusyMarkWysiwygDocumentController(document: document); + expect( + controller.replaceSpellingInTableCell( + tableBlockId: 'table', + cellId: 'cell', + expectedFieldText: 'mispelled', + plan: plan, + ), + isTrue, + ); + final updated = controller.blockById('cell')!; + expect(updated.plainText, 'misspelled'); + expect(updated.inlines.single.destination, 'target'); + expect(controller.blockById('table')!.children.length, 1); + }); + + test('maps and corrects a table-cell field containing inline math', () { + const source = + '| Value |\n' + '| --- |\n' + r'| erroor $x$ tail |' + '\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/math-table.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 3, + ); + expect(projection.complete, isTrue, reason: projection.message); + final run = projection.runs.singleWhere( + (candidate) => candidate.text.contains('erroor'), + ); + final target = run.target as SpellingRichTableCellTarget; + expect(run.atoms.every((atom) => atom.sourceStart >= 0), isTrue); + final controller = BusyMarkWysiwygDocumentController(document: document); + final cell = controller.blockById(target.cellId)!; + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'erroor'), + suggestion: 'error', + ); + + expect( + controller.replaceSpellingInTableCell( + tableBlockId: target.tableBlockId, + cellId: target.cellId, + expectedFieldText: busyMarkWysiwygEditableText(cell), + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, contains(r'error $x$ tail')); + }); + + test('corrects transformed prose in table math source fields', () { + for (final fixture + in <({String cell, String word, String suggestion, String expected})>[ + ( + cell: r'mispel**led** $x$', + word: 'mispelled', + suggestion: 'misspelled', + expected: r'misspel**led** $x$', + ), + ( + cell: r'mispelled $x$', + word: 'mispelled', + suggestion: 'misspelled', + expected: r'misspelled $x$', + ), + ( + cell: r'he**x**llo $x$', + word: 'hexllo', + suggestion: 'hello', + expected: r'hello $x$', + ), + ( + cell: r'he***x***llo $x$', + word: 'hexllo', + suggestion: 'hello', + expected: r'hello $x$', + ), + ]) { + final source = '| Value |\n| --- |\n| ${fixture.cell} |\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/transformed-math-table.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projected = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 8, + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text.contains(fixture.word), + ); + final target = run.target as SpellingRichTableCellTarget; + final controller = BusyMarkWysiwygDocumentController( + document: document, + ); + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, fixture.word), + suggestion: fixture.suggestion, + ); + + expect( + controller.replaceSpellingInTableCell( + tableBlockId: target.tableBlockId, + cellId: target.cellId, + expectedFieldText: busyMarkWysiwygEditableText( + controller.blockById(target.cellId)!, + ), + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, contains('| ${fixture.expected} |')); + } + }); + + test('corrects formatted and encoded prose in math source fields', () { + for (final fixture + in < + ({String source, String word, String suggestion, String expected}) + >[ + ( + source: + r'mispel**led** $x$' + '\n', + expected: + r'misspel**led** $x$' + '\n', + word: 'mispelled', + suggestion: 'misspelled', + ), + ( + source: + r'mispelled $x$' + '\n', + expected: + r'misspelled $x$' + '\n', + word: 'mispelled', + suggestion: 'misspelled', + ), + ( + source: + r'he**x**llo $x$' + '\n', + expected: + r'hello $x$' + '\n', + word: 'hexllo', + suggestion: 'hello', + ), + ( + source: 'cafe\u0301x \$x\$\n', + expected: 'cafe\u0301 \$x\$\n', + word: 'cafe\u0301x', + suggestion: 'café', + ), + ]) { + final document = const MarkdownParser() + .parse( + filePath: '/tmp/math-rich.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projected = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 7, + ); + final run = projected.runs.firstWhere( + (candidate) => candidate.text.contains(fixture.word), + ); + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, fixture.word), + suggestion: fixture.suggestion, + ); + final controller = BusyMarkWysiwygDocumentController( + document: document, + ); + final target = run.target as SpellingRichBlockTarget; + + expect( + controller.replaceSpellingInBlock( + blockId: target.blockId, + expectedFieldText: busyMarkWysiwygEditableText( + controller.blockById(target.blockId)!, + ), + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, fixture.expected); + } + }); + + test('owns every nested wrapper in paragraph math-source fields', () { + const source = 'he***x***llo \$y\$\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/nested-math-rich.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final projected = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-US', + snapshot: _snapshot, + documentGeneration: 10, + ); + final run = projected.runs.singleWhere( + (candidate) => candidate.text.contains('hexllo'), + ); + final target = run.target as SpellingRichBlockTarget; + final controller = BusyMarkWysiwygDocumentController(document: document); + final plan = const SpellingReplacementPlanner().build( + occurrence: _rejected(run, 'hexllo'), + suggestion: 'hello', + ); + + expect( + controller.replaceSpellingInBlock( + blockId: target.blockId, + expectedFieldText: busyMarkWysiwygEditableText( + controller.blockById(target.blockId)!, + ), + plan: plan, + ), + isTrue, + ); + expect(controller.markdown, 'hello \$y\$\n'); + }); + }); +} diff --git a/test/src/spelling_bundle_integration_test.dart b/test/src/spelling_bundle_integration_test.dart new file mode 100644 index 00000000..23d4a2d5 --- /dev/null +++ b/test/src/spelling_bundle_integration_test.dart @@ -0,0 +1,222 @@ +import 'dart:io'; + +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/spellcheck/spelling_catalog.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_worker.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:busymark_spellcheck_native/busymark_spellcheck_native.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final root = Platform.environment['BUSYMARK_TEST_SPELLING_ROOT']; + final unavailable = + root == null || !File('$root/dictionaries.json').existsSync(); + + test( + 'real en-CA checks pasted rich content completely in both editors', + () async { + final catalog = await SpellingDictionaryCatalog.load( + bundledRoot: root!, + downloadedRoot: '$root/installed', + ); + final installation = catalog.installedById('en-CA')!; + final html = await File( + 'test/fixtures/spelling/pasted_job.html', + ).readAsString(); + final target = const MarkdownParser() + .parse( + filePath: '/pasted.md', + source: 'Target\n', + mode: MarkdownMode.gfm, + ) + .busyDocument; + final editor = BusyMarkWysiwygDocumentController(document: target); + addTearDown(editor.dispose); + final fragment = const WysiwygClipboardHtml().decode( + html, + mode: MarkdownMode.gfm, + )!; + editor.insertStyledBlocksAtSelection( + blockId: target.blocks.first.id, + selectionStart: 0, + selectionEnd: 6, + blocks: fragment.blocks, + ); + final source = editor.markdown; + final document = editor.document.copyWith(source: source); + final worker = await SpellingWorker.start(); + addTearDown(worker.close); + const snapshot = SpellingSnapshotIdentity( + bufferId: 'pasted-job', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + for (final rich in [false, true]) { + final projection = await worker.project( + SpellingProjectionJob( + filePath: '/pasted.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.gfm, + languageId: 'en-CA', + snapshot: snapshot, + richDocument: rich ? document : null, + richDocumentGeneration: 1, + ), + ); + final result = await worker.check( + context: SpellingEngineContext( + languageId: 'en-CA', + affPath: installation.affPath, + dicPath: installation.dicPath, + baseFingerprint: installation.fingerprint, + personalRevision: 0, + projectIdentity: null, + projectRevision: 0, + customWords: const [], + ), + runs: projection.runs, + ); + expect(projection.complete, isTrue, reason: projection.message); + expect(result.complete, isTrue, reason: result.error); + final occurrence = result.occurrences.singleWhere( + (o) => o.word == 'helo', + ); + expect(occurrence.outcome, SpellingCheckOutcome.rejected); + expect(occurrence.sourceStart, source.indexOf('helo')); + if (rich) { + expect(occurrence.run.target, isA()); + final target = occurrence.run.target as SpellingRichBlockTarget; + final block = document.blocks.singleWhere( + (block) => block.id == target.blockId, + ); + expect(occurrence.fieldStart, block.plainText.indexOf('helo')); + expect(occurrence.fieldEnd! - occurrence.fieldStart!, 4); + } + } + }, + skip: unavailable ? 'Prepared spelling bundle is not available.' : false, + ); + + test( + 'packaged catalog opens real regional and non-Latin dictionaries', + () async { + final catalog = await SpellingDictionaryCatalog.load( + bundledRoot: root!, + downloadedRoot: '$root/installed', + ); + expect(catalog.unavailableEntries, isEmpty); + expect(catalog.availableEntries, hasLength(48)); + expect(catalog.installations, hasLength(48)); + + for (final resource in catalog.availableEntries) { + final installation = catalog.installationForResource( + resource.resourceId, + ); + expect(installation, isNotNull, reason: resource.resourceId); + late final NativeSpellDictionary dictionary; + try { + dictionary = NativeSpellDictionary.open( + affPath: installation!.affPath, + dicPath: installation.dicPath, + ); + } on Object catch (error) { + fail('${resource.resourceId} failed native validation: $error'); + } + try { + expect(dictionary.encoding, isNotEmpty, reason: resource.resourceId); + expect( + dictionary.check(resource.knownValidProbe), + NativeSpellResult.accepted, + reason: '${resource.resourceId}: ${resource.knownValidProbe}', + ); + } finally { + dictionary.close(); + } + } + + final us = _open(catalog, 'en-US'); + try { + expect(us.check('color'), NativeSpellResult.accepted); + expect(us.check('helo'), NativeSpellResult.rejected); + expect(us.suggest('helo'), contains('hello')); + } finally { + us.close(); + } + }, + skip: unavailable ? 'Prepared spelling bundle is not available.' : false, + ); + + test('real en-CA checks the general Markdown fixture completely', () async { + final catalog = await SpellingDictionaryCatalog.load( + bundledRoot: root!, + downloadedRoot: '$root/installed', + ); + final installation = catalog.installedById('en-CA')!; + final source = await File('test/fixtures/markdown/basic.md').readAsString(); + final worker = await SpellingWorker.start(); + addTearDown(worker.close); + const snapshot = SpellingSnapshotIdentity( + bufferId: 'basic-markdown-fixture', + contentRevision: 0, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + for (final rich in [false, true]) { + final document = const MarkdownParser() + .parse( + filePath: 'test/fixtures/markdown/basic.md', + source: source, + mode: MarkdownMode.gfm, + ) + .busyDocument; + final projection = await worker.project( + SpellingProjectionJob( + filePath: 'test/fixtures/markdown/basic.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.gfm, + languageId: 'en-CA', + snapshot: snapshot, + richDocument: rich ? document : null, + richDocumentGeneration: 1, + ), + ); + final result = await worker.check( + context: SpellingEngineContext( + languageId: 'en-CA', + affPath: installation.affPath, + dicPath: installation.dicPath, + baseFingerprint: installation.fingerprint, + personalRevision: 0, + projectIdentity: null, + projectRevision: 0, + customWords: const [], + ), + runs: projection.runs, + ); + + expect(projection.complete, isTrue, reason: projection.message); + expect( + projection.runs.where((run) => run.text.contains('record Document')), + isEmpty, + reason: 'Quoted fenced code must not become spelling prose.', + ); + expect(result.complete, isTrue, reason: result.error); + expect(result.error, isNull); + } + }, skip: unavailable ? 'Prepared spelling bundle is not available.' : false); +} + +NativeSpellDictionary _open(SpellingDictionaryCatalog catalog, String id) { + final entry = catalog.installedById(id)!; + return NativeSpellDictionary.open( + affPath: entry.affPath, + dicPath: entry.dicPath, + ); +} diff --git a/test/src/spelling_editor_integration_test.dart b/test/src/spelling_editor_integration_test.dart new file mode 100644 index 00000000..026d83ee --- /dev/null +++ b/test/src/spelling_editor_integration_test.dart @@ -0,0 +1,725 @@ +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/core/diagnostic.dart'; +import 'package:busymark/src/editor/source/source_editor.dart'; +import 'package:busymark/src/editor/source/source_search.dart'; +import 'package:busymark/src/editor/source_language.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_block_widgets.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_session_state.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/spellcheck/markdown_spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_coordinator.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_replacement.dart'; +import 'package:busymark/src/spellcheck/wysiwyg_spelling_projection.dart'; +import 'package:busymark/src/workspace/presentation/workspace_screen.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const _sourceSnapshot = SpellingSnapshotIdentity( + bufferId: 'source-buffer', + contentRevision: 7, + documentKind: DocumentKind.markdown, + contextGeneration: 2, +); + +void main() { + test('ordinary WYSIWYG selection never suppresses spelling underlines', () { + final controller = TextEditingController(text: 'mispelled'); + addTearDown(controller.dispose); + const range = TextRange(start: 0, end: 9); + + controller.selection = const TextSelection.collapsed(offset: 0); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection.collapsed(offset: 3); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection.collapsed(offset: 9); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection(baseOffset: 0, extentOffset: 9); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.value = controller.value.copyWith( + composing: const TextRange(start: 2, end: 6), + ); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isTrue); + + controller.value = controller.value.copyWith(composing: TextRange.empty); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + }); + + testWidgets('source spelling correction is one exact transaction', ( + tester, + ) async { + const source = 'mispelled and mispelled\n'; + final projection = const MarkdownSpellingProjector().project( + filePath: '/tmp/spelling.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _sourceSnapshot, + ); + final occurrence = _occurrence( + projection.runs.single, + word: 'mispelled', + logicalStart: 0, + ); + final key = GlobalKey(); + final transactions = + < + ({ + String text, + TextSelection before, + TextSelection after, + String? group, + }) + >[]; + + await tester.pumpWidget( + _testApp( + BusyMarkSourceEditor( + key: key, + text: source, + language: SourceSyntaxLanguage.markdown, + filePath: '/tmp/spelling.md', + documentId: 'source-buffer', + diagnostics: const [], + editorFontSize: 14, + wordWrap: true, + searchActive: false, + searchOptions: const SourceSearchOptions(), + onSearchOptionsChanged: (_) {}, + onChanged: (_, _) {}, + onTransactionalChanged: (text, _, before, after, group) { + transactions.add(( + text: text, + before: before, + after: after, + group: group, + )); + }, + onOpenSearch: () {}, + onCloseSearch: () {}, + editRevision: 7, + initialSelection: const TextSelection(baseOffset: 0, extentOffset: 9), + spellingAnnotations: [_annotation(occurrence)], + ), + ), + ); + await tester.pump(); + + final prepared = await tester.runAsync( + () => prepareSpellingCorrection( + occurrence: occurrence, + suggestion: 'misspelled', + source: source, + ), + ); + expect( + key.currentState!.applyPreparedSpellingCorrection( + occurrence: occurrence, + plan: prepared!.plan, + expectedSource: source, + replacementSource: prepared.replacementSource!, + ), + isTrue, + ); + await tester.pump(); + + expect(transactions, hasLength(1)); + expect(transactions.single.text, 'misspelled and mispelled\n'); + expect( + transactions.single.before, + const TextSelection(baseOffset: 0, extentOffset: 9), + ); + expect( + transactions.single.after, + const TextSelection.collapsed(offset: 10), + ); + expect(transactions.single.group, isNull); + }); + + testWidgets( + 'formatted rich correction preserves structure and publishes once', + (tester) async { + const source = '**mispelled**\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/formatted.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'formatted-buffer', + contentRevision: 3, + documentKind: DocumentKind.markdown, + contextGeneration: 2, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 0, + ); + expect(projection.complete, isTrue, reason: projection.message); + final run = projection.runs.singleWhere( + (candidate) => candidate.text == 'mispelled', + ); + final occurrence = _occurrence(run, word: 'mispelled', logicalStart: 0); + final key = GlobalKey(); + final sources = []; + BusyDocument? updatedDocument; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: 'formatted-buffer', + contentRevision: 3, + useExternalUndoHistory: true, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (value) => updatedDocument = value, + onSourceChanged: (_, _) {}, + onSpellingSourceChanged: (_, value, _, _) => sources.add(value), + ), + ), + ); + await tester.pump(); + + expect( + key.currentState!.applySpellingCorrection( + occurrence: occurrence, + suggestion: 'misspelled', + ), + isTrue, + ); + await tester.pump(); + + expect(sources, ['**misspelled**\n']); + expect(updatedDocument, isNotNull); + expect( + updatedDocument!.blocks.single.inlines.single.kind, + BusyInlineKind.strong, + ); + expect(updatedDocument!.blocks.single.plainText, 'misspelled'); + }, + ); + + testWidgets( + 'rich correction translates later anchors from serialized source', + (tester) async { + const source = 'helo café\n\nwrld\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/entity-normalization.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'entity-normalization-buffer', + contentRevision: 8, + documentKind: DocumentKind.markdown, + contextGeneration: 3, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 0, + ); + final run = projection.runs.singleWhere( + (candidate) => candidate.text.startsWith('helo'), + ); + final occurrence = _occurrence(run, word: 'helo', logicalStart: 0); + final planned = const SpellingReplacementPlanner().build( + occurrence: occurrence, + suggestion: 'hello', + ); + final key = GlobalKey(); + String? committedSource; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: snapshot.bufferId, + contentRevision: snapshot.contentRevision, + useExternalUndoHistory: true, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + onSpellingSourceChanged: (_, value, _, _) { + committedSource = value; + }, + ), + ), + ); + await tester.pump(); + + expect( + key.currentState!.applySpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + ), + isTrue, + ); + await tester.pump(); + + expect(committedSource, 'hello café\n\nwrld\n'); + final actual = busyMarkMinimalSourceEdit(source, committedSource!); + final oldAnchor = source.indexOf('wrld'); + final translatedAnchor = oldAnchor + (actual.newEnd - actual.oldEnd); + expect(translatedAnchor, committedSource!.indexOf('wrld')); + expect( + planned.translateSourceOffset(oldAnchor), + isNot(translatedAnchor), + reason: 'The planned word delta cannot represent entity normalization.', + ); + }, + ); + + testWidgets('rich hard-break correction keeps later source anchor', ( + tester, + ) async { + const source = 'helo \nwrld\n\nmistakke\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/hard-break.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'hard-break-buffer', + contentRevision: 5, + documentKind: DocumentKind.markdown, + contextGeneration: 2, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 0, + ); + final run = projection.runs.firstWhere( + (candidate) => candidate.text.startsWith('helo'), + ); + final occurrence = _occurrence(run, word: 'helo', logicalStart: 0); + final key = GlobalKey(); + String? committedSource; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: snapshot.bufferId, + contentRevision: snapshot.contentRevision, + useExternalUndoHistory: true, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + onSpellingSourceChanged: (_, value, _, _) { + committedSource = value; + }, + ), + ), + ); + await tester.pump(); + expect( + key.currentState!.applySpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + ), + isTrue, + ); + await tester.pump(); + + expect(committedSource, 'hello \nwrld\n\nmistakke\n'); + final actual = busyMarkMinimalSourceEdit(source, committedSource!); + final oldAnchor = source.indexOf('mistakke'); + expect( + oldAnchor + (actual.newEnd - actual.oldEnd), + committedSource!.indexOf('mistakke'), + ); + }); + + testWidgets('rich table correction uses serialized table source delta', ( + tester, + ) async { + const source = + '| helo café |\n' + '| --- |\n' + '\n' + 'wrld\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/table-entity.md', + source: source, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'table-entity-buffer', + contentRevision: 13, + documentKind: DocumentKind.markdown, + contextGeneration: 4, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 0, + ); + final run = projection.runs.firstWhere( + (candidate) => candidate.text.startsWith('helo'), + ); + final occurrence = _occurrence(run, word: 'helo', logicalStart: 0); + final key = GlobalKey(); + String? committedSource; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: snapshot.bufferId, + contentRevision: snapshot.contentRevision, + useExternalUndoHistory: true, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + onSpellingSourceChanged: (_, value, _, _) { + committedSource = value; + }, + ), + ), + ); + await tester.pump(); + expect( + key.currentState!.applySpellingCorrection( + occurrence: occurrence, + suggestion: 'hello', + ), + isTrue, + ); + await tester.pump(); + + expect(committedSource, contains('| hello café |')); + final actual = busyMarkMinimalSourceEdit(source, committedSource!); + final oldAnchor = source.indexOf('wrld'); + expect( + oldAnchor + (actual.newEnd - actual.oldEnd), + committedSource!.indexOf('wrld'), + ); + }); + + testWidgets( + 'rich table-cell correction preserves link and publishes sessions once', + (tester) async { + const source = + '| Heading |\n' + '| --- |\n' + '| [mispelled](target) |\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/table.md', + source: source, + mode: MarkdownMode.commonMark, + ) + .busyDocument; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'rich-buffer', + contentRevision: 11, + documentKind: DocumentKind.markdown, + contextGeneration: 4, + ); + final projection = const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 0, + ); + expect( + projection.complete, + isTrue, + reason: + '${projection.message}; ${projection.runs.map((run) => '${run.target.runtimeType}:${run.text}:${run.atoms.map((atom) => '${atom.context.name}/${atom.sourceStart}/${atom.fieldStart}').join(',')}').join(' | ')}', + ); + final run = projection.runs.singleWhere( + (candidate) => candidate.text == 'mispelled', + ); + expect(run.atoms.every((atom) => atom.sourceStart >= 0), isTrue); + final occurrence = _occurrence(run, word: 'mispelled', logicalStart: 0); + final target = run.target as SpellingRichTableCellTarget; + final key = GlobalKey(); + final publicationOrder = []; + final spellingTransactions = + < + ({ + String source, + WysiwygEditorSessionState before, + WysiwygEditorSessionState after, + }) + >[]; + var genericSourceChanges = 0; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + key: key, + document: document, + documentId: 'rich-buffer', + contentRevision: 11, + useExternalUndoHistory: true, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) => publicationOrder.add('document'), + onSourceChanged: (_, _) => genericSourceChanges++, + onSpellingSourceChanged: (_, source, before, after) { + publicationOrder.add('spelling'); + spellingTransactions.add(( + source: source, + before: before, + after: after, + )); + }, + ), + ), + ); + await tester.pump(); + final field = tester.widget( + find.byKey(ValueKey(target.cellId)), + ); + field.focusNode!.requestFocus(); + field.controller!.selection = const TextSelection( + baseOffset: 0, + extentOffset: 9, + ); + await tester.pump(); + + expect( + key.currentState!.applySpellingCorrection( + occurrence: occurrence, + suggestion: 'misspelled', + ), + isTrue, + ); + await tester.pump(); + + expect(publicationOrder, ['document', 'spelling']); + expect(genericSourceChanges, 0); + expect(spellingTransactions, hasLength(1)); + expect( + spellingTransactions.single.source, + contains('[misspelled](target)'), + ); + expect(spellingTransactions.single.before.activeCellId, target.cellId); + expect(spellingTransactions.single.before.extentOffset, 9); + expect(spellingTransactions.single.after.activeCellId, target.cellId); + expect(spellingTransactions.single.after.extentOffset, 10); + expect( + tester + .widget(find.byKey(ValueKey(target.cellId))) + .controller! + .text, + 'misspelled', + ); + }, + ); + + testWidgets('rich underline painter keeps confirmed helo visible at caret', ( + tester, + ) async { + const source = 'helo\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/live-overlay.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final run = const WysiwygSpellingProjector() + .project( + document: document, + languageId: 'en-Test', + snapshot: _sourceSnapshot, + documentGeneration: 0, + ) + .runs + .single; + final occurrence = _occurrence(run, word: 'helo', logicalStart: 0); + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + document: document, + documentId: 'live-overlay', + contentRevision: 1, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + ), + ), + ); + await tester.pump(); + final field = tester.widget(find.byType(TextField).first); + final controller = field.controller!; + controller.selection = const TextSelection.collapsed(offset: 4); + await tester.pump(); + final overlayFinder = find.byWidgetPredicate( + (widget) => + widget is CustomPaint && + widget.painter.runtimeType.toString() == '_SpellingUnderlinePainter', + ); + expect(overlayFinder, findsOneWidget); + final overlay = tester.widget(overlayFinder); + final painter = overlay.painter!; + const range = TextRange(start: 0, end: 4); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection.collapsed(offset: 2); + await tester.pump(); + expect(tester.widget(overlayFinder).painter, same(painter)); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection(baseOffset: 0, extentOffset: 4); + await tester.pump(); + expect(tester.widget(overlayFinder).painter, same(painter)); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.value = controller.value.copyWith( + composing: const TextRange(start: 0, end: 4), + ); + await tester.pump(); + expect(tester.widget(overlayFinder).painter, same(painter)); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isTrue); + + controller.value = controller.value.copyWith(composing: TextRange.empty); + await tester.pump(); + expect(tester.widget(overlayFinder).painter, same(painter)); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + }); + + testWidgets('table cell underline uses the live cell composing range', ( + tester, + ) async { + const source = '| helo |\n| --- |\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/table-overlay.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final run = const WysiwygSpellingProjector() + .project( + document: document, + languageId: 'en-Test', + snapshot: _sourceSnapshot, + documentGeneration: 0, + ) + .runs + .singleWhere((candidate) => candidate.text == 'helo'); + final occurrence = _occurrence(run, word: 'helo', logicalStart: 0); + final target = run.target as SpellingRichTableCellTarget; + + await tester.pumpWidget( + _testApp( + BusyMarkWysiwygEditor( + document: document, + documentId: 'table-overlay', + contentRevision: 1, + spellingAnnotations: [_annotation(occurrence)], + onDocumentChanged: (_) {}, + onSourceChanged: (_, _) {}, + ), + ), + ); + await tester.pump(); + + final tableView = tester.widget( + find.byType(BusyMarkWysiwygBlockField), + ); + expect(tableView.tableCellSpellingRanges!(target.cellId), [ + const TextRange(start: 0, end: 4), + ]); + final field = tester.widget(find.byKey(ValueKey(target.cellId))); + final controller = field.controller!; + const range = TextRange(start: 0, end: 4); + final overlayFinder = find.byWidgetPredicate( + (widget) => + widget is CustomPaint && + widget.painter.runtimeType.toString() == '_SpellingUnderlinePainter', + ); + expect(overlayFinder, findsOneWidget); + + controller.selection = const TextSelection.collapsed(offset: 4); + await tester.pump(); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection.collapsed(offset: 2); + await tester.pump(); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.selection = const TextSelection(baseOffset: 0, extentOffset: 4); + await tester.pump(); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + + controller.value = controller.value.copyWith( + composing: const TextRange(start: 0, end: 4), + ); + await tester.pump(); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isTrue); + + controller.value = controller.value.copyWith(composing: TextRange.empty); + await tester.pump(); + expect(overlayFinder, findsOneWidget); + expect(busyMarkSpellingUnderlineSuppressed(controller, range), isFalse); + }); +} + +SpellingOccurrence _occurrence( + SpellingProseRun run, { + required String word, + required int logicalStart, +}) => SpellingOccurrence( + id: '${run.id}:$logicalStart', + run: run, + logicalStart: logicalStart, + logicalEnd: logicalStart + word.length, + word: word, + outcome: SpellingCheckOutcome.rejected, +); + +SpellingAnnotation _annotation(SpellingOccurrence occurrence) => + SpellingAnnotation( + occurrenceId: occurrence.id, + start: occurrence.run.target is SpellingSourceTarget + ? occurrence.sourceStart! + : occurrence.fieldStart!, + end: occurrence.run.target is SpellingSourceTarget + ? occurrence.sourceEnd! + : occurrence.fieldEnd!, + target: occurrence.run.target, + ); + +Widget _testApp(Widget child) => MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold(body: SizedBox(width: 900, height: 640, child: child)), +); diff --git a/test/src/spelling_packaging_audit_test.dart b/test/src/spelling_packaging_audit_test.dart new file mode 100644 index 00000000..cf70c211 --- /dev/null +++ b/test/src/spelling_packaging_audit_test.dart @@ -0,0 +1,160 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('shipped spelling catalog is metadata-only and revision pinned', () { + final root = Directory('assets/spelling'); + final dictionaryFiles = root + .listSync(recursive: true) + .whereType() + .where( + (file) => file.path.endsWith('.aff') || file.path.endsWith('.dic'), + ); + expect(dictionaryFiles, isEmpty); + expect(File('${root.path}/NOTICE').existsSync(), isTrue); + expect(Directory('${root.path}/licenses').existsSync(), isTrue); + + final manifest = + jsonDecode(File('${root.path}/dictionaries.json').readAsStringSync()) + as Map; + expect(manifest['schemaVersion'], 2); + final source = (manifest['source'] as Map).cast(); + const revision = '32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4'; + expect(source['revision'], revision); + final dictionaries = (manifest['dictionaries'] as List).cast(); + expect(dictionaries, hasLength(48)); + final resourceIds = {}; + for (final raw in dictionaries) { + final entry = raw.cast(); + expect(resourceIds.add(entry['resourceId']! as String), isTrue); + expect(entry.containsKey('affPath'), isFalse); + expect(entry.containsKey('dicPath'), isFalse); + expect(entry['affSourcePath'], isNotEmpty); + expect(entry['dicSourcePath'], isNotEmpty); + expect( + entry['knownValidProbe'], + isA().having((value) => value, 'probe', isNotEmpty), + ); + expect( + entry['affSize'], + isA().having((value) => value, 'size', isPositive), + ); + expect( + entry['dicSize'], + isA().having((value) => value, 'size', isPositive), + ); + expect(entry['affSha256'].toString(), hasLength(64)); + expect(entry['dicSha256'].toString(), hasLength(64)); + expect( + entry['affDownloadUrl'].toString(), + startsWith( + 'https://raw.githubusercontent.com/LibreOffice/dictionaries/' + '$revision/', + ), + ); + expect( + entry['dicDownloadUrl'].toString(), + startsWith( + 'https://raw.githubusercontent.com/LibreOffice/dictionaries/' + '$revision/', + ), + ); + } + }); + + test('ordinary Linux release does not prepare all-language pairs', () { + final cmake = File('linux/CMakeLists.txt').readAsStringSync(); + expect(cmake, isNot(contains('add_custom_target(busymark_spelling ALL'))); + expect(cmake, isNot(contains('fetch_spelling_dictionaries.sh'))); + expect(cmake, contains('../assets/spelling/')); + expect(cmake, contains('PATTERN "*.aff" EXCLUDE')); + expect(cmake, contains('PATTERN "*.dic" EXCLUDE')); + + final snapcraft = File('snap/snapcraft.yaml').readAsStringSync(); + expect( + snapcraft, + contains( + r'BUSYMARK_SPELLING_INSTALL_ROOT: $SNAP_USER_COMMON/spelling/dictionaries', + ), + ); + }); + + test('committed spelling checksum inventory matches exact shipped bytes', () { + final root = Directory('assets/spelling'); + final inventory = File('${root.path}/CHECKSUMS.sha256') + .readAsLinesSync() + .where((line) => line.trim().isNotEmpty) + .toList(growable: false); + final inventoried = {}; + for (final line in inventory) { + final match = RegExp(r'^([0-9a-f]{64}) (.+)$').firstMatch(line); + expect(match, isNotNull, reason: line); + final relative = match!.group(2)!; + expect(inventoried.add(relative), isTrue, reason: relative); + final file = File('${root.path}/$relative'); + expect(file.existsSync(), isTrue, reason: relative); + expect(sha256.convert(file.readAsBytesSync()).toString(), match.group(1)); + } + final shipped = root + .listSync(recursive: true) + .whereType() + .map((file) => file.path.substring(root.path.length + 1)) + .where((path) => path != 'CHECKSUMS.sha256') + .toSet(); + expect(inventoried, shipped); + }); + + test('native spelling notices are explicit installed artifacts', () { + final cmake = File('linux/CMakeLists.txt').readAsStringSync(); + expect(cmake, contains('busymark_spellcheck_native/DEPENDENCIES.md')); + expect( + cmake, + contains('busymark_spellcheck_native/third_party/hunspell/licenses/'), + ); + expect(cmake, contains('Apache-2.0.txt')); + for (final notice in [ + 'COPYING', + 'COPYING.LESSER', + 'COPYING.MPL', + 'license.hunspell', + 'license.myspell', + ]) { + expect( + File( + 'packages/busymark_spellcheck_native/third_party/hunspell/licenses/$notice', + ).existsSync(), + isTrue, + reason: notice, + ); + } + }); + + test( + 'strict Snap smoke performs and verifies a local revision transition', + () { + final workflow = File( + '.github/workflows/flutter-linux.yml', + ).readAsStringSync(); + expect(workflow, isNot(contains('snap refresh --dangerous'))); + expect(workflow, contains('sudo snap install --dangerous')); + expect(workflow, contains('before_revision="\$(snap list busymark')); + expect(workflow, contains('after_revision="\$(snap list busymark')); + expect( + workflow, + contains('test "\$before_revision" != "\$after_revision"'), + ); + final revisionAssertion = workflow.indexOf( + 'test "\$before_revision" != "\$after_revision"', + ); + final networkDisconnect = workflow.indexOf( + 'sudo snap disconnect busymark:network', + revisionAssertion, + ); + expect(revisionAssertion, isNonNegative); + expect(networkDisconnect, greaterThan(revisionAssertion)); + }, + ); +} diff --git a/test/src/spelling_release_smoke_test.dart b/test/src/spelling_release_smoke_test.dart new file mode 100644 index 00000000..7880d8e3 --- /dev/null +++ b/test/src/spelling_release_smoke_test.dart @@ -0,0 +1,30 @@ +import 'package:busymark/src/spellcheck/spelling_release_smoke.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('spelling release smoke requires an explicit guarded report path', () { + expect( + spellingReleaseSmokeReportPath(const [ + '--spelling-release-smoke=/tmp/report.json', + ]), + isNull, + ); + expect( + spellingReleaseSmokeReportPath( + const ['--spelling-release-smoke='], + environment: const {'BUSYMARK_RELEASE_SMOKE': '1'}, + ), + isNull, + ); + expect( + spellingReleaseSmokeReportPath( + const [ + '/workspace/document.md', + '--spelling-release-smoke=/tmp/report.json', + ], + environment: const {'BUSYMARK_RELEASE_SMOKE': '1'}, + ), + '/tmp/report.json', + ); + }); +} diff --git a/test/src/spelling_service_test.dart b/test/src/spelling_service_test.dart new file mode 100644 index 00000000..9bb3ed89 --- /dev/null +++ b/test/src/spelling_service_test.dart @@ -0,0 +1,3795 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/l10n/generated/app_localizations_en.dart'; +import 'package:busymark/src/app/app_settings.dart'; +import 'package:busymark/src/app/busymark_toast.dart'; +import 'package:busymark/src/core/atomic_file_writer.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/spellcheck/markdown_spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_coordinator.dart'; +import 'package:busymark/src/spellcheck/spelling_catalog.dart'; +import 'package:busymark/src/spellcheck/spelling_dictionary_downloader.dart'; +import 'package:busymark/src/spellcheck/spelling_dictionary_importer.dart'; +import 'package:busymark/src/spellcheck/spelling_dictionary_installer.dart'; +import 'package:busymark/src/spellcheck/spelling_language.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_replacement.dart'; +import 'package:busymark/src/spellcheck/spelling_session_controller.dart'; +import 'package:busymark/src/spellcheck/spelling_word_store.dart'; +import 'package:busymark/src/spellcheck/spelling_worker.dart'; +import 'package:busymark/src/spellcheck/wysiwyg_spelling_projection.dart'; +import 'package:busymark/src/spellcheck/writerside_spelling_projection.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; +import 'package:busymark/src/workspace/presentation/workspace_screen.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:crypto/crypto.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +const _snapshot = SpellingSnapshotIdentity( + bufferId: 'buffer', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, +); + +void main() { + test('document kinds expose one authoritative spelling capability', () { + expect(DocumentKind.markdown.supportsSpelling, isTrue); + expect(DocumentKind.writersideMarkdownTopic.supportsSpelling, isTrue); + expect(DocumentKind.writersideXmlTopic.supportsSpelling, isTrue); + for (final kind in DocumentKind.values.where( + (kind) => + kind != DocumentKind.markdown && + kind != DocumentKind.writersideMarkdownTopic && + kind != DocumentKind.writersideXmlTopic, + )) { + expect(kind.supportsSpelling, isFalse, reason: kind.name); + } + }); + + test('effective spelling language preserves document and project order', () { + expect( + resolveSpellingLanguageId( + override: const SpellingLanguageOverride.selected('fr-CA'), + projectLanguage: 'de-DE', + defaultLanguage: 'en-CA', + ), + 'fr-CA', + ); + expect( + resolveSpellingLanguageId( + override: const SpellingLanguageOverride.inherit(), + projectLanguage: 'de-DE', + defaultLanguage: 'en-CA', + ), + 'de-DE', + ); + expect( + resolveSpellingLanguageId( + override: const SpellingLanguageOverride.inherit(), + projectLanguage: null, + defaultLanguage: 'en-CA', + ), + 'en-CA', + ); + expect( + resolveSpellingLanguageId( + override: const SpellingLanguageOverride.disabled(), + projectLanguage: 'de-DE', + defaultLanguage: 'en-CA', + ), + isNull, + ); + }); + + test('session identity changes when a stable buffer is saved to a path', () { + final settings = AppSettings.defaults(); + final untitled = DocumentBuffer.untitled( + id: 'stable-buffer', + name: 'Untitled.md', + text: 'helo', + ); + SpellingSessionInput input(DocumentBuffer buffer) => SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + + final firstSave = untitled.copyWith(filePath: '/tmp/first.md'); + final saveAs = firstSave.copyWith(filePath: '/tmp/second.md'); + expect(input(untitled).identity, isNot(input(firstSave).identity)); + expect(input(firstSave).identity, isNot(input(saveAs).identity)); + expect(saveAs.id, untitled.id); + expect(saveAs.revision, untitled.revision); + }); + + test('downloaded dictionaries use revision-shared Snap storage', () { + expect( + resolveSpellingDictionaryStorageRoot( + applicationSupportRoot: '/snap/revision/data', + environment: const {'SNAP_USER_COMMON': '/snap/common'}, + ), + '/snap/common/spelling/dictionaries', + ); + }); + + test('first save and Save As republish source routing immediately', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-save-as-spelling-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + var buffer = DocumentBuffer.untitled( + id: 'stable-save-buffer', + name: 'Untitled.md', + text: 'helo', + ); + SpellingSessionInput input() => SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + + await controller.checkNow(input()); + expect( + (controller.misspellings.single.run.target as SpellingSourceTarget) + .filePath, + 'stable-save-buffer', + ); + for (final path in ['/tmp/first-save.md', '/tmp/save-as.md']) { + buffer = buffer.copyWith(filePath: path); + controller.update(input()); + await _waitFor( + () => + controller.state.status == SpellingPresentationStatus.ready && + controller.misspellings.singleOrNull?.run.target + is SpellingSourceTarget && + (controller.misspellings.single.run.target as SpellingSourceTarget) + .filePath == + path, + ); + final occurrence = controller.occurrenceAtSource(1); + expect(occurrence, isNotNull); + expect(controller.isCurrent(occurrence!), isTrue); + expect(buffer.id, 'stable-save-buffer'); + expect(buffer.revision, 0); + } + }); + + group('persistent spelling words', () { + late Directory temporary; + late String path; + + setUp(() async { + temporary = await Directory.systemTemp.createTemp('busymark-words-'); + path = p.join(temporary.path, 'spelling.json'); + }); + + tearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + + test('rereads and merges independent external changes', () async { + final first = SpellingWordStore(filePath: path, projectStore: true); + final second = SpellingWordStore(filePath: path, projectStore: true); + + await Future.wait([ + first.addWord('en-US', 'BusyMark'), + second.addWord('en-US', 'BusyStack'), + ]); + await first.setProjectLanguage('en-US'); + final saved = await second.read(); + + expect(saved.projectLanguage, 'en-US'); + expect( + saved.wordsFor('en-US'), + containsAll(['BusyMark', 'BusyStack']), + ); + expect(saved.revision, 3); + }); + + test('coordinates writers in independent application processes', () async { + final flutterRoot = Platform.environment['FLUTTER_ROOT']; + final dartExecutable = flutterRoot == null + ? 'dart' + : p.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', 'dart'); + final helper = p.join( + Directory.current.path, + 'test', + 'support', + 'spelling_word_store_process.dart', + ); + final results = await Future.wait([ + Process.run(dartExecutable, [ + '--packages=.dart_tool/package_config.json', + helper, + path, + 'BusyMark', + ], workingDirectory: Directory.current.path), + Process.run(dartExecutable, [ + '--packages=.dart_tool/package_config.json', + helper, + path, + 'BusyStack', + ], workingDirectory: Directory.current.path), + ]); + for (final result in results) { + expect( + result.exitCode, + 0, + reason: '${result.stdout}\n${result.stderr}', + ); + } + + final saved = await SpellingWordStore( + filePath: path, + projectStore: true, + ).read(); + expect(saved.wordsFor('en-US'), containsAll(['BusyMark', 'BusyStack'])); + expect(saved.revision, 2); + }); + + test('merges an external edit injected after staging', () async { + final delayed = _DelayedAtomicFileWriter(); + addTearDown(delayed.releaseIfNeeded); + final store = SpellingWordStore(filePath: path, writer: delayed); + final mutation = store.addWord('en-US', 'BusyMark'); + await delayed.started.future; + await File(path).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 7, + 'words': { + 'en-US': [ + {'key': 'BusyStack', 'display': 'BusyStack'}, + ], + }, + }), + flush: true, + ); + delayed.releaseIfNeeded(); + + final saved = await mutation; + expect(saved.wordsFor('en-US'), containsAll(['BusyMark', 'BusyStack'])); + expect(saved.revision, 8); + }); + + test('merges an external replacement after the atomic exchange', () async { + await SpellingWordStore(filePath: path).addWord('en-US', 'InitialWord'); + final exchanged = _PostExchangeAtomicFileWriter(); + addTearDown(exchanged.releaseIfNeeded); + final store = SpellingWordStore(filePath: path, writer: exchanged); + final mutation = store.addWord('en-US', 'BusyMark'); + await exchanged.exchanged.future; + + await File(path).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 7, + 'words': { + 'en-US': [ + {'key': 'BusyStack', 'display': 'BusyStack'}, + ], + }, + }), + flush: true, + ); + exchanged.releaseIfNeeded(); + + final saved = await mutation; + expect(saved.wordsFor('en-US'), containsAll(['BusyMark', 'BusyStack'])); + expect(saved.revision, 8); + }); + + test( + 'preserves a newer destination and the rejected displaced version', + () async { + await SpellingWordStore(filePath: path).addWord('en-US', 'InitialWord'); + final writer = _RejectedExchangeAtomicFileWriter(); + addTearDown(writer.releaseIfNeeded); + final mutation = SpellingWordStore( + filePath: path, + writer: writer, + ).addWord('en-US', 'BusyMark'); + + await writer.beforeValidated.future; + await File(path).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 7, + 'words': { + 'en-US': [ + {'key': 'BusyStack', 'display': 'BusyStack'}, + ], + }, + }), + flush: true, + ); + writer.releaseBeforeExchange(); + await writer.exchanged.future; + await File(path).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 8, + 'words': { + 'en-US': [ + {'key': 'NewestExternal', 'display': 'NewestExternal'}, + ], + }, + }), + flush: true, + ); + writer.releaseValidation(); + + AtomicFileChangedException? conflict; + try { + await mutation; + fail('Expected publication ownership to be reported as uncertain.'); + } on AtomicFileChangedException catch (error) { + conflict = error; + } + expect(conflict.recoveryPath, isNotNull); + expect( + (await SpellingWordStore(filePath: path).read()).wordsFor('en-US'), + ['NewestExternal'], + ); + expect( + (await SpellingWordStore( + filePath: conflict.recoveryPath!, + ).read()).wordsFor('en-US'), + ['BusyStack'], + ); + }, + ); + + test( + 'preserves case while merging canonical Unicode equivalents', + () async { + final store = SpellingWordStore(filePath: path); + + await store.addWord('en-US', 'BusyBrand'); + await store.addWord('en-US', 'busybrand'); + await store.addWord('en-US', 'Cafe\u0301'); + await store.addWord('en-US', 'Café'); + var saved = await store.read(); + + expect(saved.wordsFor('en-US'), ['BusyBrand', 'Café', 'busybrand']); + await store.removeWord('en-US', 'BusyBrand'); + saved = await store.read(); + expect(saved.wordsFor('en-US'), ['Café', 'busybrand']); + }, + ); + + test( + 'rebuilds untrusted stored keys from validated display values', + () async { + await File(path).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'revision': 4, + 'words': { + 'en-US': [ + {'key': 'forged-key', 'display': 'BusyBrand'}, + ], + }, + }), + ); + + final saved = await SpellingWordStore(filePath: path).read(); + expect(saved.wordsByLanguage['en-US']!.single.key, 'BusyBrand'); + await expectLater( + SpellingWordStore(filePath: path).addWord('en-US', 'bad\u0001word'), + throwsArgumentError, + ); + }, + ); + + test( + 'case-distinct words survive restart into the native worker', + () async { + final store = SpellingWordStore(filePath: path); + var saved = await store.addWord('en-Test', 'BusyBrand'); + final worker = await SpellingWorker.start(); + addTearDown(worker.close); + + var result = await worker.check( + context: _fixtureContext( + project: 'persistent-case', + revision: saved.revision, + words: saved.wordsFor('en-Test').toList(), + ), + runs: [_run('BusyBrand busybrand')], + ); + expect(result.occurrences.map((item) => item.word), ['busybrand']); + + saved = await SpellingWordStore( + filePath: path, + ).addWord('en-Test', 'busybrand'); + result = await worker.check( + context: _fixtureContext( + project: 'persistent-case', + revision: saved.revision, + words: saved.wordsFor('en-Test').toList(), + ), + runs: [_run('BusyBrand busybrand')], + ); + expect(result.occurrences, isEmpty); + }, + ); + + test('malformed storage is reported instead of overwritten', () async { + await File(path).writeAsString('{broken'); + final store = SpellingWordStore(filePath: path); + + await expectLater( + store.addWord('en-US', 'BusyMark'), + throwsFormatException, + ); + expect(await File(path).readAsString(), '{broken'); + }); + }); + + test( + 'staging validation accepts numeric header revisions and count drift', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-dictionary-structure-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final aff = File(p.join(temporary.path, 'test.aff')); + final dic = File(p.join(temporary.path, 'test.dic')); + final affBytes = utf8.encode('SET UTF-8\n'); + final dicBytes = utf8.encode('2\t1\nhello\n'); + await aff.writeAsBytes(affBytes); + await dic.writeAsBytes(dicBytes); + + await expectLater( + validateSpellingDictionaryPair( + affSource: aff, + dicSource: dic, + expectedAffSize: affBytes.length, + expectedDicSize: dicBytes.length, + expectedAffSha256: sha256.convert(affBytes).toString(), + expectedDicSha256: sha256.convert(dicBytes).toString(), + ), + completes, + ); + + final emptyBytes = utf8.encode('1\n'); + await dic.writeAsBytes(emptyBytes); + await expectLater( + validateSpellingDictionaryPair( + affSource: aff, + dicSource: dic, + expectedAffSize: affBytes.length, + expectedDicSize: emptyBytes.length, + expectedAffSha256: sha256.convert(affBytes).toString(), + expectedDicSha256: sha256.convert(emptyBytes).toString(), + ), + throwsFormatException, + ); + }, + ); + + test( + 'dictionary import publishes a complete pair only after validation', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-import-', + ); + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final imported = p.join(temporary.path, 'dictionaries'); + try { + await const SpellingDictionaryImporter().import( + affPath: p.join(fixture, 'test.aff'), + dicPath: p.join(fixture, 'test.dic'), + languageId: 'en-Test', + displayLabel: 'Test English', + importedRoot: imported, + validateNativePair: (_, _, _) async => 'UTF-8', + ); + final published = Directory(p.join(imported, 'en-Test')); + expect( + File(p.join(published.path, 'dictionary.aff')).existsSync(), + isTrue, + ); + expect( + File(p.join(published.path, 'dictionary.dic')).existsSync(), + isTrue, + ); + expect( + File(p.join(published.path, 'manifest.json')).existsSync(), + isTrue, + ); + + await expectLater( + const SpellingDictionaryImporter().import( + affPath: p.join(fixture, 'test.aff'), + dicPath: p.join(fixture, 'test.dic'), + languageId: 'fr-Test', + displayLabel: 'Broken', + importedRoot: imported, + validateNativePair: (_, _, _) async => throw StateError('rejected'), + ), + throwsStateError, + ); + expect(Directory(p.join(imported, 'fr-Test')).existsSync(), isFalse); + } finally { + if (await temporary.exists()) await temporary.delete(recursive: true); + } + }, + ); + + group('on-demand dictionary installation', () { + late Directory temporary; + late File fixtureAff; + late File fixtureDic; + late SpellingDictionaryResource resource; + + setUp(() async { + temporary = await Directory.systemTemp.createTemp('busymark-download-'); + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + fixtureAff = File(p.join(fixture, 'test.aff')); + fixtureDic = File(p.join(fixture, 'test.dic')); + resource = SpellingDictionaryResource( + resourceId: 'en-Test', + id: 'en-Test', + locales: const ['en-Test', 'en-Shared'], + label: 'Test English', + affSourcePath: 'fixture/test.aff', + dicSourcePath: 'fixture/test.dic', + affDownloadUrl: Uri.parse('https://example.invalid/test.aff'), + dicDownloadUrl: Uri.parse('https://example.invalid/test.dic'), + affSize: await fixtureAff.length(), + dicSize: await fixtureDic.length(), + affSha256: (await sha256.bind(fixtureAff.openRead()).first).toString(), + dicSha256: (await sha256.bind(fixtureDic.openRead()).first).toString(), + sourceRevision: 'fixture', + knownValidProbe: 'hello', + ); + }); + + tearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + + Future copyDownload({ + required Uri source, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, + }) async { + cancellation.throwIfCancelled(); + final input = source.path.endsWith('.aff') ? fixtureAff : fixtureDic; + final bytes = await input.readAsBytes(); + expect(bytes, hasLength(expectedBytes)); + await destination.writeAsBytes(bytes, flush: true); + onProgress(bytes.length); + } + + test('installs only one shared resource and reuses it by locale', () async { + final root = p.join(temporary.path, 'downloaded'); + final installation = + await SpellingDictionaryDownloader( + downloadFile: copyDownload, + ).install( + resource: resource, + downloadedRoot: root, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_, _) {}, + ); + + expect(installation.resourceId, 'en-Test'); + expect( + await Directory( + root, + ).list().where((entity) => entity is Directory).length, + 1, + ); + final catalogRoot = Directory(p.join(temporary.path, 'catalog')); + await catalogRoot.create(); + await File(p.join(catalogRoot.path, 'dictionaries.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 2, + 'dictionaries': [_resourceJson(resource)], + }), + ); + final catalog = await SpellingDictionaryCatalog.load( + bundledRoot: catalogRoot.path, + downloadedRoot: root, + ); + expect(catalog.availableEntries, hasLength(1)); + expect( + catalog.installedById('en-Test'), + same(catalog.installedById('en-Shared')), + ); + }); + + test('cancellation and checksum failure leave no installation', () async { + final cancelledRoot = p.join(temporary.path, 'cancelled'); + final cancellation = SpellingDictionaryDownloadCancellation(); + await expectLater( + SpellingDictionaryDownloader( + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + cancellation.cancel(); + cancellation.throwIfCancelled(); + }, + ).install( + resource: resource, + downloadedRoot: cancelledRoot, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: cancellation, + onProgress: (_, _) {}, + ), + throwsA(isA()), + ); + expect(await _publishedDirectories(cancelledRoot), isEmpty); + + final badRoot = p.join(temporary.path, 'bad-checksum'); + final badResource = SpellingDictionaryResource( + resourceId: resource.resourceId, + id: resource.id, + locales: resource.locales, + label: resource.label, + affSourcePath: resource.affSourcePath, + dicSourcePath: resource.dicSourcePath, + affDownloadUrl: resource.affDownloadUrl, + dicDownloadUrl: resource.dicDownloadUrl, + affSize: resource.affSize, + dicSize: resource.dicSize, + affSha256: '0' * 64, + dicSha256: resource.dicSha256, + sourceRevision: resource.sourceRevision, + knownValidProbe: resource.knownValidProbe, + ); + await expectLater( + SpellingDictionaryDownloader(downloadFile: copyDownload).install( + resource: badResource, + downloadedRoot: badRoot, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_, _) {}, + ), + throwsFormatException, + ); + expect(await _publishedDirectories(badRoot), isEmpty); + }); + + test('cancellation observes the atomic publication commit point', () async { + final beforeRoot = p.join(temporary.path, 'cancel-before-commit'); + var guardCalls = 0; + await expectLater( + const SpellingDictionaryPairInstaller().install( + affSource: fixtureAff, + dicSource: fixtureDic, + spec: SpellingDictionaryInstallSpec.downloaded(resource), + destinationRoot: beforeRoot, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellationGuard: () { + guardCalls++; + if (guardCalls == 4) { + throw const SpellingDictionaryDownloadCancelled(); + } + }, + ), + throwsA(isA()), + ); + expect(await _publishedDirectories(beforeRoot), isEmpty); + + final afterRoot = p.join(temporary.path, 'cancel-after-commit'); + final cancellation = SpellingDictionaryDownloadCancellation(); + final installation = + await SpellingDictionaryDownloader( + installer: SpellingDictionaryPairInstaller( + onCommitted: (_) => cancellation.cancel(), + ), + downloadFile: copyDownload, + ).install( + resource: resource, + downloadedRoot: afterRoot, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: cancellation, + onProgress: (_, _) {}, + ); + + expect(cancellation.isCancelled, isTrue); + expect(Directory(installation.directoryPath).existsSync(), isTrue); + expect(await _publishedDirectories(afterRoot), hasLength(1)); + }); + + test('stalled response times out, cancels, and permits retry', () async { + final body = StreamController>(); + final cancelled = Completer(); + body.onCancel = () { + if (!cancelled.isCompleted) cancelled.complete(); + }; + body.add(const [1]); + final destination = File(p.join(temporary.path, 'stalled.dic')); + + await expectLater( + receiveSpellingDictionaryBody( + bytes: body.stream, + destination: destination, + expectedBytes: 2, + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_) {}, + inactivityTimeout: const Duration(milliseconds: 30), + ), + throwsA(isA()), + ); + await cancelled.future; + + await receiveSpellingDictionaryBody( + bytes: Stream.fromIterable(const [ + [1], + [2], + ]), + destination: destination, + expectedBytes: 2, + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_) {}, + inactivityTimeout: const Duration(milliseconds: 30), + ); + expect(await destination.readAsBytes(), [1, 2]); + }); + + test('a failed replacement cannot damage a working installation', () async { + final root = p.join(temporary.path, 'working'); + final installed = + await SpellingDictionaryDownloader( + downloadFile: copyDownload, + ).install( + resource: resource, + downloadedRoot: root, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_, _) {}, + ); + final originalAff = await File(installed.affPath).readAsBytes(); + final originalDic = await File(installed.dicPath).readAsBytes(); + final badResource = SpellingDictionaryResource( + resourceId: resource.resourceId, + id: resource.id, + locales: resource.locales, + label: resource.label, + affSourcePath: resource.affSourcePath, + dicSourcePath: resource.dicSourcePath, + affDownloadUrl: resource.affDownloadUrl, + dicDownloadUrl: resource.dicDownloadUrl, + affSize: resource.affSize, + dicSize: resource.dicSize, + affSha256: '0' * 64, + dicSha256: resource.dicSha256, + sourceRevision: resource.sourceRevision, + knownValidProbe: resource.knownValidProbe, + ); + + await expectLater( + SpellingDictionaryDownloader(downloadFile: copyDownload).install( + resource: badResource, + downloadedRoot: root, + validateNativePair: (_, _, _) async => 'UTF-8', + cancellation: SpellingDictionaryDownloadCancellation(), + onProgress: (_, _) {}, + ), + throwsFormatException, + ); + + expect(await _publishedDirectories(root), hasLength(1)); + expect(await File(installed.affPath).readAsBytes(), originalAff); + expect(await File(installed.dicPath).readAsBytes(), originalDic); + }); + + test('a failed controller download exposes a working retry', () async { + final catalogRoot = Directory(p.join(temporary.path, 'catalog')); + await catalogRoot.create(); + await File(p.join(catalogRoot.path, 'dictionaries.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 2, + 'dictionaries': [_resourceJson(resource)], + }), + ); + var failNextDownload = true; + final controller = SpellingSessionController( + bundledRoot: catalogRoot.path, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'managed'), + dictionaryDownloader: SpellingDictionaryDownloader( + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + if (failNextDownload) { + failNextDownload = false; + throw const SocketException('test download failure'); + } + await copyDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ), + ); + addTearDown(controller.dispose); + await controller.prepareSettings(null); + + await expectLater( + controller.installDictionary(resource.id), + throwsA(isA()), + ); + expect( + controller.dictionaryInstallStatus?.phase, + SpellingDictionaryInstallPhase.failed, + ); + + await controller.retryDictionaryInstallation(); + + expect(controller.dictionaryInstallStatus, isNull); + expect(controller.catalog?.installedById(resource.id), isNotNull); + expect( + await _publishedDirectories( + p.join(temporary.path, 'managed', 'downloaded'), + ), + hasLength(1), + ); + }); + }); + + test( + 'aliased imports remain selectable across collision, restart, and removal', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-alias-import-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final fixture = await _createAliasedFixtureBundle(temporary); + final support = p.join(temporary.path, 'support'); + final storage = p.join(temporary.path, 'dictionary-storage'); + var controller = SpellingSessionController( + bundledRoot: fixture.bundle, + applicationSupportRoot: support, + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + ); + await controller.prepareSettings(null); + expect(controller.catalog!.installedById('nl-AW')!.imported, isFalse); + + await controller.importDictionary( + affPath: fixture.aff, + dicPath: fixture.dic, + languageId: 'nl-NL', + displayLabel: 'Imported Dutch', + ); + final imported = controller.catalog!.installedById('nl-NL')!; + expect(imported.id, 'nl-NL'); + expect(imported.imported, isTrue); + expect( + controller.catalog!.entries.where((entry) => entry.id == 'nl-NL'), + hasLength(1), + ); + final input = SpellingSessionInput( + buffer: DocumentBuffer.untitled( + id: 'alias-import', + name: 'alias.md', + text: 'helo', + ), + workspace: null, + settings: AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'nl-NL', + ), + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + controller.update(input); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + expect(controller.effectiveLanguage, 'nl-NL'); + expect(controller.misspellings.single.word, 'helo'); + controller.dispose(); + + controller = SpellingSessionController( + bundledRoot: fixture.bundle, + applicationSupportRoot: support, + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + controller.update(input.refreshed()); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + expect(controller.catalog!.installedById('nl-NL')!.imported, isTrue); + + await controller.removeImportedDictionary('nl-NL'); + expect( + controller.catalog!.installations.where( + (installation) => installation.id == 'nl-NL', + ), + isEmpty, + ); + expect(controller.catalog!.installedById('nl-AW')!.imported, isFalse); + expect(controller.catalog!.installedById('nl-NL')!.id, 'nl-AW'); + }, + ); + + test( + 'same-resource import collision is rejected before publication', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-import-collision-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final fixtureRoot = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final storage = p.join(temporary.path, 'dictionary-storage'); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + await controller.prepareSettings(null); + + await expectLater( + controller.importDictionary( + affPath: p.join(fixtureRoot, 'test.aff'), + dicPath: p.join(fixtureRoot, 'test.dic'), + languageId: 'en-Test', + displayLabel: 'Imported Test English', + ), + throwsStateError, + ); + expect(await _publishedDirectories(p.join(storage, 'imported')), isEmpty); + expect(controller.catalog!.installedById('en-Test')!.imported, isFalse); + }, + ); + + test( + 'an import does not impersonate the downloadable resource row', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-import-first-ownership-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final fixtureRoot = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final storage = p.join(temporary.path, 'dictionary-storage'); + await Directory(p.join(storage, 'downloaded')).delete(recursive: true); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + dictionaryDownloader: SpellingDictionaryDownloader( + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + final fixture = File( + p.join( + fixtureRoot, + source.path.endsWith('.aff') ? 'test.aff' : 'test.dic', + ), + ); + await fixture.copy(destination.path); + onProgress(expectedBytes); + }, + ), + ); + addTearDown(controller.dispose); + await controller.prepareSettings(null); + await controller.importDictionary( + affPath: p.join(fixtureRoot, 'test.aff'), + dicPath: p.join(fixtureRoot, 'test.dic'), + languageId: 'en-Test', + displayLabel: 'Local Test English', + ); + + final catalog = controller.catalog!; + expect(catalog.installedById('en-Test')?.imported, isTrue); + expect( + catalog.installationForResource( + 'en-Test', + kind: SpellingDictionaryInstallationKind.downloaded, + ), + isNull, + ); + await controller.removeDownloadedDictionary('en-Test'); + expect(controller.catalog!.installedById('en-Test')?.imported, isTrue); + await expectLater( + controller.installDictionary('en-Test'), + throwsStateError, + ); + + await controller.removeImportedDictionary('en-Test'); + expect(controller.catalog!.installedById('en-Test'), isNull); + await controller.installDictionary('en-Test'); + final downloaded = controller.catalog!.installationForResource( + 'en-Test', + kind: SpellingDictionaryInstallationKind.downloaded, + ); + expect(downloaded, isNotNull); + expect(downloaded!.imported, isFalse); + }, + ); + + test('invalid imported installation is removable by exact record', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-invalid-import-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final storage = p.join(temporary.path, 'dictionary-storage'); + final broken = Directory(p.join(storage, 'imported', 'xx-Test')); + await broken.create(recursive: true); + await File(p.join(broken.path, 'manifest.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'kind': 'imported', + 'resourceId': 'xx-Test', + 'id': 'xx-Test', + 'locales': ['xx-Test'], + 'label': 'Broken import', + 'sourceRevision': 'local-import', + 'affPath': 'missing.aff', + 'dicPath': 'missing.dic', + 'affSha256': '0' * 64, + 'dicSha256': '0' * 64, + }), + ); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + await controller.prepareSettings(null); + final invalid = controller.catalog!.invalidInstallations.singleWhere( + (entry) => entry.id == 'xx-Test', + ); + + await controller.removeInvalidDictionary(invalid); + + expect(await broken.exists(), isFalse); + expect( + controller.catalog!.invalidInstallations.where( + (entry) => entry.id == 'xx-Test', + ), + isEmpty, + ); + }); + + test( + 'invalid downloaded installation repairs through settings API', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-dictionary-repair-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final fixtureAff = File(p.join(fixture, 'test.aff')); + final fixtureDic = File(p.join(fixture, 'test.dic')); + final storage = p.join(temporary.path, 'dictionary-storage'); + await File( + p.join(storage, 'downloaded', 'en-Test', 'dictionary.dic'), + ).delete(); + var notifications = 0; + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: storage, + verifyDictionaryChecksums: false, + dictionaryDownloader: SpellingDictionaryDownloader( + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + cancellation.throwIfCancelled(); + final sourceFile = source.path.endsWith('.aff') + ? fixtureAff + : fixtureDic; + final bytes = await sourceFile.readAsBytes(); + expect(bytes, hasLength(expectedBytes)); + await destination.writeAsBytes(bytes, flush: true); + onProgress(bytes.length); + }, + ), + )..addListener(() => notifications++); + addTearDown(controller.dispose); + await controller.prepareSettings(null); + expect(controller.catalog!.installedById('en-Test'), isNull); + expect(controller.catalog!.invalidById('en-Test'), isNotNull); + + final beforeInstall = notifications; + await controller.installDictionary('en-Test'); + + expect(controller.dictionaryInstallStatus, isNull); + expect(controller.catalog!.invalidById('en-Test'), isNull); + expect(controller.catalog!.installedById('en-Test'), isNotNull); + expect(notifications, greaterThan(beforeInstall)); + }, + ); + + test('Ignore Once keeps its authored anchor across editor modes', () async { + const source = 'helo hello helo\n'; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'mode-switch', + contentRevision: 3, + documentKind: DocumentKind.markdown, + contextGeneration: 2, + ); + final document = const MarkdownParser() + .parse( + filePath: '/tmp/mode-switch.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + final context = _fixtureContext(project: 'ignore-once', revision: 0); + + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: snapshot, + engineContext: context, + automatic: false, + project: () async => const WysiwygSpellingProjector().project( + document: document, + languageId: 'en-Test', + snapshot: snapshot, + documentGeneration: 5, + ), + ), + ); + final first = coordinator.misspellings.singleWhere( + (occurrence) => occurrence.sourceStart == 0, + ); + expect(coordinator.isCurrent(first), isTrue); + coordinator.ignoreOnce(first); + expect(coordinator.isCurrent(first), isFalse); + expect(coordinator.annotations, hasLength(1)); + + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: snapshot, + engineContext: context, + automatic: false, + project: () async => const MarkdownSpellingProjector().project( + filePath: '/tmp/mode-switch.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: snapshot, + ), + ), + ); + + expect(coordinator.annotations, hasLength(1)); + expect(coordinator.annotations.single.start, source.lastIndexOf('helo')); + }); + + test( + 'source hit testing excludes formatting and link destination gaps', + () async { + const source = '**mispel**led [mispelled](destination)\n'; + const snapshot = SpellingSnapshotIdentity( + bufferId: 'source-hit-segments', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: snapshot, + engineContext: _fixtureContext(project: 'source-hit', revision: 0), + automatic: false, + project: () async => const MarkdownSpellingProjector().project( + filePath: '/tmp/source-hit.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: snapshot, + ), + ), + ); + + expect(coordinator.misspellings, hasLength(2)); + expect(coordinator.occurrenceAtSource(0), isNull); + expect(coordinator.occurrenceAtSource(3)?.word, 'mispelled'); + expect(coordinator.occurrenceAtSource(8), isNull); + expect( + coordinator.occurrenceAtSource(source.indexOf('destination') + 2), + isNull, + ); + expect( + coordinator.occurrenceAtSource(source.indexOf('[mispelled]') + 2)?.word, + 'mispelled', + ); + }, + ); + + test( + 'Ignore Once follows one transaction across edit, undo, redo, and tabs', + () async { + const bufferId = 'anchor-transactions'; + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + final context = _fixtureContext(project: 'anchors', revision: 0); + + Future check(String source, int revision, {String id = bufferId}) { + final snapshot = SpellingSnapshotIdentity( + bufferId: id, + contentRevision: revision, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + return coordinator.checkNow( + SpellingCheckRequest( + snapshot: snapshot, + engineContext: context, + automatic: false, + project: () async => MarkdownSpellingProjector().project( + filePath: '/tmp/$id.md', + source: source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: snapshot, + ), + ), + ); + } + + await check('helo hello helo', 1); + coordinator.ignoreOnce(coordinator.misspellings.last); + coordinator.translateSourceEdit( + bufferId: bufferId, + start: 0, + oldEnd: 0, + newEnd: 4, + ); + await check('sun helo hello helo', 2); + expect(coordinator.annotations.map((item) => item.start), [4]); + + coordinator.translateSourceEdit( + bufferId: bufferId, + start: 0, + oldEnd: 4, + newEnd: 0, + ); + await check('helo hello helo', 3); + expect(coordinator.annotations.map((item) => item.start), [0]); + + coordinator.translateSourceEdit( + bufferId: bufferId, + start: 0, + oldEnd: 0, + newEnd: 4, + ); + await check('sun helo hello helo', 4); + expect(coordinator.annotations.map((item) => item.start), [4]); + coordinator.translateSourceEdit( + bufferId: bufferId, + start: 0, + oldEnd: 4, + newEnd: 0, + ); + await check('helo hello helo', 5); + + coordinator.translateSourceEdit( + bufferId: bufferId, + start: 0, + oldEnd: 4, + newEnd: 5, + ); + await check('hello hello helo', 6); + expect(coordinator.annotations, isEmpty); + + await check('helo', 1, id: 'other-tab'); + await check('hello hello helo', 6); + expect(coordinator.annotations, isEmpty); + + coordinator.invalidateBufferAnchors(bufferId); + await check('hello hello helo', 7); + expect(coordinator.annotations.single.start, 'hello hello '.length); + coordinator.ignoreOnce(coordinator.misspellings.single); + coordinator.closeBuffer(bufferId); + await check('hello hello helo', 8); + expect(coordinator.annotations, hasLength(1)); + }, + ); + + test( + 'document ignores survive tab changes but not an actual close', + () async { + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + final context = _fixtureContext(project: 'ignore-lifecycle', revision: 0); + const firstSnapshot = SpellingSnapshotIdentity( + bufferId: 'first', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + const secondSnapshot = SpellingSnapshotIdentity( + bufferId: 'second', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + + Future check( + SpellingSnapshotIdentity snapshot, + ) async { + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: snapshot, + engineContext: context, + automatic: false, + project: () async => SpellingProjectionResult( + runs: [_runFor('helo', snapshot: snapshot)], + complete: true, + ), + ), + ); + return coordinator.misspellings.single; + } + + final first = await check(firstSnapshot); + coordinator.ignoreAllInDocument(first); + expect(coordinator.isCurrent(first), isFalse); + + await check(secondSnapshot); + final returned = await check(firstSnapshot); + expect(coordinator.isCurrent(returned), isFalse); + + coordinator.closeBuffer(firstSnapshot.bufferId); + final reopened = await check(firstSnapshot); + expect(coordinator.isCurrent(reopened), isTrue); + }, + ); + + test('a delayed suggestion cannot revive after language changes', () async { + final delayed = Completer>(); + final coordinator = await SpellingCoordinator.start( + suggestionLookup: (_, _) => delayed.future, + ); + addTearDown(coordinator.dispose); + const oldSnapshot = SpellingSnapshotIdentity( + bufferId: 'language-change', + contentRevision: 4, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + const newSnapshot = SpellingSnapshotIdentity( + bufferId: 'language-change', + contentRevision: 4, + documentKind: DocumentKind.markdown, + contextGeneration: 2, + ); + final oldContext = _fixtureContext( + project: 'language-change', + revision: 0, + languageId: 'en-Old', + ); + final newContext = _fixtureContext( + project: 'language-change', + revision: 0, + languageId: 'en-New', + ); + + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: oldSnapshot, + engineContext: oldContext, + automatic: false, + project: () async => SpellingProjectionResult( + runs: [_runFor('helo', snapshot: oldSnapshot, languageId: 'en-Old')], + complete: true, + ), + ), + ); + final oldOccurrence = coordinator.misspellings.single; + final oldSuggestions = coordinator.suggestions( + oldOccurrence, + context: oldContext, + ); + + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: newSnapshot, + engineContext: newContext, + automatic: false, + project: () async => SpellingProjectionResult( + runs: [_runFor('helo', snapshot: newSnapshot, languageId: 'en-New')], + complete: true, + ), + ), + ); + final newOccurrence = coordinator.misspellings.single; + delayed.complete(const ['hello']); + + await expectLater(oldSuggestions, throwsStateError); + expect(coordinator.isCurrent(oldOccurrence), isFalse); + expect(coordinator.isCurrent(newOccurrence), isTrue); + expect(oldOccurrence.id, isNot(newOccurrence.id)); + }); + + test( + 'a manual request waits for its own result while a check runs', + () async { + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + final firstProjection = Completer(); + var firstProjectionStarted = false; + const firstSnapshot = SpellingSnapshotIdentity( + bufferId: 'manual-wait', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + const secondSnapshot = SpellingSnapshotIdentity( + bufferId: 'manual-wait', + contentRevision: 2, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + final context = _fixtureContext(project: 'manual-wait', revision: 0); + + final first = coordinator.checkNow( + SpellingCheckRequest( + snapshot: firstSnapshot, + engineContext: context, + automatic: false, + project: () { + firstProjectionStarted = true; + return firstProjection.future; + }, + ), + ); + await _waitFor(() => firstProjectionStarted); + var secondCompleted = false; + final second = coordinator + .checkNow( + SpellingCheckRequest( + snapshot: secondSnapshot, + engineContext: context, + automatic: false, + project: () async => SpellingProjectionResult( + runs: [_runFor('helo', snapshot: secondSnapshot)], + complete: true, + ), + ), + ) + .whenComplete(() => secondCompleted = true); + + await Future.delayed(const Duration(milliseconds: 30)); + expect(secondCompleted, isFalse); + firstProjection.complete( + SpellingProjectionResult( + runs: [_runFor('hello', snapshot: firstSnapshot)], + complete: true, + ), + ); + await Future.wait([first, second]); + + expect(secondCompleted, isTrue); + expect(coordinator.state.status, SpellingPresentationStatus.ready); + expect(coordinator.misspellings.single.word, 'helo'); + expect(coordinator.misspellings.single.run.snapshot, secondSnapshot); + }, + ); + + test('checks in bounded batches and reuses unchanged run results', () async { + final coordinator = await SpellingCoordinator.start(); + addTearDown(coordinator.dispose); + final context = _fixtureContext(project: 'progressive', revision: 0); + final publications = <({SpellingPresentationStatus status, int count})>[]; + void listen() => publications.add(( + status: coordinator.state.status, + count: coordinator.state.occurrences.length, + )); + coordinator.addListener(listen); + addTearDown(() => coordinator.removeListener(listen)); + + List runs(SpellingSnapshotIdentity snapshot) => [ + for (var index = 0; index < 25; index++) + SpellingProseRun( + id: 'progressive-$index', + text: 'helo', + languageId: 'en-Test', + atoms: const [], + target: const SpellingSourceTarget(filePath: '/tmp/progressive.md'), + snapshot: snapshot, + ), + ]; + + const firstSnapshot = SpellingSnapshotIdentity( + bufferId: 'progressive', + contentRevision: 1, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: firstSnapshot, + engineContext: context, + automatic: false, + project: () async => + SpellingProjectionResult(runs: runs(firstSnapshot), complete: true), + ), + ); + expect(coordinator.misspellings, hasLength(25)); + expect( + publications.any( + (state) => + state.status == SpellingPresentationStatus.checking && + state.count > 0 && + state.count < 25, + ), + isTrue, + ); + + publications.clear(); + const secondSnapshot = SpellingSnapshotIdentity( + bufferId: 'progressive', + contentRevision: 2, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + await coordinator.checkNow( + SpellingCheckRequest( + snapshot: secondSnapshot, + engineContext: context, + automatic: false, + project: () async => SpellingProjectionResult( + runs: runs(secondSnapshot), + complete: true, + ), + ), + ); + + expect(coordinator.misspellings, hasLength(25)); + expect( + publications.any( + (state) => + state.status == SpellingPresentationStatus.checking && + state.count == 25, + ), + isTrue, + ); + }); + + test('project initialization publishes only the latest owner', () async { + for (final completeLatestFirst in [true, false]) { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-project-race-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final firstRoot = p.join(temporary.path, 'first'); + final secondRoot = p.join(temporary.path, 'second'); + await Directory(firstRoot).create(); + await Directory(secondRoot).create(); + final firstRead = Completer(); + final secondRead = Completer(); + var firstStarted = false; + var secondStarted = false; + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + wordStoreReader: (store) { + if (!store.projectStore) return store.read(); + if (p.isWithin(firstRoot, store.filePath)) { + firstStarted = true; + return firstRead.future; + } + secondStarted = true; + return secondRead.future; + }, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + + controller.update( + _sessionInput( + id: 'first-buffer', + root: firstRoot, + text: 'FirstProjectWord', + settings: settings, + ), + ); + await _waitFor(() => firstStarted); + controller.update( + _sessionInput( + id: 'second-buffer', + root: secondRoot, + text: 'SecondProjectWord', + settings: settings, + ), + ); + await _waitFor(() => secondStarted); + final firstSnapshot = _wordSnapshot('FirstProjectWord'); + final secondSnapshot = _wordSnapshot('SecondProjectWord'); + if (completeLatestFirst) { + secondRead.complete(secondSnapshot); + firstRead.complete(firstSnapshot); + } else { + firstRead.complete(firstSnapshot); + secondRead.complete(secondSnapshot); + } + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + + expect(controller.projectWords.wordsFor('en-Test'), [ + 'SecondProjectWord', + ]); + expect(controller.misspellings, isEmpty); + controller.dispose(); + } + }); + + test('concurrent first requests start exactly one worker', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-worker-start-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final root = p.join(temporary.path, 'project'); + await Directory(root).create(); + final startupGate = Completer(); + var starts = 0; + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + coordinatorStarter: () async { + starts++; + await startupGate.future; + return SpellingCoordinator.start(); + }, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + + controller.update( + _sessionInput( + id: 'startup', + root: root, + text: 'helo', + settings: settings, + ), + ); + await _waitFor(() => starts == 1); + controller.update( + _sessionInput( + id: 'startup', + root: root, + text: 'helo again', + revision: 1, + settings: settings, + ), + ); + await Future.delayed(const Duration(milliseconds: 30)); + expect(starts, 1); + startupGate.complete(); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + expect(starts, 1); + }); + + test('a project-word mutation cannot publish into a later project', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-project-mutation-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final firstRoot = p.join(temporary.path, 'first'); + final secondRoot = p.join(temporary.path, 'second'); + await Directory(firstRoot).create(); + await Directory(secondRoot).create(); + final delayedWriter = _DelayedAtomicFileWriter(); + addTearDown(delayedWriter.releaseIfNeeded); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + wordStoreFactory: ({required filePath, required projectStore}) => + SpellingWordStore( + filePath: filePath, + projectStore: projectStore, + writer: projectStore && p.isWithin(firstRoot, filePath) + ? delayedWriter + : const AtomicFileWriter(), + ), + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + controller.update( + _sessionInput( + id: 'first-mutation', + root: firstRoot, + text: 'ProjectTypoo', + settings: settings, + ), + ); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + final occurrence = controller.misspellings.single; + final mutation = controller.addProjectWord(occurrence); + await delayedWriter.started.future; + + controller.update( + _sessionInput( + id: 'second-mutation', + root: secondRoot, + text: 'helo', + settings: settings, + ), + ); + await _waitFor( + () => + controller.state.status == SpellingPresentationStatus.ready && + controller.misspellings.singleOrNull?.word == 'helo', + ); + delayedWriter.releaseIfNeeded(); + await mutation; + + expect(controller.projectWords.wordsFor('en-Test'), isEmpty); + expect( + (await SpellingWordStore( + filePath: p.join(firstRoot, '.busymark', 'spelling.json'), + projectStore: true, + ).read()).wordsFor('en-Test'), + ['ProjectTypoo'], + ); + }); + + test('new input hides old results before preparation can fail', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-preparation-failure-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final goodRoot = p.join(temporary.path, 'good'); + final badRoot = p.join(temporary.path, 'bad'); + await Directory(goodRoot).create(); + await Directory(p.join(badRoot, '.busymark')).create(recursive: true); + await File( + p.join(badRoot, '.busymark', 'spelling.json'), + ).writeAsString('{broken'); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + controller.update( + _sessionInput( + id: 'good-buffer', + root: goodRoot, + text: 'helo', + settings: settings, + ), + ); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + final oldOccurrence = controller.misspellings.single; + + controller.update( + _sessionInput( + id: 'bad-buffer', + root: badRoot, + text: 'different', + settings: settings, + ), + ); + expect(controller.state.status, SpellingPresentationStatus.checking); + expect(controller.misspellings, isEmpty); + expect(controller.occurrenceAtSource(0), isNull); + expect(controller.isCurrent(oldOccurrence), isFalse); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.failure, + ); + expect(controller.misspellings, isEmpty); + expect(controller.state.message, contains('FormatException')); + }); + + test('external project-word edits refresh an open document', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-external-words-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final root = p.join(temporary.path, 'project'); + await Directory(root).create(recursive: true); + final storeFile = File(p.join(root, '.busymark', 'spelling.json')); + final externalStore = SpellingWordStore( + filePath: storeFile.path, + projectStore: true, + ); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + controller.update( + _sessionInput( + id: 'external-words', + root: root, + text: 'BusyBrand', + settings: settings, + ), + ); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + expect(controller.misspellings.single.word, 'BusyBrand'); + + await externalStore.addWord('en-Test', 'BusyBrand'); + await _waitFor( + () => + controller.projectWords.revision == 1 && + controller.state.status == SpellingPresentationStatus.ready && + controller.misspellings.isEmpty, + ); + expect(controller.projectWords.wordsFor('en-Test'), ['BusyBrand']); + + // Replace the inode while deliberately retaining the same revision. The + // effective-word fingerprint, rather than the advisory counter, must + // rebuild the native dictionary and invalidate checked-run caches. + await const AtomicFileWriter().writeBytes( + storeFile.path, + utf8.encode( + '${jsonEncode({'schemaVersion': 1, 'revision': 1, 'words': {}})}\n', + ), + overwrite: true, + ); + await _waitFor( + () => + controller.projectWords.wordsFor('en-Test').isEmpty && + controller.state.status == SpellingPresentationStatus.ready && + controller.misspellings.singleOrNull?.word == 'BusyBrand', + ); + + await externalStore.addWord('en-Test', 'BusyBrand'); + await _waitFor( + () => + controller.projectWords.revision == 2 && + controller.state.status == SpellingPresentationStatus.ready && + controller.misspellings.isEmpty, + ); + + Future siblingRename( + int revision, + List> words, + ) async { + final staged = File('${storeFile.path}.sibling-$revision'); + await staged.writeAsString( + '${jsonEncode({ + 'schemaVersion': 1, + 'revision': revision, + 'words': {'en-Test': words}, + })}\n', + flush: true, + ); + await staged.rename(storeFile.path); + } + + await siblingRename(3, const []); + await _waitFor( + () => + controller.projectWords.revision == 3 && + controller.misspellings.singleOrNull?.word == 'BusyBrand', + ); + await siblingRename(4, const [ + {'key': 'BusyBrand', 'display': 'BusyBrand'}, + ]); + await _waitFor( + () => + controller.projectWords.revision == 4 && + controller.misspellings.isEmpty, + ); + + await siblingRename(5, const []); + await _waitFor( + () => + controller.projectWords.revision == 5 && + controller.misspellings.singleOrNull?.word == 'BusyBrand', + ); + + // The effective list is already empty. Reattachment must therefore not + // depend on a changed snapshot being published during directory removal. + await storeFile.parent.delete(recursive: true); + await Future.delayed(const Duration(milliseconds: 250)); + await externalStore.addWord('en-Test', 'BusyBrand'); + await _waitFor( + () => + controller.projectWords.wordsFor('en-Test').contains('BusyBrand') && + controller.misspellings.isEmpty, + ); + }); + + testWidgets( + 'review dialog keeps one traversal through skip, back, correction, and persistence', + (tester) async { + tester.view.physicalSize = const Size(1200, 900); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + late final Directory temporary; + late final SpellingSessionController controller; + late DocumentBuffer buffer; + BusyDocument? richDocument; + var richGeneration = 0; + late final AppSettings settings; + final personalWriter = _ToggleFailAtomicFileWriter(); + await tester.runAsync(() async { + temporary = await Directory.systemTemp.createTemp( + 'busymark-review-dialog-', + ); + final bundle = await _createFixtureBundle(temporary); + controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + coordinatorStarter: () => SpellingCoordinator.start( + suggestionLookup: (_, word) async => switch (word) { + 'helo' => const ['hello'], + 'wrld' => const ['world'], + _ => const [], + }, + ), + wordStoreFactory: + ({required String filePath, required bool projectStore}) => + SpellingWordStore( + filePath: filePath, + projectStore: projectStore, + writer: personalWriter, + ), + ); + buffer = DocumentBuffer.untitled( + id: 'review-dialog', + name: 'review.md', + text: 'helo wrld eror', + ); + settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + await controller.checkNow( + SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ); + }); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + addTearDown(controller.dispose); + SpellingSessionInput input() => SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + richDocument: richDocument, + richDocumentGeneration: richGeneration, + ); + expect(controller.misspellings.map((item) => item.word), [ + 'helo', + 'wrld', + 'eror', + ]); + final reveals = []; + final l10n = AppLocalizationsEn(); + var initialIndex = 0; + final navigatorObserver = _RecordingNavigatorObserver(); + late BuildContext hostContext; + Future Function() chooseLanguage = () async => false; + + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [navigatorObserver], + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Builder( + builder: (context) { + hostContext = context; + return TextButton( + onPressed: () => showDialog( + context: context, + builder: (context) => BusyMarkSpellingReviewDialog( + spelling: controller, + initialIndex: initialIndex, + onReveal: (occurrence) => reveals.add(occurrence.word), + onCorrect: (occurrence, suggestion) async { + final start = occurrence.sourceStart!; + final end = occurrence.sourceEnd!; + buffer = buffer.copyWith( + text: buffer.text.replaceRange(start, end, suggestion), + revision: buffer.revision + 1, + ); + return SpellingReviewCorrection( + coordinateScope: + 'document:${occurrence.run.snapshot.bufferId}', + start: start, + oldEnd: end, + newEnd: start + suggestion.length, + ); + }, + onChooseLanguage: () => chooseLanguage(), + ), + ), + child: const Text('Open review'), + ); + }, + ), + ), + ); + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('helo').evaluate().isNotEmpty, + ); + expect(find.text('helo'), findsOneWidget); + + await tester.tap(find.text(l10n.sourceSearchNextMatch)); + await tester.pump(); + expect(find.text('wrld'), findsOneWidget); + await tester.tap(find.text(l10n.sourceSearchPreviousMatch)); + await tester.pump(); + expect(find.text('helo'), findsOneWidget); + + await tester.tap(find.text(l10n.ignoreSpellingOnce)); + await tester.pump(); + expect(find.text('wrld'), findsOneWidget); + await _pumpWidgetUntil( + tester, + () => find.text('world').evaluate().isNotEmpty, + ); + await tester.tap(find.text('world')); + await tester.runAsync(() => controller.checkNow(input())); + await tester.pump(); + await _pumpWidgetUntil( + tester, + () => find.text('eror').evaluate().isNotEmpty, + ); + expect(buffer.text, 'helo world eror'); + expect(reveals, contains('eror')); + + final erorOccurrence = controller.misspellings.singleWhere( + (occurrence) => occurrence.word == 'eror', + ); + expect(controller.isCurrent(erorOccurrence), isTrue); + final addPersonal = find.widgetWithText( + TextButton, + l10n.addPersonalSpellingWord, + ); + await tester.ensureVisible(addPersonal); + personalWriter.failWrites = true; + tester.widget(addPersonal).onPressed!.call(); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 500)), + ); + await _pumpWidgetUntil( + tester, + () => tester.widget(addPersonal).onPressed != null, + ); + expect(find.text('eror'), findsOneWidget); + expect( + controller.personalWords.wordsFor('en-Test'), + isNot(contains('eror')), + ); + + personalWriter.failWrites = false; + tester.widget(addPersonal).onPressed!.call(); + await _pumpWidgetUntil( + tester, + () => + controller.personalWords.wordsFor('en-Test').contains('eror') && + find.text(l10n.checkSpelling).evaluate().isEmpty, + ); + expect(controller.personalWords.wordsFor('en-Test'), contains('eror')); + controller.endManualReview(); + await tester.pump(const Duration(milliseconds: 300)); + await _pumpWidgetUntil( + tester, + () => controller.state.status == SpellingPresentationStatus.ready, + ); + + buffer = DocumentBuffer.untitled( + id: 'review-dialog-wrap', + name: 'review-wrap.md', + text: 'helo\n\nhelo\n\nhelo', + ); + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 2; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('hello').evaluate().isNotEmpty, + ); + await tester.tap(find.text('hello')); + await tester.runAsync(() => controller.checkNow(input())); + await tester.pump(); + + expect(tester.takeException(), isNull); + expect(find.byType(BusyMarkSpellingReviewDialog), findsOneWidget); + expect(controller.misspellings, hasLength(2)); + expect(buffer.text, 'helo\n\nhelo\n\nhello'); + await _pumpWidgetUntil( + tester, + () => find.text('hello').evaluate().isNotEmpty, + ); + await tester.tap(find.text('hello')); + await tester.runAsync(() => controller.checkNow(input())); + await tester.pump(); + expect(tester.takeException(), isNull); + expect(buffer.text, 'hello\n\nhelo\n\nhello'); + await tester.tap(find.text(l10n.close)); + await tester.pumpAndSettle(); + + buffer = DocumentBuffer.untitled( + id: 'review-dialog-rich', + name: 'review-rich.md', + text: 'helo\n\nwrld\n\nmistakke\n', + ); + richDocument = const MarkdownParser() + .parse( + filePath: '/tmp/review-rich.md', + source: buffer.text, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + richGeneration++; + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 1; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('wrld').evaluate().isNotEmpty, + ); + await tester.tap(find.text(l10n.sourceSearchNextMatch)); + await tester.pump(); + expect(reveals.last, 'mistakke'); + await tester.tap(find.text(l10n.sourceSearchNextMatch)); + await tester.pump(); + expect(reveals.last, 'helo'); + await _pumpWidgetUntil( + tester, + () => find.text('hello').evaluate().isNotEmpty, + ); + await tester.tap(find.text('hello')); + richDocument = const MarkdownParser() + .parse( + filePath: '/tmp/review-rich.md', + source: buffer.text, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + richGeneration++; + await tester.runAsync(() => controller.checkNow(input())); + await _pumpWidgetUntil( + tester, + () => find.byType(BusyMarkSpellingReviewDialog).evaluate().isEmpty, + ); + expect(buffer.text, 'hello\n\nwrld\n\nmistakke\n'); + + buffer = DocumentBuffer.untitled( + id: 'review-dialog-rich-table', + name: 'review-rich-table.md', + text: '| helo | wrld | mistakke |\n| --- | --- | --- |\n', + ); + richDocument = const MarkdownParser() + .parse( + filePath: '/tmp/review-rich-table.md', + source: buffer.text, + mode: MarkdownMode.gfm, + validateLocalReferences: false, + ) + .busyDocument; + richGeneration++; + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 1; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('wrld').evaluate().isNotEmpty, + ); + await tester.tap(find.text(l10n.sourceSearchNextMatch)); + await tester.pump(); + expect(reveals.last, 'mistakke'); + await tester.tap(find.text(l10n.sourceSearchNextMatch)); + await tester.pump(); + expect(reveals.last, 'helo'); + await tester.tap(find.text(l10n.close)); + await tester.pumpAndSettle(); + richDocument = null; + + buffer = DocumentBuffer.untitled( + id: 'review-dialog-batch', + name: 'review-batch.md', + text: List.filled(15, 'helo').join('\n\n'), + ); + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 13; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('hello').evaluate().isNotEmpty, + ); + await tester.tap(find.text('hello')); + await tester.runAsync(() => controller.checkNow(input())); + await tester.pump(); + expect(tester.takeException(), isNull); + expect(buffer.text.split('\n\n')[13], 'hello'); + expect(find.byType(BusyMarkSpellingReviewDialog), findsOneWidget); + await tester.tap(find.text(l10n.close)); + await tester.pumpAndSettle(); + + for (final action in [ + l10n.ignoreSpellingOnce, + l10n.ignoreSpellingDocument, + ]) { + buffer = DocumentBuffer.untitled( + id: 'review-single-${action.hashCode}', + name: 'review-single.md', + text: 'helo', + ); + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 0; + final popsBefore = navigatorObserver.popCount; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text(action).evaluate().isNotEmpty, + ); + final callback = tester + .widget(find.widgetWithText(TextButton, action)) + .onPressed!; + callback(); + callback(); + await tester.pumpAndSettle(); + + expect(navigatorObserver.popCount, popsBefore + 1); + expect(find.text('Open review'), findsOneWidget); + expect(find.byType(BusyMarkSpellingReviewDialog), findsNothing); + } + + buffer = DocumentBuffer.untitled( + id: 'review-language-chooser', + name: 'review-language.md', + text: 'helo', + ); + await tester.runAsync(() => controller.checkNow(input())); + initialIndex = 0; + chooseLanguage = () async => + await showDialog( + context: hostContext, + builder: (context) => AlertDialog( + title: const Text('Language chooser probe'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Cancel chooser'), + ), + ], + ), + ) ?? + false; + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text(l10n.chooseSpellingLanguage).evaluate().isNotEmpty, + ); + await tester.tap(find.text(l10n.chooseSpellingLanguage)); + await _pumpWidgetUntil( + tester, + () => find.text('Language chooser probe').evaluate().isNotEmpty, + ); + final chooserPopsBefore = navigatorObserver.popCount; + controller.ignoreOnce(controller.misspellings.single); + await tester.pump(); + expect(find.text('Language chooser probe'), findsOneWidget); + expect(navigatorObserver.popCount, chooserPopsBefore); + await tester.tap(find.text('Cancel chooser')); + await tester.pumpAndSettle(); + expect(find.text('Open review'), findsOneWidget); + }, + ); + + testWidgets( + 'review word-store conflict stays current and exposes preserved recovery path', + (tester) async { + tester.view.physicalSize = const Size(1200, 900); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + final temporary = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-review-conflict-'), + ))!; + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = (await tester.runAsync( + () => _createFixtureBundle(temporary), + ))!; + final recoveryPath = p.join(temporary.path, 'preserved-personal.json'); + final writer = _ToggleFailAtomicFileWriter(); + final conflictDestinationBytes = utf8.encode( + '${jsonEncode({ + 'schemaVersion': 1, + 'revision': 77, + 'words': { + 'en-Test': [ + {'key': 'external', 'display': 'external'}, + ], + }, + })}\n', + ); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + wordStoreFactory: + ({required String filePath, required bool projectStore}) => + SpellingWordStore( + filePath: filePath, + projectStore: projectStore, + writer: writer, + ), + ); + addTearDown(controller.dispose); + final buffer = DocumentBuffer.untitled( + id: 'review-dialog-conflict', + name: 'review-conflict.md', + text: 'helo', + ); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + await tester.runAsync( + () => controller.checkNow( + SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ), + ); + final occurrence = controller.misspellings.single; + writer + ..conflictRecoveryPath = recoveryPath + ..conflictDestinationBytes = conflictDestinationBytes; + String? copiedPath; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + (call) async { + if (call.method == 'Clipboard.setData') { + copiedPath = + (call.arguments as Map)['text'] as String?; + } + return null; + }, + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + null, + ), + ); + final l10n = AppLocalizationsEn(); + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + builder: (context, child) => BusyMarkToastOverlay(child: child!), + home: Builder( + builder: (context) => TextButton( + onPressed: () => showDialog( + context: context, + builder: (context) => BusyMarkSpellingReviewDialog( + spelling: controller, + initialIndex: 0, + onReveal: (_) {}, + onCorrect: (_, _) async => null, + onChooseLanguage: () async => false, + ), + ), + child: const Text('Open review'), + ), + ), + ), + ); + await tester.tap(find.text('Open review')); + await _pumpWidgetUntil( + tester, + () => find.text('helo').evaluate().isNotEmpty, + ); + expect(controller.isCurrent(occurrence), isTrue); + final writesBefore = writer.writeCount; + final addPersonal = find.widgetWithText( + TextButton, + l10n.addPersonalSpellingWord, + ); + await tester.ensureVisible(addPersonal); + tester.widget(addPersonal).onPressed!.call(); + await _pumpWidgetUntil(tester, () => writer.writeCount > writesBefore); + await _pumpWidgetUntil( + tester, + () => find + .text(l10n.spellingDictionaryRecoveryConflict) + .evaluate() + .isNotEmpty, + ); + + expect(writer.writeCount, writesBefore + 1); + expect(await tester.runAsync(() => File(recoveryPath).exists()), isTrue); + expect(controller.personalWords.revision, 77); + expect(controller.personalWords.wordsFor('en-Test'), ['external']); + expect(find.byType(BusyMarkSpellingReviewDialog), findsOneWidget); + expect(find.text('helo'), findsWidgets); + final reconciledOccurrence = controller.misspellings.single; + expect(reconciledOccurrence.word, 'helo'); + expect(reconciledOccurrence.sourceStart, occurrence.sourceStart); + expect(controller.isCurrent(reconciledOccurrence), isTrue); + expect( + find.text(l10n.spellingDictionaryRecoveryConflict), + findsOneWidget, + ); + + await tester.pump(const Duration(seconds: 10)); + expect( + find.text(l10n.spellingDictionaryRecoveryConflict), + findsOneWidget, + ); + await tester.tap(find.text(l10n.copyPath)); + await tester.pump(const Duration(milliseconds: 250)); + expect(copiedPath, recoveryPath); + expect(await tester.runAsync(() => File(recoveryPath).exists()), isTrue); + }, + ); + + test('equivalent rebuild does not cancel session initialization', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-session-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final buffer = DocumentBuffer.untitled( + id: 'equivalent-input', + name: 'equivalent.md', + text: 'helo', + ); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ); + final first = SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + final equivalent = SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + + controller.update(first); + controller.update(equivalent); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + + expect(controller.misspellings.single.word, 'helo'); + + final changedController = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'changed-support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(changedController.dispose); + changedController.update(first); + changedController.update( + SpellingSessionInput( + buffer: buffer.copyWith(text: 'hello', revision: 1), + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ); + await _waitFor( + () => changedController.state.status == SpellingPresentationStatus.ready, + ); + expect(changedController.misspellings, isEmpty); + }); + + test( + 'automatic session checks after an unresolved language is selected', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-language-transition-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final settings = AppSettings.defaults().copyWith( + defaultSpellingLanguage: null, + automaticSpelling: true, + ); + final buffer = DocumentBuffer.untitled( + id: 'language-transition', + name: 'language-transition.md', + text: 'helo', + ); + SpellingSessionInput input(DocumentBuffer value) => SpellingSessionInput( + buffer: value, + workspace: null, + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); + + controller.update(input(buffer)); + await _waitFor( + () => + controller.state.status == + SpellingPresentationStatus.languageRequired, + ); + + controller.update( + input( + buffer.copyWith( + editorState: buffer.editorState.copyWith( + spellingLanguage: const SpellingLanguageOverride.selected( + 'en-Test', + ), + ), + ), + ), + ); + await _waitFor(() { + final status = controller.state.status; + return status != SpellingPresentationStatus.languageRequired && + status != SpellingPresentationStatus.checking; + }); + + expect(controller.state.status, SpellingPresentationStatus.ready); + expect(controller.state.complete, isTrue); + expect(controller.misspellings.single.word, 'helo'); + expect(controller.annotations, isNotEmpty); + }, + ); + + test( + 'an available but absent dictionary is not downloaded implicitly', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-not-installed-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final dictionaryStorage = Directory( + p.join(temporary.path, 'dictionary-storage'), + ); + await dictionaryStorage.delete(recursive: true); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(temporary.path, 'support'), + dictionaryStorageRoot: dictionaryStorage.path, + verifyDictionaryChecksums: false, + ); + addTearDown(controller.dispose); + final buffer = DocumentBuffer.untitled( + id: 'not-installed', + name: 'not-installed.md', + text: 'helo', + ); + controller.update( + SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ), + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ); + await _waitFor( + () => + controller.state.status == + SpellingPresentationStatus.dictionaryNotInstalled, + ); + + expect(controller.catalog?.availableById('en-Test'), isNotNull); + expect(controller.catalog?.installedById('en-Test'), isNull); + expect(await _publishedDirectories(dictionaryStorage.path), isEmpty); + }, + ); + + test( + 'removing a downloaded pair keeps words and reports not installed', + () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-remove-dictionary-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final bundle = await _createFixtureBundle(temporary); + final support = p.join(temporary.path, 'support'); + final personal = SpellingWordStore( + filePath: p.join(support, 'spelling', 'personal.json'), + ); + await personal.addWord('en-Test', 'BusyMarkTerm'); + final controller = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: support, + dictionaryStorageRoot: p.join(temporary.path, 'dictionary-storage'), + ); + addTearDown(controller.dispose); + final buffer = DocumentBuffer.untitled( + id: 'remove-installed', + name: 'remove-installed.md', + text: 'helo', + ); + controller.update( + SpellingSessionInput( + buffer: buffer, + workspace: null, + settings: AppSettings.defaults().copyWith( + defaultSpellingLanguage: 'en-Test', + ), + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ), + ); + await _waitFor( + () => controller.state.status == SpellingPresentationStatus.ready, + ); + await controller.removeDownloadedDictionary('en-Test'); + await _waitFor( + () => + controller.state.status == + SpellingPresentationStatus.dictionaryNotInstalled, + ); + + expect(controller.catalog?.installedById('en-Test'), isNull); + expect( + (await personal.read()).wordsFor('en-Test'), + contains('BusyMarkTerm'), + ); + }, + ); + + group('long-lived spelling worker', () { + late SpellingWorker worker; + + setUp(() async => worker = await SpellingWorker.start()); + tearDown(() => worker.close()); + + test('catalog validation requires its resource-specific probe', () async { + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final affPath = p.join(fixture, 'test.aff'); + final dicPath = p.join(fixture, 'test.dic'); + + expect( + await worker.validateDictionary( + affPath: affPath, + dicPath: dicPath, + knownValidProbe: 'hello', + ), + 'UTF-8', + ); + await expectLater( + worker.validateDictionary( + affPath: affPath, + dicPath: dicPath, + knownValidProbe: 'definitelynotaword', + ), + throwsA(isA()), + ); + }); + + test( + 'projects source and rich snapshots through reusable messages', + () async { + const source = '**helo** hello\n'; + final document = const MarkdownParser() + .parse( + filePath: '/tmp/worker-project.md', + source: source, + mode: MarkdownMode.commonMark, + validateLocalReferences: false, + ) + .busyDocument; + final sourceProjection = await worker.project( + const SpellingProjectionJob( + filePath: '/tmp/worker-project.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ), + ); + final richProjection = await worker.project( + SpellingProjectionJob( + filePath: '/tmp/worker-project.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + richDocument: document, + richDocumentGeneration: 4, + ), + ); + + expect(sourceProjection.complete, isTrue); + expect(sourceProjection.runs.single.text, 'helo hello'); + expect(richProjection.complete, isTrue); + expect(richProjection.runs.single.text, 'helo hello'); + expect( + richProjection.runs.single.target, + isA(), + ); + }, + ); + + test('incrementally reuses unaffected plain Markdown runs', () async { + const firstSource = 'helo first\n\nwrld second\n'; + const secondSource = 'hello first\n\nwrld second\n'; + final first = await worker.project( + const SpellingProjectionJob( + filePath: '/tmp/incremental.md', + source: firstSource, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ), + ); + final second = await worker.project( + const SpellingProjectionJob( + filePath: '/tmp/incremental.md', + source: secondSource, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: SpellingSnapshotIdentity( + bufferId: 'buffer', + contentRevision: 2, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ), + ), + ); + + expect(first.runs.map((run) => run.text), ['helo first', 'wrld second']); + expect(second.runs.map((run) => run.text), [ + 'hello first', + 'wrld second', + ]); + expect( + secondSource.substring( + second.runs.last.atoms.first.sourceStart, + second.runs.last.atoms.last.sourceEnd, + ), + 'wrld second', + ); + expect(second.runs.last.snapshot.contentRevision, 2); + }); + + test( + 'incremental Markdown projection agrees with a fresh structural parse', + () async { + final cases = <(String, String)>[ + ('```text\n\nhelo\n\n```\n', '```text\n\nhelop\n\n```\n'), + ('\n', '\n'), + ('---\n\nhelo\n\n---\n', '---\n\nhelop\n\n---\n'), + ('
\n\nhelo\n\n
\n', '
\n\nhelop\n\n
\n'), + ('- parent\n\n helo\n', '- parent\n\n helop\n'), + ]; + for (final (oldSource, newSource) in cases) { + await worker.project( + SpellingProjectionJob( + filePath: '/tmp/differential.md', + source: oldSource, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ), + ); + const nextSnapshot = SpellingSnapshotIdentity( + bufferId: 'buffer', + contentRevision: 2, + documentKind: DocumentKind.markdown, + contextGeneration: 1, + ); + final incremental = await worker.project( + SpellingProjectionJob( + filePath: '/tmp/differential.md', + source: newSource, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: nextSnapshot, + ), + ); + final fresh = const MarkdownSpellingProjector().project( + filePath: '/tmp/differential.md', + source: newSource, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: nextSnapshot, + ); + + Object signature(SpellingProjectionResult projection) => [ + projection.complete, + projection.message, + for (final run in projection.runs) + [ + run.text, + switch (run.target) { + SpellingSourceTarget(:final filePath) => filePath, + _ => run.target.runtimeType.toString(), + }, + for (final atom in run.atoms) + [ + atom.logicalText, + atom.logicalStart, + atom.logicalEnd, + atom.sourceStart, + atom.sourceEnd, + atom.transformation.name, + atom.context.name, + ], + ], + ]; + + expect( + signature(incremental), + equals(signature(fresh)), + reason: 'Incremental mismatch for:\n$newSource', + ); + } + }, + ); + + test('projection cache rebinds source targets after Save As', () async { + const source = 'helo'; + final first = await worker.project( + const SpellingProjectionJob( + filePath: '/tmp/original.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ), + ); + final saved = await worker.project( + const SpellingProjectionJob( + filePath: '/tmp/saved-as.md', + source: source, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ), + ); + + expect( + (first.runs.single.target as SpellingSourceTarget).filePath, + '/tmp/original.md', + ); + expect( + (saved.runs.single.target as SpellingSourceTarget).filePath, + '/tmp/saved-as.md', + ); + }); + + test('project custom words do not leak between contexts', () async { + final accepted = await worker.check( + context: _fixtureContext( + project: 'one', + revision: 1, + words: const ['busystack'], + ), + runs: [_run('busystack')], + ); + final rejected = await worker.check( + context: _fixtureContext(project: 'two', revision: 0), + runs: [_run('busystack')], + ); + + expect(accepted.occurrences, isEmpty); + expect( + rejected.occurrences.single.outcome, + SpellingCheckOutcome.rejected, + ); + }); + + test('quoted corrections retain straight and curly punctuation', () async { + for (final fixture in [ + ( + source: "'helo'", + word: 'helo', + suggestion: 'hello', + expected: "'hello'", + ), + ( + source: '‘helo’', + word: 'helo', + suggestion: 'hello', + expected: '‘hello’', + ), + ( + source: "'helo world'", + word: 'helo', + suggestion: 'hello', + expected: "'hello world'", + ), + ( + source: "'hello wrld'", + word: 'wrld', + suggestion: 'world', + expected: "'hello world'", + ), + ( + source: '‘hello wrld’', + word: 'wrld', + suggestion: 'world', + expected: '‘hello world’', + ), + ( + source: "'don't wrld,'", + word: 'wrld', + suggestion: 'world', + expected: "'don't world,'", + ), + ]) { + final run = const MarkdownSpellingProjector() + .project( + filePath: '/tmp/quoted.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ) + .runs + .single; + final checked = await worker.check( + context: _fixtureContext(project: 'quoted', revision: 0), + runs: [run], + ); + final occurrence = checked.occurrences.firstWhere( + (candidate) => candidate.word == fixture.word, + ); + expect( + const SpellingReplacementPlanner() + .build(occurrence: occurrence, suggestion: fixture.suggestion) + .applyToSource(fixture.source), + fixture.expected, + ); + } + }); + + test('quotation context survives projection and worker barriers', () async { + for (final fixture in [ + (source: "'click `run` helo'", expected: "'click `run` hello'"), + (source: r"'value $x$ helo'", expected: r"'value $x$ hello'"), + ]) { + final projection = const MarkdownSpellingProjector().project( + filePath: '/tmp/barrier.md', + source: fixture.source, + mode: MarkdownMode.commonMark, + languageId: 'en-Test', + snapshot: _snapshot, + ); + final checked = await worker.check( + context: _fixtureContext(project: 'barrier', revision: 0), + runs: projection.runs, + ); + final occurrence = checked.occurrences.singleWhere( + (candidate) => candidate.word == 'helo', + ); + expect(occurrence.sourceEnd, fixture.source.length - 1); + expect( + const SpellingReplacementPlanner() + .build(occurrence: occurrence, suggestion: 'hello') + .applyToSource(fixture.source), + fixture.expected, + ); + } + + const xml = "

'value %project% helo'

"; + final xmlProjection = const WritersideXmlSpellingProjector().project( + filePath: '/tmp/barrier.topic', + source: xml, + languageId: 'en-Test', + snapshot: _snapshot, + ); + final xmlChecked = await worker.check( + context: _fixtureContext(project: 'barrier', revision: 0), + runs: xmlProjection.runs, + ); + final xmlOccurrence = xmlChecked.occurrences.singleWhere( + (candidate) => candidate.word == 'helo', + ); + expect( + const SpellingReplacementPlanner() + .build(occurrence: xmlOccurrence, suggestion: 'hello') + .applyToSource(xml), + "

'value %project% hello'

", + ); + }); + + test('quotation context survives a bounded worker chunk', () async { + final middle = List.filled(9000, 'hello').join(' '); + final text = "'hello $middle wrld'"; + final result = await worker.check( + context: _fixtureContext(project: 'chunk-quote', revision: 0), + runs: [_run(text)], + ); + final occurrence = result.occurrences.singleWhere( + (candidate) => candidate.word == 'wrld', + ); + expect(occurrence.logicalEnd, text.length - 1); + expect( + text.replaceRange( + occurrence.logicalStart, + occurrence.logicalEnd, + 'world', + ), + "'hello $middle world'", + ); + }); + + test('removing a custom exception does not forbid a base word', () async { + await worker.check( + context: _fixtureContext( + project: 'one', + revision: 1, + words: const ['hello'], + ), + runs: [_run('hello')], + ); + final rebuilt = await worker.check( + context: _fixtureContext(project: 'one', revision: 2), + runs: [_run('hello')], + ); + + expect(rebuilt.occurrences, isEmpty); + }); + + test('prose around 64 KiB is checked across bounded chunks', () async { + final fixtures = [ + List.filled(10000, 'hello').join(' '), + List.filled(8000, 'hello 🙂').join(' '), + ]; + expect(utf8.encode(fixtures.first).length, lessThan(64 * 1024)); + expect(utf8.encode(fixtures.last).length, greaterThan(64 * 1024)); + + for (final middle in fixtures) { + final text = 'helo $middle helo'; + final result = await worker.check( + context: _fixtureContext(project: 'one', revision: 0), + runs: [_run(text)], + ); + + expect(result.complete, isTrue); + expect(result.error, isNull); + expect(result.occurrences.map((item) => item.word), ['helo', 'helo']); + expect(result.occurrences.first.logicalStart, 0); + expect(result.occurrences.last.logicalEnd, text.length); + } + }); + + test('isolates encoding and oversized-token failures', () async { + final temporary = await Directory.systemTemp.createTemp( + 'busymark-token-failures-', + ); + addTearDown(() async { + if (await temporary.exists()) await temporary.delete(recursive: true); + }); + final aff = File(p.join(temporary.path, 'latin.aff')); + final dic = File(p.join(temporary.path, 'latin.dic')); + await aff.writeAsString( + 'SET ISO8859-1\nTRY abcdefghijklmnopqrstuvwxyz\n', + ); + await dic.writeAsString('1\nhello\n'); + final context = SpellingEngineContext( + languageId: 'en-Test', + affPath: aff.path, + dicPath: dic.path, + baseFingerprint: 'latin-fixture', + personalRevision: 0, + projectIdentity: 'token-failures', + projectRevision: 0, + customWords: const [], + ); + + final encodingText = 'helo Ελληνικά helo'; + final encodingResult = await worker.check( + context: context, + runs: [_run(encodingText)], + ); + expect(encodingResult.complete, isFalse); + expect( + encodingResult.occurrences + .where((item) => item.outcome == SpellingCheckOutcome.rejected) + .map((item) => item.word), + ['helo', 'helo'], + ); + expect( + encodingResult.occurrences + .singleWhere( + (item) => item.outcome == SpellingCheckOutcome.unchecked, + ) + .word, + 'Ελληνικά', + ); + + for (final oversized in ['x' * (70 * 1024), 'é' * (35 * 1024)]) { + final oversizedText = 'helo $oversized,wrld'; + final oversizedResult = await worker.check( + context: context, + runs: [_run(oversizedText)], + ); + expect(oversizedResult.complete, isFalse); + expect( + oversizedResult.occurrences + .where((item) => item.outcome == SpellingCheckOutcome.rejected) + .map((item) => item.word), + ['helo', 'wrld'], + ); + final unchecked = oversizedResult.occurrences.singleWhere( + (item) => item.outcome == SpellingCheckOutcome.unchecked, + ); + expect(unchecked.word, oversized); + expect(unchecked.logicalStart, 'helo '.length); + expect(unchecked.logicalEnd, 'helo '.length + oversized.length); + } + }); + + test('normal, large, and superseded checks stay bounded', () async { + final context = _fixtureContext(project: 'performance', revision: 0); + final normalWatch = Stopwatch()..start(); + final normal = await worker.check( + context: context, + runs: [_run(List.filled(200, 'hello').join(' '))], + ); + normalWatch.stop(); + + final largeRuns = [ + for (var index = 0; index < 128; index++) + _run(List.filled(256, index.isEven ? 'hello' : 'helo').join(' ')), + ]; + final largeWatch = Stopwatch()..start(); + final first = worker.check(context: context, runs: largeRuns); + final superseded = worker.check(context: context, runs: largeRuns); + final latest = worker.check(context: context, runs: largeRuns); + final results = await Future.wait([first, superseded, latest]); + largeWatch.stop(); + + final suggestionWatch = Stopwatch()..start(); + final suggestions = await worker.suggestions( + context: context, + word: 'helo', + ); + suggestionWatch.stop(); + debugPrint( + 'spelling benchmark: normal=${normalWatch.elapsedMilliseconds}ms ' + 'large/latest=${largeWatch.elapsedMilliseconds}ms ' + 'suggestion=${suggestionWatch.elapsedMilliseconds}ms', + ); + + expect(normal.complete, isTrue); + expect(results.last.complete, isTrue); + expect(results.take(2).any((result) => result.cancelled), isTrue); + expect(suggestions, contains('hello')); + expect(normalWatch.elapsed, lessThan(const Duration(seconds: 5))); + expect(largeWatch.elapsed, lessThan(const Duration(seconds: 30))); + expect(suggestionWatch.elapsed, lessThan(const Duration(seconds: 5))); + }, timeout: const Timeout(Duration(seconds: 45))); + }); +} + +SpellingEngineContext _fixtureContext({ + required String project, + required int revision, + List words = const [], + String languageId = 'en-Test', +}) { + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + return SpellingEngineContext( + languageId: languageId, + affPath: p.join(fixture, 'test.aff'), + dicPath: p.join(fixture, 'test.dic'), + baseFingerprint: 'controlled-fixture', + personalRevision: 0, + projectIdentity: project, + projectRevision: revision, + customWords: words, + ); +} + +SpellingProseRun _run(String text) => SpellingProseRun( + id: 'run-${text.length}', + text: text, + languageId: 'en-Test', + atoms: const [], + target: const SpellingSourceTarget(filePath: '/tmp/test.md'), + snapshot: _snapshot, +); + +SpellingProseRun _runFor( + String text, { + required SpellingSnapshotIdentity snapshot, + String languageId = 'en-Test', +}) => SpellingProseRun( + id: 'run-${text.length}', + text: text, + languageId: languageId, + atoms: const [], + target: const SpellingSourceTarget(filePath: '/tmp/test.md'), + snapshot: snapshot, +); + +SpellingSessionInput _sessionInput({ + required String id, + required String root, + required String text, + required AppSettings settings, + int revision = 0, +}) { + var buffer = DocumentBuffer.untitled(id: id, name: '$id.md', text: text); + if (revision != 0) buffer = buffer.copyWith(revision: revision); + return SpellingSessionInput( + buffer: buffer, + workspace: Workspace( + id: 'workspace-$id', + rootPath: root, + kind: WorkspaceKind.markdownFolder, + openedAt: DateTime(2026), + files: const [], + diagnostics: const [], + ), + settings: settings, + documentKind: DocumentKind.markdown, + markdownMode: MarkdownMode.commonMark, + ); +} + +SpellingWordStoreSnapshot _wordSnapshot(String word) => + SpellingWordStoreSnapshot( + revision: 1, + wordsByLanguage: { + 'en-Test': [SpellingWordEntry(key: word, display: word)], + }, + ); + +Future _createFixtureBundle(Directory temporary) async { + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final bundle = Directory(p.join(temporary.path, 'bundle')); + await bundle.create(recursive: true); + final sourceAff = File(p.join(fixture, 'test.aff')); + final sourceDic = File(p.join(fixture, 'test.dic')); + final affChecksum = await sha256.bind(sourceAff.openRead()).first; + final dicChecksum = await sha256.bind(sourceDic.openRead()).first; + await File(p.join(bundle.path, 'dictionaries.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 2, + 'dictionaries': [ + { + 'resourceId': 'en-Test', + 'id': 'en-Test', + 'knownValidProbe': 'hello', + 'locales': ['en-Test'], + 'label': 'Test English', + 'affSourcePath': 'test/test.aff', + 'dicSourcePath': 'test/test.dic', + 'affDownloadUrl': 'https://example.invalid/test.aff', + 'dicDownloadUrl': 'https://example.invalid/test.dic', + 'affSize': await sourceAff.length(), + 'dicSize': await sourceDic.length(), + 'sourceRevision': 'fixture', + 'affSha256': affChecksum.toString(), + 'dicSha256': dicChecksum.toString(), + }, + ], + }), + ); + final installed = Directory( + p.join(temporary.path, 'dictionary-storage', 'downloaded', 'en-Test'), + ); + await installed.create(recursive: true); + await sourceAff.copy(p.join(installed.path, 'dictionary.aff')); + await sourceDic.copy(p.join(installed.path, 'dictionary.dic')); + await File(p.join(installed.path, 'manifest.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'kind': 'downloaded', + 'resourceId': 'en-Test', + 'id': 'en-Test', + 'locales': ['en-Test'], + 'label': 'Test English', + 'sourceRevision': 'fixture', + 'affPath': 'dictionary.aff', + 'dicPath': 'dictionary.dic', + 'affSha256': affChecksum.toString(), + 'dicSha256': dicChecksum.toString(), + }), + ); + return bundle.path; +} + +Future<({String bundle, String aff, String dic})> _createAliasedFixtureBundle( + Directory temporary, +) async { + final fixture = p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + ); + final aff = File(p.join(fixture, 'test.aff')); + final dic = File(p.join(fixture, 'test.dic')); + final affChecksum = await sha256.bind(aff.openRead()).first; + final dicChecksum = await sha256.bind(dic.openRead()).first; + final bundle = Directory(p.join(temporary.path, 'alias-bundle')); + await bundle.create(recursive: true); + await File(p.join(bundle.path, 'dictionaries.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 2, + 'dictionaries': [ + { + 'resourceId': 'nl-AW', + 'id': 'nl-AW', + 'knownValidProbe': 'hello', + 'locales': ['nl-AW', 'nl-NL'], + 'label': 'Dutch', + 'affSourcePath': 'nl/test.aff', + 'dicSourcePath': 'nl/test.dic', + 'affDownloadUrl': 'https://example.invalid/test.aff', + 'dicDownloadUrl': 'https://example.invalid/test.dic', + 'affSize': await aff.length(), + 'dicSize': await dic.length(), + 'sourceRevision': 'fixture', + 'affSha256': affChecksum.toString(), + 'dicSha256': dicChecksum.toString(), + }, + ], + }), + ); + final installed = Directory( + p.join(temporary.path, 'dictionary-storage', 'downloaded', 'nl-AW'), + ); + await installed.create(recursive: true); + await aff.copy(p.join(installed.path, 'dictionary.aff')); + await dic.copy(p.join(installed.path, 'dictionary.dic')); + await File(p.join(installed.path, 'manifest.json')).writeAsString( + jsonEncode({ + 'schemaVersion': 1, + 'kind': 'downloaded', + 'resourceId': 'nl-AW', + 'id': 'nl-AW', + 'locales': ['nl-AW', 'nl-NL'], + 'label': 'Dutch', + 'sourceRevision': 'fixture', + 'affPath': 'dictionary.aff', + 'dicPath': 'dictionary.dic', + 'affSha256': affChecksum.toString(), + 'dicSha256': dicChecksum.toString(), + }), + ); + return (bundle: bundle.path, aff: aff.path, dic: dic.path); +} + +Map _resourceJson(SpellingDictionaryResource resource) => { + 'resourceId': resource.resourceId, + 'id': resource.id, + 'knownValidProbe': resource.knownValidProbe, + 'locales': resource.locales, + 'label': resource.label, + 'affSourcePath': resource.affSourcePath, + 'dicSourcePath': resource.dicSourcePath, + 'affDownloadUrl': resource.affDownloadUrl.toString(), + 'dicDownloadUrl': resource.dicDownloadUrl.toString(), + 'affSize': resource.affSize, + 'dicSize': resource.dicSize, + 'sourceRevision': resource.sourceRevision, + 'affSha256': resource.affSha256, + 'dicSha256': resource.dicSha256, +}; + +Future> _publishedDirectories(String rootPath) async { + final root = Directory(rootPath); + if (!await root.exists()) return const []; + return root + .list() + .where( + (entity) => + entity is Directory && !p.basename(entity.path).startsWith('.'), + ) + .toList(); +} + +Future _waitFor( + bool Function() predicate, { + Duration timeout = const Duration(seconds: 10), +}) async { + final watch = Stopwatch()..start(); + while (!predicate()) { + if (watch.elapsed > timeout) { + throw TimeoutException('Timed out waiting for spelling state.'); + } + await Future.delayed(const Duration(milliseconds: 20)); + } +} + +final class _RecordingNavigatorObserver extends NavigatorObserver { + int popCount = 0; + + @override + void didPop(Route route, Route? previousRoute) { + popCount++; + super.didPop(route, previousRoute); + } +} + +Future _pumpWidgetUntil( + WidgetTester tester, + bool Function() predicate, { + Duration timeout = const Duration(seconds: 10), +}) async { + final watch = Stopwatch()..start(); + while (!predicate()) { + if (watch.elapsed > timeout) { + throw TimeoutException('Timed out waiting for spelling widget state.'); + } + await tester.pump(const Duration(milliseconds: 20)); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + } +} + +final class _DelayedAtomicFileWriter extends AtomicFileWriter { + _DelayedAtomicFileWriter(); + + final Completer started = Completer(); + final Completer _release = Completer(); + + void releaseIfNeeded() { + if (!_release.isCompleted) _release.complete(); + } + + @override + Future writeBytes( + String targetPath, + List bytes, { + required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, + }) async { + await super.writeBytes( + targetPath, + bytes, + overwrite: overwrite, + beforePublish: () async { + if (!started.isCompleted) started.complete(); + await _release.future; + await beforePublish?.call(); + }, + acceptReplaced: acceptReplaced, + ); + } +} + +final class _ToggleFailAtomicFileWriter extends AtomicFileWriter { + bool failWrites = false; + String? conflictRecoveryPath; + List? conflictDestinationBytes; + var writeCount = 0; + + @override + Future writeBytes( + String targetPath, + List bytes, { + required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, + }) async { + writeCount++; + if (failWrites) { + throw FileSystemException('Injected spelling word-store failure.'); + } + final recoveryPath = conflictRecoveryPath; + if (recoveryPath != null) { + final destinationBytes = conflictDestinationBytes; + if (destinationBytes == null) { + throw StateError('Conflict destination bytes were not configured.'); + } + await File(targetPath).parent.create(recursive: true); + await File(targetPath).writeAsBytes(destinationBytes, flush: true); + await File(recoveryPath).writeAsBytes(bytes, flush: true); + throw AtomicFileChangedException(targetPath, recoveryPath: recoveryPath); + } + await super.writeBytes( + targetPath, + bytes, + overwrite: overwrite, + beforePublish: beforePublish, + acceptReplaced: acceptReplaced, + ); + } +} + +final class _PostExchangeAtomicFileWriter extends AtomicFileWriter { + final Completer exchanged = Completer(); + final Completer _release = Completer(); + + void releaseIfNeeded() { + if (!_release.isCompleted) _release.complete(); + } + + @override + Future writeBytes( + String targetPath, + List bytes, { + required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, + }) async { + await super.writeBytes( + targetPath, + bytes, + overwrite: overwrite, + beforePublish: beforePublish, + acceptReplaced: acceptReplaced == null + ? null + : (replacedPath) async { + if (!exchanged.isCompleted) exchanged.complete(); + await _release.future; + return acceptReplaced(replacedPath); + }, + ); + } +} + +final class _RejectedExchangeAtomicFileWriter extends AtomicFileWriter { + final Completer beforeValidated = Completer(); + final Completer exchanged = Completer(); + final Completer _releaseBefore = Completer(); + final Completer _releaseValidation = Completer(); + + void releaseBeforeExchange() { + if (!_releaseBefore.isCompleted) _releaseBefore.complete(); + } + + void releaseValidation() { + if (!_releaseValidation.isCompleted) _releaseValidation.complete(); + } + + void releaseIfNeeded() { + releaseBeforeExchange(); + releaseValidation(); + } + + @override + Future writeBytes( + String targetPath, + List bytes, { + required bool overwrite, + FutureOr Function()? beforePublish, + FutureOr Function(String replacedPath)? acceptReplaced, + }) async { + await super.writeBytes( + targetPath, + bytes, + overwrite: overwrite, + beforePublish: () async { + await beforePublish?.call(); + if (!beforeValidated.isCompleted) beforeValidated.complete(); + await _releaseBefore.future; + }, + acceptReplaced: acceptReplaced == null + ? null + : (replacedPath) async { + if (!exchanged.isCompleted) exchanged.complete(); + await _releaseValidation.future; + return acceptReplaced(replacedPath); + }, + ); + } +} diff --git a/test/src/spelling_workspace_test.dart b/test/src/spelling_workspace_test.dart new file mode 100644 index 00000000..715422b1 --- /dev/null +++ b/test/src/spelling_workspace_test.dart @@ -0,0 +1,1677 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:busymark/l10n/generated/app_localizations_en.dart'; +import 'package:busymark/src/app/app_router.dart'; +import 'package:busymark/src/app/app_settings.dart'; +import 'package:busymark/src/app/busymark_app.dart'; +import 'package:busymark/src/app/busymark_design.dart'; +import 'package:busymark/src/app/system_accent.dart'; +import 'package:busymark/src/editor/source_highlighter.dart' + show BusyMarkSourceEditingController; +import 'package:busymark/src/editor/source/source_editor.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_block_widgets.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; +import 'package:busymark/src/local_history/local_history_store.dart'; +import 'package:busymark/src/local_history/local_history_controller.dart'; +import 'package:busymark/src/platform/linux_header_bar_service.dart'; +import 'package:busymark/src/platform/native_menu_service.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:busymark/src/spellcheck/spelling_dictionary_downloader.dart'; +import 'package:busymark/src/spellcheck/spelling_coordinator.dart'; +import 'package:busymark/src/spellcheck/spelling_language.dart'; +import 'package:busymark/src/spellcheck/spelling_projection.dart'; +import 'package:busymark/src/spellcheck/spelling_session_controller.dart'; +import 'package:busymark/src/workspace/presentation/workspace_screen.dart'; +import 'package:busymark/src/workspace/recovery_persistence.dart'; +import 'package:busymark/src/workspace/session_persistence.dart'; +import 'package:busymark/src/workspace/workspace_controller.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +import '../support/spelling_test_bundle.dart'; + +void main() { + final l10n = AppLocalizationsEn(); + test( + 'workspace spelling UI has no obsolete floating or Material chooser', + () { + final source = File( + 'lib/src/workspace/presentation/workspace_screen.dart', + ).readAsStringSync(); + final chooserStart = source.indexOf( + 'Future _chooseDocumentSpellingLanguage()', + ); + final chooserEnd = source.indexOf( + 'void _handleTransactionalSourceChanged', + chooserStart, + ); + final chooser = source.substring(chooserStart, chooserEnd); + + expect(source, isNot(contains('_SpellingStatusBanner'))); + expect(chooser, isNot(contains('SimpleDialog'))); + expect(chooser, isNot(contains('SimpleDialogOption'))); + expect(chooser, isNot(contains('AlertDialog'))); + }, + ); + + setUp(() { + for (final name in ['yaru_window', 'yaru_window/events']) { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + MethodChannel(name), + (call) async => call.method == 'state' ? {} : null, + ); + } + }); + tearDown(() { + for (final name in ['yaru_window', 'yaru_window/events']) { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(MethodChannel(name), null); + } + }); + + testWidgets( + 'Writerside nested TOC and comment retain rich spelling through correction', + (tester) async { + const source = + '# hello\n\n- [hello](#hello)\n - [world](#world)\n- [hello](#hello)\n\n\n## world\n\nhelo **world**\n'; + final harness = await _pumpWorkspace( + tester, + source: source, + writerside: true, + ); + await _until(tester, () => harness.spelling.state.complete); + expect(harness.spelling.misspellings.map((o) => o.word), ['helo']); + final occurrence = harness.spelling.misspellings.single; + expect(occurrence.run.target, isA()); + final target = occurrence.run.target as SpellingRichBlockTarget; + final view = tester + .widgetList( + find.byType(BusyMarkWysiwygBlockField), + ) + .singleWhere((v) => v.block.id == target.blockId); + expect(view.spellingRanges, isNotEmpty); + await tester.sendKeyEvent(LogicalKeyboardKey.f7); + final dialog = find.byType(BusyMarkSpellingReviewDialog); + await _until( + tester, + () => find + .descendant(of: dialog, matching: find.text('hello')) + .evaluate() + .isNotEmpty, + ); + await tester.tap( + find.descendant(of: dialog, matching: find.text('hello')), + ); + await _until( + tester, + () => dialog.evaluate().isEmpty && harness.spelling.state.complete, + ); + expect(harness.workspace.activeText, contains('hello **world**')); + expect( + harness.workspace.activeText, + contains(''), + ); + expect(harness.spelling.misspellings, isEmpty); + await tester.pumpWidget(const SizedBox.shrink()); + }, + ); + + testWidgets( + 'Ctrl+N typing paints live spelling targets and corrects with undo', + (tester) async { + final harness = await _pumpWorkspace(tester); + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.createMarkdownFile).last); + await _until( + tester, + () => find.byType(BusyMarkWysiwygEditor).evaluate().isNotEmpty, + ); + final editor = find.byType(BusyMarkWysiwygEditor); + final field = find.descendant( + of: editor, + matching: find.byType(EditableText), + ); + await tester.enterText(field, 'helo'); + await _until( + tester, + () => + harness.spelling.state.complete && + harness.spelling.misspellings.any((o) => o.word == 'helo'), + ); + final view = tester.widget( + find.byType(BusyMarkWysiwygBlockField), + ); + final target = + harness.spelling.misspellings.single.run.target + as SpellingRichBlockTarget; + expect(target.blockId, view.block.id); + expect(harness.spelling.state.complete, isTrue); + expect(harness.spelling.misspellings.single.word, 'helo'); + expect(view.spellingRanges, [const TextRange(start: 0, end: 4)]); + expect(harness.workspace.activeText, 'helo'); + final liveController = _controllerForSpellingOverlay(tester, 'helo'); + expect( + liveController.selection, + const TextSelection.collapsed(offset: 4), + ); + expect( + busyMarkSpellingUnderlineSuppressed( + liveController, + const TextRange(start: 0, end: 4), + ), + isFalse, + ); + expect(_spellingUnderlineOverlay(), findsOneWidget); + + // A structural edit can change live IDs/generation without changing the + // committed source (the new buffer has no final newline). It must still + // rebind spelling to the mounted tree. + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await _until(tester, () { + final occurrences = harness.spelling.misspellings; + if (!harness.spelling.state.complete || occurrences.isEmpty) { + return false; + } + final currentTarget = + occurrences.single.run.target as SpellingRichBlockTarget; + return currentTarget.documentGeneration == + tester + .state(editor) + .spellingDocumentGeneration; + }); + expect(harness.workspace.activeText, 'helo'); + expect( + tester + .widgetList( + find.byType(BusyMarkWysiwygBlockField), + ) + .where((v) => v.spellingRanges.isNotEmpty), + hasLength(1), + ); + + await tester.sendKeyEvent(LogicalKeyboardKey.f7); + await _until( + tester, + () => find + .descendant( + of: find.byType(BusyMarkSpellingReviewDialog), + matching: find.text('hello'), + ) + .evaluate() + .isNotEmpty, + ); + await tester.tap( + find.descendant( + of: find.byType(BusyMarkSpellingReviewDialog), + matching: find.text('hello'), + ), + ); + await _until( + tester, + () => + harness.workspace.activeText == 'hello' && + find.byType(BusyMarkSpellingReviewDialog).evaluate().isEmpty, + ); + harness.controller.undoActiveBuffer(); + await _until( + tester, + () => + harness.spelling.state.complete && + harness.spelling.misspellings.any((o) => o.word == 'helo'), + ); + expect(harness.workspace.activeText, 'helo'); + final undoView = _viewWithSpellingOverlay(tester, 'helo'); + expect(undoView.spellingRanges, [const TextRange(start: 0, end: 4)]); + final undoController = _controllerForSpellingOverlay(tester, 'helo'); + expect(undoController.selection.isCollapsed, isTrue); + expect( + busyMarkSpellingUnderlineSuppressed( + undoController, + const TextRange(start: 0, end: 4), + ), + isFalse, + ); + expect(_spellingUnderlineOverlay(), findsOneWidget); + harness.controller.redoActiveBuffer(); + await _until( + tester, + () => + harness.spelling.state.complete && + harness.spelling.misspellings.isEmpty, + ); + expect(harness.workspace.activeText, 'hello'); + await tester.pumpWidget(const SizedBox.shrink()); + }, + ); + + testWidgets('confirmed spelling underline survives continued typing', ( + tester, + ) async { + final harness = await _pumpWorkspace(tester); + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.createMarkdownFile).last); + await _until( + tester, + () => find.byType(BusyMarkWysiwygEditor).evaluate().isNotEmpty, + ); + final field = find.descendant( + of: find.byType(BusyMarkWysiwygEditor), + matching: find.byType(EditableText), + ); + + await tester.enterText(field, 'helo'); + await _until( + tester, + () => + harness.spelling.state.complete && + harness.spelling.misspellings.any((item) => item.word == 'helo'), + ); + var controller = _controllerForSpellingOverlay(tester, 'helo'); + expect(controller.selection.extentOffset, 4); + expect( + busyMarkSpellingUnderlineSuppressed( + controller, + const TextRange(start: 0, end: 4), + ), + isFalse, + ); + + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'helo ', + selection: TextSelection.collapsed(offset: 5), + ), + ); + controller = _controllerForSpellingOverlay(tester, 'helo '); + expect(controller.text, 'helo '); + expect(controller.selection.extentOffset, 5); + expect( + busyMarkSpellingUnderlineSuppressed( + controller, + const TextRange(start: 0, end: 4), + ), + isFalse, + ); + expect(_spellingUnderlineOverlay(), findsOneWidget); + + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'helo world', + selection: TextSelection.collapsed(offset: 10), + ), + ); + await _until( + tester, + () => + harness.workspace.activeText == 'helo world' && + harness.spelling.state.complete && + harness.spelling.misspellings.length == 1 && + harness.spelling.misspellings.single.word == 'helo' && + _wysiwygViewWithSpellingRanges( + text: 'helo world', + ).evaluate().isNotEmpty, + ); + controller = _controllerForSpellingOverlay(tester, 'helo world'); + expect(controller.selection.extentOffset, 10); + expect( + busyMarkSpellingUnderlineSuppressed( + controller, + const TextRange(start: 0, end: 4), + ), + isFalse, + ); + expect(_spellingUnderlineOverlay(), findsOneWidget); + + controller.selection = const TextSelection.collapsed(offset: 3); + await tester.pump(); + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'helxo world', + selection: TextSelection.collapsed(offset: 4), + ), + ); + await _until( + tester, + () => + harness.workspace.activeText == 'helxo world' && + harness.spelling.state.complete && + harness.spelling.misspellings.length == 1 && + harness.spelling.misspellings.single.word == 'helxo' && + _wysiwygViewWithSpellingRanges( + text: 'helxo world', + ).evaluate().isNotEmpty, + ); + controller = _controllerForSpellingOverlay(tester, 'helxo world'); + expect(controller.selection.extentOffset, 4); + expect(_viewWithSpellingOverlay(tester, 'helxo world').spellingRanges, [ + const TextRange(start: 0, end: 5), + ]); + expect( + busyMarkSpellingUnderlineSuppressed( + controller, + const TextRange(start: 0, end: 5), + ), + isFalse, + ); + expect(_spellingUnderlineOverlay(), findsOneWidget); + await tester.pumpWidget(const SizedBox.shrink()); + }); + + for (final source in [ + 'helo café\n\nwrld\n', + 'helo \nworld\n\nwrld\n', + '| helo café |\n| --- |\n| hello |\n\nwrld\n', + ]) { + testWidgets( + 'real rich review retains later visits after serialization: $source', + (tester) async { + final harness = await _pumpWorkspace(tester, source: source); + await _until( + tester, + () => + harness.spelling.state.complete && + harness.spelling.misspellings.any((o) => o.word == 'wrld'), + ); + // Start at the later occurrence, then visit earlier words by wrapping. + final state = tester.state( + find.byType(BusyMarkWysiwygEditor), + ); + state.revealSpellingOccurrence( + harness.spelling.misspellings.firstWhere((o) => o.word == 'wrld'), + ); + await tester.pumpAndSettle(); + await tester.sendKeyEvent(LogicalKeyboardKey.f7); + final dialog = find.byType(BusyMarkSpellingReviewDialog); + await _until( + tester, + () => find + .descendant(of: dialog, matching: find.text('wrld')) + .evaluate() + .isNotEmpty, + ); + await tester.tap( + find.descendant( + of: dialog, + matching: find.text(l10n.sourceSearchNextMatch), + ), + ); + await _until( + tester, + () => find + .descendant(of: dialog, matching: find.text('hello')) + .evaluate() + .isNotEmpty, + ); + await tester.tap( + find.descendant(of: dialog, matching: find.text('hello')), + ); + await _until( + tester, + () => !harness.workspace.activeText.contains('helo'), + ); + if (source.contains('é')) { + expect(harness.workspace.activeText, contains('café')); + expect(harness.workspace.activeText, isNot(contains('é'))); + } + // The fixture deliberately does not contain café. Ignore it if present; + // the previously visited wrld must not become the next review item. + await _until( + tester, + () => + dialog.evaluate().isEmpty || + find + .descendant(of: dialog, matching: find.text('café')) + .evaluate() + .isNotEmpty, + ); + if (dialog.evaluate().isNotEmpty) { + await tester.tap( + find.descendant( + of: dialog, + matching: find.text(l10n.ignoreSpellingOnce), + ), + ); + } + await _until(tester, () => dialog.evaluate().isEmpty); + await _until(tester, () => harness.spelling.state.complete); + expect( + harness.spelling.misspellings.map((o) => o.word), + contains('wrld'), + ); + expect(harness.workspace.activeText, endsWith('wrld\n')); + await tester.pumpWidget(const SizedBox.shrink()); + }, + ); + } + + for (final viewMode in const [ + DocumentViewModePreference.editor, + DocumentViewModePreference.split, + ]) { + testWidgets( + 'missing dictionary uses one integrated banner in ${viewMode.name}', + (tester) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + dictionaryInstalled: false, + viewMode: viewMode, + ); + await _until( + tester, + () => + harness.spelling.state.status == + SpellingPresentationStatus.dictionaryNotInstalled && + find.byType(BusyMarkBanner).evaluate().isNotEmpty && + tester + .widget(find.byType(BusyMarkBanner)) + .revealed, + ); + await tester.pump(BusyMarkMotion.bannerReveal); + + final banner = find.byType(BusyMarkBanner); + final statusBar = find.byKey(const ValueKey('document-status-bar')); + final pane = find.byKey( + ValueKey( + viewMode == DocumentViewModePreference.editor + ? 'document-wysiwyg-pane' + : 'document-source-pane', + ), + ); + expect(banner, findsOneWidget); + expect( + find.text( + l10n.spellingDictionaryNotInstalledForLanguage('Test English'), + ), + findsOneWidget, + ); + expect(find.text(l10n.installSpellingDictionary), findsOneWidget); + expect(statusBar, findsOneWidget); + expect( + find.descendant(of: statusBar, matching: find.text('Test English')), + findsOneWidget, + ); + expect( + find.descendant(of: banner, matching: find.byType(FilledButton)), + findsOneWidget, + ); + expect( + find.descendant(of: banner, matching: find.byType(ElevatedButton)), + findsNothing, + ); + expect( + find.ancestor( + of: banner, + matching: find.byType(PositionedDirectional), + ), + findsNothing, + ); + expect(tester.getBottomLeft(banner).dy, tester.getTopLeft(pane).dy); + expect(tester.getBottomLeft(pane).dy, tester.getTopLeft(statusBar).dy); + }, + ); + } + + testWidgets( + 'language-required state uses compact document status instead of a banner', + (tester) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + defaultLanguage: null, + ); + await _until( + tester, + () => + harness.spelling.state.status == + SpellingPresentationStatus.languageRequired, + ); + + final statusBar = find.byKey(const ValueKey('document-status-bar')); + final languageStatus = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + final banner = tester.widget(find.byType(BusyMarkBanner)); + expect(statusBar, findsOneWidget); + expect(languageStatus, findsOneWidget); + expect( + find.descendant( + of: languageStatus, + matching: find.text(l10n.spellingLanguageUnsetStatus), + ), + findsOneWidget, + ); + expect(banner.revealed, isFalse); + + await tester.tap(languageStatus); + await _until( + tester, + () => find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + final chooser = find.byType(BusyMarkDialogShell); + expect( + find.descendant( + of: chooser, + matching: find.text(l10n.chooseSpellingLanguage), + ), + findsOneWidget, + ); + await tester.tap( + find.descendant(of: chooser, matching: find.text('Test English')), + ); + await _until( + tester, + () => + find.byType(BusyMarkDialogShell).evaluate().isEmpty && + harness.spelling.state.status == SpellingPresentationStatus.ready, + ); + + expect( + find.descendant(of: statusBar, matching: find.text('Test English')), + findsOneWidget, + ); + expect( + tester.widget(find.byType(BusyMarkBanner)).revealed, + isFalse, + ); + expect( + harness.workspace.activeBuffer?.editorState.spellingLanguage, + const SpellingLanguageOverride.selected('en-Test'), + ); + }, + ); + + testWidgets('general Markdown fixture finishes automatic rich spelling', ( + tester, + ) async { + final source = File('test/fixtures/markdown/basic.md').readAsStringSync(); + final harness = await _pumpWorkspace(tester, source: source); + await _until( + tester, + () => [ + SpellingPresentationStatus.ready, + SpellingPresentationStatus.incomplete, + SpellingPresentationStatus.failure, + ].contains(harness.spelling.state.status), + ); + expect( + harness.spelling.state.status, + SpellingPresentationStatus.ready, + reason: harness.spelling.state.message, + ); + expect(harness.spelling.state.complete, isTrue); + expect(find.text(l10n.spellingCheckIncomplete), findsNothing); + expect(find.text(l10n.spellingCheckFailed), findsNothing); + expect(harness.spelling.annotations, isNotEmpty); + }); + + for (final mode in [ + DocumentViewModePreference.editor, + DocumentViewModePreference.source, + ]) { + testWidgets( + 'pasted formatted job finishes automatic spelling in ${mode.name}', + (tester) async { + final html = File( + 'test/fixtures/spelling/pasted_job.html', + ).readAsStringSync(); + const channel = MethodChannel(richClipboardChannelName); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + channel, + (call) async => call.method == 'read' + ? {'html': html, 'text': 'Plain fallback'} + : null, + ); + addTearDown( + () => TestDefaultBinaryMessengerBinding + .instance + .defaultBinaryMessenger + .setMockMethodCallHandler(channel, null), + ); + final harness = await _pumpWorkspace( + tester, + source: 'Target\n', + viewMode: mode, + ); + await tester.tap(find.byType(EditableText).first); + for (final key in [LogicalKeyboardKey.keyA, LogicalKeyboardKey.keyV]) { + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyEvent(key); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pump(); + } + await _until( + tester, + () => harness.workspace.activeText.contains('Final helo'), + ); + final source = harness.workspace.activeText; + await _until( + tester, + () => + harness.spelling.misspellings.any((o) => o.word == 'helo') || + [ + SpellingPresentationStatus.incomplete, + SpellingPresentationStatus.failure, + ].contains(harness.spelling.state.status), + ); + expect( + harness.spelling.state.status, + SpellingPresentationStatus.ready, + reason: harness.spelling.state.message, + ); + expect(harness.spelling.state.complete, isTrue); + expect(find.text(l10n.spellingCheckIncomplete), findsNothing); + expect(find.text(l10n.spellingCheckFailed), findsNothing); + final occurrence = harness.spelling.misspellings.singleWhere( + (o) => o.word == 'helo', + ); + expect(occurrence.sourceStart, source.indexOf('helo')); + expect(harness.spelling.annotations, isNotEmpty); + if (mode == DocumentViewModePreference.editor) { + final target = occurrence.run.target as SpellingRichBlockTarget; + final block = tester + .widgetList( + find.byType(BusyMarkWysiwygBlockField), + ) + .singleWhere((field) => field.block.id == target.blockId); + expect( + block.spellingRanges, + contains( + TextRange( + start: occurrence.fieldStart!, + end: occurrence.fieldEnd!, + ), + ), + ); + } + }, + ); + } + + testWidgets('new rich document checks spelling after choosing its language', ( + tester, + ) async { + final harness = await _pumpWorkspace(tester, defaultLanguage: null); + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.createMarkdownFile).last); + await _until( + tester, + () => find.byType(BusyMarkWysiwygEditor).evaluate().isNotEmpty, + ); + + final editor = find.byType(BusyMarkWysiwygEditor); + final field = find.descendant( + of: editor, + matching: find.byType(EditableText), + ); + await tester.enterText(field, 'helo'); + await _until( + tester, + () => + harness.spelling.state.status == + SpellingPresentationStatus.languageRequired, + ); + + final languageStatus = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + expect( + find.descendant(of: languageStatus, matching: find.text('Language…')), + findsOneWidget, + ); + await tester.tap(languageStatus); + await _until( + tester, + () => find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + await tester.tap( + find.descendant( + of: find.byType(BusyMarkDialogShell), + matching: find.text('Test English'), + ), + ); + await _until(tester, () { + final status = harness.spelling.state.status; + return status != SpellingPresentationStatus.languageRequired && + status != SpellingPresentationStatus.checking; + }); + + final state = harness.spelling.state; + final diagnostics = + 'status=${state.status} message=${state.message} ' + 'misspellings=${harness.spelling.misspellings.length} ' + 'annotations=${harness.spelling.annotations.length}'; + expect(state.status, SpellingPresentationStatus.ready, reason: diagnostics); + expect(state.complete, isTrue, reason: diagnostics); + expect( + harness.spelling.misspellings.single.word, + 'helo', + reason: diagnostics, + ); + expect(harness.spelling.annotations, isNotEmpty, reason: diagnostics); + + final occurrence = harness.spelling.misspellings.single; + expect(occurrence.run.target, isA()); + final target = occurrence.run.target as SpellingRichBlockTarget; + final editorState = tester.state(editor); + expect(target.documentGeneration, editorState.spellingDocumentGeneration); + final block = tester + .widgetList( + find.byType(BusyMarkWysiwygBlockField), + ) + .singleWhere((candidate) => candidate.block.id == target.blockId); + expect(block.spellingRanges, [const TextRange(start: 0, end: 4)]); + expect(_spellingUnderlineOverlay(), findsOneWidget); + }); + + testWidgets( + 'new source document checks spelling after choosing its language', + (tester) async { + final harness = await _pumpWorkspace( + tester, + defaultLanguage: null, + viewMode: DocumentViewModePreference.source, + ); + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.keyN); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pumpAndSettle(); + await tester.tap(find.text(l10n.createMarkdownFile).last); + await _until( + tester, + () => find.byType(BusyMarkSourceEditor).evaluate().isNotEmpty, + ); + + final editor = find.byType(BusyMarkSourceEditor); + final field = find.descendant( + of: editor, + matching: find.byType(EditableText), + ); + await tester.enterText(field, 'helo'); + await _until( + tester, + () => + harness.spelling.state.status == + SpellingPresentationStatus.languageRequired, + ); + + final languageStatus = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + expect( + find.descendant(of: languageStatus, matching: find.text('Language…')), + findsOneWidget, + ); + await tester.tap(languageStatus); + await _until( + tester, + () => find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + await tester.tap( + find.descendant( + of: find.byType(BusyMarkDialogShell), + matching: find.text('Test English'), + ), + ); + await _until(tester, () { + final status = harness.spelling.state.status; + return status != SpellingPresentationStatus.languageRequired && + status != SpellingPresentationStatus.checking; + }); + + final state = harness.spelling.state; + expect(state.status, SpellingPresentationStatus.ready); + expect(state.complete, isTrue); + expect(harness.spelling.misspellings.single.word, 'helo'); + expect( + harness.spelling.annotations + .map( + (annotation) => + TextRange(start: annotation.start, end: annotation.end), + ) + .toList(), + [const TextRange(start: 0, end: 4)], + ); + expect( + harness.spelling.annotations.single.target, + isA(), + ); + + final controller = tester + .widgetList( + find.descendant(of: editor, matching: find.byType(TextField)), + ) + .map((widget) => widget.controller) + .whereType() + .single; + const range = TextRange(start: 0, end: 4); + final painter = find.byWidgetPredicate( + (widget) => + widget is CustomPaint && + widget.foregroundPainter.runtimeType.toString() == + '_SourceSpellingPainter', + ); + for (final offset in [0, 2, 4]) { + controller.fullSelection = TextSelection.collapsed(offset: offset); + await tester.pump(); + expect(painter, findsOneWidget, reason: 'caret $offset'); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + reason: 'caret $offset', + ); + } + + controller.value = controller.value.copyWith(composing: range); + await tester.pump(); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isTrue, + ); + controller.value = controller.value.copyWith(composing: TextRange.empty); + await tester.pump(); + expect(painter, findsOneWidget); + expect( + busyMarkSourceSpellingUnderlineSuppressed(controller, range), + isFalse, + ); + }, + ); + + for (final viewMode in DocumentViewModePreference.values) { + testWidgets('uses one document status strip in ${viewMode.name} mode', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + viewMode: viewMode, + ); + await _until(tester, () => harness.spelling.state.complete); + + final statusBar = find.byKey(const ValueKey('document-status-bar')); + expect(statusBar, findsOneWidget); + expect( + find.descendant(of: statusBar, matching: find.text('Test English')), + findsOneWidget, + ); + expect( + find.descendant(of: statusBar, matching: find.text('LF')), + findsOneWidget, + ); + expect( + find.byKey(const ValueKey('document-spelling-language-status')), + findsOneWidget, + ); + }); + } + + testWidgets('spelling-off status remains an actionable language control', ( + tester, + ) async { + final harness = await _pumpWorkspace(tester, source: 'helo\n'); + await _until(tester, () => harness.spelling.state.complete); + final languageStatus = find.byKey( + const ValueKey('document-spelling-language-status'), + ); + + await tester.tap(languageStatus); + await _until( + tester, + () => find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + await tester.tap(find.text(l10n.disableDocumentSpelling)); + await _until( + tester, + () => + harness.workspace.activeBuffer?.editorState.spellingLanguage == + const SpellingLanguageOverride.disabled(), + ); + + expect(find.text(l10n.spellingOffStatus), findsOneWidget); + await tester.tap(languageStatus); + await _until( + tester, + () => find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + await tester.tap(find.text('Test English')); + await _until( + tester, + () => + harness.spelling.state.status == SpellingPresentationStatus.ready && + find.text('Test English').evaluate().isNotEmpty, + ); + }); + + testWidgets('status initializes the chooser when automatic spelling is off', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + automaticSpelling: false, + ); + await _until( + tester, + () => + harness.spelling.state.status == SpellingPresentationStatus.disabled, + ); + expect(harness.spelling.catalog, isNull); + expect(find.text(l10n.spellingOffStatus), findsOneWidget); + + await tester.tap( + find.byKey(const ValueKey('document-spelling-language-status')), + ); + await _until( + tester, + () => + harness.spelling.catalog != null && + find.byType(BusyMarkDialogShell).evaluate().isNotEmpty, + ); + expect( + find.descendant( + of: find.byType(BusyMarkDialogShell), + matching: find.text('Test English'), + ), + findsOneWidget, + ); + await tester.tap(find.text(l10n.inheritSpellingLanguage)); + await tester.pumpAndSettle(); + }); + + testWidgets('banner installs the required dictionary and then conceals', ( + tester, + ) async { + var downloadCount = 0; + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + dictionaryInstalled: false, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + await _copyDictionaryDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ); + await _until( + tester, + () => + find.byType(BusyMarkBanner).evaluate().isNotEmpty && + tester.widget(find.byType(BusyMarkBanner)).revealed, + ); + await tester.pump(BusyMarkMotion.bannerReveal); + + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _until( + tester, + () => + downloadCount == 2 && + harness.spelling.catalog?.installedById('en-Test') != null && + !tester + .widget(find.byType(BusyMarkBanner)) + .revealed && + harness.spelling.state.complete, + ); + await tester.pump(BusyMarkMotion.bannerReveal); + + expect(harness.spelling.state.status, SpellingPresentationStatus.ready); + expect(find.byType(BusyMarkBanner), findsOneWidget); + expect(tester.getSize(find.byType(BusyMarkBanner)).height, 0); + expect( + find.descendant( + of: find.byType(BusyMarkBanner), + matching: find.byType(Text), + ), + findsNothing, + ); + }); + + testWidgets('failed banner installation keeps the unresolved state', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + dictionaryInstalled: false, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + throw const SocketException('test dictionary download failure'); + }, + ); + await _until( + tester, + () => + find.byType(BusyMarkBanner).evaluate().isNotEmpty && + tester.widget(find.byType(BusyMarkBanner)).revealed, + ); + await tester.pump(BusyMarkMotion.bannerReveal); + + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _until( + tester, + () => + harness.spelling.dictionaryInstallStatus?.phase == + SpellingDictionaryInstallPhase.failed, + ); + + expect( + harness.spelling.state.status, + SpellingPresentationStatus.dictionaryNotInstalled, + ); + expect(find.byType(BusyMarkBanner), findsOneWidget); + expect( + tester.widget(find.byType(BusyMarkBanner)).revealed, + isTrue, + ); + expect(find.text(l10n.spellingDictionaryInstallFailed), findsOneWidget); + }); + + testWidgets('routine checking does not create persistent editor chrome', ( + tester, + ) async { + final coordinator = Completer(); + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + coordinatorStarter: () => coordinator.future, + ); + await _until( + tester, + () => + harness.spelling.state.status == SpellingPresentationStatus.checking, + ); + + final banner = find.byType(BusyMarkBanner); + expect(banner, findsOneWidget); + expect(tester.widget(banner).revealed, isFalse); + expect(tester.getSize(banner).height, 0); + expect( + find.descendant(of: banner, matching: find.byType(Text)), + findsNothing, + ); + }); + + testWidgets('automatic spelling failure is visible in the compact banner', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + coordinatorStarter: () async => + throw StateError('injected spelling worker failure'), + ); + await _until( + tester, + () => harness.spelling.state.status == SpellingPresentationStatus.failure, + ); + + final banner = find.byType(BusyMarkBanner); + expect(tester.widget(banner).revealed, isTrue); + expect(find.text(l10n.spellingCheckFailed), findsOneWidget); + expect( + find.textContaining('injected spelling worker failure'), + findsNothing, + ); + }); + + testWidgets( + 'automatic incomplete projection is visible in the compact banner', + (tester) async { + final harness = await _pumpWorkspace( + tester, + source: '

helo', + writersideXml: true, + viewMode: DocumentViewModePreference.source, + ); + await _until( + tester, + () => + harness.spelling.state.status == + SpellingPresentationStatus.incomplete, + ); + + final banner = find.byType(BusyMarkBanner); + expect(tester.widget(banner).revealed, isTrue); + expect(find.text(l10n.spellingCheckIncomplete), findsOneWidget); + }, + ); + + testWidgets('native spelling submenu applies immediate language choices', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + includeSecondLanguage: true, + viewMode: DocumentViewModePreference.source, + ); + await _until(tester, () => harness.spelling.state.complete); + + var entries = await _chooseNativeSpellingLanguage( + tester, + l10n, + l10n.disableDocumentSpelling, + ); + final languageMenu = entries.singleWhere( + (entry) => entry['label'] == l10n.chooseSpellingLanguage, + ); + final children = (languageMenu['children'] as List) + .cast>(); + expect(children.map((entry) => entry['label']), [ + l10n.inheritSpellingLanguage, + l10n.disableDocumentSpelling, + '', + 'Test English', + 'Test French', + ]); + expect(children.where((entry) => entry['selected'] == true), hasLength(1)); + expect(children.first['selected'], isTrue); + expect(find.byType(SimpleDialog), findsNothing); + expect(find.byType(SimpleDialogOption), findsNothing); + await _until( + tester, + () => + harness.workspace.activeBuffer?.editorState.spellingLanguage == + const SpellingLanguageOverride.disabled(), + ); + + harness.controller.updateDocumentEditorState( + harness.workspace.activeBuffer!.id, + harness.workspace.activeBuffer!.editorState.copyWith( + spellingLanguage: const SpellingLanguageOverride.inherit(), + ), + ); + await _until(tester, () => harness.spelling.state.complete); + entries = await _chooseNativeSpellingLanguage(tester, l10n, 'Test English'); + await _until( + tester, + () => + harness.workspace.activeBuffer?.editorState.spellingLanguage == + const SpellingLanguageOverride.selected('en-Test'), + ); + final updatedMenu = entries.singleWhere( + (entry) => entry['label'] == l10n.chooseSpellingLanguage, + ); + expect(updatedMenu['children'], isNotNull); + + await _until(tester, () => harness.spelling.state.complete); + final selectedEntries = await _chooseNativeSpellingLanguage( + tester, + l10n, + l10n.inheritSpellingLanguage, + ); + final selectedLanguageMenu = selectedEntries.singleWhere( + (entry) => entry['label'] == l10n.chooseSpellingLanguage, + ); + final selectedChildren = (selectedLanguageMenu['children'] as List) + .cast>(); + expect( + selectedChildren.where((entry) => entry['selected'] == true), + hasLength(1), + ); + expect( + selectedChildren.singleWhere( + (entry) => entry['label'] == 'Test English', + )['selected'], + isTrue, + ); + await _until( + tester, + () => + harness.workspace.activeBuffer?.editorState.spellingLanguage == + const SpellingLanguageOverride.inherit(), + ); + await tester.pump(const Duration(milliseconds: 300)); + await _until(tester, () => harness.spelling.state.complete); + }); + + testWidgets('cancelling document dictionary install preserves override', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + includeSecondLanguage: true, + viewMode: DocumentViewModePreference.source, + ); + await _until(tester, () => harness.spelling.state.complete); + const previous = SpellingLanguageOverride.inherit(); + + await _chooseNativeSpellingLanguage(tester, l10n, 'Test French'); + expect(find.text(l10n.spellingDictionaryNotInstalled), findsOneWidget); + expect(find.byType(BusyMarkDialogShell), findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + expect( + harness.workspace.activeBuffer?.editorState.spellingLanguage, + previous, + ); + await tester.tap(find.text(l10n.cancel)); + await tester.pumpAndSettle(); + + expect( + harness.workspace.activeBuffer?.editorState.spellingLanguage, + previous, + ); + expect(harness.spelling.catalog?.installedById('fr-Test'), isNull); + }); + + testWidgets('document language changes only after dictionary installation', ( + tester, + ) async { + final releaseDownload = Completer(); + var downloadCount = 0; + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + includeSecondLanguage: true, + viewMode: DocumentViewModePreference.source, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + downloadCount += 1; + await releaseDownload.future; + await _copyDictionaryDownload( + source: source, + destination: destination, + expectedBytes: expectedBytes, + cancellation: cancellation, + onProgress: onProgress, + ); + }, + ); + await _until(tester, () => harness.spelling.state.complete); + + await _chooseNativeSpellingLanguage(tester, l10n, 'Test French'); + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _until(tester, () => downloadCount > 0); + expect( + harness.workspace.activeBuffer?.editorState.spellingLanguage, + const SpellingLanguageOverride.inherit(), + ); + + releaseDownload.complete(); + await _until( + tester, + () => + harness.workspace.activeBuffer?.editorState.spellingLanguage == + const SpellingLanguageOverride.selected('fr-Test'), + ); + expect(harness.spelling.catalog?.installedById('fr-Test'), isNotNull); + await tester.pump(const Duration(milliseconds: 300)); + await _until(tester, () => harness.spelling.state.complete); + }); + + testWidgets('failed document dictionary install preserves override', ( + tester, + ) async { + final harness = await _pumpWorkspace( + tester, + source: 'helo\n', + includeSecondLanguage: true, + viewMode: DocumentViewModePreference.source, + downloadFile: + ({ + required source, + required destination, + required expectedBytes, + required cancellation, + required onProgress, + }) async { + throw const SocketException('test dictionary download failure'); + }, + ); + await _until(tester, () => harness.spelling.state.complete); + + await _chooseNativeSpellingLanguage(tester, l10n, 'Test French'); + await tester.tap(find.text(l10n.installSpellingDictionary)); + await _until( + tester, + () => + harness.spelling.dictionaryInstallStatus?.phase == + SpellingDictionaryInstallPhase.failed, + ); + + expect( + harness.workspace.activeBuffer?.editorState.spellingLanguage, + const SpellingLanguageOverride.inherit(), + ); + expect(find.text(l10n.spellingDictionaryInstallFailed), findsOneWidget); + }); +} + +Future<_Harness> _pumpWorkspace( + WidgetTester tester, { + String? source, + bool writerside = false, + bool writersideXml = false, + bool dictionaryInstalled = true, + bool includeSecondLanguage = false, + DocumentViewModePreference viewMode = DocumentViewModePreference.editor, + String? defaultLanguage = 'en-Test', + bool automaticSpelling = true, + SpellingDictionaryFileDownload? downloadFile, + SpellingCoordinatorStarter? coordinatorStarter, +}) async { + await tester.binding.setSurfaceSize(const Size(1400, 1000)); + addTearDown(() => tester.binding.setSurfaceSize(null)); + late Directory root; + late SpellingSessionController spelling; + await tester.runAsync(() async { + root = await Directory.systemTemp.createTemp( + 'busymark-spelling-workspace-', + ); + final bundle = await createSpellingTestBundle(root); + if (includeSecondLanguage) { + final catalogFile = File(p.join(bundle, 'dictionaries.json')); + final catalog = + jsonDecode(await catalogFile.readAsString()) as Map; + final dictionaries = catalog['dictionaries']! as List; + final english = Map.from( + dictionaries.single! as Map, + ); + dictionaries.add({ + ...english, + 'resourceId': 'fr-Test', + 'id': 'fr-Test', + 'locales': ['fr-Test'], + 'label': 'Test French', + }); + await catalogFile.writeAsString(jsonEncode(catalog)); + } + if (!dictionaryInstalled) { + await Directory( + p.join(root.path, 'dictionary-storage', 'downloaded', 'en-Test'), + ).delete(recursive: true); + } + spelling = SpellingSessionController( + bundledRoot: bundle, + applicationSupportRoot: p.join(root.path, 'support'), + dictionaryStorageRoot: p.join(root.path, 'dictionary-storage'), + dictionaryDownloader: downloadFile == null + ? const SpellingDictionaryDownloader() + : SpellingDictionaryDownloader(downloadFile: downloadFile), + coordinatorStarter: coordinatorStarter, + ); + }); + final container = ProviderContainer( + overrides: [ + localSettingsStoreProvider.overrideWithValue( + _Settings(viewMode, defaultLanguage, automaticSpelling), + ), + localHistoryStoreProvider.overrideWithValue(MemoryLocalHistoryStore()), + documentSessionStoreProvider.overrideWithValue( + MemoryDocumentSessionStore(), + ), + documentRecoveryStoreProvider.overrideWithValue( + MemoryDocumentRecoveryStore(), + ), + linuxHeaderBarServiceProvider.overrideWithValue(_HeaderBar()), + systemAccentColorProvider.overrideWith((ref) => const Stream.empty()), + spellingSessionControllerProvider.overrideWith((ref) => spelling), + ], + ); + addTearDown(() async { + container.dispose(); + await root.delete(recursive: true); + }); + await tester.pumpWidget( + UncontrolledProviderScope(container: container, child: const BusyMarkApp()), + ); + await tester.pumpAndSettle(); + final controller = container.read(workspaceControllerProvider.notifier); + if (source != null) { + await tester.runAsync(() async { + final topicName = writersideXml ? 'document.topic' : 'document.md'; + final file = File( + p.join( + root.path, + writerside || writersideXml ? 'topics/$topicName' : topicName, + ), + ); + await file.parent.create(recursive: true); + await file.writeAsString(source); + if (writerside || writersideXml) { + await File(p.join(root.path, 'writerside.cfg')).writeAsString( + '', + ); + await File(p.join(root.path, 'guide.tree')).writeAsString( + '', + ); + } + await controller.openPath( + writerside || writersideXml ? root.path : file.path, + ); + }); + container.read(appRouterProvider).go('/workspace'); + await tester.pumpAndSettle(); + } + return _Harness(container, spelling); +} + +class _Harness { + _Harness(this.container, this.spelling); + final ProviderContainer container; + final SpellingSessionController spelling; + WorkspaceController get controller => + container.read(workspaceControllerProvider.notifier); + WorkspaceState get workspace => container.read(workspaceControllerProvider); +} + +BusyMarkWysiwygBlockField _viewWithSpellingOverlay( + WidgetTester tester, + String text, +) => tester.widget( + _wysiwygViewWithSpellingRanges(text: text), +); + +TextEditingController _controllerForSpellingOverlay( + WidgetTester tester, + String text, +) => tester + .widgetList( + find.descendant( + of: find.byType(BusyMarkWysiwygEditor), + matching: find.byType(EditableText), + ), + ) + .map((editable) => editable.controller) + .singleWhere((controller) => controller.text == text); + +Finder _wysiwygViewWithSpellingRanges({required String text}) => + find.byWidgetPredicate( + (widget) => + widget is BusyMarkWysiwygBlockField && + widget.block.plainText == text && + widget.spellingRanges.isNotEmpty, + ); + +Finder _spellingUnderlineOverlay() => find.byWidgetPredicate( + (widget) => + widget is CustomPaint && + widget.painter.runtimeType.toString() == '_SpellingUnderlinePainter', +); + +Future _until(WidgetTester tester, bool Function() condition) async { + final elapsed = Stopwatch()..start(); + while (!condition()) { + if (elapsed.elapsed > const Duration(seconds: 10)) { + throw TimeoutException('Spelling workspace did not settle'); + } + await tester.pump(const Duration(milliseconds: 50)); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 10)), + ); + } + await tester.pump(); +} + +class _Settings implements LocalSettingsStore { + const _Settings(this.viewMode, this.defaultLanguage, this.automaticSpelling); + + final DocumentViewModePreference viewMode; + final String? defaultLanguage; + final bool automaticSpelling; + + @override + Future> load() async => AppSettings.defaults() + .copyWith( + defaultSpellingLanguage: defaultLanguage, + automaticSpelling: automaticSpelling, + autoSave: false, + reopenPreviousWorkspaceOnStartup: false, + documentViewMode: viewMode, + ) + .toJson(); + @override + Future save(Map value) async {} +} + +class _HeaderBar extends LinuxHeaderBarService { + _HeaderBar() : super(channel: const MethodChannel('test.busymark/spelling')); + @override + bool get isAvailable => false; + @override + bool get usesNativeHeaderBar => false; + @override + Stream get actions => const Stream.empty(); +} + +Future _copyDictionaryDownload({ + required Uri source, + required File destination, + required int expectedBytes, + required SpellingDictionaryDownloadCancellation cancellation, + required void Function(int receivedBytes) onProgress, +}) async { + cancellation.throwIfCancelled(); + final fileName = source.path.endsWith('.aff') ? 'test.aff' : 'test.dic'; + final sourceFile = File( + p.join( + Directory.current.path, + 'packages', + 'busymark_spellcheck_native', + 'test', + 'fixtures', + fileName, + ), + ); + final bytes = await sourceFile.readAsBytes(); + if (bytes.length != expectedBytes) { + throw StateError('Test dictionary size does not match its catalog.'); + } + await destination.writeAsBytes(bytes, flush: true); + onProgress(bytes.length); +} + +Future>> _chooseNativeSpellingLanguage( + WidgetTester tester, + AppLocalizationsEn l10n, + String label, +) async { + List>? entries; + const channel = MethodChannel(nativeMenuChannelName); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, ( + call, + ) async { + if (call.method != 'show') return false; + final arguments = call.arguments as Map; + entries = (arguments['entries'] as List) + .cast>(); + return _nativeMenuIndexForLabel(entries!, label); + }); + addTearDown(() { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + channel, + null, + ); + }); + final field = find.descendant( + of: find.byType(BusyMarkSourceEditor), + matching: find.byType(TextField), + ); + final render = _findRenderEditable(tester.renderObject(field))!; + final caret = render.getLocalRectForCaret(const TextPosition(offset: 1)); + await tester.tapAt( + render.localToGlobal(caret.center), + buttons: kSecondaryMouseButton, + ); + await _until(tester, () => entries != null); + expect(entries, isNotNull); + expect( + entries!.any((entry) => entry['label'] == l10n.chooseSpellingLanguage), + isTrue, + ); + return entries!; +} + +int _nativeMenuIndexForLabel( + List> entries, + String label, +) { + var index = 0; + int? visit(List> items) { + for (final item in items) { + final current = index++; + if (item['label'] == label) return current; + final children = item['children']; + if (children is List) { + final found = visit(children.cast>()); + if (found != null) return found; + } + } + return null; + } + + return visit(entries) ?? -1; +} + +RenderEditable? _findRenderEditable(RenderObject root) { + if (root is RenderEditable) return root; + RenderEditable? result; + root.visitChildren((child) { + result ??= _findRenderEditable(child); + }); + return result; +} diff --git a/test/src/validation_consistency_test.dart b/test/src/validation_consistency_test.dart index c8172561..67c47a9b 100644 --- a/test/src/validation_consistency_test.dart +++ b/test/src/validation_consistency_test.dart @@ -5,6 +5,8 @@ import 'package:busymark/src/core/source_span.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/markdown/raw_html_policy.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_module_service.dart'; import 'package:busymark/src/writerside/writerside_document_resolver.dart'; @@ -15,6 +17,17 @@ import 'package:path/path.dart' as p; void main() { late Directory root; const service = WorkspaceService(); + Future reparse(Workspace workspace, String source) => + service.reparseDocument( + workspace, + DocumentBuffer( + id: 'validation:${workspace.activeFilePath ?? 'untitled'}', + filePath: workspace.activeFilePath, + text: source, + lastSavedText: source, + dirty: true, + ), + ); String path(String relative) => p.join(root.path, relative); Future write(String relative, String source) async { final file = File(path(relative)); @@ -84,15 +97,15 @@ void main() { 'writerside.link.unavailable', ]), ); - workspace = await service.reparseActive(workspace, source); + workspace = await reparse(workspace, source); expect(signature(workspace.diagnostics), original); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('writerside.cfg')), config, ); expect(signature(workspace.diagnostics), original); const fixed = '

Fixed

'; - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('topics/a.topic')), fixed, ); @@ -102,7 +115,7 @@ void main() { ), isEmpty, ); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('writerside.cfg')), config, ); @@ -125,7 +138,7 @@ void main() { ); var workspace = await service.openPath(root.path); expect(signature(workspace.diagnostics), isEmpty); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('topics/b.topic')), '

Target

', ); @@ -135,7 +148,7 @@ void main() { .map((d) => d.filePath), [path('topics/a.topic')], ); - workspace = await service.reparseActive( + workspace = await reparse( workspace, await File(path('topics/b.topic')).readAsString(), ); @@ -159,9 +172,9 @@ void main() { await write('topics/a.topic', source); var workspace = await service.openPath(root.path); expect(signature(workspace.diagnostics), isEmpty); - workspace = await service.reparseActive(workspace, source); + workspace = await reparse(workspace, source); expect(signature(workspace.diagnostics), isEmpty); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('writerside.cfg')), config, ); @@ -193,7 +206,7 @@ void main() { var workspace = await service.openPath(root.path); for (final stage in ['load', 'topic', 'config']) { if (stage != 'load') { - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith( activeFilePath: path( stage == 'topic' ? 'topics/a.topic' : 'writerside.cfg', @@ -238,10 +251,7 @@ void main() { ); var workspace = await service.openPath(root.path); expect(signature(workspace.diagnostics), isEmpty); - workspace = await service.reparseActive( - workspace, - topic('a', declaration + declaration), - ); + workspace = await reparse(workspace, topic('a', declaration + declaration)); final duplicates = workspace.diagnostics.where( (d) => d.code == 'writerside.index.duplicate-symbol', ); @@ -251,7 +261,7 @@ void main() { duplicates.single.relatedSpans.single.filePath, path('topics/a.topic'), ); - workspace = await service.reparseActive( + workspace = await reparse( workspace, topic( 'a', @@ -286,7 +296,7 @@ void main() { ), isEmpty, ); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('shared/topics/b.topic')), '

Shared

', ); @@ -335,7 +345,7 @@ void main() { 'cfg/glossary.xml': '', 'keymap.xml': '', }.entries) { - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path(entry.key)), entry.value, ); @@ -365,9 +375,9 @@ void main() { diagnostics: [...workspace.diagnostics, scanWarning], ); final before = signature(workspace.diagnostics); - workspace = await service.reparseActive(workspace, '# A\n'); + workspace = await reparse(workspace, '# A\n'); expect(signature(workspace.diagnostics), before); - workspace = await service.reparseActive( + workspace = await reparse( workspace.copyWith(activeFilePath: path('b.md')), '# Fixed\n', ); diff --git a/test/src/validation_problems_ui_test.dart b/test/src/validation_problems_ui_test.dart index 86919524..ffccc388 100644 --- a/test/src/validation_problems_ui_test.dart +++ b/test/src/validation_problems_ui_test.dart @@ -9,6 +9,7 @@ import 'package:busymark/src/app/system_accent.dart'; import 'package:busymark/src/core/source_span.dart'; import 'package:busymark/src/editor/source/source_editor.dart'; import 'package:busymark/src/platform/linux_header_bar_service.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_controller.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; @@ -308,11 +309,14 @@ class _ControlledValidationService extends WorkspaceService { String? blockedPath; int calls = 0; @override - Future reparseActive(Workspace workspace, String source) async { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { calls++; if (fail) throw StateError('Validation failed'); - if (workspace.activeFilePath == blockedPath) await gate?.future; - return super.reparseActive(workspace, source); + if (buffer.filePath == blockedPath) await gate?.future; + return super.reparseDocument(workspace, buffer); } } @@ -325,16 +329,19 @@ class _QueuedValidationService extends WorkspaceService { final sources = []; @override - Future reparseActive(Workspace workspace, String source) async { - sources.add(source); - if (source == '# Automatic first\n') { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + sources.add(buffer.text); + if (buffer.text == '# Automatic first\n') { automaticStarted.complete(); await releaseAutomatic.future; - } else if (source == '# Latest\n') { + } else if (buffer.text == '# Latest\n') { latestCalls++; if (!manualStarted.isCompleted) manualStarted.complete(); await releaseManual.future; } - return super.reparseActive(workspace, source); + return super.reparseDocument(workspace, buffer); } } diff --git a/test/src/visualization_markdown_integration_test.dart b/test/src/visualization_markdown_integration_test.dart index a1725e71..787e9bc0 100644 --- a/test/src/visualization_markdown_integration_test.dart +++ b/test/src/visualization_markdown_integration_test.dart @@ -15,6 +15,11 @@ import 'package:flutter_test/flutter_test.dart'; void main() { test('basic fixture uses a renderable OpenAPI fence', () { final source = File('test/fixtures/markdown/basic.md').readAsStringSync(); + expect( + source, + isNot(contains('center centre')), + reason: 'The general Markdown fixture is not a spelling-test corpus.', + ); final parsed = const MarkdownParser().parse( filePath: 'test/fixtures/markdown/basic.md', source: source, diff --git a/test/src/visualization_packaging_audit_test.dart b/test/src/visualization_packaging_audit_test.dart index ecd4b094..41cdae63 100644 --- a/test/src/visualization_packaging_audit_test.dart +++ b/test/src/visualization_packaging_audit_test.dart @@ -29,10 +29,10 @@ void main() { 'linux/io.busystack.busymark.metainfo.xml', ).readAsStringSync(); - expect(pubspec, contains(RegExp(r'^version: 0\.4\.2$', multiLine: true))); + expect(pubspec, contains(RegExp(r'^version: 0\.5\.0$', multiLine: true))); expect( snapcraft, - contains(RegExp(r'^version: "0\.4\.2"$', multiLine: true)), + contains(RegExp(r'^version: "0\.5\.0"$', multiLine: true)), ); expect(snapcraft, contains(RegExp(r'^grade: stable$', multiLine: true))); expect( @@ -57,9 +57,9 @@ void main() { ), ), ); - expect(metainfo, contains(' + controller.state.preview?.blocks.any( + (block) => + block.kind == PreviewBlockKind.heading && + block.text == 'Draft heading', + ) ?? + false, + ); + + final currentWorkspace = controller.state.workspace!; + final resolved = resolveWorkspaceDocumentContext( + currentWorkspace, + controller.state.activeBuffer!, + ); + expect(currentWorkspace.id, originalWorkspace.id); + expect(currentWorkspace.kind, WorkspaceKind.writersideModule); + expect(currentWorkspace.writersideProject, isNotNull); + expect(currentWorkspace.writersideModule, isNotNull); + expect(currentWorkspace.activeFilePath, isNull); + expect(untitled.id, isNot(topic.id)); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(currentWorkspace.markdown?.mode, MarkdownMode.commonMark); + expect(currentWorkspace.markdown?.source, markdown); + expect( + controller.state.preview!.blocks.map((block) => block.kind), + containsAll([ + PreviewBlockKind.heading, + PreviewBlockKind.paragraph, + PreviewBlockKind.list, + PreviewBlockKind.code, + ]), + ); + final preservedTopic = controller.state.documentBuffers.singleWhere( + (buffer) => buffer.id == topic.id, + ); + expect(preservedTopic.text, dirtyTopicText); + expect(preservedTopic.isDirty, isTrue); + expect(service.lastSources[topic.filePath], dirtyTopicText); + expect(service.lastSources.keys, isNot(contains(''))); + expect(service.lastSources, hasLength(1)); + + expect(await controller.activateDocumentBuffer(topic.id), isTrue); + expect(controller.state.activeText, dirtyTopicText); + expect(await controller.activateDocumentBuffer(untitled.id), isTrue); + expect(controller.state.activeText, markdown); + expect( + controller.state.workspace?.markdown?.mode, + MarkdownMode.commonMark, + ); + expect( + controller.state.preview?.blocks.any( + (block) => block.text == 'Draft heading', + ), + isTrue, + ); + }, + ); + + test('identical untitled buffers remain distinct by buffer id', () async { + final harness = await _createControllerHarness(); + final controller = harness.controller._notifier; + await controller.openPath('test/fixtures/writerside/basic_project'); + const source = '# Same heading\n\nSame text.\n'; + + await controller.createMarkdownFile(); + controller.updateActiveText(source); + final first = controller.state.activeBuffer!; + controller.updateDocumentEditorState( + first.id, + first.editorState.copyWith( + selection: const TextSelection.collapsed(offset: 2), + ), + ); + await controller.createMarkdownFile(); + controller.updateActiveText(source); + final second = controller.state.activeBuffer!; + controller.updateDocumentEditorState( + second.id, + second.editorState.copyWith( + selection: const TextSelection.collapsed(offset: 7), + ), + ); + + expect(first.id, isNot(second.id)); + expect(first.filePath, isNull); + expect(second.filePath, isNull); + expect(await controller.activateDocumentBuffer(first.id), isTrue); + expect(controller.state.activeBuffer?.id, first.id); + expect(controller.state.activeBuffer?.editorState.selection.baseOffset, 2); + expect(await controller.activateDocumentBuffer(second.id), isTrue); + expect(controller.state.activeBuffer?.id, second.id); + expect(controller.state.activeBuffer?.editorState.selection.baseOffset, 7); + expect(controller.state.workspace?.markdown?.source, source); + expect( + controller.state.preview?.blocks + .singleWhere((block) => block.kind == PreviewBlockKind.heading) + .text, + 'Same heading', + ); + }); + + test( + 'delayed untitled preview cannot publish into another untitled tab', + (() async { + final service = _BlockingUntitledPreviewWorkspaceService(); + final harness = await _createControllerHarness(service: service); + await harness.settingsController.setValidateOnEdit(false); + final controller = harness.controller._notifier; + await controller.openPath('test/fixtures/writerside/basic_project'); + await controller.createMarkdownFile(); + final firstId = controller.state.activeBuffer!.id; + service.blockNext(firstId); + controller.updateActiveText('# First delayed\n'); + await service.started.future; + + await controller.createMarkdownFile(); + final secondId = controller.state.activeBuffer!.id; + controller.updateActiveText('# Second current\n'); + service.release(); + await service.finished.future; + await _waitFor( + () => + controller.state.preview?.blocks.any( + (block) => block.text == 'Second current', + ) ?? + false, + ); + + expect(secondId, isNot(firstId)); + expect(controller.state.activeBuffer?.id, secondId); + expect(controller.state.activeText, '# Second current\n'); + expect( + controller.state.preview?.blocks.any( + (block) => block.text == 'First delayed', + ), + isFalse, + ); + }), + ); + test('new Markdown files leave preview mode for editor mode', () async { final harness = await _createControllerHarness(); final settingsController = harness.settingsController; @@ -989,6 +1212,125 @@ void main() { await directory.delete(recursive: true); }); + test( + 'saving untitled Markdown in Writerside keeps ordinary files CommonMark', + (() async { + final root = await _createWritableWritersideFixture('ordinary-save'); + addTearDown(() => root.delete(recursive: true)); + final harness = await _createControllerHarness(); + final controller = harness.controller._notifier; + await controller.openPath(root.path); + await controller.createMarkdownFile(); + final bufferId = controller.state.activeBuffer!.id; + controller.updateActiveText('# Ordinary saved note\n'); + final destination = p.join(root.path, 'notes.md'); + + expect(await controller.saveActiveAs(destination), isTrue); + + final state = controller.state; + expect(state.workspace?.kind, WorkspaceKind.writersideModule); + expect(state.activeBuffer?.id, bufferId); + expect(state.activeBuffer?.filePath, destination); + final resolved = resolveWorkspaceDocumentContext( + state.workspace!, + state.activeBuffer!, + ); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(state.workspace?.markdown?.mode, MarkdownMode.commonMark); + }), + ); + + test( + 'Writerside refresh preserves saved Markdown outside the workspace root', + (() async { + final root = await _createWritableWritersideFixture('external-save'); + final external = await Directory.systemTemp.createTemp( + 'busymark-writerside-external-note-', + ); + addTearDown(() => root.delete(recursive: true)); + addTearDown(() => external.delete(recursive: true)); + final harness = await _createControllerHarness(); + final controller = harness.controller; + await controller.openPath(root.path); + await controller.createMarkdownFile(); + final bufferId = controller.state.activeBuffer!.id; + const source = '''# External note + +CommonMark paragraph. + +- remains open +'''; + controller.updateActiveText(source); + final destination = p.join(external.path, 'note.md'); + + expect(await controller.saveActiveAs(destination), isTrue); + expect( + controller.state.workspace!.files.any( + (file) => file.absolutePath == destination, + ), + isFalse, + ); + expect(await controller.refreshWorkspaceFromDisk(), isTrue); + + final state = controller.state; + final buffer = state.documentBuffers.singleWhere( + (candidate) => candidate.id == bufferId, + ); + expect(state.workspace?.kind, WorkspaceKind.writersideModule); + expect(state.activeBuffer?.id, bufferId); + expect(buffer.filePath, destination); + expect(buffer.diskState, DocumentDiskState.present); + expect(buffer.text, source); + expect(state.activeText, source); + final resolved = resolveWorkspaceDocumentContext( + state.workspace!, + buffer, + ); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(state.workspace?.markdown?.mode, MarkdownMode.commonMark); + expect(state.workspace?.markdown?.source, source); + expect( + state.preview?.blocks.map((block) => block.kind), + containsAll([ + PreviewBlockKind.heading, + PreviewBlockKind.paragraph, + PreviewBlockKind.list, + ]), + ); + }), + ); + + test( + 'saving untitled Markdown into discovered topics reclassifies it', + (() async { + final root = await _createWritableWritersideFixture('topic-save'); + addTearDown(() => root.delete(recursive: true)); + final harness = await _createControllerHarness(); + final controller = harness.controller._notifier; + await controller.openPath(root.path); + await controller.createMarkdownFile(); + final bufferId = controller.state.activeBuffer!.id; + controller.updateActiveText('# Newly discovered topic\n'); + final destination = p.join(root.path, 'topics', 'new-topic.md'); + + expect(await controller.saveActiveAs(destination), isTrue); + + final state = controller.state; + expect(state.workspace?.kind, WorkspaceKind.writersideModule); + expect(state.activeBuffer?.id, bufferId); + expect(state.activeBuffer?.filePath, destination); + final resolved = resolveWorkspaceDocumentContext( + state.workspace!, + state.activeBuffer!, + ); + expect(resolved.kind, DocumentKind.writersideMarkdownTopic); + expect(resolved.markdownMode, MarkdownMode.writersideMarkdown); + expect(state.workspace?.markdown?.mode, MarkdownMode.writersideMarkdown); + }), + ); + test( 'saving multiple untitled documents creates normal file buffers', () async { @@ -2443,6 +2785,78 @@ void main() { expect(await file.readAsString(), '- changed'); }); + test( + 'spelling correction undo and redo restore source and rich selections', + () async { + final directory = await Directory.systemTemp.createTemp( + 'busymark-spelling-history-', + ); + addTearDown(() => directory.delete(recursive: true)); + final file = File(p.join(directory.path, 'note.md')); + await file.writeAsString('mispelled\n'); + final harness = await _createControllerHarness(); + await harness.controller.openPath(file.path); + final controller = harness.controller._notifier; + final buffer = controller.state.activeBuffer!; + controller.updateActiveEditorState( + buffer.editorState.copyWith( + selection: const TextSelection(baseOffset: 0, extentOffset: 9), + ), + ); + const beforeRich = WysiwygEditorSessionState( + activeBlockId: 'before-block', + anchorBlockId: 'before-block', + anchorOffset: 0, + extentBlockId: 'before-block', + extentOffset: 9, + ); + const afterRich = WysiwygEditorSessionState( + activeBlockId: 'after-block', + anchorBlockId: 'after-block', + anchorOffset: 10, + extentBlockId: 'after-block', + extentOffset: 10, + ); + final correctedDocument = const MarkdownParser() + .parse(filePath: file.path, source: 'misspelled\n') + .busyDocument; + + controller.updateActiveWysiwygText( + 'misspelled\n', + document: correctedDocument, + sourceFilePath: file.path, + previousWysiwygState: beforeRich, + wysiwygState: afterRich, + ); + expect( + controller.state.activeBuffer!.editorState.undoState.undo, + hasLength(1), + ); + expect( + controller.state.activeBuffer!.editorState.wysiwygState, + afterRich, + ); + + expect(controller.undoActiveBuffer(), isTrue); + expect(controller.state.activeText, 'mispelled\n'); + expect( + controller.state.activeBuffer!.editorState.selection, + const TextSelection(baseOffset: 0, extentOffset: 9), + ); + expect( + controller.state.activeBuffer!.editorState.wysiwygState, + beforeRich, + ); + + expect(controller.redoActiveBuffer(), isTrue); + expect(controller.state.activeText, 'misspelled\n'); + expect( + controller.state.activeBuffer!.editorState.wysiwygState, + afterRich, + ); + }, + ); + test( 'Keep Mine retains the conflict snapshot until explicit overwrite', () async { @@ -3325,6 +3739,78 @@ void main() { }, ); + for (final recoveredActive in [true, false]) { + test('Writerside session restores recovered untitled CommonMark ' + '${recoveredActive ? 'active' : 'inactive'}', () async { + final root = Directory('test/fixtures/writerside/basic_project').absolute; + final topicPath = p.join(root.path, 'topics', 'intro.md'); + const recoveredId = 'recovered-untitled'; + const topicId = 'restored-topic'; + const recoveredText = '# Recovered heading\n\nRecovered *text*.\n'; + final recoveredBuffer = DocumentBuffer.untitled( + id: recoveredId, + name: 'Recovered draft', + text: recoveredText, + ); + final sessionStore = MemoryDocumentSessionStore() + ..value = WorkspaceSessionSnapshot( + workspacePath: root.path, + activeBufferId: recoveredActive ? recoveredId : topicId, + tabs: [ + DocumentSessionEntry( + id: topicId, + filePath: topicPath, + untitledName: null, + editorState: const DocumentEditorState(), + ), + const DocumentSessionEntry( + id: recoveredId, + filePath: null, + untitledName: 'Recovered draft', + editorState: DocumentEditorState(), + ), + ], + ); + final recoveryStore = MemoryDocumentRecoveryStore() + ..value = RecoverySnapshot( + cleanShutdown: false, + entries: [ + DocumentRecoveryEntry.fromBuffer( + recoveredBuffer, + workspacePath: root.path, + ), + ], + ); + final harness = await _createControllerHarness( + sessionStore: sessionStore, + recoveryStore: recoveryStore, + ); + final controller = harness.controller._notifier; + + expect(await controller.restorePreviousSession(), isTrue); + expect(controller.state.workspace?.kind, WorkspaceKind.writersideModule); + expect(controller.state.workspace?.writersideProject, isNotNull); + if (!recoveredActive) { + expect(controller.state.activeBuffer?.id, topicId); + expect(await controller.activateDocumentBuffer(recoveredId), isTrue); + } + final state = controller.state; + expect(state.activeBuffer?.id, recoveredId); + expect(state.activeBuffer?.text, recoveredText); + final resolved = resolveWorkspaceDocumentContext( + state.workspace!, + state.activeBuffer!, + ); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(state.workspace?.markdown?.mode, MarkdownMode.commonMark); + expect( + state.preview?.blocks.any((block) => block.text == 'Recovered heading'), + isTrue, + ); + }); + } + test('clean marker cannot hide remaining recovery entries', () async { final recoveryStore = MemoryDocumentRecoveryStore(); final sessionStore = MemoryDocumentSessionStore(); @@ -3442,6 +3928,23 @@ void main() { ); } +Future _createWritableWritersideFixture(String suffix) async { + final root = await Directory.systemTemp.createTemp( + 'busymark-writerside-$suffix-', + ); + final topics = Directory(p.join(root.path, 'topics')); + await topics.create(); + await File(p.join(root.path, 'writerside.cfg')).writeAsString( + '', + ); + await File(p.join(root.path, 'guide.tree')).writeAsString( + '' + '', + ); + await File(p.join(topics.path, 'intro.md')).writeAsString('# Intro\n'); + return root; +} + Future _waitFor(bool Function() condition) async { final deadline = DateTime.now().add(const Duration(seconds: 3)); while (!condition()) { @@ -3826,24 +4329,70 @@ class _PreviewTrackingWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) { reparseCount++; - return super.reparseActive(workspace, source); + return super.reparseDocument(workspace, buffer); } @override - PreviewDocument? buildPreview(Workspace workspace, String source) { + PreviewDocument? buildDocumentPreview( + Workspace workspace, + DocumentBuffer buffer, + ) { synchronousPreviewBuildCount++; - return super.buildPreview(workspace, source); + return super.buildDocumentPreview(workspace, buffer); } @override - Future buildPreviewAsync( + Future buildDocumentPreviewAsync( Workspace workspace, - String source, + DocumentBuffer buffer, ) { asyncPreviewBuildCount++; - return super.buildPreviewAsync(workspace, source); + return super.buildDocumentPreviewAsync(workspace, buffer); + } +} + +class _BlockingUntitledPreviewWorkspaceService extends WorkspaceService { + final started = Completer(); + final finished = Completer(); + final _release = Completer(); + String? _blockedBufferId; + + void blockNext(String bufferId) => _blockedBufferId = bufferId; + + void release() { + if (!_release.isCompleted) _release.complete(); + } + + @override + Future buildDocumentPreviewAsync( + Workspace workspace, + DocumentBuffer buffer, + ) async { + final preview = await super.buildDocumentPreviewAsync(workspace, buffer); + if (_blockedBufferId != buffer.id) return preview; + _blockedBufferId = null; + if (!started.isCompleted) started.complete(); + await _release.future; + if (!finished.isCompleted) finished.complete(); + return preview; + } +} + +class _RecordingDocumentSourcesWorkspaceService extends WorkspaceService { + Map lastSources = const {}; + + @override + Future withDocumentSources( + Workspace workspace, + Map sources, + ) { + lastSources = Map.unmodifiable(sources); + return super.withDocumentSources(workspace, sources); } } @@ -3932,7 +4481,10 @@ class _AutosaveWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { return workspace.copyWith(diagnostics: const []); } @@ -3950,13 +4502,16 @@ class _ClosingAutosaveWorkspaceService extends _AutosaveWorkspaceService { final releaseActivation = Completer(); @override - Future reparseActive(Workspace workspace, String source) async { - if (pauseActivation && workspace.activeFilePath == bPath) { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + if (pauseActivation && buffer.filePath == bPath) { pauseActivation = false; activationStarted.complete(); await releaseActivation.future; } - return super.reparseActive(workspace, source); + return super.reparseDocument(workspace, buffer); } } @@ -4052,8 +4607,11 @@ class _DelayedValidationWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { - if (!_pausedValidation && source == '# Dirty A\n') { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + if (!_pausedValidation && buffer.text == '# Dirty A\n') { _pausedValidation = true; validationStarted.complete(); await _finishValidation.future; @@ -4180,8 +4738,11 @@ class _BlockingRefreshWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { - final reparsed = await super.reparseActive(workspace, source); + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { + final reparsed = await super.reparseDocument(workspace, buffer); if (_pauseReparse) { _pauseReparse = false; if (!reparseStarted.isCompleted) reparseStarted.complete(); diff --git a/test/src/workspace_document_context_test.dart b/test/src/workspace_document_context_test.dart new file mode 100644 index 00000000..b3318029 --- /dev/null +++ b/test/src/workspace_document_context_test.dart @@ -0,0 +1,118 @@ +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; +import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:busymark/src/workspace/workspace_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +void main() { + DocumentBuffer untitled(String id) => + DocumentBuffer.untitled(id: id, name: id); + + Workspace workspace(WorkspaceKind kind) => Workspace( + id: 'workspace:${kind.name}', + rootPath: '/workspace', + kind: kind, + openedAt: DateTime(2026), + files: const [], + diagnostics: const [], + ); + + for (final kind in WorkspaceKind.values) { + test('untitled buffer is CommonMark in ${kind.name}', () { + final resolved = resolveWorkspaceDocumentContext( + workspace(kind), + untitled('untitled:${kind.name}'), + ); + + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(resolved.diskPath, isNull); + expect(resolved.parserPath, isEmpty); + }); + } + + group('Writerside document resolution', () { + late Workspace writerside; + + setUpAll(() async { + writerside = await const WorkspaceService().openPath( + 'test/fixtures/writerside/basic_project', + ); + }); + + test('discovered Markdown topic wins over generic file inventory', () { + final topic = writerside.writersideModule!.topics.singleWhere( + (topic) => topic.filePath.endsWith('intro.md'), + ); + final inventory = writerside.files.singleWhere( + (file) => p.equals(file.absolutePath, topic.filePath), + ); + final buffer = DocumentBuffer( + id: 'intro', + filePath: topic.filePath, + text: topic.document.source, + lastSavedText: topic.document.source, + dirty: false, + ); + + expect(inventory.kind, DocumentKind.markdown); + final resolved = resolveWorkspaceDocumentContext(writerside, buffer); + expect(resolved.kind, DocumentKind.writersideMarkdownTopic); + expect(resolved.markdownMode, MarkdownMode.writersideMarkdown); + expect(resolved.writersideTopic, same(topic)); + }); + + test('discovered XML topic resolves as a Writerside XML topic', () { + final topic = writerside.writersideModule!.topics.singleWhere( + (topic) => topic.filePath.endsWith('install.topic'), + ); + final buffer = DocumentBuffer( + id: 'install', + filePath: topic.filePath, + text: topic.document.source, + lastSavedText: topic.document.source, + dirty: false, + ); + + final resolved = resolveWorkspaceDocumentContext(writerside, buffer); + expect(resolved.kind, DocumentKind.writersideXmlTopic); + expect(resolved.writersideTopic, same(topic)); + }); + + test('ordinary Markdown under the project is still CommonMark', () { + final path = p.join(writerside.rootPath, 'notes', 'draft.md'); + final buffer = DocumentBuffer( + id: 'ordinary', + filePath: path, + text: '# Notes\n', + lastSavedText: '# Notes\n', + dirty: false, + ); + + final resolved = resolveWorkspaceDocumentContext(writerside, buffer); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + expect(resolved.writersideTopic, isNull); + }); + + test('path fallback does not depend on workspace file inventory', () { + final path = p.join(writerside.rootPath, 'newly-saved.markdown'); + expect( + writerside.files.any((file) => p.equals(file.absolutePath, path)), + isFalse, + ); + final buffer = DocumentBuffer( + id: 'newly-saved', + filePath: path, + text: '# Saved\n', + lastSavedText: '# Saved\n', + dirty: false, + ); + + final resolved = resolveWorkspaceDocumentContext(writerside, buffer); + expect(resolved.kind, DocumentKind.markdown); + expect(resolved.markdownMode, MarkdownMode.commonMark); + }); + }); +} diff --git a/test/src/workspace_safety_test.dart b/test/src/workspace_safety_test.dart index e05276fa..237d1654 100644 --- a/test/src/workspace_safety_test.dart +++ b/test/src/workspace_safety_test.dart @@ -6,6 +6,7 @@ import 'package:busymark/src/app/app_settings.dart'; import 'package:busymark/src/app/app_theme.dart'; import 'package:busymark/src/app/busymark_design.dart'; import 'package:busymark/src/app/busymark_glyphs.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_controller.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_safety.dart'; @@ -1152,7 +1153,10 @@ class _IdentityWorkspaceService extends WorkspaceService { } @override - Future reparseActive(Workspace workspace, String source) async { + Future reparseDocument( + Workspace workspace, + DocumentBuffer buffer, + ) async { return workspace; } diff --git a/test/src/workspace_service_test.dart b/test/src/workspace_service_test.dart index c6b7aac5..c938bbbb 100644 --- a/test/src/workspace_service_test.dart +++ b/test/src/workspace_service_test.dart @@ -4,6 +4,8 @@ import 'package:busymark/src/core/busymark_exception.dart'; import 'package:busymark/src/core/path_utils.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/markdown/preview_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_module_service.dart'; @@ -148,6 +150,107 @@ void main() { expect(workspace.activeFilePath, endsWith('intro.md')); }); + test( + 'untitled Markdown in Writerside reparses, previews, and outlines as CommonMark', + () async { + final workspace = await service.openPath( + 'test/fixtures/writerside/basic_project', + ); + const source = '''# Untitled heading + +Normal *emphasized* paragraph. + +- first +- second + +```dart +final answer = 42; +``` +'''; + final buffer = DocumentBuffer.untitled( + id: 'untitled-in-writerside', + name: 'Untitled', + text: source, + ); + + final reparsed = await service.reparseDocument( + workspace.copyWith(activeFilePath: null, markdown: null), + buffer, + ); + + expect(reparsed.kind, WorkspaceKind.writersideModule); + expect(reparsed.markdown?.mode, MarkdownMode.commonMark); + expect(reparsed.markdown?.source, source); + expect( + reparsed.markdown?.headings.map((heading) => heading.text), + contains('Untitled heading'), + ); + + void expectMarkdownPreview(PreviewDocument? preview) { + expect(preview, isNotNull); + final blocks = preview!.blocks; + expect( + blocks.map((block) => block.kind), + containsAll([ + PreviewBlockKind.heading, + PreviewBlockKind.paragraph, + PreviewBlockKind.list, + PreviewBlockKind.code, + ]), + ); + expect( + blocks.where((block) => block.kind == PreviewBlockKind.code), + hasLength(1), + ); + expect(blocks, isNot(hasLength(1))); + } + + expectMarkdownPreview(service.buildDocumentPreview(reparsed, buffer)); + expectMarkdownPreview( + await service.buildDocumentPreviewAsync(reparsed, buffer), + ); + final outline = service.documentOutline(reparsed, buffer); + expect(outline.map((heading) => heading.text), ['Untitled heading']); + expect( + outline.map((heading) => heading.text), + isNot(contains('Introduction')), + ); + }, + ); + + test( + 'genuine Writerside Markdown topic keeps Writerside semantics', + () async { + final workspace = await service.openPath( + 'test/fixtures/writerside/basic_project', + ); + final topic = workspace.writersideModule!.topics.singleWhere( + (topic) => topic.filePath.endsWith('intro.md'), + ); + final source = await File(topic.filePath).readAsString(); + final buffer = DocumentBuffer( + id: 'writerside-intro', + filePath: topic.filePath, + text: source, + lastSavedText: source, + dirty: false, + ); + + final reparsed = await service.reparseDocument(workspace, buffer); + final preview = service.buildDocumentPreview(reparsed, buffer); + + expect(reparsed.markdown?.mode, MarkdownMode.writersideMarkdown); + expect( + resolveWorkspaceDocumentContext(reparsed, buffer).kind, + DocumentKind.writersideMarkdownTopic, + ); + expect( + preview?.blocks.map((block) => block.kind), + contains(PreviewBlockKind.admonition), + ); + }, + ); + test('creates and opens a Writerside starter project', () async { final parent = await Directory.systemTemp.createTemp( 'busymark-workspace-create-', @@ -227,14 +330,16 @@ void main() { ); final workspace = await parserService.openPath(root.path); - final reparsed = await parserService.reparseActive( - workspace, - activeFile.readAsStringSync(), - ); - final preview = parserService.buildPreview( - workspace, - activeFile.readAsStringSync(), + final source = activeFile.readAsStringSync(); + final buffer = DocumentBuffer( + id: 'writerside-links', + filePath: workspace.activeFilePath, + text: source, + lastSavedText: source, + dirty: false, ); + final reparsed = await parserService.reparseDocument(workspace, buffer); + final preview = parserService.buildDocumentPreview(workspace, buffer); expect(parser.validationFlags, isNotEmpty); expect(parser.validationFlags, everyElement(isFalse)); diff --git a/test/src/writerside_admonition_test.dart b/test/src/writerside_admonition_test.dart index e1310692..b3c7d66a 100644 --- a/test/src/writerside_admonition_test.dart +++ b/test/src/writerside_admonition_test.dart @@ -11,6 +11,7 @@ import 'package:busymark/src/markdown/busymark_markdown_serializer.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/markdown/preview_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -307,10 +308,15 @@ Helpful advice. const service = WorkspaceService(); final workspace = await service.openPath(root.path); - final preview = service.buildPreview( - workspace.copyWith(activeFilePath: topicPath), - source, - )!; + final targetWorkspace = workspace.copyWith(activeFilePath: topicPath); + final target = DocumentBuffer( + id: 'admonitions', + filePath: topicPath, + text: source, + lastSavedText: source, + dirty: false, + ); + final preview = service.buildDocumentPreview(targetWorkspace, target)!; final callouts = preview.blocks.where( (block) => block.kind == PreviewBlockKind.admonition || diff --git a/test/src/writerside_collapsible_test.dart b/test/src/writerside_collapsible_test.dart index 024732d5..1770aca0 100644 --- a/test/src/writerside_collapsible_test.dart +++ b/test/src/writerside_collapsible_test.dart @@ -8,6 +8,7 @@ import 'package:busymark/src/markdown/busymark_markdown_serializer.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/markdown/preview_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -273,10 +274,15 @@ fun main() = Unit const service = WorkspaceService(); final workspace = await service.openPath(root.path); - final preview = service.buildPreview( - workspace.copyWith(activeFilePath: topicPath), - source, - )!; + final targetWorkspace = workspace.copyWith(activeFilePath: topicPath); + final target = DocumentBuffer( + id: 'collapse', + filePath: topicPath, + text: source, + lastSavedText: source, + dirty: false, + ); + final preview = service.buildDocumentPreview(targetWorkspace, target)!; final collapsibles = preview.blocks.where( (block) => busyMarkWritersideIsCollapsible(block.attributes), ); diff --git a/test/src/writerside_math_diagram_test.dart b/test/src/writerside_math_diagram_test.dart index 1f32f998..f22722a8 100644 --- a/test/src/writerside_math_diagram_test.dart +++ b/test/src/writerside_math_diagram_test.dart @@ -7,6 +7,7 @@ import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/markdown/math_syntax.dart'; import 'package:busymark/src/markdown/preview_model.dart'; import 'package:busymark/src/visualization/visualization_models.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_diagram_source_loader.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -334,10 +335,15 @@ C -> D A --> B '''; - final preview = service.buildPreview( - workspace.copyWith(activeFilePath: topicPath), - source, - )!; + final targetWorkspace = workspace.copyWith(activeFilePath: topicPath); + final target = DocumentBuffer( + id: 'math-topic', + filePath: topicPath, + text: source, + lastSavedText: source, + dirty: false, + ); + final preview = service.buildDocumentPreview(targetWorkspace, target)!; final math = preview.blocks.singleWhere( (block) => block.kind == PreviewBlockKind.math, diff --git a/test/src/writerside_project_test.dart b/test/src/writerside_project_test.dart index 99f2a6f4..309621ed 100644 --- a/test/src/writerside_project_test.dart +++ b/test/src/writerside_project_test.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:convert'; import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/core/diagnostic.dart'; import 'package:busymark/src/editor/source/source_autocomplete.dart'; @@ -14,6 +15,16 @@ import 'package:busymark/src/writerside/writerside_project.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; +DocumentBuffer _documentBuffer(Workspace workspace, String source) { + return DocumentBuffer( + id: 'test:${workspace.activeFilePath ?? 'untitled'}', + filePath: workspace.activeFilePath, + text: source, + lastSavedText: source, + dirty: true, + ); +} + void main() { test( 'discovers modules, indexes symbols, and resolves origin references', @@ -267,13 +278,16 @@ void main() { isNotEmpty, ); - final reparsed = await service.reparseActive(workspace, ''' + final reparsed = await service.reparseDocument( + workspace, + _documentBuffer(workspace, '''

Indexed while unsaved.

-'''); +'''), + ); final project = reparsed.writersideProject!; final moduleId = project.activeModuleId; final topicNames = project.index.names( @@ -361,9 +375,12 @@ void main() { markdown: null, diagnostics: [...workspace.diagnostics, scanDiagnostic], ); - final reparsed = await service.reparseActive( + final reparsed = await service.reparseDocument( variableWorkspace, - '', + _documentBuffer( + variableWorkspace, + '', + ), ); final project = reparsed.writersideProject!; final module = reparsed.writersideModule!; @@ -443,12 +460,15 @@ void main() { markdown: null, ); - final reparsed = await service.reparseActive(treeWorkspace, ''' + final reparsed = await service.reparseDocument( + treeWorkspace, + _documentBuffer(treeWorkspace, ''' -'''); +'''), + ); final project = reparsed.writersideProject!; expect(reparsed.writersideModule?.instances.single.id, 'live-guide'); diff --git a/test/src/writerside_template_dialogs_test.dart b/test/src/writerside_template_dialogs_test.dart index f2fb7a03..8b2bde75 100644 --- a/test/src/writerside_template_dialogs_test.dart +++ b/test/src/writerside_template_dialogs_test.dart @@ -134,7 +134,34 @@ void main() { 1, ), ); + final markdown = tester.widget>( + find.byKey(const ValueKey('template-format-md')), + ); + final xml = tester.widget>( + find.byKey(const ValueKey('template-format-topic')), + ); + expect(markdown.value, 'md'); + expect(xml.value, 'topic'); + expect(markdown.groupValue, 'md'); + expect(xml.groupValue, 'md'); await tester.tap(find.text('XML (.topic)')); + await tester.pump(); + expect( + tester + .widget>( + find.byKey(const ValueKey('template-format-md')), + ) + .groupValue, + 'topic', + ); + expect( + tester + .widget>( + find.byKey(const ValueKey('template-format-topic')), + ) + .groupValue, + 'topic', + ); await tester.enterText(editableUnderKey('template-title'), 'A & B'); await tester.enterText( editableUnderKey('template-filename'), @@ -183,7 +210,14 @@ void main() { expect(find.byType(YaruMasterTile), findsWidgets); expect(find.byType(BusyMarkGroupedTextEntry), findsNWidgets(2)); expect(find.byType(BusyMarkActionRow), findsOneWidget); - expect(find.byType(YaruRadioButton), findsNWidgets(2)); + expect(find.byType(BusyMarkRadioButton), findsNWidgets(2)); + expect( + find.descendant( + of: find.byType(BusyMarkRadioButton), + matching: find.byType(YaruRadioButton), + ), + findsNWidgets(2), + ); expect(find.byType(BusyMarkSidebarSurface), findsOneWidget); final formatTile = tester.widget( find.byKey(const ValueKey('template-format')), @@ -226,6 +260,34 @@ void main() { .text, 'Overview', ); + + await tester.enterText( + editableUnderKey('template-search'), + 'API quickstart', + ); + await tester.pumpAndSettle(); + final markdownOnlyTile = find.byKey( + const ValueKey('template-api-quickstart/template_api-quickstart.md'), + ); + expect(markdownOnlyTile, findsOneWidget); + await tester.tap(markdownOnlyTile); + await tester.pumpAndSettle(); + expect( + tester + .widget>( + find.byKey(const ValueKey('template-format-md')), + ) + .onChanged, + isNotNull, + ); + expect( + tester + .widget>( + find.byKey(const ValueKey('template-format-topic')), + ) + .onChanged, + isNull, + ); }); testWidgets('creation opens both template editor entry points', ( diff --git a/test/src/writerside_test.dart b/test/src/writerside_test.dart index 76317b9b..8286b4a2 100644 --- a/test/src/writerside_test.dart +++ b/test/src/writerside_test.dart @@ -5,6 +5,7 @@ import 'package:busymark/src/core/diagnostic.dart'; import 'package:busymark/src/core/path_utils.dart'; import 'package:busymark/src/markdown/preview_model.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_document.dart'; import 'package:busymark/src/writerside/writerside_module_service.dart'; @@ -252,9 +253,17 @@ void main() { p.absolute('test/fixtures/writerside/basic_project/topics/math.topic'), ); final source = File(topicPath).readAsStringSync(); - final preview = workspaceService.buildPreview( - workspace.copyWith(activeFilePath: topicPath), - source, + final targetWorkspace = workspace.copyWith(activeFilePath: topicPath); + final target = DocumentBuffer( + id: 'math-topic', + filePath: topicPath, + text: source, + lastSavedText: source, + dirty: false, + ); + final preview = workspaceService.buildDocumentPreview( + targetWorkspace, + target, ); final math = preview!.blocks diff --git a/test/src/writerside_video_test.dart b/test/src/writerside_video_test.dart index 4efd3b52..f06e4e9f 100644 --- a/test/src/writerside_video_test.dart +++ b/test/src/writerside_video_test.dart @@ -10,6 +10,7 @@ import 'package:busymark/src/markdown/preview_model.dart'; import 'package:busymark/src/writerside/writerside_parsers.dart'; import 'package:busymark/src/writerside/writerside_module_service.dart'; import 'package:busymark/src/writerside/writerside_video.dart'; +import 'package:busymark/src/workspace/document_buffer.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; @@ -178,10 +179,15 @@ After. const service = WorkspaceService(); final workspace = await service.openPath(root.path); - final preview = service.buildPreview( - workspace.copyWith(activeFilePath: topicPath), - source, + final targetWorkspace = workspace.copyWith(activeFilePath: topicPath); + final target = DocumentBuffer( + id: 'video-topic', + filePath: topicPath, + text: source, + lastSavedText: source, + dirty: false, ); + final preview = service.buildDocumentPreview(targetWorkspace, target); final video = preview!.blocks.singleWhere( (block) => block.kind == PreviewBlockKind.video, ); diff --git a/test/src/wysiwyg_ai_test.dart b/test/src/wysiwyg_ai_test.dart index 567f34c0..af3b15f0 100644 --- a/test/src/wysiwyg_ai_test.dart +++ b/test/src/wysiwyg_ai_test.dart @@ -9,6 +9,7 @@ import 'package:busymark/src/markdown/busymark_document.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/platform/native_menu_service.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -216,6 +217,7 @@ void main() { home: Scaffold( body: BusyMarkWysiwygEditor( document: document, + clipboardService: _AiClipboard(), visualizationRevision: 5, onSourceChanged: (_, value) => changedSource = value, onAiEdit: (snapshot) async { @@ -276,6 +278,9 @@ void main() { if (item.type == ContextMenuButtonType.copy) { expectedSelectionActions.add('Copy Plain Text'); } + if (item.type == ContextMenuButtonType.paste) { + expectedSelectionActions.add('Paste as Plain Text'); + } } expect(paragraph.controller!.selection.isCollapsed, isFalse); @@ -304,6 +309,10 @@ void main() { expect(_nativeShortcut(nativeEntries!, 'Copy'), 'Ctrl+C'); expect(_nativeShortcut(nativeEntries!, 'Copy Plain Text'), 'Ctrl+Shift+C'); expect(_nativeShortcut(nativeEntries!, 'Paste'), 'Ctrl+V'); + expect( + _nativeShortcut(nativeEntries!, 'Paste as Plain Text'), + 'Ctrl+Shift+V', + ); expect(_nativeShortcut(nativeEntries!, 'Select all'), 'Ctrl+A'); expect(_nativeShortcut(nativeEntries!, 'Refine with AI'), 'Ctrl+G'); expect(_nativeIcon(nativeEntries!, 'Cut'), 'edit-cut-symbolic'); @@ -313,6 +322,10 @@ void main() { 'edit-copy-symbolic', ); expect(_nativeIcon(nativeEntries!, 'Paste'), 'edit-paste-symbolic'); + expect( + _nativeIcon(nativeEntries!, 'Paste as Plain Text'), + 'edit-paste-symbolic', + ); expect( _nativeIcon(nativeEntries!, 'Select all'), 'edit-select-all-symbolic', @@ -333,6 +346,14 @@ String? _nativeShortcut(List> entries, String label) { as String?; } +class _AiClipboard extends RichClipboardService { + _AiClipboard() : super(channel: const MethodChannel('busymark.test/ai')); + + @override + Future read() async => + const RichClipboardData(text: 'Paste', generation: 1); +} + String? _nativeIcon(List> entries, String label) { return entries.singleWhere((entry) => entry['label'] == label)['icon'] as String?; diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index deb409af..4e45703a 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -7,7 +7,9 @@ import 'package:busymark/src/app/app_settings.dart'; import 'package:busymark/src/assets/asset_ingestion_service.dart'; import 'package:busymark/src/assets/asset_input_service.dart'; import 'package:busymark/src/app/busymark_design.dart'; +import 'package:busymark/src/app/busymark_toast.dart'; import 'package:busymark/src/clipboard/clipboard_history_controller.dart'; +import 'package:busymark/src/clipboard/clipboard_history_panel.dart'; import 'package:busymark/src/clipboard/clipboard_insertion.dart'; import 'package:busymark/src/clipboard/clipboard_models.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; @@ -15,17 +17,23 @@ import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_session_state.dart'; import 'package:busymark/src/editor/writerside_video_player_host.dart'; import 'package:busymark/src/markdown/busymark_document.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/platform/native_menu_service.dart'; import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:busymark/src/visualization/visualization_providers.dart'; +import 'package:busymark/src/visualization/visualization_renderer.dart'; +import 'package:busymark/src/visualization/web_render_host.dart'; import 'package:flutter/material.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; const _source = '# Issues\n\n**When** selecting all, keep *formatting*.\n\n- [ ] First task\n- [x] Second task\n'; @@ -100,6 +108,65 @@ void main() { }, ); + test('single rich paragraphs preserve list descendants through source', () { + final incoming = _fragment('**X**\n').blocks; + final cases = <({String source, BusyBlockKind kind})>[ + ( + source: '- Parent\n - Child\n - Grand\n', + kind: BusyBlockKind.unorderedListItem, + ), + ( + source: '1. Parent\n 1. Child\n 1. Grand\n', + kind: BusyBlockKind.orderedListItem, + ), + ( + source: '- [ ] Parent\n - [x] Child\n - Grand\n', + kind: BusyBlockKind.taskListItem, + ), + ]; + final selections = <({int start, int end, String text})>[ + (start: 0, end: 6, text: 'X'), + (start: 1, end: 5, text: 'PXt'), + (start: 3, end: 3, text: 'ParXent'), + ]; + + for (final value in cases) { + for (final selection in selections) { + final document = _parser + .parse(filePath: '/destination.md', source: value.source) + .busyDocument; + final controller = BusyMarkWysiwygDocumentController( + document: document, + ); + addTearDown(controller.dispose); + final root = document.blocks.single; + + final result = controller.insertStyledBlocksAtSelection( + blockId: root.id, + selectionStart: selection.start, + selectionEnd: selection.end, + blocks: incoming, + ); + + expect(result, isNotNull); + final live = controller.document.blocks.single; + expect(live.kind, value.kind); + expect(live.plainText, selection.text); + expect(live.children.single.plainText, 'Child'); + expect(live.children.single.children.single.plainText, 'Grand'); + final reparsed = _parser + .parse(filePath: '/destination.md', source: controller.markdown) + .busyDocument + .blocks + .single; + expect(reparsed.kind, value.kind, reason: controller.markdown); + expect(reparsed.plainText, selection.text, reason: controller.markdown); + expect(reparsed.children.single.plainText, 'Child'); + expect(reparsed.children.single.children.single.plainText, 'Grand'); + } + } + }); + test( 'fragment rejects invalid versions, ranges, kinds, and excessive nesting', () { @@ -281,6 +348,26 @@ void main() { expect(_insert(decoded), contains('- [x] Second task')); }); + test('external HTML blockquotes survive Editor serialization', () { + for (final htmlSource in [ + '

Quoted

', + '

Nested

', + '
  • Listed
', + ]) { + final fragment = const WysiwygClipboardHtml().decode( + htmlSource, + mode: MarkdownMode.commonMark, + ); + expect(fragment, isNotNull); + final output = _insert(fragment!); + final parsed = _parser + .parse(filePath: '/quote.md', source: output) + .busyDocument; + expect(parsed.blocks.single.kind, BusyBlockKind.blockquote); + expect(parsed.blocks.single.children, isNotEmpty, reason: output); + } + }); + test('clipboard fragment serializes its selected structure as Markdown', () { final markdown = _fragment(_source).markdown; expect(markdown, contains('# Issues')); @@ -324,6 +411,7 @@ void main() { late Completer? readGate; late Completer? writeGate; late bool failWrite; + late int readCalls; const channel = MethodChannel(richClipboardChannelName); const videoChannel = MethodChannel(writersideVideoPlayerChannelName); setUp(() { @@ -331,6 +419,7 @@ void main() { readGate = null; writeGate = null; failWrite = false; + readCalls = 0; final messenger = TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; messenger.setMockMethodCallHandler(channel, (call) async { @@ -341,6 +430,7 @@ void main() { return true; } if (call.method == 'read') { + readCalls++; await readGate?.future; return Map.from(systemData); } @@ -391,32 +481,62 @@ void main() { String? filePath, String? workspaceRoot, AssetWorkspaceKind? assetWorkspaceKind, + AssetInputService? assetInputService, + AssetIngestionService assetIngestionService = + const AssetIngestionService(), + BusyMarkWysiwygTransactionalSourceChanged? onTransactionalSourceChanged, + bool useExternalUndoHistory = false, + bool hostToasts = false, + bool providerScope = false, + bool focusFirstField = true, + WysiwygEditorSessionState Function(BusyDocument document)? + initialSessionFor, }) async { - await tester.pumpWidget( - MaterialApp( - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - home: Scaffold( - body: BusyMarkWysiwygEditor( - key: ValueKey(id), - clipboardService: RichClipboardService(), - clipboardInsertionRegistry: registry, - onClipboardCaptured: onCaptured, - workspaceRoot: workspaceRoot, - assetWorkspaceKind: assetWorkspaceKind, - document: _parser - .parse( - filePath: filePath ?? '/$id.md', - source: source, - mode: MarkdownMode.writersideMarkdown, - ) - .busyDocument, - onSourceChanged: (_, value) => changed(value), - ), + final document = _parser + .parse( + filePath: filePath ?? '/$id.md', + source: source, + mode: MarkdownMode.writersideMarkdown, + ) + .busyDocument; + final app = MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + builder: hostToasts + ? (context, child) => BusyMarkToastOverlay(child: child!) + : null, + home: Scaffold( + body: BusyMarkWysiwygEditor( + key: ValueKey(id), + clipboardService: RichClipboardService(), + clipboardInsertionRegistry: registry, + onClipboardCaptured: onCaptured, + workspaceRoot: workspaceRoot, + assetWorkspaceKind: assetWorkspaceKind, + assetInputService: assetInputService, + assetIngestionService: assetIngestionService, + onTransactionalSourceChanged: onTransactionalSourceChanged, + useExternalUndoHistory: useExternalUndoHistory, + initialSessionState: + initialSessionFor?.call(document) ?? + const WysiwygEditorSessionState(), + document: document, + onSourceChanged: (_, value) => changed(value), ), ), ); + await tester.pumpWidget( + providerScope + ? ProviderScope( + overrides: [ + webRenderHostProvider.overrideWithValue(_ClipboardMathHost()), + ], + child: app, + ) + : app, + ); await tester.pumpAndSettle(); + if (!focusFirstField) return; final field = tester.widget(find.byType(TextField).first); field.focusNode!.requestFocus(); field.controller!.selection = const TextSelection.collapsed(offset: 0); @@ -450,550 +570,2378 @@ void main() { expect(result, contains('**When**')); }); - testWidgets('copy all does not duplicate nested list children', ( + testWidgets('Editor pastes a web layout table as a complete document', ( tester, ) async { - await copyAll( - tester, - source: 'Before\n\n- Parent\n - **Child**\n\nAfter\n', - ); - var result = ''; - await mount(tester, 'destination', 'Target\n', (value) => result = value); + systemData = { + 'html': File( + 'test/fixtures/clipboard/layout_table_job.html', + ).readAsStringSync(), + 'text': 'Plain job description', + }; + var result = 'Target\n'; + await mount(tester, 'layout-table', result, (value) => result = value); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(RegExp('Child').allMatches(result), hasLength(1)); - expect(result, contains(' - **Child**')); - }); - - testWidgets('whole-document copy preserves a structured blockquote', ( - tester, - ) async { - await copyAll( - tester, - source: 'Before\n\n> First\n>\n> **Second**\n\nAfter\n', + await tester.pumpAndSettle(); + final document = _parser + .parse(filePath: '/pasted.md', source: result) + .busyDocument; + expect(document.blocks.first.kind, BusyBlockKind.heading); + expect( + document.blocks.where((block) => block.kind == BusyBlockKind.table), + hasLength(1), ); - var result = ''; - await mount(tester, 'destination', 'Target\n', (value) => result = value); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('> First')); - expect(result, contains('> **Second**')); - expect(RegExp('Second').allMatches(result), hasLength(1)); + expect( + document.blocks.where( + (block) => block.kind == BusyBlockKind.unorderedListItem, + ), + hasLength(3), + ); + expect( + document.blocks.last.plainText, + 'Send questions to team@example.test.', + ); + expect(result, contains('Closing invitation with [application details]')); + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, 'Target\n'); + await key(tester, LogicalKeyboardKey.keyV, shift: true); + expect(result.trim(), 'Plain job description'); }); - testWidgets('right-click opens the menu for a whole-document selection', ( - tester, - ) async { - await mount(tester, 'issues', _source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); + testWidgets( + 'complete heading list and code blocks retain structure at every paragraph position', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final cases = <({String source, BusyBlockKind kind, String text})>[ + ( + source: '## Heading\n', + kind: BusyBlockKind.heading, + text: 'Heading', + ), + ( + source: '- Item\n', + kind: BusyBlockKind.unorderedListItem, + text: 'Item', + ), + ( + source: '```text\ncode\n```\n', + kind: BusyBlockKind.codeBlock, + text: 'code', + ), + ]; + for (final blockCase in cases) { + final fragment = _fragment(blockCase.source); + for (final position in [0, 4, 9]) { + var result = 'leftright\n'; + await mount( + tester, + '${blockCase.kind.name}-$position', + result, + (value) => result = value, + registry: registry, + ); + final field = tester.widget( + find.byType(TextField).first, + ); + field.controller!.selection = TextSelection.collapsed( + offset: position, + ); - await tester.tap( - find.widgetWithText(TextField, 'When selecting all, keep formatting.'), - buttons: kSecondaryMouseButton, - ); - await tester.pumpAndSettle(); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: '${blockCase.kind.name}-$position', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: blockCase.text, + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pump(); - for (final label in [ - 'Cut', - 'Copy', - 'Copy Plain Text', - 'Paste', - 'Select all', - ]) { - expect( - find.byWidgetPredicate( - (widget) => - widget is BusyMarkPopupMenuItem && widget.label == label, - ), - findsOneWidget, - ); - } - await tester.tap(find.text('Copy')); - await tester.pumpAndSettle(); - expect(systemData.keys, containsAll(['text', 'html', 'token'])); - expect(systemData, isNot(contains('fragment'))); - expect(systemData['text'], contains('[ ] First task')); - }); + final parsed = _parser + .parse( + filePath: '/destination.md', + source: result, + mode: MarkdownMode.writersideMarkdown, + validateLocalReferences: false, + ) + .busyDocument; + expect( + parsed.blocks.where((block) => block.kind == blockCase.kind), + hasLength(1), + reason: + '${blockCase.kind.name} was flattened at paragraph offset $position: $result', + ); + expect( + parsed.blocks + .singleWhere((block) => block.kind == blockCase.kind) + .plainText, + blockCase.text, + ); + expect( + parsed.blocks + .where((block) => block.kind == BusyBlockKind.paragraph) + .map((block) => block.plainText) + .join(), + 'leftright', + ); + } + } + }, + ); - testWidgets('Copy Plain Text strips formatting in another Editor', ( - tester, - ) async { - await mount(tester, 'issues', _source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyC, shift: true); + testWidgets( + 'complete blocks in list items preserve descendants and undo tree', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + const original = '- Parent\n - Child\n'; + for (final insertedSource in [ + '## Heading\n', + '- Inserted\n', + '```text\ncode\n```\n', + ]) { + final fragment = _fragment(insertedSource); + for (final offset in [0, 3, 6]) { + var result = original; + await mount( + tester, + 'nested-${insertedSource.hashCode}-$offset', + result, + (value) => result = value, + registry: registry, + ); + final field = tester.widget( + find.byType(TextField).first, + ); + field.focusNode!.requestFocus(); + field.controller!.selection = TextSelection.collapsed( + offset: offset, + ); - expect(systemData.keys, containsAll(['text', 'token'])); - expect(systemData, isNot(contains('fragment'))); - expect(systemData['text'], startsWith('Issues')); - expect( - systemData['text'], - contains('When selecting all, keep formatting.'), - ); - expect(systemData['text'], contains('[ ] First task')); - expect(systemData['text'], isNot(contains('# Issues'))); - expect(systemData['text'], isNot(contains('**When**'))); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'nested-${insertedSource.hashCode}-$offset', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: insertedSource, + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pump(); - var result = ''; - await mount(tester, 'destination', 'Target\n', (value) => result = value); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('Issues')); - expect(result, contains('When selecting all, keep formatting.')); - expect(result, isNot(contains('# Issues'))); - expect(result, isNot(contains('**When**'))); - expect(result, isNot(contains('- [x] Second task'))); - }); + final parsed = _parser + .parse( + filePath: '/destination.md', + source: result, + validateLocalReferences: false, + ) + .busyDocument; + expect(parsed.blocks, hasLength(1), reason: result); + final root = parsed.blocks.single; + expect(root.kind, BusyBlockKind.unorderedListItem); + expect( + root.children.where((block) => block.plainText == 'Child'), + hasLength(1), + reason: result, + ); + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, original); + } + } + }, + ); - testWidgets('document selection menu can copy plain text', (tester) async { - await mount(tester, 'issues', _source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); - await tester.tap( - find.widgetWithText(TextField, 'When selecting all, keep formatting.'), - buttons: kSecondaryMouseButton, - ); - await tester.pumpAndSettle(); + testWidgets( + 'single rich paragraph field replacement preserves every list subtree', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final fragment = _fragment('**X**\n'); + for (final (index, source) in [ + '- Parent\n - Child\n - Grand\n', + '1. Parent\n 1. Child\n 1. Grand\n', + '- [ ] Parent\n - [x] Child\n - Grand\n', + ].indexed) { + var result = source; + await mount( + tester, + 'single-nested-$index', + result, + (value) => result = value, + registry: registry, + ); + final parent = tester.widget(find.byType(TextField).first); + parent.controller!.selection = const TextSelection( + baseOffset: 0, + extentOffset: 6, + ); - await tester.tap(find.text('Copy Plain Text')); - await tester.pumpAndSettle(); - expect(systemData.keys, containsAll(['text', 'token'])); - expect(systemData, isNot(contains('fragment'))); - expect(systemData['text'], startsWith('Issues')); - expect(systemData['text'], isNot(contains('**When**'))); - }); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'single-nested-payload-$index', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + void expectTree() { + final root = _parser + .parse(filePath: '/nested.md', source: result) + .busyDocument + .blocks + .single; + expect(root.plainText, 'X', reason: result); + expect(root.children.single.plainText, 'Child', reason: result); + expect( + root.children.single.children.single.plainText, + 'Grand', + reason: result, + ); + } + + expectTree(); + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, source); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expectTree(); + } + }, + ); testWidgets( - 'partial inline copy keeps formatting inside another paragraph', + 'history rich paste keeps the committed caret and typing position', (tester) async { - await mount(tester, 'origin', 'A **bold** word\n', (_) {}); - final field = tester.widget(find.byType(TextField).first); - field.controller!.selection = const TextSelection( - baseOffset: 2, - extentOffset: 6, - ); - await key(tester, LogicalKeyboardKey.keyC); - var result = ''; + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var result = 'leftright\n'; await mount( tester, - 'destination', - 'Before after\n', + 'history-rich-caret', + result, (value) => result = value, + registry: registry, ); - tester - .widget(find.byType(TextField).first) - .controller! - .selection = const TextSelection.collapsed( - offset: 7, + var field = tester.widget(find.byType(TextField).first); + field.focusNode!.requestFocus(); + field.controller!.selection = const TextSelection.collapsed(offset: 4); + + final fragment = _fragment('**X**\n'); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'history-rich-caret-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + field = tester + .widgetList(find.byType(TextField)) + .singleWhere( + (candidate) => candidate.controller?.text == 'leftXright', + ); + expect(field.focusNode!.hasFocus, isTrue); + expect( + field.controller!.selection, + const TextSelection.collapsed(offset: 5), + ); + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'leftXYright', + selection: TextSelection.collapsed(offset: 6), + ), + ); + await tester.pump(); + expect(field.controller!.text, 'leftXYright'); + expect( + _parser + .parse(filePath: '/result.md', source: result) + .busyDocument + .blocks + .single + .plainText, + 'leftXYright', ); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, 'Before **bold**after\n'); }, ); - testWidgets('cut transfers formatting before deleting the selection', ( + testWidgets('rich paste in math fields uses source coordinates', ( tester, ) async { - var origin = 'A **bold** word\n'; - await mount(tester, 'origin', origin, (value) => origin = value); - tester - .widget(find.byType(TextField).first) - .controller! - .selection = const TextSelection( - baseOffset: 2, - extentOffset: 6, - ); + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final fragment = _fragment('**X**\n'); + final cases = <({int offset, String expected})>[ + (offset: 2, expected: r'a **X**$x$ b'), + (offset: 3, expected: r'a $**X**x$ b'), + (offset: 5, expected: r'a $x$**X** b'), + ]; + for (final (index, value) in cases.indexed) { + var result = + r'a $x$ b' + '\n'; + await mount( + tester, + 'math-rich-$index', + result, + (source) => result = source, + registry: registry, + providerScope: true, + focusFirstField: false, + ); + final renderedMath = find.byWidgetPredicate( + (widget) => + widget.key is ValueKey && + ((widget.key! as ValueKey).value).startsWith( + 'wysiwyg-rendered-math-', + ), + ); + await tester.tap(renderedMath); + await tester.pump(); + var field = tester.widget(find.byType(TextField).first); + field.controller!.selection = TextSelection.collapsed( + offset: value.offset, + ); - await key(tester, LogicalKeyboardKey.keyX); - expect(origin, 'A word\n'); - expect(systemData.keys, containsAll(['text', 'html', 'token'])); - expect(systemData, isNot(contains('fragment'))); - expect(systemData['text'], 'bold'); - expect(systemData['html'], contains('bold')); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'math-rich-payload-$index', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); - var destination = ''; + expect(result, '${value.expected}\n'); + field = tester.widget(find.byType(TextField).first); + expect(field.controller!.text, value.expected); + expect( + field.controller!.selection.extentOffset, + value.expected.indexOf('X') + 3, + ); + await key(tester, LogicalKeyboardKey.keyZ); + expect( + result, + r'a $x$ b' + '\n', + ); + } + }); + + testWidgets('math structural paste returns the committed block caret', ( + tester, + ) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final fragment = _fragment('## Heading\n\nFirst\n\nSecond\n'); + + var result = + r'a $x$ b' + '\n'; await mount( tester, - 'destination', - 'Before after\n', - (value) => destination = value, + 'math-structural-caret', + result, + (source) => result = source, + registry: registry, + providerScope: true, + focusFirstField: false, ); - tester - .widget(find.byType(TextField).first) - .controller! - .selection = const TextSelection.collapsed( - offset: 7, + final renderedMath = find.byWidgetPredicate( + (widget) => + widget.key is ValueKey && + ((widget.key! as ValueKey).value).startsWith( + 'wysiwyg-rendered-math-', + ), ); - await key(tester, LogicalKeyboardKey.keyV); - expect(destination, 'Before **bold**after\n'); + await tester.tap(renderedMath); + await tester.pump(); + final originalField = tester.widget( + find.byType(TextField).first, + ); + originalField.controller!.selection = const TextSelection.collapsed( + offset: 2, + ); + + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'math-structural-caret-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'Heading\n\nFirst\n\nSecond', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + final parsed = _parser + .parse(filePath: '/math.md', source: result) + .busyDocument; + expect( + parsed.blocks.where((block) => block.kind == BusyBlockKind.heading), + hasLength(1), + ); + expect( + parsed.blocks.map((block) => block.plainText), + containsAll(['First', 'Second']), + ); + final focused = tester + .widgetList(find.byType(TextField)) + .singleWhere((field) => field.focusNode?.hasFocus ?? false); + final caret = focused.controller!.selection.extentOffset; + final beforeTyping = focused.controller!.text; + final afterTyping = beforeTyping.replaceRange(caret, caret, 'Q'); + final focusedFinder = find.byWidgetPredicate( + (widget) => + widget is TextField && + identical(widget.controller, focused.controller), + ); + await tester.showKeyboard(focusedFinder); + focused.controller!.selection = TextSelection.collapsed(offset: caret); + tester.testTextInput.updateEditingValue( + TextEditingValue( + text: afterTyping, + selection: TextSelection.collapsed(offset: caret + 1), + ), + ); + await tester.pump(); + expect(focused.controller!.text, afterTyping); + expect(result, contains('Q')); }); - testWidgets('malformed native fragment falls back to HTML', (tester) async { - systemData = { - 'fragment': '{"version":99}', - 'html': '

Fallback

', - 'text': 'Fallback', - }; + testWidgets( + 'math structural paste preserves list descendants through Undo and Redo', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final fragment = _fragment('## Heading\n\nFirst\n\nSecond\n'); + const original = '- Parent \$x\$ tail\n - Existing\n'; + var result = original; + await mount( + tester, + 'math-list-structural-history', + result, + (source) => result = source, + registry: registry, + providerScope: true, + focusFirstField: false, + ); + final renderedMath = find.byWidgetPredicate( + (widget) => + widget.key is ValueKey && + ((widget.key! as ValueKey).value).startsWith( + 'wysiwyg-rendered-math-', + ), + ); + await tester.tap(renderedMath); + await tester.pump(); + final field = tester.widget(find.byType(TextField).first); + field.controller!.selection = const TextSelection.collapsed(offset: 7); + + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'math-list-structural-history-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'Heading\n\nFirst\n\nSecond', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pump(); + + final pasted = result; + expect(pasted, isNot(original)); + expect(RegExp(r'Existing').allMatches(pasted), hasLength(1)); + final parsed = _parser + .parse(filePath: '/math-list.md', source: pasted) + .busyDocument; + expect( + parsed.blocks + .expand((block) => [block, ...block.children]) + .where((block) => block.plainText == 'Existing'), + hasLength(1), + ); + + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, original); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expect(result, pasted); + expect(RegExp(r'Existing').allMatches(result), hasLength(1)); + }, + ); + + testWidgets('plain paste persists intentional whitespace through history', ( + tester, + ) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + final cases = + < + ({ + String source, + int start, + int end, + String pasted, + String expected, + }) + >[ + ( + source: 'Target\n', + start: 0, + end: 6, + pasted: ' ', + expected: ' \n', + ), + ( + source: 'Target\n', + start: 6, + end: 6, + pasted: ' ', + expected: 'Target \n', + ), + ( + source: '**Target**\n', + start: 2, + end: 4, + pasted: ' ', + expected: '**Ta et**\n', + ), + ]; + for (final (index, value) in cases.indexed) { + var result = value.source; + await mount( + tester, + 'whitespace-$index', + result, + (source) => result = source, + registry: registry, + ); + var field = tester.widget(find.byType(TextField).first); + field.controller!.selection = TextSelection( + baseOffset: value.start, + extentOffset: value.end, + ); + + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'whitespace-payload-$index', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + text: value.pasted, + ), + mode: BusyMarkPasteMode.plainText, + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + expect(result, value.expected); + final reopened = BusyMarkWysiwygDocumentController( + document: _parser + .parse(filePath: '/reopened.md', source: result) + .busyDocument, + ); + expect(reopened.markdown, result); + reopened.dispose(); + + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, value.source); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expect(result, value.expected); + } + }); + + testWidgets( + 'whole-document paste preserves whitespace and heading replacement scope', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + + var whitespace = 'First\n\nSecond\n'; + await mount( + tester, + 'whole-document-whitespace', + whitespace, + (source) => whitespace = source, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'whole-document-whitespace-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + text: ' ', + ), + mode: BusyMarkPasteMode.plainText, + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + expect(whitespace, ' \n'); + final reopened = BusyMarkWysiwygDocumentController( + document: _parser + .parse(filePath: '/reopened.md', source: whitespace) + .busyDocument, + ); + expect(reopened.markdown, whitespace); + reopened.dispose(); + await key(tester, LogicalKeyboardKey.keyZ); + expect(whitespace, 'First\n\nSecond\n'); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expect(whitespace, ' \n'); + + final rich = _fragment('**X**\n'); + var heading = '## Old\n'; + await mount( + tester, + 'whole-heading-scope', + heading, + (source) => heading = source, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'whole-heading-scope-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: rich.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + expect(heading, '**X**\n'); + expect( + _parser + .parse(filePath: '/heading.md', source: heading) + .busyDocument + .blocks + .single + .kind, + BusyBlockKind.paragraph, + ); + await key(tester, LogicalKeyboardKey.keyZ); + expect(heading, '## Old\n'); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expect(heading, '**X**\n'); + + await mount( + tester, + 'heading-field-scope', + '## Old\n', + (source) => heading = source, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'heading-field-scope-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: rich.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + expect(heading, '## **X**\n'); + }, + ); + + testWidgets( + 'history rich paste restores table-cell focus and committed caret', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var result = '| H |\n| --- |\n| leftright |\n'; + await mount( + tester, + 'history-table-caret', + result, + (value) => result = value, + registry: registry, + ); + var cell = tester + .widgetList(find.byType(TextField)) + .singleWhere((field) => field.controller?.text == 'leftright'); + cell.focusNode!.requestFocus(); + cell.controller!.selection = const TextSelection.collapsed(offset: 4); + await tester.pump(); + + final fragment = _fragment('**X**\n'); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'history-table-caret-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'X', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + cell = tester + .widgetList(find.byType(TextField)) + .singleWhere((field) => field.controller?.text == 'leftXright'); + expect(cell.focusNode!.hasFocus, isTrue); + expect( + cell.controller!.selection, + const TextSelection.collapsed(offset: 5), + ); + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'leftXYright', + selection: TextSelection.collapsed(offset: 6), + ), + ); + await tester.pump(); + expect(cell.controller!.text, 'leftXYright'); + expect(result, contains('left**XY**right')); + }, + ); + + testWidgets( + 'history multi-paragraph paste focuses the committed last paragraph', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var result = 'leftright\n'; + await mount( + tester, + 'history-multi-paragraph-caret', + result, + (value) => result = value, + registry: registry, + ); + final original = tester.widget(find.byType(TextField).first); + original.focusNode!.requestFocus(); + original.controller!.selection = const TextSelection.collapsed( + offset: 4, + ); + + final fragment = _fragment('*A*\n\n**B**\n'); + expect( + await registry.paste( + BusyMarkClipboardPayload( + id: 'history-multi-paragraph-caret-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.richText, + text: 'A\n\nB', + richFragment: fragment.encode(), + ), + ), + ClipboardPasteResult.inserted, + ); + await tester.pumpAndSettle(); + + final last = tester + .widgetList(find.byType(TextField)) + .singleWhere((field) => field.controller?.text == 'Bright'); + expect(last.focusNode!.hasFocus, isTrue); + expect( + last.controller!.selection, + const TextSelection.collapsed(offset: 1), + ); + tester.testTextInput.updateEditingValue( + const TextEditingValue( + text: 'BXright', + selection: TextSelection.collapsed(offset: 2), + ), + ); + await tester.pump(); + expect(last.controller!.text, 'BXright'); + expect( + _parser + .parse(filePath: '/result.md', source: result) + .busyDocument + .blocks + .map((block) => block.plainText), + ['leftA', 'BXright'], + ); + }, + ); + + testWidgets('copy all does not duplicate nested list children', ( + tester, + ) async { + await copyAll( + tester, + source: 'Before\n\n- Parent\n - **Child**\n\nAfter\n', + ); var result = ''; await mount(tester, 'destination', 'Target\n', (value) => result = value); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, '**Fallback**\n'); + expect(RegExp('Child').allMatches(result), hasLength(1)); + expect(result, contains(' - **Child**')); }); - testWidgets('HTML-only clipboard imports into a fresh Editor', ( + testWidgets('whole-document copy preserves a structured blockquote', ( tester, ) async { - systemData = { - 'html': '

Other app

Bold

', - 'text': 'Other app\nBold', - }; + await copyAll( + tester, + source: 'Before\n\n> First\n>\n> **Second**\n\nAfter\n', + ); var result = ''; await mount(tester, 'destination', 'Target\n', (value) => result = value); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('# Other app')); - expect(result, contains('**Bold**')); + expect(result, contains('> First')); + expect(result, contains('> **Second**')); + expect(RegExp('Second').allMatches(result), hasLength(1)); }); - testWidgets('retained external HTML preserves structure on history paste', ( + testWidgets('right-click opens the menu for a whole-document selection', ( tester, ) async { - systemData = { - 'html': - '

External

Bold and ' - 'linked

  • Item
', - 'text': 'External\nBold and linked\nItem', - }; - final historyClipboard = _WysiwygHistoryClipboard( - const RichClipboardData( - html: - '

External

Bold and ' - 'linked

  • Item
', - text: 'External\nBold and linked\nItem', - generation: 31, - ), + systemData = {'text': 'Paste', 'generation': 68}; + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + + await tester.tap( + find.widgetWithText(TextField, 'When selecting all, keep formatting.'), + buttons: kSecondaryMouseButton, ); - final historyScope = ProviderContainer( - overrides: [ - localSettingsStoreProvider.overrideWithValue( - _ClipboardMemorySettingsStore(), - ), - richClipboardServiceProvider.overrideWithValue(historyClipboard), - clipboardAssetInputServiceProvider.overrideWithValue( - _ClipboardEmptyAssetInput(), + await tester.pumpAndSettle(); + + for (final label in [ + 'Cut', + 'Copy', + 'Copy Plain Text', + 'Paste', + 'Select all', + ]) { + expect( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkPopupMenuItem && widget.label == label, ), - ], - ); - addTearDown(historyScope.dispose); - final history = historyScope.read( - clipboardHistoryControllerProvider.notifier, + findsOneWidget, + ); + } + await tester.tap(find.text('Copy')); + await tester.pumpAndSettle(); + expect(systemData.keys, containsAll(['text', 'html', 'token'])); + expect(systemData, isNot(contains('fragment'))); + expect(systemData['text'], contains('[ ] First task')); + }); + + testWidgets('image-only clipboard context menu offers only normal Paste', ( + tester, + ) async { + systemData = {'generation': 70}; + List>? nativeEntries; + const nativeMenuChannel = MethodChannel(nativeMenuChannelName); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + (call) async { + if (call.method != 'show') return null; + final arguments = call.arguments as Map; + nativeEntries = (arguments['entries'] as List) + .cast>(); + return null; + }, + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + nativeMenuChannel, + null, + ), + ); + await mount( + tester, + 'image-menu', + 'Target\n', + (_) {}, + assetInputService: _ClipboardImageAssetInput( + Uint8List.fromList(const [0x89, 0x50, 0x4e, 0x47]), + ), + ); + final field = find.byType(TextField).first; + final editable = find.descendant( + of: field, + matching: find.byType(EditableText), + ); + expect( + tester + .state(editable) + .contextMenuButtonItems + .where((item) => item.type == ContextMenuButtonType.paste), + isEmpty, + ); + + await tester.tap(field, buttons: kSecondaryMouseButton); + await tester.pumpAndSettle(); + + final labels = nativeEntries!.map((entry) => entry['label']).toList(); + expect(labels, contains('Paste')); + expect(labels, isNot(contains('Paste as Plain Text'))); + expect( + nativeEntries!.singleWhere( + (entry) => entry['label'] == 'Paste', + )['shortcut'], + 'Ctrl+V', + ); + }); + + testWidgets('Copy Plain Text strips formatting in another Editor', ( + tester, + ) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC, shift: true); + + expect(systemData.keys, containsAll(['text', 'token'])); + expect(systemData, isNot(contains('fragment'))); + expect(systemData['text'], startsWith('Issues')); + expect( + systemData['text'], + contains('When selecting all, keep formatting.'), + ); + expect(systemData['text'], contains('[ ] First task')); + expect(systemData['text'], isNot(contains('# Issues'))); + expect(systemData['text'], isNot(contains('**When**'))); + + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('Issues')); + expect(result, contains('When selecting all, keep formatting.')); + expect(result, isNot(contains('# Issues'))); + expect(result, isNot(contains('**When**'))); + expect(result, isNot(contains('- [x] Second task'))); + }); + + testWidgets('document selection menu can copy plain text', (tester) async { + systemData = {'text': 'Paste', 'generation': 69}; + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await tester.tap( + find.widgetWithText(TextField, 'When selecting all, keep formatting.'), + buttons: kSecondaryMouseButton, + ); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Copy Plain Text')); + await tester.pumpAndSettle(); + expect(systemData.keys, containsAll(['text', 'token'])); + expect(systemData, isNot(contains('fragment'))); + expect(systemData['text'], startsWith('Issues')); + expect(systemData['text'], isNot(contains('**When**'))); + }); + + testWidgets( + 'partial inline copy keeps formatting inside another paragraph', + (tester) async { + await mount(tester, 'origin', 'A **bold** word\n', (_) {}); + final field = tester.widget(find.byType(TextField).first); + field.controller!.selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + await key(tester, LogicalKeyboardKey.keyC); + var result = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => result = value, + ); + tester + .widget(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, 'Before **bold**after\n'); + }, + ); + + testWidgets('cut transfers formatting before deleting the selection', ( + tester, + ) async { + var origin = 'A **bold** word\n'; + await mount(tester, 'origin', origin, (value) => origin = value); + tester + .widget(find.byType(TextField).first) + .controller! + .selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + + await key(tester, LogicalKeyboardKey.keyX); + expect(origin, 'A word\n'); + expect(systemData.keys, containsAll(['text', 'html', 'token'])); + expect(systemData, isNot(contains('fragment'))); + expect(systemData['text'], 'bold'); + expect(systemData['html'], contains('bold')); + + var destination = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => destination = value, + ); + tester + .widget(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(destination, 'Before **bold**after\n'); + }); + + testWidgets('malformed native fragment falls back to HTML', (tester) async { + systemData = { + 'fragment': '{"version":99}', + 'html': '

Fallback

', + 'text': 'Fallback', + }; + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, '**Fallback**\n'); + }); + + testWidgets('HTML-only clipboard imports into a fresh Editor', ( + tester, + ) async { + systemData = { + 'html': '

Other app

Bold

', + 'text': 'Other app\nBold', + }; + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('# Other app')); + expect(result, contains('**Bold**')); + expect(readCalls, 1); + }); + + testWidgets('HTML clipboard plain paste inserts only its text', ( + tester, + ) async { + systemData = { + 'html': '

Other app

Bold

', + 'text': ' Other app\nBold\n', + }; + var result = ''; + await mount(tester, 'plain-html', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV, shift: true); + expect(result, startsWith(' Other app')); + expect(result, contains('Bold')); + expect(result, isNot(contains('# Other app'))); + expect(result, isNot(contains('**Bold**'))); + expect(readCalls, 1); + }); + + testWidgets('retained external HTML preserves structure on history paste', ( + tester, + ) async { + systemData = { + 'html': + '

External

Bold and ' + 'linked

  • Item
', + 'text': 'External\nBold and linked\nItem', + }; + final historyClipboard = _WysiwygHistoryClipboard( + const RichClipboardData( + html: + '

External

Bold and ' + 'linked

  • Item
', + text: 'External\nBold and linked\nItem', + generation: 31, + ), + ); + final historyScope = ProviderContainer( + overrides: [ + localSettingsStoreProvider.overrideWithValue( + _ClipboardMemorySettingsStore(), + ), + richClipboardServiceProvider.overrideWithValue(historyClipboard), + clipboardAssetInputServiceProvider.overrideWithValue( + _ClipboardEmptyAssetInput(), + ), + ], + ); + addTearDown(historyScope.dispose); + final history = historyScope.read( + clipboardHistoryControllerProvider.notifier, + ); + await history.refreshCurrentClipboard(); + final current = historyScope + .read(clipboardHistoryControllerProvider) + .currentClipboard!; + expect(current.html, contains('

External

')); + expect( + historyScope.read(clipboardHistoryControllerProvider).entries, + isEmpty, + ); + + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var first = ''; + await mount( + tester, + 'first', + 'Target\n', + (value) => first = value, + registry: registry, + onCaptured: history.retain, + ); + await key(tester, LogicalKeyboardKey.keyA); + expect(await registry.paste(current), ClipboardPasteResult.inserted); + await tester.pump(); + expect(first, contains('**Bold**')); + expect(first, contains('[linked](https://example.com)')); + expect(first, contains('- Item')); + expect( + historyScope.read(clipboardHistoryControllerProvider).entries, + hasLength(1), + ); + + systemData = {'text': 'Replacement clipboard'}; + historyClipboard.value = const RichClipboardData( + text: 'Replacement clipboard', + generation: 32, + ); + await history.refreshCurrentClipboard(); + var retained = ''; + await mount( + tester, + 'retained', + 'Target\n', + (value) => retained = value, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + final value = historyScope + .read(clipboardHistoryControllerProvider) + .entries + .single; + expect(await registry.paste(value), ClipboardPasteResult.inserted); + await tester.pump(); + expect(retained, contains('# External')); + expect(retained, contains('**Bold**')); + expect(retained, contains('[linked](https://example.com)')); + expect(retained, contains('- Item')); + + var plain = ''; + await mount( + tester, + 'plain', + 'Target\n', + (value) => plain = value, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + expect( + await registry.paste(current, mode: BusyMarkPasteMode.plainText), + ClipboardPasteResult.inserted, + ); + await tester.pump(); + expect(plain, contains('External')); + expect(plain, contains('Bold and linked')); + expect(plain, contains('Item')); + expect(plain, isNot(contains('**Bold**'))); + expect(plain, isNot(contains('[linked]'))); + }); + + testWidgets( + 'current HTML-only and malformed HTML use ordinary importer fallbacks', + (tester) async { + final service = _WysiwygHistoryClipboard( + const RichClipboardData( + html: '

HTML only

Supported

', + generation: 33, + ), + ); + final historyScope = ProviderContainer( + overrides: [ + localSettingsStoreProvider.overrideWithValue( + _ClipboardMemorySettingsStore(), + ), + richClipboardServiceProvider.overrideWithValue(service), + clipboardAssetInputServiceProvider.overrideWithValue( + _ClipboardEmptyAssetInput(), + ), + ], + ); + addTearDown(historyScope.dispose); + final history = historyScope.read( + clipboardHistoryControllerProvider.notifier, + ); + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + + await history.refreshCurrentClipboard(); + final htmlOnly = historyScope + .read(clipboardHistoryControllerProvider) + .currentClipboard!; + var htmlOnlyResult = ''; + await mount( + tester, + 'html-only-current', + 'Target\n', + (value) => htmlOnlyResult = value, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + expect(await registry.paste(htmlOnly), ClipboardPasteResult.inserted); + await tester.pump(); + expect(htmlOnlyResult, contains('## HTML only')); + expect(htmlOnlyResult, contains('*Supported*')); + + service.value = const RichClipboardData( + html: '

', + text: 'Safe text alternative', + generation: 34, + ); + await history.refreshCurrentClipboard(); + final malformed = historyScope + .read(clipboardHistoryControllerProvider) + .currentClipboard!; + var fallback = ''; + await mount( + tester, + 'malformed-current', + 'Target\n', + (value) => fallback = value, + registry: registry, + ); + await key(tester, LogicalKeyboardKey.keyA); + expect(await registry.paste(malformed), ClipboardPasteResult.inserted); + await tester.pump(); + expect(fallback, contains('Safe text alternative')); + }, + ); + + testWidgets( + 'external image history retains the bytes ingested before its dialog', + (tester) async { + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp( + 'busymark-clipboard-image-snapshot-', + ), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final original = base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', + ); + final replacement = Uint8List.fromList(original); + replacement[replacement.length - 1] ^= 0xff; + final sourceFile = File('${root.path}/original.png'); + await tester.runAsync(() => sourceFile.writeAsBytes(original)); + systemData = {'text': sourceFile.path}; + final historyScope = ProviderContainer( + overrides: [ + localSettingsStoreProvider.overrideWithValue( + _ClipboardMemorySettingsStore(), + ), + ], + ); + addTearDown(historyScope.dispose); + final history = historyScope.read( + clipboardHistoryControllerProvider.notifier, + ); + var changed = ''; + await mount( + tester, + 'image-snapshot', + 'Target\n', + (value) => changed = value, + onCaptured: history.retain, + filePath: '${root.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + + await key(tester, LogicalKeyboardKey.keyV); + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(find.byKey(BusyMarkImageDialogKeys.submit), findsOneWidget); + await tester.runAsync(() => sourceFile.writeAsBytes(replacement)); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + + expect(changed, contains('images/original.png')); + final retainedEntries = historyScope + .read(clipboardHistoryControllerProvider) + .entries; + expect(retainedEntries, hasLength(1)); + expect(retainedEntries.single.text, sourceFile.path); + expect(retainedEntries.single.kind, BusyMarkClipboardContentKind.image); + expect(retainedEntries.single.imageBytes, original); + expect( + await tester.runAsync( + () => File('${root.path}/images/original.png').readAsBytes(), + ), + original, + ); + + final payload = retainedEntries.single; + final replayDirectory = Directory('${root.path}/replay'); + await tester.runAsync(replayDirectory.create); + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var replayed = ''; + await mount( + tester, + 'image-replay', + 'Target\n', + (value) => replayed = value, + registry: registry, + filePath: '${replayDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + final replay = registry.paste(payload); + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(find.byKey(BusyMarkImageDialogKeys.submit), findsOneWidget); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + expect(await replay, ClipboardPasteResult.inserted); + expect(replayed, contains('images/original.png')); + expect( + await tester.runAsync( + () => File( + '${replayDirectory.path}/images/original.png', + ).readAsBytes(), + ), + original, + ); + + await tester.runAsync(sourceFile.delete); + final deletedReplayDirectory = Directory('${root.path}/deleted-replay'); + await tester.runAsync(deletedReplayDirectory.create); + var deletedReplay = ''; + await mount( + tester, + 'image-deleted-replay', + 'Target\n', + (value) => deletedReplay = value, + registry: registry, + filePath: '${deletedReplayDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + final replayAfterDelete = registry.paste(payload); + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(find.byKey(BusyMarkImageDialogKeys.submit), findsOneWidget); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + expect(await replayAfterDelete, ClipboardPasteResult.inserted); + expect(deletedReplay, contains('images/original.png')); + expect( + await tester.runAsync( + () => File( + '${deletedReplayDirectory.path}/images/original.png', + ).readAsBytes(), + ), + original, + ); + + final plainDirectory = Directory('${root.path}/plain'); + await tester.runAsync(plainDirectory.create); + var plain = ''; + await mount( + tester, + 'image-plain-replay', + 'Target\n', + (value) => plain = value, + registry: registry, + filePath: '${plainDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ); + final plainField = tester.widget( + find.byType(TextField).first, + ); + plainField.controller!.selection = TextSelection( + baseOffset: 0, + extentOffset: plainField.controller!.text.length, + ); + expect( + await registry.paste(payload, mode: BusyMarkPasteMode.plainText), + ClipboardPasteResult.inserted, + ); + await tester.pump(); + expect(plain, '${sourceFile.path}\n'); + expect( + await tester.runAsync( + () => Directory('${plainDirectory.path}/images').exists(), + ), + isFalse, + ); + }, + ); + + testWidgets('history panel path paste has one editor-owned retention write', ( + tester, + ) async { + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-panel-path-retention-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final original = base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', + ); + final sourceFile = File('${root.path}/panel.png'); + await tester.runAsync(() => sourceFile.writeAsBytes(original)); + final clipboard = _WysiwygHistoryClipboard( + RichClipboardData(text: sourceFile.path, generation: 80), + ); + final container = ProviderContainer( + overrides: [ + localSettingsStoreProvider.overrideWithValue( + _ClipboardMemorySettingsStore(), + ), + richClipboardServiceProvider.overrideWithValue(clipboard), + clipboardAssetInputServiceProvider.overrideWithValue( + _ClipboardEmptyAssetInput(), + ), + ], + ); + addTearDown(container.dispose); + final registry = container.read(clipboardInsertionRegistryProvider); + final history = container.read( + clipboardHistoryControllerProvider.notifier, + ); + var changed = 'Target\n'; + final document = _parser + .parse( + filePath: '${root.path}/target.md', + source: changed, + mode: MarkdownMode.writersideMarkdown, + ) + .busyDocument; + await tester.pumpWidget( + UncontrolledProviderScope( + container: container, + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: Row( + children: [ + Expanded( + child: BusyMarkWysiwygEditor( + document: document, + onSourceChanged: (_, value) => changed = value, + clipboardService: RichClipboardService(), + clipboardInsertionRegistry: registry, + onClipboardCaptured: history.retain, + assetWorkspaceKind: AssetWorkspaceKind.standalone, + ), + ), + const SizedBox(width: 320, child: ClipboardHistoryPanel()), + ], + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + final editorField = find.widgetWithText(TextField, 'Target'); + await tester.tap(editorField); + await tester.pump(); + expect( + container.read(clipboardHistoryControllerProvider).entries, + isEmpty, + ); + + final pathRow = find.text(sourceFile.path).first; + await tester.tap(pathRow); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tap(pathRow); + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(find.byKey(BusyMarkImageDialogKeys.submit), findsOneWidget); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + + expect(changed, contains('images/panel.png')); + final entries = container + .read(clipboardHistoryControllerProvider) + .entries; + expect(entries, hasLength(1)); + expect(entries.single.kind, BusyMarkClipboardContentKind.image); + expect(entries.single.text, sourceFile.path); + expect(entries.single.imageBytes, original); + }); + + testWidgets('copied local video can be pasted from history in Editor', ( + tester, + ) async { + final root = (await tester.runAsync( + () => + Directory.systemTemp.createTemp('busymark-wysiwyg-history-video-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final video = Uint8List.fromList([ + 0, + 0, + 0, + 20, + ...ascii.encode('ftypmp42'), + 0, + 0, + 0, + 0, + ]); + await tester.runAsync( + () => File('${root.path}/clip.mp4').writeAsBytes(video), + ); + final captures = []; + await mount( + tester, + 'video-origin', + 'Before\n\n

External

')); - expect( - historyScope.read(clipboardHistoryControllerProvider).entries, - isEmpty, + await key(tester, LogicalKeyboardKey.keyV); + await waitForDialog(); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.cancel)); + await tester.pumpAndSettle(); + await waitForRollbackCount(1); + expect(pathResult, 'Target\n'); + expect(pathCaptures, isEmpty); + expect(publishedAssets, hasLength(1)); + expect(committedAssets, isEmpty); + expect(rolledBackAssets, hasLength(1)); + expect(publishedAssets.last.publicationId, isNotNull); + expect(rolledBackAssets.last, same(publishedAssets.last)); + await expectNoPublishedAsset(root.path); + + final nativeDirectory = Directory('${root.path}/native')..createSync(); + systemData = {'generation': 71}; + var nativeResult = 'Target\n'; + await mount( + tester, + 'native-cancel', + nativeResult, + (value) => nativeResult = value, + filePath: '${nativeDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetInputService: _ClipboardImageAssetInput(png), + assetIngestionService: ingestion, ); + await key(tester, LogicalKeyboardKey.keyV); + await waitForDialog(); + await tester.sendKeyEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + await waitForRollbackCount(2); + expect(nativeResult, 'Target\n'); + await expectNoPublishedAsset(nativeDirectory.path); + final historyDirectory = Directory('${root.path}/history')..createSync(); final registry = BusyMarkClipboardInsertionRegistry(); addTearDown(registry.dispose); - var first = ''; + final historyCaptures = []; + var historyResult = 'Target\n'; await mount( tester, - 'first', - 'Target\n', - (value) => first = value, + 'history-cancel', + historyResult, + (value) => historyResult = value, registry: registry, + onCaptured: historyCaptures.add, + filePath: '${historyDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetIngestionService: ingestion, ); - await key(tester, LogicalKeyboardKey.keyA); - expect(await registry.paste(current), ClipboardPasteResult.inserted); - await tester.pump(); - expect(first, contains('**Bold**')); - expect(first, contains('[linked](https://example.com)')); - expect(first, contains('- Item')); - history.retainCurrentAfterPaste(current); - expect( - historyScope.read(clipboardHistoryControllerProvider).entries, - hasLength(1), + ClipboardPasteResult? pasteResult; + registry + .paste( + BusyMarkClipboardPayload( + id: 'cancel-image-history', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.image, + text: source.path, + imageBytes: png, + imageMimeType: 'image/png', + imageDisplayName: 'source.png', + external: true, + ), + ) + .then((value) => pasteResult = value); + await waitForDialog(); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.cancel)); + await tester.pumpAndSettle(); + for (var attempt = 0; attempt < 100 && pasteResult == null; attempt++) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(pasteResult, ClipboardPasteResult.cancelled); + await waitForRollbackCount(3); + expect(historyResult, 'Target\n'); + expect(historyCaptures, isEmpty); + await expectNoPublishedAsset(historyDirectory.path); + }); + + testWidgets('image picker alternatives stay provisional until acceptance', ( + tester, + ) async { + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-image-alternatives-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final base = base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', + ); + final files = []; + for (final (index, name) in ['a.png', 'b.png', 'c.png'].indexed) { + final bytes = Uint8List.fromList(base)..[base.length - 1] ^= index; + final file = File('${root.path}/$name'); + await tester.runAsync(() => file.writeAsBytes(bytes)); + files.add(file); + } + final published = []; + final committed = []; + final rolledBack = []; + final ingestion = AssetIngestionService( + hooks: AssetIngestionHooks( + afterPublication: (asset) async => published.add(asset), + beforeCommit: (asset) async => committed.add(asset), + afterRollback: (asset) async => rolledBack.add(asset), + ), + ); + const pickerChannel = MethodChannel('plugins.flutter.io/file_selector'); + final picks = []; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + pickerChannel, + (_) async => [picks.removeAt(0)], + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + pickerChannel, + null, + ), ); - systemData = {'text': 'Replacement clipboard'}; - historyClipboard.value = const RichClipboardData( - text: 'Replacement clipboard', - generation: 32, + Future waitForCount(List values, int count) async { + for ( + var attempt = 0; + attempt < 100 && values.length < count; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(values.length, greaterThanOrEqualTo(count)); + } + + Future waitForDialog() async { + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.choose).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + expect(find.byKey(BusyMarkImageDialogKeys.choose), findsOneWidget); + } + + systemData = {'text': files[0].path}; + var result = 'Target\n'; + await mount( + tester, + 'alternative-cancel', + result, + (source) => result = source, + filePath: '${root.path}/cancel.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetIngestionService: ingestion, ); - await history.refreshCurrentClipboard(); - var retained = ''; + await key(tester, LogicalKeyboardKey.keyV); + await waitForCount(published, 1); + await waitForDialog(); + picks.add(files[1].path); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.choose)); + await waitForCount(published, 2); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.cancel)); + await tester.pumpAndSettle(); + await waitForCount(rolledBack, 2); + expect(result, 'Target\n'); + expect(committed, isEmpty); + + final acceptedDirectory = Directory('${root.path}/accepted') + ..createSync(); + systemData = {'text': files[0].path}; await mount( tester, - 'retained', - 'Target\n', - (value) => retained = value, - registry: registry, + 'alternative-accept', + result, + (source) => result = source, + filePath: '${acceptedDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetIngestionService: ingestion, ); - await key(tester, LogicalKeyboardKey.keyA); - final value = historyScope - .read(clipboardHistoryControllerProvider) - .entries - .single; - expect(await registry.paste(value), ClipboardPasteResult.inserted); - await tester.pump(); - expect(retained, contains('# External')); - expect(retained, contains('**Bold**')); - expect(retained, contains('[linked](https://example.com)')); - expect(retained, contains('- Item')); + await key(tester, LogicalKeyboardKey.keyV); + await waitForCount(published, 3); + await waitForDialog(); + picks.addAll([files[1].path, files[2].path]); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.choose)); + await waitForCount(published, 4); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.choose)); + await waitForCount(published, 5); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + await waitForCount(committed, 1); + await waitForCount(rolledBack, 4); - var plain = ''; + expect(result, contains('images/c.png')); + expect(p.basename(committed.single.absolutePath), 'c.png'); + final remaining = await tester.runAsync( + () => Directory('${acceptedDirectory.path}/images') + .list() + .where((entity) => entity is File) + .map((entity) => p.basename(entity.path)) + .toList(), + ); + expect(remaining, ['c.png']); + + final invalidDirectory = Directory('${root.path}/invalid')..createSync(); + result = 'Target\n'; + systemData = {'text': files[0].path}; await mount( tester, - 'plain', - 'Target\n', - (value) => plain = value, - registry: registry, + 'alternative-invalid', + result, + (source) => result = source, + filePath: '${invalidDirectory.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetIngestionService: ingestion, ); - await key(tester, LogicalKeyboardKey.keyA); - expect( - await registry.paste(current, plainText: true), - ClipboardPasteResult.inserted, + await key(tester, LogicalKeyboardKey.keyV); + await waitForCount(published, 6); + await waitForDialog(); + picks.add(files[1].path); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.choose)); + await waitForCount(published, 7); + final destination = tester.widget( + find.widgetWithText(TextField, 'Target'), + ); + destination.controller!.value = const TextEditingValue( + text: 'Changed', + selection: TextSelection.collapsed(offset: 7), ); await tester.pump(); - expect(plain, contains('External')); - expect(plain, contains('Bold and linked')); - expect(plain, contains('Item')); - expect(plain, isNot(contains('**Bold**'))); - expect(plain, isNot(contains('[linked]'))); + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + await tester.pumpAndSettle(); + await waitForCount(rolledBack, 6); + expect(result, 'Target\n'); + expect(committed, hasLength(1)); + final invalidFiles = await tester.runAsync( + () => Directory( + '${invalidDirectory.path}/images', + ).list().where((entity) => entity is File).toList(), + ); + expect(invalidFiles, isEmpty); }); testWidgets( - 'current HTML-only and malformed HTML use ordinary importer fallbacks', + 'image finalization failure preserves the inserted reference and file', (tester) async { - final service = _WysiwygHistoryClipboard( - const RichClipboardData( - html: '

HTML only

Supported

', - generation: 33, + final root = (await tester.runAsync( + () => Directory.systemTemp.createTemp('busymark-image-finalization-'), + ))!; + addTearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + final source = File('${root.path}/source.png'); + await tester.runAsync( + () => source.writeAsBytes( + base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', + ), + ), + ); + final published = []; + var commitAttempts = 0; + var rollbacks = 0; + final ingestion = AssetIngestionService( + hooks: AssetIngestionHooks( + afterPublication: (asset) async => published.add(asset), + beforeCommit: (_) async { + commitAttempts += 1; + throw const FileSystemException('injected finalization failure'); + }, + afterRollback: (_) async => rollbacks += 1, + ), + ); + systemData = {'text': source.path}; + var result = 'Target\n'; + await mount( + tester, + 'image-finalization-failure', + result, + (value) => result = value, + filePath: '${root.path}/target.md', + assetWorkspaceKind: AssetWorkspaceKind.standalone, + assetIngestionService: ingestion, + hostToasts: true, + ); + await key(tester, LogicalKeyboardKey.keyV); + for ( + var attempt = 0; + attempt < 100 && + find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; + attempt++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); + for (var attempt = 0; attempt < 100 && commitAttempts == 0; attempt++) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 5)), + ); + await tester.pump(); + } + + expect(commitAttempts, 1); + expect(rollbacks, 0); + expect(published, hasLength(1)); + expect( + RegExp( + RegExp.escape(published.single.markdownPath), + ).allMatches(result), + hasLength(1), + ); + expect( + await tester.runAsync( + () => File(published.single.absolutePath).readAsBytes(), ), + isNotEmpty, + ); + final pending = await tester.runAsync( + () => Directory('${root.path}/images/.busymark-asset-transactions') + .list() + .where( + (entity) => + entity is File && !entity.path.endsWith('directory.lock'), + ) + .toList(), + ); + expect(pending, hasLength(1)); + }, + ); + + testWidgets( + 'native and history image filesystem failures are handled outcomes', + (tester) async { + final png = base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', ); + final ingestion = _FileSystemFailingAssetIngestionService(); final historyScope = ProviderContainer( overrides: [ localSettingsStoreProvider.overrideWithValue( _ClipboardMemorySettingsStore(), ), - richClipboardServiceProvider.overrideWithValue(service), - clipboardAssetInputServiceProvider.overrideWithValue( - _ClipboardEmptyAssetInput(), - ), ], ); addTearDown(historyScope.dispose); final history = historyScope.read( clipboardHistoryControllerProvider.notifier, ); - final registry = BusyMarkClipboardInsertionRegistry(); - addTearDown(registry.dispose); - - await history.refreshCurrentClipboard(); - final htmlOnly = historyScope - .read(clipboardHistoryControllerProvider) - .currentClipboard!; - var htmlOnlyResult = ''; + final transactions = []; + var result = 'Target\n'; + systemData = {'generation': 801}; await mount( tester, - 'html-only-current', - 'Target\n', - (value) => htmlOnlyResult = value, - registry: registry, + 'native-filesystem-failure', + result, + (value) => result = value, + onCaptured: history.retain, + assetInputService: _ClipboardImageAssetInput(png), + assetIngestionService: ingestion, + onTransactionalSourceChanged: (_, source, _) => + transactions.add(source), + useExternalUndoHistory: true, + hostToasts: true, ); - await key(tester, LogicalKeyboardKey.keyA); - expect(await registry.paste(htmlOnly), ClipboardPasteResult.inserted); + + await key(tester, LogicalKeyboardKey.keyV); await tester.pump(); - expect(htmlOnlyResult, contains('## HTML only')); - expect(htmlOnlyResult, contains('*Supported*')); - service.value = const RichClipboardData( - html: '

', - text: 'Safe text alternative', - generation: 34, + expect(result, 'Target\n'); + expect(transactions, isEmpty); + expect( + historyScope.read(clipboardHistoryControllerProvider).entries, + isEmpty, ); - await history.refreshCurrentClipboard(); - final malformed = historyScope - .read(clipboardHistoryControllerProvider) - .currentClipboard!; - var fallback = ''; + expect( + find.text( + 'The current clipboard content is unavailable or unsupported.', + ), + findsWidgets, + ); + expect(find.byKey(BusyMarkImageDialogKeys.submit), findsNothing); + + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); await mount( tester, - 'malformed-current', - 'Target\n', - (value) => fallback = value, + 'history-filesystem-failure', + result, + (value) => result = value, registry: registry, + onCaptured: history.retain, + assetIngestionService: ingestion, + onTransactionalSourceChanged: (_, source, _) => + transactions.add(source), + useExternalUndoHistory: true, + hostToasts: true, + ); + final pasteResult = await registry.paste( + BusyMarkClipboardPayload( + id: 'filesystem-image-history', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.image, + imageBytes: png, + imageMimeType: 'image/png', + imageDisplayName: 'failure.png', + external: true, + ), ); - await key(tester, LogicalKeyboardKey.keyA); - expect(await registry.paste(malformed), ClipboardPasteResult.inserted); await tester.pump(); - expect(fallback, contains('Safe text alternative')); + + expect(pasteResult, ClipboardPasteResult.unsupported); + expect(result, 'Target\n'); + expect(transactions, isEmpty); + expect( + historyScope.read(clipboardHistoryControllerProvider).entries, + isEmpty, + ); + expect( + find.text( + 'The current clipboard content is unavailable or unsupported.', + ), + findsWidgets, + ); + expect(ingestion.calls, 2); }, ); testWidgets( - 'external image history retains the bytes ingested before its dialog', - (tester) async { - final root = (await tester.runAsync( - () => Directory.systemTemp.createTemp( - 'busymark-clipboard-image-snapshot-', - ), - ))!; - addTearDown(() async { - if (await root.exists()) await root.delete(recursive: true); - }); - final original = base64Decode( - 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', - ); - final replacement = Uint8List.fromList(original); - replacement[replacement.length - 1] ^= 0xff; - final sourceFile = File('${root.path}/original.png'); - await tester.runAsync(() => sourceFile.writeAsBytes(original)); - systemData = {'text': sourceFile.path}; - final captures = []; - var changed = ''; + 'plain history paste replaces a document selection ending at a non-field block', + (tester) async { + final registry = BusyMarkClipboardInsertionRegistry(); + addTearDown(registry.dispose); + var result = 'First\n\n---\n'; await mount( tester, - 'image-snapshot', - 'Target\n', - (value) => changed = value, - onCaptured: captures.add, - filePath: '${root.path}/target.md', - assetWorkspaceKind: AssetWorkspaceKind.standalone, + 'plain-document-selection', + result, + (value) => result = value, + registry: registry, + initialSessionFor: (document) => WysiwygEditorSessionState( + activeBlockId: document.blocks.first.id, + anchorBlockId: document.blocks.first.id, + anchorOffset: 0, + extentBlockId: document.blocks.last.id, + extentOffset: document.blocks.last.plainText.length, + ), ); - await key(tester, LogicalKeyboardKey.keyV); - for ( - var attempt = 0; - attempt < 100 && - find.byKey(BusyMarkImageDialogKeys.submit).evaluate().isEmpty; - attempt++ - ) { - await tester.runAsync( - () => Future.delayed(const Duration(milliseconds: 5)), - ); - await tester.pump(); - } - expect(find.byKey(BusyMarkImageDialogKeys.submit), findsOneWidget); - await tester.runAsync(() => sourceFile.writeAsBytes(replacement)); - await tester.tap(find.byKey(BusyMarkImageDialogKeys.submit)); - await tester.pumpAndSettle(); - - expect(changed, contains('images/original.png')); - expect(captures, hasLength(1)); - expect(captures.single.imageBytes, original); expect( - await tester.runAsync( - () => File('${root.path}/images/original.png').readAsBytes(), + await registry.paste( + BusyMarkClipboardPayload( + id: 'plain-document-selection-payload', + acquiredAt: DateTime.utc(2026), + kind: BusyMarkClipboardContentKind.text, + text: 'Replacement', + ), + mode: BusyMarkPasteMode.plainText, ), - original, + ClipboardPasteResult.inserted, ); + await tester.pump(); + expect(result, 'Replacement\n'); }, ); - testWidgets('copied local video can be pasted from history in Editor', ( + testWidgets('image history follows table and multi-block destinations', ( tester, ) async { final root = (await tester.runAsync( - () => - Directory.systemTemp.createTemp('busymark-wysiwyg-history-video-'), + () => Directory.systemTemp.createTemp('busymark-image-routing-'), ))!; addTearDown(() async { if (await root.exists()) await root.delete(recursive: true); }); - final video = Uint8List.fromList([ - 0, - 0, - 0, - 20, - ...ascii.encode('ftypmp42'), - 0, - 0, - 0, - 0, - ]); - await tester.runAsync( - () => File('${root.path}/clip.mp4').writeAsBytes(video), - ); - final captures = []; - await mount( - tester, - 'video-origin', - 'Before\n\n

Use staged rollout with a ' 'rollback plan.

' '
  • Verify health
  • Keep the prior package
'; - final controller = ref.read(clipboardHistoryControllerProvider.notifier); final current = ref .read(clipboardHistoryControllerProvider) .currentClipboard!; @@ -474,12 +474,11 @@ class _HistoryVisualHarnessState extends ConsumerState<_HistoryVisualHarness> { ); final firstInsertion = await ref .read(clipboardInsertionRegistryProvider) - .paste(current, plainText: false); + .paste(current, mode: BusyMarkPasteMode.normal); _check( firstInsertion == ClipboardPasteResult.inserted, 'current external HTML inserted', ); - controller.retainCurrentAfterPaste(current); await Clipboard.setData(const ClipboardData(text: 'Clipboard replaced')); await Future.delayed(const Duration(milliseconds: 700)); await WidgetsBinding.instance.endOfFrame; @@ -493,7 +492,7 @@ class _HistoryVisualHarnessState extends ConsumerState<_HistoryVisualHarness> { .firstWhere((entry) => entry.html == externalHtml); final secondInsertion = await ref .read(clipboardInsertionRegistryProvider) - .paste(retained, plainText: false); + .paste(retained, mode: BusyMarkPasteMode.normal); _check( secondInsertion == ClipboardPasteResult.inserted, 'retained external HTML reused after clipboard replacement', diff --git a/tools/linux_native_menu_probe.py b/tools/linux_native_menu_probe.py index 971f794d..29939e52 100644 --- a/tools/linux_native_menu_probe.py +++ b/tools/linux_native_menu_probe.py @@ -1,8 +1,10 @@ #!/usr/bin/python3 -"""GTK accessibility/X11 driver for the disposable TOC acceptance app. +"""GTK accessibility driver for the disposable TOC acceptance app. -Run only inside the probe's dedicated Xvfb and D-Bus session. It targets the -given process, never another BusyMark window or the user's desktop. +Run only inside the probe's dedicated Xvfb and D-Bus session. A Wayland target +may be nested in that X server so the probe can keep using the isolated outer +display for screenshots and keyboard input. It targets the given process, +never another BusyMark window or the user's desktop. """ import ctypes import json @@ -10,6 +12,13 @@ import sys import time +target_gdk_backend = os.environ.get("GDK_BACKEND") +if target_gdk_backend == "wayland" and os.environ.get("DISPLAY"): + # GDK has no root window on Wayland. The acceptance target remains a + # Wayland client, while this separate probe connects to its enclosing Xvfb + # display for capture and XTest input through the nested compositor. + os.environ["GDK_BACKEND"] = "x11" + import gi gi.require_version("Atspi", "2.0") @@ -66,8 +75,12 @@ def key(name): def main(): if os.environ.get("BUSYMARK_NATIVE_PROBE") != "1": raise RuntimeError("Use an isolated probe session, not the user's desktop") - if os.environ.get("GDK_BACKEND") != "x11": - raise RuntimeError("Explicit GDK_BACKEND=x11 is required for the isolated display") + if target_gdk_backend not in ("x11", "wayland"): + raise RuntimeError( + "Explicit GDK_BACKEND=x11 or wayland is required for the isolated display" + ) + if target_gdk_backend == "wayland" and not os.environ.get("DISPLAY"): + raise RuntimeError("The Wayland probe requires an isolated enclosing X display") pid, command, *args = sys.argv[1:] app = app_for_pid(int(pid)) if command == "capture": @@ -83,6 +96,26 @@ def main(): "enabled": node.get_state_set().contains(Atspi.StateType.ENABLED)} for node in walk(app) ], ensure_ascii=False)) + elif command == "assert-check": + matches = [node for node in walk(app) + if node.get_name() == args[0] + and node.get_role() in (Atspi.Role.RADIO_MENU_ITEM, + Atspi.Role.CHECK_MENU_ITEM) + and node.get_state_set().contains(Atspi.StateType.SHOWING)] + if len(matches) != 1: + raise RuntimeError( + f"Expected one visible checked-style menu item {args[0]!r}, " + f"got {len(matches)}") + item = matches[0] + if item.get_role() != Atspi.Role.CHECK_MENU_ITEM: + raise RuntimeError( + f"Native menu item uses a radio indicator: {args[0]}") + expected = args[1].lower() == "true" + checked = item.get_state_set().contains(Atspi.StateType.CHECKED) + if checked != expected: + raise RuntimeError( + f"Native menu item {args[0]!r} checked={checked}, " + f"expected {expected}") elif command == "choose": matches = [node for node in walk(app) if node.get_name() == args[0] diff --git a/tools/prepare_spelling_dictionaries.dart b/tools/prepare_spelling_dictionaries.dart new file mode 100644 index 00000000..52d74cff --- /dev/null +++ b/tools/prepare_spelling_dictionaries.dart @@ -0,0 +1,404 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; +import 'package:xml/xml.dart'; + +const sourceRevision = '32b006a2c22a4ac7e8ed3f03346f7b3d85a970a4'; +const selectedPackages = { + 'ar', + 'de', + 'en', + 'es', + 'et_EE', + 'fa_IR', + 'fr_FR', + 'hi_IN', + 'id', + 'it_IT', + 'ko_KR', + 'no', + 'nl_NL', + 'pl_PL', + 'pt_BR', + 'ru_RU', + 'tr_TR', + 'uk_UA', + 'vi', +}; + +const languageNames = { + 'ar': 'Arabic', + 'de': 'German', + 'en': 'English', + 'es': 'Spanish', + 'et': 'Estonian', + 'fa': 'Persian', + 'fr': 'French', + 'hi': 'Hindi', + 'id': 'Indonesian', + 'it': 'Italian', + 'ko': 'Korean', + 'nb': 'Norwegian Bokmål', + 'nn': 'Norwegian Nynorsk', + 'nl': 'Dutch', + 'pl': 'Polish', + 'pt': 'Portuguese', + 'ru': 'Russian', + 'tr': 'Turkish', + 'uk': 'Ukrainian', + 'vi': 'Vietnamese', +}; + +// These catalog-owned probes are intentionally ordinary headwords rather than +// an application-specific English token. Installation validates each exact +// resource against the probe for its language after Hunspell has loaded it. +const knownValidProbes = { + 'ar': 'بيت', + 'de': 'Haus', + 'en': 'house', + 'es': 'casa', + 'et': 'maja', + 'fa': 'خانه', + 'fr': 'maison', + 'hi': 'घर', + 'id': 'rumah', + 'it': 'casa', + 'ko': '사람', + 'nb': 'hus', + 'nn': 'hus', + 'nl': 'huis', + 'pl': 'dom', + 'pt': 'casa', + 'ru': 'дом', + 'tr': 'ev', + 'uk': 'дім', + 'vi': 'nhà', +}; + +Future main(List arguments) async { + if (arguments.length < 2 || + arguments.length > 3 || + (arguments.length == 3 && arguments[2] != '--include-pairs')) { + stderr.writeln( + 'Usage: dart run tools/prepare_spelling_dictionaries.dart ' + 'SOURCE OUTPUT [--include-pairs]', + ); + exitCode = 64; + return; + } + final source = Directory(p.normalize(p.absolute(arguments[0]))); + final output = Directory(p.normalize(p.absolute(arguments[1]))); + final includePairs = arguments.length == 3; + if (!source.existsSync()) { + throw FileSystemException( + 'Dictionary source directory is missing', + source.path, + ); + } + if (output.existsSync()) output.deleteSync(recursive: true); + output.createSync(recursive: true); + + final entries = <_Entry>[]; + final pairByFingerprint = {}; + final attributionPaths = {}; + for (final packageName in selectedPackages.toList()..sort()) { + final packageDirectory = Directory(p.join(source.path, packageName)); + final configuration = File( + p.join(packageDirectory.path, 'dictionaries.xcu'), + ); + if (!configuration.existsSync()) { + throw StateError('$packageName has no dictionaries.xcu'); + } + final document = XmlDocument.parse(configuration.readAsStringSync()); + var foundSpellingResource = false; + for (final node in document.descendants.whereType().where( + (element) => element.name.local == 'node', + )) { + final properties = {}; + for (final property in node.childElements.where( + (element) => element.name.local == 'prop', + )) { + final name = _attribute(property, 'name'); + if (name != null) properties[name] = property; + } + if (_value(properties['Format']) != 'DICT_SPELL') continue; + foundSpellingResource = true; + final locations = _value(properties['Locations']) + .split(RegExp(r'\s+')) + .where((value) => value.isNotEmpty) + .map((value) => value.replaceFirst('%origin%/', '')) + .toList(); + if (locations.length != 2 || + !locations.any((value) => value.endsWith('.aff')) || + !locations.any((value) => value.endsWith('.dic'))) { + throw StateError('Invalid DICT_SPELL pair in $packageName: $locations'); + } + final affSource = _locate( + packageDirectory, + locations.singleWhere((e) => e.endsWith('.aff')), + ); + final dicSource = _locate( + packageDirectory, + locations.singleWhere((e) => e.endsWith('.dic')), + ); + final locales = _value( + properties['Locales'], + ).split(RegExp(r'\s+')).where((value) => value.isNotEmpty).toList(); + if (locales.isEmpty) { + throw StateError('DICT_SPELL entry in $packageName has no locale'); + } + final affChecksum = _checksum(affSource); + final dicChecksum = _checksum(dicSource); + final fingerprint = '$affChecksum:$dicChecksum'; + final duplicate = pairByFingerprint[fingerprint]; + if (duplicate != null) { + duplicate.locales.addAll(locales); + continue; + } + final id = locales.first; + final affSourcePath = p.posix.joinAll( + p.split(p.relative(affSource.path, from: source.path)), + ); + final dicSourcePath = p.posix.joinAll( + p.split(p.relative(dicSource.path, from: source.path)), + ); + final entry = _Entry( + resourceId: id, + id: id, + locales: locales.toSet(), + label: _label(id), + affSourcePath: affSourcePath, + dicSourcePath: dicSourcePath, + affSize: affSource.lengthSync(), + dicSize: dicSource.lengthSync(), + affChecksum: affChecksum, + dicChecksum: dicChecksum, + sourcePackage: packageName, + affSource: affSource, + dicSource: dicSource, + knownValidProbe: + knownValidProbes[id.split('-').first.toLowerCase()] ?? + (throw StateError('No validation probe is defined for $id.')), + ); + entries.add(entry); + pairByFingerprint[fingerprint] = entry; + } + if (!foundSpellingResource) { + throw StateError('$packageName declares no DICT_SPELL resource'); + } + for (final entity + in packageDirectory.listSync(recursive: true).whereType()) { + final basename = p.basename(entity.path).toLowerCase(); + if (!RegExp(r'(license|licence|copying|readme)').hasMatch(basename)) { + continue; + } + final relativeInsidePackage = p.relative( + entity.path, + from: packageDirectory.path, + ); + final destination = p.join( + 'licenses', + packageName, + relativeInsidePackage, + ); + File(p.join(output.path, destination)).parent.createSync(recursive: true); + entity.copySync(p.join(output.path, destination)); + attributionPaths.add(p.posix.joinAll(p.split(destination))); + } + } + entries.sort((left, right) => left.label.compareTo(right.label)); + if (includePairs) { + for (final entry in entries) { + _publishTestInstallation( + output: output, + entry: entry, + affSource: entry.affSource, + dicSource: entry.dicSource, + ); + } + } + final manifest = { + 'schemaVersion': 2, + 'source': { + 'name': 'LibreOffice dictionaries', + 'url': 'https://github.com/LibreOffice/dictionaries', + 'revision': sourceRevision, + 'archiveSha256': + 'cbd790eca560de5e8ec8bd64117a00dfd0bc06b091c8f52d23e44ea00d3e8461', + }, + 'dictionaries': entries.map((entry) => entry.toJson()).toList(), + 'attributions': attributionPaths.toList()..sort(), + }; + File(p.join(output.path, 'dictionaries.json')).writeAsStringSync( + '${const JsonEncoder.withIndent(' ').convert(manifest)}\n', + flush: true, + ); + File(p.join(output.path, 'NOTICE')).writeAsStringSync( + 'LibreOffice dictionary data\nRevision: $sourceRevision\n' + 'Each dictionary remains under the terms recorded in licenses/.\n', + flush: true, + ); + File( + p.join(output.path, 'VERSION'), + ).writeAsStringSync('$sourceRevision\n', flush: true); + final checksummedFiles = + output + .listSync(recursive: true) + .whereType() + .where((file) => p.basename(file.path) != 'CHECKSUMS.sha256') + .toList() + ..sort((left, right) => left.path.compareTo(right.path)); + File(p.join(output.path, 'CHECKSUMS.sha256')).writeAsStringSync( + [ + for (final file in checksummedFiles) + '${_checksum(file)} ${p.posix.joinAll(p.split(p.relative(file.path, from: output.path)))}', + '', + ].join('\n'), + flush: true, + ); +} + +String? _attribute(XmlElement element, String localName) { + for (final attribute in element.attributes) { + if (attribute.name.local == localName) return attribute.value; + } + return null; +} + +String _value(XmlElement? property) { + if (property == null) return ''; + final values = []; + for (final value in property.childElements.where( + (element) => element.name.local == 'value', + )) { + final items = value.descendants + .whereType() + .where((element) => element.name.local == 'it') + .map((element) => element.innerText.trim()) + .where((text) => text.isNotEmpty) + .toList(); + if (items.isNotEmpty) { + values.addAll(items); + } else if (value.innerText.trim() case final text when text.isNotEmpty) { + values.add(text); + } + } + return values.join(' ').trim(); +} + +File _locate(Directory packageDirectory, String configuredPath) { + final direct = File(p.join(packageDirectory.path, configuredPath)); + if (direct.existsSync()) return direct; + final basename = p.basename(configuredPath); + final candidates = packageDirectory + .listSync(recursive: true) + .whereType() + .where((file) => p.basename(file.path) == basename) + .toList(); + if (candidates.length != 1) { + throw StateError( + 'Could not resolve $configuredPath in ${packageDirectory.path}', + ); + } + return candidates.single; +} + +String _checksum(File file) => + sha256.convert(file.readAsBytesSync()).toString(); + +String _safeName(String value) => + value.replaceAll(RegExp(r'[^A-Za-z0-9._-]'), '_'); + +String _label(String locale) { + final language = locale.split('-').first.toLowerCase(); + final name = languageNames[language] ?? language; + return locale.contains('-') ? '$name ($locale)' : name; +} + +final class _Entry { + _Entry({ + required this.resourceId, + required this.id, + required this.locales, + required this.label, + required this.affSourcePath, + required this.dicSourcePath, + required this.affSize, + required this.dicSize, + required this.affChecksum, + required this.dicChecksum, + required this.sourcePackage, + required this.affSource, + required this.dicSource, + required this.knownValidProbe, + }); + + final String resourceId; + final String id; + final Set locales; + final String label; + final String affSourcePath; + final String dicSourcePath; + final int affSize; + final int dicSize; + final String affChecksum; + final String dicChecksum; + final String sourcePackage; + final File affSource; + final File dicSource; + final String knownValidProbe; + + Map toJson() => { + 'resourceId': resourceId, + 'id': id, + 'knownValidProbe': knownValidProbe, + 'locales': locales.toList()..sort(), + 'label': label, + 'affSourcePath': affSourcePath, + 'dicSourcePath': dicSourcePath, + 'affDownloadUrl': + 'https://raw.githubusercontent.com/LibreOffice/dictionaries/' + '$sourceRevision/$affSourcePath', + 'dicDownloadUrl': + 'https://raw.githubusercontent.com/LibreOffice/dictionaries/' + '$sourceRevision/$dicSourcePath', + 'affSize': affSize, + 'dicSize': dicSize, + 'sourceRevision': sourceRevision, + 'affSha256': affChecksum, + 'dicSha256': dicChecksum, + 'licenseDirectory': 'licenses/$sourcePackage', + }; +} + +void _publishTestInstallation({ + required Directory output, + required _Entry entry, + required File affSource, + required File dicSource, +}) { + final relativeDirectory = p.join('installed', _safeName(entry.resourceId)); + final directory = Directory(p.join(output.path, relativeDirectory)) + ..createSync(recursive: true); + affSource.copySync(p.join(directory.path, 'dictionary.aff')); + dicSource.copySync(p.join(directory.path, 'dictionary.dic')); + final manifest = { + 'schemaVersion': 1, + 'kind': 'downloaded', + 'resourceId': entry.resourceId, + 'id': entry.id, + 'locales': entry.locales.toList()..sort(), + 'label': entry.label, + 'sourceRevision': sourceRevision, + 'affPath': 'dictionary.aff', + 'dicPath': 'dictionary.dic', + 'affSha256': entry.affChecksum, + 'dicSha256': entry.dicChecksum, + }; + File(p.join(directory.path, 'manifest.json')).writeAsStringSync( + '${const JsonEncoder.withIndent(' ').convert(manifest)}\n', + flush: true, + ); +} diff --git a/tools/writerside_toc_visual_smoke.dart b/tools/writerside_toc_visual_smoke.dart index 3f866e7e..8f5de025 100644 --- a/tools/writerside_toc_visual_smoke.dart +++ b/tools/writerside_toc_visual_smoke.dart @@ -109,12 +109,17 @@ class _HarnessState extends ConsumerState<_Harness> { var _pointer = 0; var _nativeMenuOpen = false; - Future _native(String command, [String? argument]) async { + Future _native( + String command, [ + String? argument, + String? secondArgument, + ]) async { final result = await Process.run('/usr/bin/python3', [ p.absolute('tools/linux_native_menu_probe.py'), '$pid', command, ?argument, + ?secondArgument, ]); if (result.exitCode != 0) { throw StateError('Native $command failed: ${result.stderr}'); @@ -1240,7 +1245,7 @@ class _HarnessState extends ConsumerState<_Harness> { (await current).selectedIndex == null, 'Native menu session dismissal returns cancellation', ); - final radio = service.show( + final selector = service.show( session: NativeMenuSession(), anchor: const Rect.fromLTWH(600, 180, 80, 24), focusFirst: true, @@ -1249,16 +1254,30 @@ class _HarnessState extends ConsumerState<_Harness> { label: 'First format', checkable: true, selected: true, + mutuallyExclusive: true, + ), + NativeMenuEntry.command( + label: 'Second format', + checkable: true, + mutuallyExclusive: true, + ), + NativeMenuEntry.separator(), + NativeMenuEntry.command( + label: 'Full Screen', + checkable: true, + selected: true, ), - NativeMenuEntry.command(label: 'Second format', checkable: true), ], ); await _pause(); + await _native('assert-check', 'First format', 'true'); + await _native('assert-check', 'Second format', 'false'); + await _native('assert-check', 'Full Screen', 'true'); await _native('key', 'Down'); await _native('key', 'Return'); _check( - (await radio.timeout(const Duration(seconds: 5))).selectedIndex == 1, - 'Existing flat native single-choice selectors still return their row index', + (await selector.timeout(const Duration(seconds: 5))).selectedIndex == 1, + 'GTK checkmark selectors still return their exact row index', ); } }