summaryrefslogtreecommitdiffstats
path: root/intl/unicharutil
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /intl/unicharutil
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'intl/unicharutil')
-rw-r--r--intl/unicharutil/moz.build13
-rw-r--r--intl/unicharutil/nsUGenCategory.h25
-rw-r--r--intl/unicharutil/tools/README.txt3
-rwxr-xr-xintl/unicharutil/tools/genSpecialCasingData.pl309
-rwxr-xr-xintl/unicharutil/tools/genUnicodePropertyData.pl495
-rw-r--r--intl/unicharutil/util/GreekCasing.cpp315
-rw-r--r--intl/unicharutil/util/GreekCasing.h64
-rw-r--r--intl/unicharutil/util/ICUUtils.cpp170
-rw-r--r--intl/unicharutil/util/ICUUtils.h95
-rw-r--r--intl/unicharutil/util/IrishCasing.cpp270
-rw-r--r--intl/unicharutil/util/IrishCasing.h101
-rw-r--r--intl/unicharutil/util/base_chars.py162
-rw-r--r--intl/unicharutil/util/is_combining_diacritic.py102
-rw-r--r--intl/unicharutil/util/moz.build37
-rw-r--r--intl/unicharutil/util/nsBidiUtils.cpp84
-rw-r--r--intl/unicharutil/util/nsBidiUtils.h237
-rw-r--r--intl/unicharutil/util/nsSpecialCasingData.cpp202
-rw-r--r--intl/unicharutil/util/nsSpecialCasingData.h26
-rw-r--r--intl/unicharutil/util/nsUnicharUtils.cpp548
-rw-r--r--intl/unicharutil/util/nsUnicharUtils.h167
-rw-r--r--intl/unicharutil/util/nsUnicodeProperties.cpp216
-rw-r--r--intl/unicharutil/util/nsUnicodeProperties.h203
-rw-r--r--intl/unicharutil/util/nsUnicodePropertyData.cpp208
23 files changed, 4052 insertions, 0 deletions
diff --git a/intl/unicharutil/moz.build b/intl/unicharutil/moz.build
new file mode 100644
index 0000000000..ec7b335f9d
--- /dev/null
+++ b/intl/unicharutil/moz.build
@@ -0,0 +1,13 @@
+# -*- 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/.
+
+DIRS += ["util"]
+
+EXPORTS += [
+ "nsUGenCategory.h",
+]
+
+FINAL_LIBRARY = "xul"
diff --git a/intl/unicharutil/nsUGenCategory.h b/intl/unicharutil/nsUGenCategory.h
new file mode 100644
index 0000000000..8506c39820
--- /dev/null
+++ b/intl/unicharutil/nsUGenCategory.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 nsUGenCategory_h
+#define nsUGenCategory_h
+
+/**
+ * Read http://unicode.org/reports/tr44/#General_Category_Values
+ * for the detailed definition of the following categories
+ */
+enum class nsUGenCategory {
+ kUndefined = 0,
+ kMark = 1, // Mn, Mc, and Me
+ kNumber = 2, // Nd, Nl, and No
+ kSeparator = 3, // Zs, Zl, and Zp
+ kOther = 4, // Cc, Cf, Cs, Co, and Cn
+ kLetter = 5, // Lu, Ll, Lt, Lm, and Lo
+ kPunctuation = 6, // Pc, Pd, Ps, Pe, Pi, Pf, and Po
+ kSymbol = 7 // Sm, Sc, Sk, and So
+};
+
+#endif // nsUGenCategory_h
diff --git a/intl/unicharutil/tools/README.txt b/intl/unicharutil/tools/README.txt
new file mode 100644
index 0000000000..7295547f11
--- /dev/null
+++ b/intl/unicharutil/tools/README.txt
@@ -0,0 +1,3 @@
+Instructions for using these tools are on the Mozilla Wiki.
+
+https://wiki.mozilla.org/I18n:Updating_Unicode_version
diff --git a/intl/unicharutil/tools/genSpecialCasingData.pl b/intl/unicharutil/tools/genSpecialCasingData.pl
new file mode 100755
index 0000000000..9800688683
--- /dev/null
+++ b/intl/unicharutil/tools/genSpecialCasingData.pl
@@ -0,0 +1,309 @@
+#!/usr/bin/env perl
+
+# 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 tool is used to extract "special" (one-to-many) case mappings
+# into a form that can be used by nsTextRunTransformations.
+
+use strict;
+
+if ($#ARGV != 1) {
+ print <<__EOT;
+# Run this tool using a command line of the form
+#
+# perl genSpecialCasingData.pl UnicodeData.txt SpecialCasing.txt
+#
+# The nsSpecialCasingData.cpp file will be written to standard output.
+#
+# This tool will also write up-to-date versions of the test files
+# all-{upper,lower,title}.html
+# and corresponding -ref files in the current directory.
+#
+__EOT
+ exit 0;
+}
+
+my %allLower;
+my %allUpper;
+my %allTitle;
+my %compositions;
+my %gc;
+open FH, "< $ARGV[0]" or die "can't open $ARGV[0] (should be UnicodeData.txt)\n";
+while (<FH>) {
+ chomp;
+ my @fields = split /;/;
+ next if ($fields[1] =~ /</); # ignore ranges etc
+ my $usv = hex "0x$fields[0]";
+ $allUpper{$usv} = $fields[12] if $fields[12] ne '';
+ $allLower{$usv} = $fields[13] if $fields[13] ne '';
+ $allTitle{$usv} = $fields[14] if $fields[14] ne '';
+ $gc{$usv} = $fields[2];
+ # we only care about non-singleton canonical decomps
+ my $decomp = $fields[5];
+ next if $decomp eq '' or $decomp =~ /</ or not $decomp =~ / /;
+ $compositions{$decomp} = sprintf("%04X", $usv);
+}
+close FH;
+
+my %specialLower;
+my %specialUpper;
+my %specialTitle;
+my %charName;
+my @headerLines;
+open FH, "< $ARGV[1]" or die "can't open $ARGV[1] (should be SpecialCasing.txt)\n";
+while (<FH>) {
+ chomp;
+ m/#\s*(.+)$/;
+ my $comment = $1;
+ if ($comment =~ /^(SpecialCasing-|Date:)/) {
+ push @headerLines, $comment;
+ next;
+ }
+ s/#.*//;
+ s/;\s*$//;
+ next if $_ eq '';
+ my @fields = split /; */;
+ next unless (scalar @fields) == 4;
+ my $usv = hex "0x$fields[0]";
+ addIfSpecial(\%specialLower, $usv, $fields[1]);
+ addIfSpecial(\%specialTitle, $usv, $fields[2]);
+ addIfSpecial(\%specialUpper, $usv, $fields[3]);
+ $charName{$usv} = $comment;
+}
+close FH;
+
+print <<__END__;
+/* 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
+
+__END__
+map { print "/* $_ */\n" } @headerLines;
+
+print <<__END__;
+
+using mozilla::unicode::MultiCharMapping;
+
+__END__
+
+printMappings('Lower', \%specialLower);
+printMappings('Upper', \%specialUpper);
+printMappings('Title', \%specialTitle);
+
+print <<__END__;
+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
+__END__
+
+addSpecialsTo(\%allLower, \%specialLower);
+addSpecialsTo(\%allUpper, \%specialUpper);
+addSpecialsTo(\%allTitle, \%specialTitle);
+
+my $testFont = "../fonts/dejavu-sans/DejaVuSans.ttf";
+genTest('lower', \%allLower);
+genTest('upper', \%allUpper);
+genTitleTest();
+
+sub printMappings {
+ my ($whichMapping, $hash) = @_;
+ print "static const MultiCharMapping CaseSpecials_${whichMapping}[] = {\n";
+ foreach my $key (sort { $a <=> $b } keys %$hash) {
+ my @chars = split(/ /, $hash->{$key});
+ printf " { 0x%04x, {0x%04x, 0x%04x, 0x%04x} }, // %s\n", $key,
+ hex "0x0$chars[0]", hex "0x0$chars[1]", hex "0x0$chars[2]",
+ "$charName{$key}";
+ }
+ print "};\n\n";
+};
+
+sub addIfSpecial {
+ my ($hash, $usv, $mapping) = @_;
+ return unless $mapping =~ / /;
+ # only do compositions that start with the initial char
+ foreach (keys %compositions) {
+ $mapping =~ s/^$_/$compositions{$_}/;
+ }
+ $hash->{$usv} = $mapping;
+};
+
+sub addSpecialsTo {
+ my ($hash, $specials) = @_;
+ foreach my $key (keys %$specials) {
+ $hash->{$key} = $specials->{$key};
+ }
+};
+
+sub genTest {
+ my ($whichMapping, $hash) = @_;
+ open OUT, "> all-$whichMapping.html";
+ print OUT <<__END__;
+<!DOCTYPE html>
+<!-- GENERATED FILE, DO NOT EDIT -->
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <style type="text/css">
+ \@font-face { font-family: foo; src: url($testFont); }
+ p { font-family: foo; font-size: 12px; text-transform: ${whichMapping}case; }
+ </style>
+ </head>
+ <body>
+ <p>
+__END__
+ foreach my $key (sort { $a <=> $b } keys %$hash) {
+ # Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack
+ # of widespread font support for the corresponding Mtavruli characters
+ # at this time (July 2018).
+ # This condition is to be removed once the major platforms ship with
+ # fonts that support U+1C90..1CBF.
+ my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF;
+ print OUT "<!-- " if $skippedGeorgian;
+ printf OUT "&#x%04X;", $key;
+ print OUT " -->" if $skippedGeorgian;
+ print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
+ print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian;
+ print OUT "\n";
+ }
+ print OUT <<__END__;
+ </p>
+ </body>
+</html>
+__END__
+ close OUT;
+
+ open OUT, "> all-$whichMapping-ref.html";
+ print OUT <<__END__;
+<!DOCTYPE html>
+<!-- GENERATED FILE, DO NOT EDIT -->
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <style type="text/css">
+ \@font-face { font-family: foo; src: url($testFont); }
+ p { font-family: foo; font-size: 12px; }
+ </style>
+ </head>
+ <body>
+ <p>
+__END__
+ foreach my $key (sort { $a <=> $b } keys %$hash) {
+ # Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack
+ # of widespread font support for the corresponding Mtavruli characters
+ # at this time (July 2018).
+ # This condition is to be removed once the major platforms ship with
+ # fonts that support U+1C90..1CBF.
+ my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF;
+ print OUT "<!-- " if $skippedGeorgian;
+ print OUT join('', map { sprintf("&#x%s;", $_) } split(/ /, $hash->{$key}));
+ print OUT " -->" if $skippedGeorgian;
+ print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
+ print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian;
+ print OUT "\n";
+ }
+ print OUT <<__END__;
+ </p>
+ </body>
+</html>
+__END__
+ close OUT;
+};
+
+sub genTitleTest {
+ open OUT, "> all-title.html";
+ print OUT <<__END__;
+<!DOCTYPE html>
+<!-- GENERATED FILE, DO NOT EDIT -->
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <style type="text/css">
+ \@font-face { font-family: foo; src: url($testFont); }
+ p { font-family: foo; text-transform: capitalize; }
+ </style>
+ </head>
+ <body>
+ <p>
+__END__
+ foreach my $key (sort { $a <=> $b } keys %allTitle) {
+ printf OUT "&#x%04X;x", $key;
+ print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
+ print OUT "\n";
+ }
+ print OUT <<__END__;
+ </p>
+ </body>
+</html>
+__END__
+ close OUT;
+
+ open OUT, "> all-title-ref.html";
+ print OUT <<__END__;
+<!DOCTYPE html>
+<!-- GENERATED FILE, DO NOT EDIT -->
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <style type="text/css">
+ \@font-face { font-family: foo; src: url($testFont); }
+ p { font-family: foo; }
+ </style>
+ </head>
+ <body>
+ <p>
+__END__
+ foreach my $key (sort { $a <=> $b } keys %allTitle) {
+ # capitalize is only applied to characters with GC=L* or N*...
+ if ($gc{$key} =~ /^[LN]/) {
+ # ...and those that are already uppercase are not transformed
+ if (exists $allUpper{$key}) {
+ print OUT join('', map { sprintf("&#x%s;", $_) } split(/ /, $allTitle{$key}));
+ } else {
+ printf OUT "&#x%04X;", $key;
+ }
+ print OUT "x";
+ } else {
+ printf OUT "&#x%04X;X", $key;
+ }
+ print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
+ print OUT "\n";
+ }
+ print OUT <<__END__;
+ </p>
+ </body>
+</html>
+__END__
+ close OUT;
+};
diff --git a/intl/unicharutil/tools/genUnicodePropertyData.pl b/intl/unicharutil/tools/genUnicodePropertyData.pl
new file mode 100755
index 0000000000..f72f18f1ae
--- /dev/null
+++ b/intl/unicharutil/tools/genUnicodePropertyData.pl
@@ -0,0 +1,495 @@
+#!/usr/bin/env perl
+
+# 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 tool is used to prepare lookup tables of Unicode character properties
+# needed by gfx code to support text shaping operations. The properties are
+# read from the Unicode Character Database and compiled into multi-level arrays
+# for efficient lookup.
+#
+# Note that for most properties, we now rely on ICU; this tool and the tables
+# it generates are used only for a couple of properties not readily exposed
+# via ICU APIs.
+#
+# To regenerate the tables in nsUnicodePropertyData.cpp:
+#
+# (1) Download the current Unicode data files from
+#
+# https://www.unicode.org/Public/UNIDATA/
+#
+# NB: not all the files are actually needed; currently, we require
+# - UnicodeData.txt
+# - ReadMe.txt (to record version/date of the UCD)
+# - Unihan_Variants.txt (from Unihan.zip)
+# though this may change if we find a need for additional properties.
+#
+# The Unicode data files listed above should be together in one directory.
+#
+# We also require the file
+# https://www.unicode.org/Public/security/latest/IdentifierStatus.txt
+# This file should be in a sub-directory "security" immediately below the
+# directory containing the other Unicode data files.
+#
+# We also require the latest data file for UTR50, currently revision-17:
+# https://www.unicode.org/Public/vertical/revision-17/VerticalOrientation-17.txt
+# This file should be in a sub-directory "vertical" immediately below the
+# directory containing the other Unicode data files.
+#
+#
+# (2) Run this tool using a command line of the form
+#
+# perl genUnicodePropertyData.pl \
+# /path/to/icu/common/unicode \
+# /path/to/UCD-directory
+#
+# This will generate (or overwrite!) the files
+#
+# nsUnicodePropertyData.cpp
+# UnicodeScriptCodes.h
+#
+# in the current directory.
+
+use strict;
+use List::Util qw(first);
+
+if ($#ARGV != 1) {
+ print <<__EOT;
+# Run this tool using a command line of the form
+#
+# perl genUnicodePropertyData.pl \\
+# /path/to/icu/common/unicode \\
+# /path/to/UCD-directory
+#
+# where icu/common/unicode is the directory containing ICU 'common' headers,
+# and UCD-directory is a directory containing the current Unicode Character
+# Database files (UnicodeData.txt, etc), available from
+# https://www.unicode.org/Public/UNIDATA/, with additional resources as
+# detailed in the source comments.
+#
+# This will generate (or overwrite!) the files
+#
+# nsUnicodePropertyData.cpp
+# UnicodeScriptCodes.h
+#
+# in the current directory.
+__EOT
+ exit 0;
+}
+
+my $ICU = $ARGV[0];
+my $UNICODE = $ARGV[1];
+
+my @scriptCodeToName;
+my @idtype;
+
+my $sc = -1;
+
+sub readIcuHeader
+{
+ my $file = shift;
+ open FH, "< $ICU/$file" or die "can't open ICU header $ICU/$file\n";
+ while (<FH>) {
+ # adjust for ICU vs UCD naming discrepancies
+ s/LANNA/TAI_THAM/;
+ s/MEITEI_MAYEK/MEETEI_MAYEK/;
+ s/ORKHON/OLD_TURKIC/;
+ s/MENDE/MENDE_KIKAKUI/;
+ s/SIGN_WRITING/SIGNWRITING/;
+ if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) {
+ $sc = $2;
+ $scriptCodeToName[$sc] = $1;
+ }
+ }
+ close FH;
+}
+
+&readIcuHeader("uscript.h");
+
+die "didn't find ICU script codes\n" if $sc == -1;
+
+# We don't currently store these values; %idType is used only to check that
+# properties listed in the IdentifierType.txt file are recognized. We record
+# only the %mappedIdType values that are used by nsIDNService::isLabelSafe.
+# In practice, it would be sufficient for us to read only the last value in
+# IdentifierType.txt, but we check that all values are known so that we'll get
+# a warning if future updates introduce new ones, and can consider whether
+# they need to be taken into account.
+my %idType = (
+ "Not_Character" => 0,
+ "Recommended" => 1,
+ "Inclusion" => 2,
+ "Uncommon_Use" => 3,
+ "Technical" => 4,
+ "Obsolete" => 5,
+ "Aspirational" => 6,
+ "Limited_Use" => 7,
+ "Exclusion" => 8,
+ "Not_XID" => 9,
+ "Not_NFKC" => 10,
+ "Default_Ignorable" => 11,
+ "Deprecated" => 12
+);
+
+# These match the IdentifierType enum in UnicodeProperties.h.
+my %mappedIdType = (
+ "Restricted" => 0,
+ "Allowed" => 1
+);
+
+my %verticalOrientationCode = (
+ 'U' => 0, # U - Upright, the same orientation as in the code charts
+ 'R' => 1, # R - Rotated 90 degrees clockwise compared to the code charts
+ 'Tu' => 2, # Tu - Transformed typographically, with fallback to Upright
+ 'Tr' => 3 # Tr - Transformed typographically, with fallback to Rotated
+);
+
+# initialize default properties
+my @hanVariant;
+my @fullWidth;
+my @fullWidthInverse;
+my @verticalOrientation;
+for (my $i = 0; $i < 0x110000; ++$i) {
+ $hanVariant[$i] = 0;
+ $fullWidth[$i] = 0;
+ $fullWidthInverse[$i] = 0;
+ $verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R'
+}
+
+# read ReadMe.txt
+my @versionInfo;
+open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n";
+while (<FH>) {
+ chomp;
+ push @versionInfo, $_;
+}
+close FH;
+
+# read UnicodeData.txt
+open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n";
+while (<FH>) {
+ chomp;
+ my @fields = split /;/;
+ if ($fields[1] =~ /First/) {
+ my $first = hex "0x$fields[0]";
+ $_ = <FH>;
+ @fields = split /;/;
+ if ($fields[1] =~ /Last/) {
+ my $last = hex "0x$fields[0]";
+ do {
+ if ($fields[1] =~ /CJK/) {
+ @hanVariant[$first] = 3;
+ }
+ $first++;
+ } while ($first <= $last);
+ } else {
+ die "didn't find Last code for range!\n";
+ }
+ } else {
+ my $usv = hex "0x$fields[0]";
+ if ($fields[1] =~ /CJK/) {
+ @hanVariant[$usv] = 3;
+ }
+ if ($fields[5] =~ /^<narrow>/) {
+ my $wideChar = hex(substr($fields[5], 9));
+ die "didn't expect supplementary-plane values here" if $usv > 0xffff || $wideChar > 0xffff;
+ $fullWidth[$usv] = $wideChar;
+ $fullWidthInverse[$wideChar] = $usv;
+ }
+ elsif ($fields[5] =~ /^<wide>/) {
+ my $narrowChar = hex(substr($fields[5], 7));
+ die "didn't expect supplementary-plane values here" if $usv > 0xffff || $narrowChar > 0xffff;
+ $fullWidth[$narrowChar] = $usv;
+ $fullWidthInverse[$usv] = $narrowChar;
+ }
+ }
+}
+close FH;
+
+# read IdentifierStatus.txt
+open FH, "< $UNICODE/security/IdentifierStatus.txt" or die "can't open UCD file IdentifierStatus.txt\n";
+push @versionInfo, "";
+while (<FH>) {
+ chomp;
+ s/\xef\xbb\xbf//;
+ push @versionInfo, $_;
+ last if /Date:/;
+}
+while (<FH>) {
+ if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+Allowed/) {
+ my $start = hex "0x$1";
+ my $end = (defined $2) ? hex "0x$2" : $start;
+ for (my $i = $start; $i <= $end; ++$i) {
+ $idtype[$i] = $mappedIdType{'Allowed'};
+ }
+ }
+}
+close FH;
+
+open FH, "< $UNICODE/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n";
+push @versionInfo, "";
+while (<FH>) {
+ chomp;
+ push @versionInfo, $_;
+ last if /Date:/;
+}
+my $savedusv = 0;
+my $hasTC = 0;
+my $hasSC = 0;
+while (<FH>) {
+ chomp;
+ if (m/U\+([0-9A-F]{4,6})\s+k([^ ]+)Variant/) {
+ my $usv = hex "0x$1";
+ if ($usv != $savedusv) {
+ unless ($savedusv == 0) {
+ if ($hasTC && !$hasSC) {
+ $hanVariant[$savedusv] = 1;
+ } elsif (!$hasTC && $hasSC) {
+ $hanVariant[$savedusv] = 2;
+ }
+ }
+ $savedusv = $usv;
+ $hasTC = 0;
+ $hasSC = 0;
+ }
+ if ($2 eq "Traditional") {
+ $hasTC = 1;
+ }
+ if ($2 eq "Simplified") {
+ $hasSC = 1;
+ }
+ }
+}
+close FH;
+
+# read VerticalOrientation-17.txt
+open FH, "< $UNICODE/vertical/VerticalOrientation-17.txt" or die "can't open UTR50 data file VerticalOrientation-17.txt\n";
+push @versionInfo, "";
+while (<FH>) {
+ chomp;
+ push @versionInfo, $_;
+ last if /Date:/;
+}
+while (<FH>) {
+ chomp;
+ s/#.*//;
+ if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
+ my $vo = $3;
+ warn "unknown Vertical_Orientation code $vo"
+ unless exists $verticalOrientationCode{$vo};
+ $vo = $verticalOrientationCode{$vo};
+ my $start = hex "0x$1";
+ my $end = (defined $2) ? hex "0x$2" : $start;
+ for (my $i = $start; $i <= $end; ++$i) {
+ $verticalOrientation[$i] = $vo;
+ }
+ }
+}
+close FH;
+
+my $timestamp = gmtime();
+
+open DATA_TABLES, "> nsUnicodePropertyData.cpp" or die "unable to open nsUnicodePropertyData.cpp for output";
+
+my $licenseBlock = q[/* 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
+ */
+];
+
+my $versionInfo = join("\n", @versionInfo);
+
+print DATA_TABLES <<__END;
+$licenseBlock
+/*
+ * Created on $timestamp from UCD data files with version info:
+ *
+
+$versionInfo
+
+ *
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+
+#include <stdint.h>
+#include "harfbuzz/hb.h"
+
+__END
+
+open HEADER, "> UnicodeScriptCodes.h" or die "unable to open UnicodeScriptCodes.h for output";
+
+print HEADER <<__END;
+$licenseBlock
+/*
+ * Created on $timestamp from UCD data files with version info:
+ *
+
+$versionInfo
+
+ *
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+
+#ifndef intl_components_UnicodeScriptCodes_h_
+#define intl_components_UnicodeScriptCodes_h_
+
+__END
+
+our $totalData = 0;
+
+sub sprintCharProps2_short
+{
+ my $usv = shift;
+ return sprintf("{%d,%d},",
+ $verticalOrientation[$usv], $idtype[$usv]);
+}
+&genTables("CharProp2", "", "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
+
+sub sprintHanVariants
+{
+ my $baseUsv = shift;
+ my $varShift = 0;
+ my $val = 0;
+ while ($varShift < 8) {
+ $val |= $hanVariant[$baseUsv++] << $varShift;
+ $varShift += 2;
+ }
+ return sprintf("0x%02x,", $val);
+}
+## Han Variant data currently unused but may be needed in future, see bug 857481
+## &genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
+
+sub sprintFullWidth
+{
+ my $usv = shift;
+ return sprintf("0x%04x,", $fullWidth[$usv]);
+}
+&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
+
+sub sprintFullWidthInverse
+{
+ my $usv = shift;
+ return sprintf("0x%04x,", $fullWidthInverse[$usv]);
+}
+&genTables("FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1);
+
+print STDERR "Total data = $totalData\n";
+
+sub genTables
+{
+ my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
+
+ if ($typedef ne '') {
+ print HEADER "$typedef\n";
+ }
+
+ print DATA_TABLES "#define k${prefix}MaxPlane $maxPlane\n";
+ print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n";
+ print DATA_TABLES "#define k${prefix}CharBits $charBits\n";
+
+ my $indexLen = 1 << $indexBits;
+ my $charsPerPage = 1 << $charBits;
+ my %charIndex = ();
+ my %pageMapIndex = ();
+ my @pageMap = ();
+ my @char = ();
+
+ my $planeMap = "\x00" x $maxPlane;
+ foreach my $plane (0 .. $maxPlane) {
+ my $pageMap = "\x00" x $indexLen * 2;
+ foreach my $page (0 .. $indexLen - 1) {
+ my $charValues = "";
+ for (my $ch = 0; $ch < $charsPerPage; $ch += $charsPerEntry) {
+ my $usv = $plane * 0x10000 + $page * $charsPerPage + $ch;
+ $charValues .= &$func($usv);
+ }
+ chop $charValues;
+
+ unless (exists $charIndex{$charValues}) {
+ $charIndex{$charValues} = scalar keys %charIndex;
+ $char[$charIndex{$charValues}] = $charValues;
+ }
+ substr($pageMap, $page * 2, 2) = pack('S', $charIndex{$charValues});
+ }
+
+ unless (exists $pageMapIndex{$pageMap}) {
+ $pageMapIndex{$pageMap} = scalar keys %pageMapIndex;
+ $pageMap[$pageMapIndex{$pageMap}] = $pageMap;
+ }
+ if ($plane > 0) {
+ substr($planeMap, $plane - 1, 1) = pack('C', $pageMapIndex{$pageMap});
+ }
+ }
+
+ if ($maxPlane) {
+ print DATA_TABLES "static const uint8_t s${prefix}Planes[$maxPlane] = {";
+ print DATA_TABLES join(',', map { sprintf("%d", $_) } unpack('C*', $planeMap));
+ print DATA_TABLES "};\n\n";
+ }
+
+ my $chCount = scalar @char;
+ my $pmBits = $chCount > 255 ? 16 : 8;
+ my $pmCount = scalar @pageMap;
+ if ($maxPlane == 0) {
+ die "there should only be one pageMap entry!" if $pmCount > 1;
+ print DATA_TABLES "static const uint${pmBits}_t s${prefix}Pages[$indexLen] = {\n";
+ } else {
+ print DATA_TABLES "static const uint${pmBits}_t s${prefix}Pages[$pmCount][$indexLen] = {\n";
+ }
+ for (my $i = 0; $i < scalar @pageMap; ++$i) {
+ print DATA_TABLES $maxPlane > 0 ? " {" : " ";
+ print DATA_TABLES join(',', map { sprintf("%d", $_) } unpack('S*', $pageMap[$i]));
+ print DATA_TABLES $maxPlane > 0 ? ($i < $#pageMap ? "},\n" : "}\n") : "\n";
+ }
+ print DATA_TABLES "};\n\n";
+
+ my $pageLen = $charsPerPage / $charsPerEntry;
+ print DATA_TABLES "static const $type s${prefix}Values[$chCount][$pageLen] = {\n";
+ for (my $i = 0; $i < scalar @char; ++$i) {
+ print DATA_TABLES " {";
+ print DATA_TABLES $char[$i];
+ print DATA_TABLES $i < $#char ? "},\n" : "}\n";
+ }
+ print DATA_TABLES "};\n";
+
+ my $dataSize = $pmCount * $indexLen * $pmBits/8 +
+ $chCount * $pageLen * $bytesPerEntry +
+ $maxPlane;
+ $totalData += $dataSize;
+
+ print STDERR "Data for $prefix = $dataSize\n";
+}
+
+print DATA_TABLES <<__END;
+/*
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+__END
+
+close DATA_TABLES;
+
+print HEADER "namespace mozilla::intl {\n";
+print HEADER "enum class Script : int16_t {\n";
+for (my $i = 0; $i < scalar @scriptCodeToName; ++$i) {
+ print HEADER " ", $scriptCodeToName[$i], " = ", $i, ",\n";
+}
+print HEADER "\n NUM_SCRIPT_CODES = ", scalar @scriptCodeToName, ",\n";
+print HEADER "\n INVALID = -1\n";
+print HEADER "};\n";
+print HEADER "} // namespace mozilla::intl\n\n";
+
+print HEADER <<__END;
+#endif
+/*
+ * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
+ */
+__END
+
+close HEADER;
+
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..ea3579f27c
--- /dev/null
+++ b/intl/unicharutil/util/ICUUtils.cpp
@@ -0,0 +1,170 @@
+/* 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 "mozilla/intl/FormatBuffer.h"
+# include "mozilla/intl/NumberFormat.h"
+# include "mozilla/intl/NumberParser.h"
+# include "nsIContent.h"
+# include "mozilla/dom/Document.h"
+# include "nsString.h"
+
+using namespace mozilla;
+using mozilla::intl::LocaleService;
+
+already_AddRefed<nsAtom> ICUUtils::LanguageTagIterForContent::GetNext() {
+ 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:
+ if (auto* lang = mContent->GetLang()) {
+ return do_AddRef(lang);
+ }
+ }
+
+ if (mCurrentFallbackIndex < 1) {
+ mCurrentFallbackIndex = 1;
+ // Else try the language specified by any Content-Language HTTP header or
+ // pragma directive:
+ if (nsAtom* lang = mContent->OwnerDoc()->GetContentLanguage()) {
+ return do_AddRef(lang);
+ }
+ }
+
+ if (mCurrentFallbackIndex < 2) {
+ mCurrentFallbackIndex = 2;
+ // Else take the app's locale (or en-US, if spoof English applies):
+ if (mContent->OwnerDoc()->ShouldResistFingerprinting(RFPTarget::JSLocale)) {
+ return NS_Atomize("en-US");
+ }
+ nsAutoCString appLocale;
+ LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
+ return NS_Atomize(appLocale);
+ }
+
+ // TODO: Probably not worth it, but maybe have a fourth fallback to using
+ // the OS locale?
+ return nullptr;
+}
+
+/* static */
+bool ICUUtils::LocalizeNumber(double aValue,
+ LanguageTagIterForContent& aLangTags,
+ nsAString& aLocalizedValue) {
+ MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
+ MOZ_ASSERT(NS_IsMainThread());
+ using LangToFormatterCache =
+ nsTHashMap<RefPtr<nsAtom>, UniquePtr<intl::NumberFormat>>;
+
+ static StaticAutoPtr<LangToFormatterCache> sCache;
+ if (!sCache) {
+ sCache = new LangToFormatterCache();
+ ClearOnShutdown(&sCache);
+ }
+
+ intl::NumberFormatOptions options;
+ if (StaticPrefs::dom_forms_number_grouping()) {
+ options.mGrouping = intl::NumberFormatOptions::Grouping::Always;
+ } else {
+ options.mGrouping = intl::NumberFormatOptions::Grouping::Never;
+ }
+
+ // 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).
+ options.mFractionDigits = Some(std::make_pair(0, 16));
+
+ while (RefPtr<nsAtom> langTag = aLangTags.GetNext()) {
+ auto& formatter = sCache->LookupOrInsertWith(langTag, [&] {
+ nsAutoCString tag;
+ langTag->ToUTF8String(tag);
+ return intl::NumberFormat::TryCreate(tag, options).unwrapOr(nullptr);
+ });
+ if (!formatter) {
+ continue;
+ }
+ intl::nsTStringToBufferAdapter adapter(aLocalizedValue);
+ if (formatter->format(aValue, adapter).isOk()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* static */
+double ICUUtils::ParseNumber(const nsAString& aValue,
+ LanguageTagIterForContent& aLangTags) {
+ MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
+ using LangToParserCache =
+ nsTHashMap<RefPtr<nsAtom>, UniquePtr<intl::NumberParser>>;
+ static StaticAutoPtr<LangToParserCache> sCache;
+ if (aValue.IsEmpty()) {
+ return std::numeric_limits<float>::quiet_NaN();
+ }
+
+ if (!sCache) {
+ sCache = new LangToParserCache();
+ ClearOnShutdown(&sCache);
+ }
+
+ const Span<const char16_t> value(aValue.BeginReading(), aValue.Length());
+
+ while (RefPtr<nsAtom> langTag = aLangTags.GetNext()) {
+ auto& parser = sCache->LookupOrInsertWith(langTag, [&] {
+ nsAutoCString tag;
+ langTag->ToUTF8String(tag);
+ return intl::NumberParser::TryCreate(
+ tag.get(), StaticPrefs::dom_forms_number_grouping())
+ .unwrapOr(nullptr);
+ });
+ if (!parser) {
+ continue;
+ }
+ static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
+ "Unexpected character size - the following cast is unsafe");
+ auto parseResult = parser->ParseDouble(value);
+ if (!parseResult.isOk()) {
+ continue;
+ }
+ std::pair<double, int32_t> parsed = parseResult.unwrap();
+ if (parsed.second == static_cast<int32_t>(value.Length())) {
+ return parsed.first;
+ }
+ }
+ 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::ICUErrorToNsResult(const intl::ICUError aError) {
+ switch (aError) {
+ case intl::ICUError::OutOfMemory:
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ default:
+ return NS_ERROR_FAILURE;
+ }
+}
+
+#endif /* MOZILLA_INTERNAL_API */
diff --git a/intl/unicharutil/util/ICUUtils.h b/intl/unicharutil/util/ICUUtils.h
new file mode 100644
index 0000000000..c5d95d773f
--- /dev/null
+++ b/intl/unicharutil/util/ICUUtils.h
@@ -0,0 +1,95 @@
+/* -*- 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 "nsStringFwd.h"
+# include "unicode/unum.h" // for UNumberFormat
+# include "mozilla/intl/ICUError.h"
+# include "mozilla/AlreadyAddRefed.h"
+
+class nsIContent;
+class nsAtom;
+
+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.
+ */
+ already_AddRefed<nsAtom> GetNext();
+
+ 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(const nsAString& aValue,
+ LanguageTagIterForContent& aLangTags);
+
+ static void AssignUCharArrayToString(UChar* aICUString, int32_t aLength,
+ nsAString& aMozString);
+
+ /**
+ * Map ICUError to nsresult
+ */
+ static nsresult ICUErrorToNsResult(const mozilla::intl::ICUError aError);
+
+# 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..566d9c38ae
--- /dev/null
+++ b/intl/unicharutil/util/IrishCasing.cpp
@@ -0,0 +1,270 @@
+/* -*- 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'];
+ }
+
+ if (aCh >= 'A' && aCh <= 'Z') {
+ return sUcClasses[aCh - 'A'];
+ }
+
+ if (GetGenCategory(aCh) == nsUGenCategory::kLetter) {
+ if (aCh == a_ACUTE || aCh == e_ACUTE || aCh == i_ACUTE || aCh == o_ACUTE ||
+ aCh == u_ACUTE) {
+ return kClass_vowel;
+ }
+
+ if (aCh == A_ACUTE || aCh == E_ACUTE || aCh == I_ACUTE || aCh == O_ACUTE ||
+ aCh == U_ACUTE) {
+ return kClass_Vowel;
+ }
+
+ return kClass_letter;
+ }
+
+ if (aCh == '-' || aCh == HYPHEN || aCh == NO_BREAK_HYPHEN) {
+ return kClass_hyph;
+ }
+
+ 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/base_chars.py b/intl/unicharutil/util/base_chars.py
new file mode 100644
index 0000000000..91d3ba3352
--- /dev/null
+++ b/intl/unicharutil/util/base_chars.py
@@ -0,0 +1,162 @@
+# 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/.
+
+import re
+from collections import namedtuple
+from unicodedata import category, combining, normalize
+
+UNICODE_LIMIT = 0x110000
+
+UNICODE_COMBINING_CLASS_NOT_REORDERED = 0
+UNICODE_COMBINING_CLASS_KANA_VOICING = 8
+UNICODE_COMBINING_CLASS_VIRAMA = 9
+
+BaseCharMapping = namedtuple("BaseCharMapping", ("char", "base_char"))
+BaseCharMappingBlock = namedtuple("BaseCharMappingBlock", ("first", "last", "offset"))
+
+
+# Keep this function in sync with IsCombiningDiacritic in nsUnicodeProperties.h.
+def is_combining_diacritic(char):
+ return combining(char) not in (
+ UNICODE_COMBINING_CLASS_NOT_REORDERED,
+ UNICODE_COMBINING_CLASS_KANA_VOICING,
+ UNICODE_COMBINING_CLASS_VIRAMA,
+ 91,
+ 129,
+ 130,
+ 132,
+ )
+
+
+# Keep this function in sync with IsMathOrMusicSymbol in nsUnicodeProperties.h.
+def is_math_or_music_symbol(char):
+ return category(char) in ("Sm", "So")
+
+
+def changes_plane(char, base_char):
+ # Mappings that would change the first 16 bits of a character are not
+ # currently supported. This is because the mapping table only records the
+ # last 16 bits of the base character and also because moving into or out of
+ # the basic multilingual plane would change the length of a UTF-16 string.
+ return ord(char) >> 16 != ord(base_char) >> 16
+
+
+def main(header, fallback_table):
+ mappings = {}
+
+ # Glean mappings from decompositions
+
+ for char in range(UNICODE_LIMIT):
+ char = chr(char)
+ if is_combining_diacritic(char) or is_math_or_music_symbol(char):
+ continue
+ decomposition = normalize("NFD", char)
+ if len(decomposition) < 2:
+ continue
+ base_char = decomposition[0]
+ if changes_plane(char, base_char):
+ continue
+ next_char = decomposition[1]
+ if not is_combining_diacritic(next_char):
+ # 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).
+ continue
+ mappings[char] = base_char
+
+ # Add mappings from the ASCII fallback table
+
+ for line in open(fallback_table, encoding="UTF-8"):
+ m = re.match("^(.) → (.+?) ;", line)
+ if not m:
+ continue
+ char = m.group(1)
+ decomposition = m.group(2)
+ if len(decomposition) >= 3:
+ if decomposition.startswith("'") and decomposition.endswith("'"):
+ decomposition = decomposition[1:-1]
+ if len(decomposition) >= 2:
+ if decomposition.startswith("\\"):
+ decomposition = decomposition[1:]
+ if len(decomposition) > 1:
+ continue
+ if changes_plane(char, decomposition):
+ continue
+ mappings[char] = decomposition
+
+ # Organize mappings into contiguous blocks
+
+ mappings = sorted([BaseCharMapping(ord(k), ord(v)) for k, v in mappings.items()])
+ blocks = []
+ i = 0
+ while i < len(mappings) - 1:
+ offset = i
+ first = mappings[i].char & 0xFF
+ while (
+ i < len(mappings) - 1 and mappings[i].char >> 8 == mappings[i + 1].char >> 8
+ ):
+ while (
+ i < len(mappings) - 1
+ and mappings[i].char >> 8 == mappings[i + 1].char >> 8
+ and mappings[i + 1].char - mappings[i].char > 1
+ ):
+ char = mappings[i].char + 1
+ mappings.insert(i + 1, BaseCharMapping(char, char))
+ i += 1
+ i += 1
+ last = mappings[i].char & 0xFF
+ blocks.append(BaseCharMappingBlock(first, last, offset))
+ i += 1
+
+ indexes = []
+ for i, block in enumerate(blocks):
+ while len(indexes) < mappings[block.offset].char >> 8:
+ indexes.append(255)
+ indexes.append(i)
+
+ # Write the mappings to a C header file
+
+ header.write("struct BaseCharMappingBlock {\n")
+ header.write(" uint8_t mFirst;\n")
+ header.write(" uint8_t mLast;\n")
+ header.write(" uint16_t mMappingStartOffset;\n")
+ header.write("};\n")
+ header.write("\n")
+ header.write("static const uint16_t BASE_CHAR_MAPPING_LIST[] = {\n")
+ for char, base_char in mappings:
+ header.write(
+ " /* {:#06x}".format(char)
+ + " */ "
+ + "{:#06x}".format(base_char & 0xFFFF)
+ + ","
+ )
+ if char != base_char:
+ header.write(" /* " + chr(char) + " → " + chr(base_char) + " */")
+ header.write("\n")
+ header.write("};\n")
+ header.write("\n")
+ header.write(
+ "static const struct BaseCharMappingBlock BASE_CHAR_MAPPING_BLOCKS[] = {\n"
+ )
+ for block in blocks:
+ header.write(
+ " {"
+ + "{:#04x}".format(block.first)
+ + ", "
+ + "{:#04x}".format(block.last)
+ + ", "
+ + str(block.offset).rjust(4)
+ + "}, // "
+ + "{:#04x}".format(mappings[block.offset].char >> 8)
+ + "xx\n"
+ )
+ header.write("};\n")
+ header.write("\n")
+ header.write("static const uint8_t BASE_CHAR_MAPPING_BLOCK_INDEX[] = {\n")
+ for i, index in enumerate(indexes):
+ header.write(
+ " " + str(index).rjust(3) + ", // " + "{:#04x}".format(i) + "xx\n"
+ )
+ header.write("};\n")
diff --git a/intl/unicharutil/util/is_combining_diacritic.py b/intl/unicharutil/util/is_combining_diacritic.py
new file mode 100644
index 0000000000..d8c3c4ba35
--- /dev/null
+++ b/intl/unicharutil/util/is_combining_diacritic.py
@@ -0,0 +1,102 @@
+# 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/.
+
+from unicodedata import combining
+
+UNICODE_LIMIT = 0x110000
+
+UNICODE_COMBINING_CLASS_NOT_REORDERED = 0
+UNICODE_COMBINING_CLASS_KANA_VOICING = 8
+UNICODE_COMBINING_CLASS_VIRAMA = 9
+
+
+# Keep this function in sync with IsCombiningDiacritic in nsUnicodeProperties.h.
+def is_combining_diacritic(char):
+ return combining(char) not in (
+ UNICODE_COMBINING_CLASS_NOT_REORDERED,
+ UNICODE_COMBINING_CLASS_KANA_VOICING,
+ UNICODE_COMBINING_CLASS_VIRAMA,
+ 91,
+ 129,
+ 130,
+ 132,
+ )
+
+
+# See gfxFontUtils.h for the SharedBitSet that we're creating a const instance of here.
+BLOCK_SIZE = 32
+BLOCK_SIZE_BITS = BLOCK_SIZE * 8
+
+
+def main(header):
+ blockIndex = []
+ blocks = []
+
+ # Figure out the contents of each 256-char block, and see if it is unique
+ # or can share an already-allocated block.
+ block = [0] * BLOCK_SIZE
+ byte = 0
+ bit = 0x01
+ for char in range(UNICODE_LIMIT):
+ if is_combining_diacritic(chr(char)):
+ block[byte] |= bit
+ bit <<= 1
+ if bit == 0x100:
+ bit = 0x01
+ byte += 1
+ if byte == BLOCK_SIZE:
+ found = False
+ for b in range(len(blocks)):
+ if block == blocks[b]:
+ blockIndex.append(b)
+ found = True
+ break
+ if not found:
+ blockIndex.append(len(blocks))
+ blocks.append(block)
+ byte = 0
+ block = [0] * BLOCK_SIZE
+
+ # Strip trailing empty blocks from the index.
+ while blockIndex[len(blockIndex) - 1] == 0:
+ del blockIndex[len(blockIndex) - 1]
+
+ # Write the SharedBitSet as data in a C++ header file.
+ header.write("/* !GENERATED DATA -- DO NOT EDIT! */\n")
+ header.write("/* (see is_combining_diacritic.py) */\n")
+ header.write("\n")
+ header.write('#include "gfxFontUtils.h"\n')
+ header.write("\n")
+
+ header.write("typedef struct {\n")
+ header.write(" uint16_t mBlockIndexCount;\n")
+ header.write(" uint16_t mBlockCount;\n")
+ header.write(" uint16_t mBlockIndex[" + str(len(blockIndex)) + "];\n")
+ header.write(" uint8_t mBlockData[" + str(len(blocks) * BLOCK_SIZE) + "];\n")
+ header.write("} CombiningDiacriticsBitset_t;\n")
+ header.write("\n")
+
+ header.write(
+ "static const CombiningDiacriticsBitset_t COMBINING_DIACRITICS_BITSET_DATA = {\n"
+ )
+ header.write(" " + str(len(blockIndex)) + ",\n")
+ header.write(" " + str(len(blocks)) + ",\n")
+ header.write(" {\n")
+ for b in blockIndex:
+ header.write(" " + str(b) + ",\n")
+ header.write(" },\n")
+ header.write(" {\n")
+ for b in blocks:
+ header.write(" ")
+ for i in b:
+ header.write(str(i) + ",")
+ header.write("\n")
+ header.write(" },\n")
+ header.write("};\n")
+ header.write("\n")
+ header.write("static const SharedBitSet* sCombiningDiacriticsSet =\n")
+ header.write(
+ " reinterpret_cast<const SharedBitSet*>(&COMBINING_DIACRITICS_BITSET_DATA);\n"
+ )
+ header.write("\n")
diff --git a/intl/unicharutil/util/moz.build b/intl/unicharutil/util/moz.build
new file mode 100644
index 0000000000..2bbd00415c
--- /dev/null
+++ b/intl/unicharutil/util/moz.build
@@ -0,0 +1,37 @@
+# -*- 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",
+]
+
+UNIFIED_SOURCES += [
+ "GreekCasing.cpp",
+ "ICUUtils.cpp",
+ "IrishCasing.cpp",
+ "nsBidiUtils.cpp",
+ "nsSpecialCasingData.cpp",
+ "nsUnicharUtils.cpp",
+ "nsUnicodeProperties.cpp",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+GeneratedFile(
+ "BaseChars.h",
+ script="base_chars.py",
+ inputs=["../../icu/source/data/translit/Latin_ASCII.txt"],
+)
+
+GeneratedFile("IsCombiningDiacritic.h", script="is_combining_diacritic.py", force=True)
+
+FINAL_LIBRARY = "xul"
diff --git a/intl/unicharutil/util/nsBidiUtils.cpp b/intl/unicharutil/util/nsBidiUtils.cpp
new file mode 100644
index 0000000000..6c399dbc46
--- /dev/null
+++ b/intl/unicharutil/util/nsBidiUtils.cpp
@@ -0,0 +1,84 @@
+/* -*- 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"
+
+#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..a5ec94f3b5
--- /dev/null
+++ b/intl/unicharutil/util/nsBidiUtils.h
@@ -0,0 +1,237 @@
+/* -*- 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 "mozilla/intl/BidiClass.h"
+
+#include "nsString.h"
+#include "encoding_rs_mem.h"
+
+/**
+ * definitions of bidirection character types by category
+ */
+
+#define BIDICLASS_IS_RTL(val) \
+ (((val) == mozilla::intl::BidiClass::RightToLeft) || \
+ ((val) == mozilla::intl::BidiClass::RightToLeftArabic))
+
+#define BIDICLASS_IS_WEAK(val) \
+ (((val) == mozilla::intl::BidiClass::EuropeanNumberSeparator) || \
+ ((val) == mozilla::intl::BidiClass::EuropeanNumberTerminator) || \
+ (((val) > mozilla::intl::BidiClass::ArabicNumber) && \
+ ((val) != mozilla::intl::BidiClass::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..9908406a35
--- /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-15.0.0.txt */
+/* Date: 2022-02-02, 23:35:52 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..31ac06a52d
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicharUtils.cpp
@@ -0,0 +1,548 @@
+/* -*- 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 "nsUnicodeProperties.h"
+#include "nsUTF8Utils.h"
+#include "mozilla/Likely.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/intl/UnicodeProperties.h"
+#include "mozilla/StaticPrefs_layout.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::intl::UnicodeProperties::ToLower(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();
+ size_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();
+ size_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();
+ size_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, size_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, size_t lLength,
+ size_t rLength) {
+ return (lLength == rLength) ? CaseInsensitiveCompare(lhs, rhs, lLength)
+ : (lLength > rLength) ? 1
+ : -1;
+}
+
+int32_t nsCaseInsensitiveUTF8StringComparator(const char* lhs, const char* rhs,
+ size_t lLength, size_t rLength) {
+ return CaseInsensitiveCompare(lhs, rhs, lLength, rLength);
+}
+
+int32_t nsASCIICaseInsensitiveStringComparator(const char16_t* lhs,
+ const char16_t* rhs,
+ size_t lLength, size_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, size_t aLen) {
+ for (size_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::intl::UnicodeProperties::ToLower(
+ 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, size_t aLen) {
+ for (size_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::intl::UnicodeProperties::ToUpper(aChar);
+}
+
+void ToUpperCase(const char16_t* aIn, char16_t* aOut, size_t aLen) {
+ for (size_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::intl::UnicodeProperties::ToUpper(
+ 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,
+ size_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::intl::UnicodeProperties::ToLower(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::intl::UnicodeProperties::ToLower(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::intl::UnicodeProperties::ToLower(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,
+ size_t aLeftBytes, size_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, size_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 intl::UnicodeProperties::IsEastAsianWidthFHWexcludingEmoji(u) &&
+ intl::UnicodeProperties::GetScriptCode(u) != intl::Script::HANGUL;
+}
+
+bool IsPunctuationForWordSelect(char16_t aCh) {
+ const uint8_t cat = unicode::GetGeneralCategory(aCh);
+ switch (cat) {
+ case HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: /* Pc */
+ if (aCh == '_' && !StaticPrefs::layout_word_select_stop_at_underscore()) {
+ return false;
+ }
+ [[fallthrough]];
+ case HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: /* Pd */
+ case HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: /* Pe */
+ case HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: /* Pf */
+ case HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: /* Pi */
+ case HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: /* Po */
+ case HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: /* Ps */
+ case HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL: /* Sc */
+ // Deliberately omitted:
+ // case HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL: /* Sk */
+ case HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL: /* Sm */
+ case HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL: /* So */
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace mozilla
diff --git a/intl/unicharutil/util/nsUnicharUtils.h b/intl/unicharutil/util/nsUnicharUtils.h
new file mode 100644
index 0000000000..693e192e41
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicharUtils.h
@@ -0,0 +1,167 @@
+/* -*- 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, size_t aLen);
+void ToLowerCaseASCII(const char16_t* aIn, char16_t* aOut, size_t aLen);
+void ToUpperCase(const char16_t* aIn, char16_t* aOut, size_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, size_t aLen);
+
+uint32_t ToNaked(uint32_t aChar);
+void ToNaked(nsAString& aString);
+
+int32_t nsCaseInsensitiveStringComparator(const char16_t*, const char16_t*,
+ size_t, size_t);
+
+int32_t nsCaseInsensitiveUTF8StringComparator(const char*, const char*, size_t,
+ size_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*,
+ size_t, size_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,
+ size_t len);
+
+int32_t CaseInsensitiveCompare(const char* aLeft, const char* aRight,
+ size_t aLeftBytes, size_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, size_t aLength, bool* aErr);
+
+bool IsSegmentBreakSkipChar(uint32_t u);
+
+/**
+ * Return true for all Punctuation categories (Unicode general category P?),
+ * and also for Symbol categories (S?) except for Modifier Symbol, which is
+ * kept together with any adjacent letter/number. (Bug 1066756)
+ */
+bool IsPunctuationForWordSelect(char16_t aCh);
+
+} // 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..748a2d32c2
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodeProperties.cpp
@@ -0,0 +1,216 @@
+/* -*- 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 "mozilla/intl/Segmenter.h"
+
+#include "BaseChars.h"
+#include "IsCombiningDiacritic.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
+}
+
+bool IsClusterExtenderExcludingJoiners(uint32_t aCh, uint8_t aCategory) {
+ return (
+ (aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
+ aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) ||
+ (aCh >= 0xff9e && aCh <= 0xff9f) || // katakana sound marks
+ (aCh >= 0x1F3FB && aCh <= 0x1F3FF) || // fitzpatrick skin tone modifiers
+ (aCh >= 0xe0020 && aCh <= 0xe007f)); // emoji (flag) tag characters
+}
+
+uint32_t CountGraphemeClusters(Span<const char16_t> aText) {
+ if (aText.IsEmpty()) {
+ // Fast path for empty text.
+ return 0;
+ }
+ intl::GraphemeClusterBreakIteratorUtf16 iter(aText);
+ uint32_t result = 0;
+ while (iter.Next()) {
+ ++result;
+ }
+ return result;
+}
+
+uint32_t GetNaked(uint32_t aCh) {
+ uint32_t index = aCh >> 8;
+ if (index >= MOZ_ARRAY_LENGTH(BASE_CHAR_MAPPING_BLOCK_INDEX)) {
+ return aCh;
+ }
+ index = BASE_CHAR_MAPPING_BLOCK_INDEX[index];
+ if (index == 0xff) {
+ return aCh;
+ }
+ const BaseCharMappingBlock& block = BASE_CHAR_MAPPING_BLOCKS[index];
+ uint8_t lo = aCh & 0xff;
+ if (lo < block.mFirst || lo > block.mLast) {
+ return aCh;
+ }
+ return (aCh & 0xffff0000) |
+ BASE_CHAR_MAPPING_LIST[block.mMappingStartOffset + lo - block.mFirst];
+}
+
+bool IsCombiningDiacritic(uint32_t aCh) {
+ return sCombiningDiacriticsSet->test(aCh);
+}
+
+} // 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..9e71ecec94
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -0,0 +1,203 @@
+/* -*- 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 "mozilla/intl/UnicodeProperties.h"
+
+#include "mozilla/Span.h"
+#include "nsBidiUtils.h"
+#include "nsUGenCategory.h"
+#include "harfbuzz/hb.h"
+
+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;
+};
+
+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[];
+
+// NOTE: This returns values matching harfbuzz HB_UNICODE_GENERAL_CATEGORY_*
+// constants, NOT the mozilla::intl::GeneralCategory enum.
+// For the GeneralCategory enum, use intl::UnicodeProperties::CharType itself.
+inline uint8_t GetGeneralCategory(uint32_t aCh) {
+ return sICUtoHBcategory[unsigned(intl::UnicodeProperties::CharType(aCh))];
+}
+
+inline int8_t GetNumericValue(uint32_t aCh) {
+ return intl::UnicodeProperties::GetNumericValue(aCh);
+}
+
+inline uint8_t GetLineBreakClass(uint32_t aCh) {
+ return intl::UnicodeProperties::GetIntPropertyValue(
+ aCh, intl::UnicodeProperties::IntProperty::LineBreak);
+}
+
+inline uint32_t GetScriptTagForCode(intl::Script aScriptCode) {
+ const char* tag = intl::UnicodeProperties::GetScriptShortName(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(intl::UnicodeProperties::GetIntPropertyValue(
+ aCh, intl::UnicodeProperties::IntProperty::BidiPairedBracketType));
+}
+
+inline uint32_t GetTitlecaseForLower(
+ uint32_t aCh) // maps LC to titlecase, UC unchanged
+{
+ return intl::UnicodeProperties::IsLowercase(aCh)
+ ? intl::UnicodeProperties::ToTitle(aCh)
+ : aCh;
+}
+
+inline uint32_t GetTitlecaseForAll(
+ uint32_t aCh) // maps both UC and LC to titlecase
+{
+ return intl::UnicodeProperties::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 intl::UnicodeProperties::FoldCase(aCh);
+}
+
+inline bool IsDefaultIgnorable(uint32_t aCh) {
+ return intl::UnicodeProperties::HasBinaryProperty(
+ aCh, intl::UnicodeProperties::BinaryProperty::DefaultIgnorableCodePoint);
+}
+
+inline EmojiPresentation GetEmojiPresentation(uint32_t aCh) {
+ if (!intl::UnicodeProperties::HasBinaryProperty(
+ aCh, intl::UnicodeProperties::BinaryProperty::Emoji)) {
+ return TextOnly;
+ }
+
+ if (intl::UnicodeProperties::HasBinaryProperty(
+ aCh, intl::UnicodeProperties::BinaryProperty::EmojiPresentation)) {
+ 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) {
+ // There are no cluster-extender characters before the first combining-
+ // character block at U+03xx, so we short-circuit here to avoid the cost
+ // of calling GetGeneralCategory for Latin-1 letters etc.
+ return aCh >= 0x0300 && IsClusterExtender(aCh, GetGeneralCategory(aCh));
+}
+
+bool IsClusterExtenderExcludingJoiners(uint32_t aCh, uint8_t aCategory);
+
+inline bool IsClusterExtenderExcludingJoiners(uint32_t aCh) {
+ return aCh >= 0x0300 &&
+ IsClusterExtenderExcludingJoiners(aCh, GetGeneralCategory(aCh));
+}
+
+// Count the number of grapheme clusters in the given string
+uint32_t CountGraphemeClusters(Span<const char16_t> aText);
+
+// 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).
+// See is_combining_diacritic in base_chars.py and is_combining_diacritic.py.
+//
+// TODO: once ICU4X is integrated (replacing ICU4C) as the source of Unicode
+// properties, re-evaluate whether building the static bitset is worthwhile
+// or if we can revert to simply getting the combining class and comparing
+// to the values we care about at runtime.
+bool IsCombiningDiacritic(uint32_t aCh);
+
+// Remove diacritics from a character
+uint32_t GetNaked(uint32_t aCh);
+
+} // 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..eb2dc8a7e4
--- /dev/null
+++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp
@@ -0,0 +1,208 @@
+/* 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 Tue Oct 25 06:53:25 2022 from UCD data files with version info:
+ *
+
+# Unicode Character Database
+# Date: 2022-09-02
+# © 2022 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/Unicode15.0.0/
+
+This directory contains the final data files
+for the Unicode Character Database, for Version 15.0.0 of the Unicode Standard.
+
+# IdentifierStatus.txt
+# Date: 2022-08-26, 16:49:09 GMT
+
+#
+# Unihan_Variants.txt
+# Date: 2022-08-01 16:36:07 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,40,40,41,40,42,40,40,40,40,40,40,40,43,40,40,44,45,46,47,48,49,50,51,52,40,53,54,55,34,40,56,57,34,58,59,40,40,40,40,40,40,60,61,40,40,62,63,40,34,34,34,64,65,66,67,34,34,68,34,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,70,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,34,34,34,34,34,34,34,34,34,71,40,40,72,40,73,74,40,40,75,76,77,40,78,40,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,79,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,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,40,40,40,40,40,40,81,40,82,83},
+ {40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,84,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,85,40,40,40,40,34,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,34,34,34,34,34,34,86,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,34,34,34,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,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,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,88,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,34,34,40,40,34,40,40,40,40,40,40,40,40,40,34,34,34,34,34,86,40,40,40,40,40,40,40,40,89,40,40,90,40,40,40,40,40,40,40,40,40,40,40,40,40,91,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,34,34,34,34,92,34,34,34,34,34,34,34,34,34,34,34,40,40,34,34,40,40,40,40,40,40,40,40,40,40,40,40},
+ {69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,93,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,94,69,95,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,96,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,97,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,98},
+ {69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,99,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,100,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,98},
+ {40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40},
+ {34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,98}
+};
+
+static const nsCharProps2 sCharProp2Values[101][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,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,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,0},{1,0},{1,0},{1,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,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,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,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,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,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,1},{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,1},{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,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,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,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,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,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,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,1},{1,1},{1,1},{1,0},{1,0},{1,1},{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,0},{1,0},{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,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{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,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,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,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,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{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,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,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,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,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,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,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,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,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,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}},
+ {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,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,0},{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,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{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,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,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,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
+ {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,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}}
+};
+#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! * * * * *
+ */