Merge commit '3a74ee528255cc027d84b204a87b5c25e47bff79'

Merged from upstream:
    https://github.com/harfbuzz/harfbuzz.git refs/tags/2.6.4

Also update `Android.bp`.

NO_TYPO_CHECK=true

Change-Id: I606b1dc9a4994b2fb110a66309a57b00ec85da09
diff --git a/.ci/build-freetype.sh b/.ci/build-freetype.sh
new file mode 100644
index 0000000..0f09f92
--- /dev/null
+++ b/.ci/build-freetype.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -x
+set -o errexit -o nounset
+
+# 22.0.16 is the libtool version of 2.9.0
+if pkg-config --atleast-version 22.0.16 freetype2; then exit; fi
+
+pushd $HOME
+wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2
+tar xf freetype-2.9.tar.bz2
+pushd freetype-2.9
+./autogen.sh
+./configure --prefix=$HOME/.local
+make -j4 install
+popd
+popd
diff --git a/.circleci/config.yml b/.circleci/config.yml
index e6a5a1d..2975ea8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -4,10 +4,10 @@
 
   macos-10.12.6-aat-fonts:
     macos:
-      xcode: "9.2.0"
+      xcode: "9.0.1"
     steps:
       - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
+      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
       - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
       - run: make -j4
       - run: make check || .ci/fail.sh
@@ -17,49 +17,25 @@
       xcode: "10.1.0"
     steps:
       - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
+      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
       - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
       - run: make -j4
       - run: make check || .ci/fail.sh
 
-  macos-llvm-gcc-4.2:
+  macos-10.14.4-aat-fonts:
     macos:
-      xcode: "8.3.3"
+      xcode: "11.0.0"
     steps:
       - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
-      - run: wget https://packages.macports.org/llvm-gcc42/llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2
-      - run: CC=$PWD/opt/local/bin/llvm-gcc-4.2 CXX=$PWD/opt/local/bin/llvm-g++-4.2 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
-      # Ignoring assembler complains, https://stackoverflow.com/a/39867021
-      - run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
+      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 cmake
+      - run: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2
+      - run: make -j4
       - run: make check || .ci/fail.sh
-
-  macos-notest-apple-gcc-i686-4.2:
-    macos:
-      xcode: "8.3.3"
-    steps:
-      - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel
-      - run: wget https://packages.macports.org/apple-gcc42/apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2
-      - run: CPP=$PWD/opt/local/bin/i686-apple-darwin15-cpp-apple-4.2.1 CC=$PWD/opt/local/bin/i686-apple-darwin15-gcc-apple-4.2.1 CXX=$PWD/opt/local/bin/i686-apple-darwin15-g++-apple-4.2.1 ./autogen.sh
-      # Ignoring assembler complains, https://stackoverflow.com/a/39867021
-      - run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
-
-  macos-notest-ios:
-    macos:
-      xcode: "10.0.0"
-    steps:
-      - checkout
-      - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake
-      # not needed to be a framework but we like to test that also
-      # TODO: wrong way of targeting iOS as it doesn't point to iOS headers thus building
-      # CoreText support is not possible, after the fix feel free HB_IOS from CMake altogether
-      - run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_HAVE_CORETEXT=OFF -DHB_BUILD_SUBSET=OFF -DHB_BUILD_TESTS=OFF
-      - run: cd build && xcodebuild -sdk iphoneos12.0 -configuration Release build -arch arm64
+      - run: cmake -Bbuild -H. -DHB_HAVE_CORETEXT=1 -DHB_BUILD_TESTS=0 && cmake --build build
 
   distcheck:
     docker:
-      - image: ubuntu:17.10
+      - image: ubuntu:19.04
     steps:
       - checkout
       - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
@@ -70,36 +46,50 @@
       - run: rm -rf harfbuzz-*
       - run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
 
-  alpine-O3-NOMMAP:
+  alpine-O3-Os-NOMMAP:
     docker:
       - image: alpine
     steps:
       - checkout
-      - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
+      - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev python
       # C??FLAGS are not needed for a regular build
       - run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
       - run: make -j32
       - run: make check || .ci/fail.sh
-
-  archlinux-debug-O0-py3:
-    docker:
-      - image: base/devel
-    steps:
-      - checkout
-      - run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip
-      - run: pip install fonttools
-      # C??FLAGS are not needed for a regular build
-      - run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
+      - run: make clean
+      - run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
       - run: make -j32
       - run: make check || .ci/fail.sh
 
-  clang-O3-O0:
+  archlinux-py3-all:
     docker:
-      - image: multiarch/crossbuild
+      - image: archlinux/base
+    steps:
+      - checkout
+      - run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip make which base-devel
+      - run: pip install flake8 fonttools
+      - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
+      # C??FLAGS are not needed for a regular build
+      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
+      - run: make -j32 CPPFLAGS="-Werror"
+      - run: make check CPPFLAGS="-Werror" || .ci/fail.sh
+
+  ## Doesn't play well with CircleCI apparently
+  #void-notest:
+  #  docker:
+  #    - image: voidlinux/voidlinux
+  #  steps:
+  #    - checkout
+  #    - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make
+  #    - run: ./autogen.sh && make -j32 && make check
+
+  clang-O3-O0-and-nobuildsystem:
+    docker:
+      - image: ubuntu:18.10
     steps:
       - checkout
       - run: apt update || true
-      - run: apt install -y ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+      - run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
       - run: pip install fonttools
       - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd ..
       - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
@@ -108,6 +98,9 @@
       - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
       - run: make -j32
       - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
+      - run: make clean
+      - run: make -Csrc CPPFLAGS="-DHB_TINY -DHB_NO_OT_FONT" libharfbuzz-subset.la && make clean
+      - run: clang -c src/hb-*.cc -DHB_NO_MT
 
   gcc-valgrind:
     docker:
@@ -121,7 +114,7 @@
       - run: make -j32
       # run-shape-fuzzer-tests.py automatically runs valgrind if see available
       # but test/api runs it by request, we probably should normalize the approaches
-      - run: RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
+      - run: HB_TEST_SHAPE_FUZZER_TIMEOUT=3 HB_TEST_SUBSET_FUZZER_TIMEOUT=30 RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
       # informational for now
       - run: make -Ctest/api check-symbols || true
 
@@ -137,7 +130,7 @@
       - run: apt update || true
       - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
       - run: pip install fonttools
-      - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
+      - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command -DHB_WITH_WIN1256" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template -DHB_WITH_WIN1256" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
       - run: make -j32 CPPFLAGS="-Werror"
       - run: make check CPPFLAGS="-Werror" || .ci/fail.sh
 
@@ -173,7 +166,7 @@
       - run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
       - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
       - run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu
-      - run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt
+      - run: make -j32 && MSAN_OPTIONS=exitcode=42 HB_TEST_SUBSET_FUZZER_TIMEOUT=12 make check || .ci/fail.sh | asan_symbolize | c++filt
 
   clang-tsan:
     docker:
@@ -189,7 +182,7 @@
       - run: pip install fonttools
       - run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
       - run: make -j32
-      - run: make check || .ci/fail.sh | asan_symbolize | c++filt
+      - run: HB_TEST_SUBSET_FUZZER_TIMEOUT=40 make check || .ci/fail.sh | asan_symbolize | c++filt
 
   clang-ubsan:
     docker:
@@ -203,22 +196,31 @@
       - run: apt update || true
       - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
       - run: pip install fonttools
-      - run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
+      - run: CPPFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined" LDFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
       - run: make -j32
-      - run: make check || .ci/fail.sh | asan_symbolize | c++filt
+      - run: UBSAN_OPTIONS=print_stacktrace=1 make check || .ci/fail.sh | asan_symbolize | c++filt
 
-  fedora-outoftreebuild:
+  fedora-O0-debug-outoftreebuild-mingw:
     docker:
       - image: fedora
     steps:
       - checkout
-      - run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python || true
-      - run: NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
-      - run: mkdir build && cd build && ../configure && make && (make check || ../.ci/fail.sh)
+      - run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
+      - run: NOCONFIGURE=1 ./autogen.sh
+      - run: mkdir build && cd build && CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ../configure --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && make -j32 && (make check || ../.ci/fail.sh)
+      - run: pip install pefile
+      - run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip
+      - run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip
+      - store_artifacts:
+          path: winbuild32/harfbuzz-win32.zip
+          destination: harfbuzz-win32.zip
+      - store_artifacts:
+          path: winbuild64/harfbuzz-win64.zip
+          destination: harfbuzz-win64.zip
 
   cmake-gcc:
     docker:
-      - image: ubuntu:17.10
+      - image: ubuntu:19.04
     steps:
       - checkout
       - run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
@@ -228,17 +230,17 @@
       - run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
       - run: ninja -Cbuild install
 
-  cmake-oracledeveloperstudio:
-    docker:
-      - image: fedora
-    steps:
-      - checkout
-      - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
-      - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
-      - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
-      - run: make -Cbuild -j32
-      - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
-      - run: make -Cbuild install
+  #cmake-oracledeveloperstudio:
+  #  docker:
+  #    - image: fedora
+  #  steps:
+  #    - checkout
+  #    - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
+  #    - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
+  #    - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
+  #    - run: make -Cbuild -j32
+  #    - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
+  #    - run: make -Cbuild install
 
   crosscompile-notest-djgpp:
     docker:
@@ -250,22 +252,13 @@
       - run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
       - run: make -j32
 
-  crosscompile-notest-freebsd9:
-    docker:
-      - image: donbowman/freebsd-cross-build
-    steps:
-      - checkout
-      - run: apt update && apt install -y pkg-config ragel
-      - run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9
-      - run: make -j32
-
   crosscompile-notest-psvita:
     docker:
       - image: dockcross/base
     steps:
       - checkout
-      - run: apt update && apt install ragel
       - run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
+      - run: echo '#!/bin/true' > /usr/bin/ragel && chmod +x /usr/bin/ragel
       - run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
       - run: make -j32
 
@@ -274,17 +267,15 @@
       - image: dockcross/android-arm
     steps:
       - checkout
-      - run: apt update && apt install ragel
-      - run: cmake -Bbuild -H. -GNinja
+      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
       - run: ninja -Cbuild
 
-  crosscompile-cmake-notest-browser-asmjs:
+  crosscompile-cmake-notest-browser-asmjs-hb_tiny:
     docker:
       - image: dockcross/browser-asmjs
     steps:
       - checkout
-      - run: apt update && apt install ragel
-      - run: cmake -Bbuild -H. -GNinja
+      - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF
       - run: ninja -Cbuild
 
   crosscompile-cmake-notest-linux-arm64:
@@ -292,8 +283,7 @@
       - image: dockcross/linux-arm64
     steps:
       - checkout
-      - run: apt update && apt install ragel
-      - run: cmake -Bbuild -H. -GNinja
+      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
       - run: ninja -Cbuild
 
   crosscompile-cmake-notest-linux-mips:
@@ -301,8 +291,7 @@
       - image: dockcross/linux-mips
     steps:
       - checkout
-      - run: apt update && apt install ragel
-      - run: cmake -Bbuild -H. -GNinja
+      - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
       - run: ninja -Cbuild
 
   #crosscompile-cmake-notest-windows-x64:
@@ -310,7 +299,6 @@
   #    - image: dockcross/windows-x64
   #  steps:
   #    - checkout
-  #    - run: apt update && apt install ragel
   #    - run: cmake -Bbuild -H. -GNinja
   #    - run: ninja -Cbuild
 
@@ -321,39 +309,37 @@
       # macOS
       - macos-10.12.6-aat-fonts
       - macos-10.13.6-aat-fonts
-      - macos-llvm-gcc-4.2
-      - macos-notest-apple-gcc-i686-4.2
-      - macos-notest-ios
+      - macos-10.14.4-aat-fonts
 
       # both autotools and cmake
       - distcheck
 
       # autotools based builds
-      - alpine-O3-NOMMAP
-      - archlinux-debug-O0-py3
+      - alpine-O3-Os-NOMMAP
+      - archlinux-py3-all
+      #- void-notest
       - gcc-valgrind
-      - clang-O3-O0
+      - clang-O3-O0-and-nobuildsystem
       - clang-everything
       - clang-asan
       - clang-msan
       - clang-tsan
       - clang-ubsan
-      - fedora-outoftreebuild
+      - fedora-O0-debug-outoftreebuild-mingw
 
       # cmake based builds
       - cmake-gcc
-      - cmake-oracledeveloperstudio
+      #- cmake-oracledeveloperstudio
 
       # crosscompiles
       # they can't be test thus are without tests
       ## autotools
       - crosscompile-notest-djgpp
-      - crosscompile-notest-freebsd9
       - crosscompile-notest-psvita
 
       ## cmake
       - crosscompile-cmake-notest-android-arm
-      - crosscompile-cmake-notest-browser-asmjs
+      - crosscompile-cmake-notest-browser-asmjs-hb_tiny
       - crosscompile-cmake-notest-linux-arm64
       - crosscompile-cmake-notest-linux-mips
       #- crosscompile-cmake-notest-windows-x64
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..259427c
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,38 @@
+# The following tries to match the current code style, is imperfect for now
+# but good for new codes be added
+
+IndentWidth: 2
+TabWidth: 8
+UseTab: Always
+SpaceBeforeParens: Always
+AllowShortLoopsOnASingleLine: true
+BreakBeforeBraces: Custom
+BraceWrapping:
+  AfterEnum: true
+  AfterStruct: false
+  SplitEmptyFunction: false
+  AfterClass: true
+  AfterControlStatement: true
+  AfterEnum: false
+  AfterFunction: true
+  AfterNamespace: false
+  AfterStruct: true
+  AfterUnion: true
+  BeforeElse: true
+AlwaysBreakTemplateDeclarations: true
+AlignTrailingComments: true
+AlignEscapedNewlines: Left
+AllowShortBlocksOnASingleLine: true
+SpaceAfterCStyleCast: true
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+BinPackParameters: false
+AllowShortFunctionsOnASingleLine: Inline
+AccessModifierOffset: 0
+AlignTrailingComments: true
+AllowShortIfStatementsOnASingleLine: true
+AlignAfterOpenBracket: Align
+AlignOperands: true
+AllowShortCaseLabelsOnASingleLine: true
+
+# We like to have this only for function parameters and structs fields, not always
+# AlignConsecutiveDeclarations: true
diff --git a/.editorconfig b/.editorconfig
index bd981d1..4291676 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,10 +6,10 @@
 end_of_line = lf
 insert_final_newline = true
 
-[*.{c,cc,h,hh}]
-indent_size = 2
-indent_style = space
+[*.{c,cc,h,hh,rl}]
 tab_width = 8
+indent_size = 2
+indent_style = tab # should be space
 
 [*.{py,sh}]
 indent_style = tab
diff --git a/.travis.yml b/.travis.yml
index 3e77b26..703fac2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,8 +6,6 @@
 env:
   global:
     - CPPFLAGS=""
-    - CFLAGS="-Werror -Werror=unused -Werror=unused-function"
-    - CXXFLAGS="-Werror -Werror=unused -Werror=unused-function -Wno-deprecated-register" # glib uses register and clang raises a warning
     - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
     - NOCONFIGURE=1
     # COVERITY_SCAN_TOKEN
@@ -18,9 +16,10 @@
     - os: linux
       compiler: gcc
       script:
-        # Remove these two lines when Travis updated its distro
-        - wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
-        - export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
+        # Remove the following three lines when Travis updates its distro
+        - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
+        - export LD_LIBRARY_PATH="$HOME/.local/lib"
+        - bash .ci/build-freetype.sh
 
         - ./autogen.sh
         - ./configure $CONFIGURE_OPTS --enable-gtk-doc --enable-code-coverage
@@ -36,35 +35,24 @@
     - os: linux
       compiler: clang
       script:
-        # Remove these two lines when Travis updated its distro
-        - wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
-        - export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
+        # Remove the following three lines when Travis updates its distro
+        - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
+        - export LD_LIBRARY_PATH="$HOME/.local/lib"
+        - bash .ci/build-freetype.sh
 
         - ./autogen.sh
         - ./configure $CONFIGURE_OPTS
         - make
         - make check || .ci/fail.sh
 
-    - os: osx
-      compiler: clang
-      install:
-        - brew update;
-          # Workaround Travis/brew bug
-        - brew uninstall libtool && brew install libtool
-        - brew install ragel freetype glib gobject-introspection cairo graphite2 || true
-        - brew upgrade icu4c || true
-        - export PATH="/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:$PATH"
-        - export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"
-      script:
-        - ./autogen.sh
-        - ./configure $CONFIGURE_OPTS --with-coretext
-        - make
-        - make check || .ci/fail.sh
-
 notifications:
   irc: "irc.freenode.org#harfbuzz"
   email: harfbuzz-bots-chatter@googlegroups.com
 
+cache:
+  directories:
+    - /home/travis/.local
+
 addons:
   apt:
     packages:
diff --git a/AUTHORS b/AUTHORS
index 0763761..83c0c66 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,11 +1,14 @@
 Behdad Esfahbod
+David Corbett
 David Turner
 Ebrahim Byagowi
+Garret Rieger
 Jonathan Kew
 Khaled Hosny
 Lars Knoll
 Martin Hosken
 Owen Taylor
+Roderick Sheeter
 Roozbeh Pournader
 Simon Hausmann
 Werner Lemberg
diff --git a/Android.bp b/Android.bp
index 95d9b70..9f29062 100644
--- a/Android.bp
+++ b/Android.bp
@@ -67,8 +67,10 @@
         "src/hb-buffer.cc",
         "src/hb-common.cc",
         "src/hb-face.cc",
+        "src/hb-fallback-shape.cc",
         "src/hb-font.cc",
         "src/hb-icu.cc",
+        "src/hb-number.cc",
         "src/hb-ot-cff1-table.cc",
         "src/hb-ot-cff2-table.cc",
         "src/hb-ot-face.cc",
@@ -76,6 +78,7 @@
         "src/hb-ot-layout.cc",
         "src/hb-ot-map.cc",
         "src/hb-ot-math.cc",
+        "src/hb-ot-metrics.cc",
         "src/hb-ot-shape-complex-arabic.cc",
         "src/hb-ot-shape-complex-default.cc",
         "src/hb-ot-shape-complex-hangul.cc",
@@ -98,8 +101,8 @@
         "src/hb-shape.cc",
         "src/hb-shaper.cc",
         "src/hb-static.cc",
+        "src/hb-ucd.cc",
         "src/hb-unicode.cc",
-        "src/hb-warning.cc",
     ],
 
     target: {
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6241e9..2a8fd8b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,6 @@
 ## HarfBuzz build configurations
 option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
 option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
-option(HB_BUILTIN_UCDN "Use HarfBuzz provided UCDN" ON)
 option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
 option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
 if (APPLE)
@@ -44,6 +43,7 @@
 endif ()
 if (WIN32)
   option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF)
+  option(HB_HAVE_GDI "Enable GDI integration helpers on Windows" OFF)
   option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF)
 endif ()
 option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF)
@@ -70,7 +70,6 @@
 if (HB_CHECK)
   set (BUILD_SHARED_LIBS ON)
   set (HB_BUILD_UTILS ON)
-  set (HB_BUILTIN_UCDN ON)
   set (HB_HAVE_ICU)
   set (HB_HAVE_GLIB ON)
   #set (HB_HAVE_GOBJECT ON)
@@ -79,6 +78,7 @@
   set (HB_HAVE_GRAPHITE2 ON)
   if (WIN32)
     set (HB_HAVE_UNISCRIBE ON)
+    set (HB_HAVE_GDI ON)
     set (HB_HAVE_DIRECTWRITE ON)
   elseif (APPLE)
     set (HB_HAVE_CORETEXT ON)
@@ -90,8 +90,6 @@
   ${PROJECT_BINARY_DIR}/src
 )
 
-add_definitions(-DHAVE_FALLBACK)
-
 # We need PYTHON_EXECUTABLE to be set for running the tests...
 include (FindPythonInterp)
 
@@ -110,7 +108,7 @@
 if (UNIX)
   list(APPEND CMAKE_REQUIRED_LIBRARIES m)
 endif ()
-check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l round)
+check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
 check_include_file(unistd.h HAVE_UNISTD_H)
 if (${HAVE_UNISTD_H})
   add_definitions(-DHAVE_UNISTD_H)
@@ -144,8 +142,8 @@
 
 ## Extract variables from Makefile files
 function (extract_make_variable variable makefile_source)
-  string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${makefile_source})
-  string(REGEX MATCHALL "[^ \n\t\\]+" listVar ${CMAKE_MATCH_1})
+  string(REGEX MATCH "${variable} = ([^$]+)\\$" temp "${makefile_source}")
+  string(REGEX MATCHALL "[^ \n\t\\]+" listVar "${CMAKE_MATCH_1}")
   set (${variable} ${listVar} PARENT_SCOPE)
 endfunction ()
 
@@ -160,14 +158,9 @@
 
 file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES)
 file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES)
-file(READ ${PROJECT_SOURCE_DIR}/src/hb-ucdn/Makefile.sources UCDNSOURCES)
 
-extract_make_variable(HB_BASE_sources ${SRCSOURCES})
-add_prefix_to_list(HB_BASE_sources "${PROJECT_SOURCE_DIR}/src/")
 extract_make_variable(HB_BASE_headers ${SRCSOURCES})
 add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/")
-extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES})
-add_prefix_to_list(HB_FALLBACK_sources "${PROJECT_SOURCE_DIR}/src/")
 
 extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
 add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
@@ -191,9 +184,6 @@
 extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
 add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
 
-extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES})
-add_prefix_to_list(LIBHB_UCDN_sources "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
-
 
 file(READ configure.ac CONFIGUREAC)
 string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
@@ -202,61 +192,12 @@
 set (HB_VERSION_MINOR ${CMAKE_MATCH_3})
 set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
 
-
-## Define ragel tasks
-# if (NOT IN_HB_DIST)
-#  foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources})
-#    string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
-#    set (target_name ${CMAKE_MATCH_1})
-#    add_custom_command(OUTPUT ${ragel_output}
-#      COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
-#      DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
-#    )
-#    add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
-#  endforeach ()
-
-#  mark_as_advanced(RAGEL)
-# endif ()
-
-
-## Generate hb-version.h
-# if (NOT IN_HB_DIST)
-#  set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
-#  set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
-#  set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
-#  configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
-#  execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
-#    "${HB_VERSION_H}.tmp"
-#    "${HB_VERSION_H}"
-#  )
-#  file(REMOVE "${HB_VERSION_H}.tmp")
-# endif ()
-
-
 ## Define sources and headers of the project
-set (project_sources
-  ${HB_BASE_sources}
-  ${HB_BASE_RAGEL_GENERATED_sources}
-
-  ${HB_FALLBACK_sources}
-)
-
-set (subset_project_sources
-  ${HB_SUBSET_sources}
-)
-
+set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source
+set (subset_project_sources ${HB_SUBSET_sources})
 set (project_extra_sources)
-
-set (project_headers
-  #${HB_VERSION_H}
-
-  ${HB_BASE_headers}
-)
-
-set (subset_project_headers
-  ${HB_SUBSET_headers}
-)
-
+set (project_headers ${HB_BASE_headers})
+set (subset_project_headers ${HB_SUBSET_headers})
 
 ## Find and include needed header folders and libraries
 if (HB_HAVE_FREETYPE)
@@ -269,7 +210,6 @@
   include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
   add_definitions(-DHAVE_FREETYPE=1)
 
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
 
   # So check_funcs can find its headers
@@ -287,7 +227,6 @@
 
   include_directories(${GRAPHITE2_INCLUDE_DIR})
 
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h)
 
   list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
@@ -295,14 +234,6 @@
   mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
 endif ()
 
-if (HB_BUILTIN_UCDN)
-  include_directories(src/hb-ucdn)
-  add_definitions(-DHAVE_UCDN)
-
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ucdn.cc)
-  list(APPEND project_extra_sources ${LIBHB_UCDN_sources})
-endif ()
-
 if (HB_HAVE_GLIB)
   add_definitions(-DHAVE_GLIB)
 
@@ -316,7 +247,6 @@
 
   include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR})
 
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h)
 
   list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
@@ -336,7 +266,6 @@
 
   include_directories(${ICU_INCLUDE_DIR})
 
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
 
   list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY})
@@ -348,7 +277,6 @@
   # Apple Advanced Typography
   add_definitions(-DHAVE_CORETEXT)
 
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
 
   if (HB_IOS)
@@ -379,21 +307,21 @@
   endif ()
 endif ()
 
+if (WIN32 AND HB_HAVE_GDI)
+  add_definitions(-DHAVE_GDI)
+  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
+  list(APPEND THIRD_PARTY_LIBS gdi32)
+endif ()
+
 if (WIN32 AND HB_HAVE_UNISCRIBE)
   add_definitions(-DHAVE_UNISCRIBE)
-
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
-
   list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
 endif ()
 
 if (WIN32 AND HB_HAVE_DIRECTWRITE)
   add_definitions(-DHAVE_DIRECTWRITE)
-
-  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc)
   list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
-
   list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
 endif ()
 
@@ -501,7 +429,6 @@
   )
 endif ()
 
-
 ## Atomic ops availability detection
 file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
 "		void memory_barrier (void) { __sync_synchronize (); }
@@ -552,7 +479,7 @@
 if (UNIX OR MINGW)
   # Make symbols link locally
   include (CheckCXXCompilerFlag)
-  check_cxx_compiler_flag(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
+  CHECK_CXX_COMPILER_FLAG(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
   if (CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
     link_libraries(-Bsymbolic-functions)
   endif ()
@@ -570,8 +497,16 @@
     # No threadsafe statics as we do it ourselves
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
   endif ()
+
+  CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+  if (COMPILER_SUPPORTS_CXX11)
+    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+  else()
+    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
+  endif()
 endif ()
 
+
 ## Define harfbuzz-gobject library
 if (HB_HAVE_GOBJECT)
   add_library(harfbuzz-gobject
@@ -602,7 +537,6 @@
 endif ()
 
 if (HB_HAVE_INTROSPECTION)
-
   find_package(PkgConfig)
   pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
 
@@ -834,21 +768,9 @@
   endif ()
 endif ()
 
-if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
-  if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
-    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
-  endif ()
-  if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
-    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color")
-  endif ()
-endif ()
-
-
 if (HB_BUILD_TESTS)
   ## src/ executables
-  foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
+  foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize test-unicode-ranges) # hb-ot-tag
     set (prog_name ${prog})
     if (${prog_name} STREQUAL "test")
       # test can not be used as a valid executable name on cmake, lets special case it
@@ -857,7 +779,7 @@
     add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
     target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
   endforeach ()
-  set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
+  # set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
 
   ## Tests
   if (UNIX OR MINGW)
diff --git a/CONFIG.md b/CONFIG.md
new file mode 100644
index 0000000..46971b0
--- /dev/null
+++ b/CONFIG.md
@@ -0,0 +1,151 @@
+# Configuring HarfBuzz
+
+Most of the time you will not need any custom configuration.  The configuration
+options provided by `configure` or `cmake` should be enough.  In particular,
+if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure
+FreeType and Cairo are available and found during configuration.
+
+If you are building for distribution, you should more carefully consider whether
+you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite.  Make
+sure the relevant ones are enabled.
+
+If you are building for custom environment (embedded, downloadable app, etc)
+where you mostly just want to call `hb_shape()` and the binary size of the
+resulting library is very important to you, the rest of this file guides you
+through your options to disable features you may not need, in exchange for
+binary size savings.
+
+## Compiler Options
+
+Make sure you build with your compiler's "optimize for size" option.  On `gcc`
+this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os` either to `configure`
+(sticky) or to `make` (non-sticky).  On clang there is an even more extreme flag,
+`-Oz`.
+
+HarfBuzz heavily uses inline functions and the optimize-size flag can make the
+library smaller by 20% or more.  Moreover, sometimes, based on the target CPU,
+the optimize-size builds perform *faster* as well, thanks to lower code
+footprint and caching effects.  So, definitely try that even if size is not
+extremely tight but you have a huge application.  For example, Chrome does
+that.  Note that this configuration also automatically enables certain internal
+optimizations.  Search for `HB_OPTIMIZE_SIZE` for details, if you are using
+other compilers, or continue reading.
+
+Another compiler option to consider is "link-time optimization", also known as
+'lto'.  To enable that, with `gcc` or `clang`, add `-flto` to both `CXXFLAGS`
+and `LDFLAGS`, either on `configure` invocation (sticky) or on `make` (non-sticky).
+This, also, can have a huge impact on the final size, 20% or more.
+
+Finally, if you are making a static library build or otherwise linking the
+library into your app, make sure your linker removes unused functions.  This
+can be tricky and differ from environment to environment, but you definitely
+want to make sure this happens.  Otherwise, every unused public function will
+be adding unneeded bytes to your binary.  The following pointers might come
+handy:
+
+ * https://lwn.net/Articles/741494/ (all of the four-part series)
+ * https://elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
+
+Combining the above three build options should already shrink your library a lot.
+The rest of this file shows you ways to shrink the library even further at the
+expense of removing functionality (that may not be needed).  The remaining
+options are all enabled by defining pre-processor macros, which can be done
+via `CXXFLAGS` or `CPPFLAGS` similarly.
+
+
+## Unicode-functions
+
+Access to Unicode data can be configured at compile time as well as run-time.
+By default, HarfBuzz ships with its own compact subset of properties from
+Unicode Character Database that it needs.  This is a highly-optimized
+implementation that depending on compile settings (optimize-size or not)
+takes around ~40kb or ~60kb.  Using this implementation (default) is highly
+recommended, as HarfBuzz always ships with data from latest version of Unicode.
+This implementation can be disabled by defining `HB_NO_UCD`.
+
+For example, if you are enabling ICU as a built-in option, or GLib, those
+can provide Unicode data as well, so defining `HB_NO_UCD` might save you
+space without reducing functionality (to the extent that the Unicode version
+of those implementations is recent.)
+
+If, however, you provide your own Unicode data to HarfBuzz at run-time by
+calling `hb_buffer_set_unicode_funcs` on every buffer you create, and you do
+not rely on `hb_unicode_funcs_get_default()` results, you can disable the
+internal implementation by defining both `HB_NO_UCD` and `HB_NO_UNICODE_FUNCS`.
+The latter is needed to guard against accidentally building a library without
+any default Unicode implementations.
+
+
+## Font-functions
+
+Access to certain font functionalities can also be configured at run-time.  By
+default, HarfBuzz uses an efficient internal implementation of OpenType
+functionality for this.  This internal implementation is called `hb-ot-font`.
+All newly-created `hb_font_t` objects by default use `hb-ot-font`.  Using this
+is highly recommended, and is what fonts use by default when they are created.
+
+Most embedded uses will probably use HarfBuzz with FreeType using `hb-ft.h`.
+In that case, or if you otherwise provide those functions by calling
+`hb_font_set_funcs()` on every font you create, you can disable `hb-ot-font`
+without loss of functionality by defining `HB_NO_OT_FONT`.
+
+
+## Shapers
+
+Most HarfBuzz clients use it for the main shaper, called "ot".  However, it
+is legitimate to want to compile HarfBuzz with only another backend, eg.
+CoreText, for example for an iOS app.  For that, you want `HB_NO_OT_SHAPE`.
+If you are going down that route, check if you want `HB_NO_OT`.
+
+This is very rarely what you need.  Make sure you understand exactly what you
+are doing.
+
+Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless.  That removes the
+(unused) "fallback" shaper.
+
+
+## Thread-safety
+
+By default HarfBuzz builds as a thread-safe library.  The exception is that
+the `HB_TINY` predefined configuring (more below) disables thread-safety.
+
+If you do /not/ need thread-safety in the library (eg. you always call into
+HarfBuzz from the same thread), you can disable thread-safety by defining
+`HB_NO_MT`.  As noted already, this is enabled by `HB_TINY`.
+
+
+## Pre-defined configurations
+
+The [`hb-config.hh`](src/hb-config.hh) internal header supports three
+pre-defined configurations as well grouping of various configuration options.
+The pre-defined configurations are:
+
+  * `HB_MINI`: Disables shaping of AAT as well as legacy fonts.  Ie. it produces
+    a capable OpenType shaper only.
+
+  * `HB_LEAN`: Disables various non-shaping functionality in the library, as well
+    as esoteric or rarely-used shaping features.  See the definition for details.
+
+  * `HB_TINY`: Enables both `HB_MINI` and `HB_LEAN` configurations, as well as
+    disabling thread-safety and debugging, and use even more size-optimized data
+    tables.
+
+
+## Tailoring configuration
+
+Most of the time, one of the pre-defined configuration is exactly what one needs.
+Sometimes, however, the pre-defined configuration cuts out features that might
+be desired in the library.  Unfortunately there is no quick way to undo those
+configurations from the command-line.  But one can add a header file called
+`config-override.h` to undefine certain `HB_NO_*` symbols as desired.  Then
+define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
+overrides at the end.
+
+
+## Notes
+
+Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
+`HB_TINY` does /not/ mean that the resulting library won't work with CFF fonts.
+The library can shape valid CFF fonts just fine, with or without this option.
+This option disables (among other things) the code to calculate glyph exntents
+for CFF fonts.
diff --git a/COPYING b/COPYING
index 9d1056f..0278e60 100644
--- a/COPYING
+++ b/COPYING
@@ -2,7 +2,8 @@
 For parts of HarfBuzz that are licensed under different licenses see individual
 files names COPYING in subdirectories where applicable.
 
-Copyright © 2010,2011,2012  Google, Inc.
+Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019  Google, Inc.
+Copyright © 2019  Facebook, Inc.
 Copyright © 2012  Mozilla Foundation
 Copyright © 2011  Codethink Limited
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
diff --git a/Makefile.am b/Makefile.am
index eb46cea..2bbd3c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,12 +9,19 @@
 EXTRA_DIST = \
 	autogen.sh \
 	harfbuzz.doap \
+	README.md \
+	README.mingw.md \
 	README.python.md \
-	README.wine.md \
 	BUILD.md \
+	CONFIG.md \
 	RELEASING.md \
+	TESTING.md \
 	CMakeLists.txt \
 	replace-enum-strings.cmake \
+	mingw-configure.sh \
+	mingw-ldd.py \
+	mingw32.sh \
+	mingw64.sh \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
@@ -36,7 +43,7 @@
 $(srcdir)/ChangeLog:
 	$(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \
 	  (GIT_DIR=$(top_srcdir)/.git \
-	   $(GIT) log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
+	   $(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \
 	  && mv -f $@.tmp "$(srcdir)/ChangeLog" \
 	  || ($(RM) $@.tmp; \
 	      echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
@@ -60,8 +67,6 @@
 	--enable-introspection \
 	$(NULL)
 
-# TODO: Copy infrastructure from cairo
-
 # TAR_OPTIONS is not set as env var for 'make dist'.  How to fix that?
 TAR_OPTIONS = --owner=0 --group=0
 
@@ -70,8 +75,7 @@
 dist-clear-sticky-bits:
 	chmod -R a-s $(distdir)
 
-
-tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.bz2
+tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.xz
 sha256_file = $(tar_file).sha256
 gpg_file = $(sha256_file).asc
 $(sha256_file): $(tar_file)
@@ -82,5 +86,18 @@
 
 release-files: $(tar_file) $(sha256_file) $(gpg_file)
 
+dist-win:
+	@case $(host_triplet) in *-w64-mingw32) ;; *) echo "Error: Requires mingw build. See README.mingw.md.">&2; exit 1 ;; esac
+	@DIR=$(PACKAGE_TARNAME)-$(VERSION)-win`case $(host_triplet) in i686-*) echo 32 ;; x86_64-*) echo 64 ;; esac`; \
+	$(RM) -r $$DIR; $(MKDIR_P) $$DIR || exit 1; \
+	cp util/.libs/hb-{shape,view,subset}.exe $$DIR && \
+	$(top_srcdir)/mingw-ldd.py $$DIR/hb-view.exe | grep -v 'not found' | cut -d '>' -f 2 | xargs cp -t $$DIR && \
+	cp src/.libs/libharfbuzz{,-subset}-0.dll $$DIR && \
+	chmod a+x $$DIR/*.{exe,dll} && \
+	$(STRIP) $$DIR/*.{exe,dll} && \
+	zip -r $$DIR.zip $$DIR && \
+	$(RM) -r $$DIR && \
+	echo "$$DIR.zip is ready."
+
 
 -include $(top_srcdir)/git.mk
diff --git a/NEWS b/NEWS
index 890c258..7dde119 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,120 @@
+Overview of changes leading to 2.6.4
+Monday, October 29, 2019
+====================================
+- Small bug fix.
+- Build fixes.
+
+
+Overview of changes leading to 2.6.3
+Monday, October 28, 2019
+====================================
+- Misc small fixes, mostly to build-related issues.
+- New API:
++hb_font_get_nominal_glyphs()
+
+
+Overview of changes leading to 2.6.2
+Monday, September 30, 2019
+====================================
+- Misc small fixes, mostly to build-related issues.
+
+
+Overview of changes leading to 2.6.1
+Thursday, August 22, 2019
+====================================
+- Fix regression with hb_font_create_sub_font scaling introduced in 2.6.0.
+- Change interpretation of font PTEM size / CoreText font size handling.
+  See https://github.com/harfbuzz/harfbuzz/pull/1484
+- hb-ot-font: Prefer symbol cmap subtable if present.
+- Apply 'dist'/'abvm'/'blwm' features to all scripts.
+- Drop experimental DirectWrite API.
+
+
+Overview of changes leading to 2.6.0
+Tuesday, August 13, 2019
+====================================
+- New OpenType metrics, baseline, and metadata table access APIs.
+- New API to set font variations to a named-instance.
+- New hb-gdi.h header and API for creating hb_face_t from HFONT.
+- Amalgam: Provide a single-file harfbuzz.cc file for easier alternate building.
+- More size-reduction configurable options, enabled by HB_TINY.
+- New API:
++hb_font_set_var_named_instance()
++hb_gdi_face_create()
++hb_ot_layout_baseline_tag_t
++hb_ot_layout_get_baseline()
++hb_ot_meta_tag_t
++hb_ot_meta_get_entry_tags()
++hb_ot_meta_reference_entry()
++hb_ot_metrics_tag_t
++hb_ot_metrics_get_position()
++hb_ot_metrics_get_variation()
++hb_ot_metrics_get_x_variation()
++hb_ot_metrics_get_y_variation()
+
+
+Overview of changes leading to 2.5.3
+Wednesday, June 26, 2019
+====================================
+- Fix UCD script data for Unicode 10+ scripts.  This was broken since 2.5.0.
+- More optimizations for HB_TINY.
+
+
+Overview of changes leading to 2.5.2
+Thursday, June 20, 2019
+====================================
+- More hb-config.hh facilities to shrink library size, namely when built as
+  HB_TINY.
+- New documentation of custom configurations in CONFIG.md.
+- Fix build on gcc 4.8.  That's supported again.
+- Universal Shaping Engine improvements thanks to David Corbett.
+- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
+  such that Type1 fonts will continue kerning.
+
+
+Overview of changes leading to 2.5.1
+Friday, May 31, 2019
+====================================
+- Fix build with various versions of Visual Studio.
+- Improved documentation, thanks to Nathan Willis.
+- Bugfix in subsetting glyf table.
+- Improved scripts for cross-compiling for Windows using mingw.
+- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
+  A deprecated macro is added for backwards-compatibility.
+
+
+Overview of changes leading to 2.5.0
+Friday, May 24, 2019
+====================================
+- This release does not include much functional changes, but includes major internal
+  code-base changes.  We now require C++11.  Support for gcc 4.8 and earlier has been
+  dropped.
+- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
+- New Unicode Character Databse implementation that is half the size of previously-used
+  UCDN.
+- Subsetter improvements.
+- Improved documentation, thanks to Nathan Willis.
+- Misc shaping fixes.
+
+
+Overview of changes leading to 2.4.0
+Monday, March 25, 2019
+====================================
+- Unicode 12.
+- Misc fixes.
+- Subsetter improvements.
+- New API:
+HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
+hb_directwrite_face_create()
+
+
+Overview of changes leading to 2.3.1
+Wednesday, January 30, 2019
+====================================
+- AAT bug fixes.
+- Misc internal housekeeping cleanup.
+
+
 Overview of changes leading to 2.3.0
 Thursday, December 20, 2018
 ====================================
diff --git a/README b/README
deleted file mode 100644
index e50f8f0..0000000
--- a/README
+++ /dev/null
@@ -1,18 +0,0 @@
-[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
-[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
-[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
-[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
-[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
-[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
-[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
-[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
-
-This is HarfBuzz, a text shaping library.
-
-For bug reports, mailing list, and other information please visit:
-
-  http://harfbuzz.org/
-
-For license information, see the file COPYING.
-
-Documentation: https://harfbuzz.github.io
diff --git a/README b/README
new file mode 120000
index 0000000..42061c0
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/README.md b/README.md
deleted file mode 120000
index 100b938..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-README
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e0ef935
--- /dev/null
+++ b/README.md
@@ -0,0 +1,34 @@
+[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg?branch=master)](https://travis-ci.org/harfbuzz/harfbuzz)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true&branch=master)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
+[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
+[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
+[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
+[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
+[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
+[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
+[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
+[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
+
+This is HarfBuzz, a text shaping library.
+
+For bug reports, mailing list, and other information please visit:
+
+  http://harfbuzz.org/
+
+For license information, see [COPYING](COPYING).
+
+For build information, see [BUILD.md](BUILD.md).
+
+For custom configurations, see [CONFIG.md](CONFIG.md).
+
+For test execution, see [TESTING.md](TESTING.md).
+
+Documentation: https://harfbuzz.github.io
+
+
+<details>
+  <summary>Packaging status of HarfBuzz</summary
+
+[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)  
+
+</details>
diff --git a/README.mingw.md b/README.mingw.md
new file mode 100644
index 0000000..76d1a87
--- /dev/null
+++ b/README.mingw.md
@@ -0,0 +1,48 @@
+For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
+as a widely used and tested shaper is used as more-or-less OpenType reference
+implementation and that specially is important where OpenType specification
+is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
+steps are recommended:
+
+1. Install Wine from your favorite package manager.  On Fedora that's `dnf install wine`.
+
+2. And `mingw-w64` compiler.
+   With `brew` on macOS, you can have it like `brew install mingw-w64`.
+   On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the
+   64-bit Windows.
+
+3. Install cross-compiled dependency packages.  Alternatively see [^1] below.
+   On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
+   for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit.
+
+5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
+
+6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit.  This configures
+   HarfBuzz for cross-compiling.  It enables Uniscribe backend as well.
+
+7. `make`
+
+Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with
+the Microsoft Uniscribe,
+
+8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
+   Windows installation (assuming you have a 64-bit installation, otherwise
+   `C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
+   ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
+   Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
+   it is designed to work with DirectWrite which Wine can't work with its original one.
+   You want a Uniscribe from Windows 7 or older.
+
+   Put the DLL in the folder you are going to run the next command,
+
+9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
+
+(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
+
+
+[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
+     in your `~/.local/i686-w64-mingw32`.  Then replace all the instances of
+     `/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32`
+     with `<$HOME>/.local/i686-w64-mingw32` on that folder.
+     (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
+     You shouldn't replace the instances of those inside binary files.
diff --git a/README.python.md b/README.python.md
index 7cf091a..d9aaf89 100644
--- a/README.python.md
+++ b/README.python.md
@@ -6,21 +6,21 @@
 sudo apt-get install libgirepository1.0-dev
 ```
 
-And then run autogen.sh (if building from git), and then:
+And then run `autogen.sh` (if building from git), and then:
 
 ```bash
 ./configure --with-gobject --enable-introspection
 ```
 
-Make sure that gobject-introspection is enabled then in the final report.
+Make sure that gobject-introspection is reported enabled then in the `configure` script output.
 
 Compile and install.
 
-Make sure you have the installation lib dir in LD_LIBRARY_PATH, as needed
+Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed
 for the linker to find the library.
 
-Then make sure you also have GI_TYPELIB_PATH pointing to the resulting
-$prefix/lib/girepository-* directory.
+Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting
+`$prefix/lib/girepository-*` directory.
 
 Make sure you have pygobject installed.  Then check that the following
 import works in your Python interpreter:
@@ -30,7 +30,7 @@
 ```
 
 If it does, you are ready to call HarfBuzz from Python!  Congratulations.
-See src/sample.py.
+See [`src/sample.py`](src/sample.py).
 
 The Python API will change.  Let us know on the mailing list if you are
 using it, and send lots of feedback.
diff --git a/README.wine.md b/README.wine.md
deleted file mode 100644
index 799eb63..0000000
--- a/README.wine.md
+++ /dev/null
@@ -1,40 +0,0 @@
-For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
-as a widely used and tested shaper is used as more-or-less OpenType reference
-implementation and that specially is important where OpenType specification
-is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
-steps are recommended:
-
-1. Install Wine from your favorite package manager.
-
-2. And `mingw-w64` compiler.
-   With `brew` on macOS, you can have it like `brew install mingw-w64`
-
-3. Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
-   on your `~/.local/i686-w64-mingw32`.
-
-4. Replace all the instances of `/home/behdad/.local/i586-mingw32msvc`
-   and `/home/behdad/.local/i686-w64-mingw32` with `<$HOME>/.local/i686-w64-mingw32`
-   on that folder. (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
-
-   Probably you shouldn't replace the ones are inside binaries.
-
-5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
-
-6. `../mingw32.sh --with-uniscribe && cd ..`
-
-7. `make -Cwinbuild`
-
-Now you can use hb-shape using `wine winbuild/util/hb-shape.exe` but if you like to
-to use the original Uniscribe,
-
-8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
-   Windows installation (assuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
-   that it is not a DirectWrite proxy ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
-   Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
-   it is designed to work with DirectWrite which Wine can't work with its original one.
-
-   Put the dll on the folder you are going to run the next command,
-
-9. `WINEDLLOVERRIDES="usp10=n" wine winbuild/util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
-
-(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
diff --git a/RELEASING.md b/RELEASING.md
index 1fd8365..360aea7 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -33,39 +33,34 @@
    That's what happened to 2.0.0 going out with 1.8.0 hb-version.h...  So, that's
    a clue.
 
-7. "make release-files".  Enter your GPG password.  This creates a sha256 hash
-   and signs it.
-
-8. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
+7. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
    as well as any REPLACEME changes you made.  The commit message is simply the
    release number.  Eg. "1.4.7"
 
+8. "make dist" again to get a tarball with your new commit in the ChangeLog.  Then
+   "make release-files".  Enter your GPG password.  This creates a sha256 hash
+   and signs it.  Check the size of the three resulting files.
+
 9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7".  Enter your
    GPG password again.
 
 10. Build win32 bundle.
 
-   a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
+   a. Build Win32 binaries.  See [README.mingw.md](README.mingw.md).
 
-   b. Run `../mingw32.sh --with-uniscribe` script to configure harfbuzz with mingw
-   in a subdirector (eg. winbuild/),
-
-   c. make
-
-   d. Back in the parent directory, run `./UPDATE.sh`(available below) to build win32
-      bundle.
+   b. Run "make dist-win" to build Win32 bundle.
 
 11. Copy all artefacts to users.freedesktop.org and move them into
     `/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
     files.  Eg.:
  ```
--rw-r--r--  1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.bz2
--rw-r--r--  1 behdad eng      89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
--rw-r--r--  1 behdad eng     339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
+-rw-r--r--  1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz
+-rw-r--r--  1 behdad eng      89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256
+-rw-r--r--  1 behdad eng     339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc
 -rw-r--r--  1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
 ```
 
-12. While doing that, quickly double-check the size of the .tar.bz2 and .zip
+12. While doing that, quickly double-check the size of the .tar.xz and .zip
     files against their previous releases to make sure nothing bad happened.
     They should be in the ballpark, perhaps slightly larger.  Sometimes they
     do shrink, that's not by itself a stopper.
@@ -75,39 +70,3 @@
 
 14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
     edit the tag, upload artefacts and NEWS entry and save.
-
-
-## UPDATE.sh
-```bash
-#!/bin/bash
-
-v=$1
-
-if test "x$v" = x; then
-	echo "usage: UPDATE.sh micro-version"
-	exit 1
-fi
-
-dir_prefix=harfbuzz-1.4.
-dir_suffix=-win32
-dir=$dir_prefix$v$dir_suffix
-dir_old=$dir_prefix$((v-1))$dir_suffix
-if test -d "$dir"; then
-	echo "New dir $dir exists; not overwriting"
-	exit 1
-fi
-if ! test -d "$dir_old"; then
-	echo "Old dir $dir_old does NOT exist; aborting"
-	exit 1
-fi
-set -ex
-cp -a "$dir_old" "$dir.tmp"
-rm -f "$dir.tmp"/GDX32.dll
-rm -f "$dir.tmp"/usp10.dll
-cp ../winbuild/src/.libs/libharfbuzz-0.dll{,.def} $dir.tmp/
-cp ../winbuild/util/.libs/hb-{shape,view}.exe $dir.tmp/
-i686-w64-mingw32-strip $dir.tmp/{hb-shape.exe,hb-view.exe,libharfbuzz-0.dll}
-mv $dir.tmp $dir
-zip -r $dir.zip $dir
-echo Bundle $dir.zip ready
-```
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 0000000..94be3a0
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,86 @@
+## Build & Run
+
+Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
+Values defined in `hb-debug.hh`.
+
+```shell
+# quick sanity check
+time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
+  && (make -j4 -C test/api check || cat test/api/test-suite.log))
+
+# slower sanity check
+time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
+   && make -j4 -C src check \
+   && make -j4 -C test/api check \
+   && make -j4 -C test/subset check)
+
+# confirm you didn't break anything else
+time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
+  && make -j4 check)
+
+# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
+make distcheck
+```
+
+### Run tests with asan
+
+**NOTE**: this sometimes yields harder to read results than the full fuzzer
+
+```shell
+# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
+# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
+# ex
+export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
+
+./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
+# make/run tests as usual
+```
+
+### Debug with GDB
+
+```
+cd ./util
+../libtool --mode=execute gdb --args ./hb-subset ...
+```
+
+### Enable Debug Logging
+
+```shell
+# make clean if you previously build w/o debug logging
+make CPPFLAGS=-DHB_DEBUG_SUBSET=100
+```
+
+## Build and Test via CMake
+
+Note: You'll need to first install ninja-build via apt-get.
+
+```shell
+cd harfbuzz
+mkdir buid
+cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
+```
+## Test with the Fuzzer
+
+```shell
+# push your changs to a branch on googlefonts/harfbuzz
+# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
+# Change the git clone to pull your branch
+
+# Do this periodically
+sudo python infra/helper.py build_image harfbuzz
+
+# Do these to update/run
+sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
+sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
+```
+
+## Profiling
+
+```
+make clean
+./configure CXXFLAGS="-fno-omit-frame-pointer -g"
+make
+perf record -o <perf output file> -g <command to run>
+perf report -i<perf output file>
+```
+
diff --git a/THANKS b/THANKS
index 940cfde..88cb7e9 100644
--- a/THANKS
+++ b/THANKS
@@ -1,6 +1,6 @@
 Bradley Grainger
-Khaled Hosny
 Kenichi Ishibashi
+Ivan Kuckir <https://photopea.com/>
 Ryan Lortie
 Jeff Muizelaar
 suzuki toshiya
diff --git a/appveyor.yml b/appveyor.yml
index 21d4ea7..7fbcf49 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,16 +2,18 @@
 
 environment:
   matrix:
-    - compiler: msvc
-      generator: Visual Studio 14
-      platform: Win32
-      configuration: Debug
-      triplet: x86-windows
-    - compiler: msvc
-      generator: Visual Studio 14 Win64
-      platform: x64
-      configuration: Debug
-      triplet: x64-windows
+
+    #- compiler: msvc
+    #  generator: Visual Studio 14
+    #  platform: Win32
+    #  configuration: Debug
+    #  triplet: x86-windows
+
+    #- compiler: msvc
+    #  generator: Visual Studio 14 Win64
+    #  platform: x64
+    #  configuration: Debug
+    #  triplet: x64-windows
 
     - compiler: msvc
       generator: Visual Studio 14 ARM
@@ -19,10 +21,35 @@
       configuration: Debug
 
 
+    # Build only
+
+    #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+    #  compiler: msvc2
+    #  generator: Visual Studio 12
+    #  platform: Win32
+    #  configuration: Release
+    #  triplet: x86-windows
+
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      compiler: msvc2
+      generator: Visual Studio 15
+      platform: Win32
+      configuration: Release
+      triplet: x86-windows
+
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      compiler: msvc2
+      generator: Visual Studio 16
+      platform: Win32
+      configuration: Release
+      triplet: x86-windows
+
+
     - compiler: msys2
       MINGW_PREFIX: /mingw64
       MINGW_CHOST: x86_64-w64-mingw32
       MSYS2_ARCH: x86_64
+
     - compiler: msys2
       MINGW_PREFIX: /mingw32
       MINGW_CHOST: i686-w64-mingw32
@@ -30,30 +57,26 @@
 
 
 install:
-# - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"'
-  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
-  - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
-  - set PATH=%PATH%;C:\msys64\mingw64\bin # msys2 is added just for having "ragel" on PATH
-  - 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\setup-%CYGWIN_ARCH%.exe -g -q -P cygwin-devel,libfreetype-devel,libcairo-devel,libicu-devel,gcc,gcc-g++,gobject-introspection,libglib2.0-devel,libgraphite2-devel,pkg-config,python2'
+  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"'
   - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
 
 build_script:
-  - 'if "%compiler%"=="msvc" md build'
-  - 'if "%compiler%"=="msvc" cd build'
+  - 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"'
+  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake'
+
   - 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
-
-  - 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%" ../'
-  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake ../'
-
+  - 'if "%compiler%"=="msvc" cd build'
   - 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
   - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
 
+  - 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.'
+  - 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%'
+
   - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
-  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
+  - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --with-gdi --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
 
 cache:
   - c:\tools\vcpkg\installed\
-  - '%CYGWIN_PREFIX%\var\cache\setup'
 
 notifications:
   - provider: Email
diff --git a/configure.ac b/configure.ac
index 0315537..4125756 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [2.3.0],
+        [2.6.4],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -9,7 +9,7 @@
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
-AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
+AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability])
 AM_SILENT_RULES([yes])
 AX_CODE_COVERAGE
 
@@ -23,7 +23,7 @@
 AC_PROG_CC_C99
 AM_PROG_CC_C_O
 AC_PROG_CXX
-dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
+AX_CXX_COMPILE_STDCXX(11,, optional)
 AC_SYS_LARGEFILE
 PKG_PROG_PKG_CONFIG([0.20])
 AM_MISSING_PROG([RAGEL], [ragel])
@@ -77,13 +77,7 @@
 ])
 
 # Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
-
-save_libs="$LIBS"
-LIBS="$LIBS -lm"
-AC_CHECK_FUNCS([round], ,[AC_CHECK_DECLS([round], , ,[#include <math.h>])])
-LIBS="$save_libs"
-
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
 AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
 
 # Compiler flags
@@ -102,9 +96,6 @@
 	# by overriding CXXFLAGS.
 	CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
 
-	# Assorted warnings
-	CXXFLAGS="$CXXFLAGS -Wcast-align"
-
 	case "$host" in
 		*-*-mingw*)
 		;;
@@ -137,9 +128,7 @@
 AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
 
 have_pthread=false
-if test "$hb_os_win32" = no; then
-	AX_PTHREAD([have_pthread=true])
-fi
+AX_PTHREAD([have_pthread=true])
 if $have_pthread; then
 	AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
 fi
@@ -147,14 +136,6 @@
 
 dnl ==========================================================================
 
-have_fallback=true
-if $have_fallback; then
-	AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
-fi
-AM_CONDITIONAL(HAVE_FALLBACK, $have_fallback)
-
-dnl ===========================================================================
-
 AC_ARG_WITH(glib,
 	[AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
 			[Use glib @<:@default=auto@:>@])],,
@@ -303,21 +284,6 @@
 
 dnl ===========================================================================
 
-AC_ARG_WITH(ucdn,
-	[AS_HELP_STRING([--with-ucdn=@<:@yes/no@:>@],
-			[Use builtin UCDN library @<:@default=yes@:>@])],,
-	[with_ucdn=yes])
-have_ucdn=false
-if test "x$with_ucdn" = "xyes"; then
-	have_ucdn=true
-fi
-if $have_ucdn; then
-	AC_DEFINE(HAVE_UCDN, 1, [Have UCDN Unicode functions])
-fi
-AM_CONDITIONAL(HAVE_UCDN, $have_ucdn)
-
-dnl ==========================================================================
-
 AC_ARG_WITH(graphite2,
 	[AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
 			[Use the graphite2 library @<:@default=no@:>@])],,
@@ -395,6 +361,28 @@
 
 dnl ===========================================================================
 
+AC_ARG_WITH(gdi,
+	[AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@],
+			[Provide GDI integration helpers @<:@default=no@:>@])],,
+	[with_gdi=no])
+have_gdi=false
+if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then
+	AC_CHECK_HEADERS(windows.h, have_gdi=true)
+fi
+if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then
+	AC_MSG_ERROR([gdi support requested but not found])
+fi
+if $have_gdi; then
+	GDI_CFLAGS=
+	GDI_LIBS="-lgdi32"
+	AC_SUBST(GDI_CFLAGS)
+	AC_SUBST(GDI_LIBS)
+	AC_DEFINE(HAVE_GDI, 1, [Have GDI library])
+fi
+AM_CONDITIONAL(HAVE_GDI, $have_gdi)
+
+dnl ===========================================================================
+
 AC_ARG_WITH(directwrite,
 	[AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@],
 			[Use the DirectWrite library (experimental) @<:@default=no@:>@])],,
@@ -410,7 +398,7 @@
 fi
 if $have_directwrite; then
 	DIRECTWRITE_CXXFLAGS=
-	DIRECTWRITE_LIBS="-ldwrite"
+	DIRECTWRITE_LIBS=
 	AC_SUBST(DIRECTWRITE_CXXFLAGS)
 	AC_SUBST(DIRECTWRITE_LIBS)
 	AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
@@ -500,7 +488,6 @@
 Makefile
 src/Makefile
 src/harfbuzz-config.cmake
-src/hb-ucdn/Makefile
 util/Makefile
 test/Makefile
 test/api/Makefile
@@ -518,12 +505,17 @@
 
 AC_OUTPUT
 
+echo
+echo "C++ compiler version:"
+$CXX --version
+echo
+
 AC_MSG_NOTICE([
 
 Build configuration:
 
 Unicode callbacks (you want at least one):
-	Builtin (UCDN):		${have_ucdn}
+	Builtin			true
 	Glib:			${have_glib}
 	ICU:			${have_icu}
 
@@ -540,6 +532,7 @@
 Platform shapers (not normally needed):
 	CoreText:		${have_coretext}
 	DirectWrite:		${have_directwrite}
+	GDI:			${have_gdi}
 	Uniscribe:		${have_uniscribe}
 
 Other features:
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 9b54b40..f4bf2fd 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -33,7 +33,7 @@
 
 # Header files or dirs to ignore when scanning. Use base file/dir names
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
-IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
+IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
 if HAVE_GOBJECT
 else
 IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
@@ -75,12 +75,14 @@
 	usermanual-what-is-harfbuzz.xml \
 	usermanual-install-harfbuzz.xml \
 	usermanual-getting-started.xml \
+	usermanual-glyph-information.xml \
 	usermanual-shaping-concepts.xml \
+	usermanual-object-model.xml \
 	usermanual-buffers-language-script-and-direction.xml \
 	usermanual-fonts-and-faces.xml \
-	usermanual-clusters.xml \
 	usermanual-opentype-features.xml \
-	usermanual-glyph-information.xml \
+	usermanual-clusters.xml \
+	usermanual-utilities.xml \
 	version.xml
 
 # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 2735338..433c206 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -20,11 +20,7 @@
 
       <para>
 	The canonical source-code tree is available at
-        <ulink
-	    url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>
-        and is also available at
-        <ulink
-	    url="http://cgit.freedesktop.org/harfbuzz/">cgit.freedesktop.org/harfbuzz</ulink>.
+        <ulink url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
 	See <xref linkend="download" endterm="download.title"/> for
 	release tarballs.
       </para>
@@ -37,11 +33,12 @@
       <xi:include href="usermanual-install-harfbuzz.xml"/>
       <xi:include href="usermanual-getting-started.xml"/>
       <xi:include href="usermanual-shaping-concepts.xml"/>
+      <xi:include href="usermanual-object-model.xml"/>
       <xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
       <xi:include href="usermanual-fonts-and-faces.xml"/>
-      <xi:include href="usermanual-clusters.xml"/>
       <xi:include href="usermanual-opentype-features.xml"/>
-      <xi:include href="usermanual-glyph-information.xml"/>
+      <xi:include href="usermanual-clusters.xml"/>
+      <xi:include href="usermanual-utilities.xml"/>
   </part>
 
   <part>
@@ -136,6 +133,11 @@
       <index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
       <index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
 
+      <index id="api-index-2-6-0" role="2.6.0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-5-0" role="2.5.0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-4-0" role="2.4.0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-3-0" role="2.3.0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
+      <index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
@@ -149,7 +151,6 @@
       <index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
-      <index id="api-index-1-4-0" role="1.4.0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
       <index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index fd7682e..c625b92 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -1,6 +1,7 @@
 <SUBSECTION Private>
 HB_H_IN
 HB_OT_H_IN
+HB_AAT_H_IN
 </SECTION>
 
 <SECTION>
@@ -124,11 +125,17 @@
 hb_language_from_string
 hb_language_to_string
 hb_language_get_default
+hb_feature_from_string
+hb_feature_to_string
+hb_variation_from_string
+hb_variation_to_string
 hb_bool_t
 hb_codepoint_t
 hb_destroy_func_t
 hb_direction_t
 hb_language_t
+hb_feature_t
+hb_variation_t
 hb_mask_t
 hb_position_t
 hb_tag_t
@@ -147,6 +154,8 @@
 HB_DIRECTION_IS_VALID
 HB_DIRECTION_IS_VERTICAL
 HB_LANGUAGE_INVALID
+HB_FEATURE_GLOBAL_END
+HB_FEATURE_GLOBAL_START
 <SUBSECTION Private>
 HB_BEGIN_DECLS
 HB_END_DECLS
@@ -171,6 +180,7 @@
 HB_SCRIPT_CANADIAN_ABORIGINAL
 hb_font_funcs_set_glyph_func
 hb_font_get_glyph_func_t
+HB_MATH_GLYPH_PART_FLAG_EXTENDER
 hb_ot_layout_table_choose_script
 hb_ot_layout_table_find_script
 hb_ot_tag_from_language
@@ -187,12 +197,7 @@
 hb_unicode_decompose_compatibility_func_t
 hb_unicode_decompose_compatibility
 hb_unicode_funcs_set_decompose_compatibility_func
-hb_font_funcs_set_glyph_h_kerning_func
 hb_font_funcs_set_glyph_v_kerning_func
-hb_font_get_glyph_h_kerning
-hb_font_get_glyph_h_kerning_func_t
-hb_font_get_glyph_kerning_for_direction
-hb_font_get_glyph_kerning_func_t
 hb_font_get_glyph_v_kerning
 hb_font_get_glyph_v_kerning_func_t
 </SECTION>
@@ -209,6 +214,14 @@
 </SECTION>
 
 <SECTION>
+<FILE>hb-directwrite</FILE>
+hb_directwrite_face_create
+hb_directwrite_face_get_font_face
+<SUBSECTION Private>
+hb_directwrite_shape_experimental_width
+</SECTION>
+
+<SECTION>
 <FILE>hb-face</FILE>
 hb_face_count
 hb_face_t
@@ -255,6 +268,7 @@
 hb_font_funcs_set_glyph_from_name_func
 hb_font_funcs_set_glyph_h_advance_func
 hb_font_funcs_set_glyph_h_advances_func
+hb_font_funcs_set_glyph_h_kerning_func
 hb_font_funcs_set_glyph_h_origin_func
 hb_font_funcs_set_glyph_name_func
 hb_font_funcs_set_glyph_v_advance_func
@@ -284,8 +298,12 @@
 hb_font_get_glyph_h_advance_func_t
 hb_font_get_glyph_h_advances
 hb_font_get_glyph_h_advances_func_t
+hb_font_get_glyph_h_kerning
+hb_font_get_glyph_h_kerning_func_t
 hb_font_get_glyph_h_origin
 hb_font_get_glyph_h_origin_func_t
+hb_font_get_glyph_kerning_for_direction
+hb_font_get_glyph_kerning_func_t
 hb_font_get_glyph_name
 hb_font_get_glyph_name_func_t
 hb_font_get_glyph_origin_for_direction
@@ -321,12 +339,10 @@
 hb_font_set_ptem
 hb_font_set_scale
 hb_font_set_user_data
-hb_variation_t
-hb_variation_from_string
-hb_variation_to_string
 hb_font_set_variations
 hb_font_set_var_coords_design
 hb_font_set_var_coords_normalized
+hb_font_set_var_named_instance
 hb_font_subtract_glyph_origin_for_direction
 hb_font_t
 hb_reference_table_func_t
@@ -355,6 +371,11 @@
 </SECTION>
 
 <SECTION>
+<FILE>hb-gdi</FILE>
+hb_gdi_face_create
+</SECTION>
+
+<SECTION>
 <FILE>hb-glib</FILE>
 hb_glib_get_unicode_funcs
 hb_glib_script_from_script
@@ -527,6 +548,7 @@
 HB_OT_TAG_GPOS
 HB_OT_TAG_GSUB
 HB_OT_TAG_JSTF
+hb_ot_layout_baseline_tag_t
 hb_ot_layout_collect_lookups
 hb_ot_layout_collect_features
 hb_ot_layout_feature_get_characters
@@ -534,6 +556,7 @@
 hb_ot_layout_feature_get_name_ids
 hb_ot_layout_feature_with_variations_get_lookups
 hb_ot_layout_get_attach_points
+hb_ot_layout_get_baseline
 hb_ot_layout_get_glyph_class
 hb_ot_layout_get_glyphs_in_class
 hb_ot_layout_get_ligature_carets
@@ -588,6 +611,22 @@
 </SECTION>
 
 <SECTION>
+<FILE>hb-ot-meta</FILE>
+hb_ot_meta_tag_t
+hb_ot_meta_get_entry_tags
+hb_ot_meta_reference_entry
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot-metrics</FILE>
+hb_ot_metrics_tag_t
+hb_ot_metrics_get_position
+hb_ot_metrics_get_variation
+hb_ot_metrics_get_x_variation
+hb_ot_metrics_get_y_variation
+</SECTION>
+
+<SECTION>
 <FILE>hb-ot-shape</FILE>
 hb_ot_shape_glyphs_closure
 </SECTION>
@@ -649,11 +688,6 @@
 
 <SECTION>
 <FILE>hb-shape</FILE>
-HB_FEATURE_GLOBAL_END
-HB_FEATURE_GLOBAL_START
-hb_feature_t
-hb_feature_from_string
-hb_feature_to_string
 hb_shape
 hb_shape_full
 hb_shape_list_shapers
@@ -715,8 +749,6 @@
 <FILE>hb-uniscribe</FILE>
 hb_uniscribe_font_get_hfont
 hb_uniscribe_font_get_logfontw
-<SUBSECTION Private>
-hb_directwrite_shape_experimental_width
 </SECTION>
 
 <SECTION>
diff --git a/docs/usermanual-buffers-language-script-and-direction.xml b/docs/usermanual-buffers-language-script-and-direction.xml
index 68ce9bd..2865426 100644
--- a/docs/usermanual-buffers-language-script-and-direction.xml
+++ b/docs/usermanual-buffers-language-script-and-direction.xml
@@ -7,29 +7,38 @@
 <chapter id="buffers-language-script-and-direction">
   <title>Buffers, language, script and direction</title>
   <para>
-    The input to HarfBuzz is a series of Unicode characters, stored in a
+    The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
     buffer. In this chapter, we'll look at how to set up a buffer with
-    the text that we want and then customize the properties of the
-    buffer.
+    the text that we want and how to customize the properties of the
+    buffer. We'll also look at a piece of lower-level machinery that
+    you will need to understand before proceeding: the functions that
+    HarfBuzz uses to retrieve Unicode information.
+  </para>
+  <para>
+    After shaping is complete, HarfBuzz puts its output back
+    into the buffer. But getting that output requires setting up a
+    face and a font first, so we will look at that in the next chapter
+    instead of here.
   </para>
   <section id="creating-and-destroying-buffers">
     <title>Creating and destroying buffers</title>
     <para>
-      As we saw in our initial example, a buffer is created and
-      initialized with <literal>hb_buffer_create()</literal>. This
+      As we saw in our <emphasis>Getting Started</emphasis> example, a
+      buffer is created and 
+      initialized with <function>hb_buffer_create()</function>. This
       produces a new, empty buffer object, instantiated with some
       default values and ready to accept your Unicode strings.
     </para>
     <para>
-      HarfBuzz manages the memory of objects that it creates (such as
-      buffers), so you don't have to. When you have finished working on
-      a buffer, you can call <literal>hb_buffer_destroy()</literal>:
+      HarfBuzz manages the memory of objects (such as buffers) that it
+      creates, so you don't have to. When you have finished working on 
+      a buffer, you can call <function>hb_buffer_destroy()</function>:
     </para>
     <programlisting language="C">
-  hb_buffer_t *buffer = hb_buffer_create();
-  ...
-  hb_buffer_destroy(buffer);
-</programlisting>
+      hb_buffer_t *buf = hb_buffer_create();
+      ...
+      hb_buffer_destroy(buf);
+    </programlisting>
     <para>
       This will destroy the object and free its associated memory -
       unless some other part of the program holds a reference to this
@@ -38,46 +47,364 @@
       else destroying it, you should increase its reference count:
     </para>
     <programlisting language="C">
-void somefunc(hb_buffer_t *buffer) {
-  buffer = hb_buffer_reference(buffer);
-  ...
-</programlisting>
+      void somefunc(hb_buffer_t *buf) {
+      buf = hb_buffer_reference(buf);
+      ...
+    </programlisting>
     <para>
       And then decrease it once you're done with it:
     </para>
     <programlisting language="C">
-  hb_buffer_destroy(buffer);
-}
-</programlisting>
+      hb_buffer_destroy(buf);
+      }
+    </programlisting>
+    <para>
+      While we are on the subject of reference-counting buffers, it is
+      worth noting that an individual buffer can only meaningfully be
+      used by one thread at a time.
+    </para>
     <para>
       To throw away all the data in your buffer and start from scratch,
-      call <literal>hb_buffer_reset(buffer)</literal>. If you want to
+      call <function>hb_buffer_reset(buf)</function>. If you want to
       throw away the string in the buffer but keep the options, you can
-      instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
+      instead call <function>hb_buffer_clear_contents(buf)</function>.
     </para>
   </section>
+  
   <section id="adding-text-to-the-buffer">
     <title>Adding text to the buffer</title>
     <para>
       Now we have a brand new HarfBuzz buffer. Let's start filling it
       with text! From HarfBuzz's perspective, a buffer is just a stream
-      of Unicode codepoints, but your input string is probably in one of
-      the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
+      of Unicode code points, but your input string is probably in one of
+      the standard Unicode character encodings (UTF-8, UTF-16, or
+      UTF-32). HarfBuzz provides convenience functions that accept
+      each of these encodings:
+      <function>hb_buffer_add_utf8()</function>,
+      <function>hb_buffer_add_utf16()</function>, and
+      <function>hb_buffer_add_utf32()</function>. Other than the
+      character encoding they accept, they function identically.
     </para>
+    <para>
+      You can add UTF-8 text to a buffer by passing in the text array,
+      the array's length, an offset into the array for the first
+      character to add, and the length of the segment to add:
+    </para>
+    <programlisting language="C">
+    hb_buffer_add_utf8 (hb_buffer_t *buf,
+                    const char *text,
+                    int text_length,
+                    unsigned int item_offset,
+                    int item_length)
+    </programlisting>
+    <para>
+      So, in practice, you can say:
+    </para>
+    <programlisting language="C">
+      hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
+    </programlisting>
+    <para>
+      This will append your new characters to
+      <parameter>buf</parameter>, not replace its existing
+      contents. Also, note that you can use <literal>-1</literal> in
+      place of the first instance of <function>strlen(text)</function>
+      if your text array is NULL-terminated. Similarly, you can also use
+      <literal>-1</literal> as the final argument want to add its full
+      contents.
+    </para>
+    <para>
+      Whatever start <parameter>item_offset</parameter> and
+      <parameter>item_length</parameter> you provide, HarfBuzz will also
+      attempt to grab the five characters <emphasis>before</emphasis>
+      the offset point and the five characters
+      <emphasis>after</emphasis> the designated end. These are the
+      before and after "context" segments, which are used internally
+      for HarfBuzz to make shaping decisions. They will not be part of
+      the final output, but they ensure that HarfBuzz's
+      script-specific shaping operations are correct. If there are
+      fewer than five characters available for the before or after
+      contexts, HarfBuzz will just grab what is there.
+    </para>
+    <para>
+      For longer text runs, such as full paragraphs, it might be
+      tempting to only add smaller sub-segments to a buffer and
+      shape them in piecemeal fashion. Generally, this is not a good
+      idea, however, because a lot of shaping decisions are
+      dependent on this context information. For example, in Arabic
+      and other connected scripts, HarfBuzz needs to know the code
+      points before and after each character in order to correctly
+      determine which glyph to return.
+    </para>
+    <para>
+      The safest approach is to add all of the text available, then
+      use <parameter>item_offset</parameter> and
+      <parameter>item_length</parameter> to indicate which characters you
+      want shaped, so that HarfBuzz has access to any context.
+    </para>
+    <para>
+      You can also add Unicode code points directly with
+      <function>hb_buffer_add_codepoints()</function>. The arguments
+      to this function are the same as those for the UTF
+      encodings. But it is particularly important to note that
+      HarfBuzz does not do validity checking on the text that is added
+      to a buffer. Invalid code points will be replaced, but it is up
+      to you to do any deep-sanity checking necessary.
+    </para>
+    
   </section>
+  
   <section id="setting-buffer-properties">
     <title>Setting buffer properties</title>
     <para>
+      Buffers containing input characters still need several
+      properties set before HarfBuzz can shape their text correctly.
     </para>
-  </section>
-  <section id="what-about-the-other-scripts">
-    <title>What about the other scripts?</title>
     <para>
+      Initially, all buffers are set to the
+      <literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
+      type. After adding text, the buffer should be set to
+      <literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
+      indicates that it contains un-shaped input
+      characters. After shaping, the buffer will have the
+      <literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
+    </para>
+    <para>
+      <function>hb_buffer_add_utf8()</function> and the
+      other UTF functions set the content type of their buffer
+      automatically. But if you are reusing a buffer you may want to
+      check its state with
+      <function>hb_buffer_get_content_type(buffer)</function>. If
+      necessary you can set the content type with
+    </para>
+    <programlisting language="C">
+      hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
+    </programlisting>
+    <para>
+      to prepare for shaping.
+    </para>
+    <para>
+      Buffers also need to carry information about the script,
+      language, and text direction of their contents. You can set
+      these properties individually:
+    </para>
+    <programlisting language="C">
+      hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
+      hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
+      hb_buffer_set_language(buf, hb_language_from_string("en", -1));
+    </programlisting>
+    <para>
+      However, since these properties are often the repeated for
+      multiple text runs, you can also save them in a
+      <literal>hb_segment_properties_t</literal> for reuse:
+    </para>
+    <programlisting language="C">
+      hb_segment_properties_t *savedprops;
+      hb_buffer_get_segment_properties (buf, savedprops);
+      ...
+      hb_buffer_set_segment_properties (buf2, savedprops);
+    </programlisting>
+    <para>
+      HarfBuzz also provides getter functions to retrieve a buffer's
+      direction, script, and language properties individually.
+    </para>
+    <para>
+      HarfBuzz recognizes four text directions in
+      <type>hb_direction_t</type>: left-to-right
+      (<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
+      top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
+      bottom-to-top (<literal>HB_DIRECTION_BTT</literal>).  For the
+      script property, HarfBuzz uses identifiers based on the
+      <ulink
+      url="https://unicode.org/iso15924/">ISO 15924
+      standard</ulink>. For languages, HarfBuzz uses tags based on the
+      <ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
+    </para>
+    <para>
+      Helper functions are provided to convert character strings into
+      the necessary script and language tag types.
+    </para>
+    <para>
+      Two additional buffer properties to be aware of are the
+      "invisible glyph" and the replacement code point. The
+      replacement code point is inserted into buffer output in place of
+      any invalid code points encountered in the input. By default, it
+      is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
+      point, <literal>U+FFFD</literal> "&#xFFFD;". You can change this with
+    </para>
+    <programlisting language="C">
+      hb_buffer_set_replacement_codepoint(buf, replacement);
+    </programlisting>
+    <para>
+      passing in the replacement Unicode code point as the
+      <parameter>replacement</parameter> parameter.
+    </para>
+    <para>
+      The invisible glyph is used to replace all output glyphs that
+      are invisible. By default, the standard space character
+      <literal>U+0020</literal> is used; you can replace this (for
+      example, when using a font that provides script-specific
+      spaces) with 
+    </para>
+    <programlisting language="C">
+      hb_buffer_set_invisible_glyph(buf, replacement_glyph);
+    </programlisting>
+    <para>
+      Do note that in the <parameter>replacement_glyph</parameter>
+      parameter, you must provide the glyph ID of the replacement you
+      wish to use, not the Unicode code point.
+    </para>
+    <para>
+      HarfBuzz supports a few additional flags you might want to set
+      on your buffer under certain circumstances. The
+      <literal>HB_BUFFER_FLAG_BOT</literal> and
+      <literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
+      that the buffer represents the beginning or end (respectively)
+      of a text element (such as a paragraph or other block). Knowing
+      this allows HarfBuzz to apply certain contextual font features
+      when shaping, such as initial or final variants in connected
+      scripts.
+    </para>
+    <para>
+      <literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
+      tells HarfBuzz not to hide glyphs with the
+      <literal>Default_Ignorable</literal> property in Unicode. This 
+      property designates control characters and other non-printing
+      code points, such as joiners and variation selectors. Normally
+      HarfBuzz replaces them in the output buffer with zero-width
+      space glyphs (using the "invisible glyph" property discussed
+      above); setting this flag causes them to be printed, which can
+      be helpful for troubleshooting.
+    </para>
+    <para>
+      Conversely, setting the
+      <literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
+      tells HarfBuzz to remove <literal>Default_Ignorable</literal>
+      glyphs from the output buffer entirely. Finally, setting the
+      <literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
+      flag tells HarfBuzz not to insert the dotted-circle glyph
+      (<literal>U+25CC</literal>, "&#x25CC;"), which is normally
+      inserted into buffer output when broken character sequences are
+      encountered (such as combining marks that are not attached to a
+      base character).
     </para>
   </section>
+  
   <section id="customizing-unicode-functions">
     <title>Customizing Unicode functions</title>
     <para>
+      HarfBuzz requires some simple functions for accessing
+      information from the Unicode Character Database (such as the
+      <literal>General_Category</literal> (gc) and
+      <literal>Script</literal> (sc) properties) that is useful
+      for shaping, as well as some useful operations like composing and
+      decomposing code points.
+    </para>
+    <para>
+      HarfBuzz includes its own internal, lightweight set of Unicode
+      functions. At build time, it is also possible to compile support
+      for some other options, such as the Unicode functions provided
+      by GLib or the International Components for Unicode (ICU)
+      library. Generally, this option is only of interest for client
+      programs that have specific integration requirements or that do
+      a significant amount of customization.
+    </para>
+    <para>
+      If your program has access to other Unicode functions, however,
+      such as through a system library or application framework, you
+      might prefer to use those instead of the built-in
+      options. HarfBuzz supports this by implementing its Unicode
+      functions as a set of virtual methods that you can replace —
+      without otherwise affecting HarfBuzz's functionality.
+    </para>
+    <para>
+      The Unicode functions are specified in a structure called
+      <literal>unicode_funcs</literal> which is attached to each
+      buffer. But even though <literal>unicode_funcs</literal> is
+      associated with a <type>hb_buffer_t</type>, the functions
+      themselves are called by other HarfBuzz APIs that access
+      buffers, so it would be unwise for you to hook different
+      functions into different buffers.
+    </para>
+    <para>
+      In addition, you can mark your <literal>unicode_funcs</literal>
+      as immutable by calling
+      <function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
+      This is especially useful if your code is a
+      library or framework that will have its own client programs. By
+      marking your Unicode function choices as immutable, you prevent
+      your own client programs from changing the
+      <literal>unicode_funcs</literal> configuration and introducing
+      inconsistencies and errors downstream.
+    </para>
+    <para>
+      You can retrieve the Unicode-functions configuration for
+      your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
+    </para>
+    <programlisting language="C">
+      hb_unicode_funcs_t *ufunctions;
+      ufunctions = hb_buffer_get_unicode_funcs(buf);
+    </programlisting>
+    <para>
+      The current version of <literal>unicode_funcs</literal> uses six functions:
+    </para>
+    <itemizedlist>
+      <listitem>
+	<para>
+	  <function>hb_unicode_combining_class_func_t</function>:
+	  returns the Canonical Combining Class of a code point.
+      	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <function>hb_unicode_general_category_func_t</function>:
+	  returns the General Category (gc) of a code point.
+      	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <function>hb_unicode_mirroring_func_t</function>: returns
+	  the Mirroring Glyph code point (for bi-directional
+	  replacement) of a code point.
+      	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <function>hb_unicode_script_func_t</function>: returns the
+	  Script (sc) property of a code point.
+      	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <function>hb_unicode_compose_func_t</function>: returns the
+	  canonical composition of a sequence of two code points.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <function>hb_unicode_decompose_func_t</function>: returns
+	  the canonical decomposition of a code point.
+	</para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      Note, however, that future HarfBuzz releases may alter this set.
+    </para>
+    <para>
+      Each Unicode function has a corresponding setter, with which you
+      can assign a callback to your replacement function. For example,
+      to replace
+      <function>hb_unicode_general_category_func_t</function>, you can call
+    </para>
+    <programlisting language="C">
+      hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)	    
+    </programlisting>
+    <para>
+      Virtualizing this set of Unicode functions is primarily intended
+      to improve portability. There is no need for every client
+      program to make the effort to replace the default options, so if
+      you are unsure, do not feel any pressure to customize
+      <literal>unicode_funcs</literal>. 
     </para>
   </section>
+  
 </chapter>
diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml
index f48e89c..9147ff0 100644
--- a/docs/usermanual-clusters.xml
+++ b/docs/usermanual-clusters.xml
@@ -6,25 +6,41 @@
 ]>
 <chapter id="clusters">
   <title>Clusters</title>
-  <section id="clusters">
-    <title>Clusters</title>
+  <section id="clusters-and-shaping">
+    <title>Clusters and shaping</title>
     <para>
       In text shaping, a <emphasis>cluster</emphasis> is a sequence of
       characters that needs to be treated as a single, indivisible
-      unit.
+      unit. A single letter or symbol can be a cluster of its
+      own. Other clusters correspond to longer subsequences of the
+      input code points &mdash; such as a ligature or conjunct form
+      &mdash; and require the shaper to ensure that the cluster is not
+      broken during the shaping process.
     </para>
     <para>
       A cluster is distinct from a <emphasis>grapheme</emphasis>,
-      which is the smallest unit of a writing system or script,
-      because clusters are only relevant for script shaping and the
-      layout of glyphs.
+      which is the smallest unit of meaning in a writing system or
+      script.
     </para>
     <para>
-      For example, a grapheme may be a letter, a number, a logogram,
-      or a symbol. When two letters form a ligature, however, they
-      combine into a single glyph. They are therefore part of the same
-      cluster and are treated as a unit &mdash; even though the two
-      original, underlying letters are separate graphemes.
+      The definitions of the two terms are similar. However, clusters
+      are only relevant for script shaping and glyph layout. In
+      contrast, graphemes are a property of the underlying script, and
+      are of interest when client programs implement orthographic 
+      or linguistic functionality.
+    </para>
+    <para>
+      For example, two individual letters are often two separate
+      graphemes. When two letters form a ligature, however, they
+      combine into a single glyph. They are then part of the same
+      cluster and are treated as a unit by the shaping engine &mdash;
+      even though the two original, underlying letters remain separate
+      graphemes.
+    </para>
+    <para>
+      HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
+      with graphemes &mdash; although client programs using HarfBuzz
+      may still care about graphemes for other reasons from time to time.
     </para>
     <para>
       During the shaping process, there are several shaping operations
@@ -32,14 +48,15 @@
       points form a ligature or a conjunct form and are replaced by a
       single glyph) or split one character into several (for example,
       when decomposing a code point through the
-      <literal>ccmp</literal> feature).
+      <literal>ccmp</literal> feature). Operations like these alter
+      clusters; HarfBuzz tracks the changes to ensure that no clusters
+      get lost or broken during shaping. 
     </para>
     <para>
-      HarfBuzz tracks clusters independently from how these
-      shaping operations affect the individual glyphs that comprise the
-      output HarfBuzz returns in a buffer. Consequently,
-      a client program using HarfBuzz can utilize the cluster
-      information to implement features such as:
+      HarfBuzz records cluster information independently from how
+      shaping operations affect the individual glyphs returned in an
+      output buffer. Consequently, a client program using HarfBuzz can
+      utilize the cluster information to implement features such as:
     </para>
     <itemizedlist>
       <listitem>
@@ -77,11 +94,14 @@
 	<para>
 	  Performing line-breaking, justification, and other
 	  line-level or paragraph-level operations that must be done
-	  after shaping is complete, but which require character-level
-	  properties.
+	  after shaping is complete, but which require examining
+	  character-level properties.
 	</para>
       </listitem>
     </itemizedlist>
+  </section>
+  <section id="working-with-harfbuzz-clusters">
+    <title>Working with HarfBuzz clusters</title>
     <para>
       When you add text to a HarfBuzz buffer, each code point must be
       assigned a <emphasis>cluster value</emphasis>.
@@ -94,7 +114,67 @@
       value does not matter.
     </para>
     <para>
-      Client programs can choose how HarfBuzz handles clusters during
+      Some of the shaping operations performed by HarfBuzz &mdash;
+      such as reordering, composition, decomposition, and substitution
+      &mdash; may alter the cluster values of some characters. The
+      final cluster values in the buffer at the end of the shaping
+      process will indicate to client programs which subsequences of
+      glyphs represent a cluster and, therefore, must not be
+      separated.
+    </para>
+    <para>
+      In addition, client programs can query the final cluster values
+      to discern other potentially important information about the
+      glyphs in the output buffer (such as whether or not a ligature
+      was formed).
+    </para>
+    <para>
+      For example, if the initial sequence of cluster values was:
+    </para>
+    <programlisting>
+      0,1,2,3,4
+    </programlisting>
+    <para>
+      and the final sequence of cluster values is:
+    </para>
+    <programlisting>
+      0,0,3,3
+    </programlisting>
+    <para>
+      then there are two clusters in the output buffer: the first
+      cluster includes the first two glyphs, and the second cluster
+      includes the third and fourth glyphs. It is also evident that a
+      ligature or conjunct has been formed, because there are fewer
+      glyphs in the output buffer (four) than there were code points
+      in the input buffer (five).
+    </para>
+    <para>
+      Although client programs using HarfBuzz are free to assign
+      initial cluster values in any manner they choose to, HarfBuzz
+      does offer some useful guarantees if the cluster values are
+      assigned in a monotonic (either non-decreasing or non-increasing)
+      order.
+    </para>
+    <para>
+      For buffers in the left-to-right (LTR)
+      or top-to-bottom (TTB) text flow direction,
+      HarfBuzz will preserve the monotonic property: client programs
+      are guaranteed that monotonically increasing initial cluster
+      values will be returned as monotonically increasing final
+      cluster values.
+    </para>
+    <para>
+      For buffers in the right-to-left (RTL)
+      or bottom-to-top (BTT) text flow direction,
+      the directionality of the buffer itself is reversed for final
+      output as a matter of design. Therefore, HarfBuzz inverts the
+      monotonic property: client programs are guaranteed that
+      monotonically increasing initial cluster values will be
+      returned as monotonically <emphasis>decreasing</emphasis> final
+      cluster values.
+    </para>
+    <para>
+      Client programs can adjust how HarfBuzz handles clusters during
       shaping by setting the
       <literal>cluster_level</literal> of the
       buffer. HarfBuzz offers three <emphasis>levels</emphasis> of
@@ -179,7 +259,7 @@
       assign initial cluster values in a buffer by reusing the indices
       of the code points in the input text. This gives a sequence of
       cluster values that is monotonically increasing (for example,
-      0,1,2,3,4,5). 
+      0,1,2,3,4). 
     </para>
     <para>
       It is not <emphasis>required</emphasis> that the cluster values
@@ -233,16 +313,44 @@
 	</para>
       </listitem>
     </itemizedlist>
-	
   </section>
+  
   <section id="a-clustering-example-for-levels-0-and-1">
     <title>A clustering example for levels 0 and 1</title>
     <para>
-      The guarantees and benefits of level 0 and level 1 can be seen
-      with some examples. First, let us examine what happens with cluster
-      values when shaping involves cluster merging with ligatures and
-      decomposition.
+      The basic shaping operations affect clusters in a predictable
+      manner when using level 0 or level 1: 
     </para>
+    <itemizedlist>
+      <listitem>
+	<para>
+	  When two or more clusters <emphasis>merge</emphasis>, the
+	  resulting merged cluster takes as its cluster value the
+	  <emphasis>minimum</emphasis> of the incoming cluster values.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  When a cluster <emphasis>decomposes</emphasis>, all of the
+	  resulting child clusters inherit as their cluster value the
+	  cluster value of the parent cluster.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  When a character is <emphasis>reordered</emphasis>, the
+	  reordered character and all clusters that the character
+	  moves past as part of the reordering are merged into one cluster.
+	</para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      The functionality, guarantees, and benefits of level 0 and level
+      1 behavior can be seen with some examples. First, let us examine
+      what happens with cluster values when shaping involves cluster
+      merging with ligatures and decomposition.
+    </para>
+
     <para>
       Let's say we start with the following character sequence (top row) and
       initial cluster values (bottom row):
@@ -279,8 +387,8 @@
     <para>
       Next, let us say that the <literal>BC</literal> ligature glyph
       decomposes into three components, and <literal>D</literal> also
-      decomposes into two components. These components each inherit the
-      cluster value of their parent: 
+      decomposes into two components. Whenever a cluster decomposes,
+      its components each inherit the cluster value of their parent: 
     </para>
     <programlisting>
       A,BC0,BC1,BC2,D0,D1,E
@@ -296,6 +404,12 @@
       0,1  ,1  ,1    ,1 ,4
     </programlisting>
     <para>
+      Note that the entirety of cluster 3 merges into cluster 1, not
+      just the <literal>D0</literal> glyph. This reflects the fact
+      that the cluster <emphasis>must</emphasis> be treated as an
+      indivisible unit.
+    </para>
+    <para>
       At this point, cluster 1 means: the character sequence
       <literal>BCD</literal> is represented by glyphs
       <literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
@@ -319,18 +433,24 @@
       0,1,2,3,4
     </programlisting>
     <para>
-      If <literal>D</literal> is reordered to before <literal>B</literal>,
-      then HarfBuzz merges the <literal>B</literal>,
-      <literal>C</literal>, and <literal>D</literal> clusters, and we
-      get:
+      If <literal>D</literal> is reordered to the position immediately
+      before <literal>B</literal>, then HarfBuzz merges the
+      <literal>B</literal>, <literal>C</literal>, and
+      <literal>D</literal> clusters &mdash; all the clusters between
+      the final position of the reordered glyph and its original
+      position. This means that we get:
     </para>
     <programlisting>
       A,D,B,C,E
       0,1,1,1,4
     </programlisting>
     <para>
-      This is clearly not ideal, but it is the only sensible way to
-      maintain a monotonic sequence of cluster values and retain the
+      as the final cluster sequence.
+    </para>
+    <para>
+      Merging this many clusters is not ideal, but it is the only
+      sensible way for HarfBuzz to maintain the guarantee that the
+      sequence of cluster values remains monotonic and to retain the
       true relationship between glyphs and characters.
     </para>
   </section>
@@ -340,8 +460,9 @@
       The preceding examples demonstrate the main effects of using
       cluster levels 0 and 1. The only difference between the two
       levels is this: in level 0, at the very beginning of the shaping
-      process, HarfBuzz also merges clusters between any base character
-      and all Unicode marks (combining or not) that follow it.
+      process, HarfBuzz merges the cluster of each base character
+      with the clusters of all Unicode marks (combining or not) and
+      modifiers that follow it.
     </para>
     <para>
       For example, let us start with the following character sequence
@@ -362,15 +483,20 @@
       0,0    ,2
     </programlisting>
     <para>
+      This merger is performed before any other script-shaping
+      steps.
+    </para>
+    <para>
       This initial cluster merging is the default behavior of the
       Windows shaping engine, and the old HarfBuzz codebase copied
       that behavior to maintain compatibility. Consequently, it has
       remained the default behavior in the new HarfBuzz codebase.
     </para>
     <para>
-      But this initial cluster-merging behavior makes it impossible to
+      But this initial cluster-merging behavior makes it impossible
+      for client programs to implement some features (such as to
       color diacritic marks differently from their base
-      characters. That is why, in level 1, HarfBuzz does not perform
+      characters). That is why, in level 1, HarfBuzz does not perform
       the initial merging step.
     </para>
     <para>
@@ -378,29 +504,34 @@
       perform cursor positioning, level 0 is more convenient. But
       relying on cluster boundaries for cursor positioning is wrong: cursor
       positions should be determined based on Unicode grapheme
-      boundaries, not on shaping-cluster boundaries. As such, level 1
-      clusters are preferred. 
+      boundaries, not on shaping-cluster boundaries. As such, using
+      level 1 clustering behavior is recommended. 
     </para>
     <para>
-      One last note about levels 0 and 1. HarfBuzz currently does not allow a
-      <literal>MultipleSubst</literal> lookup to replace a glyph with zero
-      glyphs (in other words, to delete a glyph). But, in some other situations,
-      glyphs can be deleted. In those cases, if the glyph being deleted is
-      the last glyph of its cluster, HarfBuzz makes sure to merge the cluster
-      with a neighboring cluster.
+      One final facet of levels 0 and 1 is worth noting. HarfBuzz
+      currently does not allow any
+      <emphasis>multiple-substitution</emphasis> GSUB lookups to 
+      replace a glyph with zero glyphs (in other words, to delete a
+      glyph).
+    </para>
+    <para>
+      But, in some other situations, glyphs can be deleted. In
+      those cases, if the glyph being deleted is the last glyph of its
+      cluster, HarfBuzz makes sure to merge the deleted glyph's
+      cluster with a neighboring cluster.
     </para>
     <para>
       This is done primarily to make sure that the starting cluster of the
       text always has the cluster index pointing to the start of the text
-      for the run; more than one client currently relies on this
+      for the run; more than one client program currently relies on this
       guarantee.
     </para>
     <para>
-      Incidentally, Apple's CoreText does something else to maintain the
-      same promise: it inserts a glyph with id 65535 at the beginning of
-      the glyph string if the glyph corresponding to the first character
-      in the run was deleted. HarfBuzz might do something similar in the
-      future.
+      Incidentally, Apple's CoreText does something different to
+      maintain the same promise: it inserts a glyph with id 65535 at
+      the beginning of the glyph string if the glyph corresponding to
+      the first character in the run was deleted. HarfBuzz might do
+      something similar in the future.
     </para>
   </section>
   <section id="level-2">
@@ -415,16 +546,39 @@
       performs no merging of clusters whatsoever.
     </para>
     <para>
-      When glyphs form a ligature (or when some other feature
-      substitutes multiple glyphs with one glyph), the cluster value
-      of the first glyph is retained as the cluster value for the
-      ligature. However, no subsequent clusters &mdash; including
-      marks and modifiers &mdash; are affected.
+      This means that there is no initial base-and-mark merging step
+      (as is done in level 0), and it means that reordering moves and
+      ligature substitutions do not trigger a cluster merge.
     </para>
     <para>
-      Level 2 cluster behavior is less complex than level 0 or level
-      1, but there are a few cases in which processing cluster values
-      produced at level 2 may be tricky. 
+      Only one shaping operation directly affects clusters when using
+      level 2:
+    </para>
+    <itemizedlist>
+      <listitem>
+	<para>
+	  When a cluster <emphasis>decomposes</emphasis>, all of the
+	  resulting child clusters inherit as their cluster value the
+	  cluster value of the parent cluster.
+	</para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      When glyphs do form a ligature (or when some other feature
+      substitutes multiple glyphs with one glyph) the cluster value
+      of the first glyph is retained as the cluster value for the
+      resulting ligature.
+    </para>
+    <para>
+      This occurrence sounds similar to a cluster merge, but it is
+      different. In particular, no subsequent characters &mdash;
+      including marks and modifiers &mdash; are affected. They retain
+      their previous cluster values. 
+    </para>
+    <para>
+      Level 2 cluster behavior is ultimately less complex than level 0
+      or level 1, but there are several cases for which processing
+      cluster values produced at level 2 may be tricky. 
     </para>
     <section id="ligatures-with-combining-marks-in-level-2">
       <title>Ligatures with combining marks in level 2</title>
@@ -532,10 +686,11 @@
       <para>
 	There may be other problems encountered with ligatures under
 	level 2, such as if the direction of the text is forced to
-	opposite of its natural direction (for example, left-to-right
-	Arabic). But, generally speaking, these other scenarios are
-	minor corner cases that are too obscure for most client
-	programs to need to worry about.
+	the opposite of its natural direction (for example, Arabic text
+	that is forced into left-to-right directionality). But,
+	generally speaking, these other scenarios are minor corner
+	cases that are too obscure for most client programs to need to
+	worry about.
       </para>
     </section>
   </section>
diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml
index 5536004..1258bec 100644
--- a/docs/usermanual-fonts-and-faces.xml
+++ b/docs/usermanual-fonts-and-faces.xml
@@ -5,20 +5,449 @@
   <!ENTITY version SYSTEM "version.xml">
 ]>
 <chapter id="fonts-and-faces">
-  <title>Fonts and faces</title>
-  <section id="using-freetype">
+  <title>Fonts, faces, and output</title>
+    <para>
+      In the previous chapter, we saw how to set up a buffer and fill
+      it with text as Unicode code points. In order to shape this
+      buffer text with HarfBuzz, you will need also need a font
+      object.
+    </para>
+    <para>
+      HarfBuzz provides abstractions to help you cache and reuse the
+      heavier parts of working with binary fonts, so we will look at
+      how to do that. We will also look at how to work with the
+      FreeType font-rendering library and at how you can customize
+      HarfBuzz to work with other libraries.
+    </para>
+    <para>
+      Finally, we will look at how to work with OpenType variable
+      fonts, the latest update to the OpenType font format, and at
+      some other recent additions to OpenType.
+    </para>
+
+  <section id="fonts-and-faces-objects">
+    <title>Font and face objects</title>
+    <para>
+      The outcome of shaping a run of text depends on the contents of
+      a specific font file (such as the substitutions and positioning
+      moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
+      accessing those internals fast.
+    </para>
+    <para>
+      An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
+      in HarfBuzz. This data type is a wrapper around an
+      <type>hb_blob_t</type> blob that holds the contents of a binary
+      font file. Since HarfBuzz supports TrueType Collections and
+      OpenType Collections (each of which can include multiple
+      typefaces), a HarfBuzz face also requires an index number
+      specifying which typeface in the file you want to use. Most of
+      the font files you will encounter in the wild include just a
+      single face, however, so most of the time you would pass in
+      <literal>0</literal> as the index when you create a face:
+    </para>
+    <programlisting language="C">
+      hb_blob_t* blob = hb_blob_create_from_file(file);
+      ...
+      hb_face_t* face = hb_face_create(blob, 0);
+    </programlisting>
+    <para>
+      On its own, a face object is not quite ready to use for
+      shaping. The typeface must be set to a specific point size in
+      order for some details (such as hinting) to work. In addition,
+      if the font file in question is an OpenType Variable Font, then
+      you may need to specify one or variation-axis settings (or a
+      named instance) in order to get the output you need.
+    </para>
+    <para>
+      In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
+      object from your face.
+    </para>
+    <para>
+      Font objects also have the advantage of being considerably
+      lighter-weight than face objects (remember that a face contains
+      the contents of a binary font file mapped into memory). As a
+      result, you can cache and reuse a font object, but you could
+      also create a new one for each additional size you needed.
+      Creating new fonts incurs some additional overhead, of course,
+      but whether or not it is excessive is your call in the end. In
+      contrast, face objects are substantially larger, and you really
+      should cache them and reuse them whenever possible.
+    </para>
+    <para>
+      You can create a font object from a face object:
+    </para>
+    <programlisting language="C">
+      hb_font_t* hb_font = hb_font_create(hb_face);
+    </programlisting>
+    <para>
+      After creating a font, there are a few properties you should
+      set. Many fonts enable and disable hints based on the size it
+      is used at, so setting this is important for font
+      objects. <function>hb_font_set_ppem(font, x_ppem,
+      y_ppem)</function> sets the pixels-per-EM value of the font. You
+      can also set the point size of the font with
+      <function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
+      industry standard 72 points per inch.
+    </para>
+    <para>
+      HarfBuzz lets you specify the degree subpixel precision you want
+      through a scaling factor. You can set horizontal and
+      vertical scaling factors on the
+      font by calling <function>hb_font_set_scale(font, x_scale,
+      y_scale)</function>. 
+    </para>
+    <para>
+      There may be times when you are handed a font object and need to
+      access the face object that it comes from. For that, you can call
+    </para>
+    <programlisting language="C">
+      hb_face = hb_font_get_face(hb_font);
+    </programlisting>
+    <para>
+      You can also create a font object from an existing font object
+      using the <function>hb_font_create_sub_font()</function>
+      function. This creates a child font object that is initiated
+      with the same attributes as its parent; it can be used to
+      quickly set up a new font for the purpose of overriding a specific
+      font-functions method.
+    </para>
+    <para>
+      All face objects and font objects are lifecycle-managed by
+      HarfBuzz. After creating a face, you increase its reference
+      count with <function>hb_face_reference(face)</function> and
+      decrease it with
+      <function>hb_face_destroy(face)</function>. Likewise, you
+      increase the reference count on a font with
+      <function>hb_font_reference(font)</function> and decrease it
+      with <function>hb_font_destroy(font)</function>.
+    </para>
+    <para>
+      You can also attach user data to face objects and font objects.
+    </para>
+  </section>
+
+ <section id="fonts-and-faces-custom-functions">
+    <title>Customizing font functions</title>
+    <para>
+      During shaping, HarfBuzz frequently needs to query font objects
+      to get at the contents and parameters of the glyphs in a font
+      file. It includes a built-in set of functions that is tailored
+      to working with OpenType fonts. However, as was the case with
+      Unicode functions in the buffers chapter, HarfBuzz also wants to
+      make it easy for you to assign a substitute set of font
+      functions if you are developing a program to work with a library
+      or platform that provides its own font functions. 
+    </para>
+    <para>
+      Therefore, the HarfBuzz API defines a set of virtual
+      methods for accessing font-object properties, and you can
+      replace the defaults with your own selections without
+      interfering with the shaping process. Each font object in
+      HarfBuzz includes a structure called
+      <literal>font_funcs</literal> that serves as a vtable for the
+      font object. The virtual methods in
+      <literal>font_funcs</literal> are:
+    </para>
+    <itemizedlist>
+      <listitem>
+    <para>
+      <function>hb_font_get_font_h_extents_func_t</function>: returns
+      the extents of the font for horizontal text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_font_v_extents_func_t</function>: returns
+      the extents of the font for vertical text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_nominal_glyph_func_t</function>: returns
+      the font's nominal glyph for a given code point.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_variation_glyph_func_t</function>: returns
+      the font's glyph for a given code point when it is followed by a
+      given Variation Selector.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_nominal_glyphs_func_t</function>: returns
+      the font's nominal glyphs for a series of code points.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_advance_func_t</function>: returns
+      the advance for a glyph.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_h_advance_func_t</function>: returns
+      the advance for a glyph for horizontal text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_v_advance_func_t</function>:returns
+      the advance for a glyph for vertical text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_advances_func_t</function>: returns
+      the advances for a series of glyphs.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_h_advances_func_t</function>: returns
+      the advances for a series of glyphs for horizontal text .
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_v_advances_func_t</function>: returns
+      the advances for a series of glyphs for vertical text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_origin_func_t</function>: returns
+      the origin coordinates of a glyph.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_h_origin_func_t</function>: returns
+      the origin coordinates of a glyph for horizontal text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_v_origin_func_t</function>: returns
+      the origin coordinates of a glyph for vertical text.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_extents_func_t</function>: returns
+      the extents for a glyph.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_contour_point_func_t</function>:
+      returns the coordinates of a specific contour point from a glyph.
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_name_func_t</function>: returns the
+      name of a glyph (from its glyph index).
+    </para>
+      </listitem>
+      <listitem>
+    <para>
+      <function>hb_font_get_glyph_from_name_func_t</function>: returns
+      the glyph index that corresponds to a given glyph name.
+    </para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      You can fetch the font-functions configuration for a font object
+      by calling <function>hb_font_get_font_funcs()</function>:
+    </para>
+    <programlisting language="C">
+      hb_font_funcs_t *ffunctions;
+      ffunctions = hb_font_get_font_funcs (font);
+    </programlisting>
+    <para>
+      The individual methods can each be replaced with their own setter
+      function, such as
+      <function>hb_font_funcs_set_nominal_glyph_func(*ffunctions,
+      func, *user_data, destroy)</function>. 
+    </para>
+    <para>
+      Font-functions structures can be reused for multiple font
+      objects, and can be reference counted with
+      <function>hb_font_funcs_reference()</function> and
+      <function>hb_font_funcs_destroy()</function>. Just like other
+      objects in HarfBuzz, you can set user-data for each
+      font-functions structure and assign a destroy callback for
+      it.
+    </para>
+    <para>
+      You can also mark a font-functions structure as immutable,
+      with <function>hb_font_funcs_make_immutable()</function>. This
+      is especially useful if your code is a library or framework that
+      will have its own client programs. By marking your
+      font-functions structures as immutable, you prevent your client
+      programs from changing the configuration and introducing
+      inconsistencies and errors downstream.
+    </para>
+  </section>
+
+  <section id="fonts-and-faces-native-opentype">
+    <title>Font objects and HarfBuzz's native OpenType implementation</title>
+    <para>
+      By default, whenever HarfBuzz creates a font object, it will
+      configure the font to use a built-in set of font functions that
+      supports contemporary OpenType font internals. If you want to
+      work with OpenType or TrueType fonts, you should be able to use
+      these functions without difficulty.
+    </para>
+    <para>
+      Many of the methods in the font-functions structure deal with
+      the fundamental properties of glyphs that are required for
+      shaping text: extents (the maximums and minimums on each axis),
+      origins (the <literal>(0,0)</literal> coordinate point which
+      glyphs are drawn in reference to), and advances (the amount that
+      the cursor needs to be moved after drawing each glyph, including
+      any empty space for the glyph's side bearings).
+    </para>
+    <para>
+      As you can see in the list of functions, there are separate "horizontal"
+      and "vertical" variants depending on whether the text is set in
+      the horizontal or vertical direction. For some scripts, fonts
+      that are designed to support text set horizontally or vertically (for
+      example, in Japanese) may include metrics for both text
+      directions. When fonts don't include this information, HarfBuzz
+      does its best to transform what the font provides.
+    </para>
+    <para>
+      In addition to the direction-specific functions, HarfBuzz
+      provides some higher-level functions for fetching information
+      like extents and advances for a glyph. If you call
+    </para>
+    <programlisting language="C">
+      hb_font_get_glyph_advance_for_direction(font, direction, extents);
+    </programlisting>
+    <para>
+      then you can provide any <type>hb_direction_t</type> as the
+      <parameter>direction</parameter> parameter, and HarfBuzz will
+      use the correct function variant for the text direction. There
+      are similar higher-level versions of the functions for fetching
+      extents, origin coordinates, and contour-point
+      coordinates. There are also addition and subtraction functions
+      for moving points with respect to the origin.
+    </para>
+    <para>
+      There are also methods for fetching the glyph ID that
+      corresponds to a Unicode code point (possibly when followed by a
+      variation-selector code point), fetching the glyph name from the
+      font, and fetching the glyph ID that corresponds to a glyph name
+      you already have.
+    </para>
+    <para>
+      HarfBuzz also provides functions for converting between glyph
+      names and string
+      variables. <function>hb_font_glyph_to_string(font, glyph, s,
+      size)</function> retrieves the name for the glyph ID
+      <parameter>glyph</parameter> from the font object. It generates a
+      generic name of the form <literal>gidDDD</literal> (where DDD is
+      the glyph index) if there is no name for the glyph in the
+      font. The <function>hb_font_glyph_from_string(font, s, len,
+      glyph)</function> takes an input string <parameter>s</parameter>
+      and looks for a glyph with that name in the font, returning its
+      glyph ID in the <parameter>glyph</parameter>
+      output parameter. It automatically parses
+      <literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
+    </para>
+  </section>
+
+
+  <!-- Commenting out FreeType integration section-holder for now. May move
+       to the full-blown Integration Chapter. -->
+  
+  <!--   <section id="fonts-and-faces-freetype">
     <title>Using FreeType</title>
     <para>
+
     </para>
-  </section>
-  <section id="using-harfbuzzs-native-opentype-implementation">
-    <title>Using HarfBuzz's native OpenType implementation</title>
     <para>
+      
     </para>
-  </section>
-  <section id="using-your-own-font-functions">
-    <title>Using your own font functions</title>
+  </section> -->
+
+  <section id="fonts-and-faces-variable">
+    <title>Working with OpenType Variable Fonts</title>
     <para>
+      If you are working with OpenType Variable Fonts, there are a few
+      additional functions you should use to specify the
+      variation-axis settings of your font object. Without doing so,
+      your variable font's font object can still be used, but only at
+      the default setting for every axis (which, of course, is
+      sometimes what you want, but does not cover general usage).
+    </para>
+    <para>
+      HarfBuzz manages variation settings in the
+      <type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
+      variation-axis identifier tag and a <property>value</property> for its
+      setting. You can retrieve the list of variation axes in a font
+      binary from the face object (not from a font object, notably) by
+      calling <function>hb_ot_var_get_axis_count(face)</function> to
+      find the number of axes, then using
+      <function>hb_ot_var_get_axis_infos()</function> to collect the 
+      axis structures:
+    </para>
+    <programlisting language="C">
+      axes = hb_ot_var_get_axis_count(face);
+      ...
+      hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
+    </programlisting>
+    <para>
+      For each axis returned in the array, you can can access the
+      identifier in its <property>tag</property>. HarfBuzz also has
+      tag definitions predefined for the five standard axes specified
+      in OpenType (<literal>ital</literal> for italic,
+      <literal>opsz</literal> for optical size,
+      <literal>slnt</literal> for slant, <literal>wdth</literal> for
+      width, and <literal>wght</literal> for weight). Each axis also
+      has a <property>min_value</property>, a
+      <property>default_value</property>, and a <property>max_value</property>.
+    </para>
+    <para>
+      To set your font object's variation settings, you call the
+      <function>hb_font_set_variations()</function> function with an
+      array of <type>hb_variation_t</type> variation settings. Let's
+      say our font has weight and width axes. We need to specify each
+      of the axes by tag and assign a value on the axis:
+    </para>
+    <programlisting language="C">
+      unsigned int variation_count = 2;
+      hb_variation_t variation_data[variation_count];
+      variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
+      variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
+      variation_data[0].value = 80;
+      variation_data[1].value = 750;
+      ...
+      hb_font_set_variations(font, variation_data, variation_count);
+    </programlisting>
+    <para>
+      That should give us a slightly condensed font ("normal" on the
+      <literal>wdth</literal> axis is 100) at a noticeably bolder
+      weight ("regular" is 400 on the <literal>wght</literal> axis).
+    </para>
+    <para>
+      In practice, though, you should always check that the value you
+      want to set on the axis is within the
+      [<property>min_value</property>,<property>max_value</property>]
+      range actually implemented in the font's variation axis. After
+      all, a font might only provide lighter-than-regular weights, and
+      setting a heavier value on the <literal>wght</literal> axis will
+      not change that. 
+    </para>
+    <para>
+      Once your variation settings are specified on your font object,
+      however, shaping with a variable font is just like shaping a
+      static font.
     </para>
   </section>
-</chapter>
+
+ </chapter>
diff --git a/docs/usermanual-getting-started.xml b/docs/usermanual-getting-started.xml
index 932bd94..1f26df8 100644
--- a/docs/usermanual-getting-started.xml
+++ b/docs/usermanual-getting-started.xml
@@ -75,13 +75,45 @@
 
   <section>
     <title>Terminology</title>
+    <para>
+      
+    </para>
       <variablelist>
+	<?dbfo list-presentation="blocks"?> 
+	<varlistentry>
+	  <term>script</term>
+	  <listitem>
+	    <para>
+	      In text shaping, a <emphasis>script</emphasis> is a
+	      writing system: a set of symbols, rules, and conventions
+	      that is used to represent a language or multiple
+	      languages.
+	    </para>
+	    <para>
+	      In general computing lingo, the word "script" can also
+	      be used to mean an executable program (usually one
+	      written in a human-readable programming language). For
+	      the sake of clarity, HarfBuzz documents will always use
+	      more specific terminology when referring to this
+	      meaning, such as "Python script" or "shell script." In
+	      all other instances, "script" refers to a writing system.
+	    </para>
+	    <para>
+	      For developers using HarfBuzz, it is important to note
+	      the distinction between a script and a language. Most
+	      scripts are used to write a variety of different
+	      languages, and many languages may be written in more
+	      than one script.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	
 	<varlistentry>
 	  <term>shaper</term>
 	  <listitem>
 	    <para>
 	      In HarfBuzz, a <emphasis>shaper</emphasis> is a
-	      handler for a specific script shaping model. HarfBuzz
+	      handler for a specific script-shaping model. HarfBuzz
 	      implements separate shapers for Indic, Arabic, Thai and
 	      Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
 	      Universal Shaping Engine (USE), and a default shaper for
@@ -95,12 +127,12 @@
 	  <listitem>
 	    <para>
 	      In text shaping, a <emphasis>cluster</emphasis> is a
-	      sequence of codepoints that must be handled as an
-	      indivisible unit. Clusters can include codepoint
+	      sequence of codepoints that must be treated as an
+	      indivisible unit. Clusters can include code-point
 	      sequences that form a ligature or base-and-mark
 	      sequences. Tracking and preserving clusters is important
 	      when shaping operations might separate or reorder
-	      codepoints.
+	      code points.
 	    </para>
 	    <para>
 	      HarfBuzz provides three cluster
@@ -111,7 +143,59 @@
 	  </listitem>
 	</varlistentry>
 	
-
+	<varlistentry>
+	  <term>grapheme</term>
+	  <listitem>
+	    <para>
+	      In linguistics, a <emphasis>grapheme</emphasis> is one
+	      of the indivisible units that make up a writing system or
+	      script. Often, graphemes are individual symbols (letters,
+	      numbers, punctuation marks, logograms, etc.) but,
+	      depending on the writing system, a particular grapheme
+	      might correspond to a sequence of several Unicode code
+	      points.
+	    </para>
+	    <para>
+	      In practice, HarfBuzz and other text-shaping engines
+	      are not generally concerned with graphemes. However, it
+	      is important for developers using HarfBuzz to recognize
+	      that there is a difference between graphemes and shaping
+	      clusters (see above). The two concepts may overlap
+	      frequently, but there is no guarantee that they will be
+	      identical.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	
+	<varlistentry>
+	  <term>syllable</term>
+	  <listitem>
+	    <para>
+	      In linguistics, a <emphasis>syllable</emphasis> is an 
+	      a sequence of sounds that makes up a building block of a
+	      particular language. Every language has its own set of
+	      rules describing what constitutes a valid syllable.
+	    </para>
+	    <para>
+	      For text-shaping purposes, the various definitions of
+	      "syllable" are important because script-specific shaping
+	      operations may be applied at the syllable level. For
+	      example, a reordering rule might specify that a vowel
+	      mark be reordered to the beginning of the syllable.
+	    </para>
+	    <para>
+	      Syllables will consist of one or more Unicode code
+	      points. The definition of a syllable for a particular
+	      writing system might correspond to how HarfBuzz
+	      identifies clusters (see above) for the same writing
+	      system. However, it is important for developers using
+	      HarfBuzz to recognize that there is a difference between
+	      syllables and shaping clusters. The two concepts may
+	      overlap frequently, but there is no guarantee that they
+	      will be identical.
+	    </para>
+	  </listitem>
+	</varlistentry>
       </variablelist>
     
   </section>
@@ -139,7 +223,7 @@
     <orderedlist numeration="arabic">
       <listitem override="2">
 	<para>
-          Guess the script, language and direction of the buffer.
+          Set the script, language and direction of the buffer.
 	</para>
       </listitem>
     </orderedlist>
@@ -191,14 +275,14 @@
     </orderedlist>
     <programlisting language="C">
       for (i = 0; i &lt; glyph_count; ++i) {
-      glyphid = glyph_info[i].codepoint;
-      x_offset = glyph_pos[i].x_offset / 64.0;
-      y_offset = glyph_pos[i].y_offset / 64.0;
-      x_advance = glyph_pos[i].x_advance / 64.0;
-      y_advance = glyph_pos[i].y_advance / 64.0;
-      draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
-      cursor_x += x_advance;
-      cursor_y += y_advance;
+          glyphid = glyph_info[i].codepoint;
+          x_offset = glyph_pos[i].x_offset / 64.0;
+          y_offset = glyph_pos[i].y_offset / 64.0;
+          x_advance = glyph_pos[i].x_advance / 64.0;
+          y_advance = glyph_pos[i].y_advance / 64.0;
+          draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
+          cursor_x += x_advance;
+          cursor_y += y_advance;
       }
     </programlisting>
     <orderedlist numeration="arabic">
diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml
index a6484fc..2b61ce8 100644
--- a/docs/usermanual-install-harfbuzz.xml
+++ b/docs/usermanual-install-harfbuzz.xml
@@ -57,8 +57,7 @@
     <para>
       For example, on an Ubuntu or Debian system, you would run:
       <programlisting>
-	<command>sudo apt install</command> <package>gcc g++
-	libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
+	<command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
       </programlisting>
       On Fedora, RHEL, CentOS, or other Red-Hat&ndash;based systems, you would run:
       <programlisting>
@@ -126,7 +125,7 @@
       </para>
       <para>
 	If you need to build HarfBuzz from source, first put the
-	<program>ragel</program> binary on your
+	<package>ragel</package> binary on your
 	<literal>PATH</literal>, then follow the appveyor CI cmake
 	<ulink
 	    url="https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml">build
@@ -184,8 +183,7 @@
       <para>If you are
 	using MacPorts, you should run:
       <programlisting>
-	<command>sudo port install</command> <package>autoconf
-	automake libtool pkgconfig ragel gtk-doc</package> 
+	<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package> 
       </programlisting>
       to install the build dependencies.
       </para>
@@ -229,8 +227,9 @@
       </para>
 
       <variablelist>
+	<?dbfo list-presentation="blocks"?> 
 	<varlistentry>
-	  <term>--with-libstdc++</term>
+	  <term><command>--with-libstdc++</command></term>
 	  <listitem>
 	    <para>
 	      Allow linking with libstdc++. <emphasis>(Default = no)</emphasis>
@@ -243,11 +242,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-glib</term>
+	  <term><command>--with-glib</command></term>
 	  <listitem>
 	    <para>
 	     Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the GLib
 	      library.  The default setting is to check for the
@@ -259,7 +258,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-gobject</term>
+	  <term><command>--with-gobject</command></term>
 	  <listitem>
 	    <para>
 	      Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
@@ -275,7 +274,7 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-cairo</term>
+	  <term><command>--with-cairo</command></term>
 	  <listitem>
 	    <para>
 	      Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
@@ -294,11 +293,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-fontconfig</term>
+	  <term><command>--with-fontconfig</command></term>
 	  <listitem>
 	    <para>
 	      Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the Fontconfig
 	      library, which provides font-matching functions and
@@ -314,11 +313,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-icu</term>
+	  <term><command>--with-icu</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the
 	      <emphasis>International Components for
@@ -332,29 +331,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-ucdn</term>
-	  <listitem>
-	    <para>
-	      Use HarfBuzz's <ulink url="https://github.com/harfbuzz/harfbuzz/tree/master/src/hb-ucdn">built-in UCDN library</ulink>. <emphasis>(Default = auto)</emphasis>
-	    </para>	    
-	    <para>
-	      The HarfBuzz source tree includes a <emphasis>Unicode
-	      Database and Normalization</emphasis> (UCDN) library
-	      that provides access to basic character properties in
-	      the Unicode Character Database (UCD) as well as low-level
-	      normalization functions. HarfBuzz can be built without
-	      this UCDN support if the usage of a different UCDN
-	      library is desired.
-	    </para>
-	  </listitem>
-	</varlistentry>
-	
-	<varlistentry>
-	  <term>--with-graphite2</term>
+	  <term><command>--with-graphite2</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the Graphite2
 	      library, which provides support for the Graphite shaping
@@ -364,11 +345,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-freetype</term>
+	  <term><command>--with-freetype</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the FreeType
 	      font-rendering library. The default setting is to check for the
@@ -379,13 +360,13 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-uniscribe</term>
+	  <term><command>--with-uniscribe</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink
 	      url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
 	      library (experimental). <emphasis>(Default = no)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the Uniscribe
 	      font-rendering library. Uniscribe is available on
@@ -397,11 +378,11 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-directwrite</term>
+	  <term><command>--with-directwrite</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the DirectWrite
 	      font-rendering library. DirectWrite is available on
@@ -413,17 +394,29 @@
 	</varlistentry>
 	
 	<varlistentry>
-	  <term>--with-coretext</term>
+	  <term><command>--with-coretext</command></term>
 	  <listitem>
 	    <para>
 	      Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
-	    </para>	    
+	    </para>
 	    <para>
 	      This option enables or disables usage of the CoreText
 	      library. CoreText is available on macOS and iOS systems.
 	    </para>
 	  </listitem>
 	</varlistentry>	
+
+	<varlistentry>
+	  <term><command>--enable-gtk-doc</command></term>
+	  <listitem>
+	    <para>
+	      Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
+	    </para>
+	    <para>
+	      This option enables the building of the documentation.
+	    </para>
+	  </listitem>
+	</varlistentry>
       </variablelist>
     </section>
     
diff --git a/docs/usermanual-object-model.xml b/docs/usermanual-object-model.xml
new file mode 100644
index 0000000..f571c47
--- /dev/null
+++ b/docs/usermanual-object-model.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<chapter id="object-model">
+  <title>The HarfBuzz object model</title>
+  <section id="object-model-intro">
+    <title>An overview of data types in HarfBuzz</title>
+    <para>
+      HarfBuzz features two kinds of data types: non-opaque,
+      pass-by-value types and opaque, heap-allocated types.  This kind
+      of separation is common in C libraries that have to provide
+      API/ABI compatibility (almost) indefinitely. 
+    </para>
+    <para>
+      <emphasis>Value types:</emphasis> The non-opaque, pass-by-value
+      types include integer types, enums, and small structs.  Exposing
+      a struct in the public API makes it impossible to expand the
+      struct in the future. As such, exposing structs is reserved for
+      cases where it’s extremely inefficient to do otherwise.
+    </para>
+    <para>
+      In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
+      <literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
+      category and are non-opaque.
+    </para>
+    <para>
+      For all non-opaque structs where future extensibility may be
+      necessary, reserved members are included to hold space for
+      possible future members.  As such, it’s important to provide
+      <function>equal()</function>, and <function>hash()</function>
+      methods for such structs, allowing users of the API do
+      effectively deal with the type without having to 
+      adapt their code to future changes. 
+    </para>
+    <para>
+      Important value types provided by HarfBuzz include the structs
+      for working with Unicode code points, glyphs, and tags for font
+      tables and features, as well as the enums for many Unicode and
+      OpenType properties.
+    </para>
+  </section>
+  
+  <section id="object-model-object-types">
+    <title>Objects in HarfBuzz</title>
+    <para>
+      <emphasis>Object types:</emphasis> Opaque struct types are used
+      for what HarfBuzz loosely calls "objects."  This doesn’t have
+      much to do with the terminology from object-oriented programming
+      (OOP), although some of the concepts are similar.
+    </para>
+    <para>
+      In HarfBuzz, all object types provide certain
+      lifecycle-management APIs.  Objects are reference-counted, and
+      constructed with various <function>create()</function> methods, referenced via
+      <function>reference()</function> and dereferenced using
+      <function>destroy()</function>.
+    </para>
+    <para>
+      For example,
+      the <literal>hb_buffer_t</literal> object has
+      <function>hb_buffer_create()</function> as its constructor,
+      <function>hb_buffer_reference()</function> to reference, and
+      <function>hb_buffer_destroy()</function> to dereference. 
+    </para>
+    <para>
+      After construction, each object's properties are accessible only
+      through the setter and getter functions described in the API
+      Reference manual.
+    </para>
+    <para>
+      Key object types provided by HarfBuzz include:
+    </para>
+    <itemizedlist spacing="compact">
+      <listitem>
+	<para>
+	  <emphasis>blobs</emphasis>, which act as low-level wrappers around binary
+	  data. Blobs are typically used to hold the contents of a
+	  binary font file.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <emphasis>faces</emphasis>, which represent typefaces from a
+	  font file, but without specific parameters (such as size) set.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <emphasis>fonts</emphasis>, which represent instances of a
+	  face with all of their parameters specified.
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <emphasis>buffers</emphasis>, which hold Unicode code points
+	  for characters (before shaping) and the shaped glyph output
+	  (after shaping).
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  <emphasis>shape plans</emphasis>, which store the settings
+	  that HarfBuzz will use when shaping a particular text
+	  segment. Shape plans are not generally used by client
+	  programs directly, but as we will see in a later chapter,
+	  they are still valuable to understand.
+	</para>
+      </listitem>
+    </itemizedlist>
+	
+  </section>
+
+  
+  
+  <section id="object-model-lifecycle">
+    <title>Object lifecycle management</title>
+    <para>
+      Each object type in HarfBuzz provides a
+      <function>create()</function> method. Some object types provide
+      additional variants of <function>create()</function> to handle
+      special cases or to speed up common tasks; those variants are
+      documented in the API reference. For example,
+      <function>hb_blob_create_from_file()</function> constructs a new
+      blob directly from the contents of a file.
+    </para>
+    <para>
+      All objects are created with an initial reference count of
+      <literal>1</literal>. Client programs can increase the reference
+      count on an object by calling its
+      <function>reference()</function> method. Whenever a client
+      program is finished with an object, it should call its 
+      corresponding <function>destroy()</function> method. The destroy
+      method will decrease the reference count on the object and,
+      whenever the reference count reaches zero, it will also destroy
+      the object and free all of the associated memory.
+    </para>
+    <para>
+      All of HarfBuzz's object-lifecycle-management APIs are
+      thread-safe (unless you compiled HarfBuzz from source with the
+      <literal>HB_NO_MT</literal> configuration flag), even when the
+      object as a whole is not thread-safe. 
+      It is also permissible to <function>reference()</function> or to 
+      <function>destroy()</function> the <literal>NULL</literal>
+      value.
+    </para>
+    <para>
+      Some objects are thread-safe after they have been constructed
+      and set up. The general pattern is to
+      <function>create()</function> the object, make a few
+      <function>set_*()</function> calls to set up the
+      object, and then use it without further modification.
+    </para>
+    <para>
+      To ensure that such an object is not modified, client programs
+      can explicitly mark an object as immutable. HarfBuzz provides
+      <function>make_immutable()</function> methods to mark an object
+      as immutable and <function>is_immutable()</function> methods to
+      test whether or not an object is immutable. Attempts to use
+      setter functions on immutable objects will fail silently; see the API
+      Reference manual for specifics. 
+    </para>
+    <para>
+      Note also that there are no "make mutable" methods. If client
+      programs need to alter an object previously marked as immutable,
+      they will need to make a duplicate of the original.
+    </para>
+    <para>
+      Finally, object constructors (and, indeed, as much of the
+      shaping API as possible) will never return
+      <literal>NULL</literal>.  Instead, if there is an allocation
+      error, each constructor will return an “empty” object
+      singleton.
+    </para>
+    <para>
+      These empty-object singletons are inert and safe (although
+      typically useless) to pass around.  This design choice avoids
+      having to check for <literal>NULL</literal> pointers all
+      throughout the code.
+    </para>
+    <para>
+      In addition, this “empty” object singleton can also be accessed
+      using the <function>get_empty()</function> method of the object
+      type in question.
+    </para>
+  </section>
+
+  
+  <section id="object-model-user-data">
+    <title>User data</title>
+    <para>
+      To better integrate with client programs, HarfBuzz's objects
+      offer a "user data" mechanism that can be used to attach
+      arbitrary data to the object.  User-data attachment can be
+      useful for tying the lifecycles of various pieces of data
+      together, or for creating language bindings. 
+    </para>
+    <para>
+      Each object type has a <function>set_user_data()</function>
+      method and a <function>get_user_data()</function> method. The
+      <function>set_user_data()</function> methods take a client-provided
+      <literal>key</literal> and a pointer,
+      <literal>user_data</literal>, pointing to the data itself. Once
+      the key-data pair has been attached to the object, the
+      <function>get_user_data()</function> method can be called with
+      the key, returning the <function>user_data</function> pointer.
+    </para>
+    <para>
+      The <function>set_user_data()</function> methods also support an
+      optional <function>destroy</function> callback. Client programs
+      can set the <function>destroy</function> callback and receive
+      notification from HarfBuzz whenever the object is destructed.
+    </para>
+    <para>
+      Finally, each <function>set_user_data()</function> method allows
+      the client program to set a <literal>replace</literal> Boolean
+      indicating whether or not the function call should replace any
+      existing <literal>user_data</literal>
+      associated with the specified key.
+    </para>
+  </section>  
+
+  
+  
+  <section id="object-model-blobs">
+    <title>Blobs</title>
+    <para>
+      While most of HarfBuzz's object types are specific to the
+      shaping process, <emphasis>blobs</emphasis> are somewhat
+      different.
+    </para>
+    <para>
+      Blobs are an abstraction desgined to negotiate lifecycle and
+      permissions for raw pieces of data.  For example, when you load
+      the raw font data into memory and want to pass it to HarfBuzz,
+      you do so in a <literal>hb_blob_t</literal> wrapper.
+    </para>
+    <para>
+      This allows you to take advantage of HarffBuzz's
+      reference-counting and <function>destroy</function>
+      callbacks. If you allocated the memory for the data using 
+      <function>malloc()</function>, you would create the blob using
+    </para>
+    <programlisting language="C">
+      hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
+    </programlisting>
+    <para>
+      That way, HarfBuzz will call <function>free()</function> on the
+      allocated memory whenever the blob drops its last reference and
+      is deconstructed.  Consequently, the user code can stop worrying
+      about freeing memory and let the reference-counting machinery
+      take care of that. 
+    </para>
+  </section>
+  
+</chapter>
diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml
index 51ff55a..881af2a 100644
--- a/docs/usermanual-opentype-features.xml
+++ b/docs/usermanual-opentype-features.xml
@@ -6,14 +6,301 @@
 ]>
 <chapter id="shaping-and-shape-plans">
   <title>Shaping and shape plans</title>
-  <section id="opentype-features">
+  <para>
+    Once you have your face and font objects configured as desired and
+    your input buffer is filled with the characters you need to shape,
+    all you need to do is call <function>hb_shape()</function>.
+  </para>
+  <para>
+    HarfBuzz will return the shaped version of the text in the same
+    buffer that you provided, but it will be in output mode. At that
+    point, you can iterate through the glyphs in the buffer, drawing
+    each one at the specified position or handing them off to the
+    appropriate graphics library.
+  </para>
+  <para>
+    For the most part, HarfBuzz's shaping step is straightforward from
+    the outside. But that doesn't mean there will never be cases where
+    you want to look under the hood and see what is happening on the
+    inside. HarfBuzz provides facilities for doing that, too.
+  </para>
+  
+  <section id="shaping-buffer-output">
+    <title>Shaping and buffer output</title>
+    <para>
+      The <function>hb_shape()</function> function call takes four arguments: the font
+      object to use, the buffer of characters to shape, an array of
+      user-specified features to apply, and the length of that feature
+      array. The feature array can be NULL, so for the sake of
+      simplicity we will start with that case.
+    </para>
+    <para>
+      Internally, HarfBuzz looks  at the tables of the font file to
+      determine where glyph classes, substitutions, and positioning
+      are defined, using that information to decide which
+      <emphasis>shaper</emphasis> to use (<literal>ot</literal> for
+      OpenType fonts, <literal>aat</literal> for Apple Advanced
+      Typography fonts, and so on). It also looks at the direction,
+      script, and language properties of the segment to figure out
+      which script-specific shaping model is needed (at least, in
+      shapers that support multiple options).      
+    </para>
+    <para>
+      If a font has a GDEF table, then that is used for
+      glyph classes; if not, HarfBuzz will fall back to Unicode
+      categorization by code point. If a font has an AAT "morx" table,
+      then it is used for substitutions; if not, but there is a GSUB
+      table, then the GSUB table is used. If the font has an AAT
+      "kerx" table, then it is used for positioning; if not, but
+      there is a GPOS table, then the GPOS table is used. If neither
+      table is found, but there is a "kern" table, then HarfBuzz will
+      use the "kern" table. If there is no "kerx", no GPOS, and no
+      "kern", HarfBuzz will fall back to positioning marks itself.
+    </para>
+    <para>
+      With a well-behaved OpenType font, you expect GDEF, GSUB, and
+      GPOS tables to all be applied. HarfBuzz implements the
+      script-specific shaping models in internal functions, rather
+      than in the public API.
+    </para>
+    <para>
+      The algorithms
+      used for complex scripts can be quite involved; HarfBuzz tries
+      to be compatible with the OpenType Layout specification
+      and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
+      output of Microsoft's Uniscribe engine. See the <ulink
+      url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
+      Typography pages</ulink> for more detail.
+    </para>
+    <para>
+      In general, though, all that you need to know is that
+      <function>hb_shape()</function> returns the results of shaping
+      in the same buffer that you provided. The buffer's content type
+      will now be set to
+      <literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
+      that it contains shaped output, rather than input text. You can
+      now extract the glyph information and positioning arrays:
+    </para>
+    <programlisting language="C">
+      hb_glyph_info_t *glyph_info    = hb_buffer_get_glyph_infos(buf, &amp;glyph_count);
+      hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
+    </programlisting>
+    <para>
+      The glyph information array holds a <type>hb_glyph_info_t</type>
+      for each output glyph, which has two fields:
+      <parameter>codepoint</parameter> and
+      <parameter>cluster</parameter>. Whereas, in the input buffer,
+      the <parameter>codepoint</parameter> field contained the Unicode
+      code point, it now contains the glyph ID of the corresponding
+      glyph in the font. The <parameter>cluster</parameter> field is
+      an integer that you can use to help identify when shaping has
+      reordered, split, or combined code points; we will say more
+      about that in the next chapter.
+    </para>
+    <para>
+      The glyph positions array holds a corresponding
+      <type>hb_glyph_position_t</type> for each output glyph,
+      containing four fields: <parameter>x_advance</parameter>,
+      <parameter>y_advance</parameter>,
+      <parameter>x_offset</parameter>, and
+      <parameter>y_offset</parameter>. The advances tell you how far
+      you need to move the drawing point after drawing this glyph,
+      depending on whether you are setting horizontal text (in which
+      case you will have x advances) or vertical text (for which you
+      will have y advances). The x and y offsets tell you where to
+      move to start drawing the glyph; usually you will have both and
+      x and a y offset, regardless of the text direction.
+    </para>
+    <para>
+      Most of the time, you will rely on a font-rendering library or
+      other graphics library to do the actual drawing of glyphs, so
+      you will need to iterate through the glyphs in the buffer and
+      pass the corresponding values off.
+    </para>
+  </section>
+  
+  <section id="shaping-opentype-features">
     <title>OpenType features</title>
     <para>
+      OpenType features enable fonts to include smart behavior,
+      implemented as "lookup" rules stored in the GSUB and GPOS
+      tables. The OpenType specification defines a long list of
+      standard features that fonts can use for these behaviors; each
+      feature has a four-character reserved name and a well-defined
+      semantic meaning.
+    </para>
+    <para>
+      Some OpenType features are defined for the purpose of supporting
+      complex-script shaping, and are automatically activated, but
+      only when a buffer's script property is set to a script that the
+      feature supports.
+    </para>
+    <para>
+      Other features are more generic and can apply to several (or
+      any) script, and shaping engines are expected to implement
+      them. By default, HarfBuzz activates several of these features
+      on every text run. They include <literal>abvm</literal>,
+      <literal>blwm</literal>, <literal>ccmp</literal>,
+      <literal>locl</literal>, <literal>mark</literal>,
+      <literal>mkmk</literal>, and <literal>rlig</literal>.
+    </para>
+    <para>
+      In addition, if the text direction is horizontal, HarfBuzz
+      also applies the <literal>calt</literal>,
+      <literal>clig</literal>, <literal>curs</literal>,
+      <literal>dist</literal>, <literal>kern</literal>,
+      <literal>liga</literal>, <literal>rclt</literal>,
+      and <literal>frac</literal> features.
+    </para>
+    <para>
+      If the text direction is vertical, HarfBuzz applies
+      the <literal>vert</literal> feature by default.
+    </para>
+    <para>
+      Still other features are designed to be purely optional and left
+      up to the application or the end user to enable or disable as desired.
+    </para>
+    <para>
+      You can adjust the set of features that HarfBuzz applies to a
+      buffer by supplying an array of <type>hb_feature_t</type>
+      features as the third argument to
+      <function>hb_shape()</function>. For a simple case, let's just
+      enable the <literal>dlig</literal> feature, which turns on any
+      "discretionary" ligatures in the font:
+    </para>
+    <programlisting language="C">
+      hb_feature_t userfeatures[1];
+      userfeatures[0].tag = HB_TAG('d','l','i','g');
+      userfeatures[0].value = 1;
+      userfeatures[0].start = HB_FEATURE_GLOBAL_START;
+      userfeatures[0].end = HB_FEATURE_GLOBAL_END;
+    </programlisting>
+    <para>
+      <literal>HB_FEATURE_GLOBAL_END</literal> and
+      <literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
+      to indicate that the features will be applied to the entire
+      buffer. We could also have used a literal <literal>0</literal>
+      for the start and a <literal>-1</literal> to indicate the end of
+      the buffer (or have selected other start and end positions, if needed).
+    </para>
+    <para>
+      When we pass the <varname>userfeatures</varname> array to
+      <function>hb_shape()</function>, any discretionary ligature
+      substitutions from our font that match the text in our buffer
+      will get performed:
+    </para>
+    <programlisting language="C">
+      hb_shape(font, buf, userfeatures, num_features);
+    </programlisting>
+    <para>
+      Just like we enabled the <literal>dlig</literal> feature by
+      setting its <parameter>value</parameter> to
+      <literal>1</literal>, you would disable a feature by setting its
+      <parameter>value</parameter> to <literal>0</literal>. Some
+      features can take other <parameter>value</parameter> settings;
+      be sure you read the full specification of each feature tag to
+      understand what it does and how to control it.
     </para>
   </section>
-  <section id="plans-and-caching">
+
+  <section id="shaping-shaper-selection">
+    <title>Shaper selection</title>
+    <para>
+      The basic version of <function>hb_shape()</function> determines
+      its shaping strategy based on examining the capabilities of the
+      font file. OpenType font tables cause HarfBuzz to try the
+      <literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
+      <literal>aat</literal> shaper. 
+    </para>
+    <para>
+      In the real world, however, a font might include some unusual
+      mix of tables, or one of the tables might simply be broken for
+      the script you need to shape. So, sometimes, you might not
+      want to rely on HarfBuzz's process for deciding what to do, and
+      just tell <function>hb_shape()</function> what you want it to try.
+    </para>
+    <para>
+      <function>hb_shape_full()</function> is an alternate shaping
+      function that lets you supply a list of shapers for HarfBuzz to
+      try, in order, when shaping your buffer. For example, if you
+      have determined that HarfBuzz's attempts to work around broken
+      tables gives you better results than the AAT shaper itself does,
+      you might move the AAT shaper to the end of your list of
+      preferences and call <function>hb_shape_full()</function>
+    </para>
+    <programlisting language="C">
+      char *shaperprefs[3] = {"ot", "default", "aat"};
+      ...
+      hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
+    </programlisting>
+    <para>
+      to get results you are happier with.
+    </para>
+    <para>
+      You may also want to call
+      <function>hb_shape_list_shapers()</function> to get a list of
+      the shapers that were built at compile time in your copy of HarfBuzz.
+    </para>
+  </section>
+  
+  <section id="shaping-plans-and-caching">
     <title>Plans and caching</title>
     <para>
+      Internally, HarfBuzz uses a structure called a shape plan to
+      track its decisions about how to shape the contents of a
+      buffer. The <function>hb_shape()</function> function builds up the shape plan by
+      examining segment properties and by inspecting the contents of
+      the font.
+    </para>
+    <para>
+      This process can involve some decision-making and
+      trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
+      lookups for the script and language tags set on the segment
+      properties, but it falls back on the lookups under the
+      <literal>DFLT</literal> tag (and sometimes other common tags)
+      if there are actually no lookups for the tag requested.
+    </para>
+    <para>
+      HarfBuzz also includes some work-arounds for
+      handling well-known older font conventions that do not follow
+      OpenType or Unicode specifications, for buggy system fonts, and for
+      peculiarities of Microsoft Uniscribe. All of that means that a
+      shape plan, while not something that you should edit directly in
+      client code, still might be an object that you want to
+      inspect. Furthermore, if resources are tight, you might want to
+      cache the shape plan that HarfBuzz builds for your buffer and
+      font, so that you do not have to rebuild it for every shaping call.
+    </para>
+    <para>
+      You can create a cacheable shape plan with
+      <function>hb_shape_plan_create_cached(face, props,
+      user_features, num_user_features, shaper_list)</function>, where
+      <parameter>face</parameter> is a face object (not a font object,
+      notably), <parameter>props</parameter> is an
+      <type>hb_segment_properties_t</type>,
+      <parameter>user_features</parameter> is an array of
+      <type>hb_feature_t</type>s (with length
+      <parameter>num_user_features</parameter>), and
+      <parameter>shaper_list</parameter> is a list of shapers to try.
+    </para>
+    <para>
+      Shape plans are objects in HarfBuzz, so there are
+      reference-counting functions and user-data attachment functions
+      you can
+      use. <function>hb_shape_plan_reference(shape_plan)</function>
+      increases the reference count on a shape plan, while
+      <function>hb_shape_plan_destroy(shape_plan)</function> decreases
+      the reference count, destroying the shape plan when the last
+      reference is dropped.
+    </para>
+    <para>
+      You can attach user data to a shaper (with a key) using the
+      <function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
+      function, optionally supplying a <function>destroy</function>
+      callback to use. You can then fetch the user data attached to a
+      shape plan with
+      <function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
     </para>
   </section>
+  
 </chapter>
diff --git a/docs/usermanual-shaping-concepts.xml b/docs/usermanual-shaping-concepts.xml
index bc9f1b8..db4e309 100644
--- a/docs/usermanual-shaping-concepts.xml
+++ b/docs/usermanual-shaping-concepts.xml
@@ -182,22 +182,23 @@
       Southeast Asian scripts are also assigned
       <emphasis>Unicode Indic Syllabic Category</emphasis> (UISC) and
       <emphasis>Unicode Indic Positional Category</emphasis> (UIPC)
-      property that provides more detailed information needed for
+      properties that provide more detailed information needed for
       shaping.
     </para>
     <para>
       The UISC property sub-categorizes Letters and Marks according to
       common script-shaping behaviors. For example, UISC distinguishes
       between consonant letters, vowel letters, and vowel marks. The
-      UIPC property sub-categorizes Mark codepoints by the visual
+      UIPC property sub-categorizes Mark codepoints by the relative visual
       position that they occupy (above, below, right, left, or in
       multiple positions).
     </para>
     <para>
       Some complex scripts require that the text run be split into
-      syllables, and what constitutes a valid syllable in these
-      scripts is specified in regular expressions of the Letter and
-      Mark codepoints that take the UISC and UIPC properties into account.
+      syllables. What constitutes a valid syllable in these
+      scripts is specified in regular expressions, formed from the
+      Letter and Mark codepoints, that take the UISC and UIPC
+      properties into account.
     </para>
 
   </section>
diff --git a/docs/usermanual-utilities.xml b/docs/usermanual-utilities.xml
new file mode 100644
index 0000000..1c5370c
--- /dev/null
+++ b/docs/usermanual-utilities.xml
@@ -0,0 +1,244 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<chapter id="utilities">
+  <title>Utilities</title>
+  <para>
+    HarfBuzz includes several auxiliary components in addition to the
+    main APIs. These include a set of command-line tools, a set of
+    lower-level APIs for common data types that may be of interest to
+    client programs, and an embedded library for working with
+    Unicode Character Database (UCD) data.
+  </para>
+  
+  <section id="utilities-command-line-tools">
+    <title>Command-line tools</title>
+    <para>
+      HarfBuzz include three command-line tools:
+      <program>hb-shape</program>, <program>hb-view</program>, and
+      <program>hb-subset</program>. They can be used to examine
+      HarfBuzz's functionality, debug font binaries, or explore the
+      various shaping models and features from a terminal.
+    </para>
+    
+    <section id="utilities-command-line-hbshape">
+      <title>hb-shape</title>
+      <para>
+	<emphasis><program>hb-shape</program></emphasis> allows you to run HarfBuzz's
+	<function>hb_shape()</function> function on an input string and
+	to examine the outcome, in human-readable form, as terminal
+	output. <program>hb-shape</program> does
+	<emphasis>not</emphasis> render the results of the shaping call
+	into rendered text (you can use <program>hb-view</program>, below, for
+	that). Instead, it prints out the final glyph indices and
+	positions, taking all shaping operations into account, as if the
+	input string were a HarfBuzz input buffer.
+      </para>
+      <para>
+	You can specify the font to be used for shaping and, with
+	command-line options, you can add various aspects of the
+	internal state to the output that is sent to the terminal. The
+	general format is
+      </para>
+      <programlisting>
+	<command>hb-shape</command> <optional>[OPTIONS]</optional>
+      <parameter>path/to/font/file.ttf</parameter>
+      <parameter>yourinputtext</parameter>
+      </programlisting>
+      <para>
+	The default output format is plain text (although JSON output
+	can be selected instead by specifying the option
+	<optional>--output-format=json</optional>). The default output
+	syntax reports each glyph name (or glyph index if there is no
+	name) followed by its cluster value, its horizontal and vertical
+	position displacement, and its horizontal and vertical advances.
+      </para>
+      <para>
+	Output options exist to skip any of these elements in the
+	output, and to include additional data, such as Unicode
+	code-point values, glyph extents, glyph flags, or interim
+	shaping results.
+      </para>
+      <para>
+	Output can also be redirected to a file, or input read from a
+	file. Additional options enable you to enable or disable
+	specific font features, to set variation-font axis values, to
+	alter the language, script, direction, and clustering settings
+	used, to enable sanity checks, or to change which shaping engine is used.
+      </para>
+      <para>
+	For a complete explanation of the options available, run
+      </para>
+      <programlisting>
+	<command>hb-shape</command> <parameter>--help</parameter>
+      </programlisting>  
+    </section>
+    
+    <section id="utilities-command-line-hbview">
+      <title>hb-view</title>
+      <para>
+	<emphasis><program>hb-view</program></emphasis> allows you to
+	see the shaped output of an input string in rendered
+	form. Like <program>hb-shape</program>,
+	<program>hb-view</program> takes a font file and a text string
+	as its arguments:
+      </para>
+      <programlisting>
+	<command>hb-view</command> <optional>[OPTIONS]</optional>
+	<parameter>path/to/font/file.ttf</parameter>
+	<parameter>yourinputtext</parameter>
+      </programlisting>
+      <para>
+	By default, <program>hb-view</program> renders the shaped
+	text in ASCII block-character images as terminal output. By
+	appending the
+	<command>--output-file=<optional>filename</optional></command>
+	switch, you can write the output to a PNG, SVG, or PDF file
+	(among other formats).
+      </para>
+      <para>
+	As with <program>hb-shape</program>, a lengthy set of options
+	is available, with which you can  enable or disable
+	specific font features, set variation-font axis values,
+	alter the language, script, direction, and clustering settings
+	used, enable sanity checks, or change which shaping engine is
+	used.
+      </para>
+      <para>
+	You can also set the foreground and background colors used for
+	the output, independently control the width of all four
+	margins, alter the line spacing, and annotate the output image
+	with 
+      </para>
+      <para>
+	In general, <program>hb-view</program> is a quick way to
+	verify that the output of HarfBuzz's shaping operation looks
+	correct for a given text-and-font combination, but you may
+	want to use <program>hb-shape</program> to figure out exactly
+	why something does not appear as expected.
+      </para>
+    </section>
+    
+    <section id="utilities-command-line-hbsubset">
+      <title>hb-subset</title>
+      <para>
+	<emphasis><program>hb-subset</program></emphasis> allows you
+	to generate a subset of a given font, with a limited set of
+	supported characters, features, and variation settings.
+      </para>
+      <para>
+	By default, you provide an input font and an input text string
+	as the arguments to <program>hb-subset</program>, and it will
+	generate a font that covers the input text exactly like the
+	input font does, but includes no other characters or features.
+      </para>
+      <programlisting>
+	<command>hb-subset</command> <optional>[OPTIONS]</optional>
+	<parameter>path/to/font/file.ttf</parameter>
+	<parameter>yourinputtext</parameter>
+      </programlisting>
+      <para>
+	For example, to create a subset of Noto Serif that just includes the
+	numerals and the lowercase Latin alphabet, you could run
+      </para>
+      <programlisting>
+	<command>hb-subset</command> <optional>[OPTIONS]</optional>
+	<parameter>NotoSerif-Regular.ttf</parameter>
+	<parameter>0123456789abcdefghijklmnopqrstuvwxyz</parameter>
+      </programlisting>
+      <para>
+	There are options available to remove hinting from the
+	subsetted font and to specify a list of variation-axis settings.
+      </para>
+    </section>
+    
+  </section>
+  
+  <section id="utilities-common-types-apis">
+    <title>Common data types and APIs</title>
+    <para>
+      HarfBuzz includes several APIs for working with general-purpose
+      data that you may find convenient to leverage in your own
+      software. They include set operations and integer-to-integer
+      mapping operations.
+    </para>
+    <para>
+      HarfBuzz uses set operations for internal bookkeeping, such as
+      when it collects all of the glyph IDs covered by a particular
+      font feature. You can also use the set API to build sets, add
+      and remove elements, test whether or not sets contain particular
+      elements, or compute the unions, intersections, or differences
+      between sets.
+    </para>
+    <para>
+      All set elements are integers (specifically,
+      <type>hb_codepoint_t</type> 32-bit unsigned ints), and there are
+      functions for fetching the minimum and maximum element from a
+      set. The set API also includes some functions that might not 
+      be part of a generic set facility, such as the ability to add a
+      contiguous range of integer elements to a set in bulk, and the
+      ability to fetch the next-smallest or next-largest element.
+    </para>
+    <para>
+      The HarfBuzz set API includes some conveniences as well. All
+      sets are lifecycle-managed, just like other HarfBuzz
+      objects. You increase the reference count on a set with
+      <function>hb_set_reference()</function> and decrease it with
+      <function>hb_set_destroy()</function>. You can also attach
+      user data to a set, just like you can to blobs, buffers, faces,
+      fonts, and other objects, and set destroy callbacks.
+    </para>
+    <para>
+      HarfBuzz also provides an API for keeping track of
+      integer-to-integer mappings. As with the set API, each integer is
+      stored as an unsigned 32-bit <type>hb_codepoint_t</type>
+      element. Maps, like other objects, are reference counted with
+      reference and destroy functions, and you can attach user data to
+      them. The mapping operations include adding and deleting
+      integer-to-integer key:value pairs to the map, testing for the
+      presence of a key, fetching the population of the map, and so on.
+    </para>
+    <para>
+      There are several other internal HarfBuzz facilities that are
+      exposed publicly and which you may want to take advantage of
+      while processing text. HarfBuzz uses a common
+      <type>hb_tag_t</type> for a variety of OpenType tag identifiers (for
+      scripts, languages, font features, table names, variation-axis
+      names, and more), and provides functions for converting strings
+      to tags and vice-versa. 
+    </para>
+    <para>
+      Finally, HarfBuzz also includes data type for Booleans, bit
+      masks, and other simple types.
+    </para>
+  </section>
+
+  <section id="utilities-ucdn">
+    <title>UCDN</title>
+    <para>
+      HarfBuzz includes a copy of the <ulink
+      url="https://github.com/grigorig/ucdn">UCDN</ulink> (Unicode
+      Database and Normalization) library, which provides functions
+      for accessing basic Unicode character properties, performing
+      canonical composition, and performing both canonical and
+      compatibility decomposition.
+    </para>
+    <para>
+      Currently, UCDN supports direct queries for several more character
+      properties than HarfBuzz's built-in set of Unicode functions
+      does, such as the BiDirectional Class, East Asian Width, Paired
+      Bracket and Resolved Linebreak properties. If you need to access
+      more properties than HarfBuzz's internal implementation
+      provides, using the built-in UCDN functions may be a useful solution.
+    </para>
+    <para>
+      The built-in UCDN functions are compiled by default when
+      building HarfBuzz from source, but this can be disabled with a
+      compile-time switch.
+    </para>
+  </section>
+
+</chapter>
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml
index 8532d7c..3513fb2 100644
--- a/docs/usermanual-what-is-harfbuzz.xml
+++ b/docs/usermanual-what-is-harfbuzz.xml
@@ -18,7 +18,7 @@
   <para>
     HarfBuzz can properly shape all of the world's major writing
     systems. It runs on all major operating systems and software
-    platforms and it supports the modern font formats in use
+    platforms and it supports the major font formats in use
     today.
   </para>
   <section id="what-is-text-shaping">
@@ -48,7 +48,8 @@
       url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>. The
     OpenType specification defines a series of <ulink url="https://github.com/n8willis/opentype-shaping-documents">shaping models</ulink> for
     various scripts from around the world. These shaping models depend on
-    the font including certain features in its <literal>GSUB</literal>
+    the font incorporating certain features as
+    <emphasis>lookups</emphasis> in its <literal>GSUB</literal> 
     and <literal>GPOS</literal> tables.
     </para>
     <para>
@@ -65,7 +66,7 @@
       Text strings will usually be tagged with a script and language
       tag that provide the context needed to perform text shaping
       correctly.  The necessary <ulink
-      url="https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags">Script</ulink> 
+      url="https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags">script</ulink> 
       and <ulink
       url="https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags">language</ulink>
       tags are defined by OpenType.
@@ -126,8 +127,8 @@
         <para>
           Many OpenType fonts contain ligatures: combinations of
           characters that are rendered as a single unit. For instance,
-	  it is common for the <literal>fi</literal> letter
-	  combination to appear in print as the single ligature glyph
+	  it is common for the &quot;f, i&quot; letter
+	  sequence to appear in print as the single ligature glyph
 	  &quot;fi&quot;.
 	</para>
 	<para>
@@ -150,9 +151,9 @@
         </para>
 	<para>
 	  For example, in Tamil, when the letter &quot;TTA&quot; (ட)
-	  letter is followed by &quot;U&quot; (உ), the pair
+	  letter is followed by the vowel sign &quot;U&quot; (ு), the pair
 	  must be replaced by the single glyph &quot;டு&quot;. The
-	  sequence of Unicode characters &quot;டஉ&quot; needs to be
+	  sequence of Unicode characters &quot;ட,ு&quot; needs to be
 	  substituted with a single &quot;டு&quot; glyph from the
 	  font.
 	</para>
diff --git a/mingw-configure.sh b/mingw-configure.sh
new file mode 100755
index 0000000..3281ce3
--- /dev/null
+++ b/mingw-configure.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+case $1 in
+	i686 | x86_64) ;;
+	*) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;;
+esac
+
+target=$1-w64-mingw32
+shift
+
+exec "$(dirname "$0")"/configure \
+	--build=`../config.guess` \
+	--host=$target \
+	--prefix=$HOME/.local/$target \
+	CC= \
+	CXX= \
+	CPP= \
+	LD= \
+	CFLAGS="-static-libgcc" \
+	CXXFLAGS="-static-libgcc -static-libstdc++" \
+	CPPFLAGS="-I$HOME/.local/$target/include" \
+	LDFLAGS=-L$HOME/.local/$target/lib \
+	PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
+	PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
+	PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
+	--without-icu \
+	--with-uniscribe \
+	"$@"
diff --git a/mingw-ldd.py b/mingw-ldd.py
new file mode 100755
index 0000000..1d659ef
--- /dev/null
+++ b/mingw-ldd.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
+# Modified to point to right prefix location on Fedora.
+
+# WTFPL - Do What the Fuck You Want to Public License
+from __future__ import print_function
+import pefile
+import os
+import sys
+
+
+def get_dependency(filename):
+    deps = []
+    pe = pefile.PE(filename)
+    for imp in pe.DIRECTORY_ENTRY_IMPORT:
+        deps.append(imp.dll.decode())
+    return deps
+
+
+def dep_tree(root, prefix=None):
+    if not prefix:
+        arch = get_arch(root)
+        #print('Arch =', arch)
+        prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
+        #print('Using default prefix', prefix)
+    dep_dlls = dict()
+
+    def dep_tree_impl(root, prefix):
+        for dll in get_dependency(root):
+            if dll in dep_dlls:
+                continue
+            full_path = os.path.join(prefix, dll)
+            if os.path.exists(full_path):
+                dep_dlls[dll] = full_path
+                dep_tree_impl(full_path, prefix=prefix)
+            else:
+                dep_dlls[dll] = 'not found'
+
+    dep_tree_impl(root, prefix)
+    return (dep_dlls)
+
+
+def get_arch(filename):
+    type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
+                pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
+    pe = pefile.PE(filename)
+    try:
+        return type2arch[pe.PE_TYPE]
+    except KeyError:
+        sys.stderr.write('Error: unknown architecture')
+        sys.exit(1)
+
+if __name__ == '__main__':
+    filename = sys.argv[1]
+    for dll, full_path in dep_tree(filename).items():
+        print(' ' * 7, dll, '=>', full_path)
+
diff --git a/mingw32.sh b/mingw32.sh
index 6774405..77edffa 100755
--- a/mingw32.sh
+++ b/mingw32.sh
@@ -1,22 +1,2 @@
-#!/bin/bash
-
-target=i686-w64-mingw32
-
-unset CC
-unset CXX
-unset CPP
-unset LD
-unset LDFLAGS
-unset CFLAGS
-unset CXXFLAGS
-unset PKG_CONFIG_PATH
-
-# Removed -static from the following
-export CFLAGS="-static-libgcc"
-export CXXFLAGS="-static-libgcc -static-libstdc++"
-export CPPFLAGS="-I$HOME/.local/$target/include -O2"
-export LDFLAGS=-L$HOME/.local/$target/lib
-export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
-export PATH=$HOME/.local/$target/bin:$PATH
-
-../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
+#!/bin/sh
+exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"
diff --git a/mingw64.sh b/mingw64.sh
index 49a1431..28724a4 100755
--- a/mingw64.sh
+++ b/mingw64.sh
@@ -1,22 +1,2 @@
-#!/bin/bash
-
-target=x86_64-w64-mingw32
-
-unset CC
-unset CXX
-unset CPP
-unset LD
-unset LDFLAGS
-unset CFLAGS
-unset CXXFLAGS
-unset PKG_CONFIG_PATH
-
-# Removed -static from the following
-export CFLAGS="-static-libgcc"
-export CXXFLAGS="-static-libgcc -static-libstdc++"
-export CPPFLAGS="-I$HOME/.local/$target/include -O2"
-export LDFLAGS=-L$HOME/.local/$target/lib
-export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
-export PATH=$HOME/.local/$target/bin:$PATH
-
-../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
+#!/bin/sh
+exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"
diff --git a/src/Makefile.am b/src/Makefile.am
index 3618d03..a76d968 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,9 +12,15 @@
 TESTS =
 check_PROGRAMS =
 
+EXTRA_DIST += harfbuzz.cc
+
 # Convenience targets:
 lib: $(BUILT_SOURCES) libharfbuzz.la
 libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
+tiny:
+	$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs
+tinyz:
+	$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs
 
 lib_LTLIBRARIES = libharfbuzz.la
 
@@ -28,10 +34,6 @@
 HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
 HBHEADERS = $(HB_BASE_headers)
 
-if HAVE_FALLBACK
-HBSOURCES += $(HB_FALLBACK_sources)
-endif
-
 if HAVE_PTHREAD
 HBCFLAGS += $(PTHREAD_CFLAGS)
 HBNONPCLIBS += $(PTHREAD_LIBS)
@@ -80,6 +82,13 @@
 HBHEADERS += $(HB_DIRECTWRITE_headers)
 endif
 
+if HAVE_GDI
+HBCFLAGS += $(GDI_CXXFLAGS)
+HBNONPCLIBS += $(GDI_LIBS)
+HBSOURCES += $(HB_GDI_sources)
+HBHEADERS += $(HB_GDI_headers)
+endif
+
 if HAVE_CORETEXT
 HBCFLAGS += $(CORETEXT_CFLAGS)
 HBNONPCLIBS += $(CORETEXT_LIBS)
@@ -87,17 +96,6 @@
 HBHEADERS += $(HB_CORETEXT_headers)
 endif
 
-if HAVE_UCDN
-SUBDIRS += hb-ucdn
-HBCFLAGS += -I$(srcdir)/hb-ucdn
-HBLIBS   += hb-ucdn/libhb-ucdn.la
-HBSOURCES += $(HB_UCDN_sources)
-hb-ucdn/libhb-ucdn.la: ucdn
-ucdn:
-	@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
-endif
-DIST_SUBDIRS += hb-ucdn
-
 
 BUILT_SOURCES += \
 	hb-version.h
@@ -258,36 +256,44 @@
 	gen-indic-table.py \
 	gen-os2-unicode-ranges.py \
 	gen-tag-table.py \
+	gen-ucd-table.py \
 	gen-use-table.py \
 	gen-vowel-constraints.py \
 	$(NULL)
 EXTRA_DIST += $(GENERATORS)
 
-unicode-tables: arabic-table indic-table tag-table use-table emoji-table
+unicode-tables: \
+	arabic-table \
+	emoji-table \
+	indic-table \
+	tag-table \
+	ucd-table \
+	use-table \
+	emoji-table \
+	$(NULL)
 
 arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
 	|| ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false)
-
+emoji-table: gen-emoji-table.py emoji-data.txt
+	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
+	|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
 indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
 	|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
-
 tag-table: gen-tag-table.py languagetags language-subtag-registry
 	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
 	|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
-
+ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
+	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \
+	|| ($(RM) $(srcdir)/hb-ucd-table.hh; false)
 use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
 	|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
-
 vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt
 	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
 	|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
 
-emoji-table: gen-emoji-table.py emoji-data.txt
-	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
-	|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
 
 built-sources: $(BUILT_SOURCES)
 
@@ -306,13 +312,30 @@
 	$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
 	|| ($(RM) "$@"; false)
 
+harfbuzz.cc: Makefile.sources
+	$(AM_V_GEN) \
+	for f in \
+		$(HB_BASE_sources) \
+		$(HB_GLIB_sources) \
+		$(HB_FT_sources) \
+		$(HB_GRAPHITE2_sources) \
+		$(HB_UNISCRIBE_sources) \
+		$(HB_GDI_sources) \
+		$(HB_DIRECTWRITE_sources) \
+		$(HB_CORETEXT_sources) \
+		; do echo '#include "'$$f'"'; done | \
+	grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
+	|| ($(RM) $(srcdir)/harfbuzz.cc; false)
+BUILT_SOURCES += harfbuzz.cc
+
 noinst_PROGRAMS = \
 	main \
 	test \
 	test-buffer-serialize \
-	test-name-table \
-	test-size-params \
-	test-would-substitute \
+	test-ot-meta \
+	test-ot-name \
+	test-gpos-size-params \
+	test-gsub-would-substitute \
 	$(NULL)
 bin_PROGRAMS =
 
@@ -328,17 +351,21 @@
 test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
 test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_name_table_SOURCES = test-name-table.cc
-test_name_table_CPPFLAGS = $(HBCFLAGS)
-test_name_table_LDADD = libharfbuzz.la $(HBLIBS)
+test_ot_meta_SOURCES = test-ot-meta.cc
+test_ot_meta_CPPFLAGS = $(HBCFLAGS)
+test_ot_meta_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_size_params_SOURCES = test-size-params.cc
-test_size_params_CPPFLAGS = $(HBCFLAGS)
-test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+test_ot_name_SOURCES = test-ot-name.cc
+test_ot_name_CPPFLAGS = $(HBCFLAGS)
+test_ot_name_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_would_substitute_SOURCES = test-would-substitute.cc
-test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
-test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+test_gpos_size_params_SOURCES = test-gpos-size-params.cc
+test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
+test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+
+test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
+test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
 
 if HAVE_FREETYPE
 if HAVE_CAIRO_FT
@@ -384,15 +411,39 @@
 dump_use_data_CPPFLAGS = $(HBCFLAGS)
 dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
 
-check_PROGRAMS += test-ot-tag test-unicode-ranges
-TESTS += test-ot-tag test-unicode-ranges
+COMPILED_TESTS = test-algs test-iter test-meta test-number test-ot-tag test-unicode-ranges test-bimap
+COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
+COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
+check_PROGRAMS += $(COMPILED_TESTS)
+TESTS += $(COMPILED_TESTS)
+
+test_algs_SOURCES = test-algs.cc hb-static.cc
+test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_algs_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_iter_SOURCES = test-iter.cc hb-static.cc
+test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_iter_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_meta_SOURCES = test-meta.cc hb-static.cc
+test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_meta_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_number_SOURCES = test-number.cc hb-number.cc
+test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_number_LDADD = $(COMPILED_TESTS_LDADD)
 
 test_ot_tag_SOURCES = hb-ot-tag.cc
-test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
-test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
+test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
 
 test_unicode_ranges_SOURCES = test-unicode-ranges.cc
-test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS)
+test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
+
+test_bimap_SOURCES = test-bimap.cc hb-static.cc
+test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
+test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
 
 TESTS_ENVIRONMENT = \
 	srcdir="$(srcdir)" \
@@ -422,6 +473,7 @@
 	-DHB_AAT_H_IN \
 	-DHB_GOBJECT_H \
 	-DHB_GOBJECT_H_IN \
+	-DHAVE_GOBJECT \
 	-DHB_EXTERN= \
 	$(NULL)
 HarfBuzz_0_0_gir_LIBS = \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 98b6228..cbbad90 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -10,12 +10,14 @@
 	hb-aat-layout-kerx-table.hh \
 	hb-aat-layout-lcar-table.hh \
 	hb-aat-layout-morx-table.hh \
+	hb-aat-layout-opbd-table.hh \
 	hb-aat-layout-trak-table.hh \
 	hb-aat-layout.cc \
 	hb-aat-layout.hh \
 	hb-aat-ltag-table.hh \
 	hb-aat-map.cc \
 	hb-aat-map.hh \
+	hb-algs.hh \
 	hb-array.hh \
 	hb-atomic.hh \
 	hb-blob.cc \
@@ -30,18 +32,25 @@
 	hb-cff1-interp-cs.hh \
 	hb-cff2-interp-cs.hh \
 	hb-common.cc \
+	hb-config.hh \
 	hb-debug.hh \
-	hb-dsalgs.hh \
+	hb-dispatch.hh \
 	hb-face.cc \
 	hb-face.hh \
+	hb-fallback-shape.cc \
 	hb-font.cc \
 	hb-font.hh \
+	hb-iter.hh \
 	hb-kern.hh \
 	hb-machinery.hh \
 	hb-map.cc \
 	hb-map.hh \
+	hb-bimap.hh \
+	hb-meta.hh \
 	hb-mutex.hh \
 	hb-null.hh \
+	hb-number.cc \
+	hb-number.hh \
 	hb-object.hh \
 	hb-open-file.hh \
 	hb-open-type.hh \
@@ -59,6 +68,7 @@
 	hb-ot-color.cc \
 	hb-ot-face.cc \
 	hb-ot-face.hh \
+	hb-ot-face-table-list.hh \
 	hb-ot-font.cc \
 	hb-ot-gasp-table.hh \
 	hb-ot-glyf-table.hh \
@@ -81,7 +91,11 @@
 	hb-ot-math-table.hh \
 	hb-ot-math.cc \
 	hb-ot-maxp-table.hh \
-	hb-ot-name-language.cc \
+	hb-ot-meta-table.hh \
+	hb-ot-meta.cc \
+	hb-ot-metrics.cc \
+	hb-ot-metrics.hh \
+	hb-ot-name-language-static.hh \
 	hb-ot-name-language.hh \
 	hb-ot-name-table.hh \
 	hb-ot-name.cc \
@@ -122,10 +136,14 @@
 	hb-ot-tag.cc \
 	hb-ot-var-avar-table.hh \
 	hb-ot-var-fvar-table.hh \
+	hb-ot-var-gvar-table.hh \
 	hb-ot-var-hvar-table.hh \
 	hb-ot-var-mvar-table.hh \
 	hb-ot-var.cc \
 	hb-ot-vorg-table.hh \
+	hb-pool.hh \
+	hb-sanitize.hh \
+	hb-serialize.hh \
 	hb-set-digest.hh \
 	hb-set.cc \
 	hb-set.hh \
@@ -138,18 +156,20 @@
 	hb-shaper.hh \
 	hb-static.cc \
 	hb-string-array.hh \
+	hb-ucd-table.hh \
+	hb-ucd.cc \
 	hb-unicode-emoji-table.hh \
 	hb-unicode.cc \
 	hb-unicode.hh \
 	hb-utf.hh \
 	hb-vector.hh \
-	hb-warning.cc \
 	hb.hh \
 	$(NULL)
 
 HB_BASE_RAGEL_GENERATED_sources = \
 	hb-buffer-deserialize-json.hh \
 	hb-buffer-deserialize-text.hh \
+	hb-number-parser.hh \
 	hb-ot-shape-complex-indic-machine.hh \
 	hb-ot-shape-complex-khmer-machine.hh \
 	hb-ot-shape-complex-myanmar-machine.hh \
@@ -158,6 +178,7 @@
 HB_BASE_RAGEL_sources = \
 	hb-buffer-deserialize-json.rl \
 	hb-buffer-deserialize-text.rl \
+	hb-number-parser.rl \
 	hb-ot-shape-complex-indic-machine.rl \
 	hb-ot-shape-complex-khmer-machine.rl \
 	hb-ot-shape-complex-myanmar-machine.rl \
@@ -179,6 +200,8 @@
 	hb-ot-font.h \
 	hb-ot-layout.h \
 	hb-ot-math.h \
+	hb-ot-meta.h \
+	hb-ot-metrics.h \
 	hb-ot-name.h \
 	hb-ot-shape.h \
 	hb-ot-var.h \
@@ -191,10 +214,6 @@
 	hb.h \
 	$(NULL)
 
-HB_FALLBACK_sources = \
-	hb-fallback-shape.cc	\
-	$(NULL)
-
 # Optional Sources and Headers with external deps
 
 HB_FT_sources = hb-ft.cc
@@ -214,18 +233,20 @@
 HB_DIRECTWRITE_sources = hb-directwrite.cc
 HB_DIRECTWRITE_headers = hb-directwrite.h
 
+HB_GDI_sources = hb-gdi.cc
+HB_GDI_headers = hb-gdi.h
+
 HB_UNISCRIBE_sources = hb-uniscribe.cc
 HB_UNISCRIBE_headers = hb-uniscribe.h
 
-# Additional supplemental sources
-HB_UCDN_sources  = hb-ucdn.cc
-
 # Sources for libharfbuzz-gobject and libharfbuzz-icu
 HB_ICU_sources = hb-icu.cc
 HB_ICU_headers = hb-icu.h
 
 # Sources for libharfbuzz-subset
 HB_SUBSET_sources = \
+	hb-number.cc \
+	hb-number.hh \
 	hb-ot-cff1-table.cc \
 	hb-ot-cff2-table.cc \
 	hb-static.cc \
@@ -235,9 +256,6 @@
 	hb-subset-cff1.hh \
 	hb-subset-cff2.cc \
 	hb-subset-cff2.hh \
-	hb-subset-glyf.cc \
-	hb-subset-glyf.hh \
-	hb-subset-glyf.hh \
 	hb-subset-input.cc \
 	hb-subset-input.hh \
 	hb-subset-plan.cc \
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
index cea8684..f181b63 100755
--- a/src/check-symbols.sh
+++ b/src/check-symbols.sh
@@ -7,7 +7,7 @@
 test -z "$libs" && libs=.libs
 stat=0
 
-IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_flush\|llvm_.*'
+IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*'
 
 if which nm 2>/dev/null >/dev/null; then
 	:
@@ -26,7 +26,7 @@
 		symprefix=
 		if test $suffix = dylib; then symprefix=_; fi
 
-		EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
+		EXPORTED_SYMBOLS=`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`
 
 		prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
 
diff --git a/src/dev-run.sh b/src/dev-run.sh
deleted file mode 100755
index 82de688..0000000
--- a/src/dev-run.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/bash
-# Suggested setup to use the script:
-#  (on the root of the project)
-#  $ NOCONFIGURE=1 ./autogen.sh && mkdir build && cd build
-#  $ ../configure --with-freetype --with-glib --with-gobject --with-cairo
-#  $ make -j5 && cd ..
-#  $ src/dev-run.sh [FONT-FILE] [TEXT]
-#
-# Or, using cmake:
-#  $ cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild
-#  $ src/dev-run.sh [FONT-FILE] [TEXT]
-#
-# If you want to open the result rendering using a GUI app,
-#  $ src/dev-run.sh open [FONT-FILE] [TEXT]
-#
-# And if you are using iTerm2, you can use the script like this,
-#  $ src/dev-run.sh img [FONT-FILE] [TEXT]
-#
-
-[ $# = 0 ] && echo Usage: "src/dev-run.sh [FONT-FILE] [TEXT]" && exit
-command -v entr >/dev/null 2>&1 || { echo >&2 "This script needs `entr` be installed"; exit 1; }
-
-
-GDB=gdb
-# if gdb doesn't exist, hopefully lldb exist
-command -v $GDB >/dev/null 2>&1 || export GDB="lldb"
-
-
-[ $1 = "open" ] && openimg=1 && shift
-OPEN=xdg-open
-[ "$(uname)" == "Darwin" ] && OPEN=open
-
-
-[ $1 = "img" ] && img=1 && shift
-# http://iterm2.com/documentation-images.html
-osc="\033]"
-if [[ $TERM == screen* ]]; then osc="\033Ptmux;\033\033]"; fi
-st="\a"
-if [[ $TERM == screen* ]]; then st="\a"; fi
-
-
-tmp=tmp.png
-[ -f 'build/build.ninja' ] && CMAKENINJA=TRUE
-# or "fswatch -0 . -e build/ -e .git"
-find src/ | entr printf '\0' | while read -d ""; do
-	clear
-	yes = | head -n`tput cols` | tr -d '\n'
-	if [[ $CMAKENINJA ]]; then
-		ninja -Cbuild hb-shape hb-view && {
-			build/hb-shape $@
-			if [ $openimg ]; then
-				build/hb-view $@ -O png -o $tmp
-				$OPEN $tmp
-			elif [ $img ]; then
-				build/hb-view $@ -O png -o $tmp
-				printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n"
-			else
-				build/hb-view $@
-			fi
-		}
-	else
-		make -Cbuild/src -j5 -s lib && {
-			build/util/hb-shape $@
-			if [ $openimg ]; then
-				build/util/hb-view $@ -O png -o $tmp
-				$OPEN $tmp
-			elif [ $img ]; then
-				build/util/hb-view $@ -O png -o $tmp
-				printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n"
-			else
-				build/util/hb-view $@
-			fi
-		}
-	fi
-done
-
-read -n 1 -p "[C]heck, [D]ebug, [R]estart, [Q]uit? " answer
-case "$answer" in
-c|C )
-	if [[ $CMAKENINJA ]]; then
-		CTEST_OUTPUT_ON_FAILURE=1 CTEST_PARALLEL_LEVEL=5 ninja -Cbuild test
-	else
-		make -Cbuild -j5 check && .ci/fail.sh
-	fi
-;;
-d|D )
-	if [[ $CMAKENINJA ]]; then
-		echo "Not supported on cmake builds yet"
-	else
-		build/libtool --mode=execute $GDB -- build/util/hb-shape $@
-	fi
-;;
-r|R )
-	src/dev-run.sh $@
-;;
-* )
-	exit
-;;
-esac
diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py
index 9afe747..49770d4 100755
--- a/src/gen-emoji-table.py
+++ b/src/gen-emoji-table.py
@@ -4,6 +4,7 @@
 import sys
 import os.path
 from collections import OrderedDict
+import packTab
 
 if len (sys.argv) != 2:
 	print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
@@ -52,14 +53,19 @@
 print ('#include "hb-unicode.hh"')
 print ()
 
-for typ,s in ranges.items():
+for typ, s in ranges.items():
 	if typ != "Extended_Pictographic": continue
+
+	arr = dict()
+	for start,end in s:
+		for i in range(start,end):
+			arr[i] = 1
+
+	sol = packTab.pack_table(arr, 0, compression=3)
+	code = packTab.Code('_hb_emoji')
+	sol.genCode(code, 'is_'+typ)
+	code.print_c(linkage='static inline')
 	print()
-	print("static const struct hb_unicode_range_t _hb_unicode_emoji_%s_table[] =" % typ)
-	print("{")
-	for pair in sorted(s):
-		print("  {0x%04X, 0x%04X}," % pair)
-	print("};")
 
 print ()
 print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index e65b981..912b1d7 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -79,10 +79,6 @@
 del combined
 num = len (data)
 
-for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
-	if data[u][0] == 'Other':
-		data[u][0] = "Vowel_Dependent"
-
 # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
 singles = {}
 for u in ALLOWED_SINGLES:
@@ -102,6 +98,10 @@
 		print (" * %s" % (l.strip()))
 print (" */")
 print ()
+print ('#include "hb.hh"')
+print ()
+print ('#ifndef HB_NO_OT_SHAPE')
+print ()
 print ('#include "hb-ot-shape-complex-indic.hh"')
 print ()
 
@@ -131,8 +131,10 @@
 
 what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
 what_short = ["ISC", "IMC"]
+print ('#pragma GCC diagnostic push')
+print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
+cat_defs = []
 for i in range (2):
-	print ()
 	vv = sorted (values[i].keys ())
 	for v in vv:
 		v_no_and = v.replace ('_And_', '_')
@@ -144,10 +146,18 @@
 				raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
 			all_shorts[i][s] = v
 			short[i][v] = s
-		print ("#define %s_%s	%s_%s	%s/* %3d chars; %s */" %
-			(what_short[i], s, what[i], v.upper (),
-			'	'* ((48-1 - len (what[i]) - 1 - len (v)) // 8),
-			values[i][v], v))
+		cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + v.upper (), str (values[i][v]), v))
+
+maxlen_s = max ([len (c[0]) for c in cat_defs])
+maxlen_l = max ([len (c[1]) for c in cat_defs])
+maxlen_n = max ([len (c[2]) for c in cat_defs])
+for s in what_short:
+	print ()
+	for c in [c for c in cat_defs if s in c[0]]:
+		print ("#define %s %s /* %s chars; %s */" %
+			(c[0].ljust (maxlen_s), c[1].ljust (maxlen_l), c[2].rjust (maxlen_n), c[3]))
+print ()
+print ('#pragma GCC diagnostic pop')
 print ()
 print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
 print ()
@@ -246,12 +256,14 @@
 print ()
 print ("#undef _")
 for i in range (2):
-	print
+	print ()
 	vv = sorted (values[i].keys ())
 	for v in vv:
 		print ("#undef %s_%s" %
 			(what_short[i], short[i][v]))
 print ()
+print ('#endif')
+print ()
 print ("/* == End of generated table == */")
 
 # Maintain at least 30% occupancy in the table */
diff --git a/src/gen-os2-unicode-ranges.py b/src/gen-os2-unicode-ranges.py
old mode 100644
new mode 100755
index d768313..515f4ca
--- a/src/gen-os2-unicode-ranges.py
+++ b/src/gen-os2-unicode-ranges.py
@@ -1,8 +1,10 @@
+#!/usr/bin/python
+
 # -*- coding: utf-8 -*-
 
 # Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
 # Input is a tab seperated list of unicode ranges from the otspec
-# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1).
+# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
 
 from __future__ import print_function, division, absolute_import
 
@@ -10,8 +12,11 @@
 import re
 import sys
 
-reload(sys)
-sys.setdefaultencoding('utf-8')
+try:
+  reload(sys)
+  sys.setdefaultencoding('utf-8')
+except NameError:
+  pass  # Python 3
 
 print ("""static OS2Range _hb_os2_unicode_ranges[] =
 {""")
@@ -32,12 +37,12 @@
       current_bit = fields[0]
       fields = fields[1:]
     elif len(fields) > 3:
-      raise Error("bad input :(.")
+      raise Exception("bad input :(.")
 
     name = fields[0]
     ranges = re.split("-", fields[1])
     if len(ranges) != 2:
-      raise Error("bad input :(.")
+      raise Exception("bad input :(.")
 
     v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name))
     all_ranges.append(v)
diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py
index 1300462..49f5b30 100755
--- a/src/gen-tag-table.py
+++ b/src/gen-tag-table.py
@@ -895,20 +895,18 @@
 def get_matching_language_name (intersection, candidates):
 	return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c))))
 
-maximum_tags = 0
+def same_tag (bcp_47_tag, ot_tags):
+	return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
+
 for language, tags in sorted (ot.from_bcp_47.items ()):
 	if language == '' or '-' in language:
 		continue
-	print ('  {\"%s\",\t{' % language, end='')
-	maximum_tags = max (maximum_tags, len (tags))
-	tag_count = len (tags)
+	commented_out = same_tag (language, tags)
 	for i, tag in enumerate (tags, start=1):
-		if i > 1:
-			print ('\t\t ', end='')
-		print (hb_tag (tag), end='')
-		if i == tag_count:
-			print ('}}', end='')
-		print (',\t/* ', end='')
+		print ('%s{\"%s\",\t%s},' % ('/*' if commented_out else '  ', language, hb_tag (tag)), end='')
+		if commented_out:
+			print ('*/', end='')
+		print ('\t/* ', end='')
 		bcp_47_name = bcp_47.names.get (language, '')
 		bcp_47_name_candidates = bcp_47_name.split ('\n')
 		intersection = language_name_intersection (bcp_47_name, ot.names[tag])
@@ -923,8 +921,6 @@
 
 print ('};')
 print ()
-print ('static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == %iu, "");' % maximum_tags)
-print ()
 
 print ('/**')
 print (' * hb_ot_tags_from_complex_language:')
@@ -1051,7 +1047,8 @@
 print (' *')
 print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to')
 print (' * many language tags) and the best tag is not the alphabetically first, or if')
-print (' * the best tag consists of multiple subtags.')
+print (' * the best tag consists of multiple subtags, or if the best tag does not appear')
+print (' * in #ot_languages.')
 print (' *')
 print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
 print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
@@ -1102,7 +1099,8 @@
 						'%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
 			elif ot_tag not in disambiguation:
 				disambiguation[ot_tag] = macrolanguages[0]
-			if disambiguation[ot_tag] == sorted (primary_tags)[0] and '-' not in disambiguation[ot_tag]:
+			different_primary_tags = sorted (t for t in primary_tags if not same_tag (t, ot.from_bcp_47.get (t)))
+			if different_primary_tags and disambiguation[ot_tag] == different_primary_tags[0] and '-' not in disambiguation[ot_tag]:
 				del disambiguation[ot_tag]
 	for ot_tag in disambiguation.keys ():
 		expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
diff --git a/src/gen-ucd-table.py b/src/gen-ucd-table.py
new file mode 100755
index 0000000..552c3c6
--- /dev/null
+++ b/src/gen-ucd-table.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+
+from __future__ import print_function, division, absolute_import
+
+import io, os.path, sys, re
+import logging
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+
+if len (sys.argv) not in (2, 3):
+	print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]", file=sys.stderr)
+	sys.exit(1)
+
+# https://github.com/harfbuzz/packtab
+import packTab
+import packTab.ucdxml
+
+logging.info('Loading UCDXML...')
+ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
+ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
+
+hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
+
+logging.info('Preparing data tables...')
+
+gc = [u['gc'] for u in ucd]
+ccc = [int(u['ccc']) for u in ucd]
+bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
+#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
+#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)
+
+sc = [u['sc'] for u in ucd]
+
+dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
+      if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
+ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
+
+assert not any(v for v in dm.values() if len(v) not in (1,2))
+dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
+assert all((v[0] >> 16) in (0,2) for v in dm1)
+dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
+dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
+dm1_order = {v:i+1 for i,v in enumerate(dm1)}
+
+dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
+             for i,v in dm.items() if len(v) == 2)
+
+filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
+                  (v[1] & 0xFFFFFF80) == 0x0300 and
+                  (v[2] & 0xFFF0C000) == 0x0000)
+dm2_u32_array = [v for v in dm2 if filt(v[0])]
+dm2_u64_array = [v for v in dm2 if not filt(v[0])]
+assert dm2_u32_array + dm2_u64_array == dm2
+dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
+dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]
+
+l = 1 + len(dm1_p0_array) + len(dm1_p2_array)
+dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
+
+dm_order = {None: 0}
+dm_order.update(dm1_order)
+dm_order.update(dm2_order)
+
+gc_order = dict()
+for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
+                      'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
+                      'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',)):
+    gc_order[i] = v
+    gc_order[v] = i
+
+sc_order = dict()
+sc_array = []
+sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
+for line in open(hb_common_h):
+    m = sc_re.search (line)
+    if not m: continue
+    name = m.group(1)
+    tag = ''.join(m.group(i) for i in range(2, 6))
+    i = len(sc_array)
+    sc_order[tag] = i
+    sc_order[i] = tag
+    sc_array.append(name)
+
+DEFAULT = 1
+COMPACT = 3
+SLOPPY  = 5
+
+
+logging.info('Generating output...')
+print("/* == Start of generated table == */")
+print("/*")
+print(" * The following table is generated by running:")
+print(" *")
+print(" *   ./gen-ucd-table.py ucd.nounihan.grouped.xml")
+print(" *")
+print(" * on file with this description:", ucdxml.description)
+print(" */")
+print()
+print("#ifndef HB_UCD_TABLE_HH")
+print("#define HB_UCD_TABLE_HH")
+print()
+print('#include "hb.hh"')
+print()
+
+code = packTab.Code('_hb_ucd')
+sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
+dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
+dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
+dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
+dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
+code.print_c(linkage='static inline')
+
+datasets = [
+    ('gc', gc, 'Cn', gc_order),
+    ('ccc', ccc, 0, None),
+    ('bmg', bmg, 0, None),
+    ('sc', sc, 'Zzzz', sc_order),
+    ('dm', dm, None, dm_order),
+]
+
+for compression in (DEFAULT, COMPACT, SLOPPY):
+    logging.info('  Compression=%d:' % compression)
+    print()
+    if compression == DEFAULT:
+        print('#ifndef HB_OPTIMIZE_SIZE')
+    elif compression == COMPACT:
+        print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
+    else:
+        print('#else')
+    print()
+
+    if compression == SLOPPY:
+        for i in range(len(gc)):
+            if (i % 128) and gc[i] == 'Cn':
+                gc[i] = gc[i - 1]
+        for i in range(len(gc) - 2, -1, -1):
+            if ((i + 1) % 128) and gc[i] == 'Cn':
+                gc[i] = gc[i + 1]
+        for i in range(len(sc)):
+            if (i % 128) and sc[i] == 'Zzzz':
+                sc[i] = sc[i - 1]
+        for i in range(len(sc) - 2, -1, -1):
+            if ((i + 1) % 128) and sc[i] == 'Zzzz':
+                sc[i] = sc[i + 1]
+
+
+    code = packTab.Code('_hb_ucd')
+
+    for name,data,default,mapping in datasets:
+        sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
+        logging.info('      Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
+        sol.genCode(code, name)
+
+    code.print_c(linkage='static inline')
+
+    print()
+
+print('#endif')
+print()
+
+print()
+print("#endif /* HB_UCD_TABLE_HH */")
+print()
+print("/* == End of generated table == */")
+logging.info('Done.')
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index 099f6a1..4523fb8 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -1,8 +1,10 @@
 #!/usr/bin/env python
+# flake8: noqa
 
 from __future__ import print_function, division, absolute_import
 
-import io, sys
+import io
+import sys
 
 if len (sys.argv) != 5:
 	print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
@@ -45,9 +47,22 @@
 
 # TODO Characters that are not in Unicode Indic files, but used in USE
 data[0][0x034F] = defaults[0]
+data[0][0x1B61] = defaults[0]
+data[0][0x1B63] = defaults[0]
+data[0][0x1B64] = defaults[0]
+data[0][0x1B65] = defaults[0]
+data[0][0x1B66] = defaults[0]
+data[0][0x1B67] = defaults[0]
+data[0][0x1B69] = defaults[0]
+data[0][0x1B6A] = defaults[0]
 data[0][0x2060] = defaults[0]
-data[0][0x20F0] = defaults[0]
-# TODO https://github.com/roozbehp/unicode-data/issues/9
+# TODO https://github.com/harfbuzz/harfbuzz/pull/1685
+data[0][0x1B5B] = 'Consonant_Placeholder'
+data[0][0x1B5C] = 'Consonant_Placeholder'
+data[0][0x1B5F] = 'Consonant_Placeholder'
+data[0][0x1B62] = 'Consonant_Placeholder'
+data[0][0x1B68] = 'Consonant_Placeholder'
+# TODO https://github.com/harfbuzz/harfbuzz/issues/1035
 data[0][0x11C44] = 'Consonant_Placeholder'
 data[0][0x11C45] = 'Consonant_Placeholder'
 # TODO https://github.com/harfbuzz/harfbuzz/pull/1399
@@ -170,7 +185,7 @@
 def is_BASE_IND(U, UISC, UGC):
 	#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
 	return (UISC in [Consonant_Dead, Modifying_Letter] or
-		(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
+		(UGC == Po and not U in [0x104B, 0x104E, 0x1B5B, 0x1B5C, 0x1B5F, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
 		False # SPEC-DRAFT-OUTDATED! U == 0x002D
 		)
 def is_BASE_NUM(U, UISC, UGC):
@@ -182,15 +197,15 @@
 def is_CGJ(U, UISC, UGC):
 	return U == 0x034F
 def is_CONS_FINAL(U, UISC, UGC):
-	# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
 	return ((UISC == Consonant_Final and UGC != Lo) or
-		UISC == Consonant_Initial_Postfixed or
 		UISC == Consonant_Succeeding_Repha)
 def is_CONS_FINAL_MOD(U, UISC, UGC):
 	#SPEC-DRAFT return  UISC in [Consonant_Final_Modifier, Syllable_Modifier]
 	return  UISC == Syllable_Modifier
 def is_CONS_MED(U, UISC, UGC):
-	return UISC == Consonant_Medial and UGC != Lo
+	# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
+	return (UISC == Consonant_Medial and UGC != Lo or
+		UISC == Consonant_Initial_Postfixed)
 def is_CONS_MOD(U, UISC, UGC):
 	return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
 def is_CONS_SUB(U, UISC, UGC):
@@ -199,7 +214,9 @@
 def is_CONS_WITH_STACKER(U, UISC, UGC):
 	return UISC == Consonant_With_Stacker
 def is_HALANT(U, UISC, UGC):
-	return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
+	return (UISC in [Virama, Invisible_Stacker]
+		and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
+		and not is_SAKOT(U, UISC, UGC))
 def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
 	# https://github.com/harfbuzz/harfbuzz/issues/1102
 	# https://github.com/harfbuzz/harfbuzz/issues/1379
@@ -215,6 +232,7 @@
 def is_OTHER(U, UISC, UGC):
 	#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
 	return (UISC == Other
+		and not is_SYM(U, UISC, UGC)
 		and not is_SYM_MOD(U, UISC, UGC)
 		and not is_CGJ(U, UISC, UGC)
 		and not is_Word_Joiner(U, UISC, UGC)
@@ -224,20 +242,22 @@
 	return UGC == 'Cn'
 def is_REPHA(U, UISC, UGC):
 	return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
+def is_SAKOT(U, UISC, UGC):
+	return U == 0x1A60
 def is_SYM(U, UISC, UGC):
 	if U == 0x25CC: return False #SPEC-DRAFT
 	#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
-	return UGC in [So, Sc]
+	return UGC in [So, Sc] and U not in [0x1B62, 0x1B68]
 def is_SYM_MOD(U, UISC, UGC):
 	return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
 def is_VARIATION_SELECTOR(U, UISC, UGC):
 	return 0xFE00 <= U <= 0xFE0F
 def is_VOWEL(U, UISC, UGC):
-	# https://github.com/roozbehp/unicode-data/issues/6
+	# https://github.com/harfbuzz/harfbuzz/issues/376
 	return (UISC == Pure_Killer or
 		(UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
 def is_VOWEL_MOD(U, UISC, UGC):
-	# https://github.com/roozbehp/unicode-data/issues/6
+	# https://github.com/harfbuzz/harfbuzz/issues/376
 	return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
 		(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
 
@@ -263,6 +283,7 @@
 	'Rsv':	is_Reserved,
 	'R':	is_REPHA,
 	'S':	is_SYM,
+	'Sk':	is_SAKOT,
 	'SM':	is_SYM_MOD,
 	'VS':	is_VARIATION_SELECTOR,
 	'V':	is_VOWEL,
@@ -304,7 +325,11 @@
 	'H': None,
 	'HVM': None,
 	'B': None,
-	'FM': None,
+	'FM': {
+		'Abv': [Top],
+		'Blw': [Bottom],
+		'Pst': [Not_Applicable],
+	},
 	'SUB': None,
 }
 
@@ -315,12 +340,11 @@
 
 		# Resolve Indic_Syllabic_Category
 
-		# TODO: These don't have UISC assigned in Unicode 8.0, but have UIPC
-		if U == 0x17DD: UISC = Vowel_Dependent
+		# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
 		if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
 
 		# Tibetan:
-		# TODO: These don't have UISC assigned in Unicode 11.0, but have UIPC
+		# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
 		if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
 		if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark
 		# Overrides to allow NFC order matching syllable
@@ -344,48 +368,31 @@
 		# the nasalization marks, maybe only for U+1CE9..U+1CF1.
 		if U == 0x1CED: UISC = Tone_Mark
 
-		# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
-		if U == 0x1A7F: UISC = Consonant_Final; UIPC = Bottom
-
-		# TODO: https://github.com/harfbuzz/harfbuzz/pull/609
-		if U == 0x20F0: UISC = Cantillation_Mark; UIPC = Top
-
-		# TODO: https://github.com/harfbuzz/harfbuzz/pull/626
-		if U == 0xA8B4: UISC = Consonant_Medial
-
 		# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
 		if U == 0x11134: UISC = Gemination_Mark
 
-		# TODO: https://github.com/harfbuzz/harfbuzz/pull/1399
-		if U == 0x111C9: UISC = Consonant_Final
-
 		values = [k for k,v in items if v(U,UISC,UGC)]
 		assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
 		USE = values[0]
 
 		# Resolve Indic_Positional_Category
 
-		# TODO: Not in Unicode 8.0 yet, but in spec.
-		if U == 0x1B6C: UIPC = Bottom
-
-		# TODO: These should die, but have UIPC in Unicode 8.0
+		# TODO: These should die, but have UIPC in Unicode 12.0
 		if U in [0x953, 0x954]: UIPC = Not_Applicable
 
-		# TODO: In USE's override list but not in Unicode 11.0
+		# TODO: In USE's override list but not in Unicode 12.0
 		if U == 0x103C: UIPC = Left
 
-		# TODO: These are not in USE's override list that we have, nor are they in Unicode 11.0
+		# TODO: https://github.com/harfbuzz/harfbuzz/pull/2012
+		if U == 0x1C29: UIPC = Left
+
+		# TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0
 		if 0xA926 <= U <= 0xA92A: UIPC = Top
-		if U == 0x111CA: UIPC = Bottom
-		if U == 0x11300: UIPC = Top
 		# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
-		if U == 0x11302: UIPC = Top
-		if U == 0x1133C: UIPC = Bottom
-		if U == 0x1171E: UIPC = Left # Correct?!
-		if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
+		#  and https://github.com/harfbuzz/harfbuzz/issues/1631
+		if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
+		if U == 0x1171E: UIPC = Left
 		if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
-		# https://github.com/roozbehp/unicode-data/issues/8
-		if U == 0x0A51: UIPC = Bottom
 
 		assert (UIPC in [Not_Applicable, Visual_Order_Left] or
 			USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
@@ -415,6 +422,10 @@
 		print (" * %s" % (l.strip()))
 print (" */")
 print ()
+print ('#include "hb.hh"')
+print ()
+print ('#ifndef HB_NO_OT_SHAPE')
+print ()
 print ('#include "hb-ot-shape-complex-use.hh"')
 print ()
 
@@ -453,6 +464,8 @@
 offset = 0
 starts = []
 ends = []
+print ('#pragma GCC diagnostic push')
+print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
 for k,v in sorted(use_mapping.items()):
 	if k in use_positions and use_positions[k]: continue
 	print ("#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:]))
@@ -461,6 +474,7 @@
 	for suf in v.keys():
 		tag = k + suf
 		print ("#define %s	USE_%s" % (tag, tag))
+print ('#pragma GCC diagnostic pop')
 print ("")
 print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
 for u in uu:
@@ -526,6 +540,8 @@
 		tag = k + suf
 		print ("#undef %s" % tag)
 print ()
+print ()
+print ('#endif')
 print ("/* == End of generated table == */")
 
 # Maintain at least 50% occupancy in the table */
diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py
index b7f6be2..8ca90c8 100755
--- a/src/gen-vowel-constraints.py
+++ b/src/gen-vowel-constraints.py
@@ -157,6 +157,11 @@
 for line in scripts_header:
 	print (' * %s' % line.strip ())
 print (' */')
+
+print ()
+print ('#include "hb.hh"')
+print ()
+print ('#ifndef HB_NO_OT_SHAPE')
 print ()
 print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
 print ()
@@ -180,6 +185,12 @@
 print ('\t\t\t\t       hb_buffer_t              *buffer,')
 print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
 print ('{')
+print ('#if defined(HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS)')
+print ('  return;')
+print ('#endif')
+print ('  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
+print ('    return;')
+print ()
 print ('  /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
 print ('   * vowel-sequences that look like another vowel.  Data for each script')
 print ('   * collected from the USE script development spec.')
@@ -212,8 +223,11 @@
 print ('  {')
 print ('    if (buffer->idx < count)')
 print ('      buffer->next_glyph ();')
+print ('    buffer->swap_buffers ();')
 print ('  }')
 print ('}')
 
 print ()
+print ()
+print ('#endif')
 print ('/* == End of generated functions == */')
diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc
new file mode 100644
index 0000000..251a065
--- /dev/null
+++ b/src/harfbuzz.cc
@@ -0,0 +1,53 @@
+#include "hb-aat-layout.cc"
+#include "hb-aat-map.cc"
+#include "hb-blob.cc"
+#include "hb-buffer-serialize.cc"
+#include "hb-buffer.cc"
+#include "hb-common.cc"
+#include "hb-face.cc"
+#include "hb-fallback-shape.cc"
+#include "hb-font.cc"
+#include "hb-map.cc"
+#include "hb-number.cc"
+#include "hb-ot-cff1-table.cc"
+#include "hb-ot-cff2-table.cc"
+#include "hb-ot-color.cc"
+#include "hb-ot-face.cc"
+#include "hb-ot-font.cc"
+#include "hb-ot-layout.cc"
+#include "hb-ot-map.cc"
+#include "hb-ot-math.cc"
+#include "hb-ot-meta.cc"
+#include "hb-ot-metrics.cc"
+#include "hb-ot-name.cc"
+#include "hb-ot-shape-complex-arabic.cc"
+#include "hb-ot-shape-complex-default.cc"
+#include "hb-ot-shape-complex-hangul.cc"
+#include "hb-ot-shape-complex-hebrew.cc"
+#include "hb-ot-shape-complex-indic-table.cc"
+#include "hb-ot-shape-complex-indic.cc"
+#include "hb-ot-shape-complex-khmer.cc"
+#include "hb-ot-shape-complex-myanmar.cc"
+#include "hb-ot-shape-complex-thai.cc"
+#include "hb-ot-shape-complex-use-table.cc"
+#include "hb-ot-shape-complex-use.cc"
+#include "hb-ot-shape-complex-vowel-constraints.cc"
+#include "hb-ot-shape-fallback.cc"
+#include "hb-ot-shape-normalize.cc"
+#include "hb-ot-shape.cc"
+#include "hb-ot-tag.cc"
+#include "hb-ot-var.cc"
+#include "hb-set.cc"
+#include "hb-shape-plan.cc"
+#include "hb-shape.cc"
+#include "hb-shaper.cc"
+#include "hb-static.cc"
+#include "hb-ucd.cc"
+#include "hb-unicode.cc"
+#include "hb-glib.cc"
+#include "hb-ft.cc"
+#include "hb-graphite2.cc"
+#include "hb-uniscribe.cc"
+#include "hb-gdi.cc"
+#include "hb-directwrite.cc"
+#include "hb-coretext.cc"
diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh
index a1af595..604d5bc 100644
--- a/src/hb-aat-fdsc-table.hh
+++ b/src/hb-aat-fdsc-table.hh
@@ -65,7 +65,7 @@
   protected:
   Tag		tag;		/* The 4-byte table tag name. */
   union {
-  Fixed		value;		/* The value for the descriptor tag. */
+  HBFixed		value;		/* The value for the descriptor tag. */
   HBUINT32	nalfType;	/* If the tag is `nalf`, see non_alphabetic_value_t */
   } u;
   public:
@@ -74,7 +74,7 @@
 
 struct fdsc
 {
-  enum { tableTag = HB_AAT_TAG_fdsc };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
 
   enum {
     Weight	 = HB_TAG ('w','g','h','t'),
@@ -108,7 +108,7 @@
   }
 
   protected:
-  Fixed		version;	/* Version number of the font descriptors
+  HBFixed		version;	/* Version number of the font descriptors
 				 * table (0x00010000 for the current version). */
   LArrayOf<FontDescriptor>
 		descriptors;	/* List of tagged-coordinate pairs style descriptors
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index 4235b36..ef98884 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -58,20 +58,16 @@
 
 struct ankr
 {
-  enum { tableTag = HB_AAT_TAG_ankr };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
 
   const Anchor &get_anchor (hb_codepoint_t glyph_id,
 			    unsigned int i,
-			    unsigned int num_glyphs,
-			    const char *end) const
+			    unsigned int num_glyphs) const
   {
-    const Offset<HBUINT16, false> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
+    const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
     if (!offset)
       return Null(Anchor);
-    const GlyphAnchors &anchors = StructAtOffset<GlyphAnchors> (&(this+anchorData), *offset);
-    /* TODO Use sanitizer; to avoid overflows and more. */
-    if (unlikely ((const char *) &anchors + anchors.get_size () > end))
-      return Null(Anchor);
+    const GlyphAnchors &anchors = &(this+anchorData) + *offset;
     return anchors[i];
   }
 
@@ -80,15 +76,16 @@
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
 			  version == 0 &&
-			  lookupTable.sanitize (c, this)));
+			  c->check_range (this, anchorData) &&
+			  lookupTable.sanitize (c, this, &(this+anchorData))));
   }
 
   protected:
   HBUINT16	version; 	/* Version number (set to zero) */
   HBUINT16	flags;		/* Flags (currently unused; set to zero) */
-  LOffsetTo<Lookup<Offset<HBUINT16, false> >, false>
+  LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
 		lookupTable;	/* Offset to the table's lookup table */
-  LOffsetTo<HBUINT8, false>
+  LNNOffsetTo<HBUINT8>
 		anchorData;	/* Offset to the glyph data table */
 
   public:
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index 5bc59cb..15ef2da 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -82,7 +82,7 @@
   }
 
   protected:
-  GlyphID	stdGlyph;	/* The specific glyph index number in this
+  HBGlyphID	stdGlyph;	/* The specific glyph index number in this
 				 * font that is used to set the baseline values.
 				 * This is the standard glyph.
 				 * This glyph must contain a set of control points
@@ -105,7 +105,7 @@
   }
 
   protected:
-  GlyphID	stdGlyph;	/* ditto */
+  HBGlyphID	stdGlyph;	/* ditto */
   HBUINT16	ctlPoints[32];	/* ditto */
   Lookup<HBUINT16>
 		lookupTable;	/* Lookup table that maps glyphs to their
@@ -116,7 +116,7 @@
 
 struct bsln
 {
-  enum { tableTag = HB_AAT_TAG_bsln };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 95d6b31..473f2cd 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -77,7 +77,7 @@
 template <typename T>
 struct LookupSegmentSingle
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   int cmp (hb_codepoint_t g) const
   { return g < first ? -1 : g <= last ? 0 : +1 ; }
@@ -93,8 +93,8 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  GlyphID	last;		/* Last GlyphID in this segment */
-  GlyphID	first;		/* First GlyphID in this segment */
+  HBGlyphID	last;		/* Last GlyphID in this segment */
+  HBGlyphID	first;		/* First GlyphID in this segment */
   T		value;		/* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (4 + T::static_size);
@@ -125,7 +125,7 @@
 
   protected:
   HBUINT16	format;		/* Format identifier--format = 2 */
-  VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
+  VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
 		segments;	/* The actual segments. These must already be sorted,
 				 * according to the first word in each one (the last
 				 * glyph in each segment). */
@@ -136,7 +136,7 @@
 template <typename T>
 struct LookupSegmentArray
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
   {
@@ -153,18 +153,18 @@
 		  first <= last &&
 		  valuesZ.sanitize (c, base, last - first + 1));
   }
-  template <typename T2>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  first <= last &&
-		  valuesZ.sanitize (c, base, last - first + 1, user_data));
+		  valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
   }
 
-  GlyphID	last;		/* Last GlyphID in this segment */
-  GlyphID	first;		/* First GlyphID in this segment */
-  OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
+  HBGlyphID	last;		/* Last GlyphID in this segment */
+  HBGlyphID	first;		/* First GlyphID in this segment */
+  NNOffsetTo<UnsizedArrayOf<T>>
 		valuesZ;	/* A 16-bit offset from the start of
 				 * the table to the data. */
   public:
@@ -196,7 +196,7 @@
 
   protected:
   HBUINT16	format;		/* Format identifier--format = 4 */
-  VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
+  VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
 		segments;	/* The actual segments. These must already be sorted,
 				 * according to the first word in each one (the last
 				 * glyph in each segment). */
@@ -207,7 +207,7 @@
 template <typename T>
 struct LookupSingle
 {
-  enum { TerminationWordCount = 1 };
+  static constexpr unsigned TerminationWordCount = 1u;
 
   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
 
@@ -222,7 +222,7 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  GlyphID	glyph;		/* Last GlyphID */
+  HBGlyphID	glyph;		/* Last GlyphID */
   T		value;		/* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (2 + T::static_size);
@@ -253,7 +253,7 @@
 
   protected:
   HBUINT16	format;		/* Format identifier--format = 6 */
-  VarSizedBinSearchArrayOf<LookupSingle<T> >
+  VarSizedBinSearchArrayOf<LookupSingle<T>>
 		entries;	/* The actual entries, sorted by glyph index. */
   public:
   DEFINE_SIZE_ARRAY (8, entries);
@@ -284,7 +284,7 @@
 
   protected:
   HBUINT16	format;		/* Format identifier--format = 8 */
-  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBGlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
 				 * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<T>
@@ -326,7 +326,7 @@
   protected:
   HBUINT16	format;		/* Format identifier--format = 8 */
   HBUINT16	valueSize;	/* Byte size of each value. */
-  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBGlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
   HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
 				 * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<HBUINT8>
@@ -394,7 +394,7 @@
     case 4: return_trace (u.format4.sanitize (c, base));
     case 6: return_trace (u.format6.sanitize (c, base));
     case 8: return_trace (u.format8.sanitize (c, base));
-    case 10: return_trace (false); /* No need to support format10 apparently */
+    case 10: return_trace (false); /* We don't support format10 here currently. */
     default:return_trace (true);
     }
   }
@@ -418,15 +418,11 @@
 } /* Close namespace. */
 /* Ugly hand-coded null objects for template Lookup<> :(. */
 extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
-template <>
-/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); }
-template <>
-/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
-template <>
-/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
+template <typename T>
+struct Null<AAT::Lookup<T>> {
+  static AAT::Lookup<T> const & get_null ()
+  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
+};
 namespace AAT {
 
 enum { DELETED_GLYPH = 0xFFFF };
@@ -511,9 +507,10 @@
   const Entry<Extra> *get_entries () const
   { return (this+entryTable).arrayZ; }
 
-  const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
+  const Entry<Extra> &get_entry (int state, unsigned int klass) const
   {
-    if (unlikely (klass >= nClasses)) return nullptr;
+    if (unlikely (klass >= nClasses))
+      klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -521,7 +518,7 @@
     unsigned int entry = states[state * nClasses + klass];
     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
 
-    return &entries[entry];
+    return entries[entry];
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -529,6 +526,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) &&
+		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
 		    classTable.sanitize (c, this)))) return_trace (false);
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
@@ -571,14 +569,14 @@
 				       -min_state,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= state_neg - min_state) < 0)
+	if ((c->max_ops -= state_neg - min_state) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  const HBUSHORT *stop = &states[min_state * num_classes];
 	  if (unlikely (stop > states))
 	    return_trace (false);
 	  for (const HBUSHORT *p = states; stop < p; p--)
-	    num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
+	    num_entries = hb_max (num_entries, *(p - 1) + 1);
 	  state_neg = min_state;
 	}
       }
@@ -590,7 +588,7 @@
 				       max_state + 1,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= max_state - state_pos + 1) < 0)
+	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
@@ -599,22 +597,22 @@
 	  if (unlikely (stop < states))
 	    return_trace (false);
 	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
-	    num_entries = MAX<unsigned int> (num_entries, *p + 1);
+	    num_entries = hb_max (num_entries, *p + 1);
 	  state_pos = max_state + 1;
 	}
       }
 
       if (unlikely (!c->check_array (entries, num_entries)))
 	return_trace (false);
-      if ((c->max_ops -= num_entries - entry) < 0)
+      if ((c->max_ops -= num_entries - entry) <= 0)
 	return_trace (false);
       { /* Sweep new entries. */
 	const Entry<Extra> *stop = &entries[num_entries];
 	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
 	{
 	  int newState = new_state (p->newState);
-	  min_state = MIN (min_state, newState);
-	  max_state = MAX (max_state, newState);
+	  min_state = hb_min (min_state, newState);
+	  max_state = hb_max (max_state, newState);
 	}
 	entry = num_entries;
       }
@@ -629,11 +627,11 @@
   protected:
   HBUINT	nClasses;	/* Number of classes, which is the number of indices
 				 * in a single line in the state array. */
-  OffsetTo<ClassType, HBUINT, false>
+  NNOffsetTo<ClassType, HBUINT>
 		classTable;	/* Offset to the class table. */
-  OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
 		stateArrayTable;/* Offset to the state array. */
-  OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
 		entryTable;	/* Offset to the entry array. */
 
   public:
@@ -660,7 +658,7 @@
     return_trace (c->check_struct (this) && classArray.sanitize (c));
   }
   protected:
-  GlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
+  HBGlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
   ArrayOf<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
 					 * firstGlyph). */
   public:
@@ -669,7 +667,7 @@
 
 struct ObsoleteTypes
 {
-  enum { extended = false };
+  static constexpr bool extended = false;
   typedef HBUINT16 HBUINT;
   typedef HBUINT8 HBUSHORT;
   typedef ClassTable<HBUINT8> ClassTypeNarrow;
@@ -680,7 +678,7 @@
 				     const void *base,
 				     const T *array)
   {
-    return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
+    return (offset - ((const char *) array - (const char *) base)) / T::static_size;
   }
   template <typename T>
   static unsigned int byteOffsetToIndex (unsigned int offset,
@@ -699,7 +697,7 @@
 };
 struct ExtendedTypes
 {
-  enum { extended = true };
+  static constexpr bool extended = true;
   typedef HBUINT32 HBUINT;
   typedef HBUINT16 HBUSHORT;
   typedef Lookup<HBUINT16> ClassTypeNarrow;
@@ -707,22 +705,22 @@
 
   template <typename T>
   static unsigned int offsetToIndex (unsigned int offset,
-				     const void *base,
-				     const T *array)
+				     const void *base HB_UNUSED,
+				     const T *array HB_UNUSED)
   {
     return offset;
   }
   template <typename T>
   static unsigned int byteOffsetToIndex (unsigned int offset,
-					 const void *base,
-					 const T *array)
+					 const void *base HB_UNUSED,
+					 const T *array HB_UNUSED)
   {
     return offset / 2;
   }
   template <typename T>
   static unsigned int wordOffsetToIndex (unsigned int offset,
-					 const void *base,
-					 const T *array)
+					 const void *base HB_UNUSED,
+					 const T *array HB_UNUSED)
   {
     return offset;
   }
@@ -745,16 +743,13 @@
       buffer->clear_output ();
 
     int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
-    bool last_was_dont_advance = false;
     for (buffer->idx = 0; buffer->successful;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
 			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
-      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
-      if (unlikely (!entry))
-	break;
+      const Entry<EntryData> &entry = machine.get_entry (state, klass);
 
       /* Unsafe-to-break before this if not in state 0, as things might
        * go differently if we start from state 0 here.
@@ -765,31 +760,28 @@
 	/* If there's no action and we're just epsilon-transitioning to state 0,
 	 * safe to break. */
 	if (c->is_actionable (this, entry) ||
-	    !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
-	      entry->flags == context_t::DontAdvance))
+	    !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
+	      entry.flags == context_t::DontAdvance))
 	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
       }
 
       /* Unsafe-to-break if end-of-text would kick in here. */
       if (buffer->idx + 2 <= buffer->len)
       {
-	const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
+	const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
 	if (c->is_actionable (this, end_entry))
 	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
       }
 
-      if (unlikely (!c->transition (this, entry)))
-	break;
+      c->transition (this, entry);
 
-      last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
-
-      state = machine.new_state (entry->newState);
+      state = machine.new_state (entry.newState);
       DEBUG_MSG (APPLY, nullptr, "s%d", state);
 
       if (buffer->idx == buffer->len)
 	break;
 
-      if (!last_was_dont_advance)
+      if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
 	buffer->next_glyph ();
     }
 
@@ -825,7 +817,6 @@
   hb_buffer_t *buffer;
   hb_sanitize_context_t sanitizer;
   const ankr *ankr_table;
-  const char *ankr_end;
 
   /* Unused. For debug tracing only. */
   unsigned int lookup_index;
@@ -838,7 +829,7 @@
 
   HB_INTERNAL ~hb_aat_apply_context_t ();
 
-  HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_, const char *ankr_end_);
+  HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
 
   void set_lookup_index (unsigned int i) { lookup_index = i; }
 };
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index 63c69a2..788d408 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -47,17 +47,16 @@
   hb_aat_layout_feature_selector_t get_selector () const
   { return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
 
-  void get_info (hb_aat_layout_feature_selector_info_t *s,
-			hb_aat_layout_feature_selector_t default_selector) const
+  hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
   {
-    s->name_id = nameIndex;
-
-    s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting;
-    s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ?
-		 (hb_aat_layout_feature_selector_t) (s->enable + 1) :
-		 default_selector;
-
-    s->reserved = 0;
+    return {
+      nameIndex,
+      (hb_aat_layout_feature_selector_t) (unsigned int) setting,
+      default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
+	? (hb_aat_layout_feature_selector_t) (setting + 1)
+	: default_selector,
+      0
+    };
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -117,12 +116,12 @@
 
     if (selectors_count)
     {
-      hb_array_t<const SettingName> arr = settings_table.sub_array (start_offset, selectors_count);
-      unsigned int count = arr.len;
-      for (unsigned int i = 0; i < count; i++)
-        settings_table[start_offset + i].get_info (&selectors[i], default_selector);
+      + settings_table.sub_array (start_offset, selectors_count)
+      | hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
+      | hb_sink (hb_array (selectors, *selectors_count))
+      ;
     }
-    return settings_table.len;
+    return settings_table.length;
   }
 
   hb_aat_layout_feature_type_t get_feature_type () const
@@ -155,7 +154,7 @@
 
 struct feat
 {
-  enum { tableTag = HB_AAT_TAG_feat };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
 
   bool has_data () const { return version.to_int (); }
 
@@ -163,21 +162,18 @@
 				  unsigned int                 *count,
 				  hb_aat_layout_feature_type_t *features) const
   {
-    unsigned int feature_count = featureNameCount;
-    if (count && *count)
+    if (count)
     {
-      unsigned int len = MIN (feature_count - start_offset, *count);
-      for (unsigned int i = 0; i < len; i++)
-	features[i] = namesZ[i + start_offset].get_feature_type ();
-      *count = len;
+      + namesZ.as_array (featureNameCount).sub_array (start_offset, count)
+      | hb_map (&FeatureName::get_feature_type)
+      | hb_sink (hb_array (features, *count))
+      ;
     }
     return featureNameCount;
   }
 
   const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
-  {
-    return namesZ.bsearch (featureNameCount, feature_type);
-  }
+  { return namesZ.bsearch (featureNameCount, feature_type); }
 
   hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
   { return get_feature (feature).get_feature_name_id (); }
@@ -210,7 +206,7 @@
   SortedUnsizedArrayOf<FeatureName>
 		namesZ;		/* The feature name array. */
   public:
-  DEFINE_SIZE_STATIC (24);
+  DEFINE_SIZE_ARRAY (12, namesZ);
 };
 
 } /* namespace AAT */
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index d39945a..e1787d1 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -70,9 +70,9 @@
 
   ActionSubrecordHeader
 		header;
-  Fixed		lowerLimit; 	/* If the distance factor is less than this value,
+  HBFixed		lowerLimit; 	/* If the distance factor is less than this value,
 				 * then the ligature is decomposed. */
-  Fixed		upperLimit; 	/* If the distance factor is greater than this value,
+  HBFixed		upperLimit; 	/* If the distance factor is greater than this value,
 				 * then the ligature is decomposed. */
   HBUINT16 	order;		/* Numerical order in which this ligature will
 				 * be decomposed; you may want infrequent ligatures
@@ -100,7 +100,7 @@
   protected:
   ActionSubrecordHeader
 		header;
-  GlyphID	addGlyph;	/* Glyph that should be added if the distance factor
+  HBGlyphID	addGlyph;	/* Glyph that should be added if the distance factor
 				 * is growing. */
 
   public:
@@ -118,14 +118,14 @@
   protected:
   ActionSubrecordHeader
 		header;
-  Fixed 	substThreshold; /* Distance growth factor (in ems) at which
+  HBFixed 	substThreshold; /* Distance growth factor (in ems) at which
 				 * this glyph is replaced and the growth factor
 				 * recalculated. */
-  GlyphID 	addGlyph; 	/* Glyph to be added as kashida. If this value is
+  HBGlyphID 	addGlyph; 	/* Glyph to be added as kashida. If this value is
 				 * 0xFFFF, no extra glyph will be added. Note that
 				 * generally when a glyph is added, justification
 				 * will need to be redone. */
-  GlyphID 	substGlyph; 	/* Glyph to be substituted for this glyph if the
+  HBGlyphID 	substGlyph; 	/* Glyph to be substituted for this glyph if the
 				 * growth factor equals or exceeds the value of
 				 * substThreshold. */
   public:
@@ -146,13 +146,13 @@
   HBUINT32 	variationAxis;	/* The 4-byte tag identifying the ductile axis.
 				 * This would normally be 0x64756374 ('duct'),
 				 * but you may use any axis the font contains. */
-  Fixed 	minimumLimit; 	/* The lowest value for the ductility axis tha
+  HBFixed 	minimumLimit; 	/* The lowest value for the ductility axis tha
 				 * still yields an acceptable appearance. Normally
 				 * this will be 1.0. */
-  Fixed 	noStretchValue; /* This is the default value that corresponds to
+  HBFixed 	noStretchValue; /* This is the default value that corresponds to
 				 * no change in appearance. Normally, this will
 				 * be 1.0. */
-  Fixed 	maximumLimit; 	/* The highest value for the ductility axis that
+  HBFixed 	maximumLimit; 	/* The highest value for the ductility axis that
 				 * still yields an acceptable appearance. */
   public:
   DEFINE_SIZE_STATIC (22);
@@ -170,7 +170,7 @@
   ActionSubrecordHeader
 		header;
   HBUINT16 	flags;		/* Currently unused; set to 0. */
-  GlyphID 	glyph;		/* Glyph that should be added if the distance factor
+  HBGlyphID 	glyph;		/* Glyph that should be added if the distance factor
 				 * is growing. */
   public:
   DEFINE_SIZE_STATIC (10);
@@ -271,14 +271,14 @@
   };
 
   protected:
-  Fixed		beforeGrowLimit;/* The ratio by which the advance width of the
+  HBFixed		beforeGrowLimit;/* The ratio by which the advance width of the
 				 * glyph is permitted to grow on the left or top side. */
-  Fixed		beforeShrinkLimit;
+  HBFixed		beforeShrinkLimit;
 				/* The ratio by which the advance width of the
 				 * glyph is permitted to shrink on the left or top side. */
-  Fixed		afterGrowLimit;	/* The ratio by which the advance width of the glyph
+  HBFixed		afterGrowLimit;	/* The ratio by which the advance width of the glyph
 				 * is permitted to shrink on the left or top side. */
-  Fixed		afterShrinkLimit;
+  HBFixed		afterShrinkLimit;
 				/* The ratio by which the advance width of the glyph
 				 * is at most permitted to shrink on the right or
 				 * bottom side. */
@@ -309,7 +309,7 @@
   public:
   DEFINE_SIZE_STATIC (24);
 };
-  
+
 typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
 
 struct JustificationCategory
@@ -371,7 +371,7 @@
 				 * of postcompensation subtable (set to zero if none).
 				 *
 				 * The postcompensation subtable, if present in the font. */
-  Lookup<OffsetTo<WidthDeltaCluster> >
+  Lookup<OffsetTo<WidthDeltaCluster>>
   		lookupTable;	/* Lookup table associating glyphs with width delta
 				 * clusters. See the description of Width Delta Clusters
 				 * table for details on how to interpret the lookup values. */
@@ -382,7 +382,7 @@
 
 struct just
 {
-  enum { tableTag = HB_AAT_TAG_just };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index 291f3e3..be1b339 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -82,8 +82,8 @@
   }
 
   protected:
-  GlyphID	left;
-  GlyphID	right;
+  HBGlyphID	left;
+  HBGlyphID	right;
   FWORD		value;
   public:
   DEFINE_SIZE_STATIC (6);
@@ -170,11 +170,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex != 0xFFFF; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex != 0xFFFF; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex; }
 };
 template <>
 struct Format1Entry<false>
@@ -192,11 +192,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 template <typename KernSubTableHeader>
@@ -210,7 +210,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum
     {
       DontAdvance	= Format1EntryT::DontAdvance,
@@ -228,15 +228,15 @@
 	crossStream (table->header.coverage & table->header.CrossStream) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return Format1EntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & Format1EntryT::Reset)
 	depth = 0;
@@ -251,7 +251,7 @@
 
       if (Format1EntryT::performAction (entry) && depth)
       {
-	unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
+	unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
 
 	unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
 	kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
@@ -259,7 +259,7 @@
 	if (!c->sanitizer.check_array (actions, depth, tuple_count))
 	{
 	  depth = 0;
-	  return false;
+	  return;
 	}
 
 	hb_mask_t kern_mask = c->plan->kern_mask;
@@ -334,8 +334,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     private:
@@ -374,7 +372,7 @@
   protected:
   KernSubTableHeader				header;
   StateTable<Types, EntryData>			machine;
-  OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false>kernAction;
+  NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>	kernAction;
   public:
   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
 };
@@ -394,7 +392,7 @@
 
     const UnsizedArrayOf<FWORD> &arrayZ = this+array;
     unsigned int kern_idx = l + r;
-    kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ);
+    kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
     const FWORD *v = &arrayZ[kern_idx];
     if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
 
@@ -443,13 +441,13 @@
   protected:
   KernSubTableHeader	header;
   HBUINT		rowWidth;	/* The width, in bytes, of a row in the table. */
-  OffsetTo<typename Types::ClassTypeWide, HBUINT, false>
+  NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
 			leftClassTable;	/* Offset from beginning of this subtable to
 					 * left-hand class table. */
-  OffsetTo<typename Types::ClassTypeWide, HBUINT, false>
+  NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
 			rightClassTable;/* Offset from beginning of this subtable to
 					 * right-hand class table. */
-  OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>
 			 array;		/* Offset from beginning of this subtable to
 					 * the start of the kerning array. */
   public:
@@ -471,7 +469,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       Mark		= 0x8000,	/* If set, remember this glyph as the marked glyph. */
@@ -498,16 +496,16 @@
 	mark (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return entry->data.ankrActionIndex != 0xFFFF;
+      return entry.data.ankrActionIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
-      if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
+      if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
       {
 	hb_glyph_position_t &o = buffer->cur_pos();
 	switch (action_type)
@@ -515,9 +513,8 @@
 	  case 0: /* Control Point Actions.*/
 	  {
 	    /* indexed into glyph outline. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    HB_UNUSED unsigned int markControlPoint = *data++;
 	    HB_UNUSED unsigned int currControlPoint = *data++;
 	    hb_position_t markX = 0;
@@ -532,7 +529,7 @@
 							      currControlPoint,
 							      HB_DIRECTION_LTR /*XXX*/,
 							      &currX, &currY))
-	      return true; /* True, such that the machine continues. */
+	      return;
 
 	    o.x_offset = markX - currX;
 	    o.y_offset = markY - currY;
@@ -542,19 +539,16 @@
 	  case 1: /* Anchor Point Actions. */
 	  {
 	   /* Indexed into 'ankr' table. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    unsigned int markAnchorPoint = *data++;
 	    unsigned int currAnchorPoint = *data++;
-	    const Anchor markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
-								 markAnchorPoint,
-								 c->sanitizer.get_num_glyphs (),
-								 c->ankr_end);
-	    const Anchor currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
-								 currAnchorPoint,
-								 c->sanitizer.get_num_glyphs (),
-								 c->ankr_end);
+	    const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
+								  markAnchorPoint,
+								  c->sanitizer.get_num_glyphs ());
+	    const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
+								  currAnchorPoint,
+								  c->sanitizer.get_num_glyphs ());
 
 	    o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
 	    o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
@@ -563,9 +557,8 @@
 
 	  case 2: /* Control Point Coordinate Actions. */
 	  {
-	    const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 4))
-	      return false;
+	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 4)) return;
 	    int markX = *data++;
 	    int markY = *data++;
 	    int currX = *data++;
@@ -581,13 +574,11 @@
 	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
 
-      if (entry->flags & Mark)
+      if (entry.flags & Mark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     private:
@@ -721,18 +712,18 @@
   {
     struct Long
     {
-      LOffsetTo<Lookup<HBUINT32>, false>	rowIndexTable;
-      LOffsetTo<Lookup<HBUINT32>, false>	columnIndexTable;
-      LOffsetTo<UnsizedArrayOf<FWORD32>, false>	array;
+      LNNOffsetTo<Lookup<HBUINT32>>		rowIndexTable;
+      LNNOffsetTo<Lookup<HBUINT32>>		columnIndexTable;
+      LNNOffsetTo<UnsizedArrayOf<FWORD32>>	array;
     } l;
     struct Short
     {
-      LOffsetTo<Lookup<HBUINT16>, false>	rowIndexTable;
-      LOffsetTo<Lookup<HBUINT16>, false>	columnIndexTable;
-      LOffsetTo<UnsizedArrayOf<FWORD>, false>	array;
+      LNNOffsetTo<Lookup<HBUINT16>>		rowIndexTable;
+      LNNOffsetTo<Lookup<HBUINT16>>		columnIndexTable;
+      LNNOffsetTo<UnsizedArrayOf<FWORD>>	array;
     } s;
   } u;
-  LOffsetTo<UnsizedArrayOf<FWORD>, false>	vector;
+  LNNOffsetTo<UnsizedArrayOf<FWORD>>	vector;
   public:
   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
 };
@@ -742,8 +733,8 @@
 {
   typedef ExtendedTypes Types;
 
-  unsigned int tuple_count () const { return tupleCount; }
-  bool is_horizontal () const       { return !(coverage & Vertical); }
+  unsigned   tuple_count () const { return tupleCount; }
+  bool     is_horizontal () const { return !(coverage & Vertical); }
 
   enum Coverage
   {
@@ -780,17 +771,17 @@
   unsigned int get_size () const { return u.header.length; }
   unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:	return_trace (c->dispatch (u.format0));
-    case 1:	return_trace (c->dispatch (u.format1));
-    case 2:	return_trace (c->dispatch (u.format2));
-    case 4:	return_trace (c->dispatch (u.format4));
-    case 6:	return_trace (c->dispatch (u.format6));
+    case 0:	return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
+    case 1:	return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2:	return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 4:	return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
+    case 6:	return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
     default:	return_trace (c->default_return_value ());
     }
   }
@@ -839,7 +830,7 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (st->get_type () == 1)
-        return true;
+	return true;
       st = &StructAfter<SubTable> (*st);
     }
     return false;
@@ -854,7 +845,7 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (st->u.header.coverage & st->u.header.CrossStream)
-        return true;
+	return true;
       st = &StructAfter<SubTable> (*st);
     }
     return false;
@@ -871,7 +862,7 @@
     {
       if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
 	  !st->u.header.is_horizontal ())
-        continue;
+	continue;
       v += st->get_kerning (left, right);
       st = &StructAfter<SubTable> (*st);
     }
@@ -892,7 +883,7 @@
       bool reverse;
 
       if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
-        goto skip;
+	goto skip;
 
       if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
 	goto skip;
@@ -906,8 +897,8 @@
       if (!seenCrossStream &&
 	  (st->u.header.coverage & st->u.header.CrossStream))
       {
-        /* Attach all glyphs into a chain. */
-        seenCrossStream = true;
+	/* Attach all glyphs into a chain. */
+	seenCrossStream = true;
 	hb_glyph_position_t *pos = c->buffer->pos;
 	unsigned int count = c->buffer->len;
 	for (unsigned int i = 0; i < count; i++)
@@ -981,8 +972,8 @@
 {
   friend struct KerxTable<kerx>;
 
-  enum { tableTag = HB_AAT_TAG_kerx };
-  enum { minVersion = 2u };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
+  static constexpr unsigned minVersion = 2u;
 
   typedef KerxSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh
index cac9697..7063b38 100644
--- a/src/hb-aat-layout-lcar-table.hh
+++ b/src/hb-aat-layout-lcar-table.hh
@@ -38,9 +38,83 @@
 
 typedef ArrayOf<HBINT16> LigCaretClassEntry;
 
+struct lcarFormat0
+{
+  unsigned int get_lig_carets (hb_font_t      *font,
+			       hb_direction_t  direction,
+			       hb_codepoint_t  glyph,
+			       unsigned int    start_offset,
+			       unsigned int   *caret_count /* IN/OUT */,
+			       hb_position_t  *caret_array /* OUT */,
+			       const void     *base) const
+  {
+    const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
+									      font->face->get_num_glyphs ());
+    const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
+    if (caret_count)
+    {
+      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
+      for (unsigned int i = 0; i < arr.length; ++i)
+	caret_array[i] = font->em_scale_dir (arr[i], direction);
+    }
+    return array.len;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<LigCaretClassEntry>>
+		lookupTable;	/* data Lookup table associating glyphs */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct lcarFormat1
+{
+  unsigned int get_lig_carets (hb_font_t      *font,
+			       hb_direction_t  direction,
+			       hb_codepoint_t  glyph,
+			       unsigned int    start_offset,
+			       unsigned int   *caret_count /* IN/OUT */,
+			       hb_position_t  *caret_array /* OUT */,
+			       const void     *base) const
+  {
+    const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
+									      font->face->get_num_glyphs ());
+    const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
+    if (caret_count)
+    {
+      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
+      for (unsigned int i = 0; i < arr.length; ++i)
+      {
+	hb_position_t x = 0, y = 0;
+	font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
+	caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
+      }
+    }
+    return array.len;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<LigCaretClassEntry>>
+		lookupTable;	/* data Lookup table associating glyphs */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
 struct lcar
 {
-  enum { tableTag = HB_AAT_TAG_lcar };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
 
   unsigned int get_lig_carets (hb_font_t      *font,
 			       hb_direction_t  direction,
@@ -49,41 +123,36 @@
 			       unsigned int   *caret_count /* IN/OUT */,
 			       hb_position_t  *caret_array /* OUT */) const
   {
-    const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
-									 font->face->get_num_glyphs ());
-    const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
-    if (caret_count)
+    switch (format)
     {
-      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
-      unsigned int count = arr.len;
-      for (unsigned int i = 0; i < count; ++i)
-	switch (format)
-	{
-	case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break;
-	case 1:
-	  hb_position_t x, y;
-	  font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
-	  caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
-	  break;
-	}
+    case 0: return u.format0.get_lig_carets (font, direction, glyph, start_offset,
+					     caret_count, caret_array, this);
+    case 1: return u.format1.get_lig_carets (font, direction, glyph, start_offset,
+					     caret_count, caret_array, this);
+    default:if (caret_count) *caret_count = 0; return 0;
     }
-    return array.len;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-			  version.major == 1 &&
-			  lookup.sanitize (c, this)));
+    if (unlikely (!c->check_struct (this) || version.major != 1))
+      return_trace (false);
+
+    switch (format) {
+    case 0: return_trace (u.format0.sanitize (c, this));
+    case 1: return_trace (u.format1.sanitize (c, this));
+    default:return_trace (true);
+    }
   }
 
   protected:
   FixedVersion<>version;	/* Version number of the ligature caret table */
   HBUINT16	format;		/* Format of the ligature caret table. */
-  Lookup<OffsetTo<LigCaretClassEntry> >
-		lookup;		/* data Lookup table associating glyphs */
-
+  union {
+  lcarFormat0	format0;
+  lcarFormat0	format1;
+  } u;
   public:
   DEFINE_SIZE_MIN (8);
 };
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index c7600aa..d8df579 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -54,7 +54,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       MarkFirst		= 0x8000,	/* If set, make the current glyph the first
@@ -74,21 +74,21 @@
 	start (0), end (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & Verb) && start < end;
+      return (entry.flags & Verb) && start < end;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & MarkFirst)
 	start = buffer->idx;
 
       if (flags & MarkLast)
-	end = MIN (buffer->idx + 1, buffer->len);
+	end = hb_min (buffer->idx + 1, buffer->len);
 
       if ((flags & Verb) && start < end)
       {
@@ -117,14 +117,14 @@
 	};
 
 	unsigned int m = map[flags & Verb];
-	unsigned int l = MIN<unsigned int> (2, m >> 4);
-	unsigned int r = MIN<unsigned int> (2, m & 0x0F);
+	unsigned int l = hb_min (2u, m >> 4);
+	unsigned int r = hb_min (2u, m & 0x0F);
 	bool reverse_l = 3 == (m >> 4);
 	bool reverse_r = 3 == (m & 0x0F);
 
 	if (end - start >= l + r)
 	{
-	  buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
+	  buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
 	  buffer->merge_clusters (start, end);
 
 	  hb_glyph_info_t *info = buffer->info;
@@ -152,8 +152,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     public:
@@ -204,7 +202,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
@@ -223,65 +221,65 @@
 	subs (table+table->substitutionTables) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       if (buffer->idx == buffer->len && !mark_set)
-        return false;
+	return false;
 
-      return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
+      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       /* Looks like CoreText applies neither mark nor current substitution for
        * end-of-text if mark was not explicitly set. */
       if (buffer->idx == buffer->len && !mark_set)
-        return true;
+	return;
 
-      const GlyphID *replacement;
+      const HBGlyphID *replacement;
 
       replacement = nullptr;
       if (Types::extended)
       {
-	if (entry->data.markIndex != 0xFFFF)
+	if (entry.data.markIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
+	  const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex];
 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.markIndex + buffer->info[mark].codepoint;
-	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
+	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
+	const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
 	  replacement = nullptr;
       }
       if (replacement)
       {
-	buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
+	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
 	buffer->info[mark].codepoint = *replacement;
 	ret = true;
       }
 
       replacement = nullptr;
-      unsigned int idx = MIN (buffer->idx, buffer->len - 1);
+      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
       if (Types::extended)
       {
-	if (entry->data.currentIndex != 0xFFFF)
+	if (entry.data.currentIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
+	  const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex];
 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.currentIndex + buffer->info[idx].codepoint;
-	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
+	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
+	const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
 	  replacement = nullptr;
@@ -292,13 +290,11 @@
 	ret = true;
       }
 
-      if (entry->flags & SetMark)
+      if (entry.flags & SetMark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     public:
@@ -308,7 +304,7 @@
     bool mark_set;
     unsigned int mark;
     const ContextualSubtable *table;
-    const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
+    const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -330,7 +326,8 @@
     unsigned int num_entries = 0;
     if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
 
-    if (!Types::extended) return_trace (true);
+    if (!Types::extended)
+      return_trace (substitutionTables.sanitize (c, this, 0));
 
     unsigned int num_lookups = 0;
 
@@ -340,9 +337,9 @@
       const EntryData &data = entries[i].data;
 
       if (data.markIndex != 0xFFFF)
-	num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
+	num_lookups = hb_max (num_lookups, 1 + data.markIndex);
       if (data.currentIndex != 0xFFFF)
-	num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
+	num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
     }
 
     return_trace (substitutionTables.sanitize (c, this, num_lookups));
@@ -351,7 +348,7 @@
   protected:
   StateTable<Types, EntryData>
 		machine;
-  OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT, false>
+  NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
 		substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
@@ -384,11 +381,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & PerformAction; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & PerformAction; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.ligActionIndex; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.ligActionIndex; }
 };
 template <>
 struct LigatureEntry<false>
@@ -406,11 +403,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 
@@ -424,7 +421,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum
     {
       DontAdvance	= LigatureEntryT::DontAdvance,
@@ -452,26 +449,23 @@
 	match_length (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return LigatureEntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
-      if (entry->flags & LigatureEntryT::SetComponent)
+      if (entry.flags & LigatureEntryT::SetComponent)
       {
-        if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
-	  return false;
-
 	/* Never mark same index twice, in case DontAdvance was used... */
-	if (match_length && match_positions[match_length - 1] == buffer->out_len)
+	if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
 	  match_length--;
 
-	match_positions[match_length++] = buffer->out_len;
+	match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
 	DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
       }
 
@@ -481,10 +475,10 @@
 	unsigned int end = buffer->out_len;
 
 	if (unlikely (!match_length))
-	  return true;
+	  return;
 
 	if (buffer->idx >= buffer->len)
-	  return false; // TODO Work on previous instead?
+	  return; /* TODO Work on previous instead? */
 
 	unsigned int cursor = match_length;
 
@@ -494,7 +488,7 @@
 
 	unsigned int ligature_idx = 0;
 	unsigned int action;
-        do
+	do
 	{
 	  if (unlikely (!cursor))
 	  {
@@ -505,9 +499,9 @@
 	  }
 
 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
-	  buffer->move_to (match_positions[--cursor]);
+	  buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
 
-	  if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
 	  action = *actionData;
 
 	  uint32_t uoffset = action & LigActionOffset;
@@ -517,7 +511,7 @@
 	  unsigned int component_idx = buffer->cur().codepoint + offset;
 	  component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
 	  const HBUINT16 &componentData = component[component_idx];
-	  if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
 	  ligature_idx += componentData;
 
 	  DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
@@ -526,24 +520,24 @@
 	  if (action & (LigActionStore | LigActionLast))
 	  {
 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
-	    const GlyphID &ligatureData = ligature[ligature_idx];
-	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
+	    const HBGlyphID &ligatureData = ligature[ligature_idx];
+	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
 	    buffer->replace_glyph (lig);
 
-	    unsigned int lig_end = match_positions[match_length - 1] + 1;
+	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
-	    while (match_length - 1 > cursor)
+	    while (match_length - 1u > cursor)
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
-	      buffer->move_to (match_positions[--match_length]);
+	      buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
 	      buffer->replace_glyph (DELETED_GLYPH);
 	    }
 
 	    buffer->move_to (lig_end);
-	    buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
+	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
 	  }
 
 	  actionData++;
@@ -551,8 +545,6 @@
 	while (!(action & LigActionLast));
 	buffer->move_to (end);
       }
-
-      return true;
     }
 
     public:
@@ -562,7 +554,7 @@
     const LigatureSubtable *table;
     const UnsizedArrayOf<HBUINT32> &ligAction;
     const UnsizedArrayOf<HBUINT16> &component;
-    const UnsizedArrayOf<GlyphID> &ligature;
+    const UnsizedArrayOf<HBGlyphID> &ligature;
     unsigned int match_length;
     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   };
@@ -590,11 +582,11 @@
   protected:
   StateTable<Types, EntryData>
 		machine;
-  OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
 		ligAction;	/* Offset to the ligature action table. */
-  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
 		component;	/* Offset to the component table. */
-  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
 		ligature;	/* Offset to the actual ligature lists. */
   public:
   DEFINE_SIZE_STATIC (28);
@@ -614,7 +606,7 @@
     unsigned int count = c->buffer->len;
     for (unsigned int i = 0; i < count; i++)
     {
-      const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
+      const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
 	info[i].codepoint = *replacement;
@@ -632,7 +624,7 @@
   }
 
   protected:
-  Lookup<GlyphID>	substitute;
+  Lookup<HBGlyphID>	substitute;
   public:
   DEFINE_SIZE_MIN (2);
 };
@@ -660,7 +652,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, mark the current glyph. */
@@ -713,28 +705,29 @@
 		      hb_aat_apply_context_t *c_) :
 	ret (false),
 	c (c_),
-	mark_set (false),
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
-	     (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
+      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
+	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
-      if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
+      unsigned mark_loc = buffer->out_len;
+
+      if (entry.data.markedInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & MarkedInsertCount);
-	unsigned int start = entry->data.markedInsertIndex;
-	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	unsigned int start = entry.data.markedInsertIndex;
+	const HBGlyphID *glyphs = &insertionAction[start];
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & MarkedInsertBefore;
 
@@ -751,15 +744,18 @@
 
 	buffer->move_to (end + count);
 
-	buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
+	buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
       }
 
-      if (entry->data.currentInsertIndex != 0xFFFF)
+      if (flags & SetMark)
+	mark = mark_loc;
+
+      if (entry.data.currentInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & CurrentInsertCount) >> 5;
-	unsigned int start = entry->data.currentInsertIndex;
-	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	unsigned int start = entry.data.currentInsertIndex;
+	const HBGlyphID *glyphs = &insertionAction[start];
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & CurrentInsertBefore;
 
@@ -790,23 +786,14 @@
 	 */
 	buffer->move_to ((flags & DontAdvance) ? end : end + count);
       }
-
-      if (flags & SetMark)
-      {
-	mark_set = true;
-	mark = buffer->out_len;
-      }
-
-      return true;
     }
 
     public:
     bool ret;
     private:
     hb_aat_apply_context_t *c;
-    bool mark_set;
     unsigned int mark;
-    const UnsizedArrayOf<GlyphID> &insertionAction;
+    const UnsizedArrayOf<HBGlyphID> &insertionAction;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -832,7 +819,7 @@
   protected:
   StateTable<Types, EntryData>
 		machine;
-  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
 		insertionAction;	/* Byte offset from stateHeader to the start of
 					 * the insertion glyph table. */
   public:
@@ -896,17 +883,17 @@
     Insertion		= 5
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case Rearrangement:		return_trace (c->dispatch (u.rearrangement));
-    case Contextual:		return_trace (c->dispatch (u.contextual));
-    case Ligature:		return_trace (c->dispatch (u.ligature));
-    case Noncontextual:		return_trace (c->dispatch (u.noncontextual));
-    case Insertion:		return_trace (c->dispatch (u.insertion));
+    case Rearrangement:		return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
+    case Contextual:		return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
+    case Ligature:		return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
+    case Noncontextual:		return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
+    case Insertion:		return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
     default:			return_trace (c->default_return_value ());
     }
   }
@@ -961,7 +948,7 @@
 	hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
 	hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
       retry:
-	const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch ((uint16_t) type);
+	const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
 	if (info && info->setting == setting)
 	{
 	  flags &= feature.disableFlags;
@@ -982,19 +969,19 @@
   void apply (hb_aat_apply_context_t *c,
 		     hb_mask_t flags) const
   {
-    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
+    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
       bool reverse;
 
       if (!(subtable->subFeatureFlags & flags))
-        goto skip;
+	goto skip;
 
       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
 	  bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
-        goto skip;
+	goto skip;
 
       /* Buffer contents is always in logical direction.  Determine if
        * we need to reverse before applying this subtable.  We reverse
@@ -1029,22 +1016,22 @@
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
       if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
-        goto skip;
+	goto skip;
 
       if (reverse)
-        c->buffer->reverse ();
+	c->buffer->reverse ();
 
       subtable->apply (c);
 
       if (reverse)
-        c->buffer->reverse ();
+	c->buffer->reverse ();
 
       (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
 
       if (unlikely (!c->buffer->successful)) return;
 
     skip:
-      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
       c->set_lookup_index (c->lookup_index + 1);
     }
   }
@@ -1062,13 +1049,13 @@
     if (!c->check_array (featureZ.arrayZ, featureCount))
       return_trace (false);
 
-    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
+    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
       if (!subtable->sanitize (c))
 	return_trace (false);
-      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
     }
 
     return_trace (true);
@@ -1093,10 +1080,10 @@
  * The 'mort'/'morx' Table
  */
 
-template <typename Types>
+template <typename Types, hb_tag_t TAG>
 struct mortmorx
 {
-  enum { tableTag = HB_AAT_TAG_morx };
+  static constexpr hb_tag_t tableTag = TAG;
 
   bool has_data () const { return version != 0; }
 
@@ -1108,7 +1095,7 @@
     for (unsigned int i = 0; i < count; i++)
     {
       map->chain_flags.push (chain->compile_flags (mapper));
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
   }
 
@@ -1122,7 +1109,7 @@
     {
       chain->apply (c, c->plan->aat_map.chain_flags[i]);
       if (unlikely (!c->buffer->successful)) return;
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
   }
 
@@ -1138,7 +1125,7 @@
     {
       if (!chain->sanitize (c, version))
 	return_trace (false);
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
 
     return_trace (true);
@@ -1156,14 +1143,8 @@
   DEFINE_SIZE_MIN (8);
 };
 
-struct morx : mortmorx<ExtendedTypes>
-{
-  enum { tableTag = HB_AAT_TAG_morx };
-};
-struct mort : mortmorx<ObsoleteTypes>
-{
-  enum { tableTag = HB_AAT_TAG_mort };
-};
+struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
+struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
 
 
 } /* namespace AAT */
diff --git a/src/hb-aat-layout-opbd-table.hh b/src/hb-aat-layout-opbd-table.hh
new file mode 100644
index 0000000..4e02340
--- /dev/null
+++ b/src/hb-aat-layout-opbd-table.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
+#define HB_AAT_LAYOUT_OPBD_TABLE_HH
+
+#include "hb-aat-layout-common.hh"
+#include "hb-open-type.hh"
+
+/*
+ * opbd -- Optical Bounds
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
+ */
+#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
+
+
+namespace AAT {
+
+struct OpticalBounds
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  FWORD		leftSide;
+  FWORD		topSide;
+  FWORD		rightSide;
+  FWORD		bottomSide;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct opbdFormat0
+{
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+		   hb_glyph_extents_t *extents, const void *base) const
+  {
+    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    if (!bounds_offset) return false;
+    const OpticalBounds &bounds = base+*bounds_offset;
+
+    if (extents)
+      *extents = {
+	font->em_scale_x (bounds.leftSide),
+	font->em_scale_y (bounds.topSide),
+	font->em_scale_x (bounds.rightSide),
+	font->em_scale_y (bounds.bottomSide)
+      };
+    return true;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<OpticalBounds>>
+		lookupTable;	/* Lookup table associating glyphs with the four
+				 * int16 values for the left-side, top-side,
+				 * right-side, and bottom-side optical bounds. */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct opbdFormat1
+{
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+		   hb_glyph_extents_t *extents, const void *base) const
+  {
+    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    if (!bounds_offset) return false;
+    const OpticalBounds &bounds = base+*bounds_offset;
+
+    hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
+    if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
+	font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
+	font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
+	font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
+    {
+      if (extents)
+	*extents = {left, top, right, bottom};
+      return true;
+    }
+    return false;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<OpticalBounds>>
+		lookupTable;	/* Lookup table associating glyphs with the four
+				 * int16 values for the left-side, top-side,
+				 * right-side, and bottom-side optical bounds. */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct opbd
+{
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
+
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+		   hb_glyph_extents_t *extents) const
+  {
+    switch (format)
+    {
+    case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
+    case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
+    default:return false;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this) || version.major != 1))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, this));
+    case 1: return_trace (u.format1.sanitize (c, this));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  FixedVersion<>version;	/* Version number of the optical bounds
+				 * table (0x00010000 for the current version). */
+  HBUINT16	format;		/* Format of the optical bounds table.
+				 * Format 0 indicates distance and Format 1 indicates
+				 * control point. */
+  union {
+  opbdFormat0 format0;
+  opbdFormat1 format1;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index 0648f61..99dddd8 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -62,11 +62,11 @@
   }
 
   protected:
-  Fixed		track;		/* Track value for this record. */
+  HBFixed		track;		/* Track value for this record. */
   NameID	trackNameID;	/* The 'name' table index for this track.
 				 * (a short word or phrase like "loose"
 				 * or "very tight") */
-  OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
+  NNOffsetTo<UnsizedArrayOf<FWORD>>
 		valuesZ;	/* Offset from start of tracking table to
 				 * per-size tracking values for this track. */
 
@@ -82,7 +82,7 @@
 			const void *base) const
   {
     unsigned int sizes = nSizes;
-    hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
 
     float s0 = size_table[idx].to_float ();
     float s1 = size_table[idx + 1].to_float ();
@@ -93,13 +93,6 @@
 
   int get_tracking (const void *base, float ptem) const
   {
-    /* CoreText points are CSS pixels (96 per inch),
-     * NOT typographic points (72 per inch).
-     *
-     * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
-     */
-    float csspx = ptem * 96.f / 72.f;
-
     /*
      * Choose track.
      */
@@ -127,14 +120,14 @@
     if (!sizes) return 0.;
     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
 
-    hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
     unsigned int size_index;
     for (size_index = 0; size_index < sizes - 1; size_index++)
-      if (size_table[size_index].to_float () >= csspx)
-        break;
+      if (size_table[size_index].to_float () >= ptem)
+	break;
 
-    return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
-				  *trackTableEntry, base));
+    return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
+				   *trackTableEntry, base));
   }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -148,7 +141,7 @@
   protected:
   HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
   HBUINT16	nSizes;		/* Number of point sizes included in this table. */
-  LOffsetTo<UnsizedArrayOf<Fixed>, false>
+  LOffsetTo<UnsizedArrayOf<HBFixed>, false>
 		sizeTable;	/* Offset from start of the tracking table to
 				 * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>
@@ -160,7 +153,7 @@
 
 struct trak
 {
-  enum { tableTag = HB_AAT_TAG_trak };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
 
   bool has_data () const { return version.to_int (); }
 
@@ -183,7 +176,7 @@
       hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
       foreach_grapheme (buffer, start, end)
       {
-        if (!(buffer->info[start].mask & trak_mask)) continue;
+	if (!(buffer->info[start].mask & trak_mask)) continue;
 	buffer->pos[start].x_advance += advance_to_add;
 	buffer->pos[start].x_offset += offset_to_add;
       }
@@ -196,7 +189,7 @@
       hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
       foreach_grapheme (buffer, start, end)
       {
-        if (!(buffer->info[start].mask & trak_mask)) continue;
+	if (!(buffer->info[start].mask & trak_mask)) continue;
 	buffer->pos[start].y_advance += advance_to_add;
 	buffer->pos[start].y_offset += offset_to_add;
       }
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 8de8205..4e506de 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -25,9 +25,8 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
 #include "hb-aat-layout.hh"
 #include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-ankr-table.hh"
@@ -40,6 +39,42 @@
 #include "hb-aat-ltag-table.hh"
 
 
+/*
+ * hb_aat_apply_context_t
+ */
+
+/* Note: This context is used for kerning, even without AAT, hence the condition. */
+#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
+
+AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
+						     hb_font_t *font_,
+						     hb_buffer_t *buffer_,
+						     hb_blob_t *blob) :
+						       plan (plan_),
+						       font (font_),
+						       face (font->face),
+						       buffer (buffer_),
+						       sanitizer (),
+						       ankr_table (&Null(AAT::ankr)),
+						       lookup_index (0),
+						       debug_depth (0)
+{
+  sanitizer.init (blob);
+  sanitizer.set_num_glyphs (face->get_num_glyphs ());
+  sanitizer.start_processing ();
+  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
+}
+
+AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
+{ sanitizer.end_processing (); }
+
+void
+AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
+{ ankr_table = ankr_table_; }
+
+#endif
+
+
 /**
  * SECTION:hb-aat-layout
  * @title: hb-aat-layout
@@ -50,6 +85,8 @@
  **/
 
 
+#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
+
 /* Table data courtesy of Apple.  Converted from mnemonics to integers
  * when moving to this file. */
 static const hb_aat_feature_mapping_t feature_mappings[] =
@@ -135,49 +172,16 @@
 const hb_aat_feature_mapping_t *
 hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 {
-  return (const hb_aat_feature_mapping_t *) bsearch (&tag,
-						     feature_mappings,
-						     ARRAY_LENGTH (feature_mappings),
-						     sizeof (feature_mappings[0]),
-						     hb_aat_feature_mapping_t::cmp);
+  return (const hb_aat_feature_mapping_t *) hb_bsearch (&tag,
+							feature_mappings,
+							ARRAY_LENGTH (feature_mappings),
+							sizeof (feature_mappings[0]),
+							hb_aat_feature_mapping_t::cmp);
 }
+#endif
 
 
-/*
- * hb_aat_apply_context_t
- */
-
-AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
-						     hb_font_t *font_,
-						     hb_buffer_t *buffer_,
-						     hb_blob_t *blob) :
-						       plan (plan_),
-						       font (font_),
-						       face (font->face),
-						       buffer (buffer_),
-						       sanitizer (),
-						       ankr_table (&Null(AAT::ankr)),
-						       ankr_end (nullptr),
-						       lookup_index (0),
-						       debug_depth (0)
-{
-  sanitizer.init (blob);
-  sanitizer.set_num_glyphs (face->get_num_glyphs ());
-  sanitizer.start_processing ();
-  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
-}
-
-AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
-{ sanitizer.end_processing (); }
-
-void
-AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_,
-					     const char      *ankr_end_)
-{
-  ankr_table = ankr_table_;
-  ankr_end = ankr_end_;
-}
-
+#ifndef HB_NO_AAT
 
 /*
  * mort/morx/kerx/trak
@@ -286,11 +290,8 @@
   hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
   const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
 
-  hb_blob_t *ankr_blob = font->face->table.ankr.get_blob ();;
-  const AAT::ankr& ankr = *font->face->table.ankr;
-
   AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
-  c.set_ankr_table (&ankr, ankr_blob->data + ankr_blob->length);
+  c.set_ankr_table (font->face->table.ankr.get ());
   kerx.apply (&c);
 }
 
@@ -319,14 +320,6 @@
   trak.apply (&c);
 }
 
-
-hb_language_t
-_hb_aat_language_get (hb_face_t *face,
-		      unsigned int i)
-{
-  return face->table.ltag->get_language (i);
-}
-
 /**
  * hb_aat_layout_get_feature_types:
  * @face: a face object
@@ -390,3 +383,6 @@
 {
   return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
 }
+
+
+#endif
diff --git a/src/hb-aat-layout.h b/src/hb-aat-layout.h
index 760aaae..b617e8b 100644
--- a/src/hb-aat-layout.h
+++ b/src/hb-aat-layout.h
@@ -85,7 +85,7 @@
   HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE			= 39,
   HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE		= 103,
 
-  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
+  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_type_t;
 
 /**
@@ -424,7 +424,7 @@
   HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN		= 2,
   HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN		= 3,
 
-  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
+  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_selector_t;
 
 HB_EXTERN unsigned int
diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh
index 8346d9f..8310bfc 100644
--- a/src/hb-aat-layout.hh
+++ b/src/hb-aat-layout.hh
@@ -30,7 +30,7 @@
 #include "hb.hh"
 
 #include "hb-ot-shape.hh"
-
+#include "hb-aat-ltag-table.hh"
 
 struct hb_aat_feature_mapping_t
 {
@@ -39,7 +39,7 @@
   hb_aat_layout_feature_selector_t selectorToEnable;
   hb_aat_layout_feature_selector_t selectorToDisable;
 
-  static int cmp (const void *key_, const void *entry_)
+  HB_INTERNAL static int cmp (const void *key_, const void *entry_)
   {
     hb_tag_t key = * (unsigned int *) key_;
     const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
@@ -77,9 +77,5 @@
 		     hb_font_t *font,
 		     hb_buffer_t *buffer);
 
-HB_INTERNAL hb_language_t
-_hb_aat_language_get (hb_face_t *face,
-		      unsigned int i);
-
 
 #endif /* HB_AAT_LAYOUT_HH */
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 3b00b55..711f9aa 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -50,7 +50,7 @@
   }
 
   protected:
-  OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
 		tag;		/* Offset from the start of the table to
 				 * the beginning of the string */
   HBUINT16	length;		/* String length (in bytes) */
@@ -60,7 +60,7 @@
 
 struct ltag
 {
-  enum { tableTag = HB_AAT_TAG_ltag };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
 
   hb_language_t get_language (unsigned int i) const
   {
diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc
index 1c65a67..bc87935 100644
--- a/src/hb-aat-map.cc
+++ b/src/hb-aat-map.cc
@@ -26,6 +26,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_AAT_SHAPE
+
 #include "hb-aat-map.hh"
 
 #include "hb-aat-layout.hh"
@@ -54,11 +58,11 @@
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 {
   /* Sort features and merge duplicates */
-  if (features.len)
+  if (features.length)
   {
     features.qsort ();
     unsigned int j = 0;
-    for (unsigned int i = 1; i < features.len; i++)
+    for (unsigned int i = 1; i < features.length; i++)
       if (features[i].type != features[j].type)
 	features[++j] = features[i];
     features.shrink (j + 1);
@@ -66,3 +70,6 @@
 
   hb_aat_layout_compile_map (this, &m);
 }
+
+
+#endif
diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh
index fa312db..984a59c 100644
--- a/src/hb-aat-map.hh
+++ b/src/hb-aat-map.hh
@@ -44,7 +44,7 @@
   void fini () { chain_flags.fini (); }
 
   public:
-  hb_vector_t<hb_mask_t, 1> chain_flags;
+  hb_vector_t<hb_mask_t> chain_flags;
 };
 
 struct hb_aat_map_builder_t
@@ -66,7 +66,7 @@
     hb_aat_layout_feature_selector_t  setting;
     unsigned  seq; /* For stable sorting only. */
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const feature_info_t *a = (const feature_info_t *) pa;
       const feature_info_t *b = (const feature_info_t *) pb;
@@ -74,7 +74,7 @@
 	     (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
     }
 
-    int cmp (unsigned int ty) const
+    int cmp (hb_aat_layout_feature_type_t ty) const
     {
       return (type != ty) ? (type < ty ? -1 : 1) : 0;
     }
@@ -84,7 +84,7 @@
   hb_face_t *face;
 
   public:
-  hb_vector_t<feature_info_t, 32> features;
+  hb_sorted_vector_t<feature_info_t> features;
 };
 
 
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
new file mode 100644
index 0000000..042e1c2
--- /dev/null
+++ b/src/hb-algs.hh
@@ -0,0 +1,1059 @@
+/*
+ * Copyright © 2017  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_ALGS_HH
+#define HB_ALGS_HH
+
+#include "hb.hh"
+#include "hb-meta.hh"
+#include "hb-null.hh"
+#include "hb-number.hh"
+
+
+/* Encodes three unsigned integers in one 64-bit number.  If the inputs have more than 21 bits,
+ * values will be truncated / overlap, and might not decode exactly. */
+#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
+#define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42))
+#define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu)
+#define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu)
+
+/* Custom encoding used by hb-ucd. */
+#define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu))
+#define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21))
+#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
+#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
+
+struct
+{
+  /* Note.  This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN ( hb_forward<T> (v) )
+}
+HB_FUNCOBJ (hb_identity);
+struct
+{
+  /* Like identity(), but only retains lvalue-references.  Rvalues are returned as rvalues. */
+  template <typename T> constexpr T&
+  operator () (T& v) const { return v; }
+
+  template <typename T> constexpr hb_remove_reference<T>
+  operator () (T&& v) const { return v; }
+}
+HB_FUNCOBJ (hb_lidentity);
+struct
+{
+  /* Like identity(), but always returns rvalue. */
+  template <typename T> constexpr hb_remove_reference<T>
+  operator () (T&& v) const { return v; }
+}
+HB_FUNCOBJ (hb_ridentity);
+
+struct
+{
+  template <typename T> constexpr bool
+  operator () (T&& v) const { return bool (hb_forward<T> (v)); }
+}
+HB_FUNCOBJ (hb_bool);
+
+struct
+{
+  private:
+
+  template <typename T> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+
+  template <typename T,
+	    hb_enable_if (hb_is_integral (T))> constexpr auto
+  impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    /* Knuth's multiplicative method: */
+    (uint32_t) v * 2654435761u
+  )
+
+  public:
+
+  template <typename T> constexpr auto
+  operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize))
+}
+HB_FUNCOBJ (hb_hash);
+
+
+struct
+{
+  private:
+
+  /* Pointer-to-member-function. */
+  template <typename Appl, typename T, typename ...Ts> auto
+  impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
+  ((hb_deref (hb_forward<T> (v)).*hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+
+  /* Pointer-to-member. */
+  template <typename Appl, typename T> auto
+  impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
+  ((hb_deref (hb_forward<T> (v))).*hb_forward<Appl> (a))
+
+  /* Operator(). */
+  template <typename Appl, typename ...Ts> auto
+  impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+
+  public:
+
+  template <typename Appl, typename ...Ts> auto
+  operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
+  (
+    impl (hb_forward<Appl> (a),
+	  hb_prioritize,
+	  hb_forward<Ts> (ds)...)
+  )
+}
+HB_FUNCOBJ (hb_invoke);
+
+template <unsigned Pos, typename Appl, typename V>
+struct hb_partial_t
+{
+  hb_partial_t (Appl a, V v) : a (a), v (v) {}
+
+  static_assert (Pos > 0, "");
+
+  template <typename ...Ts,
+	    unsigned P = Pos,
+	    hb_enable_if (P == 1)> auto
+  operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
+						   hb_declval (V),
+						   hb_declval (Ts)...))
+  {
+    return hb_invoke (hb_forward<Appl> (a),
+		      hb_forward<V> (v),
+		      hb_forward<Ts> (ds)...);
+  }
+  template <typename T0, typename ...Ts,
+	    unsigned P = Pos,
+	    hb_enable_if (P == 2)> auto
+  operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
+							    hb_declval (T0),
+							    hb_declval (V),
+							    hb_declval (Ts)...))
+  {
+    return hb_invoke (hb_forward<Appl> (a),
+		      hb_forward<T0> (d0),
+		      hb_forward<V> (v),
+		      hb_forward<Ts> (ds)...);
+  }
+
+  private:
+  hb_reference_wrapper<Appl> a;
+  V v;
+};
+template <unsigned Pos=1, typename Appl, typename V>
+auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
+(( hb_partial_t<Pos, Appl, V> (a, v) ))
+
+/* The following, HB_PARTIALIZE, macro uses a particular corner-case
+ * of C++11 that is not particularly well-supported by all compilers.
+ * What's happening is that it's using "this" in a trailing return-type
+ * via decltype().  Broken compilers deduce the type of "this" pointer
+ * in that context differently from what it resolves to in the body
+ * of the function.
+ *
+ * One probable cause of this is that at the time of trailing return
+ * type declaration, "this" points to an incomplete type, whereas in
+ * the function body the type is complete.  That doesn't justify the
+ * error in any way, but is probably what's happening.
+ *
+ * In the case of MSVC, we get around this by using C++14 "decltype(auto)"
+ * which deduces the type from the actual return statement.  For gcc 4.8
+ * we use "+this" instead of "this" which produces an rvalue that seems
+ * to be deduced as the same type with this particular compiler, and seem
+ * to be fine as default code path as well.
+ */
+#ifdef _MSC_VER
+/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
+#define HB_PARTIALIZE(Pos) \
+  template <typename _T> \
+  decltype(auto) operator () (_T&& _v) const \
+  { return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
+  static_assert (true, "")
+#else
+/* https://github.com/harfbuzz/harfbuzz/issues/1724 */
+#define HB_PARTIALIZE(Pos) \
+  template <typename _T> \
+  auto operator () (_T&& _v) const HB_AUTO_RETURN \
+  (hb_partial<Pos> (+this, hb_forward<_T> (_v))) \
+  static_assert (true, "")
+#endif
+
+
+struct
+{
+  private:
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_invoke (hb_forward<Pred> (p),
+	       hb_forward<Val> (v))
+  )
+
+  public:
+
+  template <typename Pred, typename Val> auto
+  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
+    impl (hb_forward<Pred> (p),
+	  hb_forward<Val> (v),
+	  hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_has);
+
+struct
+{
+  private:
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (
+    hb_has (hb_forward<Pred> (p),
+	    hb_forward<Val> (v))
+  )
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_forward<Pred> (p) == hb_forward<Val> (v)
+  )
+
+  public:
+
+  template <typename Pred, typename Val> auto
+  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
+    impl (hb_forward<Pred> (p),
+	  hb_forward<Val> (v),
+	  hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_match);
+
+struct
+{
+  private:
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (
+    hb_invoke (hb_forward<Proj> (f),
+	       hb_forward<Val> (v))
+  )
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_forward<Proj> (f)[hb_forward<Val> (v)]
+  )
+
+  public:
+
+  template <typename Proj, typename Val> auto
+  operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN
+  (
+    impl (hb_forward<Proj> (f),
+	  hb_forward<Val> (v),
+	  hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_get);
+
+
+template <typename T1, typename T2>
+struct hb_pair_t
+{
+  typedef T1 first_t;
+  typedef T2 second_t;
+  typedef hb_pair_t<T1, T2> pair_t;
+
+  hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
+
+  template <typename Q1, typename Q2,
+	    hb_enable_if (hb_is_convertible (T1, Q1) &&
+			  hb_is_convertible (T2, T2))>
+  operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
+
+  hb_pair_t<T1, T2> reverse () const
+  { return hb_pair_t<T1, T2> (second, first); }
+
+  bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
+  bool operator != (const pair_t& o) const { return !(*this == o); }
+  bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); }
+  bool operator >= (const pair_t& o) const { return !(*this < o); }
+  bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
+  bool operator <= (const pair_t& o) const { return !(*this > o); }
+
+  T1 first;
+  T2 second;
+};
+#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
+template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
+hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
+
+struct
+{
+  template <typename Pair> constexpr typename Pair::first_t
+  operator () (const Pair& pair) const { return pair.first; }
+}
+HB_FUNCOBJ (hb_first);
+
+struct
+{
+  template <typename Pair> constexpr typename Pair::second_t
+  operator () (const Pair& pair) const { return pair.second; }
+}
+HB_FUNCOBJ (hb_second);
+
+/* Note.  In min/max impl, we can use hb_type_identity<T> for second argument.
+ * However, that would silently convert between different-signedness integers.
+ * Instead we accept two different types, such that compiler can err if
+ * comparing integers of different signedness. */
+struct
+{
+  template <typename T, typename T2> constexpr auto
+  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
+  (hb_forward<T> (a) <= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+}
+HB_FUNCOBJ (hb_min);
+struct
+{
+  template <typename T, typename T2> constexpr auto
+  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
+  (hb_forward<T> (a) >= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+}
+HB_FUNCOBJ (hb_max);
+
+
+/*
+ * Bithacks.
+ */
+
+/* Return the number of 1 bits in v. */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_popcount (T v)
+{
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return __builtin_popcount (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return __builtin_popcountl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return __builtin_popcountll (v);
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "HACKMEM 169" */
+    uint32_t y;
+    y = (v >> 1) &033333333333;
+    y = v - y - ((y >>1) & 033333333333);
+    return (((y + (y >> 3)) & 030707070707) % 077);
+  }
+
+  if (sizeof (T) == 8)
+  {
+    unsigned int shift = 32;
+    return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
+  }
+
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+/* Returns the number of bits needed to store number */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_bit_storage (T v)
+{
+  if (unlikely (!v)) return 0;
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return sizeof (unsigned int) * 8 - __builtin_clz (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
+#endif
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
+  if (sizeof (T) <= sizeof (unsigned int))
+  {
+    unsigned long where;
+    _BitScanReverse (&where, v);
+    return 1 + where;
+  }
+# if defined(_WIN64)
+  if (sizeof (T) <= 8)
+  {
+    unsigned long where;
+    _BitScanReverse64 (&where, v);
+    return 1 + where;
+  }
+# endif
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "bithacks" */
+    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
+    const unsigned int S[] = {1, 2, 4, 8, 16};
+    unsigned int r = 0;
+    for (int i = 4; i >= 0; i--)
+      if (v & b[i])
+      {
+	v >>= S[i];
+	r |= S[i];
+      }
+    return r + 1;
+  }
+  if (sizeof (T) <= 8)
+  {
+    /* "bithacks" */
+    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
+    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
+    unsigned int r = 0;
+    for (int i = 5; i >= 0; i--)
+      if (v & b[i])
+      {
+	v >>= S[i];
+	r |= S[i];
+      }
+    return r + 1;
+  }
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
+			  hb_bit_storage<uint64_t> ((uint64_t) v);
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+/* Returns the number of zero bits in the least significant side of v */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_ctz (T v)
+{
+  if (unlikely (!v)) return 0;
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return __builtin_ctz (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return __builtin_ctzl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return __builtin_ctzll (v);
+#endif
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
+  if (sizeof (T) <= sizeof (unsigned int))
+  {
+    unsigned long where;
+    _BitScanForward (&where, v);
+    return where;
+  }
+# if defined(_WIN64)
+  if (sizeof (T) <= 8)
+  {
+    unsigned long where;
+    _BitScanForward64 (&where, v);
+    return where;
+  }
+# endif
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "bithacks" */
+    unsigned int c = 32;
+    v &= - (int32_t) v;
+    if (v) c--;
+    if (v & 0x0000FFFF) c -= 16;
+    if (v & 0x00FF00FF) c -= 8;
+    if (v & 0x0F0F0F0F) c -= 4;
+    if (v & 0x33333333) c -= 2;
+    if (v & 0x55555555) c -= 1;
+    return c;
+  }
+  if (sizeof (T) <= 8)
+  {
+    /* "bithacks" */
+    unsigned int c = 64;
+    v &= - (int64_t) (v);
+    if (v) c--;
+    if (v & 0x00000000FFFFFFFFULL) c -= 32;
+    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
+    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
+    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
+    if (v & 0x3333333333333333ULL) c -= 2;
+    if (v & 0x5555555555555555ULL) c -= 1;
+    return c;
+  }
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
+			  hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+
+/*
+ * Tiny stuff.
+ */
+
+/* ASCII tag/character handling */
+static inline bool ISALPHA (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
+static inline bool ISALNUM (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
+static inline unsigned char TOUPPER (unsigned char c)
+{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
+static inline unsigned char TOLOWER (unsigned char c)
+{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
+
+static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
+{ return (a + (b - 1)) / b; }
+
+
+#undef  ARRAY_LENGTH
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+
+static inline int
+hb_memcmp (const void *a, const void *b, unsigned int len)
+{
+  /* It's illegal to pass NULL to memcmp(), even if len is zero.
+   * So, wrap it.
+   * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
+  if (unlikely (!len)) return 0;
+  return memcmp (a, b, len);
+}
+
+static inline void *
+hb_memset (void *s, int c, unsigned int n)
+{
+  /* It's illegal to pass NULL to memset(), even if n is zero. */
+  if (unlikely (!n)) return 0;
+  return memset (s, c, n);
+}
+
+static inline bool
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+{
+  return (size > 0) && (count >= ((unsigned int) -1) / size);
+}
+
+static inline unsigned int
+hb_ceil_to_4 (unsigned int v)
+{
+  return ((v - 1) | 3) + 1;
+}
+
+template <typename T> static inline bool
+hb_in_range (T u, T lo, T hi)
+{
+  static_assert (!hb_is_signed<T>::value, "");
+
+  /* The casts below are important as if T is smaller than int,
+   * the subtract results will become a signed int! */
+  return (T)(u - lo) <= (T)(hi - lo);
+}
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+}
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
+}
+
+
+/*
+ * Sort and search.
+ */
+template <typename ...Ts>
+static inline void *
+hb_bsearch (const void *key, const void *base,
+	    size_t nmemb, size_t size,
+	    int (*compar)(const void *_key, const void *_item, Ts... _ds),
+	    Ts... ds)
+{
+  int min = 0, max = (int) nmemb - 1;
+  while (min <= max)
+  {
+    int mid = ((unsigned int) min + (unsigned int) max) / 2;
+    const void *p = (const void *) (((const char *) base) + (mid * size));
+    int c = compar (key, p, ds...);
+    if (c < 0)
+      max = mid - 1;
+    else if (c > 0)
+      min = mid + 1;
+    else
+      return (void *) p;
+  }
+  return nullptr;
+}
+
+
+/* From https://github.com/noporpoise/sort_r
+   Feb 5, 2019 (c8c65c1e)
+   Modified to support optional argument using templates */
+
+/* Isaac Turner 29 April 2014 Public Domain */
+
+/*
+hb_qsort function to be exported.
+Parameters:
+  base is the array to be sorted
+  nel is the number of elements in the array
+  width is the size in bytes of each element of the array
+  compar is the comparison function
+  arg (optional) is a pointer to be passed to the comparison function
+
+void hb_qsort(void *base, size_t nel, size_t width,
+              int (*compar)(const void *_a, const void *_b, [void *_arg]),
+              [void *arg]);
+*/
+
+#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+
+/* swap a and b */
+/* a and b must not be equal! */
+static inline void sort_r_swap(char *__restrict a, char *__restrict b,
+                               size_t w)
+{
+  char tmp, *end = a+w;
+  for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
+}
+
+/* swap a, b iff a>b */
+/* a and b must not be equal! */
+/* __restrict is same as restrict but better support on old machines */
+template <typename ...Ts>
+static inline int sort_r_cmpswap(char *__restrict a,
+                                 char *__restrict b, size_t w,
+                                 int (*compar)(const void *_a,
+                                               const void *_b,
+                                               Ts... _ds),
+                                 Ts... ds)
+{
+  if(compar(a, b, ds...) > 0) {
+    sort_r_swap(a, b, w);
+    return 1;
+  }
+  return 0;
+}
+
+/*
+Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
+with the smallest swap so that the blocks are in the opposite order. Blocks may
+be internally re-ordered e.g.
+  12345ab  ->   ab34512
+  123abc   ->   abc123
+  12abcde  ->   deabc12
+*/
+static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
+{
+  if(na > 0 && nb > 0) {
+    if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
+    else { sort_r_swap(ptr, ptr+nb, na); }
+  }
+}
+
+/* Implement recursive quicksort ourselves */
+/* Note: quicksort is not stable, equivalent values may be swapped */
+template <typename ...Ts>
+static inline void sort_r_simple(void *base, size_t nel, size_t w,
+                                 int (*compar)(const void *_a,
+                                               const void *_b,
+                                               Ts... _ds),
+                                 Ts... ds)
+{
+  char *b = (char *)base, *end = b + nel*w;
+
+  /* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
+  printf("\n"); */
+
+  if(nel < 10) {
+    /* Insertion sort for arbitrarily small inputs */
+    char *pi, *pj;
+    for(pi = b+w; pi < end; pi += w) {
+      for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
+    }
+  }
+  else
+  {
+    /* nel > 9; Quicksort */
+
+    int cmp;
+    char *pl, *ple, *pr, *pre, *pivot;
+    char *last = b+w*(nel-1), *tmp;
+
+    /*
+    Use median of second, middle and second-last items as pivot.
+    First and last may have been swapped with pivot and therefore be extreme
+    */
+    char *l[3];
+    l[0] = b + w;
+    l[1] = b+w*(nel/2);
+    l[2] = last - w;
+
+    /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
+
+    if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
+    if(compar(l[1],l[2],ds...) > 0) {
+      SORT_R_SWAP(l[1], l[2], tmp);
+      if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
+    }
+
+    /* swap mid value (l[1]), and last element to put pivot as last element */
+    if(l[1] != last) { sort_r_swap(l[1], last, w); }
+
+    /*
+    pl is the next item on the left to be compared to the pivot
+    pr is the last item on the right that was compared to the pivot
+    ple is the left position to put the next item that equals the pivot
+    ple is the last right position where we put an item that equals the pivot
+                                           v- end (beyond the array)
+      EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
+      ^- b  ^- ple  ^- pl   ^- pr  ^- pre ^- last (where the pivot is)
+    Pivot comparison key:
+      E = equal, L = less than, u = unknown, G = greater than, E = equal
+    */
+    pivot = last;
+    ple = pl = b;
+    pre = pr = last;
+
+    /*
+    Strategy:
+    Loop into the list from the left and right at the same time to find:
+    - an item on the left that is greater than the pivot
+    - an item on the right that is less than the pivot
+    Once found, they are swapped and the loop continues.
+    Meanwhile items that are equal to the pivot are moved to the edges of the
+    array.
+    */
+    while(pl < pr) {
+      /* Move left hand items which are equal to the pivot to the far left.
+         break when we find an item that is greater than the pivot */
+      for(; pl < pr; pl += w) {
+        cmp = compar(pl, pivot, ds...);
+        if(cmp > 0) { break; }
+        else if(cmp == 0) {
+          if(ple < pl) { sort_r_swap(ple, pl, w); }
+          ple += w;
+        }
+      }
+      /* break if last batch of left hand items were equal to pivot */
+      if(pl >= pr) { break; }
+      /* Move right hand items which are equal to the pivot to the far right.
+         break when we find an item that is less than the pivot */
+      for(; pl < pr; ) {
+        pr -= w; /* Move right pointer onto an unprocessed item */
+        cmp = compar(pr, pivot, ds...);
+        if(cmp == 0) {
+          pre -= w;
+          if(pr < pre) { sort_r_swap(pr, pre, w); }
+        }
+        else if(cmp < 0) {
+          if(pl < pr) { sort_r_swap(pl, pr, w); }
+          pl += w;
+          break;
+        }
+      }
+    }
+
+    pl = pr; /* pr may have gone below pl */
+
+    /*
+    Now we need to go from: EEELLLGGGGEEEE
+                        to: LLLEEEEEEEGGGG
+    Pivot comparison key:
+      E = equal, L = less than, u = unknown, G = greater than, E = equal
+    */
+    sort_r_swap_blocks(b, ple-b, pl-ple);
+    sort_r_swap_blocks(pr, pre-pr, end-pre);
+
+    /*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
+    printf("\n");*/
+
+    sort_r_simple(b, (pl-ple)/w, w, compar, ds...);
+    sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...);
+  }
+}
+
+static inline void
+hb_qsort (void *base, size_t nel, size_t width,
+	  int (*compar)(const void *_a, const void *_b))
+{
+#if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
+  qsort (base, nel, width, compar);
+#else
+  sort_r_simple (base, nel, width, compar);
+#endif
+}
+
+static inline void
+hb_qsort (void *base, size_t nel, size_t width,
+	  int (*compar)(const void *_a, const void *_b, void *_arg),
+	  void *arg)
+{
+#ifdef HAVE_GNU_QSORT_R
+  qsort_r (base, nel, width, compar, arg);
+#else
+  sort_r_simple (base, nel, width, compar, arg);
+#endif
+}
+
+
+template <typename T, typename T2, typename T3> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
+{
+  for (unsigned int i = 1; i < len; i++)
+  {
+    unsigned int j = i;
+    while (j && compar (&array[j - 1], &array[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    {
+      T t = array[i];
+      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
+      array[j] = t;
+    }
+    if (array2)
+    {
+      T3 t = array2[i];
+      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
+      array2[j] = t;
+    }
+  }
+}
+
+template <typename T> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+  hb_stable_sort (array, len, compar, (int *) nullptr);
+}
+
+static inline hb_bool_t
+hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
+{
+  unsigned int v;
+  const char *p = s;
+  const char *end = p + len;
+  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base)))
+    return false;
+
+  *out = v;
+  return true;
+}
+
+
+/* Operators. */
+
+struct hb_bitwise_and
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = false;
+  static constexpr bool passthru_right = false;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
+}
+HB_FUNCOBJ (hb_bitwise_and);
+struct hb_bitwise_or
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
+}
+HB_FUNCOBJ (hb_bitwise_or);
+struct hb_bitwise_xor
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
+}
+HB_FUNCOBJ (hb_bitwise_xor);
+struct hb_bitwise_sub
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = false;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
+}
+HB_FUNCOBJ (hb_bitwise_sub);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (~a)
+}
+HB_FUNCOBJ (hb_bitwise_neg);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
+}
+HB_FUNCOBJ (hb_add);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
+}
+HB_FUNCOBJ (hb_sub);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
+}
+HB_FUNCOBJ (hb_mul);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
+}
+HB_FUNCOBJ (hb_div);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
+}
+HB_FUNCOBJ (hb_mod);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (+a)
+}
+HB_FUNCOBJ (hb_pos);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (-a)
+}
+HB_FUNCOBJ (hb_neg);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T &a) const HB_AUTO_RETURN (++a)
+}
+HB_FUNCOBJ (hb_inc);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T &a) const HB_AUTO_RETURN (--a)
+}
+HB_FUNCOBJ (hb_dec);
+
+
+/* Compiler-assisted vectorization. */
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
+ * basically a fixed-size bitset. */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+  elt_t& operator [] (unsigned int i) { return v[i]; }
+  const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
+
+  template <typename Op>
+  hb_vector_size_t process (const Op& op) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i]);
+    return r;
+  }
+  template <typename Op>
+  hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i], o.v[i]);
+    return r;
+  }
+  hb_vector_size_t operator | (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_or, o); }
+  hb_vector_size_t operator & (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_and, o); }
+  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_xor, o); }
+  hb_vector_size_t operator ~ () const
+  { return process (hb_bitwise_neg); }
+
+  private:
+  static_assert (0 == byte_size % sizeof (elt_t), "");
+  elt_t v[byte_size / sizeof (elt_t)];
+};
+
+
+#endif /* HB_ALGS_HH */
diff --git a/src/hb-array.hh b/src/hb-array.hh
index d4df165..d9adf2c 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -28,90 +28,108 @@
 #define HB_ARRAY_HH
 
 #include "hb.hh"
+#include "hb-algs.hh"
+#include "hb-iter.hh"
+#include "hb-null.hh"
 
 
 template <typename Type>
 struct hb_sorted_array_t;
 
 template <typename Type>
-struct hb_array_t
+struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 {
-  typedef Type ItemType;
-  enum { item_size = hb_static_size (Type) };
-
   /*
    * Constructors.
    */
-  hb_array_t () : arrayZ (nullptr), len (0) {}
-  hb_array_t (const hb_array_t &o) : arrayZ (o.arrayZ), len (o.len) {}
-  hb_array_t (Type *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
-  template <unsigned int len_> hb_array_t (Type (&array_)[len_]) : arrayZ (array_), len (len_) {}
+  hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
+  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
+  template <unsigned int length_>
+  hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
+
+  template <typename U,
+	    hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_array_t (const hb_array_t<U> &o) :
+    hb_iter_with_fallback_t<hb_array_t, Type&> (),
+    arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
+  template <typename U,
+	    hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_array_t& operator = (const hb_array_t<U> &o)
+  { arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
 
   /*
-   * Operators.
+   * Iterator implementation.
    */
-
-  Type& operator [] (int i_) const
+  typedef Type& __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  Type& __item_at__ (unsigned i) const
   {
-    unsigned int i = (unsigned int) i_;
-    if (unlikely (i >= len)) return CrapOrNull(Type);
+    if (unlikely (i >= length)) return CrapOrNull (Type);
     return arrayZ[i];
   }
+  void __forward__ (unsigned n)
+  {
+    if (unlikely (n > length))
+      n = length;
+    length -= n;
+    backwards_length += n;
+    arrayZ += n;
+  }
+  void __rewind__ (unsigned n)
+  {
+    if (unlikely (n > backwards_length))
+      n = backwards_length;
+    length += n;
+    backwards_length -= n;
+    arrayZ -= n;
+  }
+  unsigned __len__ () const { return length; }
+  /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
+   * it's best if we can just compare arrayZ, though comparing contents is still fast,
+   * but also would require that Type has operator==.  As such, we optimize this operator
+   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
+   * assume we're only compared to .end(). */
+  bool operator != (const hb_array_t& o) const
+  { return arrayZ != o.arrayZ; }
 
-  explicit_operator bool () const { return len; }
+  /* Extra operators.
+   */
   Type * operator & () const { return arrayZ; }
-  Type & operator * () { return (this->operator [])[0]; }
-  operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, len); }
+  operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
   template <typename T> operator T * () const { return arrayZ; }
 
-  hb_array_t<Type> & operator += (unsigned int count)
-  {
-    if (unlikely (count > len))
-      count = len;
-    len -= count;
-    arrayZ += count;
-    return *this;
+  HB_INTERNAL bool operator == (const hb_array_t &o) const;
+
+  uint32_t hash () const {
+    uint32_t current = 0;
+    for (unsigned int i = 0; i < this->length; i++) {
+      current = current * 31 + hb_hash (this->arrayZ[i]);
+    }
+    return current;
   }
-  hb_array_t<Type> & operator -= (unsigned int count)
-  {
-    if (unlikely (count > len))
-      count = len;
-    len -= count;
-    return *this;
-  }
-  hb_array_t<Type> & operator ++ () { *this += 1; }
-  hb_array_t<Type> & operator -- () { *this -= 1; }
-  hb_array_t<Type> operator + (unsigned int count)
-  { hb_array_t<Type> copy (*this); *this += count; return copy; }
-  hb_array_t<Type> operator - (unsigned int count)
-  { hb_array_t<Type> copy (*this); *this -= count; return copy; }
-  hb_array_t<Type>  operator ++ (int)
-  { hb_array_t<Type> copy (*this); ++*this; return copy; }
-  hb_array_t<Type>  operator -- (int)
-  { hb_array_t<Type> copy (*this); --*this; return copy; }
 
   /*
    * Compare, Sort, and Search.
    */
 
   /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
-  int cmp (const hb_array_t<Type> &a) const
+  int cmp (const hb_array_t &a) const
   {
-    if (len != a.len)
-      return (int) a.len - (int) len;
+    if (length != a.length)
+      return (int) a.length - (int) length;
     return hb_memcmp (a.arrayZ, arrayZ, get_size ());
   }
-  static int cmp (const void *pa, const void *pb)
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
   {
-    hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
-    hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
+    hb_array_t *a = (hb_array_t *) pa;
+    hb_array_t *b = (hb_array_t *) pb;
     return b->cmp (*a);
   }
 
   template <typename T>
   Type *lsearch (const T &x, Type *not_found = nullptr)
   {
-    unsigned int count = len;
+    unsigned int count = length;
     for (unsigned int i = 0; i < count; i++)
       if (!this->arrayZ[i].cmp (x))
 	return &this->arrayZ[i];
@@ -120,7 +138,7 @@
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   {
-    unsigned int count = len;
+    unsigned int count = length;
     for (unsigned int i = 0; i < count; i++)
       if (!this->arrayZ[i].cmp (x))
 	return &this->arrayZ[i];
@@ -129,51 +147,82 @@
 
   hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
   {
-    ::qsort (arrayZ, len, item_size, cmp_);
+    if (likely (length))
+      hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
     return hb_sorted_array_t<Type> (*this);
   }
   hb_sorted_array_t<Type> qsort ()
   {
-    ::qsort (arrayZ, len, item_size, Type::cmp);
+    if (likely (length))
+      hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
     return hb_sorted_array_t<Type> (*this);
   }
   void qsort (unsigned int start, unsigned int end)
   {
-    end = MIN (end, len);
+    end = hb_min (end, length);
     assert (start <= end);
-    ::qsort (arrayZ + start, end - start, item_size, Type::cmp);
+    if (likely (start < end))
+      hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
   }
 
   /*
    * Other methods.
    */
 
-  unsigned int get_size () const { return len * item_size; }
+  unsigned int get_size () const { return length * this->get_item_size (); }
 
-  hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
+  hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
   {
     if (!start_offset && !seg_count)
       return *this;
 
-    unsigned int count = len;
+    unsigned int count = length;
     if (unlikely (start_offset > count))
       count = 0;
     else
       count -= start_offset;
     if (seg_count)
-      count = *seg_count = MIN (count, *seg_count);
-    return hb_array_t<Type> (arrayZ + start_offset, count);
+      count = *seg_count = hb_min (count, *seg_count);
+    return hb_array_t (arrayZ + start_offset, count);
   }
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
   { return sub_array (start_offset, &seg_count); }
 
+  hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
+
+  template <typename T,
+	    unsigned P = sizeof (Type),
+	    hb_enable_if (P == 1)>
+  const T *as () const
+  { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
+
+  template <typename T,
+	    unsigned P = sizeof (Type),
+	    hb_enable_if (P == 1)>
+  bool in_range (const T *p, unsigned int size = T::static_size) const
+  {
+    return ((const char *) p) >= arrayZ
+	&& ((const char *) p + size) <= arrayZ + length;
+  }
+
   /* Only call if you allocated the underlying array using malloc() or similar. */
   void free ()
-  { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
+  { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
+
+  template <typename hb_serialize_context_t>
+  hb_array_t copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto* out = c->start_embed (arrayZ);
+    if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
+    for (unsigned i = 0; i < length; i++)
+      out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
+    return_trace (hb_array_t (out, length));
+  }
 
   template <typename hb_sanitize_context_t>
   bool sanitize (hb_sanitize_context_t *c) const
-  { return c->check_array (arrayZ, len); }
+  { return c->check_array (arrayZ, length); }
 
   /*
    * Members
@@ -181,12 +230,15 @@
 
   public:
   Type *arrayZ;
-  unsigned int len;
+  unsigned int length;
+  unsigned int backwards_length;
 };
-template <typename T>
-inline hb_array_t<T> hb_array (T *array, unsigned int len)
-{ return hb_array_t<T> (array, len); }
-
+template <typename T> inline hb_array_t<T>
+hb_array (T *array, unsigned int length)
+{ return hb_array_t<T> (array, length); }
+template <typename T, unsigned int length_> inline hb_array_t<T>
+hb_array (T (&array_)[length_])
+{ return hb_array_t<T> (array_); }
 
 enum hb_bfind_not_found_t
 {
@@ -196,17 +248,41 @@
 };
 
 template <typename Type>
-struct hb_sorted_array_t : hb_array_t<Type>
+struct hb_sorted_array_t :
+	hb_iter_t<hb_sorted_array_t<Type>, Type&>,
+	hb_array_t<Type>
 {
-  hb_sorted_array_t () : hb_array_t<Type> () {}
-  hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
-  hb_sorted_array_t (Type *array_, unsigned int len_) : hb_array_t<Type> (array_, len_) {}
+  typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
+  HB_ITER_USING (iter_base_t);
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
 
-  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
-  { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
-  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  hb_sorted_array_t () : hb_array_t<Type> () {}
+  hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
+  template <unsigned int length_>
+  hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
+
+  template <typename U,
+	    hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_sorted_array_t (const hb_array_t<U> &o) :
+    hb_iter_t<hb_sorted_array_t, Type&> (),
+    hb_array_t<Type> (o) {}
+  template <typename U,
+	    hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_sorted_array_t& operator = (const hb_array_t<U> &o)
+  { hb_array_t<Type> (*this) = o; return *this; }
+
+  /* Iterator implementation. */
+  bool operator != (const hb_sorted_array_t& o) const
+  { return this->arrayZ != o.arrayZ || this->length != o.length; }
+
+  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
+  { return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
+  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
   { return sub_array (start_offset, &seg_count); }
 
+  hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
+
   template <typename T>
   Type *bsearch (const T &x, Type *not_found = nullptr)
   {
@@ -221,19 +297,19 @@
   }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-		     unsigned int to_store = (unsigned int) -1) const
+	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
   {
-    int min = 0, max = (int) this->len - 1;
+    int min = 0, max = (int) this->length - 1;
     const Type *array = this->arrayZ;
     while (min <= max)
     {
       int mid = ((unsigned int) min + (unsigned int) max) / 2;
       int c = array[mid].cmp (x);
       if (c < 0)
-        max = mid - 1;
+	max = mid - 1;
       else if (c > 0)
-        min = mid + 1;
+	min = mid + 1;
       else
       {
 	if (i)
@@ -253,7 +329,7 @@
 	  break;
 
 	case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
-	  if (max < 0 || (max < (int) this->len && array[max].cmp (x) > 0))
+	  if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
 	    max++;
 	  *i = max;
 	  break;
@@ -262,13 +338,45 @@
     return false;
   }
 };
+template <typename T> inline hb_sorted_array_t<T>
+hb_sorted_array (T *array, unsigned int length)
+{ return hb_sorted_array_t<T> (array, length); }
+template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
+hb_sorted_array (T (&array_)[length_])
+{ return hb_sorted_array_t<T> (array_); }
+
 template <typename T>
-inline hb_sorted_array_t<T> hb_sorted_array (T *array, unsigned int len)
-{ return hb_sorted_array_t<T> (array, len); }
+bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
+{
+  if (o.length != this->length) return false;
+  for (unsigned int i = 0; i < this->length; i++) {
+    if (this->arrayZ[i] != o.arrayZ[i]) return false;
+  }
+  return true;
+}
+
+/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
+
+template <>
+inline uint32_t hb_array_t<const char>::hash () const {
+  uint32_t current = 0;
+  for (unsigned int i = 0; i < this->length; i++)
+    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+  return current;
+}
+
+template <>
+inline uint32_t hb_array_t<const unsigned char>::hash () const {
+  uint32_t current = 0;
+  for (unsigned int i = 0; i < this->length; i++)
+    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+  return current;
+}
 
 
 typedef hb_array_t<const char> hb_bytes_t;
 typedef hb_array_t<const unsigned char> hb_ubytes_t;
 
 
+
 #endif /* HB_ARRAY_HH */
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index 9321932..b3fb296 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -33,6 +33,7 @@
 #define HB_ATOMIC_HH
 
 #include "hb.hh"
+#include "hb-meta.hh"
 
 
 /*
@@ -85,11 +86,11 @@
 #define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
 #define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_int_impl_set(AI, V)		(reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
-#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
+#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
 
 #define hb_atomic_ptr_impl_set_relaxed(P, V)	(reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
-#define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
+#define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get(P)		(reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
 static inline bool
 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
@@ -106,7 +107,7 @@
 
 static inline void _hb_memory_barrier ()
 {
-#if !defined(MemoryBarrier)
+#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
   /* MinGW has a convoluted history of supporting MemoryBarrier. */
   LONG dummy = 0;
   InterlockedExchange (&dummy, 1);
@@ -184,7 +185,7 @@
 #endif
 
 
-#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
+#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
 
 #include <builtins.h>
 
@@ -211,25 +212,19 @@
 static_assert ((sizeof (long) == sizeof (void *)), "");
 
 
-#elif !defined(HB_NO_MT)
-
-#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
-
-#define _hb_memory_barrier()
+#elif defined(HB_NO_MT)
 
 #define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
 
+#define _hb_memory_barrier()			do {} while (0)
+
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
 
-#else /* HB_NO_MT */
+#else
 
-#define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
-
-#define _hb_memory_barrier()
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
-
+#error "Could not find any system to define atomic_int macros."
+#error "Check hb-atomic.hh for possible resolutions."
 
 #endif
 
@@ -282,7 +277,7 @@
 template <typename P>
 struct hb_atomic_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   void init (T* v_ = nullptr) { set_relaxed (v_); }
   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/src/hb-bimap.hh b/src/hb-bimap.hh
new file mode 100644
index 0000000..cae0a4d
--- /dev/null
+++ b/src/hb-bimap.hh
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_BIMAP_HH
+#define HB_BIMAP_HH
+
+#include "hb.hh"
+#include "hb-map.hh"
+
+/* Bi-directional map */
+struct hb_bimap_t
+{
+  hb_bimap_t () { init (); }
+  ~hb_bimap_t () { fini (); }
+
+  void init ()
+  {
+    forw_map.init ();
+    back_map.init ();
+  }
+
+  void fini ()
+  {
+    forw_map.fini ();
+    back_map.fini ();
+  }
+
+  void reset ()
+  {
+    forw_map.reset ();
+    back_map.reset ();
+  }
+
+  bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+  void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
+  {
+    if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
+    if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
+    forw_map.set (lhs, rhs);
+    back_map.set (rhs, lhs);
+  }
+
+  hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+  hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
+
+  hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+  bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
+
+  void del (hb_codepoint_t lhs)
+  {
+    back_map.del (get (lhs));
+    forw_map.del (lhs);
+  }
+
+  void clear ()
+  {
+    forw_map.clear ();
+    back_map.clear ();
+  }
+
+  bool is_empty () const { return get_population () == 0; }
+
+  unsigned int get_population () const { return forw_map.get_population (); }
+
+  protected:
+  hb_map_t  forw_map;
+  hb_map_t  back_map;
+};
+
+/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
+struct hb_inc_bimap_t : hb_bimap_t
+{
+  hb_inc_bimap_t () { init (); }
+
+  void init ()
+  {
+    hb_bimap_t::init ();
+    next_value = 0;
+  }
+
+  /* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
+   * Return the rhs value as the result.
+   */
+  hb_codepoint_t add (hb_codepoint_t lhs)
+  {
+    hb_codepoint_t  rhs = forw_map[lhs];
+    if (rhs == HB_MAP_VALUE_INVALID)
+    {
+      rhs = next_value++;
+      set (lhs, rhs);
+    }
+    return rhs;
+  }
+
+  hb_codepoint_t skip ()
+  { return next_value++; }
+
+  hb_codepoint_t get_next_value () const
+  { return next_value; }
+
+  void add_set (const hb_set_t *set)
+  {
+    hb_codepoint_t i = HB_SET_VALUE_INVALID;
+    while (hb_set_next (set, &i)) add (i);
+  }
+
+  /* Create an identity map. */
+  bool identity (unsigned int size)
+  {
+    clear ();
+    for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+    return !in_error ();
+  }
+
+  protected:
+  static int cmp_id (const void* a, const void* b)
+  { return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
+
+  public:
+  /* Optional: after finished adding all mappings in a random order,
+   * reassign rhs to lhs so that they are in the same order. */
+  void sort ()
+  {
+    hb_codepoint_t  count = get_population ();
+    hb_vector_t <hb_codepoint_t> work;
+    work.resize (count);
+
+    for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
+      work[rhs] = back_map[rhs];
+  
+    work.qsort (cmp_id);
+  
+    clear ();
+    for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
+      set (work[rhs], rhs);
+  }
+
+  protected:
+  unsigned int	next_value;
+};
+
+#endif /* HB_BIMAP_HH */
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index b53b20b..2e72683 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -25,6 +25,18 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+
+/* https://github.com/harfbuzz/harfbuzz/issues/1308
+ * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
+ * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
+ */
+#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#define _POSIX_C_SOURCE 200809L
+#pragma GCC diagnostic pop
+#endif
+
 #include "hb.hh"
 #include "hb-blob.hh"
 
@@ -36,7 +48,6 @@
 #endif /* HAVE_SYS_MMAN_H */
 
 #include <stdio.h>
-#include <errno.h>
 #include <stdlib.h>
 
 
@@ -143,7 +154,7 @@
   hb_blob_make_immutable (parent);
 
   blob = hb_blob_create (parent->data + offset,
-			 MIN (length, parent->length - offset),
+			 hb_min (length, parent->length - offset),
 			 HB_MEMORY_MODE_READONLY,
 			 hb_blob_reference (parent),
 			 _hb_blob_destroy);
@@ -475,6 +486,7 @@
  * Mmap
  */
 
+#ifndef HB_NO_OPEN
 #ifdef HAVE_MMAP
 # include <sys/types.h>
 # include <sys/stat.h>
@@ -579,7 +591,7 @@
     ceparams.lpSecurityAttributes = nullptr;
     ceparams.hTemplateFile = nullptr;
     fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
-                      OPEN_EXISTING, &ceparams);
+		      OPEN_EXISTING, &ceparams);
   }
 #else
   fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
@@ -656,7 +668,7 @@
   }
 
   return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
-                         (hb_destroy_func_t) free);
+			 (hb_destroy_func_t) free);
 
 fread_fail:
   fclose (fp);
@@ -664,3 +676,4 @@
   free (data);
   return hb_blob_get_empty ();
 }
+#endif /* !HB_NO_OPEN */
diff --git a/src/hb-blob.h b/src/hb-blob.h
index d1d9134..f80e9af 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -71,6 +71,9 @@
 		void              *user_data,
 		hb_destroy_func_t  destroy);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_from_file (const char *file_name);
+
 /* Always creates with MEMORY_MODE_READONLY.
  * Even if the parent blob is writable, we don't
  * want the user of the sub-blob to be able to
@@ -123,9 +126,6 @@
 HB_EXTERN char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
 
-HB_EXTERN hb_blob_t *
-hb_blob_create_from_file (const char *file_name);
-
 HB_END_DECLS
 
 #endif /* HB_BLOB_H */
diff --git a/src/hb-blob.hh b/src/hb-blob.hh
index 4ea13f8..d85bd82 100644
--- a/src/hb-blob.hh
+++ b/src/hb-blob.hh
@@ -54,13 +54,9 @@
   HB_INTERNAL bool try_make_writable_inplace ();
   HB_INTERNAL bool try_make_writable_inplace_unix ();
 
+  hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); }
   template <typename Type>
-  const Type* as () const
-  {
-    return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast<const Type *> (data);
-  }
-  hb_bytes_t as_bytes () const
-  { return hb_bytes_t (data, length); }
+  const Type* as () const { return as_bytes ().as<Type> (); }
 
   public:
   hb_object_header_t header;
@@ -81,7 +77,7 @@
 template <typename P>
 struct hb_blob_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
   hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 6e265e8..e64eb0e 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_BUFFER_SERIALIZE
+
 #include "hb-buffer.hh"
 
 
@@ -85,7 +89,7 @@
 const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
 {
-  switch (format)
+  switch ((unsigned) format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
@@ -131,41 +135,41 @@
       hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
       *p++ = '"';
       for (char *q = g; *q; q++) {
-        if (*q == '"')
+	if (*q == '"')
 	  *p++ = '\\';
 	*p++ = *q;
       }
       *p++ = '"';
     }
     else
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
 			     x+pos[i].x_offset, y+pos[i].y_offset));
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
 			       pos[i].x_advance, pos[i].y_advance));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
 		extents.x_bearing, extents.y_bearing));
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
 		extents.width, extents.height));
     }
 
@@ -224,37 +228,37 @@
       p += strlen (p);
     }
     else
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       if (x+pos[i].x_offset || y+pos[i].y_offset)
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
 
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
       {
 	*p++ = '+';
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
 	if (pos[i].y_advance)
-	  p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+	  p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
       }
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
+	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
     }
 
     unsigned int l = p - b;
@@ -375,43 +379,24 @@
   }
 }
 
-
-static hb_bool_t
-parse_uint (const char *pp, const char *end, uint32_t *pv)
+static bool
+parse_int (const char *pp, const char *end, int32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  uint32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
+  int v;
+  const char *p = pp;
+  if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
     return false;
 
   *pv = v;
   return true;
 }
 
-static hb_bool_t
-parse_int (const char *pp, const char *end, int32_t *pv)
+static bool
+parse_uint (const char *pp, const char *end, uint32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  int32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
+  unsigned int v;
+  const char *p = pp;
+  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
     return false;
 
   *pv = v;
@@ -484,3 +469,6 @@
 
   }
 }
+
+
+#endif
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 2dc02e9..6131c86 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -324,7 +324,7 @@
   out_len = 0;
   out_info = info;
 
-  memset (pos, 0, sizeof (pos[0]) * len);
+  hb_memset (pos, 0, sizeof (pos[0]) * len);
 }
 
 void
@@ -524,7 +524,7 @@
   unsigned int cluster = info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN<unsigned int> (cluster, info[i].cluster);
+    cluster = hb_min (cluster, info[i].cluster);
 
   /* Extend end */
   while (end < len && info[end - 1].cluster == info[end].cluster)
@@ -555,7 +555,7 @@
   unsigned int cluster = out_info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
+    cluster = hb_min (cluster, out_info[i].cluster);
 
   /* Extend start */
   while (start && out_info[start - 1].cluster == out_info[start].cluster)
@@ -648,8 +648,8 @@
       if (likely (script != HB_SCRIPT_COMMON &&
 		  script != HB_SCRIPT_INHERITED &&
 		  script != HB_SCRIPT_UNKNOWN)) {
-        props.script = script;
-        break;
+	props.script = script;
+	break;
       }
     }
   }
@@ -776,8 +776,10 @@
 
   free (buffer->info);
   free (buffer->pos);
+#ifndef HB_NO_BUFFER_MESSAGE
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
+#endif
 
   free (buffer);
 }
@@ -1388,7 +1390,7 @@
  **/
 hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
-                           unsigned int *length)
+			   unsigned int *length)
 {
   if (length)
     *length = buffer->len;
@@ -1412,7 +1414,7 @@
  **/
 hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
-                               unsigned int *length)
+			       unsigned int *length)
 {
   if (!buffer->have_positions)
     buffer->clear_positions ();
@@ -1936,9 +1938,9 @@
     for (i = 0; i < count; i++)
     {
       if (contains && info[i].codepoint == dottedcircle_glyph)
-        result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
+	result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
       if (contains && info[i].codepoint == 0)
-        result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
+	result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
     }
     result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
     return hb_buffer_diff_flags_t (result);
@@ -1973,12 +1975,12 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
-          (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
-          (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
-          (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
+	  (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
+	  (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
+	  (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
       {
-        result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
-        break;
+	result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
+	break;
       }
       buf_pos++;
       ref_pos++;
@@ -1993,6 +1995,7 @@
  * Debugging.
  */
 
+#ifndef HB_NO_BUFFER_MESSAGE
 /**
  * hb_buffer_set_message_func:
  * @buffer: an #hb_buffer_t.
@@ -2022,11 +2025,11 @@
     buffer->message_destroy = nullptr;
   }
 }
-
 bool
 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
 {
   char buf[100];
-  vsnprintf (buf, sizeof (buf),  fmt, ap);
+  vsnprintf (buf, sizeof (buf), fmt, ap);
   return (bool) this->message_func (this, font, buf, this->message_data);
 }
+#endif
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index f989d25..d5cb746 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -284,6 +284,10 @@
  *                      space glyph and zeroing the advance width.)
  *                      @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
  *                      precedence over this flag. Since: 1.8.0
+ * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
+ *                      flag indicating that a dotted circle should
+ *                      not be inserted in the rendering of incorrect
+ *                      character sequences (such at <0905 093E>). Since: 2.4
  *
  * Since: 0.9.20
  */
@@ -292,7 +296,8 @@
   HB_BUFFER_FLAG_BOT				= 0x00000001u, /* Beginning-of-text */
   HB_BUFFER_FLAG_EOT				= 0x00000002u, /* End-of-text */
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u,
-  HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES	= 0x00000008u
+  HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES	= 0x00000008u,
+  HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE	= 0x00000010u
 } hb_buffer_flags_t;
 
 HB_EXTERN void
@@ -436,11 +441,11 @@
 
 HB_EXTERN hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
-                           unsigned int *length);
+			   unsigned int *length);
 
 HB_EXTERN hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
-                               unsigned int *length);
+			       unsigned int *length);
 
 
 HB_EXTERN void
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index 8a3170c..b5596d9 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -119,14 +119,16 @@
   /* Text before / after the main buffer contents.
    * Always in Unicode, and ordered outward.
    * Index 0 is for "pre-context", 1 for "post-context". */
-  enum { CONTEXT_LENGTH = 5 };
+  static constexpr unsigned CONTEXT_LENGTH = 5u;
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
   /* Debugging API */
+#ifndef HB_NO_BUFFER_MESSAGE
   hb_buffer_message_func_t message_func;
   void *message_data;
   hb_destroy_func_t message_destroy;
+#endif
 
   /* Internal debugging. */
   /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
@@ -347,9 +349,19 @@
 
   HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
 
-  bool messaging () { return unlikely (message_func); }
+  bool messaging ()
+  {
+#ifdef HB_NO_BUFFER_MESSAGE
+    return false;
+#else
+    return unlikely (message_func);
+#endif
+  }
   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
   {
+#ifdef HB_NO_BUFFER_MESSAGE
+   return true;
+#else
     if (!messaging ())
       return true;
     va_list ap;
@@ -357,6 +369,7 @@
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
     return ret;
+#endif
   }
   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
 
@@ -379,7 +392,7 @@
 				     unsigned int cluster) const
   {
     for (unsigned int i = start; i < end; i++)
-      cluster = MIN<unsigned int> (cluster, infos[i].cluster);
+      cluster = hb_min (cluster, infos[i].cluster);
     return cluster;
   }
   void
@@ -395,8 +408,7 @@
       }
   }
 
-  void unsafe_to_break_all ()
-  { unsafe_to_break_impl (0, len); }
+  void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
   void safe_to_break_all ()
   {
     for (unsigned int i = 0; i < len; i++)
diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh
index c2be034..780f618 100644
--- a/src/hb-cff-interp-common.hh
+++ b/src/hb-cff-interp-common.hh
@@ -30,7 +30,7 @@
 
 using namespace OT;
 
-typedef unsigned int OpCode;
+typedef unsigned int op_code_t;
 
 
 /* === Dict operators === */
@@ -88,11 +88,11 @@
 
 /* Two byte escape operators 12, (0-41) */
 #define OpCode_ESC_Base		256
-#define Make_OpCode_ESC(byte2)	((OpCode)(OpCode_ESC_Base + (byte2)))
+#define Make_OpCode_ESC(byte2)	((op_code_t)(OpCode_ESC_Base + (byte2)))
 
-inline OpCode Unmake_OpCode_ESC (OpCode op)  { return (OpCode)(op - OpCode_ESC_Base); }
-inline bool Is_OpCode_ESC (OpCode op) { return op >= OpCode_ESC_Base; }
-inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op) ? 2: 1; }
+inline op_code_t Unmake_OpCode_ESC (op_code_t op)  { return (op_code_t)(op - OpCode_ESC_Base); }
+inline bool Is_OpCode_ESC (op_code_t op) { return op >= OpCode_ESC_Base; }
+inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: 1; }
 
 #define OpCode_Copyright	Make_OpCode_ESC(0) /* CFF Top */
 #define OpCode_isFixedPitch	Make_OpCode_ESC(1) /* CFF Top (false) */
@@ -215,39 +215,29 @@
 #define OpCode_Invalid		0xFFFFu
 
 
-struct Number
+struct number_t
 {
   void init () { set_real (0.0); }
   void fini () {}
 
-  void set_int (int v)       { value = (double) v; }
-  int to_int () const        { return (int) value; }
+  void set_int (int v)       { value = v; }
+  int to_int () const        { return value; }
 
   void set_fixed (int32_t v) { value = v / 65536.0; }
-  int32_t to_fixed () const  { return (int32_t) (value * 65536.0); }
+  int32_t to_fixed () const  { return value * 65536.0; }
 
-  void set_real (double v)	 { value = v; }
+  void set_real (double v)   { value = v; }
   double to_real () const    { return value; }
 
-  int ceil () const          { return (int) ::ceil (value); }
-  int floor () const         { return (int) ::floor (value); }
-
   bool in_int_range () const
   { return ((double) (int16_t) to_int () == value); }
 
-  bool operator > (const Number &n) const
-  { return value > n.to_real (); }
+  bool operator >  (const number_t &n) const { return value > n.to_real (); }
+  bool operator <  (const number_t &n) const { return n > *this; }
+  bool operator >= (const number_t &n) const { return !(*this < n); }
+  bool operator <= (const number_t &n) const { return !(*this > n); }
 
-  bool operator < (const Number &n) const
-  { return n > *this; }
-
-  bool operator >= (const Number &n) const
-  { return !(*this < n); }
-
-  bool operator <= (const Number &n) const
-  { return !(*this > n); }
-
-  const Number &operator += (const Number &n)
+  const number_t &operator += (const number_t &n)
   {
     set_real (to_real () + n.to_real ());
 
@@ -255,7 +245,7 @@
   }
 
   protected:
-  double  value;
+  double value;
 };
 
 /* byte string */
@@ -263,7 +253,7 @@
 {
   // encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
   template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int (hb_serialize_context_t *c, OpCode intOp, int value)
+  static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
   {
     TRACE_SERIALIZE (this);
 
@@ -272,11 +262,11 @@
 
     HBUINT8 *p = c->allocate_size<HBUINT8> (1);
     if (unlikely (p == nullptr)) return_trace (false);
-    p->set (intOp);
+    *p = intOp;
 
     INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
     if (unlikely (ip == nullptr)) return_trace (false);
-    ip->set ((unsigned int)value);
+    *ip = (unsigned int) value;
 
     return_trace (true);
   }
@@ -290,106 +280,83 @@
   /* Defining null_size allows a Null object may be created. Should be safe because:
    * A descendent struct Dict uses a Null pointer to indicate a missing table,
    * checked before access.
-   * ByteStr, a wrapper struct pairing a byte pointer along with its length, always
+   * byte_str_t, a wrapper struct pairing a byte pointer along with its length, always
    * checks the length before access. A Null pointer is used as the initial pointer
    * along with zero length by the default ctor.
    */
   DEFINE_SIZE_MIN(0);
 };
 
-struct ByteStr
+/* Holder of a section of byte string within a CFFIndex entry */
+struct byte_str_t : hb_ubytes_t
 {
-  ByteStr ()
-    : str (&Null(UnsizedByteStr)), len (0) {}
-  ByteStr (const UnsizedByteStr& s, unsigned int l)
-    : str (&s), len (l) {}
-  ByteStr (const char *s, unsigned int l=0)
-    : str ((const UnsizedByteStr *)s), len (l) {}
+  byte_str_t ()
+    : hb_ubytes_t () {}
+  byte_str_t (const UnsizedByteStr& s, unsigned int l)
+    : hb_ubytes_t ((const unsigned char*)&s, l) {}
+  byte_str_t (const unsigned char *s, unsigned int l)
+    : hb_ubytes_t (s, l) {}
+  byte_str_t (const hb_ubytes_t &ub)	/* conversion from hb_ubytes_t */
+    : hb_ubytes_t (ub) {}
+
   /* sub-string */
-  ByteStr (const ByteStr &bs, unsigned int offset, unsigned int len_)
-  {
-    str = (const UnsizedByteStr *)&bs.str[offset];
-    len = len_;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const { return str->sanitize (c, len); }
-
-  const HBUINT8& operator [] (unsigned int i) const
-  {
-    if (likely (str && (i < len)))
-      return (*str)[i];
-    else
-      return Null(HBUINT8);
-  }
-
-  bool serialize (hb_serialize_context_t *c, const ByteStr &src)
-  {
-    TRACE_SERIALIZE (this);
-    HBUINT8 *dest = c->allocate_size<HBUINT8> (src.len);
-    if (unlikely (dest == nullptr))
-      return_trace (false);
-    memcpy (dest, src.str, src.len);
-    return_trace (true);
-  }
-
-  unsigned int get_size () const { return len; }
+  byte_str_t sub_str (unsigned int offset, unsigned int len_) const
+  { return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); }
 
   bool check_limit (unsigned int offset, unsigned int count) const
-  { return (offset + count <= len); }
-
-  const UnsizedByteStr *str;
-  unsigned int len;
+  { return (offset + count <= length); }
 };
 
-struct SubByteStr
+/* A byte string associated with the current offset and an error condition */
+struct byte_str_ref_t
 {
-  SubByteStr ()
-  { init (); }
+  byte_str_ref_t () { init (); }
 
   void init ()
   {
-    str = ByteStr (0);
+    str = byte_str_t ();
     offset = 0;
     error = false;
   }
 
   void fini () {}
 
-  SubByteStr (const ByteStr &str_, unsigned int offset_ = 0)
+  byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0)
     : str (str_), offset (offset_), error (false) {}
 
-  void reset (const ByteStr &str_, unsigned int offset_ = 0)
+  void reset (const byte_str_t &str_, unsigned int offset_ = 0)
   {
     str = str_;
     offset = offset_;
     error = false;
   }
 
-  const HBUINT8& operator [] (int i) {
-    if (unlikely ((unsigned int)(offset + i) >= str.len))
+  const unsigned char& operator [] (int i) {
+    if (unlikely ((unsigned int) (offset + i) >= str.length))
     {
       set_error ();
-      return Null(HBUINT8);
+      return Null (unsigned char);
     }
-    else
-      return str[offset + i];
+    return str[offset + i];
   }
 
-  operator ByteStr () const { return ByteStr (str, offset, str.len - offset); }
+  /* Conversion to byte_str_t */
+  operator byte_str_t () const { return str.sub_str (offset, str.length - offset); }
+
+  byte_str_t sub_str (unsigned int offset_, unsigned int len_) const
+  { return str.sub_str (offset_, len_); }
 
   bool avail (unsigned int count=1) const
-  {
-    return (!in_error () && str.check_limit (offset, count));
-  }
+  { return (!in_error () && str.check_limit (offset, count)); }
   void inc (unsigned int count=1)
   {
-    if (likely (!in_error () && (offset <= str.len) && (offset + count <= str.len)))
+    if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
     {
       offset += count;
     }
     else
     {
-      offset = str.len;
+      offset = str.length;
       set_error ();
     }
   }
@@ -397,18 +364,18 @@
   void set_error ()      { error = true; }
   bool in_error () const { return error; }
 
-  ByteStr       str;
+  byte_str_t       str;
   unsigned int  offset; /* beginning of the sub-string within str */
 
   protected:
   bool	  error;
 };
 
-typedef hb_vector_t<ByteStr> ByteStrArray;
+typedef hb_vector_t<byte_str_t> byte_str_array_t;
 
 /* stack */
 template <typename ELEM, int LIMIT>
-struct Stack
+struct cff_stack_t
 {
   void init ()
   {
@@ -416,14 +383,10 @@
     count = 0;
     elements.init ();
     elements.resize (kSizeLimit);
-    for (unsigned int i = 0; i < elements.len; i++)
+    for (unsigned int i = 0; i < elements.length; i++)
       elements[i].init ();
   }
-
-  void fini ()
-  {
-    elements.fini_deep ();
-  }
+  void fini () { elements.fini_deep (); }
 
   ELEM& operator [] (unsigned int i)
   {
@@ -433,15 +396,14 @@
 
   void push (const ELEM &v)
   {
-    if (likely (count < elements.len))
+    if (likely (count < elements.length))
       elements[count++] = v;
     else
       set_error ();
   }
-
   ELEM &push ()
   {
-    if (likely (count < elements.len))
+    if (likely (count < elements.length))
       return elements[count++];
     else
     {
@@ -460,7 +422,6 @@
       return Crap(ELEM);
     }
   }
-
   void pop (unsigned int n)
   {
     if (likely (count >= n))
@@ -471,18 +432,17 @@
 
   const ELEM& peek ()
   {
-    if (likely (count > 0))
-      return elements[count-1];
-    else
+    if (unlikely (count < 0))
     {
       set_error ();
       return Null(ELEM);
     }
+    return elements[count - 1];
   }
 
   void unpop ()
   {
-    if (likely (count < elements.len))
+    if (likely (count < elements.length))
       count++;
     else
       set_error ();
@@ -494,19 +454,19 @@
   void set_error ()      { error = true; }
 
   unsigned int get_count () const { return count; }
-  bool is_empty () const { return count == 0; }
+  bool is_empty () const          { return !count; }
 
-  static const unsigned int kSizeLimit = LIMIT;
+  static constexpr unsigned kSizeLimit = LIMIT;
 
   protected:
   bool error;
   unsigned int count;
-  hb_vector_t<ELEM, kSizeLimit> elements;
+  hb_vector_t<ELEM> elements;
 };
 
 /* argument stack */
-template <typename ARG=Number>
-struct ArgStack : Stack<ARG, 513>
+template <typename ARG=number_t>
+struct arg_stack_t : cff_stack_t<ARG, 513>
 {
   void push_int (int v)
   {
@@ -538,60 +498,58 @@
       i = 0;
       S::set_error ();
     }
-    return (unsigned)i;
+    return (unsigned) i;
   }
 
-  void push_longint_from_substr (SubByteStr& substr)
+  void push_longint_from_substr (byte_str_ref_t& str_ref)
   {
-    push_int ((substr[0] << 24) | (substr[1] << 16) | (substr[2] << 8) | (substr[3]));
-    substr.inc (4);
+    push_int ((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3]));
+    str_ref.inc (4);
   }
 
-  bool push_fixed_from_substr (SubByteStr& substr)
+  bool push_fixed_from_substr (byte_str_ref_t& str_ref)
   {
-    if (unlikely (!substr.avail (4)))
+    if (unlikely (!str_ref.avail (4)))
       return false;
-    push_fixed ((int32_t)*(const HBUINT32*)&substr[0]);
-    substr.inc (4);
+    push_fixed ((int32_t)*(const HBUINT32*)&str_ref[0]);
+    str_ref.inc (4);
     return true;
   }
 
   hb_array_t<const ARG> get_subarray (unsigned int start) const
-  {
-    return S::elements.sub_array (start);
-  }
+  { return S::elements.sub_array (start); }
 
   private:
-  typedef Stack<ARG, 513> S;
+  typedef cff_stack_t<ARG, 513> S;
 };
 
 /* an operator prefixed by its operands in a byte string */
-struct OpStr
+struct op_str_t
 {
   void init () {}
   void fini () {}
 
-  OpCode  op;
-  ByteStr str;
+  op_code_t  op;
+  byte_str_t str;
 };
 
 /* base of OP_SERIALIZER */
-struct OpSerializer
+struct op_serializer_t
 {
   protected:
-  bool copy_opstr (hb_serialize_context_t *c, const OpStr& opstr) const
+  bool copy_opstr (hb_serialize_context_t *c, const op_str_t& opstr) const
   {
     TRACE_SERIALIZE (this);
 
-    HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
+    HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
     if (unlikely (d == nullptr)) return_trace (false);
-    memcpy (d, &opstr.str.str[0], opstr.str.len);
+    memcpy (d, &opstr.str[0], opstr.str.length);
     return_trace (true);
   }
 };
 
 template <typename VAL>
-struct ParsedValues
+struct parsed_values_t
 {
   void init ()
   {
@@ -600,118 +558,107 @@
   }
   void fini () { values.fini_deep (); }
 
-  void add_op (OpCode op, const SubByteStr& substr = SubByteStr ())
+  void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
   {
     VAL *val = values.push ();
     val->op = op;
-    val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
-    opStart = substr.offset;
+    val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart);
+    opStart = str_ref.offset;
   }
 
-  void add_op (OpCode op, const SubByteStr& substr, const VAL &v)
+  void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
   {
     VAL *val = values.push (v);
     val->op = op;
-    val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
-    opStart = substr.offset;
+    val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart);
+    opStart = str_ref.offset;
   }
 
-  bool has_op (OpCode op) const
+  bool has_op (op_code_t op) const
   {
     for (unsigned int i = 0; i < get_count (); i++)
       if (get_value (i).op == op) return true;
     return false;
   }
 
-  unsigned get_count () const { return values.len; }
-  const VAL &get_value (unsigned int i) const { return values[i]; }
+  unsigned get_count () const { return values.length; }
+  const VAL &get_value (unsigned int i)   const { return values[i]; }
   const VAL &operator [] (unsigned int i) const { return get_value (i); }
 
   unsigned int       opStart;
   hb_vector_t<VAL>   values;
 };
 
-template <typename ARG=Number>
-struct InterpEnv
+template <typename ARG=number_t>
+struct interp_env_t
 {
-  void init (const ByteStr &str_)
+  void init (const byte_str_t &str_)
   {
-    substr.reset (str_);
+    str_ref.reset (str_);
     argStack.init ();
     error = false;
   }
   void fini () { argStack.fini (); }
 
   bool in_error () const
-  { return error || substr.in_error () || argStack.in_error (); }
+  { return error || str_ref.in_error () || argStack.in_error (); }
 
   void set_error () { error = true; }
 
-  OpCode fetch_op ()
+  op_code_t fetch_op ()
   {
-    OpCode  op = OpCode_Invalid;
-    if (unlikely (!substr.avail ()))
+    op_code_t  op = OpCode_Invalid;
+    if (unlikely (!str_ref.avail ()))
       return OpCode_Invalid;
-    op = (OpCode)(unsigned char)substr[0];
+    op = (op_code_t)(unsigned char)str_ref[0];
     if (op == OpCode_escape) {
-      if (unlikely (!substr.avail ()))
+      if (unlikely (!str_ref.avail ()))
 	return OpCode_Invalid;
-      op = Make_OpCode_ESC(substr[1]);
-      substr.inc ();
+      op = Make_OpCode_ESC(str_ref[1]);
+      str_ref.inc ();
     }
-    substr.inc ();
+    str_ref.inc ();
     return op;
   }
 
-  const ARG& eval_arg (unsigned int i)
-  {
-    return argStack[i];
-  }
+  const ARG& eval_arg (unsigned int i) { return argStack[i]; }
 
-  ARG& pop_arg ()
-  {
-    return argStack.pop ();
-  }
+  ARG& pop_arg () { return argStack.pop (); }
+  void pop_n_args (unsigned int n) { argStack.pop (n); }
 
-  void pop_n_args (unsigned int n)
-  {
-    argStack.pop (n);
-  }
+  void clear_args () { pop_n_args (argStack.get_count ()); }
 
-  void clear_args ()
-  {
-    pop_n_args (argStack.get_count ());
-  }
-
-  SubByteStr    substr;
-  ArgStack<ARG> argStack;
+  byte_str_ref_t
+		str_ref;
+  arg_stack_t<ARG>
+		argStack;
   protected:
-  bool	  error;
+  bool		error;
 };
 
-typedef InterpEnv<> NumInterpEnv;
+typedef interp_env_t<> num_interp_env_t;
 
-template <typename ARG=Number>
-struct OpSet
+template <typename ARG=number_t>
+struct opset_t
 {
-  static void process_op (OpCode op, InterpEnv<ARG>& env)
+  static void process_op (op_code_t op, interp_env_t<ARG>& env)
   {
     switch (op) {
       case OpCode_shortint:
-	env.argStack.push_int ((int16_t)((env.substr[0] << 8) | env.substr[1]));
-	env.substr.inc (2);
+	env.argStack.push_int ((int16_t)((env.str_ref[0] << 8) | env.str_ref[1]));
+	env.str_ref.inc (2);
 	break;
 
       case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
       case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
-	env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.substr[0] + 108));
-	env.substr.inc ();
+	env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.str_ref[0] + 108));
+	env.str_ref.inc ();
 	break;
 
       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
-	env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.substr[0] - 108));
-	env.substr.inc ();
+	env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
+	env.str_ref.inc ();
 	break;
 
       default:
@@ -730,9 +677,9 @@
 };
 
 template <typename ENV>
-struct Interpreter {
-
-  ~Interpreter() { fini (); }
+struct interpreter_t
+{
+  ~interpreter_t() { fini (); }
 
   void fini () { env.fini (); }
 
diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh
index e78d557..d9ad4d0 100644
--- a/src/hb-cff-interp-cs-common.hh
+++ b/src/hb-cff-interp-cs-common.hh
@@ -33,38 +33,38 @@
 
 using namespace OT;
 
-enum CSType {
+enum cs_type_t {
   CSType_CharString,
   CSType_GlobalSubr,
   CSType_LocalSubr
 };
 
-struct CallContext
+struct call_context_t
 {
-  void init (const SubByteStr substr_=SubByteStr (), CSType type_=CSType_CharString, unsigned int subr_num_=0)
+  void init (const byte_str_ref_t substr_=byte_str_ref_t (), cs_type_t type_=CSType_CharString, unsigned int subr_num_=0)
   {
-    substr = substr_;
+    str_ref = substr_;
     type = type_;
     subr_num = subr_num_;
   }
 
   void fini () {}
 
-  SubByteStr      substr;
-  CSType	  type;
+  byte_str_ref_t  str_ref;
+  cs_type_t	  type;
   unsigned int    subr_num;
 };
 
 /* call stack */
 const unsigned int kMaxCallLimit = 10;
-struct CallStack : Stack<CallContext, kMaxCallLimit> {};
+struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 
 template <typename SUBRS>
-struct BiasedSubrs
+struct biased_subrs_t
 {
-  void init (const SUBRS &subrs_)
+  void init (const SUBRS *subrs_)
   {
-    subrs = &subrs_;
+    subrs = subrs_;
     unsigned int  nSubrs = get_count ();
     if (nSubrs < 1240)
       bias = 107;
@@ -76,13 +76,13 @@
 
   void fini () {}
 
-  unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
-  unsigned int get_bias () const { return bias; }
+  unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; }
+  unsigned int get_bias () const  { return bias; }
 
-  ByteStr operator [] (unsigned int index) const
+  byte_str_t operator [] (unsigned int index) const
   {
     if (unlikely ((subrs == nullptr) || index >= subrs->count))
-      return Null(ByteStr);
+      return Null(byte_str_t);
     else
       return (*subrs)[index];
   }
@@ -92,7 +92,7 @@
   const SUBRS   *subrs;
 };
 
-struct Point
+struct point_t
 {
   void init ()
   {
@@ -106,27 +106,28 @@
     y.set_int (_y);
   }
 
-  void move_x (const Number &dx) { x += dx; }
-  void move_y (const Number &dy) { y += dy; }
-  void move (const Number &dx, const Number &dy) { move_x (dx); move_y (dy); }
-  void move (const Point &d) { move_x (d.x); move_y (d.y); }
+  void move_x (const number_t &dx) { x += dx; }
+  void move_y (const number_t &dy) { y += dy; }
+  void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
+  void move (const point_t &d) { move_x (d.x); move_y (d.y); }
 
-  Number  x;
-  Number  y;
+  number_t  x;
+  number_t  y;
 };
 
 template <typename ARG, typename SUBRS>
-struct CSInterpEnv : InterpEnv<ARG>
+struct cs_interp_env_t : interp_env_t<ARG>
 {
-  void init (const ByteStr &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
+  void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
   {
-    InterpEnv<ARG>::init (str);
+    interp_env_t<ARG>::init (str);
 
     context.init (str, CSType_CharString);
     seen_moveto = true;
     seen_hintmask = false;
     hstem_count = 0;
     vstem_count = 0;
+    hintmask_size = 0;
     pt.init ();
     callStack.init ();
     globalSubrs.init (globalSubrs_);
@@ -134,7 +135,7 @@
   }
   void fini ()
   {
-    InterpEnv<ARG>::fini ();
+    interp_env_t<ARG>::fini ();
 
     callStack.fini ();
     globalSubrs.fini ();
@@ -146,8 +147,9 @@
     return callStack.in_error () || SUPER::in_error ();
   }
 
-  bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num)
+  bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
   {
+    subr_num = 0;
     int n = SUPER::argStack.pop_int ();
     n += biasedSubrs.get_bias ();
     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
@@ -157,29 +159,29 @@
     return true;
   }
 
-  void callSubr (const BiasedSubrs<SUBRS>& biasedSubrs, CSType type)
+  void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
   {
-    unsigned int subr_num;
+    unsigned int subr_num = 0;
 
-    if (unlikely (!popSubrNum (biasedSubrs, subr_num)
+    if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
 		 || callStack.get_count () >= kMaxCallLimit))
     {
       SUPER::set_error ();
       return;
     }
-    context.substr = SUPER::substr;
+    context.str_ref = SUPER::str_ref;
     callStack.push (context);
 
     context.init ( biasedSubrs[subr_num], type, subr_num);
-    SUPER::substr = context.substr;
+    SUPER::str_ref = context.str_ref;
   }
 
-  void returnFromSubr ()
+  void return_from_subr ()
   {
-    if (unlikely (SUPER::substr.in_error ()))
+    if (unlikely (SUPER::str_ref.in_error ()))
       SUPER::set_error ();
     context = callStack.pop ();
-    SUPER::substr = context.substr;
+    SUPER::str_ref = context.str_ref;
   }
 
   void determine_hintmask_size ()
@@ -195,14 +197,14 @@
   void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
   bool is_endchar () const { return endchar_flag; }
 
-  const Number &get_x () const { return pt.x; }
-  const Number &get_y () const { return pt.y; }
-  const Point &get_pt () const { return pt; }
+  const number_t &get_x () const { return pt.x; }
+  const number_t &get_y () const { return pt.y; }
+  const point_t &get_pt () const { return pt; }
 
-  void moveto (const Point &pt_ ) { pt = pt_; }
+  void moveto (const point_t &pt_ ) { pt = pt_; }
 
   public:
-  CallContext   context;
+  call_context_t   context;
   bool	  endchar_flag;
   bool	  seen_moveto;
   bool	  seen_hintmask;
@@ -210,18 +212,18 @@
   unsigned int  hstem_count;
   unsigned int  vstem_count;
   unsigned int  hintmask_size;
-  CallStack	    callStack;
-  BiasedSubrs<SUBRS>   globalSubrs;
-  BiasedSubrs<SUBRS>   localSubrs;
+  call_stack_t	callStack;
+  biased_subrs_t<SUBRS>   globalSubrs;
+  biased_subrs_t<SUBRS>   localSubrs;
 
   private:
-  Point	 pt;
+  point_t	 pt;
 
-  typedef InterpEnv<ARG> SUPER;
+  typedef interp_env_t<ARG> SUPER;
 };
 
 template <typename ENV, typename PARAM>
-struct PathProcsNull
+struct path_procs_null_t
 {
   static void rmoveto (ENV &env, PARAM& param) {}
   static void hmoveto (ENV &env, PARAM& param) {}
@@ -236,24 +238,24 @@
   static void hhcurveto (ENV &env, PARAM& param) {}
   static void vhcurveto (ENV &env, PARAM& param) {}
   static void hvcurveto (ENV &env, PARAM& param) {}
-  static void moveto (ENV &env, PARAM& param, const Point &pt) {}
-  static void line (ENV &env, PARAM& param, const Point &pt1) {}
-  static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3) {}
+  static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
+  static void line (ENV &env, PARAM& param, const point_t &pt1) {}
+  static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
   static void hflex (ENV &env, PARAM& param) {}
   static void flex (ENV &env, PARAM& param) {}
   static void hflex1 (ENV &env, PARAM& param) {}
   static void flex1 (ENV &env, PARAM& param) {}
 };
 
-template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=PathProcsNull<ENV, PARAM> >
-struct CSOpSet : OpSet<ARG>
+template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
+struct cs_opset_t : opset_t<ARG>
 {
-  static void process_op (OpCode op, ENV &env, PARAM& param)
+  static void process_op (op_code_t op, ENV &env, PARAM& param)
   {
     switch (op) {
 
       case OpCode_return:
-	env.returnFromSubr ();
+	env.return_from_subr ();
 	break;
       case OpCode_endchar:
 	OPSET::check_width (op, env, param);
@@ -262,15 +264,15 @@
 	break;
 
       case OpCode_fixedcs:
-	env.argStack.push_fixed_from_substr (env.substr);
+	env.argStack.push_fixed_from_substr (env.str_ref);
 	break;
 
       case OpCode_callsubr:
-	env.callSubr (env.localSubrs, CSType_LocalSubr);
+	env.call_subr (env.localSubrs, CSType_LocalSubr);
 	break;
 
       case OpCode_callgsubr:
-	env.callSubr (env.globalSubrs, CSType_GlobalSubr);
+	env.call_subr (env.globalSubrs, CSType_GlobalSubr);
 	break;
 
       case OpCode_hstem:
@@ -370,37 +372,37 @@
     }
   }
 
-  static void process_hstem (OpCode op, ENV &env, PARAM& param)
+  static void process_hstem (op_code_t op, ENV &env, PARAM& param)
   {
     env.hstem_count += env.argStack.get_count () / 2;
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static void process_vstem (OpCode op, ENV &env, PARAM& param)
+  static void process_vstem (op_code_t op, ENV &env, PARAM& param)
   {
     env.vstem_count += env.argStack.get_count () / 2;
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static void process_hintmask (OpCode op, ENV &env, PARAM& param)
+  static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
   {
     env.determine_hintmask_size ();
-    if (likely (env.substr.avail (env.hintmask_size)))
+    if (likely (env.str_ref.avail (env.hintmask_size)))
     {
       OPSET::flush_hintmask (op, env, param);
-      env.substr.inc (env.hintmask_size);
+      env.str_ref.inc (env.hintmask_size);
     }
   }
 
-  static void process_post_flex (OpCode op, ENV &env, PARAM& param)
+  static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
   {
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static void check_width (OpCode op, ENV &env, PARAM& param)
+  static void check_width (op_code_t op, ENV &env, PARAM& param)
   {}
 
-  static void process_post_move (OpCode op, ENV &env, PARAM& param)
+  static void process_post_move (op_code_t op, ENV &env, PARAM& param)
   {
     if (!env.seen_moveto)
     {
@@ -410,12 +412,12 @@
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static void process_post_path (OpCode op, ENV &env, PARAM& param)
+  static void process_post_path (op_code_t op, ENV &env, PARAM& param)
   {
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static void flush_args_and_op (OpCode op, ENV &env, PARAM& param)
+  static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
   {
     OPSET::flush_args (env, param);
     OPSET::flush_op (op, env, param);
@@ -426,16 +428,16 @@
     env.pop_n_args (env.argStack.get_count ());
   }
 
-  static void flush_op (OpCode op, ENV &env, PARAM& param)
+  static void flush_op (op_code_t op, ENV &env, PARAM& param)
   {
   }
 
-  static void flush_hintmask (OpCode op, ENV &env, PARAM& param)
+  static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
   {
     OPSET::flush_args_and_op (op, env, param);
   }
 
-  static bool is_number_op (OpCode op)
+  static bool is_number_op (op_code_t op)
   {
     switch (op)
     {
@@ -454,31 +456,31 @@
   }
 
   protected:
-  typedef OpSet<ARG>  SUPER;
+  typedef opset_t<ARG>  SUPER;
 };
 
 template <typename PATH, typename ENV, typename PARAM>
-struct PathProcs
+struct path_procs_t
 {
   static void rmoveto (ENV &env, PARAM& param)
   {
-    Point pt1 = env.get_pt ();
-    const Number &dy = env.pop_arg ();
-    const Number &dx = env.pop_arg ();
+    point_t pt1 = env.get_pt ();
+    const number_t &dy = env.pop_arg ();
+    const number_t &dx = env.pop_arg ();
     pt1.move (dx, dy);
     PATH::moveto (env, param, pt1);
   }
 
   static void hmoveto (ENV &env, PARAM& param)
   {
-    Point pt1 = env.get_pt ();
+    point_t pt1 = env.get_pt ();
     pt1.move_x (env.pop_arg ());
     PATH::moveto (env, param, pt1);
   }
 
   static void vmoveto (ENV &env, PARAM& param)
   {
-    Point pt1 = env.get_pt ();
+    point_t pt1 = env.get_pt ();
     pt1.move_y (env.pop_arg ());
     PATH::moveto (env, param, pt1);
   }
@@ -487,7 +489,7 @@
   {
     for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
       PATH::line (env, param, pt1);
     }
@@ -495,7 +497,7 @@
 
   static void hlineto (ENV &env, PARAM& param)
   {
-    Point pt1;
+    point_t pt1;
     unsigned int i = 0;
     for (; i + 2 <= env.argStack.get_count (); i += 2)
     {
@@ -515,7 +517,7 @@
 
   static void vlineto (ENV &env, PARAM& param)
   {
-    Point pt1;
+    point_t pt1;
     unsigned int i = 0;
     for (; i + 2 <= env.argStack.get_count (); i += 2)
     {
@@ -537,11 +539,11 @@
   {
     for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
       PATH::curve (env, param, pt1, pt2, pt3);
     }
@@ -552,17 +554,17 @@
     unsigned int i = 0;
     for (; i + 6 <= env.argStack.get_count (); i += 6)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
       PATH::curve (env, param, pt1, pt2, pt3);
     }
     for (; i + 2 <= env.argStack.get_count (); i += 2)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
       PATH::line (env, param, pt1);
     }
@@ -574,17 +576,17 @@
     unsigned int line_limit = (env.argStack.get_count () % 6);
     for (; i + 2 <= line_limit; i += 2)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
       PATH::line (env, param, pt1);
     }
     for (; i + 6 <= env.argStack.get_count (); i += 6)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
       PATH::curve (env, param, pt1, pt2, pt3);
     }
@@ -593,15 +595,15 @@
   static void vvcurveto (ENV &env, PARAM& param)
   {
     unsigned int i = 0;
-    Point pt1 = env.get_pt ();
+    point_t pt1 = env.get_pt ();
     if ((env.argStack.get_count () & 1) != 0)
       pt1.move_x (env.eval_arg (i++));
     for (; i + 4 <= env.argStack.get_count (); i += 4)
     {
       pt1.move_y (env.eval_arg (i));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_y (env.eval_arg (i+3));
       PATH::curve (env, param, pt1, pt2, pt3);
       pt1 = env.get_pt ();
@@ -611,15 +613,15 @@
   static void hhcurveto (ENV &env, PARAM& param)
   {
     unsigned int i = 0;
-    Point pt1 = env.get_pt ();
+    point_t pt1 = env.get_pt ();
     if ((env.argStack.get_count () & 1) != 0)
       pt1.move_y (env.eval_arg (i++));
     for (; i + 4 <= env.argStack.get_count (); i += 4)
     {
       pt1.move_x (env.eval_arg (i));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_x (env.eval_arg (i+3));
       PATH::curve (env, param, pt1, pt2, pt3);
       pt1 = env.get_pt ();
@@ -628,15 +630,15 @@
 
   static void vhcurveto (ENV &env, PARAM& param)
   {
-    Point pt1, pt2, pt3;
+    point_t pt1, pt2, pt3;
     unsigned int i = 0;
     if ((env.argStack.get_count () % 8) >= 4)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move_y (env.eval_arg (i));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_x (env.eval_arg (i+3));
       i += 4;
 
@@ -689,15 +691,15 @@
 
   static void hvcurveto (ENV &env, PARAM& param)
   {
-    Point pt1, pt2, pt3;
+    point_t pt1, pt2, pt3;
     unsigned int i = 0;
     if ((env.argStack.get_count () % 8) >= 4)
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move_x (env.eval_arg (i));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_y (env.eval_arg (i+3));
       i += 4;
 
@@ -749,31 +751,31 @@
   }
 
   /* default actions to be overridden */
-  static void moveto (ENV &env, PARAM& param, const Point &pt)
+  static void moveto (ENV &env, PARAM& param, const point_t &pt)
   { env.moveto (pt); }
 
-  static void line (ENV &env, PARAM& param, const Point &pt1)
+  static void line (ENV &env, PARAM& param, const point_t &pt1)
   { PATH::moveto (env, param, pt1); }
 
-  static void curve (ENV &env, PARAM& param, const Point &pt1, const Point &pt2, const Point &pt3)
+  static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   { PATH::moveto (env, param, pt3); }
 
   static void hflex (ENV &env, PARAM& param)
   {
     if (likely (env.argStack.get_count () == 7))
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move_x (env.eval_arg (0));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (1), env.eval_arg (2));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_x (env.eval_arg (3));
-      Point pt4 = pt3;
+      point_t pt4 = pt3;
       pt4.move_x (env.eval_arg (4));
-      Point pt5 = pt4;
+      point_t pt5 = pt4;
       pt5.move_x (env.eval_arg (5));
       pt5.y = pt1.y;
-      Point pt6 = pt5;
+      point_t pt6 = pt5;
       pt6.move_x (env.eval_arg (6));
 
       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
@@ -786,17 +788,17 @@
   {
     if (likely (env.argStack.get_count () == 13))
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (0), env.eval_arg (1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (2), env.eval_arg (3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move (env.eval_arg (4), env.eval_arg (5));
-      Point pt4 = pt3;
+      point_t pt4 = pt3;
       pt4.move (env.eval_arg (6), env.eval_arg (7));
-      Point pt5 = pt4;
+      point_t pt5 = pt4;
       pt5.move (env.eval_arg (8), env.eval_arg (9));
-      Point pt6 = pt5;
+      point_t pt6 = pt5;
       pt6.move (env.eval_arg (10), env.eval_arg (11));
 
       curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
@@ -809,17 +811,17 @@
   {
     if (likely (env.argStack.get_count () == 9))
     {
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (0), env.eval_arg (1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (2), env.eval_arg (3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move_x (env.eval_arg (4));
-      Point pt4 = pt3;
+      point_t pt4 = pt3;
       pt4.move_x (env.eval_arg (5));
-      Point pt5 = pt4;
+      point_t pt5 = pt4;
       pt5.move (env.eval_arg (6), env.eval_arg (7));
-      Point pt6 = pt5;
+      point_t pt6 = pt5;
       pt6.move_x (env.eval_arg (8));
       pt6.y = env.get_pt ().y;
 
@@ -833,22 +835,22 @@
   {
     if (likely (env.argStack.get_count () == 11))
     {
-      Point d;
+      point_t d;
       d.init ();
       for (unsigned int i = 0; i < 10; i += 2)
 	d.move (env.eval_arg (i), env.eval_arg (i+1));
 
-      Point pt1 = env.get_pt ();
+      point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (0), env.eval_arg (1));
-      Point pt2 = pt1;
+      point_t pt2 = pt1;
       pt2.move (env.eval_arg (2), env.eval_arg (3));
-      Point pt3 = pt2;
+      point_t pt3 = pt2;
       pt3.move (env.eval_arg (4), env.eval_arg (5));
-      Point pt4 = pt3;
+      point_t pt4 = pt3;
       pt4.move (env.eval_arg (6), env.eval_arg (7));
-      Point pt5 = pt4;
+      point_t pt5 = pt4;
       pt5.move (env.eval_arg (8), env.eval_arg (9));
-      Point pt6 = pt5;
+      point_t pt6 = pt5;
 
       if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
       {
@@ -869,8 +871,8 @@
 
   protected:
   static void curve2 (ENV &env, PARAM& param,
-		      const Point &pt1, const Point &pt2, const Point &pt3,
-		      const Point &pt4, const Point &pt5, const Point &pt6)
+		      const point_t &pt1, const point_t &pt2, const point_t &pt3,
+		      const point_t &pt4, const point_t &pt5, const point_t &pt6)
   {
     PATH::curve (env, param, pt1, pt2, pt3);
     PATH::curve (env, param, pt4, pt5, pt6);
@@ -878,7 +880,7 @@
 };
 
 template <typename ENV, typename OPSET, typename PARAM>
-struct CSInterpreter : Interpreter<ENV>
+struct cs_interpreter_t : interpreter_t<ENV>
 {
   bool interpret (PARAM& param)
   {
@@ -896,7 +898,7 @@
   }
 
   private:
-  typedef Interpreter<ENV> SUPER;
+  typedef interpreter_t<ENV> SUPER;
 };
 
 } /* namespace CFF */
diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh
index 8000d76..1f03d82 100644
--- a/src/hb-cff-interp-dict-common.hh
+++ b/src/hb-cff-interp-dict-common.hh
@@ -35,28 +35,28 @@
 using namespace OT;
 
 /* an opstr and the parsed out dict value(s) */
-struct DictVal : OpStr
+struct dict_val_t : op_str_t
 {
   void init () { single_val.set_int (0); }
   void fini () {}
 
-  Number	      single_val;
+  number_t	      single_val;
 };
 
-typedef DictVal NumDictVal;
+typedef dict_val_t num_dict_val_t;
 
-template <typename VAL> struct DictValues : ParsedValues<VAL> {};
+template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {};
 
-template <typename OPSTR=OpStr>
-struct TopDictValues : DictValues<OPSTR>
+template <typename OPSTR=op_str_t>
+struct top_dict_values_t : dict_values_t<OPSTR>
 {
   void init ()
   {
-    DictValues<OPSTR>::init ();
+    dict_values_t<OPSTR>::init ();
     charStringsOffset = 0;
     FDArrayOffset = 0;
   }
-  void fini () { DictValues<OPSTR>::fini (); }
+  void fini () { dict_values_t<OPSTR>::fini (); }
 
   unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
   {
@@ -67,7 +67,7 @@
 	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 
       default:
-	return opstr.str.len;
+	return opstr.str.length;
     }
   }
 
@@ -75,152 +75,74 @@
   unsigned int  FDArrayOffset;
 };
 
-struct DictOpSet : OpSet<Number>
+struct dict_opset_t : opset_t<number_t>
 {
-  static void process_op (OpCode op, InterpEnv<Number>& env)
+  static void process_op (op_code_t op, interp_env_t<number_t>& env)
   {
     switch (op) {
       case OpCode_longintdict:  /* 5-byte integer */
-	env.argStack.push_longint_from_substr (env.substr);
+	env.argStack.push_longint_from_substr (env.str_ref);
 	break;
 
       case OpCode_BCD:  /* real number */
-	env.argStack.push_real (parse_bcd (env.substr));
+	env.argStack.push_real (parse_bcd (env.str_ref));
 	break;
 
       default:
-	OpSet<Number>::process_op (op, env);
+	opset_t<number_t>::process_op (op, env);
 	break;
     }
   }
 
-  static double parse_bcd (SubByteStr& substr)
+  /* Turns CFF's BCD format into strtod understandable string */
+  static double parse_bcd (byte_str_ref_t& str_ref)
   {
-    bool    neg = false;
-    double  int_part = 0;
-    uint64_t frac_part = 0;
-    uint32_t  frac_count = 0;
-    bool    exp_neg = false;
-    uint32_t  exp_part = 0;
-    bool    exp_overflow = false;
-    enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
-    enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
-    const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
-    const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
+    if (unlikely (str_ref.in_error ())) return .0;
 
-    double  value = 0.0;
+    enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
+
+    char buf[32];
     unsigned char byte = 0;
-    for (uint32_t i = 0;; i++)
+    for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
     {
-      char d;
-      if ((i & 1) == 0)
+      unsigned nibble;
+      if (!(i & 1))
       {
-	if (!substr.avail ())
-	{
-	  substr.set_error ();
-	  return 0.0;
-	}
-	byte = substr[0];
-	substr.inc ();
-	d = byte >> 4;
+	if (unlikely (!str_ref.avail ())) break;
+
+	byte = str_ref[0];
+	str_ref.inc ();
+	nibble = byte >> 4;
       }
       else
-	d = byte & 0x0F;
+	nibble = byte & 0x0F;
 
-      switch (d)
+      if (unlikely (nibble == RESERVED)) break;
+      else if (nibble == END)
       {
-	case RESERVED:
-	  substr.set_error ();
-	  return value;
-
-	case END:
-	  value = (double)(neg? -int_part: int_part);
-	  if (frac_count > 0)
-	  {
-	    double frac = (frac_part / pow (10.0, (double)frac_count));
-	    if (neg) frac = -frac;
-	    value += frac;
-	  }
-	  if (unlikely (exp_overflow))
-	  {
-	    if (value == 0.0)
-	      return value;
-	    if (exp_neg)
-	      return neg? -DBL_MIN: DBL_MIN;
-	    else
-	      return neg? -DBL_MAX: DBL_MAX;
-	  }
-	  if (exp_part != 0)
-	  {
-	    if (exp_neg)
-	      value /= pow (10.0, (double)exp_part);
-	    else
-	      value *= pow (10.0, (double)exp_part);
-	  }
-	  return value;
-
-	case NEG:
-	  if (i != 0)
-	  {
-	    substr.set_error ();
-	    return 0.0;
-	  }
-	  neg = true;
+	const char *p = buf;
+	double pv;
+	if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */)))
 	  break;
-
-	case DECIMAL:
-	  if (part != INT_PART)
-	  {
-	    substr.set_error ();
-	    return value;
-	  }
-	  part = FRAC_PART;
-	  break;
-
-	case EXP_NEG:
-	  exp_neg = true;
-	  HB_FALLTHROUGH;
-
-	case EXP_POS:
-	  if (part == EXP_PART)
-	  {
-	    substr.set_error ();
-	    return value;
-	  }
-	  part = EXP_PART;
-	  break;
-
-	default:
-	  switch (part) {
-	    default:
-	    case INT_PART:
-	      int_part = (int_part * 10) + d;
-	      break;
-
-	    case FRAC_PART:
-	      if (likely (frac_part <= MAX_FRACT / 10))
-	      {
-		frac_part = (frac_part * 10) + (unsigned)d;
-		frac_count++;
-	      }
-	      break;
-
-	    case EXP_PART:
-	      if (likely (exp_part * 10 + d <= MAX_EXP))
-	      {
-	      	exp_part = (exp_part * 10) + d;
-	      }
-	      else
-	      	exp_overflow = true;
-	      break;
-	  }
+	return pv;
+      }
+      else
+      {
+	buf[count] = "0123456789.EE?-?"[nibble];
+	if (nibble == EXP_NEG)
+	{
+	  ++count;
+	  if (unlikely (count == ARRAY_LENGTH (buf))) break;
+	  buf[count] = '-';
+	}
       }
     }
 
-    return value;
+    str_ref.set_error ();
+    return .0;
   }
 
-  static bool is_hint_op (OpCode op)
+  static bool is_hint_op (op_code_t op)
   {
     switch (op)
     {
@@ -245,10 +167,10 @@
   }
 };
 
-template <typename VAL=OpStr>
-struct TopDictOpSet : DictOpSet
+template <typename VAL=op_str_t>
+struct top_dict_opset_t : dict_opset_t
 {
-  static void process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval)
+  static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval)
   {
     switch (op) {
       case OpCode_CharStrings:
@@ -263,19 +185,19 @@
 	env.clear_args ();
 	break;
       default:
-	DictOpSet::process_op (op, env);
+	dict_opset_t::process_op (op, env);
 	break;
     }
   }
 };
 
-template <typename OPSET, typename PARAM, typename ENV=NumInterpEnv>
-struct DictInterpreter : Interpreter<ENV>
+template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t>
+struct dict_interpreter_t : interpreter_t<ENV>
 {
   bool interpret (PARAM& param)
   {
     param.init ();
-    while (SUPER::env.substr.avail ())
+    while (SUPER::env.str_ref.avail ())
     {
       OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
       if (unlikely (SUPER::env.in_error ()))
@@ -286,7 +208,7 @@
   }
 
   private:
-  typedef Interpreter<ENV> SUPER;
+  typedef interpreter_t<ENV> SUPER;
 };
 
 } /* namespace CFF */
diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh
index 68e1d81..1c8762c 100644
--- a/src/hb-cff1-interp-cs.hh
+++ b/src/hb-cff1-interp-cs.hh
@@ -33,14 +33,14 @@
 
 using namespace OT;
 
-typedef BiasedSubrs<CFF1Subrs>   CFF1BiasedSubrs;
+typedef biased_subrs_t<CFF1Subrs>   cff1_biased_subrs_t;
 
-struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
+struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
 {
   template <typename ACC>
-  void init (const ByteStr &str, ACC &acc, unsigned int fd)
+  void init (const byte_str_t &str, ACC &acc, unsigned int fd)
   {
-    SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
+    SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
     processed_width = false;
     has_width = false;
     arg_start = 0;
@@ -74,20 +74,20 @@
   bool	  processed_width;
   bool	  has_width;
   unsigned int  arg_start;
-  Number	width;
+  number_t	width;
   bool	  in_seac;
 
   private:
-  typedef CSInterpEnv<Number, CFF1Subrs> SUPER;
+  typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
 };
 
-template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF1CSInterpEnv, PARAM> >
-struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>
+template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
+struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
 {
   /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
   /* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */
 
-  static void process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
+  static void process_op (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
   {
     switch (op) {
       case OpCode_dotsection:
@@ -109,7 +109,7 @@
     }
   }
 
-  static void check_width (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
+  static void check_width (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
   {
     if (!env.processed_width)
     {
@@ -139,22 +139,22 @@
     }
   }
 
-  static void process_seac (CFF1CSInterpEnv &env, PARAM& param)
+  static void process_seac (cff1_cs_interp_env_t &env, PARAM& param)
   {
   }
 
-  static void flush_args (CFF1CSInterpEnv &env, PARAM& param)
+  static void flush_args (cff1_cs_interp_env_t &env, PARAM& param)
   {
     SUPER::flush_args (env, param);
     env.clear_args ();  /* pop off width */
   }
 
   private:
-  typedef CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>  SUPER;
+  typedef cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>  SUPER;
 };
 
 template <typename OPSET, typename PARAM>
-struct CFF1CSInterpreter : CSInterpreter<CFF1CSInterpEnv, OPSET, PARAM> {};
+struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {};
 
 } /* namespace CFF */
 
diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh
index 709bdef..a72100e 100644
--- a/src/hb-cff2-interp-cs.hh
+++ b/src/hb-cff2-interp-cs.hh
@@ -33,26 +33,26 @@
 
 using namespace OT;
 
-struct BlendArg : Number
+struct blend_arg_t : number_t
 {
   void init ()
   {
-    Number::init ();
+    number_t::init ();
     deltas.init ();
   }
 
   void fini ()
   {
-    Number::fini ();
+    number_t::fini ();
     deltas.fini_deep ();
   }
 
-  void set_int (int v) { reset_blends (); Number::set_int (v); }
-  void set_fixed (int32_t v) { reset_blends (); Number::set_fixed (v); }
-  void set_real (double v) { reset_blends (); Number::set_real (v); }
+  void set_int (int v) { reset_blends (); number_t::set_int (v); }
+  void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
+  void set_real (double v) { reset_blends (); number_t::set_real (v); }
 
   void set_blends (unsigned int numValues_, unsigned int valueIndex_,
-			  unsigned int numBlends, hb_array_t<const BlendArg> blends_)
+			  unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
   {
     numValues = numValues_;
     valueIndex = valueIndex_;
@@ -61,7 +61,7 @@
       deltas[i] = blends_[i];
   }
 
-  bool blending () const { return deltas.len > 0; }
+  bool blending () const { return deltas.length > 0; }
   void reset_blends ()
   {
     numValues = valueIndex = 0;
@@ -70,19 +70,19 @@
 
   unsigned int numValues;
   unsigned int valueIndex;
-  hb_vector_t<Number> deltas;
+  hb_vector_t<number_t> deltas;
 };
 
-typedef InterpEnv<BlendArg> BlendInterpEnv;
-typedef BiasedSubrs<CFF2Subrs>   CFF2BiasedSubrs;
+typedef interp_env_t<blend_arg_t> BlendInterpEnv;
+typedef biased_subrs_t<CFF2Subrs>   cff2_biased_subrs_t;
 
-struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
+struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
 {
   template <typename ACC>
-  void init (const ByteStr &str, ACC &acc, unsigned int fd,
+  void init (const byte_str_t &str, ACC &acc, unsigned int fd,
 		    const int *coords_=nullptr, unsigned int num_coords_=0)
   {
-    SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
+    SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
 
     coords = coords_;
     num_coords = num_coords_;
@@ -100,9 +100,9 @@
     SUPER::fini ();
   }
 
-  OpCode fetch_op ()
+  op_code_t fetch_op ()
   {
-    if (this->substr.avail ())
+    if (this->str_ref.avail ())
       return SUPER::fetch_op ();
 
     /* make up return or endchar op */
@@ -112,16 +112,16 @@
       return OpCode_return;
   }
 
-  const BlendArg& eval_arg (unsigned int i)
+  const blend_arg_t& eval_arg (unsigned int i)
   {
-    BlendArg  &arg = argStack[i];
+    blend_arg_t  &arg = argStack[i];
     blend_arg (arg);
     return arg;
   }
 
-  const BlendArg& pop_arg ()
+  const blend_arg_t& pop_arg ()
   {
-    BlendArg  &arg = argStack.pop ();
+    blend_arg_t  &arg = argStack.pop ();
     blend_arg (arg);
     return arg;
   }
@@ -163,14 +163,14 @@
   bool	 seen_vsindex () const { return seen_vsindex_; }
 
   protected:
-  void blend_arg (BlendArg &arg)
+  void blend_arg (blend_arg_t &arg)
   {
     if (do_blend && arg.blending ())
     {
-      if (likely (scalars.len == arg.deltas.len))
+      if (likely (scalars.length == arg.deltas.length))
       {
 	double v = arg.to_real ();
-	for (unsigned int i = 0; i < scalars.len; i++)
+	for (unsigned int i = 0; i < scalars.length; i++)
 	{
 	  v += (double)scalars[i] * arg.deltas[i].to_real ();
 	}
@@ -191,12 +191,12 @@
   bool	  seen_vsindex_;
   bool	  seen_blend;
 
-  typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER;
+  typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
 };
-template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF2CSInterpEnv, PARAM> >
-struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
+template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
+struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
 {
-  static void process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
+  static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
   {
     switch (op) {
       case OpCode_callsubr:
@@ -228,7 +228,7 @@
     }
   }
 
-  static void process_blend (CFF2CSInterpEnv &env, PARAM& param)
+  static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
   {
     unsigned int n, k;
 
@@ -245,7 +245,7 @@
     }
     for (unsigned int i = 0; i < n; i++)
     {
-      const hb_array_t<const BlendArg>	blends = env.argStack.get_subarray (start + n + (i * k));
+      const hb_array_t<const blend_arg_t>	blends = env.argStack.get_subarray (start + n + (i * k));
       env.argStack[start + i].set_blends (n, i, k, blends);
     }
 
@@ -253,18 +253,18 @@
     env.argStack.pop (k * n);
   }
 
-  static void process_vsindex (CFF2CSInterpEnv &env, PARAM& param)
+  static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param)
   {
     env.process_vsindex ();
     env.clear_args ();
   }
 
   private:
-  typedef CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>  SUPER;
+  typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>  SUPER;
 };
 
 template <typename OPSET, typename PARAM>
-struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {};
+struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
 
 } /* namespace CFF */
 
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 93f5b79..0ae0c05 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -27,14 +27,13 @@
  */
 
 #include "hb.hh"
-
 #include "hb-machinery.hh"
 
 #include <locale.h>
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h>
-#endif
 
+#ifdef HB_NO_SETLOCALE
+#define setlocale(Category, Locale) "C"
+#endif
 
 /**
  * SECTION:hb-common
@@ -64,10 +63,10 @@
     {
       const char *p = strchr (c, ':');
       if (!p)
-        p = c + strlen (c);
+	p = c + strlen (c);
 
 #define OPTION(name, symbol) \
-	if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
+	if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
 
       OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
       OPTION ("aat", aat);
@@ -356,7 +355,7 @@
   {
     /* NUL-terminate it. */
     char strbuf[64];
-    len = MIN (len, (int) sizeof (strbuf) - 1);
+    len = hb_min (len, (int) sizeof (strbuf) - 1);
     memcpy (strbuf, str, len);
     strbuf[len] = '\0';
     item = lang_find_or_insert (strbuf);
@@ -382,7 +381,8 @@
 const char *
 hb_language_to_string (hb_language_t language)
 {
-  /* This is actually nullptr-safe! */
+  if (unlikely (!language)) return nullptr;
+
   return language->s;
 }
 
@@ -488,7 +488,7 @@
 
 /**
  * hb_script_to_iso15924_tag:
- * @script: an #hb_script_ to convert.
+ * @script: an #hb_script_t to convert.
  *
  * See hb_script_from_iso15924_tag().
  *
@@ -719,131 +719,24 @@
 static bool
 parse_uint (const char **pp, const char *end, unsigned int *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  unsigned int v;
-
-  /* Intentionally use strtol instead of strtoul, such that
-   * -1 turns into "big number"... */
-  errno = 0;
-  v = strtol (p, &pend, 0);
-  if (errno || p == pend)
-    return false;
+  /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
+   * such that -1 turns into "big number"... */
+  int v;
+  if (unlikely (!hb_parse_int (pp, end, &v))) return false;
 
   *pv = v;
-  *pp += pend - p;
   return true;
 }
 
 static bool
 parse_uint32 (const char **pp, const char *end, uint32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  unsigned int v;
-
-  /* Intentionally use strtol instead of strtoul, such that
-   * -1 turns into "big number"... */
-  errno = 0;
-  v = strtol (p, &pend, 0);
-  if (errno || p == pend)
-    return false;
+  /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
+   * such that -1 turns into "big number"... */
+  int v;
+  if (unlikely (!hb_parse_int (pp, end, &v))) return false;
 
   *pv = v;
-  *pp += pend - p;
-  return true;
-}
-
-#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T locale_t
-#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
-#define HB_FREE_LOCALE(loc) freelocale (loc)
-#elif defined(_MSC_VER)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T _locale_t
-#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
-#define HB_FREE_LOCALE(loc) _free_locale (loc)
-#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
-#endif
-
-#ifdef USE_XLOCALE
-
-#if HB_USE_ATEXIT
-static void free_static_C_locale ();
-#endif
-
-static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
-							  hb_C_locale_lazy_loader_t>
-{
-  static HB_LOCALE_T create ()
-  {
-    HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
-
-#if HB_USE_ATEXIT
-    atexit (free_static_C_locale);
-#endif
-
-    return C_locale;
-  }
-  static void destroy (HB_LOCALE_T p)
-  {
-    HB_FREE_LOCALE (p);
-  }
-  static HB_LOCALE_T get_null ()
-  {
-    return nullptr;
-  }
-} static_C_locale;
-
-#if HB_USE_ATEXIT
-static
-void free_static_C_locale ()
-{
-  static_C_locale.free_instance ();
-}
-#endif
-
-static HB_LOCALE_T
-get_C_locale ()
-{
-  return static_C_locale.get_unconst ();
-}
-#endif /* USE_XLOCALE */
-
-static bool
-parse_float (const char **pp, const char *end, float *pv)
-{
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  float v;
-
-  errno = 0;
-#ifdef USE_XLOCALE
-  v = strtod_l (p, &pend, get_C_locale ());
-#else
-  v = strtod (p, &pend);
-#endif
-  if (errno || p == pend)
-    return false;
-
-  *pv = v;
-  *pp += pend - p;
   return true;
 }
 
@@ -857,9 +750,14 @@
     (*pp)++;
 
   /* CSS allows on/off as aliases 1/0. */
-  if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
+  if (*pp - p == 2
+      && TOLOWER (p[0]) == 'o'
+      && TOLOWER (p[1]) == 'n')
     *pv = 1;
-  else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
+  else if (*pp - p == 3
+	   && TOLOWER (p[0]) == 'o'
+	   && TOLOWER (p[1]) == 'f'
+	   && TOLOWER (p[2]) == 'f')
     *pv = 0;
   else
     return false;
@@ -948,7 +846,7 @@
 {
   bool had_equal = parse_char (pp, end, '=');
   bool had_value = parse_uint32 (pp, end, &feature->value) ||
-                   parse_bool (pp, end, &feature->value);
+		   parse_bool (pp, end, &feature->value);
   /* CSS doesn't use equal-sign between tag and value.
    * If there was an equal-sign, then there *must* be a value.
    * A value without an equal-sign is ok, but not required. */
@@ -974,7 +872,41 @@
  *
  * Parses a string into a #hb_feature_t.
  *
- * TODO: document the syntax here.
+ * The format for specifying feature strings follows. All valid CSS
+ * font-feature-settings values other than 'normal' and the global values are
+ * also accepted, though not documented below. CSS string escapes are not
+ * supported.
+ *
+ * The range indices refer to the positions between Unicode characters. The
+ * position before the first character is always 0.
+ *
+ * The format is Python-esque.  Here is how it all works:
+ *
+ * <informaltable pgwide='1' align='left' frame='none'>
+ * <tgroup cols='5'>
+ * <thead>
+ * <row><entry>Syntax</entry>    <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
+ * </thead>
+ * <tbody>
+ * <row><entry>Setting value:</entry></row>
+ * <row><entry>kern</entry>      <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>+kern</entry>     <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>-kern</entry>     <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
+ * <row><entry>kern=0</entry>    <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
+ * <row><entry>kern=1</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>aalt=2</entry>    <entry>2</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Choose 2nd alternate</entry></row>
+ * <row><entry>Setting index:</entry></row>
+ * <row><entry>kern[]</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>kern[:]</entry>   <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>kern[5:]</entry>  <entry>1</entry>     <entry>5</entry>      <entry>∞</entry>   <entry>Turn feature on, partial</entry></row>
+ * <row><entry>kern[:5]</entry>  <entry>1</entry>     <entry>0</entry>      <entry>5</entry>   <entry>Turn feature on, partial</entry></row>
+ * <row><entry>kern[3:5]</entry> <entry>1</entry>     <entry>3</entry>      <entry>5</entry>   <entry>Turn feature on, range</entry></row>
+ * <row><entry>kern[3]</entry>   <entry>1</entry>     <entry>3</entry>      <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
+ * <row><entry>Mixing it all:</entry></row>
+ * <row><entry>aalt[3:5]=2</entry> <entry>2</entry>   <entry>3</entry>      <entry>5</entry>   <entry>Turn 2nd alternate on for range</entry></row>
+ * </tbody>
+ * </tgroup>
+ * </informaltable>
  *
  * Return value:
  * %true if @str is successfully parsed, %false otherwise.
@@ -1032,21 +964,21 @@
   {
     s[len++] = '[';
     if (feature->start)
-      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
+      len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
       if (feature->end != (unsigned int) -1)
-	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
+	len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
     }
     s[len++] = ']';
   }
   if (feature->value > 1)
   {
     s[len++] = '=';
-    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+    len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
   }
   assert (len < ARRAY_LENGTH (s));
-  len = MIN (len, size - 1);
+  len = hb_min (len, size - 1);
   memcpy (buf, s, len);
   buf[len] = '\0';
 }
@@ -1057,7 +989,11 @@
 parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
 {
   parse_char (pp, end, '='); /* Optional. */
-  return parse_float (pp, end, &variation->value);
+  double v;
+  if (unlikely (!hb_parse_double (pp, end, &v))) return false;
+
+  variation->value = v;
+  return true;
 }
 
 static bool
@@ -1113,14 +1049,71 @@
   while (len && s[len - 1] == ' ')
     len--;
   s[len++] = '=';
-  len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
+  len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
 
   assert (len < ARRAY_LENGTH (s));
-  len = MIN (len, size - 1);
+  len = hb_min (len, size - 1);
   memcpy (buf, s, len);
   buf[len] = '\0';
 }
 
+/**
+ * hb_color_get_alpha:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Alpha channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_alpha) (hb_color_t color)
+{
+  return hb_color_get_alpha (color);
+}
+
+/**
+ * hb_color_get_red:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Red channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_red) (hb_color_t color)
+{
+  return hb_color_get_red (color);
+}
+
+/**
+ * hb_color_get_green:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Green channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_green) (hb_color_t color)
+{
+  return hb_color_get_green (color);
+}
+
+/**
+ * hb_color_get_blue:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Blue channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_blue) (hb_color_t color)
+{
+  return hb_color_get_blue (color);
+}
+
+
 /* If there is no visibility control, then hb-static.cc will NOT
  * define anything.  Instead, we get it to define one set in here
  * only, so only libharfbuzz.so defines them, not other libs. */
diff --git a/src/hb-common.h b/src/hb-common.h
index ae23698..037e508 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -63,11 +63,13 @@
 typedef unsigned __int32 uint32_t;
 typedef __int64 int64_t;
 typedef unsigned __int64 uint64_t;
+#elif defined (__KERNEL__)
+#  include <linux/types.h>
 #else
 #  include <stdint.h>
 #endif
 
-#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
 #define HB_DEPRECATED __attribute__((__deprecated__))
 #elif defined(_MSC_VER) && (_MSC_VER >= 1300)
 #define HB_DEPRECATED __declspec(deprecated)
@@ -75,7 +77,7 @@
 #define HB_DEPRECATED
 #endif
 
-#if    __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
 #define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
 #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
 #define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
@@ -108,7 +110,7 @@
 typedef uint32_t hb_tag_t;
 
 #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
-#define HB_UNTAG(tag)   (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF)
+#define HB_UNTAG(tag)   (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
@@ -357,6 +359,14 @@
   /*11.0*/HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'),
   /*11.0*/HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'),
 
+  /*
+   * Since 2.4.0
+   */
+  /*12.0*/HB_SCRIPT_ELYMAIC			= HB_TAG ('E','l','y','m'),
+  /*12.0*/HB_SCRIPT_NANDINAGARI			= HB_TAG ('N','a','n','d'),
+  /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG	= HB_TAG ('H','m','n','p'),
+  /*12.0*/HB_SCRIPT_WANCHO			= HB_TAG ('W','c','h','o'),
+
   /* No script set. */
   HB_SCRIPT_INVALID				= HB_TAG_NONE,
 
@@ -415,6 +425,21 @@
  */
 #define HB_FEATURE_GLOBAL_END	((unsigned int) -1)
 
+/**
+ * hb_feature_t:
+ * @tag: a feature tag
+ * @value: 0 disables the feature, non-zero (usually 1) enables the feature.
+ * For features implemented as lookup type 3 (like 'salt') the @value is a one
+ * based index into the alternates.
+ * @start: the cluster to start applying this feature setting (inclusive).
+ * @end: the cluster to end applying this feature setting (exclusive).
+ *
+ * The #hb_feature_t is the structure that holds information about requested
+ * feature application. The feature will be applied with the given value to all
+ * glyphs which are in clusters between @start (inclusive) and @end (exclusive).
+ * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
+ * specifies that the feature always applies to the entire buffer.
+ */
 typedef struct hb_feature_t {
   hb_tag_t      tag;
   uint32_t      value;
@@ -459,39 +484,21 @@
 
 #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
 
-/**
- * hb_color_get_alpha:
- *
- *
- *
- * Since: 2.1.0
- */
+HB_EXTERN uint8_t
+hb_color_get_alpha (hb_color_t color);
 #define hb_color_get_alpha(color)	((color) & 0xFF)
-/**
- * hb_color_get_red:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_red(color)		(((color) >> 8) & 0xFF)
-/**
- * hb_color_get_green:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_green(color)	(((color) >> 16) & 0xFF)
-/**
- * hb_color_get_blue:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_blue(color)	(((color) >> 24) & 0xFF)
 
+HB_EXTERN uint8_t
+hb_color_get_red (hb_color_t color);
+#define hb_color_get_red(color)		(((color) >> 8) & 0xFF)
+
+HB_EXTERN uint8_t
+hb_color_get_green (hb_color_t color);
+#define hb_color_get_green(color)	(((color) >> 16) & 0xFF)
+
+HB_EXTERN uint8_t
+hb_color_get_blue (hb_color_t color);
+#define hb_color_get_blue(color)	(((color) >> 24) & 0xFF)
 
 HB_END_DECLS
 
diff --git a/src/hb-config.hh b/src/hb-config.hh
new file mode 100644
index 0000000..14c5395
--- /dev/null
+++ b/src/hb-config.hh
@@ -0,0 +1,162 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_CONFIG_HH
+#define HB_CONFIG_HH
+
+#if 0 /* Make test happy. */
+#include "hb.hh"
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef HB_TINY
+#define HB_LEAN
+#define HB_MINI
+#define HB_NO_MT
+#define HB_NO_UCD_UNASSIGNED
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#ifndef __OPTIMIZE_SIZE__
+#define __OPTIMIZE_SIZE__
+#endif
+#endif
+
+#ifdef HB_LEAN
+#define HB_DISABLE_DEPRECATED
+#define HB_NDEBUG
+#define HB_NO_ATEXIT
+#define HB_NO_BUFFER_MESSAGE
+#define HB_NO_BUFFER_SERIALIZE
+#define HB_NO_BITMAP
+#define HB_NO_CFF
+#define HB_NO_COLOR
+#define HB_NO_ERRNO
+#define HB_NO_FACE_COLLECT_UNICODES
+#define HB_NO_GETENV
+#define HB_NO_HINTING
+#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
+#define HB_NO_LAYOUT_FEATURE_PARAMS
+#define HB_NO_LAYOUT_COLLECT_GLYPHS
+#define HB_NO_LAYOUT_UNUSED
+#define HB_NO_MATH
+#define HB_NO_META
+#define HB_NO_METRICS
+#define HB_NO_MMAP
+#define HB_NO_NAME
+#define HB_NO_OPEN
+#define HB_NO_SETLOCALE
+#define HB_NO_OT_FONT_GLYPH_NAMES
+#define HB_NO_OT_SHAPE_FRACTIONS
+#define HB_NO_STAT
+#define HB_NO_SUBSET_LAYOUT
+#define HB_NO_VAR
+#endif
+
+#ifdef HB_MINI
+#define HB_NO_AAT
+#define HB_NO_LEGACY
+#endif
+
+
+/* Closure of options. */
+
+#ifdef HB_DISABLE_DEPRECATED
+#define HB_IF_NOT_DEPRECATED(x)
+#else
+#define HB_IF_NOT_DEPRECATED(x) x
+#endif
+
+#ifdef HB_NO_AAT
+#define HB_NO_OT_NAME_LANGUAGE_AAT
+#define HB_NO_AAT_SHAPE
+#endif
+
+#ifdef HB_NO_BITMAP
+#define HB_NO_OT_FONT_BITMAP
+#endif
+
+#ifdef HB_NO_CFF
+#define HB_NO_OT_FONT_CFF
+#define HB_NO_SUBSET_CFF
+#endif
+
+#ifdef HB_NO_GETENV
+#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
+#endif
+
+#ifdef HB_NO_LEGACY
+#define HB_NO_CMAP_LEGACY_SUBTABLES
+#define HB_NO_FALLBACK_SHAPE
+#define HB_NO_OT_KERN
+#define HB_NO_OT_LAYOUT_BLACKLIST
+#define HB_NO_OT_SHAPE_FALLBACK
+#endif
+
+#ifdef HB_NO_NAME
+#define HB_NO_OT_NAME_LANGUAGE
+#endif
+
+#ifdef HB_NO_OT
+#define HB_NO_OT_FONT
+#define HB_NO_OT_LAYOUT
+#define HB_NO_OT_TAG
+#define HB_NO_OT_SHAPE
+#endif
+
+#ifdef HB_NO_OT_SHAPE
+#define HB_NO_AAT_SHAPE
+#endif
+
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#endif
+
+#ifdef NDEBUG
+#ifndef HB_NDEBUG
+#define HB_NDEBUG
+#endif
+#endif
+
+#ifdef __OPTIMIZE_SIZE__
+#ifndef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE
+#endif
+#endif
+
+#ifdef HAVE_CONFIG_OVERRIDE_H
+#include "config-override.h"
+#endif
+
+
+#endif /* HB_CONFIG_HH */
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index c181950..8885cfe 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -27,6 +27,9 @@
  */
 
 #include "hb.hh"
+
+#ifdef HAVE_CORETEXT
+
 #include "hb-shaper-impl.hh"
 
 #include "hb-coretext.h"
@@ -46,24 +49,6 @@
 /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
 #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
 
-static CGFloat
-coretext_font_size_from_ptem (float ptem)
-{
-  /* CoreText points are CSS pixels (96 per inch),
-   * NOT typographic points (72 per inch).
-   *
-   * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
-   */
-  ptem *= 96.f / 72.f;
-  return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
-}
-static float
-coretext_font_size_to_ptem (CGFloat size)
-{
-  size *= 72.f / 96.f;
-  return size <= 0.f ? 0 : size;
-}
-
 static void
 release_table_data (void *user_data)
 {
@@ -72,7 +57,7 @@
 }
 
 static hb_blob_t *
-reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
@@ -126,7 +111,7 @@
 release_data (void *info, const void *data, size_t size)
 {
   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
-          hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
+	  hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
 
   hb_blob_destroy ((hb_blob_t *) info);
 }
@@ -171,7 +156,7 @@
   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
   {
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
 # define kCTFontUIFontSystem kCTFontSystemFontType
 # define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
 #endif
@@ -214,7 +199,7 @@
   }
 
   CFURLRef original_url = nullptr;
-#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
   ATSFontRef atsFont;
   FSRef fsref;
   OSStatus status;
@@ -244,25 +229,25 @@
        * process in Blink. This can be detected by the new file URL location
        * that the newly found font points to. */
       CFURLRef new_url = nullptr;
-#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
       atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
       status = ATSFontGetFileReference (atsFont, &fsref);
       if (status == noErr)
-        new_url = CFURLCreateFromFSRef (NULL, &fsref);
+	new_url = CFURLCreateFromFSRef (NULL, &fsref);
 #else
       new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
 #endif
       // Keep reconfigured font if URL cannot be retrieved (seems to be the case
       // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
       if (!original_url || !new_url || CFEqual (original_url, new_url)) {
-        CFRelease (ct_font);
-        ct_font = new_ct_font;
+	CFRelease (ct_font);
+	ct_font = new_ct_font;
       } else {
-        CFRelease (new_ct_font);
-        DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+	CFRelease (new_ct_font);
+	DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
       }
       if (new_url)
-        CFRelease (new_url);
+	CFRelease (new_url);
     }
     else
       DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
@@ -296,7 +281,7 @@
 hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font)
 {
-  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+  return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
 }
 
 /*
@@ -317,7 +302,8 @@
   if (unlikely (!face_data)) return nullptr;
   CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
 
-  CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
+  CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem);
+  CTFontRef ct_font = create_ct_font (cg_font, font_size);
 
   if (unlikely (!ct_font))
   {
@@ -341,7 +327,7 @@
   const hb_coretext_font_data_t *data = font->data.coretext;
   if (unlikely (!data)) return nullptr;
 
-  if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5)
+  if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
   {
     /* XXX-MT-bug
      * Note that evaluating condition above can be dangerous if another thread
@@ -381,7 +367,7 @@
   if (unlikely (hb_object_is_immutable (font)))
     return font;
 
-  hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
+  hb_font_set_ptem (font, CTFontGetSize (ct_font));
 
   /* Let there be dragons here... */
   font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
@@ -410,7 +396,7 @@
   feature_record_t rec;
   unsigned int order;
 
-  static int cmp (const void *pa, const void *pb) {
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
     const active_feature_t *a = (const active_feature_t *) pa;
     const active_feature_t *b = (const active_feature_t *) pb;
     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
@@ -428,7 +414,7 @@
   bool start;
   active_feature_t feature;
 
-  static int cmp (const void *pa, const void *pb) {
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
     const feature_event_t *a = (const feature_event_t *) pa;
     const feature_event_t *b = (const feature_event_t *) pb;
     return a->index < b->index ? -1 : a->index > b->index ? 1 :
@@ -447,9 +433,9 @@
 hb_bool_t
 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 		    hb_font_t          *font,
-                    hb_buffer_t        *buffer,
-                    const hb_feature_t *features,
-                    unsigned int        num_features)
+		    hb_buffer_t        *buffer,
+		    const hb_feature_t *features,
+		    unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
@@ -491,7 +477,7 @@
     {
       const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
       if (!mapping)
-        continue;
+	continue;
 
       active_feature_t feature;
       feature.rec.feature = mapping->aatFeatureType;
@@ -527,22 +513,22 @@
     /* Scan events and save features for each range. */
     hb_vector_t<active_feature_t> active_features;
     unsigned int last_index = 0;
-    for (unsigned int i = 0; i < feature_events.len; i++)
+    for (unsigned int i = 0; i < feature_events.length; i++)
     {
       feature_event_t *event = &feature_events[i];
 
       if (event->index != last_index)
       {
-        /* Save a snapshot of active features and the range. */
+	/* Save a snapshot of active features and the range. */
 	range_record_t *range = range_records.push ();
 
-	if (active_features.len)
+	if (active_features.length)
 	{
 	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 
 	  /* TODO sort and resolve conflicting features? */
 	  /* active_features.qsort (); */
-	  for (unsigned int j = 0; j < active_features.len; j++)
+	  for (unsigned int j = 0; j < active_features.length; j++)
 	  {
 	    CFStringRef keys[] = {
 	      kCTFontFeatureTypeIdentifierKey,
@@ -594,11 +580,11 @@
 
       if (event->start)
       {
-        active_features.push (event->feature);
+	active_features.push (event->feature);
       } else {
-        active_feature_t *feature = active_features.find (&event->feature);
+	active_feature_t *feature = active_features.find (&event->feature);
 	if (feature)
-	  active_features.remove (feature - active_features.arrayZ ());
+	  active_features.remove (feature - active_features.arrayZ);
       }
     }
   }
@@ -608,7 +594,7 @@
 
 #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
   Type *name = (Type *) scratch; \
-  { \
+  do { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     if (unlikely (_consumed > scratch_size)) \
     { \
@@ -617,7 +603,7 @@
     } \
     scratch += _consumed; \
     scratch_size -= _consumed; \
-  }
+  } while (0)
 
   ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
   unsigned int chars_len = 0;
@@ -649,7 +635,7 @@
     DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
     ret = false; \
     goto fail; \
-  } HB_STMT_END;
+  } HB_STMT_END
 
   bool ret = true;
   CFStringRef string_ref = nullptr;
@@ -711,18 +697,18 @@
 /* What's the iOS equivalent of this check?
  * The symbols was introduced in iOS 7.0.
  * At any rate, our fallback is safe and works fine. */
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
 #  define kCTLanguageAttributeName CFSTR ("NSLanguage")
 #endif
-        CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
+	CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
 							    hb_language_to_string (buffer->props.language),
 							    kCFStringEncodingUTF8,
 							    kCFAllocatorNull);
 	if (unlikely (!lang))
-        {
+	{
 	  CFRelease (attr_string);
 	  FAIL ("CFStringCreateWithCStringNoCopy failed");
-        }
+	}
 	CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
 					kCTLanguageAttributeName, lang);
 	CFRelease (lang);
@@ -730,7 +716,7 @@
       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
 				      kCTFontAttributeName, ct_font);
 
-      if (num_features && range_records.len)
+      if (num_features && range_records.length)
       {
 	unsigned int start = 0;
 	range_record_t *last_range = &range_records[0];
@@ -771,7 +757,7 @@
 	      feature.start < chars_len && feature.start < feature.end)
 	  {
 	    CFRange feature_range = CFRangeMake (feature.start,
-	                                         MIN (feature.end, chars_len) - feature.start);
+						 hb_min (feature.end, chars_len) - feature.start);
 	    if (feature.value)
 	      CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
 	    else
@@ -783,7 +769,7 @@
 
       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
       extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
 #endif
       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
@@ -795,8 +781,8 @@
       CFRelease (level_number);
       if (unlikely (!options))
       {
-        CFRelease (attr_string);
-        FAIL ("CFDictionaryCreate failed");
+	CFRelease (attr_string);
+	FAIL ("CFDictionaryCreate failed");
       }
 
       CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
@@ -879,7 +865,7 @@
 	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
 	 */
 	bool matched = false;
-	for (unsigned int i = 0; i < range_records.len; i++)
+	for (unsigned int i = 0; i < range_records.length; i++)
 	  if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
 	  {
 	    matched = true;
@@ -907,7 +893,7 @@
 	if (!matched)
 	{
 	  CFRange range = CTRunGetStringRange (run);
-          DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
+	  DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
 		     range.location, range.location + range.length);
 	  if (!buffer->ensure_inplace (buffer->len + range.length))
 	    goto resize_and_retry;
@@ -935,7 +921,7 @@
 		  continue;
 	      }
 	      if (buffer->unicode->is_default_ignorable (ch))
-	        continue;
+		continue;
 
 	      info->codepoint = notdef;
 	      info->cluster = log_clusters[j];
@@ -977,10 +963,10 @@
 
 #define SCRATCH_RESTORE() \
   scratch_size = scratch_size_saved; \
-  scratch = scratch_saved;
+  scratch = scratch_saved
 
       { /* Setup glyphs */
-        SCRATCH_SAVE();
+	SCRATCH_SAVE();
 	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
 	if (!glyphs) {
 	  ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
@@ -1003,12 +989,12 @@
 	SCRATCH_RESTORE();
       }
       {
-        /* Setup positions.
+	/* Setup positions.
 	 * Note that CoreText does not return advances for glyphs.  As such,
 	 * for all but last glyph, we use the delta position to next glyph as
 	 * advance (in the advance direction only), and for last glyph we set
 	 * whatever is needed to make the whole run's advance add up. */
-        SCRATCH_SAVE();
+	SCRATCH_SAVE();
 	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
 	if (!positions) {
 	  ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
@@ -1069,7 +1055,7 @@
     if (false)
     {
       /* Make sure all runs had the expected direction. */
-      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+      HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
       assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
       assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
     }
@@ -1116,7 +1102,7 @@
 	unsigned int cluster = info[count - 1].cluster;
 	for (unsigned int i = count - 1; i > 0; i--)
 	{
-	  cluster = MIN (cluster, info[i - 1].cluster);
+	  cluster = hb_min (cluster, info[i - 1].cluster);
 	  info[i - 1].cluster = cluster;
 	}
       }
@@ -1125,7 +1111,7 @@
 	unsigned int cluster = info[0].cluster;
 	for (unsigned int i = 1; i < count; i++)
 	{
-	  cluster = MIN (cluster, info[i].cluster);
+	  cluster = hb_min (cluster, info[i].cluster);
 	  info[i].cluster = cluster;
 	}
       }
@@ -1142,7 +1128,7 @@
   if (line)
     CFRelease (line);
 
-  for (unsigned int i = 0; i < range_records.len; i++)
+  for (unsigned int i = 0; i < range_records.length; i++)
     if (range_records[i].font)
       CFRelease (range_records[i].font);
 
@@ -1150,57 +1136,4 @@
 }
 
 
-/*
- * AAT shaper
- */
-
-/*
- * shaper face data
- */
-
-struct hb_coretext_aat_face_data_t {};
-
-hb_coretext_aat_face_data_t *
-_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
-{
-  return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ?
-	 (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
-}
-
-void
-_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
-{
-}
-
-
-/*
- * shaper font data
- */
-
-struct hb_coretext_aat_font_data_t {};
-
-hb_coretext_aat_font_data_t *
-_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
-{
-  return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
-}
-
-void
-_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
-{
-}
-
-
-/*
- * shaper
- */
-
-hb_bool_t
-_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
-			hb_font_t          *font,
-			hb_buffer_t        *buffer,
-			const hb_feature_t *features,
-			unsigned int        num_features)
-{
-  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
-}
+#endif
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index 41a85b5..a7e52c8 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -29,7 +29,7 @@
 
 #include "hb.hh"
 #include "hb-atomic.hh"
-#include "hb-dsalgs.hh"
+#include "hb-algs.hh"
 
 
 #ifndef HB_DEBUG
@@ -63,6 +63,9 @@
 static inline hb_options_t
 hb_options ()
 {
+#ifdef HB_NO_GETENV
+  return hb_options_t ();
+#endif
   /* Make a local copy, so we can access bitfield threadsafely. */
   hb_options_union_t u;
   u.i = _hb_options.get_relaxed ();
@@ -158,7 +161,7 @@
       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
     fprintf (stderr, "%2u %s" VRBAR "%s",
 	     level,
-	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
+	     bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
 	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
   } else
     fprintf (stderr, "   " VRBAR LBAR);
@@ -246,8 +249,8 @@
 };
 
 template <>
-struct hb_printer_t<hb_void_t> {
-  const char *print (hb_void_t) { return ""; }
+struct hb_printer_t<hb_empty_t> {
+  const char *print (hb_empty_t) { return ""; }
 };
 
 
@@ -263,7 +266,7 @@
   }
 }
 template <>
-/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
 {}
 
 template <int max_level, typename ret_t>
@@ -293,22 +296,23 @@
     if (plevel) --*plevel;
   }
 
-  ret_t ret (ret_t v,
-	     const char *func = "",
-	     unsigned int line = 0)
+  template <typename T>
+  T ret (T&& v,
+	 const char *func = "",
+	 unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
-      return v;
+      return hb_forward<T> (v);
     }
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
 			      "return %s (line %d)",
-			      hb_printer_t<ret_t>().print (v), line);
+			      hb_printer_t<decltype (v)>().print (v), line);
     if (plevel) --*plevel;
     plevel = nullptr;
     returned = true;
-    return v;
+    return hb_forward<T> (v);
   }
 
   private:
@@ -327,18 +331,20 @@
 				   const char *message,
 				   ...) HB_PRINTF_FUNC(6, 7) {}
 
-  ret_t ret (ret_t v,
-	     const char *func HB_UNUSED = nullptr,
-	     unsigned int line HB_UNUSED = 0) { return v; }
+  template <typename T>
+  T ret (T&& v,
+	 const char *func HB_UNUSED = nullptr,
+	 unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
 };
 
 /* For disabled tracing; optimize out everything.
  * https://github.com/harfbuzz/harfbuzz/pull/605 */
 template <typename ret_t>
 struct hb_no_trace_t {
-  ret_t ret (ret_t v,
-	     const char *func HB_UNUSED = "",
-	     unsigned int line HB_UNUSED = 0) { return v; }
+  template <typename T>
+  T ret (T&& v,
+	 const char *func HB_UNUSED = nullptr,
+	 unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
 };
 
 #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
@@ -401,30 +407,6 @@
 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
 #endif
 
-#ifndef HB_DEBUG_CLOSURE
-#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
-#endif
-#if HB_DEBUG_CLOSURE
-#define TRACE_CLOSURE(this) \
-	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 " ")
-#else
-#define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
-#endif
-
-#ifndef HB_DEBUG_COLLECT_GLYPHS
-#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
-#endif
-#if HB_DEBUG_COLLECT_GLYPHS
-#define TRACE_COLLECT_GLYPHS(this) \
-	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 " ")
-#else
-#define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
-#endif
-
 #ifndef HB_DEBUG_SANITIZE
 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
 #endif
@@ -432,7 +414,7 @@
 #define TRACE_SANITIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 " ");
+	 " ")
 #else
 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
 #endif
@@ -444,7 +426,7 @@
 #define TRACE_SERIALIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
 	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
-	 " ");
+	 " ")
 #else
 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
 #endif
@@ -456,39 +438,24 @@
 #define TRACE_SUBSET(this) \
   hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
   (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-   " ");
+   " ")
 #else
 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 #endif
 
-#ifndef HB_DEBUG_WOULD_APPLY
-#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
-#endif
-#if HB_DEBUG_WOULD_APPLY
-#define TRACE_WOULD_APPLY(this) \
-	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "%d glyphs", c->len);
-#else
-#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
-#endif
-
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
 	HB_DEBUG_APPLY + \
-	HB_DEBUG_CLOSURE + \
-	HB_DEBUG_COLLECT_GLYPHS + \
 	HB_DEBUG_SANITIZE + \
 	HB_DEBUG_SERIALIZE + \
-  HB_DEBUG_SUBSET + \
-	HB_DEBUG_WOULD_APPLY + \
+	HB_DEBUG_SUBSET + \
 	0)
 #endif
 #if HB_DEBUG_DISPATCH
 #define TRACE_DISPATCH(this, format) \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "format %d", (int) format);
+	 "format %d", (int) format)
 #else
 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 #endif
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index 4a5e702..43f89a4 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -63,7 +63,7 @@
 					       hb_codepoint_t *glyph,
 					       void *user_data);
 
-HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
+HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
@@ -165,30 +165,9 @@
 				    hb_codepoint_t     *decomposed);
 
 
-typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
-							   hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
-							   void *user_data);
-typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
 typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
 
 /**
- * hb_font_funcs_set_glyph_h_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
- * 
- *
- * Since: 0.9.2
- * Deprecated: 2.0.0
- **/
-HB_EXTERN void
-hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
-					hb_font_get_glyph_h_kerning_func_t func,
-					void *user_data, hb_destroy_func_t destroy);
-
-/**
  * hb_font_funcs_set_glyph_v_kerning_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
@@ -206,19 +185,9 @@
 					void *user_data, hb_destroy_func_t destroy);
 
 HB_EXTERN hb_position_t
-hb_font_get_glyph_h_kerning (hb_font_t *font,
-			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
-HB_EXTERN hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
 			     hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
 
-HB_EXTERN void
-hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
-					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
-					 hb_direction_t direction,
-					 hb_position_t *x, hb_position_t *y);
-
-
 #endif
 
 HB_END_DECLS
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index e93cf90..efb2029 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2015-2018  Ebrahim Byagowi
+ * Copyright © 2015-2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -23,13 +23,23 @@
  */
 
 #include "hb.hh"
+
+#ifdef HAVE_DIRECTWRITE
+
 #include "hb-shaper-impl.hh"
 
-#include <DWrite_1.h>
+#include <dwrite_1.h>
 
 #include "hb-directwrite.h"
 
 
+/* Declare object creator for dynamic support of DWRITE */
+typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
+  DWRITE_FACTORY_TYPE factoryType,
+  REFIID              iid,
+  IUnknown            **factory
+);
+
 /*
  * hb-directwrite uses new/delete syntatically but as we let users
  * to override malloc/free, we will redefine new/delete so users
@@ -71,6 +81,8 @@
     *fontFileStream = mFontFileStream;
     return S_OK;
   }
+
+  virtual ~DWriteFontFileLoader() {}
 };
 
 class DWriteFontFileStream : public IDWriteFontFileStream
@@ -122,6 +134,8 @@
 
   virtual HRESULT STDMETHODCALLTYPE
   GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
+
+  virtual ~DWriteFontFileStream() {}
 };
 
 
@@ -131,10 +145,11 @@
 
 struct hb_directwrite_face_data_t
 {
+  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
-  IDWriteFontFileStream *fontFileStream;
-  IDWriteFontFileLoader *fontFileLoader;
+  DWriteFontFileStream *fontFileStream;
+  DWriteFontFileLoader *fontFileLoader;
   IDWriteFontFace *fontFace;
   hb_blob_t *faceBlob;
 };
@@ -146,12 +161,43 @@
   if (unlikely (!data))
     return nullptr;
 
-  // TODO: factory and fontFileLoader should be cached separately
-  IDWriteFactory* dwriteFactory;
-  DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-		       (IUnknown**) &dwriteFactory);
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
+    return nullptr; \
+  } HB_STMT_END
+
+  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
+  if (unlikely (!data->dwrite_dll))
+    FAIL ("Cannot find DWrite.DLL");
+
+  t_DWriteCreateFactory p_DWriteCreateFactory;
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+  p_DWriteCreateFactory = (t_DWriteCreateFactory)
+			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+  if (unlikely (!p_DWriteCreateFactory))
+    FAIL ("Cannot find DWriteCreateFactory().");
 
   HRESULT hr;
+
+  // TODO: factory and fontFileLoader should be cached separately
+  IDWriteFactory* dwriteFactory;
+  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+			      (IUnknown**) &dwriteFactory);
+
+  if (unlikely (hr != S_OK))
+    FAIL ("Failed to run DWriteCreateFactory().");
+
   hb_blob_t *blob = hb_face_reference_blob (face);
   DWriteFontFileStream *fontFileStream;
   fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
@@ -165,12 +211,6 @@
   hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
 						     fontFileLoader, &fontFile);
 
-#define FAIL(...) \
-  HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
-    return nullptr; \
-  } HB_STMT_END;
-
   if (FAILED (hr))
     FAIL ("Failed to load font file from data!");
 
@@ -217,6 +257,8 @@
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
+  if (data->dwrite_dll)
+    FreeLibrary (data->dwrite_dll);
   if (data)
     delete data;
 }
@@ -281,7 +323,7 @@
 public:
   TextAnalysis (const wchar_t* text, uint32_t textLength,
 		const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
-	       : mText (text), mTextLength (textLength), mLocaleName (localeName),
+	       : mTextLength (textLength), mText (text), mLocaleName (localeName),
 		 mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
   ~TextAnalysis ()
   {
@@ -497,11 +539,6 @@
   Run  mRunHead;
 };
 
-static inline uint16_t hb_uint16_swap (const uint16_t v)
-{ return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
-
 /*
  * shaper
  */
@@ -516,7 +553,6 @@
 {
   hb_face_t *face = font->face;
   const hb_directwrite_face_data_t *face_data = face->data.directwrite;
-  const hb_directwrite_font_data_t *font_data = font->data.directwrite;
   IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
   IDWriteFontFace *fontFace = face_data->fontFace;
 
@@ -527,12 +563,12 @@
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
-  { \
+  do { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     assert (_consumed <= scratch_size); \
     scratch += _consumed; \
     scratch_size -= _consumed; \
-  }
+  } while (0)
 
 #define utf16_index() var1.u32
 
@@ -589,7 +625,7 @@
   HB_STMT_START { \
     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
-  } HB_STMT_END;
+  } HB_STMT_END
 
   if (FAILED (hr))
     FAIL ("Analyzer failed to generate results.");
@@ -655,10 +691,10 @@
    * alignment needed after the WORD array.  sizeof (WORD) == 2. */
   unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
 			     / (sizeof (WORD) +
-			        sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
-			        sizeof (int) +
-			        sizeof (DWRITE_GLYPH_OFFSET) +
-			        sizeof (uint32_t));
+				sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
+				sizeof (int) +
+				sizeof (DWRITE_GLYPH_OFFSET) +
+				sizeof (uint32_t));
   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
 
 #undef ALLOCATE_ARRAY
@@ -770,15 +806,15 @@
 
   /* Calculate visual-clusters.  That's what we ship. */
   for (unsigned int i = 0; i < glyphCount; i++)
-    vis_clusters[i] = -1;
+    vis_clusters[i] = (uint32_t) -1;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
     uint32_t *p =
       &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
-    *p = MIN (*p, buffer->info[i].cluster);
+    *p = hb_min (*p, buffer->info[i].cluster);
   }
   for (unsigned int i = 1; i < glyphCount; i++)
-    if (vis_clusters[i] == -1)
+    if (vis_clusters[i] == (uint32_t) -1)
       vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
@@ -843,16 +879,12 @@
 				     features, num_features, 0);
 }
 
-/*
- * Public [experimental] API
- */
-
-hb_bool_t
-hb_directwrite_shape_experimental_width (hb_font_t          *font,
-					 hb_buffer_t        *buffer,
-					 const hb_feature_t *features,
-					 unsigned int        num_features,
-					 float               width)
+HB_UNUSED static bool
+_hb_directwrite_shape_experimental_width (hb_font_t          *font,
+					  hb_buffer_t        *buffer,
+					  const hb_feature_t *features,
+					  unsigned int        num_features,
+					  float               width)
 {
   static const char *shapers = "directwrite";
   hb_shape_plan_t *shape_plan;
@@ -865,3 +897,83 @@
 
   return res;
 }
+
+struct _hb_directwrite_font_table_context {
+  IDWriteFontFace *face;
+  void *table_context;
+};
+
+static void
+_hb_directwrite_table_data_release (void *data)
+{
+  _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
+  context->face->ReleaseFontTable (context->table_context);
+  delete context;
+}
+
+static hb_blob_t *
+_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
+  const void *data;
+  uint32_t length;
+  void *table_context;
+  BOOL exists;
+  if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
+						    &length, &table_context, &exists)))
+    return nullptr;
+
+  if (!data || !exists || !length)
+  {
+    dw_face->ReleaseFontTable (table_context);
+    return nullptr;
+  }
+
+  _hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
+  context->face = dw_face;
+  context->table_context = table_context;
+
+  return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
+			 context, _hb_directwrite_table_data_release);
+}
+
+static void
+_hb_directwrite_font_release (void *data)
+{
+  if (data)
+    ((IDWriteFontFace *) data)->Release ();
+}
+
+/**
+ * hb_directwrite_face_create:
+ * @font_face: a DirectWrite IDWriteFontFace object.
+ *
+ * Return value: #hb_face_t object corresponding to the given input
+ *
+ * Since: 2.4.0
+ **/
+hb_face_t *
+hb_directwrite_face_create (IDWriteFontFace *font_face)
+{
+  if (font_face)
+    font_face->AddRef ();
+  return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
+				    _hb_directwrite_font_release);
+}
+
+/**
+* hb_directwrite_face_get_font_face:
+* @face: a #hb_face_t object
+*
+* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
+*
+* Since: 2.5.0
+**/
+IDWriteFontFace *
+hb_directwrite_face_get_font_face (hb_face_t *face)
+{
+  return face->data.directwrite->fontFace;
+}
+
+
+#endif
diff --git a/src/hb-directwrite.h b/src/hb-directwrite.h
index 9bfd1f7..f837627 100644
--- a/src/hb-directwrite.h
+++ b/src/hb-directwrite.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2015  Ebrahim Byagowi
+ * Copyright © 2015-2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -29,10 +29,11 @@
 
 HB_BEGIN_DECLS
 
-HB_EXTERN hb_bool_t
-hb_directwrite_shape_experimental_width (hb_font_t *font, hb_buffer_t *buffer,
-					 const hb_feature_t *features,
-					 unsigned int num_features, float width);
+HB_EXTERN hb_face_t *
+hb_directwrite_face_create (IDWriteFontFace *font_face);
+
+HB_EXTERN IDWriteFontFace *
+hb_directwrite_face_get_font_face (hb_face_t *face);
 
 HB_END_DECLS
 
diff --git a/src/hb-dispatch.hh b/src/hb-dispatch.hh
new file mode 100644
index 0000000..1ce3fac
--- /dev/null
+++ b/src/hb-dispatch.hh
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_DISPATCH_HH
+#define HB_DISPATCH_HH
+
+#include "hb.hh"
+
+/*
+ * Dispatch
+ */
+
+template <typename Context, typename Return, unsigned int MaxDebugDepth>
+struct hb_dispatch_context_t
+{
+  private:
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  const Context* thiz () const { return static_cast<const Context *> (this); }
+	Context* thiz ()       { return static_cast<      Context *> (this); }
+  public:
+  static constexpr unsigned max_debug_depth = MaxDebugDepth;
+  typedef Return return_t;
+  template <typename T, typename F>
+  bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
+  template <typename T, typename ...Ts>
+  return_t dispatch (const T &obj, Ts&&... ds)
+  { return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
+  static return_t no_dispatch_return_value () { return Context::default_return_value (); }
+  static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
+};
+
+
+#endif /* HB_DISPATCH_HH */
diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
deleted file mode 100644
index 48ce989..0000000
--- a/src/hb-dsalgs.hh
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * Copyright © 2017  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_DSALGS_HH
-#define HB_DSALGS_HH
-
-#include "hb.hh"
-
-#include "hb-null.hh"
-
-
-/* Void! For when we need a expression-type of void. */
-typedef const struct _hb_void_t *hb_void_t;
-#define HB_VOID ((const _hb_void_t *) nullptr)
-
-
-/*
- * Bithacks.
- */
-
-/* Return the number of 1 bits in v. */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_popcount (T v)
-{
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return __builtin_popcount (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return __builtin_popcountl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return __builtin_popcountll (v);
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "HACKMEM 169" */
-    uint32_t y;
-    y = (v >> 1) &033333333333;
-    y = v - y - ((y >>1) & 033333333333);
-    return (((y + (y >> 3)) & 030707070707) % 077);
-  }
-
-  if (sizeof (T) == 8)
-  {
-    unsigned int shift = 32;
-    return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
-  }
-
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-/* Returns the number of bits needed to store number */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_bit_storage (T v)
-{
-  if (unlikely (!v)) return 0;
-
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return sizeof (unsigned int) * 8 - __builtin_clz (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
-#endif
-
-#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
-  if (sizeof (T) <= sizeof (unsigned int))
-  {
-    unsigned long where;
-    _BitScanReverse (&where, v);
-    return 1 + where;
-  }
-# if _WIN64
-  if (sizeof (T) <= 8)
-  {
-    unsigned long where;
-    _BitScanReverse64 (&where, v);
-    return 1 + where;
-  }
-# endif
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "bithacks" */
-    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
-    const unsigned int S[] = {1, 2, 4, 8, 16};
-    unsigned int r = 0;
-    for (int i = 4; i >= 0; i--)
-      if (v & b[i])
-      {
-	v >>= S[i];
-	r |= S[i];
-      }
-    return r + 1;
-  }
-  if (sizeof (T) <= 8)
-  {
-    /* "bithacks" */
-    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
-    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
-    unsigned int r = 0;
-    for (int i = 5; i >= 0; i--)
-      if (v & b[i])
-      {
-	v >>= S[i];
-	r |= S[i];
-      }
-    return r + 1;
-  }
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
-			  hb_bit_storage<uint64_t> ((uint64_t) v);
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-/* Returns the number of zero bits in the least significant side of v */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_ctz (T v)
-{
-  if (unlikely (!v)) return 0;
-
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return __builtin_ctz (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return __builtin_ctzl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return __builtin_ctzll (v);
-#endif
-
-#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
-  if (sizeof (T) <= sizeof (unsigned int))
-  {
-    unsigned long where;
-    _BitScanForward (&where, v);
-    return where;
-  }
-# if _WIN64
-  if (sizeof (T) <= 8)
-  {
-    unsigned long where;
-    _BitScanForward64 (&where, v);
-    return where;
-  }
-# endif
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "bithacks" */
-    unsigned int c = 32;
-    v &= - (int32_t) v;
-    if (v) c--;
-    if (v & 0x0000FFFF) c -= 16;
-    if (v & 0x00FF00FF) c -= 8;
-    if (v & 0x0F0F0F0F) c -= 4;
-    if (v & 0x33333333) c -= 2;
-    if (v & 0x55555555) c -= 1;
-    return c;
-  }
-  if (sizeof (T) <= 8)
-  {
-    /* "bithacks" */
-    unsigned int c = 64;
-    v &= - (int64_t) (v);
-    if (v) c--;
-    if (v & 0x00000000FFFFFFFFULL) c -= 32;
-    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
-    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
-    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
-    if (v & 0x3333333333333333ULL) c -= 2;
-    if (v & 0x5555555555555555ULL) c -= 1;
-    return c;
-  }
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
-			  hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-
-/*
- * Tiny stuff.
- */
-
-template <typename T>
-static inline T* hb_addressof (T& arg)
-{
-  /* https://en.cppreference.com/w/cpp/memory/addressof */
-  return reinterpret_cast<T*>(
-	   &const_cast<char&>(
-	      reinterpret_cast<const volatile char&>(arg)));
-}
-
-/* ASCII tag/character handling */
-static inline bool ISALPHA (unsigned char c)
-{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
-static inline bool ISALNUM (unsigned char c)
-{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
-static inline bool ISSPACE (unsigned char c)
-{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
-static inline unsigned char TOUPPER (unsigned char c)
-{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
-static inline unsigned char TOLOWER (unsigned char c)
-{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
-
-#undef MIN
-template <typename Type>
-static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
-
-#undef MAX
-template <typename Type>
-static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
-
-static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
-{ return (a + (b - 1)) / b; }
-
-
-#undef  ARRAY_LENGTH
-template <typename Type, unsigned int n>
-static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
-/* A const version, but does not detect erratically being called on pointers. */
-#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
-
-
-static inline int
-hb_memcmp (const void *a, const void *b, unsigned int len)
-{
-  /* It's illegal to pass NULL to memcmp(), even if len is zero.
-   * So, wrap it.
-   * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
-  if (!len) return 0;
-  return memcmp (a, b, len);
-}
-
-static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
-{
-  return (size > 0) && (count >= ((unsigned int) -1) / size);
-}
-
-static inline unsigned int
-hb_ceil_to_4 (unsigned int v)
-{
-  return ((v - 1) | 3) + 1;
-}
-
-template <typename T> struct hb_is_signed;
-template <> struct hb_is_signed<signed char> { enum { value = true }; };
-template <> struct hb_is_signed<signed short> { enum { value = true }; };
-template <> struct hb_is_signed<signed int> { enum { value = true }; };
-template <> struct hb_is_signed<signed long> { enum { value = true }; };
-template <> struct hb_is_signed<unsigned char> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned short> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned int> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned long> { enum { value = false }; };
-/* We need to define hb_is_signed for the typedefs we use on pre-Visual
- * Studio 2010 for the int8_t type, since __int8/__int64 is not considered
- * the same as char/long.  The previous lines will suffice for the other
- * types, though.  Note that somehow, unsigned __int8 is considered same
- * as unsigned char.
- * https://github.com/harfbuzz/harfbuzz/pull/1499
- */
-#if defined(_MSC_VER) && (_MSC_VER < 1600)
-template <> struct hb_is_signed<__int8> { enum { value = true }; };
-#endif
-
-template <typename T> static inline bool
-hb_in_range (T u, T lo, T hi)
-{
-  /* The sizeof() is here to force template instantiation.
-   * I'm sure there are better ways to do this but can't think of
-   * one right now.  Declaring a variable won't work as HB_UNUSED
-   * is unusable on some platforms and unused types are less likely
-   * to generate a warning than unused variables. */
-  static_assert (!hb_is_signed<T>::value, "");
-
-  /* The casts below are important as if T is smaller than int,
-   * the subtract results will become a signed int! */
-  return (T)(u - lo) <= (T)(hi - lo);
-}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
-{
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
-}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
-{
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
-}
-
-
-/*
- * Sort and search.
- */
-
-static inline void *
-hb_bsearch (const void *key, const void *base,
-	    size_t nmemb, size_t size,
-	    int (*compar)(const void *_key, const void *_item))
-{
-  int min = 0, max = (int) nmemb - 1;
-  while (min <= max)
-  {
-    int mid = (min + max) / 2;
-    const void *p = (const void *) (((const char *) base) + (mid * size));
-    int c = compar (key, p);
-    if (c < 0)
-      max = mid - 1;
-    else if (c > 0)
-      min = mid + 1;
-    else
-      return (void *) p;
-  }
-  return nullptr;
-}
-
-static inline void *
-hb_bsearch_r (const void *key, const void *base,
-	      size_t nmemb, size_t size,
-	      int (*compar)(const void *_key, const void *_item, void *_arg),
-	      void *arg)
-{
-  int min = 0, max = (int) nmemb - 1;
-  while (min <= max)
-  {
-    int mid = ((unsigned int) min + (unsigned int) max) / 2;
-    const void *p = (const void *) (((const char *) base) + (mid * size));
-    int c = compar (key, p, arg);
-    if (c < 0)
-      max = mid - 1;
-    else if (c > 0)
-      min = mid + 1;
-    else
-      return (void *) p;
-  }
-  return nullptr;
-}
-
-
-/* From https://github.com/noporpoise/sort_r
- * With following modifications:
- *
- * 10 November 2018:
- * https://github.com/noporpoise/sort_r/issues/7
- */
-
-/* Isaac Turner 29 April 2014 Public Domain */
-
-/*
-
-hb_sort_r function to be exported.
-
-Parameters:
-  base is the array to be sorted
-  nel is the number of elements in the array
-  width is the size in bytes of each element of the array
-  compar is the comparison function
-  arg is a pointer to be passed to the comparison function
-
-void hb_sort_r(void *base, size_t nel, size_t width,
-               int (*compar)(const void *_a, const void *_b, void *_arg),
-               void *arg);
-*/
-
-
-/* swap a, b iff a>b */
-/* __restrict is same as restrict but better support on old machines */
-static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
-			  int (*compar)(const void *_a, const void *_b,
-					void *_arg),
-			  void *arg)
-{
-  char tmp, *end = a+w;
-  if(compar(a, b, arg) > 0) {
-    for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
-    return 1;
-  }
-  return 0;
-}
-
-/* Note: quicksort is not stable, equivalent values may be swapped */
-static inline void sort_r_simple(void *base, size_t nel, size_t w,
-				 int (*compar)(const void *_a, const void *_b,
-					       void *_arg),
-				 void *arg)
-{
-  char *b = (char *)base, *end = b + nel*w;
-  if(nel < 7) {
-    /* Insertion sort for arbitrarily small inputs */
-    char *pi, *pj;
-    for(pi = b+w; pi < end; pi += w) {
-      for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
-    }
-  }
-  else
-  {
-    /* nel > 6; Quicksort */
-
-    /* Use median of first, middle and last items as pivot */
-    char *x, *y, *xend, ch;
-    char *pl, *pm, *pr;
-    char *last = b+w*(nel-1), *tmp;
-    char *l[3];
-    l[0] = b;
-    l[1] = b+w*(nel/2);
-    l[2] = last;
-
-    if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
-    if(compar(l[1],l[2],arg) > 0) {
-      tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
-      if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
-    }
-
-    /* swap l[id], l[2] to put pivot as last element */
-    for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
-      ch = *x; *x = *y; *y = ch;
-    }
-
-    pl = b;
-    pr = last;
-
-    while(pl < pr) {
-      pm = pl+((pr-pl+1)>>1);
-      for(; pl < pm; pl += w) {
-        if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
-          pr -= w; /* pivot now at pl */
-          break;
-        }
-      }
-      pm = pl+((pr-pl)>>1);
-      for(; pm < pr; pr -= w) {
-        if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
-          pl += w; /* pivot now at pr */
-          break;
-        }
-      }
-    }
-
-    sort_r_simple(b, (pl-b)/w, w, compar, arg);
-    sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
-  }
-}
-
-static inline void hb_sort_r(void *base, size_t nel, size_t width,
-			     int (*compar)(const void *_a, const void *_b, void *_arg),
-			     void *arg)
-{
-    sort_r_simple(base, nel, width, compar, arg);
-}
-
-
-template <typename T, typename T2> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
-{
-  for (unsigned int i = 1; i < len; i++)
-  {
-    unsigned int j = i;
-    while (j && compar (&array[j - 1], &array[i]) > 0)
-      j--;
-    if (i == j)
-      continue;
-    /* Move item i to occupy place for item j, shift what's in between. */
-    {
-      T t = array[i];
-      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
-      array[j] = t;
-    }
-    if (array2)
-    {
-      T2 t = array2[i];
-      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
-      array2[j] = t;
-    }
-  }
-}
-
-template <typename T> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
-{
-  hb_stable_sort (array, len, compar, (int *) nullptr);
-}
-
-static inline hb_bool_t
-hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
-{
-  /* Pain because we don't know whether s is nul-terminated. */
-  char buf[64];
-  len = MIN (ARRAY_LENGTH (buf) - 1, len);
-  strncpy (buf, s, len);
-  buf[len] = '\0';
-
-  char *end;
-  errno = 0;
-  unsigned long v = strtoul (buf, &end, base);
-  if (errno) return false;
-  if (*end) return false;
-  *out = v;
-  return true;
-}
-
-
-struct HbOpOr
-{
-  enum { passthru_left = true };
-  enum { passthru_right = true };
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
-};
-struct HbOpAnd
-{
-  enum { passthru_left = false };
-  enum { passthru_right = false };
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
-};
-struct HbOpMinus
-{
-  enum { passthru_left = true };
-  enum { passthru_right = false };
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
-};
-struct HbOpXor
-{
-  enum { passthru_left = true };
-  enum { passthru_right = true };
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
-};
-
-
-/* Compiler-assisted vectorization. */
-
-/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
- * Define that to 0 to disable. */
-template <typename elt_t, unsigned int byte_size>
-struct hb_vector_size_t
-{
-  elt_t& operator [] (unsigned int i) { return u.v[i]; }
-  const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
-
-  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
-
-  template <class Op>
-  hb_vector_size_t process (const hb_vector_size_t &o) const
-  {
-    hb_vector_size_t r;
-#if HB_VECTOR_SIZE
-    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
-	Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
-    else
-#endif
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
-	Op::process (r.u.v[i], u.v[i], o.u.v[i]);
-    return r;
-  }
-  hb_vector_size_t operator | (const hb_vector_size_t &o) const
-  { return process<HbOpOr> (o); }
-  hb_vector_size_t operator & (const hb_vector_size_t &o) const
-  { return process<HbOpAnd> (o); }
-  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
-  { return process<HbOpXor> (o); }
-  hb_vector_size_t operator ~ () const
-  {
-    hb_vector_size_t r;
-#if HB_VECTOR_SIZE && 0
-    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
-	r.u.vec[i] = ~u.vec[i];
-    else
-#endif
-    for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
-      r.u.v[i] = ~u.v[i];
-    return r;
-  }
-
-  private:
-  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
-  union {
-    elt_t v[byte_size / sizeof (elt_t)];
-#if HB_VECTOR_SIZE
-    hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
-#endif
-  } u;
-};
-
-
-#endif /* HB_DSALGS_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 8bb8c51..0c9949f 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -367,6 +367,9 @@
 hb_face_reference_table (const hb_face_t *face,
 			 hb_tag_t tag)
 {
+  if (unlikely (tag == HB_TAG_NONE))
+    return hb_blob_get_empty ();
+
   return face->reference_table (tag);
 }
 
@@ -531,6 +534,7 @@
  */
 
 
+#ifndef HB_NO_FACE_COLLECT_UNICODES
 /**
  * hb_face_collect_unicodes:
  * @face: font face.
@@ -544,7 +548,6 @@
 {
   face->table.cmap->collect_unicodes (out);
 }
-
 /**
  * hb_face_collect_variation_selectors:
  * @face: font face.
@@ -560,7 +563,6 @@
 {
   face->table.cmap->collect_variation_selectors (out);
 }
-
 /**
  * hb_face_collect_variation_unicodes:
  * @face: font face.
@@ -577,7 +579,7 @@
 {
   face->table.cmap->collect_variation_unicodes (variation_selector, out);
 }
-
+#endif
 
 
 /*
@@ -599,7 +601,7 @@
     hb_blob_t *blob;
   };
 
-  hb_vector_t<table_entry_t, 32> tables;
+  hb_vector_t<table_entry_t> tables;
 };
 
 static hb_face_builder_data_t *
@@ -619,7 +621,7 @@
 {
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
 
-  for (unsigned int i = 0; i < data->tables.len; i++)
+  for (unsigned int i = 0; i < data->tables.length; i++)
     hb_blob_destroy (data->tables[i].blob);
 
   data->tables.fini ();
@@ -631,7 +633,7 @@
 _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
 {
 
-  unsigned int table_count = data->tables.len;
+  unsigned int table_count = data->tables.length;
   unsigned int face_length = table_count * 16 + 12;
 
   for (unsigned int i = 0; i < table_count; i++)
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 09f0290..c5b7c2c 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -26,6 +26,7 @@
 
 #include "hb-shaper-impl.hh"
 
+#ifndef HB_NO_FALLBACK_SHAPE
 
 /*
  * shaper face data
@@ -120,3 +121,5 @@
 
   return true;
 }
+
+#endif
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 0f0bcad..e89ad69 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -139,10 +139,10 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (!font->get_nominal_glyph (*first_unicode, first_glyph))
-        return i;
+	return i;
 
-      first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     }
     return count;
   }
@@ -238,8 +238,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_h_advance (*first_glyph);
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -250,7 +250,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_x_distance (*first_advance);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -270,8 +270,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_v_advance (*first_glyph);
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -282,7 +282,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_y_distance (*first_advance);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -355,6 +355,7 @@
   return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 static hb_position_t
 hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
@@ -373,6 +374,7 @@
 {
   return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
 }
+#endif
 
 static hb_bool_t
 hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
@@ -516,9 +518,9 @@
 /**
  * hb_font_funcs_create: (Xconstructor)
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
@@ -538,9 +540,9 @@
 /**
  * hb_font_funcs_get_empty:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
@@ -554,9 +556,9 @@
  * hb_font_funcs_reference: (skip)
  * @ffuncs: font functions.
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -570,7 +572,7 @@
  * hb_font_funcs_destroy: (skip)
  * @ffuncs: font functions.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -590,14 +592,14 @@
 /**
  * hb_font_funcs_set_user_data: (skip)
  * @ffuncs: font functions.
- * @key: 
- * @data: 
- * @destroy: 
- * @replace: 
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -614,11 +616,11 @@
 /**
  * hb_font_funcs_get_user_data: (skip)
  * @ffuncs: font functions.
- * @key: 
+ * @key:
  *
- * 
  *
- * Return value: (transfer none): 
+ *
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
@@ -634,7 +636,7 @@
  * hb_font_funcs_make_immutable:
  * @ffuncs: font functions.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -651,9 +653,9 @@
  * hb_font_funcs_is_immutable:
  * @ffuncs: font functions.
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -665,22 +667,22 @@
 
 
 #define HB_FONT_FUNC_IMPLEMENT(name) \
-                                                                         \
+									 \
 void                                                                     \
 hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
-                                 hb_font_get_##name##_func_t  func,      \
-                                 void                        *user_data, \
-                                 hb_destroy_func_t            destroy)   \
+				 hb_font_get_##name##_func_t  func,      \
+				 void                        *user_data, \
+				 hb_destroy_func_t            destroy)   \
 {                                                                        \
   if (hb_object_is_immutable (ffuncs)) {                                 \
     if (destroy)                                                         \
       destroy (user_data);                                               \
     return;                                                              \
   }                                                                      \
-                                                                         \
+									 \
   if (ffuncs->destroy.name)                                              \
     ffuncs->destroy.name (ffuncs->user_data.name);                       \
-                                                                         \
+									 \
   if (func) {                                                            \
     ffuncs->get.f.name = func;                                           \
     ffuncs->user_data.name = user_data;                                  \
@@ -749,13 +751,13 @@
 /**
  * hb_font_get_glyph:
  * @font: a font.
- * @unicode: 
- * @variation_selector: 
- * @glyph: (out): 
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -772,12 +774,12 @@
 /**
  * hb_font_get_nominal_glyph:
  * @font: a font.
- * @unicode: 
- * @glyph: (out): 
+ * @unicode:
+ * @glyph: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 1.2.3
  **/
@@ -790,15 +792,38 @@
 }
 
 /**
+ * hb_font_get_nominal_glyphs:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 2.6.3
+ **/
+unsigned int
+hb_font_get_nominal_glyphs (hb_font_t *font,
+			    unsigned int count,
+			    const hb_codepoint_t *first_unicode,
+			    unsigned int unicode_stride,
+			    hb_codepoint_t *first_glyph,
+			    unsigned int glyph_stride)
+{
+  return font->get_nominal_glyphs (count,
+				   first_unicode, unicode_stride,
+				   first_glyph, glyph_stride);
+}
+
+/**
  * hb_font_get_variation_glyph:
  * @font: a font.
- * @unicode: 
- * @variation_selector: 
- * @glyph: (out): 
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 1.2.3
  **/
@@ -813,11 +838,11 @@
 /**
  * hb_font_get_glyph_h_advance:
  * @font: a font.
- * @glyph: 
+ * @glyph:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -831,11 +856,11 @@
 /**
  * hb_font_get_glyph_v_advance:
  * @font: a font.
- * @glyph: 
+ * @glyph:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -850,7 +875,7 @@
  * hb_font_get_glyph_h_advances:
  * @font: a font.
  *
- * 
+ *
  *
  * Since: 1.8.6
  **/
@@ -868,7 +893,7 @@
  * hb_font_get_glyph_v_advances:
  * @font: a font.
  *
- * 
+ *
  *
  * Since: 1.8.6
  **/
@@ -886,13 +911,13 @@
 /**
  * hb_font_get_glyph_h_origin:
  * @font: a font.
- * @glyph: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -907,13 +932,13 @@
 /**
  * hb_font_get_glyph_v_origin:
  * @font: a font.
- * @glyph: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -928,15 +953,14 @@
 /**
  * hb_font_get_glyph_h_kerning:
  * @font: a font.
- * @left_glyph: 
- * @right_glyph: 
+ * @left_glyph:
+ * @right_glyph:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
- * Deprecated: 2.0.0
  **/
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
@@ -945,15 +969,16 @@
   return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_font_get_glyph_v_kerning:
  * @font: a font.
- * @top_glyph: 
- * @bottom_glyph: 
+ * @top_glyph:
+ * @bottom_glyph:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  * Deprecated: 2.0.0
@@ -964,16 +989,17 @@
 {
   return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
 }
+#endif
 
 /**
  * hb_font_get_glyph_extents:
  * @font: a font.
- * @glyph: 
- * @extents: (out): 
+ * @glyph:
+ * @extents: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -988,14 +1014,14 @@
 /**
  * hb_font_get_glyph_contour_point:
  * @font: a font.
- * @glyph: 
- * @point_index: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @point_index:
+ * @x: (out):
+ * @y: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1010,13 +1036,13 @@
 /**
  * hb_font_get_glyph_name:
  * @font: a font.
- * @glyph: 
- * @name: (array length=size): 
- * @size: 
+ * @glyph:
+ * @name: (array length=size):
+ * @size:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1031,13 +1057,13 @@
 /**
  * hb_font_get_glyph_from_name:
  * @font: a font.
- * @name: (array length=len): 
- * @len: 
- * @glyph: (out): 
+ * @name: (array length=len):
+ * @len:
+ * @glyph: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1072,12 +1098,12 @@
 /**
  * hb_font_get_glyph_advance_for_direction:
  * @font: a font.
- * @glyph: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1092,9 +1118,9 @@
 /**
  * hb_font_get_glyph_advances_for_direction:
  * @font: a font.
- * @direction: 
+ * @direction:
  *
- * 
+ *
  *
  * Since: 1.8.6
  **/
@@ -1113,12 +1139,12 @@
 /**
  * hb_font_get_glyph_origin_for_direction:
  * @font: a font.
- * @glyph: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1134,12 +1160,12 @@
 /**
  * hb_font_add_glyph_origin_for_direction:
  * @font: a font.
- * @glyph: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1155,12 +1181,12 @@
 /**
  * hb_font_subtract_glyph_origin_for_direction:
  * @font: a font.
- * @glyph: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1176,16 +1202,15 @@
 /**
  * hb_font_get_glyph_kerning_for_direction:
  * @font: a font.
- * @first_glyph: 
- * @second_glyph: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @first_glyph:
+ * @second_glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
- * Deprecated: 2.0.0
  **/
 void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@@ -1199,13 +1224,13 @@
 /**
  * hb_font_get_glyph_extents_for_origin:
  * @font: a font.
- * @glyph: 
- * @direction: 
- * @extents: (out): 
+ * @glyph:
+ * @direction:
+ * @extents: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1221,15 +1246,15 @@
 /**
  * hb_font_get_glyph_contour_point_for_origin:
  * @font: a font.
- * @glyph: 
- * @point_index: 
- * @direction: 
- * @x: (out): 
- * @y: (out): 
+ * @glyph:
+ * @point_index:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1246,11 +1271,11 @@
 /**
  * hb_font_glyph_to_string:
  * @font: a font.
- * @glyph: 
- * @s: (array length=size): 
- * @size: 
+ * @glyph:
+ * @s: (array length=size):
+ * @size:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1266,13 +1291,13 @@
 /**
  * hb_font_glyph_from_string:
  * @font: a font.
- * @s: (array length=len) (element-type uint8_t): 
- * @len: 
- * @glyph: (out): 
+ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ * @glyph: (out):
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1298,6 +1323,8 @@
 
   1000, /* x_scale */
   1000, /* y_scale */
+  1<<16, /* x_mult */
+  1<<16, /* y_mult */
 
   0, /* x_ppem */
   0, /* y_ppem */
@@ -1328,6 +1355,7 @@
   font->klass = hb_font_funcs_get_empty ();
   font->data.init0 (font);
   font->x_scale = font->y_scale = hb_face_get_upem (face);
+  font->x_mult = font->y_mult = 1 << 16;
 
   return font;
 }
@@ -1336,9 +1364,9 @@
  * hb_font_create: (Xconstructor)
  * @face: a face.
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
@@ -1347,8 +1375,10 @@
 {
   hb_font_t *font = _hb_font_create (face);
 
+#ifndef HB_NO_OT_FONT
   /* Install our in-house, very lightweight, funcs. */
   hb_ot_font_set_funcs (font);
+#endif
 
   return font;
 }
@@ -1357,9 +1387,9 @@
  * hb_font_create_sub_font:
  * @parent: parent font.
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
@@ -1378,14 +1408,13 @@
 
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
+  font->mults_changed ();
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
 
   font->num_coords = parent->num_coords;
-  if (!font->num_coords)
-    font->coords = nullptr;
-  else
+  if (font->num_coords)
   {
     unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
     font->coords = (int *) malloc (size);
@@ -1401,7 +1430,7 @@
 /**
  * hb_font_get_empty:
  *
- * 
+ *
  *
  * Return value: (transfer full)
  *
@@ -1417,9 +1446,9 @@
  * hb_font_reference: (skip)
  * @font: a font.
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
@@ -1433,7 +1462,7 @@
  * hb_font_destroy: (skip)
  * @font: a font.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1459,14 +1488,14 @@
 /**
  * hb_font_set_user_data: (skip)
  * @font: a font.
- * @key: 
- * @data: 
- * @destroy: 
- * @replace: 
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1483,11 +1512,11 @@
 /**
  * hb_font_get_user_data: (skip)
  * @font: a font.
- * @key: 
+ * @key:
  *
- * 
  *
- * Return value: (transfer none): 
+ *
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
@@ -1502,7 +1531,7 @@
  * hb_font_make_immutable:
  * @font: a font.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1522,9 +1551,9 @@
  * hb_font_is_immutable:
  * @font: a font.
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -1564,9 +1593,9 @@
  * hb_font_get_parent:
  * @font: a font.
  *
- * 
  *
- * Return value: (transfer none): 
+ *
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
@@ -1597,7 +1626,9 @@
 
   hb_face_t *old = font->face;
 
+  hb_face_make_immutable (face);
   font->face = hb_face_reference (face);
+  font->mults_changed ();
 
   hb_face_destroy (old);
 }
@@ -1606,9 +1637,9 @@
  * hb_font_get_face:
  * @font: a font.
  *
- * 
  *
- * Return value: (transfer none): 
+ *
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
@@ -1623,10 +1654,10 @@
  * hb_font_set_funcs:
  * @font: a font.
  * @klass: (closure font_data) (destroy destroy) (scope notified):
- * @font_data: 
- * @destroy: 
+ * @font_data:
+ * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1660,16 +1691,16 @@
  * hb_font_set_funcs_data:
  * @font: a font.
  * @font_data: (destroy destroy) (scope notified):
- * @destroy: 
+ * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_font_set_funcs_data (hb_font_t         *font,
-		        void              *font_data,
-		        hb_destroy_func_t  destroy)
+			void              *font_data,
+			hb_destroy_func_t  destroy)
 {
   /* Destroy user_data? */
   if (hb_object_is_immutable (font))
@@ -1690,10 +1721,10 @@
 /**
  * hb_font_set_scale:
  * @font: a font.
- * @x_scale: 
- * @y_scale: 
+ * @x_scale:
+ * @y_scale:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1707,15 +1738,16 @@
 
   font->x_scale = x_scale;
   font->y_scale = y_scale;
+  font->mults_changed ();
 }
 
 /**
  * hb_font_get_scale:
  * @font: a font.
- * @x_scale: (out): 
- * @y_scale: (out): 
+ * @x_scale: (out):
+ * @y_scale: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1731,10 +1763,10 @@
 /**
  * hb_font_set_ppem:
  * @font: a font.
- * @x_ppem: 
- * @y_ppem: 
+ * @x_ppem:
+ * @y_ppem:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1753,10 +1785,10 @@
 /**
  * hb_font_get_ppem:
  * @font: a font.
- * @x_ppem: (out): 
- * @y_ppem: (out): 
+ * @x_ppem: (out):
+ * @y_ppem: (out):
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -1805,6 +1837,7 @@
   return font->ptem;
 }
 
+#ifndef HB_NO_VAR
 /*
  * Variations
  */
@@ -1873,6 +1906,33 @@
 }
 
 /**
+ * hb_font_set_var_named_instance:
+ * @font: a font.
+ * @instance_index: named instance index.
+ *
+ * Sets design coords of a font from a named instance index.
+ *
+ * Since: 2.6.0
+ */
+void
+hb_font_set_var_named_instance (hb_font_t *font,
+				unsigned instance_index)
+{
+  if (hb_object_is_immutable (font))
+    return;
+
+  unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
+
+  float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  if (unlikely (coords_length && !coords))
+    return;
+
+  hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
+  hb_font_set_var_coords_design (font, coords, coords_length);
+  free (coords);
+}
+
+/**
  * hb_font_set_var_coords_normalized:
  *
  * Since: 1.4.2
@@ -1912,8 +1972,9 @@
 
   return font->coords;
 }
+#endif
 
-
+#ifndef HB_DISABLE_DEPRECATED
 /*
  * Deprecated get_glyph_func():
  */
@@ -2036,3 +2097,4 @@
 					  trampoline,
 					  trampoline_destroy);
 }
+#endif
diff --git a/src/hb-font.h b/src/hb-font.h
index e2086d8..01ff201 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -157,6 +157,11 @@
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
 
+typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
+							   hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+							   void *user_data);
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
+
 
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
 						       hb_codepoint_t glyph,
@@ -219,7 +224,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 1.2.3
  **/
@@ -251,7 +256,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 1.2.3
  **/
@@ -267,7 +272,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -283,7 +288,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -299,7 +304,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 1.8.6
  **/
@@ -315,7 +320,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 1.8.6
  **/
@@ -331,7 +336,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -347,7 +352,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -357,13 +362,29 @@
 				       void *user_data, hb_destroy_func_t destroy);
 
 /**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
+					hb_font_get_glyph_h_kerning_func_t func,
+					void *user_data, hb_destroy_func_t destroy);
+
+/**
  * hb_font_funcs_set_glyph_extents_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -379,7 +400,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -395,7 +416,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -411,7 +432,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -438,6 +459,14 @@
 			     hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 			     hb_codepoint_t *glyph);
 
+HB_EXTERN unsigned int
+hb_font_get_nominal_glyphs (hb_font_t *font,
+			    unsigned int count,
+			    const hb_codepoint_t *first_unicode,
+			    unsigned int unicode_stride,
+			    hb_codepoint_t *first_glyph,
+			    unsigned int glyph_stride);
+
 HB_EXTERN hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
 			     hb_codepoint_t glyph);
@@ -469,6 +498,10 @@
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y);
 
+HB_EXTERN hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+
 HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
 			   hb_codepoint_t glyph,
@@ -531,6 +564,12 @@
 					     hb_direction_t direction,
 					     hb_position_t *x, hb_position_t *y);
 
+HB_EXTERN void
+hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
+					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+					 hb_direction_t direction,
+					 hb_position_t *x, hb_position_t *y);
+
 HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
 				      hb_codepoint_t glyph,
@@ -618,8 +657,8 @@
 /* Be *very* careful with this function! */
 HB_EXTERN void
 hb_font_set_funcs_data (hb_font_t         *font,
-		        void              *font_data,
-		        hb_destroy_func_t  destroy);
+			void              *font_data,
+			hb_destroy_func_t  destroy);
 
 
 HB_EXTERN void
@@ -674,6 +713,10 @@
 hb_font_get_var_coords_normalized (hb_font_t *font,
 				   unsigned int *length);
 
+HB_EXTERN void
+hb_font_set_var_named_instance (hb_font_t *font,
+				unsigned instance_index);
+
 HB_END_DECLS
 
 #endif /* HB_FONT_H */
diff --git a/src/hb-font.hh b/src/hb-font.hh
index aaa0fd9..b1e8e64 100644
--- a/src/hb-font.hh
+++ b/src/hb-font.hh
@@ -52,7 +52,7 @@
   HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
+  HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
   HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
   HB_FONT_FUNC_IMPLEMENT (glyph_name) \
@@ -107,8 +107,10 @@
   hb_font_t *parent;
   hb_face_t *face;
 
-  int x_scale;
-  int y_scale;
+  int32_t x_scale;
+  int32_t y_scale;
+  int64_t x_mult;
+  int64_t y_mult;
 
   unsigned int x_ppem;
   unsigned int y_ppem;
@@ -127,16 +129,16 @@
 
 
   /* Convert from font-space to user-space */
-  int dir_scale (hb_direction_t direction)
-  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
-  hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
-  hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
-  hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
-  hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
+  int64_t dir_mult (hb_direction_t direction)
+  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
+  hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
+  hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
+  hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
+  hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
   float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
   float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
-  { return em_scale (v, dir_scale (direction)); }
+  { return em_mult (v, dir_mult (direction)); }
 
   /* Convert from parent-font user-space to our user-space */
   hb_position_t parent_scale_x_distance (hb_position_t v)
@@ -214,7 +216,7 @@
   }
 
   hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
-				      hb_codepoint_t *glyph)
+			       hb_codepoint_t *glyph)
   {
     *glyph = 0;
     return klass->get.f.nominal_glyph (this, user_data,
@@ -284,7 +286,7 @@
   }
 
   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
-				       hb_position_t *x, hb_position_t *y)
+			        hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
     return klass->get.f.glyph_h_origin (this, user_data,
@@ -304,21 +306,29 @@
   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
 				     hb_codepoint_t right_glyph)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    return 0;
+#else
     return klass->get.f.glyph_h_kerning (this, user_data,
 					 left_glyph, right_glyph,
 					 klass->user_data.glyph_h_kerning);
+#endif
   }
 
   hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
 				     hb_codepoint_t bottom_glyph)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    return 0;
+#else
     return klass->get.f.glyph_v_kerning (this, user_data,
 					 top_glyph, bottom_glyph,
 					 klass->user_data.glyph_v_kerning);
+#endif
   }
 
   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
-				      hb_glyph_extents_t *extents)
+			       hb_glyph_extents_t *extents)
   {
     memset (extents, 0, sizeof (*extents));
     return klass->get.f.glyph_extents (this, user_data,
@@ -489,7 +499,7 @@
   }
 
   void subtract_glyph_h_origin (hb_codepoint_t glyph,
-			        hb_position_t *x, hb_position_t *y)
+				hb_position_t *x, hb_position_t *y)
   {
     hb_position_t origin_x, origin_y;
 
@@ -599,15 +609,19 @@
     return false;
   }
 
-  hb_position_t em_scale (int16_t v, int scale)
+  void mults_changed ()
   {
-    int upem = face->get_upem ();
-    int64_t scaled = v * (int64_t) scale;
-    scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
-    return (hb_position_t) (scaled / upem);
+    signed upem = face->get_upem ();
+    x_mult = ((int64_t) x_scale << 16) / upem;
+    y_mult = ((int64_t) y_scale << 16) / upem;
+  }
+
+  hb_position_t em_mult (int16_t v, int64_t mult)
+  {
+    return (hb_position_t) ((v * mult) >> 16);
   }
   hb_position_t em_scalef (float v, int scale)
-  { return (hb_position_t) round (v * scale / face->get_upem ()); }
+  { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
   float em_fscale (int16_t v, int scale)
   { return (float) v * scale / face->get_upem (); }
 };
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 5f6e380..e526bf4 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -29,6 +29,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_FREETYPE
+
 #include "hb-ft.h"
 
 #include "hb-font.hh"
@@ -96,7 +98,7 @@
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_x_scale.set (0);
+  ft_font->cached_x_scale.set_relaxed (0);
   ft_font->advance_cache.init ();
 
   return ft_font;
@@ -228,8 +230,8 @@
        done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
        done++)
   {
-    first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
   }
   /* We don't need to do ft_font->symbol dance here, since HB calls the singular
    * nominal_glyph() for what we don't handle here. */
@@ -292,8 +294,8 @@
     }
 
     *first_advance = (v * mult + (1<<9)) >> 10;
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -346,6 +348,25 @@
   return true;
 }
 
+#ifndef HB_NO_OT_SHAPE_FALLBACK
+static hb_position_t
+hb_ft_get_glyph_h_kerning (hb_font_t *font,
+			   void *font_data,
+			   hb_codepoint_t left_glyph,
+			   hb_codepoint_t right_glyph,
+			   void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Vector kerningv;
+
+  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
+    return 0;
+
+  return kerningv.x;
+}
+#endif
+
 static hb_bool_t
 hb_ft_get_glyph_extents (hb_font_t *font,
 			 void *font_data,
@@ -439,7 +460,7 @@
   else {
     /* Make a nul-terminated version. */
     char buf[128];
-    len = MIN (len, (int) sizeof (buf) - 1);
+    len = hb_min (len, (int) sizeof (buf) - 1);
     strncpy (buf, name, len);
     buf[len] = '\0';
     *glyph = FT_Get_Name_Index (ft_face, buf);
@@ -450,7 +471,7 @@
     /* Check whether the given name was actually the name of glyph 0. */
     char buf[128];
     if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
-        len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+	len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
       return true;
   }
 
@@ -497,6 +518,10 @@
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
+#ifndef HB_NO_OT_SHAPE_FALLBACK
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
+#endif
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@@ -539,7 +564,7 @@
 
 
 static hb_blob_t *
-reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   FT_Face ft_face = (FT_Face) user_data;
   FT_Byte *buffer;
@@ -594,7 +619,7 @@
     face = hb_face_create (blob, ft_face->face_index);
     hb_blob_destroy (blob);
   } else {
-    face = hb_face_create_for_tables (reference_table, ft_face, destroy);
+    face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
   }
 
   hb_face_set_index (face, ft_face->face_index);
@@ -748,7 +773,7 @@
 static void free_static_ft_library ();
 #endif
 
-static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
+static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
 							     hb_ft_library_lazy_loader_t>
 {
   static FT_Library create ()
@@ -815,8 +840,8 @@
     return;
   }
 
-  if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
-    FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
+  if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
+    FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
 
   FT_Set_Char_Size (ft_face,
 		    abs (font->x_scale), abs (font->y_scale),
@@ -841,7 +866,7 @@
     if (ft_coords)
     {
       for (unsigned int i = 0; i < num_coords; i++)
-	ft_coords[i] = coords[i] << 2;
+	ft_coords[i] = coords[i] * 4;
       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
       free (ft_coords);
     }
@@ -854,3 +879,6 @@
   _hb_ft_font_set_funcs (font, ft_face, true);
   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 }
+
+
+#endif
diff --git a/src/hb-gdi.cc b/src/hb-gdi.cc
new file mode 100644
index 0000000..f6306ef
--- /dev/null
+++ b/src/hb-gdi.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_GDI
+
+#include "hb-gdi.h"
+
+static hb_blob_t *
+_hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  char *buffer = nullptr;
+  DWORD length = 0;
+
+  HDC hdc = GetDC (nullptr);
+  if (unlikely (!SelectObject (hdc, (HFONT) user_data))) goto fail;
+
+  length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
+  if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
+
+  buffer = (char *) malloc (length);
+  if (unlikely (!buffer)) goto fail_with_releasedc;
+  length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
+  if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
+  ReleaseDC (nullptr, hdc);
+
+  return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
+
+fail_with_releasedc_and_free:
+  free (buffer);
+fail_with_releasedc:
+  ReleaseDC (nullptr, hdc);
+fail:
+  return hb_blob_get_empty ();
+}
+
+/**
+ * hb_gdi_face_create:
+ * @hfont: a HFONT object.
+ *
+ * Return value: #hb_face_t object corresponding to the given input
+ *
+ * Since: 2.6.0
+ **/
+hb_face_t *
+hb_gdi_face_create (HFONT hfont)
+{
+  return hb_face_create_for_tables (_hb_gdi_reference_table, (void *) hfont, nullptr);
+}
+
+#endif
diff --git a/src/hb-subset-glyf.hh b/src/hb-gdi.h
similarity index 71%
copy from src/hb-subset-glyf.hh
copy to src/hb-gdi.h
index 99cf8f0..68cc439 100644
--- a/src/hb-subset-glyf.hh
+++ b/src/hb-gdi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,21 +20,20 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger
  */
 
-#ifndef HB_SUBSET_GLYF_HH
-#define HB_SUBSET_GLYF_HH
+#ifndef HB_GDI_H
+#define HB_GDI_H
 
-#include "hb.hh"
+#include "hb.h"
 
-#include "hb-subset.hh"
+#include <windows.h>
 
-HB_INTERNAL bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-			 bool             *use_short_loca, /* OUT */
-			 hb_blob_t       **glyf_prime      /* OUT */,
-			 hb_blob_t       **loca_prime      /* OUT */);
+HB_BEGIN_DECLS
 
-#endif /* HB_SUBSET_GLYF_HH */
+HB_EXTERN hb_face_t *
+hb_gdi_face_create (HFONT hfont);
+
+HB_END_DECLS
+
+#endif /* HB_GDI_H */
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 5763754..db02b67 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -28,6 +28,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_GLIB
+
 #include "hb-glib.h"
 
 #include "hb-machinery.hh"
@@ -404,3 +406,6 @@
 			 _hb_g_bytes_unref);
 }
 #endif
+
+
+#endif
diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl
index e3a9a6b..17f1ade 100644
--- a/src/hb-gobject-enums.cc.tmpl
+++ b/src/hb-gobject-enums.cc.tmpl
@@ -27,6 +27,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_GOBJECT
+
 /* g++ didn't like older gtype.h gcc-only code path. */
 #include <glib.h>
 #if !GLIB_CHECK_VERSION(2,29,16)
@@ -44,6 +46,11 @@
 /* enumerations from "@filename@" */
 /*** END file-production ***/
 
+/*** BEGIN file-tail ***/
+
+#endif
+/*** END file-tail ***/
+
 /*** BEGIN value-header ***/
 GType
 @enum_name@_get_type ()
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 846240e..7f4922e 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -26,6 +26,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_GOBJECT
+
 
 /**
  * SECTION:hb-gobject
@@ -64,7 +66,7 @@
 }
 
 #define HB_DEFINE_OBJECT_TYPE(name) \
-	HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
+	HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy)
 
 #define HB_DEFINE_VALUE_TYPE(name) \
 	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
@@ -75,7 +77,7 @@
 	  return c; \
 	} \
 	static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
-	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy);
+	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
 
 HB_DEFINE_OBJECT_TYPE (buffer)
 HB_DEFINE_OBJECT_TYPE (blob)
@@ -94,3 +96,6 @@
 
 HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
 HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
+
+
+#endif
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index a1c602c..f0f2f8c 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -26,6 +26,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifdef HAVE_GRAPHITE2
+
 #include "hb-shaper-impl.hh"
 
 #include "hb-graphite2.h"
@@ -102,32 +106,6 @@
   return d;
 }
 
-static void hb_graphite2_release_table(const void *data, const void *table_buffer)
-{
-  hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
-  hb_graphite2_tablelist_t *tlist = face_data->tlist;
-
-  hb_graphite2_tablelist_t *prev = nullptr;
-  hb_graphite2_tablelist_t *curr = tlist;
-  while (curr)
-  {
-    if (hb_blob_get_data(curr->blob, nullptr) == table_buffer)
-    {
-      if (prev == nullptr)
-        face_data->tlist.cmpexch(tlist, curr->next);
-      else
-        prev->next = curr->next;
-      hb_blob_destroy(curr->blob);
-      free(curr);
-      break;
-    }
-    prev = curr;
-    curr = curr->next;
-  }
-}
-
-static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table };
-
 hb_graphite2_face_data_t *
 _hb_graphite2_shaper_face_data_create (hb_face_t *face)
 {
@@ -146,7 +124,7 @@
     return nullptr;
 
   data->face = face;
-  data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll);
+  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
     free (data);
@@ -202,6 +180,7 @@
 {
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_graphite2_font_get_gr_font:
  *
@@ -213,6 +192,7 @@
 {
   return nullptr;
 }
+#endif
 
 
 /*
@@ -225,7 +205,7 @@
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
-  float advance;
+  unsigned int advance;
 };
 
 hb_bool_t
@@ -253,7 +233,7 @@
   gr_segment *seg = nullptr;
   const gr_slot *is;
   unsigned int ci = 0, ic = 0;
-  float curradvx = 0., curradvy = 0.;
+  unsigned int curradvx = 0, curradvy = 0;
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
@@ -308,12 +288,12 @@
 
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
-  { \
+  do { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     assert (_consumed <= scratch_size); \
     scratch += _consumed; \
     scratch_size -= _consumed; \
-  }
+  } while (0)
 
   ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
   ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
@@ -324,11 +304,15 @@
 
   hb_codepoint_t *pg = gids;
   clusters[0].cluster = buffer->info[0].cluster;
-  float curradv = 0.;
+  unsigned int upem = hb_face_get_upem (face);
+  float xscale = (float) font->x_scale / upem;
+  float yscale = (float) font->y_scale / upem;
+  yscale *= yscale / xscale;
+  unsigned int curradv = 0;
   if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
-    curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
-    clusters[0].advance = gr_seg_advance_X(seg) - curradv;
+    curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
+    clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
   }
   else
     clusters[0].advance = 0;
@@ -355,14 +339,17 @@
       c->base_glyph = ic;
       c->num_glyphs = 0;
       if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
-        c->advance = curradv - gr_slot_origin_X(is);
+      {
+	c->advance = curradv - gr_slot_origin_X(is) * xscale;
+	curradv -= c->advance;
+      }
       else
       {
-        c->advance = 0;
-        clusters[ci].advance += gr_slot_origin_X(is) - curradv;
+	c->advance = 0;
+	clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
+	curradv += clusters[ci].advance;
       }
       ci++;
-      curradv = gr_slot_origin_X(is);
     }
     clusters[ci].num_glyphs++;
 
@@ -373,7 +360,7 @@
   if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
     clusters[ci].advance += curradv;
   else
-    clusters[ci].advance += gr_seg_advance_X(seg) - curradv;
+    clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
   ci++;
 
   for (unsigned int i = 0; i < ci; ++i)
@@ -388,10 +375,6 @@
   }
   buffer->len = glyph_count;
 
-  unsigned int upem = hb_face_get_upem (face);
-  float xscale = (float) font->x_scale / upem;
-  float yscale = (float) font->y_scale / upem;
-  yscale *= yscale / xscale;
   /* Positioning. */
   unsigned int currclus = (unsigned int) -1;
   const hb_glyph_info_t *info = buffer->info;
@@ -404,7 +387,7 @@
       pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
       if (info->cluster != currclus) {
-	pPos->x_advance = info->var1.i32 * xscale;
+	pPos->x_advance = info->var1.i32;
 	curradvx += pPos->x_advance;
 	currclus = info->cluster;
       } else
@@ -421,7 +404,7 @@
     {
       if (info->cluster != currclus)
       {
-	pPos->x_advance = info->var1.i32 * xscale;
+	pPos->x_advance = info->var1.i32;
 	curradvx -= pPos->x_advance;
 	currclus = info->cluster;
       } else
@@ -429,7 +412,7 @@
 
       pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy -= pPos->y_advance;
-      pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
+      pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1.i32 - curradvx + pPos->x_advance;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
     }
     hb_buffer_reverse_clusters (buffer);
@@ -442,3 +425,6 @@
 
   return true;
 }
+
+
+#endif
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index c26c91d..985ff02 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -29,6 +29,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_ICU
+
 #include "hb-icu.h"
 
 #include "hb-machinery.hh"
@@ -39,6 +41,12 @@
 #include <unicode/utf16.h>
 #include <unicode/uversion.h>
 
+/* ICU extra semicolon, fixed since 65, https://github.com/unicode-org/icu/commit/480bec3 */
+#if U_ICU_VERSION_MAJOR_NUM < 65 && (defined(__GNUC__) || defined(__clang__))
+#define HB_ICU_EXTRA_SEMI_IGNORED
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra-semi-stmt"
+#endif
 
 /**
  * SECTION:hb-icu
@@ -49,7 +57,6 @@
  * Functions for using HarfBuzz with the ICU library to provide Unicode data.
  **/
 
-
 hb_script_t
 hb_icu_script_to_script (UScriptCode script)
 {
@@ -225,7 +232,7 @@
       *b = 0;
       return *a != ab;
     } else if (len == 2) {
-      len =0;
+      len = 0;
       U16_NEXT_UNSAFE (decomposed, len, *a);
       U16_NEXT_UNSAFE (decomposed, len, *b);
     }
@@ -236,7 +243,7 @@
   /* We don't ifdef-out the fallback code such that compiler always
    * sees it and makes sure it's compilable. */
 
-  UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
+  UChar utf16[2], normalized[2 * 19/*HB_UNICODE_MAX_DECOMPOSITION_LEN*/ + 1];
   unsigned int len;
   hb_bool_t ret, err;
   UErrorCode icu_err;
@@ -262,7 +269,7 @@
     *b = 0;
     ret = *a != ab;
   } else if (len == 2) {
-    len =0;
+    len = 0;
     U16_NEXT_UNSAFE (normalized, len, *a);
     U16_NEXT_UNSAFE (normalized, len, *b);
 
@@ -348,3 +355,9 @@
 {
   return static_icu_funcs.get_unconst ();
 }
+
+#ifdef HB_ICU_EXTRA_SEMI_IGNORED
+#pragma GCC diagnostic pop
+#endif
+
+#endif
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
new file mode 100644
index 0000000..981c5c2
--- /dev/null
+++ b/src/hb-iter.hh
@@ -0,0 +1,939 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_ITER_HH
+#define HB_ITER_HH
+
+#include "hb.hh"
+#include "hb-algs.hh"
+#include "hb-meta.hh"
+
+
+/* Unified iterator object.
+ *
+ * The goal of this template is to make the same iterator interface
+ * available to all types, and make it very easy and compact to use.
+ * hb_iter_tator objects are small, light-weight, objects that can be
+ * copied by value.  If the collection / object being iterated on
+ * is writable, then the iterator returns lvalues, otherwise it
+ * returns rvalues.
+ *
+ * TODO Document more.
+ *
+ * If iterator implementation implements operator!=, then can be
+ * used in range-based for loop.  That comes free if the iterator
+ * is random-access.  Otherwise, the range-based for loop incurs
+ * one traversal to find end(), which can be avoided if written
+ * as a while-style for loop, or if iterator implements a faster
+ * __end__() method.
+ * TODO When opting in for C++17, address this by changing return
+ * type of .end()?
+ */
+
+/*
+ * Base classes for iterators.
+ */
+
+/* Base class for all iterators. */
+template <typename iter_t, typename Item = typename iter_t::__item_t__>
+struct hb_iter_t
+{
+  typedef Item item_t;
+  constexpr unsigned get_item_size () const { return hb_static_size (Item); }
+  static constexpr bool is_iterator = true;
+  static constexpr bool is_random_access_iterator = false;
+  static constexpr bool is_sorted_iterator = false;
+
+  private:
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
+	iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
+  public:
+
+  /* TODO:
+   * Port operators below to use hb_enable_if to sniff which method implements
+   * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
+
+  /* Operators. */
+  iter_t iter () const { return *thiz(); }
+  iter_t operator + () const { return *thiz(); }
+  iter_t begin () const { return *thiz(); }
+  iter_t end () const { return thiz()->__end__ (); }
+  explicit operator bool () const { return thiz()->__more__ (); }
+  unsigned len () const { return thiz()->__len__ (); }
+  /* The following can only be enabled if item_t is reference type.  Otherwise
+   * it will be returning pointer to temporary rvalue.
+   * TODO Use a wrapper return type to fix for non-reference type. */
+  template <typename T = item_t,
+	    hb_enable_if (hb_is_reference (T))>
+  hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
+  item_t operator * () const { return thiz()->__item__ (); }
+  item_t operator * () { return thiz()->__item__ (); }
+  item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
+  item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
+  iter_t& operator += (unsigned count) &  { thiz()->__forward__ (count); return *thiz(); }
+  iter_t  operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
+  iter_t& operator ++ () &  { thiz()->__next__ (); return *thiz(); }
+  iter_t  operator ++ () && { thiz()->__next__ (); return *thiz(); }
+  iter_t& operator -= (unsigned count) &  { thiz()->__rewind__ (count); return *thiz(); }
+  iter_t  operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
+  iter_t& operator -- () &  { thiz()->__prev__ (); return *thiz(); }
+  iter_t  operator -- () && { thiz()->__prev__ (); return *thiz(); }
+  iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
+  friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
+  iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
+  iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
+  iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
+  template <typename T>
+  iter_t& operator >> (T &v) &  { v = **thiz(); ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t  operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t& operator << (const T v) &  { **thiz() = v; ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t  operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
+
+  protected:
+  hb_iter_t () = default;
+  hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
+  hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
+  hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
+  hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
+};
+
+#define HB_ITER_USING(Name) \
+  using item_t = typename Name::item_t; \
+  using Name::begin; \
+  using Name::end; \
+  using Name::get_item_size; \
+  using Name::is_iterator; \
+  using Name::iter; \
+  using Name::operator bool; \
+  using Name::len; \
+  using Name::operator ->; \
+  using Name::operator *; \
+  using Name::operator []; \
+  using Name::operator +=; \
+  using Name::operator ++; \
+  using Name::operator -=; \
+  using Name::operator --; \
+  using Name::operator +; \
+  using Name::operator -; \
+  using Name::operator >>; \
+  using Name::operator <<; \
+  static_assert (true, "")
+
+/* Returns iterator / item type of a type. */
+template <typename Iterable>
+using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
+template <typename Iterable>
+using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
+
+
+template <typename> struct hb_array_t;
+template <typename> struct hb_sorted_array_t;
+
+struct
+{
+  template <typename T> hb_iter_type<T>
+  operator () (T&& c) const
+  { return hb_deref (hb_forward<T> (c)).iter (); }
+
+  /* Specialization for C arrays. */
+
+  template <typename Type> inline hb_array_t<Type>
+  operator () (Type *array, unsigned int length) const
+  { return hb_array_t<Type> (array, length); }
+
+  template <typename Type, unsigned int length> hb_array_t<Type>
+  operator () (Type (&array)[length]) const
+  { return hb_array_t<Type> (array, length); }
+
+}
+HB_FUNCOBJ (hb_iter);
+struct
+{
+  template <typename T> unsigned
+  operator () (T&& c) const
+  { return c.len (); }
+
+}
+HB_FUNCOBJ (hb_len);
+
+/* Mixin to fill in what the subclass doesn't provide. */
+template <typename iter_t, typename item_t = typename iter_t::__item_t__>
+struct hb_iter_fallback_mixin_t
+{
+  private:
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
+	iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
+  public:
+
+  /* Access: Implement __item__(), or __item_at__() if random-access. */
+  item_t __item__ () const { return (*thiz())[0]; }
+  item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
+
+  /* Termination: Implement __more__(), or __len__() if random-access. */
+  bool __more__ () const { return bool (thiz()->len ()); }
+  unsigned __len__ () const
+  { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
+
+  /* Advancing: Implement __next__(), or __forward__() if random-access. */
+  void __next__ () { *thiz() += 1; }
+  void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
+
+  /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
+  void __prev__ () { *thiz() -= 1; }
+  void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
+
+  /* Range-based for: Implement __end__() if can be done faster,
+   * and operator!=. */
+  iter_t __end__ () const
+  {
+    if (thiz()->is_random_access_iterator)
+      return *thiz() + thiz()->len ();
+    /* Above expression loops twice. Following loops once. */
+    auto it = *thiz();
+    while (it) ++it;
+    return it;
+  }
+
+  protected:
+  hb_iter_fallback_mixin_t () = default;
+  hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
+};
+
+template <typename iter_t, typename item_t = typename iter_t::__item_t__>
+struct hb_iter_with_fallback_t :
+  hb_iter_t<iter_t, item_t>,
+  hb_iter_fallback_mixin_t<iter_t, item_t>
+{
+  protected:
+  hb_iter_with_fallback_t () = default;
+  hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
+  hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
+  hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
+  hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
+};
+
+/*
+ * Meta-programming predicates.
+ */
+
+/* hb_is_iterator() / hb_is_iterator_of() */
+
+template<typename Iter, typename Item>
+struct hb_is_iterator_of
+{
+  template <typename Item2 = Item>
+  static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
+  static hb_false_type impl (hb_priority<0>, const void *);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
+};
+#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
+#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+
+/* hb_is_iterable() */
+
+template <typename T>
+struct hb_is_iterable
+{
+  private:
+
+  template <typename U>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
+
+  template <typename>
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
+};
+#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
+
+/* hb_is_source_of() / hb_is_sink_of() */
+
+template<typename Iter, typename Item>
+struct hb_is_source_of
+{
+  private:
+  template <typename Iter2 = Iter,
+	    hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
+  static hb_true_type impl (hb_priority<2>);
+  template <typename Iter2 = Iter>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize))::value;
+};
+#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
+
+template<typename Iter, typename Item>
+struct hb_is_sink_of
+{
+  private:
+  template <typename Iter2 = Iter,
+	    hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
+  static hb_true_type impl (hb_priority<2>);
+  template <typename Iter2 = Iter>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize))::value;
+};
+#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
+
+/* This is commonly used, so define: */
+#define hb_is_sorted_source_of(Iter, Item) \
+	(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
+
+
+/* Range-based 'for' for iterables. */
+
+template <typename Iterable,
+	  hb_requires (hb_is_iterable (Iterable))>
+static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
+
+template <typename Iterable,
+	  hb_requires (hb_is_iterable (Iterable))>
+static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
+
+/* begin()/end() are NOT looked up non-ADL.  So each namespace must declare them.
+ * Do it for namespace OT. */
+namespace OT {
+
+template <typename Iterable,
+	  hb_requires (hb_is_iterable (Iterable))>
+static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
+
+template <typename Iterable,
+	  hb_requires (hb_is_iterable (Iterable))>
+static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
+
+}
+
+
+/*
+ * Adaptors, combiners, etc.
+ */
+
+template <typename Lhs, typename Rhs,
+	  hb_requires (hb_is_iterator (Lhs))>
+static inline auto
+operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
+
+/* hb_map(), hb_filter(), hb_reduce() */
+
+enum  class hb_function_sortedness_t {
+  NOT_SORTED,
+  RETAINS_SORTING,
+  SORTED,
+};
+
+template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
+	 hb_requires (hb_is_iterator (Iter))>
+struct hb_map_iter_t :
+  hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
+	    decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
+{
+  hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
+
+  typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
+  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator =
+    Sorted == hb_function_sortedness_t::SORTED ? true :
+    Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
+    false;
+  __item_t__ __item__ () const { return hb_get (f.get (), *it); }
+  __item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
+  bool __more__ () const { return bool (it); }
+  unsigned __len__ () const { return it.len (); }
+  void __next__ () { ++it; }
+  void __forward__ (unsigned n) { it += n; }
+  void __prev__ () { --it; }
+  void __rewind__ (unsigned n) { it -= n; }
+  hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
+  bool operator != (const hb_map_iter_t& o) const
+  { return it != o.it; }
+
+  private:
+  Iter it;
+  hb_reference_wrapper<Proj> f;
+};
+
+template <typename Proj, hb_function_sortedness_t Sorted>
+struct hb_map_iter_factory_t
+{
+  hb_map_iter_factory_t (Proj f) : f (f) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  hb_map_iter_t<Iter, Proj, Sorted>
+  operator () (Iter it)
+  { return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
+
+  private:
+  Proj f;
+};
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
+}
+HB_FUNCOBJ (hb_map);
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
+}
+HB_FUNCOBJ (hb_map_retains_sorting);
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
+}
+HB_FUNCOBJ (hb_map_sorted);
+
+template <typename Iter, typename Pred, typename Proj,
+	 hb_requires (hb_is_iterator (Iter))>
+struct hb_filter_iter_t :
+  hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
+			  typename Iter::item_t>
+{
+  hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
+  { while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
+
+  typedef typename Iter::item_t __item_t__;
+  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+  __item_t__ __item__ () const { return *it; }
+  bool __more__ () const { return bool (it); }
+  void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
+  void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
+  hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
+  bool operator != (const hb_filter_iter_t& o) const
+  { return it != o.it; }
+
+  private:
+  Iter it;
+  hb_reference_wrapper<Pred> p;
+  hb_reference_wrapper<Proj> f;
+};
+template <typename Pred, typename Proj>
+struct hb_filter_iter_factory_t
+{
+  hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  hb_filter_iter_t<Iter, Pred, Proj>
+  operator () (Iter it)
+  { return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
+
+  private:
+  Pred p;
+  Proj f;
+};
+struct
+{
+  template <typename Pred = decltype ((hb_identity)),
+	    typename Proj = decltype ((hb_identity))>
+  hb_filter_iter_factory_t<Pred, Proj>
+  operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
+  { return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
+}
+HB_FUNCOBJ (hb_filter);
+
+template <typename Redu, typename InitT>
+struct hb_reduce_t
+{
+  hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter)),
+	    typename AccuT = hb_decay<decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>>
+  AccuT
+  operator () (Iter it)
+  {
+    AccuT value = init_value;
+    for (; it; ++it)
+      value = r (value, *it);
+    return value;
+  }
+
+  private:
+  Redu r;
+  InitT init_value;
+};
+struct
+{
+  template <typename Redu, typename InitT>
+  hb_reduce_t<Redu, InitT>
+  operator () (Redu&& r, InitT init_value) const
+  { return hb_reduce_t<Redu, InitT> (r, init_value); }
+}
+HB_FUNCOBJ (hb_reduce);
+
+
+/* hb_zip() */
+
+template <typename A, typename B>
+struct hb_zip_iter_t :
+  hb_iter_t<hb_zip_iter_t<A, B>,
+	    hb_pair_t<typename A::item_t, typename B::item_t>>
+{
+  hb_zip_iter_t () {}
+  hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
+
+  typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
+  static constexpr bool is_random_access_iterator =
+    A::is_random_access_iterator &&
+    B::is_random_access_iterator;
+  /* Note.  The following categorization is only valid if A is strictly sorted,
+   * ie. does NOT have duplicates.  Previously I tried to categorize sortedness
+   * more granularly, see commits:
+   *
+   *   513762849a683914fc266a17ddf38f133cccf072
+   *   4d3cf2adb669c345cc43832d11689271995e160a
+   *
+   * However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
+   * SortedArrayOf, etc all needed to be updated to add more variants.  At that
+   * point I saw it not worth the effort, and instead we now deem all sorted
+   * collections as essentially strictly-sorted for the purposes of zip.
+   *
+   * The above assumption is not as bad as it sounds.  Our "sorted" comes with
+   * no guarantees.  It's just a contract, put in place to help you remember,
+   * and think about, whether an iterator you receive is expected to be
+   * sorted or not.  As such, it's not perfect by definition, and should not
+   * be treated so.  The inaccuracy here just errs in the direction of being
+   * more permissive, so your code compiles instead of erring on the side of
+   * marking your zipped iterator unsorted in which case your code won't
+   * compile.
+   *
+   * This semantical limitation does NOT affect logic in any other place I
+   * know of as of this writing.
+   */
+  static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
+
+  __item_t__ __item__ () const { return __item_t__ (*a, *b); }
+  __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
+  bool __more__ () const { return bool (a) && bool (b); }
+  unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
+  void __next__ () { ++a; ++b; }
+  void __forward__ (unsigned n) { a += n; b += n; }
+  void __prev__ () { --a; --b; }
+  void __rewind__ (unsigned n) { a -= n; b -= n; }
+  hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
+  /* Note, we should stop if ANY of the iters reaches end.  As such two compare
+   * unequal if both items are unequal, NOT if either is unequal. */
+  bool operator != (const hb_zip_iter_t& o) const
+  { return a != o.a && b != o.b; }
+
+  private:
+  A a;
+  B b;
+};
+struct
+{ HB_PARTIALIZE(2);
+  template <typename A, typename B,
+	    hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
+  hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
+  operator () (A&& a, B&& b) const
+  { return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
+}
+HB_FUNCOBJ (hb_zip);
+
+/* hb_apply() */
+
+template <typename Appl>
+struct hb_apply_t
+{
+  hb_apply_t (Appl a) : a (a) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+      (void) hb_invoke (a, *it);
+  }
+
+  private:
+  Appl a;
+};
+struct
+{
+  template <typename Appl> hb_apply_t<Appl>
+  operator () (Appl&& a) const
+  { return hb_apply_t<Appl> (a); }
+
+  template <typename Appl> hb_apply_t<Appl&>
+  operator () (Appl *a) const
+  { return hb_apply_t<Appl&> (*a); }
+}
+HB_FUNCOBJ (hb_apply);
+
+/* hb_range()/hb_iota()/hb_repeat() */
+
+template <typename T, typename S>
+struct hb_range_iter_t :
+  hb_iter_t<hb_range_iter_t<T, S>, T>
+{
+  hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return hb_ridentity (v); }
+  __item_t__ __item_at__ (unsigned j) const { return v + j * step; }
+  bool __more__ () const { return v != end_; }
+  unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
+  void __next__ () { v += step; }
+  void __forward__ (unsigned n) { v += n * step; }
+  void __prev__ () { v -= step; }
+  void __rewind__ (unsigned n) { v -= n * step; }
+  hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); }
+  bool operator != (const hb_range_iter_t& o) const
+  { return v != o.v; }
+
+  private:
+  static inline T end_for (T start, T end_, S step)
+  {
+    if (!step)
+      return end_;
+    auto res = (end_ - start) % step;
+    if (!res)
+      return end_;
+    end_ += step - res;
+    return end_;
+  }
+
+  private:
+  T v;
+  T end_;
+  S step;
+};
+struct
+{
+  template <typename T = unsigned> hb_range_iter_t<T, unsigned>
+  operator () (T end = (unsigned) -1) const
+  { return hb_range_iter_t<T, unsigned> (0, end, 1u); }
+
+  template <typename T, typename S = unsigned> hb_range_iter_t<T, S>
+  operator () (T start, T end, S step = 1u) const
+  { return hb_range_iter_t<T, S> (start, end, step); }
+}
+HB_FUNCOBJ (hb_range);
+
+template <typename T, typename S>
+struct hb_iota_iter_t :
+  hb_iter_with_fallback_t<hb_iota_iter_t<T, S>, T>
+{
+  hb_iota_iter_t (T start, S step) : v (start), step (step) {}
+
+  private:
+
+  template <typename S2 = S>
+  auto
+  inc (hb_type_identity<S2> s, hb_priority<1>)
+    -> hb_void_t<decltype (hb_invoke (hb_forward<S2> (s), hb_declval<T&> ()))>
+  { v = hb_invoke (hb_forward<S2> (s), v); }
+
+  void
+  inc (S s, hb_priority<0>)
+  { v += s; }
+
+  public:
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return hb_ridentity (v); }
+  bool __more__ () const { return true; }
+  unsigned __len__ () const { return UINT_MAX; }
+  void __next__ () { inc (step, hb_prioritize); }
+  void __prev__ () { v -= step; }
+  hb_iota_iter_t __end__ () const { return *this; }
+  bool operator != (const hb_iota_iter_t& o) const { return true; }
+
+  private:
+  T v;
+  S step;
+};
+struct
+{
+  template <typename T = unsigned, typename S = unsigned> hb_iota_iter_t<T, S>
+  operator () (T start = 0u, S step = 1u) const
+  { return hb_iota_iter_t<T, S> (start, step); }
+}
+HB_FUNCOBJ (hb_iota);
+
+template <typename T>
+struct hb_repeat_iter_t :
+  hb_iter_t<hb_repeat_iter_t<T>, T>
+{
+  hb_repeat_iter_t (T value) : v (value) {}
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return v; }
+  __item_t__ __item_at__ (unsigned j) const { return v; }
+  bool __more__ () const { return true; }
+  unsigned __len__ () const { return UINT_MAX; }
+  void __next__ () {}
+  void __forward__ (unsigned) {}
+  void __prev__ () {}
+  void __rewind__ (unsigned) {}
+  hb_repeat_iter_t __end__ () const { return *this; }
+  bool operator != (const hb_repeat_iter_t& o) const { return true; }
+
+  private:
+  T v;
+};
+struct
+{
+  template <typename T> hb_repeat_iter_t<T>
+  operator () (T value) const
+  { return hb_repeat_iter_t<T> (value); }
+}
+HB_FUNCOBJ (hb_repeat);
+
+/* hb_enumerate()/hb_take() */
+
+struct
+{
+  template <typename Iterable,
+	    typename Index = unsigned,
+	    hb_requires (hb_is_iterable (Iterable))>
+  auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
+  ( hb_zip (hb_iota (start), it) )
+}
+HB_FUNCOBJ (hb_enumerate);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename Iterable,
+	    hb_requires (hb_is_iterable (Iterable))>
+  auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
+  ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+
+  /* Specialization arrays. */
+
+  template <typename Type> inline hb_array_t<Type>
+  operator () (hb_array_t<Type> array, unsigned count) const
+  { return array.sub_array (0, count); }
+
+  template <typename Type> inline hb_sorted_array_t<Type>
+  operator () (hb_sorted_array_t<Type> array, unsigned count) const
+  { return array.sub_array (0, count); }
+}
+HB_FUNCOBJ (hb_take);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN
+  (
+    + hb_iota (it, hb_add (count))
+    | hb_map (hb_take (count))
+    | hb_take ((hb_len (it) + count - 1) / count)
+  )
+}
+HB_FUNCOBJ (hb_chop);
+
+/* hb_sink() */
+
+template <typename Sink>
+struct hb_sink_t
+{
+  hb_sink_t (Sink s) : s (s) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+      s << *it;
+  }
+
+  private:
+  Sink s;
+};
+struct
+{
+  template <typename Sink> hb_sink_t<Sink>
+  operator () (Sink&& s) const
+  { return hb_sink_t<Sink> (s); }
+
+  template <typename Sink> hb_sink_t<Sink&>
+  operator () (Sink *s) const
+  { return hb_sink_t<Sink&> (*s); }
+}
+HB_FUNCOBJ (hb_sink);
+
+/* hb-drain: hb_sink to void / blackhole / /dev/null. */
+
+struct
+{
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it) const
+  {
+    for (; it; ++it)
+      (void) *it;
+  }
+}
+HB_FUNCOBJ (hb_drain);
+
+/* hb_unzip(): unzip and sink to two sinks. */
+
+template <typename Sink1, typename Sink2>
+struct hb_unzip_t
+{
+  hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
+
+  template <typename Iter,
+	    hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+    {
+      const auto &v = *it;
+      s1 << v.first;
+      s2 << v.second;
+    }
+  }
+
+  private:
+  Sink1 s1;
+  Sink2 s2;
+};
+struct
+{
+  template <typename Sink1, typename Sink2> hb_unzip_t<Sink1, Sink2>
+  operator () (Sink1&& s1, Sink2&& s2) const
+  { return hb_unzip_t<Sink1, Sink2> (s1, s2); }
+
+  template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
+  operator () (Sink1 *s1, Sink2 *s2) const
+  { return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
+}
+HB_FUNCOBJ (hb_unzip);
+
+
+/* hb-all, hb-any, hb-none. */
+
+struct
+{
+  template <typename Iterable,
+	    typename Pred = decltype ((hb_identity)),
+	    typename Proj = decltype ((hb_identity)),
+	    hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+		    Pred&& p = hb_identity,
+		    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+	return false;
+    return true;
+  }
+}
+HB_FUNCOBJ (hb_all);
+struct
+{
+  template <typename Iterable,
+	    typename Pred = decltype ((hb_identity)),
+	    typename Proj = decltype ((hb_identity)),
+	    hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+		    Pred&& p = hb_identity,
+		    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+	return true;
+    return false;
+  }
+}
+HB_FUNCOBJ (hb_any);
+struct
+{
+  template <typename Iterable,
+	    typename Pred = decltype ((hb_identity)),
+	    typename Proj = decltype ((hb_identity)),
+	    hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+		    Pred&& p = hb_identity,
+		    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+	return false;
+    return true;
+  }
+}
+HB_FUNCOBJ (hb_none);
+
+/*
+ * Algorithms operating on iterators.
+ */
+
+template <typename C, typename V,
+	  hb_requires (hb_is_iterable (C))>
+inline void
+hb_fill (C& c, const V &v)
+{
+  for (auto i = hb_iter (c); i; i++)
+    *i = v;
+}
+
+template <typename S, typename D>
+inline void
+hb_copy (S&& is, D&& id)
+{
+  hb_iter (is) | hb_sink (id);
+}
+
+
+#endif /* HB_ITER_HH */
diff --git a/src/hb-kern.hh b/src/hb-kern.hh
index fd5bb9e..99d533c 100644
--- a/src/hb-kern.hh
+++ b/src/hb-kern.hh
@@ -82,11 +82,11 @@
 
 
       if (likely (!kern))
-        goto skip;
+	goto skip;
 
       if (horizontal)
       {
-        if (scale)
+	if (scale)
 	  kern = font->em_scale_x (kern);
 	if (crossStream)
 	{
@@ -104,7 +104,7 @@
       }
       else
       {
-        if (scale)
+	if (scale)
 	  kern = font->em_scale_y (kern);
 	if (crossStream)
 	{
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 9d2ae95..15535d7 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -32,8 +32,9 @@
 #include "hb.hh"
 #include "hb-blob.hh"
 
-#include "hb-array.hh"
-#include "hb-vector.hh"
+#include "hb-dispatch.hh"
+#include "hb-sanitize.hh"
+#include "hb-serialize.hh"
 
 
 /*
@@ -64,6 +65,22 @@
 template<typename Type>
 static inline Type& StructAtOffset(void *P, unsigned int offset)
 { return * reinterpret_cast<Type*> ((char *) P + offset); }
+template<typename Type>
+static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
+template<typename Type>
+static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
 
 /* StructAfter<T>(X) returns the struct T& that is placed after X.
  * Works with X of variable size also.  X must implement get_size() */
@@ -97,651 +114,36 @@
 #define DEFINE_SIZE_STATIC(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \
   unsigned int get_size () const { return (size); } \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }; \
-  enum { static_size = (size) }
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size); \
+  static constexpr unsigned static_size = (size)
 
 #define DEFINE_SIZE_UNION(size, _member) \
   DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \
   DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size)
 
 #define DEFINE_SIZE_MIN(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size)
 
 #define DEFINE_SIZE_UNBOUNDED(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
-  enum { min_size = (size) }
+  static constexpr unsigned min_size = (size)
 
 #define DEFINE_SIZE_ARRAY(size, array) \
   DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + HB_VAR_ARRAY * sizeof ((array)[0])) \
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size)
 
 #define DEFINE_SIZE_ARRAY_SIZED(size, array) \
   unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \
   DEFINE_SIZE_ARRAY(size, array)
 
 
-/*
- * Dispatch
- */
-
-template <typename Context, typename Return, unsigned int MaxDebugDepth>
-struct hb_dispatch_context_t
-{
-  enum { max_debug_depth = MaxDebugDepth };
-  typedef Return return_t;
-  template <typename T, typename F>
-  bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
-  static return_t no_dispatch_return_value () { return Context::default_return_value (); }
-  static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
-};
-
-
-/*
- * Sanitize
- *
- *
- * === Introduction ===
- *
- * The sanitize machinery is at the core of our zero-cost font loading.  We
- * mmap() font file into memory and create a blob out of it.  Font subtables
- * are returned as a readonly sub-blob of the main font blob.  These table
- * blobs are then sanitized before use, to ensure invalid memory access does
- * not happen.  The toplevel sanitize API use is like, eg. to load the 'head'
- * table:
- *
- *   hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
- *
- * The blob then can be converted to a head table struct with:
- *
- *   const head *head_table = head_blob->as<head> ();
- *
- * What the reference_table does is, to call hb_face_reference_table() to load
- * the table blob, sanitize it and return either the sanitized blob, or empty
- * blob if sanitization failed.  The blob->as() function returns the null
- * object of its template type argument if the blob is empty.  Otherwise, it
- * just casts the blob contents to the desired type.
- *
- * Sanitizing a blob of data with a type T works as follows (with minor
- * simplification):
- *
- *   - Cast blob content to T*, call sanitize() method of it,
- *   - If sanitize succeeded, return blob.
- *   - Otherwise, if blob is not writable, try making it writable,
- *     or copy if cannot be made writable in-place,
- *   - Call sanitize() again.  Return blob if sanitize succeeded.
- *   - Return empty blob otherwise.
- *
- *
- * === The sanitize() contract ===
- *
- * The sanitize() method of each object type shall return true if it's safe to
- * call other methods of the object, and false otherwise.
- *
- * Note that what sanitize() checks for might align with what the specification
- * describes as valid table data, but does not have to be.  In particular, we
- * do NOT want to be pedantic and concern ourselves with validity checks that
- * are irrelevant to our use of the table.  On the contrary, we want to be
- * lenient with error handling and accept invalid data to the extent that it
- * does not impose extra burden on us.
- *
- * Based on the sanitize contract, one can see that what we check for depends
- * on how we use the data in other table methods.  Ie. if other table methods
- * assume that offsets do NOT point out of the table data block, then that's
- * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way).  On
- * the other hand, if other methods do such checks themselves, then sanitize()
- * does not have to bother with them (glyf/local work this way).  The choice
- * depends on the table structure and sanitize() performance.  For example, to
- * check glyf/loca offsets in sanitize() would cost O(num-glyphs).  We try hard
- * to avoid such costs during font loading.  By postponing such checks to the
- * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
- * cost to O(used-glyphs).  As such, this is preferred.
- *
- * The same argument can be made re GSUB/GPOS/GDEF, but there, the table
- * structure is so complicated that by checking all offsets at sanitize() time,
- * we make the code much simpler in other methods, as offsets and referenced
- * objects do not need to be validated at each use site.
- */
-
-/* This limits sanitizing time on really broken fonts. */
-#ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 32
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_FACTOR
-#define HB_SANITIZE_MAX_OPS_FACTOR 8
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_MIN
-#define HB_SANITIZE_MAX_OPS_MIN 16384
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_MAX
-#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
-#endif
-
-struct hb_sanitize_context_t :
-       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
-{
-  hb_sanitize_context_t () :
-	debug_depth (0),
-	start (nullptr), end (nullptr),
-	max_ops (0),
-	writable (false), edit_count (0),
-	blob (nullptr),
-	num_glyphs (65536),
-	num_glyphs_set (false) {}
-
-  const char *get_name () { return "SANITIZE"; }
-  template <typename T, typename F>
-  bool may_dispatch (const T *obj HB_UNUSED, const F *format)
-  { return format->sanitize (this); }
-  template <typename T>
-  return_t dispatch (const T &obj) { return obj.sanitize (this); }
-  static return_t default_return_value () { return true; }
-  static return_t no_dispatch_return_value () { return false; }
-  bool stop_sublookup_iteration (const return_t r) const { return !r; }
-
-  void init (hb_blob_t *b)
-  {
-    this->blob = hb_blob_reference (b);
-    this->writable = false;
-  }
-
-  void set_num_glyphs (unsigned int num_glyphs_)
-  {
-    num_glyphs = num_glyphs_;
-    num_glyphs_set = true;
-  }
-  unsigned int get_num_glyphs () { return num_glyphs; }
-
-  void set_max_ops (int max_ops_) { max_ops = max_ops_; }
-
-  template <typename T>
-  void set_object (const T *obj)
-  {
-    reset_object ();
-
-    if (!obj) return;
-
-    const char *obj_start = (const char *) obj;
-    const char *obj_end = (const char *) obj + obj->get_size ();
-    assert (obj_start <= obj_end); /* Must not overflow. */
-
-    if (unlikely (obj_end < this->start || this->end < obj_start))
-      this->start = this->end = nullptr;
-    else
-    {
-      this->start = MAX (this->start, obj_start);
-      this->end   = MIN (this->end  , obj_end  );
-    }
-  }
-
-  void reset_object ()
-  {
-    this->start = this->blob->data;
-    this->end = this->start + this->blob->length;
-    assert (this->start <= this->end); /* Must not overflow. */
-  }
-
-  void start_processing ()
-  {
-    reset_object ();
-    this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
-			 (unsigned) HB_SANITIZE_MAX_OPS_MIN);
-    this->edit_count = 0;
-    this->debug_depth = 0;
-
-    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
-		     "start [%p..%p] (%lu bytes)",
-		     this->start, this->end,
-		     (unsigned long) (this->end - this->start));
-  }
-
-  void end_processing ()
-  {
-    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
-		     "end [%p..%p] %u edit requests",
-		     this->start, this->end, this->edit_count);
-
-    hb_blob_destroy (this->blob);
-    this->blob = nullptr;
-    this->start = this->end = nullptr;
-  }
-
-  bool check_range (const void *base,
-			   unsigned int len) const
-  {
-    const char *p = (const char *) base;
-    bool ok = this->start <= p &&
-	      p <= this->end &&
-	      (unsigned int) (this->end - p) >= len &&
-	      this->max_ops-- > 0;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       p, p + len, len,
-       this->start, this->end,
-       ok ? "OK" : "OUT-OF-RANGE");
-
-    return likely (ok);
-  }
-
-  template <typename T>
-  bool check_range (const T *base,
-			   unsigned int a,
-			   unsigned int b) const
-  {
-    return !hb_unsigned_mul_overflows (a, b) &&
-	   this->check_range (base, a * b);
-  }
-
-  template <typename T>
-  bool check_range (const T *base,
-			   unsigned int a,
-			   unsigned int b,
-			   unsigned int c) const
-  {
-    return !hb_unsigned_mul_overflows (a, b) &&
-	   this->check_range (base, a * b, c);
-  }
-
-  template <typename T>
-  bool check_array (const T *base, unsigned int len) const
-  {
-    return this->check_range (base, len, hb_static_size (T));
-  }
-
-  template <typename T>
-  bool check_array (const T *base,
-		    unsigned int a,
-		    unsigned int b) const
-  {
-    return this->check_range (base, a, b, hb_static_size (T));
-  }
-
-  template <typename Type>
-  bool check_struct (const Type *obj) const
-  { return likely (this->check_range (obj, obj->min_size)); }
-
-  bool may_edit (const void *base, unsigned int len)
-  {
-    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
-      return false;
-
-    const char *p = (const char *) base;
-    this->edit_count++;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       this->edit_count,
-       p, p + len, len,
-       this->start, this->end,
-       this->writable ? "GRANTED" : "DENIED");
-
-    return this->writable;
-  }
-
-  template <typename Type, typename ValueType>
-  bool try_set (const Type *obj, const ValueType &v)
-  {
-    if (this->may_edit (obj, hb_static_size (Type)))
-    {
-      hb_assign (* const_cast<Type *> (obj), v);
-      return true;
-    }
-    return false;
-  }
-
-  template <typename Type>
-  hb_blob_t *sanitize_blob (hb_blob_t *blob)
-  {
-    bool sane;
-
-    init (blob);
-
-  retry:
-    DEBUG_MSG_FUNC (SANITIZE, start, "start");
-
-    start_processing ();
-
-    if (unlikely (!start))
-    {
-      end_processing ();
-      return blob;
-    }
-
-    Type *t = CastP<Type> (const_cast<char *> (start));
-
-    sane = t->sanitize (this);
-    if (sane)
-    {
-      if (edit_count)
-      {
-	DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
-
-        /* sanitize again to ensure no toe-stepping */
-        edit_count = 0;
-	sane = t->sanitize (this);
-	if (edit_count) {
-	  DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count);
-	  sane = false;
-	}
-      }
-    }
-    else
-    {
-      if (edit_count && !writable) {
-        start = hb_blob_get_data_writable (blob, nullptr);
-	end = start + blob->length;
-
-	if (start)
-	{
-	  writable = true;
-	  /* ok, we made it writable by relocating.  try again */
-	  DEBUG_MSG_FUNC (SANITIZE, start, "retry");
-	  goto retry;
-	}
-      }
-    }
-
-    end_processing ();
-
-    DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED");
-    if (sane)
-    {
-      hb_blob_make_immutable (blob);
-      return blob;
-    }
-    else
-    {
-      hb_blob_destroy (blob);
-      return hb_blob_get_empty ();
-    }
-  }
-
-  template <typename Type>
-  hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag)
-  {
-    if (!num_glyphs_set)
-      set_num_glyphs (hb_face_get_glyph_count (face));
-    return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
-  }
-
-  mutable unsigned int debug_depth;
-  const char *start, *end;
-  mutable int max_ops;
-  private:
-  bool writable;
-  unsigned int edit_count;
-  hb_blob_t *blob;
-  unsigned int num_glyphs;
-  bool  num_glyphs_set;
-};
-
-struct hb_sanitize_with_object_t
-{
-  template <typename T>
-  hb_sanitize_with_object_t (hb_sanitize_context_t *c,
-				    const T& obj) : c (c)
-  { c->set_object (obj); }
-  ~hb_sanitize_with_object_t ()
-  { c->reset_object (); }
-
-  private:
-  hb_sanitize_context_t *c;
-};
-
-
-/*
- * Serialize
- */
-
-struct hb_serialize_context_t
-{
-  hb_serialize_context_t (void *start_, unsigned int size)
-  {
-    this->start = (char *) start_;
-    this->end = this->start + size;
-    reset ();
-  }
-
-  bool in_error () const { return !this->successful; }
-
-  void reset ()
-  {
-    this->successful = true;
-    this->head = this->start;
-    this->debug_depth = 0;
-  }
-
-  bool propagate_error (bool e)
-  { return this->successful = this->successful && e; }
-  template <typename T> bool propagate_error (const T &obj)
-  { return this->successful = this->successful && !obj.in_error (); }
-  template <typename T> bool propagate_error (const T *obj)
-  { return this->successful = this->successful && !obj->in_error (); }
-  template <typename T1, typename T2> bool propagate_error (T1 &o1, T2 &o2)
-  { return propagate_error (o1) && propagate_error (o2); }
-  template <typename T1, typename T2> bool propagate_error (T1 *o1, T2 *o2)
-  { return propagate_error (o1) && propagate_error (o2); }
-  template <typename T1, typename T2, typename T3>
-  bool propagate_error (T1 &o1, T2 &o2, T3 &o3)
-  { return propagate_error (o1) && propagate_error (o2, o3); }
-  template <typename T1, typename T2, typename T3>
-  bool propagate_error (T1 *o1, T2 *o2, T3 *o3)
-  { return propagate_error (o1) && propagate_error (o2, o3); }
-
-  /* To be called around main operation. */
-  template <typename Type>
-  Type *start_serialize ()
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
-		     "start [%p..%p] (%lu bytes)",
-		     this->start, this->end,
-		     (unsigned long) (this->end - this->start));
-
-    return start_embed<Type> ();
-  }
-  void end_serialize ()
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
-		     "end [%p..%p] serialized %d bytes; %s",
-		     this->start, this->end,
-		     (int) (this->head - this->start),
-		     this->successful ? "successful" : "UNSUCCESSFUL");
-  }
-
-  unsigned int length () const { return this->head - this->start; }
-
-  void align (unsigned int alignment)
-  {
-    unsigned int l = length () % alignment;
-    if (l)
-      allocate_size<void> (alignment - l);
-  }
-
-  template <typename Type>
-  Type *start_embed (const Type *_ HB_UNUSED = nullptr) const
-  {
-    Type *ret = reinterpret_cast<Type *> (this->head);
-    return ret;
-  }
-
-  template <typename Type>
-  Type *allocate_size (unsigned int size)
-  {
-    if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) {
-      this->successful = false;
-      return nullptr;
-    }
-    memset (this->head, 0, size);
-    char *ret = this->head;
-    this->head += size;
-    return reinterpret_cast<Type *> (ret);
-  }
-
-  template <typename Type>
-  Type *allocate_min ()
-  {
-    return this->allocate_size<Type> (Type::min_size);
-  }
-
-  template <typename Type>
-  Type *embed (const Type &obj)
-  {
-    unsigned int size = obj.get_size ();
-    Type *ret = this->allocate_size<Type> (size);
-    if (unlikely (!ret)) return nullptr;
-    memcpy (ret, &obj, size);
-    return ret;
-  }
-  template <typename Type>
-  hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; }
-
-  template <typename Type>
-  Type *extend_size (Type &obj, unsigned int size)
-  {
-    assert (this->start <= (char *) &obj);
-    assert ((char *) &obj <= this->head);
-    assert ((char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
-    return reinterpret_cast<Type *> (&obj);
-  }
-
-  template <typename Type>
-  Type *extend_min (Type &obj) { return extend_size (obj, obj.min_size); }
-
-  template <typename Type>
-  Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
-
-  /* Output routines. */
-  template <typename Type>
-  Type *copy () const
-  {
-    assert (this->successful);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    return reinterpret_cast<Type *> (p);
-  }
-  hb_bytes_t copy_bytes () const
-  {
-    assert (this->successful);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    else
-      return hb_bytes_t ();
-    return hb_bytes_t ((char *) p, len);
-  }
-  hb_blob_t *copy_blob () const
-  {
-    assert (this->successful);
-    return hb_blob_create (this->start,
-			   this->head - this->start,
-			   HB_MEMORY_MODE_DUPLICATE,
-			   nullptr, nullptr);
-  }
-
-  public:
-  unsigned int debug_depth;
-  char *start, *end, *head;
-  bool successful;
-};
-
-
-
-/*
- * Big-endian integers.
- */
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
-  public:
-  typedef Type type;
-  void set (Type V)      { v = V; }
-  operator Type () const { return v; }
-  private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
-  public:
-  typedef Type type;
-  void set (Type V)
-  {
-    v[0] = (V >>  8) & 0xFF;
-    v[1] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
-    defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
-    /* Spoon-feed the compiler a big-endian integer with alignment 1.
-     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
-    struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
-#endif
-#endif
-    return (v[0] <<  8)
-         + (v[1]      );
-  }
-  private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
-  public:
-  typedef Type type;
-  void set (Type V)
-  {
-    v[0] = (V >> 16) & 0xFF;
-    v[1] = (V >>  8) & 0xFF;
-    v[2] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-    return (v[0] << 16)
-         + (v[1] <<  8)
-         + (v[2]      );
-  }
-  private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
-  public:
-  typedef Type type;
-  void set (Type V)
-  {
-    v[0] = (V >> 24) & 0xFF;
-    v[1] = (V >> 16) & 0xFF;
-    v[2] = (V >>  8) & 0xFF;
-    v[3] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-    return (v[0] << 24)
-         + (v[1] << 16)
-         + (v[2] <<  8)
-         + (v[3]      );
-  }
-  private: uint8_t v[4];
-};
-
 
 /*
  * Lazy loaders.
@@ -804,7 +206,7 @@
 
   const Returned * operator -> () const { return get (); }
   const Returned & operator * () const  { return *get (); }
-  explicit_operator bool () const
+  explicit operator bool () const
   { return get_stored () != Funcs::get_null (); }
   template <typename C> operator const C * () const { return get (); }
 
@@ -823,7 +225,7 @@
 
       if (unlikely (!cmpexch (nullptr, p)))
       {
-        do_destroy (p);
+	do_destroy (p);
 	goto retry;
       }
     }
diff --git a/src/hb-map.hh b/src/hb-map.hh
index 3b119da..8c8db4d 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -30,31 +30,36 @@
 #include "hb.hh"
 
 
-template <typename T>
-inline uint32_t Hash (const T &v)
-{
-  /* Knuth's multiplicative method: */
-  return (uint32_t) v * 2654435761u;
-}
-
-
 /*
- * hb_map_t
+ * hb_hashmap_t
  */
 
-struct hb_map_t
+template <typename K, typename V,
+	  K kINVALID = hb_is_pointer (K) ? 0 : hb_is_signed (K) ? hb_int_min (K) : (K) -1,
+	  V vINVALID = hb_is_pointer (V) ? 0 : hb_is_signed (V) ? hb_int_min (V) : (V) -1>
+struct hb_hashmap_t
 {
-  HB_NO_COPY_ASSIGN (hb_map_t);
-  hb_map_t ()  { init (); }
-  ~hb_map_t () { fini (); }
+  HB_DELETE_COPY_ASSIGN (hb_hashmap_t);
+  hb_hashmap_t ()  { init (); }
+  ~hb_hashmap_t () { fini (); }
+
+  static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
+  static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
 
   struct item_t
   {
-    hb_codepoint_t key;
-    hb_codepoint_t value;
+    K key;
+    V value;
+    uint32_t hash;
 
-    bool is_unused () const    { return key == INVALID; }
-    bool is_tombstone () const { return key != INVALID && value == INVALID; }
+    void clear () { key = kINVALID; value = vINVALID; hash = 0; }
+
+    bool operator == (K o) { return hb_deref (key) == hb_deref (o); }
+    bool operator == (const item_t &o) { return *this == o.key; }
+    bool is_unused () const    { return key == kINVALID; }
+    bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
+    bool is_real () const { return key != kINVALID && value != vINVALID; }
+    hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
   };
 
   hb_object_header_t header;
@@ -82,14 +87,22 @@
   {
     free (items);
     items = nullptr;
+    population = occupancy = 0;
   }
   void fini ()
   {
-    population = occupancy = 0;
     hb_object_fini (this);
     fini_shallow ();
   }
 
+  void reset ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    successful = true;
+    clear ();
+  }
+
   bool in_error () const { return !successful; }
 
   bool resize ()
@@ -104,7 +117,9 @@
       successful = false;
       return false;
     }
-    memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
+    + hb_iter (new_items, new_size)
+    | hb_apply (&item_t::clear)
+    ;
 
     unsigned int old_size = mask + 1;
     item_t *old_items = items;
@@ -118,22 +133,97 @@
     /* Insert back old items. */
     if (old_items)
       for (unsigned int i = 0; i < old_size; i++)
-	if (old_items[i].key != INVALID && old_items[i].value != INVALID)
-	  set (old_items[i].key, old_items[i].value);
+	if (old_items[i].is_real ())
+	  set_with_hash (old_items[i].key,
+                         old_items[i].hash,
+                         old_items[i].value);
 
     free (old_items);
 
     return true;
   }
 
-  void set (hb_codepoint_t key, hb_codepoint_t value)
+  void set (K key, V value)
+  {
+    set_with_hash (key, hb_hash (key), value);
+  }
+
+  V get (K key) const
+  {
+    if (unlikely (!items)) return vINVALID;
+    unsigned int i = bucket_for (key);
+    return items[i].is_real () && items[i] == key ? items[i].value : vINVALID;
+  }
+
+  void del (K key) { set (key, vINVALID); }
+
+  /* Has interface. */
+  static constexpr V SENTINEL = vINVALID;
+  typedef V value_t;
+  value_t operator [] (K k) const { return get (k); }
+  bool has (K k, V *vp = nullptr) const
+  {
+    V v = (*this)[k];
+    if (vp) *vp = v;
+    return v != SENTINEL;
+  }
+  /* Projection. */
+  V operator () (K k) const { return get (k); }
+
+  void clear ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    if (items)
+      + hb_iter (items, mask + 1)
+      | hb_apply (&item_t::clear)
+      ;
+
+    population = occupancy = 0;
+  }
+
+  bool is_empty () const { return population == 0; }
+
+  unsigned int get_population () const { return population; }
+
+  /*
+   * Iterator
+   */
+  auto iter () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::get_pair)
+  )
+  auto keys () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::key)
+    | hb_map (hb_ridentity)
+  )
+  auto values () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::value)
+    | hb_map (hb_ridentity)
+  )
+
+  /* Sink interface. */
+  hb_hashmap_t<K, V, kINVALID, vINVALID>& operator << (const hb_pair_t<K, V>& v)
+  { set (v.first, v.second); return *this; }
+
+  protected:
+
+  void set_with_hash (K key, uint32_t hash, V value)
   {
     if (unlikely (!successful)) return;
-    if (unlikely (key == INVALID)) return;
+    if (unlikely (key == kINVALID)) return;
     if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
-    unsigned int i = bucket_for (key);
+    unsigned int i = bucket_for_hash (key, hash);
 
-    if (value == INVALID && items[i].key != key)
+    if (value == vINVALID && items[i].key != key)
       return; /* Trying to delete non-existent key. */
 
     if (!items[i].is_unused ())
@@ -145,55 +235,32 @@
 
     items[i].key = key;
     items[i].value = value;
+    items[i].hash = hash;
 
     occupancy++;
     if (!items[i].is_tombstone ())
       population++;
-
-  }
-  hb_codepoint_t get (hb_codepoint_t key) const
-  {
-    if (unlikely (!items)) return INVALID;
-    unsigned int i = bucket_for (key);
-    return items[i].key == key ? items[i].value : INVALID;
   }
 
-  void del (hb_codepoint_t key) { set (key, INVALID); }
-
-  bool has (hb_codepoint_t key) const
-  { return get (key) != INVALID; }
-
-  hb_codepoint_t operator [] (unsigned int key) const
-  { return get (key); }
-
-  enum { INVALID = HB_MAP_VALUE_INVALID };
-
-  void clear ()
+  unsigned int bucket_for (K key) const
   {
-    memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
-    population = occupancy = 0;
+    return bucket_for_hash (key, hb_hash (key));
   }
 
-  bool is_empty () const { return population == 0; }
-
-  unsigned int get_population () const { return population; }
-
-  protected:
-
-  unsigned int bucket_for (hb_codepoint_t key) const
+  unsigned int bucket_for_hash (K key, uint32_t hash) const
   {
-    unsigned int i = Hash (key) % prime;
+    unsigned int i = hash % prime;
     unsigned int step = 0;
-    unsigned int tombstone = INVALID;
+    unsigned int tombstone = (unsigned) -1;
     while (!items[i].is_unused ())
     {
-      if (items[i].key == key)
-        return i;
-      if (tombstone == INVALID && items[i].is_tombstone ())
-        tombstone = i;
+      if (items[i].hash == hash && items[i] == key)
+	return i;
+      if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
+	tombstone = i;
       i = (i + ++step) & mask;
     }
-    return tombstone == INVALID ? i : tombstone;
+    return tombstone == (unsigned) -1 ? i : tombstone;
   }
 
   static unsigned int prime_for (unsigned int shift)
@@ -248,5 +315,14 @@
   }
 };
 
+/*
+ * hb_map_t
+ */
+
+struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
+			       hb_codepoint_t,
+			       HB_MAP_VALUE_INVALID,
+			       HB_MAP_VALUE_INVALID> {};
+
 
 #endif /* HB_MAP_HH */
diff --git a/src/hb-meta.hh b/src/hb-meta.hh
new file mode 100644
index 0000000..2dfaeb7
--- /dev/null
+++ b/src/hb-meta.hh
@@ -0,0 +1,400 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_META_HH
+#define HB_META_HH
+
+#include "hb.hh"
+
+
+/*
+ * C++ template meta-programming & fundamentals used with them.
+ */
+
+/* Void!  For when we need a expression-type of void. */
+struct hb_empty_t {};
+
+/* https://en.cppreference.com/w/cpp/types/void_t */
+template<typename... Ts> struct _hb_void_t { typedef void type; };
+template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
+
+template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
+template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
+
+template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
+template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
+using hb_true_type = hb_bool_constant<true>;
+using hb_false_type = hb_bool_constant<false>;
+
+
+/* Basic type SFINAE. */
+
+template <bool B, typename T = void> struct hb_enable_if {};
+template <typename T>                struct hb_enable_if<true, T> { typedef T type; };
+#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
+/* Concepts/Requires alias: */
+#define hb_requires(Cond) hb_enable_if((Cond))
+
+template <typename T, typename T2> struct hb_is_same : hb_false_type {};
+template <typename T>              struct hb_is_same<T, T> : hb_true_type {};
+#define hb_is_same(T, T2) hb_is_same<T, T2>::value
+
+/* Function overloading SFINAE and priority. */
+
+#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
+#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
+#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }
+
+template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
+template <>             struct hb_priority<0> {};
+#define hb_prioritize hb_priority<16> ()
+
+#define HB_FUNCOBJ(x) static_const x HB_UNUSED
+
+
+template <typename T> struct hb_type_identity_t { typedef T type; };
+template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
+
+struct
+{
+  template <typename T> constexpr T*
+  operator () (T& arg) const
+  {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+    /* https://en.cppreference.com/w/cpp/memory/addressof */
+    return reinterpret_cast<T*> (
+	     &const_cast<char&> (
+		reinterpret_cast<const volatile char&> (arg)));
+#pragma GCC diagnostic pop
+  }
+}
+HB_FUNCOBJ (hb_addressof);
+
+template <typename T> static inline T hb_declval ();
+#define hb_declval(T) (hb_declval<T> ())
+
+template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
+template <typename T> using hb_add_const = const T;
+#define hb_is_const(T) hb_match_const<T>::value
+template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
+template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
+template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
+template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
+template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
+template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
+template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
+#define hb_is_reference(T) hb_match_reference<T>::value
+template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
+template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
+template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
+template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
+#define hb_is_pointer(T) hb_match_pointer<T>::value
+
+
+/* TODO Add feature-parity to std::decay. */
+template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
+
+
+template<bool B, class T, class F>
+struct _hb_conditional { typedef T type; };
+template<class T, class F>
+struct _hb_conditional<false, T, F> { typedef F type; };
+template<bool B, class T, class F>
+using hb_conditional = typename _hb_conditional<B, T, F>::type;
+
+
+template <typename From, typename To>
+struct hb_is_convertible
+{
+  private:
+  static constexpr bool   from_void = hb_is_same (void, hb_decay<From>);
+  static constexpr bool     to_void = hb_is_same (void, hb_decay<To>  );
+  static constexpr bool either_void = from_void || to_void;
+  static constexpr bool   both_void = from_void && to_void;
+
+  static hb_true_type impl2 (hb_conditional<to_void, int, To>);
+
+  template <typename T>
+  static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
+  template <typename T>
+  static hb_false_type impl (hb_priority<0>);
+  public:
+  static constexpr bool value = both_void ||
+		       (!either_void &&
+			decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
+};
+#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value
+
+template <typename Base, typename Derived>
+using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
+#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value
+
+template <typename From, typename To>
+using hb_is_cr_convertible = hb_bool_constant<
+  hb_is_same (hb_decay<From>, hb_decay<To>) &&
+  (!hb_is_const (From) || hb_is_const (To)) &&
+  (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
+>;
+#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
+
+/* std::move and std::forward */
+
+template <typename T>
+static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
+
+template <typename T>
+static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
+template <typename T>
+static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
+
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+
+  template <typename T> constexpr auto
+  operator () (T *v) const HB_AUTO_RETURN (*v)
+}
+HB_FUNCOBJ (hb_deref);
+
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+
+  template <typename T> constexpr auto
+  operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
+}
+HB_FUNCOBJ (hb_ref);
+
+template <typename T>
+struct hb_reference_wrapper
+{
+  hb_reference_wrapper (T v) : v (v) {}
+  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
+  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
+  operator T () const { return v; }
+  T get () const { return v; }
+  T v;
+};
+template <typename T>
+struct hb_reference_wrapper<T&>
+{
+  hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
+  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
+  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
+  operator T& () const { return *v; }
+  T& get () const { return *v; }
+  T* v;
+};
+
+
+template <typename T>
+using hb_is_integral = hb_bool_constant<
+  hb_is_same (hb_decay<T>, char) ||
+  hb_is_same (hb_decay<T>, signed char) ||
+  hb_is_same (hb_decay<T>, unsigned char) ||
+  hb_is_same (hb_decay<T>, signed int) ||
+  hb_is_same (hb_decay<T>, unsigned int) ||
+  hb_is_same (hb_decay<T>, signed short) ||
+  hb_is_same (hb_decay<T>, unsigned short) ||
+  hb_is_same (hb_decay<T>, signed long) ||
+  hb_is_same (hb_decay<T>, unsigned long) ||
+  hb_is_same (hb_decay<T>, signed long long) ||
+  hb_is_same (hb_decay<T>, unsigned long long) ||
+  false
+>;
+#define hb_is_integral(T) hb_is_integral<T>::value
+template <typename T>
+using hb_is_floating_point = hb_bool_constant<
+  hb_is_same (hb_decay<T>, float) ||
+  hb_is_same (hb_decay<T>, double) ||
+  hb_is_same (hb_decay<T>, long double) ||
+  false
+>;
+#define hb_is_floating_point(T) hb_is_floating_point<T>::value
+template <typename T>
+using hb_is_arithmetic = hb_bool_constant<
+  hb_is_integral (T) ||
+  hb_is_floating_point (T) ||
+  false
+>;
+#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
+
+
+template <typename T>
+using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
+				    hb_bool_constant<(T) -1 < (T) 0>,
+				    hb_false_type>;
+#define hb_is_signed(T) hb_is_signed<T>::value
+template <typename T>
+using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
+				      hb_bool_constant<(T) 0 < (T) -1>,
+				      hb_false_type>;
+#define hb_is_unsigned(T) hb_is_unsigned<T>::value
+
+template <typename T> struct hb_int_min;
+template <> struct hb_int_min<char>			: hb_integral_constant<char,			CHAR_MIN>	{};
+template <> struct hb_int_min<signed char>		: hb_integral_constant<signed char,		SCHAR_MIN>	{};
+template <> struct hb_int_min<unsigned char>		: hb_integral_constant<unsigned char,		0>		{};
+template <> struct hb_int_min<signed short>		: hb_integral_constant<signed short,		SHRT_MIN>	{};
+template <> struct hb_int_min<unsigned short>		: hb_integral_constant<unsigned short,		0>		{};
+template <> struct hb_int_min<signed int>		: hb_integral_constant<signed int,		INT_MIN>	{};
+template <> struct hb_int_min<unsigned int>		: hb_integral_constant<unsigned int,		0>		{};
+template <> struct hb_int_min<signed long>		: hb_integral_constant<signed long,		LONG_MIN>	{};
+template <> struct hb_int_min<unsigned long>		: hb_integral_constant<unsigned long,		0>		{};
+template <> struct hb_int_min<signed long long>		: hb_integral_constant<signed long long,	LLONG_MIN>	{};
+template <> struct hb_int_min<unsigned long long>	: hb_integral_constant<unsigned long long,	0>		{};
+#define hb_int_min(T) hb_int_min<T>::value
+template <typename T> struct hb_int_max;
+template <> struct hb_int_max<char>			: hb_integral_constant<char,			CHAR_MAX>	{};
+template <> struct hb_int_max<signed char>		: hb_integral_constant<signed char,		SCHAR_MAX>	{};
+template <> struct hb_int_max<unsigned char>		: hb_integral_constant<unsigned char,		UCHAR_MAX>	{};
+template <> struct hb_int_max<signed short>		: hb_integral_constant<signed short,		SHRT_MAX>	{};
+template <> struct hb_int_max<unsigned short>		: hb_integral_constant<unsigned short,		USHRT_MAX>	{};
+template <> struct hb_int_max<signed int>		: hb_integral_constant<signed int,		INT_MAX>	{};
+template <> struct hb_int_max<unsigned int>		: hb_integral_constant<unsigned int,		UINT_MAX>	{};
+template <> struct hb_int_max<signed long>		: hb_integral_constant<signed long,		LONG_MAX>	{};
+template <> struct hb_int_max<unsigned long>		: hb_integral_constant<unsigned long,		ULONG_MAX>	{};
+template <> struct hb_int_max<signed long long>		: hb_integral_constant<signed long long,	LLONG_MAX>	{};
+template <> struct hb_int_max<unsigned long long>	: hb_integral_constant<unsigned long long,	ULLONG_MAX>	{};
+#define hb_int_max(T) hb_int_max<T>::value
+
+
+
+template <typename T, typename>
+struct _hb_is_destructible : hb_false_type {};
+template <typename T>
+struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
+template <typename T>
+using hb_is_destructible = _hb_is_destructible<T, void>;
+#define hb_is_destructible(T) hb_is_destructible<T>::value
+
+template <typename T, typename, typename ...Ts>
+struct _hb_is_constructible : hb_false_type {};
+template <typename T, typename ...Ts>
+struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
+template <typename T, typename ...Ts>
+using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
+#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
+
+template <typename T>
+using hb_is_default_constructible = hb_is_constructible<T>;
+#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
+
+template <typename T>
+using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
+#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
+
+template <typename T>
+using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
+#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
+
+template <typename T, typename U, typename>
+struct _hb_is_assignable : hb_false_type {};
+template <typename T, typename U>
+struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
+template <typename T, typename U>
+using hb_is_assignable = _hb_is_assignable<T, U, void>;
+#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value
+
+template <typename T>
+using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
+					       hb_add_lvalue_reference<hb_add_const<T>>>;
+#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
+
+template <typename T>
+using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
+					       hb_add_rvalue_reference<T>>;
+#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
+
+/* Trivial versions. */
+
+template <typename T> union hb_trivial { T value; };
+
+/* Don't know how to do the following. */
+template <typename T>
+using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
+#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
+
+/* Don't know how to do the following. */
+//template <typename T, typename ...Ts>
+//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
+//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
+
+template <typename T>
+using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
+#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
+
+template <typename T>
+using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
+#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
+
+template <typename T>
+using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
+#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
+
+/* Don't know how to do the following. */
+//template <typename T, typename U>
+//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
+//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
+
+template <typename T>
+using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
+#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
+
+template <typename T>
+using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
+#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
+
+template <typename T>
+using hb_is_trivially_copyable= hb_bool_constant<
+  hb_is_trivially_destructible (T) &&
+  (!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
+  (!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
+  (!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
+  (!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
+  true
+>;
+#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
+
+template <typename T>
+using hb_is_trivial= hb_bool_constant<
+  hb_is_trivially_copyable (T) &&
+  hb_is_trivially_default_constructible (T)
+>;
+#define hb_is_trivial(T) hb_is_trivial<T>::value
+
+
+#endif /* HB_META_HH */
diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh
index 35f1fde..e7f8b1c 100644
--- a/src/hb-mutex.hh
+++ b/src/hb-mutex.hh
@@ -48,6 +48,17 @@
 /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
 
 
+#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
+
+#include <pthread.h>
+typedef pthread_mutex_t hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
+#define hb_mutex_impl_init(M)	pthread_mutex_init (M, nullptr)
+#define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
+#define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
+#define hb_mutex_impl_finish(M)	pthread_mutex_destroy (M)
+
+
 #elif !defined(HB_NO_MT) && defined(_WIN32)
 
 #include <windows.h>
@@ -63,17 +74,6 @@
 #define hb_mutex_impl_finish(M)	DeleteCriticalSection (M)
 
 
-#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
-
-#include <pthread.h>
-typedef pthread_mutex_t hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
-#define hb_mutex_impl_init(M)	pthread_mutex_init (M, nullptr)
-#define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
-#define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
-#define hb_mutex_impl_finish(M)	pthread_mutex_destroy (M)
-
-
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
@@ -92,25 +92,7 @@
 #define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
 
 
-#elif !defined(HB_NO_MT)
-
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
-# include <sched.h>
-# define HB_SCHED_YIELD() sched_yield ()
-#else
-# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
-#endif
-
-#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
-typedef volatile int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	0
-#define hb_mutex_impl_init(M)	*(M) = 0
-#define hb_mutex_impl_lock(M)	HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
-#define hb_mutex_impl_unlock(M)	(*(M))--;
-#define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
-
-
-#else /* HB_NO_MT */
+#elif defined(HB_NO_MT)
 
 typedef int hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	0
@@ -120,6 +102,11 @@
 #define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
 
 
+#else
+
+#error "Could not find any system to define mutex macros."
+#error "Check hb-mutex.hh for possible resolutions."
+
 #endif
 
 
@@ -127,8 +114,6 @@
 
 struct hb_mutex_t
 {
-  /* TODO Add tracing. */
-
   hb_mutex_impl_t m;
 
   void init   () { hb_mutex_impl_init   (&m); }
diff --git a/src/hb-null.hh b/src/hb-null.hh
index 8a3e0d4..d457820 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -28,6 +28,7 @@
 #define HB_NULL_HH
 
 #include "hb.hh"
+#include "hb-meta.hh"
 
 
 /*
@@ -36,7 +37,7 @@
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 
-#define HB_NULL_POOL_SIZE 9880
+#define HB_NULL_POOL_SIZE 384
 
 /* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
  * otherwise return sizeof(T). */
@@ -45,18 +46,13 @@
  * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
  */
 
-template<bool> struct _hb_bool_type {};
-
-template <typename T, typename B>
-struct _hb_null_size
-{ enum { value = sizeof (T) }; };
+template <typename T, typename>
+struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_null_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ enum { value = T::null_size }; };
+struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
 
 template <typename T>
-struct hb_null_size
-{ enum { value = _hb_null_size<T, _hb_bool_type<true> >::value }; };
+using hb_null_size = _hb_null_size<T, void>;
 #define hb_null_size(T) hb_null_size<T>::value
 
 /* These doesn't belong here, but since is copy/paste from above, put it here. */
@@ -64,56 +60,36 @@
 /* hb_static_size (T)
  * Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */
 
-template <typename T, typename B>
-struct _hb_static_size
-{ enum { value = sizeof (T) }; };
+template <typename T, typename>
+struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_static_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ enum { value = T::static_size }; };
-
+struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
 template <typename T>
-struct hb_static_size
-{ enum { value = _hb_static_size<T, _hb_bool_type<true> >::value }; };
+using hb_static_size = _hb_static_size<T, void>;
 #define hb_static_size(T) hb_static_size<T>::value
 
 
-/* hb_assign (obj, value)
- * Calls obj.set (value) if obj.min_size is defined and value has different type
- * from obj, or obj = v otherwise. */
-
-template <typename T, typename V, typename B>
-struct _hb_assign
-{ static inline void value (T &o, const V v) { o = v; } };
-template <typename T, typename V>
-struct _hb_assign<T, V, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ static inline void value (T &o, const V v) { o.set (v); } };
-template <typename T>
-struct _hb_assign<T, T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ static inline void value (T &o, const T v) { o = v; } };
-
-template <typename T, typename V>
-static inline void hb_assign (T &o, const V v)
-{ _hb_assign<T, V, _hb_bool_type<true> >::value (o, v); };
-
-
 /*
  * Null()
  */
 
 extern HB_INTERNAL
-hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
-static inline Type const & Null () {
-  static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
-  return *reinterpret_cast<Type const *> (_hb_NullPool);
-}
+struct Null {
+  static Type const & get_null ()
+  {
+    static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
+    return *reinterpret_cast<Type const *> (_hb_NullPool);
+  }
+};
 template <typename QType>
 struct NullHelper
 {
-  typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
-  static const Type & get_null () { return Null<Type> (); }
+  typedef hb_remove_const<hb_remove_reference<QType>> Type;
+  static const Type & get_null () { return Null<Type>::get_null (); }
 };
 #define Null(Type) NullHelper<Type>::get_null ()
 
@@ -122,9 +98,11 @@
 	} /* Close namespace. */ \
 	extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
 	template <> \
-	/*static*/ inline const Namespace::Type& Null<Namespace::Type> () { \
-	  return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
-	} \
+	struct Null<Namespace::Type> { \
+	  static Namespace::Type const & get_null () { \
+	    return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
+	  } \
+	}; \
 	namespace Namespace { \
 	static_assert (true, "Just so we take semicolon after.")
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
@@ -134,10 +112,12 @@
 #define DECLARE_NULL_INSTANCE(Type) \
 	extern HB_INTERNAL const Type _hb_Null_##Type; \
 	template <> \
-	/*static*/ inline const Type& Null<Type> () { \
-	  return _hb_Null_##Type; \
-	} \
-static_assert (true, "Just so we take semicolon after.")
+	struct Null<Type> { \
+	  static Type const & get_null () { \
+	    return _hb_Null_##Type; \
+	  } \
+	}; \
+	static_assert (true, "Just so we take semicolon after.")
 #define DEFINE_NULL_INSTANCE(Type) \
 	const Type _hb_Null_##Type
 
@@ -148,7 +128,7 @@
  * causing bad memory access. So, races there are not actually introducing incorrectness
  * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
 extern HB_INTERNAL
-/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
 
 /* CRAP pool: Common Region for Access Protection. */
 template <typename Type>
@@ -161,7 +141,7 @@
 template <typename QType>
 struct CrapHelper
 {
-  typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
+  typedef hb_remove_const<hb_remove_reference<QType>> Type;
   static Type & get_crap () { return Crap<Type> (); }
 };
 #define Crap(Type) CrapHelper<Type>::get_crap ()
@@ -184,7 +164,7 @@
 template <typename P>
 struct hb_nonnull_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {}
   T * operator = (T *v_)   { return v = v_; }
diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh
new file mode 100644
index 0000000..c78c850
--- /dev/null
+++ b/src/hb-number-parser.hh
@@ -0,0 +1,240 @@
+
+#line 1 "hb-number-parser.rl"
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#ifndef HB_NUMBER_PARSER_HH
+#define HB_NUMBER_PARSER_HH
+
+#include "hb.hh"
+
+#include <float.h>
+
+
+#line 37 "hb-number-parser.hh"
+static const unsigned char _double_parser_trans_keys[] = {
+	0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 
+	46u, 101u, 0
+};
+
+static const char _double_parser_key_spans[] = {
+	0, 15, 12, 10, 15, 10, 54, 10, 
+	56
+};
+
+static const unsigned char _double_parser_index_offsets[] = {
+	0, 0, 16, 29, 40, 56, 67, 122, 
+	133
+};
+
+static const char _double_parser_indicies[] = {
+	0, 1, 2, 3, 1, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	1, 3, 1, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 1, 5, 5, 
+	5, 5, 5, 5, 5, 5, 5, 5, 
+	1, 6, 1, 7, 1, 1, 8, 8, 
+	8, 8, 8, 8, 8, 8, 8, 8, 
+	1, 8, 8, 8, 8, 8, 8, 8, 
+	8, 8, 8, 1, 5, 5, 5, 5, 
+	5, 5, 5, 5, 5, 5, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 9, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 9, 1, 8, 8, 8, 8, 8, 
+	8, 8, 8, 8, 8, 1, 3, 1, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 9, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 9, 1, 0
+};
+
+static const char _double_parser_trans_targs[] = {
+	2, 0, 2, 3, 8, 6, 5, 5, 
+	7, 4
+};
+
+static const char _double_parser_trans_actions[] = {
+	0, 0, 1, 0, 2, 3, 0, 4, 
+	5, 0
+};
+
+static const int double_parser_start = 1;
+static const int double_parser_first_final = 6;
+static const int double_parser_error = 0;
+
+static const int double_parser_en_main = 1;
+
+
+#line 70 "hb-number-parser.rl"
+
+
+/* Works only for n < 512 */
+static inline double
+_pow10 (unsigned int exponent)
+{
+  static const double _powers_of_10[] =
+  {
+    1.0e+256,
+    1.0e+128,
+    1.0e+64,
+    1.0e+32,
+    1.0e+16,
+    1.0e+8,
+    10000.,
+    100.,
+    10.
+  };
+  unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
+  double result = 1;
+  for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
+    if (exponent & mask) result *= *power;
+  return result;
+}
+
+static inline double
+strtod_rl (const char *buf, char **end_ptr)
+{
+  const char *p, *pe;
+  double value = 0;
+  double frac = 0;
+  double frac_count = 0;
+  unsigned int exp = 0;
+  bool neg = false, exp_neg = false, exp_overflow = false;
+  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
+  const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
+  p = buf;
+  pe = p + strlen (p);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+
+  int cs;
+  
+#line 142 "hb-number-parser.hh"
+	{
+	cs = double_parser_start;
+	}
+
+#line 147 "hb-number-parser.hh"
+	{
+	int _slen;
+	int _trans;
+	const unsigned char *_keys;
+	const char *_inds;
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _double_parser_trans_keys + (cs<<1);
+	_inds = _double_parser_indicies + _double_parser_index_offsets[cs];
+
+	_slen = _double_parser_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+		(*p) <= _keys[1] ?
+		(*p) - _keys[0] : _slen ];
+
+	cs = _double_parser_trans_targs[_trans];
+
+	if ( _double_parser_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _double_parser_trans_actions[_trans] ) {
+	case 1:
+#line 39 "hb-number-parser.rl"
+	{ neg = true; }
+	break;
+	case 4:
+#line 40 "hb-number-parser.rl"
+	{ exp_neg = true; }
+	break;
+	case 2:
+#line 42 "hb-number-parser.rl"
+	{
+	value = value * 10. + ((*p) - '0');
+}
+	break;
+	case 3:
+#line 45 "hb-number-parser.rl"
+	{
+	if (likely (frac <= MAX_FRACT / 10))
+	{
+	  frac = frac * 10. + ((*p) - '0');
+	  ++frac_count;
+	}
+}
+	break;
+	case 5:
+#line 52 "hb-number-parser.rl"
+	{
+	if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
+	  exp = exp * 10 + ((*p) - '0');
+	else
+	  exp_overflow = true;
+}
+	break;
+#line 205 "hb-number-parser.hh"
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	_out: {}
+	}
+
+#line 116 "hb-number-parser.rl"
+
+
+  *end_ptr = (char *) p;
+
+  if (frac_count) value += frac / _pow10 (frac_count);
+  if (neg) value *= -1.;
+
+  if (unlikely (exp_overflow))
+  {
+    if (value == 0) return value;
+    if (exp_neg)    return neg ? -DBL_MIN : DBL_MIN;
+    else            return neg ? -DBL_MAX : DBL_MAX;
+  }
+
+  if (exp)
+  {
+    if (exp_neg) value /= _pow10 (exp);
+    else         value *= _pow10 (exp);
+  }
+
+  return value;
+}
+
+#endif /* HB_NUMBER_PARSER_HH */
diff --git a/src/hb-number-parser.rl b/src/hb-number-parser.rl
new file mode 100644
index 0000000..8445fa2
--- /dev/null
+++ b/src/hb-number-parser.rl
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#ifndef HB_NUMBER_PARSER_HH
+#define HB_NUMBER_PARSER_HH
+
+#include "hb.hh"
+
+#include <float.h>
+
+%%{
+
+machine double_parser;
+alphtype unsigned char;
+write data;
+
+action see_neg { neg = true; }
+action see_exp_neg { exp_neg = true; }
+
+action add_int  {
+	value = value * 10. + (fc - '0');
+}
+action add_frac {
+	if (likely (frac <= MAX_FRACT / 10))
+	{
+	  frac = frac * 10. + (fc - '0');
+	  ++frac_count;
+	}
+}
+action add_exp  {
+	if (likely (exp * 10 + (fc - '0') <= MAX_EXP))
+	  exp = exp * 10 + (fc - '0');
+	else
+	  exp_overflow = true;
+}
+
+num = [0-9]+;
+
+main := (
+	(
+		(('+'|'-'@see_neg)? num @add_int) ('.' num @add_frac)?
+		|
+		(('+'|'-'@see_neg)? '.' num @add_frac)
+	)
+	(('e'|'E') (('+'|'-'@see_exp_neg)? num @add_exp))?
+);
+
+}%%
+
+/* Works only for n < 512 */
+static inline double
+_pow10 (unsigned int exponent)
+{
+  static const double _powers_of_10[] =
+  {
+    1.0e+256,
+    1.0e+128,
+    1.0e+64,
+    1.0e+32,
+    1.0e+16,
+    1.0e+8,
+    10000.,
+    100.,
+    10.
+  };
+  unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
+  double result = 1;
+  for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
+    if (exponent & mask) result *= *power;
+  return result;
+}
+
+static inline double
+strtod_rl (const char *buf, char **end_ptr)
+{
+  const char *p, *pe;
+  double value = 0;
+  double frac = 0;
+  double frac_count = 0;
+  unsigned int exp = 0;
+  bool neg = false, exp_neg = false, exp_overflow = false;
+  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
+  const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */
+  p = buf;
+  pe = p + strlen (p);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+
+  int cs;
+  %%{
+    write init;
+    write exec;
+  }%%
+
+  *end_ptr = (char *) p;
+
+  if (frac_count) value += frac / _pow10 (frac_count);
+  if (neg) value *= -1.;
+
+  if (unlikely (exp_overflow))
+  {
+    if (value == 0) return value;
+    if (exp_neg)    return neg ? -DBL_MIN : DBL_MIN;
+    else            return neg ? -DBL_MAX : DBL_MAX;
+  }
+
+  if (exp)
+  {
+    if (exp_neg) value /= _pow10 (exp);
+    else         value *= _pow10 (exp);
+  }
+
+  return value;
+}
+
+#endif /* HB_NUMBER_PARSER_HH */
diff --git a/src/hb-number.cc b/src/hb-number.cc
new file mode 100644
index 0000000..4f84d4a
--- /dev/null
+++ b/src/hb-number.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include "hb.hh"
+#include "hb-machinery.hh"
+#include "hb-number-parser.hh"
+
+#include <locale.h>
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
+
+template<typename T, typename Func>
+static bool
+_parse_number (const char **pp, const char *end, T *pv,
+	       bool whole_buffer, Func f)
+{
+  char buf[32];
+  unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1,
+			     (unsigned int) (end - *pp));
+  strncpy (buf, *pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+
+  errno = 0;
+  *pv = f (p, &pend);
+  if (unlikely (errno || p == pend ||
+		/* Check if consumed whole buffer if is requested */
+		(whole_buffer && pend - p != end - *pp))) return false;
+
+  *pp += pend - p;
+  return true;
+}
+
+bool
+hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
+{
+  return _parse_number<int> (pp, end, pv, whole_buffer,
+			     [] (const char *p, char **end)
+			     { return strtol (p, end, 10); });
+}
+
+bool
+hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
+	       bool whole_buffer, int base)
+{
+  return _parse_number<unsigned int> (pp, end, pv, whole_buffer,
+				      [base] (const char *p, char **end)
+				      { return strtoul (p, end, base); });
+}
+
+
+#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
+#define USE_XLOCALE 1
+#define HB_LOCALE_T locale_t
+#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
+#define HB_FREE_LOCALE(loc) freelocale (loc)
+#elif defined(_MSC_VER)
+#define USE_XLOCALE 1
+#define HB_LOCALE_T _locale_t
+#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
+#define HB_FREE_LOCALE(loc) _free_locale (loc)
+#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
+#endif
+
+#ifdef USE_XLOCALE
+
+#if HB_USE_ATEXIT
+static void free_static_C_locale ();
+#endif
+
+static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<HB_LOCALE_T>,
+							  hb_C_locale_lazy_loader_t>
+{
+  static HB_LOCALE_T create ()
+  {
+    HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
+
+#if HB_USE_ATEXIT
+    atexit (free_static_C_locale);
+#endif
+
+    return C_locale;
+  }
+  static void destroy (HB_LOCALE_T p)
+  {
+    HB_FREE_LOCALE (p);
+  }
+  static HB_LOCALE_T get_null ()
+  {
+    return nullptr;
+  }
+} static_C_locale;
+
+#if HB_USE_ATEXIT
+static
+void free_static_C_locale ()
+{
+  static_C_locale.free_instance ();
+}
+#endif
+
+static HB_LOCALE_T
+get_C_locale ()
+{
+  return static_C_locale.get_unconst ();
+}
+#endif /* USE_XLOCALE */
+
+bool
+hb_parse_double (const char **pp, const char *end, double *pv,
+		 bool whole_buffer)
+{
+  return _parse_number<double> (pp, end, pv, whole_buffer,
+				[] (const char *p, char **end)
+				{
+#ifdef USE_XLOCALE
+				  return strtod_l (p, end, get_C_locale ());
+#else
+				  return strtod_rl (p, end);
+#endif
+				});
+}
diff --git a/src/hb-subset-glyf.hh b/src/hb-number.hh
similarity index 70%
copy from src/hb-subset-glyf.hh
copy to src/hb-number.hh
index 99cf8f0..14d1260 100644
--- a/src/hb-subset-glyf.hh
+++ b/src/hb-number.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -21,20 +21,21 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Garret Rieger
  */
 
-#ifndef HB_SUBSET_GLYF_HH
-#define HB_SUBSET_GLYF_HH
-
-#include "hb.hh"
-
-#include "hb-subset.hh"
+#ifndef HB_NUMBER_HH
+#define HB_NUMBER_HH
 
 HB_INTERNAL bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-			 bool             *use_short_loca, /* OUT */
-			 hb_blob_t       **glyf_prime      /* OUT */,
-			 hb_blob_t       **loca_prime      /* OUT */);
+hb_parse_int (const char **pp, const char *end, int *pv,
+	      bool whole_buffer = false);
 
-#endif /* HB_SUBSET_GLYF_HH */
+HB_INTERNAL bool
+hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
+	       bool whole_buffer = false, int base = 10);
+
+HB_INTERNAL bool
+hb_parse_double (const char **pp, const char *end, double *pv,
+		 bool whole_buffer = false);
+
+#endif /* HB_NUMBER_HH */
diff --git a/src/hb-object.hh b/src/hb-object.hh
index 6eb1173..c470532 100644
--- a/src/hb-object.hh
+++ b/src/hb-object.hh
@@ -45,7 +45,7 @@
 template <typename item_t, typename lock_t>
 struct hb_lockable_set_t
 {
-  hb_vector_t <item_t, 1> items;
+  hb_vector_t<item_t> items;
 
   void init () { items.init (); }
 
@@ -62,7 +62,7 @@
 	old.fini ();
       }
       else {
-        item = nullptr;
+	item = nullptr;
 	l.unlock ();
       }
     } else {
@@ -77,9 +77,10 @@
   {
     l.lock ();
     item_t *item = items.find (v);
-    if (item) {
+    if (item)
+    {
       item_t old = *item;
-      *item = items[items.len - 1];
+      *item = items[items.length - 1];
       items.pop ();
       l.unlock ();
       old.fini ();
@@ -113,18 +114,20 @@
 
   void fini (lock_t &l)
   {
-    if (!items.len) {
-      /* No need for locking. */
+    if (!items.length)
+    {
+      /* No need to lock. */
       items.fini ();
       return;
     }
     l.lock ();
-    while (items.len) {
-      item_t old = items[items.len - 1];
-	items.pop ();
-	l.unlock ();
-	old.fini ();
-	l.lock ();
+    while (items.length)
+    {
+      item_t old = items[items.length - 1];
+      items.pop ();
+      l.unlock ();
+      old.fini ();
+      l.lock ();
     }
     items.fini ();
     l.unlock ();
diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh
index 822a92d..cb1fdf1 100644
--- a/src/hb-open-file.hh
+++ b/src/hb-open-file.hh
@@ -56,7 +56,7 @@
 {
   int cmp (Tag t) const { return -t.cmp (tag); }
 
-  static int cmp (const void *pa, const void *pb)
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
   {
     const TableRecord *a = (const TableRecord *) pa;
     const TableRecord *b = (const TableRecord *) pb;
@@ -86,15 +86,15 @@
   const TableRecord& get_table (unsigned int i) const
   { return tables[i]; }
   unsigned int get_table_tags (unsigned int  start_offset,
-				      unsigned int *table_count, /* IN/OUT */
-				      hb_tag_t     *table_tags /* OUT */) const
+			       unsigned int *table_count, /* IN/OUT */
+			       hb_tag_t     *table_tags /* OUT */) const
   {
     if (table_count)
     {
       if (start_offset >= tables.len)
-        *table_count = 0;
+	*table_count = 0;
       else
-        *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
+	*table_count = hb_min (*table_count, tables.len - start_offset);
 
       const TableRecord *sub_tables = tables.arrayZ + start_offset;
       unsigned int count = *table_count;
@@ -106,7 +106,7 @@
   bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
   {
     Tag t;
-    t.set (tag);
+    t = tag;
     return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
   }
   const TableRecord& get_table_by_tag (hb_tag_t tag) const
@@ -127,10 +127,10 @@
     /* Alloc 12 for the OTHeader. */
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     /* Write sfntVersion (bytes 0..3). */
-    sfnt_version.set (sfnt_tag);
+    sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
-    if (unlikely (!tables.serialize (c, items.len))) return_trace (false);
+    if (unlikely (!tables.serialize (c, items.length))) return_trace (false);
 
     const char *dir_end = (const char *) c->head;
     HBUINT32 *checksum_adjustment = nullptr;
@@ -140,25 +140,27 @@
     {
       TableRecord &rec = tables.arrayZ[i];
       hb_blob_t *blob = items[i].blob;
-      rec.tag.set (items[i].tag);
-      rec.length.set (hb_blob_get_length (blob));
+      rec.tag = items[i].tag;
+      rec.length = blob->length;
       rec.offset.serialize (c, this);
 
       /* Allocate room for the table and copy it. */
       char *start = (char *) c->allocate_size<void> (rec.length);
-      if (unlikely (!start)) {return false;}
+      if (unlikely (!start)) return false;
 
-      memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
+      if (likely (rec.length))
+	memcpy (start, blob->data, rec.length);
 
       /* 4-byte alignment. */
       c->align (4);
       const char *end = (const char *) c->head;
 
-      if (items[i].tag == HB_OT_TAG_head && end - start >= head::static_size)
+      if (items[i].tag == HB_OT_TAG_head &&
+	  (unsigned) (end - start) >= head::static_size)
       {
 	head *h = (head *) start;
 	checksum_adjustment = &h->checkSumAdjustment;
-	checksum_adjustment->set (0);
+	*checksum_adjustment = 0;
       }
 
       rec.checkSum.set_for_data (start, end - start);
@@ -173,13 +175,13 @@
       /* The following line is a slower version of the following block. */
       //checksum.set_for_data (this, (const char *) c->head - (const char *) this);
       checksum.set_for_data (this, dir_end - (const char *) this);
-      for (unsigned int i = 0; i < items.len; i++)
+      for (unsigned int i = 0; i < items.length; i++)
       {
 	TableRecord &rec = tables.arrayZ[i];
-	checksum.set (checksum + rec.checkSum);
+	checksum = checksum + rec.checkSum;
       }
 
-      checksum_adjustment->set (0xB1B0AFBAu - checksum);
+      *checksum_adjustment = 0xB1B0AFBAu - checksum;
     }
 
     return_trace (true);
@@ -221,7 +223,7 @@
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  LArrayOf<LOffsetTo<OffsetTable> >
+  LArrayOf<LOffsetTo<OffsetTable>>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
@@ -285,7 +287,7 @@
   { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); }
 
   bool sanitize (hb_sanitize_context_t *c,
-			const void *data_base) const
+		 const void *data_base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
@@ -298,7 +300,7 @@
   HBINT16	nameOffset;	/* Offset from beginning of resource name list
 				 * to resource name, -1 means there is none. */
   HBUINT8	attrs;		/* Resource attributes */
-  OffsetTo<LArrayOf<HBUINT8>, HBUINT24, false>
+  NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24>
 		offset;		/* Offset from beginning of data block to
 				 * data for this resource */
   HBUINT32	reserved;	/* Reserved for handle to resource */
@@ -333,7 +335,7 @@
   protected:
   Tag		tag;		/* Resource type. */
   HBUINT16	resCountM1;	/* Number of resources minus 1. */
-  OffsetTo<UnsizedArrayOf<ResourceRecord>, HBUINT16, false>
+  NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
 		resourcesZ;	/* Offset from beginning of resource type list
 				 * to reference item list for this type. */
   public:
@@ -389,7 +391,7 @@
   HBUINT32	reserved1;	/* Reserved for handle to next resource map */
   HBUINT16	resreved2;	/* Reserved for file reference number */
   HBUINT16	attrs;		/* Resource fork attribute */
-  OffsetTo<ArrayOfM1<ResourceTypeRecord>, HBUINT16, false>
+  NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
 		typeList;	/* Offset from beginning of map to
 				 * resource type list */
   Offset16	nameList;	/* Offset from beginning of map to
@@ -421,10 +423,10 @@
   }
 
   protected:
-  LOffsetTo<UnsizedArrayOf<HBUINT8>, false>
+  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
 		data;		/* Offset from beginning of resource fork
 				 * to resource data */
-  LOffsetTo<ResourceMap, false>
+  LNNOffsetTo<ResourceMap >
 		map;		/* Offset from beginning of resource fork
 				 * to resource map */
   HBUINT32	dataLen;	/* Length of resource data */
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 7f88279..af242ec 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -52,22 +52,27 @@
  * Int types
  */
 
-template <bool is_signed> struct hb_signedness_int;
-template <> struct hb_signedness_int<false> { typedef unsigned int value; };
-template <> struct hb_signedness_int<true>  { typedef   signed int value; };
-
 /* Integer types in big-endian order and no alignment requirement */
 template <typename Type, unsigned int Size>
 struct IntType
 {
   typedef Type type;
-  typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type;
+  typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
 
-  void set (wide_type i) { v.set (i); }
+  IntType& operator = (wide_type i) { v = i; return *this; }
   operator wide_type () const { return v; }
-  bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
-  bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
-  static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
+  bool operator != (const IntType &o) const { return !(*this == o); }
+
+  IntType& operator += (unsigned count) { *this = *this + count; return *this; }
+  IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
+  IntType& operator ++ () { *this += 1; return *this; }
+  IntType& operator -- () { *this -= 1; return *this; }
+  IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
+  IntType operator -- (int) { IntType c (*this); --*this; return c; }
+
+  HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
+  { return b->cmp (*a); }
   template <typename Type2>
   int cmp (Type2 a) const
   {
@@ -110,19 +115,21 @@
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
 struct F2DOT14 : HBINT16
 {
+  F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
   // 16384 means 1<<14
   float to_float () const  { return ((int32_t) v) / 16384.f; }
-  void set_float (float f) { v.set (round (f * 16384.f)); }
+  void set_float (float f) { v = roundf (f * 16384.f); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed : HBINT32
+struct HBFixed : HBINT32
 {
+  HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
   // 65536 means 1<<16
   float to_float () const  { return ((int32_t) v) / 65536.f; }
-  void set_float (float f) { v.set (round (f * 65536.f)); }
+  void set_float (float f) { v = roundf (f * 65536.f); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -147,6 +154,7 @@
  * system, feature, or baseline */
 struct Tag : HBUINT32
 {
+  Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
   operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
   operator char* ()             { return reinterpret_cast<char *> (&this->v); }
@@ -155,11 +163,15 @@
 };
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef HBUINT16 GlyphID;
+struct HBGlyphID : HBUINT16
+{
+  HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
-  enum { NOT_FOUND_INDEX = 0xFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
+  Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
 
@@ -169,6 +181,8 @@
 template <typename Type, bool has_null=true>
 struct Offset : Type
 {
+  Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
+
   typedef Type type;
 
   bool is_null () const { return has_null && 0 == *this; }
@@ -176,7 +190,7 @@
   void *serialize (hb_serialize_context_t *c, const void *base)
   {
     void *t = c->start_embed<void> ();
-    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+    c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
     return t;
   }
 
@@ -191,6 +205,8 @@
 /* CheckSum */
 struct CheckSum : HBUINT32
 {
+  CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
+
   /* This is reference implementation from the spec. */
   static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
   {
@@ -205,7 +221,7 @@
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
   void set_for_data (const void *data, unsigned int length)
-  { set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
+  { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
 
   public:
   DEFINE_SIZE_STATIC (4);
@@ -248,13 +264,18 @@
 template <typename Type>
 struct _hb_has_null<Type, true>
 {
-  static const Type *get_null () { return &Null(Type); }
-  static Type *get_crap ()       { return &Crap(Type); }
+  static const Type *get_null () { return &Null (Type); }
+  static       Type *get_crap () { return &Crap (Type); }
 };
 
 template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
+  HB_DELETE_COPY_ASSIGN (OffsetTo);
+  OffsetTo () = default;
+
+  OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
+
   const Type& operator () (const void *base) const
   {
     if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
@@ -266,22 +287,68 @@
     return StructAtOffset<Type> (base, *this);
   }
 
+  template <typename Base,
+	    hb_enable_if (hb_is_convertible (const Base, const void *))>
+  friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
+  template <typename Base,
+	    hb_enable_if (hb_is_convertible (const Base, const void *))>
+  friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
+  template <typename Base,
+	    hb_enable_if (hb_is_convertible (Base, void *))>
+  friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
+  template <typename Base,
+	    hb_enable_if (hb_is_convertible (Base, void *))>
+  friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
+
   Type& serialize (hb_serialize_context_t *c, const void *base)
   {
     return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
-  template <typename T>
-  void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+  template <typename ...Ts>
+  bool serialize_subset (hb_subset_context_t *c,
+			 const OffsetTo& src,
+			 const void *src_base,
+			 const void *dst_base,
+			 Ts&&... ds)
   {
-    if (&src == &Null (T))
-    {
-      this->set (0);
-      return;
-    }
-    serialize (c->serializer, base);
-    if (!src.subset (c))
-      this->set (0);
+    *this = 0;
+    if (src.is_null ())
+      return false;
+
+    auto *s = c->serializer;
+
+    s->push ();
+
+    bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
+
+    if (ret || !has_null)
+      s->add_link (*this, s->pop_pack (), dst_base);
+    else
+      s->pop_discard ();
+
+    return ret;
+  }
+
+  /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
+  template <typename ...Ts>
+  bool serialize_copy (hb_serialize_context_t *c,
+		       const OffsetTo& src,
+		       const void *src_base,
+		       const void *dst_base,
+		       Ts&&... ds)
+  {
+    *this = 0;
+    if (src.is_null ())
+      return false;
+
+    c->push ();
+
+    bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
+
+    c->add_link (*this, c->pop_pack (), dst_base);
+
+    return ret;
   }
 
   bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
@@ -293,39 +360,13 @@
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     return_trace (sanitize_shallow (c, base) &&
 		  (this->is_null () ||
-		   StructAtOffset<Type> (base, *this).sanitize (c) ||
-		   neuter (c)));
-  }
-  template <typename T1>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-		  (this->is_null () ||
-		   StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
-		   neuter (c)));
-  }
-  template <typename T1, typename T2>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-		  (this->is_null () ||
-		   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
-		   neuter (c)));
-  }
-  template <typename T1, typename T2, typename T3>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-		  (this->is_null () ||
-		   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
+		   c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
 		   neuter (c)));
   }
 
@@ -337,12 +378,13 @@
   }
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
-template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {};
-
-template <typename Base, typename OffsetType, bool has_null, typename Type>
-static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
-template <typename Base, typename OffsetType, bool has_null, typename Type>
-static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
+/* Partial specializations. */
+template <typename Type, bool has_null=true>
+using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
+template <typename Type, typename OffsetType=HBUINT16>
+using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
+template <typename Type>
+using LNNOffsetTo = LOffsetTo<Type, false>;
 
 
 /*
@@ -352,10 +394,10 @@
 template <typename Type>
 struct UnsizedArrayOf
 {
-  typedef Type ItemType;
-  enum { item_size = hb_static_size (Type) };
+  typedef Type item_t;
+  static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
+  HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -381,7 +423,7 @@
   { return hb_array (arrayZ, len); }
   hb_array_t<const Type> as_array (unsigned int len) const
   { return hb_array (arrayZ, len); }
-  operator hb_array_t<Type> ()             { return as_array (); }
+  operator hb_array_t<      Type> ()       { return as_array (); }
   operator hb_array_t<const Type> () const { return as_array (); }
 
   template <typename T>
@@ -394,38 +436,42 @@
   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array (len).qsort (start, end); }
 
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend (*this, items_len))) return_trace (false);
     return_trace (true);
   }
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base)))
-	return_trace (false);
+    TRACE_SERIALIZE (this);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
+
+  UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
+    return_trace (out);
+  }
+
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -437,14 +483,14 @@
   }
 
   public:
-  Type		arrayZ[VAR];
+  Type		arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_UNBOUNDED (0);
 };
 
 /* Unsized array of offset's */
 template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
+using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
 template <typename Type, typename OffsetType, bool has_null=true>
@@ -465,17 +511,12 @@
     return this+*p;
   }
 
-
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
+		   ::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
   }
 };
 
@@ -508,10 +549,10 @@
 template <typename Type, typename LenType=HBUINT16>
 struct ArrayOf
 {
-  typedef Type ItemType;
-  enum { item_size = hb_static_size (Type) };
+  typedef Type item_t;
+  static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -529,74 +570,83 @@
   unsigned int get_size () const
   { return len.static_size + len * Type::static_size; }
 
-  hb_array_t<Type> as_array ()
-  { return hb_array (arrayZ, len); }
-  hb_array_t<const Type> as_array () const
-  { return hb_array (arrayZ, len); }
-  operator hb_array_t<Type> (void)             { return as_array (); }
-  operator hb_array_t<const Type> (void) const { return as_array (); }
+  explicit operator bool () const { return len; }
+
+  void pop () { len--; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, len); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
 
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
 
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    len.set (items_len); /* TODO(serialize) Overflow? */
+    c->check_assign (len, items_len);
     if (unlikely (!c->extend (*this))) return_trace (false);
     return_trace (true);
   }
-  template <typename T>
-  bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items)
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!serialize (c, items.len))) return_trace (false);
-    for (unsigned int i = 0; i < items.len; i++)
-      hb_assign (arrayZ[i], items[i]);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  Type* serialize_append (hb_serialize_context_t *c)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
-    return_trace (true);
+    TRACE_SERIALIZE (this);
+    len++;
+    if (unlikely (!len || !c->extend (*this)))
+    {
+      len--;
+      return_trace (nullptr);
+    }
+    return_trace (&arrayZ[len - 1]);
   }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+
+  ArrayOf* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!c->extend_min (out))) return_trace (nullptr);
+    c->check_assign (out->len, len);
+    if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
+    return_trace (out);
+  }
+
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base)))
-	return_trace (false);
-    return_trace (true);
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -619,20 +669,21 @@
 
   public:
   LenType	len;
-  Type		arrayZ[VAR];
+  Type		arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
-template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
-typedef ArrayOf<HBUINT8, HBUINT8> PString;
+template <typename Type>
+using LArrayOf = ArrayOf<Type, HBUINT32>;
+using PString = ArrayOf<HBUINT8, HBUINT8>;
 
 /* Array of Offset's */
 template <typename Type>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
+using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
 template <typename Type>
-struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
+using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
 template <typename Type>
-struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
+using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
@@ -658,20 +709,15 @@
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
-      out->arrayZ[i].serialize_subset (c, (*this)[i], out);
+      out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this));
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
   }
 };
 
@@ -679,9 +725,9 @@
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -696,34 +742,53 @@
     return arrayZ[i-1];
   }
   unsigned int get_size () const
-  { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
+  { return lenP1.static_size + get_length () * Type::static_size; }
 
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const Type> items)
+  unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, get_length ()); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
+
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    lenP1.set (items.len + 1); /* TODO(serialize) Overflow? */
+    c->check_assign (lenP1, items_len + 1);
     if (unlikely (!c->extend (*this))) return_trace (false);
-    for (unsigned int i = 0; i < items.len; i++)
-      arrayZ[i] = items[i];
+    return_trace (true);
+  }
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    unsigned int count = get_length ();
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+	return_trace (false);
     return_trace (true);
   }
 
@@ -737,7 +802,7 @@
 
   public:
   LenType	lenP1;
-  Type		arrayZ[VAR];
+  Type		arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
@@ -746,7 +811,7 @@
 template <typename Type, typename LenType=HBUINT16>
 struct ArrayOfM1
 {
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
 
   const Type& operator [] (int i_) const
   {
@@ -763,14 +828,14 @@
   unsigned int get_size () const
   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
 
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = lenM1 + 1;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
@@ -785,7 +850,7 @@
 
   public:
   LenType	lenM1;
-  Type		arrayZ[VAR];
+  Type		arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
@@ -794,21 +859,40 @@
 template <typename Type, typename LenType=HBUINT16>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
-  hb_sorted_array_t<Type> as_array ()
-  { return hb_sorted_array (this->arrayZ, this->len); }
-  hb_sorted_array_t<const Type> as_array () const
-  { return hb_sorted_array (this->arrayZ, this->len); }
-  operator hb_sorted_array_t<Type> ()             { return as_array (); }
-  operator hb_sorted_array_t<const Type> () const { return as_array (); }
+  hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
+  hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
 
-  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  /* Iterator. */
+  typedef hb_sorted_array_t<const Type>   iter_t;
+  typedef hb_sorted_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
+
+  hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count); }
+
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
+    return_trace (ret);
+  }
+  template <typename Iterator,
+	    hb_requires (hb_is_sorted_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
+  {
+    TRACE_SERIALIZE (this);
+    bool ret = ArrayOf<Type, LenType>::serialize (c, items);
+    return_trace (ret);
+  }
 
   template <typename T>
   Type &bsearch (const T &x, Type &not_found = Crap (Type))
@@ -818,8 +902,8 @@
   { return *as_array ().bsearch (x, &not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-		     unsigned int to_store = (unsigned int) -1) const
+	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
   { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
@@ -838,15 +922,16 @@
     return_trace (c->check_struct (this));
   }
 
-  void set (unsigned int v)
+  BinSearchHeader& operator = (unsigned int v)
   {
-    len.set (v);
+    len = v;
     assert (len == v);
-    entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
-    searchRange.set (16 * (1u << entrySelector));
-    rangeShift.set (v * 16 > searchRange
-		    ? 16 * v - searchRange
-		    : 0);
+    entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
+    searchRange = 16 * (1u << entrySelector);
+    rangeShift = v * 16 > searchRange
+		 ? 16 * v - searchRange
+		 : 0;
+    return *this;
   }
 
   protected:
@@ -860,7 +945,7 @@
 };
 
 template <typename Type, typename LenType=HBUINT16>
-struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
+using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
 
 
 struct VarSizedBinSearchHeader
@@ -888,9 +973,9 @@
 template <typename Type>
 struct VarSizedBinSearchArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
+  HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
 
   bool last_is_terminator () const
   {
@@ -904,7 +989,7 @@
     unsigned int count = Type::TerminationWordCount;
     for (unsigned int i = 0; i < count; i++)
       if (words[i] != 0xFFFFu)
-        return false;
+	return false;
     return true;
   }
 
@@ -925,40 +1010,15 @@
   unsigned int get_size () const
   { return header.static_size + header.nUnits * header.unitSize; }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
-
-    return_trace (true);
-  }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(*this)[i].sanitize (c, base)))
-	return_trace (false);
-    return_trace (true);
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = get_length ();
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
+      if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
 	return_trace (false);
     return_trace (true);
   }
diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh
index db04b3e..6735c74 100644
--- a/src/hb-ot-cff-common.hh
+++ b/src/hb-ot-cff-common.hh
@@ -27,6 +27,7 @@
 #define HB_OT_CFF_COMMON_HH
 
 #include "hb-open-type.hh"
+#include "hb-bimap.hh"
 #include "hb-ot-layout-common.hh"
 #include "hb-cff-interp-dict-common.hh"
 #include "hb-subset-plan.hh"
@@ -39,14 +40,14 @@
 
 /* utility macro */
 template<typename Type>
-static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
-{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
+static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
+{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
 
-inline unsigned int calcOffSize(unsigned int dataSize)
+inline unsigned int calcOffSize (unsigned int dataSize)
 {
   unsigned int size = 1;
   unsigned int offset = dataSize + 1;
-  while ((offset & ~0xFF) != 0)
+  while (offset & ~0xFF)
   {
     size++;
     offset >>= 8;
@@ -55,54 +56,44 @@
   return size;
 }
 
-struct code_pair
+struct code_pair_t
 {
-  hb_codepoint_t  code;
-  hb_codepoint_t  glyph;
+  hb_codepoint_t code;
+  hb_codepoint_t glyph;
 };
 
-typedef hb_vector_t<char, 1> StrBuff;
-struct StrBuffArray : hb_vector_t<StrBuff>
+typedef hb_vector_t<unsigned char> str_buff_t;
+struct str_buff_vec_t : hb_vector_t<str_buff_t>
 {
   void fini () { SUPER::fini_deep (); }
 
   unsigned int total_size () const
   {
     unsigned int size = 0;
-    for (unsigned int i = 0; i < len; i++)
-      size += (*this)[i].len;
+    for (unsigned int i = 0; i < length; i++)
+      size += (*this)[i].length;
     return size;
   }
 
   private:
-  typedef hb_vector_t<StrBuff> SUPER;
+  typedef hb_vector_t<str_buff_t> SUPER;
 };
 
 /* CFF INDEX */
 template <typename COUNT>
 struct CFFIndex
 {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
-			  (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
-			   c->check_array (offsets, offSize, count + 1) &&
-			   c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
-  }
-
   static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
   { return offSize * (count + 1); }
 
   unsigned int offset_array_size () const
   { return calculate_offset_array_size (offSize, count); }
 
-  static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
+  static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count,
+						 unsigned int dataSize)
   {
-    if (count == 0)
-      return COUNT::static_size;
-    else
-      return min_size + calculate_offset_array_size (offSize, count) + dataSize;
+    if (count == 0) return COUNT::static_size;
+    return min_size + calculate_offset_array_size (offSize_, count) + dataSize;
   }
 
   bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
@@ -117,28 +108,28 @@
 
   bool serialize (hb_serialize_context_t *c,
 		  unsigned int offSize_,
-		  const ByteStrArray &byteArray)
+		  const byte_str_array_t &byteArray)
   {
     TRACE_SERIALIZE (this);
-    if (byteArray.len == 0)
+    if (byteArray.length == 0)
     {
       COUNT *dest = c->allocate_min<COUNT> ();
       if (unlikely (dest == nullptr)) return_trace (false);
-      dest->set (0);
+      *dest = 0;
     }
     else
     {
       /* serialize CFFIndex header */
       if (unlikely (!c->extend_min (*this))) return_trace (false);
-      this->count.set (byteArray.len);
-      this->offSize.set (offSize_);
-      if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
+      this->count = byteArray.length;
+      this->offSize = offSize_;
+      if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
 	return_trace (false);
 
       /* serialize indices */
       unsigned int  offset = 1;
       unsigned int  i = 0;
-      for (; i < byteArray.len; i++)
+      for (; i < byteArray.length; i++)
       {
 	set_offset_at (i, offset);
 	offset += byteArray[i].get_size ();
@@ -146,12 +137,13 @@
       set_offset_at (i, offset);
 
       /* serialize data */
-      for (unsigned int i = 0; i < byteArray.len; i++)
+      for (unsigned int i = 0; i < byteArray.length; i++)
       {
-	ByteStr  *dest = c->start_embed<ByteStr> ();
-	if (unlikely (dest == nullptr ||
-		      !dest->serialize (c, byteArray[i])))
+      	const byte_str_t &bs = byteArray[i];
+	unsigned char  *dest = c->allocate_size<unsigned char> (bs.length);
+	if (unlikely (dest == nullptr))
 	  return_trace (false);
+	memcpy (dest, &bs[0], bs.length);
       }
     }
     return_trace (true);
@@ -159,15 +151,13 @@
 
   bool serialize (hb_serialize_context_t *c,
 		  unsigned int offSize_,
-		  const StrBuffArray &buffArray)
+		  const str_buff_vec_t &buffArray)
   {
-    ByteStrArray  byteArray;
+    byte_str_array_t  byteArray;
     byteArray.init ();
-    byteArray.resize (buffArray.len);
-    for (unsigned int i = 0; i < byteArray.len; i++)
-    {
-      byteArray[i] = ByteStr (buffArray[i].arrayZ (), buffArray[i].len);
-    }
+    byteArray.resize (buffArray.length);
+    for (unsigned int i = 0; i < byteArray.length; i++)
+      byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length);
     bool result = this->serialize (c, offSize_, byteArray);
     byteArray.fini ();
     return result;
@@ -180,7 +170,7 @@
     for (; size; size--)
     {
       --p;
-      p->set (offset & 0xFF);
+      *p = offset & 0xFF;
       offset >>= 8;
     }
   }
@@ -198,37 +188,38 @@
 
   unsigned int length_at (unsigned int index) const
   {
-	if (likely ((offset_at (index + 1) >= offset_at (index)) &&
-		    (offset_at (index + 1) <= offset_at (count))))
-	  return offset_at (index + 1) - offset_at (index);
-	else
-	  return 0;
+    if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
+	          (offset_at (index + 1) > offset_at (count))))
+      return 0;
+    return offset_at (index + 1) - offset_at (index);
   }
 
-  const char *data_base () const
-  { return (const char *)this + min_size + offset_array_size (); }
+  const unsigned char *data_base () const
+  { return (const unsigned char *) this + min_size + offset_array_size (); }
 
   unsigned int data_size () const { return HBINT8::static_size; }
 
-  ByteStr operator [] (unsigned int index) const
+  byte_str_t operator [] (unsigned int index) const
   {
-    if (likely (index < count))
-      return ByteStr (data_base () + offset_at (index) - 1, length_at (index));
-    else
-      return Null(ByteStr);
+    if (unlikely (index >= count)) return Null (byte_str_t);
+    return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
   }
 
   unsigned int get_size () const
   {
-    if (this != &Null(CFFIndex))
-    {
-      if (count > 0)
-	return min_size + offset_array_size () + (offset_at (count) - 1);
-      else
-	return count.static_size;  /* empty CFFIndex contains count only */
-    }
-    else
-      return 0;
+    if (this == &Null (CFFIndex)) return 0;
+    if (count > 0)
+      return min_size + offset_array_size () + (offset_at (count) - 1);
+    return count.static_size;  /* empty CFFIndex contains count only */
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */
+			  (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
+			   c->check_array (offsets, offSize, count + 1) &&
+			   c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
   }
 
   protected:
@@ -244,10 +235,10 @@
   }
 
   public:
-  COUNT     count;	/* Number of object data. Note there are (count+1) offsets */
-  HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
-  HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
-  /* HBUINT8 data[VAR];      Object data */
+  COUNT		count;		/* Number of object data. Note there are (count+1) offsets */
+  HBUINT8	offSize;	/* The byte size of each offset in the offsets array. */
+  HBUINT8	offsets[HB_VAR_ARRAY];	/* The array of (count + 1) offsets into objects array (1-base). */
+  /* HBUINT8 data[HB_VAR_ARRAY];	Object data */
   public:
   DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
 };
@@ -255,11 +246,11 @@
 template <typename COUNT, typename TYPE>
 struct CFFIndexOf : CFFIndex<COUNT>
 {
-  const ByteStr operator [] (unsigned int index) const
+  const byte_str_t operator [] (unsigned int index) const
   {
     if (likely (index < CFFIndex<COUNT>::count))
-      return ByteStr (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
-    return Null(ByteStr);
+      return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
+    return Null(byte_str_t);
   }
 
   template <typename DATA, typename PARAM1, typename PARAM2>
@@ -274,9 +265,9 @@
     TRACE_SERIALIZE (this);
     /* serialize CFFIndex header */
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (dataArrayLen);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
+    this->count = dataArrayLen;
+    this->offSize = offSize_;
+    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
       return_trace (false);
 
     /* serialize indices */
@@ -292,7 +283,7 @@
     /* serialize data */
     for (unsigned int i = 0; i < dataArrayLen; i++)
     {
-      TYPE  *dest = c->start_embed<TYPE> ();
+      TYPE *dest = c->start_embed<TYPE> ();
       if (unlikely (dest == nullptr ||
 		    !dest->serialize (c, dataArray[i], param1, param2)))
 	return_trace (false);
@@ -309,7 +300,7 @@
 						 const PARAM &param)
   {
     /* determine offset size */
-    unsigned int  totalDataSize = 0;
+    unsigned int totalDataSize = 0;
     for (unsigned int i = 0; i < dataArrayLen; i++)
     {
       unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
@@ -333,10 +324,9 @@
   {
     TRACE_SERIALIZE (this);
     for (unsigned int i = 0; i < dictval.get_count (); i++)
-    {
       if (unlikely (!opszr.serialize (c, dictval[i], param)))
 	return_trace (false);
-    }
+
     return_trace (true);
   }
 
@@ -363,7 +353,7 @@
   }
 
   template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp)
+  static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
   {
     // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
     if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
@@ -375,36 +365,32 @@
     if (unlikely (p == nullptr)) return_trace (false);
     if (Is_OpCode_ESC (op))
     {
-      p->set (OpCode_escape);
+      *p = OpCode_escape;
       op = Unmake_OpCode_ESC (op);
       p++;
     }
-    p->set (op);
+    *p = op;
     return_trace (true);
   }
 
-  static bool serialize_uint4_op (hb_serialize_context_t *c, OpCode op, int value)
+  static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
   { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
 
-  static bool serialize_uint2_op (hb_serialize_context_t *c, OpCode op, int value)
+  static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
   { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
 
-  static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value)
-  {
-    return serialize_uint4_op (c, op, value);
-  }
+  static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
+  { return serialize_uint4_op (c, op, value); }
 
-  static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value)
-  {
-    return serialize_uint2_op (c, op, value);
-  }
+  static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
+  { return serialize_uint2_op (c, op, value); }
 };
 
 struct TopDict : Dict {};
 struct FontDict : Dict {};
 struct PrivateDict : Dict {};
 
-struct TableInfo
+struct table_info_t
 {
   void init () { offSize = offset = size = 0; }
 
@@ -413,57 +399,6 @@
   unsigned int    offSize;
 };
 
-/* used to remap font index or SID from fullset to subset.
- * set to CFF_UNDEF_CODE if excluded from subset */
-struct Remap : hb_vector_t<hb_codepoint_t>
-{
-  void init () { SUPER::init (); }
-
-  void fini () { SUPER::fini (); }
-
-  bool reset (unsigned int size)
-  {
-    if (unlikely (!SUPER::resize (size)))
-      return false;
-    for (unsigned int i = 0; i < len; i++)
-      (*this)[i] = CFF_UNDEF_CODE;
-    count = 0;
-    return true;
-  }
-
-  bool identity (unsigned int size)
-  {
-    if (unlikely (!SUPER::resize (size)))
-      return false;
-    unsigned int i;
-    for (i = 0; i < len; i++)
-      (*this)[i] = i;
-    count = i;
-    return true;
-  }
-
-  bool excludes (hb_codepoint_t id) const
-  { return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); }
-
-  bool includes (hb_codepoint_t id) const
-  { return !excludes (id); }
-
-  unsigned int add (unsigned int i)
-  {
-    if ((*this)[i] == CFF_UNDEF_CODE)
-      (*this)[i] = count++;
-    return (*this)[i];
-  }
-
-  hb_codepoint_t get_count () const { return count; }
-
-  protected:
-  hb_codepoint_t  count;
-
-  private:
-  typedef hb_vector_t<hb_codepoint_t> SUPER;
-};
-
 template <typename COUNT>
 struct FDArray : CFFIndexOf<COUNT, FontDict>
 {
@@ -476,15 +411,15 @@
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (fontDicts.len);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.len + 1))))
+    this->count = fontDicts.length;
+    this->offSize = offSize_;
+    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
       return_trace (false);
 
     /* serialize font dict offsets */
-    unsigned int  offset = 1;
+    unsigned int offset = 1;
     unsigned int fid = 0;
-    for (; fid < fontDicts.len; fid++)
+    for (; fid < fontDicts.length; fid++)
     {
       CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
       offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
@@ -492,7 +427,7 @@
     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
 
     /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.len; i++)
+    for (unsigned int i = 0; i < fontDicts.length; i++)
     {
       FontDict *dict = c->start_embed<FontDict> ();
       if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
@@ -507,31 +442,32 @@
 		  unsigned int offSize_,
 		  const hb_vector_t<DICTVAL> &fontDicts,
 		  unsigned int fdCount,
-		  const Remap &fdmap,
+		  const hb_inc_bimap_t &fdmap,
 		  OP_SERIALIZER& opszr,
-		  const hb_vector_t<TableInfo> &privateInfos)
+		  const hb_vector_t<table_info_t> &privateInfos)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (fdCount);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
+    this->count = fdCount;
+    this->offSize = offSize_;
+    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
       return_trace (false);
 
     /* serialize font dict offsets */
     unsigned int  offset = 1;
     unsigned int  fid = 0;
-    for (unsigned i = 0; i < fontDicts.len; i++)
-      if (fdmap.includes (i))
+    for (unsigned i = 0; i < fontDicts.length; i++)
+      if (fdmap.has (i))
       {
+      	if (unlikely (fid >= fdCount)) return_trace (false);
 	CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
 	offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
       }
     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
 
     /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.len; i++)
-      if (fdmap.includes (i))
+    for (unsigned int i = 0; i < fontDicts.length; i++)
+      if (fdmap.has (i))
       {
 	FontDict *dict = c->start_embed<FontDict> ();
 	if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
@@ -545,12 +481,12 @@
   static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
 						 const hb_vector_t<DICTVAL> &fontDicts,
 						 unsigned int fdCount,
-						 const Remap &fdmap,
+						 const hb_inc_bimap_t &fdmap,
 						 OP_SERIALIZER& opszr)
   {
     unsigned int dictsSize = 0;
     for (unsigned int i = 0; i < fontDicts.len; i++)
-      if (fdmap.includes (i))
+      if (fdmap.has (i))
 	dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
 
     offSize_ = calcOffSize (dictsSize);
@@ -573,50 +509,48 @@
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
-  {
-    return (hb_codepoint_t)fds[glyph];
-  }
+  { return (hb_codepoint_t) fds[glyph]; }
 
   unsigned int get_size (unsigned int num_glyphs) const
   { return HBUINT8::static_size * num_glyphs; }
 
-  HBUINT8     fds[VAR];
+  HBUINT8     fds[HB_VAR_ARRAY];
 
-  DEFINE_SIZE_MIN (1);
+  DEFINE_SIZE_MIN (0);
 };
 
 template <typename GID_TYPE, typename FD_TYPE>
-struct FDSelect3_4_Range {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
+struct FDSelect3_4_Range
+{
+  bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount)));
+    return_trace (first < c->get_num_glyphs () && (fd < fdcount));
   }
 
   GID_TYPE    first;
   FD_TYPE     fd;
-
+  public:
   DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
 };
 
 template <typename GID_TYPE, typename FD_TYPE>
-struct FDSelect3_4 {
+struct FDSelect3_4
+{
   unsigned int get_size () const
-  { return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; }
+  { return GID_TYPE::static_size * 2 + ranges.get_size (); }
 
   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
+    if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) ||
+    		  (nRanges () == 0) || ranges[0].first != 0))
       return_trace (false);
 
-    for (unsigned int i = 0; i < nRanges; i++)
-    {
-      if (unlikely (!ranges[i].sanitize (c, fdcount)))
+    for (unsigned int i = 1; i < nRanges (); i++)
+      if (unlikely (ranges[i - 1].first >= ranges[i].first))
 	return_trace (false);
-      if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first))
-	return_trace (false);
-    }
+
     if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
       return_trace (false);
 
@@ -626,18 +560,19 @@
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
   {
     unsigned int i;
-    for (i = 1; i < nRanges; i++)
+    for (i = 1; i < nRanges (); i++)
       if (glyph < ranges[i].first)
 	break;
 
-    return (hb_codepoint_t)ranges[i - 1].fd;
+    return (hb_codepoint_t) ranges[i - 1].fd;
   }
 
-  GID_TYPE &sentinel ()  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
-  const GID_TYPE &sentinel () const  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
+  GID_TYPE        &nRanges ()       { return ranges.len; }
+  GID_TYPE         nRanges () const { return ranges.len; }
+  GID_TYPE       &sentinel ()       { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
+  const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
 
-  GID_TYPE	 nRanges;
-  FDSelect3_4_Range<GID_TYPE, FD_TYPE>  ranges[VAR];
+  ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
   /* GID_TYPE sentinel */
 
   DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges);
@@ -646,17 +581,8 @@
 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
 
-struct FDSelect {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
-  {
-    TRACE_SANITIZE (this);
-
-    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
-			  (format == 0)?
-			  u.format0.sanitize (c, fdcount):
-			  u.format3.sanitize (c, fdcount)));
-  }
-
+struct FDSelect
+{
   bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
@@ -672,30 +598,46 @@
 
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = format.static_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else
-      size += u.format3.get_size ();
-    return size;
+    switch (format)
+    {
+    case 0: return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: return format.static_size + u.format3.get_size ();
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
   {
-    if (this == &Null(FDSelect))
-      return 0;
-    if (format == 0)
-      return u.format0.get_fd (glyph);
-    else
-      return u.format3.get_fd (glyph);
+    if (this == &Null (FDSelect)) return 0;
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd (glyph);
+    case 3: return u.format3.get_fd (glyph);
+    default:return 0;
+    }
   }
 
-  HBUINT8       format;
-  union {
-    FDSelect0   format0;
-    FDSelect3   format3;
-  } u;
+  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
 
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, fdcount));
+    case 3: return_trace (u.format3.sanitize (c, fdcount));
+    default:return_trace (false);
+    }
+  }
+
+  HBUINT8	format;
+  union {
+  FDSelect0	format0;
+  FDSelect3	format3;
+  } u;
+  public:
   DEFINE_SIZE_MIN (1);
 };
 
diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc
index 51cecb6..55abd11 100644
--- a/src/hb-ot-cff1-table.cc
+++ b/src/hb-ot-cff1-table.cc
@@ -24,6 +24,10 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_CFF
+
 #include "hb-ot-cff1-table.hh"
 #include "hb-cff1-interp-cs.hh"
 
@@ -161,15 +165,15 @@
     return CFF_UNDEF_SID;
 }
 
-struct Bounds
+struct bounds_t
 {
   void init ()
   {
-    min.set_int (0x7FFFFFFF, 0x7FFFFFFF);
-    max.set_int (-0x80000000, -0x80000000);
+    min.set_int (INT_MAX, INT_MAX);
+    max.set_int (INT_MIN, INT_MIN);
   }
 
-  void update (const Point &pt)
+  void update (const point_t &pt)
   {
     if (pt.x < min.x) min.x = pt.x;
     if (pt.x > max.x) max.x = pt.x;
@@ -177,7 +181,7 @@
     if (pt.y > max.y) max.y = pt.y;
   }
 
-  void merge (const Bounds &b)
+  void merge (const bounds_t &b)
   {
     if (empty ())
       *this = b;
@@ -190,7 +194,7 @@
     }
   }
 
-  void offset (const Point &delta)
+  void offset (const point_t &delta)
   {
     if (!empty ())
     {
@@ -199,14 +203,13 @@
     }
   }
 
-  bool empty () const
-  { return (min.x >= max.x) || (min.y >= max.y); }
+  bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
 
-  Point min;
-  Point max;
+  point_t min;
+  point_t max;
 };
 
-struct ExtentsParam
+struct cff1_extents_param_t
 {
   void init (const OT::cff1::accelerator_t *_cff)
   {
@@ -215,25 +218,25 @@
     bounds.init ();
   }
 
-  void start_path ()         { path_open = true; }
-  void end_path ()           { path_open = false; }
+  void start_path   ()       { path_open = true; }
+  void end_path     ()       { path_open = false; }
   bool is_path_open () const { return path_open; }
 
-  bool    path_open;
-  Bounds  bounds;
+  bool path_open;
+  bounds_t bounds;
 
   const OT::cff1::accelerator_t *cff;
 };
 
-struct CFF1PathProcs_Extents : PathProcs<CFF1PathProcs_Extents, CFF1CSInterpEnv, ExtentsParam>
+struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
 {
-  static void moveto (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt)
+  static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
   {
     param.end_path ();
     env.moveto (pt);
   }
 
-  static void line (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt1)
+  static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
   {
     if (!param.is_path_open ())
     {
@@ -244,7 +247,7 @@
     param.bounds.update (env.get_pt ());
   }
 
-  static void curve (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt1, const Point &pt2, const Point &pt3)
+  static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     if (!param.is_path_open ())
     {
@@ -259,20 +262,20 @@
   }
 };
 
-static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds, bool in_seac=false);
+static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
 
-struct CFF1CSOpSet_Extents : CFF1CSOpSet<CFF1CSOpSet_Extents, ExtentsParam, CFF1PathProcs_Extents>
+struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
 {
-  static void process_seac (CFF1CSInterpEnv &env, ExtentsParam& param)
+  static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
   {
     unsigned int  n = env.argStack.get_count ();
-    Point delta;
+    point_t delta;
     delta.x = env.argStack[n-4];
     delta.y = env.argStack[n-3];
     hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
     hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
 
-    Bounds  base_bounds, accent_bounds;
+    bounds_t  base_bounds, accent_bounds;
     if (likely (!env.in_seac && base && accent
 	       && _get_bounds (param.cff, base, base_bounds, true)
 	       && _get_bounds (param.cff, accent, accent_bounds, true)))
@@ -286,26 +289,31 @@
   }
 };
 
-bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds, bool in_seac)
+bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
 {
   bounds.init ();
   if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
 
   unsigned int fd = cff->fdSelect->get_fd (glyph);
-  CFF1CSInterpreter<CFF1CSOpSet_Extents, ExtentsParam> interp;
-  const ByteStr str = (*cff->charStrings)[glyph];
+  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
+  const byte_str_t str = (*cff->charStrings)[glyph];
   interp.env.init (str, *cff, fd);
   interp.env.set_in_seac (in_seac);
-  ExtentsParam  param;
+  cff1_extents_param_t  param;
   param.init (cff);
   if (unlikely (!interp.interpret (param))) return false;
   bounds = param.bounds;
   return true;
 }
 
-bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
 {
-  Bounds  bounds;
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
+  bounds_t bounds;
 
   if (!_get_bounds (this, glyph, bounds))
     return false;
@@ -317,8 +325,8 @@
   }
   else
   {
-    extents->x_bearing = (int32_t)bounds.min.x.floor ();
-    extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing;
+    extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
+    extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
   }
   if (bounds.min.y >= bounds.max.y)
   {
@@ -327,14 +335,14 @@
   }
   else
   {
-    extents->y_bearing = (int32_t)bounds.max.y.ceil ();
-    extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing;
+    extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
+    extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
   }
 
   return true;
 }
 
-struct GetSeacParam
+struct get_seac_param_t
 {
   void init (const OT::cff1::accelerator_t *_cff)
   {
@@ -350,9 +358,9 @@
   hb_codepoint_t  accent;
 };
 
-struct CFF1CSOpSet_Seac : CFF1CSOpSet<CFF1CSOpSet_Seac, GetSeacParam>
+struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
 {
-  static void process_seac (CFF1CSInterpEnv &env, GetSeacParam& param)
+  static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
   {
     unsigned int  n = env.argStack.get_count ();
     hb_codepoint_t  base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
@@ -368,10 +376,10 @@
   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 
   unsigned int fd = fdSelect->get_fd (glyph);
-  CFF1CSInterpreter<CFF1CSOpSet_Seac, GetSeacParam> interp;
-  const ByteStr str = (*charStrings)[glyph];
+  cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp;
+  const byte_str_t str = (*charStrings)[glyph];
   interp.env.init (str, *this, fd);
-  GetSeacParam  param;
+  get_seac_param_t  param;
   param.init (this);
   if (unlikely (!interp.interpret (param))) return false;
 
@@ -383,3 +391,6 @@
   }
   return false;
 }
+
+
+#endif
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index 72dc0ef..ad20651 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -59,14 +59,14 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c));
+    return_trace (codes.sanitize (c));
   }
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
     assert (glyph > 0);
     glyph--;
-    if (glyph < nCodes)
+    if (glyph < nCodes ())
     {
       return (hb_codepoint_t)codes[glyph];
     }
@@ -74,13 +74,12 @@
       return CFF_UNDEF_CODE;
   }
 
-  unsigned int get_size () const
-  { return HBUINT8::static_size * (nCodes + 1); }
+  HBUINT8 &nCodes () { return codes.len; }
+  HBUINT8 nCodes () const { return codes.len; }
 
-  HBUINT8     nCodes;
-  HBUINT8     codes[VAR];
+  ArrayOf<HBUINT8, HBUINT8> codes;
 
-  DEFINE_SIZE_ARRAY(1, codes);
+  DEFINE_SIZE_ARRAY_SIZED (1, codes);
 };
 
 struct Encoding1_Range {
@@ -97,34 +96,34 @@
 };
 
 struct Encoding1 {
-  unsigned int get_size () const
-  { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; }
-
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
+    return_trace (ranges.sanitize (c));
   }
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
     assert (glyph > 0);
     glyph--;
-    for (unsigned int i = 0; i < nRanges; i++)
+    for (unsigned int i = 0; i < nRanges (); i++)
     {
       if (glyph <= ranges[i].nLeft)
       {
-	return (hb_codepoint_t)ranges[i].first + glyph;
+	hb_codepoint_t code = (hb_codepoint_t) ranges[i].first + glyph;
+	return (likely (code < 0x100) ? code: CFF_UNDEF_CODE);
       }
       glyph -= (ranges[i].nLeft + 1);
     }
     return CFF_UNDEF_CODE;
   }
 
-  HBUINT8	   nRanges;
-  Encoding1_Range   ranges[VAR];
+  HBUINT8 &nRanges () { return ranges.len; }
+  HBUINT8 nRanges () const { return ranges.len; }
 
-  DEFINE_SIZE_ARRAY (1, ranges);
+  ArrayOf<Encoding1_Range, HBUINT8> ranges;
+
+  DEFINE_SIZE_ARRAY_SIZED (1, ranges);
 };
 
 struct SuppEncoding {
@@ -144,40 +143,26 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c)));
+    return_trace (supps.sanitize (c));
   }
 
   void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
   {
-    for (unsigned int i = 0; i < nSups; i++)
+    for (unsigned int i = 0; i < nSups (); i++)
       if (sid == supps[i].glyph)
 	codes.push (supps[i].code);
   }
 
-  unsigned int get_size () const
-  { return HBUINT8::static_size + SuppEncoding::static_size * nSups; }
+  HBUINT8 &nSups () { return supps.len; }
+  HBUINT8 nSups () const { return supps.len; }
 
-  HBUINT8	 nSups;
-  SuppEncoding   supps[VAR];
+  ArrayOf<SuppEncoding, HBUINT8> supps;
 
-  DEFINE_SIZE_ARRAY (1, supps);
+  DEFINE_SIZE_ARRAY_SIZED (1, supps);
 };
 
-struct Encoding {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (unlikely (!c->check_struct (this)))
-      return_trace (false);
-    unsigned int fmt = format & 0x7F;
-    if (unlikely (fmt > 1))
-      return_trace (false);
-    if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
-      return_trace (false);
-    return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
-  }
-
+struct Encoding
+{
   /* serialize a fullset Encoding */
   bool serialize (hb_serialize_context_t *c, const Encoding &src)
   {
@@ -193,52 +178,60 @@
   bool serialize (hb_serialize_context_t *c,
 		  uint8_t format,
 		  unsigned int enc_count,
-		  const hb_vector_t<code_pair>& code_ranges,
-		  const hb_vector_t<code_pair>& supp_codes)
+		  const hb_vector_t<code_pair_t>& code_ranges,
+		  const hb_vector_t<code_pair_t>& supp_codes)
   {
     TRACE_SERIALIZE (this);
     Encoding *dest = c->extend_min (*this);
     if (unlikely (dest == nullptr)) return_trace (false);
-    dest->format.set (format | ((supp_codes.len > 0)? 0x80: 0));
-    if (format == 0)
+    dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
+    switch (format) {
+    case 0:
     {
       Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count);
-    if (unlikely (fmt0 == nullptr)) return_trace (false);
-      fmt0->nCodes.set (enc_count);
+      if (unlikely (fmt0 == nullptr)) return_trace (false);
+      fmt0->nCodes () = enc_count;
       unsigned int glyph = 0;
-      for (unsigned int i = 0; i < code_ranges.len; i++)
+      for (unsigned int i = 0; i < code_ranges.length; i++)
       {
 	hb_codepoint_t code = code_ranges[i].code;
 	for (int left = (int)code_ranges[i].glyph; left >= 0; left--)
-	  fmt0->codes[glyph++].set (code++);
+	  fmt0->codes[glyph++] = code++;
 	if (unlikely (!((glyph <= 0x100) && (code <= 0x100))))
 	  return_trace (false);
       }
     }
-    else
+    break;
+
+    case 1:
     {
-      Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.len);
+      Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length);
       if (unlikely (fmt1 == nullptr)) return_trace (false);
-      fmt1->nRanges.set (code_ranges.len);
-      for (unsigned int i = 0; i < code_ranges.len; i++)
+      fmt1->nRanges () = code_ranges.length;
+      for (unsigned int i = 0; i < code_ranges.length; i++)
       {
 	if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF))))
 	  return_trace (false);
-	fmt1->ranges[i].first.set (code_ranges[i].code);
-	fmt1->ranges[i].nLeft.set (code_ranges[i].glyph);
+	fmt1->ranges[i].first = code_ranges[i].code;
+	fmt1->ranges[i].nLeft = code_ranges[i].glyph;
       }
     }
-    if (supp_codes.len > 0)
+    break;
+
+    }
+
+    if (supp_codes.length)
     {
-      CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.len);
+      CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length);
       if (unlikely (suppData == nullptr)) return_trace (false);
-      suppData->nSups.set (supp_codes.len);
-      for (unsigned int i = 0; i < supp_codes.len; i++)
+      suppData->nSups () = supp_codes.length;
+      for (unsigned int i = 0; i < supp_codes.length; i++)
       {
-	suppData->supps[i].code.set (supp_codes[i].code);
-	suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */
+	suppData->supps[i].code = supp_codes[i].code;
+	suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */
       }
     }
+
     return_trace (true);
   }
 
@@ -247,11 +240,13 @@
 						 unsigned int enc_count,
 						 unsigned int supp_count)
   {
-    unsigned int  size = min_size;
-    if (format == 0)
-      size += Encoding0::min_size + HBUINT8::static_size * enc_count;
-    else
-      size += Encoding1::min_size + Encoding1_Range::static_size * enc_count;
+    unsigned int size = min_size;
+    switch (format)
+    {
+    case 0: size += Encoding0::min_size + HBUINT8::static_size * enc_count; break;
+    case 1: size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; break;
+    default:return 0;
+    }
     if (supp_count > 0)
       size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count;
     return size;
@@ -260,10 +255,11 @@
   unsigned int get_size () const
   {
     unsigned int size = min_size;
-    if (table_format () == 0)
-      size += u.format0.get_size ();
-    else
-      size += u.format1.get_size ();
+    switch (table_format ())
+    {
+    case 0: size += u.format0.get_size (); break;
+    case 1: size += u.format1.get_size (); break;
+    }
     if (has_supplement ())
       size += suppEncData ().get_size ();
     return size;
@@ -271,14 +267,16 @@
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
-    if (table_format () == 0)
-      return u.format0.get_code (glyph);
-    else
-      return u.format1.get_code (glyph);
+    switch (table_format ())
+    {
+    case 0: return u.format0.get_code (glyph);
+    case 1: return u.format1.get_code (glyph);
+    default:return 0;
+    }
   }
 
-  uint8_t table_format () const { return (format & 0x7F); }
-  bool  has_supplement () const { return (format & 0x80) != 0; }
+  uint8_t table_format () const { return format & 0x7F; }
+  bool  has_supplement () const { return format & 0x80; }
 
   void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
   {
@@ -287,21 +285,37 @@
       suppEncData().get_codes (sid, codes);
   }
 
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (table_format ())
+    {
+    case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break;
+    case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break;
+    default:return_trace (false);
+    }
+    return_trace (likely (!has_supplement () || suppEncData ().sanitize (c)));
+  }
+
   protected:
   const CFF1SuppEncData &suppEncData () const
   {
-    if ((format & 0x7F) == 0)
-      return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]);
-    else
-      return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]);
+    switch (table_format ())
+    {
+    case 0: return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
+    case 1: return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
+    default:return Null (CFF1SuppEncData);
+    }
   }
 
   public:
-  HBUINT8       format;
-
+  HBUINT8	format;
   union {
-    Encoding0   format0;
-    Encoding1   format1;
+  Encoding0	format0;
+  Encoding1	format1;
   } u;
   /* CFF1SuppEncData  suppEncData; */
 
@@ -343,7 +357,7 @@
     return HBUINT16::static_size * (num_glyphs - 1);
   }
 
-  HBUINT16  sids[VAR];
+  HBUINT16  sids[HB_VAR_ARRAY];
 
   DEFINE_SIZE_ARRAY(0, sids);
 };
@@ -425,7 +439,7 @@
     return size;
   }
 
-  Charset_Range<TYPE>   ranges[VAR];
+  Charset_Range<TYPE>   ranges[HB_VAR_ARRAY];
 
   DEFINE_SIZE_ARRAY (0, ranges);
 };
@@ -435,23 +449,8 @@
 typedef Charset_Range<HBUINT8>  Charset1_Range;
 typedef Charset_Range<HBUINT16> Charset2_Range;
 
-struct Charset {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (unlikely (!c->check_struct (this)))
-      return_trace (false);
-    if (format == 0)
-      return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
-    else if (format == 1)
-      return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
-    else if (likely (format == 2))
-      return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
-    else
-      return_trace (false);
-  }
-
+struct Charset
+{
   /* serialize a fullset Charset */
   bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
   {
@@ -467,97 +466,119 @@
   bool serialize (hb_serialize_context_t *c,
 		  uint8_t format,
 		  unsigned int num_glyphs,
-		  const hb_vector_t<code_pair>& sid_ranges)
+		  const hb_vector_t<code_pair_t>& sid_ranges)
   {
     TRACE_SERIALIZE (this);
     Charset *dest = c->extend_min (*this);
     if (unlikely (dest == nullptr)) return_trace (false);
-    dest->format.set (format);
-    if (format == 0)
+    dest->format = format;
+    switch (format)
+    {
+    case 0:
     {
       Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
-    if (unlikely (fmt0 == nullptr)) return_trace (false);
+      if (unlikely (fmt0 == nullptr)) return_trace (false);
       unsigned int glyph = 0;
-      for (unsigned int i = 0; i < sid_ranges.len; i++)
+      for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
 	hb_codepoint_t sid = sid_ranges[i].code;
 	for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
-	  fmt0->sids[glyph++].set (sid++);
+	  fmt0->sids[glyph++] = sid++;
       }
     }
-    else if (format == 1)
+    break;
+
+    case 1:
     {
-      Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.len);
+      Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
       if (unlikely (fmt1 == nullptr)) return_trace (false);
-      for (unsigned int i = 0; i < sid_ranges.len; i++)
+      for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
       	if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
 	  return_trace (false);
-	fmt1->ranges[i].first.set (sid_ranges[i].code);
-	fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph);
+	fmt1->ranges[i].first = sid_ranges[i].code;
+	fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
       }
     }
-    else /* format 2 */
+    break;
+
+    case 2:
     {
-      Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.len);
+      Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
       if (unlikely (fmt2 == nullptr)) return_trace (false);
-      for (unsigned int i = 0; i < sid_ranges.len; i++)
+      for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
       	if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
 	  return_trace (false);
-	fmt2->ranges[i].first.set (sid_ranges[i].code);
-	fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph);
+	fmt2->ranges[i].first = sid_ranges[i].code;
+	fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
       }
     }
+    break;
+
+    }
     return_trace (true);
   }
 
   /* parallel to above: calculate the size of a subset Charset */
-  static unsigned int calculate_serialized_size (
-			uint8_t format,
-			unsigned int count)
+  static unsigned int calculate_serialized_size (uint8_t format,
+						 unsigned int count)
   {
-    unsigned int  size = min_size;
-    if (format == 0)
-      size += Charset0::min_size + HBUINT16::static_size * (count - 1);
-    else if (format == 1)
-      size += Charset1::min_size + Charset1_Range::static_size * count;
-    else
-      size += Charset2::min_size + Charset2_Range::static_size * count;
-
-    return size;
+    switch (format)
+    {
+    case 0: return min_size + Charset0::min_size + HBUINT16::static_size * (count - 1);
+    case 1: return min_size + Charset1::min_size + Charset1_Range::static_size * count;
+    case 2: return min_size + Charset2::min_size + Charset2_Range::static_size * count;
+    default:return 0;
+    }
   }
 
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = min_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else if (format == 1)
-      size += u.format1.get_size (num_glyphs);
-    else
-      size += u.format2.get_size (num_glyphs);
-    return size;
+    switch (format)
+    {
+    case 0: return min_size + u.format0.get_size (num_glyphs);
+    case 1: return min_size + u.format1.get_size (num_glyphs);
+    case 2: return min_size + u.format2.get_size (num_glyphs);
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_sid (hb_codepoint_t glyph) const
   {
-    if (format == 0)
-      return u.format0.get_sid (glyph);
-    else if (format == 1)
-      return u.format1.get_sid (glyph);
-    else
-      return u.format2.get_sid (glyph);
+    switch (format)
+    {
+    case 0: return u.format0.get_sid (glyph);
+    case 1: return u.format1.get_sid (glyph);
+    case 2: return u.format2.get_sid (glyph);
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
   {
-    if (format == 0)
-      return u.format0.get_glyph (sid, num_glyphs);
-    else if (format == 1)
-      return u.format1.get_glyph (sid, num_glyphs);
-    else
-      return u.format2.get_glyph (sid, num_glyphs);
+    switch (format)
+    {
+    case 0: return u.format0.get_glyph (sid, num_glyphs);
+    case 1: return u.format1.get_glyph (sid, num_glyphs);
+    case 2: return u.format2.get_glyph (sid, num_glyphs);
+    default:return 0;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
+    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
+    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+    default:return_trace (false);
+    }
   }
 
   HBUINT8       format;
@@ -573,20 +594,20 @@
 struct CFF1StringIndex : CFF1Index
 {
   bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
-		  unsigned int offSize_, const Remap &sidmap)
+		  unsigned int offSize_, const hb_inc_bimap_t &sidmap)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
+    if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
     {
-      if (!unlikely (c->extend_min (this->count)))
+      if (unlikely (!c->extend_min (this->count)))
 	return_trace (false);
-      count.set (0);
+      count = 0;
       return_trace (true);
     }
 
-    ByteStrArray bytesArray;
+    byte_str_array_t bytesArray;
     bytesArray.init ();
-    if (!bytesArray.resize (sidmap.get_count ()))
+    if (!bytesArray.resize (sidmap.get_population ()))
       return_trace (false);
     for (unsigned int i = 0; i < strings.count; i++)
     {
@@ -601,10 +622,10 @@
   }
 
   /* in parallel to above */
-  unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const Remap &sidmap) const
+  unsigned int calculate_serialized_size (unsigned int &offSize_ /*OUT*/, const hb_inc_bimap_t &sidmap) const
   {
-    offSize = 0;
-    if ((count == 0) || (sidmap.get_count () == 0))
+    offSize_ = 0;
+    if ((count == 0) || (sidmap.get_population () == 0))
       return count.static_size;
 
     unsigned int dataSize = 0;
@@ -612,23 +633,23 @@
       if (sidmap[i] != CFF_UNDEF_CODE)
 	dataSize += length_at (i);
 
-    offSize = calcOffSize(dataSize);
-    return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize);
+    offSize_ = calcOffSize(dataSize);
+    return CFF1Index::calculate_serialized_size (offSize_, sidmap.get_population (), dataSize);
   }
 };
 
-struct CFF1TopDictInterpEnv : NumInterpEnv
+struct cff1_top_dict_interp_env_t : num_interp_env_t
 {
-  CFF1TopDictInterpEnv ()
-    : NumInterpEnv(), prev_offset(0), last_offset(0) {}
+  cff1_top_dict_interp_env_t ()
+    : num_interp_env_t(), prev_offset(0), last_offset(0) {}
 
   unsigned int prev_offset;
   unsigned int last_offset;
 };
 
-struct NameDictValues
+struct name_dict_values_t
 {
-  enum NameDictValIndex
+  enum name_dict_val_index_t
   {
       version,
       notice,
@@ -657,7 +678,7 @@
   unsigned int operator[] (unsigned int i) const
   { assert (i < ValCount); return values[i]; }
 
-  static enum NameDictValIndex name_op_to_index (OpCode op)
+  static enum name_dict_val_index_t name_op_to_index (op_code_t op)
   {
     switch (op) {
       default: // can't happen - just make some compiler happy
@@ -685,16 +706,16 @@
   unsigned int  values[ValCount];
 };
 
-struct CFF1TopDictVal : OpStr
+struct cff1_top_dict_val_t : op_str_t
 {
   unsigned int  last_arg_offset;
 };
 
-struct CFF1TopDictValues : TopDictValues<CFF1TopDictVal>
+struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
 {
   void init ()
   {
-    TopDictValues<CFF1TopDictVal>::init ();
+    top_dict_values_t<cff1_top_dict_val_t>::init ();
 
     nameSIDs.init ();
     ros_supplement = 0;
@@ -704,12 +725,12 @@
     FDSelectOffset = 0;
     privateDictInfo.init ();
   }
-  void fini () { TopDictValues<CFF1TopDictVal>::fini (); }
+  void fini () { top_dict_values_t<cff1_top_dict_val_t>::fini (); }
 
   bool is_CID () const
-  { return nameSIDs[NameDictValues::registry] != CFF_UNDEF_SID; }
+  { return nameSIDs[name_dict_values_t::registry] != CFF_UNDEF_SID; }
 
-  NameDictValues  nameSIDs;
+  name_dict_values_t  nameSIDs;
   unsigned int    ros_supplement_offset;
   unsigned int    ros_supplement;
   unsigned int    cidCount;
@@ -717,14 +738,14 @@
   unsigned int    EncodingOffset;
   unsigned int    CharsetOffset;
   unsigned int    FDSelectOffset;
-  TableInfo       privateDictInfo;
+  table_info_t       privateDictInfo;
 };
 
-struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
+struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
 {
-  static void process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval)
+  static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval)
   {
-    CFF1TopDictVal  val;
+    cff1_top_dict_val_t  val;
     val.last_arg_offset = (env.last_offset-1) - dictval.opStart;  /* offset to the last argument */
 
     switch (op) {
@@ -736,7 +757,7 @@
       case OpCode_Weight:
       case OpCode_PostScript:
       case OpCode_BaseFontName:
-	dictval.nameSIDs[NameDictValues::name_op_to_index (op)] = env.argStack.pop_uint ();
+	dictval.nameSIDs[name_dict_values_t::name_op_to_index (op)] = env.argStack.pop_uint ();
 	env.clear_args ();
 	break;
       case OpCode_isFixedPitch:
@@ -765,8 +786,8 @@
 
       case OpCode_ROS:
 	dictval.ros_supplement = env.argStack.pop_uint ();
-	dictval.nameSIDs[NameDictValues::ordering] = env.argStack.pop_uint ();
-	dictval.nameSIDs[NameDictValues::registry] = env.argStack.pop_uint ();
+	dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint ();
+	dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint ();
 	env.clear_args ();
 	break;
 
@@ -794,8 +815,8 @@
 	break;
 
       default:
-	env.last_offset = env.substr.offset;
-	TopDictOpSet<CFF1TopDictVal>::process_op (op, env, dictval);
+	env.last_offset = env.str_ref.offset;
+	top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval);
 	/* Record this operand below if stack is empty, otherwise done */
 	if (!env.argStack.is_empty ()) return;
 	break;
@@ -803,27 +824,27 @@
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr, val);
+    dictval.add_op (op, env.str_ref, val);
   }
 };
 
-struct CFF1FontDictValues : DictValues<OpStr>
+struct cff1_font_dict_values_t : dict_values_t<op_str_t>
 {
   void init ()
   {
-    DictValues<OpStr>::init ();
+    dict_values_t<op_str_t>::init ();
     privateDictInfo.init ();
     fontName = CFF_UNDEF_SID;
   }
-  void fini () { DictValues<OpStr>::fini (); }
+  void fini () { dict_values_t<op_str_t>::fini (); }
 
-  TableInfo       privateDictInfo;
+  table_info_t       privateDictInfo;
   unsigned int    fontName;
 };
 
-struct CFF1FontDictOpSet : DictOpSet
+struct cff1_font_dict_opset_t : dict_opset_t
 {
-  static void process_op (OpCode op, NumInterpEnv& env, CFF1FontDictValues& dictval)
+  static void process_op (op_code_t op, num_interp_env_t& env, cff1_font_dict_values_t& dictval)
   {
     switch (op) {
       case OpCode_FontName:
@@ -841,36 +862,36 @@
 	break;
 
       default:
-	DictOpSet::process_op (op, env);
+	dict_opset_t::process_op (op, env);
 	if (!env.argStack.is_empty ()) return;
 	break;
     }
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr);
+    dictval.add_op (op, env.str_ref);
   }
 };
 
 template <typename VAL>
-struct CFF1PrivateDictValues_Base : DictValues<VAL>
+struct cff1_private_dict_values_base_t : dict_values_t<VAL>
 {
   void init ()
   {
-    DictValues<VAL>::init ();
+    dict_values_t<VAL>::init ();
     subrsOffset = 0;
     localSubrs = &Null(CFF1Subrs);
   }
-  void fini () { DictValues<VAL>::fini (); }
+  void fini () { dict_values_t<VAL>::fini (); }
 
   unsigned int calculate_serialized_size () const
   {
     unsigned int size = 0;
-    for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++)
-      if (DictValues<VAL>::get_value (i).op == OpCode_Subrs)
+    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
+      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
 	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
       else
-	size += DictValues<VAL>::get_value (i).str.len;
+	size += dict_values_t<VAL>::get_value (i).str.length;
     return size;
   }
 
@@ -878,14 +899,14 @@
   const CFF1Subrs    *localSubrs;
 };
 
-typedef CFF1PrivateDictValues_Base<OpStr> CFF1PrivateDictValues_Subset;
-typedef CFF1PrivateDictValues_Base<NumDictVal> CFF1PrivateDictValues;
+typedef cff1_private_dict_values_base_t<op_str_t> cff1_private_dict_values_subset_t;
+typedef cff1_private_dict_values_base_t<num_dict_val_t> cff1_private_dict_values_t;
 
-struct CFF1PrivateDictOpSet : DictOpSet
+struct cff1_private_dict_opset_t : dict_opset_t
 {
-  static void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues& dictval)
+  static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_t& dictval)
   {
-    NumDictVal val;
+    num_dict_val_t val;
     val.init ();
 
     switch (op) {
@@ -917,20 +938,20 @@
 	break;
 
       default:
-	DictOpSet::process_op (op, env);
+	dict_opset_t::process_op (op, env);
 	if (!env.argStack.is_empty ()) return;
 	break;
     }
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr, val);
+    dictval.add_op (op, env.str_ref, val);
   }
 };
 
-struct CFF1PrivateDictOpSet_Subset : DictOpSet
+struct cff1_private_dict_opset_subset : dict_opset_t
 {
-  static void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues_Subset& dictval)
+  static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
   {
     switch (op) {
       case OpCode_BlueValues:
@@ -959,25 +980,24 @@
 	break;
 
       default:
-	DictOpSet::process_op (op, env);
+	dict_opset_t::process_op (op, env);
 	if (!env.argStack.is_empty ()) return;
 	break;
     }
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr);
+    dictval.add_op (op, env.str_ref);
   }
 };
 
-typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues, CFF1TopDictInterpEnv> CFF1TopDict_Interpreter;
-typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter;
-typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter;
+typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_top_dict_interp_env_t> cff1_top_dict_interpreter_t;
+typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t;
 
 typedef CFF1Index CFF1NameIndex;
 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
 
-}; /* namespace CFF */
+} /* namespace CFF */
 
 namespace OT {
 
@@ -985,7 +1005,7 @@
 
 struct cff1
 {
-  static const hb_tag_t tableTag	= HB_OT_TAG_cff1;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1023,9 +1043,9 @@
       { fini (); return; }
 
       { /* parse top dict */
-	const ByteStr topDictStr = (*topDictIndex)[0];
+	const byte_str_t topDictStr = (*topDictIndex)[0];
 	if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
-	CFF1TopDict_Interpreter top_interp;
+	cff1_top_dict_interpreter_t top_interp;
 	top_interp.env.init (topDictStr);
 	topDict.init ();
 	if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
@@ -1082,24 +1102,24 @@
       {
 	for (unsigned int i = 0; i < fdCount; i++)
 	{
-	  ByteStr fontDictStr = (*fdArray)[i];
+	  byte_str_t fontDictStr = (*fdArray)[i];
 	  if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
-	  CFF1FontDictValues  *font;
-	  CFF1FontDict_Interpreter font_interp;
+	  cff1_font_dict_values_t  *font;
+	  cff1_font_dict_interpreter_t font_interp;
 	  font_interp.env.init (fontDictStr);
 	  font = fontDicts.push ();
-	  if (unlikely (font == &Crap(CFF1FontDictValues))) { fini (); return; }
+	  if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; }
 	  font->init ();
 	  if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 	  PRIVDICTVAL  *priv = &privateDicts[i];
-	  const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
+	  const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
 	  if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
-	  DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp;
+	  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
 	  priv_interp.env.init (privDictStr);
 	  priv->init ();
 	  if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
-	  priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
+	  priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
 	  if (priv->localSubrs != &Null(CFF1Subrs) &&
 	      unlikely (!priv->localSubrs->sanitize (&sc)))
 	  { fini (); return; }
@@ -1107,17 +1127,17 @@
       }
       else  /* non-CID */
       {
-	CFF1TopDictValues  *font = &topDict;
+	cff1_top_dict_values_t  *font = &topDict;
 	PRIVDICTVAL  *priv = &privateDicts[0];
 
-	const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
+	const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
 	if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
-	DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp;
+	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
 	priv_interp.env.init (privDictStr);
 	priv->init ();
 	if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
-	priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
+	priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
 	if (priv->localSubrs != &Null(CFF1Subrs) &&
 	    unlikely (!priv->localSubrs->sanitize (&sc)))
 	{ fini (); return; }
@@ -1135,7 +1155,7 @@
     }
 
     bool is_valid () const { return blob != nullptr; }
-    bool is_CID () const { return topDict.is_CID (); }
+    bool   is_CID () const { return topDict.is_CID (); }
 
     bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; }
 
@@ -1167,20 +1187,20 @@
     const CFF1FDSelect      *fdSelect;
     unsigned int	    fdCount;
 
-    CFF1TopDictValues       topDict;
-    hb_vector_t<CFF1FontDictValues>   fontDicts;
+    cff1_top_dict_values_t       topDict;
+    hb_vector_t<cff1_font_dict_values_t>   fontDicts;
     hb_vector_t<PRIVDICTVAL>	  privateDicts;
 
     unsigned int	    num_glyphs;
   };
 
-  struct accelerator_t : accelerator_templ_t<CFF1PrivateDictOpSet, CFF1PrivateDictValues>
+  struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
   {
-    HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
+    HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
     HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
   };
 
-  struct accelerator_subset_t : accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset>
+  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t>
   {
     void init (hb_face_t *face)
     {
@@ -1205,25 +1225,25 @@
 
     bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
 
-    hb_codepoint_t  glyph_to_code (hb_codepoint_t glyph) const
+    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
     {
       if (encoding != &Null(Encoding))
 	return encoding->get_code (glyph);
       else
       {
-	hb_codepoint_t  sid = glyph_to_sid (glyph);
+	hb_codepoint_t sid = glyph_to_sid (glyph);
 	if (sid == 0) return 0;
-	hb_codepoint_t  code = 0;
+	hb_codepoint_t code = 0;
 	switch (topDict.EncodingOffset)
 	{
-	  case  StandardEncoding:
-	    code = lookup_standard_encoding_for_code (sid);
-	    break;
-	  case  ExpertEncoding:
-	    code = lookup_expert_encoding_for_code (sid);
-	    break;
-	  default:
-	    break;
+	case StandardEncoding:
+	  code = lookup_standard_encoding_for_code (sid);
+	  break;
+	case ExpertEncoding:
+	  code = lookup_expert_encoding_for_code (sid);
+	  break;
+	default:
+	  break;
 	}
 	return code;
       }
@@ -1257,7 +1277,7 @@
     const Encoding	  *encoding;
 
     private:
-    typedef accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset> SUPER;
+    typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER;
   };
 
   bool subset (hb_subset_plan_t *plan) const
diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc
index 7188a3b..a2242b7 100644
--- a/src/hb-ot-cff2-table.cc
+++ b/src/hb-ot-cff2-table.cc
@@ -24,27 +24,31 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_FONT_CFF
+
 #include "hb-ot-cff2-table.hh"
 #include "hb-cff2-interp-cs.hh"
 
 using namespace CFF;
 
-struct ExtentsParam
+struct cff2_extents_param_t
 {
   void init ()
   {
     path_open = false;
-    min_x.set_int (0x7FFFFFFF);
-    min_y.set_int (0x7FFFFFFF);
-    max_x.set_int (-0x80000000);
-    max_y.set_int (-0x80000000);
+    min_x.set_int (INT_MAX);
+    min_y.set_int (INT_MAX);
+    max_x.set_int (INT_MIN);
+    max_y.set_int (INT_MIN);
   }
 
-  void start_path ()         { path_open = true; }
-  void end_path ()           { path_open = false; }
+  void   start_path ()       { path_open = true; }
+  void     end_path ()       { path_open = false; }
   bool is_path_open () const { return path_open; }
 
-  void update_bounds (const Point &pt)
+  void update_bounds (const point_t &pt)
   {
     if (pt.x < min_x) min_x = pt.x;
     if (pt.x > max_x) max_x = pt.x;
@@ -53,21 +57,21 @@
   }
 
   bool  path_open;
-  Number min_x;
-  Number min_y;
-  Number max_x;
-  Number max_y;
+  number_t min_x;
+  number_t min_y;
+  number_t max_x;
+  number_t max_y;
 };
 
-struct CFF2PathProcs_Extents : PathProcs<CFF2PathProcs_Extents, CFF2CSInterpEnv, ExtentsParam>
+struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
 {
-  static void moveto (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt)
+  static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
   {
     param.end_path ();
     env.moveto (pt);
   }
 
-  static void line (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1)
+  static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
   {
     if (!param.is_path_open ())
     {
@@ -78,7 +82,7 @@
     param.update_bounds (env.get_pt ());
   }
 
-  static void curve (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1, const Point &pt2, const Point &pt3)
+  static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     if (!param.is_path_open ())
     {
@@ -93,21 +97,24 @@
   }
 };
 
-struct CFF2CSOpSet_Extents : CFF2CSOpSet<CFF2CSOpSet_Extents, ExtentsParam, CFF2PathProcs_Extents> {};
+struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
 
 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
 					   hb_codepoint_t glyph,
 					   hb_glyph_extents_t *extents) const
 {
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 
-  unsigned int num_coords;
-  const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   unsigned int fd = fdSelect->get_fd (glyph);
-  CFF2CSInterpreter<CFF2CSOpSet_Extents, ExtentsParam> interp;
-  const ByteStr str = (*charStrings)[glyph];
-  interp.env.init (str, *this, fd, coords, num_coords);
-  ExtentsParam  param;
+  cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
+  const byte_str_t str = (*charStrings)[glyph];
+  interp.env.init (str, *this, fd, font->coords, font->num_coords);
+  cff2_extents_param_t  param;
   param.init ();
   if (unlikely (!interp.interpret (param))) return false;
 
@@ -118,8 +125,8 @@
   }
   else
   {
-    extents->x_bearing = (int32_t)param.min_x.floor ();
-    extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing;
+    extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
+    extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
   }
   if (param.min_y >= param.max_y)
   {
@@ -128,9 +135,12 @@
   }
   else
   {
-    extents->y_bearing = (int32_t)param.max_y.ceil ();
-    extents->height = (int32_t)param.min_y.floor () - extents->y_bearing;
+    extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
+    extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
   }
 
   return true;
 }
+
+
+#endif
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index 25c41ef..8646cde 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -51,18 +51,6 @@
 
 struct CFF2FDSelect
 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
-  {
-    TRACE_SANITIZE (this);
-
-    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
-			  (format == 0)?
-			  u.format0.sanitize (c, fdcount):
-			    ((format == 3)?
-			    u.format3.sanitize (c, fdcount):
-			    u.format4.sanitize (c, fdcount))));
-  }
-
   bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
@@ -78,35 +66,51 @@
 
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = format.static_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else if (format == 3)
-      size += u.format3.get_size ();
-    else
-      size += u.format4.get_size ();
-    return size;
+    switch (format)
+    {
+    case 0: return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: return format.static_size + u.format3.get_size ();
+    case 4: return format.static_size + u.format4.get_size ();
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
   {
-    if (this == &Null(CFF2FDSelect))
+    if (this == &Null (CFF2FDSelect))
       return 0;
-    if (format == 0)
-      return u.format0.get_fd (glyph);
-    else if (format == 3)
-      return u.format3.get_fd (glyph);
-    else
-      return u.format4.get_fd (glyph);
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd (glyph);
+    case 3: return u.format3.get_fd (glyph);
+    case 4: return u.format4.get_fd (glyph);
+    default:return 0;
+    }
   }
 
-  HBUINT8       format;
-  union {
-    FDSelect0   format0;
-    FDSelect3   format3;
-    FDSelect4   format4;
-  } u;
+  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
 
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, fdcount));
+    case 3: return_trace (u.format3.sanitize (c, fdcount));
+    case 4: return_trace (u.format4.sanitize (c, fdcount));
+    default:return_trace (false);
+    }
+  }
+
+  HBUINT8	format;
+  union {
+  FDSelect0	format0;
+  FDSelect3	format3;
+  FDSelect4	format4;
+  } u;
+  public:
   DEFINE_SIZE_MIN (2);
 };
 
@@ -136,22 +140,22 @@
   DEFINE_SIZE_MIN (2 + VariationStore::min_size);
 };
 
-struct CFF2TopDictValues : TopDictValues<>
+struct cff2_top_dict_values_t : top_dict_values_t<>
 {
   void init ()
   {
-    TopDictValues<>::init ();
+    top_dict_values_t<>::init ();
     vstoreOffset = 0;
     FDSelectOffset = 0;
   }
-  void fini () { TopDictValues<>::fini (); }
+  void fini () { top_dict_values_t<>::fini (); }
 
   unsigned int calculate_serialized_size () const
   {
     unsigned int size = 0;
     for (unsigned int i = 0; i < get_count (); i++)
     {
-      OpCode op = get_value (i).op;
+      op_code_t op = get_value (i).op;
       switch (op)
       {
 	case OpCode_vstore:
@@ -159,7 +163,7 @@
 	  size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
 	  break;
 	default:
-	  size += TopDictValues<>::calculate_serialized_op_size (get_value (i));
+	  size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i));
 	  break;
       }
     }
@@ -170,16 +174,16 @@
   unsigned int  FDSelectOffset;
 };
 
-struct CFF2TopDictOpSet : TopDictOpSet<>
+struct cff2_top_dict_opset_t : top_dict_opset_t<>
 {
-  static void process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval)
+  static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval)
   {
     switch (op) {
       case OpCode_FontMatrix:
 	{
-	  DictVal val;
+	  dict_val_t val;
 	  val.init ();
-	  dictval.add_op (op, env.substr);
+	  dictval.add_op (op, env.str_ref);
 	  env.clear_args ();
 	}
 	break;
@@ -201,27 +205,27 @@
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr);
+    dictval.add_op (op, env.str_ref);
   }
 
-  typedef TopDictOpSet<> SUPER;
+  typedef top_dict_opset_t<> SUPER;
 };
 
-struct CFF2FontDictValues : DictValues<OpStr>
+struct cff2_font_dict_values_t : dict_values_t<op_str_t>
 {
   void init ()
   {
-    DictValues<OpStr>::init ();
+    dict_values_t<op_str_t>::init ();
     privateDictInfo.init ();
   }
-  void fini () { DictValues<OpStr>::fini (); }
+  void fini () { dict_values_t<op_str_t>::fini (); }
 
-  TableInfo    privateDictInfo;
+  table_info_t    privateDictInfo;
 };
 
-struct CFF2FontDictOpSet : DictOpSet
+struct cff2_font_dict_opset_t : dict_opset_t
 {
-  static void process_op (OpCode op, NumInterpEnv& env, CFF2FontDictValues& dictval)
+  static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval)
   {
     switch (op) {
       case OpCode_Private:
@@ -238,33 +242,33 @@
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr);
+    dictval.add_op (op, env.str_ref);
   }
 
   private:
-  typedef DictOpSet SUPER;
+  typedef dict_opset_t SUPER;
 };
 
 template <typename VAL>
-struct CFF2PrivateDictValues_Base : DictValues<VAL>
+struct cff2_private_dict_values_base_t : dict_values_t<VAL>
 {
   void init ()
   {
-    DictValues<VAL>::init ();
+    dict_values_t<VAL>::init ();
     subrsOffset = 0;
     localSubrs = &Null(CFF2Subrs);
     ivs = 0;
   }
-  void fini () { DictValues<VAL>::fini (); }
+  void fini () { dict_values_t<VAL>::fini (); }
 
   unsigned int calculate_serialized_size () const
   {
     unsigned int size = 0;
-    for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++)
-      if (DictValues<VAL>::get_value (i).op == OpCode_Subrs)
+    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
+      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
 	size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
       else
-	size += DictValues<VAL>::get_value (i).str.len;
+	size += dict_values_t<VAL>::get_value (i).str.length;
     return size;
   }
 
@@ -273,14 +277,14 @@
   unsigned int      ivs;
 };
 
-typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
-typedef CFF2PrivateDictValues_Base<NumDictVal> CFF2PrivateDictValues;
+typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
+typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
 
-struct CFF2PrivDictInterpEnv : NumInterpEnv
+struct cff2_priv_dict_interp_env_t : num_interp_env_t
 {
-  void init (const ByteStr &str)
+  void init (const byte_str_t &str)
   {
-    NumInterpEnv::init (str);
+    num_interp_env_t::init (str);
     ivs = 0;
     seen_vsindex = false;
   }
@@ -302,11 +306,11 @@
   bool	  seen_vsindex;
 };
 
-struct CFF2PrivateDictOpSet : DictOpSet
+struct cff2_private_dict_opset_t : dict_opset_t
 {
-  static void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues& dictval)
+  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval)
   {
-    NumDictVal val;
+    num_dict_val_t val;
     val.init ();
 
     switch (op) {
@@ -341,20 +345,20 @@
 	break;
 
       default:
-	DictOpSet::process_op (op, env);
+	dict_opset_t::process_op (op, env);
 	if (!env.argStack.is_empty ()) return;
 	break;
     }
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr, val);
+    dictval.add_op (op, env.str_ref, val);
   }
 };
 
-struct CFF2PrivateDictOpSet_Subset : DictOpSet
+struct cff2_private_dict_opset_subset_t : dict_opset_t
 {
-  static void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
+  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval)
   {
     switch (op) {
       case OpCode_BlueValues:
@@ -390,17 +394,17 @@
 
     if (unlikely (env.in_error ())) return;
 
-    dictval.add_op (op, env.substr);
+    dictval.add_op (op, env.str_ref);
   }
 
   private:
-  typedef DictOpSet SUPER;
+  typedef dict_opset_t SUPER;
 };
 
-typedef DictInterpreter<CFF2TopDictOpSet, CFF2TopDictValues> CFF2TopDict_Interpreter;
-typedef DictInterpreter<CFF2FontDictOpSet, CFF2FontDictValues> CFF2FontDict_Interpreter;
+typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
+typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
 
-}; /* namespace CFF */
+} /* namespace CFF */
 
 namespace OT {
 
@@ -408,7 +412,7 @@
 
 struct cff2
 {
-  static const hb_tag_t tableTag	= HB_OT_TAG_cff2;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -438,9 +442,9 @@
       { fini (); return; }
 
       { /* parse top dict */
-	ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
+	byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
 	if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
-	CFF2TopDict_Interpreter top_interp;
+	cff2_top_dict_interpreter_t top_interp;
 	top_interp.env.init (topDictStr);
 	topDict.init ();
 	if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
@@ -469,24 +473,24 @@
       /* parse font dicts and gather private dicts */
       for (unsigned int i = 0; i < fdCount; i++)
       {
-	const ByteStr fontDictStr = (*fdArray)[i];
+	const byte_str_t fontDictStr = (*fdArray)[i];
 	if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
-	CFF2FontDictValues  *font;
-	CFF2FontDict_Interpreter font_interp;
+	cff2_font_dict_values_t  *font;
+	cff2_font_dict_interpreter_t font_interp;
 	font_interp.env.init (fontDictStr);
 	font = fontDicts.push ();
-	if (unlikely (font == &Crap(CFF2FontDictValues))) { fini (); return; }
+	if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; }
 	font->init ();
 	if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 
-	const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
+	const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
 	if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
-	DictInterpreter<PRIVOPSET, PRIVDICTVAL, CFF2PrivDictInterpEnv>  priv_interp;
+	dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t>  priv_interp;
 	priv_interp.env.init(privDictStr);
 	privateDicts[i].init ();
 	if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
 
-	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (privDictStr.str, privateDicts[i].subrsOffset);
+	privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
 	if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
 	  unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
 	{ fini (); return; }
@@ -496,6 +500,7 @@
     void fini ()
     {
       sc.end_processing ();
+      topDict.fini ();
       fontDicts.fini_deep ();
       privateDicts.fini_deep ();
       hb_blob_destroy (blob);
@@ -505,32 +510,32 @@
     bool is_valid () const { return blob != nullptr; }
 
     protected:
-    hb_blob_t	       *blob;
-    hb_sanitize_context_t   sc;
+    hb_blob_t			*blob;
+    hb_sanitize_context_t	sc;
 
     public:
-    CFF2TopDictValues	 topDict;
-    const CFF2Subrs	   *globalSubrs;
-    const CFF2VariationStore  *varStore;
-    const CFF2CharStrings     *charStrings;
-    const CFF2FDArray	 *fdArray;
-    const CFF2FDSelect	*fdSelect;
-    unsigned int	      fdCount;
+    cff2_top_dict_values_t	topDict;
+    const CFF2Subrs		*globalSubrs;
+    const CFF2VariationStore	*varStore;
+    const CFF2CharStrings	*charStrings;
+    const CFF2FDArray		*fdArray;
+    const CFF2FDSelect		*fdSelect;
+    unsigned int		fdCount;
 
-    hb_vector_t<CFF2FontDictValues>     fontDicts;
+    hb_vector_t<cff2_font_dict_values_t>     fontDicts;
     hb_vector_t<PRIVDICTVAL>  privateDicts;
 
-    unsigned int	    num_glyphs;
+    unsigned int	      num_glyphs;
   };
 
-  struct accelerator_t : accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues>
+  struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
   {
     HB_INTERNAL bool get_extents (hb_font_t *font,
 				  hb_codepoint_t glyph,
 				  hb_glyph_extents_t *extents) const;
   };
 
-  typedef accelerator_templ_t<CFF2PrivateDictOpSet_Subset, CFF2PrivateDictValues_Subset> accelerator_subset_t;
+  typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
 
   bool subset (hb_subset_plan_t *plan) const
   {
@@ -551,9 +556,9 @@
   }
 
   public:
-  FixedVersion<HBUINT8> version;	/* Version of CFF2 table. set to 0x0200u */
-  OffsetTo<TopDict, HBUINT8, false> topDict;   /* headerSize = Offset to Top DICT. */
-  HBUINT16       topDictSize;	   /* Top DICT size */
+  FixedVersion<HBUINT8>		version;	/* Version of CFF2 table. set to 0x0200u */
+  NNOffsetTo<TopDict, HBUINT8>	topDict;	/* headerSize = Offset to Top DICT. */
+  HBUINT16			topDictSize;	/* Top DICT size */
 
   public:
   DEFINE_SIZE_STATIC (5);
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 7567e52..9ebd8e4 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -74,154 +74,201 @@
 
 struct CmapSubtableFormat4
 {
-  struct segment_plan
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_endcode_array (hb_serialize_context_t *c,
+				     Iterator it)
   {
-    HBUINT16 start_code;
-    HBUINT16 end_code;
-    bool use_delta;
-  };
+    HBUINT16 *endCode = c->start_embed<HBUINT16> ();
+    hb_codepoint_t prev_endcp = 0xFFFF;
 
-  bool serialize (hb_serialize_context_t *c,
-		  const hb_subset_plan_t *plan,
-		  const hb_vector_t<segment_plan> &segments)
-  {
-    TRACE_SERIALIZE (this);
+    + it
+    | hb_apply ([&] (const hb_item_type<Iterator> _)
+		{
+		  if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
+		  {
+		    HBUINT16 end_code;
+		    end_code = prev_endcp;
+		    c->copy<HBUINT16> (end_code);
+		  }
+		  prev_endcp = _.first;
+		})
+    ;
 
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-
-    this->format.set (4);
-    this->length.set (get_sub_table_size (segments));
-
-    this->segCountX2.set (segments.len * 2);
-    this->entrySelector.set (MAX (1u, hb_bit_storage (segments.len)) - 1);
-    this->searchRange.set (2 * (1u << this->entrySelector));
-    this->rangeShift.set (segments.len * 2 > this->searchRange
-			  ? 2 * segments.len - this->searchRange
-			  : 0);
-
-    HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
-    c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
-    HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
-    HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
-    HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
-
-    if (id_range_offset == nullptr)
-      return_trace (false);
-
-    for (unsigned int i = 0; i < segments.len; i++)
     {
-      end_count[i].set (segments[i].end_code);
-      start_count[i].set (segments[i].start_code);
-      if (segments[i].use_delta)
+      // last endCode
+      HBUINT16 endcode;
+      endcode = prev_endcp;
+      if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr;
+      // There must be a final entry with end_code == 0xFFFF.
+      if (prev_endcp != 0xFFFF)
       {
-	hb_codepoint_t cp = segments[i].start_code;
-	hb_codepoint_t start_gid = 0;
-	if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
-	  return_trace (false);
-	id_delta[i].set (start_gid - segments[i].start_code);
-      } else {
-	id_delta[i].set (0);
-	unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
-	HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
-	if (glyph_id_array == nullptr)
-	  return_trace (false);
-	// From the cmap spec:
-	//
-	// id_range_offset[i]/2
-	// + (cp - segments[i].start_code)
-	// + (id_range_offset + i)
-	// =
-	// glyph_id_array + (cp - segments[i].start_code)
-	//
-	// So, solve for id_range_offset[i]:
-	//
-	// id_range_offset[i]
-	// =
-	// 2 * (glyph_id_array - id_range_offset - i)
-	id_range_offset[i].set (2 * (
-	    glyph_id_array - id_range_offset - i));
-	for (unsigned int j = 0; j < num_codepoints; j++)
-	{
-	  hb_codepoint_t cp = segments[i].start_code + j;
-	  hb_codepoint_t new_gid;
-	  if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-	    return_trace (false);
-	  glyph_id_array[j].set (new_gid);
-	}
+	HBUINT16 finalcode;
+	finalcode = 0xFFFF;
+	if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
       }
     }
 
-    return_trace (true);
+    return endCode;
   }
 
-  static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_startcode_array (hb_serialize_context_t *c,
+				       Iterator it)
   {
-    size_t segment_size = 0;
-    for (unsigned int i = 0; i < segments.len; i++)
-    {
-      // Parallel array entries
-      segment_size +=
-	    2  // end count
-	  + 2  // start count
-	  + 2  // delta
-	  + 2; // range offset
+    HBUINT16 *startCode = c->start_embed<HBUINT16> ();
+    hb_codepoint_t prev_cp = 0xFFFF;
 
-      if (!segments[i].use_delta)
-	// Add bytes for the glyph index array entries for this segment.
-	segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
+    + it
+    | hb_apply ([&] (const hb_item_type<Iterator> _)
+		{
+		  if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
+		  {
+		    HBUINT16 start_code;
+		    start_code = _.first;
+		    c->copy<HBUINT16> (start_code);
+		  }
+
+		  prev_cp = _.first;
+		})
+    ;
+
+    // There must be a final entry with end_code == 0xFFFF.
+    if (it.len () == 0 || prev_cp != 0xFFFF)
+    {
+      HBUINT16 finalcode;
+      finalcode = 0xFFFF;
+      if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
     }
 
-    return min_size
-	+ 2 // Padding
-	+ segment_size;
+    return startCode;
   }
 
-  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
-				     hb_vector_t<segment_plan> *segments)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  HBINT16* serialize_idDelta_array (hb_serialize_context_t *c,
+				     Iterator it,
+				     HBUINT16 *endCode,
+				     HBUINT16 *startCode,
+				     unsigned segcount)
   {
-    segment_plan *segment = nullptr;
-    hb_codepoint_t last_gid = 0;
+    unsigned i = 0;
+    hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF;
+    bool use_delta = true;
 
-    hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-    while (plan->unicodes->next (&cp)) {
-      hb_codepoint_t new_gid;
-      if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
-	return false;
-      }
+    HBINT16 *idDelta = c->start_embed<HBINT16> ();
+    if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
+      return nullptr;
 
-      /* Stop adding to cmap if we are now outside of unicode BMP. */
-      if (cp > 0xFFFF) break;
+    + it
+    | hb_apply ([&] (const hb_item_type<Iterator> _)
+		{
+		  if (_.first == startCode[i])
+		  {
+		    use_delta = true;
+		    start_gid = _.second;
+		  }
+		  else if (_.second != last_gid + 1) use_delta = false;
 
-      if (!segment ||
-	  cp != segment->end_code + 1u)
-      {
-	segment = segments->push ();
-	segment->start_code.set (cp);
-	segment->end_code.set (cp);
-	segment->use_delta = true;
-      } else {
-	segment->end_code.set (cp);
-	if (last_gid + 1u != new_gid)
-	  // gid's are not consecutive in this segment so delta
-	  // cannot be used.
-	  segment->use_delta = false;
-      }
+		  if (_.first == endCode[i])
+		  {
+		    HBINT16 delta;
+		    if (use_delta) delta = (int)start_gid - (int)startCode[i];
+		    else delta = 0;
+		    c->copy<HBINT16> (delta);
 
-      last_gid = new_gid;
-    }
+		    i++;
+		  }
 
-    // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
-    if (segment == nullptr || segment->end_code != 0xFFFF)
+		  last_gid = _.second;
+		  last_cp = _.first;
+		})
+    ;
+
+    if (it.len () == 0 || last_cp != 0xFFFF)
     {
-      segment = segments->push ();
-      segment->start_code.set (0xFFFF);
-      segment->end_code.set (0xFFFF);
-      segment->use_delta = true;
+      HBINT16 delta;
+      delta = 1;
+      if (unlikely (!c->copy<HBINT16> (delta))) return nullptr;
     }
 
-    return true;
+    return idDelta;
+  }
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
+					 Iterator it,
+					 HBUINT16 *endCode,
+					 HBUINT16 *startCode,
+					 HBINT16 *idDelta,
+					 unsigned segcount)
+  {
+    HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+    if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
+    if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
+
+    + hb_range (segcount)
+    | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
+    | hb_apply ([&] (const unsigned i)
+		{
+		  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+
+		  + it
+		  | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
+		  | hb_apply ([&] (const hb_item_type<Iterator> _)
+			      {
+				HBUINT16 glyID;
+				glyID = _.second;
+				c->copy<HBUINT16> (glyID);
+			      })
+		  ;
+
+
+		})
+    ;
+
+    return idRangeOffset;
+  }
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it)
+  {
+    unsigned table_initpos = c->length ();
+    if (unlikely (!c->extend_min (*this))) return;
+    this->format = 4;
+
+    //serialize endCode[]
+    HBUINT16 *endCode = serialize_endcode_array (c, it);
+    if (unlikely (!endCode)) return;
+
+    unsigned segcount = (c->length () - min_size) / HBUINT16::static_size;
+
+    // 2 bytes of padding.
+    if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding.
+
+   // serialize startCode[]
+    HBUINT16 *startCode = serialize_startcode_array (c, it);
+    if (unlikely (!startCode)) return;
+
+    //serialize idDelta[]
+    HBINT16 *idDelta = serialize_idDelta_array (c, it, endCode, startCode, segcount);
+    if (unlikely (!idDelta)) return;
+
+    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, it, endCode, startCode, idDelta, segcount);
+    if (unlikely (!c->check_success (idRangeOffset))) return;
+
+    if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return;
+    this->segCountX2 = segcount * 2;
+    this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
+    this->searchRange = 2 * (1u << this->entrySelector);
+    this->rangeShift = segcount * 2 > this->searchRange
+		       ? 2 * segcount - this->searchRange
+		       : 0;
   }
 
   struct accelerator_t
@@ -286,10 +333,8 @@
       *glyph = gid;
       return true;
     }
-    static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
-    {
-      return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
-    }
+    HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+    { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
     void collect_unicodes (hb_set_t *out) const
     {
       unsigned int count = this->segCount;
@@ -297,14 +342,22 @@
 	count--; /* Skip sentinel segment. */
       for (unsigned int i = 0; i < count; i++)
       {
+	hb_codepoint_t start = this->startCount[i];
+	hb_codepoint_t end = this->endCount[i];
 	unsigned int rangeOffset = this->idRangeOffset[i];
 	if (rangeOffset == 0)
-	  out->add_range (this->startCount[i], this->endCount[i]);
+	{
+	  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+	  {
+	    hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
+	    if (unlikely (!gid))
+	      continue;
+	    out->add (codepoint);
+	  }
+	}
 	else
 	{
-	  for (hb_codepoint_t codepoint = this->startCount[i];
-	       codepoint <= this->endCount[i];
-	       codepoint++)
+	  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
 	  {
 	    unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
 	    if (unlikely (index >= this->glyphIdArrayLength))
@@ -349,7 +402,7 @@
       /* Some broken fonts have too long of a "length" value.
        * If that is the case, just change the value to truncate
        * the subtable at the end of the blob. */
-      uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
+      uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
 					    (uintptr_t) (c->end -
 							 (char *) this));
       if (!c->try_set (&length, new_length))
@@ -451,7 +504,7 @@
   UINT		length;		/* Byte length of this subtable. */
   UINT		language;	/* Ignore. */
   UINT		startCharCode;	/* First character code covered. */
-  ArrayOf<GlyphID, UINT>
+  ArrayOf<HBGlyphID, UINT>
 		glyphIdArray;	/* Array of glyph index values for character
 				 * codes in the range. */
   public:
@@ -477,10 +530,18 @@
 
   void collect_unicodes (hb_set_t *out) const
   {
-    for (unsigned int i = 0; i < this->groups.len; i++) {
-      out->add_range (this->groups[i].startCharCode,
-		      MIN ((hb_codepoint_t) this->groups[i].endCharCode,
-			   (hb_codepoint_t) HB_UNICODE_MAX));
+    for (unsigned int i = 0; i < this->groups.len; i++)
+    {
+      hb_codepoint_t start = this->groups[i].startCharCode;
+      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
+				   (hb_codepoint_t) HB_UNICODE_MAX);
+      for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+      {
+	hb_codepoint_t gid = T::group_get_glyph (this->groups[i], codepoint);
+	if (unlikely (!gid))
+	  continue;
+	out->add (codepoint);
+      }
     }
   }
 
@@ -490,15 +551,6 @@
     return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
-  bool serialize (hb_serialize_context_t *c,
-		  const hb_vector_t<CmapSubtableLongGroup> &group_data)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
-    return true;
-  }
-
   protected:
   HBUINT16	format;		/* Subtable format; set to 12. */
   HBUINT16	reserved;	/* Reserved; set to 0. */
@@ -518,63 +570,70 @@
 	   group.glyphID + (u - group.startCharCode) : 0; }
 
 
-  bool serialize (hb_serialize_context_t *c,
-		  const hb_vector_t<CmapSubtableLongGroup> &groups)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it)
   {
-    if (unlikely (!c->extend_min (*this))) return false;
+    if (it.len () == 0) return;
+    unsigned table_initpos = c->length ();
+    if (unlikely (!c->extend_min (*this))) return;
 
-    this->format.set (12);
-    this->reserved.set (0);
-    this->length.set (get_sub_table_size (groups));
+    hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
+    hb_codepoint_t glyphID = 0;
 
-    return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
+    + it
+    | hb_apply ([&] (const hb_item_type<Iterator> _)
+	      {
+		if (startCharCode == 0xFFFF)
+		{
+		  startCharCode = _.first;
+		  endCharCode = _.first;
+		  glyphID = _.second;
+		}
+		else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
+		{
+		  CmapSubtableLongGroup  grouprecord;
+		  grouprecord.startCharCode = startCharCode;
+		  grouprecord.endCharCode = endCharCode;
+		  grouprecord.glyphID = glyphID;
+		  c->copy<CmapSubtableLongGroup> (grouprecord);
+
+		  startCharCode = _.first;
+		  endCharCode = _.first;
+		  glyphID = _.second;
+		}
+		else
+		{
+		  endCharCode = _.first;
+		}
+	      })
+    ;
+
+    CmapSubtableLongGroup record;
+    record.startCharCode = startCharCode;
+    record.endCharCode = endCharCode;
+    record.glyphID = glyphID;
+    c->copy<CmapSubtableLongGroup> (record);
+
+    this->format = 12;
+    this->reserved = 0;
+    this->length = c->length () - table_initpos;
+    this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size;
   }
 
-  static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
-  {
-    return 16 + 12 * groups.len;
-  }
+  static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
+  { return 16 + 12 * groups_data.length; }
 
-  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
-				     hb_vector_t<CmapSubtableLongGroup> *groups)
-  {
-    CmapSubtableLongGroup *group = nullptr;
-
-    hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-    while (plan->unicodes->next (&cp)) {
-      hb_codepoint_t new_gid;
-      if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
-	return false;
-      }
-
-      if (!group || !_is_gid_consecutive (group, cp, new_gid))
-      {
-	group = groups->push ();
-	group->startCharCode.set (cp);
-	group->endCharCode.set (cp);
-	group->glyphID.set (new_gid);
-      }
-      else group->endCharCode.set (cp);
-    }
-
-    DEBUG_MSG(SUBSET, nullptr, "cmap");
-    for (unsigned int i = 0; i < groups->len; i++) {
-      CmapSubtableLongGroup& group = (*groups)[i];
-      DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
-    }
-
-    return true;
-  }
-
- private:
-  static bool _is_gid_consecutive (CmapSubtableLongGroup *group,
+  private:
+  static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
+				   hb_codepoint_t startCharCode,
+				   hb_codepoint_t glyphID,
 				   hb_codepoint_t cp,
 				   hb_codepoint_t new_gid)
   {
-    return (cp - 1 == group->endCharCode) &&
-	new_gid == group->glyphID + (cp - group->startCharCode);
+    return (cp - 1 == endCharCode) &&
+	new_gid == glyphID + (cp - startCharCode);
   }
 
 };
@@ -623,12 +682,69 @@
     for (unsigned int i = 0; i < count; i++)
     {
       hb_codepoint_t first = arrayZ[i].startUnicodeValue;
-      hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
+      hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
 				 (hb_codepoint_t) HB_UNICODE_MAX);
       out->add_range (first, last);
     }
   }
 
+  DefaultUVS* copy (hb_serialize_context_t *c,
+		    const hb_set_t *unicodes) const
+  {
+    DefaultUVS *out = c->start_embed<DefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+    auto snap = c->snapshot ();
+
+    HBUINT32 len;
+    len = 0;
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+    unsigned init_len = c->length ();
+
+    hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
+    int count = -1;
+
+    for (const UnicodeValueRange& _ : as_array ())
+    {
+      for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
+      {
+	unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
+	if (!unicodes->has (curEntry)) continue;
+	count += 1;
+	if (lastCode == HB_MAP_VALUE_INVALID)
+	  lastCode = curEntry;
+	else if (lastCode + count != curEntry)
+	{
+	  UnicodeValueRange rec;
+	  rec.startUnicodeValue = lastCode;
+	  rec.additionalCount = count - 1;
+	  c->copy<UnicodeValueRange> (rec);
+
+	  lastCode = curEntry;
+	  count = 0;
+	}
+      }
+    }
+
+    if (lastCode != HB_MAP_VALUE_INVALID)
+    {
+      UnicodeValueRange rec;
+      rec.startUnicodeValue = lastCode;
+      rec.additionalCount = count;
+      c->copy<UnicodeValueRange> (rec);
+    }
+
+    if (c->length () - init_len == 0)
+    {
+      c->revert (snap);
+      return nullptr;
+    }
+    else
+    {
+      if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
+      return out;
+    }
+  }
+
   public:
   DEFINE_SIZE_ARRAY (4, *this);
 };
@@ -636,9 +752,7 @@
 struct UVSMapping
 {
   int cmp (const hb_codepoint_t &codepoint) const
-  {
-    return unicodeValue.cmp (codepoint);
-  }
+  { return unicodeValue.cmp (codepoint); }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -647,7 +761,7 @@
   }
 
   HBUINT24	unicodeValue;	/* Base Unicode value of the UVS */
-  GlyphID	glyphID;	/* Glyph ID of the UVS */
+  HBGlyphID	glyphID;	/* Glyph ID of the UVS */
   public:
   DEFINE_SIZE_STATIC (5);
 };
@@ -661,6 +775,49 @@
       out->add (arrayZ[i].glyphID);
   }
 
+  void closure_glyphs (const hb_set_t      *unicodes,
+		       hb_set_t            *glyphset) const
+  {
+    + as_array ()
+    | hb_filter (unicodes, &UVSMapping::unicodeValue)
+    | hb_map (&UVSMapping::glyphID)
+    | hb_sink (glyphset)
+    ;
+  }
+
+  NonDefaultUVS* copy (hb_serialize_context_t *c,
+		       const hb_set_t *unicodes,
+		       const hb_set_t *glyphs,
+		       const hb_map_t *glyph_map) const
+  {
+    NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+
+    auto it =
+    + as_array ()
+    | hb_filter ([&] (const UVSMapping& _)
+		 {
+		   return unicodes->has (_.unicodeValue) || glyphs->has (_.glyphID);
+		 })
+    ;
+
+    if (!it) return nullptr;
+
+    HBUINT32 len;
+    len = it.len ();
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+
+    for (const UVSMapping& _ : it)
+    {
+      UVSMapping mapping;
+      mapping.unicodeValue = _.unicodeValue;
+      mapping.glyphID = glyph_map->get (_.glyphID);
+      c->copy<UVSMapping> (mapping);
+    }
+
+    return out;
+  }
+
   public:
   DEFINE_SIZE_ARRAY (4, *this);
 };
@@ -689,9 +846,7 @@
   }
 
   int cmp (const hb_codepoint_t &variation_selector) const
-  {
-    return varSelector.cmp (variation_selector);
-  }
+  { return varSelector.cmp (variation_selector); }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
@@ -701,6 +856,52 @@
 		  nonDefaultUVS.sanitize (c, base));
   }
 
+  VariationSelectorRecord* copy (hb_serialize_context_t *c,
+				 const hb_set_t *unicodes,
+				 const hb_set_t *glyphs,
+				 const hb_map_t *glyph_map,
+				 const void *src_base,
+				 const void *dst_base) const
+  {
+    auto snap = c->snapshot ();
+    auto *out = c->embed<VariationSelectorRecord> (*this);
+    if (unlikely (!out)) return nullptr;
+
+    out->defaultUVS = 0;
+    out->nonDefaultUVS = 0;
+
+    bool drop = true;
+
+    if (defaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (src_base+defaultUVS, unicodes))
+      {
+	c->add_link (out->defaultUVS, c->pop_pack (), dst_base);
+	drop = false;
+      }
+      else c->pop_discard ();
+    }
+
+    if (nonDefaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (src_base+nonDefaultUVS, unicodes, glyphs, glyph_map))
+      {
+	c->add_link (out->nonDefaultUVS, c->pop_pack (), dst_base);
+	drop = false;
+      }
+      else c->pop_discard ();
+    }
+
+    if (drop)
+    {
+      c->revert (snap);
+      return nullptr;
+    }
+    else return out;
+  }
+
   HBUINT24	varSelector;	/* Variation selector. */
   LOffsetTo<DefaultUVS>
 		defaultUVS;	/* Offset to Default UVS Table.  May be 0. */
@@ -715,9 +916,7 @@
   glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
 				     hb_codepoint_t variation_selector,
 				     hb_codepoint_t *glyph) const
-  {
-    return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this);
-  }
+  { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
 
   void collect_variation_selectors (hb_set_t *out) const
   {
@@ -727,8 +926,44 @@
   }
   void collect_variation_unicodes (hb_codepoint_t variation_selector,
 				   hb_set_t *out) const
+  { record.bsearch (variation_selector).collect_unicodes (out, this); }
+
+  void serialize (hb_serialize_context_t *c,
+		  const hb_set_t *unicodes,
+		  const hb_set_t *glyphs,
+		  const hb_map_t *glyph_map,
+		  const void *src_base)
   {
-    record.bsearch (variation_selector).collect_unicodes (out, this);
+    auto snap = c->snapshot ();
+    unsigned table_initpos = c->length ();
+    const char* init_tail = c->tail;
+
+    if (unlikely (!c->extend_min (*this))) return;
+    this->format = 14;
+
+    const CmapSubtableFormat14 *src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (src_base);
+    for (const VariationSelectorRecord& _ : src_tbl->record)
+      c->copy (_, unicodes, glyphs, glyph_map, src_base, this);
+
+    if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
+      c->revert (snap);
+    else
+    {
+      int tail_len = init_tail - c->tail;
+      c->check_assign (this->length, c->length () - table_initpos + tail_len);
+      c->check_assign (this->record.len, (c->length () - table_initpos - CmapSubtableFormat14::min_size) / VariationSelectorRecord::static_size);
+    }
+  }
+
+  void closure_glyphs (const hb_set_t      *unicodes,
+		       hb_set_t            *glyphset) const
+  {
+    + hb_iter (record)
+    | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
+    | hb_map (&VariationSelectorRecord::nonDefaultUVS)
+    | hb_map (hb_add (this))
+    | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
+    ;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -780,6 +1015,22 @@
     }
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  unsigned format,
+		  const hb_subset_plan_t *plan,
+		  const void *src_base)
+  {
+    switch (format) {
+    case  4: u.format4.serialize (c, it);  return;
+    case 12: u.format12.serialize (c, it); return;
+    case 14: u.format14.serialize (c, plan->unicodes, plan->_glyphset, plan->glyph_map, src_base); return;
+    default: return;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -831,6 +1082,41 @@
 		  subtable.sanitize (c, base));
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  EncodingRecord* copy (hb_serialize_context_t *c,
+			Iterator it,
+			unsigned format,
+			const void *src_base,
+			const void *dst_base,
+			const hb_subset_plan_t *plan,
+			/* INOUT */ unsigned *objidx) const
+  {
+    TRACE_SERIALIZE (this);
+    auto snap = c->snapshot ();
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+    out->subtable = 0;
+
+    if (*objidx == 0)
+    {
+      CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
+      unsigned origin_length = c->length ();
+      cmapsubtable->serialize (c, it, format, plan, &(src_base+subtable));
+      if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
+      else c->pop_discard ();
+    }
+
+    if (*objidx == 0)
+    {
+      c->revert (snap);
+      return_trace (nullptr);
+    }
+
+    c->add_link (out->subtable, *objidx, dst_base);
+    return_trace (out);
+  }
+
   HBUINT16	platformID;	/* Platform ID. */
   HBUINT16	encodingID;	/* Platform-specific encoding ID. */
   LOffsetTo<CmapSubtable>
@@ -841,126 +1127,101 @@
 
 struct cmap
 {
-  enum { tableTag = HB_OT_TAG_cmap };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
-  struct subset_plan
+  template<typename Iterator, typename EncodingRecIter,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  EncodingRecIter encodingrec_iter,
+		  const void *src_base,
+		  const hb_subset_plan_t *plan)
   {
-    size_t final_size () const
+    if (unlikely (!c->extend_min ((*this))))  return;
+    this->version = 0;
+
+    unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
+
+    for (const EncodingRecord& _ : encodingrec_iter)
     {
-      return 4 // header
-	  +  8 * 3 // 3 EncodingRecord
-	  +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
-	  +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
+      unsigned format = (src_base+_.subtable).u.format;
+
+      if (format == 4) c->copy (_, it, 4u, src_base, this, plan, &format4objidx);
+      else if (format == 12) c->copy (_, it, 12u, src_base, this, plan, &format12objidx);
+      else if (format == 14) c->copy (_, it, 14u, src_base, this, plan, &format14objidx);
     }
 
-    hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
-    hb_vector_t<CmapSubtableLongGroup> format12_groups;
-  };
-
-  bool _create_plan (const hb_subset_plan_t *plan,
-		     subset_plan *cmap_plan) const
-  {
-    if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
-      return false;
-
-    return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
+    c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
   }
 
-  bool _subset (const hb_subset_plan_t *plan,
-		const subset_plan &cmap_subset_plan,
-		size_t dest_sz,
-		void *dest) const
+  void closure_glyphs (const hb_set_t      *unicodes,
+		       hb_set_t            *glyphset) const
   {
-    hb_serialize_context_t c (dest, dest_sz);
-
-    cmap *table = c.start_serialize<cmap> ();
-    if (unlikely (!c.extend_min (*table)))
-    {
-      return false;
-    }
-
-    table->version.set (0);
-
-    if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
-      return false;
-
-    // TODO(grieger): Convert the below to a for loop
-
-    // Format 4, Plat 0 Encoding Record
-    EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
-    format4_plat0_rec.platformID.set (0); // Unicode
-    format4_plat0_rec.encodingID.set (3);
-
-    // Format 4, Plat 3 Encoding Record
-    EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
-    format4_plat3_rec.platformID.set (3); // Windows
-    format4_plat3_rec.encodingID.set (1); // Unicode BMP
-
-    // Format 12 Encoding Record
-    EncodingRecord &format12_rec = table->encodingRecord[2];
-    format12_rec.platformID.set (3); // Windows
-    format12_rec.encodingID.set (10); // Unicode UCS-4
-
-    // Write out format 4 sub table
-    {
-      CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
-      format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
-      subtable.u.format.set (4);
-
-      CmapSubtableFormat4 &format4 = subtable.u.format4;
-      if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
-	return false;
-    }
-
-    // Write out format 12 sub table.
-    {
-      CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
-      subtable.u.format.set (12);
-
-      CmapSubtableFormat12 &format12 = subtable.u.format12;
-      if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
-	return false;
-    }
-
-    c.end_serialize ();
-
-    return true;
+    + hb_iter (encodingRecord)
+    | hb_map (&EncodingRecord::subtable)
+    | hb_map (hb_add (this))
+    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
+    | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
+    ;
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    subset_plan cmap_subset_plan;
+    TRACE_SUBSET (this);
 
-    if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
+    cmap *cmap_prime = c->serializer->start_embed<cmap> ();
+    if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
+
+    auto encodingrec_iter =
+    + hb_iter (encodingRecord)
+    | hb_filter ([&] (const EncodingRecord& _)
+		{
+		  if ((_.platformID == 0 && _.encodingID == 3) ||
+		      (_.platformID == 0 && _.encodingID == 4) ||
+		      (_.platformID == 3 && _.encodingID == 1) ||
+		      (_.platformID == 3 && _.encodingID == 10) ||
+		      (this + _.subtable).u.format == 14)
+		    return true;
+
+		  return false;
+		})
+    ;
+
+
+    if (unlikely (!encodingrec_iter.len ())) return_trace (false);
+
+    const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
+    bool has_format12 = false;
+
+    for (const EncodingRecord& _ : encodingrec_iter)
     {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
-      return false;
+      unsigned format = (this + _.subtable).u.format;
+      if (format == 12) has_format12 = true;
+
+      const EncodingRecord *table = hb_addressof (_);
+      if      (_.platformID == 0 && _.encodingID ==  3) unicode_bmp = table;
+      else if (_.platformID == 0 && _.encodingID ==  4) unicode_ucs4 = table;
+      else if (_.platformID == 3 && _.encodingID ==  1) ms_bmp = table;
+      else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
     }
 
-    // We now know how big our blob needs to be
-    size_t dest_sz = cmap_subset_plan.final_size ();
-    void *dest = malloc (dest_sz);
-    if (unlikely (!dest)) {
-      DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
-      return false;
-    }
+    if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false);
+    if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
 
-    if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
-      free (dest);
-      return false;
-    }
+    auto it =
+    + hb_iter (c->plan->unicodes)
+    | hb_map ([&] (hb_codepoint_t _)
+	      {
+		hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID;
+		c->plan->new_gid_for_codepoint (_, &new_gid);
+		return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
+	      })
+    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+		 { return (_.second != HB_MAP_VALUE_INVALID); })
+    ;
 
-    // all done, write the blob into dest
-    hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest,
-					    dest_sz,
-					    HB_MEMORY_MODE_READONLY,
-					    dest,
-					    free);
-    bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
-    hb_blob_destroy (cmap_prime);
-    return result;
+    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
+    return_trace (true);
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -969,6 +1230,15 @@
 
     const CmapSubtable *subtable;
 
+    /* Symbol subtable.
+     * Prefer symbol if available.
+     * https://github.com/harfbuzz/harfbuzz/issues/1918 */
+    if ((subtable = this->find_subtable (3, 0)))
+    {
+      if (symbol) *symbol = true;
+      return subtable;
+    }
+
     /* 32-bit subtables. */
     if ((subtable = this->find_subtable (3, 10))) return subtable;
     if ((subtable = this->find_subtable (0, 6))) return subtable;
@@ -981,13 +1251,6 @@
     if ((subtable = this->find_subtable (0, 1))) return subtable;
     if ((subtable = this->find_subtable (0, 0))) return subtable;
 
-    /* Symbol subtable. */
-    if ((subtable = this->find_subtable (3, 0)))
-    {
-      if (symbol) *symbol = true;
-      return subtable;
-    }
-
     /* Meh. */
     return &Null (CmapSubtable);
   }
@@ -1008,9 +1271,9 @@
 
       this->get_glyph_data = subtable;
       if (unlikely (symbol))
-      {
 	this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
-      } else {
+      else
+      {
 	switch (subtable->u.format) {
 	/* Accelerate format 4 and format 12. */
 	default:
@@ -1020,20 +1283,20 @@
 	  this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
 	  break;
 	case  4:
-	  {
-	    this->format4_accel.init (&subtable->u.format4);
-	    this->get_glyph_data = &this->format4_accel;
-	    this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
-	  }
+	{
+	  this->format4_accel.init (&subtable->u.format4);
+	  this->get_glyph_data = &this->format4_accel;
+	  this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
 	  break;
 	}
+	}
       }
     }
 
     void fini () { this->table.destroy (); }
 
     bool get_nominal_glyph (hb_codepoint_t  unicode,
-				   hb_codepoint_t *glyph) const
+			    hb_codepoint_t *glyph) const
     {
       if (unlikely (!this->get_glyph_funcZ)) return false;
       return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
@@ -1054,8 +1317,8 @@
 	   done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
 	   done++)
       {
-	first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-	first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+	first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+	first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       }
       return done;
     }
@@ -1077,18 +1340,12 @@
     }
 
     void collect_unicodes (hb_set_t *out) const
-    {
-      subtable->collect_unicodes (out);
-    }
+    { subtable->collect_unicodes (out); }
     void collect_variation_selectors (hb_set_t *out) const
-    {
-      subtable_uvs->collect_variation_selectors (out);
-    }
+    { subtable_uvs->collect_variation_selectors (out); }
     void collect_variation_unicodes (hb_codepoint_t variation_selector,
 				     hb_set_t *out) const
-    {
-      subtable_uvs->collect_variation_unicodes (variation_selector, out);
-    }
+    { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
 
     protected:
     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
@@ -1096,18 +1353,18 @@
 					      hb_codepoint_t *glyph);
 
     template <typename Type>
-    static bool get_glyph_from (const void *obj,
-				hb_codepoint_t codepoint,
-				hb_codepoint_t *glyph)
+    HB_INTERNAL static bool get_glyph_from (const void *obj,
+					    hb_codepoint_t codepoint,
+					    hb_codepoint_t *glyph)
     {
       const Type *typed_obj = (const Type *) obj;
       return typed_obj->get_glyph (codepoint, glyph);
     }
 
     template <typename Type>
-    static bool get_glyph_from_symbol (const void *obj,
-					      hb_codepoint_t codepoint,
-					      hb_codepoint_t *glyph)
+    HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
+						   hb_codepoint_t codepoint,
+						   hb_codepoint_t *glyph)
     {
       const Type *typed_obj = (const Type *) obj;
       if (likely (typed_obj->get_glyph (codepoint, glyph)))
@@ -1135,6 +1392,7 @@
 
     CmapSubtableFormat4::accelerator_t format4_accel;
 
+    public:
     hb_blob_ptr_t<cmap> table;
   };
 
@@ -1144,8 +1402,8 @@
 				     unsigned int encoding_id) const
   {
     EncodingRecord key;
-    key.platformID.set (platform_id);
-    key.encodingID.set (encoding_id);
+    key.platformID = platform_id;
+    key.encodingID = encoding_id;
 
     const EncodingRecord &result = encodingRecord.bsearch (key);
     if (!result.subtable)
@@ -1154,6 +1412,28 @@
     return &(this+result.subtable);
   }
 
+  const EncodingRecord *find_encodingrec (unsigned int platform_id,
+				    unsigned int encoding_id) const
+  {
+    EncodingRecord key;
+    key.platformID = platform_id;
+    key.encodingID = encoding_id;
+
+    return encodingRecord.as_array ().bsearch (key);
+  }
+
+  bool find_subtable (unsigned format) const
+  {
+    auto it =
+    + hb_iter (encodingRecord)
+    | hb_map (&EncodingRecord::subtable)
+    | hb_map (hb_add (this))
+    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
+    ;
+
+    return it.len ();
+  }
+
   public:
 
   bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index b1971a7..3498d3b 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -51,12 +51,12 @@
     return_trace (c->check_struct (this));
   }
 
-  void get_extents (hb_glyph_extents_t *extents) const
+  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
   {
-    extents->x_bearing = bearingX;
-    extents->y_bearing = bearingY;
-    extents->width = width;
-    extents->height = -height;
+    extents->x_bearing = font->em_scale_x (bearingX);
+    extents->y_bearing = font->em_scale_y (bearingY);
+    extents->width = font->em_scale_x (width);
+    extents->height = font->em_scale_y (-height);
   }
 
   HBUINT8	height;
@@ -144,7 +144,7 @@
   }
 
   IndexSubtableHeader	header;
-  UnsizedArrayOf<Offset<OffsetType> >
+  UnsizedArrayOf<Offset<OffsetType>>
  			offsetArrayZ;
   public:
   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
@@ -226,8 +226,8 @@
 						   offset, length, format);
   }
 
-  GlyphID			firstGlyphIndex;
-  GlyphID			lastGlyphIndex;
+  HBGlyphID			firstGlyphIndex;
+  HBGlyphID			lastGlyphIndex;
   LOffsetTo<IndexSubtable>	offsetToSubtable;
   public:
   DEFINE_SIZE_STATIC(8);
@@ -251,7 +251,7 @@
       unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
       unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
       if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
-        return &indexSubtablesZ[i];
+	return &indexSubtablesZ[i];
     }
     return nullptr;
   }
@@ -283,15 +283,15 @@
   }
 
   protected:
-  LOffsetTo<IndexSubtableArray, false>
+  LNNOffsetTo<IndexSubtableArray>
 			indexSubtableArrayOffset;
   HBUINT32		indexTablesSize;
   HBUINT32		numberOfIndexSubtables;
   HBUINT32		colorRef;
   SBitLineMetrics	horizontal;
   SBitLineMetrics	vertical;
-  GlyphID		startGlyphIndex;
-  GlyphID		endGlyphIndex;
+  HBGlyphID		startGlyphIndex;
+  HBGlyphID		endGlyphIndex;
   HBUINT8		ppemX;
   HBUINT8		ppemY;
   HBUINT8		bitDepth;
@@ -332,7 +332,7 @@
 {
   friend struct CBDT;
 
-  enum { tableTag = HB_OT_TAG_CBLC };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -349,15 +349,15 @@
     if (unlikely (!count))
       return Null(BitmapSizeTable);
 
-    unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
+    unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
     if (!requested_ppem)
       requested_ppem = 1<<30; /* Choose largest strike. */
     unsigned int best_i = 0;
-    unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
+    unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);
 
     for (unsigned int i = 1; i < count; i++)
     {
-      unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
+      unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
       if ((requested_ppem <= ppem && ppem < best_ppem) ||
 	  (requested_ppem > best_ppem && ppem > best_ppem))
       {
@@ -378,7 +378,7 @@
 
 struct CBDT
 {
-  enum { tableTag = HB_OT_TAG_CBDT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
 
   struct accelerator_t
   {
@@ -424,7 +424,7 @@
 	      return false;
 	    const GlyphBitmapDataFormat17& glyphFormat17 =
 		StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	    glyphFormat17.glyphMetrics.get_extents (extents);
+	    glyphFormat17.glyphMetrics.get_extents (font, extents);
 	    break;
 	  }
 	  case 18: {
@@ -432,7 +432,7 @@
 	      return false;
 	    const GlyphBitmapDataFormat18& glyphFormat18 =
 		StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-	    glyphFormat18.glyphMetrics.get_extents (extents);
+	    glyphFormat18.glyphMetrics.get_extents (font, extents);
 	    break;
 	  }
 	  default:
@@ -442,18 +442,18 @@
       }
 
       /* Convert to font units. */
-      double x_scale = upem / (double) strike.ppemX;
-      double y_scale = upem / (double) strike.ppemY;
-      extents->x_bearing = round (extents->x_bearing * x_scale);
-      extents->y_bearing = round (extents->y_bearing * y_scale);
-      extents->width = round (extents->width * x_scale);
-      extents->height = round (extents->height * y_scale);
+      float x_scale = upem / (float) strike.ppemX;
+      float y_scale = upem / (float) strike.ppemY;
+      extents->x_bearing = roundf (extents->x_bearing * x_scale);
+      extents->y_bearing = roundf (extents->y_bearing * y_scale);
+      extents->width = roundf (extents->width * x_scale);
+      extents->height = roundf (extents->height * y_scale);
 
       return true;
     }
 
     hb_blob_t* reference_png (hb_font_t      *font,
-				     hb_codepoint_t  glyph) const
+			      hb_codepoint_t  glyph) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index 3883604..e2ed7c6 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -39,14 +39,16 @@
 
 struct LayerRecord
 {
+  operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  public:
-  GlyphID	glyphId;	/* Glyph ID of layer glyph */
+  protected:
+  HBGlyphID	glyphId;	/* Glyph ID of layer glyph */
   Index		colorIdx;	/* Index value to use with a
 				 * selected color palette.
 				 * An index value of 0xFFFF
@@ -73,7 +75,7 @@
   }
 
   public:
-  GlyphID	glyphId;	/* Glyph ID of reference glyph */
+  HBGlyphID	glyphId;	/* Glyph ID of reference glyph */
   HBUINT16	firstLayerIdx;	/* Index (from beginning of
 				 * the Layer Records) to the
 				 * layer record. There will be
@@ -87,7 +89,7 @@
 
 struct COLR
 {
-  enum { tableTag = HB_OT_TAG_COLR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
   bool has_data () const { return numBaseGlyphs; }
 
@@ -98,20 +100,16 @@
   {
     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
 
-    hb_array_t<const LayerRecord> all_layers ((this+layersZ).arrayZ, numLayers);
+    hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
 								       record.numLayers);
     if (count)
     {
-      hb_array_t<const LayerRecord> segment_layers = glyph_layers.sub_array (start_offset, *count);
-      *count = segment_layers.len;
-      for (unsigned int i = 0; i < segment_layers.len; i++)
-      {
-        layers[i].glyph = segment_layers.arrayZ[i].glyphId;
-        layers[i].color_index = segment_layers.arrayZ[i].colorIdx;
-      }
+      + glyph_layers.sub_array (start_offset, count)
+      | hb_sink (hb_array (layers, *count))
+      ;
     }
-    return glyph_layers.len;
+    return glyph_layers.length;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -125,9 +123,9 @@
   protected:
   HBUINT16	version;	/* Table version number (starts at 0). */
   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
-  LOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>, false>
+  LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
 		baseGlyphsZ;	/* Offset to Base Glyph records. */
-  LOffsetTo<UnsizedArrayOf<LayerRecord>, false>
+  LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
 		layersZ;	/* Offset to Layer Records. */
   HBUINT16	numLayers;	/* Number of Layer Records. */
   public:
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index bd57d8a..1b3c7fc 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/src/hb-ot-color-cpal-table.hh
@@ -87,15 +87,15 @@
   }
 
   protected:
-  LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
+  LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
 		paletteFlagsZ;		/* Offset from the beginning of CPAL table to
 					 * the Palette Type Array. Set to 0 if no array
 					 * is provided. */
-  LOffsetTo<UnsizedArrayOf<NameID>, false>
+  LNNOffsetTo<UnsizedArrayOf<NameID>>
 		paletteLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the palette labels array. Set to 0 if no
 					 * array is provided. */
-  LOffsetTo<UnsizedArrayOf<NameID>, false>
+  LNNOffsetTo<UnsizedArrayOf<NameID>>
 		colorLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the color labels array. Set to 0
 					 * if no array is provided. */
@@ -107,7 +107,7 @@
 
 struct CPAL
 {
-  enum { tableTag = HB_OT_TAG_CPAL };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
 
   bool has_data () const { return numPalettes; }
 
@@ -115,7 +115,7 @@
   { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
 
   unsigned int get_palette_count () const { return numPalettes; }
-  unsigned int get_color_count () const   { return numColors; }
+  unsigned int   get_color_count () const { return numColors; }
 
   hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
   { return v1 ().get_palette_flags (this, palette_index, numPalettes); }
@@ -144,10 +144,10 @@
     {
       hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
       /* Always return numColors colors per palette even if it has out-of-bounds start index. */
-      unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count);
+      unsigned int count = hb_min ((unsigned) hb_max ((int) (numColors - start_offset), 0), *color_count);
       *color_count = count;
       for (unsigned int i = 0; i < count; i++)
-        colors[i] = segment_colors[i]; /* Bound-checked read. */
+	colors[i] = segment_colors[i]; /* Bound-checked read. */
     }
     return numColors;
   }
@@ -176,7 +176,7 @@
   HBUINT16	numPalettes;		/* Number of palettes in the table. */
   HBUINT16	numColorRecords;	/* Total number of color records, combined for
 					 * all palettes. */
-  LOffsetTo<UnsizedArrayOf<BGRAColor>, false>
+  LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
 		colorRecordsZ;		/* Offset from the beginning of CPAL table to
 					 * the first ColorRecord. */
   UnsizedArrayOf<HBUINT16>
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index ed93d65..35d3fd5 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -121,16 +121,16 @@
   HBUINT16	resolution;	/* The device pixel density (in PPI) for which this
 				 * strike was designed. (E.g., 96 PPI, 192 PPI.) */
   protected:
-  UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
+  UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
 		imageOffsetsZ;	/* Offset from the beginning of the strike data header
 				 * to bitmap data for an individual glyph ID. */
   public:
-  DEFINE_SIZE_STATIC (8);
+  DEFINE_SIZE_ARRAY (4, imageOffsetsZ);
 };
 
 struct sbix
 {
-  enum { tableTag = HB_OT_TAG_sbix };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
 
   bool has_data () const { return version; }
 
@@ -173,11 +173,11 @@
     {
       unsigned count = table->strikes.len;
       if (unlikely (!count))
-        return Null(SBIXStrike);
+	return Null(SBIXStrike);
 
-      unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
+      unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
       if (!requested_ppem)
-        requested_ppem = 1<<30; /* Choose largest strike. */
+	requested_ppem = 1<<30; /* Choose largest strike. */
       /* TODO Add DPI sensitivity as well? */
       unsigned int best_i = 0;
       unsigned int best_ppem = table->get_strike (0).ppem;
@@ -201,7 +201,7 @@
       HBUINT8	signature[8];
       struct
       {
-        struct
+	struct
 	{
 	  HBUINT32	length;
 	  Tag		type;
@@ -226,7 +226,7 @@
       /* Following code is safe to call even without data.
        * But faster to short-circuit. */
       if (!has_data ())
-        return false;
+	return false;
 
       int x_offset = 0, y_offset = 0;
       unsigned int strike_ppem = 0;
@@ -235,18 +235,25 @@
       const PNGHeader &png = *blob->as<PNGHeader>();
 
       extents->x_bearing = x_offset;
-      extents->y_bearing = y_offset;
+      extents->y_bearing = png.IHDR.height + y_offset;
       extents->width     = png.IHDR.width;
-      extents->height    = png.IHDR.height;
+      extents->height    = -png.IHDR.height;
 
       /* Convert to font units. */
       if (strike_ppem)
       {
-	double scale = font->face->get_upem () / (double) strike_ppem;
-	extents->x_bearing = round (extents->x_bearing * scale);
-	extents->y_bearing = round (extents->y_bearing * scale);
-	extents->width = round (extents->width * scale);
-	extents->height = round (extents->height * scale);
+	float scale = font->face->get_upem () / (float) strike_ppem;
+	extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
+	extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
+	extents->width = font->em_scalef_x (extents->width * scale);
+	extents->height = font->em_scalef_y (extents->height * scale);
+      }
+      else
+      {
+	extents->x_bearing = font->em_scale_x (extents->x_bearing);
+	extents->y_bearing = font->em_scale_y (extents->y_bearing);
+	extents->width = font->em_scale_x (extents->width);
+	extents->height = font->em_scale_y (extents->height);
       }
 
       hb_blob_destroy (blob);
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 554453f..926d61e 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -62,7 +62,7 @@
 				 * this index entry. */
   HBUINT16	endGlyphID;	/* The last glyph ID in the range described by
 				 * this index entry. Must be >= startGlyphID. */
-  LOffsetTo<UnsizedArrayOf<HBUINT8>, false>
+  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
 		svgDoc;		/* Offset from the beginning of the SVG Document Index
 				 * to an SVG document. Must be non-zero. */
   HBUINT32	svgDocLength;	/* Length of the SVG document.
@@ -73,7 +73,7 @@
 
 struct SVG
 {
-  enum { tableTag = HB_OT_TAG_SVG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG;
 
   bool has_data () const { return svgDocEntries; }
 
@@ -107,7 +107,7 @@
 
   protected:
   HBUINT16	version;	/* Table version (starting at 0). */
-  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
+  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
 		svgDocEntries;	/* Offset (relative to the start of the SVG table) to the
 				 * SVG Documents Index. Must be non-zero. */
 				/* Array of SVG Document Index Entries. */
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 791135b..0e7203a 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -25,20 +25,21 @@
  * Google Author(s): Sascha Brawer, Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
+
+#ifndef HB_NO_COLOR
+
+#include "hb-ot.h"
+
 #include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-color-colr-table.hh"
 #include "hb-ot-color-cpal-table.hh"
 #include "hb-ot-color-sbix-table.hh"
 #include "hb-ot-color-svg-table.hh"
-#include "hb-ot-face.hh"
-#include "hb-ot.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include "hb-ot-layout.hh"
-
 
 /**
  * SECTION:hb-ot-color
@@ -47,6 +48,8 @@
  * @include: hb-ot.h
  *
  * Functions for fetching color-font information from OpenType font faces.
+ *
+ * HarfBuzz supports `COLR`/`CPAL`, `sbix`, `CBDT`, and `SVG` color fonts.
  **/
 
 
@@ -57,9 +60,11 @@
 
 /**
  * hb_ot_color_has_palettes:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: whether CPAL table is available.
+ * Tests whether a face includes a `CPAL` color-palette table.
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -71,10 +76,11 @@
 
 /**
  * hb_ot_color_palette_get_count:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: the number of color palettes in @face, or zero if @face has
- * no colors.
+ * Fetches the number of color palettes in a face.
+ *
+ * Return value: the number of palettes found
  *
  * Since: 2.1.0
  */
@@ -86,13 +92,16 @@
 
 /**
  * hb_ot_color_palette_get_name_id:
- * @face:    a font face.
- * @palette_index: the index of the color palette whose name is being requested.
+ * @face: #hb_face_t to work upon
+ * @palette_index: The index of the color palette 
  *
- * Retrieves the name id of a color palette. For example, a color font can
- * have themed palettes like "Spring", "Summer", "Fall", and "Winter".
+ * Fetches the `name` table Name ID that provides display names for
+ * a `CPAL` color palette. 
  *
- * Returns: an identifier within @face's `name` table.
+ * Palette display names can be generic (e.g., "Default") or provide
+ * specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").
+ *
+ * Return value: the Named ID found for the palette. 
  * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
  *
  * Since: 2.1.0
@@ -106,10 +115,16 @@
 
 /**
  * hb_ot_color_palette_color_get_name_id:
- * @face:        a font face.
- * @color_index: palette entry index.
+ * @face: #hb_face_t to work upon
+ * @color_index: The index of the color
  *
- * Returns: Name ID associated with a palette entry, e.g. eye color
+ * Fetches the `name` table Name ID that provides display names for
+ * the specificed color in a face's `CPAL` color palette. 
+ *
+ * Display names can be generic (e.g., "Background") or specific
+ * (e.g., "Eye color").
+ *
+ * Return value: the Name ID found for the color.
  *
  * Since: 2.1.0
  */
@@ -122,10 +137,12 @@
 
 /**
  * hb_ot_color_palette_get_flags:
- * @face:          a font face
- * @palette_index: the index of the color palette whose flags are being requested
+ * @face: #hb_face_t to work upon
+ * @palette_index: The index of the color palette
  *
- * Returns: the flags for the requested color palette.
+ * Fetches the flags defined for a color palette.
+ *
+ * Return value: the #hb_ot_color_palette_flags_t of the requested color palette
  *
  * Since: 2.1.0
  */
@@ -138,25 +155,22 @@
 
 /**
  * hb_ot_color_palette_get_colors:
- * @face:         a font face.
- * @palette_index:the index of the color palette whose colors
- *                are being requested.
- * @start_offset: the index of the first color being requested.
- * @color_count:  (inout) (optional): on input, how many colors
- *                can be maximally stored into the @colors array;
- *                on output, how many colors were actually stored.
- * @colors: (array length=color_count) (out) (optional):
- *                an array of #hb_color_t records. After calling
- *                this function, @colors will be filled with
- *                the palette colors. If @colors is NULL, the function
- *                will just return the number of total colors
- *                without storing any actual colors; this can be used
- *                for allocating a buffer of suitable size before calling
- *                hb_ot_color_palette_get_colors() a second time.
+ * @face: #hb_face_t to work upon
+ * @palette_index: the index of the color palette to query
+ * @start_offset: offset of the first color to retrieve
+ * @color_count: (inout) (optional): Input = the maximum number of colors to return;
+ *               Output = the actual number of colors returned (may be zero)
+ * @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found
  *
- * Retrieves the colors in a color palette.
+ * Fetches a list of the colors in a color palette.
  *
- * Returns: the total number of colors in the palette.
+ * After calling this function, @colors will be filled with the palette
+ * colors. If @colors is NULL, the function will just return the number
+ * of total colors without storing any actual colors; this can be used
+ * for allocating a buffer of suitable size before calling
+ * hb_ot_color_palette_get_colors() a second time.
+ *
+ * Return value: the total number of colors in the palette
  *
  * Since: 2.1.0
  */
@@ -177,9 +191,11 @@
 
 /**
  * hb_ot_color_has_layers:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: whether COLR table is available.
+ * Tests whether a face includes any `COLR` color layers.
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -191,14 +207,17 @@
 
 /**
  * hb_ot_color_glyph_get_layers:
- * @face:         a font face.
- * @glyph:        a layered color glyph id.
- * @start_offset: starting offset of layers.
- * @count:  (inout) (optional): gets number of layers available to be written on buffer
- * 				and returns number of written layers.
- * @layers: (array length=count) (out) (optional): layers buffer to buffer.
+ * @face: #hb_face_t to work upon
+ * @glyph: The glyph index to query
+ * @start_offset: offset of the first layer to retrieve
+ * @layer_count: (inout) (optional): Input = the maximum number of layers to return;
+ *         Output = the actual number of layers returned (may be zero)
+ * @layers: (out) (array length=layer_count) (nullable): The array of layers found
  *
- * Returns: Total number of layers a layered color glyph have.
+ * Fetches a list of all color layers for the specified glyph index in the specified
+ * face. The list returned will begin at the offset provided.
+ *
+ * Return value: Total number of layers available for the glyph index queried
  *
  * Since: 2.1.0
  */
@@ -206,10 +225,10 @@
 hb_ot_color_glyph_get_layers (hb_face_t           *face,
 			      hb_codepoint_t       glyph,
 			      unsigned int         start_offset,
-			      unsigned int        *count, /* IN/OUT.  May be NULL. */
+			      unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
 			      hb_ot_color_layer_t *layers /* OUT.     May be NULL. */)
 {
-  return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers);
+  return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
 }
 
 
@@ -219,11 +238,11 @@
 
 /**
  * hb_ot_color_has_svg:
- * @face: a font face.
+ * @face: #hb_face_t to work upon.
  *
- * Check whether @face has SVG glyph images.
+ * Tests whether a face includes any `SVG` glyph images.
  *
- * Returns true if available, false otherwise.
+ * Return value: true if data found, false otherwise.
  *
  * Since: 2.1.0
  */
@@ -235,12 +254,12 @@
 
 /**
  * hb_ot_color_glyph_reference_svg:
- * @face:  a font face.
- * @glyph: a svg glyph index.
+ * @face: #hb_face_t to work upon
+ * @glyph: a svg glyph index
  *
- * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded.
+ * Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded.
  *
- * Returns: (transfer full): respective svg blob of the glyph, if available.
+ * Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available
  *
  * Since: 2.1.0
  */
@@ -257,11 +276,11 @@
 
 /**
  * hb_ot_color_has_png:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Check whether @face has PNG glyph images (either CBDT or sbix tables).
+ * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
  *
- * Returns true if available, false otherwise.
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -273,14 +292,14 @@
 
 /**
  * hb_ot_color_glyph_reference_png:
- * @font:  a font object, not face. upem should be set on
- * 	   that font object if one wants to get optimal png blob, otherwise
- * 	   return the biggest one
- * @glyph: a glyph index.
+ * @font: #hb_font_t to work upon
+ * @glyph: a glyph index
  *
- * Get PNG image for a glyph.
+ * Fetches the PNG image for a glyph. This function takes a font object, not a face object,
+ * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
+ * object. If UPEM is unset, the blob returned will be the largest PNG available.
  *
- * Returns: (transfer full): respective PNG blob of the glyph, if available.
+ * Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available
  *
  * Since: 2.1.0
  */
@@ -297,3 +316,6 @@
 
   return blob;
 }
+
+
+#endif
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
index 49646bf..63ef20a 100644
--- a/src/hb-ot-color.h
+++ b/src/hb-ot-color.h
@@ -59,11 +59,11 @@
 
 /**
  * hb_ot_color_palette_flags_t:
- * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special
+ * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: Default indicating that there is nothing special
  *   to note about a color palette.
- * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color
+ * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: Flag indicating that the color
  *   palette is appropriate to use when displaying the font on a light background such as white.
- * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color
+ * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
  *   palette is appropriate to use when displaying the font on a dark background such as black.
  *
  * Since: 2.1.0
@@ -110,7 +110,7 @@
 hb_ot_color_glyph_get_layers (hb_face_t           *face,
 			      hb_codepoint_t       glyph,
 			      unsigned int         start_offset,
-			      unsigned int        *count, /* IN/OUT.  May be NULL. */
+			      unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
 			      hb_ot_color_layer_t *layers /* OUT.     May be NULL. */);
 
 /*
diff --git a/src/hb-ot-deprecated.h b/src/hb-ot-deprecated.h
index bce51b7..bc72f8a 100644
--- a/src/hb-ot-deprecated.h
+++ b/src/hb-ot-deprecated.h
@@ -40,6 +40,10 @@
 #ifndef HB_DISABLE_DEPRECATED
 
 
+/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
+#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
+
+
 /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
 HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh
new file mode 100644
index 0000000..6fa9baf
--- /dev/null
+++ b/src/hb-ot-face-table-list.hh
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2012,2013  Google, Inc.
+ * Copyright © 2019, Facebook Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_FACE_TABLE_LIST_HH
+#define HB_OT_FACE_TABLE_LIST_HH
+#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
+
+#ifndef HB_OT_ACCELERATOR
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_ACCELERATOR_UNDEF
+#endif
+
+
+/* This lists font tables that the hb_face_t will contain and lazily
+ * load.  Don't add a table unless it's used though.  This is not
+ * exactly free. */
+
+/* v--- Add new tables in the right place here. */
+
+
+/* OpenType fundamentals. */
+HB_OT_TABLE (OT, head)
+#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
+HB_OT_ACCELERATOR (OT, cmap)
+#endif
+HB_OT_TABLE (OT, hhea)
+HB_OT_ACCELERATOR (OT, hmtx)
+HB_OT_TABLE (OT, OS2)
+#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS)
+HB_OT_ACCELERATOR (OT, post)
+#endif
+#ifndef HB_NO_NAME
+HB_OT_ACCELERATOR (OT, name)
+#endif
+#ifndef HB_NO_STAT
+HB_OT_TABLE (OT, STAT)
+#endif
+#ifndef HB_NO_META
+HB_OT_ACCELERATOR (OT, meta)
+#endif
+
+/* Vertical layout. */
+HB_OT_TABLE (OT, vhea)
+HB_OT_ACCELERATOR (OT, vmtx)
+
+/* TrueType outlines. */
+HB_OT_ACCELERATOR (OT, glyf)
+
+/* CFF outlines. */
+#ifndef HB_NO_CFF
+HB_OT_ACCELERATOR (OT, cff1)
+HB_OT_ACCELERATOR (OT, cff2)
+HB_OT_TABLE (OT, VORG)
+#endif
+
+/* OpenType variations. */
+#ifndef HB_NO_VAR
+HB_OT_TABLE (OT, fvar)
+HB_OT_TABLE (OT, avar)
+HB_OT_ACCELERATOR (OT, gvar)
+HB_OT_TABLE (OT, MVAR)
+#endif
+
+/* Legacy kern. */
+#ifndef HB_NO_OT_KERN
+HB_OT_TABLE (OT, kern)
+#endif
+
+/* OpenType shaping. */
+#ifndef HB_NO_OT_LAYOUT
+HB_OT_ACCELERATOR (OT, GDEF)
+HB_OT_ACCELERATOR (OT, GSUB)
+HB_OT_ACCELERATOR (OT, GPOS)
+//HB_OT_TABLE (OT, JSTF)
+#endif
+
+/* OpenType baseline. */
+#ifndef HB_NO_BASE
+HB_OT_TABLE (OT, BASE)
+#endif
+
+/* AAT shaping. */
+#ifndef HB_NO_AAT
+HB_OT_TABLE (AAT, morx)
+HB_OT_TABLE (AAT, mort)
+HB_OT_TABLE (AAT, kerx)
+HB_OT_TABLE (AAT, ankr)
+HB_OT_TABLE (AAT, trak)
+HB_OT_TABLE (AAT, lcar)
+HB_OT_TABLE (AAT, ltag)
+HB_OT_TABLE (AAT, feat)
+// HB_OT_TABLE (AAT, opbd)
+#endif
+
+/* OpenType color fonts. */
+#ifndef HB_NO_COLOR
+HB_OT_TABLE (OT, COLR)
+HB_OT_TABLE (OT, CPAL)
+HB_OT_ACCELERATOR (OT, CBDT)
+HB_OT_ACCELERATOR (OT, sbix)
+HB_OT_ACCELERATOR (OT, SVG)
+#endif
+
+/* OpenType math. */
+#ifndef HB_NO_MATH
+HB_OT_TABLE (OT, MATH)
+#endif
+
+
+#ifdef _HB_OT_ACCELERATOR_UNDEF
+#undef HB_OT_ACCELERATOR
+#endif
diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc
index 9b17526..5ef8df4 100644
--- a/src/hb-ot-face.cc
+++ b/src/hb-ot-face.cc
@@ -32,6 +32,7 @@
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-kern-table.hh"
+#include "hb-ot-meta-table.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-color-cbdt-table.hh"
@@ -46,16 +47,12 @@
 {
   this->face = face;
 #define HB_OT_TABLE(Namespace, Type) Type.init0 ();
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-  HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
 }
 void hb_ot_face_t::fini ()
 {
 #define HB_OT_TABLE(Namespace, Type) Type.fini ();
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-  HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
 }
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index 7f47ba6..e24d380 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -38,54 +38,10 @@
  * hb_ot_face_t
  */
 
-#define HB_OT_TABLES \
-    /* OpenType fundamentals. */ \
-    HB_OT_TABLE(OT, head) \
-    HB_OT_ACCELERATOR(OT, cmap) \
-    HB_OT_ACCELERATOR(OT, hmtx) \
-    HB_OT_ACCELERATOR(OT, vmtx) \
-    HB_OT_ACCELERATOR(OT, post) \
-    HB_OT_TABLE(OT, kern) \
-    HB_OT_ACCELERATOR(OT, glyf) \
-    HB_OT_ACCELERATOR(OT, cff1) \
-    HB_OT_ACCELERATOR(OT, cff2) \
-    HB_OT_TABLE(OT, VORG) \
-    HB_OT_ACCELERATOR(OT, name) \
-    HB_OT_TABLE(OT, OS2) \
-    HB_OT_TABLE(OT, STAT) \
-    /* OpenType shaping. */ \
-    HB_OT_ACCELERATOR(OT, GDEF) \
-    HB_OT_ACCELERATOR(OT, GSUB) \
-    HB_OT_ACCELERATOR(OT, GPOS) \
-    HB_OT_TABLE(OT, BASE) \
-    HB_OT_TABLE(OT, JSTF) \
-    /* AAT shaping. */ \
-    HB_OT_TABLE(AAT, mort) \
-    HB_OT_TABLE(AAT, morx) \
-    HB_OT_TABLE(AAT, kerx) \
-    HB_OT_TABLE(AAT, ankr) \
-    HB_OT_TABLE(AAT, trak) \
-    HB_OT_TABLE(AAT, lcar) \
-    HB_OT_TABLE(AAT, ltag) \
-    HB_OT_TABLE(AAT, feat) \
-    /* OpenType variations. */ \
-    HB_OT_TABLE(OT, fvar) \
-    HB_OT_TABLE(OT, avar) \
-    HB_OT_TABLE(OT, MVAR) \
-    /* OpenType math. */ \
-    HB_OT_TABLE(OT, MATH) \
-    /* OpenType color fonts. */ \
-    HB_OT_TABLE(OT, COLR) \
-    HB_OT_TABLE(OT, CPAL) \
-    HB_OT_ACCELERATOR(OT, CBDT) \
-    HB_OT_ACCELERATOR(OT, sbix) \
-    HB_OT_ACCELERATOR(OT, SVG) \
-    /* */
-
 /* Declare tables. */
 #define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
 #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t)
-HB_OT_TABLES
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 
@@ -100,9 +56,7 @@
   {
     ORDER_ZERO,
 #define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type),
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-    HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
   };
 
@@ -111,7 +65,7 @@
   hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
 #define HB_OT_ACCELERATOR(Namespace, Type) \
   hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
-  HB_OT_TABLES
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 };
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index c080f0f..96f94e4 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -26,6 +26,8 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_OT_FONT
+
 #include "hb-ot.h"
 
 #include "hb-font.hh"
@@ -37,7 +39,6 @@
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-hmtx-table.hh"
-#include "hb-ot-kern-table.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
@@ -52,7 +53,7 @@
  * @short_description: OpenType font implementation
  * @include: hb-ot.h
  *
- * Functions for using OpenType fonts with hb_shape().  Not that fonts returned
+ * Functions for using OpenType fonts with hb_shape().  Note that fonts returned
  * by hb_font_create() default to using these functions, so most clients would
  * never need to call these functions directly.
  **/
@@ -112,8 +113,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font));
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -132,8 +133,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -149,19 +150,21 @@
 
   *x = font->get_glyph_h_advance (glyph) / 2;
 
+#ifndef HB_NO_OT_FONT_CFF
   const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
     *y = font->em_scale_y (VORG.get_y_origin (glyph));
     return true;
   }
+#endif
 
   hb_glyph_extents_t extents = {0};
-  if (ot_face->glyf->get_extents (glyph, &extents))
+  if (ot_face->glyf->get_extents (font, glyph, &extents))
   {
     const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    hb_position_t tsb = vmtx.get_side_bearing (glyph);
-    *y = font->em_scale_y (extents.y_bearing + tsb);
+    hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
+    *y = extents.y_bearing + font->em_scale_y (tsb);
     return true;
   }
 
@@ -180,73 +183,67 @@
 			 void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  bool ret = ot_face->sbix->get_extents (font, glyph, extents);
-  if (!ret)
-    ret = ot_face->glyf->get_extents (glyph, extents);
-  if (!ret)
-    ret = ot_face->cff1->get_extents (glyph, extents);
-  if (!ret)
-    ret = ot_face->cff2->get_extents (font, glyph, extents);
-  if (!ret)
-    ret = ot_face->CBDT->get_extents (font, glyph, extents);
+  bool ret = false;
+
+#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
+  if (!ret) ret = ot_face->sbix->get_extents (font, glyph, extents);
+#endif
+  if (!ret) ret = ot_face->glyf->get_extents (font, glyph, extents);
+#ifndef HB_NO_OT_FONT_CFF
+  if (!ret) ret = ot_face->cff1->get_extents (font, glyph, extents);
+  if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents);
+#endif
+#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
+  if (!ret) ret = ot_face->CBDT->get_extents (font, glyph, extents);
+#endif
+
   // TODO Hook up side-bearings variations.
-  extents->x_bearing = font->em_scale_x (extents->x_bearing);
-  extents->y_bearing = font->em_scale_y (extents->y_bearing);
-  extents->width     = font->em_scale_x (extents->width);
-  extents->height    = font->em_scale_y (extents->height);
   return ret;
 }
 
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
 static hb_bool_t
 hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
-                      void *font_data,
-                      hb_codepoint_t glyph,
-                      char *name, unsigned int size,
-                      void *user_data HB_UNUSED)
+		      void *font_data,
+		      hb_codepoint_t glyph,
+		      char *name, unsigned int size,
+		      void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   return ot_face->post->get_glyph_name (glyph, name, size);
 }
-
 static hb_bool_t
 hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
-                           void *font_data,
-                           const char *name, int len,
-                           hb_codepoint_t *glyph,
-                           void *user_data HB_UNUSED)
+			   void *font_data,
+			   const char *name, int len,
+			   hb_codepoint_t *glyph,
+			   void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   return ot_face->post->get_glyph_from_name (name, len, glyph);
 }
+#endif
 
 static hb_bool_t
 hb_ot_get_font_h_extents (hb_font_t *font,
-			  void *font_data,
+			  void *font_data HB_UNUSED,
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
-  metrics->ascender = font->em_scale_y (hmtx.ascender);
-  metrics->descender = font->em_scale_y (hmtx.descender);
-  metrics->line_gap = font->em_scale_y (hmtx.line_gap);
-  // TODO Hook up variations.
-  return hmtx.has_font_extents;
+  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
 }
 
 static hb_bool_t
 hb_ot_get_font_v_extents (hb_font_t *font,
-			  void *font_data,
+			  void *font_data HB_UNUSED,
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-  metrics->ascender = font->em_scale_x (vmtx.ascender);
-  metrics->descender = font->em_scale_x (vmtx.descender);
-  metrics->line_gap = font->em_scale_x (vmtx.line_gap);
-  // TODO Hook up variations.
-  return vmtx.has_font_extents;
+  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
+	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
 }
 
 #if HB_USE_ATEXIT
@@ -270,8 +267,10 @@
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
     hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
+#endif
 
     hb_font_funcs_make_immutable (funcs);
 
@@ -311,3 +310,20 @@
 		     &font->face->table,
 		     nullptr);
 }
+
+#ifndef HB_NO_VAR
+int
+_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+{
+  return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
+}
+
+unsigned
+_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+{
+  return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+}
+#endif
+
+
+#endif
diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh
index d328fd2..94fff58 100644
--- a/src/hb-ot-gasp-table.hh
+++ b/src/hb-ot-gasp-table.hh
@@ -57,7 +57,7 @@
 
 struct gasp
 {
-  enum { tableTag = HB_OT_TAG_gasp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_gasp;
 
   const GaspRange &get_gasp_range (unsigned int i) const
   { return gaspRanges[i]; }
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index a6dec40..571e50e 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -1,5 +1,7 @@
 /*
  * Copyright © 2015  Google, Inc.
+ * Copyright © 2019  Adobe Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -21,7 +23,8 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
+ * Adobe Author(s): Michiharu Ariza
  */
 
 #ifndef HB_OT_GLYF_TABLE_HH
@@ -29,7 +32,10 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-head-table.hh"
-#include "hb-subset-glyf.hh"
+#include "hb-ot-hmtx-table.hh"
+#include "hb-ot-var-gvar-table.hh"
+
+#include <float.h>
 
 namespace OT {
 
@@ -45,7 +51,7 @@
 {
   friend struct glyf;
 
-  enum { tableTag = HB_OT_TAG_loca };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
@@ -54,11 +60,12 @@
   }
 
   protected:
-  UnsizedArrayOf<HBUINT8>	dataZ;		/* Location data. */
+  UnsizedArrayOf<HBUINT8>
+		dataZ;	/* Location data. */
   public:
-  DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
-			* check the size externally, allow Null() object of it by
-			* defining it MIN() instead. */
+  DEFINE_SIZE_MIN (0);	/* In reality, this is UNBOUNDED() type; but since we always
+			 * check the size externally, allow Null() object of it by
+			 * defining it _MIN instead. */
 };
 
 
@@ -71,34 +78,133 @@
 
 struct glyf
 {
-  enum { tableTag = HB_OT_TAG_glyf };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
-    /* We don't check for anything specific here.  The users of the
-     * struct do all the hard work... */
+    /* Runtime checks as eager sanitizing each glyph is costy */
     return_trace (true);
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  template<typename Iterator,
+	   hb_requires (hb_is_source_of (Iterator, unsigned int))>
+  static bool
+  _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
   {
-    hb_blob_t *glyf_prime = nullptr;
-    hb_blob_t *loca_prime = nullptr;
+    unsigned max_offset = + padded_offsets | hb_reduce(hb_add, 0);
+    unsigned num_offsets = padded_offsets.len () + 1;
+    bool use_short_loca = max_offset < 0x1FFFF;
+    unsigned entry_size = use_short_loca ? 2 : 4;
+    char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
 
-    bool success = true;
-    bool use_short_loca = false;
-    if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
-      success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
-      success = success && _add_head_and_set_loca_version (plan, use_short_loca);
-    } else {
-      success = false;
-    }
-    hb_blob_destroy (loca_prime);
-    hb_blob_destroy (glyf_prime);
+    if (unlikely (!loca_prime_data)) return false;
 
-    return success;
+    DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d "
+				"max_offset %d size %d",
+	       entry_size, num_offsets, max_offset, entry_size * num_offsets);
+
+    if (use_short_loca)
+      _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets));
+    else
+      _write_loca (padded_offsets, 0, hb_array ((HBUINT32*) loca_prime_data, num_offsets));
+
+    hb_blob_t * loca_blob = hb_blob_create (loca_prime_data,
+					    entry_size * num_offsets,
+					    HB_MEMORY_MODE_WRITABLE,
+					    loca_prime_data,
+					    free);
+
+    bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
+		  && _add_head_and_set_loca_version (plan, use_short_loca);
+
+    hb_blob_destroy (loca_blob);
+    return result;
+  }
+
+  template<typename IteratorIn, typename IteratorOut,
+	   hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
+	   hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+  static void
+  _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
+  {
+    unsigned int offset = 0;
+    dest << 0;
+    + it
+    | hb_map ([=, &offset] (unsigned int padded_size)
+	      {
+		offset += padded_size;
+		DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
+		return offset >> right_shift;
+	      })
+    | hb_sink (dest)
+    ;
+  }
+
+  /* requires source of SubsetGlyph complains the identifier isn't declared */
+  template <typename Iterator>
+  bool serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  const hb_subset_plan_t *plan)
+  {
+    TRACE_SERIALIZE (this);
+    for (const auto &_ : it) _.serialize (c, plan);
+    return_trace (true);
+  }
+
+  /* Byte region(s) per glyph to output
+     unpadded, hints removed if so requested
+     If we fail to process a glyph we produce an empty (0-length) glyph */
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    glyf *glyf_prime = c->serializer->start_embed <glyf> ();
+    if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
+
+    hb_vector_t<SubsetGlyph> glyphs;
+    _populate_subset_glyphs (c->plan, &glyphs);
+
+    glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
+
+    auto padded_offsets =
+    + hb_iter (glyphs)
+    | hb_map (&SubsetGlyph::padded_size)
+    ;
+
+    if (c->serializer->in_error ()) return_trace (false);
+    return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
+								    padded_offsets)));
+  }
+
+  template <typename SubsetGlyph>
+  void
+  _populate_subset_glyphs (const hb_subset_plan_t   *plan,
+			   hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const
+  {
+    OT::glyf::accelerator_t glyf;
+    glyf.init (plan->source);
+
+    + hb_range (plan->num_output_glyphs ())
+    | hb_map ([&] (hb_codepoint_t new_gid)
+	      {
+		SubsetGlyph subset_glyph = {0};
+		subset_glyph.new_gid = new_gid;
+
+		/* should never fail: all old gids should be mapped */
+		if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
+		  return subset_glyph;
+
+		subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+		if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
+		else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+
+		return subset_glyph;
+	      })
+    | hb_sink (glyphs)
+    ;
+
+    glyf.fini ();
   }
 
   static bool
@@ -112,30 +218,17 @@
       return false;
 
     head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
-    head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
+    head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
     bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
 
     hb_blob_destroy (head_prime_blob);
     return success;
   }
 
-  struct GlyphHeader
+  struct CompositeGlyphChain
   {
-    HBINT16		numberOfContours;	/* If the number of contours is
-						 * greater than or equal to zero,
-						 * this is a simple glyph; if negative,
-						 * this is a composite glyph. */
-    FWORD		xMin;			/* Minimum x for coordinate data. */
-    FWORD		yMin;			/* Minimum y for coordinate data. */
-    FWORD		xMax;			/* Maximum x for coordinate data. */
-    FWORD		yMax;			/* Maximum y for coordinate data. */
-
-    DEFINE_SIZE_STATIC (10);
-  };
-
-  struct CompositeGlyphHeader
-  {
-    enum composite_glyph_flag_t {
+    enum composite_glyph_flag_t
+    {
       ARG_1_AND_2_ARE_WORDS =      0x0001,
       ARGS_ARE_XY_VALUES =         0x0002,
       ROUND_XY_TO_GRID =           0x0004,
@@ -150,180 +243,247 @@
       UNSCALED_COMPONENT_OFFSET =  0x1000
     };
 
-    HBUINT16 flags;
-    GlyphID  glyphIndex;
-
     unsigned int get_size () const
     {
       unsigned int size = min_size;
-      // arg1 and 2 are int16
+      /* arg1 and 2 are int16 */
       if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
-      // arg1 and 2 are int8
+      /* arg1 and 2 are int8 */
       else size += 2;
 
-      // One x 16 bit (scale)
+      /* One x 16 bit (scale) */
       if (flags & WE_HAVE_A_SCALE) size += 2;
-      // Two x 16 bit (xscale, yscale)
+      /* Two x 16 bit (xscale, yscale) */
       else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
-      // Four x 16 bit (xscale, scale01, scale10, yscale)
+      /* Four x 16 bit (xscale, scale01, scale10, yscale) */
       else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
 
       return size;
     }
 
-    struct Iterator
+    bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
+    bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
+    void get_anchor_points (unsigned int &point1, unsigned int &point2) const
     {
-      const char *glyph_start;
-      const char *glyph_end;
-      const CompositeGlyphHeader *current;
-
-      bool move_to_next ()
+      const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
+      if (flags & ARG_1_AND_2_ARE_WORDS)
       {
-	if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
-	{
-	  const CompositeGlyphHeader *possible =
-	    &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
-	  if (!in_range (possible))
-	    return false;
-	  current = possible;
-	  return true;
-	}
-	return false;
+	point1 = ((const HBUINT16 *) p)[0];
+	point2 = ((const HBUINT16 *) p)[1];
       }
-
-      bool in_range (const CompositeGlyphHeader *composite) const
+      else
       {
-	return (const char *) composite >= glyph_start
-	  && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
-	  && ((const char *) composite + composite->get_size ()) <= glyph_end;
+	point1 = p[0];
+	point2 = p[1];
       }
-    };
-
-    static bool get_iterator (const char * glyph_data,
-				     unsigned int length,
-				     CompositeGlyphHeader::Iterator *iterator /* OUT */)
-    {
-      if (length < GlyphHeader::static_size)
-	return false; /* Empty glyph; zero extents. */
-
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
-      if (glyph_header.numberOfContours < 0)
-      {
-	const CompositeGlyphHeader *possible =
-	  &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
-
-	iterator->glyph_start = glyph_data;
-	iterator->glyph_end = (const char *) glyph_data + length;
-	if (!iterator->in_range (possible))
-	  return false;
-	iterator->current = possible;
-	return true;
-      }
-
-      return false;
     }
 
+    void transform_points (contour_point_vector_t &points) const
+    {
+      float matrix[4];
+      contour_point_t trans;
+      if (get_transformation (matrix, trans))
+      {
+	if (scaled_offsets ())
+	{
+	  points.translate (trans);
+	  points.transform (matrix);
+	}
+	else
+	{
+	  points.transform (matrix);
+	  points.translate (trans);
+	}
+      }
+    }
+
+    protected:
+    bool scaled_offsets () const
+    { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
+
+    bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
+    {
+      matrix[0] = matrix[3] = 1.f;
+      matrix[1] = matrix[2] = 0.f;
+
+      int tx, ty;
+      const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
+      if (flags & ARG_1_AND_2_ARE_WORDS)
+      {
+	tx = *(const HBINT16 *) p;
+	p += HBINT16::static_size;
+	ty = *(const HBINT16 *) p;
+	p += HBINT16::static_size;
+      }
+      else
+      {
+	tx = *p++;
+	ty = *p++;
+      }
+      if (is_anchored ()) tx = ty = 0;
+
+      trans.init ((float) tx, (float) ty);
+
+      {
+	const F2DOT14 *points = (const F2DOT14 *) p;
+	if (flags & WE_HAVE_A_SCALE)
+	{
+	  matrix[0] = matrix[3] = points[0].to_float ();
+	  return true;
+	}
+	else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
+	{
+	  matrix[0] = points[0].to_float ();
+	  matrix[3] = points[1].to_float ();
+	  return true;
+	}
+	else if (flags & WE_HAVE_A_TWO_BY_TWO)
+	{
+	  matrix[0] = points[0].to_float ();
+	  matrix[1] = points[1].to_float ();
+	  matrix[2] = points[2].to_float ();
+	  matrix[3] = points[3].to_float ();
+	  return true;
+	}
+      }
+      return tx || ty;
+    }
+
+    public:
+    HBUINT16	flags;
+    HBGlyphID	glyphIndex;
+    public:
     DEFINE_SIZE_MIN (4);
   };
 
-  struct accelerator_t
+  struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &>
   {
-    void init (hb_face_t *face)
+    typedef const CompositeGlyphChain *__item_t__;
+    composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
+      glyph (glyph_), current (current_)
+    { if (!in_range (current)) current = nullptr; }
+    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
+
+    const CompositeGlyphChain &__item__ () const { return *current; }
+    bool __more__ () const { return current; }
+    void __next__ ()
     {
-      memset (this, 0, sizeof (accelerator_t));
+      if (!(current->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; }
 
-      const OT::head &head = *face->table.head;
-      if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0)
-	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
-	return;
-      short_offset = 0 == head.indexToLocFormat;
+      const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
+							 CompositeGlyphChain> (*current);
+      if (!in_range (possible)) { current = nullptr; return; }
+      current = possible;
+    }
+    bool operator != (const composite_iter_t& o) const
+    { return glyph != o.glyph || current != o.current; }
 
-      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
-      glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
-
-      num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+    bool in_range (const CompositeGlyphChain *composite) const
+    {
+      return glyph.in_range (composite, CompositeGlyphChain::min_size)
+	  && glyph.in_range (composite, composite->get_size ());
     }
 
-    void fini ()
+    private:
+    hb_bytes_t glyph;
+    __item_t__ current;
+  };
+
+  struct Glyph
+  {
+    private:
+    struct GlyphHeader
     {
-      loca_table.destroy ();
-      glyf_table.destroy ();
-    }
+      bool has_data () const { return numberOfContours; }
 
-    /*
-     * Returns true if the referenced glyph is a valid glyph and a composite glyph.
-     * If true is returned a pointer to the composite glyph will be written into
-     * composite.
-     */
-    bool get_composite (hb_codepoint_t glyph,
-			CompositeGlyphHeader::Iterator *composite /* OUT */) const
-    {
-      if (unlikely (!num_glyphs))
-	return false;
+      bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+      {
+	/* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
+	/* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
+	extents->x_bearing = font->em_scale_x (font->face->table.hmtx->get_side_bearing (gid));
+	extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
+	extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
+	extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
 
-      unsigned int start_offset, end_offset;
-      if (!get_offsets (glyph, &start_offset, &end_offset))
-	return false; /* glyph not found */
+	return true;
+      }
 
-      return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset,
-						 end_offset - start_offset,
-						 composite);
-    }
-
-    enum simple_glyph_flag_t {
-      FLAG_ON_CURVE = 0x01,
-      FLAG_X_SHORT = 0x02,
-      FLAG_Y_SHORT = 0x04,
-      FLAG_REPEAT = 0x08,
-      FLAG_X_SAME = 0x10,
-      FLAG_Y_SAME = 0x20,
-      FLAG_RESERVED1 = 0x40,
-      FLAG_RESERVED2 = 0x80
+      HBINT16	numberOfContours;
+			/* If the number of contours is
+			 * greater than or equal to zero,
+			 * this is a simple glyph; if negative,
+			 * this is a composite glyph. */
+      FWORD	xMin;	/* Minimum x for coordinate data. */
+      FWORD	yMin;	/* Minimum y for coordinate data. */
+      FWORD	xMax;	/* Maximum x for coordinate data. */
+      FWORD	yMax;	/* Maximum y for coordinate data. */
+      public:
+      DEFINE_SIZE_STATIC (10);
     };
 
-    /* based on FontTools _g_l_y_f.py::trim */
-    bool remove_padding (unsigned int start_offset,
-				unsigned int *end_offset) const
+    struct SimpleGlyph
     {
-      if (*end_offset - start_offset < GlyphHeader::static_size) return true;
+      const GlyphHeader &header;
+      hb_bytes_t bytes;
+      SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+	header (header_), bytes (bytes_) {}
 
-      const char *glyph = ((const char *) glyf_table) + start_offset;
-      const char * const glyph_end = glyph + (*end_offset - start_offset);
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
-      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
+      unsigned int instruction_len_offset () const
+      { return GlyphHeader::static_size + 2 * header.numberOfContours; }
 
-      if (num_contours < 0)
-	/* Trimming for composites not implemented.
-	 * If removing hints it falls out of that. */
-	return true;
-      else if (num_contours > 0)
+      unsigned int length (unsigned int instruction_len) const
+      { return instruction_len_offset () + 2 + instruction_len; }
+
+      unsigned int instructions_length () const
       {
+	unsigned int instruction_length_offset = instruction_len_offset ();
+	if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
+
+	const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
+	/* Out of bounds of the current glyph */
+	if (unlikely (length (instructionLength) > bytes.length)) return 0;
+	return instructionLength;
+      }
+
+      enum simple_glyph_flag_t
+      {
+	FLAG_ON_CURVE  = 0x01,
+	FLAG_X_SHORT   = 0x02,
+	FLAG_Y_SHORT   = 0x04,
+	FLAG_REPEAT    = 0x08,
+	FLAG_X_SAME    = 0x10,
+	FLAG_Y_SAME    = 0x20,
+	FLAG_RESERVED1 = 0x40,
+	FLAG_RESERVED2 = 0x80
+      };
+
+      const Glyph trim_padding () const
+      {
+	/* based on FontTools _g_l_y_f.py::trim */
+	const char *glyph = bytes.arrayZ;
+	const char *glyph_end = glyph + bytes.length;
 	/* simple glyph w/contours, possibly trimmable */
-	glyph += GlyphHeader::static_size + 2 * num_contours;
+	glyph += instruction_len_offset ();
 
-	if (unlikely (glyph + 2 >= glyph_end)) return false;
-	uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
-	uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16> (glyph, 0);
+	if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
+	unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
+	unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
 
-	glyph += 2 + nInstructions;
-	if (unlikely (glyph + 2 >= glyph_end)) return false;
+	glyph += 2 + num_instructions;
+	if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
 
-	unsigned int coordBytes = 0;
-	unsigned int coordsWithFlags = 0;
+	unsigned int coord_bytes = 0;
+	unsigned int coords_with_flags = 0;
 	while (glyph < glyph_end)
 	{
-	  uint8_t flag = (uint8_t) *glyph;
+	  uint8_t flag = *glyph;
 	  glyph++;
 
 	  unsigned int repeat = 1;
 	  if (flag & FLAG_REPEAT)
 	  {
-	    if (glyph >= glyph_end)
-	    {
-	      DEBUG_MSG(SUBSET, nullptr, "Bad flag");
-	      return false;
-	    }
-	    repeat = ((uint8_t) *glyph) + 1;
+	    if (unlikely (glyph >= glyph_end)) return Glyph ();
+	    repeat = *glyph + 1;
 	    glyph++;
 	  }
 
@@ -335,128 +495,548 @@
 	  if (flag & FLAG_Y_SHORT) yBytes = 1;
 	  else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
 
-	  coordBytes += (xBytes + yBytes) * repeat;
-	  coordsWithFlags += repeat;
-	  if (coordsWithFlags >= nCoordinates)
-	    break;
+	  coord_bytes += (xBytes + yBytes) * repeat;
+	  coords_with_flags += repeat;
+	  if (coords_with_flags >= num_coordinates) break;
 	}
 
-	if (coordsWithFlags != nCoordinates)
-	{
-	  DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
-	  return false;
-	}
-	glyph += coordBytes;
-
-	if (glyph < glyph_end)
-	  *end_offset -= glyph_end - glyph;
+	if (unlikely (coords_with_flags != num_coordinates)) return Glyph ();
+	return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)));
       }
+
+      /* zero instruction length */
+      void drop_hints ()
+      {
+	GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
+	(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
+      }
+
+      void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+      {
+	unsigned int instructions_len = instructions_length ();
+	unsigned int glyph_length = length (instructions_len);
+	dest_start = bytes.sub_array (0, glyph_length - instructions_len);
+	dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
+      }
+
+      struct x_setter_t
+      {
+	void set (contour_point_t &point, float v) const { point.x = v; }
+	bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; }
+	bool is_same  (uint8_t flag) const { return flag & FLAG_X_SAME; }
+      };
+
+      struct y_setter_t
+      {
+	void set (contour_point_t &point, float v) const { point.y = v; }
+	bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; }
+	bool is_same  (uint8_t flag) const { return flag & FLAG_Y_SAME; }
+      };
+
+      template <typename T>
+      static bool read_points (const HBUINT8 *&p /* IN/OUT */,
+			       contour_point_vector_t &points_ /* IN/OUT */,
+			       const hb_bytes_t &bytes)
+      {
+	T coord_setter;
+	float v = 0;
+	for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++)
+	{
+	  uint8_t flag = points_[i].flag;
+	  if (coord_setter.is_short (flag))
+	  {
+	    if (unlikely (!bytes.in_range (p))) return false;
+	    if (coord_setter.is_same (flag))
+	      v += *p++;
+	    else
+	      v -= *p++;
+	  }
+	  else
+	  {
+	    if (!coord_setter.is_same (flag))
+	    {
+	      if (unlikely (!bytes.in_range ((const HBUINT16 *) p))) return false;
+	      v += *(const HBINT16 *) p;
+	      p += HBINT16::static_size;
+	    }
+	  }
+	  coord_setter.set (points_[i], v);
+	}
+	return true;
+      }
+
+      bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+			       hb_vector_t<unsigned int> &end_points_ /* OUT */,
+			       const bool phantom_only=false) const
+      {
+	const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
+	int num_contours = header.numberOfContours;
+	if (unlikely (!bytes.in_range (&endPtsOfContours[num_contours + 1]))) return false;
+	unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
+
+	points_.resize (num_points + PHANTOM_COUNT);
+	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
+	if (phantom_only) return true;
+
+	/* Read simple glyph points if !phantom_only */
+	end_points_.resize (num_contours);
+
+	for (int i = 0; i < num_contours; i++)
+	  end_points_[i] = endPtsOfContours[i];
+
+	/* Skip instructions */
+	const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
+						     endPtsOfContours[num_contours]);
+
+	/* Read flags */
+	for (unsigned int i = 0; i < num_points; i++)
+	{
+	  if (unlikely (!bytes.in_range (p))) return false;
+	  uint8_t flag = *p++;
+	  points_[i].flag = flag;
+	  if (flag & FLAG_REPEAT)
+	  {
+	    if (unlikely (!bytes.in_range (p))) return false;
+	    unsigned int repeat_count = *p++;
+	    while ((repeat_count-- > 0) && (++i < num_points))
+	      points_[i].flag = flag;
+	  }
+	}
+
+	/* Read x & y coordinates */
+	return (read_points<x_setter_t> (p, points_, bytes) &&
+		read_points<y_setter_t> (p, points_, bytes));
+      }
+    };
+
+    struct CompositeGlyph
+    {
+      const GlyphHeader &header;
+      hb_bytes_t bytes;
+      CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+	header (header_), bytes (bytes_) {}
+
+      composite_iter_t get_iterator () const
+      { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); }
+
+      unsigned int instructions_length (hb_bytes_t bytes) const
+      {
+	unsigned int start = bytes.length;
+	unsigned int end = bytes.length;
+	const CompositeGlyphChain *last = nullptr;
+	for (auto &item : get_iterator ())
+	  last = &item;
+	if (unlikely (!last)) return 0;
+
+	if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS)
+	  start = (char *) last - &bytes + last->get_size ();
+	if (unlikely (start > end)) return 0;
+	return end - start;
+      }
+
+      /* Trimming for composites not implemented.
+       * If removing hints it falls out of that. */
+      const Glyph trim_padding () const { return Glyph (bytes); }
+
+      /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */
+      void drop_hints ()
+      {
+	for (const auto &_ : get_iterator ())
+	  *const_cast<OT::HBUINT16 *> (&_.flags) = (uint16_t) _.flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS;
+      }
+
+      /* Chop instructions off the end */
+      void drop_hints_bytes (hb_bytes_t &dest_start) const
+      { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
+
+      bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+			       hb_vector_t<unsigned int> &end_points_ /* OUT */,
+			       const bool phantom_only=false) const
+      {
+	/* add one pseudo point for each component in composite glyph */
+	unsigned int num_points = hb_len (get_iterator ());
+	points_.resize (num_points + PHANTOM_COUNT);
+	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
+	return true;
+      }
+    };
+
+    enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
+
+    enum phantom_point_index_t
+    {
+      PHANTOM_LEFT   = 0,
+      PHANTOM_RIGHT  = 1,
+      PHANTOM_TOP    = 2,
+      PHANTOM_BOTTOM = 3,
+      PHANTOM_COUNT  = 4
+    };
+
+    public:
+    composite_iter_t get_composite_iterator () const
+    {
+      if (type != COMPOSITE) return composite_iter_t ();
+      return CompositeGlyph (*header, bytes).get_iterator ();
+    }
+
+    const Glyph trim_padding () const
+    {
+      switch (type) {
+      case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
+      case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
+      default:        return bytes;
+      }
+    }
+
+    void drop_hints ()
+    {
+      switch (type) {
+      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
+      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
+      default:        return;
+      }
+    }
+
+    void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+    {
+      switch (type) {
+      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
+      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
+      default:        return;
+      }
+    }
+
+    /* for a simple glyph, return contour end points, flags, along with coordinate points
+     * for a composite glyph, return pseudo component points
+     * in both cases points trailed with four phantom points
+     */
+    bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+			     hb_vector_t<unsigned int> &end_points_ /* OUT */,
+			     const bool phantom_only=false) const
+    {
+      switch (type) {
+      case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only);
+      case SIMPLE:    return SimpleGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only);
+      default:
+	/* empty glyph */
+	points_.resize (PHANTOM_COUNT);
+	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
+	return true;
+      }
+    }
+
+    bool is_simple_glyph ()    const { return type == SIMPLE; }
+    bool is_composite_glyph () const { return type == COMPOSITE; }
+
+    bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+    {
+      if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+      return header->get_extents (font, gid, extents);
+    }
+
+    hb_bytes_t get_bytes ()          const { return bytes; }
+    const GlyphHeader &get_header () const { return *header; }
+
+    Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) :
+      bytes (bytes_), header (bytes.as<GlyphHeader> ())
+    {
+      int num_contours = header->numberOfContours;
+      if (unlikely (num_contours == 0)) type = EMPTY;
+      else if (num_contours > 0) type = SIMPLE;
+      else type = COMPOSITE; /* negative numbers */
+    }
+
+    protected:
+    hb_bytes_t bytes;
+    const GlyphHeader *header;
+    unsigned type;
+  };
+
+  struct accelerator_t
+  {
+    void init (hb_face_t *face_)
+    {
+      short_offset = false;
+      num_glyphs = 0;
+      loca_table = nullptr;
+      glyf_table = nullptr;
+      face = face_;
+      const OT::head &head = *face->table.head;
+      if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
+	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+	return;
+      short_offset = 0 == head.indexToLocFormat;
+
+      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
+      glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
+
+      num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+    }
+
+    void fini ()
+    {
+      loca_table.destroy ();
+      glyf_table.destroy ();
+    }
+
+    enum phantom_point_index_t
+    {
+      PHANTOM_LEFT   = 0,
+      PHANTOM_RIGHT  = 1,
+      PHANTOM_TOP    = 2,
+      PHANTOM_BOTTOM = 3,
+      PHANTOM_COUNT  = 4
+    };
+
+    protected:
+
+    void init_phantom_points (hb_codepoint_t gid, hb_array_t<contour_point_t> &phantoms /* IN/OUT */) const
+    {
+      const Glyph &glyph = glyph_for_gid (gid);
+      int h_delta = (int) glyph.get_header ().xMin - face->table.hmtx->get_side_bearing (gid);
+      int v_orig  = (int) glyph.get_header ().yMax + face->table.vmtx->get_side_bearing (gid);
+      unsigned int h_adv = face->table.hmtx->get_advance (gid);
+      unsigned int v_adv = face->table.vmtx->get_advance (gid);
+
+      phantoms[PHANTOM_LEFT].x = h_delta;
+      phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
+      phantoms[PHANTOM_TOP].y = v_orig;
+      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+    }
+
+    struct contour_bounds_t
+    {
+      contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
+
+      void add (const contour_point_t &p)
+      {
+	min_x = hb_min (min_x, p.x);
+	min_y = hb_min (min_y, p.y);
+	max_x = hb_max (max_x, p.x);
+	max_y = hb_max (max_y, p.y);
+      }
+
+      bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
+
+      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
+      {
+	if (unlikely (empty ()))
+	{
+	  extents->width = 0;
+	  extents->x_bearing = 0;
+	  extents->height = 0;
+	  extents->y_bearing = 0;
+	  return;
+	}
+	extents->x_bearing = font->em_scalef_x (min_x);
+	extents->width = font->em_scalef_x (max_x - min_x);
+	extents->y_bearing = font->em_scalef_y (max_y);
+	extents->height = font->em_scalef_y (min_y - max_y);
+      }
+
+      protected:
+      float min_x, min_y, max_x, max_y;
+    };
+
+#ifndef HB_NO_VAR
+    /* Note: Recursively calls itself.
+     * all_points includes phantom points
+     */
+    bool get_points_var (hb_codepoint_t gid,
+			 const int *coords, unsigned int coord_count,
+			 contour_point_vector_t &all_points /* OUT */,
+			 unsigned int depth = 0) const
+    {
+      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false;
+      contour_point_vector_t points;
+      hb_vector_t<unsigned int> end_points;
+      const Glyph &glyph = glyph_for_gid (gid);
+      if (unlikely (!glyph.get_contour_points (points, end_points))) return false;
+      hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+      init_phantom_points (gid, phantoms);
+      if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array (), end_points.as_array ()))) return false;
+
+      unsigned int comp_index = 0;
+      if (glyph.is_simple_glyph ())
+	all_points.extend (points.as_array ());
+      else if (glyph.is_composite_glyph ())
+      {
+	for (auto &item : glyph.get_composite_iterator ())
+	{
+	  contour_point_vector_t comp_points;
+	  if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count,
+					 comp_points, depth))
+			|| comp_points.length < PHANTOM_COUNT)
+	    return false;
+
+	  /* Copy phantom points from component if USE_MY_METRICS flag set */
+	  if (item.is_use_my_metrics ())
+	    for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+	      phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+	  /* Apply component transformation & translation */
+	  item.transform_points (comp_points);
+
+	  /* Apply translatation from gvar */
+	  comp_points.translate (points[comp_index]);
+
+	  if (item.is_anchored ())
+	  {
+	    unsigned int p1, p2;
+	    item.get_anchor_points (p1, p2);
+	    if (likely (p1 < all_points.length && p2 < comp_points.length))
+	    {
+	      contour_point_t delta;
+	      delta.init (all_points[p1].x - comp_points[p2].x,
+			  all_points[p1].y - comp_points[p2].y);
+
+	      comp_points.translate (delta);
+	    }
+	  }
+
+	  all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+	  comp_index++;
+	}
+
+	all_points.extend (phantoms);
+      }
+      else return false;
+
       return true;
     }
 
-    bool get_offsets (hb_codepoint_t  glyph,
-			     unsigned int   *start_offset /* OUT */,
-			     unsigned int   *end_offset   /* OUT */) const
+    bool get_points_bearing_applied (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const
     {
-      if (unlikely (glyph >= num_glyphs))
-	return false;
+      if (unlikely (!get_points_var (gid, font->coords, font->num_coords, all_points) ||
+		    all_points.length < PHANTOM_COUNT)) return false;
+
+      /* Undocumented rasterizer behavior:
+       * Shift points horizontally by the updated left side bearing
+       */
+      contour_point_t delta;
+      delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f);
+      if (delta.x) all_points.translate (delta);
+      return true;
+    }
+
+    protected:
+
+    bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t gid,
+				       hb_glyph_extents_t *extents=nullptr /* OUT */,
+				       contour_point_vector_t *phantoms=nullptr /* OUT */) const
+    {
+      contour_point_vector_t all_points;
+      if (!unlikely (get_points_bearing_applied (font, gid, all_points))) return false;
+      if (extents)
+      {
+	contour_bounds_t bounds;
+	for (unsigned int i = 0; i + PHANTOM_COUNT < all_points.length; i++)
+	  bounds.add (all_points[i]);
+	bounds.get_extents (font, extents);
+      }
+      if (phantoms)
+	for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+	  (*phantoms)[i] = all_points[all_points.length - PHANTOM_COUNT + i];
+      return true;
+    }
+
+    bool get_var_metrics (hb_font_t *font, hb_codepoint_t gid,
+			  contour_point_vector_t &phantoms) const
+    { return get_var_extents_and_phantoms (font, gid, nullptr, &phantoms); }
+
+    bool get_extents_var (hb_font_t *font, hb_codepoint_t gid,
+			  hb_glyph_extents_t *extents) const
+    { return get_var_extents_and_phantoms (font, gid, extents); }
+#endif
+
+    public:
+#ifndef HB_NO_VAR
+    unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t gid,
+				  bool is_vertical) const
+    {
+      bool success = false;
+      contour_point_vector_t phantoms;
+      phantoms.resize (PHANTOM_COUNT);
+
+      if (likely (font->num_coords == face->table.gvar->get_axis_count ()))
+	success = get_var_metrics (font, gid, phantoms);
+
+      if (unlikely (!success))
+	return is_vertical ? face->table.vmtx->get_advance (gid) : face->table.hmtx->get_advance (gid);
+
+      if (is_vertical)
+	return roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y);
+      else
+	return roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x);
+    }
+
+    int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+    {
+      hb_glyph_extents_t extents;
+      contour_point_vector_t phantoms;
+      phantoms.resize (PHANTOM_COUNT);
+
+      if (unlikely (!get_var_extents_and_phantoms (font, gid, &extents, &phantoms)))
+	return is_vertical ? face->table.vmtx->get_side_bearing (gid) : face->table.hmtx->get_side_bearing (gid);
+
+      return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x);
+    }
+#endif
+
+    bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+    {
+#ifndef HB_NO_VAR
+      unsigned int coord_count;
+      const int *coords = hb_font_get_var_coords_normalized (font, &coord_count);
+      if (coords && coord_count > 0 && coord_count == face->table.gvar->get_axis_count ())
+	return get_extents_var (font, gid, extents);
+#endif
+
+      if (unlikely (gid >= num_glyphs)) return false;
+
+      return glyph_for_gid (gid).get_extents (font, gid, extents);
+    }
+
+    const Glyph
+    glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
+    {
+      unsigned int start_offset, end_offset;
+      if (unlikely (gid >= num_glyphs)) return Glyph ();
 
       if (short_offset)
       {
 	const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
-	*start_offset = 2 * offsets[glyph];
-	*end_offset   = 2 * offsets[glyph + 1];
+	start_offset = 2 * offsets[gid];
+	end_offset   = 2 * offsets[gid + 1];
       }
       else
       {
 	const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
-
-	*start_offset = offsets[glyph];
-	*end_offset   = offsets[glyph + 1];
+	start_offset = offsets[gid];
+	end_offset   = offsets[gid + 1];
       }
 
-      if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ())
-	return false;
+      if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
+	return Glyph ();
 
-      return true;
+      Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
+			       end_offset - start_offset));
+      return needs_padding_removal ? glyph.trim_padding () : glyph;
     }
 
-    bool get_instruction_offsets (unsigned int start_offset,
-				  unsigned int end_offset,
-				  unsigned int *instruction_start /* OUT */,
-				  unsigned int *instruction_end /* OUT */) const
+    void
+    add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
+			  unsigned int depth = 0) const
     {
-      if (end_offset - start_offset < GlyphHeader::static_size)
-      {
-	*instruction_start = 0;
-	*instruction_end = 0;
-	return true; /* Empty glyph; no instructions. */
-      }
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
-      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
-      if (num_contours < 0)
-      {
-	CompositeGlyphHeader::Iterator composite_it;
-	if (unlikely (!CompositeGlyphHeader::get_iterator (
-	    (const char*) this->glyf_table + start_offset,
-	     end_offset - start_offset, &composite_it))) return false;
-	const CompositeGlyphHeader *last;
-	do {
-	  last = composite_it.current;
-	} while (composite_it.move_to_next ());
+      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return;
+      /* Check if is already visited */
+      if (gids_to_retain->has (gid)) return;
 
-	if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
-	  *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size ();
-	else
-	  *instruction_start = end_offset;
-	*instruction_end = end_offset;
-	if (unlikely (*instruction_start > *instruction_end))
-	{
-	  DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
-	  return false;
-	}
-      }
-      else
-      {
-	unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
-	if (unlikely (instruction_length_offset + 2 > end_offset))
-	{
-	  DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
-	  return false;
-	}
+      gids_to_retain->add (gid);
 
-	const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
-	unsigned int start = instruction_length_offset + 2;
-	unsigned int end = start + (uint16_t) instruction_length;
-	if (unlikely (end > end_offset)) // Out of bounds of the current glyph
-	{
-	  DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
-	  return false;
-	}
-
-	*instruction_start = start;
-	*instruction_end = end;
-      }
-      return true;
-    }
-
-    bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
-    {
-      unsigned int start_offset, end_offset;
-      if (!get_offsets (glyph, &start_offset, &end_offset))
-	return false;
-
-      if (end_offset - start_offset < GlyphHeader::static_size)
-	return true; /* Empty glyph; zero extents. */
-
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
-
-      extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
-      extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
-      extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
-      extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
-
-      return true;
+      for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
+        add_gid_and_children (item.glyphIndex, gids_to_retain, depth);
     }
 
     private:
@@ -464,14 +1044,66 @@
     unsigned int num_glyphs;
     hb_blob_ptr_t<loca> loca_table;
     hb_blob_ptr_t<glyf> glyf_table;
+    hb_face_t *face;
+  };
+
+  struct SubsetGlyph
+  {
+    hb_codepoint_t new_gid;
+    hb_codepoint_t old_gid;
+    Glyph source_glyph;
+    hb_bytes_t dest_start;  /* region of source_glyph to copy first */
+    hb_bytes_t dest_end;    /* region of source_glyph to copy second */
+
+    bool serialize (hb_serialize_context_t *c,
+		    const hb_subset_plan_t *plan) const
+    {
+      TRACE_SERIALIZE (this);
+
+      hb_bytes_t dest_glyph = dest_start.copy (c);
+      dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
+      unsigned int pad_length = padding ();
+      DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length  + pad_length, pad_length);
+
+      HBUINT8 pad;
+      pad = 0;
+      while (pad_length > 0)
+      {
+	c->embed (pad);
+	pad_length--;
+      }
+
+      if (!unlikely (dest_glyph.length)) return_trace (true);
+
+      /* update components gids */
+      for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
+      {
+	hb_codepoint_t new_gid;
+	if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid))
+	  ((OT::glyf::CompositeGlyphChain *) &_)->glyphIndex = new_gid;
+      }
+
+      if (plan->drop_hints) Glyph (dest_glyph).drop_hints ();
+
+      return_trace (true);
+    }
+
+    void drop_hints_bytes ()
+    { source_glyph.drop_hints_bytes (dest_start, dest_end); }
+
+    unsigned int      length () const { return dest_start.length + dest_end.length; }
+    /* pad to 2 to ensure 2-byte loca will be ok */
+    unsigned int     padding () const { return length () % 2; }
+    unsigned int padded_size () const { return length () + padding (); }
   };
 
   protected:
-  UnsizedArrayOf<HBUINT8>	dataZ;		/* Glyphs data. */
+  UnsizedArrayOf<HBUINT8>
+		dataZ;	/* Glyphs data. */
   public:
-  DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
-			* check the size externally, allow Null() object of it by
-			* defining it MIN() instead. */
+  DEFINE_SIZE_MIN (0);	/* In reality, this is UNBOUNDED() type; but since we always
+			 * check the size externally, allow Null() object of it by
+			 * defining it _MIN instead. */
 };
 
 struct glyf_accelerator_t : glyf::accelerator_t {};
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 48421ee..96c1d1f 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -41,68 +41,31 @@
 
 struct DeviceRecord
 {
-  struct SubsetView
-  {
-    const DeviceRecord *source_device_record;
-    unsigned int sizeDeviceRecord;
-    hb_subset_plan_t *subset_plan;
-
-    void init (const DeviceRecord *source_device_record,
-	       unsigned int sizeDeviceRecord,
-	       hb_subset_plan_t   *subset_plan)
-    {
-      this->source_device_record = source_device_record;
-      this->sizeDeviceRecord = sizeDeviceRecord;
-      this->subset_plan = subset_plan;
-    }
-
-    unsigned int len () const
-    { return this->subset_plan->glyphs.len; }
-
-    const HBUINT8* operator [] (unsigned int i) const
-    {
-      if (unlikely (i >= len ())) return nullptr;
-      hb_codepoint_t gid = this->subset_plan->glyphs [i];
-
-      if (gid >= sizeDeviceRecord - DeviceRecord::min_size)
-        return nullptr;
-      return &(this->source_device_record->widthsZ[gid]);
-    }
-  };
-
-  static unsigned int get_size (unsigned int count)
+  static unsigned int get_size (unsigned count)
   { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
 
-  bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned int size = get_size (subset_view.len ());
-    if (unlikely (!c->allocate_size<DeviceRecord> (size)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
-		 size);
-      return_trace (false);
-    }
+    unsigned length = it.len ();
 
-    this->pixelSize.set (subset_view.source_device_record->pixelSize);
-    this->maxWidth.set (subset_view.source_device_record->maxWidth);
+    if (unlikely (!c->extend (*this, length)))  return_trace (false);
 
-    for (unsigned int i = 0; i < subset_view.len (); i++)
-    {
-      const HBUINT8 *width = subset_view[i];
-      if (!width)
-      {
-	DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
-	return_trace (false);
-      }
-      widthsZ[i].set (*width);
-    }
+    this->pixelSize = pixelSize;
+    this->maxWidth =
+    + it
+    | hb_reduce (hb_max, 0u);
+
+    + it
+    | hb_sink (widthsZ.as_array (length));
 
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
@@ -119,7 +82,7 @@
 
 struct hdmx
 {
-  enum { tableTag = HB_OT_TAG_hdmx };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
 
   unsigned int get_size () const
   { return min_size + numRecords * sizeDeviceRecord; }
@@ -132,62 +95,63 @@
     return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
   }
 
-  bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
   {
     TRACE_SERIALIZE (this);
 
     if (unlikely (!c->extend_min ((*this))))  return_trace (false);
 
-    this->version.set (source_hdmx->version);
-    this->numRecords.set (source_hdmx->numRecords);
-    this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.len));
+    this->version = version;
+    this->numRecords = it.len ();
+    this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
 
-    for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
-    {
-      DeviceRecord::SubsetView subset_view;
-      subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
+    + it
+    | hb_apply ([c] (const hb_item_type<Iterator>& _) {
+		  c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
+		})
+    ;
 
-      if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
-	return_trace (false);
-    }
+    return_trace (c->successful);
+  }
 
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
+    if (unlikely (!hdmx_prime)) return_trace (false);
+
+    auto it =
+    + hb_range ((unsigned) numRecords)
+    | hb_map ([c, this] (unsigned _)
+	{
+	  const DeviceRecord *device_record =
+	    &StructAtOffset<DeviceRecord> (&firstDeviceRecord,
+					   _ * sizeDeviceRecord);
+	  auto row =
+	    + hb_range (c->plan->num_output_glyphs ())
+	    | hb_map (c->plan->reverse_glyph_map)
+	    | hb_map ([=] (hb_codepoint_t _)
+		      {
+			if (c->plan->is_empty_glyph (_))
+			  return Null(HBUINT8);
+			return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+		      })
+	    ;
+	  return hb_pair ((unsigned) device_record->pixelSize, +row);
+	})
+    ;
+
+    hdmx_prime->serialize (c->serializer, version, it);
     return_trace (true);
   }
 
-  static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
+  unsigned get_num_glyphs () const
   {
-    return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.len);
-  }
-
-  bool subset (hb_subset_plan_t *plan) const
-  {
-    size_t dest_size = get_subsetted_size (this, plan);
-    hdmx *dest = (hdmx *) malloc (dest_size);
-    if (unlikely (!dest))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
-      return false;
-    }
-
-    hb_serialize_context_t c (dest, dest_size);
-    hdmx *hdmx_prime = c.start_serialize<hdmx> ();
-    if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
-    {
-      free (dest);
-      DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
-      return false;
-    }
-    c.end_serialize ();
-
-    hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
-						 dest_size,
-						 HB_MEMORY_MODE_READONLY,
-						 dest,
-						 free);
-    bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
-    hb_blob_destroy (hdmx_prime_blob);
-
-    return result;
+    return sizeDeviceRecord - DeviceRecord::min_size;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 41062ca..3c0bb3d 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -45,7 +45,7 @@
 {
   friend struct OffsetTable;
 
-  enum { tableTag = HB_OT_TAG_head };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
 
   unsigned int get_upem () const
   {
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index 7bc1817..778b6c5 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -45,6 +45,8 @@
 template <typename T>
 struct _hea
 {
+  bool has_data () const { return version.major; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -86,10 +88,10 @@
 };
 
 struct hhea : _hea<hhea> {
-  enum { tableTag = HB_OT_TAG_hhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea;
 };
 struct vhea : _hea<vhea> {
-  enum { tableTag = HB_OT_TAG_vhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea;
 };
 
 
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index fa74a0e..e20b372 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -29,8 +29,8 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-hhea-table.hh"
-#include "hb-ot-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-metrics.hh"
 
 /*
  * hmtx -- Horizontal Metrics
@@ -42,6 +42,13 @@
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
+HB_INTERNAL int
+_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+
+HB_INTERNAL unsigned
+_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+
+
 namespace OT {
 
 
@@ -53,6 +60,7 @@
   DEFINE_SIZE_STATIC (4);
 };
 
+
 template <typename T, typename H>
 struct hmtxvmtx
 {
@@ -66,7 +74,7 @@
 
 
   bool subset_update_header (hb_subset_plan_t *plan,
-				    unsigned int num_hmetrics) const
+			     unsigned int num_hmetrics) const
   {
     hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -78,7 +86,7 @@
 
     unsigned int length;
     H *table = (H *) hb_blob_get_data (dest_blob, &length);
-    table->numberOfLongMetrics.set (num_hmetrics);
+    table->numberOfLongMetrics = num_hmetrics;
 
     bool result = plan->add_table (H::tableTag, dest_blob);
     hb_blob_destroy (dest_blob);
@@ -86,100 +94,68 @@
     return result;
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  unsigned num_advances)
   {
-    typename T::accelerator_t _mtx;
-    _mtx.init (plan->source);
+    unsigned idx = 0;
+    + it
+    | hb_apply ([c, &idx, num_advances] (const hb_item_type<Iterator>& _)
+		{
+		  if (idx < num_advances)
+		  {
+		    LongMetric lm;
+		    lm.advance = _.first;
+		    lm.sb = _.second;
+		    if (unlikely (!c->embed<LongMetric> (&lm))) return;
+		  }
+		  else
+		  {
+		    FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
+		    if (unlikely (!sb)) return;
+		    *sb = _.second;
+		  }
+		  idx++;
+		})
+    ;
+  }
 
-    /* All the trailing glyphs with the same advance can use one LongMetric
-     * and just keep LSB */
-    hb_vector_t<hb_codepoint_t> &gids = plan->glyphs;
-    unsigned int num_advances = gids.len;
-    unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]);
-    while (num_advances > 1 &&
-	   last_advance == _mtx.get_advance (gids[num_advances - 2]))
-    {
-      num_advances--;
-    }
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
 
-    /* alloc the new table */
-    size_t dest_sz = num_advances * 4
-		  + (gids.len - num_advances) * 2;
-    void *dest = (void *) malloc (dest_sz);
-    if (unlikely (!dest))
-    {
-      return false;
-    }
-    DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances);
-    DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.len - num_advances, (unsigned int) dest_sz);
+    T *table_prime = c->serializer->start_embed <T> ();
+    if (unlikely (!table_prime)) return_trace (false);
 
-    const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr);
-    // Copy everything over
-    LongMetric * old_metrics = (LongMetric *) source_table;
-    FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances);
-    char * dest_pos = (char *) dest;
+    accelerator_t _mtx;
+    _mtx.init (c->plan->source);
+    unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
 
-    bool failed = false;
-    for (unsigned int i = 0; i < gids.len; i++)
-    {
-      /* the last metric or the one for gids[i] */
-      LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]);
-      if (gids[i] < _mtx.num_advances)
-      {
-        /* src is a LongMetric */
-        if (i < num_advances)
-        {
-          /* dest is a LongMetric, copy it */
-          *((LongMetric *) dest_pos) = *src_metric;
-        }
-        else
-        {
-          /* dest just sb */
-          *((FWORD *) dest_pos) = src_metric->sb;
-        }
-      }
-      else
-      {
-	if (gids[i] >= _mtx.num_metrics)
-	{
-	  DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d",
-		    gids[i], _mtx.num_metrics);
-	  failed = true;
-	  break;
-	}
-	FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances);
-        if (i < num_advances)
-        {
-          /* dest needs a full LongMetric */
-          LongMetric *metric = (LongMetric *)dest_pos;
-          metric->advance = src_metric->advance;
-          metric->sb = src_sb;
-        }
-        else
-        {
-          /* dest just needs an sb */
-          *((FWORD *) dest_pos) = src_sb;
-        }
-      }
-      dest_pos += (i < num_advances ? 4 : 2);
-    }
+    auto it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map ([c, &_mtx] (unsigned _)
+	      {
+		hb_codepoint_t old_gid;
+		if (!c->plan->old_gid_for_new_gid (_, &old_gid))
+		  return hb_pair (0u, 0);
+		return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+	      })
+    ;
+
+    table_prime->serialize (c->serializer, it, num_advances);
+
     _mtx.fini ();
 
-    // Amend header num hmetrics
-    if (failed || unlikely (!subset_update_header (plan, num_advances)))
-    {
-      free (dest);
-      return false;
-    }
+    if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
+      return_trace (false);
 
-    hb_blob_t *result = hb_blob_create ((const char *)dest,
-                                        dest_sz,
-                                        HB_MEMORY_MODE_READONLY,
-                                        dest,
-                                        free);
-    bool success = plan->add_table (T::tableTag, result);
-    hb_blob_destroy (result);
-    return success;
+    // Amend header num hmetrics
+    if (unlikely (!subset_update_header (c->plan, num_advances)))
+      return_trace (false);
+
+    return_trace (true);
   }
 
   struct accelerator_t
@@ -187,32 +163,11 @@
     friend struct hmtxvmtx;
 
     void init (hb_face_t *face,
-		      unsigned int default_advance_ = 0)
+	       unsigned int default_advance_ = 0)
     {
       default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
 
-      bool got_font_extents = false;
-      if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ())
-      {
-	ascender = abs (face->table.OS2->sTypoAscender);
-	descender = -abs (face->table.OS2->sTypoDescender);
-	line_gap = face->table.OS2->sTypoLineGap;
-	got_font_extents = (ascender | descender) != 0;
-      }
-
-      hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face);
-      const H *_hea_table = _hea_blob->as<H> ();
-      num_advances = _hea_table->numberOfLongMetrics;
-      if (!got_font_extents)
-      {
-	ascender = abs (_hea_table->ascender);
-	descender = -abs (_hea_table->descender);
-	line_gap = _hea_table->lineGap;
-	got_font_extents = (ascender | descender) != 0;
-      }
-      hb_blob_destroy (_hea_blob);
-
-      has_font_extents = got_font_extents;
+      num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
 
       table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag);
 
@@ -240,19 +195,35 @@
       var_table.destroy ();
     }
 
-    /* TODO Add variations version. */
-    unsigned int get_side_bearing (hb_codepoint_t glyph) const
+    int get_side_bearing (hb_codepoint_t glyph) const
     {
       if (glyph < num_advances)
-        return table->longMetricZ[glyph].sb;
+	return table->longMetricZ[glyph].sb;
 
       if (unlikely (glyph >= num_metrics))
-        return 0;
+	return 0;
 
       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
       return bearings[glyph - num_advances];
     }
 
+    int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+    {
+      int side_bearing = get_side_bearing (glyph);
+
+#ifndef HB_NO_VAR
+      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+	return side_bearing;
+
+      if (var_table.get_length ())
+        return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+
+      return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+#else
+      return side_bearing;
+#endif
+    }
+
     unsigned int get_advance (hb_codepoint_t glyph) const
     {
       if (unlikely (glyph >= num_metrics))
@@ -266,25 +237,52 @@
 	  return default_advance;
       }
 
-      return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance;
+      return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
     }
 
     unsigned int get_advance (hb_codepoint_t  glyph,
 			      hb_font_t      *font) const
     {
       unsigned int advance = get_advance (glyph);
-      if (likely (glyph < num_metrics))
-      {
-	advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
-      }
+
+#ifndef HB_NO_VAR
+      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+	return advance;
+
+      if (var_table.get_length ())
+	return advance + roundf (var_table->get_advance_var (font, glyph)); // TODO Optimize?!
+
+      return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+#else
       return advance;
+#endif
     }
 
-    public:
-    bool has_font_extents;
-    int ascender;
-    int descender;
-    int line_gap;
+    unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
+    {
+      unsigned int num_advances = plan->num_output_glyphs ();
+      unsigned int last_advance = _advance_for_new_gid (plan,
+							num_advances - 1);
+      while (num_advances > 1 &&
+	     last_advance == _advance_for_new_gid (plan,
+						   num_advances - 2))
+      {
+	num_advances--;
+      }
+
+      return num_advances;
+    }
+
+    private:
+    unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
+				       hb_codepoint_t new_gid) const
+    {
+      hb_codepoint_t old_gid;
+      if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
+	return 0;
+
+      return get_advance (old_gid);
+    }
 
     protected:
     unsigned int num_metrics;
@@ -323,14 +321,14 @@
 };
 
 struct hmtx : hmtxvmtx<hmtx, hhea> {
-  enum { tableTag = HB_OT_TAG_hmtx };
-  enum { variationsTag = HB_OT_TAG_HVAR };
-  enum { os2Tag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
+  static constexpr bool is_horizontal = true;
 };
 struct vmtx : hmtxvmtx<vmtx, vhea> {
-  enum { tableTag = HB_OT_TAG_vmtx };
-  enum { variationsTag = HB_OT_TAG_VVAR };
-  enum { os2Tag = HB_TAG_NONE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
+  static constexpr bool is_horizontal = false;
 };
 
 struct hmtx_accelerator_t : hmtx::accelerator_t {};
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index 5e75d08..36e5a35 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -47,9 +47,9 @@
   int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
   {
     hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
-    hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (kernValue).as_array (glyphCount);
-    hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (leftClass).as_array (glyphCount);
-    hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8> > (rightClass).as_array (leftClassCount * rightClassCount);
+    hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
+    hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
+    hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
 
     unsigned int leftC = leftClass[left];
     unsigned int rightC = rightClass[right];
@@ -121,16 +121,20 @@
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
     case 0:	return_trace (c->dispatch (u.format0));
-    case 1:	return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ());
+#ifndef HB_NO_AAT_SHAPE
+    case 1:	return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
+#endif
     case 2:	return_trace (c->dispatch (u.format2));
-    case 3:	return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ());
+#ifndef HB_NO_AAT_SHAPE
+    case 3:	return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
+#endif
     default:	return_trace (c->default_return_value ());
     }
   }
@@ -160,11 +164,11 @@
 
 struct KernOTSubTableHeader
 {
-  enum { apple = false };
+  static constexpr bool apple = false;
   typedef AAT::ObsoleteTypes Types;
 
-  unsigned int tuple_count () const { return 0; }
-  bool is_horizontal () const { return (coverage & Horizontal); }
+  unsigned   tuple_count () const { return 0; }
+  bool     is_horizontal () const { return (coverage & Horizontal); }
 
   enum Coverage
   {
@@ -197,8 +201,8 @@
 {
   friend struct AAT::KerxTable<KernOT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0u;
 
   typedef KernOTSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -215,11 +219,11 @@
 
 struct KernAATSubTableHeader
 {
-  enum { apple = true };
+  static constexpr bool apple = true;
   typedef AAT::ObsoleteTypes Types;
 
-  unsigned int tuple_count () const { return 0; }
-  bool is_horizontal () const       { return !(coverage & Vertical); }
+  unsigned   tuple_count () const { return 0; }
+  bool     is_horizontal () const { return !(coverage & Vertical); }
 
   enum Coverage
   {
@@ -252,8 +256,8 @@
 {
   friend struct AAT::KerxTable<KernAAT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0x00010000u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0x00010000u;
 
   typedef KernAATSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -269,16 +273,18 @@
 
 struct kern
 {
-  enum { tableTag = HB_OT_TAG_kern };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
 
-  bool has_data () const { return u.version32; }
-  unsigned int get_type () const { return u.major; }
+  bool     has_data () const { return u.version32; }
+  unsigned get_type () const { return u.major; }
 
   bool has_state_machine () const
   {
     switch (get_type ()) {
     case 0: return u.ot.has_state_machine ();
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.has_state_machine ();
+#endif
     default:return false;
     }
   }
@@ -287,7 +293,9 @@
   {
     switch (get_type ()) {
     case 0: return u.ot.has_cross_stream ();
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.has_cross_stream ();
+#endif
     default:return false;
     }
   }
@@ -296,7 +304,9 @@
   {
     switch (get_type ()) {
     case 0: return u.ot.get_h_kerning (left, right);
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.get_h_kerning (left, right);
+#endif
     default:return 0;
     }
   }
@@ -304,14 +314,16 @@
   bool apply (AAT::hb_aat_apply_context_t *c) const
   { return dispatch (c); }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:	return_trace (c->dispatch (u.ot));
-    case 1:	return_trace (c->dispatch (u.aat));
+    case 0:	return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
+#ifndef HB_NO_AAT_SHAPE
+    case 1:	return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
+#endif
     default:	return_trace (c->default_return_value ());
     }
   }
@@ -328,7 +340,9 @@
   HBUINT32		version32;
   HBUINT16		major;
   KernOT		ot;
+#ifndef HB_NO_AAT_SHAPE
   KernAAT		aat;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (4, version32);
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 6c39932..02fe14f 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -1,7 +1,7 @@
 /*
- * Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
+ * Copyright © 2016  Elie Roux <elie.roux@telecom-bretagne.eu>
  * Copyright © 2018  Google, Inc.
- * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2018-2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -32,9 +32,6 @@
 #include "hb-open-type.hh"
 #include "hb-ot-layout-common.hh"
 
-/* To be removed */
-typedef hb_tag_t hb_ot_layout_baseline_t;
-
 namespace OT {
 
 /*
@@ -76,7 +73,7 @@
   protected:
   HBUINT16	format;		/* Format identifier--format = 2 */
   FWORD		coordinate;	/* X or Y value, in design units */
-  GlyphID	referenceGlyph;	/* Glyph ID of control glyph */
+  HBGlyphID	referenceGlyph;	/* Glyph ID of control glyph */
   HBUINT16	coordPoint;	/* Index of contour point on the
 				 * reference glyph */
   public:
@@ -116,9 +113,11 @@
 
 struct BaseCoord
 {
-  hb_position_t get_coord (hb_font_t *font,
+  bool has_data () const { return u.format; }
+
+  hb_position_t get_coord (hb_font_t            *font,
 			   const VariationStore &var_store,
-			   hb_direction_t direction) const
+			   hb_direction_t        direction) const
   {
     switch (u.format) {
     case 1: return u.format1.get_coord ();
@@ -142,10 +141,10 @@
 
   protected:
   union {
-    HBUINT16		format;
-    BaseCoordFormat1	format1;
-    BaseCoordFormat2	format2;
-    BaseCoordFormat3	format3;
+  HBUINT16		format;
+  BaseCoordFormat1	format1;
+  BaseCoordFormat2	format2;
+  BaseCoordFormat3	format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
@@ -153,14 +152,9 @@
 
 struct FeatMinMaxRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_;
-    return key < (unsigned int) entry.tag ? -1 :
-	   key > (unsigned int) entry.tag ? 1 :
-	   0;
-  }
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  bool has_data () const { return tag; }
 
   void get_min_max (const BaseCoord **min, const BaseCoord **max) const
   {
@@ -195,17 +189,12 @@
 struct MinMax
 {
   void get_min_max (hb_tag_t          feature_tag,
-			   const BaseCoord **min,
-			   const BaseCoord **max) const
+		    const BaseCoord **min,
+		    const BaseCoord **max) const
   {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *)
-					  hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ,
-						      featMinMaxRecords.len,
-						      FeatMinMaxRecord::static_size,
-						      FeatMinMaxRecord::cmp);
-    if (minMaxCoord)
-      minMaxCoord->get_min_max (min, max);
+    const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
+    if (minMaxCoord.has_data ())
+      minMaxCoord.get_min_max (min, max);
     else
     {
       if (likely (min)) *min = &(this+minCoord);
@@ -271,17 +260,11 @@
 
 struct BaseLangSysRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_;
-    return key < (unsigned int) entry.baseLangSysTag ? -1 :
-	   key > (unsigned int) entry.baseLangSysTag ? 1 :
-	   0;
-  }
+  int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
 
-  const MinMax &get_min_max () const
-  { return this+minMax; }
+  bool has_data () const { return baseLangSysTag; }
+
+  const MinMax &get_min_max () const { return this+minMax; }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
@@ -303,19 +286,14 @@
 {
   const MinMax &get_min_max (hb_tag_t language_tag) const
   {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    const BaseLangSysRecord* record = (const BaseLangSysRecord *)
-				      hb_bsearch (&language_tag, baseLangSysRecords.arrayZ,
-						  baseLangSysRecords.len,
-						  BaseLangSysRecord::static_size,
-						  BaseLangSysRecord::cmp);
-    return record ? record->get_min_max () : this+defaultMinMax;
+    const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
+    return record.has_data () ? record.get_min_max () : this+defaultMinMax;
   }
 
   const BaseCoord &get_base_coord (int baseline_tag_index) const
   { return (this+baseValues).get_base_coord (baseline_tag_index); }
 
-  bool is_empty () const { return !baseValues; }
+  bool has_data () const { return baseValues; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -345,14 +323,9 @@
 struct BaseScriptList;
 struct BaseScriptRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_;
-    return key < (unsigned int) entry.baseScriptTag ? -1 :
-	   key > (unsigned int) entry.baseScriptTag ? 1 :
-	   0;
-  }
+  int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
+
+  bool has_data () const { return baseScriptTag; }
 
   const BaseScript &get_base_script (const BaseScriptList *list) const
   { return list+baseScript; }
@@ -376,22 +349,11 @@
 
 struct BaseScriptList
 {
-  const BaseScriptRecord *find_record (hb_tag_t script) const
-  {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ,
-						  baseScriptRecords.len,
-						  BaseScriptRecord::static_size,
-						  BaseScriptRecord::cmp);
-  }
-
-  /* TODO: Or client should handle fallback? */
   const BaseScript &get_base_script (hb_tag_t script) const
   {
-    const BaseScriptRecord *record = find_record (script);
-    if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T'));
-
-    return record ? record->get_base_script (this) : Null (BaseScript);
+    const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
+    if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
+    return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -411,15 +373,20 @@
 
 struct Axis
 {
-  bool get_baseline (hb_ot_layout_baseline_t   baseline,
-			    hb_tag_t                  script_tag,
-			    hb_tag_t                  language_tag,
-			    const BaseCoord         **coord) const
+  bool get_baseline (hb_tag_t          baseline_tag,
+		     hb_tag_t          script_tag,
+		     hb_tag_t          language_tag,
+		     const BaseCoord **coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (base_script.is_empty ()) return false;
+    if (!base_script.has_data ()) return false;
 
-    if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline));
+    if (likely (coord))
+    {
+      unsigned int tag_index = 0;
+      (this+baseTagList).bfind (baseline_tag, &tag_index);
+      *coord = &base_script.get_base_coord (tag_index);
+    }
 
     return true;
   }
@@ -431,7 +398,7 @@
 		    const BaseCoord **max_coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (base_script.is_empty ()) return false;
+    if (!base_script.has_data ()) return false;
 
     base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
 
@@ -447,7 +414,7 @@
   }
 
   protected:
-  OffsetTo<SortedArrayOf<Tag> >
+  OffsetTo<SortedArrayOf<Tag>>
 		baseTagList;	/* Offset to BaseTagList table, from beginning
 				 * of Axis table (may be NULL)
 				 * Array of 4-byte baseline identification tags — must
@@ -464,7 +431,7 @@
 
 struct BASE
 {
-  enum { tableTag = HB_OT_TAG_BASE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
 
   const Axis &get_axis (hb_direction_t direction) const
   { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
@@ -472,20 +439,21 @@
   const VariationStore &get_var_store () const
   { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
 
-  bool get_baseline (hb_font_t               *font,
-		     hb_ot_layout_baseline_t  baseline,
-		     hb_direction_t           direction,
-		     hb_tag_t                 script_tag,
-		     hb_tag_t                 language_tag,
-		     hb_position_t           *base) const
+  bool get_baseline (hb_font_t      *font,
+		     hb_tag_t        baseline_tag,
+		     hb_direction_t  direction,
+		     hb_tag_t        script_tag,
+		     hb_tag_t        language_tag,
+		     hb_position_t  *base) const
   {
-    const BaseCoord *base_coord;
-    if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord))
+    const BaseCoord *base_coord = nullptr;
+    if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
+		  !base_coord || !base_coord->has_data ()))
       return false;
 
-    if (likely (base && base_coord)) *base = base_coord->get_coord (font,
-								    get_var_store (),
-								    direction);
+    if (likely (base))
+      *base = base_coord->get_coord (font, get_var_store (), direction);
+
     return true;
   }
 
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index d9f5728..fa08140 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -33,6 +33,7 @@
 #include "hb-ot-layout.hh"
 #include "hb-open-type.hh"
 #include "hb-set.hh"
+#include "hb-bimap.hh"
 
 
 #ifndef HB_MAX_NESTING_LEVEL
@@ -66,6 +67,75 @@
 #define NOT_COVERED		((unsigned int) -1)
 
 
+template<typename Iterator>
+static inline void Coverage_serialize (hb_serialize_context_t *c,
+				       Iterator it);
+
+template<typename Iterator>
+static inline void ClassDef_serialize (hb_serialize_context_t *c,
+                                       Iterator it);
+
+static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
+                                          const hb_set_t &glyphset,
+                                          const hb_map_t &gid_klass_map,
+                                          hb_sorted_vector_t<HBGlyphID> glyphs,
+                                          hb_sorted_vector_t<unsigned> klasses,
+                                          hb_map_t *klass_map /*INOUT*/);
+
+
+template<typename OutputArray>
+struct subset_offset_array_t
+{
+  subset_offset_array_t
+  (hb_subset_context_t *subset_context,
+   OutputArray& out,
+   const void *src_base,
+   const void *dest_base)
+      : _subset_context(subset_context), _out (out), _src_base (src_base), _dest_base (dest_base) {}
+
+  template <typename T>
+  bool
+  operator ()
+  (T&& offset)
+  {
+    auto *o = _out.serialize_append (_subset_context->serializer);
+    if (unlikely (!o)) return false;
+    auto snap = _subset_context->serializer->snapshot ();
+    bool ret = o->serialize_subset (_subset_context, offset, _src_base, _dest_base);
+    if (!ret)
+    {
+      _out.pop ();
+      _subset_context->serializer->revert (snap);
+    }
+    return ret;
+  }
+
+  private:
+  hb_subset_context_t *_subset_context;
+  OutputArray &_out;
+  const void *_src_base;
+  const void *_dest_base;
+};
+
+/*
+ * Helper to subset an array of offsets. Subsets the thing pointed to by each offset
+ * and discards the offset in the array if the subset operation results in an empty
+ * thing.
+ */
+struct
+{
+  template<typename OutputArray>
+  subset_offset_array_t<OutputArray>
+  operator ()
+  (hb_subset_context_t *subset_context,
+   OutputArray& out,
+   const void *src_base,
+   const void *dest_base) const
+  {
+    return subset_offset_array_t<OutputArray> (subset_context, out, src_base, dest_base);
+  }
+}
+HB_FUNCOBJ (subset_offset_array);
 
 /*
  *
@@ -83,6 +153,26 @@
   const void *list_base;
 };
 
+struct RecordList_subset_context_t {
+
+  RecordList_subset_context_t() : script_count (0), langsys_count (0)
+  {}
+
+  bool visitScript ()
+  {
+    return script_count++ < HB_MAX_SCRIPTS;
+  }
+
+  bool visitLangSys ()
+  {
+    return langsys_count++ < HB_MAX_LANGSYS;
+  }
+
+  private:
+  unsigned int script_count;
+  unsigned int langsys_count;
+};
+
 template <typename Type>
 struct Record
 {
@@ -104,7 +194,7 @@
 };
 
 template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type> >
+struct RecordArrayOf : SortedArrayOf<Record<Type>>
 {
   const OffsetTo<Type>& get_offset (unsigned int i) const
   { return (*this)[i].offset; }
@@ -139,11 +229,26 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct RecordListOf<Type> *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    RecordList_subset_context_t record_list_context;
+
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
-      out->get_offset (i).serialize_subset (c, (*this)[i], out);
+    {
+      auto *record = out->serialize_append (c->serializer);
+      if (unlikely (!record)) return false;
+      auto snap = c->serializer->snapshot ();
+      if (record->offset.serialize_subset (c, this->get_offset (i), this, out, &record_list_context))
+      {
+        record->tag = this->get_tag(i);
+        continue;
+      }
+      out->pop ();
+      c->serializer->revert (snap);
+    }
+
     return_trace (true);
   }
 
@@ -173,8 +278,8 @@
   bool add_coverage (set_t *glyphs) const
   { return glyphs->add_range (start, end); }
 
-  GlyphID	start;		/* First GlyphID in the range */
-  GlyphID	end;		/* Last GlyphID in the range */
+  HBGlyphID	start;		/* First GlyphID in the range */
+  HBGlyphID	end;		/* Last GlyphID in the range */
   HBUINT16	value;		/* Value */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -208,7 +313,6 @@
 struct LangSys;
 struct Feature;
 
-
 struct LangSys
 {
   unsigned int get_feature_count () const
@@ -227,13 +331,13 @@
   {
     if (reqFeatureIndex == 0xFFFFu)
       return Index::NOT_FOUND_INDEX;
-   return reqFeatureIndex;;
+   return reqFeatureIndex;
   }
 
-  bool subset (hb_subset_context_t *c) const
+  LangSys* copy (hb_serialize_context_t *c) const
   {
-    TRACE_SUBSET (this);
-    return_trace (c->serializer->embed (*this));
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (*this));
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -275,15 +379,33 @@
   bool has_default_lang_sys () const           { return defaultLangSys != 0; }
   const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c, RecordList_subset_context_t *record_list_context) const
   {
     TRACE_SUBSET (this);
-    struct Script *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
-    unsigned int count = langSys.len;
-    for (unsigned int i = 0; i < count; i++)
-      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
+    if (!record_list_context->visitScript ()) return_trace (false);
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    out->defaultLangSys.serialize_copy (c->serializer, defaultLangSys, this, out);
+
+    for (const auto &src: langSys)
+    {
+      if (!record_list_context->visitLangSys ()) {
+        continue;
+      }
+
+      auto snap = c->serializer->snapshot ();
+      auto *lang_sys = c->serializer->embed (src);
+
+      if (likely(lang_sys)
+          && lang_sys->offset.serialize_copy (c->serializer, src.offset, this, out))
+      {
+        out->langSys.len++;
+        continue;
+      }
+      c->serializer->revert (snap);
+    }
     return_trace (true);
   }
 
@@ -500,6 +622,9 @@
 {
   bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
   {
+#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
+    return true;
+#endif
     TRACE_SANITIZE (this);
     if (tag == HB_TAG ('s','i','z','e'))
       return_trace (u.size.sanitize (c));
@@ -510,26 +635,26 @@
     return_trace (true);
   }
 
+#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
   const FeatureParamsSize& get_size_params (hb_tag_t tag) const
   {
     if (tag == HB_TAG ('s','i','z','e'))
       return u.size;
     return Null (FeatureParamsSize);
   }
-
   const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
   {
     if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
       return u.stylisticSet;
     return Null (FeatureParamsStylisticSet);
   }
-
   const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
   {
     if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
       return u.characterVariants;
     return Null (FeatureParamsCharacterVariants);
   }
+#endif
 
   private:
   union {
@@ -538,7 +663,7 @@
   FeatureParamsCharacterVariants	characterVariants;
   } u;
   public:
-  DEFINE_SIZE_STATIC (17);
+  DEFINE_SIZE_MIN (0);
 };
 
 struct Feature
@@ -557,12 +682,12 @@
   const FeatureParams &get_feature_params () const
   { return this+featureParams; }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c, RecordList_subset_context_t *r) const
   {
     TRACE_SUBSET (this);
-    struct Feature *out = c->serializer->embed (*this);
+    auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
-    out->featureParams.set (0); /* TODO(subset) FeatureParams. */
+    out->featureParams = 0; /* TODO(subset) FeatureParams. */
     return_trace (true);
   }
 
@@ -584,25 +709,25 @@
      * Adobe tools, only the 'size' feature had FeatureParams defined.
      */
 
-    OffsetTo<FeatureParams> orig_offset = featureParams;
+    if (likely (featureParams.is_null ()))
+      return_trace (true);
+
+    unsigned int orig_offset = featureParams;
     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
       return_trace (false);
 
-    if (likely (orig_offset.is_null ()))
-      return_trace (true);
-
     if (featureParams == 0 && closure &&
 	closure->tag == HB_TAG ('s','i','z','e') &&
 	closure->list_base && closure->list_base < this)
     {
-      unsigned int new_offset_int = (unsigned int) orig_offset -
+      unsigned int new_offset_int = orig_offset -
 				    (((char *) this) - ((char *) closure->list_base));
 
       OffsetTo<FeatureParams> new_offset;
-      /* Check that it did not overflow. */
-      new_offset.set (new_offset_int);
+      /* Check that it would not overflow. */
+      new_offset = new_offset_int;
       if (new_offset == new_offset_int &&
-	  c->try_set (&featureParams, new_offset) &&
+	  c->try_set (&featureParams, new_offset_int) &&
 	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
 	return_trace (false);
     }
@@ -649,15 +774,18 @@
   unsigned int get_subtable_count () const { return subTable.len; }
 
   template <typename TSubTable>
-  const TSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
-
-  template <typename TSubTable>
   const OffsetArrayOf<TSubTable>& get_subtables () const
-  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
   template <typename TSubTable>
   OffsetArrayOf<TSubTable>& get_subtables ()
-  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
+
+  template <typename TSubTable>
+  const TSubTable& get_subtable (unsigned int i) const
+  { return this+get_subtables<TSubTable> ()[i]; }
+  template <typename TSubTable>
+  TSubTable& get_subtable (unsigned int i)
+  { return this+get_subtables<TSubTable> ()[i]; }
 
   unsigned int get_size () const
   {
@@ -683,14 +811,14 @@
     return flag;
   }
 
-  template <typename TSubTable, typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename TSubTable, typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int lookup_type = get_type ();
     TRACE_DISPATCH (this, lookup_type);
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
+      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
       if (c->stop_sublookup_iteration (r))
 	return_trace (r);
     }
@@ -704,40 +832,23 @@
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    lookupType.set (lookup_type);
-    lookupFlag.set (lookup_props & 0xFFFFu);
+    lookupType = lookup_type;
+    lookupFlag = lookup_props & 0xFFFFu;
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       if (unlikely (!c->extend (*this))) return_trace (false);
       HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
-      markFilteringSet.set (lookup_props >> 16);
+      markFilteringSet = lookup_props >> 16;
     }
     return_trace (true);
   }
 
-  /* Older compilers need this to NOT be locally defined in a function. */
-  template <typename TSubTable>
-  struct SubTableSubsetWrapper
-  {
-    SubTableSubsetWrapper (const TSubTable &subtable_,
-			   unsigned int lookup_type_) :
-			     subtable (subtable_),
-			     lookup_type (lookup_type_) {}
-
-    bool subset (hb_subset_context_t *c) const
-    { return subtable.dispatch (c, lookup_type); }
-
-    private:
-    const TSubTable &subtable;
-    unsigned int lookup_type;
-  };
-
   template <typename TSubTable>
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct Lookup *out = c->serializer->embed (*this);
+    auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
     /* Subset the actual subtables. */
@@ -747,23 +858,11 @@
     OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
     unsigned int count = subTable.len;
     for (unsigned int i = 0; i < count; i++)
-    {
-      SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
-
-      out_subtables[i].serialize_subset (c, wrapper, out);
-    }
+      out_subtables[i].serialize_subset (c, subtables[i], this, out, get_type ());
 
     return_trace (true);
   }
 
-  /* Older compilers need this to NOT be locally defined in a function. */
-  template <typename TSubTable>
-  struct SubTableSanitizeWrapper : TSubTable
-  {
-    bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const
-    { return this->dispatch (c, lookup_type); }
-  };
-
   template <typename TSubTable>
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -775,16 +874,21 @@
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
 
-    if (unlikely (!CastR<OffsetArrayOf<SubTableSanitizeWrapper<TSubTable> > > (subTable)
-		   .sanitize (c, this, get_type ())))
+    if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
       return_trace (false);
 
-    if (unlikely (get_type () == TSubTable::Extension))
+    if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
        * itself (but we already checked for that).
-       * This is specially important if one has a reverse type! */
+       * This is specially important if one has a reverse type!
+       *
+       * We only do this if sanitizer edit_count is zero.  Otherwise,
+       * some of the subtables might have become insane after they
+       * were sanity-checked by the edits of subsequent subtables.
+       * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
+       */
       unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
@@ -792,7 +896,6 @@
 	  return_trace (false);
     }
     return_trace (true);
-    return_trace (true);
   }
 
   private:
@@ -800,7 +903,7 @@
   HBUINT16	lookupFlag;		/* Lookup qualifiers */
   ArrayOf<Offset16>
 		subTable;		/* Array of SubTables */
-/*HBUINT16	markFilteringSetX[VAR];*//* Index (base 0) into GDEF mark glyph sets
+/*HBUINT16	markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
   public:
@@ -826,8 +929,9 @@
     return i;
   }
 
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     return_trace (glyphArray.serialize (c, glyphs));
@@ -853,19 +957,19 @@
 
   template <typename set_t>
   bool add_coverage (set_t *glyphs) const
-  {
-    return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
-  }
+  { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
 
   public:
   /* Older compilers need this to be public. */
-  struct Iter {
+  struct iter_t
+  {
     void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
     void fini () {}
-    bool more () { return i < c->glyphArray.len; }
+    bool more () const { return i < c->glyphArray.len; }
     void next () { i++; }
-    hb_codepoint_t get_glyph () { return c->glyphArray[i]; }
-    unsigned int get_coverage () { return i; }
+    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || c != o.c; }
 
     private:
     const struct CoverageFormat1 *c;
@@ -875,7 +979,7 @@
 
   protected:
   HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
-  SortedArrayOf<GlyphID>
+  SortedArrayOf<HBGlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
@@ -894,38 +998,48 @@
 	   NOT_COVERED;
   }
 
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.len))
+    if (unlikely (!glyphs))
     {
-      rangeRecord.len.set (0);
+      rangeRecord.len = 0;
       return_trace (true);
     }
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.len; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i])
-	num_ranges++;
-    rangeRecord.len.set (num_ranges);
-    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+    /* TODO(iter) Write more efficiently? */
 
-    unsigned int range = 0;
-    rangeRecord[range].start = glyphs[0];
-    rangeRecord[range].value.set (0);
-    for (unsigned int i = 1; i < glyphs.len; i++)
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
     {
-      if (glyphs[i - 1] + 1 != glyphs[i])
+      if (last + 1 != g)
+	num_ranges++;
+      last = g;
+    }
+
+    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
+
+    unsigned count = 0;
+    unsigned range = (unsigned) -1;
+    last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
       {
 	range++;
-	rangeRecord[range].start = glyphs[i];
-	rangeRecord[range].value.set (i);
+	rangeRecord[range].start = g;
+	rangeRecord[range].value = count;
       }
-      rangeRecord[range].end = glyphs[i];
+      rangeRecord[range].end = g;
+      last = g;
+      count++;
     }
+
     return_trace (true);
   }
 
@@ -972,7 +1086,7 @@
 
   public:
   /* Older compilers need this to be public. */
-  struct Iter
+  struct iter_t
   {
     void init (const CoverageFormat2 &c_)
     {
@@ -987,7 +1101,7 @@
       }
     }
     void fini () {}
-    bool more () { return i < c->rangeRecord.len; }
+    bool more () const { return i < c->rangeRecord.len; }
     void next ()
     {
       if (j >= c->rangeRecord[i].end)
@@ -995,23 +1109,27 @@
 	i++;
 	if (more ())
 	{
-	  hb_codepoint_t old = j;
+	  unsigned int old = coverage;
 	  j = c->rangeRecord[i].start;
-	  if (unlikely (j <= old))
+	  coverage = c->rangeRecord[i].value;
+	  if (unlikely (coverage != old + 1))
 	  {
-	    /* Broken table. Skip. Important to avoid DoS. */
+	    /* Broken table. Skip. Important to avoid DoS.
+	     * Also, our callers depend on coverage being
+	     * consecutive and monotonically increasing,
+	     * ie. iota(). */
 	   i = c->rangeRecord.len;
 	   return;
 	  }
-	  coverage = c->rangeRecord[i].value;
 	}
 	return;
       }
       coverage++;
       j++;
     }
-    hb_codepoint_t get_glyph () { return j; }
-    unsigned int get_coverage () { return coverage; }
+    hb_codepoint_t get_glyph () const { return j; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || j != o.j || c != o.c; }
 
     private:
     const struct CoverageFormat2 *c;
@@ -1032,6 +1150,15 @@
 
 struct Coverage
 {
+  /* Has interface. */
+  static constexpr unsigned SENTINEL = NOT_COVERED;
+  typedef unsigned int value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
   unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -1041,17 +1168,24 @@
     }
   }
 
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.len; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i])
+    unsigned count = 0;
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
 	num_ranges++;
-    u.format.set (glyphs.len * 2 < num_ranges * 3 ? 1 : 2);
+      last = g;
+      count++;
+    }
+    u.format = count <= num_ranges * 3 ? 1 : 2;
 
     switch (u.format)
     {
@@ -1061,6 +1195,23 @@
     }
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + iter ()
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    bool ret = bool (it);
+    Coverage_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1105,9 +1256,10 @@
     }
   }
 
-  struct Iter
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
   {
-    Iter (const Coverage &c_)
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const Coverage &c_ = Null(Coverage))
     {
       memset (this, 0, sizeof (*this));
       format = c_.u.format;
@@ -1118,7 +1270,7 @@
       default:				     return;
       }
     }
-    bool more ()
+    bool __more__ () const
     {
       switch (format)
       {
@@ -1127,7 +1279,7 @@
       default:return false;
       }
     }
-    void next ()
+    void __next__ ()
     {
       switch (format)
       {
@@ -1136,7 +1288,10 @@
       default:			 break;
       }
     }
-    hb_codepoint_t get_glyph ()
+    typedef hb_codepoint_t __item_t__;
+    __item_t__ __item__ () const { return get_glyph (); }
+
+    hb_codepoint_t get_glyph () const
     {
       switch (format)
       {
@@ -1145,23 +1300,25 @@
       default:return 0;
       }
     }
-    unsigned int get_coverage ()
+    bool operator != (const iter_t& o) const
     {
+      if (format != o.format) return true;
       switch (format)
       {
-      case 1: return u.format1.get_coverage ();
-      case 2: return u.format2.get_coverage ();
-      default:return -1;
+      case 1: return u.format1 != o.u.format1;
+      case 2: return u.format2 != o.u.format2;
+      default:return false;
       }
     }
 
     private:
     unsigned int format;
     union {
-    CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
-    CoverageFormat1::Iter	format1;
+    CoverageFormat2::iter_t	format2; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1::iter_t	format1;
     } u;
   };
+  iter_t iter () const { return iter_t (*this); }
 
   protected:
   union {
@@ -1173,15 +1330,51 @@
   DEFINE_SIZE_UNION (2, format);
 };
 
+template<typename Iterator>
+static inline void
+Coverage_serialize (hb_serialize_context_t *c,
+                    Iterator it)
+{ c->start_embed<Coverage> ()->serialize (c, it); }
+
+static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
+                                          const hb_set_t &glyphset,
+                                          const hb_map_t &gid_klass_map,
+                                          hb_sorted_vector_t<HBGlyphID> glyphs,
+                                          hb_sorted_vector_t<unsigned> klasses,
+                                          hb_map_t *klass_map /*INOUT*/)
+{
+  bool has_no_match = glyphset.get_population () > gid_klass_map.get_population ();
+  
+  hb_map_t m;
+  if (!klass_map) klass_map = &m;
+
+  if (has_no_match) klass_map->set (0, 0);
+  unsigned idx = klass_map->has (0) ? 1 : 0;
+  for (const unsigned k: klasses.iter ())
+  {
+    if (klass_map->has (k)) continue;
+    klass_map->set (k, idx);
+    idx++;
+  }
+  
+  auto it =
+  + glyphs.iter ()
+  | hb_map_retains_sorting ([&] (const HBGlyphID& gid) -> hb_pair_t<hb_codepoint_t, HBUINT16>
+                            {
+                              HBUINT16 new_klass;
+                              new_klass = klass_map->get (gid_klass_map[gid]);
+                              return hb_pair ((hb_codepoint_t)gid, new_klass);
+                            })
+  ;
+  
+  c->propagate_error (glyphs, klasses);
+  ClassDef_serialize (c, it);
+}
 
 /*
  * Class Definition Table
  */
 
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
-				       hb_array_t<const GlyphID> glyphs,
-				       hb_array_t<const HBUINT16> klasses);
-
 struct ClassDefFormat1
 {
   friend struct ClassDef;
@@ -1192,54 +1385,54 @@
     return classValue[(unsigned int) (glyph_id - startGlyph)];
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const HBUINT16> glyphs,
-		  hb_array_t<const HBUINT16> klasses)
+                  Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.len))
+    if (unlikely (!it))
     {
-      startGlyph.set (0);
-      classValue.len.set (0);
+      startGlyph = 0;
+      classValue.len = 0;
       return_trace (true);
     }
 
-    hb_codepoint_t glyph_min = glyphs[0];
-    hb_codepoint_t glyph_max = glyphs[glyphs.len - 1];
-
-    startGlyph.set (glyph_min);
-    classValue.len.set (glyph_max - glyph_min + 1);
-    if (unlikely (!c->extend (classValue))) return_trace (false);
-
-    for (unsigned int i = 0; i < glyphs.len; i++)
-      classValue[glyphs[i] - glyph_min] = klasses[i];
-
+    startGlyph = (*it).first;
+    classValue.serialize (c, + it
+                             | hb_map (hb_second));
     return_trace (true);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> glyphs;
-    hb_vector_t<HBUINT16> klasses;
+   
+    hb_sorted_vector_t<HBGlyphID> glyphs;
+    hb_sorted_vector_t<unsigned> orig_klasses;
+    hb_map_t gid_org_klass_map;
 
     hb_codepoint_t start = startGlyph;
     hb_codepoint_t end   = start + classValue.len;
-    for (hb_codepoint_t g = start; g < end; g++)
+    for (const hb_codepoint_t gid : + hb_range (start, end)
+				    | hb_filter (glyphset))
     {
-      unsigned int value = classValue[g - start];
-      if (!value) continue;
-      if (!glyphset.has (g)) continue;
-      glyphs.push()->set (glyph_map[g]);
-      klasses.push()->set (value);
+      unsigned klass = classValue[gid - start];
+      if (!klass) continue;
+
+      glyphs.push (glyph_map[gid]);
+      gid_org_klass_map.set (glyph_map[gid], klass);
+      orig_klasses.push (klass);
     }
-    c->serializer->propagate_error (glyphs, klasses);
-    ClassDef_serialize (c->serializer, glyphs, klasses);
-    return_trace (glyphs.len);
+
+    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
+                                  glyphs, orig_klasses, klass_map);
+    return_trace ((bool) glyphs);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1311,7 +1504,7 @@
 
   protected:
   HBUINT16	classFormat;	/* Format identifier--format = 1 */
-  GlyphID	startGlyph;	/* First GlyphID of the classValueArray */
+  HBGlyphID	startGlyph;	/* First GlyphID of the classValueArray */
   ArrayOf<HBUINT16>
 		classValue;	/* Array of Class Values--one per GlyphID */
   public:
@@ -1328,69 +1521,90 @@
     return rangeRecord.bsearch (glyph_id).value;
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const HBUINT16> glyphs,
-		  hb_array_t<const HBUINT16> klasses)
+                  Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.len))
+    if (unlikely (!it))
     {
-      rangeRecord.len.set (0);
+      rangeRecord.len = 0;
       return_trace (true);
     }
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.len; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i] ||
-	  klasses[i - 1] != klasses[i])
-	num_ranges++;
-    rangeRecord.len.set (num_ranges);
-    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+    unsigned num_ranges = 1;
+    hb_codepoint_t prev_gid = (*it).first;
+    unsigned prev_klass = (*it).second;
 
-    unsigned int range = 0;
-    rangeRecord[range].start = glyphs[0];
-    rangeRecord[range].value.set (klasses[0]);
-    for (unsigned int i = 1; i < glyphs.len; i++)
+    RangeRecord range_rec;
+    range_rec.start = prev_gid;
+    range_rec.end = prev_gid;
+    range_rec.value = prev_klass;
+
+    RangeRecord *record = c->copy (range_rec);
+    if (unlikely (!record)) return_trace (false);
+
+    for (const auto gid_klass_pair : + (++it))
     {
-      if (glyphs[i - 1] + 1 != glyphs[i] ||
-	  klasses[i - 1] != klasses[i])
+      hb_codepoint_t cur_gid = gid_klass_pair.first;
+      unsigned cur_klass = gid_klass_pair.second;
+
+      if (cur_gid != prev_gid + 1 ||
+          cur_klass != prev_klass)
       {
-	range++;
-	rangeRecord[range].start = glyphs[i];
-	rangeRecord[range].value = klasses[i];
+        if (unlikely (!record)) break;
+        record->end = prev_gid;
+        num_ranges++;
+
+        range_rec.start = cur_gid;
+        range_rec.end = cur_gid;
+        range_rec.value = cur_klass;
+
+        record = c->copy (range_rec);
       }
-      rangeRecord[range].end = glyphs[i];
+
+      prev_klass = cur_klass;
+      prev_gid = cur_gid;
     }
+
+    if (likely (record)) record->end = prev_gid;
+    rangeRecord.len = num_ranges;
     return_trace (true);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> glyphs;
-    hb_vector_t<HBUINT16> klasses;
 
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
+    hb_sorted_vector_t<HBGlyphID> glyphs;
+    hb_sorted_vector_t<unsigned> orig_klasses;
+    hb_map_t gid_org_klass_map;
+
+    unsigned count = rangeRecord.len;
+    for (unsigned i = 0; i < count; i++)
     {
-      unsigned int value = rangeRecord[i].value;
-      if (!value) continue;
+      unsigned klass = rangeRecord[i].value;
+      if (!klass) continue;
       hb_codepoint_t start = rangeRecord[i].start;
       hb_codepoint_t end   = rangeRecord[i].end + 1;
       for (hb_codepoint_t g = start; g < end; g++)
       {
 	if (!glyphset.has (g)) continue;
-	glyphs.push ()->set (glyph_map[g]);
-	klasses.push ()->set (value);
+	glyphs.push (glyph_map[g]);
+        gid_org_klass_map.set (glyph_map[g], klass);
+        orig_klasses.push (klass);
       }
     }
-    c->serializer->propagate_error (glyphs, klasses);
-    ClassDef_serialize (c->serializer, glyphs, klasses);
-    return_trace (glyphs.len);
+
+    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
+                                  glyphs, orig_klasses, klass_map);
+    return_trace ((bool) glyphs);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1468,6 +1682,15 @@
 
 struct ClassDef
 {
+  /* Has interface. */
+  static constexpr unsigned SENTINEL = 0;
+  typedef unsigned int value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Projection. */
+  hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_class (k); }
   unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -1477,44 +1700,57 @@
     }
   }
 
-  bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
-		  hb_array_t<const HBUINT16> klasses)
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    unsigned int format = 2;
-    if (glyphs.len)
+    unsigned format = 2;
+    if (likely (it))
     {
-      hb_codepoint_t glyph_min = glyphs[0];
-      hb_codepoint_t glyph_max = glyphs[glyphs.len - 1];
+      hb_codepoint_t glyph_min = (*it).first;
+      hb_codepoint_t glyph_max = + it
+				 | hb_map (hb_first)
+                                 | hb_reduce (hb_max, 0u);
 
-      unsigned int num_ranges = 1;
-      for (unsigned int i = 1; i < glyphs.len; i++)
-	if (glyphs[i - 1] + 1 != glyphs[i] ||
-	    klasses[i - 1] != klasses[i])
-	  num_ranges++;
+      unsigned num_ranges = 1;
+      hb_codepoint_t prev_gid = glyph_min;
+      unsigned prev_klass = (*it).second;
+
+      for (const auto gid_klass_pair : it)
+      {
+        hb_codepoint_t cur_gid = gid_klass_pair.first;
+        unsigned cur_klass = gid_klass_pair.second;
+        if (cur_gid != prev_gid + 1 ||
+            cur_klass != prev_klass)
+          num_ranges++;
+
+        prev_gid = cur_gid;
+        prev_klass = cur_klass;
+      }
 
       if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3)
-        format = 1;
+	format = 1;
     }
-    u.format.set (format);
+    u.format = format;
 
     switch (u.format)
     {
-    case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
-    case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
+    case 1: return_trace (u.format1.serialize (c, it));
+    case 2: return_trace (u.format2.serialize (c, it));
     default:return_trace (false);
     }
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
     switch (u.format) {
-    case 1: return_trace (u.format1.subset (c));
-    case 2: return_trace (u.format2.subset (c));
+    case 1: return_trace (u.format1.subset (c, klass_map));
+    case 2: return_trace (u.format2.subset (c, klass_map));
     default:return_trace (false);
     }
   }
@@ -1581,10 +1817,10 @@
   DEFINE_SIZE_UNION (2, format);
 };
 
+template<typename Iterator>
 static inline void ClassDef_serialize (hb_serialize_context_t *c,
-				       hb_array_t<const GlyphID> glyphs,
-				       hb_array_t<const HBUINT16> klasses)
-{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
+                                       Iterator it)
+{ c->start_embed<ClassDef> ()->serialize (c, it); }
 
 
 /*
@@ -1662,6 +1898,21 @@
 		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
   }
 
+  bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
+  {
+    TRACE_SERIALIZE (this);
+    VarRegionList *out = c->allocate_min<VarRegionList> ();
+    if (unlikely (!out)) return_trace (false);
+    axisCount = src->axisCount;
+    regionCount = region_map.get_population ();
+    if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false);
+    for (unsigned int r = 0; r < regionCount; r++)
+      memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * region_map.backward (r)], VarRegionAxis::static_size * axisCount);
+
+    return_trace (true);
+  }
+
+  unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
   unsigned int get_region_count () const { return regionCount; }
 
   protected:
@@ -1694,7 +1945,7 @@
    unsigned int count = regionIndices.len;
    unsigned int scount = shortCount;
 
-   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
+   const HBUINT8 *bytes = get_delta_bytes ();
    const HBUINT8 *row = bytes + inner * (scount + count);
 
    float delta = 0.;
@@ -1717,15 +1968,15 @@
   }
 
   void get_scalars (int *coords, unsigned int coord_count,
-                    const VarRegionList &regions,
-                    float *scalars /*OUT */,
-                    unsigned int num_scalars) const
+		    const VarRegionList &regions,
+		    float *scalars /*OUT */,
+		    unsigned int num_scalars) const
   {
-    assert (num_scalars == regionIndices.len);
-   for (unsigned int i = 0; i < num_scalars; i++)
-   {
-     scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
-   }
+    unsigned count = hb_min (num_scalars, regionIndices.len);
+    for (unsigned int i = 0; i < count; i++)
+      scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+    for (unsigned int i = count; i < num_scalars; i++)
+      scalars[i] = 0.f;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1734,11 +1985,117 @@
     return_trace (c->check_struct (this) &&
 		  regionIndices.sanitize (c) &&
 		  shortCount <= regionIndices.len &&
-		  c->check_range (&StructAfter<HBUINT8> (regionIndices),
+		  c->check_range (get_delta_bytes (),
 				  itemCount,
 				  get_row_size ()));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+		  const VarData *src,
+		  const hb_inc_bimap_t &inner_map,
+		  const hb_bimap_t &region_map)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    itemCount = inner_map.get_next_value ();
+
+    /* Optimize short count */
+    unsigned short ri_count = src->regionIndices.len;
+    enum delta_size_t { kZero=0, kByte, kShort };
+    hb_vector_t<delta_size_t> delta_sz;
+    hb_vector_t<unsigned int> ri_map;	/* maps old index to new index */
+    delta_sz.resize (ri_count);
+    ri_map.resize (ri_count);
+    unsigned int new_short_count = 0;
+    unsigned int r;
+    for (r = 0; r < ri_count; r++)
+    {
+      delta_sz[r] = kZero;
+      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+      {
+	unsigned int old = inner_map.backward (i);
+	int16_t delta = src->get_item_delta (old, r);
+	if (delta < -128 || 127 < delta)
+	{
+	  delta_sz[r] = kShort;
+	  new_short_count++;
+	  break;
+	}
+	else if (delta != 0)
+	  delta_sz[r] = kByte;
+      }
+    }
+    unsigned int short_index = 0;
+    unsigned int byte_index = new_short_count;
+    unsigned int new_ri_count = 0;
+    for (r = 0; r < ri_count; r++)
+      if (delta_sz[r])
+      {
+      	ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
+      	new_ri_count++;
+      }
+
+    shortCount = new_short_count;
+    regionIndices.len = new_ri_count;
+
+    unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount);
+    if (unlikely (!c->allocate_size<HBUINT8> (size)))
+      return_trace (false);
+
+    for (r = 0; r < ri_count; r++)
+      if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
+
+    for (unsigned int i = 0; i < itemCount; i++)
+    {
+      unsigned int	old = inner_map.backward (i);
+      for (unsigned int r = 0; r < ri_count; r++)
+	if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r));
+    }
+
+    return_trace (true);
+  }
+
+  void collect_region_refs (hb_inc_bimap_t &region_map, const hb_inc_bimap_t &inner_map) const
+  {
+    for (unsigned int r = 0; r < regionIndices.len; r++)
+    {
+      unsigned int region = regionIndices[r];
+      if (region_map.has (region)) continue;
+      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+	if (get_item_delta (inner_map.backward (i), r) != 0)
+	{
+	  region_map.add (region);
+	  break;
+	}
+    }
+  }
+
+  protected:
+  const HBUINT8 *get_delta_bytes () const
+  { return &StructAfter<HBUINT8> (regionIndices); }
+
+  HBUINT8 *get_delta_bytes ()
+  { return &StructAfter<HBUINT8> (regionIndices); }
+
+  int16_t get_item_delta (unsigned int item, unsigned int region) const
+  {
+    if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0;
+    const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size ();
+    if (region < shortCount)
+      return ((const HBINT16 *)p)[region];
+    else
+      return (p + HBINT16::static_size * shortCount)[region - shortCount];
+  }
+
+  void set_item_delta (unsigned int item, unsigned int region, int16_t delta)
+  {
+    HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
+    if (region < shortCount)
+      ((HBINT16 *)p)[region] = delta;
+    else
+      (p + HBINT16::static_size * shortCount)[region - shortCount] = delta;
+  }
+
   protected:
   HBUINT16		itemCount;
   HBUINT16		shortCount;
@@ -1753,8 +2110,12 @@
   float get_delta (unsigned int outer, unsigned int inner,
 		   const int *coords, unsigned int coord_count) const
   {
+#ifdef HB_NO_VAR
+    return 0.f;
+#endif
+
     if (unlikely (outer >= dataSets.len))
-      return 0.;
+      return 0.f;
 
     return (this+dataSets[outer]).get_delta (inner,
 					     coords, coord_count,
@@ -1771,6 +2132,10 @@
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
+#ifdef HB_NO_VAR
+    return true;
+#endif
+
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
 		  format == 1 &&
@@ -1778,6 +2143,43 @@
 		  dataSets.sanitize (c, this));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+		  const VariationStore *src,
+  		  const hb_array_t <hb_inc_bimap_t> &inner_maps)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned int set_count = 0;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      if (inner_maps[i].get_population () > 0) set_count++;
+
+    unsigned int size = min_size + HBUINT32::static_size * set_count;
+    if (unlikely (!c->allocate_size<HBUINT32> (size))) return_trace (false);
+    format = 1;
+
+    hb_inc_bimap_t region_map;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]);
+    region_map.sort ();
+
+    if (unlikely (!regions.serialize (c, this)
+		  .serialize (c, &(src+src->regions), region_map))) return_trace (false);
+
+    /* TODO: The following code could be simplified when
+     * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize ()
+     */
+    dataSets.len = set_count;
+    unsigned int set_index = 0;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+    {
+      if (inner_maps[i].get_population () == 0) continue;
+      if (unlikely (!dataSets[set_index++].serialize (c, this)
+		      .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
+	return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
   unsigned int get_region_index_count (unsigned int ivs) const
   { return (this+dataSets[ivs]).get_region_index_count (); }
 
@@ -1786,10 +2188,18 @@
 		    float *scalars /*OUT*/,
 		    unsigned int num_scalars) const
   {
+#ifdef HB_NO_VAR
+    for (unsigned i = 0; i < num_scalars; i++)
+      scalars[i] = 0.f;
+    return;
+#endif
+
     (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
-                                      &scalars[0], num_scalars);
+				      &scalars[0], num_scalars);
   }
 
+  unsigned int get_sub_table_count () const { return dataSets.len; }
+
   protected:
   HBUINT16				format;
   LOffsetTo<VarRegionList>		regions;
@@ -1949,7 +2359,7 @@
 
 struct FeatureVariations
 {
-  enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
 
   bool find_index (const int *coords, unsigned int coord_len,
 			  unsigned int *index) const
@@ -1975,10 +2385,10 @@
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  FeatureVariations* copy (hb_serialize_context_t *c) const
   {
-    TRACE_SUBSET (this);
-    return_trace (c->serializer->embed (*this));
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (*this));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2014,6 +2424,8 @@
   hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
+  public:
+
   unsigned int get_size () const
   {
     unsigned int f = deltaFormat;
@@ -2027,6 +2439,12 @@
     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
+  HintingDevice* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<HintingDevice> (this));
+  }
+
   private:
 
   int get_delta (unsigned int ppem, int scale) const
@@ -2088,6 +2506,12 @@
   hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
   { return font->em_scalef_y (get_delta (font, store)); }
 
+  VariationDevice* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<VariationDevice> (this));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2126,10 +2550,14 @@
   {
     switch (u.b.format)
     {
+#ifndef HB_NO_HINTING
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return u.variation.get_x_delta (font, store);
+#endif
     default:
       return 0;
     }
@@ -2139,9 +2567,13 @@
     switch (u.b.format)
     {
     case 1: case 2: case 3:
+#ifndef HB_NO_HINTING
       return u.hinting.get_y_delta (font);
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return u.variation.get_y_delta (font, store);
+#endif
     default:
       return 0;
     }
@@ -2152,20 +2584,45 @@
     TRACE_SANITIZE (this);
     if (!u.b.format.sanitize (c)) return_trace (false);
     switch (u.b.format) {
+#ifndef HB_NO_HINTING
     case 1: case 2: case 3:
       return_trace (u.hinting.sanitize (c));
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return_trace (u.variation.sanitize (c));
+#endif
     default:
       return_trace (true);
     }
   }
 
+  Device* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.b.format) {
+#ifndef HB_NO_HINTING
+    case 1:
+    case 2:
+    case 3:
+      return_trace (reinterpret_cast<Device *> (u.hinting.copy (c)));
+#endif
+#ifndef HB_NO_VAR
+    case 0x8000:
+      return_trace (reinterpret_cast<Device *> (u.variation.copy (c)));
+#endif
+    default:
+      return_trace (nullptr);
+    }
+  }
+
   protected:
   union {
   DeviceHeader		b;
   HintingDevice		hinting;
+#ifndef HB_NO_VAR
   VariationDevice	variation;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (6, b);
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 3099fb9..dc751d8 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -64,7 +64,7 @@
     if (point_count)
     {
       hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
-      unsigned int count = array.len;
+      unsigned int count = array.length;
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
     }
@@ -149,8 +149,8 @@
 				 const VariationStore &var_store) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
-           font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
-           font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
+	   font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
+	   font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -220,8 +220,8 @@
   {
     if (caret_count)
     {
-      hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count);
-      unsigned int count = array.len;
+      hb_array_t <const OffsetTo<CaretValue>> array = carets.sub_array (start_offset, caret_count);
+      unsigned int count = array.length;
       for (unsigned int i = 0; i < count; i++)
 	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
     }
@@ -296,7 +296,7 @@
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  ArrayOf<LOffsetTo<Coverage> >
+  ArrayOf<LOffsetTo<Coverage>>
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
   public:
@@ -341,7 +341,7 @@
 
 struct GDEF
 {
-  enum { tableTag = HB_OT_TAG_GDEF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
 
   enum GlyphClasses {
     UnclassifiedGlyph	= 0,
@@ -439,19 +439,19 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GDEF *out = c->serializer->embed (*this);
+    auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out);
-    out->attachList.set (0);//TODO(subset) serialize_subset (c, this+attachList, out);
-    out->ligCaretList.set (0);//TODO(subset) serialize_subset (c, this+ligCaretList, out);
-    out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out);
+    out->glyphClassDef.serialize_subset (c, glyphClassDef, this, out);
+    out->attachList = 0;//TODO(subset) serialize_subset (c, attachList, this, out);
+    out->ligCaretList = 0;//TODO(subset) serialize_subset (c, ligCaretList, this, out);
+    out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, out);
 
     if (version.to_int () >= 0x00010002u)
-      out->markGlyphSetsDef.set (0);// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out);
+      out->markGlyphSetsDef = 0;// TODO(subset) serialize_subset (c, markGlyphSetsDef, this, out);
 
     if (version.to_int () >= 0x00010003u)
-      out->varStore.set (0);// TODO(subset) serialize_subset (c, this+varStore, out);
+      out->varStore = 0;// TODO(subset) serialize_subset (c, varStore, this, out);
 
     return_trace (true);
   }
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index b123336..024312d 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -84,16 +84,16 @@
   HBINT16		yAdvance;		/* Vertical adjustment for advance--in
 					 * design units (only used for vertical
 					 * writing) */
-  Offset	xPlaDevice;		/* Offset to Device table for
+  OffsetTo<Device>	xPlaDevice;	/* Offset to Device table for
 					 * horizontal placement--measured from
 					 * beginning of PosTable (may be NULL) */
-  Offset	yPlaDevice;		/* Offset to Device table for vertical
+  OffsetTo<Device>	yPlaDevice;	/* Offset to Device table for vertical
 					 * placement--measured from beginning
 					 * of PosTable (may be NULL) */
-  Offset	xAdvDevice;		/* Offset to Device table for
+  OffsetTo<Device>	xAdvDevice;	/* Offset to Device table for
 					 * horizontal advance--measured from
 					 * beginning of PosTable (may be NULL) */
-  Offset	yAdvDevice;		/* Offset to Device table for vertical
+  OffsetTo<Device>	yAdvDevice;	/* Offset to Device table for vertical
 					 * advance--measured from beginning of
 					 * PosTable (may be NULL) */
 #endif
@@ -101,10 +101,10 @@
   unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
   unsigned int get_size () const { return get_len () * Value::static_size; }
 
-  bool apply_value (hb_ot_apply_context_t   *c,
-		    const void           *base,
-		    const Value          *values,
-		    hb_glyph_position_t  &glyph_pos) const
+  bool apply_value (hb_ot_apply_context_t *c,
+		    const void            *base,
+		    const Value           *values,
+		    hb_glyph_position_t   &glyph_pos) const
   {
     bool ret = false;
     unsigned int format = *this;
@@ -173,17 +173,17 @@
     return true;
   }
 
-  static OffsetTo<Device>& get_device (Value* value)
-  { return *CastP<OffsetTo<Device> > (value); }
-  static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
+  HB_INTERNAL static OffsetTo<Device>& get_device (Value* value)
+  { return *CastP<OffsetTo<Device>> (value); }
+  HB_INTERNAL static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
   {
-    if (worked) *worked |= *value;
-    return *CastP<OffsetTo<Device> > (value);
+    if (worked) *worked |= bool (*value);
+    return *CastP<OffsetTo<Device>> (value);
   }
 
-  static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+  HB_INTERNAL static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
   {
-    if (worked) *worked |= *value;
+    if (worked) *worked |= bool (*value);
     return *CastP<HBINT16> (value);
   }
 
@@ -236,6 +236,11 @@
   }
 };
 
+template<typename Iterator>
+static inline void SinglePos_serialize (hb_serialize_context_t *c,
+					Iterator it,
+					ValueFormat valFormat);
+
 
 struct AnchorFormat1
 {
@@ -253,6 +258,12 @@
     return_trace (c->check_struct (this));
   }
 
+  AnchorFormat1* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat1> (this));
+  }
+
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
   FWORD		xCoordinate;		/* Horizontal value--in design units */
@@ -267,6 +278,13 @@
 		   float *x, float *y) const
   {
     hb_font_t *font = c->font;
+
+#ifdef HB_NO_HINTING
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+    return;
+#endif
+
     unsigned int x_ppem = font->x_ppem;
     unsigned int y_ppem = font->y_ppem;
     hb_position_t cx = 0, cy = 0;
@@ -284,6 +302,12 @@
     return_trace (c->check_struct (this));
   }
 
+  AnchorFormat2* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat2> (this));
+  }
+
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
   FWORD		xCoordinate;		/* Horizontal value--in design units */
@@ -314,6 +338,17 @@
     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
+  AnchorFormat3* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed<AnchorFormat3> (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, out);
+    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, out);
+    return_trace (out);
+  }
+
   protected:
   HBUINT16	format;			/* Format identifier--format = 3 */
   FWORD		xCoordinate;		/* Horizontal value--in design units */
@@ -356,6 +391,17 @@
     }
   }
 
+  Anchor* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.format) {
+    case 1: return_trace (reinterpret_cast<Anchor *> (u.format1.copy (c)));
+    case 2: return_trace (reinterpret_cast<Anchor *> (u.format2.copy (c)));
+    case 3: return_trace (reinterpret_cast<Anchor *> (u.format3.copy (c)));
+    default:return_trace (nullptr);
+    }
+  }
+
   protected:
   union {
   HBUINT16		format;		/* Format identifier */
@@ -393,7 +439,7 @@
 
   HBUINT16	rows;			/* Number of rows */
   protected:
-  UnsizedArrayOf<OffsetTo<Anchor> >
+  UnsizedArrayOf<OffsetTo<Anchor>>
 		matrixZ;		/* Matrix of offsets to Anchor tables--
 					 * from beginning of AnchorMatrix table */
   public:
@@ -446,8 +492,8 @@
     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
     hb_glyph_position_t &o = buffer->cur_pos();
-    o.x_offset = round (base_x - mark_x);
-    o.y_offset = round (base_y - mark_y);
+    o.x_offset = roundf (base_x - mark_x);
+    o.y_offset = roundf (base_y - mark_y);
     o.attach_type() = ATTACH_TYPE_MARK;
     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
@@ -472,10 +518,7 @@
   { return (this+coverage).intersects (glyphs); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-  }
+  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -492,11 +535,42 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+
+    for (const auto &_ : hb_second (*it))
+      c->copy (_);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, it, valueFormat);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -527,10 +601,7 @@
   { return (this+coverage).intersects (glyphs); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-  }
+  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -551,11 +622,51 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+    if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+
+    for (const auto iter : it)
+      for (const auto &_ : iter.second)
+	c->copy (_);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned sub_length = valueFormat.get_len ();
+    auto values_array = values.as_array (valueCount * sub_length);
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+			      {
+				return hb_pair (glyph_map[_.first],
+						values_array.sub_array (_.second * sub_length,
+									sub_length));
+			      })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, it, valueFormat);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -582,14 +693,50 @@
 
 struct SinglePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  unsigned get_format (Iterator glyph_val_iter_pairs)
+  {
+    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+    for (const auto iter : glyph_val_iter_pairs)
+      for (const auto _ : hb_zip (iter.second, first_val_iter))
+	if (_.first != _.second)
+	  return 2;
+
+    return 1;
+  }
+
+
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator glyph_val_iter_pairs,
+		  ValueFormat valFormat)
+  {
+    if (unlikely (!c->extend_min (u.format))) return;
+    unsigned format = 2;
+
+    if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs);
+
+    u.format = format;
+    switch (u.format) {
+    case 1: u.format1.serialize (c, glyph_val_iter_pairs, valFormat);
+	    return;
+    case 2: u.format2.serialize (c, glyph_val_iter_pairs, valFormat);
+	    return;
+    default:return;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -602,13 +749,32 @@
   } u;
 };
 
+template<typename Iterator>
+static inline void
+SinglePos_serialize (hb_serialize_context_t *c,
+		     Iterator it,
+		     ValueFormat valFormat)
+{ c->start_embed<SinglePos> ()->serialize (c, it, valFormat); }
+
 
 struct PairValueRecord
 {
   friend struct PairSet;
 
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned length,
+                  const hb_map_t &glyph_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (*this);
+    if (unlikely (!c->extend_min (out))) return_trace (false);
+    
+    out->secondGlyph = glyph_map[secondGlyph];
+    return_trace (c->copy (values, length));
+  }
+
   protected:
-  GlyphID	secondGlyph;		/* GlyphID of second glyph in the
+  HBGlyphID	secondGlyph;		/* GlyphID of second glyph in the
 					 * pair--first glyph is listed in the
 					 * Coverage table */
   ValueRecord	values;			/* Positioning data for the first glyph
@@ -622,7 +788,7 @@
   friend struct PairPosFormat1;
 
   bool intersects (const hb_set_t *glyphs,
-			  const ValueFormat *valueFormats) const
+		   const ValueFormat *valueFormats) const
   {
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
@@ -642,7 +808,6 @@
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 			      const ValueFormat *valueFormats) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
@@ -693,6 +858,37 @@
     return_trace (false);
   }
 
+  bool subset (hb_subset_context_t *c,
+               const ValueFormat valueFormats[2]) const
+  {
+    TRACE_SUBSET (this);
+    auto snap = c->serializer->snapshot ();
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->len = 0;
+
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len, num = 0;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (!glyphset.has (record->secondGlyph)) continue;
+      if (record->serialize (c->serializer, len1 + len2, glyph_map)) num++;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+
+    out->len = num;
+    if (!num) c->serializer->revert (snap);
+    return_trace (num);
+  }
+
   struct sanitize_closure_t
   {
     const void *base;
@@ -729,21 +925,18 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int count = pairSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-	  (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
-	return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([glyphs, this] (const OffsetTo<PairSet> &_)
+	      { return (this+_).intersects (glyphs, valueFormat); })
+    | hb_any
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     unsigned int count = pairSet.len;
     for (unsigned int i = 0; i < count; i++)
@@ -769,8 +962,43 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat[0] = valueFormat[0];
+    out->valueFormat[1] = valueFormat[1];
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([this, c, out] (const OffsetTo<PairSet>& _)
+		 {
+		   auto *o = out->pairSet.serialize_append (c->serializer);
+		   if (unlikely (!o)) return false;
+		   auto snap = c->serializer->snapshot ();
+		   bool ret = o->serialize_subset (c, _, this, out, valueFormat);
+		   if (!ret)
+		   {
+		     out->pairSet.pop ();
+		     c->serializer->revert (snap);
+		   }
+		   return ret;
+		 },
+		 hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize (c->serializer, out)
+		 .serialize (c->serializer, new_coverage.iter ());
+
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -820,7 +1048,6 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
   }
@@ -862,8 +1089,49 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat1 = valueFormat1;
+    out->valueFormat2 = valueFormat2;
+
+    hb_map_t klass1_map;
+    out->classDef1.serialize_subset (c, classDef1, this, out, &klass1_map);
+    out->class1Count = klass1_map.get_population ();
+
+    hb_map_t klass2_map;
+    out->classDef2.serialize_subset (c, classDef2, this, out, &klass2_map);
+    out->class2Count = klass2_map.get_population ();
+
+    unsigned record_len = valueFormat1.get_len () + valueFormat2.get_len ();
+
+    + hb_range ((unsigned) class1Count)
+    | hb_filter (klass1_map)
+    | hb_apply ([&] (const unsigned class1_idx)
+                {
+                  + hb_range ((unsigned) class2Count)
+                  | hb_filter (klass2_map)
+                  | hb_apply ([&] (const unsigned class2_idx)
+                              {
+                                unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_len;
+                                for (unsigned i = 0; i < record_len; i++)
+                                  c->serializer->copy (values[idx+i]);
+                              })
+                  ;
+                })
+    ;
+
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    out->coverage.serialize (c->serializer, out).serialize (c->serializer, it);
+    return_trace (out->class1Count && out->class2Count && bool (it));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -918,14 +1186,14 @@
 
 struct PairPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -949,6 +1217,19 @@
     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
+  EntryExitRecord* copy (hb_serialize_context_t *c,
+			 const void *src_base,
+			 const void *dst_base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->entryAnchor.serialize_copy (c, entryAnchor, src_base, dst_base);
+    out->exitAnchor.serialize_copy (c, exitAnchor, src_base, dst_base);
+    return_trace (out);
+  }
+
   protected:
   OffsetTo<Anchor>
 		entryAnchor;		/* Offset to EntryAnchor table--from
@@ -971,10 +1252,7 @@
   { return (this+coverage).intersects (glyphs); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-  }
+  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -1007,32 +1285,32 @@
     /* Main-direction adjustment */
     switch (c->direction) {
       case HB_DIRECTION_LTR:
-	pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
+	pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
 
-	d = round (entry_x) + pos[j].x_offset;
+	d = roundf (entry_x) + pos[j].x_offset;
 	pos[j].x_advance -= d;
 	pos[j].x_offset  -= d;
 	break;
       case HB_DIRECTION_RTL:
-	d = round (exit_x) + pos[i].x_offset;
+	d = roundf (exit_x) + pos[i].x_offset;
 	pos[i].x_advance -= d;
 	pos[i].x_offset  -= d;
 
-	pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
+	pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
 	break;
       case HB_DIRECTION_TTB:
-	pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
+	pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
 
-	d = round (entry_y) + pos[j].y_offset;
+	d = roundf (entry_y) + pos[j].y_offset;
 	pos[j].y_advance -= d;
 	pos[j].y_offset  -= d;
 	break;
       case HB_DIRECTION_BTT:
-	d = round (exit_y) + pos[i].y_offset;
+	d = roundf (exit_y) + pos[i].y_offset;
 	pos[i].y_advance -= d;
 	pos[i].y_offset  -= d;
 
-	pos[j].y_advance  = round (entry_y);
+	pos[j].y_advance  = roundf (entry_y);
 	break;
       case HB_DIRECTION_INVALID:
       default:
@@ -1079,11 +1357,47 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+	    hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  const void *src_base)
+  {
+    if (unlikely (!c->extend_min ((*this)))) return;
+    this->format = 1;
+    this->entryExitRecord.len = it.len ();
+
+    for (const EntryExitRecord& entry_record : + it
+					       | hb_map (hb_second))
+      c->copy (entry_record, src_base, this);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto it =
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
+			      { return hb_pair (glyph_map[p.first], p.second);})
+    ;
+
+    bool ret = bool (it);
+    out->serialize (c->serializer, it, this);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1106,13 +1420,13 @@
 
 struct CursivePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1138,7 +1452,6 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
     if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
   }
@@ -1223,13 +1536,13 @@
 
 struct MarkBasePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1260,7 +1573,6 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
     if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
   }
@@ -1303,7 +1615,7 @@
     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     if (lig_id && lig_id == mark_id && mark_comp > 0)
-      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
     else
       comp_index = comp_count - 1;
 
@@ -1349,13 +1661,13 @@
 
 struct MarkLigPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1381,7 +1693,6 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
     if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
   }
@@ -1472,13 +1783,13 @@
 
 struct MarkMarkPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1524,20 +1835,20 @@
     Extension		= 9
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c));
-    case Pair:			return_trace (u.pair.dispatch (c));
-    case Cursive:		return_trace (u.cursive.dispatch (c));
-    case MarkBase:		return_trace (u.markBase.dispatch (c));
-    case MarkLig:		return_trace (u.markLig.dispatch (c));
-    case MarkMark:		return_trace (u.markMark.dispatch (c));
-    case Context:		return_trace (u.context.dispatch (c));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c));
-    case Extension:		return_trace (u.extension.dispatch (c));
+    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
+    case Pair:			return_trace (u.pair.dispatch (c, hb_forward<Ts> (ds)...));
+    case Cursive:		return_trace (u.cursive.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkBase:		return_trace (u.markBase.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkLig:		return_trace (u.markLig.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkMark:		return_trace (u.markMark.dispatch (c, hb_forward<Ts> (ds)...));
+    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
+    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
+    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
     default:			return_trace (c->default_return_value ());
     }
   }
@@ -1584,10 +1895,7 @@
   }
 
   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    return_trace (dispatch (c));
-  }
+  { return dispatch (c); }
 
   template <typename set_t>
   void add_coverage (set_t *glyphs) const
@@ -1596,14 +1904,14 @@
     dispatch (&c);
   }
 
-  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   template <typename context_t>
   static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<SubTable> (c); }
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1619,7 +1927,7 @@
 
 struct GPOS : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GPOS };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
   const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
@@ -1750,13 +2058,13 @@
 
 /* Out-of-class implementation for methods recursing */
 
+#ifndef HB_NO_OT_LAYOUT
 template <typename context_t>
 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
-
 /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
@@ -1769,6 +2077,7 @@
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
+#endif
 
 
 } /* namespace OT */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 180e7f2..fc21cb0 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -34,10 +34,12 @@
 
 namespace OT {
 
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
 
+template<typename Iterator>
 static inline void SingleSubst_serialize (hb_serialize_context_t *c,
-					  hb_array_t<const GlyphID> glyphs,
-					  hb_array_t<const GlyphID> substitutes);
+					  Iterator it);
+
 
 struct SingleSubstFormat1
 {
@@ -46,37 +48,28 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/harfbuzz/harfbuzz/issues/363 */
-      hb_codepoint_t glyph_id = iter.get_glyph ();
-      if (c->glyphs->has (glyph_id))
-	c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
-    }
+    unsigned d = deltaGlyphID;
+    + hb_iter (this+coverage)
+    | hb_filter (*c->glyphs)
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/harfbuzz/harfbuzz/issues/363 */
-      hb_codepoint_t glyph_id = iter.get_glyph ();
-      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
-    }
+    unsigned d = deltaGlyphID;
+    + hb_iter (this+coverage)
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -93,34 +86,41 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
-		  int delta)
+		  Iterator glyphs,
+		  unsigned delta)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
-    deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
+    c->check_assign (deltaGlyphID, delta);
     return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> from;
-    hb_vector_t<GlyphID> to;
+
     hb_codepoint_t delta = deltaGlyphID;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (!glyphset.has (iter.get_glyph ())) continue;
-      from.push ()->set (glyph_map[iter.get_glyph ()]);
-      to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
-    }
-    c->serializer->propagate_error (from, to);
-    SingleSubst_serialize (c->serializer, from, to);
-    return_trace (from.len);
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
+				return hb_codepoint_pair_t (g,
+							    (g + delta) & 0xFFFF); })
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
+			      { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -134,8 +134,8 @@
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
-					 * substitute GlyphID */
+  HBUINT16	deltaGlyphID;		/* Add to original GlyphID to get
+					 * substitute GlyphID, modulo 0x10000 */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -147,37 +147,26 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	c->out->add (substitute[iter.get_coverage ()]);
-    }
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      c->output->add (substitute[iter.get_coverage ()]);
-    }
+    + hb_zip (this+coverage, substitute)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -192,11 +181,21 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_sorted_source_of (Iterator,
+						hb_codepoint_pair_t))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
-		  hb_array_t<const GlyphID> substitutes)
+		  Iterator it)
   {
     TRACE_SERIALIZE (this);
+    auto substitutes =
+      + it
+      | hb_map (hb_second)
+      ;
+    auto glyphs =
+      + it
+      | hb_map_retains_sorting (hb_first)
+      ;
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
@@ -206,19 +205,20 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> from;
-    hb_vector_t<GlyphID> to;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (!glyphset.has (iter.get_glyph ())) continue;
-      from.push ()->set (glyph_map[iter.get_glyph ()]);
-      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
-    }
-    c->serializer->propagate_error (from, to);
-    SingleSubst_serialize (c->serializer, from, to);
-    return_trace (from.len);
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID &> p) -> hb_codepoint_pair_t
+			      { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -232,7 +232,7 @@
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -241,41 +241,45 @@
 
 struct SingleSubst
 {
+
+  template<typename Iterator,
+	   hb_requires (hb_is_sorted_source_of (Iterator,
+						const hb_codepoint_pair_t))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
-		  hb_array_t<const GlyphID> substitutes)
+		  Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 2;
-    int delta = 0;
-    if (glyphs.len)
+    unsigned format = 2;
+    unsigned delta = 0;
+    if (glyphs)
     {
       format = 1;
-      /* TODO(serialize) check for wrap-around */
-      delta = substitutes[0] - glyphs[0];
-      for (unsigned int i = 1; i < glyphs.len; i++)
-	if (delta != (int) (substitutes[i] - glyphs[i])) {
-	  format = 2;
-	  break;
-	}
+      auto get_delta = [=] (hb_codepoint_pair_t _) {
+			 return (unsigned) (_.second - _.first) & 0xFFFF;
+		       };
+      delta = get_delta (*glyphs);
+      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
     }
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, delta));
-    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
+    case 1: return_trace (u.format1.serialize (c,
+					       + glyphs
+					       | hb_map_retains_sorting (hb_first),
+					       delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -288,27 +292,22 @@
   } u;
 };
 
+template<typename Iterator>
 static inline void
 SingleSubst_serialize (hb_serialize_context_t *c,
-		       hb_array_t<const GlyphID> glyphs,
-		       hb_array_t<const GlyphID> substitutes)
-{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
+		       Iterator it)
+{ c->start_embed<SingleSubst> ()->serialize (c, it); }
 
 struct Sequence
 {
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (substitute, glyphs); }
+
   void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE (this);
-    unsigned int count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->out->add (substitute[i]);
-  }
+  { c->output->add_array (substitute.arrayZ, substitute.len); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    c->output->add_array (substitute.arrayZ, substitute.len);
-  }
+  { c->output->add_array (substitute.arrayZ, substitute.len); }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -342,11 +341,30 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs)
+		  Iterator subst)
   {
     TRACE_SERIALIZE (this);
-    return_trace (substitute.serialize (c, glyphs));
+    return_trace (substitute.serialize (c, subst));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset)) return_trace (false);
+
+    auto it =
+      + hb_iter (substitute)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -356,7 +374,7 @@
   }
 
   protected:
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
@@ -369,33 +387,28 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int count = sequence.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	(this+sequence[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = sequence.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+sequence[i]).collect_glyphs (c);
+    + hb_zip (this+coverage, sequence)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -408,14 +421,14 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID> glyphs,
 		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const GlyphID> substitute_glyphs_list)
+		  hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!sequence.serialize (c, glyphs.len))) return_trace (false);
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < glyphs.length; i++)
     {
       unsigned int substitute_len = substitute_len_list[i];
       if (unlikely (!sequence[i].serialize (c, this)
@@ -429,8 +442,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->sequence, this, out), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+		 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -454,27 +483,27 @@
 struct MultipleSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID> glyphs,
 		  hb_array_t<const unsigned int> substitute_len_list,
-		  hb_array_t<const GlyphID> substitute_glyphs_list)
+		  hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -488,19 +517,14 @@
 
 struct AlternateSet
 {
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_any (alternates, glyphs); }
+
   void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE (this);
-    unsigned int count = alternates.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->out->add (alternates[i]);
-  }
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  {
-    TRACE_COLLECT_GLYPHS (this);
-    c->output->add_array (alternates.arrayZ, alternates.len);
-  }
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -516,7 +540,7 @@
     unsigned int shift = hb_ctz (lookup_mask);
     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
 
-    /* If alt_index is MAX, randomize feature if it is the rand feature. */
+    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
     if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
       alt_index = c->random_number () % count + 1;
 
@@ -527,11 +551,30 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs)
+		  Iterator alts)
   {
     TRACE_SERIALIZE (this);
-    return_trace (alternates.serialize (c, glyphs));
+    return_trace (alternates.serialize (c, alts));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+      + hb_iter (alternates)
+      | hb_filter (glyphset)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it) &&
+		  out->alternates);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -541,7 +584,7 @@
   }
 
   protected:
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
 		alternates;		/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
   public:
@@ -555,37 +598,27 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int count = alternateSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	(this+alternateSet[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, alternateSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = alternateSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
-    }
+    + hb_zip (this+coverage, alternateSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -598,14 +631,14 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID> glyphs,
 		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const GlyphID> alternate_glyphs_list)
+		  hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!alternateSet.serialize (c, glyphs.len))) return_trace (false);
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < glyphs.length; i++)
     {
       unsigned int alternate_len = alternate_len_list[i];
       if (unlikely (!alternateSet[i].serialize (c, this)
@@ -619,8 +652,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->alternateSet, this, out), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+		 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -644,27 +693,27 @@
 struct AlternateSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> glyphs,
+		  hb_sorted_array_t<const HBGlyphID> glyphs,
 		  hb_array_t<const unsigned int> alternate_len_list,
-		  hb_array_t<const GlyphID> alternate_glyphs_list)
+		  hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -680,42 +729,30 @@
 struct Ligature
 {
   bool intersects (const hb_set_t *glyphs) const
-  {
-    unsigned int count = component.lenP1;
-    for (unsigned int i = 1; i < count; i++)
-      if (!glyphs->has (component[i]))
-        return false;
-    return true;
-  }
+  { return hb_all (component, glyphs); }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int count = component.lenP1;
-    for (unsigned int i = 1; i < count; i++)
-      if (!c->glyphs->has (component[i]))
-        return;
-    c->out->add (ligGlyph);
+    if (!intersects (c->glyphs)) return;
+    c->output->add (ligGlyph);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
+    c->input->add_array (component.arrayZ, component.get_length ());
     c->output->add (ligGlyph);
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
     if (c->len != component.lenP1)
-      return_trace (false);
+      return false;
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
-	return_trace (false);
+	return false;
 
-    return_trace (true);
+    return true;
   }
 
   bool apply (hb_ot_apply_context_t *c) const
@@ -757,9 +794,11 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-		  GlyphID ligature,
-		  hb_array_t<const GlyphID> components /* Starting from second */)
+		  hb_codepoint_t ligature,
+		  Iterator components /* Starting from second */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -768,6 +807,25 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
+
+    auto it =
+      + hb_iter (component)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer,
+				   glyph_map[ligGlyph],
+				   it));
+  }
+
   public:
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -776,8 +834,8 @@
   }
 
   protected:
-  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
-  HeadlessArrayOf<GlyphID>
+  HBGlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
+  HeadlessArrayOf<HBGlyphID>
 		component;		/* Array of component GlyphIDs--start
 					 * with the second  component--ordered
 					 * in writing direction */
@@ -789,40 +847,38 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      if ((this+ligature[i]).intersects (glyphs))
-        return true;
-    return false;
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      (this+ligature[i]).closure (c);
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      (this+ligature[i]).collect_glyphs (c);
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-    {
-      const Ligature &lig = this+ligature[i];
-      if (lig.would_apply (c))
-        return_trace (true);
-    }
-    return_trace (false);
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c) const
@@ -839,16 +895,16 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> ligatures,
+		  hb_array_t<const HBGlyphID> ligatures,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+		  hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!ligature.serialize (c, ligatures.len))) return_trace (false);
-    for (unsigned int i = 0; i < ligatures.len; i++)
+    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
+    for (unsigned int i = 0; i < ligatures.length; i++)
     {
-      unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
+      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
       if (unlikely (!ligature[i].serialize (c, this)
 				.serialize (c,
 					    ligatures[i],
@@ -859,6 +915,19 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (ligature)
+    | hb_filter (subset_offset_array (c, out->ligature, this, out))
+    | hb_drain
+    ;
+    return_trace (bool (out->ligature));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -877,54 +946,46 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-	  (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
-        return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
+	      { return (this+_).intersects (glyphs); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	(this+ligatureSet[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
-    }
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return false;
 
     const LigatureSet &lig_set = this+ligatureSet[index];
-    return_trace (lig_set.would_apply (c));
+    return lig_set.would_apply (c);
   }
 
   bool apply (hb_ot_apply_context_t *c) const
@@ -939,16 +1000,16 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> first_glyphs,
+		  hb_sorted_array_t<const HBGlyphID> first_glyphs,
 		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const GlyphID> ligatures_list,
+		  hb_array_t<const HBGlyphID> ligatures_list,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+		  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!ligatureSet.serialize (c, first_glyphs.len))) return_trace (false);
-    for (unsigned int i = 0; i < first_glyphs.len; i++)
+    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
+    for (unsigned int i = 0; i < first_glyphs.length; i++)
     {
       unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
       if (unlikely (!ligatureSet[i].serialize (c, this)
@@ -958,8 +1019,6 @@
 					       component_list))) return_trace (false);
       ligatures_list += ligature_count;
       component_count_list += ligature_count;
-      for (unsigned int i = 0; i < ligature_count; i++)
-	component_list += MAX<int> (component_count_list[i] - 1, 0);
     }
     return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
   }
@@ -967,8 +1026,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ligatureSet, this, out), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+		 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -992,16 +1067,16 @@
 struct LigatureSubst
 {
   bool serialize (hb_serialize_context_t *c,
-		  hb_array_t<const GlyphID> first_glyphs,
+		  hb_sorted_array_t<const HBGlyphID> first_glyphs,
 		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-		  hb_array_t<const GlyphID> ligatures_list,
+		  hb_array_t<const HBGlyphID> ligatures_list,
 		  hb_array_t<const unsigned int> component_count_list,
-		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+		  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c,
 					       first_glyphs,
@@ -1013,13 +1088,13 @@
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1051,54 +1126,39 @@
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     unsigned int count;
 
     count = backtrack.len;
     for (unsigned int i = 0; i < count; i++)
       if (!(this+backtrack[i]).intersects (glyphs))
-        return false;
+	return false;
 
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
       if (!(this+lookahead[i]).intersects (glyphs))
-        return false;
+	return false;
 
     return true;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (!intersects (c->glyphs)) return;
 
-    unsigned int count;
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
 
-    count = backtrack.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+backtrack[i]).intersects (c->glyphs))
-        return;
-
-    count = lookahead.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+lookahead[i]).intersects (c->glyphs))
-        return;
-
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
-    count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	c->out->add (substitute[iter.get_coverage ()]);
-    }
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
 
     unsigned int count;
@@ -1107,12 +1167,12 @@
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
 
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -1120,10 +1180,7 @@
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1134,15 +1191,15 @@
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
 
   unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
 			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
 			 match_coverage, this,
 			 &start_index) &&
-        match_lookahead (c,
+	match_lookahead (c,
 			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
 			 match_coverage, this,
 			 1, &end_index))
@@ -1170,10 +1227,10 @@
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
@@ -1190,7 +1247,7 @@
 		lookaheadX;		/* Array of coverage tables
 					 * in lookahead sequence, in glyph
 					 * sequence order */
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
 		substituteX;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -1199,13 +1256,13 @@
 
 struct ReverseChainSingleSubst
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1239,19 +1296,19 @@
     ReverseChainSingle	= 8
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:		return_trace (u.single.dispatch (c));
-    case Multiple:		return_trace (u.multiple.dispatch (c));
-    case Alternate:		return_trace (u.alternate.dispatch (c));
-    case Ligature:		return_trace (u.ligature.dispatch (c));
-    case Context:		return_trace (u.context.dispatch (c));
-    case ChainContext:		return_trace (u.chainContext.dispatch (c));
-    case Extension:		return_trace (u.extension.dispatch (c));
-    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
+    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
+    case Multiple:		return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
+    case Alternate:		return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
+    case Ligature:		return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
+    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
+    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
+    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
+    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
     default:			return_trace (c->default_return_value ());
     }
   }
@@ -1279,7 +1336,7 @@
   const SubTable& get_subtable (unsigned int i) const
   { return Lookup::get_subtable<SubTable> (i); }
 
-  static bool lookup_type_is_reverse (unsigned int lookup_type)
+  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
   { return lookup_type == SubTable::ReverseChainSingle; }
 
   bool is_reverse () const
@@ -1304,9 +1361,8 @@
 
   hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
   {
-    TRACE_CLOSURE (this);
     if (!c->should_visit_lookup (this_index))
-      return_trace (HB_VOID);
+      return hb_closure_context_t::default_return_value ();
 
     c->set_recurse_func (dispatch_closure_recurse_func);
 
@@ -1314,14 +1370,13 @@
 
     c->flush ();
 
-    return_trace (ret);
+    return ret;
   }
 
   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
-    return_trace (dispatch (c));
+    return dispatch (c);
   }
 
   template <typename set_t>
@@ -1334,81 +1389,84 @@
   bool would_apply (hb_would_apply_context_t *c,
 		    const hb_ot_layout_lookup_accelerator_t *accel) const
   {
-    TRACE_WOULD_APPLY (this);
-    if (unlikely (!c->len))  return_trace (false);
-    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
-      return_trace (dispatch (c));
+    if (unlikely (!c->len)) return false;
+    if (!accel->may_have (c->glyphs[0])) return false;
+      return dispatch (c);
   }
 
-  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   SubTable& serialize_subtable (hb_serialize_context_t *c,
-				       unsigned int i)
+				unsigned int i)
   { return get_subtables<SubTable> ()[i].serialize (c, this); }
 
   bool serialize_single (hb_serialize_context_t *c,
 			 uint32_t lookup_props,
-		         hb_array_t<const GlyphID> glyphs,
-		         hb_array_t<const GlyphID> substitutes)
+			 hb_sorted_array_t<const HBGlyphID> glyphs,
+			 hb_array_t<const HBGlyphID> substitutes)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
+    return_trace (serialize_subtable (c, 0).u.single.
+		  serialize (c, hb_zip (glyphs, substitutes)));
   }
 
   bool serialize_multiple (hb_serialize_context_t *c,
 			   uint32_t lookup_props,
-			   hb_array_t<const GlyphID> glyphs,
+			   hb_sorted_array_t<const HBGlyphID> glyphs,
 			   hb_array_t<const unsigned int> substitute_len_list,
-			   hb_array_t<const GlyphID> substitute_glyphs_list)
+			   hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
-								  glyphs,
-								  substitute_len_list,
-								  substitute_glyphs_list));
+    return_trace (serialize_subtable (c, 0).u.multiple.
+		  serialize (c,
+			     glyphs,
+			     substitute_len_list,
+			     substitute_glyphs_list));
   }
 
   bool serialize_alternate (hb_serialize_context_t *c,
 			    uint32_t lookup_props,
-			    hb_array_t<const GlyphID> glyphs,
+			    hb_sorted_array_t<const HBGlyphID> glyphs,
 			    hb_array_t<const unsigned int> alternate_len_list,
-			    hb_array_t<const GlyphID> alternate_glyphs_list)
+			    hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
-								   glyphs,
-								   alternate_len_list,
-								   alternate_glyphs_list));
+    return_trace (serialize_subtable (c, 0).u.alternate.
+		  serialize (c,
+			     glyphs,
+			     alternate_len_list,
+			     alternate_glyphs_list));
   }
 
   bool serialize_ligature (hb_serialize_context_t *c,
 			   uint32_t lookup_props,
-			   hb_array_t<const GlyphID> first_glyphs,
+			   hb_sorted_array_t<const HBGlyphID> first_glyphs,
 			   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-			   hb_array_t<const GlyphID> ligatures_list,
+			   hb_array_t<const HBGlyphID> ligatures_list,
 			   hb_array_t<const unsigned int> component_count_list,
-			   hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+			   hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
-								  first_glyphs,
-								  ligature_per_first_glyph_count_list,
-								  ligatures_list,
-								  component_count_list,
-								  component_list));
+    return_trace (serialize_subtable (c, 0).u.ligature.
+		  serialize (c,
+			     first_glyphs,
+			     ligature_per_first_glyph_count_list,
+			     ligatures_list,
+			     component_count_list,
+			     component_list));
   }
 
   template <typename context_t>
-  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+  HB_INTERNAL static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
   {
     if (!c->should_visit_lookup (lookup_index))
-      return HB_VOID;
+      return hb_empty_t ();
 
     hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
 
@@ -1420,9 +1478,9 @@
     return ret;
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<SubTable> (c); }
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1438,7 +1496,7 @@
 
 struct GSUB : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GSUB };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
 
   const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
@@ -1461,6 +1519,7 @@
 
 /* Out-of-class implementation for methods recursing */
 
+#ifndef HB_NO_OT_LAYOUT
 /*static*/ inline bool ExtensionSubst::is_reverse () const
 {
   unsigned int type = get_type ();
@@ -1468,14 +1527,12 @@
     return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
-
 template <typename context_t>
 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
-
 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
@@ -1488,6 +1545,8 @@
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
+#endif
+
 
 } /* namespace OT */
 
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index ac6e646..579d178 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -59,13 +59,13 @@
 };
 
 struct hb_closure_context_t :
-       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
+       hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0>
 {
   const char *get_name () { return "CLOSURE"; }
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
-  return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
-  static return_t default_return_value () { return HB_VOID; }
+  return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
   void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -92,7 +92,7 @@
 
   hb_face_t *face;
   hb_set_t *glyphs;
-  hb_set_t out[1];
+  hb_set_t output[1];
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
@@ -114,8 +114,8 @@
 
   void flush ()
   {
-    hb_set_union (glyphs, out);
-    hb_set_clear (out);
+    hb_set_union (glyphs, output);
+    hb_set_clear (output);
   }
 
   private:
@@ -124,7 +124,7 @@
 
 
 struct hb_would_apply_context_t :
-       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
+       hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
 {
   const char *get_name () { return "WOULD_APPLY"; }
   template <typename T>
@@ -151,13 +151,13 @@
 
 
 struct hb_collect_glyphs_context_t :
-       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
+       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0>
 {
   const char *get_name () { return "COLLECT_GLYPHS"; }
   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   template <typename T>
-  return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
-  static return_t default_return_value () { return HB_VOID; }
+  return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
   void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -286,7 +286,7 @@
     };
 
     may_match_t may_match (const hb_glyph_info_t &info,
-				  const HBUINT16        *glyph_data) const
+			   const HBUINT16        *glyph_data) const
     {
       if (!(info.mask & mask) ||
 	  (syllable && syllable != info.syllable ()))
@@ -387,7 +387,7 @@
 	     skip == matcher_t::SKIP_NO))
 	{
 	  num_items--;
-	  match_glyph_data++;
+	  if (match_glyph_data) match_glyph_data++;
 	  return true;
 	}
 
@@ -414,7 +414,7 @@
 	     skip == matcher_t::SKIP_NO))
 	{
 	  num_items--;
-	  match_glyph_data++;
+	  if (match_glyph_data) match_glyph_data++;
 	  return true;
 	}
 
@@ -483,7 +483,13 @@
 			iter_input (), iter_context (),
 			font (font_), face (font->face), buffer (buffer_),
 			recurse_func (nullptr),
-			gdef (*face->table.GDEF->table),
+			gdef (
+#ifndef HB_NO_OT_LAYOUT
+			      *face->table.GDEF->table
+#else
+			      Null(GDEF)
+#endif
+			     ),
 			var_store (gdef.get_var_store ()),
 			direction (buffer_->props.direction),
 			lookup_mask (1),
@@ -610,10 +616,10 @@
 
 
 struct hb_get_subtables_context_t :
-       hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+       hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
 {
   template <typename Type>
-  static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+  HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
   {
     const Type *typed_obj = (const Type *) obj;
     return typed_obj->apply (c);
@@ -643,7 +649,7 @@
     hb_set_digest_t digest;
   };
 
-  typedef hb_vector_t<hb_applicable_t, 2> array_t;
+  typedef hb_vector_t<hb_applicable_t> array_t;
 
   /* Dispatch interface. */
   const char *get_name () { return "GET_SUBTABLES"; }
@@ -652,9 +658,9 @@
   {
     hb_applicable_t *entry = array.push();
     entry->init (obj, apply_to<T>);
-    return HB_VOID;
+    return hb_empty_t ();
   }
-  static return_t default_return_value () { return HB_VOID; }
+  static return_t default_return_value () { return hb_empty_t (); }
 
   hb_get_subtables_context_t (array_t &array_) :
 			      array (array_),
@@ -706,10 +712,9 @@
 				     intersects_func_t intersects_func,
 				     const void *intersects_data)
 {
-  for (unsigned int i = 0; i < count; i++)
-    if (likely (!intersects_func (glyphs, values[i], intersects_data)))
-      return false;
-  return true;
+  for (const HBUINT16 &_ : + hb_iter (values, count))
+    if (intersects_func (glyphs, _, intersects_data)) return true;
+  return false;
 }
 
 
@@ -734,8 +739,10 @@
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
-  for (unsigned int i = 0; i < count; i++)
-    collect_func (glyphs, values[i], collect_data);
+  return
+  + hb_iter (values, count)
+  | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
+  ;
 }
 
 
@@ -846,7 +853,7 @@
 	if (ligbase == LIGBASE_NOT_CHECKED)
 	{
 	  bool found = false;
-	  const hb_glyph_info_t *out = buffer->out_info;
+	  const auto *out = buffer->out_info;
 	  unsigned int j = buffer->out_len;
 	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
 	  {
@@ -970,7 +977,7 @@
 	if (this_comp == 0)
 	  this_comp = last_num_components;
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (this_comp, last_num_components);
+				    hb_min (this_comp, last_num_components);
 	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
       buffer->next_glyph ();
@@ -992,7 +999,7 @@
 	if (!this_comp)
 	  break;
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (this_comp, last_num_components);
+				    hb_min (this_comp, last_num_components);
 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
       } else
 	break;
@@ -1170,7 +1177,7 @@
     else
     {
       /* NOTE: delta is negative. */
-      delta = MAX (delta, (int) next - (int) count);
+      delta = hb_max (delta, (int) next - (int) count);
       next -= delta;
     }
 
@@ -1296,8 +1303,7 @@
 
   void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
 						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
     context_closure_lookup (c,
 			    inputCount, inputZ.arrayZ,
@@ -1308,8 +1314,7 @@
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 		       ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     context_collect_glyphs_lookup (c,
 				   inputCount, inputZ.arrayZ,
@@ -1320,17 +1325,19 @@
   bool would_apply (hb_would_apply_context_t *c,
 		    ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
-    return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
+    return context_would_apply_lookup (c,
+				       inputCount, inputZ.arrayZ,
+				       lookupCount, lookupRecord.arrayZ,
+				       lookup_context);
   }
 
   bool apply (hb_ot_apply_context_t *c,
 	      ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
 						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
   }
@@ -1366,55 +1373,56 @@
   bool intersects (const hb_set_t *glyphs,
 		   ContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).intersects (glyphs, lookup_context))
-	return true;
-    return false;
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c,
 		ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).closure (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 		       ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).collect_glyphs (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c,
 		    ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-    {
-      if ((this+rule[i]).would_apply (c, lookup_context))
-	return_trace (true);
-    }
-    return_trace (false);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c,
 	      ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-    {
-      if ((this+rule[i]).apply (c, lookup_context))
-	return_trace (true);
-    }
-    return_trace (false);
+    return_trace (
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+    | hb_any
+    )
+    ;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1441,40 +1449,33 @@
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
-	return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
-    }
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
@@ -1482,21 +1483,20 @@
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
       nullptr
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -1556,18 +1556,17 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (class_def.intersects_class (glyphs, i) &&
-	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
-	return true;
-
-    return false;
+    return
+    + hb_enumerate (ruleSet)
+    | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
+	      { return class_def.intersects_class (glyphs, p.first) &&
+		       (this+p.second).intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
@@ -1578,17 +1577,19 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (class_def.intersects_class (c->glyphs, i)) {
-	const RuleSet &rule_set = this+ruleSet[i];
-	rule_set.closure (c, lookup_context);
-      }
+    return
+    + hb_enumerate (ruleSet)
+    | hb_filter ([&] (unsigned _)
+		 { return class_def.intersects_class (c->glyphs, _); },
+		 hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     const ClassDef &class_def = this+classDef;
@@ -1597,15 +1598,14 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ClassDef &class_def = this+classDef;
     unsigned int index = class_def.get_class (c->glyphs[0]);
     const RuleSet &rule_set = this+ruleSet[index];
@@ -1613,7 +1613,7 @@
       {match_class},
       &class_def
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -1681,7 +1681,6 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
     if (!(this+coverageZ[0]).intersects (c->glyphs))
       return;
 
@@ -1698,7 +1697,6 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     (this+coverageZ[0]).add_coverage (c->input);
 
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
@@ -1715,14 +1713,15 @@
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
+    return context_would_apply_lookup (c,
+				       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
+				       lookupCount, lookupRecord,
+				       lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverageZ[0]; }
@@ -1766,7 +1765,7 @@
   HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
 					 * sequence */
   HBUINT16	lookupCount;		/* Number of LookupRecords */
-  UnsizedArrayOf<OffsetTo<Coverage> >
+  UnsizedArrayOf<OffsetTo<Coverage>>
 		coverageZ;		/* Array of offsets to Coverage
 					 * table in glyph sequence order */
 /*UnsizedArrayOf<LookupRecord>
@@ -1778,15 +1777,15 @@
 
 struct Context
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    case 3: return_trace (c->dispatch (u.format3));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1938,8 +1937,8 @@
 {
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
     return chain_context_intersects (glyphs,
 				     backtrack.len, backtrack.arrayZ,
 				     input.lenP1, input.arrayZ,
@@ -1950,10 +1949,9 @@
   void closure (hb_closure_context_t *c,
 		ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.arrayZ,
 				  input.lenP1, input.arrayZ,
@@ -1965,10 +1963,9 @@
   void collect_glyphs (hb_collect_glyphs_context_t *c,
 		       ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.arrayZ,
 					 input.lenP1, input.arrayZ,
@@ -1980,23 +1977,22 @@
   bool would_apply (hb_would_apply_context_t *c,
 		    ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return_trace (chain_context_would_apply_lookup (c,
-						    backtrack.len, backtrack.arrayZ,
-						    input.lenP1, input.arrayZ,
-						    lookahead.len, lookahead.arrayZ, lookup.len,
-						    lookup.arrayZ, lookup_context));
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    return chain_context_would_apply_lookup (c,
+					     backtrack.len, backtrack.arrayZ,
+					     input.lenP1, input.arrayZ,
+					     lookahead.len, lookahead.arrayZ, lookup.len,
+					     lookup.arrayZ, lookup_context);
   }
 
   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.arrayZ,
 					      input.lenP1, input.arrayZ,
@@ -2004,15 +2000,92 @@
 					      lookup.arrayZ, lookup_context));
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  void serialize_array (hb_serialize_context_t *c,
+                        HBUINT16 len,
+                        Iterator it) const
+  {
+    c->copy (len);
+    for (const auto g : it)
+    {
+      HBUINT16 gid;
+      gid = g;
+      c->copy (gid);
+    }
+  }
+
+  ChainRule* copy (hb_serialize_context_t *c,
+		   const hb_map_t *backtrack_map,
+		   const hb_map_t *input_map = nullptr,
+		   const hb_map_t *lookahead_map = nullptr) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    const hb_map_t *mapping = backtrack_map;
+    serialize_array (c, backtrack.len, + backtrack.iter ()
+				       | hb_map (mapping));
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    if (input_map) mapping = input_map;
+    serialize_array (c, input.lenP1, + input.iter ()
+				     | hb_map (mapping));
+
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    if (lookahead_map) mapping = lookahead_map;
+    serialize_array (c, lookahead.len, + lookahead.iter ()
+				       | hb_map (mapping));
+
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    c->copy (lookup);
+
+    return_trace (out);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *backtrack_map = nullptr,
+               const hb_map_t *input_map = nullptr,
+               const hb_map_t *lookahead_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+
+    if (!backtrack_map)
+    {
+      const hb_set_t &glyphset = *c->plan->glyphset ();
+      if (!hb_all (backtrack, glyphset) ||
+          !hb_all (input, glyphset) ||
+          !hb_all (lookahead, glyphset))
+        return_trace (false);
+
+      copy (c->serializer, c->plan->glyph_map);
+    }
+    else
+    {
+      if (!hb_all (backtrack, backtrack_map) ||
+          !hb_all (input, input_map) ||
+          !hb_all (lookahead, lookahead_map))
+        return_trace (false);
+
+      copy (c->serializer, backtrack_map, input_map, lookahead_map);
+    }
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
     if (!lookahead.sanitize (c)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
@@ -2038,48 +2111,85 @@
 {
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).intersects (glyphs, lookup_context))
-	return true;
-    return false;
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
   void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).closure (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).collect_glyphs (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).would_apply (c, lookup_context))
-	return_trace (true);
-
-    return_trace (false);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).apply (c, lookup_context))
-	return_trace (true);
+    return_trace (
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+    | hb_any
+    )
+    ;
+  }
 
-    return_trace (false);
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *backtrack_klass_map = nullptr,
+               const hb_map_t *input_klass_map = nullptr,
+               const hb_map_t *lookahead_klass_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    auto snap = c->serializer->snapshot ();
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    for (const OffsetTo<ChainRule>& _ : rule)
+    {
+      if (!_) continue;
+      auto *o = out->rule.serialize_append (c->serializer);
+      if (unlikely (!o)) continue;
+
+      auto o_snap = c->serializer->snapshot ();
+      if (!o->serialize_subset (c, _, this, out,
+                                backtrack_klass_map,
+                                input_klass_map,
+                                lookahead_klass_map))
+      {
+        out->rule.pop ();
+        c->serializer->revert (o_snap);
+      }
+    }
+
+    bool ret = bool (out->rule);
+    if (!ret) c->serializer->revert (snap);
+
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2105,40 +2215,33 @@
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
-	return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
-    }
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
@@ -2146,21 +2249,20 @@
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
       {nullptr, nullptr, nullptr}
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -2182,8 +2284,25 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ruleSet, this, out), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize (c->serializer, out)
+		 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2222,17 +2341,16 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (input_class_def.intersects_class (glyphs, i) &&
-	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
-	return true;
-
-    return false;
+    return
+    + hb_enumerate (ruleSet)
+    | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
+	      { return input_class_def.intersects_class (glyphs, p.first) &&
+		       (this+p.second).intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
@@ -2247,17 +2365,19 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (input_class_def.intersects_class (c->glyphs, i)) {
-	const ChainRuleSet &rule_set = this+ruleSet[i];
-	rule_set.closure (c, lookup_context);
-      }
+    return
+    + hb_enumerate (ruleSet)
+    | hb_filter ([&] (unsigned _)
+		 { return input_class_def.intersects_class (c->glyphs, _); },
+		 hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
     (this+coverage).add_coverage (c->input);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
@@ -2271,15 +2391,14 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
@@ -2292,7 +2411,7 @@
        &input_class_def,
        &lookahead_class_def}
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -2321,8 +2440,54 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->coverage.serialize_subset (c, coverage, this, out);
+
+    hb_map_t backtrack_klass_map;
+    out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, out, &backtrack_klass_map);
+
+    // subset inputClassDef based on glyphs survived in Coverage subsetting
+    hb_map_t input_klass_map;
+    out->inputClassDef.serialize_subset (c, inputClassDef, this, out, &input_klass_map);
+
+    hb_map_t lookahead_klass_map;
+    out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, out, &lookahead_klass_map);
+
+    hb_vector_t<unsigned> rulesets;
+    bool ret = true;
+    for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
+					   | hb_filter (input_klass_map, hb_first)
+					   | hb_map (hb_second))
+    {
+      auto *o = out->ruleSet.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+        ret = false;
+        break;
+      }
+      if (!o->serialize_subset (c, _, this, out,
+                                &backtrack_klass_map,
+                                &input_klass_map,
+                                &lookahead_klass_map))
+      {
+        rulesets.push (0);
+      }
+      else rulesets.push (1);
+    }
+
+    if (!ret) return_trace (ret);
+
+    //prune empty trailing ruleSets
+    unsigned count = rulesets.length;
+    while (count > 0 && rulesets[count-1] == 0)
+    {
+      out->ruleSet.pop ();
+      count--;
+    }
+
+    return_trace (bool (out->ruleSet));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2363,12 +2528,12 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
@@ -2382,14 +2547,13 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
@@ -2404,13 +2568,12 @@
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_COLLECT_GLYPHS (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     (this+input[0]).add_coverage (c->input);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
@@ -2425,38 +2588,36 @@
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
-    return_trace (chain_context_would_apply_lookup (c,
-						    backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
-						    input.len, (const HBUINT16 *) input.arrayZ + 1,
-						    lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
-						    lookup.len, lookup.arrayZ, lookup_context));
+    return chain_context_would_apply_lookup (c,
+					     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
+					     input.len, (const HBUINT16 *) input.arrayZ + 1,
+					     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
+					     lookup.len, lookup.arrayZ, lookup_context);
   }
 
   const Coverage &get_coverage () const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     return this+input[0];
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
@@ -2468,23 +2629,58 @@
 					      lookup.len, lookup.arrayZ, lookup_context));
   }
 
+  template<typename Iterator,
+	   hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_coverage_offsets (hb_subset_context_t *c,
+                                   Iterator it,
+				   const void* src_base,
+				   const void* dst_base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
+
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+
+    + it
+    | hb_apply (subset_offset_array (c, *out, src_base, dst_base))
+    ;
+
+    return_trace (out->len);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out)) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+
+    if (!serialize_coverage_offsets (c, backtrack.iter (), this, out))
+      return_trace (false);
+
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    if (!serialize_coverage_offsets (c, input.iter (), this, out))
+      return_trace (false);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    if (!serialize_coverage_offsets (c, lookahead.iter (), this, out))
+      return_trace (false);
+
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    return_trace (c->serializer->copy (lookup));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return_trace (false);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     if (!input.sanitize (c, this)) return_trace (false);
     if (!input.len) return_trace (false); /* To be consistent with Context. */
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
@@ -2511,15 +2707,15 @@
 
 struct ChainContext
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    case 3: return_trace (c->dispatch (u.format3));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -2541,18 +2737,14 @@
 
   template <typename X>
   const X& get_subtable () const
-  {
-    unsigned int offset = extensionOffset;
-    if (unlikely (!offset)) return Null(typename T::SubTable);
-    return StructAtOffset<typename T::SubTable> (this, offset);
-  }
+  { return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, format);
     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
-    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
+    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
   }
 
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
@@ -2560,7 +2752,6 @@
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-		  extensionOffset != 0 &&
 		  extensionLookupType != T::SubTable::Extension);
   }
 
@@ -2569,7 +2760,7 @@
   HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
 					 * by ExtensionOffset (i.e. the
 					 * extension subtable). */
-  HBUINT32	extensionOffset;	/* Offset to the extension subtable,
+  Offset32	extensionOffset;	/* Offset to the extension subtable,
 					 * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -2594,13 +2785,13 @@
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (u.format1.dispatch (c));
+    case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -2636,7 +2827,7 @@
 
   bool apply (hb_ot_apply_context_t *c) const
   {
-    for (unsigned int i = 0; i < subtables.len; i++)
+    for (unsigned int i = 0; i < subtables.length; i++)
       if (subtables[i].apply (c))
 	return true;
     return false;
@@ -2683,11 +2874,17 @@
 
   bool find_variations_index (const int *coords, unsigned int num_coords,
 			      unsigned int *index) const
-  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
-	   .find_index (coords, num_coords, index); }
-  const Feature& get_feature_variation (unsigned int feature_index,
-					       unsigned int variations_index) const
   {
+#ifdef HB_NOVAR
+    return false;
+#endif
+    return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+	    .find_index (coords, num_coords, index);
+  }
+  const Feature& get_feature_variation (unsigned int feature_index,
+					unsigned int variations_index) const
+  {
+#ifndef HB_NO_VAR
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
 	version.to_int () >= 0x00010001u)
     {
@@ -2696,6 +2893,7 @@
       if (feature)
 	return *feature;
     }
+#endif
     return get_feature (feature_index);
   }
 
@@ -2703,21 +2901,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GSUBGPOS *out = c->serializer->embed (*this);
+    auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    out->scriptList.serialize_subset (c, this+scriptList, out);
-    out->featureList.serialize_subset (c, this+featureList, out);
+    out->scriptList.serialize_subset (c, scriptList, this, out);
+    out->featureList.serialize_subset (c, featureList, this, out);
 
     typedef OffsetListOf<TLookup> TLookupList;
     /* TODO Use intersects() to count how many subtables survive? */
-    CastR<OffsetTo<TLookupList> > (out->lookupList)
+    CastR<OffsetTo<TLookupList>> (out->lookupList)
       .serialize_subset (c,
-			 this+CastR<const OffsetTo<TLookupList> > (lookupList),
+			 CastR<OffsetTo<TLookupList>> (lookupList),
+			 this,
 			 out);
 
+#ifndef HB_NO_VAR
     if (version.to_int () >= 0x00010001u)
-     out->featureVars.serialize_subset (c, this+featureVars, out);
+     out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
+#endif
 
     return_trace (true);
   }
@@ -2733,12 +2934,19 @@
   {
     TRACE_SANITIZE (this);
     typedef OffsetListOf<TLookup> TLookupList;
-    return_trace (version.sanitize (c) &&
-		  likely (version.major == 1) &&
-		  scriptList.sanitize (c, this) &&
-		  featureList.sanitize (c, this) &&
-		  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
-		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
+    if (unlikely (!(version.sanitize (c) &&
+		    likely (version.major == 1) &&
+		    scriptList.sanitize (c, this) &&
+		    featureList.sanitize (c, this) &&
+		    CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this))))
+      return_trace (false);
+
+#ifndef HB_NO_VAR
+    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
+      return_trace (false);
+#endif
+
+    return_trace (true);
   }
 
   template <typename T>
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 3beedc4..53eb623 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -136,7 +136,7 @@
  * ExtenderGlyphs -- Extender Glyph Table
  */
 
-typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+typedef SortedArrayOf<HBGlyphID> ExtenderGlyphs;
 
 
 /*
@@ -195,7 +195,7 @@
 
 struct JSTF
 {
-  enum { tableTag = HB_OT_TAG_JSTF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_JSTF;
 
   unsigned int get_script_count () const
   { return scriptList.len; }
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 67ce923..fba3ad1 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -28,6 +28,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_LAYOUT
+
+#ifdef HB_NO_OT_TAG
+#error "Cannot compile hb-ot-layout.cc with HB_NO_OT_TAG."
+#endif
+
 #include "hb-open-type.hh"
 #include "hb-ot-layout.hh"
 #include "hb-ot-face.hh"
@@ -35,7 +43,6 @@
 #include "hb-map.hh"
 
 #include "hb-ot-kern-table.hh"
-#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
@@ -47,6 +54,7 @@
 #include "hb-aat-layout-lcar-table.hh"
 #include "hb-aat-layout-morx-table.hh"
 
+#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
 /**
  * SECTION:hb-ot-layout
@@ -62,18 +70,53 @@
  * kern
  */
 
+#ifndef HB_NO_OT_KERN
+/**
+ * hb_ot_layout_has_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face includes any kerning data in the 'kern' table.
+ * Does NOT test for kerning lookups in the GPOS table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_kerning (hb_face_t *face)
 {
   return face->table.kern->has_data ();
 }
 
+/**
+ * hb_ot_layout_has_machine_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face includes any state-machine kerning in the 'kern' table.
+ * Does NOT examine the GPOS table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_machine_kerning (hb_face_t *face)
 {
   return face->table.kern->has_state_machine ();
 }
 
+/**
+ * hb_ot_layout_has_cross_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face has any cross-stream kerning (i.e., kerns
+ * that make adjustments perpendicular to the direction of the text
+ * flow: Y adjustments in horizontal text or X adjustments in
+ * vertical text) in the 'kern' table.
+ *
+ * Does NOT examine the GPOS table.
+ *
+ * Return value: true is data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_cross_kerning (hb_face_t *face)
 {
@@ -92,6 +135,7 @@
 
   kern.apply (&c);
 }
+#endif
 
 
 /*
@@ -102,6 +146,9 @@
 OT::GDEF::is_blacklisted (hb_blob_t *blob,
 			  hb_face_t *face) const
 {
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
   /* The ugly business of blacklisting individual fonts' tables happen here!
    * See this thread for why we finally had to bend in and do this:
    * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
@@ -119,84 +166,82 @@
    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
    */
-#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z))
-  switch ENCODE(blob->length,
-		face->table.GSUB->table.get_length (),
-		face->table.GPOS->table.get_length ())
+  switch HB_CODEPOINT_ENCODE3(blob->length,
+			      face->table.GSUB->table.get_length (),
+			      face->table.GPOS->table.get_length ())
   {
     /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
-    case ENCODE (442, 2874, 42038):
+    case HB_CODEPOINT_ENCODE3 (442, 2874, 42038):
     /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
-    case ENCODE (430, 2874, 40662):
+    case HB_CODEPOINT_ENCODE3 (430, 2874, 40662):
     /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
-    case ENCODE (442, 2874, 39116):
+    case HB_CODEPOINT_ENCODE3 (442, 2874, 39116):
     /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
-    case ENCODE (430, 2874, 39374):
+    case HB_CODEPOINT_ENCODE3 (430, 2874, 39374):
     /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
-    case ENCODE (490, 3046, 41638):
+    case HB_CODEPOINT_ENCODE3 (490, 3046, 41638):
     /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
-    case ENCODE (478, 3046, 41902):
+    case HB_CODEPOINT_ENCODE3 (478, 3046, 41902):
     /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c  tahoma.ttf from Windows 8 */
-    case ENCODE (898, 12554, 46470):
+    case HB_CODEPOINT_ENCODE3 (898, 12554, 46470):
     /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc  tahomabd.ttf from Windows 8 */
-    case ENCODE (910, 12566, 47732):
+    case HB_CODEPOINT_ENCODE3 (910, 12566, 47732):
     /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e  tahoma.ttf from Windows 8.1 */
-    case ENCODE (928, 23298, 59332):
+    case HB_CODEPOINT_ENCODE3 (928, 23298, 59332):
     /* sha1sum:6d400781948517c3c0441ba42acb309584b73033  tahomabd.ttf from Windows 8.1 */
-    case ENCODE (940, 23310, 60732):
+    case HB_CODEPOINT_ENCODE3 (940, 23310, 60732):
     /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (964, 23836, 60072):
+    case HB_CODEPOINT_ENCODE3 (964, 23836, 60072):
     /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (976, 23832, 61456):
+    case HB_CODEPOINT_ENCODE3 (976, 23832, 61456):
     /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846  tahoma.ttf from Windows 10 */
-    case ENCODE (994, 24474, 60336):
+    case HB_CODEPOINT_ENCODE3 (994, 24474, 60336):
     /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343  tahomabd.ttf from Windows 10 */
-    case ENCODE (1006, 24470, 61740):
+    case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740):
     /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (1006, 24576, 61346):
+    case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346):
     /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (1018, 24572, 62828):
+    case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828):
     /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5  tahoma.ttf from Windows 10 AU */
-    case ENCODE (1006, 24576, 61352):
+    case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352):
     /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2  tahomabd.ttf from Windows 10 AU */
-    case ENCODE (1018, 24572, 62834):
+    case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834):
     /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7  Tahoma.ttf from Mac OS X 10.9 */
-    case ENCODE (832, 7324, 47162):
+    case HB_CODEPOINT_ENCODE3 (832, 7324, 47162):
     /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba  Tahoma Bold.ttf from Mac OS X 10.9 */
-    case ENCODE (844, 7302, 45474):
+    case HB_CODEPOINT_ENCODE3 (844, 7302, 45474):
     /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc  himalaya.ttf from Windows 7 */
-    case ENCODE (180, 13054, 7254):
+    case HB_CODEPOINT_ENCODE3 (180, 13054, 7254):
     /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0  himalaya.ttf from Windows 8 */
-    case ENCODE (192, 12638, 7254):
+    case HB_CODEPOINT_ENCODE3 (192, 12638, 7254):
     /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427  himalaya.ttf from Windows 8.1 */
-    case ENCODE (192, 12690, 7254):
+    case HB_CODEPOINT_ENCODE3 (192, 12690, 7254):
     /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44  cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
     /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371  cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
-    case ENCODE (188, 248, 3852):
+    case HB_CODEPOINT_ENCODE3 (188, 248, 3852):
     /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f  cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
     /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b  cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
-    case ENCODE (188, 264, 3426):
+    case HB_CODEPOINT_ENCODE3 (188, 264, 3426):
     /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
-    case ENCODE (1058, 47032, 11818):
+    case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818):
     /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
-    case ENCODE (1046, 47030, 12600):
+    case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600):
     /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
-    case ENCODE (1058, 71796, 16770):
+    case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770):
     /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
-    case ENCODE (1046, 71790, 17862):
+    case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862):
     /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
-    case ENCODE (1046, 71788, 17112):
+    case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112):
     /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
-    case ENCODE (1058, 71794, 17514):
+    case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514):
     /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
-    case ENCODE (1330, 109904, 57938):
+    case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938):
     /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
-    case ENCODE (1330, 109904, 58972):
+    case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972):
     /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85  Padauk.ttf
      *  "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
-    case ENCODE (1004, 59092, 14836):
+    case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):
       return true;
-#undef ENCODE
   }
   return false;
 }
@@ -219,6 +264,15 @@
 
 /* Public API */
 
+/**
+ * hb_ot_layout_has_glyph_classes:
+ * @face: #hb_face_t to work upon
+ *
+ * Tests whether a face has any glyph classes defined in its GDEF table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face)
 {
@@ -227,6 +281,13 @@
 
 /**
  * hb_ot_layout_get_glyph_class:
+ * @face: The #hb_face_t to work on
+ * @glyph: The #hb_codepoint_t code point to query
+ *
+ * Fetches the GDEF class of the requested glyph in the specified face.
+ *
+ * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code
+ * point in the GDEF table of the face.
  *
  * Since: 0.9.7
  **/
@@ -239,6 +300,13 @@
 
 /**
  * hb_ot_layout_get_glyphs_in_class:
+ * @face: The #hb_face_t to work on
+ * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve
+ * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested
+ *          class.
+ *
+ * Retrieves the set of all glyphs from the face that belong to the requested
+ * glyph class in the face's GDEF table.
  *
  * Since: 0.9.7
  **/
@@ -250,6 +318,23 @@
   return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
 }
 
+
+#ifndef HB_NO_LAYOUT_UNUSED
+/**
+ * hb_ot_layout_get_attach_points:
+ * @face: The #hb_face_t to work on
+ * @glyph: The #hb_codepoint_t code point to query
+ * @start_offset: offset of the first attachment point to retrieve
+ * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
+ *               Output = the actual number of attachment points returned (may be zero)
+ * @point_array: (out) (array length=point_count): The array of attachment points found for the query
+ *
+ * Fetches a list of all attachment points for the specified glyph in the GDEF
+ * table of the face. The list returned will begin at the offset provided.
+ *
+ * Useful if the client program wishes to cache the list.
+ *
+ **/
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
@@ -262,7 +347,20 @@
 						     point_count,
 						     point_array);
 }
-
+/**
+ * hb_ot_layout_get_ligature_carets:
+ * @font: The #hb_font_t to work on
+ * @direction: The #hb_direction_t text direction to use
+ * @glyph: The #hb_codepoint_t code point to query
+ * @start_offset: offset of the first caret position to retrieve
+ * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
+ *               Output = the actual number of caret positions returned (may be zero)
+ * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
+ *
+ * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
+ * table of the font. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
 				  hb_direction_t  direction,
@@ -278,9 +376,16 @@
     if (caret_count) *caret_count = result_caret_count;
   }
   else
+  {
+#ifndef HB_NO_AAT
     result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
+#else
+    if (caret_count) *caret_count = 0;
+#endif
+  }
   return result;
 }
+#endif
 
 
 /*
@@ -291,6 +396,11 @@
 OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face) const
 {
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
+
+#ifndef HB_NO_AAT_SHAPE
   /* Mac OS X prefers morx over GSUB.  It also ships with various Indic fonts,
    * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken
    * GSUB/GPOS tables.  Some have GSUB with zero scripts, those are ignored by
@@ -308,6 +418,7 @@
   if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') &&
 		face->table.morx->has_data ()))
     return true;
+#endif
 
   return false;
 }
@@ -316,6 +427,9 @@
 OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face HB_UNUSED) const
 {
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
   return false;
 }
 
@@ -331,6 +445,19 @@
 }
 
 
+/**
+ * hb_ot_layout_table_get_script_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @start_offset: offset of the first script tag to retrieve
+ * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
+ *                Output = the actual number of script tags returned (may be zero)
+ * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
+ *
+ * Fetches a list of all scripts enumerated in the specified face's GSUB table
+ * or GPOS table. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
 				    hb_tag_t      table_tag,
@@ -345,11 +472,24 @@
 
 #define HB_OT_TAG_LATIN_SCRIPT		HB_TAG ('l', 'a', 't', 'n')
 
+/**
+ * hb_ot_layout_table_find_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_tag: #hb_tag_t of the script tag requested
+ * @script_index: (out): The index of the requested script tag
+ *
+ * Fetches the index if a given script tag in the specified face's GSUB table
+ * or GPOS table.
+ *
+ * Return value: true if the script is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_table_find_script (hb_face_t    *face,
 				hb_tag_t      table_tag,
 				hb_tag_t      script_tag,
-				unsigned int *script_index)
+				unsigned int *script_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -375,20 +515,38 @@
   return false;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_layout_table_choose_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_tags: Array of #hb_tag_t script tags
+ * @script_index: (out): The index of the requested script tag
+ * @chosen_script: (out): #hb_tag_t of the script tag requested
+ *
+ * Deprecated since 2.0.0
+ **/
 hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
 				  hb_tag_t        table_tag,
 				  const hb_tag_t *script_tags,
-				  unsigned int   *script_index,
-				  hb_tag_t       *chosen_script)
+				  unsigned int   *script_index  /* OUT */,
+				  hb_tag_t       *chosen_script /* OUT */)
 {
   const hb_tag_t *t;
   for (t = script_tags; *t; t++);
   return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
 }
+#endif
 
 /**
  * hb_ot_layout_table_select_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_count: Number of script tags in the array
+ * @script_tags: Array of #hb_tag_t script tags
+ * @script_index: (out): The index of the requested script
+ * @chosen_script: (out): #hb_tag_t of the requested script
  *
  * Since: 2.0.0
  **/
@@ -409,7 +567,7 @@
     if (g.find_script_index (script_tags[i], script_index))
     {
       if (chosen_script)
-        *chosen_script = script_tags[i];
+	*chosen_script = script_tags[i];
       return true;
     }
   }
@@ -442,6 +600,19 @@
   return false;
 }
 
+
+/**
+ * hb_ot_layout_table_get_feature_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output = the actual number of feature tags returned (may be zero)
+ * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
+ *
+ * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+ *
+ **/
 unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
 				     hb_tag_t      table_tag,
@@ -454,11 +625,24 @@
   return g.get_feature_tags (start_offset, feature_count, feature_tags);
 }
 
+
+/**
+ * hb_ot_layout_table_find_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_tag: The #hb_tag_t og the requested feature tag
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index for a given feature tag in the specified face's GSUB table
+ * or GPOS table.
+ *
+ * Return value: true if the feature is found, false otherwise
+ **/
 bool
 hb_ot_layout_table_find_feature (hb_face_t    *face,
 				 hb_tag_t      table_tag,
 				 hb_tag_t      feature_tag,
-				 unsigned int *feature_index)
+				 unsigned int *feature_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -477,6 +661,20 @@
 }
 
 
+/**
+ * hb_ot_layout_script_get_language_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @start_offset: offset of the first language tag to retrieve
+ * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
+ *                  Output = the actual number of language tags returned (may be zero)
+ * @language_tags: (out) (array length=language_count): Array of language tags found in the table
+ *
+ * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
+ * the specified script index. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
 				       hb_tag_t      table_tag,
@@ -490,6 +688,24 @@
   return s.get_lang_sys_tags (start_offset, language_count, language_tags);
 }
 
+
+#ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_layout_script_find_language:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_tag: The #hb_tag_t of the requested language
+ * @language_index: The index of the requested language
+ *
+ * Fetches the index of a given language tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script tag.
+ *
+ * Return value: true if the language tag is found, false otherwise
+ *
+ * Since: ??
+ * Deprecated: ??
+ **/
 hb_bool_t
 hb_ot_layout_script_find_language (hb_face_t    *face,
 				   hb_tag_t      table_tag,
@@ -504,9 +720,22 @@
 					      &language_tag,
 					      language_index);
 }
+#endif
+
 
 /**
  * hb_ot_layout_script_select_language:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_count: The number of languages in the specified script
+ * @language_tags: The array of language tags
+ * @language_index: (out): The index of the requested language
+ *
+ * Fetches the index of a given language tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script index.
+ *
+ * Return value: true if the language tag is found, false otherwise
  *
  * Since: 2.0.0
  **/
@@ -536,6 +765,21 @@
   return false;
 }
 
+
+/**
+ * hb_ot_layout_language_get_required_feature_index:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
+ * underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
 						  hb_tag_t      table_tag,
@@ -551,8 +795,20 @@
 						     nullptr);
 }
 
+
 /**
  * hb_ot_layout_language_get_required_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_index: The index of the requested feature
+ * @feature_tag: (out): The #hb_tag_t of the requested feature
+ *
+ * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
+ * underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
  *
  * Since: 0.9.30
  **/
@@ -574,6 +830,22 @@
   return l.has_required_feature ();
 }
 
+
+/**
+ * hb_ot_layout_language_get_feature_indexes:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output: the actual number of feature tags returned (may be zero)
+ * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
+ *
+ * Fetches a list of all features in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language. The list
+ * returned will begin at the offset provided.
+ **/
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
 					   hb_tag_t      table_tag,
@@ -589,6 +861,23 @@
   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
 }
 
+
+/**
+ * hb_ot_layout_language_get_feature_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output = the actual number of feature tags returned (may be zero)
+ * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
+ *
+ * Fetches a list of all features in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language. The list
+ * returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
 					hb_tag_t      table_tag,
@@ -614,13 +903,28 @@
 }
 
 
+/**
+ * hb_ot_layout_language_find_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_tag: #hb_tag_t of the feature tag requested
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index of a given feature tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_language_find_feature (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  script_index,
 				    unsigned int  language_index,
 				    hb_tag_t      feature_tag,
-				    unsigned int *feature_index)
+				    unsigned int *feature_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -640,8 +944,20 @@
   return false;
 }
 
+
 /**
  * hb_ot_layout_feature_get_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_index: The index of the requested feature
+ * @start_offset: offset of the first lookup to retrieve
+ * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ *                Output = the actual number of lookups returned (may be zero)
+ * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
+ *
+ * Fetches a list of all lookups enumerated for the specified feature, in
+ * the specified face's GSUB table or GPOS table. The list returned will
+ * begin at the offset provided.
  *
  * Since: 0.9.7
  **/
@@ -662,8 +978,14 @@
 							   lookup_indexes);
 }
 
+
 /**
  * hb_ot_layout_table_get_lookup_count:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ *
+ * Fetches the total number of lookups enumerated in the specified
+ * face's GSUB table or GPOS table.
  *
  * Since: 0.9.22
  **/
@@ -677,14 +999,14 @@
 
 struct hb_collect_features_context_t
 {
-  hb_collect_features_context_t (hb_face_t       *face,
-				 hb_tag_t         table_tag,
-				 hb_set_t        *feature_indexes_)
+  hb_collect_features_context_t (hb_face_t *face,
+				 hb_tag_t   table_tag,
+				 hb_set_t  *feature_indexes_)
     : g (get_gsubgpos_table (face, table_tag)),
       feature_indexes (feature_indexes_),
       script_count(0),langsys_count(0) {}
 
-  bool inline visited (const OT::Script &s)
+  bool visited (const OT::Script &s)
   {
     /* We might have Null() object here.  Don't want to involve
      * that in the memoize.  So, detect empty objects and return. */
@@ -697,7 +1019,7 @@
 
     return visited (s, visited_script);
   }
-  bool inline visited (const OT::LangSys &l)
+  bool visited (const OT::LangSys &l)
   {
     /* We might have Null() object here.  Don't want to involve
      * that in the memoize.  So, detect empty objects and return. */
@@ -713,7 +1035,7 @@
 
   private:
   template <typename T>
-  bool inline visited (const T &p, hb_set_t &visited_set)
+  bool visited (const T &p, hb_set_t &visited_set)
   {
     hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) &p - (uintptr_t) &g);
      if (visited_set.has (delta))
@@ -805,18 +1127,31 @@
   }
 }
 
+
 /**
  * hb_ot_layout_collect_features:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @scripts: The array of scripts to collect features for
+ * @languages: The array of languages to collect features for
+ * @features: The array of features to collect
+ * @feature_indexes: (out): The array of feature indexes found for the query
+ *
+ * Fetches a list of all feature indexes in the specified face's GSUB table
+ * or GPOS table, underneath the specified scripts, languages, and features.
+ * If no list of scripts is provided, all scripts will be queried. If no list
+ * of languages is provided, all languages will be queried. If no list of
+ * features is provided, all features will be queried.
  *
  * Since: 1.8.5
  **/
 void
 hb_ot_layout_collect_features (hb_face_t      *face,
-                               hb_tag_t        table_tag,
-                               const hb_tag_t *scripts,
-                               const hb_tag_t *languages,
-                               const hb_tag_t *features,
-                               hb_set_t       *feature_indexes /* OUT */)
+			       hb_tag_t        table_tag,
+			       const hb_tag_t *scripts,
+			       const hb_tag_t *languages,
+			       const hb_tag_t *features,
+			       hb_set_t       *feature_indexes /* OUT */)
 {
   hb_collect_features_context_t c (face, table_tag, feature_indexes);
   if (!scripts)
@@ -843,8 +1178,21 @@
   }
 }
 
+
 /**
  * hb_ot_layout_collect_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @scripts: The array of scripts to collect lookups for
+ * @languages: The array of languages to collect lookups for
+ * @features: The array of features to collect lookups for
+ * @lookup_indexes: (out): The array of lookup indexes found for the query
+ *
+ * Fetches a list of all feature-lookup indexes in the specified face's GSUB
+ * table or GPOS table, underneath the specified scripts, languages, and
+ * features. If no list of scripts is provided, all scripts will be queried.
+ * If no list of languages is provided, all languages will be queried. If no
+ * list of features is provided, all features will be queried.
  *
  * Since: 0.9.8
  **/
@@ -866,8 +1214,20 @@
     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
 }
 
+
+#ifndef HB_NO_LAYOUT_COLLECT_GLYPHS
 /**
  * hb_ot_layout_lookup_collect_glyphs:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @lookup_index: The index of the feature lookup to query
+ * @glyphs_before: (out): Array of glyphs preceding the substitution range
+ * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
+ * @glyphs_after: (out): Array of glyphs following the substition range
+ * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup
+ *
+ * Fetches a list of all glyphs affected by the specified lookup in the
+ * specified face's GSUB table or GPOS table.
  *
  * Since: 0.9.7
  **/
@@ -902,10 +1262,24 @@
     }
   }
 }
+#endif
 
 
 /* Variations support */
 
+
+/**
+ * hb_ot_layout_table_find_feature_variations:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @coords: The variation coordinates to query
+ * @num_coords: The number of variation coorinates
+ * @variations_index: (out): The array of feature variations found for the query
+ *
+ * Fetches a list of feature variations in the specified face's GSUB table
+ * or GPOS table, at the specified variation coordinates.
+ *
+ **/
 hb_bool_t
 hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
 					    hb_tag_t      table_tag,
@@ -918,6 +1292,23 @@
   return g.find_variations_index (coords, num_coords, variations_index);
 }
 
+
+/**
+ * hb_ot_layout_feature_with_variations_get_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_index: The index of the feature to query
+ * @variations_index: The index of the feature variation to query
+ * @start_offset: offset of the first lookup to retrieve
+ * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ *                Output = the actual number of lookups returned (may be zero)
+ * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
+ *
+ * Fetches a list of all lookups enumerated for the specified feature, in
+ * the specified face's GSUB table or GPOS table, enabled at the specified
+ * variations index. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
 						  hb_tag_t      table_tag,
@@ -940,14 +1331,35 @@
  * OT::GSUB
  */
 
+
+/**
+ * hb_ot_layout_has_substitution:
+ * @face: #hb_face_t to work upon
+ *
+ * Tests whether the specified face includes any GSUB substitutions.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
   return face->table.GSUB->table->has_data ();
 }
 
+
 /**
  * hb_ot_layout_lookup_would_substitute:
+ * @face: #hb_face_t to work upon
+ * @lookup_index: The index of the lookup to query
+ * @glyphs: The sequence of glyphs to query for substitution
+ * @glyphs_length: The length of the glyph sequence
+ * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
+ *
+ * Tests whether a specified lookup in the specified face would
+ * trigger a substitution on the given glyph sequence.
+ *
+ * Return value: true if a substitution would be triggered, false otherwise
  *
  * Since: 0.9.7
  **/
@@ -958,19 +1370,6 @@
 				      unsigned int          glyphs_length,
 				      hb_bool_t             zero_context)
 {
-  return hb_ot_layout_lookup_would_substitute_fast (face,
-						    lookup_index,
-						    glyphs, glyphs_length,
-						    zero_context);
-}
-
-bool
-hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
-					   unsigned int          lookup_index,
-					   const hb_codepoint_t *glyphs,
-					   unsigned int          glyphs_length,
-					   bool                  zero_context)
-{
   if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
 
@@ -979,6 +1378,16 @@
   return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
 }
 
+
+/**
+ * hb_ot_layout_substitute_start:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called before substitution lookups are performed, to ensure that glyph
+ * class and other properties are set on the glyphs in the buffer.
+ *
+ **/
 void
 hb_ot_layout_substitute_start (hb_font_t    *font,
 			       hb_buffer_t  *buffer)
@@ -1038,13 +1447,19 @@
 
 /**
  * hb_ot_layout_lookup_substitute_closure:
+ * @face: #hb_face_t to work upon
+ * @lookup_index: index of the feature lookup to query
+ * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup
+ *
+ * Compute the transitive closure of glyphs needed for a
+ * specified lookup.
  *
  * Since: 0.9.7
  **/
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
-				        hb_set_t     *glyphs)
+				        hb_set_t     *glyphs /* OUT */)
 {
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
@@ -1056,6 +1471,9 @@
 
 /**
  * hb_ot_layout_lookups_substitute_closure:
+ * @face: #hb_face_t to work upon
+ * @lookups: The set of lookups to query
+ * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups
  *
  * Compute the transitive closure of glyphs needed for all of the
  * provided lookups.
@@ -1064,8 +1482,8 @@
  **/
 void
 hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
-                                         const hb_set_t *lookups,
-                                         hb_set_t       *glyphs)
+					 const hb_set_t *lookups,
+					 hb_set_t       *glyphs /* OUT */)
 {
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
@@ -1079,12 +1497,12 @@
     if (lookups != nullptr)
     {
       for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
-        gsub.get_lookup (lookup_index).closure (&c, lookup_index);
+	gsub.get_lookup (lookup_index).closure (&c, lookup_index);
     }
     else
     {
       for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)
-        gsub.get_lookup (i).closure (&c, i);
+	gsub.get_lookup (i).closure (&c, i);
     }
   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
 	   glyphs_length != glyphs->get_population ());
@@ -1094,32 +1512,85 @@
  * OT::GPOS
  */
 
+
+/**
+ * hb_ot_layout_has_positioning:
+ * @face: #hb_face_t to work upon
+ *
+ * Return value: true if the face has GPOS data, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face)
 {
   return face->table.GPOS->table->has_data ();
 }
 
+/**
+ * hb_ot_layout_position_start:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called before positioning lookups are performed, to ensure that glyph
+ * attachment types and glyph-attachment chains are set for the glyphs in the buffer.
+ *
+ **/
 void
 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_start (font, buffer);
 }
 
+
+/**
+ * hb_ot_layout_position_finish_advances:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called after positioning lookups are performed, to finish glyph advances.
+ *
+ **/
 void
 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_finish_advances (font, buffer);
 }
 
+/**
+ * hb_ot_layout_position_finish_offsets:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called after positioning lookups are performed, to finish glyph offsets.
+ *
+ **/
 void
 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_finish_offsets (font, buffer);
 }
 
+
+#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
 /**
  * hb_ot_layout_get_size_params:
+ * @face: #hb_face_t to work upon
+ * @design_size: (out): The design size of the face
+ * @subfamily_id: (out): The identifier of the face within the font subfamily
+ * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily
+ * @range_start: (out): The minimum size of the recommended size range for the face
+ * @range_end: (out): The maximum size of the recommended size range for the face
+ *
+ * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that
+ * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id)
+ * as used here are defined as pertaining only to fonts within a font family that differ
+ * specifically in their respective size ranges; other ways to differentiate fonts within
+ * a subfamily are not covered by the `size` feature.
+ *
+ * For more information on this distinction, see the `size` documentation at
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-39size39
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 0.9.10
  **/
@@ -1163,7 +1634,6 @@
 
   return false;
 }
-
 /**
  * hb_ot_layout_feature_get_name_ids:
  * @face: #hb_face_t to work upon
@@ -1238,24 +1708,26 @@
   if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
   return false;
 }
-
 /**
  * hb_ot_layout_feature_get_characters:
  * @face: #hb_face_t to work upon
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
- * @start_offset: In case the resulting char_count was equal to its input value, there
- *                is a chance there were more characters on the tag so this API can be
- *                called with an offset till resulting char_count gets to a number
- *                lower than input buffer (or consider using just a bigger buffer for
- *                one shot copying).
- * @char_count: (inout) (allow-none): The count of characters for which this feature
- *              provides glyph variants. (May be zero.)
- * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. The Unicode codepoints
- *              of the characters for which this feature provides glyph variants.
+ * @start_offset: offset of the first character to retrieve
+ * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
+ *              Output = the actual number of characters returned (may be zero)
+ * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
+ *              The Unicode codepoints of the characters for which this feature provides
+ *               glyph variants.
  *
- * Fetches characters listed by designer under feature parameters for "Character
- * Variant" ("cvXX") features.
+ * Fetches a list of the characters defined as having a variant under the specified
+ * "Character Variant" ("cvXX") feature tag.
+ *
+ * <note>Note: If the char_count output value is equal to its input value, then there
+ *       is a chance there were more characters defined under the feature tag than were
+ *       returned. This function can be called with incrementally larger start_offset
+ *       until the char_count output value is lower than its input value, or the size
+ *       of the characters array can be increased.</note>
  *
  * Return value: Number of total sample characters in the cvXX feature.
  *
@@ -1282,13 +1754,14 @@
   unsigned int len = 0;
   if (char_count && characters && start_offset < cv_params.characters.len)
   {
-    len = MIN (cv_params.characters.len - start_offset, *char_count);
+    len = hb_min (cv_params.characters.len - start_offset, *char_count);
     for (unsigned int i = 0; i < len; ++i)
       characters[i] = cv_params.characters[start_offset + i];
   }
   if (char_count) *char_count = len;
   return cv_params.characters.len;
 }
+#endif
 
 
 /*
@@ -1299,8 +1772,8 @@
 
 struct GSUBProxy
 {
-  enum { table_index = 0 };
-  enum { inplace = false };
+  static constexpr unsigned table_index = 0u;
+  static constexpr bool inplace = false;
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
@@ -1313,8 +1786,8 @@
 
 struct GPOSProxy
 {
-  enum { table_index = 1 };
-  enum { inplace = true };
+  static constexpr unsigned table_index = 1u;
+  static constexpr bool inplace = true;
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
@@ -1387,7 +1860,7 @@
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->clear_output ();
     buffer->idx = 0;
 
@@ -1404,7 +1877,7 @@
   else
   {
     /* in-place backward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->remove_output ();
     buffer->idx = buffer->len - 1;
 
@@ -1423,7 +1896,7 @@
   OT::hb_ot_apply_context_t c (table_index, font, buffer);
   c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
 
-  for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
     const stage_map_t *stage = &stages[table_index][stage_index];
     for (; i < stage->last_lookup; i++)
     {
@@ -1472,60 +1945,36 @@
   apply_string<GSUBProxy> (c, lookup, accel);
 }
 
-#if 0
-static const OT::BASE& _get_base (hb_face_t *face)
-{
-  return *face->table.BASE;
-}
-
+#ifndef HB_NO_BASE
+/**
+ * hb_ot_layout_get_baseline:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script_tag:  script tag.
+ * @language_tag: language tag.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face.
+ *
+ * Return value: if found baseline value in the the font.
+ *
+ * Since: 2.6.0
+ **/
 hb_bool_t
-hb_ot_layout_get_baseline (hb_font_t               *font,
-			   hb_ot_layout_baseline_t  baseline,
-			   hb_direction_t           direction,
-			   hb_tag_t                 script_tag,
-			   hb_tag_t                 language_tag,
-			   hb_position_t           *coord        /* OUT.  May be NULL. */)
+hb_ot_layout_get_baseline (hb_font_t                   *font,
+			   hb_ot_layout_baseline_tag_t  baseline_tag,
+			   hb_direction_t               direction,
+			   hb_tag_t                     script_tag,
+			   hb_tag_t                     language_tag,
+			   hb_position_t               *coord        /* OUT.  May be NULL. */)
 {
-  const OT::BASE &base = _get_base (font->face);
-  bool result = base.get_baseline (font, baseline, direction, script_tag,
-				   language_tag, coord);
+  bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
 
-  /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */
-  if (!result && coord) *coord = 0;
-
-  if (coord) *coord = font->em_scale_dir (*coord, direction);
+  if (result && coord)
+    *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord);
 
   return result;
 }
-
-/* To be moved to public header */
-/*
- * BASE
- */
-
-/**
- * hb_ot_layout_baseline_t:
- *
- * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
- *
- * Since: DONTREPLACEME
- */
-typedef enum {
-  HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'),
-  HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'),
-  HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'),
-  HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'),
-  HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'),
-  HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'),
-  HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n')
-} hb_ot_layout_baseline_t;
-
-HB_EXTERN hb_bool_t
-hb_ot_layout_get_baseline (hb_font_t               *font,
-			   hb_ot_layout_baseline_t  baseline,
-			   hb_direction_t           direction,
-			   hb_tag_t                 script_tag,
-			   hb_tag_t                 language_tag,
-			   hb_position_t           *coord        /* OUT.  May be NULL. */);
-
+#endif
 #endif
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index e473954..7e8a897 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -93,6 +93,17 @@
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
+/**
+ * hb_ot_layout_glyph_class_t:
+ * @HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: Glyphs not matching the other classifications
+ * @HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: Spacing, single characters, capable of accepting marks
+ * @HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: Glyphs that represent ligation of multiple characters
+ * @HB_OT_LAYOUT_GLYPH_CLASS_MARK: Non-spacing, combining glyphs that represent marks
+ * @HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: Spacing glyphs that represent part of a single character
+ *
+ * The GDEF classes defined for glyphs.
+ *
+ **/
 typedef enum {
   HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0,
   HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 1,
@@ -238,11 +249,11 @@
 
 HB_EXTERN void
 hb_ot_layout_collect_features (hb_face_t      *face,
-                               hb_tag_t        table_tag,
-                               const hb_tag_t *scripts,
-                               const hb_tag_t *languages,
-                               const hb_tag_t *features,
-                               hb_set_t       *feature_indexes /* OUT */);
+			       hb_tag_t        table_tag,
+			       const hb_tag_t *scripts,
+			       const hb_tag_t *languages,
+			       const hb_tag_t *features,
+			       hb_set_t       *feature_indexes /* OUT */);
 
 HB_EXTERN void
 hb_ot_layout_collect_lookups (hb_face_t      *face,
@@ -322,14 +333,14 @@
 
 HB_EXTERN void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
-				        unsigned int  lookup_index,
-				        hb_set_t     *glyphs
+					unsigned int  lookup_index,
+					hb_set_t     *glyphs
 					/*TODO , hb_bool_t  inclusive */);
 
 HB_EXTERN void
 hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
-                                         const hb_set_t *lookups,
-                                         hb_set_t       *glyphs);
+					 const hb_set_t *lookups,
+					 hb_set_t       *glyphs);
 
 
 #ifdef HB_NOT_IMPLEMENTED
@@ -391,6 +402,55 @@
 				     unsigned int   *char_count    /* IN/OUT.  May be NULL */,
 				     hb_codepoint_t *characters    /* OUT.     May be NULL */);
 
+/*
+ * BASE
+ */
+
+/**
+ * hb_ot_layout_baseline_tag_t:
+ * @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek.
+ * In vertical writing mode, the alphabetic baseline for characters rotated 90 degrees clockwise.
+ * (This would not apply to alphabetic characters that remain upright in vertical writing mode, since these
+ * characters are not rotated.)
+ * @HB_OT_LAYOUT_BASELINE_TAG_HANGING: The hanging baseline. In horizontal direction, this is the horizontal
+ * line from which syllables seem, to hang in Tibetan and other similar scripts. In vertical writing mode,
+ * for Tibetan (or some other similar script) characters rotated 90 degrees clockwise.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: Ideographic character face bottom or left edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
+ * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
+ *
+ * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ *
+ * Since: 2.6.0
+ */
+typedef enum {
+  HB_OT_LAYOUT_BASELINE_TAG_ROMAN			= HB_TAG ('r','o','m','n'),
+  HB_OT_LAYOUT_BASELINE_TAG_HANGING			= HB_TAG ('h','a','n','g'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT	= HB_TAG ('i','c','f','b'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT	= HB_TAG ('i','c','f','t'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT	= HB_TAG ('i','d','e','o'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT	= HB_TAG ('i','d','t','p'),
+  HB_OT_LAYOUT_BASELINE_TAG_MATH			= HB_TAG ('m','a','t','h'),
+
+  _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_layout_baseline_tag_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_baseline (hb_font_t                   *font,
+			   hb_ot_layout_baseline_tag_t  baseline_tag,
+			   hb_direction_t               direction,
+			   hb_tag_t                     script_tag,
+			   hb_tag_t                     language_tag,
+			   hb_position_t               *coord        /* OUT.  May be NULL. */);
+
+
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh
index a00b940..f3bb155 100644
--- a/src/hb-ot-layout.hh
+++ b/src/hb-ot-layout.hh
@@ -96,13 +96,6 @@
  * GSUB/GPOS
  */
 
-HB_INTERNAL bool
-hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
-					   unsigned int          lookup_index,
-					   const hb_codepoint_t *glyphs,
-					   unsigned int          glyphs_length,
-					   bool                  zero_context);
-
 
 /* Should be called before all the substitute_lookup's are done. */
 HB_INTERNAL void
@@ -175,6 +168,17 @@
   return start;
 }
 
+static inline void
+_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		     hb_font_t *font HB_UNUSED,
+		     hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+}
+
 
 /* unicode_props */
 
@@ -215,7 +219,7 @@
   unsigned int gen_cat = (unsigned int) unicode->general_category (u);
   unsigned int props = gen_cat;
 
-  if (u >= 0x80)
+  if (u >= 0x80u)
   {
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
 
@@ -232,10 +236,10 @@
        * FVSes are GC=Mn, we have use a separate bit to remember them.
        * Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/234 */
-      else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
       /* TAG characters need similar treatment. Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/463 */
-      else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
       /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
        * https://github.com/harfbuzz/harfbuzz/issues/554 */
       else if (unlikely (u == 0x034Fu))
@@ -558,6 +562,17 @@
   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 }
 
+static inline void
+_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			      hb_font_t *font HB_UNUSED,
+			      hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    _hb_glyph_info_clear_substituted (&info[i]);
+}
+
 
 /* Allocation / deallocation. */
 
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 884202c..e4bb4b6 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -26,6 +26,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-map.hh"
 #include "hb-ot-shape.hh"
 #include "hb-ot-layout.hh"
@@ -33,8 +37,8 @@
 
 void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
-  for (unsigned int i = 0; i < lookups[table_index].len; i++)
-    hb_set_add (lookups_out, lookups[table_index][i].index);
+  for (unsigned int i = 0; i < lookups[table_index].length; i++)
+    lookups_out->add (lookups[table_index][i].index);
 }
 
 
@@ -82,7 +86,7 @@
   if (unlikely (!tag)) return;
   feature_info_t *info = feature_infos.push();
   info->tag = tag;
-  info->seq = feature_infos.len;
+  info->seq = feature_infos.length;
   info->max_value = value;
   info->flags = flags;
   info->default_value = (flags & F_GLOBAL) ? value : 0;
@@ -174,11 +178,11 @@
   }
 
   /* Sort features and merge duplicates */
-  if (feature_infos.len)
+  if (feature_infos.length)
   {
     feature_infos.qsort ();
     unsigned int j = 0;
-    for (unsigned int i = 1; i < feature_infos.len; i++)
+    for (unsigned int i = 1; i < feature_infos.length; i++)
       if (feature_infos[i].tag != feature_infos[j].tag)
 	feature_infos[++j] = feature_infos[i];
       else {
@@ -187,13 +191,14 @@
 	  feature_infos[j].max_value = feature_infos[i].max_value;
 	  feature_infos[j].default_value = feature_infos[i].default_value;
 	} else {
-	  feature_infos[j].flags &= ~F_GLOBAL;
-	  feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+	  if (feature_infos[j].flags & F_GLOBAL)
+	    feature_infos[j].flags ^= F_GLOBAL;
+	  feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value);
 	  /* Inherit default_value from j */
 	}
 	feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
-	feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
-	feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+	feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]);
+	feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]);
       }
     feature_infos.shrink (j + 1);
   }
@@ -202,7 +207,7 @@
   /* Allocate bits now */
   unsigned int next_bit = global_bit_shift + 1;
 
-  for (unsigned int i = 0; i < feature_infos.len; i++)
+  for (unsigned int i = 0; i < feature_infos.length; i++)
   {
     const feature_info_t *info = &feature_infos[i];
 
@@ -213,34 +218,34 @@
       bits_needed = 0;
     else
       /* Limit bits per feature. */
-      bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
+      bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
 
     if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
       continue; /* Feature disabled, or not enough bits. */
 
 
-    hb_bool_t found = false;
+    bool found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
     {
       if (required_feature_tag[table_index] == info->tag)
 	required_feature_stage[table_index] = info->stage[table_index];
 
-      found |= hb_ot_layout_language_find_feature (face,
-						   table_tags[table_index],
-						   script_index[table_index],
-						   language_index[table_index],
-						   info->tag,
-						   &feature_index[table_index]);
+      found |= (bool) hb_ot_layout_language_find_feature (face,
+							  table_tags[table_index],
+							  script_index[table_index],
+							  language_index[table_index],
+							  info->tag,
+							  &feature_index[table_index]);
     }
     if (!found && (info->flags & F_GLOBAL_SEARCH))
     {
       for (unsigned int table_index = 0; table_index < 2; table_index++)
       {
-	found |= hb_ot_layout_table_find_feature (face,
-						  table_tags[table_index],
-						  info->tag,
-						  &feature_index[table_index]);
+	found |= (bool) hb_ot_layout_table_find_feature (face,
+							 table_tags[table_index],
+							 info->tag,
+							 &feature_index[table_index]);
       }
     }
     if (!found && !(info->flags & F_HAS_FALLBACK))
@@ -292,8 +297,8 @@
 		     key.variations_index[table_index],
 		     global_bit_mask);
 
-      for (unsigned i = 0; i < m.features.len; i++)
-        if (m.features[i].stage[table_index] == stage)
+      for (unsigned i = 0; i < m.features.length; i++)
+	if (m.features[i].stage[table_index] == stage)
 	  add_lookups (m, table_index,
 		       m.features[i].index[table_index],
 		       key.variations_index[table_index],
@@ -303,12 +308,12 @@
 		       m.features[i].random);
 
       /* Sort lookups and merge duplicates */
-      if (last_num_lookups < m.lookups[table_index].len)
+      if (last_num_lookups < m.lookups[table_index].length)
       {
-	m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
+	m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].length);
 
 	unsigned int j = last_num_lookups;
-	for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
+	for (unsigned int i = j + 1; i < m.lookups[table_index].length; i++)
 	  if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
 	    m.lookups[table_index][++j] = m.lookups[table_index][i];
 	  else
@@ -320,9 +325,9 @@
 	m.lookups[table_index].shrink (j + 1);
       }
 
-      last_num_lookups = m.lookups[table_index].len;
+      last_num_lookups = m.lookups[table_index].length;
 
-      if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
+      if (stage_index < stages[table_index].length && stages[table_index][stage_index].index == stage) {
 	hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
 	stage_map->last_lookup = last_num_lookups;
 	stage_map->pause_func = stages[table_index][stage_index].pause_func;
@@ -332,3 +337,6 @@
     }
   }
 }
+
+
+#endif
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 35e9493..0a4827d 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -68,7 +68,7 @@
     unsigned short random : 1;
     hb_mask_t mask;
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const lookup_map_t *a = (const lookup_map_t *) pa;
       const lookup_map_t *b = (const lookup_map_t *) pb;
@@ -145,17 +145,17 @@
       *lookup_count = 0;
       return;
     }
-    assert (stage <= stages[table_index].len);
+    assert (stage <= stages[table_index].length);
     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
-    unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
+    unsigned int end   = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
     *plookups = end == start ? nullptr : &lookups[table_index][start];
     *lookup_count = end - start;
   }
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
   template <typename Proxy>
-  HB_INTERNAL inline void apply (const Proxy &proxy,
-				 const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void apply (const Proxy &proxy,
+			  const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 
@@ -167,9 +167,9 @@
 
   hb_mask_t global_mask;
 
-  hb_vector_t<feature_map_t, 8> features;
-  hb_vector_t<lookup_map_t, 16> lookups[2]; /* GSUB/GPOS */
-  hb_vector_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
+  hb_sorted_vector_t<feature_map_t> features;
+  hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
+  hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */
 };
 
 enum hb_ot_map_feature_flags_t
@@ -247,7 +247,7 @@
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const feature_info_t *a = (const feature_info_t *) pa;
       const feature_info_t *b = (const feature_info_t *) pb;
@@ -275,8 +275,8 @@
   private:
 
   unsigned int current_stage[2]; /* GSUB/GPOS */
-  hb_vector_t<feature_info_t, 32> feature_infos;
-  hb_vector_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
+  hb_vector_t<feature_info_t> feature_infos;
+  hb_vector_t<stage_info_t> stages[2]; /* GSUB/GPOS */
 };
 
 
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index 120ab06..7529e0c 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -423,7 +423,7 @@
   }
 
   protected:
-  GlyphID variantGlyph;       /* Glyph ID for the variant. */
+  HBGlyphID variantGlyph;       /* Glyph ID for the variant. */
   HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
 				 * variant, in the direction of requested
 				 * glyph extension. */
@@ -453,16 +453,16 @@
   }
 
   void extract (hb_ot_math_glyph_part_t &out,
-		int scale,
+		int64_t mult,
 		hb_font_t *font) const
   {
     out.glyph			= glyph;
 
-    out.start_connector_length	= font->em_scale (startConnectorLength, scale);
-    out.end_connector_length	= font->em_scale (endConnectorLength, scale);
-    out.full_advance		= font->em_scale (fullAdvance, scale);
+    out.start_connector_length	= font->em_mult (startConnectorLength, mult);
+    out.end_connector_length	= font->em_mult (endConnectorLength, mult);
+    out.full_advance		= font->em_mult (fullAdvance, mult);
 
-    static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+    static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
 		   (unsigned int) PartFlags::Extender, "");
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
@@ -471,7 +471,7 @@
   }
 
   protected:
-  GlyphID   glyph;		  /* Glyph ID for the part. */
+  HBGlyphID   glyph;		  /* Glyph ID for the part. */
   HBUINT16    startConnectorLength; /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the beginning of the glyph, in the
@@ -508,11 +508,11 @@
   {
     if (parts_count)
     {
-      int scale = font->dir_scale (direction);
+      int64_t mult = font->dir_mult (direction);
       hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count);
-      unsigned int count = arr.len;
+      unsigned int count = arr.length;
       for (unsigned int i = 0; i < count; i++)
-	arr[i].extract (parts[i], scale, font);
+	arr[i].extract (parts[i], mult, font);
     }
 
     if (italics_correction)
@@ -553,13 +553,13 @@
   {
     if (variants_count)
     {
-      int scale = font->dir_scale (direction);
+      int64_t mult = font->dir_mult (direction);
       hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count);
-      unsigned int count = arr.len;
+      unsigned int count = arr.length;
       for (unsigned int i = 0; i < count; i++)
       {
 	variants[i].glyph = arr[i].variantGlyph;
-	variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
+	variants[i].advance = font->em_mult (arr[i].advanceMeasurement, mult);
       }
     }
     return mathGlyphVariantRecord.len;
@@ -664,7 +664,7 @@
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
-  UnsizedArrayOf<OffsetTo<MathGlyphConstruction> >
+  UnsizedArrayOf<OffsetTo<MathGlyphConstruction>>
  			glyphConstruction;
 
   public:
@@ -679,7 +679,7 @@
 
 struct MATH
 {
-  enum { tableTag = HB_OT_TAG_MATH };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index bd31bf5..9d8c6e7 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -24,9 +24,10 @@
  * Igalia Author(s): Frédéric Wang
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
+#ifndef HB_NO_MATH
+
 #include "hb-ot-math-table.hh"
 
 
@@ -37,6 +38,11 @@
  * @include: hb-ot.h
  *
  * Functions for fetching mathematics layout data from OpenType fonts.
+ *
+ * HarfBuzz itself does not implement a math layout solution. The
+ * functions and types provided can be used by client programs to access
+ * the font data necessary for typesetting OpenType Math layout.
+ *
  **/
 
 
@@ -48,10 +54,9 @@
  * hb_ot_math_has_data:
  * @face: #hb_face_t to test
  *
- * This function allows to verify the presence of an OpenType MATH table on the
- * face.
+ * Tests whether a face has a `MATH` table.
  *
- * Return value: true if face has a MATH table, false otherwise
+ * Return value: true if the table is found, false otherwise
  *
  * Since: 1.3.3
  **/
@@ -63,16 +68,18 @@
 
 /**
  * hb_ot_math_get_constant:
- * @font: #hb_font_t from which to retrieve the value
+ * @font: #hb_font_t to work upon
  * @constant: #hb_ot_math_constant_t the constant to retrieve
  *
- * This function returns the requested math constants as a #hb_position_t.
- * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
- * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
- * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
- * actually an integer between 0 and 100 representing that percentage.
+ * Fetches the specified math constant. For most constants, the value returned
+ * is an #hb_position_t.
  *
- * Return value: the requested constant or 0
+ * However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
+ * #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
+ * #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is
+ * an integer between 0 and 100 representing that percentage.
+ *
+ * Return value: the requested constant or zero
  *
  * Since: 1.3.3
  **/
@@ -85,10 +92,13 @@
 
 /**
  * hb_ot_math_get_glyph_italics_correction:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
  *
- * Return value: the italics correction of the glyph or 0
+ * Fetches an italics-correction value (if one exists) for the specified
+ * glyph index.
+ *
+  * Return value: the italics correction of the glyph or zero
  *
  * Since: 1.3.3
  **/
@@ -101,10 +111,20 @@
 
 /**
  * hb_ot_math_get_glyph_top_accent_attachment:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
  *
- * Return value: the top accent attachment of the glyph or 0
+ * Fetches a top-accent-attachment value (if one exists) for the specified
+ * glyph index.
+ *
+ * For any glyph that does not have a top-accent-attachment value - that is,
+ * a glyph not covered by the `MathTopAccentAttachment` table (or, when
+ * @font has no `MathTopAccentAttachment` table or no `MATH` table, any
+ * glyph) - the function synthesizes a value, returning the position at
+ * one-half the glyph's advance width.
+ *
+ * Return value: the top accent attachment of the glyph or 0.5 * the advance
+ *               width of @glyph
  *
  * Since: 1.3.3
  **/
@@ -117,8 +137,10 @@
 
 /**
  * hb_ot_math_is_glyph_extended_shape:
- * @face: a #hb_face_t to test
- * @glyph: a glyph index to test
+ * @face: #hb_face_t to work upon
+ * @glyph: The glyph index to test
+ *
+ * Tests whether the given glyph index is an extended shape in the face.
  *
  * Return value: true if the glyph is an extended shape, false otherwise
  *
@@ -133,18 +155,20 @@
 
 /**
  * hb_ot_math_get_glyph_kerning:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
- * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
+ * @kern: The #hb_ot_math_kern_t from which to retrieve the value
  * @correction_height: the correction height to use to determine the kerning.
  *
- * This function tries to retrieve the MathKern table for the specified font,
- * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
- * MathKern table to find one value that is greater or equal to specified
- * correction_height. If one is found the corresponding value from the list of
- * kerns is returned and otherwise the last kern value is returned.
+ * Fetches the math kerning (cut-ins) value for the specified font, glyph index, and
+ * @kern. 
  *
- * Return value: requested kerning or 0
+ * If the MathKern table is found, the function examines it to find a height
+ * value that is greater or equal to @correction_height. If such a height
+ * value is found, corresponding kerning value from the table is returned. If
+ * no such height value is found, the last kerning value is returned.
+ *
+ * Return value: requested kerning value or zero
  *
  * Since: 1.3.3
  **/
@@ -162,20 +186,24 @@
 
 /**
  * hb_ot_math_get_glyph_variants:
- * @font: #hb_font_t from which to retrieve the values
- * @glyph: index of the glyph to stretch
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @glyph: The index of the glyph to stretch
+ * @direction: The direction of the stretching (horizontal or vertical)
  * @start_offset: offset of the first variant to retrieve
- * @variants_count: maximum number of variants to retrieve after start_offset
- * (IN) and actual number of variants retrieved (OUT)
- * @variants: array of size at least @variants_count to store the result
+ * @variants_count: (inout): Input = the maximum number of variants to return;
+ *                           Output = the actual number of variants returned
+ * @variants: (out) (array length=variants_count): array of variants returned
  *
- * This function tries to retrieve the MathGlyphConstruction for the specified
- * font, glyph and direction. Note that only the value of
- * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
- * of size variants as an array of hb_ot_math_glyph_variant_t structs.
+ * Fetches the MathGlyphConstruction for the specified font, glyph index, and
+ * direction. The corresponding list of size variants is returned as a list of
+ * #hb_ot_math_glyph_variant_t structs.
  *
- * Return value: the total number of size variants available or 0
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note> 
+ *
+ * Return value: the total number of size variants available or zero
  *
  * Since: 1.3.3
  **/
@@ -195,15 +223,19 @@
 
 /**
  * hb_ot_math_get_min_connector_overlap:
- * @font: #hb_font_t from which to retrieve the value
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @direction: direction of the stretching (horizontal or vertical)
  *
- * This function tries to retrieve the MathVariants table for the specified
- * font and returns the minimum overlap of connecting glyphs to draw a glyph
- * assembly in the specified direction. Note that only the value of
- * #HB_DIRECTION_IS_HORIZONTAL is considered.
+ * Fetches the MathVariants table for the specified font and returns the
+ * minimum overlap of connecting glyphs that are required to draw a glyph
+ * assembly in the specified direction.
  *
- * Return value: requested min connector overlap or 0
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note> 
+ *
+ * Return value: requested minimum connector overlap or zero
  *
  * Since: 1.3.3
  **/
@@ -216,19 +248,24 @@
 
 /**
  * hb_ot_math_get_glyph_assembly:
- * @font: #hb_font_t from which to retrieve the values
- * @glyph: index of the glyph to stretch
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @glyph: The index of the glyph to stretch
+ * @direction: direction of the stretching (horizontal or vertical)
  * @start_offset: offset of the first glyph part to retrieve
- * @parts_count: maximum number of glyph parts to retrieve after start_offset
- * (IN) and actual number of parts retrieved (OUT)
- * @parts: array of size at least @parts_count to store the result
- * @italics_correction: italic correction of the glyph assembly
+ * @parts_count: (inout): Input = maximum number of glyph parts to return;
+ *               Output = actual number of parts returned
+ * @parts: (out) (array length=parts_count): the glyph parts returned
+ * @italics_correction: (out): italics correction of the glyph assembly
  *
- * This function tries to retrieve the GlyphAssembly for the specified font,
- * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
- * is considered. It provides the information necessary to draw the glyph
- * assembly as an array of #hb_ot_math_glyph_part_t.
+ * Fetches the GlyphAssembly for the specified font, glyph index, and direction.
+ * Returned are a list of #hb_ot_math_glyph_part_t glyph parts that can be
+ * used to draw the glyph and an italics-correction value (if one is defined
+ * in the font).
+ *
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note> 
  *
  * Return value: the total number of parts in the glyph assembly
  *
@@ -251,3 +288,6 @@
 								 parts,
 								 italics_correction);
 }
+
+
+#endif
diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h
index 521a5ca..ad864a7 100644
--- a/src/hb-ot-math.h
+++ b/src/hb-ot-math.h
@@ -50,6 +50,9 @@
 /**
  * hb_ot_math_constant_t:
  *
+ * The 'MATH' table constants specified at
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/math
+ *
  * Since: 1.3.3
  */
 typedef enum {
@@ -114,6 +117,9 @@
 /**
  * hb_ot_math_kern_t:
  *
+ * The math kerning-table types defined for the four corners
+ * of a glyph.
+ *
  * Since: 1.3.3
  */
 typedef enum {
@@ -125,6 +131,10 @@
 
 /**
  * hb_ot_math_glyph_variant_t:
+ * @glyph: The glyph index of the variant
+ * @advance: The advance width of the variant
+ *
+ * Data type to hold math-variant information for a glyph.
  *
  * Since: 1.3.3
  */
@@ -136,14 +146,25 @@
 /**
  * hb_ot_math_glyph_part_flags_t:
  *
+ * Flags for math glyph parts.
+ *
  * Since: 1.3.3
  */
 typedef enum { /*< flags >*/
-  HB_MATH_GLYPH_PART_FLAG_EXTENDER	= 0x00000001u  /* Extender glyph */
+  HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER	= 0x00000001u  /* Extender glyph */
 } hb_ot_math_glyph_part_flags_t;
 
 /**
  * hb_ot_math_glyph_part_t:
+ * @glyph: The glyph index of the variant part
+ * @start_connector_length: The length of the connector on the starting side of the variant part
+ * @end_connector_length: The length of the connector on the ending side of the variant part
+ * @full_advance: The total advance of the part
+ * @flags: #hb_ot_math_glyph_part_flags_t flags for the part
+ * 
+ * Data type to hold information for a "part" component of a math-variant glyph.
+ * Large variants for stretchable math glyphs (such as parentheses) can be constructed
+ * on the fly from parts.
  *
  * Since: 1.3.3
  */
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index ba474fd..1c25eda 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -71,13 +71,13 @@
 
 struct maxp
 {
-  enum { tableTag = HB_OT_TAG_maxp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp;
 
   unsigned int get_num_glyphs () const { return numGlyphs; }
 
   void set_num_glyphs (unsigned int count)
   {
-    numGlyphs.set (count);
+    numGlyphs = count;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -94,46 +94,42 @@
     return_trace (likely (version.major == 0 && version.minor == 0x5000u));
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table<maxp> (plan->source);
-    hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob);
-    hb_blob_destroy (maxp_blob);
+    TRACE_SUBSET (this);
+    maxp *maxp_prime = c->serializer->embed (this);
+    if (unlikely (!maxp_prime)) return_trace (false);
 
-    if (unlikely (!maxp_prime_blob)) {
-      return false;
-    }
-    maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
-
-    maxp_prime->set_num_glyphs (plan->glyphs.len);
-    if (plan->drop_hints)
-      drop_hint_fields (plan, maxp_prime);
-
-    bool result = plan->add_table (HB_OT_TAG_maxp, maxp_prime_blob);
-    hb_blob_destroy (maxp_prime_blob);
-    return result;
-  }
-
-  static void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime)
-  {
+    maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
     if (maxp_prime->version.major == 1)
     {
-      maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime);
-      v1.maxZones.set (1);
-      v1.maxTwilightPoints.set (0);
-      v1.maxStorage.set (0);
-      v1.maxFunctionDefs.set (0);
-      v1.maxInstructionDefs.set (0);
-      v1.maxStackElements.set (0);
-      v1.maxSizeOfInstructions.set (0);
+      const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
+      maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
+      if (unlikely (!dest_v1)) return_trace (false);
+
+      if (c->plan->drop_hints)
+	drop_hint_fields (dest_v1);
     }
+
+    return_trace (true);
+  }
+
+  static void drop_hint_fields (maxpV1Tail* dest_v1)
+  {
+    dest_v1->maxZones = 1;
+    dest_v1->maxTwilightPoints = 0;
+    dest_v1->maxStorage = 0;
+    dest_v1->maxFunctionDefs = 0;
+    dest_v1->maxInstructionDefs = 0;
+    dest_v1->maxStackElements = 0;
+    dest_v1->maxSizeOfInstructions = 0;
   }
 
   protected:
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
-/*maxpV1Tail	v1Tail[VAR]; */
+/*maxpV1Tail	v1Tail[HB_VAR_ARRAY]; */
   public:
   DEFINE_SIZE_STATIC (6);
 };
diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh
new file mode 100644
index 0000000..43a02d6
--- /dev/null
+++ b/src/hb-ot-meta-table.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_META_TABLE_HH
+#define HB_OT_META_TABLE_HH
+
+#include "hb-open-type.hh"
+
+/*
+ * meta -- Metadata Table
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/meta
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html
+ */
+#define HB_OT_TAG_meta HB_TAG ('m','e','t','a')
+
+
+namespace OT {
+
+
+struct DataMap
+{
+  int cmp (hb_tag_t a) const { return tag.cmp (a); }
+
+  hb_tag_t get_tag () const { return tag; }
+
+  hb_blob_t *reference_entry (hb_blob_t *meta_blob) const
+  { return hb_blob_create_sub_blob (meta_blob, dataZ, dataLength); }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  dataZ.sanitize (c, base, dataLength)));
+  }
+
+  protected:
+  Tag		tag;		/* A tag indicating the type of metadata. */
+  LOffsetTo<UnsizedArrayOf<HBUINT8>>
+		dataZ;		/* Offset in bytes from the beginning of the
+				 * metadata table to the data for this tag. */
+  HBUINT32	dataLength;	/* Length of the data. The data is not required to
+				 * be padded to any byte boundary. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct meta
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_meta;
+
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
+    { table = hb_sanitize_context_t ().reference_table<meta> (face); }
+    void fini () { table.destroy (); }
+
+    hb_blob_t *reference_entry (hb_tag_t tag) const
+    { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); }
+
+    unsigned int get_entries (unsigned int      start_offset,
+			      unsigned int     *count,
+			      hb_ot_meta_tag_t *entries) const
+    {
+      if (count)
+      {
+	+ table->dataMaps.sub_array (start_offset, count)
+	| hb_map (&DataMap::get_tag)
+	| hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; })
+	| hb_sink (hb_array (entries, *count))
+	;
+      }
+      return table->dataMaps.len;
+    }
+
+    private:
+    hb_blob_ptr_t<meta> table;
+  };
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  version == 1 &&
+			  dataMaps.sanitize (c, this)));
+  }
+
+  protected:
+  HBUINT32	version;	/* Version number of the metadata table — set to 1. */
+  HBUINT32	flags;		/* Flags — currently unused; set to 0. */
+  HBUINT32	dataOffset;	/* Per Apple specification:
+				 * Offset from the beginning of the table to the data.
+				 * Per OT specification:
+				 * Reserved. Not used; should be set to 0. */
+  LArrayOf<DataMap>
+		dataMaps;	/* Array of data map records. */
+  public:
+  DEFINE_SIZE_ARRAY (16, dataMaps);
+};
+
+struct meta_accelerator_t : meta::accelerator_t {};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_META_TABLE_HH */
diff --git a/src/hb-ot-meta.cc b/src/hb-ot-meta.cc
new file mode 100644
index 0000000..a1e081b
--- /dev/null
+++ b/src/hb-ot-meta.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_META
+
+#include "hb-ot-meta-table.hh"
+
+/**
+ * SECTION:hb-ot-meta
+ * @title: hb-ot-meta
+ * @short_description: OpenType Metadata
+ * @include: hb-ot.h
+ *
+ * Functions for fetching metadata from fonts.
+ **/
+
+/**
+ * hb_ot_meta_reference_entry:
+ * @face: a face object
+ * @start_offset: iteration's start offset
+ * @entries_count:(inout) (allow-none): buffer size as input, filled size as output
+ * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer
+ *
+ * Return value: Number of all available feature types.
+ *
+ * Since: 2.6.0
+ **/
+unsigned int
+hb_ot_meta_get_entry_tags (hb_face_t        *face,
+			   unsigned int      start_offset,
+			   unsigned int     *entries_count, /* IN/OUT.  May be NULL. */
+			   hb_ot_meta_tag_t *entries        /* OUT.     May be NULL. */)
+{
+  return face->table.meta->get_entries (start_offset, entries_count, entries);
+}
+
+/**
+ * hb_ot_meta_reference_entry:
+ * @face: a #hb_face_t object.
+ * @meta_tag: tag of metadata you like to have.
+ *
+ * It fetches metadata entry of a given tag from a font.
+ *
+ * Returns: (transfer full): A blob containing the blob.
+ *
+ * Since: 2.6.0
+ **/
+hb_blob_t *
+hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag)
+{
+  return face->table.meta->reference_entry (meta_tag);
+}
+
+#endif
diff --git a/src/hb-ot-meta.h b/src/hb-ot-meta.h
new file mode 100644
index 0000000..0278d84
--- /dev/null
+++ b/src/hb-ot-meta.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_META_H
+#define HB_OT_META_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/**
+ * hb_ot_meta_tag_t:
+ * @HB_OT_META_TAG_DESIGN_LANGUAGES: Design languages. Text, using only
+ * Basic Latin (ASCII) characters. Indicates languages and/or scripts
+ * for the user audiences that the font was primarily designed for.
+ * @HB_OT_META_TAG_SUPPORTED_LANGUAGES: Supported languages. Text, using
+ * only Basic Latin (ASCII) characters. Indicates languages and/or scripts
+ * that the font is declared to be capable of supporting.
+ *
+ * Known metadata tags from https://docs.microsoft.com/en-us/typography/opentype/spec/meta
+ *
+ * Since: 2.6.0
+ **/
+typedef enum {
+/*
+   HB_OT_META_TAG_APPL		= HB_TAG ('a','p','p','l'),
+   HB_OT_META_TAG_BILD		= HB_TAG ('b','i','l','d'),
+*/
+  HB_OT_META_TAG_DESIGN_LANGUAGES	= HB_TAG ('d','l','n','g'),
+  HB_OT_META_TAG_SUPPORTED_LANGUAGES	= HB_TAG ('s','l','n','g'),
+
+  _HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_meta_tag_t;
+
+HB_EXTERN unsigned int
+hb_ot_meta_get_entry_tags (hb_face_t        *face,
+			   unsigned int      start_offset,
+			   unsigned int     *entries_count, /* IN/OUT.  May be NULL. */
+			   hb_ot_meta_tag_t *entries        /* OUT.     May be NULL. */);
+
+HB_EXTERN hb_blob_t *
+hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag);
+
+HB_END_DECLS
+
+#endif /* HB_OT_META_H */
diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc
new file mode 100644
index 0000000..181ac4d
--- /dev/null
+++ b/src/hb-ot-metrics.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright © 2018-2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#include "hb-ot-var-mvar-table.hh"
+#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-post-table.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-metrics.hh"
+#include "hb-ot-face.hh"
+
+
+static float
+_fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag)
+{
+  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER ||
+      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_ASCENDER)
+    return fabs ((double) value);
+  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER ||
+      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_DESCENDER)
+    return -fabs ((double) value);
+  return value;
+}
+
+/* The common part of _get_position logic needed on hb-ot-font and here
+   to be able to have slim builds without the not always needed parts */
+bool
+_hb_ot_metrics_get_position_common (hb_font_t           *font,
+				    hb_ot_metrics_tag_t  metrics_tag,
+				    hb_position_t       *position     /* OUT.  May be NULL. */)
+{
+  hb_face_t *face = font->face;
+  switch ((unsigned) metrics_tag)
+  {
+#ifndef HB_NO_VAR
+#define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords)
+#else
+#define GET_VAR .0f
+#endif
+#define GET_METRIC_X(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+#define GET_METRIC_Y(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
+	   GET_METRIC_Y (hhea, ascender);
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) ||
+	   GET_METRIC_Y (hhea, descender);
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) ||
+	   GET_METRIC_Y (hhea, lineGap);
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:  return GET_METRIC_X (vhea, ascender);
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender);
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:  return GET_METRIC_X (vhea, lineGap);
+#undef GET_METRIC_Y
+#undef GET_METRIC_X
+#undef GET_VAR
+  default:                               assert (0); return false;
+  }
+}
+
+#ifndef HB_NO_METRICS
+
+#if 0
+static bool
+_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag)
+{
+  const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0'));
+  if (&range == &Null (OT::GaspRange)) return false;
+  if (result) *result = range.rangeMaxPPEM + font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
+  return true;
+}
+#endif
+
+/* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */
+#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2   HB_TAG ('O','a','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA  HB_TAG ('H','a','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2  HB_TAG ('O','d','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2   HB_TAG ('O','l','g','p')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA  HB_TAG ('H','l','g','p')
+
+/**
+ * hb_ot_metrics_get_position:
+ * @font: a #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ * @position: (out) (optional): result of metrics value from the font.
+ *
+ * It fetches metrics value corresponding to a given tag from a font.
+ *
+ * Returns: Whether found the requested metrics in the font.
+ * Since: 2.6.0
+ **/
+hb_bool_t
+hb_ot_metrics_get_position (hb_font_t           *font,
+			    hb_ot_metrics_tag_t  metrics_tag,
+			    hb_position_t       *position     /* OUT.  May be NULL. */)
+{
+  hb_face_t *face = font->face;
+  switch ((unsigned) metrics_tag)
+  {
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:           return _hb_ot_metrics_get_position_common (font, metrics_tag, position);
+#ifndef HB_NO_VAR
+#define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag)
+#else
+#define GET_VAR 0
+#endif
+#define GET_METRIC_X(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true))
+#define GET_METRIC_Y(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true))
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:  return GET_METRIC_Y (OS2, usWinAscent);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:       return GET_METRIC_Y (hhea, caretSlopeRise);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:        return GET_METRIC_X (hhea, caretSlopeRun);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:     return GET_METRIC_X (hhea, caretOffset);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:         return GET_METRIC_X (vhea, caretSlopeRise);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:          return GET_METRIC_Y (vhea, caretSlopeRun);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:       return GET_METRIC_Y (vhea, caretOffset);
+  case HB_OT_METRICS_TAG_X_HEIGHT:                    return GET_METRIC_Y (OS2->v2 (), sxHeight);
+  case HB_OT_METRICS_TAG_CAP_HEIGHT:                  return GET_METRIC_Y (OS2->v2 (), sCapHeight);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:         return GET_METRIC_X (OS2, ySubscriptXSize);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:         return GET_METRIC_Y (OS2, ySubscriptYSize);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:       return GET_METRIC_X (OS2, ySubscriptXOffset);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:       return GET_METRIC_Y (OS2, ySubscriptYOffset);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:       return GET_METRIC_X (OS2, ySuperscriptXSize);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:       return GET_METRIC_Y (OS2, ySuperscriptYSize);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:     return GET_METRIC_X (OS2, ySuperscriptXOffset);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:     return GET_METRIC_Y (OS2, ySuperscriptYOffset);
+  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:              return GET_METRIC_Y (OS2, yStrikeoutSize);
+  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:            return GET_METRIC_Y (OS2, yStrikeoutPosition);
+  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:              return GET_METRIC_Y (post->table, underlineThickness);
+  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:            return GET_METRIC_Y (post->table, underlinePosition);
+
+  /* Private tags */
+  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2:    return GET_METRIC_Y (OS2, sTypoAscender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA:   return GET_METRIC_Y (hhea, ascender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2:   return GET_METRIC_Y (OS2, sTypoDescender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA:  return GET_METRIC_Y (hhea, descender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2:    return GET_METRIC_Y (OS2, sTypoLineGap);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA:   return GET_METRIC_Y (hhea, lineGap);
+#undef GET_METRIC_Y
+#undef GET_METRIC_X
+#undef GET_VAR
+  default:                                        return false;
+  }
+}
+
+#ifndef HB_NO_VAR
+/**
+ * hb_ot_metrics_get_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+float
+hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
+}
+
+/**
+ * hb_ot_metrics_get_x_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+hb_position_t
+hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag));
+}
+
+/**
+ * hb_ot_metrics_get_y_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+hb_position_t
+hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag));
+}
+#endif
+
+#endif
diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h
new file mode 100644
index 0000000..42c7363
--- /dev/null
+++ b/src/hb-ot-metrics.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_METRICS_H
+#define HB_OT_METRICS_H
+
+#include "hb.h"
+#include "hb-ot-name.h"
+
+HB_BEGIN_DECLS
+
+
+/**
+ * hb_ot_metrics_tag_t:
+ * @HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: horizontal ascender.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: horizontal descender.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: horizontal line gap.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: horizontal clipping ascent.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: horizontal clipping descent.
+ * @HB_OT_METRICS_TAG_VERTICAL_ASCENDER: vertical ascender.
+ * @HB_OT_METRICS_TAG_VERTICAL_DESCENDER: vertical descender.
+ * @HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: vertical line gap.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: horizontal caret rise.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: horizontal caret run.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: horizontal caret offset.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: vertical caret rise.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: vertical caret run.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: vertical caret offset.
+ * @HB_OT_METRICS_TAG_X_HEIGHT: x height.
+ * @HB_OT_METRICS_TAG_CAP_HEIGHT: cap height.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: subscript em x size.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: subscript em y size.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: subscript em x offset.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: subscript em y offset.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: superscript em x size.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: superscript em y size.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: superscript em x offset.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: superscript em y offset.
+ * @HB_OT_METRICS_TAG_STRIKEOUT_SIZE: strikeout size.
+ * @HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: strikeout offset.
+ * @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size.
+ * @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset.
+ *
+ * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags
+ *
+ * Since: 2.6.0
+ **/
+typedef enum {
+  HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER		= HB_TAG ('h','a','s','c'),
+  HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER	= HB_TAG ('h','d','s','c'),
+  HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP		= HB_TAG ('h','l','g','p'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT	= HB_TAG ('h','c','l','a'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT	= HB_TAG ('h','c','l','d'),
+  HB_OT_METRICS_TAG_VERTICAL_ASCENDER		= HB_TAG ('v','a','s','c'),
+  HB_OT_METRICS_TAG_VERTICAL_DESCENDER		= HB_TAG ('v','d','s','c'),
+  HB_OT_METRICS_TAG_VERTICAL_LINE_GAP		= HB_TAG ('v','l','g','p'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE	= HB_TAG ('h','c','r','s'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN	= HB_TAG ('h','c','r','n'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET	= HB_TAG ('h','c','o','f'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_RISE		= HB_TAG ('v','c','r','s'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_RUN		= HB_TAG ('v','c','r','n'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET	= HB_TAG ('v','c','o','f'),
+  HB_OT_METRICS_TAG_X_HEIGHT			= HB_TAG ('x','h','g','t'),
+  HB_OT_METRICS_TAG_CAP_HEIGHT			= HB_TAG ('c','p','h','t'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE		= HB_TAG ('s','b','x','s'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE		= HB_TAG ('s','b','y','s'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET	= HB_TAG ('s','b','x','o'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET	= HB_TAG ('s','b','y','o'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE	= HB_TAG ('s','p','x','s'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE	= HB_TAG ('s','p','y','s'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET	= HB_TAG ('s','p','x','o'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET	= HB_TAG ('s','p','y','o'),
+  HB_OT_METRICS_TAG_STRIKEOUT_SIZE		= HB_TAG ('s','t','r','s'),
+  HB_OT_METRICS_TAG_STRIKEOUT_OFFSET		= HB_TAG ('s','t','r','o'),
+  HB_OT_METRICS_TAG_UNDERLINE_SIZE		= HB_TAG ('u','n','d','s'),
+  HB_OT_METRICS_TAG_UNDERLINE_OFFSET		= HB_TAG ('u','n','d','o'),
+
+  _HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_metrics_tag_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_metrics_get_position (hb_font_t           *font,
+			    hb_ot_metrics_tag_t  metrics_tag,
+			    hb_position_t       *position     /* OUT.  May be NULL. */);
+
+HB_EXTERN float
+hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_EXTERN hb_position_t
+hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_EXTERN hb_position_t
+hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_END_DECLS
+
+#endif /* HB_OT_METRICS_H */
diff --git a/src/hb-subset-glyf.hh b/src/hb-ot-metrics.hh
similarity index 73%
rename from src/hb-subset-glyf.hh
rename to src/hb-ot-metrics.hh
index 99cf8f0..19a5e9e 100644
--- a/src/hb-subset-glyf.hh
+++ b/src/hb-ot-metrics.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,21 +20,16 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger
  */
 
-#ifndef HB_SUBSET_GLYF_HH
-#define HB_SUBSET_GLYF_HH
+#ifndef HB_OT_METRICS_HH
+#define HB_OT_METRICS_HH
 
 #include "hb.hh"
 
-#include "hb-subset.hh"
-
 HB_INTERNAL bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-			 bool             *use_short_loca, /* OUT */
-			 hb_blob_t       **glyf_prime      /* OUT */,
-			 hb_blob_t       **loca_prime      /* OUT */);
+_hb_ot_metrics_get_position_common (hb_font_t           *font,
+				    hb_ot_metrics_tag_t  metrics_tag,
+				    hb_position_t       *position     /* OUT.  May be NULL. */);
 
-#endif /* HB_SUBSET_GLYF_HH */
+#endif /* HB_OT_METRICS_HH */
diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language-static.hh
similarity index 98%
rename from src/hb-ot-name-language.cc
rename to src/hb-ot-name-language-static.hh
index 0e37e0a..580e763 100644
--- a/src/hb-ot-name-language.cc
+++ b/src/hb-ot-name-language-static.hh
@@ -24,6 +24,9 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_OT_NAME_LANGUAGE_STATIC_HH
+#define HB_OT_NAME_LANGUAGE_STATIC_HH
+
 #include "hb-ot-name-language.hh"
 
 /* Following two tables were generated by joining FreeType, FontConfig,
@@ -427,6 +430,9 @@
 			  const hb_ot_language_map_t *array,
 			  unsigned int len)
 {
+#ifdef HB_NO_OT_NAME_LANGUAGE
+  return HB_LANGUAGE_INVALID;
+#endif
   const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *)
 				      hb_bsearch (&code,
 						  array,
@@ -455,3 +461,5 @@
 				   hb_mac_language_map,
 				   ARRAY_LENGTH (hb_mac_language_map));
 }
+
+#endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 705ae0e..84be04c 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -51,6 +51,7 @@
 {
   hb_language_t language (hb_face_t *face) const
   {
+#ifndef HB_NO_OT_NAME_LANGUAGE
     unsigned int p = platformID;
     unsigned int l = languageID;
 
@@ -60,9 +61,12 @@
     if (p == 1)
       return _hb_ot_name_language_for_mac_code (l);
 
+#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
     if (p == 0)
-      return _hb_aat_language_get (face, l);
+      return face->table.ltag->get_language (l);
+#endif
 
+#endif
     return HB_LANGUAGE_INVALID;
   }
 
@@ -93,11 +97,21 @@
     return UNSUPPORTED;
   }
 
+  NameRecord* copy (hb_serialize_context_t *c,
+		    const void *src_base,
+		    const void *dst_base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+    out->offset.serialize_copy (c, offset, src_base, dst_base, length);
+    return_trace (out);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    /* We can check from base all the way up to the end of string... */
-    return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
   }
 
   HBUINT16	platformID;	/* Platform ID. */
@@ -105,7 +119,8 @@
   HBUINT16	languageID;	/* Language ID. */
   HBUINT16	nameID;		/* Name ID. */
   HBUINT16	length;		/* String length (in bytes). */
-  HBUINT16	offset;		/* String offset from start of storage area (in bytes). */
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+		offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
@@ -151,20 +166,61 @@
 
 struct name
 {
-  enum { tableTag = HB_OT_TAG_name };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
 
   unsigned int get_size () const
   { return min_size + count * nameRecordZ.item_size; }
 
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
+  bool serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  const void *src_string_pool)
+  {
+    TRACE_SERIALIZE (this);
+
+    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
+
+    this->format = 0;
+    this->count = it.len ();
+
+    auto snap = c->snapshot ();
+    this->nameRecordZ.serialize (c, this->count);
+    if (unlikely (!c->check_assign (this->stringOffset, c->length ()))) return_trace (false);
+    c->revert (snap);
+
+    const void *dst_string_pool = &(this + this->stringOffset);
+
+    for (const auto &_ : it) c->copy (_, src_string_pool, dst_string_pool);
+
+    if (unlikely (c->ran_out_of_room)) return_trace (false);
+
+    assert (this->stringOffset == c->length ());
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    name *name_prime = c->serializer->start_embed<name> ();
+    if (unlikely (!name_prime)) return_trace (false);
+
+    auto it =
+    + nameRecordZ.as_array (count)
+    | hb_filter (c->plan->name_ids, &NameRecord::nameID)
+    ;
+
+    name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
+    return_trace (name_prime->count);
+  }
+
   bool sanitize_records (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     const void *string_pool = (this+stringOffset).arrayZ;
-    unsigned int _count = count;
-    /* Move to run-time?! */
-    for (unsigned int i = 0; i < _count; i++)
-      if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false);
-    return_trace (true);
+    return_trace (nameRecordZ.sanitize (c, count, string_pool));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -173,7 +229,8 @@
     return_trace (c->check_struct (this) &&
 		  likely (format == 0 || format == 1) &&
 		  c->check_array (nameRecordZ.arrayZ, count) &&
-		  c->check_range (this, stringOffset));
+		  c->check_range (this, stringOffset) &&
+		  sanitize_records (c));
   }
 
   struct accelerator_t
@@ -188,9 +245,9 @@
 						    this->table->count);
 
       this->names.init ();
-      this->names.alloc (all_names.len);
+      this->names.alloc (all_names.length);
 
-      for (unsigned int i = 0; i < all_names.len; i++)
+      for (unsigned int i = 0; i < all_names.length; i++)
       {
 	hb_ot_name_entry_t *entry = this->names.push ();
 
@@ -204,12 +261,12 @@
       /* Walk and pick best only for each name_id,language pair,
        * while dropping unsupported encodings. */
       unsigned int j = 0;
-      for (unsigned int i = 0; i < this->names.len; i++)
+      for (unsigned int i = 0; i < this->names.length; i++)
       {
-        if (this->names[i].entry_score == UNSUPPORTED ||
+	if (this->names[i].entry_score == UNSUPPORTED ||
 	    this->names[i].language == HB_LANGUAGE_INVALID)
 	  continue;
-        if (i &&
+	if (i &&
 	    this->names[i - 1].name_id  == this->names[i].name_id &&
 	    this->names[i - 1].language == this->names[i].language)
 	  continue;
@@ -231,15 +288,15 @@
       const hb_ot_name_entry_t key = {name_id, {0}, language};
       const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
 					hb_bsearch (&key,
-						    this->names.arrayZ(),
-						    this->names.len,
+						    (const hb_ot_name_entry_t *) this->names,
+						    this->names.length,
 						    sizeof (key),
 						    _hb_ot_name_entry_cmp_key);
       if (!entry)
-        return -1;
+	return -1;
 
       if (width)
-        *width = entry->entry_score < 10 ? 2 : 1;
+	*width = entry->entry_score < 10 ? 2 : 1;
 
       return entry->entry_index;
     }
@@ -263,7 +320,7 @@
   /* We only implement format 0 for now. */
   HBUINT16	format;			/* Format selector (=0/1). */
   HBUINT16	count;			/* Number of name records. */
-  OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
 		stringOffset;		/* Offset to start of string storage (from start of table). */
   UnsizedArrayOf<NameRecord>
 		nameRecordZ;		/* The name records where count is the number of records. */
@@ -271,6 +328,9 @@
   DEFINE_SIZE_ARRAY (6, nameRecordZ);
 };
 
+#undef entry_index
+#undef entry_score
+
 struct name_accelerator_t : name::accelerator_t {};
 
 } /* namespace OT */
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index b2eda29..10122b8 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -26,9 +26,10 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_NAME
+
 #include "hb-ot-name-table.hh"
 
-#include "hb-ot-face.hh"
 #include "hb-utf.hh"
 
 
@@ -59,8 +60,8 @@
 		       unsigned int *num_entries /* OUT */)
 {
   const OT::name_accelerator_t &name = *face->table.name;
-  if (num_entries) *num_entries = name.names.len;
-  return name.names.arrayZ();
+  if (num_entries) *num_entries = name.names.length;
+  return (const hb_ot_name_entry_t *) name.names;
 }
 
 
@@ -70,7 +71,7 @@
 			unsigned int                    *text_size /* IN/OUT */,
 			typename out_utf_t::codepoint_t *text /* OUT */)
 {
-  unsigned int src_len = bytes.len / sizeof (typename in_utf_t::codepoint_t);
+  unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
   const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
   const typename in_utf_t::codepoint_t *src_end = src + src_len;
 
@@ -89,11 +90,11 @@
       const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
       typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
       if (dst_next == dst)
-        break; /* Out-of-room. */
+	break; /* Out-of-room. */
 
       dst = dst_next;
       src = src_next;
-    };
+    }
 
     *text_size = dst - text;
     *dst = 0; /* NUL-terminate. */
@@ -105,7 +106,7 @@
   {
     src = in_utf_t::next (src, src_end, &unicode, replacement);
     dst_len += out_utf_t::encode_len (unicode);
-  };
+  }
   return dst_len;
 }
 
@@ -222,3 +223,6 @@
 {
   return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
 }
+
+
+#endif
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 4c1812c..f6b1503 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -59,6 +59,10 @@
 
 struct OS2V2Tail
 {
+  bool has_data () const { return sxHeight || sCapHeight; }
+
+  const OS2V2Tail * operator -> () const { return this; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -77,6 +81,23 @@
 
 struct OS2V5Tail
 {
+  inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const
+  {
+    unsigned int lower_optical_size = usLowerOpticalPointSize;
+    unsigned int upper_optical_size = usUpperOpticalPointSize;
+
+    /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */
+    if (lower_optical_size < upper_optical_size &&
+	lower_optical_size >= 1 && lower_optical_size <= 0xFFFE &&
+	upper_optical_size >= 2 && upper_optical_size <= 0xFFFF)
+    {
+      *lower = lower_optical_size;
+      *upper = upper_optical_size;
+      return true;
+    }
+    return false;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -92,9 +113,9 @@
 
 struct OS2
 {
-  enum { tableTag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
 
-  bool has_data () const { return this != &Null (OS2); }
+  bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; }
 
   const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); }
   const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); }
@@ -113,9 +134,9 @@
     OBLIQUE		= 1u<<9
   };
 
-  bool is_italic () const       { return fsSelection & ITALIC; }
-  bool is_oblique () const      { return fsSelection & OBLIQUE; }
-  bool is_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
+  bool        is_italic () const { return fsSelection & ITALIC; }
+  bool       is_oblique () const { return fsSelection & OBLIQUE; }
+  bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
 
   enum width_class_t {
     FWIDTH_ULTRA_CONDENSED	= 1, /* 50% */
@@ -145,36 +166,28 @@
     }
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *os2_blob = hb_sanitize_context_t ().reference_table<OS2> (plan->source);
-    hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1);
-    // TODO(grieger): move to hb_blob_copy_writable_or_fail
-    hb_blob_destroy (os2_blob);
-
-    OS2 *os2_prime = (OS2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr);
-    if (unlikely (!os2_prime)) {
-      hb_blob_destroy (os2_prime_blob);
-      return false;
-    }
+    TRACE_SUBSET (this);
+    OS2 *os2_prime = c->serializer->embed (this);
+    if (unlikely (!os2_prime)) return_trace (false);
 
     uint16_t min_cp, max_cp;
-    find_min_and_max_codepoint (plan->unicodes, &min_cp, &max_cp);
-    os2_prime->usFirstCharIndex.set (min_cp);
-    os2_prime->usLastCharIndex.set (max_cp);
+    find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
+    os2_prime->usFirstCharIndex = min_cp;
+    os2_prime->usLastCharIndex = max_cp;
 
-    _update_unicode_ranges (plan->unicodes, os2_prime->ulUnicodeRange);
-    bool result = plan->add_table (HB_OT_TAG_OS2, os2_prime_blob);
+    _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
 
-    hb_blob_destroy (os2_prime_blob);
-    return result;
+    return_trace (true);
   }
 
   void _update_unicode_ranges (const hb_set_t *codepoints,
 			       HBUINT32 ulUnicodeRange[4]) const
   {
+    HBUINT32	newBits[4];
     for (unsigned int i = 0; i < 4; i++)
-      ulUnicodeRange[i].set (0);
+      newBits[i] = 0;
 
     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
     while (codepoints->next (&cp)) {
@@ -184,26 +197,30 @@
 	unsigned int block = bit / 32;
 	unsigned int bit_in_block = bit % 32;
 	unsigned int mask = 1 << bit_in_block;
-	ulUnicodeRange[block].set (ulUnicodeRange[block] | mask);
+	newBits[block] = newBits[block] | mask;
       }
       if (cp >= 0x10000 && cp <= 0x110000)
       {
 	/* the spec says that bit 57 ("Non Plane 0") implies that there's
 	   at least one codepoint beyond the BMP; so I also include all
 	   the non-BMP codepoints here */
-	ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25));
+	newBits[1] = newBits[1] | (1 << 25);
       }
     }
+
+    for (unsigned int i = 0; i < 4; i++)
+      ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original
   }
 
   static void find_min_and_max_codepoint (const hb_set_t *codepoints,
-						 uint16_t *min_cp, /* OUT */
-						 uint16_t *max_cp  /* OUT */)
+					  uint16_t *min_cp, /* OUT */
+					  uint16_t *max_cp  /* OUT */)
   {
     *min_cp = codepoints->get_min ();
     *max_cp = codepoints->get_max ();
   }
 
+  /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */
   enum font_page_t {
     HEBREW_FONT_PAGE		= 0xB100, // Hebrew Windows 3.1 font page
     SIMP_ARABIC_FONT_PAGE	= 0xB200, // Simplified Arabic Windows 3.1 font page
@@ -213,11 +230,18 @@
     TRAD_FARSI_FONT_PAGE	= 0xBB00, // Traditional Farsi Windows 3.1 font page
     THAI_FONT_PAGE		= 0xDE00  // Thai Windows 3.1 font page
   };
-
-  // https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
   font_page_t get_font_page () const
   { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
 
+  unsigned get_size () const
+  {
+    unsigned result = min_size;
+    if (version >= 1) result += v1X.get_size ();
+    if (version >= 2) result += v2X.get_size ();
+    if (version >= 5) result += v5X.get_size ();
+    return result;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 33b7070..38302f5 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -71,28 +71,27 @@
 
 struct post
 {
-  enum { tableTag = HB_OT_TAG_post };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
-  bool subset (hb_subset_plan_t *plan) const
+  void serialize (hb_serialize_context_t *c) const
   {
-    unsigned int post_prime_length;
-    hb_blob_t *post_blob = hb_sanitize_context_t ().reference_table<post>(plan->source);
-    hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::min_size);
-    post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length);
-    hb_blob_destroy (post_blob);
+    post *post_prime = c->allocate_min<post> ();
+    if (unlikely (!post_prime))  return;
 
-    if (unlikely (!post_prime || post_prime_length != post::min_size))
-    {
-      hb_blob_destroy (post_prime_blob);
-      DEBUG_MSG(SUBSET, nullptr, "Invalid source post table with length %d.", post_prime_length);
-      return false;
-    }
+    memcpy (post_prime, this, post::min_size);
+    post_prime->version.major = 3; // Version 3 does not have any glyph names.
+  }
 
-    post_prime->version.major.set (3); // Version 3 does not have any glyph names.
-    bool result = plan->add_table (HB_OT_TAG_post, post_prime_blob);
-    hb_blob_destroy (post_prime_blob);
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    post *post_prime = c->serializer->start_embed<post> ();
+    if (unlikely (!post_prime)) return_trace (false);
 
-    return result;
+    serialize (c->serializer);
+    if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
+
+    return_trace (true);
   }
 
   struct accelerator_t
@@ -114,7 +113,7 @@
 
       const uint8_t *end = (const uint8_t *) (const void *) table + table_length;
       for (const uint8_t *data = pool;
-	   index_to_offset.len < 65535 && data < end && data + *data < end;
+	   index_to_offset.length < 65535 && data < end && data + *data < end;
 	   data += 1 + *data)
 	index_to_offset.push (data - pool);
     }
@@ -129,9 +128,9 @@
 			 char *buf, unsigned int buf_len) const
     {
       hb_bytes_t s = find_glyph_name (glyph);
-      if (!s.len) return false;
+      if (!s.length) return false;
       if (!buf_len) return true;
-      unsigned int len = MIN (buf_len - 1, s.len);
+      unsigned int len = hb_min (buf_len - 1, s.length);
       strncpy (buf, s.arrayZ, len);
       buf[len] = '\0';
       return true;
@@ -158,7 +157,7 @@
 
 	for (unsigned int i = 0; i < count; i++)
 	  gids[i] = i;
-	hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
+	hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
 
 	if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
 	{
@@ -168,8 +167,8 @@
       }
 
       hb_bytes_t st (name, len);
-      const uint16_t *gid = (const uint16_t *) hb_bsearch_r (hb_addressof (st), gids, count,
-							     sizeof (gids[0]), cmp_key, (void *) this);
+      const uint16_t *gid = (const uint16_t *) hb_bsearch (hb_addressof (st), gids, count,
+							   sizeof (gids[0]), cmp_key, (void *) this);
       if (gid)
       {
 	*glyph = *gid;
@@ -179,6 +178,8 @@
       return false;
     }
 
+    hb_blob_ptr_t<post> table;
+
     protected:
 
     unsigned int get_glyph_count () const
@@ -226,7 +227,7 @@
 	return format1_names (index);
       index -= NUM_FORMAT1_NAMES;
 
-      if (index >= index_to_offset.len)
+      if (index >= index_to_offset.length)
 	return hb_bytes_t ();
       unsigned int offset = index_to_offset[index];
 
@@ -238,14 +239,15 @@
     }
 
     private:
-    hb_blob_ptr_t<post> table;
     uint32_t version;
     const ArrayOf<HBUINT16> *glyphNameIndex;
-    hb_vector_t<uint32_t, 1> index_to_offset;
+    hb_vector_t<uint32_t> index_to_offset;
     const uint8_t *pool;
     hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
   };
 
+  bool has_data () const { return version.to_int (); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -260,7 +262,7 @@
 					 * 0x00020000 for version 2.0
 					 * 0x00025000 for version 2.5 (deprecated)
 					 * 0x00030000 for version 3.0 */
-  Fixed		italicAngle;		/* Italic angle in counter-clockwise degrees
+  HBFixed		italicAngle;		/* Italic angle in counter-clockwise degrees
 					 * from the vertical. Zero for upright text,
 					 * negative for text that leans to the right
 					 * (forward). */
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 2a1f2f8..2a7a8eb 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -49,8 +49,8 @@
 					  hb_font_t *font,
 					  unsigned int feature_index)
 {
-  OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
-  OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
   unsigned int num_glyphs = 0;
 
   /* Populate arrays */
@@ -66,8 +66,8 @@
 	u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
       continue;
 
-    glyphs[num_glyphs].set (u_glyph);
-    substitutes[num_glyphs].set (s_glyph);
+    glyphs[num_glyphs] = u_glyph;
+    substitutes[num_glyphs] = s_glyph;
 
     num_glyphs++;
   }
@@ -77,7 +77,9 @@
 
   /* Bubble-sort or something equally good!
    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
-  hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]);
+  hb_stable_sort (&glyphs[0], num_glyphs,
+		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+		  &substitutes[0]);
 
 
   /* Each glyph takes four bytes max, and there's some overhead. */
@@ -86,10 +88,9 @@
   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
   bool ret = lookup->serialize_single (&c,
 				       OT::LookupFlag::IgnoreMarks,
-				       hb_array (glyphs, num_glyphs),
+				       hb_sorted_array (glyphs, num_glyphs),
 				       hb_array (substitutes, num_glyphs));
   c.end_serialize ();
-  /* TODO sanitize the results? */
 
   return ret ? c.copy<OT::SubstLookup> () : nullptr;
 }
@@ -98,15 +99,15 @@
 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
 					    hb_font_t *font)
 {
-  OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
+  OT::HBGlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
   unsigned int num_first_glyphs = 0;
 
   /* We know that all our ligatures are 2-component */
-  OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
+  OT::HBGlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
   unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
-  OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  OT::HBGlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
   unsigned int num_ligatures = 0;
 
   /* Populate arrays */
@@ -118,12 +119,14 @@
     hb_codepoint_t first_glyph;
     if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
       continue;
-    first_glyphs[num_first_glyphs].set (first_glyph);
+    first_glyphs[num_first_glyphs] = first_glyph;
     ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
     first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
     num_first_glyphs++;
   }
-  hb_stable_sort (&first_glyphs[0], num_first_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+  hb_stable_sort (&first_glyphs[0], num_first_glyphs,
+		  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+		  &first_glyphs_indirection[0]);
 
   /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
   for (unsigned int i = 0; i < num_first_glyphs; i++)
@@ -142,9 +145,9 @@
 
       ligature_per_first_glyph_count_list[i]++;
 
-      ligature_list[num_ligatures].set (ligature_glyph);
+      ligature_list[num_ligatures] = ligature_glyph;
       component_count_list[num_ligatures] = 2;
-      component_list[num_ligatures].set (second_glyph);
+      component_list[num_ligatures] = second_glyph;
       num_ligatures++;
     }
   }
@@ -159,7 +162,7 @@
   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
   bool ret = lookup->serialize_ligature (&c,
 					 OT::LookupFlag::IgnoreMarks,
-					 hb_array (first_glyphs, num_first_glyphs),
+					 hb_sorted_array (first_glyphs, num_first_glyphs),
 					 hb_array (ligature_per_first_glyph_count_list, num_first_glyphs),
 					 hb_array (ligature_list, num_ligatures),
 					 hb_array (component_count_list, num_ligatures),
@@ -227,8 +230,8 @@
     return false;
 
   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
-  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
-		 <= ARABIC_FALLBACK_MAX_LOOKUPS, "");
+  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) ==
+		 ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), "");
   /* TODO sanitize the table? */
 
   unsigned j = 0;
diff --git a/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shape-complex-arabic-table.hh
index 9459aad..719fabd 100644
--- a/src/hb-ot-shape-complex-arabic-table.hh
+++ b/src/hb-ot-shape-complex-arabic-table.hh
@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-11.0.0.txt
- * # Date: 2018-02-21, 14:50:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # ArabicShaping-12.0.0.txt
+ * # Date: 2018-09-22, 23:54:00 GMT [KW, RP]
+ * # Blocks-12.0.0.txt
+ * # Date: 2018-07-30, 19:40:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -152,9 +152,9 @@
 
   /* 1E900 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
-  /* 1E940 */ D,D,D,D,
+  /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1304; occupancy: 56% */
+}; /* Table items: 1312; occupancy: 56% */
 
 
 static unsigned int
@@ -190,7 +190,7 @@
       break;
 
     case 0x1Eu:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E94Bu)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
       break;
 
     default:
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 50a5213..f92e637 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -25,6 +25,9 @@
  */
 
 #include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-arabic.hh"
 #include "hb-ot-shape.hh"
 
@@ -383,6 +386,10 @@
 		       hb_font_t *font,
 		       hb_buffer_t *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
+  return;
+#endif
+
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   if (!arabic_plan->do_fallback)
@@ -467,15 +474,15 @@
     unsigned int j = new_len;
     for (unsigned int i = count; i; i--)
     {
-      if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      if (!hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
       {
-        if (step == CUT)
+	if (step == CUT)
 	{
 	  --j;
 	  info[j] = info[i - 1];
 	  pos[j] = pos[i - 1];
 	}
-        continue;
+	continue;
       }
 
       /* Yay, justification! */
@@ -488,7 +495,7 @@
 
       unsigned int end = i;
       while (i &&
-	     hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+	     hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
       {
 	i--;
 	hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
@@ -506,7 +513,7 @@
       unsigned int start = i;
       unsigned int context = i;
       while (context &&
-	     !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
+	     !hb_in_range<uint8_t> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
 	     (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
 	      HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
       {
@@ -533,10 +540,10 @@
       hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
       if (shortfall > 0 && n_repeating > 0)
       {
-        ++n_copies;
-        hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
-        if (excess > 0)
-          extra_repeat_overlap = excess / (n_copies * n_repeating);
+	++n_copies;
+	hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
+	if (excess > 0)
+	  extra_repeat_overlap = excess / (n_copies * n_repeating);
       }
 
       if (step == MEASURE)
@@ -576,7 +583,7 @@
     if (step == MEASURE)
     {
       if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
-        break;
+	break;
     }
     else
     {
@@ -706,3 +713,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index 97923ec..a921f16 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -44,3 +48,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index e143867..f5915f4 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -200,7 +204,7 @@
       if (start < end && end == buffer->out_len)
       {
 	/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
-        buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
+	buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
 	buffer->next_glyph ();
 	if (!is_zero_width_char (font, u))
 	{
@@ -214,7 +218,8 @@
       else
       {
 	/* No valid syllable as base for tone mark; try to insert dotted circle. */
-	if (font->has_glyph (0x25CCu))
+      if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
+	  font->has_glyph (0x25CCu))
 	{
 	  hb_codepoint_t chars[2];
 	  if (!is_zero_width_char (font, u)) {
@@ -349,9 +354,9 @@
 	   */
 	  if (has_glyph && !tindex)
 	  {
-            buffer->next_glyph ();
-            s_len++;
-          }
+	    buffer->next_glyph ();
+	    s_len++;
+	  }
 
 	  if (unlikely (!buffer->successful))
 	    return;
@@ -360,7 +365,7 @@
 	   * that are now in buffer->out_info.
 	   */
 	  hb_glyph_info_t *info = buffer->out_info;
-          end = start + s_len;
+	  end = start + s_len;
 
 	  unsigned int i = start;
 	  info[i++].hangul_shaping_feature() = LJMO;
@@ -378,7 +383,7 @@
 
       if (has_glyph)
       {
-        /* We didn't decompose the S, so just advance past it. */
+	/* We didn't decompose the S, so just advance past it. */
 	end = start + 1;
 	buffer->next_glyph ();
 	continue;
@@ -429,3 +434,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc
index 90c36c0..334d3de 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -70,6 +74,10 @@
 
   bool found = (bool) c->unicode->compose (a, b, ab);
 
+#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+  return found;
+#endif
+
   if (!found && !c->plan->has_gpos_mark)
   {
       /* Special-case Hebrew presentation forms that are excluded from
@@ -172,3 +180,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
index e2ecfb8..670b6bf 100644
--- a/src/hb-ot-shape-complex-indic-machine.hh
+++ b/src/hb-ot-shape-complex-indic-machine.hh
@@ -34,711 +34,284 @@
 
 #line 36 "hb-ot-shape-complex-indic-machine.hh"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
-	8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 
-	5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 
-	4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 
-	16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 
-	4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 
-	7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 
-	6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 
-	4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 
-	4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 
-	5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 
-	7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 
-	6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 
-	4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u, 
-	7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 
-	5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 
-	4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 
-	4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, 
-	5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 
-	3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 
-	3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 
-	5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 
-	4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 
-	3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 
-	3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 
-	1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 
-	3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 
-	3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 
-	3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 
-	10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 
-	4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 
-	3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 
-	1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 
-	1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u, 
-	3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 
-	3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 
-	5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 
-	3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 
-	5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 
-	3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 
-	1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, 
-	3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 
-	4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 
-	4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 
-	10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 
-	5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 
-	4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 
-	1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 
-	3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u, 
-	1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 
-	3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 
-	0
+	8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 
+	4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 
+	4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 
+	6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 
+	4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u, 
+	3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 
+	1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 
+	3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 
+	3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 
+	1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 
+	5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 
+	3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 
+	4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 
+	3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 
+	1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 
+	5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u, 
+	3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 
+	5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0
 };
 
 static const char _indic_syllable_machine_key_spans[] = {
-	1, 5, 3, 1, 4, 3, 1, 4, 
-	3, 1, 4, 3, 1, 5, 1, 1, 
-	5, 1, 1, 5, 1, 1, 5, 1, 
-	1, 10, 5, 10, 5, 10, 5, 10, 
-	5, 10, 1, 5, 3, 1, 4, 3, 
-	1, 4, 3, 1, 4, 3, 1, 5, 
-	1, 1, 5, 1, 1, 5, 1, 1, 
-	5, 1, 1, 10, 5, 10, 5, 10, 
-	5, 10, 5, 10, 1, 5, 3, 1, 
-	4, 3, 1, 4, 3, 1, 4, 3, 
-	1, 5, 1, 1, 5, 1, 1, 5, 
-	1, 1, 5, 1, 1, 10, 5, 10, 
-	5, 10, 5, 10, 5, 1, 5, 3, 
-	1, 4, 3, 1, 4, 3, 1, 4, 
-	3, 1, 5, 1, 1, 5, 1, 1, 
-	5, 1, 1, 5, 1, 1, 10, 5, 
-	10, 5, 10, 5, 10, 5, 10, 10, 
-	4, 1, 19, 11, 8, 7, 16, 11, 
-	8, 7, 16, 11, 8, 7, 16, 11, 
-	8, 7, 16, 11, 8, 7, 6, 6, 
-	6, 1, 1, 1, 6, 8, 6, 8, 
-	7, 6, 8, 7, 6, 8, 7, 6, 
-	8, 7, 8, 11, 16, 16, 16, 8, 
-	11, 16, 16, 16, 8, 11, 16, 16, 
-	16, 8, 11, 16, 16, 16, 8, 11, 
-	11, 8, 7, 16, 11, 8, 7, 16, 
-	11, 8, 7, 16, 11, 8, 7, 16, 
-	11, 8, 7, 6, 6, 6, 1, 1, 
-	1, 6, 8, 6, 8, 7, 6, 8, 
-	7, 6, 8, 7, 6, 8, 7, 8, 
-	11, 16, 16, 16, 8, 11, 16, 16, 
-	16, 8, 11, 16, 16, 16, 8, 11, 
-	16, 16, 16, 5, 8, 8, 7, 16, 
-	11, 8, 7, 16, 11, 8, 7, 16, 
-	11, 8, 7, 16, 11, 8, 7, 6, 
-	6, 6, 1, 1, 1, 6, 8, 6, 
-	8, 7, 6, 8, 7, 6, 8, 7, 
-	6, 8, 7, 8, 11, 16, 16, 16, 
-	8, 11, 16, 16, 16, 8, 11, 16, 
-	16, 16, 8, 11, 16, 16, 16, 10, 
-	8, 5, 11, 8, 7, 16, 11, 8, 
-	7, 16, 11, 8, 7, 16, 11, 8, 
-	7, 16, 11, 8, 7, 6, 6, 6, 
-	1, 1, 1, 6, 8, 6, 8, 7, 
-	6, 8, 7, 6, 8, 7, 6, 8, 
-	7, 8, 11, 16, 16, 16, 8, 11, 
-	16, 16, 16, 8, 11, 16, 16, 16, 
-	8, 11, 16, 16, 16, 8, 16, 11, 
-	16, 10, 6, 1, 1, 1, 6, 16, 
-	8, 6, 6, 1, 1, 1, 6, 16
+	1, 5, 3, 4, 5, 1, 1, 5, 
+	10, 5, 1, 3, 4, 5, 1, 1, 
+	5, 10, 10, 10, 1, 3, 4, 5, 
+	1, 1, 5, 5, 10, 1, 3, 4, 
+	5, 1, 1, 5, 5, 4, 1, 19, 
+	15, 15, 14, 16, 6, 6, 1, 6, 
+	16, 16, 16, 8, 7, 6, 7, 6, 
+	8, 6, 15, 15, 15, 15, 14, 16, 
+	15, 15, 14, 16, 6, 1, 6, 16, 
+	16, 8, 7, 6, 7, 6, 6, 8, 
+	6, 15, 15, 5, 15, 15, 14, 16, 
+	15, 16, 6, 1, 6, 16, 16, 8, 
+	7, 6, 15, 7, 6, 6, 8, 6, 
+	15, 10, 5, 15, 15, 14, 16, 15, 
+	16, 6, 1, 6, 16, 16, 8, 7, 
+	6, 15, 7, 6, 6, 8, 6, 17, 
+	15, 17, 10, 6, 1, 6, 16, 8, 
+	6, 6, 1, 6, 16
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
-	0, 2, 8, 12, 14, 19, 23, 25, 
-	30, 34, 36, 41, 45, 47, 53, 55, 
-	57, 63, 65, 67, 73, 75, 77, 83, 
-	85, 87, 98, 104, 115, 121, 132, 138, 
-	149, 155, 166, 168, 174, 178, 180, 185, 
-	189, 191, 196, 200, 202, 207, 211, 213, 
-	219, 221, 223, 229, 231, 233, 239, 241, 
-	243, 249, 251, 253, 264, 270, 281, 287, 
-	298, 304, 315, 321, 332, 334, 340, 344, 
-	346, 351, 355, 357, 362, 366, 368, 373, 
-	377, 379, 385, 387, 389, 395, 397, 399, 
-	405, 407, 409, 415, 417, 419, 430, 436, 
-	447, 453, 464, 470, 481, 487, 489, 495, 
-	499, 501, 506, 510, 512, 517, 521, 523, 
-	528, 532, 534, 540, 542, 544, 550, 552, 
-	554, 560, 562, 564, 570, 572, 574, 585, 
-	591, 602, 608, 619, 625, 636, 642, 653, 
-	664, 669, 671, 691, 703, 712, 720, 737, 
-	749, 758, 766, 783, 795, 804, 812, 829, 
-	841, 850, 858, 875, 887, 896, 904, 911, 
-	918, 925, 927, 929, 931, 938, 947, 954, 
-	963, 971, 978, 987, 995, 1002, 1011, 1019, 
-	1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115, 
-	1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225, 
-	1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340, 
-	1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427, 
-	1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519, 
-	1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588, 
-	1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639, 
-	1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704, 
-	1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814, 
-	1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929, 
-	1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024, 
-	2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116, 
-	2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208, 
-	2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251, 
-	2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315, 
-	2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402, 
-	2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512, 
-	2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635, 
-	2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719, 
-	2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811, 
-	2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888, 
-	2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933, 
-	2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996, 
-	3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094, 
-	3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212, 
-	3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327, 
-	3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387, 
-	3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440
+	0, 2, 8, 12, 17, 23, 25, 27, 
+	33, 44, 50, 52, 56, 61, 67, 69, 
+	71, 77, 88, 99, 110, 112, 116, 121, 
+	127, 129, 131, 137, 143, 154, 156, 160, 
+	165, 171, 173, 175, 181, 187, 192, 194, 
+	214, 230, 246, 261, 278, 285, 292, 294, 
+	301, 318, 335, 352, 361, 369, 376, 384, 
+	391, 400, 407, 423, 439, 455, 471, 486, 
+	503, 519, 535, 550, 567, 574, 576, 583, 
+	600, 617, 626, 634, 641, 649, 656, 663, 
+	672, 679, 695, 711, 717, 733, 749, 764, 
+	781, 797, 814, 821, 823, 830, 847, 864, 
+	873, 881, 888, 904, 912, 919, 926, 935, 
+	942, 958, 969, 975, 991, 1007, 1022, 1039, 
+	1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131, 
+	1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200, 
+	1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296, 
+	1305, 1312, 1319, 1321, 1328
 };
 
-static const short _indic_syllable_machine_indicies[] = {
+static const unsigned char _indic_syllable_machine_indicies[] = {
 	1, 0, 2, 3, 3, 4, 1, 0, 
-	5, 5, 4, 0, 4, 0, 6, 6, 
-	7, 1, 0, 8, 8, 7, 0, 7, 
-	0, 9, 9, 10, 1, 0, 11, 11, 
-	10, 0, 10, 0, 12, 12, 13, 1, 
-	0, 14, 14, 13, 0, 13, 0, 15, 
-	0, 0, 0, 1, 0, 16, 0, 17, 
-	0, 18, 12, 12, 13, 1, 0, 19, 
-	0, 20, 0, 21, 9, 9, 10, 1, 
-	0, 22, 0, 23, 0, 24, 6, 6, 
-	7, 1, 0, 25, 0, 26, 0, 2, 
-	3, 3, 4, 1, 0, 0, 0, 0, 
-	27, 0, 28, 3, 3, 4, 1, 0, 
-	28, 3, 3, 4, 1, 0, 0, 0, 
-	0, 29, 0, 30, 3, 3, 4, 1, 
-	0, 30, 3, 3, 4, 1, 0, 0, 
-	0, 0, 31, 0, 32, 3, 3, 4, 
-	1, 0, 32, 3, 3, 4, 1, 0, 
-	0, 0, 0, 33, 0, 34, 3, 3, 
-	4, 1, 0, 34, 3, 3, 4, 1, 
-	0, 0, 0, 0, 35, 0, 37, 36, 
-	38, 39, 39, 40, 37, 36, 41, 41, 
-	40, 36, 40, 36, 42, 42, 43, 37, 
-	36, 44, 44, 43, 36, 43, 36, 45, 
-	45, 46, 37, 36, 47, 47, 46, 36, 
-	46, 36, 48, 48, 49, 37, 36, 50, 
-	50, 49, 36, 49, 36, 51, 36, 36, 
-	36, 37, 36, 52, 36, 53, 36, 54, 
-	48, 48, 49, 37, 36, 55, 36, 56, 
-	36, 57, 45, 45, 46, 37, 36, 58, 
-	36, 59, 36, 60, 42, 42, 43, 37, 
-	36, 61, 36, 62, 36, 38, 39, 39, 
-	40, 37, 36, 36, 36, 36, 63, 36, 
-	64, 39, 39, 40, 37, 36, 64, 39, 
-	39, 40, 37, 36, 36, 36, 36, 65, 
-	36, 66, 39, 39, 40, 37, 36, 66, 
-	39, 39, 40, 37, 36, 36, 36, 36, 
-	67, 36, 68, 39, 39, 40, 37, 36, 
-	68, 39, 39, 40, 37, 36, 36, 36, 
-	36, 69, 36, 70, 39, 39, 40, 37, 
-	36, 70, 39, 39, 40, 37, 36, 36, 
-	36, 36, 71, 36, 73, 72, 74, 75, 
-	75, 76, 73, 72, 78, 78, 76, 77, 
-	76, 77, 79, 79, 80, 73, 72, 81, 
-	81, 80, 72, 80, 72, 82, 82, 83, 
-	73, 72, 84, 84, 83, 72, 83, 72, 
-	85, 85, 86, 73, 72, 87, 87, 86, 
-	72, 86, 72, 88, 72, 72, 72, 73, 
-	72, 89, 72, 90, 72, 91, 85, 85, 
-	86, 73, 72, 92, 72, 93, 72, 94, 
-	82, 82, 83, 73, 72, 95, 72, 96, 
-	72, 97, 79, 79, 80, 73, 72, 98, 
-	72, 99, 72, 74, 75, 75, 76, 73, 
-	72, 72, 72, 72, 100, 72, 101, 75, 
-	75, 76, 73, 72, 101, 75, 75, 76, 
-	73, 72, 72, 72, 72, 102, 72, 103, 
-	75, 75, 76, 73, 72, 103, 75, 75, 
-	76, 73, 72, 72, 72, 72, 104, 72, 
-	105, 75, 75, 76, 73, 72, 105, 75, 
-	75, 76, 73, 72, 72, 72, 72, 106, 
-	72, 107, 75, 75, 76, 73, 72, 109, 
-	108, 110, 111, 111, 112, 109, 108, 113, 
-	113, 112, 108, 112, 108, 114, 114, 115, 
-	109, 108, 116, 116, 115, 108, 115, 108, 
-	117, 117, 118, 109, 108, 119, 119, 118, 
-	108, 118, 108, 120, 120, 121, 109, 108, 
-	122, 122, 121, 108, 121, 108, 123, 108, 
-	108, 108, 109, 108, 124, 108, 125, 108, 
-	126, 120, 120, 121, 109, 108, 127, 108, 
-	128, 108, 129, 117, 117, 118, 109, 108, 
-	130, 108, 131, 108, 132, 114, 114, 115, 
-	109, 108, 133, 108, 134, 108, 110, 111, 
-	111, 112, 109, 108, 108, 108, 108, 135, 
-	108, 136, 111, 111, 112, 109, 108, 136, 
-	111, 111, 112, 109, 108, 108, 108, 108, 
-	137, 108, 138, 111, 111, 112, 109, 108, 
-	138, 111, 111, 112, 109, 108, 108, 108, 
-	108, 139, 108, 140, 111, 111, 112, 109, 
-	108, 140, 111, 111, 112, 109, 108, 108, 
-	108, 108, 141, 108, 142, 111, 111, 112, 
-	109, 108, 142, 111, 111, 112, 109, 108, 
-	108, 108, 108, 143, 108, 107, 75, 75, 
-	76, 73, 72, 72, 72, 72, 144, 72, 
-	78, 78, 76, 1, 0, 146, 145, 148, 
-	149, 150, 151, 152, 153, 76, 73, 147, 
-	154, 155, 155, 144, 147, 156, 157, 147, 
-	158, 159, 147, 161, 162, 163, 164, 4, 
-	1, 160, 165, 160, 160, 35, 160, 166, 
-	162, 167, 167, 4, 1, 160, 165, 160, 
-	162, 167, 167, 4, 1, 160, 165, 160, 
-	168, 160, 160, 160, 17, 169, 160, 1, 
-	160, 165, 160, 160, 160, 160, 160, 168, 
-	160, 170, 171, 172, 173, 4, 1, 160, 
-	165, 160, 160, 33, 160, 174, 171, 175, 
-	175, 4, 1, 160, 165, 160, 171, 175, 
-	175, 4, 1, 160, 165, 160, 176, 160, 
-	160, 160, 17, 177, 160, 1, 160, 165, 
-	160, 160, 160, 160, 160, 176, 160, 178, 
-	179, 180, 181, 4, 1, 160, 165, 160, 
-	160, 31, 160, 182, 179, 183, 183, 4, 
-	1, 160, 165, 160, 179, 183, 183, 4, 
-	1, 160, 165, 160, 184, 160, 160, 160, 
-	17, 185, 160, 1, 160, 165, 160, 160, 
-	160, 160, 160, 184, 160, 186, 187, 188, 
-	189, 4, 1, 160, 165, 160, 160, 29, 
-	160, 190, 187, 191, 191, 4, 1, 160, 
-	165, 160, 187, 191, 191, 4, 1, 160, 
-	165, 160, 192, 160, 160, 160, 17, 193, 
-	160, 1, 160, 165, 160, 160, 160, 160, 
-	160, 192, 160, 194, 195, 196, 197, 4, 
-	1, 160, 165, 160, 160, 27, 160, 198, 
-	195, 199, 199, 4, 1, 160, 165, 160, 
-	195, 199, 199, 4, 1, 160, 165, 160, 
-	17, 200, 160, 1, 160, 165, 160, 201, 
-	201, 160, 1, 160, 165, 160, 202, 160, 
-	160, 203, 160, 165, 160, 165, 160, 204, 
-	160, 205, 160, 202, 160, 160, 160, 160, 
-	165, 160, 17, 160, 201, 201, 160, 1, 
-	160, 165, 160, 201, 200, 160, 1, 160, 
-	165, 160, 206, 26, 207, 208, 7, 1, 
-	160, 165, 160, 26, 207, 208, 7, 1, 
-	160, 165, 160, 207, 207, 7, 1, 160, 
-	165, 160, 209, 23, 210, 211, 10, 1, 
-	160, 165, 160, 23, 210, 211, 10, 1, 
-	160, 165, 160, 210, 210, 10, 1, 160, 
-	165, 160, 212, 20, 213, 214, 13, 1, 
-	160, 165, 160, 20, 213, 214, 13, 1, 
-	160, 165, 160, 213, 213, 13, 1, 160, 
-	165, 160, 215, 17, 201, 216, 160, 1, 
-	160, 165, 160, 17, 201, 216, 160, 1, 
-	160, 165, 160, 194, 195, 199, 199, 4, 
-	1, 160, 165, 160, 194, 195, 196, 199, 
-	4, 1, 160, 165, 160, 160, 27, 160, 
-	192, 160, 217, 160, 201, 201, 160, 1, 
-	160, 165, 160, 160, 160, 160, 160, 192, 
-	160, 192, 160, 160, 160, 201, 201, 160, 
-	1, 160, 165, 160, 160, 160, 160, 160, 
-	192, 160, 192, 160, 160, 160, 201, 193, 
-	160, 1, 160, 165, 160, 160, 160, 160, 
-	160, 192, 160, 186, 187, 191, 191, 4, 
-	1, 160, 165, 160, 186, 187, 188, 191, 
-	4, 1, 160, 165, 160, 160, 29, 160, 
-	184, 160, 218, 160, 201, 201, 160, 1, 
-	160, 165, 160, 160, 160, 160, 160, 184, 
-	160, 184, 160, 160, 160, 201, 201, 160, 
-	1, 160, 165, 160, 160, 160, 160, 160, 
-	184, 160, 184, 160, 160, 160, 201, 185, 
-	160, 1, 160, 165, 160, 160, 160, 160, 
-	160, 184, 160, 178, 179, 183, 183, 4, 
-	1, 160, 165, 160, 178, 179, 180, 183, 
-	4, 1, 160, 165, 160, 160, 31, 160, 
-	176, 160, 219, 160, 201, 201, 160, 1, 
-	160, 165, 160, 160, 160, 160, 160, 176, 
-	160, 176, 160, 160, 160, 201, 201, 160, 
-	1, 160, 165, 160, 160, 160, 160, 160, 
-	176, 160, 176, 160, 160, 160, 201, 177, 
-	160, 1, 160, 165, 160, 160, 160, 160, 
-	160, 176, 160, 170, 171, 175, 175, 4, 
-	1, 160, 165, 160, 170, 171, 172, 175, 
-	4, 1, 160, 165, 160, 160, 33, 160, 
-	168, 160, 220, 160, 201, 201, 160, 1, 
-	160, 165, 160, 160, 160, 160, 160, 168, 
-	160, 168, 160, 160, 160, 201, 201, 160, 
-	1, 160, 165, 160, 160, 160, 160, 160, 
-	168, 160, 168, 160, 160, 160, 201, 169, 
-	160, 1, 160, 165, 160, 160, 160, 160, 
-	160, 168, 160, 161, 162, 167, 167, 4, 
-	1, 160, 165, 160, 161, 162, 163, 167, 
-	4, 1, 160, 165, 160, 160, 35, 160, 
-	222, 223, 224, 225, 40, 37, 221, 226, 
-	221, 221, 71, 221, 227, 223, 228, 225, 
-	40, 37, 221, 226, 221, 223, 228, 225, 
-	40, 37, 221, 226, 221, 229, 221, 221, 
-	221, 53, 230, 221, 37, 221, 226, 221, 
-	221, 221, 221, 221, 229, 221, 231, 232, 
-	233, 234, 40, 37, 221, 226, 221, 221, 
-	69, 221, 235, 232, 236, 236, 40, 37, 
-	221, 226, 221, 232, 236, 236, 40, 37, 
-	221, 226, 221, 237, 221, 221, 221, 53, 
-	238, 221, 37, 221, 226, 221, 221, 221, 
-	221, 221, 237, 221, 239, 240, 241, 242, 
-	40, 37, 221, 226, 221, 221, 67, 221, 
-	243, 240, 244, 244, 40, 37, 221, 226, 
-	221, 240, 244, 244, 40, 37, 221, 226, 
-	221, 245, 221, 221, 221, 53, 246, 221, 
-	37, 221, 226, 221, 221, 221, 221, 221, 
-	245, 221, 247, 248, 249, 250, 40, 37, 
-	221, 226, 221, 221, 65, 221, 251, 248, 
-	252, 252, 40, 37, 221, 226, 221, 248, 
-	252, 252, 40, 37, 221, 226, 221, 253, 
-	221, 221, 221, 53, 254, 221, 37, 221, 
-	226, 221, 221, 221, 221, 221, 253, 221, 
-	255, 256, 257, 258, 40, 37, 221, 226, 
-	221, 221, 63, 221, 259, 256, 260, 260, 
-	40, 37, 221, 226, 221, 256, 260, 260, 
-	40, 37, 221, 226, 221, 53, 261, 221, 
-	37, 221, 226, 221, 262, 262, 221, 37, 
-	221, 226, 221, 263, 221, 221, 264, 221, 
-	226, 221, 226, 221, 265, 221, 266, 221, 
-	263, 221, 221, 221, 221, 226, 221, 53, 
-	221, 262, 262, 221, 37, 221, 226, 221, 
-	262, 261, 221, 37, 221, 226, 221, 267, 
-	62, 268, 269, 43, 37, 221, 226, 221, 
-	62, 268, 269, 43, 37, 221, 226, 221, 
-	268, 268, 43, 37, 221, 226, 221, 270, 
-	59, 271, 272, 46, 37, 221, 226, 221, 
-	59, 271, 272, 46, 37, 221, 226, 221, 
-	271, 271, 46, 37, 221, 226, 221, 273, 
-	56, 274, 275, 49, 37, 221, 226, 221, 
-	56, 274, 275, 49, 37, 221, 226, 221, 
-	274, 274, 49, 37, 221, 226, 221, 276, 
-	53, 262, 277, 221, 37, 221, 226, 221, 
-	53, 262, 277, 221, 37, 221, 226, 221, 
-	255, 256, 260, 260, 40, 37, 221, 226, 
-	221, 255, 256, 257, 260, 40, 37, 221, 
-	226, 221, 221, 63, 221, 253, 221, 278, 
-	221, 262, 262, 221, 37, 221, 226, 221, 
-	221, 221, 221, 221, 253, 221, 253, 221, 
-	221, 221, 262, 262, 221, 37, 221, 226, 
-	221, 221, 221, 221, 221, 253, 221, 253, 
-	221, 221, 221, 262, 254, 221, 37, 221, 
-	226, 221, 221, 221, 221, 221, 253, 221, 
-	247, 248, 252, 252, 40, 37, 221, 226, 
-	221, 247, 248, 249, 252, 40, 37, 221, 
-	226, 221, 221, 65, 221, 245, 221, 279, 
-	221, 262, 262, 221, 37, 221, 226, 221, 
-	221, 221, 221, 221, 245, 221, 245, 221, 
-	221, 221, 262, 262, 221, 37, 221, 226, 
-	221, 221, 221, 221, 221, 245, 221, 245, 
-	221, 221, 221, 262, 246, 221, 37, 221, 
-	226, 221, 221, 221, 221, 221, 245, 221, 
-	239, 240, 244, 244, 40, 37, 221, 226, 
-	221, 239, 240, 241, 244, 40, 37, 221, 
-	226, 221, 221, 67, 221, 237, 221, 280, 
-	221, 262, 262, 221, 37, 221, 226, 221, 
-	221, 221, 221, 221, 237, 221, 237, 221, 
-	221, 221, 262, 262, 221, 37, 221, 226, 
-	221, 221, 221, 221, 221, 237, 221, 237, 
-	221, 221, 221, 262, 238, 221, 37, 221, 
-	226, 221, 221, 221, 221, 221, 237, 221, 
-	231, 232, 236, 236, 40, 37, 221, 226, 
-	221, 231, 232, 233, 236, 40, 37, 221, 
-	226, 221, 221, 69, 221, 229, 221, 281, 
-	221, 262, 262, 221, 37, 221, 226, 221, 
-	221, 221, 221, 221, 229, 221, 229, 221, 
-	221, 221, 262, 262, 221, 37, 221, 226, 
-	221, 221, 221, 221, 221, 229, 221, 229, 
-	221, 221, 221, 262, 230, 221, 37, 221, 
-	226, 221, 221, 221, 221, 221, 229, 221, 
-	70, 39, 39, 40, 37, 221, 222, 223, 
-	228, 225, 40, 37, 221, 226, 221, 283, 
-	151, 284, 284, 76, 73, 282, 154, 282, 
-	151, 284, 284, 76, 73, 282, 154, 282, 
-	285, 282, 282, 282, 90, 286, 282, 73, 
-	282, 154, 282, 282, 282, 282, 282, 285, 
-	282, 287, 288, 289, 290, 76, 73, 282, 
-	154, 282, 282, 106, 282, 291, 288, 292, 
-	292, 76, 73, 282, 154, 282, 288, 292, 
-	292, 76, 73, 282, 154, 282, 293, 282, 
-	282, 282, 90, 294, 282, 73, 282, 154, 
-	282, 282, 282, 282, 282, 293, 282, 295, 
-	296, 297, 298, 76, 73, 282, 154, 282, 
-	282, 104, 282, 299, 296, 300, 300, 76, 
-	73, 282, 154, 282, 296, 300, 300, 76, 
-	73, 282, 154, 282, 301, 282, 282, 282, 
-	90, 302, 282, 73, 282, 154, 282, 282, 
-	282, 282, 282, 301, 282, 303, 304, 305, 
-	306, 76, 73, 282, 154, 282, 282, 102, 
-	282, 307, 304, 308, 308, 76, 73, 282, 
-	154, 282, 304, 308, 308, 76, 73, 282, 
-	154, 282, 309, 282, 282, 282, 90, 310, 
-	282, 73, 282, 154, 282, 282, 282, 282, 
-	282, 309, 282, 311, 312, 313, 314, 76, 
-	73, 282, 154, 282, 282, 100, 282, 315, 
-	312, 316, 316, 76, 73, 282, 154, 282, 
-	312, 316, 316, 76, 73, 282, 154, 282, 
-	90, 317, 282, 73, 282, 154, 282, 318, 
-	318, 282, 73, 282, 154, 282, 319, 282, 
-	282, 320, 282, 154, 282, 154, 282, 321, 
-	282, 322, 282, 319, 282, 282, 282, 282, 
-	154, 282, 90, 282, 318, 318, 282, 73, 
-	282, 154, 282, 318, 317, 282, 73, 282, 
-	154, 282, 323, 99, 324, 325, 80, 73, 
-	282, 154, 282, 99, 324, 325, 80, 73, 
-	282, 154, 282, 324, 324, 80, 73, 282, 
-	154, 282, 326, 96, 327, 328, 83, 73, 
-	282, 154, 282, 96, 327, 328, 83, 73, 
-	282, 154, 282, 327, 327, 83, 73, 282, 
-	154, 282, 329, 93, 330, 331, 86, 73, 
-	282, 154, 282, 93, 330, 331, 86, 73, 
-	282, 154, 282, 330, 330, 86, 73, 282, 
-	154, 282, 332, 90, 318, 333, 282, 73, 
-	282, 154, 282, 90, 318, 333, 282, 73, 
-	282, 154, 282, 311, 312, 316, 316, 76, 
-	73, 282, 154, 282, 311, 312, 313, 316, 
-	76, 73, 282, 154, 282, 282, 100, 282, 
-	309, 282, 334, 282, 318, 318, 282, 73, 
-	282, 154, 282, 282, 282, 282, 282, 309, 
-	282, 309, 282, 282, 282, 318, 318, 282, 
-	73, 282, 154, 282, 282, 282, 282, 282, 
-	309, 282, 309, 282, 282, 282, 318, 310, 
-	282, 73, 282, 154, 282, 282, 282, 282, 
-	282, 309, 282, 303, 304, 308, 308, 76, 
-	73, 282, 154, 282, 303, 304, 305, 308, 
-	76, 73, 282, 154, 282, 282, 102, 282, 
-	301, 282, 335, 282, 318, 318, 282, 73, 
-	282, 154, 282, 282, 282, 282, 282, 301, 
-	282, 301, 282, 282, 282, 318, 318, 282, 
-	73, 282, 154, 282, 282, 282, 282, 282, 
-	301, 282, 301, 282, 282, 282, 318, 302, 
-	282, 73, 282, 154, 282, 282, 282, 282, 
-	282, 301, 282, 295, 296, 300, 300, 76, 
-	73, 282, 154, 282, 295, 296, 297, 300, 
-	76, 73, 282, 154, 282, 282, 104, 282, 
-	293, 282, 336, 282, 318, 318, 282, 73, 
-	282, 154, 282, 282, 282, 282, 282, 293, 
-	282, 293, 282, 282, 282, 318, 318, 282, 
-	73, 282, 154, 282, 282, 282, 282, 282, 
-	293, 282, 293, 282, 282, 282, 318, 294, 
-	282, 73, 282, 154, 282, 282, 282, 282, 
-	282, 293, 282, 287, 288, 292, 292, 76, 
-	73, 282, 154, 282, 287, 288, 289, 292, 
-	76, 73, 282, 154, 282, 282, 106, 282, 
-	285, 282, 337, 282, 318, 318, 282, 73, 
-	282, 154, 282, 282, 282, 282, 282, 285, 
-	282, 285, 282, 282, 282, 318, 318, 282, 
-	73, 282, 154, 282, 282, 282, 282, 282, 
-	285, 282, 285, 282, 282, 282, 318, 286, 
-	282, 73, 282, 154, 282, 282, 282, 282, 
-	282, 285, 282, 107, 75, 75, 76, 73, 
-	338, 338, 338, 338, 144, 338, 150, 151, 
-	284, 284, 76, 73, 282, 154, 282, 107, 
-	75, 75, 76, 73, 338, 340, 341, 342, 
-	343, 112, 109, 339, 344, 339, 339, 143, 
-	339, 345, 341, 343, 343, 112, 109, 339, 
-	344, 339, 341, 343, 343, 112, 109, 339, 
-	344, 339, 346, 339, 339, 339, 125, 347, 
-	339, 109, 339, 344, 339, 339, 339, 339, 
-	339, 346, 339, 348, 349, 350, 351, 112, 
-	109, 339, 344, 339, 339, 141, 339, 352, 
-	349, 353, 353, 112, 109, 339, 344, 339, 
-	349, 353, 353, 112, 109, 339, 344, 339, 
-	354, 339, 339, 339, 125, 355, 339, 109, 
-	339, 344, 339, 339, 339, 339, 339, 354, 
-	339, 356, 357, 358, 359, 112, 109, 339, 
-	344, 339, 339, 139, 339, 360, 357, 361, 
-	361, 112, 109, 339, 344, 339, 357, 361, 
-	361, 112, 109, 339, 344, 339, 362, 339, 
-	339, 339, 125, 363, 339, 109, 339, 344, 
-	339, 339, 339, 339, 339, 362, 339, 364, 
-	365, 366, 367, 112, 109, 339, 344, 339, 
-	339, 137, 339, 368, 365, 369, 369, 112, 
-	109, 339, 344, 339, 365, 369, 369, 112, 
-	109, 339, 344, 339, 370, 339, 339, 339, 
-	125, 371, 339, 109, 339, 344, 339, 339, 
-	339, 339, 339, 370, 339, 372, 373, 374, 
-	375, 112, 109, 339, 344, 339, 339, 135, 
-	339, 376, 373, 377, 377, 112, 109, 339, 
-	344, 339, 373, 377, 377, 112, 109, 339, 
-	344, 339, 125, 378, 339, 109, 339, 344, 
-	339, 379, 379, 339, 109, 339, 344, 339, 
-	380, 339, 339, 381, 339, 344, 339, 344, 
-	339, 382, 339, 383, 339, 380, 339, 339, 
-	339, 339, 344, 339, 125, 339, 379, 379, 
-	339, 109, 339, 344, 339, 379, 378, 339, 
-	109, 339, 344, 339, 384, 134, 385, 386, 
-	115, 109, 339, 344, 339, 134, 385, 386, 
-	115, 109, 339, 344, 339, 385, 385, 115, 
-	109, 339, 344, 339, 387, 131, 388, 389, 
-	118, 109, 339, 344, 339, 131, 388, 389, 
-	118, 109, 339, 344, 339, 388, 388, 118, 
-	109, 339, 344, 339, 390, 128, 391, 392, 
-	121, 109, 339, 344, 339, 128, 391, 392, 
-	121, 109, 339, 344, 339, 391, 391, 121, 
-	109, 339, 344, 339, 393, 125, 379, 394, 
-	339, 109, 339, 344, 339, 125, 379, 394, 
-	339, 109, 339, 344, 339, 372, 373, 377, 
-	377, 112, 109, 339, 344, 339, 372, 373, 
-	374, 377, 112, 109, 339, 344, 339, 339, 
-	135, 339, 370, 339, 395, 339, 379, 379, 
-	339, 109, 339, 344, 339, 339, 339, 339, 
-	339, 370, 339, 370, 339, 339, 339, 379, 
-	379, 339, 109, 339, 344, 339, 339, 339, 
-	339, 339, 370, 339, 370, 339, 339, 339, 
-	379, 371, 339, 109, 339, 344, 339, 339, 
-	339, 339, 339, 370, 339, 364, 365, 369, 
-	369, 112, 109, 339, 344, 339, 364, 365, 
-	366, 369, 112, 109, 339, 344, 339, 339, 
-	137, 339, 362, 339, 396, 339, 379, 379, 
-	339, 109, 339, 344, 339, 339, 339, 339, 
-	339, 362, 339, 362, 339, 339, 339, 379, 
-	379, 339, 109, 339, 344, 339, 339, 339, 
-	339, 339, 362, 339, 362, 339, 339, 339, 
-	379, 363, 339, 109, 339, 344, 339, 339, 
-	339, 339, 339, 362, 339, 356, 357, 361, 
-	361, 112, 109, 339, 344, 339, 356, 357, 
-	358, 361, 112, 109, 339, 344, 339, 339, 
-	139, 339, 354, 339, 397, 339, 379, 379, 
-	339, 109, 339, 344, 339, 339, 339, 339, 
-	339, 354, 339, 354, 339, 339, 339, 379, 
-	379, 339, 109, 339, 344, 339, 339, 339, 
-	339, 339, 354, 339, 354, 339, 339, 339, 
-	379, 355, 339, 109, 339, 344, 339, 339, 
-	339, 339, 339, 354, 339, 348, 349, 353, 
-	353, 112, 109, 339, 344, 339, 348, 349, 
-	350, 353, 112, 109, 339, 344, 339, 339, 
-	141, 339, 346, 339, 398, 339, 379, 379, 
-	339, 109, 339, 344, 339, 339, 339, 339, 
-	339, 346, 339, 346, 339, 339, 339, 379, 
-	379, 339, 109, 339, 344, 339, 339, 339, 
-	339, 339, 346, 339, 346, 339, 339, 339, 
-	379, 347, 339, 109, 339, 344, 339, 339, 
-	339, 339, 339, 346, 339, 340, 341, 343, 
-	343, 112, 109, 339, 344, 339, 148, 149, 
-	150, 151, 399, 284, 76, 73, 282, 154, 
-	155, 155, 144, 282, 282, 148, 282, 161, 
-	400, 163, 164, 4, 1, 160, 165, 160, 
-	160, 35, 160, 168, 149, 150, 151, 401, 
-	402, 76, 403, 160, 404, 160, 155, 144, 
-	160, 160, 168, 160, 107, 405, 405, 76, 
-	403, 160, 165, 160, 160, 144, 160, 406, 
-	160, 160, 407, 160, 404, 160, 404, 160, 
-	408, 160, 205, 160, 406, 160, 160, 160, 
-	160, 404, 160, 168, 160, 220, 107, 405, 
-	405, 76, 403, 160, 165, 160, 160, 160, 
-	160, 160, 168, 160, 410, 409, 411, 411, 
-	409, 146, 409, 412, 409, 411, 411, 409, 
-	146, 409, 412, 409, 413, 409, 409, 414, 
-	409, 412, 409, 412, 409, 415, 409, 416, 
-	409, 413, 409, 409, 409, 409, 412, 409, 
-	148, 338, 338, 338, 338, 338, 338, 338, 
-	338, 338, 155, 338, 338, 338, 338, 148, 
-	338, 0
+	3, 3, 4, 0, 3, 3, 4, 1, 
+	0, 5, 3, 3, 4, 1, 0, 6, 
+	0, 7, 0, 8, 3, 3, 4, 1, 
+	0, 2, 3, 3, 4, 1, 0, 0, 
+	0, 0, 9, 0, 11, 12, 12, 13, 
+	14, 10, 14, 10, 12, 12, 13, 10, 
+	12, 12, 13, 14, 10, 15, 12, 12, 
+	13, 14, 10, 16, 10, 17, 10, 18, 
+	12, 12, 13, 14, 10, 11, 12, 12, 
+	13, 14, 10, 10, 10, 10, 19, 10, 
+	11, 12, 12, 13, 14, 10, 10, 10, 
+	10, 20, 10, 22, 23, 23, 24, 25, 
+	21, 21, 21, 21, 26, 21, 25, 21, 
+	23, 23, 24, 27, 23, 23, 24, 25, 
+	21, 28, 23, 23, 24, 25, 21, 29, 
+	21, 30, 21, 22, 23, 23, 24, 25, 
+	21, 31, 23, 23, 24, 25, 21, 33, 
+	34, 34, 35, 36, 32, 32, 32, 32, 
+	37, 32, 36, 32, 34, 34, 35, 32, 
+	34, 34, 35, 36, 32, 38, 34, 34, 
+	35, 36, 32, 39, 32, 40, 32, 33, 
+	34, 34, 35, 36, 32, 41, 34, 34, 
+	35, 36, 32, 23, 23, 24, 1, 0, 
+	43, 42, 45, 46, 47, 48, 49, 50, 
+	24, 25, 44, 51, 52, 52, 26, 44, 
+	53, 54, 55, 56, 57, 44, 59, 60, 
+	61, 62, 4, 1, 58, 63, 58, 58, 
+	9, 58, 58, 58, 64, 58, 65, 60, 
+	66, 66, 4, 1, 58, 63, 58, 58, 
+	58, 58, 58, 58, 64, 58, 60, 66, 
+	66, 4, 1, 58, 63, 58, 58, 58, 
+	58, 58, 58, 64, 58, 45, 58, 58, 
+	58, 67, 68, 58, 1, 58, 63, 58, 
+	58, 58, 58, 58, 45, 58, 69, 69, 
+	58, 1, 58, 63, 58, 63, 58, 58, 
+	70, 58, 63, 58, 63, 58, 63, 58, 
+	58, 58, 58, 63, 58, 45, 58, 71, 
+	58, 69, 69, 58, 1, 58, 63, 58, 
+	58, 58, 58, 58, 45, 58, 45, 58, 
+	58, 58, 69, 69, 58, 1, 58, 63, 
+	58, 58, 58, 58, 58, 45, 58, 45, 
+	58, 58, 58, 69, 68, 58, 1, 58, 
+	63, 58, 58, 58, 58, 58, 45, 58, 
+	72, 7, 73, 74, 4, 1, 58, 63, 
+	58, 7, 73, 74, 4, 1, 58, 63, 
+	58, 73, 73, 4, 1, 58, 63, 58, 
+	75, 76, 76, 4, 1, 58, 63, 58, 
+	67, 77, 58, 1, 58, 63, 58, 67, 
+	58, 69, 69, 58, 1, 58, 63, 58, 
+	69, 77, 58, 1, 58, 63, 58, 59, 
+	60, 66, 66, 4, 1, 58, 63, 58, 
+	58, 58, 58, 58, 58, 64, 58, 59, 
+	60, 61, 66, 4, 1, 58, 63, 58, 
+	58, 9, 58, 58, 58, 64, 58, 79, 
+	80, 81, 82, 13, 14, 78, 83, 78, 
+	78, 20, 78, 78, 78, 84, 78, 85, 
+	80, 86, 82, 13, 14, 78, 83, 78, 
+	78, 78, 78, 78, 78, 84, 78, 80, 
+	86, 82, 13, 14, 78, 83, 78, 78, 
+	78, 78, 78, 78, 84, 78, 87, 78, 
+	78, 78, 88, 89, 78, 14, 78, 83, 
+	78, 78, 78, 78, 78, 87, 78, 90, 
+	80, 91, 92, 13, 14, 78, 83, 78, 
+	78, 19, 78, 78, 78, 84, 78, 93, 
+	80, 86, 86, 13, 14, 78, 83, 78, 
+	78, 78, 78, 78, 78, 84, 78, 80, 
+	86, 86, 13, 14, 78, 83, 78, 78, 
+	78, 78, 78, 78, 84, 78, 87, 78, 
+	78, 78, 94, 89, 78, 14, 78, 83, 
+	78, 78, 78, 78, 78, 87, 78, 83, 
+	78, 78, 95, 78, 83, 78, 83, 78, 
+	83, 78, 78, 78, 78, 83, 78, 87, 
+	78, 96, 78, 94, 94, 78, 14, 78, 
+	83, 78, 78, 78, 78, 78, 87, 78, 
+	87, 78, 78, 78, 94, 94, 78, 14, 
+	78, 83, 78, 78, 78, 78, 78, 87, 
+	78, 97, 17, 98, 99, 13, 14, 78, 
+	83, 78, 17, 98, 99, 13, 14, 78, 
+	83, 78, 98, 98, 13, 14, 78, 83, 
+	78, 100, 101, 101, 13, 14, 78, 83, 
+	78, 88, 102, 78, 14, 78, 83, 78, 
+	94, 94, 78, 14, 78, 83, 78, 88, 
+	78, 94, 94, 78, 14, 78, 83, 78, 
+	94, 102, 78, 14, 78, 83, 78, 90, 
+	80, 86, 86, 13, 14, 78, 83, 78, 
+	78, 78, 78, 78, 78, 84, 78, 90, 
+	80, 91, 86, 13, 14, 78, 83, 78, 
+	78, 19, 78, 78, 78, 84, 78, 11, 
+	12, 12, 13, 14, 78, 79, 80, 86, 
+	82, 13, 14, 78, 83, 78, 78, 78, 
+	78, 78, 78, 84, 78, 104, 48, 105, 
+	105, 24, 25, 103, 51, 103, 103, 103, 
+	103, 103, 103, 55, 103, 48, 105, 105, 
+	24, 25, 103, 51, 103, 103, 103, 103, 
+	103, 103, 55, 103, 106, 103, 103, 103, 
+	107, 108, 103, 25, 103, 51, 103, 103, 
+	103, 103, 103, 106, 103, 47, 48, 109, 
+	110, 24, 25, 103, 51, 103, 103, 26, 
+	103, 103, 103, 55, 103, 106, 103, 103, 
+	103, 111, 108, 103, 25, 103, 51, 103, 
+	103, 103, 103, 103, 106, 103, 51, 103, 
+	103, 112, 103, 51, 103, 51, 103, 51, 
+	103, 103, 103, 103, 51, 103, 106, 103, 
+	113, 103, 111, 111, 103, 25, 103, 51, 
+	103, 103, 103, 103, 103, 106, 103, 106, 
+	103, 103, 103, 111, 111, 103, 25, 103, 
+	51, 103, 103, 103, 103, 103, 106, 103, 
+	114, 30, 115, 116, 24, 25, 103, 51, 
+	103, 30, 115, 116, 24, 25, 103, 51, 
+	103, 115, 115, 24, 25, 103, 51, 103, 
+	47, 48, 105, 105, 24, 25, 103, 51, 
+	103, 103, 103, 103, 103, 103, 55, 103, 
+	117, 118, 118, 24, 25, 103, 51, 103, 
+	107, 119, 103, 25, 103, 51, 103, 111, 
+	111, 103, 25, 103, 51, 103, 107, 103, 
+	111, 111, 103, 25, 103, 51, 103, 111, 
+	119, 103, 25, 103, 51, 103, 47, 48, 
+	109, 105, 24, 25, 103, 51, 103, 103, 
+	26, 103, 103, 103, 55, 103, 22, 23, 
+	23, 24, 25, 120, 120, 120, 120, 26, 
+	120, 22, 23, 23, 24, 25, 120, 122, 
+	123, 124, 125, 35, 36, 121, 126, 121, 
+	121, 37, 121, 121, 121, 127, 121, 128, 
+	123, 125, 125, 35, 36, 121, 126, 121, 
+	121, 121, 121, 121, 121, 127, 121, 123, 
+	125, 125, 35, 36, 121, 126, 121, 121, 
+	121, 121, 121, 121, 127, 121, 129, 121, 
+	121, 121, 130, 131, 121, 36, 121, 126, 
+	121, 121, 121, 121, 121, 129, 121, 122, 
+	123, 124, 52, 35, 36, 121, 126, 121, 
+	121, 37, 121, 121, 121, 127, 121, 129, 
+	121, 121, 121, 132, 131, 121, 36, 121, 
+	126, 121, 121, 121, 121, 121, 129, 121, 
+	126, 121, 121, 133, 121, 126, 121, 126, 
+	121, 126, 121, 121, 121, 121, 126, 121, 
+	129, 121, 134, 121, 132, 132, 121, 36, 
+	121, 126, 121, 121, 121, 121, 121, 129, 
+	121, 129, 121, 121, 121, 132, 132, 121, 
+	36, 121, 126, 121, 121, 121, 121, 121, 
+	129, 121, 135, 40, 136, 137, 35, 36, 
+	121, 126, 121, 40, 136, 137, 35, 36, 
+	121, 126, 121, 136, 136, 35, 36, 121, 
+	126, 121, 122, 123, 125, 125, 35, 36, 
+	121, 126, 121, 121, 121, 121, 121, 121, 
+	127, 121, 138, 139, 139, 35, 36, 121, 
+	126, 121, 130, 140, 121, 36, 121, 126, 
+	121, 132, 132, 121, 36, 121, 126, 121, 
+	130, 121, 132, 132, 121, 36, 121, 126, 
+	121, 132, 140, 121, 36, 121, 126, 121, 
+	45, 46, 47, 48, 109, 105, 24, 25, 
+	103, 51, 52, 52, 26, 103, 103, 45, 
+	55, 103, 59, 141, 61, 62, 4, 1, 
+	58, 63, 58, 58, 9, 58, 58, 58, 
+	64, 58, 45, 46, 47, 48, 142, 143, 
+	24, 144, 58, 145, 58, 52, 26, 58, 
+	58, 45, 55, 58, 22, 146, 146, 24, 
+	144, 58, 63, 58, 58, 26, 58, 145, 
+	58, 58, 147, 58, 145, 58, 145, 58, 
+	145, 58, 58, 58, 58, 145, 58, 45, 
+	58, 71, 22, 146, 146, 24, 144, 58, 
+	63, 58, 58, 58, 58, 58, 45, 58, 
+	149, 148, 150, 150, 148, 43, 148, 151, 
+	148, 150, 150, 148, 43, 148, 151, 148, 
+	151, 148, 148, 152, 148, 151, 148, 151, 
+	148, 151, 148, 148, 148, 148, 151, 148, 
+	45, 120, 120, 120, 120, 120, 120, 120, 
+	120, 120, 52, 120, 120, 120, 120, 45, 
+	120, 0
 };
 
-static const short _indic_syllable_machine_trans_targs[] = {
-	138, 160, 166, 2, 167, 3, 5, 170, 
-	6, 8, 173, 9, 11, 176, 12, 14, 
-	15, 159, 17, 18, 175, 20, 21, 172, 
-	23, 24, 169, 178, 182, 183, 187, 188, 
-	192, 193, 197, 198, 138, 221, 227, 36, 
-	228, 37, 39, 231, 40, 42, 234, 43, 
-	45, 237, 46, 48, 49, 220, 51, 52, 
-	236, 54, 55, 233, 57, 58, 230, 239, 
-	243, 244, 248, 249, 253, 254, 258, 260, 
-	138, 281, 287, 70, 288, 138, 71, 73, 
-	291, 74, 76, 294, 77, 79, 297, 80, 
-	82, 83, 280, 85, 86, 296, 88, 89, 
-	293, 91, 92, 290, 299, 303, 304, 308, 
-	309, 313, 314, 318, 138, 343, 349, 103, 
-	350, 104, 106, 353, 107, 109, 356, 110, 
-	112, 359, 113, 115, 116, 342, 118, 119, 
-	358, 121, 122, 355, 124, 125, 352, 361, 
-	365, 366, 370, 371, 375, 376, 380, 381, 
-	320, 138, 394, 138, 139, 200, 261, 263, 
-	319, 321, 283, 322, 382, 383, 392, 399, 
-	138, 140, 142, 33, 199, 162, 141, 32, 
-	143, 195, 144, 146, 31, 194, 145, 30, 
-	147, 190, 148, 150, 29, 189, 149, 28, 
-	151, 185, 152, 154, 27, 184, 153, 26, 
-	155, 180, 156, 158, 25, 179, 157, 1, 
-	165, 0, 161, 164, 163, 138, 168, 4, 
-	22, 171, 7, 19, 174, 10, 16, 177, 
-	13, 181, 186, 191, 196, 138, 201, 203, 
-	67, 259, 223, 202, 66, 204, 256, 205, 
-	207, 65, 255, 206, 64, 208, 251, 209, 
-	211, 63, 250, 210, 62, 212, 246, 213, 
-	215, 61, 245, 214, 60, 216, 241, 217, 
-	219, 59, 240, 218, 35, 226, 34, 222, 
-	225, 224, 138, 229, 38, 56, 232, 41, 
-	53, 235, 44, 50, 238, 47, 242, 247, 
-	252, 257, 138, 262, 100, 264, 316, 265, 
-	267, 99, 315, 266, 98, 268, 311, 269, 
-	271, 97, 310, 270, 96, 272, 306, 273, 
-	275, 95, 305, 274, 94, 276, 301, 277, 
-	279, 93, 300, 278, 69, 286, 68, 282, 
-	285, 284, 138, 289, 72, 90, 292, 75, 
-	87, 295, 78, 84, 298, 81, 302, 307, 
-	312, 317, 138, 138, 323, 325, 134, 133, 
-	345, 324, 326, 378, 327, 329, 132, 377, 
-	328, 131, 330, 373, 331, 333, 130, 372, 
-	332, 129, 334, 368, 335, 337, 128, 367, 
-	336, 127, 338, 363, 339, 341, 126, 362, 
-	340, 102, 348, 101, 344, 347, 346, 138, 
-	351, 105, 123, 354, 108, 120, 357, 111, 
-	117, 360, 114, 364, 369, 374, 379, 135, 
-	384, 385, 391, 386, 388, 136, 387, 390, 
-	389, 138, 393, 137, 396, 395, 398, 397, 
-	138
+static const unsigned char _indic_syllable_machine_trans_targs[] = {
+	39, 45, 50, 2, 51, 5, 6, 53, 
+	57, 58, 39, 67, 11, 73, 68, 14, 
+	15, 75, 80, 81, 84, 39, 89, 21, 
+	95, 90, 98, 39, 24, 25, 97, 103, 
+	39, 112, 30, 118, 113, 121, 33, 34, 
+	120, 126, 39, 137, 39, 40, 60, 85, 
+	87, 105, 106, 91, 107, 127, 128, 99, 
+	135, 140, 39, 41, 43, 8, 59, 46, 
+	54, 42, 1, 44, 48, 0, 47, 49, 
+	52, 3, 4, 55, 7, 56, 39, 61, 
+	63, 18, 83, 69, 76, 62, 9, 64, 
+	78, 71, 65, 17, 82, 66, 10, 70, 
+	72, 74, 12, 13, 77, 16, 79, 39, 
+	86, 26, 88, 101, 93, 19, 104, 20, 
+	92, 94, 96, 22, 23, 100, 27, 102, 
+	39, 39, 108, 110, 28, 35, 114, 122, 
+	109, 111, 124, 116, 29, 115, 117, 119, 
+	31, 32, 123, 36, 125, 129, 130, 134, 
+	131, 132, 37, 133, 39, 136, 38, 138, 
+	139
 };
 
 static const char _indic_syllable_machine_trans_actions[] = {
 	1, 0, 2, 0, 2, 0, 0, 2, 
-	0, 0, 2, 0, 0, 2, 0, 0, 
-	0, 2, 0, 0, 2, 0, 0, 2, 
-	0, 0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 3, 0, 2, 0, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	0, 2, 0, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 0, 2, 2, 
-	2, 2, 2, 2, 2, 2, 2, 2, 
-	4, 0, 2, 0, 2, 5, 0, 0, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	0, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 6, 2, 6, 2, 
-	6, 2, 6, 2, 7, 0, 2, 0, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	0, 2, 0, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 0, 2, 2, 
-	2, 2, 2, 2, 2, 2, 2, 2, 
-	6, 8, 0, 11, 2, 2, 6, 0, 
-	12, 12, 0, 2, 6, 2, 2, 0, 
-	13, 2, 0, 0, 2, 0, 2, 0, 
-	2, 2, 2, 0, 0, 2, 2, 0, 
-	2, 2, 2, 0, 0, 2, 2, 0, 
-	2, 2, 2, 0, 0, 2, 2, 0, 
-	2, 2, 2, 0, 0, 2, 2, 0, 
-	2, 0, 0, 0, 0, 14, 2, 0, 
-	0, 2, 0, 0, 2, 0, 0, 2, 
-	0, 2, 2, 2, 2, 15, 2, 0, 
-	0, 2, 0, 2, 0, 2, 2, 2, 
-	0, 0, 2, 2, 0, 2, 2, 2, 
-	0, 0, 2, 2, 0, 2, 2, 2, 
-	0, 0, 2, 2, 0, 2, 2, 2, 
-	0, 0, 2, 2, 0, 2, 0, 0, 
-	0, 0, 16, 2, 0, 0, 2, 0, 
-	0, 2, 0, 0, 2, 0, 2, 2, 
-	2, 2, 17, 6, 0, 6, 2, 6, 
-	0, 0, 6, 6, 0, 6, 2, 6, 
-	0, 0, 6, 6, 0, 6, 2, 6, 
-	0, 0, 6, 6, 0, 6, 2, 6, 
-	0, 0, 6, 6, 0, 2, 0, 0, 
-	0, 0, 18, 2, 0, 0, 2, 0, 
-	0, 2, 0, 0, 2, 0, 2, 2, 
-	2, 2, 19, 20, 2, 0, 0, 0, 
-	0, 2, 2, 2, 2, 0, 0, 2, 
-	2, 0, 2, 2, 2, 0, 0, 2, 
-	2, 0, 2, 2, 2, 0, 0, 2, 
-	2, 0, 2, 2, 2, 0, 0, 2, 
-	2, 0, 2, 0, 0, 0, 0, 21, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	0, 2, 0, 2, 2, 2, 2, 0, 
-	0, 22, 22, 0, 0, 0, 0, 0, 
-	0, 23, 2, 0, 0, 0, 0, 0, 
-	24
+	2, 2, 3, 2, 0, 2, 0, 0, 
+	0, 2, 2, 2, 2, 4, 2, 0, 
+	5, 0, 5, 6, 0, 0, 5, 2, 
+	7, 2, 0, 2, 0, 2, 0, 0, 
+	2, 2, 8, 0, 11, 2, 2, 5, 
+	0, 12, 12, 0, 2, 5, 2, 5, 
+	2, 0, 13, 2, 0, 0, 2, 0, 
+	2, 2, 0, 2, 2, 0, 0, 2, 
+	2, 0, 0, 0, 0, 2, 14, 2, 
+	0, 0, 2, 0, 2, 2, 0, 2, 
+	2, 2, 2, 0, 2, 2, 0, 0, 
+	2, 2, 0, 0, 0, 0, 2, 15, 
+	5, 0, 5, 2, 2, 0, 5, 0, 
+	0, 2, 5, 0, 0, 0, 0, 2, 
+	16, 17, 2, 0, 0, 0, 0, 2, 
+	2, 2, 2, 2, 0, 0, 2, 2, 
+	0, 0, 0, 0, 2, 0, 18, 18, 
+	0, 0, 0, 0, 19, 2, 0, 0, 
+	0
 };
 
 static const char _indic_syllable_machine_to_state_actions[] = {
@@ -746,6 +319,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 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, 
@@ -758,40 +332,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 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
 };
 
 static const char _indic_syllable_machine_from_state_actions[] = {
@@ -799,6 +340,7 @@
 	0, 0, 0, 0, 0, 0, 0, 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, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
@@ -811,126 +353,61 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 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, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0
+	0, 0, 0, 0, 0
 };
 
 static const short _indic_syllable_machine_eof_trans[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 37, 37, 37, 37, 37, 37, 
-	37, 37, 37, 37, 37, 37, 37, 37, 
-	37, 37, 37, 37, 37, 37, 37, 37, 
-	37, 37, 37, 37, 37, 37, 37, 37, 
-	37, 37, 37, 37, 73, 73, 78, 78, 
-	73, 73, 73, 73, 73, 73, 73, 73, 
-	73, 73, 73, 73, 73, 73, 73, 73, 
-	73, 73, 73, 73, 73, 73, 73, 73, 
-	73, 73, 73, 73, 73, 109, 109, 109, 
-	109, 109, 109, 109, 109, 109, 109, 109, 
-	109, 109, 109, 109, 109, 109, 109, 109, 
-	109, 109, 109, 109, 109, 109, 109, 109, 
-	109, 109, 109, 109, 109, 109, 109, 73, 
-	1, 146, 0, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 222, 222, 222, 
-	222, 222, 222, 222, 222, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 283, 
-	283, 283, 283, 283, 283, 283, 283, 339, 
-	283, 339, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 340, 340, 
-	340, 340, 340, 340, 340, 340, 283, 161, 
-	161, 161, 161, 161, 161, 161, 161, 161, 
-	410, 410, 410, 410, 410, 410, 410, 339
+	1, 11, 11, 11, 11, 11, 11, 11, 
+	11, 11, 11, 22, 22, 28, 22, 22, 
+	22, 22, 22, 22, 33, 33, 33, 33, 
+	33, 33, 33, 33, 33, 1, 43, 0, 
+	59, 59, 59, 59, 59, 59, 59, 59, 
+	59, 59, 59, 59, 59, 59, 59, 59, 
+	59, 59, 59, 59, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 104, 104, 104, 
+	104, 104, 104, 104, 104, 104, 104, 104, 
+	104, 104, 104, 104, 104, 104, 104, 104, 
+	104, 121, 121, 122, 122, 122, 122, 122, 
+	122, 122, 122, 122, 122, 122, 122, 122, 
+	122, 122, 122, 122, 122, 122, 122, 104, 
+	59, 59, 59, 59, 59, 59, 59, 149, 
+	149, 149, 149, 149, 121
 };
 
-static const int indic_syllable_machine_start = 138;
-static const int indic_syllable_machine_first_final = 138;
+static const int indic_syllable_machine_start = 39;
+static const int indic_syllable_machine_first_final = 39;
 static const int indic_syllable_machine_error = -1;
 
-static const int indic_syllable_machine_en_main = 138;
+static const int indic_syllable_machine_en_main = 39;
 
 
 #line 36 "hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_indic (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 934 "hb-ot-shape-complex-indic-machine.hh"
+#line 411 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
@@ -938,7 +415,7 @@
 	act = 0;
 	}
 
-#line 112 "hb-ot-shape-complex-indic-machine.rl"
+#line 113 "hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
@@ -946,12 +423,12 @@
 
   unsigned int syllable_serial = 1;
   
-#line 950 "hb-ot-shape-complex-indic-machine.hh"
+#line 427 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	int _slen;
 	int _trans;
 	const unsigned char *_keys;
-	const short *_inds;
+	const unsigned char *_inds;
 	if ( p == pe )
 		goto _test_eof;
 _resume:
@@ -960,7 +437,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 964 "hb-ot-shape-complex-indic-machine.hh"
+#line 441 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -982,75 +459,55 @@
 #line 1 "NONE"
 	{te = p+1;}
 	break;
-	case 14:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (consonant_syllable); }}
-	break;
-	case 16:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (vowel_syllable); }}
-	break;
-	case 21:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (standalone_cluster); }}
-	break;
-	case 24:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (symbol_cluster); }}
-	break;
-	case 18:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
-	{te = p+1;{ found_syllable (broken_cluster); }}
-	break;
 	case 11:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 13:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
-	case 15:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+	case 14:
+#line 85 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (vowel_syllable); }}
 	break;
-	case 20:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
+	case 17:
+#line 86 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (standalone_cluster); }}
 	break;
-	case 23:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
+	case 19:
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (symbol_cluster); }}
 	break;
-	case 17:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+	case 15:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
-	case 19:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+	case 16:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 1:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
 	break;
 	case 3:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+#line 85 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
 	break;
 	case 7:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
+#line 86 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
 	break;
 	case 8:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
 	break;
 	case 4:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
 	break;
-	case 5:
+	case 6:
 #line 1 "NONE"
 	{	switch( act ) {
 	case 1:
@@ -1065,25 +522,25 @@
 	}
 	}
 	break;
-	case 22:
+	case 18:
 #line 1 "NONE"
 	{te = p+1;}
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 1;}
 	break;
-	case 6:
+	case 5:
 #line 1 "NONE"
 	{te = p+1;}
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 5;}
 	break;
 	case 12:
 #line 1 "NONE"
 	{te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 6;}
 	break;
-#line 1087 "hb-ot-shape-complex-indic-machine.hh"
+#line 544 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 _again:
@@ -1092,7 +549,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 1096 "hb-ot-shape-complex-indic-machine.hh"
+#line 553 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -1108,8 +565,10 @@
 
 	}
 
-#line 120 "hb-ot-shape-complex-indic-machine.rl"
+#line 121 "hb-ot-shape-complex-indic-machine.rl"
 
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index c5d945d..5f819bd 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -52,6 +52,7 @@
 RS    = 13;
 Repha = 15;
 Ra    = 16;
+CM    = 17;
 Symbol= 18;
 CS    = 19;
 
@@ -63,14 +64,14 @@
 cn = c.ZWJ?.n?;
 forced_rakar = ZWJ H ZWJ Ra;
 symbol = Symbol.N?;
-matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
-syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}?;
+matra_group = z*.M.N?.(H | forced_rakar)?;
+syllable_tail = (z?.SM.SM?.ZWNJ?)? A*;
 halant_group = (z?.H.(ZWJ.N?)?);
 final_halant_group = halant_group | H.ZWNJ;
-halant_or_matra_group = (final_halant_group | matra_group{0,4});
+medial_group = CM?;
+halant_or_matra_group = (final_halant_group | matra_group*);
 
-complex_syllable_tail = (halant_group.cn){0,4} halant_or_matra_group syllable_tail;
-
+complex_syllable_tail = (halant_group.cn)* medial_group halant_or_matra_group syllable_tail;
 
 consonant_syllable =	(Repha|CS)? cn complex_syllable_tail;
 vowel_syllable =	reph? V.n? (ZWJ | complex_syllable_tail);
@@ -95,13 +96,13 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_indic (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
@@ -120,4 +121,6 @@
   }%%
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
index b7e4e7c..cc91f17 100644
--- a/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -6,69 +6,77 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-11.0.0.txt
- * # Date: 2018-05-21, 18:33:00 GMT [KW, RP]
- * # IndicPositionalCategory-11.0.0.txt
- * # Date: 2018-02-05, 16:21:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # IndicSyllabicCategory-12.0.0.txt
+ * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
+ * # IndicPositionalCategory-12.0.0.txt
+ * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
+ * # Blocks-12.0.0.txt
+ * # Date: 2018-07-30, 19:40:00 GMT [KW]
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-indic.hh"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
 
-#define ISC_A	INDIC_SYLLABIC_CATEGORY_AVAGRAHA		/*  16 chars; Avagraha */
-#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  83 chars; Bindu */
-#define ISC_BJN	INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER	/*  20 chars; Brahmi_Joining_Number */
-#define ISC_Ca	INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK	/*  58 chars; Cantillation_Mark */
-#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 2110 chars; Consonant */
-#define ISC_CD	INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD		/*  10 chars; Consonant_Dead */
-#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  67 chars; Consonant_Final */
-#define ISC_CHL	INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	/*   5 chars; Consonant_Head_Letter */
-#define ISC_CIP	INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED	/*   1 chars; Consonant_Initial_Postfixed */
-#define ISC_CK	INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER	/*   2 chars; Consonant_Killer */
-#define ISC_CM	INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	/*  28 chars; Consonant_Medial */
-#define ISC_CP	INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	/*  21 chars; Consonant_Placeholder */
-#define ISC_CPR	INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA	/*   2 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf	INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED	/*   7 chars; Consonant_Prefixed */
-#define ISC_CS	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED	/*  95 chars; Consonant_Subjoined */
-#define ISC_CSR	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA	/*   4 chars; Consonant_Succeeding_Repha */
-#define ISC_CWS	INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	/*   6 chars; Consonant_With_Stacker */
-#define ISC_GM	INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		/*   3 chars; Gemination_Mark */
-#define ISC_IS	INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER	/*  11 chars; Invisible_Stacker */
-#define ISC_ZWJ	INDIC_SYLLABIC_CATEGORY_JOINER			/*   1 chars; Joiner */
-#define ISC_ML	INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER	/*   1 chars; Modifying_Letter */
-#define ISC_ZWNJ	INDIC_SYLLABIC_CATEGORY_NON_JOINER		/*   1 chars; Non_Joiner */
-#define ISC_N	INDIC_SYLLABIC_CATEGORY_NUKTA			/*  30 chars; Nukta */
-#define ISC_Nd	INDIC_SYLLABIC_CATEGORY_NUMBER			/* 480 chars; Number */
-#define ISC_NJ	INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER		/*   1 chars; Number_Joiner */
-#define ISC_x	INDIC_SYLLABIC_CATEGORY_OTHER			/*   1 chars; Other */
-#define ISC_PK	INDIC_SYLLABIC_CATEGORY_PURE_KILLER		/*  21 chars; Pure_Killer */
-#define ISC_RS	INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER	/*   2 chars; Register_Shifter */
-#define ISC_SM	INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER	/*  25 chars; Syllable_Modifier */
-#define ISC_TL	INDIC_SYLLABIC_CATEGORY_TONE_LETTER		/*   7 chars; Tone_Letter */
-#define ISC_TM	INDIC_SYLLABIC_CATEGORY_TONE_MARK		/*  42 chars; Tone_Mark */
-#define ISC_V	INDIC_SYLLABIC_CATEGORY_VIRAMA			/*  25 chars; Virama */
-#define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  36 chars; Visarga */
-#define ISC_Vo	INDIC_SYLLABIC_CATEGORY_VOWEL			/*  30 chars; Vowel */
-#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 660 chars; Vowel_Dependent */
-#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/* 464 chars; Vowel_Independent */
+#define ISC_A    INDIC_SYLLABIC_CATEGORY_AVAGRAHA                    /*   17 chars; Avagraha */
+#define ISC_Bi   INDIC_SYLLABIC_CATEGORY_BINDU                       /*   86 chars; Bindu */
+#define ISC_BJN  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER       /*   20 chars; Brahmi_Joining_Number */
+#define ISC_Ca   INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK           /*   59 chars; Cantillation_Mark */
+#define ISC_C    INDIC_SYLLABIC_CATEGORY_CONSONANT                   /* 2160 chars; Consonant */
+#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   12 chars; Consonant_Dead */
+#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   67 chars; Consonant_Final */
+#define ISC_CHL  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER       /*    5 chars; Consonant_Head_Letter */
+#define ISC_CIP  INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /*    1 chars; Consonant_Initial_Postfixed */
+#define ISC_CK   INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER            /*    2 chars; Consonant_Killer */
+#define ISC_CM   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL            /*   29 chars; Consonant_Medial */
+#define ISC_CP   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER       /*   22 chars; Consonant_Placeholder */
+#define ISC_CPR  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA   /*    2 chars; Consonant_Preceding_Repha */
+#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED          /*    9 chars; Consonant_Prefixed */
+#define ISC_CS   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED         /*   94 chars; Consonant_Subjoined */
+#define ISC_CSR  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA  /*    4 chars; Consonant_Succeeding_Repha */
+#define ISC_CWS  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER      /*    6 chars; Consonant_With_Stacker */
+#define ISC_GM   INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK             /*    3 chars; Gemination_Mark */
+#define ISC_IS   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER           /*   11 chars; Invisible_Stacker */
+#define ISC_ZWJ  INDIC_SYLLABIC_CATEGORY_JOINER                      /*    1 chars; Joiner */
+#define ISC_ML   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER            /*    1 chars; Modifying_Letter */
+#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER                  /*    1 chars; Non_Joiner */
+#define ISC_N    INDIC_SYLLABIC_CATEGORY_NUKTA                       /*   30 chars; Nukta */
+#define ISC_Nd   INDIC_SYLLABIC_CATEGORY_NUMBER                      /*  481 chars; Number */
+#define ISC_NJ   INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER               /*    1 chars; Number_Joiner */
+#define ISC_x    INDIC_SYLLABIC_CATEGORY_OTHER                       /*    1 chars; Other */
+#define ISC_PK   INDIC_SYLLABIC_CATEGORY_PURE_KILLER                 /*   21 chars; Pure_Killer */
+#define ISC_RS   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER            /*    2 chars; Register_Shifter */
+#define ISC_SM   INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER           /*   25 chars; Syllable_Modifier */
+#define ISC_TL   INDIC_SYLLABIC_CATEGORY_TONE_LETTER                 /*    7 chars; Tone_Letter */
+#define ISC_TM   INDIC_SYLLABIC_CATEGORY_TONE_MARK                   /*   42 chars; Tone_Mark */
+#define ISC_V    INDIC_SYLLABIC_CATEGORY_VIRAMA                      /*   27 chars; Virama */
+#define ISC_Vs   INDIC_SYLLABIC_CATEGORY_VISARGA                     /*   35 chars; Visarga */
+#define ISC_Vo   INDIC_SYLLABIC_CATEGORY_VOWEL                       /*   30 chars; Vowel */
+#define ISC_M    INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT             /*  673 chars; Vowel_Dependent */
+#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  476 chars; Vowel_Independent */
 
-#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/* 340 chars; Bottom */
-#define IMC_BL	INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT		/*   1 chars; Bottom_And_Left */
-#define IMC_BR	INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT		/*   2 chars; Bottom_And_Right */
-#define IMC_L	INDIC_MATRA_CATEGORY_LEFT			/*  59 chars; Left */
-#define IMC_LR	INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT		/*  21 chars; Left_And_Right */
-#define IMC_x	INDIC_MATRA_CATEGORY_NOT_APPLICABLE		/*   1 chars; Not_Applicable */
-#define IMC_O	INDIC_MATRA_CATEGORY_OVERSTRUCK			/*  10 chars; Overstruck */
-#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/* 276 chars; Right */
-#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/* 393 chars; Top */
-#define IMC_TB	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM		/*  10 chars; Top_And_Bottom */
-#define IMC_TBR	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT	/*   1 chars; Top_And_Bottom_And_Right */
-#define IMC_TL	INDIC_MATRA_CATEGORY_TOP_AND_LEFT		/*   6 chars; Top_And_Left */
-#define IMC_TLR	INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT	/*   4 chars; Top_And_Left_And_Right */
-#define IMC_TR	INDIC_MATRA_CATEGORY_TOP_AND_RIGHT		/*  13 chars; Top_And_Right */
-#define IMC_VOL	INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT		/*  19 chars; Visual_Order_Left */
+#define IMC_B    INDIC_MATRA_CATEGORY_BOTTOM                         /*  349 chars; Bottom */
+#define IMC_BL   INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT                /*    1 chars; Bottom_And_Left */
+#define IMC_BR   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT               /*    2 chars; Bottom_And_Right */
+#define IMC_L    INDIC_MATRA_CATEGORY_LEFT                           /*   61 chars; Left */
+#define IMC_LR   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                 /*   21 chars; Left_And_Right */
+#define IMC_x    INDIC_MATRA_CATEGORY_NOT_APPLICABLE                 /*    1 chars; Not_Applicable */
+#define IMC_O    INDIC_MATRA_CATEGORY_OVERSTRUCK                     /*   10 chars; Overstruck */
+#define IMC_R    INDIC_MATRA_CATEGORY_RIGHT                          /*  281 chars; Right */
+#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  398 chars; Top */
+#define IMC_TB   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                 /*   10 chars; Top_And_Bottom */
+#define IMC_TBR  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT       /*    1 chars; Top_And_Bottom_And_Right */
+#define IMC_TL   INDIC_MATRA_CATEGORY_TOP_AND_LEFT                   /*    6 chars; Top_And_Left */
+#define IMC_TLR  INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT         /*    4 chars; Top_And_Left_And_Right */
+#define IMC_TR   INDIC_MATRA_CATEGORY_TOP_AND_RIGHT                  /*   13 chars; Top_And_Right */
+#define IMC_VOL  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT              /*   19 chars; Visual_Order_Left */
+
+#pragma GCC diagnostic pop
 
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
 
@@ -149,7 +157,7 @@
   /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(x,x),  _(M,R),  _(M,L),
   /* 0A40 */  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),
   /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
-  /* 0A50 */  _(x,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0A50 */  _(x,x), _(Ca,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 0A58 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),
   /* 0A60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -234,7 +242,7 @@
 
   /* Kannada */
 
-  /* 0C80 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0C90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -343,8 +351,8 @@
   /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
   /* 1CE0 */ _(Ca,T), _(Ca,R),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),
   /* 1CE8 */  _(x,O),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,B),  _(x,x),  _(x,x),
-  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
-  /* 1CF8 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
+  /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
 #define indic_offset_0x2008u 1656
 
@@ -432,6 +440,7 @@
 }
 
 #undef _
+
 #undef ISC_A
 #undef ISC_Bi
 #undef ISC_BJN
@@ -468,6 +477,7 @@
 #undef ISC_Vo
 #undef ISC_M
 #undef ISC_VI
+
 #undef IMC_B
 #undef IMC_BL
 #undef IMC_BR
@@ -484,4 +494,6 @@
 #undef IMC_TR
 #undef IMC_VOL
 
+#endif
+
 /* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index d2d0a5a..26dc60d 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-indic.hh"
 #include "hb-ot-shape-complex-vowel-constraints.hh"
 #include "hb-ot-layout.hh"
@@ -127,62 +131,47 @@
   {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  {HB_TAG('d','i','s','t'), F_GLOBAL},
-  {HB_TAG('a','b','v','m'), F_GLOBAL},
-  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
 /*
  * Must be in the same order as the indic_features array.
  */
 enum {
-  _NUKT,
-  _AKHN,
-  RPHF,
-  _RKRF,
-  PREF,
-  BLWF,
-  ABVF,
-  HALF,
-  PSTF,
-  _VATU,
-  _CJCT,
+  _INDIC_NUKT,
+  _INDIC_AKHN,
+  INDIC_RPHF,
+  _INDIC_RKRF,
+  INDIC_PREF,
+  INDIC_BLWF,
+  INDIC_ABVF,
+  INDIC_HALF,
+  INDIC_PSTF,
+  _INDIC_VATU,
+  _INDIC_CJCT,
 
-  INIT,
-  _PRES,
-  _ABVS,
-  _BLWS,
-  _PSTS,
-  _HALN,
-
-  _DIST,
-  _ABVM,
-  _BLWM,
+  INDIC_INIT,
+  _INDIC_PRES,
+  _INDIC_ABVS,
+  _INDIC_BLWS,
+  _INDIC_PSTS,
+  _INDIC_HALN,
 
   INDIC_NUM_FEATURES,
-  INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */
+  INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */
 };
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
+setup_syllables_indic (const hb_ot_shape_plan_t *plan,
+		       hb_font_t *font,
+		       hb_buffer_t *buffer);
 static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-		    hb_font_t *font,
-		    hb_buffer_t *buffer);
+initial_reordering_indic (const hb_ot_shape_plan_t *plan,
+			  hb_font_t *font,
+			  hb_buffer_t *buffer);
 static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-		  hb_font_t *font,
-		  hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
+final_reordering_indic (const hb_ot_shape_plan_t *plan,
+			hb_font_t *font,
+			hb_buffer_t *buffer);
 
 static void
 collect_features_indic (hb_ot_shape_planner_t *plan)
@@ -190,7 +179,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_indic);
 
   map->enable_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
@@ -199,14 +188,14 @@
 
 
   unsigned int i = 0;
-  map->add_gsub_pause (initial_reordering);
+  map->add_gsub_pause (initial_reordering_indic);
 
   for (; i < INDIC_BASIC_FEATURES; i++) {
     map->add_feature (indic_features[i]);
     map->add_gsub_pause (nullptr);
   }
 
-  map->add_gsub_pause (final_reordering);
+  map->add_gsub_pause (final_reordering_indic);
 
   for (; i < INDIC_NUM_FEATURES; i++)
     map->add_feature (indic_features[i]);
@@ -214,7 +203,7 @@
   map->enable_feature (HB_TAG('c','a','l','t'));
   map->enable_feature (HB_TAG('c','l','i','g'));
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 }
 
 static void
@@ -224,32 +213,6 @@
 }
 
 
-struct would_substitute_feature_t
-{
-  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
-  {
-    zero_context = zero_context_;
-    map->get_stage_lookups (0/*GSUB*/,
-			    map->get_feature_stage (0/*GSUB*/, feature_tag),
-			    &lookups, &count);
-  }
-
-  bool would_substitute (const hb_codepoint_t *glyphs,
-			 unsigned int          glyphs_count,
-			 hb_face_t            *face) const
-  {
-    for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
-	return true;
-    return false;
-  }
-
-  private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
-  bool zero_context;
-};
-
 struct indic_shape_plan_t
 {
   bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
@@ -274,13 +237,17 @@
   const indic_config_t *config;
 
   bool is_old_spec;
+#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
   bool uniscribe_bug_compatible;
+#else
+  static constexpr bool uniscribe_bug_compatible = false;
+#endif
   mutable hb_atomic_int_t virama_glyph;
 
-  would_substitute_feature_t rphf;
-  would_substitute_feature_t pref;
-  would_substitute_feature_t blwf;
-  would_substitute_feature_t pstf;
+  hb_indic_would_substitute_feature_t rphf;
+  hb_indic_would_substitute_feature_t pref;
+  hb_indic_would_substitute_feature_t blwf;
+  hb_indic_would_substitute_feature_t pstf;
 
   hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
@@ -300,7 +267,9 @@
     }
 
   indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
   indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
+#endif
   indic_plan->virama_glyph.set_relaxed (-1);
 
   /* Use zero-context would_substitute() matching for new-spec of the main
@@ -361,13 +330,13 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  vowel_syllable,
-  standalone_cluster,
-  symbol_cluster,
-  broken_cluster,
-  non_indic_cluster,
+enum indic_syllable_type_t {
+  indic_consonant_syllable,
+  indic_vowel_syllable,
+  indic_standalone_cluster,
+  indic_symbol_cluster,
+  indic_broken_cluster,
+  indic_non_indic_cluster,
 };
 
 #include "hb-ot-shape-complex-indic-machine.hh"
@@ -391,11 +360,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
+setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		       hb_font_t *font HB_UNUSED,
+		       hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_indic (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -412,9 +381,9 @@
 
 
 static void
-update_consonant_positions (const hb_ot_shape_plan_t *plan,
-			    hb_font_t         *font,
-			    hb_buffer_t       *buffer)
+update_consonant_positions_indic (const hb_ot_shape_plan_t *plan,
+				  hb_font_t         *font,
+				  hb_buffer_t       *buffer)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
@@ -487,7 +456,7 @@
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
-    if (indic_plan->mask_array[RPHF] &&
+    if (indic_plan->mask_array[INDIC_RPHF] &&
 	start + 3 <= end &&
 	(
 	 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
@@ -571,7 +540,7 @@
 
       case BASE_POS_LAST_SINHALA:
       {
-        /* Sinhala base positioning is slightly different from main Indic, in that:
+	/* Sinhala base positioning is slightly different from main Indic, in that:
 	 * 1. Its ZWJ behavior is different,
 	 * 2. We don't need to look into the font for consonant positions.
 	 */
@@ -645,7 +614,7 @@
   /* Reorder characters */
 
   for (unsigned int i = start; i < base; i++)
-    info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
+    info[i].indic_position() = hb_min (POS_PRE_C, (indic_position_t) info[i].indic_position());
 
   if (base < end)
     info[base].indic_position() = POS_BASE_C;
@@ -700,8 +669,8 @@
     for (unsigned int i = base + 1; i < end; i++)
       if (info[i].indic_category() == OT_H)
       {
-        unsigned int j;
-        for (j = end - 1; j > i; j--)
+	unsigned int j;
+	for (j = end - 1; j > i; j--)
 	  if (is_consonant (info[j]) ||
 	      (disallow_double_halants && info[j].indic_category() == OT_H))
 	    break;
@@ -711,7 +680,7 @@
 	  memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
 	  info[j] = t;
 	}
-        break;
+	break;
       }
   }
 
@@ -720,7 +689,7 @@
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
-      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H))))
+      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H))))
       {
 	info[i].indic_position() = last_pos;
 	if (unlikely (info[i].indic_category() == OT_H &&
@@ -742,7 +711,7 @@
 	    }
 	}
       } else if (info[i].indic_position() != POS_SMVD) {
-        last_pos = (indic_position_t) info[i].indic_position();
+	last_pos = (indic_position_t) info[i].indic_position();
       }
     }
   }
@@ -758,7 +727,7 @@
 	    info[j].indic_position() = info[i].indic_position();
 	last = i;
       } else if (info[i].indic_category() == OT_M)
-        last = i;
+	last = i;
   }
 
 
@@ -795,13 +764,13 @@
     {
       /* Note!  syllable() is a one-byte field. */
       for (unsigned int i = base; i < end; i++)
-        if (info[i].syllable() != 255)
+	if (info[i].syllable() != 255)
 	{
 	  unsigned int max = i;
 	  unsigned int j = start + info[i].syllable();
 	  while (j != i)
 	  {
-	    max = MAX (max, j);
+	    max = hb_max (max, j);
 	    unsigned int next = start + info[j].syllable();
 	    info[j].syllable() = 255; /* So we don't process j later again. */
 	    j = next;
@@ -823,13 +792,13 @@
 
     /* Reph */
     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
-      info[i].mask |= indic_plan->mask_array[RPHF];
+      info[i].mask |= indic_plan->mask_array[INDIC_RPHF];
 
     /* Pre-base */
-    mask = indic_plan->mask_array[HALF];
+    mask = indic_plan->mask_array[INDIC_HALF];
     if (!indic_plan->is_old_spec &&
 	indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
-      mask |= indic_plan->mask_array[BLWF];
+      mask |= indic_plan->mask_array[INDIC_BLWF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;
     /* Base */
@@ -837,7 +806,9 @@
     if (base < end)
       info[base].mask |= mask;
     /* Post-base */
-    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
+    mask = indic_plan->mask_array[INDIC_BLWF] |
+	   indic_plan->mask_array[INDIC_ABVF] |
+	   indic_plan->mask_array[INDIC_PSTF];
     for (unsigned int i = base + 1; i < end; i++)
       info[i].mask  |= mask;
   }
@@ -869,23 +840,23 @@
 	  (i + 2 == base ||
 	   info[i+2].indic_category() != OT_ZWJ))
       {
-	info[i  ].mask |= indic_plan->mask_array[BLWF];
-	info[i+1].mask |= indic_plan->mask_array[BLWF];
+	info[i  ].mask |= indic_plan->mask_array[INDIC_BLWF];
+	info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF];
       }
   }
 
   unsigned int pref_len = 2;
-  if (indic_plan->mask_array[PREF] && base + pref_len < end)
+  if (indic_plan->mask_array[INDIC_PREF] && base + pref_len < end)
   {
     /* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */
     for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
       hb_codepoint_t glyphs[2];
       for (unsigned int j = 0; j < pref_len; j++)
-        glyphs[j] = info[i + j].codepoint;
+	glyphs[j] = info[i + j].codepoint;
       if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
       {
 	for (unsigned int j = 0; j < pref_len; j++)
-	  info[i++].mask |= indic_plan->mask_array[PREF];
+	  info[i++].mask |= indic_plan->mask_array[INDIC_PREF];
 	break;
       }
     }
@@ -906,7 +877,7 @@
 
 	/* A ZWNJ disables HALF. */
 	if (non_joiner)
-	  info[j].mask &= ~indic_plan->mask_array[HALF];
+	  info[j].mask &= ~indic_plan->mask_array[INDIC_HALF];
 
       } while (j > start && !is_consonant (info[j]));
     }
@@ -918,11 +889,10 @@
 				       hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
-  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
-
   /* We treat placeholder/dotted-circle as if they are consonants, so we
    * should just chain.  Only if not in compatibility mode that is... */
 
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   if (indic_plan->uniscribe_bug_compatible)
   {
     /* For dotted-circle, this is what Uniscribe does:
@@ -936,42 +906,45 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-			     hb_face_t *face,
-			     hb_buffer_t *buffer,
-			     unsigned int start, unsigned int end)
+initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
+				   hb_face_t *face,
+				   hb_buffer_t *buffer,
+				   unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  indic_syllable_type_t syllable_type = (indic_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type)
   {
-    case vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
-    case consonant_syllable:
+    case indic_vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
+    case indic_consonant_syllable:
      initial_reordering_consonant_syllable (plan, face, buffer, start, end);
      break;
 
-    case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
-    case standalone_cluster:
+    case indic_broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
+    case indic_standalone_cluster:
      initial_reordering_standalone_cluster (plan, face, buffer, start, end);
      break;
 
-    case symbol_cluster:
-    case non_indic_cluster:
+    case indic_symbol_cluster:
+    case indic_non_indic_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		       hb_font_t *font,
-		       hb_buffer_t *buffer)
+insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			     hb_font_t *font,
+			     hb_buffer_t *buffer)
 {
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
   /* Note: This loop is extra overhead, but should not be measurable.
    * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == indic_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -996,8 +969,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -1005,13 +978,12 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().indic_category() == OT_Repha)
-        buffer->next_glyph ();
+	buffer->next_glyph ();
 
       buffer->output_info (ginfo);
     }
@@ -1022,21 +994,21 @@
 }
 
 static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-		    hb_font_t *font,
-		    hb_buffer_t *buffer)
+initial_reordering_indic (const hb_ot_shape_plan_t *plan,
+			  hb_font_t *font,
+			  hb_buffer_t *buffer)
 {
-  update_consonant_positions (plan, font, buffer);
-  insert_dotted_circles (plan, font, buffer);
+  update_consonant_positions_indic (plan, font, buffer);
+  insert_dotted_circles_indic (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
 }
 
 static void
-final_reordering_syllable (const hb_ot_shape_plan_t *plan,
-			   hb_buffer_t *buffer,
-			   unsigned int start, unsigned int end)
+final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
+				 hb_buffer_t *buffer,
+				 unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
@@ -1057,7 +1029,7 @@
 	  _hb_glyph_info_ligated (&info[i]) &&
 	  _hb_glyph_info_multiplied (&info[i]))
       {
-        /* This will make sure that this glyph passes is_halant() test. */
+	/* This will make sure that this glyph passes is_halant() test. */
 	info[i].indic_category() = OT_H;
 	_hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
       }
@@ -1072,7 +1044,7 @@
    * syllable.
    */
 
-  bool try_pref = !!indic_plan->mask_array[PREF];
+  bool try_pref = !!indic_plan->mask_array[INDIC_PREF];
 
   /* Find base again */
   unsigned int base;
@@ -1082,7 +1054,7 @@
       if (try_pref && base + 1 < end)
       {
 	for (unsigned int i = base + 1; i < end; i++)
-	  if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+	  if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0)
 	  {
 	    if (!(_hb_glyph_info_substituted (&info[i]) &&
 		  _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
@@ -1120,7 +1092,7 @@
       }
 
       if (start < base && info[base].indic_position() > POS_BASE_C)
-        base--;
+	base--;
       break;
     }
   if (base == end && start < base &&
@@ -1199,13 +1171,18 @@
 	      goto search;
 	    }
 	  }
-	  /* -> If ZWNJ follows this halant, position is moved after it. */
-	  if (info[new_pos + 1].indic_category() == OT_ZWNJ)
-	    new_pos++;
+	  /* -> If ZWNJ follows this halant, position is moved after it.
+	   *
+	   * IMPLEMENTATION NOTES:
+	   *
+	   * This is taken care of by the state-machine. A Halant,ZWNJ is a terminating
+	   * sequence for a consonant syllable; any pre-base matras occurring after it
+	   * will belong to the subsequent syllable.
+	   */
 	}
       }
       else
-        new_pos = start; /* No move. */
+	new_pos = start; /* No move. */
     }
 
     if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
@@ -1224,14 +1201,14 @@
 
 	  /* Note: this merge_clusters() is intentionally *after* the reordering.
 	   * Indic matra reordering is special and tricky... */
-	  buffer->merge_clusters (new_pos, MIN (end, base + 1));
+	  buffer->merge_clusters (new_pos, hb_min (end, base + 1));
 
 	  new_pos--;
 	}
     } else {
       for (unsigned int i = start; i < base; i++)
 	if (info[i].indic_position () == POS_PRE_M) {
-	  buffer->merge_clusters (i, MIN (end, base + 1));
+	  buffer->merge_clusters (i, hb_min (end, base + 1));
 	  break;
 	}
     }
@@ -1307,7 +1284,7 @@
       while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
 	new_reph_pos++;
       if (new_reph_pos < end)
-        goto reph_move;
+	goto reph_move;
     }
 
     /*       4. If reph should be positioned before post-base consonant, find
@@ -1323,7 +1300,7 @@
 	     !( FLAG_UNSAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
 	new_reph_pos++;
       if (new_reph_pos < end)
-        goto reph_move;
+	goto reph_move;
     }
 
     /*       5. If no consonant is found in steps 3 or 4, move reph to a position
@@ -1364,13 +1341,15 @@
        * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
        */
       if (!indic_plan->uniscribe_bug_compatible &&
-	  unlikely (is_halant (info[new_reph_pos]))) {
+	  unlikely (is_halant (info[new_reph_pos])))
+      {
 	for (unsigned int i = base + 1; i < new_reph_pos; i++)
 	  if (info[i].indic_category() == OT_M) {
 	    /* Ok, got it. */
 	    new_reph_pos--;
 	  }
       }
+
       goto reph_move;
     }
 
@@ -1397,13 +1376,13 @@
   if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */
   {
     for (unsigned int i = base + 1; i < end; i++)
-      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+      if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0)
       {
 	/*       1. Only reorder a glyph produced by substitution during application
 	 *          of the <pref> feature. (Note that a font may shape a Ra consonant with
 	 *          the feature generally but block it in certain contexts.)
 	 */
-        /* Note: We just check that something got substituted.  We don't check that
+	/* Note: We just check that something got substituted.  We don't check that
 	 * the <pref> feature actually did it...
 	 *
 	 * Reorder pref only if it ligated. */
@@ -1449,7 +1428,7 @@
 	  }
 	}
 
-        break;
+	break;
       }
   }
 
@@ -1460,7 +1439,7 @@
     if (!start ||
 	!(FLAG_UNSAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
 	 FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
-      info[start].mask |= indic_plan->mask_array[INIT];
+      info[start].mask |= indic_plan->mask_array[INDIC_INIT];
     else
       buffer->unsafe_to_break (start - 1, start + 1);
   }
@@ -1475,7 +1454,7 @@
     {
       case HB_SCRIPT_TAMIL:
       case HB_SCRIPT_SINHALA:
-        break;
+	break;
 
       default:
 	/* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala.
@@ -1490,15 +1469,15 @@
 
 
 static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-		  hb_font_t *font HB_UNUSED,
-		  hb_buffer_t *buffer)
+final_reordering_indic (const hb_ot_shape_plan_t *plan,
+			hb_font_t *font HB_UNUSED,
+			hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   if (unlikely (!count)) return;
 
   foreach_syllable (buffer, start, end)
-    final_reordering_syllable (plan, buffer, start, end);
+    final_reordering_syllable_indic (plan, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
@@ -1506,18 +1485,6 @@
 
 
 static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
-
-static void
 preprocess_text_indic (const hb_ot_shape_plan_t *plan,
 		       hb_buffer_t              *buffer,
 		       hb_font_t                *font)
@@ -1583,11 +1550,10 @@
      *   https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping
      */
 
+
     const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
-
     hb_codepoint_t glyph;
-
-    if (hb_options ().uniscribe_bug_compatible ||
+    if (indic_plan->uniscribe_bug_compatible ||
 	(c->font->get_nominal_glyph (ab, &glyph) &&
 	 indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
     {
@@ -1635,3 +1601,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh
index dcc2a7a..1eeed68 100644
--- a/src/hb-ot-shape-complex-indic.hh
+++ b/src/hb-ot-shape-complex-indic.hh
@@ -62,17 +62,26 @@
   OT_Coeng = 14, /* Khmer-style Virama. */
   OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
   OT_Ra = 16,
-  OT_CM = 17,  /* Consonant-Medial; Unused by Indic shaper. */
+  OT_CM = 17,  /* Consonant-Medial. */
   OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
-  OT_CS = 19
+  OT_CS = 19,
+
+  /* The following are used by Khmer & Myanmar shapers.  Defined
+   * here for them to share. */
+  OT_VAbv    = 26,
+  OT_VBlw    = 27,
+  OT_VPre    = 28,
+  OT_VPst    = 29,
 };
 
+#define MEDIAL_FLAGS (FLAG (OT_CM))
+
 /* Note:
  *
  * We treat Vowels and placeholders as if they were consonants.  This is safe because Vowels
  * cannot happen in a consonant syllable.  The plus side however is, we can call the
  * consonant syllable logic from the vowel syllable function and get it all right! */
-#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
 
 
@@ -276,7 +285,7 @@
     case POS_POST_C:	return MATRA_POS_RIGHT (u);
     case POS_ABOVE_C:	return MATRA_POS_TOP (u);
     case POS_BELOW_C:	return MATRA_POS_BOTTOM (u);
-  };
+  }
   return side;
 }
 
@@ -357,11 +366,12 @@
   /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
    * so the Indic shaper needs to know their categories. */
   else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM;
-  else if (unlikely (u == 0x1133cu)) cat = OT_N;
+  else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
 
   else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
 
   else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
+  else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
   else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
   else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
 				    cat = OT_PLACEHOLDER;
@@ -395,5 +405,31 @@
   info.indic_position() = pos;
 }
 
+struct hb_indic_would_substitute_feature_t
+{
+  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+  {
+    zero_context = zero_context_;
+    map->get_stage_lookups (0/*GSUB*/,
+			    map->get_feature_stage (0/*GSUB*/, feature_tag),
+			    &lookups, &count);
+  }
+
+  bool would_substitute (const hb_codepoint_t *glyphs,
+			 unsigned int          glyphs_count,
+			 hb_face_t            *face) const
+  {
+    for (unsigned int i = 0; i < count; i++)
+      if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+	return true;
+    return false;
+  }
+
+  private:
+  const hb_ot_map_t::lookup_map_t *lookups;
+  unsigned int count;
+  bool zero_context;
+};
+
 
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */
diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh
index 2bc8ca6..a040318 100644
--- a/src/hb-ot-shape-complex-khmer-machine.hh
+++ b/src/hb-ot-shape-complex-khmer-machine.hh
@@ -35,29 +35,27 @@
 #line 36 "hb-ot-shape-complex-khmer-machine.hh"
 static const unsigned char _khmer_syllable_machine_trans_keys[] = {
 	5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 
-	5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 
-	5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u, 
-	5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u, 
-	5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 
-	5u, 29u, 0
+	5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 
+	5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u, 
+	22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u, 
+	5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u, 
+	0
 };
 
 static const char _khmer_syllable_machine_key_spans[] = {
 	22, 17, 22, 17, 16, 17, 22, 17, 
-	22, 17, 16, 17, 22, 17, 16, 17, 
-	22, 17, 22, 17, 22, 16, 29, 25, 
-	25, 25, 1, 18, 25, 25, 25, 22, 
-	25, 25, 1, 18, 25, 25, 16, 25, 
-	25
+	22, 17, 17, 22, 17, 16, 17, 22, 
+	17, 22, 17, 22, 29, 25, 25, 25, 
+	1, 18, 25, 25, 25, 16, 22, 25, 
+	25, 1, 18, 25, 25, 16, 25, 25
 };
 
 static const short _khmer_syllable_machine_index_offsets[] = {
 	0, 23, 41, 64, 82, 99, 117, 140, 
-	158, 181, 199, 216, 234, 257, 275, 292, 
-	310, 333, 351, 374, 392, 415, 432, 462, 
-	488, 514, 540, 542, 561, 587, 613, 639, 
-	662, 688, 714, 716, 735, 761, 787, 804, 
-	830
+	158, 181, 199, 217, 240, 258, 275, 293, 
+	316, 334, 357, 375, 398, 428, 454, 480, 
+	506, 508, 527, 553, 579, 605, 622, 645, 
+	671, 697, 699, 718, 744, 770, 787, 813
 };
 
 static const char _khmer_syllable_machine_indicies[] = {
@@ -85,142 +83,136 @@
 	0, 0, 0, 0, 0, 0, 12, 0, 
 	0, 0, 0, 4, 0, 11, 11, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 12, 0, 13, 
-	13, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 13, 0, 
-	15, 15, 14, 14, 14, 14, 14, 14, 
-	14, 14, 14, 14, 14, 14, 14, 14, 
-	16, 14, 15, 15, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 16, 17, 17, 17, 17, 18, 
-	17, 19, 19, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 18, 17, 20, 20, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 20, 17, 21, 21, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 22, 17, 23, 23, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 24, 17, 
-	17, 17, 17, 18, 17, 23, 23, 17, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 24, 17, 25, 
-	25, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 26, 
-	17, 17, 17, 17, 18, 17, 25, 25, 
-	17, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 26, 17, 
-	15, 15, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 17, 27, 
-	16, 17, 17, 17, 17, 18, 17, 28, 
-	28, 17, 17, 17, 17, 17, 17, 17, 
-	17, 17, 17, 17, 17, 17, 28, 17, 
-	13, 13, 29, 29, 30, 30, 29, 29, 
-	29, 29, 2, 2, 29, 31, 29, 13, 
-	29, 29, 29, 29, 16, 20, 29, 29, 
-	29, 18, 24, 26, 22, 29, 33, 33, 
-	32, 32, 32, 32, 32, 32, 32, 34, 
-	32, 32, 32, 32, 32, 2, 3, 6, 
-	32, 32, 32, 4, 10, 12, 8, 32, 
-	35, 35, 32, 32, 32, 32, 32, 32, 
-	32, 36, 32, 32, 32, 32, 32, 32, 
-	3, 6, 32, 32, 32, 4, 10, 12, 
-	8, 32, 5, 5, 32, 32, 32, 32, 
-	32, 32, 32, 36, 32, 32, 32, 32, 
-	32, 32, 4, 6, 32, 32, 32, 32, 
-	32, 32, 8, 32, 6, 32, 7, 7, 
-	32, 32, 32, 32, 32, 32, 32, 36, 
-	32, 32, 32, 32, 32, 32, 8, 6, 
-	32, 37, 37, 32, 32, 32, 32, 32, 
-	32, 32, 36, 32, 32, 32, 32, 32, 
-	32, 10, 6, 32, 32, 32, 4, 32, 
-	32, 8, 32, 38, 38, 32, 32, 32, 
-	32, 32, 32, 32, 36, 32, 32, 32, 
-	32, 32, 32, 12, 6, 32, 32, 32, 
-	4, 10, 32, 8, 32, 35, 35, 32, 
-	32, 32, 32, 32, 32, 32, 34, 32, 
-	32, 32, 32, 32, 32, 3, 6, 32, 
-	32, 32, 4, 10, 12, 8, 32, 15, 
-	15, 39, 39, 39, 39, 39, 39, 39, 
-	39, 39, 39, 39, 39, 39, 39, 16, 
-	39, 39, 39, 39, 18, 39, 41, 41, 
-	40, 40, 40, 40, 40, 40, 40, 42, 
-	40, 40, 40, 40, 40, 40, 16, 20, 
-	40, 40, 40, 18, 24, 26, 22, 40, 
-	19, 19, 40, 40, 40, 40, 40, 40, 
-	40, 42, 40, 40, 40, 40, 40, 40, 
-	18, 20, 40, 40, 40, 40, 40, 40, 
-	22, 40, 20, 40, 21, 21, 40, 40, 
-	40, 40, 40, 40, 40, 42, 40, 40, 
-	40, 40, 40, 40, 22, 20, 40, 43, 
-	43, 40, 40, 40, 40, 40, 40, 40, 
-	42, 40, 40, 40, 40, 40, 40, 24, 
-	20, 40, 40, 40, 18, 40, 40, 22, 
-	40, 44, 44, 40, 40, 40, 40, 40, 
-	40, 40, 42, 40, 40, 40, 40, 40, 
-	40, 26, 20, 40, 40, 40, 18, 24, 
-	40, 22, 40, 28, 28, 39, 39, 39, 
+	0, 0, 0, 0, 0, 12, 0, 14, 
+	14, 13, 13, 13, 13, 13, 13, 13, 
+	13, 13, 13, 13, 13, 13, 13, 15, 
+	13, 14, 14, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 15, 16, 16, 16, 16, 17, 16, 
+	18, 18, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	17, 16, 19, 19, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 19, 16, 20, 20, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 21, 16, 22, 22, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 23, 16, 16, 
+	16, 16, 17, 16, 22, 22, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 23, 16, 24, 24, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 25, 16, 
+	16, 16, 16, 17, 16, 24, 24, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 25, 16, 14, 
+	14, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 26, 15, 
+	16, 16, 16, 16, 17, 16, 28, 28, 
+	27, 27, 29, 29, 27, 27, 27, 27, 
+	2, 2, 27, 30, 27, 28, 27, 27, 
+	27, 27, 15, 19, 27, 27, 27, 17, 
+	23, 25, 21, 27, 32, 32, 31, 31, 
+	31, 31, 31, 31, 31, 33, 31, 31, 
+	31, 31, 31, 2, 3, 6, 31, 31, 
+	31, 4, 10, 12, 8, 31, 34, 34, 
+	31, 31, 31, 31, 31, 31, 31, 35, 
+	31, 31, 31, 31, 31, 31, 3, 6, 
+	31, 31, 31, 4, 10, 12, 8, 31, 
+	5, 5, 31, 31, 31, 31, 31, 31, 
+	31, 35, 31, 31, 31, 31, 31, 31, 
+	4, 6, 31, 31, 31, 31, 31, 31, 
+	8, 31, 6, 31, 7, 7, 31, 31, 
+	31, 31, 31, 31, 31, 35, 31, 31, 
+	31, 31, 31, 31, 8, 6, 31, 36, 
+	36, 31, 31, 31, 31, 31, 31, 31, 
+	35, 31, 31, 31, 31, 31, 31, 10, 
+	6, 31, 31, 31, 4, 31, 31, 8, 
+	31, 37, 37, 31, 31, 31, 31, 31, 
+	31, 31, 35, 31, 31, 31, 31, 31, 
+	31, 12, 6, 31, 31, 31, 4, 10, 
+	31, 8, 31, 34, 34, 31, 31, 31, 
+	31, 31, 31, 31, 33, 31, 31, 31, 
+	31, 31, 31, 3, 6, 31, 31, 31, 
+	4, 10, 12, 8, 31, 28, 28, 31, 
+	31, 31, 31, 31, 31, 31, 31, 31, 
+	31, 31, 31, 31, 28, 31, 14, 14, 
+	38, 38, 38, 38, 38, 38, 38, 38, 
+	38, 38, 38, 38, 38, 38, 15, 38, 
+	38, 38, 38, 17, 38, 40, 40, 39, 
+	39, 39, 39, 39, 39, 39, 41, 39, 
+	39, 39, 39, 39, 39, 15, 19, 39, 
+	39, 39, 17, 23, 25, 21, 39, 18, 
+	18, 39, 39, 39, 39, 39, 39, 39, 
+	41, 39, 39, 39, 39, 39, 39, 17, 
+	19, 39, 39, 39, 39, 39, 39, 21, 
+	39, 19, 39, 20, 20, 39, 39, 39, 
+	39, 39, 39, 39, 41, 39, 39, 39, 
+	39, 39, 39, 21, 19, 39, 42, 42, 
+	39, 39, 39, 39, 39, 39, 39, 41, 
+	39, 39, 39, 39, 39, 39, 23, 19, 
+	39, 39, 39, 17, 39, 39, 21, 39, 
+	43, 43, 39, 39, 39, 39, 39, 39, 
+	39, 41, 39, 39, 39, 39, 39, 39, 
+	25, 19, 39, 39, 39, 17, 23, 39, 
+	21, 39, 44, 44, 39, 39, 39, 39, 
 	39, 39, 39, 39, 39, 39, 39, 39, 
-	39, 39, 28, 39, 45, 45, 40, 40, 
-	40, 40, 40, 40, 40, 46, 40, 40, 
-	40, 40, 40, 27, 16, 20, 40, 40, 
-	40, 18, 24, 26, 22, 40, 41, 41, 
-	40, 40, 40, 40, 40, 40, 40, 46, 
-	40, 40, 40, 40, 40, 40, 16, 20, 
-	40, 40, 40, 18, 24, 26, 22, 40, 
-	0
+	39, 44, 39, 45, 45, 39, 39, 39, 
+	39, 39, 39, 39, 30, 39, 39, 39, 
+	39, 39, 26, 15, 19, 39, 39, 39, 
+	17, 23, 25, 21, 39, 40, 40, 39, 
+	39, 39, 39, 39, 39, 39, 30, 39, 
+	39, 39, 39, 39, 39, 15, 19, 39, 
+	39, 39, 17, 23, 25, 21, 39, 0
 };
 
 static const char _khmer_syllable_machine_trans_targs[] = {
-	22, 1, 30, 24, 25, 3, 26, 5, 
-	27, 7, 28, 9, 29, 23, 22, 11, 
-	32, 22, 33, 13, 34, 15, 35, 17, 
-	36, 19, 37, 40, 39, 22, 31, 38, 
-	22, 0, 10, 2, 4, 6, 8, 22, 
-	22, 12, 14, 16, 18, 20, 21
+	20, 1, 28, 22, 23, 3, 24, 5, 
+	25, 7, 26, 9, 27, 20, 10, 31, 
+	20, 32, 12, 33, 14, 34, 16, 35, 
+	18, 36, 39, 20, 21, 30, 37, 20, 
+	0, 29, 2, 4, 6, 8, 20, 20, 
+	11, 13, 15, 17, 38, 19
 };
 
 static const char _khmer_syllable_machine_trans_actions[] = {
 	1, 0, 2, 2, 2, 0, 0, 0, 
-	2, 0, 2, 0, 2, 2, 3, 0, 
-	4, 5, 2, 0, 0, 0, 2, 0, 
-	2, 0, 2, 4, 4, 8, 9, 0, 
-	10, 0, 0, 0, 0, 0, 0, 11, 
-	12, 0, 0, 0, 0, 0, 0
+	2, 0, 2, 0, 2, 3, 0, 4, 
+	5, 2, 0, 0, 0, 2, 0, 2, 
+	0, 2, 4, 8, 2, 9, 0, 10, 
+	0, 0, 0, 0, 0, 0, 11, 12, 
+	0, 0, 0, 0, 4, 0
 };
 
 static const char _khmer_syllable_machine_to_state_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 6, 0, 
+	0, 0, 0, 0, 6, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0
+	0, 0, 0, 0, 0, 0, 0, 0
 };
 
 static const char _khmer_syllable_machine_from_state_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 7, 0, 
+	0, 0, 0, 0, 7, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0
+	0, 0, 0, 0, 0, 0, 0, 0
 };
 
 static const unsigned char _khmer_syllable_machine_eof_trans[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 15, 18, 18, 18, 18, 
-	18, 18, 18, 18, 18, 18, 0, 33, 
-	33, 33, 33, 33, 33, 33, 33, 40, 
-	41, 41, 41, 41, 41, 41, 40, 41, 
-	41
+	1, 1, 14, 17, 17, 17, 17, 17, 
+	17, 17, 17, 17, 0, 32, 32, 32, 
+	32, 32, 32, 32, 32, 32, 39, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40
 };
 
-static const int khmer_syllable_machine_start = 22;
-static const int khmer_syllable_machine_first_final = 22;
+static const int khmer_syllable_machine_start = 20;
+static const int khmer_syllable_machine_first_final = 20;
 static const int khmer_syllable_machine_error = -1;
 
-static const int khmer_syllable_machine_en_main = 22;
+static const int khmer_syllable_machine_en_main = 20;
 
 
 #line 36 "hb-ot-shape-complex-khmer-machine.rl"
@@ -234,19 +226,19 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_khmer (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 250 "hb-ot-shape-complex-khmer-machine.hh"
+#line 242 "hb-ot-shape-complex-khmer-machine.hh"
 	{
 	cs = khmer_syllable_machine_start;
 	ts = 0;
@@ -262,7 +254,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 266 "hb-ot-shape-complex-khmer-machine.hh"
+#line 258 "hb-ot-shape-complex-khmer-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -276,7 +268,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 280 "hb-ot-shape-complex-khmer-machine.hh"
+#line 272 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 	_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -346,7 +338,7 @@
 #line 76 "hb-ot-shape-complex-khmer-machine.rl"
 	{act = 3;}
 	break;
-#line 350 "hb-ot-shape-complex-khmer-machine.hh"
+#line 342 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 _again:
@@ -355,7 +347,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 359 "hb-ot-shape-complex-khmer-machine.hh"
+#line 351 "hb-ot-shape-complex-khmer-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -375,4 +367,6 @@
 
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl
index 4c596ab..e7f1453 100644
--- a/src/hb-ot-shape-complex-khmer-machine.rl
+++ b/src/hb-ot-shape-complex-khmer-machine.rl
@@ -66,7 +66,7 @@
 syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup;
 
 
-broken_cluster =	(Coeng.cn)* syllable_tail;
+broken_cluster =	(Coeng.cn)* (Coeng | syllable_tail);
 consonant_syllable =	(cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
 other =			any;
 
@@ -83,13 +83,13 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_khmer (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
@@ -108,4 +108,6 @@
   }%%
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc
index 4475ceb..fd8a9be 100644
--- a/src/hb-ot-shape-complex-khmer.cc
+++ b/src/hb-ot-shape-complex-khmer.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-khmer.hh"
 #include "hb-ot-layout.hh"
 
@@ -52,50 +56,35 @@
   {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  {HB_TAG('d','i','s','t'), F_GLOBAL},
-  {HB_TAG('a','b','v','m'), F_GLOBAL},
-  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
 /*
  * Must be in the same order as the khmer_features array.
  */
 enum {
-  PREF,
-  BLWF,
-  ABVF,
-  PSTF,
-  CFAR,
+  KHMER_PREF,
+  KHMER_BLWF,
+  KHMER_ABVF,
+  KHMER_PSTF,
+  KHMER_CFAR,
 
-  _PRES,
-  _ABVS,
-  _BLWS,
-  _PSTS,
-
-  _DIST,
-  _ABVM,
-  _BLWM,
+  _KHMER_PRES,
+  _KHMER_ABVS,
+  _KHMER_BLWS,
+  _KHMER_PSTS,
 
   KHMER_NUM_FEATURES,
-  KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */
+  KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */
 };
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
+setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
+		       hb_font_t *font,
+		       hb_buffer_t *buffer);
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
+reorder_khmer (const hb_ot_shape_plan_t *plan,
+	       hb_font_t *font,
+	       hb_buffer_t *buffer);
 
 static void
 collect_features_khmer (hb_ot_shape_planner_t *plan)
@@ -103,8 +92,8 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
-  map->add_gsub_pause (reorder);
+  map->add_gsub_pause (setup_syllables_khmer);
+  map->add_gsub_pause (reorder_khmer);
 
   /* Testing suggests that Uniscribe does NOT pause between basic
    * features.  Test with KhmerUI.ttf and the following three
@@ -123,7 +112,7 @@
   for (; i < KHMER_BASIC_FEATURES; i++)
     map->add_feature (khmer_features[i]);
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 
   for (; i < KHMER_NUM_FEATURES; i++)
     map->add_feature (khmer_features[i]);
@@ -149,32 +138,6 @@
 }
 
 
-struct would_substitute_feature_t
-{
-  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
-  {
-    zero_context = zero_context_;
-    map->get_stage_lookups (0/*GSUB*/,
-			    map->get_feature_stage (0/*GSUB*/, feature_tag),
-			    &lookups, &count);
-  }
-
-  bool would_substitute (const hb_codepoint_t *glyphs,
-			 unsigned int          glyphs_count,
-			 hb_face_t            *face) const
-  {
-    for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
-	return true;
-    return false;
-  }
-
-  private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
-  bool zero_context;
-};
-
 struct khmer_shape_plan_t
 {
   bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
@@ -198,7 +161,7 @@
 
   mutable hb_codepoint_t virama_glyph;
 
-  would_substitute_feature_t pref;
+  hb_indic_would_substitute_feature_t pref;
 
   hb_mask_t mask_array[KHMER_NUM_FEATURES];
 };
@@ -228,10 +191,10 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  broken_cluster,
-  non_khmer_cluster,
+enum khmer_syllable_type_t {
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
 };
 
 #include "hb-ot-shape-complex-khmer-machine.hh"
@@ -253,11 +216,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
+setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		       hb_font_t *font HB_UNUSED,
+		       hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_khmer (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -278,7 +241,9 @@
   /* Setup masks. */
   {
     /* Post-base */
-    hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF];
+    hb_mask_t mask = khmer_plan->mask_array[KHMER_BLWF] |
+		     khmer_plan->mask_array[KHMER_ABVF] |
+		     khmer_plan->mask_array[KHMER_PSTF];
     for (unsigned int i = start + 1; i < end; i++)
       info[i].mask  |= mask;
   }
@@ -305,7 +270,7 @@
       if (info[i + 1].khmer_category() == OT_Ra)
       {
 	for (unsigned int j = 0; j < 2; j++)
-	  info[i + j].mask |= khmer_plan->mask_array[PREF];
+	  info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF];
 
 	/* Move the Coeng,Ro sequence to the start. */
 	buffer->merge_clusters (start, i + 2);
@@ -321,9 +286,9 @@
 	 * U+1784,U+17D2,U+179A,U+17D2,U+1782
 	 * U+1784,U+17D2,U+1782,U+17D2,U+179A
 	 */
-	if (khmer_plan->mask_array[CFAR])
+	if (khmer_plan->mask_array[KHMER_CFAR])
 	  for (unsigned int j = i + 2; j < end; j++)
-	    info[j].mask |= khmer_plan->mask_array[CFAR];
+	    info[j].mask |= khmer_plan->mask_array[KHMER_CFAR];
 
 	num_coengs = 2; /* Done. */
       }
@@ -342,35 +307,39 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-			     hb_face_t *face,
-			     hb_buffer_t *buffer,
-			     unsigned int start, unsigned int end)
+reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
+			hb_face_t *face,
+			hb_buffer_t *buffer,
+			unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type)
   {
-    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
-    case consonant_syllable:
+    case khmer_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case khmer_consonant_syllable:
      reorder_consonant_syllable (plan, face, buffer, start, end);
      break;
 
-    case non_khmer_cluster:
+    case khmer_non_khmer_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		       hb_font_t *font,
-		       hb_buffer_t *buffer)
+insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			     hb_font_t *font,
+			     hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == khmer_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -395,8 +364,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -404,13 +373,12 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().khmer_category() == OT_Repha)
-        buffer->next_glyph ();
+	buffer->next_glyph ();
 
       buffer->output_info (ginfo);
     }
@@ -421,29 +389,18 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer)
+reorder_khmer (const hb_ot_shape_plan_t *plan,
+	       hb_font_t *font,
+	       hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_khmer (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    reorder_syllable_khmer (plan, font->face, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 static bool
 decompose_khmer (const hb_ot_shape_normalize_context_t *c,
@@ -499,3 +456,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh
index 6222945..11a77bf 100644
--- a/src/hb-ot-shape-complex-khmer.hh
+++ b/src/hb-ot-shape-complex-khmer.hh
@@ -43,11 +43,10 @@
   OT_Robatic = 20,
   OT_Xgroup  = 21,
   OT_Ygroup  = 22,
-
-  OT_VAbv    = 26,
-  OT_VBlw    = 27,
-  OT_VPre    = 28,
-  OT_VPst    = 29,
+  //OT_VAbv = 26,
+  //OT_VBlw = 27,
+  //OT_VPre = 28,
+  //OT_VPst = 29,
 };
 
 static inline void
@@ -100,12 +99,12 @@
   if (cat == (khmer_category_t) OT_M)
     switch ((int) pos)
     {
-      case POS_PRE_C:	cat = OT_VPre; break;
-      case POS_BELOW_C:	cat = OT_VBlw; break;
-      case POS_ABOVE_C:	cat = OT_VAbv; break;
-      case POS_POST_C:	cat = OT_VPst; break;
+      case POS_PRE_C:	cat = (khmer_category_t) OT_VPre; break;
+      case POS_BELOW_C:	cat = (khmer_category_t) OT_VBlw; break;
+      case POS_ABOVE_C:	cat = (khmer_category_t) OT_VAbv; break;
+      case POS_POST_C:	cat = (khmer_category_t) OT_VPst; break;
       default: assert (0);
-    };
+    }
 
   info.khmer_category() = cat;
 }
diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh
index 0c19e4f..c2f4c00 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -36,29 +36,31 @@
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
 	1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
 	3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 5u, 29u, 
-	5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 30u, 3u, 29u, 1u, 32u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 
-	3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 32u, 8u, 8u, 
-	0
+	3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 
+	5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 
+	3u, 29u, 3u, 29u, 1u, 16u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 
+	3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 
+	3u, 29u, 1u, 32u, 1u, 32u, 8u, 8u, 0
 };
 
 static const char _myanmar_syllable_machine_key_spans[] = {
 	32, 28, 25, 4, 25, 23, 21, 21, 
 	27, 27, 27, 27, 16, 27, 27, 27, 
-	27, 27, 28, 27, 27, 27, 27, 25, 
-	4, 25, 23, 21, 21, 27, 27, 27, 
-	27, 28, 27, 32, 27, 27, 27, 27, 
-	27, 28, 27, 27, 27, 27, 32, 1
+	27, 27, 28, 27, 27, 27, 27, 27, 
+	25, 4, 25, 23, 21, 21, 27, 27, 
+	27, 27, 16, 28, 27, 27, 27, 27, 
+	27, 28, 27, 27, 27, 27, 27, 28, 
+	27, 32, 32, 1
 };
 
 static const short _myanmar_syllable_machine_index_offsets[] = {
 	0, 33, 62, 88, 93, 119, 143, 165, 
 	187, 215, 243, 271, 299, 316, 344, 372, 
 	400, 428, 456, 485, 513, 541, 569, 597, 
-	623, 628, 654, 678, 700, 722, 750, 778, 
-	806, 834, 863, 891, 924, 952, 980, 1008, 
-	1036, 1064, 1093, 1121, 1149, 1177, 1205, 1238
+	625, 651, 656, 682, 706, 728, 750, 778, 
+	806, 834, 862, 879, 908, 936, 964, 992, 
+	1020, 1048, 1077, 1105, 1133, 1161, 1189, 1217, 
+	1246, 1274, 1307, 1340
 };
 
 static const char _myanmar_syllable_machine_indicies[] = {
@@ -124,120 +126,134 @@
 	21, 21, 21, 21, 21, 21, 32, 33, 
 	34, 35, 36, 43, 21, 22, 21, 24, 
 	24, 21, 25, 21, 26, 21, 21, 21, 
-	21, 21, 21, 21, 43, 21, 21, 28, 
+	21, 21, 21, 21, 21, 21, 21, 28, 
 	21, 30, 21, 32, 33, 34, 35, 36, 
 	21, 22, 21, 24, 24, 21, 25, 21, 
 	26, 21, 21, 21, 21, 21, 21, 21, 
 	43, 21, 21, 28, 21, 21, 21, 32, 
 	33, 34, 35, 36, 21, 22, 21, 24, 
 	24, 21, 25, 21, 26, 21, 21, 21, 
-	21, 21, 21, 21, 43, 21, 21, 28, 
+	21, 21, 21, 21, 44, 21, 21, 28, 
 	29, 30, 21, 32, 33, 34, 35, 36, 
-	21, 22, 23, 24, 24, 21, 25, 21, 
+	21, 22, 21, 24, 24, 21, 25, 21, 
 	26, 21, 21, 21, 21, 21, 21, 21, 
-	27, 21, 21, 28, 29, 30, 31, 32, 
-	33, 34, 35, 36, 21, 3, 3, 44, 
-	5, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 45, 44, 44, 44, 44, 44, 
-	44, 14, 44, 44, 44, 18, 44, 3, 
-	3, 44, 5, 44, 3, 3, 44, 5, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	14, 44, 44, 44, 18, 44, 46, 44, 
-	3, 3, 44, 5, 44, 14, 44, 44, 
-	44, 44, 44, 44, 44, 47, 44, 44, 
-	44, 44, 44, 44, 14, 44, 3, 3, 
-	44, 5, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 47, 44, 44, 44, 44, 
-	44, 44, 14, 44, 3, 3, 44, 5, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	14, 44, 2, 44, 3, 3, 44, 5, 
-	44, 6, 44, 44, 44, 44, 44, 44, 
-	44, 48, 44, 44, 48, 44, 44, 44, 
-	14, 49, 44, 44, 18, 44, 2, 44, 
-	3, 3, 44, 5, 44, 6, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 14, 44, 44, 44, 
-	18, 44, 2, 44, 3, 3, 44, 5, 
-	44, 6, 44, 44, 44, 44, 44, 44, 
-	44, 48, 44, 44, 44, 44, 44, 44, 
-	14, 49, 44, 44, 18, 44, 2, 44, 
-	3, 3, 44, 5, 44, 6, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 14, 49, 44, 44, 
-	18, 44, 22, 23, 24, 24, 21, 25, 
-	21, 26, 21, 21, 21, 21, 21, 21, 
-	21, 50, 21, 21, 28, 29, 30, 31, 
-	32, 33, 34, 35, 36, 37, 21, 22, 
-	51, 24, 24, 21, 25, 21, 26, 21, 
-	21, 21, 21, 21, 21, 21, 27, 21, 
-	21, 28, 29, 30, 31, 32, 33, 34, 
-	35, 36, 21, 1, 1, 2, 3, 3, 
-	3, 44, 5, 44, 6, 1, 44, 44, 
-	44, 44, 1, 44, 8, 44, 44, 10, 
+	21, 21, 21, 28, 29, 30, 21, 32, 
+	33, 34, 35, 36, 21, 22, 23, 24, 
+	24, 21, 25, 21, 26, 21, 21, 21, 
+	21, 21, 21, 21, 27, 21, 21, 28, 
+	29, 30, 31, 32, 33, 34, 35, 36, 
+	21, 46, 46, 45, 5, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 47, 45, 
+	45, 45, 45, 45, 45, 14, 45, 45, 
+	45, 18, 45, 46, 46, 45, 5, 45, 
+	46, 46, 45, 5, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 14, 45, 45, 45, 
+	18, 45, 48, 45, 46, 46, 45, 5, 
+	45, 14, 45, 45, 45, 45, 45, 45, 
+	45, 49, 45, 45, 45, 45, 45, 45, 
+	14, 45, 46, 46, 45, 5, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 49, 
+	45, 45, 45, 45, 45, 45, 14, 45, 
+	46, 46, 45, 5, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 14, 45, 2, 45, 
+	46, 46, 45, 5, 45, 6, 45, 45, 
+	45, 45, 45, 45, 45, 50, 45, 45, 
+	50, 45, 45, 45, 14, 51, 45, 45, 
+	18, 45, 2, 45, 46, 46, 45, 5, 
+	45, 6, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	14, 45, 45, 45, 18, 45, 2, 45, 
+	46, 46, 45, 5, 45, 6, 45, 45, 
+	45, 45, 45, 45, 45, 50, 45, 45, 
+	45, 45, 45, 45, 14, 51, 45, 45, 
+	18, 45, 2, 45, 46, 46, 45, 5, 
+	45, 6, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	14, 51, 45, 45, 18, 45, 52, 52, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 52, 45, 2, 
+	3, 46, 46, 45, 5, 45, 6, 45, 
+	45, 45, 45, 45, 45, 45, 8, 45, 
+	45, 10, 11, 12, 13, 14, 15, 16, 
+	17, 18, 19, 45, 2, 45, 46, 46, 
+	45, 5, 45, 6, 45, 45, 45, 45, 
+	45, 45, 45, 8, 45, 45, 10, 11, 
+	12, 13, 14, 15, 16, 17, 18, 45, 
+	2, 45, 46, 46, 45, 5, 45, 6, 
+	45, 45, 45, 45, 45, 45, 45, 53, 
+	45, 45, 45, 45, 45, 45, 14, 15, 
+	16, 17, 18, 45, 2, 45, 46, 46, 
+	45, 5, 45, 6, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 14, 15, 16, 17, 18, 45, 
+	2, 45, 46, 46, 45, 5, 45, 6, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 14, 15, 
+	16, 45, 18, 45, 2, 45, 46, 46, 
+	45, 5, 45, 6, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 14, 45, 16, 45, 18, 45, 
+	2, 45, 46, 46, 45, 5, 45, 6, 
+	45, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 14, 15, 
+	16, 17, 18, 53, 45, 2, 45, 46, 
+	46, 45, 5, 45, 6, 45, 45, 45, 
+	45, 45, 45, 45, 45, 45, 45, 10, 
+	45, 12, 45, 14, 15, 16, 17, 18, 
+	45, 2, 45, 46, 46, 45, 5, 45, 
+	6, 45, 45, 45, 45, 45, 45, 45, 
+	53, 45, 45, 10, 45, 45, 45, 14, 
+	15, 16, 17, 18, 45, 2, 45, 46, 
+	46, 45, 5, 45, 6, 45, 45, 45, 
+	45, 45, 45, 45, 54, 45, 45, 10, 
+	11, 12, 45, 14, 15, 16, 17, 18, 
+	45, 2, 45, 46, 46, 45, 5, 45, 
+	6, 45, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 10, 11, 12, 45, 14, 
+	15, 16, 17, 18, 45, 2, 3, 46, 
+	46, 45, 5, 45, 6, 45, 45, 45, 
+	45, 45, 45, 45, 8, 45, 45, 10, 
 	11, 12, 13, 14, 15, 16, 17, 18, 
-	19, 44, 1, 44, 2, 44, 3, 3, 
-	44, 5, 44, 6, 44, 44, 44, 44, 
-	44, 44, 44, 8, 44, 44, 10, 11, 
-	12, 13, 14, 15, 16, 17, 18, 44, 
-	2, 44, 3, 3, 44, 5, 44, 6, 
-	44, 44, 44, 44, 44, 44, 44, 52, 
-	44, 44, 44, 44, 44, 44, 14, 15, 
-	16, 17, 18, 44, 2, 44, 3, 3, 
-	44, 5, 44, 6, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 14, 15, 16, 17, 18, 44, 
-	2, 44, 3, 3, 44, 5, 44, 6, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 14, 15, 
-	16, 44, 18, 44, 2, 44, 3, 3, 
-	44, 5, 44, 6, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 14, 44, 16, 44, 18, 44, 
-	2, 44, 3, 3, 44, 5, 44, 6, 
-	44, 44, 44, 44, 44, 44, 44, 44, 
-	44, 44, 44, 44, 44, 44, 14, 15, 
-	16, 17, 18, 52, 44, 2, 44, 3, 
-	3, 44, 5, 44, 6, 44, 44, 44, 
-	44, 44, 44, 44, 52, 44, 44, 10, 
-	44, 12, 44, 14, 15, 16, 17, 18, 
-	44, 2, 44, 3, 3, 44, 5, 44, 
-	6, 44, 44, 44, 44, 44, 44, 44, 
-	52, 44, 44, 10, 44, 44, 44, 14, 
-	15, 16, 17, 18, 44, 2, 44, 3, 
-	3, 44, 5, 44, 6, 44, 44, 44, 
-	44, 44, 44, 44, 52, 44, 44, 10, 
-	11, 12, 44, 14, 15, 16, 17, 18, 
-	44, 2, 3, 3, 3, 44, 5, 44, 
-	6, 44, 44, 44, 44, 44, 44, 44, 
-	8, 44, 44, 10, 11, 12, 13, 14, 
-	15, 16, 17, 18, 44, 1, 1, 53, 
-	53, 53, 53, 53, 53, 53, 53, 1, 
-	53, 53, 53, 53, 1, 53, 53, 53, 
-	53, 53, 53, 53, 53, 53, 53, 53, 
-	53, 53, 53, 53, 1, 53, 54, 53, 
-	0
+	45, 22, 23, 24, 24, 21, 25, 21, 
+	26, 21, 21, 21, 21, 21, 21, 21, 
+	55, 21, 21, 28, 29, 30, 31, 32, 
+	33, 34, 35, 36, 37, 21, 22, 56, 
+	24, 24, 21, 25, 21, 26, 21, 21, 
+	21, 21, 21, 21, 21, 27, 21, 21, 
+	28, 29, 30, 31, 32, 33, 34, 35, 
+	36, 21, 1, 1, 2, 3, 46, 46, 
+	45, 5, 45, 6, 1, 45, 45, 45, 
+	45, 1, 45, 8, 45, 45, 10, 11, 
+	12, 13, 14, 15, 16, 17, 18, 19, 
+	45, 1, 45, 1, 1, 57, 57, 57, 
+	57, 57, 57, 57, 57, 1, 57, 57, 
+	57, 57, 1, 57, 57, 57, 57, 57, 
+	57, 57, 57, 57, 57, 57, 57, 57, 
+	57, 57, 1, 57, 58, 57, 0
 };
 
 static const char _myanmar_syllable_machine_trans_targs[] = {
-	0, 1, 23, 0, 0, 24, 30, 33, 
-	36, 46, 37, 42, 43, 44, 26, 39, 
-	40, 41, 29, 45, 47, 0, 2, 12, 
+	0, 1, 24, 34, 0, 25, 31, 47, 
+	36, 50, 37, 42, 43, 44, 27, 39, 
+	40, 41, 30, 46, 51, 0, 2, 12, 
 	0, 3, 9, 13, 14, 19, 20, 21, 
-	5, 16, 17, 18, 8, 22, 4, 6, 
-	7, 10, 11, 15, 0, 25, 27, 28, 
-	31, 32, 34, 35, 38, 0, 0
+	5, 16, 17, 18, 8, 23, 4, 6, 
+	7, 10, 11, 15, 22, 0, 0, 26, 
+	28, 29, 32, 33, 35, 38, 45, 48, 
+	49, 0, 0
 };
 
 static const char _myanmar_syllable_machine_trans_actions[] = {
-	3, 0, 0, 4, 5, 0, 0, 0, 
+	3, 0, 0, 0, 4, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 6, 0, 0, 
-	7, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 5, 0, 0, 
+	6, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 8, 0, 0, 0, 
-	0, 0, 0, 0, 0, 9, 10
+	0, 0, 0, 0, 0, 7, 8, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 9, 10
 };
 
 static const char _myanmar_syllable_machine_to_state_actions[] = {
@@ -246,7 +262,8 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0
 };
 
 static const char _myanmar_syllable_machine_from_state_actions[] = {
@@ -255,16 +272,18 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0
 };
 
 static const short _myanmar_syllable_machine_eof_trans[] = {
 	0, 22, 22, 22, 22, 22, 22, 22, 
 	22, 22, 22, 22, 22, 22, 22, 22, 
-	22, 22, 22, 22, 22, 22, 22, 45, 
-	45, 45, 45, 45, 45, 45, 45, 45, 
-	45, 22, 22, 45, 45, 45, 45, 45, 
-	45, 45, 45, 45, 45, 45, 54, 54
+	22, 22, 22, 22, 22, 22, 22, 22, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 22, 
+	22, 46, 58, 58
 };
 
 static const int myanmar_syllable_machine_start = 0;
@@ -285,19 +304,19 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_myanmar (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 301 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	cs = myanmar_syllable_machine_start;
 	ts = 0;
@@ -313,7 +332,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 317 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -327,7 +346,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 331 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -345,11 +364,11 @@
 		goto _again;
 
 	switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
-	case 7:
+	case 6:
 #line 86 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
-	case 5:
+	case 4:
 #line 87 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
@@ -357,7 +376,7 @@
 #line 88 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (punctuation_cluster); }}
 	break;
-	case 4:
+	case 8:
 #line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
@@ -365,11 +384,11 @@
 #line 90 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
-	case 6:
+	case 5:
 #line 86 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
-	case 8:
+	case 7:
 #line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
@@ -377,7 +396,7 @@
 #line 90 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
 	break;
-#line 381 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 _again:
@@ -386,7 +405,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 390 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	if ( ++p != pe )
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
index 7845a86..67133cd 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -69,15 +69,15 @@
 
 c = C|Ra;			# is_consonant
 
-medial_group = MY? MR? MW? MH? As?;
+medial_group = MY? As? MR? ((MW MH? | MH) As?)?;
 main_vowel_group = (VPre.VS?)* VAbv* VBlw* A* (DB As?)?;
 post_vowel_group = VPst MH? As* VAbv* A* (DB As?)?;
 pwo_tone_group = PT A* DB? As?;
 
 complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* V* j?;
-syllable_tail = (H | complex_syllable_tail);
+syllable_tail = (H (c|IV).VS?)* (H | complex_syllable_tail);
 
-consonant_syllable =	(k|CS)? (c|IV|D|GB).VS? (H (c|IV).VS?)* syllable_tail;
+consonant_syllable =	(k|CS)? (c|IV|D|GB).VS? syllable_tail;
 punctuation_cluster = 	P V;
 broken_cluster =	k? VS? syllable_tail;
 other =			any;
@@ -97,13 +97,13 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_myanmar (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index 8fdf2f4..fc3490d 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-myanmar.hh"
 
 
@@ -32,7 +36,7 @@
  */
 
 static const hb_tag_t
-basic_features[] =
+myanmar_basic_features[] =
 {
   /*
    * Basic features.
@@ -44,7 +48,7 @@
   HB_TAG('p','s','t','f'),
 };
 static const hb_tag_t
-other_features[] =
+myanmar_other_features[] =
 {
   /*
    * Other features.
@@ -55,36 +59,13 @@
   HB_TAG('b','l','w','s'),
   HB_TAG('p','s','t','s'),
 };
-static const hb_tag_t
-positioning_features[] =
-{
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  HB_TAG('d','i','s','t'),
-  /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
-   * features.  The released Windows 8 version of the font (as well
-   * as the released spec) used 'mark' instead.  The Windows 8
-   * shaper however didn't apply 'mark' but did apply 'mkmk'.
-   * Perhaps it applied abvm/blwm.  This was fixed in a Windows 8
-   * update, so now it applies mark/mkmk.  We are guessing that
-   * it still applies abvm/blwm too.
-   */
-  HB_TAG('a','b','v','m'),
-  HB_TAG('b','l','w','m'),
-};
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
+setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
+			 hb_font_t *font,
+			 hb_buffer_t *buffer);
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
+reorder_myanmar (const hb_ot_shape_plan_t *plan,
 		 hb_font_t *font,
 		 hb_buffer_t *buffer);
 
@@ -94,7 +75,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_myanmar);
 
   map->enable_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
@@ -102,21 +83,18 @@
   map->enable_feature (HB_TAG('c','c','m','p'));
 
 
-  map->add_gsub_pause (reorder);
+  map->add_gsub_pause (reorder_myanmar);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+  for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
   {
-    map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
     map->add_gsub_pause (nullptr);
   }
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
-    map->enable_feature (other_features[i], F_MANUAL_ZWJ);
-
-  for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
-    map->enable_feature (positioning_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
+    map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
 }
 
 static void
@@ -126,11 +104,11 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  punctuation_cluster,
-  broken_cluster,
-  non_myanmar_cluster,
+enum myanmar_syllable_type_t {
+  myanmar_consonant_syllable,
+  myanmar_punctuation_cluster,
+  myanmar_broken_cluster,
+  myanmar_non_myanmar_cluster,
 };
 
 #include "hb-ot-shape-complex-myanmar-machine.hh"
@@ -138,8 +116,8 @@
 
 static void
 setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		   hb_buffer_t              *buffer,
-		   hb_font_t                *font HB_UNUSED)
+		     hb_buffer_t              *buffer,
+		     hb_font_t                *font HB_UNUSED)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
@@ -154,11 +132,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
+setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			 hb_font_t *font HB_UNUSED,
+			 hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_myanmar (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -261,7 +239,7 @@
       }
       if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
       {
-        pos = POS_AFTER_SUB;
+	pos = POS_AFTER_SUB;
 	info[i].myanmar_position() = pos;
 	continue;
       }
@@ -274,36 +252,40 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			     hb_face_t *face HB_UNUSED,
-			     hb_buffer_t *buffer,
-			     unsigned int start, unsigned int end)
+reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			  hb_face_t *face HB_UNUSED,
+			  hb_buffer_t *buffer,
+			  unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type) {
 
-    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
-    case consonant_syllable:
+    case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case myanmar_consonant_syllable:
       initial_reordering_consonant_syllable  (buffer, start, end);
       break;
 
-    case punctuation_cluster:
-    case non_myanmar_cluster:
+    case myanmar_punctuation_cluster:
+    case myanmar_non_myanmar_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		       hb_font_t *font,
-		       hb_buffer_t *buffer)
+insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			       hb_font_t *font,
+			       hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -328,8 +310,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -347,30 +329,19 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer)
+reorder_myanmar (const hb_ot_shape_plan_t *plan,
+		 hb_font_t *font,
+		 hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_myanmar (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    reorder_syllable_myanmar (plan, font->face, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
@@ -411,3 +382,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-myanmar.hh b/src/hb-ot-shape-complex-myanmar.hh
index 3e9537a..7b9821e 100644
--- a/src/hb-ot-shape-complex-myanmar.hh
+++ b/src/hb-ot-shape-complex-myanmar.hh
@@ -49,10 +49,10 @@
   OT_MW  = 23, /* Various consonant medial types */
   OT_MY  = 24, /* Various consonant medial types */
   OT_PT  = 25, /* Pwo and other tones */
-  OT_VAbv = 26,
-  OT_VBlw = 27,
-  OT_VPre = 28,
-  OT_VPst = 29,
+  //OT_VAbv = 26,
+  //OT_VBlw = 27,
+  //OT_VPre = 28,
+  //OT_VPst = 29,
   OT_VS   = 30, /* Variation selectors */
   OT_P    = 31, /* Punctuation */
   OT_D    = 32, /* Digits except zero */
@@ -146,7 +146,7 @@
       break;
 
     case 0xAA74u: case 0xAA75u: case 0xAA76u:
-      /* https://github.com/roozbehp/unicode-data/issues/3 */
+      /* https://github.com/harfbuzz/harfbuzz/issues/218 */
       cat = OT_C;
       break;
   }
@@ -155,11 +155,11 @@
   {
     switch ((int) pos)
     {
-      case POS_PRE_C:	cat = OT_VPre;
+      case POS_PRE_C:	cat = (myanmar_category_t) OT_VPre;
 			pos = POS_PRE_M; break;
-      case POS_ABOVE_C:	cat = OT_VAbv;   break;
-      case POS_BELOW_C:	cat = OT_VBlw;   break;
-      case POS_POST_C:	cat = OT_VPst;   break;
+      case POS_ABOVE_C:	cat = (myanmar_category_t) OT_VAbv;   break;
+      case POS_BELOW_C:	cat = (myanmar_category_t) OT_VBlw;   break;
+      case POS_POST_C:	cat = (myanmar_category_t) OT_VPst;   break;
     }
   }
 
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index 650c980..347ea2e 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -218,6 +222,10 @@
 		     hb_buffer_t              *buffer,
 		     hb_font_t                *font)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+  return;
+#endif
+
   thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
   thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
   unsigned int base = 0;
@@ -381,3 +389,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
index c9410e4..462342c 100644
--- a/src/hb-ot-shape-complex-use-machine.hh
+++ b/src/hb-ot-shape-complex-use-machine.hh
@@ -36,345 +36,363 @@
 
 #line 38 "hb-ot-shape-complex-use-machine.hh"
 static const unsigned char _use_syllable_machine_trans_keys[] = {
-	12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u,
-	1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u,
-	8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
-	8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u,
-	8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u,
-	8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
-	8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u,
-	41u, 42u, 42u, 42u, 1u, 5u, 0
+	12u, 48u, 1u, 15u, 1u, 1u, 12u, 48u, 1u, 1u, 0u, 48u, 21u, 21u, 11u, 48u, 
+	11u, 48u, 1u, 15u, 1u, 1u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 
+	26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 
+	23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, 
+	1u, 48u, 11u, 48u, 13u, 21u, 4u, 4u, 13u, 13u, 11u, 48u, 11u, 48u, 41u, 42u, 
+	42u, 42u, 11u, 48u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 
+	45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u, 
+	23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, 1u, 48u, 1u, 15u, 
+	4u, 4u, 13u, 21u, 13u, 13u, 12u, 48u, 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u, 
+	21u, 42u, 1u, 5u, 0
 };
 
 static const char _use_syllable_machine_key_spans[] = {
-	33, 15, 1, 33, 45, 1, 37, 37,
-	15, 1, 37, 37, 32, 19, 19, 19,
-	32, 32, 32, 37, 37, 37, 37, 37,
-	37, 37, 37, 39, 37, 9, 1, 1,
-	37, 37, 37, 32, 19, 19, 19, 32,
-	32, 32, 37, 37, 37, 37, 37, 37,
-	37, 37, 39, 15, 33, 44, 37, 22,
-	2, 1, 5
+	37, 15, 1, 37, 1, 49, 1, 38, 
+	38, 15, 1, 38, 27, 26, 24, 23, 
+	22, 2, 1, 25, 25, 25, 1, 25, 
+	26, 26, 26, 27, 27, 27, 27, 38, 
+	48, 38, 9, 1, 1, 38, 38, 2, 
+	1, 38, 38, 27, 26, 24, 23, 22, 
+	2, 1, 25, 25, 25, 25, 26, 26, 
+	26, 27, 27, 27, 27, 38, 48, 15, 
+	1, 9, 1, 37, 48, 38, 2, 1, 
+	22, 5
 };
 
 static const short _use_syllable_machine_index_offsets[] = {
-	0, 34, 50, 52, 86, 132, 134, 172,
-	210, 226, 228, 266, 304, 337, 357, 377,
-	397, 430, 463, 496, 534, 572, 610, 648,
-	686, 724, 762, 800, 840, 878, 888, 890,
-	892, 930, 968, 1006, 1039, 1059, 1079, 1099,
-	1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388,
-	1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675,
-	1698, 1701, 1703
+	0, 38, 54, 56, 94, 96, 146, 148, 
+	187, 226, 242, 244, 283, 311, 338, 363, 
+	387, 410, 413, 415, 441, 467, 493, 495, 
+	521, 548, 575, 602, 630, 658, 686, 714, 
+	753, 802, 841, 851, 853, 855, 894, 933, 
+	936, 938, 977, 1016, 1044, 1071, 1096, 1120, 
+	1143, 1146, 1148, 1174, 1200, 1226, 1252, 1279, 
+	1306, 1333, 1361, 1389, 1417, 1445, 1484, 1533, 
+	1549, 1551, 1561, 1563, 1601, 1650, 1689, 1692, 
+	1694, 1717
 };
 
 static const char _use_syllable_machine_indicies[] = {
-	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,
-	1, 0, 3, 2, 2, 2, 2, 2, 
+	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, 
+	1, 0, 0, 0, 1, 0, 3, 2, 
 	2, 2, 2, 2, 2, 2, 2, 2, 
-	4, 2, 3, 2, 6, 5, 5, 5,
-	5, 5, 5, 5, 5, 5, 5, 5,
-	5, 5, 5, 5, 5, 5, 5, 5,
-	5, 5, 5, 5, 5, 5, 5, 5,
-	5, 5, 5, 5, 6, 5, 7, 8,
-	9, 7, 10, 8, 9, 9, 11, 9, 
-	9, 3, 12, 9, 9, 13, 7, 7, 
-	14, 15, 9, 9, 16, 17, 18, 19, 
-	20, 21, 22, 16, 23, 24, 25, 26, 
-	27, 28, 9, 29, 30, 31, 9, 9, 
-	9, 32, 33, 9, 35, 34, 37, 36,
-	36, 38, 1, 36, 36, 39, 36, 36,
-	36, 36, 36, 40, 41, 42, 43, 44,
-	45, 46, 47, 41, 48, 40, 49, 50,
-	51, 52, 36, 53, 54, 55, 36, 36,
-	36, 36, 56, 36, 37, 36, 36, 38,
-	1, 36, 36, 39, 36, 36, 36, 36,
-	36, 57, 41, 42, 43, 44, 45, 46,
-	47, 41, 48, 49, 49, 50, 51, 52,
-	36, 53, 54, 55, 36, 36, 36, 36,
-	56, 36, 38, 58, 58, 58, 58, 58,
-	58, 58, 58, 58, 58, 58, 58, 58,
-	59, 58, 38, 58, 37, 36, 36, 38,
-	1, 36, 36, 39, 36, 36, 36, 36,
-	36, 36, 41, 42, 43, 44, 45, 46,
-	47, 41, 48, 49, 49, 50, 51, 52,
-	36, 53, 54, 55, 36, 36, 36, 36,
-	56, 36, 37, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	41, 42, 43, 44, 45, 36, 36, 36,
-	36, 36, 36, 50, 51, 52, 36, 53,
-	54, 55, 36, 36, 36, 36, 42, 36,
-	37, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 42,
-	43, 44, 45, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 53, 54, 55,
-	36, 37, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 43, 44, 45, 36, 37, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 44, 45,
-	36, 37, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 45, 36, 37, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 43, 44, 45,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 53, 54, 55, 36, 37, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 43, 44,
-	45, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 54, 55, 36, 37,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 43,
-	44, 45, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 55, 36,
-	37, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 42,
-	43, 44, 45, 36, 36, 36, 36, 36,
-	36, 50, 51, 52, 36, 53, 54, 55,
-	36, 36, 36, 36, 42, 36, 37, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 42, 43, 44,
-	45, 36, 36, 36, 36, 36, 36, 36,
-	51, 52, 36, 53, 54, 55, 36, 36,
-	36, 36, 42, 36, 37, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 42, 43, 44, 45, 36,
-	36, 36, 36, 36, 36, 36, 36, 52,
-	36, 53, 54, 55, 36, 36, 36, 36,
-	42, 36, 37, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	41, 42, 43, 44, 45, 36, 47, 41,
-	36, 36, 36, 50, 51, 52, 36, 53,
-	54, 55, 36, 36, 36, 36, 42, 36,
-	37, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 41, 42,
-	43, 44, 45, 36, 60, 41, 36, 36,
-	36, 50, 51, 52, 36, 53, 54, 55,
-	36, 36, 36, 36, 42, 36, 37, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 36, 36, 41, 42, 43, 44,
-	45, 36, 36, 41, 36, 36, 36, 50,
-	51, 52, 36, 53, 54, 55, 36, 36,
-	36, 36, 42, 36, 37, 36, 36, 36,
-	36, 36, 36, 36, 36, 36, 36, 36,
-	36, 36, 41, 42, 43, 44, 45, 46,
-	47, 41, 36, 36, 36, 50, 51, 52,
-	36, 53, 54, 55, 36, 36, 36, 36,
-	42, 36, 37, 36, 36, 38, 1, 36,
-	36, 39, 36, 36, 36, 36, 36, 36,
-	41, 42, 43, 44, 45, 46, 47, 41,
-	48, 36, 49, 50, 51, 52, 36, 53,
-	54, 55, 36, 36, 36, 36, 56, 36,
-	38, 58, 58, 58, 58, 58, 58, 37,
-	58, 58, 58, 58, 58, 58, 59, 58,
-	58, 58, 58, 58, 58, 58, 42, 43,
-	44, 45, 58, 58, 58, 58, 58, 58,
-	58, 58, 58, 58, 53, 54, 55, 58,
-	37, 36, 36, 38, 1, 36, 36, 39,
-	36, 36, 36, 36, 36, 36, 41, 42,
-	43, 44, 45, 46, 47, 41, 48, 40,
-	49, 50, 51, 52, 36, 53, 54, 55,
-	36, 36, 36, 36, 56, 36, 62, 61,
-	61, 61, 61, 61, 61, 61, 63, 61,
-	10, 64, 62, 61, 11, 65, 65, 3,
-	6, 65, 65, 66, 65, 65, 65, 65,
-	65, 67, 16, 17, 18, 19, 20, 21,
-	22, 16, 23, 25, 25, 26, 27, 28,
-	65, 29, 30, 31, 65, 65, 65, 65,
-	33, 65, 11, 65, 65, 3, 6, 65,
-	65, 66, 65, 65, 65, 65, 65, 65,
-	16, 17, 18, 19, 20, 21, 22, 16, 
-	23, 25, 25, 26, 27, 28, 65, 29,
-	30, 31, 65, 65, 65, 65, 33, 65,
-	11, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 16, 17,
-	18, 19, 20, 65, 65, 65, 65, 65,
-	65, 26, 27, 28, 65, 29, 30, 31,
-	65, 65, 65, 65, 17, 65, 11, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 17, 18, 19,
-	20, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 29, 30, 31, 65, 11,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 18,
-	19, 20, 65, 11, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 19, 20, 65, 11,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 20, 65, 11, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 18, 19, 20, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	29, 30, 31, 65, 11, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 18, 19, 20, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 30, 31, 65, 11, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 18, 19, 20,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 31, 65, 11, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 17, 18, 19,
-	20, 65, 65, 65, 65, 65, 65, 26,
-	27, 28, 65, 29, 30, 31, 65, 65,
-	65, 65, 17, 65, 11, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 17, 18, 19, 20, 65,
-	65, 65, 65, 65, 65, 65, 27, 28,
-	65, 29, 30, 31, 65, 65, 65, 65,
-	17, 65, 11, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 17, 18, 19, 20, 65, 65, 65,
-	65, 65, 65, 65, 65, 28, 65, 29,
-	30, 31, 65, 65, 65, 65, 17, 65,
-	11, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 16, 17,
-	18, 19, 20, 65, 22, 16, 65, 65,
-	65, 26, 27, 28, 65, 29, 30, 31,
-	65, 65, 65, 65, 17, 65, 11, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 16, 17, 18, 19,
-	20, 65, 68, 16, 65, 65, 65, 26,
-	27, 28, 65, 29, 30, 31, 65, 65,
-	65, 65, 17, 65, 11, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 16, 17, 18, 19, 20, 65,
-	65, 16, 65, 65, 65, 26, 27, 28,
-	65, 29, 30, 31, 65, 65, 65, 65,
-	17, 65, 11, 65, 65, 65, 65, 65,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	16, 17, 18, 19, 20, 21, 22, 16,
-	65, 65, 65, 26, 27, 28, 65, 29,
-	30, 31, 65, 65, 65, 65, 17, 65,
-	11, 65, 65, 3, 6, 65, 65, 66,
-	65, 65, 65, 65, 65, 65, 16, 17,
-	18, 19, 20, 21, 22, 16, 23, 65,
-	25, 26, 27, 28, 65, 29, 30, 31,
-	65, 65, 65, 65, 33, 65, 3, 65,
-	65, 65, 65, 65, 65, 11, 65, 65,
-	65, 65, 65, 65, 4, 65, 65, 65,
-	65, 65, 65, 65, 17, 18, 19, 20,
-	65, 65, 65, 65, 65, 65, 65, 65,
-	65, 65, 29, 30, 31, 65, 3, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 4, 69, 6, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 6, 69,
-	8, 65, 65, 65, 8, 65, 65, 11,
-	65, 65, 3, 6, 65, 65, 66, 65,
-	65, 65, 65, 65, 65, 16, 17, 18,
-	19, 20, 21, 22, 16, 23, 24, 25, 
-	26, 27, 28, 65, 29, 30, 31, 65,
-	65, 65, 65, 33, 65, 11, 65, 65,
-	3, 6, 65, 65, 66, 65, 65, 65,
-	65, 65, 65, 16, 17, 18, 19, 20,
-	21, 22, 16, 23, 24, 25, 26, 27,
-	28, 65, 29, 30, 31, 65, 65, 65,
-	65, 33, 65, 71, 70, 70, 70, 70,
-	70, 70, 70, 70, 70, 70, 70, 70,
-	70, 70, 70, 70, 70, 70, 70, 71,
-	72, 70, 71, 72, 70, 72, 70, 8,
-	69, 69, 69, 8, 69, 0
+	2, 2, 2, 2, 4, 2, 3, 2, 
+	6, 5, 5, 5, 5, 5, 5, 5, 
+	5, 5, 5, 5, 5, 5, 5, 5, 
+	5, 5, 5, 5, 5, 5, 5, 5, 
+	5, 5, 5, 5, 5, 5, 5, 5, 
+	6, 5, 5, 5, 6, 5, 7, 5, 
+	8, 9, 10, 8, 11, 12, 10, 10, 
+	10, 10, 10, 3, 13, 14, 10, 15, 
+	8, 8, 16, 17, 10, 10, 18, 19, 
+	20, 21, 22, 23, 24, 18, 25, 26, 
+	27, 28, 29, 30, 10, 31, 32, 33, 
+	10, 34, 35, 36, 37, 38, 39, 40, 
+	13, 10, 42, 41, 44, 1, 43, 43, 
+	45, 43, 43, 43, 43, 43, 46, 47, 
+	48, 49, 50, 51, 52, 53, 47, 54, 
+	46, 55, 56, 57, 58, 43, 59, 60, 
+	61, 43, 43, 43, 43, 62, 63, 64, 
+	65, 1, 43, 44, 1, 43, 43, 45, 
+	43, 43, 43, 43, 43, 66, 47, 48, 
+	49, 50, 51, 52, 53, 47, 54, 55, 
+	55, 56, 57, 58, 43, 59, 60, 61, 
+	43, 43, 43, 43, 62, 63, 64, 65, 
+	1, 43, 44, 67, 67, 67, 67, 67, 
+	67, 67, 67, 67, 67, 67, 67, 67, 
+	68, 67, 44, 67, 44, 1, 43, 43, 
+	45, 43, 43, 43, 43, 43, 43, 47, 
+	48, 49, 50, 51, 52, 53, 47, 54, 
+	55, 55, 56, 57, 58, 43, 59, 60, 
+	61, 43, 43, 43, 43, 62, 63, 64, 
+	65, 1, 43, 47, 48, 49, 50, 51, 
+	43, 43, 43, 43, 43, 43, 56, 57, 
+	58, 43, 59, 60, 61, 43, 43, 43, 
+	43, 48, 63, 64, 65, 69, 43, 48, 
+	49, 50, 51, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 59, 60, 61, 
+	43, 43, 43, 43, 43, 63, 64, 65, 
+	69, 43, 49, 50, 51, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 63, 
+	64, 65, 43, 50, 51, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 63, 
+	64, 65, 43, 51, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 63, 64, 
+	65, 43, 63, 64, 43, 64, 43, 49, 
+	50, 51, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 59, 60, 61, 43, 
+	43, 43, 43, 43, 63, 64, 65, 69, 
+	43, 49, 50, 51, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 60, 
+	61, 43, 43, 43, 43, 43, 63, 64, 
+	65, 69, 43, 49, 50, 51, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 61, 43, 43, 43, 43, 43, 
+	63, 64, 65, 69, 43, 71, 70, 49, 
+	50, 51, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 43, 43, 43, 43, 
+	43, 43, 43, 43, 63, 64, 65, 69, 
+	43, 48, 49, 50, 51, 43, 43, 43, 
+	43, 43, 43, 56, 57, 58, 43, 59, 
+	60, 61, 43, 43, 43, 43, 48, 63, 
+	64, 65, 69, 43, 48, 49, 50, 51, 
+	43, 43, 43, 43, 43, 43, 43, 57, 
+	58, 43, 59, 60, 61, 43, 43, 43, 
+	43, 48, 63, 64, 65, 69, 43, 48, 
+	49, 50, 51, 43, 43, 43, 43, 43, 
+	43, 43, 43, 58, 43, 59, 60, 61, 
+	43, 43, 43, 43, 48, 63, 64, 65, 
+	69, 43, 47, 48, 49, 50, 51, 43, 
+	53, 47, 43, 43, 43, 56, 57, 58, 
+	43, 59, 60, 61, 43, 43, 43, 43, 
+	48, 63, 64, 65, 69, 43, 47, 48, 
+	49, 50, 51, 43, 72, 47, 43, 43, 
+	43, 56, 57, 58, 43, 59, 60, 61, 
+	43, 43, 43, 43, 48, 63, 64, 65, 
+	69, 43, 47, 48, 49, 50, 51, 43, 
+	43, 47, 43, 43, 43, 56, 57, 58, 
+	43, 59, 60, 61, 43, 43, 43, 43, 
+	48, 63, 64, 65, 69, 43, 47, 48, 
+	49, 50, 51, 52, 53, 47, 43, 43, 
+	43, 56, 57, 58, 43, 59, 60, 61, 
+	43, 43, 43, 43, 48, 63, 64, 65, 
+	69, 43, 44, 1, 43, 43, 45, 43, 
+	43, 43, 43, 43, 43, 47, 48, 49, 
+	50, 51, 52, 53, 47, 54, 43, 55, 
+	56, 57, 58, 43, 59, 60, 61, 43, 
+	43, 43, 43, 62, 63, 64, 65, 1, 
+	43, 44, 67, 67, 67, 67, 67, 67, 
+	67, 67, 67, 67, 67, 67, 67, 68, 
+	67, 67, 67, 67, 67, 67, 67, 48, 
+	49, 50, 51, 67, 67, 67, 67, 67, 
+	67, 67, 67, 67, 67, 59, 60, 61, 
+	67, 67, 67, 67, 67, 63, 64, 65, 
+	69, 67, 44, 1, 43, 43, 45, 43, 
+	43, 43, 43, 43, 43, 47, 48, 49, 
+	50, 51, 52, 53, 47, 54, 46, 55, 
+	56, 57, 58, 43, 59, 60, 61, 43, 
+	43, 43, 43, 62, 63, 64, 65, 1, 
+	43, 74, 73, 73, 73, 73, 73, 73, 
+	73, 75, 73, 11, 76, 74, 73, 44, 
+	1, 43, 43, 45, 43, 43, 43, 43, 
+	43, 77, 47, 48, 49, 50, 51, 52, 
+	53, 47, 54, 46, 55, 56, 57, 58, 
+	43, 59, 60, 61, 43, 78, 79, 43, 
+	62, 63, 64, 65, 1, 43, 44, 1, 
+	43, 43, 45, 43, 43, 43, 43, 43, 
+	43, 47, 48, 49, 50, 51, 52, 53, 
+	47, 54, 46, 55, 56, 57, 58, 43, 
+	59, 60, 61, 43, 78, 79, 43, 62, 
+	63, 64, 65, 1, 43, 78, 79, 80, 
+	79, 80, 3, 6, 81, 81, 82, 81, 
+	81, 81, 81, 81, 83, 18, 19, 20, 
+	21, 22, 23, 24, 18, 25, 27, 27, 
+	28, 29, 30, 81, 31, 32, 33, 81, 
+	81, 81, 81, 37, 38, 39, 40, 6, 
+	81, 3, 6, 81, 81, 82, 81, 81, 
+	81, 81, 81, 81, 18, 19, 20, 21, 
+	22, 23, 24, 18, 25, 27, 27, 28, 
+	29, 30, 81, 31, 32, 33, 81, 81, 
+	81, 81, 37, 38, 39, 40, 6, 81, 
+	18, 19, 20, 21, 22, 81, 81, 81, 
+	81, 81, 81, 28, 29, 30, 81, 31, 
+	32, 33, 81, 81, 81, 81, 19, 38, 
+	39, 40, 84, 81, 19, 20, 21, 22, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 31, 32, 33, 81, 81, 81, 
+	81, 81, 38, 39, 40, 84, 81, 20, 
+	21, 22, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 38, 39, 40, 81, 
+	21, 22, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 38, 39, 40, 81, 
+	22, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 38, 39, 40, 81, 38, 
+	39, 81, 39, 81, 20, 21, 22, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 31, 32, 33, 81, 81, 81, 81, 
+	81, 38, 39, 40, 84, 81, 20, 21, 
+	22, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 32, 33, 81, 81, 
+	81, 81, 81, 38, 39, 40, 84, 81, 
+	20, 21, 22, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 33, 
+	81, 81, 81, 81, 81, 38, 39, 40, 
+	84, 81, 20, 21, 22, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 38, 
+	39, 40, 84, 81, 19, 20, 21, 22, 
+	81, 81, 81, 81, 81, 81, 28, 29, 
+	30, 81, 31, 32, 33, 81, 81, 81, 
+	81, 19, 38, 39, 40, 84, 81, 19, 
+	20, 21, 22, 81, 81, 81, 81, 81, 
+	81, 81, 29, 30, 81, 31, 32, 33, 
+	81, 81, 81, 81, 19, 38, 39, 40, 
+	84, 81, 19, 20, 21, 22, 81, 81, 
+	81, 81, 81, 81, 81, 81, 30, 81, 
+	31, 32, 33, 81, 81, 81, 81, 19, 
+	38, 39, 40, 84, 81, 18, 19, 20, 
+	21, 22, 81, 24, 18, 81, 81, 81, 
+	28, 29, 30, 81, 31, 32, 33, 81, 
+	81, 81, 81, 19, 38, 39, 40, 84, 
+	81, 18, 19, 20, 21, 22, 81, 85, 
+	18, 81, 81, 81, 28, 29, 30, 81, 
+	31, 32, 33, 81, 81, 81, 81, 19, 
+	38, 39, 40, 84, 81, 18, 19, 20, 
+	21, 22, 81, 81, 18, 81, 81, 81, 
+	28, 29, 30, 81, 31, 32, 33, 81, 
+	81, 81, 81, 19, 38, 39, 40, 84, 
+	81, 18, 19, 20, 21, 22, 23, 24, 
+	18, 81, 81, 81, 28, 29, 30, 81, 
+	31, 32, 33, 81, 81, 81, 81, 19, 
+	38, 39, 40, 84, 81, 3, 6, 81, 
+	81, 82, 81, 81, 81, 81, 81, 81, 
+	18, 19, 20, 21, 22, 23, 24, 18, 
+	25, 81, 27, 28, 29, 30, 81, 31, 
+	32, 33, 81, 81, 81, 81, 37, 38, 
+	39, 40, 6, 81, 3, 81, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	81, 81, 4, 81, 81, 81, 81, 81, 
+	81, 81, 19, 20, 21, 22, 81, 81, 
+	81, 81, 81, 81, 81, 81, 81, 81, 
+	31, 32, 33, 81, 81, 81, 81, 81, 
+	38, 39, 40, 84, 81, 3, 86, 86, 
+	86, 86, 86, 86, 86, 86, 86, 86, 
+	86, 86, 86, 4, 86, 87, 81, 14, 
+	81, 81, 81, 81, 81, 81, 81, 88, 
+	81, 14, 81, 6, 86, 86, 86, 86, 
+	86, 86, 86, 86, 86, 86, 86, 86, 
+	86, 86, 86, 86, 86, 86, 86, 86, 
+	86, 86, 86, 86, 86, 86, 86, 86, 
+	86, 86, 86, 6, 86, 86, 86, 6, 
+	86, 9, 81, 81, 81, 9, 81, 81, 
+	81, 81, 81, 3, 6, 14, 81, 82, 
+	81, 81, 81, 81, 81, 81, 18, 19, 
+	20, 21, 22, 23, 24, 18, 25, 26, 
+	27, 28, 29, 30, 81, 31, 32, 33, 
+	81, 34, 35, 81, 37, 38, 39, 40, 
+	6, 81, 3, 6, 81, 81, 82, 81, 
+	81, 81, 81, 81, 81, 18, 19, 20, 
+	21, 22, 23, 24, 18, 25, 26, 27, 
+	28, 29, 30, 81, 31, 32, 33, 81, 
+	81, 81, 81, 37, 38, 39, 40, 6, 
+	81, 34, 35, 81, 35, 81, 78, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 80, 80, 80, 80, 80, 80, 
+	80, 80, 78, 79, 80, 9, 86, 86, 
+	86, 9, 86, 0
 };
 
 static const char _use_syllable_machine_trans_targs[] = {
-	4, 8, 4, 32, 2, 4, 1, 5,
-	6, 4, 29, 4, 51, 52, 53, 55,
-	34, 35, 36, 37, 38, 45, 46, 48,
-	54, 49, 42, 43, 44, 39, 40, 41,
-	58, 50, 4, 4, 4, 4, 7, 0,
-	28, 11, 12, 13, 14, 15, 22, 23,
-	25, 26, 19, 20, 21, 16, 17, 18,
-	27, 10, 4, 9, 24, 4, 30, 31,
-	4, 4, 3, 33, 47, 4, 4, 56,
-	57
+	5, 9, 5, 41, 2, 5, 1, 53, 
+	6, 7, 5, 34, 37, 63, 64, 67, 
+	68, 72, 43, 44, 45, 46, 47, 57, 
+	58, 60, 69, 61, 54, 55, 56, 50, 
+	51, 52, 70, 71, 73, 62, 48, 49, 
+	5, 5, 5, 5, 8, 0, 33, 12, 
+	13, 14, 15, 16, 27, 28, 30, 31, 
+	24, 25, 26, 19, 20, 21, 32, 17, 
+	18, 5, 11, 5, 10, 22, 5, 23, 
+	29, 5, 35, 36, 5, 38, 39, 40, 
+	5, 5, 3, 42, 4, 59, 5, 65, 
+	66
 };
 
 static const char _use_syllable_machine_trans_actions[] = {
-	1, 0, 2, 3, 0, 4, 0, 0, 
-	7, 8, 0, 9, 10, 10, 3, 0, 
+	1, 0, 2, 3, 0, 4, 0, 5, 
+	0, 5, 8, 0, 5, 9, 0, 9, 
+	3, 0, 5, 5, 0, 0, 0, 5, 
+	5, 5, 3, 3, 5, 5, 5, 5, 
+	5, 5, 0, 0, 0, 3, 0, 0, 
+	10, 11, 12, 13, 5, 0, 5, 0, 
+	0, 0, 0, 0, 0, 0, 0, 5, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	3, 3, 0, 0, 0, 0, 0, 0, 
-	0, 3, 11, 12, 13, 14, 7, 0,
-	7, 0, 0, 0, 0, 0, 0, 0,
-	0, 7, 0, 0, 0, 0, 0, 0,
-	0, 7, 15, 0, 0, 16, 0, 0,
-	17, 18, 0, 3, 0, 19, 20, 0,
+	0, 14, 5, 15, 0, 0, 16, 0, 
+	0, 17, 0, 0, 18, 5, 0, 0, 
+	19, 20, 0, 3, 0, 5, 21, 0, 
 	0
 };
 
 static const char _use_syllable_machine_to_state_actions[] = {
-	0, 0, 0, 0, 5, 0, 0, 0, 
+	0, 0, 0, 0, 0, 6, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0
 };
 
 static const char _use_syllable_machine_from_state_actions[] = {
-	0, 0, 0, 0, 6, 0, 0, 0, 
+	0, 0, 0, 0, 0, 7, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0
 };
 
 static const short _use_syllable_machine_eof_trans[] = {
-	1, 3, 3, 6, 0, 35, 37, 37,
-	59, 59, 37, 37, 37, 37, 37, 37,
-	37, 37, 37, 37, 37, 37, 37, 37,
-	37, 37, 37, 59, 37, 62, 65, 62,
-	66, 66, 66, 66, 66, 66, 66, 66,
-	66, 66, 66, 66, 66, 66, 66, 66,
-	66, 66, 66, 70, 70, 66, 66, 71,
-	71, 71, 70
+	1, 3, 3, 6, 6, 0, 42, 44, 
+	44, 68, 68, 44, 44, 44, 44, 44, 
+	44, 44, 44, 44, 44, 44, 71, 44, 
+	44, 44, 44, 44, 44, 44, 44, 44, 
+	68, 44, 74, 77, 74, 44, 44, 81, 
+	81, 82, 82, 82, 82, 82, 82, 82, 
+	82, 82, 82, 82, 82, 82, 82, 82, 
+	82, 82, 82, 82, 82, 82, 82, 87, 
+	82, 82, 82, 87, 82, 82, 82, 82, 
+	81, 87
 };
 
-static const int use_syllable_machine_start = 4;
-static const int use_syllable_machine_first_final = 4;
+static const int use_syllable_machine_start = 5;
+static const int use_syllable_machine_first_final = 5;
 static const int use_syllable_machine_error = -1;
 
-static const int use_syllable_machine_en_main = 4;
+static const int use_syllable_machine_en_main = 5;
 
 
 #line 38 "hb-ot-shape-complex-use-machine.rl"
 
 
 
-#line 143 "hb-ot-shape-complex-use-machine.rl"
+#line 162 "hb-ot-shape-complex-use-machine.rl"
 
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_use (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 378 "hb-ot-shape-complex-use-machine.hh"
+#line 396 "hb-ot-shape-complex-use-machine.hh"
 	{
 	cs = use_syllable_machine_start;
 	ts = 0;
@@ -382,7 +400,7 @@
 	act = 0;
 	}
 
-#line 163 "hb-ot-shape-complex-use-machine.rl"
+#line 182 "hb-ot-shape-complex-use-machine.rl"
 
 
   p = 0;
@@ -390,7 +408,7 @@
 
   unsigned int syllable_serial = 1;
   
-#line 394 "hb-ot-shape-complex-use-machine.hh"
+#line 412 "hb-ot-shape-complex-use-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -400,11 +418,11 @@
 		goto _test_eof;
 _resume:
 	switch ( _use_syllable_machine_from_state_actions[cs] ) {
-	case 6:
+	case 7:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 408 "hb-ot-shape-complex-use-machine.hh"
+#line 426 "hb-ot-shape-complex-use-machine.hh"
 	}
 
 	_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -422,73 +440,77 @@
 		goto _again;
 
 	switch ( _use_syllable_machine_trans_actions[_trans] ) {
-	case 7:
+	case 5:
 #line 1 "NONE"
 	{te = p+1;}
 	break;
 	case 12:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 150 "hb-ot-shape-complex-use-machine.rl"
 	{te = p+1;{ found_syllable (independent_cluster); }}
 	break;
 	case 14:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
 	{te = p+1;{ found_syllable (standard_cluster); }}
 	break;
-	case 9:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+	case 10:
+#line 157 "hb-ot-shape-complex-use-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
 	case 8:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+#line 158 "hb-ot-shape-complex-use-machine.rl"
 	{te = p+1;{ found_syllable (non_cluster); }}
 	break;
 	case 11:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 150 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (independent_cluster); }}
 	break;
 	case 15:
-#line 133 "hb-ot-shape-complex-use-machine.rl"
+#line 151 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
 	break;
+	case 16:
+#line 152 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (sakot_terminated_cluster); }}
+	break;
 	case 13:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (standard_cluster); }}
 	break;
-	case 17:
-#line 135 "hb-ot-shape-complex-use-machine.rl"
+	case 18:
+#line 154 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
 	break;
-	case 16:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+	case 17:
+#line 155 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (numeral_cluster); }}
 	break;
-	case 20:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
+	case 19:
+#line 156 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (symbol_cluster); }}
 	break;
-	case 18:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+	case 20:
+#line 157 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
-	case 19:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+	case 21:
+#line 158 "hb-ot-shape-complex-use-machine.rl"
 	{te = p;p--;{ found_syllable (non_cluster); }}
 	break;
 	case 1:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (standard_cluster); }}
 	break;
 	case 4:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+#line 157 "hb-ot-shape-complex-use-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
 	break;
 	case 2:
 #line 1 "NONE"
 	{	switch( act ) {
-	case 7:
+	case 8:
 	{{p = ((te))-1;} found_syllable (broken_cluster); }
 	break;
-	case 8:
+	case 9:
 	{{p = ((te))-1;} found_syllable (non_cluster); }
 	break;
 	}
@@ -497,25 +519,25 @@
 	case 3:
 #line 1 "NONE"
 	{te = p+1;}
-#line 138 "hb-ot-shape-complex-use-machine.rl"
-	{act = 7;}
-	break;
-	case 10:
-#line 1 "NONE"
-	{te = p+1;}
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+#line 157 "hb-ot-shape-complex-use-machine.rl"
 	{act = 8;}
 	break;
-#line 510 "hb-ot-shape-complex-use-machine.hh"
+	case 9:
+#line 1 "NONE"
+	{te = p+1;}
+#line 158 "hb-ot-shape-complex-use-machine.rl"
+	{act = 9;}
+	break;
+#line 532 "hb-ot-shape-complex-use-machine.hh"
 	}
 
 _again:
 	switch ( _use_syllable_machine_to_state_actions[cs] ) {
-	case 5:
+	case 6:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 519 "hb-ot-shape-complex-use-machine.hh"
+#line 541 "hb-ot-shape-complex-use-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -531,7 +553,7 @@
 
 	}
 
-#line 171 "hb-ot-shape-complex-use-machine.rl"
+#line 190 "hb-ot-shape-complex-use-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl
index 7702cd9..9b75b5c 100644
--- a/src/hb-ot-shape-complex-use-machine.rl
+++ b/src/hb-ot-shape-complex-use-machine.rl
@@ -49,7 +49,7 @@
 GB	= 5; # BASE_OTHER
 CGJ	= 6; # CGJ
 #F	= 7; # CONS_FINAL
-FM	= 8; # CONS_FINAL_MOD
+#FM	= 8; # CONS_FINAL_MOD
 #M	= 9; # CONS_MED
 #CM	= 10; # CONS_MOD
 SUB	= 11; # CONS_SUB
@@ -66,6 +66,9 @@
 VS	= 21; # VARIATION_SELECTOR
 #V	= 36; # VOWEL
 #VM	= 40; # VOWEL_MOD
+CS	= 43; # CONS_WITH_STACKER
+HVM	= 44; # HALANT_OR_VOWEL_MODIFIER
+Sk	= 48; # SAKOT
 
 FAbv	= 24; # CONS_FINAL_ABOVE
 FBlw	= 25; # CONS_FINAL_BELOW
@@ -86,11 +89,11 @@
 VMPre	= 23; # VOWEL_MOD_PRE
 SMAbv	= 41; # SYM_MOD_ABOVE
 SMBlw	= 42; # SYM_MOD_BELOW
-CS	= 43; # CONS_WITH_STACKER
+FMAbv	= 45; # CONS_FINAL_MOD	UIPC = Top
+FMBlw	= 46; # CONS_FINAL_MOD	UIPC = Bottom
+FMPst	= 47; # CONS_FINAL_MOD	UIPC = Not_Applicable
 
-HVM	= 44; # HALANT_OR_VOWEL_MODIFIER
-
-h = H | HVM; # https://github.com/harfbuzz/harfbuzz/issues/1102
+h = H | HVM | Sk;
 
 # Override: Adhoc ZWJ placement. https://github.com/harfbuzz/harfbuzz/issues/542#issuecomment-353169729
 consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.h.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*;
@@ -98,39 +101,55 @@
 medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
 dependent_vowels = VPre* VAbv* VBlw* VPst*;
 vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
-final_consonants = FAbv* FBlw* FPst* FM?;
+final_consonants = FAbv* FBlw* FPst*;
+final_modifiers = FMAbv* FMBlw* | FMPst?;
 
-complex_syllable_tail =
+complex_syllable_start = (R | CS)? (B | GB) VS?;
+complex_syllable_middle =
 	consonant_modifiers
 	medial_consonants
 	dependent_vowels
 	vowel_modifiers
-	final_consonants
+	(Sk B)*
 ;
+complex_syllable_tail =
+	complex_syllable_middle
+	final_consonants
+	final_modifiers
+;
+number_joiner_terminated_cluster_tail = (HN N VS?)* HN;
+numeral_cluster_tail = (HN N VS?)+;
+symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
 
 virama_terminated_cluster =
-	(R|CS)? (B | GB) VS?
+	complex_syllable_start
 	consonant_modifiers
 	ZWJ?.h.ZWJ?
 ;
+sakot_terminated_cluster =
+	complex_syllable_start
+	complex_syllable_middle
+	Sk
+;
 standard_cluster =
-	(R|CS)? (B | GB) VS?
+	complex_syllable_start
 	complex_syllable_tail
 ;
 broken_cluster =
 	R?
-	complex_syllable_tail
+	(complex_syllable_tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail | symbol_cluster_tail)
 ;
 
-number_joiner_terminated_cluster = N VS? (HN N VS?)* HN;
-numeral_cluster = N VS? (HN N VS?)*;
-symbol_cluster = S VS? SMAbv* SMBlw*;
+number_joiner_terminated_cluster = N VS? number_joiner_terminated_cluster_tail;
+numeral_cluster = N VS? numeral_cluster_tail?;
+symbol_cluster = (S | GB) VS? symbol_cluster_tail?;
 independent_cluster = (IND | O | Rsv | WJ) VS?;
 other = any;
 
 main := |*
 	independent_cluster			=> { found_syllable (independent_cluster); };
 	virama_terminated_cluster		=> { found_syllable (virama_terminated_cluster); };
+	sakot_terminated_cluster		=> { found_syllable (sakot_terminated_cluster); };
 	standard_cluster			=> { found_syllable (standard_cluster); };
 	number_joiner_terminated_cluster	=> { found_syllable (number_joiner_terminated_cluster); };
 	numeral_cluster				=> { found_syllable (numeral_cluster); };
@@ -146,13 +165,13 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_use (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc
index 2f3eb70..e3889b3 100644
--- a/src/hb-ot-shape-complex-use-table.cc
+++ b/src/hb-ot-shape-complex-use-table.cc
@@ -6,21 +6,26 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-11.0.0.txt
- * # Date: 2018-05-21, 18:33:00 GMT [KW, RP]
- * # IndicPositionalCategory-11.0.0.txt
- * # Date: 2018-02-05, 16:21:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # IndicSyllabicCategory-12.0.0.txt
+ * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
+ * # IndicPositionalCategory-12.0.0.txt
+ * # Date: 2019-01-31, 02:26:00 GMT [KW, RP]
+ * # Blocks-12.0.0.txt
+ * # Date: 2018-07-30, 19:40:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-use.hh"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-macros"
 #define B	USE_B	/* BASE */
 #define CGJ	USE_CGJ	/* CGJ */
 #define CS	USE_CS	/* CONS_WITH_STACKER */
-#define FM	USE_FM	/* CONS_FINAL_MOD */
 #define GB	USE_GB	/* BASE_OTHER */
 #define H	USE_H	/* HALANT */
 #define HN	USE_HN	/* HALANT_NUM */
@@ -32,6 +37,7 @@
 #define Rsv	USE_Rsv	/* Reserved */
 #define S	USE_S	/* SYM */
 #define SUB	USE_SUB	/* CONS_SUB */
+#define Sk	USE_Sk	/* SAKOT */
 #define VS	USE_VS	/* VARIATION_SELECTOR */
 #define WJ	USE_WJ	/* Word_Joiner */
 #define ZWJ	USE_ZWJ	/* ZWJ */
@@ -41,6 +47,9 @@
 #define FBlw	USE_FBlw
 #define FPst	USE_FPst
 #define FAbv	USE_FAbv
+#define FMBlw	USE_FMBlw
+#define FMPst	USE_FMPst
+#define FMAbv	USE_FMAbv
 #define MPre	USE_MPre
 #define MBlw	USE_MBlw
 #define MPst	USE_MPst
@@ -55,6 +64,7 @@
 #define VMBlw	USE_VMBlw
 #define VMPst	USE_VMPst
 #define VMAbv	USE_VMAbv
+#pragma GCC diagnostic pop
 
 static const USE_TABLE_ELEMENT_TYPE use_table[] = {
 
@@ -72,7 +82,7 @@
   /* Latin-1 Supplement */
 
   /* 00A0 */    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 00B0 */     O,     O,    FM,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00B0 */     O,     O, FMPst, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 00C0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 00D0 */     O,     O,     O,     O,     O,     O,     O,    GB,
 
@@ -105,7 +115,7 @@
   /* 09C0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPst,  VPst,     H,   IND,     O,
   /* 09D0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     B,     B,     O,     B,
   /* 09E0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O,    FM,     O,
+  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O, FMAbv,     O,
 
   /* Gurmukhi */
 
@@ -164,7 +174,7 @@
 
   /* Kannada */
 
-  /* 0C80 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0C80 */     B, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
   /* 0C90 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 0CB0 */     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
@@ -201,7 +211,7 @@
   /* Tibetan */
                                                                       VBlw,  VBlw,     O,     O,     O,     O,     O,     O,
   /* 0F20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0F30 */     B,     B,     B,     B,     O,    FM,     O,    FM,     O, CMAbv,     O,     O,     O,     O,  VPst,  VPre,
+  /* 0F30 */     B,     B,     B,     B,     O, FMBlw,     O, FMBlw,     O, CMAbv,     O,     O,     O,     O,  VPst,  VPre,
   /* 0F40 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
   /* 0F50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0F60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
@@ -210,7 +220,7 @@
   /* 0F90 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 0FA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 0FB0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,     O,     O,
-  /* 0FC0 */     O,     O,     O,     O,     O,     O,    FM,     O,
+  /* 0FC0 */     O,     O,     O,     O,     O,     O, FMBlw,     O,
 
 #define use_offset_0x1000u 1536
 
@@ -257,8 +267,8 @@
   /* 1790 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 17A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 17B0 */     B,     B,     B,     B,     O,     O,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPst,  VPst,
-  /* 17C0 */  VPst,  VPre,  VPre,  VPre,  VPst,  VPst, VMAbv, VMPst,  VPst, VMAbv, VMAbv,    FM,  FAbv, CMAbv,    FM,    FM,
-  /* 17D0 */    FM,  VAbv,     H,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     B,  VAbv,     O,     O,
+  /* 17C0 */  VPst,  VPre,  VPre,  VPre,  VPst,  VPst, VMAbv, VMPst,  VPst, VMAbv, VMAbv, FMAbv,  FAbv, CMAbv, FMAbv, FMAbv,
+  /* 17D0 */ FMAbv,  VAbv,     H, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,     O,     O,
   /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
 #define use_offset_0x1900u 1936
@@ -269,7 +279,7 @@
   /* 1900 */    GB,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
   /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,     O,     O,     O,     O,
-  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv,    FM,     O,     O,     O,     O,
+  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv, FMBlw,     O,     O,     O,     O,
   /* 1940 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
 
   /* Tai Le */
@@ -285,7 +295,7 @@
   /* 19A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
   /* 19B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 19C0 */     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,     O,     O,     O,     O,     O,     O,
-  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,
   /* 19E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 19F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
@@ -299,9 +309,9 @@
   /* 1A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1A30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,   SUB,  FAbv,  FAbv,  FAbv,   SUB,   SUB,   SUB,   SUB,     O,
-  /* 1A60 */     H,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
-  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv,    FM,    FM,     O,     O,  FBlw,
+  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,   SUB,  FAbv,  FAbv,  MAbv,   SUB,   SUB,   SUB,   SUB,     O,
+  /* 1A60 */    Sk,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
+  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv, FMAbv, FMAbv,     O,     O, FMBlw,
   /* 1A80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
   /* 1A90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
@@ -315,8 +325,8 @@
   /* 1B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1B30 */     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VPre,
   /* 1B40 */  VPst,  VPst,  VAbv,  VAbv,     H,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
-  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 1B60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
+  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,    GB,     O,     O,    GB,
+  /* 1B60 */     O,     S,    GB,     S,     S,     S,     S,     S,    GB,     S,     S, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
   /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Sundanese */
@@ -337,8 +347,8 @@
 
   /* 1C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPst,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
-  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre,    FM, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPre,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
+  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre, FMAbv, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 1C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,
 
 #define use_offset_0x1cd0u 2688
@@ -348,13 +358,13 @@
 
   /* 1CD0 */ VMAbv, VMAbv, VMAbv,     O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
   /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,     O,     O,     O,     O, VMBlw,     O,     O,
-  /* 1CF0 */     O,     O, VMPst, VMPst, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,
+  /* 1CF0 */     O,     O,   IND,   IND, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,    GB,     O,     O,     O,     O,     O,
 
 #define use_offset_0x1df8u 2736
 
 
   /* Combining Diacritical Marks Supplement */
-                                                                         O,     O,     O,    FM,     O,     O,     O,     O,
+                                                                         O,     O,     O, FMAbv,     O,     O,     O,     O,
 
 #define use_offset_0x2008u 2744
 
@@ -369,8 +379,8 @@
 
   /* Superscripts and Subscripts */
 
-  /* 2070 */     O,     O,     O,     O,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2080 */     O,     O,    FM,    FM,    FM,     O,     O,     O,
+  /* 2070 */     O,     O,     O,     O, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 2080 */     O,     O, FMPst, FMPst, FMPst,     O,     O,     O,
 
 #define use_offset_0x20f0u 2800
 
@@ -390,7 +400,7 @@
 
   /* Syloti Nagri */
 
-  /* A800 */     B,     B,     O,     B,     B,     B,  VAbv,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
+  /* A800 */     B,     B,  VAbv,     B,     B,     B,     H,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
   /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
@@ -435,7 +445,7 @@
   /* A980 */ VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A9A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,   SUB,  MPst,  MBlw,
+  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,  MBlw,  MPst,  MBlw,
   /* A9C0 */     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A9D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
@@ -544,7 +554,7 @@
   /* 11190 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 111A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 111B0 */     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,
-  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,    GB,  FBlw, CMBlw,  VAbv,  VBlw,     O,     O,     O,
+  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,    GB, FMBlw, CMBlw,  VAbv,  VBlw,     O,     O,     O,
   /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
   /* Sinhala Archaic Numbers */
@@ -578,7 +588,7 @@
 
   /* Grantha */
 
-  /* 11300 */ VMAbv, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
+  /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
   /* 11310 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 11330 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O, CMBlw, CMBlw,     B,  VPst,  VPst,
@@ -597,7 +607,7 @@
   /* 11420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11430 */     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,
   /* 11440 */  VPst,  VPst,     H, VMAbv, VMAbv, VMPst, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,    FM,     O,
+  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O, FMAbv,     B,
   /* 11460 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 11470 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
@@ -607,7 +617,7 @@
   /* 11490 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VPre,  VAbv,  VPst,  VPst,  VPst,  VPst, VMAbv,
-  /* 114C0 */ VMAbv, VMPst,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 114C0 */ VMAbv, VMAbv,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 114D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
 #define use_offset_0x11580u 4720
@@ -640,7 +650,7 @@
   /* 11680 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11690 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 116A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMPst,  VAbv,  VPre,  VPst,
-  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,
   /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
   /* 116D0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 116E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
@@ -663,15 +673,24 @@
   /* 11820 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,
   /* 11830 */  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMPst,     H, CMBlw,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11a00u 5232
+#define use_offset_0x119a0u 5232
 
 
+  /* Nandinagari */
+
+  /* 119A0 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,     B,     B,     B,     B,     B,
+  /* 119B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 119C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 119D0 */     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VAbv,  VAbv,  VPst,  VPst, VMPst, VMPst,
+  /* 119E0 */     H,     B,     O,     O,  VPre,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 119F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
   /* Zanabazar Square */
 
   /* 11A00 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     B,     B,     B,     B,     B,
   /* 11A10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A30 */     B,     B,     B,    FM,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
+  /* 11A30 */     B,     B,     B, FMBlw,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
   /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,     H,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Soyombo */
@@ -679,10 +698,10 @@
   /* 11A50 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VBlw,  VBlw,  VBlw,     B,     B,     B,     B,
   /* 11A60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A80 */     B,     B,     B,     B,     O,     O,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
+  /* 11A80 */     B,     B,     B,     B,     R,     R,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
   /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,     H,     O,     O,     O,     B,     O,     O,
 
-#define use_offset_0x11c00u 5392
+#define use_offset_0x11c00u 5488
 
 
   /* Bhaiksuki */
@@ -703,7 +722,7 @@
   /* 11CA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 11CB0 */  VBlw,  VPre,  VBlw,  VAbv,  VPst, VMAbv, VMAbv,     O,
 
-#define use_offset_0x11d00u 5576
+#define use_offset_0x11d00u 5672
 
 
   /* Masaram Gondi */
@@ -723,7 +742,7 @@
   /* 11D90 */  VAbv,  VAbv,     O,  VPst,  VPst, VMAbv, VMPst,     H,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 11DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11ee0u 5752
+#define use_offset_0x11ee0u 5848
 
 
   /* Makasar */
@@ -731,7 +750,7 @@
   /* 11EE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11EF0 */     B,     B,    GB,  VAbv,  VBlw,  VPre,  VPst,     O,
 
-}; /* Table items: 5776; occupancy: 74% */
+}; /* Table items: 5872; occupancy: 74% */
 
 USE_TABLE_ELEMENT_TYPE
 hb_use_get_category (hb_codepoint_t u)
@@ -782,7 +801,7 @@
       if (hb_in_range<hb_codepoint_t> (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11800u, 0x1183Fu)) return use_table[u - 0x11800u + use_offset_0x11800u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11A00u, 0x11A9Fu)) return use_table[u - 0x11A00u + use_offset_0x11a00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x119A0u, 0x11A9Fu)) return use_table[u - 0x119A0u + use_offset_0x119a0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11D00u, 0x11DAFu)) return use_table[u - 0x11D00u + use_offset_0x11d00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11EE0u, 0x11EF7u)) return use_table[u - 0x11EE0u + use_offset_0x11ee0u];
@@ -797,7 +816,6 @@
 #undef B
 #undef CGJ
 #undef CS
-#undef FM
 #undef GB
 #undef H
 #undef HN
@@ -809,6 +827,7 @@
 #undef Rsv
 #undef S
 #undef SUB
+#undef Sk
 #undef VS
 #undef WJ
 #undef ZWJ
@@ -818,6 +837,9 @@
 #undef FBlw
 #undef FPst
 #undef FAbv
+#undef FMBlw
+#undef FMPst
+#undef FMAbv
 #undef MPre
 #undef MBlw
 #undef MPst
@@ -833,4 +855,6 @@
 #undef VMPst
 #undef VMAbv
 
+
+#endif
 /* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index 2e3f202..10f5822 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -26,6 +26,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-use.hh"
 #include "hb-ot-shape-complex-arabic.hh"
 #include "hb-ot-shape-complex-vowel-constraints.hh"
@@ -40,7 +44,7 @@
  */
 
 static const hb_tag_t
-basic_features[] =
+use_basic_features[] =
 {
   /*
    * Basic features.
@@ -55,28 +59,23 @@
   HB_TAG('c','j','c','t'),
 };
 static const hb_tag_t
-arabic_features[] =
+use_topographical_features[] =
 {
   HB_TAG('i','s','o','l'),
   HB_TAG('i','n','i','t'),
   HB_TAG('m','e','d','i'),
   HB_TAG('f','i','n','a'),
-  /* The spec doesn't specify these but we apply anyway, since our Arabic shaper
-   * does.  These are only used in Syriac spec. */
-  HB_TAG('m','e','d','2'),
-  HB_TAG('f','i','n','2'),
-  HB_TAG('f','i','n','3'),
 };
-/* Same order as arabic_features.  Don't need Syriac stuff.*/
+/* Same order as use_topographical_features. */
 enum joining_form_t {
-  ISOL,
-  INIT,
-  MEDI,
-  FINA,
-  _NONE
+  USE_ISOL,
+  USE_INIT,
+  USE_MEDI,
+  USE_FINA,
+  _USE_NONE
 };
 static const hb_tag_t
-other_features[] =
+use_other_features[] =
 {
   /*
    * Other features.
@@ -89,42 +88,23 @@
   HB_TAG('p','r','e','s'),
   HB_TAG('p','s','t','s'),
 };
-static const hb_tag_t
-positioning_features[] =
-{
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  HB_TAG('d','i','s','t'),
-  HB_TAG('a','b','v','m'),
-  HB_TAG('b','l','w','m'),
-};
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
+setup_syllables_use (const hb_ot_shape_plan_t *plan,
+		     hb_font_t *font,
+		     hb_buffer_t *buffer);
+static void
+record_rphf_use (const hb_ot_shape_plan_t *plan,
 		 hb_font_t *font,
 		 hb_buffer_t *buffer);
 static void
-clear_substitution_flags (const hb_ot_shape_plan_t *plan,
-			  hb_font_t *font,
-			  hb_buffer_t *buffer);
-static void
-record_rphf (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
-	     hb_buffer_t *buffer);
-static void
-record_pref (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
-	     hb_buffer_t *buffer);
-static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
+record_pref_use (const hb_ot_shape_plan_t *plan,
 		 hb_font_t *font,
 		 hb_buffer_t *buffer);
+static void
+reorder_use (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer);
 
 static void
 collect_features_use (hb_ot_shape_planner_t *plan)
@@ -132,7 +112,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_use);
 
   /* "Default glyph pre-processing group" */
   map->enable_feature (HB_TAG('l','o','c','l'));
@@ -141,32 +121,28 @@
   map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
 
   /* "Reordering group" */
-  map->add_gsub_pause (clear_substitution_flags);
+  map->add_gsub_pause (_hb_clear_substitution_flags);
   map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
-  map->add_gsub_pause (record_rphf);
-  map->add_gsub_pause (clear_substitution_flags);
+  map->add_gsub_pause (record_rphf_use);
+  map->add_gsub_pause (_hb_clear_substitution_flags);
   map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
-  map->add_gsub_pause (record_pref);
+  map->add_gsub_pause (record_pref_use);
 
   /* "Orthographic unit shaping group" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
-    map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
+    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
 
-  map->add_gsub_pause (reorder);
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (reorder_use);
+  map->add_gsub_pause (_hb_clear_syllables);
 
   /* "Topographical features" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
-    map->add_feature (arabic_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
+    map->add_feature (use_topographical_features[i]);
   map->add_gsub_pause (nullptr);
 
   /* "Standard typographic presentation" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
-    map->enable_feature (other_features[i], F_MANUAL_ZWJ);
-
-  /* "Positional feature application" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
-    map->enable_feature (positioning_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++)
+    map->enable_feature (use_other_features[i], F_MANUAL_ZWJ);
 }
 
 struct use_shape_plan_t
@@ -243,15 +219,16 @@
   free (data);
 }
 
-enum syllable_type_t {
-  independent_cluster,
-  virama_terminated_cluster,
-  standard_cluster,
-  number_joiner_terminated_cluster,
-  numeral_cluster,
-  symbol_cluster,
-  broken_cluster,
-  non_cluster,
+enum use_syllable_type_t {
+  use_independent_cluster,
+  use_virama_terminated_cluster,
+  use_sakot_terminated_cluster,
+  use_standard_cluster,
+  use_number_joiner_terminated_cluster,
+  use_numeral_cluster,
+  use_symbol_cluster,
+  use_broken_cluster,
+  use_non_cluster,
 };
 
 #include "hb-ot-shape-complex-use-machine.hh"
@@ -294,7 +271,7 @@
 
   foreach_syllable (buffer, start, end)
   {
-    unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start);
+    unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
     for (unsigned int i = start; i < start + limit; i++)
       info[i].mask |= mask;
   }
@@ -308,11 +285,11 @@
   if (use_plan->arabic_plan)
     return;
 
-  static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), "");
+  static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
   hb_mask_t masks[4], all_masks = 0;
   for (unsigned int i = 0; i < 4; i++)
   {
-    masks[i] = plan->map.get_1_mask (arabic_features[i]);
+    masks[i] = plan->map.get_1_mask (use_topographical_features[i]);
     if (masks[i] == plan->map.get_global_mask ())
       masks[i] = 0;
     all_masks |= masks[i];
@@ -322,38 +299,39 @@
   hb_mask_t other_masks = ~all_masks;
 
   unsigned int last_start = 0;
-  joining_form_t last_form = _NONE;
+  joining_form_t last_form = _USE_NONE;
   hb_glyph_info_t *info = buffer->info;
   foreach_syllable (buffer, start, end)
   {
-    syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
+    use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
     switch (syllable_type)
     {
-      case independent_cluster:
-      case symbol_cluster:
-      case non_cluster:
+      case use_independent_cluster:
+      case use_symbol_cluster:
+      case use_non_cluster:
 	/* These don't join.  Nothing to do. */
-	last_form = _NONE;
+	last_form = _USE_NONE;
 	break;
 
-      case virama_terminated_cluster:
-      case standard_cluster:
-      case number_joiner_terminated_cluster:
-      case numeral_cluster:
-      case broken_cluster:
+      case use_virama_terminated_cluster:
+      case use_sakot_terminated_cluster:
+      case use_standard_cluster:
+      case use_number_joiner_terminated_cluster:
+      case use_numeral_cluster:
+      case use_broken_cluster:
 
-	bool join = last_form == FINA || last_form == ISOL;
+	bool join = last_form == USE_FINA || last_form == USE_ISOL;
 
 	if (join)
 	{
 	  /* Fixup previous syllable's form. */
-	  last_form = last_form == FINA ? MEDI : INIT;
+	  last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
 	  for (unsigned int i = last_start; i < start; i++)
 	    info[i].mask = (info[i].mask & other_masks) | masks[last_form];
 	}
 
 	/* Form for this syllable. */
-	last_form = join ? FINA : ISOL;
+	last_form = join ? USE_FINA : USE_ISOL;
 	for (unsigned int i = start; i < end; i++)
 	  info[i].mask = (info[i].mask & other_masks) | masks[last_form];
 
@@ -365,11 +343,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
+setup_syllables_use (const hb_ot_shape_plan_t *plan,
+		     hb_font_t *font HB_UNUSED,
+		     hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_use (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
   setup_rphf_mask (plan, buffer);
@@ -377,20 +355,9 @@
 }
 
 static void
-clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
-			  hb_font_t *font HB_UNUSED,
-			  hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    _hb_glyph_info_clear_substituted (&info[i]);
-}
-
-static void
-record_rphf (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font HB_UNUSED,
-	     hb_buffer_t *buffer)
+record_rphf_use (const hb_ot_shape_plan_t *plan,
+		 hb_font_t *font HB_UNUSED,
+		 hb_buffer_t *buffer)
 {
   const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
 
@@ -411,9 +378,9 @@
 }
 
 static void
-record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED,
-	     hb_font_t *font HB_UNUSED,
-	     hb_buffer_t *buffer)
+record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		 hb_font_t *font HB_UNUSED,
+		 hb_buffer_t *buffer)
 {
   hb_glyph_info_t *info = buffer->info;
 
@@ -430,21 +397,22 @@
 }
 
 static inline bool
-is_halant (const hb_glyph_info_t &info)
+is_halant_use (const hb_glyph_info_t &info)
 {
   return (info.use_category() == USE_H || info.use_category() == USE_HVM) &&
 	 !_hb_glyph_info_ligated (&info);
 }
 
 static void
-reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
+reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   /* Only a few syllable types need reordering. */
   if (unlikely (!(FLAG_UNSAFE (syllable_type) &
-		  (FLAG (virama_terminated_cluster) |
-		   FLAG (standard_cluster) |
-		   FLAG (broken_cluster) |
+		  (FLAG (use_virama_terminated_cluster) |
+		   FLAG (use_sakot_terminated_cluster) |
+		   FLAG (use_standard_cluster) |
+		   FLAG (use_broken_cluster) |
 		   0))))
     return;
 
@@ -475,7 +443,7 @@
     for (unsigned int i = start + 1; i < end; i++)
     {
       bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) ||
-				is_halant (info[i]);
+				is_halant_use (info[i]);
       if (is_post_base_glyph || i == end - 1)
       {
 	/* If we hit a post-base glyph, move before it; otherwise move to the
@@ -499,7 +467,7 @@
   for (unsigned int i = start; i < end; i++)
   {
     uint32_t flag = FLAG_UNSAFE (info[i].use_category());
-    if (is_halant (info[i]))
+    if (is_halant_use (info[i]))
     {
       /* If we hit a halant, move after it; otherwise move to the beginning, and
        * shift things in between forward. */
@@ -519,16 +487,20 @@
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		       hb_font_t *font,
-		       hb_buffer_t *buffer)
+insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
+			   hb_font_t *font,
+			   hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == use_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -548,8 +520,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -557,13 +529,12 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().use_category() == USE_R)
-        buffer->next_glyph ();
+	buffer->next_glyph ();
 
       buffer->output_info (ginfo);
     }
@@ -574,29 +545,18 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-	 hb_font_t *font,
-	 hb_buffer_t *buffer)
+reorder_use (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_use (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    reorder_syllable (buffer, start, end);
+    reorder_syllable_use (buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 static void
 preprocess_text_use (const hb_ot_shape_plan_t *plan,
@@ -637,3 +597,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/hb-ot-shape-complex-use.hh b/src/hb-ot-shape-complex-use.hh
index ab56e1b..ce6645e 100644
--- a/src/hb-ot-shape-complex-use.hh
+++ b/src/hb-ot-shape-complex-use.hh
@@ -68,6 +68,12 @@
   USE_VS	= 21,	/* VARIATION_SELECTOR */
 //  USE_V	= 36,	/* VOWEL */
 //  USE_VM	= 40,	/* VOWEL_MOD */
+  USE_CS	= 43,	/* CONS_WITH_STACKER */
+
+  /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
+  USE_HVM	= 44,	/* HALANT_OR_VOWEL_MODIFIER */
+
+  USE_Sk	= 48,	/* SAKOT */
 
   USE_FAbv	= 24,	/* CONS_FINAL_ABOVE */
   USE_FBlw	= 25,	/* CONS_FINAL_BELOW */
@@ -88,10 +94,9 @@
   USE_VMPre	= 23,	/* VOWEL_MOD_PRE */
   USE_SMAbv	= 41,	/* SYM_MOD_ABOVE */
   USE_SMBlw	= 42,	/* SYM_MOD_BELOW */
-  USE_CS	= 43,	/* CONS_WITH_STACKER */
-
-  /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
-  USE_HVM	= 44,	/* HALANT_OR_VOWEL_MODIFIER */
+  USE_FMAbv	= 45,	/* CONS_FINAL_MOD	UIPC = Top */
+  USE_FMBlw	= 46,	/* CONS_FINAL_MOD	UIPC = Bottom */
+  USE_FMPst	= 47,	/* CONS_FINAL_MOD	UIPC = Not_Applicable */
 };
 
 HB_INTERNAL USE_TABLE_ELEMENT_TYPE
diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc
index 0e53258..2f80413 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -9,10 +9,14 @@
  * # Copied from https://docs.microsoft.com/en-us/typography/script-development/use
  * # On October 23, 2018; with documentd dated 02/07/2018.
  *
- * # Scripts-11.0.0.txt
- * # Date: 2018-02-21, 05:34:31 GMT
+ * # Scripts-12.0.0.txt
+ * # Date: 2019-01-28, 22:16:47 GMT
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-vowel-constraints.hh"
 
 static void
@@ -34,6 +38,12 @@
 				       hb_buffer_t              *buffer,
 				       hb_font_t                *font HB_UNUSED)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+  return;
+#endif
+  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)
+    return;
+
   /* UGLY UGLY UGLY business of adding dotted-circle in the middle of
    * vowel-sequences that look like another vowel.  Data for each script
    * collected from the USE script development spec.
@@ -434,4 +444,6 @@
   }
 }
 
+
+#endif
 /* == End of generated functions == */
diff --git a/src/hb-ot-shape-complex.hh b/src/hb-ot-shape-complex.hh
index a2499de..2691622 100644
--- a/src/hb-ot-shape-complex.hh
+++ b/src/hb-ot-shape-complex.hh
@@ -377,6 +377,9 @@
     case HB_SCRIPT_MAKASAR:
     //case HB_SCRIPT_SOGDIAN:
 
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_NANDINAGARI:
+
       /* If the designer designed the font for the 'DFLT' script,
        * (or we ended up arbitrarily pick 'latn'), use the default shaper.
        * Otherwise, use the specific shaper.
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index d3afdff..024bcfe 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-fallback.hh"
 #include "hb-kern.hh"
 
@@ -41,30 +45,30 @@
     {
       switch (u)
       {
-        case 0x0E31u:
-        case 0x0E34u:
-        case 0x0E35u:
-        case 0x0E36u:
-        case 0x0E37u:
-        case 0x0E47u:
-        case 0x0E4Cu:
-        case 0x0E4Du:
-        case 0x0E4Eu:
+	case 0x0E31u:
+	case 0x0E34u:
+	case 0x0E35u:
+	case 0x0E36u:
+	case 0x0E37u:
+	case 0x0E47u:
+	case 0x0E4Cu:
+	case 0x0E4Du:
+	case 0x0E4Eu:
 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
 	  break;
 
-        case 0x0EB1u:
-        case 0x0EB4u:
-        case 0x0EB5u:
-        case 0x0EB6u:
-        case 0x0EB7u:
-        case 0x0EBBu:
-        case 0x0ECCu:
-        case 0x0ECDu:
+	case 0x0EB1u:
+	case 0x0EB4u:
+	case 0x0EB5u:
+	case 0x0EB6u:
+	case 0x0EB7u:
+	case 0x0EBBu:
+	case 0x0ECCu:
+	case 0x0ECDu:
 	  klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
 	  break;
 
-        case 0x0EBCu:
+	case 0x0EBCu:
 	  klass = HB_UNICODE_COMBINING_CLASS_BELOW;
 	  break;
       }
@@ -163,9 +167,13 @@
 
 void
 _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
-						        hb_font_t *font HB_UNUSED,
-						        hb_buffer_t  *buffer)
+							hb_font_t *font HB_UNUSED,
+							hb_buffer_t  *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
@@ -180,12 +188,18 @@
 static void
 zero_mark_advances (hb_buffer_t *buffer,
 		    unsigned int start,
-		    unsigned int end)
+		    unsigned int end,
+		    bool adjust_offsets_when_zeroing)
 {
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
+      if (adjust_offsets_when_zeroing)
+      {
+	buffer->pos[i].x_offset -= buffer->pos[i].x_advance;
+	buffer->pos[i].y_offset -= buffer->pos[i].y_advance;
+      }
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
@@ -218,10 +232,10 @@
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
       if (buffer->props.direction == HB_DIRECTION_LTR) {
 	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
-        break;
+	break;
       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
 	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
-        break;
+	break;
       }
       HB_FALLTHROUGH;
 
@@ -303,7 +317,8 @@
 		      hb_font_t *font,
 		      hb_buffer_t  *buffer,
 		      unsigned int base,
-		      unsigned int end)
+		      unsigned int end,
+		      bool adjust_offsets_when_zeroing)
 {
   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
 
@@ -314,11 +329,15 @@
 				&base_extents))
   {
     /* If extents don't work, zero marks and go home. */
-    zero_mark_advances (buffer, base + 1, end);
+    zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing);
     return;
   }
-  base_extents.x_bearing += buffer->pos[base].x_offset;
   base_extents.y_bearing += buffer->pos[base].y_offset;
+  /* Use horizontal advance for horizontal positioning.
+   * Generally a better idea.  Also works for zero-ink glyphs.  See:
+   * https://github.com/harfbuzz/harfbuzz/issues/1532 */
+  base_extents.x_bearing = 0;
+  base_extents.width = font->get_glyph_h_advance (buffer->info[base].codepoint);
 
   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
   /* Use integer for num_lig_components such that it doesn't convert to unsigned
@@ -368,7 +387,7 @@
       if (last_combining_class != this_combining_class)
       {
 	last_combining_class = this_combining_class;
-        cluster_extents = component_extents;
+	cluster_extents = component_extents;
       }
 
       position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
@@ -394,7 +413,8 @@
 		  hb_font_t *font,
 		  hb_buffer_t  *buffer,
 		  unsigned int start,
-		  unsigned int end)
+		  unsigned int end,
+		  bool adjust_offsets_when_zeroing)
 {
   if (end - start < 2)
     return;
@@ -410,7 +430,7 @@
 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
 	  break;
 
-      position_around_base (plan, font, buffer, i, j);
+      position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
 
       i = j - 1;
     }
@@ -419,8 +439,13 @@
 void
 _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 				     hb_font_t *font,
-				     hb_buffer_t  *buffer)
+				     hb_buffer_t  *buffer,
+				     bool adjust_offsets_when_zeroing)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   unsigned int start = 0;
@@ -428,13 +453,14 @@
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
-      position_cluster (plan, font, buffer, start, i);
+      position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
-  position_cluster (plan, font, buffer, start, count);
+  position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing);
 }
 
 
+#ifndef HB_DISABLE_DEPRECATED
 struct hb_ot_shape_fallback_kern_driver_t
 {
   hb_ot_shape_fallback_kern_driver_t (hb_font_t   *font_,
@@ -453,6 +479,7 @@
   hb_font_t *font;
   hb_direction_t direction;
 };
+#endif
 
 /* Performs font-assisted kerning. */
 void
@@ -460,6 +487,11 @@
 			    hb_font_t *font,
 			    hb_buffer_t *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
+#ifndef HB_DISABLE_DEPRECATED
   if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
       !font->has_glyph_h_kerning_func () :
       !font->has_glyph_v_kerning_func ())
@@ -476,6 +508,7 @@
 
   if (reverse)
     buffer->reverse ();
+#endif
 }
 
 
@@ -558,3 +591,6 @@
       }
     }
 }
+
+
+#endif
diff --git a/src/hb-ot-shape-fallback.hh b/src/hb-ot-shape-fallback.hh
index 12f18ed..5faf5f2 100644
--- a/src/hb-ot-shape-fallback.hh
+++ b/src/hb-ot-shape-fallback.hh
@@ -34,7 +34,8 @@
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 						      hb_font_t *font,
-						      hb_buffer_t  *buffer);
+						      hb_buffer_t  *buffer,
+						      bool adjust_offsets_when_zeroing);
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
 									 hb_font_t *font,
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 82bb24b..553d532 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-normalize.hh"
 #include "hb-ot-shape-complex.hh"
 #include "hb-ot-shape.hh"
@@ -229,7 +233,7 @@
       }
       else
       {
-        /* Just pass on the two characters separately, let GSUB do its magic. */
+	/* Just pass on the two characters separately, let GSUB do its magic. */
 	set_glyph (buffer->cur(), font);
 	buffer->next_glyph ();
 	set_glyph (buffer->cur(), font);
@@ -339,7 +343,7 @@
       /* From idx to end are simple clusters. */
       if (might_short_circuit)
       {
-        unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
+	unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
 						      &buffer->cur().codepoint,
 						      sizeof (buffer->info[0]),
 						      &buffer->cur().glyph_index(),
@@ -469,3 +473,6 @@
     buffer->swap_buffers ();
   }
 }
+
+
+#endif
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6e5ce15..5d9a70c 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -26,6 +26,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#ifdef HB_NO_OT_LAYOUT
+#error "Cannot compile 'ot' shaper with HB_NO_OT_LAYOUT."
+#endif
+
 #include "hb-shaper-impl.hh"
 
 #include "hb-ot-shape.hh"
@@ -55,7 +63,8 @@
 			      const hb_feature_t             *user_features,
 			      unsigned int                    num_user_features);
 
-static bool
+#ifndef HB_NO_AAT_SHAPE
+static inline bool
 _hb_apply_morx (hb_face_t *face)
 {
   if (hb_options ().aat &&
@@ -69,14 +78,17 @@
 					       0, nullptr, nullptr)) &&
 	 hb_aat_layout_has_substitution (face);
 }
+#endif
 
 hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *face,
 					      const hb_segment_properties_t *props) :
 						face (face),
 						props (*props),
 						map (face, props),
-						aat_map (face, props),
-						apply_morx (_hb_apply_morx (face))
+						aat_map (face, props)
+#ifndef HB_NO_AAT_SHAPE
+						, apply_morx (_hb_apply_morx (face))
+#endif
 {
   shaper = hb_ot_shape_complex_categorize (this);
 
@@ -94,21 +106,30 @@
   plan.props = props;
   plan.shaper = shaper;
   map.compile (plan.map, key);
+#ifndef HB_NO_AAT_SHAPE
   if (apply_morx)
     aat_map.compile (plan.aat_map);
+#endif
 
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
   plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
   plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
   plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+#endif
+
   plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
   hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ?
 		      HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
+#ifndef HB_NO_OT_KERN
   plan.kern_mask = plan.map.get_mask (kern_tag);
-  plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
-
   plan.requested_kerning = !!plan.kern_mask;
+#endif
+#ifndef HB_NO_AAT_SHAPE
+  plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
   plan.requested_tracking = !!plan.trak_mask;
+#endif
+
   bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
   bool disable_gpos = plan.shaper->gpos_tag &&
 		      plan.shaper->gpos_tag != plan.map.chosen_script[1];
@@ -124,42 +145,65 @@
    * Decide who does substitutions. GSUB, morx, or fallback.
    */
 
+#ifndef HB_NO_AAT_SHAPE
   plan.apply_morx = apply_morx;
+#endif
 
   /*
    * Decide who does positioning. GPOS, kerx, kern, or fallback.
    */
 
-  if (hb_options ().aat && hb_aat_layout_has_positioning (face))
+  if (0)
+    ;
+#ifndef HB_NO_AAT_SHAPE
+  else if (hb_options ().aat && hb_aat_layout_has_positioning (face))
     plan.apply_kerx = true;
+#endif
   else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
     plan.apply_gpos = true;
+#ifndef HB_NO_AAT_SHAPE
   else if (hb_aat_layout_has_positioning (face))
     plan.apply_kerx = true;
+#endif
 
   if (!plan.apply_kerx && !has_gpos_kern)
   {
     /* Apparently Apple applies kerx if GPOS kern was not applied. */
+#ifndef HB_NO_AAT_SHAPE
     if (hb_aat_layout_has_positioning (face))
       plan.apply_kerx = true;
-    else if (hb_ot_layout_has_kerning (face))
+    else
+#endif
+#ifndef HB_NO_OT_KERN
+    if (hb_ot_layout_has_kerning (face))
       plan.apply_kern = true;
+#endif
   }
 
   plan.zero_marks = script_zero_marks &&
 		    !plan.apply_kerx &&
-		    (!plan.apply_kern || !hb_ot_layout_has_machine_kerning (face));
+		    (!plan.apply_kern
+#ifndef HB_NO_OT_KERN
+		     || !hb_ot_layout_has_machine_kerning (face)
+#endif
+		    );
   plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
 
   plan.adjust_mark_positioning_when_zeroing = !plan.apply_gpos &&
 					      !plan.apply_kerx &&
-					      (!plan.apply_kern || !hb_ot_layout_has_cross_kerning (face));
+					      (!plan.apply_kern
+#ifndef HB_NO_OT_KERN
+					       || !hb_ot_layout_has_cross_kerning (face)
+#endif
+					      );
 
   plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing &&
 				   script_fallback_mark_positioning;
 
+#ifndef HB_NO_AAT_SHAPE
   /* Currently we always apply trak. */
   plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
+#endif
 }
 
 bool
@@ -167,7 +211,9 @@
 			   const hb_shape_plan_key_t     *key)
 {
   map.init ();
+#ifndef HB_NO_AAT_SHAPE
   aat_map.init ();
+#endif
 
   hb_ot_shape_planner_t planner (face,
 				 &key->props);
@@ -195,16 +241,20 @@
     shaper->data_destroy (const_cast<void *> (data));
 
   map.fini ();
+#ifndef HB_NO_AAT_SHAPE
   aat_map.fini ();
+#endif
 }
 
 void
 hb_ot_shape_plan_t::substitute (hb_font_t   *font,
 				hb_buffer_t *buffer) const
 {
+#ifndef HB_NO_AAT_SHAPE
   if (unlikely (apply_morx))
     hb_aat_layout_substitute (this, font, buffer);
   else
+#endif
     map.substitute (this, font, buffer);
 }
 
@@ -214,21 +264,29 @@
 {
   if (this->apply_gpos)
     map.position (this, font, buffer);
+#ifndef HB_NO_AAT_SHAPE
   else if (this->apply_kerx)
     hb_aat_layout_position (this, font, buffer);
+#endif
+#ifndef HB_NO_OT_KERN
   else if (this->apply_kern)
     hb_ot_layout_kern (this, font, buffer);
+#endif
   else
     _hb_ot_shape_fallback_kern (this, font, buffer);
 
+#ifndef HB_NO_AAT_SHAPE
   if (this->apply_trak)
     hb_aat_layout_track (this, font, buffer);
+#endif
 }
 
 
 static const hb_ot_map_feature_t
 common_features[] =
 {
+  {HB_TAG('a','b','v','m'), F_GLOBAL},
+  {HB_TAG('b','l','w','m'), F_GLOBAL},
   {HB_TAG('c','c','m','p'), F_GLOBAL},
   {HB_TAG('l','o','c','l'), F_GLOBAL},
   {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS},
@@ -243,6 +301,7 @@
   {HB_TAG('c','a','l','t'), F_GLOBAL},
   {HB_TAG('c','l','i','g'), F_GLOBAL},
   {HB_TAG('c','u','r','s'), F_GLOBAL},
+  {HB_TAG('d','i','s','t'), F_GLOBAL},
   {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK},
   {HB_TAG('l','i','g','a'), F_GLOBAL},
   {HB_TAG('r','c','l','t'), F_GLOBAL},
@@ -274,18 +333,22 @@
       break;
   }
 
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   /* Automatic fractions. */
   map->add_feature (HB_TAG ('f','r','a','c'));
   map->add_feature (HB_TAG ('n','u','m','r'));
   map->add_feature (HB_TAG ('d','n','o','m'));
+#endif
 
   /* Random! */
   map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
 
+#ifndef HB_NO_AAT_SHAPE
   /* Tracking.  We enable dummy feature here just to allow disabling
    * AAT 'trak' table using features.
    * https://github.com/harfbuzz/harfbuzz/issues/1303 */
   map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
+#endif
 
   map->enable_feature (HB_TAG ('H','A','R','F'));
 
@@ -318,6 +381,7 @@
 		      feature->value);
   }
 
+#ifndef HB_NO_AAT_SHAPE
   if (planner->apply_morx)
   {
     hb_aat_map_builder_t *aat_map = &planner->aat_map;
@@ -327,6 +391,7 @@
       aat_map->add_feature (feature->tag, feature->value);
     }
   }
+#endif
 
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
@@ -417,23 +482,42 @@
     {
 	_hb_glyph_info_set_continuation (&info[i]);
     }
+#ifndef HB_NO_EMOJI_SEQUENCES
     else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
     {
       _hb_glyph_info_set_continuation (&info[i]);
       if (i + 1 < count &&
 	  _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
       {
-        i++;
+	i++;
 	_hb_glyph_info_set_unicode_props (&info[i], buffer);
 	_hb_glyph_info_set_continuation (&info[i]);
       }
     }
+#endif
+    /* Or part of the Other_Grapheme_Extend that is not marks.
+     * As of Unicode 11 that is just:
+     *
+     * 200C          ; Other_Grapheme_Extend # Cf       ZERO WIDTH NON-JOINER
+     * FF9E..FF9F    ; Other_Grapheme_Extend # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+     * E0020..E007F  ; Other_Grapheme_Extend # Cf  [96] TAG SPACE..CANCEL TAG
+     *
+     * ZWNJ is special, we don't want to merge it as there's no need, and keeping
+     * it separate results in more granular clusters.  Ignore Katakana for now.
+     * Tags are used for Emoji sub-region flag sequences:
+     * https://github.com/harfbuzz/harfbuzz/issues/1556
+     */
+    else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+      _hb_glyph_info_set_continuation (&info[i]);
   }
 }
 
 static void
 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
 {
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
   if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
       buffer->context_len[0] ||
       !_hb_glyph_info_is_unicode_mark (&buffer->info[0]))
@@ -534,6 +618,10 @@
 static inline void
 hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
 {
+#ifdef HB_NO_OT_SHAPE_FRACTIONS
+  return;
+#endif
+
   if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
       !c->plan->has_frac)
     return;
@@ -562,19 +650,19 @@
       while (start &&
 	     _hb_glyph_info_get_general_category (&info[start - 1]) ==
 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
-        start--;
+	start--;
       while (end < count &&
 	     _hb_glyph_info_get_general_category (&info[end]) ==
 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
-        end++;
+	end++;
 
       buffer->unsafe_to_break (start, end);
 
       for (unsigned int j = start; j < i; j++)
-        info[j].mask |= pre_mask;
+	info[j].mask |= pre_mask;
       info[i].mask |= c->plan->frac_mask;
       for (unsigned int j = i + 1; j < end; j++)
-        info[j].mask |= post_mask;
+	info[j].mask |= post_mask;
 
       i = end - 1;
     }
@@ -744,8 +832,10 @@
 hb_ot_substitute_post (const hb_ot_shape_context_t *c)
 {
   hb_ot_hide_default_ignorables (c->buffer, c->font);
+#ifndef HB_NO_AAT_SHAPE
   if (c->plan->apply_morx)
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
 
   if (c->plan->shaper->postprocess_glyphs)
     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
@@ -779,7 +869,7 @@
     if (_hb_glyph_info_is_mark (&info[i]))
     {
       if (adjust_offsets)
-        adjust_mark_offsets (&buffer->pos[i]);
+	adjust_mark_offsets (&buffer->pos[i]);
       zero_mark_width (&buffer->pos[i]);
     }
 }
@@ -795,7 +885,7 @@
   if (HB_DIRECTION_IS_HORIZONTAL (direction))
   {
     c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]),
-                                   &pos[0].x_advance, sizeof(pos[0]));
+				   &pos[0].x_advance, sizeof(pos[0]));
     /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
     if (c->font->has_glyph_h_origin_func ())
       for (unsigned int i = 0; i < count; i++)
@@ -806,7 +896,7 @@
   else
   {
     c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]),
-                                   &pos[0].y_advance, sizeof(pos[0]));
+				   &pos[0].y_advance, sizeof(pos[0]));
     for (unsigned int i = 0; i < count; i++)
     {
       c->font->subtract_glyph_v_origin (info[i].codepoint,
@@ -879,8 +969,10 @@
   /* Finish off.  Has to follow a certain order. */
   hb_ot_layout_position_finish_advances (c->font, c->buffer);
   hb_ot_zero_width_default_ignorables (c->buffer);
+#ifndef HB_NO_AAT_SHAPE
   if (c->plan->apply_morx)
     hb_aat_layout_zero_width_deleted_glyphs (c->buffer);
+#endif
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
 
   /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
@@ -891,7 +983,8 @@
 					&pos[i].y_offset);
 
   if (c->plan->fallback_mark_positioning)
-    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer);
+    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer,
+					 adjust_offsets_when_zeroing);
 }
 
 static inline void
@@ -944,12 +1037,12 @@
   c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
   {
-    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
+    c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
 			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
   {
-    c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
+    c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
 			      (unsigned) HB_BUFFER_MAX_OPS_MIN);
   }
 
@@ -1066,3 +1159,6 @@
 
   hb_shape_plan_destroy (shape_plan);
 }
+
+
+#endif
diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh
index 73a11e1..2cde73d 100644
--- a/src/hb-ot-shape.hh
+++ b/src/hb-ot-shape.hh
@@ -65,14 +65,40 @@
   hb_ot_map_t map;
   hb_aat_map_t aat_map;
   const void *data;
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   hb_mask_t frac_mask, numr_mask, dnom_mask;
+#else
+  static constexpr hb_mask_t frac_mask = 0;
+  static constexpr hb_mask_t numr_mask = 0;
+  static constexpr hb_mask_t dnom_mask = 0;
+#endif
   hb_mask_t rtlm_mask;
+#ifndef HB_NO_OT_KERN
   hb_mask_t kern_mask;
+#else
+  static constexpr hb_mask_t kern_mask = 0;
+#endif
+#ifndef HB_NO_AAT_SHAPE
   hb_mask_t trak_mask;
+#else
+  static constexpr hb_mask_t trak_mask = 0;
+#endif
 
+#ifndef HB_NO_OT_KERN
   bool requested_kerning : 1;
+#else
+  static constexpr bool requested_kerning = false;
+#endif
+#ifndef HB_NO_AAT_SHAPE
   bool requested_tracking : 1;
+#else
+  static constexpr bool requested_tracking = false;
+#endif
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   bool has_frac : 1;
+#else
+  static constexpr bool has_frac = false;
+#endif
   bool has_gpos_mark : 1;
   bool zero_marks : 1;
   bool fallback_glyph_classes : 1;
@@ -80,10 +106,20 @@
   bool adjust_mark_positioning_when_zeroing : 1;
 
   bool apply_gpos : 1;
-  bool apply_kerx : 1;
+#ifndef HB_NO_OT_KERN
   bool apply_kern : 1;
+#else
+  static constexpr bool apply_kern = false;
+#endif
+#ifndef HB_NO_AAT_SHAPE
+  bool apply_kerx : 1;
   bool apply_morx : 1;
   bool apply_trak : 1;
+#else
+  static constexpr bool apply_kerx = false;
+  static constexpr bool apply_morx = false;
+  static constexpr bool apply_trak = false;
+#endif
 
   void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
   {
@@ -113,7 +149,11 @@
   hb_segment_properties_t props;
   hb_ot_map_builder_t map;
   hb_aat_map_builder_t aat_map;
+#ifndef HB_NO_AAT_SHAPE
   bool apply_morx : 1;
+#else
+  static constexpr bool apply_morx = false;
+#endif
   bool script_zero_marks : 1;
   bool script_fallback_mark_positioning : 1;
   const struct hb_ot_complex_shaper_t *shaper;
diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index ffab28c..2cdd3a4 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -59,6 +59,8 @@
 
 struct AxisValueFormat1
 {
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -75,13 +77,15 @@
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  Fixed		value;		/* A numeric value for this attribute value. */
+  HBFixed		value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct AxisValueFormat2
 {
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -98,10 +102,10 @@
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  Fixed		nominalValue;	/* A numeric value for this attribute value. */
-  Fixed		rangeMinValue;	/* The minimum value for a range associated
+  HBFixed		nominalValue;	/* A numeric value for this attribute value. */
+  HBFixed		rangeMinValue;	/* The minimum value for a range associated
 				 * with the specified name ID. */
-  Fixed		rangeMaxValue;	/* The maximum value for a range associated
+  HBFixed		rangeMaxValue;	/* The maximum value for a range associated
 				 * with the specified name ID. */
   public:
   DEFINE_SIZE_STATIC (20);
@@ -109,6 +113,8 @@
 
 struct AxisValueFormat3
 {
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -125,8 +131,8 @@
   NameID	valueNameID;	/* The name ID for entries in the 'name' table
 				 * that provide a display string for this
 				 * attribute value. */
-  Fixed		value;		/* A numeric value for this attribute value. */
-  Fixed		linkedValue;	/* The numeric value for a style-linked mapping
+  HBFixed		value;		/* A numeric value for this attribute value. */
+  HBFixed		linkedValue;	/* The numeric value for a style-linked mapping
 				 * from this value. */
   public:
   DEFINE_SIZE_STATIC (16);
@@ -144,13 +150,15 @@
   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
 				 * identifying the axis to which this value
 				 * applies. Must be less than designAxisCount. */
-  Fixed		value;		/* A numeric value for this attribute value. */
+  HBFixed		value;		/* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AxisValueFormat4
 {
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -175,19 +183,31 @@
 
 struct AxisValue
 {
+  hb_ot_name_id_t get_value_name_id () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value_name_id ();
+    case 2: return u.format2.get_value_name_id ();
+    case 3: return u.format3.get_value_name_id ();
+    case 4: return u.format4.get_value_name_id ();
+    default:return HB_OT_NAME_ID_INVALID;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (c->check_struct (this)))
+    if (unlikely (!c->check_struct (this)))
       return_trace (false);
 
     switch (u.format)
     {
-    case 1:  return_trace (likely (u.format1.sanitize (c)));
-    case 2:  return_trace (likely (u.format2.sanitize (c)));
-    case 3:  return_trace (likely (u.format3.sanitize (c)));
-    case 4:  return_trace (likely (u.format4.sanitize (c)));
-    default: return_trace (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -206,6 +226,8 @@
 
 struct StatAxisRecord
 {
+  hb_ot_name_id_t get_name_id () const { return nameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -225,23 +247,65 @@
 
 struct STAT
 {
-  enum { tableTag = HB_OT_TAG_STAT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
+
+  bool has_data () const { return version.to_int (); }
+
+  unsigned get_design_axis_count () const { return designAxisCount; }
+
+  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
+  {
+    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
+    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
+    return axis_record.get_name_id ();
+  }
+
+  unsigned get_axis_value_count () const { return axisValueCount; }
+
+  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
+  {
+    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
+    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
+    return axis_value.get_value_name_id ();
+  }
+
+  void collect_name_ids (hb_set_t *nameids_to_retain) const
+  {
+    if (!has_data ()) return;
+
+    + get_design_axes ()
+    | hb_map (&StatAxisRecord::get_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+
+    + get_axis_value_offsets ()
+    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+    | hb_map (&AxisValue::get_value_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+  }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-			  majorVersion == 1 &&
-			  minorVersion > 0 &&
+			  version.major == 1 &&
+			  version.minor > 0 &&
 			  designAxesOffset.sanitize (c, this, designAxisCount) &&
 			  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
   }
 
   protected:
-  HBUINT16	majorVersion;	/* Major version number of the style attributes
-				 * table — set to 1. */
-  HBUINT16	minorVersion;	/* Minor version number of the style attributes
-				 * table — set to 2. */
+  hb_array_t<const StatAxisRecord> const get_design_axes () const
+  { return (this+designAxesOffset).as_array (designAxisCount); }
+
+  hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
+  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
+
+
+  protected:
+  FixedVersion<>version;	/* Version of the stat table
+				 * initially set to 0x00010002u */
   HBUINT16	designAxisSize;	/* The size in bytes of each axis record. */
   HBUINT16	designAxisCount;/* The number of design axis records. In a
 				 * font with an 'fvar' table, this value must be
@@ -249,7 +313,7 @@
 				 * in the 'fvar' table. In all fonts, must
 				 * be greater than zero if axisValueCount
 				 * is greater than zero. */
-  LOffsetTo<UnsizedArrayOf<StatAxisRecord>, false>
+  LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
 		designAxesOffset;
 				/* Offset in bytes from the beginning of
 				 * the STAT table to the start of the design
@@ -257,7 +321,7 @@
 				 * set to zero; if designAxisCount is greater
 				 * than zero, must be greater than zero. */
   HBUINT16	axisValueCount;	/* The number of axis value tables. */
-  LOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue> >, false>
+  LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
 		offsetToAxisValueOffsets;
 				/* Offset in bytes from the beginning of
 				 * the STAT table to the start of the design
diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh
index b7090a0..d8fcd2f 100644
--- a/src/hb-ot-tag-table.hh
+++ b/src/hb-ot-tag-table.hh
@@ -6,1055 +6,1053 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2018-09-07 07:45 PM" />
- * File-Date: 2018-08-08
+ * <meta name="updated_at" content="2018-11-18 05:25 AM" />
+ * File-Date: 2019-04-03
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
 #define HB_OT_TAG_TABLE_HH
 
 static const LangTag ot_languages[] = {
-  {"aa",	{HB_TAG('A','F','R',' ')}},	/* Afar */
-  {"aae",	{HB_TAG('S','Q','I',' ')}},	/* Arbëreshë Albanian -> Albanian */
-  {"aao",	{HB_TAG('A','R','A',' ')}},	/* Algerian Saharan Arabic -> Arabic */
-  {"aat",	{HB_TAG('S','Q','I',' ')}},	/* Arvanitika Albanian -> Albanian */
-  {"ab",	{HB_TAG('A','B','K',' ')}},	/* Abkhazian */
-  {"abh",	{HB_TAG('A','R','A',' ')}},	/* Tajiki Arabic -> Arabic */
-  {"abq",	{HB_TAG('A','B','A',' ')}},	/* Abaza */
-  {"abv",	{HB_TAG('A','R','A',' ')}},	/* Baharna Arabic -> Arabic */
-  {"acf",	{HB_TAG('F','A','N',' ')}},	/* Saint Lucian Creole French -> French Antillean */
-  {"ach",	{HB_TAG('A','C','H',' ')}},	/* Acoli -> Acholi */
-  {"acm",	{HB_TAG('A','R','A',' ')}},	/* Mesopotamian Arabic -> Arabic */
-  {"acq",	{HB_TAG('A','R','A',' ')}},	/* Ta'izzi-Adeni Arabic -> Arabic */
-  {"acr",	{HB_TAG('A','C','R',' ')}},	/* Achi */
-  {"acw",	{HB_TAG('A','R','A',' ')}},	/* Hijazi Arabic -> Arabic */
-  {"acx",	{HB_TAG('A','R','A',' ')}},	/* Omani Arabic -> Arabic */
-  {"acy",	{HB_TAG('A','R','A',' ')}},	/* Cypriot Arabic -> Arabic */
-  {"ada",	{HB_TAG('D','N','G',' ')}},	/* Adangme -> Dangme */
-  {"adf",	{HB_TAG('A','R','A',' ')}},	/* Dhofari Arabic -> Arabic */
-  {"adp",	{HB_TAG('D','Z','N',' ')}},	/* Adap (retired code) -> Dzongkha */
-  {"ady",	{HB_TAG('A','D','Y',' ')}},	/* Adyghe */
-  {"aeb",	{HB_TAG('A','R','A',' ')}},	/* Tunisian Arabic -> Arabic */
-  {"aec",	{HB_TAG('A','R','A',' ')}},	/* Saidi Arabic -> Arabic */
-  {"af",	{HB_TAG('A','F','K',' ')}},	/* Afrikaans */
-  {"afb",	{HB_TAG('A','R','A',' ')}},	/* Gulf Arabic -> Arabic */
-  {"ahg",	{HB_TAG('A','G','W',' ')}},	/* Qimant -> Agaw */
-  {"aht",	{HB_TAG('A','T','H',' ')}},	/* Ahtena -> Athapaskan */
-  {"aii",	{HB_TAG('S','W','A',' '),	/* Assyrian Neo-Aramaic -> Swadaya Aramaic */
-		 HB_TAG('S','Y','R',' ')}},	/* Assyrian Neo-Aramaic -> Syriac */
-  {"aio",	{HB_TAG('A','I','O',' ')}},	/* Aiton */
-  {"aiw",	{HB_TAG('A','R','I',' ')}},	/* Aari */
-  {"ajp",	{HB_TAG('A','R','A',' ')}},	/* South Levantine Arabic -> Arabic */
-  {"ak",	{HB_TAG('A','K','A',' '),	/* Akan [macrolanguage] */
-		 HB_TAG('T','W','I',' ')}},	/* Akan [macrolanguage] -> Twi */
-  {"aln",	{HB_TAG('S','Q','I',' ')}},	/* Gheg Albanian -> Albanian */
-  {"als",	{HB_TAG('S','Q','I',' ')}},	/* Tosk Albanian -> Albanian */
-  {"alt",	{HB_TAG('A','L','T',' ')}},	/* Southern Altai -> Altai */
-  {"am",	{HB_TAG('A','M','H',' ')}},	/* Amharic */
-  {"amf",	{HB_TAG('H','B','N',' ')}},	/* Hamer-Banna -> Hammer-Banna */
-  {"amw",	{HB_TAG('S','Y','R',' ')}},	/* Western Neo-Aramaic -> Syriac */
-  {"an",	{HB_TAG('A','R','G',' ')}},	/* Aragonese */
-  {"ang",	{HB_TAG('A','N','G',' ')}},	/* Old English (ca. 450-1100) -> Anglo-Saxon */
-  {"apc",	{HB_TAG('A','R','A',' ')}},	/* North Levantine Arabic -> Arabic */
-  {"apd",	{HB_TAG('A','R','A',' ')}},	/* Sudanese Arabic -> Arabic */
-  {"apj",	{HB_TAG('A','T','H',' ')}},	/* Jicarilla Apache -> Athapaskan */
-  {"apk",	{HB_TAG('A','T','H',' ')}},	/* Kiowa Apache -> Athapaskan */
-  {"apl",	{HB_TAG('A','T','H',' ')}},	/* Lipan Apache -> Athapaskan */
-  {"apm",	{HB_TAG('A','T','H',' ')}},	/* Mescalero-Chiricahua Apache -> Athapaskan */
-  {"apw",	{HB_TAG('A','T','H',' ')}},	/* Western Apache -> Athapaskan */
-  {"ar",	{HB_TAG('A','R','A',' ')}},	/* Arabic [macrolanguage] */
-  {"arb",	{HB_TAG('A','R','A',' ')}},	/* Standard Arabic -> Arabic */
-  {"arn",	{HB_TAG('M','A','P',' ')}},	/* Mapudungun */
-  {"arq",	{HB_TAG('A','R','A',' ')}},	/* Algerian Arabic -> Arabic */
-  {"ars",	{HB_TAG('A','R','A',' ')}},	/* Najdi Arabic -> Arabic */
-  {"ary",	{HB_TAG('M','O','R',' ')}},	/* Moroccan Arabic -> Moroccan */
-  {"arz",	{HB_TAG('A','R','A',' ')}},	/* Egyptian Arabic -> Arabic */
-  {"as",	{HB_TAG('A','S','M',' ')}},	/* Assamese */
-  {"ast",	{HB_TAG('A','S','T',' ')}},	/* Asturian */
-  {"ath",	{HB_TAG('A','T','H',' ')}},	/* Athapascan [family] -> Athapaskan */
-  {"atj",	{HB_TAG('R','C','R',' ')}},	/* Atikamekw -> R-Cree */
-  {"atv",	{HB_TAG('A','L','T',' ')}},	/* Northern Altai -> Altai */
-  {"auz",	{HB_TAG('A','R','A',' ')}},	/* Uzbeki Arabic -> Arabic */
-  {"av",	{HB_TAG('A','V','R',' ')}},	/* Avaric -> Avar */
-  {"avl",	{HB_TAG('A','R','A',' ')}},	/* Eastern Egyptian Bedawi Arabic -> Arabic */
-  {"awa",	{HB_TAG('A','W','A',' ')}},	/* Awadhi */
-  {"ay",	{HB_TAG('A','Y','M',' ')}},	/* Aymara [macrolanguage] */
-  {"ayc",	{HB_TAG('A','Y','M',' ')}},	/* Southern Aymara -> Aymara */
-  {"ayh",	{HB_TAG('A','R','A',' ')}},	/* Hadrami Arabic -> Arabic */
-  {"ayl",	{HB_TAG('A','R','A',' ')}},	/* Libyan Arabic -> Arabic */
-  {"ayn",	{HB_TAG('A','R','A',' ')}},	/* Sanaani Arabic -> Arabic */
-  {"ayp",	{HB_TAG('A','R','A',' ')}},	/* North Mesopotamian Arabic -> Arabic */
-  {"ayr",	{HB_TAG('A','Y','M',' ')}},	/* Central Aymara -> Aymara */
-  {"az",	{HB_TAG('A','Z','E',' ')}},	/* Azerbaijani [macrolanguage] */
-  {"azb",	{HB_TAG('A','Z','B',' ')}},	/* South Azerbaijani -> Torki */
-  {"azj",	{HB_TAG('A','Z','E',' ')}},	/* North Azerbaijani -> Azerbaijani */
-  {"ba",	{HB_TAG('B','S','H',' ')}},	/* Bashkir */
-  {"bad",	{HB_TAG('B','A','D','0')}},	/* Banda [family] */
-  {"bai",	{HB_TAG('B','M','L',' ')}},	/* Bamileke [family] */
-  {"bal",	{HB_TAG('B','L','I',' ')}},	/* Baluchi [macrolanguage] */
-  {"ban",	{HB_TAG('B','A','N',' ')}},	/* Balinese */
-  {"bar",	{HB_TAG('B','A','R',' ')}},	/* Bavarian */
-  {"bbc",	{HB_TAG('B','B','C',' ')}},	/* Batak Toba */
-  {"bbz",	{HB_TAG('A','R','A',' ')}},	/* Babalia Creole Arabic -> Arabic */
-  {"bcc",	{HB_TAG('B','L','I',' ')}},	/* Southern Balochi -> Baluchi */
-  {"bci",	{HB_TAG('B','A','U',' ')}},	/* Baoulé -> Baulé */
-  {"bcl",	{HB_TAG('B','I','K',' ')}},	/* Central Bikol -> Bikol */
-  {"bcq",	{HB_TAG('B','C','H',' ')}},	/* Bench */
-  {"bcr",	{HB_TAG('A','T','H',' ')}},	/* Babine -> Athapaskan */
-  {"bdy",	{HB_TAG('B','D','Y',' ')}},	/* Bandjalang */
-  {"be",	{HB_TAG('B','E','L',' ')}},	/* Belarusian -> Belarussian */
-  {"bea",	{HB_TAG('A','T','H',' ')}},	/* Beaver -> Athapaskan */
-  {"beb",	{HB_TAG('B','T','I',' ')}},	/* Bebele -> Beti */
-  {"bem",	{HB_TAG('B','E','M',' ')}},	/* Bemba (Zambia) */
-  {"ber",	{HB_TAG('B','B','R',' ')}},	/* Berber [family] */
-  {"bfq",	{HB_TAG('B','A','D',' ')}},	/* Badaga */
-  {"bft",	{HB_TAG('B','L','T',' ')}},	/* Balti */
-  {"bfu",	{HB_TAG('L','A','H',' ')}},	/* Gahri -> Lahuli */
-  {"bfy",	{HB_TAG('B','A','G',' ')}},	/* Bagheli -> Baghelkhandi */
-  {"bg",	{HB_TAG('B','G','R',' ')}},	/* Bulgarian */
-  {"bgc",	{HB_TAG('B','G','C',' ')}},	/* Haryanvi */
-  {"bgn",	{HB_TAG('B','L','I',' ')}},	/* Western Balochi -> Baluchi */
-  {"bgp",	{HB_TAG('B','L','I',' ')}},	/* Eastern Balochi -> Baluchi */
-  {"bgq",	{HB_TAG('B','G','Q',' ')}},	/* Bagri */
-  {"bgr",	{HB_TAG('Q','I','N',' ')}},	/* Bawm Chin -> Chin */
-  {"bhb",	{HB_TAG('B','H','I',' ')}},	/* Bhili */
-  {"bhi",	{HB_TAG('B','H','I',' ')}},	/* Bhilali -> Bhili */
-  {"bhk",	{HB_TAG('B','I','K',' ')}},	/* Albay Bicolano (retired code) -> Bikol */
-  {"bho",	{HB_TAG('B','H','O',' ')}},	/* Bhojpuri */
-  {"bhr",	{HB_TAG('M','L','G',' ')}},	/* Bara Malagasy -> Malagasy */
-  {"bi",	{HB_TAG('B','I','S',' ')}},	/* Bislama */
-  {"bik",	{HB_TAG('B','I','K',' ')}},	/* Bikol [macrolanguage] */
-  {"bin",	{HB_TAG('E','D','O',' ')}},	/* Edo */
-  {"bjj",	{HB_TAG('B','J','J',' ')}},	/* Kanauji */
-  {"bjn",	{HB_TAG('M','L','Y',' ')}},	/* Banjar -> Malay */
-  {"bjq",	{HB_TAG('M','L','G',' ')}},	/* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
-  {"bjt",	{HB_TAG('B','L','N',' ')}},	/* Balanta-Ganja -> Balante */
-  {"bla",	{HB_TAG('B','K','F',' ')}},	/* Siksika -> Blackfoot */
-  {"ble",	{HB_TAG('B','L','N',' ')}},	/* Balanta-Kentohe -> Balante */
-  {"blk",	{HB_TAG('B','L','K',' ')}},	/* Pa'o Karen */
-  {"bln",	{HB_TAG('B','I','K',' ')}},	/* Southern Catanduanes Bikol -> Bikol */
-  {"bm",	{HB_TAG('B','M','B',' ')}},	/* Bambara (Bamanankan) */
-  {"bmm",	{HB_TAG('M','L','G',' ')}},	/* Northern Betsimisaraka Malagasy -> Malagasy */
-  {"bn",	{HB_TAG('B','E','N',' ')}},	/* Bengali */
-  {"bo",	{HB_TAG('T','I','B',' ')}},	/* Tibetan */
-  {"bpy",	{HB_TAG('B','P','Y',' ')}},	/* Bishnupriya -> Bishnupriya Manipuri */
-  {"bqi",	{HB_TAG('L','R','C',' ')}},	/* Bakhtiari -> Luri */
-  {"br",	{HB_TAG('B','R','E',' ')}},	/* Breton */
-  {"bra",	{HB_TAG('B','R','I',' ')}},	/* Braj -> Braj Bhasha */
-  {"brh",	{HB_TAG('B','R','H',' ')}},	/* Brahui */
-  {"brx",	{HB_TAG('B','R','X',' ')}},	/* Bodo (India) */
-  {"bs",	{HB_TAG('B','O','S',' ')}},	/* Bosnian */
-  {"bsk",	{HB_TAG('B','S','K',' ')}},	/* Burushaski */
-  {"btb",	{HB_TAG('B','T','I',' ')}},	/* Beti (Cameroon) (retired code) */
-  {"btj",	{HB_TAG('M','L','Y',' ')}},	/* Bacanese Malay -> Malay */
-  {"bto",	{HB_TAG('B','I','K',' ')}},	/* Rinconada Bikol -> Bikol */
-  {"bts",	{HB_TAG('B','T','S',' ')}},	/* Batak Simalungun */
-  {"bug",	{HB_TAG('B','U','G',' ')}},	/* Buginese -> Bugis */
-  {"bum",	{HB_TAG('B','T','I',' ')}},	/* Bulu (Cameroon) -> Beti */
-  {"bve",	{HB_TAG('M','L','Y',' ')}},	/* Berau Malay -> Malay */
-  {"bvu",	{HB_TAG('M','L','Y',' ')}},	/* Bukit Malay -> Malay */
-  {"bxk",	{HB_TAG('L','U','H',' ')}},	/* Bukusu -> Luyia */
-  {"bxp",	{HB_TAG('B','T','I',' ')}},	/* Bebil -> Beti */
-  {"bxr",	{HB_TAG('R','B','U',' ')}},	/* Russia Buriat -> Russian Buriat */
-  {"byn",	{HB_TAG('B','I','L',' ')}},	/* Bilin -> Bilen */
-  {"byv",	{HB_TAG('B','Y','V',' ')}},	/* Medumba */
-  {"bzc",	{HB_TAG('M','L','G',' ')}},	/* Southern Betsimisaraka Malagasy -> Malagasy */
-  {"ca",	{HB_TAG('C','A','T',' ')}},	/* Catalan */
-  {"caf",	{HB_TAG('C','R','R',' '),	/* Southern Carrier -> Carrier */
-		 HB_TAG('A','T','H',' ')}},	/* Southern Carrier -> Athapaskan */
-  {"cak",	{HB_TAG('C','A','K',' ')}},	/* Kaqchikel */
-  {"cbk",	{HB_TAG('C','B','K',' ')}},	/* Chavacano -> Zamboanga Chavacano */
-  {"cbl",	{HB_TAG('Q','I','N',' ')}},	/* Bualkhaw Chin -> Chin */
-  {"cco",	{HB_TAG('C','C','H','N')}},	/* Comaltepec Chinantec -> Chinantec */
-  {"ccq",	{HB_TAG('A','R','K',' ')}},	/* Chaungtha (retired code) -> Rakhine */
-  {"cdo",	{HB_TAG('Z','H','S',' ')}},	/* Min Dong Chinese -> Chinese Simplified */
-  {"ce",	{HB_TAG('C','H','E',' ')}},	/* Chechen */
-  {"ceb",	{HB_TAG('C','E','B',' ')}},	/* Cebuano */
-  {"cfm",	{HB_TAG('H','A','L',' ')}},	/* Halam (Falam Chin) */
-  {"cgg",	{HB_TAG('C','G','G',' ')}},	/* Chiga */
-  {"ch",	{HB_TAG('C','H','A',' ')}},	/* Chamorro */
-  {"chj",	{HB_TAG('C','C','H','N')}},	/* Ojitlán Chinantec -> Chinantec */
-  {"chk",	{HB_TAG('C','H','K','0')}},	/* Chuukese */
-  {"cho",	{HB_TAG('C','H','O',' ')}},	/* Choctaw */
-  {"chp",	{HB_TAG('C','H','P',' '),	/* Chipewyan */
-		 HB_TAG('S','A','Y',' '),	/* Chipewyan -> Sayisi */
-		 HB_TAG('A','T','H',' ')}},	/* Chipewyan -> Athapaskan */
-  {"chq",	{HB_TAG('C','C','H','N')}},	/* Quiotepec Chinantec -> Chinantec */
-  {"chr",	{HB_TAG('C','H','R',' ')}},	/* Cherokee */
-  {"chy",	{HB_TAG('C','H','Y',' ')}},	/* Cheyenne */
-  {"chz",	{HB_TAG('C','C','H','N')}},	/* Ozumacín Chinantec -> Chinantec */
-  {"ciw",	{HB_TAG('O','J','B',' ')}},	/* Chippewa -> Ojibway */
-  {"cja",	{HB_TAG('C','J','A',' ')}},	/* Western Cham */
-  {"cjm",	{HB_TAG('C','J','M',' ')}},	/* Eastern Cham */
-  {"cjy",	{HB_TAG('Z','H','S',' ')}},	/* Jinyu Chinese -> Chinese Simplified */
-  {"cka",	{HB_TAG('Q','I','N',' ')}},	/* Khumi Awa Chin (retired code) -> Chin */
-  {"ckb",	{HB_TAG('K','U','R',' ')}},	/* Central Kurdish -> Kurdish */
-  {"ckt",	{HB_TAG('C','H','K',' ')}},	/* Chukot -> Chukchi */
-  {"clc",	{HB_TAG('A','T','H',' ')}},	/* Chilcotin -> Athapaskan */
-  {"cld",	{HB_TAG('S','Y','R',' ')}},	/* Chaldean Neo-Aramaic -> Syriac */
-  {"cle",	{HB_TAG('C','C','H','N')}},	/* Lealao Chinantec -> Chinantec */
-  {"cmn",	{HB_TAG('Z','H','S',' ')}},	/* Mandarin Chinese -> Chinese Simplified */
-  {"cmr",	{HB_TAG('Q','I','N',' ')}},	/* Mro-Khimi Chin -> Chin */
-  {"cnb",	{HB_TAG('Q','I','N',' ')}},	/* Chinbon Chin -> Chin */
-  {"cnh",	{HB_TAG('Q','I','N',' ')}},	/* Hakha Chin -> Chin */
-  {"cnk",	{HB_TAG('Q','I','N',' ')}},	/* Khumi Chin -> Chin */
-  {"cnl",	{HB_TAG('C','C','H','N')}},	/* Lalana Chinantec -> Chinantec */
-  {"cnt",	{HB_TAG('C','C','H','N')}},	/* Tepetotutla Chinantec -> Chinantec */
-  {"cnw",	{HB_TAG('Q','I','N',' ')}},	/* Ngawn Chin -> Chin */
-  {"co",	{HB_TAG('C','O','S',' ')}},	/* Corsican */
-  {"coa",	{HB_TAG('M','L','Y',' ')}},	/* Cocos Islands Malay -> Malay */
-  {"cop",	{HB_TAG('C','O','P',' ')}},	/* Coptic */
-  {"coq",	{HB_TAG('A','T','H',' ')}},	/* Coquille -> Athapaskan */
-  {"cpa",	{HB_TAG('C','C','H','N')}},	/* Palantla Chinantec -> Chinantec */
-  {"cpe",	{HB_TAG('C','P','P',' ')}},	/* English-based creoles and pidgins [family] -> Creoles */
-  {"cpf",	{HB_TAG('C','P','P',' ')}},	/* French-based creoles and pidgins [family] -> Creoles */
-  {"cpp",	{HB_TAG('C','P','P',' ')}},	/* Portuguese-based creoles and pidgins [family] -> Creoles */
-  {"cpx",	{HB_TAG('Z','H','S',' ')}},	/* Pu-Xian Chinese -> Chinese Simplified */
-  {"cqd",	{HB_TAG('H','M','N',' ')}},	/* Chuanqiandian Cluster Miao -> Hmong */
-  {"cqu",	{HB_TAG('Q','U','H',' ')}},	/* Chilean Quechua (retired code) -> Quechua (Bolivia) */
-  {"cr",	{HB_TAG('C','R','E',' '),	/* Cree [macrolanguage] */
-		 HB_TAG('Y','C','R',' ')}},	/* Cree [macrolanguage] -> Y-Cree */
-  {"crh",	{HB_TAG('C','R','T',' ')}},	/* Crimean Tatar */
-  {"crj",	{HB_TAG('E','C','R',' ')}},	/* Southern East Cree -> Eastern Cree */
-  {"crk",	{HB_TAG('W','C','R',' ')}},	/* Plains Cree -> West-Cree */
-  {"crl",	{HB_TAG('E','C','R',' ')}},	/* Northern East Cree -> Eastern Cree */
-  {"crm",	{HB_TAG('M','C','R',' '),	/* Moose Cree */
-		 HB_TAG('L','C','R',' ')}},	/* Moose Cree -> L-Cree */
-  {"crp",	{HB_TAG('C','P','P',' ')}},	/* Creoles and pidgins [family] -> Creoles */
-  {"crx",	{HB_TAG('C','R','R',' '),	/* Carrier */
-		 HB_TAG('A','T','H',' ')}},	/* Carrier -> Athapaskan */
-  {"cs",	{HB_TAG('C','S','Y',' ')}},	/* Czech */
-  {"csa",	{HB_TAG('C','C','H','N')}},	/* Chiltepec Chinantec -> Chinantec */
-  {"csb",	{HB_TAG('C','S','B',' ')}},	/* Kashubian */
-  {"csh",	{HB_TAG('Q','I','N',' ')}},	/* Asho Chin -> Chin */
-  {"cso",	{HB_TAG('C','C','H','N')}},	/* Sochiapam Chinantec -> Chinantec */
-  {"csw",	{HB_TAG('N','C','R',' '),	/* Swampy Cree -> N-Cree */
-		 HB_TAG('N','H','C',' ')}},	/* Swampy Cree -> Norway House Cree */
-  {"csy",	{HB_TAG('Q','I','N',' ')}},	/* Siyin Chin -> Chin */
-  {"ctc",	{HB_TAG('A','T','H',' ')}},	/* Chetco -> Athapaskan */
-  {"ctd",	{HB_TAG('Q','I','N',' ')}},	/* Tedim Chin -> Chin */
-  {"cte",	{HB_TAG('C','C','H','N')}},	/* Tepinapa Chinantec -> Chinantec */
-  {"ctg",	{HB_TAG('C','T','G',' ')}},	/* Chittagonian */
-  {"ctl",	{HB_TAG('C','C','H','N')}},	/* Tlacoatzintepec Chinantec -> Chinantec */
-  {"cts",	{HB_TAG('B','I','K',' ')}},	/* Northern Catanduanes Bikol -> Bikol */
-  {"cu",	{HB_TAG('C','S','L',' ')}},	/* Church Slavonic */
-  {"cuc",	{HB_TAG('C','C','H','N')}},	/* Usila Chinantec -> Chinantec */
-  {"cuk",	{HB_TAG('C','U','K',' ')}},	/* San Blas Kuna */
-  {"cv",	{HB_TAG('C','H','U',' ')}},	/* Chuvash */
-  {"cvn",	{HB_TAG('C','C','H','N')}},	/* Valle Nacional Chinantec -> Chinantec */
-  {"cwd",	{HB_TAG('D','C','R',' '),	/* Woods Cree */
-		 HB_TAG('T','C','R',' ')}},	/* Woods Cree -> TH-Cree */
-  {"cy",	{HB_TAG('W','E','L',' ')}},	/* Welsh */
-  {"czh",	{HB_TAG('Z','H','S',' ')}},	/* Huizhou Chinese -> Chinese Simplified */
-  {"czo",	{HB_TAG('Z','H','S',' ')}},	/* Min Zhong Chinese -> Chinese Simplified */
-  {"czt",	{HB_TAG('Q','I','N',' ')}},	/* Zotung Chin -> Chin */
-  {"da",	{HB_TAG('D','A','N',' ')}},	/* Danish */
-  {"dao",	{HB_TAG('Q','I','N',' ')}},	/* Daai Chin -> Chin */
-  {"dap",	{HB_TAG('N','I','S',' ')}},	/* Nisi (India) (retired code) */
-  {"dar",	{HB_TAG('D','A','R',' ')}},	/* Dargwa */
-  {"dax",	{HB_TAG('D','A','X',' ')}},	/* Dayi */
-  {"de",	{HB_TAG('D','E','U',' ')}},	/* German */
-  {"den",	{HB_TAG('S','L','A',' '),	/* Slave (Athapascan) [macrolanguage] -> Slavey */
-		 HB_TAG('A','T','H',' ')}},	/* Slave (Athapascan) [macrolanguage] -> Athapaskan */
-  {"dgo",	{HB_TAG('D','G','O',' ')}},	/* Dogri */
-  {"dgr",	{HB_TAG('A','T','H',' ')}},	/* Dogrib -> Athapaskan */
-  {"dhd",	{HB_TAG('M','A','W',' ')}},	/* Dhundari -> Marwari */
-  {"dhg",	{HB_TAG('D','H','G',' ')}},	/* Dhangu */
-  {"dib",	{HB_TAG('D','N','K',' ')}},	/* South Central Dinka -> Dinka */
-  {"dik",	{HB_TAG('D','N','K',' ')}},	/* Southwestern Dinka -> Dinka */
-  {"din",	{HB_TAG('D','N','K',' ')}},	/* Dinka [macrolanguage] */
-  {"dip",	{HB_TAG('D','N','K',' ')}},	/* Northeastern Dinka -> Dinka */
-  {"diq",	{HB_TAG('D','I','Q',' ')}},	/* Dimli */
-  {"diw",	{HB_TAG('D','N','K',' ')}},	/* Northwestern Dinka -> Dinka */
-  {"dje",	{HB_TAG('D','J','R',' ')}},	/* Zarma */
-  {"djr",	{HB_TAG('D','J','R','0')}},	/* Djambarrpuyngu */
-  {"dks",	{HB_TAG('D','N','K',' ')}},	/* Southeastern Dinka -> Dinka */
-  {"dng",	{HB_TAG('D','U','N',' ')}},	/* Dungan */
-  {"dnj",	{HB_TAG('D','N','J',' ')}},	/* Dan */
-  {"doi",	{HB_TAG('D','G','R',' ')}},	/* Dogri [macrolanguage] */
-  {"drh",	{HB_TAG('M','N','G',' ')}},	/* Darkhat (retired code) -> Mongolian */
-  {"drw",	{HB_TAG('D','R','I',' ')}},	/* Darwazi (retired code) -> Dari */
-  {"dsb",	{HB_TAG('L','S','B',' ')}},	/* Lower Sorbian */
-  {"dty",	{HB_TAG('N','E','P',' ')}},	/* Dotyali -> Nepali */
-  {"duj",	{HB_TAG('D','U','J',' ')}},	/* Dhuwal (retired code) */
-  {"dup",	{HB_TAG('M','L','Y',' ')}},	/* Duano -> Malay */
-  {"dv",	{HB_TAG('D','I','V',' '),	/* Divehi (Dhivehi, Maldivian) */
-		 HB_TAG('D','H','V',' ')}},	/* Divehi (Dhivehi, Maldivian) (deprecated) */
-  {"dwu",	{HB_TAG('D','U','J',' ')}},	/* Dhuwal */
-  {"dwy",	{HB_TAG('D','U','J',' ')}},	/* Dhuwaya -> Dhuwal */
-  {"dyu",	{HB_TAG('J','U','L',' ')}},	/* Dyula -> Jula */
-  {"dz",	{HB_TAG('D','Z','N',' ')}},	/* Dzongkha */
-  {"ee",	{HB_TAG('E','W','E',' ')}},	/* Ewe */
-  {"efi",	{HB_TAG('E','F','I',' ')}},	/* Efik */
-  {"ekk",	{HB_TAG('E','T','I',' ')}},	/* Standard Estonian -> Estonian */
-  {"el",	{HB_TAG('E','L','L',' ')}},	/* Modern Greek (1453-) -> Greek */
-  {"emk",	{HB_TAG('E','M','K',' '),	/* Eastern Maninkakan */
-		 HB_TAG('M','N','K',' ')}},	/* Eastern Maninkakan -> Maninka */
-  {"en",	{HB_TAG('E','N','G',' ')}},	/* English */
-  {"enb",	{HB_TAG('K','A','L',' ')}},	/* Markweeta -> Kalenjin */
-  {"enf",	{HB_TAG('F','N','E',' ')}},	/* Forest Enets -> Forest Nenets */
-  {"enh",	{HB_TAG('T','N','E',' ')}},	/* Tundra Enets -> Tundra Nenets */
-  {"eo",	{HB_TAG('N','T','O',' ')}},	/* Esperanto */
-  {"es",	{HB_TAG('E','S','P',' ')}},	/* Spanish */
-  {"esg",	{HB_TAG('G','O','N',' ')}},	/* Aheri Gondi -> Gondi */
-  {"esi",	{HB_TAG('I','P','K',' ')}},	/* North Alaskan Inupiatun -> Inupiat */
-  {"esk",	{HB_TAG('I','P','K',' ')}},	/* Northwest Alaska Inupiatun -> Inupiat */
-  {"esu",	{HB_TAG('E','S','U',' ')}},	/* Central Yupik */
-  {"et",	{HB_TAG('E','T','I',' ')}},	/* Estonian [macrolanguage] */
-  {"eto",	{HB_TAG('B','T','I',' ')}},	/* Eton (Cameroon) -> Beti */
-  {"eu",	{HB_TAG('E','U','Q',' ')}},	/* Basque */
-  {"eve",	{HB_TAG('E','V','N',' ')}},	/* Even */
-  {"evn",	{HB_TAG('E','V','K',' ')}},	/* Evenki */
-  {"ewo",	{HB_TAG('B','T','I',' ')}},	/* Ewondo -> Beti */
-  {"eyo",	{HB_TAG('K','A','L',' ')}},	/* Keiyo -> Kalenjin */
-  {"fa",	{HB_TAG('F','A','R',' ')}},	/* Persian [macrolanguage] */
-  {"fan",	{HB_TAG('F','A','N','0')}},	/* Fang (Equatorial Guinea) */
-  {"fat",	{HB_TAG('F','A','T',' ')}},	/* Fanti */
-  {"fbl",	{HB_TAG('B','I','K',' ')}},	/* West Albay Bikol -> Bikol */
-  {"ff",	{HB_TAG('F','U','L',' ')}},	/* Fulah [macrolanguage] */
-  {"ffm",	{HB_TAG('F','U','L',' ')}},	/* Maasina Fulfulde -> Fulah */
-  {"fi",	{HB_TAG('F','I','N',' ')}},	/* Finnish */
-  {"fil",	{HB_TAG('P','I','L',' ')}},	/* Filipino */
-  {"fj",	{HB_TAG('F','J','I',' ')}},	/* Fijian */
-  {"flm",	{HB_TAG('H','A','L',' '),	/* Halam (Falam Chin) (retired code) */
-		 HB_TAG('Q','I','N',' ')}},	/* Falam Chin (retired code) -> Chin */
-  {"fmp",	{HB_TAG('F','M','P',' ')}},	/* Fe'fe' */
-  {"fo",	{HB_TAG('F','O','S',' ')}},	/* Faroese */
-  {"fon",	{HB_TAG('F','O','N',' ')}},	/* Fon */
-  {"fr",	{HB_TAG('F','R','A',' ')}},	/* French */
-  {"frc",	{HB_TAG('F','R','C',' ')}},	/* Cajun French */
-  {"frp",	{HB_TAG('F','R','P',' ')}},	/* Arpitan */
-  {"fub",	{HB_TAG('F','U','L',' ')}},	/* Adamawa Fulfulde -> Fulah */
-  {"fuc",	{HB_TAG('F','U','L',' ')}},	/* Pulaar -> Fulah */
-  {"fue",	{HB_TAG('F','U','L',' ')}},	/* Borgu Fulfulde -> Fulah */
-  {"fuf",	{HB_TAG('F','T','A',' ')}},	/* Pular -> Futa */
-  {"fuh",	{HB_TAG('F','U','L',' ')}},	/* Western Niger Fulfulde -> Fulah */
-  {"fui",	{HB_TAG('F','U','L',' ')}},	/* Bagirmi Fulfulde -> Fulah */
-  {"fuq",	{HB_TAG('F','U','L',' ')}},	/* Central-Eastern Niger Fulfulde -> Fulah */
-  {"fur",	{HB_TAG('F','R','L',' ')}},	/* Friulian */
-  {"fuv",	{HB_TAG('F','U','V',' ')}},	/* Nigerian Fulfulde */
-  {"fy",	{HB_TAG('F','R','I',' ')}},	/* Western Frisian -> Frisian */
-  {"ga",	{HB_TAG('I','R','I',' ')}},	/* Irish */
-  {"gaa",	{HB_TAG('G','A','D',' ')}},	/* Ga */
-  {"gag",	{HB_TAG('G','A','G',' ')}},	/* Gagauz */
-  {"gan",	{HB_TAG('Z','H','S',' ')}},	/* Gan Chinese -> Chinese Simplified */
-  {"gax",	{HB_TAG('O','R','O',' ')}},	/* Borana-Arsi-Guji Oromo -> Oromo */
-  {"gaz",	{HB_TAG('O','R','O',' ')}},	/* West Central Oromo -> Oromo */
-  {"gbm",	{HB_TAG('G','A','W',' ')}},	/* Garhwali */
-  {"gce",	{HB_TAG('A','T','H',' ')}},	/* Galice -> Athapaskan */
-  {"gd",	{HB_TAG('G','A','E',' ')}},	/* Scottish Gaelic (Gaelic) */
-  {"gda",	{HB_TAG('R','A','J',' ')}},	/* Gade Lohar -> Rajasthani */
-  {"gez",	{HB_TAG('G','E','Z',' ')}},	/* Geez */
-  {"ggo",	{HB_TAG('G','O','N',' ')}},	/* Southern Gondi (retired code) -> Gondi */
-  {"gih",	{HB_TAG('G','I','H',' ')}},	/* Githabul */
-  {"gil",	{HB_TAG('G','I','L','0')}},	/* Kiribati (Gilbertese) */
-  {"gju",	{HB_TAG('R','A','J',' ')}},	/* Gujari -> Rajasthani */
-  {"gkp",	{HB_TAG('G','K','P',' ')}},	/* Guinea Kpelle -> Kpelle (Guinea) */
-  {"gl",	{HB_TAG('G','A','L',' ')}},	/* Galician */
-  {"gld",	{HB_TAG('N','A','N',' ')}},	/* Nanai */
-  {"glk",	{HB_TAG('G','L','K',' ')}},	/* Gilaki */
-  {"gn",	{HB_TAG('G','U','A',' ')}},	/* Guarani [macrolanguage] */
-  {"gnn",	{HB_TAG('G','N','N',' ')}},	/* Gumatj */
-  {"gno",	{HB_TAG('G','O','N',' ')}},	/* Northern Gondi -> Gondi */
-  {"gnw",	{HB_TAG('G','U','A',' ')}},	/* Western Bolivian Guaraní -> Guarani */
-  {"gog",	{HB_TAG('G','O','G',' ')}},	/* Gogo */
-  {"gom",	{HB_TAG('K','O','K',' ')}},	/* Goan Konkani -> Konkani */
-  {"gon",	{HB_TAG('G','O','N',' ')}},	/* Gondi [macrolanguage] */
-  {"grt",	{HB_TAG('G','R','O',' ')}},	/* Garo */
-  {"gru",	{HB_TAG('S','O','G',' ')}},	/* Kistane -> Sodo Gurage */
-  {"gsw",	{HB_TAG('A','L','S',' ')}},	/* Alsatian */
-  {"gu",	{HB_TAG('G','U','J',' ')}},	/* Gujarati */
-  {"guc",	{HB_TAG('G','U','C',' ')}},	/* Wayuu */
-  {"guf",	{HB_TAG('G','U','F',' ')}},	/* Gupapuyngu */
-  {"gug",	{HB_TAG('G','U','A',' ')}},	/* Paraguayan Guaraní -> Guarani */
-  {"gui",	{HB_TAG('G','U','A',' ')}},	/* Eastern Bolivian Guaraní -> Guarani */
-  {"guk",	{HB_TAG('G','M','Z',' '),	/* Gumuz */
-		 HB_TAG('G','U','K',' ')}},	/* Gumuz (SIL fonts) */
-  {"gun",	{HB_TAG('G','U','A',' ')}},	/* Mbyá Guaraní -> Guarani */
-  {"guz",	{HB_TAG('G','U','Z',' ')}},	/* Gusii */
-  {"gv",	{HB_TAG('M','N','X',' ')}},	/* Manx */
-  {"gwi",	{HB_TAG('A','T','H',' ')}},	/* Gwichʼin -> Athapaskan */
-  {"ha",	{HB_TAG('H','A','U',' ')}},	/* Hausa */
-  {"haa",	{HB_TAG('A','T','H',' ')}},	/* Han -> Athapaskan */
-  {"hae",	{HB_TAG('O','R','O',' ')}},	/* Eastern Oromo -> Oromo */
-  {"hak",	{HB_TAG('Z','H','S',' ')}},	/* Hakka Chinese -> Chinese Simplified */
-  {"har",	{HB_TAG('H','R','I',' ')}},	/* Harari */
-  {"haw",	{HB_TAG('H','A','W',' ')}},	/* Hawaiian */
-  {"hay",	{HB_TAG('H','A','Y',' ')}},	/* Haya */
-  {"haz",	{HB_TAG('H','A','Z',' ')}},	/* Hazaragi */
-  {"he",	{HB_TAG('I','W','R',' ')}},	/* Hebrew */
-  {"hea",	{HB_TAG('H','M','N',' ')}},	/* Northern Qiandong Miao -> Hmong */
-  {"hi",	{HB_TAG('H','I','N',' ')}},	/* Hindi */
-  {"hil",	{HB_TAG('H','I','L',' ')}},	/* Hiligaynon */
-  {"hji",	{HB_TAG('M','L','Y',' ')}},	/* Haji -> Malay */
-  {"hlt",	{HB_TAG('Q','I','N',' ')}},	/* Matu Chin -> Chin */
-  {"hma",	{HB_TAG('H','M','N',' ')}},	/* Southern Mashan Hmong -> Hmong */
-  {"hmc",	{HB_TAG('H','M','N',' ')}},	/* Central Huishui Hmong -> Hmong */
-  {"hmd",	{HB_TAG('H','M','N',' ')}},	/* Large Flowery Miao -> Hmong */
-  {"hme",	{HB_TAG('H','M','N',' ')}},	/* Eastern Huishui Hmong -> Hmong */
-  {"hmg",	{HB_TAG('H','M','N',' ')}},	/* Southwestern Guiyang Hmong -> Hmong */
-  {"hmh",	{HB_TAG('H','M','N',' ')}},	/* Southwestern Huishui Hmong -> Hmong */
-  {"hmi",	{HB_TAG('H','M','N',' ')}},	/* Northern Huishui Hmong -> Hmong */
-  {"hmj",	{HB_TAG('H','M','N',' ')}},	/* Ge -> Hmong */
-  {"hml",	{HB_TAG('H','M','N',' ')}},	/* Luopohe Hmong -> Hmong */
-  {"hmm",	{HB_TAG('H','M','N',' ')}},	/* Central Mashan Hmong -> Hmong */
-  {"hmn",	{HB_TAG('H','M','N',' ')}},	/* Hmong [macrolanguage] */
-  {"hmp",	{HB_TAG('H','M','N',' ')}},	/* Northern Mashan Hmong -> Hmong */
-  {"hmq",	{HB_TAG('H','M','N',' ')}},	/* Eastern Qiandong Miao -> Hmong */
-  {"hms",	{HB_TAG('H','M','N',' ')}},	/* Southern Qiandong Miao -> Hmong */
-  {"hmw",	{HB_TAG('H','M','N',' ')}},	/* Western Mashan Hmong -> Hmong */
-  {"hmy",	{HB_TAG('H','M','N',' ')}},	/* Southern Guiyang Hmong -> Hmong */
-  {"hmz",	{HB_TAG('H','M','N',' ')}},	/* Hmong Shua -> Hmong */
-  {"hnd",	{HB_TAG('H','N','D',' ')}},	/* Southern Hindko -> Hindko */
-  {"hne",	{HB_TAG('C','H','H',' ')}},	/* Chhattisgarhi -> Chattisgarhi */
-  {"hnj",	{HB_TAG('H','M','N',' ')}},	/* Hmong Njua -> Hmong */
-  {"hno",	{HB_TAG('H','N','D',' ')}},	/* Northern Hindko -> Hindko */
-  {"ho",	{HB_TAG('H','M','O',' ')}},	/* Hiri Motu */
-  {"hoc",	{HB_TAG('H','O',' ',' ')}},	/* Ho */
-  {"hoi",	{HB_TAG('A','T','H',' ')}},	/* Holikachuk -> Athapaskan */
-  {"hoj",	{HB_TAG('H','A','R',' ')}},	/* Hadothi -> Harauti */
-  {"hr",	{HB_TAG('H','R','V',' ')}},	/* Croatian */
-  {"hrm",	{HB_TAG('H','M','N',' ')}},	/* Horned Miao -> Hmong */
-  {"hsb",	{HB_TAG('U','S','B',' ')}},	/* Upper Sorbian */
-  {"hsn",	{HB_TAG('Z','H','S',' ')}},	/* Xiang Chinese -> Chinese Simplified */
-  {"ht",	{HB_TAG('H','A','I',' ')}},	/* Haitian (Haitian Creole) */
-  {"hu",	{HB_TAG('H','U','N',' ')}},	/* Hungarian */
-  {"huj",	{HB_TAG('H','M','N',' ')}},	/* Northern Guiyang Hmong -> Hmong */
-  {"hup",	{HB_TAG('A','T','H',' ')}},	/* Hupa -> Athapaskan */
-  {"hy",	{HB_TAG('H','Y','E','0'),	/* Armenian -> Armenian East */
-		 HB_TAG('H','Y','E',' ')}},	/* Armenian */
-  {"hyw",	{HB_TAG('H','Y','E',' ')}},	/* Western Armenian -> Armenian */
-  {"hz",	{HB_TAG('H','E','R',' ')}},	/* Herero */
-  {"ia",	{HB_TAG('I','N','A',' ')}},	/* Interlingua (International Auxiliary Language Association) */
-  {"iba",	{HB_TAG('I','B','A',' ')}},	/* Iban */
-  {"ibb",	{HB_TAG('I','B','B',' ')}},	/* Ibibio */
-  {"id",	{HB_TAG('I','N','D',' ')}},	/* Indonesian */
-  {"ida",	{HB_TAG('L','U','H',' ')}},	/* Idakho-Isukha-Tiriki -> Luyia */
-  {"ie",	{HB_TAG('I','L','E',' ')}},	/* Interlingue */
-  {"ig",	{HB_TAG('I','B','O',' ')}},	/* Igbo */
-  {"igb",	{HB_TAG('E','B','I',' ')}},	/* Ebira */
-  {"ii",	{HB_TAG('Y','I','M',' ')}},	/* Sichuan Yi -> Yi Modern */
-  {"ijc",	{HB_TAG('I','J','O',' ')}},	/* Izon -> Ijo */
-  {"ijo",	{HB_TAG('I','J','O',' ')}},	/* Ijo [family] */
-  {"ik",	{HB_TAG('I','P','K',' ')}},	/* Inupiaq [macrolanguage] -> Inupiat */
-  {"ike",	{HB_TAG('I','N','U',' ')}},	/* Eastern Canadian Inuktitut -> Inuktitut */
-  {"ikt",	{HB_TAG('I','N','U',' ')}},	/* Inuinnaqtun -> Inuktitut */
-  {"ilo",	{HB_TAG('I','L','O',' ')}},	/* Iloko -> Ilokano */
-  {"in",	{HB_TAG('I','N','D',' ')}},	/* Indonesian (retired code) */
-  {"ing",	{HB_TAG('A','T','H',' ')}},	/* Degexit'an -> Athapaskan */
-  {"inh",	{HB_TAG('I','N','G',' ')}},	/* Ingush */
-  {"io",	{HB_TAG('I','D','O',' ')}},	/* Ido */
-  {"is",	{HB_TAG('I','S','L',' ')}},	/* Icelandic */
-  {"it",	{HB_TAG('I','T','A',' ')}},	/* Italian */
-  {"iu",	{HB_TAG('I','N','U',' ')}},	/* Inuktitut [macrolanguage] */
-  {"iw",	{HB_TAG('I','W','R',' ')}},	/* Hebrew (retired code) */
-  {"ja",	{HB_TAG('J','A','N',' ')}},	/* Japanese */
-  {"jak",	{HB_TAG('M','L','Y',' ')}},	/* Jakun -> Malay */
-  {"jam",	{HB_TAG('J','A','M',' ')}},	/* Jamaican Creole English -> Jamaican Creole */
-  {"jax",	{HB_TAG('M','L','Y',' ')}},	/* Jambi Malay -> Malay */
-  {"jbo",	{HB_TAG('J','B','O',' ')}},	/* Lojban */
-  {"jct",	{HB_TAG('J','C','T',' ')}},	/* Krymchak */
-  {"ji",	{HB_TAG('J','I','I',' ')}},	/* Yiddish (retired code) */
-  {"jv",	{HB_TAG('J','A','V',' ')}},	/* Javanese */
-  {"jw",	{HB_TAG('J','A','V',' ')}},	/* Javanese (retired code) */
-  {"ka",	{HB_TAG('K','A','T',' ')}},	/* Georgian */
-  {"kaa",	{HB_TAG('K','R','K',' ')}},	/* Kara-Kalpak -> Karakalpak */
-  {"kab",	{HB_TAG('K','A','B','0')}},	/* Kabyle */
-  {"kam",	{HB_TAG('K','M','B',' ')}},	/* Kamba (Kenya) */
-  {"kar",	{HB_TAG('K','R','N',' ')}},	/* Karen [family] */
-  {"kbd",	{HB_TAG('K','A','B',' ')}},	/* Kabardian */
-  {"kby",	{HB_TAG('K','N','R',' ')}},	/* Manga Kanuri -> Kanuri */
-  {"kca",	{HB_TAG('K','H','K',' '),	/* Khanty -> Khanty-Kazim */
-		 HB_TAG('K','H','S',' '),	/* Khanty -> Khanty-Shurishkar */
-		 HB_TAG('K','H','V',' ')}},	/* Khanty -> Khanty-Vakhi */
-  {"kde",	{HB_TAG('K','D','E',' ')}},	/* Makonde */
-  {"kdr",	{HB_TAG('K','R','M',' ')}},	/* Karaim */
-  {"kdt",	{HB_TAG('K','U','Y',' ')}},	/* Kuy */
-  {"kea",	{HB_TAG('K','E','A',' ')}},	/* Kabuverdianu (Crioulo) */
-  {"kek",	{HB_TAG('K','E','K',' ')}},	/* Kekchi */
-  {"kex",	{HB_TAG('K','K','N',' ')}},	/* Kukna -> Kokni */
-  {"kfa",	{HB_TAG('K','O','D',' ')}},	/* Kodava -> Kodagu */
-  {"kfr",	{HB_TAG('K','A','C',' ')}},	/* Kachhi -> Kachchi */
-  {"kfx",	{HB_TAG('K','U','L',' ')}},	/* Kullu Pahari -> Kulvi */
-  {"kfy",	{HB_TAG('K','M','N',' ')}},	/* Kumaoni */
-  {"kg",	{HB_TAG('K','O','N','0')}},	/* Kongo [macrolanguage] */
-  {"kha",	{HB_TAG('K','S','I',' ')}},	/* Khasi */
-  {"khb",	{HB_TAG('X','B','D',' ')}},	/* Lü */
-  {"khk",	{HB_TAG('M','N','G',' ')}},	/* Halh Mongolian -> Mongolian */
-  {"kht",	{HB_TAG('K','H','N',' '),	/* Khamti -> Khamti Shan (Microsoft fonts) */
-		 HB_TAG('K','H','T',' ')}},	/* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
-  {"khw",	{HB_TAG('K','H','W',' ')}},	/* Khowar */
-  {"ki",	{HB_TAG('K','I','K',' ')}},	/* Kikuyu (Gikuyu) */
-  {"kiu",	{HB_TAG('K','I','U',' ')}},	/* Kirmanjki */
-  {"kj",	{HB_TAG('K','U','A',' ')}},	/* Kuanyama */
-  {"kjd",	{HB_TAG('K','J','D',' ')}},	/* Southern Kiwai */
-  {"kjh",	{HB_TAG('K','H','A',' ')}},	/* Khakas -> Khakass */
-  {"kjp",	{HB_TAG('K','J','P',' ')}},	/* Pwo Eastern Karen -> Eastern Pwo Karen */
-  {"kjz",	{HB_TAG('K','J','Z',' ')}},	/* Bumthangkha */
-  {"kk",	{HB_TAG('K','A','Z',' ')}},	/* Kazakh */
-  {"kkz",	{HB_TAG('A','T','H',' ')}},	/* Kaska -> Athapaskan */
-  {"kl",	{HB_TAG('G','R','N',' ')}},	/* Greenlandic */
-  {"kln",	{HB_TAG('K','A','L',' ')}},	/* Kalenjin [macrolanguage] */
-  {"km",	{HB_TAG('K','H','M',' ')}},	/* Khmer */
-  {"kmb",	{HB_TAG('M','B','N',' ')}},	/* Kimbundu -> Mbundu */
-  {"kmr",	{HB_TAG('K','U','R',' ')}},	/* Northern Kurdish -> Kurdish */
-  {"kmw",	{HB_TAG('K','M','O',' ')}},	/* Komo (Democratic Republic of Congo) */
-  {"kmz",	{HB_TAG('K','M','Z',' ')}},	/* Khorasani Turkish -> Khorasani Turkic */
-  {"kn",	{HB_TAG('K','A','N',' ')}},	/* Kannada */
-  {"knc",	{HB_TAG('K','N','R',' ')}},	/* Central Kanuri -> Kanuri */
-  {"kng",	{HB_TAG('K','O','N','0')}},	/* Koongo -> Kongo */
-  {"knn",	{HB_TAG('K','O','K',' ')}},	/* Konkani */
-  {"ko",	{HB_TAG('K','O','R',' ')}},	/* Korean */
-  {"koi",	{HB_TAG('K','O','P',' ')}},	/* Komi-Permyak */
-  {"kok",	{HB_TAG('K','O','K',' ')}},	/* Konkani [macrolanguage] */
-  {"kos",	{HB_TAG('K','O','S',' ')}},	/* Kosraean */
-  {"koy",	{HB_TAG('A','T','H',' ')}},	/* Koyukon -> Athapaskan */
-  {"kpe",	{HB_TAG('K','P','L',' ')}},	/* Kpelle [macrolanguage] */
-  {"kpv",	{HB_TAG('K','O','Z',' ')}},	/* Komi-Zyrian */
-  {"kpy",	{HB_TAG('K','Y','K',' ')}},	/* Koryak */
-  {"kqs",	{HB_TAG('K','I','S',' ')}},	/* Northern Kissi -> Kisii */
-  {"kqy",	{HB_TAG('K','R','T',' ')}},	/* Koorete */
-  {"kr",	{HB_TAG('K','N','R',' ')}},	/* Kanuri [macrolanguage] */
-  {"krc",	{HB_TAG('K','A','R',' '),	/* Karachay-Balkar -> Karachay */
-		 HB_TAG('B','A','L',' ')}},	/* Karachay-Balkar -> Balkar */
-  {"kri",	{HB_TAG('K','R','I',' ')}},	/* Krio */
-  {"krl",	{HB_TAG('K','R','L',' ')}},	/* Karelian */
-  {"krt",	{HB_TAG('K','N','R',' ')}},	/* Tumari Kanuri -> Kanuri */
-  {"kru",	{HB_TAG('K','U','U',' ')}},	/* Kurukh */
-  {"ks",	{HB_TAG('K','S','H',' ')}},	/* Kashmiri */
-  {"ksh",	{HB_TAG('K','S','H','0')}},	/* Kölsch -> Ripuarian */
-  {"kss",	{HB_TAG('K','I','S',' ')}},	/* Southern Kisi -> Kisii */
-  {"ksw",	{HB_TAG('K','S','W',' ')}},	/* S’gaw Karen */
-  {"ktb",	{HB_TAG('K','E','B',' ')}},	/* Kambaata -> Kebena */
-  {"ktu",	{HB_TAG('K','O','N',' ')}},	/* Kituba (Democratic Republic of Congo) -> Kikongo */
-  {"ktw",	{HB_TAG('A','T','H',' ')}},	/* Kato -> Athapaskan */
-  {"ku",	{HB_TAG('K','U','R',' ')}},	/* Kurdish [macrolanguage] */
-  {"kum",	{HB_TAG('K','U','M',' ')}},	/* Kumyk */
-  {"kuu",	{HB_TAG('A','T','H',' ')}},	/* Upper Kuskokwim -> Athapaskan */
-  {"kv",	{HB_TAG('K','O','M',' ')}},	/* Komi [macrolanguage] */
-  {"kvb",	{HB_TAG('M','L','Y',' ')}},	/* Kubu -> Malay */
-  {"kvr",	{HB_TAG('M','L','Y',' ')}},	/* Kerinci -> Malay */
-  {"kw",	{HB_TAG('C','O','R',' ')}},	/* Cornish */
-  {"kwy",	{HB_TAG('K','O','N','0')}},	/* San Salvador Kongo -> Kongo */
-  {"kxc",	{HB_TAG('K','M','S',' ')}},	/* Konso -> Komso */
-  {"kxd",	{HB_TAG('M','L','Y',' ')}},	/* Brunei -> Malay */
-  {"kxu",	{HB_TAG('K','U','I',' ')}},	/* Kui (India) */
-  {"ky",	{HB_TAG('K','I','R',' ')}},	/* Kirghiz (Kyrgyz) */
-  {"kyu",	{HB_TAG('K','Y','U',' ')}},	/* Western Kayah */
-  {"la",	{HB_TAG('L','A','T',' ')}},	/* Latin */
-  {"lad",	{HB_TAG('J','U','D',' ')}},	/* Ladino */
-  {"lb",	{HB_TAG('L','T','Z',' ')}},	/* Luxembourgish */
-  {"lbe",	{HB_TAG('L','A','K',' ')}},	/* Lak */
-  {"lbj",	{HB_TAG('L','D','K',' ')}},	/* Ladakhi */
-  {"lbl",	{HB_TAG('B','I','K',' ')}},	/* Libon Bikol -> Bikol */
-  {"lce",	{HB_TAG('M','L','Y',' ')}},	/* Loncong -> Malay */
-  {"lcf",	{HB_TAG('M','L','Y',' ')}},	/* Lubu -> Malay */
-  {"ldi",	{HB_TAG('K','O','N','0')}},	/* Laari -> Kongo */
-  {"lez",	{HB_TAG('L','E','Z',' ')}},	/* Lezghian -> Lezgi */
-  {"lg",	{HB_TAG('L','U','G',' ')}},	/* Ganda */
-  {"li",	{HB_TAG('L','I','M',' ')}},	/* Limburgish */
-  {"lif",	{HB_TAG('L','M','B',' ')}},	/* Limbu */
-  {"lij",	{HB_TAG('L','I','J',' ')}},	/* Ligurian */
-  {"lis",	{HB_TAG('L','I','S',' ')}},	/* Lisu */
-  {"liw",	{HB_TAG('M','L','Y',' ')}},	/* Col -> Malay */
-  {"ljp",	{HB_TAG('L','J','P',' ')}},	/* Lampung Api -> Lampung */
-  {"lkb",	{HB_TAG('L','U','H',' ')}},	/* Kabras -> Luyia */
-  {"lki",	{HB_TAG('L','K','I',' ')}},	/* Laki */
-  {"lko",	{HB_TAG('L','U','H',' ')}},	/* Khayo -> Luyia */
-  {"lks",	{HB_TAG('L','U','H',' ')}},	/* Kisa -> Luyia */
-  {"lld",	{HB_TAG('L','A','D',' ')}},	/* Ladin */
-  {"lmn",	{HB_TAG('L','A','M',' ')}},	/* Lambadi -> Lambani */
-  {"lmo",	{HB_TAG('L','M','O',' ')}},	/* Lombard */
-  {"ln",	{HB_TAG('L','I','N',' ')}},	/* Lingala */
-  {"lo",	{HB_TAG('L','A','O',' ')}},	/* Lao */
-  {"lom",	{HB_TAG('L','O','M',' ')}},	/* Loma (Liberia) */
-  {"lrc",	{HB_TAG('L','R','C',' ')}},	/* Northern Luri -> Luri */
-  {"lri",	{HB_TAG('L','U','H',' ')}},	/* Marachi -> Luyia */
-  {"lrm",	{HB_TAG('L','U','H',' ')}},	/* Marama -> Luyia */
-  {"lsm",	{HB_TAG('L','U','H',' ')}},	/* Saamia -> Luyia */
-  {"lt",	{HB_TAG('L','T','H',' ')}},	/* Lithuanian */
-  {"ltg",	{HB_TAG('L','V','I',' ')}},	/* Latgalian -> Latvian */
-  {"lto",	{HB_TAG('L','U','H',' ')}},	/* Tsotso -> Luyia */
-  {"lts",	{HB_TAG('L','U','H',' ')}},	/* Tachoni -> Luyia */
-  {"lu",	{HB_TAG('L','U','B',' ')}},	/* Luba-Katanga */
-  {"lua",	{HB_TAG('L','U','A',' ')}},	/* Luba-Lulua */
-  {"luo",	{HB_TAG('L','U','O',' ')}},	/* Luo (Kenya and Tanzania) */
-  {"lus",	{HB_TAG('M','I','Z',' ')}},	/* Lushai -> Mizo */
-  {"luy",	{HB_TAG('L','U','H',' ')}},	/* Luyia [macrolanguage] */
-  {"luz",	{HB_TAG('L','R','C',' ')}},	/* Southern Luri -> Luri */
-  {"lv",	{HB_TAG('L','V','I',' ')}},	/* Latvian [macrolanguage] */
-  {"lvs",	{HB_TAG('L','V','I',' ')}},	/* Standard Latvian -> Latvian */
-  {"lwg",	{HB_TAG('L','U','H',' ')}},	/* Wanga -> Luyia */
-  {"lzh",	{HB_TAG('Z','H','T',' ')}},	/* Literary Chinese -> Chinese Traditional */
-  {"lzz",	{HB_TAG('L','A','Z',' ')}},	/* Laz */
-  {"mad",	{HB_TAG('M','A','D',' ')}},	/* Madurese -> Madura */
-  {"mag",	{HB_TAG('M','A','G',' ')}},	/* Magahi */
-  {"mai",	{HB_TAG('M','T','H',' ')}},	/* Maithili */
-  {"mak",	{HB_TAG('M','K','R',' ')}},	/* Makasar */
-  {"mam",	{HB_TAG('M','A','M',' ')}},	/* Mam */
-  {"man",	{HB_TAG('M','N','K',' ')}},	/* Mandingo [macrolanguage] -> Maninka */
-  {"max",	{HB_TAG('M','L','Y',' ')}},	/* North Moluccan Malay -> Malay */
-  {"mbo",	{HB_TAG('M','B','O',' ')}},	/* Mbo (Cameroon) */
-  {"mct",	{HB_TAG('B','T','I',' ')}},	/* Mengisa -> Beti */
-  {"mdf",	{HB_TAG('M','O','K',' ')}},	/* Moksha */
-  {"mdr",	{HB_TAG('M','D','R',' ')}},	/* Mandar */
-  {"mdy",	{HB_TAG('M','L','E',' ')}},	/* Male (Ethiopia) */
-  {"men",	{HB_TAG('M','D','E',' ')}},	/* Mende (Sierra Leone) */
-  {"meo",	{HB_TAG('M','L','Y',' ')}},	/* Kedah Malay -> Malay */
-  {"mer",	{HB_TAG('M','E','R',' ')}},	/* Meru */
-  {"mfa",	{HB_TAG('M','F','A',' ')}},	/* Pattani Malay */
-  {"mfb",	{HB_TAG('M','L','Y',' ')}},	/* Bangka -> Malay */
-  {"mfe",	{HB_TAG('M','F','E',' ')}},	/* Morisyen */
-  {"mg",	{HB_TAG('M','L','G',' ')}},	/* Malagasy [macrolanguage] */
-  {"mh",	{HB_TAG('M','A','H',' ')}},	/* Marshallese */
-  {"mhr",	{HB_TAG('L','M','A',' ')}},	/* Eastern Mari -> Low Mari */
-  {"mhv",	{HB_TAG('A','R','K',' ')}},	/* Arakanese (retired code) -> Rakhine */
-  {"mi",	{HB_TAG('M','R','I',' ')}},	/* Maori */
-  {"min",	{HB_TAG('M','I','N',' ')}},	/* Minangkabau */
-  {"mk",	{HB_TAG('M','K','D',' ')}},	/* Macedonian */
-  {"mku",	{HB_TAG('M','N','K',' ')}},	/* Konyanka Maninka -> Maninka */
-  {"mkw",	{HB_TAG('M','K','W',' ')}},	/* Kituba (Congo) */
-  {"ml",	{HB_TAG('M','A','L',' '),	/* Malayalam -> Malayalam Traditional */
-		 HB_TAG('M','L','R',' ')}},	/* Malayalam -> Malayalam Reformed */
-  {"mlq",	{HB_TAG('M','L','N',' '),	/* Western Maninkakan -> Malinke */
-		 HB_TAG('M','N','K',' ')}},	/* Western Maninkakan -> Maninka */
-  {"mmr",	{HB_TAG('H','M','N',' ')}},	/* Western Xiangxi Miao -> Hmong */
-  {"mn",	{HB_TAG('M','N','G',' ')}},	/* Mongolian [macrolanguage] */
-  {"mnc",	{HB_TAG('M','C','H',' ')}},	/* Manchu */
-  {"mni",	{HB_TAG('M','N','I',' ')}},	/* Manipuri */
-  {"mnk",	{HB_TAG('M','N','D',' '),	/* Mandinka */
-		 HB_TAG('M','N','K',' ')}},	/* Mandinka -> Maninka */
-  {"mnp",	{HB_TAG('Z','H','S',' ')}},	/* Min Bei Chinese -> Chinese Simplified */
-  {"mns",	{HB_TAG('M','A','N',' ')}},	/* Mansi */
-  {"mnw",	{HB_TAG('M','O','N',' ')}},	/* Mon */
-  {"mo",	{HB_TAG('M','O','L',' ')}},	/* Moldavian (retired code) */
-  {"moh",	{HB_TAG('M','O','H',' ')}},	/* Mohawk */
-  {"mos",	{HB_TAG('M','O','S',' ')}},	/* Mossi */
-  {"mpe",	{HB_TAG('M','A','J',' ')}},	/* Majang */
-  {"mqg",	{HB_TAG('M','L','Y',' ')}},	/* Kota Bangun Kutai Malay -> Malay */
-  {"mr",	{HB_TAG('M','A','R',' ')}},	/* Marathi */
-  {"mrh",	{HB_TAG('Q','I','N',' ')}},	/* Mara Chin -> Chin */
-  {"mrj",	{HB_TAG('H','M','A',' ')}},	/* Western Mari -> High Mari */
-  {"ms",	{HB_TAG('M','L','Y',' ')}},	/* Malay [macrolanguage] */
-  {"msc",	{HB_TAG('M','N','K',' ')}},	/* Sankaran Maninka -> Maninka */
-  {"msh",	{HB_TAG('M','L','G',' ')}},	/* Masikoro Malagasy -> Malagasy */
-  {"msi",	{HB_TAG('M','L','Y',' ')}},	/* Sabah Malay -> Malay */
-  {"mt",	{HB_TAG('M','T','S',' ')}},	/* Maltese */
-  {"mtr",	{HB_TAG('M','A','W',' ')}},	/* Mewari -> Marwari */
-  {"mui",	{HB_TAG('M','L','Y',' ')}},	/* Musi -> Malay */
-  {"mup",	{HB_TAG('R','A','J',' ')}},	/* Malvi -> Rajasthani */
-  {"muq",	{HB_TAG('H','M','N',' ')}},	/* Eastern Xiangxi Miao -> Hmong */
-  {"mus",	{HB_TAG('M','U','S',' ')}},	/* Creek -> Muscogee */
-  {"mvb",	{HB_TAG('A','T','H',' ')}},	/* Mattole -> Athapaskan */
-  {"mve",	{HB_TAG('M','A','W',' ')}},	/* Marwari (Pakistan) */
-  {"mvf",	{HB_TAG('M','N','G',' ')}},	/* Peripheral Mongolian -> Mongolian */
-  {"mwk",	{HB_TAG('M','N','K',' ')}},	/* Kita Maninkakan -> Maninka */
-  {"mwl",	{HB_TAG('M','W','L',' ')}},	/* Mirandese */
-  {"mwr",	{HB_TAG('M','A','W',' ')}},	/* Marwari [macrolanguage] */
-  {"mww",	{HB_TAG('M','W','W',' ')}},	/* Hmong Daw */
-  {"my",	{HB_TAG('B','R','M',' ')}},	/* Burmese */
-  {"mym",	{HB_TAG('M','E','N',' ')}},	/* Me'en */
-  {"myn",	{HB_TAG('M','Y','N',' ')}},	/* Mayan [family] */
-  {"myq",	{HB_TAG('M','N','K',' ')}},	/* Forest Maninka (retired code) -> Maninka */
-  {"myv",	{HB_TAG('E','R','Z',' ')}},	/* Erzya */
-  {"mzn",	{HB_TAG('M','Z','N',' ')}},	/* Mazanderani */
-  {"na",	{HB_TAG('N','A','U',' ')}},	/* Nauru -> Nauruan */
-  {"nag",	{HB_TAG('N','A','G',' ')}},	/* Naga Pidgin -> Naga-Assamese */
-  {"nah",	{HB_TAG('N','A','H',' ')}},	/* Nahuatl [family] */
-  {"nan",	{HB_TAG('Z','H','S',' ')}},	/* Min Nan Chinese -> Chinese Simplified */
-  {"nap",	{HB_TAG('N','A','P',' ')}},	/* Neapolitan */
-  {"nb",	{HB_TAG('N','O','R',' ')}},	/* Norwegian Bokmål -> Norwegian */
-  {"nd",	{HB_TAG('N','D','B',' ')}},	/* North Ndebele -> Ndebele */
-  {"ndc",	{HB_TAG('N','D','C',' ')}},	/* Ndau */
-  {"nds",	{HB_TAG('N','D','S',' ')}},	/* Low Saxon */
-  {"ne",	{HB_TAG('N','E','P',' ')}},	/* Nepali [macrolanguage] */
-  {"new",	{HB_TAG('N','E','W',' ')}},	/* Newari */
-  {"ng",	{HB_TAG('N','D','G',' ')}},	/* Ndonga */
-  {"nga",	{HB_TAG('N','G','A',' ')}},	/* Ngbaka */
-  {"ngl",	{HB_TAG('L','M','W',' ')}},	/* Lomwe */
-  {"ngo",	{HB_TAG('S','X','T',' ')}},	/* Ngoni -> Sutu */
-  {"nhd",	{HB_TAG('G','U','A',' ')}},	/* Chiripá -> Guarani */
-  {"niq",	{HB_TAG('K','A','L',' ')}},	/* Nandi -> Kalenjin */
-  {"niu",	{HB_TAG('N','I','U',' ')}},	/* Niuean */
-  {"niv",	{HB_TAG('G','I','L',' ')}},	/* Gilyak */
-  {"njz",	{HB_TAG('N','I','S',' ')}},	/* Nyishi -> Nisi */
-  {"nl",	{HB_TAG('N','L','D',' ')}},	/* Dutch */
-  {"nle",	{HB_TAG('L','U','H',' ')}},	/* East Nyala -> Luyia */
-  {"nn",	{HB_TAG('N','Y','N',' ')}},	/* Norwegian Nynorsk (Nynorsk, Norwegian) */
-  {"no",	{HB_TAG('N','O','R',' ')}},	/* Norwegian [macrolanguage] */
-  {"nod",	{HB_TAG('N','T','A',' ')}},	/* Northern Thai -> Northern Tai */
-  {"noe",	{HB_TAG('N','O','E',' ')}},	/* Nimadi */
-  {"nog",	{HB_TAG('N','O','G',' ')}},	/* Nogai */
-  {"nov",	{HB_TAG('N','O','V',' ')}},	/* Novial */
-  {"npi",	{HB_TAG('N','E','P',' ')}},	/* Nepali */
-  {"nqo",	{HB_TAG('N','K','O',' ')}},	/* N'Ko */
-  {"nr",	{HB_TAG('N','D','B',' ')}},	/* South Ndebele -> Ndebele */
-  {"nsk",	{HB_TAG('N','A','S',' ')}},	/* Naskapi */
-  {"nso",	{HB_TAG('N','S','O',' ')}},	/* Pedi -> Sotho, Northern */
-  {"nv",	{HB_TAG('N','A','V',' '),	/* Navajo */
-		 HB_TAG('A','T','H',' ')}},	/* Navajo -> Athapaskan */
-  {"ny",	{HB_TAG('C','H','I',' ')}},	/* Chichewa (Chewa, Nyanja) */
-  {"nyd",	{HB_TAG('L','U','H',' ')}},	/* Nyore -> Luyia */
-  {"nym",	{HB_TAG('N','Y','M',' ')}},	/* Nyamwezi */
-  {"nyn",	{HB_TAG('N','K','L',' ')}},	/* Nyankole */
-  {"nza",	{HB_TAG('N','Z','A',' ')}},	/* Tigon Mbembe -> Mbembe Tigon */
-  {"oc",	{HB_TAG('O','C','I',' ')}},	/* Occitan (post 1500) */
-  {"oj",	{HB_TAG('O','J','B',' ')}},	/* Ojibwa [macrolanguage] -> Ojibway */
-  {"ojb",	{HB_TAG('O','J','B',' ')}},	/* Northwestern Ojibwa -> Ojibway */
-  {"ojc",	{HB_TAG('O','J','B',' ')}},	/* Central Ojibwa -> Ojibway */
-  {"ojg",	{HB_TAG('O','J','B',' ')}},	/* Eastern Ojibwa -> Ojibway */
-  {"ojs",	{HB_TAG('O','C','R',' ')}},	/* Severn Ojibwa -> Oji-Cree */
-  {"ojw",	{HB_TAG('O','J','B',' ')}},	/* Western Ojibwa -> Ojibway */
-  {"oki",	{HB_TAG('K','A','L',' ')}},	/* Okiek -> Kalenjin */
-  {"okm",	{HB_TAG('K','O','H',' ')}},	/* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
-  {"om",	{HB_TAG('O','R','O',' ')}},	/* Oromo [macrolanguage] */
-  {"or",	{HB_TAG('O','R','I',' ')}},	/* Odia (formerly Oriya) [macrolanguage] */
-  {"orc",	{HB_TAG('O','R','O',' ')}},	/* Orma -> Oromo */
-  {"orn",	{HB_TAG('M','L','Y',' ')}},	/* Orang Kanaq -> Malay */
-  {"ors",	{HB_TAG('M','L','Y',' ')}},	/* Orang Seletar -> Malay */
-  {"ory",	{HB_TAG('O','R','I',' ')}},	/* Odia (formerly Oriya) */
-  {"os",	{HB_TAG('O','S','S',' ')}},	/* Ossetian */
-  {"otw",	{HB_TAG('O','J','B',' ')}},	/* Ottawa -> Ojibway */
-  {"pa",	{HB_TAG('P','A','N',' ')}},	/* Punjabi */
-  {"pag",	{HB_TAG('P','A','G',' ')}},	/* Pangasinan */
-  {"pam",	{HB_TAG('P','A','M',' ')}},	/* Pampanga -> Pampangan */
-  {"pap",	{HB_TAG('P','A','P','0')}},	/* Papiamento -> Papiamentu */
-  {"pau",	{HB_TAG('P','A','U',' ')}},	/* Palauan */
-  {"pbt",	{HB_TAG('P','A','S',' ')}},	/* Southern Pashto -> Pashto */
-  {"pbu",	{HB_TAG('P','A','S',' ')}},	/* Northern Pashto -> Pashto */
-  {"pcc",	{HB_TAG('P','C','C',' ')}},	/* Bouyei */
-  {"pcd",	{HB_TAG('P','C','D',' ')}},	/* Picard */
-  {"pce",	{HB_TAG('P','L','G',' ')}},	/* Ruching Palaung -> Palaung */
-  {"pck",	{HB_TAG('Q','I','N',' ')}},	/* Paite Chin -> Chin */
-  {"pdc",	{HB_TAG('P','D','C',' ')}},	/* Pennsylvania German */
-  {"pel",	{HB_TAG('M','L','Y',' ')}},	/* Pekal -> Malay */
-  {"pes",	{HB_TAG('F','A','R',' ')}},	/* Iranian Persian -> Persian */
-  {"pga",	{HB_TAG('A','R','A',' ')}},	/* Sudanese Creole Arabic -> Arabic */
-  {"phk",	{HB_TAG('P','H','K',' ')}},	/* Phake */
-  {"pi",	{HB_TAG('P','A','L',' ')}},	/* Pali */
-  {"pih",	{HB_TAG('P','I','H',' ')}},	/* Pitcairn-Norfolk -> Norfolk */
-  {"pko",	{HB_TAG('K','A','L',' ')}},	/* Pökoot -> Kalenjin */
-  {"pl",	{HB_TAG('P','L','K',' ')}},	/* Polish */
-  {"pll",	{HB_TAG('P','L','G',' ')}},	/* Shwe Palaung -> Palaung */
-  {"plp",	{HB_TAG('P','A','P',' ')}},	/* Palpa */
-  {"plt",	{HB_TAG('M','L','G',' ')}},	/* Plateau Malagasy -> Malagasy */
-  {"pms",	{HB_TAG('P','M','S',' ')}},	/* Piemontese */
-  {"pnb",	{HB_TAG('P','N','B',' ')}},	/* Western Panjabi */
-  {"poh",	{HB_TAG('P','O','H',' ')}},	/* Poqomchi' -> Pocomchi */
-  {"pon",	{HB_TAG('P','O','N',' ')}},	/* Pohnpeian */
-  {"ppa",	{HB_TAG('B','A','G',' ')}},	/* Pao (retired code) -> Baghelkhandi */
-  {"pro",	{HB_TAG('P','R','O',' ')}},	/* Old Provençal (to 1500) -> Provençal / Old Provençal */
-  {"prs",	{HB_TAG('D','R','I',' ')}},	/* Dari */
-  {"ps",	{HB_TAG('P','A','S',' ')}},	/* Pashto [macrolanguage] */
-  {"pse",	{HB_TAG('M','L','Y',' ')}},	/* Central Malay -> Malay */
-  {"pst",	{HB_TAG('P','A','S',' ')}},	/* Central Pashto -> Pashto */
-  {"pt",	{HB_TAG('P','T','G',' ')}},	/* Portuguese */
-  {"pwo",	{HB_TAG('P','W','O',' ')}},	/* Pwo Western Karen -> Western Pwo Karen */
-  {"qu",	{HB_TAG('Q','U','Z',' ')}},	/* Quechua [macrolanguage] */
-  {"qub",	{HB_TAG('Q','W','H',' ')}},	/* Huallaga Huánuco Quechua -> Quechua (Peru) */
-  {"quc",	{HB_TAG('Q','U','C',' ')}},	/* K’iche’ */
-  {"qud",	{HB_TAG('Q','V','I',' ')}},	/* Calderón Highland Quichua -> Quechua (Ecuador) */
-  {"quf",	{HB_TAG('Q','U','Z',' ')}},	/* Lambayeque Quechua -> Quechua */
-  {"qug",	{HB_TAG('Q','V','I',' ')}},	/* Chimborazo Highland Quichua -> Quechua (Ecuador) */
-  {"quh",	{HB_TAG('Q','U','H',' ')}},	/* South Bolivian Quechua -> Quechua (Bolivia) */
-  {"quk",	{HB_TAG('Q','U','Z',' ')}},	/* Chachapoyas Quechua -> Quechua */
-  {"qul",	{HB_TAG('Q','U','Z',' ')}},	/* North Bolivian Quechua -> Quechua */
-  {"qup",	{HB_TAG('Q','V','I',' ')}},	/* Southern Pastaza Quechua -> Quechua (Ecuador) */
-  {"qur",	{HB_TAG('Q','W','H',' ')}},	/* Yanahuanca Pasco Quechua -> Quechua (Peru) */
-  {"qus",	{HB_TAG('Q','U','H',' ')}},	/* Santiago del Estero Quichua -> Quechua (Bolivia) */
-  {"quw",	{HB_TAG('Q','V','I',' ')}},	/* Tena Lowland Quichua -> Quechua (Ecuador) */
-  {"qux",	{HB_TAG('Q','W','H',' ')}},	/* Yauyos Quechua -> Quechua (Peru) */
-  {"quy",	{HB_TAG('Q','U','Z',' ')}},	/* Ayacucho Quechua -> Quechua */
-  {"quz",	{HB_TAG('Q','U','Z',' ')}},	/* Cusco Quechua -> Quechua */
-  {"qva",	{HB_TAG('Q','W','H',' ')}},	/* Ambo-Pasco Quechua -> Quechua (Peru) */
-  {"qvc",	{HB_TAG('Q','U','Z',' ')}},	/* Cajamarca Quechua -> Quechua */
-  {"qve",	{HB_TAG('Q','U','Z',' ')}},	/* Eastern Apurímac Quechua -> Quechua */
-  {"qvh",	{HB_TAG('Q','W','H',' ')}},	/* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
-  {"qvi",	{HB_TAG('Q','V','I',' ')}},	/* Imbabura Highland Quichua -> Quechua (Ecuador) */
-  {"qvj",	{HB_TAG('Q','V','I',' ')}},	/* Loja Highland Quichua -> Quechua (Ecuador) */
-  {"qvl",	{HB_TAG('Q','W','H',' ')}},	/* Cajatambo North Lima Quechua -> Quechua (Peru) */
-  {"qvm",	{HB_TAG('Q','W','H',' ')}},	/* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
-  {"qvn",	{HB_TAG('Q','W','H',' ')}},	/* North Junín Quechua -> Quechua (Peru) */
-  {"qvo",	{HB_TAG('Q','V','I',' ')}},	/* Napo Lowland Quechua -> Quechua (Ecuador) */
-  {"qvp",	{HB_TAG('Q','W','H',' ')}},	/* Pacaraos Quechua -> Quechua (Peru) */
-  {"qvs",	{HB_TAG('Q','U','Z',' ')}},	/* San Martín Quechua -> Quechua */
-  {"qvw",	{HB_TAG('Q','W','H',' ')}},	/* Huaylla Wanca Quechua -> Quechua (Peru) */
-  {"qvz",	{HB_TAG('Q','V','I',' ')}},	/* Northern Pastaza Quichua -> Quechua (Ecuador) */
-  {"qwa",	{HB_TAG('Q','W','H',' ')}},	/* Corongo Ancash Quechua -> Quechua (Peru) */
-  {"qwc",	{HB_TAG('Q','U','Z',' ')}},	/* Classical Quechua -> Quechua */
-  {"qwh",	{HB_TAG('Q','W','H',' ')}},	/* Huaylas Ancash Quechua -> Quechua (Peru) */
-  {"qws",	{HB_TAG('Q','W','H',' ')}},	/* Sihuas Ancash Quechua -> Quechua (Peru) */
-  {"qxa",	{HB_TAG('Q','W','H',' ')}},	/* Chiquián Ancash Quechua -> Quechua (Peru) */
-  {"qxc",	{HB_TAG('Q','W','H',' ')}},	/* Chincha Quechua -> Quechua (Peru) */
-  {"qxh",	{HB_TAG('Q','W','H',' ')}},	/* Panao Huánuco Quechua -> Quechua (Peru) */
-  {"qxl",	{HB_TAG('Q','V','I',' ')}},	/* Salasaca Highland Quichua -> Quechua (Ecuador) */
-  {"qxn",	{HB_TAG('Q','W','H',' ')}},	/* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxo",	{HB_TAG('Q','W','H',' ')}},	/* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxp",	{HB_TAG('Q','U','Z',' ')}},	/* Puno Quechua -> Quechua */
-  {"qxr",	{HB_TAG('Q','V','I',' ')}},	/* Cañar Highland Quichua -> Quechua (Ecuador) */
-  {"qxt",	{HB_TAG('Q','W','H',' ')}},	/* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
-  {"qxu",	{HB_TAG('Q','U','Z',' ')}},	/* Arequipa-La Unión Quechua -> Quechua */
-  {"qxw",	{HB_TAG('Q','W','H',' ')}},	/* Jauja Wanca Quechua -> Quechua (Peru) */
-  {"rag",	{HB_TAG('L','U','H',' ')}},	/* Logooli -> Luyia */
-  {"raj",	{HB_TAG('R','A','J',' ')}},	/* Rajasthani [macrolanguage] */
-  {"rar",	{HB_TAG('R','A','R',' ')}},	/* Rarotongan */
-  {"rbb",	{HB_TAG('P','L','G',' ')}},	/* Rumai Palaung -> Palaung */
-  {"rbl",	{HB_TAG('B','I','K',' ')}},	/* Miraya Bikol -> Bikol */
-  {"rej",	{HB_TAG('R','E','J',' ')}},	/* Rejang */
-  {"ria",	{HB_TAG('R','I','A',' ')}},	/* Riang (India) */
-  {"rif",	{HB_TAG('R','I','F',' ')}},	/* Tarifit */
-  {"rit",	{HB_TAG('R','I','T',' ')}},	/* Ritarungo */
-  {"rki",	{HB_TAG('A','R','K',' ')}},	/* Rakhine */
-  {"rkw",	{HB_TAG('R','K','W',' ')}},	/* Arakwal */
-  {"rm",	{HB_TAG('R','M','S',' ')}},	/* Romansh */
-  {"rmc",	{HB_TAG('R','O','Y',' ')}},	/* Carpathian Romani -> Romany */
-  {"rmf",	{HB_TAG('R','O','Y',' ')}},	/* Kalo Finnish Romani -> Romany */
-  {"rml",	{HB_TAG('R','O','Y',' ')}},	/* Baltic Romani -> Romany */
-  {"rmn",	{HB_TAG('R','O','Y',' ')}},	/* Balkan Romani -> Romany */
-  {"rmo",	{HB_TAG('R','O','Y',' ')}},	/* Sinte Romani -> Romany */
-  {"rmw",	{HB_TAG('R','O','Y',' ')}},	/* Welsh Romani -> Romany */
-  {"rmy",	{HB_TAG('R','M','Y',' ')}},	/* Vlax Romani */
-  {"rmz",	{HB_TAG('A','R','K',' ')}},	/* Marma -> Rakhine */
-  {"rn",	{HB_TAG('R','U','N',' ')}},	/* Rundi */
-  {"rnl",	{HB_TAG('H','A','L',' ')}},	/* Ranglong -> Halam (Falam Chin) */
-  {"ro",	{HB_TAG('R','O','M',' ')}},	/* Romanian */
-  {"rom",	{HB_TAG('R','O','Y',' ')}},	/* Romany [macrolanguage] */
-  {"rtm",	{HB_TAG('R','T','M',' ')}},	/* Rotuman */
-  {"ru",	{HB_TAG('R','U','S',' ')}},	/* Russian */
-  {"rue",	{HB_TAG('R','S','Y',' ')}},	/* Rusyn */
-  {"rup",	{HB_TAG('R','U','P',' ')}},	/* Aromanian */
-  {"rw",	{HB_TAG('R','U','A',' ')}},	/* Kinyarwanda */
-  {"rwr",	{HB_TAG('M','A','W',' ')}},	/* Marwari (India) */
-  {"sa",	{HB_TAG('S','A','N',' ')}},	/* Sanskrit */
-  {"sah",	{HB_TAG('Y','A','K',' ')}},	/* Yakut -> Sakha */
-  {"sam",	{HB_TAG('P','A','A',' ')}},	/* Samaritan Aramaic -> Palestinian Aramaic */
-  {"sas",	{HB_TAG('S','A','S',' ')}},	/* Sasak */
-  {"sat",	{HB_TAG('S','A','T',' ')}},	/* Santali */
-  {"sc",	{HB_TAG('S','R','D',' ')}},	/* Sardinian [macrolanguage] */
-  {"sck",	{HB_TAG('S','A','D',' ')}},	/* Sadri */
-  {"scn",	{HB_TAG('S','C','N',' ')}},	/* Sicilian */
-  {"sco",	{HB_TAG('S','C','O',' ')}},	/* Scots */
-  {"scs",	{HB_TAG('S','C','S',' '),	/* North Slavey */
-		 HB_TAG('S','L','A',' '),	/* North Slavey -> Slavey */
-		 HB_TAG('A','T','H',' ')}},	/* North Slavey -> Athapaskan */
-  {"sd",	{HB_TAG('S','N','D',' ')}},	/* Sindhi */
-  {"sdc",	{HB_TAG('S','R','D',' ')}},	/* Sassarese Sardinian -> Sardinian */
-  {"sdh",	{HB_TAG('K','U','R',' ')}},	/* Southern Kurdish -> Kurdish */
-  {"sdn",	{HB_TAG('S','R','D',' ')}},	/* Gallurese Sardinian -> Sardinian */
-  {"se",	{HB_TAG('N','S','M',' ')}},	/* Northern Sami */
-  {"seh",	{HB_TAG('S','N','A',' ')}},	/* Sena */
-  {"sek",	{HB_TAG('A','T','H',' ')}},	/* Sekani -> Athapaskan */
-  {"sel",	{HB_TAG('S','E','L',' ')}},	/* Selkup */
-  {"sez",	{HB_TAG('Q','I','N',' ')}},	/* Senthang Chin -> Chin */
-  {"sfm",	{HB_TAG('H','M','N',' ')}},	/* Small Flowery Miao -> Hmong */
-  {"sg",	{HB_TAG('S','G','O',' ')}},	/* Sango */
-  {"sga",	{HB_TAG('S','G','A',' ')}},	/* Old Irish (to 900) */
-  {"sgc",	{HB_TAG('K','A','L',' ')}},	/* Kipsigis -> Kalenjin */
-  {"sgs",	{HB_TAG('S','G','S',' ')}},	/* Samogitian */
-  {"sgw",	{HB_TAG('C','H','G',' '),	/* Sebat Bet Gurage -> Chaha Gurage */
-		 HB_TAG('S','G','W',' ')}},	/* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
-  {"shi",	{HB_TAG('S','H','I',' ')}},	/* Tachelhit */
-  {"shn",	{HB_TAG('S','H','N',' ')}},	/* Shan */
-  {"shu",	{HB_TAG('A','R','A',' ')}},	/* Chadian Arabic -> Arabic */
-  {"si",	{HB_TAG('S','N','H',' ')}},	/* Sinhala (Sinhalese) */
-  {"sid",	{HB_TAG('S','I','D',' ')}},	/* Sidamo */
-  {"sjd",	{HB_TAG('K','S','M',' ')}},	/* Kildin Sami */
-  {"sjo",	{HB_TAG('S','I','B',' ')}},	/* Xibe -> Sibe */
-  {"sk",	{HB_TAG('S','K','Y',' ')}},	/* Slovak */
-  {"skg",	{HB_TAG('M','L','G',' ')}},	/* Sakalava Malagasy -> Malagasy */
-  {"skr",	{HB_TAG('S','R','K',' ')}},	/* Saraiki */
-  {"sl",	{HB_TAG('S','L','V',' ')}},	/* Slovenian */
-  {"sm",	{HB_TAG('S','M','O',' ')}},	/* Samoan */
-  {"sma",	{HB_TAG('S','S','M',' ')}},	/* Southern Sami */
-  {"smj",	{HB_TAG('L','S','M',' ')}},	/* Lule Sami */
-  {"smn",	{HB_TAG('I','S','M',' ')}},	/* Inari Sami */
-  {"sms",	{HB_TAG('S','K','S',' ')}},	/* Skolt Sami */
-  {"sn",	{HB_TAG('S','N','A','0')}},	/* Shona */
-  {"snk",	{HB_TAG('S','N','K',' ')}},	/* Soninke */
-  {"so",	{HB_TAG('S','M','L',' ')}},	/* Somali */
-  {"sop",	{HB_TAG('S','O','P',' ')}},	/* Songe */
-  {"spv",	{HB_TAG('O','R','I',' ')}},	/* Sambalpuri -> Odia (formerly Oriya) */
-  {"spy",	{HB_TAG('K','A','L',' ')}},	/* Sabaot -> Kalenjin */
-  {"sq",	{HB_TAG('S','Q','I',' ')}},	/* Albanian [macrolanguage] */
-  {"sr",	{HB_TAG('S','R','B',' ')}},	/* Serbian */
-  {"src",	{HB_TAG('S','R','D',' ')}},	/* Logudorese Sardinian -> Sardinian */
-  {"sro",	{HB_TAG('S','R','D',' ')}},	/* Campidanese Sardinian -> Sardinian */
-  {"srr",	{HB_TAG('S','R','R',' ')}},	/* Serer */
-  {"srs",	{HB_TAG('A','T','H',' ')}},	/* Sarsi -> Athapaskan */
-  {"ss",	{HB_TAG('S','W','Z',' ')}},	/* Swati */
-  {"ssh",	{HB_TAG('A','R','A',' ')}},	/* Shihhi Arabic -> Arabic */
-  {"st",	{HB_TAG('S','O','T',' ')}},	/* Southern Sotho -> Sotho, Southern */
-  {"stq",	{HB_TAG('S','T','Q',' ')}},	/* Saterfriesisch -> Saterland Frisian */
-  {"stv",	{HB_TAG('S','I','G',' ')}},	/* Silt'e -> Silte Gurage */
-  {"su",	{HB_TAG('S','U','N',' ')}},	/* Sundanese */
-  {"suk",	{HB_TAG('S','U','K',' ')}},	/* Sukuma */
-  {"suq",	{HB_TAG('S','U','R',' ')}},	/* Suri */
-  {"sv",	{HB_TAG('S','V','E',' ')}},	/* Swedish */
-  {"sva",	{HB_TAG('S','V','A',' ')}},	/* Svan */
-  {"sw",	{HB_TAG('S','W','K',' ')}},	/* Swahili [macrolanguage] */
-  {"swb",	{HB_TAG('C','M','R',' ')}},	/* Maore Comorian -> Comorian */
-  {"swc",	{HB_TAG('S','W','K',' ')}},	/* Congo Swahili -> Swahili */
-  {"swh",	{HB_TAG('S','W','K',' ')}},	/* Swahili */
-  {"swv",	{HB_TAG('M','A','W',' ')}},	/* Shekhawati -> Marwari */
-  {"sxu",	{HB_TAG('S','X','U',' ')}},	/* Upper Saxon */
-  {"syc",	{HB_TAG('S','Y','R',' ')}},	/* Classical Syriac -> Syriac */
-  {"syl",	{HB_TAG('S','Y','L',' ')}},	/* Sylheti */
-  {"syr",	{HB_TAG('S','Y','R',' ')}},	/* Syriac [macrolanguage] */
-  {"szl",	{HB_TAG('S','Z','L',' ')}},	/* Silesian */
-  {"ta",	{HB_TAG('T','A','M',' ')}},	/* Tamil */
-  {"taa",	{HB_TAG('A','T','H',' ')}},	/* Lower Tanana -> Athapaskan */
-  {"tab",	{HB_TAG('T','A','B',' ')}},	/* Tabassaran -> Tabasaran */
-  {"taq",	{HB_TAG('T','M','H',' ')}},	/* Tamasheq -> Tamashek */
-  {"tau",	{HB_TAG('A','T','H',' ')}},	/* Upper Tanana -> Athapaskan */
-  {"tcb",	{HB_TAG('A','T','H',' ')}},	/* Tanacross -> Athapaskan */
-  {"tce",	{HB_TAG('A','T','H',' ')}},	/* Southern Tutchone -> Athapaskan */
-  {"tcp",	{HB_TAG('Q','I','N',' ')}},	/* Tawr Chin -> Chin */
-  {"tcy",	{HB_TAG('T','U','L',' ')}},	/* Tulu -> Tumbuka */
-  {"tcz",	{HB_TAG('Q','I','N',' ')}},	/* Thado Chin -> Chin */
-  {"tdd",	{HB_TAG('T','D','D',' ')}},	/* Tai Nüa -> Dehong Dai */
-  {"tdx",	{HB_TAG('M','L','G',' ')}},	/* Tandroy-Mahafaly Malagasy -> Malagasy */
-  {"te",	{HB_TAG('T','E','L',' ')}},	/* Telugu */
-  {"tec",	{HB_TAG('K','A','L',' ')}},	/* Terik -> Kalenjin */
-  {"tem",	{HB_TAG('T','M','N',' ')}},	/* Timne -> Temne */
-  {"tet",	{HB_TAG('T','E','T',' ')}},	/* Tetum */
-  {"tfn",	{HB_TAG('A','T','H',' ')}},	/* Tanaina -> Athapaskan */
-  {"tg",	{HB_TAG('T','A','J',' ')}},	/* Tajik -> Tajiki */
-  {"tgj",	{HB_TAG('N','I','S',' ')}},	/* Tagin -> Nisi */
-  {"tgx",	{HB_TAG('A','T','H',' ')}},	/* Tagish -> Athapaskan */
-  {"th",	{HB_TAG('T','H','A',' ')}},	/* Thai */
-  {"tht",	{HB_TAG('A','T','H',' ')}},	/* Tahltan -> Athapaskan */
-  {"thv",	{HB_TAG('T','M','H',' ')}},	/* Tahaggart Tamahaq -> Tamashek */
-  {"thz",	{HB_TAG('T','M','H',' ')}},	/* Tayart Tamajeq -> Tamashek */
-  {"ti",	{HB_TAG('T','G','Y',' ')}},	/* Tigrinya */
-  {"tig",	{HB_TAG('T','G','R',' ')}},	/* Tigre */
-  {"tiv",	{HB_TAG('T','I','V',' ')}},	/* Tiv */
-  {"tk",	{HB_TAG('T','K','M',' ')}},	/* Turkmen */
-  {"tkg",	{HB_TAG('M','L','G',' ')}},	/* Tesaka Malagasy -> Malagasy */
-  {"tl",	{HB_TAG('T','G','L',' ')}},	/* Tagalog */
-  {"tmh",	{HB_TAG('T','M','H',' ')}},	/* Tamashek [macrolanguage] */
-  {"tmw",	{HB_TAG('M','L','Y',' ')}},	/* Temuan -> Malay */
-  {"tn",	{HB_TAG('T','N','A',' ')}},	/* Tswana */
-  {"tnf",	{HB_TAG('D','R','I',' ')}},	/* Tangshewi (retired code) -> Dari */
-  {"to",	{HB_TAG('T','G','N',' ')}},	/* Tonga (Tonga Islands) -> Tongan */
-  {"tod",	{HB_TAG('T','O','D','0')}},	/* Toma */
-  {"toi",	{HB_TAG('T','N','G',' ')}},	/* Tonga (Zambia) */
-  {"tol",	{HB_TAG('A','T','H',' ')}},	/* Tolowa -> Athapaskan */
-  {"tpi",	{HB_TAG('T','P','I',' ')}},	/* Tok Pisin */
-  {"tr",	{HB_TAG('T','R','K',' ')}},	/* Turkish */
-  {"tru",	{HB_TAG('T','U','A',' '),	/* Turoyo -> Turoyo Aramaic */
-		 HB_TAG('S','Y','R',' ')}},	/* Turoyo -> Syriac */
-  {"ts",	{HB_TAG('T','S','G',' ')}},	/* Tsonga */
-  {"tsj",	{HB_TAG('T','S','J',' ')}},	/* Tshangla */
-  {"tt",	{HB_TAG('T','A','T',' ')}},	/* Tatar */
-  {"ttm",	{HB_TAG('A','T','H',' ')}},	/* Northern Tutchone -> Athapaskan */
-  {"ttq",	{HB_TAG('T','M','H',' ')}},	/* Tawallammat Tamajaq -> Tamashek */
-  {"tum",	{HB_TAG('T','U','M',' ')}},	/* Tumbuka -> Tulu */
-  {"tuu",	{HB_TAG('A','T','H',' ')}},	/* Tututni -> Athapaskan */
-  {"tuy",	{HB_TAG('K','A','L',' ')}},	/* Tugen -> Kalenjin */
-  {"tvl",	{HB_TAG('T','V','L',' ')}},	/* Tuvalu */
-  {"tw",	{HB_TAG('T','W','I',' '),	/* Twi */
-		 HB_TAG('A','K','A',' ')}},	/* Twi -> Akan */
-  {"txc",	{HB_TAG('A','T','H',' ')}},	/* Tsetsaut -> Athapaskan */
-  {"txy",	{HB_TAG('M','L','G',' ')}},	/* Tanosy Malagasy -> Malagasy */
-  {"ty",	{HB_TAG('T','H','T',' ')}},	/* Tahitian */
-  {"tyv",	{HB_TAG('T','U','V',' ')}},	/* Tuvinian -> Tuvin */
-  {"tyz",	{HB_TAG('T','Y','Z',' ')}},	/* Tày */
-  {"tzm",	{HB_TAG('T','Z','M',' ')}},	/* Central Atlas Tamazight -> Tamazight */
-  {"tzo",	{HB_TAG('T','Z','O',' ')}},	/* Tzotzil */
-  {"ubl",	{HB_TAG('B','I','K',' ')}},	/* Buhi'non Bikol -> Bikol */
-  {"udm",	{HB_TAG('U','D','M',' ')}},	/* Udmurt */
-  {"ug",	{HB_TAG('U','Y','G',' ')}},	/* Uyghur */
-  {"uk",	{HB_TAG('U','K','R',' ')}},	/* Ukrainian */
-  {"umb",	{HB_TAG('U','M','B',' ')}},	/* Umbundu */
-  {"unr",	{HB_TAG('M','U','N',' ')}},	/* Mundari */
-  {"ur",	{HB_TAG('U','R','D',' ')}},	/* Urdu */
-  {"urk",	{HB_TAG('M','L','Y',' ')}},	/* Urak Lawoi' -> Malay */
-  {"uz",	{HB_TAG('U','Z','B',' ')}},	/* Uzbek [macrolanguage] */
-  {"uzn",	{HB_TAG('U','Z','B',' ')}},	/* Northern Uzbek -> Uzbek */
-  {"uzs",	{HB_TAG('U','Z','B',' ')}},	/* Southern Uzbek -> Uzbek */
-  {"ve",	{HB_TAG('V','E','N',' ')}},	/* Venda */
-  {"vec",	{HB_TAG('V','E','C',' ')}},	/* Venetian */
-  {"vi",	{HB_TAG('V','I','T',' ')}},	/* Vietnamese */
-  {"vkk",	{HB_TAG('M','L','Y',' ')}},	/* Kaur -> Malay */
-  {"vkt",	{HB_TAG('M','L','Y',' ')}},	/* Tenggarong Kutai Malay -> Malay */
-  {"vls",	{HB_TAG('F','L','E',' ')}},	/* Vlaams -> Dutch (Flemish) */
-  {"vmw",	{HB_TAG('M','A','K',' ')}},	/* Makhuwa */
-  {"vo",	{HB_TAG('V','O','L',' ')}},	/* Volapük */
-  {"vro",	{HB_TAG('V','R','O',' ')}},	/* Võro */
-  {"wa",	{HB_TAG('W','L','N',' ')}},	/* Walloon */
-  {"war",	{HB_TAG('W','A','R',' ')}},	/* Waray (Philippines) -> Waray-Waray */
-  {"wbm",	{HB_TAG('W','A',' ',' ')}},	/* Wa */
-  {"wbr",	{HB_TAG('W','A','G',' ')}},	/* Wagdi */
-  {"wlc",	{HB_TAG('C','M','R',' ')}},	/* Mwali Comorian -> Comorian */
-  {"wle",	{HB_TAG('S','I','G',' ')}},	/* Wolane -> Silte Gurage */
-  {"wlk",	{HB_TAG('A','T','H',' ')}},	/* Wailaki -> Athapaskan */
-  {"wni",	{HB_TAG('C','M','R',' ')}},	/* Ndzwani Comorian -> Comorian */
-  {"wo",	{HB_TAG('W','L','F',' ')}},	/* Wolof */
-  {"wry",	{HB_TAG('M','A','W',' ')}},	/* Merwari -> Marwari */
-  {"wsg",	{HB_TAG('G','O','N',' ')}},	/* Adilabad Gondi -> Gondi */
-  {"wtm",	{HB_TAG('W','T','M',' ')}},	/* Mewati */
-  {"wuu",	{HB_TAG('Z','H','S',' ')}},	/* Wu Chinese -> Chinese Simplified */
-  {"xal",	{HB_TAG('K','L','M',' '),	/* Kalmyk */
-		 HB_TAG('T','O','D',' ')}},	/* Kalmyk -> Todo */
-  {"xan",	{HB_TAG('S','E','K',' ')}},	/* Xamtanga -> Sekota */
-  {"xh",	{HB_TAG('X','H','S',' ')}},	/* Xhosa */
-  {"xjb",	{HB_TAG('X','J','B',' ')}},	/* Minjungbal -> Minjangbal */
-  {"xkf",	{HB_TAG('X','K','F',' ')}},	/* Khengkha */
-  {"xmm",	{HB_TAG('M','L','Y',' ')}},	/* Manado Malay -> Malay */
-  {"xmv",	{HB_TAG('M','L','G',' ')}},	/* Antankarana Malagasy -> Malagasy */
-  {"xmw",	{HB_TAG('M','L','G',' ')}},	/* Tsimihety Malagasy -> Malagasy */
-  {"xnr",	{HB_TAG('D','G','R',' ')}},	/* Kangri -> Dogri */
-  {"xog",	{HB_TAG('X','O','G',' ')}},	/* Soga */
-  {"xpe",	{HB_TAG('X','P','E',' ')}},	/* Liberia Kpelle -> Kpelle (Liberia) */
-  {"xsl",	{HB_TAG('S','S','L',' '),	/* South Slavey */
-		 HB_TAG('S','L','A',' '),	/* South Slavey -> Slavey */
-		 HB_TAG('A','T','H',' ')}},	/* South Slavey -> Athapaskan */
-  {"xst",	{HB_TAG('S','I','G',' ')}},	/* Silt'e (retired code) -> Silte Gurage */
-  {"xwo",	{HB_TAG('T','O','D',' ')}},	/* Written Oirat -> Todo */
-  {"yao",	{HB_TAG('Y','A','O',' ')}},	/* Yao */
-  {"yap",	{HB_TAG('Y','A','P',' ')}},	/* Yapese */
-  {"ybd",	{HB_TAG('A','R','K',' ')}},	/* Yangbye (retired code) -> Rakhine */
-  {"ydd",	{HB_TAG('J','I','I',' ')}},	/* Eastern Yiddish -> Yiddish */
-  {"yi",	{HB_TAG('J','I','I',' ')}},	/* Yiddish [macrolanguage] */
-  {"yih",	{HB_TAG('J','I','I',' ')}},	/* Western Yiddish -> Yiddish */
-  {"yo",	{HB_TAG('Y','B','A',' ')}},	/* Yoruba */
-  {"yos",	{HB_TAG('Q','I','N',' ')}},	/* Yos (retired code) -> Chin */
-  {"yrk",	{HB_TAG('T','N','E',' '),	/* Nenets -> Tundra Nenets */
-		 HB_TAG('F','N','E',' ')}},	/* Nenets -> Forest Nenets */
-  {"yue",	{HB_TAG('Z','H','H',' ')}},	/* Yue Chinese -> Chinese, Hong Kong SAR */
-  {"za",	{HB_TAG('Z','H','A',' ')}},	/* Zhuang [macrolanguage] */
-  {"zch",	{HB_TAG('Z','H','A',' ')}},	/* Central Hongshuihe Zhuang -> Zhuang */
-  {"zdj",	{HB_TAG('C','M','R',' ')}},	/* Ngazidja Comorian -> Comorian */
-  {"zea",	{HB_TAG('Z','E','A',' ')}},	/* Zeeuws -> Zealandic */
-  {"zeh",	{HB_TAG('Z','H','A',' ')}},	/* Eastern Hongshuihe Zhuang -> Zhuang */
-  {"zgb",	{HB_TAG('Z','H','A',' ')}},	/* Guibei Zhuang -> Zhuang */
-  {"zgh",	{HB_TAG('Z','G','H',' ')}},	/* Standard Moroccan Tamazight */
-  {"zgm",	{HB_TAG('Z','H','A',' ')}},	/* Minz Zhuang -> Zhuang */
-  {"zgn",	{HB_TAG('Z','H','A',' ')}},	/* Guibian Zhuang -> Zhuang */
-  {"zh",	{HB_TAG('Z','H','S',' ')}},	/* Chinese [macrolanguage] -> Chinese Simplified */
-  {"zhd",	{HB_TAG('Z','H','A',' ')}},	/* Dai Zhuang -> Zhuang */
-  {"zhn",	{HB_TAG('Z','H','A',' ')}},	/* Nong Zhuang -> Zhuang */
-  {"zlj",	{HB_TAG('Z','H','A',' ')}},	/* Liujiang Zhuang -> Zhuang */
-  {"zlm",	{HB_TAG('M','L','Y',' ')}},	/* Malay */
-  {"zln",	{HB_TAG('Z','H','A',' ')}},	/* Lianshan Zhuang -> Zhuang */
-  {"zlq",	{HB_TAG('Z','H','A',' ')}},	/* Liuqian Zhuang -> Zhuang */
-  {"zmi",	{HB_TAG('M','L','Y',' ')}},	/* Negeri Sembilan Malay -> Malay */
-  {"zne",	{HB_TAG('Z','N','D',' ')}},	/* Zande */
-  {"zom",	{HB_TAG('Q','I','N',' ')}},	/* Zou -> Chin */
-  {"zqe",	{HB_TAG('Z','H','A',' ')}},	/* Qiubei Zhuang -> Zhuang */
-  {"zsm",	{HB_TAG('M','L','Y',' ')}},	/* Standard Malay -> Malay */
-  {"zu",	{HB_TAG('Z','U','L',' ')}},	/* Zulu */
-  {"zum",	{HB_TAG('L','R','C',' ')}},	/* Kumzari -> Luri */
-  {"zyb",	{HB_TAG('Z','H','A',' ')}},	/* Yongbei Zhuang -> Zhuang */
-  {"zyg",	{HB_TAG('Z','H','A',' ')}},	/* Yang Zhuang -> Zhuang */
-  {"zyj",	{HB_TAG('Z','H','A',' ')}},	/* Youjiang Zhuang -> Zhuang */
-  {"zyn",	{HB_TAG('Z','H','A',' ')}},	/* Yongnan Zhuang -> Zhuang */
-  {"zza",	{HB_TAG('Z','Z','A',' ')}},	/* Zazaki [macrolanguage] */
-  {"zzj",	{HB_TAG('Z','H','A',' ')}},	/* Zuojiang Zhuang -> Zhuang */
+  {"aa",	HB_TAG('A','F','R',' ')},	/* Afar */
+  {"aae",	HB_TAG('S','Q','I',' ')},	/* Arbëreshë Albanian -> Albanian */
+  {"aao",	HB_TAG('A','R','A',' ')},	/* Algerian Saharan Arabic -> Arabic */
+  {"aat",	HB_TAG('S','Q','I',' ')},	/* Arvanitika Albanian -> Albanian */
+  {"ab",	HB_TAG('A','B','K',' ')},	/* Abkhazian */
+  {"abh",	HB_TAG('A','R','A',' ')},	/* Tajiki Arabic -> Arabic */
+  {"abq",	HB_TAG('A','B','A',' ')},	/* Abaza */
+  {"abv",	HB_TAG('A','R','A',' ')},	/* Baharna Arabic -> Arabic */
+  {"acf",	HB_TAG('F','A','N',' ')},	/* Saint Lucian Creole French -> French Antillean */
+/*{"ach",	HB_TAG('A','C','H',' ')},*/	/* Acoli -> Acholi */
+  {"acm",	HB_TAG('A','R','A',' ')},	/* Mesopotamian Arabic -> Arabic */
+  {"acq",	HB_TAG('A','R','A',' ')},	/* Ta'izzi-Adeni Arabic -> Arabic */
+/*{"acr",	HB_TAG('A','C','R',' ')},*/	/* Achi */
+  {"acw",	HB_TAG('A','R','A',' ')},	/* Hijazi Arabic -> Arabic */
+  {"acx",	HB_TAG('A','R','A',' ')},	/* Omani Arabic -> Arabic */
+  {"acy",	HB_TAG('A','R','A',' ')},	/* Cypriot Arabic -> Arabic */
+  {"ada",	HB_TAG('D','N','G',' ')},	/* Adangme -> Dangme */
+  {"adf",	HB_TAG('A','R','A',' ')},	/* Dhofari Arabic -> Arabic */
+  {"adp",	HB_TAG('D','Z','N',' ')},	/* Adap (retired code) -> Dzongkha */
+/*{"ady",	HB_TAG('A','D','Y',' ')},*/	/* Adyghe */
+  {"aeb",	HB_TAG('A','R','A',' ')},	/* Tunisian Arabic -> Arabic */
+  {"aec",	HB_TAG('A','R','A',' ')},	/* Saidi Arabic -> Arabic */
+  {"af",	HB_TAG('A','F','K',' ')},	/* Afrikaans */
+  {"afb",	HB_TAG('A','R','A',' ')},	/* Gulf Arabic -> Arabic */
+  {"ahg",	HB_TAG('A','G','W',' ')},	/* Qimant -> Agaw */
+  {"aht",	HB_TAG('A','T','H',' ')},	/* Ahtena -> Athapaskan */
+  {"aii",	HB_TAG('S','W','A',' ')},	/* Assyrian Neo-Aramaic -> Swadaya Aramaic */
+  {"aii",	HB_TAG('S','Y','R',' ')},	/* Assyrian Neo-Aramaic -> Syriac */
+/*{"aio",	HB_TAG('A','I','O',' ')},*/	/* Aiton */
+  {"aiw",	HB_TAG('A','R','I',' ')},	/* Aari */
+  {"ajp",	HB_TAG('A','R','A',' ')},	/* South Levantine Arabic -> Arabic */
+  {"ak",	HB_TAG('A','K','A',' ')},	/* Akan [macrolanguage] */
+  {"ak",	HB_TAG('T','W','I',' ')},	/* Akan [macrolanguage] -> Twi */
+  {"aln",	HB_TAG('S','Q','I',' ')},	/* Gheg Albanian -> Albanian */
+  {"als",	HB_TAG('S','Q','I',' ')},	/* Tosk Albanian -> Albanian */
+/*{"alt",	HB_TAG('A','L','T',' ')},*/	/* Southern Altai -> Altai */
+  {"am",	HB_TAG('A','M','H',' ')},	/* Amharic */
+  {"amf",	HB_TAG('H','B','N',' ')},	/* Hamer-Banna -> Hammer-Banna */
+  {"amw",	HB_TAG('S','Y','R',' ')},	/* Western Neo-Aramaic -> Syriac */
+  {"an",	HB_TAG('A','R','G',' ')},	/* Aragonese */
+/*{"ang",	HB_TAG('A','N','G',' ')},*/	/* Old English (ca. 450-1100) -> Anglo-Saxon */
+  {"apc",	HB_TAG('A','R','A',' ')},	/* North Levantine Arabic -> Arabic */
+  {"apd",	HB_TAG('A','R','A',' ')},	/* Sudanese Arabic -> Arabic */
+  {"apj",	HB_TAG('A','T','H',' ')},	/* Jicarilla Apache -> Athapaskan */
+  {"apk",	HB_TAG('A','T','H',' ')},	/* Kiowa Apache -> Athapaskan */
+  {"apl",	HB_TAG('A','T','H',' ')},	/* Lipan Apache -> Athapaskan */
+  {"apm",	HB_TAG('A','T','H',' ')},	/* Mescalero-Chiricahua Apache -> Athapaskan */
+  {"apw",	HB_TAG('A','T','H',' ')},	/* Western Apache -> Athapaskan */
+  {"ar",	HB_TAG('A','R','A',' ')},	/* Arabic [macrolanguage] */
+  {"arb",	HB_TAG('A','R','A',' ')},	/* Standard Arabic -> Arabic */
+  {"arn",	HB_TAG('M','A','P',' ')},	/* Mapudungun */
+  {"arq",	HB_TAG('A','R','A',' ')},	/* Algerian Arabic -> Arabic */
+  {"ars",	HB_TAG('A','R','A',' ')},	/* Najdi Arabic -> Arabic */
+  {"ary",	HB_TAG('M','O','R',' ')},	/* Moroccan Arabic -> Moroccan */
+  {"arz",	HB_TAG('A','R','A',' ')},	/* Egyptian Arabic -> Arabic */
+  {"as",	HB_TAG('A','S','M',' ')},	/* Assamese */
+/*{"ast",	HB_TAG('A','S','T',' ')},*/	/* Asturian */
+/*{"ath",	HB_TAG('A','T','H',' ')},*/	/* Athapascan [family] -> Athapaskan */
+  {"atj",	HB_TAG('R','C','R',' ')},	/* Atikamekw -> R-Cree */
+  {"atv",	HB_TAG('A','L','T',' ')},	/* Northern Altai -> Altai */
+  {"auz",	HB_TAG('A','R','A',' ')},	/* Uzbeki Arabic -> Arabic */
+  {"av",	HB_TAG('A','V','R',' ')},	/* Avaric -> Avar */
+  {"avl",	HB_TAG('A','R','A',' ')},	/* Eastern Egyptian Bedawi Arabic -> Arabic */
+/*{"awa",	HB_TAG('A','W','A',' ')},*/	/* Awadhi */
+  {"ay",	HB_TAG('A','Y','M',' ')},	/* Aymara [macrolanguage] */
+  {"ayc",	HB_TAG('A','Y','M',' ')},	/* Southern Aymara -> Aymara */
+  {"ayh",	HB_TAG('A','R','A',' ')},	/* Hadrami Arabic -> Arabic */
+  {"ayl",	HB_TAG('A','R','A',' ')},	/* Libyan Arabic -> Arabic */
+  {"ayn",	HB_TAG('A','R','A',' ')},	/* Sanaani Arabic -> Arabic */
+  {"ayp",	HB_TAG('A','R','A',' ')},	/* North Mesopotamian Arabic -> Arabic */
+  {"ayr",	HB_TAG('A','Y','M',' ')},	/* Central Aymara -> Aymara */
+  {"az",	HB_TAG('A','Z','E',' ')},	/* Azerbaijani [macrolanguage] */
+/*{"azb",	HB_TAG('A','Z','B',' ')},*/	/* South Azerbaijani -> Torki */
+  {"azj",	HB_TAG('A','Z','E',' ')},	/* North Azerbaijani -> Azerbaijani */
+  {"ba",	HB_TAG('B','S','H',' ')},	/* Bashkir */
+  {"bad",	HB_TAG('B','A','D','0')},	/* Banda [family] */
+  {"bai",	HB_TAG('B','M','L',' ')},	/* Bamileke [family] */
+  {"bal",	HB_TAG('B','L','I',' ')},	/* Baluchi [macrolanguage] */
+/*{"ban",	HB_TAG('B','A','N',' ')},*/	/* Balinese */
+/*{"bar",	HB_TAG('B','A','R',' ')},*/	/* Bavarian */
+/*{"bbc",	HB_TAG('B','B','C',' ')},*/	/* Batak Toba */
+  {"bbz",	HB_TAG('A','R','A',' ')},	/* Babalia Creole Arabic -> Arabic */
+  {"bcc",	HB_TAG('B','L','I',' ')},	/* Southern Balochi -> Baluchi */
+  {"bci",	HB_TAG('B','A','U',' ')},	/* Baoulé -> Baulé */
+  {"bcl",	HB_TAG('B','I','K',' ')},	/* Central Bikol -> Bikol */
+  {"bcq",	HB_TAG('B','C','H',' ')},	/* Bench */
+  {"bcr",	HB_TAG('A','T','H',' ')},	/* Babine -> Athapaskan */
+/*{"bdy",	HB_TAG('B','D','Y',' ')},*/	/* Bandjalang */
+  {"be",	HB_TAG('B','E','L',' ')},	/* Belarusian -> Belarussian */
+  {"bea",	HB_TAG('A','T','H',' ')},	/* Beaver -> Athapaskan */
+  {"beb",	HB_TAG('B','T','I',' ')},	/* Bebele -> Beti */
+/*{"bem",	HB_TAG('B','E','M',' ')},*/	/* Bemba (Zambia) */
+  {"ber",	HB_TAG('B','B','R',' ')},	/* Berber [family] */
+  {"bfq",	HB_TAG('B','A','D',' ')},	/* Badaga */
+  {"bft",	HB_TAG('B','L','T',' ')},	/* Balti */
+  {"bfu",	HB_TAG('L','A','H',' ')},	/* Gahri -> Lahuli */
+  {"bfy",	HB_TAG('B','A','G',' ')},	/* Bagheli -> Baghelkhandi */
+  {"bg",	HB_TAG('B','G','R',' ')},	/* Bulgarian */
+/*{"bgc",	HB_TAG('B','G','C',' ')},*/	/* Haryanvi */
+  {"bgn",	HB_TAG('B','L','I',' ')},	/* Western Balochi -> Baluchi */
+  {"bgp",	HB_TAG('B','L','I',' ')},	/* Eastern Balochi -> Baluchi */
+/*{"bgq",	HB_TAG('B','G','Q',' ')},*/	/* Bagri */
+  {"bgr",	HB_TAG('Q','I','N',' ')},	/* Bawm Chin -> Chin */
+  {"bhb",	HB_TAG('B','H','I',' ')},	/* Bhili */
+/*{"bhi",	HB_TAG('B','H','I',' ')},*/	/* Bhilali -> Bhili */
+  {"bhk",	HB_TAG('B','I','K',' ')},	/* Albay Bicolano (retired code) -> Bikol */
+/*{"bho",	HB_TAG('B','H','O',' ')},*/	/* Bhojpuri */
+  {"bhr",	HB_TAG('M','L','G',' ')},	/* Bara Malagasy -> Malagasy */
+  {"bi",	HB_TAG('B','I','S',' ')},	/* Bislama */
+/*{"bik",	HB_TAG('B','I','K',' ')},*/	/* Bikol [macrolanguage] */
+  {"bin",	HB_TAG('E','D','O',' ')},	/* Edo */
+/*{"bjj",	HB_TAG('B','J','J',' ')},*/	/* Kanauji */
+  {"bjn",	HB_TAG('M','L','Y',' ')},	/* Banjar -> Malay */
+  {"bjq",	HB_TAG('M','L','G',' ')},	/* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
+  {"bjt",	HB_TAG('B','L','N',' ')},	/* Balanta-Ganja -> Balante */
+  {"bla",	HB_TAG('B','K','F',' ')},	/* Siksika -> Blackfoot */
+  {"ble",	HB_TAG('B','L','N',' ')},	/* Balanta-Kentohe -> Balante */
+/*{"blk",	HB_TAG('B','L','K',' ')},*/	/* Pa’o Karen */
+  {"bln",	HB_TAG('B','I','K',' ')},	/* Southern Catanduanes Bikol -> Bikol */
+  {"bm",	HB_TAG('B','M','B',' ')},	/* Bambara (Bamanankan) */
+  {"bmm",	HB_TAG('M','L','G',' ')},	/* Northern Betsimisaraka Malagasy -> Malagasy */
+  {"bn",	HB_TAG('B','E','N',' ')},	/* Bengali */
+  {"bo",	HB_TAG('T','I','B',' ')},	/* Tibetan */
+/*{"bpy",	HB_TAG('B','P','Y',' ')},*/	/* Bishnupriya -> Bishnupriya Manipuri */
+  {"bqi",	HB_TAG('L','R','C',' ')},	/* Bakhtiari -> Luri */
+  {"br",	HB_TAG('B','R','E',' ')},	/* Breton */
+  {"bra",	HB_TAG('B','R','I',' ')},	/* Braj -> Braj Bhasha */
+/*{"brh",	HB_TAG('B','R','H',' ')},*/	/* Brahui */
+/*{"brx",	HB_TAG('B','R','X',' ')},*/	/* Bodo (India) */
+  {"bs",	HB_TAG('B','O','S',' ')},	/* Bosnian */
+/*{"bsk",	HB_TAG('B','S','K',' ')},*/	/* Burushaski */
+  {"btb",	HB_TAG('B','T','I',' ')},	/* Beti (Cameroon) (retired code) */
+  {"btj",	HB_TAG('M','L','Y',' ')},	/* Bacanese Malay -> Malay */
+  {"bto",	HB_TAG('B','I','K',' ')},	/* Rinconada Bikol -> Bikol */
+/*{"bts",	HB_TAG('B','T','S',' ')},*/	/* Batak Simalungun */
+/*{"bug",	HB_TAG('B','U','G',' ')},*/	/* Buginese -> Bugis */
+  {"bum",	HB_TAG('B','T','I',' ')},	/* Bulu (Cameroon) -> Beti */
+  {"bve",	HB_TAG('M','L','Y',' ')},	/* Berau Malay -> Malay */
+  {"bvu",	HB_TAG('M','L','Y',' ')},	/* Bukit Malay -> Malay */
+  {"bxk",	HB_TAG('L','U','H',' ')},	/* Bukusu -> Luyia */
+  {"bxp",	HB_TAG('B','T','I',' ')},	/* Bebil -> Beti */
+  {"bxr",	HB_TAG('R','B','U',' ')},	/* Russia Buriat -> Russian Buriat */
+  {"byn",	HB_TAG('B','I','L',' ')},	/* Bilin -> Bilen */
+/*{"byv",	HB_TAG('B','Y','V',' ')},*/	/* Medumba */
+  {"bzc",	HB_TAG('M','L','G',' ')},	/* Southern Betsimisaraka Malagasy -> Malagasy */
+  {"ca",	HB_TAG('C','A','T',' ')},	/* Catalan */
+  {"caf",	HB_TAG('C','R','R',' ')},	/* Southern Carrier -> Carrier */
+  {"caf",	HB_TAG('A','T','H',' ')},	/* Southern Carrier -> Athapaskan */
+/*{"cak",	HB_TAG('C','A','K',' ')},*/	/* Kaqchikel */
+/*{"cbk",	HB_TAG('C','B','K',' ')},*/	/* Chavacano -> Zamboanga Chavacano */
+  {"cbl",	HB_TAG('Q','I','N',' ')},	/* Bualkhaw Chin -> Chin */
+  {"cco",	HB_TAG('C','C','H','N')},	/* Comaltepec Chinantec -> Chinantec */
+  {"ccq",	HB_TAG('A','R','K',' ')},	/* Chaungtha (retired code) -> Rakhine */
+  {"cdo",	HB_TAG('Z','H','S',' ')},	/* Min Dong Chinese -> Chinese Simplified */
+  {"ce",	HB_TAG('C','H','E',' ')},	/* Chechen */
+/*{"ceb",	HB_TAG('C','E','B',' ')},*/	/* Cebuano */
+  {"cfm",	HB_TAG('H','A','L',' ')},	/* Halam (Falam Chin) */
+/*{"cgg",	HB_TAG('C','G','G',' ')},*/	/* Chiga */
+  {"ch",	HB_TAG('C','H','A',' ')},	/* Chamorro */
+  {"chj",	HB_TAG('C','C','H','N')},	/* Ojitlán Chinantec -> Chinantec */
+  {"chk",	HB_TAG('C','H','K','0')},	/* Chuukese */
+/*{"cho",	HB_TAG('C','H','O',' ')},*/	/* Choctaw */
+  {"chp",	HB_TAG('C','H','P',' ')},	/* Chipewyan */
+  {"chp",	HB_TAG('S','A','Y',' ')},	/* Chipewyan -> Sayisi */
+  {"chp",	HB_TAG('A','T','H',' ')},	/* Chipewyan -> Athapaskan */
+  {"chq",	HB_TAG('C','C','H','N')},	/* Quiotepec Chinantec -> Chinantec */
+/*{"chr",	HB_TAG('C','H','R',' ')},*/	/* Cherokee */
+/*{"chy",	HB_TAG('C','H','Y',' ')},*/	/* Cheyenne */
+  {"chz",	HB_TAG('C','C','H','N')},	/* Ozumacín Chinantec -> Chinantec */
+  {"ciw",	HB_TAG('O','J','B',' ')},	/* Chippewa -> Ojibway */
+/*{"cja",	HB_TAG('C','J','A',' ')},*/	/* Western Cham */
+/*{"cjm",	HB_TAG('C','J','M',' ')},*/	/* Eastern Cham */
+  {"cjy",	HB_TAG('Z','H','S',' ')},	/* Jinyu Chinese -> Chinese Simplified */
+  {"cka",	HB_TAG('Q','I','N',' ')},	/* Khumi Awa Chin (retired code) -> Chin */
+  {"ckb",	HB_TAG('K','U','R',' ')},	/* Central Kurdish -> Kurdish */
+  {"ckt",	HB_TAG('C','H','K',' ')},	/* Chukot -> Chukchi */
+  {"clc",	HB_TAG('A','T','H',' ')},	/* Chilcotin -> Athapaskan */
+  {"cld",	HB_TAG('S','Y','R',' ')},	/* Chaldean Neo-Aramaic -> Syriac */
+  {"cle",	HB_TAG('C','C','H','N')},	/* Lealao Chinantec -> Chinantec */
+  {"cmn",	HB_TAG('Z','H','S',' ')},	/* Mandarin Chinese -> Chinese Simplified */
+  {"cmr",	HB_TAG('Q','I','N',' ')},	/* Mro-Khimi Chin -> Chin */
+  {"cnb",	HB_TAG('Q','I','N',' ')},	/* Chinbon Chin -> Chin */
+  {"cnh",	HB_TAG('Q','I','N',' ')},	/* Hakha Chin -> Chin */
+  {"cnk",	HB_TAG('Q','I','N',' ')},	/* Khumi Chin -> Chin */
+  {"cnl",	HB_TAG('C','C','H','N')},	/* Lalana Chinantec -> Chinantec */
+  {"cnt",	HB_TAG('C','C','H','N')},	/* Tepetotutla Chinantec -> Chinantec */
+  {"cnw",	HB_TAG('Q','I','N',' ')},	/* Ngawn Chin -> Chin */
+  {"co",	HB_TAG('C','O','S',' ')},	/* Corsican */
+  {"coa",	HB_TAG('M','L','Y',' ')},	/* Cocos Islands Malay -> Malay */
+/*{"cop",	HB_TAG('C','O','P',' ')},*/	/* Coptic */
+  {"coq",	HB_TAG('A','T','H',' ')},	/* Coquille -> Athapaskan */
+  {"cpa",	HB_TAG('C','C','H','N')},	/* Palantla Chinantec -> Chinantec */
+  {"cpe",	HB_TAG('C','P','P',' ')},	/* English-based creoles and pidgins [family] -> Creoles */
+  {"cpf",	HB_TAG('C','P','P',' ')},	/* French-based creoles and pidgins [family] -> Creoles */
+/*{"cpp",	HB_TAG('C','P','P',' ')},*/	/* Portuguese-based creoles and pidgins [family] -> Creoles */
+  {"cpx",	HB_TAG('Z','H','S',' ')},	/* Pu-Xian Chinese -> Chinese Simplified */
+  {"cqd",	HB_TAG('H','M','N',' ')},	/* Chuanqiandian Cluster Miao -> Hmong */
+  {"cqu",	HB_TAG('Q','U','H',' ')},	/* Chilean Quechua (retired code) -> Quechua (Bolivia) */
+  {"cr",	HB_TAG('C','R','E',' ')},	/* Cree [macrolanguage] */
+  {"cr",	HB_TAG('Y','C','R',' ')},	/* Cree [macrolanguage] -> Y-Cree */
+  {"crh",	HB_TAG('C','R','T',' ')},	/* Crimean Tatar */
+  {"crj",	HB_TAG('E','C','R',' ')},	/* Southern East Cree -> Eastern Cree */
+  {"crk",	HB_TAG('W','C','R',' ')},	/* Plains Cree -> West-Cree */
+  {"crl",	HB_TAG('E','C','R',' ')},	/* Northern East Cree -> Eastern Cree */
+  {"crm",	HB_TAG('M','C','R',' ')},	/* Moose Cree */
+  {"crm",	HB_TAG('L','C','R',' ')},	/* Moose Cree -> L-Cree */
+  {"crp",	HB_TAG('C','P','P',' ')},	/* Creoles and pidgins [family] -> Creoles */
+  {"crx",	HB_TAG('C','R','R',' ')},	/* Carrier */
+  {"crx",	HB_TAG('A','T','H',' ')},	/* Carrier -> Athapaskan */
+  {"cs",	HB_TAG('C','S','Y',' ')},	/* Czech */
+  {"csa",	HB_TAG('C','C','H','N')},	/* Chiltepec Chinantec -> Chinantec */
+/*{"csb",	HB_TAG('C','S','B',' ')},*/	/* Kashubian */
+  {"csh",	HB_TAG('Q','I','N',' ')},	/* Asho Chin -> Chin */
+  {"cso",	HB_TAG('C','C','H','N')},	/* Sochiapam Chinantec -> Chinantec */
+  {"csw",	HB_TAG('N','C','R',' ')},	/* Swampy Cree -> N-Cree */
+  {"csw",	HB_TAG('N','H','C',' ')},	/* Swampy Cree -> Norway House Cree */
+  {"csy",	HB_TAG('Q','I','N',' ')},	/* Siyin Chin -> Chin */
+  {"ctc",	HB_TAG('A','T','H',' ')},	/* Chetco -> Athapaskan */
+  {"ctd",	HB_TAG('Q','I','N',' ')},	/* Tedim Chin -> Chin */
+  {"cte",	HB_TAG('C','C','H','N')},	/* Tepinapa Chinantec -> Chinantec */
+/*{"ctg",	HB_TAG('C','T','G',' ')},*/	/* Chittagonian */
+  {"ctl",	HB_TAG('C','C','H','N')},	/* Tlacoatzintepec Chinantec -> Chinantec */
+  {"cts",	HB_TAG('B','I','K',' ')},	/* Northern Catanduanes Bikol -> Bikol */
+  {"cu",	HB_TAG('C','S','L',' ')},	/* Church Slavonic */
+  {"cuc",	HB_TAG('C','C','H','N')},	/* Usila Chinantec -> Chinantec */
+/*{"cuk",	HB_TAG('C','U','K',' ')},*/	/* San Blas Kuna */
+  {"cv",	HB_TAG('C','H','U',' ')},	/* Chuvash */
+  {"cvn",	HB_TAG('C','C','H','N')},	/* Valle Nacional Chinantec -> Chinantec */
+  {"cwd",	HB_TAG('D','C','R',' ')},	/* Woods Cree */
+  {"cwd",	HB_TAG('T','C','R',' ')},	/* Woods Cree -> TH-Cree */
+  {"cy",	HB_TAG('W','E','L',' ')},	/* Welsh */
+  {"czh",	HB_TAG('Z','H','S',' ')},	/* Huizhou Chinese -> Chinese Simplified */
+  {"czo",	HB_TAG('Z','H','S',' ')},	/* Min Zhong Chinese -> Chinese Simplified */
+  {"czt",	HB_TAG('Q','I','N',' ')},	/* Zotung Chin -> Chin */
+  {"da",	HB_TAG('D','A','N',' ')},	/* Danish */
+  {"dao",	HB_TAG('Q','I','N',' ')},	/* Daai Chin -> Chin */
+  {"dap",	HB_TAG('N','I','S',' ')},	/* Nisi (India) (retired code) */
+/*{"dar",	HB_TAG('D','A','R',' ')},*/	/* Dargwa */
+/*{"dax",	HB_TAG('D','A','X',' ')},*/	/* Dayi */
+  {"de",	HB_TAG('D','E','U',' ')},	/* German */
+  {"den",	HB_TAG('S','L','A',' ')},	/* Slave (Athapascan) [macrolanguage] -> Slavey */
+  {"den",	HB_TAG('A','T','H',' ')},	/* Slave (Athapascan) [macrolanguage] -> Athapaskan */
+/*{"dgo",	HB_TAG('D','G','O',' ')},*/	/* Dogri */
+  {"dgr",	HB_TAG('A','T','H',' ')},	/* Dogrib -> Athapaskan */
+  {"dhd",	HB_TAG('M','A','W',' ')},	/* Dhundari -> Marwari */
+/*{"dhg",	HB_TAG('D','H','G',' ')},*/	/* Dhangu */
+  {"dib",	HB_TAG('D','N','K',' ')},	/* South Central Dinka -> Dinka */
+  {"dik",	HB_TAG('D','N','K',' ')},	/* Southwestern Dinka -> Dinka */
+  {"din",	HB_TAG('D','N','K',' ')},	/* Dinka [macrolanguage] */
+  {"dip",	HB_TAG('D','N','K',' ')},	/* Northeastern Dinka -> Dinka */
+/*{"diq",	HB_TAG('D','I','Q',' ')},*/	/* Dimli */
+  {"diw",	HB_TAG('D','N','K',' ')},	/* Northwestern Dinka -> Dinka */
+  {"dje",	HB_TAG('D','J','R',' ')},	/* Zarma */
+  {"djr",	HB_TAG('D','J','R','0')},	/* Djambarrpuyngu */
+  {"dks",	HB_TAG('D','N','K',' ')},	/* Southeastern Dinka -> Dinka */
+  {"dng",	HB_TAG('D','U','N',' ')},	/* Dungan */
+/*{"dnj",	HB_TAG('D','N','J',' ')},*/	/* Dan */
+  {"doi",	HB_TAG('D','G','R',' ')},	/* Dogri [macrolanguage] */
+  {"drh",	HB_TAG('M','N','G',' ')},	/* Darkhat (retired code) -> Mongolian */
+  {"drw",	HB_TAG('D','R','I',' ')},	/* Darwazi (retired code) -> Dari */
+  {"dsb",	HB_TAG('L','S','B',' ')},	/* Lower Sorbian */
+  {"dty",	HB_TAG('N','E','P',' ')},	/* Dotyali -> Nepali */
+/*{"duj",	HB_TAG('D','U','J',' ')},*/	/* Dhuwal (retired code) */
+  {"dup",	HB_TAG('M','L','Y',' ')},	/* Duano -> Malay */
+  {"dv",	HB_TAG('D','I','V',' ')},	/* Divehi (Dhivehi, Maldivian) */
+  {"dv",	HB_TAG('D','H','V',' ')},	/* Divehi (Dhivehi, Maldivian) (deprecated) */
+  {"dwu",	HB_TAG('D','U','J',' ')},	/* Dhuwal */
+  {"dwy",	HB_TAG('D','U','J',' ')},	/* Dhuwaya -> Dhuwal */
+  {"dyu",	HB_TAG('J','U','L',' ')},	/* Dyula -> Jula */
+  {"dz",	HB_TAG('D','Z','N',' ')},	/* Dzongkha */
+  {"ee",	HB_TAG('E','W','E',' ')},	/* Ewe */
+/*{"efi",	HB_TAG('E','F','I',' ')},*/	/* Efik */
+  {"ekk",	HB_TAG('E','T','I',' ')},	/* Standard Estonian -> Estonian */
+  {"el",	HB_TAG('E','L','L',' ')},	/* Modern Greek (1453-) -> Greek */
+  {"emk",	HB_TAG('E','M','K',' ')},	/* Eastern Maninkakan */
+  {"emk",	HB_TAG('M','N','K',' ')},	/* Eastern Maninkakan -> Maninka */
+  {"en",	HB_TAG('E','N','G',' ')},	/* English */
+  {"enb",	HB_TAG('K','A','L',' ')},	/* Markweeta -> Kalenjin */
+  {"enf",	HB_TAG('F','N','E',' ')},	/* Forest Enets -> Forest Nenets */
+  {"enh",	HB_TAG('T','N','E',' ')},	/* Tundra Enets -> Tundra Nenets */
+  {"eo",	HB_TAG('N','T','O',' ')},	/* Esperanto */
+  {"es",	HB_TAG('E','S','P',' ')},	/* Spanish */
+  {"esg",	HB_TAG('G','O','N',' ')},	/* Aheri Gondi -> Gondi */
+  {"esi",	HB_TAG('I','P','K',' ')},	/* North Alaskan Inupiatun -> Inupiat */
+  {"esk",	HB_TAG('I','P','K',' ')},	/* Northwest Alaska Inupiatun -> Inupiat */
+/*{"esu",	HB_TAG('E','S','U',' ')},*/	/* Central Yupik */
+  {"et",	HB_TAG('E','T','I',' ')},	/* Estonian [macrolanguage] */
+  {"eto",	HB_TAG('B','T','I',' ')},	/* Eton (Cameroon) -> Beti */
+  {"eu",	HB_TAG('E','U','Q',' ')},	/* Basque */
+  {"eve",	HB_TAG('E','V','N',' ')},	/* Even */
+  {"evn",	HB_TAG('E','V','K',' ')},	/* Evenki */
+  {"ewo",	HB_TAG('B','T','I',' ')},	/* Ewondo -> Beti */
+  {"eyo",	HB_TAG('K','A','L',' ')},	/* Keiyo -> Kalenjin */
+  {"fa",	HB_TAG('F','A','R',' ')},	/* Persian [macrolanguage] */
+  {"fan",	HB_TAG('F','A','N','0')},	/* Fang (Equatorial Guinea) */
+/*{"fat",	HB_TAG('F','A','T',' ')},*/	/* Fanti */
+  {"fbl",	HB_TAG('B','I','K',' ')},	/* West Albay Bikol -> Bikol */
+  {"ff",	HB_TAG('F','U','L',' ')},	/* Fulah [macrolanguage] */
+  {"ffm",	HB_TAG('F','U','L',' ')},	/* Maasina Fulfulde -> Fulah */
+  {"fi",	HB_TAG('F','I','N',' ')},	/* Finnish */
+  {"fil",	HB_TAG('P','I','L',' ')},	/* Filipino */
+  {"fj",	HB_TAG('F','J','I',' ')},	/* Fijian */
+  {"flm",	HB_TAG('H','A','L',' ')},	/* Halam (Falam Chin) (retired code) */
+  {"flm",	HB_TAG('Q','I','N',' ')},	/* Falam Chin (retired code) -> Chin */
+/*{"fmp",	HB_TAG('F','M','P',' ')},*/	/* Fe’fe’ */
+  {"fo",	HB_TAG('F','O','S',' ')},	/* Faroese */
+/*{"fon",	HB_TAG('F','O','N',' ')},*/	/* Fon */
+  {"fr",	HB_TAG('F','R','A',' ')},	/* French */
+/*{"frc",	HB_TAG('F','R','C',' ')},*/	/* Cajun French */
+/*{"frp",	HB_TAG('F','R','P',' ')},*/	/* Arpitan */
+  {"fub",	HB_TAG('F','U','L',' ')},	/* Adamawa Fulfulde -> Fulah */
+  {"fuc",	HB_TAG('F','U','L',' ')},	/* Pulaar -> Fulah */
+  {"fue",	HB_TAG('F','U','L',' ')},	/* Borgu Fulfulde -> Fulah */
+  {"fuf",	HB_TAG('F','T','A',' ')},	/* Pular -> Futa */
+  {"fuh",	HB_TAG('F','U','L',' ')},	/* Western Niger Fulfulde -> Fulah */
+  {"fui",	HB_TAG('F','U','L',' ')},	/* Bagirmi Fulfulde -> Fulah */
+  {"fuq",	HB_TAG('F','U','L',' ')},	/* Central-Eastern Niger Fulfulde -> Fulah */
+  {"fur",	HB_TAG('F','R','L',' ')},	/* Friulian */
+/*{"fuv",	HB_TAG('F','U','V',' ')},*/	/* Nigerian Fulfulde */
+  {"fy",	HB_TAG('F','R','I',' ')},	/* Western Frisian -> Frisian */
+  {"ga",	HB_TAG('I','R','I',' ')},	/* Irish */
+  {"gaa",	HB_TAG('G','A','D',' ')},	/* Ga */
+/*{"gag",	HB_TAG('G','A','G',' ')},*/	/* Gagauz */
+  {"gan",	HB_TAG('Z','H','S',' ')},	/* Gan Chinese -> Chinese Simplified */
+  {"gax",	HB_TAG('O','R','O',' ')},	/* Borana-Arsi-Guji Oromo -> Oromo */
+  {"gaz",	HB_TAG('O','R','O',' ')},	/* West Central Oromo -> Oromo */
+  {"gbm",	HB_TAG('G','A','W',' ')},	/* Garhwali */
+  {"gce",	HB_TAG('A','T','H',' ')},	/* Galice -> Athapaskan */
+  {"gd",	HB_TAG('G','A','E',' ')},	/* Scottish Gaelic (Gaelic) */
+  {"gda",	HB_TAG('R','A','J',' ')},	/* Gade Lohar -> Rajasthani */
+/*{"gez",	HB_TAG('G','E','Z',' ')},*/	/* Geez */
+  {"ggo",	HB_TAG('G','O','N',' ')},	/* Southern Gondi (retired code) -> Gondi */
+/*{"gih",	HB_TAG('G','I','H',' ')},*/	/* Githabul */
+  {"gil",	HB_TAG('G','I','L','0')},	/* Kiribati (Gilbertese) */
+  {"gju",	HB_TAG('R','A','J',' ')},	/* Gujari -> Rajasthani */
+/*{"gkp",	HB_TAG('G','K','P',' ')},*/	/* Guinea Kpelle -> Kpelle (Guinea) */
+  {"gl",	HB_TAG('G','A','L',' ')},	/* Galician */
+  {"gld",	HB_TAG('N','A','N',' ')},	/* Nanai */
+/*{"glk",	HB_TAG('G','L','K',' ')},*/	/* Gilaki */
+  {"gn",	HB_TAG('G','U','A',' ')},	/* Guarani [macrolanguage] */
+/*{"gnn",	HB_TAG('G','N','N',' ')},*/	/* Gumatj */
+  {"gno",	HB_TAG('G','O','N',' ')},	/* Northern Gondi -> Gondi */
+  {"gnw",	HB_TAG('G','U','A',' ')},	/* Western Bolivian Guaraní -> Guarani */
+/*{"gog",	HB_TAG('G','O','G',' ')},*/	/* Gogo */
+  {"gom",	HB_TAG('K','O','K',' ')},	/* Goan Konkani -> Konkani */
+/*{"gon",	HB_TAG('G','O','N',' ')},*/	/* Gondi [macrolanguage] */
+  {"grt",	HB_TAG('G','R','O',' ')},	/* Garo */
+  {"gru",	HB_TAG('S','O','G',' ')},	/* Kistane -> Sodo Gurage */
+  {"gsw",	HB_TAG('A','L','S',' ')},	/* Alsatian */
+  {"gu",	HB_TAG('G','U','J',' ')},	/* Gujarati */
+/*{"guc",	HB_TAG('G','U','C',' ')},*/	/* Wayuu */
+/*{"guf",	HB_TAG('G','U','F',' ')},*/	/* Gupapuyngu */
+  {"gug",	HB_TAG('G','U','A',' ')},	/* Paraguayan Guaraní -> Guarani */
+  {"gui",	HB_TAG('G','U','A',' ')},	/* Eastern Bolivian Guaraní -> Guarani */
+  {"guk",	HB_TAG('G','M','Z',' ')},	/* Gumuz */
+  {"guk",	HB_TAG('G','U','K',' ')},	/* Gumuz (SIL fonts) */
+  {"gun",	HB_TAG('G','U','A',' ')},	/* Mbyá Guaraní -> Guarani */
+/*{"guz",	HB_TAG('G','U','Z',' ')},*/	/* Gusii */
+  {"gv",	HB_TAG('M','N','X',' ')},	/* Manx */
+  {"gwi",	HB_TAG('A','T','H',' ')},	/* Gwichʼin -> Athapaskan */
+  {"ha",	HB_TAG('H','A','U',' ')},	/* Hausa */
+  {"haa",	HB_TAG('A','T','H',' ')},	/* Han -> Athapaskan */
+  {"hae",	HB_TAG('O','R','O',' ')},	/* Eastern Oromo -> Oromo */
+  {"hak",	HB_TAG('Z','H','S',' ')},	/* Hakka Chinese -> Chinese Simplified */
+  {"har",	HB_TAG('H','R','I',' ')},	/* Harari */
+/*{"haw",	HB_TAG('H','A','W',' ')},*/	/* Hawaiian */
+/*{"hay",	HB_TAG('H','A','Y',' ')},*/	/* Haya */
+/*{"haz",	HB_TAG('H','A','Z',' ')},*/	/* Hazaragi */
+  {"he",	HB_TAG('I','W','R',' ')},	/* Hebrew */
+  {"hea",	HB_TAG('H','M','N',' ')},	/* Northern Qiandong Miao -> Hmong */
+  {"hi",	HB_TAG('H','I','N',' ')},	/* Hindi */
+/*{"hil",	HB_TAG('H','I','L',' ')},*/	/* Hiligaynon */
+  {"hji",	HB_TAG('M','L','Y',' ')},	/* Haji -> Malay */
+  {"hlt",	HB_TAG('Q','I','N',' ')},	/* Matu Chin -> Chin */
+  {"hma",	HB_TAG('H','M','N',' ')},	/* Southern Mashan Hmong -> Hmong */
+  {"hmc",	HB_TAG('H','M','N',' ')},	/* Central Huishui Hmong -> Hmong */
+  {"hmd",	HB_TAG('H','M','N',' ')},	/* Large Flowery Miao -> Hmong */
+  {"hme",	HB_TAG('H','M','N',' ')},	/* Eastern Huishui Hmong -> Hmong */
+  {"hmg",	HB_TAG('H','M','N',' ')},	/* Southwestern Guiyang Hmong -> Hmong */
+  {"hmh",	HB_TAG('H','M','N',' ')},	/* Southwestern Huishui Hmong -> Hmong */
+  {"hmi",	HB_TAG('H','M','N',' ')},	/* Northern Huishui Hmong -> Hmong */
+  {"hmj",	HB_TAG('H','M','N',' ')},	/* Ge -> Hmong */
+  {"hml",	HB_TAG('H','M','N',' ')},	/* Luopohe Hmong -> Hmong */
+  {"hmm",	HB_TAG('H','M','N',' ')},	/* Central Mashan Hmong -> Hmong */
+/*{"hmn",	HB_TAG('H','M','N',' ')},*/	/* Hmong [macrolanguage] */
+  {"hmp",	HB_TAG('H','M','N',' ')},	/* Northern Mashan Hmong -> Hmong */
+  {"hmq",	HB_TAG('H','M','N',' ')},	/* Eastern Qiandong Miao -> Hmong */
+  {"hms",	HB_TAG('H','M','N',' ')},	/* Southern Qiandong Miao -> Hmong */
+  {"hmw",	HB_TAG('H','M','N',' ')},	/* Western Mashan Hmong -> Hmong */
+  {"hmy",	HB_TAG('H','M','N',' ')},	/* Southern Guiyang Hmong -> Hmong */
+  {"hmz",	HB_TAG('H','M','N',' ')},	/* Hmong Shua -> Hmong */
+/*{"hnd",	HB_TAG('H','N','D',' ')},*/	/* Southern Hindko -> Hindko */
+  {"hne",	HB_TAG('C','H','H',' ')},	/* Chhattisgarhi -> Chattisgarhi */
+  {"hnj",	HB_TAG('H','M','N',' ')},	/* Hmong Njua -> Hmong */
+  {"hno",	HB_TAG('H','N','D',' ')},	/* Northern Hindko -> Hindko */
+  {"ho",	HB_TAG('H','M','O',' ')},	/* Hiri Motu */
+  {"hoc",	HB_TAG('H','O',' ',' ')},	/* Ho */
+  {"hoi",	HB_TAG('A','T','H',' ')},	/* Holikachuk -> Athapaskan */
+  {"hoj",	HB_TAG('H','A','R',' ')},	/* Hadothi -> Harauti */
+  {"hr",	HB_TAG('H','R','V',' ')},	/* Croatian */
+  {"hrm",	HB_TAG('H','M','N',' ')},	/* Horned Miao -> Hmong */
+  {"hsb",	HB_TAG('U','S','B',' ')},	/* Upper Sorbian */
+  {"hsn",	HB_TAG('Z','H','S',' ')},	/* Xiang Chinese -> Chinese Simplified */
+  {"ht",	HB_TAG('H','A','I',' ')},	/* Haitian (Haitian Creole) */
+  {"hu",	HB_TAG('H','U','N',' ')},	/* Hungarian */
+  {"huj",	HB_TAG('H','M','N',' ')},	/* Northern Guiyang Hmong -> Hmong */
+  {"hup",	HB_TAG('A','T','H',' ')},	/* Hupa -> Athapaskan */
+  {"hy",	HB_TAG('H','Y','E','0')},	/* Armenian -> Armenian East */
+  {"hy",	HB_TAG('H','Y','E',' ')},	/* Armenian */
+  {"hyw",	HB_TAG('H','Y','E',' ')},	/* Western Armenian -> Armenian */
+  {"hz",	HB_TAG('H','E','R',' ')},	/* Herero */
+  {"ia",	HB_TAG('I','N','A',' ')},	/* Interlingua (International Auxiliary Language Association) */
+/*{"iba",	HB_TAG('I','B','A',' ')},*/	/* Iban */
+/*{"ibb",	HB_TAG('I','B','B',' ')},*/	/* Ibibio */
+  {"id",	HB_TAG('I','N','D',' ')},	/* Indonesian */
+  {"ida",	HB_TAG('L','U','H',' ')},	/* Idakho-Isukha-Tiriki -> Luyia */
+  {"ie",	HB_TAG('I','L','E',' ')},	/* Interlingue */
+  {"ig",	HB_TAG('I','B','O',' ')},	/* Igbo */
+  {"igb",	HB_TAG('E','B','I',' ')},	/* Ebira */
+  {"ii",	HB_TAG('Y','I','M',' ')},	/* Sichuan Yi -> Yi Modern */
+  {"ijc",	HB_TAG('I','J','O',' ')},	/* Izon -> Ijo */
+/*{"ijo",	HB_TAG('I','J','O',' ')},*/	/* Ijo [family] */
+  {"ik",	HB_TAG('I','P','K',' ')},	/* Inupiaq [macrolanguage] -> Inupiat */
+  {"ike",	HB_TAG('I','N','U',' ')},	/* Eastern Canadian Inuktitut -> Inuktitut */
+  {"ikt",	HB_TAG('I','N','U',' ')},	/* Inuinnaqtun -> Inuktitut */
+/*{"ilo",	HB_TAG('I','L','O',' ')},*/	/* Iloko -> Ilokano */
+  {"in",	HB_TAG('I','N','D',' ')},	/* Indonesian (retired code) */
+  {"ing",	HB_TAG('A','T','H',' ')},	/* Degexit'an -> Athapaskan */
+  {"inh",	HB_TAG('I','N','G',' ')},	/* Ingush */
+  {"io",	HB_TAG('I','D','O',' ')},	/* Ido */
+  {"is",	HB_TAG('I','S','L',' ')},	/* Icelandic */
+  {"it",	HB_TAG('I','T','A',' ')},	/* Italian */
+  {"iu",	HB_TAG('I','N','U',' ')},	/* Inuktitut [macrolanguage] */
+  {"iw",	HB_TAG('I','W','R',' ')},	/* Hebrew (retired code) */
+  {"ja",	HB_TAG('J','A','N',' ')},	/* Japanese */
+  {"jak",	HB_TAG('M','L','Y',' ')},	/* Jakun -> Malay */
+/*{"jam",	HB_TAG('J','A','M',' ')},*/	/* Jamaican Creole English -> Jamaican Creole */
+  {"jax",	HB_TAG('M','L','Y',' ')},	/* Jambi Malay -> Malay */
+/*{"jbo",	HB_TAG('J','B','O',' ')},*/	/* Lojban */
+/*{"jct",	HB_TAG('J','C','T',' ')},*/	/* Krymchak */
+  {"ji",	HB_TAG('J','I','I',' ')},	/* Yiddish (retired code) */
+  {"jv",	HB_TAG('J','A','V',' ')},	/* Javanese */
+  {"jw",	HB_TAG('J','A','V',' ')},	/* Javanese (retired code) */
+  {"ka",	HB_TAG('K','A','T',' ')},	/* Georgian */
+  {"kaa",	HB_TAG('K','R','K',' ')},	/* Kara-Kalpak -> Karakalpak */
+  {"kab",	HB_TAG('K','A','B','0')},	/* Kabyle */
+  {"kam",	HB_TAG('K','M','B',' ')},	/* Kamba (Kenya) */
+  {"kar",	HB_TAG('K','R','N',' ')},	/* Karen [family] */
+  {"kbd",	HB_TAG('K','A','B',' ')},	/* Kabardian */
+  {"kby",	HB_TAG('K','N','R',' ')},	/* Manga Kanuri -> Kanuri */
+  {"kca",	HB_TAG('K','H','K',' ')},	/* Khanty -> Khanty-Kazim */
+  {"kca",	HB_TAG('K','H','S',' ')},	/* Khanty -> Khanty-Shurishkar */
+  {"kca",	HB_TAG('K','H','V',' ')},	/* Khanty -> Khanty-Vakhi */
+/*{"kde",	HB_TAG('K','D','E',' ')},*/	/* Makonde */
+  {"kdr",	HB_TAG('K','R','M',' ')},	/* Karaim */
+  {"kdt",	HB_TAG('K','U','Y',' ')},	/* Kuy */
+/*{"kea",	HB_TAG('K','E','A',' ')},*/	/* Kabuverdianu (Crioulo) */
+/*{"kek",	HB_TAG('K','E','K',' ')},*/	/* Kekchi */
+  {"kex",	HB_TAG('K','K','N',' ')},	/* Kukna -> Kokni */
+  {"kfa",	HB_TAG('K','O','D',' ')},	/* Kodava -> Kodagu */
+  {"kfr",	HB_TAG('K','A','C',' ')},	/* Kachhi -> Kachchi */
+  {"kfx",	HB_TAG('K','U','L',' ')},	/* Kullu Pahari -> Kulvi */
+  {"kfy",	HB_TAG('K','M','N',' ')},	/* Kumaoni */
+  {"kg",	HB_TAG('K','O','N','0')},	/* Kongo [macrolanguage] */
+  {"kha",	HB_TAG('K','S','I',' ')},	/* Khasi */
+  {"khb",	HB_TAG('X','B','D',' ')},	/* Lü */
+  {"khk",	HB_TAG('M','N','G',' ')},	/* Halh Mongolian -> Mongolian */
+  {"kht",	HB_TAG('K','H','N',' ')},	/* Khamti -> Khamti Shan (Microsoft fonts) */
+  {"kht",	HB_TAG('K','H','T',' ')},	/* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
+/*{"khw",	HB_TAG('K','H','W',' ')},*/	/* Khowar */
+  {"ki",	HB_TAG('K','I','K',' ')},	/* Kikuyu (Gikuyu) */
+/*{"kiu",	HB_TAG('K','I','U',' ')},*/	/* Kirmanjki */
+  {"kj",	HB_TAG('K','U','A',' ')},	/* Kuanyama */
+/*{"kjd",	HB_TAG('K','J','D',' ')},*/	/* Southern Kiwai */
+  {"kjh",	HB_TAG('K','H','A',' ')},	/* Khakas -> Khakass */
+/*{"kjp",	HB_TAG('K','J','P',' ')},*/	/* Pwo Eastern Karen -> Eastern Pwo Karen */
+/*{"kjz",	HB_TAG('K','J','Z',' ')},*/	/* Bumthangkha */
+  {"kk",	HB_TAG('K','A','Z',' ')},	/* Kazakh */
+  {"kkz",	HB_TAG('A','T','H',' ')},	/* Kaska -> Athapaskan */
+  {"kl",	HB_TAG('G','R','N',' ')},	/* Greenlandic */
+  {"kln",	HB_TAG('K','A','L',' ')},	/* Kalenjin [macrolanguage] */
+  {"km",	HB_TAG('K','H','M',' ')},	/* Khmer */
+  {"kmb",	HB_TAG('M','B','N',' ')},	/* Kimbundu -> Mbundu */
+  {"kmr",	HB_TAG('K','U','R',' ')},	/* Northern Kurdish -> Kurdish */
+  {"kmw",	HB_TAG('K','M','O',' ')},	/* Komo (Democratic Republic of Congo) */
+/*{"kmz",	HB_TAG('K','M','Z',' ')},*/	/* Khorasani Turkish -> Khorasani Turkic */
+  {"kn",	HB_TAG('K','A','N',' ')},	/* Kannada */
+  {"knc",	HB_TAG('K','N','R',' ')},	/* Central Kanuri -> Kanuri */
+  {"kng",	HB_TAG('K','O','N','0')},	/* Koongo -> Kongo */
+  {"knn",	HB_TAG('K','O','K',' ')},	/* Konkani */
+  {"ko",	HB_TAG('K','O','R',' ')},	/* Korean */
+  {"koi",	HB_TAG('K','O','P',' ')},	/* Komi-Permyak */
+/*{"kok",	HB_TAG('K','O','K',' ')},*/	/* Konkani [macrolanguage] */
+/*{"kos",	HB_TAG('K','O','S',' ')},*/	/* Kosraean */
+  {"koy",	HB_TAG('A','T','H',' ')},	/* Koyukon -> Athapaskan */
+  {"kpe",	HB_TAG('K','P','L',' ')},	/* Kpelle [macrolanguage] */
+  {"kpv",	HB_TAG('K','O','Z',' ')},	/* Komi-Zyrian */
+  {"kpy",	HB_TAG('K','Y','K',' ')},	/* Koryak */
+  {"kqs",	HB_TAG('K','I','S',' ')},	/* Northern Kissi -> Kisii */
+  {"kqy",	HB_TAG('K','R','T',' ')},	/* Koorete */
+  {"kr",	HB_TAG('K','N','R',' ')},	/* Kanuri [macrolanguage] */
+  {"krc",	HB_TAG('K','A','R',' ')},	/* Karachay-Balkar -> Karachay */
+  {"krc",	HB_TAG('B','A','L',' ')},	/* Karachay-Balkar -> Balkar */
+/*{"kri",	HB_TAG('K','R','I',' ')},*/	/* Krio */
+/*{"krl",	HB_TAG('K','R','L',' ')},*/	/* Karelian */
+  {"krt",	HB_TAG('K','N','R',' ')},	/* Tumari Kanuri -> Kanuri */
+  {"kru",	HB_TAG('K','U','U',' ')},	/* Kurukh */
+  {"ks",	HB_TAG('K','S','H',' ')},	/* Kashmiri */
+  {"ksh",	HB_TAG('K','S','H','0')},	/* Kölsch -> Ripuarian */
+  {"kss",	HB_TAG('K','I','S',' ')},	/* Southern Kisi -> Kisii */
+/*{"ksw",	HB_TAG('K','S','W',' ')},*/	/* S’gaw Karen */
+  {"ktb",	HB_TAG('K','E','B',' ')},	/* Kambaata -> Kebena */
+  {"ktu",	HB_TAG('K','O','N',' ')},	/* Kituba (Democratic Republic of Congo) -> Kikongo */
+  {"ktw",	HB_TAG('A','T','H',' ')},	/* Kato -> Athapaskan */
+  {"ku",	HB_TAG('K','U','R',' ')},	/* Kurdish [macrolanguage] */
+/*{"kum",	HB_TAG('K','U','M',' ')},*/	/* Kumyk */
+  {"kuu",	HB_TAG('A','T','H',' ')},	/* Upper Kuskokwim -> Athapaskan */
+  {"kv",	HB_TAG('K','O','M',' ')},	/* Komi [macrolanguage] */
+  {"kvb",	HB_TAG('M','L','Y',' ')},	/* Kubu -> Malay */
+  {"kvr",	HB_TAG('M','L','Y',' ')},	/* Kerinci -> Malay */
+  {"kw",	HB_TAG('C','O','R',' ')},	/* Cornish */
+  {"kwy",	HB_TAG('K','O','N','0')},	/* San Salvador Kongo -> Kongo */
+  {"kxc",	HB_TAG('K','M','S',' ')},	/* Konso -> Komso */
+  {"kxd",	HB_TAG('M','L','Y',' ')},	/* Brunei -> Malay */
+  {"kxu",	HB_TAG('K','U','I',' ')},	/* Kui (India) */
+  {"ky",	HB_TAG('K','I','R',' ')},	/* Kirghiz (Kyrgyz) */
+/*{"kyu",	HB_TAG('K','Y','U',' ')},*/	/* Western Kayah */
+  {"la",	HB_TAG('L','A','T',' ')},	/* Latin */
+  {"lad",	HB_TAG('J','U','D',' ')},	/* Ladino */
+  {"lb",	HB_TAG('L','T','Z',' ')},	/* Luxembourgish */
+  {"lbe",	HB_TAG('L','A','K',' ')},	/* Lak */
+  {"lbj",	HB_TAG('L','D','K',' ')},	/* Ladakhi */
+  {"lbl",	HB_TAG('B','I','K',' ')},	/* Libon Bikol -> Bikol */
+  {"lce",	HB_TAG('M','L','Y',' ')},	/* Loncong -> Malay */
+  {"lcf",	HB_TAG('M','L','Y',' ')},	/* Lubu -> Malay */
+  {"ldi",	HB_TAG('K','O','N','0')},	/* Laari -> Kongo */
+/*{"lez",	HB_TAG('L','E','Z',' ')},*/	/* Lezghian -> Lezgi */
+  {"lg",	HB_TAG('L','U','G',' ')},	/* Ganda */
+  {"li",	HB_TAG('L','I','M',' ')},	/* Limburgish */
+  {"lif",	HB_TAG('L','M','B',' ')},	/* Limbu */
+/*{"lij",	HB_TAG('L','I','J',' ')},*/	/* Ligurian */
+/*{"lis",	HB_TAG('L','I','S',' ')},*/	/* Lisu */
+  {"liw",	HB_TAG('M','L','Y',' ')},	/* Col -> Malay */
+/*{"ljp",	HB_TAG('L','J','P',' ')},*/	/* Lampung Api -> Lampung */
+  {"lkb",	HB_TAG('L','U','H',' ')},	/* Kabras -> Luyia */
+/*{"lki",	HB_TAG('L','K','I',' ')},*/	/* Laki */
+  {"lko",	HB_TAG('L','U','H',' ')},	/* Khayo -> Luyia */
+  {"lks",	HB_TAG('L','U','H',' ')},	/* Kisa -> Luyia */
+  {"lld",	HB_TAG('L','A','D',' ')},	/* Ladin */
+  {"lmn",	HB_TAG('L','A','M',' ')},	/* Lambadi -> Lambani */
+/*{"lmo",	HB_TAG('L','M','O',' ')},*/	/* Lombard */
+  {"ln",	HB_TAG('L','I','N',' ')},	/* Lingala */
+  {"lo",	HB_TAG('L','A','O',' ')},	/* Lao */
+/*{"lom",	HB_TAG('L','O','M',' ')},*/	/* Loma (Liberia) */
+/*{"lrc",	HB_TAG('L','R','C',' ')},*/	/* Northern Luri -> Luri */
+  {"lri",	HB_TAG('L','U','H',' ')},	/* Marachi -> Luyia */
+  {"lrm",	HB_TAG('L','U','H',' ')},	/* Marama -> Luyia */
+  {"lsm",	HB_TAG('L','U','H',' ')},	/* Saamia -> Luyia */
+  {"lt",	HB_TAG('L','T','H',' ')},	/* Lithuanian */
+  {"ltg",	HB_TAG('L','V','I',' ')},	/* Latgalian -> Latvian */
+  {"lto",	HB_TAG('L','U','H',' ')},	/* Tsotso -> Luyia */
+  {"lts",	HB_TAG('L','U','H',' ')},	/* Tachoni -> Luyia */
+  {"lu",	HB_TAG('L','U','B',' ')},	/* Luba-Katanga */
+/*{"lua",	HB_TAG('L','U','A',' ')},*/	/* Luba-Lulua */
+/*{"luo",	HB_TAG('L','U','O',' ')},*/	/* Luo (Kenya and Tanzania) */
+  {"lus",	HB_TAG('M','I','Z',' ')},	/* Lushai -> Mizo */
+  {"luy",	HB_TAG('L','U','H',' ')},	/* Luyia [macrolanguage] */
+  {"luz",	HB_TAG('L','R','C',' ')},	/* Southern Luri -> Luri */
+  {"lv",	HB_TAG('L','V','I',' ')},	/* Latvian [macrolanguage] */
+  {"lvs",	HB_TAG('L','V','I',' ')},	/* Standard Latvian -> Latvian */
+  {"lwg",	HB_TAG('L','U','H',' ')},	/* Wanga -> Luyia */
+  {"lzh",	HB_TAG('Z','H','T',' ')},	/* Literary Chinese -> Chinese Traditional */
+  {"lzz",	HB_TAG('L','A','Z',' ')},	/* Laz */
+/*{"mad",	HB_TAG('M','A','D',' ')},*/	/* Madurese -> Madura */
+/*{"mag",	HB_TAG('M','A','G',' ')},*/	/* Magahi */
+  {"mai",	HB_TAG('M','T','H',' ')},	/* Maithili */
+  {"mak",	HB_TAG('M','K','R',' ')},	/* Makasar */
+/*{"mam",	HB_TAG('M','A','M',' ')},*/	/* Mam */
+  {"man",	HB_TAG('M','N','K',' ')},	/* Mandingo [macrolanguage] -> Maninka */
+  {"max",	HB_TAG('M','L','Y',' ')},	/* North Moluccan Malay -> Malay */
+/*{"mbo",	HB_TAG('M','B','O',' ')},*/	/* Mbo (Cameroon) */
+  {"mct",	HB_TAG('B','T','I',' ')},	/* Mengisa -> Beti */
+  {"mdf",	HB_TAG('M','O','K',' ')},	/* Moksha */
+/*{"mdr",	HB_TAG('M','D','R',' ')},*/	/* Mandar */
+  {"mdy",	HB_TAG('M','L','E',' ')},	/* Male (Ethiopia) */
+  {"men",	HB_TAG('M','D','E',' ')},	/* Mende (Sierra Leone) */
+  {"meo",	HB_TAG('M','L','Y',' ')},	/* Kedah Malay -> Malay */
+/*{"mer",	HB_TAG('M','E','R',' ')},*/	/* Meru */
+/*{"mfa",	HB_TAG('M','F','A',' ')},*/	/* Pattani Malay */
+  {"mfb",	HB_TAG('M','L','Y',' ')},	/* Bangka -> Malay */
+/*{"mfe",	HB_TAG('M','F','E',' ')},*/	/* Morisyen */
+  {"mg",	HB_TAG('M','L','G',' ')},	/* Malagasy [macrolanguage] */
+  {"mh",	HB_TAG('M','A','H',' ')},	/* Marshallese */
+  {"mhr",	HB_TAG('L','M','A',' ')},	/* Eastern Mari -> Low Mari */
+  {"mhv",	HB_TAG('A','R','K',' ')},	/* Arakanese (retired code) -> Rakhine */
+  {"mi",	HB_TAG('M','R','I',' ')},	/* Maori */
+/*{"min",	HB_TAG('M','I','N',' ')},*/	/* Minangkabau */
+  {"mk",	HB_TAG('M','K','D',' ')},	/* Macedonian */
+  {"mku",	HB_TAG('M','N','K',' ')},	/* Konyanka Maninka -> Maninka */
+/*{"mkw",	HB_TAG('M','K','W',' ')},*/	/* Kituba (Congo) */
+  {"ml",	HB_TAG('M','A','L',' ')},	/* Malayalam -> Malayalam Traditional */
+  {"ml",	HB_TAG('M','L','R',' ')},	/* Malayalam -> Malayalam Reformed */
+  {"mlq",	HB_TAG('M','L','N',' ')},	/* Western Maninkakan -> Malinke */
+  {"mlq",	HB_TAG('M','N','K',' ')},	/* Western Maninkakan -> Maninka */
+  {"mmr",	HB_TAG('H','M','N',' ')},	/* Western Xiangxi Miao -> Hmong */
+  {"mn",	HB_TAG('M','N','G',' ')},	/* Mongolian [macrolanguage] */
+  {"mnc",	HB_TAG('M','C','H',' ')},	/* Manchu */
+/*{"mni",	HB_TAG('M','N','I',' ')},*/	/* Manipuri */
+  {"mnk",	HB_TAG('M','N','D',' ')},	/* Mandinka */
+  {"mnk",	HB_TAG('M','N','K',' ')},	/* Mandinka -> Maninka */
+  {"mnp",	HB_TAG('Z','H','S',' ')},	/* Min Bei Chinese -> Chinese Simplified */
+  {"mns",	HB_TAG('M','A','N',' ')},	/* Mansi */
+  {"mnw",	HB_TAG('M','O','N',' ')},	/* Mon */
+  {"mo",	HB_TAG('M','O','L',' ')},	/* Moldavian (retired code) */
+/*{"moh",	HB_TAG('M','O','H',' ')},*/	/* Mohawk */
+/*{"mos",	HB_TAG('M','O','S',' ')},*/	/* Mossi */
+  {"mpe",	HB_TAG('M','A','J',' ')},	/* Majang */
+  {"mqg",	HB_TAG('M','L','Y',' ')},	/* Kota Bangun Kutai Malay -> Malay */
+  {"mr",	HB_TAG('M','A','R',' ')},	/* Marathi */
+  {"mrh",	HB_TAG('Q','I','N',' ')},	/* Mara Chin -> Chin */
+  {"mrj",	HB_TAG('H','M','A',' ')},	/* Western Mari -> High Mari */
+  {"ms",	HB_TAG('M','L','Y',' ')},	/* Malay [macrolanguage] */
+  {"msc",	HB_TAG('M','N','K',' ')},	/* Sankaran Maninka -> Maninka */
+  {"msh",	HB_TAG('M','L','G',' ')},	/* Masikoro Malagasy -> Malagasy */
+  {"msi",	HB_TAG('M','L','Y',' ')},	/* Sabah Malay -> Malay */
+  {"mt",	HB_TAG('M','T','S',' ')},	/* Maltese */
+  {"mtr",	HB_TAG('M','A','W',' ')},	/* Mewari -> Marwari */
+  {"mui",	HB_TAG('M','L','Y',' ')},	/* Musi -> Malay */
+  {"mup",	HB_TAG('R','A','J',' ')},	/* Malvi -> Rajasthani */
+  {"muq",	HB_TAG('H','M','N',' ')},	/* Eastern Xiangxi Miao -> Hmong */
+/*{"mus",	HB_TAG('M','U','S',' ')},*/	/* Creek -> Muscogee */
+  {"mvb",	HB_TAG('A','T','H',' ')},	/* Mattole -> Athapaskan */
+  {"mve",	HB_TAG('M','A','W',' ')},	/* Marwari (Pakistan) */
+  {"mvf",	HB_TAG('M','N','G',' ')},	/* Peripheral Mongolian -> Mongolian */
+  {"mwk",	HB_TAG('M','N','K',' ')},	/* Kita Maninkakan -> Maninka */
+/*{"mwl",	HB_TAG('M','W','L',' ')},*/	/* Mirandese */
+  {"mwr",	HB_TAG('M','A','W',' ')},	/* Marwari [macrolanguage] */
+/*{"mww",	HB_TAG('M','W','W',' ')},*/	/* Hmong Daw */
+  {"my",	HB_TAG('B','R','M',' ')},	/* Burmese */
+  {"mym",	HB_TAG('M','E','N',' ')},	/* Me’en */
+/*{"myn",	HB_TAG('M','Y','N',' ')},*/	/* Mayan [family] */
+  {"myq",	HB_TAG('M','N','K',' ')},	/* Forest Maninka (retired code) -> Maninka */
+  {"myv",	HB_TAG('E','R','Z',' ')},	/* Erzya */
+/*{"mzn",	HB_TAG('M','Z','N',' ')},*/	/* Mazanderani */
+  {"na",	HB_TAG('N','A','U',' ')},	/* Nauru -> Nauruan */
+/*{"nag",	HB_TAG('N','A','G',' ')},*/	/* Naga Pidgin -> Naga-Assamese */
+/*{"nah",	HB_TAG('N','A','H',' ')},*/	/* Nahuatl [family] */
+  {"nan",	HB_TAG('Z','H','S',' ')},	/* Min Nan Chinese -> Chinese Simplified */
+/*{"nap",	HB_TAG('N','A','P',' ')},*/	/* Neapolitan */
+  {"nb",	HB_TAG('N','O','R',' ')},	/* Norwegian Bokmål -> Norwegian */
+  {"nd",	HB_TAG('N','D','B',' ')},	/* North Ndebele -> Ndebele */
+/*{"ndc",	HB_TAG('N','D','C',' ')},*/	/* Ndau */
+/*{"nds",	HB_TAG('N','D','S',' ')},*/	/* Low Saxon */
+  {"ne",	HB_TAG('N','E','P',' ')},	/* Nepali [macrolanguage] */
+/*{"new",	HB_TAG('N','E','W',' ')},*/	/* Newari */
+  {"ng",	HB_TAG('N','D','G',' ')},	/* Ndonga */
+/*{"nga",	HB_TAG('N','G','A',' ')},*/	/* Ngbaka */
+  {"ngl",	HB_TAG('L','M','W',' ')},	/* Lomwe */
+  {"ngo",	HB_TAG('S','X','T',' ')},	/* Ngoni -> Sutu */
+  {"nhd",	HB_TAG('G','U','A',' ')},	/* Chiripá -> Guarani */
+  {"niq",	HB_TAG('K','A','L',' ')},	/* Nandi -> Kalenjin */
+/*{"niu",	HB_TAG('N','I','U',' ')},*/	/* Niuean */
+  {"niv",	HB_TAG('G','I','L',' ')},	/* Gilyak */
+  {"njz",	HB_TAG('N','I','S',' ')},	/* Nyishi -> Nisi */
+  {"nl",	HB_TAG('N','L','D',' ')},	/* Dutch */
+  {"nle",	HB_TAG('L','U','H',' ')},	/* East Nyala -> Luyia */
+  {"nn",	HB_TAG('N','Y','N',' ')},	/* Norwegian Nynorsk (Nynorsk, Norwegian) */
+  {"no",	HB_TAG('N','O','R',' ')},	/* Norwegian [macrolanguage] */
+  {"nod",	HB_TAG('N','T','A',' ')},	/* Northern Thai -> Northern Tai */
+/*{"noe",	HB_TAG('N','O','E',' ')},*/	/* Nimadi */
+/*{"nog",	HB_TAG('N','O','G',' ')},*/	/* Nogai */
+/*{"nov",	HB_TAG('N','O','V',' ')},*/	/* Novial */
+  {"npi",	HB_TAG('N','E','P',' ')},	/* Nepali */
+  {"nqo",	HB_TAG('N','K','O',' ')},	/* N’Ko */
+  {"nr",	HB_TAG('N','D','B',' ')},	/* South Ndebele -> Ndebele */
+  {"nsk",	HB_TAG('N','A','S',' ')},	/* Naskapi */
+/*{"nso",	HB_TAG('N','S','O',' ')},*/	/* Pedi -> Sotho, Northern */
+  {"nv",	HB_TAG('N','A','V',' ')},	/* Navajo */
+  {"nv",	HB_TAG('A','T','H',' ')},	/* Navajo -> Athapaskan */
+  {"ny",	HB_TAG('C','H','I',' ')},	/* Chichewa (Chewa, Nyanja) */
+  {"nyd",	HB_TAG('L','U','H',' ')},	/* Nyore -> Luyia */
+/*{"nym",	HB_TAG('N','Y','M',' ')},*/	/* Nyamwezi */
+  {"nyn",	HB_TAG('N','K','L',' ')},	/* Nyankole */
+/*{"nza",	HB_TAG('N','Z','A',' ')},*/	/* Tigon Mbembe -> Mbembe Tigon */
+  {"oc",	HB_TAG('O','C','I',' ')},	/* Occitan (post 1500) */
+  {"oj",	HB_TAG('O','J','B',' ')},	/* Ojibwa [macrolanguage] -> Ojibway */
+/*{"ojb",	HB_TAG('O','J','B',' ')},*/	/* Northwestern Ojibwa -> Ojibway */
+  {"ojc",	HB_TAG('O','J','B',' ')},	/* Central Ojibwa -> Ojibway */
+  {"ojg",	HB_TAG('O','J','B',' ')},	/* Eastern Ojibwa -> Ojibway */
+  {"ojs",	HB_TAG('O','C','R',' ')},	/* Severn Ojibwa -> Oji-Cree */
+  {"ojw",	HB_TAG('O','J','B',' ')},	/* Western Ojibwa -> Ojibway */
+  {"oki",	HB_TAG('K','A','L',' ')},	/* Okiek -> Kalenjin */
+  {"okm",	HB_TAG('K','O','H',' ')},	/* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
+  {"om",	HB_TAG('O','R','O',' ')},	/* Oromo [macrolanguage] */
+  {"or",	HB_TAG('O','R','I',' ')},	/* Odia (formerly Oriya) [macrolanguage] */
+  {"orc",	HB_TAG('O','R','O',' ')},	/* Orma -> Oromo */
+  {"orn",	HB_TAG('M','L','Y',' ')},	/* Orang Kanaq -> Malay */
+  {"ors",	HB_TAG('M','L','Y',' ')},	/* Orang Seletar -> Malay */
+  {"ory",	HB_TAG('O','R','I',' ')},	/* Odia (formerly Oriya) */
+  {"os",	HB_TAG('O','S','S',' ')},	/* Ossetian */
+  {"otw",	HB_TAG('O','J','B',' ')},	/* Ottawa -> Ojibway */
+  {"pa",	HB_TAG('P','A','N',' ')},	/* Punjabi */
+/*{"pag",	HB_TAG('P','A','G',' ')},*/	/* Pangasinan */
+/*{"pam",	HB_TAG('P','A','M',' ')},*/	/* Pampanga -> Pampangan */
+  {"pap",	HB_TAG('P','A','P','0')},	/* Papiamento -> Papiamentu */
+/*{"pau",	HB_TAG('P','A','U',' ')},*/	/* Palauan */
+  {"pbt",	HB_TAG('P','A','S',' ')},	/* Southern Pashto -> Pashto */
+  {"pbu",	HB_TAG('P','A','S',' ')},	/* Northern Pashto -> Pashto */
+/*{"pcc",	HB_TAG('P','C','C',' ')},*/	/* Bouyei */
+/*{"pcd",	HB_TAG('P','C','D',' ')},*/	/* Picard */
+  {"pce",	HB_TAG('P','L','G',' ')},	/* Ruching Palaung -> Palaung */
+  {"pck",	HB_TAG('Q','I','N',' ')},	/* Paite Chin -> Chin */
+/*{"pdc",	HB_TAG('P','D','C',' ')},*/	/* Pennsylvania German */
+  {"pel",	HB_TAG('M','L','Y',' ')},	/* Pekal -> Malay */
+  {"pes",	HB_TAG('F','A','R',' ')},	/* Iranian Persian -> Persian */
+  {"pga",	HB_TAG('A','R','A',' ')},	/* Sudanese Creole Arabic -> Arabic */
+/*{"phk",	HB_TAG('P','H','K',' ')},*/	/* Phake */
+  {"pi",	HB_TAG('P','A','L',' ')},	/* Pali */
+/*{"pih",	HB_TAG('P','I','H',' ')},*/	/* Pitcairn-Norfolk -> Norfolk */
+  {"pko",	HB_TAG('K','A','L',' ')},	/* Pökoot -> Kalenjin */
+  {"pl",	HB_TAG('P','L','K',' ')},	/* Polish */
+  {"pll",	HB_TAG('P','L','G',' ')},	/* Shwe Palaung -> Palaung */
+  {"plp",	HB_TAG('P','A','P',' ')},	/* Palpa */
+  {"plt",	HB_TAG('M','L','G',' ')},	/* Plateau Malagasy -> Malagasy */
+/*{"pms",	HB_TAG('P','M','S',' ')},*/	/* Piemontese */
+/*{"pnb",	HB_TAG('P','N','B',' ')},*/	/* Western Panjabi */
+/*{"poh",	HB_TAG('P','O','H',' ')},*/	/* Poqomchi' -> Pocomchi */
+/*{"pon",	HB_TAG('P','O','N',' ')},*/	/* Pohnpeian */
+  {"ppa",	HB_TAG('B','A','G',' ')},	/* Pao (retired code) -> Baghelkhandi */
+/*{"pro",	HB_TAG('P','R','O',' ')},*/	/* Old Provençal (to 1500) -> Provençal / Old Provençal */
+  {"prs",	HB_TAG('D','R','I',' ')},	/* Dari */
+  {"ps",	HB_TAG('P','A','S',' ')},	/* Pashto [macrolanguage] */
+  {"pse",	HB_TAG('M','L','Y',' ')},	/* Central Malay -> Malay */
+  {"pst",	HB_TAG('P','A','S',' ')},	/* Central Pashto -> Pashto */
+  {"pt",	HB_TAG('P','T','G',' ')},	/* Portuguese */
+/*{"pwo",	HB_TAG('P','W','O',' ')},*/	/* Pwo Western Karen -> Western Pwo Karen */
+  {"qu",	HB_TAG('Q','U','Z',' ')},	/* Quechua [macrolanguage] */
+  {"qub",	HB_TAG('Q','W','H',' ')},	/* Huallaga Huánuco Quechua -> Quechua (Peru) */
+/*{"quc",	HB_TAG('Q','U','C',' ')},*/	/* K’iche’ */
+  {"qud",	HB_TAG('Q','V','I',' ')},	/* Calderón Highland Quichua -> Quechua (Ecuador) */
+  {"quf",	HB_TAG('Q','U','Z',' ')},	/* Lambayeque Quechua -> Quechua */
+  {"qug",	HB_TAG('Q','V','I',' ')},	/* Chimborazo Highland Quichua -> Quechua (Ecuador) */
+/*{"quh",	HB_TAG('Q','U','H',' ')},*/	/* South Bolivian Quechua -> Quechua (Bolivia) */
+  {"quk",	HB_TAG('Q','U','Z',' ')},	/* Chachapoyas Quechua -> Quechua */
+  {"qul",	HB_TAG('Q','U','Z',' ')},	/* North Bolivian Quechua -> Quechua */
+  {"qup",	HB_TAG('Q','V','I',' ')},	/* Southern Pastaza Quechua -> Quechua (Ecuador) */
+  {"qur",	HB_TAG('Q','W','H',' ')},	/* Yanahuanca Pasco Quechua -> Quechua (Peru) */
+  {"qus",	HB_TAG('Q','U','H',' ')},	/* Santiago del Estero Quichua -> Quechua (Bolivia) */
+  {"quw",	HB_TAG('Q','V','I',' ')},	/* Tena Lowland Quichua -> Quechua (Ecuador) */
+  {"qux",	HB_TAG('Q','W','H',' ')},	/* Yauyos Quechua -> Quechua (Peru) */
+  {"quy",	HB_TAG('Q','U','Z',' ')},	/* Ayacucho Quechua -> Quechua */
+/*{"quz",	HB_TAG('Q','U','Z',' ')},*/	/* Cusco Quechua -> Quechua */
+  {"qva",	HB_TAG('Q','W','H',' ')},	/* Ambo-Pasco Quechua -> Quechua (Peru) */
+  {"qvc",	HB_TAG('Q','U','Z',' ')},	/* Cajamarca Quechua -> Quechua */
+  {"qve",	HB_TAG('Q','U','Z',' ')},	/* Eastern Apurímac Quechua -> Quechua */
+  {"qvh",	HB_TAG('Q','W','H',' ')},	/* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
+/*{"qvi",	HB_TAG('Q','V','I',' ')},*/	/* Imbabura Highland Quichua -> Quechua (Ecuador) */
+  {"qvj",	HB_TAG('Q','V','I',' ')},	/* Loja Highland Quichua -> Quechua (Ecuador) */
+  {"qvl",	HB_TAG('Q','W','H',' ')},	/* Cajatambo North Lima Quechua -> Quechua (Peru) */
+  {"qvm",	HB_TAG('Q','W','H',' ')},	/* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
+  {"qvn",	HB_TAG('Q','W','H',' ')},	/* North Junín Quechua -> Quechua (Peru) */
+  {"qvo",	HB_TAG('Q','V','I',' ')},	/* Napo Lowland Quechua -> Quechua (Ecuador) */
+  {"qvp",	HB_TAG('Q','W','H',' ')},	/* Pacaraos Quechua -> Quechua (Peru) */
+  {"qvs",	HB_TAG('Q','U','Z',' ')},	/* San Martín Quechua -> Quechua */
+  {"qvw",	HB_TAG('Q','W','H',' ')},	/* Huaylla Wanca Quechua -> Quechua (Peru) */
+  {"qvz",	HB_TAG('Q','V','I',' ')},	/* Northern Pastaza Quichua -> Quechua (Ecuador) */
+  {"qwa",	HB_TAG('Q','W','H',' ')},	/* Corongo Ancash Quechua -> Quechua (Peru) */
+  {"qwc",	HB_TAG('Q','U','Z',' ')},	/* Classical Quechua -> Quechua */
+/*{"qwh",	HB_TAG('Q','W','H',' ')},*/	/* Huaylas Ancash Quechua -> Quechua (Peru) */
+  {"qws",	HB_TAG('Q','W','H',' ')},	/* Sihuas Ancash Quechua -> Quechua (Peru) */
+  {"qxa",	HB_TAG('Q','W','H',' ')},	/* Chiquián Ancash Quechua -> Quechua (Peru) */
+  {"qxc",	HB_TAG('Q','W','H',' ')},	/* Chincha Quechua -> Quechua (Peru) */
+  {"qxh",	HB_TAG('Q','W','H',' ')},	/* Panao Huánuco Quechua -> Quechua (Peru) */
+  {"qxl",	HB_TAG('Q','V','I',' ')},	/* Salasaca Highland Quichua -> Quechua (Ecuador) */
+  {"qxn",	HB_TAG('Q','W','H',' ')},	/* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {"qxo",	HB_TAG('Q','W','H',' ')},	/* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {"qxp",	HB_TAG('Q','U','Z',' ')},	/* Puno Quechua -> Quechua */
+  {"qxr",	HB_TAG('Q','V','I',' ')},	/* Cañar Highland Quichua -> Quechua (Ecuador) */
+  {"qxt",	HB_TAG('Q','W','H',' ')},	/* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
+  {"qxu",	HB_TAG('Q','U','Z',' ')},	/* Arequipa-La Unión Quechua -> Quechua */
+  {"qxw",	HB_TAG('Q','W','H',' ')},	/* Jauja Wanca Quechua -> Quechua (Peru) */
+  {"rag",	HB_TAG('L','U','H',' ')},	/* Logooli -> Luyia */
+/*{"raj",	HB_TAG('R','A','J',' ')},*/	/* Rajasthani [macrolanguage] */
+/*{"rar",	HB_TAG('R','A','R',' ')},*/	/* Rarotongan */
+  {"rbb",	HB_TAG('P','L','G',' ')},	/* Rumai Palaung -> Palaung */
+  {"rbl",	HB_TAG('B','I','K',' ')},	/* Miraya Bikol -> Bikol */
+/*{"rej",	HB_TAG('R','E','J',' ')},*/	/* Rejang */
+/*{"ria",	HB_TAG('R','I','A',' ')},*/	/* Riang (India) */
+/*{"rif",	HB_TAG('R','I','F',' ')},*/	/* Tarifit */
+/*{"rit",	HB_TAG('R','I','T',' ')},*/	/* Ritarungo */
+  {"rki",	HB_TAG('A','R','K',' ')},	/* Rakhine */
+/*{"rkw",	HB_TAG('R','K','W',' ')},*/	/* Arakwal */
+  {"rm",	HB_TAG('R','M','S',' ')},	/* Romansh */
+  {"rmc",	HB_TAG('R','O','Y',' ')},	/* Carpathian Romani -> Romany */
+  {"rmf",	HB_TAG('R','O','Y',' ')},	/* Kalo Finnish Romani -> Romany */
+  {"rml",	HB_TAG('R','O','Y',' ')},	/* Baltic Romani -> Romany */
+  {"rmn",	HB_TAG('R','O','Y',' ')},	/* Balkan Romani -> Romany */
+  {"rmo",	HB_TAG('R','O','Y',' ')},	/* Sinte Romani -> Romany */
+  {"rmw",	HB_TAG('R','O','Y',' ')},	/* Welsh Romani -> Romany */
+/*{"rmy",	HB_TAG('R','M','Y',' ')},*/	/* Vlax Romani */
+  {"rmz",	HB_TAG('A','R','K',' ')},	/* Marma -> Rakhine */
+  {"rn",	HB_TAG('R','U','N',' ')},	/* Rundi */
+  {"rnl",	HB_TAG('H','A','L',' ')},	/* Ranglong -> Halam (Falam Chin) */
+  {"ro",	HB_TAG('R','O','M',' ')},	/* Romanian */
+  {"rom",	HB_TAG('R','O','Y',' ')},	/* Romany [macrolanguage] */
+/*{"rtm",	HB_TAG('R','T','M',' ')},*/	/* Rotuman */
+  {"ru",	HB_TAG('R','U','S',' ')},	/* Russian */
+  {"rue",	HB_TAG('R','S','Y',' ')},	/* Rusyn */
+/*{"rup",	HB_TAG('R','U','P',' ')},*/	/* Aromanian */
+  {"rw",	HB_TAG('R','U','A',' ')},	/* Kinyarwanda */
+  {"rwr",	HB_TAG('M','A','W',' ')},	/* Marwari (India) */
+  {"sa",	HB_TAG('S','A','N',' ')},	/* Sanskrit */
+  {"sah",	HB_TAG('Y','A','K',' ')},	/* Yakut -> Sakha */
+  {"sam",	HB_TAG('P','A','A',' ')},	/* Samaritan Aramaic -> Palestinian Aramaic */
+/*{"sas",	HB_TAG('S','A','S',' ')},*/	/* Sasak */
+/*{"sat",	HB_TAG('S','A','T',' ')},*/	/* Santali */
+  {"sc",	HB_TAG('S','R','D',' ')},	/* Sardinian [macrolanguage] */
+  {"sck",	HB_TAG('S','A','D',' ')},	/* Sadri */
+/*{"scn",	HB_TAG('S','C','N',' ')},*/	/* Sicilian */
+/*{"sco",	HB_TAG('S','C','O',' ')},*/	/* Scots */
+  {"scs",	HB_TAG('S','C','S',' ')},	/* North Slavey */
+  {"scs",	HB_TAG('S','L','A',' ')},	/* North Slavey -> Slavey */
+  {"scs",	HB_TAG('A','T','H',' ')},	/* North Slavey -> Athapaskan */
+  {"sd",	HB_TAG('S','N','D',' ')},	/* Sindhi */
+  {"sdc",	HB_TAG('S','R','D',' ')},	/* Sassarese Sardinian -> Sardinian */
+  {"sdh",	HB_TAG('K','U','R',' ')},	/* Southern Kurdish -> Kurdish */
+  {"sdn",	HB_TAG('S','R','D',' ')},	/* Gallurese Sardinian -> Sardinian */
+  {"se",	HB_TAG('N','S','M',' ')},	/* Northern Sami */
+  {"seh",	HB_TAG('S','N','A',' ')},	/* Sena */
+  {"sek",	HB_TAG('A','T','H',' ')},	/* Sekani -> Athapaskan */
+/*{"sel",	HB_TAG('S','E','L',' ')},*/	/* Selkup */
+  {"sez",	HB_TAG('Q','I','N',' ')},	/* Senthang Chin -> Chin */
+  {"sfm",	HB_TAG('H','M','N',' ')},	/* Small Flowery Miao -> Hmong */
+  {"sg",	HB_TAG('S','G','O',' ')},	/* Sango */
+/*{"sga",	HB_TAG('S','G','A',' ')},*/	/* Old Irish (to 900) */
+  {"sgc",	HB_TAG('K','A','L',' ')},	/* Kipsigis -> Kalenjin */
+/*{"sgs",	HB_TAG('S','G','S',' ')},*/	/* Samogitian */
+  {"sgw",	HB_TAG('C','H','G',' ')},	/* Sebat Bet Gurage -> Chaha Gurage */
+  {"sgw",	HB_TAG('S','G','W',' ')},	/* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
+/*{"shi",	HB_TAG('S','H','I',' ')},*/	/* Tachelhit */
+/*{"shn",	HB_TAG('S','H','N',' ')},*/	/* Shan */
+  {"shu",	HB_TAG('A','R','A',' ')},	/* Chadian Arabic -> Arabic */
+  {"si",	HB_TAG('S','N','H',' ')},	/* Sinhala (Sinhalese) */
+/*{"sid",	HB_TAG('S','I','D',' ')},*/	/* Sidamo */
+  {"sjd",	HB_TAG('K','S','M',' ')},	/* Kildin Sami */
+  {"sjo",	HB_TAG('S','I','B',' ')},	/* Xibe -> Sibe */
+  {"sk",	HB_TAG('S','K','Y',' ')},	/* Slovak */
+  {"skg",	HB_TAG('M','L','G',' ')},	/* Sakalava Malagasy -> Malagasy */
+  {"skr",	HB_TAG('S','R','K',' ')},	/* Saraiki */
+  {"sl",	HB_TAG('S','L','V',' ')},	/* Slovenian */
+  {"sm",	HB_TAG('S','M','O',' ')},	/* Samoan */
+  {"sma",	HB_TAG('S','S','M',' ')},	/* Southern Sami */
+  {"smj",	HB_TAG('L','S','M',' ')},	/* Lule Sami */
+  {"smn",	HB_TAG('I','S','M',' ')},	/* Inari Sami */
+  {"sms",	HB_TAG('S','K','S',' ')},	/* Skolt Sami */
+  {"sn",	HB_TAG('S','N','A','0')},	/* Shona */
+/*{"snk",	HB_TAG('S','N','K',' ')},*/	/* Soninke */
+  {"so",	HB_TAG('S','M','L',' ')},	/* Somali */
+/*{"sop",	HB_TAG('S','O','P',' ')},*/	/* Songe */
+  {"spv",	HB_TAG('O','R','I',' ')},	/* Sambalpuri -> Odia (formerly Oriya) */
+  {"spy",	HB_TAG('K','A','L',' ')},	/* Sabaot -> Kalenjin */
+  {"sq",	HB_TAG('S','Q','I',' ')},	/* Albanian [macrolanguage] */
+  {"sr",	HB_TAG('S','R','B',' ')},	/* Serbian */
+  {"src",	HB_TAG('S','R','D',' ')},	/* Logudorese Sardinian -> Sardinian */
+  {"sro",	HB_TAG('S','R','D',' ')},	/* Campidanese Sardinian -> Sardinian */
+/*{"srr",	HB_TAG('S','R','R',' ')},*/	/* Serer */
+  {"srs",	HB_TAG('A','T','H',' ')},	/* Sarsi -> Athapaskan */
+  {"ss",	HB_TAG('S','W','Z',' ')},	/* Swati */
+  {"ssh",	HB_TAG('A','R','A',' ')},	/* Shihhi Arabic -> Arabic */
+  {"st",	HB_TAG('S','O','T',' ')},	/* Southern Sotho -> Sotho, Southern */
+/*{"stq",	HB_TAG('S','T','Q',' ')},*/	/* Saterfriesisch -> Saterland Frisian */
+  {"stv",	HB_TAG('S','I','G',' ')},	/* Silt'e -> Silte Gurage */
+  {"su",	HB_TAG('S','U','N',' ')},	/* Sundanese */
+/*{"suk",	HB_TAG('S','U','K',' ')},*/	/* Sukuma */
+  {"suq",	HB_TAG('S','U','R',' ')},	/* Suri */
+  {"sv",	HB_TAG('S','V','E',' ')},	/* Swedish */
+/*{"sva",	HB_TAG('S','V','A',' ')},*/	/* Svan */
+  {"sw",	HB_TAG('S','W','K',' ')},	/* Swahili [macrolanguage] */
+  {"swb",	HB_TAG('C','M','R',' ')},	/* Maore Comorian -> Comorian */
+  {"swc",	HB_TAG('S','W','K',' ')},	/* Congo Swahili -> Swahili */
+  {"swh",	HB_TAG('S','W','K',' ')},	/* Swahili */
+  {"swv",	HB_TAG('M','A','W',' ')},	/* Shekhawati -> Marwari */
+/*{"sxu",	HB_TAG('S','X','U',' ')},*/	/* Upper Saxon */
+  {"syc",	HB_TAG('S','Y','R',' ')},	/* Classical Syriac -> Syriac */
+/*{"syl",	HB_TAG('S','Y','L',' ')},*/	/* Sylheti */
+/*{"syr",	HB_TAG('S','Y','R',' ')},*/	/* Syriac [macrolanguage] */
+/*{"szl",	HB_TAG('S','Z','L',' ')},*/	/* Silesian */
+  {"ta",	HB_TAG('T','A','M',' ')},	/* Tamil */
+  {"taa",	HB_TAG('A','T','H',' ')},	/* Lower Tanana -> Athapaskan */
+/*{"tab",	HB_TAG('T','A','B',' ')},*/	/* Tabassaran -> Tabasaran */
+  {"taq",	HB_TAG('T','M','H',' ')},	/* Tamasheq -> Tamashek */
+  {"tau",	HB_TAG('A','T','H',' ')},	/* Upper Tanana -> Athapaskan */
+  {"tcb",	HB_TAG('A','T','H',' ')},	/* Tanacross -> Athapaskan */
+  {"tce",	HB_TAG('A','T','H',' ')},	/* Southern Tutchone -> Athapaskan */
+  {"tcp",	HB_TAG('Q','I','N',' ')},	/* Tawr Chin -> Chin */
+  {"tcy",	HB_TAG('T','U','L',' ')},	/* Tulu -> Tumbuka */
+  {"tcz",	HB_TAG('Q','I','N',' ')},	/* Thado Chin -> Chin */
+/*{"tdd",	HB_TAG('T','D','D',' ')},*/	/* Tai Nüa -> Dehong Dai */
+  {"tdx",	HB_TAG('M','L','G',' ')},	/* Tandroy-Mahafaly Malagasy -> Malagasy */
+  {"te",	HB_TAG('T','E','L',' ')},	/* Telugu */
+  {"tec",	HB_TAG('K','A','L',' ')},	/* Terik -> Kalenjin */
+  {"tem",	HB_TAG('T','M','N',' ')},	/* Timne -> Temne */
+/*{"tet",	HB_TAG('T','E','T',' ')},*/	/* Tetum */
+  {"tfn",	HB_TAG('A','T','H',' ')},	/* Tanaina -> Athapaskan */
+  {"tg",	HB_TAG('T','A','J',' ')},	/* Tajik -> Tajiki */
+  {"tgj",	HB_TAG('N','I','S',' ')},	/* Tagin -> Nisi */
+  {"tgx",	HB_TAG('A','T','H',' ')},	/* Tagish -> Athapaskan */
+  {"th",	HB_TAG('T','H','A',' ')},	/* Thai */
+  {"tht",	HB_TAG('A','T','H',' ')},	/* Tahltan -> Athapaskan */
+  {"thv",	HB_TAG('T','M','H',' ')},	/* Tahaggart Tamahaq -> Tamashek */
+  {"thz",	HB_TAG('T','M','H',' ')},	/* Tayart Tamajeq -> Tamashek */
+  {"ti",	HB_TAG('T','G','Y',' ')},	/* Tigrinya */
+  {"tig",	HB_TAG('T','G','R',' ')},	/* Tigre */
+/*{"tiv",	HB_TAG('T','I','V',' ')},*/	/* Tiv */
+  {"tk",	HB_TAG('T','K','M',' ')},	/* Turkmen */
+  {"tkg",	HB_TAG('M','L','G',' ')},	/* Tesaka Malagasy -> Malagasy */
+  {"tl",	HB_TAG('T','G','L',' ')},	/* Tagalog */
+/*{"tmh",	HB_TAG('T','M','H',' ')},*/	/* Tamashek [macrolanguage] */
+  {"tmw",	HB_TAG('M','L','Y',' ')},	/* Temuan -> Malay */
+  {"tn",	HB_TAG('T','N','A',' ')},	/* Tswana */
+  {"tnf",	HB_TAG('D','R','I',' ')},	/* Tangshewi (retired code) -> Dari */
+  {"to",	HB_TAG('T','G','N',' ')},	/* Tonga (Tonga Islands) -> Tongan */
+  {"tod",	HB_TAG('T','O','D','0')},	/* Toma */
+  {"toi",	HB_TAG('T','N','G',' ')},	/* Tonga (Zambia) */
+  {"tol",	HB_TAG('A','T','H',' ')},	/* Tolowa -> Athapaskan */
+/*{"tpi",	HB_TAG('T','P','I',' ')},*/	/* Tok Pisin */
+  {"tr",	HB_TAG('T','R','K',' ')},	/* Turkish */
+  {"tru",	HB_TAG('T','U','A',' ')},	/* Turoyo -> Turoyo Aramaic */
+  {"tru",	HB_TAG('S','Y','R',' ')},	/* Turoyo -> Syriac */
+  {"ts",	HB_TAG('T','S','G',' ')},	/* Tsonga */
+/*{"tsj",	HB_TAG('T','S','J',' ')},*/	/* Tshangla */
+  {"tt",	HB_TAG('T','A','T',' ')},	/* Tatar */
+  {"ttm",	HB_TAG('A','T','H',' ')},	/* Northern Tutchone -> Athapaskan */
+  {"ttq",	HB_TAG('T','M','H',' ')},	/* Tawallammat Tamajaq -> Tamashek */
+/*{"tum",	HB_TAG('T','U','M',' ')},*/	/* Tumbuka -> Tulu */
+  {"tuu",	HB_TAG('A','T','H',' ')},	/* Tututni -> Athapaskan */
+  {"tuy",	HB_TAG('K','A','L',' ')},	/* Tugen -> Kalenjin */
+/*{"tvl",	HB_TAG('T','V','L',' ')},*/	/* Tuvalu */
+  {"tw",	HB_TAG('T','W','I',' ')},	/* Twi */
+  {"tw",	HB_TAG('A','K','A',' ')},	/* Twi -> Akan */
+  {"txc",	HB_TAG('A','T','H',' ')},	/* Tsetsaut -> Athapaskan */
+  {"txy",	HB_TAG('M','L','G',' ')},	/* Tanosy Malagasy -> Malagasy */
+  {"ty",	HB_TAG('T','H','T',' ')},	/* Tahitian */
+  {"tyv",	HB_TAG('T','U','V',' ')},	/* Tuvinian -> Tuvin */
+/*{"tyz",	HB_TAG('T','Y','Z',' ')},*/	/* Tày */
+/*{"tzm",	HB_TAG('T','Z','M',' ')},*/	/* Central Atlas Tamazight -> Tamazight */
+/*{"tzo",	HB_TAG('T','Z','O',' ')},*/	/* Tzotzil */
+  {"ubl",	HB_TAG('B','I','K',' ')},	/* Buhi'non Bikol -> Bikol */
+/*{"udm",	HB_TAG('U','D','M',' ')},*/	/* Udmurt */
+  {"ug",	HB_TAG('U','Y','G',' ')},	/* Uyghur */
+  {"uk",	HB_TAG('U','K','R',' ')},	/* Ukrainian */
+/*{"umb",	HB_TAG('U','M','B',' ')},*/	/* Umbundu */
+  {"unr",	HB_TAG('M','U','N',' ')},	/* Mundari */
+  {"ur",	HB_TAG('U','R','D',' ')},	/* Urdu */
+  {"urk",	HB_TAG('M','L','Y',' ')},	/* Urak Lawoi' -> Malay */
+  {"uz",	HB_TAG('U','Z','B',' ')},	/* Uzbek [macrolanguage] */
+  {"uzn",	HB_TAG('U','Z','B',' ')},	/* Northern Uzbek -> Uzbek */
+  {"uzs",	HB_TAG('U','Z','B',' ')},	/* Southern Uzbek -> Uzbek */
+  {"ve",	HB_TAG('V','E','N',' ')},	/* Venda */
+/*{"vec",	HB_TAG('V','E','C',' ')},*/	/* Venetian */
+  {"vi",	HB_TAG('V','I','T',' ')},	/* Vietnamese */
+  {"vkk",	HB_TAG('M','L','Y',' ')},	/* Kaur -> Malay */
+  {"vkt",	HB_TAG('M','L','Y',' ')},	/* Tenggarong Kutai Malay -> Malay */
+  {"vls",	HB_TAG('F','L','E',' ')},	/* Vlaams -> Dutch (Flemish) */
+  {"vmw",	HB_TAG('M','A','K',' ')},	/* Makhuwa */
+  {"vo",	HB_TAG('V','O','L',' ')},	/* Volapük */
+/*{"vro",	HB_TAG('V','R','O',' ')},*/	/* Võro */
+  {"wa",	HB_TAG('W','L','N',' ')},	/* Walloon */
+/*{"war",	HB_TAG('W','A','R',' ')},*/	/* Waray (Philippines) -> Waray-Waray */
+  {"wbm",	HB_TAG('W','A',' ',' ')},	/* Wa */
+  {"wbr",	HB_TAG('W','A','G',' ')},	/* Wagdi */
+  {"wlc",	HB_TAG('C','M','R',' ')},	/* Mwali Comorian -> Comorian */
+  {"wle",	HB_TAG('S','I','G',' ')},	/* Wolane -> Silte Gurage */
+  {"wlk",	HB_TAG('A','T','H',' ')},	/* Wailaki -> Athapaskan */
+  {"wni",	HB_TAG('C','M','R',' ')},	/* Ndzwani Comorian -> Comorian */
+  {"wo",	HB_TAG('W','L','F',' ')},	/* Wolof */
+  {"wry",	HB_TAG('M','A','W',' ')},	/* Merwari -> Marwari */
+  {"wsg",	HB_TAG('G','O','N',' ')},	/* Adilabad Gondi -> Gondi */
+/*{"wtm",	HB_TAG('W','T','M',' ')},*/	/* Mewati */
+  {"wuu",	HB_TAG('Z','H','S',' ')},	/* Wu Chinese -> Chinese Simplified */
+  {"xal",	HB_TAG('K','L','M',' ')},	/* Kalmyk */
+  {"xal",	HB_TAG('T','O','D',' ')},	/* Kalmyk -> Todo */
+  {"xan",	HB_TAG('S','E','K',' ')},	/* Xamtanga -> Sekota */
+  {"xh",	HB_TAG('X','H','S',' ')},	/* Xhosa */
+/*{"xjb",	HB_TAG('X','J','B',' ')},*/	/* Minjungbal -> Minjangbal */
+/*{"xkf",	HB_TAG('X','K','F',' ')},*/	/* Khengkha */
+  {"xmm",	HB_TAG('M','L','Y',' ')},	/* Manado Malay -> Malay */
+  {"xmv",	HB_TAG('M','L','G',' ')},	/* Antankarana Malagasy -> Malagasy */
+  {"xmw",	HB_TAG('M','L','G',' ')},	/* Tsimihety Malagasy -> Malagasy */
+  {"xnr",	HB_TAG('D','G','R',' ')},	/* Kangri -> Dogri */
+/*{"xog",	HB_TAG('X','O','G',' ')},*/	/* Soga */
+/*{"xpe",	HB_TAG('X','P','E',' ')},*/	/* Liberia Kpelle -> Kpelle (Liberia) */
+  {"xsl",	HB_TAG('S','S','L',' ')},	/* South Slavey */
+  {"xsl",	HB_TAG('S','L','A',' ')},	/* South Slavey -> Slavey */
+  {"xsl",	HB_TAG('A','T','H',' ')},	/* South Slavey -> Athapaskan */
+  {"xst",	HB_TAG('S','I','G',' ')},	/* Silt'e (retired code) -> Silte Gurage */
+  {"xwo",	HB_TAG('T','O','D',' ')},	/* Written Oirat -> Todo */
+/*{"yao",	HB_TAG('Y','A','O',' ')},*/	/* Yao */
+/*{"yap",	HB_TAG('Y','A','P',' ')},*/	/* Yapese */
+  {"ybd",	HB_TAG('A','R','K',' ')},	/* Yangbye (retired code) -> Rakhine */
+  {"ydd",	HB_TAG('J','I','I',' ')},	/* Eastern Yiddish -> Yiddish */
+  {"yi",	HB_TAG('J','I','I',' ')},	/* Yiddish [macrolanguage] */
+  {"yih",	HB_TAG('J','I','I',' ')},	/* Western Yiddish -> Yiddish */
+  {"yo",	HB_TAG('Y','B','A',' ')},	/* Yoruba */
+  {"yos",	HB_TAG('Q','I','N',' ')},	/* Yos (retired code) -> Chin */
+  {"yrk",	HB_TAG('T','N','E',' ')},	/* Nenets -> Tundra Nenets */
+  {"yrk",	HB_TAG('F','N','E',' ')},	/* Nenets -> Forest Nenets */
+  {"yue",	HB_TAG('Z','H','H',' ')},	/* Yue Chinese -> Chinese, Hong Kong SAR */
+  {"za",	HB_TAG('Z','H','A',' ')},	/* Zhuang [macrolanguage] */
+  {"zch",	HB_TAG('Z','H','A',' ')},	/* Central Hongshuihe Zhuang -> Zhuang */
+  {"zdj",	HB_TAG('C','M','R',' ')},	/* Ngazidja Comorian -> Comorian */
+/*{"zea",	HB_TAG('Z','E','A',' ')},*/	/* Zeeuws -> Zealandic */
+  {"zeh",	HB_TAG('Z','H','A',' ')},	/* Eastern Hongshuihe Zhuang -> Zhuang */
+  {"zgb",	HB_TAG('Z','H','A',' ')},	/* Guibei Zhuang -> Zhuang */
+/*{"zgh",	HB_TAG('Z','G','H',' ')},*/	/* Standard Moroccan Tamazight */
+  {"zgm",	HB_TAG('Z','H','A',' ')},	/* Minz Zhuang -> Zhuang */
+  {"zgn",	HB_TAG('Z','H','A',' ')},	/* Guibian Zhuang -> Zhuang */
+  {"zh",	HB_TAG('Z','H','S',' ')},	/* Chinese [macrolanguage] -> Chinese Simplified */
+  {"zhd",	HB_TAG('Z','H','A',' ')},	/* Dai Zhuang -> Zhuang */
+  {"zhn",	HB_TAG('Z','H','A',' ')},	/* Nong Zhuang -> Zhuang */
+  {"zlj",	HB_TAG('Z','H','A',' ')},	/* Liujiang Zhuang -> Zhuang */
+  {"zlm",	HB_TAG('M','L','Y',' ')},	/* Malay */
+  {"zln",	HB_TAG('Z','H','A',' ')},	/* Lianshan Zhuang -> Zhuang */
+  {"zlq",	HB_TAG('Z','H','A',' ')},	/* Liuqian Zhuang -> Zhuang */
+  {"zmi",	HB_TAG('M','L','Y',' ')},	/* Negeri Sembilan Malay -> Malay */
+  {"zne",	HB_TAG('Z','N','D',' ')},	/* Zande */
+  {"zom",	HB_TAG('Q','I','N',' ')},	/* Zou -> Chin */
+  {"zqe",	HB_TAG('Z','H','A',' ')},	/* Qiubei Zhuang -> Zhuang */
+  {"zsm",	HB_TAG('M','L','Y',' ')},	/* Standard Malay -> Malay */
+  {"zu",	HB_TAG('Z','U','L',' ')},	/* Zulu */
+  {"zum",	HB_TAG('L','R','C',' ')},	/* Kumzari -> Luri */
+  {"zyb",	HB_TAG('Z','H','A',' ')},	/* Yongbei Zhuang -> Zhuang */
+  {"zyg",	HB_TAG('Z','H','A',' ')},	/* Yang Zhuang -> Zhuang */
+  {"zyj",	HB_TAG('Z','H','A',' ')},	/* Youjiang Zhuang -> Zhuang */
+  {"zyn",	HB_TAG('Z','H','A',' ')},	/* Yongnan Zhuang -> Zhuang */
+/*{"zza",	HB_TAG('Z','Z','A',' ')},*/	/* Zazaki [macrolanguage] */
+  {"zzj",	HB_TAG('Z','H','A',' ')},	/* Zuojiang Zhuang -> Zhuang */
 };
 
-static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, "");
-
 /**
  * hb_ot_tags_from_complex_language:
  * @lang_str: a BCP 47 language tag to convert.
@@ -1934,7 +1932,8 @@
  *
  * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
  * many language tags) and the best tag is not the alphabetically first, or if
- * the best tag consists of multiple subtags.
+ * the best tag consists of multiple subtags, or if the best tag does not appear
+ * in #ot_languages.
  *
  * Return value: The #hb_language_t corresponding to the BCP 47 language tag,
  * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
@@ -1944,6 +1943,8 @@
 {
   switch (tag)
   {
+  case HB_TAG('A','L','T',' '):  /* Altai */
+    return hb_language_from_string ("alt", -1);  /* Southern Altai */
   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
     return hb_language_from_string ("und-fonnapa", -1);  /* Undetermined; North American Phonetic Alphabet */
   case HB_TAG('A','R','A',' '):  /* Arabic */
@@ -1962,8 +1963,6 @@
     return hb_language_from_string ("din", -1);  /* Dinka */
   case HB_TAG('D','R','I',' '):  /* Dari */
     return hb_language_from_string ("prs", -1);  /* Dari */
-  case HB_TAG('D','U','J',' '):  /* Dhuwal */
-    return hb_language_from_string ("dwu", -1);  /* Dhuwal */
   case HB_TAG('D','Z','N',' '):  /* Dzongkha */
     return hb_language_from_string ("dz", -1);  /* Dzongkha */
   case HB_TAG('E','T','I',' '):  /* Estonian */
@@ -1972,6 +1971,8 @@
     return hb_language_from_string ("gon", -1);  /* Gondi */
   case HB_TAG('H','M','N',' '):  /* Hmong */
     return hb_language_from_string ("hmn", -1);  /* Hmong */
+  case HB_TAG('H','N','D',' '):  /* Hindko */
+    return hb_language_from_string ("hnd", -1);  /* Southern Hindko */
   case HB_TAG('I','J','O',' '):  /* Ijo */
     return hb_language_from_string ("ijo", -1);  /* Ijo */
   case HB_TAG('I','N','U',' '):  /* Inuktitut */
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index d04e532..8ad917a 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -28,6 +28,8 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_OT_TAG
+
 
 /* hb_script_t */
 
@@ -113,6 +115,7 @@
   return HB_SCRIPT_UNKNOWN;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 void
 hb_ot_tags_from_script (hb_script_t  script,
 			hb_tag_t    *script_tag_1,
@@ -124,6 +127,7 @@
   *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT;
   *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT;
 }
+#endif
 
 /*
  * Complete list at:
@@ -143,7 +147,9 @@
   hb_tag_t new_tag = hb_ot_new_tag_from_script (script);
   if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT))
   {
-    tags[i++] = new_tag | '3';
+    /* HB_SCRIPT_MYANMAR maps to 'mym2', but there is no 'mym3'. */
+    if (new_tag != HB_TAG('m','y','m','2'))
+      tags[i++] = new_tag | '3';
     if (*count > i)
       tags[i++] = new_tag;
   }
@@ -171,24 +177,6 @@
 
 /* hb_language_t */
 
-static int
-lang_compare_first_component (const void *pa,
-			      const void *pb)
-{
-  const char *a = (const char *) pa;
-  const char *b = (const char *) pb;
-  unsigned int da, db;
-  const char *p;
-
-  p = strchr (a, '-');
-  da = p ? (unsigned int) (p - a) : strlen (a);
-
-  p = strchr (b, '-');
-  db = p ? (unsigned int) (p - b) : strlen (b);
-
-  return strncmp (a, b, MAX (da, db));
-}
-
 static bool
 subtag_matches (const char *lang_str,
 		const char *limit,
@@ -213,10 +201,28 @@
 	 (lang_str[len] == '\0' || lang_str[len] == '-');
 }
 
-typedef struct {
+struct LangTag
+{
   char language[4];
-  hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
-} LangTag;
+  hb_tag_t tag;
+
+  int cmp (const char *a) const
+  {
+    const char *b = this->language;
+    unsigned int da, db;
+    const char *p;
+
+    p = strchr (a, '-');
+    da = p ? (unsigned int) (p - a) : strlen (a);
+
+    p = strchr (b, '-');
+    db = p ? (unsigned int) (p - b) : strlen (b);
+
+    return strncmp (a, b, hb_max (da, db));
+  }
+  int cmp (const LangTag *that) const
+  { return cmp (that->language); }
+};
 
 #include "hb-ot-tag-table.hh"
 
@@ -230,6 +236,7 @@
 /*{"??",	{HB_TAG('Y','I','C',' ')}},*/	/* Yi Classic */
 /*{"zh?",	{HB_TAG('Z','H','P',' ')}},*/	/* Chinese Phonetic */
 
+#ifndef HB_DISABLE_DEPRECATED
 hb_tag_t
 hb_ot_tag_from_language (hb_language_t language)
 {
@@ -238,6 +245,7 @@
   hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags);
   return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE;
 }
+#endif
 
 static void
 hb_ot_tags_from_language (const char   *lang_str,
@@ -246,6 +254,7 @@
 			  hb_tag_t     *tags)
 {
   const char *s;
+  unsigned int tag_idx;
 
   /* Check for matches of multiple subtags. */
   if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags))
@@ -254,7 +263,6 @@
   /* Find a language matching in the first component. */
   s = strchr (lang_str, '-');
   {
-    const LangTag *lang_tag;
     if (s && limit - lang_str >= 6)
     {
       const char *extlang_end = strchr (s + 1, '-');
@@ -263,14 +271,18 @@
 	  ISALPHA (s[1]))
 	lang_str = s + 1;
     }
-    lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
-				    ARRAY_LENGTH (ot_languages), sizeof (LangTag),
-				    lang_compare_first_component);
-    if (lang_tag)
+    if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx))
     {
       unsigned int i;
-      for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++)
-	tags[i] = lang_tag->tags[i];
+      while (tag_idx != 0 &&
+	     0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language))
+	tag_idx--;
+      for (i = 0;
+	   i < *count &&
+	   tag_idx + i < ARRAY_LENGTH (ot_languages) &&
+	   0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language);
+	   i++)
+	tags[i] = ot_languages[tag_idx + i].tag;
       *count = i;
       return;
     }
@@ -295,28 +307,28 @@
 			  const char     *prefix,
 			  unsigned char (*normalize) (unsigned char))
 {
-  if (private_use_subtag && count && tags && *count)
-  {
-    const char *s = strstr (private_use_subtag, prefix);
-    if (s)
-    {
-      char tag[4];
-      int i;
-      s += strlen (prefix);
-      for (i = 0; i < 4 && ISALNUM (s[i]); i++)
-	tag[i] = normalize (s[i]);
-      if (i)
-      {
-	for (; i < 4; i++)
-	  tag[i] = ' ';
-	tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
-	if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
-	  tags[0] ^= ~0xDFDFDFDF;
-	*count = 1;
-	return false;
-      }
-    }
-  }
+#ifdef HB_NO_LANGUAGE_PRIVATE_SUBTAG
+  return false;
+#endif
+
+  if (!(private_use_subtag && count && tags && *count)) return false;
+
+  const char *s = strstr (private_use_subtag, prefix);
+  if (!s) return false;
+
+  char tag[4];
+  int i;
+  s += strlen (prefix);
+  for (i = 0; i < 4 && ISALNUM (s[i]); i++)
+    tag[i] = normalize (s[i]);
+  if (!i) return false;
+
+  for (; i < 4; i++)
+    tag[i] = ' ';
+  tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
+  if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
+    tags[0] ^= ~0xDFDFDFDF;
+  *count = 1;
   return true;
 }
 
@@ -384,8 +396,8 @@
 	limit = s;
     }
 
-    needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER);
-    needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
+    needs_script = !parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER);
+    needs_language = !parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
 
     if (needs_language && language_count && language_tags && *language_count)
       hb_ot_tags_from_language (lang_str, limit, language_count, language_tags);
@@ -419,20 +431,33 @@
   }
 
   for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
-    if (ot_languages[i].tags[0] == tag)
+    if (ot_languages[i].tag == tag)
       return hb_language_from_string (ot_languages[i].language, -1);
 
-  /* Else return a custom language in the form of "x-hbotABCD" */
+  /* If it's three letters long, assume it's ISO 639-3 and lower-case and use it
+   * (if it's not a registered tag, calling hb_ot_tag_from_language on the
+   * result might not return the same tag as the original tag).
+   * Else return a custom language in the form of "x-hbotABCD". */
   {
-    unsigned char buf[11] = "x-hbot";
+    char buf[11] = "x-hbot";
+    char *str = buf;
     buf[6] = tag >> 24;
     buf[7] = (tag >> 16) & 0xFF;
     buf[8] = (tag >> 8) & 0xFF;
     buf[9] = tag & 0xFF;
     if (buf[9] == 0x20)
+    {
       buf[9] = '\0';
+      if (ISALPHA (buf[6]) && ISALPHA (buf[7]) && ISALPHA (buf[8]))
+      {
+	buf[6] = TOLOWER (buf[6]);
+	buf[7] = TOLOWER (buf[7]);
+	buf[8] = TOLOWER (buf[8]);
+	str += 6;
+      }
+    }
     buf[10] = '\0';
-    return hb_language_from_string ((char *) buf, -1);
+    return hb_language_from_string (str, -1);
   }
 }
 
@@ -507,8 +532,8 @@
 {
   for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
   {
-    int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
-    if (c >= 0)
+    int c = ot_languages[i].cmp (&ot_languages[i - 1]);
+    if (c > 0)
     {
       fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
 	       i, ot_languages[i-1].language, c, ot_languages[i].language);
@@ -525,3 +550,6 @@
 }
 
 #endif
+
+
+#endif
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index 67a60f5e..ef8ba3f 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -49,9 +49,10 @@
   }
 
   public:
-  F2DOT14	fromCoord;	/* A normalized coordinate value obtained using
-				 * default normalization. */
-  F2DOT14	toCoord;	/* The modified, normalized coordinate value. */
+  F2DOT14	coords[2];
+//   F2DOT14	fromCoord;	/* A normalized coordinate value obtained using
+// 				 * default normalization. */
+//   F2DOT14	toCoord;	/* The modified, normalized coordinate value. */
 
   public:
   DEFINE_SIZE_STATIC (4);
@@ -59,12 +60,13 @@
 
 struct SegmentMaps : ArrayOf<AxisValueMap>
 {
-  int map (int value) const
+  int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
   {
+#define fromCoord coords[from_offset]
+#define toCoord coords[to_offset]
     /* The following special-cases are not part of OpenType, which requires
      * that at least -1, 0, and +1 must be mapped. But we include these as
      * part of a better error recovery scheme. */
-
     if (len < 2)
     {
       if (!len)
@@ -91,15 +93,19 @@
     return arrayZ[i-1].toCoord +
 	   ((arrayZ[i].toCoord - arrayZ[i-1].toCoord) *
 	    (value - arrayZ[i-1].fromCoord) + denom/2) / denom;
+#undef toCoord
+#undef fromCoord
   }
 
+  int unmap (int value) const { return map (value, 1, 0); }
+
   public:
   DEFINE_SIZE_ARRAY (2, *this);
 };
 
 struct avar
 {
-  enum { tableTag = HB_OT_TAG_avar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -114,7 +120,7 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (unlikely (!map->sanitize (c)))
-        return_trace (false);
+	return_trace (false);
       map = &StructAfter<SegmentMaps> (*map);
     }
 
@@ -123,7 +129,7 @@
 
   void map_coords (int *coords, unsigned int coords_length) const
   {
-    unsigned int count = MIN<unsigned int> (coords_length, axisCount);
+    unsigned int count = hb_min (coords_length, axisCount);
 
     const SegmentMaps *map = &firstAxisSegmentMaps;
     for (unsigned int i = 0; i < count; i++)
@@ -133,6 +139,18 @@
     }
   }
 
+  void unmap_coords (int *coords, unsigned int coords_length) const
+  {
+    unsigned int count = hb_min (coords_length, axisCount);
+
+    const SegmentMaps *map = &firstAxisSegmentMaps;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      coords[i] = map->unmap (coords[i]);
+      map = &StructAfter<SegmentMaps> (*map);
+    }
+  }
+
   protected:
   FixedVersion<>version;	/* Version of the avar table
 				 * initially set to 0x00010000u */
@@ -140,7 +158,7 @@
   HBUINT16	axisCount;	/* The number of variation axes in the font. This
 				 * must be the same number as axisCount in the
 				 * 'fvar' table. */
-  SegmentMaps   firstAxisSegmentMaps;
+  SegmentMaps	firstAxisSegmentMaps;
 
   public:
   DEFINE_SIZE_MIN (8);
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 76c9eb2..7ce3123 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -44,7 +44,7 @@
 {
   friend struct fvar;
 
-  hb_array_t<const Fixed> get_coordinates (unsigned int axis_count) const
+  hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
   { return coordinatesZ.as_array (axis_count); }
 
   bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
@@ -58,7 +58,7 @@
   NameID	subfamilyNameID;/* The name ID for entries in the 'name' table
 				 * that provide subfamily names for this instance. */
   HBUINT16	flags;		/* Reserved for future use — set to 0. */
-  UnsizedArrayOf<Fixed>
+  UnsizedArrayOf<HBFixed>
 		coordinatesZ;	/* The coordinates array for this instance. */
   //NameID	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
   //				  * table that provide PostScript names for this
@@ -83,9 +83,9 @@
 
   public:
   Tag		axisTag;	/* Tag identifying the design variation for the axis. */
-  Fixed		minValue;	/* The minimum coordinate value for the axis. */
-  Fixed		defaultValue;	/* The default coordinate value for the axis. */
-  Fixed		maxValue;	/* The maximum coordinate value for the axis. */
+  HBFixed		minValue;	/* The minimum coordinate value for the axis. */
+  HBFixed		defaultValue;	/* The default coordinate value for the axis. */
+  HBFixed		maxValue;	/* The maximum coordinate value for the axis. */
   HBUINT16	flags;		/* Axis flags. */
   NameID	axisNameID;	/* The name ID for entries in the 'name' table that
 				 * provide a display name for this axis. */
@@ -96,7 +96,7 @@
 
 struct fvar
 {
-  enum { tableTag = HB_OT_TAG_fvar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_fvar;
 
   bool has_data () const { return version.to_int (); }
 
@@ -114,17 +114,19 @@
 
   unsigned int get_axis_count () const { return axisCount; }
 
+#ifndef HB_DISABLE_DEPRECATED
   void get_axis_deprecated (unsigned int axis_index,
 				   hb_ot_var_axis_t *info) const
   {
     const AxisRecord &axis = get_axes ()[axis_index];
     info->tag = axis.axisTag;
     info->name_id =  axis.axisNameID;
-    info->default_value = axis.defaultValue / 65536.;
+    info->default_value = axis.defaultValue / 65536.f;
     /* Ensure order, to simplify client math. */
-    info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
-    info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
+    info->min_value = hb_min (info->default_value, axis.minValue / 65536.f);
+    info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f);
   }
+#endif
 
   void get_axis_info (unsigned int axis_index,
 		      hb_ot_var_axis_info_t *info) const
@@ -134,13 +136,14 @@
     info->tag = axis.axisTag;
     info->name_id =  axis.axisNameID;
     info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags;
-    info->default_value = axis.defaultValue / 65536.;
+    info->default_value = axis.defaultValue / 65536.f;
     /* Ensure order, to simplify client math. */
-    info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
-    info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
+    info->min_value = hb_min (info->default_value, axis.minValue / 65536.f);
+    info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f);
     info->reserved = 0;
   }
 
+#ifndef HB_DISABLE_DEPRECATED
   unsigned int get_axes_deprecated (unsigned int      start_offset,
 				    unsigned int     *axes_count /* IN/OUT */,
 				    hb_ot_var_axis_t *axes_array /* OUT */) const
@@ -149,12 +152,12 @@
     {
       /* TODO Rewrite as hb_array_t<>::sub-array() */
       unsigned int count = axisCount;
-      start_offset = MIN (start_offset, count);
+      start_offset = hb_min (start_offset, count);
 
       count -= start_offset;
       axes_array += start_offset;
 
-      count = MIN (count, *axes_count);
+      count = hb_min (count, *axes_count);
       *axes_count = count;
 
       for (unsigned int i = 0; i < count; i++)
@@ -162,6 +165,7 @@
     }
     return axisCount;
   }
+#endif
 
   unsigned int get_axis_infos (unsigned int           start_offset,
 			       unsigned int          *axes_count /* IN/OUT */,
@@ -171,12 +175,12 @@
     {
       /* TODO Rewrite as hb_array_t<>::sub-array() */
       unsigned int count = axisCount;
-      start_offset = MIN (start_offset, count);
+      start_offset = hb_min (start_offset, count);
 
       count -= start_offset;
       axes_array += start_offset;
 
-      count = MIN (count, *axes_count);
+      count = hb_min (count, *axes_count);
       *axes_count = count;
 
       for (unsigned int i = 0; i < count; i++)
@@ -185,6 +189,7 @@
     return axisCount;
   }
 
+#ifndef HB_DISABLE_DEPRECATED
   bool find_axis_deprecated (hb_tag_t tag,
 			     unsigned int *axis_index,
 			     hb_ot_var_axis_t *info) const
@@ -194,7 +199,7 @@
     for (unsigned int i = 0; i < count; i++)
       if (axes[i].axisTag == tag)
       {
-        if (axis_index)
+	if (axis_index)
 	  *axis_index = i;
 	get_axis_deprecated (i, info);
 	return true;
@@ -203,6 +208,7 @@
       *axis_index = HB_OT_VAR_NO_AXIS_INDEX;
     return false;
   }
+#endif
 
   bool find_axis_info (hb_tag_t tag,
 		       hb_ot_var_axis_info_t *info) const
@@ -223,7 +229,7 @@
     hb_ot_var_axis_info_t axis;
     get_axis_info (axis_index, &axis);
 
-    v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */
+    v = hb_max (hb_min (v, axis.max_value), axis.min_value); /* Clamp. */
 
     if (v == axis.default_value)
       return 0;
@@ -231,7 +237,21 @@
       v = (v - axis.default_value) / (axis.default_value - axis.min_value);
     else
       v = (v - axis.default_value) / (axis.max_value - axis.default_value);
-    return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f));
+    return roundf (v * 16384.f);
+  }
+
+  float unnormalize_axis_value (unsigned int axis_index, float v) const
+  {
+    hb_ot_var_axis_info_t axis;
+    get_axis_info (axis_index, &axis);
+
+    if (v == 0)
+      return axis.default_value;
+    else if (v < 0)
+      v = v * (axis.default_value - axis.min_value) / 16384.f + axis.default_value;
+    else
+      v = v * (axis.max_value - axis.default_value) / 16384.f + axis.default_value;
+    return v;
   }
 
   unsigned int get_instance_count () const { return instanceCount; }
@@ -253,27 +273,48 @@
   }
 
   unsigned int get_instance_coords (unsigned int  instance_index,
-					   unsigned int *coords_length, /* IN/OUT */
-					   float        *coords         /* OUT */) const
+				    unsigned int *coords_length, /* IN/OUT */
+				    float        *coords         /* OUT */) const
   {
     const InstanceRecord *instance = get_instance (instance_index);
     if (unlikely (!instance))
     {
       if (coords_length)
-        *coords_length = 0;
+	*coords_length = 0;
       return 0;
     }
 
     if (coords_length && *coords_length)
     {
-      hb_array_t<const Fixed> instanceCoords = instance->get_coordinates (axisCount)
+      hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
 							 .sub_array (0, *coords_length);
-      for (unsigned int i = 0; i < instanceCoords.len; i++)
-        coords[i] = instanceCoords.arrayZ[i].to_float ();
+      for (unsigned int i = 0; i < instanceCoords.length; i++)
+	coords[i] = instanceCoords.arrayZ[i].to_float ();
     }
     return axisCount;
   }
 
+  void collect_name_ids (hb_set_t *nameids) const
+  {
+    if (!has_data ()) return;
+
+    + get_axes ()
+    | hb_map (&AxisRecord::axisNameID)
+    | hb_sink (nameids)
+    ;
+
+    + hb_range ((unsigned) instanceCount)
+    | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); })
+    | hb_sink (nameids)
+    ;
+
+    + hb_range ((unsigned) instanceCount)
+    | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); })
+    | hb_sink (nameids)
+    ;
+  }
+
+
   protected:
   hb_array_t<const AxisRecord> get_axes () const
   { return hb_array (&(this+firstAxis), axisCount); }
@@ -299,8 +340,8 @@
   HBUINT16	instanceCount;	/* The number of named instances defined in the font
 				 * (the number of records in the instances array). */
   HBUINT16	instanceSize;	/* The size in bytes of each InstanceRecord — set
-				 * to either axisCount * sizeof(Fixed) + 4, or to
-				 * axisCount * sizeof(Fixed) + 6. */
+				 * to either axisCount * sizeof(HBFixed) + 4, or to
+				 * axisCount * sizeof(HBFixed) + 6. */
 
   public:
   DEFINE_SIZE_STATIC (16);
diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh
new file mode 100644
index 0000000..a76121d
--- /dev/null
+++ b/src/hb-ot-var-gvar-table.hh
@@ -0,0 +1,717 @@
+/*
+ * Copyright © 2019  Adobe Inc.
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_OT_VAR_GVAR_TABLE_HH
+#define HB_OT_VAR_GVAR_TABLE_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-glyf-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+
+/*
+ * gvar -- Glyph Variation Table
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar
+ */
+#define HB_OT_TAG_gvar HB_TAG('g','v','a','r')
+
+namespace OT {
+
+struct contour_point_t
+{
+  void init (float x_=0.f, float y_=0.f) { flag = 0; x = x_; y = y_; }
+
+  void translate (const contour_point_t &p) { x += p.x; y += p.y; }
+
+  uint8_t flag;
+  float x, y;
+};
+
+struct contour_point_vector_t : hb_vector_t<contour_point_t>
+{
+  void extend (const hb_array_t<contour_point_t> &a)
+  {
+    unsigned int old_len = length;
+    resize (old_len + a.length);
+    for (unsigned int i = 0; i < a.length; i++)
+      (*this)[old_len + i] = a[i];
+  }
+
+  void transform (const float (&matrix)[4])
+  {
+    for (unsigned int i = 0; i < length; i++)
+    {
+      contour_point_t &p = (*this)[i];
+      float x_ = p.x * matrix[0] + p.y * matrix[2];
+	   p.y = p.x * matrix[1] + p.y * matrix[3];
+      p.x = x_;
+    }
+  }
+
+  void translate (const contour_point_t& delta)
+  {
+    for (unsigned int i = 0; i < length; i++)
+      (*this)[i].translate (delta);
+  }
+};
+
+struct Tuple : UnsizedArrayOf<F2DOT14> {};
+
+struct TuppleIndex : HBUINT16
+{
+  enum Flags {
+    EmbeddedPeakTuple   = 0x8000u,
+    IntermediateRegion  = 0x4000u,
+    PrivatePointNumbers = 0x2000u,
+    TupleIndexMask      = 0x0FFFu
+  };
+
+  DEFINE_SIZE_STATIC (2);
+};
+
+struct TupleVarHeader
+{
+  unsigned int get_size (unsigned int axis_count) const
+  {
+    return min_size +
+	   (has_peak () ? get_peak_tuple ().get_size (axis_count) : 0) +
+	   (has_intermediate () ? (get_start_tuple (axis_count).get_size (axis_count) +
+				   get_end_tuple (axis_count).get_size (axis_count)) : 0);
+  }
+
+  const TupleVarHeader &get_next (unsigned int axis_count) const
+  { return StructAtOffset<TupleVarHeader> (this, get_size (axis_count)); }
+
+  float calculate_scalar (const int *coords, unsigned int coord_count,
+  			  const hb_array_t<const F2DOT14> shared_tuples) const
+  {
+    const F2DOT14 *peak_tuple;
+
+    if (has_peak ())
+      peak_tuple = &(get_peak_tuple ()[0]);
+    else
+    {
+      unsigned int index = get_index ();
+      if (unlikely (index * coord_count >= shared_tuples.length))
+	return 0.f;
+      peak_tuple = &shared_tuples[coord_count * index];
+    }
+
+    const F2DOT14 *start_tuple = nullptr;
+    const F2DOT14 *end_tuple = nullptr;
+    if (has_intermediate ())
+    {
+      start_tuple = get_start_tuple (coord_count);
+      end_tuple = get_end_tuple (coord_count);
+    }
+
+    float scalar = 1.f;
+    for (unsigned int i = 0; i < coord_count; i++)
+    {
+      int v = coords[i];
+      int peak = peak_tuple[i];
+      if (!peak || v == peak) continue;
+
+      if (has_intermediate ())
+      {
+	int start = start_tuple[i];
+	int end = end_tuple[i];
+	if (unlikely (start > peak || peak > end ||
+		      (start < 0 && end > 0 && peak))) continue;
+	if (v < start || v > end) return 0.f;
+	if (v < peak)
+	{ if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+	else
+	{ if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+      }
+      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+      else
+	scalar *= (float) v / peak;
+    }
+    return scalar;
+  }
+
+  unsigned int get_data_size () const { return varDataSize; }
+
+  bool           has_peak () const { return (tupleIndex & TuppleIndex::EmbeddedPeakTuple); }
+  bool   has_intermediate () const { return (tupleIndex & TuppleIndex::IntermediateRegion); }
+  bool has_private_points () const { return (tupleIndex & TuppleIndex::PrivatePointNumbers); }
+  unsigned int  get_index () const { return (tupleIndex & TuppleIndex::TupleIndexMask); }
+
+  protected:
+  const Tuple &get_peak_tuple () const
+  { return StructAfter<Tuple> (tupleIndex); }
+  const Tuple &get_start_tuple (unsigned int axis_count) const
+  { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? axis_count : 0]; }
+  const Tuple &get_end_tuple (unsigned int axis_count) const
+  { return *(const Tuple *) &get_peak_tuple ()[has_peak () ? (axis_count * 2) : axis_count]; }
+
+  HBUINT16		varDataSize;
+  TuppleIndex		tupleIndex;
+  /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
+  /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
+  /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
+
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct TupleVarCount : HBUINT16
+{
+  bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+  unsigned int get_count () const { return (*this) & CountMask; }
+
+  protected:
+  enum Flags
+  {
+    SharedPointNumbers	= 0x8000u,
+    CountMask		= 0x0FFFu
+  };
+
+  public:
+  DEFINE_SIZE_STATIC (2);
+};
+
+struct GlyphVarData
+{
+  const TupleVarHeader &get_tuple_var_header (void) const
+  { return StructAfter<TupleVarHeader> (data); }
+
+  struct tuple_iterator_t
+  {
+    void init (const GlyphVarData *var_data_, unsigned int length_, unsigned int axis_count_)
+    {
+      var_data = var_data_;
+      length = length_;
+      index = 0;
+      axis_count = axis_count_;
+      current_tuple = &var_data->get_tuple_var_header ();
+      data_offset = 0;
+    }
+
+    bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+    {
+      if (var_data->has_shared_point_numbers ())
+      {
+	hb_bytes_t bytes ((const char *) var_data, length);
+	const HBUINT8 *base = &(var_data+var_data->data);
+	const HBUINT8 *p = base;
+	if (!unpack_points (p, shared_indices, bytes)) return false;
+	data_offset = p - base;
+      }
+      return true;
+    }
+
+    bool is_valid () const
+    {
+      return (index < var_data->tupleVarCount.get_count ()) &&
+	     in_range (current_tuple) &&
+	     current_tuple->get_size (axis_count);
+    }
+
+    bool move_to_next ()
+    {
+      data_offset += current_tuple->get_data_size ();
+      current_tuple = &current_tuple->get_next (axis_count);
+      index++;
+      return is_valid ();
+    }
+
+    bool in_range (const void *p, unsigned int l) const
+    { return (const char*) p >= (const char*) var_data && (const char*) p+l <= (const char*) var_data + length; }
+
+    template <typename T> bool in_range (const T *p) const { return in_range (p, sizeof (*p)); }
+
+    const HBUINT8 *get_serialized_data () const
+    { return &(var_data+var_data->data) + data_offset; }
+
+    private:
+    const GlyphVarData *var_data;
+    unsigned int length;
+    unsigned int index;
+    unsigned int axis_count;
+    unsigned int data_offset;
+
+    public:
+    const TupleVarHeader *current_tuple;
+  };
+
+  static bool get_tuple_iterator (const GlyphVarData *var_data,
+  				  unsigned int length,
+  				  unsigned int axis_count,
+  				  hb_vector_t<unsigned int> &shared_indices /* OUT */,
+  				  tuple_iterator_t *iterator /* OUT */)
+  {
+    iterator->init (var_data, length, axis_count);
+    if (!iterator->get_shared_indices (shared_indices))
+      return false;
+    return iterator->is_valid ();
+  }
+
+  bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+
+  static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
+			     hb_vector_t<unsigned int> &points /* OUT */,
+			     const hb_bytes_t &bytes)
+  {
+    enum packed_point_flag_t
+    {
+      POINTS_ARE_WORDS     = 0x80,
+      POINT_RUN_COUNT_MASK = 0x7F
+    };
+
+    if (unlikely (!bytes.in_range (p))) return false;
+
+    uint16_t count = *p++;
+    if (count & POINTS_ARE_WORDS)
+    {
+      if (unlikely (!bytes.in_range (p))) return false;
+      count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
+    }
+    points.resize (count);
+
+    unsigned int n = 0;
+    uint16_t i = 0;
+    while (i < count)
+    {
+      if (unlikely (!bytes.in_range (p))) return false;
+      uint16_t j;
+      uint8_t control = *p++;
+      uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+      if (control & POINTS_ARE_WORDS)
+      {
+	for (j = 0; j < run_count && i < count; j++, i++)
+	{
+	  if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+	    return false;
+	  n += *(const HBUINT16 *)p;
+	  points[i] = n;
+	  p += HBUINT16::static_size;
+	}
+      }
+      else
+      {
+	for (j = 0; j < run_count && i < count; j++, i++)
+	{
+	  if (unlikely (!bytes.in_range (p))) return false;
+	  n += *p++;
+	  points[i] = n;
+	}
+      }
+      if (j < run_count) return false;
+    }
+    return true;
+  }
+
+  static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
+			     hb_vector_t<int> &deltas /* IN/OUT */,
+			     const hb_bytes_t &bytes)
+  {
+    enum packed_delta_flag_t
+    {
+      DELTAS_ARE_ZERO      = 0x80,
+      DELTAS_ARE_WORDS     = 0x40,
+      DELTA_RUN_COUNT_MASK = 0x3F
+    };
+
+    unsigned int i = 0;
+    unsigned int count = deltas.length;
+    while (i < count)
+    {
+      if (unlikely (!bytes.in_range (p))) return false;
+      uint8_t control = *p++;
+      unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+      unsigned int j;
+      if (control & DELTAS_ARE_ZERO)
+	for (j = 0; j < run_count && i < count; j++, i++)
+	  deltas[i] = 0;
+      else if (control & DELTAS_ARE_WORDS)
+	for (j = 0; j < run_count && i < count; j++, i++)
+	{
+	  if (unlikely (!bytes.in_range ((const HBUINT16 *) p)))
+	    return false;
+	  deltas[i] = *(const HBINT16 *) p;
+	  p += HBUINT16::static_size;
+	}
+      else
+	for (j = 0; j < run_count && i < count; j++, i++)
+	{
+	  if (unlikely (!bytes.in_range (p)))
+	    return false;
+	  deltas[i] = *(const HBINT8 *) p++;
+	}
+      if (j < run_count)
+	return false;
+    }
+    return true;
+  }
+
+  protected:
+  TupleVarCount		tupleVarCount;
+  OffsetTo<HBUINT8>	data;
+  /* TupleVarHeader tupleVarHeaders[] */
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct gvar
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
+
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && (version.major == 1) &&
+		  (glyphCount == c->get_num_glyphs ()) &&
+		  c->check_array (&(this+sharedTuples), axisCount * sharedTupleCount) &&
+		  (is_long_offset () ?
+		     c->check_array (get_long_offset_array (), glyphCount+1) :
+		     c->check_array (get_short_offset_array (), glyphCount+1)) &&
+		  c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0),
+				  get_offset (glyphCount) - get_offset (0)));
+  }
+
+  /* GlyphVarData not sanitized here; must be checked while accessing each glyph varation data */
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return sanitize_shallow (c); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    gvar *out = c->serializer->allocate_min<gvar> ();
+    if (unlikely (!out)) return_trace (false);
+
+    out->version.major = 1;
+    out->version.minor = 0;
+    out->axisCount = axisCount;
+    out->sharedTupleCount = sharedTupleCount;
+
+    unsigned int num_glyphs = c->plan->num_output_glyphs ();
+    out->glyphCount = num_glyphs;
+
+    unsigned int subset_data_size = 0;
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    {
+      hb_codepoint_t old_gid;
+      if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
+      subset_data_size += get_glyph_var_data_length (old_gid);
+    }
+
+    bool long_offset = subset_data_size & ~0xFFFFu;
+    out->flags = long_offset ? 1 : 0;
+
+    HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1));
+    if (!subset_offsets) return_trace (false);
+
+    /* shared tuples */
+    if (!sharedTupleCount || !sharedTuples)
+      out->sharedTuples = 0;
+    else
+    {
+      unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount;
+      F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
+      if (!tuples) return_trace (false);
+      out->sharedTuples = (char *) tuples - (char *) out;
+      memcpy (tuples, &(this+sharedTuples), shared_tuple_size);
+    }
+
+    char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
+    if (!subset_data) return_trace (false);
+    out->dataZ = subset_data - (char *)out;
+
+    unsigned int glyph_offset = 0;
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    {
+      hb_codepoint_t old_gid;
+      unsigned int length = c->plan->old_gid_for_new_gid (gid, &old_gid) ? get_glyph_var_data_length (old_gid) : 0;
+
+      if (long_offset)
+	((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+      else
+	((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+
+      if (length > 0) memcpy (subset_data, get_glyph_var_data (old_gid), length);
+      subset_data += length;
+      glyph_offset += length;
+    }
+    if (long_offset)
+      ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
+    else
+      ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2;
+
+    return_trace (true);
+  }
+
+  protected:
+  const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
+  {
+    unsigned int start_offset = get_offset (glyph);
+    unsigned int end_offset = get_offset (glyph+1);
+
+    if ((start_offset == end_offset) ||
+	unlikely ((start_offset > get_offset (glyphCount)) ||
+		  (start_offset + GlyphVarData::min_size > end_offset)))
+      return &Null (GlyphVarData);
+    return &(((unsigned char *) this + start_offset) + dataZ);
+  }
+
+  bool is_long_offset () const { return (flags & 1) != 0; }
+
+  unsigned int get_offset (unsigned int i) const
+  {
+    if (is_long_offset ())
+      return get_long_offset_array ()[i];
+    else
+      return get_short_offset_array ()[i] * 2;
+  }
+
+  unsigned int get_glyph_var_data_length (unsigned int glyph) const
+  {
+    unsigned int end_offset = get_offset (glyph + 1);
+    unsigned int start_offset = get_offset (glyph);
+    if (unlikely (start_offset > end_offset || end_offset > get_offset (glyphCount)))
+      return 0;
+    return end_offset - start_offset;
+  }
+
+  const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
+  const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
+
+  public:
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
+    {
+      gvar_table = hb_sanitize_context_t ().reference_table<gvar> (face);
+      hb_blob_ptr_t<fvar> fvar_table = hb_sanitize_context_t ().reference_table<fvar> (face);
+      unsigned int axis_count = fvar_table->get_axis_count ();
+      fvar_table.destroy ();
+
+      if (unlikely ((gvar_table->glyphCount != face->get_num_glyphs ()) ||
+		    (gvar_table->axisCount != axis_count)))
+      	fini ();
+
+      unsigned int num_shared_coord = gvar_table->sharedTupleCount * gvar_table->axisCount;
+      shared_tuples.resize (num_shared_coord);
+      for (unsigned int i = 0; i < num_shared_coord; i++)
+	shared_tuples[i] = (&(gvar_table + gvar_table->sharedTuples))[i];
+    }
+
+    void fini ()
+    {
+      gvar_table.destroy ();
+      shared_tuples.fini ();
+    }
+
+    private:
+    struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
+    struct y_getter { static float get (const contour_point_t &p) { return p.y; } };
+
+    template <typename T>
+    static float infer_delta (const hb_array_t<contour_point_t> points,
+			      const hb_array_t<contour_point_t> deltas,
+			      unsigned int target, unsigned int prev, unsigned int next)
+    {
+      float target_val = T::get (points[target]);
+      float prev_val = T::get (points[prev]);
+      float next_val = T::get (points[next]);
+      float prev_delta = T::get (deltas[prev]);
+      float next_delta = T::get (deltas[next]);
+
+      if (prev_val == next_val)
+      	return (prev_delta == next_delta) ? prev_delta : 0.f;
+      else if (target_val <= hb_min (prev_val, next_val))
+      	return (prev_val < next_val) ? prev_delta : next_delta;
+      else if (target_val >= hb_max (prev_val, next_val))
+      	return (prev_val > next_val) ? prev_delta : next_delta;
+
+      /* linear interpolation */
+      float r = (target_val - prev_val) / (next_val - prev_val);
+      return (1.f - r) * prev_delta + r * next_delta;
+    }
+
+    static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
+    { return (i >= end) ? start : (i + 1); }
+
+    public:
+    bool apply_deltas_to_points (hb_codepoint_t glyph,
+				 const int *coords, unsigned int coord_count,
+				 const hb_array_t<contour_point_t> points,
+				 const hb_array_t<unsigned int> end_points) const
+    {
+      if (unlikely (coord_count != gvar_table->axisCount)) return false;
+
+      const GlyphVarData *var_data = gvar_table->get_glyph_var_data (glyph);
+      if (var_data == &Null (GlyphVarData)) return true;
+      hb_vector_t<unsigned int> shared_indices;
+      GlyphVarData::tuple_iterator_t iterator;
+      if (!GlyphVarData::get_tuple_iterator (var_data,
+					     gvar_table->get_glyph_var_data_length (glyph),
+					     gvar_table->axisCount,
+					     shared_indices,
+					     &iterator))
+	return false;
+
+      /* Save original points for inferred delta calculation */
+      contour_point_vector_t orig_points;
+      orig_points.resize (points.length);
+      for (unsigned int i = 0; i < orig_points.length; i++)
+	orig_points[i] = points[i];
+
+      contour_point_vector_t deltas; /* flag is used to indicate referenced point */
+      deltas.resize (points.length);
+
+      do
+      {
+	float scalar = iterator.current_tuple->calculate_scalar (coords, coord_count, shared_tuples.as_array ());
+	if (scalar == 0.f) continue;
+	const HBUINT8 *p = iterator.get_serialized_data ();
+	unsigned int length = iterator.current_tuple->get_data_size ();
+	if (unlikely (!iterator.in_range (p, length)))
+	  return false;
+
+	hb_bytes_t bytes ((const char *) p, length);
+	hb_vector_t<unsigned int> private_indices;
+	if (iterator.current_tuple->has_private_points () &&
+	    !GlyphVarData::unpack_points (p, private_indices, bytes))
+	  return false;
+	const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
+
+	bool apply_to_all = (indices.length == 0);
+	unsigned int num_deltas = apply_to_all ? points.length : indices.length;
+	hb_vector_t<int> x_deltas;
+	x_deltas.resize (num_deltas);
+	if (!GlyphVarData::unpack_deltas (p, x_deltas, bytes))
+	  return false;
+	hb_vector_t<int> y_deltas;
+	y_deltas.resize (num_deltas);
+	if (!GlyphVarData::unpack_deltas (p, y_deltas, bytes))
+	  return false;
+
+	for (unsigned int i = 0; i < deltas.length; i++)
+	  deltas[i].init ();
+	for (unsigned int i = 0; i < num_deltas; i++)
+	{
+	  unsigned int pt_index = apply_to_all ? i : indices[i];
+	  deltas[pt_index].flag = 1;	/* this point is referenced, i.e., explicit deltas specified */
+	  deltas[pt_index].x += x_deltas[i] * scalar;
+	  deltas[pt_index].y += y_deltas[i] * scalar;
+	}
+
+	/* infer deltas for unreferenced points */
+	unsigned int start_point = 0;
+	for (unsigned int c = 0; c < end_points.length; c++)
+	{
+	  unsigned int end_point = end_points[c];
+	  unsigned int i, j;
+
+	  /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+	  unsigned int unref_count = 0;
+	  for (i = start_point; i <= end_point; i++)
+	    if (!deltas[i].flag) unref_count++;
+	  if (unref_count == 0 || unref_count > end_point - start_point)
+	    goto no_more_gaps;
+
+	  j = start_point;
+	  for (;;)
+	  {
+	    /* Locate the next gap of unreferenced points between two referenced points prev and next.
+	     * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+	     */
+	    unsigned int prev, next;
+	    for (;;)
+	    {
+	      i = j;
+	      j = next_index (i, start_point, end_point);
+	      if (deltas[i].flag && !deltas[j].flag) break;
+	    }
+	    prev = j = i;
+	    for (;;)
+	    {
+	      i = j;
+	      j = next_index (i, start_point, end_point);
+	      if (!deltas[i].flag && deltas[j].flag) break;
+	    }
+	    next = j;
+	    /* Infer deltas for all unref points in the gap between prev and next */
+	    i = prev;
+	    for (;;)
+	    {
+	      i = next_index (i, start_point, end_point);
+	      if (i == next) break;
+	      deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+	      deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+	      if (--unref_count == 0) goto no_more_gaps;
+	    }
+	  }
+no_more_gaps:
+	  start_point = end_point + 1;
+	}
+
+	/* apply specified / inferred deltas to points */
+	for (unsigned int i = 0; i < points.length; i++)
+	{
+	  points[i].x += (float) roundf (deltas[i].x);
+	  points[i].y += (float) roundf (deltas[i].y);
+	}
+      } while (iterator.move_to_next ());
+
+      return true;
+    }
+
+    unsigned int get_axis_count () const { return gvar_table->axisCount; }
+
+    protected:
+    const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const
+    { return gvar_table->get_glyph_var_data (glyph); }
+
+    private:
+    hb_blob_ptr_t<gvar> gvar_table;
+    hb_vector_t<F2DOT14> shared_tuples;
+  };
+
+  protected:
+  FixedVersion<>version;	/* Version of gvar table. Set to 0x00010000u. */
+  HBUINT16	axisCount;
+  HBUINT16	sharedTupleCount;
+  LOffsetTo<F2DOT14>
+		sharedTuples;	/* LOffsetTo<UnsizedArrayOf<Tupple>> */
+  HBUINT16	glyphCount;
+  HBUINT16	flags;
+  LOffsetTo<GlyphVarData>
+		dataZ;		/* Array of GlyphVarData */
+  UnsizedArrayOf<HBUINT8>
+		offsetZ;	/* Array of 16-bit or 32-bit (glyphCount+1) offsets */
+  public:
+  DEFINE_SIZE_MIN (20);
+};
+
+struct gvar_accelerator_t : gvar::accelerator_t {};
+
+} /* namespace OT */
+
+#endif /* HB_OT_VAR_GVAR_TABLE_HH */
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 2640f07..223430f 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -100,8 +100,8 @@
 
 struct HVARVVAR
 {
-  enum { HVARTag = HB_OT_TAG_HVAR };
-  enum { VVARTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR;
+  static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -114,14 +114,21 @@
 		  rsbMap.sanitize (c, this));
   }
 
-  float get_advance_var (hb_codepoint_t glyph,
-			 const int *coords, unsigned int coord_count) const
+  float get_advance_var (hb_font_t *font, hb_codepoint_t glyph) const
   {
     unsigned int varidx = (this+advMap).map (glyph);
+    return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
+  }
+
+  float get_side_bearing_var (hb_codepoint_t glyph,
+			      const int *coords, unsigned int coord_count) const
+  {
+    if (!has_side_bearing_deltas ()) return 0.f;
+    unsigned int varidx = (this+lsbMap).map (glyph);
     return (this+varStore).get_delta (varidx, coords, coord_count);
   }
 
-  bool has_sidebearing_deltas () const { return lsbMap && rsbMap; }
+  bool has_side_bearing_deltas () const { return lsbMap && rsbMap; }
 
   protected:
   FixedVersion<>version;	/* Version of the metrics variation table
@@ -140,10 +147,10 @@
 };
 
 struct HVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_HVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
 };
 struct VVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index a5eeddc..5a9d2af 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -58,7 +58,7 @@
 
 struct MVAR
 {
-  enum { tableTag = HB_OT_TAG_MVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -77,9 +77,9 @@
 		 const int *coords, unsigned int coord_count) const
   {
     const VariationValueRecord *record;
-    record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ,
-					       valueRecordCount, valueRecordSize,
-					       tag_compare);
+    record = (VariationValueRecord *) hb_bsearch (&tag, valuesZ.arrayZ,
+						  valueRecordCount, valueRecordSize,
+						  tag_compare);
     if (!record)
       return 0.;
 
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index e327fb7..6b8b09b 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -24,13 +24,15 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
+#ifndef HB_NO_VAR
+
+#include "hb-ot-var.h"
+
 #include "hb-ot-var-avar-table.hh"
 #include "hb-ot-var-fvar-table.hh"
 #include "hb-ot-var-mvar-table.hh"
-#include "hb-ot-var.h"
 
 
 /**
@@ -75,6 +77,7 @@
   return face->table.fvar->get_axis_count ();
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_ot_var_get_axes:
  *
@@ -104,6 +107,7 @@
 {
   return face->table.fvar->find_axis_deprecated (axis_tag, axis_index, axis_info);
 }
+#endif
 
 /**
  * hb_ot_var_get_axis_infos:
@@ -211,3 +215,6 @@
 
   face->table.avar->map_coords (normalized_coords, coords_length);
 }
+
+
+#endif
diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h
index cf6f0c9..df89bc5 100644
--- a/src/hb-ot-var.h
+++ b/src/hb-ot-var.h
@@ -68,7 +68,7 @@
 typedef enum { /*< flags >*/
   HB_OT_VAR_AXIS_FLAG_HIDDEN	= 0x00000001u,
 
-  _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= 0x7FFFFFFFu /*< skip >*/
+  _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_var_axis_flags_t;
 
 /**
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index 884d043..a4d6b06 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -48,7 +48,7 @@
   }
 
   public:
-  GlyphID	glyph;
+  HBGlyphID	glyph;
   FWORD		vertOriginY;
 
   public:
@@ -57,7 +57,7 @@
 
 struct VORG
 {
-  enum { tableTag = HB_OT_TAG_VORG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG;
 
   bool has_data () const { return version.to_int (); }
 
@@ -69,102 +69,56 @@
     return vertYOrigins[i].vertOriginY;
   }
 
-  bool _subset (const hb_subset_plan_t *plan HB_UNUSED,
-		const VORG *vorg_table,
-		const hb_vector_t<VertOriginMetric> &subset_metrics,
-		unsigned int dest_sz,
-		void *dest) const
+  template <typename Iterator,
+	    hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  FWORD defaultVertOriginY)
   {
-    hb_serialize_context_t c (dest, dest_sz);
 
-    VORG *subset_table = c.start_serialize<VORG> ();
-    if (unlikely (!c.extend_min (*subset_table)))
-      return false;
+    if (unlikely (!c->extend_min ((*this))))  return;
 
-    subset_table->version.major.set (1);
-    subset_table->version.minor.set (0);
+    this->version.major = 1;
+    this->version.minor = 0;
 
-    subset_table->defaultVertOriginY.set (vorg_table->defaultVertOriginY);
-    subset_table->vertYOrigins.len.set (subset_metrics.len);
+    this->defaultVertOriginY = defaultVertOriginY;
+    this->vertYOrigins.len = it.len ();
 
-    bool success = true;
-    if (subset_metrics.len > 0)
-    {
-      unsigned int  size = VertOriginMetric::static_size * subset_metrics.len;
-      VertOriginMetric  *metrics = c.allocate_size<VertOriginMetric> (size);
-      if (likely (metrics != nullptr))
-        memcpy (metrics, &subset_metrics[0], size);
-      else
-        success = false;
-    }
-    c.end_serialize ();
-
-    return success;
+    for (const auto _ : it) c->copy (_);
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *vorg_blob = hb_sanitize_context_t().reference_table<VORG> (plan->source);
-    const VORG *vorg_table = vorg_blob->as<VORG> ();
+    TRACE_SUBSET (this);
+    VORG *vorg_prime = c->serializer->start_embed<VORG> ();
+    if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false);
 
-    /* count the number of glyphs to be included in the subset table */
-    hb_vector_t<VertOriginMetric> subset_metrics;
-    subset_metrics.init ();
-    unsigned int glyph = 0;
-    unsigned int i = 0;
-    while ((glyph < plan->glyphs.len) && (i < vertYOrigins.len))
-    {
-      if (plan->glyphs[glyph] > vertYOrigins[i].glyph)
-        i++;
-      else if (plan->glyphs[glyph] < vertYOrigins[i].glyph)
-        glyph++;
-      else
-      {
-        VertOriginMetric *metrics = subset_metrics.push ();
-        metrics->glyph.set (glyph);
-        metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
-        glyph++;
-        i++;
-      }
-    }
+    auto it =
+    + vertYOrigins.as_array ()
+    | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph)
+    | hb_map ([&] (const VertOriginMetric& _)
+	      {
+		hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID;
+		c->plan->new_gid_for_old_gid (_.glyph, &new_glyph);
 
-    /* alloc the new table */
-    unsigned int dest_sz = VORG::min_size + VertOriginMetric::static_size * subset_metrics.len;
-    void *dest = (void *) malloc (dest_sz);
-    if (unlikely (!dest))
-    {
-      subset_metrics.fini ();
-      hb_blob_destroy (vorg_blob);
-      return false;
-    }
+		VertOriginMetric metric;
+		metric.glyph = new_glyph;
+		metric.vertOriginY = _.vertOriginY;
+		return metric;
+	      })
+    ;
 
     /* serialize the new table */
-    if (!_subset (plan, vorg_table, subset_metrics, dest_sz, dest))
-    {
-      subset_metrics.fini ();
-      free (dest);
-      hb_blob_destroy (vorg_blob);
-      return false;
-    }
-
-    hb_blob_t *result = hb_blob_create ((const char *)dest,
-                                        dest_sz,
-                                        HB_MEMORY_MODE_READONLY,
-                                        dest,
-                                        free);
-    bool success = plan->add_table (HB_OT_TAG_VORG, result);
-    hb_blob_destroy (result);
-    subset_metrics.fini ();
-    hb_blob_destroy (vorg_blob);
-    return success;
+    vorg_prime->serialize (c->serializer, it, defaultVertOriginY);
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-                  version.major == 1 &&
-                  vertYOrigins.sanitize (c));
+		  version.major == 1 &&
+		  vertYOrigins.sanitize (c));
   }
 
   protected:
diff --git a/src/hb-ot.h b/src/hb-ot.h
index db78469..f2dbaa1 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -35,6 +35,8 @@
 #include "hb-ot-font.h"
 #include "hb-ot-layout.h"
 #include "hb-ot-math.h"
+#include "hb-ot-meta.h"
+#include "hb-ot-metrics.h"
 #include "hb-ot-name.h"
 #include "hb-ot-shape.h"
 #include "hb-ot-var.h"
diff --git a/src/hb-pool.hh b/src/hb-pool.hh
new file mode 100644
index 0000000..83875db
--- /dev/null
+++ b/src/hb-pool.hh
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_POOL_HH
+#define HB_POOL_HH
+
+#include "hb.hh"
+
+/* Memory pool for persistent allocation of small objects. */
+
+template <typename T, unsigned ChunkLen = 16>
+struct hb_pool_t
+{
+  hb_pool_t () : next (nullptr) {}
+  ~hb_pool_t () { fini (); }
+
+  void fini ()
+  {
+    next = nullptr;
+
+    + hb_iter (chunks)
+    | hb_apply ([] (chunk_t *_) { ::free (_); })
+    ;
+
+    chunks.fini ();
+  }
+
+  T* alloc ()
+  {
+    if (unlikely (!next))
+    {
+      if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
+      chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t));
+      if (unlikely (!chunk)) return nullptr;
+      chunks.push (chunk);
+      next = chunk->thread ();
+    }
+
+    T* obj = next;
+    next = * ((T**) next);
+
+    memset (obj, 0, sizeof (T));
+
+    return obj;
+  }
+
+  void free (T* obj)
+  {
+    * (T**) obj = next;
+    next = obj;
+  }
+
+  private:
+
+  static_assert (ChunkLen > 1, "");
+  static_assert (sizeof (T) >= sizeof (void *), "");
+  static_assert (alignof (T) % alignof (void *) == 0, "");
+
+  struct chunk_t
+  {
+    T* thread ()
+    {
+      for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++)
+	* (T**) &arrayZ[i] = &arrayZ[i + 1];
+
+      * (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr;
+
+      return arrayZ;
+    }
+
+    T arrayZ[ChunkLen];
+  };
+
+  T* next;
+  hb_vector_t<chunk_t *> chunks;
+};
+
+
+#endif /* HB_POOL_HH */
diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh
new file mode 100644
index 0000000..7859c6a
--- /dev/null
+++ b/src/hb-sanitize.hh
@@ -0,0 +1,401 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SANITIZE_HH
+#define HB_SANITIZE_HH
+
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-dispatch.hh"
+
+
+/*
+ * Sanitize
+ *
+ *
+ * === Introduction ===
+ *
+ * The sanitize machinery is at the core of our zero-cost font loading.  We
+ * mmap() font file into memory and create a blob out of it.  Font subtables
+ * are returned as a readonly sub-blob of the main font blob.  These table
+ * blobs are then sanitized before use, to ensure invalid memory access does
+ * not happen.  The toplevel sanitize API use is like, eg. to load the 'head'
+ * table:
+ *
+ *   hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
+ *
+ * The blob then can be converted to a head table struct with:
+ *
+ *   const head *head_table = head_blob->as<head> ();
+ *
+ * What the reference_table does is, to call hb_face_reference_table() to load
+ * the table blob, sanitize it and return either the sanitized blob, or empty
+ * blob if sanitization failed.  The blob->as() function returns the null
+ * object of its template type argument if the blob is empty.  Otherwise, it
+ * just casts the blob contents to the desired type.
+ *
+ * Sanitizing a blob of data with a type T works as follows (with minor
+ * simplification):
+ *
+ *   - Cast blob content to T*, call sanitize() method of it,
+ *   - If sanitize succeeded, return blob.
+ *   - Otherwise, if blob is not writable, try making it writable,
+ *     or copy if cannot be made writable in-place,
+ *   - Call sanitize() again.  Return blob if sanitize succeeded.
+ *   - Return empty blob otherwise.
+ *
+ *
+ * === The sanitize() contract ===
+ *
+ * The sanitize() method of each object type shall return true if it's safe to
+ * call other methods of the object, and false otherwise.
+ *
+ * Note that what sanitize() checks for might align with what the specification
+ * describes as valid table data, but does not have to be.  In particular, we
+ * do NOT want to be pedantic and concern ourselves with validity checks that
+ * are irrelevant to our use of the table.  On the contrary, we want to be
+ * lenient with error handling and accept invalid data to the extent that it
+ * does not impose extra burden on us.
+ *
+ * Based on the sanitize contract, one can see that what we check for depends
+ * on how we use the data in other table methods.  Ie. if other table methods
+ * assume that offsets do NOT point out of the table data block, then that's
+ * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way).  On
+ * the other hand, if other methods do such checks themselves, then sanitize()
+ * does not have to bother with them (glyf/local work this way).  The choice
+ * depends on the table structure and sanitize() performance.  For example, to
+ * check glyf/loca offsets in sanitize() would cost O(num-glyphs).  We try hard
+ * to avoid such costs during font loading.  By postponing such checks to the
+ * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
+ * cost to O(used-glyphs).  As such, this is preferred.
+ *
+ * The same argument can be made re GSUB/GPOS/GDEF, but there, the table
+ * structure is so complicated that by checking all offsets at sanitize() time,
+ * we make the code much simpler in other methods, as offsets and referenced
+ * objects do not need to be validated at each use site.
+ */
+
+/* This limits sanitizing time on really broken fonts. */
+#ifndef HB_SANITIZE_MAX_EDITS
+#define HB_SANITIZE_MAX_EDITS 32
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_FACTOR
+#define HB_SANITIZE_MAX_OPS_FACTOR 8
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_MIN
+#define HB_SANITIZE_MAX_OPS_MIN 16384
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_MAX
+#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
+#endif
+
+struct hb_sanitize_context_t :
+       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
+{
+  hb_sanitize_context_t () :
+	debug_depth (0),
+	start (nullptr), end (nullptr),
+	max_ops (0),
+	writable (false), edit_count (0),
+	blob (nullptr),
+	num_glyphs (65536),
+	num_glyphs_set (false) {}
+
+  const char *get_name () { return "SANITIZE"; }
+  template <typename T, typename F>
+  bool may_dispatch (const T *obj HB_UNUSED, const F *format)
+  { return format->sanitize (this); }
+  static return_t default_return_value () { return true; }
+  static return_t no_dispatch_return_value () { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.sanitize (this, hb_forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+
+
+  void init (hb_blob_t *b)
+  {
+    this->blob = hb_blob_reference (b);
+    this->writable = false;
+  }
+
+  void set_num_glyphs (unsigned int num_glyphs_)
+  {
+    num_glyphs = num_glyphs_;
+    num_glyphs_set = true;
+  }
+  unsigned int get_num_glyphs () { return num_glyphs; }
+
+  void set_max_ops (int max_ops_) { max_ops = max_ops_; }
+
+  template <typename T>
+  void set_object (const T *obj)
+  {
+    reset_object ();
+
+    if (!obj) return;
+
+    const char *obj_start = (const char *) obj;
+    if (unlikely (obj_start < this->start || this->end <= obj_start))
+      this->start = this->end = nullptr;
+    else
+    {
+      this->start = obj_start;
+      this->end   = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ());
+    }
+  }
+
+  void reset_object ()
+  {
+    this->start = this->blob->data;
+    this->end = this->start + this->blob->length;
+    assert (this->start <= this->end); /* Must not overflow. */
+  }
+
+  void start_processing ()
+  {
+    reset_object ();
+    this->max_ops = hb_max ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+			 (unsigned) HB_SANITIZE_MAX_OPS_MIN);
+    this->edit_count = 0;
+    this->debug_depth = 0;
+
+    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
+		     "start [%p..%p] (%lu bytes)",
+		     this->start, this->end,
+		     (unsigned long) (this->end - this->start));
+  }
+
+  void end_processing ()
+  {
+    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
+		     "end [%p..%p] %u edit requests",
+		     this->start, this->end, this->edit_count);
+
+    hb_blob_destroy (this->blob);
+    this->blob = nullptr;
+    this->start = this->end = nullptr;
+  }
+
+  unsigned get_edit_count () { return edit_count; }
+
+  bool check_range (const void *base,
+		    unsigned int len) const
+  {
+    const char *p = (const char *) base;
+    bool ok = !len ||
+	      (this->start <= p &&
+	       p <= this->end &&
+	       (unsigned int) (this->end - p) >= len &&
+	       this->max_ops-- > 0);
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+		     "check_range [%p..%p]"
+		     " (%d bytes) in [%p..%p] -> %s",
+		     p, p + len, len,
+		     this->start, this->end,
+		     ok ? "OK" : "OUT-OF-RANGE");
+
+    return likely (ok);
+  }
+
+  template <typename T>
+  bool check_range (const T *base,
+		    unsigned int a,
+		    unsigned int b) const
+  {
+    return !hb_unsigned_mul_overflows (a, b) &&
+	   this->check_range (base, a * b);
+  }
+
+  template <typename T>
+  bool check_range (const T *base,
+		    unsigned int a,
+		    unsigned int b,
+		    unsigned int c) const
+  {
+    return !hb_unsigned_mul_overflows (a, b) &&
+	   this->check_range (base, a * b, c);
+  }
+
+  template <typename T>
+  bool check_array (const T *base, unsigned int len) const
+  {
+    return this->check_range (base, len, hb_static_size (T));
+  }
+
+  template <typename T>
+  bool check_array (const T *base,
+		    unsigned int a,
+		    unsigned int b) const
+  {
+    return this->check_range (base, a, b, hb_static_size (T));
+  }
+
+  template <typename Type>
+  bool check_struct (const Type *obj) const
+  { return likely (this->check_range (obj, obj->min_size)); }
+
+  bool may_edit (const void *base, unsigned int len)
+  {
+    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
+      return false;
+
+    const char *p = (const char *) base;
+    this->edit_count++;
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end,
+       this->writable ? "GRANTED" : "DENIED");
+
+    return this->writable;
+  }
+
+  template <typename Type, typename ValueType>
+  bool try_set (const Type *obj, const ValueType &v)
+  {
+    if (this->may_edit (obj, hb_static_size (Type)))
+    {
+      * const_cast<Type *> (obj) = v;
+      return true;
+    }
+    return false;
+  }
+
+  template <typename Type>
+  hb_blob_t *sanitize_blob (hb_blob_t *blob)
+  {
+    bool sane;
+
+    init (blob);
+
+  retry:
+    DEBUG_MSG_FUNC (SANITIZE, start, "start");
+
+    start_processing ();
+
+    if (unlikely (!start))
+    {
+      end_processing ();
+      return blob;
+    }
+
+    Type *t = reinterpret_cast<Type *> (const_cast<char *> (start));
+
+    sane = t->sanitize (this);
+    if (sane)
+    {
+      if (edit_count)
+      {
+	DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
+
+	/* sanitize again to ensure no toe-stepping */
+	edit_count = 0;
+	sane = t->sanitize (this);
+	if (edit_count) {
+	  DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count);
+	  sane = false;
+	}
+      }
+    }
+    else
+    {
+      if (edit_count && !writable) {
+	start = hb_blob_get_data_writable (blob, nullptr);
+	end = start + blob->length;
+
+	if (start)
+	{
+	  writable = true;
+	  /* ok, we made it writable by relocating.  try again */
+	  DEBUG_MSG_FUNC (SANITIZE, start, "retry");
+	  goto retry;
+	}
+      }
+    }
+
+    end_processing ();
+
+    DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED");
+    if (sane)
+    {
+      hb_blob_make_immutable (blob);
+      return blob;
+    }
+    else
+    {
+      hb_blob_destroy (blob);
+      return hb_blob_get_empty ();
+    }
+  }
+
+  template <typename Type>
+  hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag)
+  {
+    if (!num_glyphs_set)
+      set_num_glyphs (hb_face_get_glyph_count (face));
+    return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
+  }
+
+  mutable unsigned int debug_depth;
+  const char *start, *end;
+  mutable int max_ops;
+  private:
+  bool writable;
+  unsigned int edit_count;
+  hb_blob_t *blob;
+  unsigned int num_glyphs;
+  bool  num_glyphs_set;
+};
+
+struct hb_sanitize_with_object_t
+{
+  template <typename T>
+  hb_sanitize_with_object_t (hb_sanitize_context_t *c, const T& obj) : c (c)
+  { c->set_object (obj); }
+  ~hb_sanitize_with_object_t ()
+  { c->reset_object (); }
+
+  private:
+  hb_sanitize_context_t *c;
+};
+
+
+#endif /* HB_SANITIZE_HH */
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
new file mode 100644
index 0000000..4c674b1
--- /dev/null
+++ b/src/hb-serialize.hh
@@ -0,0 +1,466 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SERIALIZE_HH
+#define HB_SERIALIZE_HH
+
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-map.hh"
+#include "hb-pool.hh"
+
+
+/*
+ * Serialize
+ */
+
+struct hb_serialize_context_t
+{
+  typedef unsigned objidx_t;
+
+  struct range_t
+  {
+    char *head, *tail;
+  };
+
+  struct object_t : range_t
+  {
+    void fini () { links.fini (); }
+
+    bool operator == (const object_t &o) const
+    {
+      return (tail - head == o.tail - o.head)
+	  && (links.length == o.links.length)
+	  && 0 == hb_memcmp (head, o.head, tail - head)
+	  && links.as_bytes () == o.links.as_bytes ();
+    }
+    uint32_t hash () const
+    {
+      return hb_bytes_t (head, tail - head).hash () ^
+	     links.as_bytes ().hash ();
+    }
+
+    struct link_t
+    {
+      bool is_wide: 1;
+      unsigned position : 31;
+      unsigned bias;
+      objidx_t objidx;
+    };
+
+    hb_vector_t<link_t> links;
+    object_t *next;
+  };
+
+  range_t snapshot () { range_t s = {head, tail} ; return s; }
+
+
+  hb_serialize_context_t (void *start_, unsigned int size) :
+    start ((char *) start_),
+    end (start + size),
+    current (nullptr)
+  { reset (); }
+  ~hb_serialize_context_t () { fini (); }
+
+  void fini ()
+  {
+    for (object_t *_ : ++hb_iter (packed)) _->fini ();
+    packed.fini ();
+    this->packed_map.fini ();
+
+    while (current)
+    {
+      auto *_ = current;
+      current = current->next;
+      _->fini ();
+    }
+    object_pool.fini ();
+  }
+
+  bool in_error () const { return !this->successful; }
+
+  void reset ()
+  {
+    this->successful = true;
+    this->ran_out_of_room = false;
+    this->head = this->start;
+    this->tail = this->end;
+    this->debug_depth = 0;
+
+    fini ();
+    this->packed.push (nullptr);
+  }
+
+  bool check_success (bool success)
+  { return this->successful && (success || (err_other_error (), false)); }
+
+  template <typename T1, typename T2>
+  bool check_equal (T1 &&v1, T2 &&v2)
+  { return check_success (v1 == v2); }
+
+  template <typename T1, typename T2>
+  bool check_assign (T1 &v1, T2 &&v2)
+  { return check_equal (v1 = v2, v2); }
+
+  template <typename T> bool propagate_error (T &&obj)
+  { return check_success (!hb_deref (obj).in_error ()); }
+
+  template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os)
+  { return propagate_error (hb_forward<T1> (o1)) &&
+	   propagate_error (hb_forward<Ts> (os)...); }
+
+  /* To be called around main operation. */
+  template <typename Type>
+  Type *start_serialize ()
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
+		     "start [%p..%p] (%lu bytes)",
+		     this->start, this->end,
+		     (unsigned long) (this->end - this->start));
+
+    assert (!current);
+    return push<Type> ();
+  }
+  void end_serialize ()
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
+		     "end [%p..%p] serialized %u bytes; %s",
+		     this->start, this->end,
+		     (unsigned) (this->head - this->start),
+		     this->successful ? "successful" : "UNSUCCESSFUL");
+
+    propagate_error (packed, packed_map);
+
+    if (unlikely (!current)) return;
+    assert (!current->next);
+
+    /* Only "pack" if there exist other objects... Otherwise, don't bother.
+     * Saves a move. */
+    if (packed.length <= 1)
+      return;
+
+    pop_pack ();
+
+    resolve_links ();
+  }
+
+  template <typename Type = void>
+  Type *push ()
+  {
+    object_t *obj = object_pool.alloc ();
+    if (unlikely (!obj))
+      check_success (false);
+    else
+    {
+      obj->head = head;
+      obj->tail = tail;
+      obj->next = current;
+      current = obj;
+    }
+    return start_embed<Type> ();
+  }
+  void pop_discard ()
+  {
+    object_t *obj = current;
+    if (unlikely (!obj)) return;
+    current = current->next;
+    revert (*obj);
+    obj->fini ();
+    object_pool.free (obj);
+  }
+  objidx_t pop_pack ()
+  {
+    object_t *obj = current;
+    if (unlikely (!obj)) return 0;
+    current = current->next;
+    obj->tail = head;
+    obj->next = nullptr;
+    unsigned len = obj->tail - obj->head;
+    head = obj->head; /* Rewind head. */
+
+    if (!len)
+    {
+      assert (!obj->links.length);
+      return 0;
+    }
+
+    objidx_t objidx = packed_map.get (obj);
+    if (objidx)
+    {
+      obj->fini ();
+      return objidx;
+    }
+
+    tail -= len;
+    memmove (tail, obj->head, len);
+
+    obj->head = tail;
+    obj->tail = tail + len;
+
+    packed.push (obj);
+
+    if (unlikely (packed.in_error ()))
+      return 0;
+
+    objidx = packed.length - 1;
+
+    packed_map.set (obj, objidx);
+
+    return objidx;
+  }
+
+  void revert (range_t snap)
+  {
+    assert (snap.head <= head);
+    assert (tail <= snap.tail);
+    head = snap.head;
+    tail = snap.tail;
+    discard_stale_objects ();
+  }
+
+  void discard_stale_objects ()
+  {
+    while (packed.length > 1 &&
+	   packed.tail ()->head < tail)
+    {
+      packed_map.del (packed.tail ());
+      assert (!packed.tail ()->next);
+      packed.tail ()->fini ();
+      packed.pop ();
+    }
+    if (packed.length > 1)
+      assert (packed.tail ()->head == tail);
+  }
+
+  template <typename T>
+  void add_link (T &ofs, objidx_t objidx, const void *base = nullptr)
+  {
+    static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
+
+    if (!objidx)
+      return;
+
+    assert (current);
+    assert (current->head <= (const char *) &ofs);
+
+    if (!base)
+      base = current->head;
+    else
+      assert (current->head <= (const char *) base);
+
+    auto& link = *current->links.push ();
+    link.is_wide = sizeof (T) == 4;
+    link.position = (const char *) &ofs - current->head;
+    link.bias = (const char *) base - current->head;
+    link.objidx = objidx;
+  }
+
+  void resolve_links ()
+  {
+    if (unlikely (in_error ())) return;
+
+    assert (!current);
+    assert (packed.length > 1);
+
+    for (const object_t* parent : ++hb_iter (packed))
+      for (const object_t::link_t &link : parent->links)
+      {
+	const object_t* child = packed[link.objidx];
+	assert (link.bias <= (size_t) (parent->tail - parent->head));
+	unsigned offset = (child->head - parent->head) - link.bias;
+
+	if (link.is_wide)
+	{
+	  auto &off = * ((BEInt<uint32_t, 4> *) (parent->head + link.position));
+	  assert (0 == off);
+	  check_assign (off, offset);
+	}
+	else
+	{
+	  auto &off = * ((BEInt<uint16_t, 2> *) (parent->head + link.position));
+	  assert (0 == off);
+	  check_assign (off, offset);
+	}
+      }
+  }
+
+  unsigned int length () const { return this->head - current->head; }
+
+  void align (unsigned int alignment)
+  {
+    unsigned int l = length () % alignment;
+    if (l)
+      allocate_size<void> (alignment - l);
+  }
+
+  template <typename Type = void>
+  Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
+  { return reinterpret_cast<Type *> (this->head); }
+  template <typename Type>
+  Type *start_embed (const Type &obj) const
+  { return start_embed (hb_addressof (obj)); }
+
+  /* Following two functions exist to allow setting breakpoint on. */
+  void err_ran_out_of_room () { this->ran_out_of_room = true; }
+  void err_other_error () { this->successful = false; }
+
+  template <typename Type>
+  Type *allocate_size (unsigned int size)
+  {
+    if (unlikely (!this->successful)) return nullptr;
+
+    if (this->tail - this->head < ptrdiff_t (size))
+    {
+      err_ran_out_of_room ();
+      this->successful = false;
+      return nullptr;
+    }
+    memset (this->head, 0, size);
+    char *ret = this->head;
+    this->head += size;
+    return reinterpret_cast<Type *> (ret);
+  }
+
+  template <typename Type>
+  Type *allocate_min ()
+  { return this->allocate_size<Type> (Type::min_size); }
+
+  template <typename Type>
+  Type *embed (const Type *obj)
+  {
+    unsigned int size = obj->get_size ();
+    Type *ret = this->allocate_size<Type> (size);
+    if (unlikely (!ret)) return nullptr;
+    memcpy (ret, obj, size);
+    return ret;
+  }
+  template <typename Type>
+  Type *embed (const Type &obj)
+  { return embed (hb_addressof (obj)); }
+
+  template <typename Type, typename ...Ts> auto
+  _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
+  (Type *, src.copy (this, hb_forward<Ts> (ds)...))
+
+  template <typename Type> auto
+  _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src))
+  {
+    Type *ret = this->allocate_size<Type> (sizeof (Type));
+    if (unlikely (!ret)) return nullptr;
+    *ret = src;
+    return ret;
+  }
+
+  /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
+   * instead of memcpy(). */
+  template <typename Type, typename ...Ts>
+  Type *copy (const Type &src, Ts&&... ds)
+  { return _copy (src, hb_prioritize, hb_forward<Ts> (ds)...); }
+  template <typename Type, typename ...Ts>
+  Type *copy (const Type *src, Ts&&... ds)
+  { return copy (*src, hb_forward<Ts> (ds)...); }
+
+  template <typename Type>
+  hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
+
+  template <typename Type>
+  Type *extend_size (Type *obj, unsigned int size)
+  {
+    assert (this->start <= (char *) obj);
+    assert ((char *) obj <= this->head);
+    assert ((char *) obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+    return reinterpret_cast<Type *> (obj);
+  }
+  template <typename Type>
+  Type *extend_size (Type &obj, unsigned int size)
+  { return extend_size (hb_addressof (obj), size); }
+
+  template <typename Type>
+  Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
+  template <typename Type>
+  Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); }
+
+  template <typename Type, typename ...Ts>
+  Type *extend (Type *obj, Ts&&... ds)
+  { return extend_size (obj, obj->get_size (hb_forward<Ts> (ds)...)); }
+  template <typename Type, typename ...Ts>
+  Type *extend (Type &obj, Ts&&... ds)
+  { return extend (hb_addressof (obj), hb_forward<Ts> (ds)...); }
+
+  /* Output routines. */
+  hb_bytes_t copy_bytes () const
+  {
+    assert (this->successful);
+    /* Copy both items from head side and tail side... */
+    unsigned int len = (this->head - this->start)
+		     + (this->end  - this->tail);
+
+    char *p = (char *) malloc (len);
+    if (unlikely (!p)) return hb_bytes_t ();
+
+    memcpy (p, this->start, this->head - this->start);
+    memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
+    return hb_bytes_t (p, len);
+  }
+  template <typename Type>
+  Type *copy () const
+  { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); }
+  hb_blob_t *copy_blob () const
+  {
+    hb_bytes_t b = copy_bytes ();
+    return hb_blob_create (b.arrayZ, b.length,
+			   HB_MEMORY_MODE_WRITABLE,
+			   (char *) b.arrayZ, free);
+  }
+
+  public: /* TODO Make private. */
+  char *start, *head, *tail, *end;
+  unsigned int debug_depth;
+  bool successful;
+  bool ran_out_of_room;
+
+  private:
+
+  /* Object memory pool. */
+  hb_pool_t<object_t> object_pool;
+
+  /* Stack of currently under construction objects. */
+  object_t *current;
+
+  /* Stack of packed objects.  Object 0 is always nil object. */
+  hb_vector_t<object_t *> packed;
+
+  /* Map view of packed objects. */
+  hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
+};
+
+
+#endif /* HB_SERIALIZE_HH */
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index 9f49af1..b97526f 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -48,15 +48,15 @@
 template <typename mask_t, unsigned int shift>
 struct hb_set_digest_lowest_bits_t
 {
-  enum { mask_bytes = sizeof (mask_t) };
-  enum { mask_bits = sizeof (mask_t) * 8 };
-  enum { num_bits = 0
-		  + (mask_bytes >= 1 ? 3 : 0)
-		  + (mask_bytes >= 2 ? 1 : 0)
-		  + (mask_bytes >= 4 ? 1 : 0)
-		  + (mask_bytes >= 8 ? 1 : 0)
-		  + (mask_bytes >= 16? 1 : 0)
-		  + 0 };
+  static constexpr unsigned mask_bytes = sizeof (mask_t);
+  static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
+  static constexpr unsigned num_bits = 0
+				     + (mask_bytes >= 1 ? 3 : 0)
+				     + (mask_bytes >= 2 ? 1 : 0)
+				     + (mask_bytes >= 4 ? 1 : 0)
+				     + (mask_bytes >= 8 ? 1 : 0)
+				     + (mask_bytes >= 16? 1 : 0)
+				     + 0;
 
   static_assert ((shift < sizeof (hb_codepoint_t) * 8), "");
   static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), "");
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 0682362..10638a7 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -389,6 +389,7 @@
   set->symmetric_difference (other);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_set_invert:
  * @set: a set.
@@ -403,6 +404,7 @@
 hb_set_invert (hb_set_t *set HB_UNUSED)
 {
 }
+#endif
 
 /**
  * hb_set_get_population:
@@ -477,7 +479,7 @@
  * @set: a set.
  * @codepoint: (inout):
  *
- * Gets the previous number in @set that is slower than current value of @codepoint.
+ * Gets the previous number in @set that is lower than current value of @codepoint.
  *
  * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
  *
@@ -522,7 +524,7 @@
  * @last: (out): output last codepoint in the range.
  *
  * Gets the previous consecutive range of numbers in @set that
- * are greater than current value of @last.
+ * are less than current value of @first.
  *
  * Set @first to %HB_SET_VALUE_INVALID to get started.
  *
diff --git a/src/hb-set.hh b/src/hb-set.hh
index 1959688..36d11c0 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -28,6 +28,7 @@
 #define HB_SET_HH
 
 #include "hb.hh"
+#include "hb-machinery.hh"
 
 
 /*
@@ -39,7 +40,7 @@
 
 struct hb_set_t
 {
-  HB_NO_COPY_ASSIGN (hb_set_t);
+  HB_DELETE_COPY_ASSIGN (hb_set_t);
   hb_set_t ()  { init (); }
   ~hb_set_t () { fini (); }
 
@@ -62,21 +63,21 @@
     bool is_empty () const
     {
       for (unsigned int i = 0; i < len (); i++)
-        if (v[i])
+	if (v[i])
 	  return false;
       return true;
     }
 
     void add (hb_codepoint_t g) { elt (g) |= mask (g); }
     void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-    bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
+    bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
     void add_range (hb_codepoint_t a, hb_codepoint_t b)
     {
       elt_t *la = &elt (a);
       elt_t *lb = &elt (b);
       if (la == lb)
-        *la |= (mask (b) << 1) - mask(a);
+	*la |= (mask (b) << 1) - mask(a);
       else
       {
 	*la |= ~(mask (a) - 1);
@@ -97,7 +98,7 @@
     {
       unsigned int pop = 0;
       for (unsigned int i = 0; i < len (); i++)
-        pop += hb_popcount (v[i]);
+	pop += hb_popcount (v[i]);
       return pop;
     }
 
@@ -135,12 +136,17 @@
       unsigned int j = m & ELT_MASK;
 
       const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1);
-      for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i])
+      const elt_t *p = &vv;
+      while (true)
+      {
 	if (*p)
 	{
 	  *codepoint = i * ELT_BITS + elt_get_max (*p);
 	  return true;
 	}
+	if ((int) i <= 0) break;
+	p = &v[--i];
+      }
 
       *codepoint = INVALID;
       return false;
@@ -148,20 +154,20 @@
     hb_codepoint_t get_min () const
     {
       for (unsigned int i = 0; i < len (); i++)
-        if (v[i])
+	if (v[i])
 	  return i * ELT_BITS + elt_get_min (v[i]);
       return INVALID;
     }
     hb_codepoint_t get_max () const
     {
       for (int i = len () - 1; i >= 0; i--)
-        if (v[i])
+	if (v[i])
 	  return i * ELT_BITS + elt_get_max (v[i]);
       return 0;
     }
 
     typedef unsigned long long elt_t;
-    enum { PAGE_BITS = 512 };
+    static constexpr unsigned PAGE_BITS = 512;
     static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
 
     static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
@@ -169,10 +175,10 @@
 
     typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
 
-    enum { ELT_BITS = sizeof (elt_t) * 8 };
-    enum { ELT_MASK = ELT_BITS - 1 };
-    enum { BITS = sizeof (vector_t) * 8 };
-    enum { MASK = BITS - 1 };
+    static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+    static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+    static constexpr unsigned BITS = sizeof (vector_t) * 8;
+    static constexpr unsigned MASK = BITS - 1;
     static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
 
     elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
@@ -186,8 +192,8 @@
   hb_object_header_t header;
   bool successful; /* Allocations successful */
   mutable unsigned int population;
-  hb_vector_t<page_map_t, 1> page_map;
-  hb_vector_t<page_t, 1> pages;
+  hb_sorted_vector_t<page_map_t> page_map;
+  hb_vector_t<page_t> pages;
 
   void init_shallow ()
   {
@@ -220,28 +226,35 @@
     if (unlikely (!successful)) return false;
     if (!pages.resize (count) || !page_map.resize (count))
     {
-      pages.resize (page_map.len);
+      pages.resize (page_map.length);
       successful = false;
       return false;
     }
     return true;
   }
 
+  void reset ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    clear ();
+    successful = true;
+  }
+
   void clear ()
   {
     if (unlikely (hb_object_is_immutable (this)))
       return;
-    successful = true;
     population = 0;
     page_map.resize (0);
     pages.resize (0);
   }
   bool is_empty () const
   {
-    unsigned int count = pages.len;
+    unsigned int count = pages.length;
     for (unsigned int i = 0; i < count; i++)
       if (!pages[i].is_empty ())
-        return false;
+	return false;
     return true;
   }
 
@@ -301,7 +314,7 @@
       {
 	page->add (g);
 
-	array = (const T *) ((const char *) array + stride);
+	array = &StructAtOffsetUnaligned<T> (array, stride);
 	count--;
       }
       while (count && (g = *array, start <= g && g < end));
@@ -325,9 +338,9 @@
       unsigned int end = major_start (m + 1);
       do
       {
-        /* If we try harder we can change the following comparison to <=;
+	/* If we try harder we can change the following comparison to <=;
 	 * Not sure if it's worth it. */
-        if (g < last_g) return false;
+	if (g < last_g) return false;
 	last_g = g;
 	page->add (g);
 
@@ -357,15 +370,26 @@
     for (unsigned int i = a; i < b + 1; i++)
       del (i);
   }
-  bool has (hb_codepoint_t g) const
+  bool get (hb_codepoint_t g) const
   {
     const page_t *page = page_for (g);
     if (!page)
       return false;
-    return page->has (g);
+    return page->get (g);
   }
-  bool intersects (hb_codepoint_t first,
-			  hb_codepoint_t last) const
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_set_t& operator << (hb_codepoint_t v) { add (v); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
   {
     hb_codepoint_t c = first - 1;
     return next (&c) && c <= last;
@@ -373,7 +397,7 @@
   void set (const hb_set_t *other)
   {
     if (unlikely (!successful)) return;
-    unsigned int count = other->pages.len;
+    unsigned int count = other->pages.length;
     if (!resize (count))
       return;
     population = other->population;
@@ -386,8 +410,8 @@
     if (get_population () != other->get_population ())
       return false;
 
-    unsigned int na = pages.len;
-    unsigned int nb = other->pages.len;
+    unsigned int na = pages.length;
+    unsigned int nb = other->pages.length;
 
     unsigned int a = 0, b = 0;
     for (; a < na && b < nb; )
@@ -396,7 +420,7 @@
       if (other->page_at (b).is_empty ()) { b++; continue; }
       if (page_map[a].major != other->page_map[b].major ||
 	  !page_at (a).is_equal (&other->page_at (b)))
-        return false;
+	return false;
       a++;
       b++;
     }
@@ -417,20 +441,20 @@
     hb_codepoint_t c = INVALID;
     while (next (&c))
       if (!larger_set->has (c))
-        return false;
+	return false;
 
     return true;
   }
 
-  template <class Op>
-  void process (const hb_set_t *other)
+  template <typename Op>
+  void process (const Op& op, const hb_set_t *other)
   {
     if (unlikely (!successful)) return;
 
     dirty ();
 
-    unsigned int na = pages.len;
-    unsigned int nb = other->pages.len;
+    unsigned int na = pages.length;
+    unsigned int nb = other->pages.length;
     unsigned int next_page = na;
 
     unsigned int count = 0, newCount = 0;
@@ -439,21 +463,21 @@
     {
       if (page_map[a].major == other->page_map[b].major)
       {
-        count++;
+	count++;
 	a++;
 	b++;
       }
       else if (page_map[a].major < other->page_map[b].major)
       {
-        if (Op::passthru_left)
+	if (Op::passthru_left)
 	  count++;
-        a++;
+	a++;
       }
       else
       {
-        if (Op::passthru_right)
+	if (Op::passthru_right)
 	  count++;
-        b++;
+	b++;
       }
     }
     if (Op::passthru_left)
@@ -461,9 +485,9 @@
     if (Op::passthru_right)
       count += nb - b;
 
-    if (count > pages.len)
+    if (count > pages.length)
       if (!resize (count))
-        return;
+	return;
     newCount = count;
 
     /* Process in-place backward. */
@@ -477,7 +501,7 @@
 	b--;
 	count--;
 	page_map[count] = page_map[a];
-	Op::process (page_at (count).v, page_at (a).v, other->page_at (b).v);
+	page_at (count).v = op (page_at (a).v, other->page_at (b).v);
       }
       else if (page_map[a - 1].major > other->page_map[b - 1].major)
       {
@@ -517,25 +541,25 @@
 	page_at (count).v = other->page_at (b).v;
       }
     assert (!count);
-    if (pages.len > newCount)
+    if (pages.length > newCount)
       resize (newCount);
   }
 
   void union_ (const hb_set_t *other)
   {
-    process<HbOpOr> (other);
+    process (hb_bitwise_or, other);
   }
   void intersect (const hb_set_t *other)
   {
-    process<HbOpAnd> (other);
+    process (hb_bitwise_and, other);
   }
   void subtract (const hb_set_t *other)
   {
-    process<HbOpMinus> (other);
+    process (hb_bitwise_sub, other);
   }
   void symmetric_difference (const hb_set_t *other)
   {
-    process<HbOpXor> (other);
+    process (hb_bitwise_xor, other);
   }
   bool next (hb_codepoint_t *codepoint) const
   {
@@ -547,7 +571,7 @@
     page_map_t map = {get_major (*codepoint), 0};
     unsigned int i;
     page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.len && page_map[i].major == map.major)
+    if (i < page_map.length && page_map[i].major == map.major)
     {
       if (pages[page_map[i].index].next (codepoint))
       {
@@ -556,7 +580,7 @@
       }
       i++;
     }
-    for (; i < page_map.len; i++)
+    for (; i < page_map.length; i++)
     {
       hb_codepoint_t m = pages[page_map[i].index].get_min ();
       if (m != INVALID)
@@ -578,7 +602,7 @@
     page_map_t map = {get_major (*codepoint), 0};
     unsigned int i;
     page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST);
-    if (i < page_map.len && page_map[i].major == map.major)
+    if (i < page_map.length && page_map[i].major == map.major)
     {
       if (pages[page_map[i].index].previous (codepoint))
       {
@@ -642,7 +666,7 @@
       return population;
 
     unsigned int pop = 0;
-    unsigned int count = pages.len;
+    unsigned int count = pages.length;
     for (unsigned int i = 0; i < count; i++)
       pop += pages[i].get_population ();
 
@@ -651,36 +675,65 @@
   }
   hb_codepoint_t get_min () const
   {
-    unsigned int count = pages.len;
+    unsigned int count = pages.length;
     for (unsigned int i = 0; i < count; i++)
       if (!page_at (i).is_empty ())
-        return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
+	return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
     return INVALID;
   }
   hb_codepoint_t get_max () const
   {
-    unsigned int count = pages.len;
+    unsigned int count = pages.length;
     for (int i = count - 1; i >= 0; i++)
       if (!page_at (i).is_empty ())
-        return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max ();
+	return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max ();
     return INVALID;
   }
 
-  static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_set_t &s_ = Null(hb_set_t)) :
+      s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
+
+    protected:
+    const hb_set_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+
+  protected:
 
   page_t *page_for_insert (hb_codepoint_t g)
   {
-    page_map_t map = {get_major (g), pages.len};
+    page_map_t map = {get_major (g), pages.length};
     unsigned int i;
     if (!page_map.bfind (map, &i, HB_BFIND_NOT_FOUND_STORE_CLOSEST))
     {
-      if (!resize (pages.len + 1))
+      if (!resize (pages.length + 1))
 	return nullptr;
 
       pages[map.index].init0 ();
       memmove (page_map + i + 1,
 	       page_map + i,
-	       (page_map.len - 1 - i) * page_map.item_size);
+	       (page_map.length - 1 - i) * page_map.item_size);
       page_map[i] = map;
     }
     return &pages[page_map[i].index];
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 61ea8d0..ffd723d 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -79,7 +79,9 @@
   }
   this->shaper_func = nullptr;
   this->shaper_name = nullptr;
+#ifndef HB_NO_OT_SHAPE
   this->ot.init (face, coords, num_coords);
+#endif
 
   /*
    * Choose shaper.
@@ -148,7 +150,9 @@
 {
   return hb_segment_properties_equal (&this->props, &other->props) &&
 	 this->user_features_match (other) &&
+#ifndef HB_NO_OT_SHAPE
 	 this->ot.equal (&other->ot) &&
+#endif
 	 this->shaper_func == other->shaper_func;
 }
 
@@ -160,13 +164,13 @@
 
 /**
  * hb_shape_plan_create: (Xconstructor)
- * @face: 
- * @props: 
+ * @face:
+ * @props:
  * @user_features: (array length=num_user_features):
- * @num_user_features: 
+ * @num_user_features:
  * @shaper_list: (array zero-terminated=1):
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
@@ -224,12 +228,16 @@
 				       num_coords,
 				       shaper_list)))
     goto bail2;
+#ifndef HB_NO_OT_SHAPE
   if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
     goto bail3;
+#endif
 
   return shape_plan;
 
+#ifndef HB_NO_OT_SHAPE
 bail3:
+#endif
   shape_plan->key.free ();
 bail2:
   free (shape_plan);
@@ -240,7 +248,7 @@
 /**
  * hb_shape_plan_get_empty:
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
@@ -256,7 +264,7 @@
  * hb_shape_plan_reference: (skip)
  * @shape_plan: a shape plan.
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
@@ -272,7 +280,7 @@
  * hb_shape_plan_destroy: (skip)
  * @shape_plan: a shape plan.
  *
- * 
+ *
  *
  * Since: 0.9.7
  **/
@@ -281,7 +289,9 @@
 {
   if (!hb_object_destroy (shape_plan)) return;
 
+#ifndef HB_NO_OT_SHAPE
   shape_plan->ot.fini ();
+#endif
   shape_plan->key.free ();
   free (shape_plan);
 }
@@ -289,14 +299,14 @@
 /**
  * hb_shape_plan_set_user_data: (skip)
  * @shape_plan: a shape plan.
- * @key: 
- * @data: 
- * @destroy: 
- * @replace: 
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.7
  **/
@@ -313,9 +323,9 @@
 /**
  * hb_shape_plan_get_user_data: (skip)
  * @shape_plan: a shape plan.
- * @key: 
+ * @key:
  *
- * 
+ *
  *
  * Return value: (transfer none):
  *
@@ -332,7 +342,7 @@
  * hb_shape_plan_get_shaper:
  * @shape_plan: a shape plan.
  *
- * 
+ *
  *
  * Return value: (transfer none):
  *
@@ -351,11 +361,11 @@
  * @font: a font.
  * @buffer: a buffer.
  * @features: (array length=num_features):
- * @num_features: 
+ * @num_features:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.7
  **/
@@ -410,13 +420,13 @@
 
 /**
  * hb_shape_plan_create_cached:
- * @face: 
- * @props: 
+ * @face:
+ * @props:
  * @user_features: (array length=num_user_features):
- * @num_user_features: 
+ * @num_user_features:
  * @shaper_list: (array zero-terminated=1):
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
@@ -471,8 +481,8 @@
     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
       if (node->shape_plan->key.equal (&key))
       {
-        DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
-        return hb_shape_plan_reference (node->shape_plan);
+	DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+	return hb_shape_plan_reference (node->shape_plan);
       }
   }
 
diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh
index 3a057fd..6da7edb 100644
--- a/src/hb-shape-plan.hh
+++ b/src/hb-shape-plan.hh
@@ -39,21 +39,23 @@
   const hb_feature_t      *user_features;
   unsigned int             num_user_features;
 
+#ifndef HB_NO_OT_SHAPE
   hb_ot_shape_plan_key_t   ot;
+#endif
 
   hb_shape_func_t         *shaper_func;
   const char              *shaper_name;
 
-  HB_INTERNAL inline bool init (bool                           copy,
-				hb_face_t                     *face,
-				const hb_segment_properties_t *props,
-				const hb_feature_t            *user_features,
-				unsigned int                   num_user_features,
-				const int                     *coords,
-				unsigned int                   num_coords,
-				const char * const            *shaper_list);
+  HB_INTERNAL bool init (bool                           copy,
+			 hb_face_t                     *face,
+			 const hb_segment_properties_t *props,
+			 const hb_feature_t            *user_features,
+			 unsigned int                   num_user_features,
+			 const int                     *coords,
+			 unsigned int                   num_coords,
+			 const char * const            *shaper_list);
 
-  HB_INTERNAL inline void free () { ::free ((void *) user_features); }
+  HB_INTERNAL void free () { ::free ((void *) user_features); }
 
   HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
 
@@ -65,7 +67,9 @@
   hb_object_header_t header;
   hb_face_t *face_unsafe; /* We don't carry a reference to face. */
   hb_shape_plan_key_t key;
+#ifndef HB_NO_OT_SHAPE
   hb_ot_shape_plan_t ot;
+#endif
 };
 
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index deff77b..cf4e152 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -154,7 +154,9 @@
  *
  * Shapes @buffer using @font turning its Unicode characters content to
  * positioned glyphs. If @features is not %NULL, it will be used to control the
- * features applied during shaping.
+ * features applied during shaping. If two @features have the same tag but
+ * overlapping ranges the value of the feature with the higher index takes
+ * precedence.
  *
  * Since: 0.9.2
  **/
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
index 36d8fc7..0d63933 100644
--- a/src/hb-shaper-list.hh
+++ b/src/hb-shaper-list.hh
@@ -28,6 +28,9 @@
 #define HB_SHAPER_LIST_HH
 #endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
 
+#ifndef HB_NO_SHAPER
+
+
 /* v--- Add new shapers in the right place here. */
 
 #ifdef HAVE_GRAPHITE2
@@ -35,7 +38,9 @@
 HB_SHAPER_IMPLEMENT (graphite2)
 #endif
 
+#ifndef HB_NO_OT_SHAPE
 HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
 
 #ifdef HAVE_UNISCRIBE
 HB_SHAPER_IMPLEMENT (uniscribe)
@@ -45,12 +50,11 @@
 #endif
 #ifdef HAVE_CORETEXT
 HB_SHAPER_IMPLEMENT (coretext)
-
-/* Only picks up fonts that have a "mort" or "morx" table.
-   Probably going to be removed https://github.com/harfbuzz/harfbuzz/issues/1478 */
-HB_SHAPER_IMPLEMENT (coretext_aat)
 #endif
 
-#ifdef HAVE_FALLBACK
+#ifndef HB_NO_FALLBACK_SHAPE
 HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
 #endif
+
+
+#endif
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index 575ab1f..0ea68ad 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -34,6 +34,9 @@
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
+#ifndef HB_NO_SHAPER
+static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled.");
+#endif
 
 #if HB_USE_ATEXIT
 static void free_static_shapers ();
diff --git a/src/hb-static.cc b/src/hb-static.cc
index 4c51588..08a2f21 100644
--- a/src/hb-static.cc
+++ b/src/hb-static.cc
@@ -37,9 +37,10 @@
 #include "hb-ot-maxp-table.hh"
 
 #ifndef HB_NO_VISIBILITY
+#include "hb-ot-name-language-static.hh"
 
-hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {};
-/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {};
+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
 
 DEFINE_NULL_NAMESPACE_BYTES (OT, Index) =  {0xFF,0xFF};
 DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh
index c4cf666..1c67ab4 100644
--- a/src/hb-string-array.hh
+++ b/src/hb-string-array.hh
@@ -48,7 +48,7 @@
 #include HB_STRING_ARRAY_LIST
 #undef _S
   } st;
-  char str[VAR];
+  char str[HB_VAR_ARRAY];
 }
 HB_STRING_ARRAY_POOL_NAME =
 {
diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc
index b6127a9..c9a880a 100644
--- a/src/hb-subset-cff-common.cc
+++ b/src/hb-subset-cff-common.cc
@@ -24,6 +24,10 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-ot-cff-common.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-subset-cff-common.hh"
@@ -43,40 +47,46 @@
  **/
 
 bool
-hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
-			    unsigned int fdCount,
-			    const FDSelect &src, /* IN */
-			    unsigned int &subset_fd_count /* OUT */,
-			    unsigned int &subset_fdselect_size /* OUT */,
-			    unsigned int &subset_fdselect_format /* OUT */,
-			    hb_vector_t<code_pair> &fdselect_ranges /* OUT */,
-			    Remap &fdmap /* OUT */)
+hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
+			     unsigned int fdCount,
+			     const FDSelect &src, /* IN */
+			     unsigned int &subset_fd_count /* OUT */,
+			     unsigned int &subset_fdselect_size /* OUT */,
+			     unsigned int &subset_fdselect_format /* OUT */,
+			     hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */,
+			     hb_inc_bimap_t &fdmap /* OUT */)
 {
   subset_fd_count = 0;
   subset_fdselect_size = 0;
   subset_fdselect_format = 0;
-  unsigned int  num_ranges = 0;
+  unsigned int num_ranges = 0;
 
-  unsigned int subset_num_glyphs = glyphs.len;
+  unsigned int subset_num_glyphs = plan->num_output_glyphs ();
   if (subset_num_glyphs == 0)
     return true;
 
   {
     /* use hb_set to determine the subset of font dicts */
-    hb_set_t  *set = hb_set_create ();
-    if (set == &Null (hb_set_t))
-      return false;
-    hb_codepoint_t  prev_fd = CFF_UNDEF_CODE;
+    hb_set_t *set = hb_set_create ();
+    if (unlikely (set == &Null (hb_set_t))) return false;
+    hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
     for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
     {
-      hb_codepoint_t  fd = src.get_fd (glyphs[i]);
+      hb_codepoint_t glyph;
+      hb_codepoint_t fd;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+	/* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
+	glyph = i;
+      }
+      fd = src.get_fd (glyph);
       set->add (fd);
 
       if (fd != prev_fd)
       {
 	num_ranges++;
 	prev_fd = fd;
-	code_pair pair = { fd, i };
+	code_pair_t pair = { fd, i };
 	fdselect_ranges.push (pair);
       }
     }
@@ -91,22 +101,18 @@
     else
     {
       /* create a fdmap */
-      if (!fdmap.reset (fdCount))
-      {
-	hb_set_destroy (set);
-	return false;
-      }
+      fdmap.reset ();
 
-      hb_codepoint_t  fd = CFF_UNDEF_CODE;
+      hb_codepoint_t fd = CFF_UNDEF_CODE;
       while (set->next (&fd))
 	fdmap.add (fd);
       hb_set_destroy (set);
-      if (unlikely (fdmap.get_count () != subset_fd_count))
+      if (unlikely (fdmap.get_population () != subset_fd_count))
       	return false;
     }
 
     /* update each font dict index stored as "code" in fdselect_ranges */
-    for (unsigned int i = 0; i < fdselect_ranges.len; i++)
+    for (unsigned int i = 0; i < fdselect_ranges.length; i++)
       fdselect_ranges[i].code = fdmap[fdselect_ranges[i].code];
   }
 
@@ -145,21 +151,21 @@
 template <typename FDSELECT3_4>
 static inline bool
 serialize_fdselect_3_4 (hb_serialize_context_t *c,
-			  const unsigned int num_glyphs,
-			  const FDSelect &src,
-			  unsigned int size,
-			  const hb_vector_t<code_pair> &fdselect_ranges)
+			const unsigned int num_glyphs,
+			const FDSelect &src,
+			unsigned int size,
+			const hb_vector_t<code_pair_t> &fdselect_ranges)
 {
   TRACE_SERIALIZE (this);
   FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
   if (unlikely (p == nullptr)) return_trace (false);
-  p->nRanges.set (fdselect_ranges.len);
-  for (unsigned int i = 0; i < fdselect_ranges.len; i++)
+  p->nRanges () = fdselect_ranges.length;
+  for (unsigned int i = 0; i < fdselect_ranges.length; i++)
   {
-    p->ranges[i].first.set (fdselect_ranges[i].glyph);
-    p->ranges[i].fd.set (fdselect_ranges[i].code);
+    p->ranges[i].first = fdselect_ranges[i].glyph;
+    p->ranges[i].fd = fdselect_ranges[i].code;
   }
-  p->sentinel().set (num_glyphs);
+  p->sentinel () = num_glyphs;
   return_trace (true);
 }
 
@@ -169,58 +175,53 @@
  **/
 bool
 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
-			  const unsigned int num_glyphs,
-			  const FDSelect &src,
-			  unsigned int fd_count,
-			  unsigned int fdselect_format,
-			  unsigned int size,
-			  const hb_vector_t<code_pair> &fdselect_ranges)
+			   const unsigned int num_glyphs,
+			   const FDSelect &src,
+			   unsigned int fd_count,
+			   unsigned int fdselect_format,
+			   unsigned int size,
+			   const hb_vector_t<code_pair_t> &fdselect_ranges)
 {
   TRACE_SERIALIZE (this);
-  FDSelect  *p = c->allocate_min<FDSelect> ();
+  FDSelect *p = c->allocate_min<FDSelect> ();
   if (unlikely (p == nullptr)) return_trace (false);
-  p->format.set (fdselect_format);
+  p->format = fdselect_format;
   size -= FDSelect::min_size;
 
   switch (fdselect_format)
   {
 #if CFF_SERIALIZE_FDSELECT_0
-    case 0:
+  case 0:
+  {
+    FDSelect0 *p = c->allocate_size<FDSelect0> (size);
+    if (unlikely (p == nullptr)) return_trace (false);
+    unsigned int range_index = 0;
+    unsigned int fd = fdselect_ranges[range_index++].code;
+    for (unsigned int i = 0; i < num_glyphs; i++)
     {
-      FDSelect0 *p = c->allocate_size<FDSelect0> (size);
-      if (unlikely (p == nullptr)) return_trace (false);
-      unsigned int range_index = 0;
-      unsigned int  fd = fdselect_ranges[range_index++].code;
-      for (unsigned int i = 0; i < num_glyphs; i++)
+      if ((range_index < fdselect_ranges.len) &&
+	  (i >= fdselect_ranges[range_index].glyph))
       {
-	if ((range_index < fdselect_ranges.len) &&
-	    (i >= fdselect_ranges[range_index].glyph))
-	{
-	  fd = fdselect_ranges[range_index++].code;
-	}
-	p->fds[i].set (fd);
+	fd = fdselect_ranges[range_index++].code;
       }
-      break;
+      p->fds[i] = fd;
     }
+    return_trace (true);
+  }
 #endif /* CFF_SERIALIZE_FDSELECT_0 */
 
-    case 3:
-      return serialize_fdselect_3_4<FDSelect3> (c,
-						num_glyphs,
-						src,
-						size,
-						fdselect_ranges);
+  case 3:
+    return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src,
+					      size, fdselect_ranges);
 
-    case 4:
-      return serialize_fdselect_3_4<FDSelect4> (c,
-						num_glyphs,
-						src,
-						size,
-						fdselect_ranges);
+  case 4:
+    return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src,
+					      size, fdselect_ranges);
 
-    default:
-      assert(false);
+  default:
+    return_trace (false);
   }
-
-  return_trace (true);
 }
+
+
+#endif
diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh
index 820a090..3c66119 100644
--- a/src/hb-subset-cff-common.hh
+++ b/src/hb-subset-cff-common.hh
@@ -35,16 +35,16 @@
 namespace CFF {
 
 /* Used for writing a temporary charstring */
-struct StrEncoder
+struct str_encoder_t
 {
-  StrEncoder (StrBuff &buff_)
+  str_encoder_t (str_buff_t &buff_)
     : buff (buff_), error (false) {}
 
   void reset () { buff.resize (0); }
 
   void encode_byte (unsigned char b)
   {
-    if (unlikely (buff.push ((const char)b) == &Crap(char)))
+    if (unlikely (buff.push (b) == &Crap(unsigned char)))
       set_error ();
   }
 
@@ -79,7 +79,7 @@
     }
   }
 
-  void encode_num (const Number& n)
+  void encode_num (const number_t& n)
   {
     if (n.in_int_range ())
     {
@@ -96,7 +96,7 @@
     }
   }
 
-  void encode_op (OpCode op)
+  void encode_op (op_code_t op)
   {
     if (Is_OpCode_ESC (op))
     {
@@ -107,16 +107,16 @@
       encode_byte (op);
   }
 
-  void copy_str (const ByteStr &str)
+  void copy_str (const byte_str_t &str)
   {
-    unsigned int  offset = buff.len;
-    buff.resize (offset + str.len);
-    if (unlikely (buff.len < offset + str.len))
+    unsigned int  offset = buff.length;
+    buff.resize (offset + str.length);
+    if (unlikely (buff.length < offset + str.length))
     {
       set_error ();
       return;
     }
-    memcpy (&buff[offset], &str.str[0], str.len);
+    memcpy (&buff[offset], &str[0], str.length);
   }
 
   bool is_error () const { return error; }
@@ -124,12 +124,12 @@
   protected:
   void set_error () { error = true; }
 
-  StrBuff &buff;
+  str_buff_t &buff;
   bool    error;
 };
 
-struct CFFSubTableOffsets {
-  CFFSubTableOffsets () : privateDictsOffset (0)
+struct cff_sub_table_offsets_t {
+  cff_sub_table_offsets_t () : privateDictsOffset (0)
   {
     topDictInfo.init ();
     FDSelectInfo.init ();
@@ -139,23 +139,23 @@
     localSubrsInfos.init ();
   }
 
-  ~CFFSubTableOffsets () { localSubrsInfos.fini (); }
+  ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); }
 
-  TableInfo     topDictInfo;
-  TableInfo     FDSelectInfo;
-  TableInfo     FDArrayInfo;
-  TableInfo     charStringsInfo;
+  table_info_t     topDictInfo;
+  table_info_t     FDSelectInfo;
+  table_info_t     FDArrayInfo;
+  table_info_t     charStringsInfo;
   unsigned int  privateDictsOffset;
-  TableInfo     globalSubrsInfo;
-  hb_vector_t<TableInfo>  localSubrsInfos;
+  table_info_t     globalSubrsInfo;
+  hb_vector_t<table_info_t>  localSubrsInfos;
 };
 
-template <typename OPSTR=OpStr>
-struct CFFTopDict_OpSerializer : OpSerializer
+template <typename OPSTR=op_str_t>
+struct cff_top_dict_op_serializer_t : op_serializer_t
 {
   bool serialize (hb_serialize_context_t *c,
 		  const OPSTR &opstr,
-		  const CFFSubTableOffsets &offsets) const
+		  const cff_sub_table_offsets_t &offsets) const
   {
     TRACE_SERIALIZE (this);
 
@@ -186,16 +186,16 @@
 	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 
       default:
-	return opstr.str.len;
+	return opstr.str.length;
     }
   }
 };
 
-struct CFFFontDict_OpSerializer : OpSerializer
+struct cff_font_dict_op_serializer_t : op_serializer_t
 {
   bool serialize (hb_serialize_context_t *c,
-		  const OpStr &opstr,
-		  const TableInfo &privateDictInfo) const
+		  const op_str_t &opstr,
+		  const table_info_t &privateDictInfo) const
   {
     TRACE_SERIALIZE (this);
 
@@ -209,40 +209,40 @@
       /* serialize the opcode */
       HBUINT8 *p = c->allocate_size<HBUINT8> (1);
       if (unlikely (p == nullptr)) return_trace (false);
-      p->set (OpCode_Private);
+      *p = OpCode_Private;
 
       return_trace (true);
     }
     else
     {
-      HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
+      HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
       if (unlikely (d == nullptr)) return_trace (false);
-      memcpy (d, &opstr.str.str[0], opstr.str.len);
+      memcpy (d, &opstr.str[0], opstr.str.length);
     }
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (const OpStr &opstr) const
+  unsigned int calculate_serialized_size (const op_str_t &opstr) const
   {
     if (opstr.op == OpCode_Private)
       return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
     else
-      return opstr.str.len;
+      return opstr.str.length;
   }
 };
 
-struct CFFPrivateDict_OpSerializer : OpSerializer
+struct cff_private_dict_op_serializer_t : op_serializer_t
 {
-  CFFPrivateDict_OpSerializer (bool desubroutinize_, bool drop_hints_)
+  cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
     : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
 
   bool serialize (hb_serialize_context_t *c,
-		  const OpStr &opstr,
+		  const op_str_t &opstr,
 		  const unsigned int subrsOffset) const
   {
     TRACE_SERIALIZE (this);
 
-    if (drop_hints && DictOpSet::is_hint_op (opstr.op))
+    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
       return true;
     if (opstr.op == OpCode_Subrs)
     {
@@ -255,10 +255,10 @@
       return_trace (copy_opstr (c, opstr));
   }
 
-  unsigned int calculate_serialized_size (const OpStr &opstr,
+  unsigned int calculate_serialized_size (const op_str_t &opstr,
 					  bool has_localsubr=true) const
   {
-    if (drop_hints && DictOpSet::is_hint_op (opstr.op))
+    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
       return 0;
     if (opstr.op == OpCode_Subrs)
     {
@@ -268,7 +268,7 @@
 	return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op);
     }
     else
-      return opstr.str.len;
+      return opstr.str.length;
   }
 
   protected:
@@ -276,39 +276,41 @@
   const bool  drop_hints;
 };
 
-struct FlattenParam
+struct flatten_param_t
 {
-  StrBuff     &flatStr;
+  str_buff_t     &flatStr;
   bool	drop_hints;
 };
 
-template <typename ACC, typename ENV, typename OPSET>
-struct SubrFlattener
+template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
+struct subr_flattener_t
 {
-  SubrFlattener (const ACC &acc_,
-			const hb_vector_t<hb_codepoint_t> &glyphs_,
-			bool drop_hints_)
-    : acc (acc_),
-      glyphs (glyphs_),
-      drop_hints (drop_hints_)
-  {}
+  subr_flattener_t (const ACC &acc_,
+		    const hb_subset_plan_t *plan_)
+		   : acc (acc_), plan (plan_) {}
 
-  bool flatten (StrBuffArray &flat_charstrings)
+  bool flatten (str_buff_vec_t &flat_charstrings)
   {
-    if (!flat_charstrings.resize (glyphs.len))
+    if (!flat_charstrings.resize (plan->num_output_glyphs ()))
       return false;
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       flat_charstrings[i].init ();
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      hb_codepoint_t  glyph = glyphs[i];
-      const ByteStr str = (*acc.charStrings)[glyph];
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+      	/* add an endchar only charstring for a missing glyph if CFF1 */
+      	if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
+      	continue;
+      }
+      const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
       	return false;
-      CSInterpreter<ENV, OPSET, FlattenParam> interp;
+      cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
       interp.env.init (str, acc, fd);
-      FlattenParam  param = { flat_charstrings[i], drop_hints };
+      flatten_param_t  param = { flat_charstrings[i], plan->drop_hints };
       if (unlikely (!interp.interpret (param)))
 	return false;
     }
@@ -316,13 +318,12 @@
   }
 
   const ACC &acc;
-  const hb_vector_t<hb_codepoint_t> &glyphs;
-  bool  drop_hints;
+  const hb_subset_plan_t *plan;
 };
 
-struct SubrClosures
+struct subr_closures_t
 {
-  SubrClosures () : valid (false), global_closure (nullptr)
+  subr_closures_t () : valid (false), global_closure (nullptr)
   { local_closures.init (); }
 
   void init (unsigned int fd_count)
@@ -334,7 +335,7 @@
     if (!local_closures.resize (fd_count))
       valid = false;
 
-    for (unsigned int i = 0; i < local_closures.len; i++)
+    for (unsigned int i = 0; i < local_closures.length; i++)
     {
       local_closures[i] = hb_set_create ();
       if (local_closures[i] == hb_set_get_empty ())
@@ -345,7 +346,7 @@
   void fini ()
   {
     hb_set_destroy (global_closure);
-    for (unsigned int i = 0; i < local_closures.len; i++)
+    for (unsigned int i = 0; i < local_closures.length; i++)
       hb_set_destroy (local_closures[i]);
     local_closures.fini ();
   }
@@ -353,7 +354,7 @@
   void reset ()
   {
     hb_set_clear (global_closure);
-    for (unsigned int i = 0; i < local_closures.len; i++)
+    for (unsigned int i = 0; i < local_closures.length; i++)
       hb_set_clear (local_closures[i]);
   }
 
@@ -363,18 +364,18 @@
   hb_vector_t<hb_set_t *> local_closures;
 };
 
-struct ParsedCSOp : OpStr
+struct parsed_cs_op_t : op_str_t
 {
   void init (unsigned int subr_num_ = 0)
   {
-    OpStr::init ();
+    op_str_t::init ();
     subr_num = subr_num_;
     drop_flag = false;
     keep_flag = false;
     skip_flag = false;
   }
 
-  void fini () { OpStr::fini (); }
+  void fini () { op_str_t::fini (); }
 
   bool for_drop () const { return drop_flag; }
   void set_drop ()       { if (!for_keep ()) drop_flag = true; }
@@ -393,7 +394,7 @@
   bool	  skip_flag : 1;
 };
 
-struct ParsedCStr : ParsedValues<ParsedCSOp>
+struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
 {
   void init ()
   {
@@ -403,13 +404,13 @@
     has_prefix_ = false;
   }
 
-  void add_op (OpCode op, const SubByteStr& substr)
+  void add_op (op_code_t op, const byte_str_ref_t& str_ref)
   {
     if (!is_parsed ())
-      SUPER::add_op (op, substr);
+      SUPER::add_op (op, str_ref);
   }
 
-  void add_call_op (OpCode op, const SubByteStr& substr, unsigned int subr_num)
+  void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num)
   {
     if (!is_parsed ())
     {
@@ -417,13 +418,13 @@
       if (likely (parsed_len > 0))
 	values[parsed_len-1].set_skip ();
 
-      ParsedCSOp val;
+      parsed_cs_op_t val;
       val.init (subr_num);
-      SUPER::add_op (op, substr, val);
+      SUPER::add_op (op, str_ref, val);
     }
   }
 
-  void set_prefix (const Number &num, OpCode op = OpCode_Invalid)
+  void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid)
   {
     has_prefix_ = true;
     prefix_op_ = op;
@@ -432,7 +433,7 @@
 
   bool at_end (unsigned int pos) const
   {
-    return ((pos + 1 >= values.len) /* CFF2 */
+    return ((pos + 1 >= values.length) /* CFF2 */
 	|| (values[pos + 1].op == OpCode_return));
   }
 
@@ -446,42 +447,42 @@
   void set_vsindex_dropped ()      { vsindex_dropped = true; }
 
   bool has_prefix () const          { return has_prefix_; }
-  OpCode prefix_op () const         { return prefix_op_; }
-  const Number &prefix_num () const { return prefix_num_; }
+  op_code_t prefix_op () const         { return prefix_op_; }
+  const number_t &prefix_num () const { return prefix_num_; }
 
   protected:
   bool    parsed;
   bool    hint_dropped;
   bool    vsindex_dropped;
   bool    has_prefix_;
-  OpCode  prefix_op_;
-  Number  prefix_num_;
+  op_code_t	prefix_op_;
+  number_t 	prefix_num_;
 
   private:
-  typedef ParsedValues<ParsedCSOp> SUPER;
+  typedef parsed_values_t<parsed_cs_op_t> SUPER;
 };
 
-struct ParsedCStrs : hb_vector_t<ParsedCStr>
+struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
 {
   void init (unsigned int len_ = 0)
   {
     SUPER::init ();
     resize (len_);
-    for (unsigned int i = 0; i < len; i++)
+    for (unsigned int i = 0; i < length; i++)
       (*this)[i].init ();
   }
   void fini () { SUPER::fini_deep (); }
 
   private:
-  typedef hb_vector_t<ParsedCStr> SUPER;
+  typedef hb_vector_t<parsed_cs_str_t> SUPER;
 };
 
-struct SubrSubsetParam
+struct subr_subset_param_t
 {
-  void init (ParsedCStr *parsed_charstring_,
-		    ParsedCStrs *parsed_global_subrs_, ParsedCStrs *parsed_local_subrs_,
-		    hb_set_t *global_closure_, hb_set_t *local_closure_,
-		    bool drop_hints_)
+  void init (parsed_cs_str_t *parsed_charstring_,
+	     parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_,
+	     hb_set_t *global_closure_, hb_set_t *local_closure_,
+	     bool drop_hints_)
   {
     parsed_charstring = parsed_charstring_;
     current_parsed_str = parsed_charstring;
@@ -492,7 +493,7 @@
     drop_hints = drop_hints_;
   }
 
-  ParsedCStr *get_parsed_str_for_context (CallContext &context)
+  parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context)
   {
     switch (context.type)
     {
@@ -500,12 +501,12 @@
 	return parsed_charstring;
 
       case CSType_LocalSubr:
-	if (likely (context.subr_num < parsed_local_subrs->len))
+	if (likely (context.subr_num < parsed_local_subrs->length))
 	  return &(*parsed_local_subrs)[context.subr_num];
 	break;
 
       case CSType_GlobalSubr:
-	if (likely (context.subr_num < parsed_global_subrs->len))
+	if (likely (context.subr_num < parsed_global_subrs->length))
 	  return &(*parsed_global_subrs)[context.subr_num];
 	break;
     }
@@ -515,13 +516,13 @@
   template <typename ENV>
   void set_current_str (ENV &env, bool calling)
   {
-    ParsedCStr  *parsed_str = get_parsed_str_for_context (env.context);
+    parsed_cs_str_t  *parsed_str = get_parsed_str_for_context (env.context);
     if (likely (parsed_str != nullptr))
     {
       /* If the called subroutine is parsed partially but not completely yet,
        * it must be because we are calling it recursively.
        * Handle it as an error. */
-      if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.len > 0)))
+      if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
       	env.set_error ();
       else
       	current_parsed_str = parsed_str;
@@ -530,49 +531,39 @@
       env.set_error ();
   }
 
-  ParsedCStr    *current_parsed_str;
+  parsed_cs_str_t	*current_parsed_str;
 
-  ParsedCStr    *parsed_charstring;
-  ParsedCStrs   *parsed_global_subrs;
-  ParsedCStrs   *parsed_local_subrs;
+  parsed_cs_str_t	*parsed_charstring;
+  parsed_cs_str_vec_t	*parsed_global_subrs;
+  parsed_cs_str_vec_t	*parsed_local_subrs;
   hb_set_t      *global_closure;
   hb_set_t      *local_closure;
   bool	  drop_hints;
 };
 
-struct SubrRemap : Remap
+struct subr_remap_t : hb_inc_bimap_t
 {
   void create (hb_set_t *closure)
   {
     /* create a remapping of subroutine numbers from old to new.
      * no optimization based on usage counts. fonttools doesn't appear doing that either.
      */
-    reset (closure->get_max () + 1);
-    for (hb_codepoint_t old_num = 0; old_num < len; old_num++)
-    {
-      if (hb_set_has (closure, old_num))
-	add (old_num);
-    }
 
-    if (get_count () < 1240)
+    hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
+    while (hb_set_next (closure, &old_num))
+      add (old_num);
+
+    if (get_population () < 1240)
       bias = 107;
-    else if (get_count () < 33900)
+    else if (get_population () < 33900)
       bias = 1131;
     else
       bias = 32768;
   }
 
-  hb_codepoint_t operator[] (unsigned int old_num) const
-  {
-    if (old_num >= len)
-      return CFF_UNDEF_CODE;
-    else
-      return Remap::operator[] (old_num);
-  }
-
   int biased_num (unsigned int old_num) const
   {
-    hb_codepoint_t new_num = (*this)[old_num];
+    hb_codepoint_t new_num = get (old_num);
     return (int)new_num - bias;
   }
 
@@ -580,15 +571,15 @@
   int bias;
 };
 
-struct SubrRemaps
+struct subr_remaps_t
 {
-  SubrRemaps ()
+  subr_remaps_t ()
   {
     global_remap.init ();
     local_remaps.init ();
   }
 
-  ~SubrRemaps () { fini (); }
+  ~subr_remaps_t () { fini (); }
 
   void init (unsigned int fdCount)
   {
@@ -597,10 +588,10 @@
       local_remaps[i].init ();
   }
 
-  void create (SubrClosures& closures)
+  void create (subr_closures_t& closures)
   {
     global_remap.create (closures.global_closure);
-    for (unsigned int i = 0; i < local_remaps.len; i++)
+    for (unsigned int i = 0; i < local_remaps.length; i++)
       local_remaps[i].create (closures.local_closures[i]);
   }
 
@@ -610,21 +601,22 @@
     local_remaps.fini_deep ();
   }
 
-  SubrRemap	       global_remap;
-  hb_vector_t<SubrRemap>  local_remaps;
+  subr_remap_t	       global_remap;
+  hb_vector_t<subr_remap_t>  local_remaps;
 };
 
-template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET>
-struct SubrSubsetter
+template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
+struct subr_subsetter_t
 {
-  SubrSubsetter ()
+  subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
+    : acc (acc_), plan (plan_)
   {
     parsed_charstrings.init ();
     parsed_global_subrs.init ();
     parsed_local_subrs.init ();
   }
 
-  ~SubrSubsetter ()
+  ~subr_subsetter_t ()
   {
     closures.fini ();
     remaps.fini ();
@@ -647,12 +639,12 @@
    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
    */
-  bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints)
+  bool subset (void)
   {
     closures.init (acc.fdCount);
     remaps.init (acc.fdCount);
 
-    parsed_charstrings.init (glyphs.len);
+    parsed_charstrings.init (plan->num_output_glyphs ());
     parsed_global_subrs.init (acc.globalSubrs->count);
     parsed_local_subrs.resize (acc.fdCount);
     for (unsigned int i = 0; i < acc.fdCount; i++)
@@ -663,22 +655,24 @@
       return false;
 
     /* phase 1 & 2 */
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      hb_codepoint_t  glyph = glyphs[i];
-      const ByteStr str = (*acc.charStrings)[glyph];
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      	continue;
+      const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
       	return false;
 
-      CSInterpreter<ENV, OPSET, SubrSubsetParam> interp;
+      cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
       interp.env.init (str, acc, fd);
 
-      SubrSubsetParam  param;
+      subr_subset_param_t  param;
       param.init (&parsed_charstrings[i],
 		  &parsed_global_subrs,  &parsed_local_subrs[fd],
 		  closures.global_closure, closures.local_closures[fd],
-		  drop_hints);
+		  plan->drop_hints);
 
       if (unlikely (!interp.interpret (param)))
 	return false;
@@ -687,21 +681,24 @@
       SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]);
     }
 
-    if (drop_hints)
+    if (plan->drop_hints)
     {
       /* mark hint ops and arguments for drop */
-      for (unsigned int i = 0; i < glyphs.len; i++)
+      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       {
-	unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
+	hb_codepoint_t  glyph;
+	if (!plan->old_gid_for_new_gid (i, &glyph))
+	  continue;
+	unsigned int fd = acc.fdSelect->get_fd (glyph);
 	if (unlikely (fd >= acc.fdCount))
 	  return false;
-	SubrSubsetParam  param;
+	subr_subset_param_t  param;
 	param.init (&parsed_charstrings[i],
 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
 		    closures.global_closure, closures.local_closures[fd],
-		    drop_hints);
+		    plan->drop_hints);
 
-	DropHintsParam  drop;
+	drop_hints_param_t  drop;
 	if (drop_hints_in_str (parsed_charstrings[i], param, drop))
 	{
 	  parsed_charstrings[i].set_hint_dropped ();
@@ -712,16 +709,19 @@
 
       /* after dropping hints recreate closures of actually used subrs */
       closures.reset ();
-      for (unsigned int i = 0; i < glyphs.len; i++)
+      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       {
-	unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
+	hb_codepoint_t  glyph;
+	if (!plan->old_gid_for_new_gid (i, &glyph))
+	  continue;
+	unsigned int fd = acc.fdSelect->get_fd (glyph);
 	if (unlikely (fd >= acc.fdCount))
 	  return false;
-	SubrSubsetParam  param;
+	subr_subset_param_t  param;
 	param.init (&parsed_charstrings[i],
 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
 		    closures.global_closure, closures.local_closures[fd],
-		    drop_hints);
+		    plan->drop_hints);
 	collect_subr_refs_in_str (parsed_charstrings[i], param);
       }
     }
@@ -731,13 +731,20 @@
     return true;
   }
 
-  bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, StrBuffArray &buffArray) const
+  bool encode_charstrings (str_buff_vec_t &buffArray) const
   {
-    if (unlikely (!buffArray.resize (glyphs.len)))
+    if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
       return false;
-    for (unsigned int i = 0; i < glyphs.len; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      unsigned int  fd = acc.fdSelect->get_fd (glyphs[i]);
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+      	/* add an endchar only charstring for a missing glyph if CFF1 */
+      	if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
+      	continue;
+      }
+      unsigned int  fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
       	return false;
       if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
@@ -746,13 +753,13 @@
     return true;
   }
 
-  bool encode_subrs (const ParsedCStrs &subrs, const SubrRemap& remap, unsigned int fd, StrBuffArray &buffArray) const
+  bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
   {
-    unsigned int  count = remap.get_count ();
+    unsigned int  count = remap.get_population ();
 
     if (unlikely (!buffArray.resize (count)))
       return false;
-    for (unsigned int old_num = 0; old_num < subrs.len; old_num++)
+    for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
     {
       hb_codepoint_t new_num = remap[old_num];
       if (new_num != CFF_UNDEF_CODE)
@@ -764,37 +771,39 @@
     return true;
   }
 
-  bool encode_globalsubrs (StrBuffArray &buffArray)
+  bool encode_globalsubrs (str_buff_vec_t &buffArray)
   {
     return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray);
   }
 
-  bool encode_localsubrs (unsigned int fd, StrBuffArray &buffArray) const
+  bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
   {
     return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray);
   }
 
   protected:
-  struct DropHintsParam
+  struct drop_hints_param_t
   {
-    DropHintsParam ()
+    drop_hints_param_t ()
       : seen_moveto (false),
 	ends_in_hint (false),
+	all_dropped (false),
 	vsindex_dropped (false) {}
 
     bool  seen_moveto;
     bool  ends_in_hint;
+    bool  all_dropped;
     bool  vsindex_dropped;
   };
 
-  bool drop_hints_in_subr (ParsedCStr &str, unsigned int pos,
-			   ParsedCStrs &subrs, unsigned int subr_num,
-			   const SubrSubsetParam &param, DropHintsParam &drop)
+  bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos,
+			   parsed_cs_str_vec_t &subrs, unsigned int subr_num,
+			   const subr_subset_param_t &param, drop_hints_param_t &drop)
   {
     drop.ends_in_hint = false;
     bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
 
-    /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto),
+    /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
      * then this entire subroutine must be a hint. drop its call. */
     if (drop.ends_in_hint)
     {
@@ -804,16 +813,20 @@
       if (!str.at_end (pos))
 	drop.ends_in_hint = false;
     }
+    else if (drop.all_dropped)
+    {
+      str.values[pos].set_drop ();
+    }
 
     return has_hint;
   }
 
   /* returns true if it sees a hint op before the first moveto */
-  bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam &param, DropHintsParam &drop)
+  bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param, drop_hints_param_t &drop)
   {
     bool  seen_hint = false;
 
-    for (unsigned int pos = 0; pos < str.values.len; pos++)
+    for (unsigned int pos = 0; pos < str.values.length; pos++)
     {
       bool  has_hint = false;
       switch (str.values[pos].op)
@@ -822,7 +835,6 @@
 	  has_hint = drop_hints_in_subr (str, pos,
 					*param.parsed_local_subrs, str.values[pos].subr_num,
 					param, drop);
-
 	  break;
 
 	case OpCode_callgsubr:
@@ -868,7 +880,7 @@
       {
 	for (int i = pos - 1; i >= 0; i--)
 	{
-	  ParsedCSOp  &csop = str.values[(unsigned)i];
+	  parsed_cs_op_t  &csop = str.values[(unsigned)i];
 	  if (csop.for_drop ())
 	    break;
 	  csop.set_drop ();
@@ -879,21 +891,38 @@
       }
     }
 
+    /* Raise all_dropped flag if all operators except return are dropped from a subr.
+     * It may happen even after seeing the first moveto if a subr contains
+     * only (usually one) hintmask operator, then calls to this subr can be dropped.
+     */
+    drop.all_dropped = true;
+    for (unsigned int pos = 0; pos < str.values.length; pos++)
+    {
+      parsed_cs_op_t  &csop = str.values[pos];
+      if (csop.op == OpCode_return)
+      	break;
+      if (!csop.for_drop ())
+      {
+      	drop.all_dropped = false;
+      	break;
+      }
+    }
+
     return seen_hint;
   }
 
-  void collect_subr_refs_in_subr (ParsedCStr &str, unsigned int pos,
-				  unsigned int subr_num, ParsedCStrs &subrs,
+  void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
+				  unsigned int subr_num, parsed_cs_str_vec_t &subrs,
 				  hb_set_t *closure,
-				  const SubrSubsetParam &param)
+				  const subr_subset_param_t &param)
   {
-    hb_set_add (closure, subr_num);
+    closure->add (subr_num);
     collect_subr_refs_in_str (subrs[subr_num], param);
   }
 
-  void collect_subr_refs_in_str (ParsedCStr &str, const SubrSubsetParam &param)
+  void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param)
   {
-    for (unsigned int pos = 0; pos < str.values.len; pos++)
+    for (unsigned int pos = 0; pos < str.values.length; pos++)
     {
       if (!str.values[pos].for_drop ())
       {
@@ -917,10 +946,10 @@
     }
   }
 
-  bool encode_str (const ParsedCStr &str, const unsigned int fd, StrBuff &buff) const
+  bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
   {
     buff.init ();
-    StrEncoder  encoder (buff);
+    str_encoder_t  encoder (buff);
     encoder.reset ();
     /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
      * re-insert it at the beginning of charstreing */
@@ -932,7 +961,7 @@
     }
     for (unsigned int i = 0; i < str.get_count(); i++)
     {
-      const ParsedCSOp  &opstr = str.values[i];
+      const parsed_cs_op_t  &opstr = str.values[i];
       if (!opstr.for_drop () && !opstr.for_skip ())
       {
 	switch (opstr.op)
@@ -957,28 +986,32 @@
   }
 
   protected:
-  SubrClosures	      closures;
+  const ACC   			&acc;
+  const hb_subset_plan_t	*plan;
 
-  ParsedCStrs	       parsed_charstrings;
-  ParsedCStrs	       parsed_global_subrs;
-  hb_vector_t<ParsedCStrs>  parsed_local_subrs;
+  subr_closures_t		closures;
 
-  SubrRemaps		remaps;
+  parsed_cs_str_vec_t		parsed_charstrings;
+  parsed_cs_str_vec_t		parsed_global_subrs;
+  hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs;
+
+  subr_remaps_t			remaps;
 
   private:
   typedef typename SUBRS::count_type subr_count_type;
 };
-};  /* namespace CFF */
+
+} /* namespace CFF */
 
 HB_INTERNAL bool
-hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
+hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
 			    unsigned int fdCount,
 			    const CFF::FDSelect &src, /* IN */
 			    unsigned int &subset_fd_count /* OUT */,
 			    unsigned int &subset_fdselect_size /* OUT */,
 			    unsigned int &subset_fdselect_format /* OUT */,
-			    hb_vector_t<CFF::code_pair> &fdselect_ranges /* OUT */,
-			    CFF::Remap &fdmap /* OUT */);
+			    hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
+			    hb_inc_bimap_t &fdmap /* OUT */);
 
 HB_INTERNAL bool
 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
@@ -987,6 +1020,6 @@
 			  unsigned int fd_count,
 			  unsigned int fdselect_format,
 			  unsigned int size,
-			  const hb_vector_t<CFF::code_pair> &fdselect_ranges);
+			  const hb_vector_t<CFF::code_pair_t> &fdselect_ranges);
 
 #endif /* HB_SUBSET_CFF_COMMON_HH */
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index 09364a2..e9e0757 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -24,9 +24,14 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-open-type.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-set.h"
+#include "hb-bimap.hh"
 #include "hb-subset-cff1.hh"
 #include "hb-subset-plan.hh"
 #include "hb-subset-cff-common.hh"
@@ -34,12 +39,12 @@
 
 using namespace CFF;
 
-struct RemapSID : Remap
+struct remap_sid_t : hb_inc_bimap_t
 {
   unsigned int add (unsigned int sid)
   {
     if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
-      return offset_sid (Remap::add (unoffset_sid (sid)));
+      return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid)));
     else
       return sid;
   }
@@ -49,7 +54,7 @@
     if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
       return sid;
     else
-      return offset_sid (Remap::operator [] (unoffset_sid (sid)));
+      return offset_sid (get (unoffset_sid (sid)));
   }
 
   static const unsigned int num_std_strings = 391;
@@ -59,10 +64,10 @@
   static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
 };
 
-struct CFF1SubTableOffsets : CFFSubTableOffsets
+struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t
 {
-  CFF1SubTableOffsets ()
-    : CFFSubTableOffsets (),
+  cff1_sub_table_offsets_t ()
+    : cff_sub_table_offsets_t (),
       nameIndexOffset (0),
       encodingOffset (0)
   {
@@ -72,16 +77,16 @@
   }
 
   unsigned int  nameIndexOffset;
-  TableInfo     stringIndexInfo;
+  table_info_t	stringIndexInfo;
   unsigned int  encodingOffset;
-  TableInfo     charsetInfo;
-  TableInfo     privateDictInfo;
+  table_info_t	charsetInfo;
+  table_info_t	privateDictInfo;
 };
 
-/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */
-struct CFF1TopDictValuesMod : CFF1TopDictValues
+/* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
+struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
 {
-  void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues))
+  void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t))
   {
     SUPER::init ();
     base = base_;
@@ -90,47 +95,47 @@
   void fini () { SUPER::fini (); }
 
   unsigned get_count () const { return base->get_count () + SUPER::get_count (); }
-  const CFF1TopDictVal &get_value (unsigned int i) const
+  const cff1_top_dict_val_t &get_value (unsigned int i) const
   {
     if (i < base->get_count ())
       return (*base)[i];
     else
       return SUPER::values[i - base->get_count ()];
   }
-  const CFF1TopDictVal &operator [] (unsigned int i) const { return get_value (i); }
+  const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); }
 
-  void reassignSIDs (const RemapSID& sidmap)
+  void reassignSIDs (const remap_sid_t& sidmap)
   {
-    for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
+    for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
       nameSIDs[i] = sidmap[base->nameSIDs[i]];
   }
 
   protected:
-  typedef CFF1TopDictValues SUPER;
-  const CFF1TopDictValues *base;
+  typedef cff1_top_dict_values_t SUPER;
+  const cff1_top_dict_values_t *base;
 };
 
-struct TopDictModifiers
+struct top_dict_modifiers_t
 {
-  TopDictModifiers (const CFF1SubTableOffsets &offsets_,
-			   const unsigned int (&nameSIDs_)[NameDictValues::ValCount])
+  top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_,
+			   const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
     : offsets (offsets_),
       nameSIDs (nameSIDs_)
   {}
 
-  const CFF1SubTableOffsets &offsets;
-  const unsigned int	(&nameSIDs)[NameDictValues::ValCount];
+  const cff1_sub_table_offsets_t &offsets;
+  const unsigned int	(&nameSIDs)[name_dict_values_t::ValCount];
 };
 
-struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer<CFF1TopDictVal>
+struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t>
 {
   bool serialize (hb_serialize_context_t *c,
-		  const CFF1TopDictVal &opstr,
-		  const TopDictModifiers &mod) const
+		  const cff1_top_dict_val_t &opstr,
+		  const top_dict_modifiers_t &mod) const
   {
     TRACE_SERIALIZE (this);
 
-    OpCode op = opstr.op;
+    op_code_t op = opstr.op;
     switch (op)
     {
       case OpCode_charset:
@@ -147,7 +152,7 @@
 	    return_trace (false);
 	  HBUINT8 *p = c->allocate_size<HBUINT8> (1);
 	  if (unlikely (p == nullptr)) return_trace (false);
-	  p->set (OpCode_Private);
+	  *p = OpCode_Private;
 	}
 	break;
 
@@ -160,31 +165,30 @@
       case OpCode_PostScript:
       case OpCode_BaseFontName:
       case OpCode_FontName:
-	return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[NameDictValues::name_op_to_index (op)]));
+	return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
 
       case OpCode_ROS:
 	{
 	  /* for registry & ordering, reassigned SIDs are serialized
 	   * for supplement, the original byte string is copied along with the op code */
-	  OpStr supp_op;
+	  op_str_t supp_op;
 	  supp_op.op = op;
-	  supp_op.str.str = opstr.str.str + opstr.last_arg_offset;
-	  if ( unlikely (!(opstr.str.len >= opstr.last_arg_offset + 3)))
+	  if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3)))
 	    return_trace (false);
-	  supp_op.str.len = opstr.str.len - opstr.last_arg_offset;
-	  return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValues::registry]) &&
-			UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValues::ordering]) &&
+	  supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset);
+	  return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) &&
+			UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
 			copy_opstr (c, supp_op));
 	}
       default:
-	return_trace (CFFTopDict_OpSerializer<CFF1TopDictVal>::serialize (c, opstr, mod.offsets));
+	return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets));
     }
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (const CFF1TopDictVal &opstr) const
+  unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const
   {
-    OpCode op = opstr.op;
+    op_code_t op = opstr.op;
     switch (op)
     {
       case OpCode_charset:
@@ -206,19 +210,19 @@
 	return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
 
       case OpCode_ROS:
-	return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.len - opstr.last_arg_offset)/* supplement + op */;
+	return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */;
 
       default:
-	return CFFTopDict_OpSerializer<CFF1TopDictVal>::calculate_serialized_size (opstr);
+	return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr);
     }
   }
 };
 
-struct FontDictValuesMod
+struct font_dict_values_mod_t
 {
-  void init (const CFF1FontDictValues *base_,
+  void init (const cff1_font_dict_values_t *base_,
 	     unsigned int fontName_,
-	     const TableInfo &privateDictInfo_)
+	     const table_info_t &privateDictInfo_)
   {
     base = base_;
     fontName = fontName_;
@@ -227,18 +231,18 @@
 
   unsigned get_count () const { return base->get_count (); }
 
-  const OpStr &operator [] (unsigned int i) const { return (*base)[i]; }
+  const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
 
-  const CFF1FontDictValues    *base;
-  TableInfo		   privateDictInfo;
+  const cff1_font_dict_values_t    *base;
+  table_info_t		   privateDictInfo;
   unsigned int		fontName;
 };
 
-struct CFF1FontDict_OpSerializer : CFFFontDict_OpSerializer
+struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
 {
   bool serialize (hb_serialize_context_t *c,
-		  const OpStr &opstr,
-		  const FontDictValuesMod &mod) const
+		  const op_str_t &opstr,
+		  const font_dict_values_mod_t &mod) const
   {
     TRACE_SERIALIZE (this);
 
@@ -248,7 +252,7 @@
       return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
   }
 
-  unsigned int calculate_serialized_size (const OpStr &opstr) const
+  unsigned int calculate_serialized_size (const op_str_t &opstr) const
   {
     if (opstr.op == OpCode_FontName)
       return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
@@ -257,12 +261,12 @@
   }
 
   private:
-  typedef CFFFontDict_OpSerializer SUPER;
+  typedef cff_font_dict_op_serializer_t SUPER;
 };
 
-struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
+struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t>
 {
-  static void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
+  static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
   {
     if (env.arg_start > 0)
       flush_width (env, param);
@@ -288,51 +292,51 @@
 	break;
     }
   }
-  static void flush_args (CFF1CSInterpEnv &env, FlattenParam& param)
+  static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param)
   {
-    StrEncoder  encoder (param.flatStr);
+    str_encoder_t  encoder (param.flatStr);
     for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
       encoder.encode_num (env.eval_arg (i));
     SUPER::flush_args (env, param);
   }
 
-  static void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
+  static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
   {
-    StrEncoder  encoder (param.flatStr);
+    str_encoder_t  encoder (param.flatStr);
     encoder.encode_op (op);
   }
 
-  static void flush_width (CFF1CSInterpEnv &env, FlattenParam& param)
+  static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param)
   {
     assert (env.has_width);
-    StrEncoder  encoder (param.flatStr);
+    str_encoder_t  encoder (param.flatStr);
     encoder.encode_num (env.width);
   }
 
-  static void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
+  static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param)
   {
     SUPER::flush_hintmask (op, env, param);
     if (!param.drop_hints)
     {
-      StrEncoder  encoder (param.flatStr);
+      str_encoder_t  encoder (param.flatStr);
       for (unsigned int i = 0; i < env.hintmask_size; i++)
-	encoder.encode_byte (env.substr[i]);
+	encoder.encode_byte (env.str_ref[i]);
     }
   }
 
   private:
-  typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam> SUPER;
+  typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER;
 };
 
-struct RangeList : hb_vector_t<code_pair>
+struct range_list_t : hb_vector_t<code_pair_t>
 {
   /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
   bool finalize (unsigned int last_glyph)
   {
     bool  two_byte = false;
-    for (unsigned int i = (*this).len; i > 0; i--)
+    for (unsigned int i = (*this).length; i > 0; i--)
     {
-      code_pair &pair = (*this)[i - 1];
+      code_pair_t &pair = (*this)[i - 1];
       unsigned int  nLeft = last_glyph - pair.glyph - 1;
       if (nLeft >= 0x100)
 	two_byte = true;
@@ -343,21 +347,21 @@
   }
 };
 
-struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam>
+struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t>
 {
-  static void process_op (OpCode op, CFF1CSInterpEnv &env, SubrSubsetParam& param)
+  static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param)
   {
     switch (op) {
 
       case OpCode_return:
-	param.current_parsed_str->add_op (op, env.substr);
+	param.current_parsed_str->add_op (op, env.str_ref);
 	param.current_parsed_str->set_parsed ();
-	env.returnFromSubr ();
+	env.return_from_subr ();
 	param.set_current_str (env, false);
 	break;
 
       case OpCode_endchar:
-	param.current_parsed_str->add_op (op, env.substr);
+	param.current_parsed_str->add_op (op, env.str_ref);
 	param.current_parsed_str->set_parsed ();
 	SUPER::process_op (op, env, param);
 	break;
@@ -372,30 +376,33 @@
 
       default:
 	SUPER::process_op (op, env, param);
-	param.current_parsed_str->add_op (op, env.substr);
+	param.current_parsed_str->add_op (op, env.str_ref);
 	break;
     }
   }
 
   protected:
-  static void process_call_subr (OpCode op, CSType type,
-				 CFF1CSInterpEnv &env, SubrSubsetParam& param,
-				 CFF1BiasedSubrs& subrs, hb_set_t *closure)
+  static void process_call_subr (op_code_t op, cs_type_t type,
+				 cff1_cs_interp_env_t &env, subr_subset_param_t& param,
+				 cff1_biased_subrs_t& subrs, hb_set_t *closure)
   {
-    SubByteStr    substr = env.substr;
-    env.callSubr (subrs, type);
-    param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
-    hb_set_add (closure, env.context.subr_num);
+    byte_str_ref_t    str_ref = env.str_ref;
+    env.call_subr (subrs, type);
+    param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
+    closure->add (env.context.subr_num);
     param.set_current_str (env, true);
   }
 
   private:
-  typedef CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam> SUPER;
+  typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
 };
 
-struct CFF1SubrSubsetter : SubrSubsetter<CFF1SubrSubsetter, CFF1Subrs, const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubrSubset>
+struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, OpCode_endchar>
 {
-  static void finalize_parsed_str (CFF1CSInterpEnv &env, SubrSubsetParam& param, ParsedCStr &charstring)
+  cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
+    : subr_subsetter_t (acc_, plan_) {}
+
+  static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
   {
     /* insert width at the beginning of the charstring as necessary */
     if (env.has_width)
@@ -407,7 +414,7 @@
     param.current_parsed_str->set_parsed ();
     for (unsigned int i = 0; i < env.callStack.get_count (); i++)
     {
-      ParsedCStr  *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
+      parsed_cs_str_t  *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
       if (likely (parsed_str != nullptr))
 	parsed_str->set_parsed ();
       else
@@ -439,7 +446,7 @@
     subset_enc_supp_codes.init ();
     subset_charset_ranges.init ();
     sidmap.init ();
-    for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
+    for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
       topDictModSIDs[i] = CFF_UNDEF_SID;
   }
 
@@ -454,10 +461,9 @@
     subset_localsubrs.fini_deep ();
     fontdicts_mod.fini ();
     subset_enc_code_ranges.fini ();
-    subset_enc_supp_codes.init ();
+    subset_enc_supp_codes.fini ();
     subset_charset_ranges.fini ();
     sidmap.fini ();
-    fontdicts_mod.fini ();
   }
 
   unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
@@ -471,35 +477,40 @@
     supp_size = 0;
     supp_codes.init ();
 
-    subset_enc_num_codes = plan->glyphs.len - 1;
+    subset_enc_num_codes = plan->num_output_glyphs () - 1;
     unsigned int glyph;
-    for (glyph = 1; glyph < plan->glyphs.len; glyph++)
+    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
     {
-      hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
-      code = acc.glyph_to_code (orig_glyph);
+      hb_codepoint_t  old_glyph;
+      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      {
+      	/* Retain the code for the old missing glyph ID */
+	old_glyph = glyph;
+      }
+      code = acc.glyph_to_code (old_glyph);
       if (code == CFF_UNDEF_CODE)
       {
 	subset_enc_num_codes = glyph - 1;
 	break;
       }
 
-      if (code != last_code + 1)
+      if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
       {
-	code_pair pair = { code, glyph };
+	code_pair_t pair = { code, glyph };
 	subset_enc_code_ranges.push (pair);
       }
       last_code = code;
 
       if (encoding != &Null(Encoding))
       {
-	hb_codepoint_t  sid = acc.glyph_to_sid (orig_glyph);
+	hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph);
 	encoding->get_supplement_codes (sid, supp_codes);
-	for (unsigned int i = 0; i < supp_codes.len; i++)
+	for (unsigned int i = 0; i < supp_codes.length; i++)
 	{
-	  code_pair pair = { supp_codes[i], sid };
+	  code_pair_t pair = { supp_codes[i], sid };
 	  subset_enc_supp_codes.push (pair);
 	}
-	supp_size += SuppEncoding::static_size * supp_codes.len;
+	supp_size += SuppEncoding::static_size * supp_codes.length;
       }
     }
     supp_codes.fini ();
@@ -508,7 +519,7 @@
 
     assert (subset_enc_num_codes <= 0xFF);
     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
-    size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.len;
+    size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length;
 
     if (size0 < size1)
       subset_enc_format = 0;
@@ -517,8 +528,8 @@
 
     return Encoding::calculate_serialized_size (
 			subset_enc_format,
-			subset_enc_format? subset_enc_code_ranges.len: subset_enc_num_codes,
-			subset_enc_supp_codes.len);
+			subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes,
+			subset_enc_supp_codes.length);
   }
 
   unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
@@ -528,17 +539,22 @@
 
     subset_charset_ranges.resize (0);
     unsigned int glyph;
-    for (glyph = 1; glyph < plan->glyphs.len; glyph++)
+    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
     {
-      hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
-      sid = acc.glyph_to_sid (orig_glyph);
+      hb_codepoint_t  old_glyph;
+      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      {
+      	/* Retain the SID for the old missing glyph ID */
+	old_glyph = glyph;
+      }
+      sid = acc.glyph_to_sid (old_glyph);
 
       if (!acc.is_CID ())
 	sid = sidmap.add (sid);
 
-      if (sid != last_sid + 1)
+      if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
       {
-	code_pair pair = { sid, glyph };
+	code_pair_t pair = { sid, glyph };
 	subset_charset_ranges.push (pair);
       }
       last_sid = sid;
@@ -546,11 +562,11 @@
 
     bool two_byte = subset_charset_ranges.finalize (glyph);
 
-    size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.len - 1);
+    size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
     if (!two_byte)
-      size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.len;
+      size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
     else
-      size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.len;
+      size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
 
     if (size0 < size_ranges)
       subset_charset_format = 0;
@@ -561,15 +577,14 @@
 
     return Charset::calculate_serialized_size (
 			subset_charset_format,
-			subset_charset_format? subset_charset_ranges.len: plan->glyphs.len);
+			subset_charset_format? subset_charset_ranges.length: plan->num_output_glyphs ());
   }
 
   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
   {
-    if (unlikely (!sidmap.reset (acc.stringIndex->count)))
-      return false;
+    sidmap.reset ();
 
-    for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
+    for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
     {
       unsigned int sid = acc.topDict.nameSIDs[i];
       if (sid != CFF_UNDEF_SID)
@@ -581,29 +596,32 @@
 
     if (acc.fdArray != &Null(CFF1FDArray))
       for (unsigned int i = 0; i < orig_fdcount; i++)
-	if (fdmap.includes (i))
+	if (fdmap.has (i))
 	  (void)sidmap.add (acc.fontDicts[i].fontName);
 
     return true;
   }
 
   bool create (const OT::cff1::accelerator_subset_t &acc,
-		      hb_subset_plan_t *plan)
+	       hb_subset_plan_t *plan)
   {
-     /* make sure notdef is first */
-    if ((plan->glyphs.len == 0) || (plan->glyphs[0] != 0)) return false;
+    /* make sure notdef is first */
+    hb_codepoint_t old_glyph;
+    if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
 
     final_size = 0;
-    num_glyphs = plan->glyphs.len;
+    num_glyphs = plan->num_output_glyphs ();
     orig_fdcount = acc.fdCount;
     drop_hints = plan->drop_hints;
     desubroutinize = plan->desubroutinize;
 
     /* check whether the subset renumbers any glyph IDs */
     gid_renum = false;
-    for (unsigned int glyph = 0; glyph < plan->glyphs.len; glyph++)
+    for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
     {
-      if (plan->glyphs[glyph] != glyph) {
+      if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
+      	continue;
+      if (new_glyph != old_glyph) {
 	gid_renum = true;
 	break;
       }
@@ -633,12 +651,12 @@
 	  topdict_mod.add_op (OpCode_charset);
       }
       offsets.topDictInfo.offset = final_size;
-      CFF1TopDict_OpSerializer topSzr;
+      cff1_top_dict_op_serializer_t topSzr;
       unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
       offsets.topDictInfo.offSize = calcOffSize(topDictSize);
       if (unlikely (offsets.topDictInfo.offSize > 4))
       	return false;
-      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValuesMod>
+      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t>
 						(offsets.topDictInfo.offSize,
 						 &topdict_mod, 1, topdict_sizes, topSzr);
     }
@@ -646,7 +664,7 @@
     /* Determine re-mapping of font index as fdmap among other info */
     if (acc.fdSelect != &Null(CFF1FDSelect))
     {
-	if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
+	if (unlikely (!hb_plan_subset_cff_fdselect (plan,
 				  orig_fdcount,
 				  *acc.fdSelect,
 				  subset_fdcount,
@@ -664,7 +682,7 @@
       /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
       if (unlikely (!collect_sids_in_dicts (acc)))
 	return false;
-      if (unlikely (sidmap.get_count () > 0x8000))	/* assumption: a dict won't reference that many strings */
+      if (unlikely (sidmap.get_population () > 0x8000))	/* assumption: a dict won't reference that many strings */
       	return false;
       if (subset_charset)
 	offsets.charsetInfo.size = plan_subset_charset (acc, plan);
@@ -682,8 +700,8 @@
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
-      SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten>
-		    flattener(acc, plan->glyphs, plan->drop_hints);
+      subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
+		    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
 	return false;
 
@@ -692,12 +710,14 @@
     }
     else
     {
+      cff1_subr_subsetter_t       subr_subsetter (acc, plan);
+
       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
-      if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+      if (!subr_subsetter.subset ())
 	return false;
 
       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
-      if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+      if (!subr_subsetter.encode_charstrings (subset_charstrings))
 	return false;
 
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
@@ -708,7 +728,7 @@
       offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
       if (unlikely (offsets.globalSubrsInfo.offSize > 4))
       	return false;
-      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.len, dataSize);
+      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
 
       /* local subrs */
       if (!offsets.localSubrsInfos.resize (orig_fdcount))
@@ -719,7 +739,7 @@
       {
 	subset_localsubrs[fd].init ();
 	offsets.localSubrsInfos[fd].init ();
-	if (fdmap.includes (fd))
+	if (fdmap.has (fd))
 	{
 	  if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
 	    return false;
@@ -731,7 +751,7 @@
 	    offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
 	    if (unlikely (offsets.localSubrsInfos[fd].offSize > 4))
 	      return false;
-	    offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
+	    offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
 	  }
 	}
       }
@@ -767,10 +787,10 @@
     /* FDArray (FDIndex) */
     if (acc.fdArray != &Null(CFF1FDArray)) {
       offsets.FDArrayInfo.offset = final_size;
-      CFF1FontDict_OpSerializer fontSzr;
+      cff1_font_dict_op_serializer_t fontSzr;
       unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.len; i++)
-	if (fdmap.includes (i))
+      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
+	if (fdmap.has (i))
 	  dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
 
       offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
@@ -786,22 +806,22 @@
       offsets.charStringsInfo.offSize = calcOffSize (dataSize);
       if (unlikely (offsets.charStringsInfo.offSize > 4))
       	return false;
-      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
+      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
     }
 
     /* private dicts & local subrs */
     offsets.privateDictInfo.offset = final_size;
     for (unsigned int i = 0; i < orig_fdcount; i++)
     {
-      if (fdmap.includes (i))
+      if (fdmap.has (i))
       {
 	bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-	CFFPrivateDict_OpSerializer privSzr (desubroutinize, plan->drop_hints);
+	cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints);
 	unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-	TableInfo  privInfo = { final_size, priv_size, 0 };
-	FontDictValuesMod fontdict_mod;
+	table_info_t  privInfo = { final_size, priv_size, 0 };
+	font_dict_values_mod_t fontdict_mod;
 	if (!acc.is_CID ())
-	  fontdict_mod.init ( &Null(CFF1FontDictValues), CFF_UNDEF_SID, privInfo );
+	  fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo );
 	else
 	  fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
 	fontdicts_mod.push (fontdict_mod);
@@ -818,76 +838,72 @@
     if (!acc.is_CID ())
       offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
 
-    return ((subset_charstrings.len == plan->glyphs.len)
-	   && (fontdicts_mod.len == subset_fdcount));
+    return ((subset_charstrings.length == plan->num_output_glyphs ())
+	   && (fontdicts_mod.length == subset_fdcount));
   }
 
   unsigned int get_final_size () const  { return final_size; }
 
   unsigned int	      final_size;
-  hb_vector_t<unsigned int> topdict_sizes;
-  CFF1TopDictValuesMod      topdict_mod;
-  CFF1SubTableOffsets       offsets;
+  hb_vector_t<unsigned int>	topdict_sizes;
+  cff1_top_dict_values_mod_t	topdict_mod;
+  cff1_sub_table_offsets_t	offsets;
 
   unsigned int    num_glyphs;
   unsigned int    orig_fdcount;
   unsigned int    subset_fdcount;
   unsigned int    subset_fdselect_format;
-  hb_vector_t<code_pair>   subset_fdselect_ranges;
+  hb_vector_t<code_pair_t>   subset_fdselect_ranges;
 
   /* font dict index remap table from fullset FDArray to subset FDArray.
    * set to CFF_UNDEF_CODE if excluded from subset */
-  Remap   fdmap;
+  hb_inc_bimap_t   fdmap;
 
-  StrBuffArray	    subset_charstrings;
-  StrBuffArray	    subset_globalsubrs;
-  hb_vector_t<StrBuffArray> subset_localsubrs;
-  hb_vector_t<FontDictValuesMod>  fontdicts_mod;
+  str_buff_vec_t		subset_charstrings;
+  str_buff_vec_t		subset_globalsubrs;
+  hb_vector_t<str_buff_vec_t>	subset_localsubrs;
+  hb_vector_t<font_dict_values_mod_t>  fontdicts_mod;
 
-  bool		    drop_hints;
+  bool		drop_hints;
 
-  bool		    gid_renum;
-  bool		    subset_encoding;
-  uint8_t		 subset_enc_format;
-  unsigned int	    subset_enc_num_codes;
-  RangeList	       subset_enc_code_ranges;
-  hb_vector_t<code_pair>  subset_enc_supp_codes;
+  bool		gid_renum;
+  bool		subset_encoding;
+  uint8_t	subset_enc_format;
+  unsigned int	subset_enc_num_codes;
+  range_list_t	subset_enc_code_ranges;
+  hb_vector_t<code_pair_t>  subset_enc_supp_codes;
 
-  uint8_t		 subset_charset_format;
-  RangeList	       subset_charset_ranges;
-  bool		    subset_charset;
+  uint8_t	subset_charset_format;
+  range_list_t	subset_charset_ranges;
+  bool		subset_charset;
 
-  RemapSID		sidmap;
-  unsigned int	    topDictModSIDs[NameDictValues::ValCount];
+  remap_sid_t	sidmap;
+  unsigned int	topDictModSIDs[name_dict_values_t::ValCount];
 
-  bool		    desubroutinize;
-  CFF1SubrSubsetter       subr_subsetter;
+  bool		desubroutinize;
 };
 
 static inline bool _write_cff1 (const cff_subset_plan &plan,
 				const OT::cff1::accelerator_subset_t  &acc,
-				const hb_vector_t<hb_codepoint_t>& glyphs,
+				unsigned int num_glyphs,
 				unsigned int dest_sz,
 				void *dest)
 {
   hb_serialize_context_t c (dest, dest_sz);
 
-  char RETURN_OP[1] = { OpCode_return };
-  const ByteStr NULL_SUBR (RETURN_OP, 1);
-
   OT::cff1 *cff = c.start_serialize<OT::cff1> ();
   if (unlikely (!c.extend_min (*cff)))
     return false;
 
   /* header */
-  cff->version.major.set (0x01);
-  cff->version.minor.set (0x00);
-  cff->nameIndex.set (cff->min_size);
-  cff->offSize.set (4); /* unused? */
+  cff->version.major = 0x01;
+  cff->version.minor = 0x00;
+  cff->nameIndex = cff->min_size;
+  cff->offSize = 4; /* unused? */
 
   /* name INDEX */
   {
-    assert (cff->nameIndex == c.head - c.start);
+    assert (cff->nameIndex == (unsigned) (c.head - c.start));
     CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
@@ -899,11 +915,11 @@
 
   /* top dict INDEX */
   {
-    assert (plan.offsets.topDictInfo.offset == c.head - c.start);
-    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
+    assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
+    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict>> ();
     if (dest == nullptr) return false;
-    CFF1TopDict_OpSerializer topSzr;
-    TopDictModifiers  modifier (plan.offsets, plan.topDictModSIDs);
+    cff1_top_dict_op_serializer_t topSzr;
+    top_dict_modifiers_t  modifier (plan.offsets, plan.topDictModSIDs);
     if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
 				    &plan.topdict_mod, 1,
 				    plan.topdict_sizes, topSzr, modifier)))
@@ -915,7 +931,7 @@
 
   /* String INDEX */
   {
-    assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
+    assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
     CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
@@ -928,7 +944,7 @@
   /* global subrs */
   {
     assert (plan.offsets.globalSubrsInfo.offset != 0);
-    assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
+    assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
 
     CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
     if (unlikely (dest == nullptr)) return false;
@@ -942,7 +958,7 @@
   /* Encoding */
   if (plan.subset_encoding)
   {
-    assert (plan.offsets.encodingOffset == c.head - c.start);
+    assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
     Encoding *dest = c.start_embed<Encoding> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -959,7 +975,7 @@
   /* Charset */
   if (plan.subset_charset)
   {
-    assert (plan.offsets.charsetInfo.offset == c.head - c.start);
+    assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
     Charset *dest = c.start_embed<Charset> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -975,9 +991,9 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF1FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
-    if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.len, *acc.fdSelect, acc.fdCount,
+    if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *acc.fdSelect, acc.fdCount,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
 					      plan.subset_fdselect_ranges)))
     {
@@ -989,10 +1005,10 @@
   /* FDArray (FD Index) */
   if (acc.fdArray != &Null(CFF1FDArray))
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
     if (unlikely (fda == nullptr)) return false;
-    CFF1FontDict_OpSerializer  fontSzr;
+    cff1_font_dict_op_serializer_t  fontSzr;
     if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
 				   plan.fontdicts_mod,
 				   fontSzr)))
@@ -1004,7 +1020,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -1015,18 +1031,18 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
-  for (unsigned int i = 0; i < acc.privateDicts.len; i++)
+  assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
+  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
-    if (plan.fdmap.includes (i))
+    if (plan.fdmap.has (i))
     {
       PrivateDict  *pd = c.start_embed<PrivateDict> ();
       if (unlikely (pd == nullptr)) return false;
       unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
       bool result;
-      CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
+      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
+      unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
       result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
       if (unlikely (!result))
       {
@@ -1052,11 +1068,11 @@
   return true;
 }
 
-static bool
+static inline bool
 _hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
-		const char		      *data,
-		hb_subset_plan_t		*plan,
-		hb_blob_t		       **prime /* OUT */)
+		const char		*data,
+		hb_subset_plan_t	*plan,
+		hb_blob_t		**prime /* OUT */)
 {
   cff_subset_plan cff_plan;
 
@@ -1069,7 +1085,7 @@
   unsigned int  cff_prime_size = cff_plan.get_final_size ();
   char *cff_prime_data = (char *) calloc (1, cff_prime_size);
 
-  if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
+  if (unlikely (!_write_cff1 (cff_plan, acc, plan->num_output_glyphs (),
 			      cff_prime_size, cff_prime_data))) {
     DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
     free (cff_prime_data);
@@ -1106,3 +1122,6 @@
 
   return result;
 }
+
+
+#endif
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 5a5f29d..7edc3f5 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -24,6 +24,10 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-open-type.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-set.h"
@@ -34,21 +38,21 @@
 
 using namespace CFF;
 
-struct CFF2SubTableOffsets : CFFSubTableOffsets
+struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t
 {
-  CFF2SubTableOffsets ()
-    : CFFSubTableOffsets (),
+  cff2_sub_table_offsets_t ()
+    : cff_sub_table_offsets_t (),
       varStoreOffset (0)
   {}
 
   unsigned int  varStoreOffset;
 };
 
-struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer<>
+struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
 {
   bool serialize (hb_serialize_context_t *c,
-		  const OpStr &opstr,
-		  const CFF2SubTableOffsets &offsets) const
+		  const op_str_t &opstr,
+		  const cff2_sub_table_offsets_t &offsets) const
   {
     TRACE_SERIALIZE (this);
 
@@ -58,11 +62,11 @@
 	return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
 
       default:
-	return_trace (CFFTopDict_OpSerializer<>::serialize (c, opstr, offsets));
+	return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets));
     }
   }
 
-  unsigned int calculate_serialized_size (const OpStr &opstr) const
+  unsigned int calculate_serialized_size (const op_str_t &opstr) const
   {
     switch (opstr.op)
     {
@@ -70,14 +74,14 @@
 	return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 
       default:
-	return CFFTopDict_OpSerializer<>::calculate_serialized_size (opstr);
+	return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr);
     }
   }
 };
 
-struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
+struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t>
 {
-  static void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
+  static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
   {
     switch (op)
     {
@@ -105,11 +109,11 @@
     }
   }
 
-  static void flush_args (CFF2CSInterpEnv &env, FlattenParam& param)
+  static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
   {
     for (unsigned int i = 0; i < env.argStack.get_count ();)
     {
-      const BlendArg &arg = env.argStack[i];
+      const blend_arg_t &arg = env.argStack[i];
       if (arg.blending ())
       {
       	if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues))))
@@ -122,7 +126,7 @@
       }
       else
       {
-	StrEncoder  encoder (param.flatStr);
+	str_encoder_t  encoder (param.flatStr);
 	encoder.encode_num (arg);
 	i++;
       }
@@ -130,15 +134,15 @@
     SUPER::flush_args (env, param);
   }
 
-  static void flatten_blends (const BlendArg &arg, unsigned int i, CFF2CSInterpEnv &env, FlattenParam& param)
+  static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param)
   {
     /* flatten the default values */
-    StrEncoder  encoder (param.flatStr);
+    str_encoder_t  encoder (param.flatStr);
     for (unsigned int j = 0; j < arg.numValues; j++)
     {
-      const BlendArg &arg1 = env.argStack[i + j];
+      const blend_arg_t &arg1 = env.argStack[i + j];
       if (unlikely (!((arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
-	      (arg1.deltas.len == env.get_region_count ())))))
+	      (arg1.deltas.length == env.get_region_count ())))))
       {
       	env.set_error ();
       	return;
@@ -148,8 +152,8 @@
     /* flatten deltas for each value */
     for (unsigned int j = 0; j < arg.numValues; j++)
     {
-      const BlendArg &arg1 = env.argStack[i + j];
-      for (unsigned int k = 0; k < arg1.deltas.len; k++)
+      const blend_arg_t &arg1 = env.argStack[i + j];
+      for (unsigned int k = 0; k < arg1.deltas.length; k++)
 	encoder.encode_num (arg1.deltas[k]);
     }
     /* flatten the number of values followed by blend operator */
@@ -157,7 +161,7 @@
     encoder.encode_op (OpCode_blendcs);
   }
 
-  static void flush_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
+  static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
   {
     switch (op)
     {
@@ -165,25 +169,25 @@
       case OpCode_endchar:
 	return;
       default:
-	StrEncoder  encoder (param.flatStr);
+	str_encoder_t  encoder (param.flatStr);
 	encoder.encode_op (op);
     }
   }
 
   private:
-  typedef CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam> SUPER;
-  typedef CSOpSet<BlendArg, CFF2CSOpSet_Flatten, CFF2CSOpSet_Flatten, CFF2CSInterpEnv, FlattenParam> CSOPSET;
+  typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER;
+  typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET;
 };
 
-struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetParam>
+struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t>
 {
-  static void process_op (OpCode op, CFF2CSInterpEnv &env, SubrSubsetParam& param)
+  static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param)
   {
     switch (op) {
 
       case OpCode_return:
 	param.current_parsed_str->set_parsed ();
-	env.returnFromSubr ();
+	env.return_from_subr ();
 	param.set_current_str (env, false);
 	break;
 
@@ -202,35 +206,38 @@
 
       default:
 	SUPER::process_op (op, env, param);
-	param.current_parsed_str->add_op (op, env.substr);
+	param.current_parsed_str->add_op (op, env.str_ref);
 	break;
     }
   }
 
   protected:
-  static void process_call_subr (OpCode op, CSType type,
-				 CFF2CSInterpEnv &env, SubrSubsetParam& param,
-				 CFF2BiasedSubrs& subrs, hb_set_t *closure)
+  static void process_call_subr (op_code_t op, cs_type_t type,
+				 cff2_cs_interp_env_t &env, subr_subset_param_t& param,
+				 cff2_biased_subrs_t& subrs, hb_set_t *closure)
   {
-    SubByteStr    substr = env.substr;
-    env.callSubr (subrs, type);
-    param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
-    hb_set_add (closure, env.context.subr_num);
+    byte_str_ref_t    str_ref = env.str_ref;
+    env.call_subr (subrs, type);
+    param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
+    closure->add (env.context.subr_num);
     param.set_current_str (env, true);
   }
 
   private:
-  typedef CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetParam> SUPER;
+  typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
 };
 
-struct CFF2SubrSubsetter : SubrSubsetter<CFF2SubrSubsetter, CFF2Subrs, const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset>
+struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
 {
-  static void finalize_parsed_str (CFF2CSInterpEnv &env, SubrSubsetParam& param, ParsedCStr &charstring)
+  cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
+    : subr_subsetter_t (acc_, plan_) {}
+
+  static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
   {
     /* vsindex is inserted at the beginning of the charstring as necessary */
     if (env.seen_vsindex ())
     {
-      Number  ivs;
+      number_t  ivs;
       ivs.set_int ((int)env.get_ivs ());
       charstring.set_prefix (ivs, OpCode_vsindexcs);
     }
@@ -278,7 +285,7 @@
 
     /* top dict */
     {
-      CFF2TopDict_OpSerializer topSzr;
+      cff2_top_dict_op_serializer_t topSzr;
       offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr);
       final_size += offsets.topDictInfo.size;
     }
@@ -286,8 +293,8 @@
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
-      SubrFlattener<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_Flatten>
-		    flattener(acc, plan->glyphs, plan->drop_hints);
+      subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
+		    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
 	return false;
 
@@ -296,12 +303,14 @@
     }
     else
     {
+      cff2_subr_subsetter_t	subr_subsetter (acc, plan);
+
       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
-      if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+      if (!subr_subsetter.subset ())
 	return false;
 
       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
-      if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+      if (!subr_subsetter.encode_charstrings (subset_charstrings))
 	return false;
 
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
@@ -310,7 +319,7 @@
       /* global subrs */
       unsigned int dataSize = subset_globalsubrs.total_size ();
       offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
-      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.len, dataSize);
+      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
 
       /* local subrs */
       if (!offsets.localSubrsInfos.resize (orig_fdcount))
@@ -321,18 +330,15 @@
       {
 	subset_localsubrs[fd].init ();
 	offsets.localSubrsInfos[fd].init ();
-	if (fdmap.includes (fd))
-	{
-	  if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
-	    return false;
+	if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
+	  return false;
 
-	  unsigned int dataSize = subset_localsubrs[fd].total_size ();
-	  if (dataSize > 0)
-	  {
-	    offsets.localSubrsInfos[fd].offset = final_size;
-	    offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-	    offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
-	  }
+	unsigned int dataSize = subset_localsubrs[fd].total_size ();
+	if (dataSize > 0)
+	{
+	  offsets.localSubrsInfos[fd].offset = final_size;
+	  offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
+	  offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
 	}
       }
     }
@@ -352,7 +358,7 @@
     if (acc.fdSelect != &Null(CFF2FDSelect))
     {
       offsets.FDSelectInfo.offset = final_size;
-      if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
+      if (unlikely (!hb_plan_subset_cff_fdselect (plan,
 				  orig_fdcount,
 				  *(const FDSelect *)acc.fdSelect,
 				  subset_fdcount,
@@ -370,10 +376,10 @@
     /* FDArray (FDIndex) */
     {
       offsets.FDArrayInfo.offset = final_size;
-      CFFFontDict_OpSerializer fontSzr;
+      cff_font_dict_op_serializer_t fontSzr;
       unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.len; i++)
-	if (fdmap.includes (i))
+      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
+	if (fdmap.has (i))
 	  dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
 
       offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
@@ -385,19 +391,19 @@
       offsets.charStringsInfo.offset = final_size;
       unsigned int dataSize = subset_charstrings.total_size ();
       offsets.charStringsInfo.offSize = calcOffSize (dataSize);
-      final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
+      final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
     }
 
     /* private dicts & local subrs */
     offsets.privateDictsOffset = final_size;
     for (unsigned int i = 0; i < orig_fdcount; i++)
     {
-      if (fdmap.includes (i))
+      if (fdmap.has (i))
       {
 	bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-	CFFPrivateDict_OpSerializer privSzr (desubroutinize, drop_hints);
+	cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints);
 	unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-	TableInfo  privInfo = { final_size, priv_size, 0 };
+	table_info_t  privInfo = { final_size, priv_size, 0 };
 	privateDictInfos.push (privInfo);
 	final_size += privInfo.size;
 
@@ -415,28 +421,27 @@
   unsigned int get_final_size () const  { return final_size; }
 
   unsigned int	final_size;
-  CFF2SubTableOffsets offsets;
+  cff2_sub_table_offsets_t offsets;
 
   unsigned int    orig_fdcount;
   unsigned int    subset_fdcount;
   unsigned int    subset_fdselect_format;
-  hb_vector_t<code_pair>   subset_fdselect_ranges;
+  hb_vector_t<code_pair_t>   subset_fdselect_ranges;
 
-  Remap   fdmap;
+  hb_inc_bimap_t   fdmap;
 
-  StrBuffArray	    subset_charstrings;
-  StrBuffArray	    subset_globalsubrs;
-  hb_vector_t<StrBuffArray> subset_localsubrs;
-  hb_vector_t<TableInfo>  privateDictInfos;
+  str_buff_vec_t	    subset_charstrings;
+  str_buff_vec_t	    subset_globalsubrs;
+  hb_vector_t<str_buff_vec_t> subset_localsubrs;
+  hb_vector_t<table_info_t>  privateDictInfos;
 
   bool	    drop_hints;
   bool	    desubroutinize;
-  CFF2SubrSubsetter       subr_subsetter;
 };
 
 static inline bool _write_cff2 (const cff2_subset_plan &plan,
 				const OT::cff2::accelerator_subset_t  &acc,
-				const hb_vector_t<hb_codepoint_t>& glyphs,
+				unsigned int num_glyphs,
 				unsigned int dest_sz,
 				void *dest)
 {
@@ -447,16 +452,16 @@
     return false;
 
   /* header */
-  cff2->version.major.set (0x02);
-  cff2->version.minor.set (0x00);
-  cff2->topDict.set (OT::cff2::static_size);
+  cff2->version.major = 0x02;
+  cff2->version.minor = 0x00;
+  cff2->topDict = OT::cff2::static_size;
 
   /* top dict */
   {
-    assert (cff2->topDict == c.head - c.start);
-    cff2->topDictSize.set (plan.offsets.topDictInfo.size);
+    assert (cff2->topDict == (unsigned) (c.head - c.start));
+    cff2->topDictSize = plan.offsets.topDictInfo.size;
     TopDict &dict = cff2 + cff2->topDict;
-    CFF2TopDict_OpSerializer topSzr;
+    cff2_top_dict_op_serializer_t topSzr;
     if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
     {
       DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
@@ -466,7 +471,7 @@
 
   /* global subrs */
   {
-    assert (cff2->topDict + plan.offsets.topDictInfo.size == c.head - c.start);
+    assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
     CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
@@ -479,7 +484,7 @@
   /* variation store */
   if (acc.varStore != &Null(CFF2VariationStore))
   {
-    assert (plan.offsets.varStoreOffset == c.head - c.start);
+    assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
     CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
     if (unlikely (!dest->serialize (&c, acc.varStore)))
     {
@@ -491,9 +496,9 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF2FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
-    if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.len, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
+    if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
 					      plan.subset_fdselect_ranges)))
     {
@@ -504,10 +509,10 @@
 
   /* FDArray (FD Index) */
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
     if (unlikely (fda == nullptr)) return false;
-    CFFFontDict_OpSerializer  fontSzr;
+    cff_font_dict_op_serializer_t  fontSzr;
     if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
 				   acc.fontDicts, plan.subset_fdcount, plan.fdmap,
 				   fontSzr, plan.privateDictInfos)))
@@ -519,7 +524,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -530,18 +535,18 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictsOffset == c.head - c.start);
-  for (unsigned int i = 0; i < acc.privateDicts.len; i++)
+  assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
+  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
-    if (plan.fdmap.includes (i))
+    if (plan.fdmap.has (i))
     {
       PrivateDict  *pd = c.start_embed<PrivateDict> ();
       if (unlikely (pd == nullptr)) return false;
       unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
       bool result;
-      CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
+      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
       /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
+      unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0;
       result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
       if (unlikely (!result))
       {
@@ -567,7 +572,7 @@
   return true;
 }
 
-static bool
+static inline bool
 _hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
 		const char		      *data,
 		hb_subset_plan_t		*plan,
@@ -584,7 +589,7 @@
   unsigned int  cff2_prime_size = cff2_plan.get_final_size ();
   char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
 
-  if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs,
+  if (unlikely (!_write_cff2 (cff2_plan, acc, plan->num_output_glyphs (),
 			      cff2_prime_size, cff2_prime_data))) {
     DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
     free (cff2_prime_data);
@@ -592,10 +597,10 @@
   }
 
   *prime = hb_blob_create (cff2_prime_data,
-				cff2_prime_size,
-				HB_MEMORY_MODE_READONLY,
-				cff2_prime_data,
-				free);
+			   cff2_prime_size,
+			   HB_MEMORY_MODE_READONLY,
+			   cff2_prime_data,
+			   free);
   return true;
 }
 
@@ -622,3 +627,6 @@
 
   return result;
 }
+
+
+#endif
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
deleted file mode 100644
index 2219d37..0000000
--- a/src/hb-subset-glyf.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright © 2018  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger, Roderick Sheeter
- */
-
-#include "hb-open-type.hh"
-#include "hb-ot-glyf-table.hh"
-#include "hb-set.h"
-#include "hb-subset-glyf.hh"
-
-static bool
-_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
-				     hb_vector_t<hb_codepoint_t> &glyph_ids,
-				     hb_bool_t drop_hints,
-				     bool *use_short_loca /* OUT */,
-				     unsigned int *glyf_size /* OUT */,
-				     unsigned int *loca_size /* OUT */,
-				     hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
-{
-  unsigned int total = 0;
-  for (unsigned int i = 0; i < glyph_ids.len; i++)
-  {
-    hb_codepoint_t next_glyph = glyph_ids[i];
-    if (!instruction_ranges->resize (instruction_ranges->len + 2))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
-      return false;
-    }
-    unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->len - 2];
-    *instruction_start = 0;
-    unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->len - 1];
-    *instruction_end = 0;
-
-    unsigned int start_offset, end_offset;
-    if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) &&
-		    glyf.remove_padding (start_offset, &end_offset))))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph);
-      continue;
-    }
-    if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size)
-      continue; /* 0-length glyph */
-
-    if (drop_hints)
-    {
-      if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset,
-						   instruction_start, instruction_end)))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph);
-	return false;
-      }
-    }
-
-    total += end_offset - start_offset - (*instruction_end - *instruction_start);
-    /* round2 so short loca will work */
-    total += total % 2;
-  }
-
-  *glyf_size = total;
-  *use_short_loca = (total <= 131070);
-  *loca_size = (glyph_ids.len + 1)
-      * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
-
-  DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
-	    total,
-	    *loca_size,
-	    *use_short_loca ? "short" : "long");
-  return true;
-}
-
-static bool
-_write_loca_entry (unsigned int  id,
-		   unsigned int  offset,
-		   bool          is_short,
-		   void         *loca_prime,
-		   unsigned int  loca_size)
-{
-  unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32);
-  if ((id + 1) * entry_size <= loca_size)
-  {
-    if (is_short) {
-      ((OT::HBUINT16*) loca_prime) [id].set (offset / 2);
-    } else {
-      ((OT::HBUINT32*) loca_prime) [id].set (offset);
-    }
-    return true;
-  }
-
-  // Offset was not written because the write is out of bounds.
-  DEBUG_MSG(SUBSET,
-	    nullptr,
-	    "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.",
-	    id,
-	    loca_size);
-  return false;
-}
-
-static void
-_update_components (hb_subset_plan_t * plan,
-		    char * glyph_start,
-		    unsigned int length)
-{
-  OT::glyf::CompositeGlyphHeader::Iterator iterator;
-  if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
-						    length,
-						    &iterator))
-  {
-    do
-    {
-      hb_codepoint_t new_gid;
-      if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
-				      &new_gid))
-	continue;
-
-      ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid);
-    } while (iterator.move_to_next ());
-  }
-}
-
-static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int length)
-{
-  /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
-  OT::glyf::CompositeGlyphHeader::Iterator composite_it;
-  if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false;
-  const OT::glyf::CompositeGlyphHeader *glyph;
-  do {
-    glyph = composite_it.current;
-    OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
-    flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
-  } while (composite_it.move_to_next ());
-  return true;
-}
-
-static bool
-_write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
-			    const OT::glyf::accelerator_t &glyf,
-			    const char                    *glyf_data,
-			    bool                           use_short_loca,
-			    hb_vector_t<unsigned int> &instruction_ranges,
-			    unsigned int                   glyf_prime_size,
-			    char                          *glyf_prime_data /* OUT */,
-			    unsigned int                   loca_prime_size,
-			    char                          *loca_prime_data /* OUT */)
-{
-  hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
-  char *glyf_prime_data_next = glyf_prime_data;
-
-  bool success = true;
-  for (unsigned int i = 0; i < glyph_ids.len; i++)
-  {
-    unsigned int start_offset, end_offset;
-    if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) &&
-		    glyf.remove_padding (start_offset, &end_offset))))
-      end_offset = start_offset = 0;
-
-    unsigned int instruction_start = instruction_ranges[i * 2];
-    unsigned int instruction_end = instruction_ranges[i * 2 + 1];
-
-    int length = end_offset - start_offset - (instruction_end - instruction_start);
-
-    if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
-    {
-      DEBUG_MSG(SUBSET,
-		 nullptr,
-		 "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)",
-		 i, length);
-      return false;
-    }
-
-    if (instruction_start == instruction_end)
-      memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
-    else
-    {
-      memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset);
-      memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
-      /* if the instructions end at the end this was a composite glyph, else simple */
-      if (instruction_end == end_offset)
-      {
-	if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false;
-      }
-      else
-	/* zero instruction length, which is just before instruction_start */
-	memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
-    }
-
-    success = success && _write_loca_entry (i,
-					    glyf_prime_data_next - glyf_prime_data,
-					    use_short_loca,
-					    loca_prime_data,
-					    loca_prime_size);
-    _update_components (plan, glyf_prime_data_next, length);
-
-    // TODO: don't align to two bytes if using long loca.
-    glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
-  }
-
-  success = success && _write_loca_entry (glyph_ids.len,
-					  glyf_prime_data_next - glyf_prime_data,
-					  use_short_loca,
-					  loca_prime_data,
-					  loca_prime_size);
-  return success;
-}
-
-static bool
-_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t  &glyf,
-			  const char                     *glyf_data,
-			  hb_subset_plan_t               *plan,
-			  bool                           *use_short_loca,
-			  hb_blob_t                     **glyf_prime /* OUT */,
-			  hb_blob_t                     **loca_prime /* OUT */)
-{
-  // TODO(grieger): Sanity check allocation size for the new table.
-  hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs;
-
-  unsigned int glyf_prime_size;
-  unsigned int loca_prime_size;
-  hb_vector_t<unsigned int> instruction_ranges;
-  instruction_ranges.init ();
-
-  if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
-						      glyphs_to_retain,
-						      plan->drop_hints,
-						      use_short_loca,
-						      &glyf_prime_size,
-						      &loca_prime_size,
-						      &instruction_ranges))) {
-    instruction_ranges.fini ();
-    return false;
-  }
-
-  char *glyf_prime_data = (char *) calloc (1, glyf_prime_size);
-  char *loca_prime_data = (char *) calloc (1, loca_prime_size);
-  if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
-					     *use_short_loca,
-					     instruction_ranges,
-					     glyf_prime_size, glyf_prime_data,
-					     loca_prime_size, loca_prime_data))) {
-    free (glyf_prime_data);
-    free (loca_prime_data);
-    instruction_ranges.fini ();
-    return false;
-  }
-  instruction_ranges.fini ();
-
-  *glyf_prime = hb_blob_create (glyf_prime_data,
-				glyf_prime_size,
-				HB_MEMORY_MODE_READONLY,
-				glyf_prime_data,
-				free);
-  *loca_prime = hb_blob_create (loca_prime_data,
-				loca_prime_size,
-				HB_MEMORY_MODE_READONLY,
-				loca_prime_data,
-				free);
-  return true;
-}
-
-/**
- * hb_subset_glyf:
- * Subsets the glyph table according to a provided plan.
- *
- * Return value: subsetted glyf table.
- *
- * Since: 1.7.5
- **/
-bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-			 bool             *use_short_loca, /* OUT */
-			 hb_blob_t       **glyf_prime, /* OUT */
-			 hb_blob_t       **loca_prime /* OUT */)
-{
-  hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table<OT::glyf> (plan->source);
-  const char *glyf_data = hb_blob_get_data (glyf_blob, nullptr);
-
-  OT::glyf::accelerator_t glyf;
-  glyf.init (plan->source);
-  bool result = _hb_subset_glyf_and_loca (glyf,
-					  glyf_data,
-					  plan,
-					  use_short_loca,
-					  glyf_prime,
-					  loca_prime);
-
-  hb_blob_destroy (glyf_blob);
-  glyf.fini ();
-
-  return result;
-}
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index f718a56..d92f33f 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -44,7 +44,44 @@
 
   input->unicodes = hb_set_create ();
   input->glyphs = hb_set_create ();
-  input->drop_layout = true;
+  input->name_ids = hb_set_create ();
+  hb_set_add_range (input->name_ids, 0, 6);
+  input->drop_tables = hb_set_create ();
+  input->drop_hints = false;
+  input->desubroutinize = false;
+  input->retain_gids = false;
+
+  hb_tag_t default_drop_tables[] = {
+    // Layout disabled by default
+    HB_TAG ('G', 'S', 'U', 'B'),
+    HB_TAG ('G', 'P', 'O', 'S'),
+    HB_TAG ('G', 'D', 'E', 'F'),
+    HB_TAG ('m', 'o', 'r', 'x'),
+    HB_TAG ('m', 'o', 'r', 't'),
+    HB_TAG ('k', 'e', 'r', 'x'),
+    HB_TAG ('k', 'e', 'r', 'n'),
+
+    // Copied from fontTools:
+    HB_TAG ('B', 'A', 'S', 'E'),
+    HB_TAG ('J', 'S', 'T', 'F'),
+    HB_TAG ('D', 'S', 'I', 'G'),
+    HB_TAG ('E', 'B', 'D', 'T'),
+    HB_TAG ('E', 'B', 'L', 'C'),
+    HB_TAG ('E', 'B', 'S', 'C'),
+    HB_TAG ('S', 'V', 'G', ' '),
+    HB_TAG ('P', 'C', 'L', 'T'),
+    HB_TAG ('L', 'T', 'S', 'H'),
+    // Graphite tables
+    HB_TAG ('F', 'e', 'a', 't'),
+    HB_TAG ('G', 'l', 'a', 't'),
+    HB_TAG ('G', 'l', 'o', 'c'),
+    HB_TAG ('S', 'i', 'l', 'f'),
+    HB_TAG ('S', 'i', 'l', 'l'),
+    // Colour
+    HB_TAG ('s', 'b', 'i', 'x')
+  };
+
+  input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
 
   return input;
 }
@@ -78,6 +115,8 @@
 
   hb_set_destroy (subset_input->unicodes);
   hb_set_destroy (subset_input->glyphs);
+  hb_set_destroy (subset_input->name_ids);
+  hb_set_destroy (subset_input->drop_tables);
 
   free (subset_input);
 }
@@ -106,6 +145,18 @@
   return subset_input->glyphs;
 }
 
+HB_EXTERN hb_set_t *
+hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
+{
+  return subset_input->name_ids;
+}
+
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input)
+{
+  return subset_input->drop_tables;
+}
+
 HB_EXTERN void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
 				hb_bool_t drop_hints)
@@ -120,21 +171,8 @@
 }
 
 HB_EXTERN void
-hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
-				 hb_bool_t drop_layout)
-{
-  subset_input->drop_layout = drop_layout;
-}
-
-HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
-{
-  return subset_input->drop_layout;
-}
-
-HB_EXTERN void
 hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-        hb_bool_t desubroutinize)
+				    hb_bool_t desubroutinize)
 {
   subset_input->desubroutinize = desubroutinize;
 }
@@ -144,3 +182,27 @@
 {
   return subset_input->desubroutinize;
 }
+
+/**
+ * hb_subset_input_set_retain_gids:
+ * @subset_input: a subset_input.
+ * @retain_gids: If true the subsetter will not renumber glyph ids.
+ * Since: 2.4.0
+ **/
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+				 hb_bool_t retain_gids)
+{
+  subset_input->retain_gids = retain_gids;
+}
+
+/**
+ * hb_subset_input_get_retain_gids:
+ * Returns: value of retain_gids.
+ * Since: 2.4.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
+{
+  return subset_input->retain_gids;
+}
diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh
index 8dad94f..f6dd4ac 100644
--- a/src/hb-subset-input.hh
+++ b/src/hb-subset-input.hh
@@ -40,15 +40,17 @@
 
   hb_set_t *unicodes;
   hb_set_t *glyphs;
+  hb_set_t *name_ids;
+  hb_set_t *drop_tables;
 
-  bool drop_hints : 1;
-  bool drop_layout : 1;
-  bool desubroutinize : 1;
+  bool drop_hints;
+  bool desubroutinize;
+  bool retain_gids;
   /* TODO
    *
    * features
    * lookups
-   * nameIDs
+   * name_ids
    * ...
    */
 };
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 5c0983b..f4912f8 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -31,42 +31,26 @@
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
 #include "hb-ot-cff1-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-stat-table.hh"
 
-static void
-_add_gid_and_children (const OT::glyf::accelerator_t &glyf,
-		       hb_codepoint_t gid,
-		       hb_set_t *gids_to_retain)
-{
-  if (hb_set_has (gids_to_retain, gid))
-    // Already visited this gid, ignore.
-    return;
-
-  hb_set_add (gids_to_retain, gid);
-
-  OT::glyf::CompositeGlyphHeader::Iterator composite;
-  if (glyf.get_composite (gid, &composite))
-  {
-    do
-    {
-      _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain);
-    } while (composite.move_to_next());
-  }
-}
-
-static void
+#ifndef HB_NO_SUBSET_CFF
+static inline void
 _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
-           hb_codepoint_t gid,
-           hb_set_t *gids_to_retain)
+			  hb_codepoint_t gid,
+			  hb_set_t *gids_to_retain)
 {
   hb_codepoint_t base_gid, accent_gid;
   if (cff.get_seac_components (gid, &base_gid, &accent_gid))
   {
-    hb_set_add (gids_to_retain, base_gid);
-    hb_set_add (gids_to_retain, accent_gid);
+    gids_to_retain->add (base_gid);
+    gids_to_retain->add (accent_gid);
   }
 }
+#endif
 
-static void
+#ifndef HB_NO_SUBSET_LAYOUT
+static inline void
 _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
 {
   hb_set_t lookup_indices;
@@ -80,8 +64,20 @@
 					   &lookup_indices,
 					   gids_to_retain);
 }
+#endif
 
-static void
+static inline void
+_cmap_closure (hb_face_t           *face,
+	       const hb_set_t      *unicodes,
+	       hb_set_t            *glyphset)
+{
+  OT::cmap::accelerator_t cmap;
+  cmap.init (face);
+  cmap.table->closure_glyphs (unicodes, glyphset);
+  cmap.fini ();
+}
+
+static inline void
 _remove_invalid_gids (hb_set_t *glyphs,
 		      unsigned int num_glyphs)
 {
@@ -93,23 +89,21 @@
   }
 }
 
-static hb_set_t *
-_populate_gids_to_retain (hb_face_t *face,
+static void
+_populate_gids_to_retain (hb_subset_plan_t* plan,
 			  const hb_set_t *unicodes,
-			  bool close_over_gsub,
-			  hb_set_t *unicodes_to_retain,
-			  hb_map_t *codepoint_to_glyph,
-			  hb_vector_t<hb_codepoint_t> *glyphs)
+			  const hb_set_t *input_glyphs_to_retain,
+			  bool close_over_gsub)
 {
   OT::cmap::accelerator_t cmap;
   OT::glyf::accelerator_t glyf;
   OT::cff1::accelerator_t cff;
-  cmap.init (face);
-  glyf.init (face);
-  cff.init (face);
+  cmap.init (plan->source);
+  glyf.init (plan->source);
+  cff.init (plan->source);
 
-  hb_set_t *initial_gids_to_retain = hb_set_create ();
-  initial_gids_to_retain->add (0); // Not-def
+  plan->_glyphset_gsub->add (0); // Not-def
+  hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
 
   hb_codepoint_t cp = HB_SET_VALUE_INVALID;
   while (unicodes->next (&cp))
@@ -120,48 +114,84 @@
       DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
       continue;
     }
-    unicodes_to_retain->add (cp);
-    codepoint_to_glyph->set (cp, gid);
-    initial_gids_to_retain->add (gid);
+    plan->unicodes->add (cp);
+    plan->codepoint_to_glyph->set (cp, gid);
+    plan->_glyphset_gsub->add (gid);
   }
 
+  _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
+
+#ifndef HB_NO_SUBSET_LAYOUT
   if (close_over_gsub)
     // Add all glyphs needed for GSUB substitutions.
-    _gsub_closure (face, initial_gids_to_retain);
+    _gsub_closure (plan->source, plan->_glyphset_gsub);
+#endif
+  _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
 
   // Populate a full set of glyphs to retain by adding all referenced
   // composite glyphs.
   hb_codepoint_t gid = HB_SET_VALUE_INVALID;
-  hb_set_t *all_gids_to_retain = hb_set_create ();
-  while (initial_gids_to_retain->next (&gid))
+  while (plan->_glyphset_gsub->next (&gid))
   {
-    _add_gid_and_children (glyf, gid, all_gids_to_retain);
+    glyf.add_gid_and_children (gid, plan->_glyphset);
+#ifndef HB_NO_SUBSET_CFF
     if (cff.is_valid ())
-      _add_cff_seac_components (cff, gid, all_gids_to_retain);
+      _add_cff_seac_components (cff, gid, plan->_glyphset);
+#endif
   }
-  hb_set_destroy (initial_gids_to_retain);
 
-  _remove_invalid_gids (all_gids_to_retain, face->get_num_glyphs ());
-
-  glyphs->alloc (all_gids_to_retain->get_population ());
-  gid = HB_SET_VALUE_INVALID;
-  while (all_gids_to_retain->next (&gid))
-    glyphs->push (gid);
+  _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
 
   cff.fini ();
   glyf.fini ();
   cmap.fini ();
-
-  return all_gids_to_retain;
 }
 
 static void
-_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
-				hb_map_t *glyph_map)
+_create_old_gid_to_new_gid_map (const hb_face_t *face,
+				bool             retain_gids,
+				const hb_set_t  *all_gids_to_retain,
+				hb_map_t        *glyph_map, /* OUT */
+				hb_map_t        *reverse_glyph_map, /* OUT */
+				unsigned int    *num_glyphs /* OUT */)
 {
-  for (unsigned int i = 0; i < glyphs.len; i++) {
-    glyph_map->set (glyphs[i], i);
+  if (!retain_gids)
+  {
+    + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
+    | hb_sink (reverse_glyph_map)
+    ;
+    *num_glyphs = reverse_glyph_map->get_population ();
+  } else {
+    + hb_iter (all_gids_to_retain)
+    | hb_map ([] (hb_codepoint_t _) {
+		return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _);
+	      })
+    | hb_sink (reverse_glyph_map)
+    ;
+
+    unsigned max_glyph =
+    + hb_iter (all_gids_to_retain)
+    | hb_reduce (hb_max, 0u)
+    ;
+    *num_glyphs = max_glyph + 1;
   }
+
+  + reverse_glyph_map->iter ()
+  | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
+  | hb_sink (glyph_map)
+  ;
+}
+
+static void
+_nameid_closure (hb_face_t *face,
+		 hb_set_t  *nameids)
+{
+#ifndef HB_NO_STAT
+  face->table.STAT->collect_name_ids (nameids);
+#endif
+#ifndef HB_NO_VAR
+  face->table.fvar->collect_name_ids (nameids);
+#endif
 }
 
 /**
@@ -175,28 +205,38 @@
  * Since: 1.7.5
  **/
 hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t           *face,
-		       hb_subset_input_t   *input)
+hb_subset_plan_create (hb_face_t         *face,
+		       hb_subset_input_t *input)
 {
   hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
 
   plan->drop_hints = input->drop_hints;
-  plan->drop_layout = input->drop_layout;
   plan->desubroutinize = input->desubroutinize;
-  plan->unicodes = hb_set_create();
-  plan->glyphs.init();
+  plan->retain_gids = input->retain_gids;
+  plan->unicodes = hb_set_create ();
+  plan->name_ids = hb_set_reference (input->name_ids);
+  _nameid_closure (face, plan->name_ids);
+  plan->drop_tables = hb_set_reference (input->drop_tables);
   plan->source = hb_face_reference (face);
   plan->dest = hb_face_builder_create ();
-  plan->codepoint_to_glyph = hb_map_create();
-  plan->glyph_map = hb_map_create();
-  plan->glyphset = _populate_gids_to_retain (face,
-					     input->unicodes,
-					     !plan->drop_layout,
-					     plan->unicodes,
-					     plan->codepoint_to_glyph,
-					     &plan->glyphs);
-  _create_old_gid_to_new_gid_map (plan->glyphs,
-				  plan->glyph_map);
+
+  plan->_glyphset = hb_set_create ();
+  plan->_glyphset_gsub = hb_set_create ();
+  plan->codepoint_to_glyph = hb_map_create ();
+  plan->glyph_map = hb_map_create ();
+  plan->reverse_glyph_map = hb_map_create ();
+
+  _populate_gids_to_retain (plan,
+			    input->unicodes,
+			    input->glyphs,
+			    !input->drop_tables->has (HB_OT_TAG_GSUB));
+
+  _create_old_gid_to_new_gid_map (face,
+				  input->retain_gids,
+				  plan->_glyphset,
+				  plan->glyph_map,
+				  plan->reverse_glyph_map,
+				  &plan->_num_output_glyphs);
 
   return plan;
 }
@@ -212,12 +252,15 @@
   if (!hb_object_destroy (plan)) return;
 
   hb_set_destroy (plan->unicodes);
-  plan->glyphs.fini ();
+  hb_set_destroy (plan->name_ids);
+  hb_set_destroy (plan->drop_tables);
   hb_face_destroy (plan->source);
   hb_face_destroy (plan->dest);
   hb_map_destroy (plan->codepoint_to_glyph);
   hb_map_destroy (plan->glyph_map);
-  hb_set_destroy (plan->glyphset);
+  hb_map_destroy (plan->reverse_glyph_map);
+  hb_set_destroy (plan->_glyphset);
+  hb_set_destroy (plan->_glyphset_gsub);
 
   free (plan);
 }
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index a710a4d..af2337e 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -33,30 +33,82 @@
 #include "hb-subset-input.hh"
 
 #include "hb-map.hh"
+#include "hb-set.hh"
 
 struct hb_subset_plan_t
 {
   hb_object_header_t header;
 
   bool drop_hints : 1;
-  bool drop_layout : 1;
   bool desubroutinize : 1;
+  bool retain_gids : 1;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
 
-  hb_vector_t<hb_codepoint_t> glyphs;
-  hb_set_t *glyphset;
+  // name_ids we would like to retain
+  hb_set_t *name_ids;
 
+  // Tables which should be dropped.
+  hb_set_t *drop_tables;
+
+  // The glyph subset
   hb_map_t *codepoint_to_glyph;
+
+  // Old -> New glyph id mapping
   hb_map_t *glyph_map;
+  hb_map_t *reverse_glyph_map;
 
   // Plan is only good for a specific source/dest so keep them with it
   hb_face_t *source;
   hb_face_t *dest;
 
-  bool new_gid_for_codepoint (hb_codepoint_t codepoint,
-			      hb_codepoint_t *new_gid) const
+  unsigned int _num_output_glyphs;
+  hb_set_t *_glyphset;
+  hb_set_t *_glyphset_gsub;
+
+ public:
+
+  /*
+   * The set of input glyph ids which will be retained in the subset.
+   * Does NOT include ids kept due to retain_gids. You probably want to use
+   * glyph_map/reverse_glyph_map.
+   */
+  inline const hb_set_t *
+  glyphset () const
+  {
+    return _glyphset;
+  }
+
+  /*
+   * The set of input glyph ids which will be retained in the subset.
+   */
+  inline const hb_set_t *
+  glyphset_gsub () const
+  {
+    return _glyphset_gsub;
+  }
+
+  /*
+   * The total number of output glyphs in the final subset.
+   */
+  inline unsigned int
+  num_output_glyphs () const
+  {
+    return _num_output_glyphs;
+  }
+
+  /*
+   * Given an output gid , returns true if that glyph id is an empty
+   * glyph (ie. it's a gid that we are dropping all data for).
+   */
+  inline bool is_empty_glyph (hb_codepoint_t gid) const
+  {
+    return !_glyphset->has (gid);
+  }
+
+  inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
+				     hb_codepoint_t *new_gid) const
   {
     hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
     if (old_gid == HB_MAP_VALUE_INVALID)
@@ -65,8 +117,8 @@
     return new_gid_for_old_gid (old_gid, new_gid);
   }
 
-  bool new_gid_for_old_gid (hb_codepoint_t old_gid,
-			    hb_codepoint_t *new_gid) const
+  inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
+				   hb_codepoint_t *new_gid) const
   {
     hb_codepoint_t gid = glyph_map->get (old_gid);
     if (gid == HB_MAP_VALUE_INVALID)
@@ -76,7 +128,18 @@
     return true;
   }
 
-  bool
+  inline bool old_gid_for_new_gid (hb_codepoint_t  new_gid,
+				   hb_codepoint_t *old_gid) const
+  {
+    hb_codepoint_t gid = reverse_glyph_map->get (new_gid);
+    if (gid == HB_MAP_VALUE_INVALID)
+      return false;
+
+    *old_gid = gid;
+    return true;
+  }
+
+  inline bool
   add_table (hb_tag_t tag,
 	     hb_blob_t *contents)
   {
@@ -94,7 +157,7 @@
 
 HB_INTERNAL hb_subset_plan_t *
 hb_subset_plan_create (hb_face_t           *face,
-                       hb_subset_input_t   *input);
+		       hb_subset_input_t   *input);
 
 HB_INTERNAL void
 hb_subset_plan_destroy (hb_subset_plan_t *plan);
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 37e7cec..ec2f889 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -28,7 +28,6 @@
 #include "hb-open-type.hh"
 
 #include "hb-subset.hh"
-#include "hb-subset-glyf.hh"
 
 #include "hb-open-file.hh"
 #include "hb-ot-cmap-table.hh"
@@ -43,16 +42,20 @@
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-vorg-table.hh"
+#include "hb-ot-name-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 
 
-static unsigned int
+HB_UNUSED static inline unsigned int
+_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
+				  unsigned int table_len);
+static inline unsigned int
 _plan_estimate_subset_table_size (hb_subset_plan_t *plan,
 				  unsigned int table_len)
 {
   unsigned int src_glyphs = plan->source->get_num_glyphs ();
-  unsigned int dst_glyphs = plan->glyphset->get_population ();
+  unsigned int dst_glyphs = plan->glyphset ()->get_population ();
 
   if (unlikely (!src_glyphs))
     return 512 + table_len;
@@ -64,47 +67,58 @@
 static bool
 _subset2 (hb_subset_plan_t *plan)
 {
+  bool result = false;
   hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
   const TableType *table = source_blob->as<TableType> ();
 
   hb_tag_t tag = TableType::tableTag;
-  hb_bool_t result = false;
   if (source_blob->data)
   {
     hb_vector_t<char> buf;
+    /* TODO Not all tables are glyph-related.  'name' table size for example should not be
+     * affected by number of glyphs.  Accommodate that. */
     unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
     DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
     if (unlikely (!buf.alloc (buf_size)))
     {
       DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
+      hb_blob_destroy (source_blob);
       return false;
     }
   retry:
     hb_serialize_context_t serializer ((void *) buf, buf_size);
+    serializer.start_serialize<TableType> ();
     hb_subset_context_t c (plan, &serializer);
-    result = table->subset (&c);
-    if (serializer.in_error ())
+    bool needed = table->subset (&c);
+    if (serializer.ran_out_of_room)
     {
       buf_size += (buf_size >> 1) + 32;
       DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
       if (unlikely (!buf.alloc (buf_size)))
       {
 	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
+	hb_blob_destroy (source_blob);
 	return false;
       }
       goto retry;
     }
+    serializer.end_serialize ();
+
+    result = !serializer.in_error ();
+
     if (result)
     {
-      hb_blob_t *dest_blob = serializer.copy_blob ();
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
-      result = c.plan->add_table (tag, dest_blob);
-      hb_blob_destroy (dest_blob);
-    }
-    else
-    {
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
-      result = true;
+      if (needed)
+      {
+	hb_blob_t *dest_blob = serializer.copy_blob ();
+	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
+	result = c.plan->add_table (tag, dest_blob);
+	hb_blob_destroy (dest_blob);
+      }
+      else
+      {
+	DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
+      }
     }
   }
   else
@@ -143,10 +157,13 @@
   bool result = true;
   switch (tag) {
     case HB_OT_TAG_glyf:
-      result = _subset<const OT::glyf> (plan);
+      result = _subset2<const OT::glyf> (plan);
       break;
     case HB_OT_TAG_hdmx:
-      result = _subset<const OT::hdmx> (plan);
+      result = _subset2<const OT::hdmx> (plan);
+      break;
+    case HB_OT_TAG_name:
+      result = _subset2<const OT::name> (plan);
       break;
     case HB_OT_TAG_head:
       // TODO that won't work well if there is no glyf
@@ -157,29 +174,31 @@
       DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx");
       return true;
     case HB_OT_TAG_hmtx:
-      result = _subset<const OT::hmtx> (plan);
+      result = _subset2<const OT::hmtx> (plan);
       break;
     case HB_OT_TAG_vhea:
       DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx");
       return true;
     case HB_OT_TAG_vmtx:
-      result = _subset<const OT::vmtx> (plan);
+      result = _subset2<const OT::vmtx> (plan);
       break;
     case HB_OT_TAG_maxp:
-      result = _subset<const OT::maxp> (plan);
+      result = _subset2<const OT::maxp> (plan);
       break;
     case HB_OT_TAG_loca:
       DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
       return true;
     case HB_OT_TAG_cmap:
-      result = _subset<const OT::cmap> (plan);
+      result = _subset2<const OT::cmap> (plan);
       break;
     case HB_OT_TAG_OS2:
-      result = _subset<const OT::OS2> (plan);
+      result = _subset2<const OT::OS2> (plan);
       break;
     case HB_OT_TAG_post:
-      result = _subset<const OT::post> (plan);
+      result = _subset2<const OT::post> (plan);
       break;
+
+#ifndef HB_NO_SUBSET_CFF
     case HB_OT_TAG_cff1:
       result = _subset<const OT::cff1> (plan);
       break;
@@ -187,8 +206,11 @@
       result = _subset<const OT::cff2> (plan);
       break;
     case HB_OT_TAG_VORG:
-      result = _subset<const OT::VORG> (plan);
+      result = _subset2<const OT::VORG> (plan);
       break;
+#endif
+
+#ifndef HB_NO_SUBSET_LAYOUT
     case HB_OT_TAG_GDEF:
       result = _subset2<const OT::GDEF> (plan);
       break;
@@ -198,6 +220,7 @@
     case HB_OT_TAG_GPOS:
       result = _subset2<const OT::GPOS> (plan);
       break;
+#endif
 
     default:
       hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
@@ -215,6 +238,9 @@
 static bool
 _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
 {
+  if (plan->drop_tables->has (tag))
+    return true;
+
   switch (tag) {
     case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
     case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */
@@ -223,31 +249,19 @@
     case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
     case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
       return plan->drop_hints;
+
+#ifdef HB_NO_SUBSET_LAYOUT
     // Drop Layout Tables if requested.
     case HB_OT_TAG_GDEF:
     case HB_OT_TAG_GPOS:
     case HB_OT_TAG_GSUB:
-      return plan->drop_layout;
-    // Drop these tables below by default, list pulled
-    // from fontTools:
-    case HB_TAG ('B', 'A', 'S', 'E'):
-    case HB_TAG ('J', 'S', 'T', 'F'):
-    case HB_TAG ('D', 'S', 'I', 'G'):
-    case HB_TAG ('E', 'B', 'D', 'T'):
-    case HB_TAG ('E', 'B', 'L', 'C'):
-    case HB_TAG ('E', 'B', 'S', 'C'):
-    case HB_TAG ('S', 'V', 'G', ' '):
-    case HB_TAG ('P', 'C', 'L', 'T'):
-    case HB_TAG ('L', 'T', 'S', 'H'):
-    // Graphite tables:
-    case HB_TAG ('F', 'e', 'a', 't'):
-    case HB_TAG ('G', 'l', 'a', 't'):
-    case HB_TAG ('G', 'l', 'o', 'c'):
-    case HB_TAG ('S', 'i', 'l', 'f'):
-    case HB_TAG ('S', 'i', 'l', 'l'):
-    // Colour
-    case HB_TAG ('s', 'b', 'i', 'x'):
+    case HB_TAG ('m', 'o', 'r', 'x'):
+    case HB_TAG ('m', 'o', 'r', 't'):
+    case HB_TAG ('k', 'e', 'r', 'x'):
+    case HB_TAG ('k', 'e', 'r', 'n'):
       return true;
+#endif
+
     default:
       return false;
   }
@@ -271,17 +285,19 @@
   hb_tag_t table_tags[32];
   unsigned int offset = 0, count;
   bool success = true;
+  hb_set_t tags_set;
   do {
     count = ARRAY_LENGTH (table_tags);
     hb_face_get_table_tags (source, offset, &count, table_tags);
     for (unsigned int i = 0; i < count; i++)
     {
       hb_tag_t tag = table_tags[i];
-      if (_should_drop_table (plan, tag))
+      if (_should_drop_table (plan, tag) && !tags_set.has (tag))
       {
 	DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag));
 	continue;
       }
+      tags_set.add (tag);
       success = success && _subset_table (plan, tag);
     }
     offset += count;
diff --git a/src/hb-subset.h b/src/hb-subset.h
index f582e46..960afef 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -54,6 +54,12 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
 
+HB_EXTERN hb_set_t *
+hb_subset_input_nameid_set (hb_subset_input_t *subset_input);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input);
+
 HB_EXTERN void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
 				hb_bool_t drop_hints);
@@ -61,17 +67,17 @@
 hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
 
 HB_EXTERN void
-hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
-				 hb_bool_t drop_layout);
-HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
-
-HB_EXTERN void
 hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-        hb_bool_t desubroutinize);
+				    hb_bool_t desubroutinize);
 HB_EXTERN hb_bool_t
 hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
 
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+				 hb_bool_t retain_gids);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
+
 /* hb_subset () */
 HB_EXTERN hb_face_t *
 hb_subset (hb_face_t *source, hb_subset_input_t *input);
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
index 45cb763..b8dd07a 100644
--- a/src/hb-subset.hh
+++ b/src/hb-subset.hh
@@ -40,9 +40,19 @@
        hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET>
 {
   const char *get_name () { return "SUBSET"; }
-  template <typename T>
-  bool dispatch (const T &obj) { return obj.subset (this); }
-  static bool default_return_value () { return true; }
+  static return_t default_return_value () { return true; }
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.subset (this, hb_forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
 
   hb_subset_plan_t *plan;
   hb_serialize_context_t *serializer;
diff --git a/src/hb-ucd-table.hh b/src/hb-ucd-table.hh
new file mode 100644
index 0000000..8b7d648
--- /dev/null
+++ b/src/hb-ucd-table.hh
@@ -0,0 +1,6696 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-ucd-table.py ucd.nounihan.grouped.xml
+ *
+ * on file with this description: Unicode 12.1.0
+ */
+
+#ifndef HB_UCD_TABLE_HH
+#define HB_UCD_TABLE_HH
+
+#include "hb.hh"
+
+static const hb_script_t
+_hb_ucd_sc_map[153] =
+{
+                   HB_SCRIPT_COMMON,              HB_SCRIPT_INHERITED,
+                  HB_SCRIPT_UNKNOWN,                 HB_SCRIPT_ARABIC,
+                 HB_SCRIPT_ARMENIAN,                HB_SCRIPT_BENGALI,
+                 HB_SCRIPT_CYRILLIC,             HB_SCRIPT_DEVANAGARI,
+                 HB_SCRIPT_GEORGIAN,                  HB_SCRIPT_GREEK,
+                 HB_SCRIPT_GUJARATI,               HB_SCRIPT_GURMUKHI,
+                   HB_SCRIPT_HANGUL,                    HB_SCRIPT_HAN,
+                   HB_SCRIPT_HEBREW,               HB_SCRIPT_HIRAGANA,
+                  HB_SCRIPT_KANNADA,               HB_SCRIPT_KATAKANA,
+                      HB_SCRIPT_LAO,                  HB_SCRIPT_LATIN,
+                HB_SCRIPT_MALAYALAM,                  HB_SCRIPT_ORIYA,
+                    HB_SCRIPT_TAMIL,                 HB_SCRIPT_TELUGU,
+                     HB_SCRIPT_THAI,                HB_SCRIPT_TIBETAN,
+                 HB_SCRIPT_BOPOMOFO,                HB_SCRIPT_BRAILLE,
+       HB_SCRIPT_CANADIAN_SYLLABICS,               HB_SCRIPT_CHEROKEE,
+                 HB_SCRIPT_ETHIOPIC,                  HB_SCRIPT_KHMER,
+                HB_SCRIPT_MONGOLIAN,                HB_SCRIPT_MYANMAR,
+                    HB_SCRIPT_OGHAM,                  HB_SCRIPT_RUNIC,
+                  HB_SCRIPT_SINHALA,                 HB_SCRIPT_SYRIAC,
+                   HB_SCRIPT_THAANA,                     HB_SCRIPT_YI,
+                  HB_SCRIPT_DESERET,                 HB_SCRIPT_GOTHIC,
+               HB_SCRIPT_OLD_ITALIC,                  HB_SCRIPT_BUHID,
+                  HB_SCRIPT_HANUNOO,                HB_SCRIPT_TAGALOG,
+                 HB_SCRIPT_TAGBANWA,                HB_SCRIPT_CYPRIOT,
+                    HB_SCRIPT_LIMBU,               HB_SCRIPT_LINEAR_B,
+                  HB_SCRIPT_OSMANYA,                HB_SCRIPT_SHAVIAN,
+                   HB_SCRIPT_TAI_LE,               HB_SCRIPT_UGARITIC,
+                 HB_SCRIPT_BUGINESE,                 HB_SCRIPT_COPTIC,
+               HB_SCRIPT_GLAGOLITIC,             HB_SCRIPT_KHAROSHTHI,
+              HB_SCRIPT_NEW_TAI_LUE,            HB_SCRIPT_OLD_PERSIAN,
+             HB_SCRIPT_SYLOTI_NAGRI,               HB_SCRIPT_TIFINAGH,
+                 HB_SCRIPT_BALINESE,              HB_SCRIPT_CUNEIFORM,
+                      HB_SCRIPT_NKO,               HB_SCRIPT_PHAGS_PA,
+               HB_SCRIPT_PHOENICIAN,                 HB_SCRIPT_CARIAN,
+                     HB_SCRIPT_CHAM,               HB_SCRIPT_KAYAH_LI,
+                   HB_SCRIPT_LEPCHA,                 HB_SCRIPT_LYCIAN,
+                   HB_SCRIPT_LYDIAN,               HB_SCRIPT_OL_CHIKI,
+                   HB_SCRIPT_REJANG,             HB_SCRIPT_SAURASHTRA,
+                HB_SCRIPT_SUNDANESE,                    HB_SCRIPT_VAI,
+                  HB_SCRIPT_AVESTAN,                  HB_SCRIPT_BAMUM,
+     HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,       HB_SCRIPT_IMPERIAL_ARAMAIC,
+    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+                 HB_SCRIPT_JAVANESE,                 HB_SCRIPT_KAITHI,
+                     HB_SCRIPT_LISU,           HB_SCRIPT_MEETEI_MAYEK,
+        HB_SCRIPT_OLD_SOUTH_ARABIAN,             HB_SCRIPT_OLD_TURKIC,
+                HB_SCRIPT_SAMARITAN,               HB_SCRIPT_TAI_THAM,
+                 HB_SCRIPT_TAI_VIET,                  HB_SCRIPT_BATAK,
+                   HB_SCRIPT_BRAHMI,                HB_SCRIPT_MANDAIC,
+                   HB_SCRIPT_CHAKMA,       HB_SCRIPT_MEROITIC_CURSIVE,
+     HB_SCRIPT_MEROITIC_HIEROGLYPHS,                   HB_SCRIPT_MIAO,
+                  HB_SCRIPT_SHARADA,           HB_SCRIPT_SORA_SOMPENG,
+                    HB_SCRIPT_TAKRI,              HB_SCRIPT_BASSA_VAH,
+       HB_SCRIPT_CAUCASIAN_ALBANIAN,               HB_SCRIPT_DUPLOYAN,
+                  HB_SCRIPT_ELBASAN,                HB_SCRIPT_GRANTHA,
+                   HB_SCRIPT_KHOJKI,              HB_SCRIPT_KHUDAWADI,
+                 HB_SCRIPT_LINEAR_A,               HB_SCRIPT_MAHAJANI,
+               HB_SCRIPT_MANICHAEAN,          HB_SCRIPT_MENDE_KIKAKUI,
+                     HB_SCRIPT_MODI,                    HB_SCRIPT_MRO,
+                HB_SCRIPT_NABATAEAN,      HB_SCRIPT_OLD_NORTH_ARABIAN,
+               HB_SCRIPT_OLD_PERMIC,           HB_SCRIPT_PAHAWH_HMONG,
+                HB_SCRIPT_PALMYRENE,            HB_SCRIPT_PAU_CIN_HAU,
+          HB_SCRIPT_PSALTER_PAHLAVI,                HB_SCRIPT_SIDDHAM,
+                  HB_SCRIPT_TIRHUTA,            HB_SCRIPT_WARANG_CITI,
+                     HB_SCRIPT_AHOM,  HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
+                   HB_SCRIPT_HATRAN,                HB_SCRIPT_MULTANI,
+            HB_SCRIPT_OLD_HUNGARIAN,            HB_SCRIPT_SIGNWRITING,
+                    HB_SCRIPT_ADLAM,              HB_SCRIPT_BHAIKSUKI,
+                  HB_SCRIPT_MARCHEN,                  HB_SCRIPT_OSAGE,
+                   HB_SCRIPT_TANGUT,                   HB_SCRIPT_NEWA,
+            HB_SCRIPT_MASARAM_GONDI,                  HB_SCRIPT_NUSHU,
+                  HB_SCRIPT_SOYOMBO,       HB_SCRIPT_ZANABAZAR_SQUARE,
+                    HB_SCRIPT_DOGRA,          HB_SCRIPT_GUNJALA_GONDI,
+          HB_SCRIPT_HANIFI_ROHINGYA,                HB_SCRIPT_MAKASAR,
+              HB_SCRIPT_MEDEFAIDRIN,            HB_SCRIPT_OLD_SOGDIAN,
+                  HB_SCRIPT_SOGDIAN,                HB_SCRIPT_ELYMAIC,
+              HB_SCRIPT_NANDINAGARI, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG,
+                   HB_SCRIPT_WANCHO,
+};
+static const uint16_t
+_hb_ucd_dm1_p0_map[825] =
+{
+   0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u,
+   0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu,
+   0x038Eu, 0x038Fu, 0x0390u, 0x03A9u, 0x03ACu, 0x03ADu, 0x03AEu, 0x03AFu,
+   0x03B0u, 0x03B9u, 0x03CCu, 0x03CDu, 0x03CEu, 0x2002u, 0x2003u, 0x3008u,
+   0x3009u, 0x349Eu, 0x34B9u, 0x34BBu, 0x34DFu, 0x3515u, 0x36EEu, 0x36FCu,
+   0x3781u, 0x382Fu, 0x3862u, 0x387Cu, 0x38C7u, 0x38E3u, 0x391Cu, 0x393Au,
+   0x3A2Eu, 0x3A6Cu, 0x3AE4u, 0x3B08u, 0x3B19u, 0x3B49u, 0x3B9Du, 0x3C18u,
+   0x3C4Eu, 0x3D33u, 0x3D96u, 0x3EACu, 0x3EB8u, 0x3F1Bu, 0x3FFCu, 0x4008u,
+   0x4018u, 0x4039u, 0x4046u, 0x4096u, 0x40E3u, 0x412Fu, 0x4202u, 0x4227u,
+   0x42A0u, 0x4301u, 0x4334u, 0x4359u, 0x43D5u, 0x43D9u, 0x440Bu, 0x446Bu,
+   0x452Bu, 0x455Du, 0x4561u, 0x456Bu, 0x45D7u, 0x45F9u, 0x4635u, 0x46BEu,
+   0x46C7u, 0x4995u, 0x49E6u, 0x4A6Eu, 0x4A76u, 0x4AB2u, 0x4B33u, 0x4BCEu,
+   0x4CCEu, 0x4CEDu, 0x4CF8u, 0x4D56u, 0x4E0Du, 0x4E26u, 0x4E32u, 0x4E38u,
+   0x4E39u, 0x4E3Du, 0x4E41u, 0x4E82u, 0x4E86u, 0x4EAEu, 0x4EC0u, 0x4ECCu,
+   0x4EE4u, 0x4F60u, 0x4F80u, 0x4F86u, 0x4F8Bu, 0x4FAEu, 0x4FBBu, 0x4FBFu,
+   0x5002u, 0x502Bu, 0x507Au, 0x5099u, 0x50CFu, 0x50DAu, 0x50E7u, 0x5140u,
+   0x5145u, 0x514Du, 0x5154u, 0x5164u, 0x5167u, 0x5168u, 0x5169u, 0x516Du,
+   0x5177u, 0x5180u, 0x518Du, 0x5192u, 0x5195u, 0x5197u, 0x51A4u, 0x51ACu,
+   0x51B5u, 0x51B7u, 0x51C9u, 0x51CCu, 0x51DCu, 0x51DEu, 0x51F5u, 0x5203u,
+   0x5207u, 0x5217u, 0x5229u, 0x523Au, 0x523Bu, 0x5246u, 0x5272u, 0x5277u,
+   0x5289u, 0x529Bu, 0x52A3u, 0x52B3u, 0x52C7u, 0x52C9u, 0x52D2u, 0x52DEu,
+   0x52E4u, 0x52F5u, 0x52FAu, 0x5305u, 0x5306u, 0x5317u, 0x533Fu, 0x5349u,
+   0x5351u, 0x535Au, 0x5373u, 0x5375u, 0x537Du, 0x537Fu, 0x53C3u, 0x53CAu,
+   0x53DFu, 0x53E5u, 0x53EBu, 0x53F1u, 0x5406u, 0x540Fu, 0x541Du, 0x5438u,
+   0x5442u, 0x5448u, 0x5468u, 0x549Eu, 0x54A2u, 0x54BDu, 0x54F6u, 0x5510u,
+   0x5553u, 0x5555u, 0x5563u, 0x5584u, 0x5587u, 0x5599u, 0x559Du, 0x55ABu,
+   0x55B3u, 0x55C0u, 0x55C2u, 0x55E2u, 0x5606u, 0x5651u, 0x5668u, 0x5674u,
+   0x56F9u, 0x5716u, 0x5717u, 0x578Bu, 0x57CEu, 0x57F4u, 0x580Du, 0x5831u,
+   0x5832u, 0x5840u, 0x585Au, 0x585Eu, 0x58A8u, 0x58ACu, 0x58B3u, 0x58D8u,
+   0x58DFu, 0x58EEu, 0x58F2u, 0x58F7u, 0x5906u, 0x591Au, 0x5922u, 0x5944u,
+   0x5948u, 0x5951u, 0x5954u, 0x5962u, 0x5973u, 0x59D8u, 0x59ECu, 0x5A1Bu,
+   0x5A27u, 0x5A62u, 0x5A66u, 0x5AB5u, 0x5B08u, 0x5B28u, 0x5B3Eu, 0x5B85u,
+   0x5BC3u, 0x5BD8u, 0x5BE7u, 0x5BEEu, 0x5BF3u, 0x5BFFu, 0x5C06u, 0x5C22u,
+   0x5C3Fu, 0x5C60u, 0x5C62u, 0x5C64u, 0x5C65u, 0x5C6Eu, 0x5C8Du, 0x5CC0u,
+   0x5D19u, 0x5D43u, 0x5D50u, 0x5D6Bu, 0x5D6Eu, 0x5D7Cu, 0x5DB2u, 0x5DBAu,
+   0x5DE1u, 0x5DE2u, 0x5DFDu, 0x5E28u, 0x5E3Du, 0x5E69u, 0x5E74u, 0x5EA6u,
+   0x5EB0u, 0x5EB3u, 0x5EB6u, 0x5EC9u, 0x5ECAu, 0x5ED2u, 0x5ED3u, 0x5ED9u,
+   0x5EECu, 0x5EFEu, 0x5F04u, 0x5F22u, 0x5F53u, 0x5F62u, 0x5F69u, 0x5F6Bu,
+   0x5F8Bu, 0x5F9Au, 0x5FA9u, 0x5FADu, 0x5FCDu, 0x5FD7u, 0x5FF5u, 0x5FF9u,
+   0x6012u, 0x601Cu, 0x6075u, 0x6081u, 0x6094u, 0x60C7u, 0x60D8u, 0x60E1u,
+   0x6108u, 0x6144u, 0x6148u, 0x614Cu, 0x614Eu, 0x6160u, 0x6168u, 0x617Au,
+   0x618Eu, 0x6190u, 0x61A4u, 0x61AFu, 0x61B2u, 0x61DEu, 0x61F2u, 0x61F6u,
+   0x6200u, 0x6210u, 0x621Bu, 0x622Eu, 0x6234u, 0x625Du, 0x62B1u, 0x62C9u,
+   0x62CFu, 0x62D3u, 0x62D4u, 0x62FCu, 0x62FEu, 0x633Du, 0x6350u, 0x6368u,
+   0x637Bu, 0x6383u, 0x63A0u, 0x63A9u, 0x63C4u, 0x63C5u, 0x63E4u, 0x641Cu,
+   0x6422u, 0x6452u, 0x6469u, 0x6477u, 0x647Eu, 0x649Au, 0x649Du, 0x64C4u,
+   0x654Fu, 0x6556u, 0x656Cu, 0x6578u, 0x6599u, 0x65C5u, 0x65E2u, 0x65E3u,
+   0x6613u, 0x6649u, 0x6674u, 0x6688u, 0x6691u, 0x669Cu, 0x66B4u, 0x66C6u,
+   0x66F4u, 0x66F8u, 0x6700u, 0x6717u, 0x671Bu, 0x6721u, 0x674Eu, 0x6753u,
+   0x6756u, 0x675Eu, 0x677Bu, 0x6785u, 0x6797u, 0x67F3u, 0x67FAu, 0x6817u,
+   0x681Fu, 0x6852u, 0x6881u, 0x6885u, 0x688Eu, 0x68A8u, 0x6914u, 0x6942u,
+   0x69A3u, 0x69EAu, 0x6A02u, 0x6A13u, 0x6AA8u, 0x6AD3u, 0x6ADBu, 0x6B04u,
+   0x6B21u, 0x6B54u, 0x6B72u, 0x6B77u, 0x6B79u, 0x6B9Fu, 0x6BAEu, 0x6BBAu,
+   0x6BBBu, 0x6C4Eu, 0x6C67u, 0x6C88u, 0x6CBFu, 0x6CCCu, 0x6CCDu, 0x6CE5u,
+   0x6D16u, 0x6D1Bu, 0x6D1Eu, 0x6D34u, 0x6D3Eu, 0x6D41u, 0x6D69u, 0x6D6Au,
+   0x6D77u, 0x6D78u, 0x6D85u, 0x6DCBu, 0x6DDAu, 0x6DEAu, 0x6DF9u, 0x6E1Au,
+   0x6E2Fu, 0x6E6Eu, 0x6E9Cu, 0x6EBAu, 0x6EC7u, 0x6ECBu, 0x6ED1u, 0x6EDBu,
+   0x6F0Fu, 0x6F22u, 0x6F23u, 0x6F6Eu, 0x6FC6u, 0x6FEBu, 0x6FFEu, 0x701Bu,
+   0x701Eu, 0x7039u, 0x704Au, 0x7070u, 0x7077u, 0x707Du, 0x7099u, 0x70ADu,
+   0x70C8u, 0x70D9u, 0x7145u, 0x7149u, 0x716Eu, 0x719Cu, 0x71CEu, 0x71D0u,
+   0x7210u, 0x721Bu, 0x7228u, 0x722Bu, 0x7235u, 0x7250u, 0x7262u, 0x7280u,
+   0x7295u, 0x72AFu, 0x72C0u, 0x72FCu, 0x732Au, 0x7375u, 0x737Au, 0x7387u,
+   0x738Bu, 0x73A5u, 0x73B2u, 0x73DEu, 0x7406u, 0x7409u, 0x7422u, 0x7447u,
+   0x745Cu, 0x7469u, 0x7471u, 0x7485u, 0x7489u, 0x7498u, 0x74CAu, 0x7506u,
+   0x7524u, 0x753Bu, 0x753Eu, 0x7559u, 0x7565u, 0x7570u, 0x75E2u, 0x7610u,
+   0x761Du, 0x761Fu, 0x7642u, 0x7669u, 0x76CAu, 0x76DBu, 0x76E7u, 0x76F4u,
+   0x7701u, 0x771Eu, 0x771Fu, 0x7740u, 0x774Au, 0x778Bu, 0x77A7u, 0x784Eu,
+   0x786Bu, 0x788Cu, 0x7891u, 0x78CAu, 0x78CCu, 0x78FBu, 0x792Au, 0x793Cu,
+   0x793Eu, 0x7948u, 0x7949u, 0x7950u, 0x7956u, 0x795Du, 0x795Eu, 0x7965u,
+   0x797Fu, 0x798Du, 0x798Eu, 0x798Fu, 0x79AEu, 0x79CAu, 0x79EBu, 0x7A1Cu,
+   0x7A40u, 0x7A4Au, 0x7A4Fu, 0x7A81u, 0x7AB1u, 0x7ACBu, 0x7AEEu, 0x7B20u,
+   0x7BC0u, 0x7BC6u, 0x7BC9u, 0x7C3Eu, 0x7C60u, 0x7C7Bu, 0x7C92u, 0x7CBEu,
+   0x7CD2u, 0x7CD6u, 0x7CE3u, 0x7CE7u, 0x7CE8u, 0x7D00u, 0x7D10u, 0x7D22u,
+   0x7D2Fu, 0x7D5Bu, 0x7D63u, 0x7DA0u, 0x7DBEu, 0x7DC7u, 0x7DF4u, 0x7E02u,
+   0x7E09u, 0x7E37u, 0x7E41u, 0x7E45u, 0x7F3Eu, 0x7F72u, 0x7F79u, 0x7F7Au,
+   0x7F85u, 0x7F95u, 0x7F9Au, 0x7FBDu, 0x7FFAu, 0x8001u, 0x8005u, 0x8046u,
+   0x8060u, 0x806Fu, 0x8070u, 0x807Eu, 0x808Bu, 0x80ADu, 0x80B2u, 0x8103u,
+   0x813Eu, 0x81D8u, 0x81E8u, 0x81EDu, 0x8201u, 0x8204u, 0x8218u, 0x826Fu,
+   0x8279u, 0x828Bu, 0x8291u, 0x829Du, 0x82B1u, 0x82B3u, 0x82BDu, 0x82E5u,
+   0x82E6u, 0x831Du, 0x8323u, 0x8336u, 0x8352u, 0x8353u, 0x8363u, 0x83ADu,
+   0x83BDu, 0x83C9u, 0x83CAu, 0x83CCu, 0x83DCu, 0x83E7u, 0x83EFu, 0x83F1u,
+   0x843Du, 0x8449u, 0x8457u, 0x84EEu, 0x84F1u, 0x84F3u, 0x84FCu, 0x8516u,
+   0x8564u, 0x85CDu, 0x85FAu, 0x8606u, 0x8612u, 0x862Du, 0x863Fu, 0x8650u,
+   0x865Cu, 0x8667u, 0x8669u, 0x8688u, 0x86A9u, 0x86E2u, 0x870Eu, 0x8728u,
+   0x876Bu, 0x8779u, 0x8786u, 0x87BAu, 0x87E1u, 0x8801u, 0x881Fu, 0x884Cu,
+   0x8860u, 0x8863u, 0x88C2u, 0x88CFu, 0x88D7u, 0x88DEu, 0x88E1u, 0x88F8u,
+   0x88FAu, 0x8910u, 0x8941u, 0x8964u, 0x8986u, 0x898Bu, 0x8996u, 0x8AA0u,
+   0x8AAAu, 0x8ABFu, 0x8ACBu, 0x8AD2u, 0x8AD6u, 0x8AEDu, 0x8AF8u, 0x8AFEu,
+   0x8B01u, 0x8B39u, 0x8B58u, 0x8B80u, 0x8B8Au, 0x8C48u, 0x8C55u, 0x8CABu,
+   0x8CC1u, 0x8CC2u, 0x8CC8u, 0x8CD3u, 0x8D08u, 0x8D1Bu, 0x8D77u, 0x8DBCu,
+   0x8DCBu, 0x8DEFu, 0x8DF0u, 0x8ECAu, 0x8ED4u, 0x8F26u, 0x8F2Au, 0x8F38u,
+   0x8F3Bu, 0x8F62u, 0x8F9Eu, 0x8FB0u, 0x8FB6u, 0x9023u, 0x9038u, 0x9072u,
+   0x907Cu, 0x908Fu, 0x9094u, 0x90CEu, 0x90DEu, 0x90F1u, 0x90FDu, 0x9111u,
+   0x911Bu, 0x916Au, 0x9199u, 0x91B4u, 0x91CCu, 0x91CFu, 0x91D1u, 0x9234u,
+   0x9238u, 0x9276u, 0x927Cu, 0x92D7u, 0x92D8u, 0x9304u, 0x934Au, 0x93F9u,
+   0x9415u, 0x958Bu, 0x95ADu, 0x95B7u, 0x962Eu, 0x964Bu, 0x964Du, 0x9675u,
+   0x9678u, 0x967Cu, 0x9686u, 0x96A3u, 0x96B7u, 0x96B8u, 0x96C3u, 0x96E2u,
+   0x96E3u, 0x96F6u, 0x96F7u, 0x9723u, 0x9732u, 0x9748u, 0x9756u, 0x97DBu,
+   0x97E0u, 0x97FFu, 0x980Bu, 0x9818u, 0x9829u, 0x983Bu, 0x985Eu, 0x98E2u,
+   0x98EFu, 0x98FCu, 0x9928u, 0x9929u, 0x99A7u, 0x99C2u, 0x99F1u, 0x99FEu,
+   0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u,
+   0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u,
+   0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu,
+   0x9F9Cu,
+};
+static const uint16_t
+_hb_ucd_dm1_p2_map[110] =
+{
+   0x0122u, 0x051Cu, 0x0525u, 0x054Bu, 0x063Au, 0x0804u, 0x08DEu, 0x0A2Cu,
+   0x0B63u, 0x14E4u, 0x16A8u, 0x16EAu, 0x19C8u, 0x1B18u, 0x1D0Bu, 0x1DE4u,
+   0x1DE6u, 0x2183u, 0x219Fu, 0x2331u, 0x26D4u, 0x2844u, 0x284Au, 0x2B0Cu,
+   0x2BF1u, 0x300Au, 0x32B8u, 0x335Fu, 0x3393u, 0x339Cu, 0x33C3u, 0x33D5u,
+   0x346Du, 0x36A3u, 0x38A7u, 0x3A8Du, 0x3AFAu, 0x3CBCu, 0x3D1Eu, 0x3ED1u,
+   0x3F5Eu, 0x3F8Eu, 0x4263u, 0x42EEu, 0x43ABu, 0x4608u, 0x4735u, 0x4814u,
+   0x4C36u, 0x4C92u, 0x4FA1u, 0x4FB8u, 0x5044u, 0x50F2u, 0x50F3u, 0x5119u,
+   0x5133u, 0x5249u, 0x541Du, 0x5626u, 0x569Au, 0x56C5u, 0x597Cu, 0x5AA7u,
+   0x5BABu, 0x5C80u, 0x5CD0u, 0x5F86u, 0x61DAu, 0x6228u, 0x6247u, 0x62D9u,
+   0x633Eu, 0x64DAu, 0x6523u, 0x65A8u, 0x67A7u, 0x67B5u, 0x6B3Cu, 0x6C36u,
+   0x6CD5u, 0x6D6Bu, 0x6F2Cu, 0x6FB1u, 0x70D2u, 0x73CAu, 0x7667u, 0x78AEu,
+   0x7966u, 0x7CA8u, 0x7ED3u, 0x7F2Fu, 0x85D2u, 0x85EDu, 0x872Eu, 0x8BFAu,
+   0x8D77u, 0x9145u, 0x91DFu, 0x921Au, 0x940Au, 0x9496u, 0x95B6u, 0x9B30u,
+   0xA0CEu, 0xA105u, 0xA20Eu, 0xA291u, 0xA392u, 0xA600u,
+};
+static const uint32_t
+_hb_ucd_dm2_u32_map[638] =
+{
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Cu, 0x0338u, 0x226Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Du, 0x0338u, 0x2260u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Eu, 0x0338u, 0x226Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0300u, 0x00C0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0301u, 0x00C1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0302u, 0x00C2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0303u, 0x00C3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0304u, 0x0100u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0306u, 0x0102u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0307u, 0x0226u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0308u, 0x00C4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0309u, 0x1EA2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Au, 0x00C5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Cu, 0x01CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Fu, 0x0200u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0311u, 0x0202u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0323u, 0x1EA0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0325u, 0x1E00u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0328u, 0x0104u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0307u, 0x1E02u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0323u, 0x1E04u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0331u, 0x1E06u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0301u, 0x0106u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0302u, 0x0108u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0307u, 0x010Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x030Cu, 0x010Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0327u, 0x00C7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0307u, 0x1E0Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x030Cu, 0x010Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0323u, 0x1E0Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0327u, 0x1E10u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x032Du, 0x1E12u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0331u, 0x1E0Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0300u, 0x00C8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0301u, 0x00C9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0302u, 0x00CAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0303u, 0x1EBCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0304u, 0x0112u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0306u, 0x0114u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0307u, 0x0116u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0308u, 0x00CBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0309u, 0x1EBAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Cu, 0x011Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Fu, 0x0204u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0311u, 0x0206u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0323u, 0x1EB8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0327u, 0x0228u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0328u, 0x0118u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x032Du, 0x1E18u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0330u, 0x1E1Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0046u, 0x0307u, 0x1E1Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0301u, 0x01F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0302u, 0x011Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0304u, 0x1E20u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0306u, 0x011Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0307u, 0x0120u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x030Cu, 0x01E6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0327u, 0x0122u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0302u, 0x0124u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0307u, 0x1E22u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0308u, 0x1E26u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x030Cu, 0x021Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0323u, 0x1E24u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0327u, 0x1E28u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x032Eu, 0x1E2Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0300u, 0x00CCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0301u, 0x00CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0302u, 0x00CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0303u, 0x0128u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0304u, 0x012Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0306u, 0x012Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0307u, 0x0130u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0308u, 0x00CFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0309u, 0x1EC8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Cu, 0x01CFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Fu, 0x0208u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0311u, 0x020Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0323u, 0x1ECAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0328u, 0x012Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0330u, 0x1E2Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Au, 0x0302u, 0x0134u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0301u, 0x1E30u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x030Cu, 0x01E8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0323u, 0x1E32u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0327u, 0x0136u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0331u, 0x1E34u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0301u, 0x0139u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x030Cu, 0x013Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0323u, 0x1E36u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0327u, 0x013Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x032Du, 0x1E3Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0331u, 0x1E3Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0301u, 0x1E3Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0307u, 0x1E40u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0323u, 0x1E42u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0300u, 0x01F8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0301u, 0x0143u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0303u, 0x00D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0307u, 0x1E44u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x030Cu, 0x0147u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0323u, 0x1E46u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0327u, 0x0145u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x032Du, 0x1E4Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0331u, 0x1E48u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0300u, 0x00D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0301u, 0x00D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0302u, 0x00D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0303u, 0x00D5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0304u, 0x014Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0306u, 0x014Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0307u, 0x022Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0308u, 0x00D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0309u, 0x1ECEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Bu, 0x0150u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Cu, 0x01D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Fu, 0x020Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0311u, 0x020Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x031Bu, 0x01A0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0323u, 0x1ECCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0328u, 0x01EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0301u, 0x1E54u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0307u, 0x1E56u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0301u, 0x0154u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0307u, 0x1E58u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Cu, 0x0158u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Fu, 0x0210u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0311u, 0x0212u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0323u, 0x1E5Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0327u, 0x0156u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0331u, 0x1E5Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0301u, 0x015Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0302u, 0x015Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0307u, 0x1E60u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x030Cu, 0x0160u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0323u, 0x1E62u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0326u, 0x0218u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0327u, 0x015Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0307u, 0x1E6Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x030Cu, 0x0164u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0323u, 0x1E6Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0326u, 0x021Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0327u, 0x0162u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x032Du, 0x1E70u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0331u, 0x1E6Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0300u, 0x00D9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0301u, 0x00DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0302u, 0x00DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0303u, 0x0168u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0304u, 0x016Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0306u, 0x016Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0308u, 0x00DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0309u, 0x1EE6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Au, 0x016Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Bu, 0x0170u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Cu, 0x01D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Fu, 0x0214u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0311u, 0x0216u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x031Bu, 0x01AFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0323u, 0x1EE4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0324u, 0x1E72u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0328u, 0x0172u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x032Du, 0x1E76u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0330u, 0x1E74u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0303u, 0x1E7Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0323u, 0x1E7Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0300u, 0x1E80u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0301u, 0x1E82u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0302u, 0x0174u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0307u, 0x1E86u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0308u, 0x1E84u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0323u, 0x1E88u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0307u, 0x1E8Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0308u, 0x1E8Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0300u, 0x1EF2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0301u, 0x00DDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0302u, 0x0176u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0303u, 0x1EF8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0304u, 0x0232u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0307u, 0x1E8Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0308u, 0x0178u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0309u, 0x1EF6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0323u, 0x1EF4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0301u, 0x0179u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0302u, 0x1E90u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0307u, 0x017Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x030Cu, 0x017Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0323u, 0x1E92u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0331u, 0x1E94u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0300u, 0x00E0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0301u, 0x00E1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0302u, 0x00E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0303u, 0x00E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0304u, 0x0101u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0306u, 0x0103u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0307u, 0x0227u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0308u, 0x00E4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0309u, 0x1EA3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Au, 0x00E5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Cu, 0x01CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Fu, 0x0201u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0311u, 0x0203u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0323u, 0x1EA1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0325u, 0x1E01u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0328u, 0x0105u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0307u, 0x1E03u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0323u, 0x1E05u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0331u, 0x1E07u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0301u, 0x0107u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0302u, 0x0109u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0307u, 0x010Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x030Cu, 0x010Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0327u, 0x00E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0307u, 0x1E0Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x030Cu, 0x010Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0323u, 0x1E0Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0327u, 0x1E11u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x032Du, 0x1E13u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0331u, 0x1E0Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0300u, 0x00E8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0301u, 0x00E9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0302u, 0x00EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0303u, 0x1EBDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0304u, 0x0113u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0306u, 0x0115u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0307u, 0x0117u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0308u, 0x00EBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0309u, 0x1EBBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Cu, 0x011Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Fu, 0x0205u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0311u, 0x0207u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0323u, 0x1EB9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0327u, 0x0229u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0328u, 0x0119u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x032Du, 0x1E19u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0330u, 0x1E1Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0066u, 0x0307u, 0x1E1Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0301u, 0x01F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0302u, 0x011Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0304u, 0x1E21u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0306u, 0x011Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0307u, 0x0121u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x030Cu, 0x01E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0327u, 0x0123u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0302u, 0x0125u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0307u, 0x1E23u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0308u, 0x1E27u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x030Cu, 0x021Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0323u, 0x1E25u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0327u, 0x1E29u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x032Eu, 0x1E2Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0331u, 0x1E96u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0300u, 0x00ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0301u, 0x00EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0302u, 0x00EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0303u, 0x0129u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0304u, 0x012Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0306u, 0x012Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0308u, 0x00EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0309u, 0x1EC9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Cu, 0x01D0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Fu, 0x0209u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0311u, 0x020Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0323u, 0x1ECBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0328u, 0x012Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0330u, 0x1E2Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x0302u, 0x0135u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x030Cu, 0x01F0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0301u, 0x1E31u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x030Cu, 0x01E9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0323u, 0x1E33u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0327u, 0x0137u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0331u, 0x1E35u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0301u, 0x013Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x030Cu, 0x013Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0323u, 0x1E37u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0327u, 0x013Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x032Du, 0x1E3Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0331u, 0x1E3Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0301u, 0x1E3Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0307u, 0x1E41u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0323u, 0x1E43u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0300u, 0x01F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0301u, 0x0144u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0303u, 0x00F1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0307u, 0x1E45u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x030Cu, 0x0148u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0323u, 0x1E47u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0327u, 0x0146u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x032Du, 0x1E4Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0331u, 0x1E49u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0300u, 0x00F2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0301u, 0x00F3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0302u, 0x00F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0303u, 0x00F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0304u, 0x014Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0306u, 0x014Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0307u, 0x022Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0308u, 0x00F6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0309u, 0x1ECFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Bu, 0x0151u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Cu, 0x01D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Fu, 0x020Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0311u, 0x020Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x031Bu, 0x01A1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0323u, 0x1ECDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0328u, 0x01EBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0301u, 0x1E55u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0307u, 0x1E57u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0301u, 0x0155u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0307u, 0x1E59u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Cu, 0x0159u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Fu, 0x0211u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0311u, 0x0213u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0323u, 0x1E5Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0327u, 0x0157u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0331u, 0x1E5Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0301u, 0x015Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0302u, 0x015Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0307u, 0x1E61u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x030Cu, 0x0161u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0323u, 0x1E63u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0326u, 0x0219u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0327u, 0x015Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0307u, 0x1E6Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0308u, 0x1E97u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x030Cu, 0x0165u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0323u, 0x1E6Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0326u, 0x021Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0327u, 0x0163u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x032Du, 0x1E71u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0331u, 0x1E6Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0300u, 0x00F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0301u, 0x00FAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0302u, 0x00FBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0303u, 0x0169u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0304u, 0x016Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0306u, 0x016Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0308u, 0x00FCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0309u, 0x1EE7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Au, 0x016Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Bu, 0x0171u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Cu, 0x01D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Fu, 0x0215u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0311u, 0x0217u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x031Bu, 0x01B0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0323u, 0x1EE5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0324u, 0x1E73u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0328u, 0x0173u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x032Du, 0x1E77u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0330u, 0x1E75u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0303u, 0x1E7Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0323u, 0x1E7Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0300u, 0x1E81u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0301u, 0x1E83u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0302u, 0x0175u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0307u, 0x1E87u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0308u, 0x1E85u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x030Au, 0x1E98u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0323u, 0x1E89u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0307u, 0x1E8Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0308u, 0x1E8Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0300u, 0x1EF3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0301u, 0x00FDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0302u, 0x0177u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0303u, 0x1EF9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0304u, 0x0233u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0307u, 0x1E8Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0308u, 0x00FFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0309u, 0x1EF7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x030Au, 0x1E99u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0323u, 0x1EF5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0301u, 0x017Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0302u, 0x1E91u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0307u, 0x017Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x030Cu, 0x017Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0323u, 0x1E93u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0331u, 0x1E95u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0300u, 0x1FEDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0301u, 0x0385u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0342u, 0x1FC1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0300u, 0x1EA6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0301u, 0x1EA4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0303u, 0x1EAAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0309u, 0x1EA8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4u, 0x0304u, 0x01DEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5u, 0x0301u, 0x01FAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0301u, 0x01FCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0304u, 0x01E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7u, 0x0301u, 0x1E08u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0300u, 0x1EC0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0301u, 0x1EBEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0303u, 0x1EC4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0309u, 0x1EC2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CFu, 0x0301u, 0x1E2Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0300u, 0x1ED2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0301u, 0x1ED0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0303u, 0x1ED6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0309u, 0x1ED4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0301u, 0x1E4Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0304u, 0x022Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0308u, 0x1E4Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6u, 0x0304u, 0x022Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8u, 0x0301u, 0x01FEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0300u, 0x01DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0301u, 0x01D7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0304u, 0x01D5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x030Cu, 0x01D9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0300u, 0x1EA7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0301u, 0x1EA5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0303u, 0x1EABu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0309u, 0x1EA9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4u, 0x0304u, 0x01DFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5u, 0x0301u, 0x01FBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0301u, 0x01FDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0304u, 0x01E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7u, 0x0301u, 0x1E09u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0300u, 0x1EC1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0301u, 0x1EBFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0303u, 0x1EC5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0309u, 0x1EC3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EFu, 0x0301u, 0x1E2Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0300u, 0x1ED3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0301u, 0x1ED1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0303u, 0x1ED7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0309u, 0x1ED5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0301u, 0x1E4Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0304u, 0x022Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0308u, 0x1E4Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6u, 0x0304u, 0x022Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8u, 0x0301u, 0x01FFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0300u, 0x01DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0301u, 0x01D8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0304u, 0x01D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x030Cu, 0x01DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0300u, 0x1EB0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0301u, 0x1EAEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0303u, 0x1EB4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0309u, 0x1EB2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0300u, 0x1EB1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0301u, 0x1EAFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0303u, 0x1EB5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0309u, 0x1EB3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0300u, 0x1E14u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0301u, 0x1E16u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0300u, 0x1E15u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0301u, 0x1E17u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0300u, 0x1E50u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0301u, 0x1E52u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0300u, 0x1E51u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0301u, 0x1E53u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x015Au, 0x0307u, 0x1E64u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x015Bu, 0x0307u, 0x1E65u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0160u, 0x0307u, 0x1E66u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0161u, 0x0307u, 0x1E67u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0168u, 0x0301u, 0x1E78u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0169u, 0x0301u, 0x1E79u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x016Au, 0x0308u, 0x1E7Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x016Bu, 0x0308u, 0x1E7Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x017Fu, 0x0307u, 0x1E9Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0300u, 0x1EDCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0301u, 0x1EDAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0303u, 0x1EE0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0309u, 0x1EDEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0323u, 0x1EE2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0300u, 0x1EDDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0301u, 0x1EDBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0303u, 0x1EE1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0309u, 0x1EDFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0323u, 0x1EE3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0300u, 0x1EEAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0301u, 0x1EE8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0303u, 0x1EEEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0309u, 0x1EECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0323u, 0x1EF0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0300u, 0x1EEBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0301u, 0x1EE9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0303u, 0x1EEFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0309u, 0x1EEDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0323u, 0x1EF1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7u, 0x030Cu, 0x01EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01EAu, 0x0304u, 0x01ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01EBu, 0x0304u, 0x01EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0226u, 0x0304u, 0x01E0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0227u, 0x0304u, 0x01E1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0228u, 0x0306u, 0x1E1Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0229u, 0x0306u, 0x1E1Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x022Eu, 0x0304u, 0x0230u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x022Fu, 0x0304u, 0x0231u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0292u, 0x030Cu, 0x01EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0308u, 0x0301u, 0x0000u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0300u, 0x1FBAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0301u, 0x0386u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0304u, 0x1FB9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0306u, 0x1FB8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0313u, 0x1F08u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0314u, 0x1F09u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0345u, 0x1FBCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0300u, 0x1FC8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0301u, 0x0388u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0313u, 0x1F18u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0314u, 0x1F19u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0300u, 0x1FCAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0301u, 0x0389u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0313u, 0x1F28u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0314u, 0x1F29u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0345u, 0x1FCCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0300u, 0x1FDAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0301u, 0x038Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0304u, 0x1FD9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0306u, 0x1FD8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0308u, 0x03AAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0313u, 0x1F38u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0314u, 0x1F39u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0300u, 0x1FF8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0301u, 0x038Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0313u, 0x1F48u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0314u, 0x1F49u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1u, 0x0314u, 0x1FECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0300u, 0x1FEAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0301u, 0x038Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0304u, 0x1FE9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0306u, 0x1FE8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0308u, 0x03ABu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0314u, 0x1F59u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0300u, 0x1FFAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0301u, 0x038Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0313u, 0x1F68u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0314u, 0x1F69u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0345u, 0x1FFCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03ACu, 0x0345u, 0x1FB4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03AEu, 0x0345u, 0x1FC4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0300u, 0x1F70u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0301u, 0x03ACu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0304u, 0x1FB1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0306u, 0x1FB0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0313u, 0x1F00u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0314u, 0x1F01u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0342u, 0x1FB6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0345u, 0x1FB3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0300u, 0x1F72u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0301u, 0x03ADu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0313u, 0x1F10u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0314u, 0x1F11u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0300u, 0x1F74u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0301u, 0x03AEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0313u, 0x1F20u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0314u, 0x1F21u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0342u, 0x1FC6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0345u, 0x1FC3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0300u, 0x1F76u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0301u, 0x03AFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0304u, 0x1FD1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0306u, 0x1FD0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0308u, 0x03CAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0313u, 0x1F30u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0314u, 0x1F31u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0342u, 0x1FD6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0300u, 0x1F78u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0301u, 0x03CCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0313u, 0x1F40u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0314u, 0x1F41u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0313u, 0x1FE4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0314u, 0x1FE5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0300u, 0x1F7Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0301u, 0x03CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0304u, 0x1FE1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0306u, 0x1FE0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0308u, 0x03CBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0313u, 0x1F50u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0314u, 0x1F51u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0342u, 0x1FE6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0300u, 0x1F7Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0301u, 0x03CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0313u, 0x1F60u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0314u, 0x1F61u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0342u, 0x1FF6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0345u, 0x1FF3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0300u, 0x1FD2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0301u, 0x0390u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0342u, 0x1FD7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0300u, 0x1FE2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0301u, 0x03B0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0342u, 0x1FE7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CEu, 0x0345u, 0x1FF4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0301u, 0x03D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0308u, 0x03D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0406u, 0x0308u, 0x0407u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0306u, 0x04D0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0308u, 0x04D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0413u, 0x0301u, 0x0403u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0300u, 0x0400u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0306u, 0x04D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0308u, 0x0401u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0306u, 0x04C1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0308u, 0x04DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0417u, 0x0308u, 0x04DEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0300u, 0x040Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0304u, 0x04E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0306u, 0x0419u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0308u, 0x04E4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x041Au, 0x0301u, 0x040Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x041Eu, 0x0308u, 0x04E6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0304u, 0x04EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0306u, 0x040Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0308u, 0x04F0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x030Bu, 0x04F2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0427u, 0x0308u, 0x04F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x042Bu, 0x0308u, 0x04F8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x042Du, 0x0308u, 0x04ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0306u, 0x04D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0308u, 0x04D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0433u, 0x0301u, 0x0453u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0300u, 0x0450u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0306u, 0x04D7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0308u, 0x0451u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0306u, 0x04C2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0308u, 0x04DDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0437u, 0x0308u, 0x04DFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0300u, 0x045Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0304u, 0x04E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0306u, 0x0439u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0308u, 0x04E5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x043Au, 0x0301u, 0x045Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x043Eu, 0x0308u, 0x04E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0304u, 0x04EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0306u, 0x045Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0308u, 0x04F1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x030Bu, 0x04F3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0447u, 0x0308u, 0x04F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x044Bu, 0x0308u, 0x04F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x044Du, 0x0308u, 0x04EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0456u, 0x0308u, 0x0457u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0474u, 0x030Fu, 0x0476u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0475u, 0x030Fu, 0x0477u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8u, 0x0308u, 0x04DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9u, 0x0308u, 0x04DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8u, 0x0308u, 0x04EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu),
+};
+static const uint64_t
+_hb_ucd_dm2_u64_map[387] =
+{
+     HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BFu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D2u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D3u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D4u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05B9u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D6u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D8u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05B4u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DAu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BFu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05DCu, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DEu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E0u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E1u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E3u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BFu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E6u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E7u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E8u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C1u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C2u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05EAu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05F2u, 0x05B7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0627u, 0x0653u, 0x0622u),   HB_CODEPOINT_ENCODE3 (0x0627u, 0x0654u, 0x0623u),
+     HB_CODEPOINT_ENCODE3 (0x0627u, 0x0655u, 0x0625u),   HB_CODEPOINT_ENCODE3 (0x0648u, 0x0654u, 0x0624u),
+     HB_CODEPOINT_ENCODE3 (0x064Au, 0x0654u, 0x0626u),   HB_CODEPOINT_ENCODE3 (0x06C1u, 0x0654u, 0x06C2u),
+     HB_CODEPOINT_ENCODE3 (0x06D2u, 0x0654u, 0x06D3u),   HB_CODEPOINT_ENCODE3 (0x06D5u, 0x0654u, 0x06C0u),
+     HB_CODEPOINT_ENCODE3 (0x0915u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0916u, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0917u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x091Cu, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0921u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0922u, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0928u, 0x093Cu, 0x0929u),   HB_CODEPOINT_ENCODE3 (0x092Bu, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x092Fu, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0930u, 0x093Cu, 0x0931u),
+     HB_CODEPOINT_ENCODE3 (0x0933u, 0x093Cu, 0x0934u),   HB_CODEPOINT_ENCODE3 (0x09A1u, 0x09BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x09A2u, 0x09BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x09AFu, 0x09BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09BEu, 0x09CBu),   HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09D7u, 0x09CCu),
+     HB_CODEPOINT_ENCODE3 (0x0A16u, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A17u, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0A1Cu, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A2Bu, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0A32u, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A38u, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0B21u, 0x0B3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0B22u, 0x0B3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B3Eu, 0x0B4Bu),   HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B56u, 0x0B48u),
+     HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B57u, 0x0B4Cu),   HB_CODEPOINT_ENCODE3 (0x0B92u, 0x0BD7u, 0x0B94u),
+     HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BBEu, 0x0BCAu),   HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BD7u, 0x0BCCu),
+     HB_CODEPOINT_ENCODE3 (0x0BC7u, 0x0BBEu, 0x0BCBu),   HB_CODEPOINT_ENCODE3 (0x0C46u, 0x0C56u, 0x0C48u),
+     HB_CODEPOINT_ENCODE3 (0x0CBFu, 0x0CD5u, 0x0CC0u),   HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CC2u, 0x0CCAu),
+     HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD5u, 0x0CC7u),   HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD6u, 0x0CC8u),
+     HB_CODEPOINT_ENCODE3 (0x0CCAu, 0x0CD5u, 0x0CCBu),   HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D3Eu, 0x0D4Au),
+     HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D57u, 0x0D4Cu),   HB_CODEPOINT_ENCODE3 (0x0D47u, 0x0D3Eu, 0x0D4Bu),
+     HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCAu, 0x0DDAu),   HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCFu, 0x0DDCu),
+     HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DDFu, 0x0DDEu),   HB_CODEPOINT_ENCODE3 (0x0DDCu, 0x0DCAu, 0x0DDDu),
+     HB_CODEPOINT_ENCODE3 (0x0F40u, 0x0FB5u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F42u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F4Cu, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F51u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F56u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F5Bu, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F72u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F74u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F80u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F90u, 0x0FB5u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F92u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F9Cu, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FA1u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0FA6u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FABu, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0FB2u, 0x0F80u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FB3u, 0x0F80u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x1025u, 0x102Eu, 0x1026u),
+     HB_CODEPOINT_ENCODE3 (0x1B05u, 0x1B35u, 0x1B06u),   HB_CODEPOINT_ENCODE3 (0x1B07u, 0x1B35u, 0x1B08u),
+     HB_CODEPOINT_ENCODE3 (0x1B09u, 0x1B35u, 0x1B0Au),   HB_CODEPOINT_ENCODE3 (0x1B0Bu, 0x1B35u, 0x1B0Cu),
+     HB_CODEPOINT_ENCODE3 (0x1B0Du, 0x1B35u, 0x1B0Eu),   HB_CODEPOINT_ENCODE3 (0x1B11u, 0x1B35u, 0x1B12u),
+     HB_CODEPOINT_ENCODE3 (0x1B3Au, 0x1B35u, 0x1B3Bu),   HB_CODEPOINT_ENCODE3 (0x1B3Cu, 0x1B35u, 0x1B3Du),
+     HB_CODEPOINT_ENCODE3 (0x1B3Eu, 0x1B35u, 0x1B40u),   HB_CODEPOINT_ENCODE3 (0x1B3Fu, 0x1B35u, 0x1B41u),
+     HB_CODEPOINT_ENCODE3 (0x1B42u, 0x1B35u, 0x1B43u),   HB_CODEPOINT_ENCODE3 (0x1E36u, 0x0304u, 0x1E38u),
+     HB_CODEPOINT_ENCODE3 (0x1E37u, 0x0304u, 0x1E39u),   HB_CODEPOINT_ENCODE3 (0x1E5Au, 0x0304u, 0x1E5Cu),
+     HB_CODEPOINT_ENCODE3 (0x1E5Bu, 0x0304u, 0x1E5Du),   HB_CODEPOINT_ENCODE3 (0x1E62u, 0x0307u, 0x1E68u),
+     HB_CODEPOINT_ENCODE3 (0x1E63u, 0x0307u, 0x1E69u),   HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0302u, 0x1EACu),
+     HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0306u, 0x1EB6u),   HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0302u, 0x1EADu),
+     HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0306u, 0x1EB7u),   HB_CODEPOINT_ENCODE3 (0x1EB8u, 0x0302u, 0x1EC6u),
+     HB_CODEPOINT_ENCODE3 (0x1EB9u, 0x0302u, 0x1EC7u),   HB_CODEPOINT_ENCODE3 (0x1ECCu, 0x0302u, 0x1ED8u),
+     HB_CODEPOINT_ENCODE3 (0x1ECDu, 0x0302u, 0x1ED9u),   HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0300u, 0x1F02u),
+     HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0301u, 0x1F04u),   HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0342u, 0x1F06u),
+     HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0345u, 0x1F80u),   HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0300u, 0x1F03u),
+     HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0301u, 0x1F05u),   HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0342u, 0x1F07u),
+     HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0345u, 0x1F81u),   HB_CODEPOINT_ENCODE3 (0x1F02u, 0x0345u, 0x1F82u),
+     HB_CODEPOINT_ENCODE3 (0x1F03u, 0x0345u, 0x1F83u),   HB_CODEPOINT_ENCODE3 (0x1F04u, 0x0345u, 0x1F84u),
+     HB_CODEPOINT_ENCODE3 (0x1F05u, 0x0345u, 0x1F85u),   HB_CODEPOINT_ENCODE3 (0x1F06u, 0x0345u, 0x1F86u),
+     HB_CODEPOINT_ENCODE3 (0x1F07u, 0x0345u, 0x1F87u),   HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0300u, 0x1F0Au),
+     HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0301u, 0x1F0Cu),   HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0342u, 0x1F0Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0345u, 0x1F88u),   HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0300u, 0x1F0Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0301u, 0x1F0Du),   HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0342u, 0x1F0Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0345u, 0x1F89u),   HB_CODEPOINT_ENCODE3 (0x1F0Au, 0x0345u, 0x1F8Au),
+     HB_CODEPOINT_ENCODE3 (0x1F0Bu, 0x0345u, 0x1F8Bu),   HB_CODEPOINT_ENCODE3 (0x1F0Cu, 0x0345u, 0x1F8Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F0Du, 0x0345u, 0x1F8Du),   HB_CODEPOINT_ENCODE3 (0x1F0Eu, 0x0345u, 0x1F8Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F0Fu, 0x0345u, 0x1F8Fu),   HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0300u, 0x1F12u),
+     HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0301u, 0x1F14u),   HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0300u, 0x1F13u),
+     HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0301u, 0x1F15u),   HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0300u, 0x1F1Au),
+     HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0301u, 0x1F1Cu),   HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0300u, 0x1F1Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0301u, 0x1F1Du),   HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0300u, 0x1F22u),
+     HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0301u, 0x1F24u),   HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0342u, 0x1F26u),
+     HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0345u, 0x1F90u),   HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0300u, 0x1F23u),
+     HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0301u, 0x1F25u),   HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0342u, 0x1F27u),
+     HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0345u, 0x1F91u),   HB_CODEPOINT_ENCODE3 (0x1F22u, 0x0345u, 0x1F92u),
+     HB_CODEPOINT_ENCODE3 (0x1F23u, 0x0345u, 0x1F93u),   HB_CODEPOINT_ENCODE3 (0x1F24u, 0x0345u, 0x1F94u),
+     HB_CODEPOINT_ENCODE3 (0x1F25u, 0x0345u, 0x1F95u),   HB_CODEPOINT_ENCODE3 (0x1F26u, 0x0345u, 0x1F96u),
+     HB_CODEPOINT_ENCODE3 (0x1F27u, 0x0345u, 0x1F97u),   HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0300u, 0x1F2Au),
+     HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0301u, 0x1F2Cu),   HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0342u, 0x1F2Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0345u, 0x1F98u),   HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0300u, 0x1F2Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0301u, 0x1F2Du),   HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0342u, 0x1F2Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0345u, 0x1F99u),   HB_CODEPOINT_ENCODE3 (0x1F2Au, 0x0345u, 0x1F9Au),
+     HB_CODEPOINT_ENCODE3 (0x1F2Bu, 0x0345u, 0x1F9Bu),   HB_CODEPOINT_ENCODE3 (0x1F2Cu, 0x0345u, 0x1F9Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F2Du, 0x0345u, 0x1F9Du),   HB_CODEPOINT_ENCODE3 (0x1F2Eu, 0x0345u, 0x1F9Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F2Fu, 0x0345u, 0x1F9Fu),   HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0300u, 0x1F32u),
+     HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0301u, 0x1F34u),   HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0342u, 0x1F36u),
+     HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0300u, 0x1F33u),   HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0301u, 0x1F35u),
+     HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0342u, 0x1F37u),   HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0300u, 0x1F3Au),
+     HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0301u, 0x1F3Cu),   HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0342u, 0x1F3Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0300u, 0x1F3Bu),   HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0301u, 0x1F3Du),
+     HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0342u, 0x1F3Fu),   HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0300u, 0x1F42u),
+     HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0301u, 0x1F44u),   HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0300u, 0x1F43u),
+     HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0301u, 0x1F45u),   HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0300u, 0x1F4Au),
+     HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0301u, 0x1F4Cu),   HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0300u, 0x1F4Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0301u, 0x1F4Du),   HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0300u, 0x1F52u),
+     HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0301u, 0x1F54u),   HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0342u, 0x1F56u),
+     HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0300u, 0x1F53u),   HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0301u, 0x1F55u),
+     HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0342u, 0x1F57u),   HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0300u, 0x1F5Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0301u, 0x1F5Du),   HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0342u, 0x1F5Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0300u, 0x1F62u),   HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0301u, 0x1F64u),
+     HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0342u, 0x1F66u),   HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0345u, 0x1FA0u),
+     HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0300u, 0x1F63u),   HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0301u, 0x1F65u),
+     HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0342u, 0x1F67u),   HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0345u, 0x1FA1u),
+     HB_CODEPOINT_ENCODE3 (0x1F62u, 0x0345u, 0x1FA2u),   HB_CODEPOINT_ENCODE3 (0x1F63u, 0x0345u, 0x1FA3u),
+     HB_CODEPOINT_ENCODE3 (0x1F64u, 0x0345u, 0x1FA4u),   HB_CODEPOINT_ENCODE3 (0x1F65u, 0x0345u, 0x1FA5u),
+     HB_CODEPOINT_ENCODE3 (0x1F66u, 0x0345u, 0x1FA6u),   HB_CODEPOINT_ENCODE3 (0x1F67u, 0x0345u, 0x1FA7u),
+     HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0300u, 0x1F6Au),   HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0301u, 0x1F6Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0342u, 0x1F6Eu),   HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0345u, 0x1FA8u),
+     HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0300u, 0x1F6Bu),   HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0301u, 0x1F6Du),
+     HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0342u, 0x1F6Fu),   HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0345u, 0x1FA9u),
+     HB_CODEPOINT_ENCODE3 (0x1F6Au, 0x0345u, 0x1FAAu),   HB_CODEPOINT_ENCODE3 (0x1F6Bu, 0x0345u, 0x1FABu),
+     HB_CODEPOINT_ENCODE3 (0x1F6Cu, 0x0345u, 0x1FACu),   HB_CODEPOINT_ENCODE3 (0x1F6Du, 0x0345u, 0x1FADu),
+     HB_CODEPOINT_ENCODE3 (0x1F6Eu, 0x0345u, 0x1FAEu),   HB_CODEPOINT_ENCODE3 (0x1F6Fu, 0x0345u, 0x1FAFu),
+     HB_CODEPOINT_ENCODE3 (0x1F70u, 0x0345u, 0x1FB2u),   HB_CODEPOINT_ENCODE3 (0x1F74u, 0x0345u, 0x1FC2u),
+     HB_CODEPOINT_ENCODE3 (0x1F7Cu, 0x0345u, 0x1FF2u),   HB_CODEPOINT_ENCODE3 (0x1FB6u, 0x0345u, 0x1FB7u),
+     HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0300u, 0x1FCDu),   HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0301u, 0x1FCEu),
+     HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0342u, 0x1FCFu),   HB_CODEPOINT_ENCODE3 (0x1FC6u, 0x0345u, 0x1FC7u),
+     HB_CODEPOINT_ENCODE3 (0x1FF6u, 0x0345u, 0x1FF7u),   HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0300u, 0x1FDDu),
+     HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0301u, 0x1FDEu),   HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0342u, 0x1FDFu),
+     HB_CODEPOINT_ENCODE3 (0x2190u, 0x0338u, 0x219Au),   HB_CODEPOINT_ENCODE3 (0x2192u, 0x0338u, 0x219Bu),
+     HB_CODEPOINT_ENCODE3 (0x2194u, 0x0338u, 0x21AEu),   HB_CODEPOINT_ENCODE3 (0x21D0u, 0x0338u, 0x21CDu),
+     HB_CODEPOINT_ENCODE3 (0x21D2u, 0x0338u, 0x21CFu),   HB_CODEPOINT_ENCODE3 (0x21D4u, 0x0338u, 0x21CEu),
+     HB_CODEPOINT_ENCODE3 (0x2203u, 0x0338u, 0x2204u),   HB_CODEPOINT_ENCODE3 (0x2208u, 0x0338u, 0x2209u),
+     HB_CODEPOINT_ENCODE3 (0x220Bu, 0x0338u, 0x220Cu),   HB_CODEPOINT_ENCODE3 (0x2223u, 0x0338u, 0x2224u),
+     HB_CODEPOINT_ENCODE3 (0x2225u, 0x0338u, 0x2226u),   HB_CODEPOINT_ENCODE3 (0x223Cu, 0x0338u, 0x2241u),
+     HB_CODEPOINT_ENCODE3 (0x2243u, 0x0338u, 0x2244u),   HB_CODEPOINT_ENCODE3 (0x2245u, 0x0338u, 0x2247u),
+     HB_CODEPOINT_ENCODE3 (0x2248u, 0x0338u, 0x2249u),   HB_CODEPOINT_ENCODE3 (0x224Du, 0x0338u, 0x226Du),
+     HB_CODEPOINT_ENCODE3 (0x2261u, 0x0338u, 0x2262u),   HB_CODEPOINT_ENCODE3 (0x2264u, 0x0338u, 0x2270u),
+     HB_CODEPOINT_ENCODE3 (0x2265u, 0x0338u, 0x2271u),   HB_CODEPOINT_ENCODE3 (0x2272u, 0x0338u, 0x2274u),
+     HB_CODEPOINT_ENCODE3 (0x2273u, 0x0338u, 0x2275u),   HB_CODEPOINT_ENCODE3 (0x2276u, 0x0338u, 0x2278u),
+     HB_CODEPOINT_ENCODE3 (0x2277u, 0x0338u, 0x2279u),   HB_CODEPOINT_ENCODE3 (0x227Au, 0x0338u, 0x2280u),
+     HB_CODEPOINT_ENCODE3 (0x227Bu, 0x0338u, 0x2281u),   HB_CODEPOINT_ENCODE3 (0x227Cu, 0x0338u, 0x22E0u),
+     HB_CODEPOINT_ENCODE3 (0x227Du, 0x0338u, 0x22E1u),   HB_CODEPOINT_ENCODE3 (0x2282u, 0x0338u, 0x2284u),
+     HB_CODEPOINT_ENCODE3 (0x2283u, 0x0338u, 0x2285u),   HB_CODEPOINT_ENCODE3 (0x2286u, 0x0338u, 0x2288u),
+     HB_CODEPOINT_ENCODE3 (0x2287u, 0x0338u, 0x2289u),   HB_CODEPOINT_ENCODE3 (0x2291u, 0x0338u, 0x22E2u),
+     HB_CODEPOINT_ENCODE3 (0x2292u, 0x0338u, 0x22E3u),   HB_CODEPOINT_ENCODE3 (0x22A2u, 0x0338u, 0x22ACu),
+     HB_CODEPOINT_ENCODE3 (0x22A8u, 0x0338u, 0x22ADu),   HB_CODEPOINT_ENCODE3 (0x22A9u, 0x0338u, 0x22AEu),
+     HB_CODEPOINT_ENCODE3 (0x22ABu, 0x0338u, 0x22AFu),   HB_CODEPOINT_ENCODE3 (0x22B2u, 0x0338u, 0x22EAu),
+     HB_CODEPOINT_ENCODE3 (0x22B3u, 0x0338u, 0x22EBu),   HB_CODEPOINT_ENCODE3 (0x22B4u, 0x0338u, 0x22ECu),
+     HB_CODEPOINT_ENCODE3 (0x22B5u, 0x0338u, 0x22EDu),   HB_CODEPOINT_ENCODE3 (0x2ADDu, 0x0338u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x3046u, 0x3099u, 0x3094u),   HB_CODEPOINT_ENCODE3 (0x304Bu, 0x3099u, 0x304Cu),
+     HB_CODEPOINT_ENCODE3 (0x304Du, 0x3099u, 0x304Eu),   HB_CODEPOINT_ENCODE3 (0x304Fu, 0x3099u, 0x3050u),
+     HB_CODEPOINT_ENCODE3 (0x3051u, 0x3099u, 0x3052u),   HB_CODEPOINT_ENCODE3 (0x3053u, 0x3099u, 0x3054u),
+     HB_CODEPOINT_ENCODE3 (0x3055u, 0x3099u, 0x3056u),   HB_CODEPOINT_ENCODE3 (0x3057u, 0x3099u, 0x3058u),
+     HB_CODEPOINT_ENCODE3 (0x3059u, 0x3099u, 0x305Au),   HB_CODEPOINT_ENCODE3 (0x305Bu, 0x3099u, 0x305Cu),
+     HB_CODEPOINT_ENCODE3 (0x305Du, 0x3099u, 0x305Eu),   HB_CODEPOINT_ENCODE3 (0x305Fu, 0x3099u, 0x3060u),
+     HB_CODEPOINT_ENCODE3 (0x3061u, 0x3099u, 0x3062u),   HB_CODEPOINT_ENCODE3 (0x3064u, 0x3099u, 0x3065u),
+     HB_CODEPOINT_ENCODE3 (0x3066u, 0x3099u, 0x3067u),   HB_CODEPOINT_ENCODE3 (0x3068u, 0x3099u, 0x3069u),
+     HB_CODEPOINT_ENCODE3 (0x306Fu, 0x3099u, 0x3070u),   HB_CODEPOINT_ENCODE3 (0x306Fu, 0x309Au, 0x3071u),
+     HB_CODEPOINT_ENCODE3 (0x3072u, 0x3099u, 0x3073u),   HB_CODEPOINT_ENCODE3 (0x3072u, 0x309Au, 0x3074u),
+     HB_CODEPOINT_ENCODE3 (0x3075u, 0x3099u, 0x3076u),   HB_CODEPOINT_ENCODE3 (0x3075u, 0x309Au, 0x3077u),
+     HB_CODEPOINT_ENCODE3 (0x3078u, 0x3099u, 0x3079u),   HB_CODEPOINT_ENCODE3 (0x3078u, 0x309Au, 0x307Au),
+     HB_CODEPOINT_ENCODE3 (0x307Bu, 0x3099u, 0x307Cu),   HB_CODEPOINT_ENCODE3 (0x307Bu, 0x309Au, 0x307Du),
+     HB_CODEPOINT_ENCODE3 (0x309Du, 0x3099u, 0x309Eu),   HB_CODEPOINT_ENCODE3 (0x30A6u, 0x3099u, 0x30F4u),
+     HB_CODEPOINT_ENCODE3 (0x30ABu, 0x3099u, 0x30ACu),   HB_CODEPOINT_ENCODE3 (0x30ADu, 0x3099u, 0x30AEu),
+     HB_CODEPOINT_ENCODE3 (0x30AFu, 0x3099u, 0x30B0u),   HB_CODEPOINT_ENCODE3 (0x30B1u, 0x3099u, 0x30B2u),
+     HB_CODEPOINT_ENCODE3 (0x30B3u, 0x3099u, 0x30B4u),   HB_CODEPOINT_ENCODE3 (0x30B5u, 0x3099u, 0x30B6u),
+     HB_CODEPOINT_ENCODE3 (0x30B7u, 0x3099u, 0x30B8u),   HB_CODEPOINT_ENCODE3 (0x30B9u, 0x3099u, 0x30BAu),
+     HB_CODEPOINT_ENCODE3 (0x30BBu, 0x3099u, 0x30BCu),   HB_CODEPOINT_ENCODE3 (0x30BDu, 0x3099u, 0x30BEu),
+     HB_CODEPOINT_ENCODE3 (0x30BFu, 0x3099u, 0x30C0u),   HB_CODEPOINT_ENCODE3 (0x30C1u, 0x3099u, 0x30C2u),
+     HB_CODEPOINT_ENCODE3 (0x30C4u, 0x3099u, 0x30C5u),   HB_CODEPOINT_ENCODE3 (0x30C6u, 0x3099u, 0x30C7u),
+     HB_CODEPOINT_ENCODE3 (0x30C8u, 0x3099u, 0x30C9u),   HB_CODEPOINT_ENCODE3 (0x30CFu, 0x3099u, 0x30D0u),
+     HB_CODEPOINT_ENCODE3 (0x30CFu, 0x309Au, 0x30D1u),   HB_CODEPOINT_ENCODE3 (0x30D2u, 0x3099u, 0x30D3u),
+     HB_CODEPOINT_ENCODE3 (0x30D2u, 0x309Au, 0x30D4u),   HB_CODEPOINT_ENCODE3 (0x30D5u, 0x3099u, 0x30D6u),
+     HB_CODEPOINT_ENCODE3 (0x30D5u, 0x309Au, 0x30D7u),   HB_CODEPOINT_ENCODE3 (0x30D8u, 0x3099u, 0x30D9u),
+     HB_CODEPOINT_ENCODE3 (0x30D8u, 0x309Au, 0x30DAu),   HB_CODEPOINT_ENCODE3 (0x30DBu, 0x3099u, 0x30DCu),
+     HB_CODEPOINT_ENCODE3 (0x30DBu, 0x309Au, 0x30DDu),   HB_CODEPOINT_ENCODE3 (0x30EFu, 0x3099u, 0x30F7u),
+     HB_CODEPOINT_ENCODE3 (0x30F0u, 0x3099u, 0x30F8u),   HB_CODEPOINT_ENCODE3 (0x30F1u, 0x3099u, 0x30F9u),
+     HB_CODEPOINT_ENCODE3 (0x30F2u, 0x3099u, 0x30FAu),   HB_CODEPOINT_ENCODE3 (0x30FDu, 0x3099u, 0x30FEu),
+     HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C1u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C2u, 0x0000u),
+  HB_CODEPOINT_ENCODE3 (0x11099u, 0x110BAu, 0x1109Au),HB_CODEPOINT_ENCODE3 (0x1109Bu, 0x110BAu, 0x1109Cu),
+  HB_CODEPOINT_ENCODE3 (0x110A5u, 0x110BAu, 0x110ABu),HB_CODEPOINT_ENCODE3 (0x11131u, 0x11127u, 0x1112Eu),
+  HB_CODEPOINT_ENCODE3 (0x11132u, 0x11127u, 0x1112Fu),HB_CODEPOINT_ENCODE3 (0x11347u, 0x1133Eu, 0x1134Bu),
+  HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu),
+  HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu),
+  HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu),HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu),
+   HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u),
+};
+
+#ifndef HB_OPTIMIZE_SIZE
+
+static const uint8_t
+_hb_ucd_u8[32102] =
+{
+    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, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 28,
+   29, 26, 30, 31, 32, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 34, 35, 35, 35, 35,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 38, 39, 40,
+   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+   26, 57, 58, 59, 59, 59, 59, 59, 26, 26, 60, 59, 59, 59, 59, 59,
+   59, 59, 26, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 26, 62, 59, 63, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 64, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 66, 67, 59, 59, 59, 59, 68, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 69, 70, 71, 72, 73, 74, 59, 59,
+   75, 76, 59, 59, 77, 59, 78, 79, 80, 81, 73, 82, 83, 84, 59, 59,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 85, 26, 26, 26, 26, 26, 26, 26, 86, 87, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 88, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 89, 59, 59, 59, 59, 59, 59, 26, 90, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   91, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21,
+   21,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22, 21, 18, 24, 16,
+   24,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   29, 21, 23, 23, 23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24,
+   26, 25, 15, 15, 24,  5, 21, 21, 24, 15,  7, 19, 15, 15, 15, 21,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9, 25,  9,  9,  9,  9,  9,  9,  9,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,
+    5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  9,  5,  5,
+    5,  9,  9,  5,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  9,  9,
+    9,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  5,  9,  9,  5,  9,
+    9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  5,  9,  5,  9,  9,
+    5,  9,  9,  9,  5,  9,  5,  9,  9,  5,  5,  7,  9,  5,  5,  5,
+    7,  7,  7,  7,  9,  8,  5,  9,  8,  5,  9,  8,  5,  9,  5,  9,
+    5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,
+    5,  9,  8,  5,  9,  5,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  9,  9,  5,  9,  9,  5,
+    5,  9,  5,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  5,  5,  7,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+    6,  6,  6,  6,  6, 24, 24, 24, 24, 24, 24, 24,  6, 24,  6, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    9,  5,  9,  5,  6, 24,  9,  5,  2,  2,  6,  5,  5,  5, 21,  9,
+    2,  2,  2,  2, 24, 24,  9, 21,  9,  9,  9,  2,  9,  2,  9,  9,
+    5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,
+    5,  5,  9,  9,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  5,  5,  9,  5, 25,  9,  5,  9,  9,  5,  5,  9,  9,  9,
+    9,  5, 26, 12, 12, 12, 12, 12, 11, 11,  9,  5,  9,  5,  9,  5,
+    9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,
+    2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  2,  2,  6, 21, 21, 21, 21, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5, 21, 17,  2,  2, 26, 26, 23,
+    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12,
+   21, 12, 12, 21, 12, 12, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
+    7,  7,  7, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  1,  2, 21, 21,
+    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21,  7,  7,
+   12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 21,  7, 12, 12, 12, 12, 12, 12, 12,  1, 26, 12,
+   12, 12, 12, 12, 12,  6,  6, 12, 12, 26, 12, 12, 12, 12,  7,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7, 26, 26,  7,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  1,
+    7, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
+   12, 12, 12, 12,  6,  6, 26, 21, 21, 21,  6,  2,  2, 12, 23, 23,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12,  6, 12, 12, 12, 12, 12,
+   12, 12, 12, 12,  6, 12, 12, 12,  6, 12, 12, 12, 12, 12,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12,  2,  2, 21,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,
+    2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12,  1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12,  7, 10, 10,
+   10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10,
+    7, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   21,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  2,  7,  2,  2,  2,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
+   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  7,  2,
+    2,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  7,  7,  2,  7,
+    7,  7, 12, 12,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    7,  7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23,  7, 21, 12,  2,
+    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  2,  7,  7,  2,  2, 12,  2, 10, 10,
+   10, 12, 12,  2,  2,  2,  2, 12, 12,  2,  2, 12, 12, 12,  2,  2,
+    2, 12,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  2,  7,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   12, 12,  7,  7,  7, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
+    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
+   10, 12, 12, 12, 12, 12,  2, 12, 12, 10,  2, 10, 10, 12,  2,  2,
+    7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 23,  2,  2,  2,  2,  2,  2,  2,  7, 12, 12, 12, 12, 12, 12,
+    2, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
+   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  2,  2,
+    2,  2,  2,  2,  2,  2, 12, 10,  2,  2,  2,  2,  7,  7,  2,  7,
+   26,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2, 12,  7,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,
+    7,  2,  7,  7,  7,  7,  2,  2,  2,  7,  7,  2,  7,  2,  7,  7,
+    2,  2,  2,  7,  7,  2,  2,  2,  7,  7,  7,  2,  2,  2,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 10, 10,
+   12, 10, 10,  2,  2,  2, 10, 10, 10,  2, 10, 10, 10, 12,  2,  2,
+    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26,  2,  2,  2,  2,  2,
+   12, 10, 10, 10, 12,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7, 12, 12,
+   12, 10, 10, 10, 10,  2, 12, 12, 12,  2, 12, 12, 12, 12,  2,  2,
+    2,  2,  2,  2,  2, 12, 12,  2,  7,  7,  7,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 21, 15, 15, 15, 15, 15, 15, 15, 26,
+    7, 12, 10, 10, 21,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
+   10, 10, 10, 10, 10,  2, 12, 10, 10,  2, 10, 10, 12, 12,  2,  2,
+    2,  2,  2,  2,  2, 10, 10,  2,  2,  2,  2,  2,  2,  2,  7,  2,
+    2,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12,  7, 10, 10,
+   10, 12, 12, 12, 12,  2, 10, 10, 10,  2, 10, 10, 10, 12,  7, 26,
+    2,  2,  2,  2,  7,  7,  7, 10, 15, 15, 15, 15, 15, 15, 15,  7,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 26,  7,  7,  7,  7,  7,  7,
+    2,  2, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 12,  2,  2,  2,  2, 10,
+   10, 10, 12, 12, 12,  2, 12,  2, 10, 10, 10, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2, 23,
+    7,  7,  7,  7,  7,  7,  6, 12, 12, 12, 12, 12, 12, 12, 12, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21,  2,  2,  2,  2,
+    2,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,
+    7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  2,  2,
+    7,  7,  7,  7,  7,  2,  6,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  7,  7,  7,  7,
+    7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,
+    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
+   12, 12, 12, 12, 12, 21, 12, 12,  7,  7,  7,  7,  7, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 26, 26,
+   26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26,  2, 26, 26,
+   21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 12, 12, 12,
+   12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21,
+    7,  7,  7,  7,  7,  7, 10, 10, 12, 12,  7,  7,  7,  7, 12, 12,
+   12,  7, 10, 10, 10,  7,  7, 10, 10, 10, 10, 10, 10, 10,  7,  7,
+    7, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12,  7, 10,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26,
+    9,  9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  2,  2,  9,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 21,  6,  5,  5,  5,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  2,
+    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  2,
+    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  2,  2,  5,  5,  5,  5,  5,  5,  2,  2,
+   17,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 26, 21,  7,
+   29,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 22, 18,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21, 21, 21, 14, 14,
+   14,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7, 12, 12, 12, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  2, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10,
+   10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 21, 21, 21,  6, 21, 21, 21, 23,  7, 12,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12,  1,  2,
+    7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12,  7,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,
+   12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10,  2,  2,  2,  2,
+   10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12,  2,  2,  2,  2,
+   26,  2,  2,  2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,
+    7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15,  2,  2,  2, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 10, 10, 12,  2,  2, 21, 21,
+    7,  7,  7,  7,  7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12,  2,
+   12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12,
+   21, 21, 21, 21, 21, 21, 21,  6, 21, 21, 21, 21, 21, 21,  2,  2,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11,  2,
+   12, 12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10,
+   10, 10, 12, 10, 10,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,
+   21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
+   12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12,  7,  7,
+    7,  7,  7,  7,  7,  7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12,
+   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,
+    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
+   12, 12, 12, 12, 10, 10, 12, 12,  2,  2,  2, 21, 21, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,
+   21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 10, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7, 12,  7,  7,
+    7,  7,  7,  7, 12,  7,  7, 10, 12, 12,  7,  2,  2,  2,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  6,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12,
+    9,  5,  9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,
+    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  2,  9,  2,  9,  2,  9,  2,  9,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  8,  8,  8,  8,  8,  8,  8,  8,
+    5,  5,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24,  5, 24,
+   24, 24,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24, 24,
+    5,  5,  5,  5,  2,  2,  5,  5,  9,  9,  9,  9,  2, 24, 24, 24,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9, 24, 24, 24,
+    2,  2,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24,  2,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  1,  1,  1,  1,  1,
+   17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20,
+   21, 21, 21, 21, 21, 21, 21, 21, 27, 28,  1,  1,  1,  1,  1, 29,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16,
+   16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29,
+    1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+   15,  6,  2,  2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  6,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  2,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+   11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26,  9, 26, 26, 26, 26,  9, 26, 26,  5,  9,  9,  9,  5,  5,
+    9,  9,  9,  5, 26,  9, 26, 26, 25,  9,  9,  9,  9,  9, 26, 26,
+   26, 26, 26, 26,  9, 26,  9, 26,  9, 26,  9,  9,  9,  9, 26,  5,
+    9,  9,  9,  9,  5,  7,  7,  7,  7,  5, 26, 26,  5,  5,  9,  9,
+   25, 25, 25, 25, 25,  9,  5,  5,  5,  5, 26, 25, 26, 26,  5, 26,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14,  9,  5, 14, 14, 14, 14, 15, 26, 26,  2,  2,  2,  2,
+   25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26,
+   25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25,
+   26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26,
+   25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25,
+   25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15,
+   26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18,
+   22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18,
+   25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
+   18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25,
+   25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26,
+   26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    9,  5,  9,  9,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,
+    9,  5,  9,  5,  5,  9,  5,  5,  5,  5,  5,  5,  6,  6,  9,  9,
+    9,  5,  9,  5,  5, 26, 26, 26, 26, 26, 26,  9,  5,  9,  5, 12,
+   12, 12,  9,  5,  2,  2,  2,  2,  2, 21, 21, 21, 21, 15, 21, 21,
+    5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  2,  2,  5,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  6,
+   21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  2,
+   21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21,
+   20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21,  6,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21,
+   17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26,
+   26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,
+   29, 21, 21, 21, 26,  6,  7, 14, 22, 18, 22, 18, 22, 18, 22, 18,
+   22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18,
+   26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10,
+   17,  6,  6,  6,  6,  6, 26, 26, 14, 14, 14,  6,  7, 21, 26, 26,
+    7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 24, 24,  6,  6,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  6,  6,  6,  7,
+    2,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15,
+   26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  2,  2,  2,  2,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  7, 12,
+   11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  6,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  6,  6, 12, 12,
+    7,  7,  7,  7,  7,  7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   12, 12, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   24, 24, 24, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+   24, 24,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    6,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,  9,  5,  9,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  6, 24, 24,  9,  5,  9,  5,  7,
+    9,  5,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,  9,  9,  5,
+    9,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    2,  2,  9,  5,  9,  9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  7,  6,  6,  5,  7,  7,  7,  7,  7,
+    7,  7, 12,  7,  7,  7, 12,  7,  7,  7,  7, 12,  7,  7,  7,  7,
+    7,  7,  7, 10, 10, 12, 12, 10, 26, 26, 26, 26,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 26, 26, 23, 26,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21,
+   12, 12,  7,  7,  7,  7,  7,  7, 21, 21, 21,  7, 21,  7,  7, 12,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+    7,  7,  7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10,
+   10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  6,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 21, 21,
+    7,  7,  7,  7,  7, 12,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 10,
+   10, 12, 12, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2, 21, 21, 21, 21,
+    6,  7,  7,  7,  7,  7,  7, 26, 26, 26,  7, 10, 12, 10,  7,  7,
+   12,  7, 12, 12, 12,  7,  7, 12, 12,  7,  7,  7,  7,  7, 12, 12,
+    7, 12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  6, 21, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 12, 12, 10, 10,
+   21, 21,  7,  6,  6, 10, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  2,
+    2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 24,  6,  6,  6,  6,
+    5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12,  2,  2,
+    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  7, 12,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 25,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  2,
+    7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 18, 22,
+    2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 23, 26,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 22, 18, 21,  2,  2,  2,  2,  2,  2,
+   21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
+   18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16,
+   21, 21, 21,  2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21,
+   21, 21, 25, 17, 25, 25, 25,  2, 21, 23, 21, 21,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  1,
+    2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 25, 18, 25, 22,
+   18, 21, 22, 18, 21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6,  6,
+    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
+    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  2,  2,  2,
+   23, 23, 25, 24, 26, 23, 23,  2, 26, 25, 25, 25, 25, 26, 26,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1, 26, 26,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,
+   21, 21, 21,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26,  2,
+   26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12,  2,  2,
+   12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,
+   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,
+    7, 14,  7,  7,  7,  7,  7,  7,  7,  7, 14,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2, 21,
+    7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+   21, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  9,  9,  9,  2,  2,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,
+    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  2,  2,  7,  2,  2,  7,
+    7,  7,  7,  7,  7,  7,  2, 21, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  7,  7, 26, 26, 15, 15, 15, 15, 15, 15, 15,
+    2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  2,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 15, 15,  7,  7,
+    2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7, 12, 12, 12,  2, 12, 12,  2,  2,  2,  2,  2, 12, 12, 12, 12,
+    7,  7,  7,  7,  2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,  2,  2,  2,  2, 12,
+   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 15,
+    7,  7,  7,  7,  7,  7,  7,  7, 26,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7, 12, 12,  2,  2,  2,  2, 15, 15, 15, 15, 15,
+   21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  2,  2, 21, 21, 21, 21, 21, 21, 21,
+    7,  7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15,
+    9,  9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,
+   15, 15, 15, 15, 15, 15, 15,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 15, 15, 15, 15, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,
+   10, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21,  2,  2,
+   15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
+   10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21,  1, 21, 21,
+   21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  2,  2,
+   12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 10, 12, 12, 12,
+   12, 12, 12, 12, 12,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   21, 21, 21, 21,  7, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
+   10,  7,  7,  7,  7, 21, 21, 21, 21, 12, 12, 12, 12, 21,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7, 21,  7, 21, 21, 21,
+    2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 12,
+   12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+   12, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2, 12, 12,  7, 10, 10,
+   12, 10, 10, 10, 10,  2,  2, 10, 10,  2,  2, 10, 10, 10,  2,  2,
+    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  7,  7,  7,
+    7,  7, 10, 10,  2,  2, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,
+   12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
+   10, 10, 12, 12, 12, 10, 12,  7,  7,  7,  7, 21, 21, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2, 21,  2, 21, 12,  7,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12,
+   12, 10, 12, 12,  7,  7, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
+   10, 10, 12, 12, 12, 12,  2,  2, 10, 10, 10, 10, 12, 12, 10, 12,
+   12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21,  7,  7,  7,  7, 12, 12,  2,  2,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12,
+   12, 21, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12, 10, 10,
+   12, 12, 12, 12, 12, 12, 10, 12,  7,  2,  2,  2,  2,  2,  2,  2,
+   10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26,
+   12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21,  2,  2,  2,  2,
+   15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
+    7, 10, 10, 10, 12, 12, 12, 12,  2,  2, 12, 12, 10, 10, 10, 10,
+   12,  7, 21,  7, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,
+    7,  7,  7, 12, 12, 12, 12, 12, 12, 10,  7, 12, 12, 12, 12, 21,
+   21, 21, 21, 21, 21, 21, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21,  7, 21, 21,
+   21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 10, 12,
+    7, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12,  2, 10, 12, 12, 12, 12, 12, 12,
+   12, 10, 12, 12, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,
+    7, 12, 12, 12, 12, 12, 12,  2,  2,  2, 12,  2, 12, 12,  2, 12,
+   12, 12, 12, 12, 12, 12,  7, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 10, 10,  2,
+   12, 12,  2, 10, 10, 12, 10, 12,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12, 12, 10, 10, 21, 21,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23,
+   23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,
+   21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26,
+    6,  6,  6,  6, 21, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2, 15, 15, 15, 15, 15,
+   15, 15,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  7,  7,  7,
+   15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 12,
+    7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 12,
+   12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 21,  6,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 26, 12, 12, 21,
+    1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10,
+   10, 10, 10,  1,  1,  1,  1,  1,  1,  1,  1, 12, 12, 12, 12, 12,
+   12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 12, 12, 12, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,
+    5,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  2,  9,  9,
+    2,  2,  9,  2,  2,  9,  9,  2,  2,  9,  9,  9,  9,  2,  9,  9,
+    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  2,  5,  2,  5,  5,  5,
+    5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,  2,  9,  9,  9,
+    9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  2,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,
+    9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  9,  9,  9,  9,  9,  9,
+    9,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  9,  9,
+    9, 25,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,
+    5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,
+    5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,
+    9,  9,  9,  9,  9, 25,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 25,
+    5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,
+    5,  5,  5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,
+    9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,  5,  5,
+    5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  5,  2,  2, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26,
+   26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12,
+   12, 12,  2, 12, 12,  2, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  7, 26,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2, 23,
+    7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  5, 12, 12, 12, 12, 12, 12, 12,  6,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15,
+   23, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,
+    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,  7,  2,  2,  2,  2,
+    2,  2,  7,  2,  2,  2,  2,  7,  2,  7,  2,  7,  2,  7,  7,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  2,  7,  2,  7,  2,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,
+    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
+    2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
+   25, 25,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24,
+   26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26,
+   26, 26,  2, 26, 26, 26, 26,  2,  2,  2, 26, 26, 26, 26, 26, 26,
+   26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26,  2,  2,  2, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26,
+   26, 26, 26, 26,  2,  2,  2,  2, 26, 26, 26,  2,  2,  2,  2,  2,
+    7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,
+    0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,
+   14,  0,  0, 15,  0,  0,  0, 16, 17, 18, 19, 20, 21, 22,  0,  0,
+   23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 24, 25,  0,  0,
+   26,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 27,  0, 28, 29, 30, 31,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 32,  0,  0, 33,  0,
+    0, 34, 35, 36,  0,  0,  0,  0,  0,  0, 37,  0,  0, 38,  0, 39,
+   40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,  0, 51, 52,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53, 54,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 56, 57,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   58, 54, 59,  0,  0,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,
+    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  9, 10, 11, 12,  0,  0,  0,  0, 13,  0,  0, 14, 15,
+    0, 16,  0,  0,  0,  0,  0, 17, 18,  0,  0, 19,  0, 20, 21,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,
+    0,  0,  0,  0,  0,  0,  0, 27, 28, 29,  0,  0,  0, 30, 31, 32,
+    0,  0,  0,  0,  0, 30, 31,  0,  0, 33,  0,  0,  0, 30, 31,  0,
+    0,  0,  0,  0,  0, 30, 31,  0,  0,  0,  0,  0,  0, 30, 31,  0,
+    0,  0,  0,  0,  0,  0, 31,  0,  0,  0,  0,  0,  0,  0, 31, 34,
+    0,  0,  0,  0,  0, 30, 31,  0,  0,  0,  0,  0,  0, 35, 31,  0,
+    0,  0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0, 37, 38,  0,
+    0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0, 41,  0, 42,  0,  0,
+    0, 43, 44,  0,  0,  0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0,
+    0,  0, 47,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,  0, 49,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 50,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 51,  0,  0,  0,  0,  0,  0,  0,  0, 52,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0,  0,  0,  0,
+   54, 55,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0, 57, 49,  0,
+   58, 59,  0,  0, 60,  0,  0,  0, 61, 62,  0,  0,  0, 63,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 64, 65, 66,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 67, 68,  1, 69,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 70, 71, 72,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 73, 74,  0,  0,  0,  0,  0,  0,
+    0, 75,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0, 76,  0,  0,  0,
+    0,  0,  0, 77,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   73, 78,  0, 79,  0,  0,  0,  0,  0, 74, 80,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 49,  0,  1, 74,  0,  0, 81,  0,  0, 82,
+    0,  0,  0,  0,  0, 83, 54,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 84, 85,  0,  0, 80,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 31,  0,  0, 86,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 87,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 47,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 88,  0,  0,  0,  0,  0,  0,  0,
+    0, 89,  0,  0,  0,  0,  0,  0,  0,  0, 90,  0,  0, 91,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 92,  0,  0,  0, 93,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 94, 88,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 80,  0,
+    0, 75,  0,  0,  0, 95,  0,  0,  0,  0, 96,  0,  0, 97,  0,  0,
+    0, 83,  0,  0,  0,  0, 98,  0,  0,  0,  0,  0,  0, 99,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,100,  0,  0,  0,  0,101, 31,  0,
+  102,103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,104, 33,
+    0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 75,106,  0,  0,  0,  0,  0,  0, 75,  0,  0,
+    0,  0,  0,  0,  0,107,  0,  0,  0,  0,  0,  0,108,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 95,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 54,  0,  0,  0,  0, 49,109,  0,
+    0,  0,  0,110,  0,  0,  0,  0,  0,  0,  0,  0,  0, 75,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,111,  0,
+    0,  0,  0,109,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,112,  0,  0,  0,113,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,114,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  115,116,117,  0,118,  0,  0,  0,  0,  0,  0,  0,  0,  0,119,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,120,121,122,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,123,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,124,  0,  0,  0,  0,  0,  0,125,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
+  230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,232,
+  220,220,220,220,232,216,220,220,220,220,220,202,202,220,220,220,
+  220,202,202,220,220,220,220,220,220,220,220,220,220,220,  1,  1,
+    1,  1,  1,220,220,220,220,230,230,230,230,230,230,230,230,240,
+  230,220,220,220,230,230,230,220,220,  0,230,230,230,220,220,220,
+  220,230,232,220,220,230,233,234,234,233,234,234,233,230,230,230,
+  230,230,230,230,230,230,230,230,230,230,  0,  0,  0,230,230,230,
+  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,220,230,230,230,230,
+  220,230,230,230,222,220,230,230,230,230,230,230,220,220,220,220,
+  220,220,230,230,220,230,230,222,228,230, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 19, 20, 21, 22,  0, 23,  0, 24, 25,  0,230,220,
+    0, 18,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
+  230,230, 30, 31, 32,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,
+  220,230,230,230,230,230,220,230,230,220, 35,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  230,230,230,230,230,230,230,  0,  0,230,230,230,230,220,230,  0,
+    0,230,230,  0,220,230,230,220,  0,  0,  0, 36,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,220,230,230,220,230,
+  230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230,
+  220,230,220,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,230,230,230,230,230,230,230,220,230,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,
+  230,230,230,230,  0,230,230,230,230,230,230,230,230,230,  0,230,
+  230,230,  0,230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,220,220,220,  0,  0,  0,  0,  0,  0,  0,220,230,230,
+  230,230,230,230,230,230,230,230,230,230,230,230,  0,220,230,230,
+  220,230,230,220,230,230,230,220,220,220, 27, 28, 29,230,230,230,
+  220,230,230,220,220,230,230,230,230,230,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,230,220,230,230,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,  0,  0,  0, 84,
+   91,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,103,103,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,107,107,107,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,118,118,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,122,122,122,122,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,220,220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,220,
+    0,220,  0,216,  0,  0,  0,  0,  0,  0,  0,129,130,  0,132,  0,
+    0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,230,230,  9,  0,
+  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  7,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,  0,  9,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,228,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,222,230,220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,230,220,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,
+  230,230,230,230,230,230,230,  0,  0,220,230,230,230,230,230,220,
+  220,220,220,220,220,230,230,220,  0,  0,  0,  0,  0,  0,  7,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,230,220,230,230,230,230,230,230,230,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  7,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  1,220,
+  220,220,220,220,230,230,220,220,220,220,230,  0,  1,  1,  1,  1,
+    1,  1,  1,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,230,  0,
+    0,  0,230,230,  0,  0,  0,  0,  0,  0,230,230,220,230,230,230,
+  230,230,230,230,220,230,230,234,214,220,202,230,230,230,230,230,
+  230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,
+  232,228,228,220,  0,230,233,220,230,220,230,230,  1,  1,230,230,
+  230,230,  1,  1,  1,230,230,  0,  0,  0,  0,230,  0,  0,  0,  1,
+    1,230,220,230,  1,  1,220,220,220,220,230,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,218,228,232,222,224,224,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,
+  230,230,230,230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,230,230,  0,  0,  0,  0,  0,  0,
+    9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,220,220,220,  0,  0,  0,  0,  0,  9,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,  0,230,230,220,  0,
+    0,230,230,  0,  0,  0,  0,  0,230,230,  0,230,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 26,  0,230,230,230,230,230,230,
+  230,220,220,220,220,220,220,220,230,230,220,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,220,  0,230,  0,  0,  0,  0,  0,  0,
+    0,  0,230,  1,220,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,230,
+  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,
+  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  220,220,230,230,230,220,230,220,220,220,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  9,  7,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,
+    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  7,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  7,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  230,230,230,230,230,230,230,  0,  0,  0,230,230,230,230,230,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
+    7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  7,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    9,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  9,  9,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
+  230,  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,216,
+  216,  1,  1,  1,  0,  0,  0,226,216,216,216,216,216,  0,  0,  0,
+    0,  0,  0,  0,  0,220,220,220,220,220,220,220,220,  0,  0,230,
+  230,230,230,230,220,220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,230,230,230,230,  0,  0,  0,  0,230,230,230,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
+  230,  0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,
+  230,230,230,  0,  0,230,230,230,230,230,230,230,  0,230,230,  0,
+  230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,230,230,230,230,220,220,220,220,220,220,
+  220,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,
+  230,230,230,230,  7,  0,  0,  0,  0,  0, 16, 17, 17, 17, 17, 17,
+   17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169,
+   17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17,237,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+    3,  4,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  5,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  7,  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,
+    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, 10,  0,  0, 10,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0, 10,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 12,  0, 13,
+    0, 14, 15, 16,  0,  0,  0,  0,  0,  1, 17, 18,  0, 19,  7,  1,
+    0,  0,  0, 20, 20,  7, 20, 20, 20, 20, 20, 20, 20,  8, 21,  0,
+   22,  0,  7, 23, 24,  0, 20, 20, 25,  0,  0,  0, 26, 27,  1,  7,
+   20, 20, 20, 20, 20,  1, 28, 29, 30, 31,  0,  0, 20,  0,  0,  0,
+    0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 20, 20, 20,  1,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 21, 32,  4,  0, 10,
+    0, 33,  7, 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 34, 34, 35, 36, 34,
+   37,  0, 38,  1, 20, 20,  0,  0, 39,  0,  1,  1,  0,  8, 21,  1,
+   20,  0,  0,  0,  1,  0,  0, 40,  1,  1,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  8, 21,  0,  1,  0,  1,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  1,  0,  0,  0,  0, 26, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 21,  7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,
+    0, 42, 43, 44,  0, 45,  0,  8, 21,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 46,  7,  1, 10,  1,  0,  0,
+    0,  1, 20, 20,  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, 20, 20,  1, 20,
+   20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   26, 21,  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,  1,  0,  0,  0,
+    0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,  0,  0,
+    3, 47, 48,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+    3,  4,  0,  0,  0,  0,  0,  0,  3,  4,  0,  1,  2,  3,  4,  5,
+    6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 17, 19, 20,
+   21, 22, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 27, 28, 28, 29, 30, 31, 32,
+   33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+   33, 33, 33, 33, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+   46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 35, 35, 35,
+   35, 35, 59, 59, 60, 35, 35, 35, 35, 35, 35, 35, 61, 62, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 63, 64,
+   35, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 66, 68,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 69, 70, 35, 35, 35, 35, 71, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 72, 73, 74, 75, 76, 77, 35, 35, 78, 79, 35, 35, 80, 35,
+   81, 82, 83, 84, 17, 85, 86, 87, 35, 35, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 88, 25, 25,
+   25, 25, 25, 25, 25, 89, 90, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92,
+   35, 35, 35, 35, 35, 35, 25, 93, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 94,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19,
+   19,  0,  0,  0,  0,  0, 26, 26,  0,  0,  0,  0,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  9,  9,  9,  9,
+    0,  9,  9,  9,  2,  2,  9,  9,  9,  9,  0,  9,  2,  2,  2,  2,
+    9,  0,  9,  0,  9,  9,  9,  2,  9,  2,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 55, 55,
+   55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,  6,  6,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  1,  1,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,  4,  4,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  2,  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  0,  4,  2,  2,  4,  4,  4,  2, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14,  2,  2,  2,  2,  2,  2,  2,  2, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14,  2,  2,  2,  2, 14, 14, 14, 14, 14,
+   14,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  0,  3,  2,  3,  0,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1,  1,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  1,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  3,  3, 37, 37, 37, 37,
+   37, 37, 37, 37, 37, 37, 37, 37, 37, 37,  2, 37, 37, 37, 37, 37,
+   37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37, 37, 37, 37, 37, 37, 37,  2,  2, 37, 37, 37, 38, 38, 38, 38,
+   38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 64, 64, 64, 64,
+   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+   64, 64, 64, 64, 64, 64, 64,  2,  2, 64, 64, 64, 90, 90, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90,  2,  2, 90, 90, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,  2, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95,  2,  2, 95,  2, 37, 37, 37, 37,
+   37, 37, 37, 37, 37, 37, 37,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  1,  1,  1,
+    1,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    0,  0,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  5,  5,  5,  5,
+    2,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,  2,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  2,  5,  2,
+    2,  2,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  2,  2,  5,  5,  2,  2,  5,  5,  5,  5,  2,  2,  2,  2,  2,
+    2,  2,  2,  5,  2,  2,  2,  2,  5,  5,  2,  5,  5,  5,  5,  5,
+    2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2, 11, 11, 11,
+    2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,  2, 11,
+   11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11,  2, 11, 11, 11, 11, 11, 11, 11,  2, 11, 11,
+    2, 11, 11,  2, 11, 11,  2,  2, 11,  2, 11, 11, 11, 11, 11,  2,
+    2,  2,  2, 11, 11,  2,  2, 11, 11, 11,  2,  2,  2, 11,  2,  2,
+    2,  2,  2,  2,  2, 11, 11, 11, 11,  2, 11,  2,  2,  2,  2,  2,
+    2,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 10, 10, 10,
+    2, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,  2, 10,
+   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10,
+    2, 10, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10,  2, 10, 10, 10,  2, 10, 10, 10,  2,  2, 10,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10,
+    2,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,  2,
+    2,  2,  2,  2,  2, 10, 10, 10, 10, 10, 10, 10,  2, 21, 21, 21,
+    2, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,  2, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21,  2, 21, 21, 21, 21, 21, 21, 21,  2, 21, 21,
+    2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21, 21, 21, 21, 21, 21,
+   21,  2,  2, 21, 21,  2,  2, 21, 21, 21,  2,  2,  2,  2,  2,  2,
+    2,  2, 21, 21,  2,  2,  2,  2, 21, 21,  2, 21, 21, 21, 21, 21,
+    2,  2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 22,
+    2, 22, 22, 22, 22, 22, 22,  2,  2,  2, 22, 22, 22,  2, 22, 22,
+   22, 22,  2,  2,  2, 22, 22,  2, 22,  2, 22, 22,  2,  2,  2, 22,
+   22,  2,  2,  2, 22, 22, 22,  2,  2,  2, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22,  2,  2,  2,  2, 22, 22, 22, 22, 22,  2,
+    2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2, 22,  2,  2,  2,
+    2,  2,  2, 22,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2,  2, 23, 23, 23, 23,
+   23, 23, 23, 23, 23, 23, 23, 23, 23,  2, 23, 23, 23,  2, 23, 23,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23, 23, 23, 23,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23,
+   23,  2, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,  2,  2,
+    2, 23, 23,  2, 23, 23, 23,  2,  2,  2,  2,  2, 23, 23, 23, 23,
+    2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,  2,  2,  2,  2,
+    2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+    2, 16, 16, 16, 16, 16,  2,  2, 16, 16, 16, 16, 16, 16, 16, 16,
+   16,  2, 16, 16, 16,  2, 16, 16, 16, 16,  2,  2,  2,  2,  2,  2,
+    2, 16, 16,  2,  2,  2,  2,  2,  2,  2, 16,  2, 16, 16, 16, 16,
+    2,  2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 20, 20, 20, 20,
+    2, 20, 20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+   20,  2, 20, 20, 20,  2, 20, 20, 20, 20, 20, 20,  2,  2,  2,  2,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    2,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 36, 36,
+    2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2, 36,
+   36, 36, 36, 36, 36, 36, 36, 36,  2, 36,  2,  2, 36, 36, 36, 36,
+   36, 36, 36,  2,  2,  2, 36,  2,  2,  2,  2, 36, 36, 36, 36, 36,
+   36,  2, 36,  2, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,  2,
+    2,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2, 36, 36,
+   36,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24,  2,  2,  2,  2,  0, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24,  2,  2,  2,  2,  2, 18, 18,  2,
+   18,  2, 18, 18, 18, 18, 18,  2, 18, 18, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+    2, 18,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2,  2, 18, 18, 18, 18,
+   18,  2, 18,  2, 18, 18, 18, 18, 18, 18,  2,  2, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25,  2,  2,  2,  2, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25, 25, 25,
+   25,  0,  0,  0,  0, 25, 25,  2,  2,  2,  2,  2, 33, 33, 33, 33,
+   33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  2,  8,  2,  2,  2,  2,  2,  8,  2,  2,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  0,  8,  8,  8,  8, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30, 30, 30,
+   30, 30, 30,  2, 30,  2, 30, 30, 30, 30,  2,  2, 30,  2, 30, 30,
+   30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30,  2, 30, 30,
+   30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30,  2,  2,  2, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30,  2,  2,  2,  2,  2,  2, 29, 29, 29, 29,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+   29, 29,  2,  2, 29, 29, 29, 29, 29, 29,  2,  2, 28, 28, 28, 28,
+   28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34,  2,  2,  2, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35,  0,  0,  0, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35,  2,  2,  2,  2,  2,  2,  2, 45, 45, 45, 45,
+   45, 45, 45, 45, 45, 45, 45, 45, 45,  2, 45, 45, 45, 45, 45, 45,
+   45,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 44, 44, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+   44,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 46, 46, 46, 46,
+   46, 46, 46, 46, 46, 46, 46, 46, 46,  2, 46, 46, 46,  2, 46, 46,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31,  2,  2, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31,  2,  2,  2,  2,  2,  2, 32, 32,  0,  0,
+   32,  0, 32, 32, 32, 32, 32, 32, 32, 32, 32,  2, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32,  2,  2,  2,  2,  2,  2, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32,  2,  2,  2,  2,  2,  2,  2, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32,  2,  2,  2,  2,  2, 28, 28, 28, 28,
+   28, 28,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 48, 48, 48, 48,
+   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,  2, 48, 48, 48, 48,
+   48, 48, 48, 48, 48, 48, 48, 48,  2,  2,  2,  2, 48,  2,  2,  2,
+   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 52, 52, 52,
+   52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+   52, 52, 52, 52, 52, 52, 52, 52, 52, 52,  2,  2, 52, 52, 52, 52,
+   52,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 58,  2,  2,  2,  2, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58,  2,  2,  2,  2,  2,  2, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54, 54, 54,
+   54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+   54, 54, 54, 54, 54, 54, 54, 54,  2,  2, 54, 54, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,  2, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91,  2,  2, 91, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91,  2,  2,  2,  2,  2,  2, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91,  2,  2,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62,  2,  2,  2,  2, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62,  2,  2,  2, 76, 76, 76, 76,
+   76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93,
+   93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+    2,  2,  2,  2,  2,  2,  2,  2, 93, 93, 93, 93, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 73, 73, 73, 73,
+   73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,  6,  6,  6,  6,
+    6,  6,  6,  6,  6,  2,  2,  2,  2,  2,  2,  2,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  2,  2,  8,  8,  8, 76, 76, 76, 76,
+   76, 76, 76, 76,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1,  0,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,
+    1,  1,  1,  1,  1,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
+    1,  0,  0,  0,  1,  1,  0,  2,  2,  2,  2,  2, 19, 19, 19, 19,
+   19, 19,  9,  9,  9,  9,  9,  6, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  9,  9,  9,  9,  9, 19, 19,
+   19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  9,  9,  9,  9,
+    9,  9,  2,  2,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  2,  9,  2,  9,  2,  9,  2,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,
+    9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    2,  2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  2,  2,  9,  9,
+    9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  0,  0,  0,  0,
+    0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  2,  2,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,  1,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  9,  0,  0,  0, 19, 19,  0,  0,  0,  0,  0,  0, 19,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  0, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  0,  0,  0,  0,
+    2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0, 56, 56, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2, 55, 55, 55, 55,
+   55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+    2,  2,  2,  2,  2, 55, 55, 55, 55, 55, 55, 55, 61, 61, 61, 61,
+   61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+   61, 61, 61, 61,  2,  2,  2,  2,  2,  2,  2, 61, 61,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 61, 30, 30, 30, 30,
+   30, 30, 30,  2,  2,  2,  2,  2,  2,  2,  2,  2, 30, 30, 30, 30,
+   30, 30, 30,  2, 30, 30, 30, 30, 30, 30, 30,  2, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13, 13, 13,
+   13, 13,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,  0,
+    0, 13,  0, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0, 13, 13, 13,
+   13, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,  0,  0,  0,  0,
+    0,  0,  0,  0, 13, 13, 13, 13,  0,  0,  0,  0,  2, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15,  2,  2,  1,  1,  0,  0, 15, 15, 15,  0, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17,  0,  0, 17, 17, 17,  2,  2,  2,  2,
+    2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  0, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,  0, 17, 17, 17, 17,
+   17, 17, 17, 17,  0,  0,  0,  0,  0,  0,  0,  0, 39, 39, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39, 39, 39,
+   39, 39, 39,  2,  2,  2,  2,  2,  2,  2,  2,  2, 86, 86, 86, 86,
+   86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77,  2,  2,  2,  2, 79, 79, 79, 79,
+   79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+   79, 79, 79, 79,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19,  0,  0,  0, 19, 19, 19, 19, 19,  2,  2, 19, 19,
+   19, 19, 19,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60,
+   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60, 60, 60, 60, 60, 60, 60,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2, 65, 65, 65, 65,
+   65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+   65, 65, 65, 65,  2,  2,  2,  2,  2,  2,  2,  2, 75, 75, 75, 75,
+   75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+   75, 75,  2,  2,  2,  2,  2,  2,  2,  2, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75, 75, 75,  2,  2,  2,  2,  2,  2, 69, 69, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69,  0, 69, 74, 74, 74, 74,
+   74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 74, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2, 84, 84, 84, 84,
+   84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84, 84, 84, 84, 84, 84, 84,  2,  0, 84, 84, 84, 84,
+   84, 84, 84, 84, 84, 84,  2,  2,  2,  2, 84, 84, 33, 33, 33, 33,
+   33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,  2, 68, 68, 68, 68,
+   68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   68, 68, 68,  2,  2,  2,  2,  2,  2,  2,  2,  2, 68, 68, 68, 68,
+   68, 68, 68, 68, 68, 68, 68, 68, 68, 68,  2,  2, 68, 68, 68, 68,
+   68, 68, 68, 68, 68, 68,  2,  2, 68, 68, 68, 68, 92, 92, 92, 92,
+   92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 92, 92, 92, 92, 92, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 30, 30, 30,
+   30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30,  2,  2, 30, 30, 30,
+   30, 30, 30,  2,  2,  2,  2,  2,  2,  2,  2,  2, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19,  0, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  9, 19, 19,  2,  2,  2,  2,  2,  2,  2,  2, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87,  2,  2, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12,
+   12, 12, 12,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2, 19, 19, 19, 19,
+   19, 19, 19,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  4,
+    4,  4,  4,  4,  2,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14,  2, 14, 14, 14, 14, 14,  2, 14,  2, 14, 14,  2, 14,
+   14,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  3,  3,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,  0,  2,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  0,  2,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0,  2,  2, 12, 12,
+   12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2, 12, 12,
+   12, 12, 12, 12,  2,  2, 12, 12, 12,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49,  2, 49, 49,  2, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2,  2, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49,  2,  2,  2,  2,  2,  0,  0,  0,  2,
+    2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  2, 71, 71, 71, 71,
+   71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+   71, 71, 71, 71, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 42, 42, 42, 42,
+   42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+    2,  2,  2,  2,  2,  2,  2,  2,  2, 42, 42, 42, 41, 41, 41, 41,
+   41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+   41, 41, 41, 41, 41, 41, 41,  2,  2,  2,  2,  2,118,118,118,118,
+  118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,
+  118,118,118,118,118,118,118,  2,  2,  2,  2,  2, 53, 53, 53, 53,
+   53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+   53, 53, 53, 53, 53, 53, 53, 53, 53, 53,  2, 53, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+    2,  2,  2,  2, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 40, 40, 40, 40,
+   40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51,
+   51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, 50,
+   50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+   50, 50, 50, 50, 50, 50, 50, 50, 50, 50,  2,  2, 50, 50, 50, 50,
+   50, 50, 50, 50, 50, 50,  2,  2,  2,  2,  2,  2,135,135,135,135,
+  135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
+    2,  2,  2,  2,135,135,135,135,135,135,135,135,135,135,135,135,
+  135,135,135,135,135,135,135,135,  2,  2,  2,  2,106,106,106,106,
+  106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
+  106,106,106,106,  2,  2,  2,  2,  2,  2,  2,  2,104,104,104,104,
+  104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,104,110,110,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+  110,110,110,  2,  2,  2,  2,  2,  2,  2,  2,  2,110,110,110,110,
+  110,110,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,110,110,110,110,
+  110,110,110,110,  2,  2,  2,  2,  2,  2,  2,  2, 47, 47, 47, 47,
+   47, 47,  2,  2, 47,  2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47,  2, 47, 47,  2,  2,  2, 47,  2,  2, 47, 81, 81, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+   81, 81,  2, 81, 81, 81, 81, 81, 81, 81, 81, 81,120,120,120,120,
+  120,120,120,120,120,120,120,120,120,120,120,120,116,116,116,116,
+  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,116,116,116,116,116,116,  2,  2,  2,  2,  2,
+    2,  2,  2,116,116,116,116,116,116,116,116,116,128,128,128,128,
+  128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,  2,
+  128,128,  2,  2,  2,  2,  2,128,128,128,128,128, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66, 66, 66,  2,  2,  2, 66, 72, 72, 72, 72,
+   72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+   72, 72, 72, 72, 72, 72,  2,  2,  2,  2,  2, 72, 98, 98, 98, 98,
+   98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97,  2,  2,  2,  2, 97, 97, 97, 97,  2,  2, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57,
+    2, 57, 57,  2,  2,  2,  2,  2, 57, 57, 57, 57, 57, 57, 57, 57,
+    2, 57, 57, 57,  2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57,  2,  2, 57, 57, 57,  2,  2,  2,  2, 57, 57, 57, 57, 57,
+   57, 57, 57, 57, 57,  2,  2,  2,  2,  2,  2,  2, 88, 88, 88, 88,
+   88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,117,117,117,117,
+  117,117,117,117,117,117,117,117,117,117,117,117,112,112,112,112,
+  112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
+  112,112,112,  2,  2,  2,  2,112,112,112,112,112,112,112,112,112,
+  112,112,112,  2,  2,  2,  2,  2,  2,  2,  2,  2, 78, 78, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+   78, 78,  2,  2,  2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83,
+   83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+   83, 83,  2,  2, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82,
+   82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,  2,
+    2,  2,  2,  2, 82, 82, 82, 82, 82, 82, 82, 82,122,122,122,122,
+  122,122,122,122,122,122,122,122,122,122,122,122,122,122,  2,  2,
+    2,  2,  2,  2,  2,122,122,122,122,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,122,122,122,122,122,122,122, 89, 89, 89, 89,
+   89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+   89, 89, 89, 89, 89,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,
+  130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,130,130,130,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,144,144,144,144,
+  144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
+  144,144,144,144,  2,  2,  2,  2,  2,  2,  2,  2,144,144,144,144,
+  144,144,144,144,144,144,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,147,147,147,147,
+  147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
+  147,147,147,147,  2,  2,  2,  2,  2,  2,  2,  2,148,148,148,148,
+  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
+  148,148,148,148,148,148,  2,  2,  2,  2,  2,  2,149,149,149,149,
+  149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
+  149,149,149,  2,  2,  2,  2,  2,  2,  2,  2,  2, 94, 94, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 94, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2, 85,  2,  2,101,101,101,101,
+  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
+  101,101,101,101,101,  2,  2,  2,  2,  2,  2,  2,101,101,101,101,
+  101,101,101,101,101,101,  2,  2,  2,  2,  2,  2, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96,  2,  2,  2,  2,  2,  2,  2,  2,  2,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,  2,  2,  2,  2,  2,  2,  2,  2,  2,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,  2,  2,  2, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,108,108,108,108,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,  2,108,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+  108,108,108,108,108,108,108,108,108,108,108,  2,129,129,129,129,
+  129,129,129,  2,129,  2,129,129,129,129,  2,129,129,129,129,129,
+  129,129,129,129,129,129,129,129,129,129,  2,129,129,129,129,129,
+  129,129,129,129,129,129,  2,  2,  2,  2,  2,  2,109,109,109,109,
+  109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
+  109,109,109,109,109,109,109,  2,  2,  2,  2,  2,109,109,109,109,
+  109,109,109,109,109,109,  2,  2,  2,  2,  2,  2,107,107,107,107,
+    2,107,107,107,107,107,107,107,107,  2,  2,107,107,  2,  2,107,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+  107,107,107,107,107,  2,107,107,107,107,107,107,107,  2,107,107,
+    2,107,107,107,107,107,  2,  1,107,107,107,107,107,107,107,107,
+  107,  2,  2,107,107,  2,  2,107,107,107,  2,  2,107,  2,  2,  2,
+    2,  2,  2,107,  2,  2,  2,  2,  2,107,107,107,107,107,107,107,
+    2,  2,107,107,107,107,107,107,107,  2,  2,  2,107,107,107,107,
+  107,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,137,137,137,137,
+  137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
+  137,137,137,137,137,137,  2,137,  2,137,137,137,124,124,124,124,
+  124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
+  124,124,124,124,  2,  2,  2,  2,  2,  2,  2,  2,124,124,124,124,
+  124,124,124,124,124,124,  2,  2,  2,  2,  2,  2,123,123,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
+  123,123,  2,  2,123,123,123,123,123,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,123,123,  2,  2,114,114,114,114,
+  114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+  114,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,114,114,114,114,
+  114,114,114,114,114,114,  2,  2,  2,  2,  2,  2, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32,  2,  2,  2,102,102,102,102,
+  102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,
+  102,102,102,102,102,  2,  2,  2,  2,  2,  2,  2,102,102,102,102,
+  102,102,102,102,102,102,  2,  2,  2,  2,  2,  2,126,126,126,126,
+  126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
+  126,126,126,126,126,126,126,  2,  2,126,126,126,126,126,126,126,
+  126,126,126,126,126,126,126,126,  2,  2,  2,  2,142,142,142,142,
+  142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
+  142,142,142,142,142,142,142,142,  2,  2,  2,  2,125,125,125,125,
+  125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,125,150,150,150,150,
+  150,150,150,150,  2,  2,150,150,150,150,150,150,150,150,150,150,
+  150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
+  150,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,141,141,141,141,
+  141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
+  141,141,141,141,  2,  2,  2,  2,  2,  2,  2,  2,140,140,140,140,
+  140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,121,121,121,121,
+  121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
+  121,121,121,121,121,  2,  2,  2,  2,  2,  2,  2,133,133,133,133,
+  133,133,133,133,133,  2,133,133,133,133,133,133,133,133,133,133,
+  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
+  133,133,133,  2,133,133,133,133,133,133,133,133,133,133,133,133,
+  133,133,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,133,133,133,133,
+  133,133,133,133,133,133,133,133,133,  2,  2,  2,134,134,134,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,  2,  2,134,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
+  134,134,134,134,  2,134,134,134,134,134,134,134,134,134,134,134,
+  134,134,134,  2,  2,  2,  2,  2,  2,  2,  2,  2,138,138,138,138,
+  138,138,138,  2,138,138,  2,138,138,138,138,138,138,138,138,138,
+  138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
+  138,138,138,  2,  2,  2,138,  2,138,138,  2,138,138,138,138,138,
+  138,138,138,138,  2,  2,  2,  2,  2,  2,  2,  2,138,138,138,138,
+  138,138,138,138,138,138,  2,  2,  2,  2,  2,  2,143,143,143,143,
+  143,143,  2,143,143,  2,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,143,143,143,143,143,143,  2,143,143,  2,143,
+  143,143,143,143,143,  2,  2,  2,  2,  2,  2,  2,143,143,143,143,
+  143,143,143,143,143,143,  2,  2,  2,  2,  2,  2,145,145,145,145,
+  145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
+  145,145,145,145,145,  2,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63,  2,  2,  2,  2,  2,  2, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,  2, 63, 63, 63, 63,
+   63,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 63, 63, 63, 63,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 80, 80, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2, 80, 80, 80, 80,
+   80, 80, 80, 80, 80,  2,  2,  2,  2,  2,  2,  2,127,127,127,127,
+  127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,
+  127,127,127,  2,  2,  2,  2,  2,  2,  2,  2,  2, 79, 79, 79, 79,
+   79, 79, 79, 79, 79,  2,  2,  2,  2,  2,  2,  2,115,115,115,115,
+  115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,115,115,115,115,115,115,  2,115,115,115,115,
+  115,115,115,115,115,115,  2,  2,  2,  2,115,115,103,103,103,103,
+  103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
+  103,103,103,103,103,103,103,103,103,103,  2,  2,103,103,103,103,
+  103,103,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,119,119,119,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
+  119,119,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,119,119,119,119,
+  119,119,119,119,119,119,  2,119,119,119,119,119,119,119,  2,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,
+  119,119,119,119,  2,  2,  2,  2,  2,119,119,119,146,146,146,146,
+  146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
+  146,146,146,146,146,146,146,  2,  2,  2,  2,  2, 99, 99, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+   99, 99, 99, 99, 99, 99, 99,  2,  2,  2,  2, 99, 99, 99, 99, 99,
+   99, 99, 99, 99,  2,  2,  2,  2,  2,  2,  2, 99,136,139,  0,  0,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,136,136,136,136,
+  136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
+  136,136,136,136,  2,  2,  2,  2,  2,  2,  2,  2,136,136,136,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 17, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2, 15, 15, 15,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   17, 17, 17, 17,  2,  2,  2,  2,  2,  2,  2,  2,139,139,139,139,
+  139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
+  139,139,139,139,139,139,139,139,  2,  2,  2,  2,105,105,105,105,
+  105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
+  105,105,105,105,105,105,105,  2,  2,  2,  2,  2,105,105,105,105,
+  105,105,105,105,105,105,105,105,105,  2,  2,  2,105,105,105,105,
+  105,105,105,105,105,  2,  2,  2,  2,  2,  2,  2,105,105,105,105,
+  105,105,105,105,105,105,  2,  2,105,105,105,105,  0,  0,  0,  0,
+    0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  1,  1,  1,  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,  0,
+    0,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  9,  9,  9,  9,
+    9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  2,  2,  0,  2,
+    2,  0,  0,  2,  2,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  2,  0,  2,  0,  0,  0,  0,  0,  0,  0,
+    2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  2,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,
+    0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  2,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  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,  2,  2,  0,  0,131,131,131,131,
+  131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
+  131,131,131,131,131,131,131,131,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,131,131,131,131,131,  2,131,131,131,
+  131,131,131,131,131,131,131,131,131,131,131,131, 56, 56, 56, 56,
+   56, 56, 56,  2, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,  2, 56,
+   56,  2, 56, 56, 56, 56, 56,  2,  2,  2,  2,  2,151,151,151,151,
+  151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
+  151,151,151,151,151,151,151,151,151,  2,  2,  2,151,151,151,151,
+  151,151,151,151,151,151,151,151,151,151,  2,  2,151,151,151,151,
+  151,151,151,151,151,151,  2,  2,  2,  2,151,151,152,152,152,152,
+  152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
+  152,152,152,152,152,152,  2,  2,  2,  2,  2,152,113,113,113,113,
+  113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+  113,  2,  2,113,113,113,113,113,113,113,113,113,113,113,113,113,
+  113,113,113,  2,  2,  2,  2,  2,  2,  2,  2,  2,132,132,132,132,
+  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
+  132,132,132,132,132,132,132,132,  2,  2,  2,  2,132,132,132,132,
+  132,132,132,132,132,132,  2,  2,  2,  2,132,132,  0,  0,  0,  0,
+    0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  3,  3,  3,  3,
+    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  2,
+    3,  2,  2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,
+    3,  3,  3,  3,  2,  3,  2,  3,  2,  2,  2,  2,  2,  2,  3,  2,
+    2,  2,  2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  2,  3,  3,  2,
+    3,  2,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  3,  2,
+    3,  2,  2,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,  3,  3,  2,
+    3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  3,  3,  3,
+    2,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  2,  0,
+    0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,
+    2,  0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,
+    2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13, 13, 13,
+   13, 13, 13,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13, 13, 13,
+   13,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13, 13,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 13,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,  0,  0,  1,
+    2,  3,  4,  5,  6,  0,  0,  0,  0,  7,  8,  9, 10, 11,  0, 12,
+    0,  0,  0,  0, 13,  0,  0, 14,  0,  0,  0,  0,  0,  0,  0,  0,
+   15, 16,  0, 17, 18, 19,  0,  0,  0, 20, 21, 22,  0, 23,  0, 24,
+    0, 25,  0, 26,  0,  0,  0,  0,  0, 27, 28,  0, 29,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 30, 31,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 32, 33, 34, 35, 36, 37, 38, 39, 40,  0,  0,  0,
+   41,  0, 42, 43, 44, 45, 46, 47, 48,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 50, 51, 52,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   53, 54, 55, 56, 57, 58, 59, 60, 61, 62,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 63,  0,
+   64,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,  0,  0,  0, 66,  0,
+    0,  0, 67,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 68, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 71, 72, 73, 74,
+   75, 76, 77, 78, 79,  0,
+};
+static const uint16_t
+_hb_ucd_u16[11168] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
+    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
+    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
+    48,  67,  68,  69,  48,  70,  71,  72,  72,  72,  48,  73,  72,  74,  75,  32,
+    76,  48,  48,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+    90,  83,  84,  91,  92,  93,  94,  95,  96,  97,  84,  98,  99, 100,  88, 101,
+   102,  83,  84, 103, 104, 105,  88, 106, 107, 108, 109, 110, 111, 112,  94, 113,
+   114, 115,  84, 116, 117, 118,  88, 119, 120, 115,  84, 121, 122, 123,  88, 124,
+   125, 115,  48, 126, 127, 128,  88, 129, 130, 131,  48, 132, 133, 134,  94, 135,
+   136,  48,  48, 137, 138, 139,  72,  72, 140,  48, 141, 142, 143, 144,  72,  72,
+   145, 146, 147, 148, 149,  48, 150, 151, 152, 153,  32, 154, 155, 156,  72,  72,
+    48,  48, 157, 158, 159, 160, 161, 162, 163, 164,   9,   9, 165,  11,  11, 166,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48, 167, 168,  48,  48, 167,  48,  48, 169, 170, 171,  48,  48,
+    48, 170,  48,  48,  48, 172, 173, 174,  48, 175,   9,   9,   9,   9,   9, 176,
+   177,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 178,  48, 179, 180,  48,  48,  48,  48, 181, 182,
+   183, 184,  48, 185,  48, 186, 183, 187,  48,  48,  48, 188, 189, 190, 191, 192,
+   193, 191,  48,  48, 194,  48,  48, 195, 196,  48, 197,  48,  48,  48,  48, 198,
+    48, 199, 200, 201, 202,  48, 203, 204,  48,  48, 205,  48, 206, 207, 208, 208,
+    48, 209,  48,  48,  48, 210, 211, 212, 191, 191, 213, 214,  72,  72,  72,  72,
+   215,  48,  48, 216, 217, 159, 218, 219, 220,  48, 221,  64,  48,  48, 222, 223,
+    48,  48, 224, 225, 226,  64,  48, 227, 228,   9,   9, 229, 230, 231, 232, 233,
+    11,  11, 234,  27,  27,  27, 235, 236,  11, 237,  27,  27,  32,  32,  32, 238,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 239,  13,  13,  13,  13,  13,  13,
+   240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249,
+   250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260,  72, 261, 262, 263,
+   264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   278, 208, 279, 208, 208, 208, 208, 280, 208, 281, 277, 282, 208, 283, 284, 208,
+   208, 208, 285,  72, 286,  72, 269, 269, 269, 287, 208, 208, 208, 208, 288, 269,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 289, 290, 208, 208, 291,
+   208, 208, 208, 208, 208, 208, 292, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+   208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+   277, 277, 277, 277, 277, 277, 277, 277, 298, 299, 277, 277, 277, 300, 277, 301,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   208, 208, 208, 277, 302, 208, 208, 303, 208, 304, 208, 208, 208, 208, 208, 208,
+     9,   9, 305,  11,  11, 306, 307, 308,  13,  13,  13,  13,  13,  13, 309, 310,
+    11,  11, 311,  48,  48,  48, 312, 313,  48, 314, 315, 315, 315, 315,  32,  32,
+   316, 317, 318, 319, 320,  72,  72,  72, 208, 321, 208, 208, 208, 208, 208, 322,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323,  72, 324,
+   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 177,  48,  48,  48,  48, 330,
+   331,  48,  48, 136,  48,  48,  48,  48, 199, 332,  48,  71, 208, 208, 322,  48,
+   208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 198, 208, 208, 208, 208,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  72,
+    48, 337,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48, 150, 208, 208, 208, 285,  48,  48, 227,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+   338,  48, 339,  72,  13,  13, 340, 341,  13, 342,  48,  48,  48,  48, 343, 344,
+    31, 345, 346, 347,  13,  13,  13, 348, 349, 350, 351, 352, 353,  72,  72, 354,
+   355,  48, 356, 357,  48,  48,  48, 358, 359,  48,  48, 360, 361, 191,  32, 362,
+    64,  48, 363,  48, 364, 365,  48, 150,  76,  48,  48, 366, 367, 368, 369, 370,
+    48,  48, 371, 372, 373, 374,  48, 375,  48,  48,  48, 376, 377, 378, 379, 380,
+   381, 382, 315,  11,  11, 383, 384,  11,  11,  11,  11,  11,  48,  48, 385, 191,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 386,  48, 387,  48,  48, 205,
+   388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
+   388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 203,  48,  48,  48,  48,  48,  48, 206,  72,  72,
+   390, 391, 392, 393, 394,  48,  48,  48,  48,  48,  48, 395, 396, 397,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 398,  72,  48,  48,  48,  48, 399,  48,  48, 400,  72,  72, 401,
+    32, 402,  32, 403, 404, 405, 406, 407,  48,  48,  48,  48,  48,  48,  48, 408,
+   409,   2,   3,   4,   5, 410, 411, 412,  48, 413,  48, 199, 414, 415, 416, 417,
+   418,  48, 171, 419, 203, 203,  72,  72,  48,  48,  48,  48,  48,  48,  48,  71,
+   420, 269, 269, 421, 270, 270, 270, 422, 423, 324, 424,  72,  72, 208, 208, 425,
+    72,  72,  72,  72,  72,  72,  72,  72,  48, 150,  48,  48,  48, 100, 426, 427,
+    48,  48, 428,  48, 429,  48,  48, 430,  48, 431,  48,  48, 432, 433,  72,  72,
+     9,   9, 434,  11,  11,  48,  48,  48,  48, 203, 191,   9,   9, 435,  11, 436,
+    48,  48, 400,  48,  48,  48, 437,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 314,  48, 198, 400,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   438,  48,  48, 439,  48, 440,  48, 441,  48, 199, 442,  72,  72,  72,  48, 443,
+    48, 444,  48, 445,  72,  72,  72,  72,  48,  48,  48, 446, 269, 447, 269, 269,
+   448, 449,  48, 450, 451, 452,  48, 453,  48, 454,  72,  72, 455,  48, 456, 457,
+    48,  48,  48, 458,  48, 459,  48, 460,  48, 461, 462,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 195,  72,  72,  72,   9,   9,   9, 463,  11,  11,  11, 464,
+    48,  48, 465, 191,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72, 269, 466,  72,  72,  72,  72,  72,  72,  72,  72,
+    48, 454, 467,  48,  62, 468,  72,  72,  72,  72,  72,  72,  72,  72,  48, 314,
+   469,  48,  48, 470, 471, 447, 472, 473, 220,  48,  48, 474, 475,  48, 195, 191,
+   476,  48, 477, 478, 479,  48,  48, 480, 220,  48,  48, 481, 482, 483, 484, 485,
+    48,  97, 486, 487,  72,  72,  72,  72, 488, 489, 490,  48,  48, 491, 492, 191,
+   493,  83,  84, 494, 495, 496, 497, 498,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48, 499, 500, 501,  72,  72,  48,  48,  48, 502, 503, 191,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 504, 505, 506, 507,  72,  72,
+    48,  48,  48, 508, 509, 191, 510,  72,  48,  48, 511, 512, 191,  72,  72,  72,
+    48, 172, 513, 514,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 486, 515,  72,  72,  72,  72,  72,  72,   9,   9,  11,  11, 147, 516,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72, 517,  48,  48, 518, 519,  72,
+   520,  48,  48, 521, 522, 523,  48,  48, 524, 525, 526,  72,  48,  48,  48, 195,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    84,  48, 504, 527, 528, 147, 174, 529,  48, 530, 531, 532,  72,  72,  72,  72,
+   533,  48,  48, 534, 535, 191, 536,  48, 537, 538, 191,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 539,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72, 269, 540, 541, 542,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48, 206,  72,  72,  72,  72,  72,  72,
+   270, 270, 270, 270, 270, 270, 543, 544,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48, 386,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 199, 545,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 314,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48, 195,  48, 199, 368,  72,  72,  72,  72,  72,  72,  48, 203, 546,
+    48,  48,  48, 547, 548, 549, 550, 551,  48,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,   9,   9,  11,  11, 269, 552,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 553, 554, 555, 555, 556, 557,  72,  72,  72,  72, 558,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 400,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 559,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48, 199,  72,  72,  72, 559, 560,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 205,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  71, 150, 195, 561, 562,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323,
+   208, 208, 563, 208, 208, 208, 564, 565, 566, 208, 567, 208, 208, 208, 568,  72,
+   208, 208, 208, 208, 569,  72,  72,  72,  72,  72,  72,  72,  72,  72, 269, 570,
+   208, 208, 208, 208, 208, 285, 269, 451,  72,  72,  72,  72,  72,  72,  72,  72,
+     9, 571,  11, 572, 573, 574, 240,   9, 575, 576, 577, 578, 579,   9, 571,  11,
+   580, 581,  11, 582, 583, 584, 585,   9, 586,  11,   9, 571,  11, 572, 573,  11,
+   240,   9, 575, 585,   9, 586,  11,   9, 571,  11, 587,   9, 588, 589, 590, 591,
+    11, 592,   9, 593, 594, 595, 596,  11, 597,   9, 598,  11, 599, 600, 600, 600,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+    32,  32,  32, 601,  32,  32, 602, 603, 604, 605,  45,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   606, 607, 608,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 150, 609, 610,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 611, 612,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 613, 614,  72,  72,
+     9,   9, 575,  11, 615, 368,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72, 484, 269, 269, 616, 617,  72,  72,  72,  72,
+   484, 269, 618, 619,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   620,  48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205,  72,  72,  72, 629,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323,
+   174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631,  72,  72,  72, 632, 208,
+   633, 208, 208, 324, 568, 634, 323,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 635,
+   208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323, 631, 286,
+   208, 208, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 568, 324,  72,
+   324, 208, 208, 208, 636, 175, 208, 208, 636, 208, 637,  72,  72,  72,  72,  72,
+   638, 208, 208, 208, 208, 208, 208, 639, 208, 208, 640, 208, 641, 208, 208, 208,
+   208, 208, 208, 208, 208, 322, 637, 642, 633, 323,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 314,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 204,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48, 203,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 643,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 100,  72,
+    48, 203,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   644,  72, 645, 645, 645, 645, 645, 645,  72,  72,  72,  72,  72,  72,  72,  72,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  72,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 646,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+   389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 647,
+     0,   0,   0,   0,   1,   2,   1,   2,   0,   0,   3,   3,   4,   5,   4,   5,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   6,   0,   0,   7,   0,
+     8,   8,   8,   8,   8,   8,   8,   9,  10,  11,  12,  11,  11,  11,  13,  11,
+    14,  14,  14,  14,  14,  14,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,
+    14,  14,  14,  16,  17,  18,  17,  17,  19,  20,  21,  21,  22,  21,  23,  24,
+    25,  26,  27,  27,  28,  29,  27,  30,  27,  27,  27,  27,  27,  31,  27,  27,
+    32,  33,  33,  33,  34,  27,  27,  27,  35,  35,  35,  36,  37,  37,  37,  38,
+    39,  39,  40,  41,  42,  43,  44,  45,  45,  45,  27,  46,  45,  47,  48,  27,
+    49,  49,  49,  49,  49,  50,  51,  49,  52,  53,  54,  55,  56,  57,  58,  59,
+    60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
+    76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
+    92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107,
+   108, 109, 110, 110, 111, 112, 113, 110, 114, 115, 116, 117, 118, 119, 120, 121,
+   122, 123, 123, 124, 123, 125,  45,  45, 126, 127, 128, 129, 130, 131,  45,  45,
+   132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137,  45,  45,
+   138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
+   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+   143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
+   143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
+   154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+   154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+   154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
+   160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
+   171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
+   177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
+   188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 195,  45,  45,  45,  45,
+   196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
+   202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
+     4,   4, 212,   4,   4, 213, 214, 215,   4,   4,   4, 216,   8,   8,   8, 217,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
+    11, 218,  11,  11, 218, 219,  11, 220,  11,  11,  11, 221, 221, 222,  11, 223,
+   224,   0,   0,   0,   0,   0, 225, 226, 227, 228,   0,   0,  45,   8,   8, 229,
+     0,   0, 230, 231, 232,   0,   4,   4, 233,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 234,  45, 235,  45,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0, 237,   0, 238,   0,   0,   0,   0,   0,   0,
+   239, 239, 240, 239, 239, 240,   4,   4, 241, 241, 241, 241, 241, 241, 241, 242,
+   139, 139, 140, 243, 243, 243, 244, 245, 143, 246, 247, 247, 247, 247,  14,  14,
+     0,   0,   0,   0,   0,  45,  45,  45, 248, 249, 248, 248, 248, 248, 248, 250,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251,  45, 252,
+   253,   0, 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 260, 260, 261,
+   262, 263, 263, 264, 142, 142, 142, 142, 265,   0, 263, 266,   0,   0, 267, 260,
+   142, 265,   0,   0,   0,   0, 142, 268,   0,   0,   0,   0,   0, 260, 260, 269,
+   260, 260, 260, 260, 260, 270,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251,   0,   0,   0,   0,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,  45,
+   271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
+   271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
+   271, 271, 271, 271, 271, 271, 271, 271, 272, 271, 271, 271, 273, 274, 274, 274,
+   275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275,
+   275, 275, 276,  45,  14,  14,  14,  14,  14,  14, 277, 277, 277, 277, 277, 278,
+     0,   0, 279,   4,   4,   4,   4,   4, 280,   4,   4,   4, 281,  45,  45, 282,
+   283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290,  49,  49,
+   291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
+   300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
+   309, 310, 247,   4,   4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
+   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+   142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 315, 142, 316, 142, 142, 317,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319,  45,  45,
+   320, 321,  21, 322, 323,  27,  27,  27,  27,  27,  27,  27, 324,  47,  27,  27,
+    27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
+    27,  27,  27, 325,  45,  27,  27,  27,  27, 326,  27,  27, 327,  45,  45, 328,
+     8, 285, 329,   0,   0, 330, 331, 332,  27,  27,  27,  27,  27,  27,  27, 333,
+   334,   0,   1,   2,   1,   2, 335, 259, 260, 336, 142, 265, 337, 338, 339, 340,
+   341, 342, 343, 344, 345, 345,  45,  45, 342, 342, 342, 342, 342, 342, 342, 346,
+   347,   0,   0, 348,  11,  11,  11,  11, 349, 252, 350,  45,  45,   0,   0, 351,
+    45,  45,  45,  45,  45,  45,  45,  45, 352, 353, 354, 354, 354, 355, 356, 252,
+   357, 357, 358, 359, 360, 361, 361, 362, 363, 364, 365, 365, 366, 367,  45,  45,
+   368, 368, 368, 368, 368, 369, 369, 369, 370, 371, 372, 373, 373, 374, 373, 375,
+   376, 376, 377, 378, 378, 378, 379,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+   380, 380, 380, 381, 380, 382, 383,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392,  45,  45,  45, 393, 394,
+   395, 396, 397, 398,  45,  45,  45,  45, 399, 399, 400, 401, 400, 402, 400, 400,
+   403, 404, 405, 406, 407, 407, 408, 408, 409, 409,  45,  45, 410, 410, 411, 412,
+   413, 413, 413, 414, 415, 416, 417, 418, 419, 420, 421,  45,  45,  45,  45,  45,
+   422, 422, 422, 422, 423,  45,  45,  45, 424, 424, 424, 425, 424, 424, 424, 426,
+   427, 427, 428, 429,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  27, 430,  45,  45,  45,  45,  45,  45,  45,  45,
+   431, 431, 432, 433, 433, 434,  45,  45,  45,  45,  45,  45,  45,  45, 435, 436,
+   437, 437, 437, 437, 438, 439, 437, 440, 441, 441, 441, 441, 442, 443, 444, 445,
+   446, 446, 446, 447, 448, 449, 449, 450, 451, 451, 451, 451, 452, 451, 453, 454,
+   455, 456, 455, 457,  45,  45,  45,  45, 458, 459, 460, 461, 461, 461, 462, 463,
+   464, 465, 466, 467, 468, 469, 470, 471,  45,  45,  45,  45,  45,  45,  45,  45,
+   472, 472, 472, 472, 472, 473,  45,  45, 474, 474, 474, 474, 475, 476,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45, 477, 477, 477, 478, 477, 479,  45,  45,
+   480, 480, 480, 480, 481, 482, 483,  45, 484, 484, 484, 485, 486,  45,  45,  45,
+   487, 488, 489, 487,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   490, 490, 490, 491,  45,  45,  45,  45,  45,  45, 492, 492, 492, 492, 492, 493,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 494, 495, 495, 494, 496,  45,
+   497, 497, 497, 497, 498, 499, 499, 499, 499, 499, 500,  45, 501, 501, 501, 502,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   503, 504, 504, 505, 506, 504, 507, 508, 508, 509, 510, 511,  45,  45,  45,  45,
+   512, 513, 513, 514, 515, 516, 517, 518, 519, 520, 521,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 522, 523,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 524, 524, 524, 525,
+   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
+   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
+   526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
+   526, 526, 526, 526, 526, 526, 526, 526, 526, 527,  45,  45,  45,  45,  45,  45,
+   526, 526, 526, 526, 526, 526, 528, 529, 526, 526, 526, 526, 526, 526, 526, 526,
+   526, 526, 526, 526, 530,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531,
+   531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531,
+   531, 531, 532, 533,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534,
+   534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534,
+   534, 534, 534, 534, 535,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 536, 537, 538, 539,  45,  45,  45,  45,  45,  45, 540, 541, 542,
+   543, 543, 543, 543, 544, 545, 546, 547, 543,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45, 548, 548, 548, 548, 548, 549,  45,  45,  45,  45,  45,  45,
+   550, 550, 550, 550, 551, 550, 550, 550, 552, 550,  45,  45,  45,  45, 553,  45,
+   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
+   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
+   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554,
+   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555,
+   554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 556,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   557, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+   257, 558,  45,  45,  45, 559, 560, 561, 561, 561, 561, 561, 561, 561, 561, 561,
+   561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   563, 563, 563, 563, 563, 563, 564, 565, 566, 567, 267,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 568,
+     0,   0, 569,   0,   0,   0, 570, 571, 572,   0, 573,   0,   0,   0, 574,  45,
+    11,  11,  11,  11, 575,  45,  45,  45,  45,  45,  45,  45,  45,  45,   0, 267,
+     0,   0,   0,   0,   0, 234,   0, 574,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0, 225,   0,   0,   0, 576, 577, 578, 579,   0,   0,   0,
+   580, 581,   0, 582, 583, 584,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 238,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 585,   0,   0,   0,
+   586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586,
+   586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586,
+   586, 586, 586, 586, 586, 586, 586, 586, 587, 588, 589,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   590, 591, 592,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   593, 593, 594, 595, 596,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 597, 597, 597, 598,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 601,  45,  45,
+   602, 602, 602, 602, 603, 604,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45, 334,   0,   0,   0, 605,  45,  45,  45,  45,
+   334,   0,   0, 606,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   607,  27, 608, 609, 610, 611, 612, 613, 614, 615, 616, 615,  45,  45,  45, 324,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0, 252,   0,   0,   0,   0,   0,   0, 267, 227, 334, 334, 334,   0, 568,
+   617,   0,   0,   0,   0,   0, 617,   0,   0,   0, 617,  45,  45,  45, 618,   0,
+   619,   0,   0, 252, 574, 620, 568,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 568, 617, 235,
+     0,   0,   0,   0,   0,   0,   0, 267,   0,   0,   0,   0,   0, 574, 252,  45,
+   252,   0,   0,   0, 621, 285,   0,   0, 621,   0, 606,  45,  45,  45,  45,  45,
+   622,   0,   0,   0,   0,   0,   0, 623,   0,   0, 624,   0, 625,   0,   0,   0,
+     0,   0,   0,   0,   0, 267, 606, 626, 627, 568,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 628,  45,  45,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 629, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 630, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+   248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 631,  45,
+   248, 318,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   632,  45,   0,   0,   0,   0,   0,   0,  45,  45,  45,  45,  45,  45,  45,  45,
+     8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
+  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
+   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
+  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
+     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
+  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
+  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
+  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
+  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
+  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
+   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
+     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
+  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
+  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
+     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
+     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
+  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
+     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
+     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
+     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
+     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
+     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
+  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
+   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
+  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
+  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
+  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
+  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
+  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
+     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
+  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
+  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
+     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
+    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
+  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
+  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
+  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
+  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
+  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
+  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
+  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
+  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
+   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
+   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
+   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
+   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
+   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
+  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
+  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1948,1949,
+  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,1957,1959,1958,
+  1960,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
+   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
+   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
+   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
+   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
+   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
+    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
+   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
+   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
+   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
+   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
+   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
+   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
+    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
+   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
+   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
+   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
+   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
+   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
+   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
+   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
+   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[196] =
+{
+      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
+      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
+      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
+     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
+   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
+      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
+      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
+      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
+     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
+      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
+  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
+     -1,    0,    1,   -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[14026+(((_hb_ucd_u8[13034+(((_hb_ucd_u8[12544+(u>>4>>4)])<<4)+((u>>4)&15u))])<<4)+((u)&15u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16170+(((_hb_ucd_b4(16042+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918000u?_hb_ucd_u8[18924+(((_hb_ucd_u16[3008+(((_hb_ucd_u8[17130+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[6048+(((_hb_ucd_u8[29052+(u>>6)])<<6)+((u)&63u))]:0;
+}
+
+
+#elif !defined(HB_NO_UCD_UNASSIGNED)
+
+static const uint8_t
+_hb_ucd_u8[17198] =
+{
+    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 14, 14, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 21, 23, 21, 21, 21, 21, 24,  7,  7,
+   25, 26, 21, 21, 21, 21, 27, 28, 21, 21, 29, 30, 31, 32, 33, 34,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 35,  7, 36, 37,  7, 38,  7,  7,  7, 39, 21, 40,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   41, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 43,
+    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, 40, 41, 42, 43,
+   44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+   60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+   69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+   84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91,
+   92, 34, 34, 34, 34, 34, 34, 34, 34, 93, 34, 34, 94, 95, 96, 97,
+   98, 99,100,101,102,103,104,105, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,106,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+  108,108, 34, 34,109,110,111,112, 34, 34,113,114,115,116,117,118,
+  119,120,121,122,123,124,125,126,127,128,129,123, 34, 34,130,123,
+  131,132,133,134,135,136,137,138,139,140,141,123,142,123,143,144,
+  145,146,147,148,149,150,151,123,152,153,123,154,155,156,157,123,
+  158,159,123,160,161,162,123,123,163,164,165,166,123,167,123,168,
+   34, 34, 34, 34, 34, 34, 34,169,170, 34,171,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34, 34, 34, 34, 34,172,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123, 34, 34, 34, 34,173,123,123,123,
+   34, 34, 34, 34,174,175,176,177,123,123,123,123,178,179,180,181,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,182,
+   34, 34, 34, 34, 34,183,123,123,123,123,123,123,123,123,123,123,
+   34, 34,184, 34, 34,185,123,123,123,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,186,187,123,123,123,123,123,123,
+   69,188,189,190,191,192,193,123,194,195,196,197,198,199,200,201,
+   69, 69, 69, 69,202,203,123,123,123,123,123,123,123,123,123,123,
+  204,123,205,123,123,206,123,123,123,123,123,123,123,123,123,123,
+   34,207,208,123,123,123,123,123,209,210,211,123,212,213,123,123,
+  214,215,216,217,218,123, 69,219, 69, 69, 69, 69, 69,220,221,222,
+  223,224,225,226,227,228,123,123,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,229, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,230, 34,
+  231, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,232, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,233,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34,234,123,123,123,123,123,123,123,123,123,123,123,
+  235,123,236,237,123,123,123,123,123,123,123,123,123,123,123,123,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,238,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,239,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
+    7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 17, 18, 19,  1, 20, 20, 21, 22, 23, 24, 25,
+   26, 27, 15,  2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+   32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+   11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+   34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+   34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+   32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+   16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+   40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+   43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10,
+   44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11,
+   32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52,  2,  2,  2,
+   16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62,
+   36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65,  8,  9, 66,  2, 67,
+   43, 43, 43, 43, 43, 60, 68,  2, 69, 36, 36, 36, 36, 70, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 71, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 77, 78,  2,  2,  2,  2,  2,  2,  2, 79,
+   70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36,
+   36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44,
+    7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43,
+   43, 43, 40, 21,  2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43,
+   43, 43, 75, 43, 75, 43, 43, 44,  2,  2,  2,  2,  2,  2,  2, 64,
+   36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 44,
+   44, 57, 43, 43, 43, 43, 43, 43, 43, 82, 43, 43, 43, 43, 43, 43,
+   43, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 83, 71, 84,
+   85, 43, 43, 43, 83, 84, 85, 84, 70, 43, 43, 43, 36, 36, 36, 36,
+   36, 43,  2,  7,  7,  7,  7,  7, 86, 36, 36, 36, 36, 36, 36, 36,
+   70, 84, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 84,
+   85, 43, 80, 87, 88, 87, 85, 61, 44, 44, 44, 87, 44, 44, 36, 62,
+   36, 43, 44,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 56, 63, 80,
+   57, 83, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 84,
+   85, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61,
+   44, 44, 44,  7,  7,  7,  7,  7, 43, 36, 70, 64, 44, 44, 44, 44,
+   57, 83, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
+   61, 36, 62, 36, 36, 44, 71, 84, 85, 43, 43, 57, 83, 87, 85, 44,
+   61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
+   57, 84, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 85,
+   85, 43, 80, 87, 88, 87, 85, 44, 44, 44, 44, 83, 44, 44, 36, 62,
+   78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36,
+   61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36,
+   36, 36, 36, 36, 36, 44, 44, 84, 83, 88, 44, 84, 88, 84, 85, 44,
+   61, 44, 44, 87, 44, 44, 44, 44, 27, 89, 67, 67, 56, 90, 44, 44,
+   83, 84, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 44, 62, 43, 83, 84, 88, 43, 80, 43, 43, 44,
+   44, 44, 57, 80, 36, 61, 44, 44, 44, 44, 44, 91, 27, 27, 27, 89,
+   70, 84, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 85,
+   84, 84, 88, 83, 88, 84, 43, 44, 44, 44, 87, 88, 44, 44, 44, 61,
+   62, 61, 44, 44, 44, 44, 44, 44, 43, 84, 62, 36, 36, 36, 61, 36,
+   36, 36, 36, 36, 36, 70, 71, 84, 85, 43, 80, 84, 88, 84, 85, 77,
+   44, 44, 36, 92, 27, 27, 27, 93, 27, 27, 27, 27, 89, 36, 36, 36,
+   44, 84, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
+   36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 87,
+   84, 43, 80, 80, 84, 84, 84, 84, 44, 84, 64, 44, 44, 44, 44, 44,
+   62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 94,
+   36, 36, 36, 75, 43, 43, 43, 60,  7,  7,  7,  7,  7,  2, 44, 44,
+   62, 61, 61, 36, 36, 61, 36, 36, 36, 36, 62, 62, 36, 36, 36, 36,
+   70, 36, 43, 43, 43, 43, 71, 44, 36, 36, 61, 81, 43, 43, 43, 44,
+    7,  7,  7,  7,  7, 44, 36, 36, 77, 67,  2,  2,  2,  2,  2,  2,
+    2, 95, 95, 67, 43, 67, 67, 67,  7,  7,  7,  7,  7, 27, 27, 27,
+   27, 27, 50, 50, 50,  4,  4, 84, 36, 36, 36, 36, 62, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 61, 44, 57, 43, 43, 43, 43, 43, 43, 83,
+   43, 43, 60, 43, 36, 36, 70, 43, 43, 43, 43, 43, 57, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 80, 67, 67, 67, 67, 76, 67, 67, 90, 67,
+    2,  2, 95, 67, 21, 64, 44, 44, 36, 36, 36, 36, 36, 92, 85, 43,
+   83, 43, 43, 43, 85, 83, 85, 71,  7,  7,  7,  7,  7,  2,  2,  2,
+   36, 36, 36, 84, 43, 36, 36, 43, 71, 84, 96, 92, 84, 84, 84, 36,
+   70, 43, 71, 36, 36, 36, 36, 36, 36, 83, 85, 83, 84, 84, 85, 92,
+    7,  7,  7,  7,  7, 84, 85, 67, 11, 11, 11, 48, 44, 44, 48, 44,
+   16, 16, 16, 16, 16, 53, 45, 16, 36, 36, 36, 36, 61, 36, 36, 44,
+   36, 36, 36, 61, 61, 36, 36, 44, 61, 36, 36, 44, 36, 36, 36, 61,
+   61, 36, 36, 44, 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 61, 57, 43,  2,  2,  2,  2, 97, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 98, 44, 67, 67, 67, 67, 67, 44, 44, 44,
+   11, 11, 11, 44, 16, 16, 16, 44, 99, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 77, 72,100, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36,101,102, 44, 36, 36, 36, 36, 36, 63,  2,103,
+  104, 36, 36, 36, 61, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
+   36, 43, 80, 44, 44, 44, 44, 44, 36, 43, 60, 64, 44, 44, 44, 44,
+   36, 43, 44, 44, 44, 44, 44, 44, 61, 43, 44, 44, 44, 44, 44, 44,
+   36, 36, 43, 85, 43, 43, 43, 84, 84, 84, 84, 83, 85, 43, 43, 43,
+   43, 43,  2, 86,  2, 66, 70, 44,  7,  7,  7,  7,  7, 44, 44, 44,
+   27, 27, 27, 27, 27, 44, 44, 44,  2,  2,  2,105,  2, 59, 43, 68,
+   36,106, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 44, 44,
+   36, 36, 70, 71, 36, 36, 36, 36, 36, 36, 36, 36, 70, 61, 44, 44,
+   36, 36, 36, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 61,
+   43, 83, 84, 85, 83, 84, 44, 44, 84, 83, 84, 84, 85, 43, 44, 44,
+   90, 44,  2,  7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 44,
+   36, 36, 61, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 44, 44,
+   36, 36, 36, 36, 36, 44, 44, 44,  7,  7,  7,  7,  7, 98, 44, 67,
+   67, 67, 67, 67, 67, 67, 67, 67, 36, 36, 36, 70, 83, 85, 44,  2,
+   36, 36, 92, 83, 43, 43, 43, 80, 83, 83, 85, 43, 43, 43, 83, 84,
+   84, 85, 43, 43, 43, 43, 80, 57,  2,  2,  2, 86,  2,  2,  2, 44,
+   43, 43, 43, 43, 43, 43, 43,107, 43, 43, 96, 36, 36, 36, 36, 36,
+   36, 36, 83, 43, 43, 83, 83, 84, 84, 83, 96, 36, 36, 36, 44, 44,
+   95, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 90, 44,
+   43, 96, 36, 36, 36, 36, 36, 36, 92, 43, 43, 84, 43, 85, 43, 36,
+   36, 36, 36, 83, 43, 84, 85, 85, 43, 84, 44, 44, 44, 44,  2,  2,
+   36, 36, 84, 84, 84, 84, 43, 43, 43, 43, 84, 43, 44, 91,  2,  2,
+    7,  7,  7,  7,  7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40,  2,
+   16, 16, 16, 16,108, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+    2,  2,  2,  2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43,
+   83, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 92, 43, 61, 44, 44,
+   16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16,
+   16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,109, 40, 40,
+   43, 43, 43, 43, 43, 57, 43, 43, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 44, 11, 11, 11, 44,
+   16, 16, 16, 16, 48, 48, 48, 48, 16, 16, 16, 16, 16, 16, 16, 44,
+   16, 16, 16, 16,110,110,110,110, 16, 16,108, 16, 11, 11,111,112,
+   41, 16,108, 16, 11, 11,111, 41, 16, 16, 44, 16, 11, 11,113, 41,
+   16, 16, 16, 16, 11, 11,114, 41, 44, 16,108, 16, 11, 11,111,115,
+  116,116,116,116,116,117, 65, 65,118,118,118,  2,119,120,119,120,
+    2,  2,  2,  2,121, 65, 65,122,  2,  2,  2,  2,123,124,  2,125,
+  126,  2,127,128,  2,  2,  2,  2,  2,  9,126,  2,  2,  2,  2,129,
+   65, 65, 68, 65, 65, 65, 65, 65,130, 44, 27, 27, 27,  8,127,131,
+   27, 27, 27, 27, 27,  8,127,102, 40, 40, 40, 40, 40, 40, 81, 44,
+   20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,132, 51,
+  133, 51,133, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
+   67,134, 67,135, 67, 34, 11, 16, 11, 32,135, 67, 49, 11, 11, 67,
+   67, 67,134,134,134, 11, 11,136, 11, 11, 35, 36, 39, 67, 16, 11,
+    8,  8, 49, 16, 16, 26, 67,137, 27, 27, 27, 27, 27, 27, 27, 27,
+  103,103,103,103,103,103,103,103,103,138,139,103,140, 67, 44, 44,
+    8,  8,141, 67, 67,  8, 67, 67,141, 26, 67,141, 67, 67, 67,141,
+   67, 67, 67, 67, 67, 67, 67,  8, 67,141,141, 67, 67, 67, 67, 67,
+   67, 67,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+   67, 67, 67, 67,  4,  4, 67, 67,  8, 67, 67, 67,142,143, 67, 67,
+   67, 67, 67, 67, 67, 67,141, 67, 67, 67, 67, 67, 67, 26,  8,  8,
+    8,  8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,  8,  8,
+    8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 90, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67,
+   67, 67, 67, 67, 67, 27, 27, 27, 67, 67, 67, 26, 67, 67, 67, 67,
+   26, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,  8,  8,  8,  8,
+   67, 67, 67, 67, 67, 67, 67, 26, 67, 67, 67, 67,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67,
+    8,  8,127,144,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,127,145,145,145,145,145,145,145,145,145,145,144,  8,  8,  8,
+    8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
+    8,  8,141, 26,  8,  8,141, 67, 67, 67, 44, 67, 67, 67, 67, 67,
+   67, 67, 67, 44, 67, 67, 67, 67, 11, 11, 11, 11, 11, 11, 11, 47,
+   16, 16, 16, 16, 16, 16, 16,108, 32, 11, 32, 34, 34, 34, 34, 11,
+   32, 32, 34, 16, 16, 16, 40, 11, 32, 32,137, 67, 67,135, 34,146,
+   43, 32, 44, 44, 91,  2, 97,  2, 16, 16, 16,147, 44, 44,147, 44,
+   36, 36, 36, 36, 44, 44, 44, 52, 64, 44, 44, 44, 44, 44, 44, 57,
+   36, 36, 36, 61, 44, 44, 44, 44, 36, 36, 36, 61, 36, 36, 36, 61,
+    2,119,119,  2,123,124,119,  2,  2,  2,  2,  6,  2,105,119,  2,
+  119,  4,  4,  4,  4,  2,  2, 86,  2,  2,  2,  2,  2,118,  2,  2,
+  105,148,  2,  2,  2,  2,  2,  2, 67, 67, 67, 67, 67, 55, 67, 67,
+   67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 67, 44, 44,  1,  2,149,150,  4,  4,  4,  4,
+    4, 67,  4,  4,  4,  4,151,152,153,103,103,103,103, 43, 43, 84,
+  154, 40, 40, 67,103,155, 63, 67, 36, 36, 36, 61, 57,156,157, 69,
+   36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+   67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90,
+   27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27,
+  158, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36,159,  2,  7,  7,  7,  7,  7, 36, 44, 44,
+   32, 32, 32, 32, 32, 32, 32, 70, 51,160, 43, 43, 43, 43, 43, 86,
+   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36,103,103,103,103,103,
+   43,  2,  2,  2, 44, 44, 44, 44, 41, 41, 41,157, 40, 40, 40, 40,
+   41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32,
+   45, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,161, 34, 35,
+   32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32,
+   11, 11, 32, 32, 32, 32, 32, 32, 44, 32, 11, 47, 44, 44, 44, 44,
+   44, 44, 44, 62, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
+   36, 92, 85, 83, 67, 67, 44, 44, 27, 27, 27, 67,162, 44, 44, 44,
+   36, 36,  2,  2, 44, 44, 44, 44, 84, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 84, 84, 84, 84, 84, 84, 84, 84, 43, 44, 44, 44, 44,  2,
+   43, 36, 36, 36,  2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43,  2,
+   36, 36, 36, 70, 43, 43, 43, 43, 43, 84, 44, 44, 44, 44, 44, 91,
+   36, 70, 84, 43, 43, 84, 43, 84,163,  2,  2,  2,  2,  2,  2, 52,
+    7,  7,  7,  7,  7, 44, 44,  2, 36, 36, 70, 69, 36, 36, 36, 36,
+    7,  7,  7,  7,  7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 83,
+   85, 83, 85, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 83, 44,
+    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 92, 83, 36,
+   71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
+   44, 44, 44, 44, 44, 62,106,  2, 36, 36, 36, 36, 36, 92, 43, 84,
+    2,106,164, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61,
+   62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,112, 40, 40,
+   16, 16, 16, 16, 44, 44, 44, 44, 36, 92, 85, 84, 83,163, 85, 44,
+   36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
+  165,165,165,165,165,165,165,165,166,166,166,166,166,166,166,166,
+   16, 16, 16,108, 44, 44, 44, 44, 44,147, 16, 16, 44, 44, 62, 71,
+   36, 36, 36, 36,167, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+   36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+   41, 44, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,145, 44, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,162, 44,
+    2,  2,  2,168,128, 44, 44, 44,  6,169,170,145,145,145,145,145,
+  145,145,128,168,128,  2,125,171,  2, 64,  2,  2,151,145,145,128,
+    2,172,  8,173, 66,  2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 61, 79, 91,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,127,128,  4,  2, 36, 36, 36, 36, 36,
+   69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+   44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44,
+   20,174, 56,175, 26,  8,141, 90, 44, 44, 44, 44, 79, 65, 67, 44,
+   36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62,
+    2, 64, 44,176, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
+  103,103,140, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90,
+   90, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 50, 44,
+  177, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 44, 44,
+   27, 27, 44, 44, 44, 44, 62, 36,150, 36, 36, 36, 36,178, 44, 44,
+   36, 36, 36, 43, 43, 80, 44, 44, 36, 36, 36, 36, 36, 36, 36, 91,
+   36, 36, 44, 44, 36, 36, 36, 36,179,103,103, 44, 44, 44, 44, 44,
+   11, 11, 11, 11, 16, 16, 16, 16, 11, 11, 44, 44, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 44, 44, 36, 36, 44, 44, 44, 44, 44, 91,
+   36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
+   36, 36, 36, 91, 27, 27, 27, 27, 36, 36, 36, 77,158, 27, 27, 27,
+   44, 44, 44,176, 27, 27, 27, 27, 36, 61, 36, 44, 44,176, 27, 27,
+   36, 36, 36, 27, 27, 27, 44, 91, 36, 36, 36, 36, 36, 44, 44, 91,
+   36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27,
+   70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36,
+   36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27, 98, 44, 44, 44,
+    2,  2,  2,  2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,180, 30,
+   36, 36, 36, 36, 36, 36,180, 27, 36, 36, 36, 36, 78, 36, 36, 36,
+   36, 36, 70, 80, 44,176, 27, 27,  2,  2,  2, 64, 44, 44, 44, 44,
+   36, 36, 36, 44, 91,  2,  2,  2, 36, 36, 36, 44, 27, 27, 27, 27,
+   36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 91,  2, 64, 44,
+   44, 44, 44, 44,176, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
+   16,108, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
+   27, 27, 27, 27, 27, 27, 27, 98, 27, 27, 27, 93, 44, 44, 44, 44,
+  177, 27, 30,  2,  2, 44, 44, 44, 85, 96, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60,  2,  2,  2, 44,
+   27, 27, 27,  7,  7,  7,  7,  7, 44, 44, 44, 44, 44, 44, 44, 57,
+   84, 85, 43, 83, 85, 60,181,  2,  2, 44, 44, 44, 44, 44, 79, 44,
+   43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 85, 43,
+   43, 43, 80,  7,  7,  7,  7,  7,  2,  2, 92, 88, 44, 44, 44, 44,
+   36, 70,  2, 61, 44, 44, 44, 44, 36, 92, 84, 43, 43, 43, 43, 83,
+   96, 36, 63,  2, 59, 43, 60, 44,  7,  7,  7,  7,  7, 63, 63,  2,
+  176, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 84, 85, 43, 84, 83, 43,  2,  2,  2, 80,
+   36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
+   36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
+   84, 85, 43, 43, 43, 80, 44, 44, 43, 84, 62, 36, 36, 36, 61, 62,
+   61, 36, 62, 36, 36, 57, 71, 84, 83, 84, 88, 87, 88, 87, 84, 44,
+   61, 44, 44, 87, 44, 44, 62, 36, 36, 84, 44, 43, 43, 43, 80, 44,
+   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 92, 84, 43, 43, 43, 43,
+   84, 43, 83, 71, 36, 63,  2,  2,  7,  7,  7,  7,  7, 91, 91, 71,
+   84, 85, 43, 43, 83, 83, 84, 85, 83, 43, 36, 72, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 92, 84, 43, 43, 44, 84, 84, 43, 85,
+   60,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 43, 44,
+   84, 85, 43, 43, 43, 83, 85, 85, 60,  2, 61, 44, 44, 44, 44, 44,
+    2,  2,  2,  2,  2,  2, 64, 44, 36, 36, 36, 36, 36, 70, 85, 84,
+   43, 43, 43, 85, 61, 44, 44, 44, 84, 43, 43, 85, 43, 43, 44, 44,
+    7,  7,  7,  7,  7, 27,  2, 95, 43, 43, 43, 43, 85, 60, 44, 44,
+   27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 44, 36, 36, 36,
+   92, 84, 43, 43, 44, 43, 84, 84, 71, 72, 88, 44, 44, 44, 44, 44,
+   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 83, 70, 43, 60,
+    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 83, 85, 43, 36, 36,
+   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 83, 43,  2, 72,  2,
+    2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 85,
+   63,  2,  2, 44, 44, 44, 44, 44,  2, 36, 36, 36, 36, 36, 36, 36,
+   44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 87, 43, 43, 43,
+   83, 43, 85, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
+   70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
+   36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84, 88,
+   43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,163, 64, 44, 44, 44,
+   27, 27, 89, 67, 67, 67, 56, 20,162, 67, 67, 67, 67, 67, 67, 67,
+   67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,178,
+    2,  2, 64, 44, 44, 44, 44, 44, 65, 65, 65, 65, 68, 44, 44, 44,
+   43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60,  2,  2, 67, 67,
+   40, 40, 95, 44, 44, 44, 44, 44,  7,  7,  7,  7,  7,176, 27, 27,
+   27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36,
+   27, 27, 27, 30,  2, 64, 44, 44, 36, 36, 36, 36, 36, 61, 44, 57,
+   92, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40,
+   40, 86, 44, 44, 44, 44, 44, 44, 36, 61, 44, 44, 44, 44, 44, 44,
+   44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60,
+   65, 65, 44, 44, 44, 44, 44, 44, 67, 67, 67, 90, 55, 67, 67, 67,
+   67, 67,182, 85, 43, 67,182, 84, 84,183, 65, 65, 65, 82, 43, 43,
+   43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67,
+   67, 67, 67, 67, 90, 44, 44, 44, 67, 43, 76, 44, 44, 44, 44, 44,
+   27, 27, 44, 44, 44, 44, 44, 44, 11, 11, 11, 11, 11, 16, 16, 16,
+   16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
+   16, 16,108, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 47, 11, 44, 47, 48, 47, 48, 11, 47, 11,
+   11, 11, 11, 16, 16,147,147, 16, 16, 16,147, 16, 16, 16, 16, 16,
+   16, 16, 11, 48, 11, 47, 48, 11, 11, 11, 47, 11, 11, 11, 47, 16,
+   16, 16, 16, 16, 11, 48, 11, 47, 11, 11, 47, 47, 44, 11, 11, 11,
+   47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
+   11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 44, 11, 11, 11, 11,
+   31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16,
+   16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16,
+   16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16,
+   11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 44,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 43, 43, 43, 76, 67, 50, 43, 43,
+   43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
+   67, 67, 76, 21,  2,  2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
+   43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
+   43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
+    7,  7,  7,  7,  7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 43, 43,
+    7,  7,  7,  7,  7, 44, 44, 94, 36, 36, 61,176, 27, 27, 27, 27,
+   43, 43, 43, 80, 44, 44, 44, 44, 16, 16, 43, 43, 43, 74, 44, 44,
+   27, 27, 27, 27, 27, 27,158, 27,184, 27, 98, 44, 44, 44, 44, 44,
+   27, 27, 27, 27, 27, 27, 27,158, 27, 27, 27, 27, 27, 27, 27, 44,
+   36, 36, 62, 36, 36, 36, 36, 36, 62, 61, 61, 62, 62, 36, 36, 36,
+   36, 61, 36, 36, 62, 62, 44, 44, 44, 61, 44, 62, 62, 62, 62, 36,
+   62, 61, 61, 62, 62, 62, 62, 62, 62, 61, 61, 62, 36, 61, 36, 36,
+   36, 61, 36, 36, 62, 36, 61, 61, 36, 36, 36, 36, 36, 62, 36, 36,
+   62, 36, 62, 36, 36, 62, 36, 36,  8, 44, 44, 44, 44, 44, 44, 44,
+   55, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44,
+   44, 44, 44, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44, 44, 44,
+   67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+   67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 44,
+   67, 67, 67, 67, 67, 67, 55, 67, 67, 55, 67, 90, 44, 67, 67, 67,
+   67, 90, 55, 67, 67, 90, 44, 67, 67, 67, 67, 67, 67, 90, 55, 67,
+   67, 67, 44, 44, 67, 90, 44, 44, 36, 44, 44, 44, 44, 44, 44, 44,
+   79, 44, 44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 65, 65, 65,
+  166,166,166,166,166,166,166, 44,166,166,166,166,166,166,166,  0,
+    0,  0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
+   25, 25, 25, 21, 21,  9,  9,  9,  9, 22, 21, 18, 24, 16, 24,  5,
+    5,  5,  5, 22, 25, 18, 25,  0, 23, 23, 26, 21, 24, 26,  7, 20,
+   25,  1, 26, 24, 26, 25, 15, 15, 24, 15,  7, 19, 15, 21,  9, 25,
+    9,  5,  5, 25,  5,  9,  5,  7,  7,  7,  9,  8,  8,  5,  7,  5,
+    6,  6, 24, 24,  6, 24, 12, 12,  2,  2,  6,  5,  9, 21,  9,  2,
+    2,  9, 25,  9, 26, 12, 11, 11,  2,  6,  5, 21, 17,  2,  2, 26,
+   26, 23,  2, 12, 17, 12, 21, 12, 12, 21,  7,  2,  2,  7,  7, 21,
+   21,  2,  1,  1, 21, 23, 26, 26,  1,  2,  6,  7,  7, 12, 12,  7,
+   21,  7, 12,  1, 12,  6,  6, 12, 12, 26,  7, 26, 26,  7,  2,  1,
+   12,  2,  6,  2,  1, 12, 12, 10, 10, 10, 10, 12, 21,  6,  2, 10,
+   10,  2, 15, 26, 26,  2,  2, 21,  7, 10, 15,  7,  2, 23, 21, 26,
+   10,  7, 21, 15, 15,  2, 17,  7, 29,  7,  7, 22, 18,  2, 14, 14,
+   14,  7, 17, 21,  7,  6, 11,  2,  5,  2,  5,  6,  8,  8,  8, 24,
+    5, 24,  2, 24,  9, 24, 24,  2, 29, 29, 29,  1, 17, 17, 20, 19,
+   22, 20, 27, 28,  1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22,
+   18, 21, 21, 29, 15,  6, 18,  6, 12, 11, 11, 12,  9, 26, 26,  9,
+   26,  5,  5, 26, 14,  9,  5, 14, 14, 15, 25, 26, 26, 22, 18, 26,
+   18, 25, 18, 22,  5, 12,  2,  5, 22, 21, 26,  6,  7, 14, 17, 22,
+   18, 18, 26, 14, 17,  6, 14,  6, 12, 24, 24,  6, 26, 15,  6, 21,
+   11, 21, 24,  9, 23, 26, 10, 21,  6, 10,  4,  4,  3,  3,  7, 25,
+   21, 22, 17, 16, 16, 22, 16, 16, 25, 17, 25,  2, 25, 24, 23,  2,
+    2, 15, 12, 15, 14,  2, 21, 14,  7, 15, 21,  1, 26, 10, 10,  1,
+   23, 15,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12,
+   13,  0, 14,  0,  0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,
+    0, 21, 22, 23,  0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+   33,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 34,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   35,  0,  0,  0,  0,  0,  0,  0,  0,  0, 36, 37,  0,  0,  0,  0,
+    0,  0, 38, 39,  0,  0, 40,  0,  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,  2,  3,  4,  0,  0,  0,  0,  0,  0,  0,  0,  5,  0,  0,  0,
+    0,  0,  0,  0,  6,  7,  8,  0,  9,  0, 10, 11,  0,  0, 12, 13,
+   14, 15, 16,  0,  0,  0,  0, 17, 18, 19, 20,  0,  0,  0, 21, 22,
+    0, 23, 24,  0,  0, 23, 25, 26,  0, 23, 25,  0,  0, 23, 25,  0,
+    0, 23, 25,  0,  0,  0, 25,  0,  0,  0, 27,  0,  0, 23, 25,  0,
+    0, 28, 25,  0,  0,  0, 29,  0,  0, 30, 31,  0,  0, 32, 33,  0,
+   34, 35,  0, 36, 37,  0, 38,  0,  0, 39,  0,  0, 40,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   42, 42,  0,  0,  0,  0, 43,  0,  0,  0,  0,  0,  0, 44,  0,  0,
+    0, 45,  0,  0,  0,  0,  0,  0, 46,  0,  0, 47,  0, 48,  0,  0,
+    0, 49, 50, 51,  0, 52,  0, 53,  0, 54,  0,  0,  0,  0, 55, 56,
+    0,  0,  0,  0,  0,  0, 57, 58,  0,  0,  0,  0,  0,  0, 59, 60,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 61,
+    0,  0,  0, 62,  0,  0,  0, 63,  0, 64,  0,  0, 65,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66, 67,  0,  0, 68,
+    0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,  0,  0,  0, 50, 70,
+    0, 71, 72,  0,  0, 73, 74,  0,  0,  0,  0,  0,  0, 75, 76, 77,
+    0,  0,  0,  0,  0,  0,  0, 25,  0,  0,  0,  0,  0,  0,  0,  0,
+   78,  0,  0,  0,  0,  0,  0,  0,  0, 79,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 80,  0,  0,  0,  0,  0,  0,  0, 81,
+    0,  0,  0, 82,  0,  0,  0,  0, 83, 84,  0,  0,  0,  0,  0, 85,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 87,  0,  0,  0,  0,  0,  0,  0, 69, 62,  0, 88,  0,  0,
+   89, 90,  0, 73,  0,  0, 91,  0,  0, 92,  0,  0,  0,  0,  0, 93,
+    0, 94, 25, 95,  0,  0,  0,  0,  0,  0, 96,  0,  0,  0, 97,  0,
+    0,  0,  0,  0,  0, 62, 98,  0,  0, 62,  0,  0,  0, 99,  0,  0,
+    0,100,  0,  0,  0,  0,  0,  0,  0, 88,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 74,  0, 42,101,  0,102,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,
+    0,  0,103,  0,104,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,
+    0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,108,109,110,  0,  0,  0,  0,111,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,112,113,  0,  0,  0,  0,  0,  0,
+    0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,114,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,115,  0,
+    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,  1,  1,  1,  2,  3,  4,  5,  6,  7,  4,  4,  8,  9, 10,
+    1, 11, 12, 13, 14, 15, 16, 17, 18,  1,  1,  1,  0,  0,  0,  0,
+   19,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 21, 22,  1,
+   23,  4, 21, 24, 25, 26, 27, 28, 29, 30,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33, 34, 35,  1, 36,
+    0,  0,  0,  0, 37,  0,  0,  0,  0,  0,  0,  0,  0, 38,  1, 39,
+   14, 39, 40, 41,  0,  0,  0,  0,  0,  0,  0,  0, 42,  0,  0,  0,
+    0,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0,  0,  0,
+    0,  0, 19,  1, 21,  0,  0, 47,  0,  0,  0,  0,  0, 38, 48,  1,
+    1, 49, 49, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0,
+    0,  0,  0,  0, 52,  1,  1,  1, 53, 21, 43, 54, 55, 21, 35,  1,
+    0,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0, 57, 58, 59,  0,  0,
+    0,  0,  0, 57,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 60,
+    0,  0,  0, 57,  0, 61,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63,
+    0,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 65,  0,
+    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67,  0,
+    0,  0, 68,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,
+    0,  0,  0,  0,  0, 70, 71,  0,  0,  0,  0,  0, 72, 73, 74, 75,
+   76, 77,  0,  0,  0,  0,  0,  0,  0, 78,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 79, 80,  0,  0,  0,  0, 47,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,  0, 63,  0,  0,
+    0,  0,  0,  0, 64,  0,  0, 81,  0,  0, 82,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 83,  0,  0,  0,  0,  0,  0, 19, 84,  0,
+   63,  0,  0,  0,  0, 49,  1, 85,  0,  0,  0,  0,  1, 54, 15, 41,
+    0,  0,  0,  0,  0, 56,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,
+    0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 86,  0,  0,  0,  0,  0,
+    0, 87,  0,  0, 86,  0,  0,  0,  0,  0,  0,  0,  0, 79,  0,  0,
+    0,  0,  0,  0, 88,  9, 12,  4, 89,  8, 90, 47,  0, 59, 50,  0,
+   21,  1, 21, 91, 92,  1,  1,  1,  1,  1,  1,  1,  1, 93, 94, 95,
+    0,  0,  0,  0, 96,  1, 97, 59, 81, 98, 99,  4, 59,  0,  0,  0,
+    0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,
+    1,  1,  1,  1,  1,  1,  1,  1,  0,  0,100,101,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,102,  0,  0,  0,  0, 19,  0,  1,  1, 50,
+    0,  0,  0,  0,  0,  0,  0, 38,  0,  0,  0,  0, 50,  0,  0,  0,
+    0, 64,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1, 50,  0,  0,  0,
+    0,  0, 52, 69,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,
+    0,  0,  0,  0, 79,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,103,104, 59, 38, 81,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,
+    1, 14,  4, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47,
+   84,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 38, 88,  0,
+    0,  0,  0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,107, 62,
+    0,108,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
+    0,109, 14, 54, 84,  0,  0,  0,  0,  0,  0,  0,  0,  0,110,  0,
+   88,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63,  0,  0,
+   63,  0, 87,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,110,  0,  0,
+    0,  0,111,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 79, 56,
+    0, 38,  1, 59,  1, 59,  0,  0, 64, 87,  0,  0,  0,  0,  0, 60,
+  112,  0,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,112,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,
+    0, 62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,
+   87,113,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,
+    0,  0,  0,  0,  8, 90,  0,  0,  0,  0,  0,  0,  1, 88,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,114,  0,115,116,117,118,  0, 52,  4,
+  119, 49, 23,  0,  0,  0,  0,  0,  0,  0, 38, 50,  0,  0,  0,  0,
+   38, 59,  0,  0,  0,  0,  0,  0,  1, 88,  1,  1,  1,  1, 39,  1,
+   48,103, 88,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    0,  0,  0,  0,  4,119,  0,  0,  0,  1,120,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,230,230,230,230,230,232,220,220,220,220,232,216,
+  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+    1,  1,  1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,
+  220,220,230,230,230,220,220,  0,230,230,230,220,220,220,220,230,
+  232,220,220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,
+    0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
+    0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+  220,230,230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,
+  230,  0,220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,
+  220,220,230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,
+  230,230,  0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,
+    0,  0,  0,220,230,230,  0,220,230,220,220,220, 27, 28, 29,230,
+    7,  0,  0,  0,  0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,
+    0,  0,230,  0,  0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,
+    0,  0,  9,  0,103,103,  9,  0,107,107,107,107,118,118,  9,  0,
+  122,122,122,122,220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,
+    0,129,130,  0,132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,
+  130,  0,230,230,  9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,
+    0,  9,  9,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,
+  220,  0,  0,  0,230,  0,  0,220,  0,  0,  9,  9,  0,  0,  7,  0,
+  230,230,230,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,
+  202,230,230,230,230,230,232,228,228,220,  0,230,233,220,230,220,
+  230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,220,230,  1,  1,
+    0,  0,218,228,232,222,224,224,  0,  8,  8,  0,230,  0,230,230,
+  220,  0,  0,230,  0,  0, 26,  0,  0,220,  0,230,230,  1,220,  0,
+    0,230,220,  0,  0,  0,220,220,  0,  9,  7,  0,  0,  7,  9,  0,
+    0,  0,  9,  7,  9,  9,  0,  0,  0,  0,  1,  0,  0,216,216,  1,
+    1,  1,  0,  0,  0,226,216,216,216,216,216,  0,220,220,220,  0,
+  230,230,  7,  0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+   17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17,237,  0,  1,  2,  2,  0,  3,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    5,  0,  0,  0,  0,  6,  7,  8,  9,  0,  0,  0, 10, 11, 12, 13,
+   14, 15, 16, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,
+    0,  0, 21, 22,  0,  0,  0,  0, 23, 24, 25, 26,  0, 27,  0, 28,
+   29, 30, 31, 32,  0,  0,  0,  0,  0,  0,  0, 33, 34, 35,  0,  0,
+    0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0, 37, 38,
+    0,  0,  0,  0,  1,  2, 39, 40,  0,  1,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  0,  3,  4,  0,  0,  5,  0,  0,  0,  6,  0,  0,  0,  0,  0,
+    0,  0,  7,  1,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,  0,
+    0,  0, 10,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 10,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0, 11, 12,
+    0, 13,  0, 14, 15, 16,  0,  0,  0,  0,  0,  1, 17, 18,  0, 19,
+    7,  1,  0,  0,  0, 20, 20,  7, 20, 20, 20, 20, 20, 20, 20,  8,
+   21,  0, 22,  0,  7, 23, 24,  0, 20, 20, 25,  0,  0,  0, 26, 27,
+    1,  7, 20, 20, 20, 20, 20,  1, 28, 29, 30, 31,  0,  0, 20,  0,
+    0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0, 20, 20,
+   20,  1,  0,  0,  8, 21, 32,  4,  0, 10,  0, 33,  7, 20, 20, 20,
+    0,  0,  0,  0,  8, 34, 34, 35, 36, 34, 37,  0, 38,  1, 20, 20,
+    0,  0, 39,  0,  1,  1,  0,  8, 21,  1, 20,  0,  0,  0,  1,  0,
+    0, 40,  1,  1,  0,  0,  8, 21,  0,  1,  0,  1,  0,  1,  0,  0,
+    0,  0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  7, 20, 41,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  0, 42, 43, 44,  0, 45,
+    0,  8, 21,  0,  0,  0,  0,  0,  0,  0,  0, 46,  7,  1, 10,  1,
+    0,  0,  0,  1, 20, 20,  1,  0,  0,  0,  0,  0,  0,  0, 20, 20,
+    1, 20, 20,  0,  0,  0,  0,  0,  0,  0, 26, 21,  0,  1,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3, 47, 48,  0,  0,  0,
+    0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  9, 10, 11, 12, 12, 12, 12, 13, 14,
+   14, 14, 14, 15, 16, 17, 18, 19, 20, 14, 21, 14, 22, 14, 14, 14,
+   14, 23, 24, 24, 25, 26, 14, 14, 14, 14, 27, 28, 14, 14, 29, 30,
+   31, 32, 33, 34,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 35,  7, 36, 37,  7, 38,  7,  7,
+    7, 39, 14, 40, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 41,  0,  0,  1,  2,  2,  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, 32, 33, 34, 35, 36, 37, 37,
+   37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+   51, 52,  2,  2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+   59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+   66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 79, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82,
+   83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 70, 70, 98, 99,100,101,102,102,
+  103,104,105,106,107,108,109,110,111,112, 97,113,114,115,116,117,
+  118, 97,119,119,120, 97,121,122,123,124,125,126,127,128,129,130,
+  131, 97,132, 97,133,134,135,136,137,138,139,140,141, 97,142,143,
+   97,144,145,146,147, 97,148,149, 97,150,151,152, 97, 97,153,154,
+  155,156, 97,157, 97,158,159,159,159,159,159,159,159,160,161,159,
+  162, 97, 97, 97, 97, 97,163,163,163,163,163,163,163,163,164, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,165,165,
+  165,165,166, 97, 97, 97,167,167,167,167,168,169,170,171, 97, 97,
+   97, 97,172,173,174,175,176,176,176,176,176,176,176,176,176,176,
+  176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+  176,176,176,176,176,177,176,176,176,176,176,178, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,179,180,181,182,182,183, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,184,185,
+   97, 97, 97, 97, 97, 97, 59,186,187,188,189,190,191, 97,192,193,
+  194, 59, 59,195, 59,196,197,197,197,197,197,198, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,199, 97,200, 97, 97,201, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,202,203,204, 97, 97, 97, 97, 97,205,206,
+  207, 97,208,209, 97, 97,210,211,212,213,214, 97, 59, 59, 59, 59,
+   59, 59, 59,215,216,217,218,219,220,221,222,223, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70,224, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70,225, 70,226, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70,227, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 97, 97,
+   97, 97, 97, 97, 97, 97, 70, 70, 70, 70,229, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,230, 97,231,232,  0,  1,  2,  2,  0,  1,
+    2,  2,  2,  3,  4,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  0,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0, 19, 19,
+   19, 19, 19, 19, 19,  0, 19,  0,  0,  0,  0,  0,  0,  0, 19, 19,
+   19, 19, 19,  0,  0,  0,  0,  0, 26, 26,  0,  0,  0,  0,  1,  1,
+    1,  1,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,  2,  2,
+    9,  9,  9,  9,  0,  9,  2,  2,  2,  2,  9,  0,  9,  0,  9,  9,
+    9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    2,  9,  9,  9,  9,  9,  9,  9, 55, 55, 55, 55, 55, 55, 55, 55,
+   55, 55, 55, 55, 55, 55,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6,  6,  1,  1,  6,  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  4,  0,
+    4,  2,  2,  4,  4,  4,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,  2,  2,  2, 14, 14,
+   14,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14,  2,  2,  2,  3,  3,
+    3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  3,  2,  3,  0,  0,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  1,  1,  1,  1,  1,  1,  1,
+    1,  1,  1,  1,  3,  3,  1,  3,  3,  3,  3,  3,  3,  3, 37, 37,
+   37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,  2, 37, 37, 37,
+   37,  2,  2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+    2,  2,  2,  2,  2,  2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+   64,  2,  2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+   90, 90, 90, 90,  2,  2, 90, 90, 90, 90, 90, 90, 90,  2, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95,  2,  2, 95,  2, 37, 37,
+   37,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,
+    0,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  7,  1,
+    1,  1,  1,  7,  7,  7,  7,  7,  7,  7,  0,  0,  7,  7,  5,  5,
+    5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,
+    2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  5,  5,  5,  5,
+    2,  2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  2,  2,  2,
+    2,  2,  2,  2,  2,  5,  2,  2,  2,  2,  5,  5,  2,  5,  5,  5,
+    5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2, 11,
+   11, 11,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,
+   11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2, 11,  2, 11, 11, 11,  2,  2, 11, 11, 11,  2,  2,  2, 11,
+    2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,  2, 11,  2,  2,  2,
+    2,  2,  2,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,  2, 10,
+   10, 10,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
+    2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,
+   10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,  2,  2, 10,  2,
+    2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10,
+    2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10, 10, 10, 10,  2, 21,
+   21, 21,  2, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,
+    2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+   21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21, 21, 21, 21, 21,
+    2,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21,  2,  2,  2,  2,
+    2,  2,  2,  2, 21, 21,  2,  2,  2,  2, 21, 21,  2, 21, 21, 21,
+   21, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22,
+   22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2, 22, 22, 22,  2,
+    2,  2,  2,  2,  2, 22,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
+   22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23,
+    2,  2,  2, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
+    2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2,  2,  2,  2, 23, 23,
+   23, 23,  2,  2, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16,
+    2,  2, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16,  2,  2,  2,  2,
+    2,  2,  2, 16, 16,  2,  2,  2,  2,  2,  2,  2, 16,  2, 16, 16,
+   16, 16,  2,  2, 16, 16,  2, 16, 16,  2,  2,  2,  2,  2, 20, 20,
+   20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2,
+    2,  2, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 20, 20,  2,  2,
+   36, 36,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36, 36,
+    2, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2, 36,  2,  2,  2,  2,
+   36,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36,  2, 36,  2,  2,  2,
+    2,  2,  2,  2, 36, 36,  2,  2, 36, 36, 36,  2,  2,  2,  2, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24,  2,  2,  2,  2,  0, 24, 24, 24, 24,  2,  2,  2,  2,  2, 18,
+   18,  2, 18,  2, 18, 18, 18, 18, 18,  2, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,
+   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18,
+    2,  2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25,  2, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,  2,  2,  2, 25, 25,
+   25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25,  0,  0,  0,  0, 25,
+   25,  2,  2,  2,  2,  2, 33, 33, 33, 33, 33, 33, 33, 33,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  2,  8,  2,  2,
+    2,  2,  2,  8,  2,  2,  8,  8,  8,  0,  8,  8,  8,  8, 12, 12,
+   12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30,  2,
+   30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
+   30,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30,  2,  2,  2, 30, 30,
+    2,  2,  2,  2,  2,  2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+   29, 29, 29, 29,  2,  2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,  2,  2,  2, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35,  0,  0,  0, 35, 35, 35,  2,
+    2,  2,  2,  2,  2,  2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+   45, 45, 45,  2, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,  0,  0,  2, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 43, 43, 43,  2,  2,  2,  2, 46, 46,
+   46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,  2, 46, 46, 46,  2,
+   46, 46,  2,  2,  2,  2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31,  2,  2, 31, 31,  2,  2,  2,  2,  2,  2, 32, 32,
+    0,  0, 32,  0, 32, 32, 32, 32, 32, 32, 32, 32, 32,  2, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32,  2,  2,  2,  2,  2,  2, 32,  2,
+    2,  2,  2,  2,  2,  2, 32, 32, 32,  2,  2,  2,  2,  2, 28, 28,
+   28, 28, 28, 28,  2,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48,  2, 48, 48, 48, 48,  2,  2,  2,  2, 48,  2,
+    2,  2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+   52, 52, 52, 52,  2,  2, 52, 52, 52, 52, 52,  2,  2,  2, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 58, 58, 58,  2,  2,  2,  2, 58, 58,
+    2,  2,  2,  2,  2,  2, 58, 58, 58,  2,  2,  2, 58, 58, 54, 54,
+   54, 54, 54, 54, 54, 54, 54, 54, 54, 54,  2,  2, 54, 54, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,  2, 91, 91,
+   91, 91, 91,  2,  2, 91, 91, 91,  2,  2,  2,  2,  2,  2, 91, 91,
+   91, 91, 91, 91,  2,  2,  1,  1,  1,  1,  1,  1,  1,  2, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62,  2,  2,  2,  2, 62, 62,
+   62, 62, 62,  2,  2,  2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93,
+   93, 93, 93, 93, 93, 93, 93, 93, 93, 93,  2,  2,  2,  2,  2,  2,
+    2,  2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70,  2,  2,
+    2, 70, 70, 70, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 73, 73,
+   73, 73, 73, 73, 73, 73,  6,  2,  2,  2,  2,  2,  2,  2,  8,  8,
+    8,  2,  2,  8,  8,  8,  1,  1,  1,  0,  1,  1,  1,  1,  1,  0,
+    1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    0,  0,  1,  0,  0,  0,  1,  1,  0,  2,  2,  2,  2,  2, 19, 19,
+   19, 19, 19, 19,  9,  9,  9,  9,  9,  6, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19,  9,  9,  9,  9,
+    9, 19, 19, 19, 19, 19,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  9,  1,  1,  2,  1,  1,  1,  1,  1,  9,  9,
+    9,  9,  9,  9,  2,  2,  2,  9,  2,  9,  2,  9,  2,  9,  9,  9,
+    9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,
+    9,  9,  2,  9,  9,  9,  2,  2,  9,  9,  9,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  1,  1,  0,  0,  0,  0,
+    0,  0,  0,  2,  0,  0,  0, 19,  2,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0,  2, 19, 19,
+   19, 19, 19,  2,  2,  2,  1,  2,  2,  2,  2,  2,  2,  2,  0,  0,
+    0,  0,  0,  0,  9,  0,  0,  0, 19, 19,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 19,  0, 19,  0,  0,  0,  2,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27, 27,  0,  0,
+    0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2, 55, 55,
+   55, 55,  2,  2,  2,  2,  2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
+   61, 61, 61, 61, 61, 61,  2,  2,  2,  2,  2,  2,  2, 61, 61,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 13, 13,
+   13, 13, 13, 13,  2,  2,  0,  0,  0,  0,  2,  2,  2,  2,  0,  0,
+    0,  0,  0, 13,  0, 13,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    1,  1,  1,  1, 12, 12, 13, 13, 13, 13,  0,  0,  0,  0,  2, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15,  2,  2,  1,  1,  0,  0, 15, 15, 15,  0, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17,  0,  0, 17, 17, 17,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12,  2, 26, 26, 26,  2,  2,  2,  2,  2, 12, 12,
+   12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17, 17,  0, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39,
+   39, 39, 39, 39, 39,  2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77, 77, 77,  2,  2,  2,  2, 79, 79,
+   79, 79, 79, 79, 79, 79,  0,  0, 19, 19, 19, 19, 19, 19,  0,  0,
+    0, 19, 19, 19, 19, 19,  2,  2, 19, 19, 19, 19, 19,  2,  2,  2,
+    2,  2,  2,  2,  2, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60,  2,  2,  2,  2,  0,  0,  2,  2,  2,  2,  2,  2, 65, 65,
+   65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75,  2,  2,  2,  2,  2,  2,  2,  2, 75, 75, 75, 75,
+    2,  2,  2,  2,  2,  2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+   74, 74,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 74, 12, 12,
+   12, 12, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84,  2,  0, 84, 84,  2,  2,  2,  2, 84, 84, 33, 33,
+   33, 33, 33, 33, 33,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   68, 68, 68, 68, 68,  2, 68, 68, 68, 68, 68, 68,  2,  2, 68, 68,
+    2,  2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+   92,  2,  2,  2,  2,  2,  2,  2,  2, 92, 92, 92, 92, 92, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,  2,  2, 30,
+   30, 30, 30, 30, 30,  2, 19, 19, 19,  0, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  9, 19, 19, 87, 87, 87, 87, 87, 87,  2,  2, 87, 87,
+    2,  2,  2,  2,  2,  2, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,
+    2, 12, 12, 12, 12, 12, 13, 13,  2,  2,  2,  2,  2,  2, 19, 19,
+   19, 19, 19, 19, 19,  2,  2,  2,  2,  4,  4,  4,  4,  4,  2,  2,
+    2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2, 14, 14,
+   14, 14, 14,  2, 14,  2, 14, 14,  2, 14, 14,  2, 14, 14,  3,  3,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,
+    3,  3,  3,  3,  3,  3,  1,  1,  1,  1,  1,  1,  6,  6,  0,  0,
+    0,  2,  0,  0,  0,  0,  3,  3,  3,  3,  3,  2,  2,  0,  2,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 17, 17, 17,
+   17, 17, 17, 17,  0,  0,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   12, 12, 12,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49,  2, 49, 49, 49,  2, 49, 49,  2, 49, 49, 49,
+   49, 49, 49, 49,  2,  2, 49, 49, 49,  2,  2,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  2,  2,  2,  0,  9,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  1,  2,  2, 71, 71,
+   71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67,
+   67, 67, 67, 67, 67, 67, 67,  2,  2,  2,  2,  2,  2,  2,  1,  0,
+    0,  0,  0,  0,  0,  0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+   42, 42,  2,  2,  2,  2,  2,  2,  2,  2,  2, 42, 42, 42, 41, 41,
+   41, 41, 41, 41, 41, 41, 41, 41, 41,  2,  2,  2,  2,  2,118,118,
+  118,118,118,118,118,118,118,118,118,  2,  2,  2,  2,  2, 53, 53,
+   53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,  2, 53, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2, 59, 59,
+   59, 59, 59, 59,  2,  2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51,
+   51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+   50, 50, 50, 50,  2,  2, 50, 50,  2,  2,  2,  2,  2,  2,135,135,
+  135,135,135,135,135,135,135,135,135,135,  2,  2,  2,  2,106,106,
+  106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,
+  104,104,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,104,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
+  110,110,110,110,  2,  2, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,  2, 47, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,  2, 81,120,120,
+  120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,  2,116,128,128,
+  128,128,128,128,128,128,128,128,128,  2,128,128,  2,  2,  2,  2,
+    2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+    2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+   97, 97, 97, 97, 97, 97,  2,  2,  2,  2, 97, 97, 97, 97,  2,  2,
+   97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57, 57,  2,  2,  2,
+    2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57, 57, 57,  2, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57, 57, 57,  2,  2, 57, 57, 57,  2,  2,  2,  2, 57, 57,  2,
+    2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
+  117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+  112,112,112,112,112,  2,  2,  2,  2,112,112,112,112,112, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,  2,  2,  2, 78,
+   78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+   83, 83, 83, 83,  2,  2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+   82,  2,  2,  2,  2,  2,122,122,122,122,122,122,122,122,122,122,
+    2,  2,  2,  2,  2,  2,  2,122,122,122,122,  2,  2,  2,  2,122,
+  122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,130,130,130,130,
+  130,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,130,130,144,144,
+  144,144,144,144,144,144,144,144,  2,  2,  2,  2,  2,  2,  3,  3,
+    3,  3,  3,  3,  3,  2,147,147,147,147,147,147,147,147,148,148,
+  148,148,148,148,148,148,148,148,  2,  2,  2,  2,  2,  2,149,149,
+  149,149,149,149,149,149,149,149,149,149,149,149,149,  2, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,  2,  2,  2,  2,
+   94, 94, 94, 94, 94, 94,  2,  2,  2,  2,  2,  2,  2, 94, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 85,  2,  2,101,101,101,101,101,101,101,101,101,  2,
+    2,  2,  2,  2,  2,  2,101,101,  2,  2,  2,  2,  2,  2, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2, 96, 96, 96, 96,
+   96, 96, 96, 96, 96,  2,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,  2,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36,  2,  2,  2,108,108,108,108,108,108,108,108,108,108,
+    2,108,108,108,108,108,108,108,108,108,108,108,108,  2,129,129,
+  129,129,129,129,129,  2,129,  2,129,129,129,129,  2,129,129,129,
+  129,129,129,129,129,129,129,129,129,129,129,129,  2,129,129,129,
+    2,  2,  2,  2,  2,  2,109,109,109,109,109,109,109,109,109,109,
+  109,  2,  2,  2,  2,  2,109,109,  2,  2,  2,  2,  2,  2,107,107,
+  107,107,  2,107,107,107,107,107,107,107,107,  2,  2,107,107,  2,
+    2,107,107,107,107,107,107,107,107,107,107,107,107,107,107,  2,
+  107,107,107,107,107,107,107,  2,107,107,  2,107,107,107,107,107,
+    2,  1,107,107,107,107,107,  2,  2,107,107,107,  2,  2,107,  2,
+    2,  2,  2,  2,  2,107,  2,  2,  2,  2,  2,107,107,107,107,107,
+  107,107,  2,  2,107,107,107,107,107,107,107,  2,  2,  2,137,137,
+  137,137,137,137,137,137,137,137,  2,137,  2,137,137,137,124,124,
+  124,124,124,124,124,124,124,124,  2,  2,  2,  2,  2,  2,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,  2,  2,114,114,
+  114,114,114,114,114,114,114,114,114,114,114,  2,  2,  2,114,114,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32,  2,  2,  2,102,102,
+  102,102,102,102,102,102,102,  2,  2,  2,  2,  2,  2,  2,102,102,
+    2,  2,  2,  2,  2,  2,126,126,126,126,126,126,126,126,126,126,
+  126,  2,  2,126,126,126,126,126,126,126,  2,  2,  2,  2,142,142,
+  142,142,142,142,142,142,142,142,142,142,  2,  2,  2,  2,125,125,
+  125,125,125,125,125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,125,150,150,150,150,150,150,150,150,  2,  2,
+  150,150,150,150,150,150,150,150,150,150,150,  2,  2,  2,141,141,
+  141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140,
+  140,  2,  2,  2,  2,  2,121,121,121,121,121,121,121,121,121,  2,
+    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,  2,
+  133,133,133,133,133,133,133,133,133,133,133,133,133,  2,133,133,
+  133,133,133,133,  2,  2,133,133,133,133,133,  2,  2,  2,134,134,
+  134,134,134,134,134,134,  2,  2,134,134,134,134,134,134,  2,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,134,  2,138,138,
+  138,138,138,138,138,  2,138,138,  2,138,138,138,138,138,138,138,
+  138,138,138,138,138,138,  2,  2,138,  2,138,138,  2,138,138,138,
+    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,  2,143,143,  2,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,  2,143,143,  2,143,143,143,143,143,143,  2,
+    2,  2,  2,  2,  2,  2,143,143,  2,  2,  2,  2,  2,  2,145,145,
+  145,145,145,145,145,145,145,  2,  2,  2,  2,  2,  2,  2, 22, 22,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 63, 63,
+   63, 63, 63, 63, 63, 63, 63, 63,  2,  2,  2,  2,  2,  2, 63, 63,
+   63, 63, 63, 63, 63,  2, 63, 63, 63, 63, 63,  2,  2,  2, 63, 63,
+   63, 63,  2,  2,  2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+   80, 80, 80, 80, 80,  2, 80,  2,  2,  2,  2,  2,  2,  2,127,127,
+  127,127,127,127,127,127,127,127,127,127,127,127,127,  2, 79,  2,
+    2,  2,  2,  2,  2,  2,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,  2,115,115,  2,  2,  2,  2,115,115,103,103,
+  103,103,103,103,103,103,103,103,103,103,103,103,  2,  2,119,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,119,119,
+    2,119,119,119,119,119,  2,  2,  2,  2,  2,119,119,119,146,146,
+  146,146,146,146,146,146,146,146,146,  2,  2,  2,  2,  2, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99,  2,  2,  2,  2, 99,  2,  2,
+    2,  2,  2,  2,  2, 99,136,139,  0,  0,  2,  2,  2,  2,136,136,
+  136,136,136,136,136,136,136,136,136,  2,  2,  2,  2,  2, 17, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
+    2,  2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139,
+  139,139,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
+  105,  2,  2,  2,  2,  2,105,105,105,105,105,  2,  2,  2,105,  2,
+    2,  2,  2,  2,  2,  2,105,105,  2,  2,105,105,105,105,  0,  0,
+    0,  0,  0,  0,  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,
+    1,  1,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  0,  0,  0,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  0,  2,  2,  0,  0,  2,  2,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  2,  0,  2,  0,  0,  0,  0,  0,
+    0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+    0,  2,  2,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  2,  0,  0,
+    0,  0,  0,  2,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,
+    0,  0,  0,  0,  0,  0,131,131,131,131,131,131,131,131,131,131,
+  131,131,  2,  2,  2,  2,  2,  2,  2,131,131,131,131,131,  2,131,
+  131,131,131,131,131,131, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,
+    2, 56, 56,  2, 56, 56, 56, 56, 56,  2,  2,  2,  2,  2,151,151,
+  151,151,151,151,151,151,151,151,151,151,151,  2,  2,  2,151,151,
+  151,151,151,151,  2,  2,151,151,  2,  2,  2,  2,151,151,152,152,
+  152,152,152,152,152,152,152,152,  2,  2,  2,  2,  2,152,113,113,
+  113,113,113,113,113,113,113,113,113,113,113,  2,  2,113,113,113,
+  113,113,113,113,113,  2,132,132,132,132,132,132,132,132,132,132,
+  132,132,  2,  2,  2,  2,132,132,  2,  2,  2,  2,132,132,  0,  0,
+    0,  0,  0,  2,  2,  2,  3,  3,  3,  3,  2,  3,  3,  3,  2,  3,
+    3,  2,  3,  2,  2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  2,  2,  2,  2,  2,  2,
+    3,  2,  2,  2,  2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  2,  3,
+    2,  3,  2,  3,  2,  3,  2,  3,  3,  3,  3,  2,  3,  2,  3,  3,
+    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  3,
+    3,  3,  2,  3,  3,  3,  2,  2,  2,  2,  2,  2,  0,  0, 15,  0,
+    0,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  0,  0, 13, 13,
+   13, 13, 13, 13, 13,  2, 13, 13, 13, 13, 13,  2,  2,  2, 13,  2,
+    2,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2, 16, 50,
+   84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91, 85, 85,
+  220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,
+    7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18, 19, 20,
+   21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0, 31, 32,
+    0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,  0,  0,
+    0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,  0,  0,
+    0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,  0,  0,
+    0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,  0,  0,
+   66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67, 68,
+    0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 71, 72,
+   73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+   89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,108,  0,
+  109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,  0,  0,
+  116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,118,119,120,121,  0,122,123,124,125,126,  0,127,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,129,
+  130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
+  146,147,148,149,150,151,152,153,154,155,156,157,  0,  0,  0,158,
+  159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,  0,  0,
+  164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,168,169,  0,  0,  0,  0,170,171,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,172,173,
+  174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,
+  190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,
+    0,  0,  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,  2,  3,  4,
+};
+static const uint16_t
+_hb_ucd_u16[8944] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
+    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
+    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
+    48,  67,  68,  69,  48,  70,  71,  72,  72,  72,  48,  73,  72,  74,  75,  32,
+    76,  48,  48,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+    90,  83,  84,  91,  92,  93,  94,  95,  96,  97,  84,  98,  99, 100,  88, 101,
+   102,  83,  84, 103, 104, 105,  88, 106, 107, 108, 109, 110, 111, 112,  94, 113,
+   114, 115,  84, 116, 117, 118,  88, 119, 120, 115,  84, 121, 122, 123,  88, 124,
+   125, 115,  48, 126, 127, 128,  88, 129, 130, 131,  48, 132, 133, 134,  94, 135,
+   136,  48,  48, 137, 138, 139,  72,  72, 140,  48, 141, 142, 143, 144,  72,  72,
+   145, 146, 147, 148, 149,  48, 150, 151, 152, 153,  32, 154, 155, 156,  72,  72,
+    48,  48, 157, 158, 159, 160, 161, 162, 163, 164,   9,   9, 165,  11,  11, 166,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 167, 168,  48,  48,
+   167,  48,  48, 169, 170, 171,  48,  48,  48, 170,  48,  48,  48, 172, 173, 174,
+    48, 175,   9,   9,   9,   9,   9, 176, 177,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 178,  48, 179, 180,  48,  48,  48,  48, 181, 182,
+   183, 184,  48, 185,  48, 186, 183, 187,  48,  48,  48, 188, 189, 190, 191, 192,
+   193, 191,  48,  48, 194,  48,  48, 195, 196,  48, 197,  48,  48,  48,  48, 198,
+    48, 199, 200, 201, 202,  48, 203, 204,  48,  48, 205,  48, 206, 207, 208, 208,
+    48, 209,  48,  48,  48, 210, 211, 212, 191, 191, 213, 214,  72,  72,  72,  72,
+   215,  48,  48, 216, 217, 159, 218, 219, 220,  48, 221,  64,  48,  48, 222, 223,
+    48,  48, 224, 225, 226,  64,  48, 227, 228,   9,   9, 229, 230, 231, 232, 233,
+    11,  11, 234,  27,  27,  27, 235, 236,  11, 237,  27,  27,  32,  32,  32, 238,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 239,  13,  13,  13,  13,  13,  13,
+   240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249,
+   250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260,  72, 261, 262, 263,
+   264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276,
+   277, 277, 277, 277, 277, 277, 277, 277, 278, 208, 279, 208, 208, 208, 208, 280,
+   208, 281, 277, 282, 208, 283, 284, 208, 208, 208, 285,  72, 286,  72, 269, 269,
+   269, 287, 208, 208, 208, 208, 288, 269, 208, 208, 208, 208, 208, 208, 208, 208,
+   208, 208, 208, 289, 290, 208, 208, 291, 208, 208, 208, 208, 208, 208, 292, 208,
+   208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277,
+   298, 299, 277, 277, 277, 300, 277, 301, 208, 208, 208, 277, 302, 208, 208, 303,
+   208, 304, 208, 208, 208, 208, 208, 208,   9,   9, 305,  11,  11, 306, 307, 308,
+    13,  13,  13,  13,  13,  13, 309, 310,  11,  11, 311,  48,  48,  48, 312, 313,
+    48, 314, 315, 315, 315, 315,  32,  32, 316, 317, 318, 319, 320,  72,  72,  72,
+   208, 321, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 323,  72, 324,
+   325, 326, 327, 328, 136,  48,  48,  48,  48, 329, 177,  48,  48,  48,  48, 330,
+   331,  48,  48, 136,  48,  48,  48,  48, 199, 332,  48,  71, 208, 208, 322,  48,
+   208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208,
+    48,  48,  48, 198, 208, 208, 208, 208,  48,  48,  48,  48,  48,  48,  48,  72,
+    48, 337,  48,  48,  48,  48,  48,  48, 150, 208, 208, 208, 285,  48,  48, 227,
+   338,  48, 339,  72,  13,  13, 340, 341,  13, 342,  48,  48,  48,  48, 343, 344,
+    31, 345, 346, 347,  13,  13,  13, 348, 349, 350, 351, 352, 353,  72,  72, 354,
+   355,  48, 356, 357,  48,  48,  48, 358, 359,  48,  48, 360, 361, 191,  32, 362,
+    64,  48, 363,  48, 364, 365,  48, 150,  76,  48,  48, 366, 367, 368, 369, 370,
+    48,  48, 371, 372, 373, 374,  48, 375,  48,  48,  48, 376, 377, 378, 379, 380,
+   381, 382, 315,  11,  11, 383, 384,  11,  11,  11,  11,  11,  48,  48, 385, 191,
+    48,  48, 386,  48, 387,  48,  48, 205, 388, 388, 388, 388, 388, 388, 388, 388,
+   389, 389, 389, 389, 389, 389, 389, 389,  48,  48,  48,  48,  48,  48, 203,  48,
+    48,  48,  48,  48,  48, 206,  72,  72, 390, 391, 392, 393, 394,  48,  48,  48,
+    48,  48,  48, 395, 396, 397,  48,  48,  48,  48,  48, 398,  72,  48,  48,  48,
+    48, 399,  48,  48, 400,  72,  72, 401,  32, 402,  32, 403, 404, 405, 406, 407,
+    48,  48,  48,  48,  48,  48,  48, 408, 409,   2,   3,   4,   5, 410, 411, 412,
+    48, 413,  48, 199, 414, 415, 416, 417, 418,  48, 171, 419, 203, 203,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  71, 420, 269, 269, 421, 270, 270, 270, 422,
+   423, 324, 424,  72,  72, 208, 208, 425,  72,  72,  72,  72,  72,  72,  72,  72,
+    48, 150,  48,  48,  48, 100, 426, 427,  48,  48, 428,  48, 429,  48,  48, 430,
+    48, 431,  48,  48, 432, 433,  72,  72,   9,   9, 434,  11,  11,  48,  48,  48,
+    48, 203, 191,   9,   9, 435,  11, 436,  48,  48, 400,  48,  48,  48, 437,  72,
+    48,  48,  48, 314,  48, 198, 400,  72, 438,  48,  48, 439,  48, 440,  48, 441,
+    48, 199, 442,  72,  72,  72,  48, 443,  48, 444,  48, 445,  72,  72,  72,  72,
+    48,  48,  48, 446, 269, 447, 269, 269, 448, 449,  48, 450, 451, 452,  48, 453,
+    48, 454,  72,  72, 455,  48, 456, 457,  48,  48,  48, 458,  48, 459,  48, 460,
+    48, 461, 462,  72,  72,  72,  72,  72,  48,  48,  48,  48, 195,  72,  72,  72,
+     9,   9,   9, 463,  11,  11,  11, 464,  48,  48, 465, 191,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72, 269, 466,  48, 454, 467,  48,  62, 468,  72,  72,
+    72,  72,  72,  72,  72,  72,  48, 314, 469,  48,  48, 470, 471, 447, 472, 473,
+   220,  48,  48, 474, 475,  48, 195, 191, 476,  48, 477, 478, 479,  48,  48, 480,
+   220,  48,  48, 481, 482, 483, 484, 485,  48,  97, 486, 487,  72,  72,  72,  72,
+   488, 489, 490,  48,  48, 491, 492, 191, 493,  83,  84, 494, 495, 496, 497, 498,
+    48,  48,  48, 499, 500, 501,  72,  72,  48,  48,  48, 502, 503, 191,  72,  72,
+    48,  48, 504, 505, 506, 507,  72,  72,  48,  48,  48, 508, 509, 191, 510,  72,
+    48,  48, 511, 512, 191,  72,  72,  72,  48, 172, 513, 514,  72,  72,  72,  72,
+    48,  48, 486, 515,  72,  72,  72,  72,  72,  72,   9,   9,  11,  11, 147, 516,
+    72,  72, 517,  48,  48, 518, 519,  72, 520,  48,  48, 521, 522, 523,  48,  48,
+   524, 525, 526,  72,  48,  48,  48, 195,  84,  48, 504, 527, 528, 147, 174, 529,
+    48, 530, 531, 532,  72,  72,  72,  72, 533,  48,  48, 534, 535, 191, 536,  48,
+   537, 538, 191,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 539,
+    72,  72,  72,  72, 269, 540, 541, 542,  48, 206,  72,  72,  72,  72,  72,  72,
+   270, 270, 270, 270, 270, 270, 543, 544,  48,  48,  48,  48, 386,  72,  72,  72,
+    48,  48, 199, 545,  72,  72,  72,  72,  48,  48,  48,  48, 314,  72,  72,  72,
+    48,  48,  48, 195,  48, 199, 368,  72,  72,  72,  72,  72,  72,  48, 203, 546,
+    48,  48,  48, 547, 548, 549, 550, 551,  48,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,   9,   9,  11,  11, 269, 552,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 553, 554, 555, 555, 556, 557,  72,  72,  72,  72, 558,  72,
+    48,  48,  48,  48,  48,  48,  48, 400,  48,  48,  48,  48,  48,  48,  48, 559,
+    48, 199,  72,  72,  72, 559, 560,  48,  48,  48,  48,  48,  48,  48,  48, 205,
+    48,  48,  48,  48,  48,  48,  71, 150, 195, 561, 562,  72,  72,  72,  72,  72,
+   208, 208, 208, 208, 208, 208, 208, 323, 208, 208, 563, 208, 208, 208, 564, 565,
+   566, 208, 567, 208, 208, 208, 568,  72, 208, 208, 208, 208, 569,  72,  72,  72,
+    72,  72,  72,  72,  72,  72, 269, 570, 208, 208, 208, 208, 208, 285, 269, 451,
+     9, 571,  11, 572, 573, 574, 240,   9, 575, 576, 577, 578, 579,   9, 571,  11,
+   580, 581,  11, 582, 583, 584, 585,   9, 586,  11,   9, 571,  11, 572, 573,  11,
+   240,   9, 575, 585,   9, 586,  11,   9, 571,  11, 587,   9, 588, 589, 590, 591,
+    11, 592,   9, 593, 594, 595, 596,  11, 597,   9, 598,  11, 599, 600, 600, 600,
+    32,  32,  32, 601,  32,  32, 602, 603, 604, 605,  45,  72,  72,  72,  72,  72,
+   606, 607, 608,  72,  72,  72,  72,  72,  48,  48, 150, 609, 610,  72,  72,  72,
+    72,  72,  72,  72,  48,  48, 611, 612,  48,  48,  48,  48, 613, 614,  72,  72,
+     9,   9, 575,  11, 615, 368,  72,  72,  72,  72,  72,  72,  72,  72,  72, 484,
+   269, 269, 616, 617,  72,  72,  72,  72, 484, 269, 618, 619,  72,  72,  72,  72,
+   620,  48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205,  72,  72,  72, 629,
+   208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323,
+   174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631,  72,  72,  72, 632, 208,
+   633, 208, 208, 324, 568, 634, 323,  72, 208, 208, 208, 208, 208, 208, 208, 635,
+   208, 208, 208, 208, 208, 323, 631, 286, 208, 208, 208, 208, 208, 208, 208, 322,
+   208, 208, 208, 208, 208, 568, 324,  72, 324, 208, 208, 208, 636, 175, 208, 208,
+   636, 208, 637,  72,  72,  72,  72,  72, 638, 208, 208, 208, 208, 208, 208, 639,
+   208, 208, 640, 208, 641, 208, 208, 208, 208, 208, 208, 208, 208, 322, 637, 642,
+   633, 323,  72,  72,  72,  72,  72,  72,  48,  48,  48,  48,  48, 314,  72,  72,
+    48,  48,  48, 204,  48,  48,  48,  48,  48, 203,  48,  48,  48,  48,  48,  48,
+    48,  48, 643,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 100,  72,
+    48, 203,  72,  72,  72,  72,  72,  72, 644,  72, 645, 645, 645, 645, 645, 645,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  72,
+   389, 389, 389, 389, 389, 389, 389, 646, 389, 389, 389, 389, 389, 389, 389, 647,
+     0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3,
+     0,   0,   0,   0,   0,   4,   0,   4,   2,   2,   5,   2,   2,   2,   5,   2,
+     2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     2,   2,   2,   2,   2,   2,   2,   6,   0,   0,   0,   0,   7,   8,   0,   0,
+     9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,  10,  11,
+    12,  13,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,  16,  17,  14,  14,
+    18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,
+    19,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18,  18,  18,  20,  21,  21,  21,  22,  20,  21,  21,  21,  21,
+    21,  23,  24,  25,  25,  25,  25,  25,  25,  26,  25,  25,  25,  27,  28,  26,
+    29,  30,  31,  32,  31,  31,  31,  31,  33,  34,  35,  31,  31,  31,  36,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  29,  31,  31,  31,  31,
+    37,  38,  37,  37,  37,  37,  37,  37,  37,  39,  31,  31,  31,  31,  31,  31,
+    40,  40,  40,  40,  40,  40,  41,  26,  42,  42,  42,  42,  42,  42,  42,  43,
+    44,  44,  44,  44,  44,  45,  44,  46,  47,  47,  47,  48,  37,  49,  26,  26,
+    26,  26,  26,  26,  31,  31,  50,  51,  26,  26,  52,  31,  53,  31,  31,  31,
+    54,  54,  54,  54,  54,  54,  54,  54,  54,  54,  55,  54,  56,  54,  54,  54,
+    57,  58,  59,  60,  60,  61,  62,  63,  58,  64,  65,  66,  67,  60,  60,  68,
+    69,  70,  71,  72,  72,  73,  74,  75,  70,  76,  77,  78,  79,  72,  80,  26,
+    81,  82,  83,  84,  84,  85,  86,  87,  82,  88,  89,  26,  90,  84,  91,  92,
+    93,  94,  95,  96,  96,  97,  98,  99,  94, 100, 101, 102, 103,  96,  96,  26,
+   104, 105, 106, 107, 108, 105, 109, 110, 105, 106, 111,  26, 112, 109, 109, 113,
+   114, 115, 116, 114, 114, 116, 114, 117, 115, 118, 119, 120, 121, 114, 122, 114,
+   123, 124, 125, 123, 123, 125, 126, 127, 124, 128, 129, 130, 131, 123, 132,  26,
+   133, 134, 135, 136, 136, 136, 136, 136, 134, 135, 137, 136, 138, 136, 136, 136,
+   139, 140, 141, 142, 140, 140, 143, 144, 141, 145, 146, 140, 147, 140, 148,  26,
+   149, 150, 150, 150, 150, 150, 150, 151, 150, 150, 150, 152,  26,  26,  26,  26,
+   153, 154, 155, 155, 156, 155, 155, 157, 158, 157, 155, 159,  26,  26,  26,  26,
+   160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160, 162, 161, 160,
+   160, 160, 160, 161, 160, 160, 160, 163, 160, 163, 164, 165,  26,  26,  26,  26,
+   166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166,
+   166, 166, 166, 166, 167, 167, 167, 167, 168, 169, 167, 167, 167, 167, 167, 170,
+   171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+   172, 172, 172, 172, 172, 172, 172, 172, 172, 173, 174, 173, 172, 172, 172, 172,
+   172, 173, 172, 172, 172, 172, 173, 174, 173, 172, 174, 172, 172, 172, 172, 172,
+   172, 172, 173, 172, 172, 172, 172, 172, 172, 172, 172, 175, 172, 172, 172, 176,
+   172, 172, 172, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179,
+   180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180,
+   181, 181, 181, 182, 183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 183, 185,
+   186, 187, 188,  26, 189, 189, 190,  26, 191, 191, 192,  26, 193, 194, 195,  26,
+   196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 197, 196, 198, 196, 198,
+   199, 200, 201, 202, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 203,
+   201, 201, 201, 201, 201, 204, 180, 180, 180, 180, 180, 180, 180, 180, 205,  26,
+   206, 206, 206, 207, 206, 208, 206, 208, 209, 206, 210, 210, 210, 211, 212,  26,
+   213, 213, 213, 213, 213, 214, 213, 213, 213, 215, 213, 216, 196, 196, 196, 196,
+   217, 217, 217, 218, 219, 219, 219, 219, 219, 219, 219, 220, 219, 219, 219, 221,
+   219, 222, 219, 222, 219, 223,   9, 224,  26,  26,  26,  26,  26,  26,  26,  26,
+   225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 225, 225, 225, 225, 225, 227,
+   228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 230, 231,
+   232, 232, 232, 232, 232, 232, 232, 233, 232, 234, 235, 235, 235, 235, 235, 235,
+    18, 236, 167, 167, 167, 167, 167, 237, 228,  26, 238,   9, 239, 240, 241, 242,
+     2,   2,   2,   2, 243, 244,   2,   2,   2,   2,   2, 245, 246, 247,   2, 248,
+     2,   2,   2,   2,   2,   2,   2, 249,   9,   9,   9,   9,   9,   9,   9, 250,
+    14,  14, 251, 251,  14,  14,  14,  14, 251, 251,  14, 252,  14,  14,  14, 251,
+    14,  14,  14,  14,  14,  14, 253,  14, 253,  14, 254, 255,  14,  14, 256, 257,
+     0, 258,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 259,   0, 260, 261,
+     0, 262,   2, 263,   0,   0,   0,   0,  26,  26,   9,   9,   9,   9, 264,  26,
+     0,   0,   0,   0, 265, 266,   4,   0,   0, 267,   0,   0,   2,   2,   2,   2,
+     2, 268,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 262,  26,  26,  26,   0, 269,  26,  26,   0,   0,   0,   0,
+   270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 271,   0,
+     0,   0, 272,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   273, 273, 273, 273, 273, 274, 273, 273, 273, 273, 273, 274,   2,   2,   2,   2,
+    17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17, 275, 276,
+   167, 167, 167, 167, 168, 169, 277, 277, 277, 277, 277, 277, 277, 278, 279, 278,
+   172, 172, 174,  26, 174, 174, 174, 174, 174, 174, 174, 174,  18,  18,  18,  18,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  26,  26,  26,  26,  26,  26,
+   280, 280, 280, 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 282,  26,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283,  26,  26,  26,   0, 284,
+   285,   0,   0,   0, 286, 287,   0, 288, 289, 290, 290, 290, 290, 290, 290, 290,
+   290, 290, 291, 292, 293, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 295,
+   296, 297, 297, 297, 297, 297, 298, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+   171, 299,   0,   0, 297, 297, 297, 300,   0,   0,   0,   0, 284,  26, 294, 294,
+   171, 171, 171, 299,   0,   0,   0,   0,   0,   0,   0,   0, 171, 171, 171, 301,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 294, 294, 294, 294, 294, 302,
+   294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294,   0,   0,   0,   0,   0,
+   280, 280, 280, 280, 280, 280, 283,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,  26,  26,
+   303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303,
+   303, 304, 303, 303, 303, 303, 303, 303, 305,  26, 306, 306, 306, 306, 306, 306,
+   307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307,
+   307, 307, 307, 307, 307, 308,  26,  26,  18,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309,  26,
+     0,   0,   0,   0, 310,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     2, 311,   2,   2,   2,   2,   2,   2, 312,  26,  26,  26,  26,  26, 313,   2,
+   314, 314, 314, 314, 314, 315,   0, 316, 317, 317, 317, 317, 317, 317, 317,  26,
+   318, 318, 318, 318, 318, 318, 318, 318, 319, 320, 318, 321,  54,  54,  54,  54,
+   322, 322, 322, 322, 322, 323, 324, 324, 324, 324, 325, 326, 171, 171, 171, 327,
+   328, 328, 328, 328, 328, 328, 328, 328, 328, 329, 328, 330, 166, 166, 166, 331,
+   332, 332, 332, 332, 332, 332, 333,  26, 332, 334, 332, 335, 166, 166, 166, 166,
+   336, 336, 336, 336, 336, 336, 336, 336, 337,  26,  26, 338, 339, 339, 340,  26,
+   341, 341, 341,  26, 174, 174,   2,   2,   2,   2,   2, 342, 343,  26, 178, 178,
+   178, 178, 178, 178, 178, 178, 178, 178, 339, 339, 339, 339, 339, 344, 339, 345,
+   171, 171, 171, 171, 346,  26, 171, 171, 299, 347, 171, 171, 171, 171, 171, 346,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283, 280, 280,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 348,  26,  26,  26,  26,
+   349,  26, 350, 351,  25,  25, 352, 353, 354,  25,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31,  31, 355,  26,  52,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31, 356,  26,  26,  31,  31,  31,  31,  31,  31,
+    31,  31, 357,  31,  31,  31,  31,  31,  31,  26,  26,  26,  26,  26,  31,  51,
+     9,   9,   0, 316,   9, 358,   0,   0,   0,   0, 359,   0, 262, 284,  50,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 360,
+   361,   0,   0,   0,   1,   2,   2,   3,   1,   2,   2,   3, 362, 294, 293, 294,
+   294, 294, 294, 363, 171, 171, 171, 299, 364, 364, 364, 365, 262, 262,  26, 366,
+   367, 368, 367, 367, 369, 367, 367, 370, 367, 371, 367, 371,  26,  26,  26,  26,
+   367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 372,
+   373,   0,   0,   0,   0,   0, 374,   0,  14,  14,  14,  14,  14,  14,  14,  14,
+    14, 257,   0, 284, 375,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0, 376,
+   377, 377, 377, 378, 379, 379, 379, 379, 379, 379, 380,  26, 381,   0,   0, 284,
+   382, 382, 382, 382, 383, 384, 385, 385, 385, 386, 387, 387, 387, 387, 387, 388,
+   389, 389, 389, 390, 391, 391, 391, 391, 392, 391, 393,  26,  26,  26,  26,  26,
+   394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395,
+   396, 396, 396, 397, 396, 398, 399, 399, 399, 399, 400, 399, 399, 399, 399, 400,
+   401, 401, 401, 401, 401,  26, 402, 402, 402, 402, 402, 402, 403, 404,  26,  26,
+   405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405,
+   405, 405, 405, 405, 405, 405, 406,  26, 405, 405, 407,  26, 405,  26,  26,  26,
+   408, 409, 410, 410, 410, 410, 411, 412, 413, 413, 414, 413, 415, 415, 415, 415,
+   416, 416, 416, 417, 418, 416,  26,  26,  26,  26,  26,  26, 419, 419, 420, 421,
+   422, 422, 422, 423, 424, 424, 424, 425,  26,  26,  26,  26,  26,  26,  26,  26,
+   426, 426, 426, 426, 427, 427, 427, 428, 427, 427, 429, 427, 427, 427, 427, 427,
+   430, 431, 432, 433, 434, 434, 435, 436, 434, 437, 434, 437, 438, 438, 438, 438,
+   439, 439, 439, 439,  26,  26,  26,  26, 440, 440, 440, 440, 441, 442, 441,  26,
+   443, 443, 443, 443, 443, 443, 444, 445, 446, 446, 447, 446, 448, 448, 449, 448,
+   450, 450, 451, 452,  26, 453,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   454, 454, 454, 454, 454, 454, 454, 454, 454, 455,  26,  26,  26,  26,  26,  26,
+   456, 456, 456, 456, 456, 456, 457,  26, 456, 456, 456, 456, 456, 456, 457, 458,
+   459, 459, 459, 459, 459,  26, 459, 460,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  31,  31,  31, 461,
+   462, 462, 462, 462, 462,  26, 463, 463, 463, 463, 463, 464,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 465, 465, 466,  26,
+   467, 467, 467, 467, 467, 467, 467, 467, 467, 468, 469, 467, 467, 467,  26, 470,
+   471, 471, 471, 471, 471, 471, 471, 471, 472, 473, 474, 474, 474, 475, 474, 476,
+   477, 477, 477, 477, 477, 477, 478, 477, 479,  26, 480, 480, 480, 480, 481,  26,
+   482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 482, 482, 484, 140, 485,  26,
+   486, 486, 487, 486, 486, 486, 486, 488,  26,  26,  26,  26,  26,  26,  26,  26,
+   489, 490, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 494, 495, 494, 496,
+   497, 498, 499, 500, 500, 501, 502, 503, 498, 504, 505, 506, 507, 508, 508,  26,
+   509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 510,  26,  26,  26,  26,
+   511, 511, 511, 511, 511, 511, 511, 511, 511,  26, 511, 512,  26,  26,  26,  26,
+   513, 513, 513, 513, 513, 513, 514, 513, 513, 513, 513, 514,  26,  26,  26,  26,
+   515, 515, 515, 515, 515, 515, 515, 515, 516,  26, 515, 517, 201, 518,  26,  26,
+   519, 519, 519, 519, 519, 519, 519, 520, 519, 521,  26,  26,  26,  26,  26,  26,
+   522, 522, 522, 523, 522, 524, 522, 522,  26,  26,  26,  26,  26,  26,  26,  26,
+   525, 525, 525, 525, 525, 525, 525, 526,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 529,
+    26,  26,  26,  26, 530, 531, 530, 530, 530, 530, 530, 531, 532,  26,  26,  26,
+   533, 533, 533, 533, 533, 533, 533, 533, 533,  26, 534, 534, 534, 534, 534, 534,
+   534, 534, 534, 534, 535,  26,  26,  26, 536, 536, 536, 536, 536, 536, 536, 537,
+   538, 539, 538, 538, 538, 538, 540, 538, 541,  26, 538, 538, 538, 542, 543, 543,
+   543, 543, 544, 543, 543, 545, 546,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   547, 548, 549, 549, 549, 549, 547, 550, 549,  26, 549, 551, 552, 553, 554, 554,
+   554, 555, 556, 557, 554, 558,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 559, 559, 559, 560,
+    26,  26,  26,  26,  26,  26,  26,  26, 109, 109, 109, 109, 109, 109, 561, 562,
+   563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563,
+   563, 563, 563, 564,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 565, 566,  26,
+   563, 563, 563, 563, 563, 563, 563, 563, 567,  26,  26,  26,  26,  26,  26,  26,
+   568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568,
+   568, 568, 568, 568, 568, 569, 568, 570,  26,  26,  26,  26,  26,  26,  26,  26,
+   571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+   571, 571, 571, 571, 571, 571, 571, 571, 572,  26,  26,  26,  26,  26,  26,  26,
+   309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309,
+   309, 309, 309, 309, 309, 309, 309, 573, 574, 574, 574, 575, 574, 576,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 577, 577, 577, 578, 578,  26,
+   579, 579, 579, 579, 579, 579, 579, 579, 580,  26, 579, 581, 581, 579, 579, 582,
+   579, 579,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 583, 583, 583, 583, 583, 583, 583, 583,
+   583, 583, 583, 584,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   585, 585, 585, 585, 585, 585, 585, 585, 585, 586, 585, 585, 585, 585, 585, 585,
+   585, 587, 585, 585,  26,  26,  26,  26,  26,  26,  26,  26, 588,  26,  26,  26,
+   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589,
+   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589,  26,
+   589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 590,  26,
+   591, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+   290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+   290, 290, 290, 291,  26,  26,  26,  26,  26,  26, 592,  26, 593,  26, 594, 594,
+   594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594,
+   594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 595,
+   596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 596, 598,
+   596, 599, 596, 600, 284,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 272,  26,
+     0,   0,   0,   0, 262, 361,   0,   0,   0,   0,   0,   0, 601, 602,   0, 603,
+   604, 605,   0,   0,   0, 606,   0,   0,   0,   0,   0,   0,   0, 607,  26,  26,
+    14,  14,  14,  14,  14,  14,  14,  14, 251,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,   0,   0, 284,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 262,  26,   0,   0,   0, 607,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 259,   0,   0,   0,   0,   0,
+     0,   0,   0, 259, 608, 609,   0, 610, 611,   0,   0,   0,   0,   0,   0,   0,
+   612, 613, 259, 259,   0,   0,   0, 614, 615, 616, 617,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 272,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0, 271,   0,   0,   0,   0,   0,   0,
+   618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
+   618, 619,  26, 620, 621, 618,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   274, 273, 273, 622, 623, 624,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   625, 625, 625, 625, 625, 626, 625, 627, 625, 628,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 629, 629, 629, 629, 629, 629, 629, 630,
+   631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631,
+   631, 631, 631, 631, 631, 631, 631, 631, 632, 631, 633,  26,  26,  26,  26,  26,
+   634, 634, 634, 634, 634, 634, 634, 634, 634, 635, 634, 636,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 361,   0,
+     0,   0,   0,   0,   0,   0, 637,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   361,   0,   0,   0,   0,   0,   0, 272,  26,  26,  26,  26,  26,  26,  26,  26,
+   638,  31,  31,  31, 639, 640, 641, 642, 643, 644, 639, 645, 639, 641, 641, 646,
+    31, 647,  31, 648, 649, 647,  31, 648,  26,  26,  26,  26,  26,  26, 355,  26,
+     0,   0,   0,   0,   0, 284,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 284,  26,   0, 262, 361,   0, 361,   0, 361,   0,   0,   0, 272,  26,
+     0, 637,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 637,   0,   0,
+     0,   0,   0,   0,   0, 637,  26,  26,  26,  26,  26,  26, 650,   0,   0,   0,
+   651,  26,   0,   0,   0,   0,   0, 284,   0, 607, 316,  26, 272,  26,  26,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 272,  26,   0, 637,   0, 269,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 284,  26,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 607,   0, 284,  26,  26,
+     0, 284,   0,   0,   0,   0,   0,   0,   0,  26,   0, 316,   0,   0,   0,   0,
+     0,  26,   0,   0,   0, 272,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+     0, 611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 614, 616,
+     0,   0,   0,   0, 613, 652,   0,   0,   0, 613,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 284,  26,   0, 272, 284, 269,
+   269,  26, 272,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 653,  26,  26,  26,  26,  26,
+   280, 280, 280, 280, 280, 280, 654,  26, 280, 280, 280, 280, 280, 280, 280, 280,
+   280, 280, 280, 283, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   280, 280, 280, 280, 348,  26, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+   280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 655,  26,  26,  26,
+   280, 280, 280, 283,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   656,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,
+     9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
+  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
+   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
+  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
+     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
+  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
+  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
+  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
+  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
+  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
+  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
+   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
+     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
+  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
+  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
+     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
+  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
+     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
+     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
+  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
+     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
+     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
+     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
+     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
+  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
+     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
+     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
+     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
+     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
+     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
+  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
+   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
+  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
+  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
+  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
+  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
+  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
+     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
+  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
+  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
+     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
+    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
+     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
+     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
+   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
+  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
+  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
+  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
+  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
+  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
+  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
+     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
+  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
+  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
+  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
+     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
+   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
+   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
+   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
+   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
+   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
+  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
+  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1948,1949,
+  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,1957,1959,1958,
+  1960,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
+   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
+   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
+   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
+   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
+   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
+    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
+   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
+   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
+   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
+   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
+   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
+   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
+    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
+   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
+   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
+   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
+   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
+   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
+   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
+   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
+   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[196] =
+{
+      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
+      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
+      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
+     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
+   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
+      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
+      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
+      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
+     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
+      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
+  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
+     -1,    0,    1,   -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114110u?_hb_ucd_u8[6432+(((_hb_ucd_u8[1248+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[8640+(((_hb_ucd_u8[7704+(((_hb_ucd_u8[7048+(((_hb_ucd_u8[6802+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9372+(((_hb_ucd_u8[9252+(((_hb_ucd_b4(9124+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918000u?_hb_ucd_u8[10822+(((_hb_ucd_u16[1920+(((_hb_ucd_u8[10150+(((_hb_ucd_u8[9700+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[5648+(((_hb_ucd_u8[16174+(((_hb_ucd_b4(16078+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0;
+}
+
+
+#else
+
+static const uint8_t
+_hb_ucd_u8[13072] =
+{
+    0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  5,  5,  7,  8,  9,
+   10, 11, 12, 13, 14, 15, 16,  5, 17, 15, 15, 18, 15, 19, 20, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 23,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    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, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41,
+   42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+   58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 67, 70, 71,
+   67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67,
+   79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90,
+   91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108,
+   34, 34,109,110,111,112,113,114,115,116,117,111, 34, 34, 34,111,
+  118,119,120,121,122,123,124,125, 34,126,127,111,128,111,129, 34,
+  130,131,132,133,134,135,136,111,137,138,111,139,140,141,142,111,
+  143,144,111,145,146,147,111,111,148,149,150,151,111,152,111,153,
+   34, 34, 34, 34, 34, 34, 34, 34,154, 34, 34,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34,155,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34,156,157,158, 34,111,111,111,111,159,160,161,162,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 34,163,111,111,111,111,111,111,
+   67, 67,164,165,166,128, 65,111,167,168,169,170,171,172,173,174,
+   67, 67, 67, 67,175,176,111,111,111,111,111,111,111,111,111,111,
+  177,111,178,111,111,179,111,111,111,111,111,111,111,111,111,111,
+   34,180,181,111,111,111,111,111,128,182,183,111, 34,184,111,111,
+   67, 67,185, 67, 67,111, 67,186, 67, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
+  187,111,177,177,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
+    7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 17, 18, 19,  1, 20, 20, 21, 22, 23, 24, 25,
+   26, 27, 15,  2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+   32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+   11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+   34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+   34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+   32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+   16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+   40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+   43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 16, 44, 16, 10,
+   41, 41, 41, 45, 11, 11, 11, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 46, 34, 32, 34, 11,
+   32, 47, 43, 43, 48, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   11, 11, 11, 11, 49,  2,  2,  2, 16, 16, 16, 16, 50, 51, 52, 53,
+   54, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 55,
+   56, 57, 43, 56, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 58,  2,  2,  2,  2,  2,  2, 59, 59, 59,  8,  9, 60,  2, 61,
+   43, 43, 43, 43, 43, 57, 59,  2, 62, 36, 36, 36, 36, 63, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 64, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 65, 43, 43, 43, 66, 47, 43, 43, 67, 68, 69, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 70, 71,  2,  2,  2,  2,  2,  2,  2, 72,
+   63, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 64, 36,
+   36, 36, 36, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 43, 43, 43, 43, 40, 21,  2, 40, 68, 20,
+   36, 36, 36, 43, 43, 68, 43, 43, 43, 43, 68, 43, 68, 43, 43, 43,
+    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 63, 43, 43,  2,
+   36, 63, 43, 43, 43, 43, 43, 43, 43, 73, 43, 43, 43, 43, 43, 43,
+   43, 74, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 74, 64, 75,
+   76, 43, 43, 43, 74, 75, 76, 75, 63, 43, 43, 43, 36, 36, 36, 36,
+   36, 43,  2,  7,  7,  7,  7,  7, 77, 36, 36, 36, 36, 36, 36, 36,
+   63, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 75,
+   76, 43, 43, 74, 75, 75, 76, 36, 36, 36, 36, 79, 75, 75, 36, 36,
+   36, 43, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 53, 58, 43,
+   43, 74, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 75,
+   76, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 64, 36, 36, 36,
+   36, 36, 36,  7,  7,  7,  7,  7, 43, 36, 63,  2,  2,  2,  2,  2,
+   76, 43, 43, 43, 74, 75, 76, 43, 60, 20, 20, 20, 80, 43, 43, 43,
+   43, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 76,
+   76, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 74, 75, 75, 36, 36,
+   71, 27, 27, 27, 27, 27, 27, 27, 43, 64, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 75, 74, 75, 75, 75, 75, 75, 76, 43,
+   36, 36, 36, 79, 75, 75, 75, 75, 75, 75, 75,  7,  7,  7,  7,  7,
+   27, 81, 61, 61, 53, 61, 61, 61, 74, 75, 64, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 43, 74, 75, 75, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 36, 36, 36, 36,  7,  7,  7, 82, 27, 27, 27, 81,
+   63, 75, 65, 36, 36, 36, 36, 36, 75, 75, 75, 74, 75, 75, 43, 43,
+   43, 43, 74, 75, 75, 75, 75, 36, 83, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 64, 75, 76, 43, 43, 75, 75, 75, 76, 70,
+   61, 61, 36, 79, 27, 27, 27, 84, 27, 27, 27, 27, 81, 36, 36, 36,
+   75, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74,
+   75, 43, 43, 43, 75, 75, 75, 75,  7, 75,  2,  2,  2,  2,  2,  2,
+   63, 36, 43, 43, 43, 43, 43, 85, 36, 36, 36, 68, 43, 43, 43, 57,
+    7,  7,  7,  7,  7,  2,  2,  2, 63, 36, 43, 43, 43, 43, 64, 36,
+   36, 36, 36, 40, 43, 43, 43, 43,  7,  7,  7,  7,  7,  7, 36, 36,
+   70, 61,  2,  2,  2,  2,  2,  2,  2, 86, 86, 61, 43, 61, 61, 61,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 47, 47, 47,  4,  4, 75,
+   63, 43, 43, 43, 43, 43, 43, 74, 43, 43, 57, 43, 36, 36, 63, 43,
+   43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 69, 61, 61, 61, 61,
+    2,  2, 86, 61, 21,  2,  2,  2, 36, 36, 36, 36, 36, 79, 76, 43,
+   74, 43, 43, 43, 76, 74, 76, 64, 36, 36, 36, 75, 43, 36, 36, 43,
+   64, 75, 78, 79, 75, 75, 75, 36, 63, 43, 64, 36, 36, 36, 36, 36,
+   36, 74, 76, 74, 75, 75, 76, 79,  7,  7,  7,  7,  7, 75, 76, 61,
+   16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 63, 43,
+    2,  2,  2,  2, 87, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+   61, 61, 61, 61, 61, 61, 61, 61, 11, 11, 11, 11, 16, 16, 16, 16,
+   88, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65,
+   89, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 90, 91, 91,
+   36, 36, 36, 36, 36, 58,  2, 92, 93, 36, 36, 36, 36, 36, 36, 36,
+   36, 43, 43, 43, 43, 43, 43, 43, 36, 43, 57,  2,  2,  2,  2,  2,
+   36, 36, 43, 76, 43, 43, 43, 75, 75, 75, 75, 74, 76, 43, 43, 43,
+   43, 43,  2, 77,  2, 60, 63, 43,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  2,  2, 94,  2, 56, 43, 59, 36, 95, 36, 36, 36, 36, 36, 36,
+   36, 36, 63, 64, 36, 36, 36, 36, 36, 36, 36, 36, 63, 36, 36, 36,
+   43, 74, 75, 76, 74, 75, 75, 75, 75, 74, 75, 75, 76, 43, 43, 43,
+   61, 61,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 27, 27, 61,
+   36, 36, 36, 63, 74, 76, 43,  2, 36, 36, 79, 74, 43, 43, 43, 43,
+   74, 74, 76, 43, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 43, 43,
+    2,  2,  2, 77,  2,  2,  2,  2, 43, 43, 43, 43, 43, 43, 43, 48,
+   48, 48, 48, 48, 48, 48, 48, 48, 43, 43, 78, 36, 36, 36, 36, 36,
+   36, 36, 74, 43, 43, 74, 74, 75, 75, 74, 78, 36, 36, 36, 36, 36,
+   86, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 61, 61,
+   43, 78, 36, 36, 36, 36, 36, 36, 79, 43, 43, 75, 43, 76, 43, 36,
+   36, 36, 36, 74, 43, 75, 76, 76, 43, 75, 75, 75, 75, 75,  2,  2,
+   36, 36, 75, 75, 75, 75, 43, 43, 43, 43, 75, 43, 43, 57,  2,  2,
+    7,  7,  7,  7,  7,  7, 83, 36, 36, 36, 36, 36, 40, 40, 40,  2,
+   43, 57, 43, 43, 43, 43, 43, 43, 74, 43, 43, 43, 64, 36, 63, 36,
+   36, 36, 64, 79, 43, 36, 36, 36, 16, 16, 16, 16, 16, 16, 40, 40,
+   40, 40, 40, 40, 40, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16,
+   16, 16, 16, 16, 16, 96, 40, 40, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 16, 34, 11, 11, 11,
+   16, 16, 16, 16, 97, 97, 97, 97, 16, 16, 16, 16, 11, 11, 98, 99,
+   41, 16, 16, 16, 11, 11, 98, 41, 16, 16, 16, 16, 11, 11,100, 41,
+  101,101,101,101,101,102, 59, 59, 51, 51, 51,  2,103,104,103,104,
+    2,  2,  2,  2,105, 59, 59,106,  2,  2,  2,  2,107,108,  2,109,
+  110,  2,111,112,  2,  2,  2,  2,  2,  9,110,  2,  2,  2,  2,113,
+   59, 59, 59, 59, 59, 59, 59, 59,114, 40, 27, 27, 27,  8,111,115,
+   27, 27, 27, 27, 27,  8,111, 91, 20, 20, 20, 20, 20, 20, 20, 20,
+   43, 43, 43, 43, 43, 43,116, 48,117, 48,117, 43, 43, 43, 43, 43,
+   61,118, 61,119, 61, 34, 11, 16, 11, 32,119, 61, 46, 11, 11, 61,
+   61, 61,118,118,118, 11, 11,120, 11, 11, 35, 36, 39, 61, 16, 11,
+    8,  8, 46, 16, 16, 26, 61,121, 92, 92, 92, 92, 92, 92, 92, 92,
+   92,122,123, 92,124, 61, 61, 61,  8,  8,125, 61, 61,  8, 61, 61,
+  125, 26, 61,125, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 61,  8,
+   61,125,125, 61, 61, 61, 61, 61, 61, 61,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8, 61, 61, 61, 61,  4,  4, 61, 61,
+    8, 61, 61, 61,126,127, 61, 61, 61, 61, 61, 61, 61, 61,125, 61,
+   61, 61, 61, 61, 61, 26,  8,  8,  8,  8, 61, 61, 61, 61, 61, 61,
+   61, 61, 61, 61, 61, 61,  8,  8,  8, 61, 61, 61, 61, 61, 61, 61,
+   27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27,
+   61, 61, 61, 26, 61, 61, 61, 61, 26, 61, 61, 61, 61, 61, 61, 61,
+   61, 61, 61, 61,  8,  8,  8,  8, 61, 61, 61, 61, 61, 61, 61, 26,
+   61, 61, 61, 61,  4,  4,  4,  4,  4,  4,  4, 27, 27, 27, 27, 27,
+   27, 27, 61, 61, 61, 61, 61, 61,  8,  8,111,128,  8,  8,  8,  8,
+    8,  8,  8,  4,  4,  4,  4,  4,  8,111,129,129,129,129,129,129,
+  129,129,129,129,128,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
+    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,125, 26,  8,  8,125, 61,
+   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11,
+   32, 32,121, 61, 61,119, 34,130, 43, 32, 16, 16, 50,  2, 87,  2,
+   36, 36, 36, 36, 36, 36, 36, 95,  2,  2,  2,  2,  2,  2,  2, 56,
+    2,103,103,  2,107,108,103,  2,  2,  2,  2,  6,  2, 94,103,  2,
+  103,  4,  4,  4,  4,  2,  2, 77,  2,  2,  2,  2,  2, 51,  2,  2,
+   94,131,  2,  2,  2,  2,  2,  2,  1,  2,132,133,  4,  4,  4,  4,
+    4, 61,  4,  4,  4,  4,134, 91,135, 92, 92, 92, 92, 43, 43, 75,
+  136, 40, 40, 61, 92,137, 58, 61, 71, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 63,138,139, 62, 36, 36, 36, 36, 36, 58, 40, 62,
+   61, 27, 27, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 61, 61, 61,
+   61, 61, 61, 61, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 27,
+   36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,141,  2,
+   32, 32, 32, 32, 32, 32, 32, 63, 48,142, 43, 43, 43, 43, 43, 77,
+   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36, 92, 92, 92, 92, 92,
+   43,  2,  2,  2,  2,  2,  2,  2, 41, 41, 41,139, 40, 40, 40, 40,
+   41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32,
+   44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,143, 34, 35,
+   32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32,
+   11, 11, 32, 32, 32, 32, 32, 32, 16, 32, 11, 11, 11, 11, 11, 11,
+   11, 11, 11,144, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36,
+   36, 79, 76, 74, 61, 61, 61, 61, 27, 27, 27, 61,145, 61, 61, 61,
+   36, 36,  2,  2,  2,  2,  2,  2, 75, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 75, 75, 75, 75, 75, 75, 75, 75, 43, 43, 43, 43, 43,  2,
+   43, 36, 36, 36,  2, 65, 65, 63, 36, 36, 36, 43, 43, 43, 43,  2,
+   36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,146,
+   36, 63, 75, 43, 43, 75, 43, 75,146,  2,  2,  2,  2,  2,  2, 77,
+    7,  7,  7,  7,  7,  7,  7,  2, 36, 36, 63, 62, 36, 36, 36, 36,
+   36, 36, 36, 36, 63, 43, 43, 74, 76, 74, 76, 43, 43, 43, 43, 43,
+   36, 63, 36, 36, 36, 36, 74, 75,  7,  7,  7,  7,  7,  7,  2,  2,
+   62, 36, 36, 70, 61, 79, 74, 36, 64, 43, 64, 63, 64, 36, 36, 43,
+   36, 36, 36, 36, 36, 36, 95,  2, 36, 36, 36, 36, 36, 79, 43, 75,
+    2, 95,147, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16, 99, 40, 40,
+   36, 79, 76, 75, 74,146, 76, 43,148,148,148,148,148,148,148,148,
+  149,149,149,149,149,149,149,149, 16, 16, 16, 16, 16, 16, 35, 64,
+   36, 36, 36, 36,150, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+   41,151, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,129,
+  152,152,152,152,152,152,152,152, 36, 36, 36, 36, 36, 36,145, 61,
+    2,  2,  2,153,112,  2,  2,  2,  6,154,155,129,129,129,129,129,
+  129,129,112,153,112,  2,109,156,  2,  2,  2,  2,134,129,129,112,
+    2,157,  8,  8, 60,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36,158,
+    2,  2,  3,  2,  4,  5,  6,  2, 16, 16, 16, 16, 16, 17, 18,111,
+  112,  4,  2, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 40, 20,159, 53, 20, 26,  8,125, 61,
+   61, 61, 61, 61,160, 59, 61, 61,  2,  2,  2, 87, 27, 27, 27, 27,
+   27, 27, 27, 81, 61, 61, 61, 61, 92, 92,124, 27, 81, 61, 61, 61,
+   61, 61, 61, 61, 61, 27, 61, 61, 61, 61, 61, 61, 61, 61, 47, 43,
+  161,161,161,161,161,161,161,161,162, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 84, 36,133, 36, 36, 36, 36, 92, 92, 92,
+   36, 36, 36, 36, 36, 36, 36, 58,163, 92, 92, 92, 92, 92, 92, 92,
+   36, 36, 36, 58, 27, 27, 27, 27, 36, 36, 36, 70,140, 27, 27, 27,
+   36, 36, 36,164, 27, 27, 27, 27, 36, 36, 36, 36, 36,164, 27, 27,
+   36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36,
+   63, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36,164, 30, 36, 36, 36, 36, 36, 36,164, 27,
+   36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 43, 43,162, 27, 27,
+   36, 36, 36, 36, 58,  2,  2,  2, 36, 36, 36, 36, 27, 27, 27, 27,
+   16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 43, 43, 43, 43, 43, 43,
+   27, 27, 27, 84, 36, 36, 36, 36,162, 27, 30,  2,  2,  2,  2,  2,
+   76, 78, 36, 36, 36, 36, 36, 36, 43, 43, 43, 57,  2,  2,  2,  2,
+    2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,165, 75, 76, 43, 74, 76, 57, 72,  2,
+    2,  2,  2,  2,  2,  2, 72, 59, 36, 36, 36, 63, 43, 43, 76, 43,
+   43, 43, 43,  7,  7,  7,  7,  7,  2,  2, 79, 75, 75, 75, 75, 75,
+   36, 63,  2, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 43, 74,
+   78, 36, 58,  2, 56, 43, 57,  2,  7,  7,  7,  7,  7, 58, 58,  2,
+   87, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 75, 76,
+   43, 75, 74, 43,  2,  2,  2, 43, 36, 36, 36, 36, 36, 36, 36, 63,
+   74, 75, 75, 75, 75, 75, 75, 75, 36, 36, 36, 79, 75, 75, 78, 36,
+   36, 75, 75, 43, 43, 43, 43, 43, 36, 36, 79, 75, 43, 43, 43, 43,
+   75, 43, 74, 64, 36, 58,  2,  2,  7,  7,  7,  7,  7, 82,  2, 64,
+   75, 76, 43, 43, 74, 74, 75, 76, 74, 43, 36, 65, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 75, 75, 43, 76,
+   57,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 43, 43,
+   75, 76, 43, 43, 43, 74, 76, 76, 57,  2, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 76, 75, 43, 43, 43, 76, 36, 36, 36, 36,
+   75, 43, 43, 76, 43, 43, 43, 43,  7,  7,  7,  7,  7, 27,  2, 86,
+   43, 43, 43, 43, 76, 57,  2,  2, 27, 27, 27, 27, 27, 27, 27, 84,
+   79, 75, 43, 43, 43, 43, 75, 75, 64, 65, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75, 75, 75, 75, 75, 63, 43, 43, 43, 43, 64, 36, 36,
+   36, 63, 43, 43, 74, 63, 43, 57,  2,  2,  2, 56, 43, 43, 43, 43,
+   63, 43, 43, 74, 76, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43,
+   43, 43, 43, 74, 43,  2, 65,  2, 43, 43, 43, 43, 43, 43, 43, 76,
+   58,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36, 36,
+   43, 43, 43, 43, 74, 43, 43, 43, 74, 43, 76, 43, 43, 43, 43, 43,
+   43, 43, 43, 63, 43, 43, 43, 43, 36, 36, 36, 36, 36, 75, 75, 75,
+   43, 74, 76, 76, 36, 36, 36, 36, 36, 63, 74,146,  2,  2,  2,  2,
+   27, 27, 81, 61, 61, 61, 53, 20,145, 61, 61, 61, 61, 61, 61, 61,
+   61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57,  2,  2,  2,  2,  2,
+   43, 43, 43, 57,  2,  2, 61, 61, 40, 40, 86, 61, 61, 61, 61, 61,
+    7,  7,  7,  7,  7,166, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36,
+   27, 27, 27, 30,  2,  2,  2,  2, 79, 75, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75, 75, 75, 75, 76, 43, 67, 40, 40, 40, 40, 40, 40,
+   40, 77, 40, 40, 40, 40, 40, 40, 36, 36, 36, 36, 36, 36, 47, 57,
+   61, 61,167, 76, 43, 61,167, 75, 75,168, 59, 59, 59, 73, 43, 43,
+   43, 69, 47, 43, 43, 43, 61, 61, 61, 61, 61, 61, 61, 43, 43, 61,
+   61, 43, 69, 61, 61, 61, 61, 61, 11, 11, 11, 11, 11, 16, 16, 16,
+   16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
+   11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
+   11, 11, 11, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11,
+   11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33,
+   16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31,
+   16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16,
+   16, 33, 16, 16, 16, 32, 16,  7, 43, 43, 43, 69, 61, 47, 43, 43,
+   43, 43, 43, 43, 43, 43, 69, 61, 61, 61, 47, 61, 61, 61, 61, 61,
+   61, 61, 69, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2, 56, 43, 43,
+   43, 43, 43, 67, 40, 40, 40, 40,  7,  7,  7,  7,  7,  7,  7, 70,
+   36, 36, 36, 36, 36, 36, 43, 43,  7,  7,  7,  7,  7,  7,  7,169,
+   16, 16, 43, 43, 43, 67, 40, 40, 27, 27, 27, 27, 27, 27,140, 27,
+  170, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,140,
+   61, 61, 61, 61, 61, 25, 41, 41,  0,  0, 29, 21, 21, 21, 23, 21,
+   22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
+    9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24, 26, 25, 15, 15,
+   24, 15,  7, 19, 15, 21,  9, 25,  9,  5,  5, 25,  5,  9,  5,  7,
+    7,  7,  9,  8,  8,  5,  7,  5,  6,  6, 24, 24,  6, 24, 12, 12,
+    6,  5,  9, 21, 25,  9, 26, 12, 11, 11,  9,  6,  5, 21, 17, 17,
+   17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21,  7, 21,  1,  1,
+   21, 23, 26, 26,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1, 12,  6,
+    6, 12, 12, 26,  7, 26, 26,  7, 21,  1,  1, 12, 12, 10, 10, 10,
+   10, 12, 21,  6, 10,  7,  7, 10, 23,  7, 15, 26, 13, 21, 13,  7,
+   15,  7, 12, 23, 21, 26, 21, 15, 17,  7, 29,  7,  7, 22, 18, 18,
+   14, 14, 14,  7, 17, 21,  7,  6,  5,  6,  8,  8,  8, 24,  5, 24,
+    9, 24, 29, 29, 29,  1, 20, 19, 22, 20, 27, 28,  1, 29, 21, 20,
+   19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15,  6, 18,  6,
+   12, 11, 11, 12,  9, 26, 26,  9, 26,  5,  5, 26, 14,  9,  5, 14,
+   14, 15, 25, 26, 26, 22, 18, 26, 18, 25, 18, 22,  5, 12, 22, 21,
+   26,  6,  7, 14, 17, 22, 26, 14, 17,  6, 14,  6, 12, 24, 24,  6,
+   26, 15,  6, 21, 11, 21, 24,  9,  9,  7, 23, 26, 10, 21,  6, 10,
+    4,  4,  3,  3,  7, 25, 24,  7, 22, 22, 21, 22, 17, 16, 16, 22,
+   16, 16, 25, 17,  7,  1, 25, 24, 26,  1,  2,  2, 12, 15, 21, 14,
+    7, 15, 13, 12, 13, 15, 26, 10, 10,  1, 13, 23, 23, 15,  0,  1,
+    2,  3,  4,  5,  6,  7,  8,  9,  9, 10, 11,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9, 12, 13,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 14, 15, 16,  9,
+   17, 18, 19, 20, 21, 22,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9, 23,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 24,  9,  9,
+    9,  9, 25,  9,  9,  9, 26,  9, 27,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  2,  0,  0,  0,  0,  3,  0,  0,  0,
+    4,  5,  6,  7,  0,  8,  9, 10,  0, 11, 12, 13,  0, 14, 15, 16,
+   15, 17, 15, 18, 15, 18, 15, 18,  0, 18,  0, 19, 15, 18, 20, 18,
+    0, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,  0, 31,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 32,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 33,  0,  0, 34,  0,  0, 35,  0, 36,  0,
+    0,  0, 37, 38, 39,  0, 40, 41, 42, 43, 44,  0,  0, 45,  0,  0,
+    0, 46,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,  0, 49,
+    0, 50,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0, 52,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 53, 54, 55,  0,  0,  0,  0, 56,  0,  0, 57, 58, 59,
+   60, 61,  0,  0, 62, 63,  0,  0,  0, 64,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 65,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 67,  0,  0,  0, 68,  0, 69,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 70,  0,  0, 71,  0,  0,  0,  0,  0,  0,  0,  0, 72,  0,
+    0,  0,  0,  0,  0,  0,  0, 73,  0,  0,  0, 74, 75,  0, 76, 60,
+    0, 77, 78,  0,  0, 79, 80, 81,  0,  0,  0, 82,  0, 83,  0,  0,
+   49, 84, 49,  0, 85,  0, 86,  0,  0,  0, 75,  0,  0,  0,  0,  0,
+    0, 87, 88, 89, 90,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0, 91,
+   92,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 93, 94,  0,  0,  0,  0,  0, 95,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 96,
+   97,  0,  0, 98,  0,  0,  0,  0,  0,  0, 99,  0,  0,  0, 94,  0,
+    0,  0,  0,  0,  0,100,  0,  0,  0,  0,  0,  0,  0,101,  0,102,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,
+    3,  4,  5,  6,  7,  0,  8,  0,  0,  0,  0,  9, 10, 11, 12,  0,
+    0,  0,  0, 13,  0,  0, 14, 15,  0, 16,  0, 17, 18,  0,  0, 19,
+    0, 20, 21,  0,  0,  0,  0,  0, 22, 23,  0, 24, 25,  0,  0, 26,
+    0,  0,  0, 27, 28, 29,  0,  0,  0, 30, 31, 32,  0,  0, 31,  0,
+    0, 33, 31,  0,  0,  0, 31, 34,  0,  0,  0,  0,  0, 35, 36,  0,
+    0,  0,  0,  0,  0, 37, 38,  0,  0,  0,  0,  0,  0, 39, 40,  0,
+    0,  0,  0, 41,  0, 42,  0,  0,  0, 43, 44,  0,  0,  0, 45,  0,
+    0,  0,  0,  0,  0, 46, 47,  0,  0,  0,  0, 48,  0,  0,  0, 49,
+    0, 49,  0, 50,  0,  0,  0,  0, 51,  0,  0,  0,  0, 52,  0, 53,
+    0,  0,  0,  0, 54, 55,  0,  0,  0, 56,  0,  0,  0, 57, 49,  0,
+   58, 59,  0,  0, 60,  0,  0,  0, 61, 62,  0,  0,  0, 63,  0, 64,
+   65, 66, 67, 68,  1, 69,  0, 70, 71, 72,  0,  0, 73, 74,  0,  0,
+    0, 75,  0,  0,  1,  1,  0,  0, 76,  0,  0, 77,  0,  0,  0,  0,
+   73, 78,  0, 79,  0,  0,  0,  0,  0, 74, 80,  0,  0,  0, 49,  0,
+    1, 74,  0,  0, 81,  0,  0, 82,  0,  0,  0,  0,  0, 83, 54,  0,
+    0,  0,  0,  0,  0, 84, 85,  0,  0, 80,  0,  0, 31,  0,  0, 86,
+    0,  0,  0,  0, 87,  0,  0,  0,  0, 47,  0,  0, 88,  0,  0,  0,
+    0, 89, 90,  0,  0, 91,  0,  0, 92,  0,  0,  0, 93,  0, 94, 88,
+    0,  0, 80,  0,  0, 75,  0,  0,  0, 95, 96,  0,  0, 97, 98,  0,
+    0,  0,  0,  0,  0, 99,  0,  0,100,  0,  0,  0,  0,101, 31,  0,
+  102,103,104, 33,  0,  0,105,  0,  0,  0,106,  0,  0,  0,  0,  0,
+    0,107,  0,  0,108,  0,  0,  0, 54,  0,  0,  0,  0, 49,109,  0,
+    0,  0,  0,110,  0,  0,111,  0,  0,  0,  0,109,  0,  0,  0,  0,
+    0,112,  0,  0,  0,113,  0,114,  0,  0,  0,  0,115,116,117,  0,
+  118,  0,119,  0,  0,  0,120,121,122,  0,  0,  0,123,  0,  0,124,
+    0,  0,125,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,
+    3,  4,  5,  6,  7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15,
+   16, 17, 18,  1,  1,  1, 19,  1,  0,  0, 20, 21, 22,  1, 23,  4,
+   21, 24, 25, 26, 27, 28, 29, 30,  0,  0,  1,  1, 31,  0,  0,  0,
+   32, 33, 34, 35,  1, 36, 37,  0,  0,  0,  0, 38,  1, 39, 14, 39,
+   40, 41, 42,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0,
+   19,  1, 21,  0,  0, 47,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0,
+   51,  0, 52,  1,  1,  1, 53, 21, 43, 54, 55, 21, 35,  1,  0,  0,
+    0, 56,  0,  0,  0, 57, 58, 59,  0,  0,  0,  0,  0, 60,  0, 61,
+    0,  0,  0,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65,  0,  0,  0,
+   66,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0,  0, 69,  0,  0, 70,
+   71,  0, 72, 73, 74, 75, 76, 77,  0,  0,  0, 78,  0,  0,  0, 79,
+   80,  0,  0,  0,  0, 47,  0,  0,  0, 49,  0, 63,  0,  0, 64,  0,
+    0, 81,  0,  0, 82,  0,  0,  0, 83,  0,  0, 19, 84,  0, 63,  0,
+    0,  0,  0, 49,  1, 85,  1, 54, 15, 41,  0, 56,  0,  0,  0,  0,
+   19, 10,  1,  0,  0,  0,  0,  0, 86,  0,  0, 87,  0,  0, 86,  0,
+    0,  0,  0, 79,  0,  0, 88,  9, 12,  4, 89,  8, 90, 47,  0, 59,
+   50,  0, 21,  1, 21, 91, 92,  1,  1,  1,  1, 93, 94, 95, 96,  1,
+   97, 59, 81, 98, 99,  4, 59,  0,  0,  0,  0,  0,  0, 19, 50,  0,
+    0,  0,  0,  0,  0, 62,  0,  0,100,101,  0,  0,102,  0,  0,  1,
+    1, 50,  0,  0,  0, 38,  0, 64,  0,  0,  0,  0, 52, 69, 62,  0,
+    0,  0, 79,  0,  0,  0,103,104, 59, 38, 81,  0,  0,  0,  0,  0,
+    0,105,  1, 14,  4, 12, 84,  0,  0,  0,  0, 38, 88,  0,  0,  0,
+    0,106,  0,  0,107, 62,  0,108,  0,  0,  0,  1,  0,  0,  0,109,
+   14, 54,  0,  0,110,  0, 88,  0,  0,  0, 62, 63,  0,  0, 63,  0,
+   87,  0,  0,110,  0,  0,  0,  0,111,  0,  0,  0, 79, 56,  0, 38,
+    1, 59,  1, 59,  0,  0, 64, 87,  0,  0,112,  0,  0,  0, 56,  0,
+    0,  0,  0,112,  0,  0,  0,  0, 62,  0,  0, 62,  0,  0,  0,  0,
+   57,  0, 87,113,  0,  0,  8, 90,  0,  0,  1, 88,  0,  0,  0,  0,
+    0,114,  0,115,116,117,118,  0, 52,  4,119, 49, 23,  0,  0,  0,
+   38, 50, 38, 59,  0,  0,  1, 88,  1,  1,  1,  1, 39,  1, 48,103,
+   88,  0,  0,  0,  0,  1,  4,119,  0,  0,  0,  1,120,  0,  0,  0,
+    0,  0,230,230,230,230,230,232,220,220,220,220,232,216,220,220,
+  220,220,220,202,202,220,220,220,220,202,202,220,220,220,  1,  1,
+    1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,220,220,
+  230,230,230,220,220,  0,230,230,230,220,220,220,220,230,232,220,
+  220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,  0,220,
+  230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222,
+  228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,
+    0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,  0,  0,
+    0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,
+  230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,230,  0,
+  220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,220,220,
+  230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,230,230,
+    0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,  0,  0,
+    0,220,230,230,  0,220,230,220,220,220, 27, 28, 29,230,  7,  0,
+    0,  0,  0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,
+  230,  0,  0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,
+    9,  0,103,103,  9,  0,107,107,107,107,118,118,  9,  0,122,122,
+  122,122,220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,  0,129,
+  130,  0,132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,
+  230,230,  9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,  0,  9,
+    9,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,220,  0,
+    0,  0,230,  0,  0,220,  0,  0,  9,  9,  0,  0,  7,  0,230,230,
+  230,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,202,230,
+  230,230,230,230,232,228,228,220,  0,230,233,220,230,220,230,230,
+    1,  1,  1,  1,  1,230,  0,  1,  1,230,220,230,  1,  1,  0,  0,
+  218,228,232,222,224,224,  0,  8,  8,  0,230,  0,230,230,220,  0,
+    0,230,  0,  0, 26,  0,  0,220,  0,230,230,  1,220,  0,  0,230,
+  220,  0,  0,  0,220,220,  0,  9,  7,  0,  0,  7,  9,  0,  0,  0,
+    9,  7,  9,  9,  0,  0,  0,  0,  1,  0,  0,216,216,  1,  1,  1,
+    0,  0,  0,226,216,216,216,216,216,  0,220,220,220,  0,230,230,
+    7,  0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17,177,  0,  1,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  4,  3,  3,  3,  3,  3,  5,  3,  3,  3,
+    3,  3,  6,  7,  8,  3,  3,  3,  3,  3,  9, 10, 11, 12, 13,  3,
+    3,  3,  3,  3,  3,  3,  3, 14,  3, 15,  3,  3,  3,  3,  3,  3,
+   16, 17, 18, 19, 20, 21,  3,  3,  3, 22, 23,  3,  3,  3,  3,  3,
+    3,  3, 24,  3,  3,  3,  3,  3,  3,  3,  3, 25,  3,  3, 26, 27,
+    0,  1,  0,  0,  0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,
+    0,  3,  0,  0,  0,  0,  0,  4,  0,  5,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  0,  0,  0,  7,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,  0,  0,
+    0,  9,  0,  9,  0,  0,  0,  0,  0,  0,  0, 10, 11, 12, 13,  0,
+    0, 14, 15, 16,  6,  0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24,
+   19, 25,  0, 26, 27, 19, 19, 28, 29, 30,  0, 31,  0,  0,  0,  8,
+    0,  0,  0,  0,  0,  0,  0, 19, 28,  0, 32, 33,  9, 34, 35, 19,
+    0,  0, 36, 37, 38, 39, 40, 19,  0, 41, 42, 43, 44, 31,  0,  1,
+   45, 42,  0,  0,  0,  0,  0, 32, 14, 14,  0,  0,  0,  0, 14,  0,
+    0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53,
+   43, 21,  0,  0,  0,  0,  0,  0,  0, 54,  6, 55,  0, 14, 19,  1,
+    0,  0,  0, 19, 56, 31,  0,  0,  0,  0,  0,  0,  0, 57, 14,  0,
+    0,  0,  0,  1,  0,  2,  0,  0,  0,  3,  0,  0,  0, 58, 59,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  2,  3,  0,  4,
+    5,  0,  0,  6,  0,  0,  0,  7,  0,  0,  0,  1,  1,  0,  0,  8,
+    9,  0,  8,  9,  0,  0,  0,  0,  8,  9, 10, 11, 12,  0,  0,  0,
+   13,  0,  0,  0,  0, 14, 15, 16, 17,  0,  0,  0,  1,  0,  0, 18,
+   19,  0,  0,  0, 20,  0,  0,  0,  1,  1,  1,  1,  0,  1,  1,  1,
+    1,  1,  1,  1,  0,  8, 21,  9,  0,  0, 22,  0,  0,  0,  0,  1,
+    0, 23, 24, 25,  0,  0, 26,  0,  0,  0,  8, 21, 27,  0,  1,  0,
+    0,  1,  1,  1,  1,  0,  1, 28, 29, 30,  0, 31, 32, 20,  1,  1,
+    0,  0,  0,  8, 21,  9,  1,  4,  5,  0,  0,  0, 33,  9,  0,  1,
+    1,  1,  0,  8, 21, 21, 21, 21, 34,  1, 35, 21, 21, 21,  9, 36,
+    0,  0, 37, 38,  1,  0, 39,  0,  0,  0,  1,  0,  1,  0,  0,  0,
+    0,  8, 21,  9,  1,  0,  0,  0, 40,  0,  8, 21, 21, 21, 21, 21,
+   21, 21, 21,  9,  0,  1,  1,  1,  1,  8, 21, 21, 21,  9,  0,  0,
+    0, 41,  0, 42, 43,  0,  0,  0,  1, 44,  0,  0,  0, 45,  8,  9,
+    1,  0,  1,  0,  1,  1,  8, 21, 21,  9,  0,  4,  5,  8,  9,  1,
+    0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  9, 10, 11, 11, 11, 11, 11, 12, 12, 12,
+   12, 13, 14, 15, 16, 17, 18, 12, 19, 12, 20, 12, 12, 12, 12, 21,
+   22, 22, 22, 23, 12, 12, 12, 12, 24, 25, 12, 12, 26, 27, 28, 29,
+   30, 31,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 32,
+   12, 33, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 34,  0,  0,  1,  2,  2,  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, 32, 33, 33, 33, 34, 35, 35, 35, 35,
+   35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+    2,  2, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 57, 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61,
+   56, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 71,
+   62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 74, 74,
+   75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89,
+   91, 92, 93, 94, 95, 95, 96, 97, 87, 98, 99,100,101,102,103, 87,
+  104,104,104, 87,105,106,107,108,109,110,111,112,113,114,115, 87,
+   89, 87,116,117,118,119,120,121,122,123,124, 87,125,126, 87,127,
+  128,129,130, 87,131,132, 87,133,134,135, 87, 87,136,137,138,139,
+   87,140, 87, 21,141,141,141,141,141,141,141,141,141,141,141, 87,
+   87, 87, 87, 87,142,142,142,142,142,142,142,142,142, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,143,143,143,143,
+  143, 87, 87, 87,144,144,144,144,145,146,147,147, 87, 87, 87, 87,
+  148,148,149,150,151,151,151,151,151,151,151,151,151,151,151,151,
+  151,151,151,151,151,151,151,151,151,151, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87,152,153,154,155,155,155, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,156,157, 87, 87,
+   87, 87, 87, 87, 56, 56,158,159, 51, 56, 56, 87, 56, 56, 56, 56,
+   56, 56, 56, 56,160,160,160,160,160,160, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87,161, 87,162, 87, 87,163, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87,164,164,165, 87, 87, 87, 87, 87, 56, 56, 56, 87,
+   89, 89, 87, 87, 56, 56, 56, 56,166, 87, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87,
+   87, 87, 87, 87, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 56, 87,167,167,  0,  1,  2,  2,  0,  1,  2,  2,
+    2,  3,  4,  5,  0,  0,  0,  0,  1,  2,  1,  2,  0,  0,  3,  3,
+    4,  5,  4,  5,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  6,
+    0,  0,  7,  0,  8,  8,  8,  8,  8,  8,  8,  9, 10, 11, 11, 11,
+   11, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, 17, 18, 19, 19,
+   19, 19, 19, 19, 20, 21, 22, 22, 23, 24, 22, 25, 22, 22, 22, 22,
+   22, 26, 22, 22, 27, 27, 27, 27, 27, 22, 22, 22, 28, 28, 28, 28,
+   29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 27, 27, 22, 22, 22, 22,
+   22, 22, 32, 22, 33, 33, 33, 33, 33, 34, 35, 33, 36, 36, 36, 36,
+   36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38,
+   38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40,
+   40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42,
+   42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44,
+   44, 44, 44, 44, 45, 45, 45, 46, 45, 45, 45, 45, 47, 47, 47, 47,
+   47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 49, 48, 48, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51,
+   51, 51, 51, 52, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54,
+   54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56,
+   56, 56, 56, 56, 57, 57, 58, 58, 58, 58, 59, 58, 60, 60, 61, 62,
+   63, 63, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 66, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 67, 56, 56, 56, 56, 56, 68, 68, 68, 68,
+   68, 69, 69, 69, 70, 70, 70, 70, 70, 70, 65, 65, 71, 71, 72, 72,
+   72, 72, 72, 72, 72, 72, 72,  8,  8,  8,  8,  8, 73, 73, 73, 73,
+   73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76,
+   76, 77, 77, 77, 13, 51, 51, 51, 74, 78, 79, 80,  4,  4, 81,  4,
+    4, 82, 83, 84,  4,  4,  4, 85,  8,  8,  8,  8, 11, 11, 11, 11,
+   11, 11, 11, 11, 86,  0,  0,  0,  0,  0,  0, 87,  0,  4,  0,  0,
+    0,  8,  8,  8,  0,  0, 88, 89, 90,  0,  4,  4,  6,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 91, 91, 91, 91,
+   91, 91, 91, 91, 92, 92, 92, 92, 92, 92,  4,  4, 93, 93, 93, 93,
+   93, 93, 93, 93, 51, 51, 51, 94, 94, 94, 94, 94, 54, 54, 54, 54,
+   54, 54, 13, 13, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95,  0, 96,  0, 97, 98, 99,100,100,100,100,101,102,103,
+  103,103,103,104,105,105,105,106, 53, 53, 53, 53, 53,  0,105,105,
+    0,  0,  0,103, 53, 53,  0,  0,  0,  0, 53,107,  0,  0,  0,  0,
+    0,103,103,108,103,103,103,103,103,109,  0,  0, 95, 95, 95, 95,
+    0,  0,  0,  0,110,110,110,110,110,110,110,110,110,110,110,110,
+  110,111,111,111,112,112,112,112,112,112,112,112,112,112,112,112,
+   13, 13, 13, 13, 13, 13,113,113,113,113,113,113,  0,  0,114,  4,
+    4,  4,  4,  4,115,  4,  4,  4,  4,  4,  4,  4,116,116,116,  0,
+  117,117,117,117,118,118,118,118,118,118, 33, 33,119,119,120,121,
+  121,121, 53, 53,122,122,122,122,123,122, 50, 50,124,124,124,124,
+  124,124, 50, 50,125,125,125,125,125,125,126,126, 54, 54, 54,  4,
+    4,127,128, 55, 55, 55, 55, 55,126,126,126,126,129,129,129,129,
+  129,129,129,129,  4,130, 19, 19, 19, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22,131,  0, 22, 22, 22,  8,  0,132,  0,
+    0,  0,  0, 22, 22, 22, 22, 22, 22, 22, 22,133,  0,  0,  1,  2,
+    1,  2,134,102,103,135, 53, 53, 53, 53,  0,  0,136,136,136,136,
+  136,136,136,136,  0,  0,  0,  0, 11, 11, 11, 11, 11,  0, 11, 11,
+   11,  0,  0,137,138,138,139,139,139,139,140,  0,141,141,141,142,
+  142,143,143,143,144,144,145,145,145,145,145,145,146,146,146,146,
+  146,147,147,147,148,148,148,149,149,149,149,149,150,150,150,151,
+  151,151,151,151,152,152,152,152,152,152,152,152,153,153,153,153,
+  154,154,155,155,156,156,156,156,156,156,157,157,158,158,159,159,
+  159,159,159,159,160,160,161,161,161,161,161,161,162,162,162,162,
+  162,162,163,163,164,164,164,164,165,165,165,165,166,166,166,166,
+  167,167,168,168,169,169,169,169,169,169,169,169,170,170,170,170,
+  170,170,170,170,171,171,171,171,171,171,171,171,172,172,172,172,
+  172,172,172,172,173,173,173,174,174,174,174,174,175,175,175,175,
+  175,175,175,175,176,176,176,176,176,176,176,176,177,177,177,177,
+  177,178,178,178,179,179,179,179,179,180,180,180,181,181,181,181,
+  181,181,182, 44,183,183,183,183,183,183,183,183,184,184,184,185,
+  185,185,185,185,186,186,186,187,186,186,186,186,188,188,188,188,
+  188,188,188,188,189,189,189,189,189,189,189,189,190,190,190,190,
+  190,190,190,190,191,191,191,191,191,191, 67, 67,192,192,192,192,
+  192,192,192,192,193,193,193,193,193,193,193,193,194,194,194,194,
+  194,194,194,194,195,195,195,195,195,195,195,195,196,196,196,196,
+  196,196,196,196,197,197,197,197,197,198,198,198,198,198,198,198,
+  199,199,199,199,200,200,200,200,200,200,200,201,201,201,201,201,
+  201,201,201,201,202,202,202,202,202,202,203,203,203,203,203,203,
+  203,203,203,203,204,204,204,204,204,204,204,204,205,205,205,205,
+  205,205,205,205,206,206,206,206,206,206,206,206,207,207,207,207,
+  207,207,207,207,113,113,113,113,113,113,113,113,113,113,113,113,
+  208,208,208,208,209,209,209,209,209,209,209,209,210,210,210,210,
+  210,210,210,210,211,211,211,211,211,211,211,211,212,212,212,212,
+  212,212,212,212,212,212,212,212,212,212,213,  0,214,214,214,214,
+  214,214,214,214,215,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,216,217,217,217,217,217,
+  217,217,217,217,218,218,218,218,218,218,218,218,218,218,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,219,220,221,  0,222,  0,
+    0,  0,  0,  0,223,223,223,223,223,223,223,223, 92, 92, 92, 92,
+   92, 92, 92, 92,224,224,224,224,224,224,224,224,225,225,225,225,
+  225,225,225,225,226,226,226,226,226,226,226,226,227,227,227,227,
+  227,227,227,227,228,  0,  0,  0,  0,  0,  0,  0,  8,  8,  8,  8,
+    8,  8,  8,  8,  0,  0,  0,  0,  1,  2,  2,  2,  2,  2,  3,  0,
+    0,  0,  4,  0,  2,  2,  2,  2,  2,  3,  2,  2,  2,  2,  5,  0,
+    2,  5,  6,  0,  7,  7,  7,  7,  8,  9,  8, 10,  8, 11,  8,  8,
+    8,  8,  8,  8, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14,
+   16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 17, 19, 20, 20, 20,
+   20, 20, 20, 20, 21, 22, 21, 23, 21, 21, 24, 24, 21, 21, 21, 21,
+   23, 21, 25,  7,  7, 26, 21, 21, 27, 21, 21, 21, 21, 21, 21, 22,
+   28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+   32, 32, 32, 32, 33, 21, 21, 21, 34, 34, 34, 34, 35, 36, 34, 34,
+   34, 37, 34, 34, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40,
+   41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44,
+   45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 48,
+   49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 50, 53, 53, 53, 53,
+   54, 54, 54, 54, 54, 54, 55, 54, 56, 56, 56, 56, 57, 57, 57, 57,
+   58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61,
+   61, 61, 62, 63, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66,  0,  0,
+   67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 71, 72, 72,
+   72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
+   76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79,
+   80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83,  7,  7,  7,
+   84,  7, 85, 86,  0, 85, 87,  0,  2, 88, 89,  2,  2,  2,  2, 90,
+   91, 88, 92,  2,  2,  2, 93,  2,  2,  2,  2, 94,  0,  0,  0, 87,
+    1,  0,  0, 95,  0, 96, 97,  0,  4,  0,  0,  0,  0,  0,  0,  4,
+   98, 98, 98, 98, 99, 99, 99, 99, 13, 13, 13, 13,100,100,100,100,
+  101,101,101,101,  0,102,  0,  0,103,101,104,105,  0,  0,101,  0,
+  106,107,107,107,107,107,107,107,107,107,108,106,109,110,110,110,
+  110,110,110,110,110,110,111,109,112,112,112,112,113, 56, 56, 56,
+   56, 56, 56,114,110,110,110,111,110,110,  0,  0,115,115,115,115,
+  116,116,116,116,117,117,117,117,118,118,118,118, 97,  2,  2,  2,
+    2,  2, 95,  2,119,119,119,119,120,120,120,120,121,121,121,121,
+  122,122,122,122,122,122,122,123,124,124,124,124,125,125,125,125,
+  125,125,125,126,127,127,127,127,128,128,128,128,129,129,129,129,
+    2,  2,  3,  2,  2,130,  2,  2,131,131,131,131,132, 17, 17, 19,
+   21, 21, 21,133,  7,  7,  7,134, 21, 21, 21, 24,  0,135,110,110,
+  110,110,110,136,137,137,137,137,  0,  0,  0,138,139,139,139,139,
+  140,140,140,140, 85,  0,  0,  0,141,141,141,141,142,142,142,142,
+  143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146,
+  147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150,
+  151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154,
+  155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158,
+  159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162,
+  163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166,
+  167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,
+  171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174,
+  175,175,175,175,176,176,176,176,177,177,177,177,178,178,178,178,
+  179,179,179,179,180,180,180,180,181,181,181,181,182, 46, 46, 46,
+  183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,
+  186,186,187,186,188,188,188,188,189,189,189,189,190,190,190,190,
+  191,191,191,191,192,192,192,192,193,193,193,193,194,194,194,194,
+  195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
+  199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,
+  203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,
+  207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,
+  211,211,211,211,212,212,212,212,213,  0,  0,  0,214,214,214,214,
+  215,107,107,107,107,110,110,110,216,216,216,216,217,217,217,217,
+    0,218, 87,  0,  0,  0,218,  7, 83,138,  7,  0,  0,  0,219, 87,
+  220,220,220,220,221,221,221,221,222,222,222,222,223,223,223,223,
+  224,224,224,224,225,  0,  0,  0,  0,  0,  0,  0,  0, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19,  0,  0,  0, 19,  0, 19,  0,  0,  0,
+    0,  0, 26, 26,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,
+    9,  9,  0,  9,  9,  0,  9,  0,  9,  9, 55, 55, 55, 55, 55, 55,
+    6,  6,  6,  6,  6,  1,  1,  6,  6,  4,  4,  4,  4,  4,  4,  4,
+    4,  0,  4,  4,  4, 14, 14, 14, 14, 14, 14, 14,  3,  3,  3,  3,
+    3,  0,  3,  3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  1,
+    1,  1,  3,  3,  1,  3,  3,  3, 37, 37, 37, 37, 38, 38, 38, 38,
+   64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95,  3,  3,  0,  3,
+    7,  7,  7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  0,  0,  7,  7,
+    5,  5,  5,  5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21,
+   22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20,
+   36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24,  0, 18, 18, 18, 18,
+   25, 25, 25, 25, 25,  0,  0,  0,  0, 25, 25, 25, 33, 33, 33, 33,
+    8,  8,  8,  8,  8,  8,  8,  0, 12, 12, 12, 12, 30, 30, 30, 30,
+   29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35,
+   35, 35, 35,  0,  0,  0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44,
+   44,  0,  0,  0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31,
+   32, 32,  0,  0, 32,  0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48,
+   52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91,
+   62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70,
+   73, 73, 73, 73,  1,  1,  1,  0,  1,  0,  1,  1,  1,  0,  0,  0,
+    0,  1,  0,  0,  1,  1,  0,  0, 19, 19,  9,  9,  9,  9,  9,  6,
+   19,  9,  9,  9,  9,  9, 19, 19,  9,  9,  9, 19,  6, 19, 19, 19,
+   19, 19, 19,  9,  0,  0,  0, 19,  0,  0,  9,  0,  0,  0, 19, 19,
+   27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,
+    0, 13,  0, 13,  0, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,
+    0, 15, 15, 15, 15, 15, 15, 15, 15,  1,  1,  0,  0, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17,  0, 26, 26, 26, 26, 26, 12, 12, 12,
+   12, 12, 12,  0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77,
+   79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75,
+   69, 69, 69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 84, 84, 84, 84,
+   84, 84, 84,  0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87,
+   19,  9, 19, 19,  2,  2,  2,  2, 19, 19, 19,  4,  3,  3,  0,  0,
+    1,  1,  6,  6,  0,  0, 17, 17, 17, 17,  0,  0, 49, 49, 49, 49,
+    0,  1,  1,  1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42,
+   41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59,
+   40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,
+  106,106,106,106,104,104,104,104,110,110,110,110, 47, 47, 47, 47,
+   81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,128,128,
+   66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, 97, 97,
+   57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,112,112,
+   78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,122,122,
+   89, 89, 89, 89,130,130,130,130,144,144,144,144,147,147,147,147,
+  148,148,148,148,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,
+  101,101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100,
+  100, 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109,
+  107,107,107,107,107,107,107,  1,137,137,137,137,124,124,124,124,
+  123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126,
+  142,142,142,142,125,125,125,125,150,150,150,150,141,141,141,141,
+  140,140,140,140,121,121,121,121,133,133,133,133,134,134,134,134,
+  138,138,138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63,
+   80, 80, 80, 80,127,127,127,127,115,115,115,115,103,103,103,103,
+  119,119,119,119,146,146,146,146, 99, 99, 99, 99,136,139,  0,  0,
+  136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,105,105,
+    0,  0,  0,  1,  0,  0,  1,  1,131,131,131,131,151,151,151,151,
+  152,152,152,152,113,113,113,113,132,132,132,132, 15,  0,  0,  0,
+   16, 50, 84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91,
+   85, 85,220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+    5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18,
+   19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0,
+   31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,
+    0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,
+    0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
+    0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,
+    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+   87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,
+  103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,
+  108,  0,109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,
+    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,118,119,120,121,  0,122,123,124,125,126,  0,127,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,152,153,154,155,156,157,  0,  0,
+    0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,
+    0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,168,169,  0,  0,  0,  0,170,171,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
+  188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,
+  204,205,  0,  0,  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,  2,  3,  4,
+};
+static const uint16_t
+_hb_ucd_u16[4800] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  35,   9,  42,  11,  11,  43,  44,  32,  45,  46,  47,  47,  48,
+    49,  50,  47,  47,  51,  32,  52,  53,  47,  47,  47,  47,  47,  54,  55,  56,
+    57,  58,  47,  32,  59,  47,  47,  47,  47,  47,  60,  53,  61,  47,  62,  63,
+    47,  64,  65,  66,  47,  67,  47,  47,  47,  47,  47,  47,  47,  68,  69,  32,
+    70,  47,  47,  71,  72,  73,  74,  75,  76,  47,  47,  77,  78,  79,  80,  81,
+    82,  47,  47,  83,  84,  85,  86,  87,  82,  47,  47,  77,  88,  47,  80,  89,
+    90,  47,  47,  91,  92,  93,  80,  94,  95,  47,  47,  96,  97,  98,  99, 100,
+   101,  47,  47, 102, 103, 104,  80, 105, 106,  47,  47,  91, 107, 108,  80, 109,
+    90,  47,  47, 110, 111, 112,  80, 113, 114,  47,  47,  47, 115, 116,  99, 117,
+    47,  47,  47, 118, 119, 120,  66,  66,  47,  47,  47, 121, 122, 123,  47,  47,
+   124, 125, 126, 127,  47,  47,  47, 128, 129,  32,  32, 130, 131, 132,  66,  66,
+    47,  47, 133, 134, 120, 135, 136, 137, 138, 139,   9,   9,   9,  11,  11, 140,
+    47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47, 141, 142, 143,
+    47, 144,   9,   9,   9,   9,   9, 145, 146,  47,  47,  47,  47,  47,  47,  47,
+    47,  47,  47,  47,  47,  47, 147,  47, 148, 149,  47,  47,  47,  47, 150, 151,
+    47, 152,  47, 153,  47, 152,  47, 152,  47,  47,  47, 154, 155, 156, 157, 143,
+   158, 157,  47,  47, 159,  47,  47,  47, 160,  47, 161,  47,  47,  47,  47,  47,
+    47,  47, 162, 163, 164,  47,  47,  47,  47,  47,  47,  47,  47, 165, 144, 144,
+    47, 166,  47,  47,  47, 167, 168, 169, 157, 157, 170, 171, 172, 172, 172, 172,
+   173,  47,  47, 174, 175, 120, 176, 177, 178,  47, 179,  61,  47,  47, 180, 181,
+    47,  47, 182, 183, 184,  61,  47, 185,  11,   9,   9,   9,  66, 186, 187, 188,
+    11,  11, 189,  27,  27,  27, 190, 191,  11, 192,  27,  27,  32,  32,  32,  32,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 193,  13,  13,  13,  13,  13,  13,
+   194, 194, 194, 194, 194, 195, 194,  11, 196, 196, 196, 197, 198, 199, 199, 198,
+   200, 201, 202, 203, 204, 205, 206, 207, 208,  27, 209, 209, 209, 210, 211,  32,
+   212, 213, 214, 215, 216, 143, 217, 217, 218, 219, 220, 144, 221, 222, 144, 223,
+   224, 224, 224, 224, 224, 224, 224, 224, 225, 144, 226, 144, 144, 144, 144, 227,
+   144, 228, 224, 229, 144, 230, 231, 144, 144, 144, 144, 144, 144, 144, 143, 143,
+   143, 232, 144, 144, 144, 144, 233, 143, 144, 144, 144, 144, 144, 144, 144, 144,
+   144, 144, 144, 234, 235, 144, 144, 236, 144, 144, 144, 144, 144, 144, 237, 144,
+   144, 144, 144, 144, 144, 144, 238, 239, 143, 240, 144, 144, 241, 224, 242, 224,
+   243, 244, 224, 224, 224, 245, 224, 246, 144, 144, 144, 224, 247, 144, 144, 144,
+     9,   9,   9,  11,  11,  11, 248, 249,  13,  13,  13,  13,  13,  13, 250, 251,
+    11,  11,  11,  47,  47,  47, 252, 253,  47,  47,  47,  47,  47,  47,  32,  32,
+   254, 255, 256, 257, 258,  66,  66,  66, 259, 260, 261, 262, 263,  47,  47,  47,
+    47, 264, 146,  47,  47,  47,  47, 265,  47, 266,  47,  47, 144, 144, 144,  47,
+   144, 144, 267, 144, 268, 269, 144, 144, 267, 144, 144, 269, 144, 144, 144, 144,
+    47,  47,  47,  47, 144, 144, 144, 144,  47, 270,  47,  47,  47,  47,  47,  47,
+    47, 144, 144, 144, 144,  47,  47, 185, 271,  47,  61,  47,  13,  13, 272, 273,
+    13, 274,  47,  47,  47,  47, 275, 276,  31, 277, 278, 279,  13,  13,  13, 280,
+   281, 282, 283, 284, 285,   9,   9, 286, 287,  47, 288, 289,  47,  47,  47, 290,
+   291,  47,  47, 292, 293, 157,  32, 294,  61,  47, 295,  47, 296, 297,  47,  47,
+    70,  47,  47, 298, 299, 300, 301,  61,  47,  47, 302, 303, 304, 305,  47, 306,
+    47,  47,  47, 307,  58, 308, 309, 310,  47,  47,  47,  11,  11, 311,  11,  11,
+    11,  11,  11,  11,  47,  47, 312, 157, 313, 313, 313, 313, 313, 313, 313, 313,
+   314, 314, 314, 314, 314, 314, 314, 314,  11, 315, 316,  47,  47,  47,  47,  47,
+    47,  47,  47, 317,  31, 318,  47,  47,  47,  47,  47, 319, 320,  47,  47,  47,
+    47,  47,  47,  47,  47,  47,  47, 321,  32, 322,  32, 323, 324, 325, 326,  47,
+    47,  47,  47,  47,  47,  47,  47, 327, 328,   2,   3,   4,   5, 329, 330, 331,
+    47, 332,  47,  47,  47,  47, 333, 334, 335, 143, 143, 336, 217, 217, 217, 337,
+   338, 144, 144, 144, 144, 144, 144, 339, 340, 340, 340, 340, 340, 340, 340, 340,
+    47,  47,  47,  47,  47,  47, 341, 143,  47,  47, 342,  47, 343,  47,  47,  60,
+    47, 344,  47,  47,  47, 345, 217, 217,   9,   9, 145,  11,  11,  47,  47,  47,
+    47,  47, 157,   9,   9, 145,  11,  11,  47,  47,  47,  47,  47,  47, 344,  66,
+    47,  47,  47,  47,  47, 346,  47, 347,  47,  47, 348, 143, 143, 143,  47, 349,
+    47, 350,  47, 344,  66,  66,  66,  66,  47,  47,  47, 351, 143, 143, 143, 143,
+   352,  47,  47, 353, 143,  66,  47, 354,  47, 355, 143, 143, 356,  47, 357,  66,
+    47,  47,  47, 358,  47, 359,  47, 359,  47, 358, 142, 143, 143, 143, 143, 143,
+     9,   9,   9,   9,  11,  11,  11, 360,  47,  47, 361, 157, 157, 157, 157, 157,
+   143, 143, 143, 143, 143, 143, 143, 143,  47, 355, 362,  47,  60, 363,  66,  66,
+   364,  47,  47, 353, 365, 366, 367, 368, 178,  47,  47, 369, 370,  47,  47, 157,
+    95,  47, 371, 372, 373,  47,  47, 374, 178,  47,  47, 375, 376, 377, 378, 143,
+    47,  47, 379, 380,  32,  32,  32,  32,  47,  47, 358,  47,  47, 381, 169, 157,
+    90,  47,  47, 110, 382, 383, 384,  32,  47,  47,  47, 385, 386, 387,  47,  47,
+    47,  47,  47, 388, 389, 157, 157, 157,  47,  47, 390, 391, 392, 393,  32,  32,
+    47,  47,  47, 394, 395, 157,  66,  66,  47,  47, 396, 397, 157, 157, 157, 157,
+    47, 141, 398, 399, 144, 144, 144, 144,  47,  47, 379, 400,  66,  66,  66,  66,
+     9,   9,   9,   9,  11,  11, 126, 401,  47,  47,  47,  47,  47, 402, 403, 404,
+   405,  47,  47, 406, 407, 408,  47,  47, 409, 410,  66,  66,  47,  47,  47,  47,
+    47,  47, 390, 411, 412, 126, 143, 413,  47, 152, 414, 415,  32,  32,  32,  32,
+    47,  47,  47, 352, 416, 157,  47,  47, 417, 418, 157, 157, 157, 157, 157, 157,
+    47,  47,  47,  47,  47,  47,  47, 419, 143, 143, 143, 143, 143, 420, 421, 422,
+   217, 217, 217, 217, 217, 217, 217,  66,  47,  47,  47, 206, 206, 206, 206, 206,
+    47,  47,  47,  47,  47,  47, 300,  66,  47,  47,  47,  47,  47,  47,  47, 423,
+    47,  47,  47, 424, 425, 426, 427,  47,   9,   9,   9,   9,   9,   9,  11,  11,
+   143, 428,  66,  66,  66,  66,  66,  66,  47,  47,  47,  47, 381, 429, 404, 404,
+   430, 431,  27,  27,  27,  27, 432,  27,  47, 433, 206, 206, 206, 206, 206, 206,
+   144, 144, 144, 144, 144, 144, 434, 435, 436, 144, 437, 144, 144, 144, 144, 144,
+   144, 144, 144, 144, 438, 144, 144, 144,   9, 439,  11, 440, 441,  11, 194,   9,
+   442, 443,   9, 444,  11,   9, 439,  11, 440, 441,  11, 194,   9, 442, 443,   9,
+   444,  11,   9, 439,  11, 440, 441,  11, 194,   9, 442, 443,   9, 444,  11,   9,
+   439,  11, 194,   9, 445, 446, 447, 448,  11, 449,   9, 450, 451, 452, 453,  11,
+   454,   9, 455,  11, 456, 157, 157, 157,  32,  32,  32, 457,  32,  32, 458, 459,
+   460, 461,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    47,  47,  47, 462, 463, 144, 144, 144,  47,  47,  47,  47,  47,  47, 464, 465,
+    47,  47,  47,  47, 348,  32,  32,  32,   9,   9, 442,  11, 466, 300,  66,  66,
+   143, 143, 467, 468, 143, 143, 143, 143, 143, 143, 469, 143, 143, 143, 143, 143,
+    47,  47,  47,  47,  47,  47,  47, 224, 143, 144, 144, 144, 144, 144, 144, 144,
+   144, 144, 144, 144, 144, 144, 144, 470, 206, 206, 206, 206, 206, 206, 206, 206,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
+  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
+   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
+  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
+     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
+  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
+  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
+  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
+  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
+  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
+  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
+   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
+     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
+  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
+  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
+     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
+  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
+     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
+     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
+  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
+     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
+     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
+     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
+     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
+  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
+     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
+     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
+     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
+     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
+     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
+  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
+   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
+  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
+  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
+  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
+  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
+  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
+     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
+  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
+  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
+     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
+    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
+     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
+     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
+   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
+  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
+  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
+  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
+  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
+  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
+  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
+     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
+  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
+  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
+  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
+     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
+   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
+   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
+   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
+   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
+   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
+  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
+  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1948,1949,
+  1950,1951,1952,1953,1954,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1955,1956,1957,1959,1958,
+  1960,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
+   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
+   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
+   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
+   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
+   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
+    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
+   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
+   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
+   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
+   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
+   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
+   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
+    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
+   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
+   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
+   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
+   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
+   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
+   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
+   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
+   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[92] =
+{
+      0,    0,    1,   -1,    2,    0,   -2,    0,    0,    2,    0,   -2,    0,   16,    0,  -16,
+      0,    1,   -1,    0,    3,    3,    3,   -3,   -3,   -3,    0, 2016,    0, 2527, 1923, 1914,
+   1918,    0, 2250,    0,    0,  138,    0,    7,   -7,    0,   -1,    1, 1824,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,   -1, -138,    8,    8,    8,    0,    7,    7,   -8,   -8,
+     -8,   -7,-1316,    1,   -1,    3,   -3,    1,    0,-1914,-1918,    0,    0,-1923,-1824,    0,
+      0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114112u?_hb_ucd_u8[4840+(((_hb_ucd_u8[1072+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[6670+(((_hb_ucd_u8[6166+(((_hb_ucd_u8[5754+(((_hb_ucd_u8[5306+(((_hb_ucd_u8[5182+(u>>2>>2>>2>>4)])<<4)+((u>>2>>2>>2)&15u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7538+(((_hb_ucd_u8[7314+(((_hb_ucd_u8[7218+(((_hb_ucd_b4(7154+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918016u?_hb_ucd_u8[11048+(((_hb_ucd_u8[10132+(((_hb_ucd_u8[8788+(((_hb_ucd_u8[8228+(((_hb_ucd_u8[7778+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[1504+(((_hb_ucd_u8[12048+(((_hb_ucd_b4(11952+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0;
+}
+
+#endif
+
+
+#endif /* HB_UCD_TABLE_HH */
+
+/* == End of generated table == */
diff --git a/src/hb-ucd.cc b/src/hb-ucd.cc
new file mode 100644
index 0000000..b29f2a9
--- /dev/null
+++ b/src/hb-ucd.cc
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hb.hh"
+#include "hb-unicode.hh"
+#include "hb-machinery.hh"
+
+#include "hb-ucd-table.hh"
+
+static hb_unicode_combining_class_t
+hb_ucd_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			hb_codepoint_t unicode,
+			void *user_data HB_UNUSED)
+{
+  return (hb_unicode_combining_class_t) _hb_ucd_ccc (unicode);
+}
+
+static hb_unicode_general_category_t
+hb_ucd_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			 hb_codepoint_t unicode,
+			 void *user_data HB_UNUSED)
+{
+  return (hb_unicode_general_category_t) _hb_ucd_gc (unicode);
+}
+
+static hb_codepoint_t
+hb_ucd_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+		  hb_codepoint_t unicode,
+		  void *user_data HB_UNUSED)
+{
+  return unicode + _hb_ucd_bmg (unicode);
+}
+
+static hb_script_t
+hb_ucd_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+	       hb_codepoint_t unicode,
+	       void *user_data HB_UNUSED)
+{
+  return _hb_ucd_sc_map[_hb_ucd_sc (unicode)];
+}
+
+
+#define SBASE 0xAC00u
+#define LBASE 0x1100u
+#define VBASE 0x1161u
+#define TBASE 0x11A7u
+#define SCOUNT 11172u
+#define LCOUNT 19u
+#define VCOUNT 21u
+#define TCOUNT 28u
+#define NCOUNT (VCOUNT * TCOUNT)
+
+static inline bool
+_hb_ucd_decompose_hangul (hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b)
+{
+  unsigned si = ab - SBASE;
+
+  if (si >= SCOUNT)
+    return false;
+
+  if (si % TCOUNT)
+  {
+    /* LV,T */
+    *a = SBASE + (si / TCOUNT) * TCOUNT;
+    *b = TBASE + (si % TCOUNT);
+    return true;
+  } else {
+    /* L,V */
+    *a = LBASE + (si / NCOUNT);
+    *b = VBASE + (si % NCOUNT) / TCOUNT;
+    return true;
+  }
+}
+
+static inline bool
+_hb_ucd_compose_hangul (hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab)
+{
+  if (a >= SBASE && a < (SBASE + SCOUNT) && b > TBASE && b < (TBASE + TCOUNT) &&
+    !((a - SBASE) % TCOUNT))
+  {
+    /* LV,T */
+    *ab = a + (b - TBASE);
+    return true;
+  }
+  else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT))
+  {
+    /* L,V */
+    int li = a - LBASE;
+    int vi = b - VBASE;
+    *ab = SBASE + li * NCOUNT + vi * TCOUNT;
+    return true;
+  }
+  else
+    return false;
+}
+
+static int
+_cmp_pair (const void *_key, const void *_item)
+{
+  uint64_t& a = * (uint64_t*) _key;
+  uint64_t b = (* (uint64_t*) _item) & HB_CODEPOINT_ENCODE3(0x1FFFFFu, 0x1FFFFFu, 0);
+
+  return a < b ? -1 : a > b ? +1 : 0;
+}
+static int
+_cmp_pair_11_7_14 (const void *_key, const void *_item)
+{
+  uint32_t& a = * (uint32_t*) _key;
+  uint32_t b = (* (uint32_t*) _item) & HB_CODEPOINT_ENCODE3_11_7_14(0x1FFFFFu, 0x1FFFFFu, 0);
+
+  return a < b ? -1 : a > b ? +1 : 0;
+}
+
+static hb_bool_t
+hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+		hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
+		void *user_data HB_UNUSED)
+{
+  if (_hb_ucd_compose_hangul (a, b, ab)) return true;
+
+  hb_codepoint_t u = 0;
+
+  if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
+  {
+    uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
+    uint32_t *v = (uint32_t*) hb_bsearch (&k, _hb_ucd_dm2_u32_map,
+					  ARRAY_LENGTH (_hb_ucd_dm2_u32_map),
+					  sizeof (*_hb_ucd_dm2_u32_map),
+					  _cmp_pair_11_7_14);
+    if (likely (!v)) return false;
+    u = HB_CODEPOINT_DECODE3_11_7_14_3 (*v);
+  }
+  else
+  {
+    uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
+    uint64_t *v = (uint64_t*) hb_bsearch (&k, _hb_ucd_dm2_u64_map,
+					  ARRAY_LENGTH (_hb_ucd_dm2_u64_map),
+					  sizeof (*_hb_ucd_dm2_u64_map),
+					  _cmp_pair);
+    if (likely (!v)) return false;
+    u = HB_CODEPOINT_DECODE3_3 (*v);
+  }
+
+  if (unlikely (!u)) return false;
+  *ab = u;
+  return true;
+}
+
+static hb_bool_t
+hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+		  hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
+		  void *user_data HB_UNUSED)
+{
+  if (_hb_ucd_decompose_hangul (ab, a, b)) return true;
+
+  unsigned i = _hb_ucd_dm (ab);
+
+  if (likely (!i)) return false;
+  i--;
+
+  if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map))
+  {
+    if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map))
+      *a = _hb_ucd_dm1_p0_map[i];
+    else
+    {
+      i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map);
+      *a = 0x20000 | _hb_ucd_dm1_p2_map[i];
+    }
+    *b = 0;
+    return true;
+  }
+  i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map);
+
+  if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map))
+  {
+    uint32_t v = _hb_ucd_dm2_u32_map[i];
+    *a = HB_CODEPOINT_DECODE3_11_7_14_1 (v);
+    *b = HB_CODEPOINT_DECODE3_11_7_14_2 (v);
+    return true;
+  }
+  i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map);
+
+  uint64_t v = _hb_ucd_dm2_u64_map[i];
+  *a = HB_CODEPOINT_DECODE3_1 (v);
+  *b = HB_CODEPOINT_DECODE3_2 (v);
+  return true;
+}
+
+
+#if HB_USE_ATEXIT
+static void free_static_ucd_funcs ();
+#endif
+
+static struct hb_ucd_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucd_unicode_funcs_lazy_loader_t>
+{
+  static hb_unicode_funcs_t *create ()
+  {
+    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
+
+    hb_unicode_funcs_set_combining_class_func (funcs, hb_ucd_combining_class, nullptr, nullptr);
+    hb_unicode_funcs_set_general_category_func (funcs, hb_ucd_general_category, nullptr, nullptr);
+    hb_unicode_funcs_set_mirroring_func (funcs, hb_ucd_mirroring, nullptr, nullptr);
+    hb_unicode_funcs_set_script_func (funcs, hb_ucd_script, nullptr, nullptr);
+    hb_unicode_funcs_set_compose_func (funcs, hb_ucd_compose, nullptr, nullptr);
+    hb_unicode_funcs_set_decompose_func (funcs, hb_ucd_decompose, nullptr, nullptr);
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+#if HB_USE_ATEXIT
+    atexit (free_static_ucd_funcs);
+#endif
+
+    return funcs;
+  }
+} static_ucd_funcs;
+
+#if HB_USE_ATEXIT
+static
+void free_static_ucd_funcs ()
+{
+  static_ucd_funcs.free_instance ();
+}
+#endif
+
+hb_unicode_funcs_t *
+hb_ucd_get_unicode_funcs ()
+{
+#ifdef HB_NO_UCD
+  return hb_unicode_funcs_get_empty ();
+#endif
+  return static_ucd_funcs.get_unconst ();
+}
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
deleted file mode 100644
index 534935f..0000000
--- a/src/hb-ucdn.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "hb.hh"
-
-#include "hb-machinery.hh"
-
-#include "ucdn.h"
-
-static const hb_script_t ucdn_script_translate[] =
-{
-    HB_SCRIPT_COMMON,
-    HB_SCRIPT_LATIN,
-    HB_SCRIPT_GREEK,
-    HB_SCRIPT_CYRILLIC,
-    HB_SCRIPT_ARMENIAN,
-    HB_SCRIPT_HEBREW,
-    HB_SCRIPT_ARABIC,
-    HB_SCRIPT_SYRIAC,
-    HB_SCRIPT_THAANA,
-    HB_SCRIPT_DEVANAGARI,
-    HB_SCRIPT_BENGALI,
-    HB_SCRIPT_GURMUKHI,
-    HB_SCRIPT_GUJARATI,
-    HB_SCRIPT_ORIYA,
-    HB_SCRIPT_TAMIL,
-    HB_SCRIPT_TELUGU,
-    HB_SCRIPT_KANNADA,
-    HB_SCRIPT_MALAYALAM,
-    HB_SCRIPT_SINHALA,
-    HB_SCRIPT_THAI,
-    HB_SCRIPT_LAO,
-    HB_SCRIPT_TIBETAN,
-    HB_SCRIPT_MYANMAR,
-    HB_SCRIPT_GEORGIAN,
-    HB_SCRIPT_HANGUL,
-    HB_SCRIPT_ETHIOPIC,
-    HB_SCRIPT_CHEROKEE,
-    HB_SCRIPT_CANADIAN_SYLLABICS,
-    HB_SCRIPT_OGHAM,
-    HB_SCRIPT_RUNIC,
-    HB_SCRIPT_KHMER,
-    HB_SCRIPT_MONGOLIAN,
-    HB_SCRIPT_HIRAGANA,
-    HB_SCRIPT_KATAKANA,
-    HB_SCRIPT_BOPOMOFO,
-    HB_SCRIPT_HAN,
-    HB_SCRIPT_YI,
-    HB_SCRIPT_OLD_ITALIC,
-    HB_SCRIPT_GOTHIC,
-    HB_SCRIPT_DESERET,
-    HB_SCRIPT_INHERITED,
-    HB_SCRIPT_TAGALOG,
-    HB_SCRIPT_HANUNOO,
-    HB_SCRIPT_BUHID,
-    HB_SCRIPT_TAGBANWA,
-    HB_SCRIPT_LIMBU,
-    HB_SCRIPT_TAI_LE,
-    HB_SCRIPT_LINEAR_B,
-    HB_SCRIPT_UGARITIC,
-    HB_SCRIPT_SHAVIAN,
-    HB_SCRIPT_OSMANYA,
-    HB_SCRIPT_CYPRIOT,
-    HB_SCRIPT_BRAILLE,
-    HB_SCRIPT_BUGINESE,
-    HB_SCRIPT_COPTIC,
-    HB_SCRIPT_NEW_TAI_LUE,
-    HB_SCRIPT_GLAGOLITIC,
-    HB_SCRIPT_TIFINAGH,
-    HB_SCRIPT_SYLOTI_NAGRI,
-    HB_SCRIPT_OLD_PERSIAN,
-    HB_SCRIPT_KHAROSHTHI,
-    HB_SCRIPT_BALINESE,
-    HB_SCRIPT_CUNEIFORM,
-    HB_SCRIPT_PHOENICIAN,
-    HB_SCRIPT_PHAGS_PA,
-    HB_SCRIPT_NKO,
-    HB_SCRIPT_SUNDANESE,
-    HB_SCRIPT_LEPCHA,
-    HB_SCRIPT_OL_CHIKI,
-    HB_SCRIPT_VAI,
-    HB_SCRIPT_SAURASHTRA,
-    HB_SCRIPT_KAYAH_LI,
-    HB_SCRIPT_REJANG,
-    HB_SCRIPT_LYCIAN,
-    HB_SCRIPT_CARIAN,
-    HB_SCRIPT_LYDIAN,
-    HB_SCRIPT_CHAM,
-    HB_SCRIPT_TAI_THAM,
-    HB_SCRIPT_TAI_VIET,
-    HB_SCRIPT_AVESTAN,
-    HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
-    HB_SCRIPT_SAMARITAN,
-    HB_SCRIPT_LISU,
-    HB_SCRIPT_BAMUM,
-    HB_SCRIPT_JAVANESE,
-    HB_SCRIPT_MEETEI_MAYEK,
-    HB_SCRIPT_IMPERIAL_ARAMAIC,
-    HB_SCRIPT_OLD_SOUTH_ARABIAN,
-    HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
-    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
-    HB_SCRIPT_OLD_TURKIC,
-    HB_SCRIPT_KAITHI,
-    HB_SCRIPT_BATAK,
-    HB_SCRIPT_BRAHMI,
-    HB_SCRIPT_MANDAIC,
-    HB_SCRIPT_CHAKMA,
-    HB_SCRIPT_MEROITIC_CURSIVE,
-    HB_SCRIPT_MEROITIC_HIEROGLYPHS,
-    HB_SCRIPT_MIAO,
-    HB_SCRIPT_SHARADA,
-    HB_SCRIPT_SORA_SOMPENG,
-    HB_SCRIPT_TAKRI,
-    HB_SCRIPT_UNKNOWN,
-    HB_SCRIPT_BASSA_VAH,
-    HB_SCRIPT_CAUCASIAN_ALBANIAN,
-    HB_SCRIPT_DUPLOYAN,
-    HB_SCRIPT_ELBASAN,
-    HB_SCRIPT_GRANTHA,
-    HB_SCRIPT_KHOJKI,
-    HB_SCRIPT_KHUDAWADI,
-    HB_SCRIPT_LINEAR_A,
-    HB_SCRIPT_MAHAJANI,
-    HB_SCRIPT_MANICHAEAN,
-    HB_SCRIPT_MENDE_KIKAKUI,
-    HB_SCRIPT_MODI,
-    HB_SCRIPT_MRO,
-    HB_SCRIPT_NABATAEAN,
-    HB_SCRIPT_OLD_NORTH_ARABIAN,
-    HB_SCRIPT_OLD_PERMIC,
-    HB_SCRIPT_PAHAWH_HMONG,
-    HB_SCRIPT_PALMYRENE,
-    HB_SCRIPT_PAU_CIN_HAU,
-    HB_SCRIPT_PSALTER_PAHLAVI,
-    HB_SCRIPT_SIDDHAM,
-    HB_SCRIPT_TIRHUTA,
-    HB_SCRIPT_WARANG_CITI,
-    HB_SCRIPT_AHOM,
-    HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
-    HB_SCRIPT_HATRAN,
-    HB_SCRIPT_MULTANI,
-    HB_SCRIPT_OLD_HUNGARIAN,
-    HB_SCRIPT_SIGNWRITING,
-    HB_SCRIPT_ADLAM,
-    HB_SCRIPT_BHAIKSUKI,
-    HB_SCRIPT_MARCHEN,
-    HB_SCRIPT_NEWA,
-    HB_SCRIPT_OSAGE,
-    HB_SCRIPT_TANGUT,
-    HB_SCRIPT_MASARAM_GONDI,
-    HB_SCRIPT_NUSHU,
-    HB_SCRIPT_SOYOMBO,
-    HB_SCRIPT_ZANABAZAR_SQUARE,
-    HB_SCRIPT_DOGRA,
-    HB_SCRIPT_GUNJALA_GONDI,
-    HB_SCRIPT_HANIFI_ROHINGYA,
-    HB_SCRIPT_MAKASAR,
-    HB_SCRIPT_MEDEFAIDRIN,
-    HB_SCRIPT_OLD_SOGDIAN,
-    HB_SCRIPT_SOGDIAN,
-};
-
-static hb_unicode_combining_class_t
-hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-			hb_codepoint_t unicode,
-			void *user_data HB_UNUSED)
-{
-    return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
-}
-
-static hb_unicode_general_category_t
-hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-			 hb_codepoint_t unicode,
-			 void *user_data HB_UNUSED)
-{
-    return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
-}
-
-static hb_codepoint_t
-hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-		  hb_codepoint_t unicode,
-		  void *user_data HB_UNUSED)
-{
-    return ucdn_mirror(unicode);
-}
-
-static hb_script_t
-hb_ucdn_script(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-	       hb_codepoint_t unicode,
-	       void *user_data HB_UNUSED)
-{
-    return ucdn_script_translate[ucdn_get_script(unicode)];
-}
-
-static hb_bool_t
-hb_ucdn_compose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-		hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
-		void *user_data HB_UNUSED)
-{
-    return ucdn_compose(ab, a, b);
-}
-
-static hb_bool_t
-hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-		  hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
-		  void *user_data HB_UNUSED)
-{
-    return ucdn_decompose(ab, a, b);
-}
-
-
-#if HB_USE_ATEXIT
-static void free_static_ucdn_funcs ();
-#endif
-
-static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t>
-{
-  static hb_unicode_funcs_t *create ()
-  {
-    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
-
-    hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr);
-    hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr);
-    hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr);
-    hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr);
-    hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr);
-    hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr);
-
-    hb_unicode_funcs_make_immutable (funcs);
-
-#if HB_USE_ATEXIT
-    atexit (free_static_ucdn_funcs);
-#endif
-
-    return funcs;
-  }
-} static_ucdn_funcs;
-
-#if HB_USE_ATEXIT
-static
-void free_static_ucdn_funcs ()
-{
-  static_ucdn_funcs.free_instance ();
-}
-#endif
-
-extern "C" HB_INTERNAL
-hb_unicode_funcs_t *
-hb_ucdn_get_unicode_funcs ();
-
-hb_unicode_funcs_t *
-hb_ucdn_get_unicode_funcs ()
-{
-  return static_ucdn_funcs.get_unconst ();
-}
diff --git a/src/hb-ucdn/COPYING b/src/hb-ucdn/COPYING
deleted file mode 100644
index be5205c..0000000
--- a/src/hb-ucdn/COPYING
+++ /dev/null
@@ -1,13 +0,0 @@
-The contents of this directory are licensed under the following terms:
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/src/hb-ucdn/Makefile.am b/src/hb-ucdn/Makefile.am
deleted file mode 100644
index 73b5502..0000000
--- a/src/hb-ucdn/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-noinst_LTLIBRARIES = libhb-ucdn.la
-
-include Makefile.sources
-
-libhb_ucdn_la_SOURCES = $(LIBHB_UCDN_sources)
-libhb_ucdn_la_CPPFLAGS = \
-	-I$(top_srcdir) \
-	-I$(top_srcdir)/src \
-	-I$(top_builddir)/src
-libhb_ucdn_la_LIBADD =
-
-EXTRA_DIST = README COPYING
-
--include $(top_srcdir)/git.mk
diff --git a/src/hb-ucdn/Makefile.sources b/src/hb-ucdn/Makefile.sources
deleted file mode 100644
index cb823b6..0000000
--- a/src/hb-ucdn/Makefile.sources
+++ /dev/null
@@ -1,7 +0,0 @@
-NULL =
-
-LIBHB_UCDN_sources = \
-	ucdn.h \
-	ucdn.c \
-	ucdn_db.h \
-	$(NULL)
diff --git a/src/hb-ucdn/README b/src/hb-ucdn/README
deleted file mode 100644
index 2203ae6..0000000
--- a/src/hb-ucdn/README
+++ /dev/null
@@ -1,40 +0,0 @@
-Contents of this directory are derived from UCDN:
-
-  https://github.com/grigorig/ucdn
-
-The original README follows:
-
-
-UCDN - Unicode Database and Normalization
-
-UCDN is a Unicode support library. Currently, it provides access
-to basic character properties contained in the Unicode Character
-Database and low-level normalization functions (pairwise canonical
-composition/decomposition and compatibility decomposition). More
-functionality might be provided in the future, such as additional
-properties, string normalization and encoding conversion.
-
-UCDN uses standard C89 with no particular dependencies or requirements
-except for stdint.h, and can be easily integrated into existing
-projects. However, it can also be used as a standalone library,
-and a CMake build script is provided for this. The first motivation
-behind UCDN development was to provide a standalone set of Unicode
-functions for the HarfBuzz OpenType shaping library. For this purpose,
-a HarfBuzz-specific wrapper is shipped along with it (hb-ucdn.h).
-
-UCDN is published under the ISC license, please see the license header
-in the C source code for more information. The makeunicodata.py script
-required for parsing Unicode database files is licensed under the
-PSF license, please see PYTHON-LICENSE for more information.
-
-UCDN was written by Grigori Goronzy <greg@kinoho.net>.
-
-How to Use
-
-Include ucdn.c, ucdn.h and ucdn_db.h in your project. Now, just use the
-functions as documented in ucdn.h.
-
-In some cases, it might be necessary to regenerate the Unicode
-database file. The script makeunicodedata.py (Python 3.x required)
-fetches the appropriate files and dumps the compressed database into
-ucdn_db.h.
diff --git a/src/hb-ucdn/ucdn.c b/src/hb-ucdn/ucdn.c
deleted file mode 100644
index 30747fe..0000000
--- a/src/hb-ucdn/ucdn.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "ucdn.h"
-
-typedef struct {
-    unsigned char category;
-    unsigned char combining;
-    unsigned char bidi_class;
-    unsigned char east_asian_width;
-    unsigned char script;
-    unsigned char linebreak_class;
-} UCDRecord;
-
-typedef struct {
-    unsigned short from, to;
-} MirrorPair;
-
-typedef struct {
-  unsigned short from, to;
-  unsigned char type;
-} BracketPair;
-
-typedef struct {
-    unsigned int start;
-    short count, index;
-} Reindex;
-
-#include "ucdn_db.h"
-
-/* constants required for Hangul (de)composition */
-#define SBASE 0xAC00
-#define LBASE 0x1100
-#define VBASE 0x1161
-#define TBASE 0x11A7
-#define SCOUNT 11172
-#define LCOUNT 19
-#define VCOUNT 21
-#define TCOUNT 28
-#define NCOUNT (VCOUNT * TCOUNT)
-
-static const UCDRecord *get_ucd_record(uint32_t code)
-{
-    int index, offset;
-
-    if (code >= 0x110000)
-        index = 0;
-    else {
-        index  = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1;
-        offset = (code >> SHIFT2) & ((1<<SHIFT1) - 1);
-        index  = index1[index + offset] << SHIFT2;
-        offset = code & ((1<<SHIFT2) - 1);
-        index  = index2[index + offset];
-    }
-
-    return &ucd_records[index];
-}
-
-static const unsigned short *get_decomp_record(uint32_t code)
-{
-    int index, offset;
-
-    if (code >= 0x110000)
-        index = 0;
-    else {
-        index  = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)]
-            << DECOMP_SHIFT1;
-        offset = (code >> DECOMP_SHIFT2) & ((1<<DECOMP_SHIFT1) - 1);
-        index  = decomp_index1[index + offset] << DECOMP_SHIFT2;
-        offset = code & ((1<<DECOMP_SHIFT2) - 1);
-        index  = decomp_index2[index + offset];
-    }
-
-    return &decomp_data[index];
-}
-
-static int compare_reindex(const void *a, const void *b)
-{
-    Reindex *ra = (Reindex *)a;
-    Reindex *rb = (Reindex *)b;
-
-    if (ra->start < rb->start)
-        return -1;
-    else if (ra->start > (rb->start + rb->count))
-        return 1;
-    else
-        return 0;
-}
-
-static int get_comp_index(uint32_t code, const Reindex *idx, size_t len)
-{
-    Reindex *res;
-    Reindex r = {0, 0, 0};
-    r.start = code;
-    res = (Reindex *) bsearch(&r, idx, len, sizeof(Reindex), compare_reindex);
-
-    if (res != NULL)
-        return res->index + (code - res->start);
-    else
-        return -1;
-}
-
-static int compare_mp(const void *a, const void *b)
-{
-    MirrorPair *mpa = (MirrorPair *)a;
-    MirrorPair *mpb = (MirrorPair *)b;
-    return mpa->from - mpb->from;
-}
-
-static int compare_bp(const void *a, const void *b)
-{
-    BracketPair *bpa = (BracketPair *)a;
-    BracketPair *bpb = (BracketPair *)b;
-    return bpa->from - bpb->from;
-}
-
-static BracketPair *search_bp(uint32_t code)
-{
-    BracketPair bp = {0,0,2};
-    BracketPair *res;
-
-    bp.from = code;
-    res = (BracketPair *) bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN,
-                                 sizeof(BracketPair), compare_bp);
-    return res;
-}
-
-static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b)
-{
-    int si = code - SBASE;
-
-    if (si < 0 || si >= SCOUNT)
-        return 0;
-
-    if (si % TCOUNT) {
-        /* LV,T */
-        *a = SBASE + (si / TCOUNT) * TCOUNT;
-        *b = TBASE + (si % TCOUNT);
-        return 3;
-    } else {
-        /* L,V */
-        *a = LBASE + (si / NCOUNT);
-        *b = VBASE + (si % NCOUNT) / TCOUNT;
-        return 2;
-    }
-}
-
-static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
-{
-    if (a >= SBASE && a < (SBASE + SCOUNT) && b >= TBASE && b < (TBASE + TCOUNT)) {
-        /* LV,T */
-        *code = a + (b - TBASE);
-        return 3;
-    } else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT)) {
-        /* L,V */
-        int li = a - LBASE;
-        int vi = b - VBASE;
-        *code = SBASE + li * NCOUNT + vi * TCOUNT;
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-static uint32_t decode_utf16(const unsigned short **code_ptr)
-{
-    const unsigned short *code = *code_ptr;
-
-    if (code[0] < 0xd800 || code[0] > 0xdc00) {
-        *code_ptr += 1;
-        return (uint32_t)code[0];
-    } else {
-        *code_ptr += 2;
-        return 0x10000 + ((uint32_t)code[1] - 0xdc00) +
-            (((uint32_t)code[0] - 0xd800) << 10);
-    }
-}
-
-const char *ucdn_get_unicode_version(void)
-{
-    return UNIDATA_VERSION;
-}
-
-int ucdn_get_combining_class(uint32_t code)
-{
-    return get_ucd_record(code)->combining;
-}
-
-int ucdn_get_east_asian_width(uint32_t code)
-{
-    return get_ucd_record(code)->east_asian_width;
-}
-
-int ucdn_get_general_category(uint32_t code)
-{
-    return get_ucd_record(code)->category;
-}
-
-int ucdn_get_bidi_class(uint32_t code)
-{
-    return get_ucd_record(code)->bidi_class;
-}
-
-int ucdn_get_mirrored(uint32_t code)
-{
-    return ucdn_mirror(code) != code;
-}
-
-int ucdn_get_script(uint32_t code)
-{
-    return get_ucd_record(code)->script;
-}
-
-int ucdn_get_linebreak_class(uint32_t code)
-{
-    return get_ucd_record(code)->linebreak_class;
-}
-
-int ucdn_get_resolved_linebreak_class(uint32_t code)
-{
-    const UCDRecord *record = get_ucd_record(code);
-
-    switch (record->linebreak_class)
-    {
-    case UCDN_LINEBREAK_CLASS_AI:
-    case UCDN_LINEBREAK_CLASS_SG:
-    case UCDN_LINEBREAK_CLASS_XX:
-        return UCDN_LINEBREAK_CLASS_AL;
-
-    case UCDN_LINEBREAK_CLASS_SA:
-        if (record->category == UCDN_GENERAL_CATEGORY_MC ||
-                record->category == UCDN_GENERAL_CATEGORY_MN)
-            return UCDN_LINEBREAK_CLASS_CM;
-        return UCDN_LINEBREAK_CLASS_AL;
-
-    case UCDN_LINEBREAK_CLASS_CJ:
-        return UCDN_LINEBREAK_CLASS_NS;
-
-    case UCDN_LINEBREAK_CLASS_CB:
-        return UCDN_LINEBREAK_CLASS_B2;
-
-    case UCDN_LINEBREAK_CLASS_NL:
-        return UCDN_LINEBREAK_CLASS_BK;
-
-    default:
-        return record->linebreak_class;
-    }
-}
-
-uint32_t ucdn_mirror(uint32_t code)
-{
-    MirrorPair mp = {0};
-    MirrorPair *res;
-
-    mp.from = code;
-    res = (MirrorPair *) bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN,
-                                sizeof(MirrorPair), compare_mp);
-
-    if (res == NULL)
-        return code;
-    else
-        return res->to;
-}
-
-uint32_t ucdn_paired_bracket(uint32_t code)
-{
-    BracketPair *res = search_bp(code);
-    if (res == NULL)
-        return code;
-    else
-        return res->to;
-}
-
-int ucdn_paired_bracket_type(uint32_t code)
-{
-    BracketPair *res = search_bp(code);
-    if (res == NULL)
-        return UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE;
-    else
-        return res->type;
-}
-
-int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
-{
-    const unsigned short *rec;
-    int len;
-
-    if (hangul_pair_decompose(code, a, b))
-        return 1;
-
-    rec = get_decomp_record(code);
-    len = rec[0] >> 8;
-
-    if ((rec[0] & 0xff) != 0 || len == 0)
-        return 0;
-
-    rec++;
-    *a = decode_utf16(&rec);
-    if (len > 1)
-        *b = decode_utf16(&rec);
-    else
-        *b = 0;
-
-    return 1;
-}
-
-int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
-{
-    int l, r, index, indexi, offset;
-
-    if (hangul_pair_compose(code, a, b))
-        return 1;
-
-    l = get_comp_index(a, nfc_first, sizeof(nfc_first) / sizeof(Reindex));
-    r = get_comp_index(b, nfc_last, sizeof(nfc_last) / sizeof(Reindex));
-
-    if (l < 0 || r < 0)
-        return 0;
-
-    indexi = l * TOTAL_LAST + r;
-    index  = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1;
-    offset = (indexi >> COMP_SHIFT2) & ((1<<COMP_SHIFT1) - 1);
-    index  = comp_index1[index + offset] << COMP_SHIFT2;
-    offset = indexi & ((1<<COMP_SHIFT2) - 1);
-    *code  = comp_data[index + offset];
-
-    return *code != 0;
-}
-
-int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
-{
-    int i, len;
-    const unsigned short *rec = get_decomp_record(code);
-    len = rec[0] >> 8;
-
-    if (len == 0)
-        return 0;
-
-    rec++;
-    for (i = 0; i < len; i++)
-        decomposed[i] = decode_utf16(&rec);
-
-    return len;
-}
diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h
deleted file mode 100644
index 05d46d2..0000000
--- a/src/hb-ucdn/ucdn.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef UCDN_H
-#define UCDN_H
-
-
-
-#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
-# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)")
-# define HB_END_VISIBILITY _Pragma ("GCC visibility pop")
-#else
-# define HB_BEGIN_VISIBILITY
-# define HB_END_VISIBILITY
-#endif
-#ifdef __cplusplus
-# define HB_BEGIN_HEADER  extern "C" { HB_BEGIN_VISIBILITY
-# define HB_END_HEADER  HB_END_VISIBILITY }
-#else
-# define HB_BEGIN_HEADER  HB_BEGIN_VISIBILITY
-# define HB_END_HEADER  HB_END_VISIBILITY
-#endif
-
-HB_BEGIN_HEADER
-
-#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
-    defined (_sgi) || defined (__sun) || defined (sun) || \
-    defined (__digital__) || defined (__HP_cc)
-#  include <inttypes.h>
-#elif defined (_AIX)
-#  include <sys/inttypes.h>
-#elif defined (_MSC_VER) && _MSC_VER < 1600
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-#  include <stdint.h>
-#endif
-
-
-#define UCDN_EAST_ASIAN_F 0
-#define UCDN_EAST_ASIAN_H 1
-#define UCDN_EAST_ASIAN_W 2
-#define UCDN_EAST_ASIAN_NA 3
-#define UCDN_EAST_ASIAN_A 4
-#define UCDN_EAST_ASIAN_N 5
-
-#define UCDN_SCRIPT_COMMON 0
-#define UCDN_SCRIPT_LATIN 1
-#define UCDN_SCRIPT_GREEK 2
-#define UCDN_SCRIPT_CYRILLIC 3
-#define UCDN_SCRIPT_ARMENIAN 4
-#define UCDN_SCRIPT_HEBREW 5
-#define UCDN_SCRIPT_ARABIC 6
-#define UCDN_SCRIPT_SYRIAC 7
-#define UCDN_SCRIPT_THAANA 8
-#define UCDN_SCRIPT_DEVANAGARI 9
-#define UCDN_SCRIPT_BENGALI 10
-#define UCDN_SCRIPT_GURMUKHI 11
-#define UCDN_SCRIPT_GUJARATI 12
-#define UCDN_SCRIPT_ORIYA 13
-#define UCDN_SCRIPT_TAMIL 14
-#define UCDN_SCRIPT_TELUGU 15
-#define UCDN_SCRIPT_KANNADA 16
-#define UCDN_SCRIPT_MALAYALAM 17
-#define UCDN_SCRIPT_SINHALA 18
-#define UCDN_SCRIPT_THAI 19
-#define UCDN_SCRIPT_LAO 20
-#define UCDN_SCRIPT_TIBETAN 21
-#define UCDN_SCRIPT_MYANMAR 22
-#define UCDN_SCRIPT_GEORGIAN 23
-#define UCDN_SCRIPT_HANGUL 24
-#define UCDN_SCRIPT_ETHIOPIC 25
-#define UCDN_SCRIPT_CHEROKEE 26
-#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
-#define UCDN_SCRIPT_OGHAM 28
-#define UCDN_SCRIPT_RUNIC 29
-#define UCDN_SCRIPT_KHMER 30
-#define UCDN_SCRIPT_MONGOLIAN 31
-#define UCDN_SCRIPT_HIRAGANA 32
-#define UCDN_SCRIPT_KATAKANA 33
-#define UCDN_SCRIPT_BOPOMOFO 34
-#define UCDN_SCRIPT_HAN 35
-#define UCDN_SCRIPT_YI 36
-#define UCDN_SCRIPT_OLD_ITALIC 37
-#define UCDN_SCRIPT_GOTHIC 38
-#define UCDN_SCRIPT_DESERET 39
-#define UCDN_SCRIPT_INHERITED 40
-#define UCDN_SCRIPT_TAGALOG 41
-#define UCDN_SCRIPT_HANUNOO 42
-#define UCDN_SCRIPT_BUHID 43
-#define UCDN_SCRIPT_TAGBANWA 44
-#define UCDN_SCRIPT_LIMBU 45
-#define UCDN_SCRIPT_TAI_LE 46
-#define UCDN_SCRIPT_LINEAR_B 47
-#define UCDN_SCRIPT_UGARITIC 48
-#define UCDN_SCRIPT_SHAVIAN 49
-#define UCDN_SCRIPT_OSMANYA 50
-#define UCDN_SCRIPT_CYPRIOT 51
-#define UCDN_SCRIPT_BRAILLE 52
-#define UCDN_SCRIPT_BUGINESE 53
-#define UCDN_SCRIPT_COPTIC 54
-#define UCDN_SCRIPT_NEW_TAI_LUE 55
-#define UCDN_SCRIPT_GLAGOLITIC 56
-#define UCDN_SCRIPT_TIFINAGH 57
-#define UCDN_SCRIPT_SYLOTI_NAGRI 58
-#define UCDN_SCRIPT_OLD_PERSIAN 59
-#define UCDN_SCRIPT_KHAROSHTHI 60
-#define UCDN_SCRIPT_BALINESE 61
-#define UCDN_SCRIPT_CUNEIFORM 62
-#define UCDN_SCRIPT_PHOENICIAN 63
-#define UCDN_SCRIPT_PHAGS_PA 64
-#define UCDN_SCRIPT_NKO 65
-#define UCDN_SCRIPT_SUNDANESE 66
-#define UCDN_SCRIPT_LEPCHA 67
-#define UCDN_SCRIPT_OL_CHIKI 68
-#define UCDN_SCRIPT_VAI 69
-#define UCDN_SCRIPT_SAURASHTRA 70
-#define UCDN_SCRIPT_KAYAH_LI 71
-#define UCDN_SCRIPT_REJANG 72
-#define UCDN_SCRIPT_LYCIAN 73
-#define UCDN_SCRIPT_CARIAN 74
-#define UCDN_SCRIPT_LYDIAN 75
-#define UCDN_SCRIPT_CHAM 76
-#define UCDN_SCRIPT_TAI_THAM 77
-#define UCDN_SCRIPT_TAI_VIET 78
-#define UCDN_SCRIPT_AVESTAN 79
-#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
-#define UCDN_SCRIPT_SAMARITAN 81
-#define UCDN_SCRIPT_LISU 82
-#define UCDN_SCRIPT_BAMUM 83
-#define UCDN_SCRIPT_JAVANESE 84
-#define UCDN_SCRIPT_MEETEI_MAYEK 85
-#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
-#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
-#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
-#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
-#define UCDN_SCRIPT_OLD_TURKIC 90
-#define UCDN_SCRIPT_KAITHI 91
-#define UCDN_SCRIPT_BATAK 92
-#define UCDN_SCRIPT_BRAHMI 93
-#define UCDN_SCRIPT_MANDAIC 94
-#define UCDN_SCRIPT_CHAKMA 95
-#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
-#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
-#define UCDN_SCRIPT_MIAO 98
-#define UCDN_SCRIPT_SHARADA 99
-#define UCDN_SCRIPT_SORA_SOMPENG 100
-#define UCDN_SCRIPT_TAKRI 101
-#define UCDN_SCRIPT_UNKNOWN 102
-#define UCDN_SCRIPT_BASSA_VAH 103
-#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
-#define UCDN_SCRIPT_DUPLOYAN 105
-#define UCDN_SCRIPT_ELBASAN 106
-#define UCDN_SCRIPT_GRANTHA 107
-#define UCDN_SCRIPT_KHOJKI 108
-#define UCDN_SCRIPT_KHUDAWADI 109
-#define UCDN_SCRIPT_LINEAR_A 110
-#define UCDN_SCRIPT_MAHAJANI 111
-#define UCDN_SCRIPT_MANICHAEAN 112
-#define UCDN_SCRIPT_MENDE_KIKAKUI 113
-#define UCDN_SCRIPT_MODI 114
-#define UCDN_SCRIPT_MRO 115
-#define UCDN_SCRIPT_NABATAEAN 116
-#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
-#define UCDN_SCRIPT_OLD_PERMIC 118
-#define UCDN_SCRIPT_PAHAWH_HMONG 119
-#define UCDN_SCRIPT_PALMYRENE 120
-#define UCDN_SCRIPT_PAU_CIN_HAU 121
-#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
-#define UCDN_SCRIPT_SIDDHAM 123
-#define UCDN_SCRIPT_TIRHUTA 124
-#define UCDN_SCRIPT_WARANG_CITI 125
-#define UCDN_SCRIPT_AHOM 126
-#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
-#define UCDN_SCRIPT_HATRAN 128
-#define UCDN_SCRIPT_MULTANI 129
-#define UCDN_SCRIPT_OLD_HUNGARIAN 130
-#define UCDN_SCRIPT_SIGNWRITING 131
-#define UCDN_SCRIPT_ADLAM 132
-#define UCDN_SCRIPT_BHAIKSUKI 133
-#define UCDN_SCRIPT_MARCHEN 134
-#define UCDN_SCRIPT_NEWA 135
-#define UCDN_SCRIPT_OSAGE 136
-#define UCDN_SCRIPT_TANGUT 137
-#define UCDN_SCRIPT_MASARAM_GONDI 138
-#define UCDN_SCRIPT_NUSHU 139
-#define UCDN_SCRIPT_SOYOMBO 140
-#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141
-
-#define UCDN_LINEBREAK_CLASS_OP 0
-#define UCDN_LINEBREAK_CLASS_CL 1
-#define UCDN_LINEBREAK_CLASS_CP 2
-#define UCDN_LINEBREAK_CLASS_QU 3
-#define UCDN_LINEBREAK_CLASS_GL 4
-#define UCDN_LINEBREAK_CLASS_NS 5
-#define UCDN_LINEBREAK_CLASS_EX 6
-#define UCDN_LINEBREAK_CLASS_SY 7
-#define UCDN_LINEBREAK_CLASS_IS 8
-#define UCDN_LINEBREAK_CLASS_PR 9
-#define UCDN_LINEBREAK_CLASS_PO 10
-#define UCDN_LINEBREAK_CLASS_NU 11
-#define UCDN_LINEBREAK_CLASS_AL 12
-#define UCDN_LINEBREAK_CLASS_HL 13
-#define UCDN_LINEBREAK_CLASS_ID 14
-#define UCDN_LINEBREAK_CLASS_IN 15
-#define UCDN_LINEBREAK_CLASS_HY 16
-#define UCDN_LINEBREAK_CLASS_BA 17
-#define UCDN_LINEBREAK_CLASS_BB 18
-#define UCDN_LINEBREAK_CLASS_B2 19
-#define UCDN_LINEBREAK_CLASS_ZW 20
-#define UCDN_LINEBREAK_CLASS_CM 21
-#define UCDN_LINEBREAK_CLASS_WJ 22
-#define UCDN_LINEBREAK_CLASS_H2 23
-#define UCDN_LINEBREAK_CLASS_H3 24
-#define UCDN_LINEBREAK_CLASS_JL 25
-#define UCDN_LINEBREAK_CLASS_JV 26
-#define UCDN_LINEBREAK_CLASS_JT 27
-#define UCDN_LINEBREAK_CLASS_RI 28
-#define UCDN_LINEBREAK_CLASS_AI 29
-#define UCDN_LINEBREAK_CLASS_BK 30
-#define UCDN_LINEBREAK_CLASS_CB 31
-#define UCDN_LINEBREAK_CLASS_CJ 32
-#define UCDN_LINEBREAK_CLASS_CR 33
-#define UCDN_LINEBREAK_CLASS_LF 34
-#define UCDN_LINEBREAK_CLASS_NL 35
-#define UCDN_LINEBREAK_CLASS_SA 36
-#define UCDN_LINEBREAK_CLASS_SG 37
-#define UCDN_LINEBREAK_CLASS_SP 38
-#define UCDN_LINEBREAK_CLASS_XX 39
-#define UCDN_LINEBREAK_CLASS_ZWJ 40
-#define UCDN_LINEBREAK_CLASS_EB 41
-#define UCDN_LINEBREAK_CLASS_EM 42
-
-#define UCDN_GENERAL_CATEGORY_CC 0
-#define UCDN_GENERAL_CATEGORY_CF 1
-#define UCDN_GENERAL_CATEGORY_CN 2
-#define UCDN_GENERAL_CATEGORY_CO 3
-#define UCDN_GENERAL_CATEGORY_CS 4
-#define UCDN_GENERAL_CATEGORY_LL 5
-#define UCDN_GENERAL_CATEGORY_LM 6
-#define UCDN_GENERAL_CATEGORY_LO 7
-#define UCDN_GENERAL_CATEGORY_LT 8
-#define UCDN_GENERAL_CATEGORY_LU 9
-#define UCDN_GENERAL_CATEGORY_MC 10
-#define UCDN_GENERAL_CATEGORY_ME 11
-#define UCDN_GENERAL_CATEGORY_MN 12
-#define UCDN_GENERAL_CATEGORY_ND 13
-#define UCDN_GENERAL_CATEGORY_NL 14
-#define UCDN_GENERAL_CATEGORY_NO 15
-#define UCDN_GENERAL_CATEGORY_PC 16
-#define UCDN_GENERAL_CATEGORY_PD 17
-#define UCDN_GENERAL_CATEGORY_PE 18
-#define UCDN_GENERAL_CATEGORY_PF 19
-#define UCDN_GENERAL_CATEGORY_PI 20
-#define UCDN_GENERAL_CATEGORY_PO 21
-#define UCDN_GENERAL_CATEGORY_PS 22
-#define UCDN_GENERAL_CATEGORY_SC 23
-#define UCDN_GENERAL_CATEGORY_SK 24
-#define UCDN_GENERAL_CATEGORY_SM 25
-#define UCDN_GENERAL_CATEGORY_SO 26
-#define UCDN_GENERAL_CATEGORY_ZL 27
-#define UCDN_GENERAL_CATEGORY_ZP 28
-#define UCDN_GENERAL_CATEGORY_ZS 29
-
-#define UCDN_BIDI_CLASS_L 0
-#define UCDN_BIDI_CLASS_LRE 1
-#define UCDN_BIDI_CLASS_LRO 2
-#define UCDN_BIDI_CLASS_R 3
-#define UCDN_BIDI_CLASS_AL 4
-#define UCDN_BIDI_CLASS_RLE 5
-#define UCDN_BIDI_CLASS_RLO 6
-#define UCDN_BIDI_CLASS_PDF 7
-#define UCDN_BIDI_CLASS_EN 8
-#define UCDN_BIDI_CLASS_ES 9
-#define UCDN_BIDI_CLASS_ET 10
-#define UCDN_BIDI_CLASS_AN 11
-#define UCDN_BIDI_CLASS_CS 12
-#define UCDN_BIDI_CLASS_NSM 13
-#define UCDN_BIDI_CLASS_BN 14
-#define UCDN_BIDI_CLASS_B 15
-#define UCDN_BIDI_CLASS_S 16
-#define UCDN_BIDI_CLASS_WS 17
-#define UCDN_BIDI_CLASS_ON 18
-#define UCDN_BIDI_CLASS_LRI 19
-#define UCDN_BIDI_CLASS_RLI 20
-#define UCDN_BIDI_CLASS_FSI 21
-#define UCDN_BIDI_CLASS_PDI 22
-
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_OPEN 0
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_CLOSE 1
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE 2
-
-/**
- * Return version of the Unicode database.
- *
- * @return Unicode database version
- */
-const char *ucdn_get_unicode_version(void);
-
-/**
- * Get combining class of a codepoint.
- *
- * @param code Unicode codepoint
- * @return combining class value, as defined in UAX#44
- */
-int ucdn_get_combining_class(uint32_t code);
-
-/**
- * Get east-asian width of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11.
- */
-int ucdn_get_east_asian_width(uint32_t code);
-
-/**
- * Get general category of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in
- * UAX#44.
- */
-int ucdn_get_general_category(uint32_t code);
-
-/**
- * Get bidirectional class of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44.
- */
-int ucdn_get_bidi_class(uint32_t code);
-
-/**
- * Get script of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_SCRIPT_* and as defined in UAX#24.
- */
-int ucdn_get_script(uint32_t code);
-
-/**
- * Get unresolved linebreak class of a codepoint. This does not take
- * rule LB1 of UAX#14 into account. See ucdn_get_resolved_linebreak_class()
- * for resolved linebreak classes.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
- */
-int ucdn_get_linebreak_class(uint32_t code);
-
-/**
- * Get resolved linebreak class of a codepoint. This resolves characters
- * in the AI, SG, XX, SA and CJ classes according to rule LB1 of UAX#14.
- * In addition the CB class is resolved as the equivalent B2 class and
- * the NL class is resolved as the equivalent BK class.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
- */
-int ucdn_get_resolved_linebreak_class(uint32_t code);
-
-/**
- * Check if codepoint can be mirrored.
- *
- * @param code Unicode codepoint
- * @return 1 if mirrored character exists, otherwise 0
- */
-int ucdn_get_mirrored(uint32_t code);
-
-/**
- * Mirror a codepoint.
- *
- * @param code Unicode codepoint
- * @return mirrored codepoint or the original codepoint if no
- * mirrored character exists
- */
-uint32_t ucdn_mirror(uint32_t code);
-
-/**
- * Get paired bracket for a codepoint.
- *
- * @param code Unicode codepoint
- * @return paired bracket codepoint or the original codepoint if no
- * paired bracket character exists
- */
-uint32_t ucdn_paired_bracket(uint32_t code);
-
-/**
- * Get paired bracket type for a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_BIDI_PAIRED_BRACKET_TYPE_* and as defined
- * in UAX#9.
- *
- */
-int ucdn_paired_bracket_type(uint32_t code);
-
-/**
- * Pairwise canonical decomposition of a codepoint. This includes
- * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core
- * specification).
- *
- * Hangul is decomposed into L and V jamos for LV forms, and an
- * LV precomposed syllable and a T jamo for LVT forms.
- *
- * @param code Unicode codepoint
- * @param a filled with first codepoint of decomposition
- * @param b filled with second codepoint of decomposition, or 0
- * @return success
- */
-int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b);
-
-/**
- * Compatibility decomposition of a codepoint.
- *
- * @param code Unicode codepoint
- * @param decomposed filled with decomposition, must be able to hold 18
- * characters
- * @return length of decomposition or 0 in case none exists
- */
-int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed);
-
-/**
- * Pairwise canonical composition of two codepoints. This includes
- * Hangul Jamo composition (see chapter 3.12 of the Unicode core
- * specification).
- *
- * Hangul composition expects either L and V jamos, or an LV
- * precomposed syllable and a T jamo. This is exactly the inverse
- * of pairwise Hangul decomposition.
- *
- * @param code filled with composition
- * @param a first codepoint
- * @param b second codepoint
- * @return success
- */
-int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b);
-
-HB_END_HEADER
-
-#endif
diff --git a/src/hb-ucdn/ucdn_db.h b/src/hb-ucdn/ucdn_db.h
deleted file mode 100644
index 87872b7..0000000
--- a/src/hb-ucdn/ucdn_db.h
+++ /dev/null
@@ -1,5730 +0,0 @@
-/* this file was generated by makeunicodedata.py 3.2 */
-
-#define UNIDATA_VERSION "11.0.0"
-/* a list of unique database records */
-static const UCDRecord ucd_records[] = {
-    {2, 0, 18, 5, 102, 39},
-    {0, 0, 14, 5, 0, 21},
-    {0, 0, 16, 5, 0, 17},
-    {0, 0, 15, 5, 0, 34},
-    {0, 0, 16, 5, 0, 30},
-    {0, 0, 17, 5, 0, 30},
-    {0, 0, 15, 5, 0, 33},
-    {0, 0, 15, 5, 0, 21},
-    {0, 0, 16, 5, 0, 21},
-    {29, 0, 17, 3, 0, 38},
-    {21, 0, 18, 3, 0, 6},
-    {21, 0, 18, 3, 0, 3},
-    {21, 0, 10, 3, 0, 12},
-    {23, 0, 10, 3, 0, 9},
-    {21, 0, 10, 3, 0, 10},
-    {21, 0, 18, 3, 0, 12},
-    {22, 0, 18, 3, 0, 0},
-    {18, 0, 18, 3, 0, 2},
-    {25, 0, 9, 3, 0, 9},
-    {21, 0, 12, 3, 0, 8},
-    {17, 0, 9, 3, 0, 16},
-    {21, 0, 12, 3, 0, 7},
-    {13, 0, 8, 3, 0, 11},
-    {21, 0, 18, 3, 0, 8},
-    {25, 0, 18, 3, 0, 12},
-    {9, 0, 0, 3, 1, 12},
-    {21, 0, 18, 3, 0, 9},
-    {24, 0, 18, 3, 0, 12},
-    {16, 0, 18, 3, 0, 12},
-    {5, 0, 0, 3, 1, 12},
-    {25, 0, 18, 3, 0, 17},
-    {18, 0, 18, 3, 0, 1},
-    {0, 0, 15, 5, 0, 35},
-    {29, 0, 12, 5, 0, 4},
-    {21, 0, 18, 4, 0, 0},
-    {23, 0, 10, 3, 0, 10},
-    {23, 0, 10, 4, 0, 9},
-    {26, 0, 18, 3, 0, 12},
-    {21, 0, 18, 4, 0, 29},
-    {24, 0, 18, 4, 0, 29},
-    {26, 0, 18, 5, 0, 12},
-    {7, 0, 0, 4, 1, 29},
-    {20, 0, 18, 5, 0, 3},
-    {1, 0, 14, 4, 0, 17},
-    {26, 0, 18, 4, 0, 12},
-    {26, 0, 10, 4, 0, 10},
-    {25, 0, 10, 4, 0, 9},
-    {15, 0, 8, 4, 0, 29},
-    {24, 0, 18, 4, 0, 18},
-    {5, 0, 0, 5, 0, 12},
-    {19, 0, 18, 5, 0, 3},
-    {15, 0, 18, 4, 0, 29},
-    {9, 0, 0, 5, 1, 12},
-    {9, 0, 0, 4, 1, 12},
-    {25, 0, 18, 4, 0, 29},
-    {5, 0, 0, 4, 1, 12},
-    {5, 0, 0, 5, 1, 12},
-    {7, 0, 0, 5, 1, 12},
-    {8, 0, 0, 5, 1, 12},
-    {6, 0, 0, 5, 1, 12},
-    {6, 0, 18, 5, 0, 12},
-    {6, 0, 0, 5, 0, 12},
-    {24, 0, 18, 5, 0, 12},
-    {24, 0, 18, 4, 0, 12},
-    {6, 0, 18, 4, 0, 29},
-    {6, 0, 18, 5, 0, 18},
-    {6, 0, 0, 4, 0, 29},
-    {24, 0, 18, 5, 34, 12},
-    {12, 230, 13, 4, 40, 21},
-    {12, 232, 13, 4, 40, 21},
-    {12, 220, 13, 4, 40, 21},
-    {12, 216, 13, 4, 40, 21},
-    {12, 202, 13, 4, 40, 21},
-    {12, 1, 13, 4, 40, 21},
-    {12, 240, 13, 4, 40, 21},
-    {12, 0, 13, 4, 40, 4},
-    {12, 233, 13, 4, 40, 4},
-    {12, 234, 13, 4, 40, 4},
-    {9, 0, 0, 5, 2, 12},
-    {5, 0, 0, 5, 2, 12},
-    {24, 0, 18, 5, 2, 12},
-    {2, 0, 18, 5, 102, 39},
-    {6, 0, 0, 5, 2, 12},
-    {21, 0, 18, 5, 0, 8},
-    {21, 0, 18, 5, 0, 12},
-    {9, 0, 0, 4, 2, 12},
-    {5, 0, 0, 4, 2, 12},
-    {9, 0, 0, 5, 54, 12},
-    {5, 0, 0, 5, 54, 12},
-    {25, 0, 18, 5, 2, 12},
-    {9, 0, 0, 5, 3, 12},
-    {9, 0, 0, 4, 3, 12},
-    {5, 0, 0, 4, 3, 12},
-    {5, 0, 0, 5, 3, 12},
-    {26, 0, 0, 5, 3, 12},
-    {12, 230, 13, 5, 3, 21},
-    {12, 230, 13, 5, 40, 21},
-    {11, 0, 13, 5, 3, 21},
-    {9, 0, 0, 5, 4, 12},
-    {6, 0, 0, 5, 4, 12},
-    {21, 0, 0, 5, 4, 12},
-    {5, 0, 0, 5, 4, 12},
-    {21, 0, 0, 5, 0, 8},
-    {17, 0, 18, 5, 4, 17},
-    {26, 0, 18, 5, 4, 12},
-    {23, 0, 10, 5, 4, 9},
-    {12, 220, 13, 5, 5, 21},
-    {12, 230, 13, 5, 5, 21},
-    {12, 222, 13, 5, 5, 21},
-    {12, 228, 13, 5, 5, 21},
-    {12, 10, 13, 5, 5, 21},
-    {12, 11, 13, 5, 5, 21},
-    {12, 12, 13, 5, 5, 21},
-    {12, 13, 13, 5, 5, 21},
-    {12, 14, 13, 5, 5, 21},
-    {12, 15, 13, 5, 5, 21},
-    {12, 16, 13, 5, 5, 21},
-    {12, 17, 13, 5, 5, 21},
-    {12, 18, 13, 5, 5, 21},
-    {12, 19, 13, 5, 5, 21},
-    {12, 20, 13, 5, 5, 21},
-    {12, 21, 13, 5, 5, 21},
-    {12, 22, 13, 5, 5, 21},
-    {17, 0, 3, 5, 5, 17},
-    {12, 23, 13, 5, 5, 21},
-    {21, 0, 3, 5, 5, 12},
-    {12, 24, 13, 5, 5, 21},
-    {12, 25, 13, 5, 5, 21},
-    {21, 0, 3, 5, 5, 6},
-    {7, 0, 3, 5, 5, 13},
-    {1, 0, 11, 5, 6, 12},
-    {1, 0, 11, 5, 0, 12},
-    {25, 0, 18, 5, 6, 12},
-    {25, 0, 4, 5, 6, 12},
-    {21, 0, 10, 5, 6, 10},
-    {23, 0, 4, 5, 6, 10},
-    {21, 0, 12, 5, 0, 8},
-    {21, 0, 4, 5, 6, 8},
-    {26, 0, 18, 5, 6, 12},
-    {12, 230, 13, 5, 6, 21},
-    {12, 30, 13, 5, 6, 21},
-    {12, 31, 13, 5, 6, 21},
-    {12, 32, 13, 5, 6, 21},
-    {21, 0, 4, 5, 0, 6},
-    {1, 0, 4, 5, 6, 21},
-    {21, 0, 4, 5, 6, 6},
-    {7, 0, 4, 5, 6, 12},
-    {6, 0, 4, 5, 0, 12},
-    {12, 27, 13, 5, 40, 21},
-    {12, 28, 13, 5, 40, 21},
-    {12, 29, 13, 5, 40, 21},
-    {12, 30, 13, 5, 40, 21},
-    {12, 31, 13, 5, 40, 21},
-    {12, 32, 13, 5, 40, 21},
-    {12, 33, 13, 5, 40, 21},
-    {12, 34, 13, 5, 40, 21},
-    {12, 220, 13, 5, 40, 21},
-    {12, 220, 13, 5, 6, 21},
-    {13, 0, 11, 5, 6, 11},
-    {21, 0, 11, 5, 6, 11},
-    {21, 0, 4, 5, 6, 12},
-    {12, 35, 13, 5, 40, 21},
-    {6, 0, 4, 5, 6, 12},
-    {13, 0, 8, 5, 6, 11},
-    {26, 0, 4, 5, 6, 12},
-    {21, 0, 4, 5, 7, 12},
-    {1, 0, 4, 5, 7, 12},
-    {7, 0, 4, 5, 7, 12},
-    {12, 36, 13, 5, 7, 21},
-    {12, 230, 13, 5, 7, 21},
-    {12, 220, 13, 5, 7, 21},
-    {7, 0, 4, 5, 8, 12},
-    {12, 0, 13, 5, 8, 21},
-    {13, 0, 3, 5, 65, 11},
-    {7, 0, 3, 5, 65, 12},
-    {12, 230, 13, 5, 65, 21},
-    {12, 220, 13, 5, 65, 21},
-    {6, 0, 3, 5, 65, 12},
-    {26, 0, 18, 5, 65, 12},
-    {21, 0, 18, 5, 65, 12},
-    {21, 0, 18, 5, 65, 8},
-    {21, 0, 18, 5, 65, 6},
-    {23, 0, 3, 5, 65, 9},
-    {7, 0, 3, 5, 81, 12},
-    {12, 230, 13, 5, 81, 21},
-    {6, 0, 3, 5, 81, 12},
-    {21, 0, 3, 5, 81, 12},
-    {7, 0, 3, 5, 94, 12},
-    {12, 220, 13, 5, 94, 21},
-    {21, 0, 3, 5, 94, 12},
-    {12, 27, 13, 5, 6, 21},
-    {12, 28, 13, 5, 6, 21},
-    {12, 29, 13, 5, 6, 21},
-    {12, 0, 13, 5, 9, 21},
-    {10, 0, 0, 5, 9, 21},
-    {7, 0, 0, 5, 9, 12},
-    {12, 7, 13, 5, 9, 21},
-    {12, 9, 13, 5, 9, 21},
-    {12, 230, 13, 5, 9, 21},
-    {21, 0, 0, 5, 0, 17},
-    {13, 0, 0, 5, 9, 11},
-    {21, 0, 0, 5, 9, 12},
-    {6, 0, 0, 5, 9, 12},
-    {7, 0, 0, 5, 10, 12},
-    {12, 0, 13, 5, 10, 21},
-    {10, 0, 0, 5, 10, 21},
-    {12, 7, 13, 5, 10, 21},
-    {12, 9, 13, 5, 10, 21},
-    {13, 0, 0, 5, 10, 11},
-    {23, 0, 10, 5, 10, 10},
-    {15, 0, 0, 5, 10, 12},
-    {15, 0, 0, 5, 10, 10},
-    {26, 0, 0, 5, 10, 12},
-    {23, 0, 10, 5, 10, 9},
-    {21, 0, 0, 5, 10, 12},
-    {12, 230, 13, 5, 10, 21},
-    {12, 0, 13, 5, 11, 21},
-    {10, 0, 0, 5, 11, 21},
-    {7, 0, 0, 5, 11, 12},
-    {12, 7, 13, 5, 11, 21},
-    {12, 9, 13, 5, 11, 21},
-    {13, 0, 0, 5, 11, 11},
-    {21, 0, 0, 5, 11, 12},
-    {12, 0, 13, 5, 12, 21},
-    {10, 0, 0, 5, 12, 21},
-    {7, 0, 0, 5, 12, 12},
-    {12, 7, 13, 5, 12, 21},
-    {12, 9, 13, 5, 12, 21},
-    {13, 0, 0, 5, 12, 11},
-    {21, 0, 0, 5, 12, 12},
-    {23, 0, 10, 5, 12, 9},
-    {12, 0, 13, 5, 13, 21},
-    {10, 0, 0, 5, 13, 21},
-    {7, 0, 0, 5, 13, 12},
-    {12, 7, 13, 5, 13, 21},
-    {12, 9, 13, 5, 13, 21},
-    {13, 0, 0, 5, 13, 11},
-    {26, 0, 0, 5, 13, 12},
-    {15, 0, 0, 5, 13, 12},
-    {12, 0, 13, 5, 14, 21},
-    {7, 0, 0, 5, 14, 12},
-    {10, 0, 0, 5, 14, 21},
-    {12, 9, 13, 5, 14, 21},
-    {13, 0, 0, 5, 14, 11},
-    {15, 0, 0, 5, 14, 12},
-    {26, 0, 18, 5, 14, 12},
-    {23, 0, 10, 5, 14, 9},
-    {12, 0, 13, 5, 15, 21},
-    {10, 0, 0, 5, 15, 21},
-    {7, 0, 0, 5, 15, 12},
-    {12, 9, 13, 5, 15, 21},
-    {12, 84, 13, 5, 15, 21},
-    {12, 91, 13, 5, 15, 21},
-    {13, 0, 0, 5, 15, 11},
-    {15, 0, 18, 5, 15, 12},
-    {26, 0, 0, 5, 15, 12},
-    {7, 0, 0, 5, 16, 12},
-    {12, 0, 13, 5, 16, 21},
-    {10, 0, 0, 5, 16, 21},
-    {21, 0, 0, 5, 16, 18},
-    {12, 7, 13, 5, 16, 21},
-    {12, 0, 0, 5, 16, 21},
-    {12, 9, 13, 5, 16, 21},
-    {13, 0, 0, 5, 16, 11},
-    {12, 0, 13, 5, 17, 21},
-    {10, 0, 0, 5, 17, 21},
-    {7, 0, 0, 5, 17, 12},
-    {12, 9, 13, 5, 17, 21},
-    {26, 0, 0, 5, 17, 12},
-    {15, 0, 0, 5, 17, 12},
-    {13, 0, 0, 5, 17, 11},
-    {26, 0, 0, 5, 17, 10},
-    {10, 0, 0, 5, 18, 21},
-    {7, 0, 0, 5, 18, 12},
-    {12, 9, 13, 5, 18, 21},
-    {12, 0, 13, 5, 18, 21},
-    {13, 0, 0, 5, 18, 11},
-    {21, 0, 0, 5, 18, 12},
-    {7, 0, 0, 5, 19, 36},
-    {12, 0, 13, 5, 19, 36},
-    {12, 103, 13, 5, 19, 36},
-    {12, 9, 13, 5, 19, 36},
-    {23, 0, 10, 5, 0, 9},
-    {6, 0, 0, 5, 19, 36},
-    {12, 107, 13, 5, 19, 36},
-    {21, 0, 0, 5, 19, 12},
-    {13, 0, 0, 5, 19, 11},
-    {21, 0, 0, 5, 19, 17},
-    {7, 0, 0, 5, 20, 36},
-    {12, 0, 13, 5, 20, 36},
-    {12, 118, 13, 5, 20, 36},
-    {6, 0, 0, 5, 20, 36},
-    {12, 122, 13, 5, 20, 36},
-    {13, 0, 0, 5, 20, 11},
-    {7, 0, 0, 5, 21, 12},
-    {26, 0, 0, 5, 21, 18},
-    {21, 0, 0, 5, 21, 18},
-    {21, 0, 0, 5, 21, 12},
-    {21, 0, 0, 5, 21, 4},
-    {21, 0, 0, 5, 21, 17},
-    {21, 0, 0, 5, 21, 6},
-    {26, 0, 0, 5, 21, 12},
-    {12, 220, 13, 5, 21, 21},
-    {13, 0, 0, 5, 21, 11},
-    {15, 0, 0, 5, 21, 12},
-    {26, 0, 0, 5, 21, 17},
-    {12, 216, 13, 5, 21, 21},
-    {22, 0, 18, 5, 21, 0},
-    {18, 0, 18, 5, 21, 1},
-    {10, 0, 0, 5, 21, 21},
-    {12, 129, 13, 5, 21, 21},
-    {12, 130, 13, 5, 21, 21},
-    {12, 0, 13, 5, 21, 21},
-    {12, 132, 13, 5, 21, 21},
-    {10, 0, 0, 5, 21, 17},
-    {12, 230, 13, 5, 21, 21},
-    {12, 9, 13, 5, 21, 21},
-    {26, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 22, 36},
-    {10, 0, 0, 5, 22, 36},
-    {12, 0, 13, 5, 22, 36},
-    {12, 7, 13, 5, 22, 36},
-    {12, 9, 13, 5, 22, 36},
-    {13, 0, 0, 5, 22, 11},
-    {21, 0, 0, 5, 22, 17},
-    {21, 0, 0, 5, 22, 12},
-    {12, 220, 13, 5, 22, 36},
-    {26, 0, 0, 5, 22, 36},
-    {9, 0, 0, 5, 23, 12},
-    {5, 0, 0, 5, 23, 12},
-    {21, 0, 0, 5, 0, 12},
-    {6, 0, 0, 5, 23, 12},
-    {7, 0, 0, 2, 24, 25},
-    {7, 0, 0, 5, 24, 26},
-    {7, 0, 0, 5, 24, 27},
-    {7, 0, 0, 5, 25, 12},
-    {12, 230, 13, 5, 25, 21},
-    {21, 0, 0, 5, 25, 12},
-    {21, 0, 0, 5, 25, 17},
-    {15, 0, 0, 5, 25, 12},
-    {26, 0, 18, 5, 25, 12},
-    {9, 0, 0, 5, 26, 12},
-    {5, 0, 0, 5, 26, 12},
-    {17, 0, 18, 5, 27, 17},
-    {7, 0, 0, 5, 27, 12},
-    {21, 0, 0, 5, 27, 12},
-    {29, 0, 17, 5, 28, 17},
-    {7, 0, 0, 5, 28, 12},
-    {22, 0, 18, 5, 28, 0},
-    {18, 0, 18, 5, 28, 1},
-    {7, 0, 0, 5, 29, 12},
-    {14, 0, 0, 5, 29, 12},
-    {7, 0, 0, 5, 41, 12},
-    {12, 0, 13, 5, 41, 21},
-    {12, 9, 13, 5, 41, 21},
-    {7, 0, 0, 5, 42, 12},
-    {12, 0, 13, 5, 42, 21},
-    {12, 9, 13, 5, 42, 21},
-    {7, 0, 0, 5, 43, 12},
-    {12, 0, 13, 5, 43, 21},
-    {7, 0, 0, 5, 44, 12},
-    {12, 0, 13, 5, 44, 21},
-    {7, 0, 0, 5, 30, 36},
-    {12, 0, 13, 5, 30, 36},
-    {10, 0, 0, 5, 30, 36},
-    {12, 9, 13, 5, 30, 36},
-    {21, 0, 0, 5, 30, 17},
-    {21, 0, 0, 5, 30, 5},
-    {6, 0, 0, 5, 30, 36},
-    {21, 0, 0, 5, 30, 12},
-    {23, 0, 10, 5, 30, 9},
-    {12, 230, 13, 5, 30, 36},
-    {13, 0, 0, 5, 30, 11},
-    {15, 0, 18, 5, 30, 12},
-    {21, 0, 18, 5, 31, 12},
-    {21, 0, 18, 5, 0, 6},
-    {21, 0, 18, 5, 31, 17},
-    {21, 0, 18, 5, 0, 17},
-    {17, 0, 18, 5, 31, 18},
-    {21, 0, 18, 5, 31, 6},
-    {12, 0, 13, 5, 31, 21},
-    {1, 0, 14, 5, 31, 4},
-    {13, 0, 0, 5, 31, 11},
-    {7, 0, 0, 5, 31, 12},
-    {6, 0, 0, 5, 31, 12},
-    {12, 228, 13, 5, 31, 21},
-    {7, 0, 0, 5, 45, 12},
-    {12, 0, 13, 5, 45, 21},
-    {10, 0, 0, 5, 45, 21},
-    {12, 222, 13, 5, 45, 21},
-    {12, 230, 13, 5, 45, 21},
-    {12, 220, 13, 5, 45, 21},
-    {26, 0, 18, 5, 45, 12},
-    {21, 0, 18, 5, 45, 6},
-    {13, 0, 0, 5, 45, 11},
-    {7, 0, 0, 5, 46, 36},
-    {7, 0, 0, 5, 55, 36},
-    {13, 0, 0, 5, 55, 11},
-    {15, 0, 0, 5, 55, 36},
-    {26, 0, 18, 5, 55, 36},
-    {26, 0, 18, 5, 30, 12},
-    {7, 0, 0, 5, 53, 12},
-    {12, 230, 13, 5, 53, 21},
-    {12, 220, 13, 5, 53, 21},
-    {10, 0, 0, 5, 53, 21},
-    {12, 0, 13, 5, 53, 21},
-    {21, 0, 0, 5, 53, 12},
-    {7, 0, 0, 5, 77, 36},
-    {10, 0, 0, 5, 77, 36},
-    {12, 0, 13, 5, 77, 36},
-    {12, 9, 13, 5, 77, 36},
-    {12, 230, 13, 5, 77, 36},
-    {12, 220, 13, 5, 77, 21},
-    {13, 0, 0, 5, 77, 11},
-    {21, 0, 0, 5, 77, 36},
-    {6, 0, 0, 5, 77, 36},
-    {11, 0, 13, 5, 40, 21},
-    {12, 0, 13, 5, 61, 21},
-    {10, 0, 0, 5, 61, 21},
-    {7, 0, 0, 5, 61, 12},
-    {12, 7, 13, 5, 61, 21},
-    {10, 9, 0, 5, 61, 21},
-    {13, 0, 0, 5, 61, 11},
-    {21, 0, 0, 5, 61, 17},
-    {21, 0, 0, 5, 61, 12},
-    {26, 0, 0, 5, 61, 12},
-    {12, 230, 13, 5, 61, 21},
-    {12, 220, 13, 5, 61, 21},
-    {12, 0, 13, 5, 66, 21},
-    {10, 0, 0, 5, 66, 21},
-    {7, 0, 0, 5, 66, 12},
-    {10, 9, 0, 5, 66, 21},
-    {12, 9, 13, 5, 66, 21},
-    {13, 0, 0, 5, 66, 11},
-    {7, 0, 0, 5, 92, 12},
-    {12, 7, 13, 5, 92, 21},
-    {10, 0, 0, 5, 92, 21},
-    {12, 0, 13, 5, 92, 21},
-    {10, 9, 0, 5, 92, 21},
-    {21, 0, 0, 5, 92, 12},
-    {7, 0, 0, 5, 67, 12},
-    {10, 0, 0, 5, 67, 21},
-    {12, 0, 13, 5, 67, 21},
-    {12, 7, 13, 5, 67, 21},
-    {21, 0, 0, 5, 67, 17},
-    {13, 0, 0, 5, 67, 11},
-    {13, 0, 0, 5, 68, 11},
-    {7, 0, 0, 5, 68, 12},
-    {6, 0, 0, 5, 68, 12},
-    {21, 0, 0, 5, 68, 17},
-    {21, 0, 0, 5, 66, 12},
-    {12, 1, 13, 5, 40, 21},
-    {10, 0, 0, 5, 0, 21},
-    {7, 0, 0, 5, 0, 12},
-    {6, 0, 0, 5, 3, 12},
-    {12, 234, 13, 5, 40, 21},
-    {12, 214, 13, 5, 40, 21},
-    {12, 202, 13, 5, 40, 21},
-    {12, 232, 13, 5, 40, 21},
-    {12, 228, 13, 5, 40, 21},
-    {12, 233, 13, 5, 40, 21},
-    {8, 0, 0, 5, 2, 12},
-    {24, 0, 18, 5, 2, 18},
-    {29, 0, 17, 5, 0, 17},
-    {29, 0, 17, 5, 0, 4},
-    {1, 0, 14, 5, 0, 20},
-    {1, 0, 14, 5, 40, 21},
-    {1, 0, 14, 5, 40, 40},
-    {1, 0, 0, 5, 0, 21},
-    {1, 0, 3, 5, 0, 21},
-    {17, 0, 18, 4, 0, 17},
-    {17, 0, 18, 5, 0, 4},
-    {17, 0, 18, 5, 0, 17},
-    {17, 0, 18, 4, 0, 19},
-    {17, 0, 18, 4, 0, 29},
-    {20, 0, 18, 4, 0, 3},
-    {19, 0, 18, 4, 0, 3},
-    {22, 0, 18, 5, 0, 0},
-    {21, 0, 18, 4, 0, 12},
-    {21, 0, 18, 4, 0, 15},
-    {21, 0, 18, 4, 0, 17},
-    {27, 0, 17, 5, 0, 30},
-    {28, 0, 15, 5, 0, 30},
-    {1, 0, 1, 5, 0, 21},
-    {1, 0, 5, 5, 0, 21},
-    {1, 0, 7, 5, 0, 21},
-    {1, 0, 2, 5, 0, 21},
-    {1, 0, 6, 5, 0, 21},
-    {21, 0, 10, 4, 0, 10},
-    {21, 0, 10, 5, 0, 10},
-    {21, 0, 18, 4, 0, 10},
-    {21, 0, 18, 5, 0, 10},
-    {21, 0, 18, 5, 0, 5},
-    {16, 0, 18, 5, 0, 12},
-    {25, 0, 12, 5, 0, 8},
-    {18, 0, 18, 5, 0, 1},
-    {25, 0, 18, 5, 0, 12},
-    {1, 0, 14, 5, 0, 22},
-    {1, 0, 14, 5, 0, 12},
-    {1, 0, 19, 5, 0, 21},
-    {1, 0, 20, 5, 0, 21},
-    {1, 0, 21, 5, 0, 21},
-    {1, 0, 22, 5, 0, 21},
-    {1, 0, 14, 5, 0, 21},
-    {15, 0, 8, 5, 0, 12},
-    {25, 0, 9, 5, 0, 12},
-    {6, 0, 0, 4, 1, 29},
-    {23, 0, 10, 5, 0, 10},
-    {23, 0, 10, 1, 0, 9},
-    {2, 0, 18, 5, 102, 9},
-    {9, 0, 0, 5, 0, 12},
-    {26, 0, 18, 4, 0, 10},
-    {26, 0, 18, 4, 0, 29},
-    {5, 0, 0, 4, 0, 29},
-    {26, 0, 18, 4, 0, 9},
-    {9, 0, 0, 4, 1, 29},
-    {26, 0, 10, 5, 0, 12},
-    {15, 0, 18, 5, 0, 12},
-    {15, 0, 18, 4, 0, 12},
-    {15, 0, 18, 5, 0, 29},
-    {14, 0, 0, 4, 1, 29},
-    {14, 0, 0, 5, 1, 12},
-    {25, 0, 9, 5, 0, 9},
-    {25, 0, 10, 5, 0, 9},
-    {25, 0, 18, 5, 0, 15},
-    {26, 0, 18, 2, 0, 14},
-    {22, 0, 18, 2, 0, 0},
-    {18, 0, 18, 2, 0, 1},
-    {26, 0, 18, 2, 0, 12},
-    {26, 0, 18, 5, 0, 14},
-    {26, 0, 0, 4, 0, 29},
-    {26, 0, 18, 5, 0, 29},
-    {25, 0, 18, 2, 0, 12},
-    {26, 0, 18, 4, 0, 14},
-    {26, 0, 18, 5, 0, 41},
-    {26, 0, 18, 4, 0, 41},
-    {26, 0, 18, 2, 0, 41},
-    {26, 0, 18, 2, 0, 29},
-    {26, 0, 18, 5, 0, 3},
-    {26, 0, 18, 5, 0, 6},
-    {26, 0, 0, 5, 52, 12},
-    {9, 0, 0, 5, 56, 12},
-    {5, 0, 0, 5, 56, 12},
-    {26, 0, 18, 5, 54, 12},
-    {12, 230, 13, 5, 54, 21},
-    {21, 0, 18, 5, 54, 6},
-    {21, 0, 18, 5, 54, 17},
-    {15, 0, 18, 5, 54, 12},
-    {7, 0, 0, 5, 57, 12},
-    {6, 0, 0, 5, 57, 12},
-    {21, 0, 0, 5, 57, 17},
-    {12, 9, 13, 5, 57, 21},
-    {21, 0, 18, 5, 0, 3},
-    {21, 0, 18, 5, 0, 0},
-    {17, 0, 18, 5, 0, 12},
-    {17, 0, 18, 5, 0, 19},
-    {26, 0, 18, 2, 35, 14},
-    {29, 0, 17, 0, 0, 17},
-    {21, 0, 18, 2, 0, 1},
-    {21, 0, 18, 2, 0, 14},
-    {6, 0, 0, 2, 35, 5},
-    {7, 0, 0, 2, 0, 14},
-    {14, 0, 0, 2, 35, 14},
-    {17, 0, 18, 2, 0, 5},
-    {12, 218, 13, 2, 40, 21},
-    {12, 228, 13, 2, 40, 21},
-    {12, 232, 13, 2, 40, 21},
-    {12, 222, 13, 2, 40, 21},
-    {10, 224, 0, 2, 24, 21},
-    {17, 0, 18, 2, 0, 14},
-    {6, 0, 0, 2, 0, 14},
-    {6, 0, 0, 2, 0, 21},
-    {7, 0, 0, 2, 0, 5},
-    {7, 0, 0, 2, 32, 32},
-    {7, 0, 0, 2, 32, 14},
-    {12, 8, 13, 2, 40, 21},
-    {24, 0, 18, 2, 0, 5},
-    {6, 0, 0, 2, 32, 5},
-    {7, 0, 0, 2, 33, 32},
-    {7, 0, 0, 2, 33, 14},
-    {21, 0, 18, 2, 0, 5},
-    {6, 0, 0, 2, 0, 32},
-    {6, 0, 0, 2, 33, 5},
-    {7, 0, 0, 2, 34, 14},
-    {7, 0, 0, 2, 24, 14},
-    {26, 0, 0, 2, 0, 14},
-    {15, 0, 0, 2, 0, 14},
-    {26, 0, 0, 2, 24, 14},
-    {26, 0, 18, 2, 24, 14},
-    {15, 0, 0, 4, 0, 29},
-    {15, 0, 18, 2, 0, 14},
-    {26, 0, 0, 2, 33, 14},
-    {7, 0, 0, 2, 35, 14},
-    {2, 0, 18, 2, 102, 14},
-    {7, 0, 0, 2, 36, 14},
-    {6, 0, 0, 2, 36, 5},
-    {26, 0, 18, 2, 36, 14},
-    {7, 0, 0, 5, 82, 12},
-    {6, 0, 0, 5, 82, 12},
-    {21, 0, 0, 5, 82, 17},
-    {7, 0, 0, 5, 69, 12},
-    {6, 0, 0, 5, 69, 12},
-    {21, 0, 18, 5, 69, 17},
-    {21, 0, 18, 5, 69, 6},
-    {13, 0, 0, 5, 69, 11},
-    {7, 0, 0, 5, 3, 12},
-    {21, 0, 18, 5, 3, 12},
-    {6, 0, 18, 5, 3, 12},
-    {7, 0, 0, 5, 83, 12},
-    {14, 0, 0, 5, 83, 12},
-    {12, 230, 13, 5, 83, 21},
-    {21, 0, 0, 5, 83, 12},
-    {21, 0, 0, 5, 83, 17},
-    {24, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 58, 12},
-    {12, 0, 13, 5, 58, 21},
-    {12, 9, 13, 5, 58, 21},
-    {10, 0, 0, 5, 58, 21},
-    {26, 0, 18, 5, 58, 12},
-    {15, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 64, 12},
-    {21, 0, 18, 5, 64, 18},
-    {21, 0, 18, 5, 64, 6},
-    {10, 0, 0, 5, 70, 21},
-    {7, 0, 0, 5, 70, 12},
-    {12, 9, 13, 5, 70, 21},
-    {12, 0, 13, 5, 70, 21},
-    {21, 0, 0, 5, 70, 17},
-    {13, 0, 0, 5, 70, 11},
-    {21, 0, 0, 5, 9, 18},
-    {13, 0, 0, 5, 71, 11},
-    {7, 0, 0, 5, 71, 12},
-    {12, 0, 13, 5, 71, 21},
-    {12, 220, 13, 5, 71, 21},
-    {21, 0, 0, 5, 71, 17},
-    {7, 0, 0, 5, 72, 12},
-    {12, 0, 13, 5, 72, 21},
-    {10, 0, 0, 5, 72, 21},
-    {10, 9, 0, 5, 72, 21},
-    {21, 0, 0, 5, 72, 12},
-    {12, 0, 13, 5, 84, 21},
-    {10, 0, 0, 5, 84, 21},
-    {7, 0, 0, 5, 84, 12},
-    {12, 7, 13, 5, 84, 21},
-    {10, 9, 0, 5, 84, 21},
-    {21, 0, 0, 5, 84, 12},
-    {21, 0, 0, 5, 84, 17},
-    {13, 0, 0, 5, 84, 11},
-    {6, 0, 0, 5, 22, 36},
-    {7, 0, 0, 5, 76, 12},
-    {12, 0, 13, 5, 76, 21},
-    {10, 0, 0, 5, 76, 21},
-    {13, 0, 0, 5, 76, 11},
-    {21, 0, 0, 5, 76, 12},
-    {21, 0, 0, 5, 76, 17},
-    {7, 0, 0, 5, 78, 36},
-    {12, 230, 13, 5, 78, 36},
-    {12, 220, 13, 5, 78, 36},
-    {6, 0, 0, 5, 78, 36},
-    {21, 0, 0, 5, 78, 36},
-    {7, 0, 0, 5, 85, 12},
-    {10, 0, 0, 5, 85, 21},
-    {12, 0, 13, 5, 85, 21},
-    {21, 0, 0, 5, 85, 17},
-    {6, 0, 0, 5, 85, 12},
-    {12, 9, 13, 5, 85, 21},
-    {13, 0, 0, 5, 85, 11},
-    {7, 0, 0, 2, 24, 23},
-    {7, 0, 0, 2, 24, 24},
-    {4, 0, 0, 5, 102, 37},
-    {3, 0, 0, 4, 102, 39},
-    {12, 26, 13, 5, 5, 21},
-    {25, 0, 9, 5, 5, 12},
-    {24, 0, 4, 5, 6, 12},
-    {12, 0, 13, 4, 40, 21},
-    {21, 0, 18, 2, 0, 8},
-    {21, 0, 18, 2, 0, 6},
-    {21, 0, 18, 2, 0, 15},
-    {16, 0, 18, 2, 0, 14},
-    {21, 0, 12, 2, 0, 1},
-    {21, 0, 12, 2, 0, 5},
-    {21, 0, 10, 2, 0, 14},
-    {25, 0, 9, 2, 0, 14},
-    {17, 0, 9, 2, 0, 14},
-    {25, 0, 18, 2, 0, 14},
-    {23, 0, 10, 2, 0, 9},
-    {21, 0, 10, 2, 0, 10},
-    {21, 0, 18, 0, 0, 6},
-    {21, 0, 18, 0, 0, 14},
-    {21, 0, 10, 0, 0, 14},
-    {23, 0, 10, 0, 0, 9},
-    {21, 0, 10, 0, 0, 10},
-    {22, 0, 18, 0, 0, 0},
-    {18, 0, 18, 0, 0, 1},
-    {25, 0, 9, 0, 0, 14},
-    {21, 0, 12, 0, 0, 1},
-    {17, 0, 9, 0, 0, 14},
-    {21, 0, 12, 0, 0, 14},
-    {13, 0, 8, 0, 0, 14},
-    {21, 0, 12, 0, 0, 5},
-    {21, 0, 18, 0, 0, 5},
-    {25, 0, 18, 0, 0, 14},
-    {9, 0, 0, 0, 1, 14},
-    {24, 0, 18, 0, 0, 14},
-    {16, 0, 18, 0, 0, 14},
-    {5, 0, 0, 0, 1, 14},
-    {21, 0, 18, 1, 0, 1},
-    {22, 0, 18, 1, 0, 0},
-    {18, 0, 18, 1, 0, 1},
-    {21, 0, 18, 1, 0, 5},
-    {7, 0, 0, 1, 33, 14},
-    {7, 0, 0, 1, 33, 32},
-    {6, 0, 0, 1, 0, 32},
-    {6, 0, 0, 1, 0, 5},
-    {7, 0, 0, 1, 24, 14},
-    {23, 0, 10, 0, 0, 10},
-    {26, 0, 18, 0, 0, 14},
-    {26, 0, 18, 1, 0, 12},
-    {25, 0, 18, 1, 0, 12},
-    {1, 0, 18, 5, 0, 21},
-    {26, 0, 18, 5, 0, 31},
-    {7, 0, 0, 5, 47, 12},
-    {14, 0, 18, 5, 2, 12},
-    {15, 0, 18, 5, 2, 12},
-    {26, 0, 18, 5, 2, 12},
-    {26, 0, 0, 5, 2, 12},
-    {7, 0, 0, 5, 73, 12},
-    {7, 0, 0, 5, 74, 12},
-    {7, 0, 0, 5, 37, 12},
-    {15, 0, 0, 5, 37, 12},
-    {7, 0, 0, 5, 38, 12},
-    {14, 0, 0, 5, 38, 12},
-    {7, 0, 0, 5, 118, 12},
-    {12, 230, 13, 5, 118, 21},
-    {7, 0, 0, 5, 48, 12},
-    {21, 0, 0, 5, 48, 17},
-    {7, 0, 0, 5, 59, 12},
-    {21, 0, 0, 5, 59, 17},
-    {14, 0, 0, 5, 59, 12},
-    {9, 0, 0, 5, 39, 12},
-    {5, 0, 0, 5, 39, 12},
-    {7, 0, 0, 5, 49, 12},
-    {7, 0, 0, 5, 50, 12},
-    {13, 0, 0, 5, 50, 11},
-    {9, 0, 0, 5, 136, 12},
-    {5, 0, 0, 5, 136, 12},
-    {7, 0, 0, 5, 106, 12},
-    {7, 0, 0, 5, 104, 12},
-    {21, 0, 0, 5, 104, 12},
-    {7, 0, 0, 5, 110, 12},
-    {7, 0, 3, 5, 51, 12},
-    {7, 0, 3, 5, 86, 12},
-    {21, 0, 3, 5, 86, 17},
-    {15, 0, 3, 5, 86, 12},
-    {7, 0, 3, 5, 120, 12},
-    {26, 0, 3, 5, 120, 12},
-    {15, 0, 3, 5, 120, 12},
-    {7, 0, 3, 5, 116, 12},
-    {15, 0, 3, 5, 116, 12},
-    {7, 0, 3, 5, 128, 12},
-    {15, 0, 3, 5, 128, 12},
-    {7, 0, 3, 5, 63, 12},
-    {15, 0, 3, 5, 63, 12},
-    {21, 0, 18, 5, 63, 17},
-    {7, 0, 3, 5, 75, 12},
-    {21, 0, 3, 5, 75, 12},
-    {7, 0, 3, 5, 97, 12},
-    {7, 0, 3, 5, 96, 12},
-    {15, 0, 3, 5, 96, 12},
-    {7, 0, 3, 5, 60, 12},
-    {12, 0, 13, 5, 60, 21},
-    {12, 220, 13, 5, 60, 21},
-    {12, 230, 13, 5, 60, 21},
-    {12, 1, 13, 5, 60, 21},
-    {12, 9, 13, 5, 60, 21},
-    {15, 0, 3, 5, 60, 12},
-    {21, 0, 3, 5, 60, 17},
-    {21, 0, 3, 5, 60, 12},
-    {7, 0, 3, 5, 87, 12},
-    {15, 0, 3, 5, 87, 12},
-    {21, 0, 3, 5, 87, 12},
-    {7, 0, 3, 5, 117, 12},
-    {15, 0, 3, 5, 117, 12},
-    {7, 0, 3, 5, 112, 12},
-    {26, 0, 3, 5, 112, 12},
-    {12, 230, 13, 5, 112, 21},
-    {12, 220, 13, 5, 112, 21},
-    {15, 0, 3, 5, 112, 12},
-    {21, 0, 3, 5, 112, 17},
-    {21, 0, 3, 5, 112, 15},
-    {7, 0, 3, 5, 79, 12},
-    {21, 0, 18, 5, 79, 17},
-    {7, 0, 3, 5, 88, 12},
-    {15, 0, 3, 5, 88, 12},
-    {7, 0, 3, 5, 89, 12},
-    {15, 0, 3, 5, 89, 12},
-    {7, 0, 3, 5, 122, 12},
-    {21, 0, 3, 5, 122, 12},
-    {15, 0, 3, 5, 122, 12},
-    {7, 0, 3, 5, 90, 12},
-    {9, 0, 3, 5, 130, 12},
-    {5, 0, 3, 5, 130, 12},
-    {15, 0, 3, 5, 130, 12},
-    {7, 0, 4, 5, 144, 12},
-    {12, 230, 13, 5, 144, 21},
-    {13, 0, 11, 5, 144, 11},
-    {15, 0, 11, 5, 6, 12},
-    {7, 0, 3, 5, 147, 12},
-    {15, 0, 3, 5, 147, 12},
-    {7, 0, 4, 5, 148, 12},
-    {12, 220, 13, 5, 148, 21},
-    {12, 230, 13, 5, 148, 21},
-    {15, 0, 4, 5, 148, 12},
-    {21, 0, 4, 5, 148, 12},
-    {10, 0, 0, 5, 93, 21},
-    {12, 0, 13, 5, 93, 21},
-    {7, 0, 0, 5, 93, 12},
-    {12, 9, 13, 5, 93, 21},
-    {21, 0, 0, 5, 93, 17},
-    {21, 0, 0, 5, 93, 12},
-    {15, 0, 18, 5, 93, 12},
-    {13, 0, 0, 5, 93, 11},
-    {12, 0, 13, 5, 91, 21},
-    {10, 0, 0, 5, 91, 21},
-    {7, 0, 0, 5, 91, 12},
-    {12, 9, 13, 5, 91, 21},
-    {12, 7, 13, 5, 91, 21},
-    {21, 0, 0, 5, 91, 12},
-    {1, 0, 0, 5, 91, 12},
-    {21, 0, 0, 5, 91, 17},
-    {7, 0, 0, 5, 100, 12},
-    {13, 0, 0, 5, 100, 11},
-    {12, 230, 13, 5, 95, 21},
-    {7, 0, 0, 5, 95, 12},
-    {12, 0, 13, 5, 95, 21},
-    {10, 0, 0, 5, 95, 21},
-    {12, 9, 13, 5, 95, 21},
-    {13, 0, 0, 5, 95, 11},
-    {21, 0, 0, 5, 95, 17},
-    {7, 0, 0, 5, 111, 12},
-    {12, 7, 13, 5, 111, 21},
-    {21, 0, 0, 5, 111, 12},
-    {21, 0, 0, 5, 111, 18},
-    {12, 0, 13, 5, 99, 21},
-    {10, 0, 0, 5, 99, 21},
-    {7, 0, 0, 5, 99, 12},
-    {10, 9, 0, 5, 99, 21},
-    {21, 0, 0, 5, 99, 17},
-    {21, 0, 0, 5, 99, 12},
-    {12, 7, 13, 5, 99, 21},
-    {13, 0, 0, 5, 99, 11},
-    {21, 0, 0, 5, 99, 18},
-    {15, 0, 0, 5, 18, 12},
-    {7, 0, 0, 5, 108, 12},
-    {10, 0, 0, 5, 108, 21},
-    {12, 0, 13, 5, 108, 21},
-    {10, 9, 0, 5, 108, 21},
-    {12, 7, 13, 5, 108, 21},
-    {21, 0, 0, 5, 108, 17},
-    {21, 0, 0, 5, 108, 12},
-    {7, 0, 0, 5, 129, 12},
-    {21, 0, 0, 5, 129, 17},
-    {7, 0, 0, 5, 109, 12},
-    {12, 0, 13, 5, 109, 21},
-    {10, 0, 0, 5, 109, 21},
-    {12, 7, 13, 5, 109, 21},
-    {12, 9, 13, 5, 109, 21},
-    {13, 0, 0, 5, 109, 11},
-    {12, 0, 13, 5, 107, 21},
-    {10, 0, 0, 5, 107, 21},
-    {7, 0, 0, 5, 107, 12},
-    {12, 7, 13, 5, 40, 21},
-    {12, 7, 13, 5, 107, 21},
-    {10, 9, 0, 5, 107, 21},
-    {12, 230, 13, 5, 107, 21},
-    {7, 0, 0, 5, 135, 12},
-    {10, 0, 0, 5, 135, 21},
-    {12, 0, 13, 5, 135, 21},
-    {12, 9, 13, 5, 135, 21},
-    {12, 7, 13, 5, 135, 21},
-    {21, 0, 0, 5, 135, 17},
-    {21, 0, 0, 5, 135, 12},
-    {13, 0, 0, 5, 135, 11},
-    {12, 230, 13, 5, 135, 21},
-    {7, 0, 0, 5, 124, 12},
-    {10, 0, 0, 5, 124, 21},
-    {12, 0, 13, 5, 124, 21},
-    {12, 9, 13, 5, 124, 21},
-    {12, 7, 13, 5, 124, 21},
-    {21, 0, 0, 5, 124, 12},
-    {13, 0, 0, 5, 124, 11},
-    {7, 0, 0, 5, 123, 12},
-    {10, 0, 0, 5, 123, 21},
-    {12, 0, 13, 5, 123, 21},
-    {12, 9, 13, 5, 123, 21},
-    {12, 7, 13, 5, 123, 21},
-    {21, 0, 0, 5, 123, 18},
-    {21, 0, 0, 5, 123, 17},
-    {21, 0, 0, 5, 123, 6},
-    {21, 0, 0, 5, 123, 12},
-    {7, 0, 0, 5, 114, 12},
-    {10, 0, 0, 5, 114, 21},
-    {12, 0, 13, 5, 114, 21},
-    {12, 9, 13, 5, 114, 21},
-    {21, 0, 0, 5, 114, 17},
-    {21, 0, 0, 5, 114, 12},
-    {13, 0, 0, 5, 114, 11},
-    {21, 0, 18, 5, 31, 18},
-    {7, 0, 0, 5, 101, 12},
-    {12, 0, 13, 5, 101, 21},
-    {10, 0, 0, 5, 101, 21},
-    {10, 9, 0, 5, 101, 21},
-    {12, 7, 13, 5, 101, 21},
-    {13, 0, 0, 5, 101, 11},
-    {7, 0, 0, 5, 126, 36},
-    {12, 0, 13, 5, 126, 36},
-    {10, 0, 0, 5, 126, 36},
-    {12, 9, 13, 5, 126, 36},
-    {13, 0, 0, 5, 126, 11},
-    {15, 0, 0, 5, 126, 36},
-    {21, 0, 0, 5, 126, 17},
-    {26, 0, 0, 5, 126, 36},
-    {7, 0, 0, 5, 142, 12},
-    {10, 0, 0, 5, 142, 21},
-    {12, 0, 13, 5, 142, 21},
-    {12, 9, 13, 5, 142, 21},
-    {12, 7, 13, 5, 142, 21},
-    {21, 0, 0, 5, 142, 12},
-    {9, 0, 0, 5, 125, 12},
-    {5, 0, 0, 5, 125, 12},
-    {13, 0, 0, 5, 125, 11},
-    {15, 0, 0, 5, 125, 12},
-    {7, 0, 0, 5, 125, 12},
-    {7, 0, 0, 5, 141, 12},
-    {12, 0, 13, 5, 141, 21},
-    {12, 0, 0, 5, 141, 21},
-    {12, 9, 13, 5, 141, 21},
-    {10, 0, 0, 5, 141, 21},
-    {21, 0, 0, 5, 141, 18},
-    {21, 0, 0, 5, 141, 12},
-    {21, 0, 0, 5, 141, 17},
-    {7, 0, 0, 5, 140, 12},
-    {12, 0, 13, 5, 140, 21},
-    {10, 0, 0, 5, 140, 21},
-    {12, 9, 13, 5, 140, 21},
-    {21, 0, 0, 5, 140, 17},
-    {21, 0, 0, 5, 140, 18},
-    {7, 0, 0, 5, 121, 12},
-    {7, 0, 0, 5, 133, 12},
-    {10, 0, 0, 5, 133, 21},
-    {12, 0, 13, 5, 133, 21},
-    {12, 9, 0, 5, 133, 21},
-    {21, 0, 0, 5, 133, 17},
-    {13, 0, 0, 5, 133, 11},
-    {15, 0, 0, 5, 133, 12},
-    {21, 0, 0, 5, 134, 18},
-    {21, 0, 0, 5, 134, 6},
-    {7, 0, 0, 5, 134, 12},
-    {12, 0, 13, 5, 134, 21},
-    {10, 0, 0, 5, 134, 21},
-    {7, 0, 0, 5, 138, 12},
-    {12, 0, 13, 5, 138, 21},
-    {12, 7, 13, 5, 138, 21},
-    {12, 9, 13, 5, 138, 21},
-    {13, 0, 0, 5, 138, 11},
-    {7, 0, 0, 5, 143, 12},
-    {10, 0, 0, 5, 143, 21},
-    {12, 0, 13, 5, 143, 21},
-    {12, 9, 13, 5, 143, 21},
-    {13, 0, 0, 5, 143, 11},
-    {7, 0, 0, 5, 145, 12},
-    {12, 0, 13, 5, 145, 21},
-    {10, 0, 0, 5, 145, 21},
-    {21, 0, 0, 5, 145, 12},
-    {7, 0, 0, 5, 62, 12},
-    {14, 0, 0, 5, 62, 12},
-    {21, 0, 0, 5, 62, 17},
-    {7, 0, 0, 5, 80, 12},
-    {7, 0, 0, 5, 80, 0},
-    {7, 0, 0, 5, 80, 1},
-    {7, 0, 0, 5, 127, 12},
-    {7, 0, 0, 5, 127, 0},
-    {7, 0, 0, 5, 127, 1},
-    {7, 0, 0, 5, 115, 12},
-    {13, 0, 0, 5, 115, 11},
-    {21, 0, 0, 5, 115, 17},
-    {7, 0, 0, 5, 103, 12},
-    {12, 1, 13, 5, 103, 21},
-    {21, 0, 0, 5, 103, 17},
-    {7, 0, 0, 5, 119, 12},
-    {12, 230, 13, 5, 119, 21},
-    {21, 0, 0, 5, 119, 17},
-    {21, 0, 0, 5, 119, 12},
-    {26, 0, 0, 5, 119, 12},
-    {6, 0, 0, 5, 119, 12},
-    {13, 0, 0, 5, 119, 11},
-    {15, 0, 0, 5, 119, 12},
-    {9, 0, 0, 5, 146, 12},
-    {5, 0, 0, 5, 146, 12},
-    {15, 0, 0, 5, 146, 12},
-    {21, 0, 0, 5, 146, 17},
-    {21, 0, 0, 5, 146, 12},
-    {7, 0, 0, 5, 98, 12},
-    {10, 0, 0, 5, 98, 21},
-    {12, 0, 13, 5, 98, 21},
-    {6, 0, 0, 5, 98, 12},
-    {6, 0, 0, 2, 137, 5},
-    {6, 0, 0, 2, 139, 5},
-    {7, 0, 0, 2, 137, 14},
-    {7, 0, 0, 2, 139, 14},
-    {7, 0, 0, 5, 105, 12},
-    {26, 0, 0, 5, 105, 12},
-    {12, 0, 13, 5, 105, 21},
-    {12, 1, 13, 5, 105, 21},
-    {21, 0, 0, 5, 105, 17},
-    {10, 216, 0, 5, 0, 21},
-    {10, 226, 0, 5, 0, 21},
-    {12, 230, 13, 5, 2, 21},
-    {25, 0, 0, 5, 0, 12},
-    {13, 0, 8, 5, 0, 11},
-    {26, 0, 0, 5, 131, 12},
-    {12, 0, 13, 5, 131, 21},
-    {21, 0, 0, 5, 131, 17},
-    {21, 0, 0, 5, 131, 12},
-    {12, 230, 13, 5, 56, 21},
-    {7, 0, 3, 5, 113, 12},
-    {15, 0, 3, 5, 113, 12},
-    {12, 220, 13, 5, 113, 21},
-    {9, 0, 3, 5, 132, 12},
-    {5, 0, 3, 5, 132, 12},
-    {12, 230, 13, 5, 132, 21},
-    {12, 7, 13, 5, 132, 21},
-    {13, 0, 3, 5, 132, 11},
-    {21, 0, 3, 5, 132, 0},
-    {15, 0, 4, 5, 0, 12},
-    {26, 0, 4, 5, 0, 10},
-    {23, 0, 4, 5, 0, 10},
-    {2, 0, 18, 5, 102, 14},
-    {26, 0, 0, 2, 0, 29},
-    {26, 0, 0, 5, 0, 28},
-    {26, 0, 0, 2, 32, 14},
-    {24, 0, 18, 2, 0, 42},
-    {26, 0, 18, 5, 0, 5},
-};
-
-#define BIDI_MIRROR_LEN 420
-static const MirrorPair mirror_pairs[] = {
-    {40, 41},
-    {41, 40},
-    {60, 62},
-    {62, 60},
-    {91, 93},
-    {93, 91},
-    {123, 125},
-    {125, 123},
-    {171, 187},
-    {187, 171},
-    {3898, 3899},
-    {3899, 3898},
-    {3900, 3901},
-    {3901, 3900},
-    {5787, 5788},
-    {5788, 5787},
-    {8249, 8250},
-    {8250, 8249},
-    {8261, 8262},
-    {8262, 8261},
-    {8317, 8318},
-    {8318, 8317},
-    {8333, 8334},
-    {8334, 8333},
-    {8712, 8715},
-    {8713, 8716},
-    {8714, 8717},
-    {8715, 8712},
-    {8716, 8713},
-    {8717, 8714},
-    {8725, 10741},
-    {8735, 11262},
-    {8736, 10659},
-    {8737, 10651},
-    {8738, 10656},
-    {8740, 10990},
-    {8764, 8765},
-    {8765, 8764},
-    {8771, 8909},
-    {8773, 8780},
-    {8780, 8773},
-    {8786, 8787},
-    {8787, 8786},
-    {8788, 8789},
-    {8789, 8788},
-    {8804, 8805},
-    {8805, 8804},
-    {8806, 8807},
-    {8807, 8806},
-    {8808, 8809},
-    {8809, 8808},
-    {8810, 8811},
-    {8811, 8810},
-    {8814, 8815},
-    {8815, 8814},
-    {8816, 8817},
-    {8817, 8816},
-    {8818, 8819},
-    {8819, 8818},
-    {8820, 8821},
-    {8821, 8820},
-    {8822, 8823},
-    {8823, 8822},
-    {8824, 8825},
-    {8825, 8824},
-    {8826, 8827},
-    {8827, 8826},
-    {8828, 8829},
-    {8829, 8828},
-    {8830, 8831},
-    {8831, 8830},
-    {8832, 8833},
-    {8833, 8832},
-    {8834, 8835},
-    {8835, 8834},
-    {8836, 8837},
-    {8837, 8836},
-    {8838, 8839},
-    {8839, 8838},
-    {8840, 8841},
-    {8841, 8840},
-    {8842, 8843},
-    {8843, 8842},
-    {8847, 8848},
-    {8848, 8847},
-    {8849, 8850},
-    {8850, 8849},
-    {8856, 10680},
-    {8866, 8867},
-    {8867, 8866},
-    {8870, 10974},
-    {8872, 10980},
-    {8873, 10979},
-    {8875, 10981},
-    {8880, 8881},
-    {8881, 8880},
-    {8882, 8883},
-    {8883, 8882},
-    {8884, 8885},
-    {8885, 8884},
-    {8886, 8887},
-    {8887, 8886},
-    {8888, 10204},
-    {8905, 8906},
-    {8906, 8905},
-    {8907, 8908},
-    {8908, 8907},
-    {8909, 8771},
-    {8912, 8913},
-    {8913, 8912},
-    {8918, 8919},
-    {8919, 8918},
-    {8920, 8921},
-    {8921, 8920},
-    {8922, 8923},
-    {8923, 8922},
-    {8924, 8925},
-    {8925, 8924},
-    {8926, 8927},
-    {8927, 8926},
-    {8928, 8929},
-    {8929, 8928},
-    {8930, 8931},
-    {8931, 8930},
-    {8932, 8933},
-    {8933, 8932},
-    {8934, 8935},
-    {8935, 8934},
-    {8936, 8937},
-    {8937, 8936},
-    {8938, 8939},
-    {8939, 8938},
-    {8940, 8941},
-    {8941, 8940},
-    {8944, 8945},
-    {8945, 8944},
-    {8946, 8954},
-    {8947, 8955},
-    {8948, 8956},
-    {8950, 8957},
-    {8951, 8958},
-    {8954, 8946},
-    {8955, 8947},
-    {8956, 8948},
-    {8957, 8950},
-    {8958, 8951},
-    {8968, 8969},
-    {8969, 8968},
-    {8970, 8971},
-    {8971, 8970},
-    {9001, 9002},
-    {9002, 9001},
-    {10088, 10089},
-    {10089, 10088},
-    {10090, 10091},
-    {10091, 10090},
-    {10092, 10093},
-    {10093, 10092},
-    {10094, 10095},
-    {10095, 10094},
-    {10096, 10097},
-    {10097, 10096},
-    {10098, 10099},
-    {10099, 10098},
-    {10100, 10101},
-    {10101, 10100},
-    {10179, 10180},
-    {10180, 10179},
-    {10181, 10182},
-    {10182, 10181},
-    {10184, 10185},
-    {10185, 10184},
-    {10187, 10189},
-    {10189, 10187},
-    {10197, 10198},
-    {10198, 10197},
-    {10204, 8888},
-    {10205, 10206},
-    {10206, 10205},
-    {10210, 10211},
-    {10211, 10210},
-    {10212, 10213},
-    {10213, 10212},
-    {10214, 10215},
-    {10215, 10214},
-    {10216, 10217},
-    {10217, 10216},
-    {10218, 10219},
-    {10219, 10218},
-    {10220, 10221},
-    {10221, 10220},
-    {10222, 10223},
-    {10223, 10222},
-    {10627, 10628},
-    {10628, 10627},
-    {10629, 10630},
-    {10630, 10629},
-    {10631, 10632},
-    {10632, 10631},
-    {10633, 10634},
-    {10634, 10633},
-    {10635, 10636},
-    {10636, 10635},
-    {10637, 10640},
-    {10638, 10639},
-    {10639, 10638},
-    {10640, 10637},
-    {10641, 10642},
-    {10642, 10641},
-    {10643, 10644},
-    {10644, 10643},
-    {10645, 10646},
-    {10646, 10645},
-    {10647, 10648},
-    {10648, 10647},
-    {10651, 8737},
-    {10656, 8738},
-    {10659, 8736},
-    {10660, 10661},
-    {10661, 10660},
-    {10664, 10665},
-    {10665, 10664},
-    {10666, 10667},
-    {10667, 10666},
-    {10668, 10669},
-    {10669, 10668},
-    {10670, 10671},
-    {10671, 10670},
-    {10680, 8856},
-    {10688, 10689},
-    {10689, 10688},
-    {10692, 10693},
-    {10693, 10692},
-    {10703, 10704},
-    {10704, 10703},
-    {10705, 10706},
-    {10706, 10705},
-    {10708, 10709},
-    {10709, 10708},
-    {10712, 10713},
-    {10713, 10712},
-    {10714, 10715},
-    {10715, 10714},
-    {10728, 10729},
-    {10729, 10728},
-    {10741, 8725},
-    {10744, 10745},
-    {10745, 10744},
-    {10748, 10749},
-    {10749, 10748},
-    {10795, 10796},
-    {10796, 10795},
-    {10797, 10798},
-    {10798, 10797},
-    {10804, 10805},
-    {10805, 10804},
-    {10812, 10813},
-    {10813, 10812},
-    {10852, 10853},
-    {10853, 10852},
-    {10873, 10874},
-    {10874, 10873},
-    {10875, 10876},
-    {10876, 10875},
-    {10877, 10878},
-    {10878, 10877},
-    {10879, 10880},
-    {10880, 10879},
-    {10881, 10882},
-    {10882, 10881},
-    {10883, 10884},
-    {10884, 10883},
-    {10885, 10886},
-    {10886, 10885},
-    {10887, 10888},
-    {10888, 10887},
-    {10889, 10890},
-    {10890, 10889},
-    {10891, 10892},
-    {10892, 10891},
-    {10893, 10894},
-    {10894, 10893},
-    {10895, 10896},
-    {10896, 10895},
-    {10897, 10898},
-    {10898, 10897},
-    {10899, 10900},
-    {10900, 10899},
-    {10901, 10902},
-    {10902, 10901},
-    {10903, 10904},
-    {10904, 10903},
-    {10905, 10906},
-    {10906, 10905},
-    {10907, 10908},
-    {10908, 10907},
-    {10909, 10910},
-    {10910, 10909},
-    {10911, 10912},
-    {10912, 10911},
-    {10913, 10914},
-    {10914, 10913},
-    {10918, 10919},
-    {10919, 10918},
-    {10920, 10921},
-    {10921, 10920},
-    {10922, 10923},
-    {10923, 10922},
-    {10924, 10925},
-    {10925, 10924},
-    {10927, 10928},
-    {10928, 10927},
-    {10929, 10930},
-    {10930, 10929},
-    {10931, 10932},
-    {10932, 10931},
-    {10933, 10934},
-    {10934, 10933},
-    {10935, 10936},
-    {10936, 10935},
-    {10937, 10938},
-    {10938, 10937},
-    {10939, 10940},
-    {10940, 10939},
-    {10941, 10942},
-    {10942, 10941},
-    {10943, 10944},
-    {10944, 10943},
-    {10945, 10946},
-    {10946, 10945},
-    {10947, 10948},
-    {10948, 10947},
-    {10949, 10950},
-    {10950, 10949},
-    {10951, 10952},
-    {10952, 10951},
-    {10953, 10954},
-    {10954, 10953},
-    {10955, 10956},
-    {10956, 10955},
-    {10957, 10958},
-    {10958, 10957},
-    {10959, 10960},
-    {10960, 10959},
-    {10961, 10962},
-    {10962, 10961},
-    {10963, 10964},
-    {10964, 10963},
-    {10965, 10966},
-    {10966, 10965},
-    {10974, 8870},
-    {10979, 8873},
-    {10980, 8872},
-    {10981, 8875},
-    {10988, 10989},
-    {10989, 10988},
-    {10990, 8740},
-    {10999, 11000},
-    {11000, 10999},
-    {11001, 11002},
-    {11002, 11001},
-    {11262, 8735},
-    {11778, 11779},
-    {11779, 11778},
-    {11780, 11781},
-    {11781, 11780},
-    {11785, 11786},
-    {11786, 11785},
-    {11788, 11789},
-    {11789, 11788},
-    {11804, 11805},
-    {11805, 11804},
-    {11808, 11809},
-    {11809, 11808},
-    {11810, 11811},
-    {11811, 11810},
-    {11812, 11813},
-    {11813, 11812},
-    {11814, 11815},
-    {11815, 11814},
-    {11816, 11817},
-    {11817, 11816},
-    {12296, 12297},
-    {12297, 12296},
-    {12298, 12299},
-    {12299, 12298},
-    {12300, 12301},
-    {12301, 12300},
-    {12302, 12303},
-    {12303, 12302},
-    {12304, 12305},
-    {12305, 12304},
-    {12308, 12309},
-    {12309, 12308},
-    {12310, 12311},
-    {12311, 12310},
-    {12312, 12313},
-    {12313, 12312},
-    {12314, 12315},
-    {12315, 12314},
-    {65113, 65114},
-    {65114, 65113},
-    {65115, 65116},
-    {65116, 65115},
-    {65117, 65118},
-    {65118, 65117},
-    {65124, 65125},
-    {65125, 65124},
-    {65288, 65289},
-    {65289, 65288},
-    {65308, 65310},
-    {65310, 65308},
-    {65339, 65341},
-    {65341, 65339},
-    {65371, 65373},
-    {65373, 65371},
-    {65375, 65376},
-    {65376, 65375},
-    {65378, 65379},
-    {65379, 65378},
-};
-
-#define BIDI_BRACKET_LEN 120
-static const BracketPair bracket_pairs[] = {
-    {40, 41, 0},
-    {41, 40, 1},
-    {91, 93, 0},
-    {93, 91, 1},
-    {123, 125, 0},
-    {125, 123, 1},
-    {3898, 3899, 0},
-    {3899, 3898, 1},
-    {3900, 3901, 0},
-    {3901, 3900, 1},
-    {5787, 5788, 0},
-    {5788, 5787, 1},
-    {8261, 8262, 0},
-    {8262, 8261, 1},
-    {8317, 8318, 0},
-    {8318, 8317, 1},
-    {8333, 8334, 0},
-    {8334, 8333, 1},
-    {8968, 8969, 0},
-    {8969, 8968, 1},
-    {8970, 8971, 0},
-    {8971, 8970, 1},
-    {9001, 9002, 0},
-    {9002, 9001, 1},
-    {10088, 10089, 0},
-    {10089, 10088, 1},
-    {10090, 10091, 0},
-    {10091, 10090, 1},
-    {10092, 10093, 0},
-    {10093, 10092, 1},
-    {10094, 10095, 0},
-    {10095, 10094, 1},
-    {10096, 10097, 0},
-    {10097, 10096, 1},
-    {10098, 10099, 0},
-    {10099, 10098, 1},
-    {10100, 10101, 0},
-    {10101, 10100, 1},
-    {10181, 10182, 0},
-    {10182, 10181, 1},
-    {10214, 10215, 0},
-    {10215, 10214, 1},
-    {10216, 10217, 0},
-    {10217, 10216, 1},
-    {10218, 10219, 0},
-    {10219, 10218, 1},
-    {10220, 10221, 0},
-    {10221, 10220, 1},
-    {10222, 10223, 0},
-    {10223, 10222, 1},
-    {10627, 10628, 0},
-    {10628, 10627, 1},
-    {10629, 10630, 0},
-    {10630, 10629, 1},
-    {10631, 10632, 0},
-    {10632, 10631, 1},
-    {10633, 10634, 0},
-    {10634, 10633, 1},
-    {10635, 10636, 0},
-    {10636, 10635, 1},
-    {10637, 10640, 0},
-    {10638, 10639, 1},
-    {10639, 10638, 0},
-    {10640, 10637, 1},
-    {10641, 10642, 0},
-    {10642, 10641, 1},
-    {10643, 10644, 0},
-    {10644, 10643, 1},
-    {10645, 10646, 0},
-    {10646, 10645, 1},
-    {10647, 10648, 0},
-    {10648, 10647, 1},
-    {10712, 10713, 0},
-    {10713, 10712, 1},
-    {10714, 10715, 0},
-    {10715, 10714, 1},
-    {10748, 10749, 0},
-    {10749, 10748, 1},
-    {11810, 11811, 0},
-    {11811, 11810, 1},
-    {11812, 11813, 0},
-    {11813, 11812, 1},
-    {11814, 11815, 0},
-    {11815, 11814, 1},
-    {11816, 11817, 0},
-    {11817, 11816, 1},
-    {12296, 12297, 0},
-    {12297, 12296, 1},
-    {12298, 12299, 0},
-    {12299, 12298, 1},
-    {12300, 12301, 0},
-    {12301, 12300, 1},
-    {12302, 12303, 0},
-    {12303, 12302, 1},
-    {12304, 12305, 0},
-    {12305, 12304, 1},
-    {12308, 12309, 0},
-    {12309, 12308, 1},
-    {12310, 12311, 0},
-    {12311, 12310, 1},
-    {12312, 12313, 0},
-    {12313, 12312, 1},
-    {12314, 12315, 0},
-    {12315, 12314, 1},
-    {65113, 65114, 0},
-    {65114, 65113, 1},
-    {65115, 65116, 0},
-    {65116, 65115, 1},
-    {65117, 65118, 0},
-    {65118, 65117, 1},
-    {65288, 65289, 0},
-    {65289, 65288, 1},
-    {65339, 65341, 0},
-    {65341, 65339, 1},
-    {65371, 65373, 0},
-    {65373, 65371, 1},
-    {65375, 65376, 0},
-    {65376, 65375, 1},
-    {65378, 65379, 0},
-    {65379, 65378, 1},
-};
-
-/* Reindexing of NFC first characters. */
-#define TOTAL_FIRST 376
-#define TOTAL_LAST 62
-static const Reindex nfc_first[] = {
-  { 60, 2, 0},
-  { 65, 15, 3},
-  { 82, 8, 19},
-  { 97, 15, 28},
-  { 114, 8, 44},
-  { 168, 0, 53},
-  { 194, 0, 54},
-  { 196, 3, 55},
-  { 202, 0, 59},
-  { 207, 0, 60},
-  { 212, 2, 61},
-  { 216, 0, 64},
-  { 220, 0, 65},
-  { 226, 0, 66},
-  { 228, 3, 67},
-  { 234, 0, 71},
-  { 239, 0, 72},
-  { 244, 2, 73},
-  { 248, 0, 76},
-  { 252, 0, 77},
-  { 258, 1, 78},
-  { 274, 1, 80},
-  { 332, 1, 82},
-  { 346, 1, 84},
-  { 352, 1, 86},
-  { 360, 3, 88},
-  { 383, 0, 92},
-  { 416, 1, 93},
-  { 431, 1, 95},
-  { 439, 0, 97},
-  { 490, 1, 98},
-  { 550, 3, 100},
-  { 558, 1, 104},
-  { 658, 0, 106},
-  { 913, 0, 107},
-  { 917, 0, 108},
-  { 919, 0, 109},
-  { 921, 0, 110},
-  { 927, 0, 111},
-  { 929, 0, 112},
-  { 933, 0, 113},
-  { 937, 0, 114},
-  { 940, 0, 115},
-  { 942, 0, 116},
-  { 945, 0, 117},
-  { 949, 0, 118},
-  { 951, 0, 119},
-  { 953, 0, 120},
-  { 959, 0, 121},
-  { 961, 0, 122},
-  { 965, 0, 123},
-  { 969, 2, 124},
-  { 974, 0, 127},
-  { 978, 0, 128},
-  { 1030, 0, 129},
-  { 1040, 0, 130},
-  { 1043, 0, 131},
-  { 1045, 3, 132},
-  { 1050, 0, 136},
-  { 1054, 0, 137},
-  { 1059, 0, 138},
-  { 1063, 0, 139},
-  { 1067, 0, 140},
-  { 1069, 0, 141},
-  { 1072, 0, 142},
-  { 1075, 0, 143},
-  { 1077, 3, 144},
-  { 1082, 0, 148},
-  { 1086, 0, 149},
-  { 1091, 0, 150},
-  { 1095, 0, 151},
-  { 1099, 0, 152},
-  { 1101, 0, 153},
-  { 1110, 0, 154},
-  { 1140, 1, 155},
-  { 1240, 1, 157},
-  { 1256, 1, 159},
-  { 1575, 0, 161},
-  { 1608, 0, 162},
-  { 1610, 0, 163},
-  { 1729, 0, 164},
-  { 1746, 0, 165},
-  { 1749, 0, 166},
-  { 2344, 0, 167},
-  { 2352, 0, 168},
-  { 2355, 0, 169},
-  { 2503, 0, 170},
-  { 2887, 0, 171},
-  { 2962, 0, 172},
-  { 3014, 1, 173},
-  { 3142, 0, 175},
-  { 3263, 0, 176},
-  { 3270, 0, 177},
-  { 3274, 0, 178},
-  { 3398, 1, 179},
-  { 3545, 0, 181},
-  { 3548, 0, 182},
-  { 4133, 0, 183},
-  { 6917, 0, 184},
-  { 6919, 0, 185},
-  { 6921, 0, 186},
-  { 6923, 0, 187},
-  { 6925, 0, 188},
-  { 6929, 0, 189},
-  { 6970, 0, 190},
-  { 6972, 0, 191},
-  { 6974, 1, 192},
-  { 6978, 0, 194},
-  { 7734, 1, 195},
-  { 7770, 1, 197},
-  { 7778, 1, 199},
-  { 7840, 1, 201},
-  { 7864, 1, 203},
-  { 7884, 1, 205},
-  { 7936, 17, 207},
-  { 7960, 1, 225},
-  { 7968, 17, 227},
-  { 7992, 1, 245},
-  { 8000, 1, 247},
-  { 8008, 1, 249},
-  { 8016, 1, 251},
-  { 8025, 0, 253},
-  { 8032, 16, 254},
-  { 8052, 0, 271},
-  { 8060, 0, 272},
-  { 8118, 0, 273},
-  { 8127, 0, 274},
-  { 8134, 0, 275},
-  { 8182, 0, 276},
-  { 8190, 0, 277},
-  { 8592, 0, 278},
-  { 8594, 0, 279},
-  { 8596, 0, 280},
-  { 8656, 0, 281},
-  { 8658, 0, 282},
-  { 8660, 0, 283},
-  { 8707, 0, 284},
-  { 8712, 0, 285},
-  { 8715, 0, 286},
-  { 8739, 0, 287},
-  { 8741, 0, 288},
-  { 8764, 0, 289},
-  { 8771, 0, 290},
-  { 8773, 0, 291},
-  { 8776, 0, 292},
-  { 8781, 0, 293},
-  { 8801, 0, 294},
-  { 8804, 1, 295},
-  { 8818, 1, 297},
-  { 8822, 1, 299},
-  { 8826, 3, 301},
-  { 8834, 1, 305},
-  { 8838, 1, 307},
-  { 8849, 1, 309},
-  { 8866, 0, 311},
-  { 8872, 1, 312},
-  { 8875, 0, 314},
-  { 8882, 3, 315},
-  { 12358, 0, 319},
-  { 12363, 0, 320},
-  { 12365, 0, 321},
-  { 12367, 0, 322},
-  { 12369, 0, 323},
-  { 12371, 0, 324},
-  { 12373, 0, 325},
-  { 12375, 0, 326},
-  { 12377, 0, 327},
-  { 12379, 0, 328},
-  { 12381, 0, 329},
-  { 12383, 0, 330},
-  { 12385, 0, 331},
-  { 12388, 0, 332},
-  { 12390, 0, 333},
-  { 12392, 0, 334},
-  { 12399, 0, 335},
-  { 12402, 0, 336},
-  { 12405, 0, 337},
-  { 12408, 0, 338},
-  { 12411, 0, 339},
-  { 12445, 0, 340},
-  { 12454, 0, 341},
-  { 12459, 0, 342},
-  { 12461, 0, 343},
-  { 12463, 0, 344},
-  { 12465, 0, 345},
-  { 12467, 0, 346},
-  { 12469, 0, 347},
-  { 12471, 0, 348},
-  { 12473, 0, 349},
-  { 12475, 0, 350},
-  { 12477, 0, 351},
-  { 12479, 0, 352},
-  { 12481, 0, 353},
-  { 12484, 0, 354},
-  { 12486, 0, 355},
-  { 12488, 0, 356},
-  { 12495, 0, 357},
-  { 12498, 0, 358},
-  { 12501, 0, 359},
-  { 12504, 0, 360},
-  { 12507, 0, 361},
-  { 12527, 3, 362},
-  { 12541, 0, 366},
-  { 69785, 0, 367},
-  { 69787, 0, 368},
-  { 69797, 0, 369},
-  { 69937, 1, 370},
-  { 70471, 0, 372},
-  { 70841, 0, 373},
-  { 71096, 1, 374},
-  {0,0,0}
-};
-
-static const Reindex nfc_last[] = {
-  { 768, 4, 0},
-  { 774, 6, 5},
-  { 783, 0, 12},
-  { 785, 0, 13},
-  { 787, 1, 14},
-  { 795, 0, 16},
-  { 803, 5, 17},
-  { 813, 1, 23},
-  { 816, 1, 25},
-  { 824, 0, 27},
-  { 834, 0, 28},
-  { 837, 0, 29},
-  { 1619, 2, 30},
-  { 2364, 0, 33},
-  { 2494, 0, 34},
-  { 2519, 0, 35},
-  { 2878, 0, 36},
-  { 2902, 1, 37},
-  { 3006, 0, 39},
-  { 3031, 0, 40},
-  { 3158, 0, 41},
-  { 3266, 0, 42},
-  { 3285, 1, 43},
-  { 3390, 0, 45},
-  { 3415, 0, 46},
-  { 3530, 0, 47},
-  { 3535, 0, 48},
-  { 3551, 0, 49},
-  { 4142, 0, 50},
-  { 6965, 0, 51},
-  { 12441, 1, 52},
-  { 69818, 0, 54},
-  { 69927, 0, 55},
-  { 70462, 0, 56},
-  { 70487, 0, 57},
-  { 70832, 0, 58},
-  { 70842, 0, 59},
-  { 70845, 0, 60},
-  { 71087, 0, 61},
-  {0,0,0}
-};
-
-#define UCDN_EAST_ASIAN_F 0
-#define UCDN_EAST_ASIAN_H 1
-#define UCDN_EAST_ASIAN_W 2
-#define UCDN_EAST_ASIAN_NA 3
-#define UCDN_EAST_ASIAN_A 4
-#define UCDN_EAST_ASIAN_N 5
-
-#define UCDN_SCRIPT_COMMON 0
-#define UCDN_SCRIPT_LATIN 1
-#define UCDN_SCRIPT_GREEK 2
-#define UCDN_SCRIPT_CYRILLIC 3
-#define UCDN_SCRIPT_ARMENIAN 4
-#define UCDN_SCRIPT_HEBREW 5
-#define UCDN_SCRIPT_ARABIC 6
-#define UCDN_SCRIPT_SYRIAC 7
-#define UCDN_SCRIPT_THAANA 8
-#define UCDN_SCRIPT_DEVANAGARI 9
-#define UCDN_SCRIPT_BENGALI 10
-#define UCDN_SCRIPT_GURMUKHI 11
-#define UCDN_SCRIPT_GUJARATI 12
-#define UCDN_SCRIPT_ORIYA 13
-#define UCDN_SCRIPT_TAMIL 14
-#define UCDN_SCRIPT_TELUGU 15
-#define UCDN_SCRIPT_KANNADA 16
-#define UCDN_SCRIPT_MALAYALAM 17
-#define UCDN_SCRIPT_SINHALA 18
-#define UCDN_SCRIPT_THAI 19
-#define UCDN_SCRIPT_LAO 20
-#define UCDN_SCRIPT_TIBETAN 21
-#define UCDN_SCRIPT_MYANMAR 22
-#define UCDN_SCRIPT_GEORGIAN 23
-#define UCDN_SCRIPT_HANGUL 24
-#define UCDN_SCRIPT_ETHIOPIC 25
-#define UCDN_SCRIPT_CHEROKEE 26
-#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
-#define UCDN_SCRIPT_OGHAM 28
-#define UCDN_SCRIPT_RUNIC 29
-#define UCDN_SCRIPT_KHMER 30
-#define UCDN_SCRIPT_MONGOLIAN 31
-#define UCDN_SCRIPT_HIRAGANA 32
-#define UCDN_SCRIPT_KATAKANA 33
-#define UCDN_SCRIPT_BOPOMOFO 34
-#define UCDN_SCRIPT_HAN 35
-#define UCDN_SCRIPT_YI 36
-#define UCDN_SCRIPT_OLD_ITALIC 37
-#define UCDN_SCRIPT_GOTHIC 38
-#define UCDN_SCRIPT_DESERET 39
-#define UCDN_SCRIPT_INHERITED 40
-#define UCDN_SCRIPT_TAGALOG 41
-#define UCDN_SCRIPT_HANUNOO 42
-#define UCDN_SCRIPT_BUHID 43
-#define UCDN_SCRIPT_TAGBANWA 44
-#define UCDN_SCRIPT_LIMBU 45
-#define UCDN_SCRIPT_TAI_LE 46
-#define UCDN_SCRIPT_LINEAR_B 47
-#define UCDN_SCRIPT_UGARITIC 48
-#define UCDN_SCRIPT_SHAVIAN 49
-#define UCDN_SCRIPT_OSMANYA 50
-#define UCDN_SCRIPT_CYPRIOT 51
-#define UCDN_SCRIPT_BRAILLE 52
-#define UCDN_SCRIPT_BUGINESE 53
-#define UCDN_SCRIPT_COPTIC 54
-#define UCDN_SCRIPT_NEW_TAI_LUE 55
-#define UCDN_SCRIPT_GLAGOLITIC 56
-#define UCDN_SCRIPT_TIFINAGH 57
-#define UCDN_SCRIPT_SYLOTI_NAGRI 58
-#define UCDN_SCRIPT_OLD_PERSIAN 59
-#define UCDN_SCRIPT_KHAROSHTHI 60
-#define UCDN_SCRIPT_BALINESE 61
-#define UCDN_SCRIPT_CUNEIFORM 62
-#define UCDN_SCRIPT_PHOENICIAN 63
-#define UCDN_SCRIPT_PHAGS_PA 64
-#define UCDN_SCRIPT_NKO 65
-#define UCDN_SCRIPT_SUNDANESE 66
-#define UCDN_SCRIPT_LEPCHA 67
-#define UCDN_SCRIPT_OL_CHIKI 68
-#define UCDN_SCRIPT_VAI 69
-#define UCDN_SCRIPT_SAURASHTRA 70
-#define UCDN_SCRIPT_KAYAH_LI 71
-#define UCDN_SCRIPT_REJANG 72
-#define UCDN_SCRIPT_LYCIAN 73
-#define UCDN_SCRIPT_CARIAN 74
-#define UCDN_SCRIPT_LYDIAN 75
-#define UCDN_SCRIPT_CHAM 76
-#define UCDN_SCRIPT_TAI_THAM 77
-#define UCDN_SCRIPT_TAI_VIET 78
-#define UCDN_SCRIPT_AVESTAN 79
-#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
-#define UCDN_SCRIPT_SAMARITAN 81
-#define UCDN_SCRIPT_LISU 82
-#define UCDN_SCRIPT_BAMUM 83
-#define UCDN_SCRIPT_JAVANESE 84
-#define UCDN_SCRIPT_MEETEI_MAYEK 85
-#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
-#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
-#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
-#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
-#define UCDN_SCRIPT_OLD_TURKIC 90
-#define UCDN_SCRIPT_KAITHI 91
-#define UCDN_SCRIPT_BATAK 92
-#define UCDN_SCRIPT_BRAHMI 93
-#define UCDN_SCRIPT_MANDAIC 94
-#define UCDN_SCRIPT_CHAKMA 95
-#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
-#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
-#define UCDN_SCRIPT_MIAO 98
-#define UCDN_SCRIPT_SHARADA 99
-#define UCDN_SCRIPT_SORA_SOMPENG 100
-#define UCDN_SCRIPT_TAKRI 101
-#define UCDN_SCRIPT_UNKNOWN 102
-#define UCDN_SCRIPT_BASSA_VAH 103
-#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
-#define UCDN_SCRIPT_DUPLOYAN 105
-#define UCDN_SCRIPT_ELBASAN 106
-#define UCDN_SCRIPT_GRANTHA 107
-#define UCDN_SCRIPT_KHOJKI 108
-#define UCDN_SCRIPT_KHUDAWADI 109
-#define UCDN_SCRIPT_LINEAR_A 110
-#define UCDN_SCRIPT_MAHAJANI 111
-#define UCDN_SCRIPT_MANICHAEAN 112
-#define UCDN_SCRIPT_MENDE_KIKAKUI 113
-#define UCDN_SCRIPT_MODI 114
-#define UCDN_SCRIPT_MRO 115
-#define UCDN_SCRIPT_NABATAEAN 116
-#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
-#define UCDN_SCRIPT_OLD_PERMIC 118
-#define UCDN_SCRIPT_PAHAWH_HMONG 119
-#define UCDN_SCRIPT_PALMYRENE 120
-#define UCDN_SCRIPT_PAU_CIN_HAU 121
-#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
-#define UCDN_SCRIPT_SIDDHAM 123
-#define UCDN_SCRIPT_TIRHUTA 124
-#define UCDN_SCRIPT_WARANG_CITI 125
-#define UCDN_SCRIPT_AHOM 126
-#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
-#define UCDN_SCRIPT_HATRAN 128
-#define UCDN_SCRIPT_MULTANI 129
-#define UCDN_SCRIPT_OLD_HUNGARIAN 130
-#define UCDN_SCRIPT_SIGNWRITING 131
-#define UCDN_SCRIPT_ADLAM 132
-#define UCDN_SCRIPT_BHAIKSUKI 133
-#define UCDN_SCRIPT_MARCHEN 134
-#define UCDN_SCRIPT_NEWA 135
-#define UCDN_SCRIPT_OSAGE 136
-#define UCDN_SCRIPT_TANGUT 137
-#define UCDN_SCRIPT_MASARAM_GONDI 138
-#define UCDN_SCRIPT_NUSHU 139
-#define UCDN_SCRIPT_SOYOMBO 140
-#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141
-#define UCDN_SCRIPT_DOGRA 142
-#define UCDN_SCRIPT_GUNJALA_GONDI 143
-#define UCDN_SCRIPT_HANIFI_ROHINGYA 144
-#define UCDN_SCRIPT_MAKASAR 145
-#define UCDN_SCRIPT_MEDEFAIDRIN 146
-#define UCDN_SCRIPT_OLD_SOGDIAN 147
-#define UCDN_SCRIPT_SOGDIAN 148
-
-#define UCDN_GENERAL_CATEGORY_CC 0
-#define UCDN_GENERAL_CATEGORY_CF 1
-#define UCDN_GENERAL_CATEGORY_CN 2
-#define UCDN_GENERAL_CATEGORY_CO 3
-#define UCDN_GENERAL_CATEGORY_CS 4
-#define UCDN_GENERAL_CATEGORY_LL 5
-#define UCDN_GENERAL_CATEGORY_LM 6
-#define UCDN_GENERAL_CATEGORY_LO 7
-#define UCDN_GENERAL_CATEGORY_LT 8
-#define UCDN_GENERAL_CATEGORY_LU 9
-#define UCDN_GENERAL_CATEGORY_MC 10
-#define UCDN_GENERAL_CATEGORY_ME 11
-#define UCDN_GENERAL_CATEGORY_MN 12
-#define UCDN_GENERAL_CATEGORY_ND 13
-#define UCDN_GENERAL_CATEGORY_NL 14
-#define UCDN_GENERAL_CATEGORY_NO 15
-#define UCDN_GENERAL_CATEGORY_PC 16
-#define UCDN_GENERAL_CATEGORY_PD 17
-#define UCDN_GENERAL_CATEGORY_PE 18
-#define UCDN_GENERAL_CATEGORY_PF 19
-#define UCDN_GENERAL_CATEGORY_PI 20
-#define UCDN_GENERAL_CATEGORY_PO 21
-#define UCDN_GENERAL_CATEGORY_PS 22
-#define UCDN_GENERAL_CATEGORY_SC 23
-#define UCDN_GENERAL_CATEGORY_SK 24
-#define UCDN_GENERAL_CATEGORY_SM 25
-#define UCDN_GENERAL_CATEGORY_SO 26
-#define UCDN_GENERAL_CATEGORY_ZL 27
-#define UCDN_GENERAL_CATEGORY_ZP 28
-#define UCDN_GENERAL_CATEGORY_ZS 29
-
-#define UCDN_BIDI_CLASS_L 0
-#define UCDN_BIDI_CLASS_LRE 1
-#define UCDN_BIDI_CLASS_LRO 2
-#define UCDN_BIDI_CLASS_R 3
-#define UCDN_BIDI_CLASS_AL 4
-#define UCDN_BIDI_CLASS_RLE 5
-#define UCDN_BIDI_CLASS_RLO 6
-#define UCDN_BIDI_CLASS_PDF 7
-#define UCDN_BIDI_CLASS_EN 8
-#define UCDN_BIDI_CLASS_ES 9
-#define UCDN_BIDI_CLASS_ET 10
-#define UCDN_BIDI_CLASS_AN 11
-#define UCDN_BIDI_CLASS_CS 12
-#define UCDN_BIDI_CLASS_NSM 13
-#define UCDN_BIDI_CLASS_BN 14
-#define UCDN_BIDI_CLASS_B 15
-#define UCDN_BIDI_CLASS_S 16
-#define UCDN_BIDI_CLASS_WS 17
-#define UCDN_BIDI_CLASS_ON 18
-#define UCDN_BIDI_CLASS_LRI 19
-#define UCDN_BIDI_CLASS_RLI 20
-#define UCDN_BIDI_CLASS_FSI 21
-#define UCDN_BIDI_CLASS_PDI 22
-
-/* index tables for the database records */
-#define SHIFT1 5
-#define SHIFT2 3
-static const unsigned char index0[] = {
-    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, 35, 36, 37, 38, 
-    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 54, 55, 56, 56, 56, 57, 
-    58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 
-    69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 
-    66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 72, 73, 73, 73, 
-    73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 52, 75, 76, 77, 78, 79, 
-    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 
-    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 106, 108, 109, 110, 106, 
-    111, 111, 111, 112, 113, 114, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 115, 115, 116, 117, 118, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 119, 120, 121, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 122, 122, 123, 124, 106, 106, 125, 126, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 128, 127, 127, 129, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 130, 131, 132, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 133, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 134, 135, 136, 137, 138, 139, 
-    140, 141, 142, 142, 143, 106, 106, 106, 106, 106, 144, 106, 106, 106, 
-    106, 106, 106, 106, 145, 146, 106, 106, 147, 106, 148, 106, 149, 150, 
-    151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 160, 160, 160, 161, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 162, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 163, 164, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 165, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
-    166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 52, 52, 
-    168, 167, 167, 167, 167, 169, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 170, 171, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    172, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 172, 
-};
-
-static const unsigned short index1[] = {
-    0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15, 
-    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32, 
-    33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 
-    47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54, 
-    53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63, 
-    64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78, 
-    79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 
-    97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103, 
-    101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101, 
-    101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 110, 
-    110, 110, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 120, 
-    120, 121, 122, 119, 123, 124, 125, 126, 127, 127, 127, 127, 128, 129, 
-    130, 131, 132, 133, 134, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
-    127, 127, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 144, 
-    145, 146, 147, 148, 127, 127, 127, 127, 127, 127, 149, 149, 149, 149, 
-    150, 151, 152, 119, 153, 154, 155, 155, 155, 156, 157, 158, 159, 159, 
-    160, 161, 162, 163, 164, 165, 166, 166, 166, 167, 144, 168, 119, 119, 
-    119, 119, 119, 119, 127, 127, 169, 170, 119, 119, 171, 125, 172, 173, 
-    174, 175, 176, 177, 177, 177, 177, 177, 177, 178, 179, 180, 181, 177, 
-    182, 183, 184, 177, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193, 
-    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, 
-    207, 208, 209, 210, 211, 212, 213, 119, 214, 215, 216, 217, 217, 218, 
-    219, 220, 221, 222, 223, 119, 224, 225, 226, 227, 228, 229, 230, 231, 
-    231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 119, 242, 243, 
-    244, 245, 246, 243, 247, 248, 249, 250, 251, 119, 252, 253, 254, 255, 
-    256, 257, 258, 259, 259, 258, 259, 260, 261, 262, 263, 264, 265, 266, 
-    119, 267, 268, 269, 270, 271, 271, 270, 272, 273, 274, 275, 276, 277, 
-    278, 279, 280, 119, 281, 282, 283, 284, 284, 284, 284, 285, 286, 287, 
-    288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 295, 295, 298, 299, 
-    296, 300, 301, 302, 303, 304, 305, 119, 306, 307, 307, 307, 307, 307, 
-    308, 309, 310, 311, 312, 313, 119, 119, 119, 119, 314, 315, 316, 317, 
-    318, 319, 320, 321, 322, 323, 324, 325, 119, 119, 119, 119, 326, 327, 
-    328, 329, 330, 331, 332, 333, 334, 335, 334, 334, 334, 336, 337, 338, 
-    339, 340, 341, 342, 341, 341, 341, 343, 344, 345, 346, 347, 119, 119, 
-    119, 119, 348, 348, 348, 348, 348, 349, 350, 351, 352, 353, 354, 355, 
-    356, 357, 358, 348, 359, 360, 352, 361, 362, 362, 362, 362, 363, 364, 
-    365, 365, 365, 365, 365, 366, 367, 367, 367, 367, 367, 367, 367, 367, 
-    367, 367, 367, 367, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369, 
-    369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 370, 370, 370, 370, 
-    370, 370, 370, 370, 370, 371, 372, 371, 370, 370, 370, 370, 370, 371, 
-    370, 370, 370, 370, 371, 372, 371, 370, 372, 370, 370, 370, 370, 370, 
-    370, 370, 371, 370, 370, 370, 370, 370, 370, 370, 370, 373, 374, 375, 
-    376, 377, 370, 370, 378, 379, 380, 380, 380, 380, 380, 380, 380, 380, 
-    380, 380, 381, 382, 383, 384, 384, 384, 384, 384, 384, 384, 384, 384, 
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 385, 384, 384, 
-    386, 387, 387, 388, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, 
-    391, 392, 393, 394, 395, 119, 396, 396, 397, 119, 398, 398, 399, 119, 
-    400, 401, 402, 119, 403, 403, 403, 403, 403, 403, 404, 405, 406, 407, 
-    408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 418, 418, 418, 
-    419, 418, 418, 418, 418, 418, 418, 420, 421, 418, 418, 418, 418, 422, 
-    384, 384, 384, 384, 384, 384, 384, 384, 423, 119, 424, 424, 424, 425, 
-    426, 427, 428, 429, 430, 431, 432, 432, 432, 433, 434, 119, 435, 435, 
-    435, 435, 435, 436, 435, 435, 435, 437, 438, 439, 440, 440, 440, 440, 
-    441, 441, 442, 443, 444, 444, 444, 444, 444, 444, 445, 446, 447, 448, 
-    449, 450, 451, 452, 451, 452, 453, 454, 455, 456, 119, 119, 119, 119, 
-    119, 119, 119, 119, 457, 458, 458, 458, 458, 458, 459, 460, 461, 462, 
-    463, 464, 465, 466, 467, 468, 469, 470, 470, 470, 471, 472, 473, 474, 
-    475, 475, 475, 475, 476, 477, 478, 479, 480, 480, 480, 480, 481, 482, 
-    483, 484, 485, 486, 487, 488, 489, 489, 489, 490, 100, 491, 362, 362, 
-    362, 362, 362, 492, 493, 119, 494, 495, 496, 497, 498, 499, 54, 54, 54, 
-    54, 500, 501, 56, 56, 56, 56, 56, 502, 503, 504, 54, 505, 54, 54, 54, 
-    506, 56, 56, 56, 507, 508, 509, 510, 511, 511, 511, 512, 513, 27, 27, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 514, 515, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 516, 517, 518, 519, 516, 517, 
-    516, 517, 518, 519, 516, 520, 516, 517, 516, 518, 516, 521, 516, 521, 
-    516, 521, 522, 523, 524, 525, 526, 527, 516, 528, 529, 530, 531, 532, 
-    533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 
-    547, 548, 56, 549, 550, 551, 552, 553, 554, 554, 555, 556, 557, 558, 559, 
-    119, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 
-    573, 572, 574, 575, 576, 577, 578, 579, 580, 581, 582, 581, 583, 584, 
-    581, 585, 581, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 587, 
-    596, 597, 587, 598, 599, 587, 587, 599, 587, 600, 601, 600, 587, 587, 
-    602, 587, 587, 587, 587, 587, 603, 587, 587, 581, 604, 605, 606, 607, 
-    608, 609, 610, 610, 610, 610, 610, 610, 610, 610, 611, 581, 581, 612, 
-    613, 587, 587, 614, 581, 581, 581, 581, 586, 607, 615, 616, 581, 581, 
-    581, 581, 581, 617, 119, 119, 119, 581, 618, 119, 119, 619, 619, 619, 
-    619, 619, 620, 620, 621, 622, 622, 622, 622, 622, 622, 622, 622, 622, 
-    623, 619, 624, 625, 625, 625, 625, 625, 625, 625, 625, 625, 626, 625, 
-    625, 625, 625, 627, 581, 625, 625, 628, 581, 629, 630, 631, 632, 633, 
-    634, 630, 581, 628, 635, 581, 636, 637, 638, 639, 640, 581, 581, 581, 
-    641, 642, 643, 644, 581, 645, 646, 581, 647, 581, 581, 648, 649, 650, 
-    651, 581, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 581, 
-    581, 581, 663, 581, 664, 581, 665, 666, 667, 668, 669, 670, 619, 671, 
-    671, 672, 581, 581, 581, 663, 673, 674, 587, 587, 587, 675, 676, 587, 
-    587, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 
-    677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 
-    677, 677, 677, 677, 677, 587, 587, 587, 587, 587, 587, 587, 587, 587, 
-    587, 587, 587, 587, 587, 587, 587, 678, 679, 679, 680, 587, 587, 587, 
-    587, 587, 587, 587, 681, 587, 587, 587, 682, 587, 587, 587, 587, 587, 
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 581, 
-    581, 581, 683, 581, 581, 587, 587, 684, 685, 686, 630, 581, 581, 687, 
-    581, 581, 581, 688, 581, 581, 581, 581, 581, 581, 689, 581, 581, 581, 
-    581, 581, 617, 690, 690, 690, 690, 690, 691, 692, 692, 692, 692, 692, 
-    693, 694, 695, 696, 697, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
-    698, 699, 700, 701, 365, 365, 365, 365, 702, 703, 704, 704, 704, 704, 
-    704, 704, 704, 705, 706, 707, 370, 370, 372, 119, 372, 372, 372, 372, 
-    372, 372, 372, 372, 708, 708, 708, 708, 709, 710, 711, 712, 713, 714, 
-    715, 716, 717, 718, 119, 119, 119, 119, 119, 119, 719, 719, 719, 720, 
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 721, 119, 719, 719, 
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 722, 119, 119, 119, 
-    723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 735, 
-    736, 735, 735, 735, 737, 738, 739, 740, 741, 742, 743, 743, 744, 743, 
-    743, 743, 745, 746, 747, 748, 749, 750, 750, 750, 750, 750, 751, 752, 
-    752, 752, 752, 752, 752, 752, 752, 752, 752, 753, 754, 755, 750, 750, 
-    750, 756, 723, 723, 723, 723, 724, 119, 757, 757, 758, 758, 758, 759, 
-    760, 761, 755, 755, 755, 762, 763, 764, 758, 758, 758, 765, 760, 761, 
-    755, 755, 755, 755, 766, 764, 755, 767, 768, 768, 768, 768, 768, 769, 
-    768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 755, 755, 755, 
-    770, 771, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 772, 
-    755, 755, 755, 770, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 774, 775, 581, 581, 581, 581, 581, 581, 581, 581, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    775, 775, 776, 776, 777, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 778, 
-    779, 779, 779, 779, 779, 779, 780, 119, 781, 781, 781, 781, 781, 782, 
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 
-    783, 783, 783, 783, 783, 784, 783, 783, 785, 786, 119, 119, 101, 101, 
-    101, 101, 101, 787, 788, 789, 101, 101, 101, 790, 791, 791, 791, 791, 
-    791, 791, 791, 791, 792, 793, 794, 119, 64, 64, 795, 796, 797, 27, 798, 
-    27, 27, 27, 27, 27, 27, 27, 799, 800, 27, 801, 802, 27, 27, 803, 804, 
-    805, 119, 119, 119, 119, 119, 119, 806, 807, 808, 809, 810, 810, 811, 
-    812, 813, 814, 815, 815, 815, 815, 815, 815, 816, 119, 817, 818, 818, 
-    818, 818, 818, 819, 820, 821, 822, 823, 824, 825, 825, 826, 827, 828, 
-    829, 830, 830, 831, 832, 833, 833, 834, 835, 836, 837, 367, 367, 367, 
-    838, 839, 840, 840, 840, 840, 840, 841, 842, 843, 844, 845, 846, 847, 
-    348, 352, 848, 849, 849, 849, 849, 849, 850, 851, 119, 852, 853, 854, 
-    855, 348, 348, 856, 857, 858, 858, 858, 858, 858, 858, 859, 860, 861, 
-    119, 119, 862, 863, 864, 865, 119, 866, 866, 866, 119, 372, 372, 54, 54, 
-    54, 54, 54, 867, 868, 119, 869, 869, 869, 869, 869, 869, 869, 869, 869, 
-    869, 863, 863, 863, 863, 870, 871, 872, 873, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 875, 875, 875, 874, 875, 
-    875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 
-    875, 877, 119, 368, 368, 878, 879, 369, 369, 369, 369, 369, 880, 881, 
-    881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 
-    881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 
-    881, 881, 881, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 
-    882, 882, 882, 882, 882, 882, 882, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 883, 775, 775, 775, 775, 884, 119, 885, 
-    886, 120, 887, 888, 889, 890, 120, 127, 127, 127, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 891, 892, 893, 119, 894, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 895, 119, 
-    119, 127, 127, 127, 127, 127, 127, 127, 127, 896, 127, 127, 127, 127, 
-    127, 127, 119, 119, 119, 119, 119, 127, 897, 898, 898, 899, 900, 901, 
-    902, 903, 904, 905, 906, 907, 908, 909, 910, 169, 127, 127, 127, 127, 
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 911, 912, 
-    913, 914, 915, 916, 917, 917, 918, 919, 920, 920, 921, 922, 923, 924, 
-    925, 925, 925, 925, 926, 927, 927, 927, 928, 929, 929, 929, 930, 931, 
-    932, 119, 933, 934, 935, 934, 934, 936, 934, 934, 937, 934, 938, 934, 
-    938, 119, 119, 119, 119, 934, 934, 934, 934, 934, 934, 934, 934, 934, 
-    934, 934, 934, 934, 934, 934, 939, 940, 941, 941, 941, 941, 941, 942, 
-    610, 943, 943, 943, 943, 943, 943, 944, 945, 946, 947, 581, 948, 949, 
-    119, 119, 119, 119, 119, 610, 610, 610, 610, 610, 950, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 951, 
-    951, 951, 952, 953, 953, 953, 953, 953, 953, 954, 119, 955, 956, 956, 
-    957, 958, 958, 958, 958, 959, 960, 961, 961, 962, 963, 964, 964, 964, 
-    964, 965, 966, 967, 967, 967, 968, 969, 969, 969, 969, 970, 969, 971, 
-    119, 119, 119, 119, 119, 972, 972, 972, 972, 972, 973, 973, 973, 973, 
-    973, 974, 974, 974, 974, 974, 974, 975, 975, 975, 976, 977, 978, 979, 
-    979, 979, 979, 980, 981, 981, 981, 981, 982, 983, 983, 983, 983, 983, 
-    119, 984, 984, 984, 984, 984, 984, 985, 986, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 987, 
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 988, 119, 987, 987, 989, 
-    119, 987, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 990, 991, 992, 992, 992, 992, 993, 
-    994, 995, 995, 996, 997, 998, 998, 999, 1000, 1001, 1001, 1001, 1002, 
-    1003, 1004, 119, 119, 119, 119, 119, 119, 1005, 1005, 1006, 1007, 1008, 
-    1008, 1009, 1010, 1011, 1011, 1011, 1012, 119, 119, 119, 119, 119, 119, 
-    119, 119, 1013, 1013, 1013, 1013, 1014, 1014, 1014, 1015, 1016, 1016, 
-    1017, 1016, 1016, 1016, 1016, 1016, 1018, 1019, 1020, 1021, 1022, 1022, 
-    1023, 1024, 1025, 1026, 1027, 1028, 1029, 1029, 1029, 1030, 1031, 1031, 
-    1031, 1032, 119, 119, 119, 119, 1033, 1034, 1033, 1033, 1035, 1036, 1037, 
-    119, 1038, 1038, 1038, 1038, 1038, 1038, 1039, 1040, 1041, 1041, 1042, 
-    1043, 1044, 1044, 1045, 1046, 1047, 1047, 1048, 1049, 119, 1050, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 1051, 1051, 1051, 1051, 
-    1051, 1051, 1051, 1051, 1051, 1052, 119, 119, 119, 119, 119, 119, 1053, 
-    1053, 1053, 1053, 1053, 1053, 1054, 119, 1055, 1055, 1055, 1055, 1055, 
-    1055, 1056, 1057, 1058, 1058, 1058, 1058, 1059, 119, 1060, 1061, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 1062, 1062, 1062, 1063, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1064, 
-    1064, 1064, 1065, 1066, 119, 1067, 1067, 1068, 1069, 1070, 1071, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 1072, 1073, 1073, 1073, 1073, 1073, 1073, 1074, 
-    1075, 1076, 1077, 1078, 1079, 1080, 119, 1081, 1082, 1083, 1083, 1083, 
-    1083, 1083, 1084, 1085, 1086, 1087, 1088, 1088, 1088, 1089, 1090, 1091, 
-    1092, 1093, 1093, 1093, 1094, 1095, 1096, 1097, 1098, 119, 1099, 1099, 
-    1099, 1099, 1100, 119, 1101, 1102, 1102, 1102, 1102, 1102, 1103, 1104, 
-    1105, 1106, 1107, 1108, 1109, 1110, 1111, 119, 1112, 1112, 1113, 1112, 
-    1112, 1114, 1115, 1116, 119, 119, 119, 119, 119, 119, 119, 119, 1117, 
-    1118, 1119, 1120, 1119, 1121, 1122, 1122, 1122, 1122, 1122, 1123, 1124, 
-    1125, 1126, 1127, 1128, 1129, 1130, 1131, 1131, 1132, 1133, 1134, 1135, 
-    1136, 1137, 1138, 1139, 1140, 1140, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1141, 1141, 1141, 1141, 
-    1141, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 119, 119, 119, 119, 1148, 
-    1148, 1148, 1148, 1148, 1148, 1149, 1150, 1151, 119, 1152, 1153, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 1154, 1154, 1154, 1154, 1154, 1155, 1156, 1157, 
-    1158, 1159, 1160, 1161, 119, 119, 119, 119, 1162, 1162, 1162, 1162, 1162, 
-    1162, 1163, 1164, 1165, 119, 1166, 1167, 1168, 1169, 119, 119, 1170, 
-    1170, 1170, 1170, 1170, 1171, 1172, 119, 1173, 1174, 119, 119, 119, 119, 
-    119, 119, 1175, 1175, 1175, 1176, 1177, 1178, 1179, 1180, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 1181, 1181, 1181, 1181, 1181, 1182, 
-    1183, 1184, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    1185, 1185, 1185, 1185, 1186, 1186, 1186, 1186, 1187, 1188, 1189, 1190, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 1191, 1192, 1193, 1193, 1193, 1193, 1194, 1195, 1196, 
-    119, 1197, 1198, 1199, 1199, 1199, 1199, 1200, 1201, 1202, 1203, 1204, 
-    119, 119, 119, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1206, 1207, 
-    1208, 1207, 1207, 1207, 1209, 1210, 1211, 1212, 119, 1213, 1214, 1215, 
-    1216, 1217, 1218, 1218, 1218, 1219, 1220, 1220, 1221, 1222, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 1223, 1224, 1225, 1225, 1225, 1225, 
-    1226, 1227, 1228, 119, 1229, 1230, 1231, 1232, 1233, 1233, 1233, 1234, 
-    1235, 1236, 1237, 1238, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    1239, 1239, 1240, 1241, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1243, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 1244, 1244, 1244, 1244, 1244, 1244, 
-    1244, 1244, 1244, 1244, 1244, 1244, 1244, 1245, 1246, 119, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1247, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1249, 1248, 1248, 1248, 1248, 1250, 1251, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1252, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 
-    1253, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1255, 1254, 1254, 1254, 
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1256, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 791, 791, 791, 791, 791, 
-    791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 
-    791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 
-    791, 791, 791, 791, 791, 791, 1257, 1258, 1258, 1258, 1259, 1260, 1261, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1262, 1262, 
-    1262, 1263, 1264, 119, 1265, 1265, 1265, 1265, 1265, 1265, 1266, 1267, 
-    1268, 119, 1269, 1270, 1271, 1265, 1265, 1272, 1265, 1265, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 1273, 1273, 1273, 1273, 1274, 1274, 1274, 1274, 
-    1275, 1275, 1276, 1277, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1279, 119, 
-    1280, 1281, 1281, 1281, 1281, 1282, 119, 1283, 1284, 1285, 119, 119, 119, 
-    119, 119, 119, 119, 119, 1286, 119, 119, 119, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1288, 119, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 
-    1287, 1287, 1287, 1287, 1287, 1287, 1289, 119, 1290, 735, 735, 735, 735, 
-    735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 
-    735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 
-    735, 735, 1291, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1292, 
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 
-    1293, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 
-    1294, 1294, 1295, 1294, 1296, 1294, 1297, 1294, 1298, 1299, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 610, 610, 610, 610, 610, 
-    610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 
-    610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 1300, 119, 610, 
-    610, 610, 610, 1301, 1302, 610, 610, 610, 610, 610, 610, 1303, 1304, 
-    1305, 1306, 1307, 1308, 610, 610, 610, 1309, 610, 610, 610, 610, 610, 
-    610, 610, 1310, 119, 119, 946, 946, 946, 946, 946, 946, 946, 946, 1311, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 941, 941, 1312, 119, 581, 581, 581, 581, 581, 
-    581, 581, 581, 581, 581, 617, 119, 941, 941, 941, 1313, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1314, 
-    1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314, 1318, 1319, 1316, 1316, 
-    1314, 1314, 1314, 1315, 1316, 1316, 1320, 1321, 1322, 1318, 1323, 1324, 
-    1316, 1314, 1314, 1314, 1315, 1316, 1316, 1325, 1326, 1327, 1328, 1316, 
-    1316, 1316, 1329, 1330, 1331, 1332, 1316, 1316, 1317, 1314, 1314, 1318, 
-    1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314, 
-    1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314, 
-    1314, 1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1333, 
-    1314, 1314, 1314, 1334, 1316, 1316, 1335, 1336, 1314, 1314, 1337, 1316, 
-    1316, 1338, 1317, 1314, 1314, 1339, 1316, 1316, 1340, 1341, 1314, 1314, 
-    1342, 1316, 1316, 1316, 1343, 1314, 1314, 1314, 1334, 1316, 1316, 1335, 
-    1344, 1345, 1345, 1345, 1345, 1345, 1345, 1346, 1346, 1346, 1346, 1346, 
-    1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 
-    1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 
-    1346, 1346, 1346, 1347, 1347, 1347, 1347, 1347, 1347, 1348, 1349, 1347, 
-    1347, 1347, 1347, 1347, 1350, 1351, 1346, 1352, 1353, 119, 1354, 1355, 
-    1347, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1356, 1357, 1357, 
-    1358, 1359, 1360, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1362, 1363, 1364, 119, 119, 119, 119, 119, 1365, 1365, 1365, 1365, 
-    1366, 1367, 1367, 1367, 1368, 1369, 1370, 1371, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 1372, 1373, 1373, 1373, 1373, 1373, 1373, 1374, 1375, 119, 119, 119, 
-    119, 119, 119, 119, 119, 119, 1376, 127, 127, 127, 1377, 1378, 1379, 
-    1380, 1381, 1382, 1377, 1383, 1377, 1379, 1379, 1384, 127, 1385, 127, 
-    1386, 1387, 1385, 127, 1386, 119, 119, 119, 119, 119, 119, 1388, 119, 
-    1389, 1390, 1390, 1390, 1390, 1391, 1390, 1390, 1390, 1390, 1390, 1390, 
-    1390, 1390, 1390, 1390, 1390, 1390, 1391, 1392, 1390, 1393, 1394, 1390, 
-    1394, 1395, 1394, 1390, 1390, 1390, 1396, 1392, 620, 1397, 622, 622, 622, 
-    1398, 622, 622, 622, 622, 622, 622, 622, 1399, 622, 622, 622, 1400, 1401, 
-    1402, 622, 1403, 1392, 1392, 1392, 1392, 1392, 1392, 1404, 1405, 1405, 
-    1405, 1406, 1392, 755, 755, 755, 755, 755, 1407, 755, 1408, 1409, 1392, 
-    1410, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 723, 723, 723, 723, 1411, 
-    1412, 1413, 723, 723, 723, 723, 723, 723, 723, 723, 1414, 1415, 723, 
-    1416, 1417, 723, 723, 1418, 1419, 1420, 1421, 1416, 1390, 723, 723, 1422, 
-    1423, 723, 723, 723, 723, 723, 723, 723, 1424, 1425, 1426, 1427, 723, 
-    1428, 1429, 1426, 1430, 1431, 723, 723, 723, 1432, 1433, 1434, 723, 723, 
-    723, 723, 723, 723, 723, 723, 1435, 1436, 723, 1437, 643, 1438, 723, 
-    1439, 1440, 581, 1441, 723, 723, 723, 1390, 1442, 1443, 1390, 1390, 1444, 
-    1390, 1389, 1390, 1390, 1390, 1390, 1390, 1445, 1446, 1390, 1390, 1445, 
-    1447, 723, 723, 723, 723, 723, 723, 723, 723, 1448, 1449, 581, 581, 581, 
-    581, 1450, 1451, 723, 723, 723, 723, 1452, 723, 1453, 723, 1454, 1455, 
-    1456, 1392, 1390, 1457, 1458, 1459, 581, 581, 581, 581, 581, 581, 581, 
-    581, 581, 581, 581, 581, 581, 581, 1460, 1392, 581, 581, 581, 581, 581, 
-    581, 581, 581, 581, 581, 1461, 1462, 1392, 1392, 1392, 1392, 581, 1460, 
-    581, 581, 581, 581, 581, 581, 581, 1392, 581, 1463, 581, 581, 581, 581, 
-    581, 1392, 581, 581, 581, 1464, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 581, 1460, 723, 1465, 1466, 723, 1426, 1467, 723, 723, 
-    723, 723, 723, 723, 1468, 1469, 723, 723, 723, 723, 1470, 1392, 1471, 
-    1472, 1470, 1392, 1473, 1474, 723, 723, 723, 723, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1390, 1396, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1475, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 1476, 775, 775, 775, 775, 775, 773, 
-    773, 773, 773, 773, 773, 1477, 775, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 883, 
-    775, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 1478, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 773, 773, 773, 774, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 1479, 1480, 
-    119, 119, 119, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 
-    1481, 1481, 1481, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 
-    119, 119, 119, 119, 119, 898, 898, 898, 898, 898, 898, 898, 898, 898, 
-    898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 
-    898, 898, 898, 898, 898, 898, 898, 119, 119, 882, 882, 882, 882, 882, 
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 1482, 
-};
-
-static const unsigned short index2[] = {
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1, 7, 7, 7, 8, 
-    9, 10, 11, 12, 13, 14, 15, 11, 16, 17, 15, 18, 19, 20, 19, 21, 22, 22, 
-    22, 22, 22, 22, 22, 22, 22, 22, 19, 23, 24, 24, 24, 10, 15, 25, 25, 25, 
-    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 16, 26, 17, 
-    27, 28, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 
-    29, 29, 29, 16, 30, 31, 24, 1, 1, 1, 1, 1, 1, 32, 1, 1, 33, 34, 35, 13, 
-    36, 13, 37, 38, 39, 40, 41, 42, 24, 43, 44, 27, 45, 46, 47, 47, 48, 49, 
-    38, 38, 39, 47, 41, 50, 51, 51, 51, 34, 52, 52, 52, 52, 52, 52, 53, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 52, 54, 53, 52, 
-    52, 52, 52, 52, 53, 55, 55, 55, 56, 56, 56, 56, 55, 56, 55, 55, 55, 56, 
-    55, 55, 56, 56, 55, 56, 55, 55, 56, 56, 56, 54, 55, 55, 55, 56, 55, 56, 
-    55, 56, 52, 55, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 
-    52, 55, 52, 55, 52, 56, 52, 56, 52, 56, 52, 55, 52, 56, 52, 56, 52, 56, 
-    52, 56, 52, 56, 53, 55, 52, 55, 53, 55, 52, 56, 52, 56, 55, 52, 56, 52, 
-    56, 52, 56, 53, 55, 53, 55, 52, 55, 52, 56, 52, 55, 55, 53, 55, 52, 55, 
-    52, 56, 52, 56, 53, 55, 52, 56, 52, 56, 52, 52, 56, 52, 56, 52, 56, 56, 
-    56, 52, 52, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 56, 52, 52, 52, 52, 
-    56, 52, 52, 56, 52, 52, 52, 56, 56, 56, 52, 52, 56, 52, 52, 56, 52, 56, 
-    52, 56, 52, 52, 56, 52, 56, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 52, 
-    56, 52, 52, 56, 56, 57, 52, 56, 56, 56, 57, 57, 57, 57, 52, 58, 56, 52, 
-    58, 56, 52, 58, 56, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52, 
-    55, 52, 55, 56, 52, 56, 56, 52, 58, 56, 52, 56, 52, 52, 52, 56, 52, 56, 
-    56, 56, 56, 56, 56, 56, 52, 52, 56, 52, 52, 56, 56, 52, 56, 52, 52, 52, 
-    52, 56, 56, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 
-    56, 56, 56, 56, 57, 56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 
-    60, 61, 61, 61, 61, 61, 61, 61, 62, 62, 63, 62, 60, 64, 65, 64, 64, 64, 
-    65, 64, 60, 60, 66, 61, 62, 62, 62, 62, 62, 62, 39, 39, 39, 39, 62, 39, 
-    62, 48, 59, 59, 59, 59, 59, 62, 62, 62, 62, 62, 67, 67, 60, 62, 61, 62, 
-    62, 62, 62, 62, 62, 62, 62, 62, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
-    68, 68, 68, 69, 70, 70, 70, 70, 69, 71, 70, 70, 70, 70, 70, 72, 72, 70, 
-    70, 70, 70, 72, 72, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 73, 73, 
-    73, 73, 73, 70, 70, 70, 70, 68, 68, 68, 68, 68, 68, 68, 68, 74, 68, 70, 
-    70, 70, 68, 68, 68, 70, 70, 75, 68, 68, 68, 70, 70, 70, 70, 68, 69, 70, 
-    70, 68, 76, 77, 77, 76, 77, 77, 76, 68, 68, 68, 68, 68, 78, 79, 78, 79, 
-    60, 80, 78, 79, 81, 81, 82, 79, 79, 79, 83, 78, 81, 81, 81, 81, 80, 62, 
-    78, 84, 78, 78, 78, 81, 78, 81, 78, 78, 79, 85, 85, 85, 85, 85, 85, 85, 
-    85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 81, 85, 85, 85, 85, 85, 85, 85, 
-    78, 78, 79, 79, 79, 79, 79, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 
-    86, 86, 86, 86, 86, 86, 79, 86, 86, 86, 86, 86, 86, 86, 79, 79, 79, 79, 
-    79, 78, 79, 79, 78, 78, 78, 79, 79, 79, 78, 79, 78, 79, 78, 79, 78, 79, 
-    78, 79, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 79, 79, 
-    79, 79, 78, 79, 89, 78, 79, 78, 78, 79, 79, 78, 78, 78, 90, 91, 90, 90, 
-    90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 
-    91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 93, 92, 93, 93, 93, 93, 93, 93, 
-    93, 93, 93, 93, 93, 93, 93, 93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93, 
-    94, 95, 95, 96, 96, 95, 97, 97, 90, 93, 90, 93, 90, 93, 90, 90, 93, 90, 
-    93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93, 93, 81, 98, 98, 98, 98, 98, 
-    98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 81, 
-    81, 99, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 
-    101, 101, 102, 103, 81, 81, 104, 104, 105, 81, 106, 107, 107, 107, 107, 
-    106, 107, 107, 107, 108, 106, 107, 107, 107, 107, 107, 107, 106, 106, 
-    106, 106, 106, 106, 107, 107, 106, 107, 107, 108, 109, 107, 110, 111, 
-    112, 113, 114, 115, 116, 117, 118, 119, 119, 120, 121, 122, 123, 124, 
-    125, 126, 127, 125, 107, 106, 128, 118, 81, 81, 81, 81, 81, 81, 81, 81, 
-    129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 81, 81, 81, 
-    129, 129, 129, 129, 125, 125, 81, 81, 81, 130, 130, 130, 130, 130, 131, 
-    132, 132, 133, 134, 134, 135, 136, 137, 138, 138, 139, 139, 139, 139, 
-    139, 139, 139, 139, 140, 141, 142, 143, 144, 81, 145, 143, 146, 146, 146, 
-    146, 146, 146, 146, 146, 147, 146, 146, 146, 146, 146, 146, 146, 146, 
-    146, 146, 148, 149, 150, 151, 152, 153, 154, 155, 96, 96, 156, 157, 139, 
-    139, 139, 139, 139, 157, 139, 139, 157, 158, 158, 158, 158, 158, 158, 
-    158, 158, 158, 158, 134, 159, 159, 160, 146, 146, 161, 146, 146, 146, 
-    146, 146, 146, 146, 146, 146, 146, 146, 145, 146, 139, 139, 139, 139, 
-    139, 139, 139, 131, 138, 139, 139, 139, 139, 157, 139, 162, 162, 139, 
-    139, 138, 157, 139, 139, 157, 146, 146, 163, 163, 163, 163, 163, 163, 
-    163, 163, 163, 163, 146, 146, 146, 164, 164, 146, 165, 165, 165, 165, 
-    165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 81, 166, 167, 168, 167, 
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 
-    170, 169, 169, 170, 169, 169, 170, 170, 170, 169, 170, 170, 169, 170, 
-    169, 169, 169, 170, 169, 170, 169, 170, 169, 170, 169, 169, 81, 81, 167, 
-    167, 167, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 
-    171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 171, 81, 
-    81, 81, 81, 81, 81, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 
-    174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 
-    174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 176, 175, 177, 177, 
-    178, 179, 180, 181, 177, 81, 81, 176, 182, 182, 183, 183, 183, 183, 183, 
-    183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 185, 
-    184, 184, 184, 184, 184, 184, 184, 184, 184, 185, 184, 184, 184, 185, 
-    184, 184, 184, 184, 184, 81, 81, 186, 186, 186, 186, 186, 186, 186, 186, 
-    186, 186, 186, 186, 186, 186, 186, 81, 187, 187, 187, 187, 187, 187, 187, 
-    187, 187, 188, 188, 188, 81, 81, 189, 81, 167, 167, 167, 81, 81, 81, 81, 
-    81, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146, 
-    81, 81, 81, 81, 81, 157, 139, 139, 139, 139, 139, 139, 131, 157, 139, 
-    139, 157, 139, 139, 157, 139, 139, 139, 157, 157, 157, 190, 191, 192, 
-    139, 139, 139, 157, 139, 139, 157, 157, 139, 139, 139, 139, 139, 193, 
-    193, 193, 194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 
-    195, 195, 195, 193, 194, 196, 195, 194, 194, 194, 193, 193, 193, 193, 
-    193, 193, 193, 193, 194, 194, 194, 194, 197, 194, 194, 195, 96, 156, 198, 
-    198, 193, 193, 193, 195, 195, 193, 193, 199, 199, 200, 200, 200, 200, 
-    200, 200, 200, 200, 200, 200, 201, 202, 195, 195, 195, 195, 195, 195, 
-    203, 204, 205, 205, 81, 203, 203, 203, 203, 203, 203, 203, 203, 81, 81, 
-    203, 203, 81, 81, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 
-    203, 203, 203, 81, 203, 203, 203, 203, 203, 203, 203, 81, 203, 81, 81, 
-    81, 203, 203, 203, 203, 81, 81, 206, 203, 205, 205, 205, 204, 204, 204, 
-    204, 81, 81, 205, 205, 81, 81, 205, 205, 207, 203, 81, 81, 81, 81, 81, 
-    81, 81, 81, 205, 81, 81, 81, 81, 203, 203, 81, 203, 203, 203, 204, 204, 
-    81, 81, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 203, 203, 209, 
-    209, 210, 210, 210, 210, 210, 211, 212, 213, 203, 214, 215, 81, 81, 216, 
-    216, 217, 81, 218, 218, 218, 218, 218, 218, 81, 81, 81, 81, 218, 218, 81, 
-    81, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 
-    81, 218, 218, 218, 218, 218, 218, 218, 81, 218, 218, 81, 218, 218, 81, 
-    218, 218, 81, 81, 219, 81, 217, 217, 217, 216, 216, 81, 81, 81, 81, 216, 
-    216, 81, 81, 216, 216, 220, 81, 81, 81, 216, 81, 81, 81, 81, 81, 81, 81, 
-    218, 218, 218, 218, 81, 218, 81, 81, 81, 81, 81, 81, 81, 221, 221, 221, 
-    221, 221, 221, 221, 221, 221, 221, 216, 216, 218, 218, 218, 216, 222, 81, 
-    81, 223, 223, 224, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 81, 
-    225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 
-    225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 81, 225, 225, 81, 
-    225, 225, 225, 225, 225, 81, 81, 226, 225, 224, 224, 224, 223, 223, 223, 
-    223, 223, 81, 223, 223, 224, 81, 224, 224, 227, 81, 81, 225, 81, 81, 81, 
-    81, 81, 81, 81, 225, 225, 223, 223, 81, 81, 228, 228, 228, 228, 228, 228, 
-    228, 228, 228, 228, 229, 230, 81, 81, 81, 81, 81, 81, 81, 225, 223, 223, 
-    223, 223, 223, 223, 81, 231, 232, 232, 81, 233, 233, 233, 233, 233, 233, 
-    233, 233, 81, 81, 233, 233, 81, 81, 233, 233, 233, 233, 233, 233, 233, 
-    233, 233, 233, 233, 233, 233, 233, 81, 233, 233, 233, 233, 233, 233, 233, 
-    81, 233, 233, 81, 233, 233, 233, 233, 233, 81, 81, 234, 233, 232, 231, 
-    232, 231, 231, 231, 231, 81, 81, 232, 232, 81, 81, 232, 232, 235, 81, 81, 
-    81, 81, 81, 81, 81, 81, 231, 232, 81, 81, 81, 81, 233, 233, 81, 233, 233, 
-    233, 231, 231, 81, 81, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 
-    237, 233, 238, 238, 238, 238, 238, 238, 81, 81, 239, 240, 81, 240, 240, 
-    240, 240, 240, 240, 81, 81, 81, 240, 240, 240, 81, 240, 240, 240, 240, 
-    81, 81, 81, 240, 240, 81, 240, 81, 240, 240, 81, 81, 81, 240, 240, 81, 
-    81, 81, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 81, 81, 81, 81, 
-    241, 241, 239, 241, 241, 81, 81, 81, 241, 241, 241, 81, 241, 241, 241, 
-    242, 81, 81, 240, 81, 81, 81, 81, 81, 81, 241, 81, 81, 81, 81, 81, 81, 
-    243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 245, 
-    245, 245, 245, 245, 245, 246, 245, 81, 81, 81, 81, 81, 247, 248, 248, 
-    248, 247, 249, 249, 249, 249, 249, 249, 249, 249, 81, 249, 249, 249, 81, 
-    249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 
-    249, 249, 81, 81, 81, 249, 247, 247, 247, 248, 248, 248, 248, 81, 247, 
-    247, 247, 81, 247, 247, 247, 250, 81, 81, 81, 81, 81, 81, 81, 251, 252, 
-    81, 249, 249, 249, 81, 81, 81, 81, 81, 249, 249, 247, 247, 81, 81, 253, 
-    253, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 
-    254, 254, 255, 256, 257, 258, 258, 259, 256, 256, 256, 256, 256, 256, 
-    256, 256, 81, 256, 256, 256, 81, 256, 256, 256, 256, 256, 256, 256, 256, 
-    256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 81, 256, 256, 256, 256, 
-    256, 81, 81, 260, 256, 258, 261, 258, 258, 258, 258, 258, 81, 261, 258, 
-    258, 81, 258, 258, 257, 262, 81, 81, 81, 81, 81, 81, 81, 258, 258, 81, 
-    81, 81, 81, 81, 81, 81, 256, 81, 256, 256, 257, 257, 81, 81, 263, 263, 
-    263, 263, 263, 263, 263, 263, 263, 263, 81, 256, 256, 81, 81, 81, 81, 81, 
-    264, 264, 265, 265, 81, 266, 266, 266, 266, 266, 266, 266, 266, 81, 266, 
-    266, 266, 81, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 
-    266, 266, 266, 266, 266, 267, 267, 266, 265, 265, 265, 264, 264, 264, 
-    264, 81, 265, 265, 265, 81, 265, 265, 265, 267, 266, 268, 81, 81, 81, 81, 
-    266, 266, 266, 265, 269, 269, 269, 269, 269, 269, 269, 266, 266, 266, 
-    264, 264, 81, 81, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 269, 
-    269, 269, 269, 269, 269, 269, 269, 269, 271, 266, 266, 266, 266, 266, 
-    266, 81, 81, 272, 272, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273, 
-    273, 273, 273, 273, 273, 273, 273, 273, 273, 81, 81, 81, 273, 273, 273, 
-    273, 273, 273, 273, 273, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273, 
-    81, 273, 81, 81, 81, 81, 274, 81, 81, 81, 81, 272, 272, 272, 275, 275, 
-    275, 81, 275, 81, 272, 272, 272, 272, 272, 272, 272, 272, 81, 81, 81, 81, 
-    81, 81, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 81, 81, 272, 
-    272, 277, 81, 81, 81, 81, 278, 278, 278, 278, 278, 278, 278, 278, 278, 
-    278, 278, 278, 278, 278, 278, 278, 279, 278, 278, 279, 279, 279, 279, 
-    280, 280, 281, 81, 81, 81, 81, 282, 278, 278, 278, 278, 278, 278, 283, 
-    279, 284, 284, 284, 284, 279, 279, 279, 285, 286, 286, 286, 286, 286, 
-    286, 286, 286, 286, 286, 287, 287, 81, 81, 81, 81, 81, 288, 288, 81, 288, 
-    81, 81, 288, 288, 81, 288, 81, 81, 288, 81, 81, 81, 81, 81, 81, 288, 288, 
-    288, 288, 81, 288, 288, 288, 288, 288, 288, 288, 81, 288, 288, 288, 81, 
-    288, 81, 288, 81, 81, 288, 288, 81, 288, 288, 288, 288, 289, 288, 288, 
-    289, 289, 289, 289, 290, 290, 81, 289, 289, 288, 81, 81, 288, 288, 288, 
-    288, 288, 81, 291, 81, 292, 292, 292, 292, 289, 289, 81, 81, 293, 293, 
-    293, 293, 293, 293, 293, 293, 293, 293, 81, 81, 288, 288, 288, 288, 294, 
-    295, 295, 295, 296, 297, 296, 296, 298, 296, 296, 299, 298, 300, 300, 
-    300, 300, 300, 298, 301, 300, 301, 301, 301, 302, 302, 301, 301, 301, 
-    301, 301, 301, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 
-    304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 302, 301, 302, 301, 
-    306, 307, 308, 307, 308, 309, 309, 294, 294, 294, 294, 294, 294, 294, 
-    294, 81, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 81, 
-    81, 81, 81, 310, 311, 312, 313, 312, 312, 312, 312, 312, 311, 311, 311, 
-    311, 312, 314, 311, 312, 315, 315, 316, 299, 315, 315, 294, 294, 294, 
-    294, 294, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 312, 
-    312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 305, 305, 301, 
-    301, 301, 301, 301, 301, 302, 301, 301, 301, 301, 301, 301, 81, 301, 301, 
-    296, 296, 299, 296, 297, 317, 317, 317, 317, 298, 298, 81, 81, 81, 81, 
-    81, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 319, 319, 320, 
-    320, 320, 320, 319, 320, 320, 320, 320, 320, 321, 319, 322, 322, 319, 
-    319, 320, 320, 318, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, 
-    324, 324, 325, 325, 325, 325, 318, 318, 318, 318, 318, 318, 319, 319, 
-    320, 320, 318, 318, 318, 318, 320, 320, 320, 318, 319, 319, 319, 318, 
-    318, 319, 319, 319, 319, 319, 319, 319, 318, 318, 318, 320, 320, 320, 
-    320, 318, 318, 318, 318, 318, 320, 319, 319, 320, 320, 319, 319, 319, 
-    319, 319, 319, 326, 318, 319, 323, 323, 319, 319, 319, 320, 327, 327, 
-    328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 81, 
-    328, 81, 81, 81, 81, 81, 328, 81, 81, 329, 329, 329, 329, 329, 329, 329, 
-    329, 329, 329, 329, 330, 331, 329, 329, 329, 332, 332, 332, 332, 332, 
-    332, 332, 332, 333, 333, 333, 333, 333, 333, 333, 333, 334, 334, 334, 
-    334, 334, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 81, 
-    335, 335, 335, 335, 81, 81, 335, 335, 335, 335, 335, 335, 335, 81, 335, 
-    335, 335, 81, 81, 336, 336, 336, 337, 338, 337, 337, 337, 337, 337, 337, 
-    337, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 
-    339, 339, 339, 339, 339, 339, 339, 81, 81, 81, 340, 340, 340, 340, 340, 
-    340, 340, 340, 340, 340, 81, 81, 81, 81, 81, 81, 341, 341, 341, 341, 341, 
-    341, 341, 341, 341, 341, 341, 341, 341, 341, 81, 81, 342, 342, 342, 342, 
-    342, 342, 81, 81, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 
-    344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 345, 345, 344, 346, 
-    347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 
-    347, 347, 347, 347, 348, 349, 81, 81, 81, 350, 350, 350, 350, 350, 350, 
-    350, 350, 350, 350, 350, 199, 199, 199, 351, 351, 351, 350, 350, 350, 
-    350, 350, 350, 350, 350, 81, 81, 81, 81, 81, 81, 81, 352, 352, 352, 352, 
-    352, 352, 352, 352, 352, 352, 352, 352, 352, 81, 352, 352, 352, 352, 353, 
-    353, 354, 81, 81, 81, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 
-    356, 356, 357, 199, 199, 81, 358, 358, 358, 358, 358, 358, 358, 358, 358, 
-    358, 359, 359, 81, 81, 81, 81, 360, 360, 360, 360, 360, 360, 360, 360, 
-    360, 360, 360, 360, 360, 81, 360, 360, 360, 81, 361, 361, 81, 81, 81, 81, 
-    362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 363, 363, 
-    364, 363, 363, 363, 363, 363, 363, 363, 364, 364, 364, 364, 364, 364, 
-    364, 364, 363, 364, 364, 363, 363, 363, 363, 363, 363, 363, 363, 363, 
-    365, 363, 366, 366, 367, 368, 366, 369, 366, 370, 362, 371, 81, 81, 372, 
-    372, 372, 372, 372, 372, 372, 372, 372, 372, 81, 81, 81, 81, 81, 81, 373, 
-    373, 373, 373, 373, 373, 373, 373, 373, 373, 81, 81, 81, 81, 81, 81, 374, 
-    374, 375, 375, 376, 377, 378, 374, 379, 379, 374, 380, 380, 380, 381, 81, 
-    382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 81, 81, 81, 81, 81, 81, 
-    383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 383, 383, 
-    383, 383, 383, 81, 81, 81, 81, 81, 81, 81, 383, 383, 383, 383, 383, 380, 
-    380, 383, 383, 385, 383, 81, 81, 81, 81, 81, 344, 344, 344, 344, 344, 
-    344, 81, 81, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 
-    386, 386, 386, 81, 387, 387, 387, 388, 388, 388, 388, 387, 387, 388, 388, 
-    388, 81, 81, 81, 81, 388, 388, 387, 388, 388, 388, 388, 388, 388, 389, 
-    390, 391, 81, 81, 81, 81, 392, 81, 81, 81, 393, 393, 394, 394, 394, 394, 
-    394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395, 395, 395, 
-    395, 395, 395, 395, 395, 395, 81, 81, 395, 395, 395, 395, 395, 81, 81, 
-    81, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 81, 81, 
-    81, 81, 396, 396, 81, 81, 81, 81, 81, 81, 397, 397, 397, 397, 397, 397, 
-    397, 397, 397, 397, 398, 81, 81, 81, 399, 399, 400, 400, 400, 400, 400, 
-    400, 400, 400, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401, 
-    401, 401, 401, 401, 402, 403, 404, 404, 405, 81, 81, 406, 406, 407, 407, 
-    407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 408, 409, 408, 
-    409, 409, 409, 409, 409, 409, 409, 81, 410, 408, 409, 408, 408, 409, 409, 
-    409, 409, 409, 409, 409, 409, 408, 408, 408, 408, 408, 408, 409, 409, 
-    411, 411, 411, 411, 411, 411, 411, 411, 81, 81, 412, 413, 413, 413, 413, 
-    413, 413, 413, 413, 413, 413, 81, 81, 81, 81, 81, 81, 414, 414, 414, 414, 
-    414, 414, 414, 415, 414, 414, 414, 414, 414, 414, 81, 81, 96, 96, 96, 96, 
-    96, 156, 156, 156, 156, 156, 156, 96, 96, 156, 416, 81, 417, 417, 417, 
-    417, 418, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 
-    419, 419, 419, 420, 418, 417, 417, 417, 417, 417, 418, 417, 418, 418, 
-    418, 418, 418, 417, 418, 421, 419, 419, 419, 419, 419, 419, 419, 81, 81, 
-    81, 81, 422, 422, 422, 422, 422, 422, 422, 422, 422, 422, 423, 423, 424, 
-    423, 423, 423, 423, 425, 425, 425, 425, 425, 425, 425, 425, 425, 425, 
-    426, 427, 426, 426, 426, 426, 426, 426, 426, 425, 425, 425, 425, 425, 
-    425, 425, 425, 425, 81, 81, 81, 428, 428, 429, 430, 430, 430, 430, 430, 
-    430, 430, 430, 430, 430, 430, 430, 430, 430, 429, 428, 428, 428, 428, 
-    429, 429, 428, 428, 431, 432, 428, 428, 430, 430, 433, 433, 433, 433, 
-    433, 433, 433, 433, 433, 433, 430, 430, 430, 430, 430, 430, 434, 434, 
-    434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 435, 436, 
-    437, 437, 436, 436, 436, 437, 436, 437, 437, 437, 438, 438, 81, 81, 81, 
-    81, 81, 81, 81, 81, 439, 439, 439, 439, 440, 440, 440, 440, 440, 440, 
-    440, 440, 440, 440, 440, 440, 441, 441, 441, 441, 441, 441, 441, 441, 
-    442, 442, 442, 442, 442, 442, 442, 442, 441, 441, 442, 443, 81, 81, 81, 
-    444, 444, 444, 444, 444, 445, 445, 445, 445, 445, 445, 445, 445, 445, 
-    445, 81, 81, 81, 440, 440, 440, 446, 446, 446, 446, 446, 446, 446, 446, 
-    446, 446, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 
-    447, 447, 448, 448, 448, 448, 448, 448, 449, 449, 93, 81, 81, 81, 81, 81, 
-    81, 81, 328, 328, 328, 81, 81, 328, 328, 328, 450, 450, 450, 450, 450, 
-    450, 450, 450, 96, 96, 96, 330, 451, 156, 156, 156, 156, 156, 96, 96, 
-    156, 156, 156, 156, 96, 452, 451, 451, 451, 451, 451, 451, 451, 453, 453, 
-    453, 453, 156, 453, 453, 453, 453, 452, 452, 96, 453, 453, 452, 96, 96, 
-    81, 81, 81, 81, 81, 81, 56, 56, 56, 56, 56, 56, 79, 79, 79, 79, 79, 93, 
-    59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 82, 82, 82, 82, 59, 59, 59, 59, 
-    82, 82, 82, 82, 82, 56, 56, 56, 56, 56, 454, 56, 56, 56, 56, 56, 56, 56, 
-    56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 96, 96, 
-    156, 96, 96, 96, 96, 96, 96, 96, 156, 96, 96, 455, 456, 156, 457, 96, 96, 
-    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 
-    96, 458, 459, 459, 156, 81, 96, 460, 156, 96, 156, 52, 56, 52, 56, 52, 
-    56, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 79, 79, 79, 79, 79, 79, 79, 
-    79, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 81, 81, 78, 
-    78, 78, 78, 78, 78, 81, 81, 81, 78, 81, 78, 81, 78, 81, 78, 461, 461, 
-    461, 461, 461, 461, 461, 461, 79, 79, 79, 79, 79, 81, 79, 79, 78, 78, 78, 
-    78, 461, 80, 79, 80, 80, 80, 79, 79, 79, 81, 79, 79, 78, 78, 78, 78, 461, 
-    80, 80, 80, 79, 79, 79, 79, 81, 81, 79, 79, 78, 78, 78, 78, 81, 80, 80, 
-    80, 78, 78, 78, 78, 78, 80, 80, 80, 81, 81, 79, 79, 79, 81, 79, 79, 78, 
-    78, 78, 78, 461, 462, 80, 81, 463, 463, 463, 463, 463, 463, 463, 464, 
-    463, 463, 463, 465, 466, 467, 468, 469, 470, 471, 472, 470, 473, 474, 38, 
-    84, 475, 476, 477, 42, 475, 476, 477, 42, 38, 38, 478, 84, 479, 479, 479, 
-    480, 481, 482, 483, 484, 485, 486, 487, 33, 488, 489, 488, 488, 489, 490, 
-    491, 491, 84, 42, 50, 38, 492, 492, 478, 493, 493, 84, 84, 84, 494, 477, 
-    495, 492, 492, 492, 84, 84, 84, 84, 84, 84, 84, 84, 496, 84, 493, 84, 
-    377, 84, 377, 377, 377, 377, 84, 377, 377, 463, 497, 498, 498, 498, 498, 
-    81, 499, 500, 501, 502, 503, 503, 503, 503, 503, 503, 504, 59, 81, 81, 
-    47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 506, 504, 47, 47, 
-    47, 47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 81, 59, 59, 59, 
-    59, 59, 81, 81, 81, 282, 282, 282, 282, 282, 282, 282, 507, 282, 508, 
-    282, 282, 36, 282, 282, 282, 282, 282, 282, 282, 282, 282, 507, 282, 282, 
-    282, 282, 507, 282, 282, 507, 282, 509, 509, 509, 509, 509, 509, 509, 
-    509, 96, 96, 451, 451, 96, 96, 96, 96, 451, 451, 451, 96, 96, 416, 416, 
-    416, 416, 96, 416, 416, 416, 451, 451, 96, 156, 96, 451, 451, 156, 156, 
-    156, 156, 96, 81, 81, 81, 81, 81, 81, 81, 40, 40, 510, 511, 40, 512, 40, 
-    510, 40, 511, 49, 510, 510, 510, 49, 49, 510, 510, 510, 513, 40, 510, 
-    514, 40, 496, 510, 510, 510, 510, 510, 40, 40, 40, 512, 512, 40, 510, 40, 
-    85, 40, 510, 40, 52, 515, 510, 510, 516, 49, 510, 510, 52, 510, 49, 453, 
-    453, 453, 453, 49, 40, 40, 49, 49, 510, 510, 496, 496, 496, 496, 496, 
-    510, 49, 49, 49, 49, 40, 496, 40, 40, 56, 317, 517, 517, 517, 518, 51, 
-    519, 517, 517, 517, 517, 517, 51, 518, 518, 51, 517, 520, 520, 520, 520, 
-    520, 520, 520, 520, 520, 520, 520, 520, 521, 521, 521, 521, 520, 520, 
-    521, 521, 521, 521, 521, 521, 521, 521, 521, 52, 56, 521, 521, 521, 521, 
-    51, 40, 40, 81, 81, 81, 81, 54, 54, 54, 54, 54, 512, 512, 512, 512, 512, 
-    496, 496, 40, 40, 40, 40, 496, 40, 40, 496, 40, 40, 496, 40, 40, 40, 40, 
-    40, 40, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 44, 40, 40, 40, 
-    40, 40, 40, 40, 40, 40, 40, 40, 40, 496, 496, 40, 40, 54, 40, 54, 40, 40, 
-    40, 40, 40, 40, 40, 40, 40, 40, 44, 40, 40, 40, 40, 496, 496, 496, 496, 
-    496, 496, 496, 496, 496, 496, 496, 496, 54, 496, 54, 54, 496, 496, 496, 
-    54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 54, 522, 523, 496, 54, 496, 
-    496, 496, 496, 54, 496, 496, 54, 54, 54, 54, 496, 496, 54, 496, 54, 496, 
-    54, 54, 54, 54, 54, 54, 496, 54, 496, 496, 496, 496, 496, 54, 54, 54, 54, 
-    496, 496, 496, 496, 54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 496, 
-    496, 496, 496, 54, 496, 496, 496, 496, 496, 54, 54, 496, 496, 54, 54, 54, 
-    54, 496, 496, 54, 54, 496, 496, 54, 54, 496, 496, 496, 496, 496, 54, 496, 
-    496, 496, 54, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 
-    496, 54, 496, 496, 496, 496, 496, 496, 496, 524, 477, 495, 477, 495, 40, 
-    40, 40, 40, 40, 40, 512, 40, 40, 40, 40, 40, 40, 40, 525, 525, 40, 40, 
-    40, 40, 496, 496, 40, 40, 40, 40, 40, 40, 40, 526, 527, 40, 40, 40, 40, 
-    40, 40, 40, 40, 40, 40, 40, 317, 317, 317, 317, 317, 317, 317, 317, 317, 
-    317, 317, 317, 317, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 317, 40, 40, 
-    40, 40, 40, 496, 496, 496, 496, 496, 496, 496, 496, 496, 40, 40, 40, 40, 
-    40, 528, 528, 528, 528, 40, 40, 40, 525, 529, 529, 525, 40, 40, 40, 40, 
-    40, 40, 40, 40, 40, 40, 40, 81, 40, 40, 40, 81, 81, 81, 81, 81, 51, 51, 
-    51, 51, 51, 51, 51, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 
-    530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 
-    519, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 518, 512, 512, 512, 
-    512, 512, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 512, 512, 
-    512, 512, 531, 40, 40, 40, 40, 40, 512, 512, 512, 512, 40, 40, 512, 512, 
-    40, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 40, 40, 40, 40, 
-    512, 512, 40, 40, 512, 54, 40, 40, 40, 40, 512, 512, 40, 40, 512, 54, 40, 
-    40, 40, 40, 512, 512, 512, 40, 40, 512, 40, 40, 512, 512, 40, 40, 40, 40, 
-    40, 40, 40, 512, 496, 496, 496, 496, 496, 532, 532, 496, 529, 529, 529, 
-    529, 40, 512, 512, 40, 40, 512, 40, 40, 40, 40, 512, 512, 40, 40, 40, 40, 
-    525, 525, 531, 531, 529, 40, 529, 529, 533, 534, 533, 529, 40, 529, 529, 
-    529, 40, 40, 40, 40, 512, 40, 512, 40, 40, 40, 40, 40, 528, 528, 528, 
-    528, 528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 512, 512, 
-    40, 512, 512, 512, 40, 512, 533, 512, 512, 40, 512, 512, 40, 54, 40, 40, 
-    40, 40, 40, 40, 40, 525, 40, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 
-    40, 40, 512, 512, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 528, 528, 317, 
-    40, 40, 40, 40, 40, 40, 40, 40, 525, 525, 533, 529, 529, 529, 529, 525, 
-    525, 533, 533, 533, 512, 512, 512, 512, 533, 528, 533, 533, 533, 512, 
-    533, 525, 512, 512, 512, 533, 533, 512, 512, 533, 512, 512, 533, 533, 
-    533, 40, 512, 40, 40, 40, 40, 512, 512, 525, 512, 512, 512, 512, 512, 
-    512, 533, 525, 525, 533, 525, 512, 533, 533, 535, 525, 512, 512, 525, 
-    533, 533, 529, 529, 529, 529, 529, 528, 40, 40, 529, 529, 536, 536, 534, 
-    534, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 40, 
-    40, 40, 40, 40, 40, 528, 40, 528, 40, 40, 40, 40, 528, 528, 528, 40, 537, 
-    40, 40, 40, 538, 538, 538, 538, 538, 538, 40, 539, 539, 529, 40, 40, 40, 
-    477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 51, 
-    51, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 40, 528, 
-    528, 528, 40, 40, 40, 40, 40, 40, 40, 528, 496, 496, 496, 496, 496, 477, 
-    495, 496, 496, 496, 496, 496, 496, 496, 16, 31, 16, 31, 16, 31, 16, 31, 
-    477, 495, 540, 540, 540, 540, 540, 540, 540, 540, 496, 496, 496, 477, 
-    495, 16, 31, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 496, 496, 
-    496, 496, 496, 496, 496, 477, 495, 477, 495, 496, 496, 496, 496, 496, 
-    496, 496, 496, 477, 495, 496, 496, 40, 40, 40, 528, 528, 40, 40, 40, 496, 
-    496, 496, 496, 496, 40, 40, 496, 496, 496, 496, 496, 496, 40, 40, 40, 
-    528, 40, 40, 40, 40, 537, 512, 512, 40, 40, 40, 40, 81, 81, 40, 40, 40, 
-    40, 40, 40, 40, 40, 81, 81, 40, 81, 40, 40, 40, 40, 40, 40, 541, 541, 
-    541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 81, 542, 
-    542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 81, 
-    52, 56, 52, 52, 52, 56, 56, 52, 56, 52, 56, 52, 56, 52, 52, 52, 52, 56, 
-    52, 56, 56, 52, 56, 56, 56, 56, 56, 56, 59, 59, 52, 52, 87, 88, 87, 88, 
-    88, 543, 543, 543, 543, 543, 543, 87, 88, 87, 88, 544, 544, 544, 87, 88, 
-    81, 81, 81, 81, 81, 545, 546, 546, 546, 547, 545, 546, 329, 329, 329, 
-    329, 329, 329, 81, 329, 81, 81, 81, 81, 81, 329, 81, 81, 548, 548, 548, 
-    548, 548, 548, 548, 548, 81, 81, 81, 81, 81, 81, 81, 549, 550, 81, 81, 
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 551, 95, 95, 95, 95, 95, 
-    95, 95, 95, 552, 552, 42, 50, 42, 50, 552, 552, 552, 42, 50, 552, 42, 50, 
-    377, 377, 377, 377, 377, 377, 377, 377, 84, 472, 553, 377, 554, 84, 42, 
-    50, 84, 84, 42, 50, 477, 495, 477, 495, 477, 495, 477, 495, 377, 377, 
-    377, 377, 375, 60, 377, 377, 84, 377, 377, 84, 84, 84, 84, 84, 555, 555, 
-    377, 377, 377, 84, 472, 377, 477, 377, 377, 377, 377, 377, 377, 377, 377, 
-    84, 377, 84, 377, 81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 
-    81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 81, 81, 81, 81, 556, 
-    556, 556, 556, 556, 556, 81, 81, 525, 525, 525, 525, 525, 525, 525, 525, 
-    525, 525, 525, 525, 81, 81, 81, 81, 557, 558, 558, 559, 525, 560, 561, 
-    562, 526, 527, 526, 527, 526, 527, 526, 527, 526, 527, 525, 525, 526, 
-    527, 526, 527, 526, 527, 526, 527, 563, 526, 527, 527, 525, 562, 562, 
-    562, 562, 562, 562, 562, 562, 562, 564, 565, 566, 567, 568, 568, 569, 
-    570, 570, 570, 570, 571, 525, 525, 562, 562, 562, 560, 572, 559, 525, 
-    529, 81, 573, 574, 573, 574, 573, 574, 573, 574, 573, 574, 574, 574, 574, 
-    574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 573, 
-    574, 574, 574, 574, 574, 574, 574, 573, 574, 573, 574, 573, 574, 574, 
-    574, 574, 574, 574, 573, 574, 574, 574, 574, 574, 574, 573, 573, 81, 81, 
-    575, 575, 576, 576, 577, 577, 574, 563, 578, 579, 578, 579, 578, 579, 
-    578, 579, 578, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 
-    579, 579, 579, 579, 579, 579, 578, 579, 579, 579, 579, 579, 579, 579, 
-    578, 579, 578, 579, 578, 579, 579, 579, 579, 579, 579, 578, 579, 579, 
-    579, 579, 579, 579, 578, 578, 579, 579, 579, 579, 580, 581, 582, 582, 
-    579, 81, 81, 81, 81, 81, 583, 583, 583, 583, 583, 583, 583, 583, 583, 
-    583, 583, 81, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 
-    584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 81, 585, 585, 586, 586, 
-    586, 586, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 583, 583, 
-    583, 81, 81, 81, 81, 81, 578, 578, 578, 578, 578, 578, 578, 578, 587, 
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 588, 81, 
-    586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 585, 585, 585, 585, 
-    585, 585, 589, 589, 589, 589, 589, 589, 589, 589, 525, 590, 590, 590, 
-    590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 587, 587, 
-    587, 587, 588, 588, 588, 585, 585, 590, 590, 590, 590, 590, 590, 590, 
-    585, 585, 585, 585, 525, 525, 525, 525, 591, 591, 591, 591, 591, 591, 
-    591, 591, 591, 591, 591, 591, 591, 591, 591, 81, 585, 585, 585, 585, 585, 
-    585, 585, 525, 525, 525, 525, 585, 585, 585, 585, 585, 585, 585, 585, 
-    585, 585, 585, 525, 525, 592, 592, 592, 592, 592, 592, 592, 592, 592, 
-    592, 592, 592, 592, 592, 593, 593, 593, 593, 593, 593, 593, 593, 593, 
-    593, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 
-    595, 594, 594, 594, 594, 594, 594, 594, 81, 81, 81, 596, 596, 596, 596, 
-    596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 81, 597, 597, 597, 
-    597, 597, 597, 597, 597, 598, 598, 598, 598, 598, 598, 599, 599, 600, 
-    600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 601, 602, 603, 
-    602, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 600, 600, 81, 81, 
-    81, 81, 90, 93, 90, 93, 90, 93, 605, 95, 97, 97, 97, 606, 95, 95, 95, 95, 
-    95, 95, 95, 95, 95, 95, 606, 607, 90, 93, 90, 93, 454, 454, 95, 95, 608, 
-    608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 609, 
-    609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610, 611, 612, 612, 
-    612, 612, 612, 62, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60, 60, 60, 60, 
-    60, 60, 62, 62, 52, 56, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 56, 
-    59, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 52, 56, 52, 52, 56, 60, 613, 
-    613, 52, 56, 52, 56, 57, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 52, 
-    52, 52, 52, 56, 52, 52, 52, 52, 52, 56, 52, 56, 52, 56, 81, 81, 81, 81, 
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 57, 59, 59, 56, 57, 57, 57, 57, 57, 
-    614, 614, 615, 614, 614, 614, 616, 614, 614, 614, 614, 615, 614, 614, 
-    614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 617, 
-    617, 615, 615, 617, 618, 618, 618, 618, 81, 81, 81, 81, 619, 619, 619, 
-    619, 619, 619, 317, 317, 507, 516, 81, 81, 81, 81, 81, 81, 620, 620, 620, 
-    620, 620, 620, 620, 620, 620, 620, 620, 620, 621, 621, 622, 622, 623, 
-    623, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 
-    624, 624, 624, 624, 624, 623, 623, 623, 623, 623, 623, 623, 623, 623, 
-    623, 623, 623, 623, 623, 623, 623, 625, 626, 81, 81, 81, 81, 81, 81, 81, 
-    81, 627, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 81, 81, 
-    81, 81, 81, 81, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 195, 
-    195, 195, 195, 195, 195, 201, 201, 201, 195, 629, 195, 195, 193, 630, 
-    630, 630, 630, 630, 630, 630, 630, 630, 630, 631, 631, 631, 631, 631, 
-    631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 
-    631, 632, 632, 632, 632, 632, 633, 633, 633, 199, 634, 635, 635, 635, 
-    635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636, 
-    636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 81, 81, 81, 81, 
-    81, 81, 81, 81, 81, 81, 81, 639, 332, 332, 332, 332, 332, 81, 81, 81, 
-    640, 640, 640, 641, 642, 642, 642, 642, 642, 642, 642, 642, 642, 642, 
-    642, 642, 642, 642, 642, 643, 641, 641, 640, 640, 640, 640, 641, 641, 
-    640, 641, 641, 641, 644, 645, 645, 645, 645, 645, 645, 646, 646, 646, 
-    645, 645, 645, 645, 81, 61, 647, 647, 647, 647, 647, 647, 647, 647, 647, 
-    647, 81, 81, 81, 81, 645, 645, 318, 318, 318, 318, 318, 320, 648, 318, 
-    323, 323, 318, 318, 318, 318, 318, 81, 649, 649, 649, 649, 649, 649, 649, 
-    649, 649, 650, 650, 650, 650, 650, 650, 651, 651, 650, 650, 651, 651, 
-    650, 650, 81, 649, 649, 649, 650, 649, 649, 649, 649, 649, 649, 649, 649, 
-    650, 651, 81, 81, 652, 652, 652, 652, 652, 652, 652, 652, 652, 652, 81, 
-    81, 653, 654, 654, 654, 648, 318, 318, 318, 318, 318, 318, 327, 327, 327, 
-    318, 319, 320, 319, 318, 318, 655, 655, 655, 655, 655, 655, 655, 655, 
-    656, 655, 656, 656, 657, 655, 655, 656, 656, 655, 655, 655, 655, 655, 
-    656, 656, 655, 656, 655, 81, 81, 81, 81, 81, 81, 81, 81, 655, 655, 658, 
-    659, 659, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661, 
-    662, 662, 661, 661, 663, 663, 660, 664, 664, 661, 665, 81, 81, 335, 335, 
-    335, 335, 335, 335, 81, 56, 56, 56, 613, 59, 59, 59, 59, 56, 56, 56, 56, 
-    56, 79, 81, 81, 342, 342, 342, 342, 342, 342, 342, 342, 660, 660, 660, 
-    661, 661, 662, 661, 661, 662, 661, 661, 663, 661, 665, 81, 81, 666, 666, 
-    666, 666, 666, 666, 666, 666, 666, 666, 81, 81, 81, 81, 81, 81, 667, 668, 
-    668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 
-    668, 668, 668, 668, 667, 668, 668, 668, 668, 668, 668, 668, 81, 81, 81, 
-    81, 333, 333, 333, 333, 333, 333, 333, 81, 81, 81, 81, 334, 334, 334, 
-    334, 334, 334, 334, 334, 334, 81, 81, 81, 81, 669, 669, 669, 669, 669, 
-    669, 669, 669, 670, 670, 670, 670, 670, 670, 670, 670, 592, 592, 593, 
-    593, 593, 593, 593, 593, 56, 56, 56, 56, 56, 56, 56, 81, 81, 81, 81, 101, 
-    101, 101, 101, 101, 81, 81, 81, 81, 81, 129, 671, 129, 129, 672, 129, 
-    129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 129, 129, 
-    129, 129, 129, 81, 129, 81, 129, 129, 81, 129, 129, 81, 129, 129, 146, 
-    146, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 
-    673, 673, 673, 81, 81, 81, 81, 81, 81, 81, 81, 81, 146, 146, 146, 146, 
-    146, 146, 146, 146, 146, 146, 146, 495, 477, 81, 81, 146, 146, 146, 146, 
-    146, 146, 146, 146, 146, 146, 135, 138, 81, 81, 674, 674, 674, 674, 674, 
-    674, 674, 674, 675, 558, 558, 675, 675, 676, 676, 526, 527, 677, 81, 81, 
-    81, 81, 81, 81, 96, 96, 96, 96, 96, 96, 96, 156, 156, 156, 156, 156, 156, 
-    156, 95, 95, 559, 569, 569, 678, 678, 526, 527, 526, 527, 526, 527, 526, 
-    527, 526, 527, 526, 527, 526, 527, 526, 527, 559, 559, 526, 527, 559, 
-    559, 559, 559, 678, 678, 678, 679, 559, 679, 81, 580, 680, 676, 676, 569, 
-    526, 527, 526, 527, 526, 527, 681, 559, 559, 682, 683, 684, 684, 684, 81, 
-    559, 685, 686, 559, 81, 81, 81, 81, 146, 146, 146, 146, 146, 81, 81, 497, 
-    81, 687, 688, 689, 690, 691, 688, 688, 692, 693, 688, 694, 695, 696, 695, 
-    697, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 699, 700, 701, 
-    701, 701, 687, 688, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 
-    702, 702, 702, 702, 702, 702, 702, 702, 692, 688, 693, 703, 704, 703, 
-    705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 
-    705, 705, 705, 705, 692, 701, 693, 701, 692, 693, 706, 707, 708, 706, 
-    709, 710, 711, 711, 711, 711, 711, 711, 711, 711, 711, 712, 710, 710, 
-    710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 
-    710, 710, 710, 710, 710, 713, 713, 714, 714, 714, 714, 714, 714, 714, 
-    714, 714, 714, 714, 714, 714, 714, 714, 81, 81, 81, 714, 714, 714, 714, 
-    714, 714, 81, 81, 714, 714, 714, 81, 81, 81, 715, 690, 701, 703, 716, 
-    690, 690, 81, 717, 718, 718, 718, 718, 717, 717, 81, 81, 719, 719, 719, 
-    720, 512, 81, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 
-    721, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 81, 721, 721, 
-    721, 81, 721, 721, 81, 721, 721, 721, 721, 721, 721, 721, 81, 81, 721, 
-    721, 721, 81, 81, 81, 81, 81, 199, 377, 199, 81, 81, 81, 81, 619, 619, 
-    619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 81, 81, 81, 317, 
-    722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 723, 
-    723, 723, 723, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 
-    724, 724, 724, 724, 724, 724, 723, 723, 724, 725, 725, 81, 40, 40, 40, 
-    40, 81, 81, 81, 81, 724, 81, 81, 81, 81, 81, 81, 81, 317, 317, 317, 317, 
-    317, 156, 81, 81, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 
-    726, 726, 81, 81, 81, 727, 727, 727, 727, 727, 727, 727, 727, 727, 81, 
-    81, 81, 81, 81, 81, 81, 156, 504, 504, 504, 504, 504, 504, 504, 504, 504, 
-    504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 81, 81, 81, 81, 728, 
-    728, 728, 728, 728, 728, 728, 728, 729, 729, 729, 729, 81, 81, 81, 81, 
-    81, 81, 81, 81, 81, 728, 728, 728, 730, 730, 730, 730, 730, 730, 730, 
-    730, 730, 731, 730, 730, 730, 730, 730, 730, 730, 730, 731, 81, 81, 81, 
-    81, 81, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 
-    732, 733, 733, 733, 733, 733, 81, 81, 81, 81, 81, 734, 734, 734, 734, 
-    734, 734, 734, 734, 734, 734, 734, 734, 734, 734, 81, 735, 736, 736, 736, 
-    736, 736, 736, 736, 736, 736, 736, 736, 736, 81, 81, 81, 81, 737, 738, 
-    738, 738, 738, 738, 81, 81, 739, 739, 739, 739, 739, 739, 739, 739, 740, 
-    740, 740, 740, 740, 740, 740, 740, 741, 741, 741, 741, 741, 741, 741, 
-    741, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 
-    742, 81, 81, 743, 743, 743, 743, 743, 743, 743, 743, 743, 743, 81, 81, 
-    81, 81, 81, 81, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744, 
-    744, 81, 81, 81, 81, 745, 745, 745, 745, 745, 745, 745, 745, 745, 745, 
-    745, 745, 81, 81, 81, 81, 746, 746, 746, 746, 746, 746, 746, 746, 747, 
-    747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 81, 81, 81, 81, 
-    81, 81, 81, 81, 81, 81, 81, 748, 749, 749, 749, 749, 749, 749, 749, 749, 
-    749, 749, 749, 749, 749, 749, 749, 81, 749, 749, 749, 749, 749, 749, 81, 
-    81, 750, 750, 750, 750, 750, 750, 81, 81, 750, 81, 750, 750, 750, 750, 
-    750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 
-    750, 750, 81, 750, 750, 81, 81, 81, 750, 81, 81, 750, 751, 751, 751, 751, 
-    751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 81, 752, 753, 753, 753, 
-    753, 753, 753, 753, 753, 754, 754, 754, 754, 754, 754, 754, 754, 754, 
-    754, 754, 754, 754, 754, 754, 755, 755, 756, 756, 756, 756, 756, 756, 
-    756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 81, 81, 81, 81, 81, 81, 81, 81, 758, 758, 758, 758, 758, 758, 
-    758, 758, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 81, 
-    759, 759, 81, 81, 81, 81, 81, 760, 760, 760, 760, 760, 761, 761, 761, 
-    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 762, 762, 762, 
-    762, 762, 762, 81, 81, 81, 763, 764, 764, 764, 764, 764, 764, 764, 764, 
-    764, 764, 81, 81, 81, 81, 81, 765, 766, 766, 766, 766, 766, 766, 766, 
-    766, 767, 767, 767, 767, 767, 767, 767, 767, 81, 81, 81, 81, 768, 768, 
-    767, 767, 768, 768, 768, 768, 768, 768, 768, 768, 81, 81, 768, 768, 768, 
-    768, 768, 768, 769, 770, 770, 770, 81, 770, 770, 81, 81, 81, 81, 81, 770, 
-    771, 770, 772, 769, 769, 769, 769, 81, 769, 769, 769, 81, 769, 769, 769, 
-    769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 
-    769, 769, 769, 769, 81, 81, 772, 773, 771, 81, 81, 81, 81, 774, 775, 775, 
-    775, 775, 775, 775, 775, 775, 775, 81, 81, 81, 81, 81, 81, 81, 776, 776, 
-    776, 776, 776, 776, 776, 776, 777, 81, 81, 81, 81, 81, 81, 81, 778, 778, 
-    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 779, 779, 780, 
-    781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 782, 
-    782, 782, 783, 783, 783, 783, 783, 783, 783, 783, 784, 783, 783, 783, 
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 785, 786, 81, 81, 81, 81, 
-    787, 787, 787, 787, 787, 788, 788, 788, 788, 788, 788, 789, 81, 790, 790, 
-    790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 81, 81, 81, 
-    791, 791, 791, 791, 791, 791, 791, 792, 792, 792, 792, 792, 792, 792, 
-    792, 792, 792, 792, 792, 792, 792, 81, 81, 793, 793, 793, 793, 793, 793, 
-    793, 793, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 81, 81, 
-    81, 81, 81, 795, 795, 795, 795, 795, 795, 795, 795, 796, 796, 796, 796, 
-    796, 796, 796, 796, 796, 796, 81, 81, 81, 81, 81, 81, 81, 797, 797, 797, 
-    797, 81, 81, 81, 81, 798, 798, 798, 798, 798, 798, 798, 799, 799, 799, 
-    799, 799, 799, 799, 799, 799, 81, 81, 81, 81, 81, 81, 81, 800, 800, 800, 
-    800, 800, 800, 800, 800, 800, 800, 800, 81, 81, 81, 81, 81, 801, 801, 
-    801, 801, 801, 801, 801, 801, 801, 801, 801, 81, 81, 81, 81, 81, 81, 81, 
-    802, 802, 802, 802, 802, 802, 803, 803, 803, 803, 803, 803, 803, 803, 
-    803, 803, 803, 803, 804, 804, 804, 804, 805, 805, 805, 805, 805, 805, 
-    805, 805, 805, 805, 81, 81, 81, 81, 81, 81, 806, 806, 806, 806, 806, 806, 
-    806, 806, 806, 806, 806, 806, 806, 806, 806, 81, 807, 807, 807, 807, 807, 
-    807, 807, 807, 807, 807, 807, 807, 807, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 807, 809, 809, 809, 809, 809, 809, 809, 809, 809, 
-    809, 809, 809, 809, 809, 810, 810, 811, 811, 811, 810, 811, 810, 810, 
-    810, 810, 812, 812, 812, 812, 813, 813, 813, 813, 813, 81, 81, 81, 81, 
-    81, 81, 814, 815, 814, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816, 
-    816, 816, 816, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 
-    815, 815, 815, 817, 818, 818, 819, 819, 819, 819, 819, 81, 81, 81, 81, 
-    820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 
-    820, 820, 820, 820, 820, 820, 821, 821, 821, 821, 821, 821, 821, 821, 
-    821, 821, 81, 81, 81, 81, 81, 81, 81, 817, 822, 822, 823, 824, 824, 824, 
-    824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 823, 823, 823, 822, 
-    822, 822, 822, 823, 823, 825, 826, 827, 827, 828, 829, 829, 829, 829, 81, 
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 828, 81, 81, 830, 830, 830, 830, 
-    830, 830, 830, 830, 830, 81, 81, 81, 81, 81, 81, 81, 831, 831, 831, 831, 
-    831, 831, 831, 831, 831, 831, 81, 81, 81, 81, 81, 81, 832, 832, 832, 833, 
-    833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 
-    833, 833, 833, 833, 833, 834, 834, 834, 834, 834, 835, 834, 834, 834, 
-    834, 834, 834, 836, 836, 81, 837, 837, 837, 837, 837, 837, 837, 837, 837, 
-    837, 838, 838, 838, 838, 833, 835, 835, 81, 839, 839, 839, 839, 839, 839, 
-    839, 839, 839, 839, 839, 840, 841, 842, 839, 81, 843, 843, 844, 845, 845, 
-    845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 
-    844, 844, 844, 843, 843, 843, 843, 843, 843, 843, 843, 843, 844, 846, 
-    845, 845, 845, 845, 847, 847, 848, 847, 843, 849, 843, 843, 848, 81, 81, 
-    850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 845, 851, 845, 847, 
-    847, 847, 81, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 
-    852, 852, 852, 852, 852, 852, 852, 852, 81, 81, 81, 853, 853, 853, 853, 
-    853, 853, 853, 853, 853, 853, 81, 853, 853, 853, 853, 853, 853, 853, 853, 
-    853, 854, 854, 854, 855, 855, 855, 854, 854, 855, 856, 857, 855, 858, 
-    858, 859, 858, 858, 859, 855, 81, 860, 860, 860, 860, 860, 860, 860, 81, 
-    860, 81, 860, 860, 860, 860, 81, 860, 860, 860, 860, 860, 860, 860, 860, 
-    860, 860, 860, 860, 860, 860, 860, 81, 860, 860, 861, 81, 81, 81, 81, 81, 
-    81, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 
-    862, 863, 864, 864, 864, 863, 863, 863, 863, 863, 863, 865, 866, 81, 81, 
-    81, 81, 81, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 81, 81, 81, 
-    81, 81, 81, 868, 868, 869, 869, 81, 870, 870, 870, 870, 870, 870, 870, 
-    870, 81, 81, 870, 870, 81, 81, 870, 870, 870, 870, 870, 870, 870, 870, 
-    870, 870, 870, 870, 870, 870, 81, 870, 870, 870, 870, 870, 870, 870, 81, 
-    870, 870, 81, 870, 870, 870, 870, 870, 81, 871, 872, 870, 869, 869, 868, 
-    869, 869, 869, 869, 81, 81, 869, 869, 81, 81, 869, 869, 873, 81, 81, 870, 
-    81, 81, 81, 81, 81, 81, 869, 81, 81, 81, 81, 81, 870, 870, 870, 870, 870, 
-    869, 869, 81, 81, 874, 874, 874, 874, 874, 874, 874, 81, 81, 81, 875, 
-    875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 876, 876, 
-    876, 877, 877, 877, 877, 877, 877, 877, 877, 876, 876, 878, 877, 877, 
-    876, 879, 875, 875, 875, 875, 880, 880, 880, 880, 881, 882, 882, 882, 
-    882, 882, 882, 882, 882, 882, 882, 81, 880, 81, 881, 883, 81, 884, 884, 
-    884, 884, 884, 884, 884, 884, 885, 885, 885, 886, 886, 886, 886, 886, 
-    886, 885, 886, 885, 885, 885, 885, 886, 886, 885, 887, 888, 884, 884, 
-    889, 884, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 81, 81, 81, 
-    81, 81, 81, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 
-    891, 891, 891, 892, 892, 892, 893, 893, 893, 893, 81, 81, 892, 892, 892, 
-    892, 893, 893, 892, 894, 895, 896, 897, 897, 898, 898, 899, 899, 899, 
-    897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 
-    897, 891, 891, 891, 891, 893, 893, 81, 81, 900, 900, 900, 900, 900, 900, 
-    900, 900, 901, 901, 901, 902, 902, 902, 902, 902, 902, 902, 902, 901, 
-    901, 902, 901, 903, 902, 904, 904, 905, 900, 81, 81, 81, 906, 906, 906, 
-    906, 906, 906, 906, 906, 906, 906, 81, 81, 81, 81, 81, 81, 907, 907, 907, 
-    907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 81, 81, 81, 908, 908, 
-    908, 908, 908, 908, 908, 908, 908, 908, 908, 909, 910, 909, 910, 910, 
-    909, 909, 909, 909, 909, 909, 911, 912, 913, 913, 913, 913, 913, 913, 
-    913, 913, 913, 913, 81, 81, 81, 81, 81, 81, 914, 914, 914, 914, 914, 914, 
-    914, 914, 914, 914, 914, 81, 81, 915, 915, 915, 916, 916, 915, 915, 915, 
-    915, 916, 915, 915, 915, 915, 917, 81, 81, 81, 81, 918, 918, 918, 918, 
-    918, 918, 918, 918, 918, 918, 919, 919, 920, 920, 920, 921, 922, 922, 
-    922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 923, 923, 923, 924, 
-    924, 924, 924, 924, 924, 924, 924, 924, 923, 925, 926, 927, 81, 81, 81, 
-    81, 928, 928, 928, 928, 928, 928, 928, 928, 929, 929, 929, 929, 929, 929, 
-    929, 929, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 931, 931, 
-    931, 931, 931, 931, 931, 931, 931, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
-    81, 81, 81, 932, 933, 934, 934, 934, 934, 934, 934, 935, 935, 934, 934, 
-    933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 
-    933, 933, 934, 936, 934, 934, 934, 934, 937, 933, 934, 934, 934, 934, 
-    938, 939, 940, 940, 940, 940, 938, 939, 936, 941, 942, 942, 942, 942, 
-    942, 942, 943, 943, 942, 942, 942, 941, 941, 941, 941, 941, 941, 941, 
-    941, 941, 941, 941, 941, 941, 941, 941, 941, 81, 81, 941, 941, 941, 941, 
-    942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 943, 
-    942, 944, 945, 945, 945, 941, 946, 946, 946, 945, 945, 81, 81, 81, 81, 
-    81, 947, 947, 947, 947, 947, 947, 947, 947, 947, 81, 81, 81, 81, 81, 81, 
-    81, 948, 948, 948, 948, 948, 948, 948, 948, 948, 81, 948, 948, 948, 948, 
-    948, 948, 948, 948, 948, 948, 948, 948, 948, 949, 950, 950, 950, 950, 
-    950, 950, 950, 81, 950, 950, 950, 950, 950, 950, 949, 951, 948, 952, 952, 
-    952, 952, 952, 81, 81, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 
-    954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 
-    954, 954, 954, 954, 954, 81, 81, 81, 955, 956, 957, 957, 957, 957, 957, 
-    957, 957, 957, 957, 957, 957, 957, 957, 957, 81, 81, 958, 958, 958, 958, 
-    958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 81, 959, 958, 958, 958, 
-    958, 958, 958, 958, 959, 958, 958, 959, 958, 958, 81, 960, 960, 960, 960, 
-    960, 960, 960, 81, 960, 960, 81, 960, 960, 960, 960, 960, 960, 960, 960, 
-    960, 960, 960, 960, 960, 960, 961, 961, 961, 961, 961, 961, 81, 81, 81, 
-    961, 81, 961, 961, 81, 961, 961, 961, 962, 961, 963, 963, 960, 961, 964, 
-    964, 964, 964, 964, 964, 964, 964, 964, 964, 81, 81, 81, 81, 81, 81, 965, 
-    965, 965, 965, 965, 965, 81, 965, 965, 81, 965, 965, 965, 965, 965, 965, 
-    965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 966, 966, 966, 966, 
-    966, 81, 967, 967, 81, 966, 966, 967, 966, 968, 965, 81, 81, 81, 81, 81, 
-    81, 81, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 81, 81, 81, 81, 
-    81, 81, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 971, 971, 
-    972, 972, 973, 973, 81, 81, 81, 81, 81, 81, 81, 974, 974, 974, 974, 974, 
-    974, 974, 974, 974, 974, 81, 81, 81, 81, 81, 81, 975, 975, 975, 975, 975, 
-    975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 81, 976, 976, 976, 976, 
-    976, 81, 81, 81, 974, 974, 974, 974, 81, 81, 81, 81, 977, 977, 977, 977, 
-    977, 977, 977, 977, 978, 978, 978, 979, 979, 979, 977, 977, 977, 977, 
-    979, 977, 977, 977, 978, 979, 978, 979, 977, 977, 977, 977, 977, 977, 
-    977, 978, 979, 979, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 
-    977, 81, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 
-    980, 981, 982, 980, 980, 980, 980, 980, 980, 980, 81, 608, 81, 81, 81, 
-    81, 81, 81, 81, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 
-    983, 983, 983, 983, 81, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 
-    81, 81, 81, 81, 985, 985, 986, 986, 986, 986, 986, 986, 986, 986, 986, 
-    986, 986, 986, 986, 986, 81, 81, 987, 987, 987, 987, 987, 988, 81, 81, 
-    989, 989, 989, 989, 989, 989, 989, 989, 990, 990, 990, 990, 990, 990, 
-    990, 991, 991, 991, 992, 992, 993, 993, 993, 993, 994, 994, 994, 994, 
-    991, 993, 81, 81, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 81, 
-    996, 996, 996, 996, 996, 996, 996, 81, 989, 989, 989, 989, 989, 81, 81, 
-    81, 81, 81, 989, 989, 989, 997, 997, 997, 997, 997, 997, 997, 997, 998, 
-    998, 998, 998, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, 999, 
-    999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, 1001, 1001, 81, 81, 
-    81, 81, 81, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 
-    1002, 1002, 1002, 81, 81, 81, 1002, 1003, 1003, 1003, 1003, 1003, 1003, 
-    1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 
-    1003, 1003, 1003, 1003, 81, 81, 81, 81, 81, 81, 81, 81, 1004, 1004, 1004, 
-    1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 
-    1005, 1005, 1006, 1007, 81, 81, 81, 81, 81, 81, 1008, 1008, 1008, 1008, 
-    1008, 1008, 1008, 1008, 1008, 1008, 81, 81, 81, 81, 81, 81, 1008, 1008, 
-    1008, 81, 81, 81, 81, 81, 579, 574, 574, 574, 574, 574, 574, 574, 574, 
-    574, 574, 574, 574, 574, 574, 81, 1009, 1009, 1009, 1009, 1009, 1009, 
-    1009, 1009, 1009, 1009, 1009, 1009, 81, 81, 81, 81, 1010, 1010, 1010, 
-    1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 81, 81, 81, 81, 81, 1010, 
-    1010, 1010, 1010, 1010, 81, 81, 81, 1010, 81, 81, 81, 81, 81, 81, 81, 
-    1010, 1010, 81, 81, 1011, 1012, 1013, 1014, 503, 503, 503, 503, 81, 81, 
-    81, 81, 317, 317, 317, 317, 317, 317, 81, 81, 317, 317, 317, 317, 317, 
-    317, 317, 81, 81, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 
-    317, 1015, 1015, 451, 451, 451, 317, 317, 317, 1016, 1015, 1015, 1015, 
-    1015, 1015, 503, 503, 503, 503, 503, 503, 503, 503, 156, 156, 156, 156, 
-    156, 156, 156, 156, 317, 317, 96, 96, 96, 96, 96, 156, 156, 317, 317, 
-    317, 317, 317, 317, 96, 96, 96, 96, 317, 317, 317, 81, 81, 81, 81, 81, 
-    81, 81, 724, 724, 1017, 1017, 1017, 724, 81, 81, 619, 619, 619, 619, 81, 
-    81, 81, 81, 619, 81, 81, 81, 81, 81, 81, 81, 510, 510, 510, 510, 510, 
-    510, 510, 510, 510, 510, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 
-    49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, 
-    49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, 49, 49, 510, 81, 510, 
-    510, 81, 81, 510, 81, 81, 510, 510, 81, 81, 510, 510, 510, 510, 81, 510, 
-    510, 49, 49, 81, 49, 81, 49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, 
-    49, 49, 49, 510, 510, 81, 510, 510, 510, 510, 81, 81, 510, 510, 510, 510, 
-    510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49, 
-    510, 510, 81, 510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 81, 510, 
-    81, 81, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49, 49, 49, 49, 
-    49, 49, 49, 49, 49, 49, 49, 81, 81, 510, 1018, 49, 49, 49, 49, 49, 49, 
-    49, 49, 49, 496, 49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 
-    510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496, 49, 49, 
-    510, 510, 510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496, 
-    49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510, 
-    1018, 49, 496, 49, 49, 49, 49, 49, 49, 49, 49, 510, 49, 81, 81, 1019, 
-    1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1020, 1020, 1020, 
-    1020, 1020, 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 
-    1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020, 1020, 1020, 
-    1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020, 
-    1020, 1020, 1020, 1020, 1020, 1020, 1021, 1020, 1020, 1020, 1020, 1020, 
-    1020, 1021, 1020, 1020, 1022, 1022, 1022, 1022, 1023, 81, 81, 81, 81, 81, 
-    81, 81, 1021, 1021, 1021, 1021, 1021, 81, 1021, 1021, 1021, 1021, 1021, 
-    1021, 1021, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 1024, 1024, 
-    1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 81, 1024, 1024, 1024, 1024, 
-    1024, 1024, 1024, 81, 1024, 1024, 81, 1024, 1024, 1024, 1024, 1024, 81, 
-    81, 81, 81, 81, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 
-    1025, 1025, 1025, 1025, 81, 81, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 
-    1026, 1026, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 81, 1028, 1028, 
-    1028, 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1029, 1029, 1029, 1029, 
-    1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 
-    1029, 1029, 1030, 1030, 1030, 1030, 1030, 1030, 1031, 81, 81, 81, 81, 81, 
-    1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 81, 81, 81, 
-    81, 1033, 1033, 81, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 
-    1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1035, 1034, 
-    1034, 1034, 1036, 1034, 1034, 1034, 1034, 81, 81, 81, 146, 146, 146, 146, 
-    81, 146, 146, 146, 81, 146, 146, 81, 146, 81, 81, 146, 81, 146, 146, 146, 
-    146, 146, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 81, 146, 81, 
-    146, 81, 81, 81, 81, 81, 81, 146, 81, 81, 81, 81, 146, 81, 146, 81, 146, 
-    81, 146, 146, 146, 81, 146, 81, 146, 81, 146, 81, 146, 81, 146, 146, 146, 
-    146, 81, 146, 81, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146, 
-    146, 81, 81, 81, 81, 81, 146, 146, 146, 81, 146, 146, 146, 132, 132, 81, 
-    81, 81, 81, 81, 81, 529, 529, 529, 529, 525, 529, 529, 529, 529, 529, 
-    529, 529, 529, 529, 529, 529, 529, 529, 529, 529, 1037, 1037, 1037, 1037, 
-    1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 529, 529, 529, 529, 529, 
-    529, 529, 1037, 1037, 529, 529, 529, 529, 529, 529, 529, 529, 529, 529, 
-    529, 529, 529, 529, 525, 529, 529, 529, 529, 529, 529, 1037, 1037, 47, 
-    47, 47, 519, 519, 1037, 1037, 1037, 530, 530, 530, 530, 530, 530, 317, 
-    40, 530, 530, 40, 40, 1037, 1037, 1037, 1037, 530, 530, 530, 530, 530, 
-    530, 1038, 530, 530, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 
-    1038, 1038, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 1037, 1037, 
-    1037, 1037, 1037, 1037, 1037, 1037, 1037, 1039, 1039, 1039, 1039, 1039, 
-    1039, 1039, 1039, 1039, 1039, 1040, 585, 585, 1037, 1037, 1037, 1037, 
-    1037, 585, 585, 585, 585, 1037, 1037, 1037, 1037, 585, 1037, 1037, 1037, 
-    1037, 1037, 1037, 1037, 585, 585, 1037, 1037, 1037, 1037, 1037, 1037, 
-    525, 525, 525, 525, 525, 525, 1037, 1037, 525, 529, 529, 529, 529, 529, 
-    529, 529, 529, 529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 525, 
-    525, 525, 529, 525, 525, 525, 525, 525, 525, 529, 525, 525, 525, 525, 
-    525, 525, 525, 536, 525, 525, 525, 525, 525, 525, 529, 529, 529, 529, 
-    529, 529, 529, 529, 40, 40, 529, 529, 525, 525, 525, 525, 525, 528, 528, 
-    525, 525, 525, 525, 525, 528, 525, 525, 525, 525, 525, 536, 536, 536, 
-    525, 525, 536, 525, 525, 536, 534, 534, 529, 529, 525, 525, 529, 529, 
-    529, 525, 529, 529, 529, 525, 525, 525, 1041, 1041, 1041, 1041, 1041, 
-    525, 525, 525, 525, 525, 525, 525, 529, 525, 529, 536, 536, 525, 525, 
-    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 525, 
-    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536, 536, 
-    525, 525, 525, 525, 536, 525, 536, 525, 525, 525, 536, 525, 525, 525, 
-    525, 536, 536, 536, 525, 536, 536, 536, 528, 525, 528, 525, 528, 525, 
-    525, 525, 525, 525, 536, 525, 525, 525, 525, 528, 525, 528, 528, 525, 
-    525, 525, 525, 525, 525, 525, 525, 525, 525, 529, 529, 525, 528, 528, 
-    528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 525, 525, 525, 528, 
-    528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 528, 528, 528, 528, 
-    528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 529, 525, 525, 
-    525, 525, 529, 529, 529, 529, 529, 534, 534, 529, 529, 529, 529, 536, 
-    529, 529, 529, 529, 529, 534, 529, 529, 529, 529, 536, 536, 529, 529, 
-    529, 529, 529, 40, 40, 40, 40, 40, 40, 40, 40, 529, 529, 529, 529, 40, 
-    40, 529, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536, 
-    525, 525, 525, 536, 536, 536, 536, 536, 40, 40, 40, 40, 40, 40, 538, 538, 
-    538, 1042, 1042, 1042, 40, 40, 40, 40, 525, 525, 525, 536, 525, 525, 525, 
-    525, 525, 525, 525, 525, 536, 536, 536, 525, 536, 525, 525, 525, 525, 
-    525, 529, 529, 529, 529, 529, 529, 536, 529, 529, 529, 525, 525, 525, 
-    529, 529, 1037, 1037, 1037, 529, 529, 529, 525, 525, 1037, 1037, 1037, 
-    529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 1037, 1037, 1037, 1037, 
-    1037, 1037, 40, 40, 40, 40, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40, 
-    529, 529, 529, 529, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 40, 40, 
-    1037, 1037, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40, 40, 1037, 1037, 
-    536, 536, 536, 536, 536, 525, 536, 536, 525, 525, 525, 525, 525, 525, 
-    536, 525, 536, 536, 525, 525, 525, 536, 536, 1037, 525, 1037, 1037, 525, 
-    525, 525, 525, 1037, 1037, 1037, 525, 1037, 525, 525, 525, 525, 525, 525, 
-    525, 1037, 1037, 1037, 1037, 1037, 525, 525, 525, 525, 525, 536, 536, 
-    525, 536, 536, 1037, 1037, 1037, 1037, 1037, 1037, 525, 536, 536, 536, 
-    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 1037, 1037, 
-    1037, 1037, 1037, 1037, 81, 81, 592, 592, 592, 592, 592, 592, 592, 593, 
-    592, 592, 592, 592, 592, 593, 593, 593, 592, 593, 593, 593, 593, 593, 
-    593, 593, 593, 593, 593, 593, 593, 593, 81, 81, 81, 503, 81, 81, 81, 81, 
-    81, 81, 503, 503, 503, 503, 503, 503, 503, 503, 670, 670, 670, 670, 670, 
-    670, 81, 81, 
-};
-
-/* decomposition data */
-static const unsigned short decomp_data[] = {
-    0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514, 
-    32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52, 
-    772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512, 
-    65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69, 
-    768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73, 
-    769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79, 
-    769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85, 
-    769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97, 
-    769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99, 
-    807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512, 
-    105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771, 
-    512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111, 
-    776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512, 
-    121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512, 
-    97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67, 
-    770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99, 
-    780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69, 
-    774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101, 
-    808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71, 
-    774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103, 
-    807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73, 
-    772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105, 
-    808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106, 
-    770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76, 
-    807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108, 
-    183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78, 
-    780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79, 
-    774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114, 
-    769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83, 
-    769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115, 
-    807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84, 
-    780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117, 
-    772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85, 
-    779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119, 
-    770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122, 
-    769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115, 
-    512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381, 
-    514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106, 
-    514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780, 
-    512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780, 
-    512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252, 
-    769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512, 
-    196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772, 
-    512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780, 
-    512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780, 
-    512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122, 
-    512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769, 
-    512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248, 
-    769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69, 
-    783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105, 
-    783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79, 
-    785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114, 
-    785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83, 
-    806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104, 
-    780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214, 
-    772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111, 
-    775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104, 
-    259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119, 
-    259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514, 
-    32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661, 
-    256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256, 
-    59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769, 
-    512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937, 
-    769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512, 
-    949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776, 
-    512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946, 
-    258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960, 
-    258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045, 
-    768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512, 
-    1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077, 
-    768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512, 
-    1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046, 
-    774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512, 
-    1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241, 
-    776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512, 
-    1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054, 
-    776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512, 
-    1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091, 
-    776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512, 
-    1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575, 
-    1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652, 
-    514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512, 
-    1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355, 
-    2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364, 
-    512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512, 
-    2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479, 
-    2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620, 
-    512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512, 
-    2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014, 
-    3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285, 
-    512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512, 
-    3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545, 
-    3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762, 
-    514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916, 
-    4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021, 
-    512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512, 
-    4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996, 
-    4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021, 
-    512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921, 
-    6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965, 
-    512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259, 
-    65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259, 
-    73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259, 
-    80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259, 
-    7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259, 
-    103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259, 
-    7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259, 
-    7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261, 
-    114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261, 
-    967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259, 
-    102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259, 
-    7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259, 
-    626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259, 
-    427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259, 
-    656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66, 
-    775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98, 
-    817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68, 
-    803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100, 
-    807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274, 
-    769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101, 
-    816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71, 
-    772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104, 
-    803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72, 
-    814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239, 
-    769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75, 
-    817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512, 
-    7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512, 
-    77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512, 
-    109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512, 
-    78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512, 
-    245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768, 
-    512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775, 
-    512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803, 
-    512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83, 
-    775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347, 
-    775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512, 
-    84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512, 
-    116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512, 
-    85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512, 
-    361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512, 
-    86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512, 
-    119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512, 
-    87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512, 
-    120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512, 
-    90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512, 
-    116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512, 
-    65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512, 
-    226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777, 
-    512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258, 
-    769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512, 
-    259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774, 
-    512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771, 
-    512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234, 
-    768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512, 
-    7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803, 
-    512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777, 
-    512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212, 
-    777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512, 
-    7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768, 
-    512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416, 
-    803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117, 
-    777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512, 
-    431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803, 
-    512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803, 
-    512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787, 
-    512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937, 
-    769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512, 
-    7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944, 
-    834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512, 
-    7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788, 
-    512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951, 
-    787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512, 
-    7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788, 
-    512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512, 
-    7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768, 
-    512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512, 
-    7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768, 
-    512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959, 
-    787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512, 
-    8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768, 
-    512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016, 
-    768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512, 
-    8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834, 
-    512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032, 
-    769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512, 
-    937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769, 
-    512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768, 
-    256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959, 
-    768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512, 
-    7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940, 
-    837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512, 
-    7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949, 
-    837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512, 
-    7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974, 
-    837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512, 
-    7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983, 
-    837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512, 
-    8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040, 
-    837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512, 
-    8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772, 
-    512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118, 
-    837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913, 
-    837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834, 
-    512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134, 
-    837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837, 
-    512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953, 
-    772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921, 
-    774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190, 
-    769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256, 
-    944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512, 
-    933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512, 
-    168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974, 
-    837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937, 
-    768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256, 
-    8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258, 
-    32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46, 
-    46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245, 
-    770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63, 
-    33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259, 
-    105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259, 
-    8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50, 
-    261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43, 
-    261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261, 
-    120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261, 
-    112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115, 
-    262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514, 
-    176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262, 
-    73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81, 
-    262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77, 
-    262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262, 
-    101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258, 
-    1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915, 
-    262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106, 
-    772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49, 
-    8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772, 
-    51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54, 
-    772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260, 
-    56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86, 
-    258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88, 
-    258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258, 
-    77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118, 
-    514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105, 
-    120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258, 
-    100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512, 
-    8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707, 
-    824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514, 
-    8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750, 
-    8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824, 
-    512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824, 
-    512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512, 
-    8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834, 
-    824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512, 
-    8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829, 
-    824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512, 
-    8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263, 
-    51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48, 
-    519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49, 
-    54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41, 
-    770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770, 
-    40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40, 
-    49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51, 
-    41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41, 
-    1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026, 
-    40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514, 
-    53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48, 
-    46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46, 
-    770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770, 
-    49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40, 
-    99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40, 
-    103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40, 
-    107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40, 
-    111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40, 
-    115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40, 
-    119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65, 
-    263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73, 
-    263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81, 
-    263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89, 
-    263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263, 
-    103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263, 
-    110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263, 
-    117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026, 
-    8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61, 
-    512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863, 
-    258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101, 
-    258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843, 
-    258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992, 
-    258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313, 
-    258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475, 
-    258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805, 
-    258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567, 
-    258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037, 
-    258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308, 
-    258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435, 
-    258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908, 
-    258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085, 
-    258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513, 
-    258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668, 
-    258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247, 
-    258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577, 
-    258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000, 
-    258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399, 
-    258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160, 
-    258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992, 
-    258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780, 
-    258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258, 
-    258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390, 
-    258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892, 
-    258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895, 
-    258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208, 
-    258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789, 
-    258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263, 
-    258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737, 
-    258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899, 
-    258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321, 
-    258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727, 
-    258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575, 
-    258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697, 
-    258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778, 
-    258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258, 
-    21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512, 
-    12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441, 
-    512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381, 
-    12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512, 
-    12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442, 
-    512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405, 
-    12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512, 
-    12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512, 
-    12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441, 
-    512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469, 
-    12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512, 
-    12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441, 
-    512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495, 
-    12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512, 
-    12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441, 
-    512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528, 
-    12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521, 
-    12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258, 
-    4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530, 
-    258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258, 
-    4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365, 
-    258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258, 
-    4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456, 
-    258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258, 
-    4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469, 
-    258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258, 
-    4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575, 
-    258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258, 
-    4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402, 
-    258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258, 
-    4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497, 
-    258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259, 
-    19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259, 
-    20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770, 
-    40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41, 
-    770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363, 
-    41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40, 
-    4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41, 
-    1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449, 
-    41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361, 
-    4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40, 
-    4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026, 
-    40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41, 
-    1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370, 
-    4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41, 
-    770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40, 
-    19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41, 
-    770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40, 
-    26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41, 
-    770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40, 
-    21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41, 
-    770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40, 
-    23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41, 
-    770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40, 
-    33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263, 
-    31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50, 
-    52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519, 
-    51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53, 
-    263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263, 
-    4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369, 
-    263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357, 
-    4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449, 
-    519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519, 
-    4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031, 
-    4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263, 
-    19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263, 
-    20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263, 
-    37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263, 
-    21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263, 
-    30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263, 
-    38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263, 
-    19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263, 
-    30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519, 
-    51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50, 
-    519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52, 
-    56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51, 
-    26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376, 
-    514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376, 
-    770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778, 
-    76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458, 
-    263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469, 
-    263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481, 
-    263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492, 
-    263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504, 
-    263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514, 
-    263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523, 
-    263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530, 
-    1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034, 
-    12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491, 
-    12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290, 
-    12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778, 
-    12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522, 
-    1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778, 
-    12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778, 
-    12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462, 
-    12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521, 
-    12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461, 
-    12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521, 
-    12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034, 
-    12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523, 
-    12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290, 
-    12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778, 
-    12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473, 
-    522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490, 
-    12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497, 
-    12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540, 
-    12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463, 
-    12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521, 
-    12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483, 
-    12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479, 
-    12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504, 
-    12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778, 
-    12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523, 
-    12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540, 
-    12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778, 
-    12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463, 
-    1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525, 
-    12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522, 
-    12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540, 
-    12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778, 
-    12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521, 
-    778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524, 
-    12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488, 
-    514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52, 
-    28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857, 
-    514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50, 
-    28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770, 
-    49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57, 
-    28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770, 
-    50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522, 
-    65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778, 
-    100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522, 
-    26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335, 
-    20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65, 
-    522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108, 
-    1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522, 
-    956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122, 
-    778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467, 
-    522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110, 
-    109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109, 
-    109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109, 
-    109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109, 
-    8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778, 
-    77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725, 
-    115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115, 
-    522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86, 
-    522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522, 
-    956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77, 
-    937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100, 
-    1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121, 
-    522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522, 
-    107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108, 
-    120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72, 
-    1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522, 
-    83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49, 
-    26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085, 
-    514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49, 
-    48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085, 
-    770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55, 
-    26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770, 
-    50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52, 
-    26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770, 
-    50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49, 
-    26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294, 
-    259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256, 
-    26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256, 
-    40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256, 
-    25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256, 
-    37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256, 
-    37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256, 
-    34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256, 
-    25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256, 
-    29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256, 
-    27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256, 
-    36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256, 
-    32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256, 
-    24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256, 
-    38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256, 
-    32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256, 
-    20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256, 
-    25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256, 
-    29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256, 
-    19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256, 
-    30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256, 
-    25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256, 
-    20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256, 
-    21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256, 
-    31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256, 
-    26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256, 
-    25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256, 
-    32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256, 
-    21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256, 
-    24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256, 
-    22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256, 
-    32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256, 
-    20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256, 
-    20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256, 
-    30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, 
-    21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, 
-    30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, 
-    38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, 
-    24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256, 
-    23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256, 
-    30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256, 
-    21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256, 
-    38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256, 
-    31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256, 
-    20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256, 
-    31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256, 
-    38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256, 
-    26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256, 
-    31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256, 
-    35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256, 
-    40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256, 
-    21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256, 
-    22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256, 
-    24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256, 
-    28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256, 
-    30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256, 
-    31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256, 
-    32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256, 
-    33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256, 
-    35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256, 
-    38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006, 
-    256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191, 
-    256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618, 
-    256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, 
-    256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, 
-    256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628, 
-    256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454, 
-    256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450, 
-    256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482, 
-    256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410, 
-    256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409, 
-    256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773, 
-    256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222, 
-    256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565, 
-    256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273, 
-    256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911, 
-    256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256, 
-    55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256, 
-    55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256, 
-    40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105, 
-    770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514, 
-    1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497, 
-    1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262, 
-    1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513, 
-    1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488, 
-    1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468, 
-    512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512, 
-    1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500, 
-    1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468, 
-    512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512, 
-    1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499, 
-    1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659, 
-    268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270, 
-    1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658, 
-    269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267, 
-    1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700, 
-    270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268, 
-    1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667, 
-    267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269, 
-    1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678, 
-    268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268, 
-    1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711, 
-    269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267, 
-    1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723, 
-    268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268, 
-    1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726, 
-    267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269, 
-    1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736, 
-    268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267, 
-    1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609, 
-    270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574, 
-    1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735, 
-    523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523, 
-    1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574, 
-    1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523, 
-    1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574, 
-    1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605, 
-    523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523, 
-    1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579, 
-    1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581, 
-    523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523, 
-    1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587, 
-    1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580, 
-    523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523, 
-    1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594, 
-    1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582, 
-    523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523, 
-    1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603, 
-    1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605, 
-    523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523, 
-    1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605, 
-    1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609, 
-    523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523, 
-    1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607, 
-    1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581, 
-    523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523, 
-    1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779, 
-    32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616, 
-    1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574, 
-    1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585, 
-    524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524, 
-    1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578, 
-    1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586, 
-    524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524, 
-    1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603, 
-    1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610, 
-    524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524, 
-    1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606, 
-    1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585, 
-    524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524, 
-    1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574, 
-    1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582, 
-    525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525, 
-    1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580, 
-    1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580, 
-    525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525, 
-    1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590, 
-    1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581, 
-    525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525, 
-    1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601, 
-    1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581, 
-    525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525, 
-    1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605, 
-    1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580, 
-    525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525, 
-    1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610, 
-    1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605, 
-    526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526, 
-    1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587, 
-    1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605, 
-    526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526, 
-    1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600, 
-    1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593, 
-    1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610, 
-    523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523, 
-    1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589, 
-    1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580, 
-    523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523, 
-    1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591, 
-    1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610, 
-    524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524, 
-    1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582, 
-    1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609, 
-    524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524, 
-    1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590, 
-    1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605, 
-    525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526, 
-    1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588, 
-    1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611, 
-    781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781, 
-    1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781, 
-    1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781, 
-    1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781, 
-    1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780, 
-    1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780, 
-    1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781, 
-    1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781, 
-    1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781, 
-    1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780, 
-    1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780, 
-    1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780, 
-    1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781, 
-    1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780, 
-    1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781, 
-    1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780, 
-    1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781, 
-    1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781, 
-    1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781, 
-    1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781, 
-    1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781, 
-    1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781, 
-    1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780, 
-    1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780, 
-    1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781, 
-    1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780, 
-    1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780, 
-    1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780, 
-    1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780, 
-    1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780, 
-    1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780, 
-    1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780, 
-    1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781, 
-    1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781, 
-    1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780, 
-    1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780, 
-    1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780, 
-    1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781, 
-    1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780, 
-    1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035, 
-    1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581, 
-    1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604, 
-    1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589, 
-    1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593, 
-    1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580, 
-    1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265, 
-    12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265, 
-    12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265, 
-    40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265, 
-    12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265, 
-    12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254, 
-    258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289, 
-    271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41, 
-    271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42, 
-    271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37, 
-    271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613, 
-    523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32, 
-    1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618, 
-    526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571, 
-    267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269, 
-    1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576, 
-    270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270, 
-    1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580, 
-    269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267, 
-    1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584, 
-    268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268, 
-    1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588, 
-    267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269, 
-    1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592, 
-    268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270, 
-    1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601, 
-    269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267, 
-    1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604, 
-    270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268, 
-    1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607, 
-    267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269, 
-    1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524, 
-    1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604, 
-    1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264, 
-    40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264, 
-    48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264, 
-    56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264, 
-    64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264, 
-    72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264, 
-    80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264, 
-    88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264, 
-    96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103, 
-    264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110, 
-    264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117, 
-    264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124, 
-    264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272, 
-    12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272, 
-    12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272, 
-    12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272, 
-    12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272, 
-    12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272, 
-    12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272, 
-    12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272, 
-    12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272, 
-    12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272, 
-    12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272, 
-    12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272, 
-    12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272, 
-    12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272, 
-    12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272, 
-    12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272, 
-    12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272, 
-    12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272, 
-    12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272, 
-    12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264, 
-    163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272, 
-    8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300, 
-    56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485, 
-    55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300, 
-    56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175, 
-    512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512, 
-    55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301, 
-    56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664, 
-    55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348, 
-    56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689, 
-    512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512, 
-    55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348, 
-    56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764, 
-    55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 
-    71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 
-    79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 
-    87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 
-    101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 
-    108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 
-    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 
-    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 
-    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 
-    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 
-    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
-    102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 
-    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 
-    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 
-    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 
-    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 
-    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 
-    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 
-    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 
-    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 
-    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68, 
-    262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 
-    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 
-    262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262, 
-    107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262, 
-    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 
-    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 
-    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 
-    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 
-    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
-    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 
-    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 
-    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 
-    262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76, 
-    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85, 
-    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, 
-    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 
-    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 
-    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 
-    262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73, 
-    262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85, 
-    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, 
-    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 
-    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 
-    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 
-    262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 
-    262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 
-    262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 
-    262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 
-    262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 
-    262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 
-    262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 
-    262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 
-    262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 
-    262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 
-    262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
-    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 
-    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 
-    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 
-    262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 
-    262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 
-    262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 
-    262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 
-    103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 
-    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 
-    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 
-    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 
-    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 
-    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 
-    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 
-    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 
-    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 
-    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 
-    262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 
-    262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 
-    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 
-    262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 
-    105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 
-    112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 
-    119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 
-    262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 
-    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 
-    262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 
-    262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 
-    106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 
-    113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 
-    120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262, 
-    915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 
-    922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 
-    929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 
-    936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 
-    949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 
-    956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 
-    963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 
-    8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 
-    913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 
-    920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 
-    927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 
-    934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 
-    947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 
-    954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 
-    961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 
-    968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 
-    1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 
-    918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 
-    925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 
-    932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 
-    945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 
-    952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 
-    959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 
-    966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 
-    1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 
-    916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 
-    923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 
-    1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 
-    937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 
-    950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 
-    957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 
-    964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 
-    1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 
-    914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 
-    921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 
-    928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 
-    935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 
-    948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 
-    955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 
-    962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 
-    969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 
-    982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 
-    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 
-    262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 
-    262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 
-    262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 
-    262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 
-    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262, 
-    1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 
-    262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 
-    1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 
-    262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262, 
-    1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581, 
-    262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 
-    1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579, 
-    262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262, 
-    1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588, 
-    262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262, 
-    1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605, 
-    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, 
-    1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594, 
-    262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262, 
-    1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 
-    262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 
-    1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 
-    262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262, 
-    1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605, 
-    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, 
-    1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590, 
-    262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44, 
-    514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56, 
-    44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770, 
-    40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40, 
-    72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76, 
-    41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41, 
-    770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770, 
-    40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40, 
-    89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519, 
-    67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266, 
-    70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266, 
-    78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266, 
-    86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522, 
-    83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77, 
-    68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266, 
-    25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266, 
-    35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266, 
-    21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266, 
-    29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266, 
-    25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266, 
-    21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266, 
-    21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266, 
-    21942, 266, 37197, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309, 
-    770, 12308, 20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857, 
-    12309, 770, 12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308, 
-    21213, 12309, 770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256, 
-    20029, 256, 20024, 256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398, 
-    256, 20411, 256, 20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687, 
-    256, 13470, 256, 55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256, 
-    20855, 256, 55361, 56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361, 
-    56651, 256, 20887, 256, 20900, 256, 20172, 256, 20908, 256, 20917, 256, 
-    55396, 56799, 256, 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062, 
-    256, 21106, 256, 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220, 
-    256, 21242, 256, 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329, 
-    256, 21338, 256, 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375, 
-    256, 55362, 56876, 256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187, 
-    256, 21483, 256, 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576, 
-    256, 21608, 256, 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859, 
-    256, 21892, 256, 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954, 
-    256, 22294, 256, 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999, 
-    256, 22766, 256, 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578, 
-    256, 22577, 256, 22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256, 
-    22790, 256, 22810, 256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365, 
-    57066, 256, 23020, 256, 23067, 256, 23079, 256, 23000, 256, 23142, 256, 
-    14062, 256, 14076, 256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776, 
-    256, 23491, 256, 23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256, 
-    23551, 256, 23558, 256, 24403, 256, 23586, 256, 14209, 256, 23648, 256, 
-    23662, 256, 23744, 256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367, 
-    56806, 256, 23918, 256, 23915, 256, 23932, 256, 24033, 256, 24034, 256, 
-    14383, 256, 24061, 256, 24104, 256, 24125, 256, 24169, 256, 14434, 256, 
-    55368, 56707, 256, 14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266, 
-    256, 55400, 57234, 256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256, 
-    33281, 256, 24354, 256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384, 
-    56794, 256, 24418, 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256, 
-    24535, 256, 24569, 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256, 
-    55369, 57044, 256, 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908, 
-    256, 24954, 256, 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054, 
-    256, 25074, 256, 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265, 
-    256, 25300, 256, 25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256, 
-    25448, 256, 25475, 256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541, 
-    256, 25513, 256, 14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719, 
-    256, 14956, 256, 25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256, 
-    26360, 256, 26185, 256, 15129, 256, 26257, 256, 15112, 256, 15076, 256, 
-    20882, 256, 20885, 256, 26368, 256, 26268, 256, 32941, 256, 17369, 256, 
-    26391, 256, 26395, 256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283, 
-    256, 15177, 256, 26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373, 
-    56429, 256, 26766, 256, 26655, 256, 26900, 256, 15261, 256, 26946, 256, 
-    27043, 256, 27114, 256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384, 
-    256, 27425, 256, 55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256, 
-    27551, 256, 27578, 256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256, 
-    55374, 57082, 256, 27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256, 
-    27751, 256, 27926, 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256, 
-    28024, 256, 28037, 256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270, 
-    256, 15667, 256, 28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256, 
-    28526, 256, 55375, 57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256, 
-    28702, 256, 28699, 256, 15766, 256, 28746, 256, 28797, 256, 28791, 256, 
-    28845, 256, 55361, 56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256, 
-    55376, 57259, 256, 29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256, 
-    29312, 256, 29333, 256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256, 
-    29579, 256, 16044, 256, 29605, 256, 16056, 256, 16056, 256, 29767, 256, 
-    29788, 256, 29809, 256, 29829, 256, 29898, 256, 16155, 256, 29988, 256, 
-    55379, 56374, 256, 30014, 256, 55379, 56466, 256, 30064, 256, 55368, 
-    56735, 256, 30224, 256, 55379, 57249, 256, 55379, 57272, 256, 55380, 
-    56388, 256, 16380, 256, 16392, 256, 30452, 256, 55380, 56563, 256, 55380, 
-    56562, 256, 55380, 56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256, 
-    30495, 256, 30538, 256, 16441, 256, 30603, 256, 16454, 256, 16534, 256, 
-    55381, 56349, 256, 30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381, 
-    56870, 256, 31062, 256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256, 
-    31211, 256, 16687, 256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700, 
-    256, 55382, 56999, 256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382, 
-    57259, 256, 31686, 256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954, 
-    256, 17056, 256, 31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256, 
-    32099, 256, 17153, 256, 32199, 256, 32258, 256, 32325, 256, 17204, 256, 
-    55384, 56872, 256, 55384, 56903, 256, 17241, 256, 55384, 57049, 256, 
-    32634, 256, 55384, 57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385, 
-    56538, 256, 55385, 56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256, 
-    55372, 57183, 256, 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086, 
-    256, 23221, 256, 55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256, 
-    55372, 57244, 256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425, 
-    256, 33419, 256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469, 
-    256, 33510, 256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256, 
-    33709, 256, 33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256, 
-    33738, 256, 33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256, 
-    55387, 56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388, 
-    57290, 256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387, 
-    57265, 256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407, 
-    256, 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681, 
-    256, 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817, 
-    256, 17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256, 
-    35038, 256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390, 
-    56678, 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256, 
-    35925, 256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215, 
-    256, 55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336, 
-    256, 55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393, 
-    56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147, 
-    256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909, 
-    256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695, 
-    256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256, 
-    55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256, 
-    19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397, 
-    56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256, 
-    39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189, 
-    256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256, 
-    55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256, 
-    19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256, 
-    40763, 256, 55401, 56832, 
-};
-
-/* index tables for the decomposition data */
-#define DECOMP_SHIFT1 6
-#define DECOMP_SHIFT2 4
-static const unsigned char decomp_index0[] = {
-    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 14, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20, 
-    5, 5, 5, 5, 5, 21, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
-};
-
-static const unsigned short decomp_index1[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
-    14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 
-    25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0, 
-    36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0, 
-    0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0, 
-    0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 53, 0, 0, 0, 0, 
-    0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 
-    0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 
-    0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70, 
-    71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0, 
-    82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 84, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0, 
-    93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
-    109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
-    123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0, 
-    0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0, 
-    0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0, 
-    0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 
-    158, 159, 160, 161, 162, 163, 164, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, 
-    0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
-    182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0, 
-    193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204, 
-    205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 
-    216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 
-    230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 
-    0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 243, 244, 245, 246, 247, 
-    248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 
-    262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274, 
-    275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288, 
-    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 
-    303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315, 
-    0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 
-    329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 
-    343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0, 
-    347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 
-    365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 
-    379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 
-    393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 
-    407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431, 432, 433, 434, 435, 0, 436, 0, 
-    0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 445, 
-    446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 
-    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 
-    474, 475, 476, 477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-};
-
-static const unsigned short decomp_index2[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
-    3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27, 
-    31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81, 
-    0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120, 
-    123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0, 
-    162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198, 
-    201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 
-    243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 
-    282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318, 
-    321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357, 
-    360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0, 
-    396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432, 
-    435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471, 
-    474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 
-    516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587, 
-    590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629, 
-    632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668, 
-    671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707, 
-    710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749, 
-    752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791, 
-    794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821, 
-    824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888, 
-    890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0, 
-    908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933, 
-    936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, 969, 972, 975, 
-    0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994, 
-    996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0, 
-    1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, 
-    0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048, 
-    1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060, 
-    1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0, 
-    0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102, 
-    1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135, 
-    1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168, 
-    1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183, 
-    1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216, 
-    1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234, 
-    1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246, 
-    0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267, 
-    0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276, 
-    1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306, 
-    1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0, 
-    1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0, 
-    0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0, 
-    1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0, 
-    1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0, 
-    1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462, 
-    1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484, 
-    1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506, 
-    1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530, 
-    1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554, 
-    1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570, 
-    1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594, 
-    1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618, 
-    1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644, 
-    1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680, 
-    1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716, 
-    1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752, 
-    1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788, 
-    1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824, 
-    1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860, 
-    1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, 
-    1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932, 
-    1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 
-    1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 
-    2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040, 
-    2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076, 
-    2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106, 
-    2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142, 
-    2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178, 
-    2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214, 
-    2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250, 
-    2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286, 
-    2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322, 
-    2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358, 
-    2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385, 
-    2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421, 
-    2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454, 
-    2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487, 
-    2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523, 
-    2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559, 
-    2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0, 
-    2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0, 
-    2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652, 
-    2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686, 
-    2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714, 
-    2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750, 
-    2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786, 
-    2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822, 
-    2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858, 
-    2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890, 
-    2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922, 
-    2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952, 
-    2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984, 
-    2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018, 
-    3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045, 
-    3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069, 
-    3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0, 
-    3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0, 
-    0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135, 
-    3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159, 
-    3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183, 
-    3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205, 
-    3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0, 
-    0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244, 
-    3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0, 
-    3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289, 
-    0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309, 
-    3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0, 
-    0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349, 
-    3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398, 
-    3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438, 
-    3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469, 
-    3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0, 
-    3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535, 
-    0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0, 
-    0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579, 
-    3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600, 
-    0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0, 
-    0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667, 
-    3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700, 
-    3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747, 
-    3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803, 
-    3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844, 
-    3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892, 
-    3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940, 
-    3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980, 
-    3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 
-    4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028, 
-    4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052, 
-    4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0, 
-    0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097, 
-    4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121, 
-    4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145, 
-    4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169, 
-    4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193, 
-    4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217, 
-    4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241, 
-    4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265, 
-    4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, 
-    4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313, 
-    4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337, 
-    4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361, 
-    4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385, 
-    4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409, 
-    4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433, 
-    4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457, 
-    4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481, 
-    4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505, 
-    4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529, 
-    4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0, 
-    4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0, 
-    4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0, 
-    4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0, 
-    0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0, 
-    4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674, 
-    0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0, 
-    4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716, 
-    4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741, 
-    4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765, 
-    4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789, 
-    4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813, 
-    4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837, 
-    4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861, 
-    4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885, 
-    4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909, 
-    4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929, 
-    4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959, 
-    4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008, 
-    5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068, 
-    5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121, 
-    5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169, 
-    5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217, 
-    5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0, 
-    5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279, 
-    5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, 
-    5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337, 
-    5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0, 
-    5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400, 
-    5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, 
-    5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, 
-    5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472, 
-    5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506, 
-    5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542, 
-    5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580, 
-    5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604, 
-    5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, 
-    5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652, 
-    5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683, 
-    5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737, 
-    5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796, 
-    5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847, 
-    5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898, 
-    5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951, 
-    5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003, 
-    6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054, 
-    6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092, 
-    6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140, 
-    6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182, 
-    6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220, 
-    6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261, 
-    6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299, 
-    6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345, 
-    6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391, 
-    6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429, 
-    6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468, 
-    6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510, 
-    6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548, 
-    6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594, 
-    6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660, 
-    6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684, 
-    6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, 
-    6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, 
-    6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, 
-    6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780, 
-    6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804, 
-    6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828, 
-    6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852, 
-    6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876, 
-    6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900, 
-    6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924, 
-    6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948, 
-    6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972, 
-    6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996, 
-    6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020, 
-    7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044, 
-    7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068, 
-    7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092, 
-    7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116, 
-    7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140, 
-    7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164, 
-    7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188, 
-    7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0, 
-    7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0, 
-    7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246, 
-    7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270, 
-    7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294, 
-    7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318, 
-    7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342, 
-    7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366, 
-    7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389, 
-    7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413, 
-    7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437, 
-    7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461, 
-    7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485, 
-    7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509, 
-    7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533, 
-    7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557, 
-    7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587, 
-    7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0, 
-    0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651, 
-    7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685, 
-    7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0, 
-    7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748, 
-    7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 
-    7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 
-    7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 
-    7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846, 
-    7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 
-    7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 
-    7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 
-    7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942, 
-    7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972, 
-    7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996, 
-    7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032, 
-    8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064, 
-    8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100, 
-    8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136, 
-    8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172, 
-    8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208, 
-    8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244, 
-    8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280, 
-    8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316, 
-    8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356, 
-    8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394, 
-    8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430, 
-    8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466, 
-    8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502, 
-    8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538, 
-    8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574, 
-    8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610, 
-    8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646, 
-    8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682, 
-    8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718, 
-    8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754, 
-    8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790, 
-    8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829, 
-    8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865, 
-    8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901, 
-    8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937, 
-    8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973, 
-    8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009, 
-    9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049, 
-    9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097, 
-    9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145, 
-    9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193, 
-    9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241, 
-    9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285, 
-    9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333, 
-    9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381, 
-    9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429, 
-    9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477, 
-    9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511, 
-    9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575, 
-    9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593, 
-    9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617, 
-    9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639, 
-    9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661, 
-    9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685, 
-    9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0, 
-    9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735, 
-    9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763, 
-    9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787, 
-    9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811, 
-    9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835, 
-    9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859, 
-    9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883, 
-    9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907, 
-    9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931, 
-    9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955, 
-    9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979, 
-    9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005, 
-    10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025, 
-    10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045, 
-    10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065, 
-    10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085, 
-    10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105, 
-    10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125, 
-    10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145, 
-    10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165, 
-    10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185, 
-    10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205, 
-    10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225, 
-    10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245, 
-    10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265, 
-    10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285, 
-    10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305, 
-    10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325, 
-    10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345, 
-    10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365, 
-    10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0, 
-    10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401, 
-    10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0, 
-    0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435, 
-    10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560, 
-    10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580, 
-    10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600, 
-    10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620, 
-    10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640, 
-    10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660, 
-    10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680, 
-    10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700, 
-    10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720, 
-    10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740, 
-    10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760, 
-    10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780, 
-    10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800, 
-    10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820, 
-    10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840, 
-    10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860, 
-    10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880, 
-    10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0, 
-    10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914, 
-    10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934, 
-    0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952, 
-    10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972, 
-    10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992, 
-    10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012, 
-    11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032, 
-    11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052, 
-    11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072, 
-    11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090, 
-    11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110, 
-    11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130, 
-    11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150, 
-    11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170, 
-    11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188, 
-    11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204, 
-    11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224, 
-    11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244, 
-    11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264, 
-    11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284, 
-    11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304, 
-    11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324, 
-    11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344, 
-    11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364, 
-    11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384, 
-    11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 
-    11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 
-    11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 
-    11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 
-    11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 
-    11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504, 
-    11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524, 
-    11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544, 
-    11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564, 
-    11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584, 
-    11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604, 
-    11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624, 
-    11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644, 
-    11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664, 
-    11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684, 
-    11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704, 
-    11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724, 
-    11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744, 
-    11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764, 
-    11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784, 
-    11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804, 
-    11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824, 
-    11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844, 
-    11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864, 
-    11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884, 
-    11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902, 
-    11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922, 
-    11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942, 
-    11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962, 
-    11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982, 
-    11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002, 
-    12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022, 
-    12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042, 
-    12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062, 
-    12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082, 
-    12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102, 
-    12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122, 
-    12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142, 
-    12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162, 
-    12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182, 
-    12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202, 
-    12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222, 
-    12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242, 
-    12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, 
-    12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282, 
-    12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302, 
-    12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322, 
-    12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342, 
-    12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362, 
-    12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382, 
-    12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402, 
-    12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422, 
-    12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442, 
-    12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462, 
-    12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480, 
-    12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500, 
-    12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520, 
-    12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540, 
-    12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560, 
-    12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580, 
-    12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600, 
-    12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620, 
-    12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0, 
-    0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656, 
-    12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0, 
-    0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684, 
-    12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0, 
-    12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714, 
-    12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732, 
-    12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750, 
-    12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770, 
-    12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790, 
-    12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806, 
-    12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824, 
-    12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844, 
-    12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863, 
-    12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887, 
-    12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927, 
-    12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967, 
-    12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0, 
-    13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023, 
-    13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043, 
-    13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066, 
-    13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0, 
-    13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101, 
-    13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121, 
-    13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141, 
-    13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161, 
-    13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 13179, 0, 0, 0, 
-    0, 13181, 13185, 13189, 13193, 13197, 13201, 13205, 13209, 13213, 0, 0, 
-    0, 0, 0, 0, 0, 13217, 13219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    13221, 13223, 13225, 13227, 13230, 13232, 13234, 13236, 13238, 13240, 
-    13242, 13244, 13246, 13248, 13251, 13253, 13255, 13257, 13259, 13262, 
-    13264, 13266, 13268, 13271, 13273, 13275, 13277, 13279, 13281, 13284, 
-    13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302, 13304, 
-    13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322, 13324, 
-    13326, 13328, 13330, 13333, 13335, 13337, 13339, 13342, 13344, 13346, 
-    13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364, 13366, 
-    13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384, 13386, 
-    13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404, 13406, 
-    13409, 13411, 13413, 13415, 13417, 13419, 13421, 13424, 13427, 13429, 
-    13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13447, 13450, 
-    13452, 13454, 13456, 13458, 13461, 13463, 13465, 13467, 13469, 13471, 
-    13473, 13475, 13477, 13479, 13482, 13484, 13487, 13489, 13491, 13493, 
-    13495, 13497, 13499, 13501, 13503, 13505, 13507, 13509, 13512, 13514, 
-    13516, 13518, 13520, 13522, 13525, 13527, 13530, 13533, 13535, 13537, 
-    13539, 13541, 13544, 13547, 13549, 13551, 13553, 13555, 13557, 13559, 
-    13561, 13563, 13565, 13567, 13569, 13572, 13574, 13576, 13578, 13580, 
-    13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598, 13600, 
-    13602, 13604, 13606, 13608, 13610, 13613, 13615, 13617, 13619, 13621, 
-    13623, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640, 13642, 
-    13644, 13646, 13648, 13651, 13653, 13655, 13657, 13659, 13661, 13663, 
-    13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681, 13683, 
-    13685, 13687, 13690, 13692, 13694, 13696, 13698, 13700, 13703, 13705, 
-    13707, 13709, 13711, 13713, 13715, 13717, 13719, 13722, 13724, 13726, 
-    13728, 13731, 13733, 13735, 13737, 13739, 13741, 13743, 13746, 13749, 
-    13752, 13754, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 13771, 
-    13773, 13775, 13777, 13780, 13782, 13784, 13786, 13788, 13790, 13792, 
-    13795, 13797, 13799, 13802, 13805, 13807, 13809, 13811, 13813, 13815, 
-    13817, 13819, 13821, 13823, 13826, 13828, 13831, 13833, 13836, 13838, 
-    13840, 13842, 13845, 13847, 13849, 13852, 13855, 13857, 13859, 13861, 
-    13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 13881, 
-    13884, 13886, 13889, 13891, 13894, 13896, 13899, 13902, 13905, 13907, 
-    13909, 13911, 13914, 13917, 13920, 13923, 13925, 13927, 13929, 13931, 
-    13933, 13935, 13937, 13939, 13942, 13944, 13946, 13948, 13950, 13953, 
-    13955, 13958, 13961, 13963, 13965, 13967, 13969, 13971, 13973, 13976, 
-    13979, 13982, 13984, 13986, 13989, 13991, 13993, 13995, 13998, 14000, 
-    14002, 14004, 14006, 14008, 14011, 14013, 14015, 14017, 14019, 14021, 
-    14023, 14026, 14029, 14031, 14034, 14036, 14039, 14041, 14043, 14045, 
-    14048, 14051, 14053, 14056, 14058, 14061, 14063, 14065, 14067, 14069, 
-    14071, 14073, 14076, 14079, 14082, 14085, 14087, 14089, 14091, 14093, 
-    14095, 14097, 14099, 14101, 14103, 14105, 14107, 14109, 14112, 14114, 
-    14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132, 14134, 
-    14136, 14139, 14142, 14145, 14147, 14149, 14151, 14153, 14156, 14158, 
-    14161, 14163, 14165, 14168, 14171, 14173, 14175, 14177, 14179, 14181, 
-    14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199, 14201, 
-    14203, 14205, 14207, 14209, 14212, 14214, 14216, 14218, 14220, 14222, 
-    14225, 14228, 14230, 14232, 14234, 14236, 14238, 14240, 14243, 14245, 
-    14247, 14249, 14251, 14254, 14257, 14259, 14261, 14263, 14266, 14268, 
-    14270, 14273, 14276, 14278, 14280, 14282, 14285, 14287, 14289, 14291, 
-    14293, 14295, 14297, 14299, 14302, 14304, 14306, 14308, 14311, 14313, 
-    14315, 14317, 14319, 14322, 14325, 14327, 14329, 14331, 14334, 14336, 
-    14339, 14341, 14343, 14345, 14348, 14350, 14352, 14354, 14356, 14358, 
-    14360, 14362, 14365, 14367, 14369, 14371, 14373, 14375, 14377, 14380, 
-    14382, 14385, 14388, 14391, 14393, 14395, 14397, 14399, 14401, 14403, 
-    14405, 14407, 0, 0, 
-};
-
-/* NFC pairs */
-#define COMP_SHIFT1 2
-#define COMP_SHIFT2 1
-static const unsigned short comp_index0[] = {
-    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 
-    5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 
-    15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 
-    23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34, 
-    0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42, 
-    43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51, 
-    52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0, 
-    0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71, 
-    0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0, 
-    0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84, 
-    85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0, 
-    0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0, 
-    0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108, 
-    109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117, 
-    0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124, 
-    125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0, 
-    0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0, 
-    0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0, 
-    151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 
-    156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0, 
-    164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168, 
-    0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 
-    172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0, 
-    0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 
-    0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186, 
-    0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0, 
-    190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 
-    0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0, 
-    0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203, 
-    204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 
-    208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 
-    0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, 
-    0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 
-    0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0, 
-    0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0, 
-    0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0, 
-    0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0, 
-    0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238, 
-    0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 
-    241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0, 
-    0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0, 
-    254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0, 
-    259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0, 
-    0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0, 
-    271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0, 
-    0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0, 
-    285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0, 
-    0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0, 
-    0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 
-    0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0, 
-    0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, 
-    0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0, 
-    0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308, 
-    0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 
-    311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 
-    0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, 
-    0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 
-    0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0, 
-    0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 
-    0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 
-    0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0, 
-    0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0, 
-    338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0, 
-    0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 
-    0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, 
-    0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0, 
-    0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353, 
-    0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, 
-    356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 
-    0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0, 
-    0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0, 
-    0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368, 
-    0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, 
-    372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0, 
-    0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379, 
-    0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0, 
-    382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0, 
-    0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, 
-    0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, 
-    0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0, 
-    0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, 
-    0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 
-    403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0, 
-    0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409, 
-    0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0, 
-    0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 
-    0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0, 
-    0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0, 
-    0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0, 
-    0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0, 
-    433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438, 
-    0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 
-    442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0, 
-    0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0, 
-    449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0, 
-    0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0, 
-    0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458, 
-    0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0, 
-    0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0, 
-    0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0, 
-    0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0, 
-    0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0, 
-    0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477, 
-    0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0, 
-    480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0, 
-    0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0, 
-    0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0, 
-    0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 
-    0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494, 
-    0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 
-    497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0, 
-    0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0, 
-    0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0, 
-    0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 
-    0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0, 
-    0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0, 
-    0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0, 
-    0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522, 
-    0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 
-    525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0, 
-    0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0, 
-    0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0, 
-    0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0, 
-    0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539, 
-    0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0, 
-    542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0, 
-    0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0, 
-    0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0, 
-    0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, 
-    0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556, 
-    0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0, 
-    559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0, 
-    0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564, 
-};
-
-static const unsigned short comp_index1[] = {
-    0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 
-    0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0, 
-    0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0, 
-    25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0, 
-    0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, 
-    0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56, 
-    57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0, 
-    65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71, 
-    72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80, 
-    0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0, 
-    92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0, 
-    100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108, 
-    0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115, 
-    116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0, 
-    0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133, 
-    134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0, 
-    143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153, 
-    0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160, 
-    0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0, 
-    169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0, 
-    0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0, 
-    188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198, 
-    199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0, 
-    0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0, 
-    0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0, 
-    0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0, 
-    0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0, 
-    237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0, 
-    0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0, 
-    0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261, 
-    262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0, 
-    0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277, 
-    278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0, 
-    287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292, 
-    0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0, 
-    0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304, 
-    0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0, 
-    0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0, 
-    0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0, 
-    322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0, 
-    0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0, 
-    335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0, 
-    342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0, 
-    0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 
-    352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0, 
-    358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364, 
-    365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0, 
-    0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0, 
-    0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381, 
-    0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387, 
-    0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0, 
-    0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0, 
-    399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0, 
-    0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0, 
-    410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0, 
-    0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0, 
-    422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 
-    0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433, 
-    0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0, 
-    439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0, 
-    0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0, 
-    454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0, 
-    0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469, 
-    0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477, 
-    0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0, 
-    482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0, 
-    487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493, 
-    0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0, 
-    498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0, 
-    0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0, 
-    0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0, 
-    0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0, 
-    0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0, 
-    0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0, 
-    0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538, 
-    0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0, 
-    0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0, 
-    0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0, 
-    0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0, 
-    559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0, 
-    564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569, 
-    0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0, 
-    0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0, 
-    580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0, 
-    585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0, 
-    590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0, 
-    0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0, 
-    600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605, 
-    0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0, 
-    610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0, 
-    0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620, 
-    0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0, 
-    626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0, 
-    0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0, 
-    0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0, 
-    641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646, 
-    0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0, 
-    652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0, 
-    0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0, 
-    662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667, 
-    0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0, 
-    0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0, 
-    0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0, 
-    0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0, 
-    688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693, 
-    0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0, 
-    698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703, 
-    0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0, 
-    709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0, 
-    0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0, 
-    719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0, 
-    724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0, 
-    0, 0, 0, 0, 0, 731, 
-};
-
-static const unsigned int comp_data[] = {
-    0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196, 
-    7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684, 
-    7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0, 
-    7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203, 
-    7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0, 
-    0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0, 
-    542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207, 
-    7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0, 
-    488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740, 
-    7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0, 
-    7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214, 
-    7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340, 
-    7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0, 
-    7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354, 
-    0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368, 
-    467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806, 
-    7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374, 
-    7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0, 
-    381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229, 
-    0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0, 
-    263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697, 
-    0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0, 
-    283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285, 
-    0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0, 
-    7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239, 
-    7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0, 
-    7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316, 
-    0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0, 
-    0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335, 
-    559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767, 
-    0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347, 
-    349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789, 
-    539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911, 
-    367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805, 
-    0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821, 
-    7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378, 
-    7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846, 
-    7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872, 
-    7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756, 
-    556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0, 
-    7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0, 
-    7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0, 
-    7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860, 
-    7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760, 
-    7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801, 
-    0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901, 
-    7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920, 
-    7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0, 
-    481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120, 
-    7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0, 
-    8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009, 
-    0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041, 
-    0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115, 
-    8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943, 
-    8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164, 
-    8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974, 
-    8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180, 
-    0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0, 
-    1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036, 
-    0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0, 
-    1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0, 
-    1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0, 
-    1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0, 
-    1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574, 
-    0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891, 
-    2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264, 
-    3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548, 
-    3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0, 
-    6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0, 
-    7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863, 
-    7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941, 
-    7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946, 
-    7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0, 
-    8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965, 
-    7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0, 
-    8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981, 
-    7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986, 
-    7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997, 
-    7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020, 
-    8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038, 
-    8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0, 
-    8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106, 
-    0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178, 
-    0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0, 
-    8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0, 
-    8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0, 
-    8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0, 
-    8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0, 
-    8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0, 
-    8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374, 
-    0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0, 
-    12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409, 
-    12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0, 
-    12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0, 
-    12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499, 
-    12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0, 
-    12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0, 
-    69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099, 
-};
-
diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh
index 1dd0b32..1ff79c9 100644
--- a/src/hb-unicode-emoji-table.hh
+++ b/src/hb-unicode-emoji-table.hh
@@ -7,13 +7,13 @@
  * on file with this header:
  *
  * # emoji-data.txt
- * # Date: 2018-02-07, 07:55:18 GMT
- * # © 2018 Unicode®, Inc.
+ * # Date: 2019-01-15, 12:10:05 GMT
+ * # © 2019 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 http://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Version: 11.0
+ * # Version: 12.0
  * #
  * # For documentation and usage, see http://www.unicode.org/reports/tr51
  */
@@ -23,88 +23,56 @@
 
 #include "hb-unicode.hh"
 
-
-static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] =
+static const uint8_t
+_hb_emoji_u8[448] =
 {
-  {0x00A9, 0x00A9},
-  {0x00AE, 0x00AE},
-  {0x203C, 0x203C},
-  {0x2049, 0x2049},
-  {0x2122, 0x2122},
-  {0x2139, 0x2139},
-  {0x2194, 0x2199},
-  {0x21A9, 0x21AA},
-  {0x231A, 0x231B},
-  {0x2328, 0x2328},
-  {0x2388, 0x2388},
-  {0x23CF, 0x23CF},
-  {0x23E9, 0x23F3},
-  {0x23F8, 0x23FA},
-  {0x24C2, 0x24C2},
-  {0x25AA, 0x25AB},
-  {0x25B6, 0x25B6},
-  {0x25C0, 0x25C0},
-  {0x25FB, 0x25FE},
-  {0x2600, 0x2605},
-  {0x2607, 0x2612},
-  {0x2614, 0x2685},
-  {0x2690, 0x2705},
-  {0x2708, 0x2712},
-  {0x2714, 0x2714},
-  {0x2716, 0x2716},
-  {0x271D, 0x271D},
-  {0x2721, 0x2721},
-  {0x2728, 0x2728},
-  {0x2733, 0x2734},
-  {0x2744, 0x2744},
-  {0x2747, 0x2747},
-  {0x274C, 0x274C},
-  {0x274E, 0x274E},
-  {0x2753, 0x2755},
-  {0x2757, 0x2757},
-  {0x2763, 0x2767},
-  {0x2795, 0x2797},
-  {0x27A1, 0x27A1},
-  {0x27B0, 0x27B0},
-  {0x27BF, 0x27BF},
-  {0x2934, 0x2935},
-  {0x2B05, 0x2B07},
-  {0x2B1B, 0x2B1C},
-  {0x2B50, 0x2B50},
-  {0x2B55, 0x2B55},
-  {0x3030, 0x3030},
-  {0x303D, 0x303D},
-  {0x3297, 0x3297},
-  {0x3299, 0x3299},
-  {0x1F000, 0x1F0FF},
-  {0x1F10D, 0x1F10F},
-  {0x1F12F, 0x1F12F},
-  {0x1F16C, 0x1F171},
-  {0x1F17E, 0x1F17F},
-  {0x1F18E, 0x1F18E},
-  {0x1F191, 0x1F19A},
-  {0x1F1AD, 0x1F1E5},
-  {0x1F201, 0x1F20F},
-  {0x1F21A, 0x1F21A},
-  {0x1F22F, 0x1F22F},
-  {0x1F232, 0x1F23A},
-  {0x1F23C, 0x1F23F},
-  {0x1F249, 0x1F3FA},
-  {0x1F400, 0x1F53D},
-  {0x1F546, 0x1F64F},
-  {0x1F680, 0x1F6FF},
-  {0x1F774, 0x1F77F},
-  {0x1F7D5, 0x1F7FF},
-  {0x1F80C, 0x1F80F},
-  {0x1F848, 0x1F84F},
-  {0x1F85A, 0x1F85F},
-  {0x1F888, 0x1F88F},
-  {0x1F8AE, 0x1F8FF},
-  {0x1F90C, 0x1F93A},
-  {0x1F93C, 0x1F945},
-  {0x1F947, 0x1FFFD},
+    0,  0,  0,  0, 33,  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,  0, 84,118,
+    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,  2,  0,  0,  3,
+    0,  0,  0,  0,  0,  0,  4,  5,  6,  7,  8,  7,  9, 10, 11,  0,
+    0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0,  0,
+    7,  7,  7, 14, 15, 16, 17, 18, 19, 20,  7,  7,  7,  7,  7, 21,
+    7,  7,  7,  7, 22, 23,  7,  7,  7, 24,  7, 14,  0, 25,  0, 26,
+   27, 28, 29, 14, 30, 31,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 22,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,  1,  0,  2,  0,  0,
+    0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,254,  7,  3,
+    0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0, 56,
+  159,255,243,255,255,255,255,255,255,255,255,255,255,255,255,255,
+   31,  0,255,255,255,255,255,255, 31,255,  3,  0,  0,  0,  8,  0,
+    0,  0, 24,  0,120,  0,  0,  0,  0,  0, 96,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 16,  0, 96,  0,  0,  8,  0,  0,  0,  0,
+  255,255,255,255,255,255,255,127,  0, 96,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,240,  1, 64,  0,  0,254,  3,  0,224,255,255,
+  255,255,255,255, 31,  0,  0,  0,254,127,  0,  0,  0,  0,252,115,
+    0,254,255,255,255,255,255,255,255,255,255,255,255,255,255,  3,
+  255,255,255,255,255,255,255, 31,192,255,255,255,255,255,255,255,
+  255,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,127,
+    0,  0,224,255,255,255,255,127,  0,112,  0,  0,  0,  0,  0,  0,
+    0,127,  0,124,  0,  0,  0,  0,  0,127,  0,  0,  0,192,255,255,
+    0,240,255,255,255,255,255,243,159,255,255,255,255,255,255,255,
 };
 
+static inline unsigned
+_hb_emoji_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline unsigned
+_hb_emoji_b1 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>3]>>((i&7u)<<0))&1u;
+}
+static inline uint_fast8_t
+_hb_emoji_is_Extended_Pictographic (unsigned u)
+{
+  return u<131069u?_hb_emoji_b1(192+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+}
+
+
 #endif /* HB_UNICODE_EMOJI_TABLE_HH */
 
 /* == End of generated table == */
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 4ac521d..08a4054 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -60,6 +60,7 @@
   return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 static unsigned int
 hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
 				hb_codepoint_t      unicode   HB_UNUSED,
@@ -67,6 +68,7 @@
 {
   return 1;
 }
+#endif
 
 static hb_unicode_general_category_t
 hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
@@ -113,6 +115,7 @@
 }
 
 
+#ifndef HB_DISABLE_DEPRECATED
 static unsigned int
 hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs     HB_UNUSED,
 					hb_codepoint_t      u          HB_UNUSED,
@@ -121,20 +124,23 @@
 {
   return 0;
 }
+#endif
 
-
-extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs ();
-extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs ();
-extern "C" hb_unicode_funcs_t *hb_ucdn_get_unicode_funcs ();
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB)
+#include "hb-glib.h"
+#endif
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+#include "hb-icu.h"
+#endif
 
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_default ()
 {
-#if defined(HAVE_UCDN)
-  return hb_ucdn_get_unicode_funcs ();
-#elif defined(HAVE_GLIB)
+#if !defined(HB_NO_UNICODE_FUNCS) && !defined(HB_NO_UCD)
+  return hb_ucd_get_unicode_funcs ();
+#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB)
   return hb_glib_get_unicode_funcs ();
-#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
   return hb_icu_get_unicode_funcs ();
 #else
 #define HB_UNICODE_FUNCS_NIL 1
@@ -144,7 +150,7 @@
 
 #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
 #error "Could not find any Unicode functions implementation, you have to provide your own"
-#error "Consider building hb-ucdn.c.  If you absolutely want to build without any, check the code."
+#error "Consider building hb-ucd.cc.  If you absolutely want to build without any, check the code."
 #endif
 
 /**
@@ -264,9 +270,9 @@
  **/
 hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
-			        hb_user_data_key_t *key,
-			        void *              data,
-			        hb_destroy_func_t   destroy,
+				hb_user_data_key_t *key,
+				void *              data,
+				hb_destroy_func_t   destroy,
 				hb_bool_t           replace)
 {
   return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
@@ -285,7 +291,7 @@
  **/
 void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-			        hb_user_data_key_t *key)
+				hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (ufuncs, key);
 }
@@ -425,6 +431,7 @@
   return ufuncs->decompose (ab, a, b);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_unicode_decompose_compatibility:
  * @ufuncs: Unicode functions.
@@ -445,8 +452,10 @@
 {
   return ufuncs->decompose_compatibility (u, decomposed);
 }
+#endif
 
 
+#ifndef HB_NO_OT_SHAPE
 /* See hb-unicode.hh for details. */
 const uint8_t
 _hb_modified_combining_class[256] =
@@ -559,19 +568,19 @@
   241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
   255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
 };
+#endif
 
 
 /*
  * Emoji
  */
+#ifndef HB_NO_EMOJI_SEQUENCES
 
 #include "hb-unicode-emoji-table.hh"
 
 bool
 _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp)
 {
-  return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table,
-		     ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table),
-		     sizeof (hb_unicode_range_t),
-		     hb_unicode_range_t::cmp);
+  return _hb_emoji_is_Extended_Pictographic (cp);
 }
+#endif
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index df0b91f..61b1b0b 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -200,15 +200,15 @@
 
 HB_EXTERN hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
-			        hb_user_data_key_t *key,
-			        void *              data,
-			        hb_destroy_func_t   destroy,
+				hb_user_data_key_t *key,
+				void *              data,
+				hb_destroy_func_t   destroy,
 				hb_bool_t           replace);
 
 
 HB_EXTERN void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
-			        hb_user_data_key_t *key);
+				hb_user_data_key_t *key);
 
 
 HB_EXTERN void
@@ -260,7 +260,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -276,7 +276,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -292,7 +292,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -308,7 +308,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -324,7 +324,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
@@ -340,7 +340,7 @@
  * @user_data:
  * @destroy:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh
index 82ebb10..0c355f1 100644
--- a/src/hb-unicode.hh
+++ b/src/hb-unicode.hh
@@ -42,19 +42,19 @@
 
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS \
   HB_UNICODE_FUNC_IMPLEMENT (combining_class) \
-  HB_UNICODE_FUNC_IMPLEMENT (eastasian_width) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (eastasian_width)) \
   HB_UNICODE_FUNC_IMPLEMENT (general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (mirroring) \
   HB_UNICODE_FUNC_IMPLEMENT (script) \
   HB_UNICODE_FUNC_IMPLEMENT (compose) \
   HB_UNICODE_FUNC_IMPLEMENT (decompose) \
-  HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility)) \
   /* ^--- Add new callbacks here */
 
 /* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
-  HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width)) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
@@ -89,7 +89,11 @@
   unsigned int decompose_compatibility (hb_codepoint_t  u,
 					hb_codepoint_t *decomposed)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    unsigned int ret  = 0;
+#else
     unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+#endif
     if (ret == 1 && u == decomposed[0]) {
       decomposed[0] = 0;
       return 0;
@@ -101,9 +105,6 @@
   unsigned int
   modified_combining_class (hb_codepoint_t u)
   {
-    /* XXX This hack belongs to the Myanmar shaper. */
-    if (unlikely (u == 0x1037u)) u = 0x103Au;
-
     /* XXX This hack belongs to the USE shaper (for Tai Tham):
      * Reorder SAKOT to ensure it comes after any tone marks. */
     if (unlikely (u == 0x1A60u)) return 254;
@@ -322,11 +323,11 @@
  *
  * Modify Telugu length marks (ccc=84, ccc=91).
  * These are the only matras in the main Indic scripts range that have
- * a non-zero ccc.  That makes them reorder with the Halant that is
- * ccc=9.  Just zero them, we don't need them in our Indic shaper.
+ * a non-zero ccc.  That makes them reorder with the Halant (ccc=9).
+ * Assign 5 and 6, which are otherwise unassigned.
  */
-#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */
-#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 5 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 6 /* ai length mark */
 
 /* Thai
  *
@@ -391,4 +392,7 @@
 _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp);
 
 
+extern "C" HB_INTERNAL hb_unicode_funcs_t *hb_ucd_get_unicode_funcs ();
+
+
 #endif /* HB_UNICODE_HH */
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 8d0473d..e93cf7f 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -25,12 +25,23 @@
  */
 
 #include "hb.hh"
+
+#ifdef HAVE_UNISCRIBE
+
+#ifdef HB_NO_OT_TAG
+#error "Cannot compile 'uniscribe' shaper with HB_NO_OT_TAG."
+#endif
+
 #include "hb-shaper-impl.hh"
 
 #include <windows.h>
 #include <usp10.h>
 #include <rpc.h>
 
+#ifndef E_NOT_SUFFICIENT_BUFFER
+#define E_NOT_SUFFICIENT_BUFFER HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)
+#endif
+
 #include "hb-uniscribe.h"
 
 #include "hb-open-file.hh"
@@ -47,13 +58,6 @@
  * Functions for using HarfBuzz with the Windows fonts.
  **/
 
-
-static inline uint16_t hb_uint16_swap (const uint16_t v)
-{ return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
-
-
 typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
   const WCHAR *pwcInChars,
   int cInChars,
@@ -215,9 +219,12 @@
     hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
     if (hinstLib)
     {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-function-type"
       this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
       this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
       this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
+#pragma GCC diagnostic pop
     }
     if (!this->ScriptItemizeOpenType ||
 	!this->ScriptShapeOpenType   ||
@@ -231,8 +238,9 @@
   }
 };
 
-
+#if HB_USE_ATEXIT
 static void free_static_uniscribe_shaper_funcs ();
+#endif
 
 static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t,
 									 hb_uniscribe_shaper_funcs_lazy_loader_t>
@@ -280,7 +288,7 @@
   OPENTYPE_FEATURE_RECORD rec;
   unsigned int order;
 
-  static int cmp (const void *pa, const void *pb) {
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
     const active_feature_t *a = (const active_feature_t *) pa;
     const active_feature_t *b = (const active_feature_t *) pb;
     return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
@@ -297,7 +305,7 @@
   bool start;
   active_feature_t feature;
 
-  static int cmp (const void *pa, const void *pb)
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
   {
     const feature_event_t *a = (const feature_event_t *) pa;
     const feature_event_t *b = (const feature_event_t *) pb;
@@ -377,8 +385,8 @@
   static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
 
   unsigned int name_table_length = OT::name::min_size +
-                                   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
-                                   name_str_len * 2; /* for name data in UTF16BE form */
+				   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
+				   name_str_len * 2; /* for name data in UTF16BE form */
   unsigned int padded_name_table_length = ((name_table_length + 3) & ~3);
   unsigned int name_table_offset = (length + 3) & ~3;
 
@@ -393,18 +401,18 @@
   memcpy(new_sfnt_data, orig_sfnt_data, length);
 
   OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
-  name.format.set (0);
-  name.count.set (ARRAY_LENGTH (name_IDs));
-  name.stringOffset.set (name.get_size ());
+  name.format = 0;
+  name.count = ARRAY_LENGTH (name_IDs);
+  name.stringOffset = name.get_size ();
   for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
   {
     OT::NameRecord &record = name.nameRecordZ[i];
-    record.platformID.set (3);
-    record.encodingID.set (1);
-    record.languageID.set (0x0409u); /* English */
-    record.nameID.set (name_IDs[i]);
-    record.length.set (name_str_len * 2);
-    record.offset.set (0);
+    record.platformID = 3;
+    record.encodingID = 1;
+    record.languageID = 0x0409u; /* English */
+    record.nameID = name_IDs[i];
+    record.length = name_str_len * 2;
+    record.offset = 0;
   }
 
   /* Copy string data from new_name, converting wchar_t to UTF16BE. */
@@ -428,8 +436,8 @@
     {
       OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
       record.checkSum.set_for_data (&name, padded_name_table_length);
-      record.offset.set (name_table_offset);
-      record.length.set (name_table_length);
+      record.offset = name_table_offset;
+      record.length = name_table_length;
     }
     else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
     {
@@ -652,35 +660,35 @@
     /* Scan events and save features for each range. */
     hb_vector_t<active_feature_t> active_features;
     unsigned int last_index = 0;
-    for (unsigned int i = 0; i < feature_events.len; i++)
+    for (unsigned int i = 0; i < feature_events.length; i++)
     {
       feature_event_t *event = &feature_events[i];
 
       if (event->index != last_index)
       {
-        /* Save a snapshot of active features and the range. */
+	/* Save a snapshot of active features and the range. */
 	range_record_t *range = range_records.push ();
 
-	unsigned int offset = feature_records.len;
+	unsigned int offset = feature_records.length;
 
 	active_features.qsort ();
-	for (unsigned int j = 0; j < active_features.len; j++)
+	for (unsigned int j = 0; j < active_features.length; j++)
 	{
-	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
+	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.length - 1].tagFeature)
 	  {
 	    feature_records.push (active_features[j].rec);
 	  }
 	  else
 	  {
 	    /* Overrides value for existing feature. */
-	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
+	    feature_records[feature_records.length - 1].lParameter = active_features[j].rec.lParameter;
 	  }
 	}
 
 	/* Will convert to pointer after all is ready, since feature_records.array
 	 * may move as we grow it. */
 	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
-	range->props.cotfRecords = feature_records.len - offset;
+	range->props.cotfRecords = feature_records.length - offset;
 	range->index_first = last_index;
 	range->index_last  = event->index - 1;
 
@@ -693,20 +701,20 @@
       }
       else
       {
-        active_feature_t *feature = active_features.find (&event->feature);
+	active_feature_t *feature = active_features.find (&event->feature);
 	if (feature)
-	  active_features.remove (feature - active_features.arrayZ ());
+	  active_features.remove (feature - active_features.arrayZ);
       }
     }
 
-    if (!range_records.len) /* No active feature found. */
+    if (!range_records.length) /* No active feature found. */
       num_features = 0;
 
     /* Fixup the pointers. */
-    for (unsigned int i = 0; i < range_records.len; i++)
+    for (unsigned int i = 0; i < range_records.length; i++)
     {
       range_record_t *range = &range_records[i];
-      range->props.potfRecords = feature_records + reinterpret_cast<uintptr_t> (range->props.potfRecords);
+      range->props.potfRecords = (OPENTYPE_FEATURE_RECORD *) feature_records + reinterpret_cast<uintptr_t> (range->props.potfRecords);
     }
   }
 
@@ -714,7 +722,7 @@
   HB_STMT_START { \
     DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
     return false; \
-  } HB_STMT_END;
+  } HB_STMT_END
 
   HRESULT hr;
 
@@ -725,12 +733,12 @@
 
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
-  { \
+  do { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     assert (_consumed <= scratch_size); \
     scratch += _consumed; \
     scratch_size -= _consumed; \
-  }
+  } while (0)
 
 #define utf16_index() var1.u32
 
@@ -817,7 +825,7 @@
 				     script_tags,
 				     &item_count);
   if (unlikely (FAILED (hr)))
-    FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
+    FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr);
 
 #undef MAX_ITEMS
 
@@ -853,8 +861,8 @@
 	  range--;
 	while (log_clusters[k] > range->index_last)
 	  range++;
-	if (!range_properties.len ||
-	    &range->props != range_properties[range_properties.len - 1])
+	if (!range_properties.length ||
+	    &range->props != range_properties[range_properties.length - 1])
 	{
 	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
 	  int *c = range_char_counts.push ();
@@ -869,7 +877,7 @@
 	}
 	else
 	{
-	  range_char_counts[range_char_counts.len - 1]++;
+	  range_char_counts[range_char_counts.length - 1]++;
 	}
 
 	last_range = range;
@@ -886,9 +894,9 @@
 				     &items[i].a,
 				     script_tags[i],
 				     language_tag,
-				     range_char_counts.arrayZ (),
-				     range_properties.arrayZ (),
-				     range_properties.len,
+				     range_char_counts.arrayZ,
+				     range_properties.arrayZ,
+				     range_properties.length,
 				     pchars + chars_offset,
 				     item_chars_len,
 				     glyphs_size - glyphs_offset,
@@ -916,7 +924,7 @@
     }
     if (unlikely (FAILED (hr)))
     {
-      FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
+      FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr);
     }
 
     for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
@@ -927,9 +935,9 @@
 				     &items[i].a,
 				     script_tags[i],
 				     language_tag,
-				     range_char_counts.arrayZ (),
-				     range_properties.arrayZ (),
-				     range_properties.len,
+				     range_char_counts.arrayZ,
+				     range_properties.arrayZ,
+				     range_properties.length,
 				     pchars + chars_offset,
 				     log_clusters + chars_offset,
 				     char_props + chars_offset,
@@ -942,7 +950,7 @@
 				     offsets + glyphs_offset,
 				     nullptr);
     if (unlikely (FAILED (hr)))
-      FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
+      FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr);
 
     if (DEBUG_ENABLED (UNISCRIBE))
       fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
@@ -961,13 +969,13 @@
 
   /* Calculate visual-clusters.  That's what we ship. */
   for (unsigned int i = 0; i < glyphs_len; i++)
-    vis_clusters[i] = -1;
+    vis_clusters[i] = (uint32_t) -1;
   for (unsigned int i = 0; i < buffer->len; i++) {
     uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
-    *p = MIN (*p, buffer->info[i].cluster);
+    *p = hb_min (*p, buffer->info[i].cluster);
   }
   for (unsigned int i = 1; i < glyphs_len; i++)
-    if (vis_clusters[i] == -1)
+    if (vis_clusters[i] == (uint32_t) -1)
       vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
@@ -1016,3 +1024,4 @@
 }
 
 
+#endif
diff --git a/src/hb-utf.hh b/src/hb-utf.hh
index 59ec75e..ff5712d 100644
--- a/src/hb-utf.hh
+++ b/src/hb-utf.hh
@@ -235,10 +235,10 @@
       hb_codepoint_t h = text[-1];
       if (likely (hb_in_range<hb_codepoint_t> (h, 0xD800u, 0xDBFFu)))
       {
-        /* High-surrogate in h */
-        *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
-        text--;
-        return text;
+	/* High-surrogate in h */
+	*unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+	text--;
+	return text;
       }
     }
 
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index d8e3f4e..7b150fb 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -29,124 +29,162 @@
 
 #include "hb.hh"
 #include "hb-array.hh"
+#include "hb-null.hh"
 
 
-template <typename Type, unsigned int PreallocedCount=8>
+template <typename Type>
 struct hb_vector_t
 {
-  typedef Type ItemType;
-  enum { item_size = hb_static_size (Type) };
+  typedef Type item_t;
+  static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_COPY_ASSIGN_TEMPLATE2 (hb_vector_t, Type, PreallocedCount);
   hb_vector_t ()  { init (); }
+  hb_vector_t (const hb_vector_t &o)
+  {
+    init ();
+    alloc (o.length);
+    hb_copy (o, *this);
+  }
+  hb_vector_t (hb_vector_t &&o)
+  {
+    allocated = o.allocated;
+    length = o.length;
+    arrayZ = o.arrayZ;
+    o.init ();
+  }
   ~hb_vector_t () { fini (); }
 
-  unsigned int len;
   private:
-  unsigned int allocated; /* == 0 means allocation failed. */
-  Type *arrayZ_;
-  Type static_array[PreallocedCount];
+  int allocated; /* == -1 means allocation failed. */
   public:
+  unsigned int length;
+  public:
+  Type *arrayZ;
 
   void init ()
   {
-    len = 0;
-    allocated = ARRAY_LENGTH (static_array);
-    arrayZ_ = nullptr;
+    allocated = length = 0;
+    arrayZ = nullptr;
   }
 
   void fini ()
   {
-    if (arrayZ_)
-      free (arrayZ_);
-    arrayZ_ = nullptr;
-    allocated = len = 0;
+    free (arrayZ);
+    init ();
   }
   void fini_deep ()
   {
-    Type *array = arrayZ();
-    unsigned int count = len;
+    unsigned int count = length;
     for (unsigned int i = 0; i < count; i++)
-      array[i].fini ();
+      arrayZ[i].fini ();
     fini ();
   }
 
-  Type * arrayZ ()             { return arrayZ_ ? arrayZ_ : static_array; }
-  const Type * arrayZ () const { return arrayZ_ ? arrayZ_ : static_array; }
+  void reset () { resize (0); }
+
+  hb_vector_t& operator = (const hb_vector_t &o)
+  {
+    reset ();
+    alloc (o.length);
+    hb_copy (o, *this);
+    return *this;
+  }
+  hb_vector_t& operator = (hb_vector_t &&o)
+  {
+    fini ();
+    allocated = o.allocated;
+    length = o.length;
+    arrayZ = o.arrayZ;
+    o.init ();
+    return *this;
+  }
+
+  hb_bytes_t as_bytes () const
+  { return hb_bytes_t ((const char *) arrayZ, length * item_size); }
+
+  bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
+  bool operator != (const hb_vector_t &o) const { return !(*this == o); }
+  uint32_t hash () const { return as_array ().hash (); }
 
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
-    if (unlikely (i >= len))
+    if (unlikely (i >= length))
       return Crap (Type);
-    return arrayZ()[i];
+    return arrayZ[i];
   }
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
-    if (unlikely (i >= len))
+    if (unlikely (i >= length))
       return Null(Type);
-    return arrayZ()[i];
+    return arrayZ[i];
   }
 
-  hb_array_t<Type> as_array ()
-  { return hb_array (arrayZ(), len); }
-  hb_array_t<const Type> as_array () const
-  { return hb_array (arrayZ(), len); }
+  Type& tail () { return (*this)[length - 1]; }
+  const Type& tail () const { return (*this)[length - 1]; }
+
+  explicit operator bool () const { return length; }
+  unsigned get_size () const { return length * item_size; }
+
+  /* Sink interface. */
+  template <typename T>
+  hb_vector_t& operator << (T&& v) { push (hb_forward<T> (v)); return *this; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, length); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
 
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
 
   hb_sorted_array_t<Type> as_sorted_array ()
-  { return hb_sorted_array (arrayZ(), len); }
+  { return hb_sorted_array (arrayZ, length); }
   hb_sorted_array_t<const Type> as_sorted_array () const
-  { return hb_sorted_array (arrayZ(), len); }
+  { return hb_sorted_array (arrayZ, length); }
 
-  hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int count)
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
+  template <typename T> explicit operator T * () { return arrayZ; }
+  template <typename T> explicit operator const T * () const { return arrayZ; }
 
-  template <typename T> explicit_operator T * () { return arrayZ(); }
-  template <typename T> explicit_operator const T * () const { return arrayZ(); }
-  operator hb_array_t<Type> ()             { return as_array (); }
-  operator hb_array_t<const Type> () const { return as_array (); }
-
-  Type * operator  + (unsigned int i) { return arrayZ() + i; }
-  const Type * operator  + (unsigned int i) const { return arrayZ() + i; }
+  Type * operator  + (unsigned int i) { return arrayZ + i; }
+  const Type * operator  + (unsigned int i) const { return arrayZ + i; }
 
   Type *push ()
   {
-    if (unlikely (!resize (len + 1)))
+    if (unlikely (!resize (length + 1)))
       return &Crap(Type);
-    return &arrayZ()[len - 1];
+    return &arrayZ[length - 1];
   }
-  Type *push (const Type& v)
+  template <typename T>
+  Type *push (T&& v)
   {
     Type *p = push ();
-    *p = v;
+    *p = hb_forward<T> (v);
     return p;
   }
 
-  bool in_error () const { return allocated == 0; }
+  bool in_error () const { return allocated < 0; }
 
-  /* Allocate for size but don't adjust len. */
+  /* Allocate for size but don't adjust length. */
   bool alloc (unsigned int size)
   {
-    if (unlikely (!allocated))
+    if (unlikely (allocated < 0))
       return false;
 
-    if (likely (size <= allocated))
+    if (likely (size <= (unsigned) allocated))
       return true;
 
     /* Reallocate */
@@ -156,27 +194,20 @@
       new_allocated += (new_allocated >> 1) + 8;
 
     Type *new_array = nullptr;
-
-    if (!arrayZ_)
-    {
-      new_array = (Type *) calloc (new_allocated, sizeof (Type));
-      if (new_array)
-        memcpy (new_array, static_array, len * sizeof (Type));
-    }
-    else
-    {
-      bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
-      if (likely (!overflows))
-        new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type));
-    }
+    bool overflows =
+      (int) new_allocated < 0 ||
+      (new_allocated < (unsigned) allocated) ||
+      hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
+    if (likely (!overflows))
+      new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
 
     if (unlikely (!new_array))
     {
-      allocated = 0;
+      allocated = -1;
       return false;
     }
 
-    arrayZ_ = new_array;
+    arrayZ = new_array;
     allocated = new_allocated;
 
     return true;
@@ -188,53 +219,50 @@
     if (!alloc (size))
       return false;
 
-    if (size > len)
-      memset (arrayZ() + len, 0, (size - len) * sizeof (*arrayZ()));
+    if (size > length)
+      memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
 
-    len = size;
+    length = size;
     return true;
   }
 
-  void pop ()
+  Type pop ()
   {
-    if (!len) return;
-    len--;
+    if (!length) return Null(Type);
+    return hb_move (arrayZ[--length]); /* Does this move actually work? */
   }
 
   void remove (unsigned int i)
   {
-    if (unlikely (i >= len))
+    if (unlikely (i >= length))
       return;
-    Type *array = arrayZ();
-    memmove (static_cast<void *> (&array[i]),
-	     static_cast<void *> (&array[i + 1]),
-	     (len - i - 1) * sizeof (Type));
-    len--;
+    memmove (static_cast<void *> (&arrayZ[i]),
+	     static_cast<void *> (&arrayZ[i + 1]),
+	     (length - i - 1) * sizeof (Type));
+    length--;
   }
 
   void shrink (int size_)
   {
     unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
-     if (size < len)
-       len = size;
+     if (size < length)
+       length = size;
   }
 
   template <typename T>
   Type *find (T v)
   {
-    Type *array = arrayZ();
-    for (unsigned int i = 0; i < len; i++)
-      if (array[i] == v)
-	return &array[i];
+    for (unsigned int i = 0; i < length; i++)
+      if (arrayZ[i] == v)
+	return &arrayZ[i];
     return nullptr;
   }
   template <typename T>
   const Type *find (T v) const
   {
-    const Type *array = arrayZ();
-    for (unsigned int i = 0; i < len; i++)
-      if (array[i] == v)
-	return &array[i];
+    for (unsigned int i = 0; i < length; i++)
+      if (arrayZ[i] == v)
+	return &arrayZ[i];
     return nullptr;
   }
 
@@ -249,19 +277,34 @@
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   { return as_array ().lsearch (x, not_found); }
+};
+
+template <typename Type>
+struct hb_sorted_vector_t : hb_vector_t<Type>
+{
+  hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->length); }
+  hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); }
+
+  /* Iterator. */
+  typedef hb_sorted_array_t<const Type> const_iter_t;
+  typedef hb_sorted_array_t<      Type>       iter_t;
+  const_iter_t  iter () const { return as_array (); }
+  const_iter_t citer () const { return as_array (); }
+	iter_t  iter ()       { return as_array (); }
+  operator       iter_t ()       { return iter (); }
+  operator const_iter_t () const { return iter (); }
 
   template <typename T>
   Type *bsearch (const T &x, Type *not_found = nullptr)
-  { return as_sorted_array ().bsearch (x, not_found); }
+  { return as_array ().bsearch (x, not_found); }
   template <typename T>
   const Type *bsearch (const T &x, const Type *not_found = nullptr) const
-  { return as_sorted_array ().bsearch (x, not_found); }
+  { return as_array ().bsearch (x, not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-		     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-		     unsigned int to_store = (unsigned int) -1) const
-  { return as_sorted_array ().bfind (x, i, not_found, to_store); }
+	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
+  { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
-
 #endif /* HB_VECTOR_HH */
diff --git a/src/hb-version.h b/src/hb-version.h
index 0c82d5b..a564e9f 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -37,10 +37,10 @@
 
 
 #define HB_VERSION_MAJOR 2
-#define HB_VERSION_MINOR 3
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MINOR 6
+#define HB_VERSION_MICRO 4
 
-#define HB_VERSION_STRING "2.3.0"
+#define HB_VERSION_STRING "2.6.4"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
diff --git a/src/hb-warning.cc b/src/hb-warning.cc
deleted file mode 100644
index 9fb4100..0000000
--- a/src/hb-warning.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright © 2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb.hh"
-
-#if defined(HB_ATOMIC_INT_NIL)
-#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
-#error "Check hb-atomic.hh for possible resolutions."
-#endif
-
-#if defined(HB_MUTEX_IMPL_NIL)
-#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
-#error "Check hb-mutex.hh for possible resolutions."
-#endif
diff --git a/src/hb.hh b/src/hb.hh
index a55e92d..fcbd330 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -29,9 +29,113 @@
 #ifndef HB_HH
 #define HB_HH
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
+
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
+#ifdef _MSC_VER
+#pragma warning( disable: 4068 ) /* Unknown pragma */
 #endif
+#if defined(__GNUC__) || defined(__clang__)
+/* Rules:
+ *
+ * - All pragmas are declared GCC even if they are clang ones.  Otherwise GCC
+ *   nags, even though we instruct it to ignore -Wunknown-pragmas. ¯\_(ツ)_/¯
+ *
+ * - Within each category, keep sorted.
+ *
+ * - Warnings whose scope can be expanded in future compiler versions shall
+ *   be declared as "warning".  Otherwise, either ignored or error.
+ */
+
+/* Setup.  Don't sort order within this category. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
+#pragma GCC diagnostic warning "-Wall"
+#pragma GCC diagnostic warning "-Wextra"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#pragma GCC diagnostic ignored "-Wunknown-warning-option"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
+//#pragma GCC diagnostic warning "-Weverything"
+#endif
+
+/* Error.  Should never happen. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
+#pragma GCC diagnostic error   "-Wc++11-narrowing"
+#pragma GCC diagnostic error   "-Wcast-align"
+#pragma GCC diagnostic error   "-Wcast-function-type"
+#pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
+#pragma GCC diagnostic error   "-Wembedded-directive"
+#pragma GCC diagnostic error   "-Wextra-semi-stmt"
+#pragma GCC diagnostic error   "-Wformat-security"
+#pragma GCC diagnostic error   "-Wimplicit-function-declaration"
+#pragma GCC diagnostic error   "-Winit-self"
+#pragma GCC diagnostic error   "-Winjected-class-name"
+#pragma GCC diagnostic error   "-Wmissing-braces"
+#pragma GCC diagnostic error   "-Wmissing-declarations"
+#pragma GCC diagnostic error   "-Wmissing-prototypes"
+#pragma GCC diagnostic error   "-Wnested-externs"
+#pragma GCC diagnostic error   "-Wold-style-definition"
+#pragma GCC diagnostic error   "-Wpointer-arith"
+#pragma GCC diagnostic error   "-Wredundant-decls"
+#pragma GCC diagnostic error   "-Wreorder"
+#pragma GCC diagnostic error   "-Wsign-compare"
+#pragma GCC diagnostic error   "-Wstrict-prototypes"
+#pragma GCC diagnostic error   "-Wstring-conversion"
+#pragma GCC diagnostic error   "-Wswitch-enum"
+#pragma GCC diagnostic error   "-Wtautological-overlap-compare"
+#pragma GCC diagnostic error   "-Wunneeded-internal-declaration"
+#pragma GCC diagnostic error   "-Wunused"
+#pragma GCC diagnostic error   "-Wunused-local-typedefs"
+#pragma GCC diagnostic error   "-Wunused-value"
+#pragma GCC diagnostic error   "-Wunused-variable"
+#pragma GCC diagnostic error   "-Wvla"
+#pragma GCC diagnostic error   "-Wwrite-strings"
+#endif
+
+/* Warning.  To be investigated if happens. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
+#pragma GCC diagnostic warning "-Wbuiltin-macro-redefined"
+#pragma GCC diagnostic warning "-Wdeprecated"
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
+#pragma GCC diagnostic warning "-Wdisabled-optimization"
+#pragma GCC diagnostic warning "-Wdouble-promotion"
+#pragma GCC diagnostic warning "-Wformat=2"
+#pragma GCC diagnostic warning "-Wignored-pragma-optimize"
+#pragma GCC diagnostic warning "-Wlogical-op"
+#pragma GCC diagnostic warning "-Wmaybe-uninitialized"
+#pragma GCC diagnostic warning "-Wmissing-format-attribute"
+#pragma GCC diagnostic warning "-Wundef"
+#endif
+
+/* Ignored currently, but should be fixed at some point. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
+#pragma GCC diagnostic ignored "-Wconversion"			// TODO fix
+#pragma GCC diagnostic ignored "-Wformat-signedness"		// TODO fix
+#pragma GCC diagnostic ignored "-Wshadow"			// TODO fix
+#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"	// TODO fix
+#pragma GCC diagnostic ignored "-Wunused-parameter"		// TODO fix
+#endif
+
+/* Ignored intentionally. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
+#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#pragma GCC diagnostic ignored "-Wformat-zero-length"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it
+#endif
+
+#endif
+#endif
+
+
+#include "hb-config.hh"
+
 
 /*
  * Following added based on what AC_USE_SYSTEM_EXTENSIONS adds to
@@ -59,10 +163,6 @@
 # define __EXTENSIONS__ 1
 #endif
 
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200809L
-#endif
-
 #if defined (_MSC_VER) && defined (HB_DLL_EXPORT)
 #define HB_EXTERN __declspec (dllexport) extern
 #endif
@@ -74,20 +174,25 @@
 #include "hb-aat.h"
 #define HB_AAT_H_IN
 
-#include "hb-aat.h"
-
+#include <limits.h>
 #include <math.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <assert.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
 
 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
+#ifdef __MINGW32_VERSION
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+#else
 #include <intrin.h>
 #endif
+#endif
 
 #define HB_PASTE1(a,b) a##b
 #define HB_PASTE(a,b) HB_PASTE1(a,b)
@@ -107,14 +212,6 @@
 #define calloc hb_calloc_impl
 #define realloc hb_realloc_impl
 #define free hb_free_impl
-
-#if defined(hb_memalign_impl)
-extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
-#define posix_memalign hb_memalign_impl
-#else
-#undef HAVE_POSIX_MEMALIGN
-#endif
-
 #endif
 
 
@@ -122,58 +219,6 @@
  * Compiler attributes
  */
 
-#if __cplusplus < 201103L
-
-#ifndef nullptr
-#define nullptr NULL
-#endif
-
-#ifndef constexpr
-#define constexpr const
-#endif
-
-#ifndef static_assert
-#define static_assert(e, msg) \
-	HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
-#endif // static_assert
-
-#ifdef __GNUC__
-#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
-#define thread_local __thread
-#endif
-#else
-#define thread_local
-#endif
-
-template <typename T>
-struct _hb_alignof
-{
-  struct s
-  {
-    char c;
-    T t;
-  };
-  static constexpr size_t value = offsetof (s, t);
-};
-#ifndef alignof
-#define alignof(x) (_hb_alignof<x>::value)
-#endif
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
-#ifndef explicit_operator
-#define explicit_operator operator
-#endif
-
-#else /* __cplusplus >= 201103L */
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
-#ifndef explicit_operator
-#define explicit_operator explicit operator
-#endif
-
-#endif /* __cplusplus < 201103L */
-
-
 #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
 #define likely(expr) (__builtin_expect (!!(expr), 1))
 #define unlikely(expr) (__builtin_expect (!!(expr), 0))
@@ -187,7 +232,7 @@
 #define __attribute__(x)
 #endif
 
-#if __GNUC__ >= 3
+#if defined(__GNUC__) && (__GNUC__ >= 3)
 #define HB_PURE_FUNC	__attribute__((pure))
 #define HB_CONST_FUNC	__attribute__((const))
 #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
@@ -196,7 +241,7 @@
 #define HB_CONST_FUNC
 #define HB_PRINTF_FUNC(format_idx, arg_idx)
 #endif
-#if __GNUC__ >= 4
+#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
 #define HB_UNUSED	__attribute__((unused))
 #elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
 #define HB_UNUSED __pragma(warning(suppress: 4100 4101))
@@ -219,7 +264,14 @@
 # endif
 #endif
 
-#if __GNUC__ >= 3
+/* https://github.com/harfbuzz/harfbuzz/issues/1651 */
+#if defined(__clang__) && __clang_major__ < 10
+#define static_const static
+#else
+#define static_const static const
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
 #define HB_FUNC __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
 #define HB_FUNC __FUNCSIG__
@@ -251,7 +303,7 @@
 #if defined(__clang__) && __cplusplus >= 201103L
    /* clang's fallthrough annotations are only available starting in C++11. */
 #  define HB_FALLTHROUGH [[clang::fallthrough]]
-#elif __GNUC__ >= 7
+#elif defined(__GNUC__) && (__GNUC__ >= 7)
    /* GNU fallthrough attribute is available from GCC7 */
 #  define HB_FALLTHROUGH __attribute__((fallthrough))
 #elif defined(_MSC_VER)
@@ -265,7 +317,8 @@
 #  define HB_FALLTHROUGH /* FALLTHROUGH */
 #endif
 
-#if defined(__clang__)
+/* https://github.com/harfbuzz/harfbuzz/issues/1852 */
+#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__)))
 /* Disable certain sanitizer errors. */
 /* https://github.com/harfbuzz/harfbuzz/issues/1247 */
 #define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
@@ -296,19 +349,35 @@
 #  if defined(_WIN32_WCE)
      /* Some things not defined on Windows CE. */
 #    define vsnprintf _vsnprintf
-#    define getenv(Name) nullptr
+#    ifndef HB_NO_GETENV
+#      define HB_NO_GETENV
+#    endif
 #    if _WIN32_WCE < 0x800
-#      define setlocale(Category, Locale) "C"
-static int errno = 0; /* Use something better? */
+#      define HB_NO_SETLOCALE
+#      define HB_NO_ERRNO
 #    endif
 #  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
-#    define getenv(Name) nullptr
+#    ifndef HB_NO_GETENV
+#      define HB_NO_GETENV
+#    endif
 #  endif
 #  if defined(_MSC_VER) && _MSC_VER < 1900
 #    define snprintf _snprintf
 #  endif
 #endif
 
+#ifdef HB_NO_GETENV
+#define getenv(Name) nullptr
+#endif
+
+#ifndef HB_NO_ERRNO
+#  include <errno.h>
+#else
+static int HB_UNUSED _hb_errno = 0;
+#  undef errno
+#  define errno _hb_errno
+#endif
+
 #if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT)
 /* atexit() is only safe to be called from shared libraries on certain
  * platforms.  Whitelist.
@@ -367,83 +436,13 @@
 static_assert ((sizeof (hb_mask_t) == 4), "");
 static_assert ((sizeof (hb_var_int_t) == 4), "");
 
-
-#if __cplusplus >= 201103L
-
-/* We only enable these with C++11 or later, since earlier language
- * does not allow structs with constructors in unions, and we need
- * those. */
-
-#define HB_NO_COPY_ASSIGN(TypeName) \
-  TypeName(const TypeName&); \
-  void operator=(const TypeName&)
-#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \
-  TypeName(const TypeName<T1, T2>&); \
-  void operator=(const TypeName<T1, T2>&)
-#define HB_NO_CREATE_COPY_ASSIGN(TypeName) \
-  TypeName(); \
-  TypeName(const TypeName&); \
-  void operator=(const TypeName&)
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) \
-  TypeName(); \
-  TypeName(const TypeName<T>&); \
-  void operator=(const TypeName<T>&)
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \
-  TypeName(); \
-  TypeName(const TypeName<T1, T2>&); \
-  void operator=(const TypeName<T1, T2>&)
-
-#else /* __cpluspplus >= 201103L */
-
-#define HB_NO_COPY_ASSIGN(TypeName) static_assert (true, "")
-#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN(TypeName) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "")
-
-#endif /* __cpluspplus >= 201103L */
-
-
-/*
- * Compiler-assisted vectorization parameters.
- */
-
-/*
- * Disable vectorization for now.  To correctly use them, we should
- * use posix_memalign() to allocate in hb_vector_t.  Otherwise, can
- * cause misaligned access.
- *
- * https://bugs.chromium.org/p/chromium/issues/detail?id=860184
- */
-#if !defined(HB_VECTOR_SIZE)
-#  define HB_VECTOR_SIZE 0
-#endif
-
-/* The `vector_size' attribute was introduced in gcc 3.1. */
-#if !defined(HB_VECTOR_SIZE)
-#  if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
-#    define HB_VECTOR_SIZE 128
-#  else
-#    define HB_VECTOR_SIZE 0
-#  endif
-#endif
-static_assert (0 == (HB_VECTOR_SIZE & (HB_VECTOR_SIZE - 1)), "HB_VECTOR_SIZE is not power of 2.");
-static_assert (0 == (HB_VECTOR_SIZE % 64), "HB_VECTOR_SIZE is not multiple of 64.");
-#if HB_VECTOR_SIZE
-typedef uint64_t hb_vector_size_impl_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
-#else
-typedef uint64_t hb_vector_size_impl_t;
-#endif
-
-
-/* HB_NDEBUG disables some sanity checks that are very safe to disable and
- * should be disabled in production systems.  If NDEBUG is defined, enable
- * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
- * light-weight) to be enabled, then HB_DEBUG can be defined to disable
- * the costlier checks. */
-#ifdef NDEBUG
-#define HB_NDEBUG 1
-#endif
+#define HB_DELETE_COPY_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
+#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
+  TypeName() = delete; \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
 
 
 /* Flags */
@@ -468,7 +467,8 @@
 	  static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
 	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
 	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
-	}
+	} \
+	static_assert (true, "")
 
 /* Useful for set-operations on small enums.
  * For example, for testing "x ∈ {x1, x2, x3}" use:
@@ -482,47 +482,112 @@
 
 
 /* Size signifying variable-sized array */
-#define VAR 1
+#ifndef HB_VAR_ARRAY
+#define HB_VAR_ARRAY 1
+#endif
 
-
-/* fallback for round() */
 static inline double
-_hb_round (double x)
+_hb_roundf (float x)
 {
-  if (x >= 0)
-    return floor (x + 0.5);
-  else
-    return ceil (x - 0.5);
+  return x >= 0 ? floor ((double) x + .5) : ceil ((double) x - .5);
 }
-#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
-#define round(x) _hb_round(x)
+#ifndef HAVE_ROUNDF
+#define roundf(x) _hb_roundf(x)
 #endif
 
+/* Endian swap, used in Windows related backends */
+static inline uint16_t hb_uint16_swap (const uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline uint32_t hb_uint32_swap (const uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
 
-/* fallback for posix_memalign() */
-static inline int
-_hb_memalign(void **memptr, size_t alignment, size_t size)
+/*
+ * Big-endian integers.  Here because fundamental.
+ */
+
+template <typename Type, int Bytes> struct BEInt;
+
+template <typename Type>
+struct BEInt<Type, 1>
 {
-  if (unlikely (0 != (alignment & (alignment - 1)) ||
-		!alignment ||
-		0 != (alignment & (sizeof (void *) - 1))))
-    return EINVAL;
-
-  char *p = (char *) malloc (size + alignment - 1);
-  if (unlikely (!p))
-    return ENOMEM;
-
-  size_t off = (size_t) p & (alignment - 1);
-  if (off)
-    p += alignment - off;
-
-  *memptr = (void *) p;
-
-  return 0;
-}
-#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN)
-#define posix_memalign _hb_memalign
+  public:
+  BEInt<Type, 1>& operator = (Type V)
+  {
+    v = V;
+    return *this;
+  }
+  operator Type () const { return v; }
+  private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+  public:
+  BEInt<Type, 2>& operator = (Type V)
+  {
+    v[0] = (V >>  8) & 0xFF;
+    v[1] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+    defined(__BYTE_ORDER) && \
+    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+    /* Spoon-feed the compiler a big-endian integer with alignment 1.
+     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+    struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+    return ((packed_uint16_t *) this)->v;
 #endif
+#endif
+    return (v[0] <<  8)
+	 + (v[1]      );
+  }
+  private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+  public:
+  BEInt<Type, 3>& operator = (Type V)
+  {
+    v[0] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[2] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+    return (v[0] << 16)
+	 + (v[1] <<  8)
+	 + (v[2]      );
+  }
+  private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+  public:
+  BEInt<Type, 4>& operator = (Type V)
+  {
+    v[0] = (V >> 24) & 0xFF;
+    v[1] = (V >> 16) & 0xFF;
+    v[2] = (V >>  8) & 0xFF;
+    v[3] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+    return (v[0] << 24)
+	 + (v[1] << 16)
+	 + (v[2] <<  8)
+	 + (v[3]      );
+  }
+  private: uint8_t v[4];
+};
 
 
 /*
@@ -533,25 +598,19 @@
 #define HB_SCRIPT_MYANMAR_ZAWGYI	((hb_script_t) HB_TAG ('Q','a','a','g'))
 
 
-/* Some really basic things everyone wants. */
-template <typename T> struct hb_remove_const { typedef T value; };
-template <typename T> struct hb_remove_const<const T> { typedef T value; };
-#define hb_remove_const(T) hb_remove_const<T>::value
-template <typename T> struct hb_remove_reference { typedef T value; };
-template <typename T> struct hb_remove_reference<T &> { typedef T value; };
-#define hb_remove_reference(T) hb_remove_reference<T>::value
-template <typename T> struct hb_remove_pointer { typedef T value; };
-template <typename T> struct hb_remove_pointer<T *> { typedef T value; };
-#define hb_remove_pointer(T) hb_remove_pointer<T>::value
-
-
-/* Headers we include for everyone.  Keep sorted.  They express dependency amongst
- * themselves, but no other file should include them.*/
-#include "hb-atomic.hh"
-#include "hb-debug.hh"
-#include "hb-dsalgs.hh"
+/* Headers we include for everyone.  Keep topologically sorted by dependency.
+ * They express dependency amongst themselves, but no other file should include
+ * them directly.*/
+#include "hb-meta.hh"
 #include "hb-mutex.hh"
-#include "hb-null.hh"
-#include "hb-object.hh"
+#include "hb-number.hh"
+#include "hb-atomic.hh"	// Requires: hb-meta
+#include "hb-null.hh"	// Requires: hb-meta
+#include "hb-algs.hh"	// Requires: hb-meta hb-null hb-number
+#include "hb-iter.hh"	// Requires: hb-algs hb-meta
+#include "hb-debug.hh"	// Requires: hb-algs hb-atomic
+#include "hb-array.hh"	// Requires: hb-algs hb-iter hb-null
+#include "hb-vector.hh"	// Requires: hb-array hb-null
+#include "hb-object.hh"	// Requires: hb-atomic hb-mutex hb-vector
 
 #endif /* HB_HH */
diff --git a/src/main.cc b/src/main.cc
index 490b76e..983cb55 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -38,10 +38,15 @@
 
 using namespace OT;
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
-  if (argc != 2) {
+  if (argc != 2)
+  {
     fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
     exit (1);
   }
@@ -61,7 +66,8 @@
   const OpenTypeFontFile& ot = *sanitized;
 
 
-  switch (ot.get_tag ()) {
+  switch (ot.get_tag ())
+  {
   case OpenTypeFontFile::TrueTypeTag:
     printf ("OpenType font with TrueType outlines\n");
     break;
@@ -87,20 +93,23 @@
 
   int num_fonts = ot.get_face_count ();
   printf ("%d font(s) found in file\n", num_fonts);
-  for (int n_font = 0; n_font < num_fonts; n_font++) {
+  for (int n_font = 0; n_font < num_fonts; n_font++)
+  {
     const OpenTypeFontFace &font = ot.get_face (n_font);
     printf ("Font %d of %d:\n", n_font, num_fonts);
 
     int num_tables = font.get_table_count ();
     printf ("  %d table(s) found in font\n", num_tables);
-    for (int n_table = 0; n_table < num_tables; n_table++) {
+    for (int n_table = 0; n_table < num_tables; n_table++)
+    {
       const OpenTypeTable &table = font.get_table (n_table);
       printf ("  Table %2d of %2d: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
 	      (const char *) table.tag,
 	      (unsigned int) table.offset,
 	      (unsigned int) table.length);
 
-      switch (table.tag) {
+      switch (table.tag)
+      {
 
       case HB_OT_TAG_GSUB:
       case HB_OT_TAG_GPOS:
@@ -110,10 +119,11 @@
 
 	int num_scripts = g.get_script_count ();
 	printf ("    %d script(s) found in table\n", num_scripts);
-	for (int n_script = 0; n_script < num_scripts; n_script++) {
+	for (int n_script = 0; n_script < num_scripts; n_script++)
+	{
 	  const Script &script = g.get_script (n_script);
 	  printf ("    Script %2d of %2d: %.4s\n", n_script, num_scripts,
-	          (const char *)g.get_script_tag(n_script));
+		  (const char *)g.get_script_tag(n_script));
 
 	  if (!script.has_default_lang_sys())
 	    printf ("      No default language system\n");
@@ -136,34 +146,37 @@
 
 	    int num_features = langsys.get_feature_count ();
 	    printf ("        %d feature(s) found in language system\n", num_features);
-	    for (int n_feature = 0; n_feature < num_features; n_feature++) {
+	    for (int n_feature = 0; n_feature < num_features; n_feature++)
+	    {
 	      printf ("        Feature index %2d of %2d: %d\n", n_feature, num_features,
-	              langsys.get_feature_index (n_feature));
+		      langsys.get_feature_index (n_feature));
 	    }
 	  }
 	}
 
 	int num_features = g.get_feature_count ();
 	printf ("    %d feature(s) found in table\n", num_features);
-	for (int n_feature = 0; n_feature < num_features; n_feature++) {
+	for (int n_feature = 0; n_feature < num_features; n_feature++)
+	{
 	  const Feature &feature = g.get_feature (n_feature);
 	  int num_lookups = feature.get_lookup_count ();
 	  printf ("    Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
-	          HB_UNTAG(g.get_feature_tag(n_feature)));
+		  HB_UNTAG(g.get_feature_tag(n_feature)));
 
 	  printf ("        %d lookup(s) found in feature\n", num_lookups);
 	  for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
 	    printf ("        Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
-	            feature.get_lookup_index (n_lookup));
+		    feature.get_lookup_index (n_lookup));
 	  }
 	}
 
 	int num_lookups = g.get_lookup_count ();
 	printf ("    %d lookup(s) found in table\n", num_lookups);
-	for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
+	for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++)
+	{
 	  const Lookup &lookup = g.get_lookup (n_lookup);
 	  printf ("    Lookup %2d of %2d: type %d, props 0x%04X\n", n_lookup, num_lookups,
-	          lookup.get_type(), lookup.get_props());
+		  lookup.get_type(), lookup.get_props());
 	}
 
 	}
diff --git a/src/test-algs.cc b/src/test-algs.cc
new file mode 100644
index 0000000..f8b8ff6
--- /dev/null
+++ b/src/test-algs.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+#include "hb-algs.hh"
+
+
+static char *
+test_func (int a, char **b)
+{
+  return b ? b[a] : nullptr;
+}
+
+struct A
+{
+  void a () {}
+};
+
+int
+main (int argc, char **argv)
+{
+  int i = 1;
+  auto p = hb_pair (1, i);
+
+  p.second = 2;
+  assert (i == 2);
+
+  const int c = 3;
+  auto pc = hb_pair (1, c);
+  assert (pc.second == 3);
+
+  auto q = p;
+  assert (&q != &p);
+  q.second = 4;
+  assert (i == 4);
+
+  hb_invoke (test_func, 0, nullptr);
+
+  A a;
+  hb_invoke (&A::a, a);
+
+  assert (1 == hb_min (8, 1));
+  assert (8 == hb_max (8, 1));
+
+  int x = 1, y = 2;
+  hb_min (x, 3);
+  hb_min (3, x);
+  hb_min (x, 4 + 3);
+  int &z = hb_min (x, y);
+  z = 3;
+  assert (x == 3);
+
+  hb_pair_t<const int*, int> xp = hb_pair_t<int *, long> (nullptr, 0);
+  xp = hb_pair_t<int *, double> (nullptr, 1);
+  xp = hb_pair_t<const int*, int> (nullptr, 1);
+
+  assert (3 == hb_partial (hb_min, 3) (4));
+  assert (3 == hb_partial<1> (hb_min, 4) (3));
+
+  auto M0 = hb_partial<2> (hb_max, 0);
+  assert (M0 (-2) == 0);
+  assert (M0 (+2) == 2);
+
+  assert (hb_add (2) (5) == 7);
+  assert (hb_add (5) (2) == 7);
+
+  x = 1;
+  assert (++hb_inc (x) == 3);
+  assert (x == 3);
+
+  return 0;
+}
diff --git a/src/test-bimap.cc b/src/test-bimap.cc
new file mode 100644
index 0000000..1253d0c
--- /dev/null
+++ b/src/test-bimap.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2019  Adobe, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb.hh"
+#include "hb-bimap.hh"
+
+int
+main (int argc, char **argv)
+{
+  hb_bimap_t	bm;
+
+  assert (bm.is_empty () == true);
+  bm.set (1, 4);
+  bm.set (2, 5);
+  bm.set (3, 6);
+  assert (bm.get_population () == 3);
+  assert (bm.has (1) == true);
+  assert (bm.has (4) == false);
+  assert (bm[2] == 5);
+  assert (bm.backward (6) == 3);
+  bm.del (1);
+  assert (bm.has (1) == false);
+  assert (bm.has (3) == true);
+  bm.clear ();
+  assert (bm.get_population () == 0);
+
+  hb_inc_bimap_t  ibm;
+
+  assert (ibm.add (13) == 0);
+  assert (ibm.add (8) == 1);
+  assert (ibm.add (10) == 2);
+  assert (ibm.add (8) == 1);
+  assert (ibm.add (7) == 3);
+  assert (ibm.get_population () == 4);
+  assert (ibm[7] == 3);
+
+  ibm.sort ();
+  assert (ibm.get_population () == 4);
+  assert (ibm[7] == 0);
+  assert (ibm[13] == 3);
+
+  ibm.identity (3);
+  assert (ibm.get_population () == 3);
+  assert (ibm[0] == 0);
+  assert (ibm[1] == 1);
+  assert (ibm[2] == 2);
+  assert (ibm.backward (0) == 0);
+  assert (ibm.backward (1) == 1);
+  assert (ibm.backward (2) == 2);
+  assert (ibm.has (4) == false);
+
+  return 0;
+}
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index a91f4f7..6393f0b 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -34,9 +34,17 @@
 
 #include <stdio.h>
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
+  bool ret = true;
+
+#ifndef HB_NO_BUFFER_SERIALIZE
+
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file\n", argv[0]);
     exit (1);
@@ -59,7 +67,6 @@
   hb_buffer_t *buf;
   buf = hb_buffer_create ();
 
-  bool ret = true;
   char line[BUFSIZ], out[BUFSIZ];
   while (fgets (line, sizeof(line), stdin) != nullptr)
   {
@@ -85,5 +92,7 @@
 
   hb_font_destroy (font);
 
+#endif
+
   return !ret;
 }
diff --git a/src/test-size-params.cc b/src/test-gpos-size-params.cc
similarity index 86%
rename from src/test-size-params.cc
rename to src/test-gpos-size-params.cc
index 12eec61..ad10ed4 100644
--- a/src/test-size-params.cc
+++ b/src/test-gpos-size-params.cc
@@ -31,6 +31,10 @@
 
 #include <stdio.h>
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -45,10 +49,15 @@
   hb_blob_destroy (blob);
   blob = nullptr;
 
-  unsigned int p[5];
-  bool ret = hb_ot_layout_get_size_params (face, p, p+1, (p+2), p+3, p+4);
+  bool ret = true;
 
+#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
+  unsigned int p[5];
+  ret = hb_ot_layout_get_size_params (face, p, p+1, (p+2), p+3, p+4);
   printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.);
+#endif
+
+  hb_face_destroy (face);
 
   return !ret;
 }
diff --git a/src/test-would-substitute.cc b/src/test-gsub-would-substitute.cc
similarity index 95%
rename from src/test-would-substitute.cc
rename to src/test-gsub-would-substitute.cc
index 268f7db..7ad9e08 100644
--- a/src/test-would-substitute.cc
+++ b/src/test-gsub-would-substitute.cc
@@ -35,6 +35,10 @@
 #include "hb-ft.h"
 #endif
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
diff --git a/src/test-iter.cc b/src/test-iter.cc
new file mode 100644
index 0000000..9c83171
--- /dev/null
+++ b/src/test-iter.cc
@@ -0,0 +1,286 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+#include "hb-iter.hh"
+
+#include "hb-array.hh"
+#include "hb-set.hh"
+#include "hb-ot-layout-common.hh"
+
+
+template <typename T>
+struct array_iter_t : hb_iter_with_fallback_t<array_iter_t<T>, T&>
+{
+  array_iter_t (hb_array_t<T> arr_) : arr (arr_) {}
+
+  typedef T& __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  T& __item_at__ (unsigned i) const { return arr[i]; }
+  void __forward__ (unsigned n) { arr += n; }
+  void __rewind__ (unsigned n) { arr -= n; }
+  unsigned __len__ () const { return arr.length; }
+  bool operator != (const array_iter_t& o) { return arr != o.arr; }
+
+  private:
+  hb_array_t<T> arr;
+};
+
+template <typename T>
+struct some_array_t
+{
+  some_array_t (hb_array_t<T> arr_) : arr (arr_) {}
+
+  typedef array_iter_t<T> iter_t;
+  array_iter_t<T> iter () { return array_iter_t<T> (arr); }
+  operator array_iter_t<T> () { return iter (); }
+  operator hb_iter_t<array_iter_t<T>> () { return iter (); }
+
+  private:
+  hb_array_t<T> arr;
+};
+
+
+template <typename Iter,
+	  hb_requires (hb_is_iterator (Iter))>
+static void
+test_iterator_non_default_constructable (Iter it)
+{
+  /* Iterate over a copy of it. */
+  for (auto c = it.iter (); c; c++)
+    *c;
+
+  /* Same. */
+  for (auto c = +it; c; c++)
+    *c;
+
+  /* Range-based for over a copy. */
+  for (auto _ : +it)
+    (void) _;
+
+  it += it.len ();
+  it = it + 10;
+  it = 10 + it;
+
+  assert (*it == it[0]);
+
+  static_assert (true || it.is_random_access_iterator, "");
+  static_assert (true || it.is_sorted_iterator, "");
+}
+
+template <typename Iter,
+	  hb_requires (hb_is_iterator (Iter))>
+static void
+test_iterator (Iter it)
+{
+  Iter default_constructed;
+  assert (!default_constructed);
+
+  test_iterator_non_default_constructable (it);
+}
+
+template <typename Iterable,
+	  hb_requires (hb_is_iterable (Iterable))>
+static void
+test_iterable (const Iterable &lst = Null(Iterable))
+{
+  for (auto _ : lst)
+    (void) _;
+
+  // Test that can take iterator from.
+  test_iterator (lst.iter ());
+}
+
+int
+main (int argc, char **argv)
+{
+  const int src[10] = {};
+  int dst[20];
+  hb_vector_t<int> v;
+
+  array_iter_t<const int> s (src); /* Implicit conversion from static array. */
+  array_iter_t<const int> s2 (v); /* Implicit conversion from vector. */
+  array_iter_t<int> t (dst);
+
+  static_assert (array_iter_t<int>::is_random_access_iterator, "");
+
+  some_array_t<const int> a (src);
+
+  s2 = s;
+
+  hb_iter (src);
+  hb_iter (src, 2);
+
+  hb_fill (t, 42);
+  hb_copy (s, t);
+  hb_copy (a.iter (), t);
+
+  test_iterable (v);
+  hb_set_t st;
+  st << 1 << 15 << 43;
+  test_iterable (st);
+  hb_sorted_array_t<int> sa;
+  (void) static_cast<hb_iter_t<hb_sorted_array_t<int>, hb_sorted_array_t<int>::item_t>&> (sa);
+  (void) static_cast<hb_iter_t<hb_sorted_array_t<int>, hb_sorted_array_t<int>::__item_t__>&> (sa);
+  (void) static_cast<hb_iter_t<hb_sorted_array_t<int>, int&>&>(sa);
+  (void) static_cast<hb_iter_t<hb_sorted_array_t<int>>&>(sa);
+  (void) static_cast<hb_iter_t<hb_array_t<int>, int&>&> (sa);
+  test_iterable (sa);
+
+  test_iterable<hb_array_t<int>> ();
+  test_iterable<hb_sorted_array_t<const int>> ();
+  test_iterable<hb_vector_t<float>> ();
+  test_iterable<hb_set_t> ();
+  test_iterable<OT::Coverage> ();
+
+  test_iterator (hb_zip (st, v));
+  test_iterator_non_default_constructable (hb_enumerate (st));
+  test_iterator_non_default_constructable (hb_enumerate (st, -5));
+  test_iterator_non_default_constructable (hb_enumerate (hb_iter (st)));
+  test_iterator_non_default_constructable (hb_enumerate (hb_iter (st) + 1));
+  test_iterator_non_default_constructable (hb_iter (st) | hb_filter ());
+  test_iterator_non_default_constructable (hb_iter (st) | hb_map (hb_lidentity));
+
+  assert (true == hb_all (st));
+  assert (false == hb_all (st, 42u));
+  assert (true == hb_any (st));
+  assert (false == hb_any (st, 14u));
+  assert (true == hb_any (st, 14u, [] (unsigned _) { return _ - 1u; }));
+  assert (true == hb_any (st, [] (unsigned _) { return _ == 15u; }));
+  assert (true == hb_any (st, 15u));
+  assert (false == hb_none (st));
+  assert (false == hb_none (st, 15u));
+  assert (true == hb_none (st, 17u));
+
+  hb_array_t<hb_vector_t<int>> pa;
+  pa->as_array ();
+
+  hb_map_t m;
+
+  hb_iter (st);
+  hb_iter (&st);
+
+  + hb_iter (src)
+  | hb_map (m)
+  | hb_map (&m)
+  | hb_filter ()
+  | hb_filter (st)
+  | hb_filter (&st)
+  | hb_filter (hb_bool)
+  | hb_filter (hb_bool, hb_identity)
+  | hb_sink (st)
+  ;
+
+  + hb_iter (src)
+  | hb_sink (hb_array (dst))
+  ;
+
+  + hb_iter (src)
+  | hb_apply (&st)
+  ;
+
+  + hb_iter (src)
+  | hb_map ([] (int i) { return 1; })
+  | hb_reduce ([=] (int acc, int value) { return acc; }, 2)
+  ;
+
+  using map_pair_t = hb_item_type<hb_map_t>;
+  + hb_iter (m)
+  | hb_map ([] (map_pair_t p) { return p.first * p.second; })
+  ;
+
+  m.keys ();
+  using map_key_t = decltype (*m.keys());
+  + hb_iter (m.keys ())
+  | hb_filter ([] (map_key_t k) { return k < 42; })
+  | hb_drain
+  ;
+
+  m.values ();
+  using map_value_t = decltype (*m.values());
+  + hb_iter (m.values ())
+  | hb_filter ([] (map_value_t k) { return k < 42; })
+  | hb_drain
+  ;
+
+  unsigned int temp1 = 10;
+  unsigned int temp2 = 0;
+  hb_map_t *result =
+  + hb_iter (src)
+  | hb_map ([&] (int i) -> hb_set_t *
+	    {
+	      hb_set_t *set = hb_set_create ();
+	      for (unsigned int i = 0; i < temp1; ++i)
+		hb_set_add (set, i);
+	      temp1++;
+	      return set;
+	    })
+  | hb_reduce ([&] (hb_map_t *acc, hb_set_t *value) -> hb_map_t *
+	       {
+		 hb_map_set (acc, temp2++, hb_set_get_population (value));
+		 /* This is not a memory managed language, take care! */
+		 hb_set_destroy (value);
+		 return acc;
+	       }, hb_map_create ())
+  ;
+  /* The result should be something like 0->10, 1->11, ..., 9->19 */
+  assert (hb_map_get (result, 9) == 19);
+
+  unsigned int temp3 = 0;
+  + hb_iter(src)
+  | hb_map([&] (int i) { return ++temp3; })
+  | hb_reduce([&] (float acc, int value) { return acc + value; }, 0)
+  ;
+  hb_map_destroy (result);
+
+  + hb_iter (src)
+  | hb_drain
+  ;
+
+  t << 1;
+  long vl;
+  s >> vl;
+
+  hb_iota ();
+  hb_iota (3);
+  hb_iota (3, 2);
+  assert ((&vl) + 1 == *++hb_iota (&vl, hb_inc));
+  hb_range ();
+  hb_repeat (7u);
+  hb_repeat (nullptr);
+  hb_repeat (vl) | hb_chop (3);
+  assert (hb_len (hb_range (10) | hb_take (3)) == 3);
+  assert (hb_range (9).len () == 9);
+  assert (hb_range (2, 9).len () == 7);
+  assert (hb_range (2, 9, 3).len () == 3);
+  assert (hb_range (2, 8, 3).len () == 2);
+  assert (hb_range (2, 7, 3).len () == 2);
+  assert (hb_range (-2, -9, -3).len () == 3);
+  assert (hb_range (-2, -8, -3).len () == 2);
+  assert (hb_range (-2, -7, -3).len () == 2);
+
+  return 0;
+}
diff --git a/src/test-meta.cc b/src/test-meta.cc
new file mode 100644
index 0000000..0b6e02c
--- /dev/null
+++ b/src/test-meta.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+#include "hb-meta.hh"
+
+#include <type_traits>
+
+int
+main (int argc, char **argv)
+{
+  static_assert (hb_is_convertible (void, void), "");
+  static_assert (hb_is_convertible (void, const void), "");
+  static_assert (hb_is_convertible (const void, void), "");
+
+  static_assert (hb_is_convertible (int,  int), "");
+  static_assert (hb_is_convertible (char, int), "");
+  static_assert (hb_is_convertible (long, int), "");
+
+  static_assert (hb_is_convertible (int, int), "");
+
+  static_assert (hb_is_convertible (const int, int), "");
+  static_assert (hb_is_convertible (int, const int), "");
+  static_assert (hb_is_convertible (const int, const int), "");
+
+  static_assert (hb_is_convertible (int&, int), "");
+  static_assert (!hb_is_convertible (int, int&), "");
+
+  static_assert (hb_is_convertible (int, const int&), "");
+  static_assert (!hb_is_convertible (const int, int&), "");
+  static_assert (hb_is_convertible (const int, const int&), "");
+  static_assert (hb_is_convertible (int&, const int), "");
+  static_assert (hb_is_convertible (const int&, int), "");
+  static_assert (hb_is_convertible (const int&, const int), "");
+  static_assert (hb_is_convertible (const int&, const int), "");
+
+  struct X {};
+  struct Y : X {};
+
+  static_assert (hb_is_convertible (const X &, const X), "");
+  static_assert (hb_is_convertible (X &, const X), "");
+  static_assert (hb_is_convertible (X &, const X &), "");
+  static_assert (hb_is_convertible (X, const X &), "");
+  static_assert (hb_is_convertible (const X, const X &), "");
+  static_assert (!hb_is_convertible (const X, X &), "");
+  static_assert (!hb_is_convertible (X, X &), "");
+  static_assert (hb_is_convertible (X &, X &), "");
+
+  static_assert (hb_is_convertible (int&, long), "");
+  static_assert (!hb_is_convertible (int&, long&), "");
+
+  static_assert (hb_is_convertible (int *, int *), "");
+  static_assert (hb_is_convertible (int *, const int *), "");
+  static_assert (!hb_is_convertible (const int *, int *), "");
+  static_assert (!hb_is_convertible (int *, long *), "");
+  static_assert (hb_is_convertible (int *, void *), "");
+  static_assert (!hb_is_convertible (void *, int *), "");
+
+  static_assert (hb_is_base_of (void, void), "");
+  static_assert (hb_is_base_of (void, int), "");
+  static_assert (!hb_is_base_of (int, void), "");
+
+  static_assert (hb_is_base_of (int, int), "");
+  static_assert (hb_is_base_of (const int, int), "");
+  static_assert (hb_is_base_of (int, const int), "");
+
+  static_assert (hb_is_base_of (X, X), "");
+  static_assert (hb_is_base_of (X, Y), "");
+  static_assert (hb_is_base_of (const X, Y), "");
+  static_assert (hb_is_base_of (X, const Y), "");
+  static_assert (!hb_is_base_of (Y, X), "");
+
+  static_assert (hb_is_constructible (int), "");
+  static_assert (hb_is_constructible (int, int), "");
+  static_assert (hb_is_constructible (int, char), "");
+  static_assert (hb_is_constructible (int, long), "");
+  static_assert (!hb_is_constructible (int, X), "");
+  static_assert (!hb_is_constructible (int, int, int), "");
+  static_assert (hb_is_constructible (X), "");
+  static_assert (!hb_is_constructible (X, int), "");
+  static_assert (hb_is_constructible (X, X), "");
+  static_assert (!hb_is_constructible (X, X, X), "");
+  static_assert (hb_is_constructible (X, Y), "");
+  static_assert (!hb_is_constructible (Y, X), "");
+
+  static_assert (hb_is_trivially_default_constructible (X), "");
+  static_assert (hb_is_trivially_default_constructible (Y), "");
+  static_assert (hb_is_trivially_copy_constructible (X), "");
+  static_assert (hb_is_trivially_copy_constructible (Y), "");
+  static_assert (hb_is_trivially_move_constructible (X), "");
+  static_assert (hb_is_trivially_move_constructible (Y), "");
+  static_assert (hb_is_trivially_destructible (Y), "");
+
+  static_assert (hb_is_trivially_copyable (int), "");
+  static_assert (hb_is_trivially_copyable (X), "");
+  static_assert (hb_is_trivially_copyable (Y), "");
+
+  static_assert (hb_is_trivial (int), "");
+  static_assert (hb_is_trivial (X), "");
+  static_assert (hb_is_trivial (Y), "");
+
+  /* TODO Add more meaningful tests. */
+
+  return 0;
+}
diff --git a/src/test-number.cc b/src/test-number.cc
new file mode 100644
index 0000000..3591b13
--- /dev/null
+++ b/src/test-number.cc
@@ -0,0 +1,253 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include "hb.hh"
+#include "hb-number.hh"
+#include "hb-number-parser.hh"
+
+
+int
+main (int argc, char **argv)
+{
+  {
+    const char str[] = "123";
+    const char *pp = str;
+    const char *end = str + 3;
+
+    int pv;
+    assert (hb_parse_int (&pp, end, &pv));
+    assert (pv == 123);
+    assert (pp - str == 3);
+    assert (end - pp == 0);
+    assert (!*end);
+  }
+
+  {
+    const char str[] = "123";
+    const char *pp = str;
+    const char *end = str + strlen (str);
+
+    unsigned int pv;
+    assert (hb_parse_uint (&pp, end, &pv));
+    assert (pv == 123);
+    assert (pp - str == 3);
+    assert (end - pp == 0);
+    assert (!*end);
+  }
+
+  {
+    const char str[] = "12F";
+    const char *pp = str;
+    const char *end = str + 3;
+
+    unsigned int pv;
+    assert (hb_parse_uint (&pp, end, &pv, true, 16));
+    assert (pv == 0x12F);
+    assert (pp - str == 3);
+    assert (end - pp == 0);
+    assert (!*end);
+  }
+
+  {
+    const char str[] = "12Fq";
+    const char *pp = str;
+    const char *end = str + 4;
+
+    unsigned int pv;
+    assert (!hb_parse_uint (&pp, end, &pv, true, 16));
+    assert (hb_parse_uint (&pp, end, &pv, false, 16));
+    assert (pv == 0x12F);
+    assert (pp - str == 3);
+    assert (end - pp == 1);
+    assert (!*end);
+  }
+
+  {
+    const char str[] = "-123";
+    const char *pp = str;
+    const char *end = str + 4;
+
+    int pv;
+    assert (hb_parse_int (&pp, end, &pv));
+    assert (pv == -123);
+    assert (pp - str == 4);
+    assert (end - pp == 0);
+    assert (!*end);
+  }
+
+  {
+    const char str[] = "123";
+    const char *pp = str;
+    assert (ARRAY_LENGTH (str) == 4);
+    const char *end = str + ARRAY_LENGTH (str);
+
+    unsigned int pv;
+    assert (hb_parse_uint (&pp, end, &pv));
+    assert (pv == 123);
+    assert (pp - str == 3);
+    assert (end - pp == 1);
+  }
+
+  {
+    const char str[] = "123\0";
+    const char *pp = str;
+    assert (ARRAY_LENGTH (str) == 5);
+    const char *end = str + ARRAY_LENGTH (str);
+
+    unsigned int pv;
+    assert (hb_parse_uint (&pp, end, &pv));
+    assert (pv == 123);
+    assert (pp - str == 3);
+    assert (end - pp == 2);
+  }
+
+  {
+    const char str[] = "123V";
+    const char *pp = str;
+    assert (ARRAY_LENGTH (str) == 5);
+    const char *end = str + ARRAY_LENGTH (str);
+
+    unsigned int pv;
+    assert (hb_parse_uint (&pp, end, &pv));
+    assert (pv == 123);
+    assert (pp - str == 3);
+    assert (end - pp == 2);
+  }
+
+  {
+    const char str[] = ".123";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str);
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == 123);
+    assert (pp - str == 4);
+    assert (end - pp == 1);
+
+    /* Test strtod_rl even if libc's strtod_l is used */
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
+    assert (pend - str == 4);
+  }
+
+  {
+    const char str[] = "0.123";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == 123);
+    assert (pp - str == 5);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
+    assert (pend - str == 5);
+  }
+
+  {
+    const char str[] = "0.123e0";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == 123);
+    assert (pp - str == 7);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
+    assert (pend - str == 7);
+  }
+
+  {
+    const char str[] = "123e-3";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == 123);
+    assert (pp - str == 6);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
+    assert (pend - str == 6);
+  }
+
+  {
+    const char str[] = ".000123e+3";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == 123);
+    assert (pp - str == 10);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
+    assert (pend - str == 10);
+  }
+
+  {
+    const char str[] = "-.000000123e6";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == -123);
+    assert (pp - str == 13);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
+    assert (pend - str == 13);
+  }
+
+  {
+    const char str[] = "-1.23E-1";
+    const char *pp = str;
+    const char *end = str + ARRAY_LENGTH (str) - 1;
+
+    double pv;
+    assert (hb_parse_double (&pp, end, &pv));
+    assert ((int) roundf (pv * 1000.) == -123);
+    assert (pp - str == 8);
+    assert (end - pp == 0);
+
+    char *pend;
+    assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
+    assert (pend - str == 8);
+  }
+
+  return 0;
+}
diff --git a/src/test-ot-color.cc b/src/test-ot-color.cc
index 4050a66..88924b4 100644
--- a/src/test-ot-color.cc
+++ b/src/test-ot-color.cc
@@ -23,7 +23,16 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
-#include "hb.h"
+#include "hb.hh"
+
+#include <cairo.h>
+
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
+#if !defined(HB_NO_COLOR) && defined(CAIRO_HAS_SVG_SURFACE)
+
 #include "hb-ot.h"
 
 #include "hb-ft.h"
@@ -32,7 +41,6 @@
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
 
-#include <cairo.h>
 #include <cairo-ft.h>
 #include <cairo-svg.h>
 
@@ -133,7 +141,7 @@
   unsigned glyph_count = hb_face_get_glyph_count (face);
   for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid)
   {
-    unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, NULL, NULL);
+    unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr);
     if (!num_layers)
       continue;
 
@@ -169,7 +177,7 @@
       unsigned int palette_count = hb_ot_color_palette_get_count (face);
       for (unsigned int palette = 0; palette < palette_count; palette++)
       {
-	unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, NULL, NULL);
+	unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr);
 	if (!num_colors)
 	  continue;
 
@@ -271,14 +279,14 @@
 
 
   FILE *font_name_file = fopen ("out/.dumped_font_name", "r");
-  if (font_name_file != NULL)
+  if (font_name_file != nullptr)
   {
     fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n");
     exit (1);
   }
 
   font_name_file = fopen ("out/.dumped_font_name", "w");
-  if (font_name_file == NULL)
+  if (font_name_file == nullptr)
   {
     fprintf (stderr, "./out is not accessible as a folder, create it please\n");
     exit (1);
@@ -322,8 +330,8 @@
 
     // disabled when color font as cairo rendering of NotoColorEmoji is soooo slow
     if (!hb_ot_color_has_layers (face) &&
-        !hb_ot_color_has_png (face) &&
-        !hb_ot_color_has_svg (face))
+	!hb_ot_color_has_png (face) &&
+	!hb_ot_color_has_svg (face))
       dump_glyphs (cairo_face, upem, num_glyphs, face_index);
 
     hb_font_destroy (font);
@@ -334,3 +342,7 @@
 
   return 0;
 }
+
+#else
+int main (int argc, char **argv) { return 0; }
+#endif
diff --git a/src/test-name-table.cc b/src/test-ot-meta.cc
similarity index 66%
copy from src/test-name-table.cc
copy to src/test-ot-meta.cc
index 518e4eb..1045007 100644
--- a/src/test-name-table.cc
+++ b/src/test-ot-meta.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,8 +20,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb.hh"
@@ -30,6 +28,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -43,27 +45,26 @@
   hb_blob_destroy (blob);
   blob = nullptr;
 
-  unsigned int count;
-  const hb_ot_name_entry_t *entries = hb_ot_name_list_names (face, &count);
+  unsigned int count = 0;
 
-  for (unsigned int i = 0; i < count; i++)
+#ifndef HB_NO_META
+  count = hb_ot_meta_get_entry_tags (face, 0, nullptr, nullptr);
+
+  hb_ot_meta_tag_t *tags = (hb_ot_meta_tag_t *)
+			   malloc (sizeof (hb_ot_meta_tag_t) * count);
+  hb_ot_meta_get_entry_tags (face, 0, &count, tags);
+  for (unsigned i = 0; i < count; ++i)
   {
-    printf ("%u	%s	",
-	    entries[i].name_id,
-	    hb_language_to_string (entries[i].language));
-
-    char buf[64];
-    unsigned int buf_size = sizeof (buf);
-    hb_ot_name_get_utf8 (face,
-			 entries[i].name_id,
-			 entries[i].language,
-			 &buf_size,
-			 buf);
-
-    printf ("%s\n", buf);
+    hb_blob_t *entry = hb_ot_meta_reference_entry (face, tags[i]);
+    printf ("%c%c%c%c, size: %d: %.*s\n",
+	    HB_UNTAG (tags[i]), hb_blob_get_length (entry),
+	    hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr));
+    hb_blob_destroy (entry);
   }
+  free (tags);
+#endif
 
   hb_face_destroy (face);
 
-  return count ? 0 : 1;
+  return !count;
 }
diff --git a/src/test-name-table.cc b/src/test-ot-name.cc
similarity index 93%
rename from src/test-name-table.cc
rename to src/test-ot-name.cc
index 518e4eb..4a484c6 100644
--- a/src/test-name-table.cc
+++ b/src/test-ot-name.cc
@@ -30,6 +30,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
@@ -43,7 +47,9 @@
   hb_blob_destroy (blob);
   blob = nullptr;
 
-  unsigned int count;
+  unsigned int count = 0;
+
+#ifndef HB_NO_NAME
   const hb_ot_name_entry_t *entries = hb_ot_name_list_names (face, &count);
 
   for (unsigned int i = 0; i < count; i++)
@@ -62,6 +68,7 @@
 
     printf ("%s\n", buf);
   }
+#endif
 
   hb_face_destroy (face);
 
diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc
index ec9d17a..33cac6b 100644
--- a/src/test-unicode-ranges.cc
+++ b/src/test-unicode-ranges.cc
@@ -25,7 +25,6 @@
  */
 
 #include "hb.hh"
-
 #include "hb-ot-os2-unicode-ranges.hh"
 
 static void
@@ -34,9 +33,9 @@
   if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit)
   {
     fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.",
-             OT::_hb_ot_os2_get_unicode_range_bit (cp),
-             cp,
-             bit);
+	     OT::_hb_ot_os2_get_unicode_range_bit (cp),
+	     cp,
+	     bit);
     abort();
   }
 }
diff --git a/src/test.cc b/src/test.cc
index f0eace8..65b469f 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -34,6 +34,10 @@
 #include "hb-ft.h"
 #endif
 
+#ifdef HB_NO_OPEN
+#define hb_blob_create_from_file(x)  hb_blob_get_empty ()
+#endif
+
 int
 main (int argc, char **argv)
 {
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 9aba2d1..9d4084b 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -42,6 +42,7 @@
 	test-shape \
 	test-subset \
 	test-subset-cmap \
+	test-subset-drop-tables \
 	test-subset-glyf \
 	test-subset-hdmx \
 	test-subset-hmtx \
@@ -52,11 +53,12 @@
 	test-subset-cff2 \
 	test-unicode \
 	test-version \
+	test-subset-nameids \
 	$(NULL)
 
 test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
-test_subset_codepoints_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cmap_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_drop_tables_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_glyf_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_hdmx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_hmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
@@ -65,6 +67,7 @@
 test_subset_vmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cff1_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 test_subset_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
 
 test_unicode_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
@@ -81,8 +84,11 @@
 	test-ot-color \
 	test-ot-ligature-carets \
 	test-ot-name \
+	test-ot-meta \
+	test-ot-metrics \
 	test-ot-tag \
 	test-ot-extents-cff \
+	test-ot-metrics-tt-var \
 	$(NULL)
 
 
diff --git a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
new file mode 100644
index 0000000..8cb3005
--- /dev/null
+++ b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
index 3a71f53..7860f2f 100644
--- a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
+++ b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.a.retaingids.ttf b/test/api/fonts/Roboto-Regular.a.retaingids.ttf
new file mode 100644
index 0000000..183b148
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.a.retaingids.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.abc.ttf b/test/api/fonts/Roboto-Regular.abc.ttf
index 9d791f7..705ec69 100644
--- a/test/api/fonts/Roboto-Regular.abc.ttf
+++ b/test/api/fonts/Roboto-Regular.abc.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.ac.retaingids.ttf b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf
new file mode 100644
index 0000000..8606a55
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.ac.ttf b/test/api/fonts/Roboto-Regular.ac.ttf
index 6ac1b33..5a5e68e 100644
--- a/test/api/fonts/Roboto-Regular.ac.ttf
+++ b/test/api/fonts/Roboto-Regular.ac.ttf
Binary files differ
diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
new file mode 100644
index 0000000..fa2a0e4
--- /dev/null
+++ b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf b/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
new file mode 100644
index 0000000..d364b48
--- /dev/null
+++ b/test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf b/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf
new file mode 100644
index 0000000..dc237e7
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman.anchor.ttf b/test/api/fonts/SourceSansVariable-Roman.anchor.ttf
new file mode 100644
index 0000000..4e8dc9d
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman.anchor.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf b/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf
new file mode 100644
index 0000000..c75041f
--- /dev/null
+++ b/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf
Binary files differ
diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf
new file mode 100644
index 0000000..7d94abc
--- /dev/null
+++ b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf
Binary files differ
diff --git a/test/api/fonts/TestCFF2VF.otf b/test/api/fonts/TestCFF2VF.otf
new file mode 100644
index 0000000..a9e48e3
--- /dev/null
+++ b/test/api/fonts/TestCFF2VF.otf
Binary files differ
diff --git a/test/api/fonts/Zycon.ttf b/test/api/fonts/Zycon.ttf
new file mode 100644
index 0000000..3a6761b
--- /dev/null
+++ b/test/api/fonts/Zycon.ttf
Binary files differ
diff --git a/test/api/fonts/cmunrm.otf b/test/api/fonts/cmunrm.otf
new file mode 100644
index 0000000..b449df0
--- /dev/null
+++ b/test/api/fonts/cmunrm.otf
Binary files differ
diff --git a/test/api/fonts/meta.ttf b/test/api/fonts/meta.ttf
new file mode 100644
index 0000000..414d7e6
--- /dev/null
+++ b/test/api/fonts/meta.ttf
Binary files differ
diff --git a/test/api/fonts/nameID.dup.expected.ttf b/test/api/fonts/nameID.dup.expected.ttf
new file mode 100644
index 0000000..e9e7ff5
--- /dev/null
+++ b/test/api/fonts/nameID.dup.expected.ttf
Binary files differ
diff --git a/test/api/fonts/nameID.dup.origin.ttf b/test/api/fonts/nameID.dup.origin.ttf
new file mode 100644
index 0000000..aad75d4
--- /dev/null
+++ b/test/api/fonts/nameID.dup.origin.ttf
Binary files differ
diff --git a/test/api/fonts/nameID.expected.ttf b/test/api/fonts/nameID.expected.ttf
new file mode 100644
index 0000000..00aecc0
--- /dev/null
+++ b/test/api/fonts/nameID.expected.ttf
Binary files differ
diff --git a/test/api/fonts/nameID.origin.ttf b/test/api/fonts/nameID.origin.ttf
new file mode 100644
index 0000000..aec973a
--- /dev/null
+++ b/test/api/fonts/nameID.origin.ttf
Binary files differ
diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h
index cefa4e0..99f567a 100644
--- a/test/api/hb-subset-test.h
+++ b/test/api/hb-subset-test.h
@@ -48,7 +48,7 @@
 HB_BEGIN_DECLS
 
 static inline hb_subset_input_t *
-hb_subset_test_create_input(const hb_set_t  *codepoints)
+hb_subset_test_create_input (const hb_set_t *codepoints)
 {
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
   hb_set_t * input_codepoints = hb_subset_input_unicode_set (input);
@@ -56,9 +56,27 @@
   return input;
 }
 
+static inline hb_subset_input_t *
+hb_subset_test_create_input_from_glyphs (const hb_set_t *glyphs)
+{
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  hb_set_t * input_glyphs  = hb_subset_input_glyph_set (input);
+  hb_set_union (input_glyphs, glyphs);
+  return input;
+}
+
+static inline hb_subset_input_t *
+hb_subset_test_create_input_from_nameids (const hb_set_t *name_ids)
+{
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  hb_set_t * input_name_ids  = hb_subset_input_nameid_set (input);
+  hb_set_set (input_name_ids, name_ids);
+  return input;
+}
+
 static inline hb_face_t *
 hb_subset_test_create_subset (hb_face_t *source,
-                              hb_subset_input_t *input)
+			      hb_subset_input_t *input)
 {
   hb_face_t *subset = hb_subset (source, input);
   g_assert (subset);
@@ -69,13 +87,13 @@
 
 static inline void
 hb_subset_test_check (hb_face_t *expected,
-                      hb_face_t *actual,
-                      hb_tag_t   table)
+		      hb_face_t *actual,
+		      hb_tag_t   table)
 {
   hb_blob_t *expected_blob, *actual_blob;
-  //fprintf(stderr, "comparing %c%c%c%c ", HB_UNTAG(table));
   expected_blob = hb_face_reference_table (expected, table);
   actual_blob = hb_face_reference_table (actual, table);
+  fprintf(stderr, "comparing %c%c%c%c, expected %d bytes, actual %d bytes\n", HB_UNTAG(table), hb_blob_get_length(expected_blob), hb_blob_get_length (actual_blob));
   hb_test_assert_blobs_equal (expected_blob, actual_blob);
   hb_blob_destroy (expected_blob);
   hb_blob_destroy (actual_blob);
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 872f45c..b866e44 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -173,6 +173,16 @@
   const char *raw_expected = hb_blob_get_data (expected_blob, &expected_length);
   const char *raw_actual = hb_blob_get_data (actual_blob, &actual_length);
   g_assert_cmpint(expected_length, ==, actual_length);
+  if (memcmp (raw_expected, raw_actual, expected_length) != 0)
+  {
+    for (unsigned int i = 0; i < expected_length; i++)
+    {
+      int expected = *(raw_expected + i);
+      int actual = *(raw_actual + i);
+      if (expected != actual) fprintf(stderr, "+%u %02x != %02x\n", i, expected, actual);
+      else fprintf(stderr, "+%u %02x\n", i, expected);
+    }
+  }
   g_assert_cmpint(0, ==, memcmp(raw_expected, raw_actual, expected_length));
 }
 
diff --git a/test/api/test-aat-layout.c b/test/api/test-aat-layout.c
index 1384556..d9dd8a3 100644
--- a/test/api/test-aat-layout.c
+++ b/test/api/test-aat-layout.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
diff --git a/test/api/test-baseline.c b/test/api/test-baseline.c
index a120e14..982c683 100644
--- a/test/api/test-baseline.c
+++ b/test/api/test-baseline.c
@@ -34,14 +34,12 @@
   hb_face_t *face = hb_test_open_font_file ("fonts/base.ttf");
   hb_font_t *font = hb_font_create (face);
 
-#if 0
   hb_position_t position;
-  g_assert (hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_ICFB, HB_DIRECTION_TTB,
+  g_assert (hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, HB_DIRECTION_TTB,
 				       HB_TAG ('h','a','n','i'),
 				       HB_TAG ('E','N','G',' '),
 				       &position));
   g_assert_cmpint (46, ==, position);
-#endif
 
   hb_font_destroy (font);
   hb_face_destroy (face);
diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c
index 64ab3db..228f0f3 100644
--- a/test/api/test-buffer.c
+++ b/test/api/test-buffer.c
@@ -208,7 +208,7 @@
       if (buffer_type == BUFFER_UTF16)
 	cluster++;
       else if (buffer_type == BUFFER_UTF8)
-        cluster += 3;
+	cluster += 3;
     }
     g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]);
     g_assert_cmphex (glyphs[i].cluster,   ==, cluster);
diff --git a/test/api/test-collect-unicodes.c b/test/api/test-collect-unicodes.c
index 50965a9..8a857e1 100644
--- a/test/api/test-collect-unicodes.c
+++ b/test/api/test-collect-unicodes.c
@@ -50,6 +50,27 @@
 }
 
 static void
+test_collect_unicodes_format12_notdef (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/cmunrm.otf");
+  hb_set_t *codepoints = hb_set_create();
+  hb_codepoint_t cp;
+
+  hb_face_collect_unicodes (face, codepoints);
+
+  cp = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (codepoints, &cp));
+  g_assert_cmpuint (0x20, ==, cp);
+  g_assert (hb_set_next (codepoints, &cp));
+  g_assert_cmpuint (0x21, ==, cp);
+  g_assert (hb_set_next (codepoints, &cp));
+  g_assert_cmpuint (0x22, ==, cp);
+
+  hb_set_destroy (codepoints);
+  hb_face_destroy (face);
+}
+
+static void
 test_collect_unicodes_format12 (void)
 {
   hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.format12.ttf");
@@ -101,6 +122,7 @@
   hb_test_add (test_collect_unicodes);
   hb_test_add (test_collect_unicodes_format4);
   hb_test_add (test_collect_unicodes_format12);
+  hb_test_add (test_collect_unicodes_format12_notdef);
 
   return hb_test_run();
 }
diff --git a/test/api/test-font.c b/test/api/test-font.c
index 6690194..c6738b4 100644
--- a/test/api/test-font.c
+++ b/test/api/test-font.c
@@ -146,9 +146,6 @@
   glyph = 3;
   g_assert (!hb_font_get_glyph (font, 17, 2, &glyph));
   g_assert_cmpint (glyph, ==, 0);
-
-  x = hb_font_get_glyph_h_kerning (font, 17, 19);
-  g_assert_cmpint (x, ==, 0);
 }
 
 static void
diff --git a/test/api/test-object.c b/test/api/test-object.c
index 093615e..5154621 100644
--- a/test/api/test-object.c
+++ b/test/api/test-object.c
@@ -345,7 +345,7 @@
       if (!obj)
 	continue;
       if (obj == o->get_empty ())
-        continue; /* Tested already */
+	continue; /* Tested already */
 
       g_assert (obj == o->reference (obj));
       o->destroy (obj);
diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c
index c0cbd77..c2bbad2 100644
--- a/test/api/test-ot-color.c
+++ b/test/api/test-ot-color.c
@@ -210,7 +210,7 @@
 test_hb_ot_color_palette_get_colors_v0 (void)
 {
   unsigned int num_colors = hb_ot_color_palette_get_colors (cpal_v0, 0, 0, NULL, NULL);
-  hb_color_t *colors = (hb_color_t*) alloca (num_colors * sizeof (hb_color_t));
+  hb_color_t *colors = (hb_color_t*) malloc (num_colors * sizeof (hb_color_t));
   size_t colors_size = num_colors * sizeof(*colors);
   g_assert_cmpint (num_colors, ==, 2);
 
@@ -252,6 +252,8 @@
   g_assert_cmpint (num_colors, ==, 0);
   assert_color_rgba (colors, 0, 0x44, 0x44, 0x44, 0x44);  /* untouched */
   assert_color_rgba (colors, 1, 0x44, 0x44, 0x44, 0x44);  /* untouched */
+	
+  free (colors);
 }
 
 
@@ -426,9 +428,9 @@
   g_assert (strncmp (data + 1, "PNG", 3) == 0);
   hb_font_get_glyph_extents (sbix_font, 1, &extents);
   g_assert_cmpint (extents.x_bearing, ==, 0);
-  g_assert_cmpint (extents.y_bearing, ==, 0);
+  g_assert_cmpint (extents.y_bearing, ==, 800);
   g_assert_cmpint (extents.width, ==, 800);
-  g_assert_cmpint (extents.height, ==, 800);
+  g_assert_cmpint (extents.height, ==, -800);
   hb_blob_destroy (blob);
   hb_font_destroy (sbix_font);
 
diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c
index 49b8799..7109e30 100644
--- a/test/api/test-ot-extents-cff.c
+++ b/test/api/test-ot-extents-cff.c
@@ -146,8 +146,8 @@
 
   g_assert_cmpint (extents.x_bearing, ==, 38);
   g_assert_cmpint (extents.y_bearing, ==, 493);
-  g_assert_cmpint (extents.width, ==, 481);
-  g_assert_cmpint (extents.height, ==, -508);
+  g_assert_cmpint (extents.width, ==, 480);
+  g_assert_cmpint (extents.height, ==, -507);
 
   hb_font_destroy (font);
 }
@@ -168,22 +168,53 @@
   hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents);
   g_assert (result);
 
-  g_assert_cmpint (extents.x_bearing, ==, 11);
-  g_assert_cmpint (extents.y_bearing, ==, 656);
-  g_assert_cmpint (extents.width, ==, 653);
-  g_assert_cmpint (extents.height, ==, -656);
+  g_assert_cmpint (extents.x_bearing, ==, 12);
+  g_assert_cmpint (extents.y_bearing, ==, 655);
+  g_assert_cmpint (extents.width, ==, 652);
+  g_assert_cmpint (extents.height, ==, -655);
 
   result = hb_font_get_glyph_extents (font, 2, &extents);
   g_assert (result);
 
-  g_assert_cmpint (extents.x_bearing, ==, 7);
+  g_assert_cmpint (extents.x_bearing, ==, 8);
   g_assert_cmpint (extents.y_bearing, ==, 669);
-  g_assert_cmpint (extents.width, ==, 650);
+  g_assert_cmpint (extents.width, ==, 649);
   g_assert_cmpint (extents.height, ==, -669);
 
   hb_font_destroy (font);
 }
 
+static void
+test_extents_cff2_vsindex_named_instance (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype_vsindex.otf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_font_set_var_named_instance (font, 6); // 6 (BlackMediumContrast): 900, 50
+  hb_glyph_extents_t  extents;
+  hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 13);
+  g_assert_cmpint (extents.y_bearing, ==, 652);
+  g_assert_cmpint (extents.width, ==, 653);
+  g_assert_cmpint (extents.height, ==, -652);
+
+  result = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 6);
+  g_assert_cmpint (extents.y_bearing, ==, 675);
+  g_assert_cmpint (extents.width, ==, 647);
+  g_assert_cmpint (extents.height, ==, -675);
+
+  hb_font_destroy (font);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -194,6 +225,7 @@
   hb_test_add (test_extents_cff1_seac);
   hb_test_add (test_extents_cff2);
   hb_test_add (test_extents_cff2_vsindex);
+  hb_test_add (test_extents_cff2_vsindex_named_instance);
 
   return hb_test_run ();
 }
diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c
index f2d2fca..44a9116 100644
--- a/test/api/test-ot-face.c
+++ b/test/api/test-ot-face.c
@@ -74,6 +74,8 @@
   hb_ot_color_has_png (face);
   hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp));
 
+  hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL);
+
   hb_ot_layout_has_glyph_classes (face);
   hb_ot_layout_has_substitution (face);
   hb_ot_layout_has_positioning (face);
@@ -88,6 +90,14 @@
   hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_RTL);
   hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, NULL, NULL, NULL);
 
+  hb_ot_meta_get_entry_tags (face, 0, NULL, NULL);
+  hb_blob_destroy (hb_ot_meta_reference_entry (face, HB_OT_META_TAG_DESIGN_LANGUAGES));
+
+  hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, NULL);
+  hb_ot_metrics_get_variation (font, HB_OT_METRICS_TAG_UNDERLINE_OFFSET);
+  hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET);
+  hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET);
+
   len = sizeof (buf);
   hb_ot_name_list_names (face, NULL);
   hb_ot_name_get_utf8 (face, cp, NULL, &len, buf);
@@ -110,12 +120,21 @@
   test_face (hb_face_get_empty (), 0);
 }
 
+static void
+test_ot_var_axis_on_zero_named_instance (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Zycon.ttf");
+  g_assert (hb_ot_var_get_axis_count (face));
+  hb_face_destroy (face);
+}
+
 int
 main (int argc, char **argv)
 {
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_ot_face_empty);
+  hb_test_add (test_ot_var_axis_on_zero_named_instance);
 
   return hb_test_run();
 }
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index 7f50015..73b1a25 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -457,41 +457,41 @@
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
   g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_BTT,
-                                                 0,
-                                                 NULL,
-                                                 NULL), ==, 0);
+						 glyph,
+						 HB_DIRECTION_BTT,
+						 0,
+						 NULL,
+						 NULL), ==, 0);
   g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_RTL,
-                                                 0,
-                                                 NULL,
-                                                 NULL), ==, 3);
+						 glyph,
+						 HB_DIRECTION_RTL,
+						 0,
+						 NULL,
+						 NULL), ==, 3);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowup", -1, &glyph));
   g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_BTT,
-                                                 0,
-                                                 NULL,
-                                                 NULL), ==, 4);
+						 glyph,
+						 HB_DIRECTION_BTT,
+						 0,
+						 NULL,
+						 NULL), ==, 4);
   g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_RTL,
-                                                 0,
-                                                 NULL,
-                                                 NULL), ==, 0);
+						 glyph,
+						 HB_DIRECTION_RTL,
+						 0,
+						 NULL,
+						 NULL), ==, 0);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph));
   do {
     count = variantsSize;
     hb_ot_math_get_glyph_variants (hb_font,
-                                   glyph,
-                                   HB_DIRECTION_RTL,
-                                   offset,
-                                   &count,
-                                   variants);
+				   glyph,
+				   HB_DIRECTION_RTL,
+				   offset,
+				   &count,
+				   variants);
     offset += count;
   } while (count == variantsSize);
   g_assert_cmpint(offset, ==, 3);
@@ -510,11 +510,11 @@
   do {
     count = variantsSize;
     hb_ot_math_get_glyph_variants (hb_font,
-                                   glyph,
-                                   HB_DIRECTION_BTT,
-                                   offset,
-                                   &count,
-                                   variants);
+				   glyph,
+				   HB_DIRECTION_BTT,
+				   offset,
+				   &count,
+				   variants);
     offset += count;
   } while (count == variantsSize);
   g_assert_cmpint(offset, ==, 4);
@@ -581,46 +581,46 @@
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
   g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_BTT,
-                                                 0,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL), ==, 0);
+						 glyph,
+						 HB_DIRECTION_BTT,
+						 0,
+						 NULL,
+						 NULL,
+						 NULL), ==, 0);
   g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_RTL,
-                                                 0,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL), ==, 3);
+						 glyph,
+						 HB_DIRECTION_RTL,
+						 0,
+						 NULL,
+						 NULL,
+						 NULL), ==, 3);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowdown", -1, &glyph));
   g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_BTT,
-                                                 0,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL), ==, 5);
+						 glyph,
+						 HB_DIRECTION_BTT,
+						 0,
+						 NULL,
+						 NULL,
+						 NULL), ==, 5);
   g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font,
-                                                 glyph,
-                                                 HB_DIRECTION_RTL,
-                                                 0,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL), ==, 0);
+						 glyph,
+						 HB_DIRECTION_RTL,
+						 0,
+						 NULL,
+						 NULL,
+						 NULL), ==, 0);
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph));
   do {
     count = partsSize;
     hb_ot_math_get_glyph_assembly (hb_font,
-                                   glyph,
-                                   HB_DIRECTION_RTL,
-                                   offset,
-                                   &count,
-                                   parts,
-                                   NULL);
+				   glyph,
+				   HB_DIRECTION_RTL,
+				   offset,
+				   &count,
+				   parts,
+				   NULL);
     offset += count;
   } while (count == partsSize);
   g_assert_cmpint(offset, ==, 3);
@@ -629,31 +629,31 @@
   g_assert_cmpint(parts[0].start_connector_length, ==, 800);
   g_assert_cmpint(parts[0].end_connector_length, ==, 384);
   g_assert_cmpint(parts[0].full_advance, ==, 2000);
-  g_assert(!(parts[0].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+  g_assert(!(parts[0].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
   g_assert(hb_font_get_glyph_from_name (hb_font, "horizontal", -1, &glyph));
   g_assert_cmpint(parts[1].glyph, ==, glyph);
   g_assert_cmpint(parts[1].start_connector_length, ==, 524);
   g_assert_cmpint(parts[1].end_connector_length, ==, 800);
   g_assert_cmpint(parts[1].full_advance, ==, 2000);
-  g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+  g_assert(parts[1].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER);
   g_assert(hb_font_get_glyph_from_name (hb_font, "right", -1, &glyph));
   g_assert_cmpint(parts[2].glyph, ==, glyph);
   g_assert_cmpint(parts[2].start_connector_length, ==, 316);
   g_assert_cmpint(parts[2].end_connector_length, ==, 454);
   g_assert_cmpint(parts[2].full_advance, ==, 2000);
-  g_assert(!(parts[2].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+  g_assert(!(parts[2].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
 
   g_assert(hb_font_get_glyph_from_name (hb_font, "arrowdown", -1, &glyph));
   offset = 0;
   do {
     count = partsSize;
     hb_ot_math_get_glyph_assembly (hb_font,
-                                   glyph,
-                                   HB_DIRECTION_BTT,
-                                   offset,
-                                   &count,
-                                   parts,
-                                   NULL);
+				   glyph,
+				   HB_DIRECTION_BTT,
+				   offset,
+				   &count,
+				   parts,
+				   NULL);
     offset += count;
   } while (count == partsSize);
   g_assert_cmpint(offset, ==, 5);
@@ -662,20 +662,20 @@
   g_assert_cmpint(parts[0].start_connector_length, ==, 365);
   g_assert_cmpint(parts[0].end_connector_length, ==, 158);
   g_assert_cmpint(parts[0].full_advance, ==, 1000);
-  g_assert(!(parts[0].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+  g_assert(!(parts[0].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
   g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
   g_assert_cmpint(parts[1].glyph, ==, glyph);
   g_assert_cmpint(parts[1].glyph, ==, glyph);
   g_assert_cmpint(parts[1].start_connector_length, ==, 227);
   g_assert_cmpint(parts[1].end_connector_length, ==, 365);
   g_assert_cmpint(parts[1].full_advance, ==, 1000);
-  g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+  g_assert(parts[1].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER);
   g_assert(hb_font_get_glyph_from_name (hb_font, "center", -1, &glyph));
   g_assert_cmpint(parts[2].glyph, ==, glyph);
   g_assert_cmpint(parts[2].start_connector_length, ==, 54);
   g_assert_cmpint(parts[2].end_connector_length, ==, 158);
   g_assert_cmpint(parts[2].full_advance, ==, 1000);
-  g_assert(!(parts[2].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+  g_assert(!(parts[2].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
   g_assert(hb_font_get_glyph_from_name (hb_font, "vertical", -1, &glyph));
   g_assert_cmpint(parts[3].glyph, ==, glyph);
   g_assert_cmpint(parts[3].glyph, ==, glyph);
@@ -683,13 +683,13 @@
   g_assert_cmpint(parts[3].start_connector_length, ==, 400);
   g_assert_cmpint(parts[3].end_connector_length, ==, 296);
   g_assert_cmpint(parts[3].full_advance, ==, 1000);
-  g_assert(parts[1].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER);
+  g_assert(parts[1].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER);
   g_assert(hb_font_get_glyph_from_name (hb_font, "top", -1, &glyph));
   g_assert_cmpint(parts[4].glyph, ==, glyph);
   g_assert_cmpint(parts[4].start_connector_length, ==, 123);
   g_assert_cmpint(parts[4].end_connector_length, ==, 192);
   g_assert_cmpint(parts[4].full_advance, ==, 1000);
-  g_assert(!(parts[4].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER));
+  g_assert(!(parts[4].flags & HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER));
 
   closeFont();
 
diff --git a/test/api/test-ot-meta.c b/test/api/test-ot-meta.c
new file mode 100644
index 0000000..573c8c6
--- /dev/null
+++ b/test/api/test-ot-meta.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb-ot.h>
+
+/* Unit tests for hb-ot-meta.h */
+
+static void
+test_ot_meta_get_entries (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf");
+  hb_ot_meta_tag_t entries[2];
+
+  unsigned int entries_count = 2;
+  g_assert_cmpint (hb_ot_meta_get_entry_tags (face, 0, &entries_count, entries), ==, 5);
+  g_assert_cmpint (entries_count, ==, 2);
+  g_assert_cmpint (entries[0], ==, HB_TAG ('a','p','p','l'));
+  g_assert_cmpint (entries[1], ==, HB_TAG ('b','i','l','d'));
+
+  entries_count = 1;
+  g_assert_cmpint (hb_ot_meta_get_entry_tags (face, 2, &entries_count, entries), ==, 5);
+  g_assert_cmpint (entries_count, ==, 1);
+  g_assert_cmpint (entries[0], ==, HB_TAG ('d','l','n','g'));
+
+  entries_count = 2;
+  g_assert_cmpint (hb_ot_meta_get_entry_tags (face, 4, &entries_count, entries), ==, 5);
+  g_assert_cmpint (entries_count, ==, 1);
+  g_assert_cmpint (entries[0], ==, HB_TAG ('s','l','n','g'));
+
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_meta_reference_entry (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf");
+  hb_blob_t *dlng = hb_ot_meta_reference_entry (face, HB_OT_META_TAG_DESIGN_LANGUAGES);
+  g_assert_cmpint (hb_blob_get_length (dlng), ==, 8);
+  g_assert_cmpmem (hb_blob_get_data (dlng, NULL), 8, "ar,de,fa", 8);
+  hb_blob_destroy (dlng);
+  hb_blob_t *fslf = hb_ot_meta_reference_entry (face, (hb_ot_meta_tag_t) HB_TAG ('f','s','l','f'));
+  g_assert_cmpint (hb_blob_get_length (fslf), ==, 12);
+  hb_blob_destroy (fslf);
+  hb_blob_t *nacl = hb_ot_meta_reference_entry (face, (hb_ot_meta_tag_t) HB_TAG ('n','a','c','l'));
+  g_assert_cmpint (hb_blob_get_length (nacl), ==, 0);
+  hb_blob_destroy (nacl);
+  hb_blob_t *slng = hb_ot_meta_reference_entry (face, HB_OT_META_TAG_SUPPORTED_LANGUAGES);
+  g_assert_cmpint (hb_blob_get_length (slng), ==, 11);
+  g_assert_cmpmem (hb_blob_get_data (slng, NULL), 11, "ar,de,en,fa", 11);
+  hb_blob_destroy (slng);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_ot_meta_get_entries);
+  hb_test_add (test_ot_meta_reference_entry);
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-metrics-tt-var.c b/test/api/test-ot-metrics-tt-var.c
new file mode 100644
index 0000000..2305a95
--- /dev/null
+++ b/test/api/test-ot-metrics-tt-var.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#include "hb-test.h"
+#include <hb-ot.h>
+
+/* Unit tests for glyph advance widths and extents of TrueType variable fonts */
+
+static void
+test_extents_tt_var (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_glyph_extents_t  extents;
+  hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 10);
+  g_assert_cmpint (extents.y_bearing, ==, 846);
+  g_assert_cmpint (extents.width, ==, 500);
+  g_assert_cmpint (extents.height, ==, -846);
+
+  float coords[1] = { 500.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+  result = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 0);
+  g_assert_cmpint (extents.y_bearing, ==, 874);
+  g_assert_cmpint (extents.width, ==, 551);
+  g_assert_cmpint (extents.height, ==, -874);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_advance_tt_var_nohvar (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_position_t x, y;
+  hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_LTR, &x, &y);
+
+  g_assert_cmpint (x, ==, 520);
+  g_assert_cmpint (y, ==, 0);
+
+  hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
+
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, -1000);
+
+  float coords[1] = { 500.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+  hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_LTR, &x, &y);
+
+  g_assert_cmpint (x, ==, 551);
+  g_assert_cmpint (y, ==, 0);
+
+  hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
+
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, -1000);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_advance_tt_var_hvarvvar (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_position_t x, y;
+  hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_LTR, &x, &y);
+
+  g_assert_cmpint (x, ==, 508);
+  g_assert_cmpint (y, ==, 0);
+
+  hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_TTB, &x, &y);
+
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, -1000);
+
+  float coords[1] = { 700.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+  hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_LTR, &x, &y);
+
+  g_assert_cmpint (x, ==, 531);
+  g_assert_cmpint (y, ==, 0);
+
+  hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_TTB, &x, &y);
+
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, -1012);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_advance_tt_var_anchor (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.anchor.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_glyph_extents_t  extents;
+  hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 56);
+  g_assert_cmpint (extents.y_bearing, ==, 672);
+  g_assert_cmpint (extents.width, ==, 556);
+  g_assert_cmpint (extents.height, ==, -684);
+
+  float coords[1] = { 500.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+  result = hb_font_get_glyph_extents (font, 2, &extents);
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 50);
+  g_assert_cmpint (extents.y_bearing, ==, 667);
+  g_assert_cmpint (extents.width, ==, 593);
+  g_assert_cmpint (extents.height, ==, -679);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_extents_tt_var_comp (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.modcomp.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  hb_glyph_extents_t  extents;
+  float coords[1] = { 800.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+
+  hb_bool_t result;
+  result = hb_font_get_glyph_extents (font, 2, &extents);	/* Ccedilla, cedilla y-scaled by 0.8, with unscaled component offset */
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 19);
+  g_assert_cmpint (extents.y_bearing, ==, 663);
+  g_assert_cmpint (extents.width, ==, 519);
+  g_assert_cmpint (extents.height, ==, -895);
+
+  result = hb_font_get_glyph_extents (font, 3, &extents);	/* Cacute, acute y-scaled by 0.8, with unscaled component offset (default) */
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 19);
+  g_assert_cmpint (extents.y_bearing, ==, 909);
+  g_assert_cmpint (extents.width, ==, 519);
+  g_assert_cmpint (extents.height, ==, -921);
+
+  result = hb_font_get_glyph_extents (font, 4, &extents);	/* Ccaron, caron y-scaled by 0.8, with scaled component offset */
+  g_assert (result);
+
+  g_assert_cmpint (extents.x_bearing, ==, 19);
+  g_assert_cmpint (extents.y_bearing, ==, 866);
+  g_assert_cmpint (extents.width, ==, 519);
+  g_assert_cmpint (extents.height, ==, -878);
+
+  hb_font_destroy (font);
+}
+
+static void
+test_advance_tt_var_comp_v (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.modcomp.ttf");
+  g_assert (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  g_assert (font);
+  hb_ot_font_set_funcs (font);
+
+  float coords[1] = { 800.0f };
+  hb_font_set_var_coords_design (font, coords, 1);
+
+  hb_position_t x, y;
+  hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);	/* No VVAR; 'C' in composite Ccedilla determines metrics */
+
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, -991);
+
+  hb_font_get_glyph_origin_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y);
+
+  g_assert_cmpint (x, ==, 292);
+  g_assert_cmpint (y, ==, 1013);
+
+  hb_font_destroy (font);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_extents_tt_var);
+  hb_test_add (test_advance_tt_var_nohvar);
+  hb_test_add (test_advance_tt_var_hvarvvar);
+  hb_test_add (test_advance_tt_var_anchor);
+  hb_test_add (test_extents_tt_var_comp);
+  hb_test_add (test_advance_tt_var_comp_v);
+
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-metrics.c b/test/api/test-ot-metrics.c
new file mode 100644
index 0000000..34f9196
--- /dev/null
+++ b/test/api/test-ot-metrics.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+#include <hb-ot.h>
+
+#include <math.h>
+
+/* Unit tests for hb-ot-metrics.h */
+
+static void
+test_ot_metrics_get_no_var (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/cpal-v0.ttf");
+  hb_font_t *font = hb_font_create (face);
+  hb_position_t value;
+  g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &value));
+  g_assert_cmpint (value, ==, 1000);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_X_HEIGHT), ==, 0);
+  // g_assert_cmpint ((int) hb_ot_metrics_get_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+static void
+test_ot_metrics_get_var (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/TestCFF2VF.otf");
+  hb_font_t *font = hb_font_create (face);
+  hb_position_t value;
+  g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &value));
+  g_assert_cmpint (value, ==, 486);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_X_HEIGHT), ==, 0);
+  float coords[] = {100.f};
+  hb_font_set_var_coords_design (font, coords, 1);
+  g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &value));
+  g_assert_cmpint (value, ==,  478);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER), ==, 0);
+  g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_TAG_X_HEIGHT), ==, -8);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+  hb_test_add (test_ot_metrics_get_no_var);
+  hb_test_add (test_ot_metrics_get_var);
+  return hb_test_run ();
+}
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index 60231af..958fd6b 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -190,7 +190,6 @@
   test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA);
   test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL);
   test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU);
-  test_indic_tags ("mym3", "mym2", "mymr", HB_SCRIPT_MYANMAR);
 }
 
 
@@ -281,6 +280,8 @@
   g_assert_cmphex (HB_TAG_CHAR4 ("dflt"), ==, HB_OT_TAG_DEFAULT_LANGUAGE);
   test_language_two_way ("dflt", NULL);
 
+  test_language_two_way ("ALT", "alt");
+
   test_language_two_way ("ARA", "ar");
 
   test_language_two_way ("AZE", "az");
@@ -350,10 +351,8 @@
   test_tag_from_language ("ZHH", "yue-Hant");
   test_tag_from_language ("ZHS", "yue-Hans");
 
-  test_tag_from_language ("ZHS", "zh"); /* Chinese */
-  test_tag_from_language ("ZHS", "zh-xx");
-
-  test_language_two_way ("ABC", "x-hbotabc");
+  test_language_two_way ("ABC", "abc");
+  test_language_two_way ("ABCD", "x-hbotabcd");
   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc");
   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc");
   test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbotabcd");
@@ -503,6 +502,7 @@
   test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
   test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR");
   test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL");
+  test_tags (HB_SCRIPT_MYANMAR, "und", HB_OT_MAX_TAGS_PER_SCRIPT, 0, 2, 0, "mym2", "mymr");
   test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ");
   test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0);
 }
diff --git a/test/api/test-shape.c b/test/api/test-shape.c
index 146cf0f..fd7acec 100644
--- a/test/api/test-shape.c
+++ b/test/api/test-shape.c
@@ -67,45 +67,16 @@
   return FALSE;
 }
 
-static hb_position_t
-glyph_h_kerning_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
-		      hb_codepoint_t left, hb_codepoint_t right,
-		      void *user_data HB_UNUSED)
-{
-  if (left == 1 && right == 2)
-    return -2;
-
-  return 0;
-}
-
 static const char TesT[] = "TesT";
 
 static void
-test_shape (void)
+test_font (hb_font_t *font)
 {
-  hb_blob_t *blob;
-  hb_face_t *face;
-  hb_font_funcs_t *ffuncs;
-  hb_font_t *font;
   hb_buffer_t *buffer;
   unsigned int len;
   hb_glyph_info_t *glyphs;
   hb_glyph_position_t *positions;
 
-  blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
-  face = hb_face_create (blob, 0);
-  hb_blob_destroy (blob);
-  font = hb_font_create (face);
-  hb_face_destroy (face);
-  hb_font_set_scale (font, 10, 10);
-
-  ffuncs = hb_font_funcs_create ();
-  hb_font_funcs_set_glyph_h_advance_func (ffuncs, glyph_h_advance_func, NULL, NULL);
-  hb_font_funcs_set_nominal_glyph_func (ffuncs, glyph_func, malloc (10), free);
-  hb_font_funcs_set_glyph_h_kerning_func (ffuncs, glyph_h_kerning_func, NULL, NULL);
-  hb_font_set_funcs (font, ffuncs, NULL, NULL);
-  hb_font_funcs_destroy (ffuncs);
-
   buffer =  hb_buffer_create ();
   hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
   hb_buffer_add_utf8 (buffer, TesT, 4, 0, 4);
@@ -118,8 +89,8 @@
 
   {
     const hb_codepoint_t output_glyphs[] = {1, 2, 3, 1};
-    const hb_position_t output_x_advances[] = {9, 5, 5, 10};
-    const hb_position_t output_x_offsets[] = {0, -1, 0, 0};
+    const hb_position_t output_x_advances[] = {10, 6, 5, 10};
+    const hb_position_t output_x_offsets[] = {0, 0, 0, 0};
     unsigned int i;
     g_assert_cmpint (len, ==, 4);
     for (i = 0; i < len; i++) {
@@ -135,6 +106,35 @@
   }
 
   hb_buffer_destroy (buffer);
+}
+
+static void
+test_shape (void)
+{
+  hb_blob_t *blob;
+  hb_face_t *face;
+  hb_font_funcs_t *ffuncs;
+  hb_font_t *font, *sub_font;
+
+  blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+  face = hb_face_create (blob, 0);
+  hb_blob_destroy (blob);
+  font = hb_font_create (face);
+  hb_face_destroy (face);
+  hb_font_set_scale (font, 10, 10);
+
+  ffuncs = hb_font_funcs_create ();
+  hb_font_funcs_set_glyph_h_advance_func (ffuncs, glyph_h_advance_func, NULL, NULL);
+  hb_font_funcs_set_nominal_glyph_func (ffuncs, glyph_func, malloc (10), free);
+  hb_font_set_funcs (font, ffuncs, NULL, NULL);
+  hb_font_funcs_destroy (ffuncs);
+
+  test_font (font);
+
+  sub_font = hb_font_create_sub_font (font);
+  test_font (sub_font);
+
+  hb_font_destroy (sub_font);
   hb_font_destroy (font);
 }
 
diff --git a/test/api/test-subset-cff1.c b/test/api/test-subset-cff1.c
index 3ee2702..8b4025d 100644
--- a/test/api/test-subset-cff1.c
+++ b/test/api/test-subset-cff1.c
@@ -290,6 +290,52 @@
   hb_face_destroy (face);
 }
 
+static void
+test_subset_cff1_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansPro-Regular.ac.retaingids.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_subset_input_t *input;
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_retain_gids (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_cff1_j_retaingids (void)
+{
+  hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
+  hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_subset_input_t *input;
+  hb_face_t *face_41_3041_4c2e_subset;
+  hb_set_add (codepoints, 0x41);
+  hb_set_add (codepoints, 0x4C2E);
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_retain_gids (input, true);
+  face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' '));
+
+  hb_face_destroy (face_41_3041_4c2e_subset);
+  hb_face_destroy (face_41_3041_4c2e);
+  hb_face_destroy (face_41_4c2e);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -307,6 +353,8 @@
   hb_test_add (test_subset_cff1_expert);
   hb_test_add (test_subset_cff1_seac);
   hb_test_add (test_subset_cff1_dotsection);
+  hb_test_add (test_subset_cff1_retaingids);
+  hb_test_add (test_subset_cff1_j_retaingids);
 
   return hb_test_run ();
 }
diff --git a/test/api/test-subset-cff2.c b/test/api/test-subset-cff2.c
index 9367965..7ffcf5e 100644
--- a/test/api/test-subset-cff2.c
+++ b/test/api/test-subset-cff2.c
@@ -138,6 +138,29 @@
   hb_face_destroy (face_ac);
 }
 
+static void
+test_subset_cff2_retaingids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.retaingids.otf");
+
+  hb_set_t *codepoints = hb_set_create ();
+  hb_subset_input_t *input;
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'c');
+  input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_retain_gids (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', '2'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -148,6 +171,7 @@
   hb_test_add (test_subset_cff2_strip_hints);
   hb_test_add (test_subset_cff2_desubr);
   hb_test_add (test_subset_cff2_desubr_strip_hints);
+  hb_test_add (test_subset_cff2_retaingids);
 
   return hb_test_run ();
 }
diff --git a/test/api/test-subset-drop-tables.c b/test/api/test-subset-drop-tables.c
new file mode 100644
index 0000000..e234080
--- /dev/null
+++ b/test/api/test-subset-drop-tables.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2019  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+/* Unit tests for hb-subset.cc drop tables functionality */
+
+static void
+test_subset_drop_tables (void)
+{
+  hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 99);
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'd', 'm', 'x'));
+  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG ('h', 'm', 't', 'x'));
+  hb_set_destroy (codepoints);
+
+  hb_face_t* subset = hb_subset (face, input);
+
+  hb_blob_t *hdmx = hb_face_reference_table (subset, HB_TAG ('h', 'd', 'm', 'x'));
+  hb_blob_t *hmtx = hb_face_reference_table (subset, HB_TAG ('h', 'm', 't', 'x'));
+  hb_blob_t *cmap = hb_face_reference_table (subset, HB_TAG ('c', 'm', 'a', 'p'));
+  g_assert (!hb_blob_get_length (hdmx));
+  g_assert (!hb_blob_get_length (hmtx));
+  g_assert ( hb_blob_get_length (cmap));
+  hb_blob_destroy (hdmx);
+  hb_blob_destroy (hmtx);
+  hb_blob_destroy (cmap);
+
+  hb_face_destroy (subset);
+  hb_subset_input_destroy (input);
+  hb_face_destroy (face);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_drop_tables);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 0e5c293..2b330ce 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -70,6 +70,29 @@
   face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
   hb_set_destroy (codepoints);
 
+  check_maxp_num_glyphs(face_abc_subset, 3, true);
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_glyf_with_input_glyphs (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
+
+  hb_set_t *glyphs = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (glyphs, 1);
+  hb_set_add (glyphs, 3);
+  face_abc_subset =
+      hb_subset_test_create_subset (face_abc, hb_subset_test_create_input_from_glyphs (glyphs));
+  hb_set_destroy (glyphs);
+
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
   check_maxp_num_glyphs(face_abc_subset, 3, true);
@@ -114,7 +137,9 @@
 
   input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  hb_subset_input_set_drop_layout (input, false);
+  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
+  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
+  hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
 
   face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -141,7 +166,9 @@
 
   input = hb_subset_test_create_input (codepoints);
   hb_set_destroy (codepoints);
-  hb_subset_input_set_drop_layout (input, true);
+  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'S', 'U', 'B'));
+  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'P', 'O', 'S'));
+  hb_set_add (hb_subset_input_drop_tables_set (input), HB_TAG('G', 'D', 'E', 'F'));
 
   face_subset = hb_subset_test_create_subset (face_fil, input);
 
@@ -167,9 +194,9 @@
   face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
   hb_set_destroy (codepoints);
 
-  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
-  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
   check_maxp_num_glyphs(face_abc_subset, 4, true);
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
 
   hb_face_destroy (face_abc_subset);
   hb_face_destroy (face_abc);
@@ -191,9 +218,9 @@
   face_abc_subset = hb_subset_test_create_subset (face_abc, input);
   hb_set_destroy (codepoints);
 
+  check_maxp_num_glyphs(face_abc_subset, 3, false);
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
-  check_maxp_num_glyphs(face_abc_subset, 3, false);
 
   hb_face_destroy (face_abc_subset);
   hb_face_destroy (face_abc);
@@ -216,9 +243,9 @@
   face_generated_subset = hb_subset_test_create_subset (face_components, input);
   hb_set_destroy (codepoints);
 
-  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
-  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
   check_maxp_num_glyphs(face_generated_subset, 4, false);
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
 
   hb_face_destroy (face_generated_subset);
   hb_face_destroy (face_subset);
@@ -257,6 +284,55 @@
   hb_face_destroy (face);
 }
 
+static void
+test_subset_glyf_retain_gids (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.retaingids.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+  hb_set_add (codepoints, 99);
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_retain_gids (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  check_maxp_num_glyphs(face_abc_subset, 4, true);
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_ac);
+}
+
+static void
+test_subset_glyf_retain_gids_truncates (void)
+{
+  hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
+  hb_face_t *face_a = hb_test_open_font_file ("fonts/Roboto-Regular.a.retaingids.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_face_t *face_abc_subset;
+  hb_set_add (codepoints, 97);
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_subset_input_set_retain_gids (input, true);
+  face_abc_subset = hb_subset_test_create_subset (face_abc, input);
+  hb_set_destroy (codepoints);
+
+  check_maxp_num_glyphs(face_abc_subset, 2, true);
+  hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('l','o','c', 'a'));
+  hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('g','l','y','f'));
+
+  hb_face_destroy (face_abc_subset);
+  hb_face_destroy (face_abc);
+  hb_face_destroy (face_a);
+}
+
 // TODO(grieger): test for long loca generation.
 
 int
@@ -266,12 +342,15 @@
 
   hb_test_add (test_subset_glyf_noop);
   hb_test_add (test_subset_glyf);
+  hb_test_add (test_subset_glyf_with_input_glyphs);
   hb_test_add (test_subset_glyf_strip_hints_simple);
   hb_test_add (test_subset_glyf_strip_hints_composite);
   hb_test_add (test_subset_glyf_strip_hints_invalid);
   hb_test_add (test_subset_glyf_with_components);
   hb_test_add (test_subset_glyf_with_gsub);
   hb_test_add (test_subset_glyf_without_gsub);
+  hb_test_add (test_subset_glyf_retain_gids);
+  hb_test_add (test_subset_glyf_retain_gids_truncates);
 
   return hb_test_run();
 }
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index 44e579a..7178833 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -92,28 +92,6 @@
 }
 
 static void
-test_subset_hdmx_fails_sanitize (void)
-{
-  hb_face_t *face = hb_test_open_font_file ("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016");
-
-  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
-  hb_set_t *codepoints = hb_subset_input_unicode_set (input);
-  hb_face_t *subset;
-
-  hb_set_add (codepoints, 'a');
-  hb_set_add (codepoints, 'b');
-  hb_set_add (codepoints, 'c');
-
-  subset = hb_subset (face, input);
-  g_assert (subset);
-  g_assert (subset == hb_face_get_empty ());
-
-  hb_subset_input_destroy (input);
-  hb_face_destroy (subset);
-  hb_face_destroy (face);
-}
-
-static void
 test_subset_hdmx_noop (void)
 {
   hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
@@ -140,7 +118,6 @@
   hb_test_add (test_subset_hdmx_simple_subset);
   hb_test_add (test_subset_hdmx_multiple_device_records);
   hb_test_add (test_subset_hdmx_invalid);
-  hb_test_add (test_subset_hdmx_fails_sanitize);
   hb_test_add (test_subset_hdmx_noop);
 
   return hb_test_run();
diff --git a/test/api/test-subset-nameids.c b/test/api/test-subset-nameids.c
new file mode 100644
index 0000000..b58a86c
--- /dev/null
+++ b/test/api/test-subset-nameids.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "hb-test.h"
+#include "hb-subset-test.h"
+
+static void
+test_subset_nameids (void)
+{
+  hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.origin.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.expected.ttf");
+
+  hb_set_t *name_ids = hb_set_create();
+  hb_face_t *face_subset;
+  hb_set_add (name_ids, 0);
+  hb_set_add (name_ids, 9);
+  face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input_from_nameids (name_ids));
+  hb_set_destroy (name_ids);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_origin);
+  hb_face_destroy (face_expected);
+}
+
+static void
+test_subset_nameids_with_dup_strs (void)
+{
+  hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.dup.origin.ttf");
+  hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.dup.expected.ttf");
+
+  hb_set_t *name_ids = hb_set_create();
+  hb_face_t *face_subset;
+  hb_set_add (name_ids, 1);
+  hb_set_add (name_ids, 3);
+  face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input_from_nameids (name_ids));
+  hb_set_destroy (name_ids);
+
+  hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e'));
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_origin);
+  hb_face_destroy (face_expected);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_subset_nameids);
+  hb_test_add (test_subset_nameids_with_dup_strs);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c
index 6195bb2..71a471d 100644
--- a/test/api/test-unicode.c
+++ b/test/api/test-unicode.c
@@ -62,8 +62,8 @@
 
 static hb_script_t
 simple_get_script (hb_unicode_funcs_t *ufuncs,
-                   hb_codepoint_t      codepoint,
-                   void               *user_data)
+		   hb_codepoint_t      codepoint,
+		   void               *user_data)
 {
   data_t *data = (data_t *) user_data;
 
@@ -79,8 +79,8 @@
 
 static hb_script_t
 a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs,
-                            hb_codepoint_t      codepoint,
-                            void               *user_data)
+			    hb_codepoint_t      codepoint,
+			    void               *user_data)
 {
   data_t *data = (data_t *) user_data;
 
@@ -157,6 +157,27 @@
   /* Unicode-6.0 character additions */
   {   0x135D, 230 },
 
+  /* Unicode-6.1 character additions */
+  {   0xA674, 230 },
+
+  /* Unicode-7.0 character additions */
+  {   0x1AB0, 230 },
+
+  /* Unicode-8.0 character additions */
+  {   0xA69E, 230 },
+
+  /* Unicode-9.0 character additions */
+  {  0x1E000, 230 },
+
+  /* Unicode-10.0 character additions */
+  {   0x1DF6, 232 },
+
+  /* Unicode-11.0 character additions */
+  {   0x07FD, 220 },
+
+  /* Unicode-12.0 character additions */
+  {   0x0EBA,   9 },
+
   { 0x111111, 0 }
 };
 
@@ -204,6 +225,36 @@
   /* Unicode-6.0 character additions */
   {   0x0620, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER },
 
+  /* Unicode-6.1 character additions */
+  {   0x058F, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
+
+  /* Unicode-6.2 character additions */
+  {   0x20BA, HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL },
+
+  /* Unicode-6.3 character additions */
+  {   0x061C, HB_UNICODE_GENERAL_CATEGORY_FORMAT },
+
+  /* Unicode-7.0 character additions */
+  {   0x058D, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
+
+  /* Unicode-8.0 character additions */
+  {   0x08E3, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK },
+
+  /* Unicode-9.0 character additions */
+  {   0x08D4, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK },
+
+  /* Unicode-10.0 character additions */
+  {   0x09FD, HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION },
+
+  /* Unicode-11.0 character additions */
+  {   0x0560, HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER },
+
+  /* Unicode-12.0 character additions */
+  {   0x0C77, HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION },
+
+  /* Unicode-12.1 character additions */
+  {   0x32FF, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL },
+
   { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED }
 };
 
@@ -242,7 +293,12 @@
 };
 static const test_pair_t mirroring_tests_more[] =
 {
-  /* No new mirroring characters have been encoded in recent Unicode versions. */
+  /* Unicode-6.1 character additions */
+  {   0x27CB, 0x27CD },
+
+  /* Unicode-11.0 character additions */
+  {   0x2BFE, 0x221F },
+
   { 0x111111, 0x111111 }
 };
 
@@ -342,8 +398,10 @@
   /* Unicode-5.2 additions */
   {  0x10B00, HB_SCRIPT_AVESTAN },
   {   0xA6A0, HB_SCRIPT_BAMUM },
+  {   0x1400, HB_SCRIPT_CANADIAN_ABORIGINAL },
   {  0x13000, HB_SCRIPT_EGYPTIAN_HIEROGLYPHS },
   {  0x10840, HB_SCRIPT_IMPERIAL_ARAMAIC },
+  {   0x1CED, HB_SCRIPT_INHERITED },
   {  0x10B60, HB_SCRIPT_INSCRIPTIONAL_PAHLAVI },
   {  0x10B40, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN },
   {   0xA980, HB_SCRIPT_JAVANESE },
@@ -361,9 +419,85 @@
   {  0x11000, HB_SCRIPT_BRAHMI },
   {   0x0840, HB_SCRIPT_MANDAIC },
 
-  /* Unicode-5.2 character additions */
-  {   0x1CED, HB_SCRIPT_INHERITED },
-  {   0x1400, HB_SCRIPT_CANADIAN_ABORIGINAL },
+  /* Unicode-6.1 additions */
+  {  0x10980, HB_SCRIPT_MEROITIC_HIEROGLYPHS },
+  {  0x109A0, HB_SCRIPT_MEROITIC_CURSIVE },
+  {  0x110D0, HB_SCRIPT_SORA_SOMPENG },
+  {  0x11100, HB_SCRIPT_CHAKMA },
+  {  0x11180, HB_SCRIPT_SHARADA },
+  {  0x11680, HB_SCRIPT_TAKRI },
+  {  0x16F00, HB_SCRIPT_MIAO },
+
+  /* Unicode-6.2 additions */
+  {   0x20BA, HB_SCRIPT_COMMON },
+
+  /* Unicode-6.3 additions */
+  {   0x2066, HB_SCRIPT_COMMON },
+
+  /* Unicode-7.0 additions */
+  {   0x10350, HB_SCRIPT_OLD_PERMIC },
+  {   0x10500, HB_SCRIPT_ELBASAN },
+  {   0x10530, HB_SCRIPT_CAUCASIAN_ALBANIAN },
+  {   0x10600, HB_SCRIPT_LINEAR_A },
+  {   0x10860, HB_SCRIPT_PALMYRENE },
+  {   0x10880, HB_SCRIPT_NABATAEAN },
+  {   0x10A80, HB_SCRIPT_OLD_NORTH_ARABIAN },
+  {   0x10AC0, HB_SCRIPT_MANICHAEAN },
+  {   0x10B80, HB_SCRIPT_PSALTER_PAHLAVI },
+  {   0x11150, HB_SCRIPT_MAHAJANI },
+  {   0x11200, HB_SCRIPT_KHOJKI },
+  {   0x112B0, HB_SCRIPT_KHUDAWADI },
+  {   0x11300, HB_SCRIPT_GRANTHA },
+  {   0x11480, HB_SCRIPT_TIRHUTA },
+  {   0x11580, HB_SCRIPT_SIDDHAM },
+  {   0x11600, HB_SCRIPT_MODI },
+  {   0x118A0, HB_SCRIPT_WARANG_CITI },
+  {   0x11AC0, HB_SCRIPT_PAU_CIN_HAU },
+  {   0x16A40, HB_SCRIPT_MRO },
+  {   0x16AD0, HB_SCRIPT_BASSA_VAH },
+  {   0x16B00, HB_SCRIPT_PAHAWH_HMONG },
+  {   0x1BC00, HB_SCRIPT_DUPLOYAN },
+  {   0x1E800, HB_SCRIPT_MENDE_KIKAKUI },
+
+  /* Unicode-8.0 additions */
+  {   0x108E0, HB_SCRIPT_HATRAN },
+  {   0x10C80, HB_SCRIPT_OLD_HUNGARIAN },
+  {   0x11280, HB_SCRIPT_MULTANI },
+  {   0x11700, HB_SCRIPT_AHOM },
+  {   0x14400, HB_SCRIPT_ANATOLIAN_HIEROGLYPHS },
+  {   0x1D800, HB_SCRIPT_SIGNWRITING },
+
+  /* Unicode-9.0 additions */
+  {   0x104B0, HB_SCRIPT_OSAGE },
+  {   0x11400, HB_SCRIPT_NEWA },
+  {   0x11C00, HB_SCRIPT_BHAIKSUKI },
+  {   0x11C70, HB_SCRIPT_MARCHEN },
+  {   0x17000, HB_SCRIPT_TANGUT },
+  {   0x1E900, HB_SCRIPT_ADLAM },
+
+  /* Unicode-10.0 additions */
+  {   0x11A00, HB_SCRIPT_ZANABAZAR_SQUARE },
+  {   0x11A50, HB_SCRIPT_SOYOMBO },
+  {   0x11D00, HB_SCRIPT_MASARAM_GONDI },
+  {   0x1B170, HB_SCRIPT_NUSHU },
+
+  /* Unicode-11.0 additions */
+  {   0x10D00, HB_SCRIPT_HANIFI_ROHINGYA },
+  {   0x10F00, HB_SCRIPT_OLD_SOGDIAN },
+  {   0x10F30, HB_SCRIPT_SOGDIAN },
+  {   0x11800, HB_SCRIPT_DOGRA },
+  {   0x11D60, HB_SCRIPT_GUNJALA_GONDI },
+  {   0x11EE0, HB_SCRIPT_MAKASAR },
+  {   0x16E40, HB_SCRIPT_MEDEFAIDRIN },
+
+  /* Unicode-12.0 additions */
+  {   0x10FE0, HB_SCRIPT_ELYMAIC },
+  {   0x119A0, HB_SCRIPT_NANDINAGARI },
+  {   0x1E100, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG },
+  {   0x1E2C0, HB_SCRIPT_WANCHO },
+
+  /* Unicode-12.1 additions */
+  {   0x32FF, HB_SCRIPT_COMMON },
 
   { 0x111111, HB_SCRIPT_UNKNOWN }
 };
@@ -413,7 +547,7 @@
 #undef PROPERTY
 
 static void
-test_unicode_properties (gconstpointer user_data)
+test_unicode_properties (gconstpointer user_data, hb_bool_t lenient)
 {
   hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
   unsigned int i, j;
@@ -437,16 +571,30 @@
     tests = p->tests_more;
     for (j = 0; j < p->num_tests_more; j++) {
       g_test_message ("Test %s more #%d: U+%04X", p->name, j, tests[j].unicode);
-      if (p->getter (uf, tests[j].unicode) != tests[j].value) {
-	g_test_message ("Soft fail: Received %x, expected %x", p->getter (uf, tests[j].unicode), tests[j].value);
-        failed = TRUE;
+      if (lenient) {
+	if (p->getter (uf, tests[j].unicode) != tests[j].value) {
+	  g_test_message ("Soft fail: Received %x, expected %x", p->getter (uf, tests[j].unicode), tests[j].value);
+	  failed = TRUE;
+	}
       }
+      else
+	g_assert_cmphex (p->getter (uf, tests[j].unicode), ==, tests[j].value);
     }
   }
 
   if (failed)
     g_test_message ("Some property tests failed.  You probably have an old version of one of the libraries used.");
 }
+static void
+test_unicode_properties_lenient (gconstpointer user_data)
+{
+  test_unicode_properties (user_data, TRUE);
+}
+static void
+test_unicode_properties_strict (gconstpointer user_data)
+{
+  test_unicode_properties (user_data, FALSE);
+}
 
 static hb_codepoint_t
 default_value (hb_codepoint_t _default_value, hb_codepoint_t unicode)
@@ -529,7 +677,7 @@
 
   g_assert (!hb_unicode_funcs_is_immutable (uf2));
   hb_unicode_funcs_make_immutable (uf2);
-  test_unicode_properties (uf2);
+  test_unicode_properties_strict (uf2);
 
   hb_unicode_funcs_destroy (uf2);
 
@@ -603,7 +751,7 @@
   hb_unicode_funcs_destroy (uf);
 
   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
-                                    &f->data[1], free_up);
+				    &f->data[1], free_up);
 
   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN);
@@ -622,7 +770,7 @@
   aa = hb_unicode_funcs_create (uf);
 
   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
-                                    &f->data[1], free_up);
+				    &f->data[1], free_up);
 
   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
@@ -640,7 +788,7 @@
   uf = hb_unicode_funcs_create (NULL);
 
   hb_unicode_funcs_set_script_func (uf, simple_get_script,
-                                    &f->data[0], free_up);
+				    &f->data[0], free_up);
 
   aa = hb_unicode_funcs_create (uf);
 
@@ -650,7 +798,7 @@
   g_assert (!f->data[0].freed);
 
   hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script,
-                                    &f->data[1], free_up);
+				    &f->data[1], free_up);
 
   g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC);
   g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN);
@@ -755,6 +903,10 @@
   g_assert (hb_unicode_compose (uf, 0xCE20, 0x11B8, &ab) && ab == 0xCE31);
   g_assert (hb_unicode_compose (uf, 0x110E, 0x1173, &ab) && ab == 0xCE20);
 
+  g_assert (!hb_unicode_compose (uf, 0xAC00, 0x11A7, &ab));
+  g_assert (hb_unicode_compose (uf, 0xAC00, 0x11A8, &ab) && ab == 0xAC01);
+  g_assert (!hb_unicode_compose (uf, 0xAC01, 0x11A8, &ab));
+
 
   /* Test decompose() */
 
@@ -796,16 +948,16 @@
   hb_test_add (test_unicode_properties_nil);
   hb_test_add (test_unicode_properties_empty);
 
-  hb_test_add_data_flavor (hb_unicode_funcs_get_default (),          "default", test_unicode_properties);
+  hb_test_add_data_flavor (hb_unicode_funcs_get_default (),          "default", test_unicode_properties_strict);
   hb_test_add_data_flavor (hb_unicode_funcs_get_default (),          "default", test_unicode_normalization);
   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_default, "default", test_unicode_script_roundtrip);
 #ifdef HAVE_GLIB
-  hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),             "glib",    test_unicode_properties);
+  hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),             "glib",    test_unicode_properties_lenient);
   hb_test_add_data_flavor (hb_glib_get_unicode_funcs (),             "glib",    test_unicode_normalization);
   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_glib,    "glib",    test_unicode_script_roundtrip);
 #endif
 #ifdef HAVE_ICU
-  hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),              "icu",     test_unicode_properties);
+  hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),              "icu",     test_unicode_properties_lenient);
   hb_test_add_data_flavor (hb_icu_get_unicode_funcs (),              "icu",     test_unicode_normalization);
   hb_test_add_data_flavor ((gconstpointer) script_roundtrip_icu,     "icu",     test_unicode_script_roundtrip);
 #endif
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index a77df70..5bd2d7e 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -55,8 +55,8 @@
 hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la
 
 check:
-	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py
-	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-subset-fuzzer-tests.py
+	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-shape-fuzzer-tests.py
+	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-subset-fuzzer-tests.py
 check-valgrind:
 	$(AM_V_at)RUN_VALGRIND=1 $(MAKE) $(AM_MAKEFLGS) check
 
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016
new file mode 100644
index 0000000..9cde3b9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5093685255077888 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5093685255077888
new file mode 100644
index 0000000..e65025e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5093685255077888
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5126525414014976 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5126525414014976
new file mode 100644
index 0000000..74cc027
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5126525414014976
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5166320261529600 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5166320261529600
new file mode 100644
index 0000000..b79765a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5166320261529600
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5662548265009152 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5662548265009152
new file mode 100644
index 0000000..0b68a30
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5662548265009152
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5702671124791296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5702671124791296
new file mode 100644
index 0000000..9ecc7f1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5702671124791296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5748102301614080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5748102301614080
new file mode 100644
index 0000000..4cb979d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5748102301614080
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6252118652092416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6252118652092416
new file mode 100644
index 0000000..e2dd6a3
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6252118652092416
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5631444412530688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5631444412530688
new file mode 100644
index 0000000..25f7d69
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5631444412530688
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5667182741028864 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5667182741028864
new file mode 100644
index 0000000..0c40dd8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5667182741028864
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5077547978588160 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5077547978588160
new file mode 100644
index 0000000..37bb009
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5077547978588160
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5634197349203968 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5634197349203968
new file mode 100644
index 0000000..39e8bd9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5634197349203968
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184
new file mode 100644
index 0000000..b11bd87
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872
new file mode 100644
index 0000000..51ab2fe
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344
new file mode 100644
index 0000000..e08ab56
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776
new file mode 100644
index 0000000..3881fbe
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5676773460672512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5676773460672512
new file mode 100644
index 0000000..4fc920b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5676773460672512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856
new file mode 100644
index 0000000..72147f6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5680398559870976 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5680398559870976
new file mode 100644
index 0000000..5c7b6b5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5680398559870976
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696825891225600 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696825891225600
new file mode 100644
index 0000000..30515a4
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696825891225600
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440
new file mode 100644
index 0000000..6391320
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904
new file mode 100644
index 0000000..683ef99
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960
new file mode 100644
index 0000000..e099413
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960
new file mode 100644
index 0000000..0264a15
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5739000398086144 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5739000398086144
new file mode 100644
index 0000000..0dec23f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5739000398086144
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624
new file mode 100644
index 0000000..3a7cc9d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5760768497156096 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5760768497156096
new file mode 100644
index 0000000..063aab2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5760768497156096
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5761434614497280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5761434614497280
new file mode 100644
index 0000000..0060ade
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5761434614497280
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576
new file mode 100644
index 0000000..da1b718
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764268627066880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764268627066880
new file mode 100644
index 0000000..2b49553
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764268627066880
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056
new file mode 100644
index 0000000..0a3c6df
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056
Binary files differ
diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc
index 5723db9..64a6b12 100644
--- a/test/fuzzing/hb-shape-fuzzer.cc
+++ b/test/fuzzing/hb-shape-fuzzer.cc
@@ -10,7 +10,7 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   hb_blob_t *blob = hb_blob_create ((const char *)data, size,
-				    HB_MEMORY_MODE_READONLY, NULL, NULL);
+				    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
   hb_face_t *face = hb_face_create (blob, 0);
   hb_font_t *font = hb_font_create (face);
   hb_ot_font_set_funcs (font);
@@ -21,7 +21,7 @@
     hb_buffer_t *buffer = hb_buffer_create ();
     hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
     hb_buffer_guess_segment_properties (buffer);
-    hb_shape (font, buffer, NULL, 0);
+    hb_shape (font, buffer, nullptr, 0);
     hb_buffer_destroy (buffer);
   }
 
@@ -34,7 +34,7 @@
   hb_buffer_t *buffer = hb_buffer_create ();
   hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
   hb_buffer_guess_segment_properties (buffer);
-  hb_shape (font, buffer, NULL, 0);
+  hb_shape (font, buffer, nullptr, 0);
   hb_buffer_destroy (buffer);
 
   /* Misc calls on face. */
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index 3a71f22..428765e 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
 
 #include "hb-subset.h"
 
@@ -11,19 +12,40 @@
 	   const hb_codepoint_t text[],
 	   int text_length,
 	   bool drop_hints,
-	   bool drop_layout)
+	   bool drop_layout,
+	   bool retain_gids)
 {
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
   hb_subset_input_set_drop_hints (input, drop_hints);
-  hb_subset_input_set_drop_layout (input, drop_layout);
+  hb_subset_input_set_retain_gids (input, retain_gids);
   hb_set_t *codepoints = hb_subset_input_unicode_set (input);
 
+  if (!drop_layout)
+  {
+    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'S', 'U', 'B'));
+    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'P', 'O', 'S'));
+    hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'D', 'E', 'F'));
+  }
+
   for (int i = 0; i < text_length; i++)
   {
     hb_set_add (codepoints, text[i]);
   }
 
   hb_face_t *result = hb_subset (face, input);
+  {
+    hb_blob_t *blob = hb_face_reference_blob (result);
+    unsigned int length;
+    const char *data = hb_blob_get_data (blob, &length);
+
+    // Something not optimizable just to access all the blob data
+    unsigned int bytes_count = 0;
+    for (unsigned int i = 0; i < length; ++i)
+      if (data[i]) ++bytes_count;
+    assert (bytes_count || !length);
+
+    hb_blob_destroy (blob);
+  }
   hb_face_destroy (result);
 
   hb_subset_input_destroy (input);
@@ -32,22 +54,20 @@
 static void
 trySubset (hb_face_t *face,
 	   const hb_codepoint_t text[],
-	   int text_length)
+	   int text_length,
+	   const uint8_t flags[1])
 {
-  for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
-  {
-    for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++)
-    {
-      trySubset (face, text, text_length,
-		 (bool) drop_hints, (bool) drop_layout);
-    }
-  }
+  bool drop_hints =  flags[0] & (1 << 0);
+  bool drop_layout = flags[0] & (1 << 1);
+  bool retain_gids = flags[0] & (1 << 2);
+  trySubset (face, text, text_length,
+	     drop_hints, drop_layout, retain_gids);
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   hb_blob_t *blob = hb_blob_create ((const char *)data, size,
-				    HB_MEMORY_MODE_READONLY, NULL, NULL);
+				    HB_MEMORY_MODE_READONLY, nullptr, nullptr);
   hb_face_t *face = hb_face_create (blob, 0);
 
   /* Just test this API here quickly. */
@@ -55,21 +75,27 @@
   hb_face_collect_unicodes (face, output);
   hb_set_destroy (output);
 
+  uint8_t flags[1] = {0};
   const hb_codepoint_t text[] =
       {
 	'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
 	'3', '@', '_', '%', '&', ')', '*', '$', '!'
       };
 
-  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t));
+  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags);
 
   hb_codepoint_t text_from_data[16];
-  if (size > sizeof(text_from_data)) {
+  if (size > sizeof(text_from_data) + sizeof(flags)) {
     memcpy (text_from_data,
 	    data + size - sizeof(text_from_data),
 	    sizeof(text_from_data));
+
+    memcpy (flags,
+	    data + size - sizeof(text_from_data) - sizeof(flags),
+	    sizeof(flags));
     unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
-    trySubset (face, text_from_data, text_size);
+
+    trySubset (face, text_from_data, text_size, flags);
   }
 
   hb_face_destroy (face);
diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc
index f15247c..5318f64 100644
--- a/test/fuzzing/main.cc
+++ b/test/fuzzing/main.cc
@@ -4,8 +4,10 @@
 #include <stdlib.h>
 #include <assert.h>
 
-int main(int argc, char **argv) {
+int main (int argc, char **argv)
+{
   hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+
   unsigned int len;
   const char *font_data = hb_blob_get_data (blob, &len);
   if (len == 0)
@@ -14,10 +16,13 @@
     exit (1);
   }
 
-  for (int i = 1; i < argc; i++) {
+  for (int i = 1; i < argc; i++)
+  {
     printf ("%s\n", argv[i]);
-    LLVMFuzzerTestOneInput((const uint8_t *) font_data, len);
+    LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len);
   }
 
   hb_blob_destroy (blob);
+
+  return 0;
 }
diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py
index e3d180f..94fc877 100755
--- a/test/fuzzing/run-shape-fuzzer-tests.py
+++ b/test/fuzzing/run-shape-fuzzer-tests.py
@@ -5,41 +5,47 @@
 import sys, os, subprocess, tempfile, threading
 
 
-def which(program):
+def which (program):
 	# https://stackoverflow.com/a/377028
-	def is_exe(fpath):
-		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+	def is_exe (fpath):
+		return os.path.isfile (fpath) and os.access (fpath, os.X_OK)
 
-	fpath, _ = os.path.split(program)
+	fpath, _ = os.path.split (program)
 	if fpath:
-		if is_exe(program):
+		if is_exe (program):
 			return program
 	else:
-		for path in os.environ["PATH"].split(os.pathsep):
-			exe_file = os.path.join(path, program)
-			if is_exe(exe_file):
+		for path in os.environ["PATH"].split (os.pathsep):
+			exe_file = os.path.join (path, program)
+			if is_exe (exe_file):
 				return exe_file
 
 	return None
 
 
-def cmd(command):
+def cmd (command):
 	# https://stackoverflow.com/a/4408409
 	# https://stackoverflow.com/a/10012262
-	with tempfile.TemporaryFile() as tempf:
+	with tempfile.TemporaryFile () as tempf:
 		p = subprocess.Popen (command, stderr=tempf)
 		is_killed = {'value': False}
 
-		def timeout(p, is_killed):
+		def timeout (p, is_killed):
 			is_killed['value'] = True
-			p.kill()
-		timer = threading.Timer (2, timeout, [p, is_killed])
+			p.kill ()
+		timeout_seconds = int (os.environ.get ("HB_TEST_SHAPE_FUZZER_TIMEOUT", "2"))
+		timer = threading.Timer (timeout_seconds, timeout, [p, is_killed])
 
 		try:
 			timer.start()
 			p.wait ()
 			tempf.seek (0)
-			text = tempf.read().decode ("utf-8").strip ()
+			text = tempf.read ()
+
+			#TODO: Detect debug mode with a better way
+			is_debug_mode = b"SANITIZE" in text
+
+			text = "" if is_debug_mode else text.decode ("utf-8").strip ()
 			returncode = p.returncode
 		finally:
 			timer.cancel()
@@ -67,33 +73,36 @@
 print ('hb_shape_fuzzer:', hb_shape_fuzzer)
 fails = 0
 
+libtool = os.environ.get ('LIBTOOL')
 valgrind = None
-if os.environ.get('RUN_VALGRIND', ''):
+if os.environ.get ('RUN_VALGRIND', ''):
 	valgrind = which ('valgrind')
+	if valgrind is None:
+		print ("""Valgrind requested but not found.""")
+		sys.exit (1)
+	if libtool is None:
+		print ("""Valgrind support is currently autotools only and needs libtool but not found.""")
+
 
 parent_path = os.path.join (srcdir, "fonts")
 for file in os.listdir (parent_path):
-	path = os.path.join(parent_path, file)
-
-	text, returncode = cmd ([hb_shape_fuzzer, path])
-	if text.strip ():
-		print (text)
-
-	failed = False
-	if returncode != 0 or 'error' in text:
-		print ('failure on %s' % file)
-		failed = True
+	path = os.path.join (parent_path, file)
 
 	if valgrind:
-		text, returncode = cmd ([valgrind, '--error-exitcode=1', hb_shape_fuzzer, path])
-		if returncode:
-			print (text)
-			print ('failure on %s' % file)
-			failed = True
+		text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --error-exitcode=1', '--', hb_shape_fuzzer, path])
+	else:
+		text, returncode = cmd ([hb_shape_fuzzer, path])
+		if 'error' in text:
+			returncode = 1
 
-	if failed:
+	if (not valgrind or returncode) and text.strip ():
+		print (text)
+
+	if returncode != 0:
+		print ('failure on %s' % file)
 		fails = fails + 1
 
+
 if fails:
 	print ("%i shape fuzzer related tests failed." % fails)
 	sys.exit (1)
diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py
index 7392a92..f290e6e 100755
--- a/test/fuzzing/run-subset-fuzzer-tests.py
+++ b/test/fuzzing/run-subset-fuzzer-tests.py
@@ -2,7 +2,60 @@
 
 from __future__ import print_function, division, absolute_import
 
-import sys, os, subprocess
+import sys, os, subprocess, tempfile, threading
+
+
+def which(program):
+	# https://stackoverflow.com/a/377028
+	def is_exe(fpath):
+		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+	fpath, _ = os.path.split(program)
+	if fpath:
+		if is_exe(program):
+			return program
+	else:
+		for path in os.environ["PATH"].split(os.pathsep):
+			exe_file = os.path.join(path, program)
+			if is_exe(exe_file):
+				return exe_file
+
+	return None
+
+
+def cmd(command):
+	# https://stackoverflow.com/a/4408409
+	# https://stackoverflow.com/a/10012262
+	with tempfile.TemporaryFile() as tempf:
+		p = subprocess.Popen (command, stderr=tempf)
+		is_killed = {'value': False}
+
+		def timeout(p, is_killed):
+			is_killed['value'] = True
+			p.kill()
+		timeout_seconds = int (os.environ.get ("HB_TEST_SUBSET_FUZZER_TIMEOUT", "8"))
+		timer = threading.Timer (timeout_seconds, timeout, [p, is_killed])
+
+		try:
+			timer.start()
+			p.wait ()
+			tempf.seek (0)
+			text = tempf.read ()
+
+			#TODO: Detect debug mode with a better way
+			is_debug_mode = b"SANITIZE" in text
+
+			text = "" if is_debug_mode else text.decode ("utf-8").strip ()
+			returncode = p.returncode
+		finally:
+			timer.cancel()
+
+		if is_killed['value']:
+			text = 'error: timeout, ' + text
+			returncode = 1
+
+		return text, returncode
+
 
 srcdir = os.environ.get ("srcdir", ".")
 EXEEXT = os.environ.get ("EXEEXT", "")
@@ -20,25 +73,42 @@
 print ('hb_subset_fuzzer:', hb_subset_fuzzer)
 fails = 0
 
+libtool = os.environ.get('LIBTOOL')
+valgrind = None
+if os.environ.get('RUN_VALGRIND', ''):
+	valgrind = which ('valgrind')
+	if valgrind is None:
+		print ("""Valgrind requested but not found.""")
+		sys.exit (1)
+	if libtool is None:
+		print ("""Valgrind support is currently autotools only and needs libtool but not found.""")
+
+
 def run_dir (parent_path):
 	global fails
 	for file in os.listdir (parent_path):
 		path = os.path.join(parent_path, file)
+		# TODO: Run on all the fonts not just subset related ones
+		if "subset" not in path: continue
 
 		print ("running subset fuzzer against %s" % path)
-		p = subprocess.Popen ([hb_subset_fuzzer, path])
+		if valgrind:
+			text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --show-leak-kinds=all --error-exitcode=1', '--', hb_subset_fuzzer, path])
+		else:
+			text, returncode = cmd ([hb_subset_fuzzer, path])
+			if 'error' in text:
+				returncode = 1
 
-		if p.wait () != 0:
+		if (not valgrind or returncode) and text.strip ():
+			print (text)
+
+		if returncode != 0:
 			print ("failed for %s" % path)
 			fails = fails + 1
 
-		if p.wait () != 0:
-			print ("failed for %s" % path)
-			fails = fails + 1
 
 run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts"))
-# TODO running these tests very slow tests.  Fix and re-enable
-#run_dir (os.path.join (srcdir, "fonts"))
+run_dir (os.path.join (srcdir, "fonts"))
 
 if fails:
         print ("%i subset fuzzer related tests failed." % fails)
diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources
index 0e9a3a2..bf14a98 100644
--- a/test/shaping/data/in-house/Makefile.sources
+++ b/test/shaping/data/in-house/Makefile.sources
@@ -41,6 +41,7 @@
 	tests/myanmar-syllable.tests \
 	tests/myanmar-zawgyi.tests \
 	tests/none-directional.tests \
+	tests/positioning-features.tests \
 	tests/rand.tests \
 	tests/spaces.tests \
 	tests/simple.tests \
diff --git a/test/shaping/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf b/test/shaping/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf
new file mode 100644
index 0000000..945d698
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf b/test/shaping/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf
new file mode 100644
index 0000000..f3d52e5
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf b/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
new file mode 100644
index 0000000..f1b84a4
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf b/test/shaping/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf
new file mode 100644
index 0000000..8cc4bb0
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf b/test/shaping/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf
new file mode 100644
index 0000000..31d4e50
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf b/test/shaping/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf
new file mode 100644
index 0000000..ffbbc0e
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf b/test/shaping/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf
new file mode 100644
index 0000000..be48fd0
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf b/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf
new file mode 100644
index 0000000..b1a8a33
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/tests/aat-trak.tests b/test/shaping/data/in-house/tests/aat-trak.tests
index 4bbe729..6da3ba8 100644
--- a/test/shaping/data/in-house/tests/aat-trak.tests
+++ b/test/shaping/data/in-house/tests/aat-trak.tests
@@ -1,11 +1,11 @@
 ../fonts/TRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
 ../fonts/TRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
 ../fonts/TRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
-../fonts/TRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187]
-../fonts/TRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
-../fonts/TRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976]
-../fonts/TRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900]
-../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786]
-../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786]
+../fonts/TRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0@30,0+1060|B=1@30,0+1060|C.alt=2@30,0+1060]
+../fonts/TRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-7,0+986|B=1@-7,0+986|C.alt=2@-7,0+986]
+../fonts/TRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-35,0+929|B=1@-35,0+929|C.alt=2@-35,0+929]
+../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
+../fonts/TRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
 ../fonts/TRAK.ttf:--font-ptem=144 --features=-trak:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
-../fonts/TRAK.ttf:--font-ptem=144 --features=-trak[1;3]:U+0041,U+0042,U+0043,U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1+1000|C.alt=2+1000|A.alt=3@-107,0+786|B=4@-107,0+786|C.alt=5@-107,0+786]
+../fonts/TRAK.ttf:--font-ptem=144 --features=-trak[1;3]:U+0041,U+0042,U+0043,U+0041,U+0042,U+0043:[A.alt=0@-78,0+843|B=1+1000|C.alt=2+1000|A.alt=3@-78,0+843|B=4@-78,0+843|C.alt=5@-78,0+843]
diff --git a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests b/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
index 274829c..8b7ced0 100644
--- a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
+++ b/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
@@ -1 +1 @@
-../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf::U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@221,0+0|uni0651=2@260,736+0|uni064E=2@935,1259+0|uni0651=2@974,736+0|uni06440627.fina=2+1470|uni064F=0@558,-10+0|uni0633.init=0+1585]
+../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf::U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@148,0+0|uni0651=2@187,736+0|uni064E=2@883,1259+0|uni0651=2@922,736+0|uni06440627.fina=2+1470|uni064F=0@629,-10+0|uni0633.init=0+1585]
diff --git a/test/shaping/data/in-house/tests/cluster.tests b/test/shaping/data/in-house/tests/cluster.tests
index fd0a0fe..928843f 100644
--- a/test/shaping/data/in-house/tests/cluster.tests
+++ b/test/shaping/data/in-house/tests/cluster.tests
@@ -1,2 +1,2 @@
-../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1131,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
+../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
 ../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf:--cluster-level=1:U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD:[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338]
diff --git a/test/shaping/data/in-house/tests/color-fonts.tests b/test/shaping/data/in-house/tests/color-fonts.tests
index b325d78..bf0005c 100644
--- a/test/shaping/data/in-house/tests/color-fonts.tests
+++ b/test/shaping/data/in-house/tests/color-fonts.tests
@@ -1 +1,2 @@
 ../fonts/ee39587d13b2afa5499cc79e45780aa79293bbd4.ttf:--font-funcs=ot --show-extents:U+1F42F:[gid1=0+2963<0,2179,2963,-2789>]
+../fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf:--font-funcs=ot --show-extents:U+1F600:[gid4=0+2550<0,1898,2555,-2405>]
diff --git a/test/shaping/data/in-house/tests/emoji.tests b/test/shaping/data/in-house/tests/emoji.tests
index 8d9b254..7ee01f3 100644
--- a/test/shaping/data/in-house/tests/emoji.tests
+++ b/test/shaping/data/in-house/tests/emoji.tests
@@ -1,4 +1,5 @@
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0]
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
 ../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
 ../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=l:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
 ../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=r:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
+../fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf::U+1F3F4,U+E0067,U+E0062,U+E0077,U+E006C,U+E0073,U+E007F:[.notdef=0+1229|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
diff --git a/test/shaping/data/in-house/tests/fallback-positioning.tests b/test/shaping/data/in-house/tests/fallback-positioning.tests
index 5047d84..0ffee50 100644
--- a/test/shaping/data/in-house/tests/fallback-positioning.tests
+++ b/test/shaping/data/in-house/tests/fallback-positioning.tests
@@ -1,2 +1,2 @@
-../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf::U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-21,-27+0|X=2+1295|acutecomb=2@-147,320+0]
-../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@-64,-128+0|uni0062=2+512]
+../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf::U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-19,-27+0|X=2+1295|acutecomb=2@-151,320+0]
+../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@0,-128+0|uni0062=2+512]
diff --git a/test/shaping/data/in-house/tests/indic-syllable.tests b/test/shaping/data/in-house/tests/indic-syllable.tests
index 4c7d651..264983b 100644
--- a/test/shaping/data/in-house/tests/indic-syllable.tests
+++ b/test/shaping/data/in-house/tests/indic-syllable.tests
@@ -6,3 +6,5 @@
 ../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+0A51:[uni25CC=0+1044|udaatguru=0+0]
 ../fonts/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+25CC,U+0A51:[uni25CC=0+1044|udaatguru=0+0]
 ../fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf:--no-glyph-names:U+0C80,U+0C82:[1=0+502|2=0+502]
+../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A47:[tthaguru=0+1352|yakashguru=0@-90,0+0|eematraguru=0@-411,0+0]
+../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A42:[tthaguru=0+1352|yakashuuguru=0+0]
diff --git a/test/shaping/data/in-house/tests/khmer-misc.tests b/test/shaping/data/in-house/tests/khmer-misc.tests
index a7a1c6d..1ea7609 100644
--- a/test/shaping/data/in-house/tests/khmer-misc.tests
+++ b/test/shaping/data/in-house/tests/khmer-misc.tests
@@ -87,3 +87,4 @@
 ../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+1782,U+17D2,U+179F,U+17CA,U+17C0:[uni17C1=0+288|uni17A0=0+928|uni17D21782=0@20,-26+0|uni17D2179F.low=0+302|uni17CA=0@-4,30+0|uni17C0.right1.high=0+288]
 ../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+1784,U+17D2,U+1780:[uni17D2179A=0+287|uni17A0=0+928|uni17D2179C=0@20,-26+0|uni1784=5+635|uni17D21780=5@0,-26+0]
 ../fonts/3998336402905b8be8301ef7f47cf7e050cbb1bd.ttf::U+17A0,U+17D2,U+179A,U+17D2,U+179C,U+17B6,U+17C6,U+1784:[uni17D2179A=0+287|uni17A017B6=0+1216|uni17D2179C=0@-268,-26+0|uni17C6=0@47,-29+0|uni1784=7+635]
+../fonts/ad01ab2ea1cb1a4d3a2783e2675112ef11ae6404.ttf::U+17D2,U+17D2:[uni25CC=0+635|uni17D2=0+0|uni25CC=0+635|uni17D2=0+0]
diff --git a/test/shaping/data/in-house/tests/macos.tests b/test/shaping/data/in-house/tests/macos.tests
index 859992c..434e0a5 100644
--- a/test/shaping/data/in-house/tests/macos.tests
+++ b/test/shaping/data/in-house/tests/macos.tests
@@ -4,8 +4,8 @@
 /System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
 /Library/Fonts/Khmer MN.ttc@5f5b1072df99b7355d3066ea85fe82969d13c94a:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
 /Library/Fonts/Tamil MN.ttc@37a2020c3f86ebcc45e02c1de5fdf81e2676989d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@-7,0+0|samekhhebrew=0+1361]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
 /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
 /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
 /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
@@ -13,8 +13,9 @@
 /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
 /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
 /System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0+1105|gid584=1@-105,0+979|gid3=2+490|gid4=3+1227|gid265=4@-65,0+1227|gid3=5+490|gid225=6+1130|gid728=7@-80,0+569|gid3=8+490|gid265=9+1227|gid505=10@-65,0+997|gid3=11+490|gid728=12+609|gid225=13@-40,0+1170|gid3=14+490|gid584=15+1004|gid225=16@-80,0+1130|gid3=17+490|gid225=18+1105|gid576=19@-105,0+1068]
-/System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0@46,0+1197|gid584=1@-59,0+1071|gid3=2@46,0+582|gid4=3@46,0+1319|gid265=4@-19,0+1319|gid3=5@46,0+582|gid225=6@46,0+1222|gid728=7@-34,0+661|gid3=8@46,0+582|gid265=9@46,0+1319|gid505=10@-19,0+1089|gid3=11@46,0+582|gid728=12@46,0+701|gid225=13@6,0+1262|gid3=14@46,0+582|gid584=15@46,0+1096|gid225=16@-34,0+1222|gid3=17@46,0+582|gid225=18@46,0+1197|gid576=19@-59,0+1160]
+/System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0@65,0+1235|gid584=1@-40,0+1109|gid3=2@65,0+620|gid4=3@65,0+1357|gid265=4+1357|gid3=5@65,0+620|gid225=6@65,0+1260|gid728=7@-15,0+699|gid3=8@65,0+620|gid265=9@65,0+1357|gid505=10+1127|gid3=11@65,0+620|gid728=12@65,0+739|gid225=13@25,0+1300|gid3=14@65,0+620|gid584=15@65,0+1134|gid225=16@-15,0+1260|gid3=17@65,0+620|gid225=18@65,0+1235|gid576=19@-40,0+1198]
 /System/Library/Fonts/Apple Color Emoji.ttc@d2fe8a134483aa48a43a9d1e4b7204d37a4abdf5:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@9ee799ffb09516ead6b0cf6f2ca807276e150748:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
 
 # 10.13.6 https://gist.github.com/ebraminio/d432e831b3f7ebe30245dde5775e1c7e
 /System/Library/Fonts/Helvetica.ttc@8a928f9866299d2455f41360202b7a3b48503a5e:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0]
@@ -22,8 +23,8 @@
 /System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
 /Library/Fonts/Khmer MN.ttc@782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
 /Library/Fonts/Tamil MN.ttc@3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@-7,0+0|samekhhebrew=0+1361]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
 /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
 /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
@@ -31,5 +32,25 @@
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
 /System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0+1055|gid658=1@-135,0+914|gid3=2+420|gid4=3+1227|gid332=4@-65,0+1227|gid3=5+420|gid282=6+1075|gid813=7@-115,0+516|gid3=8+420|gid332=9+1217|gid572=10@-75,0+953|gid3=11+420|gid813=12+546|gid282=13@-85,0+1105|gid3=14+420|gid658=15+914|gid282=16@-135,0+1055|gid3=17+420|gid282=18+1055|gid649=19@-135,0+999]
-/System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0@46,0+1147|gid658=1@-89,0+1006|gid3=2@46,0+512|gid4=3@46,0+1319|gid332=4@-19,0+1319|gid3=5@46,0+512|gid282=6@46,0+1167|gid813=7@-69,0+608|gid3=8@46,0+512|gid332=9@46,0+1309|gid572=10@-29,0+1045|gid3=11@46,0+512|gid813=12@46,0+638|gid282=13@-39,0+1197|gid3=14@46,0+512|gid658=15@46,0+1006|gid282=16@-89,0+1147|gid3=17@46,0+512|gid282=18@46,0+1147|gid649=19@-89,0+1091]
+/System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0@65,0+1185|gid658=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid332=4+1357|gid3=5@65,0+550|gid282=6@65,0+1205|gid813=7@-50,0+646|gid3=8@65,0+550|gid332=9@65,0+1347|gid572=10@-10,0+1083|gid3=11@65,0+550|gid813=12@65,0+676|gid282=13@-20,0+1235|gid3=14@65,0+550|gid658=15@65,0+1044|gid282=16@-70,0+1185|gid3=17@65,0+550|gid282=18@65,0+1185|gid649=19@-70,0+1129]
 /System/Library/Fonts/Apple Color Emoji.ttc@2e09b1f3d42c3821cc6c4ac5b6ce16237ab0d496:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
+
+# 10.14.2 https://gist.github.com/ebraminio/4b731a82f11a662b2164622ebb93086a
+/System/Library/Fonts/Helvetica.ttc@992d29a0fa4ed91773457c29b661e94843619cde:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
+/Library/Fonts/Khmer MN.ttc@37687fe0bd2548e08e29c92a30e476367ae6356b:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1230|km_ka=1+1230|km_sa.sub=1+620|km_ro=4+712|km_vs_ae=5+726|km_kha=5+1230|km_mo.sub=5+0|km_ro=9+712]
+/Library/Fonts/Tamil MN.ttc@e1df5e056be08937fd65990efbafff0814c03677:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
+/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
+/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
+/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
+/System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid283=0+1055|gid659=1@-135,0+914|gid3=2+420|gid4=3+1227|gid333=4@-65,0+1227|gid3=5+420|gid283=6+1075|gid815=7@-115,0+516|gid3=8+420|gid333=9+1217|gid573=10@-75,0+953|gid3=11+420|gid815=12+546|gid283=13@-85,0+1105|gid3=14+420|gid659=15+914|gid283=16@-135,0+1055|gid3=17+420|gid283=18+1055|gid650=19@-135,0+999]
+/System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid283=0@65,0+1185|gid659=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid333=4+1357|gid3=5@65,0+550|gid283=6@65,0+1205|gid815=7@-50,0+646|gid3=8@65,0+550|gid333=9@65,0+1347|gid573=10@-10,0+1083|gid3=11@65,0+550|gid815=12@65,0+676|gid283=13@-20,0+1235|gid3=14@65,0+550|gid659=15@65,0+1044|gid283=16@-70,0+1185|gid3=17@65,0+550|gid283=18@65,0+1185|gid650=19@-70,0+1129]
+/System/Library/Fonts/Apple Color Emoji.ttc@60f77161021b1b87e99c3690e1a9b56341cf8792:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
+/Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
diff --git a/test/shaping/data/in-house/tests/positioning-features.tests b/test/shaping/data/in-house/tests/positioning-features.tests
new file mode 100644
index 0000000..8cab9d8
--- /dev/null
+++ b/test/shaping/data/in-house/tests/positioning-features.tests
@@ -0,0 +1,3 @@
+../fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf::U+0041,U+0056:[A=0+625|V=1+675]
+../fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf::U+006D,U+0315:[m=0+945|uni0315=0@32,-178+0]
+../fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf::U+0079,U+0325:[y=0+565|uni0325=0@-422,-240+0]
diff --git a/test/shaping/data/in-house/tests/use-syllable.tests b/test/shaping/data/in-house/tests/use-syllable.tests
index 6a247ed..9056008 100644
--- a/test/shaping/data/in-house/tests/use-syllable.tests
+++ b/test/shaping/data/in-house/tests/use-syllable.tests
@@ -10,3 +10,7 @@
 ../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11044,U+11046:[brm_KA=0+754|brm_vowelOO=0@-647,0+0|brm_virama=0@-524,0+0]
 ../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+1103C:[brm_KA=0+754|brm_vowelU=0@-403,0+0]
 ../fonts/86cdd983c4e4c4d7f27dd405d6ceb7d4b9ed3d35.ttf::U+111C8,U+111C9,U+111C9:[u111C8=0+500|u111C9=0@-500,0+0|u111C9=0@-500,0+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A5A,U+1A63:[uni1A3D=0+250|uni1A5A=0+0|uni1A63=0+250]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A59:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A59=5+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A5A:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni25CC=5+250|uni1A5A=5+0]
+../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A60:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A60=5+0]
diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED
index b071904..8539c0e 100644
--- a/test/shaping/data/text-rendering-tests/DISABLED
+++ b/test/shaping/data/text-rendering-tests/DISABLED
@@ -1,6 +1,3 @@
-tests/MORX-31.tests
-tests/MORX-41.tests
-
 # Non-Unicode cmap
 tests/CMAP-3.tests
 
diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources
index 052a612..ccbbb37 100644
--- a/test/shaping/data/text-rendering-tests/Makefile.sources
+++ b/test/shaping/data/text-rendering-tests/Makefile.sources
@@ -51,6 +51,7 @@
 	tests/MORX-29.tests \
 	tests/MORX-2.tests \
 	tests/MORX-30.tests \
+	tests/MORX-31.tests \
 	tests/MORX-32.tests \
 	tests/MORX-33.tests \
 	tests/MORX-34.tests \
@@ -61,6 +62,7 @@
 	tests/MORX-39.tests \
 	tests/MORX-3.tests \
 	tests/MORX-40.tests \
+	tests/MORX-41.tests \
 	tests/MORX-4.tests \
 	tests/MORX-5.tests \
 	tests/MORX-6.tests \
diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py
index 27d5686..f1722b5 100755
--- a/test/shaping/data/text-rendering-tests/extract-tests.py
+++ b/test/shaping/data/text-rendering-tests/extract-tests.py
@@ -48,7 +48,7 @@
 		opts = opts + ' --variations=%s' % variations
 	print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
 
-for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces):
+for elt in html.findall(".//*[@class='expected-no-crash'][@ft:id]", namespaces):
 	found = True
 	name = elt.get(ns('ft:id'))
 	text = elt.get(ns('ft:render'))
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests b/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
index 1369247..d01f2e9 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
@@ -1,2 +1,2 @@
 ../fonts/TestMORXFourteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
-../fonts/TestMORXFourteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045:[B|B@626,0|B@1252,0|C@1878,0|C@2474,0|C@3070,0|D@3666,0|D@4340,0|D@5014,0|B@5688,0|C@6314,0|D@6910,0|C@7584,0|E@8180,0|A@8736,0]
+../fonts/TestMORXFourteen.ttf::U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
index 87c1152..6f3ae88 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
@@ -1,4 +1,4 @@
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[I|N@830,0|S@1660,0|A@2490,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B|I@830,0|N@1660,0|S@2490,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
index 84dca89..815bebe 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
@@ -1,4 +1,4 @@
 ../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0063:[a_c]
 ../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062,U+0063:[b_c]
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0063,U+0063:[c]
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0062,U+0063,U+0063:[a|b_c@561,0|c@1631,0]
+../fonts/TestMORXFourtyone.ttf::U+0063,U+0063:*
+../fonts/TestMORXFourtyone.ttf::U+0061,U+0062,U+0063,U+0063:*
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
index 4ab74f0..7f24354 100755
--- a/test/shaping/record-test.sh
+++ b/test/shaping/record-test.sh
@@ -2,6 +2,17 @@
 
 dir=`mktemp -d`
 
+if which sha1sum 2>/dev/null >/dev/null; then
+	SHA1SUM=sha1sum
+elif which shasum 2>/dev/null >/dev/null; then
+	SHA1SUM='shasum -a 1'
+elif which digest 2>/dev/null >/dev/null; then
+	SHA1SUM='digest -a sha1'
+else
+	echo "'sha1sum' not found"
+	exit 2
+fi
+
 out=/dev/stdout
 if test "x$1" == 'x-o'; then
 	shift
@@ -90,7 +101,7 @@
 	glyphs=$glyphs_subset
 fi
 
-sha1sum=`sha1sum "$dir/font.subset.ttf" | cut -d' ' -f1`
+sha1sum=`$SHA1SUM "$dir/font.subset.ttf" | cut -d' ' -f1`
 subset="data/in-house/fonts/$sha1sum.ttf"
 mv "$dir/font.subset.ttf" "$subset"
 
diff --git a/test/subset/Makefile.am b/test/subset/Makefile.am
index 1673cfb..da4b3d4 100644
--- a/test/subset/Makefile.am
+++ b/test/subset/Makefile.am
@@ -6,7 +6,8 @@
 SUBDIRS = data
 
 # Convenience targets:
-lib:
+lib: libs # Always build subsetter lib in this subdir
+libs:
 	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
 
 EXTRA_DIST += \
diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index 0d1b2f0..4508fcd 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -5,11 +5,19 @@
 CLEANFILES =
 SUBDIRS =
 
-EXTRA_DIST = \
+EXTRA_DIST += \
 	$(TESTS) \
 	expected/basics \
 	expected/full-font \
+	expected/cff-full-font \
 	expected/japanese \
+	expected/cff-japanese \
+	expected/layout \
+	expected/layout.gpos \
+	expected/layout.gpos2 \
+	expected/layout.gpos3 \
+	expected/layout.gsub6 \
+	expected/cmap14 \
 	fonts \
 	profiles \
 	$(NULL)
diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index dd1bcfe..5b93f27 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -1,7 +1,15 @@
 TESTS = \
 	tests/basics.tests \
 	tests/full-font.tests \
+	tests/cff-full-font.tests \
 	tests/japanese.tests \
+	tests/cff-japanese.tests \
+	tests/layout.tests \
+	tests/layout.gpos.tests \
+	tests/layout.gpos2.tests \
+	tests/layout.gpos3.tests \
+	tests/layout.gsub6.tests \
+	tests/cmap14.tests \
 	$(NULL)
 
 XFAIL_TESTS = \
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
new file mode 100644
index 0000000..efe5bcb
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
new file mode 100644
index 0000000..8e12241
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
new file mode 100644
index 0000000..bd802a5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
new file mode 100644
index 0000000..9fbebb5
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
new file mode 100644
index 0000000..7391741
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..5de8d89
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..05d83d8
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
new file mode 100644
index 0000000..f47887e
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
new file mode 100644
index 0000000..bfa9267
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
new file mode 100644
index 0000000..8c12158
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
new file mode 100644
index 0000000..6a47c39
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..e3c0727
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
new file mode 100644
index 0000000..36a4b9a
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
new file mode 100644
index 0000000..251794c
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
new file mode 100644
index 0000000..9e65c83
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
new file mode 100644
index 0000000..ada1649
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
new file mode 100644
index 0000000..6b0dc6c
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..6425ecf
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
new file mode 100644
index 0000000..90e49be
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
new file mode 100644
index 0000000..5277d15
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
new file mode 100644
index 0000000..de06660
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
new file mode 100644
index 0000000..effad7b
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
new file mode 100644
index 0000000..21c8205
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..fbb8c33
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..3c0f4cd
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
new file mode 100644
index 0000000..a5ce9e0
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
new file mode 100644
index 0000000..1b84335
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
new file mode 100644
index 0000000..97eaa26
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
new file mode 100644
index 0000000..f42edb7
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..cc2805a
--- /dev/null
+++ b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..52dc474
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
new file mode 100644
index 0000000..d6c516e
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
new file mode 100644
index 0000000..128eae0
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
new file mode 100644
index 0000000..2d2b65b
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
new file mode 100644
index 0000000..ac735b3
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..52dc474
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
new file mode 100644
index 0000000..52dc474
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
new file mode 100644
index 0000000..1af233f
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
new file mode 100644
index 0000000..a699eea
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
new file mode 100644
index 0000000..52706dc
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
new file mode 100644
index 0000000..3de7c77
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
new file mode 100644
index 0000000..f545375
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
new file mode 100644
index 0000000..a699eea
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
new file mode 100644
index 0000000..eb84f9c
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
new file mode 100644
index 0000000..efd7c16
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf
Binary files differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
new file mode 100644
index 0000000..12d9208
--- /dev/null
+++ b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..f0ea3ca
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf
new file mode 100644
index 0000000..7ea55a2
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..07b9aa2
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..2811017
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..98bbf38
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..2d88e57
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..cf0fbf6
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
new file mode 100644
index 0000000..8ab8294
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..de475e6
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..e5775fd
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..572ea74
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..376f658
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..cf3228d
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf
new file mode 100644
index 0000000..1bafff1
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..34303e7
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..e23e37f
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf
new file mode 100644
index 0000000..b5a565e
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..6045b4c
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..112dec7
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
new file mode 100644
index 0000000..929c4e2
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..939a565
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf
new file mode 100644
index 0000000..e1613ac
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf
new file mode 100644
index 0000000..479c5e0
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf
new file mode 100644
index 0000000..95149dc
--- /dev/null
+++ b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..6065be4
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..cee7584
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
new file mode 100644
index 0000000..0f13fa5
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..6db56f4
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
new file mode 100644
index 0000000..1b216cc
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..690fe90
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..f1f0cb1
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
new file mode 100644
index 0000000..b353d43
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..7d96667
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
new file mode 100644
index 0000000..afd9c33
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..1a47c85
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..b69448b
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
new file mode 100644
index 0000000..3682a0d
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..6f98c8f
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
new file mode 100644
index 0000000..1497979
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..c728315
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..9a0e726
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
new file mode 100644
index 0000000..513d47e
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..b10526d
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
new file mode 100644
index 0000000..2684381
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..68a254e
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..b900d92
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
new file mode 100644
index 0000000..6b7cc2e
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..69b6b2e
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
new file mode 100644
index 0000000..460bace
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..ecdd5d6
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..77b1f95
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
new file mode 100644
index 0000000..8a1bc96
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..7d943fd
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
new file mode 100644
index 0000000..eb01e55
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..19c8ed8
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..5c7ac1a
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
new file mode 100644
index 0000000..abac3dd
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..e593d6d
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
new file mode 100644
index 0000000..e586904
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
new file mode 100644
index 0000000..75f1613
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
new file mode 100644
index 0000000..6f3794c
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
new file mode 100644
index 0000000..7c5f648
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
new file mode 100644
index 0000000..2dcd75b
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf
Binary files differ
diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
new file mode 100644
index 0000000..a5d40d0
--- /dev/null
+++ b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..fb41408
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf
new file mode 100644
index 0000000..e50256d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..24f3871
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..38672ba
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf
new file mode 100644
index 0000000..c5f898e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf
new file mode 100644
index 0000000..03cae07
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..2506a41
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf
new file mode 100644
index 0000000..e8ebeb4
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf
new file mode 100644
index 0000000..910cc0f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf
new file mode 100644
index 0000000..d7d6972
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..a1c001c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..5b41802
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..b88e288
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..6d95272
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf
new file mode 100644
index 0000000..251568f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf
new file mode 100644
index 0000000..2b1d7a7
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..dce7f14
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..e1e2245
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf
new file mode 100644
index 0000000..f72cdc9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..4efa2e2
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..a440b96
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf
new file mode 100644
index 0000000..c503e38
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..d36d155
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..34a8469
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf
new file mode 100644
index 0000000..d695329
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf
new file mode 100644
index 0000000..1c4d2b5
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..e5981f0
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf
new file mode 100644
index 0000000..4b76f1c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf
new file mode 100644
index 0000000..cf60215
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf
new file mode 100644
index 0000000..bf353ed
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..a7b67bf
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf
new file mode 100644
index 0000000..7c6805d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..b1876b6
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..b07778f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf
new file mode 100644
index 0000000..fb77632
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf
new file mode 100644
index 0000000..4ec322c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..ec20755
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf
new file mode 100644
index 0000000..bf2c086
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf
new file mode 100644
index 0000000..0a3721e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf
new file mode 100644
index 0000000..eaaa56d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf
new file mode 100644
index 0000000..5c5ce5c
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf
new file mode 100644
index 0000000..3b87f54
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf
new file mode 100644
index 0000000..e06a24d
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf
new file mode 100644
index 0000000..aabdc5e
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf
new file mode 100644
index 0000000..4183c9f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf
new file mode 100644
index 0000000..66ef901
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf
new file mode 100644
index 0000000..4bee46f
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf
new file mode 100644
index 0000000..6e8baa9
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf
new file mode 100644
index 0000000..f6191da
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf
Binary files differ
diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..bf2746b
--- /dev/null
+++ b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
index 93efe65..e8b7b37 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
index d4d26d7..912e1fb 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
index 7e271f2..6f19df6 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
index 99b91bd..9ea42ab 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
index eb94906..4d12593 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
index ff361ba..281b475 100644
--- a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
+++ b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 1bd287d..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.61,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.default.61,62,63.otf
deleted file mode 100644
index 328c6ee..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 4602847..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 18a9bcc..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
deleted file mode 100644
index edd389b..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 65fa1da..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 53109e2..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
deleted file mode 100644
index dd908c2..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 5422d32..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.1FC,21,41,20,62,63.otf
deleted file mode 100644
index 604e140..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.1FC,21,41,20,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.61,62,63.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.61,62,63.otf
deleted file mode 100644
index a0b2c2f..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.61,62,63.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.D7,D8,D9,DA,DE.otf
deleted file mode 100644
index 8055328..0000000
--- a/test/subset/data/expected/full-font/SourceSansPro-Regular.drop-hints.desubroutinize.D7,D8,D9,DA,DE.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
index 3398999..6770dac 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
index 66b98a6..0c66219 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
index 22d1bb3..4a5a6f8 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
index 2804359..465ce34 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
index 333ca51..28f3c37 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
index c84b20c..1bebda7 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
index e757b9e..a43998d 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
index e869ff1..34c7788 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
index ed4ed4c..92ec10b 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
index cb50238..b9bb539 100644
--- a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
+++ b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,3048,304A,304B.otf
deleted file mode 100644
index 8d717cc..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,3048,304A,304B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,73E0,5EA6,8F38.otf
deleted file mode 100644
index 3d570cd..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.3042,3044,3046,73E0,5EA6,8F38.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.61,63,65,6B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.default.61,63,65,6B.otf
deleted file mode 100644
index 216ed17..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.61,63,65,6B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.otf
deleted file mode 100644
index f548f48..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E.otf
deleted file mode 100644
index 6362d21..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.default.660E.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize..otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize..otf
deleted file mode 100644
index 7c0c5fd..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize..otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,3048,304A,304B.otf
deleted file mode 100644
index e51866a..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
deleted file mode 100644
index c4f6bb2..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.61,63,65,6B.otf
deleted file mode 100644
index 62ddb60..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.61,63,65,6B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
deleted file mode 100644
index 7ce9d40..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E.otf
deleted file mode 100644
index 35d9eea..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.desubroutinize.660E.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,3048,304A,304B.otf
deleted file mode 100644
index 9e1041d..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,3048,304A,304B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
deleted file mode 100644
index 6a3bff1..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.61,63,65,6B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.61,63,65,6B.otf
deleted file mode 100644
index 06d28b6..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.61,63,65,6B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
deleted file mode 100644
index ce9d287..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E.otf
deleted file mode 100644
index 27c4676..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.660E.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize..otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize..otf
deleted file mode 100644
index a73617a..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize..otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,3048,304A,304B.otf
deleted file mode 100644
index 790b714..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,3048,304A,304B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
deleted file mode 100644
index c707bcd..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.61,63,65,6B.otf
deleted file mode 100644
index 591d139..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.61,63,65,6B.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
deleted file mode 100644
index efc98b6..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E.otf b/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E.otf
deleted file mode 100644
index 27c4676..0000000
--- a/test/subset/data/expected/japanese/SourceHanSans-Regular.drop-hints.desubroutinize.660E.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf
new file mode 100644
index 0000000..6b2879f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf
new file mode 100644
index 0000000..eebb3e1
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf
new file mode 100644
index 0000000..c271bde
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..2d6962b
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf
new file mode 100644
index 0000000..49039fe
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf
new file mode 100644
index 0000000..68cb0ec
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..8f18b89
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf
new file mode 100644
index 0000000..47fea1a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf
new file mode 100644
index 0000000..99e813f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..8f18b89
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf
new file mode 100644
index 0000000..b34a49f
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf
new file mode 100644
index 0000000..2ad1d29
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..88e6046
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf
new file mode 100644
index 0000000..195c8dc
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23,25.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf
new file mode 100644
index 0000000..d10d362
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.21,23.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..88e6046
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf
new file mode 100644
index 0000000..17aa6d8
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf
new file mode 100644
index 0000000..9e6f2eb
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf
new file mode 100644
index 0000000..0187ed7
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..d9b5dfb
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf
new file mode 100644
index 0000000..f3ca19a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,29.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf
new file mode 100644
index 0000000..2a8114a
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.28,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf
new file mode 100644
index 0000000..1426d50
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.29,2B.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..d9b5dfb
--- /dev/null
+++ b/test/subset/data/expected/layout.gpos3/gpos3_font3.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..e10d863
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..1f90754
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf
new file mode 100644
index 0000000..bdaa805
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..1f90754
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..856249e
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..e764393
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf
new file mode 100644
index 0000000..a53b114
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..e764393
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf
new file mode 100644
index 0000000..2d08eb0
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf
new file mode 100644
index 0000000..737f85a
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout-retain-gids.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf
new file mode 100644
index 0000000..fbd9a44
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.30,31,32,33.otf
Binary files differ
diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf
new file mode 100644
index 0000000..737f85a
--- /dev/null
+++ b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.keep-layout.retain-all-codepoint.otf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf
new file mode 100644
index 0000000..aa007ba
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf
new file mode 100644
index 0000000..f3be30c
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf
new file mode 100644
index 0000000..44c329e
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf
new file mode 100644
index 0000000..b0a1ea3
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf
new file mode 100644
index 0000000..16ad9d5
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf
new file mode 100644
index 0000000..d0d9d5a
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf
new file mode 100644
index 0000000..f4d881f
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf
new file mode 100644
index 0000000..9e6dd28
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf
new file mode 100644
index 0000000..50260c5
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf
Binary files differ
diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf
new file mode 100644
index 0000000..22d5b61
--- /dev/null
+++ b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Comfortaa-Regular-new.ttf b/test/subset/data/fonts/Comfortaa-Regular-new.ttf
new file mode 100644
index 0000000..4965fbe
--- /dev/null
+++ b/test/subset/data/fonts/Comfortaa-Regular-new.ttf
Binary files differ
diff --git a/test/subset/data/fonts/Roboto-Regular.smallcaps.ttf b/test/subset/data/fonts/Roboto-Regular.smallcaps.ttf
new file mode 100644
index 0000000..fc58299
--- /dev/null
+++ b/test/subset/data/fonts/Roboto-Regular.smallcaps.ttf
Binary files differ
diff --git a/test/subset/data/fonts/SourceHanSans-Regular.otf b/test/subset/data/fonts/SourceHanSans-Regular.otf
deleted file mode 100755
index dd807db..0000000
--- a/test/subset/data/fonts/SourceHanSans-Regular.otf
+++ /dev/null
Binary files differ
diff --git a/test/subset/data/fonts/SourceHanSans-Regular_subset.otf b/test/subset/data/fonts/SourceHanSans-Regular_subset.otf
new file mode 100644
index 0000000..06af9b3
--- /dev/null
+++ b/test/subset/data/fonts/SourceHanSans-Regular_subset.otf
Binary files differ
diff --git a/test/subset/data/fonts/cmap14_font1.otf b/test/subset/data/fonts/cmap14_font1.otf
new file mode 100644
index 0000000..a4283c6
--- /dev/null
+++ b/test/subset/data/fonts/cmap14_font1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos1_2_font.otf b/test/subset/data/fonts/gpos1_2_font.otf
new file mode 100644
index 0000000..28331f2
--- /dev/null
+++ b/test/subset/data/fonts/gpos1_2_font.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos2_1_font7.otf b/test/subset/data/fonts/gpos2_1_font7.otf
new file mode 100644
index 0000000..22b54ea
--- /dev/null
+++ b/test/subset/data/fonts/gpos2_1_font7.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos2_2_font5.otf b/test/subset/data/fonts/gpos2_2_font5.otf
new file mode 100644
index 0000000..63af3bc
--- /dev/null
+++ b/test/subset/data/fonts/gpos2_2_font5.otf
Binary files differ
diff --git a/test/subset/data/fonts/gpos3_font3.otf b/test/subset/data/fonts/gpos3_font3.otf
new file mode 100644
index 0000000..69c74a3
--- /dev/null
+++ b/test/subset/data/fonts/gpos3_font3.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf b/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf
new file mode 100644
index 0000000..74b9945
--- /dev/null
+++ b/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf b/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf
new file mode 100644
index 0000000..a3a1846
--- /dev/null
+++ b/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf
Binary files differ
diff --git a/test/subset/data/fonts/gsub_chaining3_simple_f2.otf b/test/subset/data/fonts/gsub_chaining3_simple_f2.otf
new file mode 100644
index 0000000..bc9ed9a
--- /dev/null
+++ b/test/subset/data/fonts/gsub_chaining3_simple_f2.otf
Binary files differ
diff --git a/test/subset/data/profiles/desubroutinize-retain-gids.txt b/test/subset/data/profiles/desubroutinize-retain-gids.txt
new file mode 100644
index 0000000..cbb37b6
--- /dev/null
+++ b/test/subset/data/profiles/desubroutinize-retain-gids.txt
@@ -0,0 +1,2 @@
+--desubroutinize
+--retain-gids
diff --git a/test/subset/data/profiles/drop-hints-desubroutinize-retain-gids.txt b/test/subset/data/profiles/drop-hints-desubroutinize-retain-gids.txt
new file mode 100644
index 0000000..848620a
--- /dev/null
+++ b/test/subset/data/profiles/drop-hints-desubroutinize-retain-gids.txt
@@ -0,0 +1,3 @@
+--no-hinting
+--desubroutinize
+--retain-gids
diff --git a/test/subset/data/profiles/drop-hints-retain-gids.txt b/test/subset/data/profiles/drop-hints-retain-gids.txt
new file mode 100644
index 0000000..b0409b8
--- /dev/null
+++ b/test/subset/data/profiles/drop-hints-retain-gids.txt
@@ -0,0 +1,2 @@
+--no-hinting
+--retain-gids
diff --git a/test/subset/data/profiles/keep-layout-retain-gids.txt b/test/subset/data/profiles/keep-layout-retain-gids.txt
new file mode 100644
index 0000000..f4787ad
--- /dev/null
+++ b/test/subset/data/profiles/keep-layout-retain-gids.txt
@@ -0,0 +1,2 @@
+--drop-tables-=GSUB,GPOS
+--retain-gids
diff --git a/test/subset/data/profiles/keep-layout.txt b/test/subset/data/profiles/keep-layout.txt
new file mode 100644
index 0000000..56da0ff
--- /dev/null
+++ b/test/subset/data/profiles/keep-layout.txt
@@ -0,0 +1 @@
+--drop-tables-=GSUB,GPOS
diff --git a/test/subset/data/profiles/name-ids.txt b/test/subset/data/profiles/name-ids.txt
new file mode 100644
index 0000000..db42c09
--- /dev/null
+++ b/test/subset/data/profiles/name-ids.txt
@@ -0,0 +1 @@
+--name-IDs=0,1,2
diff --git a/test/subset/data/profiles/retain-gids.txt b/test/subset/data/profiles/retain-gids.txt
new file mode 100644
index 0000000..d757487
--- /dev/null
+++ b/test/subset/data/profiles/retain-gids.txt
@@ -0,0 +1 @@
+--retain-gids
diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests
index 9725445..772f33c 100644
--- a/test/subset/data/tests/basics.tests
+++ b/test/subset/data/tests/basics.tests
@@ -1,9 +1,13 @@
 FONTS:
 Roboto-Regular.abc.ttf
+Comfortaa-Regular-new.ttf
 
 PROFILES:
 default.txt
 drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+name-ids.txt
 
 SUBSETS:
 abc
@@ -11,3 +15,4 @@
 c
 ac
 a
+*
diff --git a/test/subset/data/tests/cff-full-font.tests b/test/subset/data/tests/cff-full-font.tests
new file mode 100644
index 0000000..e55f21e
--- /dev/null
+++ b/test/subset/data/tests/cff-full-font.tests
@@ -0,0 +1,18 @@
+FONTS:
+SourceSansPro-Regular.otf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+desubroutinize.txt
+desubroutinize-retain-gids.txt
+drop-hints-desubroutinize.txt
+drop-hints-desubroutinize-retain-gids.txt
+
+SUBSETS:
+abc
+Ǽ!A bc
+×ØÙÚÞ
+
diff --git a/test/subset/data/tests/cff-japanese.tests b/test/subset/data/tests/cff-japanese.tests
new file mode 100644
index 0000000..d69396f
--- /dev/null
+++ b/test/subset/data/tests/cff-japanese.tests
@@ -0,0 +1,22 @@
+FONTS:
+SourceHanSans-Regular_subset.otf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+desubroutinize.txt
+desubroutinize-retain-gids.txt
+drop-hints-desubroutinize.txt
+drop-hints-desubroutinize-retain-gids.txt
+
+SUBSETS:
+明
+acek
+明極珠度輸清
+あいうえおか
+あいう珠度輸
+
+
+
diff --git a/test/subset/data/tests/cmap14.tests b/test/subset/data/tests/cmap14.tests
new file mode 100644
index 0000000..6575870
--- /dev/null
+++ b/test/subset/data/tests/cmap14.tests
@@ -0,0 +1,21 @@
+FONTS:
+cmap14_font1.otf
+
+PROFILES:
+default.txt
+drop-hints.txt
+drop-hints-retain-gids.txt
+retain-gids.txt
+name-ids.txt
+
+SUBSETS:
+一丂七
+丂
+七
+一七
+一丅万
+丅万丈三
+丈
+丈三
+丂七丈
+*
diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests
index f422ff5..225bb48 100644
--- a/test/subset/data/tests/full-font.tests
+++ b/test/subset/data/tests/full-font.tests
@@ -1,6 +1,5 @@
 FONTS:
 Roboto-Regular.ttf
-SourceSansPro-Regular.otf
 
 PROFILES:
 default.txt
@@ -10,4 +9,3 @@
 abc
 Ǽ!A bc
 ×ØÙÚÞ
-
diff --git a/test/subset/data/tests/japanese.tests b/test/subset/data/tests/japanese.tests
index fc58646..5a04380 100644
--- a/test/subset/data/tests/japanese.tests
+++ b/test/subset/data/tests/japanese.tests
@@ -1,6 +1,5 @@
 FONTS:
 Mplus1p-Regular.ttf
-SourceHanSans-Regular.otf
 
 PROFILES:
 default.txt
diff --git a/test/subset/data/tests/layout.gpos.tests b/test/subset/data/tests/layout.gpos.tests
new file mode 100644
index 0000000..2d0f936
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos.tests
@@ -0,0 +1,11 @@
+FONTS:
+gpos1_2_font.otf
+
+PROFILES:
+keep-layout-retain-gids.txt
+
+SUBSETS:
+AC
+CF
+AF
+*
diff --git a/test/subset/data/tests/layout.gpos2.tests b/test/subset/data/tests/layout.gpos2.tests
new file mode 100644
index 0000000..94fe78a
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos2.tests
@@ -0,0 +1,12 @@
+FONTS:
+gpos2_1_font7.otf
+gpos2_2_font5.otf
+
+PROFILES:
+keep-layout.txt
+keep-layout-retain-gids.txt
+
+SUBSETS:
+!#
+!#%
+*
diff --git a/test/subset/data/tests/layout.gpos3.tests b/test/subset/data/tests/layout.gpos3.tests
new file mode 100644
index 0000000..409272f
--- /dev/null
+++ b/test/subset/data/tests/layout.gpos3.tests
@@ -0,0 +1,12 @@
+FONTS:
+gpos3_font3.otf
+
+PROFILES:
+keep-layout.txt
+keep-layout-retain-gids.txt
+
+SUBSETS:
+()
+(+
+)+
+*
diff --git a/test/subset/data/tests/layout.gsub6.tests b/test/subset/data/tests/layout.gsub6.tests
new file mode 100644
index 0000000..47399b8
--- /dev/null
+++ b/test/subset/data/tests/layout.gsub6.tests
@@ -0,0 +1,12 @@
+FONTS:
+gsub_chaining1_multiple_subrules_f1.otf
+gsub_chaining2_multiple_subrules_f1.otf
+gsub_chaining3_simple_f2.otf
+
+PROFILES:
+keep-layout.txt
+keep-layout-retain-gids.txt
+
+SUBSETS:
+0123
+*
diff --git a/test/subset/data/tests/layout.tests b/test/subset/data/tests/layout.tests
new file mode 100644
index 0000000..dd1c26e
--- /dev/null
+++ b/test/subset/data/tests/layout.tests
@@ -0,0 +1,13 @@
+FONTS:
+Roboto-Regular.smallcaps.ttf
+
+PROFILES:
+keep-layout.txt
+keep-layout-retain-gids.txt
+
+SUBSETS:
+ABC
+AC
+C
+A
+ÊË
diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 9ebf082..6c65627 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -3,6 +3,8 @@
 # Pre-generates the expected output subset files (via fonttools) for
 # specified subset test suite(s).
 
+from __future__ import print_function, division, absolute_import
+
 import io
 import os
 import sys
@@ -12,19 +14,19 @@
 
 
 def usage():
-	print "Usage: generate-expected-outputs.py <test suite file> ..."
+	print("Usage: generate-expected-outputs.py <test suite file> ...")
 
 
 def generate_expected_output(input_file, unicodes, profile_flags, output_path):
 	args = ["fonttools", "subset", input_file]
-	args.extend(profile_flags)
 	args.extend(["--notdef-outline",
-		     "--name-IDs=*",
 		     "--name-languages=*",
 		     "--name-legacy",
-		     "--drop-tables+=DSIG,GPOS,GSUB,GDEF",
+                     "--layout-features=*",
+		     "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR",
 		     "--unicodes=%s" % unicodes,
 		     "--output-file=%s" % output_path])
+	args.extend(profile_flags)
 	check_call(args)
 
 
@@ -37,11 +39,11 @@
 		test_suite = SubsetTestSuite(path, f.read())
 		output_directory = test_suite.get_output_directory()
 
-		print "Generating output files for %s" % output_directory
+		print("Generating output files for %s" % output_directory)
 		for test in test_suite.tests():
 			unicodes = test.unicodes()
 			font_name = test.get_font_name()
-			print "Creating subset %s/%s" % (output_directory, font_name)
+			print("Creating subset %s/%s" % (output_directory, font_name))
 			generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
 						 os.path.join(output_directory,
 							      font_name))
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index fb4684c..5d221e6 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-# Runs a subsetting test suite. Compares the results of subsetting via harfbuz
+# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
 # to subsetting via fonttools.
 
 from __future__ import print_function, division, absolute_import
@@ -16,27 +16,27 @@
 from subset_test_suite import SubsetTestSuite
 
 # https://stackoverflow.com/a/377028
-def which(program):
-	def is_exe(fpath):
-		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+def which (program):
+	def is_exe (fpath):
+		return os.path.isfile (fpath) and os.access (fpath, os.X_OK)
 
-	fpath, _ = os.path.split(program)
+	fpath, _ = os.path.split (program)
 	if fpath:
-		if is_exe(program):
+		if is_exe (program):
 			return program
 	else:
-		for path in os.environ["PATH"].split(os.pathsep):
-			exe_file = os.path.join(path, program)
-			if is_exe(exe_file):
+		for path in os.environ["PATH"].split (os.pathsep):
+			exe_file = os.path.join (path, program)
+			if is_exe (exe_file):
 				return exe_file
 
 	return None
 
-ttx = which ("ttx")
+fonttools = which ("fonttools")
 ots_sanitize = which ("ots-sanitize")
 
-if not ttx:
-	print("TTX is not present, skipping test.")
+if not fonttools:
+	print ("fonttools is not present, skipping test.")
 	sys.exit (77)
 
 def cmd(command):
@@ -50,7 +50,7 @@
 	with open (file_path, 'rb') as f:
 		return f.read ()
 
-def fail_test(test, cli_args, message):
+def fail_test (test, cli_args, message):
 	print ('ERROR: %s' % message)
 	print ('Test State:')
 	print ('  test.font_path    %s' % os.path.abspath (test.font_path))
@@ -61,12 +61,13 @@
 	print ('  expected_file	    %s' % os.path.abspath (expected_file))
 	return 1
 
-def run_test(test, should_check_ots):
-	out_file = os.path.join(tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
+def run_test (test, should_check_ots):
+	out_file = os.path.join (tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
 	cli_args = [hb_subset,
 		    "--font-file=" + test.font_path,
 		    "--output-file=" + out_file,
-		    "--unicodes=%s" % test.unicodes ()]
+		    "--unicodes=%s" % test.unicodes (),
+		    "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR"]
 	cli_args.extend (test.get_profile_flags ())
 	print (' '.join (cli_args))
 	_, return_code = cmd (cli_args)
@@ -75,11 +76,11 @@
 		return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code))
 
 	expected_ttx, return_code = run_ttx (os.path.join (test_suite.get_output_directory (),
-					    test.get_font_name ()))
+					     test.get_font_name ()))
 	if return_code:
 		return fail_test (test, cli_args, "ttx (expected) returned %d" % (return_code))
 
-	actual_ttx, return_code = run_ttx(out_file)
+	actual_ttx, return_code = run_ttx (out_file)
 	if return_code:
 		return fail_test (test, cli_args, "ttx (actual) returned %d" % (return_code))
 
@@ -91,7 +92,7 @@
 		for line in unified_diff (expected_ttx.splitlines (1), actual_ttx.splitlines (1)):
 			sys.stdout.write (line)
 		sys.stdout.flush ()
-		return fail_test(test, cli_args, 'ttx for expected and actual does not match.')
+		return fail_test (test, cli_args, 'ttx for expected and actual does not match.')
 
 	if should_check_ots:
 		print ("Checking output with ots-sanitize.")
@@ -101,8 +102,8 @@
 	return 0
 
 def run_ttx (file):
-	print ("ttx %s" % file)
-	return cmd([ttx, "-q", "-o-", file])
+	print ("fonttools ttx %s" % file)
+	return cmd ([fonttools, "ttx", "-q", "-o-", file])
 
 def strip_check_sum (ttx_string):
 	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
@@ -123,7 +124,7 @@
 	return True
 
 args = sys.argv[1:]
-if not args or sys.argv[1].find('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
+if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
 	print ("First argument does not seem to point to usable hb-subset.")
 	sys.exit (1)
 hb_subset, args = args[0], args[1:]
@@ -138,7 +139,7 @@
 for path in args:
 	with io.open (path, mode="r", encoding="utf-8") as f:
 		print ("Running tests in " + path)
-		test_suite = SubsetTestSuite (path, f.read())
+		test_suite = SubsetTestSuite (path, f.read ())
 		for test in test_suite.tests ():
 			fails += run_test (test, has_ots)
 
diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py
index 73ac3d2..47664d0 100644
--- a/test/subset/subset_test_suite.py
+++ b/test/subset/subset_test_suite.py
@@ -12,7 +12,10 @@
 		self.subset = subset
 
 	def unicodes(self):
-		return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
+		if self.subset == '*':
+			return self.subset[0]
+		else:
+			return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
 
 	def get_profile_flags(self):
 		with io.open(self.profile_path, mode="r", encoding="utf-8") as f:
@@ -23,7 +26,12 @@
 		font_base_name_parts = os.path.splitext(font_base_name)
 		profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
 
-		return "%s.%s.%s%s" % (font_base_name_parts[0],
+		if self.unicodes() == "*":
+			return "%s.%s.retain-all-codepoint%s" % (font_base_name_parts[0],
+				       profile_name,
+				       font_base_name_parts[1])
+		else:
+			return "%s.%s.%s%s" % (font_base_name_parts[0],
 				       profile_name,
 				       self.unicodes(),
 				       font_base_name_parts[1])
@@ -33,18 +41,15 @@
 		font_base_name_parts = os.path.splitext(font_base_name)
 		return font_base_name_parts[1]
 
-	def applicable(self):
-		return self.profile_path.find("desubroutinize") < 0 or self.get_font_extension() == "otf"
-
 # A group of tests to perform on the subsetter. Each test
 # Identifies a font a subsetting profile, and a subset to be cut.
 class SubsetTestSuite:
 
 	def __init__(self, test_path, definition):
 		self.test_path = test_path
-		self.fonts = set()
-		self.profiles = set()
-		self.subsets = set()
+		self.fonts = []
+		self.profiles = []
+		self.subsets = []
 		self._parse(definition)
 
 	def get_output_directory(self):
@@ -55,7 +60,7 @@
 		if not os.path.exists(output_dir):
 			os.mkdir(output_dir)
 		if not os.path.isdir(output_dir):
-			raise Error("%s is not a directory." % output_dir)
+			raise Exception("%s is not a directory." % output_dir)
 
 		return output_dir
 
@@ -65,9 +70,7 @@
 			for profile in self.profiles:
 				profile = os.path.join(self._base_path(), "profiles", profile)
 				for subset in self.subsets:
-					test = Test(font, profile, subset)
-					if test.applicable():
-						yield test
+					yield Test(font, profile, subset)
 
 	def _base_path(self):
 		return os.path.dirname(os.path.dirname(self.test_path))
@@ -92,6 +95,6 @@
 			if line in destinations:
 				current_destination = destinations[line]
 			elif current_destination is not None:
-				current_destination.add(line)
+				current_destination.append(line)
 			else:
 				raise Exception("Failed to parse test suite file.")
diff --git a/util/Makefile.am b/util/Makefile.am
index e24a6f3..5298e77 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -50,8 +50,9 @@
 
 hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
 hb_subset_LDADD = \
-	$(LDADD) \
-	$(top_builddir)/src/libharfbuzz-subset.la
+	$(top_builddir)/src/libharfbuzz-subset.la \
+	$(LDADD)
+
 bin_PROGRAMS += hb-subset
 
 hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
diff --git a/util/Makefile.sources b/util/Makefile.sources
index 6c815d2..bcf85f5 100644
--- a/util/Makefile.sources
+++ b/util/Makefile.sources
@@ -32,6 +32,7 @@
 HB_SUBSET_CLI_sources = \
 	hb-subset.cc \
 	options.cc \
+	options-subset.cc \
 	options.hh \
 	main-font-text.hh \
 	$(NULL)
diff --git a/util/ansi-print.cc b/util/ansi-print.cc
index 49a0477..58df0a6 100644
--- a/util/ansi-print.cc
+++ b/util/ansi-print.cc
@@ -133,7 +133,7 @@
 	for (unsigned int col = 0; col < w; col++)
 	  *q++ = *p++;
       else {
-        unsigned int limit = width - x;
+	unsigned int limit = width - x;
 	for (unsigned int col = 0; col < limit; col++)
 	  *q++ = *p++;
 	p--;
@@ -171,17 +171,17 @@
     int freq[8] = {0};
     for (unsigned int y = 0; y < height; y++)
       for (unsigned int x = 0; x < width; x++) {
-        color_t c = image (x, y);
-        freq[c.to_ansi ()]++;
+	color_t c = image (x, y);
+	freq[c.to_ansi ()]++;
       }
     bg = 0;
     for (unsigned int i = 1; i < 8; i++)
       if (freq[bg] < freq[i])
-        bg = i;
+	bg = i;
     fg = 0;
     for (unsigned int i = 1; i < 8; i++)
       if (i != bg && freq[fg] < freq[i])
-        fg = i;
+	fg = i;
     if (fg == bg || freq[fg] == 0) {
       fg = bg;
       unicolor = true;
@@ -202,7 +202,7 @@
     int dd = diff.dot (diff);
     for (unsigned int y = 0; y < height; y++)
       for (unsigned int x = 0; x < width; x++) {
-        int d = diff.dot (image (x, y).diff (bgc));
+	int d = diff.dot (image (x, y).diff (bgc));
 	(*this)(x, y) = d < 0 ? 0 : d > dd ? 255 : lround (d * 255. / dd);
       }
   }
@@ -287,13 +287,13 @@
       unsigned int s;
       s = row_sum[i] + total_i - row_sum_i[i];
       if (s < best_s) {
-        best_s = s;
+	best_s = s;
 	best_i = i;
 	best_inv = false;
       }
       s = row_sum_i[i] + total - row_sum[i];
       if (s < best_s) {
-        best_s = s;
+	best_s = s;
 	best_i = i;
 	best_inv = true;
       }
@@ -319,13 +319,13 @@
       unsigned int s;
       s = col_sum[i] + total_i - col_sum_i[i];
       if (s < best_s) {
-        best_s = s;
+	best_s = s;
 	best_i = i;
 	best_inv = true;
       }
       s = col_sum_i[i] + total - col_sum[i];
       if (s < best_s) {
-        best_s = s;
+	best_s = s;
 	best_i = i;
 	best_inv = false;
       }
@@ -396,15 +396,15 @@
       image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H);
       bi.set (cell);
       if (bi.unicolor) {
-        if (last_bg != bi.bg) {
+	if (last_bg != bi.bg) {
 	  printf ("%c[%dm", ESC_E, 40 + bi.bg);
 	  last_bg = bi.bg;
 	}
 	printf (" ");
       } else {
-        /* Figure out the closest character to the biimage */
+	/* Figure out the closest character to the biimage */
 	bool inverse = false;
-        const char *c = block_best (bi, &inverse);
+	const char *c = block_best (bi, &inverse);
 	if (inverse) {
 	  if (last_bg != bi.fg || last_fg != bi.bg) {
 	    printf ("%c[%d;%dm", ESC_E, 30 + bi.bg, 40 + bi.fg);
diff --git a/util/hb-fc-list.c b/util/hb-fc-list.c
index 573d11e..39cbb4b 100644
--- a/util/hb-fc-list.c
+++ b/util/hb-fc-list.c
@@ -171,7 +171,7 @@
 	os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_FILE, (char *) 0);
     FcObjectSetAdd (os, FC_CHARSET);
     if (!format)
-        format = (const FcChar8 *) "%{=fclist}\n";
+	format = (const FcChar8 *) "%{=fclist}\n";
     fs = FcFontList (0, pat, os);
     if (os)
 	FcObjectSetDestroy (os);
diff --git a/util/hb-fc.cc b/util/hb-fc.cc
index 2fe0146..9042346 100644
--- a/util/hb-fc.cc
+++ b/util/hb-fc.cc
@@ -55,9 +55,9 @@
     {
       unsigned int var_num = 0;
       if (variation_selector - 0xFE00u < 16)
-        var_num = variation_selector - 0xFE00 + 1;
+	var_num = variation_selector - 0xFE00 + 1;
       else if (variation_selector - 0xE0100u < (256 - 16))
-        var_num = variation_selector - 0xE0100 + 17;
+	var_num = variation_selector - 0xE0100 + 17;
       *glyph = (var_num << 21) | unicode;
     }
     else
diff --git a/util/hb-ot-shape-closure.cc b/util/hb-ot-shape-closure.cc
index 77ca201..33f531b 100644
--- a/util/hb-ot-shape-closure.cc
+++ b/util/hb-ot-shape-closure.cc
@@ -39,7 +39,7 @@
     add_options (parser);
   }
 
-  void add_options (struct option_parser_t *parser)
+  void add_options (struct option_parser_t *parser) override
   {
     GOptionEntry entries[] =
     {
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index 3ae3fa1..bab5cba 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -181,7 +181,7 @@
       fflush (stdout);
 
       if (ret)
-        break;
+	break;
     }
     return ret;
   }
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index b7d9eb9..008e4e6 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -40,19 +40,26 @@
       : failed (false), options (parser), subset_options (parser), font (nullptr), input (nullptr) {}
 
   void init (hb_buffer_t  *buffer_,
-             const font_options_t *font_opts)
+	     const font_options_t *font_opts)
   {
     font = hb_font_reference (font_opts->get_font ());
-    input = hb_subset_input_create_or_fail ();
+    input = hb_subset_input_reference (subset_options.input);
   }
 
   void consume_line (const char   *text,
-                     unsigned int  text_len,
-                     const char   *text_before,
-                     const char   *text_after)
+		     unsigned int  text_len,
+		     const char   *text_before,
+		     const char   *text_after)
   {
     // TODO(Q1) does this only get called with at least 1 codepoint?
     hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+    if (0 == strcmp (text, "*"))
+    {
+      hb_face_t *face = hb_font_get_face (font);
+      hb_face_collect_unicodes (face, codepoints);
+      return;
+    }
+
     gchar *c = (gchar *)text;
     do {
       gunichar cp = g_utf8_get_char(c);
@@ -81,7 +88,7 @@
     }
     if ((unsigned int) bytes_written != data_length) {
       fprintf(stderr, "Expected %u bytes written, got %d\n", data_length,
-              bytes_written);
+	      bytes_written);
       return false;
     }
     return true;
@@ -89,10 +96,6 @@
 
   void finish (const font_options_t *font_opts)
   {
-    hb_subset_input_set_drop_layout (input, !subset_options.keep_layout);
-    hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
-    hb_subset_input_set_desubroutinize (input, subset_options.desubroutinize);
-
     hb_face_t *face = hb_font_get_face (font);
 
     hb_face_t *new_face = hb_subset (face, input);
diff --git a/util/helper-cairo-ansi.cc b/util/helper-cairo-ansi.cc
index 50f9eb4..cbda493 100644
--- a/util/helper-cairo-ansi.cc
+++ b/util/helper-cairo-ansi.cc
@@ -71,7 +71,7 @@
     unsigned int i;
     for (i = 0; i < width; i++)
       if (data[i] != bg_color)
-        break;
+	break;
     if (i < width)
       break;
     data += stride / 4;
@@ -86,7 +86,7 @@
     unsigned int i;
     for (i = 0; i < width; i++)
       if (row[i] != bg_color)
-        break;
+	break;
     if (i < width)
       break;
     height--;
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index b4f94a9..42cce71 100644
--- a/util/helper-cairo.cc
+++ b/util/helper-cairo.cc
@@ -97,7 +97,7 @@
 
     if (FT_New_Memory_Face (ft_library,
 			    (const FT_Byte *) blob_data,
-                            blob_length,
+			    blob_length,
 			    font_opts->face_index,
 			    &ft_face))
       fail (false, "FT_New_Memory_Face fail");
diff --git a/util/options-subset.cc b/util/options-subset.cc
new file mode 100644
index 0000000..35fa05e
--- /dev/null
+++ b/util/options-subset.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2019  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "options.hh"
+
+#include "hb-subset-input.hh"
+
+static gboolean
+parse_nameids (const char *name,
+	       const char *arg,
+	       gpointer    data,
+	       GError    **error G_GNUC_UNUSED)
+{
+  subset_options_t *subset_opts = (subset_options_t *) data;
+  hb_set_t *name_ids = subset_opts->input->name_ids;
+
+  char last_name_char = name[strlen (name) - 1];
+
+  if (last_name_char != '+' && last_name_char != '-')
+    hb_set_clear (name_ids);
+
+  if (0 == strcmp (arg, "*"))
+  {
+    if (last_name_char == '-')
+      hb_set_del_range (name_ids, 0, 0x7FFF);
+    else
+      hb_set_add_range (name_ids, 0, 0x7FFF);
+    return true;
+  }
+
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr (", ", *s))
+      s++;
+    if (!*s)
+      break;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 10);
+    if (errno || s == p)
+    {
+      hb_set_destroy (name_ids);
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing nameID values at: '%s'", s);
+      return false;
+    }
+
+    if (last_name_char != '-')
+    {
+      hb_set_add (name_ids, u);
+    } else {
+      hb_set_del (name_ids, u);
+    }
+
+    s = p;
+  }
+
+  return true;
+}
+
+static gboolean
+parse_drop_tables (const char *name,
+		   const char *arg,
+		   gpointer    data,
+		   GError    **error G_GNUC_UNUSED)
+{
+  subset_options_t *subset_opts = (subset_options_t *) data;
+  hb_set_t *drop_tables = subset_opts->input->drop_tables;
+
+  char last_name_char = name[strlen (name) - 1];
+
+  if (last_name_char != '+' && last_name_char != '-')
+    hb_set_clear (drop_tables);
+
+  char *s = strtok((char *) arg, ", ");
+  while (s)
+  {
+    if (strlen (s) > 4) // Table tags are at most 4 bytes.
+    {
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		   "Failed parsing table tag values at: '%s'", s);
+      return false;
+    }
+
+    hb_tag_t tag = hb_tag_from_string (s, strlen (s));
+
+    if (last_name_char != '-')
+      hb_set_add (drop_tables, tag);
+    else
+      hb_set_del (drop_tables, tag);
+
+    s = strtok(nullptr, ", ");
+  }
+
+  return true;
+}
+
+void
+subset_options_t::add_options (option_parser_t *parser)
+{
+  GOptionEntry entries[] =
+  {
+    {"no-hinting", 0, 0, G_OPTION_ARG_NONE,  &this->input->drop_hints,   "Whether to drop hints",   nullptr},
+    {"retain-gids", 0, 0, G_OPTION_ARG_NONE,  &this->input->retain_gids,   "If set don't renumber glyph ids in the subset.",   nullptr},
+    {"desubroutinize", 0, 0, G_OPTION_ARG_NONE,  &this->input->desubroutinize,   "Remove CFF/CFF2 use of subroutines",   nullptr},
+    {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_nameids,  "Subset specified nameids", "list of int numbers"},
+    {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
+    {"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
+    {"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK,  (gpointer) &parse_drop_tables,  "Drop the specified tables.", "list of string table tags."},
+
+    {nullptr}
+  };
+  parser->add_group (entries,
+	 "subset",
+	 "Subset options:",
+	 "Options subsetting",
+	 this);
+}
diff --git a/util/options.cc b/util/options.cc
index 04ddcf6..43ff90a 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -31,6 +31,8 @@
 #endif
 #include <hb-ot.h>
 
+#define DELIMITERS "<+>{},;&#\\xXuUnNiI\n\t\v\f\r "
+
 static struct supported_font_funcs_t {
 	char name[4];
 	void (*func) (hb_font_t *);
@@ -194,8 +196,8 @@
     bool found = false;
     for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) {
       if (strcmp (*shaper, *hb_shaper) == 0) {
-        found = true;
-        break;
+	found = true;
+	break;
       }
     }
     if (!found) {
@@ -226,9 +228,9 @@
 
 static gboolean
 parse_features (const char *name G_GNUC_UNUSED,
-	        const char *arg,
-	        gpointer    data,
-	        GError    **error G_GNUC_UNUSED)
+		const char *arg,
+		gpointer    data,
+		GError    **error G_GNUC_UNUSED)
 {
   shape_options_t *shape_opts = (shape_options_t *) data;
   char *s = (char *) arg;
@@ -269,9 +271,9 @@
 
 static gboolean
 parse_variations (const char *name G_GNUC_UNUSED,
-	        const char *arg,
-	        gpointer    data,
-	        GError    **error G_GNUC_UNUSED)
+		  const char *arg,
+		  gpointer    data,
+		  GError    **error G_GNUC_UNUSED)
 {
   font_options_t *font_opts = (font_options_t *) data;
   char *s = (char *) arg;
@@ -333,9 +335,9 @@
 
 static gboolean
 parse_unicodes (const char *name G_GNUC_UNUSED,
-	        const char *arg,
-	        gpointer    data,
-	        GError    **error G_GNUC_UNUSED)
+		const char *arg,
+		gpointer    data,
+		GError    **error G_GNUC_UNUSED)
 {
   text_options_t *text_opts = (text_options_t *) data;
 
@@ -347,28 +349,37 @@
   }
 
   GString *gs = g_string_new (nullptr);
-  char *s = (char *) arg;
-  char *p;
-
-  while (s && *s)
+  if (0 == strcmp (arg, "*"))
   {
-    while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t\v\f\r ", *s))
-      s++;
-    if (!*s)
-      break;
+    g_string_append_c (gs, '*');
+  }
+  else
+  {
 
-    errno = 0;
-    hb_codepoint_t u = strtoul (s, &p, 16);
-    if (errno || s == p)
+    char *s = (char *) arg;
+    char *p;
+
+    while (s && *s)
     {
-      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "Failed parsing Unicode values at: '%s'", s);
-      return false;
+      while (*s && strchr (DELIMITERS, *s))
+	s++;
+      if (!*s)
+	break;
+
+      errno = 0;
+      hb_codepoint_t u = strtoul (s, &p, 16);
+      if (errno || s == p)
+      {
+	g_string_free (gs, TRUE);
+	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+  		   "Failed parsing Unicode values at: '%s'", s);
+	return false;
+      }
+
+      g_string_append_unichar (gs, u);
+
+      s = p;
     }
-
-    g_string_append_unichar (gs, u);
-
-    s = p;
   }
 
   text_opts->text_len = gs->len;
@@ -432,7 +443,8 @@
     "    Features can be enabled or disabled, either globally or limited to\n"
     "    specific character ranges.  The format for specifying feature settings\n"
     "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
-    "    and 'inherited' are also accepted, though, not documented below.\n"
+    "    and the global values are also accepted, though not documented below.\n"
+    "    CSS string escapes are not supported."
     "\n"
     "    The range indices refer to the positions between Unicode characters,\n"
     "    unless the --utf8-clusters is provided, in which case range indices\n"
@@ -704,7 +716,7 @@
       GString *s = g_string_new (nullptr);
       for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
       {
-        if (i)
+	if (i)
 	  g_string_append_c (s, '/');
 	g_string_append (s, supported_font_funcs[i].name);
       }
@@ -865,9 +877,9 @@
   parser->add_group (entries,
 		     "output-syntax",
 		     "Output syntax:\n"
-         "    text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
-         "    json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
-         "\nOutput syntax options:",
+	 "    text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
+	 "    json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
+	 "\nOutput syntax options:",
 		     "Options for the syntax of the output",
 		     this);
 }
@@ -969,21 +981,3 @@
   serialize_glyphs (buffer, font, output_format, format_flags, gs);
   g_string_append_c (gs, '\n');
 }
-
-void
-subset_options_t::add_options (option_parser_t *parser)
-{
-  GOptionEntry entries[] =
-  {
-    {"layout", 0, 0, G_OPTION_ARG_NONE,  &this->keep_layout,   "Keep OpenType Layout tables",   nullptr},
-    {"no-hinting", 0, 0, G_OPTION_ARG_NONE,  &this->drop_hints,   "Whether to drop hints",   nullptr},
-    {"desubroutinize", 0, 0, G_OPTION_ARG_NONE,  &this->desubroutinize,   "Remove CFF/CFF2 use of subroutines",   nullptr},
-
-    {nullptr}
-  };
-  parser->add_group (entries,
-         "subset",
-         "Subset options:",
-         "Options subsetting",
-         this);
-}
diff --git a/util/options.hh b/util/options.hh
index d704519..9e22b40 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -28,6 +28,7 @@
 #define OPTIONS_HH
 
 #include "hb.hh"
+#include "hb-subset.h"
 
 #include <stdlib.h>
 #include <stddef.h>
@@ -74,10 +75,13 @@
 
     add_main_options ();
   }
+
+  static void _g_free_g_func (void *p, void * G_GNUC_UNUSED) { g_free (p); }
+
   ~option_parser_t ()
   {
     g_option_context_free (context);
-    g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr);
+    g_ptr_array_foreach (to_free, _g_free_g_func, nullptr);
     g_ptr_array_free (to_free, TRUE);
   }
 
@@ -125,13 +129,13 @@
 
     add_options (parser);
   }
-  virtual ~view_options_t ()
+  ~view_options_t () override
   {
     g_free (fore);
     g_free (back);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
   hb_bool_t annotate;
   char *fore;
@@ -161,7 +165,7 @@
 
     add_options (parser);
   }
-  virtual ~shape_options_t ()
+  ~shape_options_t () override
   {
     g_free (direction);
     g_free (language);
@@ -170,7 +174,7 @@
     g_strfreev (shapers);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
   void setup_buffer (hb_buffer_t *buffer)
   {
@@ -238,7 +242,7 @@
     if (!hb_shape_full (font, buffer, features, num_features, shapers))
     {
       if (error)
-        *error = "all shapers failed.";
+	*error = "all shapers failed.";
       goto fail;
     }
 
@@ -337,7 +341,7 @@
       /* Shape segment corresponding to glyphs start..end. */
       if (end == num_glyphs)
       {
-        if (forward)
+	if (forward)
 	  text_end = num_chars;
 	else
 	  text_start = 0;
@@ -368,9 +372,9 @@
       /* TODO: Add pre/post context text. */
       hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
       if (0 < text_start)
-        flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT);
       if (text_end < num_chars)
-        flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
+	flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT);
       hb_buffer_set_flags (fragment, flags);
 
       hb_buffer_append (fragment, text_buffer, text_start, text_end);
@@ -467,7 +471,7 @@
 
     add_options (parser);
   }
-  virtual ~font_options_t ()
+  ~font_options_t () override
   {
     g_free (font_file);
     free (variations);
@@ -475,7 +479,7 @@
     hb_font_destroy (font);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
   hb_font_t *get_font () const;
 
@@ -517,7 +521,7 @@
 
     add_options (parser);
   }
-  virtual ~text_options_t ()
+  ~text_options_t () override
   {
     g_free (text_before);
     g_free (text_after);
@@ -529,9 +533,9 @@
       fclose (fp);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
-  void post_parse (GError **error G_GNUC_UNUSED) {
+  void post_parse (GError **error G_GNUC_UNUSED) override {
     if (text && text_file)
       g_set_error (error,
 		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
@@ -568,7 +572,7 @@
 
     add_options (parser);
   }
-  virtual ~output_options_t ()
+  ~output_options_t () override
   {
     g_free (output_file);
     g_free (output_format);
@@ -576,9 +580,9 @@
       fclose (fp);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
-  void post_parse (GError **error G_GNUC_UNUSED)
+  void post_parse (GError **error G_GNUC_UNUSED) override
   {
     if (output_format)
       explicit_output_format = true;
@@ -623,7 +627,7 @@
     add_options (parser);
   }
 
-  void add_options (option_parser_t *parser);
+  void add_options (option_parser_t *parser) override;
 
   void serialize_unicode (hb_buffer_t  *buffer,
 			  GString      *gs);
@@ -670,18 +674,18 @@
 {
   subset_options_t (option_parser_t *parser)
   {
-    keep_layout = false;
-    drop_hints = false;
-    desubroutinize = false;
-
+    input = hb_subset_input_create_or_fail ();
     add_options (parser);
   }
 
-  void add_options (option_parser_t *parser);
+  ~subset_options_t () override
+  {
+    hb_subset_input_destroy (input);
+  }
 
-  hb_bool_t keep_layout;
-  hb_bool_t drop_hints;
-  hb_bool_t desubroutinize;
+  void add_options (option_parser_t *parser) override;
+
+  hb_subset_input_t *input;
 };
 
 /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */