summaryrefslogtreecommitdiffstats
path: root/intl/unicharutil/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /intl/unicharutil/util
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'intl/unicharutil/util')
-rw-r--r--intl/unicharutil/util/GreekCasing.cpp315
-rw-r--r--intl/unicharutil/util/GreekCasing.h64
-rw-r--r--intl/unicharutil/util/ICUUtils.cpp269
-rw-r--r--intl/unicharutil/util/ICUUtils.h92
-rw-r--r--intl/unicharutil/util/IrishCasing.cpp262
-rw-r--r--intl/unicharutil/util/IrishCasing.h101
-rw-r--r--intl/unicharutil/util/moz.build28
-rw-r--r--intl/unicharutil/util/nsBidiUtils.cpp88
-rw-r--r--intl/unicharutil/util/nsBidiUtils.h295
-rw-r--r--intl/unicharutil/util/nsSpecialCasingData.cpp202
-rw-r--r--intl/unicharutil/util/nsSpecialCasingData.h26
-rw-r--r--intl/unicharutil/util/nsUnicharUtils.cpp521
-rw-r--r--intl/unicharutil/util/nsUnicharUtils.h160
-rw-r--r--intl/unicharutil/util/nsUnicodeProperties.cpp387
-rw-r--r--intl/unicharutil/util/nsUnicodeProperties.h283
-rw-r--r--intl/unicharutil/util/nsUnicodePropertyData.cpp206
-rw-r--r--intl/unicharutil/util/nsUnicodeScriptCodes.h267
17 files changed, 3566 insertions, 0 deletions
diff --git a/intl/unicharutil/util/GreekCasing.cpp b/intl/unicharutil/util/GreekCasing.cpp
new file mode 100644
index 0000000000..5c7e7d506e
--- /dev/null
+++ b/intl/unicharutil/util/GreekCasing.cpp
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "GreekCasing.h"
+#include "nsUnicharUtils.h"
+#include "nsUnicodeProperties.h"
+
+// Custom uppercase mapping for Greek; see bug 307039 for details
+#define GREEK_LOWER_ALPHA 0x03B1
+#define GREEK_LOWER_ALPHA_TONOS 0x03AC
+#define GREEK_LOWER_ALPHA_OXIA 0x1F71
+#define GREEK_LOWER_EPSILON 0x03B5
+#define GREEK_LOWER_EPSILON_TONOS 0x03AD
+#define GREEK_LOWER_EPSILON_OXIA 0x1F73
+#define GREEK_LOWER_ETA 0x03B7
+#define GREEK_LOWER_ETA_TONOS 0x03AE
+#define GREEK_LOWER_ETA_OXIA 0x1F75
+#define GREEK_LOWER_IOTA 0x03B9
+#define GREEK_LOWER_IOTA_TONOS 0x03AF
+#define GREEK_LOWER_IOTA_OXIA 0x1F77
+#define GREEK_LOWER_IOTA_DIALYTIKA 0x03CA
+#define GREEK_LOWER_IOTA_DIALYTIKA_TONOS 0x0390
+#define GREEK_LOWER_IOTA_DIALYTIKA_OXIA 0x1FD3
+#define GREEK_LOWER_OMICRON 0x03BF
+#define GREEK_LOWER_OMICRON_TONOS 0x03CC
+#define GREEK_LOWER_OMICRON_OXIA 0x1F79
+#define GREEK_LOWER_UPSILON 0x03C5
+#define GREEK_LOWER_UPSILON_TONOS 0x03CD
+#define GREEK_LOWER_UPSILON_OXIA 0x1F7B
+#define GREEK_LOWER_UPSILON_DIALYTIKA 0x03CB
+#define GREEK_LOWER_UPSILON_DIALYTIKA_TONOS 0x03B0
+#define GREEK_LOWER_UPSILON_DIALYTIKA_OXIA 0x1FE3
+#define GREEK_LOWER_OMEGA 0x03C9
+#define GREEK_LOWER_OMEGA_TONOS 0x03CE
+#define GREEK_LOWER_OMEGA_OXIA 0x1F7D
+#define GREEK_UPPER_ALPHA 0x0391
+#define GREEK_UPPER_EPSILON 0x0395
+#define GREEK_UPPER_ETA 0x0397
+#define GREEK_UPPER_IOTA 0x0399
+#define GREEK_UPPER_IOTA_DIALYTIKA 0x03AA
+#define GREEK_UPPER_OMICRON 0x039F
+#define GREEK_UPPER_UPSILON 0x03A5
+#define GREEK_UPPER_UPSILON_DIALYTIKA 0x03AB
+#define GREEK_UPPER_OMEGA 0x03A9
+#define GREEK_UPPER_ALPHA_TONOS 0x0386
+#define GREEK_UPPER_ALPHA_OXIA 0x1FBB
+#define GREEK_UPPER_EPSILON_TONOS 0x0388
+#define GREEK_UPPER_EPSILON_OXIA 0x1FC9
+#define GREEK_UPPER_ETA_TONOS 0x0389
+#define GREEK_UPPER_ETA_OXIA 0x1FCB
+#define GREEK_UPPER_IOTA_TONOS 0x038A
+#define GREEK_UPPER_IOTA_OXIA 0x1FDB
+#define GREEK_UPPER_OMICRON_TONOS 0x038C
+#define GREEK_UPPER_OMICRON_OXIA 0x1FF9
+#define GREEK_UPPER_UPSILON_TONOS 0x038E
+#define GREEK_UPPER_UPSILON_OXIA 0x1FEB
+#define GREEK_UPPER_OMEGA_TONOS 0x038F
+#define GREEK_UPPER_OMEGA_OXIA 0x1FFB
+#define COMBINING_ACUTE_ACCENT 0x0301
+#define COMBINING_DIAERESIS 0x0308
+#define COMBINING_ACUTE_TONE_MARK 0x0341
+#define COMBINING_GREEK_DIALYTIKA_TONOS 0x0344
+
+namespace mozilla {
+
+uint32_t GreekCasing::UpperCase(uint32_t aCh, GreekCasing::State& aState,
+ bool& aMarkEtaPos, bool& aUpdateMarkedEta) {
+ aMarkEtaPos = false;
+ aUpdateMarkedEta = false;
+
+ uint8_t category = unicode::GetGeneralCategory(aCh);
+
+ if (aState == kEtaAccMarked) {
+ switch (category) {
+ case HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK:
+ case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK:
+ case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK:
+ aUpdateMarkedEta = true;
+ break;
+ default:
+ break;
+ }
+ aState = kEtaAcc;
+ }
+
+ switch (aCh) {
+ case GREEK_UPPER_ALPHA:
+ case GREEK_LOWER_ALPHA:
+ aState = kAlpha;
+ return GREEK_UPPER_ALPHA;
+
+ case GREEK_UPPER_EPSILON:
+ case GREEK_LOWER_EPSILON:
+ aState = kEpsilon;
+ return GREEK_UPPER_EPSILON;
+
+ case GREEK_UPPER_ETA:
+ case GREEK_LOWER_ETA:
+ aState = kEta;
+ return GREEK_UPPER_ETA;
+
+ case GREEK_UPPER_IOTA:
+ aState = kIota;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_UPPER_OMICRON:
+ case GREEK_LOWER_OMICRON:
+ aState = kOmicron;
+ return GREEK_UPPER_OMICRON;
+
+ case GREEK_UPPER_UPSILON:
+ switch (aState) {
+ case kOmicron:
+ aState = kOmicronUpsilon;
+ break;
+ default:
+ aState = kUpsilon;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_UPPER_OMEGA:
+ case GREEK_LOWER_OMEGA:
+ aState = kOmega;
+ return GREEK_UPPER_OMEGA;
+
+ // iota and upsilon may be the second vowel of a diphthong
+ case GREEK_LOWER_IOTA:
+ switch (aState) {
+ case kAlphaAcc:
+ case kEpsilonAcc:
+ case kOmicronAcc:
+ case kUpsilonAcc:
+ aState = kInWord;
+ return GREEK_UPPER_IOTA_DIALYTIKA;
+ default:
+ break;
+ }
+ aState = kIota;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_LOWER_UPSILON:
+ switch (aState) {
+ case kAlphaAcc:
+ case kEpsilonAcc:
+ case kEtaAcc:
+ case kOmicronAcc:
+ aState = kInWord;
+ return GREEK_UPPER_UPSILON_DIALYTIKA;
+ case kOmicron:
+ aState = kOmicronUpsilon;
+ break;
+ default:
+ aState = kUpsilon;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_UPPER_IOTA_DIALYTIKA:
+ case GREEK_LOWER_IOTA_DIALYTIKA:
+ case GREEK_UPPER_UPSILON_DIALYTIKA:
+ case GREEK_LOWER_UPSILON_DIALYTIKA:
+ case COMBINING_DIAERESIS:
+ aState = kDiaeresis;
+ return ToUpperCase(aCh);
+
+ // remove accent if it follows a vowel or diaeresis,
+ // and set appropriate state for diphthong detection
+ case COMBINING_ACUTE_ACCENT:
+ case COMBINING_ACUTE_TONE_MARK:
+ switch (aState) {
+ case kAlpha:
+ aState = kAlphaAcc;
+ return uint32_t(-1); // omit this char from result string
+ case kEpsilon:
+ aState = kEpsilonAcc;
+ return uint32_t(-1);
+ case kEta:
+ aState = kEtaAcc;
+ return uint32_t(-1);
+ case kIota:
+ aState = kIotaAcc;
+ return uint32_t(-1);
+ case kOmicron:
+ aState = kOmicronAcc;
+ return uint32_t(-1);
+ case kUpsilon:
+ aState = kUpsilonAcc;
+ return uint32_t(-1);
+ case kOmicronUpsilon:
+ aState = kInWord; // this completed a diphthong
+ return uint32_t(-1);
+ case kOmega:
+ aState = kOmegaAcc;
+ return uint32_t(-1);
+ case kDiaeresis:
+ aState = kInWord;
+ return uint32_t(-1);
+ default:
+ break;
+ }
+ break;
+
+ // combinations with dieresis+accent just strip the accent,
+ // and reset to start state (don't form diphthong with following vowel)
+ case GREEK_LOWER_IOTA_DIALYTIKA_TONOS:
+ case GREEK_LOWER_IOTA_DIALYTIKA_OXIA:
+ aState = kInWord;
+ return GREEK_UPPER_IOTA_DIALYTIKA;
+
+ case GREEK_LOWER_UPSILON_DIALYTIKA_TONOS:
+ case GREEK_LOWER_UPSILON_DIALYTIKA_OXIA:
+ aState = kInWord;
+ return GREEK_UPPER_UPSILON_DIALYTIKA;
+
+ case COMBINING_GREEK_DIALYTIKA_TONOS:
+ aState = kInWord;
+ return COMBINING_DIAERESIS;
+
+ // strip accents from vowels, and note the vowel seen so that we can detect
+ // diphthongs where diaeresis needs to be added
+ case GREEK_LOWER_ALPHA_TONOS:
+ case GREEK_LOWER_ALPHA_OXIA:
+ case GREEK_UPPER_ALPHA_TONOS:
+ case GREEK_UPPER_ALPHA_OXIA:
+ aState = kAlphaAcc;
+ return GREEK_UPPER_ALPHA;
+
+ case GREEK_LOWER_EPSILON_TONOS:
+ case GREEK_LOWER_EPSILON_OXIA:
+ case GREEK_UPPER_EPSILON_TONOS:
+ case GREEK_UPPER_EPSILON_OXIA:
+ aState = kEpsilonAcc;
+ return GREEK_UPPER_EPSILON;
+
+ case GREEK_LOWER_ETA_TONOS:
+ case GREEK_UPPER_ETA_TONOS:
+ if (aState == kStart) {
+ aState = kEtaAccMarked;
+ aMarkEtaPos = true; // mark in case we need to remove the tonos later
+ return GREEK_UPPER_ETA_TONOS; // treat as disjunctive eta for now
+ }
+ // if not in initial state, fall through to strip the accent
+ [[fallthrough]];
+
+ case GREEK_LOWER_ETA_OXIA:
+ case GREEK_UPPER_ETA_OXIA:
+ aState = kEtaAcc;
+ return GREEK_UPPER_ETA;
+
+ case GREEK_LOWER_IOTA_TONOS:
+ case GREEK_LOWER_IOTA_OXIA:
+ case GREEK_UPPER_IOTA_TONOS:
+ case GREEK_UPPER_IOTA_OXIA:
+ aState = kIotaAcc;
+ return GREEK_UPPER_IOTA;
+
+ case GREEK_LOWER_OMICRON_TONOS:
+ case GREEK_LOWER_OMICRON_OXIA:
+ case GREEK_UPPER_OMICRON_TONOS:
+ case GREEK_UPPER_OMICRON_OXIA:
+ aState = kOmicronAcc;
+ return GREEK_UPPER_OMICRON;
+
+ case GREEK_LOWER_UPSILON_TONOS:
+ case GREEK_LOWER_UPSILON_OXIA:
+ case GREEK_UPPER_UPSILON_TONOS:
+ case GREEK_UPPER_UPSILON_OXIA:
+ switch (aState) {
+ case kOmicron:
+ aState = kInWord; // this completed a diphthong
+ break;
+ default:
+ aState = kUpsilonAcc;
+ break;
+ }
+ return GREEK_UPPER_UPSILON;
+
+ case GREEK_LOWER_OMEGA_TONOS:
+ case GREEK_LOWER_OMEGA_OXIA:
+ case GREEK_UPPER_OMEGA_TONOS:
+ case GREEK_UPPER_OMEGA_OXIA:
+ aState = kOmegaAcc;
+ return GREEK_UPPER_OMEGA;
+ }
+
+ // all other characters just reset the state to either kStart or kInWord,
+ // and use standard mappings
+ switch (category) {
+ case HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER:
+ case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK:
+ case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK:
+ case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK:
+ aState = kInWord;
+ break;
+ default:
+ aState = kStart;
+ break;
+ }
+
+ return ToUpperCase(aCh);
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/GreekCasing.h b/intl/unicharutil/util/GreekCasing.h
new file mode 100644
index 0000000000..f46f607e05
--- /dev/null
+++ b/intl/unicharutil/util/GreekCasing.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef GreekCasing_h_
+#define GreekCasing_h_
+
+#include <stdint.h>
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+
+class GreekCasing {
+ // When doing an Uppercase transform in Greek, we need to keep track of the
+ // current state while iterating through the string, to recognize and process
+ // diphthongs correctly. For clarity, we define a state for each vowel and
+ // each vowel with accent, although a few of these do not actually need any
+ // special treatment and could be folded into kStart.
+ private:
+ enum GreekStates {
+ kStart,
+ kInWord,
+ kAlpha,
+ kEpsilon,
+ kEta,
+ kIota,
+ kOmicron,
+ kUpsilon,
+ kOmega,
+ kAlphaAcc,
+ kEpsilonAcc,
+ kEtaAcc,
+ kEtaAccMarked,
+ kIotaAcc,
+ kOmicronAcc,
+ kUpsilonAcc,
+ kOmegaAcc,
+ kOmicronUpsilon,
+ kDiaeresis
+ };
+
+ public:
+ class State {
+ public:
+ State() : mState(kStart) {}
+
+ MOZ_IMPLICIT State(const GreekStates& aState) : mState(aState) {}
+
+ void Reset() { mState = kStart; }
+
+ operator GreekStates() const { return mState; }
+
+ private:
+ GreekStates mState;
+ };
+
+ static uint32_t UpperCase(uint32_t aCh, State& aState, bool& aMarkEtaPos,
+ bool& aUpdateMarkedEta);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/intl/unicharutil/util/ICUUtils.cpp b/intl/unicharutil/util/ICUUtils.cpp
new file mode 100644
index 0000000000..3aa0b84ac4
--- /dev/null
+++ b/intl/unicharutil/util/ICUUtils.cpp
@@ -0,0 +1,269 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifdef MOZILLA_INTERNAL_API
+
+# include "mozilla/Assertions.h"
+# include "mozilla/UniquePtr.h"
+
+# include "ICUUtils.h"
+# include "mozilla/StaticPrefs_dom.h"
+# include "mozilla/intl/LocaleService.h"
+# include "nsIContent.h"
+# include "mozilla/dom/Document.h"
+# include "nsString.h"
+# include "unicode/uloc.h"
+# include "unicode/unum.h"
+
+using namespace mozilla;
+using mozilla::intl::LocaleService;
+
+class NumberFormatDeleter {
+ public:
+ void operator()(UNumberFormat* aPtr) {
+ MOZ_ASSERT(aPtr != nullptr,
+ "UniquePtr deleter shouldn't be called for nullptr");
+ unum_close(aPtr);
+ }
+};
+
+using UniqueUNumberFormat = UniquePtr<UNumberFormat, NumberFormatDeleter>;
+
+void ICUUtils::LanguageTagIterForContent::GetNext(nsACString& aBCP47LangTag) {
+ if (mCurrentFallbackIndex < 0) {
+ mCurrentFallbackIndex = 0;
+ // Try the language specified by a 'lang'/'xml:lang' attribute on mContent
+ // or any ancestor, if such an attribute is specified:
+ nsAutoString lang;
+ mContent->GetLang(lang);
+ if (!lang.IsEmpty()) {
+ CopyUTF16toUTF8(lang, aBCP47LangTag);
+ return;
+ }
+ }
+
+ if (mCurrentFallbackIndex < 1) {
+ mCurrentFallbackIndex = 1;
+ // Else try the language specified by any Content-Language HTTP header or
+ // pragma directive:
+ nsAutoString lang;
+ mContent->OwnerDoc()->GetContentLanguage(lang);
+ if (!lang.IsEmpty()) {
+ CopyUTF16toUTF8(lang, aBCP47LangTag);
+ return;
+ }
+ }
+
+ if (mCurrentFallbackIndex < 2) {
+ mCurrentFallbackIndex = 2;
+ // Else take the app's locale:
+
+ nsAutoCString appLocale;
+ LocaleService::GetInstance()->GetAppLocaleAsBCP47(aBCP47LangTag);
+ return;
+ }
+
+ // TODO: Probably not worth it, but maybe have a fourth fallback to using
+ // the OS locale?
+
+ aBCP47LangTag.Truncate(); // Signal iterator exhausted
+}
+
+/* static */
+bool ICUUtils::LocalizeNumber(double aValue,
+ LanguageTagIterForContent& aLangTags,
+ nsAString& aLocalizedValue) {
+ MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
+
+ static const int32_t kBufferSize = 256;
+
+ UChar buffer[kBufferSize];
+
+ nsAutoCString langTag;
+ aLangTags.GetNext(langTag);
+ while (!langTag.IsEmpty()) {
+ UErrorCode status = U_ZERO_ERROR;
+ UniqueUNumberFormat format(
+ unum_open(UNUM_DECIMAL, nullptr, 0, langTag.get(), nullptr, &status));
+ // Since unum_setAttribute have no UErrorCode parameter, we have to
+ // check error status.
+ if (U_FAILURE(status)) {
+ aLangTags.GetNext(langTag);
+ continue;
+ }
+ unum_setAttribute(format.get(), UNUM_GROUPING_USED,
+ StaticPrefs::dom_forms_number_grouping());
+ // ICU default is a maximum of 3 significant fractional digits. We don't
+ // want that limit, so we set it to the maximum that a double can represent
+ // (14-16 decimal fractional digits).
+ unum_setAttribute(format.get(), UNUM_MAX_FRACTION_DIGITS, 16);
+ int32_t length = unum_formatDouble(format.get(), aValue, buffer,
+ kBufferSize, nullptr, &status);
+ NS_ASSERTION(length < kBufferSize && status != U_BUFFER_OVERFLOW_ERROR &&
+ status != U_STRING_NOT_TERMINATED_WARNING,
+ "Need a bigger buffer?!");
+ if (U_SUCCESS(status)) {
+ ICUUtils::AssignUCharArrayToString(buffer, length, aLocalizedValue);
+ return true;
+ }
+ aLangTags.GetNext(langTag);
+ }
+ return false;
+}
+
+/* static */
+double ICUUtils::ParseNumber(nsAString& aValue,
+ LanguageTagIterForContent& aLangTags) {
+ MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
+
+ if (aValue.IsEmpty()) {
+ return std::numeric_limits<float>::quiet_NaN();
+ }
+
+ uint32_t length = aValue.Length();
+
+ nsAutoCString langTag;
+ aLangTags.GetNext(langTag);
+ while (!langTag.IsEmpty()) {
+ UErrorCode status = U_ZERO_ERROR;
+ UniqueUNumberFormat format(
+ unum_open(UNUM_DECIMAL, nullptr, 0, langTag.get(), nullptr, &status));
+ if (!StaticPrefs::dom_forms_number_grouping()) {
+ unum_setAttribute(format.get(), UNUM_GROUPING_USED, UBool(0));
+ }
+ int32_t parsePos = 0;
+ static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
+ "Unexpected character size - the following cast is unsafe");
+ double val = unum_parseDouble(format.get(),
+ (const UChar*)PromiseFlatString(aValue).get(),
+ length, &parsePos, &status);
+ if (U_SUCCESS(status) && parsePos == (int32_t)length) {
+ return val;
+ }
+ aLangTags.GetNext(langTag);
+ }
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+/* static */
+void ICUUtils::AssignUCharArrayToString(UChar* aICUString, int32_t aLength,
+ nsAString& aMozString) {
+ // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
+ // cast here.
+
+ static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
+ "Unexpected character size - the following cast is unsafe");
+
+ aMozString.Assign((const nsAString::char_type*)aICUString, aLength);
+
+ NS_ASSERTION((int32_t)aMozString.Length() == aLength, "Conversion failed");
+}
+
+/* static */
+nsresult ICUUtils::UErrorToNsResult(const UErrorCode aErrorCode) {
+ if (U_SUCCESS(aErrorCode)) {
+ return NS_OK;
+ }
+
+ switch (aErrorCode) {
+ case U_ILLEGAL_ARGUMENT_ERROR:
+ return NS_ERROR_INVALID_ARG;
+
+ case U_MEMORY_ALLOCATION_ERROR:
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ default:
+ return NS_ERROR_FAILURE;
+ }
+}
+
+# if 0
+/* static */
+Locale
+ICUUtils::BCP47CodeToLocale(const nsAString& aBCP47Code)
+{
+ MOZ_ASSERT(!aBCP47Code.IsEmpty(), "Don't pass an empty BCP 47 code");
+
+ Locale locale;
+ locale.setToBogus();
+
+ // BCP47 codes are guaranteed to be ASCII, so lossy conversion is okay
+ NS_LossyConvertUTF16toASCII bcp47code(aBCP47Code);
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t needed;
+
+ char localeID[256];
+ needed = uloc_forLanguageTag(bcp47code.get(), localeID,
+ PR_ARRAY_SIZE(localeID) - 1, nullptr,
+ &status);
+ MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(localeID)) - 1,
+ "Need a bigger buffer");
+ if (needed <= 0 || U_FAILURE(status)) {
+ return locale;
+ }
+
+ char lang[64];
+ needed = uloc_getLanguage(localeID, lang, PR_ARRAY_SIZE(lang) - 1,
+ &status);
+ MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(lang)) - 1,
+ "Need a bigger buffer");
+ if (needed <= 0 || U_FAILURE(status)) {
+ return locale;
+ }
+
+ char country[64];
+ needed = uloc_getCountry(localeID, country, PR_ARRAY_SIZE(country) - 1,
+ &status);
+ MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(country)) - 1,
+ "Need a bigger buffer");
+ if (needed > 0 && U_SUCCESS(status)) {
+ locale = Locale(lang, country);
+ }
+
+ if (locale.isBogus()) {
+ // Using the country resulted in a bogus Locale, so try with only the lang
+ locale = Locale(lang);
+ }
+
+ return locale;
+}
+
+/* static */
+void
+ICUUtils::ToMozString(UnicodeString& aICUString, nsAString& aMozString)
+{
+ // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
+ // cast here.
+
+ static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
+ "Unexpected character size - the following cast is unsafe");
+
+ const nsAString::char_type* buf =
+ (const nsAString::char_type*)aICUString.getTerminatedBuffer();
+ aMozString.Assign(buf);
+
+ NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(),
+ "Conversion failed");
+}
+
+/* static */
+void
+ICUUtils::ToICUString(nsAString& aMozString, UnicodeString& aICUString)
+{
+ // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
+ // cast here.
+
+ static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
+ "Unexpected character size - the following cast is unsafe");
+
+ aICUString.setTo((UChar*)PromiseFlatString(aMozString).get(),
+ aMozString.Length());
+
+ NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(),
+ "Conversion failed");
+}
+# endif
+
+#endif /* MOZILLA_INTERNAL_API */
diff --git a/intl/unicharutil/util/ICUUtils.h b/intl/unicharutil/util/ICUUtils.h
new file mode 100644
index 0000000000..6d14c604eb
--- /dev/null
+++ b/intl/unicharutil/util/ICUUtils.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ICUUtils_h__
+#define mozilla_ICUUtils_h__
+
+// The ICU utils implementation needs internal things like XPCOM strings and
+// nsGkAtom, so we only build when included into internal libs:
+#ifdef MOZILLA_INTERNAL_API
+
+# include "nsString.h"
+# include "unicode/unum.h" // for UNumberFormat
+
+class nsIContent;
+
+class ICUUtils {
+ public:
+ /**
+ * This class is used to encapsulate an nsIContent object to allow lazy
+ * iteration over its primary and fallback BCP 47 language tags.
+ */
+ class LanguageTagIterForContent {
+ public:
+ explicit LanguageTagIterForContent(nsIContent* aContent)
+ : mContent(aContent), mCurrentFallbackIndex(-1) {}
+
+ /**
+ * Used to iterate over the nsIContent object's primary language tag and
+ * its fallbacks tags. The following sources of language tag information
+ * are tried in turn:
+ *
+ * 1) the "lang" of the nsIContent object (which is based on the 'lang'/
+ * 'xml:lang' attribute on itself or the nearest ancestor to have such
+ * an attribute, if any);
+ * 2) the Content-Language HTTP pragma directive or HTTP header;
+ * 3) the configured language tag of the user-agent.
+ *
+ * Once all fallbacks have been exhausted then this function will set
+ * aBCP47LangTag to the empty string.
+ */
+ void GetNext(nsACString& aBCP47LangTag);
+
+ bool IsAtStart() const { return mCurrentFallbackIndex < 0; }
+
+ private:
+ nsIContent* mContent;
+ int8_t mCurrentFallbackIndex;
+ };
+
+ /**
+ * Attempts to localize aValue and return the result via the aLocalizedValue
+ * outparam. Returns true on success. Returns false on failure, in which
+ * case aLocalizedValue will be untouched.
+ */
+ static bool LocalizeNumber(double aValue,
+ LanguageTagIterForContent& aLangTags,
+ nsAString& aLocalizedValue);
+
+ /**
+ * Parses the localized number that is serialized in aValue using aLangTags
+ * and returns the result as a double. Returns NaN on failure.
+ */
+ static double ParseNumber(nsAString& aValue,
+ LanguageTagIterForContent& aLangTags);
+
+ static void AssignUCharArrayToString(UChar* aICUString, int32_t aLength,
+ nsAString& aMozString);
+
+ /**
+ * Map ICU UErrorCode to nsresult
+ */
+ static nsresult UErrorToNsResult(const UErrorCode aErrorCode);
+
+# if 0
+ // Currently disabled because using C++ API doesn't play nicely with enabling
+ // system ICU.
+
+ /**
+ * Converts an IETF BCP 47 language code to an ICU Locale.
+ */
+ static Locale BCP47CodeToLocale(const nsAString& aBCP47Code);
+
+ static void ToMozString(UnicodeString& aICUString, nsAString& aMozString);
+ static void ToICUString(nsAString& aMozString, UnicodeString& aICUString);
+# endif
+};
+
+#endif /* MOZILLA_INTERNAL_API */
+
+#endif /* mozilla_ICUUtils_h__ */
diff --git a/intl/unicharutil/util/IrishCasing.cpp b/intl/unicharutil/util/IrishCasing.cpp
new file mode 100644
index 0000000000..5de8a529ae
--- /dev/null
+++ b/intl/unicharutil/util/IrishCasing.cpp
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+/******************************************************************************
+
+This file provides a finite state machine to support Irish Gaelic uppercasing
+rules.
+
+The caller will need to iterate through a string, passing a State variable
+along with the current character to each UpperCase call and checking the flags
+that are returned:
+
+ If aMarkPos is true, caller must remember the current index in the string as
+ a possible target for a future action.
+
+ If aAction is non-zero, then one or more characters from the marked index are
+ to be modified:
+ 1 lowercase the marked letter
+ 2 lowercase the marked letter and its successor
+ 3 lowercase the marked letter, and delete its successor
+
+
+### Rules from https://bugzilla.mozilla.org/show_bug.cgi?id=1014639,
+### comments 1 and 4:
+
+v = [a,á,e,é,i,í,o,ó,u,ú]
+V = [A,Á,E,É,I,Í,O,Ó,U,Ú]
+
+bhf -> bhF
+bhF -> bhF
+bp -> bP
+bP -> bP
+dt -> dT
+dT -> dT
+gc -> gC
+gC -> gC
+h{V} -> h{V}
+mb -> mB
+mB -> mB
+n-{v} -> n{V}
+n{V} -> n{V}
+nd -> nD
+nD -> nD
+ng -> nG
+nG -> nG
+t-{v} -> t{V}
+t{V} -> t{V}
+ts{v} -> tS{V}
+tS{v} -> tS{V}
+tS{V} -> tS{V}
+tsl -> tSL
+tSl -> tSL
+tSL -> tSL
+tsn -> tSN
+tSn -> tSN
+tSN -> tSN
+tsr -> tSR
+tSr -> tSR
+tSR -> tSR
+
+### Create table of states and actions for each input class.
+
+Start (non-word) state is #; generic in-word state is _, once we know there's
+no special action to do in this word.
+
+ # _ b bh d g h m n n- t t- ts
+input\state
+b b' _ _ _ _ _ _ 1 _ _ _ _ _
+B _ _ _ _ _ _ _ 1 _ _ _ _ _
+c _ _ _ _ _ 1 _ _ _ _ _ _ _
+C _ _ _ _ _ 1 _ _ _ _ _ _ _
+d d' _ _ _ _ _ _ _ 1 _ _ _ _
+D _ _ _ _ _ _ _ _ 1 _ _ _ _
+f _ _ _ 2 _ _ _ _ _ _ _ _ _
+F _ _ _ 2 _ _ _ _ _ _ _ _ _
+g g' _ _ _ _ _ _ _ 1 _ _ _ _
+G _ _ _ _ _ _ _ _ 1 _ _ _ _
+h h' _ bh _ _ _ _ _ _ _ _ _ _
+l _ _ _ _ _ _ _ _ _ _ _ _ 1
+L _ _ _ _ _ _ _ _ _ _ _ _ 1
+m m' _ _ _ _ _ _ _ _ _ _ _ _
+n n' _ _ _ _ _ _ _ _ _ _ _ 1
+N _ _ _ _ _ _ _ _ _ _ _ _ 1
+p _ _ 1 _ _ _ _ _ _ _ _ _ _
+P _ _ 1 _ _ _ _ _ _ _ _ _ _
+r _ _ _ _ _ _ _ _ _ _ _ _ 1
+R _ _ _ _ _ _ _ _ _ _ _ _ 1
+s _ _ _ _ _ _ _ _ _ _ ts _ _
+S _ _ _ _ _ _ _ _ _ _ ts _ _
+t t' _ _ _ 1 _ _ _ _ _ _ _ _
+T _ _ _ _ 1 _ _ _ _ _ _ _ _
+vowel _ _ _ _ _ _ _ _ _ 1d _ 1d 1
+Vowel _ _ _ _ _ _ 1 _ 1 _ 1 _ 1
+hyph _ _ _ _ _ _ _ _ n- _ t- _ _
+letter _ _ _ _ _ _ _ _ _ _ _ _ _
+other # # # # # # # # # # # # #
+
+Actions:
+ 1 lowercase one letter at start of word
+ 2 lowercase two letters at start of word
+ 1d lowercase one letter at start of word, and delete next
+ (and then go to state _, nothing further to do in this word)
+
+else just go to the given state; suffix ' indicates mark start-of-word.
+
+### Consolidate identical states and classes:
+
+ 0 1 2 3 4 5 6 7 8 9 A B
+ # _ b bh d g h m n [nt]- t ts
+input\state
+b b' _ _ _ _ _ _ 1 _ _ _ _
+B _ _ _ _ _ _ _ 1 _ _ _ _
+[cC] _ _ _ _ _ 1 _ _ _ _ _ _
+d d' _ _ _ _ _ _ _ 1 _ _ _
+[DG] _ _ _ _ _ _ _ _ 1 _ _ _
+[fF] _ _ _ 2 _ _ _ _ _ _ _ _
+g g' _ _ _ _ _ _ _ 1 _ _ _
+h h' _ bh _ _ _ _ _ _ _ _ _
+[lLNrR] _ _ _ _ _ _ _ _ _ _ _ 1
+m m' _ _ _ _ _ _ _ _ _ _ _
+n n' _ _ _ _ _ _ _ _ _ _ 1
+[pP] _ _ 1 _ _ _ _ _ _ _ _ _
+[sS] _ _ _ _ _ _ _ _ _ _ ts _
+t t' _ _ _ 1 _ _ _ _ _ _ _
+T _ _ _ _ 1 _ _ _ _ _ _ _
+vowel _ _ _ _ _ _ _ _ _ 1d _ 1
+Vowel _ _ _ _ _ _ 1 _ 1 _ 1 1
+hyph _ _ _ _ _ _ _ _ [nt-] _ [nt-] _
+letter _ _ _ _ _ _ _ _ _ _ _ _
+other # # # # # # # # # # # #
+
+So we have 20 input classes, and 12 states.
+
+State table array will contain bytes that encode action and new state:
+
+ 0x80 - bit flag: mark start-of-word position
+ 0x40 - currently unused
+ 0x30 - action mask: 4 values
+ 0x00 - do nothing
+ 0x10 - lowercase one letter
+ 0x20 - lowercase two letters
+ 0x30 - lowercase one, delete one
+ 0x0F - next-state mask
+******************************************************************************/
+
+#include "IrishCasing.h"
+
+#include "nsUnicodeProperties.h"
+#include "nsUnicharUtils.h"
+
+namespace mozilla {
+
+const uint8_t IrishCasing::sUppercaseStateTable[kNumClasses][kNumStates] = {
+ // # _ b bh d g h m n [nt]- t ts
+ {0x82, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01,
+ 0x01}, // b
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01,
+ 0x01}, // B
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // [cC]
+ {0x84, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01,
+ 0x01}, // d
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01,
+ 0x01}, // [DG]
+ {0x01, 0x01, 0x01, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // [fF]
+ {0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01,
+ 0x01}, // g
+ {0x86, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // h
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x11}, // [lLNrR]
+ {0x87, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // m
+ {0x88, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x11}, // n
+ {0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // [pP]
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0B,
+ 0x01}, // [sS]
+ {0x8A, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // t
+ {0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // T
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x31, 0x01,
+ 0x11}, // vowel
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11,
+ 0x11}, // Vowel
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x01, 0x09,
+ 0x01}, // hyph
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01}, // letter
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00} // other
+};
+
+#define HYPHEN 0x2010
+#define NO_BREAK_HYPHEN 0x2011
+#define a_ACUTE 0x00e1
+#define e_ACUTE 0x00e9
+#define i_ACUTE 0x00ed
+#define o_ACUTE 0x00f3
+#define u_ACUTE 0x00fa
+#define A_ACUTE 0x00c1
+#define E_ACUTE 0x00c9
+#define I_ACUTE 0x00cd
+#define O_ACUTE 0x00d3
+#define U_ACUTE 0x00da
+
+const uint8_t IrishCasing::sLcClasses[26] = {
+ kClass_vowel, kClass_b, kClass_cC, kClass_d, kClass_vowel,
+ kClass_fF, kClass_g, kClass_h, kClass_vowel, kClass_letter,
+ kClass_letter, kClass_lLNrR, kClass_m, kClass_n, kClass_vowel,
+ kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_t,
+ kClass_vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter,
+ kClass_letter};
+
+const uint8_t IrishCasing::sUcClasses[26] = {
+ kClass_Vowel, kClass_B, kClass_cC, kClass_DG, kClass_Vowel,
+ kClass_fF, kClass_DG, kClass_letter, kClass_Vowel, kClass_letter,
+ kClass_letter, kClass_lLNrR, kClass_letter, kClass_lLNrR, kClass_Vowel,
+ kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_T,
+ kClass_Vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter,
+ kClass_letter};
+
+uint8_t IrishCasing::GetClass(uint32_t aCh) {
+ using mozilla::unicode::GetGenCategory;
+ if (aCh >= 'a' && aCh <= 'z') {
+ return sLcClasses[aCh - 'a'];
+ } else if (aCh >= 'A' && aCh <= 'Z') {
+ return sUcClasses[aCh - 'A'];
+ } else if (GetGenCategory(aCh) == nsUGenCategory::kLetter) {
+ if (aCh == a_ACUTE || aCh == e_ACUTE || aCh == i_ACUTE || aCh == o_ACUTE ||
+ aCh == u_ACUTE) {
+ return kClass_vowel;
+ } else if (aCh == A_ACUTE || aCh == E_ACUTE || aCh == I_ACUTE ||
+ aCh == O_ACUTE || aCh == U_ACUTE) {
+ return kClass_Vowel;
+ } else {
+ return kClass_letter;
+ }
+ } else if (aCh == '-' || aCh == HYPHEN || aCh == NO_BREAK_HYPHEN) {
+ return kClass_hyph;
+ } else {
+ return kClass_other;
+ }
+}
+
+uint32_t IrishCasing::UpperCase(uint32_t aCh, State& aState, bool& aMarkPos,
+ uint8_t& aAction) {
+ uint8_t cls = GetClass(aCh);
+ uint8_t stateEntry = sUppercaseStateTable[cls][aState];
+ aMarkPos = !!(stateEntry & kMarkPositionFlag);
+ aAction = (stateEntry & kActionMask) >> kActionShift;
+ aState = State(stateEntry & kNextStateMask);
+
+ return ToUpperCase(aCh);
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/IrishCasing.h b/intl/unicharutil/util/IrishCasing.h
new file mode 100644
index 0000000000..f5a6582a06
--- /dev/null
+++ b/intl/unicharutil/util/IrishCasing.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef IrishCasing_h_
+#define IrishCasing_h_
+
+#include <stdint.h>
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+
+class IrishCasing {
+ private:
+ enum IrishStates {
+ kState_Start,
+ kState_InWord,
+ kState_b,
+ kState_bh,
+ kState_d,
+ kState_g,
+ kState_h,
+ kState_m,
+ kState_n,
+ kState_nt_,
+ kState_t,
+ kState_ts,
+ kNumStates
+ };
+
+ enum IrishClasses {
+ kClass_b,
+ kClass_B,
+ kClass_cC,
+ kClass_d,
+ kClass_DG,
+ kClass_fF,
+ kClass_g,
+ kClass_h,
+ kClass_lLNrR,
+ kClass_m,
+ kClass_n,
+ kClass_pP,
+ kClass_sS,
+ kClass_t,
+ kClass_T,
+ kClass_vowel,
+ kClass_Vowel,
+ kClass_hyph,
+ kClass_letter,
+ kClass_other,
+ kNumClasses
+ };
+
+ public:
+ class State {
+ friend class IrishCasing;
+
+ public:
+ State() : mState(kState_Start) {}
+
+ MOZ_IMPLICIT State(const IrishStates& aState) : mState(aState) {}
+
+ void Reset() { mState = kState_Start; }
+
+ operator IrishStates() const { return mState; }
+
+ private:
+ explicit State(uint8_t aState) : mState(IrishStates(aState)) {}
+
+ uint8_t GetClass(uint32_t aCh);
+
+ IrishStates mState;
+ };
+
+ enum {
+ kMarkPositionFlag = 0x80,
+ kActionMask = 0x30,
+ kActionShift = 4,
+ kNextStateMask = 0x0f
+ };
+
+ static const uint8_t sUppercaseStateTable[kNumClasses][kNumStates];
+ static const uint8_t sLcClasses[26];
+ static const uint8_t sUcClasses[26];
+
+ static uint32_t UpperCase(uint32_t aCh, State& aState, bool& aMarkPos,
+ uint8_t& aAction);
+
+ static bool IsUpperVowel(uint32_t aCh) {
+ return GetClass(aCh) == kClass_Vowel;
+ }
+
+ private:
+ static uint8_t GetClass(uint32_t aCh);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/intl/unicharutil/util/moz.build b/intl/unicharutil/util/moz.build
new file mode 100644
index 0000000000..993daf7ded
--- /dev/null
+++ b/intl/unicharutil/util/moz.build
@@ -0,0 +1,28 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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 http://mozilla.org/MPL/2.0/.
+
+EXPORTS += [
+ "GreekCasing.h",
+ "ICUUtils.h",
+ "IrishCasing.h",
+ "nsBidiUtils.h",
+ "nsSpecialCasingData.h",
+ "nsUnicharUtils.h",
+ "nsUnicodeProperties.h",
+ "nsUnicodeScriptCodes.h",
+]
+
+UNIFIED_SOURCES += [
+ "GreekCasing.cpp",
+ "ICUUtils.cpp",
+ "IrishCasing.cpp",
+ "nsBidiUtils.cpp",
+ "nsSpecialCasingData.cpp",
+ "nsUnicharUtils.cpp",
+ "nsUnicodeProperties.cpp",
+]
+
+FINAL_LIBRARY = "xul"
diff --git a/intl/unicharutil/util/nsBidiUtils.cpp b/intl/unicharutil/util/nsBidiUtils.cpp
new file mode 100644
index 0000000000..fb7a20917a
--- /dev/null
+++ b/intl/unicharutil/util/nsBidiUtils.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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 http://mozilla.org/MPL/2.0/. */
+#include "nsBidiUtils.h"
+
+namespace mozilla {
+static const uint32_t kMinRTLChar = 0x0590;
+} // namespace mozilla
+
+#define ARABIC_TO_HINDI_DIGIT_INCREMENT \
+ (START_HINDI_DIGITS - START_ARABIC_DIGITS)
+#define PERSIAN_TO_HINDI_DIGIT_INCREMENT \
+ (START_HINDI_DIGITS - START_FARSI_DIGITS)
+#define ARABIC_TO_PERSIAN_DIGIT_INCREMENT \
+ (START_FARSI_DIGITS - START_ARABIC_DIGITS)
+#define NUM_TO_ARABIC(c) \
+ ((((c) >= START_HINDI_DIGITS) && ((c) <= END_HINDI_DIGITS)) \
+ ? ((c) - (uint16_t)ARABIC_TO_HINDI_DIGIT_INCREMENT) \
+ : ((((c) >= START_FARSI_DIGITS) && ((c) <= END_FARSI_DIGITS)) \
+ ? ((c) - (uint16_t)ARABIC_TO_PERSIAN_DIGIT_INCREMENT) \
+ : (c)))
+#define NUM_TO_HINDI(c) \
+ ((((c) >= START_ARABIC_DIGITS) && ((c) <= END_ARABIC_DIGITS)) \
+ ? ((c) + (uint16_t)ARABIC_TO_HINDI_DIGIT_INCREMENT) \
+ : ((((c) >= START_FARSI_DIGITS) && ((c) <= END_FARSI_DIGITS)) \
+ ? ((c) + (uint16_t)PERSIAN_TO_HINDI_DIGIT_INCREMENT) \
+ : (c)))
+#define NUM_TO_PERSIAN(c) \
+ ((((c) >= START_HINDI_DIGITS) && ((c) <= END_HINDI_DIGITS)) \
+ ? ((c) - (uint16_t)PERSIAN_TO_HINDI_DIGIT_INCREMENT) \
+ : ((((c) >= START_ARABIC_DIGITS) && ((c) <= END_ARABIC_DIGITS)) \
+ ? ((c) + (uint16_t)ARABIC_TO_PERSIAN_DIGIT_INCREMENT) \
+ : (c)))
+
+char16_t HandleNumberInChar(char16_t aChar, bool aPrevCharArabic,
+ uint32_t aNumFlag) {
+ // IBMBIDI_NUMERAL_NOMINAL *
+ // IBMBIDI_NUMERAL_REGULAR
+ // IBMBIDI_NUMERAL_HINDICONTEXT
+ // IBMBIDI_NUMERAL_ARABIC
+ // IBMBIDI_NUMERAL_HINDI
+
+ switch (aNumFlag) {
+ case IBMBIDI_NUMERAL_HINDI:
+ return NUM_TO_HINDI(aChar);
+ case IBMBIDI_NUMERAL_ARABIC:
+ return NUM_TO_ARABIC(aChar);
+ case IBMBIDI_NUMERAL_PERSIAN:
+ return NUM_TO_PERSIAN(aChar);
+ case IBMBIDI_NUMERAL_REGULAR:
+ case IBMBIDI_NUMERAL_HINDICONTEXT:
+ case IBMBIDI_NUMERAL_PERSIANCONTEXT:
+ // for clipboard handling
+ // XXX do we really want to convert numerals when copying text?
+ if (aPrevCharArabic) {
+ return aNumFlag == IBMBIDI_NUMERAL_PERSIANCONTEXT
+ ? NUM_TO_PERSIAN(aChar)
+ : NUM_TO_HINDI(aChar);
+ }
+ return NUM_TO_ARABIC(aChar);
+ case IBMBIDI_NUMERAL_NOMINAL:
+ default:
+ return aChar;
+ }
+}
+
+nsresult HandleNumbers(char16_t* aBuffer, uint32_t aSize, uint32_t aNumFlag) {
+ uint32_t i;
+
+ switch (aNumFlag) {
+ case IBMBIDI_NUMERAL_HINDI:
+ case IBMBIDI_NUMERAL_ARABIC:
+ case IBMBIDI_NUMERAL_PERSIAN:
+ case IBMBIDI_NUMERAL_REGULAR:
+ case IBMBIDI_NUMERAL_HINDICONTEXT:
+ case IBMBIDI_NUMERAL_PERSIANCONTEXT:
+ for (i = 0; i < aSize; i++)
+ aBuffer[i] = HandleNumberInChar(
+ aBuffer[i], !!(i > 0 ? aBuffer[i - 1] : 0), aNumFlag);
+ break;
+ case IBMBIDI_NUMERAL_NOMINAL:
+ default:
+ break;
+ }
+ return NS_OK;
+}
diff --git a/intl/unicharutil/util/nsBidiUtils.h b/intl/unicharutil/util/nsBidiUtils.h
new file mode 100644
index 0000000000..21a7ee7ffa
--- /dev/null
+++ b/intl/unicharutil/util/nsBidiUtils.h
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBidiUtils_h__
+#define nsBidiUtils_h__
+
+#include "nsString.h"
+#include "encoding_rs_mem.h"
+
+/**
+ * Read ftp://ftp.unicode.org/Public/UNIDATA/ReadMe-Latest.txt
+ * section BIDIRECTIONAL PROPERTIES
+ * for the detailed definition of the following categories
+ *
+ * The values here must match the equivalents in %bidicategorycode in
+ * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl,
+ * and must also match the values used by ICU's UCharDirection.
+ */
+
+enum nsCharType {
+ eCharType_LeftToRight = 0,
+ eCharType_RightToLeft = 1,
+ eCharType_EuropeanNumber = 2,
+ eCharType_EuropeanNumberSeparator = 3,
+ eCharType_EuropeanNumberTerminator = 4,
+ eCharType_ArabicNumber = 5,
+ eCharType_CommonNumberSeparator = 6,
+ eCharType_BlockSeparator = 7,
+ eCharType_SegmentSeparator = 8,
+ eCharType_WhiteSpaceNeutral = 9,
+ eCharType_OtherNeutral = 10,
+ eCharType_LeftToRightEmbedding = 11,
+ eCharType_LeftToRightOverride = 12,
+ eCharType_RightToLeftArabic = 13,
+ eCharType_RightToLeftEmbedding = 14,
+ eCharType_RightToLeftOverride = 15,
+ eCharType_PopDirectionalFormat = 16,
+ eCharType_DirNonSpacingMark = 17,
+ eCharType_BoundaryNeutral = 18,
+ eCharType_FirstStrongIsolate = 19,
+ eCharType_LeftToRightIsolate = 20,
+ eCharType_RightToLeftIsolate = 21,
+ eCharType_PopDirectionalIsolate = 22,
+ eCharType_CharTypeCount
+};
+
+/**
+ * This specifies the language directional property of a character set.
+ */
+typedef enum nsCharType nsCharType;
+
+/**
+ * Find the direction of an embedding level or paragraph level set by
+ * the Unicode Bidi Algorithm. (Even levels are left-to-right, odd
+ * levels right-to-left.
+ */
+#define IS_LEVEL_RTL(level) (((level)&1) == 1)
+
+/**
+ * Check whether two bidi levels have the same parity and thus the same
+ * directionality
+ */
+#define IS_SAME_DIRECTION(level1, level2) (((level1 ^ level2) & 1) == 0)
+
+/**
+ * Convert from nsBidiLevel to nsBidiDirection
+ */
+#define DIRECTION_FROM_LEVEL(level) \
+ ((IS_LEVEL_RTL(level)) ? NSBIDI_RTL : NSBIDI_LTR)
+
+/**
+ * definitions of bidirection character types by category
+ */
+
+#define CHARTYPE_IS_RTL(val) \
+ (((val) == eCharType_RightToLeft) || ((val) == eCharType_RightToLeftArabic))
+
+#define CHARTYPE_IS_WEAK(val) \
+ (((val) == eCharType_EuropeanNumberSeparator) || \
+ ((val) == eCharType_EuropeanNumberTerminator) || \
+ (((val) > eCharType_ArabicNumber) && \
+ ((val) != eCharType_RightToLeftArabic)))
+
+/**
+ * Inspects a Unichar, converting numbers to Arabic or Hindi forms and
+ * returning them
+ * @param aChar is the character
+ * @param aPrevCharArabic is true if the previous character in the string is
+ * an Arabic char
+ * @param aNumFlag specifies the conversion to perform:
+ * IBMBIDI_NUMERAL_NOMINAL: don't do any conversion
+ * IBMBIDI_NUMERAL_HINDI: convert to Hindi forms
+ * (Unicode 0660-0669)
+ * IBMBIDI_NUMERAL_ARABIC: convert to Arabic forms
+ * (Unicode 0030-0039)
+ * IBMBIDI_NUMERAL_HINDICONTEXT: convert numbers in Arabic text to
+ * Hindi, otherwise to Arabic
+ * @return the converted Unichar
+ */
+char16_t HandleNumberInChar(char16_t aChar, bool aPrevCharArabic,
+ uint32_t aNumFlag);
+
+/**
+ * Scan a Unichar string, converting numbers to Arabic or Hindi forms in
+ * place
+ * @param aBuffer is the string
+ * @param aSize is the size of aBuffer
+ * @param aNumFlag specifies the conversion to perform:
+ * IBMBIDI_NUMERAL_NOMINAL: don't do any conversion
+ * IBMBIDI_NUMERAL_HINDI: convert to Hindi forms
+ * (Unicode 0660-0669)
+ * IBMBIDI_NUMERAL_ARABIC: convert to Arabic forms
+ * (Unicode 0030-0039)
+ * IBMBIDI_NUMERAL_HINDICONTEXT: convert numbers in Arabic text to
+ * Hindi, otherwise to Arabic
+ */
+nsresult HandleNumbers(char16_t* aBuffer, uint32_t aSize, uint32_t aNumFlag);
+
+/**
+ * Give a UTF-32 codepoint
+ * return true if the codepoint is a Bidi control character (LRM, RLM, ALM;
+ * LRE, RLE, PDF, LRO, RLO; LRI, RLI, FSI, PDI).
+ * Return false, otherwise
+ */
+#define LRM_CHAR 0x200e
+#define RLM_CHAR 0x200f
+
+#define LRE_CHAR 0x202a
+#define RLE_CHAR 0x202b
+#define PDF_CHAR 0x202c
+#define LRO_CHAR 0x202d
+#define RLO_CHAR 0x202e
+
+#define LRI_CHAR 0x2066
+#define RLI_CHAR 0x2067
+#define FSI_CHAR 0x2068
+#define PDI_CHAR 0x2069
+
+#define ALM_CHAR 0x061C
+inline bool IsBidiControl(uint32_t aChar) {
+ return ((LRE_CHAR <= aChar && aChar <= RLO_CHAR) ||
+ (LRI_CHAR <= aChar && aChar <= PDI_CHAR) || (aChar == ALM_CHAR) ||
+ (aChar & 0xfffffe) == LRM_CHAR);
+}
+
+/**
+ * Give a UTF-32 codepoint
+ * Return true if the codepoint is a Bidi control character that may result
+ * in RTL directionality and therefore needs to trigger bidi resolution;
+ * return false otherwise.
+ */
+inline bool IsBidiControlRTL(uint32_t aChar) {
+ return aChar == RLM_CHAR || aChar == RLE_CHAR || aChar == RLO_CHAR ||
+ aChar == RLI_CHAR || aChar == ALM_CHAR;
+}
+
+/**
+ * Give a 16-bit (UTF-16) text buffer
+ * @return true if the string contains right-to-left characters
+ */
+inline bool HasRTLChars(mozilla::Span<const char16_t> aBuffer) {
+ // Span ensures we never pass a nullptr to Rust--even if the
+ // length of the buffer is zero.
+ return encoding_mem_is_utf16_bidi(aBuffer.Elements(), aBuffer.Length());
+}
+
+// These values are shared with Preferences dialog
+// ------------------
+// If Pref values are to be changed
+// in the XUL file of Prefs. the values
+// Must be changed here too..
+// ------------------
+//
+#define IBMBIDI_TEXTDIRECTION_STR "bidi.direction"
+#define IBMBIDI_TEXTTYPE_STR "bidi.texttype"
+#define IBMBIDI_NUMERAL_STR "bidi.numeral"
+
+// ------------------
+// Text Direction
+// ------------------
+// bidi.direction
+#define IBMBIDI_TEXTDIRECTION_LTR 1 // 1 = directionLTRBidi *
+#define IBMBIDI_TEXTDIRECTION_RTL 2 // 2 = directionRTLBidi
+// ------------------
+// Text Type
+// ------------------
+// bidi.texttype
+#define IBMBIDI_TEXTTYPE_CHARSET 1 // 1 = charsettexttypeBidi *
+#define IBMBIDI_TEXTTYPE_LOGICAL 2 // 2 = logicaltexttypeBidi
+#define IBMBIDI_TEXTTYPE_VISUAL 3 // 3 = visualtexttypeBidi
+// ------------------
+// Numeral Style
+// ------------------
+// bidi.numeral
+#define IBMBIDI_NUMERAL_NOMINAL 0 // 0 = nominalnumeralBidi *
+#define IBMBIDI_NUMERAL_REGULAR 1 // 1 = regularcontextnumeralBidi
+#define IBMBIDI_NUMERAL_HINDICONTEXT 2 // 2 = hindicontextnumeralBidi
+#define IBMBIDI_NUMERAL_ARABIC 3 // 3 = arabicnumeralBidi
+#define IBMBIDI_NUMERAL_HINDI 4 // 4 = hindinumeralBidi
+#define IBMBIDI_NUMERAL_PERSIANCONTEXT 5 // 5 = persiancontextnumeralBidi
+#define IBMBIDI_NUMERAL_PERSIAN 6 // 6 = persiannumeralBidi
+
+#define IBMBIDI_DEFAULT_BIDI_OPTIONS \
+ ((IBMBIDI_TEXTDIRECTION_LTR << 0) | (IBMBIDI_TEXTTYPE_CHARSET << 4) | \
+ (IBMBIDI_NUMERAL_NOMINAL << 8))
+
+#define GET_BIDI_OPTION_DIRECTION(bo) \
+ (((bo) >> 0) & 0x0000000F) /* 4 bits for DIRECTION */
+#define GET_BIDI_OPTION_TEXTTYPE(bo) \
+ (((bo) >> 4) & 0x0000000F) /* 4 bits for TEXTTYPE */
+#define GET_BIDI_OPTION_NUMERAL(bo) \
+ (((bo) >> 8) & 0x0000000F) /* 4 bits for NUMERAL */
+
+#define SET_BIDI_OPTION_DIRECTION(bo, dir) \
+ { (bo) = ((bo)&0xFFFFFFF0) | (((dir)&0x0000000F) << 0); }
+#define SET_BIDI_OPTION_TEXTTYPE(bo, tt) \
+ { (bo) = ((bo)&0xFFFFFF0F) | (((tt)&0x0000000F) << 4); }
+#define SET_BIDI_OPTION_NUMERAL(bo, num) \
+ { (bo) = ((bo)&0xFFFFF0FF) | (((num)&0x0000000F) << 8); }
+
+/* Constants related to the position of numerics in the codepage */
+#define START_HINDI_DIGITS 0x0660
+#define END_HINDI_DIGITS 0x0669
+#define START_ARABIC_DIGITS 0x0030
+#define END_ARABIC_DIGITS 0x0039
+#define START_FARSI_DIGITS 0x06f0
+#define END_FARSI_DIGITS 0x06f9
+#define IS_HINDI_DIGIT(u) \
+ (((u) >= START_HINDI_DIGITS) && ((u) <= END_HINDI_DIGITS))
+#define IS_ARABIC_DIGIT(u) \
+ (((u) >= START_ARABIC_DIGITS) && ((u) <= END_ARABIC_DIGITS))
+#define IS_FARSI_DIGIT(u) \
+ (((u) >= START_FARSI_DIGITS) && ((u) <= END_FARSI_DIGITS))
+/**
+ * Arabic numeric separator and numeric formatting characters:
+ * U+0600;ARABIC NUMBER SIGN
+ * U+0601;ARABIC SIGN SANAH
+ * U+0602;ARABIC FOOTNOTE MARKER
+ * U+0603;ARABIC SIGN SAFHA
+ * U+066A;ARABIC PERCENT SIGN
+ * U+066B;ARABIC DECIMAL SEPARATOR
+ * U+066C;ARABIC THOUSANDS SEPARATOR
+ * U+06DD;ARABIC END OF AYAH
+ */
+#define IS_ARABIC_SEPARATOR(u) \
+ ((/*(u) >= 0x0600 &&*/ (u) <= 0x0603) || ((u) >= 0x066A && (u) <= 0x066C) || \
+ ((u) == 0x06DD))
+
+#define IS_BIDI_DIACRITIC(u) \
+ (((u) >= 0x0591 && (u) <= 0x05A1) || ((u) >= 0x05A3 && (u) <= 0x05B9) || \
+ ((u) >= 0x05BB && (u) <= 0x05BD) || ((u) == 0x05BF) || ((u) == 0x05C1) || \
+ ((u) == 0x05C2) || ((u) == 0x05C4) || ((u) >= 0x064B && (u) <= 0x0652) || \
+ ((u) == 0x0670) || ((u) >= 0x06D7 && (u) <= 0x06E4) || ((u) == 0x06E7) || \
+ ((u) == 0x06E8) || ((u) >= 0x06EA && (u) <= 0x06ED))
+
+#define IS_HEBREW_CHAR(c) \
+ (((0x0590 <= (c)) && ((c) <= 0x05FF)) || (((c) >= 0xfb1d) && ((c) <= 0xfb4f)))
+#define IS_ARABIC_CHAR(c) \
+ ((0x0600 <= (c) && (c) <= 0x08FF) && \
+ ((c) <= 0x06ff || ((c) >= 0x0750 && (c) <= 0x077f) || (c) >= 0x08a0))
+#define IS_ARABIC_ALPHABETIC(c) \
+ (IS_ARABIC_CHAR(c) && \
+ !(IS_HINDI_DIGIT(c) || IS_FARSI_DIGIT(c) || IS_ARABIC_SEPARATOR(c)))
+
+/**
+ * The codepoint ranges in the following macros are based on the blocks
+ * allocated, or planned to be allocated, to right-to-left characters in the
+ * BMP (Basic Multilingual Plane) and SMP (Supplementary Multilingual Plane)
+ * according to
+ * http://unicode.org/Public/UNIDATA/extracted/DerivedBidiClass.txt and
+ * http://www.unicode.org/roadmaps/
+ */
+
+#define IS_IN_BMP_RTL_BLOCK(c) ((0x590 <= (c)) && ((c) <= 0x8ff))
+#define IS_RTL_PRESENTATION_FORM(c) \
+ (((0xfb1d <= (c)) && ((c) <= 0xfdff)) || ((0xfe70 <= (c)) && ((c) <= 0xfefe)))
+#define IS_IN_SMP_RTL_BLOCK(c) \
+ (((0x10800 <= (c)) && ((c) <= 0x10fff)) || \
+ ((0x1e800 <= (c)) && ((c) <= 0x1eFFF)))
+// Due to the supplementary-plane RTL blocks being identifiable from the
+// high surrogate without examining the low surrogate, it is correct to
+// use this by-code-unit check on potentially astral text without doing
+// the math to decode surrogate pairs into code points. However, unpaired
+// high surrogates that are RTL high surrogates then count as RTL even
+// though, if replaced by the REPLACEMENT CHARACTER, it would not be
+// RTL.
+#define UTF16_CODE_UNIT_IS_BIDI(c) \
+ ((IS_IN_BMP_RTL_BLOCK(c)) || (IS_RTL_PRESENTATION_FORM(c)) || \
+ (c) == 0xD802 || (c) == 0xD803 || (c) == 0xD83A || (c) == 0xD83B)
+#define UTF32_CHAR_IS_BIDI(c) \
+ ((IS_IN_BMP_RTL_BLOCK(c)) || (IS_RTL_PRESENTATION_FORM(c)) || \
+ (IS_IN_SMP_RTL_BLOCK(c)))
+#endif /* nsBidiUtils_h__ */
diff --git a/intl/unicharutil/util/nsSpecialCasingData.cpp b/intl/unicharutil/util/nsSpecialCasingData.cpp
new file mode 100644
index 0000000000..e23346f934
--- /dev/null
+++ b/intl/unicharutil/util/nsSpecialCasingData.cpp
@@ -0,0 +1,202 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+/* Auto-generated from files in the Unicode Character Database
+ by genSpecialCasingData.pl - do not edit! */
+
+#include "nsSpecialCasingData.h"
+#include "mozilla/ArrayUtils.h" // for ArrayLength
+#include <stdlib.h> // for bsearch
+
+/* SpecialCasing-13.0.0.txt */
+/* Date: 2019-09-08, 23:31:24 GMT */
+
+using mozilla::unicode::MultiCharMapping;
+
+static const MultiCharMapping CaseSpecials_Lower[] = {
+ { 0x0130, {0x0069, 0x0307, 0x0000} }, // LATIN CAPITAL LETTER I WITH DOT ABOVE
+};
+
+static const MultiCharMapping CaseSpecials_Upper[] = {
+ { 0x00df, {0x0053, 0x0053, 0x0000} }, // LATIN SMALL LETTER SHARP S
+ { 0x0149, {0x02bc, 0x004e, 0x0000} }, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+ { 0x01f0, {0x004a, 0x030c, 0x0000} }, // LATIN SMALL LETTER J WITH CARON
+ { 0x0390, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ { 0x03b0, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ { 0x0587, {0x0535, 0x0552, 0x0000} }, // ARMENIAN SMALL LIGATURE ECH YIWN
+ { 0x1e96, {0x0048, 0x0331, 0x0000} }, // LATIN SMALL LETTER H WITH LINE BELOW
+ { 0x1e97, {0x0054, 0x0308, 0x0000} }, // LATIN SMALL LETTER T WITH DIAERESIS
+ { 0x1e98, {0x0057, 0x030a, 0x0000} }, // LATIN SMALL LETTER W WITH RING ABOVE
+ { 0x1e99, {0x0059, 0x030a, 0x0000} }, // LATIN SMALL LETTER Y WITH RING ABOVE
+ { 0x1e9a, {0x0041, 0x02be, 0x0000} }, // LATIN SMALL LETTER A WITH RIGHT HALF RING
+ { 0x1f50, {0x03a5, 0x0313, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PSILI
+ { 0x1f52, {0x03a5, 0x0313, 0x0300} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+ { 0x1f54, {0x03a5, 0x0313, 0x0301} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+ { 0x1f56, {0x03a5, 0x0313, 0x0342} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+ { 0x1f80, {0x1f08, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
+ { 0x1f81, {0x1f09, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
+ { 0x1f82, {0x1f0a, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+ { 0x1f83, {0x1f0b, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+ { 0x1f84, {0x1f0c, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+ { 0x1f85, {0x1f0d, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+ { 0x1f86, {0x1f0e, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1f87, {0x1f0f, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1f88, {0x1f08, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+ { 0x1f89, {0x1f09, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+ { 0x1f8a, {0x1f0a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+ { 0x1f8b, {0x1f0b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+ { 0x1f8c, {0x1f0c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+ { 0x1f8d, {0x1f0d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+ { 0x1f8e, {0x1f0e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1f8f, {0x1f0f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1f90, {0x1f28, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
+ { 0x1f91, {0x1f29, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
+ { 0x1f92, {0x1f2a, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+ { 0x1f93, {0x1f2b, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+ { 0x1f94, {0x1f2c, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+ { 0x1f95, {0x1f2d, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+ { 0x1f96, {0x1f2e, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1f97, {0x1f2f, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1f98, {0x1f28, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+ { 0x1f99, {0x1f29, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+ { 0x1f9a, {0x1f2a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+ { 0x1f9b, {0x1f2b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+ { 0x1f9c, {0x1f2c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+ { 0x1f9d, {0x1f2d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+ { 0x1f9e, {0x1f2e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1f9f, {0x1f2f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1fa0, {0x1f68, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
+ { 0x1fa1, {0x1f69, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
+ { 0x1fa2, {0x1f6a, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+ { 0x1fa3, {0x1f6b, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+ { 0x1fa4, {0x1f6c, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+ { 0x1fa5, {0x1f6d, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+ { 0x1fa6, {0x1f6e, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fa7, {0x1f6f, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fa8, {0x1f68, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+ { 0x1fa9, {0x1f69, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+ { 0x1faa, {0x1f6a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+ { 0x1fab, {0x1f6b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+ { 0x1fac, {0x1f6c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+ { 0x1fad, {0x1f6d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+ { 0x1fae, {0x1f6e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1faf, {0x1f6f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+ { 0x1fb2, {0x1fba, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1fb3, {0x0391, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
+ { 0x1fb4, {0x0386, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1fb6, {0x0391, 0x0342, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+ { 0x1fb7, {0x0391, 0x0342, 0x0399} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fbc, {0x0391, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+ { 0x1fc2, {0x1fca, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1fc3, {0x0397, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
+ { 0x1fc4, {0x0389, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1fc6, {0x0397, 0x0342, 0x0000} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI
+ { 0x1fc7, {0x0397, 0x0342, 0x0399} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fcc, {0x0397, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+ { 0x1fd2, {0x03aa, 0x0300, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+ { 0x1fd3, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+ { 0x1fd6, {0x0399, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH PERISPOMENI
+ { 0x1fd7, {0x03aa, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+ { 0x1fe2, {0x03ab, 0x0300, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+ { 0x1fe3, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+ { 0x1fe4, {0x03a1, 0x0313, 0x0000} }, // GREEK SMALL LETTER RHO WITH PSILI
+ { 0x1fe6, {0x03a5, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+ { 0x1fe7, {0x03ab, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+ { 0x1ff2, {0x1ffa, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1ff3, {0x03a9, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
+ { 0x1ff4, {0x038f, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1ff6, {0x03a9, 0x0342, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+ { 0x1ff7, {0x03a9, 0x0342, 0x0399} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1ffc, {0x03a9, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+ { 0xfb00, {0x0046, 0x0046, 0x0000} }, // LATIN SMALL LIGATURE FF
+ { 0xfb01, {0x0046, 0x0049, 0x0000} }, // LATIN SMALL LIGATURE FI
+ { 0xfb02, {0x0046, 0x004c, 0x0000} }, // LATIN SMALL LIGATURE FL
+ { 0xfb03, {0x0046, 0x0046, 0x0049} }, // LATIN SMALL LIGATURE FFI
+ { 0xfb04, {0x0046, 0x0046, 0x004c} }, // LATIN SMALL LIGATURE FFL
+ { 0xfb05, {0x0053, 0x0054, 0x0000} }, // LATIN SMALL LIGATURE LONG S T
+ { 0xfb06, {0x0053, 0x0054, 0x0000} }, // LATIN SMALL LIGATURE ST
+ { 0xfb13, {0x0544, 0x0546, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN NOW
+ { 0xfb14, {0x0544, 0x0535, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN ECH
+ { 0xfb15, {0x0544, 0x053b, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN INI
+ { 0xfb16, {0x054e, 0x0546, 0x0000} }, // ARMENIAN SMALL LIGATURE VEW NOW
+ { 0xfb17, {0x0544, 0x053d, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN XEH
+};
+
+static const MultiCharMapping CaseSpecials_Title[] = {
+ { 0x00df, {0x0053, 0x0073, 0x0000} }, // LATIN SMALL LETTER SHARP S
+ { 0x0149, {0x02bc, 0x004e, 0x0000} }, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+ { 0x01f0, {0x004a, 0x030c, 0x0000} }, // LATIN SMALL LETTER J WITH CARON
+ { 0x0390, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ { 0x03b0, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ { 0x0587, {0x0535, 0x0582, 0x0000} }, // ARMENIAN SMALL LIGATURE ECH YIWN
+ { 0x1e96, {0x0048, 0x0331, 0x0000} }, // LATIN SMALL LETTER H WITH LINE BELOW
+ { 0x1e97, {0x0054, 0x0308, 0x0000} }, // LATIN SMALL LETTER T WITH DIAERESIS
+ { 0x1e98, {0x0057, 0x030a, 0x0000} }, // LATIN SMALL LETTER W WITH RING ABOVE
+ { 0x1e99, {0x0059, 0x030a, 0x0000} }, // LATIN SMALL LETTER Y WITH RING ABOVE
+ { 0x1e9a, {0x0041, 0x02be, 0x0000} }, // LATIN SMALL LETTER A WITH RIGHT HALF RING
+ { 0x1f50, {0x03a5, 0x0313, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PSILI
+ { 0x1f52, {0x03a5, 0x0313, 0x0300} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+ { 0x1f54, {0x03a5, 0x0313, 0x0301} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+ { 0x1f56, {0x03a5, 0x0313, 0x0342} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+ { 0x1fb2, {0x1fba, 0x0345, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1fb4, {0x0386, 0x0345, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1fb6, {0x0391, 0x0342, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+ { 0x1fb7, {0x0391, 0x0342, 0x0345} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fc2, {0x1fca, 0x0345, 0x0000} }, // GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1fc4, {0x0389, 0x0345, 0x0000} }, // GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1fc6, {0x0397, 0x0342, 0x0000} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI
+ { 0x1fc7, {0x0397, 0x0342, 0x0345} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0x1fd2, {0x03aa, 0x0300, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+ { 0x1fd3, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+ { 0x1fd6, {0x0399, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH PERISPOMENI
+ { 0x1fd7, {0x03aa, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+ { 0x1fe2, {0x03ab, 0x0300, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+ { 0x1fe3, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+ { 0x1fe4, {0x03a1, 0x0313, 0x0000} }, // GREEK SMALL LETTER RHO WITH PSILI
+ { 0x1fe6, {0x03a5, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+ { 0x1fe7, {0x03ab, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+ { 0x1ff2, {0x1ffa, 0x0345, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+ { 0x1ff4, {0x038f, 0x0345, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+ { 0x1ff6, {0x03a9, 0x0342, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+ { 0x1ff7, {0x03a9, 0x0342, 0x0345} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+ { 0xfb00, {0x0046, 0x0066, 0x0000} }, // LATIN SMALL LIGATURE FF
+ { 0xfb01, {0x0046, 0x0069, 0x0000} }, // LATIN SMALL LIGATURE FI
+ { 0xfb02, {0x0046, 0x006c, 0x0000} }, // LATIN SMALL LIGATURE FL
+ { 0xfb03, {0x0046, 0x0066, 0x0069} }, // LATIN SMALL LIGATURE FFI
+ { 0xfb04, {0x0046, 0x0066, 0x006c} }, // LATIN SMALL LIGATURE FFL
+ { 0xfb05, {0x0053, 0x0074, 0x0000} }, // LATIN SMALL LIGATURE LONG S T
+ { 0xfb06, {0x0053, 0x0074, 0x0000} }, // LATIN SMALL LIGATURE ST
+ { 0xfb13, {0x0544, 0x0576, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN NOW
+ { 0xfb14, {0x0544, 0x0565, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN ECH
+ { 0xfb15, {0x0544, 0x056b, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN INI
+ { 0xfb16, {0x054e, 0x0576, 0x0000} }, // ARMENIAN SMALL LIGATURE VEW NOW
+ { 0xfb17, {0x0544, 0x056d, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN XEH
+};
+
+static int CompareMCM(const void* aKey, const void* aElement)
+{
+ const uint32_t ch = *static_cast<const uint32_t*>(aKey);
+ const MultiCharMapping* mcm = static_cast<const MultiCharMapping*>(aElement);
+ return int(ch) - int(mcm->mOriginalChar);
+}
+
+#define MAKE_SPECIAL_CASE_ACCESSOR(which) \
+ const MultiCharMapping* \
+ Special##which(uint32_t aChar) \
+ { \
+ const void* p = bsearch(&aChar, CaseSpecials_##which, \
+ mozilla::ArrayLength(CaseSpecials_##which), \
+ sizeof(MultiCharMapping), CompareMCM); \
+ return static_cast<const MultiCharMapping*>(p); \
+ }
+
+namespace mozilla {
+namespace unicode {
+
+MAKE_SPECIAL_CASE_ACCESSOR(Lower)
+MAKE_SPECIAL_CASE_ACCESSOR(Upper)
+MAKE_SPECIAL_CASE_ACCESSOR(Title)
+
+} // namespace unicode
+} // namespace mozilla
diff --git a/intl/unicharutil/util/nsSpecialCasingData.h b/intl/unicharutil/util/nsSpecialCasingData.h
new file mode 100644
index 0000000000..b0ba4d7dcc
--- /dev/null
+++ b/intl/unicharutil/util/nsSpecialCasingData.h
@@ -0,0 +1,26 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace unicode {
+
+// Multi-character mappings (from SpecialCasing.txt) map a single Unicode
+// value to a sequence of 2 or 3 Unicode characters. There are currently none
+// defined outside the BMP, so we can use char16_t here. Unused trailing
+// positions in mMappedChars are set to 0.
+struct MultiCharMapping {
+ char16_t mOriginalChar;
+ char16_t mMappedChars[3];
+};
+
+// Return a pointer to the special case mapping for the given character;
+// returns nullptr if no such mapping is defined.
+const MultiCharMapping* SpecialUpper(uint32_t aCh);
+const MultiCharMapping* SpecialLower(uint32_t aCh);
+const MultiCharMapping* SpecialTitle(uint32_t aCh);
+
+} // namespace unicode
+} // namespace mozilla
diff --git a/intl/unicharutil/util/nsUnicharUtils.cpp b/intl/unicharutil/util/nsUnicharUtils.cpp
new file mode 100644
index 0000000000..fb4c4f8d2c
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicharUtils.cpp
@@ -0,0 +1,521 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "nsUnicharUtils.h"
+#include "nsUTF8Utils.h"
+#include "nsUnicodeProperties.h"
+#include "mozilla/Likely.h"
+#include "mozilla/HashFunctions.h"
+
+// We map x -> x, except for upper-case letters,
+// which we map to their lower-case equivalents.
+static const uint8_t gASCIIToLower[128] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+};
+
+// We want ToLowerCase(uint32_t) and ToLowerCaseASCII(uint32_t) to be fast
+// when they're called from within the case-insensitive comparators, so we
+// define inlined versions.
+static MOZ_ALWAYS_INLINE uint32_t ToLowerCase_inline(uint32_t aChar) {
+ if (IS_ASCII(aChar)) {
+ return gASCIIToLower[aChar];
+ }
+
+ return mozilla::unicode::GetLowercase(aChar);
+}
+
+static MOZ_ALWAYS_INLINE uint32_t
+ToLowerCaseASCII_inline(const uint32_t aChar) {
+ if (IS_ASCII(aChar)) {
+ return gASCIIToLower[aChar];
+ }
+
+ return aChar;
+}
+
+void ToLowerCase(nsAString& aString) {
+ char16_t* buf = aString.BeginWriting();
+ ToLowerCase(buf, buf, aString.Length());
+}
+
+void ToLowerCaseASCII(nsAString& aString) {
+ char16_t* buf = aString.BeginWriting();
+ ToLowerCaseASCII(buf, buf, aString.Length());
+}
+
+char ToLowerCaseASCII(char aChar) {
+ if (aChar >= 'A' && aChar <= 'Z') {
+ return aChar + 0x20;
+ }
+ return aChar;
+}
+
+char16_t ToLowerCaseASCII(char16_t aChar) {
+ if (aChar >= 'A' && aChar <= 'Z') {
+ return aChar + 0x20;
+ }
+ return aChar;
+}
+
+char32_t ToLowerCaseASCII(char32_t aChar) {
+ if (aChar >= 'A' && aChar <= 'Z') {
+ return aChar + 0x20;
+ }
+ return aChar;
+}
+
+char ToUpperCaseASCII(char aChar) {
+ if (aChar >= 'a' && aChar <= 'z') {
+ return aChar - 0x20;
+ }
+ return aChar;
+}
+
+char16_t ToUpperCaseASCII(char16_t aChar) {
+ if (aChar >= 'a' && aChar <= 'z') {
+ return aChar - 0x20;
+ }
+ return aChar;
+}
+
+char32_t ToUpperCaseASCII(char32_t aChar) {
+ if (aChar >= 'a' && aChar <= 'z') {
+ return aChar - 0x20;
+ }
+ return aChar;
+}
+
+void ToLowerCase(const nsAString& aSource, nsAString& aDest) {
+ const char16_t* in = aSource.BeginReading();
+ uint32_t len = aSource.Length();
+
+ aDest.SetLength(len);
+ char16_t* out = aDest.BeginWriting();
+
+ ToLowerCase(in, out, len);
+}
+
+void ToLowerCaseASCII(const nsAString& aSource, nsAString& aDest) {
+ const char16_t* in = aSource.BeginReading();
+ uint32_t len = aSource.Length();
+
+ aDest.SetLength(len);
+ char16_t* out = aDest.BeginWriting();
+
+ ToLowerCaseASCII(in, out, len);
+}
+
+uint32_t ToLowerCaseASCII(const uint32_t aChar) {
+ return ToLowerCaseASCII_inline(aChar);
+}
+
+void ToUpperCase(nsAString& aString) {
+ char16_t* buf = aString.BeginWriting();
+ ToUpperCase(buf, buf, aString.Length());
+}
+
+void ToUpperCase(const nsAString& aSource, nsAString& aDest) {
+ const char16_t* in = aSource.BeginReading();
+ uint32_t len = aSource.Length();
+
+ aDest.SetLength(len);
+ char16_t* out = aDest.BeginWriting();
+
+ ToUpperCase(in, out, len);
+}
+
+#ifdef MOZILLA_INTERNAL_API
+
+uint32_t ToFoldedCase(uint32_t aChar) {
+ if (IS_ASCII(aChar)) return gASCIIToLower[aChar];
+ return mozilla::unicode::GetFoldedcase(aChar);
+}
+
+void ToFoldedCase(nsAString& aString) {
+ char16_t* buf = aString.BeginWriting();
+ ToFoldedCase(buf, buf, aString.Length());
+}
+
+void ToFoldedCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) {
+ for (uint32_t i = 0; i < aLen; i++) {
+ uint32_t ch = aIn[i];
+ if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) {
+ ch = mozilla::unicode::GetFoldedcase(SURROGATE_TO_UCS4(ch, aIn[i + 1]));
+ NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!");
+ aOut[i++] = H_SURROGATE(ch);
+ aOut[i] = L_SURROGATE(ch);
+ continue;
+ }
+ aOut[i] = ToFoldedCase(ch);
+ }
+}
+
+uint32_t ToNaked(uint32_t aChar) {
+ if (IS_ASCII(aChar)) {
+ return aChar;
+ }
+ return mozilla::unicode::GetNaked(aChar);
+}
+
+void ToNaked(nsAString& aString) {
+ uint32_t i = 0;
+ while (i < aString.Length()) {
+ uint32_t ch = aString[i];
+ if (i < aString.Length() - 1 && NS_IS_SURROGATE_PAIR(ch, aString[i + 1])) {
+ ch = SURROGATE_TO_UCS4(ch, aString[i + 1]);
+ if (mozilla::unicode::IsCombiningDiacritic(ch)) {
+ aString.Cut(i, 2);
+ } else {
+ ch = mozilla::unicode::GetNaked(ch);
+ NS_ASSERTION(!IS_IN_BMP(ch), "stripping crossed BMP/SMP boundary!");
+ aString.Replace(i++, 1, H_SURROGATE(ch));
+ aString.Replace(i++, 1, L_SURROGATE(ch));
+ }
+ continue;
+ }
+ if (mozilla::unicode::IsCombiningDiacritic(ch)) {
+ aString.Cut(i, 1);
+ } else {
+ aString.Replace(i++, 1, ToNaked(ch));
+ }
+ }
+}
+
+int32_t nsCaseInsensitiveStringComparator(const char16_t* lhs,
+ const char16_t* rhs, uint32_t lLength,
+ uint32_t rLength) {
+ return (lLength == rLength) ? CaseInsensitiveCompare(lhs, rhs, lLength)
+ : (lLength > rLength) ? 1
+ : -1;
+}
+
+int32_t nsCaseInsensitiveUTF8StringComparator(const char* lhs, const char* rhs,
+ uint32_t lLength,
+ uint32_t rLength) {
+ return CaseInsensitiveCompare(lhs, rhs, lLength, rLength);
+}
+
+int32_t nsASCIICaseInsensitiveStringComparator(const char16_t* lhs,
+ const char16_t* rhs,
+ uint32_t lLength,
+ uint32_t rLength) {
+ if (lLength != rLength) {
+ if (lLength > rLength) return 1;
+ return -1;
+ }
+
+ while (rLength) {
+ // we don't care about surrogates here, because we're only
+ // lowercasing the ASCII range
+ char16_t l = *lhs++;
+ char16_t r = *rhs++;
+ if (l != r) {
+ l = ToLowerCaseASCII_inline(l);
+ r = ToLowerCaseASCII_inline(r);
+
+ if (l > r)
+ return 1;
+ else if (r > l)
+ return -1;
+ }
+ rLength--;
+ }
+
+ return 0;
+}
+
+#endif // MOZILLA_INTERNAL_API
+
+uint32_t ToLowerCase(uint32_t aChar) { return ToLowerCase_inline(aChar); }
+
+void ToLowerCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) {
+ for (uint32_t i = 0; i < aLen; i++) {
+ uint32_t ch = aIn[i];
+ if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) {
+ ch = mozilla::unicode::GetLowercase(SURROGATE_TO_UCS4(ch, aIn[i + 1]));
+ NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!");
+ aOut[i++] = H_SURROGATE(ch);
+ aOut[i] = L_SURROGATE(ch);
+ continue;
+ }
+ aOut[i] = ToLowerCase(ch);
+ }
+}
+
+void ToLowerCaseASCII(const char16_t* aIn, char16_t* aOut, uint32_t aLen) {
+ for (uint32_t i = 0; i < aLen; i++) {
+ char16_t ch = aIn[i];
+ aOut[i] = IS_ASCII_UPPER(ch) ? (ch + 0x20) : ch;
+ }
+}
+
+uint32_t ToUpperCase(uint32_t aChar) {
+ if (IS_ASCII(aChar)) {
+ if (IS_ASCII_LOWER(aChar)) {
+ return aChar - 0x20;
+ }
+ return aChar;
+ }
+
+ return mozilla::unicode::GetUppercase(aChar);
+}
+
+void ToUpperCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) {
+ for (uint32_t i = 0; i < aLen; i++) {
+ uint32_t ch = aIn[i];
+ if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) {
+ ch = mozilla::unicode::GetUppercase(SURROGATE_TO_UCS4(ch, aIn[i + 1]));
+ NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!");
+ aOut[i++] = H_SURROGATE(ch);
+ aOut[i] = L_SURROGATE(ch);
+ continue;
+ }
+ aOut[i] = ToUpperCase(ch);
+ }
+}
+
+uint32_t ToTitleCase(uint32_t aChar) {
+ if (IS_ASCII(aChar)) {
+ return ToUpperCase(aChar);
+ }
+
+ return mozilla::unicode::GetTitlecaseForLower(aChar);
+}
+
+int32_t CaseInsensitiveCompare(const char16_t* a, const char16_t* b,
+ uint32_t len) {
+ NS_ASSERTION(a && b, "Do not pass in invalid pointers!");
+
+ if (len) {
+ do {
+ uint32_t c1 = *a++;
+ uint32_t c2 = *b++;
+
+ // Unfortunately, we need to check for surrogates BEFORE we check
+ // for equality, because we could have identical high surrogates
+ // but non-identical characters, so we can't just skip them
+
+ // If c1 isn't a surrogate, we don't bother to check c2;
+ // in the case where it _is_ a surrogate, we're definitely going to get
+ // a mismatch, and don't need to interpret and lowercase it
+
+ if (len > 1 && NS_IS_SURROGATE_PAIR(c1, *a)) {
+ c1 = SURROGATE_TO_UCS4(c1, *a++);
+ if (NS_IS_SURROGATE_PAIR(c2, *b)) {
+ c2 = SURROGATE_TO_UCS4(c2, *b++);
+ }
+ // If c2 wasn't a surrogate, decrementing len means we'd stop
+ // short of the end of string b, but that doesn't actually matter
+ // because we're going to find a mismatch and return early
+ --len;
+ }
+
+ if (c1 != c2) {
+ c1 = ToLowerCase_inline(c1);
+ c2 = ToLowerCase_inline(c2);
+ if (c1 != c2) {
+ if (c1 < c2) {
+ return -1;
+ }
+ return 1;
+ }
+ }
+ } while (--len != 0);
+ }
+ return 0;
+}
+
+// Inlined definition of GetLowerUTF8Codepoint, which we use because we want
+// to be fast when called from the case-insensitive comparators.
+static MOZ_ALWAYS_INLINE uint32_t GetLowerUTF8Codepoint_inline(
+ const char* aStr, const char* aEnd, const char** aNext) {
+ // Convert to unsigned char so that stuffing chars into PRUint32s doesn't
+ // sign extend.
+ const unsigned char* str = (unsigned char*)aStr;
+
+ if (UTF8traits::isASCII(str[0])) {
+ // It's ASCII; just convert to lower-case and return it.
+ *aNext = aStr + 1;
+ return gASCIIToLower[*str];
+ }
+ if (UTF8traits::is2byte(str[0]) && MOZ_LIKELY(aStr + 1 < aEnd)) {
+ // It's a two-byte sequence, so it looks like
+ // 110XXXXX 10XXXXXX.
+ // This is definitely in the BMP, so we can store straightaway into a
+ // uint16_t.
+
+ uint16_t c;
+ c = (str[0] & 0x1F) << 6;
+ c += (str[1] & 0x3F);
+
+ // we don't go through ToLowerCase here, because we know this isn't
+ // an ASCII character so the ASCII fast-path there is useless
+ c = mozilla::unicode::GetLowercase(c);
+
+ *aNext = aStr + 2;
+ return c;
+ }
+ if (UTF8traits::is3byte(str[0]) && MOZ_LIKELY(aStr + 2 < aEnd)) {
+ // It's a three-byte sequence, so it looks like
+ // 1110XXXX 10XXXXXX 10XXXXXX.
+ // This will just barely fit into 16-bits, so store into a uint16_t.
+
+ uint16_t c;
+ c = (str[0] & 0x0F) << 12;
+ c += (str[1] & 0x3F) << 6;
+ c += (str[2] & 0x3F);
+
+ c = mozilla::unicode::GetLowercase(c);
+
+ *aNext = aStr + 3;
+ return c;
+ }
+ if (UTF8traits::is4byte(str[0]) && MOZ_LIKELY(aStr + 3 < aEnd)) {
+ // It's a four-byte sequence, so it looks like
+ // 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX.
+
+ uint32_t c;
+ c = (str[0] & 0x07) << 18;
+ c += (str[1] & 0x3F) << 12;
+ c += (str[2] & 0x3F) << 6;
+ c += (str[3] & 0x3F);
+
+ c = mozilla::unicode::GetLowercase(c);
+
+ *aNext = aStr + 4;
+ return c;
+ }
+
+ // Hm, we don't understand this sequence.
+ return -1;
+}
+
+uint32_t GetLowerUTF8Codepoint(const char* aStr, const char* aEnd,
+ const char** aNext) {
+ return GetLowerUTF8Codepoint_inline(aStr, aEnd, aNext);
+}
+
+int32_t CaseInsensitiveCompare(const char* aLeft, const char* aRight,
+ uint32_t aLeftBytes, uint32_t aRightBytes) {
+ const char* leftEnd = aLeft + aLeftBytes;
+ const char* rightEnd = aRight + aRightBytes;
+
+ while (aLeft < leftEnd && aRight < rightEnd) {
+ uint32_t leftChar = GetLowerUTF8Codepoint_inline(aLeft, leftEnd, &aLeft);
+ if (MOZ_UNLIKELY(leftChar == uint32_t(-1))) return -1;
+
+ uint32_t rightChar =
+ GetLowerUTF8Codepoint_inline(aRight, rightEnd, &aRight);
+ if (MOZ_UNLIKELY(rightChar == uint32_t(-1))) return -1;
+
+ // Now leftChar and rightChar are lower-case, so we can compare them.
+ if (leftChar != rightChar) {
+ if (leftChar > rightChar) return 1;
+ return -1;
+ }
+ }
+
+ // Make sure that if one string is longer than the other we return the
+ // correct result.
+ if (aLeft < leftEnd) return 1;
+ if (aRight < rightEnd) return -1;
+
+ return 0;
+}
+
+static MOZ_ALWAYS_INLINE uint32_t
+GetLowerUTF8Codepoint_inline(const char* aStr, const char* aEnd,
+ const char** aNext, bool aMatchDiacritics) {
+ uint32_t c;
+ for (;;) {
+ c = GetLowerUTF8Codepoint_inline(aStr, aEnd, aNext);
+ if (aMatchDiacritics) {
+ break;
+ }
+ if (!mozilla::unicode::IsCombiningDiacritic(c)) {
+ break;
+ }
+ aStr = *aNext;
+ }
+ return c;
+}
+
+bool CaseInsensitiveUTF8CharsEqual(const char* aLeft, const char* aRight,
+ const char* aLeftEnd, const char* aRightEnd,
+ const char** aLeftNext,
+ const char** aRightNext, bool* aErr,
+ bool aMatchDiacritics) {
+ NS_ASSERTION(aLeftNext, "Out pointer shouldn't be null.");
+ NS_ASSERTION(aRightNext, "Out pointer shouldn't be null.");
+ NS_ASSERTION(aErr, "Out pointer shouldn't be null.");
+ NS_ASSERTION(aLeft < aLeftEnd, "aLeft must be less than aLeftEnd.");
+ NS_ASSERTION(aRight < aRightEnd, "aRight must be less than aRightEnd.");
+
+ uint32_t leftChar = GetLowerUTF8Codepoint_inline(aLeft, aLeftEnd, aLeftNext,
+ aMatchDiacritics);
+ if (MOZ_UNLIKELY(leftChar == uint32_t(-1))) {
+ *aErr = true;
+ return false;
+ }
+
+ uint32_t rightChar = GetLowerUTF8Codepoint_inline(
+ aRight, aRightEnd, aRightNext, aMatchDiacritics);
+ if (MOZ_UNLIKELY(rightChar == uint32_t(-1))) {
+ *aErr = true;
+ return false;
+ }
+
+ // Can't have an error past this point.
+ *aErr = false;
+
+ if (!aMatchDiacritics) {
+ leftChar = ToNaked(leftChar);
+ rightChar = ToNaked(rightChar);
+ }
+
+ return leftChar == rightChar;
+}
+
+namespace mozilla {
+
+uint32_t HashUTF8AsUTF16(const char* aUTF8, uint32_t aLength, bool* aErr) {
+ uint32_t hash = 0;
+ const char* s = aUTF8;
+ const char* end = aUTF8 + aLength;
+
+ *aErr = false;
+
+ while (s < end) {
+ uint32_t ucs4 = UTF8CharEnumerator::NextChar(&s, end, aErr);
+ if (*aErr) {
+ return 0;
+ }
+
+ if (ucs4 < PLANE1_BASE) {
+ hash = AddToHash(hash, ucs4);
+ } else {
+ hash = AddToHash(hash, H_SURROGATE(ucs4), L_SURROGATE(ucs4));
+ }
+ }
+
+ return hash;
+}
+
+bool IsSegmentBreakSkipChar(uint32_t u) {
+ return unicode::IsEastAsianWidthFHWexcludingEmoji(u) &&
+ unicode::GetScriptCode(u) != unicode::Script::HANGUL;
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/nsUnicharUtils.h b/intl/unicharutil/util/nsUnicharUtils.h
new file mode 100644
index 0000000000..ffbbabf2c6
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicharUtils.h
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsUnicharUtils_h__
+#define nsUnicharUtils_h__
+
+#include "nsString.h"
+
+/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */
+/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */
+#define IS_CJ_CHAR(u) \
+ ((0x2e80u <= (u) && (u) <= 0x312fu) || (0x3190u <= (u) && (u) <= 0xabffu) || \
+ (0xf900u <= (u) && (u) <= 0xfaffu) || (0xff00u <= (u) && (u) <= 0xffefu))
+
+#define IS_ZERO_WIDTH_SPACE(u) ((u) == 0x200B)
+
+#define IS_ASCII(u) ((u) < 0x80)
+#define IS_ASCII_UPPER(u) (('A' <= (u)) && ((u) <= 'Z'))
+#define IS_ASCII_LOWER(u) (('a' <= (u)) && ((u) <= 'z'))
+#define IS_ASCII_ALPHA(u) (IS_ASCII_UPPER(u) || IS_ASCII_LOWER(u))
+#define IS_ASCII_SPACE(u) (' ' == (u))
+
+void ToLowerCase(nsAString& aString);
+void ToLowerCaseASCII(nsAString& aString);
+void ToUpperCase(nsAString& aString);
+
+void ToLowerCase(const nsAString& aSource, nsAString& aDest);
+void ToLowerCaseASCII(const nsAString& aSource, nsAString& aDest);
+void ToUpperCase(const nsAString& aSource, nsAString& aDest);
+
+uint32_t ToLowerCase(uint32_t aChar);
+uint32_t ToUpperCase(uint32_t aChar);
+uint32_t ToTitleCase(uint32_t aChar);
+
+void ToLowerCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen);
+void ToLowerCaseASCII(const char16_t* aIn, char16_t* aOut, uint32_t aLen);
+void ToUpperCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen);
+
+char ToLowerCaseASCII(const char aChar);
+char16_t ToLowerCaseASCII(const char16_t aChar);
+char32_t ToLowerCaseASCII(const char32_t aChar);
+
+char ToUpperCaseASCII(const char aChar);
+char16_t ToUpperCaseASCII(const char16_t aChar);
+char32_t ToUpperCaseASCII(const char32_t aChar);
+
+inline bool IsUpperCase(uint32_t c) { return ToLowerCase(c) != c; }
+
+inline bool IsLowerCase(uint32_t c) { return ToUpperCase(c) != c; }
+
+#ifdef MOZILLA_INTERNAL_API
+
+uint32_t ToFoldedCase(uint32_t aChar);
+void ToFoldedCase(nsAString& aString);
+void ToFoldedCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen);
+
+uint32_t ToNaked(uint32_t aChar);
+void ToNaked(nsAString& aString);
+
+int32_t nsCaseInsensitiveStringComparator(const char16_t*, const char16_t*,
+ uint32_t, uint32_t);
+
+int32_t nsCaseInsensitiveUTF8StringComparator(const char*, const char*,
+ uint32_t, uint32_t);
+
+class nsCaseInsensitiveStringArrayComparator {
+ public:
+ template <class A, class B>
+ bool Equals(const A& a, const B& b) const {
+ return a.Equals(b, nsCaseInsensitiveStringComparator);
+ }
+};
+
+int32_t nsASCIICaseInsensitiveStringComparator(const char16_t*, const char16_t*,
+ uint32_t, uint32_t);
+
+inline bool CaseInsensitiveFindInReadable(
+ const nsAString& aPattern, nsAString::const_iterator& aSearchStart,
+ nsAString::const_iterator& aSearchEnd) {
+ return FindInReadable(aPattern, aSearchStart, aSearchEnd,
+ nsCaseInsensitiveStringComparator);
+}
+
+inline bool CaseInsensitiveFindInReadable(const nsAString& aPattern,
+ const nsAString& aHay) {
+ nsAString::const_iterator searchBegin, searchEnd;
+ return FindInReadable(aPattern, aHay.BeginReading(searchBegin),
+ aHay.EndReading(searchEnd),
+ nsCaseInsensitiveStringComparator);
+}
+
+#endif // MOZILLA_INTERNAL_API
+
+int32_t CaseInsensitiveCompare(const char16_t* a, const char16_t* b,
+ uint32_t len);
+
+int32_t CaseInsensitiveCompare(const char* aLeft, const char* aRight,
+ uint32_t aLeftBytes, uint32_t aRightBytes);
+
+/**
+ * Calculates the lower-case of the codepoint of the UTF8 sequence starting at
+ * aStr. Sets aNext to the byte following the end of the sequence.
+ *
+ * If the sequence is invalid, or if computing the codepoint would take us off
+ * the end of the string (as marked by aEnd), returns -1 and does not set
+ * aNext. Note that this function doesn't check that aStr < aEnd -- it assumes
+ * you've done that already.
+ */
+uint32_t GetLowerUTF8Codepoint(const char* aStr, const char* aEnd,
+ const char** aNext);
+
+/**
+ * This function determines whether the UTF-8 sequence pointed to by aLeft is
+ * case insensitively equal to the UTF-8 sequence pointed to by aRight (or
+ * optionally, case and diacritic insensitively equal), as defined by having
+ * matching (naked) lower-cased codepoints.
+ *
+ * aLeftEnd marks the first memory location past aLeft that is not part of
+ * aLeft; aRightEnd similarly marks the end of aRight.
+ *
+ * The function assumes that aLeft < aLeftEnd and aRight < aRightEnd.
+ *
+ * The function stores the addresses of the next characters in the sequence
+ * into aLeftNext and aRightNext. It's up to the caller to make sure that the
+ * returned pointers are valid -- i.e. the function may return aLeftNext >=
+ * aLeftEnd or aRightNext >= aRightEnd.
+ *
+ * If the function encounters invalid text, it sets aErr to true and returns
+ * false, possibly leaving aLeftNext and aRightNext uninitialized. If the
+ * function returns true, aErr is guaranteed to be false and both aLeftNext and
+ * aRightNext are guaranteed to be initialized.
+ *
+ * If aMatchDiacritics is false, the comparison is neither case-sensitive nor
+ * diacritic-sensitive.
+ */
+bool CaseInsensitiveUTF8CharsEqual(const char* aLeft, const char* aRight,
+ const char* aLeftEnd, const char* aRightEnd,
+ const char** aLeftNext,
+ const char** aRightNext, bool* aErr,
+ bool aMatchDiacritics = true);
+
+namespace mozilla {
+
+/**
+ * Hash a UTF8 string as though it were a UTF16 string.
+ *
+ * The value returned is the same as if we converted the string to UTF16 and
+ * then ran HashString() on the result.
+ *
+ * The given |length| is in bytes.
+ */
+uint32_t HashUTF8AsUTF16(const char* aUTF8, uint32_t aLength, bool* aErr);
+
+bool IsSegmentBreakSkipChar(uint32_t u);
+
+} // namespace mozilla
+
+#endif /* nsUnicharUtils_h__ */
diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp
new file mode 100644
index 0000000000..244b7818ca
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodeProperties.cpp
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=4 sw=2 sts=2 et cindent: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "nsUnicodeProperties.h"
+#include "nsUnicodePropertyData.cpp"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/HashTable.h"
+#include "nsCharTraits.h"
+
+#include "unicode/uchar.h"
+#include "unicode/unorm2.h"
+
+#define UNICODE_BMP_LIMIT 0x10000
+#define UNICODE_LIMIT 0x110000
+
+const nsCharProps2& GetCharProps2(uint32_t aCh) {
+ if (aCh < UNICODE_BMP_LIMIT) {
+ return sCharProp2Values[sCharProp2Pages[0][aCh >> kCharProp2CharBits]]
+ [aCh & ((1 << kCharProp2CharBits) - 1)];
+ }
+ if (aCh < (kCharProp2MaxPlane + 1) * 0x10000) {
+ return sCharProp2Values[sCharProp2Pages[sCharProp2Planes[(aCh >> 16) - 1]]
+ [(aCh & 0xffff) >>
+ kCharProp2CharBits]]
+ [aCh & ((1 << kCharProp2CharBits) - 1)];
+ }
+
+ MOZ_ASSERT_UNREACHABLE(
+ "Getting CharProps for codepoint outside Unicode "
+ "range");
+
+ // Default values for unassigned
+ using namespace mozilla::unicode;
+ static const nsCharProps2 undefined = {
+ VERTICAL_ORIENTATION_R,
+ 0 // IdentifierType
+ };
+ return undefined;
+}
+
+namespace mozilla {
+
+namespace unicode {
+
+/*
+To store properties for a million Unicode codepoints compactly, we use
+a three-level array structure, with the Unicode values considered as
+three elements: Plane, Page, and Char.
+
+Space optimization happens because multiple Planes can refer to the same
+Page array, and multiple Pages can refer to the same Char array holding
+the actual values. In practice, most of the higher planes are empty and
+thus share the same data; and within the BMP, there are also many pages
+that repeat the same data for any given property.
+
+Plane is usually zero, so we skip a lookup in this case, and require
+that the Plane 0 pages are always the first set of entries in the Page
+array.
+
+The division of the remaining 16 bits into Page and Char fields is
+adjusted for each property (by experiment using the generation tool)
+to provide the most compact storage, depending on the distribution
+of values.
+*/
+
+const nsUGenCategory sDetailedToGeneralCategory[] = {
+ // clang-format off
+ /*
+ * The order here corresponds to the HB_UNICODE_GENERAL_CATEGORY_* constants
+ * of the hb_unicode_general_category_t enum in gfx/harfbuzz/src/hb-unicode.h.
+ */
+ /* CONTROL */ nsUGenCategory::kOther,
+ /* FORMAT */ nsUGenCategory::kOther,
+ /* UNASSIGNED */ nsUGenCategory::kOther,
+ /* PRIVATE_USE */ nsUGenCategory::kOther,
+ /* SURROGATE */ nsUGenCategory::kOther,
+ /* LOWERCASE_LETTER */ nsUGenCategory::kLetter,
+ /* MODIFIER_LETTER */ nsUGenCategory::kLetter,
+ /* OTHER_LETTER */ nsUGenCategory::kLetter,
+ /* TITLECASE_LETTER */ nsUGenCategory::kLetter,
+ /* UPPERCASE_LETTER */ nsUGenCategory::kLetter,
+ /* COMBINING_MARK */ nsUGenCategory::kMark,
+ /* ENCLOSING_MARK */ nsUGenCategory::kMark,
+ /* NON_SPACING_MARK */ nsUGenCategory::kMark,
+ /* DECIMAL_NUMBER */ nsUGenCategory::kNumber,
+ /* LETTER_NUMBER */ nsUGenCategory::kNumber,
+ /* OTHER_NUMBER */ nsUGenCategory::kNumber,
+ /* CONNECT_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* DASH_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* CLOSE_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* FINAL_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* INITIAL_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* OTHER_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* OPEN_PUNCTUATION */ nsUGenCategory::kPunctuation,
+ /* CURRENCY_SYMBOL */ nsUGenCategory::kSymbol,
+ /* MODIFIER_SYMBOL */ nsUGenCategory::kSymbol,
+ /* MATH_SYMBOL */ nsUGenCategory::kSymbol,
+ /* OTHER_SYMBOL */ nsUGenCategory::kSymbol,
+ /* LINE_SEPARATOR */ nsUGenCategory::kSeparator,
+ /* PARAGRAPH_SEPARATOR */ nsUGenCategory::kSeparator,
+ /* SPACE_SEPARATOR */ nsUGenCategory::kSeparator
+ // clang-format on
+};
+
+const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = {
+ // clang-format off
+ HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0,
+ HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1,
+ HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, // U_LOWERCASE_LETTER = 2,
+ HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, // U_TITLECASE_LETTER = 3,
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, // U_MODIFIER_LETTER = 4,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, // U_OTHER_LETTER = 5,
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // U_NON_SPACING_MARK = 6,
+ HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, // U_ENCLOSING_MARK = 7,
+ HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, // U_COMBINING_SPACING_MARK = 8,
+ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, // U_DECIMAL_DIGIT_NUMBER = 9,
+ HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, // U_LETTER_NUMBER = 10,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, // U_OTHER_NUMBER = 11,
+ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, // U_SPACE_SEPARATOR = 12,
+ HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, // U_LINE_SEPARATOR = 13,
+ HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, // U_PARAGRAPH_SEPARATOR = 14,
+ HB_UNICODE_GENERAL_CATEGORY_CONTROL, // U_CONTROL_CHAR = 15,
+ HB_UNICODE_GENERAL_CATEGORY_FORMAT, // U_FORMAT_CHAR = 16,
+ HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, // U_PRIVATE_USE_CHAR = 17,
+ HB_UNICODE_GENERAL_CATEGORY_SURROGATE, // U_SURROGATE = 18,
+ HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, // U_DASH_PUNCTUATION = 19,
+ HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, // U_START_PUNCTUATION = 20,
+ HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, // U_END_PUNCTUATION = 21,
+ HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, // U_CONNECTOR_PUNCTUATION = 22,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, // U_OTHER_PUNCTUATION = 23,
+ HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, // U_MATH_SYMBOL = 24,
+ HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25,
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27,
+ HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28,
+ HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29,
+ // clang-format on
+};
+
+#define DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(prefix_) \
+ uint32_t Get##prefix_(uint32_t aCh) { \
+ if (aCh >= UNICODE_BMP_LIMIT) { \
+ return aCh; \
+ } \
+ auto page = s##prefix_##Pages[aCh >> k##prefix_##CharBits]; \
+ auto index = aCh & ((1 << k##prefix_##CharBits) - 1); \
+ uint32_t v = s##prefix_##Values[page][index]; \
+ return v ? v : aCh; \
+ }
+
+// full-width mappings only exist for BMP characters; all others are
+// returned unchanged
+DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(FullWidth)
+DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(FullWidthInverse)
+
+bool IsClusterExtender(uint32_t aCh, uint8_t aCategory) {
+ return (
+ (aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
+ aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) ||
+ (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ
+ (aCh >= 0xff9e && aCh <= 0xff9f) || // katakana sound marks
+ (aCh >= 0x1F3FB && aCh <= 0x1F3FF) || // fitzpatrick skin tone modifiers
+ (aCh >= 0xe0020 && aCh <= 0xe007f)); // emoji (flag) tag characters
+}
+
+enum HSType {
+ HST_NONE = U_HST_NOT_APPLICABLE,
+ HST_L = U_HST_LEADING_JAMO,
+ HST_V = U_HST_VOWEL_JAMO,
+ HST_T = U_HST_TRAILING_JAMO,
+ HST_LV = U_HST_LV_SYLLABLE,
+ HST_LVT = U_HST_LVT_SYLLABLE
+};
+
+static HSType GetHangulSyllableType(uint32_t aCh) {
+ return HSType(u_getIntPropertyValue(aCh, UCHAR_HANGUL_SYLLABLE_TYPE));
+}
+
+void ClusterIterator::Next() {
+ if (AtEnd()) {
+ NS_WARNING("ClusterIterator has already reached the end");
+ return;
+ }
+
+ uint32_t ch = *mPos++;
+
+ if (mPos < mLimit && NS_IS_SURROGATE_PAIR(ch, *mPos)) {
+ ch = SURROGATE_TO_UCS4(ch, *mPos++);
+ } else if ((ch & ~0xff) == 0x1100 || (ch >= 0xa960 && ch <= 0xa97f) ||
+ (ch >= 0xac00 && ch <= 0xd7ff)) {
+ // Handle conjoining Jamo that make Hangul syllables
+ HSType hangulState = GetHangulSyllableType(ch);
+ while (mPos < mLimit) {
+ ch = *mPos;
+ HSType hangulType = GetHangulSyllableType(ch);
+ switch (hangulType) {
+ case HST_L:
+ case HST_LV:
+ case HST_LVT:
+ if (hangulState == HST_L) {
+ hangulState = hangulType;
+ mPos++;
+ continue;
+ }
+ break;
+ case HST_V:
+ if ((hangulState != HST_NONE) && (hangulState != HST_T) &&
+ (hangulState != HST_LVT)) {
+ hangulState = hangulType;
+ mPos++;
+ continue;
+ }
+ break;
+ case HST_T:
+ if (hangulState != HST_NONE && hangulState != HST_L) {
+ hangulState = hangulType;
+ mPos++;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ const uint32_t kVS16 = 0xfe0f;
+ const uint32_t kZWJ = 0x200d;
+ // UTF-16 surrogate values for Fitzpatrick type modifiers
+ const uint32_t kFitzpatrickHigh = 0xD83C;
+ const uint32_t kFitzpatrickLowFirst = 0xDFFB;
+ const uint32_t kFitzpatrickLowLast = 0xDFFF;
+
+ bool baseIsEmoji = (GetEmojiPresentation(ch) == EmojiDefault) ||
+ (GetEmojiPresentation(ch) == TextDefault &&
+ ((mPos < mLimit && *mPos == kVS16) ||
+ (mPos + 1 < mLimit && *mPos == kFitzpatrickHigh &&
+ *(mPos + 1) >= kFitzpatrickLowFirst &&
+ *(mPos + 1) <= kFitzpatrickLowLast)));
+ bool prevWasZwj = false;
+
+ while (mPos < mLimit) {
+ ch = *mPos;
+ size_t chLen = 1;
+
+ // Check for surrogate pairs; note that isolated surrogates will just
+ // be treated as generic (non-cluster-extending) characters here,
+ // which is fine for cluster-iterating purposes
+ if (mPos < mLimit - 1 && NS_IS_SURROGATE_PAIR(ch, *(mPos + 1))) {
+ ch = SURROGATE_TO_UCS4(ch, *(mPos + 1));
+ chLen = 2;
+ }
+
+ bool extendCluster =
+ IsClusterExtender(ch) ||
+ (baseIsEmoji && prevWasZwj &&
+ ((GetEmojiPresentation(ch) == EmojiDefault) ||
+ (GetEmojiPresentation(ch) == TextDefault && mPos + chLen < mLimit &&
+ *(mPos + chLen) == kVS16)));
+ if (!extendCluster) {
+ break;
+ }
+
+ prevWasZwj = (ch == kZWJ);
+ mPos += chLen;
+ }
+
+ NS_ASSERTION(mText < mPos && mPos <= mLimit,
+ "ClusterIterator::Next has overshot the string!");
+}
+
+void ClusterReverseIterator::Next() {
+ if (AtEnd()) {
+ NS_WARNING("ClusterReverseIterator has already reached the end");
+ return;
+ }
+
+ uint32_t ch;
+ do {
+ ch = *--mPos;
+
+ if (mPos > mLimit && NS_IS_SURROGATE_PAIR(*(mPos - 1), ch)) {
+ ch = SURROGATE_TO_UCS4(*--mPos, ch);
+ }
+
+ if (!IsClusterExtender(ch)) {
+ break;
+ }
+ } while (mPos > mLimit);
+
+ // XXX May need to handle conjoining Jamo
+
+ NS_ASSERTION(mPos >= mLimit,
+ "ClusterReverseIterator::Next has overshot the string!");
+}
+
+uint32_t CountGraphemeClusters(const char16_t* aText, uint32_t aLength) {
+ ClusterIterator iter(aText, aLength);
+ uint32_t result = 0;
+ while (!iter.AtEnd()) {
+ ++result;
+ iter.Next();
+ }
+ return result;
+}
+
+uint32_t GetNaked(uint32_t aCh) {
+ using namespace mozilla;
+
+ static const UNormalizer2* normalizer;
+ static HashMap<uint32_t, uint32_t> nakedCharCache;
+
+ NS_ASSERTION(!IsCombiningDiacritic(aCh),
+ "This character needs to be skipped");
+
+ HashMap<uint32_t, uint32_t>::Ptr entry = nakedCharCache.lookup(aCh);
+ if (entry.found()) {
+ return entry->value();
+ }
+
+ UErrorCode error = U_ZERO_ERROR;
+ if (!normalizer) {
+ normalizer = unorm2_getNFDInstance(&error);
+ if (U_FAILURE(error)) {
+ return aCh;
+ }
+ }
+
+ static const size_t MAX_DECOMPOSITION_SIZE = 16;
+ UChar decomposition[MAX_DECOMPOSITION_SIZE];
+ UChar* combiners;
+ int32_t decompositionLen;
+ uint32_t baseChar, nextChar;
+ decompositionLen = unorm2_getDecomposition(normalizer, aCh, decomposition,
+ MAX_DECOMPOSITION_SIZE, &error);
+ if (decompositionLen < 1) {
+ // The character does not decompose.
+ return aCh;
+ }
+
+ if (NS_IS_HIGH_SURROGATE(decomposition[0])) {
+ baseChar = SURROGATE_TO_UCS4(decomposition[0], decomposition[1]);
+ combiners = decomposition + 2;
+ } else {
+ baseChar = decomposition[0];
+ combiners = decomposition + 1;
+ }
+
+ if (IS_IN_BMP(baseChar) != IS_IN_BMP(aCh)) {
+ // Mappings that would change the length of a UTF-16 string are not
+ // currently supported.
+ baseChar = aCh;
+ goto cache;
+ }
+
+ if (decompositionLen > 1) {
+ if (NS_IS_HIGH_SURROGATE(combiners[0])) {
+ nextChar = SURROGATE_TO_UCS4(combiners[0], combiners[1]);
+ } else {
+ nextChar = combiners[0];
+ }
+ if (!IsCombiningDiacritic(nextChar)) {
+ // Hangul syllables decompose but do not actually have diacritics.
+ // This also excludes decompositions with the Japanese marks U+3099 and
+ // U+309A (COMBINING KATAKANA-HIRAGANA [SEMI-]VOICED SOUND MARK), which
+ // we should not ignore for searching (bug 1624244).
+ baseChar = aCh;
+ }
+ }
+
+cache:
+ if (!nakedCharCache.putNew(aCh, baseChar)) {
+ // We're out of memory, so delete the cache to free some up.
+ nakedCharCache.clearAndCompact();
+ }
+
+ return baseChar;
+}
+
+} // end namespace unicode
+
+} // end namespace mozilla
diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h
new file mode 100644
index 0000000000..11566cbffc
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -0,0 +1,283 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=4 sw=2 sts=2 et cindent: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#ifndef NS_UNICODEPROPERTIES_H
+#define NS_UNICODEPROPERTIES_H
+
+#include "nsBidiUtils.h"
+#include "nsUGenCategory.h"
+#include "nsUnicodeScriptCodes.h"
+#include "harfbuzz/hb.h"
+
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+
+const nsCharProps2& GetCharProps2(uint32_t aCh);
+
+namespace mozilla {
+
+namespace unicode {
+
+extern const nsUGenCategory sDetailedToGeneralCategory[];
+
+/* This MUST match the values assigned by genUnicodePropertyData.pl! */
+enum VerticalOrientation {
+ VERTICAL_ORIENTATION_U = 0,
+ VERTICAL_ORIENTATION_R = 1,
+ VERTICAL_ORIENTATION_Tu = 2,
+ VERTICAL_ORIENTATION_Tr = 3
+};
+
+/* This MUST match the values assigned by genUnicodePropertyData.pl! */
+enum PairedBracketType {
+ PAIRED_BRACKET_TYPE_NONE = 0,
+ PAIRED_BRACKET_TYPE_OPEN = 1,
+ PAIRED_BRACKET_TYPE_CLOSE = 2
+};
+
+/* Flags for Unicode security IdentifierType.txt attributes. Only a subset
+ of these are currently checked by Gecko, so we only define flags for the
+ ones we need. */
+enum IdentifierType {
+ IDTYPE_RESTRICTED = 0,
+ IDTYPE_ALLOWED = 1,
+};
+
+enum EmojiPresentation { TextOnly = 0, TextDefault = 1, EmojiDefault = 2 };
+
+const uint32_t kVariationSelector15 = 0xFE0E; // text presentation
+const uint32_t kVariationSelector16 = 0xFE0F; // emoji presentation
+
+// Unicode values for EMOJI MODIFIER FITZPATRICK TYPE-*
+const uint32_t kEmojiSkinToneFirst = 0x1f3fb;
+const uint32_t kEmojiSkinToneLast = 0x1f3ff;
+
+extern const hb_unicode_general_category_t sICUtoHBcategory[];
+
+inline uint32_t GetMirroredChar(uint32_t aCh) { return u_charMirror(aCh); }
+
+inline bool HasMirroredChar(uint32_t aCh) { return u_isMirrored(aCh); }
+
+inline uint8_t GetCombiningClass(uint32_t aCh) {
+ return u_getCombiningClass(aCh);
+}
+
+inline uint8_t GetGeneralCategory(uint32_t aCh) {
+ return sICUtoHBcategory[u_charType(aCh)];
+}
+
+inline nsCharType GetBidiCat(uint32_t aCh) {
+ return nsCharType(u_charDirection(aCh));
+}
+
+inline int8_t GetNumericValue(uint32_t aCh) {
+ UNumericType type =
+ UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE));
+ return type == U_NT_DECIMAL || type == U_NT_DIGIT
+ ? int8_t(u_getNumericValue(aCh))
+ : -1;
+}
+
+inline uint8_t GetLineBreakClass(uint32_t aCh) {
+ return u_getIntPropertyValue(aCh, UCHAR_LINE_BREAK);
+}
+
+inline Script GetScriptCode(uint32_t aCh) {
+ UErrorCode err = U_ZERO_ERROR;
+ return Script(uscript_getScript(aCh, &err));
+}
+
+inline bool HasScript(uint32_t aCh, Script aScript) {
+ return uscript_hasScript(aCh, UScriptCode(aScript));
+}
+
+inline uint32_t GetScriptTagForCode(Script aScriptCode) {
+ const char* tag = uscript_getShortName(UScriptCode(aScriptCode));
+ if (tag) {
+ return HB_TAG(tag[0], tag[1], tag[2], tag[3]);
+ }
+ // return UNKNOWN script tag (running with older ICU?)
+ return HB_SCRIPT_UNKNOWN;
+}
+
+inline PairedBracketType GetPairedBracketType(uint32_t aCh) {
+ return PairedBracketType(
+ u_getIntPropertyValue(aCh, UCHAR_BIDI_PAIRED_BRACKET_TYPE));
+}
+
+inline uint32_t GetPairedBracket(uint32_t aCh) {
+ return u_getBidiPairedBracket(aCh);
+}
+
+inline uint32_t GetUppercase(uint32_t aCh) { return u_toupper(aCh); }
+
+inline uint32_t GetLowercase(uint32_t aCh) { return u_tolower(aCh); }
+
+inline uint32_t GetTitlecaseForLower(
+ uint32_t aCh) // maps LC to titlecase, UC unchanged
+{
+ return u_isULowercase(aCh) ? u_totitle(aCh) : aCh;
+}
+
+inline uint32_t GetTitlecaseForAll(
+ uint32_t aCh) // maps both UC and LC to titlecase
+{
+ return u_totitle(aCh);
+}
+
+inline uint32_t GetFoldedcase(uint32_t aCh) {
+ // Handle dotted capital I and dotless small i specially because we want to
+ // use a combination of ordinary case-folding rules and Turkish case-folding
+ // rules.
+ if (aCh == 0x0130 || aCh == 0x0131) {
+ return 'i';
+ }
+ return u_foldCase(aCh, U_FOLD_CASE_DEFAULT);
+}
+
+inline bool IsEastAsianWidthFHWexcludingEmoji(uint32_t aCh) {
+ switch (u_getIntPropertyValue(aCh, UCHAR_EAST_ASIAN_WIDTH)) {
+ case U_EA_FULLWIDTH:
+ case U_EA_HALFWIDTH:
+ return true;
+ case U_EA_WIDE:
+ return u_hasBinaryProperty(aCh, UCHAR_EMOJI) ? false : true;
+ case U_EA_AMBIGUOUS:
+ case U_EA_NARROW:
+ case U_EA_NEUTRAL:
+ return false;
+ }
+ return false;
+}
+
+inline bool IsEastAsianWidthAFW(uint32_t aCh) {
+ switch (u_getIntPropertyValue(aCh, UCHAR_EAST_ASIAN_WIDTH)) {
+ case U_EA_AMBIGUOUS:
+ case U_EA_FULLWIDTH:
+ case U_EA_WIDE:
+ return true;
+ case U_EA_HALFWIDTH:
+ case U_EA_NARROW:
+ case U_EA_NEUTRAL:
+ return false;
+ }
+ return false;
+}
+
+inline bool IsDefaultIgnorable(uint32_t aCh) {
+ return u_hasBinaryProperty(aCh, UCHAR_DEFAULT_IGNORABLE_CODE_POINT);
+}
+
+inline EmojiPresentation GetEmojiPresentation(uint32_t aCh) {
+ if (!u_hasBinaryProperty(aCh, UCHAR_EMOJI)) {
+ return TextOnly;
+ }
+
+ if (u_hasBinaryProperty(aCh, UCHAR_EMOJI_PRESENTATION)) {
+ return EmojiDefault;
+ }
+ return TextDefault;
+}
+
+// returns the simplified Gen Category as defined in nsUGenCategory
+inline nsUGenCategory GetGenCategory(uint32_t aCh) {
+ return sDetailedToGeneralCategory[GetGeneralCategory(aCh)];
+}
+
+inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) {
+ return VerticalOrientation(GetCharProps2(aCh).mVertOrient);
+}
+
+inline IdentifierType GetIdentifierType(uint32_t aCh) {
+ return IdentifierType(GetCharProps2(aCh).mIdType);
+}
+
+uint32_t GetFullWidth(uint32_t aCh);
+// This is the reverse function of GetFullWidth which guarantees that
+// for every codepoint c, GetFullWidthInverse(GetFullWidth(c)) == c.
+// Note that, this function does not guarantee to convert all wide
+// form characters to their possible narrow form.
+uint32_t GetFullWidthInverse(uint32_t aCh);
+
+bool IsClusterExtender(uint32_t aCh, uint8_t aCategory);
+
+inline bool IsClusterExtender(uint32_t aCh) {
+ return IsClusterExtender(aCh, GetGeneralCategory(aCh));
+}
+
+// A simple iterator for a string of char16_t codepoints that advances
+// by Unicode grapheme clusters
+class ClusterIterator {
+ public:
+ ClusterIterator(const char16_t* aText, uint32_t aLength)
+ : mPos(aText),
+ mLimit(aText + aLength)
+#ifdef DEBUG
+ ,
+ mText(aText)
+#endif
+ {
+ }
+
+ operator const char16_t*() const { return mPos; }
+
+ bool AtEnd() const { return mPos >= mLimit; }
+
+ void Next();
+
+ private:
+ const char16_t* mPos;
+ const char16_t* mLimit;
+#ifdef DEBUG
+ const char16_t* mText;
+#endif
+};
+
+// Count the number of grapheme clusters in the given string
+uint32_t CountGraphemeClusters(const char16_t* aText, uint32_t aLength);
+
+// Determine whether a character is a "combining diacritic" for the purpose
+// of diacritic-insensitive text search. Examples of such characters include
+// European accents and Hebrew niqqud, but not Hangul components or Thaana
+// vowels, even though Thaana vowels are combining nonspacing marks that could
+// be considered diacritics.
+// As an exception to strictly following Unicode properties, we exclude the
+// Japanese kana voicing marks
+// 3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM
+// 309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM
+// which users report should not be ignored (bug 1624244).
+inline bool IsCombiningDiacritic(uint32_t aCh) {
+ uint8_t cc = u_getCombiningClass(aCh);
+ return cc != HB_UNICODE_COMBINING_CLASS_NOT_REORDERED &&
+ cc != HB_UNICODE_COMBINING_CLASS_KANA_VOICING;
+}
+
+// Remove diacritics from a character
+uint32_t GetNaked(uint32_t aCh);
+
+// A simple reverse iterator for a string of char16_t codepoints that
+// advances by Unicode grapheme clusters
+class ClusterReverseIterator {
+ public:
+ ClusterReverseIterator(const char16_t* aText, uint32_t aLength)
+ : mPos(aText + aLength), mLimit(aText) {}
+
+ operator const char16_t*() const { return mPos; }
+
+ bool AtEnd() const { return mPos <= mLimit; }
+
+ void Next();
+
+ private:
+ const char16_t* mPos;
+ const char16_t* mLimit;
+};
+
+} // end namespace unicode
+
+} // end namespace mozilla
+
+#endif /* NS_UNICODEPROPERTIES_H */
diff --git a/intl/unicharutil/util/nsUnicodePropertyData.cpp b/intl/unicharutil/util/nsUnicodePropertyData.cpp
new file mode 100644
index 0000000000..2127bc1f17
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp
@@ -0,0 +1,206 @@
+
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Derived from the Unicode Character Database by genUnicodePropertyData.pl
+ *
+ * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html
+ */
+
+/*
+ * Created on Thu Mar 12 09:57:47 2020 from UCD data files with version info:
+ *
+
+# Unicode Character Database
+# Date: 2020-03-06, 20:34:00 GMT [KW]
+# © 2020 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see https://www.unicode.org/terms_of_use.html
+#
+# For documentation, see the following:
+# NamesList.html
+# UAX #38, "Unicode Han Database (Unihan)"
+# UAX #44, "Unicode Character Database"
+# UTS #51, "Unicode Emoji"
+#
+# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode13.0.0/
+
+This directory contains the final data files
+for the Unicode Character Database, for Version 13.0.0 of the Unicode Standard.
+
+# IdentifierStatus.txt
+# Date: 2020-02-07, 22:02:47 GMT
+
+#
+# Unihan_Variants.txt
+# Date: 2020-02-18 18:27:33 GMT [JHJ]
+
+# VerticalOrientation-17.txt
+# Date: 2016-10-20, 07:00:00 GMT [EM, KI, LI]
+
+ *
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+
+#include <stdint.h>
+#include "harfbuzz/hb.h"
+
+#define kCharProp2MaxPlane 16
+#define kCharProp2IndexBits 9
+#define kCharProp2CharBits 7
+static const uint8_t sCharProp2Planes[16] = {1,2,3,4,4,4,4,4,4,4,4,4,4,4,5,5};
+
+static const uint8_t sCharProp2Pages[6][512] = {
+ {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,39,34,34,34,34,16,16,40,16,41,16,16,16,16,16,16,16,42,16,16,43,44,45,46,47,48,49,50,51,16,52,53,54,34,16,55,56,34,57,58,16,16,16,16,16,16,59,60,16,16,61,62,16,34,34,34,63,64,65,66,34,34,67,34,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,69,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,70,34,34,34,34,34,34,34,34,34,71,16,16,72,16,73,74,16,16,75,76,77,16,78,16,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,79,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,80,34,16,16,16,16,16,16,81,16,82,83},
+ {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,84,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,85,16,16,16,16,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,87,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,88,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,16,16,34,16,16,16,16,16,16,16,16,16,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,89,34,34,34,34,34,34,34,34,34,34,34,16,16,34,34,16,16,16,16,16,16,16,16,16,16,16,16},
+ {68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,90,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,91,68,92,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,93,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,94,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95},
+ {68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,96,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95},
+ {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16},
+ {34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95}
+};
+
+static const nsCharProps2 sCharProp2Values[97][128] = {
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{0,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{0,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0}},
+ {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{0,0},{2,0},{2,0},{0,0},{0,0},{0,1},{0,1},{0,1},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{2,1},{0,0},{0,0},{0,1},{0,1},{2,0},{2,0},{0,1},{0,1},{0,0},{3,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{3,1},{0,1},{0,1},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0}},
+ {{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,0},{2,0},{2,0},{2,0},{2,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}},
+ {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,0},{0,1},{0,0},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,0},{0,1},{0,0},{0,1},{0,1},{0,0},{0,0},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{2,0},{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{0,0},{0,0},{2,0},{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{1,0},{1,0},{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{0,0},{3,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
+ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}
+};
+#define kFullWidthMaxPlane 0
+#define kFullWidthIndexBits 10
+#define kFullWidthCharBits 6
+static const uint8_t sFullWidthPages[1024] = {
+ 0,1,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,6,7,8
+};
+
+static const uint16_t sFullWidthValues[9][64] = {
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3000,0xff01,0xff02,0xff03,0xff04,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f},
+ {0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xff5e,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe0,0xffe1,0x0000,0xffe5,0xffe4,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe2,0x0000,0x0000,0xffe3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe6,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0xff5f,0xff60,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3002,0x300c,0x300d,0x3001,0x30fb,0x30f2,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x30e3,0x30e5,0x30e7,0x30c3,0x30fc,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,0x30ad,0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,0x30bd},
+ {0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f3,0x3099,0x309a,0x3164,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x0000},
+ {0x0000,0x0000,0x314f,0x3150,0x3151,0x3152,0x3153,0x3154,0x0000,0x0000,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,0x0000,0x0000,0x315b,0x315c,0x315d,0x315e,0x315f,0x3160,0x0000,0x0000,0x3161,0x3162,0x3163,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2502,0x2190,0x2191,0x2192,0x2193,0x25a0,0x25cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}
+};
+#define kFullWidthInverseMaxPlane 0
+#define kFullWidthInverseIndexBits 10
+#define kFullWidthInverseCharBits 6
+static const uint8_t sFullWidthInversePages[1024] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,7,8,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,0,12
+};
+
+static const uint16_t sFullWidthInverseValues[13][64] = {
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe9,0xffea,0xffeb,0xffec,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0xffe8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffed,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0020,0xff64,0xff61,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff62,0xff63,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff9e,0xff9f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff67,0xff71,0xff68,0xff72,0xff69,0xff73,0xff6a,0xff74,0xff6b,0xff75,0xff76,0x0000,0xff77,0x0000,0xff78,0x0000,0xff79,0x0000,0xff7a,0x0000,0xff7b,0x0000,0xff7c,0x0000,0xff7d,0x0000,0xff7e,0x0000,0xff7f,0x0000,0xff80},
+ {0x0000,0xff81,0x0000,0xff6f,0xff82,0x0000,0xff83,0x0000,0xff84,0x0000,0xff85,0xff86,0xff87,0xff88,0xff89,0xff8a,0x0000,0x0000,0xff8b,0x0000,0x0000,0xff8c,0x0000,0x0000,0xff8d,0x0000,0x0000,0xff8e,0x0000,0x0000,0xff8f,0xff90,0xff91,0xff92,0xff93,0xff6c,0xff94,0xff6d,0xff95,0xff6e,0xff96,0xff97,0xff98,0xff99,0xff9a,0xff9b,0x0000,0xff9c,0x0000,0x0000,0xff66,0xff9d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff65,0xff70,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffa1,0xffa2,0xffa3,0xffa4,0xffa5,0xffa6,0xffa7,0xffa8,0xffa9,0xffaa,0xffab,0xffac,0xffad,0xffae,0xffaf},
+ {0xffb0,0xffb1,0xffb2,0xffb3,0xffb4,0xffb5,0xffb6,0xffb7,0xffb8,0xffb9,0xffba,0xffbb,0xffbc,0xffbd,0xffbe,0xffc2,0xffc3,0xffc4,0xffc5,0xffc6,0xffc7,0xffca,0xffcb,0xffcc,0xffcd,0xffce,0xffcf,0xffd2,0xffd3,0xffd4,0xffd5,0xffd6,0xffd7,0xffda,0xffdb,0xffdc,0xffa0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f},
+ {0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985,0x2986,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
+ {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}
+};
+/*
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
diff --git a/intl/unicharutil/util/nsUnicodeScriptCodes.h b/intl/unicharutil/util/nsUnicodeScriptCodes.h
new file mode 100644
index 0000000000..6c8fb24009
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodeScriptCodes.h
@@ -0,0 +1,267 @@
+
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Derived from the Unicode Character Database by genUnicodePropertyData.pl
+ *
+ * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html
+ */
+
+/*
+ * Created on Thu Mar 12 09:57:47 2020 from UCD data files with version info:
+ *
+
+# Unicode Character Database
+# Date: 2020-03-06, 20:34:00 GMT [KW]
+# © 2020 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see https://www.unicode.org/terms_of_use.html
+#
+# For documentation, see the following:
+# NamesList.html
+# UAX #38, "Unicode Han Database (Unihan)"
+# UAX #44, "Unicode Character Database"
+# UTS #51, "Unicode Emoji"
+#
+# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode13.0.0/
+
+This directory contains the final data files
+for the Unicode Character Database, for Version 13.0.0 of the Unicode Standard.
+
+# IdentifierStatus.txt
+# Date: 2020-02-07, 22:02:47 GMT
+
+#
+# Unihan_Variants.txt
+# Date: 2020-02-18 18:27:33 GMT [JHJ]
+
+# VerticalOrientation-17.txt
+# Date: 2016-10-20, 07:00:00 GMT [EM, KI, LI]
+
+ *
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+
+#ifndef NS_UNICODE_SCRIPT_CODES
+#define NS_UNICODE_SCRIPT_CODES
+
+
+struct nsCharProps2 {
+ // Currently only 4 bits are defined here, so 4 more could be added without
+ // affecting the storage requirements for this struct. Or we could pack two
+ // records per byte, at the cost of a slightly more complex accessor.
+ unsigned char mVertOrient:2;
+ unsigned char mIdType:2;
+};
+
+namespace mozilla {
+namespace unicode {
+enum class Script : int16_t {
+ COMMON = 0,
+ INHERITED = 1,
+ ARABIC = 2,
+ ARMENIAN = 3,
+ BENGALI = 4,
+ BOPOMOFO = 5,
+ CHEROKEE = 6,
+ COPTIC = 7,
+ CYRILLIC = 8,
+ DESERET = 9,
+ DEVANAGARI = 10,
+ ETHIOPIC = 11,
+ GEORGIAN = 12,
+ GOTHIC = 13,
+ GREEK = 14,
+ GUJARATI = 15,
+ GURMUKHI = 16,
+ HAN = 17,
+ HANGUL = 18,
+ HEBREW = 19,
+ HIRAGANA = 20,
+ KANNADA = 21,
+ KATAKANA = 22,
+ KHMER = 23,
+ LAO = 24,
+ LATIN = 25,
+ MALAYALAM = 26,
+ MONGOLIAN = 27,
+ MYANMAR = 28,
+ OGHAM = 29,
+ OLD_ITALIC = 30,
+ ORIYA = 31,
+ RUNIC = 32,
+ SINHALA = 33,
+ SYRIAC = 34,
+ TAMIL = 35,
+ TELUGU = 36,
+ THAANA = 37,
+ THAI = 38,
+ TIBETAN = 39,
+ CANADIAN_ABORIGINAL = 40,
+ YI = 41,
+ TAGALOG = 42,
+ HANUNOO = 43,
+ BUHID = 44,
+ TAGBANWA = 45,
+ BRAILLE = 46,
+ CYPRIOT = 47,
+ LIMBU = 48,
+ LINEAR_B = 49,
+ OSMANYA = 50,
+ SHAVIAN = 51,
+ TAI_LE = 52,
+ UGARITIC = 53,
+ KATAKANA_OR_HIRAGANA = 54,
+ BUGINESE = 55,
+ GLAGOLITIC = 56,
+ KHAROSHTHI = 57,
+ SYLOTI_NAGRI = 58,
+ NEW_TAI_LUE = 59,
+ TIFINAGH = 60,
+ OLD_PERSIAN = 61,
+ BALINESE = 62,
+ BATAK = 63,
+ BLISSYMBOLS = 64,
+ BRAHMI = 65,
+ CHAM = 66,
+ CIRTH = 67,
+ OLD_CHURCH_SLAVONIC_CYRILLIC = 68,
+ DEMOTIC_EGYPTIAN = 69,
+ HIERATIC_EGYPTIAN = 70,
+ EGYPTIAN_HIEROGLYPHS = 71,
+ KHUTSURI = 72,
+ SIMPLIFIED_HAN = 73,
+ TRADITIONAL_HAN = 74,
+ PAHAWH_HMONG = 75,
+ OLD_HUNGARIAN = 76,
+ HARAPPAN_INDUS = 77,
+ JAVANESE = 78,
+ KAYAH_LI = 79,
+ LATIN_FRAKTUR = 80,
+ LATIN_GAELIC = 81,
+ LEPCHA = 82,
+ LINEAR_A = 83,
+ MANDAIC = 84,
+ MAYAN_HIEROGLYPHS = 85,
+ MEROITIC_HIEROGLYPHS = 86,
+ NKO = 87,
+ OLD_TURKIC = 88,
+ OLD_PERMIC = 89,
+ PHAGS_PA = 90,
+ PHOENICIAN = 91,
+ MIAO = 92,
+ RONGORONGO = 93,
+ SARATI = 94,
+ ESTRANGELO_SYRIAC = 95,
+ WESTERN_SYRIAC = 96,
+ EASTERN_SYRIAC = 97,
+ TENGWAR = 98,
+ VAI = 99,
+ VISIBLE_SPEECH = 100,
+ CUNEIFORM = 101,
+ UNWRITTEN_LANGUAGES = 102,
+ UNKNOWN = 103,
+ CARIAN = 104,
+ JAPANESE = 105,
+ TAI_THAM = 106,
+ LYCIAN = 107,
+ LYDIAN = 108,
+ OL_CHIKI = 109,
+ REJANG = 110,
+ SAURASHTRA = 111,
+ SIGNWRITING = 112,
+ SUNDANESE = 113,
+ MOON = 114,
+ MEETEI_MAYEK = 115,
+ IMPERIAL_ARAMAIC = 116,
+ AVESTAN = 117,
+ CHAKMA = 118,
+ KOREAN = 119,
+ KAITHI = 120,
+ MANICHAEAN = 121,
+ INSCRIPTIONAL_PAHLAVI = 122,
+ PSALTER_PAHLAVI = 123,
+ BOOK_PAHLAVI = 124,
+ INSCRIPTIONAL_PARTHIAN = 125,
+ SAMARITAN = 126,
+ TAI_VIET = 127,
+ MATHEMATICAL_NOTATION = 128,
+ SYMBOLS = 129,
+ BAMUM = 130,
+ LISU = 131,
+ NAKHI_GEBA = 132,
+ OLD_SOUTH_ARABIAN = 133,
+ BASSA_VAH = 134,
+ DUPLOYAN = 135,
+ ELBASAN = 136,
+ GRANTHA = 137,
+ KPELLE = 138,
+ LOMA = 139,
+ MENDE_KIKAKUI = 140,
+ MEROITIC_CURSIVE = 141,
+ OLD_NORTH_ARABIAN = 142,
+ NABATAEAN = 143,
+ PALMYRENE = 144,
+ KHUDAWADI = 145,
+ WARANG_CITI = 146,
+ AFAKA = 147,
+ JURCHEN = 148,
+ MRO = 149,
+ NUSHU = 150,
+ SHARADA = 151,
+ SORA_SOMPENG = 152,
+ TAKRI = 153,
+ TANGUT = 154,
+ WOLEAI = 155,
+ ANATOLIAN_HIEROGLYPHS = 156,
+ KHOJKI = 157,
+ TIRHUTA = 158,
+ CAUCASIAN_ALBANIAN = 159,
+ MAHAJANI = 160,
+ AHOM = 161,
+ HATRAN = 162,
+ MODI = 163,
+ MULTANI = 164,
+ PAU_CIN_HAU = 165,
+ SIDDHAM = 166,
+ ADLAM = 167,
+ BHAIKSUKI = 168,
+ MARCHEN = 169,
+ NEWA = 170,
+ OSAGE = 171,
+ HAN_WITH_BOPOMOFO = 172,
+ JAMO = 173,
+ SYMBOLS_EMOJI = 174,
+ MASARAM_GONDI = 175,
+ SOYOMBO = 176,
+ ZANABAZAR_SQUARE = 177,
+ DOGRA = 178,
+ GUNJALA_GONDI = 179,
+ MAKASAR = 180,
+ MEDEFAIDRIN = 181,
+ HANIFI_ROHINGYA = 182,
+ SOGDIAN = 183,
+ OLD_SOGDIAN = 184,
+ ELYMAIC = 185,
+ NYIAKENG_PUACHUE_HMONG = 186,
+ NANDINAGARI = 187,
+ WANCHO = 188,
+ CHORASMIAN = 189,
+ DIVES_AKURU = 190,
+ KHITAN_SMALL_SCRIPT = 191,
+ YEZIDI = 192,
+
+ NUM_SCRIPT_CODES = 193,
+
+ INVALID = -1
+};
+} // namespace unicode
+} // namespace mozilla
+
+#endif
+/*
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */